¿Puedo editar los píxeles de la propiedad del UIImage CGImage

UIImage tiene una propiedad de solo lectura CGImage. Tengo que leer sus píxeles en un bloque de memoria y editarlos y luego hacer un nuevo UIImage para reemplazar el anterior. Quiero saber si hay una manera de eludir la propiedad de solo lectura y editar esos píxeles directamente.

Gracias.


Gracias a todos. He encontrado una manera de hacerlo. Escribe una clase con esos métodos:

-(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]; } 

Y preProcess y postProcess se llaman solo una vez.

Esto puede ayudarte.

Cuando hayas terminado, puedes usar CGImageCreate para crear un CGImageRef, luego usar +[UIImage imageWithCGImage:] para crear un nuevo UIImage.

No puedes obtener los píxeles originales. Sin embargo, puedes obtener una copia. Una opción es hacer lo que sugirió Matt, y convertirlo en PNG / JPG, aunque recuerde, la imagen ahora está comprimida, y manipulará el archivo comprimido y no los píxeles directamente.

Si desea obtener una copia de los píxeles sin formato, puede hacer algo como:

 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 } 

Ahora, si quisieras convertir esto en un UIImage nuevo, puedes hacer algo como:

 NSData* newPixelData = [NSData dataWithBytes:pixelBytes length:[pixelData length]]; UIImage* newImage = [UIImage imageWithData:newPixelData]; // Huzzah 

Para los más obtusos entre nosotros (léase: futuro yo) aquí hay un código de trabajo basado en las respuestas de Itay y Dave R. Comienza con un UIImage y termina con un UIImage modificado:

  // 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); 

Usé el siguiente código para agregar 2 líneas rojas finas a la derecha e izquierda de una imagen

 -(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; } 

La respuesta corta es no. Sin embargo, dices que tienes que hacer una copia de todos modos, ¿por qué no simplemente obtener un objeto NSData y manipular sus bytes?

De los documentos de Apple en UIImage:

Debido a que los objetos de imagen son inmutables, tampoco brindan acceso directo a sus datos de imagen subyacentes. Sin embargo, puede obtener un objeto NSData que contenga una representación PNG o JPEG de los datos de imagen utilizando las funciones UIImagePNGRepresentation y UIImageJPEGRepresentation.

Para obtener los datos como PNG, use:

 NSData * UIImagePNGRepresentation ( UIImage *image ); 

para JPEG, use:

 NSData * UIImageJPEGRepresentation ( UIImage *image, CGFloat compressionQuality ); 

¡Cambie la línea de datos NSData *, en la respuesta de Shaun, a esto y funciona perfectamente en iOS7!

  NSData *data = (NSData *)CFBridgingRelease(CGDataProviderCopyData(CGImageGetDataProvider(imageRef))); 

¡La publicación de @shaun Inman ha sido la única que he encontrado en la web hasta ahora! ¡GRACIAS! Sin embargo, parece que al menos en IOS3 los colores PNG se guardan un poco diferente a lo que usted indicó, esto es lo que funcionó para mí (¡ solo para 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! } 

Sería genial si alguien pudiera encontrar una manera que funcionara para cualquier tipo de archivo!