UIImage: Resize, then Crop

后端 未结 16 2272
夕颜
夕颜 2020-11-22 11:51

I\'ve been bashing my face into this one for literally days now and even though I feel constantly that I am right on the edge of revelation, I simply cannot achieve my goal.

相关标签:
16条回答
  • 2020-11-22 12:23

    An older post contains code for a method to resize your UIImage. The relevant portion is as follows:

    + (UIImage*)imageWithImage:(UIImage*)image 
                   scaledToSize:(CGSize)newSize;
    {
       UIGraphicsBeginImageContext( newSize );
       [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
       UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
       UIGraphicsEndImageContext();
    
       return newImage;
    }
    

    As far as cropping goes, I believe that if you alter the method to use a different size for the scaling than for the context, your resulting image should be clipped to the bounds of the context.

    0 讨论(0)
  • The following simple code worked for me.

    [imageView setContentMode:UIViewContentModeScaleAspectFill];
    [imageView setClipsToBounds:YES];
    
    0 讨论(0)
  • 2020-11-22 12:23

    This question seems to have been put to rest, but in my quest for a solution that I could more easily understand (and written in Swift), I arrived at this (also posted to: How to crop the UIImage?)


    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, crop 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. 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).

    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. By default, UIKit applies a multiplier based on the screen resolution.

    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. It is also worth mentioning that it is pretty fast, second to ImageIO, according to this post here: http://nshipster.com/image-resizing/

    0 讨论(0)
  • 2020-11-22 12:24

    This is a version of Jane Sales' answer in Swift. Cheers!

    public func resizeImage(image: UIImage, size: CGSize) -> UIImage? {
        var returnImage: UIImage?
    
        var scaleFactor: CGFloat = 1.0
        var scaledWidth = size.width
        var scaledHeight = size.height
        var thumbnailPoint = CGPointMake(0, 0)
    
        if !CGSizeEqualToSize(image.size, size) {
            let widthFactor = size.width / image.size.width
            let heightFactor = size.height / image.size.height
    
            if widthFactor > heightFactor {
                scaleFactor = widthFactor
            } else {
                scaleFactor = heightFactor
            }
    
            scaledWidth = image.size.width * scaleFactor
            scaledHeight = image.size.height * scaleFactor
    
            if widthFactor > heightFactor {
                thumbnailPoint.y = (size.height - scaledHeight) * 0.5
            } else if widthFactor < heightFactor {
                thumbnailPoint.x = (size.width - scaledWidth) * 0.5
            }
        }
    
        UIGraphicsBeginImageContextWithOptions(size, true, 0)
    
        var thumbnailRect = CGRectZero
        thumbnailRect.origin = thumbnailPoint
        thumbnailRect.size.width = scaledWidth
        thumbnailRect.size.height = scaledHeight
    
        image.drawInRect(thumbnailRect)
        returnImage = UIGraphicsGetImageFromCurrentImageContext()
    
        UIGraphicsEndImageContext()
    
        return returnImage
    }
    
    0 讨论(0)
  • 2020-11-22 12:26

    There's a great piece of code related to the resizing of images + several other operations. I came around this one when trying to figure ou how to resize images... http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/

    0 讨论(0)
  • 2020-11-22 12:27

    I converted Sam Wirch's guide to swift and it worked well for me, although there's some very slight "squishing" in the final image that I couldn't resolve.

    func resizedCroppedImage(image: UIImage, newSize:CGSize) -> UIImage {
        var ratio: CGFloat = 0
        var delta: CGFloat = 0
        var offset = CGPointZero
        if image.size.width > image.size.height {
            ratio = newSize.width / image.size.width
            delta = (ratio * image.size.width) - (ratio * image.size.height)
            offset = CGPointMake(delta / 2, 0)
        } else {
            ratio = newSize.width / image.size.height
            delta = (ratio * image.size.height) - (ratio * image.size.width)
            offset = CGPointMake(0, delta / 2)
        }
        let clipRect = CGRectMake(-offset.x, -offset.y, (ratio * image.size.width) + delta, (ratio * image.size.height) + delta)
        UIGraphicsBeginImageContextWithOptions(newSize, true, 0.0)
        UIRectClip(clipRect)
        image.drawInRect(clipRect)
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return newImage
    }
    

    If anyone wants the objective c version, it's on his website.

    0 讨论(0)
提交回复
热议问题