├── LICENSE ├── README.md ├── ZYImageCompress.podspec └── ZYImageCompress ├── UIImage+Resize.h ├── UIImage+Resize.m ├── UIImage+ZYCompressIB.h ├── UIImage+ZYCompressIB.m ├── UIImage+ZYCompressJPEG.h ├── UIImage+ZYCompressJPEG.m ├── UIImage+ZYCompressMoments.h ├── UIImage+ZYCompressMoments.m ├── UIImage+ZYCompressThumb.h ├── UIImage+ZYCompressThumb.m └── ZYImageCompress.h /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Jerry Hu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ZYImageCompress 2 | 3 | ZYImageCompress是UIImage的一个扩展,支持图片压缩和缩略图。 4 | 图片压缩的算法参考了 [Luban鲁班](https://github.com/Curzibn/Luban) 5 | 6 | ## 安装 7 | ### CocoaPods 8 | 9 | `pod 'ZYImageCompress'` 10 | 11 | ### 手动导入 12 | 13 | 1. 下载 ZYImageCompress 文件夹所有内容并且拖入你的工程中。 14 | 2. 导入 ZYImageCompress.h` 15 | 16 | ## 使用 17 | ### 方法列表 18 | 方法|描述 19 | ---|--- 20 | (NSData *)zy_compressForImageBrowser;|图片压缩, 适用于图片浏览器。图片尺寸的算法参考了Luban(鲁班),文件大小的算法有差异 21 | (NSData *)zy_compressForMoments;|图片压缩, 适用于朋友圈。图片尺寸和文件大小的算法都参照Luban(鲁班) 22 | (UIImage *)zy_thumbWithSize:(CGSize)size|生成指定尺寸的缩略图 23 | (NSData *)zy_thumbAndCompressWithSize:(CGSize)size|生成指定尺寸的缩略图,并且压缩图片 24 | (NSData *)zy_thumbAndCompressWithSize:(CGSize)size maxFileSize:(NSInteger)maxFileSize|生成指定尺寸的缩略图,并按照指定文件大小的限值压缩图片 25 | (NSData *)zy_thumbAndCompressWithSize:(CGSize)size maxFileSize:(NSInteger)maxFileSize|生成指定尺寸的缩略图,并按照指定文件大小的限值压缩图片 26 | (NSData *)zy_compressWithMaxFileSize:(NSInteger)maxFileSize initQuality:(double)initQuality|根据指定最大文件大小压缩图片 27 | 28 | -------------------------------------------------------------------------------- /ZYImageCompress.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "ZYImageCompress" 3 | s.version = "1.1.0" 4 | s.summary = "JPEG image compressor support with an UIImage category" 5 | 6 | s.description = <<-DESC 7 | This library provides a category for UIImage with support for compressing image 8 | into a smaller size. 9 | DESC 10 | 11 | s.homepage = "https://github.com/jerryhu/ZYImageCompress" 12 | 13 | s.license = "MIT" 14 | s.author = { "Jerry Hu" => "jerryhunn@gmail.com" } 15 | s.platform = :ios 16 | s.source = { :git => "https://github.com/jerryhu/ZYImageCompress.git", :tag => "#{s.version}" } 17 | 18 | s.source_files = "ZYImageCompress/**/*.{h,m}" 19 | s.framework = "UIKit" 20 | end 21 | -------------------------------------------------------------------------------- /ZYImageCompress/UIImage+Resize.h: -------------------------------------------------------------------------------- 1 | /*********************************************************************************** 2 | * 3 | * Copyright (c) 2010 Olivier Halligon 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | * 23 | *********************************************************************************** 24 | * 25 | * Any comment or suggestion welcome. Referencing this project in your AboutBox is appreciated. 26 | * Please tell me if you use this class so we can cross-reference our projects. 27 | * 28 | ***********************************************************************************/ 29 | 30 | 31 | #import 32 | 33 | 34 | @interface UIImage(ResizeCategory) 35 | -(UIImage*)resizedImageToSize:(CGSize)dstSize; 36 | -(UIImage*)resizedImageToFitInSize:(CGSize)boundingSize scaleIfSmaller:(BOOL)scale; 37 | @end 38 | -------------------------------------------------------------------------------- /ZYImageCompress/UIImage+Resize.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+Resize.m 3 | // 4 | // Created by Olivier Halligon on 12/08/09. 5 | // Copyright 2009 AliSoftware. All rights reserved. 6 | // 7 | 8 | #import "UIImage+Resize.h" 9 | 10 | @implementation UIImage (ResizeCategory) 11 | 12 | -(UIImage*)resizedImageToSize:(CGSize)dstSize 13 | { 14 | CGImageRef imgRef = self.CGImage; 15 | // the below values are regardless of orientation : for UIImages from Camera, width>height (landscape) 16 | CGSize srcSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef)); // not equivalent to self.size (which is dependant on the imageOrientation)! 17 | 18 | /* Don't resize if we already meet the required destination size. */ 19 | if (CGSizeEqualToSize(srcSize, dstSize)) { 20 | return self; 21 | } 22 | 23 | CGFloat scaleRatio = dstSize.width / srcSize.width; 24 | UIImageOrientation orient = self.imageOrientation; 25 | CGAffineTransform transform = CGAffineTransformIdentity; 26 | switch(orient) { 27 | 28 | case UIImageOrientationUp: //EXIF = 1 29 | transform = CGAffineTransformIdentity; 30 | break; 31 | 32 | case UIImageOrientationUpMirrored: //EXIF = 2 33 | transform = CGAffineTransformMakeTranslation(srcSize.width, 0.0); 34 | transform = CGAffineTransformScale(transform, -1.0, 1.0); 35 | break; 36 | 37 | case UIImageOrientationDown: //EXIF = 3 38 | transform = CGAffineTransformMakeTranslation(srcSize.width, srcSize.height); 39 | transform = CGAffineTransformRotate(transform, M_PI); 40 | break; 41 | 42 | case UIImageOrientationDownMirrored: //EXIF = 4 43 | transform = CGAffineTransformMakeTranslation(0.0, srcSize.height); 44 | transform = CGAffineTransformScale(transform, 1.0, -1.0); 45 | break; 46 | 47 | case UIImageOrientationLeftMirrored: //EXIF = 5 48 | dstSize = CGSizeMake(dstSize.height, dstSize.width); 49 | transform = CGAffineTransformMakeTranslation(srcSize.height, srcSize.width); 50 | transform = CGAffineTransformScale(transform, -1.0, 1.0); 51 | transform = CGAffineTransformRotate(transform, 3.0 * M_PI_2); 52 | break; 53 | 54 | case UIImageOrientationLeft: //EXIF = 6 55 | dstSize = CGSizeMake(dstSize.height, dstSize.width); 56 | transform = CGAffineTransformMakeTranslation(0.0, srcSize.width); 57 | transform = CGAffineTransformRotate(transform, 3.0 * M_PI_2); 58 | break; 59 | 60 | case UIImageOrientationRightMirrored: //EXIF = 7 61 | dstSize = CGSizeMake(dstSize.height, dstSize.width); 62 | transform = CGAffineTransformMakeScale(-1.0, 1.0); 63 | transform = CGAffineTransformRotate(transform, M_PI_2); 64 | break; 65 | 66 | case UIImageOrientationRight: //EXIF = 8 67 | dstSize = CGSizeMake(dstSize.height, dstSize.width); 68 | transform = CGAffineTransformMakeTranslation(srcSize.height, 0.0); 69 | transform = CGAffineTransformRotate(transform, M_PI_2); 70 | break; 71 | 72 | default: 73 | [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"]; 74 | 75 | } 76 | 77 | ///////////////////////////////////////////////////////////////////////////// 78 | // The actual resize: draw the image on a new context, applying a transform matrix 79 | UIGraphicsBeginImageContextWithOptions(dstSize, NO, self.scale); 80 | 81 | CGContextRef context = UIGraphicsGetCurrentContext(); 82 | 83 | if (!context) { 84 | return nil; 85 | } 86 | 87 | if (orient == UIImageOrientationRight || orient == UIImageOrientationLeft) { 88 | CGContextScaleCTM(context, -scaleRatio, scaleRatio); 89 | CGContextTranslateCTM(context, -srcSize.height, 0); 90 | } else { 91 | CGContextScaleCTM(context, scaleRatio, -scaleRatio); 92 | CGContextTranslateCTM(context, 0, -srcSize.height); 93 | } 94 | 95 | CGContextConcatCTM(context, transform); 96 | 97 | // we use srcSize (and not dstSize) as the size to specify is in user space (and we use the CTM to apply a scaleRatio) 98 | CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, srcSize.width, srcSize.height), imgRef); 99 | UIImage* resizedImage = UIGraphicsGetImageFromCurrentImageContext(); 100 | UIGraphicsEndImageContext(); 101 | 102 | return resizedImage; 103 | } 104 | 105 | 106 | 107 | ///////////////////////////////////////////////////////////////////////////// 108 | 109 | 110 | 111 | -(UIImage*)resizedImageToFitInSize:(CGSize)boundingSize scaleIfSmaller:(BOOL)scale 112 | { 113 | // get the image size (independant of imageOrientation) 114 | CGImageRef imgRef = self.CGImage; 115 | CGSize srcSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef)); // not equivalent to self.size (which depends on the imageOrientation)! 116 | 117 | // adjust boundingSize to make it independant on imageOrientation too for farther computations 118 | UIImageOrientation orient = self.imageOrientation; 119 | switch (orient) { 120 | case UIImageOrientationLeft: 121 | case UIImageOrientationRight: 122 | case UIImageOrientationLeftMirrored: 123 | case UIImageOrientationRightMirrored: 124 | boundingSize = CGSizeMake(boundingSize.height, boundingSize.width); 125 | break; 126 | default: 127 | // NOP 128 | break; 129 | } 130 | 131 | // Compute the target CGRect in order to keep aspect-ratio 132 | CGSize dstSize; 133 | 134 | if ( !scale && (srcSize.width < boundingSize.width) && (srcSize.height < boundingSize.height) ) { 135 | //NSLog(@"Image is smaller, and we asked not to scale it in this case (scaleIfSmaller:NO)"); 136 | dstSize = srcSize; // no resize (we could directly return 'self' here, but we draw the image anyway to take image orientation into account) 137 | } else { 138 | CGFloat wRatio = boundingSize.width / srcSize.width; 139 | CGFloat hRatio = boundingSize.height / srcSize.height; 140 | 141 | if (wRatio < hRatio) { 142 | //NSLog(@"Width imposed, Height scaled ; ratio = %f",wRatio); 143 | dstSize = CGSizeMake(boundingSize.width, floorf(srcSize.height * wRatio)); 144 | } else { 145 | //NSLog(@"Height imposed, Width scaled ; ratio = %f",hRatio); 146 | dstSize = CGSizeMake(floorf(srcSize.width * hRatio), boundingSize.height); 147 | } 148 | } 149 | 150 | return [self resizedImageToSize:dstSize]; 151 | } 152 | 153 | @end 154 | -------------------------------------------------------------------------------- /ZYImageCompress/UIImage+ZYCompressIB.h: -------------------------------------------------------------------------------- 1 | /*********************************************************************************** 2 | * MIT License 3 | * 4 | * Copyright (c) 2019 Jerry Hu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | ***********************************************************************************/ 25 | 26 | 27 | #import 28 | 29 | NS_ASSUME_NONNULL_BEGIN 30 | 31 | @interface UIImage (ZYCompressIB) 32 | 33 | /** 34 | 图片压缩, 适用于图片浏览器 35 | 36 | @return 压缩后的图片数据 37 | */ 38 | - (NSData *)zy_compressForImageBrowser; 39 | 40 | @end 41 | 42 | NS_ASSUME_NONNULL_END 43 | -------------------------------------------------------------------------------- /ZYImageCompress/UIImage+ZYCompressIB.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+ZYCompressIB.m 3 | // 图片压缩,适用于图片浏览器的大图 4 | // 5 | // 图片尺寸的算法参考了鲁班 https://github.com/Curzibn/Luban 6 | // 文件大小的限制算法有差异 7 | // 8 | // Created by Jerry Hu on 2019/3/20. 9 | // 10 | 11 | #import "UIImage+ZYCompressIB.h" 12 | #import "UIImage+Resize.h" 13 | 14 | @implementation UIImage (ZYCompressIB) 15 | 16 | /** 17 | 图片压缩, 适用于图片浏览器的大图 18 | 19 | @return 压缩后的图片数据, JPEG格式 20 | */ 21 | - (NSData *)zy_compressForImageBrowser { 22 | // 计算压缩后的图片尺寸 23 | CGSize newSize = [self zy_computeSizeForImageBrowser:self.size]; 24 | 25 | // 根据压缩后的图片尺寸/像素,计算图片文件大小的限值 26 | int maxFileSize = [self zy_computeMaxFileSizeForImageBrowser:newSize]; 27 | 28 | // 图片尺寸调整 29 | UIImage *resizedImage = [self resizedImageToFitInSize:newSize scaleIfSmaller:NO]; 30 | 31 | // 图片默认压缩率为85% 32 | double quality = 0.85; 33 | NSData *imageData = UIImageJPEGRepresentation(resizedImage, quality); 34 | 35 | NSUInteger fileSize = imageData.length; 36 | // 调整图片压缩率,使图片文件大小符合限值要求 37 | while(fileSize > maxFileSize * 1024 && quality > 0.2) { // 压缩率不能小于0.2 (20%) 38 | // 压缩率递减 39 | if(quality > 0.6){ 40 | quality -= 0.15; // 每次15%递减 41 | } 42 | else{ 43 | quality -= 0.05; // 每次5%递减 44 | } 45 | 46 | imageData = UIImageJPEGRepresentation(resizedImage, quality); 47 | fileSize = imageData.length; 48 | } 49 | 50 | return imageData; 51 | } 52 | 53 | /** 54 | 计算压缩后的图片尺寸 55 | 图片尺寸算法参考 https://github.com/Curzibn/Luban/blob/master/DESCRIPTION.md 56 | 57 | @param size 原图片尺寸 58 | @return 压缩后的图片尺寸 59 | */ 60 | - (CGSize)zy_computeSizeForImageBrowser:(CGSize)size{ 61 | int n; 62 | int fileSizeThreshold = 100; 63 | 64 | int srcWidth = (int) size.width; 65 | int srcHeight = (int) size.height; 66 | 67 | srcWidth = srcWidth % 2 == 1 ? srcWidth + 1 : srcWidth; 68 | srcHeight = srcHeight % 2 == 1 ? srcHeight + 1 : srcHeight; 69 | 70 | int newW; 71 | int newH; 72 | 73 | int longSide = MAX(srcWidth, srcHeight); 74 | int shortSide = MIN(srcWidth, srcHeight); 75 | double scale = ((double)shortSide / (double)longSide); 76 | if (scale <= 1 && scale > 0.5625) { 77 | if (longSide < 1664) { 78 | scale = 1; 79 | n = 1; 80 | fileSizeThreshold = 60; 81 | } else if (longSide < 4990) { 82 | n = 2; 83 | } else if (longSide > 4990 && longSide < 10240) { 84 | n = 4; 85 | } else { 86 | n = longSide / 1280 == 0 ? 1 : longSide / 1280; 87 | } 88 | } else if (scale <= 0.5625 && scale > 0.5) { 89 | n = longSide / 1280 == 0 ? 1 : longSide / 1280; 90 | } else { 91 | n = (int) ceil((double)longSide / (1280.0 / scale)); 92 | } 93 | 94 | newW = srcWidth / n; 95 | newH = srcHeight / n; 96 | 97 | return CGSizeMake(newW, newH); 98 | } 99 | 100 | 101 | /** 102 | 根据图片尺寸,计算文件大小的限值 103 | 小于50万像素: 最大100KB 104 | 50万 ~ 500万像素区间: 公式 => 图片像素/{1万} * (0.71 + 0.49 * sqrt({500万}/图片像素)) 105 | - 50万像素~= 112KB 106 | - 100万像素~= 180KB 107 | - 200万像素~= 296KB 108 | - 300万像素~= 402KB 109 | - 400万像素~= 503KB 110 | - 500万像素~= 600KB 111 | 大于500万像素: 最大650KB 112 | 113 | @param imageSize 图片尺寸 114 | @return 最大文件大小 115 | */ 116 | - (int)zy_computeMaxFileSizeForImageBrowser:(CGSize)imageSize{ 117 | int maxFileSize; 118 | double m = 10000.0; 119 | 120 | double totalImagePixel = (double)imageSize.width * (double)imageSize.height; 121 | if(totalImagePixel < (50.0 * m)){ 122 | maxFileSize = 100; 123 | } 124 | else if(totalImagePixel > (500.0 * m)){ 125 | maxFileSize = 650; 126 | } 127 | else{ 128 | maxFileSize = (int)(totalImagePixel/m * (0.71 + 0.49 * sqrt(500.0 * m/totalImagePixel))); 129 | } 130 | 131 | return maxFileSize; 132 | } 133 | 134 | 135 | @end 136 | -------------------------------------------------------------------------------- /ZYImageCompress/UIImage+ZYCompressJPEG.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+ZYCompressJPEG.h 3 | // Example 4 | // 5 | // Created by Jerry Hu on 2020/6/5. 6 | // Copyright © 2020 Zhangyin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface UIImage (ZYCompressJPEG) 14 | 15 | /** 16 | 根据指定最大文件大小压缩图片 17 | 18 | @param maxFileSize 缩略图最大文件大小 19 | @param initQuality 图片初始压缩质量 0.2~1.0之间的小数 (0.9 = 90%) 20 | @return 压缩后的缩略图, JPEG格式 21 | */ 22 | - (NSData *)zy_compressWithMaxFileSize:(NSInteger)maxFileSize initQuality:(double)initQuality; 23 | 24 | /** 25 | 根据指定最大文件大小压缩图片 26 | 27 | @param maxFileSize 缩略图最大文件大小 28 | @return 压缩后的缩略图, JPEG格式 29 | */ 30 | - (NSData *)zy_compressWithMaxFileSize:(NSInteger)maxFileSize; 31 | 32 | @end 33 | 34 | NS_ASSUME_NONNULL_END 35 | -------------------------------------------------------------------------------- /ZYImageCompress/UIImage+ZYCompressJPEG.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+ZYCompressJPEG.m 3 | // Example 4 | // 5 | // Created by Jerry Hu on 2020/6/5. 6 | // Copyright © 2020 Zhangyin. All rights reserved. 7 | // 8 | 9 | #import "UIImage+ZYCompressJPEG.h" 10 | 11 | @implementation UIImage (ZYCompressJPEG) 12 | 13 | /** 14 | 根据指定最大文件大小压缩图片 15 | 16 | @param maxFileSize 缩略图最大文件大小 17 | @param initQuality 图片初始压缩质量 0.2~1.0之间的小数 (0.9 = 90%) 18 | @return 压缩后的缩略图, JPEG格式 19 | */ 20 | - (NSData *)zy_compressWithMaxFileSize:(NSInteger)maxFileSize initQuality:(double)initQuality{ 21 | double quality = initQuality; 22 | if(quality > 1){ 23 | quality = 1; 24 | } 25 | if(quality < 0.2){ 26 | quality = 0.2; 27 | } 28 | NSData *imageData = UIImageJPEGRepresentation(self, quality); 29 | 30 | NSUInteger fileSize = imageData.length; 31 | // 调整图片压缩率,使图片文件大小符合限值要求 32 | while(fileSize > maxFileSize * 1024 && quality > 0.2) { // 压缩率不能小于0.2 (20%) 33 | // 压缩率递减 34 | if(quality > 0.6){ 35 | quality -= 0.15; // 每次15%递减 36 | } 37 | else{ 38 | quality -= 0.1; // 每次10%递减 39 | } 40 | 41 | imageData = UIImageJPEGRepresentation(self, quality); 42 | fileSize = imageData.length; 43 | } 44 | 45 | return imageData; 46 | } 47 | 48 | /** 49 | 根据指定最大文件大小压缩图片 50 | 51 | @param maxFileSize 缩略图最大文件大小 52 | @return 压缩后的缩略图, JPEG格式 53 | */ 54 | - (NSData *)zy_compressWithMaxFileSize:(NSInteger)maxFileSize{ 55 | return [self zy_compressWithMaxFileSize:maxFileSize initQuality:0.85]; 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /ZYImageCompress/UIImage+ZYCompressMoments.h: -------------------------------------------------------------------------------- 1 | /*********************************************************************************** 2 | * MIT License 3 | * 4 | * Copyright (c) 2019 Jerry Hu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | ***********************************************************************************/ 25 | 26 | #import 27 | 28 | NS_ASSUME_NONNULL_BEGIN 29 | 30 | @interface UIImage (ZYCompressMoments) 31 | 32 | /** 33 | JPEG图片压缩, 适用于朋友圈 34 | 图片压缩算法参考 => https://github.com/Curzibn/Luban/blob/master/DESCRIPTION.md 35 | 36 | @return 压缩后的图片数据 37 | */ 38 | - (NSData *)zy_compressForMoments; 39 | 40 | @end 41 | 42 | NS_ASSUME_NONNULL_END 43 | -------------------------------------------------------------------------------- /ZYImageCompress/UIImage+ZYCompressMoments.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+ZYCompressMoments.m 3 | // 图片压缩,适用于朋友圈的图片 4 | // 参考了鲁班的算法 https://github.com/Curzibn/Luban 5 | // 6 | // Created by Jerry Hu on 2019/3/24. 7 | // 8 | 9 | #import "UIImage+ZYCompressMoments.h" 10 | #import "UIImage+Resize.h" 11 | 12 | @implementation UIImage (ZYCompressMoments) 13 | 14 | typedef struct { 15 | CGSize newSize; 16 | NSInteger maxFileSize; 17 | } LubanComputeResult; 18 | 19 | /** 20 | 图片压缩, 适用于朋友圈 21 | 图片压缩算法参考 => https://github.com/Curzibn/Luban/blob/master/DESCRIPTION.md 22 | 23 | @return 压缩后的图片数据, JPEG格式 24 | */ 25 | - (NSData *)zy_compressForMoments { 26 | // 计算压缩后的图片尺寸 27 | LubanComputeResult computeResult = [self zy_computeSizeForMoments:self.size]; 28 | 29 | // 图片尺寸调整 30 | UIImage *resizedImage = [self resizedImageToFitInSize:computeResult.newSize scaleIfSmaller:NO]; 31 | 32 | // 图片默认压缩率为85% 33 | double quality = 0.85; 34 | NSData *imageData = UIImageJPEGRepresentation(resizedImage, quality); 35 | 36 | NSUInteger fileSize = imageData.length; 37 | // 调整图片压缩率,使图片文件大小符合限值要求 38 | while(fileSize > computeResult.maxFileSize * 1024 && quality > 0.2) { // 压缩率不能小于0.2 (20%) 39 | // 压缩率递减 40 | if(quality > 0.6){ 41 | quality -= 0.15; // 每次15%递减 42 | } 43 | else{ 44 | quality -= 0.05; // 每次5%递减 45 | } 46 | 47 | imageData = UIImageJPEGRepresentation(resizedImage, quality); 48 | fileSize = imageData.length; 49 | } 50 | 51 | return imageData; 52 | } 53 | 54 | /** 55 | 计算压缩后的图片尺寸和文件大小的限制 56 | 57 | @param size 原图尺寸 58 | @return 压缩后的图片尺寸和文件大小限制 59 | */ 60 | - (LubanComputeResult)zy_computeSizeForMoments:(CGSize)size{ 61 | int maxFileSize; 62 | int n; 63 | int m; 64 | int fileSizeThreshold = 100; 65 | 66 | LubanComputeResult mLubanComputeResult; 67 | 68 | int srcWidth = (int) size.width; 69 | int srcHeight = (int) size.height; 70 | 71 | srcWidth = srcWidth % 2 == 1 ? srcWidth + 1 : srcWidth; 72 | srcHeight = srcHeight % 2 == 1 ? srcHeight + 1 : srcHeight; 73 | 74 | int newW; 75 | int newH; 76 | 77 | int longSide = MAX(srcWidth, srcHeight); 78 | int shortSide = MIN(srcWidth, srcHeight); 79 | double scale = ((double)shortSide / (double)longSide); 80 | if (scale <= 1 && scale > 0.5625) { 81 | if (longSide < 1664) { 82 | scale = 1; 83 | n = 1; 84 | m = 500; 85 | fileSizeThreshold = 60; 86 | newW = srcWidth / n; 87 | newH = srcHeight / n; 88 | maxFileSize = (int)((double)newW * (double)newH) / pow(1664.0, 2.0) * (double)m; 89 | } else if (longSide < 4990) { 90 | n = 2; 91 | m = 800; 92 | newW = srcWidth / n; 93 | newH = srcHeight / n; 94 | maxFileSize = (int)((double)newW * (double)newH) / pow(4990.0, 2.0) * (double)m; 95 | } else if (longSide > 4990 && longSide < 10240) { 96 | n = 4; 97 | m = 800; 98 | newW = srcWidth / n; 99 | newH = srcHeight / n; 100 | maxFileSize = (int)((double)newW * (double)newH) / pow(1280.0 * n, 2.0) * (double)m; 101 | } else { 102 | n = longSide / 1280 == 0 ? 1 : longSide / 1280; 103 | m = 800; 104 | newW = srcWidth / n; 105 | newH = srcHeight / n; 106 | maxFileSize = (int)((double)newW * (double)newH) / pow(1280.0 * n, 2.0) * (double)m; 107 | } 108 | } else if (scale <= 0.5625 && scale > 0.5) { 109 | n = longSide / 1280 == 0 ? 1 : longSide / 1280; 110 | m = 500; 111 | newW = srcWidth / n; 112 | newH = srcHeight / n; 113 | maxFileSize = (int)((double)newW * (double)newH) / (1440.0 * 2560.0) * (double)m; 114 | } else { 115 | n = (int) ceil((double)longSide / (1280.0 / scale)); 116 | m = 500; 117 | newW = srcWidth / n; 118 | newH = srcHeight / n; 119 | maxFileSize = (int)((double)newW * (double)newH) / (1280.0 * (1280.0 / scale)) * (double)m; 120 | } 121 | 122 | maxFileSize = maxFileSize < fileSizeThreshold ? fileSizeThreshold : maxFileSize; 123 | 124 | mLubanComputeResult.newSize = CGSizeMake(newW, newH); 125 | mLubanComputeResult.maxFileSize = maxFileSize; 126 | 127 | return mLubanComputeResult; 128 | } 129 | 130 | @end 131 | -------------------------------------------------------------------------------- /ZYImageCompress/UIImage+ZYCompressThumb.h: -------------------------------------------------------------------------------- 1 | /*********************************************************************************** 2 | * MIT License 3 | * 4 | * Copyright (c) 2019 Jerry Hu 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | ***********************************************************************************/ 25 | 26 | #import 27 | 28 | NS_ASSUME_NONNULL_BEGIN 29 | 30 | @interface UIImage (ZYCompressThumb) 31 | 32 | /** 33 | 根据指定尺寸获取缩略图,并压缩图片 34 | 35 | @param size 缩略图尺寸 36 | @return 压缩后的缩略图 37 | */ 38 | - (NSData *)zy_thumbAndCompressWithSize:(CGSize)size; 39 | 40 | /** 41 | 根据指定尺寸获取缩略图,并按照指定最大文件大小压缩图片 42 | 43 | @param size 缩略图尺寸 44 | @param maxFileSize 缩略图最大文件大小 45 | @return 压缩后的缩略图 46 | */ 47 | - (NSData *)zy_thumbAndCompressWithSize:(CGSize)size maxFileSize:(NSInteger)maxFileSize; 48 | 49 | /** 50 | 根据指定尺寸获取缩略图 51 | 52 | @param size 缩略图尺寸 53 | @return 缩略图 54 | */ 55 | - (UIImage *)zy_thumbWithSize:(CGSize)size; 56 | 57 | @end 58 | 59 | NS_ASSUME_NONNULL_END 60 | -------------------------------------------------------------------------------- /ZYImageCompress/UIImage+ZYCompressThumb.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+ZYCompressThumb.m 3 | // 图片生成缩略图,并压缩文件大小 4 | // 5 | // Created by Jerry Hu on 2019/3/24. 6 | // 7 | 8 | #import "UIImage+ZYCompressThumb.h" 9 | 10 | @implementation UIImage (ZYCompressThumb) 11 | 12 | /** 13 | 根据指定尺寸获取缩略图,并压缩图片 14 | 15 | @param size 缩略图尺寸 16 | @return 压缩后的缩略图, JPEG格式 17 | */ 18 | - (NSData *)zy_thumbAndCompressWithSize:(CGSize)size{ 19 | // 根据压缩后的图片尺寸/像素,计算图片文件大小的限值 20 | int maxFileSize = [self zy_computeMaxFileSizeForThumb:size]; 21 | 22 | return [self zy_thumbAndCompressWithSize:size maxFileSize:maxFileSize]; 23 | } 24 | 25 | /** 26 | 根据指定尺寸获取缩略图,并按照指定最大文件大小压缩图片 27 | 28 | @param size 缩略图尺寸 29 | @param maxFileSize 缩略图最大文件大小 30 | @return 压缩后的缩略图, JPEG格式 31 | */ 32 | - (NSData *)zy_thumbAndCompressWithSize:(CGSize)size maxFileSize:(NSInteger)maxFileSize{ 33 | UIImage *thumbImage = [self zy_thumbWithSize:size]; 34 | 35 | // 图片默认压缩率为85% 36 | double quality = 0.85; 37 | NSData *imageData = UIImageJPEGRepresentation(thumbImage, quality); 38 | 39 | NSUInteger fileSize = imageData.length; 40 | // 调整图片压缩率,使图片文件大小符合限值要求 41 | while(fileSize > maxFileSize * 1024 && quality > 0.2) { // 压缩率不能小于0.2 (20%) 42 | // 压缩率递减 43 | if(quality > 0.6){ 44 | quality -= 0.15; // 每次15%递减 45 | } 46 | else{ 47 | quality -= 0.1; // 每次10%递减 48 | } 49 | 50 | imageData = UIImageJPEGRepresentation(thumbImage, quality); 51 | fileSize = imageData.length; 52 | } 53 | 54 | return imageData; 55 | } 56 | 57 | /** 58 | 根据指定尺寸获取缩略图 59 | 60 | @param size 缩略图尺寸 61 | @return 缩略图 62 | */ 63 | - (UIImage *)zy_thumbWithSize:(CGSize)size{ 64 | CGFloat srcWidth = self.size.width; 65 | CGFloat srcHeight = self.size.height; 66 | 67 | CGFloat targetWidth = size.width; 68 | CGFloat targetHeight = size.height; 69 | 70 | CGFloat scaleFactor = 0.0; 71 | 72 | CGFloat scaledWidth = targetWidth; 73 | CGFloat scaledHeight = targetHeight; 74 | 75 | CGPoint thumbnailPoint = CGPointMake(0.0, 0.0); 76 | if(CGSizeEqualToSize(self.size, size) == NO){ 77 | CGFloat widthFactor = targetWidth / srcWidth; 78 | CGFloat heightFactor = targetHeight / srcHeight; 79 | if(widthFactor > heightFactor){ 80 | scaleFactor = widthFactor; 81 | } 82 | else{ 83 | scaleFactor = heightFactor; 84 | } 85 | scaledWidth = srcWidth * scaleFactor; 86 | scaledHeight = srcHeight * scaleFactor; 87 | if(widthFactor > heightFactor){ 88 | thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 89 | } 90 | else if(widthFactor < heightFactor){ 91 | thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5; 92 | } 93 | } 94 | 95 | UIImage *thumbImage = nil; 96 | 97 | UIGraphicsBeginImageContextWithOptions(size, NO, 1.0); 98 | CGRect thumbnailRect = CGRectZero; 99 | thumbnailRect.origin = thumbnailPoint; 100 | thumbnailRect.size.width = scaledWidth; 101 | thumbnailRect.size.height = scaledHeight; 102 | [self drawInRect:thumbnailRect]; 103 | thumbImage = UIGraphicsGetImageFromCurrentImageContext(); 104 | UIGraphicsEndImageContext(); 105 | 106 | return thumbImage; 107 | } 108 | 109 | /** 110 | 根据图片尺寸,计算缩略图最大文件大小 111 | 公式 => 图片像素/{1万} * 4KB 112 | 113 | @param imageSize 图片尺寸 114 | @return 缩略图最大文件大小 115 | */ 116 | - (int)zy_computeMaxFileSizeForThumb:(CGSize)imageSize{ 117 | double m = 10000.0; 118 | 119 | double totalImagePixel = (double)imageSize.width * (double)imageSize.height; 120 | int maxFileSize = (int)(totalImagePixel/m * 4.0); 121 | 122 | return maxFileSize; 123 | } 124 | 125 | @end 126 | -------------------------------------------------------------------------------- /ZYImageCompress/ZYImageCompress.h: -------------------------------------------------------------------------------- 1 | /*********************************************************************************** 2 | * MIT License 3 | * 4 | * Created by Jerry Hu on 2019/3/24. 5 | * Copyright (c) 2019 Jerry Hu 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | ***********************************************************************************/ 26 | 27 | 28 | #import "UIImage+ZYCompressIB.h" 29 | #import "UIImage+ZYCompressThumb.h" 30 | #import "UIImage+ZYCompressMoments.h" 31 | #import "UIImage+ZYCompressJPEG.h" 32 | --------------------------------------------------------------------------------