iOS圖片處理(拉伸、壓縮、裁剪、旋轉、讀取、解壓縮爲位圖)

1、圖片拉伸緩存

一、UIImageView總體拉伸app

typedef enum UIViewContentMode : NSInteger {
    UIViewContentModeScaleToFill,
    UIViewContentModeScaleAspectFit,
    UIViewContentModeScaleAspectFill,
    UIViewContentModeRedraw,
    UIViewContentModeCenter,
    UIViewContentModeTop,
    UIViewContentModeBottom,
    UIViewContentModeLeft,
    UIViewContentModeRight,
    UIViewContentModeTopLeft,
    UIViewContentModeTopRight,
    UIViewContentModeBottomLeft,
    UIViewContentModeBottomRight
} UIViewContentMode;

 2、UIImage局部拉伸ide

// UIEdgeInsetsMake(5, 5, 5, 5) 
- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets 

- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets resizingMode:(UIImageResizingMode)resizingMode;

typedef NS_ENUM(NSInteger, UIImageResizingMode) {
    UIImageResizingModeTile,
    UIImageResizingModeStretch,
};

拉伸或複製下圖中的黑色區域。佈局

三、Images.xcassets的slicing功能優化

一、在imagex.xcassets選中須要處理的圖片,點擊面板右下角的Show Slicing,進入以下頁面:ui

二、點擊圖片中的Start Slicing,進入頁面:this

三、選擇左邊的左右拉伸,中間左右上下都拉伸,右邊的上下拉伸,進入編輯頁面。拉動線條,被蒙板蓋住的區域會被拉伸。url

四、最後進入圖片對應的attribtues pane面板,修改Slicing的Center爲Stretches。spa

實現效果同UIImage的局部拉伸,但設置操做可觀方便。code

 

2、圖片壓縮

UIImageJPEGRepresentation()、UIImagePNGRepresentation()

兩種方法都用UIImage,返回NSData數據。

UIImagePNGRepresentation(image)的數據 > UIImageJPEGRepresentation(image, 1.0) > UIImageJPEGRepresentation(image, 0.1);

 

3、圖片大小裁剪

- (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);
}

 

4、圖片方向處理

用相機拍攝出來的照片含有EXIF信息,UIImage的imageOrientation屬性指的就是EXIF中的orientation信息。

typedef enum UIImageOrientation : NSInteger {
    UIImageOrientationUp,
    UIImageOrientationDown,
    UIImageOrientationLeft,
    UIImageOrientationRight,
    UIImageOrientationUpMirrored,
    UIImageOrientationDownMirrored,
    UIImageOrientationLeftMirrored,
    UIImageOrientationRightMirrored
} UIImageOrientation;

若是咱們忽略orientation信息,而直接對照片進行像素處理或者drawInRect等操做,獲得的結果是翻轉或者旋轉90以後的樣子。這是由於咱們執行像素處理或者drawInRect等操做以後,imageOrientaion信息被刪除了,imageOrientaion被重設爲0,形成照片內容和imageOrientaion不匹配。因此,在對照片進行處理以前,先將照片旋轉到正確的方向,而且返回的imageOrientaion爲0。

方法一:

-drawInRect:
Draws the entire image in the specified rectangle, scaling it as needed to fit.
Discussion
This method draws the entire image in the current graphics context, respecting the image’s orientation setting. In the default coordinate system, images are situated down and to the right of the origin of the specified rectangle. This method respects any transforms applied to the current graphics context, however.

 - (UIImage *)normalizedImage {
     if (self.imageOrientation == UIImageOrientationUp) return self; 
  
     UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
     [self drawInRect:(CGRect){0, 0, self.size}];
     UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
     UIGraphicsEndImageContext();
     return normalizedImage;
 }

方法二:

爲UIImage category中的方法

