//////////////////////////////////////////////////////////////////// // Parse inline image //////////////////////////////////////////////////////////////////// internal PdfOp ParseInlineImage() { // create empty dictionary PdfDictionary ImageDict = ParseDictionary(true); // get image width if (!ImageDict.FindValue("/W").GetInteger(out int Width) || Width <= 0) { throw new ApplicationException("Parse inline image: Width error"); } // get image height if (!ImageDict.FindValue("/H").GetInteger(out int Height) || Height <= 0) { throw new ApplicationException("Parse inline image: Height error"); } // get image bits per component if (!ImageDict.FindValue("/BPC").GetInteger(out int BitPerComp) || BitPerComp != 1 && BitPerComp != 2 && BitPerComp != 4 && BitPerComp != 8) { throw new ApplicationException("Parse inline image: BPC error"); } int Components = 0; // get color space string ColorSpace = ImageDict.FindValue("/CS").ToName; if (ColorSpace != null) { // number of components if (ColorSpace == "/G") { Components = 1; } else if (ColorSpace == "/RGB") { Components = 3; } else if (ColorSpace == "/CMYK") { Components = 4; } else { throw new ApplicationException("Parse inline image: ColorSpace error"); } } ImageDict.FindValue("/IM").GetBoolean(out bool IM); if (IM) { Components = 1; } PdfBase Filter = ImageDict.FindValue("/F"); if (!Filter.IsEmpty) { throw new ApplicationException("Parse inline image: No filter support"); } // no ASCIIHexDecode AHx or ASCII85Decode A85 if (!PdfBase.IsWhiteSpace(NextChar)) { throw new ApplicationException("Parse inline image: ID must be followed by white space"); } // image width in bytes int WidthBytes = 0; switch (BitPerComp) { case 1: WidthBytes = (Width + 7) / 8; break; case 2: WidthBytes = (Width + 3) / 4; break; case 4: WidthBytes = (Width + 1) / 2; break; case 8: WidthBytes = Width; break; } // image size int Size = WidthBytes * Height * Components; // image stream byte[] ImageStream = new byte[Size]; for (int Index = 0; Index < Size; Index++) { // read next character NextChar = ReadChar(); // end of file error if (NextChar == EOF) { throw new ApplicationException("Invalid inline image (end of contents)"); } // save it in bitmap ImageStream[Index] = (byte)NextChar; } // get termination NextChar = ReadChar(); SkipWhiteSpace(); if (NextChar != 'E' || ReadChar() != 'I') { throw new ApplicationException("Parse inline image: EI is missing"); } NextChar = ReadChar(); PdfOp InlineImage = new PdfOp(Operator.BeginInlineImage); InlineImage.ArgumentArray = new PdfBase[] { ImageDict, new PdfString(ImageStream) }; // exit return(InlineImage); }
/// <summary> /// Apply predictor decode /// </summary> /// <param name="InputBuffer">Input buffer</param> /// <returns>Output buffer</returns> internal byte[] PredictorDecode ( byte[] InputBuffer ) { // test for /DecodeParams PdfDictionary DecodeParms = Dictionary.FindValue("/DecodeParms").ToDictionary; // none found if (DecodeParms == null) { return(InputBuffer); } // look for predictor code. if default (none or 1) do nothing if (!DecodeParms.FindValue("/Predictor").GetInteger(out int Predictor) || Predictor == 1) { return(InputBuffer); } // we only support predictor code 12 if (Predictor != 12) { return(null); } // get width DecodeParms.FindValue("/Columns").GetInteger(out int Width); if (Width < 0) { throw new ApplicationException("/DecodeParms /Columns is negative"); } if (Width == 0) { Width = 1; } // calculate rows int Rows = InputBuffer.Length / (Width + 1); if (Rows < 1) { throw new ApplicationException("/DecodeParms /Columns is greater than stream length"); } // create output buffer byte[] OutputBuffer = new byte[Rows * Width]; // reset pointers int InPtr = 1; int OutPtr = 0; int OutPrevPtr = 0; // first row (ignore filter) while (OutPtr < Width) { OutputBuffer[OutPtr++] = InputBuffer[InPtr++]; } // decode loop for (int Row = 1; Row < Rows; Row++) { // first byte is filter int Filter = InputBuffer[InPtr++]; // we support PNG filter up only if (Filter != 2) { throw new ApplicationException("/DecodeParms Only supported filter is 2"); } // convert input to output for (int Index = 0; Index < Width; Index++) { OutputBuffer[OutPtr++] = (byte)(OutputBuffer[OutPrevPtr++] + InputBuffer[InPtr++]); } } return(OutputBuffer); }