예제 #1
0
        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);
                }
            }
        }
예제 #2
0
        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));
        }
예제 #3
0
        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);
            }
        }
예제 #4
0
        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);
        }
예제 #5
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;
        }
예제 #6
0
        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)));
            }
        }
예제 #7
0
        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);
        }
예제 #8
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();
            }
        }
예제 #10
0
        /// <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();
            }
        }
예제 #11
0
        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.");
            }
        }
예제 #12
0
        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();
        }
예제 #13
0
        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}.");
            }
        }