- (UIImage *)fixOrientation:(UIImage *)aImage {  
      
    if (aImage.imageOrientation == UIImageOrientationUp)   
        return aImage;  
      
    // We need to calculate the proper transformation to make the image upright.  
    // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.  
    CGAffineTransform transform = CGAffineTransformIdentity;  
      
    switch (aImage.imageOrientation) {  
        case UIImageOrientationDown:  
        case UIImageOrientationDownMirrored:  
            transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height);  
            transform = CGAffineTransformRotate(transform, M_PI);  
            break;  
              
        case UIImageOrientationLeft:  
        case UIImageOrientationLeftMirrored:  
            transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);  
            transform = CGAffineTransformRotate(transform, M_PI_2);  
            break;  
              
        case UIImageOrientationRight:  
        case UIImageOrientationRightMirrored:  
            transform = CGAffineTransformTranslate(transform, 0, aImage.size.height);  
            transform = CGAffineTransformRotate(transform, -M_PI_2);  
            break;  
        default:  
            break;  
    }  
switch (aImage.imageOrientation) { case UIImageOrientationUpMirrored: case UIImageOrientationDownMirrored: transform = CGAffineTransformTranslate(transform, aImage.size.width, 0); transform = CGAffineTransformScale(transform, -1, 1); break; case UIImageOrientationLeftMirrored: case UIImageOrientationRightMirrored: transform = CGAffineTransformTranslate(transform, aImage.size.height, 0); transform = CGAffineTransformScale(transform, -1, 1); break; default: break; } // Now we draw the underlying CGImage into a new context, applying the transform // calculated above. CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height, CGImageGetBitsPerComponent(aImage.CGImage), 0, CGImageGetColorSpace(aImage.CGImage), CGImageGetBitmapInfo(aImage.CGImage)); CGContextConcatCTM(ctx, transform); switch (aImage.imageOrientation) { case UIImageOrientationLeft: case UIImageOrientationLeftMirrored: case UIImageOrientationRight: case UIImageOrientationRightMirrored: // Grr... CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage); break; default: CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage); break; } // And now we just create a new UIImage from the drawing context CGImageRef cgimg = CGBitmapContextCreateImage(ctx); UIImage *img = [UIImage imageWithCGImage:cgimg]; CGContextRelease(ctx); CGImageRelease(cgimg); return img; }

 

5、圖片讀取

+ (UIImage *) imageNamed:(NSString *)name inBundleName:(NSString *)bundleName {
    NSBundle *bundle = [NSBundle  mainBundle];
    NSURL *url = [bundle URLForResource:bundleName withExtension:@"bundle"];
    
    if (!url) {
        return nil;
    }
    NSBundle *imageBundle = [NSBundle bundleWithURL:url];
    
    NSString *path = [imageBundle pathForResource:name ofType:@"png"];
    if (kIsEmptyString(path)) {
       return  [UIImage imageNamed:name];
    }
    return [UIImage imageWithContentsOfFile:path];
}

+ (UIImage *)imageFromSDK:(NSString *)imageName {
    NSBundle *bundle = [NSBundle mainBundle];
    NSArray<NSURL *> *bundleArr = [bundle URLsForResourcesWithExtension:@"bundle" subdirectory:nil];
    __block NSString *path;
    [bundleArr enumerateObjectsUsingBlock:^(NSURL * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {

        NSBundle *imageBundle = [NSBundle bundleWithURL:obj];
        path = [imageBundle pathForResource:imageName ofType:@"png"];
        if (!kIsEmptyString(path)) {
            *stop = YES;
        }

    }];
    if (kIsEmptyString(path)) {
        return  [UIImage imageNamed:imageName];

    }
    return [UIImage imageWithContentsOfFile:path];
}

一、imageWithContentsOfFile:從指定路徑加載圖片,不會進行緩存。

二、imageNamed:方法會將圖片加載到緩存,正在屏幕中顯示的圖片不會被內存回收。

UIImage *image = [UIImage imageNamed:@"check_green"];
CFDataRef rawData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage)

 
6、圖片解壓縮詳解<圖片從二進制數據轉換爲像素數據的過程>
CGBitmapContextCreate(void * __nullable data,
                                size_t width, 
                               size_t height, 
             size_t bitsPerComponent, // 每一個顏色佔用的bit數
                size_t bytesPerRow, // 位圖中每行的字節數
           CGColorSpaceRef cg_nullable space, // 顏色空間
               uint32_t bitmapInfo) // 佈局信息(alpha信息、顏色份量是否爲浮點數、像素格式的字節順序)  

