PNG validation on iOS

前端 未结 4 1596
佛祖请我去吃肉
佛祖请我去吃肉 2021-02-11 06:10

Writing a mapping application on iOS, making use of OpenStreetMap tiles. Map tile images are downloaded asynchronously and stored in a dictionary, or persisted in a SQLite DB.

4条回答
  •  挽巷
    挽巷 (楼主)
    2021-02-11 06:26

    I found this in other question and put together what solved the issue for me. Hope you find this helpful.

    The PNG format has several built in checks. Each "chunk" has a CRC32 check, but to check that you'd need to read the full file.

    A more basic check (not foolproof, of course) would be to read the start and ending 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, the bytes second-to-fourth correspond to the ASCII string "PNG".

    In hexadecimal:

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

    You can also check the last 12 bytes of the file (IEND chunk). The middle 4 bytes should correspond to 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
    ........... I  E  N  D  ...........
    

    (Strictly speaking, it's not really obligatory for a PNG file to end with those 12 bytes, the IEND chunk itself signals the end of the PNG stream and so a file could in principle have extra trailing bytes which would be ignored by the PNG reader. In practice, this is extremely improbable).

    Here is an implementation:

    - (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);
    }
    

提交回复
热议问题