Exemple #1
0
        private T GetTag <T>(ImageFileDirectory ifd0, ImageFileDirectory raw) where T : PentaxPefFile.ImageFileDirectoryEntry
        {
            T tag = ifd0.GetEntry <T>();

            if (tag == null)
            {
                //try raw tag
                tag = raw.GetEntry <T>();
            }
            return(tag);
        }
        public RawFile(string aFileName)
            : base(aFileName)
        {
            //set some default values:

            //color channels are assumed in order RGB if no tag present
            mColorTwist           = new float[3, 4];
            mColorTwist[0, 0]     = 1.0f;
            mColorTwist[1, 1]     = 1.0f;
            mColorTwist[2, 2]     = 1.0f;
            mColorTwistIsIdentity = true;

            //it seems as if only Pentax is capable of giving us that info
            mRollAnglePresent = false;
            mRecordingDate    = new DateTime();

            //read all IFDs/Tags:
            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/DNG file?", aFileName);
            }

            mEndianSwap = fileIsLittleEndian != BitConverter.IsLittleEndian;

            ushort magicNumber = ReadUI2();

            if (magicNumber != 42)
            {
                throw new FileLoadException("This is not a valid TIFF/PEF/DNG file: Magic number is not 42.", aFileName);
            }

            uint offsetToFirstIFD = ReadUI4();

            mFile.Seek(offsetToFirstIFD, SeekOrigin.Begin);
            mIfds = new List <ImageFileDirectory>();
            while (true)
            {
                ImageFileDirectory ifd = new ImageFileDirectory(this);
                mIfds.Add(ifd);
                uint offsetToNext = ReadUI4();
                if (offsetToNext == 0)
                {
                    break;
                }
                Seek(offsetToNext, System.IO.SeekOrigin.Begin);
            }

            //until here PEF and DNG are the same. They diverge on how to read the tags
        }
        public PEFFile(string aFileName)
            : base(aFileName)
        {
            ImageFileDirectory raw = SetMembers();

            mRawImage = new ushort[mHeight, mWidth];
            if (mHhuffmanTable != null && raw.GetEntry <IFDStripOffsets>().Value.Length == 1)
            {
                uint offset = raw.GetEntry <IFDStripOffsets>().Value[0];

                Seek(offset, SeekOrigin.Begin);
                int[,] vpred = new int[2, 2];
                int[] hpred = new int[2];
                unsafe
                {
                    fixed(ushort *huff = mHhuffmanTable.Value)
                    {
                        getbithuff(-1, null);

                        for (int row = 0; row < mHeight; row++)
                        {
                            for (int col = 0; col < mWidth; col++)
                            {
                                int diff = ljpeg_diff(huff);
                                if (col < 2)
                                {
                                    hpred[col] = vpred[row & 1, col] += diff;
                                }
                                else
                                {
                                    hpred[col & 1] += diff;
                                }
                                mRawImage[row, col] = (ushort)hpred[col & 1];
                            }
                        }
                    }
                }
            }
            else if (mHhuffmanTable != null)
            {
                throw new Exception("TODO: implement compressed multiple stripes");
            }
            else
            {
                //uncompressed

                uint[] sizes        = raw.GetEntry <IFDStripByteCounts>().Value;
                uint[] offsets      = raw.GetEntry <IFDStripOffsets>().Value;
                uint   rowsPerStrip = raw.GetEntry <IFDRowsPerStrip>().Value;


                for (int strip = 0; strip < offsets.Length; strip++)
                {
                    byte[] data;
                    Seek(offsets[strip], SeekOrigin.Begin);
                    data = mFileReader.ReadBytes((int)sizes[strip]);

                    uint pos       = 0;
                    int  bitOffset = 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 (bitOffset < mBitDepth)
                            {
                                val        = data[pos];
                                bitbuf     = (bitbuf << 8) + val;
                                bitOffset += 8;
                                pos++;
                            }

                            val        = bitbuf << (32 - bitOffset) >> (32 - mBitDepth);
                            bitOffset -= mBitDepth;

                            mRawImage[row, col] = (ushort)(val);
                        }
                    }
                }
            }

            //close the file
            Close();
        }
