Cropping an UIImage

后端 未结 24 1799
轮回少年
轮回少年 2020-11-22 02:45

I\'ve got some code that resizes an image so I can get a scaled chunk of the center of the image - I use this to take a UIImage and return a small, square repre

相关标签:
24条回答
  • 2020-11-22 03:44
    CGSize size = [originalImage size];
    int padding = 20;
    int pictureSize = 300;
    int startCroppingPosition = 100;
    if (size.height > size.width) {
        pictureSize = size.width - (2.0 * padding);
        startCroppingPosition = (size.height - pictureSize) / 2.0; 
    } else {
        pictureSize = size.height - (2.0 * padding);
        startCroppingPosition = (size.width - pictureSize) / 2.0;
    }
    // WTF: Don't forget that the CGImageCreateWithImageInRect believes that 
    // the image is 180 rotated, so x and y are inverted, same for height and width.
    CGRect cropRect = CGRectMake(startCroppingPosition, padding, pictureSize, pictureSize);
    CGImageRef imageRef = CGImageCreateWithImageInRect([originalImage CGImage], cropRect);
    UIImage *newImage = [UIImage imageWithCGImage:imageRef scale:1.0 orientation:originalImage.imageOrientation];
    [m_photoView setImage:newImage];
    CGImageRelease(imageRef);
    

    Most of the responses I've seen only deals with a position of (0, 0) for (x, y). Ok that's one case but I'd like my cropping operation to be centered. What took me a while to figure out is the line following the WTF comment.

    Let's take the case of an image captured with a portrait orientation:

    1. The original image height is higher than its width (Woo, no surprise so far!)
    2. The image that the CGImageCreateWithImageInRect method imagines in its own world is not really a portrait though but a landscape (That is also why if you don't use the orientation argument in the imageWithCGImage constructor, it will show up as 180 rotated).
    3. So, you should kind of imagine that it is a landscape, the (0, 0) position being the top right corner of the image.

    Hope it makes sense! If it does not, try different values you'll see that the logic is inverted when it comes to choosing the right x, y, width, and height for your cropRect.

    0 讨论(0)
  • 2020-11-22 03:44

    Swift 2.0 Update (CIImage compatibility)

    Expanding off of Maxim's Answer but works if your image is CIImage based, as well.

    public extension UIImage {
        func imageByCroppingToRect(rect: CGRect) -> UIImage? {
            if let image = CGImageCreateWithImageInRect(self.CGImage, rect) {
                return UIImage(CGImage: image)
            } else if let image = (self.CIImage)?.imageByCroppingToRect(rect) {
                return UIImage(CIImage: image)
            }
           return nil
       }
    }
    
    0 讨论(0)
  • 2020-11-22 03:45

    Best solution for cropping an UIImage in Swift, in term of precision, pixels scaling ...:

    private func squareCropImageToSideLength(let sourceImage: UIImage,
        let sideLength: CGFloat) -> UIImage {
            // input size comes from image
            let inputSize: CGSize = sourceImage.size
    
            // round up side length to avoid fractional output size
            let sideLength: CGFloat = ceil(sideLength)
    
            // output size has sideLength for both dimensions
            let outputSize: CGSize = CGSizeMake(sideLength, sideLength)
    
            // calculate scale so that smaller dimension fits sideLength
            let scale: CGFloat = max(sideLength / inputSize.width,
                sideLength / inputSize.height)
    
            // scaling the image with this scale results in this output size
            let scaledInputSize: CGSize = CGSizeMake(inputSize.width * scale,
                inputSize.height * scale)
    
            // determine point in center of "canvas"
            let center: CGPoint = CGPointMake(outputSize.width/2.0,
                outputSize.height/2.0)
    
            // calculate drawing rect relative to output Size
            let outputRect: CGRect = CGRectMake(center.x - scaledInputSize.width/2.0,
                center.y - scaledInputSize.height/2.0,
                scaledInputSize.width,
                scaledInputSize.height)
    
            // begin a new bitmap context, scale 0 takes display scale
            UIGraphicsBeginImageContextWithOptions(outputSize, true, 0)
    
            // optional: set the interpolation quality.
            // For this you need to grab the underlying CGContext
            let ctx: CGContextRef = UIGraphicsGetCurrentContext()
            CGContextSetInterpolationQuality(ctx, kCGInterpolationHigh)
    
            // draw the source image into the calculated rect
            sourceImage.drawInRect(outputRect)
    
            // create new image from bitmap context
            let outImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()
    
            // clean up
            UIGraphicsEndImageContext()
    
            // pass back new image
            return outImage
    }
    

    Instructions used to call this function:

    let image: UIImage = UIImage(named: "Image.jpg")!
    let squareImage: UIImage = self.squareCropImageToSideLength(image, sideLength: 320)
    self.myUIImageView.image = squareImage
    

    Note: the initial source code inspiration written in Objective-C has been found on "Cocoanetics" blog.

    0 讨论(0)
  • 2020-11-22 03:45

    I wasn't satisfied with other solutions because they either draw several time (using more power than necessary) or have problems with orientation. Here is what I used for a scaled square croppedImage from a UIImage * image.

    CGFloat minimumSide = fminf(image.size.width, image.size.height);
    CGFloat finalSquareSize = 600.;
    
    //create new drawing context for right size
    CGRect rect = CGRectMake(0, 0, finalSquareSize, finalSquareSize);
    CGFloat scalingRatio = 640.0/minimumSide;
    UIGraphicsBeginImageContext(rect.size);
    
    //draw
    [image drawInRect:CGRectMake((minimumSide - photo.size.width)*scalingRatio/2., (minimumSide - photo.size.height)*scalingRatio/2., photo.size.width*scalingRatio, photo.size.height*scalingRatio)];
    
    UIImage *croppedImage = UIGraphicsGetImageFromCurrentImageContext();
    
    UIGraphicsEndImageContext();
    
    0 讨论(0)
  • 2020-11-22 03:45

    I use the method below.

      -(UIImage *)getNeedImageFrom:(UIImage*)image cropRect:(CGRect)rect
      {
        CGSize cropSize = rect.size;
        CGFloat widthScale =  
        image.size.width/self.imageViewOriginal.bounds.size.width;
        CGFloat heightScale = 
        image.size.height/self.imageViewOriginal.bounds.size.height;
        cropSize = CGSizeMake(rect.size.width*widthScale,  
        rect.size.height*heightScale);
        CGPoint  pointCrop = CGPointMake(rect.origin.x*widthScale, 
        rect.origin.y*heightScale);
        rect = CGRectMake(pointCrop.x, pointCrop.y, cropSize.width, 
        cropSize.height);
        CGImageRef subImage = CGImageCreateWithImageInRect(image.CGImage, rect);
        UIImage *croppedImage = [UIImage imageWithCGImage:subImage];
        CGImageRelease(subImage);
        return croppedImage;
    

    }

    0 讨论(0)
  • 2020-11-22 03:46

    Update 2014-05-28: I wrote this when iOS 3 or so was the hot new thing, I'm certain there are better ways to do this by now, possibly built-in. As many people have mentioned, this method doesn't take rotation into account; read some additional answers and spread some upvote love around to keep the responses to this question helpful for everyone.

    Original response:

    I'm going to copy/paste my response to the same question elsewhere:

    There isn't a simple class method to do this, but there is a function that you can use to get the desired results: CGImageCreateWithImageInRect(CGImageRef, CGRect) will help you out.

    Here's a short example using it:

    CGImageRef imageRef = CGImageCreateWithImageInRect([largeImage CGImage], cropRect);
    // or use the UIImage wherever you like
    [UIImageView setImage:[UIImage imageWithCGImage:imageRef]]; 
    CGImageRelease(imageRef);
    
    0 讨论(0)
提交回复
热议问题