【IOS开发基础系列】UIImage/UIImageView专题

1 UIImage知识点

iOS开发中关于UIImage的知识点总结

http://mobile.51cto.com/hot-442118.htm

        UIImage是iOS中层级比较高的一个用来加载和绘制图像的一个类,更底层的类还有 CGImage,以及iOS5.0以后新增加的CIImage。今天我们主要聊一聊UIImage的三个属性: imageOrientation, size, scale,几个初始化的方法: imageNamed,imageWithContentsOfFile,以及绘制Image的几个draw开头的方法。

        UIImage是iOS中层级比较高的一个用来加载和绘制图像的一个类,更底层的类还有 CGImage,以及iOS5.0以后新增加的CIImage。今天我们主要聊一聊UIImage的三个属性: imageOrientation, size, scale,几个初始化的方法: imageNamed,imageWithContentsOfFile,以及绘制Image的几个draw开头的方法。

1.1 UIImage的size,scale属性

        先想一个问题“一个图像的尺寸到底是多大呢?”

        第一反应可能就是image.size,恭喜你答错了,正确的答案是图像的实际的尺寸(像 素)等于image.size乘以image.scale。如果做过界面贴图的话你可能经常会需要准备至少两套图,一套1倍图,一套图已@2x命名的二倍 图。这样当我们的程序运行在retina屏幕的时候系统就会自动的去加载@2x的图片,它的size将和一倍图加载进来的size相等,但是scale却 置为2,这点大家可以做个简单的小测试验证一下。然我们再深入一点儿为什么不直接加载到成二倍的尺寸呢,原因很简单因为我们在界面布局中逻辑坐标系中的 (单位是point),而实际的绘制都是在设备坐标系(单位是pixel)进行的,系统会自动帮我们完成从point到pixel之间的转化。其实这个比 例也就刚好和UIScreen中的scale对应,这样整条scale的线就可以串通了。

1.2 UIImage的几种初始化方法的对比

1imageNamed:方法

        imageNamed:是UIImage的一个类方法,它做的事情比我们看到的要稍微多一些。它的加载流程如下:

    a. 系统回去检查系统缓存中是否存在该名字的图像,如果存在则直接返回。

    b. 如果系统缓存中不存在该名字的图像,则会先加载到缓存中,在返回该对象。

        观察上面的操作我们发现系统会缓存我们使用imageNamed:方法加载的图像时候,系统会自动帮我们缓存。这种机制适合于那种频繁用到界面贴图累的加载,但如果我们需要短时间内频繁的加载一些一次性的图像的话,最好不要使用这种方法。

2imageWithContentsOfFile:initWithContentsOfFile:方法

        这两个方法跟前一个方法一样都是完成从文件加载图像的功能。但是不会经过系统缓存,直接从文件系统中加载并返回。

        顺便提一下,当收到内存警告的时候,系统可能会将UIImage内部的存储图像的内存释放,下一次需要绘制的时候会重新去加载。

3imageWithCGImage:scale:orientation:方法

        该方面使用一个CGImageRef创建UIImage,在创建时还可以指定方法倍数以及旋转方向。当scale设置为1的时候,新创建的图像将和原图像尺寸一摸一样,而orientaion则可以指定新的图像的绘制方向。

1.3 UIImage的imageOrientation属性

        UIImage有一个imageOrientation的属性,主要作用是控制image的绘制方向,共有以下8中方向:

typedef NS_ENUM(NSInteger, UIImageOrientation) {

    UIImageOrientationUp,            // default orientation  

    UIImageOrientationDown,          // 180 deg rotation       

    UIImageOrientationLeft,          // 90 deg CCW(编程发现官方文档中,left和right图像标反了,此处更正过来)

    UIImageOrientationRight,         // 90 deg CW   

    UIImageOrientationUpMirrored,    // as above but image mirrored along other axis. horizontal flip  

    UIImageOrientationDownMirrored,  // horizontal flip

    UIImageOrientationLeftMirrored,  // vertical flip

    UIImageOrientationRightMirrored, // vertical flip

};

        默认的方向是UIImageOrientationUp,这8种方向对应的绘制方如上面所示。我 们在日常使用中经常会碰到把iPhone相册中的照片导入到windows中,发现方向不对的问题就是与这个属性有关,因为导出照片的时候,写exif中 的方向信息时候没有考虑该方向的原因。既然这个属性可以控制image的绘制方向,那我们能不能通过改过这个属性来完成UIImage的旋转和翻转呢?带 着这个问题我们继续往下看。

