public async Task TestImageDecodeAsync(string refImage, int refIfd, int refBitDepth, string testImage, int testIfd, int testBitDepth) { const int BufferBitDepth = 16; // We do not support decoding into 32 bit buffer yet. refBitDepth = Math.Min(refBitDepth, BufferBitDepth); testBitDepth = Math.Min(testBitDepth, BufferBitDepth); TiffStreamOffset ifdOffset; TiffImageFileDirectory ifd; // Load reference image await using TiffFileReader refTiff = await TiffFileReader.OpenAsync(refImage); ifdOffset = refTiff.FirstImageFileDirectoryOffset; Assert.False(ifdOffset.IsZero); for (int i = 0; i < refIfd; i++) { ifd = await refTiff.ReadImageFileDirectoryAsync(ifdOffset); ifdOffset = ifd.NextOffset; Assert.False(ifdOffset.IsZero); } ifd = await refTiff.ReadImageFileDirectoryAsync(ifdOffset); TiffImageDecoder refDecoder = await refTiff.CreateImageDecoderAsync(ifd); // Load test image await using TiffFileReader testTiff = await TiffFileReader.OpenAsync(testImage); ifdOffset = testTiff.FirstImageFileDirectoryOffset; Assert.False(ifdOffset.IsZero); for (int i = 0; i < testIfd; i++) { ifd = await testTiff.ReadImageFileDirectoryAsync(ifdOffset); ifdOffset = ifd.NextOffset; Assert.False(ifdOffset.IsZero); } ifd = await testTiff.ReadImageFileDirectoryAsync(ifdOffset); TiffImageDecoder testDecoder = await testTiff.CreateImageDecoderAsync(ifd); Assert.Equal(refDecoder.Width, testDecoder.Width); Assert.Equal(refDecoder.Height, testDecoder.Height); TiffRgba64[] refBuffer = new TiffRgba64[refDecoder.Width * refDecoder.Height]; TiffRgba64[] testBuffer = new TiffRgba64[testDecoder.Width * testDecoder.Height]; await refDecoder.DecodeAsync(TiffPixelBuffer.Wrap(refBuffer, refDecoder.Width, refDecoder.Height)); await testDecoder.DecodeAsync(TiffPixelBuffer.Wrap(testBuffer, testDecoder.Width, testDecoder.Height)); ShiftPixels(MemoryMarshal.Cast <TiffRgba64, ushort>(refBuffer), BufferBitDepth - refBitDepth); ShiftPixels(MemoryMarshal.Cast <TiffRgba64, ushort>(testBuffer), BufferBitDepth - testBitDepth); Assert.True(refBuffer.AsSpan().SequenceEqual(testBuffer)); }
public async Task TestAsync(string reference, string test) { using var refImage = Image.Load <L8>(reference); await using TiffFileReader tiff = await TiffFileReader.OpenAsync(test); TiffStreamOffset ifdOffset = tiff.FirstImageFileDirectoryOffset; while (!ifdOffset.IsZero) { TiffImageFileDirectory ifd = await tiff.ReadImageFileDirectoryAsync(ifdOffset); TiffImageDecoder decoder = await tiff.CreateImageDecoderAsync(ifd, new TiffImageDecoderOptions { UndoColorPreMultiplying = true }); Assert.Equal(refImage.Width, decoder.Width); Assert.Equal(refImage.Height, decoder.Height); TiffGray8[] pixels = new TiffGray8[decoder.Width * decoder.Height]; await decoder.DecodeAsync(TiffPixelBuffer.Wrap(pixels, decoder.Width, decoder.Height)); AssertEqual(refImage, pixels); using (var image = new Image <L8>(decoder.Width, decoder.Height)) { decoder.Decode(image); AssertEqual(refImage, image); } ifdOffset = ifd.NextOffset; } }
public async Task TestDoubleCompatibility(int length, bool bigTiff) { double[] refData = new double[length]; var rand = new Random(); for (int i = 0; i < refData.Length; i++) { refData[i] = rand.NextDouble(); } using Stream stream = await GenerateTiffAsync(bigTiff, async ifd => { await ifd.WriteTagAsync((TiffTag) 0x1234, TiffValueCollection.UnsafeWrap(refData)); }); await using (TiffFileReader reader = await TiffFileReader.OpenAsync(stream, leaveOpen: true)) { TiffImageFileDirectory ifd = await reader.ReadImageFileDirectoryAsync(); TiffFieldReader fieldReader = await reader.CreateFieldReaderAsync(); TiffImageFileDirectoryEntry entry = ifd.FindEntry((TiffTag)0x1234); Assert.Equal((TiffTag)0x1234, entry.Tag); // Byte await TestInvalidConversionAsync <byte>(fieldReader, entry, nameof(fieldReader.ReadByteFieldAsync), refData.Length); // SSbyte await TestInvalidConversionAsync <sbyte>(fieldReader, entry, nameof(fieldReader.ReadSByteFieldAsync), refData.Length); // Short await TestInvalidConversionAsync <ushort>(fieldReader, entry, nameof(fieldReader.ReadShortFieldAsync), refData.Length); // SShort await TestInvalidConversionAsync <short>(fieldReader, entry, nameof(fieldReader.ReadSShortFieldAsync), refData.Length); // Long await TestInvalidConversionAsync <uint>(fieldReader, entry, nameof(fieldReader.ReadLongFieldAsync), refData.Length); // SLong await TestInvalidConversionAsync <int>(fieldReader, entry, nameof(fieldReader.ReadSLongFieldAsync), refData.Length); // Float await TestInvalidConversionAsync <float>(fieldReader, entry, nameof(fieldReader.ReadFloatFieldAsync), refData.Length); // Double await TestValidConversionAsync(fieldReader, entry, nameof(fieldReader.ReadDoubleFieldAsync), refData); // Rational await TestInvalidConversionAsync <TiffRational>(fieldReader, entry, nameof(fieldReader.ReadRationalFieldAsync), refData.Length); // SRational await TestInvalidConversionAsync <TiffSRational>(fieldReader, entry, nameof(fieldReader.ReadSRationalFieldAsync), refData.Length); } }
public static async Task <int> Merge(FileInfo[] source, FileInfo output, CancellationToken cancellationToken) { if (source is null || source.Length == 0) { Console.WriteLine("Input TIFF file are not specified."); return(1); } if (output is null) { Console.WriteLine("Output TIFF file is not specified"); return(1); } await using TiffFileWriter writer = await TiffFileWriter.OpenAsync(output.FullName); TiffStreamOffset fistIfdOffset = default; TiffStreamOffset previousIfdOffset = default; foreach (FileInfo sourceFile in source) { await using TiffFileReader reader = await TiffFileReader.OpenAsync(sourceFile.FullName); await using TiffFileContentReader contentReader = await reader.CreateContentReaderAsync(); await using TiffFieldReader fieldReader = await reader.CreateFieldReaderAsync(cancellationToken); TiffStreamOffset inputIfdOffset = reader.FirstImageFileDirectoryOffset; while (!inputIfdOffset.IsZero) { TiffImageFileDirectory ifd = await reader.ReadImageFileDirectoryAsync(inputIfdOffset, cancellationToken); using (TiffImageFileDirectoryWriter ifdWriter = writer.CreateImageFileDirectory()) { await CopyIfdAsync(contentReader, fieldReader, ifd, ifdWriter, cancellationToken); previousIfdOffset = await ifdWriter.FlushAsync(previousIfdOffset); if (fistIfdOffset.IsZero) { fistIfdOffset = previousIfdOffset; } } inputIfdOffset = ifd.NextOffset; } } writer.SetFirstImageFileDirectoryOffset(fistIfdOffset); await writer.FlushAsync(); return(0); }
private async Task <IImageInfo> IdentifyCoreAsync(TiffFileContentSource contentSource, CancellationToken cancellationToken) { using TiffFileReader tiff = await TiffFileReader.OpenAsync(contentSource, cancellationToken : cancellationToken).ConfigureAwait(false); TiffImageFileDirectory ifd = await tiff.ReadImageFileDirectoryAsync(cancellationToken).ConfigureAwait(false); TiffImageDecoder decoder = await tiff.CreateImageDecoderAsync(ifd, _options, cancellationToken).ConfigureAwait(false); return(new ImageInfo() { Width = decoder.Width, Height = decoder.Height }); }
public async Task TestSLongCompatibility(int length, bool bigTiff) { int[] refData = new int[length]; new Random(42).NextBytes(MemoryMarshal.AsBytes(refData.AsSpan())); using Stream stream = await GenerateTiffAsync(bigTiff, async ifd => { await ifd.WriteTagAsync((TiffTag) 0x1234, TiffValueCollection.UnsafeWrap(refData)); }); await using (TiffFileReader reader = await TiffFileReader.OpenAsync(stream, leaveOpen: true)) { TiffImageFileDirectory ifd = await reader.ReadImageFileDirectoryAsync(); TiffFieldReader fieldReader = await reader.CreateFieldReaderAsync(); TiffImageFileDirectoryEntry entry = ifd.FindEntry((TiffTag)0x1234); Assert.Equal((TiffTag)0x1234, entry.Tag); // Byte await TestInvalidConversionAsync <byte>(fieldReader, entry, nameof(fieldReader.ReadByteFieldAsync), refData.Length); // SSbyte await TestInvalidConversionAsync <sbyte>(fieldReader, entry, nameof(fieldReader.ReadSByteFieldAsync), refData.Length); // Short await TestInvalidConversionAsync <ushort>(fieldReader, entry, nameof(fieldReader.ReadShortFieldAsync), refData.Length); // SShort await TestInvalidConversionAsync <short>(fieldReader, entry, nameof(fieldReader.ReadSShortFieldAsync), refData.Length); // Long await TestValidConversionAsync(fieldReader, entry, nameof(fieldReader.ReadLongFieldAsync), Array.ConvertAll(refData, v => (uint)v)); // SLong await TestValidConversionAsync(fieldReader, entry, nameof(fieldReader.ReadSLongFieldAsync), refData); // Float await TestInvalidConversionAsync <float>(fieldReader, entry, nameof(fieldReader.ReadFloatFieldAsync), refData.Length); // Double await TestInvalidConversionAsync <double>(fieldReader, entry, nameof(fieldReader.ReadDoubleFieldAsync), refData.Length); // Rational await TestInvalidConversionAsync <TiffRational>(fieldReader, entry, nameof(fieldReader.ReadRationalFieldAsync), refData.Length); // SRational await TestValidConversionAsync(fieldReader, entry, nameof(fieldReader.ReadSRationalFieldAsync), Array.ConvertAll(refData, v => new TiffSRational(v, 1))); } }
public static async Task <int> Dump(FileInfo file, long?offset, CancellationToken cancellationToken) { await using TiffFileReader tiff = await TiffFileReader.OpenAsync(file.FullName); await using TiffFieldReader fieldReader = await tiff.CreateFieldReaderAsync(cancellationToken); Console.WriteLine("Input File: " + file.FullName); Console.WriteLine($"StandardTIFF: {tiff.IsStandardTiff}, BigTIFF: {tiff.IsBigTiff}, IsLittleEndian: {tiff.IsLittleEndian}"); Console.WriteLine("First IFD: " + tiff.FirstImageFileDirectoryOffset); Console.WriteLine(); int ifdIndex = 0; TiffStreamOffset ifdOffset = offset.HasValue ? new TiffStreamOffset(offset.GetValueOrDefault()) : tiff.FirstImageFileDirectoryOffset; while (!ifdOffset.IsZero) { TiffImageFileDirectory ifd = await tiff.ReadImageFileDirectoryAsync(ifdOffset, cancellationToken); Console.WriteLine($"IFD #{ifdIndex++} (Offset = {ifdOffset})"); Console.WriteLine(" Well-known Tags:"); await DumpWellKnownTagsAsync(fieldReader, ifd, cancellationToken); Console.WriteLine(); Console.WriteLine(" Tags:"); for (int i = 0; i < ifd.Count; i++) { TiffImageFileDirectoryEntry entry = ifd[i]; await DumpIfdEntryAsync(i, fieldReader, entry, cancellationToken); } if (ifd.Count == 0) { Console.WriteLine(" No tags found."); } Console.WriteLine(); Console.WriteLine(); ifdOffset = ifd.NextOffset; } return(0); }
private async Task <Image <TPixel> > DecodeCoreAsync <TPixel>(TiffFileContentSource contentSource, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel <TPixel> { using TiffFileReader tiff = await TiffFileReader.OpenAsync(contentSource, cancellationToken : cancellationToken).ConfigureAwait(false); TiffImageFileDirectory ifd = await tiff.ReadImageFileDirectoryAsync(cancellationToken).ConfigureAwait(false); TiffImageDecoder decoder = await tiff.CreateImageDecoderAsync(ifd, _options, cancellationToken).ConfigureAwait(false); Image <TPixel>?image = new Image <TPixel>(_configuration, decoder.Width, decoder.Height); try { await decoder.DecodeAsync(image, cancellationToken).ConfigureAwait(false); return(Interlocked.Exchange <Image <TPixel>?>(ref image, null) !); } finally { image?.Dispose(); } }
internal async Task <TiffStreamOffset> GenerateReducedResolutionLayerAsync(int layer, TiffStreamOffset ifdOffset, IRipperReducedResolutionGenerationReporter reporter, CancellationToken cancellationToken) { int outputTileSize = _options.OutputTileSize; int outputTileSize2 = 2 * outputTileSize; TiffImageFileDirectory ifd = await _fileReader.ReadImageFileDirectoryAsync(ifdOffset).ConfigureAwait(false); TiffImageDecoder image = await _fileReader.CreateImageDecoderAsync(ifd); int width = image.Width; int height = image.Height; int tiffRowCount = (width / 2 + outputTileSize - 1) / outputTileSize; int tiffColCount = (height / 2 + outputTileSize - 1) / outputTileSize; int index = 0; ulong[] offsets = new ulong[tiffRowCount * tiffColCount]; ulong[] byteCounts = new ulong[tiffRowCount * tiffColCount]; ulong totalByteCount = 0; reporter?.ReportStartReducedResolutionLayerGeneration(layer, offsets.Length, width / 2, height / 2); using (Image <Rgb24> canvas2 = new Image <Rgb24>(_configuration, outputTileSize2, outputTileSize2)) { for (int y = 0; y < height; y += outputTileSize2) { for (int x = 0; x < width; x += outputTileSize2) { cancellationToken.ThrowIfCancellationRequested(); MemoryMarshal.AsBytes(canvas2.GetPixelSpan()).Clear(); await image.DecodeAsync(new TiffPoint(x, y), canvas2).ConfigureAwait(false); using (Image <Rgb24> tile24 = canvas2.Clone(ctx => { ctx.Resize(outputTileSize, outputTileSize); })) { cancellationToken.ThrowIfCancellationRequested(); TiffStreamRegion region = await _encoder.EncodeAsync(_fileWriter, tile24).ConfigureAwait(false); offsets[index] = (ulong)region.Offset.Offset; byteCounts[index] = (uint)region.Length; totalByteCount += (uint)region.Length; index++; reporter?.ReportReducedResolutionLayerGenerationProgress(layer, index, offsets.Length); } } } } cancellationToken.ThrowIfCancellationRequested(); using (TiffImageFileDirectoryWriter ifdWriter = _fileWriter.CreateImageFileDirectory()) { await ifdWriter.WriteTagAsync(TiffTag.NewSubfileType, new TiffValueCollection <ushort>((ushort)TiffNewSubfileType.ReducedResolution)).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.PhotometricInterpretation, new TiffValueCollection <ushort>((ushort)TiffPhotometricInterpretation.YCbCr)).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.Compression, new TiffValueCollection <ushort>((ushort)TiffCompression.Jpeg)).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.SamplesPerPixel, new TiffValueCollection <ushort>((ushort)3)).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.TileWidth, new TiffValueCollection <ushort>((ushort)outputTileSize)).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.TileLength, new TiffValueCollection <ushort>((ushort)outputTileSize)).ConfigureAwait(false); //ifdWriter.AddTag(TiffTag.ResolutionUnit, (ushort)TiffResolutionUnit.Inch); //await ifdWriter.WriteTagAsync(TiffTag.XResolution, new TiffValueCollection<TiffRational>(new TiffRational(72, 1))); //await ifdWriter.WriteTagAsync(TiffTag.YResolution, new TiffValueCollection<TiffRational>(new TiffRational(72, 1))); await ifdWriter.WriteTagAsync(TiffTag.SampleFormat, new TiffValueCollection <ushort>(new ushort[] { 1, 1, 1 })).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.BitsPerSample, new TiffValueCollection <ushort>(new ushort[] { 8, 8, 8 })).ConfigureAwait(false); if (UseBigTiff) { await ifdWriter.WriteTagAsync(TiffTag.ImageWidth, new TiffValueCollection <ulong>((ulong)(width / 2))).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.ImageLength, new TiffValueCollection <ulong>((ulong)(height / 2))).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.TileOffsets, new TiffValueCollection <ulong>(offsets)).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.TileByteCounts, new TiffValueCollection <ulong>(byteCounts)).ConfigureAwait(false); } else { await ifdWriter.WriteTagAsync(TiffTag.ImageWidth, new TiffValueCollection <uint>((uint)(width / 2))).ConfigureAwait(false); await ifdWriter.WriteTagAsync(TiffTag.ImageLength, new TiffValueCollection <uint>((uint)(height / 2))).ConfigureAwait(false); uint[] tempArr = new uint[offsets.Length]; for (int i = 0; i < tempArr.Length; i++) { tempArr[i] = (uint)offsets[i]; } await ifdWriter.WriteTagAsync(TiffTag.TileOffsets, new TiffValueCollection <uint>(tempArr)).ConfigureAwait(false); for (int i = 0; i < tempArr.Length; i++) { tempArr[i] = (uint)byteCounts[i]; } await ifdWriter.WriteTagAsync(TiffTag.TileByteCounts, new TiffValueCollection <uint>(tempArr)).ConfigureAwait(false); } string software = Software; if (!string.IsNullOrEmpty(software)) { await ifdWriter.WriteTagAsync(TiffTag.Software, new TiffValueCollection <string>(software)); } ifdOffset = await ifdWriter.FlushAsync(ifdOffset).ConfigureAwait(false); } reporter?.ReportCompleteReducedResolutionLayerGeneration(layer, offsets.Length, (long)totalByteCount); return(ifdOffset); }