Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How is PNG CRC calculated exactly?

Tags:

c#

png

crc

crc32

For the past 4 hours I've been studying the CRC algorithm. I'm pretty sure I got the hang of it already.

I'm trying to write a png encoder, and I don't wish to use external libraries for the CRC calculation, nor for the png encoding itself.

My program has been able to get the same CRC's as the examples on tutorials. Like on Wikipedia: enter image description here

Using the same polynomial and message as in the example, I was able to produce the same result in both of the cases. I was able to do this for several other examples as well.

However, I can't seem to properly calculate the CRC of png files. I tested this by creating a blank, one pixel big .png file in paint, and using it's CRC as a comparision. I copied the data (and chunk name) from the IDAT chunk of the png (which the CRC is calculated from), and calculated it's CRC using the polynomial provided in the png specification.

The polynomial provided in the png specification is the following:

x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1

Which should translate to:

1 00000100 11000001 00011101 10110111

Using that polynomial, I tried to get the CRC of the following data:

01001001 01000100 01000001 01010100
00011000 01010111 01100011 11101000
11101100 11101100 00000100 00000000
00000011 00111010 00000001 10011100

This is what I get:

01011111 11000101 01100001 01101000 (MSB First)
10111011 00010011 00101010 11001100 (LSB First)

This is what is the actual CRC:

11111010 00010110 10110110 11110111

I'm not exactly sure how to fix this, but my guess would be I'm doing this part from the specification wrong:

In PNG, the 32-bit CRC is initialized to all 1's, and then the data from each byte is processed from the least significant bit (1) to the most significant bit (128). After all the data bytes are processed, the CRC is inverted (its ones complement is taken). This value is transmitted (stored in the datastream) MSB first. For the purpose of separating into bytes and ordering, the least significant bit of the 32-bit CRC is defined to be the coefficient of the x31 term.

I'm not completely sure I can understand all of that.

Also, here is the code I use to get the CRC:

 public BitArray GetCRC(BitArray data)
    {
        // Prepare the divident; Append the proper amount of zeros to the end
        BitArray divident = new BitArray(data.Length + polynom.Length - 1);
        for (int i = 0; i < divident.Length; i++)
        {
            if (i < data.Length)
            {
                divident[i] = data[i];
            }
            else
            {
                divident[i] = false;
            }
        }

        // Calculate CRC
        for (int i = 0; i < divident.Length - polynom.Length + 1; i++)
        {
            if (divident[i] && polynom[0])
            {
                for (int j = 0; j < polynom.Length; j++)
                {
                    if ((divident[i + j] && polynom[j]) || (!divident[i + j] && !polynom[j]))
                    {
                        divident[i + j] = false;
                    }
                    else
                    {
                        divident[i + j] = true;
                    }
                }
            }
        }

        // Strip the CRC off the divident
        BitArray crc = new BitArray(polynom.Length - 1);
        for (int i = data.Length, j = 0; i < divident.Length; i++, j++)
        {
            crc[j] = divident[i];
        }
        return crc;
    }

So, how do I fix this to match the PNG specification?

like image 280
MythicManiac Avatar asked Jun 06 '14 12:06

MythicManiac


People also ask

How is CRC value calculated?

The theory of a CRC calculation is straight forward. The data is treated by the CRC algorithm as a binary num- ber. This number is divided by another binary number called the polynomial. The rest of the division is the CRC checksum, which is appended to the transmitted message.

How is CRC manually calculated?

A CRC is pretty simple; you take a polynomial represented as bits and the data, and divide the polynomial into the data (or you represent the data as a polynomial and do the same thing). The remainder, which is between 0 and the polynomial is the CRC.

What is CRC in PNG file?

Each chunk in a PNG image is verified for corrupted data using a CRC32 checksum, where CRC stands for Cyclic Redundancy Checksum. Check out the PNG Specification at W3C for more details on how the checksum is constructed.

How is CRC 16 bit calculated?

Step-01: Calculation Of CRC At Sender Side-A string of n 0's is appended to the data unit to be transmitted. Here, n is one less than the number of bits in CRC generator. Binary division is performed of the resultant string with the CRC generator. After division, the remainder so obtained is called as CRC.


1 Answers

You can find a complete implementation of the CRC calculation (and PNG encoding in general) in this public domain code:

static uint[] crcTable;

// Stores a running CRC (initialized with the CRC of "IDAT" string). When
// you write this to the PNG, write as a big-endian value
static uint idatCrc = Crc32(new byte[] { (byte)'I', (byte)'D', (byte)'A', (byte)'T' }, 0, 4, 0);

// Call this function with the compressed image bytes, 
// passing in idatCrc as the last parameter
private static uint Crc32(byte[] stream, int offset, int length, uint crc)
{
    uint c;
    if(crcTable==null){
        crcTable=new uint[256];
        for(uint n=0;n<=255;n++){
            c = n;
            for(var k=0;k<=7;k++){
                if((c & 1) == 1)
                    c = 0xEDB88320^((c>>1)&0x7FFFFFFF);
                else
                    c = ((c>>1)&0x7FFFFFFF);
            }
            crcTable[n] = c;
        }
    }
    c = crc^0xffffffff;
    var endOffset=offset+length;
    for(var i=offset;i<endOffset;i++){
        c = crcTable[(c^stream[i]) & 255]^((c>>8)&0xFFFFFF);
    }
    return c^0xffffffff;
}

1 https://web.archive.org/web/20150825201508/http://upokecenter.dreamhosters.com/articles/png-image-encoder-in-c/

like image 97
EricLaw Avatar answered Nov 02 '22 01:11

EricLaw