Printing only the active window in C# - c#

I want to print only the active window from a C# application. Using CopyFromScreen() does not work as it takes a screenshot and the window can be partially hidden by other transient windows appearing. So I tried PrintWindow():
private void printDocument1_PrintPage(object sender, PrintPageEventArgs e)
{
e.Graphics.PageScale = 10.0f;
Graphics g = e.Graphics;
PrintWindow(this.Handle, g.GetHdc(), 0);
}
This produces a tiny stamp-sized printout of the window regardless of which PageScale I use.
Any ideas?
EDIT
This does the trick:
private void printDocument1_PrintPage(object sender, PrintPageEventArgs e)
{
Graphics myGraphics = CreateGraphics();
var bitmap = new Bitmap(Width, Height, myGraphics);
DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
e.Graphics.DrawImage(bitmap, 0, 0);
}

Some googling around, and I found: Copying content from a hidden or clipped window in XP?
It seems you will need to prepare a bitmap for storing the page:
// Takes a snapshot of the window hwnd, stored in the memory device context hdcMem
HDC hdc = GetWindowDC(hwnd);
if (hdc)
{
HDC hdcMem = CreateCompatibleDC(hdc);
if (hdcMem)
{
RECT rc;
GetWindowRect(hwnd, &rc);
HBITMAP hbitmap = CreateCompatibleBitmap(hdc, RECTWIDTH(rc), RECTHEIGHT(rc));
if (hbitmap)
{
SelectObject(hdcMem, hbitmap);
PrintWindow(hwnd, hdcMem, 0);
DeleteObject(hbitmap);
}
DeleteObject(hdcMem);
}
ReleaseDC(hwnd, hdc);
}

Related

How to save drew Graphics of "Paint()" into image using c#?

