Beispiel #1
0
        /// <summary>
        /// Reduces the height of the <see cref="Image"/> by the factor of 2.
        /// </summary>
        /// <returns>The scaled <see cref="Image"/>.</returns>
        public Image Reduce1x2()
        {
            if (this.BitsPerPixel != 1)
            {
                throw new NotSupportedException(Properties.Resources.E_UnsupportedDepth_1bpp);
            }

            Image dst = new Image(
                this.Width,
                (this.Height + 1) >> 1,
                this.BitsPerPixel,
                this.HorizontalResolution,
                this.VerticalResolution / 2);

            int stride = this.Stride;

            ulong[] bitssrc = this.Bits;
            ulong[] bitsdst = dst.Bits;

            int offsrc = 0;
            int offdst = 0;

            for (int i = 0, ii = this.Height >> 1; i < ii; i++, offsrc += 2 * stride, offdst += stride)
            {
                Vectors.Or(stride, bitssrc, offsrc, bitssrc, offsrc + stride, bitsdst, offdst);
            }

            if ((this.Height & 1) != 0)
            {
                Vectors.Copy(stride, bitssrc, offsrc, bitsdst, offdst);
            }

            dst.AppendTransform(new MatrixTransform(1.0, 0.5));
            return(dst);
        }
Beispiel #2
0
        public Image Inflate(int left, int top, int right, int bottom, BorderType borderType, uint borderValue)
        {
            // calculate and verify target area in source coordinates
            Rectangle bounds = Rectangle.FromLTRB(
                -left,
                -top,
                this.Width + right,
                this.Height + bottom);

            if (bounds.Width <= 0)
            {
                throw new ArgumentException("The new image width is invalid.");
            }

            if (bounds.Height <= 0)
            {
                throw new ArgumentException("The new image height is invalid.");
            }

            Image dst = new Image(bounds.Size, this);

            // calculate source area to copy from
            Rectangle srcarea = Rectangle.Intersect(bounds, this.Bounds);

            // calculate destination area to copy to
            Rectangle dstarea = Rectangle.Offset(srcarea, -bounds.X, -bounds.Y);

            Image.CopyArea(dst, dstarea.X, dstarea.Y, srcarea.Width, srcarea.Height, this, srcarea.X, srcarea.Y);

            // set border
            dst.SetBorder(dstarea, borderType, borderValue);

            dst.AppendTransform(new MatrixTransform(left, top));
            return(dst);
        }
Beispiel #3
0
        /// <summary>
        /// Crops the <see cref="Image"/> using rectangle specified by a pair of coordinates, a width, and a height.
        /// </summary>
        /// <param name="x">The x-coordinate of the upper-left corner of the area.</param>
        /// <param name="y">The y-coordinate of the upper-left corner of the area.</param>
        /// <param name="width">The width of the area.</param>
        /// <param name="height">The height of the area.</param>
        /// <returns>
        /// A new cropped <see cref="Image"/>.
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        /// <para>The rectangular area described by <paramref name="x"/>, <paramref name="y"/>, <paramref name="width"/> and <paramref name="height"/> is outside of this <see cref="Image"/> bounds.</para>
        /// </exception>
        public Image Crop(int x, int y, int width, int height)
        {
            this.ValidateArea(x, y, width, height);

            Image dst = new Image(width, height, this);

            Image.CopyArea(dst, 0, 0, width, height, this, x, y);

            dst.AppendTransform(new MatrixTransform(-x, -y));
            return(dst);
        }
