2011-07-26 29 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); 
}