Beispiel #1
0
        private static void testAdobeJPG()
        {
            JpegDecoder jpegLibraryDecoder = new JpegDecoder();

            byte[] rawTileBuffer = File.ReadAllBytes("sof3.jpg");


            int tileWidth  = 256;
            int tileHeight = 240;

            byte[] tileBuff = new byte[tileWidth * tileHeight * 2];


            ReadOnlyMemory <byte> rawTileReadOnlyMemory;

            rawTileReadOnlyMemory = new ReadOnlyMemory <byte>(rawTileBuffer);
            jpegLibraryDecoder.SetInput(rawTileReadOnlyMemory);
            //jpegLibraryDecoder.SetFrameHeader()
            jpegLibraryDecoder.Identify(); // fails to identify. missing markers or whatever: Failed to decode JPEG data at offset 91149. No marker found.'
            jpegLibraryDecoder.SetOutputWriter(new JpegDecode.JpegBufferOutputWriterGreaterThan8Bit(tileWidth / 2, tileHeight, jpegLibraryDecoder.Precision, 2, tileBuff, 16));
            jpegLibraryDecoder.Decode();


            File.WriteAllBytes("sof3-decodetest.raw", tileBuff);
        }
Beispiel #2
0
        public void JpegEncoderDecoderTest()
        {
            // Encode and decode a basic raster structure.
            var colorModel = new ColorModel();

            colorModel.ColorSpace = ColorSpace.YCbCr;
            colorModel.Opaque     = true;
            byte[][][] originalRaster = GetRaster();
            var        image          = new Image(colorModel, originalRaster);
            var        stream         = new MemoryStream();
            var        encoder        = new JpegEncoder(image, 50, stream);

            encoder.Encode();
            stream.Seek(0, SeekOrigin.Begin);
            var         decoder      = new JpegDecoder(stream);
            DecodedJpeg decodedImage = decoder.Decode();

            // Check that the returned raster structure looks something like what we passed in.
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    for (int k = 0; k < height; k++)
                    {
                        // Tune this.
                        int diff = Math.Abs(decodedImage.Image.Raster[i][j][k] - originalRaster[i][j][k]);
                        Assert.IsTrue(diff < 5);
                    }
                }
            }
            ClientLogger.Debug("Finished JpegEncoderDecoder test.");
        }
        public void TestJpegLibrary()
        {
            var decoder = new JpegDecoder();

            decoder.SetInput(_inputBytes);
            decoder.Identify();
            int width  = decoder.Width;
            int height = decoder.Height;

            Rgba32[] rgba  = new Rgba32[width * height];
            byte[]   ycbcr = ArrayPool <byte> .Shared.Rent(3 *rgba.Length);

            try
            {
                var outputWriter = new JpegBufferOutputWriter(decoder.Width, decoder.Height, 3, ycbcr);
                decoder.SetOutputWriter(outputWriter);
                decoder.Decode();

                JpegYCbCrToRgbConverter.Shared.ConvertYCbCr8ToRgba32(ycbcr, MemoryMarshal.AsBytes(rgba.AsSpan()), decoder.Width * decoder.Height);
            }
            finally
            {
                ArrayPool <byte> .Shared.Return(ycbcr);
            }
        }
Beispiel #4
0
        public static byte[] DecodeJpeg(Stream sourceStream)
        {
            // Decode JPEG from stream
            var decoder     = new JpegDecoder(sourceStream);
            var jpegDecoded = decoder.Decode();
            var img         = jpegDecoded.Image;

            img.ChangeColorSpace(ColorSpace.Rgb);

            // Init Buffer
            int w      = img.Width;
            int h      = img.Height;
            var result = new byte[w * h * 4];

            byte[][][] pixelsFromJpeg = img.Raster;

            // Copy FluxJpeg buffer into WriteableBitmap
            int i = 0;

            for (int y = 0; y < h; y++)
            {
                for (int x = 0; x < w; x++)
                {
                    result[i++] = pixelsFromJpeg[2][x][y];                     // B
                    result[i++] = pixelsFromJpeg[1][x][y];                     // G
                    result[i++] = pixelsFromJpeg[0][x][y];                     // R
                    result[i++] = 0xFF;
                }
            }

            return(result);
        }
Beispiel #5
0
        static Image Resize(string pathIn, int edge)
        {
            JpegDecoder  decoder = new JpegDecoder(File.Open(pathIn, FileMode.Open));
            DecodedJpeg  jpeg    = decoder.Decode();
            ImageResizer resizer = new ImageResizer(jpeg.Image);

            return(resizer.ResizeToScale(edge, ResamplingFilters.LowpassAntiAlias));
        }
