public void Decode12BitRawBE(TIFFBinaryReader input, UInt32 w, UInt32 h) { if (w < 2) { throw new IOException("Are you mad? 1 pixel wide raw images are no fun"); } UInt32 pitch = mRaw.pitch; if (input.getRemainSize() < ((w * 12 / 8) * h)) { if ((UInt32)input.getRemainSize() > (w * 12 / 8)) { h = (uint)(input.getRemainSize() / (w * 12 / 8) - 1); mRaw.errors.Add("Image truncated (file is too short)"); } else { throw new IOException("readUncompressedRaw: Not enough data to decode a single line. Image file truncated."); } } for (UInt32 y = 0; y < h; y++) { for (UInt32 x = 0; x < w; x += 2) { UInt32 g1 = input.ReadByte(); UInt32 g2 = input.ReadByte(); mRaw.rawData[y * pitch + x] = (ushort)((g1 << 4) | (g2 >> 4)); UInt32 g3 = input.ReadByte(); mRaw.rawData[y * pitch + x + 1] = (ushort)(((g2 & 0x0f) << 8) | g3); } } }
/* * void DecodeThread() * { * DngDecoderThread me = _this; * DngDecoderSlices parent = me.parent; * try * { * Task * parent.decodeSlice(me); * } * catch (Exception) * { * parent.mRaw.errors.Add("DNGDEcodeThread: Caught exception."); * } * return; * }*/ public DngDecoderSlices(TIFFBinaryReader file, RawImage img, int _compression) { mFile = (file); mRaw = (img); mFixLjpeg = false; compression = _compression; }
public void Decode12BitRawUnpacked(TIFFBinaryReader input, UInt32 w, UInt32 h) { UInt32 pitch = mRaw.pitch; if (input.getRemainSize() < w * h * 2) { if ((UInt32)input.getRemainSize() > w * 2) { h = (uint)(input.getRemainSize() / (w * 2) - 1); mRaw.errors.Add("Image truncated (file is too short)"); } else { throw new IOException("readUncompressedRaw: Not enough data to decode a single line. Image file truncated."); } } for (UInt32 y = 0; y < h; y++) { for (UInt32 x = 0; x < w; x += 1) { UInt32 g1 = input.ReadByte(); UInt32 g2 = input.ReadByte(); mRaw.rawData[y * pitch + x] = (ushort)(((g2 << 8) | g1) >> 4); } } }
/*** Used for entropy encoded sections, for now only Nikon Coolpix ***/ public BitPumpMSB32(ref TIFFBinaryReader s) { s.Read(buffer, (int)s.Position, (int)s.BaseStream.Length); size = (uint)(s.getRemainSize() + sizeof(UInt32)); MIN_GET_BITS = (BITS_PER_LONG_LONG - 33); init(); }
public NikonDecompressor(TIFFBinaryReader file, RawImage img) : base(file, img) { for (UInt32 i = 0; i < 0x8000; i++) { curve[i] = (ushort)i; } }
/*** Used for entropy encoded sections ***/ public BitPumpMSB(ref TIFFBinaryReader s, uint offset, uint count) { MIN_GET_BITS = (BITS_PER_LONG - 7); size = count + sizeof(UInt32); buffer = new byte[size]; s.BaseStream.Position = offset; s.BaseStream.Read(buffer, 0, (int)count); init(); }
/* Construct decoder instance - FileMap is a filemap of the file to be decoded */ /* The FileMap is not owned by this class, will not be deleted, and must remain */ /* valid while this object exists */ public RawDecoder(ref TIFFBinaryReader file) { mRaw = new RawImage(); mFile = file; decoderVersion = 0; failOnUnknown = false; interpolateBadPixels = false; applyStage1DngOpcodes = true; applyCrop = true; uncorrectedRawValues = false; fujiRotate = true; }
public void parseData() { if (stream.Length < 16) { throw new TiffParserException("Not a TIFF file (size too small)"); } Endianness endian = Endianness.little; byte[] data = new byte[5]; stream.Position = 0; stream.Read(data, 0, 4); if (data[0] == 0x4D || data[1] == 0x4D) { //open binaryreader reader = new TIFFBinaryReaderRE(stream); endian = Endianness.big; if (data[3] != 42 && data[2] != 0x4f) // ORF sometimes has 0x4f, Lovely! { throw new TiffParserException("Not a TIFF file (magic 42)"); } } else if (data[0] == 0x49 || data[1] == 0x49) { reader = new TIFFBinaryReader(stream); if (data[2] != 42 && data[2] != 0x52 && data[2] != 0x55) // ORF has 0x52, RW2 0x55 - Brillant! { throw new TiffParserException("Not a TIFF file (magic 42)"); } } else { throw new TiffParserException("Not a TIFF file (ID)"); } UInt32 nextIFD; reader.Position = 4; nextIFD = reader.ReadUInt32(); rootIFD = new IFD(reader, nextIFD, endian, 0); nextIFD = rootIFD.nextOffset; while (nextIFD != 0) { rootIFD.subIFD.Add(new IFD(reader, nextIFD, endian, 0)); if (rootIFD.subIFD.Count > 100) { throw new TiffParserException("TIFF file has too many SubIFDs, probably broken"); } nextIFD = (rootIFD.subIFD[rootIFD.subIFD.Count - 1]).nextOffset; } }
public void Decode12BitRawBEInterlaced(TIFFBinaryReader input, UInt32 w, UInt32 h) { if (w < 2) { throw new IOException("Are you mad? 1 pixel wide raw images are no fun"); } UInt32 pitch = mRaw.pitch; if (input.getRemainSize() < ((w * 12 / 8) * h)) { if ((UInt32)input.getRemainSize() > (w * 12 / 8)) { h = (uint)(input.getRemainSize() / (w * 12 / 8) - 1); mRaw.errors.Add("Image truncated (file is too short)"); } else { throw new IOException("readUncompressedRaw: Not enough data to decode a single line. Image file truncated."); } } UInt32 half = (h + 1) >> 1; UInt32 y = 0; for (UInt32 row = 0; row < h; row++) { y = row % half * 2 + row / half; if (y == 1) { // The second field starts at a 2048 byte aligment UInt32 offset = ((half * w * 3 / 2 >> 11) + 1) << 11; if (offset > input.getRemainSize()) { throw new IOException("Decode12BitSplitRaw: Trying to jump to invalid offset " + offset); } input.Position = offset; } for (UInt32 x = 0; x < w; x += 2) { UInt32 g1 = input.ReadByte(); UInt32 g2 = input.ReadByte(); mRaw.rawData[y * pitch + x] = (ushort)((g1 << 4) | (g2 >> 4)); UInt32 g3 = input.ReadByte(); mRaw.rawData[y * pitch + x + 1] = (ushort)(((g2 & 0x0f) << 8) | g3); } } }
public LJpegDecompressor(TIFFBinaryReader file, RawImage img) { mRaw = (img); input = file; skipX = skipY = 0; for (int i = 0; i < 4; i++) { huff[i].initialized = false; huff[i].bigTable = null; } mDNGCompatible = false; slicesW.Clear(); mUseBigtable = false; mCanonFlipDim = false; mCanonDoubleHeight = false; }
public void Decode12BitRawBEWithControl(ref TIFFBinaryReader input, UInt32 w, UInt32 h) { if (w < 2) { throw new IOException("Are you mad? 1 pixel wide raw images are no fun"); } UInt32 pitch = mRaw.pitch; // Calulate expected bytes per line. UInt32 perline = (w * 12 / 8); // Add skips every 10 pixels perline += ((w + 2) / 10); // If file is too short, only decode as many lines as we have if (input.getRemainSize() < (perline * h)) { if ((UInt32)input.getRemainSize() > perline) { h = (uint)(input.getRemainSize() / perline - 1); mRaw.errors.Add("Image truncated (file is too short)"); } else { throw new IOException("Decode12BitRawBEWithControl: Not enough data to decode a single line. Image file truncated."); } } UInt32 x; for (UInt32 y = 0; y < h; y++) { for (x = 0; x < w; x += 2) { UInt32 g1 = input.ReadByte(); UInt32 g2 = input.ReadByte(); mRaw.rawData[(y * pitch) + x] = (ushort)((g1 << 4) | (g2 >> 4)); UInt32 g3 = input.ReadByte(); mRaw.rawData[(y * pitch) + x + 1] = (ushort)(((g2 & 0x0f) << 8) | g3); if ((x % 10) == 8) { input.Position++; } } } }
public void getSOF(SOFInfo sof, UInt32 offset, UInt32 size) { if (!input.isValid(offset, size)) { throw new Exception("getSOF: Start offset plus size is longer than file. Truncated file."); } try { Endianness host_endian = Common.getHostEndianness(); // JPEG is big endian if (host_endian == Endianness.big) { input = new TIFFBinaryReader(input.BaseStream, offset, size); } else { input = new TIFFBinaryReaderRE(input.BaseStream, offset, size); } if (getNextMarker(false) != JpegMarker.M_SOI) { throw new Exception("getSOF: Image did not start with SOI. Probably not an LJPEG"); } while (true) { JpegMarker m = getNextMarker(true); if (JpegMarker.M_SOF3 == m) { parseSOF(sof); return; } if (JpegMarker.M_EOI == m) { throw new Exception("LJpegDecompressor: Could not locate Start of Frame."); } } } catch (IOException) { throw new Exception("LJpegDecompressor: IO exception, read outside file. Corrupt File."); } }
public DngDecoder(IFD rootIFD, ref TIFFBinaryReader file) : base(ref file) { mRootIFD = (rootIFD); List <IFD> data = mRootIFD.getIFDsWithTag(TagType.DNGVERSION); var v = data[0].getEntry(TagType.DNGVERSION).data; if ((byte)v[0] != 1) { throw new RawDecoderException("Not a supported DNG image format: " + (int)v[0] + (int)v[1] + (int)v[2] + (int)v[3]); } // if (v[1] > 4) // throw new RawDecoderException("Not a supported DNG image format: v%u.%u.%u.%u", (int)v[0], (int)v[1], (int)v[2], (int)v[3]); if (((byte)v[0] <= 1) && ((byte)v[1] < 1)) // Prior to v1.1.xxx fix LJPEG encoding bug { mFixLjpeg = true; } else { mFixLjpeg = false; } }
public void Decode8BitRaw(ref TIFFBinaryReader input, UInt32 w, UInt32 h) { ushort[] data = mRaw.rawData; UInt32 pitch = mRaw.pitch; if (input.getRemainSize() < w * h) { if ((UInt32)input.getRemainSize() > w) { h = (uint)(input.getRemainSize() / w - 1); mRaw.errors.Add("Image truncated (file is too short)"); } else { throw new IOException("Decode8BitRaw: Not enough data to decode a single line. Image file truncated."); } } UInt32 random = 0; for (UInt32 y = 0; y < h; y++) { for (UInt32 x = 0; x < w; x += 1) { if (uncorrectedRawValues) { mRaw.rawData[(y * pitch) + x] = input.ReadByte(); } else { mRaw.setWithLookUp(input.ReadByte(), ref mRaw.rawData, x, ref random); input.Position++; } } } }
protected override Thumbnail decodeThumbInternal() { //find the preview IFD (usually the first if any) try { List <IFD> potential = mRootIFD.getIFDsWithTag(TagType.NEWSUBFILETYPE); if (potential != null || potential.Count != 0) { IFD thumbIFD = null; for (int i = 0; i < potential.Count; i++) { var subFile = potential[i].getEntry(TagType.NEWSUBFILETYPE); if (subFile.getInt() == 1) { thumbIFD = potential[i]; break; } } if (thumbIFD != null) { //there is a thumbnail UInt32 sample_format = 1; UInt32 bps = thumbIFD.getEntry(TagType.BITSPERSAMPLE).getUInt(); iPoint2D dim; if (thumbIFD.hasEntry(TagType.SAMPLEFORMAT)) { sample_format = thumbIFD.getEntry(TagType.SAMPLEFORMAT).getUInt(); } try { dim = new iPoint2D() { x = thumbIFD.getEntry(TagType.IMAGEWIDTH).getInt(), y = thumbIFD.getEntry(TagType.IMAGELENGTH).getInt() }; } catch (TiffParserException) { throw new RawDecoderException("DNG Decoder: Could not read basic image information."); } int compression = thumbIFD.getEntry(TagType.COMPRESSION).getShort(); // Now load the image if (compression == 1) { // Uncompressed. UInt32 cpp = thumbIFD.getEntry(TagType.SAMPLESPERPIXEL).getUInt(); if (cpp > 4) { throw new RawDecoderException("DNG Decoder: More than 4 samples per pixel is not supported."); } Tag offsets = thumbIFD.getEntry(TagType.STRIPOFFSETS); Tag counts = thumbIFD.getEntry(TagType.STRIPBYTECOUNTS); UInt32 yPerSlice = thumbIFD.getEntry(TagType.ROWSPERSTRIP).getUInt(); UInt32 width = thumbIFD.getEntry(TagType.IMAGEWIDTH).getUInt(); UInt32 height = thumbIFD.getEntry(TagType.IMAGELENGTH).getUInt(); if (counts.dataCount != offsets.dataCount) { throw new RawDecoderException("DNG Decoder: Byte count number does not match strip size: count:" + counts.dataCount + ", strips:" + offsets.dataCount); } UInt32 offY = 0; List <DngStrip> slices = new List <DngStrip>(); for (UInt32 s = 0; s < offsets.dataCount; s++) { DngStrip slice = new DngStrip(); slice.offset = offsets.getUInt(s); slice.count = counts.getUInt(s); slice.offsetY = offY; if (offY + yPerSlice > height) { slice.h = height - offY; } else { slice.h = yPerSlice; } offY += yPerSlice; if (mFile.isValid(slice.offset, slice.count)) // Only decode if size is valid { slices.Add(slice); } } for (int i = 0; i < slices.Count; i++) { DngStrip slice = slices[i]; TIFFBinaryReader input = new TIFFBinaryReader(mFile.BaseStream, slice.offset, (uint)mFile.BaseStream.Length); iPoint2D size = new iPoint2D((int)width, (int)slice.h); iPoint2D pos = new iPoint2D(0, (int)slice.offsetY); bool big_endian = (thumbIFD.endian == Endianness.big); // DNG spec says that if not 8 or 16 bit/sample, always use big endian if (bps != 8 && bps != 16) { big_endian = true; } try { // readUncompressedRaw(ref input, size, pos, (int)(mRaw.cpp * width * bps / 8), (int)bps, big_endian ? BitOrder.Jpeg : BitOrder.Plain); } catch (IOException ex) { throw new RawDecoderException("DNG decoder: IO error occurred in first slice, unable to decode more. Error is: " + ex.Message); } } } else if (compression == 7 || compression == 0x884c) { /* * // Let's try loading it as tiles instead * * uint cpp = (thumbIFD.getEntry(TagType.SAMPLESPERPIXEL).getUInt()); * * if (sample_format != 1) * throw new RawDecoderException("DNG Decoder: Only 16 bit unsigned data supported for compressed data."); * * DngDecoderSlices slices = new DngDecoderSlices(mFile, mRaw, compression); * if (thumbIFD.hasEntry(TagType.TILEOFFSETS)) * { * UInt32 tilew = thumbIFD.getEntry(TagType.TILEWIDTH).getUInt(); * UInt32 tileh = thumbIFD.getEntry(TagType.TILELENGTH).getUInt(); * if (tilew == 0 || tileh == 0) * throw new RawDecoderException("DNG Decoder: Invalid tile size"); * * UInt32 tilesX = (uint)(mRaw.dim.x + tilew - 1) / tilew; * UInt32 tilesY = (uint)(mRaw.dim.y + tileh - 1) / tileh; * UInt32 nTiles = tilesX * tilesY; * * Tag offsets = thumbIFD.getEntry(TagType.TILEOFFSETS); * Tag counts = thumbIFD.getEntry(TagType.TILEBYTECOUNTS); * if (offsets.dataCount != counts.dataCount || offsets.dataCount != nTiles) * throw new RawDecoderException("DNG Decoder: Tile count mismatch: offsets:" + offsets.dataCount + " count:" + counts.dataCount + ", calculated:" + nTiles); * * slices.mFixLjpeg = mFixLjpeg; * * for (UInt32 y = 0; y < tilesY; y++) * { * for (UInt32 x = 0; x < tilesX; x++) * { * DngSliceElement e = new DngSliceElement(offsets.getUInt(x + y * tilesX), counts.getUInt(x + y * tilesX), tilew * x, tileh * y); * e.mUseBigtable = tilew * tileh > 1024 * 1024; * slices.addSlice(e); * } * } * } * else * { // Strips * Tag offsets = thumbIFD.getEntry(TagType.STRIPOFFSETS); * Tag counts = thumbIFD.getEntry(TagType.STRIPBYTECOUNTS); * * UInt32 yPerSlice = thumbIFD.getEntry(TagType.ROWSPERSTRIP).getUInt(); * * if (counts.dataCount != offsets.dataCount) * { * throw new RawDecoderException("DNG Decoder: Byte count number does not match strip size: count:" + counts.dataCount + ", stips:" + offsets.dataCount); * } * * if (yPerSlice == 0 || yPerSlice > (UInt32)dim.y) * throw new RawDecoderException("DNG Decoder: Invalid y per slice"); * * UInt32 offY = 0; * for (UInt32 s = 0; s < counts.dataCount; s++) * { * DngSliceElement e = new DngSliceElement(offsets.getUInt(s), counts.getUInt(s), 0, offY); * e.mUseBigtable = yPerSlice * mRaw.dim.y > 1024 * 1024; * offY += yPerSlice; * * if (mFile.isValid(e.byteOffset, e.byteCount)) // Only decode if size is valid * slices.addSlice(e); * } * } * UInt32 nSlices = (uint)slices.slices.Count; * if (nSlices == 0) * throw new RawDecoderException("DNG Decoder: No valid slices found."); * * slices.decodeSlice(); */ } } } } catch (Exception) { //thumbnail are optional so ignore all exception } return(null); }
protected override RawImage decodeRawInternal() { List <IFD> data = mRootIFD.getIFDsWithTag(TagType.COMPRESSION); if (data.Count == 0) { throw new RawDecoderException("DNG Decoder: No image data found"); } // Erase the ones not with JPEG compression for (int k = data.Count - 1; k >= 0; k--) { IFD i = data[k]; int comp = i.getEntry(TagType.COMPRESSION).getShort(0); bool isSubsampled = false; try { isSubsampled = (i.getEntry(TagType.NEWSUBFILETYPE).getInt() & 1) != 0; // bit 0 is on if image is subsampled } catch (TiffParserException) { } if ((comp != 7 && comp != 1 && comp != 0x884c) || isSubsampled) { // Erase if subsampled, or not JPEG or uncompressed data.Remove(i); } } if (data.Count == 0) { throw new RawDecoderException("DNG Decoder: No RAW chunks found"); } /* * if (data.size() > 1) * { * _RPT0(0, "Multiple RAW chunks found - using first only!"); * }*/ IFD raw = data[0]; UInt32 sample_format = 1; UInt32 bps = raw.getEntry(TagType.BITSPERSAMPLE).getUInt(); if (raw.hasEntry(TagType.SAMPLEFORMAT)) { sample_format = raw.getEntry(TagType.SAMPLEFORMAT).getUInt(); } if (sample_format != 1) { throw new RawDecoderException("DNG Decoder: Only 16 bit unsigned data supported."); } mRaw.isCFA = (raw.getEntry(TagType.PHOTOMETRICINTERPRETATION).getUShort() == 32803); /* * if (mRaw.isCFA) * _RPT0(0, "This is a CFA image\n"); * else * _RPT0(0, "This is NOT a CFA image\n"); */ if (sample_format == 1 && bps > 16) { throw new RawDecoderException("DNG Decoder: Integer precision larger than 16 bits currently not supported."); } if (sample_format == 3 && bps != 32) { throw new RawDecoderException("DNG Decoder: Float point must be 32 bits per sample."); } try { mRaw.dim = new iPoint2D(); mRaw.dim.x = raw.getEntry(TagType.IMAGEWIDTH).getInt(); mRaw.dim.y = raw.getEntry(TagType.IMAGELENGTH).getInt(); } catch (TiffParserException) { throw new RawDecoderException("DNG Decoder: Could not read basic image information."); } //init the raw image mRaw.Init(); mRaw.colorDepth = (ushort)bps; int compression = -1; try { compression = raw.getEntry(TagType.COMPRESSION).getShort(); if (mRaw.isCFA) { // Check if layout is OK, if present if (raw.hasEntry(TagType.CFALAYOUT)) { if (raw.getEntry(TagType.CFALAYOUT).getShort() != 1) { throw new RawDecoderException("DNG Decoder: Unsupported CFA Layout."); } } Tag cfadim = raw.getEntry(TagType.CFAREPEATPATTERNDIM); if (cfadim.dataCount != 2) { throw new RawDecoderException("DNG Decoder: Couldn't read CFA pattern dimension"); } Tag pDim = raw.getEntry(TagType.CFAREPEATPATTERNDIM); // Get the size var cPat = raw.getEntry(TagType.CFAPATTERN).data; // Does NOT contain dimensions as some documents state /* * if (raw.hasEntry(CFAPLANECOLOR)) { * Tag e = raw.getEntry(CFAPLANECOLOR); * unsigned stringcPlaneOrder = e.getData(); // Map from the order in the image, to the position in the CFA * printf("Planecolor: "); * for (UInt32 i = 0; i < e.count; i++) { * printf("%u,",cPlaneOrder[i]); * } * printf("\n"); * } */ iPoint2D cfaSize = new iPoint2D(pDim.getInt(1), pDim.getInt(0)); mRaw.cfa.setSize(cfaSize); if (cfaSize.area() != raw.getEntry(TagType.CFAPATTERN).dataCount) { throw new RawDecoderException("DNG Decoder: CFA pattern dimension and pattern count does not match: " + raw.getEntry(TagType.CFAPATTERN).dataCount); } for (int y = 0; y < cfaSize.y; y++) { for (int x = 0; x < cfaSize.x; x++) { UInt32 c1 = Convert.ToUInt32(cPat[x + y * cfaSize.x]); CFAColor c2; switch (c1) { case 0: c2 = CFAColor.RED; break; case 1: c2 = CFAColor.GREEN; break; case 2: c2 = CFAColor.BLUE; break; case 3: c2 = CFAColor.CYAN; break; case 4: c2 = CFAColor.MAGENTA; break; case 5: c2 = CFAColor.YELLOW; break; case 6: c2 = CFAColor.WHITE; break; default: c2 = CFAColor.UNKNOWN; throw new RawDecoderException("DNG Decoder: Unsupported CFA Color."); } mRaw.cfa.setColorAt(new iPoint2D(x, y), c2); } } } // Now load the image if (compression == 1) { // Uncompressed. try { UInt32 cpp = raw.getEntry(TagType.SAMPLESPERPIXEL).getUInt(); if (cpp > 4) { throw new RawDecoderException("DNG Decoder: More than 4 samples per pixel is not supported."); } mRaw.cpp = cpp; Tag offsets = raw.getEntry(TagType.STRIPOFFSETS); Tag counts = raw.getEntry(TagType.STRIPBYTECOUNTS); UInt32 yPerSlice = raw.getEntry(TagType.ROWSPERSTRIP).getUInt(); UInt32 width = raw.getEntry(TagType.IMAGEWIDTH).getUInt(); UInt32 height = raw.getEntry(TagType.IMAGELENGTH).getUInt(); if (counts.dataCount != offsets.dataCount) { throw new RawDecoderException("DNG Decoder: Byte count number does not match strip size: count:" + counts.dataCount + ", strips:" + offsets.dataCount); } UInt32 offY = 0; List <DngStrip> slices = new List <DngStrip>(); for (UInt32 s = 0; s < offsets.dataCount; s++) { DngStrip slice = new DngStrip(); slice.offset = offsets.getUInt(s); slice.count = counts.getUInt(s); slice.offsetY = offY; if (offY + yPerSlice > height) { slice.h = height - offY; } else { slice.h = yPerSlice; } offY += yPerSlice; if (mFile.isValid(slice.offset, slice.count)) // Only decode if size is valid { slices.Add(slice); } } for (int i = 0; i < slices.Count; i++) { DngStrip slice = slices[i]; TIFFBinaryReader input = new TIFFBinaryReader(mFile.BaseStream, slice.offset, (uint)mFile.BaseStream.Length); iPoint2D size = new iPoint2D((int)width, (int)slice.h); iPoint2D pos = new iPoint2D(0, (int)slice.offsetY); bool big_endian = (raw.endian == Endianness.big); // DNG spec says that if not 8 or 16 bit/sample, always use big endian if (bps != 8 && bps != 16) { big_endian = true; } try { readUncompressedRaw(ref input, size, pos, (int)(mRaw.cpp * width * bps / 8), (int)bps, big_endian ? BitOrder.Jpeg : BitOrder.Plain); } catch (IOException ex) { if (i > 0) { mRaw.errors.Add(ex.Message); } else { throw new RawDecoderException("DNG decoder: IO error occurred in first slice, unable to decode more. Error is: " + ex.Message); } } } } catch (TiffParserException) { throw new RawDecoderException("DNG Decoder: Unsupported format, uncompressed with no strips."); } } else if (compression == 7 || compression == 0x884c) { try { // Let's try loading it as tiles instead mRaw.cpp = (raw.getEntry(TagType.SAMPLESPERPIXEL).getUInt()); if (sample_format != 1) { throw new RawDecoderException("DNG Decoder: Only 16 bit unsigned data supported for compressed data."); } DngDecoderSlices slices = new DngDecoderSlices(mFile, mRaw, compression); if (raw.hasEntry(TagType.TILEOFFSETS)) { UInt32 tilew = raw.getEntry(TagType.TILEWIDTH).getUInt(); UInt32 tileh = raw.getEntry(TagType.TILELENGTH).getUInt(); if (tilew == 0 || tileh == 0) { throw new RawDecoderException("DNG Decoder: Invalid tile size"); } UInt32 tilesX = (uint)(mRaw.dim.x + tilew - 1) / tilew; UInt32 tilesY = (uint)(mRaw.dim.y + tileh - 1) / tileh; UInt32 nTiles = tilesX * tilesY; Tag offsets = raw.getEntry(TagType.TILEOFFSETS); Tag counts = raw.getEntry(TagType.TILEBYTECOUNTS); if (offsets.dataCount != counts.dataCount || offsets.dataCount != nTiles) { throw new RawDecoderException("DNG Decoder: Tile count mismatch: offsets:" + offsets.dataCount + " count:" + counts.dataCount + ", calculated:" + nTiles); } slices.mFixLjpeg = mFixLjpeg; for (UInt32 y = 0; y < tilesY; y++) { for (UInt32 x = 0; x < tilesX; x++) { DngSliceElement e = new DngSliceElement(offsets.getUInt(x + y * tilesX), counts.getUInt(x + y * tilesX), tilew * x, tileh * y); e.mUseBigtable = tilew * tileh > 1024 * 1024; slices.addSlice(e); } } } else { // Strips Tag offsets = raw.getEntry(TagType.STRIPOFFSETS); Tag counts = raw.getEntry(TagType.STRIPBYTECOUNTS); UInt32 yPerSlice = raw.getEntry(TagType.ROWSPERSTRIP).getUInt(); if (counts.dataCount != offsets.dataCount) { throw new RawDecoderException("DNG Decoder: Byte count number does not match strip size: count:" + counts.dataCount + ", stips:" + offsets.dataCount); } if (yPerSlice == 0 || yPerSlice > (UInt32)mRaw.dim.y) { throw new RawDecoderException("DNG Decoder: Invalid y per slice"); } UInt32 offY = 0; for (UInt32 s = 0; s < counts.dataCount; s++) { DngSliceElement e = new DngSliceElement(offsets.getUInt(s), counts.getUInt(s), 0, offY); e.mUseBigtable = yPerSlice * mRaw.dim.y > 1024 * 1024; offY += yPerSlice; if (mFile.isValid(e.byteOffset, e.byteCount)) // Only decode if size is valid { slices.addSlice(e); } } } UInt32 nSlices = (uint)slices.slices.Count; if (nSlices == 0) { throw new RawDecoderException("DNG Decoder: No valid slices found."); } slices.decodeSlice(); if (mRaw.errors.Count >= nSlices) { throw new RawDecoderException("DNG Decoding: Too many errors encountered. Giving up.\nFirst Error:" + mRaw.errors[0]); } } catch (TiffParserException e) { throw new RawDecoderException("DNG Decoder: Unsupported format, tried strips and tiles:" + e.Message); } } else { throw new RawDecoderException("DNG Decoder: Unknown compression: " + compression); } } catch (TiffParserException e) { throw new RawDecoderException("DNG Decoder: Image could not be read:" + e.Message); } Tag as_shot_neutral = mRootIFD.getEntryRecursive(TagType.ASSHOTNEUTRAL); if (as_shot_neutral != null) { if (as_shot_neutral.dataCount == 3) { for (UInt32 i = 0; i < 3; i++) { mRaw.metadata.wbCoeffs[i] = 1.0f / Convert.ToSingle(as_shot_neutral.data[i]); } } } else { Tag as_shot_white_xy = mRootIFD.getEntryRecursive(TagType.ASSHOTWHITEXY); if (as_shot_white_xy != null) { if (as_shot_white_xy.dataCount == 2) { mRaw.metadata.wbCoeffs[0] = as_shot_white_xy.getFloat(0); mRaw.metadata.wbCoeffs[1] = as_shot_white_xy.getFloat(1); mRaw.metadata.wbCoeffs[2] = 1 - mRaw.metadata.wbCoeffs[0] - mRaw.metadata.wbCoeffs[1]; float[] d65_white = { 0.950456F, 1, 1.088754F }; for (UInt32 i = 0; i < 3; i++) { mRaw.metadata.wbCoeffs[i] /= d65_white[i]; } } } } // Crop Tag active_area = raw.getEntry(TagType.ACTIVEAREA); if (active_area != null) { iPoint2D new_size = new iPoint2D(mRaw.dim.x, mRaw.dim.y); if (active_area.dataCount != 4) { throw new RawDecoderException("DNG: active area has " + active_area.dataCount + " values instead of 4"); } active_area.getIntArray(out int[] corners, 4); if (new iPoint2D(corners[1], corners[0]).isThisInside(mRaw.dim)) { if (new iPoint2D(corners[3], corners[2]).isThisInside(mRaw.dim)) { iRectangle2D crop = new iRectangle2D(corners[1], corners[0], corners[3] - corners[1], corners[2] - corners[0]); mRaw.subFrame(crop); } } } Tag origin_entry = raw.getEntry(TagType.DEFAULTCROPORIGIN); Tag size_entry = raw.getEntry(TagType.DEFAULTCROPSIZE); if (origin_entry != null && size_entry != null) { iRectangle2D cropped = new iRectangle2D(0, 0, mRaw.dim.x, mRaw.dim.y); /* Read crop position (sometimes is rational so use float) */ origin_entry.getFloatArray(out float[] tl, 2); if (new iPoint2D((int)tl[0], (int)tl[1]).isThisInside(mRaw.dim)) { cropped = new iRectangle2D((int)tl[0], (int)tl[1], 0, 0); } cropped.dim = mRaw.dim - cropped.pos; /* Read size (sometimes is rational so use float) */ size_entry.getFloatArray(out float[] sz, 2); iPoint2D size = new iPoint2D((int)sz[0], (int)sz[1]); if ((size + cropped.pos).isThisInside(mRaw.dim)) { cropped.dim = size; } if (!cropped.hasPositiveArea()) { throw new RawDecoderException("DNG Decoder: No positive crop area"); } mRaw.subFrame(cropped); if (mRaw.isCFA && cropped.pos.x % 2 == 1) { mRaw.cfa.shiftLeft(1); } if (mRaw.isCFA && cropped.pos.y % 2 == 1) { mRaw.cfa.shiftDown(1); } } if (mRaw.dim.area() <= 0) { throw new RawDecoderException("DNG Decoder: No image left after crop"); } // Apply stage 1 opcodes if (applyStage1DngOpcodes) { if (raw.hasEntry(TagType.OPCODELIST1)) { // Apply stage 1 codes try { //DngOpcodes codes = new DngOpcodes(raw.getEntry(TagType.OPCODELIST1)); //mRaw = codes.applyOpCodes(mRaw); } catch (RawDecoderException e) { // We push back errors from the opcode parser, since the image may still be usable mRaw.errors.Add(e.Message); } } } // Linearization Tag lintable = raw.getEntry(TagType.LINEARIZATIONTABLE); if (lintable != null) { UInt32 len = lintable.dataCount; lintable.getShortArray(out ushort[] table, (int)len); mRaw.setTable(table, (int)len, !uncorrectedRawValues); if (!uncorrectedRawValues) { //TODO Fix //mRaw.sixteenBitLookup(); //mRaw.table = (null); } } // Default white level is (2 ** BitsPerSample) - 1 mRaw.whitePoint = (uint)(1 >> raw.getEntry(TagType.BITSPERSAMPLE).getShort()) - 1; Tag whitelevel = raw.getEntry(TagType.WHITELEVEL); try { mRaw.whitePoint = whitelevel.getUInt(); } catch (Exception) { } // Set black setBlack(raw); //convert to linear value //* //TODO optimize (super slow) double maxVal = Math.Pow(2, mRaw.colorDepth); double coeff = maxVal / (mRaw.whitePoint - mRaw.blackLevelSeparate[0]); Parallel.For(mRaw.mOffset.y, mRaw.dim.y + mRaw.mOffset.y, y => //for (int y = mRaw.mOffset.y; y < mRaw.dim.y + mRaw.mOffset.y; y++) { //int offset = ((y % 2) * 2); int realY = y * mRaw.dim.x; for (int x = mRaw.mOffset.x; x < mRaw.dim.x + mRaw.mOffset.x; x++) { int pos = realY + x; double val; //Linearisation if (mRaw.table != null) { val = mRaw.table.tables[mRaw.rawData[pos]]; } else { val = mRaw.rawData[pos]; } //Black sub //val -= mRaw.blackLevelSeparate[offset + x % 2]; val -= mRaw.blackLevelSeparate[0]; //Rescaling //val /= (mRaw.whitePoint - mRaw.blackLevelSeparate[offset + x % 2]); val *= coeff; //change to take into consideration each individual blacklevel //Clip if (val > maxVal) { val = maxVal; } else if (val < 0) { val = 0; } //val *= maxVal; //rescale to colordepth of the original mRaw.rawData[pos] = (ushort)val; } }); //*/ // Apply opcodes to lossy DNG if (compression == 0x884c && !uncorrectedRawValues) { /* * if (raw.hasEntry(TagType.OPCODELIST2)) * { * // We must apply black/white scaling * mRaw.scaleBlackWhite(); * // Apply stage 2 codes * try * { * DngOpcodes codes = new DngOpcodes(raw.getEntry(TagType.OPCODELIST2)); * mRaw = codes.applyOpCodes(mRaw); * } * catch (RawDecoderException e) * { * // We push back errors from the opcode parser, since the image may still be usable * mRaw.errors.Add(e.Message); * } * mRaw.blackAreas.Clear(); * mRaw.blackLevel = 0; * mRaw.blackLevelSeparate[0] = mRaw.blackLevelSeparate[1] = mRaw.blackLevelSeparate[2] = mRaw.blackLevelSeparate[3] = 0; * mRaw.whitePoint = 65535; * }*/ } return(mRaw); }
public void startDecoder(UInt32 offset, UInt32 size, UInt32 offsetX, UInt32 offsetY) { if (!input.isValid(offset, size)) { throw new Exception("startDecoder: Start offset plus size is longer than file. Truncated file."); } if ((int)offsetX >= mRaw.dim.x) { throw new Exception("startDecoder: X offset outside of image"); } if ((int)offsetY >= mRaw.dim.y) { throw new Exception("startDecoder: Y offset outside of image"); } offX = offsetX; offY = offsetY; try { Endianness host_endian = Common.getHostEndianness(); // JPEG is big endian if (host_endian == Endianness.big) { input = new TIFFBinaryReader(input.BaseStream, offset, size); } else { input = new TIFFBinaryReaderRE(input.BaseStream, offset, size); } if (getNextMarker(false) != JpegMarker.M_SOI) { throw new Exception("startDecoder: Image did not start with SOI. Probably not an LJPEG"); } // _RPT0(0,"Found SOI marker\n"); bool moreImage = true; while (moreImage) { JpegMarker m = getNextMarker(true); switch (m) { case JpegMarker.M_SOS: // _RPT0(0,"Found SOS marker\n"); parseSOS(); break; case JpegMarker.M_EOI: // _RPT0(0,"Found EOI marker\n"); moreImage = false; break; case JpegMarker.M_DHT: // _RPT0(0,"Found DHT marker\n"); parseDHT(); break; case JpegMarker.M_DQT: throw new Exception("LJpegDecompressor: Not a valid RAW file."); case JpegMarker.M_DRI: // _RPT0(0,"Found DRI marker\n"); break; case JpegMarker.M_APP0: // _RPT0(0,"Found APP0 marker\n"); break; case JpegMarker.M_SOF3: // _RPT0(0,"Found SOF 3 marker:\n"); parseSOF(frame); break; default: // Just let it skip to next marker // _RPT1(0, "Found marker:0x%x. Skipping\n", m); break; } } } catch (IOException) { throw; } }
/* Check if the decoder can decode the image from this camera */ /* A RawDecoderException will be thrown if the camera isn't supported */ /* Unknown cameras does NOT generate any specific feedback */ /* This function must be overridden by actual decoders */ public void decodeUncompressed(ref IFD rawIFD, BitOrder order) { UInt32 nslices = rawIFD.getEntry(TagType.STRIPOFFSETS).dataCount; Tag offsets = rawIFD.getEntry(TagType.STRIPOFFSETS); Tag counts = rawIFD.getEntry(TagType.STRIPBYTECOUNTS); UInt32 yPerSlice = rawIFD.getEntry(TagType.ROWSPERSTRIP).getUInt(); Int32 width = rawIFD.getEntry(TagType.IMAGEWIDTH).getInt(); UInt32 height = rawIFD.getEntry(TagType.IMAGELENGTH).getUInt(); int bitPerPixel = rawIFD.getEntry(TagType.BITSPERSAMPLE).getInt(); List <RawSlice> slices = new List <RawSlice>(); UInt32 offY = 0; for (UInt32 s = 0; s < nslices; s++) { RawSlice slice = new RawSlice() { offset = (uint)offsets.data[s], count = (uint)counts.data[s] }; if (offY + yPerSlice > height) { slice.h = height - offY; } else { slice.h = yPerSlice; } offY += yPerSlice; if (mFile.isValid(slice.offset, slice.count)) // Only decode if size is valid { slices.Add(slice); } } if (0 == slices.Count) { throw new RawDecoderException("RAW Decoder: No valid slices found. File probably truncated."); } mRaw.dim.x = width; mRaw.dim.y = (int)offY; mRaw.whitePoint = (uint)(1 << bitPerPixel) - 1; offY = 0; for (int i = 0; i < slices.Count; i++) { RawSlice slice = slices[i]; var stream = mFile.BaseStream; TIFFBinaryReader input; if (mFile is TIFFBinaryReaderRE) { input = new TIFFBinaryReaderRE(mFile.BaseStream, slice.offset, slice.count); } else { input = new TIFFBinaryReader(mFile.BaseStream, slice.offset, slice.count); } iPoint2D size = new iPoint2D(width, (int)slice.h); iPoint2D pos = new iPoint2D(0, (int)offY); bitPerPixel = (int)(slice.count * 8u / (slice.h * width)); try { readUncompressedRaw(ref input, size, pos, width * bitPerPixel / 8, bitPerPixel, order); } catch (RawDecoderException) { if (i > 0) { //TODO add something } else { throw; } } catch (IOException e) { if (i > 0) { //TODO add something } else { throw new RawDecoderException("RAW decoder: IO error occurred in first slice, unable to decode more. Error is: " + e); } } offY += slice.h; } }
protected override void decodeRawInternal() { UInt32 width = 0, height = 0, filesize = 0, bits = 0, offset = 0; if (cam.hints.TryGetValue("full_width", out string tmp)) { width = UInt32.Parse(tmp); } else { throw new RawDecoderException("Naked: couldn't ContainsKey width"); } if (cam.hints.TryGetValue("full_height", out tmp)) { height = UInt32.Parse(tmp); } else { throw new RawDecoderException("Naked: couldn't ContainsKey height"); } if (cam.hints.TryGetValue("filesize", out tmp)) { filesize = UInt32.Parse(tmp); } else { throw new RawDecoderException("Naked: couldn't ContainsKey filesize"); } if (cam.hints.TryGetValue("offset", out tmp)) { offset = UInt32.Parse(tmp); } if (cam.hints.TryGetValue("bits", out tmp)) { bits = UInt32.Parse(tmp); } else { bits = (filesize - offset) * 8 / width / height; } BitOrder bo = BitOrder.Jpeg16; // Default if (cam.hints.TryGetValue("order", out tmp)) { if (tmp == "plain") { bo = BitOrder.Plain; } else if (tmp == "jpeg") { bo = BitOrder.Jpeg; } else if (tmp == "jpeg16") { bo = BitOrder.Jpeg16; } else if (tmp == "jpeg32") { bo = BitOrder.Jpeg32; } } rawImage.dim = new Point2D((int)width, (int)height); rawImage.Init(); reader = new TIFFBinaryReader(reader.BaseStream, offset, (uint)reader.BaseStream.Length); Point2D pos = new Point2D(0, 0); readUncompressedRaw(ref reader, rawImage.dim, pos, (int)(width * bits / 8), (int)bits, bo); }
/* This will attempt to parse makernotes and return it as an IFD */ IFD parseMakerNote(TIFFBinaryReader reader, uint off, Endianness parent_end) { IFD maker_ifd = null; uint offset = 0; TIFFBinaryReader mFile = null; reader.Position = off; byte[] data = reader.ReadBytes(100); // Pentax makernote starts with AOC\0 - If it's there, skip it if (data[0] == 0x41 && data[1] == 0x4f && data[2] == 0x43 && data[3] == 0) { //data = data.Skip(4).ToArray(); offset += 4; } // Pentax also has "PENTAX" at the start, makernote starts at 8 if (data[0 + offset] == 0x50 && data[1 + offset] == 0x45 && data[2 + offset] == 0x4e && data[3 + offset] == 0x54 && data[4 + offset] == 0x41 && data[5 + offset] == 0x58) { mFile = new TIFFBinaryReader(reader.BaseStream, offset + off, (uint)data.Length); parent_end = getTiffEndianness(data.Skip(8).ToArray()); if (parent_end == Endianness.unknown) { throw new TiffParserException("Cannot determine Pentax makernote endianness"); } //data = data.Skip(10).ToArray(); offset += 10; // Check for fuji signature in else block so we don't accidentally leak FileMap } else if (Common.memcmp(ref fuji_signature, ref data)) { offset = 12; mFile = new TIFFBinaryReader(reader.BaseStream, offset + off, (uint)data.Length); } else if (Common.memcmp(ref nikon_v3_signature, ref data)) { //offset = 10; offset = 10; // Read endianness if (data[0 + offset] == 0x49 && data[1 + offset] == 0x49) { parent_end = Endianness.little; mFile = new TIFFBinaryReader(reader.BaseStream, offset + off, (uint)data.Length); offset = 8; } else if (data[0 + offset] == 0x4D && data[1 + offset] == 0x4D) { parent_end = Endianness.big; mFile = new TIFFBinaryReaderRE(reader.BaseStream, offset + off, (uint)data.Length); offset = 8; } } // Panasonic has the word Exif at byte 6, a complete Tiff header starts at byte 12 // This TIFF is 0 offset based if (data[6] == 0x45 && data[7] == 0x78 && data[8] == 0x69 && data[9] == 0x66) { parent_end = getTiffEndianness(data.Skip(12).ToArray()); if (parent_end == Endianness.unknown) { throw new TiffParserException("Cannot determine Panasonic makernote endianness"); } offset = 20; } // Some have MM or II to indicate endianness - read that if (data[0] == 0x49 && data[1] == 0x49) { offset += 2; parent_end = Endianness.little; } else if (data[0] == 0x4D && data[1] == 0x4D) { parent_end = Endianness.big; offset += 2; } // Olympus starts the makernote with their own name, sometimes truncated if (Common.strncmp(data, "OLYMP", 5)) { offset += 8; if (Common.strncmp(data, "OLYMPUS", 7)) { offset += 4; } } // Epson starts the makernote with its own name if (Common.strncmp(data, "EPSON", 5)) { offset += 8; } // Attempt to parse the rest as an IFD try { if (mFile == null) { if (parent_end == Endianness.little) { mFile = new TIFFBinaryReader(reader.BaseStream, offset + off, (uint)data.Length); } else if (parent_end == Endianness.big) { mFile = new TIFFBinaryReaderRE(reader.BaseStream, offset + off, (uint)data.Length); } } /* if (parent_end == getHostEndianness()) * maker_ifd = new IFD(mFile, offset, depth); * else * maker_ifd = new IFDBE(mFile, offset, depth);*/ maker_ifd = new IFD(mFile, offset, endian, depth); } catch (Exception e) { Debug.WriteLine(e.Message); return(null); } // If the structure cannot be read, a TiffParserException will be thrown. return(maker_ifd); }
IFD parseDngPrivateData(Tag t) { /* * 1. Six bytes containing the zero-terminated string "Adobe". (The DNG specification calls for the DNGPrivateData tag to start with an ASCII string identifying the creator/format). * 2. 4 bytes: an ASCII string ("MakN" for a Makernote), indicating what sort of data is being stored here. Note that this is not zero-terminated. * 3. A four-byte count (number of data bytes following); this is the length of the original MakerNote data. (This is always in "most significant byte first" format). * 4. 2 bytes: the byte-order indicator from the original file (the usual 'MM'/4D4D or 'II'/4949). * 5. 4 bytes: the original file offset for the MakerNote tag data (stored according to the byte order given above). * 6. The contents of the MakerNote tag. This is a simple byte-for-byte copy, with no modification. */ uint size = t.dataCount; Common.ConvertArray(ref t.data, out byte[] data); Common.ByteToChar(ref data, out char[] dataAsChar); string id = new String(dataAsChar); if (!id.StartsWith("Adobe")) { Debug.WriteLine("Not Adobe Private data"); return(null); } if (!(data[6] == 'M' && data[7] == 'a' && data[8] == 'k' && data[9] == 'N')) { Debug.WriteLine("Not Makernote"); return(null); } data = data.Skip(10).ToArray(); uint count; count = (uint)data[0] << 24 | (uint)data[1] << 16 | (uint)data[2] << 8 | data[3]; data = data.Skip(4).ToArray(); if (count > size) { Debug.WriteLine("Error reading TIFF structure (invalid size). File Corrupt"); return(null); } Endianness makernote_endian = Endianness.unknown; if (data[0] == 0x49 && data[1] == 0x49) { makernote_endian = Endianness.little; } else if (data[0] == 0x4D && data[1] == 0x4D) { makernote_endian = Endianness.big; } else { Debug.WriteLine("Cannot determine endianess of DNG makernote"); return(null); } data = data.Skip(2).ToArray(); uint org_offset; org_offset = (uint)data[0] << 24 | (uint)data[1] << 16 | (uint)data[2] << 8 | data[3]; data = data.Skip(4).ToArray(); /* We don't parse original makernotes that are placed after 300MB mark in the original file */ if (org_offset + count > 300 * 1024 * 1024) { Debug.WriteLine("Adobe Private data: original offset of makernote is past 300MB offset"); return(null); } /* Create fake tiff with original offsets */ //byte[] maker_data = new byte[count]; // Common.memcopy(ref maker_data, ref data, count, 0, 0); TIFFBinaryReader maker_map = new TIFFBinaryReader(TIFFBinaryReader.streamFromArray(data)); IFD maker_ifd; try { maker_ifd = parseMakerNote(maker_map, 0, makernote_endian); } catch (TiffParserException e) { Debug.WriteLine(e.Message); return(null); } return(maker_ifd); }
/* Attempt to decode the image */ /* A RawDecoderException will be thrown if the image cannot be decoded * public void readUncompressedRaw(ref TIFFBinaryReader input, iPoint2D size, iPoint2D offset, int inputPitch, int bitPerPixel, BitOrder order) * { * UInt32 outPitch = mRaw.pitch; * uint w = (uint)size.x; * uint h = (uint)size.y; * UInt32 cpp = mRaw.cpp; * UInt64 ox = (ulong)offset.x; * UInt64 oy = (ulong)offset.y; * if (this.mRaw.rawData == null) * { * mRaw.rawData = new ushort[w * h * cpp]; * } * if (input.getRemainSize() < (inputPitch * (int)h)) * { * if (input.getRemainSize() > inputPitch) * { * h = (uint)(input.getRemainSize() / inputPitch - 1); * mRaw.errors.Add("Image truncated (file is too short)"); * } * else * throw new IOException("readUncompressedRaw: Not enough data to decode a single line. Image file truncated."); * } * if (bitPerPixel > 16) * throw new RawDecoderException("readUncompressedRaw: Unsupported bit depth"); * * UInt32 skipBits = (uint)(inputPitch - (int)w * cpp * bitPerPixel / 8); // Skip per line * if (oy > (ulong)mRaw.dim.y) * throw new RawDecoderException("readUncompressedRaw: Invalid y offset"); * if (ox + (ulong)size.x > (ulong)mRaw.dim.x) * throw new RawDecoderException("readUncompressedRaw: Invalid x offset"); * * UInt64 y = oy; * h = (uint)Math.Min(h + (uint)oy, mRaw.dim.y); * /* * if (mRaw.getDataType() == RawImageType.TYPE_FLOAT32) * { * if (bitPerPixel != 32) * throw new RawDecoderException("readUncompressedRaw: Only 32 bit float point supported"); * BitBlt(&data[offset.x * sizeof(float) * cpp + y * outPitch], outPitch, * input.getData(), inputPitch, w * mRaw.bpp, h - y); * return; * } * * if (BitOrder.Jpeg == order) * { * BitPumpMSB bits = new BitPumpMSB(ref input); * w *= cpp; * for (; y < h; y++) * { * bits.checkPos(); * for (UInt32 x = 0; x < w; x++) * { * UInt32 b = bits.getBits((uint)bitPerPixel); * mRaw.rawData[(((int)(offset.x * sizeof(UInt16) * cpp) + (int)y * (int)outPitch)) + x] = (ushort)b; * } * bits.skipBits(skipBits); * } * } * else if (BitOrder.Jpeg16 == order) * { * BitPumpMSB16 bits = new BitPumpMSB16(input); * w *= cpp; * for (; y < h; y++) * { * bits.checkPos(); * for (UInt32 x = 0; x < w; x++) * { * UInt32 b = bits.getBits((uint)bitPerPixel); * mRaw.rawData[(offset.x * sizeof(ushort) * (int)cpp + (int)y * (int)outPitch) + x] = (ushort)b; * } * bits.skipBits(skipBits); * } * } * else if (BitOrder.Jpeg32 == order) * { * BitPumpMSB32 bits = new BitPumpMSB32(input); * w *= cpp; * for (; y < h; y++) * { * bits.checkPos(); * for (UInt32 x = 0; x < w; x++) * { * UInt32 b = bits.getBits((uint)bitPerPixel); * mRaw.rawData[(offset.x * sizeof(ushort) * (int)cpp + (int)y * (int)outPitch) + x] = (ushort)b; * } * bits.skipBits(skipBits); * } * } * else * { * if (bitPerPixel == 16) * { * Decode16BitRawUnpacked(input, w, h); * return; * } * if (bitPerPixel == 12 && (int)w == inputPitch * 8 / 12) * { * Decode12BitRaw(input, w, h); * return; * } * BitPumpPlain bits = new BitPumpPlain(input); * w *= cpp; * for (; y < h; y++) * { * bits.checkPos(); * for (UInt32 x = 0; x < w; x++) * { * UInt32 b = bits.getBits((uint)bitPerPixel); * mRaw.rawData[(offset.x * sizeof(ushort) + (int)y * (int)outPitch) + x] = (ushort)b; * } * bits.skipBits(skipBits); * } * } * } */ public unsafe void readUncompressedRaw(ref TIFFBinaryReader input, iPoint2D size, iPoint2D offset, int inputPitch, int bitPerPixel, BitOrder order) { fixed(ushort *d = mRaw.rawData) { byte *data = (byte *)d; uint outPitch = mRaw.pitch; int w = size.x; int h = size.y; uint cpp = mRaw.cpp; int ox = offset.x; int oy = offset.y; if (input.getRemainSize() < (inputPitch * h)) { if ((int)input.getRemainSize() > inputPitch) { h = input.getRemainSize() / inputPitch - 1; mRaw.errors.Add("Image truncated (file is too short)"); } else { throw new IOException("readUncompressedRaw: Not enough data to decode a single line. Image file truncated."); } } if (bitPerPixel > 16) { throw new RawDecoderException("readUncompressedRaw: Unsupported bit depth"); } uint skipBits = (uint)(inputPitch - w * cpp * bitPerPixel / 8); // Skip per line if (oy > mRaw.dim.y) { throw new RawDecoderException("readUncompressedRaw: Invalid y offset"); } if (ox + size.x > mRaw.dim.x) { throw new RawDecoderException("readUncompressedRaw: Invalid x offset"); } int y = oy; h = (int)Math.Min(h + oy, (uint)mRaw.dim.y); /*if (mRaw.getDataType() == TYPE_FLOAT32) * { * if (bitPerPixel != 32) * throw new RawDecoderException("readUncompressedRaw: Only 32 bit float point supported"); * BitBlt(&data[offset.x * sizeof(float) * cpp + y * outPitch], outPitch, * input.getData(), inputPitch, w * mRaw.bpp, h - y); * return; * }*/ if (BitOrder.Jpeg == order) { BitPumpMSB bits = new BitPumpMSB(ref input); w *= (int)cpp; for (; y < h; y++) { bits.checkPos(); for (uint x = 0; x < w; x++) { uint b = bits.getBits((uint)bitPerPixel); mRaw.rawData[x + (offset.x * cpp + y * mRaw.dim.x * cpp)] = (ushort)b; } bits.skipBits(skipBits); } } else if (BitOrder.Jpeg16 == order) { BitPumpMSB16 bits = new BitPumpMSB16(ref input); w *= (int)cpp; for (; y < h; y++) { UInt16 *dest = (UInt16 *)&data[offset.x * sizeof(UInt16) * cpp + y * outPitch]; bits.checkPos(); for (uint x = 0; x < w; x++) { uint b = bits.getBits((uint)bitPerPixel); dest[x] = (ushort)b; } bits.skipBits(skipBits); } } else if (BitOrder.Jpeg32 == order) { BitPumpMSB32 bits = new BitPumpMSB32(ref input); w *= (int)cpp; for (; y < h; y++) { UInt16 *dest = (UInt16 *)&data[offset.x * sizeof(UInt16) * cpp + y * outPitch]; bits.checkPos(); for (uint x = 0; x < w; x++) { uint b = bits.getBits((uint)bitPerPixel); dest[x] = (ushort)b; } bits.skipBits(skipBits); } } else { if (bitPerPixel == 16 && Common.getHostEndianness() == Endianness.little) { Decode16BitRawUnpacked(input, (uint)w, (uint)h); return; } if (bitPerPixel == 12 && (int)w == inputPitch * 8 / 12 && Common.getHostEndianness() == Endianness.little) { Decode12BitRaw(input, (uint)w, (uint)h); return; } BitPumpPlain bits = new BitPumpPlain(ref input); w *= (int)cpp; for (; y < h; y++) { UInt16 *dest = (UInt16 *)&data[offset.x * sizeof(UInt16) + y * outPitch]; bits.checkPos(); for (uint x = 0; x < w; x++) { uint b = bits.getBits((uint)bitPerPixel); dest[x] = (ushort)b; } bits.skipBits(skipBits); } } } }
public LJpegPlain(TIFFBinaryReader file, RawImage img) : base(file, img) { }
public IFD(TIFFBinaryReader fileStream, uint offset, Endianness endian, int depth) : this(fileStream, offset, endian) { this.depth = depth; }
public TiffDecoder(IFD rootifd, ref TIFFBinaryReader file) : base(ref file) { decoderVersion = 1; ifd = rootifd; //check if no }
/*** Used for entropy encoded sections ***/ public BitPumpMSB(ref TIFFBinaryReader s) : this(ref s, (uint)s.Position, (uint)s.BaseStream.Length) { }
public JPGParser(TIFFBinaryReader file) : base(ref file) { }
public IFD(TIFFBinaryReader fileStream, uint offset, Endianness endian) { this.endian = endian; fileStream.Position = offset; tagNumber = fileStream.ReadUInt16(); tags = new Dictionary <TagType, Tag>(); for (int i = 0; i < tagNumber; i++) { Tag temp = new Tag(); temp.tagId = (TagType)fileStream.ReadUInt16(); //add the displayname temp.displayName = null; temp.dataType = (TiffDataType)fileStream.ReadUInt16(); temp.dataCount = fileStream.ReadUInt32(); //IF makernote, do not parse data //if (temp.tagId == TagType.MAKERNOTE || temp.tagId == TagType.MAKERNOTE_ALT) temp.dataCount = 0; temp.dataOffset = 0; if (((temp.dataCount * temp.getTypeSize(temp.dataType) > 4))) { temp.dataOffset = fileStream.ReadUInt32(); } //Get the tag data temp.data = new Object[temp.dataCount]; long firstPosition = fileStream.Position; if (temp.dataOffset > 1) { fileStream.Position = temp.dataOffset; //todo check if correct } if (temp.tagId != TagType.MAKERNOTE && temp.tagId != TagType.MAKERNOTE_ALT) { for (int j = 0; j < temp.dataCount; j++) { switch (temp.dataType) { case TiffDataType.BYTE: case TiffDataType.UNDEFINED: case TiffDataType.ASCII: case TiffDataType.OFFSET: temp.data[j] = fileStream.ReadByte(); break; case TiffDataType.SHORT: temp.data[j] = fileStream.ReadUInt16(); break; case TiffDataType.LONG: temp.data[j] = fileStream.ReadUInt32(); break; case TiffDataType.RATIONAL: temp.data[j] = fileStream.ReadDouble(); break; case TiffDataType.SBYTE: temp.data[j] = fileStream.ReadSByte(); break; case TiffDataType.SSHORT: temp.data[j] = fileStream.ReadInt16(); //if (temp.dataOffset == 0 && temp.dataCount == 1) fileStream.ReadInt16(); break; case TiffDataType.SLONG: temp.data[j] = fileStream.ReadInt32(); break; case TiffDataType.SRATIONAL: //Because the nikonmakernote is broken with the tag 0x19 wich is double but offset of zero. //TODO remove this Fix if (temp.dataOffset == 0) { temp.data[j] = .0; } else { temp.data[j] = fileStream.ReadDouble(); } break; case TiffDataType.FLOAT: temp.data[j] = fileStream.ReadSingle(); break; case TiffDataType.DOUBLE: temp.data[j] = fileStream.ReadDouble(); break; } } }//Special tag switch (temp.tagId) { case TagType.DNGPRIVATEDATA: { try { IFD maker_ifd = parseDngPrivateData(temp); if (maker_ifd != null) { subIFD.Add(maker_ifd); } temp.data = null; } catch (TiffParserException) { // Unparsable private data are added as entries } catch (IOException) { // Unparsable private data are added as entries } } break; case TagType.MAKERNOTE: case TagType.MAKERNOTE_ALT: { try { //save current position long pos = fileStream.Position; IFD makernote = parseMakerNote(fileStream, temp.dataOffset, endian); if (makernote != null) { subIFD.Add(makernote); } //correct here fileStream.BaseStream.Position = pos; //return to current position } catch (TiffParserException) { // Unparsable makernotes are added as entries } catch (IOException) { // Unparsable makernotes are added as entries } } break; case TagType.FUJI_RAW_IFD: if (temp.dataType == TiffDataType.OFFSET) // FUJI - correct type { temp.dataType = TiffDataType.LONG; } goto case TagType.SUBIFDS; case TagType.SUBIFDS: case TagType.EXIFIFDPOINTER: case TagType.NIKONTHUMB: long p = fileStream.Position; try { for (Int32 k = 0; k < temp.dataCount; k++) { subIFD.Add(new IFD(fileStream, Convert.ToUInt32(temp.data[k]), endian, depth)); } } catch (TiffParserException) { // Unparsable subifds are added as entries } catch (IOException) { // Unparsable subifds are added as entries } fileStream.BaseStream.Position = p; break; } //transform data ToString if (temp.dataType == TiffDataType.ASCII) { //remove \0 if any if ((byte)temp.data[temp.dataCount - 1] == 0) { temp.data[temp.dataCount - 1] = (byte)' '; } string t = Encoding.ASCII.GetString(temp.data.Cast <byte>().ToArray()); temp.data = new Object[1]; temp.data[0] = t; } if (temp.dataOffset > 1) { fileStream.BaseStream.Position = firstPosition; } else if (temp.dataOffset == 0) { int k = (int)temp.dataCount * temp.getTypeSize(temp.dataType); if (k < 4) { fileStream.ReadBytes(4 - k); } } /*else * { * temp.dataCount = 0; * temp.data = null; * }*/ if (!tags.ContainsKey(temp.tagId)) { tags.Add(temp.tagId, temp); } else { Debug.WriteLine("tags already exist"); } } nextOffset = fileStream.ReadUInt16(); }
public void DecompressNikon(TIFFBinaryReader metadata, UInt32 w, UInt32 h, UInt32 bitsPS, UInt32 offset, UInt32 size) { metadata.Position = 0; UInt32 v0 = metadata.ReadByte(); UInt32 v1 = metadata.ReadByte(); UInt32 huffSelect = 0; UInt32 split = 0; int[] pUp1 = new int[2]; int[] pUp2 = new int[2]; mUseBigtable = true; //_RPT2(0, "Nef version v0:%u, v1:%u\n", v0, v1); if (v0 == 73 || v1 == 88) { metadata.ReadBytes(2110); } if (v0 == 70) { huffSelect = 2; } if (bitsPS == 14) { huffSelect += 3; } pUp1[0] = metadata.ReadInt16(); pUp1[1] = metadata.ReadInt16(); pUp2[0] = metadata.ReadInt16(); pUp2[1] = metadata.ReadInt16(); int _max = 1 << (int)bitsPS & 0x7fff; UInt32 step = 0; UInt32 csize = metadata.ReadUInt16(); if (csize > 1) { step = (uint)_max / (csize - 1); } if (v0 == 68 && v1 == 32 && step > 0) { for (UInt32 i = 0; i < csize; i++) { curve[i * step] = (ushort)metadata.ReadInt16(); } for (int i = 0; i < _max; i++) { curve[i] = (ushort)((curve[i - i % step] * (step - i % step) + curve[i - i % step + step] * (i % step)) / step); } metadata.Position = (562); split = metadata.ReadUInt16(); } else if (v0 != 70 && csize <= 0x4001) { for (UInt32 i = 0; i < csize; i++) { curve[i] = metadata.ReadUInt16(); } _max = (int)csize; } initTable(huffSelect); mRaw.whitePoint = curve[_max - 1]; mRaw.blackLevel = curve[0]; if (!uncorrectedRawValues) { mRaw.setTable(curve, _max, true); } UInt32 x, y; BitPumpMSB bits = new BitPumpMSB(ref input, offset, size); UInt32 pitch = w; int pLeft1 = 0; int pLeft2 = 0; UInt32 cw = w / 2; UInt32 random = bits.peekBits(24); for (y = 0; y < h; y++) { if (split != 0 && (y == split)) { initTable(huffSelect + 1); } pUp1[y & 1] += HuffDecodeNikon(bits); pUp2[y & 1] += HuffDecodeNikon(bits); pLeft1 = pUp1[y & 1]; pLeft2 = pUp2[y & 1]; uint dest = y * pitch; mRaw.setWithLookUp((ushort)Common.clampbits(pLeft1, 15), ref mRaw.rawData, dest++, ref random); mRaw.setWithLookUp((ushort)Common.clampbits(pLeft2, 15), ref mRaw.rawData, dest++, ref random); for (x = 1; x < cw; x++) { bits.checkPos(); pLeft1 += HuffDecodeNikon(bits); pLeft2 += HuffDecodeNikon(bits); mRaw.setWithLookUp((ushort)Common.clampbits(pLeft1, 15), ref mRaw.rawData, dest++, ref random); mRaw.setWithLookUp((ushort)Common.clampbits(pLeft2, 15), ref mRaw.rawData, dest++, ref random); } } if (uncorrectedRawValues) { mRaw.setTable(curve, _max, false); } else { mRaw.table = (null); } }
int MIN_GET_BITS;// = (BITS_PER_LONG - 7); /* max value for long getBuffer */ public BitPumpPlain(ref TIFFBinaryReader s) { MIN_GET_BITS = (BITS_PER_LONG - 7); s.Read(buffer, (int)s.Position, (int)s.BaseStream.Length); size = (uint)(8 * s.getRemainSize()); }