I actually wanted to Convert RTF into Image so after googling a lot I've got a code that does it by Paint() Event of Picturebox1 and it works perfectly :
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(richTextBox1.BackColor);
e.Graphics.DrawRtfText(this.richTextBox1.Rtf, this.pictureBox1.ClientRectangle);
base.OnPaint(e);
// below code just create an empty image file
Bitmap newBitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);
e.Graphics.DrawImage(newBitmap, new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height), new Rectangle(0, 0, pictureBox1.Width, pictureBox1.Height), GraphicsUnit.Pixel);
newBitmap.Save(#"c:\adv.jpg");
}
in the picture above the left is my richTextBox and the right is a Picturebox.
the ISSUE is I don't know how to save Paint() drew graphic into a file because the 3 last lines of my code just save an empty image.
UPDATE #1:
g.SmoothingMode = SmoothingMode.AntiAlias;
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
g.Clear(richTextBox1.BackColor);
g.DrawRtfText(this.richTextBox1.Rtf, this.pictureBox1.ClientRectangle);
by changing the graphics from e.graphics to g the issue is resolved but with one other issue that the quality of bitmap is too low. I've Added this bunch of code but I've got same result, the quality is too low!
Any suggestions?
UPDATE #2
here is the Graphics_DrawRtfText class that does the conversion :
public static class Graphics_DrawRtfText
{
private static RichTextBoxDrawer rtfDrawer;
public static void DrawRtfText(this Graphics graphics, string rtf, Rectangle layoutArea)
{
if (Graphics_DrawRtfText.rtfDrawer == null)
{
Graphics_DrawRtfText.rtfDrawer = new RichTextBoxDrawer();
}
Graphics_DrawRtfText.rtfDrawer.Rtf = rtf;
Graphics_DrawRtfText.rtfDrawer.Draw(graphics, layoutArea);
}
private class RichTextBoxDrawer : RichTextBox
{
//Code converted from code found here: http://support.microsoft.com/kb/812425/en-us
//Convert the unit used by the .NET framework (1/100 inch)
//and the unit used by Win32 API calls (twips 1/1440 inch)
private const double anInch = 14.4;
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
if (SafeNativeMethods.LoadLibrary("msftedit.dll") != IntPtr.Zero)
{
createParams.ExStyle |= SafeNativeMethods.WS_EX_TRANSPARENT; // transparent
createParams.ClassName = "RICHEDIT50W";
}
return createParams;
}
}
public void Draw(Graphics graphics, Rectangle layoutArea)
{
//Calculate the area to render.
SafeNativeMethods.RECT rectLayoutArea;
rectLayoutArea.Top = (int)(layoutArea.Top * anInch);
rectLayoutArea.Bottom = (int)(layoutArea.Bottom * anInch);
rectLayoutArea.Left = (int)(layoutArea.Left * anInch);
rectLayoutArea.Right = (int)(layoutArea.Right * anInch);
IntPtr hdc = graphics.GetHdc();
SafeNativeMethods.FORMATRANGE fmtRange;
fmtRange.chrg.cpMax = -1; //Indicate character from to character to
fmtRange.chrg.cpMin = 0;
fmtRange.hdc = hdc; //Use the same DC for measuring and rendering
fmtRange.hdcTarget = hdc; //Point at printer hDC
fmtRange.rc = rectLayoutArea; //Indicate the area on page to print
fmtRange.rcPage = rectLayoutArea; //Indicate size of page
IntPtr wParam = IntPtr.Zero;
wParam = new IntPtr(1);
//Get the pointer to the FORMATRANGE structure in memory
IntPtr lParam = IntPtr.Zero;
lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange));
Marshal.StructureToPtr(fmtRange, lParam, false);
SafeNativeMethods.SendMessage(this.Handle, SafeNativeMethods.EM_FORMATRANGE, wParam, lParam);
//Free the block of memory allocated
Marshal.FreeCoTaskMem(lParam);
//Release the device context handle obtained by a previous call
graphics.ReleaseHdc(hdc);
}
#region SafeNativeMethods
private static class SafeNativeMethods
{
[DllImport("USER32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr LoadLibrary(string lpFileName);
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[StructLayout(LayoutKind.Sequential)]
public struct CHARRANGE
{
public int cpMin; //First character of range (0 for start of doc)
public int cpMax; //Last character of range (-1 for end of doc)
}
[StructLayout(LayoutKind.Sequential)]
public struct FORMATRANGE
{
public IntPtr hdc; //Actual DC to draw on
public IntPtr hdcTarget; //Target DC for determining text formatting
public RECT rc; //Region of the DC to draw to (in twips)
public RECT rcPage; //Region of the whole DC (page size) (in twips)
public CHARRANGE chrg; //Range of text to draw (see earlier declaration)
}
public const int WM_USER = 0x0400;
public const int EM_FORMATRANGE = WM_USER + 57;
public const int WS_EX_TRANSPARENT = 0x20;
}
#endregion
}
}
Disclaimer: I don't have the time to dig into the posted extension method but it is interesting and works well, at least when drawing onto a control surface.
But I could reproduce how bad the results are when drawing into a bitmap..
But: When done right the saved results are excellent!
So here here are a few things to keep in mind:
Saving in the Paint event is a bad idea, as this event will be triggered by the system whenever it needs to redraw the control; test by doing a minimize/maximize cycle.
In addition the DrawRtfText semms to create a double-vision effect when drawing into a bitmap.
So make sure you use DrawToBitmap to grab the results. For this you need to place the call to DrawRtfText in the Paint event of a control!
Also make sure to have large enough resolutions both in the control (pixel size) and the Bitmap (dpi) to get nice, crispy and (if needed) printable results.
Do not save to jpg as this is bound to result in blurry text! Png is the format of choice!
Here is a Paint event:
private void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(richTextBox1.BackColor);
e.Graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
Padding pad = new Padding(120, 230, 10, 30); // pick your own numbers!
Size sz = panel1.ClientSize;
Rectangle rect = new Rectangle(pad.Left, pad.Top,
sz.Width - pad.Horizontal, sz.Height - pad.Vertical);
e.Graphics.DrawRtfText(this.richTextBox1.Rtf, rect);
}
Note that it pays to improve on the default quality settings; if you don't the text in the resulting file will break apart when zooming in..
Here is a Save button click:
private void button1_Click(object sender, EventArgs e)
{
Size sz = panel1.ClientSize;
// first we (optionally) create a bitmap in the original panel size:
Rectangle rect1 = panel1.ClientRectangle;
Bitmap bmp = new Bitmap(rect1.Width, rect1.Height);
panel1.DrawToBitmap(bmp, rect);
bmp.Save("D:\\rtfImage1.png", ImageFormat.Png);
// now we create a 4x larger one:
Rectangle rect2 = new Rectangle(0, 0, sz.Width * 4, sz.Height * 4);
Bitmap bmp2 = new Bitmap(rect2.Width, rect2.Height);
// we need to temporarily enlarge the panel:
panel1.ClientSize = rect2.Size;
// now we can let the routine draw
panel1.DrawToBitmap(bmp2, rect2);
// and before saving we optionally can set the dpi resolution
bmp2.SetResolution(300, 300);
// optionally make background transparent:
bmp2.MakeTransparent(richTextBox1.BackColor);
UnSemi(bmp2); // see the link in the comment!
// save text always as png; jpg is only for fotos!
bmp2.Save("D:\\rtfImage2.png", ImageFormat.Png);
// restore the panels size
panel1.ClientSize = sz;
}
I found the result to be really good.
Note that DrawToBitmap will internally trigger the Paint event to grab the drawn graphics.
Of course you don't need both parts - use only the one you want (.e. skip the 1st part, between first and now ) and do use your own numbers. It helps to know what the output shall be and calculate the necessary sizes and resolutions backward from there.
I added the enlarged version because usually the monitor resolution, which is what the controls all have, is rather limited, around 75-100dpi, while print quality starts only at 150dpi..
Here is a link to the UnSemi function
Your code produces an empty image file because you are not drawing anything onto 'newBitmap'.
If you want to draw anything onto 'newBitmap' you need to create a Graphics object from it. As I do not know where 'DrawRtfText' comes from and how it works my guess would be:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
//...
Bitmap newBitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);
Graphics g = Graphics.FromImage(newBitmap);
g.DrawRtfText(this.richTextBox1.Rtf, this.pictureBox1.ClientRectangle);
newBitmap.Save(#"d:\adv.jpg");
}

