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 TestRoundtrip(bool isTile) { TiffGray8[] refImage = new TiffGray8[2048 * 2048]; TiffGray8[] testImage = new TiffGray8[2048 * 2048]; var rand = new Random(42); rand.NextBytes(MemoryMarshal.AsBytes(refImage.AsSpan())); var builder = new TiffImageEncoderBuilder(); builder.PhotometricInterpretation = TiffPhotometricInterpretation.BlackIsZero; builder.Compression = TiffCompression.NoCompression; builder.IsTiled = isTile; // Make sure we have at least CacheSize strips or tiles // Cache size in the current implementation is 256 // Any value greater than 256 should be OK. builder.RowsPerStrip = 2; // 1024 strips builder.TileSize = new TiffSize(16, 16); // 16384 tiles var ms = new MemoryStream(); await GenerateImageAsync(ms, builder, TiffPixelBuffer.WrapReadOnly(refImage, 2048, 2048)); ms.Seek(0, SeekOrigin.Begin); await using TiffFileReader tiff = await TiffFileReader.OpenAsync(ms, leaveOpen : true); TiffImageDecoder decoder = await tiff.CreateImageDecoderAsync(); await decoder.DecodeAsync(TiffPixelBuffer.Wrap(testImage, 2048, 2048)); Assert.True(refImage.AsSpan().SequenceEqual(testImage.AsSpan())); }
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 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); }
public async Task TestRoundtrip(bool isTile, int maxDegreeOfParallelism, bool isYCbCr) { TiffGray8[] refImage = new TiffGray8[4096 * 4096]; TiffGray8[] testImage = new TiffGray8[4096 * 4096]; var rand = new Random(42); rand.NextBytes(MemoryMarshal.AsBytes(refImage.AsSpan())); var builder = new TiffImageEncoderBuilder(); if (isYCbCr) { builder.PhotometricInterpretation = TiffPhotometricInterpretation.YCbCr; builder.HorizontalChromaSubSampling = 2; builder.VerticalChromaSubSampling = 2; } else { builder.PhotometricInterpretation = TiffPhotometricInterpretation.BlackIsZero; builder.Predictor = TiffPredictor.HorizontalDifferencing; } builder.Compression = TiffCompression.Lzw; builder.IsTiled = isTile; builder.RowsPerStrip = 64; builder.TileSize = new TiffSize(64, 64); builder.MaxDegreeOfParallelism = maxDegreeOfParallelism; var ms = new MemoryStream(); await GenerateImageAsync(ms, builder, TiffPixelBuffer.WrapReadOnly(refImage, 4096, 4096)); ms.Seek(0, SeekOrigin.Begin); await using TiffFileReader tiff = await TiffFileReader.OpenAsync(ms, leaveOpen : true); TiffImageDecoder decoder = await tiff.CreateImageDecoderAsync(); await decoder.DecodeAsync(TiffPixelBuffer.Wrap(testImage, 4096, 4096)); Assert.True(refImage.AsSpan().SequenceEqual(testImage.AsSpan())); }
public async Task Setup() { TiffGray8[] image = new TiffGray8[8192 * 8192]; _scratchSpace = TiffPixelBuffer.Wrap(image, 8192, 8192); var builder = new TiffImageEncoderBuilder(); builder.PhotometricInterpretation = TiffPhotometricInterpretation.WhiteIsZero; builder.Compression = Compression; // Generate a image with many strips var ms = new MemoryStream(); builder.IsTiled = false; builder.RowsPerStrip = 256; await GenerateImageAsync(ms, builder, _scratchSpace); _stripTestTiff = ms.ToArray(); ms.SetLength(0); // Generate a image with many tiles builder.IsTiled = true; builder.TileSize = new TiffSize(512, 512); await GenerateImageAsync(ms, builder, _scratchSpace); _tileTestTiff = ms.ToArray(); _stripReader = await TiffFileReader.OpenAsync(_stripTestTiff); _stripDecoder = await _stripReader.CreateImageDecoderAsync(new TiffImageDecoderOptions { MaxDegreeOfParallelism = DegreeOfParallelism }); await _stripDecoder.DecodeAsync(_scratchSpace); _tileReader = await TiffFileReader.OpenAsync(_tileTestTiff); _tileDecoder = await _tileReader.CreateImageDecoderAsync(new TiffImageDecoderOptions { MaxDegreeOfParallelism = DegreeOfParallelism }); await _tileDecoder.DecodeAsync(_scratchSpace); }
public async Task Setup() { TiffGray8[] image = new TiffGray8[8192 * 8192]; _scratchSpace = TiffPixelBuffer.Wrap(image, 8192, 8192); var builder = new TiffImageEncoderBuilder(); builder.PhotometricInterpretation = TiffPhotometricInterpretation.BlackIsZero; builder.Compression = TiffCompression.NoCompression; // Generate a image with many strips var ms = new MemoryStream(); builder.IsTiled = false; builder.RowsPerStrip = 1; await GenerateImageAsync(ms, builder, _scratchSpace); _stripTestTiff = ms.ToArray(); ms.SetLength(0); // Generate a image with many tiles builder.IsTiled = true; builder.TileSize = new TiffSize(16, 16); // the minimum tile size await GenerateImageAsync(ms, builder, _scratchSpace); _tileTestTiff = ms.ToArray(); _stripReader = await TiffFileReader.OpenAsync(_stripTestTiff); _stripDecoder = await _stripReader.CreateImageDecoderAsync(); await _stripDecoder.DecodeAsync(_scratchSpace); _tileReader = await TiffFileReader.OpenAsync(_tileTestTiff); _tileDecoder = await _tileReader.CreateImageDecoderAsync(); await _tileDecoder.DecodeAsync(_scratchSpace); }
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(); } }
public async Task GenerateReducedResolutionLayerAsync(IRipperReducedResolutionGenerationReporter reporter, CancellationToken cancellationToken) { _fileReader = await TiffFileReader.OpenAsync(_stream, leaveOpen : true); TiffStreamOffset ifd = _fileReader.FirstImageFileDirectoryOffset; int width = _manifest.Width; int height = _manifest.Height; // Calculate layer count int outputTileSize = _options.OutputTileSize; int layerCount = 0; int calcWidth = width, calcHeight = height; while (Math.Min(calcWidth, calcHeight) > outputTileSize && Math.Min(calcWidth, calcHeight) >= 32) { calcWidth = calcWidth / 2; calcHeight = calcHeight / 2; layerCount++; } // Actually generate the layers int layer = 0; reporter?.ReportStartReducedResolutionGeneration(layerCount); while (Math.Min(width, height) > outputTileSize && Math.Min(width, height) >= 32) { cancellationToken.ThrowIfCancellationRequested(); ifd = await GenerateReducedResolutionLayerAsync(++layer, ifd, reporter, cancellationToken).ConfigureAwait(false); width = width / 2; height = height / 2; } reporter?.ReportCompleteReducedResolutionGeneration(layerCount); }
protected override async Task <DeepZoomManifest> InitializeManifestAsync(Uri manifestUri) { string filename = GetFileNameFromUri(manifestUri); _baseUri = new Uri(manifestUri, "./"); _baseName = Path.ChangeExtension(filename, null); // Deep Zoom format if (".dzi".Equals(Path.GetExtension(filename), StringComparison.OrdinalIgnoreCase) || ".xml".Equals(Path.GetExtension(filename), StringComparison.OrdinalIgnoreCase)) { using (var ms = new MemoryStream()) { await GetUriContentAsync(manifestUri, ms).ConfigureAwait(false); ms.Seek(0, SeekOrigin.Begin); return(await DeepZoomManifest.ParseAsync(ms).ConfigureAwait(false)); } } // local TIFF file if ("file".Equals(manifestUri.Scheme, StringComparison.OrdinalIgnoreCase)) { TiffFileReader?tiff = null; try { tiff = await TiffFileReader.OpenAsync(manifestUri.LocalPath).ConfigureAwait(false); TiffImageDecoder decoder = await tiff.CreateImageDecoderAsync().ConfigureAwait(false); _tiff = tiff; _decoder = decoder; tiff = null; return(new DeepZoomManifest { Format = "jpeg", Width = decoder.Width, Height = decoder.Height, TileSize = 256, Overlap = 0 }); } catch (InvalidDataException) { // Do nothing } finally { if (!(tiff is null)) { await tiff.DisposeAsync().ConfigureAwait(false); } } } // Other images if ("file".Equals(manifestUri.Scheme, StringComparison.OrdinalIgnoreCase)) { try { _image = Image.Load <Rgb24>(manifestUri.LocalPath); return(new DeepZoomManifest { Format = "jpeg", Width = _image.Width, Height = _image.Height, TileSize = 256, Overlap = 0 }); } catch (Exception) { // Do nothing } } throw new ArgumentException(nameof(manifestUri), $"{filename} is not a dzi file."); }