Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange colorWithPatternImage on iPhone 5 hardware

In a blank UIViewController, I change the screen color by:

self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"blackPattern.png"]];

Then I do a screen capture from my iPhone 5. The image looks like:

enter image description here

If you view the image in 100%, you'll see three bars (top, left and bottom). However, my pattern image is very simple ([email protected]):

enter image description here

It's a 8x8 png for retina display.

Ironically, the bars are not visible when the app runs on the Simulator. Is it an iPhone 5 hardware specific symtom?

p.s. If you want to see it running, you may download my app: here

like image 963
ohho Avatar asked Feb 08 '13 08:02

ohho


1 Answers

Interesting. I can reproduce the problem on an iPhone 5 (not on simulator, not even in retina mode).

Some thoughts and observations: The color in the small patten image is exactly black and white (0 and 255, each r, b and g). In the full screen image it's not. In the center it's 8 and 247, at the bottom 12, 243 and at the side 4, 251.

This very much looks like an interpolation artifact: When Core Graphics paints pixels from an image onto device pixels and the pixels do not match perfectly, it calculates interpolated colors from neighboring source pixels. Black and white would result in dark and bright grays: the effect we see in this case.

Still I don't know why this only happens on the device.

Playing a little bit with this problem I did not find the reason but a solution to your problem: Create the checkerboard pattern color yourself:

static void patternDrawPatternCallback(void *info, CGContextRef c)
{
    for (int y = 0; y < 8; ++y) {
        for (int x = 0; x < 8; ++x) {
            CGFloat v = (x + y) & 1;
            CGContextSetRGBFillColor(c, v, v, v, 1);
            CGContextFillRect(c, (CGRect){{x, y}, {1, 1}});
        }
    }
}

static void patternReleaseInfoCallback(void *info)
{
}

static UIColor *checkerColor()
{
    CGPatternCallbacks callbacks = {
        .drawPattern = patternDrawPatternCallback,
        .releaseInfo = patternReleaseInfoCallback,
    };

    CGFloat scale = 1.0f / [UIScreen mainScreen].scale;
    CGPatternRef pattern = CGPatternCreate(NULL,
                                           (CGRect){.size={8, 8}},
                                           CGAffineTransformMakeScale(scale, scale),
                                           8, 8,
                                           kCGPatternTilingConstantSpacing,
                                           YES,
                                           &callbacks);

    CGFloat components[] = {1, 1, 1, 1};
    CGColorSpaceRef colorspace = CGColorSpaceCreatePattern(NULL);
    CGColorRef color = CGColorCreateWithPattern(colorspace, pattern, components);
    CGColorSpaceRelease(colorspace);
    CGPatternRelease(pattern);

    UIColor *checkerColor = [UIColor colorWithCGColor:color];
    CGColorRelease(color);

    return checkerColor;
}

Using color from this code I was not able to reproduce the problem (even though I played with the pattern tiling and set the size of the tiles to be slightly off).

like image 101
Nikolai Ruhe Avatar answered Sep 23 '22 06:09

Nikolai Ruhe