SDWebImage源碼解析(二)

1 概述

SDWebImage使用了不少工具類來對圖片的處理。好比獲取圖片類型、圖片放大縮小、GIF圖片處理、圖片解壓縮處理等。接下來我就要分析下面這幾個工具類的實現。html

2 NSData+ImageContentType分析

這個類提供了一個類方法sd_imageFormatForImageData。經過這個方法傳入圖片的NSData數據,而後返回圖片類型。圖片類型經過SDImageFormat來定義。git

/**
 不一樣圖片類型的枚舉

 - SDImageFormatUndefined: 未知
 - SDImageFormatJPEG: JPG
 - SDImageFormatPNG: PNG
 - SDImageFormatGIF: GIF
 - SDImageFormatTIFF: TIFF
 - SDImageFormatWebP: WEBP  
 */
typedef NS_ENUM(NSInteger, SDImageFormat) {
    SDImageFormatUndefined = -1,
    SDImageFormatJPEG = 0,
    SDImageFormatPNG,
    SDImageFormatGIF,
    SDImageFormatTIFF,
    SDImageFormatWebP
};
/**
 根據圖片NSData獲取圖片的類型

 @param data NSData數據
 @return 圖片數據類型
 */
+ (SDImageFormat)sd_imageFormatForImageData:(nullable NSData *)data {
    if (!data) {
        return SDImageFormatUndefined;
    }
    
    uint8_t c;
    //獲取圖片數據的第一個字節數據
    [data getBytes:&c length:1];
    //根據字母的ASC碼比較
    switch (c) {
        case 0xFF:
            return SDImageFormatJPEG;
        case 0x89:
            return SDImageFormatPNG;
        case 0x47:
            return SDImageFormatGIF;
        case 0x49:
        case 0x4D:
            return SDImageFormatTIFF;
        case 0x52:
            // R as RIFF for WEBP
            if (data.length < 12) {
                return SDImageFormatUndefined;
            }
            
            NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding];
            if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) {
                return SDImageFormatWebP;
            }
    }
    return SDImageFormatUndefined;
}

3 SDWebImageCompat分析

SDWebImageCompat就提供一個全局方法SDScaledImageForKey。這個方法根據原始圖片繪製一張放大或者縮小的圖片。github

/**
 給定一張圖片,經過scale屬性返回一個放大的圖片。

 @param key 圖片名稱
 @param image 資源圖片
 @return 處理之後的圖片
 */
inline UIImage *SDScaledImageForKey(NSString * _Nullable key, UIImage * _Nullable image) {
    //異常處理
    if (!image) {
        return nil;
    }
#if SD_MAC
    return image;
#elif SD_UIKIT || SD_WATCH
    //若是是動態圖片,好比GIF圖片,則迭代處理
    if ((image.images).count > 0) {
        NSMutableArray<UIImage *> *scaledImages = [NSMutableArray array];
        //迭代處理每一張圖片
        for (UIImage *tempImage in image.images) {
            [scaledImages addObject:SDScaledImageForKey(key, tempImage)];
        }
        //把處理結束的圖片再合成一張動態圖片
        return [UIImage animatedImageWithImages:scaledImages duration:image.duration];
    }
    else {//非動態圖片
#if SD_WATCH
        if ([[WKInterfaceDevice currentDevice] respondsToSelector:@selector(screenScale)]) {
#elif SD_UIKIT
        if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
#endif
            CGFloat scale = 1;
            // 「@2x.png」的長度爲7,因此此處添加了這個判斷,很巧妙
            if (key.length >= 8) {
                NSRange range = [key rangeOfString:@"@2x."];
                if (range.location != NSNotFound) {
                    scale = 2.0;
                }
                
                range = [key rangeOfString:@"@3x."];
                if (range.location != NSNotFound) {
                    scale = 3.0;
                }
            }
            //返回對應分辨率下面的圖片
            UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation];
            image = scaledImage;
        }
        return image;
    }
#endif
}

4 UIImage+MultiFormat分類分析

UIImage+MultiFormat分類實現了NSData與UIImage對象之間的相互轉換。而且是根據圖片類型作轉換。好比GIF的UIImage轉換爲GIF格式的NSData。
而且還有UIImage的Orientation和alpha的處理。chrome

/**
 根據image的data數據。生成對應的image對象

 @param data 圖片的數據
 @return image對象
 */
