Проверка PNG на iOS - PullRequest
       50

Проверка PNG на iOS

2 голосов
/ 26 июля 2011

Создание картографического приложения на iOS с использованием плиток OpenStreetMap. Изображения листов карты загружаются асинхронно и сохраняются в словаре или сохраняются в БД SQLite.

Иногда, по какой-либо причине, при попытке отобразить изображение плитки карты я получаю следующую ошибку:
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

Ответы [ 4 ]

2 голосов
/ 28 мая 2013

Я нашел это в другом вопросе и соединил, что решило проблему для меня.Надеюсь, вы найдете это полезным.

Формат PNG имеет несколько встроенных проверок.Каждый «чанк» имеет проверку CRC32, но для проверки того, что вам нужно прочитать полный файл.

Более простой проверкой (конечно, не надежной) будет считывание начала и конца проверки.file.

Первые 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);
}
1 голос
/ 18 января 2019

Я знаю, что это супер старый поток, но я искал расширение NSData, которое фактически проверяло crc32 в кусках данных PNG. Не найдя его, я адаптировал его из другого источника.

Это на самом деле помечает плохие PNG CRC, что не выполняется (шокирующе) большинством библиотек изображений

static const unsigned int datacrc32_table[256] =
{
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
0x2d02ef8d
};

unsigned int
datacrc32 (unsigned int crc, unsigned char *buf, int len)
{
unsigned char *end;

crc = ~crc;
for (end = buf + len; buf < end; ++buf)
    crc = datacrc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
return ~crc;
}



-(BOOL)isCRCValidPNG {

char chnk [5];
int l = 0;
int size = (int)[self length];
unsigned int crc = 0;
unsigned char c;
unsigned int csum = 0;
unsigned char b;

unsigned char *tileBytes = (unsigned char *)[self bytes];

if (self.length > 8){
    const unsigned char pngHeaderBytes[] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };

    for (int i = 0 ; i < 8 ; ++i){
        if (tileBytes[i] != pngHeaderBytes[i])
            return NO;

    }

}

// process chunks
int bytePtr = 8;

strcpy (chnk, "");
do
{
    // get chunk size

    if (bytePtr+4 > size)
        return NO;

    l = 0;
    for (int i = 0; i < 4; i++)
    {
        l = (l << 8) + tileBytes[bytePtr++];
    }

    printf("l is %08x",l);

    // get chunk name
    crc = 0;
    strcpy (chnk, "");

    if (bytePtr+4 > size)
        return NO;

    for (int i = 0; i < 4; i++)
    {
        c = tileBytes[bytePtr++];
        crc = datacrc32 (crc, &c, 1);
        chnk[i] = (char) c;
    }
    chnk[4] = '\0';

    printf ("%s (%3d )", chnk, l);

    //  chunk data
    if (bytePtr+l > size)
        return NO;

    for (int i = 0; i < l; i++)
    {
        c = tileBytes[bytePtr++];
        crc = datacrc32 (crc, &c, 1);
    }

    //  checksum
    csum = 0;
    if (bytePtr+4 > size)
        return NO;

    for (int i = 0; i < 4; i++)
    {
        c = tileBytes[bytePtr++];
        csum = (csum << 8) + (int) c;

        b = (unsigned char) ((crc >> 8 * (3 - i)) & 0xFF);
        // printf ("b = %02x\n", b);

    }

    if (crc == csum)
        NSLog(@"Chunk %s validated",chnk);
    else
        NSLog(@"chunk %s invalid ",chnk);

    if (crc != csum)
        return NO;

}
while (strcmp (chnk, "IEND") != 0);

return YES;

}
0 голосов
/ 08 августа 2018
The Swift Version
func checkPNGImageDataFormat(_ imageData:Data) -> Bool
    {
        //More expensive since it has to go through entire data
        //Check entire header magic number and IEND trailer in PNG data
        var status:Bool = true
        if(imageData.count < 12)
        {
            return false
        }
        let totalBytes = imageData.count
        let bytes = imageData.withUnsafeBytes {
            [UInt8](UnsafeBufferPointer(start: $0, count: totalBytes))
        }
        let header:Bool = bytes[0] == 0x89 && bytes[1] == 0x50 && bytes[2] == 0x4e && bytes[3] == 0x47 && bytes[4] == 0x0d && bytes[5] == 0x0a  && bytes[6] == 0x1a && bytes[7] == 0x0a

        let iend:Bool = bytes[totalBytes - 12] == 0x00 && bytes[totalBytes - 11] == 0x00 && bytes[totalBytes - 10] == 0x00 && bytes[totalBytes - 9] == 0x00 && bytes[totalBytes - 8] == 0x49 && bytes[totalBytes - 7] == 0x45 && bytes[totalBytes - 6] == 0x4e && bytes[totalBytes - 5] == 0x44 && bytes[totalBytes - 4] == 0xae && bytes[totalBytes - 3] == 0x42 && bytes[totalBytes - 2] == 0x60 && bytes[totalBytes - 1] == 0x82

        status = header && iend
        return status
    }
0 голосов
/ 02 августа 2011

Перешел с моего собственного диспетчера очереди асинхронной загрузки на реализацию All Seeing I.Проблема стала спорным вопросом.

...