CGContextClipToMask可以屏蔽alpha = 1的所有非透明像素吗?

时间:2013-01-31 09:20:19

标签: ios core-graphics

是否可以使CGContextClipToMask忽略蒙版图像的灰度值,并将其视为纯黑色和白色?

我有一个灰度图像,当我用它作为遮罩时,灰色会被解释为alpha通道。这很好,除了我需要完全掩盖那些不透明的像素。

简短的例子:

UIImage *mask = [self prepareMaskImage];
UIGraphicsBeginImageContextWithOptions(mask.size, NO, mask.scale); {
  // Custom code
  CGContextClipToMask(UIGraphicsGetCurrentContext(), mask.size, mask.CGImage);
  // Custom code
}

是否可以调整此代码以实现我的目标?

长话短说:我需要让透明的灰度图像在最初的位置变得透明,在纯色的地方变成完全黑色。

3 个答案:

答案 0 :(得分:1)

我的粗略想法如下:

  1. 您将输入图像转换为灰色+ alpha格式的可读字节数据。由于iOS的限制,可能你不得不做RGBA。
  2. 迭代修改现有值的字节数据。
  3. 要简化访问,请使用

    typedef struct RGBA {
        UInt8 red;
        UInt8 green;
        UInt8 blue;
        UInt8 alpha;
    } RGBA;
    

    我们假设image您的输入掩码。

    // First step, using RGBA (because I know it works and does not harm, just writes/consumes twice the amount of memory)
    CGImageRef imageRef = image.CGImage;
    NSInteger rawWidth = CGImageGetWidth(imageRef);
    NSInteger rawHeight = CGImageGetHeight(imageRef);
    NSInteger rawBitsPerComponent = 8;
    NSInteger rawBytesPerPixel = 4;
    NSInteger rawBytesPerRow = rawBytesPerPixel * rawWidth;
    CGRect rawRect = CGRectMake(0, 0, rawWidth, rawHeight);
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    UInt8 *rawImage = (UInt8 *)malloc(rawHeight * rawWidth * rawBytesPerPixel);
    CGContextRef rawContext = CGBitmapContextCreate(rawImage,
                                                    rawWidth,
                                                    rawHeight,
                                                    rawBitsPerComponent,
                                                    rawBytesPerRow,
                                                    colorSpace,
                                                    kCGImageAlphaPremultipliedLast);
    CGColorSpaceRelease(colorSpace);
    
    // At this point, rawContext is ready for drawing, everything drawn will be in rawImage's byte array.
    CGContextDrawImage(rawContext, rawRect, imageRef);
    
    // Second step, crawl the byte array and do the evil work:
    for (NSInteger y = 0; y < rawHeight; ++y) {
        for (NSInteger x = 0; x < rawWidth; ++x) {
            UInt8 *address = rawImage + x * rawBytesPerPixel + y * rawBytesPerRow;
            RGBA *pixel = (RGBA *)address;
            // If it is a grey input image, it does not matter what RGB channel to use - they shall all be the same
            if (0 != pixel->red) {
                pixel->alpha = 0;
            } else {
                pixel->alpha = UINT8_MAX;
            }
            pixel->red = 0;
            pixel->green = 0;
            pixel->blue = 0;
            // I am still not sure if this is the transformation you are searching for, but it may give you the idea.
        }
    }
    
    // Third: rawContext is ready, transformation is done. Get the image out of it
    CGImageRef outputImage1 = CGBitmapContextCreateImage(rawContext);
    UIImage *outputImage2 = [UIImage imageWithCGImage:outputImage1];
    CGImageRelease(outputImage1);
    

    好的......输出是RGBA,但你可以创建一个灰度+ alpha上下文,然后在那里blit你的图像进行转换。

答案 1 :(得分:1)

有趣的问题! Here's code在一个简单的示例项目中执行我认为您想要的内容。与上述类似,但正确处理比例。如果需要,还可以选择在蒙版图像中保留alpha。快速黑客攻击测试似乎有效。

答案 2 :(得分:0)

这段代码帮助我在图像的非透明区域上应用色调。

- (UIImage*)imageWithImage:(UIImageView*)source colorValue:(CGFloat)hue {
    CGSize imageSize = [source.image size];
    CGRect imageExtent = CGRectMake(0,0,imageSize.width,imageSize.height);

    // Create a context containing the image.
    UIGraphicsBeginImageContext(imageSize);
    CGContextRef context = UIGraphicsGetCurrentContext();
    [source.image drawAtPoint:CGPointMake(0, 0)];

    // Setup a clip region using the image
    CGContextSaveGState(context);
    CGContextClipToMask(context, source.bounds, source.image.CGImage);

    self.imageColor = [UIColor colorWithHue:hue saturation:1.0 brightness:1 alpha:1.0];
    [self.imageColor set];
    CGContextFillRect(context, source.bounds);

    // Draw the hue on top of the image.
    CGContextSetBlendMode(context, kCGBlendModeHue);
    [self.imageColor set];

    UIBezierPath *imagePath = [UIBezierPath bezierPathWithRect:imageExtent];
    [imagePath fill];

    CGContextRestoreGState(context); // remove clip region

    // Retrieve the new image.
    UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return result;
}