+ (nullable UIImage *)sd_imageWithData:(nullable NSData *)data {
    if (!data) {
        return nil;
    }
    UIImage *image;
    //獲取data的圖片類型,png,gif,jpg
    SDImageFormat imageFormat = [NSData sd_imageFormatForImageData:data];
    if (imageFormat == SDImageFormatGIF) {
        //gif處理:返回一張只包含數據第一張image 的gif圖片
        image = [UIImage sd_animatedGIFWithData:data];
    }
#ifdef SD_WEBP
    else if (imageFormat == SDImageFormatWebP)
    {
        image = [UIImage sd_imageWithWebPData:data];
    }
#endif
    else {
        image = [[UIImage alloc] initWithData:data];
#if SD_UIKIT || SD_WATCH
        //獲取方向
        UIImageOrientation orientation = [self sd_imageOrientationFromImageData:data];
        //若是不是向上的,還須要再次生成圖片
        if (orientation != UIImageOrientationUp) {
            image = [UIImage imageWithCGImage:image.CGImage
                                        scale:image.scale
                                  orientation:orientation];
        }
#endif
    }


    return image;
}

#if SD_UIKIT || SD_WATCH

/**
 根據圖片數據獲取圖片的方向

 @param imageData 圖片數據
 @return 方向
 */
+(UIImageOrientation)sd_imageOrientationFromImageData:(nonnull NSData *)imageData {
    //默認是向上的
    UIImageOrientation result = UIImageOrientationUp;
    CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
    if (imageSource) {
        //獲取圖片的屬性列表
        CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL);
        if (properties) {
            CFTypeRef val;
            int exifOrientation;
            //獲取圖片方向
            val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation);
            if (val) {
                CFNumberGetValue(val, kCFNumberIntType, &exifOrientation);
                result = [self sd_exifOrientationToiOSOrientation:exifOrientation];
            } // else - if it's not set it remains at up
            CFRelease((CFTypeRef) properties);
        } else {
            //NSLog(@"NO PROPERTIES, FAIL");
        }
        CFRelease(imageSource);
    }
    return result;
}
/**
 根據不一樣的值返回不一樣的圖片方向

 @param exifOrientation 輸入值
 @return 圖片的方向
 */
+ (UIImageOrientation) sd_exifOrientationToiOSOrientation:(int)exifOrientation {
    UIImageOrientation orientation = UIImageOrientationUp;
    switch (exifOrientation) {
        case 1:
            orientation = UIImageOrientationUp;
            break;

        case 3:
            orientation = UIImageOrientationDown;
            break;

        case 8:
            orientation = UIImageOrientationLeft;
            break;

        case 6:
            orientation = UIImageOrientationRight;
            break;

        case 2:
            orientation = UIImageOrientationUpMirrored;
            break;

        case 4:
            orientation = UIImageOrientationDownMirrored;
            break;

        case 5:
            orientation = UIImageOrientationLeftMirrored;
            break;

        case 7:
            orientation = UIImageOrientationRightMirrored;
            break;
        default:
            break;
    }
    return orientation;
}
#endif

- (nullable NSData *)sd_imageData {
    return [self sd_imageDataAsFormat:SDImageFormatUndefined];
}
/**
 根據指定的圖片類型,把image對象轉換爲對應格式的data
 
 @param imageFormat 指定的image格式
 @return 返回data對象
 */
- (nullable NSData *)sd_imageDataAsFormat:(SDImageFormat)imageFormat {
    NSData *imageData = nil;
    if (self) {
#if SD_UIKIT || SD_WATCH
        int alphaInfo = CGImageGetAlphaInfo(self.CGImage);
        //是否有透明度
        BOOL hasAlpha = !(alphaInfo == kCGImageAlphaNone ||
                          alphaInfo == kCGImageAlphaNoneSkipFirst ||
                          alphaInfo == kCGImageAlphaNoneSkipLast);
        //只有png圖片有alpha屬性
        BOOL usePNG = hasAlpha;
        
        // the imageFormat param has priority here. But if the format is undefined, we relly on the alpha channel
        //是不是PNG類型的圖片
        if (imageFormat != SDImageFormatUndefined) {
            usePNG = (imageFormat == SDImageFormatPNG);
        }
        //根據不一樣的圖片類型獲取到對應的圖片data
        if (usePNG) {
            imageData = UIImagePNGRepresentation(self);
        } else {
            imageData = UIImageJPEGRepresentation(self, (CGFloat)1.0);
        }
#else
        NSBitmapImageFileType imageFileType = NSJPEGFileType;
        if (imageFormat == SDImageFormatGIF) {
            imageFileType = NSGIFFileType;
        } else if (imageFormat == SDImageFormatPNG) {
            imageFileType = NSPNGFileType;
        }
        
        imageData = [NSBitmapImageRep representationOfImageRepsInArray:self.representations
                                                             usingType:imageFileType
                                                            properties:@{}];
#endif
    }
    return imageData;
}

