void DecodeUncompressed(IFD raw) { uint width = raw.GetEntry(TagType.IMAGEWIDTH).GetUInt(0); uint height = raw.GetEntry(TagType.IMAGELENGTH).GetUInt(0); uint off = raw.GetEntry(TagType.STRIPOFFSETS).GetUInt(0); rawImage.fullSize.dim = new Point2D(width, height); rawImage.Init(false); ImageBinaryReader input = new ImageBinaryReader(reader.BaseStream, off); /* * RawDecompressor.Decode14BitRawBEunpacked(input, width, height, rawImage); */ RawDecompressor.Decode16BitRawUnpacked(input, new Point2D(width, height), new Point2D(), rawImage); }
public override void DecodeRaw() { List <IFD> data = ifd.GetIFDsWithTag(TagType.STRIPOFFSETS); if (data.Count == 0) { throw new RawDecoderException("No image data found"); } IFD raw = data[0]; int compression = raw.GetEntry(TagType.COMPRESSION).GetInt(0); if (1 == compression || compression == 32773) { DecodeUncompressed(raw, BitOrder.Jpeg); return; } if (65535 != compression) { throw new RawDecoderException("Unsupported compression"); } Tag offsets = raw.GetEntry(TagType.STRIPOFFSETS); Tag counts = raw.GetEntry(TagType.STRIPBYTECOUNTS); if (offsets.dataCount != 1) { throw new RawDecoderException("Multiple Strips found: " + offsets.dataCount); } if (counts.dataCount != offsets.dataCount) { throw new RawDecoderException("Byte count number does not match strip size: count:" + counts.dataCount + ", strips:" + offsets.dataCount); } if (!reader.IsValid(offsets.GetUInt(0), counts.GetUInt(0))) { throw new RawDecoderException("Truncated file."); } rawImage.fullSize.dim = new Point2D(raw.GetEntry(TagType.IMAGEWIDTH).GetUInt(0), raw.GetEntry(TagType.IMAGELENGTH).GetUInt(0)); rawImage.Init(false); PentaxDecompressor l = new PentaxDecompressor(reader, rawImage); l.DecodePentax(ifd, offsets.GetUInt(0), counts.GetUInt(0)); reader.Dispose(); }
void SetBlack(IFD raw) { if (raw.tags.ContainsKey(TagType.MASKEDAREAS)) { if (DecodeMaskedAreas(raw)) { return; } } if (raw.GetEntry(TagType.BLACKLEVEL) != null) { Decodeblacks(raw); } }
/* Decodes DNG masked areas into blackareas in the image */ bool DecodeMaskedAreas(IFD raw) { Tag masked = raw.GetEntry(TagType.MASKEDAREAS); if (masked.dataType != TiffDataType.SHORT && masked.dataType != TiffDataType.LONG) { return(false); } Int32 nrects = (int)masked.dataCount / 4; if (0 == nrects) { return(false); } /* Since we may both have short or int, copy it to int array. */ var rects = masked.GetUIntArray(); Point2D top = rawImage.fullSize.offset; for (int i = 0; i < nrects; i++) { Point2D topleft = new Point2D(rects[i * 4 + 1], rects[i * 4]); Point2D bottomright = new Point2D(rects[i * 4 + 3], rects[i * 4 + 2]); // Is this a horizontal box, only add it if it covers the active width of the image if (topleft.width <= top.width && bottomright.width >= (rawImage.fullSize.dim.width + top.width)) { rawImage.blackAreas.Add(new BlackArea(topleft.height, bottomright.height - topleft.height, false)); } else if (topleft.height <= top.height && bottomright.height >= (rawImage.fullSize.dim.height + top.height)) { // Is it a vertical box, only add it if it covers the active height of the image rawImage.blackAreas.Add(new BlackArea(topleft.width, bottomright.width - topleft.width, true)); } } return(rawImage.blackAreas.Count != 0); }
void GetWB() { // Set the whitebalance for all the modern ARW formats (everything after A100) Tag priv = ifd.GetEntryRecursive(TagType.DNGPRIVATEDATA); if (priv != null) { byte[] data = priv.GetByteArray(); uint off = ((((uint)(data)[3]) << 24) | (((uint)(data)[2]) << 16) | (((uint)(data)[1]) << 8) | (data)[0]); IFD sony_private; sony_private = new IFD(reader, off, ifd.endian, ifd.Depth); Tag sony_offset = sony_private.GetEntryRecursive(TagType.SONY_OFFSET); Tag sony_length = sony_private.GetEntryRecursive(TagType.SONY_LENGTH); Tag sony_key = sony_private.GetEntryRecursive(TagType.SONY_KEY); if (sony_offset == null || sony_length == null || sony_key == null || sony_key.dataCount != 4) { throw new RawDecoderException("Couldn't find the correct metadata for white balance decoding"); } off = sony_offset.GetUInt(0); uint len = sony_length.GetUInt(0); data = sony_key.GetByteArray(); uint key = (uint)((data[3] << 24) | (data[2] << 16) | (data[1] << 8) | (data)[0]); reader.BaseStream.Position = off; byte[] ifp_data = reader.ReadBytes((int)len); SonyDecrypt(ifp_data, len / 4, key); using (var reader = new ImageBinaryReader(ifp_data)) { sony_private = new IFD(reader, 0, ifd.endian, 0, -(int)off); } Tag wb = sony_private.GetEntry(TagType.SONYGRBGLEVELS); if (wb != null) { if (wb.dataCount != 4) { throw new RawDecoderException("White balance has " + wb.dataCount + " entries instead of 4"); } rawImage.metadata.WbCoeffs = new WhiteBalance(wb.GetInt(1), wb.GetInt(0), wb.GetInt(2), rawImage.fullSize.ColorDepth); } else if ((wb = sony_private.GetEntry(TagType.SONYRGGBLEVELS)) != null) { if (wb.dataCount != 4) { throw new RawDecoderException("White balance has " + wb.dataCount + " entries instead of 4"); } rawImage.metadata.WbCoeffs = new WhiteBalance(wb.GetInt(0), wb.GetInt(1), wb.GetInt(3), rawImage.fullSize.ColorDepth); } //TODO read the color matrix 0x7800 Tag black = sony_private.GetEntry((TagType)0x7300) ?? sony_private.GetEntry((TagType)0x7310); if (black != null) { rawImage.black = black.GetLong(0); } Tag white = sony_private.GetEntry((TagType)0x787f); if (white != null) { rawImage.whitePoint = white.GetLong(0); } } }
public override void DecodeRaw() { List <IFD> data = ifd.GetIFDsWithTag(TagType.STRIPOFFSETS); if (data.Count == 0) { Tag model = ifd.GetEntryRecursive(TagType.MODEL); if (model != null && model.DataAsString == "DSLR-A100") { DecodeA100(); return; } else { DecodeCryptedUncompressed(); return; } } IFD raw = data[0]; int compression = raw.GetEntry(TagType.COMPRESSION).GetInt(0); if (1 == compression) { DecodeUncompressed(raw); return; } if (32767 != compression) { throw new RawDecoderException("ARW Decoder: Unsupported compression"); } Tag offsets = raw.GetEntry(TagType.STRIPOFFSETS); Tag counts = raw.GetEntry(TagType.STRIPBYTECOUNTS); if (offsets.dataCount != 1) { throw new RawDecoderException("ARW Decoder: Multiple Strips found: " + offsets.dataCount); } if (counts.dataCount != offsets.dataCount) { throw new RawDecoderException("ARW Decoder: Byte count number does not match strip size: count:" + counts.dataCount + ", strips:%u " + offsets.dataCount); } uint width = raw.GetEntry(TagType.IMAGEWIDTH).GetUInt(0); uint height = raw.GetEntry(TagType.IMAGELENGTH).GetUInt(0); int bitPerPixel = raw.GetEntry(TagType.BITSPERSAMPLE).GetInt(0); rawImage.fullSize.ColorDepth = (ushort)bitPerPixel; // Sony E-550 marks compressed 8bpp ARW with 12 bit per pixel // this makes the compression detect it as a ARW v1. // This camera has however another MAKER entry, so we MAY be able // to detect it this way in the future. data = ifd.GetIFDsWithTag(TagType.MAKE); if (data.Count > 1) { for (Int32 i = 0; i < data.Count; i++) { string make = data[i].GetEntry(TagType.MAKE).DataAsString; // Check for maker "SONY" without spaces if (make != "SONY") { bitPerPixel = 8; } } } bool arw1 = counts.GetInt(0) * 8 != width * height * bitPerPixel; if (arw1) { height += 8; } rawImage.fullSize.dim = new Point2D(width, height); rawImage.Init(false); UInt16[] curve = new UInt16[0x4001]; Tag c = raw.GetEntry(TagType.SONY_CURVE); uint[] sony_curve = { 0, 0, 0, 0, 0, 4095 }; for (int i = 0; i < 4; i++) { sony_curve[i + 1] = (uint)(c.GetShort(i) >> 2) & 0xfff; } for (int i = 0; i < 0x4001; i++) { curve[i] = (ushort)i; } for (int i = 0; i < 5; i++) { for (uint j = sony_curve[i] + 1; j <= sony_curve[i + 1]; j++) { curve[j] = (ushort)(curve[j - 1] + (1 << i)); } } var table = new TableLookUp(curve, 0x4000, true); long c2 = counts.GetUInt(0); uint off = offsets.GetUInt(0); if (!reader.IsValid(off)) { throw new RawDecoderException("Sony ARW decoder: Data offset after EOF, file probably truncated"); } if (!reader.IsValid(off, c2)) { c2 = reader.BaseStream.Length - off; } ImageBinaryReader input = new ImageBinaryReader(reader.BaseStream, off); if (arw1) { DecodeARW(input, width, height); } else { DecodeARW2(input, width, height, bitPerPixel); } //table was already applyed rawImage.table = null; }
public override void DecodeMetadata() { base.DecodeMetadata(); //get transform matrix var matrix = ifd.GetEntryRecursive(TagType.FORWARDMATRIX1); if (matrix == null) { matrix = ifd.GetEntryRecursive(TagType.FORWARDMATRIX2); } if (matrix != null) { rawImage.convertionM = new double[3, 3]; for (int i = 0; i < 3; i++) { for (int k = 0; k < 3; k++) { rawImage.convertionM[i, k] = matrix.GetDouble(i * 3 + k); } } } // Linearization Tag lintable = raw.GetEntry(TagType.LINEARIZATIONTABLE); if (lintable != null) { rawImage.table = new TableLookUp(lintable.GetUShortArray(), (int)lintable.dataCount, true); } Tag as_shot_neutral = ifd.GetEntryRecursive(TagType.ASSHOTNEUTRAL); if (as_shot_neutral != null) { if (as_shot_neutral.dataCount == 3) { rawImage.metadata.WbCoeffs = new WhiteBalance(1.0f / as_shot_neutral.GetFloat(0), 1.0f / as_shot_neutral.GetFloat(1), 1.0f / as_shot_neutral.GetFloat(2)); } } else { Tag as_shot_white_xy = ifd.GetEntryRecursive(TagType.ASSHOTWHITEXY); if (as_shot_white_xy != null) { if (as_shot_white_xy.dataCount == 2) { float[] d65_white = { 0.950456F, 1, 1.088754F }; rawImage.metadata.WbCoeffs = new WhiteBalance( as_shot_white_xy.GetFloat(0) / d65_white[0], as_shot_white_xy.GetFloat(1) / d65_white[1], (1 - rawImage.metadata.WbCoeffs.Red - rawImage.metadata.WbCoeffs.Green) / d65_white[2]); } } } // Crop Tag active_area = raw.GetEntry(TagType.ACTIVEAREA); if (active_area != null) { if (active_area.dataCount != 4) { throw new RawDecoderException("Active area has " + active_area.dataCount + " values instead of 4"); } if (new Point2D(active_area.GetUInt(1), active_area.GetUInt(0)).IsThisInside(rawImage.fullSize.dim)) { if (new Point2D(active_area.GetUInt(3), active_area.GetUInt(2)).IsThisInside(rawImage.fullSize.dim)) { Rectangle2D crop = new Rectangle2D(active_area.GetUInt(1), active_area.GetUInt(0), active_area.GetUInt(3) - active_area.GetUInt(1), active_area.GetUInt(2) - active_area.GetUInt(0)); rawImage.Crop(crop); } } } Tag origin_entry = raw.GetEntry(TagType.DEFAULTCROPORIGIN); Tag size_entry = raw.GetEntry(TagType.DEFAULTCROPSIZE); if (origin_entry != null && size_entry != null) { Rectangle2D cropped = new Rectangle2D(0, 0, rawImage.fullSize.dim.width, rawImage.fullSize.dim.height); /* Read crop position (sometimes is rational so use float) */ if (new Point2D(origin_entry.GetUInt(0), origin_entry.GetUInt(1)).IsThisInside(rawImage.fullSize.dim)) { cropped = new Rectangle2D(origin_entry.GetUInt(0), origin_entry.GetUInt(1), 0, 0); } cropped.Dimension = rawImage.fullSize.dim - cropped.Position; /* Read size (sometimes is rational so use float) */ Point2D size = new Point2D(size_entry.GetUInt(0), size_entry.GetUInt(1)); if ((size + cropped.Position).IsThisInside(rawImage.fullSize.dim)) { cropped.Dimension = size; } if (!cropped.HasPositiveArea()) { throw new RawDecoderException("No positive crop area"); } rawImage.Crop(cropped); if (rawImage.isCFA && cropped.Position.width % 2 == 1) { rawImage.colorFilter.ShiftLeft(1); } if (rawImage.isCFA && cropped.Position.height % 2 == 1) { rawImage.colorFilter.ShiftDown(1); } } if (rawImage.fullSize.dim.Area <= 0) { throw new RawDecoderException("No image left after crop"); } // Default white level is (2 ** BitsPerSample) - 1 rawImage.whitePoint = (1 >> raw.GetEntry(TagType.BITSPERSAMPLE).GetInt(0) - 1); Tag whitelevel = raw.GetEntry(TagType.WHITELEVEL); if (whitelevel != null) { rawImage.whitePoint = whitelevel.GetInt(0); } // Set black SetBlack(raw); }
bool Decodeblacks(IFD raw) { Point2D blackdim = new Point2D(1, 1); Tag bleveldim = raw.GetEntry(TagType.BLACKLEVELREPEATDIM); if (bleveldim != null) { if (bleveldim.dataCount != 2) { return(false); } blackdim = new Point2D(bleveldim.GetUInt(0), bleveldim.GetUInt(1)); } if (blackdim.width == 0 || blackdim.height == 0) { return(false); } if (raw.GetEntry(TagType.BLACKLEVEL) == null) { return(true); } if (rawImage.fullSize.cpp != 1) { return(false); } Tag black_entry = raw.GetEntry(TagType.BLACKLEVEL); if ((int)black_entry.dataCount < blackdim.width * blackdim.height) { throw new RawDecoderException("Black level entry is too small"); } if (black_entry.dataCount > 1) { Debug.Assert(black_entry.GetFloat(0) == black_entry.GetFloat(1)); } rawImage.black = (int)black_entry.GetFloat(0); /* * if (blackdim.Width < 2 || blackdim.Height < 2) * { * // We so not have enough to fill all individually, read a single and copy it * rawImage.black = (int)black_entry.GetFloat(0); * } * else * { * for (int y = 0; y < 2; y++) * { * for (int x = 0; x < 2; x++) * rawImage.blackLevelSeparate[y * 2 + x] = (int)black_entry.GetFloat((int)(y * blackdim.Width + x)); * } * }*/ // DNG Spec says we must add black in deltav and deltah Tag blackleveldeltav = raw.GetEntry(TagType.BLACKLEVELDELTAV); if (blackleveldeltav != null) { if ((int)blackleveldeltav.dataCount < rawImage.fullSize.dim.height) { throw new RawDecoderException("BLACKLEVELDELTAV array is too small"); } float[] black_sum = { 0.0f, 0.0f }; for (int i = 0; i < rawImage.fullSize.dim.height; i++) { black_sum[i & 1] += blackleveldeltav.GetFloat(i); } Debug.Assert(black_sum[0] == black_sum[1]); rawImage.black += (int)(black_sum[0] / rawImage.fullSize.dim.height * 2.0f); //for (int i = 0; i < 4; i++) rawImage.blackLevelSeparate[i] += (int)(black_sum[i >> 1] / rawImage.raw.dim.Height * 2.0f); } Tag blackleveldeltah = raw.GetEntry(TagType.BLACKLEVELDELTAH); if (blackleveldeltah != null) { if ((int)blackleveldeltah.dataCount < rawImage.fullSize.dim.width) { throw new RawDecoderException("BLACKLEVELDELTAH array is too small"); } float[] black_sum = { 0.0f, 0.0f }; for (int i = 0; i < rawImage.fullSize.dim.width; i++) { black_sum[i & 1] += blackleveldeltah.GetFloat(i); } Debug.Assert(black_sum[0] == black_sum[1]); rawImage.black += (int)(black_sum[0] / rawImage.fullSize.dim.width * 2.0f); //for (int i = 0; i < 4; i++) rawImage.blackLevelSeparate[i] += (int)(black_sum[i & 1] / rawImage.raw.dim.Width * 2.0f); } return(true); }
public override void DecodeRaw() { List <IFD> data = ifd.GetIFDsWithTag(TagType.COMPRESSION); if (data.Count == 0) { throw new RawDecoderException("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).GetInt(0); bool isSubsampled = false; try { isSubsampled = ((i.GetEntry(TagType.NEWSUBFILETYPE)?.GetInt(0) ?? 0) & 1) != 0; // bit 0 is on if image is subsampled } catch (RawDecoderException) { } 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("No RAW chunks found"); } raw = data[0]; int sampleFormat = 1; int bps = raw.GetEntry(TagType.BITSPERSAMPLE).GetInt(0); if (raw.tags.ContainsKey(TagType.SAMPLEFORMAT)) { sampleFormat = raw.GetEntry(TagType.SAMPLEFORMAT).GetInt(0); } if (sampleFormat != 1) { throw new RawDecoderException("Only 16 bit unsigned data supported."); } rawImage.isCFA = (raw.GetEntry(TagType.PHOTOMETRICINTERPRETATION).GetUShort(0) == 32803); if (sampleFormat == 1 && bps > 16) { throw new RawDecoderException("Integer precision larger than 16 bits currently not supported."); } if (sampleFormat == 3 && bps != 32) { throw new RawDecoderException("Float point must be 32 bits per sample."); } rawImage.fullSize.dim = new Point2D() { width = raw.GetEntry(TagType.IMAGEWIDTH).GetUInt(0), height = raw.GetEntry(TagType.IMAGELENGTH).GetUInt(0) }; rawImage.Init(false); rawImage.fullSize.ColorDepth = (ushort)bps; int compression = raw.GetEntry(TagType.COMPRESSION).GetShort(0); // Now load the image switch (compression) { case 1: uint cpp = raw.GetEntry(TagType.SAMPLESPERPIXEL).GetUInt(0); if (cpp > 4) { throw new RawDecoderException("More than 4 samples per pixel is not supported."); } rawImage.fullSize.cpp = cpp; 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; } DecodeUncompressed(raw, big_endian ? BitOrder.Jpeg : BitOrder.Plain); break; case 7: case 0x884c: rawImage.fullSize.cpp = raw.GetEntry(TagType.SAMPLESPERPIXEL).GetUInt(0); // Let's try loading it as tiles instead if (sampleFormat != 1) { throw new RawDecoderException("Only 16 bit unsigned data supported for compressed data."); } DngDecoderSlices slices = new DngDecoderSlices(reader, rawImage); if (raw.tags.ContainsKey(TagType.TILEOFFSETS)) { int tilew = raw.GetEntry(TagType.TILEWIDTH).GetInt(0); int tileh = raw.GetEntry(TagType.TILELENGTH).GetInt(0); if (tilew == 0 || tileh == 0) { throw new RawDecoderException("Invalid tile size"); } long tilesX = (rawImage.fullSize.dim.width + tilew - 1) / tilew; long tilesY = (rawImage.fullSize.dim.height + tileh - 1) / tileh; long 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("Tile count mismatch: offsets:" + offsets.dataCount + " count:" + counts.dataCount + ", calculated:" + nTiles); } slices.FixLjpeg = fixLjpeg; for (int y = 0; y < tilesY; y++) { for (int x = 0; x < tilesX; x++) { DngSliceElement e = new DngSliceElement(offsets.GetUInt((int)(x + y * tilesX)), counts.GetUInt((int)(x + y * tilesX)), (uint)(tilew * x), (uint)(tileh * y)) { mUseBigtable = tilew * tileh > 1024 * 1024 }; slices.slices.Add(e); } } } else { // Strips Tag offsets = raw.GetEntry(TagType.STRIPOFFSETS); Tag counts = raw.GetEntry(TagType.STRIPBYTECOUNTS); uint yPerSlice = raw.GetEntry(TagType.ROWSPERSTRIP).GetUInt(0); if (counts.dataCount != offsets.dataCount) { throw new RawDecoderException("Byte count number does not match strip size: count:" + counts.dataCount + ", strips:" + offsets.dataCount); } if (yPerSlice == 0 || yPerSlice > rawImage.fullSize.dim.height) { throw new RawDecoderException("Invalid y per slice"); } uint offY = 0; for (int s = 0; s < counts.dataCount; s++) { DngSliceElement e = new DngSliceElement(offsets.GetUInt(s), counts.GetUInt(s), 0, offY) { mUseBigtable = yPerSlice * rawImage.fullSize.dim.height > 1024 * 1024 }; offY += yPerSlice; if (reader.IsValid(e.byteOffset, e.byteCount)) // Only decode if size is valid { slices.slices.Add(e); } } } if (slices.slices.Count == 0) { throw new RawDecoderException("No valid slices found."); } slices.DecodeSlice(); if (rawImage.errors.Count >= slices.slices.Count) { throw new RawDecoderException("Too many errors encountered. Giving up.\nFirst Error:" + rawImage.errors[0]); } break; default: throw new RawDecoderException("Unknown compression: " + compression); } }
public override void DecodeRaw() { List <IFD> data = ifd.GetIFDsWithTag(TagType.PANASONIC_STRIPOFFSET); bool isOldPanasonic = false; if (data.Count == 0) { data = ifd.GetIFDsWithTag(TagType.STRIPOFFSETS); if (data == null) { throw new RawDecoderException("No image data found"); } isOldPanasonic = true; } raw = data[0]; uint height = raw.GetEntry((TagType)3).GetUInt(0); uint width = raw.GetEntry((TagType)2).GetUInt(0); if (isOldPanasonic) { Tag offsets = raw.GetEntry(TagType.STRIPOFFSETS); if (offsets.dataCount != 1) { throw new RawDecoderException("Multiple Strips found:" + offsets.dataCount); } uint off = offsets.GetUInt(0); if (!reader.IsValid(off)) { throw new RawDecoderException("Invalid image data offset, cannot decode."); } rawImage.fullSize.dim = new Point2D(width, height); rawImage.Init(false); UInt32 size = (uint)(reader.BaseStream.Length - off); input_start = new ImageBinaryReader(stream, off); if (size >= width * height * 2) { // It's completely unpacked little-endian RawDecompressor.Decode12BitRawUnpacked(input_start, new Point2D(width, height), new Point2D(), rawImage); rawImage.fullSize.ColorDepth = 12; } else if (size >= width * height * 3 / 2) { // It's a packed format RawDecompressor.Decode12BitRawWithControl(input_start, new Point2D(width, height), new Point2D(), rawImage); rawImage.fullSize.ColorDepth = 12; } else { var colorTag = raw.GetEntry((TagType)5); if (colorTag != null) { rawImage.fullSize.ColorDepth = colorTag.GetUShort(0); } else { //try to load with 12bits colordepth } // It's using the new .RW2 decoding method load_flags = 0; DecodeRw2(); } } else { rawImage.fullSize.dim = new Point2D(width, height); rawImage.Init(false); Tag offsets = raw.GetEntry(TagType.PANASONIC_STRIPOFFSET); if (offsets.dataCount != 1) { throw new RawDecoderException("Multiple Strips found:" + offsets.dataCount); } load_flags = 0x2008; uint off = offsets.GetUInt(0); if (!reader.IsValid(off)) { throw new RawDecoderException("Invalid image data offset, cannot decode."); } input_start = new ImageBinaryReader(stream, off); DecodeRw2(); } }
public override void DecodeMetadata() { base.DecodeMetadata(); if (rawImage.metadata.Model == null) { throw new RawDecoderException("Model name not found"); } if (rawImage.metadata.Make == null) { throw new RawDecoderException("Make name not found"); } string mode = GuessMode(); SetMetadata(rawImage.metadata.Model); rawImage.metadata.Mode = mode; //in panasonic, exif are in ifd 0 if (rawImage.fullSize.ColorDepth == 16) { rawImage.fullSize.ColorDepth = 12; } //panasonic iso is in a special tag if (rawImage.metadata.IsoSpeed == 0) { var t = raw.GetEntryRecursive(TagType.PANASONIC_ISO_SPEED); if (t != null) { rawImage.metadata.IsoSpeed = t.GetInt(0); } } // Read blacklevels var bias = raw.GetEntry((TagType)0x08).GetInt(0) + raw.GetEntry((TagType)0x09).GetInt(0) + raw.GetEntry((TagType)0x0a).GetInt(0); var rTag = raw.GetEntry((TagType)0x1c); var gTag = raw.GetEntry((TagType)0x1d); var bTag = raw.GetEntry((TagType)0x1e); if (rTag != null && gTag != null && bTag != null) { Debug.Assert(bTag.GetInt(0) + 15 == rTag.GetInt(0) + 15); Debug.Assert(bTag.GetInt(0) + 15 == gTag.GetInt(0) + 15); rawImage.black = rTag.GetInt(0) + bias; /* * rawImage.blackLevelSeparate[0] = rTag.GetInt(0) + 15; * rawImage.blackLevelSeparate[1] = rawImage.blackLevelSeparate[2] = gTag.GetInt(0) + 15; * rawImage.blackLevelSeparate[3] = bTag.GetInt(0) + 15;*/ } // Read WB levels var rWBTag = raw.GetEntry((TagType)0x0024); var gWBTag = raw.GetEntry((TagType)0x0025); var bWBTag = raw.GetEntry((TagType)0x0026); if (rWBTag != null && gWBTag != null && bWBTag != null) { rawImage.metadata.WbCoeffs = new WhiteBalance(bWBTag.GetShort(0), gWBTag.GetShort(0), rWBTag.GetShort(0), rawImage.fullSize.ColorDepth); } else { var wb1Tag = raw.GetEntry((TagType)0x0011); var wb2Tag = raw.GetEntry((TagType)0x0012); if (wb1Tag != null && wb2Tag != null) { rawImage.metadata.WbCoeffs = new WhiteBalance(wb1Tag.GetShort(0), 1, wb2Tag.GetShort(0)); } } }
public override Thumbnail DecodeThumb() { //find the preview IFD (usually the first if any) List <IFD> potential = ifd.GetIFDsWithTag(TagType.NEWSUBFILETYPE); IFD thumbIFD = null; if (potential?.Count != 0) { for (int i = 0; i < potential.Count; i++) { var subFile = potential[i].GetEntry(TagType.NEWSUBFILETYPE); if (subFile.GetInt(0) == 1) { thumbIFD = potential[i]; break; } } } if (thumbIFD != null) { //there is a thumbnail uint bps = thumbIFD.GetEntry(TagType.BITSPERSAMPLE).GetUInt(0); Point2D dim = new Point2D(thumbIFD.GetEntry(TagType.IMAGEWIDTH).GetUInt(0), thumbIFD.GetEntry(TagType.IMAGELENGTH).GetUInt(0)); int compression = thumbIFD.GetEntry(TagType.COMPRESSION).GetShort(0); // Now load the image if (compression == 1) { // Uncompressed uint cpp = thumbIFD.GetEntry(TagType.SAMPLESPERPIXEL).GetUInt(0); 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); uint yPerSlice = thumbIFD.GetEntry(TagType.ROWSPERSTRIP).GetUInt(0); reader.BaseStream.Position = offsets.GetInt(0) + offsets.parent_offset; return(new JPEGThumbnail(reader.ReadBytes(counts.GetInt(0)))); } else if (compression == 6) { var offset = thumbIFD.GetEntry((TagType)0x0201); var size = thumbIFD.GetEntry((TagType)0x0202); if (size == null || offset == null) { return(null); } //get the makernote offset List <IFD> exifs = ifd.GetIFDsWithTag((TagType)0x927C); if (exifs == null || exifs.Count == 0) { return(null); } Tag makerNoteOffsetTag = exifs[0].GetEntryRecursive((TagType)0x927C); if (makerNoteOffsetTag == null) { return(null); } reader.Position = offset.GetUInt(0) + 10 + makerNoteOffsetTag.dataOffset; return(new JPEGThumbnail(reader.ReadBytes(size.GetInt(0)))); } else { return(null); } } else { var previews = ifd.GetIFDsWithTag(TagType.JPEGINTERCHANGEFORMAT); //no thumbnail if (previews?.Count == 0) { return(null); } var preview = previews[0]; var thumb = preview.GetEntry(TagType.JPEGINTERCHANGEFORMAT); var size = preview.GetEntry(TagType.JPEGINTERCHANGEFORMATLENGTH); if (size == null || thumb == null) { return(null); } reader.Position = thumb.GetUInt(0) + thumb.parent_offset; return(new JPEGThumbnail(reader.ReadBytes(size.GetInt(0)))); } }
public override void DecodeRaw() { List <IFD> data = ifd.GetIFDsWithTag(TagType.FUJI_STRIPOFFSETS); if (data.Count <= 0) { throw new RawDecoderException("Fuji decoder: Unable to locate raw IFD"); } IFD raw = data[0]; uint height = 0; uint width = 0; var dim = raw.GetEntry(TagType.FUJI_RAWIMAGEFULLHEIGHT); if (dim != null) { height = dim.GetUInt(0); width = raw.GetEntry(TagType.FUJI_RAWIMAGEFULLWIDTH).GetUInt(0); } else { Tag wtag = raw.GetEntryRecursive(TagType.IMAGEWIDTH); if (wtag != null) { if (wtag.dataCount < 2) { throw new RawDecoderException("Fuji decoder: Size array too small"); } height = wtag.GetUShort(0); width = wtag.GetUShort(1); } } Tag e = raw.GetEntryRecursive(TagType.FUJI_LAYOUT); if (e != null) { if (e.dataCount < 2) { throw new RawDecoderException("Fuji decoder: Layout array too small"); } byte[] layout = e.GetByteArray(); //alt_layout = !(layout[0] >> 7); } if (width <= 0 || height <= 0) { throw new RawDecoderException("RAF decoder: Unable to locate image size"); } Tag offsets = raw.GetEntry(TagType.FUJI_STRIPOFFSETS); Tag counts = raw.GetEntry(TagType.FUJI_STRIPBYTECOUNTS); if (offsets.dataCount != 1 || counts.dataCount != 1) { throw new RawDecoderException("RAF Decoder: Multiple Strips found: " + offsets.dataCount + " " + counts.dataCount); } int off = offsets.GetInt(0); int count = counts.GetInt(0); ushort bps = 12; var bpsTag = raw.GetEntryRecursive(TagType.FUJI_BITSPERSAMPLE) ?? raw.GetEntryRecursive(TagType.BITSPERSAMPLE); if (bpsTag != null) { bps = bpsTag.GetUShort(0); } else { rawImage.errors.Add("BPS not found"); } rawImage.fullSize.ColorDepth = bps; // x-trans sensors report 14bpp, but data isn't packed so read as 16bpp if (bps == 14) { bps = 16; } // Some fuji SuperCCD cameras include a second raw image next to the first one // that is identical but darker to the first. The two combined can produce // a higher dynamic range image. Right now we're ignoring it. //bool double_width = hints.ContainsKey("double_width_unpacked"); rawImage.fullSize.dim = new Point2D(width, height); rawImage.Init(false); ImageBinaryReader input = new ImageBinaryReader(stream, (uint)(off + raw.RelativeOffset)); Point2D pos = new Point2D(0, 0); if (count * 8 / (width * height) < 10) { throw new RawDecoderException("Don't know how to decode compressed images"); } else if (ifd.endian == Endianness.Big) { RawDecompressor.Decode16BitRawUnpacked(input, new Point2D(width, height), pos, rawImage); } else { // RawDecompressor.ReadUncompressedRaw(input, rawImage.raw.dim, pos, width * bps / 8, bps, BitOrder.Jpeg32, rawImage); RawDecompressor.ReadUncompressedRaw(input, new Point2D(width, height), pos, width * bps / 8, bps, BitOrder.Plain, rawImage); } }
public override void DecodeMetadata() { base.DecodeMetadata(); if (rawImage.metadata.Model == null) { throw new RawDecoderException("ORF Meta Decoder: Model name found"); } SetMetaData(rawImage.metadata.Model); rawImage.metadata.Lens = ifd.GetEntryRecursive((TagType)42036)?.DataAsString; var rMul = ifd.GetEntryRecursive(TagType.OLYMPUSREDMULTIPLIER); var bMul = ifd.GetEntryRecursive(TagType.OLYMPUSBLUEMULTIPLIER); if (rMul != null && bMul != null) { rawImage.metadata.WbCoeffs = new WhiteBalance( ifd.GetEntryRecursive(TagType.OLYMPUSREDMULTIPLIER).GetShort(0), 1, ifd.GetEntryRecursive(TagType.OLYMPUSREDMULTIPLIER).GetShort(0)); } else { IFD image_processing = ifd.GetIFDWithType(IFDType.Makernote).subIFD[0]; Tag wb = image_processing.GetEntry((TagType)0x0100); // Get the WB if (wb?.dataCount == 2 || wb?.dataCount == 4) { rawImage.metadata.WbCoeffs = new WhiteBalance(wb.GetInt(0), 256, wb.GetInt(1), rawImage.fullSize.ColorDepth); } //TODO fix (the sub makernote doesn't read the correct value rawImage.metadata.WbCoeffs = new WhiteBalance(1, 1, 1); Tag blackEntry = image_processing.GetEntry((TagType)0x0600); // Get the black levels if (blackEntry != null) { Debug.Assert(blackEntry.GetInt(0) == blackEntry.GetInt(1)); rawImage.black = blackEntry.GetInt(0); // Order is assumed to be RGGB if (blackEntry.dataCount == 4) { //blackEntry.parent_offset = img_entry.parent_offset - 12; //blackEntry.offsetFromParent(); /*for (int i = 0; i < 4; i++) * { * if (rawImage.colorFilter.cfa[(i & 1) * 2 + i >> 1] == CFAColor.Red) * rawImage.blackLevelSeparate[i] = blackEntry.GetShort(0); * else if (rawImage.colorFilter.cfa[(i & 1) * 2 + i >> 1] == CFAColor.Blue) * rawImage.blackLevelSeparate[i] = blackEntry.GetShort(3); * else if (rawImage.colorFilter.cfa[(i & 1) * 2 + i >> 1] == CFAColor.Green && i < 2) * rawImage.blackLevelSeparate[i] = blackEntry.GetShort(1); * else if (rawImage.colorFilter.cfa[(i & 1) * 2 + i >> 1] == CFAColor.Green) * rawImage.blackLevelSeparate[i] = blackEntry.GetShort(2); * }*/ // Adjust whitelevel based on the read black (we assume the dynamic range is the same) //rawImage.whitePoint -= rawImage.black - rawImage.bla[0]; } } } }
public override void DecodeRaw() { List <IFD> data = ifd.GetIFDsWithTag(TagType.STRIPOFFSETS); if (data.Count == 0) { throw new RawDecoderException("ORF Decoder: No image data found"); } IFD raw = data[0]; int compression = raw.GetEntry(TagType.COMPRESSION).GetInt(0); if (1 != compression) { throw new RawDecoderException("ORF Decoder: Unsupported compression"); } Tag offsets = raw.GetEntry(TagType.STRIPOFFSETS); Tag counts = raw.GetEntry(TagType.STRIPBYTECOUNTS); if (counts.dataCount != offsets.dataCount) { throw new RawDecoderException("ORF Decoder: Byte count number does not match strip size: count:" + counts.dataCount + ", strips:" + offsets.dataCount); } uint off = raw.GetEntry(TagType.STRIPOFFSETS).GetUInt(0); uint size = 0; for (int i = 0; i < counts.dataCount; i++) { size += counts.GetUInt(i); } if (!reader.IsValid(off, size)) { throw new RawDecoderException("ORF Decoder: Truncated file"); } uint width = raw.GetEntry(TagType.IMAGEWIDTH).GetUInt(0); uint height = raw.GetEntry(TagType.IMAGELENGTH).GetUInt(0); rawImage.fullSize.dim = new Point2D(width, height); rawImage.Init(false); // We add 3 bytes slack, since the bitpump might be a few bytes ahead. ImageBinaryReader input = new ImageBinaryReader(reader.BaseStream, off); input.BaseStream.Position = off; try { if (offsets.dataCount != 1) { DecodeUncompressed(input, width, height, size, raw.endian); } else { DecodeCompressed(input, width, height); } } catch (IOException e) { rawImage.errors.Add(e.Message); } }
protected void DecodeUncompressed(IFD rawIFD, BitOrder order) { uint nslices = rawIFD.GetEntry(TagType.STRIPOFFSETS).dataCount; Tag offsets = rawIFD.GetEntry(TagType.STRIPOFFSETS); Tag counts = rawIFD.GetEntry(TagType.STRIPBYTECOUNTS); if (counts.dataCount != offsets.dataCount) { throw new RawDecoderException("Byte count number does not match strip size: count:" + counts.dataCount + ", strips:" + offsets.dataCount); } uint yPerSlice = rawIFD.GetEntry(TagType.ROWSPERSTRIP).GetUInt(0); uint width = rawIFD.GetEntry(TagType.IMAGEWIDTH).GetUInt(0); uint height = rawIFD.GetEntry(TagType.IMAGELENGTH).GetUInt(0); ushort bitPerPixel = rawIFD.GetEntry(TagType.BITSPERSAMPLE).GetUShort(0); rawImage.fullSize.ColorDepth = bitPerPixel; uint offY = 0; List <RawSlice> slices = new List <RawSlice>(); for (int s = 0; s < nslices; s++) { RawSlice slice = new RawSlice() { offset = offsets.GetUInt(s), count = counts.GetUInt(s), offsetY = offY }; if (offY + yPerSlice > height) { slice.h = height - offY; } else { slice.h = yPerSlice; } offY += yPerSlice; if (reader.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."); } rawImage.fullSize.dim = new Point2D(width, offY); rawImage.whitePoint = (ushort)((1 << bitPerPixel) - 1); offY = 0; for (int i = 0; i < slices.Count; i++) { RawSlice slice = slices[i]; reader.BaseStream.Position = slice.offset; bitPerPixel = (ushort)(slice.count * 8u / (slice.h * width)); RawDecompressor.ReadUncompressedRaw(reader, new Point2D(width, slice.h), new Point2D(0, slice.offsetY), rawImage.fullSize.cpp * width * bitPerPixel / 8, bitPerPixel, order, rawImage); offY += slice.h; } }