iOS图片处理(拉伸、压缩、裁剪、旋转、读取、解压缩为位图)


一、图片拉伸

1、UIImageView整体拉伸

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

 2、UIImage局部拉伸

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

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

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

拉伸或复制下图中的黑色区域。

3、Images.xcassets的slicing功能

1、在imagex.xcassets选中需要处理的图片,点击面板右下角的Show Slicing,进入如下页面:

2、点击图片中的Start Slicing,进入页面:

3、选择左边的左右拉伸,中间左右上下都拉伸,右边的上下拉伸,进入编辑页面。拉动线条,被蒙板盖住的区域会被拉伸。

4、最后进入图片对应的attribtues pane面板,修改Slicing的Center为Stretches。

实现效果同UIImage的局部拉伸,但设置操作可观方便。

 

二、图片压缩

UIImageJPEGRepresentation()、UIImagePNGRepresentation()

两种方法都用UIImage,返回NSData数据。

UIImagePNGRepresentation(image)的数据 > UIImageJPEGRepresentation(image, 1.0) > UIImageJPEGRepresentation(image, 0.1);

 

三、图片大小裁剪

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

 

四、图片方向处理

用相机拍摄出来的照片含有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; }

 

五、图片读取

+ (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];
}

1、imageWithContentsOfFile:从指定路径加载图片,不会进行缓存。

2、imageNamed:方法会将图片加载到缓存,正在屏幕中显示的图片不会被内存回收。

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

 
六、图片解压缩详解<图片从二进制数据转换为像素数据的过程>
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、像素格式

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优化。

2、颜色空间

采用CGColorSpace.h中的方法,一般通过CGColorSpaceCreateDeviceRGB()使用 RGB 即可

3、布局信息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 */
};

4、解压缩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 { ... } }

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM