Cómo convertir un object UIImage creado a partir de un CGImageRef en datos brutos y viceversa

Digamos que comienzas con un UIImage y deseas recortarlo. El método más común es usar CGImageCreateWithImageInRect para get un CGImageRef y crear una nueva image del mismo, de esta forma:

CGRect cropRect = CGRectMake(x*width, y*height, width, height); CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect); UIImage *croppedImage = [UIImage imageWithCGImage:imageRef]; 

Ahora digamos que más adelante necesita convertir este UIImage en un object NSData. Por ejemplo, esto ocurrirá si desea almacenar la image en el disco utilizando NSKeyedArchiver. O bien, puede get un object NSData haciendo lo siguiente explícitamente:

 NSData *imageData = UIImagePNGRepresentation(croppedImage); 

Hice esto y más tarde traté de rebuild un nuevo object UIImage haciendo:

 UIImage *image = [UIImage imageWithData:imageData]; 

Hice esto por una serie de 48 imágenes. La mayoría de ellos estaban bien, pero después de cada 4 imágenes, los 2 siguientes se corrompieron con la parte superior e inferior de cada image intercambiada. Si saco la conversión a NSData y return nuevamente, funciona bien. También obtengo exactamente el mismo problema si utilizo NSKeyedArchiver para escribir una matriz de las imágenes en el disco (que supongo que llama algo así como UIImagePNGRepresentation en su rutina de encoding). Mi teoría es que esto debe tener algo que ver con cómo creo las imágenes de CGImageRefs.

¿Cuál es la solución para esto? Parece que no puedo imaginar cómo poner CGImageRefs en el object NSData y prefiero una solución que genere el UIImage correctamente para poder ser serializado.

Editar:

Algunas personas pidieron el código real que se está ejecutando, así que lo estoy agregando aquí.

  UIImage *image = self.animationObject.image; for (int y=0; y<[self.animationInfoObject.numInY intValue]; y++) { for (int x=0; x<[self.animationInfoObject.numInX intValue]; x++) { CGRect cropRect = CGRectMake(x*width, y*height, width, height); CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], cropRect); UIImage *croppedImage = [UIImage imageWithCGImage:imageRef]; NSData *imageData = UIImageJPEGRepresentation(croppedImage, 1.0); [self addImageToArray:imageData]; CFRelease(imageRef); } } 

La image de self.animationObject.image es una grilla de imágenes con numInX e y numInY imágenes en cada dirección. Recorto cada image individual de la cuadrícula en 2D y las guardo.

Más tarde, coloqué las imágenes en una vista de image para animarlas. Aquí está el código:

  NSMutableArray *animationArray = [[NSMutableArray alloc] init]; for (int frame=0; frame<[[photoObject frameArray] count]; frame++) { NSData *imageData =[[photoObject imageArray] objectAtIndex:[[[photoObject frameArray] objectAtIndex:frame] integerValue]-1]; UIImage *image = [UIImage imageWithData:imageData]; [animationArray addObject:image]; } 

Todo funciona bien en un iPhone 6, pero no funciona en un iPhone 5. También parece ser un problema cuando la grilla de imágenes es larga. Por ejemplo, para el ejemplo estoy utilizando self.animationObject.image tiene numInY como 3 y numInX 2 y el tamaño total de la image es 1536×3072 (cada miniimage es 768×1024). Es la parte inferior dos imágenes que tienen sus partes superiores e inferiores volteadas.

Su problema se debe a la orientación de la image.
Cada UIImage contiene una propiedad -imageOrientation que define la orientación que se debería aplicar en el UIImage una vez que se visualiza en la pantalla, cuando se solicita la CGImage se pierde esa información.
Si obtienes tu image de la camera dentro del dictionary de metadatos proporcionado, también encontrarás la orientación EXIF, por lo que depende de dónde vengas.
En mi blog escribí un artículo sobre eso y cómo manejarlos correctamente si la image proviene de la camera.
Una solución rápida podría leerse la propiedad CGImage y aplicar una transformación de acuerdo con la propiedad -imageOrientation . Puedes encontrar diferentes forms aquí y aquí.

Este fragment se toma de aquí , créditos para el lobo

 - (UIImage *)croppedImageInRect:(CGRect)rect { double (^rad)(double) = ^(double deg) { return deg / 180.0 * M_PI; }; CGAffineTransform rectTransform; switch (self.imageOrientation) { case UIImageOrientationLeft: rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(90)), 0, -self.size.height); break; case UIImageOrientationRight: rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-90)), -self.size.width, 0); break; case UIImageOrientationDown: rectTransform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(rad(-180)), -self.size.width, -self.size.height); break; default: rectTransform = CGAffineTransformIdentity; }; rectTransform = CGAffineTransformScale(rectTransform, self.scale, self.scale); CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], CGRectApplyAffineTransform(rect, rectTransform)); UIImage *result = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation]; CGImageRelease(imageRef); return result; }