private static void DrawWrapper(VisualStyleRenderer rnd, IDeviceContext dc, Rectangle bounds, DrawWrapperMethod func)
        {
            using (SafeGDIHandle primaryHdc = new SafeGDIHandle(dc))
            {
                // Create a memory DC so we can work offscreen
                using (SafeCompatibleDCHandle memoryHdc = new SafeCompatibleDCHandle(primaryHdc))
                {
                    // Create a device-independent bitmap and select it into our DC
                    BITMAPINFO info = new BITMAPINFO(bounds.Width, -bounds.Height);
                    using (SafeDCObjectHandle dib = new SafeDCObjectHandle(memoryHdc, GDI.CreateDIBSection(primaryHdc, ref info, 0, 0, IntPtr.Zero, 0)))
                    {
                        // Call method
                        func(memoryHdc);

                        // Copy to foreground
                        const int SRCCOPY = 0x00CC0020;
                        GDI.BitBlt(primaryHdc, bounds.Left, bounds.Top, bounds.Width, bounds.Height, memoryHdc, 0, 0, SRCCOPY);
                    }
                }
            }
        }
Exemplo n.º 2
0
        private unsafe GlyphData GdiCreateGlyph(GlyphIndex glyphIndex)
        {
            // Measure the size
            GDI.GLYPHMETRICS glyphMetrics;
            GDI.MAT2         matrix = new GDI.MAT2 {
                eM11 = 65536, eM12 = 0, eM21 = 0, eM22 = 65536
            };
            if (GDI.GetGlyphOutline(_gdiHdc, glyphIndex, GDI.GGO.GGO_METRICS | GDI.GGO.GGO_GLYPH_INDEX, out glyphMetrics, 0, IntPtr.Zero, ref matrix) == 0xffffffff)
            {
                throw new GDI.GDIException("GetGlyphOutline");
            }

            // Create bitmap
            GDI.BITMAPINFO bitmapInfo;
            bitmapInfo.biSize          = Marshal.SizeOf(typeof(GDI.BITMAPINFO));
            bitmapInfo.biWidth         = glyphMetrics.width + _marginInTexture * 2;
            bitmapInfo.biHeight        = glyphMetrics.height + _marginInTexture * 2;
            bitmapInfo.biPlanes        = 1;
            bitmapInfo.biBitCount      = 32;
            bitmapInfo.biCompression   = 0; //BI_RGB
            bitmapInfo.biSizeImage     = 0;
            bitmapInfo.biXPelsPerMeter = 1024;
            bitmapInfo.biYPelsPerMeter = 1024;
            bitmapInfo.biClrUsed       = 0;
            bitmapInfo.biClrImportant  = 0;
            IntPtr bitmapPtr;
            IntPtr hbitmap = GDI.CreateDIBSection(_gdiHdc, ref bitmapInfo, GDI.DIB_RGB_COLORS, out bitmapPtr, IntPtr.Zero, 0);

            if (hbitmap == IntPtr.Zero)
            {
                throw new GDI.GDIException("CreateDIBSection");
            }
            try
            {
                // Render gylph
                IntPtr selectObjectResult = GDI.SelectObject(_gdiHdc, hbitmap);
                if (selectObjectResult == IntPtr.Zero || selectObjectResult == new IntPtr(65535))
                {
                    throw new GDI.GDIException("SelectObject");
                }
                GDI.RECT rect = new GDI.RECT {
                    Left = 0, Top = 0, Right = bitmapInfo.biWidth, Bottom = bitmapInfo.biHeight
                };
                if (!GDI.ExtTextOutW(_gdiHdc, _marginInTexture - glyphMetrics.x, _marginInTexture + glyphMetrics.y - _lineAscent, GDI.ETO.ETO_OPAQUE | GDI.ETO.ETO_CLIPPED | GDI.ETO.ETO_GLYPH_INDEX, ref rect, new IntPtr(&glyphIndex), 1, IntPtr.Zero))
                {
                    throw new GDI.GDIException("ExtTextOut");
                }
                if (!GDI.GdiFlush())
                {
                    throw new GDI.GDIException("GdiFlush");
                }

                // Convert RGB GDI image to RGBA byte array
                // White color is mapped to full transparency
                byte[] imageData = new byte[bitmapInfo.biWidth * bitmapInfo.biHeight * ImageC.PixelSize];
                fixed(byte *destination2 = imageData)
                {
                    uint *source      = (uint *)bitmapPtr;
                    uint *destination = (uint *)destination2;
                    int   count       = bitmapInfo.biWidth * bitmapInfo.biHeight;

                    for (int i = 0; i < count; ++i)
                    {
                        // Optimized version of:
                        // https://stackoverflow.com/a/40862635

                        // White text
                        uint pixel  = source[i];
                        uint r      = 255 - (pixel & 0xff);
                        uint g      = 255 - ((pixel >> 8) & 0xff);
                        uint b      = 255 - ((pixel >> 16) & 0xff);
                        uint a      = 255;
                        uint factor = a == 0 ? 0xff0000 : (0xff0000 / a);
                        r = Math.Min((r * factor + 0x8000) >> 16, 255);
                        g = Math.Min((g * factor + 0x8000) >> 16, 255);
                        b = Math.Min((b * factor + 0x8000) >> 16, 255);
                        destination[i] = (a << 24) | (b << 16) | (g << 8) | r;

                        /* // Black text
                         * uint pixel = source[i];
                         * uint r = pixel & 0xff;
                         * uint g = (pixel >> 8) & 0xff;
                         * uint b = (pixel >> 16) & 0xff;
                         * uint a = 0xff - Math.Min(r, Math.Min(g, b));
                         * uint factor = a == 0 ? 0xff0000 : (0xff0000 / a);
                         * r = (0xff8000 - Math.Min(0xff8000, (255 - r) * factor)) >> 16;
                         * g = (0xff8000 - Math.Min(0xff8000, (255 - g) * factor)) >> 16;
                         * b = (0xff8000 - Math.Min(0xff8000, (255 - b) * factor)) >> 16;
                         * destination[i] = (a << 24) | (b << 16) | (g << 8) | r;
                         */
                    }
                }

                // TEST
                //ImageC.FromByteArray(imageData, bitmapInfo.biWidth, bitmapInfo.biHeight).Save("T:\\Out.png");

                // Generate output
                return(new GlyphData
                {
                    Image = ImageC.FromByteArray(imageData, bitmapInfo.biWidth, bitmapInfo.biHeight),
                    Offset = new VectorInt2(glyphMetrics.x - _marginInTexture, glyphMetrics.y + _marginInTexture)
                });
            }
            finally
            {
                GDI.DeleteObject(hbitmap);
            }
        }