예제 #1
0
        /// <summary>
        /// Converts <see cref="Image"/> to <see cref="Bitmap"/>.
        /// </summary>
        /// <param name="src"><see cref="Image"/> to be converted.</param>
        /// <returns>A new <see cref="Bitmap"/>.</returns>
        public static Bitmap ToBitmap(this Image src)
        {
            if (src == null)
            {
                throw new ArgumentNullException(nameof(src));
            }

            // Ensure image is converted to sRGB
            if (src.Bands >= 3)
            {
                src = src.Colourspace(Enums.Interpretation.Srgb);
            }

            PixelFormat pf;

            switch (src.Bands)
            {
            case 1:
                // when src.Interpretation == Enums.Interpretation.Multiband ||
                //      src.Interpretation == Enums.Interpretation.Bw ||
                //      src.Interpretation == Enums.Interpretation.Matrix
                pf = PixelFormat.Format8bppIndexed;

                // Ensure image is casted to uint8 (unsigned char)
                src = src.Cast(Enums.BandFormat.Uchar);

                break;

            case 2 when src.Interpretation == Enums.Interpretation.Grey16:
                // Convert to sRGB, since Format16bppGrayScale appears to be unsupported by GDI+.
                // See: https://stackoverflow.com/a/19706842/10952119
                src = src.Colourspace(Enums.Interpretation.Srgb);

                goto case 4;

            case 2:
                // when src.Interpretation == Enums.Interpretation.Multiband ||
                //      src.Interpretation == Enums.Interpretation.Bw
                // Add an additional band
                src = src.Bandjoin(255);

                goto case 3;

            case 3:
                pf = src.Format == Enums.BandFormat.Ushort
                        ? PixelFormat.Format48bppRgb
                        : PixelFormat.Format24bppRgb;

                {
                    // Switch from RGB to BGR
                    var rgb = src.Bandsplit();
                    using var r = rgb[0];
                    using var g = rgb[1];
                    using var b = rgb[2];

                    using (src)
                    {
                        src = b.Bandjoin(g, r);
                    }
                }

                break;

            case 4:
                pf = src.Format == Enums.BandFormat.Ushort
                        ? PixelFormat.Format64bppArgb
                        : PixelFormat.Format32bppArgb;

                {
                    // Switch from RGBA to BGRA
                    var rgba = src.Bandsplit();
                    using var r = rgba[0];
                    using var g = rgba[1];
                    using var b = rgba[2];
                    using var a = rgba[3];

                    using (src)
                    {
                        src = b.Bandjoin(g, r, a);
                    }
                }

                break;

            default:
                throw new NotImplementedException(
                          $"Number of bands must be 1 or in the in the range of 3 to 4. Got: {src.Bands}");
            }

            if (src.Format != Enums.BandFormat.Uchar || src.Format != Enums.BandFormat.Ushort)
            {
                // Pixel formats other than uchar and ushort needs to be casted to uint8 (unsigned char)
                using (src)
                {
                    src = src.Cast(Enums.BandFormat.Uchar);
                }
            }

            var dst = new Bitmap(src.Width, src.Height, pf);

            // We need to generate a greyscale palette for 8bpp images
            if (pf == PixelFormat.Format8bppIndexed)
            {
                var plt = dst.Palette;
                for (var x = 0; x < 256; x++)
                {
                    plt.Entries[x] = Color.FromArgb(x, x, x);
                }

                dst.Palette = plt;
            }

            var        w      = src.Width;
            var        h      = src.Height;
            var        bands  = src.Bands;
            var        rect   = new Rectangle(0, 0, w, h);
            BitmapData bd     = null;
            var        memory = IntPtr.Zero;

            try
            {
                bd = dst.LockBits(rect, ImageLockMode.WriteOnly, pf);
                var   dstSize = (ulong)(bd.Stride * h);
                ulong srcSize;

                using (src)
                {
                    memory = src.WriteToMemory(out srcSize);
                }

                // bd.Stride is aligned to a multiple of 4
                if (dstSize == srcSize)
                {
                    unsafe
                    {
                        Buffer.MemoryCopy(memory.ToPointer(), bd.Scan0.ToPointer(), srcSize, srcSize);
                    }
                }
                else
                {
                    var offset = w * bands;

                    // Copy the bytes from src to dst for each scanline
                    for (var y = 0; y < h; y++)
                    {
                        var pSrc = memory + y * offset;
                        var pDst = bd.Scan0 + y * bd.Stride;

                        unsafe
                        {
                            Buffer.MemoryCopy(pSrc.ToPointer(), pDst.ToPointer(), offset, offset);
                        }
                    }
                }
            }
            finally
            {
                if (bd != null)
                {
                    dst.UnlockBits(bd);
                }
                if (memory != IntPtr.Zero)
                {
                    NetVips.Free(memory);
                }
            }

            return(dst);
        }