Exemple #4
0
        public DNGColorSpec(uint aChannels, ImageFileDirectory ifd0, ImageFileDirectory raw)
        {
            fChannels = aChannels;
            if (GetTag <IFDDNGCalibrationIlluminant1>(ifd0, raw) != null)
            {
                fTemperature1 = ConvertIlluminantToTemperature(GetTag <IFDDNGCalibrationIlluminant1>(ifd0, raw).Value);
            }
            else
            {
                fTemperature1 = 0.0;
            }
            if (GetTag <IFDDNGCalibrationIlluminant2>(ifd0, raw) != null)
            {
                fTemperature2 = ConvertIlluminantToTemperature(GetTag <IFDDNGCalibrationIlluminant2>(ifd0, raw).Value);
            }
            else
            {
                fTemperature2 = 0.0;
            }

            fColorMatrix1 = GetTag <IFDDNGColorMatrix1>(ifd0, raw)?.Matrix;
            if (fColorMatrix1 == null)
            {
                fColorMatrix1 = DNGMatrix.Identity(fChannels); //best choice if nothing is given...
            }
            fColorMatrix2 = GetTag <IFDDNGColorMatrix2>(ifd0, raw)?.Matrix;
            if (fColorMatrix2 == null)
            {
                fColorMatrix2 = new DNGMatrix();
            }

            fForwardMatrix1 = GetTag <IFDDNGForwardMatrix1>(ifd0, raw)?.Matrix;
            if (fForwardMatrix1 == null)
            {
                fForwardMatrix1 = new DNGMatrix();
            }
            fForwardMatrix2 = GetTag <IFDDNGForwardMatrix2>(ifd0, raw)?.Matrix;
            if (fForwardMatrix2 == null)
            {
                fForwardMatrix2 = new DNGMatrix();
            }

            fReductionMatrix1 = GetTag <IFDDNGReductionMatrix1>(ifd0, raw)?.Matrix;
            if (fReductionMatrix1 == null)
            {
                fReductionMatrix1 = new DNGMatrix();
            }
            fReductionMatrix2 = GetTag <IFDDNGReductionMatrix2>(ifd0, raw)?.Matrix;
            if (fReductionMatrix2 == null)
            {
                fReductionMatrix2 = new DNGMatrix();
            }

            fCameraCalibration1 = GetTag <IFDDNGCameraCalibration1>(ifd0, raw)?.Matrix;
            fCameraCalibration2 = GetTag <IFDDNGCameraCalibration1>(ifd0, raw)?.Matrix;
            if (fCameraCalibration1 == null)
            {
                fCameraCalibration1 = DNGMatrix.Identity(fChannels);
            }
            if (fCameraCalibration2 == null)
            {
                fCameraCalibration2 = DNGMatrix.Identity(fChannels);
            }

            fAnalogBalance = GetTag <IFDDNGAnalogBalance>(ifd0, raw)?.Vector.AsDiagonal();
            if (fAnalogBalance == null)
            {
                fAnalogBalance = DNGMatrix.Identity(fChannels);
            }

            fForwardMatrix1 = NormalizeForwardMatrix(fForwardMatrix1);

            fColorMatrix1 = fAnalogBalance * fCameraCalibration1 * fColorMatrix1;

            if (fColorMatrix2.IsEmpty() ||
                fTemperature1 <= 0.0 ||
                fTemperature2 <= 0.0 ||
                fTemperature1 == fTemperature2)
            {
                fTemperature1 = 5000.0;
                fTemperature2 = 5000.0;

                fColorMatrix2       = fColorMatrix1;
                fForwardMatrix2     = fForwardMatrix1;
                fReductionMatrix2   = fReductionMatrix1;
                fCameraCalibration2 = fCameraCalibration1;
            }
            else
            {
                fForwardMatrix2 = NormalizeForwardMatrix(fForwardMatrix2);
                fColorMatrix2   = fAnalogBalance * fCameraCalibration2 * fColorMatrix2;

                // Swap values if temperatures are out of order.
                if (fTemperature1 > fTemperature2)
                {
                    double temp = fTemperature1;
                    fTemperature1 = fTemperature2;
                    fTemperature2 = temp;

                    DNGMatrix T = fColorMatrix1;
                    fColorMatrix1 = fColorMatrix2;
                    fColorMatrix2 = T;

                    T = fForwardMatrix1;
                    fForwardMatrix1 = fForwardMatrix2;
                    fForwardMatrix2 = T;

                    T = fReductionMatrix1;
                    fReductionMatrix1 = fReductionMatrix2;
                    fReductionMatrix2 = T;

                    T = fCameraCalibration1;
                    fCameraCalibration1 = fCameraCalibration2;
                    fCameraCalibration2 = T;
                }
            }

            IFDDNGAsShotNeutral neutral = GetTag <IFDDNGAsShotNeutral>(ifd0, raw);
            IFDDNGAsShotWhiteXY asShot  = GetTag <IFDDNGAsShotWhiteXY>(ifd0, raw);
            DNGxyCoord          white;

            if (asShot == null)
            {
                if (neutral == null)
                {
                    throw new ArgumentException("The DNG spec says that one of the As Shot White balance tags must be present.");
                }

                DNGVector vec = new DNGVector((uint)neutral.Value.Length);

                for (uint c = 0; c < neutral.Value.Length; c++)
                {
                    vec[c] = neutral.Value[c].Value;
                }

                double unify = 1.0 / vec.MaxEntry();
                vec = unify * vec;

                white = NeutralToXY(vec);
            }
            else
            {
                double x = asShot.Value[0].Value;
                double y = asShot.Value[1].Value;
                white = new DNGxyCoord(x, y);
            }
            WhiteXY = white;
        }
        public PEFFile(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);
            }

            //Raw Data:
            ImageFileDirectory raw  = ifds[0];
            IFDExif            exif = raw.GetEntry <IFDExif>();

            mISO      = exif.GetEntry <ExifEntry.ExifISOSpeedRatings>().Value;
            mBitDepth = raw.GetEntry <IFDBitsPerSample>().Value;
            ExifEntry.ExifMakerNote makernote = exif.GetEntry <ExifEntry.ExifMakerNote>();
            mBayerPattern = exif.GetEntry <ExifEntry.ExifCFAPattern>().Value;
            mBayerWidth   = exif.GetEntry <ExifEntry.ExifCFAPattern>().xCount;
            mBayerHeight  = exif.GetEntry <ExifEntry.ExifCFAPattern>().yCount;
            MNHuffmanTable huffmanTable = makernote.Value.GetEntry <MNHuffmanTable>();

            mWhiteLevel = makernote.Value.GetEntry <MNWhiteLevel>();
            mWhitePoint = makernote.Value.GetEntry <MNWhitePoint>();
            mBlackPoint = makernote.Value.GetEntry <MNBlackPoint>();
            mScaling    = makernote.Value.GetEntry <MNDataScaling>();

            mWidth  = (int)raw.GetEntry <IFDImageWidth>().Value;
            mHeight = (int)raw.GetEntry <IFDImageLength>().Value;
            uint offset = raw.GetEntry <IFDStripOffsets>().Value[0];

            Seek(offset, SeekOrigin.Begin);
            mRawImage    = new ushort[mHeight, mWidth];
            int[,] vpred = new int[2, 2];
            int[] hpred = new int[2];

            unsafe
            {
                fixed(ushort *huff = huffmanTable.Value)
                {
                    getbithuff(-1, null);

                    for (int row = 0; row < mHeight; row++)
                    {
                        for (int col = 0; col < mWidth; col++)
                        {
                            int diff = ljpeg_diff(huff);
                            if (col < 2)
                            {
                                hpred[col] = vpred[row & 1, col] += diff;
                            }
                            else
                            {
                                hpred[col & 1] += diff;
                            }
                            mRawImage[row, col] = (ushort)hpred[col & 1];
                        }
                    }
                }
            }
        }
        private ImageFileDirectory SetMembers()
        {
            //Raw Data:
            ImageFileDirectory raw  = mIfds[0];
            IFDExif            exif = raw.GetEntry <IFDExif>();

            mISO           = exif.GetEntry <ExifISOSpeedRatings>().Value;
            mExposureTime  = exif.GetEntry <ExifExposureTime>().Value;
            mRecordingDate = exif.GetEntry <ExifDateTimeDigitized>().Value;
            mBitDepth      = raw.GetEntry <IFDBitsPerSample>().Value[0];
            ExifMakerNote makernote = exif.GetEntry <ExifMakerNote>();

            //needed to decompress image data:
            mHhuffmanTable = makernote.Value.GetEntry <MNHuffmanTable>();
            ExifCFAPattern.BayerColor[] bayer = exif.GetEntry <ExifCFAPattern>().Value;
            mBayerPattern = new BayerColor[bayer.Length];
            for (int i = 0; i < bayer.Length; i++)
            {
                mBayerPattern[i] = (BayerColor)(int)bayer[i];
            }

            MNWhiteLevel  whiteLevel = makernote.Value.GetEntry <MNWhiteLevel>();
            MNWhitePoint  whitePoint = makernote.Value.GetEntry <MNWhitePoint>();
            MNBlackPoint  blackPoint = makernote.Value.GetEntry <MNBlackPoint>();
            MNDataScaling scaling    = makernote.Value.GetEntry <MNDataScaling>();

            float whiteLevelAll = (float)Math.Pow(2, mBitDepth);

            if (whiteLevel != null)
            {
                whiteLevelAll = whiteLevel.Value;
            }

            mBlackLevel = new float[3];
            if (blackPoint != null)
            {
                //only one value for all colors
                if (blackPoint.Value.Length == 1)
                {
                    mBlackLevel[0] = (float)blackPoint.Value[0];
                    mBlackLevel[1] = (float)blackPoint.Value[0];
                    mBlackLevel[2] = (float)blackPoint.Value[0];
                }

                //values per color channel
                if (blackPoint.Value.Length == 3)
                {
                    mBlackLevel[0] = (float)blackPoint.Value[0];
                    mBlackLevel[1] = (float)blackPoint.Value[1];
                    mBlackLevel[2] = (float)blackPoint.Value[2];
                }

                //values per color bayer pattern
                if (blackPoint.Value.Length == 4)
                {
                    //red
                    int indexR = -1;
                    for (int i = 0; i < mBayerPattern.Length; i++)
                    {
                        if (mBayerPattern[i] == BayerColor.Red)
                        {
                            indexR = i;
                            break;
                        }
                    }
                    mBlackLevel[0] = (float)blackPoint.Value[indexR];

                    //blue
                    int indexB = -1;
                    for (int i = 0; i < mBayerPattern.Length; i++)
                    {
                        if (mBayerPattern[i] == BayerColor.Blue)
                        {
                            indexB = i;
                            break;
                        }
                    }
                    mBlackLevel[2] = (float)blackPoint.Value[indexB];

                    //green, the two remaining indices
                    int indexG1 = -1, indexG2 = -1;
                    for (int i = 0; i < mBayerPattern.Length; i++)
                    {
                        if (mBayerPattern[i] == BayerColor.Green && indexG1 == -1)
                        {
                            indexG1 = i;
                        }
                        if (mBayerPattern[i] == BayerColor.Green && indexG1 != -1)
                        {
                            indexG2 = i;
                        }
                    }
                    float g1 = (float)blackPoint.Value[indexG1];
                    float g2 = (float)blackPoint.Value[indexG2];

                    mBlackLevel[1] = Math.Max(g1, g2); //well, one could distinguish the two greens, but what for?
                }
            }

            mWhiteLevel     = new float[] { whiteLevelAll, whiteLevelAll, whiteLevelAll };
            mWhiteLevel[0] -= mBlackLevel[0];
            mWhiteLevel[1] -= mBlackLevel[1];
            mWhiteLevel[2] -= mBlackLevel[2];
            float scale = scaling.Value;

            mWhiteBalance = new float[] { whitePoint.Value[0] / scale, whitePoint.Value[1] / scale, whitePoint.Value[3] / scale };

            if (makernote.Value.GetEntry <MNLevelInfo>() != null)
            {
                mRollAngle        = makernote.Value.GetEntry <MNLevelInfo>().Value.RollAngle;
                mRollAnglePresent = true;
            }

            mWidth  = (int)raw.GetEntry <IFDImageWidth>().Value;
            mHeight = (int)raw.GetEntry <IFDImageLength>().Value;


            //look for orientation tag.
            if (raw.GetEntry <IFDOrientation>() != null)
            {
                mOrientation = new DNGOrientation(raw.GetEntry <IFDOrientation>().Value);
            }
            else
            {
                //no tag found, use default
                mOrientation = new DNGOrientation(DNGOrientation.Orientation.Normal);
            }

            //we always crop at least two pixels because of our algos...
            mCropLeft = 2;
            mCropTop  = 2;

            mCroppedWidth  = mWidth - 4;
            mCroppedHeight = mHeight - 4;


            mMake            = raw.GetEntry <IFDMake>().Value;
            mUniqueModelName = raw.GetEntry <IFDModel>().Value;

            //missing data, like noise model, crop area, etc..., must be loaded afterwards!
            double[] colorMatrix = new double[] { 1, 0, 0, 0, 1, 0, 0, 0, 1 };
            mColorSpec = new DNGColorSpec(colorMatrix, colorMatrix, IFDDNGCalibrationIlluminant.Illuminant.D50, IFDDNGCalibrationIlluminant.Illuminant.D50, mWhiteBalance);
            return(raw);
        }
        public PEFFile(string aFileName, bool HeaderOnly)
            : 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);
            }

            //Raw Data:
            ImageFileDirectory raw  = ifds[0];
            IFDExif            exif = raw.GetEntry <IFDExif>();

            mISO      = exif.GetEntry <ExifEntry.ExifISOSpeedRatings>().Value;
            mBitDepth = raw.GetEntry <IFDBitsPerSample>().Value;
            ExifEntry.ExifMakerNote makernote = exif.GetEntry <ExifEntry.ExifMakerNote>();
            mBayerPattern = exif.GetEntry <ExifEntry.ExifCFAPattern>().Value;
            mBayerWidth   = exif.GetEntry <ExifEntry.ExifCFAPattern>().xCount;
            mBayerHeight  = exif.GetEntry <ExifEntry.ExifCFAPattern>().yCount;
            MNHuffmanTable huffmanTable = makernote.Value.GetEntry <MNHuffmanTable>();

            mWhiteLevel = makernote.Value.GetEntry <MNWhiteLevel>();
            mWhitePoint = makernote.Value.GetEntry <MNWhitePoint>();
            mBlackPoint = makernote.Value.GetEntry <MNBlackPoint>();
            mScaling    = makernote.Value.GetEntry <MNDataScaling>();

            mWidth  = (int)raw.GetEntry <IFDImageWidth>().Value;
            mHeight = (int)raw.GetEntry <IFDImageLength>().Value;
            uint offset = raw.GetEntry <IFDStripOffsets>().Value[0];
        }
