Ejemplo n.º 1
0
        public Composition(int width, int height, ushort bitsPerPixel)
        {
            DeviceContext = Gdi32.CreateCompatibleDC(IntPtr.Zero).ThrowWithoutLastErrorAvailableIfInvalid(nameof(Gdi32.CreateCompatibleDC));

            bitmap = Gdi32.CreateDIBSection(DeviceContext, new()
            {
                bmiHeader =
                {
                    biSize     = Marshal.SizeOf <Gdi32.BITMAPINFOHEADER>(),
                    biWidth    = width,
                    biHeight   =                                   -height,
                    biPlanes   =                                         1,
                    biBitCount = bitsPerPixel,
                },
            }, Gdi32.DIB.RGB_COLORS, out var compositionPixelDataPointer, hSection: IntPtr.Zero, offset: 0).ThrowLastErrorIfInvalid();

            Gdi32.SelectObject(DeviceContext, bitmap).ThrowWithoutLastErrorAvailableIfInvalid(nameof(Gdi32.SelectObject));

            unsafe
            {
                Pixels = new(
                    (byte *)compositionPixelDataPointer,
                    (uint)width,
                    stride : ((((uint)width * 3) + 3) / 4) * 4,
                    (uint)height);
            }
        }
Ejemplo n.º 2
0
            public void Overwrite(
                Gdi32.DeviceContextSafeHandle bitmapDC,
                Gdi32.DeviceContextSafeHandle windowDC,
                int windowClientLeft,
                int windowClientTop,
                int windowClientWidth,
                int windowClientHeight,
                uint windowDpi,
                uint zOrder)
            {
                if (windowClientWidth > 0 && windowClientHeight > 0)
                {
                    if (bitmap is null || bitmapWidth < windowClientWidth || bitmapHeight < windowClientHeight)
                    {
                        if (bitmap is null)
                        {
                            // Most of the time, windows don't resize, so save some space by not rounding up.
                            bitmapWidth  = windowClientWidth;
                            bitmapHeight = windowClientHeight;
                        }
                        else
                        {
                            // Round up to the nearest 256 pixels to minimize the number of times that bitmaps are
                            // reallocated.
                            bitmapWidth  = ((Math.Max(bitmapWidth, windowClientWidth) + 255) / 256) * 256;
                            bitmapHeight = ((Math.Max(bitmapHeight, windowClientHeight) + 255) / 256) * 256;

                            bitmap.Dispose();
                        }

                        bitmap = Gdi32.CreateDIBSection(windowDC, new()
                        {
                            bmiHeader =
                            {
                                biSize     = Marshal.SizeOf <Gdi32.BITMAPINFOHEADER>(),
                                biWidth    = bitmapWidth,
                                biHeight   =                             -bitmapHeight,
                                biPlanes   =                                         1,
                                biBitCount = BitsPerPixel,
                            },
                        }, Gdi32.DIB.RGB_COLORS, ppvBits: out _, hSection: IntPtr.Zero, offset: 0).ThrowLastErrorIfInvalid();
                    }

                    Gdi32.SelectObject(bitmapDC, bitmap).ThrowWithoutLastErrorAvailableIfInvalid(nameof(Gdi32.SelectObject));

                    if (!Gdi32.BitBlt(bitmapDC, 0, 0, windowClientWidth, windowClientHeight, windowDC, 0, 0, Gdi32.RasterOperation.SRCCOPY))
                    {
                        throw new Win32Exception();
                    }
                }

                WindowClientLeft   = windowClientLeft;
                WindowClientTop    = windowClientTop;
                WindowClientWidth  = windowClientWidth;
                WindowClientHeight = windowClientHeight;
                WindowDpi          = windowDpi;
                ZOrder             = zOrder;
            }
