【问题标题】:Any idea why this image masking code does not work?知道为什么这个图像屏蔽代码不起作用吗?
【发布时间】:2010-11-11 02:52:53
【问题描述】:

我有这个代码来屏蔽图像。基本上,我只使用 PNG 图像。所以我有一个 24 位颜色 (PNG-24) 的 300x400 PNG 图像。我不确定它是否也有 alpha 通道。但它没有透明度。

然后,有没有alpha通道的PNG-8bit的图像掩码。它只是黑色、灰度和白色。

我将这两个图像都创建为 UIImage。将它们放入 UIImageView 时,两者都正确显示。

然后我使用以下代码创建一个 UIImage ,其中包含屏蔽操作的结果:

+ (UIImage*)maskImage:(UIImage*)image withMask:(UIImage*)maskImage {
 CGImageRef maskRef = maskImage.CGImage;
 CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
          CGImageGetHeight(maskRef),
          CGImageGetBitsPerComponent(maskRef),
          CGImageGetBitsPerPixel(maskRef),
          CGImageGetBytesPerRow(maskRef),
          CGImageGetDataProvider(maskRef), NULL, false);
 CGImageRef masked = CGImageCreateWithMask([image CGImage], mask);
 return [UIImage imageWithCGImage:masked];
}

我是这样做的:

 UIImage *image = [UIImage imageNamed:@"coloredImagePNG24.png"];
 UIImage *maskImage = [UIImage imageNamed:@"theMaskPNG8_Grayscale_NoAlpha.png"];
 UIImage *maskedImage = [MyGraphicUtils maskImage:image withMask:maskImage];
 UIImageView *testImageView = [[UIImageView alloc] initWithImage:maskedImage];
 testImageView.backgroundColor = [UIColor clearColor];
 testImageView.opaque = NO;

毕竟,coloredImagePNG24.png 保持原样。没有掩蔽发生。但现在奇怪的是:如果我把它转过来,即使用这个图像作为蒙版,并将蒙版作为彩色图像到蒙版,那么我会得到灰度非常难看的东西(但被蒙版;))。

知道我的代码有什么问题吗?

更新:我刚刚搜索了一个不同的黑白 png 以将其用作掩码。然后这个成功了!但是我自己做的那个不行。所以我假设代码有很大的图像解码问题。我必须将图像“规范化”为特定格式,才能正常工作。