1.4 UIImage的几个draw方法

        UIImage的几个draw方法是用来绘制图像的利器,为什么这样说呢?因为它们在绘制图 像的时候会考虑当前图像的方向,即根据的imageOrientation绘制出不同的方向。由于图像是绘制在当前context中的,它同时还会考虑到 当前context的transform的变化。利于这两点我们就可以玩转图像的旋转和翻转了。

        搜索了一下,目前网上大部分图像旋转都是通过创建CGBitmapContext,然后根据图像方向设置context的transform来实现的,这种方法要求对整个矩阵变化的过程都非常清楚,一个参数设置不多,出来的结果就会有问题。

        下面我介绍一种实现起来简单方便的图像旋转方法,这种方法主要就是利用imageWithCGImage:scale:orientation:方法,指定不同的orientation来完成所需要的功能,先举个简单的例子:

        假设一副图片显示为 ,我们要向左旋转90°,那么转过之后应该就会显示为,即将原图从orientationUP转到orientationLeft即可。以此类推为不同的方向旋转,只需要注意看R的显示即可,这样整个旋转和翻转的实现过程中完全可以不用考虑Transform那些东西,是不是很简单。

        下面是图像旋转和翻转的完整代码:

//

//  UIImage+Rotate_Flip.h

//  SvImageEdit

//

#import <UIKit/UIKit.h>

@interface UIImage (Rotate_Flip)

/*

* @brief rotate image 90 withClockWise

*/

- (UIImage*)rotate90Clockwise;

/*

* @brief rotate image 90 counterClockwise

*/

- (UIImage*)rotate90CounterClockwise;

/*

* @brief rotate image 180 degree

*/

- (UIImage*)rotate180;

/*

* @brief rotate image to default orientation

*/

- (UIImage*)rotateImageToOrientationUp;

/*

* @brief flip horizontal

*/

- (UIImage*)flipHorizontal;

/*

* @brief flip vertical

*/

- (UIImage*)flipVertical;

/*

* @brief flip horizontal and vertical

*/

- (UIImage*)flipAll;

@end

UIImage+Rotate_Flip.h

//

//  UIImage+Rotate_Flip.m

//  SvImageEdit

//

//  Created by  maple on 5/14/13.

//  Copyright (c) 2013 smileEvday. All rights reserved.

//

#import "UIImage+Rotate_Flip.h"

@implementation UIImage (Rotate_Flip)

/*

* @brief rotate image 90 with CounterClockWise

*/

- (UIImage*)rotate90CounterClockwise

{

    UIImage *image = nil;

    switch (self.imageOrientation) {

        case UIImageOrientationUp:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationLeft];

            break;

        }

        case UIImageOrientationDown:

        {    

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationRight];

            break;

        }

        case UIImageOrientationLeft:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationDown];

            break;

        }

        case UIImageOrientationRight: 

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationUp];

            break;

        }

        case UIImageOrientationUpMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationRightMirrored];

            break;

        }

        case UIImageOrientationDownMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationLeftMirrored];

            break;

        }

        case UIImageOrientationLeftMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationUpMirrored];

            break;

        }

        case UIImageOrientationRightMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationDownMirrored];

            break;

        }

        default:

            break;

    }

    return image;

}

/*

* @brief rotate image 90 with Clockwise

*/

- (UIImage*)rotate90Clockwise

{

    UIImage *image = nil;

    switch (self.imageOrientation) {

        case UIImageOrientationUp:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationRight];

            break;

        }

        case UIImageOrientationDown:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationLeft];

            break;

        }

        case UIImageOrientationLeft:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationUp];

            break;

        }

        case UIImageOrientationRight:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationDown];

            break;

        }

        case UIImageOrientationUpMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationLeftMirrored];

            break;

        }

        case UIImageOrientationDownMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationRightMirrored];

            break;

        }

        case UIImageOrientationLeftMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationDownMirrored];

            break;

        }

        case UIImageOrientationRightMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationUpMirrored];

            break;

        }

        default:

            break;

    }

    return image;

}

/*

* @brief rotate image 180 degree

*/

- (UIImage*)rotate180

