/// <summary>
        /// Вырезает указанную зону изображения.
        /// </summary>
        /// <param name="sourceImage">Исходное изображение.</param>
        /// <param name="rectangle">Участок изображения.</param>
        /// <returns></returns>
        public static Bitmap Crop(this Bitmap sourceImage, Rectangle rectangle)
        {
            if (sourceImage.Width == rectangle.Width && sourceImage.Height == rectangle.Height)
            {
                return(sourceImage);
            }

            BitmapData sourceImageData  = sourceImage.LockBits(new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, sourceImage.PixelFormat);
            Bitmap     croppedImage     = new Bitmap(rectangle.Width, rectangle.Height, sourceImage.PixelFormat);
            BitmapData croppedImageData = croppedImage.LockBits(new Rectangle(0, 0, rectangle.Width, rectangle.Height), ImageLockMode.WriteOnly, croppedImage.PixelFormat);
            int        pixelSize        = Image.GetPixelFormatSize(croppedImageData.PixelFormat) / 8;
            byte *     src  = (byte *)(void *)sourceImageData.Scan0 + rectangle.Y * sourceImageData.Stride + rectangle.X * pixelSize;
            byte *     dest = (byte *)(void *)croppedImageData.Scan0;

            for (int y = 0; y < rectangle.Height; y++)
            {
                int srcIndex     = y * sourceImageData.Stride;
                int croppedIndex = y * croppedImageData.Stride;

                UnmanagedBitmap.CopyUnmanagedMemory(dest + croppedIndex, src + srcIndex, croppedImageData.Stride);
            }

            croppedImage.UnlockBits(croppedImageData);
            sourceImage.UnlockBits(sourceImageData);

            return(croppedImage);
        }
Exemple #2
0
        /// <summary>
        /// Копирует буфер текущего изображения в другой экземпляр <see cref="UnmanagedBitmap"/>.
        /// </summary>
        /// <param name="destImage">Экземпляр <see cref="UnmanagedBitmap"/>, куда следует скопировать буфер текущего.</param>
        public void Copy(UnmanagedBitmap destImage)
        {
            if (Width != destImage.Width || Height != destImage.Height || PixelFormat != destImage.PixelFormat)
            {
                throw new Exception("Destination image has different size or pixel format.");
            }

            if (Stride == destImage.Stride)
            {
                CopyUnmanagedMemory(destImage.ImageData, ImageData, Stride * Height);
            }
            else
            {
                int dstStride  = destImage.Stride;
                int copyLength = (Stride < dstStride) ? Stride : dstStride;

                byte *src = (byte *)(void *)ImageData;
                byte *dst = (byte *)(void *)destImage.ImageData;

                for (int i = 0; i < Height; i++)
                {
                    CopyUnmanagedMemory(dst, src, copyLength);

                    dst += dstStride;
                    src += Stride;
                }
            }
        }
        /// <summary>
        /// Усреднённая выборка.
        /// </summary>
        /// <param name="sourceData">Исходное изображение.</param>
        /// <param name="destinationData">Изображение назначения.</param>
        /// <param name="newWidth">Новая ширина.</param>
        /// <param name="newHeight">новая высота.</param>
        private static void NearestNeighbor(UnmanagedBitmap sourceData, UnmanagedBitmap destinationData, int newWidth, int newHeight)
        {
            int    pixelSize = Image.GetPixelFormatSize(sourceData.PixelFormat) / 8;
            int    srcStride = sourceData.Stride;
            int    dstStride = destinationData.Stride;
            double xFactor   = (double)sourceData.Width / newWidth;
            double yFactor   = (double)sourceData.Height / newHeight;
            byte * baseSrc   = (byte *)(void *)sourceData.ImageData;
            byte * baseDst   = (byte *)(void *)destinationData.ImageData;

            for (int y = 0; y < newHeight; y++)
            {
                byte *dst = baseDst + dstStride * y;
                byte *src = baseSrc + srcStride * ((int)(y * yFactor));
                byte *p;

                for (int x = 0; x < newWidth; x++)
                {
                    p = src + pixelSize * ((int)(x * xFactor));

                    for (int i = 0; i < pixelSize; i++, dst++, p++)
                    {
                        *dst = *p;
                    }
                }
            }
        }
        /// <summary>
        /// Билинейная фильтрация.
        /// </summary>
        /// <param name="sourceData">Исходное изображение.</param>
        /// <param name="destinationData">Изображение назначения.</param>
        /// <param name="newWidth">Новая ширина.</param>
        /// <param name="newHeight">новая высота.</param>
        private static void Bilinear(UnmanagedBitmap sourceData, UnmanagedBitmap destinationData, int newWidth, int newHeight)
        {
            int    pixelSize = Image.GetPixelFormatSize(sourceData.PixelFormat) / 8;
            int    srcStride = sourceData.Stride;
            int    dstOffset = destinationData.Stride - pixelSize * newWidth;
            double xFactor   = (double)sourceData.Width / newWidth;
            double yFactor   = (double)sourceData.Height / newHeight;
            byte * src       = (byte *)(void *)sourceData.ImageData;
            byte * dst       = (byte *)(void *)destinationData.ImageData;

            double ox, oy, dx1, dy1, dx2, dy2;
            int    ox1, oy1, ox2, oy2;

            int ymax = sourceData.Height - 1;
            int xmax = sourceData.Width - 1;

            byte *tp1, tp2;
            byte *p1, p2, p3, p4;

            for (int y = 0; y < newHeight; y++)
            {
                oy  = y * yFactor;
                oy1 = (int)oy;
                oy2 = (oy1 == ymax) ? oy1 : oy1 + 1;
                dy1 = oy - oy1;
                dy2 = 1.0 - dy1;

                tp1 = src + oy1 * srcStride;
                tp2 = src + oy2 * srcStride;

                for (int x = 0; x < newWidth; x++)
                {
                    ox  = x * xFactor;
                    ox1 = (int)ox;
                    ox2 = (ox1 == xmax) ? ox1 : ox1 + 1;
                    dx1 = ox - ox1;
                    dx2 = 1.0 - dx1;

                    p1 = tp1 + ox1 * pixelSize;
                    p2 = tp1 + ox2 * pixelSize;
                    p3 = tp2 + ox1 * pixelSize;
                    p4 = tp2 + ox2 * pixelSize;

                    for (int i = 0; i < pixelSize; i++, dst++, p1++, p2++, p3++, p4++)
                    {
                        *dst = (byte)(dy2 * (dx2 * (*p1) + dx1 * (*p2)) + dy1 * (dx2 * (*p3) + dx1 * (*p4)));
                    }
                }

                dst += dstOffset;
            }
        }
