2010-04-14 14 views
38

Desarrollo una aplicación en la que proceso la imagen utilizando sus píxeles, pero en ese proceso de imagen lleva mucho tiempo. Por lo tanto quiero recortar UIImage (Sólo parte media de la imagen, es decir la eliminación/croping bordeado parte de la imagen) .I tienen el código de desarrollo son,Cómo recortar el UIImage?

- (NSInteger) processImage1: (UIImage*) image 
{ 

CGFloat width = image.size.width; 
CGFloat height = image.size.height; 
struct pixel* pixels = (struct pixel*) calloc(1, image.size.width * image.size.height * sizeof(struct pixel)); 
if (pixels != nil) 
{ 
    // Create a new bitmap 
    CGContextRef context = CGBitmapContextCreate(
       (void*) pixels, 
       image.size.width, 
       image.size.height, 
       8, 
       image.size.width * 4, 
       CGImageGetColorSpace(image.CGImage), 
       kCGImageAlphaPremultipliedLast 
      ); 
    if (context != NULL) 
    { 
    // Draw the image in the bitmap 
    CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, image.size.width, image.size.height), image.CGImage); 
    NSUInteger numberOfPixels = image.size.width * image.size.height; 

    NSMutableArray *numberOfPixelsArray = [[[NSMutableArray alloc] initWithCapacity:numberOfPixelsArray] autorelease]; 
} 

Cómo me tomo (Croping fuera confinado) la parte media de UIImage? ????????

Respuesta

78

intentar algo como esto:

CGImageRef imageRef = CGImageCreateWithImageInRect([largeImage CGImage], cropRect); 
image = [UIImage imageWithCGImage:imageRef]; 
CGImageRelease(imageRef); 

Nota: cropRect es rectángulo más pequeño con la parte media de la imagen ...

+0

mihirpmehta , ahora estoy tratando de hacer algo como eso, - (UIImage *) cropedImage: (UIImage *) image { \t CGFloat width = image.size.width; \t CGFloat height = image.size.height; \t UIImage * cropedImage = [[UIImage alloc] init]; \t CGFloat widthCrop = (image.size.width)/2; \t CGFloat heightCrop = (image.size.height)/2; \t } Después de eso no puedo visualizar qué hacer? –

+0

obtener nuevo X y New Y como OldX + OldX/4 y OldY + OldY/4 y hacer un rectángulo con un nuevo ancho de altura NewX y NewY y usarlo como cropRect –

+0

@mihirpmehta, su método anterior es simplemente dibujar la imagen especular del original imagen en el rectángulo cropRect. No se pudo procesar el UIImage. –

38

Yo estaba buscando una manera de obtener una cosecha rectangular arbitraria (es decir. , sub-imagen) de un UIImage.

La mayoría de las soluciones que probé no funcionan si la orientación de la imagen no es otra que UIImageOrientationUp.

Por ejemplo:

http://www.hive05.com/2008/11/crop-an-image-using-the-iphone-sdk/

Normalmente si utiliza la cámara del iPhone, que tendrá como otras orientaciones UIImageOrientationLeft, y no obtendrá una cosecha correcta con lo anterior. Esto se debe al uso de CGImageRef/CGContextDrawImage que difieren en el sistema de coordenadas con respecto a UIImage.

El código siguiente utiliza métodos UI * (sin CGImageRef), y lo he probado con imágenes orientadas hacia arriba/abajo/izquierda/derecha, y parece funcionar muy bien.


// get sub image 
- (UIImage*) getSubImageFrom: (UIImage*) img WithRect: (CGRect) rect { 

    UIGraphicsBeginImageContext(rect.size); 
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    // translated rectangle for drawing sub image 
    CGRect drawRect = CGRectMake(-rect.origin.x, -rect.origin.y, img.size.width, img.size.height); 

    // clip to the bounds of the image context 
    // not strictly necessary as it will get clipped anyway? 
    CGContextClipToRect(context, CGRectMake(0, 0, rect.size.width, rect.size.height)); 

    // draw image 
    [img drawInRect:drawRect]; 

    // grab image 
    UIImage* subImage = UIGraphicsGetImageFromCurrentImageContext(); 

    UIGraphicsEndImageContext(); 

    return subImage; 
} 
 
+2

Solo tenga en cuenta que solo puede ejecutar el código anterior en el hilo principal. La ventaja de evitar 'UIGraphicsBeginImageContext', etc. es eludir esta limitación. –

+1

