Example #1
0
        /// <summary>
        /// Crops the input image into tiles and runs the next middleware for each tile.
        /// </summary>
        /// <param name="context">The encoder context.</param>
        /// <param name="next">The next middleware.</param>
        /// <returns>A <see cref="Task"/> that completes when the image has been encoded.</returns>
        public async ValueTask InvokeAsync(TiffImageEncoderContext <TPixel> context, ITiffImageEncoderPipelineNode <TPixel> next)
        {
            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (next is null)
            {
                throw new ArgumentNullException(nameof(next));
            }

            var state = context.GetService(typeof(TiffParallelEncodingState)) as TiffParallelEncodingState;
            TiffCroppedImageEncoderContext <TPixel>?wrappedContext = null;

            int width = context.ImageSize.Width, height = context.ImageSize.Height;
            int tileWidth = _tileSize.Width, tileHeight = _tileSize.Height;

            int tileAcross = (width + tileWidth - 1) / tileWidth;
            int tileDown   = (height + tileHeight - 1) / tileHeight;
            int tileCount  = tileAcross * tileDown;

            ulong[] tileOffsets    = new ulong[tileCount];
            ulong[] tileByteCounts = new ulong[tileCount];
            int     index          = 0;

            state?.LockTaskCompletion();

            for (int row = 0; row < tileDown; row++)
            {
                int offsetY     = row * tileHeight;
                int imageHeight = Math.Min(height - offsetY, tileHeight);

                for (int col = 0; col < tileAcross; col++)
                {
                    int offsetX    = col * tileWidth;
                    int imageWidth = Math.Min(width - offsetX, tileWidth);

                    wrappedContext ??= new TiffCroppedImageEncoderContext <TPixel>(context);

                    wrappedContext.ExposeIfdWriter = row == 0 && col == 0;
                    wrappedContext.OutputRegion    = default;
                    wrappedContext.Crop(new TiffPoint(offsetX, offsetY), new TiffSize(imageWidth, imageHeight));

                    if (state is null)
                    {
                        await next.RunAsync(wrappedContext).ConfigureAwait(false);

                        tileOffsets[index]    = (ulong)(long)wrappedContext.OutputRegion.Offset;
                        tileByteCounts[index] = (ulong)wrappedContext.OutputRegion.Length;
                    }
                    else
                    {
                        TiffCroppedImageEncoderContext <TPixel>?wContext = wrappedContext;
                        wrappedContext = null;
                        int currentIndex = index;
                        await state.DispatchAsync(async() =>
                        {
                            await next.RunAsync(wContext).ConfigureAwait(false);
                            tileOffsets[currentIndex]    = (ulong)(long)wContext.OutputRegion.Offset;
                            tileByteCounts[currentIndex] = (ulong)wContext.OutputRegion.Length;
                        }, context.CancellationToken).ConfigureAwait(false);
                    }

                    index++;
                }
            }

            // Wait until all tiles are written.
            if (!(state is null))
            {
                state.ReleaseTaskCompletion();
                await state.Complete.Task.ConfigureAwait(false);
            }

            TiffImageFileDirectoryWriter?ifdWriter = context.IfdWriter;

            if (!(ifdWriter is null))
            {
                using (await context.LockAsync().ConfigureAwait(false))
                {
                    CancellationToken cancellationToken = context.CancellationToken;

                    await ifdWriter.WriteTagAsync(TiffTag.ImageWidth, TiffValueCollection.Single((uint)width), cancellationToken).ConfigureAwait(false);

                    await ifdWriter.WriteTagAsync(TiffTag.ImageLength, TiffValueCollection.Single((uint)height), cancellationToken).ConfigureAwait(false);

                    await ifdWriter.WriteTagAsync(TiffTag.TileWidth, TiffValueCollection.Single((ushort)tileWidth), cancellationToken).ConfigureAwait(false);

                    await ifdWriter.WriteTagAsync(TiffTag.TileLength, TiffValueCollection.Single((ushort)tileHeight), cancellationToken).ConfigureAwait(false);

                    if (context.FileWriter?.UseBigTiff ?? false)
                    {
                        await ifdWriter.WriteTagAsync(TiffTag.TileOffsets, TiffValueCollection.UnsafeWrap(tileOffsets), cancellationToken).ConfigureAwait(false);

                        await ifdWriter.WriteTagAsync(TiffTag.TileByteCounts, TiffValueCollection.UnsafeWrap(tileByteCounts), cancellationToken).ConfigureAwait(false);
                    }
                    else
                    {
                        uint[] tileOffsets32    = new uint[tileCount];
                        uint[] tileByteCounts32 = new uint[tileCount];

                        for (int i = 0; i < tileCount; i++)
                        {
                            tileOffsets32[i]    = (uint)tileOffsets[i];
                            tileByteCounts32[i] = (uint)tileByteCounts[i];
                        }

                        await ifdWriter.WriteTagAsync(TiffTag.TileOffsets, TiffValueCollection.UnsafeWrap(tileOffsets32), cancellationToken).ConfigureAwait(false);

                        await ifdWriter.WriteTagAsync(TiffTag.TileByteCounts, TiffValueCollection.UnsafeWrap(tileByteCounts32), cancellationToken).ConfigureAwait(false);
                    }
                }
            }
        }
