Exemplo n.º 1
0
        private bool ApplyChunk(byte[] typeArray, byte[] dataArray)
        {
            bool   result     = true;
            string typeString = PNGUtil.GetTypeString(typeArray);

            switch (typeString)
            {
            case "IHDR":
                result = ApplyChunkIHDR(dataArray);
                break;

            case "PLTE":
                errorMessage = "can't handle PLTE chunk";
                result       = false;
                break;

            case "IDAT":
                result = ApplyChunkIDAT(dataArray);
                break;

            case "IEND":
                result    = ApplyChunkIEND();
                foundIEND = result;
                break;

            case "tRNS":
            case "cHRM":
            case "gAMA":
            case "iCCP":
            case "sBIT":
            case "sRGB":
            case "tEXt":
            case "iTXt":
            case "zTXt":
            case "bKGD":
            case "hIST":
            case "pHYs":
            case "sPLT":
            case "tIME":
                // chunks to be ignored
                break;

            default:
                errorMessage = "unknown chunk type";
                result       = false;
                break;
            }

            return(result);
        }
Exemplo n.º 2
0
        private bool ApplyChunkIHDR(byte[] dataArray)
        {
            // verify length
            if (13 != dataArray.Length)
            {
                return(false);
            }

            byte[] sizeArray = new byte[4];

            Array.Copy(dataArray, 0, sizeArray, 0, 4);
            width = PNGUtil.GetInt(sizeArray);

            Array.Copy(dataArray, 4, sizeArray, 0, 4);
            height = PNGUtil.GetInt(sizeArray);

            bitDepth        = (int)dataArray[8];
            colorType       = (int)dataArray[9];
            compressMethod  = (int)dataArray[10];
            filterMethod    = (int)dataArray[11];
            interlaceMethod = (int)dataArray[12];

            if (bitDepth != 8)
            {
                errorMessage = "can't handle bit depth " + bitDepth;
                return(false);
            }
            if (colorType != 2)
            {
                errorMessage = "can't handle color type " + colorType;
                return(false);
            }
            if (compressMethod != 0)
            {
                errorMessage = "strange compress method " + compressMethod;
                return(false);
            }
            if (filterMethod != 0)
            {
                errorMessage = "strange filter method " + filterMethod;
                return(false);
            }
            if (interlaceMethod < 0 || 1 < interlaceMethod)
            {
                errorMessage = "strange interlace method " + interlaceMethod;
                return(false);
            }
            return(true);
        }
Exemplo n.º 3
0
        private bool AnalyzeChunk()
        {
            bool result = true;

            int length = 0;

            byte[] typeArray = new byte[4];
            byte[] temp4Byte = new byte[4];
            uint   crc       = 0;

            // length area
            Array.Copy(pngData, index, temp4Byte, 0, 4);
            length = PNGUtil.GetInt(temp4Byte);
            index += 4;

            // type area
            Array.Copy(pngData, index, typeArray, 0, 4);
            index += 4;

            // data area
            byte[] dataArray = new byte[length];
            Array.Copy(pngData, index, dataArray, 0, length);
            index += length;

            // CRC area
            Array.Copy(pngData, index, temp4Byte, 0, 4);
            index += 4;
            crc    = (uint)PNGUtil.GetInt(temp4Byte);

            // CRC check
            if (CRCChecker.CRC(typeArray, dataArray) == crc)
            {
                result = ApplyChunk(typeArray, dataArray);
            }
            else
            {
                // CRC invalid
                errorMessage = "CRC invalid";
                result       = false;
            }

            return(result);
        }
