2012-06-27 16 views
8

Me gustaría probar algunas funciones de filtro de imagen en iPhone como instagram. Uso imagePickerController para obtener una foto del carrete de la cámara. Entiendo que la imagen devuelta por imagePickerController se redujo para ahorrar memoria. Y no es prudente cargar la imagen original en un UIImage. Pero, ¿cómo puedo procesar la imagen y luego guardarla como los píxeles originales? Uso iPhone 4S como mi dispositivo de desarrollo.¿Cómo se realiza el corte cuadrado de las fotos en el rollo de la cámara?

La foto original en rollo de la cámara es de 3264 * 2448.

El retorno imagen UIImagePickerControllerOriginalImage es 1920 * 1440

El retorno imagen UIImagePickerControllerEditedImage es 640 * 640

imageViewOld (utilizar UIImagePickerControllerCropRect [ 80,216,1280,1280] para recortar la imagen devuelta por UIImagePickerControllerOriginalImage) es 1280 * 1224

imageViewNew (utilice el UIImagePickerControll de doble tamaño erCropRect [80,216,2560,2560] para recortar la imagen de retorno por UIImagePickerControllerOriginalImage) es 1840 * 1224.

verifico la misma foto proceder por Instagram es 1280 * 1280

Mis preguntas son:

  1. ¿Por qué UIImagePickerControllerOriginalImage no devuelve la foto "Original"? ¿Por qué se redujo a 1920 * 1440?
  2. ¿Por qué UIImagePickerControllerEditedImage no devuelve la imagen por 1280 * 1280? Como el
    UIImagePickerControllerCropRect muestra que está cortado por 1280 * 1280 cuadrados?

  3. ¿Cómo puedo hacer un corte cuadrado en la foto original para que sea una imagen 2448 * 2448?

Gracias de antemano. A continuación es mi código:

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info 
    { 

    NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType]; 
    if ([mediaType isEqualToString:@"public.image"]) 
    { 

    UIImage *imageEdited = [info objectForKey:UIImagePickerControllerEditedImage]; 
    UIImage *imagePicked = [info objectForKey:UIImagePickerControllerOriginalImage]; 

    CGRect cropRect; 
    cropRect = [[info valueForKey:@"UIImagePickerControllerCropRect"] CGRectValue]; 

    NSLog(@"Original width = %f height= %f ",imagePicked.size.width, imagePicked.size.height); 
    //Original width = 1440.000000 height= 1920.000000 

    NSLog(@"imageEdited width = %f height = %f",imageEdited.size.width, imageEdited.size.height); 
    //imageEdited width = 640.000000 height = 640.000000 

    NSLog(@"corpRect %f %f %f %f", cropRect.origin.x, cropRect.origin.y , cropRect.size.width, cropRect.size.height); 
    //corpRect 80.000000 216.000000 1280.000000 1280.000000 

    CGRect rectNew = CGRectMake(cropRect.origin.x, cropRect.origin.y , cropRect.size.width*2, cropRect.size.height*2); 

    CGRect rectOld = CGRectMake(cropRect.origin.x, cropRect.origin.y , cropRect.size.width, cropRect.size.height); 

    CGImageRef imageRefNew = CGImageCreateWithImageInRect([imagePicked CGImage], rectNew); 
    CGImageRef imageRefOld = CGImageCreateWithImageInRect([imagePicked CGImage], rectOld); 

    UIImageView *imageViewNew = [[UIImageView alloc] initWithImage:[UIImage imageWithCGImage:imageRefNew]]; 
    CGImageRelease(imageRefNew); 

    UIImageView *imageViewOld = [[UIImageView alloc] initWithImage:[UIImage imageWithCGImage:imageRefOld]]; 
    CGImageRelease(imageRefOld); 


    NSLog(@"imageViewNew width = %f height = %f",imageViewNew.image.size.width, imageViewNew.image.size.height); 
    //imageViewNew width = 1840.000000 height = 1224.000000 

    NSLog(@"imageViewOld width = %f height = %f",imageViewOld.image.size.width, imageViewOld.image.size.height); 
    //imageViewOld width = 1280.000000 height = 1224.000000 

    UIImageWriteToSavedPhotosAlbum(imageEdited, nil, nil, NULL); 

    UIImageWriteToSavedPhotosAlbum([imageViewNew.image imageRotatedByDegrees:90.0], nil, nil, NULL); 
    UIImageWriteToSavedPhotosAlbum([imageViewOld.image imageRotatedByDegrees:90.0], nil, nil, NULL); 


    //assign the image to an UIImage Control 
    self.imageV.contentMode = UIViewContentModeScaleAspectFit; 
    self.imageV.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.width); 
    self.imageV.image = imageEdited; 


    } 

    [self dismissModalViewControllerAnimated:YES]; 

} 