Beispiel #6
0
        public static Image FromFile(string filename)
        {
            //TODO: review here
            //should not depend on the extension
            string fileext = IO.Path.GetExtension(filename).ToLower();

            switch (fileext)
            {
            default:
                throw new NotSupportedException();

            case ".jpg":
            {
                JpegDecoder jpegDec = new JpegDecoder();
                ImageTools.ExtendedImage outputImg = new ImageTools.ExtendedImage();
                using (System.IO.FileStream fs = new IO.FileStream(filename, IO.FileMode.Open))
                {
                    jpegDec.Decode(outputImg, fs);
                }
                //return bitmap
                return(new Bitmap(outputImg.PixelWidth, outputImg.PixelHeight, outputImg.Pixels,
                                  outputImg.DensityXInt32, outputImg.DensityYInt32));
            }

            case ".gif":
            {
                GifDecoder gifDec = new GifDecoder();
                ImageTools.ExtendedImage outputImg = new ImageTools.ExtendedImage();
                using (System.IO.FileStream fs = new IO.FileStream(filename, IO.FileMode.Open))
                {
                    gifDec.Decode(outputImg, fs);
                }
                //return bitmap
                return(new Bitmap(outputImg.PixelWidth, outputImg.PixelHeight, outputImg.Pixels,
                                  outputImg.DensityXInt32, outputImg.DensityYInt32));
            }

            case ".png":
            {
                ImageTools.IO.Png.PngDecoder pngDecoder = new PngDecoder();
                //HjgPngDecoder pngDecoder = new HjgPngDecoder();
                //PngDecoder pngDecoder = new PngDecoder();
                ImageTools.ExtendedImage outputImg = new ImageTools.ExtendedImage();
                using (System.IO.FileStream fs = new IO.FileStream(filename, IO.FileMode.Open))
                {
                    pngDecoder.Decode(outputImg, fs);
                }

                Bitmap bmp = new Bitmap(outputImg.PixelWidth,
                                        outputImg.PixelHeight, outputImg.Pixels,
                                        outputImg.DensityXInt32, outputImg.DensityYInt32);
                bmp.PixelFormat = Imaging.PixelFormat.Format32bppArgb;
                return(bmp);
            }
            }
            return(null);
        }
