Detect if PNG file is damaged in Objective-C

I upload jpg and png using NSURLRequest. This works fine, but sometimes the files are corrupted. I saw a Detection Error: corrupted JPEG data: premature end of a data segment , and this works for jpg. Does anyone know a way to do the same for pngs? those. programmatically check if png data is valid ...

+4
source share
3 answers

The PNG format has several built-in checks. Each "piece" has a CRC32 check, but to verify that you will need to read the full file.

A simpler check (of course, not reliable) should be to read the beginning and end of the file.

The first 8 bytes should always be the following (decimal) values { 137, 80, 78, 71, 13, 10, 26, 10 } ( ref ). In particular, bytes from the second to the fourth correspond to the ASCII string "PNG".

In hexadecimal format:

 89 50 4e 47 0d 0a 1a 0a .. PNG ........... 

You can also check the last 12 bytes of the file (IEND chunk). The middle 4 bytes must match the ASCII string "IEND". More specifically, the last 12 bytes should be (in hexa):

 00 00 00 00 49 45 4e 44 ae 42 60 82 ........... IEND ........... 

(Strictly speaking, it is not necessary for the PNG file to end these 12 bytes, the IEND block itself indicates the end of the PNG stream, and therefore the file can, in principle, have additional bytes that will be ignored by the PNG reader. In practice, this is extremely unlikely).

+7
source

Same as in Detection Error: Corrupt JPEG data: the premature end of the data segment is a piece of code for 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); } 
+1
source

A cleaner version of dataIsValidPNG:

 BOOL dataIsValidPNG(NSData *data) { if (!data) { return NO; } const NSInteger totalBytes = data.length; const char *bytes = (const char *)[data bytes]; const char start[] = { '\x89', 'P', 'N', 'G', '\r', '\n', '\x1a', '\n' }; const char end[] = { '\0', '\0', '\0', '\0', 'I', 'E', 'N', 'D', '\xAE', 'B', '`', '\x82' }; if (totalBytes < (sizeof(start) + sizeof(end))) { return NO; } return (memcmp(bytes, start, sizeof(start)) == 0) && (memcmp(bytes + (totalBytes - sizeof(end)), end, sizeof(end)) == 0); } 
0
source

All Articles