How to use complete space while printing lable using c#

imageI want to print data to a label using c# application. I created the application for the same purpose. Since there is only limited space in the label, I need to use the full white space available.
Here I have attached the two pictures of the data showing in the window and in the print preview. In print preview it is shown that white space from both sides are gone.But after printing in the label there is space at both ends.
Is there any way to use the complete space.
The Code I used for the same is below.
public PrintPreviewExt()
{
InitializeComponent();
}
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern long BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
private Bitmap memoryImage;
private void PrintScreen()
{
Graphics mygraphics = this.CreateGraphics();
Size s = this.Size;
memoryImage = new Bitmap(s.Width, s.Height, mygraphics);
Graphics memoryGraphics = Graphics.FromImage(memoryImage);
IntPtr dc1 = mygraphics.GetHdc();
IntPtr dc2 = memoryGraphics.GetHdc();
BitBlt(dc2, 0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height, dc1, 0, 0, 13369376);
mygraphics.ReleaseHdc(dc1);
memoryGraphics.ReleaseHdc(dc2);
}
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawImage(memoryImage, 0, 0);
}
private void print_Click(object sender, EventArgs e)
{
print.Visible = false;
PrintScreen();
printPreviewDialog1.ShowDialog();
this.Hide();
}

Print form in Windows application

