FXBlurView icon indicating copy to clipboard operation
FXBlurView copied to clipboard

Feature: Font Color For Rect

Open AnthonyMyatt opened this issue 10 years ago • 4 comments

I have quite a few FXBlurViews with labels on them and with the content behind them changing from a bright color to a dull color (UIImageViews to be exact). I'd really like to be able to pass the FXBlurView the NSRect for the UILabels frame and have it return the best color for the label to make it readable. Even if it just returned white or black for the moment as a proof of concept.

I hope something like this can be implemented.

AnthonyMyatt avatar Sep 30 '13 06:09 AnthonyMyatt

That does sound pretty neat. It's a little bit out if scope for what I'm trying to do with FXBlurview, but I'll think about it.

nicklockwood avatar Sep 30 '13 07:09 nicklockwood

Thanks Nick. Would be fantastic. I might take a look at it and see if I can come up with anything. Let me know if you work something out first.

Fantastic job by the way, performance is fantastic compared to a few other solutions I have looked at.

AnthonyMyatt avatar Sep 30 '13 08:09 AnthonyMyatt

I've come up with the following solution. It works and doesn't appear to impact overall performance since it's only rendering the required number of pixels to get the color average for the specified rect.

Please let me know what you think.

@implementation UIView (FXBlurView)

- (UIColor *) colorAverageForRect:(CGRect)rect
{
    int red   = 0;
    int green = 0;
    int blue  = 0;

    int count = 0;

    int width  = rect.size.width;
    int height = rect.size.height;

    int bitsPerComponent = 8;
    int bytesPerRow = 4 * width;

    unsigned char pixels[bytesPerRow*height];
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pixels, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

    CGContextTranslateCTM(context, -rect.origin.x, -rect.origin.y);

    [self.layer renderInContext:context];

    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);

    for (int x = 0; x < width; x++)
    {
        for (int y = 0; y < height; y++)
        {
            int pixel_y = y*(bytesPerRow);
            int pixel_x = x*4;

            red += pixels[ pixel_y + pixel_x ];
            green += pixels[ pixel_y + pixel_x + 1];
            blue += pixels[ pixel_y + pixel_x + 2];

            count++;
        }
    }

    red /= count;
    green /= count;
    blue /= count;

    return [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:1.0f];
}

- (UIColor *) contrastingTextColorForRect:(CGRect)rect
{
    UIColor *averageBackColor = [self colorAverageForRect:rect];

    const CGFloat *componentColors = CGColorGetComponents(averageBackColor.CGColor);

    CGFloat colorBrightness = ((componentColors[0] * 299) +
                               (componentColors[1] * 587) +
                               (componentColors[2] * 114)) / 1000;
    if (colorBrightness < 0.5)
    {
        return [UIColor whiteColor];
    }
    else
    {
        return [UIColor blackColor];
    }
}

@end

AnthonyMyatt avatar Oct 02 '13 13:10 AnthonyMyatt

Or a colored version:

- (UIColor *) contrastingTextColorForRect:(CGRect)rect
{
    UIColor *averageBackColor = [self colorAverageForRect:rect];

    CGColorRef oldCGColor = averageBackColor.CGColor;

    size_t numberOfComponents = CGColorGetNumberOfComponents(oldCGColor);

    // can not invert - the only component is the alpha
    // e.g. self == [UIColor groupTableViewBackgroundColor]
    if (numberOfComponents == 1) {
        return [UIColor colorWithCGColor:oldCGColor];
    }

    const CGFloat *oldComponentColors = CGColorGetComponents(oldCGColor);
    CGFloat newComponentColors[numberOfComponents];

    int i = (int)numberOfComponents - 1;
    newComponentColors[i] = oldComponentColors[i]; // alpha
    while (--i >= 0) {
        newComponentColors[i] = 1 - oldComponentColors[i];
    }

    CGColorRef newCGColor = CGColorCreate(CGColorGetColorSpace(oldCGColor), newComponentColors);
    UIColor *newColor = [UIColor colorWithCGColor:newCGColor];
    CGColorRelease(newCGColor);

    return newColor;
}

AnthonyMyatt avatar Oct 03 '13 04:10 AnthonyMyatt