{

    UIImage *image = nil;

    switch (self.imageOrientation) {

        case UIImageOrientationUp:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationDown];

            break;

        }

        case UIImageOrientationDown:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationUp];

            break;

        }

        case UIImageOrientationLeft:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationRight];

            break;

        }

        case UIImageOrientationRight:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationLeft];

            break;

        }

        case UIImageOrientationUpMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationDownMirrored];

            break;

        }

        case UIImageOrientationDownMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationUpMirrored];

            break;

        }

        case UIImageOrientationLeftMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationRightMirrored];

            break;

        }

        case UIImageOrientationRightMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationLeftMirrored];

            break;

        }

        default:

            break;

    }

    return image;

}

/*

* @brief rotate image to default orientation

*/

- (UIImage*)rotateImageToOrientationUp

{

    CGSize size = CGSizeMake(self.size.width * self.scale, self.size.height * self.scale);

    UIGraphicsBeginImageContext(size);

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextClearRect(context, CGRectMake(0, 0, size.width, size.height));

    [self drawInRect: CGRectMake(0, 0, size.width, size.height)];

    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return image;

}

/*

* @brief flip horizontal

*/

- (UIImage*)flipHorizontal

{

    UIImage *image = nil;

    switch (self.imageOrientation) {

        case UIImageOrientationUp:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationUpMirrored];

            break;

        }

        case UIImageOrientationDown:

        {    

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationDownMirrored];

            break;

        }

        case UIImageOrientationLeft:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationRightMirrored];

            break;

        }

        case UIImageOrientationRight:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationLeftMirrored];

            break;

        }

        case UIImageOrientationUpMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationUp];

            break;

        }

        case UIImageOrientationDownMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationDown];

            break;

        }

        case UIImageOrientationLeftMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationRight];

            break;

        }

        case UIImageOrientationRightMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationLeft];

            break;

        }

        default:

            break;

    }

    return image;

}

/*

* @brief flip vertical

*/

- (UIImage*)flipVertical

{

    UIImage *image = nil;

    switch(self.imageOrientation) {

        case UIImageOrientationUp:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationDownMirrored];

            break;

        }

        case UIImageOrientationDown:

        {    

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationUpMirrored];

            break;

        }

        case UIImageOrientationLeft:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationLeftMirrored];

            break;

        }

        case UIImageOrientationRight:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationRightMirrored];

            break;

        }

        case UIImageOrientationUpMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationDown];

            break;

        }

        case UIImageOrientationDownMirrored:

        { 

            image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationUp];

            break;

        }

        case UIImageOrientationLeftMirrored:

        {

            image = [UIImage imageWithCGImage: self.CGImage scale:1  orientation: UIImageOrientationLeft];

            break;

        }

        case UIImageOrientationRightMirrored:

        {

           image = [UIImage imageWithCGImage: self.CGImage scale: 1 orientation: UIImageOrientationRight];

            break;

        }

        default:

            break;

    }

    return image;

}

/*

* @brief flip horizontal and vertical

*/

- (UIImage*)flipAll

{

    return [self rotate180];

}

@end

UIImage+Rotate_Flip.m

        以上只是实现了图像的顺时针90°,逆时针90°,180°旋转,以及水平翻转,数值翻转等。至于任意角度旋转怎么实现?其实也很简单,留着给大家思考吧。虽然我们可以通过orientation这种方法简单的完成图像旋转,但是如果有时间的话还是 建议大家尽量的看一下那种通过transform来完成旋转的代码,你会彻底搞清楚旋转矩阵是怎么回事儿。当然程序中使用的时候推荐使用我上面提供的这种 方法,因为不涉及真实的旋转操作,速度会快很多。

        通过上面的小例子,我们可以看出越高级别的API帮助我们做的事情就越多,越底层的API提 供了更多的灵活性,但同时也带来了很多需要我们处理的东西。再编程的过程中尽量的使用高级别的API,同时最好能搞懂底层的实现机制。这样我们的程序才会 更高效,出了问题才知道去哪里查找。


1.5 图片处理小技巧

摘抄链接:iOS处理图片的一些小Tip

http://blog.ibireme.com/2015/11/02/ios_image_tips/

