private static void ProcessTiffImage(RandomAccessFileOrArray s, TiffImageHelper.TiffParameters tiff) { bool recoverFromImageError = tiff.image.IsRecoverFromImageError(); int page = tiff.image.GetPage(); bool direct = tiff.image.IsDirect(); if (page < 1) { throw new iText.IO.IOException(iText.IO.IOException.PageNumberMustBeGtEq1); } try { TIFFDirectory dir = new TIFFDirectory(s, page - 1); if (dir.IsTagPresent(TIFFConstants.TIFFTAG_TILEWIDTH)) { throw new iText.IO.IOException(iText.IO.IOException.TilesAreNotSupported); } int compression = TIFFConstants.COMPRESSION_NONE; if (dir.IsTagPresent(TIFFConstants.TIFFTAG_COMPRESSION)) { compression = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_COMPRESSION); } switch (compression) { case TIFFConstants.COMPRESSION_CCITTRLEW: case TIFFConstants.COMPRESSION_CCITTRLE: case TIFFConstants.COMPRESSION_CCITTFAX3: case TIFFConstants.COMPRESSION_CCITTFAX4: { break; } default: { ProcessTiffImageColor(dir, s, tiff); return; } } float rotation = 0; if (dir.IsTagPresent(TIFFConstants.TIFFTAG_ORIENTATION)) { int rot = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_ORIENTATION); if (rot == TIFFConstants.ORIENTATION_BOTRIGHT || rot == TIFFConstants.ORIENTATION_BOTLEFT) { rotation = (float)Math.PI; } else { if (rot == TIFFConstants.ORIENTATION_LEFTTOP || rot == TIFFConstants.ORIENTATION_LEFTBOT) { rotation = (float)(Math.PI / 2.0); } else { if (rot == TIFFConstants.ORIENTATION_RIGHTTOP || rot == TIFFConstants.ORIENTATION_RIGHTBOT) { rotation = -(float)(Math.PI / 2.0); } } } } long tiffT4Options = 0; long tiffT6Options = 0; int fillOrder = 1; int h = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_IMAGELENGTH); int w = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_IMAGEWIDTH); float XYRatio = 0; int resolutionUnit = TIFFConstants.RESUNIT_INCH; if (dir.IsTagPresent(TIFFConstants.TIFFTAG_RESOLUTIONUNIT)) { resolutionUnit = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_RESOLUTIONUNIT); } int dpiX = GetDpi(dir.GetField(TIFFConstants.TIFFTAG_XRESOLUTION), resolutionUnit); int dpiY = GetDpi(dir.GetField(TIFFConstants.TIFFTAG_YRESOLUTION), resolutionUnit); if (resolutionUnit == TIFFConstants.RESUNIT_NONE) { if (dpiY != 0) { XYRatio = (float)dpiX / (float)dpiY; } dpiX = 0; dpiY = 0; } int rowsStrip = h; if (dir.IsTagPresent(TIFFConstants.TIFFTAG_ROWSPERSTRIP)) { rowsStrip = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_ROWSPERSTRIP); } if (rowsStrip <= 0 || rowsStrip > h) { rowsStrip = h; } long[] offset = GetArrayLongShort(dir, TIFFConstants.TIFFTAG_STRIPOFFSETS); long[] size = GetArrayLongShort(dir, TIFFConstants.TIFFTAG_STRIPBYTECOUNTS); // some TIFF producers are really lousy, so... if ((size == null || (size.Length == 1 && (size[0] == 0 || size[0] + offset[0] > s.Length()))) && h == rowsStrip ) { size = new long[] { s.Length() - (int)offset[0] }; } bool reverse = false; TIFFField fillOrderField = dir.GetField(TIFFConstants.TIFFTAG_FILLORDER); if (fillOrderField != null) { fillOrder = fillOrderField.GetAsInt(0); } reverse = (fillOrder == TIFFConstants.FILLORDER_LSB2MSB); int parameters = 0; if (dir.IsTagPresent(TIFFConstants.TIFFTAG_PHOTOMETRIC)) { long photo = dir.GetFieldAsLong(TIFFConstants.TIFFTAG_PHOTOMETRIC); if (photo == TIFFConstants.PHOTOMETRIC_MINISBLACK) { parameters |= RawImageData.CCITT_BLACKIS1; } } int imagecomp = 0; switch (compression) { case TIFFConstants.COMPRESSION_CCITTRLEW: case TIFFConstants.COMPRESSION_CCITTRLE: { imagecomp = RawImageData.CCITTG3_1D; parameters |= RawImageData.CCITT_ENCODEDBYTEALIGN | RawImageData.CCITT_ENDOFBLOCK; break; } case TIFFConstants.COMPRESSION_CCITTFAX3: { imagecomp = RawImageData.CCITTG3_1D; parameters |= RawImageData.CCITT_ENDOFLINE | RawImageData.CCITT_ENDOFBLOCK; TIFFField t4OptionsField = dir.GetField(TIFFConstants.TIFFTAG_GROUP3OPTIONS); if (t4OptionsField != null) { tiffT4Options = t4OptionsField.GetAsLong(0); if ((tiffT4Options & TIFFConstants.GROUP3OPT_2DENCODING) != 0) { imagecomp = RawImageData.CCITTG3_2D; } if ((tiffT4Options & TIFFConstants.GROUP3OPT_FILLBITS) != 0) { parameters |= RawImageData.CCITT_ENCODEDBYTEALIGN; } } break; } case TIFFConstants.COMPRESSION_CCITTFAX4: { imagecomp = RawImageData.CCITTG4; TIFFField t6OptionsField = dir.GetField(TIFFConstants.TIFFTAG_GROUP4OPTIONS); if (t6OptionsField != null) { tiffT6Options = t6OptionsField.GetAsLong(0); } break; } } //single strip, direct if (direct && rowsStrip == h) { byte[] im = new byte[(int)size[0]]; s.Seek(offset[0]); s.ReadFully(im); RawImageHelper.UpdateRawImageParameters(tiff.image, w, h, false, imagecomp, parameters, im, null); tiff.image.SetInverted(true); } else { int rowsLeft = h; CCITTG4Encoder g4 = new CCITTG4Encoder(w); for (int k = 0; k < offset.Length; ++k) { byte[] im = new byte[(int)size[k]]; s.Seek(offset[k]); s.ReadFully(im); int height = Math.Min(rowsStrip, rowsLeft); TIFFFaxDecoder decoder = new TIFFFaxDecoder(fillOrder, w, height); decoder.SetRecoverFromImageError(recoverFromImageError); byte[] outBuf = new byte[(w + 7) / 8 * height]; switch (compression) { case TIFFConstants.COMPRESSION_CCITTRLEW: case TIFFConstants.COMPRESSION_CCITTRLE: { decoder.Decode1D(outBuf, im, 0, height); g4.Fax4Encode(outBuf, height); break; } case TIFFConstants.COMPRESSION_CCITTFAX3: { try { decoder.Decode2D(outBuf, im, 0, height, tiffT4Options); } catch (Exception e) { // let's flip the fill bits and try again... tiffT4Options ^= TIFFConstants.GROUP3OPT_FILLBITS; try { decoder.Decode2D(outBuf, im, 0, height, tiffT4Options); } catch (Exception) { if (!recoverFromImageError) { throw e; } if (rowsStrip == 1) { throw e; } // repeat of reading the tiff directly (the if section of this if else structure) // copy pasted to avoid making a method with 10 tiff im = new byte[(int)size[0]]; s.Seek(offset[0]); s.ReadFully(im); RawImageHelper.UpdateRawImageParameters(tiff.image, w, h, false, imagecomp, parameters, im, null); tiff.image.SetInverted(true); tiff.image.SetDpi(dpiX, dpiY); tiff.image.SetXYRatio(XYRatio); if (rotation != 0) { tiff.image.SetRotation(rotation); } return; } } g4.Fax4Encode(outBuf, height); break; } case TIFFConstants.COMPRESSION_CCITTFAX4: { try { decoder.DecodeT6(outBuf, im, 0, height, tiffT6Options); } catch (iText.IO.IOException e) { if (!recoverFromImageError) { throw; } } g4.Fax4Encode(outBuf, height); break; } } rowsLeft -= rowsStrip; } byte[] g4pic = g4.Close(); RawImageHelper.UpdateRawImageParameters(tiff.image, w, h, false, RawImageData.CCITTG4, parameters & RawImageData .CCITT_BLACKIS1, g4pic, null); } tiff.image.SetDpi(dpiX, dpiY); if (dir.IsTagPresent(TIFFConstants.TIFFTAG_ICCPROFILE)) { try { TIFFField fd = dir.GetField(TIFFConstants.TIFFTAG_ICCPROFILE); IccProfile icc_prof = IccProfile.GetInstance(fd.GetAsBytes()); if (icc_prof.GetNumComponents() == 1) { tiff.image.SetProfile(icc_prof); } } catch (Exception) { } } //empty if (rotation != 0) { tiff.image.SetRotation(rotation); } } catch (Exception) { throw new iText.IO.IOException(iText.IO.IOException.CannotReadTiffImage); } }
/// <summary>This method checks if the image is a valid JPEG and processes some parameters.</summary> private static void ProcessParameters(Stream jpegStream, String errorID, ImageData image) { byte[][] icc = null; if (jpegStream.Read() != 0xFF || jpegStream.Read() != 0xD8) { throw new iText.IO.IOException(iText.IO.IOException._1IsNotAValidJpegFile).SetMessageParams(errorID); } bool firstPass = true; int len; while (true) { int v = jpegStream.Read(); if (v < 0) { throw new iText.IO.IOException(iText.IO.IOException.PrematureEofWhileReadingJpeg); } if (v == 0xFF) { int marker = jpegStream.Read(); if (firstPass && marker == M_APP0) { firstPass = false; len = GetShort(jpegStream); if (len < 16) { StreamUtil.Skip(jpegStream, len - 2); continue; } byte[] bcomp = new byte[JFIF_ID.Length]; int r = jpegStream.Read(bcomp); if (r != bcomp.Length) { throw new iText.IO.IOException(iText.IO.IOException._1CorruptedJfifMarker).SetMessageParams(errorID); } bool found = true; for (int k = 0; k < bcomp.Length; ++k) { if (bcomp[k] != JFIF_ID[k]) { found = false; break; } } if (!found) { StreamUtil.Skip(jpegStream, len - 2 - bcomp.Length); continue; } StreamUtil.Skip(jpegStream, 2); int units = jpegStream.Read(); int dx = GetShort(jpegStream); int dy = GetShort(jpegStream); if (units == 1) { image.SetDpi(dx, dy); } else { if (units == 2) { image.SetDpi((int)(dx * 2.54f + 0.5f), (int)(dy * 2.54f + 0.5f)); } } StreamUtil.Skip(jpegStream, len - 2 - bcomp.Length - 7); continue; } if (marker == M_APPE) { len = GetShort(jpegStream) - 2; byte[] byteappe = new byte[len]; for (int k = 0; k < len; ++k) { byteappe[k] = (byte)jpegStream.Read(); } if (byteappe.Length >= 12) { String appe = iText.IO.Util.JavaUtil.GetStringForBytes(byteappe, 0, 5, "ISO-8859-1"); if (appe.Equals("Adobe")) { image.SetInverted(true); } } continue; } if (marker == M_APP2) { len = GetShort(jpegStream) - 2; byte[] byteapp2 = new byte[len]; for (int k = 0; k < len; ++k) { byteapp2[k] = (byte)jpegStream.Read(); } if (byteapp2.Length >= 14) { String app2 = iText.IO.Util.JavaUtil.GetStringForBytes(byteapp2, 0, 11, "ISO-8859-1"); if (app2.Equals("ICC_PROFILE")) { int order = byteapp2[12] & 0xff; int count = byteapp2[13] & 0xff; // some jpeg producers don't know how to count to 1 if (order < 1) { order = 1; } if (count < 1) { count = 1; } if (icc == null) { icc = new byte[count][]; } icc[order - 1] = byteapp2; } } continue; } if (marker == M_APPD) { len = GetShort(jpegStream) - 2; byte[] byteappd = new byte[len]; for (int k = 0; k < len; k++) { byteappd[k] = (byte)jpegStream.Read(); } // search for '8BIM Resolution' marker int k_1; for (k_1 = 0; k_1 < len - PS_8BIM_RESO.Length; k_1++) { bool found = true; for (int j = 0; j < PS_8BIM_RESO.Length; j++) { if (byteappd[k_1 + j] != PS_8BIM_RESO[j]) { found = false; break; } } if (found) { break; } } k_1 += PS_8BIM_RESO.Length; if (k_1 < len - PS_8BIM_RESO.Length) { // "PASCAL String" for name, i.e. string prefix with length byte // padded to be even length; 2 null bytes if empty byte namelength = byteappd[k_1]; // add length byte namelength++; // add padding if (namelength % 2 == 1) { namelength++; } // just skip name k_1 += namelength; // size of the resolution data int resosize = (byteappd[k_1] << 24) + (byteappd[k_1 + 1] << 16) + (byteappd[k_1 + 2] << 8) + byteappd[k_1 + 3]; // should be 16 if (resosize != 16) { // fail silently, for now //System.err.println("DEBUG: unsupported resolution IRB size"); continue; } k_1 += 4; int dx = (byteappd[k_1] << 8) + (byteappd[k_1 + 1] & 0xff); k_1 += 2; // skip 2 unknown bytes k_1 += 2; int unitsx = (byteappd[k_1] << 8) + (byteappd[k_1 + 1] & 0xff); k_1 += 2; // skip 2 unknown bytes k_1 += 2; int dy = (byteappd[k_1] << 8) + (byteappd[k_1 + 1] & 0xff); k_1 += 2; // skip 2 unknown bytes k_1 += 2; int unitsy = (byteappd[k_1] << 8) + (byteappd[k_1 + 1] & 0xff); if (unitsx == 1 || unitsx == 2) { dx = (unitsx == 2 ? (int)(dx * 2.54f + 0.5f) : dx); // make sure this is consistent with JFIF data if (image.GetDpiX() != 0 && image.GetDpiX() != dx) { ILog logger = LogManager.GetLogger(typeof(JpegImageHelper)); logger.Debug(MessageFormatUtil.Format("Inconsistent metadata (dpiX: {0} vs {1})", image.GetDpiX(), dx)); } else { image.SetDpi(dx, image.GetDpiY()); } } if (unitsy == 1 || unitsy == 2) { dy = (unitsy == 2 ? (int)(dy * 2.54f + 0.5f) : dy); // make sure this is consistent with JFIF data if (image.GetDpiY() != 0 && image.GetDpiY() != dy) { ILog logger = LogManager.GetLogger(typeof(JpegImageHelper)); logger.Debug(MessageFormatUtil.Format("Inconsistent metadata (dpiY: {0} vs {1})", image.GetDpiY(), dy)); } else { image.SetDpi(image.GetDpiX(), dx); } } } continue; } firstPass = false; int markertype = Marker(marker); if (markertype == VALID_MARKER) { StreamUtil.Skip(jpegStream, 2); if (jpegStream.Read() != 0x08) { throw new iText.IO.IOException(iText.IO.IOException._1MustHave8BitsPerComponent).SetMessageParams(errorID); } image.SetHeight(GetShort(jpegStream)); image.SetWidth(GetShort(jpegStream)); image.SetColorSpace(jpegStream.Read()); image.SetBpc(8); break; } else { if (markertype == UNSUPPORTED_MARKER) { throw new iText.IO.IOException(iText.IO.IOException._1UnsupportedJpegMarker2).SetMessageParams(errorID, JavaUtil.IntegerToString (marker)); } else { if (markertype != NOPARAM_MARKER) { StreamUtil.Skip(jpegStream, GetShort(jpegStream) - 2); } } } } } if (icc != null) { int total = 0; for (int k = 0; k < icc.Length; ++k) { if (icc[k] == null) { icc = null; return; } total += icc[k].Length - 14; } byte[] ficc = new byte[total]; total = 0; for (int k = 0; k < icc.Length; ++k) { Array.Copy(icc[k], 14, ficc, total, icc[k].Length - 14); total += icc[k].Length - 14; } try { image.SetProfile(IccProfile.GetInstance(ficc, image.GetColorSpace())); } catch (ArgumentException) { } } }
private static void ReadPng(Stream pngStream, PngImageHelper.PngParameters png) { for (int i = 0; i < PNGID.Length; i++) { if (PNGID[i] != pngStream.Read()) { throw new System.IO.IOException("file.is.not.a.valid.png"); } } byte[] buffer = new byte[TRANSFERSIZE]; while (true) { int len = GetInt(pngStream); String marker = GetString(pngStream); if (len < 0 || !CheckMarker(marker)) { throw new System.IO.IOException("corrupted.png.file"); } if (IDAT.Equals(marker)) { int size; while (len != 0) { size = pngStream.JRead(buffer, 0, Math.Min(len, TRANSFERSIZE)); if (size < 0) { return; } png.idat.Write(buffer, 0, size); len -= size; } } else { if (tRNS.Equals(marker)) { switch (png.image.GetColorType()) { case 0: { if (len >= 2) { len -= 2; int gray = GetWord(pngStream); if (png.bitDepth == 16) { png.transRedGray = gray; } else { png.additional.Put(PngImageHelperConstants.MASK, MessageFormatUtil.Format("[{0} {1}]", gray, gray)); } } break; } case 2: { if (len >= 6) { len -= 6; int red = GetWord(pngStream); int green = GetWord(pngStream); int blue = GetWord(pngStream); if (png.bitDepth == 16) { png.transRedGray = red; png.transGreen = green; png.transBlue = blue; } else { png.additional.Put(PngImageHelperConstants.MASK, MessageFormatUtil.Format("[{0} {1} {2} {3} {4} {5}]", red , red, green, green, blue, blue)); } } break; } case 3: { if (len > 0) { png.trans = new byte[len]; for (int k = 0; k < len; ++k) { png.trans[k] = (byte)pngStream.Read(); } len = 0; } break; } } StreamUtil.Skip(pngStream, len); } else { if (IHDR.Equals(marker)) { png.width = GetInt(pngStream); png.height = GetInt(pngStream); png.bitDepth = pngStream.Read(); png.image.SetColorType(pngStream.Read()); png.compressionMethod = pngStream.Read(); png.filterMethod = pngStream.Read(); png.interlaceMethod = pngStream.Read(); } else { if (PLTE.Equals(marker)) { if (png.image.IsIndexed()) { ByteBuffer colorTableBuf = new ByteBuffer(); while ((len--) > 0) { colorTableBuf.Append(pngStream.Read()); } png.image.SetColorPalette(colorTableBuf.ToByteArray()); } else { StreamUtil.Skip(pngStream, len); } } else { if (pHYs.Equals(marker)) { int dx = GetInt(pngStream); int dy = GetInt(pngStream); int unit = pngStream.Read(); if (unit == 1) { png.dpiX = (int)(dx * 0.0254f + 0.5f); png.dpiY = (int)(dy * 0.0254f + 0.5f); } else { if (dy != 0) { png.XYRatio = (float)dx / (float)dy; } } } else { if (cHRM.Equals(marker)) { PngChromaticities pngChromaticities = new PngChromaticities(GetInt(pngStream) / 100000f, GetInt(pngStream) / 100000f, GetInt(pngStream) / 100000f, GetInt(pngStream) / 100000f, GetInt(pngStream) / 100000f, GetInt (pngStream) / 100000f, GetInt(pngStream) / 100000f, GetInt(pngStream) / 100000f); if (!(Math.Abs(pngChromaticities.GetXW()) < 0.0001f || Math.Abs(pngChromaticities.GetYW()) < 0.0001f || Math .Abs(pngChromaticities.GetXR()) < 0.0001f || Math.Abs(pngChromaticities.GetYR()) < 0.0001f || Math.Abs (pngChromaticities.GetXG()) < 0.0001f || Math.Abs(pngChromaticities.GetYG()) < 0.0001f || Math.Abs(pngChromaticities .GetXB()) < 0.0001f || Math.Abs(pngChromaticities.GetYB()) < 0.0001f)) { png.image.SetPngChromaticities(pngChromaticities); } } else { if (sRGB.Equals(marker)) { int ri = pngStream.Read(); png.intent = intents[ri]; png.image.SetGamma(2.2f); PngChromaticities pngChromaticities = new PngChromaticities(0.3127f, 0.329f, 0.64f, 0.33f, 0.3f, 0.6f, 0.15f , 0.06f); png.image.SetPngChromaticities(pngChromaticities); } else { if (gAMA.Equals(marker)) { int gm = GetInt(pngStream); if (gm != 0) { png.image.SetGamma(100000f / gm); if (!png.image.IsHasCHRM()) { PngChromaticities pngChromaticities = new PngChromaticities(0.3127f, 0.329f, 0.64f, 0.33f, 0.3f, 0.6f, 0.15f , 0.06f); png.image.SetPngChromaticities(pngChromaticities); } } } else { if (iCCP.Equals(marker)) { do { --len; }while (pngStream.Read() != 0); pngStream.Read(); --len; byte[] icccom = new byte[len]; int p = 0; while (len > 0) { int r = pngStream.JRead(icccom, p, len); if (r < 0) { throw new System.IO.IOException("premature.end.of.file"); } p += r; len -= r; } byte[] iccp = FilterUtil.FlateDecode(icccom, true); icccom = null; try { png.iccProfile = IccProfile.GetInstance(iccp); } catch (Exception) { png.iccProfile = null; } } else { if (IEND.Equals(marker)) { break; } else { StreamUtil.Skip(pngStream, len); } } } } } } } } } } StreamUtil.Skip(pngStream, 4); } }
private static void ProcessTiffImageColor(TIFFDirectory dir, RandomAccessFileOrArray s, TiffImageHelper.TiffParameters tiff) { try { int compression = TIFFConstants.COMPRESSION_NONE; if (dir.IsTagPresent(TIFFConstants.TIFFTAG_COMPRESSION)) { compression = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_COMPRESSION); } int predictor = 1; TIFFLZWDecoder lzwDecoder = null; switch (compression) { case TIFFConstants.COMPRESSION_NONE: case TIFFConstants.COMPRESSION_LZW: case TIFFConstants.COMPRESSION_PACKBITS: case TIFFConstants.COMPRESSION_DEFLATE: case TIFFConstants.COMPRESSION_ADOBE_DEFLATE: case TIFFConstants.COMPRESSION_OJPEG: case TIFFConstants.COMPRESSION_JPEG: { break; } default: { throw new iText.IO.IOException(iText.IO.IOException.Compression1IsNotSupported).SetMessageParams(compression ); } } int photometric = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_PHOTOMETRIC); switch (photometric) { case TIFFConstants.PHOTOMETRIC_MINISWHITE: case TIFFConstants.PHOTOMETRIC_MINISBLACK: case TIFFConstants.PHOTOMETRIC_RGB: case TIFFConstants.PHOTOMETRIC_SEPARATED: case TIFFConstants.PHOTOMETRIC_PALETTE: { break; } default: { if (compression != TIFFConstants.COMPRESSION_OJPEG && compression != TIFFConstants.COMPRESSION_JPEG) { throw new iText.IO.IOException(iText.IO.IOException.Photometric1IsNotSupported).SetMessageParams(photometric ); } break; } } float rotation = 0; if (dir.IsTagPresent(TIFFConstants.TIFFTAG_ORIENTATION)) { int rot = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_ORIENTATION); if (rot == TIFFConstants.ORIENTATION_BOTRIGHT || rot == TIFFConstants.ORIENTATION_BOTLEFT) { rotation = (float)Math.PI; } else { if (rot == TIFFConstants.ORIENTATION_LEFTTOP || rot == TIFFConstants.ORIENTATION_LEFTBOT) { rotation = (float)(Math.PI / 2.0); } else { if (rot == TIFFConstants.ORIENTATION_RIGHTTOP || rot == TIFFConstants.ORIENTATION_RIGHTBOT) { rotation = -(float)(Math.PI / 2.0); } } } } if (dir.IsTagPresent(TIFFConstants.TIFFTAG_PLANARCONFIG) && dir.GetFieldAsLong(TIFFConstants.TIFFTAG_PLANARCONFIG ) == TIFFConstants.PLANARCONFIG_SEPARATE) { throw new iText.IO.IOException(iText.IO.IOException.PlanarImagesAreNotSupported); } int extraSamples = 0; if (dir.IsTagPresent(TIFFConstants.TIFFTAG_EXTRASAMPLES)) { extraSamples = 1; } int samplePerPixel = 1; // 1,3,4 if (dir.IsTagPresent(TIFFConstants.TIFFTAG_SAMPLESPERPIXEL)) { samplePerPixel = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_SAMPLESPERPIXEL); } int bitsPerSample = 1; if (dir.IsTagPresent(TIFFConstants.TIFFTAG_BITSPERSAMPLE)) { bitsPerSample = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_BITSPERSAMPLE); } switch (bitsPerSample) { case 1: case 2: case 4: case 8: { break; } default: { throw new iText.IO.IOException(iText.IO.IOException.BitsPerSample1IsNotSupported).SetMessageParams(bitsPerSample ); } } int h = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_IMAGELENGTH); int w = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_IMAGEWIDTH); int dpiX; int dpiY; int resolutionUnit = TIFFConstants.RESUNIT_INCH; if (dir.IsTagPresent(TIFFConstants.TIFFTAG_RESOLUTIONUNIT)) { resolutionUnit = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_RESOLUTIONUNIT); } dpiX = GetDpi(dir.GetField(TIFFConstants.TIFFTAG_XRESOLUTION), resolutionUnit); dpiY = GetDpi(dir.GetField(TIFFConstants.TIFFTAG_YRESOLUTION), resolutionUnit); int fillOrder = 1; TIFFField fillOrderField = dir.GetField(TIFFConstants.TIFFTAG_FILLORDER); if (fillOrderField != null) { fillOrder = fillOrderField.GetAsInt(0); } bool reverse = (fillOrder == TIFFConstants.FILLORDER_LSB2MSB); int rowsStrip = h; // another hack for broken tiffs if (dir.IsTagPresent(TIFFConstants.TIFFTAG_ROWSPERSTRIP)) { rowsStrip = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_ROWSPERSTRIP); } if (rowsStrip <= 0 || rowsStrip > h) { rowsStrip = h; } long[] offset = GetArrayLongShort(dir, TIFFConstants.TIFFTAG_STRIPOFFSETS); long[] size = GetArrayLongShort(dir, TIFFConstants.TIFFTAG_STRIPBYTECOUNTS); // some TIFF producers are really lousy, so... if ((size == null || (size.Length == 1 && (size[0] == 0 || size[0] + offset[0] > s.Length()))) && h == rowsStrip ) { size = new long[] { s.Length() - (int)offset[0] }; } if (compression == TIFFConstants.COMPRESSION_LZW || compression == TIFFConstants.COMPRESSION_DEFLATE || compression == TIFFConstants.COMPRESSION_ADOBE_DEFLATE) { TIFFField predictorField = dir.GetField(TIFFConstants.TIFFTAG_PREDICTOR); if (predictorField != null) { predictor = predictorField.GetAsInt(0); if (predictor != 1 && predictor != 2) { throw new iText.IO.IOException(iText.IO.IOException.IllegalValueForPredictorInTiffFile); } if (predictor == 2 && bitsPerSample != 8) { throw new iText.IO.IOException(iText.IO.IOException._1BitSamplesAreNotSupportedForHorizontalDifferencingPredictor ).SetMessageParams(bitsPerSample); } } } if (compression == TIFFConstants.COMPRESSION_LZW) { lzwDecoder = new TIFFLZWDecoder(w, predictor, samplePerPixel); } int rowsLeft = h; ByteArrayOutputStream stream = null; ByteArrayOutputStream mstream = null; DeflaterOutputStream zip = null; DeflaterOutputStream mzip = null; if (extraSamples > 0) { mstream = new ByteArrayOutputStream(); mzip = new DeflaterOutputStream(mstream); } CCITTG4Encoder g4 = null; if (bitsPerSample == 1 && samplePerPixel == 1 && photometric != TIFFConstants.PHOTOMETRIC_PALETTE) { g4 = new CCITTG4Encoder(w); } else { stream = new ByteArrayOutputStream(); if (compression != TIFFConstants.COMPRESSION_OJPEG && compression != TIFFConstants.COMPRESSION_JPEG) { zip = new DeflaterOutputStream(stream); } } if (compression == TIFFConstants.COMPRESSION_OJPEG) { // Assume that the TIFFTAG_JPEGIFBYTECOUNT tag is optional, since it's obsolete and // is often missing if ((!dir.IsTagPresent(TIFFConstants.TIFFTAG_JPEGIFOFFSET))) { throw new iText.IO.IOException(iText.IO.IOException.MissingTagsForOjpegCompression); } int jpegOffset = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_JPEGIFOFFSET); int jpegLength = (int)s.Length() - jpegOffset; if (dir.IsTagPresent(TIFFConstants.TIFFTAG_JPEGIFBYTECOUNT)) { jpegLength = (int)dir.GetFieldAsLong(TIFFConstants.TIFFTAG_JPEGIFBYTECOUNT) + (int)size[0]; } byte[] jpeg = new byte[Math.Min(jpegLength, (int)s.Length() - jpegOffset)]; int posFilePointer = (int)s.GetPosition(); posFilePointer += jpegOffset; s.Seek(posFilePointer); s.ReadFully(jpeg); tiff.image.data = jpeg; tiff.image.SetOriginalType(ImageType.JPEG); JpegImageHelper.ProcessImage(tiff.image); tiff.jpegProcessing = true; } else { if (compression == TIFFConstants.COMPRESSION_JPEG) { if (size.Length > 1) { throw new iText.IO.IOException(iText.IO.IOException.CompressionJpegIsOnlySupportedWithASingleStripThisImageHas1Strips ).SetMessageParams(size.Length); } byte[] jpeg = new byte[(int)size[0]]; s.Seek(offset[0]); s.ReadFully(jpeg); // if quantization and/or Huffman tables are stored separately in the tiff, // we need to add them to the jpeg data TIFFField jpegtables = dir.GetField(TIFFConstants.TIFFTAG_JPEGTABLES); if (jpegtables != null) { byte[] temp = jpegtables.GetAsBytes(); int tableoffset = 0; int tablelength = temp.Length; // remove FFD8 from start if (temp[0] == (byte)0xFF && temp[1] == (byte)0xD8) { tableoffset = 2; tablelength -= 2; } // remove FFD9 from end if (temp[temp.Length - 2] == (byte)0xFF && temp[temp.Length - 1] == (byte)0xD9) { tablelength -= 2; } byte[] tables = new byte[tablelength]; Array.Copy(temp, tableoffset, tables, 0, tablelength); // TODO insert after JFIF header, instead of at the start byte[] jpegwithtables = new byte[jpeg.Length + tables.Length]; Array.Copy(jpeg, 0, jpegwithtables, 0, 2); Array.Copy(tables, 0, jpegwithtables, 2, tables.Length); Array.Copy(jpeg, 2, jpegwithtables, tables.Length + 2, jpeg.Length - 2); jpeg = jpegwithtables; } tiff.image.data = jpeg; tiff.image.SetOriginalType(ImageType.JPEG); JpegImageHelper.ProcessImage(tiff.image); tiff.jpegProcessing = true; if (photometric == TIFFConstants.PHOTOMETRIC_RGB) { tiff.image.SetColorTransform(0); } } else { for (int k = 0; k < offset.Length; ++k) { byte[] im = new byte[(int)size[k]]; s.Seek(offset[k]); s.ReadFully(im); int height = Math.Min(rowsStrip, rowsLeft); byte[] outBuf = null; if (compression != TIFFConstants.COMPRESSION_NONE) { outBuf = new byte[(w * bitsPerSample * samplePerPixel + 7) / 8 * height]; } if (reverse) { TIFFFaxDecoder.ReverseBits(im); } switch (compression) { case TIFFConstants.COMPRESSION_DEFLATE: case TIFFConstants.COMPRESSION_ADOBE_DEFLATE: { FilterUtil.InflateData(im, outBuf); ApplyPredictor(outBuf, predictor, w, height, samplePerPixel); break; } case TIFFConstants.COMPRESSION_NONE: { outBuf = im; break; } case TIFFConstants.COMPRESSION_PACKBITS: { DecodePackbits(im, outBuf); break; } case TIFFConstants.COMPRESSION_LZW: { lzwDecoder.Decode(im, outBuf, height); break; } } if (bitsPerSample == 1 && samplePerPixel == 1 && photometric != TIFFConstants.PHOTOMETRIC_PALETTE) { g4.Fax4Encode(outBuf, height); } else { if (extraSamples > 0) { ProcessExtraSamples(zip, mzip, outBuf, samplePerPixel, bitsPerSample, w, height); } else { zip.Write(outBuf); } } rowsLeft -= rowsStrip; } if (bitsPerSample == 1 && samplePerPixel == 1 && photometric != TIFFConstants.PHOTOMETRIC_PALETTE) { RawImageHelper.UpdateRawImageParameters(tiff.image, w, h, false, RawImageData.CCITTG4, photometric == TIFFConstants .PHOTOMETRIC_MINISBLACK ? RawImageData.CCITT_BLACKIS1 : 0, g4.Close(), null); } else { zip.Dispose(); RawImageHelper.UpdateRawImageParameters(tiff.image, w, h, samplePerPixel - extraSamples, bitsPerSample, stream .ToArray()); tiff.image.SetDeflated(true); } } } tiff.image.SetDpi(dpiX, dpiY); if (compression != TIFFConstants.COMPRESSION_OJPEG && compression != TIFFConstants.COMPRESSION_JPEG) { if (dir.IsTagPresent(TIFFConstants.TIFFTAG_ICCPROFILE)) { try { TIFFField fd = dir.GetField(TIFFConstants.TIFFTAG_ICCPROFILE); IccProfile icc_prof = IccProfile.GetInstance(fd.GetAsBytes()); if (samplePerPixel - extraSamples == icc_prof.GetNumComponents()) { tiff.image.SetProfile(icc_prof); } } catch (Exception) { } } //empty if (dir.IsTagPresent(TIFFConstants.TIFFTAG_COLORMAP)) { TIFFField fd = dir.GetField(TIFFConstants.TIFFTAG_COLORMAP); char[] rgb = fd.GetAsChars(); byte[] palette = new byte[rgb.Length]; int gColor = rgb.Length / 3; int bColor = gColor * 2; for (int k = 0; k < gColor; ++k) { //there is no sense in >>> for unsigned char palette[k * 3] = (byte)(rgb[k] >> 8); palette[k * 3 + 1] = (byte)(rgb[k + gColor] >> 8); palette[k * 3 + 2] = (byte)(rgb[k + bColor] >> 8); } // Colormap components are supposed to go from 0 to 655535 but, // as usually, some tiff producers just put values from 0 to 255. // Let's check for these broken tiffs. bool colormapBroken = true; for (int k = 0; k < palette.Length; ++k) { if (palette[k] != 0) { colormapBroken = false; break; } } if (colormapBroken) { for (int k = 0; k < gColor; ++k) { palette[k * 3] = (byte)rgb[k]; palette[k * 3 + 1] = (byte)rgb[k + gColor]; palette[k * 3 + 2] = (byte)rgb[k + bColor]; } } Object[] indexed = new Object[4]; indexed[0] = "/Indexed"; indexed[1] = "/DeviceRGB"; indexed[2] = gColor - 1; indexed[3] = PdfEncodings.ConvertToString(palette, null); tiff.additional = new Dictionary <String, Object>(); tiff.additional.Put("ColorSpace", indexed); } } if (photometric == TIFFConstants.PHOTOMETRIC_MINISWHITE) { tiff.image.SetInverted(true); } if (rotation != 0) { tiff.image.SetRotation(rotation); } if (extraSamples > 0) { mzip.Dispose(); RawImageData mimg = (RawImageData)ImageDataFactory.CreateRawImage(null); RawImageHelper.UpdateRawImageParameters(mimg, w, h, 1, bitsPerSample, mstream.ToArray()); mimg.MakeMask(); mimg.SetDeflated(true); tiff.image.SetImageMask(mimg); } } catch (Exception) { throw new iText.IO.IOException(iText.IO.IOException.CannotGetTiffImageColor); } }
public static PdfStream GetIccProfileStream(Stream iccStream, float[] range) { IccProfile iccProfile = IccProfile.GetInstance(iccStream); return(GetIccProfileStream(iccProfile, range)); }
void readPng() { for (int i = 0; i < Pngid.Length; i++) { if (Pngid[i] != _isp.ReadByte()) { throw new IOException("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("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)(dx * 0.0254f + 0.5f); _dpiY = (int)(dy * 0.0254f + 0.5f); } else { if (dy != 0) { _xyRatio = dx / (float)dy; } } } else if (cHRM.Equals(marker)) { _xW = GetInt(_isp) / 100000f; _yW = GetInt(_isp) / 100000f; _xR = GetInt(_isp) / 100000f; _yR = GetInt(_isp) / 100000f; _xG = GetInt(_isp) / 100000f; _yG = GetInt(_isp) / 100000f; _xB = GetInt(_isp) / 100000f; _yB = 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 / 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("Premature end of file."); } p += r; len -= r; } byte[] iccp = PdfReader.FlateDecode(icccom, true); icccom = null; try { _iccProfile = IccProfile.GetInstance(iccp); } catch { _iccProfile = null; } } else if (IEND.Equals(marker)) { break; } else { Utilities.Skip(_isp, len); } Utilities.Skip(_isp, 4); } }
public static PdfStream GetIccProfileStream(Stream iccStream) { IccProfile iccProfile = IccProfile.GetInstance(iccStream); return(GetIccProfileStream(iccProfile)); }
/// <summary> /// Reads a page from a TIFF image. /// by direct byte copying. It's faster but may not work /// every time /// </summary> /// <param name="s">the file source</param> /// <param name="page">the page to get. The first page is 1</param> /// <param name="direct">for single strip, CCITT images, generate the image</param> /// <returns>the Image </returns> public static Image GetTiffImage(RandomAccessFileOrArray s, int page, bool direct) { if (page < 1) { throw new InvalidOperationException("The page number must be >= 1."); } var dir = new TiffDirectory(s, page - 1); if (dir.IsTagPresent(TiffConstants.TIFFTAG_TILEWIDTH)) { throw new InvalidOperationException("Tiles are not supported."); } var compression = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_COMPRESSION); switch (compression) { case TiffConstants.COMPRESSION_CCITTRLEW: case TiffConstants.COMPRESSION_CCITTRLE: case TiffConstants.COMPRESSION_CCITTFAX3: case TiffConstants.COMPRESSION_CCITTFAX4: break; default: return(GetTiffImageColor(dir, s)); } float rotation = 0; if (dir.IsTagPresent(TiffConstants.TIFFTAG_ORIENTATION)) { var rot = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_ORIENTATION); if (rot == TiffConstants.ORIENTATION_BOTRIGHT || rot == TiffConstants.ORIENTATION_BOTLEFT) { rotation = (float)Math.PI; } else if (rot == TiffConstants.ORIENTATION_LEFTTOP || rot == TiffConstants.ORIENTATION_LEFTBOT) { rotation = (float)(Math.PI / 2.0); } else if (rot == TiffConstants.ORIENTATION_RIGHTTOP || rot == TiffConstants.ORIENTATION_RIGHTBOT) { rotation = -(float)(Math.PI / 2.0); } } Image img = null; long tiffT4Options = 0; long tiffT6Options = 0; var fillOrder = 1; var h = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_IMAGELENGTH); var w = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_IMAGEWIDTH); var dpiX = 0; var dpiY = 0; float xyRatio = 0; var resolutionUnit = TiffConstants.RESUNIT_INCH; if (dir.IsTagPresent(TiffConstants.TIFFTAG_RESOLUTIONUNIT)) { resolutionUnit = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_RESOLUTIONUNIT); } dpiX = getDpi(dir.GetField(TiffConstants.TIFFTAG_XRESOLUTION), resolutionUnit); dpiY = getDpi(dir.GetField(TiffConstants.TIFFTAG_YRESOLUTION), resolutionUnit); if (resolutionUnit == TiffConstants.RESUNIT_NONE) { if (dpiY != 0) { xyRatio = dpiX / (float)dpiY; } dpiX = 0; dpiY = 0; } var rowsStrip = h; if (dir.IsTagPresent(TiffConstants.TIFFTAG_ROWSPERSTRIP)) { rowsStrip = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_ROWSPERSTRIP); } if (rowsStrip <= 0 || rowsStrip > h) { rowsStrip = h; } var offset = getArrayLongShort(dir, TiffConstants.TIFFTAG_STRIPOFFSETS); var size = getArrayLongShort(dir, TiffConstants.TIFFTAG_STRIPBYTECOUNTS); if ((size == null || (size.Length == 1 && (size[0] == 0 || size[0] + offset[0] > s.Length))) && h == rowsStrip) { // some TIFF producers are really lousy, so... size = new long[] { s.Length - (int)offset[0] }; } var reverse = false; var fillOrderField = dir.GetField(TiffConstants.TIFFTAG_FILLORDER); if (fillOrderField != null) { fillOrder = fillOrderField.GetAsInt(0); } reverse = (fillOrder == TiffConstants.FILLORDER_LSB2MSB); var paramsn = 0; if (dir.IsTagPresent(TiffConstants.TIFFTAG_PHOTOMETRIC)) { var photo = dir.GetFieldAsLong(TiffConstants.TIFFTAG_PHOTOMETRIC); if (photo == TiffConstants.PHOTOMETRIC_MINISBLACK) { paramsn |= Element.CCITT_BLACKIS1; } } var imagecomp = 0; switch (compression) { case TiffConstants.COMPRESSION_CCITTRLEW: case TiffConstants.COMPRESSION_CCITTRLE: imagecomp = Element.CCITTG3_1D; paramsn |= Element.CCITT_ENCODEDBYTEALIGN | Element.CCITT_ENDOFBLOCK; break; case TiffConstants.COMPRESSION_CCITTFAX3: imagecomp = Element.CCITTG3_1D; paramsn |= Element.CCITT_ENDOFLINE | Element.CCITT_ENDOFBLOCK; var t4OptionsField = dir.GetField(TiffConstants.TIFFTAG_GROUP3OPTIONS); if (t4OptionsField != null) { tiffT4Options = t4OptionsField.GetAsLong(0); if ((tiffT4Options & TiffConstants.GROUP3OPT_2DENCODING) != 0) { imagecomp = Element.CCITTG3_2D; } if ((tiffT4Options & TiffConstants.GROUP3OPT_FILLBITS) != 0) { paramsn |= Element.CCITT_ENCODEDBYTEALIGN; } } break; case TiffConstants.COMPRESSION_CCITTFAX4: imagecomp = Element.CCITTG4; var t6OptionsField = dir.GetField(TiffConstants.TIFFTAG_GROUP4OPTIONS); if (t6OptionsField != null) { tiffT6Options = t6OptionsField.GetAsLong(0); } break; } if (direct && rowsStrip == h) { //single strip, direct var im = new byte[(int)size[0]]; s.Seek(offset[0]); s.ReadFully(im); img = Image.GetInstance(w, h, false, imagecomp, paramsn, im); img.Inverted = true; } else { var rowsLeft = h; var g4 = new Ccittg4Encoder(w); for (var k = 0; k < offset.Length; ++k) { var im = new byte[(int)size[k]]; s.Seek(offset[k]); s.ReadFully(im); var height = Math.Min(rowsStrip, rowsLeft); var decoder = new TiffFaxDecoder(fillOrder, w, height); var outBuf = new byte[(w + 7) / 8 * height]; switch (compression) { case TiffConstants.COMPRESSION_CCITTRLEW: case TiffConstants.COMPRESSION_CCITTRLE: decoder.Decode1D(outBuf, im, 0, height); g4.Fax4Encode(outBuf, height); break; case TiffConstants.COMPRESSION_CCITTFAX3: try { decoder.Decode2D(outBuf, im, 0, height, tiffT4Options); } catch (Exception e) { // let's flip the fill bits and try again... tiffT4Options ^= TiffConstants.GROUP3OPT_FILLBITS; try { decoder.Decode2D(outBuf, im, 0, height, tiffT4Options); } catch { throw e; } } g4.Fax4Encode(outBuf, height); break; case TiffConstants.COMPRESSION_CCITTFAX4: decoder.DecodeT6(outBuf, im, 0, height, tiffT6Options); g4.Fax4Encode(outBuf, height); break; } rowsLeft -= rowsStrip; } var g4Pic = g4.Close(); img = Image.GetInstance(w, h, false, Element.CCITTG4, paramsn & Element.CCITT_BLACKIS1, g4Pic); } img.SetDpi(dpiX, dpiY); img.XyRatio = xyRatio; if (dir.IsTagPresent(TiffConstants.TIFFTAG_ICCPROFILE)) { try { var fd = dir.GetField(TiffConstants.TIFFTAG_ICCPROFILE); var iccProf = IccProfile.GetInstance(fd.GetAsBytes()); if (iccProf.NumComponents == 1) { img.TagIcc = iccProf; } } catch { //empty } } img.OriginalType = Image.ORIGINAL_TIFF; if (rotation.ApproxNotEqual(0)) { img.InitialRotation = rotation; } return(img); }
protected static Image GetTiffImageColor(TiffDirectory dir, RandomAccessFileOrArray s) { var predictor = 1; TifflzwDecoder lzwDecoder = null; var compression = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_COMPRESSION); switch (compression) { case TiffConstants.COMPRESSION_NONE: case TiffConstants.COMPRESSION_LZW: case TiffConstants.COMPRESSION_PACKBITS: case TiffConstants.COMPRESSION_DEFLATE: case TiffConstants.COMPRESSION_ADOBE_DEFLATE: case TiffConstants.COMPRESSION_OJPEG: case TiffConstants.COMPRESSION_JPEG: break; default: throw new InvalidOperationException("The compression " + compression + " is not supported."); } var photometric = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_PHOTOMETRIC); switch (photometric) { case TiffConstants.PHOTOMETRIC_MINISWHITE: case TiffConstants.PHOTOMETRIC_MINISBLACK: case TiffConstants.PHOTOMETRIC_RGB: case TiffConstants.PHOTOMETRIC_SEPARATED: case TiffConstants.PHOTOMETRIC_PALETTE: break; default: if (compression != TiffConstants.COMPRESSION_OJPEG && compression != TiffConstants.COMPRESSION_JPEG) { throw new InvalidOperationException("The photometric " + photometric + " is not supported."); } break; } float rotation = 0; if (dir.IsTagPresent(TiffConstants.TIFFTAG_ORIENTATION)) { var rot = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_ORIENTATION); if (rot == TiffConstants.ORIENTATION_BOTRIGHT || rot == TiffConstants.ORIENTATION_BOTLEFT) { rotation = (float)Math.PI; } else if (rot == TiffConstants.ORIENTATION_LEFTTOP || rot == TiffConstants.ORIENTATION_LEFTBOT) { rotation = (float)(Math.PI / 2.0); } else if (rot == TiffConstants.ORIENTATION_RIGHTTOP || rot == TiffConstants.ORIENTATION_RIGHTBOT) { rotation = -(float)(Math.PI / 2.0); } } if (dir.IsTagPresent(TiffConstants.TIFFTAG_PLANARCONFIG) && dir.GetFieldAsLong(TiffConstants.TIFFTAG_PLANARCONFIG) == TiffConstants.PLANARCONFIG_SEPARATE) { throw new InvalidOperationException("Planar images are not supported."); } if (dir.IsTagPresent(TiffConstants.TIFFTAG_EXTRASAMPLES)) { throw new InvalidOperationException("Extra samples are not supported."); } var samplePerPixel = 1; if (dir.IsTagPresent(TiffConstants.TIFFTAG_SAMPLESPERPIXEL)) // 1,3,4 { samplePerPixel = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_SAMPLESPERPIXEL); } var bitsPerSample = 1; if (dir.IsTagPresent(TiffConstants.TIFFTAG_BITSPERSAMPLE)) { bitsPerSample = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_BITSPERSAMPLE); } switch (bitsPerSample) { case 1: case 2: case 4: case 8: break; default: throw new InvalidOperationException("Bits per sample " + bitsPerSample + " is not supported."); } Image img = null; var h = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_IMAGELENGTH); var w = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_IMAGEWIDTH); var dpiX = 0; var dpiY = 0; var resolutionUnit = TiffConstants.RESUNIT_INCH; if (dir.IsTagPresent(TiffConstants.TIFFTAG_RESOLUTIONUNIT)) { resolutionUnit = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_RESOLUTIONUNIT); } dpiX = getDpi(dir.GetField(TiffConstants.TIFFTAG_XRESOLUTION), resolutionUnit); dpiY = getDpi(dir.GetField(TiffConstants.TIFFTAG_YRESOLUTION), resolutionUnit); var fillOrder = 1; var reverse = false; var fillOrderField = dir.GetField(TiffConstants.TIFFTAG_FILLORDER); if (fillOrderField != null) { fillOrder = fillOrderField.GetAsInt(0); } reverse = (fillOrder == TiffConstants.FILLORDER_LSB2MSB); var rowsStrip = h; if (dir.IsTagPresent(TiffConstants.TIFFTAG_ROWSPERSTRIP)) //another hack for broken tiffs { rowsStrip = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_ROWSPERSTRIP); } if (rowsStrip <= 0 || rowsStrip > h) { rowsStrip = h; } var offset = getArrayLongShort(dir, TiffConstants.TIFFTAG_STRIPOFFSETS); var size = getArrayLongShort(dir, TiffConstants.TIFFTAG_STRIPBYTECOUNTS); if ((size == null || (size.Length == 1 && (size[0] == 0 || size[0] + offset[0] > s.Length))) && h == rowsStrip) { // some TIFF producers are really lousy, so... size = new long[] { s.Length - (int)offset[0] }; } if (compression == TiffConstants.COMPRESSION_LZW) { var predictorField = dir.GetField(TiffConstants.TIFFTAG_PREDICTOR); if (predictorField != null) { predictor = predictorField.GetAsInt(0); if (predictor != 1 && predictor != 2) { throw new InvalidOperationException("Illegal value for Predictor in TIFF file."); } if (predictor == 2 && bitsPerSample != 8) { throw new InvalidOperationException(bitsPerSample + "-bit samples are not supported for Horizontal differencing Predictor."); } } lzwDecoder = new TifflzwDecoder(w, predictor, samplePerPixel); } var rowsLeft = h; MemoryStream stream = null; ZDeflaterOutputStream zip = null; Ccittg4Encoder g4 = null; if (bitsPerSample == 1 && samplePerPixel == 1) { g4 = new Ccittg4Encoder(w); } else { stream = new MemoryStream(); if (compression != TiffConstants.COMPRESSION_OJPEG && compression != TiffConstants.COMPRESSION_JPEG) { zip = new ZDeflaterOutputStream(stream); } } if (compression == TiffConstants.COMPRESSION_OJPEG) { // Assume that the TIFFTAG_JPEGIFBYTECOUNT tag is optional, since it's obsolete and // is often missing if ((!dir.IsTagPresent(TiffConstants.TIFFTAG_JPEGIFOFFSET))) { throw new IOException("Missing tag(s) for OJPEG compression."); } var jpegOffset = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_JPEGIFOFFSET); var jpegLength = s.Length - jpegOffset; if (dir.IsTagPresent(TiffConstants.TIFFTAG_JPEGIFBYTECOUNT)) { jpegLength = (int)dir.GetFieldAsLong(TiffConstants.TIFFTAG_JPEGIFBYTECOUNT) + (int)size[0]; } var jpeg = new byte[Math.Min(jpegLength, s.Length - jpegOffset)]; var posFilePointer = s.FilePointer; posFilePointer += jpegOffset; s.Seek(posFilePointer); s.ReadFully(jpeg); img = new Jpeg(jpeg); } else if (compression == TiffConstants.COMPRESSION_JPEG) { if (size.Length > 1) { throw new IOException("Compression JPEG is only supported with a single strip. This image has " + size.Length + " strips."); } var jpeg = new byte[(int)size[0]]; s.Seek(offset[0]); s.ReadFully(jpeg); img = new Jpeg(jpeg); } else { for (var k = 0; k < offset.Length; ++k) { var im = new byte[(int)size[k]]; s.Seek(offset[k]); s.ReadFully(im); var height = Math.Min(rowsStrip, rowsLeft); byte[] outBuf = null; if (compression != TiffConstants.COMPRESSION_NONE) { outBuf = new byte[(w * bitsPerSample * samplePerPixel + 7) / 8 * height]; } if (reverse) { TiffFaxDecoder.ReverseBits(im); } switch (compression) { case TiffConstants.COMPRESSION_DEFLATE: case TiffConstants.COMPRESSION_ADOBE_DEFLATE: Inflate(im, outBuf); break; case TiffConstants.COMPRESSION_NONE: outBuf = im; break; case TiffConstants.COMPRESSION_PACKBITS: DecodePackbits(im, outBuf); break; case TiffConstants.COMPRESSION_LZW: lzwDecoder.Decode(im, outBuf, height); break; } if (bitsPerSample == 1 && samplePerPixel == 1) { g4.Fax4Encode(outBuf, height); } else { zip.Write(outBuf, 0, outBuf.Length); } rowsLeft -= rowsStrip; } if (bitsPerSample == 1 && samplePerPixel == 1) { img = Image.GetInstance(w, h, false, Element.CCITTG4, photometric == TiffConstants.PHOTOMETRIC_MINISBLACK ? Element.CCITT_BLACKIS1 : 0, g4.Close()); } else { zip.Close(); img = Image.GetInstance(w, h, samplePerPixel, bitsPerSample, stream.ToArray()); img.Deflated = true; } } img.SetDpi(dpiX, dpiY); if (compression != TiffConstants.COMPRESSION_OJPEG && compression != TiffConstants.COMPRESSION_JPEG) { if (dir.IsTagPresent(TiffConstants.TIFFTAG_ICCPROFILE)) { try { var fd = dir.GetField(TiffConstants.TIFFTAG_ICCPROFILE); var iccProf = IccProfile.GetInstance(fd.GetAsBytes()); if (samplePerPixel == iccProf.NumComponents) { img.TagIcc = iccProf; } } catch { //empty } } if (dir.IsTagPresent(TiffConstants.TIFFTAG_COLORMAP)) { var fd = dir.GetField(TiffConstants.TIFFTAG_COLORMAP); var rgb = fd.GetAsChars(); var palette = new byte[rgb.Length]; var gColor = rgb.Length / 3; var bColor = gColor * 2; for (var k = 0; k < gColor; ++k) { palette[k * 3] = (byte)(rgb[k] >> 8); palette[k * 3 + 1] = (byte)(rgb[k + gColor] >> 8); palette[k * 3 + 2] = (byte)(rgb[k + bColor] >> 8); } var indexed = new PdfArray(); indexed.Add(PdfName.Indexed); indexed.Add(PdfName.Devicergb); indexed.Add(new PdfNumber(gColor - 1)); indexed.Add(new PdfString(palette)); var additional = new PdfDictionary(); additional.Put(PdfName.Colorspace, indexed); img.Additional = additional; } img.OriginalType = Image.ORIGINAL_TIFF; } if (photometric == TiffConstants.PHOTOMETRIC_MINISWHITE) { img.Inverted = true; } if (rotation.ApproxNotEqual(0)) { img.InitialRotation = rotation; } return(img); }
/// <exception cref="System.IO.IOException"/> private static void ReadPng(Stream pngStream, PngImageHelper.PngParameters png) { for (int i = 0; i < PNGID.Length; i++) { if (PNGID[i] != pngStream.Read()) { throw new System.IO.IOException("file.is.not.a.valid.png"); } } byte[] buffer = new byte[TRANSFERSIZE]; while (true) { int len = GetInt(pngStream); String marker = GetString(pngStream); if (len < 0 || !CheckMarker(marker)) { throw new System.IO.IOException("corrupted.png.file"); } if (IDAT.Equals(marker)) { int size; while (len != 0) { size = pngStream.JRead(buffer, 0, Math.Min(len, TRANSFERSIZE)); if (size < 0) { return; } png.idat.Write(buffer, 0, size); len -= size; } } else { if (tRNS.Equals(marker)) { switch (png.colorType) { case 0: { if (len >= 2) { len -= 2; int gray = GetWord(pngStream); if (png.bitDepth == 16) { png.transRedGray = gray; } else { png.additional.Put("Mask", MessageFormatUtil.Format("[{0} {1}]", gray, gray)); } } break; } case 2: { if (len >= 6) { len -= 6; int red = GetWord(pngStream); int green = GetWord(pngStream); int blue = GetWord(pngStream); if (png.bitDepth == 16) { png.transRedGray = red; png.transGreen = green; png.transBlue = blue; } else { png.additional.Put("Mask", MessageFormatUtil.Format("[{0} {1} {2} {3} {4} {5}]", red, red, green, green, blue , blue)); } } break; } case 3: { if (len > 0) { png.trans = new byte[len]; for (int k = 0; k < len; ++k) { png.trans[k] = (byte)pngStream.Read(); } len = 0; } break; } } StreamUtil.Skip(pngStream, len); } else { if (IHDR.Equals(marker)) { png.width = GetInt(pngStream); png.height = GetInt(pngStream); png.bitDepth = pngStream.Read(); png.colorType = pngStream.Read(); png.compressionMethod = pngStream.Read(); png.filterMethod = pngStream.Read(); png.interlaceMethod = pngStream.Read(); } else { if (PLTE.Equals(marker)) { if (png.colorType == 3) { Object[] colorspace = new Object[4]; colorspace[0] = "/Indexed"; colorspace[1] = GetColorspace(png); colorspace[2] = len / 3 - 1; ByteBuffer colorTableBuf = new ByteBuffer(); while ((len--) > 0) { colorTableBuf.Append(pngStream.Read()); } png.colorTable = colorTableBuf.ToByteArray(); colorspace[3] = PdfEncodings.ConvertToString(png.colorTable, null); png.additional.Put("ColorSpace", colorspace); } else { StreamUtil.Skip(pngStream, len); } } else { if (pHYs.Equals(marker)) { int dx = GetInt(pngStream); int dy = GetInt(pngStream); int unit = pngStream.Read(); if (unit == 1) { png.dpiX = (int)(dx * 0.0254f + 0.5f); png.dpiY = (int)(dy * 0.0254f + 0.5f); } else { if (dy != 0) { png.XYRatio = (float)dx / (float)dy; } } } else { if (cHRM.Equals(marker)) { png.xW = GetInt(pngStream) / 100000f; png.yW = GetInt(pngStream) / 100000f; png.xR = GetInt(pngStream) / 100000f; png.yR = GetInt(pngStream) / 100000f; png.xG = GetInt(pngStream) / 100000f; png.yG = GetInt(pngStream) / 100000f; png.xB = GetInt(pngStream) / 100000f; png.yB = GetInt(pngStream) / 100000f; png.hasCHRM = !(Math.Abs(png.xW) < 0.0001f || Math.Abs(png.yW) < 0.0001f || Math.Abs(png.xR) < 0.0001f || Math.Abs(png.yR) < 0.0001f || Math.Abs(png.xG) < 0.0001f || Math.Abs(png.yG) < 0.0001f || Math.Abs(png .xB) < 0.0001f || Math.Abs(png.yB) < 0.0001f); } else { if (sRGB.Equals(marker)) { int ri = pngStream.Read(); png.intent = intents[ri]; png.gamma = 2.2f; png.xW = 0.3127f; png.yW = 0.329f; png.xR = 0.64f; png.yR = 0.33f; png.xG = 0.3f; png.yG = 0.6f; png.xB = 0.15f; png.yB = 0.06f; png.hasCHRM = true; } else { if (gAMA.Equals(marker)) { int gm = GetInt(pngStream); if (gm != 0) { png.gamma = 100000f / gm; if (!png.hasCHRM) { png.xW = 0.3127f; png.yW = 0.329f; png.xR = 0.64f; png.yR = 0.33f; png.xG = 0.3f; png.yG = 0.6f; png.xB = 0.15f; png.yB = 0.06f; png.hasCHRM = true; } } } else { if (iCCP.Equals(marker)) { do { --len; }while (pngStream.Read() != 0); pngStream.Read(); --len; byte[] icccom = new byte[len]; int p = 0; while (len > 0) { int r = pngStream.JRead(icccom, p, len); if (r < 0) { throw new System.IO.IOException("premature.end.of.file"); } p += r; len -= r; } byte[] iccp = FilterUtil.FlateDecode(icccom, true); icccom = null; try { png.iccProfile = IccProfile.GetInstance(iccp); } catch (Exception) { png.iccProfile = null; } } else { if (IEND.Equals(marker)) { break; } else { StreamUtil.Skip(pngStream, len); } } } } } } } } } } StreamUtil.Skip(pngStream, 4); } }
/// <summary> /// private methods /// </summary> /// <summary> /// This method checks if the image is a valid JPEG and processes some parameters. /// </summary> private void processParameters() { type = JPEG; originalType = ORIGINAL_JPEG; Stream istr = null; try { string errorId; if (rawData == null) { istr = url.GetResponseStream(); errorId = url.ToString(); } else { istr = new MemoryStream(rawData); errorId = "Byte array"; } if (istr.ReadByte() != 0xFF || istr.ReadByte() != 0xD8) { throw new BadElementException(errorId + " is not a valid JPEG-file."); } bool firstPass = true; int len; while (true) { int v = istr.ReadByte(); if (v < 0) { throw new IOException("Premature EOF while reading JPG."); } if (v == 0xFF) { int marker = istr.ReadByte(); if (firstPass && marker == M_APP0) { firstPass = false; len = getShort(istr); if (len < 16) { Utilities.Skip(istr, len - 2); continue; } byte[] bcomp = new byte[JfifId.Length]; int r = istr.Read(bcomp, 0, bcomp.Length); if (r != bcomp.Length) { throw new BadElementException(errorId + " corrupted JFIF marker."); } bool found = true; for (int k = 0; k < bcomp.Length; ++k) { if (bcomp[k] != JfifId[k]) { found = false; break; } } if (!found) { Utilities.Skip(istr, len - 2 - bcomp.Length); continue; } Utilities.Skip(istr, 2); int units = istr.ReadByte(); int dx = getShort(istr); int dy = getShort(istr); if (units == 1) { dpiX = dx; dpiY = dy; } else if (units == 2) { dpiX = (int)(dx * 2.54f + 0.5f); dpiY = (int)(dy * 2.54f + 0.5f); } Utilities.Skip(istr, len - 2 - bcomp.Length - 7); continue; } if (marker == M_APPE) { len = getShort(istr) - 2; byte[] byteappe = new byte[len]; for (int k = 0; k < len; ++k) { byteappe[k] = (byte)istr.ReadByte(); } if (byteappe.Length >= 12) { string appe = System.Text.Encoding.ASCII.GetString(byteappe, 0, 5); if (Util.EqualsIgnoreCase(appe, "adobe")) { Invert = true; } } continue; } if (marker == M_APP2) { len = getShort(istr) - 2; byte[] byteapp2 = new byte[len]; for (int k = 0; k < len; ++k) { byteapp2[k] = (byte)istr.ReadByte(); } if (byteapp2.Length >= 14) { string app2 = System.Text.Encoding.ASCII.GetString(byteapp2, 0, 11); if (app2.Equals("ICC_PROFILE")) { int order = byteapp2[12] & 0xff; int count = byteapp2[13] & 0xff; if (_icc == null) { _icc = new byte[count][]; } _icc[order - 1] = byteapp2; } } continue; } firstPass = false; int markertype = markerType(marker); if (markertype == VALID_MARKER) { Utilities.Skip(istr, 2); if (istr.ReadByte() != 0x08) { throw new BadElementException(errorId + " must have 8 bits per component."); } scaledHeight = getShort(istr); Top = scaledHeight; scaledWidth = getShort(istr); Right = scaledWidth; colorspace = istr.ReadByte(); bpc = 8; break; } else if (markertype == UNSUPPORTED_MARKER) { throw new BadElementException(errorId + ": unsupported JPEG marker: " + marker); } else if (markertype != NOPARAM_MARKER) { Utilities.Skip(istr, getShort(istr) - 2); } } } } finally { if (istr != null) { istr.Dispose(); } } plainWidth = Width; plainHeight = Height; if (_icc != null) { int total = 0; for (int k = 0; k < _icc.Length; ++k) { if (_icc[k] == null) { _icc = null; return; } total += _icc[k].Length - 14; } byte[] ficc = new byte[total]; total = 0; for (int k = 0; k < _icc.Length; ++k) { Array.Copy(_icc[k], 14, ficc, total, _icc[k].Length - 14); total += _icc[k].Length - 14; } try { IccProfile iccProf = IccProfile.GetInstance(ficc); TagIcc = iccProf; } catch { } _icc = null; } }