5 UIImage+GIF分類分析

UIImage+GIF實現了對GIF圖片的NSData的處理。而且處理方法就是取出GIF圖片的第一張UIImage來顯示。若是真的要顯示動態圖片的話,咱們須要使用FLAnimatedImageView來顯示。app

/**
 根據gif圖片的data生成對應的gif的UIImage對象。並且只會取GIF圖片的第一張UIImage。

 @param data gif圖片的data對象
 @return 生成的image對象。這裏只獲取gif圖片的第一張圖像,若是要實現gif完整圖像,使用FLAnimatedImageView
 */
+ (UIImage *)sd_animatedGIFWithData:(NSData *)data {
    if (!data) {
        return nil;
    }
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
    //獲取GIF圖片包含的UIImage數量
    size_t count = CGImageSourceGetCount(source);
    UIImage *staticImage;
    //若是隻有一張UIImage
    if (count <= 1) {
        staticImage = [[UIImage alloc] initWithData:data];
    } else {
#if SD_WATCH
        CGFloat scale = 1;
        scale = [WKInterfaceDevice currentDevice].screenScale;
#elif SD_UIKIT
        CGFloat scale = 1;
        scale = [UIScreen mainScreen].scale;
#endif
        //獲取第一張UIImage對象
        CGImageRef CGImage = CGImageSourceCreateImageAtIndex(source, 0, NULL);
#if SD_UIKIT || SD_WATCH
        //獲取gif圖片的第一張圖片
        UIImage *frameImage = [UIImage imageWithCGImage:CGImage scale:scale orientation:UIImageOrientationUp];
        //用第一張圖片生成一個新的gif圖片
        staticImage = [UIImage animatedImageWithImages:@[frameImage] duration:0.0f];
#elif SD_MAC
        staticImage = [[UIImage alloc] initWithCGImage:CGImage size:NSZeroSize];
#endif
        CGImageRelease(CGImage);
    }

    CFRelease(source);

    return staticImage;
}
/**
 判斷一張圖片是否是GIF圖片

 @return bool值
 */
- (BOOL)isGIF {
    return (self.images != nil);
}

6 SDWebImageDecoder分析

經過這個類實現圖片的解壓縮操做。對於太大的圖片,先按照必定比例縮小圖片而後再解壓縮。工具

#if SD_UIKIT || SD_WATCH
//每一個像素佔用的字節數
static const size_t kBytesPerPixel = 4;
//色彩空間佔用的字節數
static const size_t kBitsPerComponent = 8;

/**
 解壓縮圖片

 @param image UIImage對象
 @return 返回解壓縮之後的圖片
 */
+ (nullable UIImage *)decodedImageWithImage:(nullable UIImage *)image {
    //圖片是否可以加壓縮
    if (![UIImage shouldDecodeImage:image]) {
        return image;
    }
    
    // autorelease the bitmap context and all vars to help system to free memory when there are memory warning.
    // on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory];
    /*
     *解壓縮操做放入一個自動釋放池裏面。一遍自動釋放全部的變量。
     */
    @autoreleasepool{
        
        CGImageRef imageRef = image.CGImage;
        //獲取圖片的色彩空間
        CGColorSpaceRef colorspaceRef = [UIImage colorSpaceForImageRef:imageRef];
        //寬度和高度
        size_t width = CGImageGetWidth(imageRef);
        size_t height = CGImageGetHeight(imageRef);
        //圖片佔用的字節數
        size_t bytesPerRow = kBytesPerPixel * width;

        // 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.
        //建立一個繪製圖片的上下文
        CGContextRef context = CGBitmapContextCreate(NULL,
                                                     width,
                                                     height,
                                                     kBitsPerComponent,
                                                     bytesPerRow,
                                                     colorspaceRef,
                                                     kCGBitmapByteOrderDefault|kCGImageAlphaNoneSkipLast);
        if (context == NULL) {
            return image;
        }
        
        // Draw the image into the context and retrieve the new bitmap image without alpha
        //繪製一個和圖片大小同樣的圖片
        CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
        //建立一個麼有alpha通道的圖片
        CGImageRef imageRefWithoutAlpha = CGBitmapContextCreateImage(context);
        //獲得解壓縮之後的圖片
        UIImage *imageWithoutAlpha = [UIImage imageWithCGImage:imageRefWithoutAlpha
                                                         scale:image.scale
                                                   orientation:image.imageOrientation];
        
        CGContextRelease(context);
        CGImageRelease(imageRefWithoutAlpha);
        
        return imageWithoutAlpha;
    }
}

