How to easily resize/optimize an image size with iOS?

后端 未结 18 1219
温柔的废话
温柔的废话 2020-11-22 11:05

My application is downloading a set of image files from the network, and saving them to the local iPhone disk. Some of those images are pretty big in size (widths larger tha

相关标签:
18条回答
  • 2020-11-22 11:41

    you can use this code to scale image in required size.

    + (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize
    {
        CGSize actSize = image.size;
        float scale = actSize.width/actSize.height;
    
        if (scale < 1) {
            newSize.height = newSize.width/scale;
        } 
        else {
            newSize.width = newSize.height*scale;
        }
    
        UIGraphicsBeginImageContext(newSize);
        [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
        UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        return newImage;
    }
    
    0 讨论(0)
  • 2020-11-22 11:45

    Best way to scale images without losing the aspect ratio (i.e. without stretching the imgage) is to use this method:

    //to scale images without changing aspect ratio
    + (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize {
    
        float width = newSize.width;
        float height = newSize.height;
    
        UIGraphicsBeginImageContext(newSize);
        CGRect rect = CGRectMake(0, 0, width, height);
    
        float widthRatio = image.size.width / width;
        float heightRatio = image.size.height / height;
        float divisor = widthRatio > heightRatio ? widthRatio : heightRatio;
    
        width = image.size.width / divisor;
        height = image.size.height / divisor;
    
        rect.size.width  = width;
        rect.size.height = height;
    
        //indent in case of width or height difference
        float offset = (width - height) / 2;
        if (offset > 0) {
            rect.origin.y = offset;
        }
        else {
            rect.origin.x = -offset;
        }
    
        [image drawInRect: rect];
    
        UIImage *smallImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        return smallImage;
    
    }
    

    Add this method to your Utility class so you can use it throughout your project, and access it like so:

    xyzImageView.image = [Utility scaleImage:yourUIImage toSize:xyzImageView.frame.size];
    

    This method takes care of scaling while maintaining aspect ratio. It also adds indents to the image in case the scaled down image has more width than height (or vice versa).

    0 讨论(0)
  • 2020-11-22 11:45
    - (UIImage *)resizeImage:(UIImage*)image newSize:(CGSize)newSize {
        CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height));
        CGImageRef imageRef = image.CGImage;
    
        UIGraphicsBeginImageContextWithOptions(newSize, NO, 0);
        CGContextRef context = UIGraphicsGetCurrentContext();
    
        CGContextSetInterpolationQuality(context, kCGInterpolationHigh);
        CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, newSize.height);
    
        CGContextConcatCTM(context, flipVertical);
        CGContextDrawImage(context, newRect, imageRef);
    
        CGImageRef newImageRef = CGBitmapContextCreateImage(context);
        UIImage *newImage = [UIImage imageWithCGImage:newImageRef];
    
        CGImageRelease(newImageRef);
        UIGraphicsEndImageContext();
    
        return newImage;
    }
    
    0 讨论(0)
  • 2020-11-22 11:48

    According to this session, iOS Memory Deep Dive, we had better use ImageIO to downscale images.

    The bad of using UIImage downscale images.

    • Will decompress original image into memory
    • Internal coordinate space transforms are expensive

    Use ImageIO

    • ImageIO can read image sizes and metadata information without dirtying memory.

    • ImageIO can resize images at cost of resized image only.

    About Image in memory

    • Memory use is related to the dimensions of the images, not the file size.
    • UIGraphicsBeginImageContextWithOptions always uses SRGB rendering-format, which use 4 bytes per pixel.
    • A image have load -> decode -> render 3 phases.
    • UIImage is expensive for sizing and to resizing

    For the following image, if you use UIGraphicsBeginImageContextWithOptions we only need 590KB to load a image, while we need 2048 pixels x 1536 pixels x 4 bytes per pixel = 10MB when decoding

    while UIGraphicsImageRenderer, introduced in iOS 10, will automatically pick the best graphic format in iOS12. It means, you may save 75% of memory by replacing UIGraphicsBeginImageContextWithOptions with UIGraphicsImageRenderer if you don't need SRGB.

    This is my article about iOS images in memory

    func resize(url: NSURL, maxPixelSize: Int) -> CGImage? {
        let imgSource = CGImageSourceCreateWithURL(url, nil)
        guard let imageSource = imgSource else {
            return nil
        }
    
        var scaledImage: CGImage?
        let options: [NSString: Any] = [
                // The maximum width and height in pixels of a thumbnail.
                kCGImageSourceThumbnailMaxPixelSize: maxPixelSize,
                kCGImageSourceCreateThumbnailFromImageAlways: true,
                // Should include kCGImageSourceCreateThumbnailWithTransform: true in the options dictionary. Otherwise, the image result will appear rotated when an image is taken from camera in the portrait orientation.
                kCGImageSourceCreateThumbnailWithTransform: true
        ]
        scaledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary)
    
        return scaledImage
    }
    
    
    let filePath = Bundle.main.path(forResource:"large_leaves_70mp", ofType: "jpg")
    
    let url = NSURL(fileURLWithPath: filePath ?? "")
    
    let image = resize(url: url, maxPixelSize: 600)
    
    

    or

    // Downsampling large images for display at smaller size
    func downsample(imageAt imageURL: URL, to pointSize: CGSize, scale: CGFloat) -> UIImage {
        let imageSourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
        let imageSource = CGImageSourceCreateWithURL(imageURL as CFURL, imageSourceOptions)!
        let maxDimensionInPixels = max(pointSize.width, pointSize.height) * scale
        let downsampleOptions =
            [kCGImageSourceCreateThumbnailFromImageAlways: true,
            kCGImageSourceShouldCacheImmediately: true,
            // Should include kCGImageSourceCreateThumbnailWithTransform: true in the options dictionary. Otherwise, the image result will appear rotated when an image is taken from camera in the portrait orientation.
            kCGImageSourceCreateThumbnailWithTransform: true,
            kCGImageSourceThumbnailMaxPixelSize: maxDimensionInPixels] as CFDictionary
        let downsampledImage =
            CGImageSourceCreateThumbnailAtIndex(imageSource, 0, downsampleOptions)!
        return UIImage(cgImage: downsampledImage)
    }
    
    
    0 讨论(0)
  • 2020-11-22 11:48

    If you image is in document directory, Add this URL extension:

    extension URL {
        func compressedImageURL(quality: CGFloat = 0.3) throws -> URL? {
            let imageData = try Data(contentsOf: self)
            debugPrint("Image file size before compression: \(imageData.count) bytes")
    
            let compressedURL = NSURL.fileURL(withPath: NSTemporaryDirectory() + NSUUID().uuidString + ".jpg")
    
            guard let actualImage = UIImage(data: imageData) else { return nil }
            guard let compressedImageData = UIImageJPEGRepresentation(actualImage, quality) else {
                return nil
            }
            debugPrint("Image file size after compression: \(compressedImageData.count) bytes")
    
            do {
                try compressedImageData.write(to: compressedURL)
                return compressedURL
            } catch {
                return nil
            }
        }
    }
    

    Usage:

    guard let localImageURL = URL(string: "< LocalImagePath.jpg >") else {
        return
    }
    
    //Here you will get URL of compressed image
    guard let compressedImageURL = try localImageURL.compressedImageURL() else {
        return
    }
    
    debugPrint("compressedImageURL: \(compressedImageURL.absoluteString)")
    

    Note:- Change < LocalImagePath.jpg > with your local jpg image path.

    0 讨论(0)
  • 2020-11-22 11:48

    To resize an image I have better (graphical) results by using this function in stead of DrawInRect:

    - (UIImage*) reduceImageSize:(UIImage*) pImage newwidth:(float) pWidth
    {
        float lScale = pWidth / pImage.size.width;
        CGImageRef cgImage = pImage.CGImage;
        UIImage   *lResult = [UIImage imageWithCGImage:cgImage scale:lScale
                                orientation:UIImageOrientationRight];
        return lResult;
    }
    

    Aspect ratio is taken care for automatically

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