如何创建一个CGBitmapContext用于视网膜显示并且不浪费空间用于常规显示? [英] How to create a CGBitmapContext which works for Retina display and not wasting space for regular display?

查看:107
本文介绍了如何创建一个CGBitmapContext用于视网膜显示并且不浪费空间用于常规显示?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否真的在UIKit中(包括drawRect)将自动处理Retina显示屏的高清方面?那么这是否意味着在drawRect中,当前1024 x 768视图的图形上下文实际上是2048 x 1536像素的位图上下文?

Is it true that if it is in UIKit, including drawRect, the HD aspect of Retina display is automatically handled? So does that mean in drawRect, the current graphics context for a 1024 x 768 view is actually a 2048 x 1536 pixel Bitmap context?

(更新:如果我使用drawRect中的当前上下文创建图像并打印其大小:

(Update: if I create an image using the current context in drawRect and print its size:

CGContextRef context = UIGraphicsGetCurrentContext();
CGImageRef image = CGBitmapContextCreateImage(context);
NSLog(@"width of context %i", (int) CGImageGetWidth(image));
NSLog(@"height of context %i", (int) CGImageGetHeight(image));

然后在新的iPad上,禁用状态栏,打印2048和1536,iPad 2将显示1024和768)

then on the new iPad, with the status bar disabled, 2048 and 1536 is printed, and iPad 2 will show 1024 and 768)

实际上,我们享受自动为我们处理的1分= 4像素的奢侈.

We actually enjoy the luxury of 1 point = 4 pixels automatically handled for us.

但是,如果我们使用CGBitmapContextCreate,那么这些像素实际上将是像素,而不是点? (至少如果我们为该位图提供数据缓冲区,则缓冲区的大小(字节数)显然不是为了更高的分辨率,而是为了标准分辨率,即使我们将NULL用作缓冲区,从而使为我们处理缓冲区,其大小可能与传递数据缓冲区的大小相同,并且它只是标准分辨率,而不是Retina的分辨率.

However, if we use CGBitmapContextCreate, then those will really be pixels, not points? (at least if we provide a data buffer for that bitmap, the size of the buffer (number of bytes) is obviously not for higher resolution, but for standard resolution, and even if we pass NULL as the buffer so that CGBitmapContextCreate handles the buffer for us, the size probably is the same as if we pass in a data buffer, and it is just standard resolution, not Retina's resolution).

我们始终可以为iPad 1和iPad 2以及新iPad创建2048 x 1536,但是这将浪费内存,处理器和GPU功能,因为只有新iPad才需要.

We can always create 2048 x 1536 for iPad 1 and iPad 2 as well as the New iPad, but it will waste memory and processor and GPU power, as it is only needed for the New iPad.

那么我们必须使用if () { } else { }来创建这样的位图上下文吗,我们实际上该如何做呢?而且我们所有的代码CGContextMoveToPoint必须针对视网膜显示进行调整以使用x * 2y * 2,而不是仅使用x, y的非视网膜显示也可以?对于代码来说,这可能是很混乱的. (或者也许我们可以定义局部变量scaleFactor并将其设置为[[UIScreen mainScreen] scale],因此对于标准分辨率,该值为1,如果是视网膜,则为2,因此我们的xy始终为x * scaleFactory * scaleFactor,而不仅仅是使用CGContextMoveToPoint等绘制的xy)

So do we have to use a if () { } else { } to create such a bitmap context and how do we actually do so? And all our code CGContextMoveToPoint has to be adjusted for Retina display to use x * 2 and y * 2 vs non-retina display of just using x, y as well? That can be quite messy for the code. (or maybe we can define a local variable scaleFactor and set it to [[UIScreen mainScreen] scale] so it is 1 for standard resolution and 2 if it is retina, so our x and y will always be x * scaleFactor, y * scaleFactor instead of just x and y when we draw using CGContextMoveToPoint, etc.)

如果传递了0.0的比例,似乎UIGraphicsBeginImageContextWithOptions可以自动为Retina创建一个,但是我认为如果需要创建上下文并保留它(并使用ivar或property),则不能使用它UIViewController来保存它).如果我不使用UIGraphicsEndImageContext释放它,那么它将保留在图形上下文堆栈中,因此似乎必须使用CGBitmapContextCreate代替. (或者我们只是让它停留在堆栈的底部而不用担心吗?)

It seems that UIGraphicsBeginImageContextWithOptions can create one for Retina automatically if the scale of 0.0 is passed in, but I don't think it can be used if I need to create the context and keep it (and using ivar or property of UIViewController to hold it). If I don't release it using UIGraphicsEndImageContext, then it stays in the graphics context stack, so it seems like I have to use CGBitmapContextCreate instead. (or do we just let it stay at the bottom of the stack and not worry about it?)

推荐答案

进行了更多研究之后,我发现了以下解决方案:

After doing more research, I found the following solution:

如果必须使用CGBitmapContextCreate,则有两个步骤可以使上下文具有适合标准显示或视网膜显示的尺寸和坐标系:

If you have to use CGBitmapContextCreate, then there are two steps that can make the context with a size and coordinate system tailored to a standard display or Retina display:

float scaleFactor = [[UIScreen mainScreen] scale];

CGSize size = CGSizeMake(768, 768);

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

CGContextRef context = CGBitmapContextCreate(NULL, 
                           size.width * scaleFactor, size.height * scaleFactor, 
                           8, size.width * scaleFactor * 4, colorSpace, 
                           kCGImageAlphaPremultipliedFirst);

CGContextScaleCTM(context, scaleFactor, scaleFactor);

该示例将创建一个768 x 768 point 区域,在The New iPad上,它将为1536 x 1536 pixels .在iPad 2上,它是768 x 768 像素 .

The sample is to create a 768 x 768 point region, and on The New iPad, it will be 1536 x 1536 pixel. On iPad 2, it is 768 x 768 pixel.

一个关键因素是,CGContextScaleCTM(context, scaleFactor, scaleFactor);用于调整坐标系,因此无论是标准分辨率还是Retina分辨率,Core Graphics的任何图形(例如CGContextMoveToPoint等)都将自动工作.

A key factor is that, CGContextScaleCTM(context, scaleFactor, scaleFactor); is used to adjust the coordinate system, so that any drawing by Core Graphics, such as CGContextMoveToPoint, etc, will automatically work, no matter it is standard resolution or the Retina resolution.

还有一点要注意的是,UIGraphicsBeginImageContext(CGSizeMake(300, 300));将在Retina显示屏上创建300 x 300 像素 ,而UIGraphicsBeginImageContextWithOptions(CGSizeMake(300, 300), NO, 0.0);将创建600 x 600 像素 . 0.0用于方法调用,以自动为标准显示或视网膜显示提供合适的大小.

One more note is that UIGraphicsBeginImageContext(CGSizeMake(300, 300)); will create a 300 x 300 pixel on Retina display, while UIGraphicsBeginImageContextWithOptions(CGSizeMake(300, 300), NO, 0.0); will create 600 x 600 pixel on the Retina display. The 0.0 is for the method call to automatically give the proper size for standard display or Retina display.

这篇关于如何创建一个CGBitmapContext用于视网膜显示并且不浪费空间用于常规显示?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