美文网首页
图片压缩性能对比

图片压缩性能对比

作者: 愤怒小鸟飞呀飞 | 来源:发表于2019-01-02 21:09 被阅读0次

参考链接:
https://www.jianshu.com/p/4dcd6e4bdbf0
https://nshipster.com/image-resizing/

  • 调研的压缩方案主要有三种 UIGraphicsBeginImageContextWithOptions、ImageIO、SDWebimage 大图压缩方案

  • 压缩代码
    (1) UIGraphicsGetImageFromCurrentImageContext&drawInRect

- (NSData *)compressImageData
{
   CGRect rect = CGRectMake(0.0, 0.0, (int)100, (int)100);
   UIGraphicsBeginImageContextWithOptions(rect.size, NO, 1);
   [self drawInRect:rect];
   UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
   NSData *imageData = UIImageJPEGRepresentation(img, 1);

   UIGraphicsEndImageContext();
   return imageData;
}

(2) SDWebimage 分段 循环绘制

  @autoreleasepool {
        CGImageRef sourceImageRef = image.CGImage;
        
        CGSize sourceResolution = CGSizeZero;
        sourceResolution.width = CGImageGetWidth(sourceImageRef);
        sourceResolution.height = CGImageGetHeight(sourceImageRef);
        float sourceTotalPixels = sourceResolution.width * sourceResolution.height;
        // Determine the scale ratio to apply to the input image
        // that results in an output image of the defined size.
        // see kDestImageSizeMB, and how it relates to destTotalPixels.
        float imageScale = kDestTotalPixels / sourceTotalPixels;
        CGSize destResolution = CGSizeZero;
        destResolution.width = (int)(sourceResolution.width*imageScale);
        destResolution.height = (int)(sourceResolution.height*imageScale);
        
        // device color space
        CGColorSpaceRef colorspaceRef = SDCGColorSpaceGetDeviceRGB();
        BOOL hasAlpha = SDCGImageRefContainsAlpha(sourceImageRef);
        // iOS display alpha info (BGRA8888/BGRX8888)
        CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host;
        bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
        
        // kCGImageAlphaNone is not supported in CGBitmapContextCreate.
        // Since the original image here has no alpha info, use kCGImageAlphaNoneSkipLast
        // to create bitmap graphics contexts without alpha info.
        destContext = CGBitmapContextCreate(NULL,
                                            destResolution.width,
                                            destResolution.height,
                                            kBitsPerComponent,
                                            0,
                                            colorspaceRef,
                                            bitmapInfo);
        
        if (destContext == NULL) {
            return image;
        }
        CGContextSetInterpolationQuality(destContext, kCGInterpolationDefault);
        
        // Now define the size of the rectangle to be used for the
        // incremental blits from the input image to the output image.
        // we use a source tile width equal to the width of the source
        // image due to the way that iOS retrieves image data from disk.
        // iOS must decode an image from disk in full width 'bands', even
        // if current graphics context is clipped to a subrect within that
        // band. Therefore we fully utilize all of the pixel data that results
        // from a decoding opertion by achnoring our tile size to the full
        // width of the input image.
        CGRect sourceTile = CGRectZero;
        sourceTile.size.width = sourceResolution.width;
        // The source tile height is dynamic. Since we specified the size
        // of the source tile in MB, see how many rows of pixels high it
        // can be given the input image width.
        sourceTile.size.height = (int)(kTileTotalPixels / sourceTile.size.width );
        sourceTile.origin.x = 0.0f;
        // The output tile is the same proportions as the input tile, but
        // scaled to image scale.
        CGRect destTile;
        destTile.size.width = destResolution.width;
        destTile.size.height = sourceTile.size.height * imageScale;
        destTile.origin.x = 0.0f;
        // The source seem overlap is proportionate to the destination seem overlap.
        // this is the amount of pixels to overlap each tile as we assemble the ouput image.
        float sourceSeemOverlap = (int)((kDestSeemOverlap/destResolution.height)*sourceResolution.height);
        CGImageRef sourceTileImageRef;
        // calculate the number of read/write operations required to assemble the
        // output image.
        int iterations = (int)( sourceResolution.height / sourceTile.size.height );
        // If tile height doesn't divide the image height evenly, add another iteration
        // to account for the remaining pixels.
        int remainder = (int)sourceResolution.height % (int)sourceTile.size.height;
        if(remainder) {
            iterations++;
        }
        // Add seem overlaps to the tiles, but save the original tile height for y coordinate calculations.
        float sourceTileHeightMinusOverlap = sourceTile.size.height;
        sourceTile.size.height += sourceSeemOverlap;
        destTile.size.height += kDestSeemOverlap;
        for( int y = 0; y < iterations; ++y ) {
            @autoreleasepool {
                sourceTile.origin.y = y * sourceTileHeightMinusOverlap + sourceSeemOverlap;
                destTile.origin.y = destResolution.height - (( y + 1 ) * sourceTileHeightMinusOverlap * imageScale + kDestSeemOverlap);
                sourceTileImageRef = CGImageCreateWithImageInRect( sourceImageRef, sourceTile );
                if( y == iterations - 1 && remainder ) {
                    float dify = destTile.size.height;
                    destTile.size.height = CGImageGetHeight( sourceTileImageRef ) * imageScale;
                    dify -= destTile.size.height;
                    destTile.origin.y += dify;
                }
                CGContextDrawImage( destContext, destTile, sourceTileImageRef );
                CGImageRelease( sourceTileImageRef );
            }
        }
        
        CGImageRef destImageRef = CGBitmapContextCreateImage(destContext);
        CGContextRelease(destContext);
        if (destImageRef == NULL) {
            return image;
        }
        UIImage *destImage = [[UIImage alloc] initWithCGImage:destImageRef scale:image.scale orientation:image.imageOrientation];
        CGImageRelease(destImageRef);
        if (destImage == nil) {
            return image;
        }
        return destImage;
    }
}

