void ReadPng() { for (int i = 0; i < PNGID.Length; i++) { if (PNGID[i] != isp.ReadByte()) { throw new IOException(MessageLocalization.GetComposedMessage("file.is.not.a.valid.png")); } } byte[] buffer = new byte[TRANSFERSIZE]; while (true) { int len = GetInt(isp); String marker = GetString(isp); if (len < 0 || !CheckMarker(marker)) throw new IOException(MessageLocalization.GetComposedMessage("corrupted.png.file")); if (IDAT.Equals(marker)) { int size; while (len != 0) { size = isp.Read(buffer, 0, Math.Min(len, TRANSFERSIZE)); if (size <= 0) return; idat.Write(buffer, 0, size); len -= size; } } else if (tRNS.Equals(marker)) { switch (colorType) { case 0: if (len >= 2) { len -= 2; int gray = GetWord(isp); if (bitDepth == 16) transRedGray = gray; else additional.Put(PdfName.MASK, new PdfLiteral("["+gray+" "+gray+"]")); } break; case 2: if (len >= 6) { len -= 6; int red = GetWord(isp); int green = GetWord(isp); int blue = GetWord(isp); if (bitDepth == 16) { transRedGray = red; transGreen = green; transBlue = blue; } else additional.Put(PdfName.MASK, new PdfLiteral("["+red+" "+red+" "+green+" "+green+" "+blue+" "+blue+"]")); } break; case 3: if (len > 0) { trans = new byte[len]; for (int k = 0; k < len; ++k) trans[k] = (byte)isp.ReadByte(); len = 0; } break; } Utilities.Skip(isp, len); } else if (IHDR.Equals(marker)) { width = GetInt(isp); height = GetInt(isp); bitDepth = isp.ReadByte(); colorType = isp.ReadByte(); compressionMethod = isp.ReadByte(); filterMethod = isp.ReadByte(); interlaceMethod = isp.ReadByte(); } else if (PLTE.Equals(marker)) { if (colorType == 3) { PdfArray colorspace = new PdfArray(); colorspace.Add(PdfName.INDEXED); colorspace.Add(GetColorspace()); colorspace.Add(new PdfNumber(len / 3 - 1)); ByteBuffer colortable = new ByteBuffer(); while ((len--) > 0) { colortable.Append_i(isp.ReadByte()); } colorspace.Add(new PdfString(colorTable = colortable.ToByteArray())); additional.Put(PdfName.COLORSPACE, colorspace); } else { Utilities.Skip(isp, len); } } else if (pHYs.Equals(marker)) { int dx = GetInt(isp); int dy = GetInt(isp); int unit = isp.ReadByte(); if (unit == 1) { dpiX = (int)((float)dx * 0.0254f + 0.5f); dpiY = (int)((float)dy * 0.0254f + 0.5f); } else { if (dy != 0) XYRatio = (float)dx / (float)dy; } } else if (cHRM.Equals(marker)) { xW = (float)GetInt(isp) / 100000f; yW = (float)GetInt(isp) / 100000f; xR = (float)GetInt(isp) / 100000f; yR = (float)GetInt(isp) / 100000f; xG = (float)GetInt(isp) / 100000f; yG = (float)GetInt(isp) / 100000f; xB = (float)GetInt(isp) / 100000f; yB = (float)GetInt(isp) / 100000f; hasCHRM = !(Math.Abs(xW)<0.0001f||Math.Abs(yW)<0.0001f||Math.Abs(xR)<0.0001f||Math.Abs(yR)<0.0001f||Math.Abs(xG)<0.0001f||Math.Abs(yG)<0.0001f||Math.Abs(xB)<0.0001f||Math.Abs(yB)<0.0001f); } else if (sRGB.Equals(marker)) { int ri = isp.ReadByte(); intent = intents[ri]; gamma = 2.2f; xW = 0.3127f; yW = 0.329f; xR = 0.64f; yR = 0.33f; xG = 0.3f; yG = 0.6f; xB = 0.15f; yB = 0.06f; hasCHRM = true; } else if (gAMA.Equals(marker)) { int gm = GetInt(isp); if (gm != 0) { gamma = 100000f / (float)gm; if (!hasCHRM) { xW = 0.3127f; yW = 0.329f; xR = 0.64f; yR = 0.33f; xG = 0.3f; yG = 0.6f; xB = 0.15f; yB = 0.06f; hasCHRM = true; } } } else if (iCCP.Equals(marker)) { do { --len; } while (isp.ReadByte() != 0); isp.ReadByte(); --len; byte[] icccom = new byte[len]; int p = 0; while (len > 0) { int r = isp.Read(icccom, p, len); if (r < 0) throw new IOException(MessageLocalization.GetComposedMessage("premature.end.of.file")); p += r; len -= r; } byte[] iccp = PdfReader.FlateDecode(icccom, true); icccom = null; try { icc_profile = ICC_Profile.GetInstance(iccp); } catch { icc_profile = null; } } else if (IEND.Equals(marker)) { break; } else { Utilities.Skip(isp, len); } Utilities.Skip(isp, 4); } }
/** * Escapes a <CODE>byte</CODE> array according to the PDF conventions. * * @param b the <CODE>byte</CODE> array to escape */ internal static void EscapeString(byte[] b, ByteBuffer content) { content.Append_i('('); for (int k = 0; k < b.Length; ++k) { byte c = b[k]; switch ((int)c) { case '\r': content.Append("\\r"); break; case '\n': content.Append("\\n"); break; case '\t': content.Append("\\t"); break; case '\b': content.Append("\\b"); break; case '\f': content.Append("\\f"); break; case '(': case ')': case '\\': content.Append_i('\\').Append_i(c); break; default: content.Append_i(c); break; } } content.Append(')'); }
// constructor /** * Constructs a <CODE>PdfImage</CODE>-object. * * @param image the <CODE>Image</CODE>-object * @param name the <CODE>PdfName</CODE> for this image * @throws BadPdfFormatException on error */ public PdfImage(Image image, string name, PdfIndirectReference maskRef) : base() { this.name = new PdfName(name); put(PdfName.TYPE, PdfName.XOBJECT); put(PdfName.SUBTYPE, PdfName.IMAGE); put(PdfName.NAME, this.name); put(PdfName.WIDTH, new PdfNumber(image.Width)); put(PdfName.HEIGHT, new PdfNumber(image.Height)); if (maskRef != null) { put(PdfName.MASK, maskRef); } if (image.isMask() && image.isInvertMask()) { put(PdfName.DECODE, new PdfLiteral("[1 0]")); } if (image.isInterpolation()) { put(PdfName.INTERPOLATE, PdfBoolean.PDFTRUE); } Stream istr = null; try { // Raw Image data if (image.isImgRaw()) { // will also have the CCITT parameters int colorspace = image.Colorspace; int[] transparency = image.Transparency; if (transparency != null && !image.isMask() && maskRef == null) { string s = "["; for (int k = 0; k < transparency.Length; ++k) { s += transparency[k] + " "; } s += "]"; put(PdfName.MASK, new PdfLiteral(s)); } bytes = image.RawData; put(PdfName.LENGTH, new PdfNumber(bytes.Length)); int bpc = image.Bpc; if (bpc > 0xff) { if (!image.isMask()) { put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); } put(PdfName.BITSPERCOMPONENT, new PdfNumber(1)); put(PdfName.FILTER, PdfName.CCITTFAXDECODE); int k = bpc - Element.CCITTG3_1D; PdfDictionary decodeparms = new PdfDictionary(); if (k != 0) { decodeparms.put(PdfName.K, new PdfNumber(k)); } if ((colorspace & Element.CCITT_BLACKIS1) != 0) { decodeparms.put(PdfName.BLACKIS1, PdfBoolean.PDFTRUE); } if ((colorspace & Element.CCITT_ENCODEDBYTEALIGN) != 0) { decodeparms.put(PdfName.ENCODEDBYTEALIGN, PdfBoolean.PDFTRUE); } if ((colorspace & Element.CCITT_ENDOFLINE) != 0) { decodeparms.put(PdfName.ENDOFLINE, PdfBoolean.PDFTRUE); } if ((colorspace & Element.CCITT_ENDOFBLOCK) != 0) { decodeparms.put(PdfName.ENDOFBLOCK, PdfBoolean.PDFFALSE); } decodeparms.put(PdfName.COLUMNS, new PdfNumber(image.Width)); decodeparms.put(PdfName.ROWS, new PdfNumber(image.Height)); put(PdfName.DECODEPARMS, decodeparms); } else { if (!image.isMask()) { switch (colorspace) { case 1: put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); break; case 3: put(PdfName.COLORSPACE, PdfName.DEVICERGB); break; case 4: default: put(PdfName.COLORSPACE, PdfName.DEVICECMYK); break; } } put(PdfName.BITSPERCOMPONENT, new PdfNumber(image.Bpc)); try { flateCompress(); } catch (PdfException pe) { throw pe; } } if (image.isMask()) { put(PdfName.IMAGEMASK, PdfBoolean.PDFTRUE); } return; } // GIF, JPEG or PNG string errorID; if (image.RawData == null) { WebRequest w = WebRequest.Create(image.Url); istr = w.GetResponse().GetResponseStream(); errorID = image.Url.ToString(); } else { istr = new MemoryStream(image.RawData); errorID = "Byte array"; } streamBytes = new MemoryStream(); int i = 0; switch (image.Type) { case Element.PNG: put(PdfName.FILTER, PdfName.FLATEDECODE); for (int j = 0; j < Png.PNGID.Length; j++) { if (Png.PNGID[j] != istr.ReadByte()) { throw new BadPdfFormatException(errorID + " is not a PNG file."); } } int colorType = 0; while (true) { int len = Png.getInt(istr); string marker = Png.getstring(istr); if (Png.IDAT.Equals(marker)) { transferBytes(istr, streamBytes, len); Png.getInt(istr); } else if (Png.tRNS.Equals(marker) && !image.isMask() && maskRef == null) { switch (colorType) { case 0: if (len >= 2) { len -= 2; int gray = Png.getWord(istr); put(PdfName.MASK, new PdfLiteral("[" + gray + " " + gray + "]")); } break; case 2: if (len >= 6) { len -= 6; int red = Png.getWord(istr); int green = Png.getWord(istr); int blue = Png.getWord(istr); put(PdfName.MASK, new PdfLiteral("[" + red + " " + red + " " + green + " " + green + " " + blue + " " + blue + "]")); } break; case 3: if (len > 0) { int idx = 0; while (len-- != 0) { if (istr.ReadByte() == 0) { put(PdfName.MASK, new PdfLiteral("[" + idx + " " + idx + "]")); break; } ++idx; } } break; } Image.skip(istr, len + 4); } else if (Png.IHDR.Equals(marker)) { int w = Png.getInt(istr); int h = Png.getInt(istr); int bitDepth = istr.ReadByte(); if (bitDepth == 16) { throw new BadPdfFormatException(errorID + " Bit depth 16 is not suported."); } put(PdfName.BITSPERCOMPONENT, new PdfNumber(bitDepth)); colorType = istr.ReadByte(); if (!(colorType == 0 || colorType == 2 || colorType == 3)) { throw new BadPdfFormatException(errorID + " Colortype " + colorType + " is not suported."); } if (colorType == 0) { put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); } else if (colorType == 2) { put(PdfName.COLORSPACE, PdfName.DEVICERGB); } int compressionMethod = istr.ReadByte(); int filterMethod = istr.ReadByte(); int interlaceMethod = istr.ReadByte(); if (interlaceMethod != 0) { throw new BadPdfFormatException(errorID + " Interlace method " + interlaceMethod + " is not suported."); } PdfDictionary decodeparms = new PdfDictionary(); decodeparms.put(PdfName.BITSPERCOMPONENT, new PdfNumber(bitDepth)); decodeparms.put(PdfName.PREDICTOR, new PdfNumber(15)); decodeparms.put(PdfName.COLUMNS, new PdfNumber(w)); decodeparms.put(PdfName.COLORS, new PdfNumber((colorType == 2) ? 3: 1)); put(PdfName.DECODEPARMS, decodeparms); Png.getInt(istr); } else if (Png.PLTE.Equals(marker)) { if (colorType == 3) { PdfArray colorspace = new PdfArray(); colorspace.Add(PdfName.INDEXED); colorspace.Add(PdfName.DEVICERGB); colorspace.Add(new PdfNumber(len / 3 - 1)); ByteBuffer colortable = new ByteBuffer(); while ((len--) > 0) { colortable.Append_i(istr.ReadByte()); } colorspace.Add(new PdfString(colortable.toByteArray())); put(PdfName.COLORSPACE, colorspace); Png.getInt(istr); } else { Image.skip(istr, len + 4); } } else if (Png.IEND.Equals(marker)) { break; } else { for (int j = -4; j < len; j++) { istr.ReadByte(); } } } break; case Element.JPEG: put(PdfName.FILTER, PdfName.DCTDECODE); switch (image.Colorspace) { case 1: put(PdfName.COLORSPACE, PdfName.DEVICEGRAY); break; case 3: put(PdfName.COLORSPACE, PdfName.DEVICERGB); break; default: put(PdfName.COLORSPACE, PdfName.DEVICECMYK); if (image.isInvertedJPEG()) { put(PdfName.DECODE, new PdfLiteral("[1 0 1 0 1 0 1 0]")); } break; } put(PdfName.BITSPERCOMPONENT, new PdfNumber(8)); if (image.RawData != null) { bytes = image.RawData; streamBytes = null; put(PdfName.LENGTH, new PdfNumber(bytes.Length)); return; } transferBytes(istr, streamBytes, -1); break; case Element.GIF: // HEADER + INFO + COLORTABLE // Byte 0-2: header // checks if the file really is a GIF-file if (istr.ReadByte() != 'G' || istr.ReadByte() != 'I' || istr.ReadByte() != 'F') { throw new BadPdfFormatException(errorID + " is not a GIF-file (GIF header not found)."); } put(PdfName.FILTER, PdfName.LZWDECODE); PdfDictionary decodeparams = new PdfDictionary(); decodeparams.put(PdfName.EARLYCHANGE, new PdfNumber(0)); put(PdfName.DECODEPARMS, decodeparams); PdfArray cspace = new PdfArray(); cspace.Add(PdfName.INDEXED); cspace.Add(PdfName.DEVICERGB); // Byte 3-5: version // Byte 6-7: logical screen width // Byte 8-9: logical screen height // Byte 10: Packed Fields for (int j = 0; j < 8; j++) { i = istr.ReadByte(); } // Byte 10: bit 1: Global Color Table Flag if ((i & 0x80) == 0) { throw new BadPdfFormatException(errorID + " is not a supported GIF-file (there is no global color table present)."); } // Byte 10: bit 6-8: Size of Global Color Table int nColors = 1 << ((i & 7) + 1); cspace.Add(new PdfNumber(nColors - 1)); // Byte 11: Background color index istr.ReadByte(); // Byte 12: Pixel aspect ratio istr.ReadByte(); // Byte 13-...: Global color table ByteBuffer ctable = new ByteBuffer(); for (int j = 0; j < nColors; j++) { ctable.Append_i(istr.ReadByte()); // red ctable.Append_i(istr.ReadByte()); // green ctable.Append_i(istr.ReadByte()); // blue } cspace.Add(new PdfString(ctable.toByteArray())); put(PdfName.COLORSPACE, cspace); put(PdfName.BITSPERCOMPONENT, new PdfNumber(8)); // IMAGE DESCRIPTOR // Byte 0: Image separator // only simple gif files with image immediate following global color table are supported // 0x2c is a fixed value for the image separator if (istr.ReadByte() != 0x2c) { throw new BadPdfFormatException(errorID + " is not a supported GIF-file (the image separator '0x2c' is not found after reading the color table)."); } // Byte 1-2: Image Left Position // Byte 3-4: Image Top Position // Byte 5-6: Image Width // Byte 7-8: Image Height // ignore position and size for (int j = 0; j < 8; j++) { istr.ReadByte(); } // Byte 9: Packed Fields // Byte 9: bit 1: Local Color Table Flag // Byte 9: bit 2: Interlace Flag if ((istr.ReadByte() & 0xc0) > 0) { throw new BadPdfFormatException(errorID + " is not a supported GIF-file (interlaced gifs or gifs using local color table can't be inserted)."); } // Byte 10: LZW initial code if (istr.ReadByte() != 0x08) { throw new BadPdfFormatException(errorID + " is not a supported GIF-file (initial LZW code not supported)."); } // Read the Image Data int code = 0; int codelength = 9; int tablelength = 257; int bitsread = 0; int bitstowrite = 0; int bitsdone = 0; int bitsleft = 23; int bytesdone = 0; int bytesread = 0; int byteswritten = 0; // read the size of the first Data Block int size = istr.ReadByte(); // Check if there is any data in the GIF if (size < 1) { throw new BadPdfFormatException(errorID + " is not a supported GIF-file. (no image data found)."); } // if possible, we read the first 24 bits of data size--; bytesread++; bitsread = istr.ReadByte(); if (size > 0) { size--; bytesread++; bitsread += (istr.ReadByte() << 8); if (size > 0) { size--; bytesread++; bitsread += (istr.ReadByte() << 16); } } while (bytesread > byteswritten) { tablelength++; // we extract a code with length=codelength code = (bitsread >> bitsdone) & ((1 << codelength) - 1); // we delete the bytesdone in bitsread and append the next byte(s) bytesdone = (bitsdone + codelength) / 8; bitsdone = (bitsdone + codelength) % 8; while (bytesdone > 0) { bytesdone--; bitsread = (bitsread >> 8); if (size > 0) { size--; bytesread++; bitsread += (istr.ReadByte() << 16); } else { size = istr.ReadByte(); if (size > 0) { size--; bytesread++; bitsread += (istr.ReadByte() << 16); } } } // we package all the bits that are done into bytes and write them to the stream bitstowrite += (code << (bitsleft - codelength + 1)); bitsleft -= codelength; while (bitsleft < 16) { streamBytes.WriteByte((byte)(bitstowrite >> 16)); byteswritten++; bitstowrite = (bitstowrite & 0xFFFF) << 8; bitsleft += 8; } if (code == 256) { codelength = 9; tablelength = 257; } if (code == 257) { break; } if (tablelength == (1 << codelength)) { codelength++; } } if (bytesread - byteswritten > 2) { throw new BadPdfFormatException(errorID + " is not a supported GIF-file (unexpected end of data block)."); } break; default: throw new BadPdfFormatException(errorID + " is an unknown Image format."); } put(PdfName.LENGTH, new PdfNumber(streamBytes.Length)); } catch (IOException ioe) { throw new BadPdfFormatException(ioe.Message); } finally { if (istr != null) { try{ istr.Close(); } catch (Exception ee) { ee.GetType(); // empty on purpose } } } }