/*
 *定義一張圖片能夠佔用的最大空間
 */
static const CGFloat kDestImageSizeMB = 60.0f;

static const CGFloat kSourceImageTileSizeMB = 20.0f;

static const CGFloat kBytesPerMB = 1024.0f * 1024.0f;
//1MB能夠存儲多少像素
static const CGFloat kPixelsPerMB = kBytesPerMB / kBytesPerPixel;
//若是像素小於這個值,則不解壓縮
static const CGFloat kDestTotalPixels = kDestImageSizeMB * kPixelsPerMB;
static const CGFloat kTileTotalPixels = kSourceImageTileSizeMB * kPixelsPerMB;

static const CGFloat kDestSeemOverlap = 2.0f;   // the numbers of pixels to overlap the seems where tiles meet.



/**
 若是原始圖片佔用的空間太大。則按照必定的比例解壓縮。從而不讓解壓縮之後的圖片佔用的空間太大。

 @param image UIImage對象
 @return 返回處理結束的UIImage對象
 */
+ (nullable UIImage *)decodedAndScaledDownImageWithImage:(nullable UIImage *)image {
    //圖片是否支持解壓縮
    if (![UIImage shouldDecodeImage:image]) {
        return image;
    }
    //圖片不須要處理。直接解壓縮
    if (![UIImage shouldScaleDownImage:image]) {
        return [UIImage decodedImageWithImage:image];
    }
    
    CGContextRef destContext;
    
    // autorelease the bitmap context and all vars to help system to free memory when there are memory warning.
    // on iOS7, do not forget to call [[SDImageCache sharedImageCache] clearMemory];
    @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);
        
        // current color space
        //獲取原始圖片的像素空間。默認是RGB
        CGColorSpaceRef colorspaceRef = [UIImage colorSpaceForImageRef:sourceImageRef];
        //每一行像素佔用的內存空間大小
        size_t bytesPerRow = kBytesPerPixel * destResolution.width;
        
        // Allocate enough pixel data to hold the output image.
        //目標圖片佔用的總內存空間大小。一行佔用內存空間大小*高度
        void* destBitmapData = malloc( bytesPerRow * destResolution.height );
        if (destBitmapData == NULL) {
            return image;
        }
        //根據各類設置建立一個上下文環境
        destContext = CGBitmapContextCreate(destBitmapData,
                                            destResolution.width,
                                            destResolution.height,
                                            kBitsPerComponent,
                                            bytesPerRow,
                                            colorspaceRef,
                                            kCGBitmapByteOrderDefault|kCGImageAlphaNoneSkipLast);
        
        if (destContext == NULL) {
            free(destBitmapData);
            return image;
        }
        //設置目標圖片的質量
        CGContextSetInterpolationQuality(destContext, kCGInterpolationHigh);
        CGRect sourceTile = CGRectZero;
        sourceTile.size.width = sourceResolution.width;
        sourceTile.size.height = (int)(kTileTotalPixels / sourceTile.size.width );
        sourceTile.origin.x = 0.0f;
        CGRect destTile;
        destTile.size.width = destResolution.width;
        destTile.size.height = sourceTile.size.height * imageScale;
        destTile.origin.x = 0.0f;
        float sourceSeemOverlap = (int)((kDestSeemOverlap/destResolution.height)*sourceResolution.height);
        CGImageRef sourceTileImageRef;
        int iterations = (int)( sourceResolution.height / sourceTile.size.height );
        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 imageWithCGImage:destImageRef scale:image.scale orientation:image.imageOrientation];
        CGImageRelease(destImageRef);
        if (destImage == nil) {
            return image;
        }
        return destImage;
    }
}

/**
 imge是否可以加壓縮

 @param image 圖片
 @return 可否解壓縮
 */
+ (BOOL)shouldDecodeImage:(nullable UIImage *)image {
    // Prevent "CGBitmapContextCreateImage: invalid context 0x0" error
    if (image == nil) {
        return NO;
    }

    // do not decode animated images
    //若是是動態圖片不處理
    if (image.images != nil) {
        return NO;
    }
    
    CGImageRef imageRef = image.CGImage;
    //獲取image的alpha通道。經過通道獲取圖片數據
    CGImageAlphaInfo alpha = CGImageGetAlphaInfo(imageRef);
    BOOL anyAlpha = (alpha == kCGImageAlphaFirst ||
                     alpha == kCGImageAlphaLast ||
                     alpha == kCGImageAlphaPremultipliedFirst ||
                     alpha == kCGImageAlphaPremultipliedLast);
    // do not decode images with alpha
    //若是有alpha通道值,則不處理
    if (anyAlpha) {
        return NO;
    }
    
    return YES;
}

