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 { ... } }
相关文章
相关标签/搜索