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 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 void DecodePentax(IFD root, uint offset, uint size) { // Prepare huffmann table 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 = 16 entries byte[] pentax_tree = { 0, 2, 3, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 3, 4, 2, 5, 1, 6, 0, 7, 8, 9, 10, 11, 12 }; // 0 1 2 3 4 5 6 7 8 9 0 1 2 = 13 entries /* Attempt to read huffman table, if found in makernote */ Tag t = root.GetEntryRecursive((TagType)0x220); if (t != null) { if (t.dataType == TiffDataType.UNDEFINED) { ImageBinaryReader stream; if (root.endian == Common.GetHostEndianness()) { stream = new ImageBinaryReader(t.GetByteArray()); } else { stream = new ImageBinaryReaderBigEndian(t.GetByteArray()); } int depth = (stream.ReadUInt16() + 12) & 0xf; stream.ReadBytes(12); uint[] v0 = new uint[16]; uint[] v1 = new uint[16]; uint[] v2 = new uint[16]; for (int i = 0; i < depth; i++) { v0[i] = stream.ReadUInt16(); } for (int i = 0; i < depth; i++) { v1[i] = stream.ReadByte(); } /* Reset bits */ for (int i = 0; i < 17; i++) { huff[0].bits[i] = 0; } /* Calculate codes and store bitcounts */ for (int c = 0; c < depth; c++) { v2[c] = v0[c] >> (int)(12 - v1[c]); huff[0].bits[v1[c]]++; } /* Find smallest */ for (int i = 0; i < depth; i++) { uint sm_val = 0xfffffff; uint sm_num = 0xff; for (uint j = 0; j < depth; j++) { if (v2[j] <= sm_val) { sm_num = j; sm_val = v2[j]; } } huff[0].huffval[i] = sm_num; v2[sm_num] = 0xffffffff; } stream.Dispose(); } else { throw new RawDecoderException("Unknown Huffman table type."); } } else { /* Initialize with legacy data */ uint acc = 0; for (int i = 0; i < 16; i++) { huff[0].bits[i + 1] = pentax_tree[i]; acc += huff[0].bits[i + 1]; } huff[0].bits[0] = 0; for (int i = 0; i < acc; i++) { huff[0].huffval[i] = pentax_tree[i + 16]; } } huff[0].UseBigTable = true; huff[0].Create(frame.precision); input.BaseStream.Position = 0; huff[0].bitPump = new BitPumpMSB(input, offset, size); int[] pUp1 = { 0, 0 }; int[] pUp2 = { 0, 0 }; int pLeft1 = 0; int pLeft2 = 0; for (int y = 0; y < raw.fullSize.dim.height; y++) { var realY = y * raw.fullSize.dim.width; pUp1[y & 1] += huff[0].Decode(); pUp2[y & 1] += huff[0].Decode(); raw.fullSize.rawView[realY] = (ushort)(pLeft1 = pUp1[y & 1]); raw.fullSize.rawView[realY + 1] = (ushort)(pLeft2 = pUp2[y & 1]); for (int x = 2; x < raw.fullSize.dim.width; x += 2) { pLeft1 += huff[0].Decode(); pLeft2 += huff[0].Decode(); raw.fullSize.rawView[realY + x] = (ushort)pLeft1; raw.fullSize.rawView[realY + x + 1] = (ushort)pLeft2; } } }
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 DecodeRaw() { int photoMetric = ifd.GetEntryRecursive((TagType)0x0106)?.GetInt(0) ?? throw new FormatException("File not correct");; if (photoMetric != 2) { throw new FormatException("Photometric interpretation " + photoMetric + " not supported yet"); } uint height = ifd.GetEntryRecursive((TagType)0x0101)?.GetUInt(0) ?? throw new FormatException("File not correct"); uint width = ifd.GetEntryRecursive((TagType)0x0100)?.GetUInt(0) ?? throw new FormatException("File not correct"); rawImage.isCFA = false; rawImage.fullSize.dim = new Point2D(width, height); rawImage.fullSize.UncroppedDim = rawImage.fullSize.dim; rawImage.fullSize.ColorDepth = ifd.GetEntryRecursive((TagType)0x0102)?.GetUShort(0) ?? throw new FormatException("File not correct"); rawImage.fullSize.cpp = 3; rawImage.Init(true); rawImage.IsGammaCorrected = false; int compression = ifd.GetEntryRecursive((TagType)0x0103)?.GetInt(0) ?? throw new FormatException("File not correct"); if (compression == 1) { DecodeUncompressed(ifd, BitOrder.Plain); } else if (compression == 32773 && rawImage.fullSize.ColorDepth <= 8) { /*Loop until you get the number of unpacked bytes you are expecting: * Read the next source byte into n. * If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. * Else if n is between - 127 and - 1 inclusive, copy the next byte -n + 1 * times. * Else if n is - 128, noop. * Endloop */ long rowperstrip = ifd.GetEntryRecursive((TagType)0x0116)?.GetLong(0) ?? throw new FormatException("File not correct"); long strips = height / rowperstrip; long lastStrip = height % rowperstrip; var imageOffsetTag = ifd.GetEntryRecursive((TagType)0x0111) ?? throw new FormatException("File not correct"); int cpp = ifd.GetEntryRecursive((TagType)0x0115)?.GetInt(0) ?? throw new FormatException("File not correct"); for (int i = 0; i < strips + ((lastStrip == 0) ? 0 : 1); i++) { //for each complete strip //move to the offset reader.Position = imageOffsetTag.GetLong(i); for (int y = 0; y < rowperstrip && !(i == strips && y < lastStrip); y++) { //uncompress line by line of pixel ushort[] temp = new ushort[3 * width]; short buffer = 0; int count = 0; for (int x = 0; x < width * 3;) { buffer = reader.ReadByte(); count = 0; if (buffer >= 0) { for (int k = 0; k < count; ++k, ++x) { temp[x] = reader.ReadByte(); } } else { count = -buffer; buffer = reader.ReadByte(); for (int k = 0; k < count; ++k, ++x) { temp[x] = (ushort)buffer; } } } for (int x = 0; x < width * 3; x++) { //red rawImage.fullSize.red[(y + i * rowperstrip) * width + x] = temp[x * 3]; //green rawImage.fullSize.green[(y + i * rowperstrip) * width + x] = temp[x * 3 + 1]; //blue rawImage.fullSize.blue[(y + i * rowperstrip) * width + x] = temp[x * 3 + 2]; for (int z = 0; z < (cpp - 3); z++) { //pass the other pixel if more light reader.ReadByte(); } } } } } else { //we know it's tiff so tiff decoder id var decoder = BitmapDecoder.CreateAsync(BitmapDecoder.TiffDecoderId, stream.AsRandomAccessStream()).AsTask(); decoder.Wait(); var bitmapasync = decoder.Result.GetSoftwareBitmapAsync().AsTask(); bitmapasync.Wait(); rawImage.fullSize.ColorDepth = 8; using (var img = bitmapasync.Result) using (BitmapBuffer buffer = img.LockBuffer(BitmapBufferAccessMode.Write)) using (IMemoryBufferReference reference = buffer.CreateReference()) { BitmapPlaneDescription bufferLayout = buffer.GetPlaneDescription(0); rawImage.fullSize.dim = new Point2D((uint)bufferLayout.Width, (uint)bufferLayout.Height); rawImage.Init(true); unsafe { ((IMemoryBufferByteAccess)reference).GetBuffer(out var temp, out uint capacity); for (int y = 0; y < rawImage.fullSize.dim.height; y++) { long realY = y * rawImage.fullSize.dim.width; long bufferY = y * rawImage.fullSize.dim.width * 4 + +bufferLayout.StartIndex; for (int x = 0; x < rawImage.fullSize.dim.width; x++) { long realPix = realY + x; long bufferPix = bufferY + (4 * x); rawImage.fullSize.red[realPix] = temp[bufferPix + 2]; rawImage.fullSize.green[realPix] = temp[bufferPix + 1]; rawImage.fullSize.blue[realPix] = temp[bufferPix]; } } } } } }