一、像素格式

1)Bits per component。在 32 位像素格式下,每一個顏色份量使用 8 位;而在 16 位像素格式下,每一個顏色份量則使用 5 位。

2)Bits per pixel。一個像素使用的總bit數,有32位和16位兩種。

3)Bytes per row。大小至少爲 < width(一行像素數) * bytes per pixel >字節。或者直接指定爲 0 ,系統不只會自動計算,並且還會進行 cache line alignment 1優化。

二、顏色空間

採用CGColorSpace.h中的方法,通常經過CGColorSpaceCreateDeviceRGB()使用 RGB 便可

三、佈局信息BitmapInfo

typedef CF_OPTIONS(uint32_t, CGBitmapInfo) {
    kCGBitmapAlphaInfoMask = 0x1F,
 
    kCGBitmapFloatInfoMask = 0xF00,
    kCGBitmapFloatComponents = (1 << 8),
 
    kCGBitmapByteOrderMask     = kCGImageByteOrderMask,
    kCGBitmapByteOrderDefault  = (0 << 12),
    kCGBitmapByteOrder16Little = kCGImageByteOrder16Little,
    kCGBitmapByteOrder32Little = kCGImageByteOrder32Little,
    kCGBitmapByteOrder16Big    = kCGImageByteOrder16Big,
    kCGBitmapByteOrder32Big    = kCGImageByteOrder32Big
} CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);

typedef CF_ENUM(uint32_t, CGImageAlphaInfo) {
    kCGImageAlphaNone,               /* For example, RGB. */
    kCGImageAlphaPremultipliedLast,  /* For example, premultiplied RGBA */
    kCGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */
    kCGImageAlphaLast,               /* For example, non-premultiplied RGBA */
    kCGImageAlphaFirst,              /* For example, non-premultiplied ARGB */
    kCGImageAlphaNoneSkipLast,       /* For example, RBGX. */
    kCGImageAlphaNoneSkipFirst,      /* For example, XRGB. */
    kCGImageAlphaOnly                /* No color data, alpha data only */
};

四、解壓縮YYKit中代碼示例

CGImageRef YYCGImageCreateDecodedCopy(CGImageRef imageRef, BOOL decodeForDisplay) {
    ...
 
    if (decodeForDisplay) { // decode with redraw (may lose some precision)
        CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef) & kCGBitmapAlphaInfoMask;
 
        BOOL hasAlpha = NO;
        if (alphaInfo == kCGImageAlphaPremultipliedLast ||
            alphaInfo == kCGImageAlphaPremultipliedFirst ||
            alphaInfo == kCGImageAlphaLast ||
            alphaInfo == kCGImageAlphaFirst) {
            hasAlpha = YES;
        }
       // You use this function to configure the drawing environment for rendering into a bitmap. The format for the bitmap is a ARGB          32-bit integer pixel format using host-byte order. If the opaque parameter is YES, the alpha channel is ignored and the              bitmap is treated as fully opaque (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host). Otherwise, each pixel uses a 
premultipled ARGB format (kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host).
CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host; bitmapInfo |= hasAlpha ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst; CGContextRef context = CGBitmapContextCreate(NULL, width, height, 8, 0, YYCGColorSpaceGetDeviceRGB(), bitmapInfo); if (!context) return NULL; CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); // decode CGImageRef newImage = CGBitmapContextCreateImage(context); CFRelease(context); return newImage; } else { ... } }
相關文章
相關標籤/搜索