Beispiel #4
0
        /// <summary>
        /// Reduces the height of the <see cref="Image"/> by the factor of 4.
        /// </summary>
        /// <returns>The scaled <see cref="Image"/>.</returns>
        public Image Reduce1x4()
        {
            if (this.BitsPerPixel != 1)
            {
                throw new NotSupportedException(Properties.Resources.E_UnsupportedDepth_1bpp);
            }

            Image dst = new Image(
                this.Width,
                (this.Height + 3) / 4,
                this.BitsPerPixel,
                this.HorizontalResolution,
                this.VerticalResolution / 4);

            int stride = this.Stride;

            ulong[] bitssrc = this.Bits;
            ulong[] bitsdst = dst.Bits;

            int offsrc = 0;
            int offdst = 0;

            for (int i = 0, ii = this.Height / 4; i < ii; i++, offsrc += 4 * stride, offdst += stride)
            {
                Vectors.Or(stride, bitssrc, offsrc, bitssrc, offsrc + stride, bitssrc, offsrc + (2 * stride), bitssrc, offsrc + (3 * stride), bitsdst, offdst);
            }

            switch (this.Height % 4)
            {
            case 1:
                Vectors.Copy(stride, bitssrc, offsrc, bitsdst, offdst);
                break;

            case 2:
                Vectors.Or(stride, bitssrc, offsrc, bitssrc, offsrc + stride, bitsdst, offdst);
                break;

            case 3:
                Vectors.Or(stride, bitssrc, offsrc, bitssrc, offsrc + stride, bitssrc, offsrc + (2 * stride), bitsdst, offdst);
                break;
            }

            dst.AppendTransform(new MatrixTransform(1.0, 0.25));
            return(dst);
        }
Beispiel #5
0
        /// <summary>
        /// Crops the <see cref="Image"/> using rectangle calculated by <see cref="Image.BlackArea"/> method.
        /// </summary>
        /// <param name="dx">The amount by which to expand or shrink the left and right sides of the image black area.</param>
        /// <param name="dy">The amount by which to expand or shrink the top and bottom sides of the image black area.</param>
        /// <returns>
        /// A new cropped <see cref="Image"/>.
        /// </returns>
        /// <exception cref="NotSupportedException">
        /// <para>
        /// The <see cref="Image{T}.BitsPerPixel"/> is not 1.
        /// </para>
        /// </exception>
        public Image CropBlackArea(int dx, int dy)
        {
            // determine black area of the image
            Rectangle blackArea = this.BlackArea();

            if (dx == 0 && dy == 0)
            {
                // no frame - simply crop the black area
                return(this.Crop(blackArea));
            }

            // expand target area
            Rectangle bounds = Rectangle.Inflate(blackArea, dx, dy);

            Image dst = new Image(bounds.Size, this);

            if (!blackArea.IsEmpty)
            {
                Rectangle srcarea = Rectangle.Intersect(bounds, blackArea);
                Rectangle dstarea = Rectangle.Offset(srcarea, -bounds.X, -bounds.Y);
                Image.CopyArea(dst, dstarea.X, dstarea.Y, srcarea.Width, srcarea.Height, this, srcarea.X, srcarea.Y);

                if (this.BitsPerPixel > 1)
                {
                    // set frame to white
                    dst.SetWhiteBorder(dstarea);
                }
            }
            else
            {
                if (this.BitsPerPixel > 1)
                {
                    // set all image to white
                    Vectors.Set(dst.Bits.Length, ulong.MaxValue, dst.Bits, 0);
                }
            }

            dst.AppendTransform(new MatrixTransform(-bounds.X, -bounds.Y));
            return(dst);
        }