Beispiel #7
0
        private static MemoryStream JpegDecode(MemoryStream jpegData)
        {
            var         byteStream = new MemoryStream();
            JpegDecoder d          = new JpegDecoder();
            var         img        = d.Decode(new Configuration(new JpegConfigurationModule()), jpegData);

            img.SaveAsBmp(byteStream, new SixLabors.ImageSharp.Formats.Bmp.BmpEncoder());
            //using SixLabors.ImageSharp.Image image = SixLabors.ImageSharp.Image.Load(jpegData, new JpegDecoder());
            // image.SaveAsBmp(byteStream);
            return(byteStream);
        }
        public void Decode_VerifyQuality(string imagePath, int quality)
        {
            var testFile = TestFile.Create(imagePath);

            using (var stream = new MemoryStream(testFile.Bytes, false))
            {
                using (Image image = JpegDecoder.Decode(Configuration.Default, stream))
                {
                    JpegMetadata meta = image.Metadata.GetJpegMetadata();
                    Assert.Equal(quality, meta.Quality);
                }
            }
        }
        public static Task <int> DebugDump(FileInfo source, string output, CancellationToken cancellationToken)
        {
            if (source is null || source.Length == 0)
            {
                Console.WriteLine("Input file are not specified.");
                return(Task.FromResult(1));
            }
            if (string.IsNullOrEmpty(output))
            {
                output = source.FullName;
            }

            byte[] input = File.ReadAllBytes(source.FullName);

            var decoder = new JpegDecoder();

            decoder.SetInput(input);
            decoder.Identify();

            int numberOfComponents = decoder.NumberOfComponents;

            if (numberOfComponents > 4)
            {
                throw new NotSupportedException("Number of components greater than 4 is not supported.");
            }

            ushort[] buffer       = new ushort[decoder.Width * decoder.Height * 4];
            var      outputWriter = new JpegExtendingOutputWriter(decoder.Width, decoder.Height, 4, decoder.Precision, buffer);

            decoder.SetOutputWriter(outputWriter);
            decoder.Decode();

            // We use RGBA PNG image to store 4 components.
            // Its content may be Grayscale, YCbCr or others.
            Rgba32[] pixels = new Rgba32[decoder.Width * decoder.Height];
            Array.Fill(pixels, new Rgba32(255, 255, 255, 255));
            using var image = Image.WrapMemory(pixels.AsMemory(), decoder.Width, decoder.Height);

            // high bits
            CopyHighBits(buffer, pixels, numberOfComponents);
            image.Save(output + ".high.png");

            // apply prediction
            ApplyPrediction(buffer);

            // low bits
            CopyLowBits(buffer, pixels, numberOfComponents);
            image.Save(output + ".low-diff.png");

            return(Task.FromResult(0));
        }
        public void Decode_VerifyQuality(string imagePath, int quality)
        {
            var testFile = TestFile.Create(imagePath);

            using (var stream = new MemoryStream(testFile.Bytes, false))
            {
                var decoder = new JpegDecoder();
                using (Image <Rgba32> image = decoder.Decode <Rgba32>(Configuration.Default, stream))
                {
                    JpegMetaData meta = image.MetaData.GetFormatMetaData(JpegFormat.Instance);
                    Assert.Equal(quality, meta.Quality);
                }
            }
        }
        public void Decode_VerifyRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit)
        {
            var testFile = TestFile.Create(imagePath);

            using (var stream = new MemoryStream(testFile.Bytes, false))
            {
                var decoder = new JpegDecoder();
                using (Image <Rgba32> image = decoder.Decode <Rgba32>(Configuration.Default, stream))
                {
                    ImageMetadata meta = image.Metadata;
                    Assert.Equal(xResolution, meta.HorizontalResolution);
                    Assert.Equal(yResolution, meta.VerticalResolution);
                    Assert.Equal(resolutionUnit, meta.ResolutionUnits);
                }
            }
        }
        public void TestDecode(string path)
        {
            byte[] jpegBytes = File.ReadAllBytes(path);

            var decoder = new JpegDecoder();

            decoder.SetInput(jpegBytes);
            decoder.Identify();

            ushort[] buffer       = new ushort[decoder.Width * decoder.Height * 4];
            var      outputWriter = new JpegExtendingOutputWriter(decoder.Width, decoder.Height, 4, decoder.Precision, buffer);

            decoder.SetOutputWriter(outputWriter);
            decoder.Decode();

            ushort[] reference = ImageHelper.LoadBuffer(path, decoder.Width, decoder.Height, decoder.NumberOfComponents);

            Assert.True(reference.AsSpan().SequenceEqual(buffer));
        }
Beispiel #13
0
        private static void testAdobeJPGEncode()
        {
            int tileWidth  = 256;
            int tileHeight = 240;


            byte[]   rawReferenceData       = File.ReadAllBytes("rawToEncode-DNG.raw");
            UInt16[] rawReferenceDataUInt16 = new UInt16[rawReferenceData.Length / 2];
            for (int i = 0; i < rawReferenceDataUInt16.Length; i++)
            {
                rawReferenceDataUInt16[i] = BitConverter.ToUInt16(rawReferenceData, i * 2);
            }

            dng_stream whatever = new dng_stream();

            DNGLosslessEncoder.EncodeLosslessJPEG(rawReferenceDataUInt16, (uint)tileHeight, (uint)tileWidth / 2, 2, 16, tileWidth, 2, whatever);

            File.WriteAllBytes("encodedTest.jpg", whatever.toByteArray());


            // Try decode again
            JpegDecoder jpegLibraryDecoder = new JpegDecoder();

            byte[] rawTileBuffer = File.ReadAllBytes("encodedTest.jpg");



            byte[] tileBuff = new byte[tileWidth * tileHeight * 2];


            ReadOnlyMemory <byte> rawTileReadOnlyMemory;

            rawTileReadOnlyMemory = new ReadOnlyMemory <byte>(rawTileBuffer);
            jpegLibraryDecoder.SetInput(rawTileReadOnlyMemory);
            //jpegLibraryDecoder.SetFrameHeader()
            jpegLibraryDecoder.Identify(); // fails to identify. missing markers or whatever: Failed to decode JPEG data at offset 91149. No marker found.'
            jpegLibraryDecoder.SetOutputWriter(new JpegDecode.JpegBufferOutputWriterGreaterThan8Bit(tileWidth / 2, tileHeight, jpegLibraryDecoder.Precision, 2, tileBuff, 16));
            jpegLibraryDecoder.Decode();


            File.WriteAllBytes("sof3-encodedecodetest.raw", tileBuff);
        }
        public void Setup()
        {
            var ms = new MemoryStream();

            using (Stream resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("JpegLibrary.Benchmarks.Resources.HETissueSlide.jpg"))
            {
                resourceStream.CopyTo(ms);
            }
            ms.Seek(0, SeekOrigin.Begin);

            // Load the image and expand it
            using var baseImage = Image.Load(ms);
            using var image     = new Image <Rgba32>(baseImage.Width * 4, baseImage.Height * 4);
            image.Mutate(ctx =>
            {
                ctx.DrawImage(baseImage, new Point(0, 0), opacity: 1);
                ctx.DrawImage(baseImage, new Point(0, baseImage.Height), opacity: 1);
                ctx.DrawImage(baseImage, new Point(baseImage.Width, 0), opacity: 1);
                ctx.DrawImage(baseImage, new Point(baseImage.Width, baseImage.Height), opacity: 1);
            });
            ms.Seek(0, SeekOrigin.Begin);
            ms.SetLength(0);
            image.SaveAsJpeg(ms);

            byte[] inputBytes = ms.ToArray();

            var decoder = new JpegDecoder();

            decoder.SetInput(inputBytes);
            decoder.Identify();
            _width  = decoder.Width;
            _height = decoder.Height;
            byte[] ycbcr = new byte[3 * _width * _height];
            decoder.SetOutputWriter(new JpegBufferOutputWriter(_width, _height, 3, ycbcr));
            decoder.Decode();

            _rgba = new Rgba32[_width * _height];
            JpegYCbCrToRgbConverter.Shared.ConvertYCbCr8ToRgba32(ycbcr, MemoryMarshal.AsBytes(_rgba.AsSpan()), _width * _height);
        }