Respuesta

12

Como se ha observado la UIImagePickerController devolverá una imagen editada reducido a veces a veces 640x640 320x320 (en función del dispositivo).

Su pregunta:

¿Cómo puedo hacer un corte cuadrado de foto original para ser una imagen de 2448 * 2448?

Para hacer esto es necesario utilizar por primera vez el UIImagePickerControllerCropRect para crear una nueva imagen de la imagen original obtenido mediante la tecla UIImagePickerControllerOriginalImage del diccionario de datos. Usando el método Quartz Core, CGImageCreateWithImageInRect, puede crear una nueva imagen que solo contenga los píxeles limitados por el rect aprobado; en este caso, el cultivo rect. Deberá tener en cuenta la orientación para que esto funcione correctamente. Entonces solo necesita escalar la imagen al tamaño deseado. Es importante tener en cuenta que el recorte es relativo a la imagen original cuando se ha orientado correctamente, no como sale de la cámara o la fototeca. Esta es la razón por la cual necesitamos transformar el recorte de cultivos para que coincida con la orientación cuando comenzamos a usar métodos de Quartz para crear nuevas imágenes, etc.

Tomé el código anterior y lo configuré para crear una imagen de 1280x1280 a partir de la imagen original basada en el recorte. Todavía hay algunos casos de borde aquí, es decir, teniendo en cuenta que el recorte de cultivos a veces puede tener valores negativos (el código asume un corte cuadrado) que no se han abordado.

  1. Primero, transforme el recorte para tener en cuenta la orientación de la imagen y el tamaño de entrada. Esta función transformCGRectForUIImageOrientation es de NiftyBean
  2. Cree una imagen recortada en el recorte transformado.
  3. Escale (y gire) la imagen al tamaño deseado. es decir, 1280x1280.
  4. Crea un UIImage del CGImage con escala y orientación correctas.

Aquí es el código con los cambios: ACTUALIZACIÓN nuevo código ha sido añadido por debajo de este que debe hacerse cargo de los casos que faltan.

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { 
NSString *mediaType = [info objectForKey:UIImagePickerControllerMediaType]; 
if ([mediaType isEqualToString:@"public.image"]) 
{ 

    UIImage *imageEdited = [info objectForKey:UIImagePickerControllerEditedImage]; 
    UIImage *imagePicked = [info objectForKey:UIImagePickerControllerOriginalImage]; 

    CGRect cropRect; 
    cropRect = [[info valueForKey:@"UIImagePickerControllerCropRect"] CGRectValue]; 

    NSLog(@"Original width = %f height= %f ",imagePicked.size.width, imagePicked.size.height); 
    //Original width = 1440.000000 height= 1920.000000 

    NSLog(@"imageEdited width = %f height = %f",imageEdited.size.width, imageEdited.size.height); 
    //imageEdited width = 640.000000 height = 640.000000 

    NSLog(@"corpRect %@", NSStringFromCGRect(cropRect)); 
    //corpRect 80.000000 216.000000 1280.000000 1280.000000 

    CGSize finalSize = CGSizeMake(1280,1280); 
    CGImageRef imagePickedRef = imagePicked.CGImage; 

    CGRect transformedRect = transformCGRectForUIImageOrientation(cropRect, imagePicked.imageOrientation, imagePicked.size); 
    CGImageRef cropRectImage = CGImageCreateWithImageInRect(imagePickedRef, transformedRect); 
    CGColorSpaceRef colorspace = CGImageGetColorSpace(imagePickedRef); 
    CGContextRef context = CGBitmapContextCreate(NULL, 
               finalSize.width, 
               finalSize.height, 
               CGImageGetBitsPerComponent(imagePickedRef), 
               CGImageGetBytesPerRow(imagePickedRef), 
               colorspace, 
               CGImageGetAlphaInfo(imagePickedRef)); 
    CGContextSetInterpolationQuality(context, kCGInterpolationHigh); //Give the context a hint that we want high quality during the scale 
    CGContextDrawImage(context, CGRectMake(0, 0, finalSize.width, finalSize.height), cropRectImage); 
    CGImageRelease(cropRectImage); 

    CGImageRef instaImage = CGBitmapContextCreateImage(context); 
    CGContextRelease(context); 

    //assign the image to an UIImage Control 
    UIImage *image = [UIImage imageWithCGImage:instaImage scale:imagePicked.scale orientation:imagePicked.imageOrientation]; 
    self.imageView.contentMode = UIViewContentModeScaleAspectFit; 
    self.imageView.image = image; 
    CGImageRelease(instaImage); 

    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil); 
} 