【问题讨论】:

    标签: iphone cocoa-touch uikit image-manipulation core-graphics


    【解决方案1】:

    看看这种方式是否效果更好:

    + (UIImage*)maskImage:(UIImage*)image withMask:(UIImage*)maskImage {
       UIGraphicsBeginImageContext(image.size);
       CGImageRef maskRef = maskImage.CGImage;
       CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef), CGImageGetHeight(maskRef), CGImageGetBitsPerComponent(maskRef), CGImageGetBitsPerPixel(maskRef), CGImageGetBytesPerRow(maskRef), CGImageGetDataProvider(maskRef), NULL, false);
       CGImageRef masked = CGImageCreateWithMask(image.CGImage, mask);
       UIImage* result = [UIImage imageWithData:UIImagePNGRepresentation(UIGraphicsGetImageFromCurrentImageContext())];
       UIGraphicsEndImageContext();
       CGImageRelease(mask);
       CGImageRelease(masked);
       return result;
    }
    

    【讨论】:

    • 虽然看起来很漂亮,但就我而言,它只是让图像完全透明。请参阅上面的更新。我发现了一些奇怪的东西。
    • 我使用了上述代码的变体,将在 Photoshop 中创建的蒙版转换为“灰度”并导出为 24 位 PNG。
    • 如果您想使用上述代码,请确保您的包含掩码的图像文件是 没有 具有 Alpha 通道的 24 位 PNG。例如,Pixelmator 不会告诉你这些信息。您需要使用 Photoshop 或 Gimp。
    【解决方案2】:

    Dave,我听说 PNG 图像具有可以影响此类代码的 Alpha 通道。

    我刚刚搜索了 PNG Alpha 频道并找到了这个链接:link text

    因此,请确保您使用的 PNG 具有正确设置的 Alpha 通道

    【讨论】:

      【解决方案3】:

      CGImageMaskCreate 确实不按照您的预期行事。特别是:

      对于每个组件 2、4 或 8 位的图像掩码,每个组件通过使用以下公式进行缩放映射到 0 到 1 的范围:

      1/(2^bits per component – 1)

      例如,4 位掩码的值范围为 0 到 15。这些值按 1/15 缩放,因此每个分量的范围为 0 到 1。重新缩放为 0 或 1 的分量值的行为方式相同因为它们适用于 1 位图像掩码。缩放到 0 和 1 之间的值充当反 alpha。也就是说,填充颜色被绘制为好像它具有 (1 – MaskSampleValue) 的 alpha 值。例如,如果 8 位掩码的样本值缩放为 0.8,则当前填充颜色将被绘制为具有 0.2 的 alpha 值,即 (1–0.8)。

      我的猜测是该函数正在以这种不同的格式重新解释您的 RGB 数据,这会扭曲颜色值。你试过直接用蒙版CGImage吗?

      快速编辑:我所说的“直接”就是写

      + (UIImage*)maskImage:(UIImage*)image withMask:(UIImage*)maskImage
      {
          CGImageRef masked = CGImageCreateWithMask([image CGImage], [maskImage CGImage]);
          return [UIImage imageWithCGImage:masked];
      }
      

      【讨论】:

        【解决方案4】:

        正如您所发现的,保存文件的方式会有所不同,因为 Core Graphics 非常注重用于掩码的位格式。

        我发现从任意图像生成图像掩码的最佳和最可靠的方法是这样做:

        1. 创建一个图像掩码可接受格式的位图图形上下文(您不能为此使用 UIGraphicsBeginImageContext())
        2. 将您的图像绘制到此位图图形上下文中
        3. 根据位图图形上下文的位创建图像掩码。

        试试这个功能:

        CGImageRef createMaskWithImage(CGImageRef image)
        {
            int maskWidth               = CGImageGetWidth(image);
            int maskHeight              = CGImageGetHeight(image);
            //  round bytesPerRow to the nearest 16 bytes, for performance's sake
            int bytesPerRow             = (maskWidth + 15) & 0xfffffff0;
            int bufferSize              = bytesPerRow * maskHeight;
        
            //  allocate memory for the bits 
            CFMutableDataRef dataBuffer = CFDataCreateMutable(kCFAllocatorDefault, 0);
            CFDataSetLength(dataBuffer, bufferSize);
        
            //  the data will be 8 bits per pixel, no alpha
            CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceGray();
            CGContextRef ctx            = CGBitmapContextCreate(CFDataGetMutableBytePtr(dataBuffer),
                                                                maskWidth, maskHeight,
                                                                8, bytesPerRow, colourSpace, kCGImageAlphaNone);
            //  drawing into this context will draw into the dataBuffer.
            CGContextDrawImage(ctx, CGRectMake(0, 0, maskWidth, maskHeight), image);
            CGContextRelease(ctx);
        
            //  now make a mask from the data.
            CGDataProviderRef dataProvider  = CGDataProviderCreateWithCFData(dataBuffer);
            CGImageRef mask                 = CGImageMaskCreate(maskWidth, maskHeight, 8, 8, bytesPerRow,
                                                                dataProvider, NULL, FALSE);
        
            CGDataProviderRelease(dataProvider);
            CGColorSpaceRelease(colourSpace);
            CFRelease(dataBuffer);
        
            return mask;
        }
        

        【讨论】:

          【解决方案5】:

          您不能使用没有 Alpha 通道的核心图形创建任何类型的图像。

          【讨论】:

            【解决方案6】:

            此代码可能对您有所帮助

            - (UIImage*) maskImage:(UIImage *)image withMask:(UIImage *)maskImage {
            
                CGImageRef maskRef = maskImage.CGImage; 
            
                CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
                    CGImageGetHeight(maskRef),
                    CGImageGetBitsPerComponent(maskRef),
                    CGImageGetBitsPerPixel(maskRef),
                    CGImageGetBytesPerRow(maskRef),
                    CGImageGetDataProvider(maskRef), NULL, false);
            
                CGImageRef masked = CGImageCreateWithMask([image CGImage], mask);
                return [UIImage imageWithCGImage:masked];
            
            }
            

            参考这个example demonstration

            【讨论】:

            • 只要生成的 UIImage 使用 UIImageView 显示或手动绘制到新的图像上下文中,它就可以工作。如果您尝试使用 UIImagePNGRepresentation(yourMaskedImage) 将图像保存到文件中,您将丢失遮罩。仅供参考 - 我把头发拉了一会儿。同样在代码的末尾,您应该释放一些引用以避免内存泄漏:CGImageRelease(maskedImageRef); CGImageRelease(掩码);
            • 浪费时间和@AlextheUkrainian 的评论就是答案。非常感谢!
            • 哇,我第一次收到人们的回应,我内心感到头晕目眩。 :p 另外,您可以为 cmets 投票,因此请对那些帮助您的人进行投票,以便其他人知道! @mxcl
            • 虽然我已经得到了掩码和从谷歌下载的图像,但它仍然对我不起作用,但上面的函数总是将掩码变量作为掩码图像返回。我正在研究 swift 4。有什么想法吗?
            【解决方案7】:

            以下代码行对我有用

                +(UIImage*)maskImageExt:(UIImage *)image withMask:(UIImage *)maskImage {
                  CGImageRef maskRef = maskImage.CGImage;
                  CGImageRef imageRef = image.CGImage;
            
                  CGImageRef mask = CGImageMaskCreate(CGImageGetWidth(maskRef),
                                                CGImageGetHeight(maskRef),
                                                CGImageGetBitsPerComponent(maskRef),
                                                CGImageGetBitsPerPixel(maskRef),
                                                CGImageGetBytesPerRow(maskRef),
                                                CGImageGetDataProvider(maskRef), NULL, true);
            
            CGImageRef maskImageRef = CGImageCreateWithMask([image CGImage], mask);
            
            CGContextRef context = CGBitmapContextCreate(nil,
                                                         CGImageGetWidth(imageRef),
                                                         CGImageGetHeight(imageRef),
                                                         CGImageGetBitsPerComponent(imageRef),
                                                         CGImageGetBytesPerRow(imageRef),
                                                         CGImageGetColorSpace(imageRef),
                                                         CGImageGetBitmapInfo(imageRef));
            CGRect imageRect = CGRectMake(0, 0, CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
            CGContextDrawImage(context, imageRect, maskImageRef);
            CGImageRef maskedImageRef = CGBitmapContextCreateImage(context);
            UIImage *maskedImage = [UIImage imageWithCGImage:maskedImageRef];
            
            CGImageRelease(mask);
            CGContextRelease(context);
            CGImageRelease(maskedImageRef);
            
            return maskedImage;
            

            }

            【讨论】:

              猜你喜欢
              • 2021-03-11
              • 2022-08-23
              • 2015-07-06
              • 2020-01-11
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-05-22
              相关资源
              最近更新 更多