/// <summary> /// Skip white space /// </summary> public void SkipWhiteSpace() { // skip white space if (PdfBase.IsWhiteSpace(NextChar)) { while ((NextChar = ReadChar()) != EOF && PdfBase.IsWhiteSpace(NextChar)) { ; } } return; }
//////////////////////////////////////////////////////////////////// // 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> /// Parse object reference number n 0 R obj /// </summary> /// <returns>Object number</returns> public int ParseObjectRefNo() { // loop in case of one or more comments SkipComments(); // must be a digit if (NextChar < '0' || NextChar > '9') { return(0); } // next content element StringBuilder NextItem = new StringBuilder(); NextItem.Append((char)NextChar); // add more characters until next delimiter while ((NextChar = ReadChar()) != EOF && !PdfBase.IsDelimiter(NextChar)) { NextItem.Append((char)NextChar); } // integer if (!int.TryParse(NextItem.ToString(), out int ObjNo) || ObjNo <= 0) { return(0); } // next character must be space if (!PdfBase.IsWhiteSpace(NextChar)) { return(0); } // skip additional white space while ((NextChar = ReadChar()) != EOF && PdfBase.IsWhiteSpace(NextChar)) { ; } // next character must be zero if (NextChar != '0') { return(0); } // next character must be white space NextChar = ReadChar(); if (!PdfBase.IsWhiteSpace(NextChar)) { return(0); } // skip additional white space while ((NextChar = ReadChar()) != EOF && PdfBase.IsWhiteSpace(NextChar)) { ; } // next 3 characters must be obj if (NextChar != 'o' || ReadChar() != 'b' || ReadChar() != 'j') { return(0); } // next character must be a delimiter NextChar = ReadChar(); if (!PdfBase.IsDelimiter(NextChar)) { return(0); } // return object number return(ObjNo); }
//////////////////////////////////////////////////////////////////// // Parse hex string item and return PdfString //////////////////////////////////////////////////////////////////// internal PdfBase ParseHexString() { // create value string List <byte> StrArr = new List <byte>(); // add more hexadecimal numbers until next closing > bool First = true; int OneChar; int OneByte = 0; for (;;) { // read next character NextChar = ReadChar(); if (NextChar == EOF) { throw new ApplicationException("Invalid hex string (End of contents)"); } // end of string if (NextChar == '>') { break; } // ignore white space within the string if (PdfBase.IsWhiteSpace(NextChar)) { continue; } // test for hex digits if (NextChar >= '0' && NextChar <= '9') { OneChar = NextChar - '0'; } else if (NextChar >= 'A' && NextChar <= 'F') { OneChar = NextChar - ('A' - 10); } else if (NextChar >= 'a' && NextChar <= 'f') { OneChar = NextChar - ('a' - 10); } else { throw new ApplicationException("Invalid hex string"); } if (First) { OneByte = OneChar; First = false; } else { StrArr.Add((byte)((OneByte << 4) | OneChar)); First = true; } } if (!First) { StrArr.Add((byte)(OneByte << 4)); } // read next character after closing > NextChar = ReadChar(); // exit return(new PdfString(StrArr.ToArray())); }
//////////////////////////////////////////////////////////////////// // Test for reference // We have positive integer already. Test for zero and R //////////////////////////////////////////////////////////////////// internal bool TestReference() { // save current file position int Pos = GetPos(); // save next character int TempChar = NextChar; for (;;) { // next character must be space if (!PdfBase.IsWhiteSpace(TempChar)) { break; } // skip additional white space while ((TempChar = ReadChar()) != EOF && PdfBase.IsWhiteSpace(TempChar)) { ; } // generation is not supported // next character must be zero if (TempChar != '0') { break; } // next character must be white space TempChar = ReadChar(); if (!PdfBase.IsWhiteSpace(TempChar)) { break; } // skip additional white space while ((TempChar = ReadChar()) != EOF && PdfBase.IsWhiteSpace(TempChar)) { ; } // next character must be R if (TempChar != 'R') { break; } // next character must be a delimiter TempChar = ReadChar(); if (!PdfBase.IsDelimiter(TempChar)) { break; } // found NextChar = TempChar; return(true); } // restore position SetPos(Pos); return(false); }
/// <summary> /// Apply ASCII 85 decode /// </summary> /// <param name="InputBuffer">Input buffer</param> /// <returns>Output buffer</returns> internal byte[] Ascii85Decode ( byte[] InputBuffer ) { // array of power of 85: 85**4, 85**3, 85**2, 85**1, 85**0 uint[] Power85 = new uint[] { 85 * 85 * 85 * 85, 85 * 85 * 85, 85 * 85, 85, 1 }; // output buffer List <byte> OutputBuffer = new List <byte>(); // convert input to output buffer int State = 0; uint FourBytes = 0; for (int Index = 0; Index < InputBuffer.Length; Index++) { // next character char NextChar = (char)InputBuffer[Index]; // end of stream "~>" if (NextChar == '~') { break; } // ignore white space if (PdfBase.IsWhiteSpace(NextChar)) { continue; } // special case of four zero bytes if (NextChar == 'z' && State == 0) { OutputBuffer.Add(0); OutputBuffer.Add(0); OutputBuffer.Add(0); OutputBuffer.Add(0); continue; } // test for valid characters if (NextChar < '!' || NextChar > 'u') { throw new ApplicationException("Illegal character in ASCII85Decode"); } // accumulate 4 output bytes from 5 input bytes FourBytes += Power85[State++] * (uint)(NextChar - '!'); // we have 4 output bytes if (State == 5) { OutputBuffer.Add((byte)(FourBytes >> 24)); OutputBuffer.Add((byte)(FourBytes >> 16)); OutputBuffer.Add((byte)(FourBytes >> 8)); OutputBuffer.Add((byte)FourBytes); // reset state State = 0; FourBytes = 0; } } // if state is not zero add one, two or three terminating bytes if (State != 0) { if (State == 1) { throw new ApplicationException("Illegal length in ASCII85Decode"); } // add padding of 84 for (int PadState = State; PadState < 5; PadState++) { FourBytes += Power85[PadState] * (uint)('u' - '!'); } // add one, two or three terminating bytes OutputBuffer.Add((byte)(FourBytes >> 24)); if (State >= 3) { OutputBuffer.Add((byte)(FourBytes >> 16)); if (State >= 4) { OutputBuffer.Add((byte)(FourBytes >> 8)); } } } // exit return(OutputBuffer.ToArray()); }