Esempio n. 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);
        }
Esempio n. 2
0
        public IImageInfo Identify()
        {
            using var memoryStream = new MemoryStream(this.jpegBytes);
            var decoder = new JpegDecoder();

            return(decoder.Identify(Configuration.Default, memoryStream));
        }
        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);
            }
        }
        public void Identify_DetectsCorrectColorType(string imagePath, JpegColorType expectedColorType)
        {
            var testFile = TestFile.Create(imagePath);

            using (var stream = new MemoryStream(testFile.Bytes, false))
            {
                IImageInfo   image = JpegDecoder.Identify(Configuration.Default, stream);
                JpegMetadata meta  = image.Metadata.GetJpegMetadata();
                Assert.Equal(expectedColorType, meta.ColorType);
            }
        }
        public void Identify_VerifyQuality(string imagePath, int quality)
        {
            var testFile = TestFile.Create(imagePath);

            using (var stream = new MemoryStream(testFile.Bytes, false))
            {
                var          decoder = new JpegDecoder();
                IImageInfo   image   = decoder.Identify(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 Identify_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();
                IImageInfo    image   = decoder.Identify(Configuration.Default, stream);
                ImageMetadata meta    = image.Metadata;
                Assert.Equal(xResolution, meta.HorizontalResolution);
                Assert.Equal(yResolution, meta.VerticalResolution);
                Assert.Equal(resolutionUnit, meta.ResolutionUnits);
            }
        }
Esempio n. 8
0
        public static void Load(Stream stream, PortableImage image)
        {
            // This just reads enough headers to set size.

            var ms = new MemoryStream();

            stream.CopyTo(ms);
            var data = new ReadOnlySequence <byte>(ms.ToArray());

            var decoder = new JpegDecoder();

            decoder.SetInput(data);
            decoder.Identify();

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

            image.Width      = decoder.Width;
            image.Height     = decoder.Height;
            image.LoadFormat = PortableImage.Jpeg;
            image.imageFlags = decoder.NumberOfComponents == 1 ? ImageFlags.ColorSpaceGray : ImageFlags.ColorSpaceRgb;

            /*
             * // TODO: bring in the huge complexity that is the JPEG read/write format.
             * // The PDF stuff doesn't need to read frames, so it would be neat to have this 'lazy'
             * // Add a frame to the image object.
             * Frame frame = image.AddFrame(image.Width, image.Height, PixelFormat.Format24bppRgb);
             *
             * if (decoder.Precision == 8)
             * {
             *  // This is the most common case for JPEG, and we have an optimised implementation.
             *  decoder.SetOutputWriter(new JpegBufferOutputWriter8Bit(image.Width, image.Height, 3, frame.data));
             * }
             * else if (decoder.Precision < 8)
             * {
             *  decoder.SetOutputWriter(new JpegBufferOutputWriterLessThan8Bit(image.Width, image.Height, decoder.Precision, 3, frame.data));
             * }
             * else
             * {
             *  decoder.SetOutputWriter(new JpegBufferOutputWriterGreaterThan8Bit(image.Width, image.Height, decoder.Precision, 3, frame.data));
             * }
             *
             * decoder.Decode();
             * // TODO: our frame buffer should now be populated with Y,Cr,Cb data. It should get converted to RGB.
             */
        }
        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));
        }
Esempio n. 10
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);
        }
Esempio n. 12
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);
                }
            }
        }
Esempio n. 13
0
        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.");
            }
        }
Esempio n. 14
0
        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));
        }
        /// <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);
        }
        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();
            }
        }