@William Denniss ¿estás seguro? http://stackoverflow.com/questions/11528803/is-uigraphicsbeginimagecontext-thread-safe/11530675#11530675 – Klaas

+0

@Klass, tienes razón, desde iOS 4 puedes llamarlo en cualquier hilo. Sin embargo, el código ** aún no es seguro para subprocesos **, solo puede usar 'UIGraphicsBeginImageContext' en un subproceso a la vez. El estado de los documentos: "Crea un contexto de gráficos basado en mapas de bits y lo convierte en el contexto actual". Creo que este "contexto actual" es global y, por lo tanto, no es seguro. Mi aplicación procesa varias imágenes a la vez, y tuve bloqueos al usar 'UIGraphicsBeginImageContext' en varios hilos, así que cambié a usar' CGContextRef''s que son seguros para subprocesos. –

2

Sería en última instancia, ser más rápido, con mucho menos creación de la imagen de los atlas de sprites, si se puede establecer no sólo la imagen de un UIImageView, sino también el desplazamiento para mostrar dentro de ese UIImage superior izquierda. Quizás esto es posible. ¡Sin duda eliminaría mucho esfuerzo!

Mientras tanto, creé estas útiles funciones en una clase de utilidad que utilizo en mis aplicaciones. Crea un UIImage de parte de otro UIImage, con opciones para rotar, escalar y voltear utilizando los valores de UIImageOrientation estándar para especificar. La escala de píxeles se preserva de la imagen original.

Mi aplicación crea muchos UIImages durante la inicialización, y esto necesariamente lleva tiempo. Pero algunas imágenes no son necesarias hasta que se selecciona una determinada pestaña. Para dar la apariencia de una carga más rápida, podría crearlos en un hilo separado creado al inicio, luego simplemente espere hasta que esté listo cuando se seleccione esa pestaña.

Este código también se encuentra publicada en Most efficient way to draw part of an image in iOS

+ (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)aperture { 
    return [ChordCalcController imageByCropping:imageToCrop toRect:aperture withOrientation:UIImageOrientationUp]; 
} 

// Draw a full image into a crop-sized area and offset to produce a cropped, rotated image 
+ (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)aperture withOrientation:(UIImageOrientation)orientation { 

      // convert y coordinate to origin bottom-left 
    CGFloat orgY = aperture.origin.y + aperture.size.height - imageToCrop.size.height, 
      orgX = -aperture.origin.x, 
      scaleX = 1.0, 
      scaleY = 1.0, 
      rot = 0.0; 
    CGSize size; 

    switch (orientation) { 
     case UIImageOrientationRight: 
     case UIImageOrientationRightMirrored: 
     case UIImageOrientationLeft: 
     case UIImageOrientationLeftMirrored: 
      size = CGSizeMake(aperture.size.height, aperture.size.width); 
      break; 
     case UIImageOrientationDown: 
     case UIImageOrientationDownMirrored: 
     case UIImageOrientationUp: 
     case UIImageOrientationUpMirrored: 
      size = aperture.size; 
      break; 
     default: 
      assert(NO); 
      return nil; 
    } 


    switch (orientation) { 
     case UIImageOrientationRight: 
      rot = 1.0 * M_PI/2.0; 
      orgY -= aperture.size.height; 
      break; 
     case UIImageOrientationRightMirrored: 
      rot = 1.0 * M_PI/2.0; 
      scaleY = -1.0; 
      break; 
     case UIImageOrientationDown: 
      scaleX = scaleY = -1.0; 
      orgX -= aperture.size.width; 
      orgY -= aperture.size.height; 
      break; 
     case UIImageOrientationDownMirrored: 
      orgY -= aperture.size.height; 
      scaleY = -1.0; 
      break; 
     case UIImageOrientationLeft: 
      rot = 3.0 * M_PI/2.0; 
      orgX -= aperture.size.height; 
      break; 
     case UIImageOrientationLeftMirrored: 
      rot = 3.0 * M_PI/2.0; 
      orgY -= aperture.size.height; 
      orgX -= aperture.size.width; 
      scaleY = -1.0; 
      break; 
     case UIImageOrientationUp: 
      break; 
     case UIImageOrientationUpMirrored: 
      orgX -= aperture.size.width; 
      scaleX = -1.0; 
      break; 
    } 

    // set the draw rect to pan the image to the right spot 
    CGRect drawRect = CGRectMake(orgX, orgY, imageToCrop.size.width, imageToCrop.size.height); 

    // create a context for the new image 
    UIGraphicsBeginImageContextWithOptions(size, NO, imageToCrop.scale); 
    CGContextRef gc = UIGraphicsGetCurrentContext(); 

    // apply rotation and scaling 
    CGContextRotateCTM(gc, rot); 
    CGContextScaleCTM(gc, scaleX, scaleY); 

    // draw the image to our clipped context using the offset rect 
    CGContextDrawImage(gc, drawRect, imageToCrop.CGImage); 

    // pull the image from our cropped context 
    UIImage *cropped = UIGraphicsGetImageFromCurrentImageContext(); 

    // pop the context to get back to the default 
    UIGraphicsEndImageContext(); 

    // Note: this is autoreleased 
    return cropped; 
} 
+0

