在 Retina 显示屏上的 CGContextRef 上绘画

Posted

技术标签:

【中文标题】在 Retina 显示屏上的 CGContextRef 上绘画【英文标题】:Painting on CGContextRef on Retina display 【发布时间】:2013-07-14 08:44:11 【问题描述】:

在我的应用程序中,我有一个主视图(带有 UIGraphicsGetCurrentContext())和其他几个 CGContextRef 画布。所有这些都是相同的大小,屏幕的大小 - 没有比例因子。

我在辅助画布上绘制,最后在辅助画布上使用 CGBitmapContextCreateImage 并在主画布上使用 CGContextDrawImage 绘制。

在视网膜显示器上显示效果很差,所有线条看起来都像素化了。 我应该如何处理视网膜显示器上的绘画?

以下是我用来在主上下文中绘制上下文的代码:

void CocoaGraphicsContext::drawContext(GraphicsContext* context, double x, double y, Box* cropBox, Matrix3D* matrix)

    CGAffineTransform matInverted;

    if (matrix != NULL)
    
        CGAffineTransform transMat = CGAffineTransformMake(matrix->vx1, matrix->vy1, matrix->vx2, matrix->vy2, matrix->tx, matrix->ty);
        matInverted = CGAffineTransformInvert(transMat);

        CGContextConcatCTM(_cgContext, transMat);
    

    CGImageRef cgImage = CGBitmapContextCreateImage(((CocoaGraphicsContext*)context)->cgContext());

    CGContextSaveGState(_cgContext);
    CGContextSetInterpolationQuality(_cgContext, kCGInterpolationNone);

    bool shouldCrop = ((cropBox != NULL) && (cropBox->valid()));

    if (shouldCrop)
    
        CGContextClipToRect(_cgContext, CGRectMake(cropBox->x(), cropBox->y(), cropBox->width(), cropBox->height()));
    

    CGContextDrawImage(_cgContext, CGRectMake(x, y, context->width(), context->height()), cgImage);

    CGContextRestoreGState(_cgContext);

    CGImageRelease(cgImage);

    if (matrix != NULL)
    
        CGContextConcatCTM(_cgContext, matInverted);
    

使用 UIView 类中的 UIGraphicsGetCurrentContext() 获取主要上下文

---- 已编辑 --- 初始化代码:

void CocoaBitmapContext::init(double width, double height, unsigned int* data)

    int bytesPerRow = width * 2  * VT_BITMAP_BYTES_PER_PIXEL;

    if (data == NULL)
    
        _dataOwner = true;
        _data = (unsigned int*)malloc(bytesPerRow * height * 2);
    
    else
    
        _dataOwner = false;
        _data = data;
    

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    _cgContext = CGBitmapContextCreate(_data,
                                       width * 2,
                                       height * 2,
                                       VT_BITMAP_BITS_PER_COMPONENT,
                                       bytesPerRow,
                                       colorSpace,
                                       kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little);

    CGContextConcatCTM(_cgContext, CGAffineTransformMakeScale([UIScreen mainScreen].scale, [UIScreen mainScreen].scale));

    CGContextSetShouldAntialias(_cgContext, false);
    CGContextSetRGBStrokeColor(_cgContext, 0.0, 0.0, 0.0, 0.0);

    CGColorSpaceRelease(colorSpace);

【问题讨论】:

使用 UIGraphicsGetCurrentContext() 获得的上下文已经被缩放。您应该手动缩放您创建的那些。如果可能的话,我建议你使用 CGBitmapContextGetWidth() 和 CGBitmapContextGetHeight() 来获取主要上下文的尺寸,并使用这些尺寸来创建所有其他上下文。 我认为您不需要在此处更改任何内容,除非您可以使用 CGContextSaveGState() 和 CGContextRestoreGState() 来恢复 CTM。 我可能需要在某处改变一些东西,因为目前它看起来像素化了 除了主上下文之外,你如何创建上下文? _cgContext = CGBitmapContextCreate(_data, width, height, VT_BITMAP_BITS_PER_COMPONENT, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little); 【参考方案1】:

位图大小以像素为单位,而屏幕上的大小以磅为单位。您可以使用[UIScreen mainScreen].scale 获取屏幕的比​​例因子。那就是一个点中有多少个像素。对于具有 Retina 显示器的设备,该值将为 2。您需要按该因子缩放画布的大小。您还应该在创建上下文后立即连接比例变换。绘制图像时,仍应使用屏幕边界作为目标矩形(缩放变换负责缩放)。

CGSize canvasSize = [UIScreen mainScreen].bounds.size;
CGFloat scale = [UIScreen mainScreen].scale;
canvasSize.width *= scale;
canvasSize.height *= scale;

UIGraphicsBeginImageContext(canvasSize);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextConcatCTM(context, CGAffineTransformMakeScale(scale, scale));
...
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

如果您要在图像视图中显示它,图像视图应该填满屏幕,它的contentMode 应该是UIViewContentModeScaleToFill

【讨论】:

请查看我添加到原始问题中的附加信息 - 我不确定我如何在代码中使用比例因子 使用UIGraphicsBeginImageContextWithOptions 并在那里传递比例因子不是更好吗?

以上是关于在 Retina 显示屏上的 CGContextRef 上绘画的主要内容,如果未能解决你的问题,请参考以下文章

使用 Core Graphics 绘图在 Retina 显示屏上看起来很厚实

Retina 图形未从 NSBundle 加载

改进 Retina iPad 上的慢画布动画 - KineticJS

Sprite Kit - 使用 textureFromNode 时 Retina 上的低分辨率纹理

使用 Retina 显示屏在画布上绘制图像

Retina 显示屏中的像素化图像