奇怪的 colorWithPatternImage 在 iPhone 5 硬件上的表现颜色问题

12

在一个空的UIViewController中,我通过以下方式改变屏幕颜色:

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

然后我从我的iPhone 5上进行屏幕截图。图片如下:

enter image description here

如果您在100%的视图中查看该图像,您将会看到三条线(顶部、左侧和底部)。然而,我的图案图像非常简单(blackPattern@2x.png):

enter image description here

这是一个用于Retina显示器的8x8 PNG格式的图像。

具有讽刺意味的是,在模拟器上运行应用程序时,这些线条是不可见的。这是否是iPhone 5硬件特定的症状?

p.s. 如果您想看它运行,可以下载我的应用程序:此处


在我看來這沒問題。colorWithPatternImage會取你提供的圖片,並連續瓦片以填滿視圖的背景。你遇到了什麼具體問題? - FeifanZ
@Inspire48,你没有注意到图像左侧、顶部和底部的不同模式吗? - ohho
你在 iPhone 上看到了那些条纹吗?在我看来,它看起来完全均匀。我想我知道为什么——我有一台 Retina MBP。它有像素可以完美地显示图像。然而,在非 Retina 显示器上(通过 HDMI 连接到我的 rMBP),我确实看到了色差条纹——顶部和左侧的条纹大约有一厘米宽(尽管这将取决于显示器),底部的条纹则宽 4 或 5 倍。这是你所描述的吗? - FeifanZ
是的,我可以看到iPhone底部的状态栏。在iPhone上,左边和顶部不太明显。底部状态栏比左边和顶部的宽度要大4到5倍。实际上,在一位报告了这个问题的用户之后,我才注意到这个奇怪的模式。 - ohho
当你使用图案图像时,应该使用大于8 x 8的大型图像。尝试使用类似120 x 120这样的图像。 - Inoka
这里有一个与你的问题类似的stackoverflow问题:http://stackoverflow.com/questions/12393788/uicolor-colorwithpatternimage-changes-the-color-of-the-image。我想知道如果你像David H建议的那样使用pngcrush是否会解决你的问题? - Bradford2000
3个回答

2
有趣。我可以在iPhone 5上重现这个问题(不是在模拟器上,甚至不是在视网膜模式下)。
一些想法和观察:小图案图像中的颜色完全是黑白的(每个r、b和g都是0和255)。但在全屏图像中却不是这样。在中心位置是8和247,在底部是12、243,在侧面是4、251。
这非常像是插值伪影:当Core Graphics将像素从图像绘制到设备像素上时,如果像素不完全匹配,它会从相邻的源像素计算出插值颜色。黑白会导致深灰色和亮灰色:这就是我们在这种情况下看到的效果。
尽管如此,我仍然不知道为什么这只会在设备上发生。
通过解决这个问题,我没有找到原因,但是找到了一个解决方案:自己创建棋盘格图案颜色。
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;
}

使用这个代码中的颜色,即使我玩弄图案平铺并将瓷砖大小设置为略微偏离,也无法复制问题。


0

我不知道这是否是你的确切问题,但是这行代码:

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

...意味着您无论设备是否为Retina,都在使用名为“blackPattern.png”的文件。该行应为:

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

...(不要在结尾加上.png)。这样,如果设备不是Retina,则您的程序将使用“blackPattern.png”,如果是Retina,则使用“blackPattern@2x.png”。

很可能,您正在运行此代码的模拟器不是Retina,因此看起来很好;只有在Retina设备上才会出现问题。


4
这并不完全准确;即使您有 .PNG 结尾,iOS 也会加载 @2x。 此外,“在 iOS 4 及更高版本中,如果文件是以 PNG 格式存储的,则无需指定 .PNG 文件扩展名。 在 iOS 4 之前,您必须指定文件名扩展名。” 不管您是否指定 .PNG 结尾都没有影响。 - FeifanZ
@Inspire48:我相信你是对的,但我找不到任何明确支持这一点的参考资料。UIImage的类参考使用了没有扩展名的文件名示例。你有好的链接吗? - MusiGenesis
我猜你可以找到一个链接,但是快速进入Xcode会发现你可以保留扩展名,系统仍然会加载@2x的图像。你可以通过将模拟器设置为使用Retina设备(在硬件菜单下)来确认。 - FeifanZ

0

看起来你正在创建一个带有透明背景的UIImageView或UIView。由于你使用的图像包含不透明和透明颜色,所以你仍然可以透过它看到后面的内容。


你认为这个图案为什么是透明的?我有什么遗漏吗? - Nikolai Ruhe
好像图像是透过来的。你的棋盘格图案中是否包含“白色”部分应该是透明的? - JasonBourne
不,图案图片完全不透明,但我可以重现这个问题。 - Nikolai Ruhe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接