private static async Task CopyIfdAsync(TiffFileContentReader contentReader, TiffFieldReader fieldReader, TiffImageFileDirectory ifd, TiffImageFileDirectoryWriter dest, CancellationToken cancellationToken) { var tagReader = new TiffTagReader(fieldReader, ifd); foreach (TiffImageFileDirectoryEntry entry in ifd) { // Stripped image data if (entry.Tag == TiffTag.StripOffsets) { await CopyStrippedImageAsync(contentReader, tagReader, dest, cancellationToken); } else if (entry.Tag == TiffTag.StripByteCounts) { // Ignore this } // Tiled image data else if (entry.Tag == TiffTag.TileOffsets) { await CopyTiledImageAsync(contentReader, tagReader, dest, cancellationToken); } else if (entry.Tag == TiffTag.TileByteCounts) { // Ignore this } // Other fields else { await CopyFieldValueAsync(fieldReader, entry, dest, cancellationToken); } } }
private static async Task TestInvalidConversionAsync <T>(TiffFieldReader fieldReader, TiffImageFileDirectoryEntry entry, string methodName, int length) where T : unmanaged { MethodInfo method1 = typeof(TiffFieldReader).GetMethod(methodName, new Type[] { typeof(TiffImageFileDirectoryEntry), typeof(bool), typeof(CancellationToken) }); MethodInfo method2 = typeof(TiffFieldReader).GetMethod(methodName, new Type[] { typeof(TiffImageFileDirectoryEntry), typeof(int), typeof(bool), typeof(CancellationToken) }); MethodInfo method3 = typeof(TiffFieldReader).GetMethod(methodName, new Type[] { typeof(TiffImageFileDirectoryEntry), typeof(int), typeof(Memory <T>), typeof(bool), typeof(CancellationToken) }); Assert.NotNull(method1); Assert.NotNull(method2); Assert.NotNull(method3); var delegate1 = (Func <TiffImageFileDirectoryEntry, bool, CancellationToken, ValueTask <TiffValueCollection <T> > >)method1.CreateDelegate(typeof(Func <TiffImageFileDirectoryEntry, bool, CancellationToken, ValueTask <TiffValueCollection <T> > >), fieldReader); var delegate2 = (Func <TiffImageFileDirectoryEntry, int, bool, CancellationToken, ValueTask <TiffValueCollection <T> > >)method2.CreateDelegate(typeof(Func <TiffImageFileDirectoryEntry, int, bool, CancellationToken, ValueTask <TiffValueCollection <T> > >), fieldReader); var delegate3 = (Func <TiffImageFileDirectoryEntry, int, Memory <T>, bool, CancellationToken, ValueTask>)method3.CreateDelegate(typeof(Func <TiffImageFileDirectoryEntry, int, Memory <T>, bool, CancellationToken, ValueTask>), fieldReader); // Test basic overload await Assert.ThrowsAsync <InvalidOperationException>(async() => await delegate1(entry, false, default)); // Test overload with sizeLimit argument int sizeLimit = length / 2; await Assert.ThrowsAsync <InvalidOperationException>(async() => await delegate2(entry, sizeLimit, false, default)); // Test overload with external buffer int offset = length / 4; T[] testArray = new T[sizeLimit]; await Assert.ThrowsAsync <InvalidOperationException>(async() => await delegate3(entry, offset, testArray, false, default)); }
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); }
public TiffStrileOffsetCache(TiffFieldReader fieldReader, TiffImageFileDirectoryEntry offsets, TiffImageFileDirectoryEntry counts, int cacheSize) { _cacheEnabled = true; _fieldReader = fieldReader; _offsetsEntry = offsets; _countsEntry = counts; _cacheSize = cacheSize; if (offsets.ValueCount != counts.ValueCount) { throw new InvalidDataException(); } _entryCount = (int)offsets.ValueCount; }
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 static async Task TestValidConversionAsync <T>(TiffFieldReader fieldReader, TiffImageFileDirectoryEntry entry, string methodName, T[] refData) where T : unmanaged { MethodInfo method1 = typeof(TiffFieldReader).GetMethod(methodName, new Type[] { typeof(TiffImageFileDirectoryEntry), typeof(bool), typeof(CancellationToken) }); MethodInfo method2 = typeof(TiffFieldReader).GetMethod(methodName, new Type[] { typeof(TiffImageFileDirectoryEntry), typeof(int), typeof(bool), typeof(CancellationToken) }); MethodInfo method3 = typeof(TiffFieldReader).GetMethod(methodName, new Type[] { typeof(TiffImageFileDirectoryEntry), typeof(int), typeof(Memory <T>), typeof(bool), typeof(CancellationToken) }); Assert.NotNull(method1); Assert.NotNull(method2); Assert.NotNull(method3); var delegate1 = (Func <TiffImageFileDirectoryEntry, bool, CancellationToken, ValueTask <TiffValueCollection <T> > >)method1.CreateDelegate(typeof(Func <TiffImageFileDirectoryEntry, bool, CancellationToken, ValueTask <TiffValueCollection <T> > >), fieldReader); var delegate2 = (Func <TiffImageFileDirectoryEntry, int, bool, CancellationToken, ValueTask <TiffValueCollection <T> > >)method2.CreateDelegate(typeof(Func <TiffImageFileDirectoryEntry, int, bool, CancellationToken, ValueTask <TiffValueCollection <T> > >), fieldReader); var delegate3 = (Func <TiffImageFileDirectoryEntry, int, Memory <T>, bool, CancellationToken, ValueTask>)method3.CreateDelegate(typeof(Func <TiffImageFileDirectoryEntry, int, Memory <T>, bool, CancellationToken, ValueTask>), fieldReader); // Test basic overload TiffValueCollection <T> testData = await delegate1(entry, false, default); Assert.True(MemoryMarshal.AsBytes(refData.AsSpan()).SequenceEqual(MemoryMarshal.AsBytes(testData.ToArray().AsSpan()))); // Test overload with sizeLimit argument int sizeLimit = refData.Length / 2; testData = await delegate2(entry, sizeLimit, false, default); Assert.Equal(sizeLimit, testData.Count); Assert.True(MemoryMarshal.AsBytes(refData.AsSpan(0, sizeLimit)).SequenceEqual(MemoryMarshal.AsBytes(testData.ToArray().AsSpan()))); // Test overload with external buffer int offset = refData.Length / 4; T[] testArray = new T[sizeLimit]; await delegate3(entry, offset, testArray, false, default); Assert.True(MemoryMarshal.AsBytes(refData.AsSpan(offset, sizeLimit)).SequenceEqual(MemoryMarshal.AsBytes(testArray.AsSpan()))); // Test invalid parameter Assert.Throws <ArgumentOutOfRangeException>("offset", () => delegate3(entry, -1, new T[entry.ValueCount], false, default)); Assert.Throws <ArgumentOutOfRangeException>("offset", () => delegate3(entry, (int)(entry.ValueCount + 1), new T[1], false, default)); Assert.Throws <ArgumentOutOfRangeException>("destination", () => delegate3(entry, 0, new T[entry.ValueCount + 1], false, default)); // Now do it again with the sync version if (methodName.EndsWith("Async", StringComparison.Ordinal)) { methodName = methodName.Substring(0, methodName.Length - 5); MethodInfo method4 = typeof(TiffFieldReader).GetMethod(methodName, new Type[] { typeof(TiffImageFileDirectoryEntry), typeof(bool) }); MethodInfo method5 = typeof(TiffFieldReader).GetMethod(methodName, new Type[] { typeof(TiffImageFileDirectoryEntry), typeof(int), typeof(bool) }); MethodInfo method6 = typeof(TiffFieldReader).GetMethod(methodName, new Type[] { typeof(TiffImageFileDirectoryEntry), typeof(int), typeof(Memory <T>), typeof(bool) }); Assert.NotNull(method4); Assert.NotNull(method5); Assert.NotNull(method6); var delegate4 = (Func <TiffImageFileDirectoryEntry, bool, TiffValueCollection <T> >)method4.CreateDelegate(typeof(Func <TiffImageFileDirectoryEntry, bool, TiffValueCollection <T> >), fieldReader); var delegate5 = (Func <TiffImageFileDirectoryEntry, int, bool, TiffValueCollection <T> >)method5.CreateDelegate(typeof(Func <TiffImageFileDirectoryEntry, int, bool, TiffValueCollection <T> >), fieldReader); var delegate6 = (Action <TiffImageFileDirectoryEntry, int, Memory <T>, bool>)method6.CreateDelegate(typeof(Action <TiffImageFileDirectoryEntry, int, Memory <T>, bool>), fieldReader); // Test basic overload testData = delegate4(entry, false); Assert.True(MemoryMarshal.AsBytes(refData.AsSpan()).SequenceEqual(MemoryMarshal.AsBytes(testData.ToArray().AsSpan()))); // Test overload with sizeLimit argument sizeLimit = refData.Length / 2; testData = delegate5(entry, sizeLimit, false); Assert.Equal(sizeLimit, testData.Count); Assert.True(MemoryMarshal.AsBytes(refData.AsSpan(0, sizeLimit)).SequenceEqual(MemoryMarshal.AsBytes(testData.ToArray().AsSpan()))); // Test overload with external buffer offset = refData.Length / 4; testArray = new T[sizeLimit]; delegate6(entry, offset, testArray, false); Assert.True(MemoryMarshal.AsBytes(refData.AsSpan(offset, sizeLimit)).SequenceEqual(MemoryMarshal.AsBytes(testArray.AsSpan()))); // Test invalid parameter Assert.Throws <ArgumentOutOfRangeException>("offset", () => delegate6(entry, -1, new T[entry.ValueCount], false)); Assert.Throws <ArgumentOutOfRangeException>("offset", () => delegate6(entry, (int)(entry.ValueCount + 1), new T[1], false)); Assert.Throws <ArgumentOutOfRangeException>("destination", () => delegate6(entry, 0, new T[entry.ValueCount + 1], false)); } }
/// <inheritdoc /> public async ValueTask InvokeAsync(TiffImageDecoderContext context, ITiffImageDecoderPipelineNode next) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (next is null) { throw new ArgumentNullException(nameof(next)); } if (context.ContentReader is null) { throw new ArgumentException("ContentReader is not provided in the TiffImageDecoderContext instance."); } if (context.OperationContext is null) { throw new ArgumentException("OperationContext is not provided in the TiffImageDecoderContext instance."); } bool isParallel = !(context.GetService(typeof(TiffParallelDecodingState)) is null); // Initialize the cache TiffFieldReader? reader = null; TiffStrileOffsetCache cache; if (_lazyLoad) { reader = new TiffFieldReader(context.ContentReader, context.OperationContext, leaveOpen: true); cache = new TiffStrileOffsetCache(reader, _stripOffsetsEntry, _stripsByteCountEntry, CacheSize); } else { cache = new TiffStrileOffsetCache(_stripOffsets, _stripsByteCount); } try { int rowsPerStrip = _rowsPerStrip; CancellationToken cancellationToken = context.CancellationToken; // Special case for mailformed file. if (rowsPerStrip <= 0 && _stripCount == 1) { rowsPerStrip = context.SourceImageSize.Height; } // Make sure the region to read is in the image boundary. if (context.SourceReadOffset.X >= context.SourceImageSize.Width || context.SourceReadOffset.Y >= context.SourceImageSize.Height) { return; } context.ReadSize = new TiffSize(Math.Min(context.ReadSize.Width, context.SourceImageSize.Width - context.SourceReadOffset.X), Math.Min(context.ReadSize.Height, context.SourceImageSize.Height - context.SourceReadOffset.Y)); if (context.ReadSize.IsAreaEmpty) { return; } // Create a wrapped context int planeCount = _planeCount; TiffImageEnumeratorDecoderContext? wrapperContext = null; TiffMutableValueCollection <TiffStreamRegion> planarRegions = default; if (!isParallel) { wrapperContext = new TiffImageEnumeratorDecoderContext(context); planarRegions = new TiffMutableValueCollection <TiffStreamRegion>(planeCount); } // loop through all the strips overlapping with the region to read int stripStart = context.SourceReadOffset.Y / rowsPerStrip; int stripEnd = (context.SourceReadOffset.Y + context.ReadSize.Height + rowsPerStrip - 1) / rowsPerStrip; int actualStripCount = _stripCount / _planeCount; for (int stripIndex = stripStart; stripIndex < stripEnd; stripIndex++) { if (isParallel) { wrapperContext = new TiffImageEnumeratorDecoderContext(context); planarRegions = new TiffMutableValueCollection <TiffStreamRegion>(planeCount); } // Calculate size info of this strip int currentYOffset = stripIndex * rowsPerStrip; int stripImageHeight = Math.Min(rowsPerStrip, context.SourceImageSize.Height - currentYOffset); int skippedScanlines = Math.Max(0, context.SourceReadOffset.Y - currentYOffset); int requestedScanlines = Math.Min(stripImageHeight - skippedScanlines, context.SourceReadOffset.Y + context.ReadSize.Height - currentYOffset - skippedScanlines); wrapperContext !.SourceImageSize = new TiffSize(context.SourceImageSize.Width, stripImageHeight); wrapperContext.SourceReadOffset = new TiffPoint(context.SourceReadOffset.X, skippedScanlines); wrapperContext.ReadSize = new TiffSize(context.ReadSize.Width, requestedScanlines); // Update size info of the destination buffer wrapperContext.SetCropSize(new TiffPoint(0, Math.Max(0, currentYOffset - context.SourceReadOffset.Y)), context.ReadSize); // Check to see if there is any region area to be read if (wrapperContext.ReadSize.IsAreaEmpty) { continue; } // Prepare stream regions of this strip for (int planarIndex = 0; planarIndex < planeCount; planarIndex++) { int accessIndex = planarIndex * actualStripCount + stripIndex; planarRegions[planarIndex] = await cache.GetOffsetAndCountAsync(accessIndex, cancellationToken).ConfigureAwait(false); } wrapperContext.PlanarRegions = planarRegions.GetReadOnlyView(); cancellationToken.ThrowIfCancellationRequested(); // Pass down the data await next.RunAsync(wrapperContext).ConfigureAwait(false); } } finally { ((IDisposable)cache).Dispose(); reader?.Dispose(); } }
/// <inheritdoc /> public async ValueTask InvokeAsync(TiffImageDecoderContext context, ITiffImageDecoderPipelineNode next) { if (context is null) { throw new ArgumentNullException(nameof(context)); } if (next is null) { throw new ArgumentNullException(nameof(next)); } if (context.ContentReader is null) { throw new ArgumentException("ContentReader is not provided in the TiffImageDecoderContext instance."); } if (context.OperationContext is null) { throw new ArgumentException("OperationContext is not provided in the TiffImageDecoderContext instance."); } bool isParallel = !(context.GetService(typeof(TiffParallelDecodingState)) is null); // Initialize the cache TiffFieldReader? reader = null; TiffStrileOffsetCache cache; if (_lazyLoad) { reader = new TiffFieldReader(context.ContentReader, context.OperationContext, leaveOpen: true); cache = new TiffStrileOffsetCache(reader, _tileOffsetsEntry, _tileByteCountsEntry, CacheSize); } else { cache = new TiffStrileOffsetCache(_tileOffsets, _tileByteCounts); } int tileWidth = _tileWidth; int tileHeight = _tileHeight; try { int tileAcross = (context.SourceImageSize.Width + tileWidth - 1) / tileWidth; int tileDown = (context.SourceImageSize.Height + tileHeight - 1) / tileHeight; int tileCount = tileAcross * tileDown; CancellationToken cancellationToken = context.CancellationToken; // Make sure the region to read is in the image boundary. if (context.SourceReadOffset.X >= context.SourceImageSize.Width || context.SourceReadOffset.Y >= context.SourceImageSize.Height) { return; } context.ReadSize = new TiffSize(Math.Min(context.ReadSize.Width, context.SourceImageSize.Width - context.SourceReadOffset.X), Math.Min(context.ReadSize.Height, context.SourceImageSize.Height - context.SourceReadOffset.Y)); if (context.ReadSize.IsAreaEmpty) { return; } int planeCount = _planaCount; TiffImageEnumeratorDecoderContext? wrapperContext = null; TiffMutableValueCollection <TiffStreamRegion> planarRegions = default; if (!isParallel) { wrapperContext = new TiffImageEnumeratorDecoderContext(context); planarRegions = new TiffMutableValueCollection <TiffStreamRegion>(planeCount); } // loop through all the tiles overlapping with the region to read. int colStart = context.SourceReadOffset.X / tileWidth; int colEnd = (context.SourceReadOffset.X + context.ReadSize.Width + tileWidth - 1) / tileWidth; int rowStart = context.SourceReadOffset.Y / tileHeight; int rowEnd = (context.SourceReadOffset.Y + context.ReadSize.Height + tileHeight - 1) / tileHeight; for (int row = rowStart; row < rowEnd; row++) { // Calculate coordinates on the y direction for the tiles on this row. int currentYOffset = row * tileHeight; int skippedScanlines = Math.Max(0, context.SourceReadOffset.Y - currentYOffset); int requestedScanlines = Math.Min(tileHeight - skippedScanlines, context.SourceReadOffset.Y + context.ReadSize.Height - currentYOffset - skippedScanlines); for (int col = colStart; col < colEnd; col++) { if (isParallel) { wrapperContext = new TiffImageEnumeratorDecoderContext(context); planarRegions = new TiffMutableValueCollection <TiffStreamRegion>(planeCount); } wrapperContext !.SourceImageSize = new TiffSize(tileWidth, tileHeight); // Calculate coordinates on the y direction for this tile. int currentXOffset = col * tileWidth; int skippedXOffset = Math.Max(0, context.SourceReadOffset.X - currentXOffset); int requestedWidth = Math.Min(tileWidth - skippedXOffset, context.SourceReadOffset.X + context.ReadSize.Width - currentXOffset - skippedXOffset); // Update size info of this tile wrapperContext.SourceReadOffset = new TiffPoint(skippedXOffset, skippedScanlines); wrapperContext.ReadSize = new TiffSize(requestedWidth, requestedScanlines); // Update size info of the destination buffer wrapperContext.SetCropSize(new TiffPoint(Math.Max(0, currentXOffset - context.SourceReadOffset.X), Math.Max(0, currentYOffset - context.SourceReadOffset.Y)), context.ReadSize); // Check to see if there is any region area to be read if (wrapperContext.ReadSize.IsAreaEmpty) { continue; } // Prepare stream regions of this tile for (int planarIndex = 0; planarIndex < planeCount; planarIndex++) { int tileIndex = planarIndex * tileCount + row * tileAcross + col; planarRegions[planarIndex] = await cache.GetOffsetAndCountAsync(tileIndex, cancellationToken).ConfigureAwait(false); } wrapperContext.PlanarRegions = planarRegions.GetReadOnlyView(); cancellationToken.ThrowIfCancellationRequested(); // Pass down the data await next.RunAsync(wrapperContext).ConfigureAwait(false); } } } finally { ((IDisposable)cache).Dispose(); reader?.Dispose(); } }
private static async Task DumpWellKnownTagsAsync(TiffFieldReader fieldReader, TiffImageFileDirectory ifd, CancellationToken cancellationToken) { int count = 0; var tagReader = new TiffTagReader(fieldReader, ifd); if (ifd.Contains(TiffTag.PhotometricInterpretation)) { Console.WriteLine(" PhotometricInterpretation = " + (await tagReader.ReadPhotometricInterpretationAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.SamplesPerPixel)) { Console.WriteLine(" SamplesPerPixel = " + (await tagReader.ReadSamplesPerPixelAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.BitsPerSample)) { Console.Write(" BitsPerSample = "); DumpValueCollecionSimple(await tagReader.ReadBitsPerSampleAsync(cancellationToken)); Console.WriteLine(); count++; } if (ifd.Contains(TiffTag.ImageWidth)) { Console.WriteLine(" ImageWidth = " + (await tagReader.ReadImageWidthAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.ImageLength)) { Console.WriteLine(" ImageLength = " + (await tagReader.ReadImageLengthAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.Compression)) { Console.WriteLine(" Compression = " + (await tagReader.ReadCompressionAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.FillOrder)) { Console.WriteLine(" FillOrder = " + (await tagReader.ReadFillOrderAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.Predictor)) { Console.WriteLine(" Predictor = " + (await tagReader.ReadPredictorAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.Orientation)) { Console.WriteLine(" Orientation = " + (await tagReader.ReadOrientationAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.RowsPerStrip)) { Console.WriteLine(" RowsPerStrip = " + (await tagReader.ReadRowsPerStripAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.TileWidth)) { Console.WriteLine(" TileWidth = " + (await tagReader.ReadTileWidthAsync(cancellationToken))); count++; } if (ifd.Contains(TiffTag.TileLength)) { Console.WriteLine(" TileLength = " + (await tagReader.ReadTileLengthAsync(cancellationToken))); count++; } if (count == 0) { Console.WriteLine(" No well-known tags found."); } }
private static async Task DumpIfdEntryAsync(int index, TiffFieldReader fieldReader, TiffImageFileDirectoryEntry entry, CancellationToken cancellationToken) { string tagName = Enum.IsDefined(typeof(TiffTag), entry.Tag) ? $"{entry.Tag} ({(int)entry.Tag})" : ((int)entry.Tag).ToString(); string typeName = Enum.IsDefined(typeof(TiffFieldType), entry.Type) ? entry.Type.ToString() : "Unknown"; Console.Write($" Tag #{index}: {tagName}, {typeName}[{entry.ValueCount}]."); switch (entry.Type) { case TiffFieldType.Byte: Console.Write(" Binary data not shown."); break; case TiffFieldType.ASCII: TiffValueCollection <string> valuesAscii = await fieldReader.ReadASCIIFieldAsync(entry, skipTypeValidation : true, cancellationToken : cancellationToken); if (valuesAscii.IsEmpty) { // Do nothing } else if (valuesAscii.Count == 1) { Console.Write(" Value = " + valuesAscii.GetFirstOrDefault()); } else { Console.WriteLine(); for (int i = 0; i < valuesAscii.Count; i++) { Console.Write($" [{i}] = {valuesAscii[i]}"); } } break; case TiffFieldType.Short: TiffValueCollection <ushort> valuesShort = await fieldReader.ReadShortFieldAsync(entry, skipTypeValidation : true, cancellationToken : cancellationToken); DumpValueCollecion(valuesShort); break; case TiffFieldType.Long: TiffValueCollection <uint> valuesLong = await fieldReader.ReadLongFieldAsync(entry, skipTypeValidation : true, cancellationToken : cancellationToken); DumpValueCollecion(valuesLong); break; case TiffFieldType.Rational: TiffValueCollection <TiffRational> valuesRational = await fieldReader.ReadRationalFieldAsync(entry, skipTypeValidation : true, cancellationToken : cancellationToken); DumpValueCollecion(valuesRational); break; case TiffFieldType.SByte: Console.Write(" Binary data not shown."); break; case TiffFieldType.Undefined: Console.Write(" Binary data not shown."); break; case TiffFieldType.SShort: TiffValueCollection <short> valuesSShort = await fieldReader.ReadSShortFieldAsync(entry, skipTypeValidation : true, cancellationToken : cancellationToken); DumpValueCollecion(valuesSShort); break; case TiffFieldType.SLong: TiffValueCollection <int> valuesSLong = await fieldReader.ReadSLongFieldAsync(entry, skipTypeValidation : true, cancellationToken : cancellationToken); DumpValueCollecion(valuesSLong); break; case TiffFieldType.SRational: TiffValueCollection <TiffSRational> valuesSRational = await fieldReader.ReadSRationalFieldAsync(entry, skipTypeValidation : true, cancellationToken : cancellationToken); DumpValueCollecion(valuesSRational); break; case TiffFieldType.Float: TiffValueCollection <float> valuesFloat = await fieldReader.ReadFloatFieldAsync(entry, skipTypeValidation : true, cancellationToken : cancellationToken); DumpValueCollecion(valuesFloat); break; case TiffFieldType.Double: TiffValueCollection <double> valuesDouble = await fieldReader.ReadDoubleFieldAsync(entry, skipTypeValidation : true, cancellationToken : cancellationToken); DumpValueCollecion(valuesDouble); break; case TiffFieldType.IFD: TiffValueCollection <TiffStreamOffset> valuesIfd = await fieldReader.ReadIFDFieldAsync(entry, skipTypeValidation : true, cancellationToken : cancellationToken); DumpValueCollecion(valuesIfd); break; case TiffFieldType.Long8: TiffValueCollection <ulong> valuesLong8 = await fieldReader.ReadLong8FieldAsync(entry, skipTypeValidation : true, cancellationToken : cancellationToken); DumpValueCollecion(valuesLong8); break; case TiffFieldType.SLong8: TiffValueCollection <long> valuesSLong8 = await fieldReader.ReadSLong8FieldAsync(entry, skipTypeValidation : true, cancellationToken : cancellationToken); DumpValueCollecion(valuesSLong8); break; case TiffFieldType.IFD8: TiffValueCollection <TiffStreamOffset> valuesIfd8 = await fieldReader.ReadIFD8FieldAsync(entry, skipTypeValidation : true, cancellationToken : cancellationToken); DumpValueCollecion(valuesIfd8); break; default: Console.Write(" Unsupported field type."); break; } Console.WriteLine(); }
private static async Task CopyFieldValueAsync(TiffFieldReader reader, TiffImageFileDirectoryEntry entry, TiffImageFileDirectoryWriter ifdWriter, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); switch (entry.Type) { case TiffFieldType.Byte: await ifdWriter.WriteTagAsync(entry.Tag, await reader.ReadByteFieldAsync(entry)); break; case TiffFieldType.ASCII: await ifdWriter.WriteTagAsync(entry.Tag, await reader.ReadASCIIFieldAsync(entry)); break; case TiffFieldType.Short: await ifdWriter.WriteTagAsync(entry.Tag, await reader.ReadShortFieldAsync(entry)); break; case TiffFieldType.Long: await ifdWriter.WriteTagAsync(entry.Tag, await reader.ReadLongFieldAsync(entry)); break; case TiffFieldType.Rational: await ifdWriter.WriteTagAsync(entry.Tag, await reader.ReadRationalFieldAsync(entry)); break; case TiffFieldType.SByte: await ifdWriter.WriteTagAsync(entry.Tag, entry.Type, await reader.ReadByteFieldAsync(entry)); break; case TiffFieldType.Undefined: await ifdWriter.WriteTagAsync(entry.Tag, entry.Type, await reader.ReadByteFieldAsync(entry)); break; case TiffFieldType.SShort: await ifdWriter.WriteTagAsync(entry.Tag, await reader.ReadSShortFieldAsync(entry)); break; case TiffFieldType.SLong: await ifdWriter.WriteTagAsync(entry.Tag, await reader.ReadSLongFieldAsync(entry)); break; case TiffFieldType.SRational: await ifdWriter.WriteTagAsync(entry.Tag, await reader.ReadSRationalFieldAsync(entry)); break; case TiffFieldType.Float: await ifdWriter.WriteTagAsync(entry.Tag, await reader.ReadFloatFieldAsync(entry)); break; case TiffFieldType.Double: await ifdWriter.WriteTagAsync(entry.Tag, await reader.ReadDoubleFieldAsync(entry)); break; case TiffFieldType.IFD: throw new NotSupportedException("This IFD type is not supported yet."); case TiffFieldType.Long8: await ifdWriter.WriteTagAsync(entry.Tag, await reader.ReadLong8FieldAsync(entry)); break; case TiffFieldType.SLong8: await ifdWriter.WriteTagAsync(entry.Tag, await reader.ReadSLong8FieldAsync(entry)); break; case TiffFieldType.IFD8: throw new NotSupportedException("This IFD type is not supported yet."); default: throw new NotSupportedException($"Unsupported IFD field type: {entry.Type}."); } }