简体   繁体   English

如何裁剪UIImage?

[英]How to crop the UIImage?

I develop an application in which i process the image using its pixels but in that image processing it takes a lot of time. 我开发了一个应用程序,其中我使用像素来处理图像,但是在图像处理中却要花费很多时间。 Therefore i want to crop UIImage (Only middle part of image ie removing/croping bordered part of image).I have the develop code are, 因此,我想裁剪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];
}

How i take(croping outside bordered) the middle part of UIImage????????? 我如何拍摄(在边框附近裁剪)UIImage的中间部分?

Try something like this: 尝试这样的事情:

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

Note: cropRect is smaller rectangle with middle part of the image... 注意:cropRect是带有图像中间部分的较小矩形...

I was looking for a way to get an arbitrary rectangular crop (ie., sub-image) of a UIImage. 我在寻找一种方法来获取UIImage的任意矩形裁剪(即子图像)。

Most of the solutions I tried do not work if the orientation of the image is anything but UIImageOrientationUp. 如果图像的方向不是UIImageOrientationUp,则我尝试的大多数解决方案均不起作用。

For example: 例如:

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

Typically if you use your iPhone camera, you will have other orientations like UIImageOrientationLeft, and you will not get a correct crop with the above. 通常,如果您使用iPhone相机,则将具有其他方向,例如UIImageOrientationLeft,并且使用上述方法无法获得正确的裁剪。 This is because of the use of CGImageRef/CGContextDrawImage which differ in the coordinate system with respect to UIImage. 这是因为使用了CGImageRef / CGContextDrawImage,它们相对于UIImage在坐标系上有所不同。

The code below uses UI* methods (no CGImageRef), and I have tested this with up/down/left/right oriented images, and it seems to work great. 下面的代码使用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;
}

Because I needed it just now, here is MV 's code in Swift 4: 因为我现在需要它,所以这是Swift 4中的MV代码:

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

It would ultimately be faster, with a lot less image creation from sprite atlases, if you could set not only the image for a UIImageView, but also the top-left offset to display within that UIImage. 如果您不仅可以设置UIImageView的图像,还可以设置要在该UIImage中显示的左上偏移,则最终将更快,并且从Sprite地图集创建的图像要少得多。 Maybe this is possible. 也许这是可能的。 It would certainly eliminate a lot of effort! 这肯定会省掉很多精力!

Meanwhile, I created these useful functions in a utility class that I use in my apps. 同时,我在应用程序中使用的实用程序类中创建了这些有用的函数。 It creates a UIImage from part of another UIImage, with options to rotate, scale, and flip using standard UIImageOrientation values to specify. 它从另一个UIImage的一部分创建一个UIImage,并具有使用标准UIImageOrientation值指定的旋转,缩放和翻转选项。 The pixel scaling is preserved from the original image. 从原始图像保留像素缩放。

My app creates a lot of UIImages during initialization, and this necessarily takes time. 我的应用程序在初始化期间创建了很多UIImage,这肯定需要时间。 But some images aren't needed until a certain tab is selected. 但是在选择了某个选项卡之前,不需要某些图像。 To give the appearance of quicker load I could create them in a separate thread spawned at startup, then just wait till it's done when that tab is selected. 为了使加载更快,我可以在启动时生成的单独线程中创建它们,然后等到选中该选项卡时再等待完成。

This code is also posted at Most efficient way to draw part of an image in iOS 此代码也以在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;
}

If you want a portrait crop down the center of every photo. 如果您想在每张照片的中央裁剪肖像。

Use @MV solution, & replace cropRect. 使用@MV解决方案,并替换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);

I wanted to be able to crop from a region based on an aspect ratio, and scale to a size based on a outer bounding extent. 我希望能够根据宽高比从某个区域进行裁剪,并根据外部边界范围将其缩放到一个大小。 Here is my variation: 这是我的变化形式:

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

There are a couple things that I found confusing, the separate concerns of cropping and resizing. 我发现有些事情令人困惑,裁剪和调整大小这两个单独的问题。 Cropping is handled with the origin of the rect that you pass to drawInRect, and scaling is handled by the size portion. 裁剪是通过传递给drawInRect的矩形的原点来处理的,缩放比例是通过大小部分来处理的。 In my case, I needed to relate the size of the cropping rect on the source, to my output rect of the same aspect ratio. 就我而言,我需要将源上的裁剪矩形的大小与相同纵横比的输出矩形相关联。 The scale factor is then output / input, and this needs to be applied to the drawRect (passed to drawInRect). 然后输出/输入比例因子,这需要应用于drawRect(传递给drawInRect)。

One caveat is that this approach effectively assumes that the image you are drawing is larger than the image context. 需要注意的是,这种方法有效地假定您所绘制的图像大于图像上下文。 I have not tested this, but I think you can use this code to handle cropping / zooming, but explicitly defining the scale parameter to be the aforementioned scale parameter. 我尚未对此进行测试,但是我认为您可以使用此代码来处理裁剪/缩放,但是可以将scale参数明确定义为上述的scale参数。 By default, UIKit applies a multiplier based on the screen resolution. 默认情况下,UIKit根据屏幕分辨率应用乘数。

Finally, it should be noted that this UIKit approach is higher level than CoreGraphics / Quartz and Core Image approaches, and seems to handle image orientation issues. 最后,应该注意的是,这种UIKit方法比CoreGraphics / Quartz和Core Image方法的级别更高,并且似乎可以处理图像方向问题。 It is also worth mentioning that it is pretty fast, second to ImageIO, according to this post here: http://nshipster.com/image-resizing/ 还值得一提的是,根据这篇文章,它的速度非常快,仅次于ImageIO: http//nshipster.com/image-resizing/

Using the function 使用功能

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

Here's an example code, used for a different purpose but clips ok. 这是一个示例代码,用于其他目的,但可以。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM