public DNGFile(string aFileName) : base(aFileName) { byte a = mFileReader.ReadByte(); byte b = mFileReader.ReadByte(); bool fileIsLittleEndian; if (a == b && b == 'I') { fileIsLittleEndian = true; } else if (a == b && b == 'M') { fileIsLittleEndian = false; } else { throw new FileLoadException("Could not determine file endianess. Is this a proper TIFF/PEF file?", aFileName); } mEndianSwap = fileIsLittleEndian != BitConverter.IsLittleEndian; ushort magicNumber = ReadUI2(); if (magicNumber != 42) { throw new FileLoadException("This is not a valid TIFF/PEF file: Magic number is not 42.", aFileName); } uint offsetToFirstIFD = ReadUI4(); mFile.Seek(offsetToFirstIFD, SeekOrigin.Begin); List <ImageFileDirectory> ifds = new List <ImageFileDirectory>(); while (true) { ImageFileDirectory ifd = new ImageFileDirectory(this); ifds.Add(ifd); uint offsetToNext = ReadUI4(); if (offsetToNext == 0) { break; } Seek(offsetToNext, System.IO.SeekOrigin.Begin); } IFDDNGVersion version = ifds[0].GetEntry <IFDDNGVersion>(); isDNGVersionLarge = version == null; if (version != null) { isDNGVersionLarge = version.Value[1] > 1; } IFDSubIFDs sub = ifds[0].GetEntry <IFDSubIFDs>(); mWidth = (int)sub.Value[0].GetEntry <IFDImageWidth>().Value; mHeight = (int)sub.Value[0].GetEntry <IFDImageLength>().Value; IFDExif exif = ifds[0].GetEntry <IFDExif>(); mISO = exif.GetEntry <ExifEntry.ExifISOSpeedRatings>().Value; mBitDepth = sub.Value[0].GetEntry <IFDBitsPerSample>().Value; mBayerPattern = sub.Value[0].GetEntry <IFDCFAPattern>().Value; mBayerWidth = sub.Value[0].GetEntry <IFDCFARepeatPatternDim>().Value[0]; mBayerHeight = sub.Value[0].GetEntry <IFDCFARepeatPatternDim>().Value[1]; mWhiteLevel = sub.Value[0].GetEntry <IFDDNGWhiteLevel>(); mBlackLevel = sub.Value[0].GetEntry <IFDDNGBlackLevel>(); mAsShotNeutral = sub.Value[0].GetEntry <IFDDNGAsShotNeutral>(); mLinearizationTable = sub.Value[0].GetEntry <IFDDNGLinearizationTable>(); mMinVal = new float[3]; mMinVal[0] = (float)mBlackLevel.Value[0].Value; mMinVal[1] = (float)mBlackLevel.Value[mBlackLevel.Value.Length > 1 ? 1 : 0].Value; mMinVal[2] = (float)mBlackLevel.Value[mBlackLevel.Value.Length > 3 ? 3 : 0].Value; mMaxVal = new float[3]; mMaxVal[0] = (float)mWhiteLevel.Value[0]; mMaxVal[1] = (float)mWhiteLevel.Value[mWhiteLevel.Value.Length > 1 ? 1 : 0]; mMaxVal[2] = (float)mWhiteLevel.Value[mWhiteLevel.Value.Length > 3 ? 3 : 0]; int tileWidth = (int)sub.Value[0].GetEntry <IFDTileWidth>().Value; int tileHeight = (int)sub.Value[0].GetEntry <IFDTileLength>().Value; uint[] offsets = sub.Value[0].GetEntry <IFDTileOffsets>().Value; uint[] byteCounts = sub.Value[0].GetEntry <IFDTileByteCounts>().Value; mRawImage = new ushort[mHeight, mWidth]; int row = 0; int col = 0; for (int tile = 0; tile < offsets.Length; tile++) { byte[] data; Seek(offsets[tile], SeekOrigin.Begin); data = mFileReader.ReadBytes((int)byteCounts[tile]); MemoryStream ms = new MemoryStream(data); ms.Seek(0, SeekOrigin.Begin); jhead jh = new jhead(); int ret = ljpeg_start(jh, 0, ms); int jrow, jcol; if (ret > 0 && jh != null) { int jwide = jh.wide; jwide *= jh.clrs; unsafe { if (jh.algo == 0xc3) //lossless JPEG { for (jrow = 0; jrow < jh.high; jrow++) { fixed(ushort *ptr = jh.row) { jh.rowPtr = ptr; ushort *rp = ljpeg_row(jrow, jh, ms); for (jcol = 0; jcol < jwide; jcol++) { if (jcol + col < mWidth && jrow + row < mHeight) { if (mLinearizationTable != null) { mRawImage[row + jrow, col + jcol] = mLinearizationTable.Value[rp[jcol] < mLinearizationTable.Value.Length ? rp[jcol] : mLinearizationTable.Value.Length - 1]; } else { mRawImage[row + jrow, col + jcol] = rp[jcol]; } } } jh.rowPtr = null; } } } } } col += tileWidth; if (col > mWidth) { col = 0; row += tileHeight; } } }
unsafe int ljpeg_start(jhead jh, int info_only, Stream s) { int c, tag, len; byte[] data = new byte[0x10000]; byte * dp; //jh = new jhead(); jh.restart = int.MaxValue; s.ReadByte(); if ((s.ReadByte()) != 0xd8) { return(0); } do { //s.Read(data, 0, 4); if (4 != s.Read(data, 0, 4)) { return(0); } tag = data[0] << 8 | data[1]; len = (data[2] << 8 | data[3]) - 2; if (tag <= 0xff00) { return(0); } s.Read(data, 0, len); //fread(data, 1, len, ifp); switch (tag) { case 0xffc3: jh.sraw = ((data[7] >> 4) * (data[7] & 15) - 1) & 3; jh.algo = tag & 0xff; jh.bits = data[0]; jh.high = data[1] << 8 | data[2]; jh.wide = data[3] << 8 | data[4]; jh.clrs = data[5] + jh.sraw; //if (len == 9 && !dng_version) getc(ifp); break; case 0xffc1: case 0xffc0: jh.algo = tag & 0xff; jh.bits = data[0]; jh.high = data[1] << 8 | data[2]; jh.wide = data[3] << 8 | data[4]; jh.clrs = data[5] + jh.sraw; //if (len == 9 && !dng_version) getc(ifp); break; case 0xffc4: //if (info_only) break; fixed(byte *ptr = data) { for (dp = ptr; dp < ptr + len && ((c = *dp++) & -20) == 0;) { jh.free[c] = jh.huff[c] = make_decoder_ref(&dp); } } break; case 0xffda: jh.psv = data[1 + data[0] * 2]; jh.bits -= data[3 + data[0] * 2] & 15; break; case 0xffdb: for (c = 0; c < 64; c++) { jh.quant[c] = (ushort)(data[c * 2 + 1] << 8 | data[c * 2 + 2]); } break; case 0xffdd: jh.restart = data[0] << 8 | data[1]; break; } } while (tag != 0xffda); for (c = 0; c < 19; c++) { if (jh.huff[c + 1] == null) { jh.huff[c + 1] = jh.huff[c]; } } //if (jh.sraw) { // FORC(4) jh->huff[2 + c] = jh->huff[1]; // FORC(jh->sraw) jh->huff[1 + c] = jh->huff[0]; //} jh.row = new ushort[jh.wide * jh.clrs * 2]; //(ushort*)calloc(jh->wide* jh->clrs, 4); //merror(jh->row, "ljpeg_start()"); return(1); }
private unsafe ushort *ljpeg_row(int jrow, jhead jh, Stream s) { int col, c, diff, pred, spred = 0; ushort mark = 0; ushort *[] row = new ushort *[3]; if (jrow * jh.wide % jh.restart == 0) { for (c = 0; c < 6; c++) { jh.vpred[c] = 1 << (jh.bits - 1); } if (jrow > 0) { s.Seek(-2, SeekOrigin.Current); //fseek(ifp, -2, SEEK_CUR); do { mark = (ushort)((mark << 8) + (c = s.ReadByte())); }while (s.Position < s.Length - 1 && mark >> 4 != 0xffd); } getbithuff(-1, null, s); } for (c = 0; c < 3; c++) { row[c] = jh.rowPtr + jh.wide * jh.clrs * ((jrow + c) & 1); } for (col = 0; col < jh.wide; col++) { for (c = 0; c < jh.clrs; c++) { fixed(ushort *ptr = jh.huff[c]) { diff = ljpeg_diff(ptr, s); if (jh.sraw > 0 && c <= jh.sraw && (col | c) > 0) { pred = spred; } else if (col > 0) { pred = row[0][-jh.clrs]; } else { pred = (jh.vpred[c] += diff) - diff; } if (jrow > 0 && col > 0) { switch (jh.psv) { case 1: break; case 2: pred = row[1][0]; break; case 3: pred = row[1][-jh.clrs]; break; case 4: pred = pred + row[1][0] - row[1][-jh.clrs]; break; case 5: pred = pred + ((row[1][0] - row[1][-jh.clrs]) >> 1); break; case 6: pred = row[1][0] + ((pred - row[1][-jh.clrs]) >> 1); break; case 7: pred = (pred + row[1][0]) >> 1; break; default: pred = 0; break; } } if ((*row[0] = (ushort)(pred + diff)) >> jh.bits != 0) { return(null); } if (c <= jh.sraw) { spred = *row[0]; } row[0]++; row[1]++; } } } return(row[2]); }
public DNGFile(string aFileName) : base(aFileName) { IFDDNGVersion version = mIfds[0].GetEntry <IFDDNGVersion>(); isDNGVersionLarge = version == null; if (version != null) { isDNGVersionLarge = version.Value[1] > 1; } ImageFileDirectory rawIFD = SetMembers(); //try to read additional noise models try { ExtraCameraProfiles profiles = ExtraCameraProfiles.Load("ExtraCameraProfiles.xml"); string make = mIfds[0].GetEntry <IFDMake>()?.Value; string uniqueModel = mIfds[0].GetEntry <IFDDNGUniqueCameraModel>()?.Value; ExtraCameraProfile profile = profiles.GetProfile(make, uniqueModel); double a, b; (a, b) = profile.NoiseModel.GetValue(mISO); if (a != 0.0) { mNoiseModelAlpha = (float)a; mNoiseModelBeta = (float)b; } } catch (Exception) { } //get non-global blacklevels ushort[] blackLevelV = new ushort[mHeight]; ushort[] blackLevelH = new ushort[mWidth]; int maxBlackLevel = 0; IFDDNGBlackLevelDeltaV deltaV = rawIFD.GetEntry <IFDDNGBlackLevelDeltaV>(); IFDDNGActiveArea activeArea = rawIFD.GetEntry <IFDDNGActiveArea>(); int blackOffsetH = 0; int blackOffsetV = 0; int borderBottom = 0; int borderRight = 0; if (activeArea != null) { blackOffsetV = (int)activeArea.Value[0]; blackOffsetH = (int)activeArea.Value[1]; borderBottom = mHeight - (int)activeArea.Value[2]; borderRight = mWidth - (int)activeArea.Value[3]; } if (deltaV != null) { if (deltaV.Value.Length + blackOffsetV + borderBottom != mHeight) { throw new Exception("Count in IFDDNGBlackLevelDeltaV doesn't fit image height"); } for (int i = 0; i < deltaV.Value.Length; i++) { blackLevelV[blackOffsetV + i] = (ushort)deltaV.Value[i].Value; } } IFDDNGBlackLevelDeltaH deltaH = rawIFD.GetEntry <IFDDNGBlackLevelDeltaH>(); if (deltaH != null) { if (deltaH.Value.Length + blackOffsetH + borderRight != mWidth) { throw new Exception("Count in IFDDNGBlackLevelDeltaH doesn't fit image width"); } for (int i = 0; i < deltaH.Value.Length; i++) { blackLevelH[blackOffsetH + i] = (ushort)deltaH.Value[i].Value; } } //read actual image data //data stored in tiles: if (rawIFD.GetEntry <IFDTileWidth>() != null) { int tileWidth = (int)rawIFD.GetEntry <IFDTileWidth>().Value; int tileHeight = (int)rawIFD.GetEntry <IFDTileLength>().Value; uint[] offsets = rawIFD.GetEntry <IFDTileOffsets>().Value; uint[] byteCounts = rawIFD.GetEntry <IFDTileByteCounts>().Value; mRawImage = new ushort[mHeight, mWidth]; int row = 0; int col = 0; if (rawIFD.GetEntry <IFDCompression>().Value == IFDCompression.Compression.LosslessJPEG) { for (int tile = 0; tile < offsets.Length; tile++) { byte[] data; Seek(offsets[tile], SeekOrigin.Begin); data = mFileReader.ReadBytes((int)byteCounts[tile]); MemoryStream ms = new MemoryStream(data); ms.Seek(0, SeekOrigin.Begin); jhead jh = new jhead(); int ret = ljpeg_start(jh, 0, ms); int jrow, jcol; if (ret > 0 && jh != null) { int jwide = jh.wide; jwide *= jh.clrs; unsafe { if (jh.algo == 0xc3) //lossless JPEG { for (jrow = 0; jrow < jh.high; jrow++) { fixed(ushort *ptr = jh.row) { jh.rowPtr = ptr; ushort *rp = ljpeg_row(jrow, jh, ms); for (jcol = 0; jcol < jwide; jcol++) { if (jcol + col < mWidth && jrow + row < mHeight) { int black = blackLevelH[jcol + col]; black += blackLevelV[jrow + row]; maxBlackLevel = Math.Max(maxBlackLevel, black); if (mLinearizationTable != null) { mRawImage[row + jrow, col + jcol] = (ushort)Math.Max(0, (int)(mLinearizationTable.Value[rp[jcol] < mLinearizationTable.Value.Length ? rp[jcol] : mLinearizationTable.Value.Length - 1]) - black); } else { mRawImage[row + jrow, col + jcol] = (ushort)Math.Max(0, (int)(rp[jcol] - black)); } } } jh.rowPtr = null; } } } } } col += tileWidth; if (col >= mWidth) { col = 0; row += tileHeight; } } } else { throw new ArgumentException("I don't know how to read that file :("); } } //data stored in strips: else if (rawIFD.GetEntry <IFDStripOffsets>() != null) { uint[] offsets = rawIFD.GetEntry <IFDStripOffsets>().Value; uint[] byteCounts = rawIFD.GetEntry <IFDStripByteCounts>().Value; uint rowsPerStrip = rawIFD.GetEntry <IFDRowsPerStrip>().Value; if (rawIFD.GetEntry <IFDCompression>().Value == IFDCompression.Compression.LosslessJPEG) { mRawImage = new ushort[mHeight, mWidth]; for (int strip = 0; strip < offsets.Length; strip++) { byte[] data; Seek(offsets[strip], SeekOrigin.Begin); data = mFileReader.ReadBytes((int)byteCounts[strip]); MemoryStream ms = new MemoryStream(data); ms.Seek(0, SeekOrigin.Begin); jhead jh = new jhead(); int ret = ljpeg_start(jh, 0, ms); int jrow, jcol; if (ret > 0 && jh != null) { int jwide = jh.wide; jwide *= jh.clrs; unsafe { if (jh.algo == 0xc3) //lossless JPEG { for (jrow = 0; jrow < jh.high; jrow++) { fixed(ushort *ptr = jh.row) { jh.rowPtr = ptr; ushort *rp = ljpeg_row(jrow, jh, ms); for (jcol = 0; jcol < jwide; jcol++) { if (jcol < mWidth && jrow + (strip * rowsPerStrip) < mHeight) { int black = blackLevelH[jcol]; black += blackLevelV[(strip * rowsPerStrip) + jrow]; maxBlackLevel = Math.Max(maxBlackLevel, black); if (mLinearizationTable != null) { mRawImage[(strip * rowsPerStrip) + jrow, jcol] = (ushort)Math.Max(0, (int)((mLinearizationTable.Value[rp[jcol] < mLinearizationTable.Value.Length ? rp[jcol] : mLinearizationTable.Value.Length - 1]) - black)); } else { mRawImage[(strip * rowsPerStrip) + jrow, jcol] = (ushort)Math.Max(0, (int)(rp[jcol] - black)); } } } jh.rowPtr = null; } } } } } } } else if (rawIFD.GetEntry <IFDCompression>().Value == IFDCompression.Compression.NoCompression) { mRawImage = new ushort[mHeight, mWidth]; if (mBitDepth == 16) { for (int strip = 0; strip < offsets.Length; strip++) { byte[] data; Seek(offsets[strip], SeekOrigin.Begin); data = mFileReader.ReadBytes((int)byteCounts[strip]); unsafe { fixed(byte *ptr = data) { ushort *usptr = (ushort *)ptr; for (int pixel = 0; pixel < data.Length / 2; pixel++) { int row = strip * (int)rowsPerStrip; int col = pixel; if (col >= mWidth) { row += pixel / mWidth; col = pixel % mWidth; } int black = blackLevelH[col]; black += blackLevelV[row]; maxBlackLevel = Math.Max(maxBlackLevel, black); if (mLinearizationTable != null) { mRawImage[row, col] = (ushort)Math.Max(0, (int)(mLinearizationTable.Value[usptr[pixel] < mLinearizationTable.Value.Length ? usptr[pixel] : mLinearizationTable.Value.Length - 1]) - black); } else { mRawImage[row, col] = (ushort)Math.Max(0, (int)(usptr[pixel]) - black); } } } } } } else if (mBitDepth < 16) { for (int strip = 0; strip < offsets.Length; strip++) { byte[] data; Seek(offsets[strip], SeekOrigin.Begin); data = mFileReader.ReadBytes((int)byteCounts[strip]); uint pos = 0; int offset = 0; for (int line = 0; line < rowsPerStrip; line++) { for (int pixel = 0; pixel < mWidth; pixel++) { int row = strip * (int)rowsPerStrip + line; int col = pixel; uint val = data[pos]; while (offset < mBitDepth) { val = data[pos]; bitbuf = (bitbuf << 8) + val; offset += 8; pos++; } val = bitbuf << (32 - offset) >> (32 - mBitDepth); offset -= mBitDepth; int black = blackLevelH[col]; black += blackLevelV[row]; maxBlackLevel = Math.Max(maxBlackLevel, black); if (mLinearizationTable != null) { mRawImage[row, col] = (ushort)Math.Max(0, (int)(mLinearizationTable.Value[val < mLinearizationTable.Value.Length ? (ushort)(val) : mLinearizationTable.Value.Length - 1]) - black); } else { mRawImage[row, col] = (ushort)Math.Max(0, (int)(val) - black); } } } } } } else { throw new ArgumentException("I don't know how to read that file :("); } } //close the file Close(); WhiteLevel[0] -= maxBlackLevel; WhiteLevel[1] -= maxBlackLevel; WhiteLevel[2] -= maxBlackLevel; }