Exemple #5
0
        /// <summary>
        /// Возвращает полную копию экземпляра <see cref="UnmanagedBitmap"/>.
        /// </summary>
        /// <returns></returns>
        public UnmanagedBitmap Clone()
        {
            IntPtr newImageData = Marshal.AllocHGlobal(Stride * Height);

            GC.AddMemoryPressure(Stride * Height);

            UnmanagedBitmap newImage = new UnmanagedBitmap(newImageData, Width, Height, Stride, PixelFormat)
            {
                disposed = true
            };

            CopyUnmanagedMemory(newImageData, ImageData, Stride * Height);

            return(newImage);
        }
Exemple #6
0
        /// <summary>
        /// Получает неуправляемый экземпляр <see cref="UnmanagedBitmap"/> из управляемого <see cref="Bitmap"/>.
        /// </summary>
        /// <param name="imageData">Исходный экземпляр <see cref="Bitmap"/>.</param>
        /// <returns></returns>
        public static UnmanagedBitmap FromManagedImage(Bitmap image)
        {
            UnmanagedBitmap dstImage   = null;
            BitmapData      sourceData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, image.PixelFormat);

            try
            {
                dstImage = FromManagedImage(sourceData);
            }
            finally
            {
                image.UnlockBits(sourceData);
            }

            return(dstImage);
        }
        /// <summary>
        /// Обрабатывает изображение указанным алгоритмом.
        /// </summary>
        /// <param name="sourceData">Исходное изображение.</param>
        /// <param name="destinationData">Изображение назначения.</param>
        /// <param name="newWidth">Новая ширина.</param>
        /// <param name="newHeight">новая высота.</param>
        /// <param name="algorithm">Алгоритм изменения размеров.</param>
        public static void Process(UnmanagedBitmap sourceData, UnmanagedBitmap destinationData, int newWidth, int newHeight, AntialiasingMethod algorithm)
        {
            switch (algorithm)
            {
            default:
            case AntialiasingMethod.NearestNeighbor:
                NearestNeighbor(sourceData, destinationData, newWidth, newHeight);
                break;

            case AntialiasingMethod.Bilinear:
                Bilinear(sourceData, destinationData, newWidth, newHeight);
                break;

            case AntialiasingMethod.Bicubic:
                Bicubic(sourceData, destinationData, newWidth, newHeight);
                break;
            }
        }
