Tengo un código que cambia el tamaño de una imagen para poder obtener un fragmento escalado del centro de la imagen. Utilizo esto para tomar UIImagey devolver una pequeña representación cuadrada de una imagen, similar a lo que se ve en la vista del álbum de la aplicación Fotos. (Sé que podría usar UIImageVieway ajustar el modo de recorte para lograr los mismos resultados, pero estas imágenes a veces se muestran en UIWebViews).
Empecé a notar algunos bloqueos en este código y estoy un poco perplejo. Tengo dos teorías diferentes y me pregunto si alguna de ellas está en la base.
Teoría 1) Logro el recorte dibujando en un contexto de imagen fuera de pantalla de mi tamaño objetivo. Como quiero la parte central de la imagen, configuro el CGRectargumento pasado drawInRecta algo que es más grande que los límites del contexto de mi imagen. Esperaba que esto fuera kosher, pero ¿estoy tratando de dibujar otro recuerdo que no debería tocar?
Teoría 2) Estoy haciendo todo esto en un hilo de fondo. Sé que hay partes de UIKit que están restringidas al hilo principal. Supuse / esperaba que dibujar en una vista fuera de pantalla no fuera uno de estos. ¿Me equivoco?
(Oh, cómo extraño el NSImage's drawInRect:fromRect:operation:fraction:método)

Respuestas:
Actualización 28/05/2014: escribí esto cuando iOS 3 más o menos era lo más nuevo, estoy seguro de que hay mejores formas de hacerlo por ahora, posiblemente incorporado. Como muchas personas han mencionado, este método no tiene en cuenta la rotación; lea algunas respuestas adicionales y difunda un poco de amor a favor para mantener las respuestas a esta pregunta útiles para todos.
Respuesta original:
Copiaré / pegaré mi respuesta a la misma pregunta en otro lugar:
No hay un método de clase simple para hacer esto, pero hay una función que puedes usar para obtener los resultados deseados:
CGImageCreateWithImageInRect(CGImageRef, CGRect)te ayudará.Aquí hay un breve ejemplo usándolo:
fuente
imageOrientationse establece en todo menos arriba,CGImagese gira con respecto alUIImagey el rectángulo de recorte estará equivocado. Puede rotar el rectángulo de recorte en consecuencia, pero el recién creadoUIImagetendráimageOrientationhacia arriba, de modo que el recortadoCGImagese rotará dentro de él.[UIImage imageWithCGImage:imageRef scale:largeImage.scale orientation:largeImage.imageOrientation];Para recortar imágenes de retina manteniendo la misma escala y orientación, use el siguiente método en una categoría UIImage (iOS 4.0 y superior):
fuente
self.scale, ¿no?CGImageRelease(imageRef);con ARC habilitado?Puede crear una categoría UIImage y usarla donde lo necesite. Basado en la respuesta de HitScans y los comentarios a continuación.
Puedes usarlo de esta manera:
fuente
[[UIScreen mainScreen] scale]soloself.scale? La escala de la imagen puede no ser la misma que la escala de la pantalla.No visible @interface for 'UIImage' declares the selector 'crop'a pesar de que puse los archivos de categoría .h y .m en mi proyecto e importé el .h en la clase en la que estoy usando la categoría. ¿Alguna idea?Versión Swift 3
con ayuda de esta función de puente
CGRectMake->CGRect(créditos a esta respuesta respondida por@rob mayoff):El uso es:
Salida:
fuente
guardla primera línea en caso deUIImage.CGImagedevolucionesnily por qué usarvarcuandoletfunciona perfectamente.cropping(to:)mucho cuidado. El resultadoCGImagetiene una fuerte referencia al más grandeCGImagedel que se recortó. Por lo tanto, si solo desea conservar la imagen recortada y no necesita el original, eche un vistazo a las otras soluciones.rightentonces el CGImage debe ser CCW girado 90 grados, de ahí el rect cultivo debe ser girado demasiadoAquí está mi implementación de recorte UIImage que obedece a la propiedad imageOrientation. Todas las orientaciones fueron probadas a fondo.
fuente
implicit declaration of function 'rad' is invalid in c99puede eliminarse reemplazando: rad (90), rad (-90), rad (-180) -> M_PI_2, -M_PI_2, -_M_PIcontains undefined reference for architecture armv7¿Me estoy perdiendo una biblioteca? CoreGraphics es importado.CGImageAviso : todas estas respuestas suponen un objeto de imagen respaldado.image.CGImagepuede devolver nil, siUIImageestá respaldado por aCIImage, que sería el caso si creara esta imagen usando unCIFilter.En ese caso, es posible que tenga que dibujar la imagen en un nuevo contexto y devolver esa imagen ( lento ).
fuente
Ninguna de las respuestas aquí maneja todos los problemas de escala y rotación 100% correctamente. Aquí hay una síntesis de todo lo dicho hasta ahora, actualizado a partir de iOS7 / 8. Está destinado a ser incluido como método en una categoría en UIImage.
fuente
Versión rápida de
awolfla respuesta de, que funcionó para mí:fuente
La mayoría de las respuestas que he visto solo tratan con una posición de (0, 0) para (x, y). Ok, ese es un caso, pero me gustaría que mi operación de recorte esté centrada. Lo que me llevó un tiempo entender es la línea que sigue al comentario de WTF.
Tomemos el caso de una imagen capturada con orientación vertical:
Espero que tenga sentido! Si no es así, intente con diferentes valores, verá que la lógica se invierte cuando se trata de elegir la x, y, la anchura y la altura correctas para su cropRect.
fuente
swift3
fuente
Extensión rápida
fuente
La mejor solución para recortar un UIImage en Swift , en términos de precisión, escala de píxeles ...:
Instrucciones utilizadas para llamar a esta función:
Nota: la inspiración inicial del código fuente escrita en Objective-C se ha encontrado en el blog "Cocoanetics".
fuente
Debajo del fragmento de código podría ayudar.
fuente
Parece un poco extraño pero funciona muy bien y tiene en cuenta la orientación de la imagen:
fuente
Swift 5:
fuente
fuente
fuente
En iOS9.2SDK, uso el siguiente método para convertir el marco de UIView a UIImage
fuente
Actualización Swift 2.0 (
CIImagecompatibilidad)Se expande a partir de la Respuesta de Maxim, pero también funciona si su imagen está
CIImagebasada.fuente
Aquí hay una versión actualizada de Swift 3 basada en la respuesta de Noodles
fuente
Siga la respuesta de @Arne. Solo estoy arreglando la función Categoría. ponlo en la Categoría de UIImage.
fuente
No estaba satisfecho con otras soluciones porque toman varias veces (usando más potencia de la necesaria) o tienen problemas con la orientación. Esto es lo que usé para una imagen recortada cuadrada a escala de una imagen UIImage *.
fuente
Yo uso el siguiente método.
}
fuente
Mirar https://github.com/vvbogdan/BVCropPhoto
- (UIImage *) croppedImage { CGFloat scale = self.sourceImage.size.width / self.scrollView.contentSize.width; UIImage * finalImage = nil; CGRect targetFrame = CGRectMake ((self.scrollView.contentInset.left + self.scrollView.contentOffset.x) * scale, (self.scrollView.contentInset.top + self.scrollView.contentOffset.y) * scale, self.cropSize.width * scale, self.cropSize.height * scale); CGImageRef contextImage = CGImageCreateWithImageInRect ([[self imageWithRotation: self.sourceImage] CGImage], targetFrame); if (contextImage! = NULL) { finalImage = [UIImage imageWithCGImage: contextImage scale: self.sourceImage.scale orientación: UIImageOrientationUp]; CGImageRelease (contextImage); } return finalImage; } - (UIImage *) imageWithRotation: (UIImage *) image { if (image.imageOrientation == UIImageOrientationUp) devuelve la imagen; CGAffineTransform transform = CGAffineTransformIdentity; switch (image.imageOrientation) { caso UIImageOrientationDown: case UIImageOrientationDownMirrored: transform = CGAffineTransformTranslate (transform, image.size.width, image.size.height); transform = CGAffineTransformRotate (transform, M_PI); descanso; caso UIImageOrientationLeft: case UIImageOrientationLeftMirrored: transform = CGAffineTransformTranslate (transform, image.size.width, 0); transformar = CGAffineTransformRotate (transformar, M_PI_2); descanso; case UIImageOrientationRight: case UIImageOrientationRightMirrored: transform = CGAffineTransformTranslate (transform, 0, image.size.height); transformar = CGAffineTransformRotate (transformar, -M_PI_2); descanso; case UIImageOrientationUp: case UIImageOrientationUpMirrored: descanso; } switch (image.imageOrientation) { case UIImageOrientationUpMirrored: case UIImageOrientationDownMirrored: transform = CGAffineTransformTranslate (transform, image.size.width, 0); transformar = CGAffineTransformScale (transformar, -1, 1); descanso; case UIImageOrientationLeftMirrored: case UIImageOrientationRightMirrored: transform = CGAffineTransformTranslate (transform, image.size.height, 0); transformar = CGAffineTransformScale (transformar, -1, 1); descanso; case UIImageOrientationUp: caso UIImageOrientationDown: caso UIImageOrientationLeft: case UIImageOrientationRight: descanso; } // Ahora dibujamos la imagen CG subyacente en un nuevo contexto, aplicando la transformación // calculado arriba. CGContextRef ctx = CGBitmapContextCreate (NULL, image.size.width, image.size.height, CGImageGetBitsPerComponent (image.CGImage), 0, CGImageGetColorSpace (image.CGImage), CGImageGetBitmapInfo (image.CGImage)); CGContextConcatCTM (ctx, transform); switch (image.imageOrientation) { caso UIImageOrientationLeft: case UIImageOrientationLeftMirrored: case UIImageOrientationRight: case UIImageOrientationRightMirrored: // Grr ... CGContextDrawImage (ctx, CGRectMake (0, 0, image.size.height, image.size.width), image.CGImage); descanso; defecto: CGContextDrawImage (ctx, CGRectMake (0, 0, image.size.width, image.size.height), image.CGImage); descanso; } // Y ahora solo creamos un nuevo UIImage del contexto de dibujo CGImageRef cgimg = CGBitmapContextCreateImage (ctx); UIImage * img = [UIImage imageWithCGImage: cgimg]; CGContextRelease (ctx); CGImageRelease (cgimg); volver img; }fuente