使用石英 2D 从透明 png 交换 UIImage 上的颜色通道
Swap color channels on UIImage from transparent png with quartz 2D
我有一个奇怪的问题。我想交换从 png 加载的 UIImage 的红色和绿色通道。我查找了示例并使用了以下代码,它适用于没有透明度的 png 图像:
- (UIImage *)redToGreen {
CGImageRef imgRef = [self CGImage];
size_t width = CGImageGetWidth(imgRef);
size_t height = CGImageGetHeight(imgRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
size_t bitsPerComponent = 8;
size_t bytesPerPixel = 4;
size_t bytesPerRow = bytesPerPixel * width;
size_t totalBytes = bytesPerRow * height;
//Allocate Image space
uint8_t* rawData = malloc(totalBytes);
//Create Bitmap of same size
CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
//Draw our image to the context
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imgRef);
for ( int i = 0; i < totalBytes; i += 4 ) {
uint8_t* red = rawData + i;
uint8_t* green = rawData + (i + 1);
uint8_t red_old = *red;
*red = *green;
*green = red_old;
}
//Create Image
CGImageRef newImg = CGBitmapContextCreateImage(context);
//Release Created Data Structs
CGColorSpaceRelease(colorSpace);
CGContextRelease(context);
free(rawData);
//Create UIImage struct around image
UIImage* newImage = [UIImage imageWithCGImage:newImg];
//Release our hold on the image
CGImageRelease(newImg);
//return new image!
return newImage;
}
但是,当我在透明 png 上尝试时,我在背景中看到了奇怪的人工制品。
例如这张透明图片:
在黑色背景上加载显示为:
我在代码中所做的是:
[btn setImage:[[UIImage imageNamed:@"trash.png"] redToGreen] forState:UIControlStateNormal];
我尝试更改 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big 因为有不同的例子,但似乎没有任何效果。有什么想法吗?
更新:
我觉得很奇怪这段代码被复制粘贴而没有抱怨。除了已接受的答案所指示的未清除缓冲区的问题外,另一个缺陷是比例始终设置为 1,因此如果您打开 @2x 图像,结果将具有两倍的磅值。制作 UIImage 的正确调用是:
UIImage* newImage = [UIImage imageWithCGImage:newImg scale:self.scale orientation:self.imageOrientation];
创建位图上下文时,它不会清除缓冲区。 (例如,使用包含预先存在的图像的缓冲区创建位图上下文是非常明智的。)
有两种方法:
1) 在绘制原始图像之前明确清除它,使用CGContextClearRect()
2) 在绘制原始图像之前将上下文的混合模式设置为 "copy",以便它 "paints over" 缓冲区中可能存在的任何垃圾;你会用 CGContextSetBlendMode(context, kCGBlendModeCopy)
来做到这一点
我有一个奇怪的问题。我想交换从 png 加载的 UIImage 的红色和绿色通道。我查找了示例并使用了以下代码,它适用于没有透明度的 png 图像:
- (UIImage *)redToGreen {
CGImageRef imgRef = [self CGImage];
size_t width = CGImageGetWidth(imgRef);
size_t height = CGImageGetHeight(imgRef);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
size_t bitsPerComponent = 8;
size_t bytesPerPixel = 4;
size_t bytesPerRow = bytesPerPixel * width;
size_t totalBytes = bytesPerRow * height;
//Allocate Image space
uint8_t* rawData = malloc(totalBytes);
//Create Bitmap of same size
CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);
//Draw our image to the context
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imgRef);
for ( int i = 0; i < totalBytes; i += 4 ) {
uint8_t* red = rawData + i;
uint8_t* green = rawData + (i + 1);
uint8_t red_old = *red;
*red = *green;
*green = red_old;
}
//Create Image
CGImageRef newImg = CGBitmapContextCreateImage(context);
//Release Created Data Structs
CGColorSpaceRelease(colorSpace);
CGContextRelease(context);
free(rawData);
//Create UIImage struct around image
UIImage* newImage = [UIImage imageWithCGImage:newImg];
//Release our hold on the image
CGImageRelease(newImg);
//return new image!
return newImage;
}
但是,当我在透明 png 上尝试时,我在背景中看到了奇怪的人工制品。
例如这张透明图片:
在黑色背景上加载显示为:
我在代码中所做的是:
[btn setImage:[[UIImage imageNamed:@"trash.png"] redToGreen] forState:UIControlStateNormal];
我尝试更改 kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big 因为有不同的例子,但似乎没有任何效果。有什么想法吗?
更新: 我觉得很奇怪这段代码被复制粘贴而没有抱怨。除了已接受的答案所指示的未清除缓冲区的问题外,另一个缺陷是比例始终设置为 1,因此如果您打开 @2x 图像,结果将具有两倍的磅值。制作 UIImage 的正确调用是:
UIImage* newImage = [UIImage imageWithCGImage:newImg scale:self.scale orientation:self.imageOrientation];
创建位图上下文时,它不会清除缓冲区。 (例如,使用包含预先存在的图像的缓冲区创建位图上下文是非常明智的。)
有两种方法:
1) 在绘制原始图像之前明确清除它,使用CGContextClearRect()
2) 在绘制原始图像之前将上下文的混合模式设置为 "copy",以便它 "paints over" 缓冲区中可能存在的任何垃圾;你会用 CGContextSetBlendMode(context, kCGBlendModeCopy)
来做到这一点