コード例 #1
0
            internal static void FromVector4 <TPixel>(
                Configuration configuration,
                PixelOperations <TPixel> pixelOperations,
                Span <Vector4> sourceVectors,
                Span <TPixel> destPixels,
                PixelConversionModifiers modifiers)
                where TPixel : struct, IPixel <TPixel>
            {
                Guard.NotNull(configuration, nameof(configuration));
                Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels));

                int count = sourceVectors.Length;

                // Not worth for small buffers:
                if (count < Vector4ConversionThreshold)
                {
                    Default.UnsafeFromVector4(sourceVectors, destPixels, modifiers);

                    return;
                }

                // TODO: Investigate optimized 1-pass approach!
                ApplyBackwardConversionModifiers(sourceVectors, modifiers);

                // For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion,
                // so let's allocate a temporary buffer as usually:
                using (IMemoryOwner <Rgba32> tempBuffer = configuration.MemoryAllocator.Allocate <Rgba32>(count))
                {
                    Span <Rgba32> tempSpan = tempBuffer.Memory.Span;

                    SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(
                        MemoryMarshal.Cast <Vector4, float>(sourceVectors),
                        MemoryMarshal.Cast <Rgba32, byte>(tempSpan));

                    pixelOperations.FromRgba32(configuration, tempSpan, destPixels);
                }
            }
コード例 #2
0
 public static bool IsDefined(this PixelConversionModifiers modifiers, PixelConversionModifiers expected) =>
 (modifiers & expected) == expected;
コード例 #3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PixelShaderProcessorBase{TPixel}"/> class.
 /// </summary>
 /// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
 /// <param name="modifiers">The <see cref="PixelConversionModifiers"/> to apply during the pixel conversions.</param>
 /// <param name="source">The source <see cref="Image{TPixel}"/> for the current processor instance.</param>
 /// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
 protected PixelShaderProcessorBase(Configuration configuration, PixelConversionModifiers modifiers, Image <TPixel> source, Rectangle sourceRectangle)
     : base(configuration, source, sourceRectangle)
 {
     this.modifiers = modifiers;
 }
コード例 #4
0
 /// <inheritdoc />
 internal override void ToVector4(Configuration configuration, ReadOnlySpan <Bgr24> sourcePixels, Span <Vector4> destVectors, PixelConversionModifiers modifiers)
 {
     Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply));
 }
コード例 #5
0
 /// <inheritdoc />
 internal override void FromVector4Destructive(Configuration configuration, Span <Vector4> sourceVectors, Span <Bgr24> destPixels, PixelConversionModifiers modifiers)
 {
     Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply));
 }
コード例 #6
0
        internal static void ApplyBackwardConversionModifiers(Span <Vector4> vectors, PixelConversionModifiers modifiers)
        {
            if (modifiers.HasFlag(PixelConversionModifiers.Premultiply))
            {
                Numeric.UnPremultiply(vectors);
            }

            if (modifiers.HasFlag(PixelConversionModifiers.SRgbCompand))
            {
                SRgbCompanding.Compress(vectors);
            }
        }
コード例 #7
0
 /// <summary>
 /// Applies a user defined pixel shader to the image.
 /// </summary>
 /// <param name="source">The image this method extends.</param>
 /// <param name="pixelShader">The user defined pixel shader to use to modify images.</param>
 /// <param name="modifiers">The <see cref="PixelConversionModifiers"/> to apply during the pixel conversions.</param>
 /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
 public static IImageProcessingContext ApplyPixelShaderProcessor(this IImageProcessingContext source, PixelShader pixelShader, PixelConversionModifiers modifiers)
 => source.ApplyProcessor(new PixelShaderProcessor(pixelShader, modifiers));
コード例 #8
0
 /// <inheritdoc />
 public override void ToVector4(Configuration configuration, ReadOnlySpan <Argb32> sourcePixels, Span <Vector4> destVectors, PixelConversionModifiers modifiers)
 {
     Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale));
 }
コード例 #9
0
ファイル: Vector4Converters.cs プロジェクト: wilka/ImageSharp
        internal static void ApplyBackwardConversionModifiers(Span <Vector4> vectors, PixelConversionModifiers modifiers)
        {
            if (modifiers.IsDefined(PixelConversionModifiers.Premultiply))
            {
                Vector4Utilities.UnPremultiply(vectors);
            }

            if (modifiers.IsDefined(PixelConversionModifiers.SRgbCompand))
            {
                SRgbCompanding.Compress(vectors);
            }
        }