Beispiel #6
0
        public Image Affine(Image dst, System.Windows.Media.Matrix matrix, BorderType borderType, uint borderValue)
        {
            const float Eps = 1e-8f;

            if (matrix.IsIdentity)
            {
                return(this.Copy(dst, true));
            }

            // IPP does not support 1bpp images - convert to 8bpp
            Image src;
            bool  convert1bpp = false;

            if (this.BitsPerPixel == 1)
            {
                src         = this.Convert1To8(null);
                borderValue = borderValue != 0 ? 0u : 255u;
                convert1bpp = true;
            }
            else
            {
                src = this;
            }

            // calculate new image size and position
            PointD tr = TransformPoint(src.Width, 0);
            PointD br = TransformPoint(src.Width, src.Height);
            PointD bl = TransformPoint(0, src.Height);

            double x1dst = Core.MinMax.Min(bl.X, tr.X, br.X, 0.0);
            double x2dst = Core.MinMax.Max(bl.X, tr.X, br.X, 0.0);
            double y1dst = Core.MinMax.Min(bl.Y, tr.Y, br.Y, 0.0);
            double y2dst = Core.MinMax.Max(bl.Y, tr.Y, br.Y, 0.0);

            // translate matrix so the transformed image fits into new frame
            matrix.OffsetX = -Core.MinMax.Min(x1dst, x2dst);
            matrix.OffsetY = -Core.MinMax.Min(y1dst, y2dst);

            // note: add epsilon to avoid rounding problems
            int widthdst  = (int)Math.Floor(x2dst - x1dst + Eps);
            int heightdst = (int)Math.Floor(y2dst - y1dst + Eps);

            bool inplace = dst == this;

            dst = src.CreateTemplate(dst, widthdst, heightdst, src.BitsPerPixel);

            IPP.Execute(() =>
            {
                return(NativeMethods.affine(
                           src.BitsPerPixel,
                           src.Width,
                           src.Height,
                           src.Stride,
                           src.Bits,
                           dst.Width,
                           dst.Height,
                           dst.Stride,
                           dst.Bits,
                           matrix.M11,
                           matrix.M12,
                           matrix.OffsetX,
                           matrix.M21,
                           matrix.M22,
                           matrix.OffsetY,
                           (int)borderType,
                           borderValue));
            });

            dst.AppendTransform(new MatrixTransform(matrix));

            // convert back to 1bpp
            if (convert1bpp)
            {
                dst.Convert8To1(dst, 1);

                /*using (Pix pixs = transformedImage.CreatePix())
                 * {
                 *  using (Pix pixd = pixs.pixOtsu(false))
                 *  {
                 *      if (pixd != null)
                 *      {
                 *          return pixd.CreateImage(transformedImage.HorizontalResolution, transformedImage.VerticalResolution);
                 *      }
                 *  }
                 * }*/
            }

            if (inplace)
            {
                this.Attach(dst);
                return(this);
            }

            return(dst);

            PointD TransformPoint(int ptx, int pty)
            {
                return(new PointD(
                           (matrix.M11 * ptx) + (matrix.M12 * pty) + matrix.OffsetX,
                           (matrix.M21 * ptx) + (matrix.M22 * pty) + matrix.OffsetY));
            }
        }