1.5.1 如何把GIF动图保存到相册?

        iOS的相册是支持保存GIF和APNG动图的,只是不能直接播放。用[ALAssetsLibrary writeImageDataToSavedPhotosAlbum: metadata: completionBlock]可以直接把APNG、GIF的数据写入相册。如果图省事直接用UIImageWriteToSavedPhotosAlbum()写相册,那么图像会被强制转码为PNG。

1.5.2 将UIImage保存到磁盘,用什么方式最好?

        目前来说,保存UIImage有三种方式:

    1.直接用NSKeyedArchiver把UIImage序列化保存;

    2.用UIImagePNGRepresentation()先把图片转为PNG保存;

    3.用UIImageJPEGRepresentation()把图片压缩成JPEG保存。

        实际上,NSKeyedArchiver是调用了UIImagePNGRepresentation进行序列化的,用它来保存图片是消耗最大的。苹果对JPEG有硬编码和硬解码,保存成JPEG会大大缩减编码解码时间,也能减小文件体积。所以如果图片不包含透明像素时,UIImageJPEGRepresentation(0.9)是最佳的图片保存方式,其次是UIImagePNGRepresentation()。

1.5.3 UIImage缓存是怎么回事?

        通过imageNamed创建UIImage时,系统实际上只是在Bundle内查找到文件名,然后把这个文件名放到UIImage里返回,并没有进行实际的文件读取和解码。当UIImage第一次显示到屏幕上时,其内部的解码方法才会被调用,同时解码结果会保存到一个全局缓存去。据我观察,在图片解码后,App第一次退到后台和收到内存警告时,该图片的缓存才会被清空,其他情况下缓存会一直存在。

1.5.4 我要是用imageWithData能不能避免缓存呢?

        不能。通过数据创建UIImage时,UIImage底层是调用ImageIO的CGImageSourceCreateWithData()方法。该方法有个参数叫ShouldCache,在64位的设备上,这个参数是默认开启的。这个图片也是同样在第一次显示到屏幕时才会被解码,随后解码数据被缓存到CGImage内部。与imageNamed创建的图片不同,如果这个图片被释放掉,其内部的解码数据也会被立刻释放。

1.5.5 怎么能避免缓存呢?

    1.手动调用CGImageSourceCreateWithData()来创建图片,并把ShouldCache和ShouldCacheImmediately关掉。这么做会导致每次图片显示到屏幕时,解码方法都会被调用,造成很大的CPU占用。

    2.把图片用CGContextDrawImage()绘制到画布上,然后把画布的数据取出来当作图片。这也是常见的网络图片库的做法。

1.5.6 我能直接取到图片解码后的数据,而不是通过画布取到吗?

    1.CGImageSourceCreateWithData(data)创建ImageSource。

    2.CGImageSourceCreateImageAtIndex(source)创建一个未解码的CGImage。

    3.CGImageGetDataProvider(image)获取这个图片的数据源。

    4.CGDataProviderCopyData(provider)从数据源获取直接解码的数据。

        ImageIO解码发生在最后一步,这样获得的数据是没有经过颜色类型转换的原生数据(比如灰度图像)。

1.5.7 如何判断一个文件的图片类型?

        通过读取文件或数据的头几个字节然后和对应图片格式标准进行比对。我在这里写了一个简单的函数,能很快速的判断图片格式。

1.5.8 怎样像浏览器那样边下载边显示图片?

        首先,图片本身有3种常见的编码方式:

    第一种是baseline,即逐行扫描。默认情况下,JPEG、PNG、GIF都是这种保存方式。

    第二种是interlaced,即隔行扫描。PNG和GIF在保存时可以选择这种格式。

    第三种是progressive,即渐进式。JPEG在保存时可以选择这种方式。

        在下载图片时,首先用CGImageSourceCreateIncremental(NULL)创建一个空的图片源,随后在获得新数据时调用CGImageSourceUpdateData(data, false)来更新图片源,最后在用CGImageSourceCreateImageAtIndex()创建图片来显示。

        你可以用PINRemoteImage或者我写的 YYWebImage来实现这个效果。SDWebImage并没有用Incremental方式解码,所以显示效果很差。


2 开发技巧

2.1 图片缩放

图片缩放的三个函数

http://www.cnblogs.com/pengyingh/articles/2355052.html

        程序中一个界面用到了好多张大图,内存报警告了,所以做了一下图片缩放,在网上找了别人写的代码

//把图片做等比缩放,生成一个新图片

