Пример #1
0
        private static async Task CopyStrippedImageAsync(TiffFileContentReader contentReader, TiffTagReader tagReader, TiffImageFileDirectoryWriter dest, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            TiffValueCollection <ulong> offsets = await tagReader.ReadStripOffsetsAsync(cancellationToken);

            TiffValueCollection <ulong> byteCounts = await tagReader.ReadStripByteCountsAsync(cancellationToken);

            if (offsets.Count != byteCounts.Count)
            {
                throw new InvalidDataException("Failed to copy stripped image data. StripOffsets and StripByteCounts don't have the same amount of elements.");
            }

            uint[] offsets32    = new uint[offsets.Count];
            uint[] byteCounts32 = new uint[offsets.Count];

            byte[]? buffer = null;
            try
            {
                for (int i = 0; i < offsets.Count; i++)
                {
                    int offset    = checked ((int)offsets[i]);
                    int byteCount = checked ((int)byteCounts[i]);
                    byteCounts32[i] = checked ((uint)byteCount);

                    if (buffer is null || byteCount > buffer.Length)
                    {
                        if (!(buffer is null))
                        {
                            ArrayPool <byte> .Shared.Return(buffer);
                        }
                        buffer = ArrayPool <byte> .Shared.Rent(byteCount);
                    }

                    if (await contentReader.ReadAsync(offset, new ArraySegment <byte>(buffer, 0, byteCount), cancellationToken) != byteCount)
                    {
                        throw new InvalidDataException("Invalid ByteCount field.");
                    }

                    TiffStreamOffset region = await dest.FileWriter.WriteAlignedBytesAsync(buffer, 0, byteCount);

                    offsets32[i] = checked ((uint)region.Offset);
                }
            }
            finally
            {
                if (!(buffer is null))
                {
                    ArrayPool <byte> .Shared.Return(buffer);
                }
            }

            await dest.WriteTagAsync(TiffTag.StripOffsets, TiffValueCollection.UnsafeWrap(offsets32));

            await dest.WriteTagAsync(TiffTag.StripByteCounts, TiffValueCollection.UnsafeWrap(byteCounts32));
        }
        public async ValueTask InvokeAsync(TiffImageDecoderContext context, ITiffImageDecoderPipelineNode next)
        {
            MemoryPool <byte>     memoryPool    = context.MemoryPool ?? MemoryPool <byte> .Shared;
            TiffFileContentReader contentReader = context.ContentReader ?? throw new InvalidOperationException();

            IMemoryOwner <byte>?dataHandle = null;
            Memory <byte>       data;

            try
            {
                const int BufferSize = 65536;
                using (var bufferWriter = new MemoryPoolBufferWriter(memoryPool))
                {
                    // Read JPEG stream
                    TiffStreamRegion streamRegion = _streamRegion;
                    do
                    {
                        int           readSize = Math.Min(streamRegion.Length, BufferSize);
                        Memory <byte> memory   = bufferWriter.GetMemory(readSize);
                        memory   = memory.Slice(0, Math.Min(streamRegion.Length, memory.Length));
                        readSize = await contentReader.ReadAsync(streamRegion.Offset, memory, context.CancellationToken).ConfigureAwait(false);

                        bufferWriter.Advance(readSize);
                        streamRegion = new TiffStreamRegion(streamRegion.Offset + readSize, streamRegion.Length - readSize);
                    } while (streamRegion.Length > 0);

                    // Identify the image
                    var decoder = new JpegDecoder();
                    decoder.MemoryPool = memoryPool;
                    decoder.SetInput(bufferWriter.GetReadOnlySequence());
                    decoder.Identify();
                    if (decoder.Width != context.SourceImageSize.Width || decoder.Height != context.SourceImageSize.Height)
                    {
                        throw new InvalidOperationException("The image size does not match.");
                    }
                    if (decoder.Precision != 8)
                    {
                        throw new InvalidOperationException("Only 8-bit JPEG is supported.");
                    }

                    // Adjust buffer size and reading region to reduce buffer size
                    int skippedWidth  = context.SourceReadOffset.X / 8 * 8;
                    int skippedHeight = context.SourceReadOffset.Y / 8 * 8;
                    context.SourceReadOffset = new TiffPoint(context.SourceReadOffset.X % 8, context.SourceReadOffset.Y % 8);
                    int bufferWidth  = context.SourceReadOffset.X + context.ReadSize.Width;
                    int bufferHeight = context.SourceReadOffset.Y + context.ReadSize.Height;
                    context.SourceImageSize = new TiffSize(bufferWidth, bufferHeight);

                    // Allocate buffer and decode image
                    int dataSize = bufferWidth * bufferHeight * decoder.NumberOfComponents;
                    dataHandle = memoryPool.Rent(dataSize);
                    data       = dataHandle.Memory.Slice(0, dataSize);
                    decoder.SetOutputWriter(new LegacyJpegBufferOutputWriter(skippedWidth, bufferWidth, skippedHeight, bufferHeight, decoder.NumberOfComponents, data));
                    decoder.Decode();
                }

                // Pass the buffer to the next middleware
                context.UncompressedData = data;
                await next.RunAsync(context).ConfigureAwait(false);

                context.UncompressedData = null;
            }
            finally
            {
                dataHandle?.Dispose();
            }
        }
        public async Task TestRead(byte[] referenceContent, TiffFileContentSource source)
        {
            var rand = new Random(42);

            try
            {
                TiffFileContentReader reader = await source.OpenReaderAsync();

                // Random read within the range of the file.
                for (int i = 0; i < 100; i++)
                {
                    int offset = rand.Next(0, referenceContent.Length);
                    int count  = 1;
                    if (offset + 1 < referenceContent.Length)
                    {
                        count = rand.Next(1, referenceContent.Length - offset);
                    }

                    await AssertReadAsync(reader, offset, count, count);
                }

                // Read on the edge of the file
                await AssertReadAsync(reader, referenceContent.Length - 2048, 4096, 2048);

                // Read past the end of the file.
                await AssertReadAsync(reader, referenceContent.Length, 4096, 0);
                await AssertReadAsync(reader, referenceContent.Length + 2048, 4096, 0);
            }
            finally
            {
                await source.DisposeAsync();
            }

            async Task AssertReadAsync(TiffFileContentReader reader, int fileOffset, int count, int expectedCount)
            {
                int readCount;

                byte[] buffer = ArrayPool <byte> .Shared.Rent(count);

                try
                {
                    // Use Memory API
                    Array.Clear(buffer, 0, count);
                    readCount = await reader.ReadAsync(fileOffset, new Memory <byte>(buffer, 0, count), CancellationToken.None);

                    Assert.Equal(expectedCount, readCount);
                    Assert.True(buffer.AsSpan(0, readCount).SequenceEqual(referenceContent.AsSpan(Math.Min(referenceContent.Length, fileOffset), expectedCount)));

                    // Use ArraySegment API
                    Array.Clear(buffer, 0, count);
                    readCount = await reader.ReadAsync(fileOffset, new ArraySegment <byte>(buffer, 0, count), CancellationToken.None);

                    Assert.Equal(expectedCount, readCount);
                    Assert.True(buffer.AsSpan(0, readCount).SequenceEqual(referenceContent.AsSpan(Math.Min(referenceContent.Length, fileOffset), expectedCount)));
                }
                finally
                {
                    ArrayPool <byte> .Shared.Return(buffer);
                }
            }
        }