Esempio n. 17
0
        public static async Task <int> Wrap(FileInfo source, FileInfo output, CancellationToken cancellationToken)
        {
            if (source is null || !source.Exists)
            {
                Console.WriteLine(source is null ? "Input JPEG image is not specified." : "File not found: " + source.FullName);
                return(1);
            }
            if (output is null)
            {
                Console.WriteLine("Output TIFF file is not specified.");
                return(1);
            }

            byte[] jpegFile = await File.ReadAllBytesAsync(source.FullName, cancellationToken);

            var decoder = new JpegDecoder();

            decoder.SetInput(jpegFile);
            decoder.Identify(loadQuantizationTables: false);

            ushort[] bitsPerSample = new ushort[decoder.NumberOfComponents];
            ushort   bits          = (ushort)decoder.Precision;

            for (int i = 0; i < bitsPerSample.Length; i++)
            {
                bitsPerSample[i] = bits;
            }
            TiffPhotometricInterpretation photometricInterpretation =
                bitsPerSample.Length == 1 ? TiffPhotometricInterpretation.BlackIsZero :
                bitsPerSample.Length == 3 ? TiffPhotometricInterpretation.YCbCr :
                throw new InvalidDataException("Photometric interpretation not supported.");

            using (TiffFileWriter writer = await TiffFileWriter.OpenAsync(output.FullName, useBigTiff: false))
            {
                TiffStreamOffset imageOffset = await writer.WriteAlignedBytesAsync(jpegFile);

                TiffStreamOffset ifdOffset;
                using (TiffImageFileDirectoryWriter ifdWriter = writer.CreateImageFileDirectory())
                {
                    await ifdWriter.WriteTagAsync(TiffTag.ImageWidth, TiffValueCollection.Single((ushort)decoder.Width));

                    await ifdWriter.WriteTagAsync(TiffTag.ImageLength, TiffValueCollection.Single((ushort)decoder.Height));

                    await ifdWriter.WriteTagAsync(TiffTag.BitsPerSample, TiffValueCollection.UnsafeWrap(bitsPerSample));

                    await ifdWriter.WriteTagAsync(TiffTag.Compression, TiffValueCollection.Single((ushort)TiffCompression.Jpeg));

                    await ifdWriter.WriteTagAsync(TiffTag.PhotometricInterpretation, TiffValueCollection.Single((ushort)photometricInterpretation));

                    await ifdWriter.WriteTagAsync(TiffTag.SamplesPerPixel, TiffValueCollection.Single((ushort)bitsPerSample.Length));

                    await ifdWriter.WriteTagAsync(TiffTag.PlanarConfiguration, TiffValueCollection.Single((ushort)TiffPlanarConfiguration.Chunky));

                    await ifdWriter.WriteTagAsync(TiffTag.RowsPerStrip, TiffValueCollection.Single((ushort)decoder.Height));

                    await ifdWriter.WriteTagAsync(TiffTag.StripOffsets, TiffValueCollection.Single((uint)imageOffset.Offset));

                    await ifdWriter.WriteTagAsync(TiffTag.StripByteCounts, TiffValueCollection.Single((uint)jpegFile.Length));

                    if (photometricInterpretation == TiffPhotometricInterpretation.YCbCr)
                    {
                        int maxHorizontalSampling   = decoder.GetMaximumHorizontalSampling();
                        int maxVerticalSampling     = decoder.GetMaximumVerticalSampling();
                        int yHorizontalSubSampling  = maxHorizontalSampling / decoder.GetHorizontalSampling(0);
                        int yVerticalSubSampling    = maxVerticalSampling / decoder.GetVerticalSampling(0);
                        int cbHorizontalSubSampling = maxHorizontalSampling / decoder.GetHorizontalSampling(1) / yHorizontalSubSampling;
                        int cbVerticalSubSampling   = maxVerticalSampling / decoder.GetVerticalSampling(1) / yVerticalSubSampling;
                        int crHorizontalSubSampling = maxHorizontalSampling / decoder.GetHorizontalSampling(2) / yHorizontalSubSampling;
                        int crVerticalSubSampling   = maxVerticalSampling / decoder.GetVerticalSampling(2) / yVerticalSubSampling;

                        if (cbHorizontalSubSampling != crHorizontalSubSampling || cbVerticalSubSampling != crVerticalSubSampling)
                        {
                            throw new InvalidDataException("Unsupported JPEG image.");
                        }

                        await ifdWriter.WriteTagAsync(TiffTag.YCbCrSubSampling, TiffValueCollection.UnsafeWrap(new ushort[] { (ushort)cbHorizontalSubSampling, (ushort)cbVerticalSubSampling }));
                    }

                    // Write other properties here (eg, XResolution, YResolution)
                    await ifdWriter.WriteTagAsync(TiffTag.XResolution, TiffValueCollection.Single(new TiffRational(96, 1)));

                    await ifdWriter.WriteTagAsync(TiffTag.YResolution, TiffValueCollection.Single(new TiffRational(96, 1)));

                    await ifdWriter.WriteTagAsync(TiffTag.ResolutionUnit, TiffValueCollection.Single((ushort)TiffResolutionUnit.Inch));

                    ifdOffset = await ifdWriter.FlushAsync();
                }

                writer.SetFirstImageFileDirectoryOffset(ifdOffset);
                await writer.FlushAsync();
            }

            return(0);
        }