Beispiel #15
0
        override public byte[] getRawImageData(int index)
        {
            using (Tiff input = Tiff.Open(paths[index], "r"))
            {
                // Try to make Adobe DNG work
                bool subIFDTagExists = input.GetField(TIFFTAG_SUBIFDS) != null;
                if (subIFDTagExists)
                {
                    UInt64 offsetOfSubIFD = (UInt64)input.GetField(TIFFTAG_SUBIFDS)[1].TolongArray()[0];
                    input.SetSubDirectory((long)offsetOfSubIFD);
                }

                if (input.IsTiled())
                {
                    if (compressedFileCacheIndex == index)
                    {
                        return((byte[])compressedFileCache.Clone());
                    }

                    int    tileWidth     = input.GetField(TiffTag.TILEWIDTH)[0].ToInt();
                    int    tileHeight    = input.GetField(TiffTag.TILELENGTH)[0].ToInt();
                    byte[] buffer        = new byte[width * height * 2];
                    long   tileSize      = input.TileSize();
                    byte[] tileBuff      = new byte[tileSize];
                    byte[] tileBuffMessy = new byte[tileSize];

                    JpegDecoder jpegLibraryDecoder = new JpegDecoder();

                    long   rawTileSize;
                    byte[] rawTileBuffer;
                    int    tileIndex;
                    ReadOnlyMemory <byte> rawTileReadOnlyMemory;

                    int row, col, x, y;

                    bool isSOF3Stuff = false;

                    for (row = 0; row < height; row += tileHeight)
                    {
                        for (col = 0; col < width; col += tileWidth)
                        {
                            // Read the tile
                            if (isSOF3Stuff || input.ReadTile(tileBuff, 0, col, row, 0, 0) < 0)
                            {
                                isSOF3Stuff = true;
                                // This means the normal tile reading failed, so we try something else.
                                tileIndex     = input.ComputeTile(col, row, 0, 0);
                                rawTileSize   = input.RawTileSize(tileIndex);
                                rawTileBuffer = new byte[rawTileSize];
                                input.ReadRawTile(tileIndex, rawTileBuffer, 0, (int)rawTileSize);
                                //File.WriteAllBytes("col"+col+"_row"+row+"_sof3.jpg",rawTileBuffer);
                                rawTileReadOnlyMemory = new ReadOnlyMemory <byte>(rawTileBuffer);
                                jpegLibraryDecoder.SetInput(rawTileReadOnlyMemory);
                                //jpegLibraryDecoder.SetFrameHeader()
                                jpegLibraryDecoder.Identify(); // fails to identify. missing markers or whatever: Failed to decode JPEG data at offset 91149. No marker found.'

                                // Hyper messy. Need to give him the wrong width bc reasons... (he thinks its 2 components and only half the width. Whatever I guess)
                                jpegLibraryDecoder.SetOutputWriter(new JpegDecode.JpegBufferOutputWriterGreaterThan8Bit(tileWidth / 2, tileHeight, jpegLibraryDecoder.Precision, 2, tileBuff, 16));
                                jpegLibraryDecoder.Decode();
                                //throw new Exception("Error reading data");

                                /*
                                 * // Translate jpegLibrary-ish to normal bayer stuff (whatever that f*****g means)
                                 * for(int yTile = 0; yTile < tileHeight; yTile++)
                                 * {
                                 *  for (int xTile = 0; xTile < tileWidth; xTile++)
                                 *  {
                                 *      tileBuff[yTile * tileWidth *2 + xTile * 2] = tileBuffMessy[yTile * tileWidth *2 + xTile * 2];
                                 *      tileBuff[yTile * tileWidth *2 + xTile * 2+1] = tileBuffMessy[yTile * tileWidth *2 + xTile * 2+1];
                                 *  }
                                 * }*/
                            }

                            int indexTileStuff = 0;

                            // Iterate the rows in the tile
                            for (y = row; y < row + tileHeight; y++)
                            {
                                if (y >= height)
                                {
                                    break;
                                }
                                for (x = col; x < col + tileWidth; x++)
                                {
                                    if (x >= width)
                                    {
                                        continue;
                                    }

                                    buffer[y * width * 2 + x * 2]     = tileBuff[(y - row) * tileWidth * 2 + (x - col) * 2];
                                    buffer[y * width * 2 + x * 2 + 1] = tileBuff[(y - row) * tileWidth * 2 + (x - col) * 2 + 1];
                                }
                            }

                            /*for (var i = 0; i < tileHeight && i + row < height; i++)
                             * {
                             *  var length = tileWidth;
                             *
                             *  // Index of the first position in the row
                             *  var position = (row + i) * tileWidth + col;
                             *
                             *  // Check we are not outside the image
                             *  if (col + length > width)
                             *  {
                             *      length = width - col;
                             *  }
                             *  for (var p = 0; p < length; p++)
                             *  {
                             *      buffer[position + p] = buffer[indexTileStuff * 2 + p * 2];
                             *  }
                             *
                             *
                             *  index += tileWidth;
                             *
                             * }*/
                        }
                    }

                    compressedFileCache      = (byte[])buffer.Clone();
                    compressedFileCacheIndex = index;

                    return(buffer);
                }
                else
                {
                    byte[] buffer       = new byte[input.StripSize() * input.NumberOfStrips()];
                    int    bufferoffset = 0;
                    int    stripsize    = input.StripSize();
                    int    stripcount   = input.NumberOfStrips();
                    for (int i = 0; i < stripcount; i++)
                    {
                        int read = input.ReadEncodedStrip(i, buffer, bufferoffset, stripsize); // This throws an error with Adobe-created DNG files
                        if (read == -1)
                        {
                            throw new Exception("Error on decoding strip " + i + " of " + input.FileName());
                        }

                        bufferoffset += read;
                    }
                    return(buffer);
                }
            }
        }
