设为首页 加入收藏

TOP

CATiledLayer(一)
2017-10-11 14:39:27 】 浏览:4539
Tags:CATiledLayer

CATiledLayer

有些时候你可能需要绘制一个很大的图片,常见的例子就是一个高像素的照片或者是地球表面的详细地图。iOS应用通畅运行在内存受限的设备上,所以读取整个图片到内存中是不明智的。载入大图可能会相当地慢,那些对你看上去比较方便的做法(在主线程调用UIImage-imageNamed:方法或者-imageWithContentsOfFile:方法)将会阻塞你的用户界面,至少会引起动画卡顿现象。

能高效绘制在iOS上的图片也有一个大小限制。所有显示在屏幕上的图片最终都会被转化为OpenGL纹理,同时OpenGL有一个最大的纹理尺寸(通常是20482048,或40964096,这个取决于设备型号)。如果你想在单个纹理中显示一个比这大的图,即便图片已经存在于内存中了,你仍然会遇到很大的性能问题,因为Core Animation强制用CPU处理图片而不是更快的GPU(见第12章『速度的曲调』,和第13章『高效绘图』,它更加详细地解释了软件绘制和硬件绘制)。

CATiledLayer为载入大图造成的性能问题提供了一个解决方案:将大图分解成小片然后将他们单独按需载入。让我们用实验来证明一下。

小片裁剪

这个示例中,我们将会从一个2048*2048分辨率的雪人图片入手。为了能够从CATiledLayer中获益,我们需要把这个图片裁切成许多小一些的图片。你可以通过代码来完成这件事情,但是如果你在运行时读入整个图片并裁切,那CATiledLayer这些所有的性能优点就损失殆尽了。理想情况下来说,最好能够逐个步骤来实现。

清单6.11 演示了一个简单的Mac OS命令行程序,它用CATiledLayer将一个图片裁剪成小图并存储到不同的文件中。

清单6.11 裁剪图片成小图的终端程序

 

 1 #import 
 2 
 3 int main(int argc, const char * argv[])
 4 {
 5     @autoreleasepool{
 6         ?//handle incorrect arguments
 7         if (argc < 2) {
 8             NSLog(@"TileCutter arguments: inputfile");
 9             return 0;
10         }
11 
12         //input file
13         NSString *inputFile = [NSString stringWithCString:argv[1] encoding:NSUTF8StringEncoding];
14 
15         //tile size
16         CGFloat tileSize = 256; //output path
17         NSString *outputPath = [inputFile stringByDeletingPathExtension];
18 
19         //load image
20         NSImage *image = [[NSImage alloc] initWithContentsOfFile:inputFile];
21         NSSize size = [image size];
22         NSArray *representations = [image representations];
23         if ([representations count]){
24             NSBitmapImageRep *representation = representations[0];
25             size.width = [representation pixelsWide];
26             size.height = [representation pixelsHigh];
27         }
28         NSRect rect = NSMakeRect(0.0, 0.0, size.width, size.height);
29         CGImageRef imageRef = [image CGImageForProposedRect:&rect context:NULL hints:nil];
30 
31         //calculate rows and columns
32         NSInteger rows = ceil(size.height / tileSize);
33         NSInteger cols = ceil(size.width / tileSize);
34 
35         //generate tiles
36         for (int y = 0; y < rows; ++y) {
37             for (int x = 0; x < cols; ++x) {
38             //extract tile image
39             CGRect tileRect = CGRectMake(x*tileSize, y*tileSize, tileSize, tileSize);
40             CGImageRef tileImage = CGImageCreateWithImageInRect(imageRef, tileRect);
41 
42             //convert to jpeg data
43             NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:tileImage];
44             NSData *data = [imageRep representationUsingType: NSJPEGFileType properties:nil];
45             CGImageRelease(tileImage);
46 
47             //save file
48             NSString *path = [outputPath stringByAppendingFormat: @"_%02i_%02i.jpg", x, y];
49             [data writeToFile:path atomically:NO];
50             }
51         }
52     }
53     return 0;
54 }
View Code

这个程序将20482048分辨率的雪人图案裁剪成了64个不同的256256的小图。(256*256是CATiledLayer的默认小图大小,默认大小可以通过tileSize属性更改)。程序接受一个图片路径作为命令行的第一个参数。我们可以在编译的scheme将路径参数硬编码然后就可以在Xcode中运行了,但是以后作用在另一个图片上就不方便了。所以,我们编译了这个程序并把它保存到敏感的地方,然后从终端调用,如下面所示:

1 > path/to/TileCutterApp path/to/Snowman.jpg

 

The app is very basic, but could easily be extended to support additional arguments such as tile size, or to export images in formats other than JPEG. The result of running it is a sequence of 64 new images, named as follows:

这个程序相当基础,但是能够轻易地扩展支持额外的参数比如小图大小,或者导出格式等等。运行结果是64个新图的序列,如下面命名:

Snowman_00_00.jpg
Snowman_00_01.jpg
Snowman_00_02.jpg
...
Snowman_07_07.jpg

既然我们有了裁切后的小图,我们就要让iOS程序用到他们。CATil

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇iOS开发之UITableView中计时器的.. 下一篇给iPhone手机安装*.ipa

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目