Exemple #8
0
        /// <summary>
        /// Получает неуправляемый экземпляр <see cref="UnmanagedBitmap"/> из <see cref="BitmapData"/>.
        /// </summary>
        /// <param name="imageData">Исходный экземпляр <see cref="BitmapData"/>.</param>
        /// <returns></returns>
        public static UnmanagedBitmap FromManagedImage(BitmapData imageData)
        {
            PixelFormat pixelFormat = imageData.PixelFormat;

            if (pixelFormat != PixelFormat.Format8bppIndexed && pixelFormat != PixelFormat.Format16bppGrayScale && pixelFormat != PixelFormat.Format24bppRgb &&
                pixelFormat != PixelFormat.Format32bppRgb && pixelFormat != PixelFormat.Format32bppArgb && pixelFormat != PixelFormat.Format32bppPArgb &&
                pixelFormat != PixelFormat.Format48bppRgb && pixelFormat != PixelFormat.Format64bppArgb && pixelFormat != PixelFormat.Format64bppPArgb)
            {
                throw new Exception("Unsupported pixel format of the source image.");
            }

            IntPtr dstImageData = Marshal.AllocHGlobal(imageData.Stride * imageData.Height);

            GC.AddMemoryPressure(imageData.Stride * imageData.Height);

            UnmanagedBitmap image = new UnmanagedBitmap(dstImageData, imageData.Width, imageData.Height, imageData.Stride, pixelFormat);

            CopyUnmanagedMemory(dstImageData, imageData.Scan0, imageData.Stride * imageData.Height);
            image.disposed = true;

            return(image);
        }
        /// <summary>
        /// Изменяет размеры исходного изображения без потерь качества.
        /// </summary>
        /// <param name="sourceData">Исходное изображение.</param>
        /// <param name="width">Новая ширина.</param>
        /// <param name="height">Новая высота.</param>
        /// <param name="algorithm">Алгоритм изменения размера.</param>
        /// <returns></returns>
        public static Bitmap Resize(this BitmapData sourceData, int width, int height, AntialiasingMethod algorithm)
        {
            Bitmap destinationImage = sourceData.PixelFormat == PixelFormat.Format8bppIndexed
                    ? UnmanagedBitmap.CreateGrayscaleImage(width, height)
                    : new Bitmap(width, height, sourceData.PixelFormat);

            BitmapData destinationData = destinationImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, sourceData.PixelFormat);

            try
            {
                using (UnmanagedBitmap unmSource = new UnmanagedBitmap(sourceData))
                    using (UnmanagedBitmap unmDestination = new UnmanagedBitmap(destinationData))
                        AntialiasingFilter.Process(unmSource, unmDestination, width, height, algorithm);
            }
            finally
            {
                destinationImage.UnlockBits(destinationData);
            }

            destinationImage.SetResolution(300, 300);

            return(destinationImage);
        }
        /// <summary>
        /// Бикубическая фильтрация.
        /// </summary>
        /// <param name="sourceData">Исходное изображение.</param>
        /// <param name="destinationData">Изображение назначения.</param>
        /// <param name="newWidth">Новая ширина.</param>
        /// <param name="newHeight">новая высота.</param>
        private static void Bicubic(UnmanagedBitmap sourceData, UnmanagedBitmap destinationData, int newWidth, int newHeight)
        {
            int    pixelSize = sourceData.PixelFormat == PixelFormat.Format8bppIndexed ? 1 : 3;
            int    srcStride = sourceData.Stride;
            int    dstOffset = destinationData.Stride - pixelSize * newWidth;
            double xFactor   = (double)sourceData.Width / newWidth;
            double yFactor   = (double)sourceData.Height / newHeight;
            byte * src       = (byte *)(void *)sourceData.ImageData;
            byte * dst       = (byte *)(void *)destinationData.ImageData;

            double ox, oy, dx, dy, k1, k2;
            int    ox1, oy1, ox2, oy2;

            double r, g, b;

            int ymax = sourceData.Height - 1;
            int xmax = sourceData.Width - 1;

            byte *p;

            if (destinationData.PixelFormat == PixelFormat.Format8bppIndexed)
            {
                for (int y = 0; y < newHeight; y++)
                {
                    oy  = y * yFactor - 0.5;
                    oy1 = (int)oy;
                    dy  = oy - oy1;

                    for (int x = 0; x < newWidth; x++, dst++)
                    {
                        ox  = x * xFactor - 0.5f;
                        ox1 = (int)ox;
                        dx  = ox - ox1;

                        g = 0;

                        for (int n = -1; n < 3; n++)
                        {
                            k1  = BicubicKernel(dy - n);
                            oy2 = oy1 + n;

                            if (oy2 < 0)
                            {
                                oy2 = 0;
                            }
                            if (oy2 > ymax)
                            {
                                oy2 = ymax;
                            }

                            for (int m = -1; m < 3; m++)
                            {
                                k2  = k1 * BicubicKernel(m - dx);
                                ox2 = ox1 + m;

                                if (ox2 < 0)
                                {
                                    ox2 = 0;
                                }
                                if (ox2 > xmax)
                                {
                                    ox2 = xmax;
                                }

                                g += k2 * src[oy2 * srcStride + ox2];
                            }
                        }

                        *dst = (byte)Math.Max(0, Math.Min(255, g));
                    }

                    dst += dstOffset;
                }
            }
            else
            {
                for (int y = 0; y < newHeight; y++)
                {
                    oy  = y * yFactor - 0.5;
                    oy1 = (int)oy;
                    dy  = oy - oy1;

                    for (int x = 0; x < newWidth; x++, dst += 3)
                    {
                        ox  = x * xFactor - 0.5;
                        ox1 = (int)ox;
                        dx  = ox - ox1;

                        r = g = b = 0;

                        for (int n = -1; n < 3; n++)
                        {
                            k1  = BicubicKernel(dy - n);
                            oy2 = oy1 + n;

                            if (oy2 < 0)
                            {
                                oy2 = 0;
                            }
                            if (oy2 > ymax)
                            {
                                oy2 = ymax;
                            }

                            for (int m = -1; m < 3; m++)
                            {
                                k2  = k1 * BicubicKernel(m - dx);
                                ox2 = ox1 + m;

                                if (ox2 < 0)
                                {
                                    ox2 = 0;
                                }
                                if (ox2 > xmax)
                                {
                                    ox2 = xmax;
                                }

                                p = src + oy2 * srcStride + ox2 * 3;

                                r += k2 * p[RGB.R];
                                g += k2 * p[RGB.G];
                                b += k2 * p[RGB.B];
                            }
                        }

                        dst[RGB.R] = (byte)Math.Max(0, Math.Min(255, r));
                        dst[RGB.G] = (byte)Math.Max(0, Math.Min(255, g));
                        dst[RGB.B] = (byte)Math.Max(0, Math.Min(255, b));
                    }

                    dst += dstOffset;
                }
            }
        }