예제 #2
0
        /// <summary>
        /// Converts <see cref="Image"/> to <see cref="Bitmap"/>.
        /// </summary>
        /// <param name="src"><see cref="Image"/> to be converted.</param>
        /// <returns>A new <see cref="Bitmap"/>.</returns>
        public static Bitmap ToBitmap(this Image src)
        {
            if (src == null)
            {
                throw new ArgumentNullException(nameof(src));
            }

            // Ensure image is casted to uint8 (unsigned char)
            if (src.Bands < 3 || src.Format != Enums.BandFormat.Ushort)
            {
                src = src.Cast(Enums.BandFormat.Uchar);
            }

            PixelFormat pf;

            switch (src.Bands)
            {
            case 1:
                pf = PixelFormat.Format8bppIndexed;
                break;

            case 2:
                // Note: Format16bppGrayScale appears to be unsupported by GDI+.
                // See: https://stackoverflow.com/a/19706842/10952119
                pf = PixelFormat.Format16bppGrayScale;

                // pf = PixelFormat.Format8bppIndexed;
                // src = src[0];
                break;

            case 3:
                pf = src.Format == Enums.BandFormat.Ushort
                        ? PixelFormat.Format48bppRgb
                        : PixelFormat.Format24bppRgb;

                // Switch from RGB to BGR
                var rgb = src.Bandsplit();
                src = rgb[2].Bandjoin(rgb[1], rgb[0]);
                break;

            case 4:
                pf = src.Format == Enums.BandFormat.Ushort
                        ? PixelFormat.Format64bppArgb
                        : PixelFormat.Format32bppArgb;

                // Switch from RGBA to BGRA
                var rgba = src.Bandsplit();
                src = rgba[2].Bandjoin(rgba[1], rgba[0], rgba[3]);
                break;

            default:
                throw new NotImplementedException(
                          $"Number of bands must be in the range of 1 to 4. Got: {src.Bands}");
            }

            var dst = new Bitmap(src.Width, src.Height, pf);

            // We need to generate a greyscale palette for 8bpp images
            if (pf == PixelFormat.Format8bppIndexed)
            {
                var plt = dst.Palette;
                for (var x = 0; x < 256; x++)
                {
                    plt.Entries[x] = Color.FromArgb(x, x, x);
                }

                dst.Palette = plt;
            }

            var        w    = src.Width;
            var        h    = src.Height;
            var        rect = new Rectangle(0, 0, w, h);
            BitmapData bd   = null;

            try
            {
                bd = dst.LockBits(rect, ImageLockMode.WriteOnly, pf);
                var dstSize = (ulong)(bd.Stride * h);
                var memory  = src.WriteToMemory(out var srcSize);

                // bd.Stride is aligned to a multiple of 4
                if (dstSize == srcSize)
                {
                    unsafe
                    {
                        Buffer.MemoryCopy(memory.ToPointer(), bd.Scan0.ToPointer(), srcSize, srcSize);
                    }
                }
                else
                {
                    var offset = w * src.Bands;

                    // Copy the bytes from src to dst for each scanline
                    for (var y = 0; y < h; y++)
                    {
                        var pSrc = memory + y * offset;
                        var pDst = bd.Scan0 + y * bd.Stride;

                        unsafe
                        {
                            Buffer.MemoryCopy(pSrc.ToPointer(), pDst.ToPointer(), offset, offset);
                        }
                    }
                }

                NetVips.Free(memory);
            }
            finally
            {
                if (bd != null)
                {
                    dst.UnlockBits(bd);
                }
            }

            return(dst);
        }