Contains an indexed array of Colors to be used by images with ColorType 3 and possibly ColorTypes 2 and 6.
예제 #1
0
        /// <summary>
        /// Does the remaining work to convert the byte[] containing the image into a Color[] containing colors
        /// for each pixel. This operation is different for most individual combinations of ColorType and bitDepth 
        /// and currently only ColorType 2 is supported.
        /// </summary>
        /// <param name="image"></param>
        /// <param name="header"></param>
        /// <param name="palette"></param>
        /// <returns></returns>
        private static Color[] BuildPixels(byte[] image, ref HeaderInfo header, ref PaletteInfo palette)
        {
            //System.Diagnostics.Trace.WriteLine(String.Format("ColorType: {0}\tBitDepth: {1}", header.ColorType, header.BitDepth));
           // System.Diagnostics.Trace.WriteLine(String.Format("Width: {0}\tHeight: {1}", header.Width, header.Height));

            int totalPixels = (int)(header.Width * header.Height);
            int currentIndex = 0;

            if (totalPixels > mStaticPixels.Length)
            {
                mStaticPixels = new Color[totalPixels];
            }


            //MemoryStream imageStream = new MemoryStream(image);
            int indexInImage = 0;

            int filterByte;

            switch ((int)header.ColorType)
            {
                //Each pixel is an R,G,B triple
                case 2:
                    {
                        //This section of code containing conversion of 16-bit samples is currently untested.
                        if (header.BitDepth > 8)
                        {
                            int bps = (int)(header.Width * header.BitDepth * 3 + 1);
                            //int R = 0;
                            //int G = 0;
                            //int B = 0;
                            while ((filterByte = image[indexInImage++]) > -1 && currentIndex < totalPixels)
                            {
                                for (int i = 0; i < header.Width; ++i)
                                {
                                    mStaticPixels[currentIndex].R = image[indexInImage++]; indexInImage++;
                                    mStaticPixels[currentIndex].G = image[indexInImage++]; indexInImage++;
                                    mStaticPixels[currentIndex].B = image[indexInImage++]; indexInImage++;
                                    mStaticPixels[currentIndex].A = byte.MaxValue;
                                    currentIndex++;
                                }
                            }

                        }
                        else
                        {
                            while ((filterByte = image[indexInImage++]) > -1 && currentIndex < totalPixels)
                            {
                                for (int i = 0; i < header.Width; ++i)
                                {
                                    mStaticPixels[currentIndex].R = image[indexInImage++];
                                    mStaticPixels[currentIndex].G = image[indexInImage++];
                                    mStaticPixels[currentIndex].B = image[indexInImage++];
                                    mStaticPixels[currentIndex].A = byte.MaxValue;
                                    currentIndex++;
                                }
                            }
                        }
                        break;
                    }

                //Each pixel is a grayscale sample
                case 0:
                    {

                        if (header.BitDepth < 8)
                        {
                            byte sample;
                            int value;
                            float grayValue;
                            int numBits = 8 / header.BitDepth;
                            int mask = (255 >> (8 - header.BitDepth));
                            while ((filterByte = image[indexInImage++]) > -1 && currentIndex < totalPixels)
                            {
                                for (int i = 0; i < header.Width / numBits; ++i)
                                {
                                    value = image[indexInImage++];
                                    for (int j = 8 - header.BitDepth; j >= 0; j -= header.BitDepth)
                                    {
                                        grayValue = (float)((value & (mask << j)) >> j);
                                        sample = (byte)((grayValue / ((1 << header.BitDepth) - 1)) * 255);
                                        mStaticPixels[currentIndex].R = sample;
                                        mStaticPixels[currentIndex].G = sample;
                                        mStaticPixels[currentIndex].B = sample;
                                        mStaticPixels[currentIndex].A = byte.MaxValue;
                                        currentIndex++;
                                    }
                                }
                            }

                        }
                        else if (header.BitDepth == 8)
                        {
                            byte sample;
                            float value;

                            //Get the filter byte out of the way
                            while ((filterByte = image[indexInImage++]) > -1 && currentIndex < totalPixels)
                            {
                                //Read the scanline
                                for (int i = 0; i < header.Width; ++i)
                                {
                                    value = (float)(image[indexInImage++]);
                                    sample = (byte)((value / ((1 << header.BitDepth) - 1)) * 255);
                                    mStaticPixels[currentIndex].R = sample;
                                    mStaticPixels[currentIndex].G = sample;
                                    mStaticPixels[currentIndex].B = sample;
                                    mStaticPixels[currentIndex].A = byte.MaxValue;
                                    currentIndex++;
                                }
                            }
                        }

                        else
                        {
                            byte sample;
                            while ((filterByte = image[indexInImage++]) > -1 && currentIndex < totalPixels)
                            {
                                for (int i = 0; i < header.Width; ++i)
                                {
                                    sample = image[indexInImage++]; indexInImage++;
                                    mStaticPixels[currentIndex].R = sample;
                                    mStaticPixels[currentIndex].G = sample;
                                    mStaticPixels[currentIndex].B = sample;
                                    mStaticPixels[currentIndex].A = byte.MaxValue;
                                    currentIndex++;
                                }
                            }
                        }

                        break;
                    }

                //Each pixel is a palette index
                case 3:
                    {
                        RGB entry;
                        int value;
                        int numBits = 8 / header.BitDepth;
                        int mask = (255 >> (8 - header.BitDepth));
                        int index;

                        long headerWidthDividedByNumBits = header.Width / numBits;

                        while ((filterByte = image[indexInImage++]) > -1 && currentIndex < totalPixels)
                        {
                            for (int i = 0; i < headerWidthDividedByNumBits; ++i)
                            {
                                value = image[indexInImage++];
                                for (int j = 8 - header.BitDepth; j >= 0; j -= header.BitDepth)
                                {
                                    index = (value & (mask << j)) >> j;
                                    entry = palette.Entries[index];
                                    mStaticPixels[currentIndex].R = entry.R;
                                    mStaticPixels[currentIndex].G = entry.G;
                                    mStaticPixels[currentIndex].B = entry.B;

                                    //if (mMaxTransIndex >= index)
                                    {
                                        mStaticPixels[currentIndex].A = mTransparentEntries[index];
                                    }
                                    currentIndex++;
                                }
                            }
                        }
                        break;
                    }

                //Each pixel is a grayscale sample, followed by an alpha sample
                case 4:
                    {
                        switch ((int)header.BitDepth)
                        {
                            case 8:
                                {
                                    //Open stream to image array
                                    byte sample;

                                    //Get the filter byte out of the way
                                    while ((filterByte = image[indexInImage++]) > -1 && currentIndex < totalPixels)
                                    {
                                        //Read the scanline
                                        for (int i = 0; i < header.Width; ++i)
                                        {
                                            sample = image[indexInImage++];
                                            mStaticPixels[currentIndex].R = sample;
                                            mStaticPixels[currentIndex].G = sample;
                                            mStaticPixels[currentIndex].B = sample;
                                            mStaticPixels[currentIndex].A = image[indexInImage++];
                                            currentIndex++;
                                        }
                                    }

                                    break;
                                }

                            case 16:
                                {
                                    byte sample;
                                    while ((filterByte = image[indexInImage++]) > -1 && currentIndex < totalPixels)
                                    {
                                        for (int i = 0; i < header.Width; ++i)
                                        {
                                            sample = image[indexInImage++]; indexInImage++;
                                            mStaticPixels[currentIndex].R = sample;
                                            mStaticPixels[currentIndex].G = sample;
                                            mStaticPixels[currentIndex].B = sample;
                                            mStaticPixels[currentIndex].A = image[indexInImage++]; 
                                            indexInImage++;
                                            currentIndex++;
                                        }
                                    }

                                    break;
                                }
                        }
                        break;
                    }

                //Each pixel is an R,G,B triple, followed by an alpha sample
                case 6:
                    {
                        switch ((int)header.BitDepth)
                        {
                            case 8:
                                {
                                    while ((filterByte = image[indexInImage++]) > -1 && currentIndex < totalPixels)
                                    {
                                        for (int i = 0; i < header.Width; ++i)
                                        {
                                            mStaticPixels[currentIndex].R = image[indexInImage++];
                                            mStaticPixels[currentIndex].G = image[indexInImage++];
                                            mStaticPixels[currentIndex].B = image[indexInImage++];
                                            mStaticPixels[currentIndex].A = image[indexInImage++];

                                            currentIndex++;
                                        }
                                    }
                                    break;
                                }

                            case 16:
                                {
                                    int bps = (int)(header.Width * header.BitDepth * 3 + 1);
                                    //int R = 0;
                                    //int G = 0;
                                    //int B = 0;
                                    //int A = 0;
                                    while ((filterByte = image[indexInImage++]) > -1 && currentIndex < totalPixels)
                                    {
                                        for (int i = 0; i < header.Width; ++i)
                                        {
                                            mStaticPixels[currentIndex].R = image[indexInImage++]; indexInImage++;
                                            mStaticPixels[currentIndex].G = image[indexInImage++]; indexInImage++;
                                            mStaticPixels[currentIndex].B = image[indexInImage++]; indexInImage++;
                                            mStaticPixels[currentIndex].A = image[indexInImage++]; indexInImage++;

                                            currentIndex++;
                                        }
                                    }

                                    break;
                                }
                        }
                        break;
                    }

            }
            //imageStream.Close();
            return mStaticPixels;
        }
