示例#1
0
        /// <inheritdoc/>
        protected override void Apply(ImageBase <T, TP> target, ImageBase <T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
        {
            // Jump out, we'll deal with that later.
            if (source.Bounds == target.Bounds)
            {
                return;
            }

            int targetY      = this.cropRectangle.Y;
            int targetBottom = this.cropRectangle.Bottom;
            int startX       = this.cropRectangle.X;
            int endX         = this.cropRectangle.Right;

            int minY = Math.Max(targetY, startY);
            int maxY = Math.Min(targetBottom, endY);

            using (IPixelAccessor <T, TP> sourcePixels = source.Lock())
                using (IPixelAccessor <T, TP> targetPixels = target.Lock())
                {
                    Parallel.For(
                        minY,
                        maxY,
                        this.ParallelOptions,
                        y =>
                    {
                        for (int x = startX; x < endX; x++)
                        {
                            targetPixels[x - startX, y - targetY] = sourcePixels[x, y];
                        }

                        this.OnRowProcessed();
                    });
                }
        }
示例#2
0
        /// <summary>
        /// Swaps the image at the Y-axis, which goes vertically through the middle
        /// at half of the width of the image.
        /// </summary>
        /// <param name="target">Target image to apply the process to.</param>
        private void FlipY(ImageBase <T, TP> target)
        {
            int           width     = target.Width;
            int           height    = target.Height;
            int           halfWidth = (int)Math.Ceiling(width * .5F);
            Image <T, TP> temp      = new Image <T, TP>(width, height);

            temp.ClonePixels(width, height, target.Pixels);

            using (IPixelAccessor <T, TP> targetPixels = target.Lock())
                using (IPixelAccessor <T, TP> tempPixels = temp.Lock())
                {
                    Parallel.For(
                        0,
                        height,
                        this.ParallelOptions,
                        y =>
                    {
                        for (int x = 0; x < halfWidth; x++)
                        {
                            int newX              = width - x - 1;
                            targetPixels[x, y]    = tempPixels[newX, y];
                            targetPixels[newX, y] = tempPixels[x, y];
                        }

                        this.OnRowProcessed();
                    });
                }
        }
示例#3
0
        /// <summary>
        /// Collects the true color pixel data.
        /// </summary>
        /// <typeparam name="T">The pixel format.</typeparam>
        /// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
        /// <param name="image">The image to encode.</param>
        private void CollectColorBytes <T, TP>(ImageBase <T, TP> image)
            where T : IPackedVector <TP>
            where TP : struct
        {
            // Copy the pixels across from the image.
            this.pixelData = new byte[this.width * this.height * this.bytesPerPixel];
            int stride = this.width * this.bytesPerPixel;

            using (IPixelAccessor <T, TP> pixels = image.Lock())
            {
                Parallel.For(
                    0,
                    this.height,
                    Bootstrapper.Instance.ParallelOptions,
                    y =>
                {
                    // Color data is stored in r -> g -> b -> a order
                    for (int x = 0; x < this.width; x++)
                    {
                        int dataOffset = (y * stride) + (x * this.bytesPerPixel);
                        byte[] source  = pixels[x, y].ToBytes();

                        for (int i = 0; i < this.bytesPerPixel; i++)
                        {
                            this.pixelData[dataOffset + i] = source[i];
                        }
                    }
                });
            }
        }
示例#4
0
        /// <summary>
        /// Rotates the image 90 degrees clockwise at the centre point.
        /// </summary>
        /// <param name="target">The target image.</param>
        /// <param name="source">The source image.</param>
        private void Rotate90(ImageBase <T, TP> target, ImageBase <T, TP> source)
        {
            int           width  = source.Width;
            int           height = source.Height;
            Image <T, TP> temp   = new Image <T, TP>(height, width);

            using (IPixelAccessor <T, TP> sourcePixels = source.Lock())
                using (IPixelAccessor <T, TP> tempPixels = temp.Lock())
                {
                    Parallel.For(
                        0,
                        height,
                        this.ParallelOptions,
                        y =>
                    {
                        for (int x = 0; x < width; x++)
                        {
                            int newX            = height - y - 1;
                            tempPixels[newX, x] = sourcePixels[x, y];
                        }

                        this.OnRowProcessed();
                    });
                }

            target.SetPixels(height, width, temp.Pixels);
        }
示例#5
0
        /// <inheritdoc/>
        protected override void Apply(ImageBase <T, TP> target, ImageBase <T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
        {
            if (OptimizedApply(target, source))
            {
                return;
            }

            int       height = target.Height;
            int       width  = target.Width;
            Matrix3x2 matrix = GetCenteredMatrix(target, source, this.processMatrix);

            using (IPixelAccessor <T, TP> sourcePixels = source.Lock())
                using (IPixelAccessor <T, TP> targetPixels = target.Lock())
                {
                    Parallel.For(
                        0,
                        height,
                        this.ParallelOptions,
                        y =>
                    {
                        for (int x = 0; x < width; x++)
                        {
                            Point transformedPoint = Point.Rotate(new Point(x, y), matrix);
                            if (source.Bounds.Contains(transformedPoint.X, transformedPoint.Y))
                            {
                                targetPixels[x, y] = sourcePixels[transformedPoint.X, transformedPoint.Y];
                            }
                        }

                        this.OnRowProcessed();
                    });
                }
        }
示例#6
0
        /// <summary>
        /// Builds a 3-D color histogram of <c>counts, r/g/b, c^2</c>.
        /// </summary>
        /// <param name="pixels">The pixel accessor.</param>
        private void Build3DHistogram(IPixelAccessor <T, TP> pixels)
        {
            for (int y = 0; y < pixels.Height; y++)
            {
                for (int x = 0; x < pixels.Width; x++)
                {
                    // Colors are expected in r->g->b->a format
                    byte[] color = pixels[x, y].ToBytes();

                    byte r = color[0];
                    byte g = color[1];
                    byte b = color[2];
                    byte a = color[3];

                    int inr = r >> (8 - IndexBits);
                    int ing = g >> (8 - IndexBits);
                    int inb = b >> (8 - IndexBits);
                    int ina = a >> (8 - IndexAlphaBits);

                    int ind = GetPaletteIndex(inr + 1, ing + 1, inb + 1, ina + 1);

                    this.vwt[ind]++;
                    this.vmr[ind] += r;
                    this.vmg[ind] += g;
                    this.vmb[ind] += b;
                    this.vma[ind] += a;
                    this.m2[ind]  += (r * r) + (g * g) + (b * b) + (a * a);
                }
            }
        }
示例#7
0
        /// <summary>
        /// Rotates the image 180 degrees clockwise at the centre point.
        /// </summary>
        /// <param name="target">The target image.</param>
        /// <param name="source">The source image.</param>
        private void Rotate180(ImageBase <T, TP> target, ImageBase <T, TP> source)
        {
            int width  = source.Width;
            int height = source.Height;

            using (IPixelAccessor <T, TP> sourcePixels = source.Lock())
                using (IPixelAccessor <T, TP> targetPixels = target.Lock())
                {
                    Parallel.For(
                        0,
                        height,
                        this.ParallelOptions,
                        y =>
                    {
                        for (int x = 0; x < width; x++)
                        {
                            int newX = width - x - 1;
                            int newY = height - y - 1;
                            targetPixels[newX, newY] = sourcePixels[x, y];
                        }

                        this.OnRowProcessed();
                    });
                }
        }
示例#8
0
        /// <inheritdoc/>
        protected override void Apply(ImageBase <T, TP> target, ImageBase <T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
        {
            int startX  = targetRectangle.X;
            int endX    = targetRectangle.Right;
            int sourceX = sourceRectangle.X;
            int sourceY = sourceRectangle.Y;

            using (IPixelAccessor <T, TP> sourcePixels = source.Lock())
                using (IPixelAccessor <T, TP> targetPixels = target.Lock())
                {
                    Parallel.For(
                        startY,
                        endY,
                        this.ParallelOptions,
                        y =>
                    {
                        for (int x = startX; x < endX; x++)
                        {
                            targetPixels[x, y] = sourcePixels[x + sourceX, y + sourceY];
                        }

                        this.OnRowProcessed();
                    });
                }
        }
示例#9
0
 private void Build3DHistogram(IPixelAccessor pixels)
 {
     for (int y = 0; y < pixels.Height; y++)
     {
         for (int x = 0; x < pixels.Width; x++)
         {
             byte[] color = pixels[x, y].ToBytes();
             byte   r     = color[0];
             byte   g     = color[1];
             byte   b     = color[2];
             byte   a     = color[3];
             int    inr   = r >> (8 - IndexBits);
             int    ing   = g >> (8 - IndexBits);
             int    inb   = b >> (8 - IndexBits);
             int    ina   = a >> (8 - IndexAlphaBits);
             int    ind   = GetPaletteIndex(inr + 1, ing + 1, inb + 1, ina + 1);
             vwt[ind]++;
             vmr[ind] += r;
             vmg[ind] += g;
             vmb[ind] += b;
             vma[ind] += a;
             m2[ind]  += (r * r) + (g * g) + (b * b) + (a * a);
         }
     }
 }
示例#10
0
        /// <inheritdoc/>
        public virtual QuantizedImage <T, TP> Quantize(ImageBase <T, TP> image, int maxColors)
        {
            Guard.NotNull(image, nameof(image));

            // Get the size of the source image
            int height = image.Height;
            int width  = image.Width;

            byte[]   quantizedPixels = new byte[width * height];
            List <T> palette;

            using (IPixelAccessor <T, TP> pixels = image.Lock())
            {
                // Call the FirstPass function if not a single pass algorithm.
                // For something like an Octree quantizer, this will run through
                // all image pixels, build a data structure, and create a palette.
                if (!this.singlePass)
                {
                    this.FirstPass(pixels, width, height);
                }

                // Get the palette
                palette = this.GetPalette();

                this.SecondPass(pixels, quantizedPixels, width, height);
            }

            return(new QuantizedImage <T, TP>(width, height, palette.ToArray(), quantizedPixels, this.TransparentIndex));
        }
示例#11
0
 private void Encode420(IPixelAccessor pixels)
 {
     Block b = new Block();
     Block[] cb = new Block[4];
     Block[] cr = new Block[4];
     int prevDcy = 0, prevDcCb = 0, prevDcCr = 0;
     for (int i = 0; i < 4; i++){
         cb[i] = new Block();
     }
     for (int i = 0; i < 4; i++){
         cr[i] = new Block();
     }
     for (int y = 0; y < pixels.Height; y += 16){
         for (int x = 0; x < pixels.Width; x += 16){
             for (int i = 0; i < 4; i++){
                 int xOff = (i & 1)*8;
                 int yOff = (i & 2)*4;
                 ToYCbCr(pixels, x + xOff, y + yOff, b, cb[i], cr[i]);
                 prevDcy = WriteBlock(b, QuantIndex.Luminance, prevDcy);
             }
             Scale16X16_8X8(b, cb);
             prevDcCb = WriteBlock(b, QuantIndex.Chrominance, prevDcCb);
             Scale16X16_8X8(b, cr);
             prevDcCr = WriteBlock(b, QuantIndex.Chrominance, prevDcCr);
         }
     }
 }
示例#12
0
        /// <inheritdoc/>
        protected override void Apply(ImageBase <T, TP> target, ImageBase <T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
        {
            int startX = sourceRectangle.X;
            int endX   = sourceRectangle.Right;

            // Align start/end positions.
            int minX = Math.Max(0, startX);
            int maxX = Math.Min(source.Width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(source.Height, endY);

            // Reset offset if necessary.
            if (minX > 0)
            {
                startX = 0;
            }

            if (minY > 0)
            {
                startY = 0;
            }

            Vector4 backgroundColor = this.Value.ToVector4();

            using (IPixelAccessor <T, TP> sourcePixels = source.Lock())
                using (IPixelAccessor <T, TP> targetPixels = target.Lock())
                {
                    Parallel.For(
                        minY,
                        maxY,
                        this.ParallelOptions,
                        y =>
                    {
                        int offsetY = y - startY;
                        for (int x = minX; x < maxX; x++)
                        {
                            int offsetX   = x - startX;
                            Vector4 color = sourcePixels[offsetX, offsetY].ToVector4();
                            float a       = color.W;

                            if (a < 1 && a > 0)
                            {
                                color = Vector4.Lerp(color, backgroundColor, .5F);
                            }

                            if (Math.Abs(a) < Epsilon)
                            {
                                color = backgroundColor;
                            }

                            T packed = default(T);
                            packed.PackFromVector4(color);
                            targetPixels[offsetX, offsetY] = packed;
                        }

                        this.OnRowProcessed();
                    });
                }
        }
示例#13
0
 public void Encode(ImageBase image, Stream stream, int quality, JpegSubsample sample)
 {
     if (image == null || stream == null){
         throw new ArgumentNullException();
     }
     ushort max = JpegConstants.MaxLength;
     if (image.Width >= max || image.Height >= max){
         throw new Exception($"Image is too large to encode at {image.Width}x{image.Height}.");
     }
     outputStream = stream;
     subsample = sample;
     for (int i = 0; i < theHuffmanSpec.Length; i++){
         theHuffmanLut[i] = new HuffmanLut(theHuffmanSpec[i]);
     }
     for (int i = 0; i < nQuantIndex; i++){
         quant[i] = new byte[Block.blockSize];
     }
     if (quality < 1){
         quality = 1;
     }
     if (quality > 100){
         quality = 100;
     }
     int scale;
     if (quality < 50){
         scale = 5000/quality;
     } else{
         scale = 200 - quality*2;
     }
     for (int i = 0; i < nQuantIndex; i++){
         for (int j = 0; j < Block.blockSize; j++){
             int x = unscaledQuant[i, j];
             x = (x*scale + 50)/100;
             if (x < 1){
                 x = 1;
             }
             if (x > 255){
                 x = 255;
             }
             quant[i][j] = (byte) x;
         }
     }
     int componentCount = 3;
     double densityX = ((Image2) image).HorizontalResolution;
     double densityY = ((Image2) image).VerticalResolution;
     WriteApplicationHeader((short) densityX, (short) densityY);
     WriteDqt();
     WriteSof0(image.Width, image.Height, componentCount);
     WriteDht(componentCount);
     using (IPixelAccessor pixels = image.Lock()){
         WriteSos(pixels);
     }
     buffer[0] = 0xff;
     buffer[1] = 0xd9;
     stream.Write(buffer, 0, 2);
     stream.Flush();
 }
示例#14
0
 protected virtual void FirstPass(IPixelAccessor source, int width, int height)
 {
     for (int y = 0; y < height; y++)
     {
         for (int x = 0; x < width; x++)
         {
             InitialQuantizePixel(source[x, y]);
         }
     }
 }
示例#15
0
 protected virtual void SecondPass(IPixelAccessor source, byte[] output, int width, int height)
 {
     Parallel.For(0, source.Height, Bootstrapper.instance.ParallelOptions, y => {
         for (int x = 0; x < source.Width; x++)
         {
             Color2 sourcePixel           = source[x, y];
             output[y * source.Width + x] = QuantizePixel(sourcePixel);
         }
     });
 }
示例#16
0
        /// <summary>
        /// Applies the process to the specified portion of the specified <see cref="ImageBase{T,TP}"/> at the specified location
        /// and with the specified size.
        /// </summary>
        /// <param name="target">Target image to apply the process to.</param>
        /// <param name="source">The source image. Cannot be null.</param>
        /// <param name="sourceRectangle">
        /// The <see cref="Rectangle"/> structure that specifies the portion of the image object to draw.
        /// </param>
        /// <param name="startY">The index of the row within the source image to start processing.</param>
        /// <param name="endY">The index of the row within the source image to end processing.</param>
        /// <param name="kernel">The kernel operator.</param>
        private void ApplyConvolution(ImageBase <T, TP> target, ImageBase <T, TP> source, Rectangle sourceRectangle, int startY, int endY, float[,] kernel)
        {
            int kernelHeight = kernel.GetLength(0);
            int kernelWidth  = kernel.GetLength(1);
            int radiusY      = kernelHeight >> 1;
            int radiusX      = kernelWidth >> 1;

            int sourceBottom = sourceRectangle.Bottom;
            int startX       = sourceRectangle.X;
            int endX         = sourceRectangle.Right;
            int maxY         = sourceBottom - 1;
            int maxX         = endX - 1;

            using (IPixelAccessor <T, TP> sourcePixels = source.Lock())
                using (IPixelAccessor <T, TP> targetPixels = target.Lock())
                {
                    Parallel.For(
                        startY,
                        endY,
                        this.ParallelOptions,
                        y =>
                    {
                        for (int x = startX; x < endX; x++)
                        {
                            Vector4 destination = new Vector4();

                            // Apply each matrix multiplier to the color components for each pixel.
                            for (int fy = 0; fy < kernelHeight; fy++)
                            {
                                int fyr     = fy - radiusY;
                                int offsetY = y + fyr;

                                offsetY = offsetY.Clamp(0, maxY);

                                for (int fx = 0; fx < kernelWidth; fx++)
                                {
                                    int fxr     = fx - radiusX;
                                    int offsetX = x + fxr;

                                    offsetX = offsetX.Clamp(0, maxX);

                                    Vector4 currentColor = sourcePixels[offsetX, offsetY].ToVector4();
                                    destination         += kernel[fy, fx] * currentColor;
                                }
                            }

                            T packed = default(T);
                            packed.PackFromVector4(destination);
                            targetPixels[x, y] = packed;
                        }

                        this.OnRowProcessed();
                    });
                }
        }
示例#17
0
        /// <inheritdoc/>
        protected override void Apply(ImageBase <T, TP> target, ImageBase <T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
        {
            int     startX      = sourceRectangle.X;
            int     endX        = sourceRectangle.Right;
            T       glowColor   = this.GlowColor;
            Vector2 centre      = Rectangle.Center(sourceRectangle).ToVector2();
            float   maxDistance = this.Radius > 0 ? Math.Min(this.Radius, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;
            Ellipse ellipse     = new Ellipse(new Point(centre), maxDistance, maxDistance);

            // Align start/end positions.
            int minX = Math.Max(0, startX);
            int maxX = Math.Min(source.Width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(source.Height, endY);

            // Reset offset if necessary.
            if (minX > 0)
            {
                startX = 0;
            }

            if (minY > 0)
            {
                startY = 0;
            }

            using (IPixelAccessor <T, TP> sourcePixels = source.Lock())
                using (IPixelAccessor <T, TP> targetPixels = target.Lock())
                {
                    Parallel.For(
                        minY,
                        maxY,
                        this.ParallelOptions,
                        y =>
                    {
                        int offsetY = y - startY;
                        for (int x = minX; x < maxX; x++)
                        {
                            int offsetX = x - startX;
                            if (ellipse.Contains(offsetX, offsetY))
                            {
                                // TODO: Premultiply?
                                float distance      = Vector2.Distance(centre, new Vector2(offsetX, offsetY));
                                Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4();
                                T packed            = default(T);
                                packed.PackFromVector4(Vector4.Lerp(glowColor.ToVector4(), sourceColor, distance / maxDistance));
                                targetPixels[offsetX, offsetY] = packed;
                            }
                        }

                        this.OnRowProcessed();
                    });
                }
        }
示例#18
0
        /// <inheritdoc/>
        protected override void Apply(ImageBase <T, TP> target, ImageBase <T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
        {
            float brightness = this.Value / 100F;
            int   startX     = sourceRectangle.X;
            int   endX       = sourceRectangle.Right;

            // Align start/end positions.
            int minX = Math.Max(0, startX);
            int maxX = Math.Min(source.Width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(source.Height, endY);

            // Reset offset if necessary.
            if (minX > 0)
            {
                startX = 0;
            }

            if (minY > 0)
            {
                startY = 0;
            }

            using (IPixelAccessor <T, TP> sourcePixels = source.Lock())
                using (IPixelAccessor <T, TP> targetPixels = target.Lock())
                {
                    Parallel.For(
                        minY,
                        maxY,
                        this.ParallelOptions,
                        y =>
                    {
                        int offsetY = y - startY;
                        for (int x = minX; x < maxX; x++)
                        {
                            int offsetX = x - startX;

                            // TODO: Check this with other formats.
                            Vector4 vector      = sourcePixels[offsetX, offsetY].ToVector4().Expand();
                            Vector3 transformed = new Vector3(vector.X, vector.Y, vector.Z) + new Vector3(brightness);
                            vector = new Vector4(transformed, vector.W);

                            T packed = default(T);
                            packed.PackFromVector4(vector.Compress());

                            targetPixels[offsetX, offsetY] = packed;
                        }

                        this.OnRowProcessed();
                    });
                }
        }
示例#19
0
        private QuantizedImage GenerateResult(IPixelAccessor imagePixels, int colorCount, Box[] cube)
        {
            List <Color2> pallette = new List <Color2>();

            byte[] pixels           = new byte[imagePixels.Width * imagePixels.Height];
            int    transparentIndex = -1;
            int    width            = imagePixels.Width;
            int    height           = imagePixels.Height;

            for (int k = 0; k < colorCount; k++)
            {
                Mark(cube[k], (byte)k);
                double weight = Volume(cube[k], vwt);
                if (Math.Abs(weight) > Epsilon)
                {
                    byte   r     = (byte)(Volume(cube[k], vmr) / weight);
                    byte   g     = (byte)(Volume(cube[k], vmg) / weight);
                    byte   b     = (byte)(Volume(cube[k], vmb) / weight);
                    byte   a     = (byte)(Volume(cube[k], vma) / weight);
                    Color2 color = Color2.FromArgb(a, r, g, b);
                    if (color.Equals(default(Color2)))
                    {
                        transparentIndex = k;
                    }
                    pallette.Add(color);
                }
                else
                {
                    pallette.Add(default(Color2));
                    transparentIndex = k;
                }
            }
            Parallel.For(0, height, Bootstrapper.instance.ParallelOptions, y => {
                for (int x = 0; x < width; x++)
                {
                    // Expected order r->g->b->a
                    byte[] color = imagePixels[x, y].ToBytes();
                    int r        = color[0] >> (8 - IndexBits);
                    int g        = color[1] >> (8 - IndexBits);
                    int b        = color[2] >> (8 - IndexBits);
                    int a        = color[3] >> (8 - IndexAlphaBits);
                    if (transparentIndex > -1 && color[3] <= Threshold)
                    {
                        pixels[(y * width) + x] = (byte)transparentIndex;
                        continue;
                    }
                    int ind = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1);
                    pixels[(y * width) + x] = tag[ind];
                }
            });
            return(new QuantizedImage(width, height, pallette.ToArray(), pixels, transparentIndex));
        }
示例#20
0
        /// <inheritdoc/>
        protected override void Apply(ImageBase <T, TP> target, ImageBase <T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
        {
            float   contrast       = (100F + this.Value) / 100F;
            int     startX         = sourceRectangle.X;
            int     endX           = sourceRectangle.Right;
            Vector4 contrastVector = new Vector4(contrast, contrast, contrast, 1);
            Vector4 shiftVector    = new Vector4(.5F, .5F, .5F, 1);

            // Align start/end positions.
            int minX = Math.Max(0, startX);
            int maxX = Math.Min(source.Width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(source.Height, endY);

            // Reset offset if necessary.
            if (minX > 0)
            {
                startX = 0;
            }

            if (minY > 0)
            {
                startY = 0;
            }

            using (IPixelAccessor <T, TP> sourcePixels = source.Lock())
                using (IPixelAccessor <T, TP> targetPixels = target.Lock())
                {
                    Parallel.For(
                        minY,
                        maxY,
                        this.ParallelOptions,
                        y =>
                    {
                        int offsetY = y - startY;
                        for (int x = minX; x < maxX; x++)
                        {
                            int offsetX = x - startX;

                            Vector4 vector = sourcePixels[offsetX, offsetY].ToVector4().Expand();
                            vector        -= shiftVector;
                            vector        *= contrastVector;
                            vector        += shiftVector;
                            T packed       = default(T);
                            packed.PackFromVector4(vector.Compress());
                            targetPixels[offsetX, offsetY] = packed;
                        }

                        this.OnRowProcessed();
                    });
                }
        }
示例#21
0
 /// <summary>
 /// Execute the first pass through the pixels in the image
 /// </summary>
 /// <param name="source">The source data</param>
 /// <param name="width">The width in pixels of the image.</param>
 /// <param name="height">The height in pixels of the image.</param>
 protected virtual void FirstPass(IPixelAccessor <T, TP> source, int width, int height)
 {
     // Loop through each row
     for (int y = 0; y < height; y++)
     {
         // And loop through each column
         for (int x = 0; x < width; x++)
         {
             // Now I have the pixel, call the FirstPassQuantize function...
             this.InitialQuantizePixel(source[x, y]);
         }
     }
 }
示例#22
0
        public void Encode(ImageBase image, Stream stream)
        {
            if (image == null || stream == null)
            {
                throw new ArgumentNullException();
            }
            stream.Write(new byte[] {
                0x89,                // Set the high bit.
                0x50,                // P
                0x4E,                // N
                0x47,                // G
                0x0D,                // Line ending CRLF
                0x0A,                // Line ending CRLF
                0x1A,                // EOF
                0x0A                 // LF
            }, 0, 8);
            int quality = Quality > 0 ? Quality : image.Quality;

            Quality  = quality > 0 ? NumUtils.Clamp(quality, 1, int.MaxValue) : int.MaxValue;
            bitDepth = Quality <= 256
                                ? (byte)NumUtils.Clamp(GifEncoderCore.GetBitsNeededForColorDepth(Quality), 1, 8)
                                : (byte)8;
            if (bitDepth == 3)
            {
                bitDepth = 4;
            }
            else if (bitDepth >= 5 || bitDepth <= 7)
            {
                bitDepth = 8;
            }
            PngHeader header = new PngHeader {
                Width             = image.Width,
                Height            = image.Height,
                ColorType         = (byte)(Quality <= 256 ? 3 : 6),
                BitDepth          = bitDepth,
                FilterMethod      = 0,            // None
                CompressionMethod = 0,
                InterlaceMethod   = 0
            };

            WriteHeaderChunk(stream, header);
            QuantizedImage quantized = WritePaletteChunk(stream, header, image);

            WritePhysicalChunk(stream, image);
            WriteGammaChunk(stream);
            using (IPixelAccessor pixels = image.Lock()){
                WriteDataChunks(stream, pixels, quantized);
            }
            WriteEndChunk(stream);
            stream.Flush();
        }
示例#23
0
        /// <inheritdoc/>
        protected override void Apply(ImageBase <T, TP> target, ImageBase <T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
        {
            int     startX        = sourceRectangle.X;
            int     endX          = sourceRectangle.Right;
            T       vignetteColor = this.VignetteColor;
            Vector2 centre        = Rectangle.Center(sourceRectangle).ToVector2();
            float   rX            = this.RadiusX > 0 ? Math.Min(this.RadiusX, sourceRectangle.Width * .5F) : sourceRectangle.Width * .5F;
            float   rY            = this.RadiusY > 0 ? Math.Min(this.RadiusY, sourceRectangle.Height * .5F) : sourceRectangle.Height * .5F;
            float   maxDistance   = (float)Math.Sqrt((rX * rX) + (rY * rY));

            // Align start/end positions.
            int minX = Math.Max(0, startX);
            int maxX = Math.Min(source.Width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(source.Height, endY);

            // Reset offset if necessary.
            if (minX > 0)
            {
                startX = 0;
            }

            if (minY > 0)
            {
                startY = 0;
            }

            using (IPixelAccessor <T, TP> sourcePixels = source.Lock())
                using (IPixelAccessor <T, TP> targetPixels = target.Lock())
                {
                    Parallel.For(
                        minY,
                        maxY,
                        this.ParallelOptions,
                        y =>
                    {
                        int offsetY = y - startY;
                        for (int x = minX; x < maxX; x++)
                        {
                            int offsetX         = x - startX;
                            float distance      = Vector2.Distance(centre, new Vector2(offsetX, offsetY));
                            Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4();
                            T packed            = default(T);
                            packed.PackFromVector4(Vector4.Lerp(vignetteColor.ToVector4(), sourceColor, 1 - (.9F * (distance / maxDistance))));
                            targetPixels[offsetX, offsetY] = packed;
                        }

                        this.OnRowProcessed();
                    });
                }
        }
示例#24
0
 private void WriteSos(IPixelAccessor pixels)
 {
     // TODO: We should allow grayscale writing.
     outputStream.Write(sosHeaderYCbCr, 0, sosHeaderYCbCr.Length);
     switch (subsample){
         case JpegSubsample.Ratio444:
             Encode444(pixels);
             break;
         case JpegSubsample.Ratio420:
             Encode420(pixels);
             break;
     }
     Emit(0x7f, 7);
 }
示例#25
0
 private static void ToYCbCr(IPixelAccessor pixels, int x, int y, Block yBlock, Block cbBlock, Block crBlock)
 {
     int xmax = pixels.Width - 1;
     int ymax = pixels.Height - 1;
     for (int j = 0; j < 8; j++){
         for (int i = 0; i < 8; i++){
             byte[] pixel = pixels[Math.Min(x + i, xmax), Math.Min(y + j, ymax)].ToBytes();
             YCbCr2 color = Color2.FromArgb(pixel[3], pixel[0], pixel[1], pixel[2]);
             int index = 8*j + i;
             yBlock[index] = (int) color.Y;
             cbBlock[index] = (int) color.Cb;
             crBlock[index] = (int) color.Cr;
         }
     }
 }
示例#26
0
        private void Write32bit(EndianBinaryWriter writer, IPixelAccessor pixels, int amount)
        {
            for (int y = pixels.Height - 1; y >= 0; y--){
                for (int x = 0; x < pixels.Width; x++){
                    // Convert back to b-> g-> r-> a order.
                    byte[] bytes = pixels[x, y].ToBytes();
                    writer.Write(new[]{bytes[2], bytes[1], bytes[0], bytes[3]});
                }

                // Pad
                for (int i = 0; i < amount; i++){
                    writer.Write((byte) 0);
                }
            }
        }
示例#27
0
 private void Encode444(IPixelAccessor pixels)
 {
     Block b = new Block();
     Block cb = new Block();
     Block cr = new Block();
     int prevDcy = 0, prevDcCb = 0, prevDcCr = 0;
     for (int y = 0; y < pixels.Height; y += 8){
         for (int x = 0; x < pixels.Width; x += 8){
             ToYCbCr(pixels, x, y, b, cb, cr);
             prevDcy = WriteBlock(b, QuantIndex.Luminance, prevDcy);
             prevDcCb = WriteBlock(cb, QuantIndex.Chrominance, prevDcCb);
             prevDcCr = WriteBlock(cr, QuantIndex.Chrominance, prevDcCr);
         }
     }
 }
示例#28
0
        /// <inheritdoc/>
        protected override void Apply(ImageBase <T, TP> target, ImageBase <T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
        {
            int     startX        = sourceRectangle.X;
            int     endX          = sourceRectangle.Right;
            Vector3 inverseVector = Vector3.One;

            // Align start/end positions.
            int minX = Math.Max(0, startX);
            int maxX = Math.Min(source.Width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(source.Height, endY);

            // Reset offset if necessary.
            if (minX > 0)
            {
                startX = 0;
            }

            if (minY > 0)
            {
                startY = 0;
            }

            using (IPixelAccessor <T, TP> sourcePixels = source.Lock())
                using (IPixelAccessor <T, TP> targetPixels = target.Lock())
                {
                    Parallel.For(
                        minY,
                        maxY,
                        this.ParallelOptions,
                        y =>
                    {
                        int offsetY = y - startY;
                        for (int x = minX; x < maxX; x++)
                        {
                            int offsetX    = x - startX;
                            Vector4 color  = sourcePixels[offsetX, offsetY].ToVector4();
                            Vector3 vector = inverseVector - new Vector3(color.X, color.Y, color.Z);

                            T packed = default(T);
                            packed.PackFromVector4(new Vector4(vector, color.W));
                            targetPixels[offsetX, offsetY] = packed;
                        }

                        this.OnRowProcessed();
                    });
                }
        }
示例#29
0
        /// <inheritdoc/>
        protected override void Apply(ImageBase <T, TP> target, ImageBase <T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
        {
            float threshold = this.Value;
            T     upper     = this.UpperColor;
            T     lower     = this.LowerColor;
            int   startX    = sourceRectangle.X;
            int   endX      = sourceRectangle.Right;

            // Align start/end positions.
            int minX = Math.Max(0, startX);
            int maxX = Math.Min(source.Width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(source.Height, endY);

            // Reset offset if necessary.
            if (minX > 0)
            {
                startX = 0;
            }

            if (minY > 0)
            {
                startY = 0;
            }

            using (IPixelAccessor <T, TP> sourcePixels = source.Lock())
                using (IPixelAccessor <T, TP> targetPixels = target.Lock())
                {
                    Parallel.For(
                        minY,
                        maxY,
                        this.ParallelOptions,
                        y =>
                    {
                        int offsetY = y - startY;
                        for (int x = minX; x < maxX; x++)
                        {
                            int offsetX = x - startX;
                            T color     = sourcePixels[offsetX, offsetY];

                            // Any channel will do since it's Grayscale.
                            targetPixels[offsetX, offsetY] = color.ToVector4().X >= threshold ? upper : lower;
                        }

                        this.OnRowProcessed();
                    });
                }
        }
示例#30
0
        /// <inheritdoc/>
        protected override void Apply(ImageBase <T, TP> target, ImageBase <T, TP> source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY)
        {
            float alpha  = this.Value / 100F;
            int   startX = sourceRectangle.X;
            int   endX   = sourceRectangle.Right;

            // Align start/end positions.
            int minX = Math.Max(0, startX);
            int maxX = Math.Min(source.Width, endX);
            int minY = Math.Max(0, startY);
            int maxY = Math.Min(source.Height, endY);

            // Reset offset if necessary.
            if (minX > 0)
            {
                startX = 0;
            }

            if (minY > 0)
            {
                startY = 0;
            }

            Vector4 alphaVector = new Vector4(1, 1, 1, alpha);

            using (IPixelAccessor <T, TP> sourcePixels = source.Lock())
                using (IPixelAccessor <T, TP> targetPixels = target.Lock())
                {
                    Parallel.For(
                        minY,
                        maxY,
                        this.ParallelOptions,
                        y =>
                    {
                        int offsetY = y - startY;
                        for (int x = minX; x < maxX; x++)
                        {
                            int offsetX = x - startX;
                            T packed    = default(T);
                            packed.PackFromVector4(sourcePixels[offsetX, offsetY].ToVector4() * alphaVector);
                            targetPixels[offsetX, offsetY] = packed;
                        }

                        this.OnRowProcessed();
                    });
                }
        }
示例#31
0
        public QuantizedImage Quantize(ImageBase image, int maxColors)
        {
            if (image == null)
            {
                throw new ArgumentNullException();
            }
            int colorCount = NumUtils.Clamp(maxColors, 1, 256);

            Clear();
            using (IPixelAccessor imagePixels = image.Lock()){
                Build3DHistogram(imagePixels);
                Get3DMoments();
                Box[] cube;
                BuildCube(out cube, ref colorCount);
                return(GenerateResult(imagePixels, colorCount, cube));
            }
        }
示例#32
0
 private void WriteSos(IPixelAccessor pixels)
 {
     // TODO: We should allow grayscale writing.
     outputStream.Write(sosHeaderYCbCr, 0, sosHeaderYCbCr.Length);
     switch (subsample){
         case JpegSubsample.Ratio444:
             Encode444(pixels);
             break;
         case JpegSubsample.Ratio420:
             Encode420(pixels);
             break;
     }
     Emit(0x7f, 7);
 }
示例#33
0
 private void Encode444(IPixelAccessor pixels)
 {
     Block b = new Block();
     Block cb = new Block();
     Block cr = new Block();
     int prevDcy = 0, prevDcCb = 0, prevDcCr = 0;
     for (int y = 0; y < pixels.Height; y += 8){
         for (int x = 0; x < pixels.Width; x += 8){
             ToYCbCr(pixels, x, y, b, cb, cr);
             prevDcy = WriteBlock(b, QuantIndex.Luminance, prevDcy);
             prevDcCb = WriteBlock(cb, QuantIndex.Chrominance, prevDcCb);
             prevDcCr = WriteBlock(cr, QuantIndex.Chrominance, prevDcCr);
         }
     }
 }
示例#34
0
 private void Encode420(IPixelAccessor pixels)
 {
     Block b = new Block();
     Block[] cb = new Block[4];
     Block[] cr = new Block[4];
     int prevDcy = 0, prevDcCb = 0, prevDcCr = 0;
     for (int i = 0; i < 4; i++){
         cb[i] = new Block();
     }
     for (int i = 0; i < 4; i++){
         cr[i] = new Block();
     }
     for (int y = 0; y < pixels.Height; y += 16){
         for (int x = 0; x < pixels.Width; x += 16){
             for (int i = 0; i < 4; i++){
                 int xOff = (i & 1)*8;
                 int yOff = (i & 2)*4;
                 ToYCbCr(pixels, x + xOff, y + yOff, b, cb[i], cr[i]);
                 prevDcy = WriteBlock(b, QuantIndex.Luminance, prevDcy);
             }
             Scale16X16_8X8(b, cb);
             prevDcCb = WriteBlock(b, QuantIndex.Chrominance, prevDcCb);
             Scale16X16_8X8(b, cr);
             prevDcCr = WriteBlock(b, QuantIndex.Chrominance, prevDcCr);
         }
     }
 }
示例#35
0
 private static void ToYCbCr(IPixelAccessor pixels, int x, int y, Block yBlock, Block cbBlock, Block crBlock)
 {
     int xmax = pixels.Width - 1;
     int ymax = pixels.Height - 1;
     for (int j = 0; j < 8; j++){
         for (int i = 0; i < 8; i++){
             byte[] pixel = pixels[Math.Min(x + i, xmax), Math.Min(y + j, ymax)].ToBytes();
             YCbCr2 color = Color2.FromArgb(pixel[3], pixel[0], pixel[1], pixel[2]);
             int index = 8*j + i;
             yBlock[index] = (int) color.Y;
             cbBlock[index] = (int) color.Cb;
             crBlock[index] = (int) color.Cr;
         }
     }
 }
示例#36
0
 private void Build3DHistogram(IPixelAccessor pixels)
 {
     for (int y = 0; y < pixels.Height; y++){
         for (int x = 0; x < pixels.Width; x++){
             byte[] color = pixels[x, y].ToBytes();
             byte r = color[0];
             byte g = color[1];
             byte b = color[2];
             byte a = color[3];
             int inr = r >> (8 - IndexBits);
             int ing = g >> (8 - IndexBits);
             int inb = b >> (8 - IndexBits);
             int ina = a >> (8 - IndexAlphaBits);
             int ind = GetPaletteIndex(inr + 1, ing + 1, inb + 1, ina + 1);
             vwt[ind]++;
             vmr[ind] += r;
             vmg[ind] += g;
             vmb[ind] += b;
             vma[ind] += a;
             m2[ind] += (r*r) + (g*g) + (b*b) + (a*a);
         }
     }
 }
示例#37
0
 private QuantizedImage GenerateResult(IPixelAccessor imagePixels, int colorCount, Box[] cube)
 {
     List<Color2> pallette = new List<Color2>();
     byte[] pixels = new byte[imagePixels.Width*imagePixels.Height];
     int transparentIndex = -1;
     int width = imagePixels.Width;
     int height = imagePixels.Height;
     for (int k = 0; k < colorCount; k++){
         Mark(cube[k], (byte) k);
         double weight = Volume(cube[k], vwt);
         if (Math.Abs(weight) > Epsilon){
             byte r = (byte) (Volume(cube[k], vmr)/weight);
             byte g = (byte) (Volume(cube[k], vmg)/weight);
             byte b = (byte) (Volume(cube[k], vmb)/weight);
             byte a = (byte) (Volume(cube[k], vma)/weight);
             Color2 color = Color2.FromArgb(a,r, g, b);
             if (color.Equals(default(Color2))){
                 transparentIndex = k;
             }
             pallette.Add(color);
         } else{
             pallette.Add(default(Color2));
             transparentIndex = k;
         }
     }
     Parallel.For(0, height, Bootstrapper.instance.ParallelOptions, y =>{
         for (int x = 0; x < width; x++){
             // Expected order r->g->b->a
             byte[] color = imagePixels[x, y].ToBytes();
             int r = color[0] >> (8 - IndexBits);
             int g = color[1] >> (8 - IndexBits);
             int b = color[2] >> (8 - IndexBits);
             int a = color[3] >> (8 - IndexAlphaBits);
             if (transparentIndex > -1 && color[3] <= Threshold){
                 pixels[(y*width) + x] = (byte) transparentIndex;
                 continue;
             }
             int ind = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1);
             pixels[(y*width) + x] = tag[ind];
         }
     });
     return new QuantizedImage(width, height, pallette.ToArray(), pixels, transparentIndex);
 }