Ejemplo n.º 3
0
        const int CBM_INIT = 0x04;//   /* initialize bitmap */

        public static IntPtr Create32BppBitmap(Image sourceImage)
        {
            BITMAPV5HEADER bi = new BITMAPV5HEADER();

            bi.bV5Size        = (uint)Marshal.SizeOf(bi);
            bi.bV5Width       = sourceImage.Width;
            bi.bV5Height      = sourceImage.Height;
            bi.bV5Planes      = 1;
            bi.bV5BitCount    = 32;
            bi.bV5Compression = BI_BITFIELDS;
            // The following mask specification specifies a supported 32 BPP
            // alpha format for Windows XP.
            bi.bV5RedMask   = 0x00FF0000;
            bi.bV5GreenMask = 0x0000FF00;
            bi.bV5BlueMask  = 0x000000FF;
            bi.bV5AlphaMask = 0xFF000000;

            IntPtr hdc  = User32.GetDC(IntPtr.Zero);
            IntPtr bits = IntPtr.Zero;

            // Create the DIB section with an alpha channel.
            IntPtr hBitmap = Gdi32.CreateDIBSection(hdc, bi, (uint)DIB.DIB_RGB_COLORS,
                                                    out bits, IntPtr.Zero, 0);

            var hMemDC = Gdi32.CreateCompatibleDC(hdc);

            Gdi32.ReleaseDC(IntPtr.Zero, hdc);

            var sourceBits = ((Bitmap)sourceImage).LockBits(
                new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly,
                PixelFormat.Format32bppArgb);

            var stride = sourceImage.Width * 4;

            for (int y = 0; y < sourceImage.Height; y++)
            {
                IntPtr DstDib = (IntPtr)(bits.ToInt32() + (y * stride));
                IntPtr SrcDib = (IntPtr)(sourceBits.Scan0.ToInt32() + ((sourceImage.Height - 1 - y) *
                                                                       stride));

                for (int x = 0; x < sourceImage.Width; x++)
                {
                    Marshal.WriteInt32(DstDib, Marshal.ReadInt32(SrcDib));
                    DstDib = (IntPtr)(DstDib.ToInt32() + 4);
                    SrcDib = (IntPtr)(SrcDib.ToInt32() + 4);
                }
            }

            return(hBitmap);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Creates a 32 bit HBITMAP of the specified size.
        /// </summary>
        /// <param name="hdc">The HDC.</param>
        /// <param name="size">The size.</param>
        /// <param name="bits">The bits.</param>
        /// <param name="hBitmap">The bitmap handle.</param>
        /// <returns>True if the bitmap was created successfully.</returns>
        private static bool Create32BitHBITMAP(IntPtr hdc, Size size, out IntPtr bits, out IntPtr hBitmap)
        {
            //  Create a bitmap info setup for a 32 bit bitmap.
            var bi = new BITMAPINFO
            {
                bmiHeader = new BITMAPINFOHEADER
                {
                    biSize        = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)),
                    biPlanes      = 1,
                    biCompression = (uint)BI.BI_RGB,
                    biWidth       = size.Width,
                    biHeight      = size.Height,
                    biBitCount    = 32
                }
            };

            //  Create the DIB section.
            hBitmap = Gdi32.CreateDIBSection(hdc, ref bi, (uint)DIB.DIB_RGB_COLORS, out bits, IntPtr.Zero, 0);

            //  Return success only if we have a handle and bitmap bits.
            return(hBitmap != IntPtr.Zero && bits != IntPtr.Zero);
        }