예제 #2
0
        /// <summary>
        /// Takes a List of all of the Chunks in the .png image being loaded (after IHDR is loaded and removed) 
        /// and processes each Chunk appropriately before returning the compressed image. NOTE: Currently only 
        /// processes the required Chunks PLTE, IDAT and IEND. Ancillary chunks are currently unsupported.
        /// </summary>
        /// <param name="chunks">The List of chunks loaded from the .png image file</param>
        /// <param name="header">The HeaderInfo loaded from the IHDR chunk</param>
        /// <param name="palette">An unused PaletteInfo struct to load the PLTE chunk data into</param>
        /// <returns>A byte[] containing the constructed and decompressed image</returns>
        private static byte[] ProcessChunks(List<Chunk> chunks, HeaderInfo header, ref PaletteInfo palette)
        {
            int numberOfBytesRead = 0;

            foreach (Chunk currentChunk in chunks)
            {

                switch (currentChunk.Type)
                {
                    //Only one IHDR can exist, and it should have already been removed
                    case ChunkTypes.IHDR:
                        {
                            throw new Exception(String.Format("List<Chunk> chunks still contains IHDR chunk info."));
                            //break;
                        }

                    case ChunkTypes.PLTE:
                        {   //Check if a palette can even be used for this image's ColorType
                            if ((header.ColorType == 0) || (header.ColorType == 4))
                                throw new Exception(String.Format(
                                    "The given ColorType, {0}, does not support the use of a Palette.", header.ColorType));
                            //if so, prepare the palette to hold the maximum number of colors for the given bitDepth
                            palette.Entries = new RGB[(1 << (header.BitDepth + 1)) - 1];
                            //Read the PLTE chunk into the given PaletteInfo
                            ReadPalette(currentChunk, ref palette);
                            break;
                        }

                    case ChunkTypes.IDAT:
                        {
                            //Read the IDAT chunk's data into the List for imageData
                            ReadImageData(currentChunk, ref sReadImageDataByteBuffer, ref numberOfBytesRead);
                            break;
                        }

                    case ChunkTypes.IEND:
                        {
                            //This should be the last chunk to be loaded, so it's safe now to decompress the image
                            //and do any extra processing caused by ancillary chunks.

                            //Check if there are any chunks after IEND
                            if (chunks.IndexOf(currentChunk) != chunks.Count - 1)
                                throw new Exception(String.Format(
                                    "IEND chunk does not appear to be the last chunk in the image."));

                            //Load the compressed image into an InflaterInputStream to inflate(decompress) the image
                            MemoryStream streamForInflater = new MemoryStream(sReadImageDataByteBuffer, 0, numberOfBytesRead);

                            InflaterInputStream decompressionStream = new InflaterInputStream(streamForInflater);

                            //Read the decompressed image through the stream and into a byte[]
                            ReadStream(ref decompressionStream);

                            break;
                        }
                    case ChunkTypes.tRNS:
                        {
                            mMaxTransIndex = (int)currentChunk.Length - 1;
                            for (int i = 0; i < currentChunk.Length; ++i)
                            {
                                mTransparentEntries[i] = (byte)currentChunk.ChunkData.ReadByte();
                            }
                            break;
                        }


                    //Represents an ancillary chunk that isn't yet implemented or an unknown chunk type
                    case ChunkTypes.UNSUPPORTED:
                        {
                            break;
                        }
                }
            }


            //Return the image
            return sByteBuffer;
        }