- (UIImage*) imageByScalingProportionallyToSize:(CGSize)targetSize sourceImage:(UIImage*)sourceImage {

    UIGraphicsBeginImageContext(targetSize);

    [sourceImage drawInRect: CGRectMake(0, 0, targetSize.width, targetSize.height)];

    UIImage* scaledImage =UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return scaledImage;


    UIImage *newImage = nil;

    CGSize imageSize = sourceImage.size;

    CGFloat width = imageSize.width;

    CGFloat height = imageSize.height;

    CGFloat targetWidth = targetSize.width;

    CGFloat targetHeight = targetSize.height;

    CGFloat scaleFactor =0.0;

    CGFloat scaledWidth = targetWidth;

    CGFloat scaledHeight = targetHeight;

    CGPoint thumbnailPoint = CGPointMake(0.0,0.0);


    UIGraphicsBeginImageContext(targetSize);// this will crop

    CGRect thumbnailRect = CGRectZero;

    thumbnailRect.origin = thumbnailPoint;

    thumbnailRect.size.width  = scaledWidth;

    thumbnailRect.size.height = scaledHeight;

    [sourceImage drawInRect: thumbnailRect];


    newImage = UIGraphicsGetImageFromCurrentImageContext();

    if(newImage== nil)

        NSLog(@"could not scale image");


    //pop the context to get back to the default

    UIGraphicsEndImageContext();

    return newImage;

}

//把图片按照新大小进行裁剪,生成一个新图片

- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize image:(UIImage  *) sourceImage

{

     //   UIImage *sourceImage = self;

     UIImage *newImage = nil;

     CGSize imageSize = sourceImage.size;

     CGFloat width = imageSize.width;

     CGFloat height = imageSize.height;

     CGFloat targetWidth = targetSize.width;

     CGFloat targetHeight = targetSize.height;

     CGFloat scaleFactor =0.0;

     CGFloat scaledWidth = targetWidth;

     CGFloat scaledHeight = targetHeight;

     CGPoint thumbnailPoint = CGPointMake(0.0,0.0);


     if (CGSizeEqualToSize(imageSize, targetSize) == NO)

     {

         CGFloat widthFactor = targetWidth / width;

         CGFloat heightFactor = targetHeight / height;


         if (widthFactor > heightFactor)

             scaleFactor = widthFactor;    // scale to fit height

         else

             scaleFactor = heightFactor;    // scale to fit width

         scaledWidth  = width * scaleFactor;

         scaledHeight = height * scaleFactor;


         // center the image

         if(widthFactor > heightFactor)

         {

             thumbnailPoint.y = (targetHeight -scaledHeight) *0.5;

         }

         else

             if(widthFactor < heightFactor)

             {

                 thumbnailPoint.x =(targetWidth - scaledWidth) *0.5;

             }

     }      


     UIGraphicsBeginImageContext(targetSize);    // this will crop


     CGRect thumbnailRect = CGRectZero;

     thumbnailRect.origin = thumbnailPoint;

     thumbnailRect.size.width  = scaledWidth;

     thumbnailRect.size.height = scaledHeight;


     [sourceImage drawInRect: thumbnailRect];


     newImage = UIGraphicsGetImageFromCurrentImageContext();

     if(newImage== nil)

         NSLog(@"could not scale image");


     //pop the context to get back to the default

     UIGraphicsEndImageContext();

     return newImage;

}


- (UIImage*)generatePhotoThumbnail:(UIImage *)image

{

     // Create a thumbnail version of the image for the event object.

     CGSize size = image.size;

     CGSize croppedSize;

     CGFloat ratio =64.0;//这个是设置转换后图片的尺寸大小

     CGFloat offsetX =0.0;

     CGFloat offsetY =0.0;


     // check the size of the image, we want to make it

     // a square with sides the size of the smallest dimension

     if(size.width > size.height) {

         offsetX = (size.height - size.width) /2;

         croppedSize = CGSizeMake(size.height, size.height);

     }

    else{

         offsetY = (size.width - size.height) /2;

         croppedSize = CGSizeMake(size.width, size.width);

     }


     // Crop the image before resize

     CGRect clippedRect = CGRectMake(offsetX *-1, offsetY * -1, croppedSize.width, croppedSize.height);

    //裁剪图片

    CGImageRef imageRef =CGImageCreateWithImageInRect([image CGImage], clippedRect);

    // Resize the image

     CGRect rect = CGRectMake(0.0,0.0,ratio, ratio);


     UIGraphicsBeginImageContext(rect.size);

     [[UIImage imageWithCGImage: imageRef] drawInRect: rect];

     UIImage *thumbnail = UIGraphicsGetImageFromCurrentImageContext();

     UIGraphicsEndImageContext();

     // DoneResizing


     return thumbnail;

}


