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

图片压缩性能对比

作者: 愤怒小鸟飞呀飞 | 来源:发表于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.haomeiwen.com/subject/osftrqtx.html