如何创建一个CGBitmapContext用于视网膜显示并且不浪费空间用于常规显示? [英] How to create a CGBitmapContext which works for Retina display and not wasting space for regular display?
问题描述
是否真的在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
用作缓冲区,从而使
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 * 2
和y * 2
,而不是仅使用x, y
的非视网膜显示也可以?对于代码来说,这可能是很混乱的. (或者也许我们可以定义局部变量scaleFactor
并将其设置为[[UIScreen mainScreen] scale]
,因此对于标准分辨率,该值为1,如果是视网膜,则为2,因此我们的x
和y
始终为x * scaleFactor
,y * scaleFactor
,而不仅仅是使用CGContextMoveToPoint
等绘制的x
和y
)
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屋!