Я загружаю jpg и png с помощью NSURLRequest. Это работает нормально, но иногда файлы повреждены. Я видел Catching error: Corrupt JPEG data: premature end of data segment и у меня это работает для jpg. Кто-нибудь знает способ сделать то же самое для pngs? т.е. программно проверить, действительны ли данные png ...Обнаружить, если файл PNG поврежден в Objective C
ответ
Формат 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. На практике это крайне маловероятно).
Так же, как и в Catching error: Corrupt JPEG data: premature end of data segment здесь есть фрагмент кода для 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);
}
Nicer версия 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);
}
Если использовать memcmp – jjxtra