UIImage

官方文档点蓝色文字:UIImageCIImageCGImage

这篇文章是对官方文档的学习笔记,不是翻译,对文档抽象的地方加了解释和示例,对啰嗦的地方删掉。前面是概念讲解,后面是 API 讲解。重要的概念有图片拉伸、动态图、图片方向、模板图片等。

先对比3个概念 UIImage、CImage、CGImage:

  • UIImage 里面可能包含 CGImage 和 CIImage 数据,是 UIKit 框架的对象。
  • CIImage 不是图片,虽然包含了 CGImage 数据,但它只是描述 Core Image filters 处理或产生图片的过程。是 Core Image 框架的对象。Core Image 框架专门处理和分析图片,比如加滤镜效果。
  • CGImage 才是图片数据,是 Core Graphics 框架的对象。Core Graphics 框架使用 Quartz 2D 技术进行图片绘制和变换、离屏渲染、图片创建、图层蒙版、创建 PDF 文档等。
  • CIImage 和 CGImage 就像菜谱和菜的区别。CIImage 是菜谱,描述如何以及用什么材料做一道菜,而 CGImage 才是可以吃的菜。


<p>


Overview

图片定义:An object that manages image data in your app. An image object may contain a single image or a sequence of images you intend to use in an animation.

图片用途之一:Draw an image directly into a view or other graphics context.

虽然支持所有类型图片,但是建议使用PNG和JPEG。这两种类型都优化过,性能更好。尤其PNG是无损格式,墙裂推荐使用。


<p>

Creating Image Objects

注意图片是否在bundle中、是否缓存图片、图片的使用频率:

  • Use the imageNamed:inBundle:compatibleWithTraitCollection: method (or the imageNamed: method) to create an image from an image asset or image file located in your app’s main bundle (or some other known bundle). Because these methods cache the image data automatically, they are especially recommended for images that you use frequently.
  • Use the imageWithContentsOfFile: or initWithContentsOfFile: method to create an image object where the initial data is not in a bundle. These methods load the image data from disk each time, so you should not use them to load the same image repeatedly.
  • Use the animatedImageWithImages:duration: and animatedImageNamed:duration: methods to create a single UIImage object comprised of multiple sequential images. Install the resulting image in a UIImageView object to create animations in your interface.

imageNamed:方法加载<u>在bundle中</u>的图片,缓存到内存中,适合频繁使用的图片。imageWithContentsOfFile:方法每次都从沙盒中加载图片,适合使用频率低的图片。animatedImageWithImages:duration:方法创建一个由多张图片构成的图片,用于UIImageView播放动画。

UIImage类的其他方法允许你从Core Graphics images or image data创建图片和动画。UIKit提供 UIGraphicsGetImageFromCurrentImageContext 方法从当前的context中获取你绘制的图片。

注意,image对象是不可变的,属性在图片创建之后就不能修改了。这也意味着,它是线程安全的。

使用Image assets管理图片是最简易的,它可以添加多个image set ,每个set包含用于不同系统版本、环境(compact or regular)和缩放比例的图片。

除了从disk加载图片,也可以使用UIImagePickerController从摄像头或者照片库获取图片,但这需要用户授权。


<p>

Defining a Stretchable Image

使用resizableImageWithCapInsets: 或者 resizableImageWithCapInsets:resizingMode:方法创建可拉伸图片,参数insets分割图片为2~9个部分。如图1所示,4个方向非零的inset把图片分割为9个部分。

Figure 1 Using insets to define stretchable regions

inset定义了4个方形盖子,top、left、bottom、right,被盖子盖住的部分不被拉伸。top、bottom保证在垂直方向不被拉伸,left、right保证在水平方向不被拉伸。图2的4个角落是不会被拉伸的,每个箭头表示该区域允许被拉伸的方向。

Each inset defines the potion of the image that does not stretch in the given dimension. The regions inside an image’s top and bottom insets maintain a fixed height, and the areas inside the left and right insets maintain a fixed width. Figure 2 shows how each part of a nine-part image stretches as the image itself is stretched to fill the available space. The corners of the image do not change size because they are inside both a horizontal and vertical inset.

Figure 2 Stretchable portions of a nine-part image


<p>

Comparing Images

