如何裁剪UIImage?

时间:2010-04-14 06:45:08

标签: iphone uiimage

我开发了一个应用程序,其中我使用其像素处理图像,但在该图像处理中需要花费大量时间。因此我想裁剪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];
}

我如何拍摄(在边界外裁剪)UIImage的中间部分?????????

8 个答案:

答案 0 :(得分:79)

尝试这样的事情:

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

注意:cropRect是较小的矩形,具有图像的中间部分......

答案 1 :(得分:39)

我一直想找到一种获取UIImage的任意矩形裁剪(即子图像)的方法。

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

例如:

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

通常情况下,如果您使用iPhone相机,您将拥有其他方向,如UIImageOrientationLeft,并且您将无法通过上述方式获得正确的裁剪。这是因为使用了CGImageRef / CGContextDrawImage,它在坐标系方面与UIImage有所不同。

下面的代码使用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 :(得分: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;
}

答案 3 :(得分:2)

因为我现在需要它,这里是Swift 4中的M-V代码:

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

答案 4 :(得分:1)

#非常小/简单的 Swift 5 版本,

您不应该混合 UI 和 CG 对象,它们有时具有非常不同的坐标空间。这会让你难过。

注意?:self.draw(at:)

@inlinable private prefix func - (right: CGPoint) -> CGPoint
{
    return CGPoint(x: -right.x, y: -right.y)
}

extension UIImage
{
    public func cropped(to cropRect: CGRect) -> UIImage?
    {
           let renderer = UIGraphicsImageRenderer(size: cropRect.size)
        return renderer.image
        {
           _ in
           
            self.draw(at: -cropRect.origin)
        }
    }
}

答案 5 :(得分: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);

答案 6 :(得分:0)

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

import pip

我发现有几件事令人困惑,裁剪和调整大小的问题。使用传递给drawInRect的rect的原点处理裁剪,并且缩放由size部分处理。在我的例子中,我需要将源上裁剪矩形的大小与相同宽高比的输出矩相关联。然后输出/输入比例因子,这需要应用于drawRect(传递给drawInRect)。

有一点需要注意,这种方法有效地假设您绘制的图像大于图像上下文。我没有对此进行测试,但我认为您可以使用此代码来处理裁剪/缩放,但明确将scale参数定义为上述缩放参数。默认情况下,UIKit根据屏幕分辨率应用乘数。

最后,应该注意的是,这种UIKit方法比CoreGraphics / Quartz和Core Image方法更高级,并且似乎处理图像方向问题。值得一提的是,它非常快,仅次于ImageIO,根据这篇文章:http://nshipster.com/image-resizing/

答案 7 :(得分:0)

使用功能

CGContextClipToRect(context, CGRectMake(0, 0, size.width, size.height));

这是一个示例代码,用于不同目的但剪辑正常。

- (UIImage *)aspectFillToSize:(CGSize)size
{
    CGFloat imgAspect = self.size.width / self.size.height;
    CGFloat sizeAspect = size.width/size.height;

    CGSize scaledSize;

        if (sizeAspect > imgAspect) { // increase width, crop height
            scaledSize = CGSizeMake(size.width, size.width / imgAspect);
        } else { // increase height, crop width
            scaledSize = CGSizeMake(size.height * imgAspect, size.height);
        }
    UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f);
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextClipToRect(context, CGRectMake(0, 0, size.width, size.height));
    [self drawInRect:CGRectMake(0.0f, 0.0f, scaledSize.width, scaledSize.height)];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}