/**
是否須要減小原始圖片的大小

 @param image UIImage對象
 @return 是否支持scale
 */
+ (BOOL)shouldScaleDownImage:(nonnull UIImage *)image {
    BOOL shouldScaleDown = YES;
        
    CGImageRef sourceImageRef = image.CGImage;
    CGSize sourceResolution = CGSizeZero;
    sourceResolution.width = CGImageGetWidth(sourceImageRef);
    sourceResolution.height = CGImageGetHeight(sourceImageRef);
    //圖片總共像素
    float sourceTotalPixels = sourceResolution.width * sourceResolution.height;
    //若是圖片的總像素大於必定比例,則須要作簡化處理
    float imageScale = kDestTotalPixels / sourceTotalPixels;
    if (imageScale < 1) {
        shouldScaleDown = YES;
    } else {
        shouldScaleDown = NO;
    }
    
    return shouldScaleDown;
}

/**
 獲取圖片的色彩空間

 @param imageRef 圖片
 @return 色彩空間
 */
+ (CGColorSpaceRef)colorSpaceForImageRef:(CGImageRef)imageRef {
    // current
    CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(CGImageGetColorSpace(imageRef));
    CGColorSpaceRef colorspaceRef = CGImageGetColorSpace(imageRef);
    
    BOOL unsupportedColorSpace = (imageColorSpaceModel == kCGColorSpaceModelUnknown ||
                                  imageColorSpaceModel == kCGColorSpaceModelMonochrome ||
                                  imageColorSpaceModel == kCGColorSpaceModelCMYK ||
                                  imageColorSpaceModel == kCGColorSpaceModelIndexed);
    if (unsupportedColorSpace) {
        colorspaceRef = CGColorSpaceCreateDeviceRGB();
        CFAutorelease(colorspaceRef);
    }
    return colorspaceRef;
}
#elif SD_MAC
+ (nullable UIImage *)decodedImageWithImage:(nullable UIImage *)image {
    return image;
}

+ (nullable UIImage *)decodedAndScaledDownImageWithImage:(nullable UIImage *)image {
    return image;
}

7 總結

下面是幾個分類工具的使用。ui

/**
 根據圖片數據獲取圖片類型

 */
- (IBAction)getImageType:(id)sender {
    NSData *imageData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"rock.gif" ofType:nil]];
    SDImageFormat formate = [NSData sd_imageFormatForImageData:imageData];
    NSString *message = [NSString stringWithFormat:@"%d",formate];
    showMessage(message,self);
}


/**
 獲取一張圖片對應的兩倍或者三倍屏幕對應的圖片

 */
- (IBAction)getScaleImage:(id)sender {
    UIImage *sourceImage = [UIImage imageNamed:@"2.png"];
    UIImage *dis2ScaleImage = SDScaledImageForKey(@"dist@2x.png", sourceImage);
    UIImage *dis3ScaleImage = SDScaledImageForKey(@"dist@3x.png", sourceImage);
    NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    //NSLog(@"document:%@",documentPath);
    NSString *path1 = [documentPath stringByAppendingPathComponent:@"dist.png"];
    [UIImagePNGRepresentation(sourceImage) writeToFile:path1 atomically:YES];
    NSString *path2 = [documentPath stringByAppendingPathComponent:@"dist@2x.png"];
    [UIImagePNGRepresentation(dis2ScaleImage) writeToFile:path2 atomically:YES];
    NSString *path3 = [documentPath stringByAppendingPathComponent:@"dist@3x.png"];
    [UIImagePNGRepresentation(dis3ScaleImage) writeToFile:path3 atomically:YES];
}

/**
 解壓縮圖片

 @param sender 解壓縮圖片
 */
- (IBAction)unZipImage:(id)sender {
    UIImage *sourceImage = [UIImage imageNamed:@"2.png"];
    UIImage *distImage = [UIImage decodedAndScaledDownImageWithImage:sourceImage];
    NSString *documentPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
    NSString *path1 = [documentPath stringByAppendingPathComponent:@"distImage.png"];
    [UIImagePNGRepresentation(distImage) writeToFile:path1 atomically:YES];
    NSString *path2 = [documentPath stringByAppendingPathComponent:@"sourceImage.png"];
    [UIImagePNGRepresentation(sourceImage) writeToFile:path2 atomically:YES];
    
}

最後原文地址.html),demo地址atom

相關文章
相關標籤/搜索