2

RenderTargetBitmap removes downgrades a RichtextBox's TextRenderingMode to GreyScale. So a captured PNG looks poor quality and doesnt match the WPF control

If I use WINDOWS ALT+PRINT SCREEN, the text is captured perfectly.

So how can I render the text control to the same quality as ALT+PRINT SCREEN.

Any advice would seriously be appreciated

All the best

TommyGuns21
  • 259
  • 2
  • 9

1 Answers1

2

You can use the same technique to render your window into the bitmap as windows using when taking a screen shot with Alt + Print Screen. The idea is to get a window handle and then render it to a bitmap using BitBlt system call.

Below is an example (you would need to reference the System.Drawing.dll assembly in your project to make it work):

public static void SaveToBitmapNative(Window window, FrameworkElement element, string fileName)
{
    WindowInteropHelper helper = new WindowInteropHelper(window);

    // detect the window client area position if rendering a child element
    double incX = 0, incY = 0;
    if (window != element)
    {
        System.Drawing.Point pos = new System.Drawing.Point(0, 0);
        ClientToScreen(helper.Handle, ref pos);
        incX = pos.X - (int)window.Left;
        incY = pos.Y - (int)window.Top;
    }

    // transform child position to window coordinates
    GeneralTransform transform = element.TransformToVisual(window);
    Point point = transform.Transform(new Point(0, 0));
    Rect rect = new Rect(point.X + incX, point.Y + incY, element.ActualWidth, element.ActualHeight);

    // render window into bitmap
    using (System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(
        (int)rect.Width, (int)rect.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
    {
        using (System.Drawing.Graphics memoryGraphics = System.Drawing.Graphics.FromImage(bitmap))
        {
            IntPtr dc = memoryGraphics.GetHdc();
            IntPtr windowDC = GetWindowDC(helper.Handle);

            BitBlt(dc, 0, 0, (int)rect.Width, (int)rect.Height,
                    windowDC, (int)rect.Left, (int)rect.Top, TernaryRasterOperations.SRCCOPY);

            memoryGraphics.ReleaseHdc(dc);
            ReleaseDC(helper.Handle, windowDC);
        }
        // save bitmap to file
        bitmap.Save(fileName);
    }
}

[DllImport("gdi32.dll")]
static extern bool BitBlt(IntPtr hdcDest, int xDest, int yDest, int wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, TernaryRasterOperations rop);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr ptr);
[DllImport("user32.dll")]
static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDc);
[DllImport("user32.dll")]
static extern bool ClientToScreen(IntPtr hWnd, ref System.Drawing.Point lpPoint);

public enum TernaryRasterOperations : uint
{
    SRCCOPY = 0x00CC0020,
    SRCPAINT = 0x00EE0086,
    SRCAND = 0x008800C6,
    SRCINVERT = 0x00660046,
    SRCERASE = 0x00440328,
    NOTSRCCOPY = 0x00330008,
    NOTSRCERASE = 0x001100A6,
    MERGECOPY = 0x00C000CA,
    MERGEPAINT = 0x00BB0226,
    PATCOPY = 0x00F00021,
    PATPAINT = 0x00FB0A09,
    PATINVERT = 0x005A0049,
    DSTINVERT = 0x00550009,
    BLACKNESS = 0x00000042,
    WHITENESS = 0x00FF0062
}

here's how you can call this

private void saveButton_Click(object sender, RoutedEventArgs e)
{
    // saves the entire window into the bitmap
    SaveToBitmapNative(this, this, "c:\\test0.png");
    // saves a child control (RichTextBox) into the bitmap
    SaveToBitmapNative(this, richTextBox, "c:\\test1.png"); 
}

Note: this would not work for layered windows updated via UpdateLayeredWindow function.

hope this helps, regards

serge_gubenko
  • 20,186
  • 2
  • 61
  • 64
  • Hi Serge,thankyou for your answer, however (I didnt explain this correctly),i need to capture the text within the richtextbox with its background transparent, not as part of the screen. Rendertargetbitmap copies the control and capture the png so what is behind it is not in the bitmap. – TommyGuns21 Mar 14 '11 at 08:28