Beispiel #7
0
        /// <summary>
        /// Reduces the size and resolution of this <see cref="Image"/> by a factor of 4 by downsampling.
        /// </summary>
        /// <param name="dst">The destination <see cref="Image"/>. Can be <b>null</b>.</param>
        /// <returns>
        /// The destination <see cref="Image"/>.
        /// </returns>
        /// <remarks>
        /// <para>If <paramref name="dst"/> is <b>null</b> the method creates new destination <see cref="Image"/> with dimensions of this <see cref="Image"/>.</para>
        /// <para>If <paramref name="dst"/> equals this <see cref="Image"/>, the operation is performed in-place.</para>
        /// <para>Conversely, the <paramref name="dst"/> is reallocated to the dimensions of this <see cref="Image"/>.</para>
        /// </remarks>
        public Image ScaleByDownsampling4(Image dst)
        {
            int width        = this.Width;
            int height       = this.Height;
            int bitsPerPixel = this.BitsPerPixel;
            int dstwidth     = width / 4;
            int dstheight    = height / 4;

            bool inplace = dst == this;

            dst = this.CreateTemplate(dst, dstwidth, dstheight, bitsPerPixel);

            switch (bitsPerPixel)
            {
            case 1:
                unsafe
                {
                    fixed(ulong *bitssrc = this.Bits, bitsdst = dst.Bits)
                    {
                        ulong * ptrsrc      = (ulong *)bitssrc;
                        ushort *ptrdst      = (ushort *)bitsdst;
                        int     stridesrc   = this.Stride;
                        int     stride16dst = dst.Stride * 4;

                        for (int ydst = 0; ydst < dstheight; ydst++, ptrsrc += 4 * stridesrc, ptrdst += stride16dst)
                        {
                            for (int x = 0, xdst = 0, xsrc = 0; x < dstwidth; x += 16, xdst++, xsrc++)
                            {
                                ulong bits = ptrsrc[xsrc];
                                ptrdst[xdst] = (ushort)(
                                    (bits & 0x0001) |
                                    ((bits >> 3) & 0x0002) |
                                    ((bits >> 6) & 0x0004) |
                                    ((bits >> 9) & 0x0008) |
                                    ((bits >> 12) & 0x0010) |
                                    ((bits >> 15) & 0x0020) |
                                    ((bits >> 18) & 0x0040) |
                                    ((bits >> 21) & 0x0080) |
                                    ((bits >> 24) & 0x0100) |
                                    ((bits >> 27) & 0x0200) |
                                    ((bits >> 30) & 0x0400) |
                                    ((bits >> 33) & 0x0800) |
                                    ((bits >> 36) & 0x1000) |
                                    ((bits >> 39) & 0x2000) |
                                    ((bits >> 42) & 0x4000) |
                                    ((bits >> 45) & 0x8000));
                            }
                        }
                    }
                }

                break;

            case 2:
                unsafe
                {
                    fixed(ulong *bitssrc = this.Bits, bitsdst = dst.Bits)
                    {
                        ulong * ptrsrc      = (ulong *)bitssrc;
                        ushort *ptrdst      = (ushort *)bitsdst;
                        int     stridesrc   = this.Stride;
                        int     stride16dst = dst.Stride * 4;

                        for (int ydst = 0; ydst < dstheight; ydst++, ptrsrc += 4 * stridesrc, ptrdst += stride16dst)
                        {
                            for (int x = 0, xdst = 0, xsrc = 0; x < dstwidth; x += 8, xdst++, xsrc++)
                            {
                                ulong bits = ptrsrc[xsrc];
                                ptrdst[xdst] = (ushort)(
                                    (bits & 0x0003) |
                                    ((bits >> 6) & 0x000c) |
                                    ((bits >> 12) & 0x0030) |
                                    ((bits >> 18) & 0x00c0) |
                                    ((bits >> 24) & 0x0300) |
                                    ((bits >> 30) & 0x0c00) |
                                    ((bits >> 36) & 0x3000) |
                                    ((bits >> 42) & 0xc000));
                            }
                        }
                    }
                }

                break;

            case 4:
                unsafe
                {
                    fixed(ulong *bitssrc = this.Bits, bitsdst = dst.Bits)
                    {
                        ulong * ptrsrc      = (ulong *)bitssrc;
                        ushort *ptrdst      = (ushort *)bitsdst;
                        int     stridesrc   = this.Stride;
                        int     stride16dst = dst.Stride * 4;

                        for (int ydst = 0; ydst < dstheight; ydst++, ptrsrc += 4 * stridesrc, ptrdst += stride16dst)
                        {
                            for (int x = 0, xdst = 0, xsrc = 0; x < dstwidth; x += 4, xdst++, xsrc++)
                            {
                                ulong bits = ptrsrc[xsrc];
                                ptrdst[xdst] = (ushort)(
                                    (bits & 0x000f) |
                                    ((bits >> 12) & 0x00f0) |
                                    ((bits >> 24) & 0x0f00) |
                                    ((bits >> 36) & 0xf000));
                            }
                        }
                    }
                }

                break;

            case 8:
                unsafe
                {
                    fixed(ulong *bitssrc = this.Bits, bitsdst = dst.Bits)
                    {
                        byte *ptrsrc     = (byte *)bitssrc;
                        byte *ptrdst     = (byte *)bitsdst;
                        int   stride8src = this.Stride8;
                        int   stride8dst = dst.Stride8;

                        for (int ydst = 0; ydst < dstheight; ydst++, ptrsrc += 4 * stride8src, ptrdst += stride8dst)
                        {
                            for (int xdst = 0, xsrc = 0; xdst < dstwidth; xdst++, xsrc += 4)
                            {
                                ptrdst[xdst] = ptrsrc[xsrc];
                            }
                        }
                    }
                }

                break;

            case 16:
                unsafe
                {
                    fixed(ulong *bitssrc = this.Bits, bitsdst = dst.Bits)
                    {
                        ushort *ptrsrc      = (ushort *)bitssrc;
                        ushort *ptrdst      = (ushort *)bitsdst;
                        int     stride16src = this.Stride * 4;
                        int     stride16dst = dst.Stride * 4;

                        for (int ydst = 0; ydst < dstheight; ydst++, ptrsrc += 4 * stride16src, ptrdst += stride16dst)
                        {
                            for (int xdst = 0, xsrc = 0; xdst < dstwidth; xdst++, xsrc += 4)
                            {
                                ptrdst[xdst] = ptrsrc[xsrc];
                            }
                        }
                    }
                }

                break;

            case 24:
                unsafe
                {
                    fixed(ulong *bitssrc = this.Bits, bitsdst = dst.Bits)
                    {
                        byte *ptrsrc     = (byte *)bitssrc;
                        byte *ptrdst     = (byte *)bitsdst;
                        int   stride8src = this.Stride8;
                        int   stride8dst = dst.Stride8;

                        for (int ydst = 0; ydst < dstheight; ydst++, ptrsrc += 4 * stride8src, ptrdst += stride8dst)
                        {
                            for (int xdst = 0, xsrc = 0; xdst < 3 * dstwidth; xdst += 3, xsrc += 4 * 3)
                            {
                                ptrdst[xdst + 0] = ptrsrc[xsrc + 0];
                                ptrdst[xdst + 1] = ptrsrc[xsrc + 1];
                                ptrdst[xdst + 2] = ptrsrc[xsrc + 2];
                            }
                        }
                    }
                }

                break;

            case 32:
                unsafe
                {
                    fixed(ulong *bitssrc = this.Bits, bitsdst = dst.Bits)
                    {
                        uint *ptrsrc      = (uint *)bitssrc;
                        uint *ptrdst      = (uint *)bitsdst;
                        int   stride32src = this.Stride * 2;
                        int   stride32dst = dst.Stride * 2;

                        for (int ydst = 0; ydst < dstheight; ydst++, ptrsrc += 4 * stride32src, ptrdst += stride32dst)
                        {
                            for (int xdst = 0, xsrc = 0; xdst < dstwidth; xdst++, xsrc += 4)
                            {
                                ptrdst[xdst] = ptrsrc[xsrc];
                            }
                        }
                    }
                }

                break;

            default:
                throw new NotSupportedException(string.Format(
                                                    CultureInfo.InvariantCulture,
                                                    Properties.Resources.E_UnsupportedDepth,
                                                    bitsPerPixel));
            }

            dst.SetResolution(this.HorizontalResolution / 4, this.VerticalResolution / 4);
            dst.AppendTransform(new MatrixTransform(0.25, 0.25));

            if (inplace)
            {
                this.Attach(dst);
                return(this);
            }

            return(dst);
        }