实际应用简化

- (UIImage *)generatePhotoThumbnail:(UIImage*)image

{

   CGRect rect=CGRectMake(0,0,60,78);

    //裁剪图片

   CGImageRef imageRef=CGImageCreateWithImageInRect([image CGImage], CGRectMake(0,0,140,182));


   UIGraphicsBeginImageContext(rect.size);

   [[UIImage imageWithCGImage: imageRef] drawInRect: rect];

    //如果不裁剪图片可以直接画

   //[image drawInRect:CGRectMake(0, 0, theSize.width, theSize.height)];

   UIImage *thumbnail = UIGraphicsGetImageFromCurrentImageContext();

   UIGraphicsEndImageContext();

   return thumbnail;

}


附:

    UIImage类并没有提供缩放图片需要用到的API,是不是觉得很吃惊?没关系,我们自己来添加一个。

定义缩放图片的Category

//  UIImage+Scale.h

@interface UIImage (scale)

- (UIImage*) scaleToSize: (CGSize)size;


@end


实现这个Category的定义

// UIImage+Scale.m 

#import "UIImage+Scale.h"


@implementation UIImage (scale)


-(UIImage*)scaleToSize:(CGSize)size

{

    // 创建一个bitmap的context,并把它设置成为当前正在使用的context

     UIGraphicsBeginImageContext(size);


     // 绘制改变大小的图片

    [self drawInRect: CGRectMake(0, 0, size.width, size.height)];


     // 从当前context中创建一个改变大小后的图片

     UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();


     // 使当前的context出堆栈

     UIGraphicsEndImageContext();


     // 返回新的改变大小后的图片

    return scaledImage;

}


@end


如何使用

// 创建图片

UIImage *image = [UIImage imageNamed:@"myImage.png"];


// 更改图片大小

UIImage *scaledImage = [image scaleToSize: CGSizeMake(25.0f,35.0f)]


2.2 图片裁切的四种方法

///方法中会自动做缩放处理

+ (void) getBitmapImage: (UIImage *)image Size: (CGSize)imageSize CompletionBlock: (HJCallbackBlock)block

