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); }
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); } }
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)); }
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); }
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); } } }
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)); }
/// <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(); } }
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); }