Exemplo n.º 4
0
        public bool Decode()
        {
            PNGAnalyzer analyzer = new PNGAnalyzer(pngData);

            if (!analyzer.Analyze())
            {
                errorMessage = analyzer.ErrorMessage;
                return(false);
            }

            // succeeded to scan data

            // ======================

            // begin to arrange the image data

            height    = analyzer.Height;
            width     = analyzer.Width;
            dataR     = new byte[height * width];
            dataG     = new byte[height * width];
            dataB     = new byte[height * width];
            colorType = analyzer.ColorType;
            switch (colorType)
            {
            case 2:
                channels = 3;
                break;

            default:
                errorMessage = "Color type can't be handled";
                return(false);
            }

            decompressedData = analyzer.DecompressData;

            passTotal = analyzer.InterlaceMethod == 0 ? 1 : 7;


            for (int passIndex = 0; passIndex < passTotal; passIndex++)
            {
                int heightStart = 0;
                int heightSkip  = 1;
                int widthStart  = 0;
                int widthSkip   = 1;
                int rowLength   = width;

                // for interlace,
                if (passTotal > 1)
                {
                    widthStart  = PNGUtil.passStart[passIndex];
                    widthSkip   = PNGUtil.passIncrement[passIndex];
                    heightStart = PNGUtil.passYStart[passIndex];
                    heightSkip  = PNGUtil.passYIncrement[passIndex];
                    rowLength   = PNGUtil.CalculateWidth(width, passIndex);
                }

                // in the case that the pass have no reduced image.
                if (rowLength <= 0)
                {
                    continue;
                }

                int    rowBytes = rowLength * channels + 1;
                byte[] rowPrev;
                byte[] rowCurrent = new byte[rowBytes];

                for (int h = heightStart; h < height; h += heightSkip)
                {
                    rowPrev    = rowCurrent;
                    rowCurrent = new byte[rowBytes];

                    Array.Copy(decompressedData, decompressedIndex, rowCurrent, 0, rowBytes);

                    switch (rowCurrent[0])
                    {
                    case 0:
                        // NONE
                        break;

                    case 1:
                        // SUB
                        for (int i = 4; i < rowBytes; i += 3)
                        {
                            rowCurrent[i + 0] = (byte)((int)rowCurrent[i + 0] + (int)rowCurrent[i - 3]);
                            rowCurrent[i + 1] = (byte)((int)rowCurrent[i + 1] + (int)rowCurrent[i - 2]);
                            rowCurrent[i + 2] = (byte)((int)rowCurrent[i + 2] + (int)rowCurrent[i - 1]);
                        }
                        break;

                    case 2:
                        // UP
                        for (int i = 1; i < rowBytes; i += 3)
                        {
                            rowCurrent[i + 0] = (byte)((int)rowCurrent[i + 0] + (int)rowPrev[i + 0]);
                            rowCurrent[i + 1] = (byte)((int)rowCurrent[i + 1] + (int)rowPrev[i + 1]);
                            rowCurrent[i + 2] = (byte)((int)rowCurrent[i + 2] + (int)rowPrev[i + 2]);
                        }
                        break;

                    case 3:
                        // AVERAGE
                        rowCurrent[1] = (byte)((int)rowCurrent[1] + ((int)rowPrev[1] / 2));
                        rowCurrent[2] = (byte)((int)rowCurrent[2] + ((int)rowPrev[2] / 2));
                        rowCurrent[3] = (byte)((int)rowCurrent[3] + ((int)rowPrev[3] / 2));
                        for (int i = 4; i < rowBytes; i += 3)
                        {
                            rowCurrent[i + 0] = (byte)((int)rowCurrent[i + 0] + (((int)rowCurrent[i - 3] + (int)rowPrev[i + 0]) / 2));
                            rowCurrent[i + 1] = (byte)((int)rowCurrent[i + 1] + (((int)rowCurrent[i - 2] + (int)rowPrev[i + 1]) / 2));
                            rowCurrent[i + 2] = (byte)((int)rowCurrent[i + 2] + (((int)rowCurrent[i - 1] + (int)rowPrev[i + 2]) / 2));
                        }
                        break;

                    case 4:
                        // PAETH
                        rowCurrent[1] = (byte)((int)rowCurrent[1] + PNGUtil.PaethPredictor(0, (int)rowPrev[1], 0));
                        rowCurrent[2] = (byte)((int)rowCurrent[2] + PNGUtil.PaethPredictor(0, (int)rowPrev[2], 0));
                        rowCurrent[3] = (byte)((int)rowCurrent[3] + PNGUtil.PaethPredictor(0, (int)rowPrev[3], 0));
                        for (int i = 4; i < rowBytes; i += 3)
                        {
                            rowCurrent[i + 0] = (byte)((int)rowCurrent[i + 0] + PNGUtil.PaethPredictor((int)rowCurrent[i - 3], (int)rowPrev[i + 0], (int)rowPrev[i - 3]));
                            rowCurrent[i + 1] = (byte)((int)rowCurrent[i + 1] + PNGUtil.PaethPredictor((int)rowCurrent[i - 2], (int)rowPrev[i + 1], (int)rowPrev[i - 2]));
                            rowCurrent[i + 2] = (byte)((int)rowCurrent[i + 2] + PNGUtil.PaethPredictor((int)rowCurrent[i - 1], (int)rowPrev[i + 2], (int)rowPrev[i - 1]));
                        }
                        break;

                    default:
                        errorMessage = "Unknown filter type";
                        return(false);
                    }

                    int t = 1;
                    for (int w = widthStart; w < width; w += widthSkip)
                    {
                        dataR[h * width + w] = rowCurrent[t++];
                        dataG[h * width + w] = rowCurrent[t++];
                        dataB[h * width + w] = rowCurrent[t++];
                    }

                    decompressedIndex += rowBytes;
                }
            }

            return(true);
        }