(3)ImageIO

        let string = Bundle.main.path(forResource: "VIIRS_3Feb2012_lrg", ofType: "jpg");
        self.URL = NSURL.fileURL(withPath: string!) as NSURL
    let date = Date.init(timeIntervalSinceNow: 0)
        // Do any additional setup after loading the view, typically from a nib.
        let size = CGSize.init(width: 100, height: 100)
        
//        ImageIO
        if let imageSource = CGImageSourceCreateWithURL(self.URL!, nil) {
            let options: [NSString: NSObject] = [
                kCGImageSourceThumbnailMaxPixelSize: max(size.width, size.height)  as NSObject,
                kCGImageSourceCreateThumbnailFromImageAlways: true as NSObject
            ]

            let scaledImage = CGImageSourceCreateThumbnailAtIndex(imageSource, 0, options as CFDictionary).flatMap { UIImage(cgImage: $0) }
            let data = scaledImage?.jpegData(compressionQuality: 1)
            print("\(Date.init(timeIntervalSinceNow: 0).timeIntervalSince(date))")

  • 测试结果:
    (1) iphoneXR 系统12.1.2
    全景图 imageSize: 16382 × 3628 压缩至:1000*100
API 压缩大小 内存消耗 耗时
UI 100* 100 峰值7.78 平稳4.78 0.354609
SD 1M 峰值134 平稳 4.43 0.672967
IO 100* 100 峰值7.69 平稳4.21 0.339498

(2) iphone8p 系统12.0.1
imageSize:1242 × 6075 压缩至:100*100

API 压缩大小 内存消耗 耗时
UI 100* 100 峰值14.6 平稳 11.3 0.06
SD 100*100 峰值 21.7 平稳 11.2 0.09
IO 100* 100 峰值 20.9 平稳 12.1 0.0938

(3)iphone7p 系统 11.2.1
imageSize:3024 × 4032 压缩至:100*100

API 压缩大小 内存消耗 耗时
UI 100* 100 峰值50.2 平稳4.28 0.640203
SD 100*100 峰值49.2 平稳3.4 0.791870
IO 100* 100 峰值3.69 平稳3.2 0.1033

(4)iphone7p 系统 11.2.1
imageSize:12000 * 12000 压缩至:100*100

API 压缩大小 内存消耗 耗时
UI 100* 100 峰值 11.82 平稳3.29 0.32567
SD 100*100 峰值 157.52 3.16 3.420274
IO 100* 100 峰值3.69 平稳3.46 0.14890503883361816

(5)iphone 6 系统 10.3.2
12000 * 12000 压缩至:100*100

API 压缩大小 内存消耗 耗时
UI 100* 100 3.6 0.343466
SD 100*100 峰值 156M 平稳 3.7 4.298185
IO 100* 100 3.5 0.418
  • 结论
    从测试结果可以看出 图片压缩 imageIO,UIGraphic性能表现良好,UIGraphic需要占用主线程绘制,对于需要后台绘制imageIO表现处理很大的优势,imageIO在各种图片压缩上整体表现良好; SD针对超长大图有优势,其他方面表现很差,这跟本身循环绘制原理也有必然联系 ,SD用的CGImageCreateWithImageInRect和CGContenxtDrawImage本身压缩性能也不错,在图片剪裁方面优势较大 ;
    代码地址:https://github.com/denghuihua/ImageScale

ImageIO 介绍:
Image I/O is a powerful, yet lesser-known framework for working with images. Independent of Core Graphics, it can read and write between many different formats, access photo metadata, and perform common image processing operations. The framework offers the fastest image encoders and decoders on the platform, with advanced caching mechanisms and even the ability to load images incrementally.
映像I/O是一个功能强大但不太为人所知的处理映像的框架。它独立于核心图形,可以在许多不同格式之间读写,访问照片元数据,并执行常见的图像处理操作。该框架提供了平台上最快的图像编码器和解码器,具有先进的缓存机制,甚至可以增量加载图像。

相关文章

  • 图片压缩性能对比

    参考链接:https://www.jianshu.com/p/4dcd6e4bdbf0https://nships...

  • 性能优化04-图片优化

    性能优化04-图片优化 一、图片压缩 图片在APP中通常占用很大的内存,所以经常需要进行图片压缩。 常用的图片压缩...

  • 安卓开发详解—Android安装包性能优化

    安装包的性能优化的精髓:尽量删。 安装包的性能优化方法: 1.图片压缩: 图片:apk里面的资源图片 压缩图片 s...

  • 十三、Android性能优化之安装包的性能优化

    安装包的性能优化的精髓:尽量删。安装包的性能优化方法: 1.图片压缩 图片:apk里面的资源图片 压缩图片svg图...

  • Android优化全面攻略

    一 :安装包性能压缩 一个字:删!!删不了就尽量小。 1.图片压缩 图片:apk里面的资源图片 压缩图片svg图片...

  • 安装包的性能优化

    安装包的性能优化方法 1.图片压缩 图片:apk里面的资源图片 压缩图片svg图片:一些图片的描述,牺牲CPU的计...

  • 前端性能优化方式

    2.前端性能优化方式 减少http请求。 大量图片渲染使用懒加载技术,图片压缩。 压缩代码,将javascript...

  • 压缩算法性能对比

    看一个压缩算法的优劣,有两个重要的指标:一个指标是压缩比,原先占 100 份空间的东西经压缩之后变成了占 20 份...

  • 面试题总结

    1页面性能优化方法精简html结构,避免过多的嵌套优化css,压缩合并,可复用图片压缩,雪碧图,图片过小(<12k...

  • iOS图片压缩新思路与代码性能对比

    关于图片的压缩或者增大,我们在网上可以搜到很多的例子.在这里,我来展示一个逼格高一点的,性能给力的!二话不说,先上...

网友评论

      本文标题:图片压缩性能对比

      本文链接:https://www.haomeiwen.com/subject/osftrqtx.html