There are two ways to compress pictures: compressed picture quality (Quality), compressed picture size (Size).
Compressed picture quality
NSData *data = UIImageJPEGRepresentation(image, compression); UIImage *resultImage = [UIImage imageWithData:data];
Compress images by reducing the quality of JPEG images through the mutual conversion of UIImage and NSData. UIImageJPEGRepresentation:: The second parameter compression takes the value 0.0~1.0. The smaller the value, the lower the image quality, and the smaller the image file.
Compressed image size
UIGraphicsBeginImageContext(size); [image drawInRect:CGRectMake(0, 0, , )]; resultImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext();
Given the required image size, resultImage is the image drawn to size in the original image image.
Compress the image to make the image file smaller than the specified size
If the image clarity is not high and the upload and download speed of the image is required to be fast, the image needs to be compressed before uploading the image. The level of compression depends on the specific situation, but the maximum value of a picture file is generally set, such as 100 KB. There are two ways to compress the picture by appealing. Assuming that the NSData object converted from the image is data, the byte size of the image can be obtained by passing it.
Compressed picture quality
The easier way to think of is to gradually reduce the image quality by looping until the image is slightly smaller than the specified size (maxLength).
+ (UIImage *)compressImageQuality:(UIImage *)image toByte:(NSInteger)maxLength { CGFloat compression = 1; NSData *data = UIImageJPEGRepresentation(image, compression); while ( > maxLength && compression > 0) { compression -= 0.02; data = UIImageJPEGRepresentation(image, compression); // When compression less than a value, this code dose not work } UIImage *resultImage = [UIImage imageWithData:data]; return resultImage; }
This way, there are many cycles, low efficiency and long time.
It can be optimized through dichotomy.
+ (UIImage *)compressImageQuality:(UIImage *)image toByte:(NSInteger)maxLength { CGFloat compression = 1; NSData *data = UIImageJPEGRepresentation(image, compression); if ( < maxLength) return image; CGFloat max = 1; CGFloat min = 0; for (int i = 0; i < 6; ++i) { compression = (max + min) / 2; data = UIImageJPEGRepresentation(image, compression); if ( < maxLength * 0.9) { min = compression; } else if ( > maxLength) { max = compression; } else { break; } } UIImage *resultImage = [UIImage imageWithData:data]; return resultImage; }
When the image size is less than maxLength and greater than maxLength * 0.9, compression will no longer continue. Compression is up to 6 times, 1/(2^6) = 0.015625 < 0.02, and it can also achieve the effect of reducing compression by 0.02 per cycle. Such compression times are less than cycle reduction compression and takes less time. It should be noted that when the image quality is lower than a certain level, there is no effect to continue compression. In other words, compression continues to decrease, and data no longer continues to decrease. The advantage of compressed image quality is that the image clarity is preserved as much as possible, so that the image will not be obviously blurred; the disadvantage is that it cannot be guaranteed that the image is less than the specified size after compression.
Compressed image size
Similar to before, the easier way to think of is to gradually reduce the image size by looping until the image is slightly smaller than the specified size (maxLength). Specific codes are omitted. The same problem is that there are many cycles, low efficiency and long time. The dichotomy can be used to improve efficiency, and the specific code is omitted. Here is another method, which is better than dichotomy, has fewer compression times, and can make the image compressed just smaller than the specified size (not just < maxLength, > maxLength * 0.9).
+ (UIImage *)compressImageSize:(UIImage *)image toByte:(NSUInteger)maxLength { UIImage *resultImage = image; NSData *data = UIImageJPEGRepresentation(resultImage, 1); NSUInteger lastDataLength = 0; while ( > maxLength && != lastDataLength) { lastDataLength = ; CGFloat ratio = (CGFloat)maxLength / ; CGSize size = CGSizeMake((NSUInteger)( * sqrtf(ratio)), (NSUInteger)( * sqrtf(ratio))); // Use NSUInteger to prevent white blank UIGraphicsBeginImageContext(size); // Use image to draw (drawInRect:), image is larger but more compression time // Use result image to draw, image is smaller but less compression time [resultImage drawInRect:CGRectMake(0, 0, , )]; resultImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); data = UIImageJPEGRepresentation(resultImage, 1); } return resultImage; }
[resultImage drawInRect:CGRectMake(0, 0, , )];
It is drawn with the new image resultImage, or it can be drawn with the original image image. Drawing with the original image, the image is closer to the specified size after compression, but it is compressed more times and takes longer. A picture with a size of 6064 KB is compressed. The original and new drawings are drawn as follows
Specify size (KB) | Original drawing compression size (KB) | Number of times of drawing and compression of original image | New graph drawing compressed size (KB) | Number of times new drawings are drawn and compressed |
---|---|---|---|---|
500 | 498 | 6 | 498 | 3 |
300 | 299 | 4 | 296 | 3 |
100 | 99 | 5 | 98 | 3 |
50 | 49 | 6 | 48 | 3 |
The sizes of the two drawing methods are very close to the specified size after compression, but the number of times the number of times the number of times the number of times the number of times the number of times the number of times the new drawing is drawn is twice. It is recommended to use new graph drawing to reduce the number of compressions. The image after compression is obviously blurry than the compression quality.
It should be noted that the code for drawing dimensions
CGSize size = CGSizeMake((NSUInteger)( * sqrtf(ratio)), (NSUInteger)( * sqrtf(ratio)));,
For each size drawn, convert width width and height to integers to prevent the drawn picture from having white edges.
Compressed image size can make the image smaller than the specified size, but will make the image significantly blurred (blurred than compressed image quality).
Combining two image compression methods
If you want to ensure the clarity of the image, it is recommended to choose compressed image quality. If you want the image to be smaller than the specified size, the compressed image size can be satisfied. For the latter requirement, you can also compress the image quality first. If it is already smaller than the specified size, you can get a clear picture, otherwise you can compress the image size.
+ (UIImage *)compressImage:(UIImage *)image toByte:(NSUInteger)maxLength { // Compress by quality CGFloat compression = 1; NSData *data = UIImageJPEGRepresentation(image, compression); if ( < maxLength) return image; CGFloat max = 1; CGFloat min = 0; for (int i = 0; i < 6; ++i) { compression = (max + min) / 2; data = UIImageJPEGRepresentation(image, compression); if ( < maxLength * 0.9) { min = compression; } else if ( > maxLength) { max = compression; } else { break; } } UIImage *resultImage = [UIImage imageWithData:data]; if ( < maxLength) return resultImage; // Compress by size NSUInteger lastDataLength = 0; while ( > maxLength && != lastDataLength) { lastDataLength = ; CGFloat ratio = (CGFloat)maxLength / ; CGSize size = CGSizeMake((NSUInteger)( * sqrtf(ratio)), (NSUInteger)( * sqrtf(ratio))); // Use NSUInteger to prevent white blank UIGraphicsBeginImageContext(size); [resultImage drawInRect:CGRectMake(0, 0, , )]; resultImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); data = UIImageJPEGRepresentation(resultImage, compression); } return resultImage; }
Let’s take a look at the implementation method of iOS image compression upload
need
Many times when we upload pictures, we often encounter some problems, either the quality of the picture becomes worse, or the picture is too large, etc. Here, I found a solution that is currently more in line with the needs. On the original basis, dynamic compression coefficient was added and rewritten into Swift version.
Implementation ideas
First adjust the resolution. You can set a value for the resolution yourself. If it is greater than, it will be reduced to this resolution. If it is less than, it will be maintained at the original resolution. Then set the compression ratio according to the final size of the picture, such as passing maxSize = 30KB, and finally calculate the compression ratio of approximately this size. Basically, the final image data can be kept at the same size according to the current resolution and will not be too blurry. The final effect of WeChat and Weibo should be similar, and the code still needs to be optimized!
Implement code
Compression mode before Swift3.0
// MARK: - Reduce quality func resetSizeOfImageData(source_image: UIImage, maxSize: Int) -> NSData { //Adjust the resolution first var newSize = CGSize(width: source_image., height: source_image.) let tempHeight = / 1024 let tempWidth = / 1024 if tempWidth > 1.0 && tempWidth > tempHeight { newSize = CGSize(width: source_image. / tempWidth, height: source_image. / tempWidth) } else if tempHeight > 1.0 && tempWidth < tempHeight { newSize = CGSize(width: source_image. / tempHeight, height: source_image. / tempHeight) } UIGraphicsBeginImageContext(newSize) source_image.drawAsPatternInRect(CGRect(x: 0, y: 0, width: , height: )) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() //First determine whether the current quality meets the requirements, and then compress it if it is not met. var finallImageData = UIImageJPEGRepresentation(newImage,1.0) let sizeOrigin = Int64((finallImageData?.length)!) let sizeOriginKB = Int(sizeOrigin / 1024) if sizeOriginKB <= maxSize { return finallImageData! } //Save the compression coefficient let compressionQualityArr = NSMutableArray() let avg = CGFloat(1.0/250) var value = avg for var i = 250; i>=1; i-- { value = CGFloat(i)*avg (value) } //Resize //Note: Compression coefficient array compressionQualityArr is stored from large to small. //Thoughts: half-fold calculation. If the intermediate compression coefficient still does not drop to the target value maxSize, then start looking for the compression coefficient from the second half; otherwise, look for the compression coefficient from the first half. finallImageData = UIImageJPEGRepresentation(newImage, CGFloat(compressionQualityArr[125] as! NSNumber)) if Int(Int64((UIImageJPEGRepresentation(newImage, CGFloat(compressionQualityArr[125] as! NSNumber))?.length)!)/1024) > maxSize { //Get the initial size finallImageData = UIImageJPEGRepresentation(newImage, 1.0) //Start from the second half for idx in 126..<250 { let value = compressionQualityArr[idx] let sizeOrigin = Int64((finallImageData?.length)!) let sizeOriginKB = Int(sizeOrigin / 1024) print("The quality currently reduced:\(sizeOriginKB)") if sizeOriginKB > maxSize { print("\(idx)----\(value)") finallImageData = UIImageJPEGRepresentation(newImage, CGFloat(value as! NSNumber)) } else { break } } } else { //Get the initial size finallImageData = UIImageJPEGRepresentation(newImage, 1.0) //Start from the first half for idx in 0..<125 { let value = compressionQualityArr[idx] let sizeOrigin = Int64((finallImageData?.length)!) let sizeOriginKB = Int(sizeOrigin / 1024) print("The quality currently reduced:\(sizeOriginKB)") if sizeOriginKB > maxSize { print("\(idx)----\(value)") finallImageData = UIImageJPEGRepresentation(newImage, CGFloat(value as! NSNumber)) } else { break } } } return finallImageData! }
Swift 3.0 version binary compression mode
// MARK: - Reduce qualityfunc resetSizeOfImageData(source_image: UIImage!, maxSize: Int) -> NSData { //First determine whether the current quality meets the requirements, and then compress it if it is not met. var finallImageData = UIImageJPEGRepresentation(source_image,1.0) let sizeOrigin = finallImageData?.count let sizeOriginKB = sizeOrigin! / 1024 if sizeOriginKB <= maxSize { return finallImageData! as NSData } //Adjust the resolution first var defaultSize = CGSize(width: 1024, height: 1024) let newImage = (size: defaultSize, source_image: source_image) finallImageData = UIImageJPEGRepresentation(newImage,1.0); //Save the compression coefficient let compressionQualityArr = NSMutableArray() let avg = CGFloat(1.0/250) var value = avg var i = 250 repeat { i -= 1 value = CGFloat(i)*avg (value) } while i >= 1 /* Resize Description: The compression coefficient array compressionQualityArr is stored from large to small. */ //Thoughts: Search using dichotomy finallImageData = (arr: () as! [CGFloat], image: newImage, sourceData: finallImageData!, maxSize: maxSize) //If the compression to the specified size is still not possible, the resolution will be reduced while finallImageData?.count == 0 { //Resolution reduction is 100 per time if -100 <= 0 || -100 <= 0 { break } defaultSize = CGSize(width: -100, height: -100) let image = (size: defaultSize, source_image: (data: UIImageJPEGRepresentation(newImage, as! CGFloat)!)!) finallImageData = (arr: () as! [CGFloat], image: image, sourceData: UIImageJPEGRepresentation(image,1.0)!, maxSize: maxSize) } return finallImageData! as NSData } // MARK: - Adjust image resolution/size (equal scale)func newSizeImage(size: CGSize, source_image: UIImage) -> UIImage { var newSize = CGSize(width: source_image., height: source_image.) let tempHeight = / let tempWidth = / if tempWidth > 1.0 && tempWidth > tempHeight { newSize = CGSize(width: source_image. / tempWidth, height: source_image. / tempWidth) } else if tempHeight > 1.0 && tempWidth < tempHeight { newSize = CGSize(width: source_image. / tempHeight, height: source_image. / tempHeight) } UIGraphicsBeginImageContext(newSize) source_image.draw(in: CGRect(x: 0, y: 0, width: , height: )) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage! } // MARK: - Dichotomyfunc halfFuntion(arr: [CGFloat], image: UIImage, sourceData finallImageData: Data, maxSize: Int) -> Data? { var tempFinallImageData = finallImageData var tempData = () var start = 0 var end = - 1 var index = 0 var difference = while start <= end { index = start + (end - start)/2 tempFinallImageData = UIImageJPEGRepresentation(image, arr[index])! let sizeOrigin = let sizeOriginKB = sizeOrigin / 1024 print("The quality currently reduced:\(sizeOriginKB)\n\(index)----\(arr[index])") if sizeOriginKB > maxSize { start = index + 1 } else if sizeOriginKB < maxSize { if maxSize-sizeOriginKB < difference { difference = maxSize-sizeOriginKB tempData = tempFinallImageData } end = index - 1 } else { break } } return tempData }
The above are the two methods of iOS image compression introduced to you by the editor. I hope it will be helpful to you. If you have any questions, please leave me a message. The editor will reply you in time. Thank you very much for your support for my website!