Beispiel #8
0
        /// <summary>
        /// Scales the <see cref="Image"/> vertically and horizontally without changing its resolution.
        /// </summary>
        /// <param name="dst">The destination <see cref="Image"/>. Can be <b>null</b>.</param>
        /// <param name="width">The desired width of the image, in pixels.</param>
        /// <param name="height">The desired height of the image, in pixels.</param>
        /// <param name="options">The scaling options.</param>
        /// <returns>
        /// The destination <see cref="Image"/>.
        /// </returns>
        public Image ScaleToSize(Image dst, int width, int height, ScalingOptions options)
        {
            if (width == this.Width && height == this.Height)
            {
                return(this.Copy(dst, true));
            }

            if (width <= 0)
            {
                throw new ArgumentException(Properties.Resources.E_InvalidWidth, nameof(width));
            }

            if (height <= 0)
            {
                throw new ArgumentException(Properties.Resources.E_InvalidHeight, nameof(height));
            }

            System.Windows.Media.Matrix matrix = System.Windows.Media.Matrix.Identity;
            matrix.Scale((double)width / this.Width, (double)height / this.Height);

#if false
            dst = this.Affine(dst, matrix, BorderType.BorderConst, this.WhiteColor);
            Debug.Assert(width == dst.Width && height == dst.Height, "Image dimensions are wrong.");
            return(dst);
#else
            // IPP does not support 1bpp images - convert to 8bpp
            Image src;
            bool  convert1bpp = false;
            if (this.BitsPerPixel == 1)
            {
                src         = this.Convert1To8(null);
                convert1bpp = true;
            }
            else
            {
                src = this;
            }

            bool inplace = dst == this;
            dst = src.CreateTemplate(dst, width, height, src.BitsPerPixel);

            IPP.Execute(() =>
            {
                return(NativeMethods.resize(
                           src.BitsPerPixel,
                           src.Width,
                           src.Height,
                           src.Bits,
                           src.Stride8,
                           dst.Width,
                           dst.Height,
                           dst.Bits,
                           dst.Stride8,
                           options.InterpolationType,
                           options.Antialiasing,
                           options.ValueB,
                           options.ValueC,
                           options.Lobes,
                           BorderType.BorderConst,
                           src.WhiteColor));
            });

            dst.AppendTransform(new MatrixTransform(matrix));

            // convert back to 1bpp
            if (convert1bpp)
            {
                dst.Convert8To1(dst, 1);
            }

            if (inplace)
            {
                this.Attach(dst);
                return(this);
            }

            return(dst);
#endif
        }