从相同的图片缓存数据创建的两个图片对象也可能是不同的。唯一可靠的办法是使用isEqual:方法比较。

正确的和错误的比较方式:

// Load the same image twice.
UIImage* image1 = [UIImage imageNamed:@"MyImage"];
UIImage* image2 = [UIImage imageNamed:@"MyImage"];
 
// The image objects may be different, but the contents are still equal
if ([image1 isEqual:image2]) {
   // Correct. This technique compares the image data correctly.
}
 
if (image1 == image2) {
   // Incorrect! Direct object comparisons may not work.
}


<p>

Accessing the Image Data

CGImageCIImage 属性分别是 Core Graphics 和 Core Image 的图片数据。也可以使用 UIImagePNGRepresentationUIImageJPEGRepresentation 函数生成一个包含 PNG 或 JPEG 格式图片数据的 NSData 对象。


<p>

Symbols


Loading and Caching Images


<p>

+ (UIImage *)imageNamed:(NSString *)name 
               inBundle:(NSBundle *)bundle 
compatibleWithTraitCollection:(UITraitCollection *)traitCollection;
  • name 除了 PNG 图片不需要后缀名,其他类型的图片需要包含后缀名。
  • bundle 是包含图片或者 image asset 的文件夹。传 nil 会搜索 main bundle。
  • bundle 理解为一个文件夹。利用 bundle 对象可以通过文件名访问里面的资源,不需要知道文件夹的结构。官方解释:Apple uses bundles to represent apps, frameworks, plug-ins, and many other specific types of content. 具体点这里 NSBundle
  • trait​Collection 是描述界面的特征集合,比如 size class,display scale,interface idiom(比如文字是从右往左显示的)。具体点这里 UITrait​Collection。传 nil 会使用 main screen 的特征。
  • 函数先在系统缓存中寻找图片,找不到再创建,可能返回 nil。系统可能在任何时候清理内存,但只清除不使用的图片。iOS 9之后,函数是线程安全的。
size class


<p>

+ (UIImage *)imageNamed:(NSString *)name;

  • name 对于 PNG 图片可以忽略后缀名,其他类型的图片需要包含后缀名。
  • 函数先在系统缓存中寻找图片,找不到再创建,可能返回 nil。系统可能在任何时候清理内存,但只清除不使用的图片。iOS 9之后,函数是线程安全的。
  • 函数会缓存图片到内存中。如果图片只展示一次,不想缓存图片,可以使用 image​With​Contents​Of​File:​ 代替。


<p>


Creating and Initializing Image Objects


<p>

+ (UIImage *)imageWithContentsOfFile:(NSString *)path;

// demo
NSString *path = [[NSBundle mainBundle]pathForResource:@"demo" ofType:@"png"];
UIImage *image = [UIImage imageWithContentsOfFile:path];
  • 如果创建图片失败会返回 nil。
  • 不会缓存 image 对象。


<p>

+ (UIImage *)imageWithData:(NSData *)data;

// demo
NSString *path = [[NSBundle mainBundle]pathForResource:@"demo" ofType:@"png"];
NSData *data = [NSData dataWithContentsOfFile:path];
UIImage *image = [UIImage imageWithData:data]; 
  • 如果创建图片失败会返回 nil。
  • 不会缓存 image 对象。


<p>

+ (UIImage *)imageWithData:(NSData *)data 
                     scale:(CGFloat)scale;

// demo
// 以为是放大十倍,结果是缩小了十倍。但是image.cgImage大小不变
image = [UIImage imageWithData:data scale:10]; // po image.size: (width = 64, height = 38.6)
image = [UIImage imageWithData:data scale:1]; //  po image.size: (width = 640, height = 386)
  • 如果创建图片失败会返回 nil。
  • 不会缓存 image 对象。
  • scale 是比例因子,会影响 size 的值。1.0时,图片的 size 和像素尺寸相等。2.0时,size 是像素尺寸的一半。屏幕大小不变,分辨率越高,显示的图片越小。想象10个人排队,每排2个人和每排1个人的长度是不同的。


<p>

+ (UIImage *)imageWithCGImage:(CGImageRef)cgImage;

+ (UIImage *)imageWithCGImage:(CGImageRef)cgImage 
                        scale:(CGFloat)scale 
                  orientation:(UIImageOrientation)orientation;