예제 #3
0
        /// <summary>
        /// Loads a .png image from the fileName given and returns an array of pixel colors.
        /// </summary>
        /// <param name="fileName">The name of the .png image to be loaded.</param>
        /// <returns>
        /// Returns a Microsoft.Xna.Framework.Graphics.Color[] containing one item(Color) for each pixel
        /// in the image.</returns>
        public static ImageData GetPixelData(string fileName)
        {
            for (int i = 0; i < ByteBufferSize; i++)
            {
                mTransparentEntries[i] = byte.MaxValue;
            }

            int bytesRead = LoadFile(fileName);

            


            mMaxTransIndex = -1;


            //Load the file into "byte stream"
            Stream sourceStream = new MemoryStream(sByteBuffer, 0, bytesRead);


            //Check the signature to verify this is an actual .png image
            if (!CheckSignature(ref sourceStream))
                throw new ArgumentException(
                    String.Format("Argument Stream {0} does not contain a valid PNG file.", sourceStream));

            //Since all data in .png files is organized into categorized chunks, create a
            //List to store them in so that they can be read and processed later.
            List<Chunk> chunks = new List<Chunk>();

            //Load each Chunk of data from the stream into the List of Chunks. Then
            //close the stream.
            while (GetNextChunk(ref sourceStream, ref chunks)) { }
            sourceStream.Close();


            //Read and store the information from the IHDR chunk, which contains
            //general info for this image. Note: IHDR chunk is removed from List<Chunk> chunks.
            HeaderInfo header = ReadHeader(ref chunks);


            //Create an empty palette in case we need it
            PaletteInfo palette = new PaletteInfo();

            //Process the Chunks of data and obtain the decompressed bytes of the image
            byte[] filteredImage = ProcessChunks(chunks, header, ref palette);


            //Reverse the filtering that was done on the image before compression
            byte[] defilteredImage = ReverseFiltering(filteredImage, header);



            //Translate the un-filtered image bytes into Colors and store in the array to be returned.
            Color[] pixelData = BuildPixels(defilteredImage, ref header, ref palette);
            //System.Diagnostics.Trace.WriteLine(pixelData.Length);

            ImageData imageData = new ImageData((int)header.Width, (int)header.Height, pixelData);


            return imageData;
        }