コード例 #10
0
 /// <summary>
 /// Applies the union of <see cref="PixelConversionModifiers.Scale"/> and <see cref="PixelConversionModifiers.SRgbCompand"/>,
 /// if <paramref name="compand"/> is true, returns unmodified <paramref name="originalModifiers"/> otherwise.
 /// </summary>
 /// <remarks>
 /// <see cref="PixelConversionModifiers.Scale"/> and <see cref="PixelConversionModifiers.SRgbCompand"/>
 /// should be always used together!
 /// </remarks>
 public static PixelConversionModifiers ApplyCompanding(
     this PixelConversionModifiers originalModifiers,
     bool compand) =>
 compand
         ? originalModifiers | PixelConversionModifiers.Scale | PixelConversionModifiers.SRgbCompand
         : originalModifiers;
コード例 #11
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PixelRowDelegateProcessor"/> class.
 /// </summary>
 /// <param name="pixelRowOperation">The user defined, row processing delegate.</param>
 /// <param name="modifiers">The <see cref="PixelConversionModifiers"/> to apply during the pixel conversions.</param>
 public PixelRowDelegateProcessor(PixelRowOperation pixelRowOperation, PixelConversionModifiers modifiers)
 {
     this.PixelRowOperation = pixelRowOperation;
     this.Modifiers         = modifiers;
 }
コード例 #12
0
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source, ImageFrame <TPixel> destination, Rectangle sourceRectangle, Configuration configuration)
        {
            // Handle resize dimensions identical to the original
            if (source.Width == destination.Width && source.Height == destination.Height && sourceRectangle == this.ResizeRectangle)
            {
                // The cloned will be blank here copy all the pixel data over
                source.GetPixelSpan().CopyTo(destination.GetPixelSpan());
                return;
            }

            int width   = this.Width;
            int height  = this.Height;
            int sourceX = sourceRectangle.X;
            int sourceY = sourceRectangle.Y;
            int startY  = this.ResizeRectangle.Y;
            int endY    = this.ResizeRectangle.Bottom;
            int startX  = this.ResizeRectangle.X;
            int endX    = this.ResizeRectangle.Right;

            int minX = Math.Max(0, startX);
            int maxX = Math.Min(width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(height, endY);

            if (this.Sampler is NearestNeighborResampler)
            {
                var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);

                // Scaling factors
                float widthFactor  = sourceRectangle.Width / (float)this.ResizeRectangle.Width;
                float heightFactor = sourceRectangle.Height / (float)this.ResizeRectangle.Height;

                ParallelHelper.IterateRows(
                    workingRect,
                    configuration,
                    rows =>
                {
                    for (int y = rows.Min; y < rows.Max; y++)
                    {
                        // Y coordinates of source points
                        Span <TPixel> sourceRow =
                            source.GetPixelRowSpan((int)(((y - startY) * heightFactor) + sourceY));
                        Span <TPixel> targetRow = destination.GetPixelRowSpan(y);

                        for (int x = minX; x < maxX; x++)
                        {
                            // X coordinates of source points
                            targetRow[x] = sourceRow[(int)(((x - startX) * widthFactor) + sourceX)];
                        }
                    }
                });

                return;
            }

            int sourceHeight = source.Height;

            PixelConversionModifiers conversionModifiers = PixelConversionModifiers.Premultiply;

            if (this.Compand)
            {
                conversionModifiers |= PixelConversionModifiers.Scale | PixelConversionModifiers.SRgbCompand;
            }

            // Interpolate the image using the calculated weights.
            // A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm
            // First process the columns. Since we are not using multiple threads startY and endY
            // are the upper and lower bounds of the source rectangle.
            using (Buffer2D <Vector4> firstPassPixelsTransposed = source.MemoryAllocator.Allocate2D <Vector4>(sourceHeight, width))
            {
                firstPassPixelsTransposed.MemorySource.Clear();

                var processColsRect = new Rectangle(0, 0, source.Width, sourceRectangle.Bottom);

                ParallelHelper.IterateRowsWithTempBuffer <Vector4>(
                    processColsRect,
                    configuration,
                    (rows, tempRowBuffer) =>
                {
                    for (int y = rows.Min; y < rows.Max; y++)
                    {
                        Span <TPixel> sourceRow    = source.GetPixelRowSpan(y).Slice(sourceX);
                        Span <Vector4> tempRowSpan = tempRowBuffer.Span.Slice(sourceX);

                        PixelOperations <TPixel> .Instance.ToVector4(configuration, sourceRow, tempRowSpan, conversionModifiers);

                        ref Vector4 firstPassBaseRef = ref firstPassPixelsTransposed.Span[y];

                        for (int x = minX; x < maxX; x++)
                        {
                            ResizeKernel kernel = this.horizontalKernelMap.GetKernel(x - startX);
                            Unsafe.Add(ref firstPassBaseRef, x * sourceHeight) = kernel.Convolve(tempRowSpan);
                        }
                    }
                });

                var processRowsRect = Rectangle.FromLTRB(0, minY, width, maxY);

                // Now process the rows.
                ParallelHelper.IterateRowsWithTempBuffer <Vector4>(
                    processRowsRect,
                    configuration,
                    (rows, tempRowBuffer) =>
                {
                    Span <Vector4> tempRowSpan = tempRowBuffer.Span;

                    for (int y = rows.Min; y < rows.Max; y++)
                    {
                        // Ensure offsets are normalized for cropping and padding.
                        ResizeKernel kernel = this.verticalKernelMap.GetKernel(y - startY);

                        ref Vector4 tempRowBase = ref MemoryMarshal.GetReference(tempRowSpan);

                        for (int x = 0; x < width; x++)
                        {
                            Span <Vector4> firstPassColumn = firstPassPixelsTransposed.GetRowSpan(x).Slice(sourceY);

                            // Destination color components
                            Unsafe.Add(ref tempRowBase, x) = kernel.Convolve(firstPassColumn);
                        }

                        Span <TPixel> targetRowSpan = destination.GetPixelRowSpan(y);

                        PixelOperations <TPixel> .Instance.FromVector4Destructive(configuration, tempRowSpan, targetRowSpan, conversionModifiers);
                    }
                });
            }
        }
