我可以编辑UIImage的属性CGImage的像素
UIImage有一个只读属性CGImage。 我必须读取它的像素到一个内存块并编辑它们,然后创build一个新的UIImage来replace旧的。 我想知道是否有绕过只读属性和直接编辑这些像素的方法。
谢谢。
谢谢大家。 我find了一个办法。 用这些方法写一个类:
-(void)preProcess:(UIImage*)srcImage { m_Context = ...// Created by calling CGBitmapContextCreate(...) ... CGContextDrawImage(m_Context, rect, srcImage.CGImage); m_Bits = (unsigned char*)CGBitmapContextGetData (mContext); } -(void)postProcess { CGContextRelease(m_Context); free(m_Bits); } -(UIImage*)doProcess:(CGPoint)pt {// just a example unsigned char* ppxl = m_Bits + ... // do something... CGImageRef imRef = CGBitmapContextCreateImage(mContext); return [UIImage imageWithCGImage:imRef]; }
而preProcess和postProcess只被调用一次。
这可能会帮助你。
完成后,可以使用CGImageCreate
创build一个CGImageRef,然后使用+[UIImage imageWithCGImage:]
创build一个新的UIImage。
你不能得到原始的像素。 不过,你可以得到一份副本。 一个select是做马特build议,并将其转换成PNG / JPG – 虽然记住,图像现在压缩,你将操纵压缩的文件,而不是直接的像素。
如果你想得到一个原始像素的副本,你可以做一些事情:
UIImage* image = ...; // An image NSData* pixelData = (NSData*) CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage)); void* pixelBytes = [pixelData bytes]; // Take away the red pixel, assuming 32-bit RGBA for(int i = 0; i < [pixelData length]; i += 4) { bytes[i] = 0; // red bytes[i+1] = bytes[i+1]; // green bytes[i+2] = bytes[i+2]; // blue bytes[i+3] = bytes[i+3]; // alpha }
现在,如果你想把它变成一个新的UIImage,你可以这样做:
NSData* newPixelData = [NSData dataWithBytes:pixelBytes length:[pixelData length]]; UIImage* newImage = [UIImage imageWithData:newPixelData]; // Huzzah
对于我们之间的更加僵硬(阅读:将来我),这里有一些基于Itay和Dave R的答案的工作代码。 它以UIImage开头,并以修改的UIImage结束:
// load image UIImage *image = [UIImage imageNamed:@"test.png"]; CGImageRef imageRef = image.CGImage; NSData *data = (NSData *)CGDataProviderCopyData(CGImageGetDataProvider(imageRef)); char *pixels = (char *)[data bytes]; // this is where you manipulate the individual pixels // assumes a 4 byte pixel consisting of rgb and alpha // for PNGs without transparency use i+=3 and remove int a for(int i = 0; i < [data length]; i += 4) { int r = i; int g = i+1; int b = i+2; int a = i+3; pixels[r] = 0; // eg. remove red pixels[g] = pixels[g]; pixels[b] = pixels[b]; pixels[a] = pixels[a]; } // create a new image from the modified pixel data size_t width = CGImageGetWidth(imageRef); size_t height = CGImageGetHeight(imageRef); size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef); size_t bitsPerPixel = CGImageGetBitsPerPixel(imageRef); size_t bytesPerRow = CGImageGetBytesPerRow(imageRef); CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, [data length], NULL); CGImageRef newImageRef = CGImageCreate ( width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorspace, bitmapInfo, provider, NULL, false, kCGRenderingIntentDefault ); // the modified image UIImage *newImage = [UIImage imageWithCGImage:newImageRef]; // cleanup free(pixels); CGImageRelease(imageRef); CGColorSpaceRelease(colorspace); CGDataProviderRelease(provider); CGImageRelease(newImageRef);
我使用下面的代码在图像的右侧和左侧添加两条细红线
-(UIImage*)ModifyImage:(UIImage*) img { UIGraphicsBeginImageContext(img.size); [img drawInRect:CGRectMake(0,0,img.size.width,img.size.height) blendMode:kCGBlendModeSourceOut alpha:1.0f]; CGContextRef ctx = UIGraphicsGetCurrentContext(); int w =img.size.width; int cw,ch; cw = img.size.width / 35; ch = img.size.height / 35; unsigned char* data = CGBitmapContextGetData (ctx); for(int y = 0 ; y < img.size.height ; y++) { for(int x = 0 ; x < img.size.width ; x++) { //int offset = 4*((w * y) + x); int offset = (CGBitmapContextGetBytesPerRow(ctx)*y) + (4 * x); int blue = data[offset]; int green = data[offset+1]; int red = data[offset+2]; //int alpha = data[offset+3]; if(x <= (cw * 2) || x >= (cw * 35)) { data[offset] = 0; data[offset+1] = 0; data[offset+2] = 255; data[offset+3] = 255; } } } UIImage *rtimg = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return rtimg; }
简短的答案是否定的。 然而,你说你必须做一个副本,所以为什么不只是得到一个NSData对象,并操纵其字节。
从UIImage上的Apple文档:
因为图像对象是不可变的,所以它们也不能直接访问它们的底层图像数据。 但是,您可以使用UIImagePNGRepresentation和UIImageJPEGRepresentation函数获取包含图像数据的PNG或JPEG表示的NSData对象。
要以PNGforms获取数据,请使用:
NSData * UIImagePNGRepresentation ( UIImage *image );
对于JPEG,请使用:
NSData * UIImageJPEGRepresentation ( UIImage *image, CGFloat compressionQuality );
在Shaun的答案中,将NSData *数据行更改为这个,它在iOS7中完美运行!
NSData *data = (NSData *)CFBridgingRelease(CGDataProviderCopyData(CGImageGetDataProvider(imageRef)));
@shaun Inman的post一直是我在网上find的唯一工作! 谢谢! 不过,至less在iOS3中,PNG的颜色保存起来与你所说的有些不同,这对我来说是有用的( 只适用于PNG! ):
for(int i = 0; i < [data length]; i += 4) { pixels[i+0] = 0; // eg. alpha? pixels[i+1] = 0; // eg. red! pixels[i+2] = 0; // eg. green! pixels[i+3] = pixels[i+3]; // eg. blue! }
如果有人能够找出适用于任何文件types的方法,这将是很酷的!