Ejemplo n.º 5
0
    public void Other()
    {
        var hDc    = User32.GetWindowDC(IntPtr.Zero);
        var hMemDc = Gdi32.CreateCompatibleDC(hDc);

        var bi = new BitmapInfoHeader();

        bi.biSize         = (uint)Marshal.SizeOf(bi);
        bi.biBitCount     = 24; //Creating RGB bitmap. The following three members don't matter
        bi.biClrUsed      = 0;
        bi.biClrImportant = 0;
        bi.biCompression  = 0;
        bi.biHeight       = Height;
        bi.biWidth        = Width;
        bi.biPlanes       = 1;

        var cb = (int)(bi.biHeight * bi.biWidth * bi.biBitCount / 8); //8 is bits per byte.

        bi.biSizeImage = (uint)(((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight);
        //bi.biXPelsPerMeter = XPelsPerMeter;
        //bi.biYPelsPerMeter = YPelsPerMeter;
        bi.biXPelsPerMeter = 96;
        bi.biYPelsPerMeter = 96;

        var pBits = IntPtr.Zero;
        //Allocate memory for bitmap bits
        var pBI = Kernel32.LocalAlloc((uint)LocalMemoryFlags.LPTR, new UIntPtr(bi.biSize));

        // Not sure if this needed - simply trying to keep marshaller happy
        Marshal.StructureToPtr(bi, pBI, false);
        //This will return IntPtr to actual DIB bits in pBits
        var hBmp = Gdi32.CreateDIBSection(hDc, ref pBI, 0, out pBits, IntPtr.Zero, 0);
        //Marshall back - now we have BitmapInfoHeader correctly filled in Marshal.PtrToStructure(pBI, bi);

        var biNew = (BitmapInfoHeader)Marshal.PtrToStructure(pBI, typeof(BitmapInfoHeader));
        //Usual stuff
        var hOldBitmap = Gdi32.SelectObject(hMemDc, hBmp);
        //Grab bitmap
        var nRet = Gdi32.BitBlt(hMemDc, 0, 0, bi.biWidth, bi.biHeight, hDc, Left, Top, CopyPixelOperations.SourceCopy | CopyPixelOperations.CaptureBlt);

        // Allocate memory for a copy of bitmap bits
        var realBits = new byte[cb];

        // And grab bits from DIBSestion data
        Marshal.Copy(pBits, realBits, 0, cb);

        //This simply creates valid bitmap file header, so it can be saved to disk
        var bfh = new BitmapFileHeader();

        bfh.bfSize    = (uint)cb + 0x36; // Size of header + size of Native.BitmapInfoHeader size of bitmap bits
        bfh.bfType    = 0x4d42;          //BM
        bfh.bfOffBits = 0x36;            //
        var hdrSize = 14;
        var header  = new byte[hdrSize];

        BitConverter.GetBytes(bfh.bfType).CopyTo(header, 0);
        BitConverter.GetBytes(bfh.bfSize).CopyTo(header, 2);
        BitConverter.GetBytes(bfh.bfOffBits).CopyTo(header, 10);
        //Allocate enough memory for complete bitmap file
        var data = new byte[cb + bfh.bfOffBits];

        //BITMAPFILEHEADER
        header.CopyTo(data, 0);

        //BitmapInfoHeader
        header = new byte[Marshal.SizeOf(bi)];
        var pHeader = Kernel32.LocalAlloc((uint)LocalMemoryFlags.LPTR, new UIntPtr((uint)Marshal.SizeOf(bi)));

        Marshal.StructureToPtr(biNew, pHeader, false);
        Marshal.Copy(pHeader, header, 0, Marshal.SizeOf(bi));
        Kernel32.LocalFree(pHeader);
        header.CopyTo(data, hdrSize);
        //Bitmap bits
        realBits.CopyTo(data, (int)bfh.bfOffBits);

        //Native.SelectObject(_compatibleDeviceContext, _oldBitmap);
        //Native.DeleteObject(_compatibleBitmap);
        //Native.DeleteDC(_compatibleDeviceContext);
        //Native.ReleaseDC(_desktopWindow, _windowDeviceContext);

        Gdi32.SelectObject(hMemDc, hOldBitmap);
        Gdi32.DeleteObject(hBmp);
        Gdi32.DeleteDC(hMemDc);
        User32.ReleaseDC(IntPtr.Zero, hDc);
    }
Ejemplo n.º 6
0
        /// <summary>
        /// Copies a bitmap into a 1bpp/8bpp bitmap of the same dimensions, very fast.
        /// </summary>
        /// <param name="bitmap">A <see cref="Bitmap"/> with the output bitmap.</param>
        /// <param name="bitPerPixel">1 or 8, target bits per pixel.</param>
        /// <returns>A <see cref="Bitmap"/> with a converted copy of the bitmap.</returns>
        public static Bitmap CopyToBpp(Bitmap bitmap, int bitPerPixel)
        {
            if (bitPerPixel != 1 && bitPerPixel != 8)
            {
                throw new System.ArgumentException("1 or 8", "bpp");
            }

            // Plan: built into Windows GDI is the ability to convert
            // bitmaps from one format to another. Most of the time, this
            // job is actually done by the graphics hardware accelerator card
            // and so is extremely fast. The rest of the time, the job is done by
            // very fast native code.
            // We will call into this GDI functionality from C#. Our plan:
            // (1) Convert our Bitmap into a GDI hbitmap (ie. copy unmanaged->managed)
            // (2) Create a GDI monochrome hbitmap
            // (3) Use GDI "BitBlt" function to copy from hbitmap into monochrome (as above)
            // (4) Convert the monochrone hbitmap into a Bitmap (ie. copy unmanaged->managed)
            int    w = bitmap.Width, h = bitmap.Height;
            IntPtr hbm = bitmap.GetHbitmap(); // this is step (1)

            // Step (2): create the monochrome bitmap.
            // "BITMAPINFO" is an interop-struct which we define below.
            // In GDI terms, it's a BITMAPHEADERINFO followed by an array of two RGBQUADs
            Gdi32.BITMAPINFO bmi = new Gdi32.BITMAPINFO();
            bmi.BiSize          = 40; // the size of the BITMAPHEADERINFO struct
            bmi.BiWidth         = w;
            bmi.BiHeight        = h;
            bmi.BiPlanes        = 1;                  // "planes" are confusing. We always use just 1. Read MSDN for more info.
            bmi.BiBitCount      = (short)bitPerPixel; // ie. 1bpp or 8bpp
            bmi.BiCompression   = BIRGB;              // ie. the pixels in our RGBQUAD table are stored as RGBs, not palette indexes
            bmi.BiSizeImage     = (uint)(((w + 7) & 0xFFFFFFF8) * h / 8);
            bmi.BiXPelsPerMeter = 1000000;            // not really important
            bmi.BiYPelsPerMeter = 1000000;            // not really important

            // Now for the colour table.
            uint ncols = (uint)1 << bitPerPixel; // 2 colours for 1bpp; 256 colours for 8bpp

            bmi.BiClrUsed      = ncols;
            bmi.BiClrImportant = ncols;
            bmi.Cols           = new uint[256]; // The structure always has fixed size 256, even if we end up using fewer colours
            if (bitPerPixel == 1)
            {
                bmi.Cols[0] = MAKERGB(0, 0, 0);
                bmi.Cols[1] = MAKERGB(255, 255, 255);
            }
            else
            {
                for (int i = 0; i < 180; i++)
                {
                    bmi.Cols[i] = MAKERGB(i, i, i);
                }
            }

            // For 8bpp we've created an palette with just grayscale colours.
            // You can set up any palette you want here. Here are some possibilities:
            // greyscale: for (int i=0; i<256; i++) bmi.cols[i]=MAKERGB(i,i,i);
            // rainbow: bmi.biClrUsed=216; bmi.biClrImportant=216; int[] colv=new int[6]{0,51,102,153,204,255};
            //          for (int i=0; i<216; i++) bmi.cols[i]=MAKERGB(colv[i/36],colv[(i/6)%6],colv[i%6]);
            // optimal: a difficult topic: http://en.wikipedia.org/wiki/Color_quantization
            //
            // Now create the indexed bitmap "hbm0"
            IntPtr bits0; // not used for our purposes. It returns a pointer to the raw bits that make up the bitmap.
            IntPtr hbm0 = Gdi32.CreateDIBSection(
                IntPtr.Zero,
                ref bmi,
                DIBRGBCOLORS,
                out bits0,
                IntPtr.Zero,
                0);

            // Step (3): use GDI's BitBlt function to copy from output hbitmap into monocrhome bitmap
            // GDI programming is kind of confusing... nb. The GDI equivalent of "Graphics" is called a "DC".
            IntPtr sdc = User32.GetDC(IntPtr.Zero); // First we obtain the DC for the screen

            // Next, create a DC for the output hbitmap
            IntPtr hdc = Gdi32.CreateCompatibleDC(sdc);

            Gdi32.SelectObject(hdc, hbm);

            // and create a DC for the monochrome hbitmap
            IntPtr hdc0 = Gdi32.CreateCompatibleDC(sdc);

            Gdi32.SelectObject(hdc0, hbm0);

            // Now we can do the BitBlt:
            Gdi32.BitBlt(hdc0, 0, 0, w, h, hdc, 0, 0, Gdi32.TernaryRasterOperations.SRCCOPY);

            // Step (4): convert this monochrome hbitmap back into a Bitmap:
            Bitmap b0 = Bitmap.FromHbitmap(hbm0);

            // Finally some cleanup.
            Gdi32.DeleteDC(hdc);
            Gdi32.DeleteDC(hdc0);
            User32.ReleaseDC(IntPtr.Zero, sdc);
            Gdi32.DeleteObject(hbm);
            Gdi32.DeleteObject(hbm0);

            return(b0);
        }