コード例 #13
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PositionAwarePixelRowDelegateProcessor"/> class.
 /// </summary>
 /// <param name="pixelRowOperation">The user defined, position aware, row processing delegate.</param>
 /// <param name="modifiers">The <see cref="PixelConversionModifiers"/> to apply during the pixel conversions.</param>
 public PositionAwarePixelRowDelegateProcessor(PixelRowOperation <Point> pixelRowOperation, PixelConversionModifiers modifiers)
 {
     this.PixelRowOperation = pixelRowOperation;
     this.Modifiers         = modifiers;
 }
コード例 #14
0
 public static PixelConversionModifiers Remove(
     this PixelConversionModifiers modifiers,
     PixelConversionModifiers removeThis) =>
 modifiers & ~removeThis;
コード例 #15
0
 /// <summary>
 /// Applies a user defined pixel shader to the image.
 /// </summary>
 /// <param name="source">The image this method extends.</param>
 /// <param name="pixelShader">The user defined pixel shader to use to modify images.</param>
 /// <param name="rectangle">
 /// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
 /// </param>
 /// <param name="modifiers">The <see cref="PixelConversionModifiers"/> to apply during the pixel conversions.</param>
 /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
 public static IImageProcessingContext ApplyPixelShaderProcessor(this IImageProcessingContext source, PositionAwarePixelShader pixelShader, Rectangle rectangle, PixelConversionModifiers modifiers)
 => source.ApplyProcessor(new PositionAwarePixelShaderProcessor(pixelShader, modifiers), rectangle);
コード例 #16
0
 /// <inheritdoc />
 public override void FromVector4Destructive(Configuration configuration, Span <Vector4> sourceVectors, Span <Argb32> destinationPixels, PixelConversionModifiers modifiers)
 {
     Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destinationPixels, modifiers.Remove(PixelConversionModifiers.Scale));
 }
コード例 #17
0
 /// <summary>
 /// Applies a user defined processing delegate to the image.
 /// </summary>
 /// <param name="source">The image this method extends.</param>
 /// <param name="rowOperation">The user defined processing delegate to use to modify image rows.</param>
 /// <param name="modifiers">The <see cref="PixelConversionModifiers"/> to apply during the pixel conversions.</param>
 /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
 public static IImageProcessingContext ProcessPixelRowsAsVector4(this IImageProcessingContext source, PixelRowOperation rowOperation, PixelConversionModifiers modifiers)
 => source.ApplyProcessor(new PixelRowDelegateProcessor(rowOperation, modifiers));