// demo
UIImage *image = [UIImage imageNamed:@"demo"];
// 图片截取
CGImageRef cgImage = CGImageCreateWithImageInRect(image.CGImage,CGRectMake(0, 0, 1000, 1000)); 
image = [UIImage imageWithCGImage:cgImage];
// UIImageOrientationUpMirrored 是图片向上并水平翻转
image = [UIImage imageWithCGImage:cgImage scale:1 orientation:UIImageOrientationUpMirrored];
CGImageRelease(cgImage); // 释放内存
  • 使用 Quartz image 创建图片,失败返回 nil。
  • image​Ref 是 Quartz image 对象,可以使用 Core Graphics framework 创建。
  • scale 是比例因子,会影响 size 的值。1.0时,图片的 size 和像素尺寸相等。2.0时,size 是像素尺寸的一半。屏幕大小不变,分辨率越高,显示的图片越小。想象10个人排队,每排2个人和每排1个人的长度是不同的。
  • orientation 是图片显示方向,详细介绍看文末 UIImageOrientation 部分。
图片方向


<p>

+ (UIImage *)imageWithCIImage:(CIImage *)ciImage;

+ (UIImage *)imageWithCIImage:(CIImage *)ciImage 
                        scale:(CGFloat)scale 
                  orientation:(UIImageOrientation)orientation;


// demo
// 创建滤镜和CIImage
CIImage *ciImage = [CIImage imageWithData:data];
CIFilter *filter = [CIFilter filterWithName:@"CISepiaTone"]; // 创建滤镜
ciImage = [filter outputImage]; // 滤镜处理后输出图像

image = [UIImage imageWithCIImage:ciImage];
image = [UIImage imageWithCIImage:ciImage scale:1 orientation:UIImageOrientationUpMirrored];
  • ci​Image 是 Core Image 对象。
  • scale 是比例因子,会影响 size 的值。1.0时,图片的 size 和像素尺寸相等。2.0时,size 是像素尺寸的一半。屏幕大小不变,分辨率越高,显示的图片越小。想象10个人排队,每排2个人和每排1个人的长度是不同的。
  • orientation 是图片显示方向,详细介绍看文末 UIImageOrientation 部分。


<p>


Creating Specialized Image Objects


<p>

+ (UIImage *)animatedImageNamed:(NSString *)name 
                       duration:(NSTimeInterval)duration;

  • 创建一个动态图(animated image)。
  • name 是部分或完整的文件路径,不带后缀名(The full or partial path to the file (sans suffix))。可以是中文。
  • duration 是动画播放周期。
  • 函数会加载一系列 name + 数字 组成名字的图片,比如 name 是 “image”,会加载 image0,image1,……,一直到 image1024。如果缺少 image5,那么 image6之后的图片都不会加载。
  • 数字从 0 或者 1 开始,但是要连续。加载图片的 scale 和 size 属性要相等。


<p>

+ (UIImage *)animatedImageWithImages:(NSArray<UIImage *> *)images 
                            duration:(NSTimeInterval)duration;

  • 从一个图片数组创建一个动态图(animated image)。
  • images 是包含图片的数组。
  • duration 是动画播放周期。
  • 数组中图片的 scale 和 size 属性要相等。


<p>

+ (UIImage *)animatedResizableImageNamed:(NSString *)name 
                               capInsets:(UIEdgeInsets)capInsets 
                                duration:(NSTimeInterval)duration;

  • 创建一个可拉伸的动态图。
  • name 是部分或完整的文件路径,不带后缀名(The full or partial path to the file (sans suffix))。可以是中文。
  • cap​Insets 是保护图片某些部位不被拉伸的矩形帽子。
  • duration 是动画播放周期。
  • 函数会加载一系列 name + 数字 组成名字的图片,比如 name 是 “image”,会加载 image0,image1,……,一直到 image1024。如果缺少 image5,那么 image6之后的图片都不会加载。
  • 数字从 0 或者 1 开始,但是要连续。加载图片的 scale 和 size 属性要相等。
  • 拉伸模式默认是平铺(UIImageResizingModeTile)。详细介绍看文末的 UIImageResizingMode 部分。


<p>

