How to easily resize/optimize an image size with iOS? - Printable Version +- 0Day Forums (https://0day.red) +-- Forum: Coding (https://0day.red/Forum-Coding) +--- Forum: Objective-C (https://0day.red/Forum-Objective-C) +--- Thread: How to easily resize/optimize an image size with iOS? (/Thread-How-to-easily-resize-optimize-an-image-size-with-iOS) Pages:
1
2
|
RE: How to easily resize/optimize an image size with iOS? - unanswerably291710 - 07-21-2023 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; } RE: How to easily resize/optimize an image size with iOS? - gustierdk - 07-21-2023 I developed an ultimate solution for image scaling in Swift. You can use it to resize image to fill, aspect fill or aspect fit specified size. You can align image to center or any of four edges and four corners. And also you can trim extra space which is added if aspect ratios of original image and target size are not equal. enum UIImageAlignment { case Center, Left, Top, Right, Bottom, TopLeft, BottomRight, BottomLeft, TopRight } enum UIImageScaleMode { case Fill, AspectFill, AspectFit(UIImageAlignment) } extension UIImage { func scaleImage(width width: CGFloat? = nil, height: CGFloat? = nil, scaleMode: UIImageScaleMode = .AspectFit(.Center), trim: Bool = false) -> UIImage { let preWidthScale = width.map { $0 / size.width } let preHeightScale = height.map { $0 / size.height } var widthScale = preWidthScale ?? preHeightScale ?? 1 var heightScale = preHeightScale ?? widthScale switch scaleMode { case .AspectFit(_): let scale = min(widthScale, heightScale) widthScale = scale heightScale = scale case .AspectFill: let scale = max(widthScale, heightScale) widthScale = scale heightScale = scale default: break } let newWidth = size.width * widthScale let newHeight = size.height * heightScale let canvasWidth = trim ? newWidth : (width ?? newWidth) let canvasHeight = trim ? newHeight : (height ?? newHeight) UIGraphicsBeginImageContextWithOptions(CGSizeMake(canvasWidth, canvasHeight), false, 0) var originX: CGFloat = 0 var originY: CGFloat = 0 switch scaleMode { case .AspectFit(let alignment): switch alignment { case .Center: originX = (canvasWidth - newWidth) / 2 originY = (canvasHeight - newHeight) / 2 case .Top: originX = (canvasWidth - newWidth) / 2 case .Left: originY = (canvasHeight - newHeight) / 2 case .Bottom: originX = (canvasWidth - newWidth) / 2 originY = canvasHeight - newHeight case .Right: originX = canvasWidth - newWidth originY = (canvasHeight - newHeight) / 2 case .TopLeft: break case .TopRight: originX = canvasWidth - newWidth case .BottomLeft: originY = canvasHeight - newHeight case .BottomRight: originX = canvasWidth - newWidth originY = canvasHeight - newHeight } default: break } self.drawInRect(CGRectMake(originX, originY, newWidth, newHeight)) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } } There are examples of applying this solution below. Gray rectangle is target site image will be resized to. Blue circles in light blue rectangle is the image (I used circles because it's easy to see when it's scaled without preserving aspect). Light orange color marks areas that will be trimmed if you pass `trim: true`. **Aspect fit** before and after scaling: [![Aspect fit 1 (before)][1]][1] [![Aspect fit 1 (after)][2]][2] Another example of **aspect fit**: [![Aspect fit 2 (before)][3]][3] [![Aspect fit 2 (after)][4]][4] **Aspect fit** with top alignment: [![Aspect fit 3 (before)][5]][5] [![Aspect fit 3 (after)][6]][6] **Aspect fill**: [![Aspect fill (before)][7]][7] [![Aspect fill (after)][8]][8] **Fill**: [![Fill (before)][9]][9] [![Fill (after)][10]][10] I used upscaling in my examples because it's simpler to demonstrate but solution also works for downscaling as in question. For JPEG compression you should use this : let compressionQuality: CGFloat = 0.75 // adjust to change JPEG quality if let data = UIImageJPEGRepresentation(image, compressionQuality) { // ... } You can check out my [gist][11] with Xcode playground. [1]: [2]: [3]: [4]: [5]: [6]: [7]: [8]: [9]: [10]: [11]: RE: How to easily resize/optimize an image size with iOS? - trisaccharide600 - 07-21-2023 I just wanted to answer that question for Cocoa Swift programmers. This function returns NSImage with new size. You can use that function like this. let sizeChangedImage = changeImageSize(image, ratio: 2) // changes image size func changeImageSize (image: NSImage, ratio: CGFloat) -> NSImage { // getting the current image size let w = image.size.width let h = image.size.height // calculating new size let w_new = w / ratio let h_new = h / ratio // creating size constant let newSize = CGSizeMake(w_new ,h_new) //creating rect let rect = NSMakeRect(0, 0, w_new, h_new) // creating a image context with new size let newImage = NSImage.init(size:newSize) newImage.lockFocus() // drawing image with new size in context image.drawInRect(rect) newImage.unlockFocus() return newImage } RE: How to easily resize/optimize an image size with iOS? - luciennenzxqgvqpg - 07-21-2023 - (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; } RE: How to easily resize/optimize an image size with iOS? - magnificat331 - 07-21-2023 For Swift 3, the below code scales the image keeping the aspect ratio. You can read more about the ImageContext in [Apple's documentation][1]: extension UIImage { class func resizeImage(image: UIImage, newHeight: CGFloat) -> UIImage { let scale = newHeight / image.size.height let newWidth = image.size.width * scale UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight)) image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight)) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage! } } To use it, call `resizeImage()` method: UIImage.resizeImage(image: yourImageName, newHeight: yourImageNewHeight) [1]: [To see links please register here] RE: How to easily resize/optimize an image size with iOS? - Siralisha9 - 07-21-2023 Adding to the slew of answers here, but I have gone for a solution which resizes by file size, rather than dimensions. This will both reduce the dimensions and quality of the image until it reaches your given size. func compressTo(toSizeInMB size: Double) -> UIImage? { let bytes = size * 1024 * 1024 let sizeInBytes = Int(bytes) var needCompress:Bool = true var imgData:Data? var compressingValue:CGFloat = 1.0 while (needCompress) { if let resizedImage = scaleImage(byMultiplicationFactorOf: compressingValue), let data: Data = UIImageJPEGRepresentation(resizedImage, compressingValue) { if data.count < sizeInBytes || compressingValue < 0.1 { needCompress = false imgData = data } else { compressingValue -= 0.1 } } } if let data = imgData { print("Finished with compression value of: \(compressingValue)") return UIImage(data: data) } return nil } private func scaleImage(byMultiplicationFactorOf factor: CGFloat) -> UIImage? { let size = CGSize(width: self.size.width*factor, height: self.size.height*factor) UIGraphicsBeginImageContext(size) draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height)) if let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext() { UIGraphicsEndImageContext() return newImage; } return nil } Credit for [scaling by size answer][1] [1]: [To see links please register here] RE: How to easily resize/optimize an image size with iOS? - hellbox642 - 07-21-2023 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. RE: How to easily resize/optimize an image size with iOS? - halftimbered942 - 07-21-2023 Swift Version ------------- func resizeImage(image: UIImage, newWidth: CGFloat) -> UIImage? { let scale = newWidth / image.size.width let newHeight = CGFloat(200.0) UIGraphicsBeginImageContext(CGSize(width: newWidth, height: newHeight)) image.draw(in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight)) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage } RE: How to easily resize/optimize an image size with iOS? - woolier103860 - 07-21-2023 According to this session, [iOS Memory Deep Dive][1], 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 [![enter image description here][2]][2] 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]( [To see links please register here] )```swift func resize(url: NSURL?, maxPixelSize: Int) -> CGImage? { guard let url = url else { return nil; } 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 } DispatchQueue.global().async { let image: CGImage? = resize(url: NSURL.init(string: "https://i.stack.imgur.com/rPcHQ.jpg"), maxPixelSize: 600) DispatchQueue.main.async { let imageView = UIImageView(frame: CGRect(x: 0, y: 0 ,width: 30, height: 30)) if let cgimage = image { imageView.image = UIImage(cgImage: cgimage); } } } ``` or ```swift // 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) } ``` [1]: [To see links please register here] [2]: |