コード例 #18
0
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source, ImageFrame <TPixel> destination)
        {
            Rectangle     sourceRectangle = this.SourceRectangle;
            Configuration configuration   = this.Configuration;

            // Handle resize dimensions identical to the original
            if (source.Width == destination.Width && source.Height == destination.Height && sourceRectangle == this.targetRectangle)
            {
                // The cloned will be blank here copy all the pixel data over
                source.GetPixelSpan().CopyTo(destination.GetPixelSpan());
                return;
            }

            int width   = this.targetWidth;
            int height  = this.targetHeight;
            int sourceX = sourceRectangle.X;
            int sourceY = sourceRectangle.Y;
            int startY  = this.targetRectangle.Y;
            int startX  = this.targetRectangle.X;

            var targetWorkingRect = Rectangle.Intersect(
                this.targetRectangle,
                new Rectangle(0, 0, width, height));

            if (this.resampler is NearestNeighborResampler)
            {
                // Scaling factors
                float widthFactor  = sourceRectangle.Width / (float)this.targetRectangle.Width;
                float heightFactor = sourceRectangle.Height / (float)this.targetRectangle.Height;

                ParallelHelper.IterateRows(
                    targetWorkingRect,
                    configuration,
                    rows =>
                {
                    for (int y = rows.Min; y < rows.Max; y++)
                    {
                        // Y coordinates of source points
                        Span <TPixel> sourceRow = source.GetPixelRowSpan((int)(((y - startY) * heightFactor) + sourceY));
                        Span <TPixel> targetRow = destination.GetPixelRowSpan(y);

                        for (int x = targetWorkingRect.Left; x < targetWorkingRect.Right; x++)
                        {
                            // X coordinates of source points
                            targetRow[x] = sourceRow[(int)(((x - startX) * widthFactor) + sourceX)];
                        }
                    }
                });

                return;
            }

            PixelConversionModifiers conversionModifiers =
                PixelConversionModifiers.Premultiply.ApplyCompanding(this.compand);

            BufferArea <TPixel> sourceArea = source.PixelBuffer.GetArea(sourceRectangle);

            // To reintroduce parallel processing, we to launch multiple workers
            // for different row intervals of the image.
            using (var worker = new ResizeWorker <TPixel>(
                       configuration,
                       sourceArea,
                       conversionModifiers,
                       this.horizontalKernelMap,
                       this.verticalKernelMap,
                       width,
                       targetWorkingRect,
                       this.targetRectangle.Location))
            {
                worker.Initialize();

                var workingInterval = new RowInterval(targetWorkingRect.Top, targetWorkingRect.Bottom);
                worker.FillDestinationPixels(workingInterval, destination.PixelBuffer);
            }
        }
コード例 #19
0
 /// <summary>
 /// Applies a user defined processing delegate to the image.
 /// </summary>
 /// <param name="source">The image this method extends.</param>
 /// <param name="rowOperation">The user defined processing delegate to use to modify image rows.</param>
 /// <param name="rectangle">
 /// The <see cref="Rectangle"/> structure that specifies the portion of the image object to alter.
 /// </param>
 /// <param name="modifiers">The <see cref="PixelConversionModifiers"/> to apply during the pixel conversions.</param>
 /// <returns>The <see cref="IImageProcessingContext"/> to allow chaining of operations.</returns>
 public static IImageProcessingContext ProcessPixelRowsAsVector4(this IImageProcessingContext source, PixelRowOperation <Point> rowOperation, Rectangle rectangle, PixelConversionModifiers modifiers)
 => source.ApplyProcessor(new PositionAwarePixelRowDelegateProcessor(rowOperation, modifiers), rectangle);
コード例 #20
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PixelRowDelegateProcessorBase{TPixel}"/> class.
 /// </summary>
 /// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
 /// <param name="modifiers">The <see cref="PixelConversionModifiers"/> to apply during the pixel conversions.</param>
 /// <param name="source">The source <see cref="Image{TPixel}"/> for the current processor instance.</param>
 /// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
 protected PixelRowDelegateProcessorBase(Configuration configuration, PixelConversionModifiers modifiers, Image <TPixel> source, Rectangle sourceRectangle)
     : base(configuration, source, sourceRectangle)
     => this.modifiers = modifiers;
コード例 #21
0
 /// <summary>
 /// Initializes a new instance of the <see cref="PositionAwarePixelShaderProcessor"/> class.
 /// </summary>
 /// <param name="pixelShader">
 /// The user defined pixel shader to use to modify images.
 /// </param>
 /// <param name="modifiers">The <see cref="PixelConversionModifiers"/> to apply during the pixel conversions.</param>
 public PositionAwarePixelShaderProcessor(PositionAwarePixelShader pixelShader, PixelConversionModifiers modifiers)
 {
     this.PixelShader = pixelShader;
     this.Modifiers   = modifiers;
 }