CGImageCreateWithMaskingColors在iOS7上无法正常工作。

4
我已经开发了一个适用于iOS5和iOS6的应用程序。但是在我升级至XCode 5和iOS7后,遇到了一些新问题。
其中一个主要问题是colorMasking不再起作用。同样的代码在安装iOS6的手机上编译和运行仍然没问题,但在iOS7上,遮罩颜色消失了。我尝试在Google上找答案,但没有找到合适的解决方法。这是iOS7的一个bug吗?或者有没有人知道更好的实现遮罩颜色的方法?
以下是代码:
- (UIImage*) processImage :(UIImage*) image
{
    UIImage *inputImage = [UIImage imageWithData:UIImageJPEGRepresentation(image, 1.0)];
    const float colorMasking[6]={100.0, 255.0, 0.0, 100.0, 100.0, 255.0};
    CGImageRef imageRef = CGImageCreateWithMaskingColors(inputImage.CGImage, colorMasking);
    UIImage* finalImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    return finalImage;
}

以下是我找到的几篇StackOverflow帖子,帮助我在iOS6中首次实现透明度: 透明度iOS iOS中UIImage的颜色变为透明


你是否对 inputImage 的位/组件与你所假定的常量进行了合理性检查?你可能还需要检查颜色模型。如果你对输入有精确的控制,这可能并不重要。 - justin
2个回答

8
我发现在使用CGImageCreateWithMaskingColorsUIImagePNGRepresentation时可能会出现一些奇怪的行为。这可能与你的问题有关。我发现如果:

  1. 使用CGImageCreateWithMaskingColors并立即将该图像添加到图像视图中,则可以看到透明度似乎已被正确应用;

  2. 但在iOS 7中,如果我:

    • CGImageCreateWithMaskingColors获取此图像并使用UIImagePNGRepresentation创建NSData; 并且

    • 重新加载来自NSData的图像,然后生成的图像将不再具有其透明度。

    要确认这一点,如果我writeToFileNSData并在诸如Photoshop之类的工具中检查保存的图像,则可以确认文件没有应用任何透明度。

    这只在iOS 7中表现出来。 在iOS 6中没问题。

  3. 但是,如果我通过drawInRect处理步骤1中的图像,则保存图像并随后加载它的相同过程正常工作。

以下代码说明了这个问题:

- (UIImage*) processImage :(UIImage*) inputImage
{
    const float colorMasking[6] = {255.0, 255.0, 255.0, 255.0, 255.0, 255.0};
    CGImageRef imageRef = CGImageCreateWithMaskingColors(inputImage.CGImage, colorMasking);
    UIImage* finalImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);

    // If I put this image in an image view, I see the transparency fine.

    self.imageView.image = finalImage;                           // this works

    // But if I save it to disk and the file does _not_ have any transparency

    NSString *documentsPath           = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    NSString *pathWithoutTransparency = [documentsPath stringByAppendingPathComponent:@"image-but-no-transparency.png"];
    NSData   *data                    = UIImagePNGRepresentation(finalImage);
    [data writeToFile:pathWithoutTransparency atomically:YES];   // save it so I can check out the file in Photoshop

    // In iOS 7, the following imageview does not honor the transparency

    self.imageView2.image = [UIImage imageWithData:data];        // this does not work in iOS 7

    // but, if I round-trip the original image through `drawInRect` one final time,
    // the transparency works

    UIGraphicsBeginImageContextWithOptions(finalImage.size, NO, 1.0);
    [finalImage drawInRect:CGRectMake(0, 0, finalImage.size.width, finalImage.size.height)];
    UIImage *anotherRendition = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    data = UIImagePNGRepresentation(anotherRendition);
    NSString *pathWithTransparency = [documentsPath stringByAppendingPathComponent:@"image-with-transparancy.png"];
    [data writeToFile:pathWithTransparency atomically:YES];

    // But this image is fine

    self.imageView3.image = [UIImage imageWithContentsOfFile:pathWithTransparency];   // this does work

    return anotherRendition;
}

从阅读您的评论和代码来看,这似乎可能是答案!!我今晚有时间尝试一下,并告诉您它的表现如何。非常感谢!!!! - surreal
1
太棒了!你的想法和代码完美地运作了!我绝对不可能自己发现这个问题...非常感谢你快速并且正确的回答。能够帮助苹果找出一个漏洞真的很酷。;)多谢你的报告。 - surreal
1
太棒了 - 我在类似的问题上纠结了两天,谢谢! - BooTooMany

0
我正在加载一个JPEG文件,出于某种原因它带有一个alpha通道,但当进行遮罩时这是行不通的,所以在这里我重新创建了一个忽略alpha通道的CGImage。可能还有更好的方法来解决这个问题,但这个方法是有效的!
- (UIImage *)imageWithChromaKeyMasking {
    const CGFloat colorMasking[6]={255.0,255.0,255.0,255.0,255.0,255.0};
    CGImageRef oldImage = self.CGImage;
    CGBitmapInfo oldInfo = CGImageGetBitmapInfo(oldImage);
    CGBitmapInfo newInfo = (oldInfo & (UINT32_MAX ^ kCGBitmapAlphaInfoMask)) | kCGImageAlphaNoneSkipLast;
    CGDataProviderRef provider = CGImageGetDataProvider(oldImage);
    CGImageRef newImage = CGImageCreate(self.size.width, self.size.height, CGImageGetBitsPerComponent(oldImage), CGImageGetBitsPerPixel(oldImage), CGImageGetBytesPerRow(oldImage), CGImageGetColorSpace(oldImage), newInfo, provider, NULL, false, kCGRenderingIntentDefault);
    CGDataProviderRelease(provider); provider = NULL;
    CGImageRef im = CGImageCreateWithMaskingColors(newImage, colorMasking);
    UIImage *ret = [UIImage imageWithCGImage:im];
    CGImageRelease(im);
    return ret;
}

1
请注意,您不应该释放 provider(如果函数名称中带有 CreateCopy,则没有将所有权转移给您,根据创建规则),但您应该释放 newImage - Rob

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