Beispiel #16
0
        public void Decode(DcmDataset dataset, DcmPixelData oldPixelData, DcmPixelData newPixelData, DcmCodecParameters parameters)
        {
            if (oldPixelData.NumberOfFrames == 0)
            {
                return;
            }

            // Determine JPEG image precision and assert that the implemented codec supports this precision
            int precision;

            try
            {
                precision = JpegHelper.ScanHeaderForBitDepth(oldPixelData);
            }
            catch (DicomCodecException)
            {
                precision = oldPixelData.BitsStored;
            }
            AssertImagePrecision(precision);

            // Ensure consistency in the new pixel data header
            if (precision > 8)
            {
                newPixelData.BitsAllocated = 16;
            }
            else if (newPixelData.BitsStored <= 8)
            {
                newPixelData.BitsAllocated = 8;
            }

            // Set up new pixel data specifics
            newPixelData.PhotometricInterpretation = newPixelData.PhotometricInterpretation.Equals("YBR_FULL_422") ||
                                                     newPixelData.PhotometricInterpretation.Equals("YBR_PARTIAL_422")
                                                         ? "YBR_FULL"
                                                         : oldPixelData.PhotometricInterpretation;
            if (newPixelData.PhotometricInterpretation.Equals("YBR_FULL"))
            {
                newPixelData.PlanarConfiguration = 1;
            }

            try
            {
                for (int j = 0; j < oldPixelData.NumberOfFrames; ++j)
                {
                    var frameData  = new byte[newPixelData.UncompressedFrameSize];
                    var jpegStream = new MemoryStream(oldPixelData.GetFrameDataU8(j));

                    // Decode JPEG from stream
                    var decoder     = new JpegDecoder(jpegStream);
                    var jpegDecoded = decoder.Decode();
                    var img         = jpegDecoded.Image;

                    // Init Buffer
                    int w = img.Width;
                    int h = img.Height;
                    var pixelsFromJpeg = img.Raster;

                    // Copy FluxJpeg buffer into frame data array

/*
 *                  int comps = pixelsFromJpeg.GetLength(0);
 *                  int preIncr = newPixelData.BytesAllocated - comps;
 *
 *                  if (preIncr < 0)
 *                      throw new InvalidOperationException(
 *                          String.Format("Number of JPEG components: {0} exceeds number of bytes allocated: {1}",
 *                                        comps, newPixelData.BytesAllocated));
 */
                    int i = 0;
                    for (int y = 0; y < h; ++y)
                    {
                        for (int x = 0; x < w; ++x)
                        {
                            var pixel = pixelsFromJpeg[0][x, y];
                            frameData[i++] = (byte)((pixel >> 8) & 0xff);
                            frameData[i++] = (byte)(pixel & 0xff);
//                            for (int k = 0; k < preIncr; ++k) frameData[i++] = 0xff;
//                            for (int k = 0; k < comps; ++k) frameData[i++] = pixelsFromJpeg[k][x, y];
                        }
                    }

                    oldPixelData.Unload();

                    if (newPixelData.IsPlanar)
                    {
                        DcmCodecHelper.ChangePlanarConfiguration(frameData,
                                                                 frameData.Length / newPixelData.BytesAllocated,
                                                                 newPixelData.BitsAllocated,
                                                                 newPixelData.SamplesPerPixel, 0);
                    }
                    newPixelData.AddFrame(frameData);
                }
            }
            catch (Exception e)
            {
                Debug.Log.Error("Failed to decode JPEG image: {0}, reason: {1}", e.StackTrace, e.Message);
            }
        }
        override public byte[] getRawImageData(int index)
        {
            Dictionary <UInt32, byte[]> tagData = readCRITagData(paths[0]);

            if (tagData.ContainsKey((UInt32)Key.FrameData))
            {
                // Detect compression
                // Only horizontal tiles are supported so far. Assuming there is no vertical tiling.
                if (tagData.ContainsKey((UInt32)Key.TileSizes))
                {
                    byte[] decodedOutputBuffer = new byte[width * height * 2];

                    byte[] tileSizeData = tagData[(UInt32)Key.TileSizes];
                    int    tileCount    = tileSizeData.Length / 8; // The tilesizes are saved as Uint64s I think, so dividing by 8 should give the right number.

                    UInt64   totalSizeFromTileSizes = 0;
                    UInt64[] tileSizes = new UInt64[tileCount];
                    for (int i = 0; i < tileCount; i++)
                    {
                        tileSizes[i]            = BitConverter.ToUInt64(tileSizeData, i * 8);
                        totalSizeFromTileSizes += tileSizes[i];
                    }

                    byte[] compressedData = tagData[(UInt32)Key.FrameData];


                    JpegDecoder           jpegLibraryDecoder = new JpegDecoder();
                    ReadOnlyMemory <byte> rawTileReadOnlyMemory;

                    byte[] tmpBuffer;
                    UInt64 alreadyRead = 0;
                    UInt32 horizOffset = 0;
                    foreach (UInt64 tileSize in tileSizes)
                    {
                        tmpBuffer = new byte[tileSize];

                        Array.Copy(compressedData, (int)alreadyRead, tmpBuffer, 0, (int)tileSize);
                        alreadyRead += tileSize;

                        rawTileReadOnlyMemory = new ReadOnlyMemory <byte>(tmpBuffer);
                        jpegLibraryDecoder.SetInput(rawTileReadOnlyMemory);
                        //jpegLibraryDecoder.SetFrameHeader()
                        jpegLibraryDecoder.Identify(); // fails to identify. missing markers or whatever: Failed to decode JPEG data at offset 91149. No marker found.'

                        int    tileActualWidth  = jpegLibraryDecoder.Width / 2;
                        int    tileActualHeight = jpegLibraryDecoder.Height * 2;
                        byte[] tileBuff         = new byte[jpegLibraryDecoder.Width * jpegLibraryDecoder.Height * 2];
                        jpegLibraryDecoder.SetOutputWriter(new JpegDecode.JpegBufferOutputWriterGreaterThan8BitCRI(jpegLibraryDecoder.Width, jpegLibraryDecoder.Height, jpegLibraryDecoder.Precision - 1, 1, tileBuff, 16));
                        jpegLibraryDecoder.Decode();

                        int actualX;
                        for (int y = 0; y < tileActualHeight; y++)
                        {
                            for (int x = 0; x < tileActualWidth; x++)
                            {
                                actualX = (Int32)horizOffset + x;
                                decodedOutputBuffer[y * width * 2 + actualX * 2]     = tileBuff[y * tileActualWidth * 2 + (x) * 2];
                                decodedOutputBuffer[y * width * 2 + actualX * 2 + 1] = tileBuff[y * tileActualWidth * 2 + (x) * 2 + 1];
                            }
                        }

                        horizOffset += (uint)tileActualWidth;
                    }
                    File.WriteAllBytes("decoded raw cri" + width + " " + height + ".raw", decodedOutputBuffer);
                    return(decodedOutputBuffer);
                }
                else
                {
                    // Presuming uncompressed
                    return(tagData[(UInt32)Key.FrameData]);
                }

                //File.WriteAllBytes("rawcri.jpg", tagData[(UInt32)Key.FrameData]);
            }
            else
            {
                throw new Exception("CRI file contains no image data apparently.");
            }
        }
        public static Task <int> Decode(FileInfo source, string output)
        {
            using var writer = new MemoryPoolBufferWriter();

            using (FileStream stream = source.OpenRead())
            {
                ReadAllBytes(stream, writer);
            }

            var decoder = new JpegDecoder();

            decoder.SetInput(writer.GetReadOnlySequence());
            decoder.Identify();

            if (decoder.NumberOfComponents != 1 && decoder.NumberOfComponents != 3)
            {
                // We only support Grayscale and YCbCr.
                throw new NotSupportedException("This color space is not supported");
            }

            int width  = decoder.Width;
            int height = decoder.Height;

            byte[] ycbcr = new byte[width * height * 3];

            if (decoder.Precision == 8)
            {
                // This is the most common case for JPEG.
                // We use the fatest implement.
                decoder.SetOutputWriter(new JpegBufferOutputWriter8Bit(width, height, 3, ycbcr));
            }
            else if (decoder.Precision < 8)
            {
                decoder.SetOutputWriter(new JpegBufferOutputWriterLessThan8Bit(width, height, decoder.Precision, 3, ycbcr));
            }
            else
            {
                decoder.SetOutputWriter(new JpegBufferOutputWriterGreaterThan8Bit(width, height, decoder.Precision, 3, ycbcr));
            }

            decoder.Decode();

            if (decoder.NumberOfComponents == 1)
            {
                // For grayscale image, we need to fill Cb and Cr in the YCbCr buffer.
                for (int i = 0; i < ycbcr.Length; i += 3)
                {
                    ycbcr[i + 1] = 128;
                    ycbcr[i + 2] = 128;
                }
            }

            using var image = new Image <Rgb24>(width, height);

            // Convert YCbCr to RGB
            for (int i = 0; i < height; i++)
            {
                JpegYCbCrToRgbConverter.Shared.ConvertYCbCr8ToRgb24(ycbcr.AsSpan(i * width * 3, width * 3), MemoryMarshal.AsBytes(image.GetPixelRowSpan(i)), width);
            }

            image.Save(output);

            return(Task.FromResult(0));
        }
        public async ValueTask InvokeAsync(TiffImageDecoderContext context, ITiffImageDecoderPipelineNode next)
        {
            MemoryPool <byte>     memoryPool    = context.MemoryPool ?? MemoryPool <byte> .Shared;
            TiffFileContentReader contentReader = context.ContentReader ?? throw new InvalidOperationException();

            IMemoryOwner <byte>?dataHandle = null;
            Memory <byte>       data;

            try
            {
                const int BufferSize = 65536;
                using (var bufferWriter = new MemoryPoolBufferWriter(memoryPool))
                {
                    // Read JPEG stream
                    TiffStreamRegion streamRegion = _streamRegion;
                    do
                    {
                        int           readSize = Math.Min(streamRegion.Length, BufferSize);
                        Memory <byte> memory   = bufferWriter.GetMemory(readSize);
                        memory   = memory.Slice(0, Math.Min(streamRegion.Length, memory.Length));
                        readSize = await contentReader.ReadAsync(streamRegion.Offset, memory, context.CancellationToken).ConfigureAwait(false);

                        bufferWriter.Advance(readSize);
                        streamRegion = new TiffStreamRegion(streamRegion.Offset + readSize, streamRegion.Length - readSize);
                    } while (streamRegion.Length > 0);

                    // Identify the image
                    var decoder = new JpegDecoder();
                    decoder.MemoryPool = memoryPool;
                    decoder.SetInput(bufferWriter.GetReadOnlySequence());
                    decoder.Identify();
                    if (decoder.Width != context.SourceImageSize.Width || decoder.Height != context.SourceImageSize.Height)
                    {
                        throw new InvalidOperationException("The image size does not match.");
                    }
                    if (decoder.Precision != 8)
                    {
                        throw new InvalidOperationException("Only 8-bit JPEG is supported.");
                    }

                    // Adjust buffer size and reading region to reduce buffer size
                    int skippedWidth  = context.SourceReadOffset.X / 8 * 8;
                    int skippedHeight = context.SourceReadOffset.Y / 8 * 8;
                    context.SourceReadOffset = new TiffPoint(context.SourceReadOffset.X % 8, context.SourceReadOffset.Y % 8);
                    int bufferWidth  = context.SourceReadOffset.X + context.ReadSize.Width;
                    int bufferHeight = context.SourceReadOffset.Y + context.ReadSize.Height;
                    context.SourceImageSize = new TiffSize(bufferWidth, bufferHeight);

                    // Allocate buffer and decode image
                    int dataSize = bufferWidth * bufferHeight * decoder.NumberOfComponents;
                    dataHandle = memoryPool.Rent(dataSize);
                    data       = dataHandle.Memory.Slice(0, dataSize);
                    decoder.SetOutputWriter(new LegacyJpegBufferOutputWriter(skippedWidth, bufferWidth, skippedHeight, bufferHeight, decoder.NumberOfComponents, data));
                    decoder.Decode();
                }

                // Pass the buffer to the next middleware
                context.UncompressedData = data;
                await next.RunAsync(context).ConfigureAwait(false);

                context.UncompressedData = null;
            }
            finally
            {
                dataHandle?.Dispose();
            }
        }
        /// <inheritdoc />
        public void Decompress(TiffDecompressionContext context, ReadOnlyMemory <byte> input, Memory <byte> output)
        {
            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            // Identify this block
            JpegDecoder decoder = Interlocked.Exchange(ref _decoder, null) ?? LoadJpegDecoder();

            decoder.MemoryPool = context.MemoryPool;
            decoder.SetInput(input);
            decoder.Identify();

            // Validate we are capable of decoding this.
            TiffSize outputBufferSize = context.ImageSize;

            if (decoder.Width < outputBufferSize.Width || decoder.Height < outputBufferSize.Height)
            {
                throw new InvalidDataException("Image dimension is too small.");
            }

            // Check number of components
            if (decoder.NumberOfComponents != _numberOfComponents)
            {
                throw new InvalidDataException($"Expect {_numberOfComponents} components, but got {decoder.NumberOfComponents} components in the JPEG stream.");
            }

            JpegBlockOutputWriter outputWriter;

            if (decoder.Precision == 8)
            {
                if (context.BitsPerSample.GetFirstOrDefault() != 8)
                {
                    throw new InvalidDataException("Precision of 8 bit is not expected.");
                }
                outputWriter = new JpegBuffer8BitOutputWriter(outputBufferSize.Width, context.SkippedScanlines, context.SkippedScanlines + context.RequestedScanlines, decoder.NumberOfComponents, output);
            }
            else if (decoder.Precision < 8)
            {
                if (context.BitsPerSample.GetFirstOrDefault() != 8)
                {
                    throw new InvalidDataException($"Precision of {decoder.Precision} bit is not expected.");
                }
                outputWriter = new JpegBufferAny8BitOutputWriter(outputBufferSize.Width, context.SkippedScanlines, context.SkippedScanlines + context.RequestedScanlines, decoder.NumberOfComponents, decoder.Precision, output);
            }
            else if (decoder.Precision <= 16)
            {
                if (context.BitsPerSample.GetFirstOrDefault() != 16)
                {
                    throw new InvalidDataException($"Precision of {decoder.Precision} bit is not expected.");
                }
                outputWriter = new JpegBufferAny16BitOutputWriter(outputBufferSize.Width, context.SkippedScanlines, context.SkippedScanlines + context.RequestedScanlines, decoder.NumberOfComponents, decoder.Precision, output);
            }
            else
            {
                throw new InvalidDataException($"Precision of {decoder.Precision} bit is not expected.");
            }

            // Decode
            decoder.SetOutputWriter(outputWriter);
            decoder.Decode();

            // Reset state
            decoder.ResetInput();
            decoder.ResetHeader();
            decoder.ResetOutputWriter();

            // Cache the instances
            Interlocked.CompareExchange(ref _decoder, decoder, null);
        }