+ (UIImage *)animatedResizableImageNamed:(NSString *)name 
                               capInsets:(UIEdgeInsets)capInsets 
                            resizingMode:(UIImageResizingMode)resizingMode 
                                duration:(NSTimeInterval)duration;

  • 创建一个可拉伸的动态图。
  • name 是部分或完整的文件路径,不带后缀名(The full or partial path to the file (sans suffix))。可以是中文。
  • cap​Insets 是保护图片某些部位不被拉伸的矩形帽子。
  • resizing​Mode 是拉伸模式,平铺或者拉伸。详细介绍看文末的 UIImageResizingMode 部分。
  • duration 是动画播放周期。
  • 函数会加载一系列 name + 数字 组成名字的图片,比如 name 是 “image”,会加载 image0,image1,……,一直到 image1024。如果缺少 image5,那么 image6之后的图片都不会加载。
  • 数字从 0 或者 1 开始,但是要连续。加载图片的 scale 和 size 属性要相等。
  • 只有拉伸模式要使用 UIImageResizingModeStretch 时,才调用该函数,否则调用上面的函数 animated​Resizable​Image​Named:​cap​Insets:​duration:。


<p>

- (UIImage *)imageFlippedForRightToLeftLayoutDirection;
  • 返回的 image 并没有翻转,只是把 flipsForRightToLeftLayoutDirection 属性设置为 YES,该属性是只读的。
  • 当系统语言决定布局方向要从右向左,或者 image view 的 semanticContentAttribute 属性设置为 UISemanticContentAttributeForceRightToLeft 时, image 才会表现为翻转的。在从左向右布局的环境中,image 表现为不翻转。比如在中国,文字是从左向右读的,通过该方法创建的 image 是不翻转的,除非修改 image view 的上述属性。

</br>

- (UIImage *)imageWithRenderingMode:(UIImageRenderingMode)renderingMode;

