zoukankan      html  css  js  c++  java
  • 图片压缩

    UIImageJPEGRepresentation方法在耗时上比较少 而UIImagePNGRepresentation耗时操作时间比较长

    -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info

    使用UIImagePNGRepresentation取得照片时候可能会造成卡顿的现象

    在Iphone上有两种读取图片数据的简单方法: UIImageJPEGRepresentation和UIImagePNGRepresentation. 

     

    UIImageJPEGRepresentation函数需要两个参数:图片的引用和压缩系数.而UIImagePNGRepresentation只需要图片引用作为参数.通过在实际使用过程中,比较发现: UIImagePNGRepresentation(UIImage* image) 要比UIImageJPEGRepresentation(UIImage* image, 1.0) 返回的图片数据量大很多.譬如,同样是读取摄像头拍摄的同样景色的照片, UIImagePNGRepresentation()返回的数据量大小为199K ,而 UIImageJPEGRepresentation(UIImage* image, 1.0)返回的数据量大小只为140KB,比前者少了50多KB.如果对图片的清晰度要求不高,还可以通过设置 UIImageJPEGRepresentation函数的第二个参数,大幅度降低图片数据量.譬如,刚才拍摄的图片, 通过调用UIImageJPEGRepresentation(UIImage* image, 1.0)读取数据时,返回的数据大小为140KB,但更改压缩系数后,通过调用UIImageJPEGRepresentation(UIImage* image, 0.5)读取数据时,返回的数据大小只有11KB多,大大压缩了图片的数据量 ,而且从视角角度看,图片的质量并没有明显的降低.因此,在读取图片数据内容时,建议优先使用UIImageJPEGRepresentation,并可根据自己的实际使用场景,设置压缩系数,进一步降低图片数据量大小.

    [cpp] view plain copy
     
    1. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];  
    2.  [formatter setDateFormat:@"YYYY-MM-DD-hh-mm-ss"];  
     
    [cpp] view plain copy
     
    1. if (UIImagePNGRepresentation(image)==nil) {  
    2.     data = UIImageJPEGRepresentation(image, 1.0);  
    3. }else{  
    4.     data = UIImagePNGRepresentation(image);  
    5. }  
     
     
     

    我是用这个函数对图片进行压缩的

    NSData *fData = UIImageJPEGRepresentation(self.photo, 1.0);

    这样,图片是7MB这样。假如压缩级别是0.5,如:

    NSData *fData = UIImageJPEGRepresentation(self.photo, 0.5);

    图片压缩之后,大小是 1MB左右。。现在问题来了。

    一张图片,压缩级别是0.5的话,大小不会变成原来的0.5倍。我算了一下,大概是0.14.所以压缩级别和这个大小好像不能形成一定的关联。

    比如我一张 500KB的图片,0.5的压缩级别。大小可能才100多KB。对我来说,正好。但是假如像上面那样,7MB的大小,按照这样的压缩率,就是1MB.所以图片时大时小。对用户来说,体验肯定比较差。

    我想动态的压缩图片,让没有wifi的情况下,无论多少大小的图片,压缩之后大小最大 200KB。有wifi,压缩大小最大 700KB。

    目前有比较好的算法吗?或者开源的函数。

    --------------------------

    贴一个相关函数

    //图片压缩到指定大小

    - (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize

    {

        UIImage *sourceImage = self;

        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;

           

           // center theimage

           if (widthFactor > heightFactor)

           {

               thumbnailPoint.y =(targetHeight - scaledHeight) * 0.5;

           }

           elseif (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)

        NSLog(@"could not scale image");

       

        //pop the context to get back tothe default

       UIGraphicsEndImageContext();

        return newImage;

    }纳

    第二个参数是压缩系数,他的设置并不能保证图片的大小,因为压缩之后的大小和图片的内容也有关系,比如你的图片的的颜色相似的话压缩之后图片的大小就会小点。你所在在意的wifi情况压缩图片是不是指需要上传呢,如果是需要上传的话你可以压缩两种格式的图片,高质量的和低质量的图片,有wifi的情况下上传高质量的图片,没有wifi的情况下上传低质量的图片

    UIImageJPEGRepresentation(self.photo, 0.5);

    对于每张图片进行压缩,其实有一个最小值,此后无论再怎么改小压缩系数都无济于事。

    如果还是过大,只能裁剪图片了。

    - (NSData *)imageWithImage:(UIImage*)image

             scaledToSize:(CGSize)newSize;

    {

       UIGraphicsBeginImageContext(newSize);

       [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];

        UIImage* newImage =UIGraphicsGetImageFromCurrentImageContext();

       UIGraphicsEndImageContext();

        return UIImageJPEGRepresentation(newImage, 0.8);

    }

    你可以弄一个 for 循环,不断的逼近你要的大小

    - (UIImage *)compressImage:(UIImage *)image toMaxFileSize:(NSInteger)maxFileSize {

        CGFloat compression = 0.9f;

        CGFloat maxCompression = 0.1f;

        NSData *imageData =UIImageJPEGRepresentation(image, compression);

        while ([imageData length] > maxFileSize&& compression > maxCompression) {

           compression -= 0.1;

           imageData = UIImageJPEGRepresentation(image, compression);

        }

       

        UIImage *compressedImage = [UIImage imageWithData:imageData];

        return compressedImage;

    }

      

    图片的压缩其实是俩概念,

    1、是 “压” 文件体积变小,但是像素数不变,长宽尺寸不变,那么质量可能下降,

    2、是 “缩” 文件的尺寸变小,也就是像素数减少。长宽尺寸变小,文件体积同样会减小。

    这个 UIImageJPEGRepresentation(image,0.0),是1的功能。

    这个 [sourceImagedrawInRect:CGRectMake(0,0,targetWidth, targetHeight)] 是2的功能。

    所以,这俩你得结合使用来满足需求,不然你一味的用1,导致,图片模糊的不行,但是尺寸还是很大。

     

    我有个图片,可能是14M或者更多,想把它压缩到500K以内,UIImageJPEGRepresentation(image,0.0),就算这个压缩系数设置为最小,压缩后仍然比500k大;那有什么方法能把任意大小的图片压缩到指定的字节大小呢,忽略图片清晰度的要求!楼主解决此问题没,求解!复制放进笔记

    -(UIImage *) imageCompressForWidth:(UIImage*)sourceImage targetWidth:(CGFloat)defineWidth

    {

        CGSize imageSize = sourceImage.size;

        CGFloat width = imageSize.width;

        CGFloat height = imageSize.height;

        CGFloat targetWidth = defineWidth;

        CGFloat targetHeight = (targetWidth / width) *height;

       UIGraphicsBeginImageContext(CGSizeMake(targetWidth, targetHeight));

       [sourceImage drawInRect:CGRectMake(0,0,targetWidth,  targetHeight)];

        UIImage* newImage =UIGraphicsGetImageFromCurrentImageContext();

       UIGraphicsEndImageContext();

        return newImage;

    }

     

    最近做论坛功能,发帖的时候需要用到从相册中选取图片然后上传,由于每次上传图片的最大数量为9张,所以需要对图片进行压缩。开始时用了以前经常用的压缩的方法:

    [objc] view plain copy
     
     
    1. //压缩图片质量  
    2. +(UIImage *)reduceImage:(UIImage *)image percent:(float)percent  
    3. {  
    4.     NSData *imageData = UIImageJPEGRepresentation(image, percent);  
    5.     UIImage *newImage = [UIImage imageWithData:imageData];  
    6.     return newImage;  
    7. }  
    8. //压缩图片尺寸  
    9. + (UIImage*)imageWithImageSimple:(UIImage*)image scaledToSize:(CGSize)newSize  
    10. {  
    11.     // Create a graphics image context  
    12.     UIGraphicsBeginImageContext(newSize);  
    13.     // new size  
    14.     [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];  
    15.     // Get the new image from the context  
    16.     UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();  
    17.       
    18.     // End the context  
    19.     UIGraphicsEndImageContext();  
    20.     // Return the new image.  
    21.     return newImage;  
    22. }  
    上面的方法比较常见,可是需要加载到内存中来处理图片,当图片数量多了的时候就会收到内存警告,程序崩溃。研究半天终于在一篇博客中找到了解决方法:
    [objc] view plain copy
     
     
    1. static size_t getAssetBytesCallback(voidvoid *info, voidvoid *buffer, off_t position, size_t count) {  
    2.     ALAssetRepresentation *rep = (__bridge id)info;  
    3.       
    4.     NSError *error = nil;  
    5.     size_t countRead = [rep getBytes:(uint8_t *)buffer fromOffset:position length:count error:&error];  
    6.       
    7.     if (countRead == 0 && error) {  
    8.         // We have no way of passing this info back to the caller, so we log it, at least.  
    9.         NDDebug(@"thumbnailForAsset:maxPixelSize: got an error reading an asset: %@", error);  
    10.     }  
    11.       
    12.     return countRead;  
    13. }  
    14.   
    15. static void releaseAssetCallback(voidvoid *info) {  
    16.     // The info here is an ALAssetRepresentation which we CFRetain in thumbnailForAsset:maxPixelSize:.  
    17.     // This release balances that retain.  
    18.     CFRelease(info);  
    19. }  
    20.   
    21. // Returns a UIImage for the given asset, with size length at most the passed size.  
    22. // The resulting UIImage will be already rotated to UIImageOrientationUp, so its CGImageRef  
    23. // can be used directly without additional rotation handling.  
    24. // This is done synchronously, so you should call this method on a background queue/thread.  
    25. - (UIImage *)thumbnailForAsset:(ALAsset *)asset maxPixelSize:(NSUInteger)size {  
    26.     NSParameterAssert(asset != nil);  
    27.     NSParameterAssert(size > 0);  
    28.       
    29.     ALAssetRepresentation *rep = [asset defaultRepresentation];  
    30.       
    31.     CGDataProviderDirectCallbacks callbacks = {  
    32.         .version = 0,  
    33.         .getBytePointer = NULL,  
    34.         .releaseBytePointer = NULL,  
    35.         .getBytesAtPosition = getAssetBytesCallback,  
    36.         .releaseInfo = releaseAssetCallback,  
    37.     };  
    38.       
    39.     CGDataProviderRef provider = CGDataProviderCreateDirect((voidvoid *)CFBridgingRetain(rep), [rep size], &callbacks);  
    40.     CGImageSourceRef source = CGImageSourceCreateWithDataProvider(provider, NULL);  
    41.       
    42.     CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(source, 0, (__bridge CFDictionaryRef) @{  
    43.                                                                                                       (NSString *)kCGImageSourceCreateThumbnailFromImageAlways : @YES,  
    44.                                                                                                       (NSString *)kCGImageSourceThumbnailMaxPixelSize : [NSNumber numberWithInt:size],  
    45.                                                                                                       (NSString *)kCGImageSourceCreateThumbnailWithTransform : @YES,  
    46.                                                                                                       });  
    47.     CFRelease(source);  
    48.     CFRelease(provider);  
    49.       
    50.     if (!imageRef) {  
    51.         return nil;  
    52.     }  
    53.       
    54.     UIImage *toReturn = [UIImage imageWithCGImage:imageRef];  
    55.       
    56.     CFRelease(imageRef);  
    57.       
    58.     return toReturn;  
    59. }  
  • 相关阅读:
    Flink SQL Client初探
    ansible快速部署cassandra3集群
    利用TfidfVectorizer进行中文文本分类(数据集是复旦中文语料)
    spark读取HDFS目录时报错Failed on local exception: com.google.protobuf.InvalidProtocolBufferException
    Spark学习进度-Spark环境搭建&Spark shell
    jquery获取select选中的值
    java零基础到架构师学习线路(附视频教程)
    plsql连接远程oracle数据库
    如何在通用异常处理时获取到方法名称(获取注解参数JoinPoint)
    java:找不到符号(使用lombok)
  • 原文地址:https://www.cnblogs.com/xsyl/p/5817826.html
Copyright © 2011-2022 走看看