2010-04-14 158 views
38

我开发了一个应用程序,使用它的像素处理图像,但在图像处理中需要很长时间。因此,我要裁剪的UIImage(仅图像的中间部分,即去除图像/ croping接壤的部分)。我已在开发代码是,如何裁剪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]; 
} 

如何我拿(croping外镶上)的UIImage的中间部分? ????????

回答

78

尝试这样:

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

注:cropRect是与图像的中间部分更小的矩形...

+0

mihirpmehta , 现在我试图做类似的事情, - (UIImage *)cropedImage:(UIImage *)image { \t CGFloat width = image.size.width; \t CGFloat height = image.size.height; UIImage * cropedImage = [[UIImage alloc] init]; \t CGFloat widthCrop =(image.size.width)/ 2; \t CGFloat heightCrop =(image.size.height)/ 2; \t } 此后我无法想象要做什么? – 2010-04-14 07:25:10

+0

将Old X + NewX/4和OldY + OldY/4换成新的X和New Y,然后使用新的宽度高度NewX和NewY制作Rectangle并将其用作cropRect – 2010-04-14 08:02:34

+0

@mihirpmehta, 您的上述方法只是绘制原始的镜像图像在cropRect矩形中。它不能被处理UIImage。 – 2010-04-14 16:59:13

38

我一直在寻找一种方式来获得一个任意矩形作物(即。 ,子图像)的UIImage。

如果图像的方向不是UIImageOrientationUp,我尝试的大多数解决方案都不起作用。

例如:

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

通常,如果你使用iPhone的摄像头,你将有其他方位像UIImageOrientationLeft,你不会得到上述正确的作物。这是因为使用了与UIImage相关的坐标系统不同的CGImageRef/CGContextDrawImage。

下面的代码使用UI *方法(无CGImageRef),并且我已经用上/下/左/右导向的图像测试了它,并且它似乎工作得很好。


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

请注意,您只能在主线程上运行上述代码。避免使用“UIGraphicsBeginImageContext”等的好处是可以绕过这个限制。 – 2012-02-02 08:54:31

+1

@William Denniss你确定吗? http://stackoverflow.com/questions/11528803/is-uigraphicsbeginimagecontext-thread-safe/11530675#11530675 – Klaas 2013-10-18 22:39:40

+0

@Klass,你是对的,因为iOS 4你可以在任何线程上调用它。但是,代码**仍然不是线程安全的**,您一次只能在一个线程上使用'UIGraphicsBeginImageContext'。文档状态:“创建一个基于位图的图形上下文,并使其成为当前上下文。”我相信这种“当前背景”是全球性的,因此不是线程安全的。我的应用程序一次处理多个图像,并且在多个线程中使用'UIGraphicsBeginImageContext'时发生崩溃,所以我切换到使用线程安全的'CGContextRef'。 – 2013-10-19 03:59:49

2

这最终将更快,图像创作少了很多,从精灵地图集,如果你能设置不仅为一个UIImageView的形象,也左上角偏移到的UIImage内显示。也许这是可能的。这肯定会消除很多努力!

同时,我在我的应用程序中使用的实用程序类中创建了这些有用的函数。它从另一个UIImage的一部分创建UIImage,并使用标准UIImageOrientation值进行旋转,缩放和翻转选项以进行指定。像素缩放从原始图像保留。

我的应用程序在初始化过程中创建了很多UIImages,这一定需要时间。但是在选择某个标签之前不需要一些图像。为了给出更快的加载外观,我可以在启动时产生的单独线程中创建它们,然后等待该选项卡被选中时完成。

此代码也张贴在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

谢谢。如果我从AVFoundation相机上转动图像,我应该为图像发送什么样的方向? – Dejell 2013-02-03 15:25:27

0

如果你想有一个人像作物下来每张照片的中心。

使用@ M-V解决方案,&替换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

我希望能够从基于纵横比的区域进行裁剪,并根据外边界范围缩放到大小。这是我的变化:

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

有一些事情,我发现混淆,裁剪和调整大小单独的关注。裁剪与您传递给drawInRect的矩形的原点一起处理,缩放由大小部分处理。在我的情况下,我需要将源代码中裁剪矩的大小与具有相同纵横比的输出矩形相关联。然后输出/输入比例因子,这需要应用于drawRect(传递给drawInRect)。

一个警告是,这种方法有效地假定你正在绘制的图像大于图像上下文。我没有测试过这个,但我认为你可以使用这段代码来处理裁剪/缩放,但是明确地将scale参数定义为前述的比例参数。默认情况下,UIKit会根据屏幕分辨率应用一个乘数。

最后,应该指出的是,这个UIKit方法比CoreGraphics/Quartz和Core Image方法更高级,并且似乎处理图像方向问题。还值得一提的是,这是相当快,第二要的ImageIO,根据这个帖子在这里:http://nshipster.com/image-resizing/

1

,因为我需要它只是现在,这里是MV的斯威夫特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! 
}