Im trying to get a button to print out my current form and have tried all the code I can find on here but it keeps printing blank pages and I cant work out why.
The code I use is as follows
Bitmap bitmap;
private void btnPrint_Click(object sender, EventArgs e)
{
//Add a Panel control.
Panel panel = new Panel();
this.Controls.Add(panel);
//Create a Bitmap of size same as that of the Form.
Graphics grp = panel.CreateGraphics();
Size formSize = this.ClientSize;
bitmap = new Bitmap(formSize.Width, formSize.Height, grp);
grp = Graphics.FromImage(bitmap);
//Copy screen area that that the Panel covers.
Point panelLocation = PointToScreen(panel.Location);
grp.CopyFromScreen(panelLocation.X, panelLocation.Y, 0, 0, formSize);
//Show the Print Preview Dialog.
printPreviewDialog1.Document = printDocument1;
printPreviewDialog1.PrintPreviewControl.Zoom = 1;
printPreviewDialog1.ShowDialog();
}
private void PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
//Print the contents.
e.Graphics.DrawImage(bitmap, 0, 0);
}
This runs from a button (btnPrint) which is on a form (Form2) along with loads of textboxes and graphics)
When clicked it brings up the print preview dialog fine but the page is blank. If I press print it prints a blank page.
Any idea why its not copying the form??
Please refer: How to: Print Preview a Form
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern long BitBlt (IntPtr hdcDest,
int nXDest, int nYDest, int nWidth, int nHeight,
IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
private Bitmap memoryImage;
private void CaptureScreen()
{
Graphics mygraphics = this.CreateGraphics();
Size s = this.Size;
memoryImage = new Bitmap(s.Width, s.Height,
mygraphics);
Graphics memoryGraphics = Graphics.FromImage(
memoryImage);
IntPtr dc1 = mygraphics.GetHdc();
IntPtr dc2 = memoryGraphics.GetHdc();
BitBlt(dc2, 0, 0, this.ClientRectangle.Width,
this.ClientRectangle.Height, dc1, 0, 0,
13369376);
mygraphics.ReleaseHdc(dc1);
memoryGraphics.ReleaseHdc(dc2);
}
private void printDocument1_PrintPage(System.Object
sender, System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawImage(memoryImage, 0, 0);
}
private void printButton_Click(System.Object sender,
System.EventArgs e)
{
CaptureScreen();
printPreviewDialog1.Document = printDocument1;
printPreviewDialog1.Show();
}

Continuous creation of bitmaps leads to memory leak

I have a thread that continuously generates bitmaps and takes a screenshot of another program's window. Now, I have a pictureBox on my form, and that's constantly being updated with the bitmaps generated. Here's the code I have in the thread:
Bitmap bitmap = null;
while (true)
{
if (listBoxIndex != -1)
{
Rectangle rect = windowRects[listBoxIndex];
bitmap = new Bitmap(rect.Width, rect.Height);
Graphics g = Graphics.FromImage(bitmap);
IntPtr hdc = g.GetHdc();
PrintWindow(windows[listBoxIndex], hdc, 0);
pictureBox1.Image = bitmap;
g.ReleaseHdc(hdc);
}
}
As you can see, this leads to a memory leak, because of the continuous call to new Bitmap(rect.Width, rect.Height). I've tried adding "bitmap.Dispose()" to the bottom of the while loop, but that leads to the pictureBox's image also being disposed, which makes a giant red X in place of the actual image. Is there any way I can dispose of "bitmap" without disposing of the pictureBox image?
You're also "leaking" the Graphics object. Try this:
while (true)
{
if (listBoxIndex != -1)
{
Rectangle rect = windowRects[listBoxIndex];
Bitmap bitmap = new Bitmap(rect.Width, rect.Height);
using (Graphics g = Graphics.FromImage(bitmap))
{
IntPtr hdc = g.GetHdc();
try
{
PrintWindow(windows[listBoxIndex], hdc, 0);
}
finally
{
g.ReleaseHdc(hdc);
}
}
if (pictureBox1.Image != null)
{
pictureBox1.Image.Dispose();
}
pictureBox1.Image = bitmap;
}
}
The answered example has a leak with Graphics g
after g.ReleaseHdc(..);
Remember to dipose the graphics variable
as for example:
g.Dispose();

C# Unmanaged code not working

This is supposed to be very simple. I basically copied the code from MSDN for printing a form in my C# winforms application. All I get when i click on "Print" is a blank sheet of paper but no error messages.
This is the link.
https://msdn.microsoft.com/en-us/library/aa287529%28v=vs.71%29.aspx
The code is:
[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern long BitBlt (IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
private Bitmap memoryImage;
private void CaptureScreen()
{
Graphics mygraphics = this.CreateGraphics();
Size s = this.Size;
memoryImage = new Bitmap(s.Width, s.Height, mygraphics);
Graphics memoryGraphics = Graphics.FromImage(memoryImage);
IntPtr dc1 = mygraphics.GetHdc();
IntPtr dc2 = memoryGraphics.GetHdc();
BitBlt(dc2, 0, 0, this.ClientRectangle.Width, this.ClientRectangle.Height, dc1, 0, 0, 13369376);
mygraphics.ReleaseHdc(dc1);
memoryGraphics.ReleaseHdc(dc2);
}
private void printDocument1_PrintPage(System.Object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawImage(memoryImage, 0, 0);
}
private void printButton_Click(System.Object sender, System.EventArgs e)
{
CaptureScreen();
printDocument1.Print();
}
All I need to do is print the current form. I just get a blank sheet of paper. I think its because of the unmanaged code(calling the dll). How do I fix this?
I tested the sample in .NET 4.5.2 and it works great.
I just get a blank sheet of paper. I think its because of the unmanaged code(calling the dll). How do I fix this?
You will get a blank sheet of paper if you don't hook up the subscriber for PrintDocument.PrintPage event.
private void printDocument1_PrintPage(Object sender, PrintPageEventArgs e)
{
e.Graphics.DrawImage(memoryImage, 0, 0);
}
The page you linked to is from 2003, likely not going to work anymore.
Here is a more recent MSDN page: How to: Print a Windows Form
You only require permissions to access the printer.
And the full code:
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Printing;
public class Form1 :
Form
{
private Button printButton = new Button();
private PrintDocument printDocument1 = new PrintDocument();
public Form1()
{
printButton.Text = "Print Form";
printButton.Click += new EventHandler(printButton_Click);
printDocument1.PrintPage += new PrintPageEventHandler(printDocument1_PrintPage);
this.Controls.Add(printButton);
}
void printButton_Click(object sender, EventArgs e)
{
CaptureScreen();
printDocument1.Print();
}
Bitmap memoryImage;
private void CaptureScreen()
{
Graphics myGraphics = this.CreateGraphics();
Size s = this.Size;
memoryImage = new Bitmap(s.Width, s.Height, myGraphics);
Graphics memoryGraphics = Graphics.FromImage(memoryImage);
memoryGraphics.CopyFromScreen(this.Location.X, this.Location.Y, 0, 0, s);
}
private void printDocument1_PrintPage(System.Object sender,
System.Drawing.Printing.PrintPageEventArgs e)
{
e.Graphics.DrawImage(memoryImage, 0, 0);
}
public static void Main()
{
Application.Run(new Form1());
}
}

Categories

Resources