iOS - Image compression algorithm

算法,iOS开发,Demo 归纳笔记

Posted by oragekk on December 30, 2016

由于最近公司在做图片相册选择上传的功能,对于图片的压缩算法这里我借鉴了ochina的ios端App。其中有涉及到图片压缩的算法,这里贴出来留待后用;

GACompressionPicHandle.h

	#import <Foundation/Foundation.h>
	#import <UIKit/UIKit.h>
	#import <CoreGraphics/CoreGraphics.h>
	
	@class GACompressionPicHandle;
	@protocol GACompressionPicHandleDelegate <NSObject>
	- (void)CompressionPicHandle:(GACompressionPicHandle* )handle
  			CompressionFailureInfo:(NSString* )info;
  	@end
  	
  	#define CompressionMax_W 1224
  	#define CompressionMax_Size 300 * 1024
  	/** OSChina 后台限制上传图片的大小*/
  	#define stand_size 1024 * 800
  	#define min_compressionRatio 0.3
  	
  	@interface GACompressionPicHandle : NSObject
  	
  	+ (instancetype)shareCompressionPicHandle;

@property(nonatomic,weak)id<GACompressionPicHandleDelegate> delegate;

	/** 分辨率越小反而越占用时间 建议分辨率高的图片使用*/
- (NSData* )scaleToSize:(CGSize)size
               image:(UIImage* )picture;
               
     /** 受到宽高比例问题 越接近正方形所用的时间越小 */
- (NSData *)imageByScalingAndCroppingForSize:(	CGSize)targetSize image:(UIImage *)image;
	@end

GACompressionPicHandle.m

	#import "GACompressionPicHandle.h"
	
	@implementation GACompressionPicHandle
	
	static GACompressioinPicHandle*_shareCompressionPicHandle;
	
	+ (instancetype)shareCompressionPicHandle{
		static dispatch_once_t onceToken;
		dispatch_once(&onceToken, ^{
    		_shareCompressionPicHandle = 					[[GACompressionPicHandle alloc]init];
		});
		return _shareCompressionPicHandle;
	}
	
	
	- (NSData* )scaleToSize:(CGSize)size
               image:(UIImage* )picture
               {    
                   CGFloat width = CGImageGetWidth(picture.CGImage);
                   CGFloat height = CGImageGetHeight(picture.CGImage);
                   float verticalRadio = size.height * 1.0 / height;
                   float horizontalRadio = size.width * 1.0 / width;
                   float radio = 1;
                   if(verticalRadio > 1 && horizontalRadio > 1) {
                   radio = verticalRadio > horizontalRadio ? horizontalRadio : verticalRadio;
}else{
radio = verticalRadio < horizontalRadio ? verticalRadio : horizontalRadio;
}
width = width * radio;
height = height * radio;

int xPos = (size.width - width) / 2;
int yPos = (size.height - height) / 2;

UIGraphicsBeginImageContext(size);

[picture drawInRect:CGRectMake(xPos, yPos, width, height)];

UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

NSData* scaledImageData = UIImageJPEGRepresentation(scaledImage, 1);

CGFloat compressionRatio = 0.9f;
NSData* tagerImageData = scaledImageData;
NSLog(@"tagerImageData.length : %lu",(unsigned long)tagerImageData.length);
while (tagerImageData.length > stand_size && compressionRatio > 0) {
    if (compressionRatio < min_compressionRatio) {
        if ([_delegate respondsToSelector:@selector(CompressionPicHandle:CompressionFailureInfo:)]) {
            [_delegate CompressionPicHandle:self CompressionFailureInfo:@"图片过大"];
        }
    }
    @autoreleasepool {
        NSData* newCompressionData = UIImageJPEGRepresentation(scaledImage, compressionRatio);
        tagerImageData = newCompressionData;
    }
    compressionRatio = compressionRatio - 0.12;
    NSLog(@"tagerImageData.length : %lu , compressionRatio : %lf",tagerImageData.length,compressionRatio);
}
NSLog(@"compressionRatio : %lf",compressionRatio);

return tagerImageData;
}


- (NSData *)imageByScalingAndCroppingForSize:(CGSize)targetSize image:(UIImage *)image {
UIImage *sourceImage = image;
UIImage *newImage = nil;
CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGFloat scaleFactor = 0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
CGPoint thumbnailPoint = CGPointMake(0.0,0.0);
if (CGSizeEqualToSize(imageSize, targetSize) == NO) {
CGFloat widthFactor = targetWidth / width;
CGFloat heightFactor = targetHeight / height;
if (widthFactor > heightFactor){
scaleFactor = widthFactor; // scale to fit height 
}else{
		scaleFactor = heightFactor; // scale to fit width
    }
    
    scaledWidth= width * scaleFactor;
    scaledHeight = height * scaleFactor;
    
    if (widthFactor > heightFactor) {
        thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
    } else if (widthFactor < heightFactor){
        thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
    }
}

UIGraphicsBeginImageContext(targetSize); // this will crop
CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width= scaledWidth;
thumbnailRect.size.height = scaledHeight;
[sourceImage drawInRect:thumbnailRect];
newImage = UIGraphicsGetImageFromCurrentImageContext();
if(newImage == nil)
UIGraphicsEndImageContext();

NSData* scaledImageData = UIImageJPEGRepresentation(newImage, 1);

CGFloat compressionRatio = 0.9f;
NSData* tagerImageData = scaledImageData;
NSLog(@"tagerImageData.length : %lu",(unsigned long)tagerImageData.length);
while (tagerImageData.length > stand_size && compressionRatio > 0) {
    if (compressionRatio < min_compressionRatio) {
        if ([_delegate respondsToSelector:@selector(CompressionPicHandle:CompressionFailureInfo:)]) {
            [_delegate CompressionPicHandle:self CompressionFailureInfo:@"图片过大"];
        }
    }
    @autoreleasepool {
        NSData* newCompressionData = UIImageJPEGRepresentation(newImage, compressionRatio);
        tagerImageData = newCompressionData;
    }
    compressionRatio = compressionRatio - 0.12;
    NSLog(@"tagerImageData.length : %lu , compressionRatio : %lf",tagerImageData.length,compressionRatio);
}
NSLog(@"compressionRatio : %lf",compressionRatio);

return tagerImageData; }