Example #1
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class.
 /// </summary>
 /// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
 /// <param name="source">The source.</param>
 internal ImageFrame(MemoryManager memoryManager, ImageFrame <TPixel> source)
 {
     this.MemoryManager = memoryManager;
     this.PixelBuffer   = memoryManager.Allocate2D <TPixel>(source.PixelBuffer.Width, source.PixelBuffer.Height);
     source.PixelBuffer.Span.CopyTo(this.PixelBuffer.Span);
     this.MetaData = source.MetaData.Clone();
 }
Example #2
0
        /// <summary>
        /// Initializes <see cref="SpectralBlocks"/>
        /// </summary>
        /// <param name="memoryManager">The <see cref="MemoryManager"/> to use for buffer allocations.</param>
        /// <param name="decoder">The <see cref="OrigJpegDecoderCore"/> instance</param>
        public void InitializeDerivedData(MemoryManager memoryManager, OrigJpegDecoderCore decoder)
        {
            // For 4-component images (either CMYK or YCbCrK), we only support two
            // hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22].
            // Theoretically, 4-component JPEG images could mix and match hv values
            // but in practice, those two combinations are the only ones in use,
            // and it simplifies the applyBlack code below if we can assume that:
            // - for CMYK, the C and K channels have full samples, and if the M
            // and Y channels subsample, they subsample both horizontally and
            // vertically.
            // - for YCbCrK, the Y and K channels have full samples.
            this.SizeInBlocks = decoder.ImageSizeInMCU.MultiplyBy(this.SamplingFactors);

            if (this.Index == 0 || this.Index == 3)
            {
                this.SubSamplingDivisors = new Size(1, 1);
            }
            else
            {
                OrigComponent c0 = decoder.Components[0];
                this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors);
            }

            this.SpectralBlocks = memoryManager.Allocate2D <Block8x8>(this.SizeInBlocks.Width, this.SizeInBlocks.Height, true);
        }
        /// <summary>
        /// TODO: This should be a common processing method! The image.Opacity(val) multiplies the alpha channel!
        /// </summary>
        /// <typeparam name="TPixel"></typeparam>
        /// <param name="ctx"></param>
        public static void MakeOpaque <TPixel>(this IImageProcessingContext <TPixel> ctx)
            where TPixel : struct, IPixel <TPixel>
        {
            MemoryManager memoryManager = ctx.MemoryManager;

            ctx.Apply(img =>
            {
                using (Buffer2D <Vector4> temp = memoryManager.Allocate2D <Vector4>(img.Width, img.Height))
                {
                    Span <Vector4> tempSpan = temp.Span;
                    foreach (ImageFrame <TPixel> frame in img.Frames)
                    {
                        Span <TPixel> pixelSpan = frame.GetPixelSpan();

                        PixelOperations <TPixel> .Instance.ToVector4(pixelSpan, tempSpan, pixelSpan.Length);

                        for (int i = 0; i < tempSpan.Length; i++)
                        {
                            ref Vector4 v = ref tempSpan[i];
                            v.W           = 1.0f;
                        }

                        PixelOperations <TPixel> .Instance.PackFromVector4(tempSpan, pixelSpan, pixelSpan.Length);
                    }
                }
            });
        /// <summary>
        /// Initializes a new instance of the <see cref="JpegComponentPostProcessor"/> class.
        /// </summary>
        public JpegComponentPostProcessor(MemoryManager memoryManager, JpegImagePostProcessor imagePostProcessor, IJpegComponent component)
        {
            this.Component          = component;
            this.ImagePostProcessor = imagePostProcessor;
            this.ColorBuffer        = memoryManager.Allocate2D <float>(
                imagePostProcessor.PostProcessorBufferSize.Width,
                imagePostProcessor.PostProcessorBufferSize.Height);

            this.BlockRowsPerStep = JpegImagePostProcessor.BlockRowsPerStep / this.Component.SubSamplingDivisors.Height;
            this.blockAreaSize    = this.Component.SubSamplingDivisors * 8;
        }
Example #5
0
 /// <summary>
 /// Initializes a new instance of the <see cref="WeightsBuffer"/> class.
 /// </summary>
 /// <param name="memoryManager">The MemoryManager to use for allocations.</param>
 /// <param name="sourceSize">The size of the source window</param>
 /// <param name="destinationSize">The size of the destination window</param>
 public WeightsBuffer(MemoryManager memoryManager, int sourceSize, int destinationSize)
 {
     this.dataBuffer = memoryManager.Allocate2D <float>(sourceSize, destinationSize, true);
     this.Weights    = new WeightsWindow[destinationSize];
 }
        /// <inheritdoc/>
        protected override void OnFrameApply(
            ImageFrame <TPixel> source,
            ImageFrame <TPixel> destination,
            Rectangle sourceRectangle,
            Configuration configuration)
        {
            int height = this.TargetDimensions.Height;
            int width  = this.TargetDimensions.Width;

            Rectangle sourceBounds = source.Bounds();
            var       targetBounds = new Rectangle(0, 0, width, height);

            // Since could potentially be resizing the canvas we might need to re-calculate the matrix
            Matrix3x2 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds);

            // Convert from screen to world space.
            Matrix3x2.Invert(matrix, out matrix);

            if (this.Sampler is NearestNeighborResampler)
            {
                Parallel.For(
                    0,
                    height,
                    configuration.ParallelOptions,
                    y =>
                {
                    Span <TPixel> destRow = destination.GetPixelRowSpan(y);

                    for (int x = 0; x < width; x++)
                    {
                        var point = Point.Transform(new Point(x, y), matrix);
                        if (sourceBounds.Contains(point.X, point.Y))
                        {
                            destRow[x] = source[point.X, point.Y];
                        }
                    }
                });

                return;
            }

            int maxSourceX = source.Width - 1;
            int maxSourceY = source.Height - 1;

            (float radius, float scale, float ratio)xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width);
            (float radius, float scale, float ratio)yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height);
            float      xScale    = xRadiusScale.scale;
            float      yScale    = yRadiusScale.scale;
            var        radius    = new Vector2(xRadiusScale.radius, yRadiusScale.radius);
            IResampler sampler   = this.Sampler;
            var        maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY);
            int        xLength   = (int)MathF.Ceiling((radius.X * 2) + 2);
            int        yLength   = (int)MathF.Ceiling((radius.Y * 2) + 2);

            MemoryManager memoryManager = configuration.MemoryManager;

            using (Buffer2D <float> yBuffer = memoryManager.Allocate2D <float>(yLength, height))
                using (Buffer2D <float> xBuffer = memoryManager.Allocate2D <float>(xLength, height))
                {
                    Parallel.For(
                        0,
                        height,
                        configuration.ParallelOptions,
                        y =>
                    {
                        ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y));
                        ref float ySpanRef    = ref MemoryMarshal.GetReference(yBuffer.GetRowSpan(y));
                        ref float xSpanRef    = ref MemoryMarshal.GetReference(xBuffer.GetRowSpan(y));
Example #7
0
 public PdfJsQuantizationTables(MemoryManager memoryManager)
 {
     this.Tables = memoryManager.Allocate2D <short>(64, 4);
 }
Example #8
0
        /// <inheritdoc/>
        protected override void OnApply(ImageFrame <TPixel> source, ImageFrame <TPixel> destination, Rectangle sourceRectangle, Configuration configuration)
        {
            int height = this.TargetDimensions.Height;
            int width  = this.TargetDimensions.Width;

            Rectangle sourceBounds = source.Bounds();
            var       targetBounds = new Rectangle(0, 0, width, height);

            // Since could potentially be resizing the canvas we might need to re-calculate the matrix
            Matrix4x4 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds);

            // Convert from screen to world space.
            Matrix4x4.Invert(matrix, out matrix);

            if (this.Sampler is NearestNeighborResampler)
            {
                Parallel.For(
                    0,
                    height,
                    configuration.ParallelOptions,
                    y =>
                {
                    Span <TPixel> destRow = destination.GetPixelRowSpan(y);

                    for (int x = 0; x < width; x++)
                    {
                        var point = Point.Round(Vector2.Transform(new Vector2(x, y), matrix));
                        if (sourceBounds.Contains(point.X, point.Y))
                        {
                            destRow[x] = source[point.X, point.Y];
                        }
                    }
                });

                return;
            }

            int maxSourceX = source.Width - 1;
            int maxSourceY = source.Height - 1;

            (float radius, float scale, float ratio)xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width);
            (float radius, float scale, float ratio)yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height);
            float      xScale    = xRadiusScale.scale;
            float      yScale    = yRadiusScale.scale;
            var        radius    = new Vector2(xRadiusScale.radius, yRadiusScale.radius);
            IResampler sampler   = this.Sampler;
            var        maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY);
            int        xLength   = (int)MathF.Ceiling((radius.X * 2) + 2);
            int        yLength   = (int)MathF.Ceiling((radius.Y * 2) + 2);

            MemoryManager memoryManager = configuration.MemoryManager;

            using (Buffer2D <float> yBuffer = memoryManager.Allocate2D <float>(yLength, height))
                using (Buffer2D <float> xBuffer = memoryManager.Allocate2D <float>(xLength, height))
                {
                    Parallel.For(
                        0,
                        height,
                        configuration.ParallelOptions,
                        y =>
                    {
                        Span <TPixel> destRow = destination.GetPixelRowSpan(y);
                        Span <float> ySpan    = yBuffer.GetRowSpan(y);
                        Span <float> xSpan    = xBuffer.GetRowSpan(y);

                        for (int x = 0; x < width; x++)
                        {
                            // Use the single precision position to calculate correct bounding pixels
                            // otherwise we get rogue pixels outside of the bounds.
                            var point = Vector2.Transform(new Vector2(x, y), matrix);

                            // Clamp sampling pixel radial extents to the source image edges
                            Vector2 maxXY = point + radius;
                            Vector2 minXY = point - radius;

                            // max, maxY, minX, minY
                            var extents = new Vector4(
                                MathF.Floor(maxXY.X + .5F),
                                MathF.Floor(maxXY.Y + .5F),
                                MathF.Ceiling(minXY.X - .5F),
                                MathF.Ceiling(minXY.Y - .5F));

                            int right  = (int)extents.X;
                            int bottom = (int)extents.Y;
                            int left   = (int)extents.Z;
                            int top    = (int)extents.W;

                            extents = Vector4.Clamp(extents, Vector4.Zero, maxSource);

                            int maxX = (int)extents.X;
                            int maxY = (int)extents.Y;
                            int minX = (int)extents.Z;
                            int minY = (int)extents.W;

                            if (minX == maxX || minY == maxY)
                            {
                                continue;
                            }

                            // It appears these have to be calculated on-the-fly.
                            // Precalulating transformed weights would require prior knowledge of every transformed pixel location
                            // since they can be at sub-pixel positions on both axis.
                            // I've optimized where I can but am always open to suggestions.
                            if (yScale > 1 && xScale > 1)
                            {
                                CalculateWeightsDown(top, bottom, minY, maxY, point.Y, sampler, yScale, ySpan);
                                CalculateWeightsDown(left, right, minX, maxX, point.X, sampler, xScale, xSpan);
                            }
                            else
                            {
                                CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ySpan);
                                CalculateWeightsScaleUp(minX, maxX, point.X, sampler, xSpan);
                            }

                            // Now multiply the results against the offsets
                            Vector4 sum = Vector4.Zero;
                            for (int yy = 0, j = minY; j <= maxY; j++, yy++)
                            {
                                float yWeight = ySpan[yy];

                                for (int xx = 0, i = minX; i <= maxX; i++, xx++)
                                {
                                    float xWeight = xSpan[xx];
                                    var vector    = source[i, j].ToVector4();

                                    // Values are first premultiplied to prevent darkening of edge pixels
                                    Vector4 multiplied = vector.Premultiply();
                                    sum += multiplied * xWeight * yWeight;
                                }
                            }

                            ref TPixel dest = ref destRow[x];

                            // Reverse the premultiplication
                            dest.PackFromVector4(sum.UnPremultiply());
                        }
                    });
                }
        }