[self dismissModalViewControllerAnimated:YES]; 

}

CGRect transformCGRectForUIImageOrientation(CGRect source, UIImageOrientation orientation, CGSize imageSize) { 
switch (orientation) { 
    case UIImageOrientationLeft: { // EXIF #8 
     CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(imageSize.height, 0.0); 
     CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI_2); 
     return CGRectApplyAffineTransform(source, txCompound); 
    } 
    case UIImageOrientationDown: { // EXIF #3 
     CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height); 
     CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI); 
     return CGRectApplyAffineTransform(source, txCompound); 
    } 
    case UIImageOrientationRight: { // EXIF #6 
     CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(0.0, imageSize.width); 
     CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI + M_PI_2); 
     return CGRectApplyAffineTransform(source, txCompound); 
    } 
    case UIImageOrientationUp: // EXIF #1 - do nothing 
    default: // EXIF 2,4,5,7 - ignore 
     return source; 
} 
} 

ACTUALIZACIÓN he hecho un par de métodos que se hará cargo del resto de los casos. Los pasos son básicamente los mismos, con un par de modificaciones.

  1. primera modificación es transformar correctamente y escalar el contexto de manejar la orientación de la imagen de entrada,
  2. y el segundo es apoyar los cultivos no cuadrados que puede obtener de la UIImagePickerController. En estos casos, la imagen cuadrada es con el color que elija.

Nuevo Código

