Example #1
0
        /// <summary>
        ///     The make image header chunk.
        /// </summary>
        private void MakeImageHeaderChunk()
        {
            this.m_ihdrChunk = new PngChunk(PngChunkIhdr);
            var ihdrData = new byte[13];

            NetworkOrderBitConverter.GetBytes((uint)this.m_imageWidth, ihdrData, 0);
            NetworkOrderBitConverter.GetBytes((uint)this.m_imageHeight, ihdrData, 4);
            ihdrData[8] = 8; // Bits per channel
            ihdrData[9] = 2; // Colour model - RGB
            this.m_ihdrChunk.SetData(ihdrData);
        }
Example #2
0
        /// <summary>
        /// Set the pixel data from which to generate this PNG as Color values.
        /// </summary>
        /// <param name="pixels">
        /// And array of Color values. This is assumed to contain
        ///     Width*Height pixels, where Width and Height are the values passed in at
        ///     construction.
        /// </param>
        public void SetPixelColorData(Color[] pixels)
        {
            // ADLER32 counters
            // This turns out to be relative expensive, which is a PITA, since it's pretty much
            // pointless in a PNG. This is something PNG inherits as a result of using the ZLIB
            // spec. In ZLIB it serves a purpose. But in PNG, all chunks have a CRC32, so the
            // data ends up being protected by both a CRC32 and an ADLER32. Last time I measured,
            // the CRC32 was taking about 20% of the CPU time, and 50% is spent in the loop
            // right here.
            // Tauntingly, if you just crop the pixel data chunk so it's too short to contain the
            // ADLER32, neither Silverlight nor WPF complain. (Not when I wrote this anyway.) And
            // it speeds things up a fair bit. But I don't want to depend on that.
            uint s1         = 1;
            uint s2         = 0;
            int  adlerCount = 0;

            for (int row = 0; row < this.m_imageHeight; ++row)
            {
                int    rowTargetOffset = row * (this.m_imageWidth * 3 + 1);
                int    rowSourceOffset = row * this.m_imageWidth;
                double rowRatio        = row / (double)this.m_imageHeight;

                // Each row starts with a 0, indicating the non-transforming filter -
                // this lets us write raw pixel data.
                // We don't write the value out - the image size is fixed, so these things
                // never move in the array, and they always keep their initial 0 value. But
                // We do need to accumulate it for the ADLER32 check
                s2          = s2 + s1; // No need to add to s1 - this is a zero byte value.
                adlerCount += 1;

                int pos = rowTargetOffset + 1;
                for (int column = 0; column < this.m_imageWidth; ++column)
                {
                    Color col = pixels[rowSourceOffset + column];

                    // Nasty duplicated code. But when I had it all nicely factored
                    // out, it was causing serious slowdowns (order of 20%), and we're
                    // inside the critical loop here.
                    // Note, the weird calculation was originally factored out into
                    // MapPixelDataOffset. Its job is to deal with the fact that even
                    // when we disable compression, we still have to insert a 5 byte
                    // deflate block header every 0xffff bytes.
                    byte v = col.R;
                    this.pngPixelData[pos + (pos / 0xffff) * 5 + 7] = v;
                    pos += 1;
                    s1   = s1 + v;
                    s2   = s2 + s1;

                    v = col.G;
                    this.pngPixelData[pos + (pos / 0xffff) * 5 + 7] = v;
                    pos += 1;
                    s1   = s1 + v;
                    s2   = s2 + s1;

                    v = col.B;
                    this.pngPixelData[pos + (pos / 0xffff) * 5 + 7] = v;
                    pos += 1;
                    s1   = s1 + v;
                    s2   = s2 + s1;

                    // Do we need to reduce  yet?
                    adlerCount += 3;
                    if (adlerCount > 5546)
                    {
                        s1        %= 65521;
                        s2        %= 65521;
                        adlerCount = 0;
                    }
                }
            }

            s1 %= 65521;
            s2 %= 65521;
            uint adler32 = (s2 << 16) + s1;

            NetworkOrderBitConverter.GetBytes(adler32, this.pngPixelData, this.pngPixelData.Length - 4);
            this.m_idatChunk.SetData(this.pngPixelData);
        }