{

        //改进方案

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{

            //YES参数表示不透明裁切

            UIGraphicsBeginImageContextWithOptions(imageSize,YES, 0);

            CGContextRef context = UIGraphicsGetCurrentContext();


            if(!context) {

                dispatch_async(dispatch_get_main_queue(),^{

                    block(image);

                });

        }


        CGRect rect = CGRectMake(0, 0, imageSize.width, imageSize.height);


        //坐标系统已经自动考虑了缩放因素,不需要额外处理

        [image drawInRect: rect blendMode: kCGBlendModeNormal alpha:1];


        UIImage*temp = UIGraphicsGetImageFromCurrentImageContext();

        NSData*tempData = UIImageJPEGRepresentation(temp,1);

        UIGraphicsEndImageContext();


        //设置SDWebImage库的缓存

        NSString*device = [HJUtility getCurrentDevice];

        if([device rangeOfString:@"iPhone 4"].length> 0) {

            if(tempData.length > 500000) {

                tempData =UIImageJPEGRepresentation(temp,0.6);

            }


            temp = [UIImage imageWithData: tempData];

        }


        dispatch_async(dispatch_get_main_queue(),^{

            if(block) {

                block(temp);

            }

        });

    });


    //    //改进方案1

    //        CGImageRef imgRef = CGImageCreateWithImageInRect(image.CGImage, CGRectMake(0, 0, image.size.width, image.size.height));

    //       UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0);

    //        CGContextRef context =UIGraphicsGetCurrentContext();

    //

    //        CGContextDrawImage(context, imageRect, imgRef);

    //

    //    //   [image drawInRect: imageRect];

    //        UIImage *imgData = UIGraphicsGetImageFromCurrentImageContext();

    //

    //        UIGraphicsEndImageContext();

    //        CGImageRelease(imgRef);

    //

    //        UIImage *data = [selfverticallyFlipImage: imgData];

    //

    //        return data;


    //方案二,内存有释放,挂机

    //   UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);

    //

    //    CGContextRef context = UIGraphicsGetCurrentContext();

    //    CGRect rect = CGRectMake(0, 0,imageSize.width * [UIScreen mainScreen].scale, imageSize.height * [UIScreenmainScreen].scale);

    //    // draw alpha-mask

    ////    CGContextSetBlendMode(context,kCGBlendModeNormal);

    //    CGContextDrawImage(context, rect,image.CGImage);

    //    // draw tint color, preserving alpha valuesof original image

    ////    CGContextSetBlendMode(context,kCGBlendModeSourceIn);

    //

    //    CGContextFillRect(context, rect);

    //

    //    //Set the original greyscale template asthe overlay of the new image

    //    UIImage *imgData = [self verticallyFlipImage: image];

    //    [imgData drawInRect: imageRect];

    //    UIImage *colouredImage = UIGraphicsGetImageFromCurrentImageContext();

    //    UIGraphicsEndImageContext();

    //    colouredImage = [self verticallyFlipImage: colouredImage];

    //    CGContextRelease(context);

    //

    //    return colouredImage;


    //方案三,CGBitmapContextCreate方案,内存没释放

    //    CGFloat targetWidth = imageSize.width *[UIScreen mainScreen].scale;

    //

    //    CGFloat targetHeight = imageSize.height *[UIScreen mainScreen].scale;

    //    CGImageRef imageRef = [image CGImage];

    //

    //    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);

    //

    //    CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);

    //    CGContextRef bitmapContext;

    //    bitmapContext = CGBitmapContextCreate(NULL, targetWidth, targetHeight, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);

    //    CGContextDrawImage(bitmapContext, CGRectMake(0, 0, targetWidth, targetHeight), imageRef);

    //

    //    CGImageRef imgref = CGBitmapContextCreateImage(bitmapContext);

    //    UIImage* newImage = [UIImage imageWithCGImage: imgref];

    //

    //    CGColorSpaceRelease(colorSpaceInfo);

    //    CGContextRelease(bitmapContext);

    //    CGImageRelease(imgref);

    //

    //    return newImage;


    //方案四,CGBitmapContextCreate方案,但是采用CGDataProviderCreateWithCFData方案解决内存占用问题

    //    NSData *data =UIImageJPEGRepresentation(image, 1);

    //    CGDataProviderRef dataProvider =CGDataProviderCreateWithCFData((__bridge CFDataRef)data);

    //    CGImageRef imageRef =CGImageCreateWithJPEGDataProvider(dataProvider,

    //                                                          NULL, NO,

    //                                                          kCGRenderingIntentDefault);

    //

    //    CGFloat targetWidth = imageSize.width *[UIScreen mainScreen].scale;

    //    CGFloat targetHeight = imageSize.height *[UIScreen mainScreen].scale;

    //    //       CGImageRef imageRef = [image CGImage];

    //

    //    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);

    //

    //    CGColorSpaceRef colorSpaceInfo =CGImageGetColorSpace(imageRef);

    //    CGContextRef bitmapContext;

    //    bitmapContext = CGBitmapContextCreate(NULL,targetWidth, targetHeight,CGImageGetBitsPerComponent(imageRef),0,colorSpaceInfo, bitmapInfo);

    //    CGContextDrawImage(bitmapContext,CGRectMake(0, 0, targetWidth, targetHeight), imageRef);

    //

    //    // If failed, return undecompressed image

    //    if (!bitmapContext) return image;

    //

    //    CGImageRef imgref =CGBitmapContextCreateImage(bitmapContext);

    //    UIImage* newImage = [UIImageimageWithCGImage:imgref];//[UIImage imageWithCGImage:decompressedImageRefscale:image.scale orientation:image.imageOrientation];

    //   

    //    CGColorSpaceRelease(colorSpaceInfo);

    //    CGContextRelease(bitmapContext);

    //    CGImageRelease(imgref);

    //   

    //    return newImage;

}


3 参考链接

iOS开发中关于UIImage的知识点总结

http://mobile.51cto.com/hot-442118.htm

iOS开发笔记--使用blend改变图片颜色

http://blog.csdn.net/hopedark/article/details/17761177

iOS处理图片的一些小Tip

http://blog.ibireme.com/2015/11/02/ios_image_tips/

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容