Exemple #8
0
        public DNGFile(string aFileName, bool HeaderOnly)
            : 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);
            }


            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>();
            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];



            mAsShotNeutral = ifds[0].GetEntry <IFDDNGAsShotNeutral>();
        }
Exemple #9
0
        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;
                }
            }
        }
Exemple #10
0
        private ImageFileDirectory SetMembers()
        {
            ImageFileDirectory rawIFD = null;

            //find the IFD with the RAW Bayer image
            for (int i = 0; i < mIfds.Count; i++)
            {
                //well, it should actually be somewhere in IFD0...
                if (mIfds[i].GetEntry <IFDPhotometricInterpretation>() != null)
                {
                    if (mIfds[i].GetEntry <IFDPhotometricInterpretation>().Value ==
                        IFDPhotometricInterpretation.PhotometricInterpretation.CFA)
                    {
                        rawIFD = mIfds[i];
                        break;
                    }
                }
            }

            //no root IFD seems to contain RAW bayer, search for Sub-IFDs
            if (rawIFD == null)
            {
                //find the IFD with the RAW Bayer image
                for (int i = 0; i < mIfds.Count; i++)
                {
                    IFDSubIFDs subIFD = mIfds[i].GetEntry <IFDSubIFDs>();
                    if (subIFD == null)
                    {
                        continue;
                    }
                    for (int j = 0; j < subIFD.Value.Count; j++)
                    {
                        if (subIFD.Value[j].GetEntry <IFDPhotometricInterpretation>().Value ==
                            IFDPhotometricInterpretation.PhotometricInterpretation.CFA)
                        {
                            rawIFD = subIFD.Value[j];
                            break;
                        }
                    }
                }
            }

            if (rawIFD == null)
            {
                throw new ArgumentException("Can't find IFD with Bayer RAW image.");
            }

            mLinearizationTable = rawIFD.GetEntry <IFDDNGLinearizationTable>();
            mWidth  = (int)rawIFD.GetEntry <IFDImageWidth>().Value;
            mHeight = (int)rawIFD.GetEntry <IFDImageLength>().Value;
            if (mIfds[0].GetEntry <IFDDateTime>() != null)
            {
                mRecordingDate = mIfds[0].GetEntry <IFDDateTime>().Value;
            }

            //in case of Pentax this will have succes:
            IFDDNGPrivateData privateData = mIfds[0].GetEntry <IFDDNGPrivateData>();

            if (privateData != null)
            {
                MNLevelInfo levelInfo = privateData.PentaxMakerNotes.GetEntry <MNLevelInfo>();
                if (levelInfo != null)
                {
                    mRollAngle        = levelInfo.Value.RollAngle;
                    mRollAnglePresent = true;
                }
            }

            IFDExif exif = mIfds[0].GetEntry <IFDExif>();

            if (exif != null)
            {
                mISO           = exif.GetEntry <ExifISOSpeedRatings>().Value;
                mExposureTime  = exif.GetEntry <ExifExposureTime>().Value;
                mRecordingDate = (exif.GetEntry <ExifDateTimeDigitized>()?.Value).GetValueOrDefault(mRecordingDate);
            }
            else if (rawIFD.GetEntry <IFDISOSpeedRatings>() != null)
            {
                mISO = rawIFD.GetEntry <IFDISOSpeedRatings>().Value;
                //very likely that exposure time is also present
                mExposureTime = rawIFD.GetEntry <IFDExposureTime>().Value;
            }
            else if (mIfds[0].GetEntry <IFDISOSpeedRatings>() != null)
            {
                mISO = mIfds[0].GetEntry <IFDISOSpeedRatings>().Value;
                //very likely that exposure time is also present
                mExposureTime = mIfds[0].GetEntry <IFDExposureTime>().Value;
            }

            mBitDepth = rawIFD.GetEntry <IFDBitsPerSample>().Value[0];

            int bayerWidth  = rawIFD.GetEntry <IFDCFARepeatPatternDim>().Value[0];
            int bayerHeight = rawIFD.GetEntry <IFDCFARepeatPatternDim>().Value[1];

            if (bayerHeight != 2 || bayerWidth != 2)
            {
                throw new ArgumentException("This file has a bayer pattern size different than 2x2. Can't decode that.");
            }

            ExifCFAPattern.BayerColor[] bayer = rawIFD.GetEntry <IFDCFAPattern>().Value;
            mBayerPattern = new BayerColor[bayer.Length];
            for (int i = 0; i < bayer.Length; i++)
            {
                mBayerPattern[i] = (BayerColor)(int)bayer[i];
            }

            IFDDNGCFAPlaneColor planeColor = rawIFD.GetEntry <IFDDNGCFAPlaneColor>();

            int[] planeColorHelper = new int[] { 0, 1, 2 };
            if (planeColor != null) //did it ever differ from 0,1,2?
            {
                //0 = red, 1 = gree, 2 = blue.
                //The debayer algo creates images with plane order red/green/blue.
                //If this order differs, we need to re-order the planes in order to
                //have the color matrices correct.

                //reset colorTwist matrix:
                mColorTwist = new float[3, 4];
                if (planeColor.Value.Length > 3 || planeColor.Value.Length < 3)
                {
                    throw new ArgumentException("This image doesn't contain three color planes.");
                }

                for (int i = 0; i < planeColor.Value.Length; i++)
                {
                    int color = planeColor.Value[i];
                    planeColorHelper[i] = color;
                    if (color > 2)
                    {
                        throw new ArgumentException("This image contains colors different than red/green/blue.");
                    }
                    mColorTwist[color, i] = 1;

                    if (color != i)
                    {
                        mColorTwistIsIdentity = false;
                    }
                }
            }

            mColorSpec = new DNGColorSpec(3, mIfds[0], rawIFD);

            IFDDNGWhiteLevel whiteLevel = rawIFD.GetEntry <IFDDNGWhiteLevel>();
            IFDDNGBlackLevel blackLevel = rawIFD.GetEntry <IFDDNGBlackLevel>();

            mBlackLevel = new float[3];
            if (blackLevel != null)
            {
                //only one value for all colors
                if (blackLevel.Value.Length == 1)
                {
                    mBlackLevel[0] = (float)blackLevel.Value[0].Value;
                    mBlackLevel[1] = (float)blackLevel.Value[0].Value;
                    mBlackLevel[2] = (float)blackLevel.Value[0].Value;
                }

                //values per color channel
                if (blackLevel.Value.Length == 3)
                {
                    mBlackLevel[planeColorHelper[0]] = (float)blackLevel.Value[0].Value;
                    mBlackLevel[planeColorHelper[1]] = (float)blackLevel.Value[1].Value;
                    mBlackLevel[planeColorHelper[2]] = (float)blackLevel.Value[2].Value;
                }

                //values per color bayer pattern
                if (blackLevel.Value.Length == 4)
                {
                    //red
                    int indexR = -1;
                    for (int i = 0; i < mBayerPattern.Length; i++)
                    {
                        if (mBayerPattern[i] == BayerColor.Red)
                        {
                            indexR = i;
                            break;
                        }
                    }
                    mBlackLevel[0] = (float)blackLevel.Value[indexR].Value;

                    //blue
                    int indexB = -1;
                    for (int i = 0; i < mBayerPattern.Length; i++)
                    {
                        if (mBayerPattern[i] == BayerColor.Blue)
                        {
                            indexB = i;
                            break;
                        }
                    }
                    mBlackLevel[2] = (float)blackLevel.Value[indexB].Value;

                    //green, the two remaining indices
                    int indexG1 = -1, indexG2 = -1;
                    for (int i = 0; i < mBayerPattern.Length; i++)
                    {
                        if (mBayerPattern[i] == BayerColor.Green && indexG1 == -1)
                        {
                            indexG1 = i;
                        }
                        if (mBayerPattern[i] == BayerColor.Green && indexG1 != -1)
                        {
                            indexG2 = i;
                        }
                    }
                    float g1 = (float)blackLevel.Value[indexG1].Value;
                    float g2 = (float)blackLevel.Value[indexG2].Value;

                    mBlackLevel[1] = Math.Max(g1, g2); //well, one could distinguish the two greens, but what for?
                }
            }
            mWhiteLevel    = new float[3];
            mWhiteLevel[0] = (float)whiteLevel.Value[0];
            mWhiteLevel[1] = (float)whiteLevel.Value[0];
            mWhiteLevel[2] = (float)whiteLevel.Value[0];

            //subtract black level from white level
            mWhiteLevel[0] -= mBlackLevel[0];
            mWhiteLevel[1] -= mBlackLevel[1];
            mWhiteLevel[2] -= mBlackLevel[2];

            //get white balance from color spec
            DNGVector wb = mColorSpec.CameraWhite;

            mWhiteBalance = new float[3];
            mWhiteBalance[planeColorHelper[0]] = 1.0f / (float)wb[0];
            mWhiteBalance[planeColorHelper[1]] = 1.0f / (float)wb[1];
            mWhiteBalance[planeColorHelper[2]] = 1.0f / (float)wb[2];


            //look for orientation tag. If RAW ifd has the tag, choose that one
            if (rawIFD.GetEntry <IFDOrientation>() != null)
            {
                mOrientation = new DNGOrientation(rawIFD.GetEntry <IFDOrientation>().Value);
            }
            else if (mIfds[0].GetEntry <IFDOrientation>() != null)
            {
                mOrientation = new DNGOrientation(mIfds[0].GetEntry <IFDOrientation>().Value);
            }
            else
            {
                //no tag found, use default
                mOrientation = new DNGOrientation(DNGOrientation.Orientation.Normal);
            }

            //default Values:
            int cropLeft      = 0;
            int cropTop       = 0;
            int croppedWidth  = mWidth;
            int croppedHeight = mHeight;

            IFDDNGActiveArea activeArea = rawIFD.GetEntry <IFDDNGActiveArea>();

            //if active area is defined:
            if (activeArea != null)
            {
                int top, left, bottom, right;
                top    = (int)activeArea.Value[0];
                left   = (int)activeArea.Value[1];
                bottom = (int)activeArea.Value[2];
                right  = (int)activeArea.Value[3];

                cropLeft     += left;
                cropTop      += top;
                croppedWidth  = right - left;
                croppedHeight = bottom - top;

                //CFA pattern is defined on active area. If top/left is uneven we need to shift the CFA pattern accordingly
                if (top % 2 != 0)
                {
                    BayerColor bayer0 = BayerPattern[0];
                    BayerColor bayer1 = BayerPattern[1];
                    BayerPattern[0] = BayerPattern[2];
                    BayerPattern[1] = BayerPattern[3];
                    BayerPattern[2] = bayer0;
                    BayerPattern[3] = bayer1;
                }

                if (left % 2 != 0)
                {
                    BayerColor bayer0 = BayerPattern[0];
                    BayerColor bayer2 = BayerPattern[2];
                    BayerPattern[0] = BayerPattern[1];
                    BayerPattern[2] = BayerPattern[3];
                    BayerPattern[1] = bayer0;
                    BayerPattern[3] = bayer2;
                }
            }

            IFDDNGDefaultCropOrigin cropOrigin = rawIFD.GetEntry <IFDDNGDefaultCropOrigin>();
            IFDDNGDefaultCropSize   cropSize   = rawIFD.GetEntry <IFDDNGDefaultCropSize>();

            if (cropOrigin != null && cropSize != null)
            {
                int top, left, width, height;
                left   = (int)(cropOrigin.Value[0].Value);
                top    = (int)(cropOrigin.Value[0].Value);
                width  = (int)(cropSize.Value[0].Value);
                height = (int)(cropSize.Value[0].Value);

                cropLeft += left;
                cropTop  += top;

                croppedWidth  = width;
                croppedHeight = height;
            }

            //we always crop at least two pixels because of our algos...
            mCropLeft = Math.Max(2, cropLeft);
            mCropTop  = Math.Max(2, cropTop);

            mCroppedWidth  = croppedWidth - Math.Max(0, (cropLeft + croppedWidth) - (mWidth - 2));
            mCroppedHeight = croppedHeight - Math.Max(0, (cropTop + croppedHeight) - (mHeight - 2));

            IFDDNGNoiseProfile noise = rawIFD.GetEntry <IFDDNGNoiseProfile>();

            if (noise == null)
            {
                noise = mIfds[0].GetEntry <IFDDNGNoiseProfile>();
            }
            if (noise != null)
            {
                //if noise level is given for all channels,
                //take the green one as it is usually scalled to one
                if (noise.Value.Length > 2)
                {
                    mNoiseModelAlpha = (float)noise.Value[planeColorHelper[1] * 2];
                    mNoiseModelBeta  = (float)noise.Value[planeColorHelper[1] * 2 + 1];
                }
                else
                {
                    mNoiseModelAlpha = (float)noise.Value[0];
                    mNoiseModelBeta  = (float)noise.Value[1];
                }
            }

            mMake            = mIfds[0].GetEntry <IFDMake>().Value;
            mUniqueModelName = mIfds[0].GetEntry <IFDDNGUniqueCameraModel>().Value;

            return(rawIFD);
        }
Exemple #11
0
        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;
        }