// demo
  UIImage *myImage = [UIImage imageNamed:@"myImageFile.png"];
  myImage = [myImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
  • 创建并返回一个特定渲染模式的 image。
  • image 的 renderingMode 属性是只读的,通过该函数创建一个新的渲染模式的 image。
  • renderingMode 有3种:UIImageRenderingModeAutomatic、UIImageRenderingModeAlwaysOriginal、UIImageRenderingModeAlwaysTemplate。默认是 automatic,根据上下文自动选择 original 或者 template;original 是绘制原图;template 是忽略图片的颜色信息(通过 tintColor 重新上色),作为一个透明的模板图片来绘制。
  • 模板图片可以理解为无色的,用 tint color 重新上色的图片。一些视图,比如 navigation bars, tab bars, toolbars, segmented controls,它们的 foreground images 自动使用模板图片, background images 自动使用原图片。另一些视图,比如 image views 和 web views,自动使用原图片。因此设置导航栏图标默认是蓝色,因为它的 tint color 是蓝色。关于模板图片,点这里
  • 总结:renderingMode 对 tint color 有影响。如果发现图片颜色不符合预期,就使用 original;如果想自定义图片颜色,使用 template,然后设置 tint color。renderingMode 也可以在故事板设置,如图所示。
设置 renderingMode


<p>

- (UIImage *)imageWithAlignmentRectInsets:(UIEdgeInsets)alignmentInsets;


  // demo
  // 图片阴影在右下方,大小是20*20,所以要往右下平移
  UIEdgeInsets rInsets = UIEdgeInsetsMake(0, 0, 20, 20);
  image = [image imageWithAlignmentRectInsets:rInsets]; // 只对自动布局有效,代码布局无效
  • 创建含有特定 alignmentRectInsets 的图片。
  • auto layout 是按 alignment rectangle 来布局的。alignment rectangle 默认和 frame 大小相等,设置 alignmentRectInsets 可以修改它的大小。
  • 参数 alignmentInsets = (上,左,下,右),逆时针旋转。正数表示往该方向平移。比如 right = 20,图片会向右平移 20。
  • 仅对自动布局有效,仅对自动布局有效,仅对自动布局有效。
  • 如图所示,图片中含有阴影,默认居中对齐的时候,蓝圆会往左上偏移。阴影大小为 20*20,为了使蓝圆居中(往右下平移),可以设置 alignmentInsets = (0, 0, 20, 20)。
alignment rectInsets


<p>

- (UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsets;
  • 创建含有特定 cap insets 的图片。cap insets 定义图片不可拉伸的区域。
  • 使用该方法创建的拉伸图片,iOS 会根据图片拉伸区域的大小选择不同的渲染技术(uses different rendering techniques),性能也不相同:
    • 如果拉伸区域宽高都是1,or the center region of the image is 1 x 1 pixel—iOS draws the image by stretching the 1-pixel region. This mode provides the fastest performance (for nonzero cap insets)。
    • 如果拉伸区域宽高大于1,iOS 使用平铺,虽然性能下降,但对纹理图片(不是纯色图片)有用。
    • 如果拉伸区域是整张图片(参数 capInsets = UIEdgeInsetsZero),而且图片大于1x1,iOS 会平铺整张图片,这样比平铺图片的部分区域性能更好(This mode is faster than the tiling mode for nonzero cap insets)。
  • 要自定义 resizing mode,使用函数 resizableImageWithCapInsets:resizingMode:
  • 头文件的注释说默认使用平铺(create a resizable version of this image. the interior is tiled when drawn),不知道文档上面说的使用不同渲染技术是什么意思。


<p>

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


    // demo
    // 拉伸图片的不同区域
    float bottom = image.size.height / 2;
    float top   =  image.size.height / 2;
    // 上,左,下,右
    UIEdgeInsets capInsets2 = UIEdgeInsetsMake(0, 0, bottom, 0); // 底部绿色区域在垂直方向上不被拉伸
    UIEdgeInsets capInsets3 = UIEdgeInsetsMake(top, 0, 0, 0); // 顶部蓝色区域在垂直方向上不被拉伸
    // 变形模式是拉伸
    UIImage *image2 = [image resizableImageWithCapInsets:capInsets2 resizingMode:UIImageResizingModeStretch];
    UIImage *image3 = [image resizableImageWithCapInsets:capInsets3 resizingMode:UIImageResizingModeStretch];

  • 创建含有特定 cap insets 和 拉伸方式的图片。
  • UIImageResizingMode 有两种,UIImageResizingModeStretchUIImageResizingModeTile。stretch 是拉伸,tile 是平铺。
  • 该函数和 resizableImageWithCapInsets: 是一样的,因此只有使用 UIImageResizingModeStretch 才使用该函数(意思是前者默认平铺咯?文档无力吐槽.)。
  • 如图所示,当 image view 高度变化时,图片会跟着拉伸。可以设置拉伸区域是蓝色或者绿色。
拉伸图片


<p>


Image Attributes


<p>

  • image​Orientation
    图片方向,默认是 up。如果图片有相关的 metadata (比如 EXIF 信息),该属性由 metadata 决定。文末有 UIImageOrientation 的详细介绍。
  • size
    图片的 logical 尺寸,单位是点。受 image​Orientation 影响,比如长方形图片旋转之后,size 会不一样。size 和属性 scale 相乘得到像素尺寸。
  • scale
    比例因子。只读。如果加载的图片有 @2x 修饰,它的比例因子就是2.0。也可以在通过 CGImage 创建图片时指定该值。默认1.0。乘以 size 得到图片的像素尺寸。

  • flips​For​Right​To​Left​Layout​Direction
    布尔值,表示是否翻转为 right-to-left 布局。

  • CGImage
    底层 Quartz image 数据。如果图片数据因为内存限制被清除了,可以调用该方法强制加载图片数据到内存中。可能会引起性能问题。如果图片是通过 CIImage 创建的,该值为 NULL。

  • CIImage
    底层 Core Image 数据。如果图片是通过 CGImageRef 创建的,该值为 nil。

  • images
    数组,保存 animated image 的所有图片。对于 non-animated image,该值为 nil。

  • duration
    播放 animated image 的时间周期,不是每张图片的时间间隔。默认 0.0 。

  • cap​Insets
    定义上左下右4个区域不被拉伸。可以理解为4个矩形帽子,盖在图片上,当图片被拉伸时,被盖住的部分保持原来的大小和外观,只有不被盖住的部分被拉伸。默认是 UIEdge​Insets​Zero,表示拉伸整张图片。可以使用 resizable​Image​With​Cap​Insets: 方法创建指定拉伸区域的拉伸图片。

  • alignment​Rect​Insets
    简单理解为布局时的位置平移量。布局是通过 alignment​Rect 而不是 size 来计算位置的,默认和 size 相等。影响视觉上的位置,但是不影响 frame。上左下右4个方向,正数表示往该方向平移。比如图片右边有宽度为2的阴影,要使图片居中,在不修改 frame 的情况下,可以通过这个变量来向右平移2,使得图片看起来是居中的,实际它是在中间偏左。

  • image​Asset
    返回图片所在的 UIImageAsset 对象,可能为 nil。

  • trait​Collection
    返回一个 UITraitCollection 对象。​

  • rendering​Mode
    返回一个 UIImageRenderingMode 类型的值,默认是 UIImageRenderingModeAutomatic​​。详细介绍请看文末的 UIImageRenderingMode 部分。


<p>


Drawing Images


<p>

这里涉及到 Core Graphics, 有几篇文章写的不错:


<p>

- (void)drawAtPoint:(CGPoint)point;

  • 绘制图片到当前的 graphics context。
  • point 指的图片左上角。
  • 图片的 orientation 和 context 的 transforms 对绘制有影响。
  • This method draws the image at full opacity using the kCGBlendModeNormal blend mode. 详情点这里 CGBlend​Mode


<p>

- (void)drawAtPoint:(CGPoint)point 
          blendMode:(CGBlendMode)blendMode 
              alpha:(CGFloat)alpha;


  • 使用特定合成模式绘制图片到当前的 graphics context。
  • point 指的图片左上角。
  • blend mode 指合成模式,详情点这里 CGBlend​Mode
  • alpha 指透明度,从0.0 ~ 1.0。0.0是完全透明,1.0是不透明。
  • 图片的 orientation 和 context 的 transforms 对绘制有影响。
  • alpha 通道记录图片的透明度信息,定义透明、不透明、半透明区域。


<p>

- (void)drawInRect:(CGRect)rect;

  • 绘制图片到当前图像上下文的特定矩形,可能会拉伸图片适应矩形。
  • rect 指在 graphics context 所在的坐标系统中,绘制图片的矩形。图片绘制在矩形原点的右下方。
  • 图片的 orientation 和 context 的 transforms 对绘制有影响。
  • This method draws the image at full opacity using the kCGBlendModeNormal blend mode. 详情点这里 CGBlend​Mode


<p>

- (void)drawInRect:(CGRect)rect 
         blendMode:(CGBlendMode)blendMode 
             alpha:(CGFloat)alpha;


  • 使用特定的合成模式,绘制图片到当前图像上下文的特定矩形,可能会拉伸图片适应矩形。
  • rect 指在 graphics context 所在的坐标系统中,绘制图片的矩形。图片绘制在矩形原点的右下方。
  • blend mode 指合成模式,详情点这里 CGBlend​Mode
  • alpha 指透明度,从0.0 ~ 1.0。0.0是完全透明,1.0是不透明。
  • 图片的 orientation 和 context 的 transforms 对绘制有影响。


<p>

- (void)drawAsPatternInRect:(CGRect)rect;


  • 使用平铺模式,绘制图片到当前图像上下文的特定矩形中。
  • 忽略 fill color。
  • rect 指在 graphics context 所在的坐标系统中,绘制图片的矩形。图片绘制在矩形原点的右下方。
  • context 的 transforms 对绘制有影响。


<p>


Constants


<p>

// UIImageOrientation
typedef NS_ENUM(NSInteger, UIImageOrientation) {
    UIImageOrientationUp,            // default orientation
    UIImageOrientationDown,          // 180 deg rotation
    UIImageOrientationLeft,          // 90 deg CCW
    UIImageOrientationRight,         // 90 deg CW
    UIImageOrientationUpMirrored,    // as above but image mirrored along other axis. horizontal flip
    UIImageOrientationDownMirrored,  // horizontal flip
    UIImageOrientationLeftMirrored,  // vertical flip
    UIImageOrientationRightMirrored, // vertical flip
};


// demo
    image = [UIImage imageNamed:@"R.jpg"];
    UIImageOrientation orientation = UIImageOrientationUp;
    orientation = UIImageOrientationLeft;
    orientation = UIImageOrientationRight;
    orientation = UIImageOrientationDown;
    orientation = UIImageOrientationUpMirrored;
    orientation = UIImageOrientationLeftMirrored; // 先左右翻转再左转90°!
    orientation = UIImageOrientationRightMirrored;
    orientation = UIImageOrientationDownMirrored;
    image = [UIImage imageWithCGImage:image.CGImage scale:1 orientation:orientation];


  • 默认是 up,left 是逆时针旋转90°,right 是顺时针旋转90°,down 是旋转180°。
  • mirrored 是水平翻转,镜子效果(左右相反,就像照镜子)。
  • 注释中,CW 是 顺时针 clockwise 的缩写,CCW 是 逆时针 counterclockwise 的缩写。
  • 图文详情点这里 UIImage​Orientation。官方文档中,带有 left 和 right 的图片都是错的,阐述也是错的。UpMirrored 也错了。好吧,除了 up 和 down,都错了。比如 left 的阐述:“The image is rotated 90 degrees clockwise, as shown here”, 这和代码注释 “90 deg CCW” 是矛盾的(CCW 是 逆时针 counterclockwise 的缩写),和我的实验结果也是矛盾的。
  • 注意,带有 mirrored 的,都是先水平翻转,再旋转!和先旋转再水平翻转效果不一样。left、down、right 是 up 的旋转版本,left、down、right + Mirrored 是 upMirrored 的旋转版本。代码效果如下图所示:
图片旋转.png


<p>

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


// demo
    image = [UIImage imageNamed:@"R.jpg"];
    UIImageResizingMode mode = UIImageResizingModeStretch; // 拉伸
    mode = UIImageResizingModeTile; // 平铺
    // 创建可变图片。当 imageView 大于 image 时,可能会拉伸或者平铺 image。
    image = [image resizableImageWithCapInsets:UIEdgeInsetsZero resizingMode:mode]; 

  • tile 是平铺,stretch 是拉伸,如图1所示。
  • image view 的 contentMode 会影响拉伸效果。当 contentMode 不是 UIViewContentModeScaleToFill、UIViewContentModeScaleAspectFit、UIViewContentModeScaleAspectFill 时,图片不会拉伸,但可能会平铺。
  • 比如 UIImageResizingModeTile 和 UIViewContentModeCenter 搭配使用,image view 比图片大很多就会在中部平铺多张图片,如图2所示。
图1 平铺和拉伸
图2 contentMode 的影响


<p>

// UIImage​Rendering​Mode
typedef NS_ENUM(NSInteger, UIImageRenderingMode) {
    UIImageRenderingModeAutomatic,          // Use the default rendering mode for the context where the image is used
    UIImageRenderingModeAlwaysOriginal,     // Always draw the original image, without treating it as a template
    UIImageRenderingModeAlwaysTemplate,     // Always draw the image as a template image, ignoring its color information
} NS_ENUM_AVAILABLE_IOS(7_0);


// demo
  UIImage *myImage = [UIImage imageNamed:@"myImageFile.png"];
  myImage = [myImage imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];

  • 默认是 automatic,根据上下文自动选择 original 或者 template。
  • original 是绘制原图。
  • template 是忽略图片颜色信息(通过 tintColor 重新上色),作为一个透明的模板图片来绘制。
  • 模板图片可以理解为无色的,用 tint color 重新上色的图片。一些视图,比如 navigation bars, tab bars, toolbars, segmented controls,它们的 foreground images 自动使用模板图片, background images 自动使用原图片。另一些视图,比如 image views 和 web views,自动使用原图片。因此设置导航栏图标默认是蓝色,因为它的 tint color 是蓝色。关于模板图片,点这里


<p>


Instance Properties


<p>

@property(nonatomic, readonly) UIGraphicsImageRendererFormat *imageRendererFormat;

  • No overview available.
  • iOS 10 新出的,搜不到资料。


<p>


Instance Methods


<p>

- (CGImageRef)CGImage;
  • The underlying Quartz image data.
  • 如果图片数据因为内存限制被清除了,调用该函数强制加载图片数据到内存。可能会引起性能问题。
  • 如果 UIImage 对象是通过 CIImage 对象创建的,该函数返回 NULL。


<p>

- (UIImage *)imageWithHorizontallyFlippedOrientation;
  • No overview available.
  • iOS 10 新出的,搜不到资料。


<p>

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

推荐阅读更多精彩内容