// CropRect is assumed to be in UIImageOrientationUp, as it is delivered this way from the UIImagePickerController when using AllowsImageEditing is on. 
// The sourceImage can be in any orientation, the crop will be transformed to match 
// The output image bounds define the final size of the image, the image will be scaled to fit,(AspectFit) the bounds, the fill color will be 
// used for areas that are not covered by the scaled image. 
-(UIImage *)cropImage:(UIImage *)sourceImage cropRect:(CGRect)cropRect aspectFitBounds:(CGSize)finalImageSize fillColor:(UIColor *)fillColor { 

CGImageRef sourceImageRef = sourceImage.CGImage; 

//Since the crop rect is in UIImageOrientationUp we need to transform it to match the source image. 
CGAffineTransform rectTransform = [self transformSize:sourceImage.size orientation:sourceImage.imageOrientation]; 
CGRect transformedRect = CGRectApplyAffineTransform(cropRect, rectTransform); 

//Now we get just the region of the source image that we are interested in. 
CGImageRef cropRectImage = CGImageCreateWithImageInRect(sourceImageRef, transformedRect); 

//Figure out which dimension fits within our final size and calculate the aspect correct rect that will fit in our new bounds 
CGFloat horizontalRatio = finalImageSize.width/CGImageGetWidth(cropRectImage); 
CGFloat verticalRatio = finalImageSize.height/CGImageGetHeight(cropRectImage); 
CGFloat ratio = MIN(horizontalRatio, verticalRatio); //Aspect Fit 
CGSize aspectFitSize = CGSizeMake(CGImageGetWidth(cropRectImage) * ratio, CGImageGetHeight(cropRectImage) * ratio); 


CGContextRef context = CGBitmapContextCreate(NULL, 
              finalImageSize.width, 
              finalImageSize.height, 
              CGImageGetBitsPerComponent(cropRectImage), 
              0, 
              CGImageGetColorSpace(cropRectImage), 
              CGImageGetBitmapInfo(cropRectImage)); 

if (context == NULL) { 
    NSLog(@"NULL CONTEXT!"); 
} 

//Fill with our background color 
CGContextSetFillColorWithColor(context, fillColor.CGColor); 
CGContextFillRect(context, CGRectMake(0, 0, finalImageSize.width, finalImageSize.height)); 

//We need to rotate and transform the context based on the orientation of the source image. 
CGAffineTransform contextTransform = [self transformSize:finalImageSize orientation:sourceImage.imageOrientation]; 
CGContextConcatCTM(context, contextTransform); 

//Give the context a hint that we want high quality during the scale 
CGContextSetInterpolationQuality(context, kCGInterpolationHigh); 

//Draw our image centered vertically and horizontally in our context. 
CGContextDrawImage(context, CGRectMake((finalImageSize.width-aspectFitSize.width)/2, (finalImageSize.height-aspectFitSize.height)/2, aspectFitSize.width, aspectFitSize.height), cropRectImage); 

//Start cleaning up.. 
CGImageRelease(cropRectImage); 

CGImageRef finalImageRef = CGBitmapContextCreateImage(context); 
UIImage *finalImage = [UIImage imageWithCGImage:finalImageRef]; 

CGContextRelease(context); 
CGImageRelease(finalImageRef); 
return finalImage; 
} 

//Creates a transform that will correctly rotate and translate for the passed orientation. 
//Based on code from niftyBean.com 
- (CGAffineTransform) transformSize:(CGSize)imageSize orientation:(UIImageOrientation)orientation { 

CGAffineTransform transform = CGAffineTransformIdentity; 
switch (orientation) { 
    case UIImageOrientationLeft: { // EXIF #8 
     CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(imageSize.height, 0.0); 
     CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI_2); 
     transform = txCompound; 
     break; 
    } 
    case UIImageOrientationDown: { // EXIF #3 
     CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height); 
     CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,M_PI); 
     transform = txCompound; 
     break; 
    } 
    case UIImageOrientationRight: { // EXIF #6 
     CGAffineTransform txTranslate = CGAffineTransformMakeTranslation(0.0, imageSize.width); 
     CGAffineTransform txCompound = CGAffineTransformRotate(txTranslate,-M_PI_2); 
     transform = txCompound; 
     break; 
    } 
    case UIImageOrientationUp: // EXIF #1 - do nothing 
    default: // EXIF 2,4,5,7 - ignore 
     break; 
} 
return transform; 

} 
+0

Sí! ¡Funciona! ¿Podría decirme por qué UIImagePickerController no me da la imagen original en el rollo de la cámara? – user1486413

+0

No estoy seguro de cuál es el razonamiento detrás de esto. He observado que definitivamente tienes una versión de resolución completa cuando tomas una foto con la cámara. Si necesita obtener la versión de resolución completa, creo que puede usar 'UIImagePickerControllerReferenceURL' en combinación con las clases' ALAssetLibrary' para recuperarla. El uso de este marco le pedirá permiso a sus usuarios para acceder a su ubicación, ya que las imágenes originales tendrán etiquetas geográficas. –

+0

También .. actualizó el código para manejar la rotación de forma más sensata, y también maneja la obtención de una imagen cuadrada incluso cuando el recorte no es cuadrado. Espero eso ayude. –

Cuestiones relacionadas