Gracias. ¿Cuál debería ser la Orientación que envío para la imagen si la tomé de la cámara AVFoundation que rota las imágenes? – Dejell

0

Si quieres un retrato de cultivos por el centro de cada foto.

Utilice la solución @ M-V, & reemplace cropRect.

CGFloat height = imageTaken.size.height; 
CGFloat width = imageTaken.size.width; 

CGFloat newWidth = height * 9/16; 
CGFloat newX = abs((width - newWidth))/2; 

CGRect cropRect = CGRectMake(newX,0, newWidth ,height); 
0

quería ser capaz de recortar de una región sobre la base de una relación de aspecto, y la escala a un tamaño sobre la base de una medida de delimitación exterior.Aquí está mi variación:

import AVFoundation 
import ImageIO 

class Image { 

    class func crop(image:UIImage, source:CGRect, aspect:CGSize, outputExtent:CGSize) -> UIImage { 

     let sourceRect = AVMakeRectWithAspectRatioInsideRect(aspect, source) 
     let targetRect = AVMakeRectWithAspectRatioInsideRect(aspect, CGRect(origin: CGPointZero, size: outputExtent)) 

     let opaque = true, deviceScale:CGFloat = 0.0 // use scale of device's main screen 
     UIGraphicsBeginImageContextWithOptions(targetRect.size, opaque, deviceScale) 

     let scale = max(
      targetRect.size.width/sourceRect.size.width, 
      targetRect.size.height/sourceRect.size.height) 

     let drawRect = CGRect(origin: -sourceRect.origin * scale, size: image.size * scale) 
     image.drawInRect(drawRect) 

     let scaledImage = UIGraphicsGetImageFromCurrentImageContext() 
     UIGraphicsEndImageContext() 

     return scaledImage 
    } 
} 

Hay un par de cosas que me pareció confuso, las preocupaciones separadas de recorte y cambio de tamaño. El recorte se maneja con el origen del rect que pasa a drawInRect, y la escala se maneja mediante la porción de tamaño. En mi caso, necesitaba relacionar el tamaño del recorte de la fuente con mi salida de la misma relación de aspecto. El factor de escala es entonces salida/entrada, y esto debe aplicarse al drawRect (pasado a drawInRect).

Una advertencia es que este enfoque supone efectivamente que la imagen que está dibujando es más grande que el contexto de la imagen. No he probado esto, pero creo que puede usar este código para manejar el recorte/acercamiento, pero definiendo explícitamente el parámetro de escala como el parámetro de escala antes mencionado. Por defecto, UIKit aplica un multiplicador basado en la resolución de la pantalla.

Por último, cabe señalar que este enfoque UIKit es de un nivel más alto que los enfoques CoreGraphics/Quartz y Core Image, y parece que maneja problemas de orientación de la imagen. También vale la pena mencionar que es bastante rápido, en segundo lugar a ImageIO, de acuerdo con este post aquí: http://nshipster.com/image-resizing/

1

Porque lo necesitaba ahora, aquí está el código MV 's en Swift 4:

func imageWithImage(image: UIImage, croppedTo rect: CGRect) -> UIImage { 

    UIGraphicsBeginImageContext(rect.size) 
    let context = UIGraphicsGetCurrentContext() 

    let drawRect = CGRect(x: -rect.origin.x, y: -rect.origin.y, 
          width: image.size.width, height: image.size.height) 

    context?.clip(to: CGRect(x: 0, y: 0, 
          width: rect.size.width, height: rect.size.height)) 

    image.draw(in: drawRect) 

    let subImage = UIGraphicsGetImageFromCurrentImageContext() 

    UIGraphicsEndImageContext() 
    return subImage! 
}