2

我注意到有些人在 a 上重绘图像CGContext以防止延迟解压缩,这导致了我们的应用程序中的错误。

错误是图像的大小声称保持不变,但CGImageDataProvider数据附加了额外的字节。

比如我们有一个从网上下载的797x500的PNG图片,AsyncImageViewredraws并返回redraw的图片。

这是代码:

UIImage *image = [[UIImage alloc] initWithData:data];
if (image)
{
    // Log to compare size and data length...
    NSLog(@"BEFORE: %f %f", image.size.width, image.size.height);
    NSLog(@"LEN  %ld", CFDataGetLength(CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage))));

    // Original code from AsyncImageView
    //redraw to prevent deferred decompression
    UIGraphicsBeginImageContextWithOptions(image.size, NO, image.scale);
    [image drawAtPoint:CGPointZero];
    image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    // Log to compare size and data length...
    NSLog(@"AFTER:  %f %f", image.size.width, image.size.height);
    NSLog(@"LEN  %ld", CFDataGetLength(CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage))));

    // Some other code...
}

日志显示如下:

BEFORE: 797.000000 500.000000
LEN  1594000
AFTER:  797.000000 500.000000
LEN  1600000

我决定一个一个地打印每个字节,果然0每行都附加了 12 个 s。

基本上,重绘导致图像数据成为 800x500 图像的数据。因此,当我们的应用程序想要查看797 * row + column第 th 个像素时,它正在查看错误的像素。

我们没有使用任何大图像,因此延迟解压不会造成任何问题,但如果我决定使用这种方法重绘图像,我可能会引入一个微妙的错误。

有人对此有解决方案吗?还是这是 Apple 引入的错误,我们真的无能为力?

4

1 回答 1

3

正如您所发现的,行被填充到一个方便的大小。这通常是为了使向量算法更有效。CGImage如果您要使用这种方式,您只需要适应该布局。您需要调用CGImageGetBytesPerRow以找出实际分配的字节数,然后根据该 ( bytesPerRow * row + column) 调整您的偏移量。

这可能对您来说是最好的,但如果您需要摆脱填充,您可以通过创建自己的填充CGBitmapContext并渲染到其中来实现。如果您不熟悉它,那将是 Stack Overflow 的一个被广泛讨论的话题。例如:如何从 UIImage (Cocoa Touch) 或 CGImage (Core Graphics) 获取像素数据?

于 2017-04-28T00:13:20.903 回答