예제 #4
0
        /// <summary>
        /// Processes the PLTE chunk by reading in all of the indexed color values and storing them in
        /// a PaletteInfo struct.
        /// </summary>
        /// <param name="plte">The Chunk containing the PLTE chunk from the file</param>
        /// <param name="palette">An unused PaletteInfo struct to be filled by data from plte</param>
        private static void ReadPalette(Chunk plte, ref PaletteInfo palette)
        {
            //The length of PLTE's data segment should be 3 * the number of entries
            uint numEntries = (uint)plte.ChunkData.Length / 3;

            //Checking for monkey-business???
            if ((numEntries * 3) == plte.ChunkData.Length)
            {
                //Read in the values of the color entries and store them.
                for (int i = 0; i < numEntries; ++i)
                {
                    RGB value = new RGB();
                    value.R = (byte)plte.ChunkData.ReadByte(); //System.Diagnostics.Trace.WriteLine(value.R);
                    value.G = (byte)plte.ChunkData.ReadByte();// System.Diagnostics.Trace.WriteLine(value.G);
                    value.B = (byte)plte.ChunkData.ReadByte();// System.Diagnostics.Trace.WriteLine(value.B);
                    palette.Entries[i] = value;
                }
            }
        }
예제 #5
0
        private static Color[] OldMethod(byte[] image, ref HeaderInfo header, ref PaletteInfo palette)
        {
            int totalPixels = (int)(header.Width * header.Height);
            int currentIndex = 0;

            if (totalPixels > mStaticPixels.Length)
            {
                mStaticPixels = new Color[totalPixels];
            }

            MemoryStream imageStream = new MemoryStream(image);
            int filterByte;

            switch ((int)header.ColorType)
            {
                //Each pixel is an R,G,B triple
                case 2:
                    {
                        //This section of code containing conversion of 16-bit samples is currently untested.
                        if (header.BitDepth > 8)
                        {
                            int bps = (int)(header.Width * header.BitDepth * 3 + 1);
                            int R = 0;
                            int G = 0;
                            int B = 0;
                            while ((filterByte = imageStream.ReadByte()) > -1 && currentIndex < totalPixels)
                            {
                                for (int i = 0; i < header.Width; ++i)
                                {
                                    R = imageStream.ReadByte(); imageStream.ReadByte();
                                    G = imageStream.ReadByte(); imageStream.ReadByte();
                                    B = imageStream.ReadByte(); imageStream.ReadByte();
                                    mStaticPixels[currentIndex] = (new Color((byte)R, (byte)G, (byte)B));
                                    currentIndex++;
                                }
                            }

                        }
                        else
                        {
                            while ((filterByte = imageStream.ReadByte()) > -1 && currentIndex < totalPixels)
                            {
                                for (int i = 0; i < header.Width; ++i)
                                {
                                    mStaticPixels[currentIndex] = (new Color(
                                        (byte)imageStream.ReadByte(),
                                        (byte)imageStream.ReadByte(),
                                        (byte)imageStream.ReadByte()));
                                    currentIndex++;
                                }
                            }
                        }
                        break;
                    }

                //Each pixel is a grayscale sample
                case 0:
                    {

                        if (header.BitDepth < 8)
                        {
                            byte sample;
                            int value;
                            float grayValue;
                            int numBits = 8 / header.BitDepth;
                            int mask = (255 >> (8 - header.BitDepth));
                            while ((filterByte = imageStream.ReadByte()) > -1 && currentIndex < totalPixels)
                            {
                                for (int i = 0; i < header.Width / numBits; ++i)
                                {
                                    value = imageStream.ReadByte();
                                    for (int j = 8 - header.BitDepth; j >= 0; j -= header.BitDepth)
                                    {
                                        grayValue = (float)((value & (mask << j)) >> j);
                                        sample = (byte)((grayValue / ((1 << header.BitDepth) - 1)) * 255);
                                        mStaticPixels[currentIndex] = (new Color(sample, sample, sample));
                                        currentIndex++;
                                    }
                                }
                            }

                        }
                        else if (header.BitDepth == 8)
                        {
                            byte sample;
                            float value;

                            //Get the filter byte out of the way
                            while ((filterByte = imageStream.ReadByte()) > -1 && currentIndex < totalPixels)
                            {
                                //Read the scanline
                                for (int i = 0; i < header.Width; ++i)
                                {
                                    value = (float)(imageStream.ReadByte());
                                    sample = (byte)((value / ((1 << header.BitDepth) - 1)) * 255);
                                    mStaticPixels[currentIndex] = (new Color(sample, sample, sample));
                                    currentIndex++;
                                }
                            }
                        }

                        else
                        {
                            byte sample;
                            while ((filterByte = imageStream.ReadByte()) > -1 && currentIndex < totalPixels)
                            {
                                for (int i = 0; i < header.Width; ++i)
                                {
                                    sample = (byte)imageStream.ReadByte(); imageStream.ReadByte();
                                    mStaticPixels[currentIndex] = (new Color(sample, sample, sample));
                                    currentIndex++;
                                }
                            }
                        }

                        break;
                    }

                //Each pixel is a palette index
                case 3:
                    {
                        RGB entry;
                        int value;
                        int numBits = 8 / header.BitDepth;
                        int mask = (255 >> (8 - header.BitDepth));
                        int index;
                        while ((filterByte = imageStream.ReadByte()) > -1 && currentIndex < totalPixels)
                        {
                            for (int i = 0; i < header.Width / numBits; ++i)
                            {
                                value = imageStream.ReadByte();
                                for (int j = 8 - header.BitDepth; j >= 0; j -= header.BitDepth)
                                {
                                    index = (value & (mask << j)) >> j;
                                    entry = palette.Entries[index];
                                    mStaticPixels[currentIndex] = (new Color((byte)entry.R, (byte)entry.G, (byte)entry.B));

                                    if (mMaxTransIndex >= index)
                                    {
                                        mStaticPixels[currentIndex].A = mTransparentEntries[index];
                                    }
                                    currentIndex++;
                                }
                            }
                        }
                        break;
                    }

                //Each pixel is a grayscale sample, followed by an alpha sample
                case 4:
                    {
                        switch ((int)header.BitDepth)
                        {
                            case 8:
                                {
                                    //Open stream to image array
                                    byte sample;

                                    //Get the filter byte out of the way
                                    while ((filterByte = imageStream.ReadByte()) > -1 && currentIndex < totalPixels)
                                    {
                                        //Read the scanline
                                        for (int i = 0; i < header.Width; ++i)
                                        {
                                            sample = (byte)(imageStream.ReadByte());
                                            mStaticPixels[currentIndex] = (new Color(sample, sample, sample, (byte)imageStream.ReadByte()));
                                            currentIndex++;
                                        }
                                    }

                                    break;
                                }

                            case 16:
                                {
                                    byte sample;
                                    while ((filterByte = imageStream.ReadByte()) > -1 && currentIndex < totalPixels)
                                    {
                                        for (int i = 0; i < header.Width; ++i)
                                        {
                                            sample = (byte)imageStream.ReadByte(); imageStream.ReadByte();
                                            mStaticPixels[currentIndex] = (new Color(sample, sample, sample, (byte)imageStream.ReadByte())); imageStream.ReadByte();
                                            currentIndex++;
                                        }
                                    }

                                    break;
                                }
                        }
                        break;
                    }

                //Each pixel is an R,G,B triple, followed by an alpha sample
                case 6:
                    {
                        switch ((int)header.BitDepth)
                        {
                            case 8:
                                {
                                    while ((filterByte = imageStream.ReadByte()) > -1 && currentIndex < totalPixels)
                                    {
                                        for (int i = 0; i < header.Width; ++i)
                                        {
                                            mStaticPixels[currentIndex] = (new Color(
                                                (byte)imageStream.ReadByte(),
                                                (byte)imageStream.ReadByte(),
                                                (byte)imageStream.ReadByte(),
                                                (byte)imageStream.ReadByte()));

                                            currentIndex++;
                                        }
                                    }
                                    break;
                                }

                            case 16:
                                {
                                    int bps = (int)(header.Width * header.BitDepth * 3 + 1);
                                    int R = 0;
                                    int G = 0;
                                    int B = 0;
                                    int A = 0;
                                    while ((filterByte = imageStream.ReadByte()) > -1 && currentIndex < totalPixels)
                                    {
                                        for (int i = 0; i < header.Width; ++i)
                                        {
                                            R = imageStream.ReadByte(); imageStream.ReadByte();
                                            G = imageStream.ReadByte(); imageStream.ReadByte();
                                            B = imageStream.ReadByte(); imageStream.ReadByte();
                                            A = imageStream.ReadByte(); imageStream.ReadByte();
                                            mStaticPixels[currentIndex] = (new Color((byte)R, (byte)G, (byte)B, (byte)A));
                                            currentIndex++;
                                        }
                                    }

                                    break;
                                }
                        }
                        break;
                    }

            }
            imageStream.Close();
            return mStaticPixels;
        }