2011-07-26 34 views
2

在iOS上编写地图应用程序,使用OpenStreetMap切片。 地图平铺图像被异步下载并存储在字典中,或者保存在SQLite数据库中。iOS上的PNG验证

有时候,不管出于什么原因,而为了显示地图平铺图像,我得到以下错误:
ImageIO: <ERROR> PNGinvalid distance too far back

这将导致讨厌的黑方块出现在我的地图。

这是一段代码,在发生这种情况:

NSData *imageData = [TileDownloader RetrieveDataAtTileX:(int)tilex Y:(int)tiley Zoom:(int)zoomLevel]; 
if (imageData != nil) { 
    NSLog(@"Obtained image data\n"); 
    UIImage *img = [[UIImage imageWithData:imageData] retain]; 
    // Perform the image render on the current UI context. 
    // ERROR OCCURS BETWEEN PUSH AND POP 
    UIGraphicsPushContext(context); 
    [img drawInRect:[self rectForMapRect:mapRect] blendMode:kCGBlendModeNormal alpha:1.0f]; 
    UIGraphicsPopContext(); 
    [img release]; 
} 

现在,我正在寻找一种方法来确保PNG是试图使它对我的地图之前有效。

编辑:该系统还偶尔会抛出这个错误:
ImageIO: <ERROR> PNGIDAT: CRC error

+0

你得到一个UIImage对象回来的时候发生这种情况?我希望'img'是'nil',这是你的有效验证。 – Tommy

+0

那么,鉴于我正在加载原始数据,并且它抛出了一个PNG错误,我怀疑UIImage对象是建立的,但其包含的数据是问题。 –

+0

我认为'+ imageWithData:'会更容易发现错误并返回'nil'。如果你已经测试过,那不是那么公平,但我真的认为你应该测试它。 – Tommy

回答

0

从我自己的异步下载队列管理器切换到全看我的实现。问题成为一个有争议的问题。

2

我在其他问题中发现了这个问题,并将它们放在一起解决了我的问题。希望你觉得这有帮助。

PNG格式有几个内置的检查。每个“块”都有CRC32检查,但要检查是否需要读取完整文件。

一个更基本的检查(当然不是简单的)将是读取文件的开始和结束。

前8个字节应始终为以下(十进制)值{137,80,78,71,13,10,26,10}(ref)。特别是,第二到第四字节对应于ASCII字符串“PNG”。

在十六进制:

89 50 4e 47 0d 0a 1a 0a 
.. P N G ........... 

您还可以查看过去的12个字节的文件(IEND块)的。中间的4个字节应对应于ASCII字符串“IEND”。更具体地说,过去的12个字节应该是(在六):

00 00 00 00 49 45 4e 44 ae 42 60 82 
........... I E N D ........... 

(严格地说,它是一个PNG文件,以结束与这12个字节没有真正必须的,在IEND块本身信号的PNG流的末尾所以一个文件原则上可能会有额外的后续字节,PNG阅读器会忽略这些字节,实际上这是非常不可能的)。

这是一个实现:

- (BOOL)dataIsValidPNG:(NSData *)data 
{ 
    if (!data || data.length < 12) 
    { 
     return NO; 
    } 

    NSInteger totalBytes = data.length; 
    const char *bytes = (const char *)[data bytes]; 

    return (bytes[0] == (char)0x89 && // PNG 
      bytes[1] == (char)0x50 && 
      bytes[2] == (char)0x4e && 
      bytes[3] == (char)0x47 && 
      bytes[4] == (char)0x0d && 
      bytes[5] == (char)0x0a && 
      bytes[6] == (char)0x1a && 
      bytes[7] == (char)0x0a && 

      bytes[totalBytes - 12] == (char)0x00 && // IEND 
      bytes[totalBytes - 11] == (char)0x00 && 
      bytes[totalBytes - 10] == (char)0x00 && 
      bytes[totalBytes - 9] == (char)0x00 && 
      bytes[totalBytes - 8] == (char)0x49 && 
      bytes[totalBytes - 7] == (char)0x45 && 
      bytes[totalBytes - 6] == (char)0x4e && 
      bytes[totalBytes - 5] == (char)0x44 && 
      bytes[totalBytes - 4] == (char)0xae && 
      bytes[totalBytes - 3] == (char)0x42 && 
      bytes[totalBytes - 2] == (char)0x60 && 
      bytes[totalBytes - 1] == (char)0x82); 
}