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