Exemple #11
0
        /// <summary>
        /// Создаёт новый экземпляр <see cref="UnmanagedBitmap"/>.
        /// </summary>
        /// <param name="width">Ширина изображения.</param>
        /// <param name="height">Высота изображения.</param>
        /// <param name="pixelFormat">Формат битовой упаковки пикселей.</param>
        /// <returns></returns>
        public static UnmanagedBitmap Create(int width, int height, PixelFormat pixelFormat)
        {
            int bytesPerPixel = Image.GetPixelFormatSize(pixelFormat) / 8;

            //switch (pixelFormat)
            //{
            //    case PixelFormat.Format8bppIndexed:
            //        bytesPerPixel = 1;
            //        break;

            //    case PixelFormat.Format16bppGrayScale:
            //        bytesPerPixel = 2;
            //        break;

            //    case PixelFormat.Format24bppRgb:
            //        bytesPerPixel = 3;
            //        break;

            //    case PixelFormat.Format32bppRgb:
            //    case PixelFormat.Format32bppArgb:
            //    case PixelFormat.Format32bppPArgb:
            //        bytesPerPixel = 4;
            //        break;

            //    case PixelFormat.Format48bppRgb:
            //        bytesPerPixel = 6;
            //        break;

            //    case PixelFormat.Format64bppArgb:
            //    case PixelFormat.Format64bppPArgb:
            //        bytesPerPixel = 8;
            //        break;

            //    default:
            //        throw new Exception("Can not create image with specified pixel format.");
            //}

            if (width <= 0 || height <= 0)
            {
                throw new Exception("Invalid image size specified.");
            }

            int stride = width * bytesPerPixel;

            if (stride % 4 != 0)
            {
                stride += (4 - (stride % 4));
            }

            IntPtr imageData = Marshal.AllocHGlobal(stride * height);

            SetUnmanagedMemory(imageData, 0, stride * height);
            GC.AddMemoryPressure(stride * height);

            UnmanagedBitmap image = new UnmanagedBitmap(imageData, width, height, stride, pixelFormat)
            {
                disposed = true
            };

            return(image);
        }