Example #2
0
        /// <summary>
        /// Crops the input image into multiple strips and runs the next middleware for each strip.
        /// </summary>
        /// <param name="context">The encoder context.</param>
        /// <param name="next">The next middleware.</param>
        /// <returns>A <see cref="Task"/> that completes when the image has been encoded.</returns>
        public async ValueTask InvokeAsync(TiffImageEncoderContext <TPixel> context, ITiffImageEncoderPipelineNode <TPixel> next)
        {
            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (next is null)
            {
                throw new ArgumentNullException(nameof(next));
            }

            var state = context.GetService(typeof(TiffParallelEncodingState)) as TiffParallelEncodingState;
            TiffCroppedImageEncoderContext <TPixel>?wrappedContext = null;

            int width = context.ImageSize.Width, height = context.ImageSize.Height;
            int rowsPerStrip = _rowsPerStrip <= 0 ? height : _rowsPerStrip;
            int stripCount   = (height + rowsPerStrip - 1) / rowsPerStrip;

            ulong[] stripOffsets    = new ulong[stripCount];
            ulong[] stripByteCounts = new ulong[stripCount];

            state?.LockTaskCompletion();

            for (int i = 0; i < stripCount; i++)
            {
                int offsetY     = i * rowsPerStrip;
                int stripHeight = Math.Min(height - offsetY, rowsPerStrip);

                wrappedContext ??= new TiffCroppedImageEncoderContext <TPixel>(context);

                wrappedContext.ExposeIfdWriter = i == 0;
                wrappedContext.OutputRegion    = default;
                wrappedContext.Crop(new TiffPoint(0, offsetY), new TiffSize(width, stripHeight));

                if (state is null)
                {
                    await next.RunAsync(wrappedContext).ConfigureAwait(false);

                    stripOffsets[i]    = (ulong)(long)wrappedContext.OutputRegion.Offset;
                    stripByteCounts[i] = (ulong)wrappedContext.OutputRegion.Length;
                }
                else
                {
                    TiffCroppedImageEncoderContext <TPixel>?wContext = wrappedContext;
                    wrappedContext = null;
                    int currentIndex = i;
                    await state.DispatchAsync(async() =>
                    {
                        await next.RunAsync(wContext).ConfigureAwait(false);
                        stripOffsets[currentIndex]    = (ulong)(long)wContext.OutputRegion.Offset;
                        stripByteCounts[currentIndex] = (ulong)wContext.OutputRegion.Length;
                    }, context.CancellationToken).ConfigureAwait(false);
                }
            }

            // Wait until all strips are written.
            if (!(state is null))
            {
                state.ReleaseTaskCompletion();
                await state.Complete.Task.ConfigureAwait(false);
            }

            TiffImageFileDirectoryWriter?ifdWriter = context.IfdWriter;

            if (!(ifdWriter is null))
            {
                CancellationToken cancellationToken = context.CancellationToken;

                await ifdWriter.WriteTagAsync(TiffTag.ImageWidth, TiffValueCollection.Single((uint)width), cancellationToken).ConfigureAwait(false);

                await ifdWriter.WriteTagAsync(TiffTag.ImageLength, TiffValueCollection.Single((uint)height), cancellationToken).ConfigureAwait(false);

                await ifdWriter.WriteTagAsync(TiffTag.RowsPerStrip, TiffValueCollection.Single((ushort)rowsPerStrip), cancellationToken).ConfigureAwait(false);

                if (context.FileWriter?.UseBigTiff ?? false)
                {
                    await ifdWriter.WriteTagAsync(TiffTag.StripOffsets, TiffValueCollection.UnsafeWrap(stripOffsets), cancellationToken).ConfigureAwait(false);

                    await ifdWriter.WriteTagAsync(TiffTag.StripByteCounts, TiffValueCollection.UnsafeWrap(stripByteCounts), cancellationToken).ConfigureAwait(false);
                }
                else
                {
                    uint[] stripOffsets32    = new uint[stripCount];
                    uint[] stripByteCounts32 = new uint[stripCount];

                    for (int i = 0; i < stripCount; i++)
                    {
                        stripOffsets32[i]    = (uint)stripOffsets[i];
                        stripByteCounts32[i] = (uint)stripByteCounts[i];
                    }

                    await ifdWriter.WriteTagAsync(TiffTag.StripOffsets, TiffValueCollection.UnsafeWrap(stripOffsets32), cancellationToken).ConfigureAwait(false);

                    await ifdWriter.WriteTagAsync(TiffTag.StripByteCounts, TiffValueCollection.UnsafeWrap(stripByteCounts32), cancellationToken).ConfigureAwait(false);
                }
            }
        }