printing a wpf usercontrol on custom paper size - c#

i have a wpf usercontrol with bellow properties:
Width=170mm(642px)
Height=85mm(321px)
i want to print that on a paper with above size(Width=170mm and Height=85mm)
my problem is:when i print it,some items print out of the paper,i think the paper size if Letter by default,if it is correct,how can i change it to above Width and Height?
my code is bellow:
var p = new myUserControl();
var pDoc = new System.Windows.Controls.PrintDialog();
if (pDoc.ShowDialog().Value)
{
pDoc.PrintVisual(p, "MyPrint");
}
maybe something like this needs(this is a settings for System.Windows.Forms.PrintDialog but i use System.Windows.Controls.PrintDialog that it has no PrinterSettings property):
var printerSettings = new PrinterSettings();
var labelPaperSize = new PaperSize { RawKind = (int)PaperKind.A6, Height = 148, Width = 105 };
printerSettings.DefaultPageSettings.PaperSize = labelPaperSize;
var labelPaperSource = new PaperSource { RawKind = (int)PaperSourceKind.Manual };
printerSettings.DefaultPageSettings.PaperSource = labelPaperSource;
if (printerSettings.CanDuplex)
{
printerSettings.Duplex = Duplex.Default;
}

In WPF 1 unit = 1/96 of inch, so you can calculate your size in inches using this formula
you can set printDlg.PrintTicket.PageMediaSize to the size of the Paper and then transform your window to print in that area as below:
private void _print()
{
PrintDialog printDlg = new System.Windows.Controls.PrintDialog();
PrintTicket pt = printDlg.PrintTicket;
Double printableWidth = pt.PageMediaSize.Width.Value;
Double printableHeight = pt.PageMediaSize.Height.Value;
Double xScale = (printableWidth - xMargin * 2) / printableWidth;
Double yScale = (printableHeight - yMargin * 2) / printableHeight;
this.Transform = new MatrixTransform(xScale, 0, 0, yScale, xMargin, yMargin);
//now print the visual to printer to fit on the one page.
printDlg.PrintVisual(this, "Print Page");
}

Related

Printing a Windows Form fit to an A4 Paper [duplicate]

In C#, I am trying to print an image using PrintDocument class with the below code. The image is of size 1200 px width and 1800 px height. I am trying to print this image in a 4*6 paper using a small zeebra printer. But the program is printing only 4*6 are of the big image. that means it is not adjusting the image to the paper size !
PrintDocument pd = new PrintDocument();
pd.PrintPage += (sender, args) =>
{
Image i = Image.FromFile("C://tesimage.PNG");
Point p = new Point(100, 100);
args.Graphics.DrawImage(i, 10, 10, i.Width, i.Height);
};
pd.Print();
When i print the same image using Window Print (right click and select print, it is scaling automatically to paper size and printing correctly. that means everything came in 4*6 paper.) How do i do the same in my C# program ?
The parameters that you are passing into the DrawImage method should be the size you want the image on the paper rather than the size of the image itself, the DrawImage command will then take care of the scaling for you. Probably the easiest way is to use the following override of the DrawImage command.
args.Graphics.DrawImage(i, args.MarginBounds);
Note: This will skew the image if the proportions of the image are not the same as the rectangle. Some simple math on the size of the image and paper size will allow you to create a new rectangle that fits in the bounds of the paper without skewing the image.
Not to trample on BBoy's already decent answer, but I've done the code that maintains aspect ratio. I took his suggestion, so he should get partial credit here!
PrintDocument pd = new PrintDocument();
pd.DefaultPageSettings.PrinterSettings.PrinterName = "Printer Name";
pd.DefaultPageSettings.Landscape = true; //or false!
pd.PrintPage += (sender, args) =>
{
Image i = Image.FromFile(#"C:\...\...\image.jpg");
Rectangle m = args.MarginBounds;
if ((double)i.Width / (double)i.Height > (double)m.Width / (double)m.Height) // image is wider
{
m.Height = (int)((double)i.Height / (double)i.Width * (double)m.Width);
}
else
{
m.Width = (int)((double)i.Width / (double)i.Height * (double)m.Height);
}
args.Graphics.DrawImage(i, m);
};
pd.Print();
The solution provided by BBoy works fine. But in my case I had to use
e.Graphics.DrawImage(memoryImage, e.PageBounds);
This will print only the form. When I use MarginBounds it prints the entire screen even if the form is smaller than the monitor screen. PageBounds solved that issue. Thanks to BBoy!
You can use my code here
//Print Button Event Handeler
private void btnPrint_Click(object sender, EventArgs e)
{
PrintDocument pd = new PrintDocument();
pd.PrintPage += PrintPage;
//here to select the printer attached to user PC
PrintDialog printDialog1 = new PrintDialog();
printDialog1.Document = pd;
DialogResult result = printDialog1.ShowDialog();
if (result == DialogResult.OK)
{
pd.Print();//this will trigger the Print Event handeler PrintPage
}
}
//The Print Event handeler
private void PrintPage(object o, PrintPageEventArgs e)
{
try
{
if (File.Exists(this.ImagePath))
{
//Load the image from the file
System.Drawing.Image img = System.Drawing.Image.FromFile(#"C:\myimage.jpg");
//Adjust the size of the image to the page to print the full image without loosing any part of it
Rectangle m = e.MarginBounds;
if ((double)img.Width / (double)img.Height > (double)m.Width / (double)m.Height) // image is wider
{
m.Height = (int)((double)img.Height / (double)img.Width * (double)m.Width);
}
else
{
m.Width = (int)((double)img.Width / (double)img.Height * (double)m.Height);
}
e.Graphics.DrawImage(img, m);
}
}
catch (Exception)
{
}
}
Answer:
public void Print(string FileName)
{
StringBuilder logMessage = new StringBuilder();
logMessage.AppendLine(string.Format(CultureInfo.InvariantCulture, "-------------------[ START - {0} - {1} -------------------]", MethodBase.GetCurrentMethod(), DateTime.Now.ToShortDateString()));
logMessage.AppendLine(string.Format(CultureInfo.InvariantCulture, "Parameter: 1: [Name - {0}, Value - {1}", "None]", Convert.ToString("")));
try
{
if (string.IsNullOrWhiteSpace(FileName)) return; // Prevents execution of below statements if filename is not selected.
PrintDocument pd = new PrintDocument();
//Disable the printing document pop-up dialog shown during printing.
PrintController printController = new StandardPrintController();
pd.PrintController = printController;
//For testing only: Hardcoded set paper size to particular paper.
//pd.PrinterSettings.DefaultPageSettings.PaperSize = new PaperSize("Custom 6x4", 720, 478);
//pd.DefaultPageSettings.PaperSize = new PaperSize("Custom 6x4", 720, 478);
pd.DefaultPageSettings.Margins = new Margins(0, 0, 0, 0);
pd.PrinterSettings.DefaultPageSettings.Margins = new Margins(0, 0, 0, 0);
pd.PrintPage += (sndr, args) =>
{
System.Drawing.Image i = System.Drawing.Image.FromFile(FileName);
//Adjust the size of the image to the page to print the full image without loosing any part of the image.
System.Drawing.Rectangle m = args.MarginBounds;
//Logic below maintains Aspect Ratio.
if ((double)i.Width / (double)i.Height > (double)m.Width / (double)m.Height) // image is wider
{
m.Height = (int)((double)i.Height / (double)i.Width * (double)m.Width);
}
else
{
m.Width = (int)((double)i.Width / (double)i.Height * (double)m.Height);
}
//Calculating optimal orientation.
pd.DefaultPageSettings.Landscape = m.Width > m.Height;
//Putting image in center of page.
m.Y = (int)((((System.Drawing.Printing.PrintDocument)(sndr)).DefaultPageSettings.PaperSize.Height - m.Height) / 2);
m.X = (int)((((System.Drawing.Printing.PrintDocument)(sndr)).DefaultPageSettings.PaperSize.Width - m.Width) / 2);
args.Graphics.DrawImage(i, m);
};
pd.Print();
}
catch (Exception ex)
{
log.ErrorFormat("Error : {0}\n By : {1}-{2}", ex.ToString(), this.GetType(), MethodBase.GetCurrentMethod().Name);
}
finally
{
logMessage.AppendLine(string.Format(CultureInfo.InvariantCulture, "-------------------[ END - {0} - {1} -------------------]", MethodBase.GetCurrentMethod().Name, DateTime.Now.ToShortDateString()));
log.Info(logMessage.ToString());
}
}
Agree with TonyM and BBoy - this is the correct answer for original 4*6 printing of label. (args.PageBounds). This worked for me for printing Endicia API service shipping Labels.
private void SubmitResponseToPrinter(ILabelRequestResponse response)
{
PrintDocument pd = new PrintDocument();
pd.PrintPage += (sender, args) =>
{
Image i = Image.FromFile(response.Labels[0].FullPathFileName.Trim());
args.Graphics.DrawImage(i, args.PageBounds);
};
pd.Print();
}
all these answers has the problem, that's always stretching the image to pagesize and cuts off some content at trying this.
Found a little bit easier way.
My own solution only stretch(is this the right word?) if the image is to large, can use multiply copies and pageorientations.
PrintDialog dlg = new PrintDialog();
if (dlg.ShowDialog() == true)
{
BitmapImage bmi = new BitmapImage(new Uri(strPath));
Image img = new Image();
img.Source = bmi;
if (bmi.PixelWidth < dlg.PrintableAreaWidth ||
bmi.PixelHeight < dlg.PrintableAreaHeight)
{
img.Stretch = Stretch.None;
img.Width = bmi.PixelWidth;
img.Height = bmi.PixelHeight;
}
if (dlg.PrintTicket.PageBorderless == PageBorderless.Borderless)
{
img.Margin = new Thickness(0);
}
else
{
img.Margin = new Thickness(48);
}
img.VerticalAlignment = VerticalAlignment.Top;
img.HorizontalAlignment = HorizontalAlignment.Left;
for (int i = 0; i < dlg.PrintTicket.CopyCount; i++)
{
dlg.PrintVisual(img, "Print a Image");
}
}

Printing a stackpanel containing a listbox over multiple pages wpf

Hi I am looking to print a StackPanel that contains a listbox which can contain an infinite number of items and therefore needs to print over multiple pages. I found this code online and it works fine.
public static FixedDocument GetFixedDocument(FrameworkElement toPrint, PrintDialog printDialog)
{
if (printDialog == null)
{
printDialog = new PrintDialog();
}
var capabilities = printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket);
var pageSize = new Size(printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight);
var visibleSize = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);
var fixedDoc = new FixedDocument();
//If the toPrint visual is not displayed on screen we neeed to measure and arrange it
toPrint.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
toPrint.Arrange(new Rect(new Point(0, 0), toPrint.DesiredSize));
//
var size = toPrint.DesiredSize;
//Will assume for simplicity the control fits horizontally on the page
double yOffset = 0;
while (yOffset < size.Height)
{
var vb = new VisualBrush(toPrint)
{
Stretch = Stretch.None,
AlignmentX = AlignmentX.Left,
AlignmentY = AlignmentY.Top,
ViewboxUnits = BrushMappingMode.Absolute,
TileMode = TileMode.None,
Viewbox = new Rect(0, yOffset, visibleSize.Width, visibleSize.Height)
};
var pageContent = new PageContent();
var page = new FixedPage();
((IAddChild)pageContent).AddChild(page);
fixedDoc.Pages.Add(pageContent);
page.Width = pageSize.Width;
page.Height = pageSize.Height;
var canvas = new Canvas();
FixedPage.SetLeft(canvas, capabilities.PageImageableArea.OriginWidth);
FixedPage.SetTop(canvas, capabilities.PageImageableArea.OriginHeight);
canvas.Width = visibleSize.Width;
canvas.Height = visibleSize.Height;
canvas.Background = vb;
page.Children.Add(canvas);
yOffset += visibleSize.Height;
}
return fixedDoc;
}
However this causes certain items of a listbox to be cut off at the bottom of a page and continued on the next page (as shown below). Is it possible to modify this code in any way to determine the size of the page and if the current listboxitem does not fit onto this page that it starts on the next page? Quite new to all this so any help would be greatly appreciated.
I had a similiar task once and came up with this code, which uses a 'dummy' renderer to determine the height of the element up front and then either adds it to the current page or creates a new one. For sure, that's not a very beautiful solution, but it did the job at the time. Maybe you can take sth. away from it.
Size A4Size = new Size(793.92, 1122.24);
Size InfiniteSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
var pages = new List<FrameworkElement>();
int pageNumber = 0;
var printDate = DateTime.Now;
var size = A4Size;
var currentPage = new Report(size, printDate);
currentPage.Render();
var listElements = new Queue<ElementsToPrint>(...);
var dummyRenderer = new Viewbox();
dummyRenderer.Child = currentPage;
dummyRenderer.Measure(InfiniteSize);
dummyRenderer.Arrange(new Rect(dummyRenderer.DesiredSize));
dummyRenderer.UpdateLayout();
var template = (DataTemplate)View.FindResource("ItemTemplate");
dummyRenderer.Child = null;
var availableHeight = currentPage.View.ActualHeight;
while (listElements.Count > 0)
{
var elementToRender = listElements.Dequeue();
dummyRenderer.Child = new ListViewItem()
{
Content = elementToRender,
ContentTemplate = template,
Foreground = Brushes.Black
};
dummyRenderer.Measure(InfiniteSize);
dummyRenderer.Arrange(new Rect(dummyRenderer.DesiredSize));
dummyRenderer.UpdateLayout();
var renderedItem = (ListViewItem)dummyRenderer.Child;
dummyRenderer.Child = null;
var willItFit = availableHeight > renderedItem.ActualHeight;
if (willItFit)
{
currentPage.DataListView.Items.Add(renderedItem);
availableHeight -= renderedItem.ActualHeight;
}
else
{
dummyRenderer.Child = currentPage;
dummyRenderer.Measure(InfiniteSize);
dummyRenderer.Arrange(new Rect(dummyRenderer.DesiredSize));
dummyRenderer.UpdateLayout();
dummyRenderer.Child = null;
pages.Add(currentPage);
// Set up a new Page
pageNumber++;
currentPage = new DiaryReport(size,pageNumber,printDate,anonymous);
dummyRenderer.Child = currentPage;
dummyRenderer.Measure(InfiniteSize);
dummyRenderer.Arrange(new Rect(dummyRenderer.DesiredSize));
dummyRenderer.UpdateLayout();
dummyRenderer.Child = null;
availableHeight = currentPage.DataListView.ActualHeight;
currentPage.DataListView.Items.Add(renderedItem);
availableHeight -= renderedItem.ActualHeight;
}

Printed wpf visual is clipped in landscape mode under Windows 8.1

I have a simple wpf desktop application which prints a bitmap in landscape mode.
Under Windows 8/8.1 the printout is clipped on the bottom of the page while under Windows 7 it is printed correctly.
The code is really simple: load a bitmap, put it into an Image object, measure the printable area, arrange the image and print.
void printButton_Click(object sender, RoutedEventArgs e)
{
var pd = new PrintDialog();
if (!pd.ShowDialog().Value)
{
return;
}
pd.PrintTicket.PageOrientation = PageOrientation.Landscape;
pd.PrintTicket.PageBorderless = PageBorderless.None;
var printingCapabilities = pd.PrintQueue.GetPrintCapabilities(pd.PrintTicket);
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.UriSource = new Uri("D:\\printTest.bmp");
bitmapImage.EndInit();
var imageuiElement = new Image { Source = bitmapImage };
var desiredSize = new Size(printingCapabilities.PageImageableArea.ExtentWidth, printingCapabilities.PageImageableArea.ExtentHeight);
imageuiElement.Measure(desiredSize);
imageuiElement.Arrange(new Rect(new Point(printingCapabilities.PageImageableArea.OriginWidth, printingCapabilities.PageImageableArea.OriginHeight), imageuiElement.DesiredSize));
pd.PrintVisual(imageuiElement, "MyImage");
}
The bitmap size is 1518 x 1092 pixels, 96 DPI, which is 40.2 x 28.9 cm.
I have found the question Cannot print a document with landscape orientation under Windows 8 (WPF, .NET 4.0)
but there is no good response for my issue (additionally I have no problem with printing as landscape itself).
I have tested it with different printers of different vendors, the printouts are clipped in all of them. A software CutePDF writer prints it to PDF correctly.
Any help appreciated.
It seems that Windows 8 does not draw ui elements outside of their container bounds. This is why the printout was clipped at the bottom.
Anyway, I ended up with a code like this, which is able to print a centered bitmap on a landscape page:
printDialog.PrintTicket.PageOrientation = PageOrientation.Landscape;
printDialog.PrintTicket.PageBorderless = PageBorderless.None;
var printingCapabilities = printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket);
if (printingCapabilities.PageImageableArea == null)
{
return;
}
var document = new FixedDocument();
document.DocumentPaginator.PageSize = new Size(printingCapabilities.PageImageableArea.ExtentWidth, printingCapabilities.PageImageableArea.ExtentHeight);
foreach (var imageStream in imageStreams)
{
document.Pages.Add(GeneratePageContent(imageStream, printingCapabilities, printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight));
}
try
{
printDialog.PrintDocument(document.DocumentPaginator, GlobalConstants.SoftwareName);
}
private PageContent GeneratePageContent(Stream imageStream, PrintCapabilities printingCapabilities, double paperWidth, double paperHeight)
{
imageStream.Seek(0, SeekOrigin.Begin);
var bmp = new BitmapImage();
bmp.BeginInit();
bmp.StreamSource = imageStream;
bmp.EndInit();
var margin = new Thickness();
var pageSize = new Size();
if (printingCapabilities.PageImageableArea != null)
{
margin = new Thickness(
printingCapabilities.PageImageableArea.OriginWidth,
printingCapabilities.PageImageableArea.OriginHeight,
printingCapabilities.PageImageableArea.OriginWidth,
printingCapabilities.PageImageableArea.OriginHeight);
pageSize = new Size(printingCapabilities.PageImageableArea.ExtentWidth, printingCapabilities.PageImageableArea.ExtentHeight);
}
var imageUiElement = new Image
{
Source = bmp,
Margin = margin
};
var canvas = new Grid { Width = paperWidth, Height = paperHeight };
canvas.Children.Add(imageUiElement);
var fixedPage = new FixedPage
{
Width = paperWidth,
Height = paperHeight
};
fixedPage.Children.Add(canvas);
var pageContent = new PageContent();
((IAddChild)pageContent).AddChild(fixedPage);
pageContent.Measure(pageSize);
pageContent.Arrange(new Rect(new Point(), pageSize));
pageContent.UpdateLayout();
return pageContent;
}

Print all pages from a TableView

I am trying to print tablview in wpf but only problem i am getting it prints only first page (like took a screenshot). not all data when scroll down.
private void Print(Visual v)
{
System.Windows.FrameworkElement e = v as System.Windows.FrameworkElement;
if (e == null)
return;
PrintDialog pd = new PrintDialog();
if (pd.ShowDialog() == true)
{
Transform originalScale = e.LayoutTransform;
System.Printing.PrintCapabilities capabilities = pd.PrintQueue.GetPrintCapabilities(pd.PrintTicket);
double scale = Math.Min(capabilities.PageImageableArea.ExtentWidth / e.ActualWidth, capabilities.PageImageableArea.ExtentHeight /e.ActualHeight);
e.LayoutTransform = new ScaleTransform(scale, scale);
System.Windows.Size sz = new System.Windows.Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);
e.Measure(sz);
e.Arrange(new System.Windows.Rect(new System.Windows.Point(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight), sz));
pd.PrintTicket.PageOrientation = System.Printing.PageOrientation.Landscape;
pd.PrintVisual(v, "print chart");
e.LayoutTransform = originalScale;
}
}

Printing more than one page for control

This code will only print one page but the height of the control exceeds the page height and therefore will need to be printed on a second page. I have been doing some investigation as to what will enable the control to proceed onto another page. I got as far as DocumentPaginator and fiddled with the size making it bigger and smaller than the sz variable but no difference. Any Ideas as to what controls a creation of a new page? does the size relate to pagination?
private void Print()
{
var pd = new PrintDialog();
var document = new FixedDocument();
var fixedPage = new FixedPage();
var pageContent = new PageContent();
System.Printing.PrintCapabilities capabilities = pd.PrintQueue.GetPrintCapabilities(pd.PrintTicket);
System.Windows.Size sz = new System.Windows.Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);
MarSheetReport mar = new MarSheetReport();
document.DocumentPaginator.PageSize = sz;
Transform originalScale = fixedPage.LayoutTransform;
//get selected printer capabilities
fixedPage.LayoutTransform = new ScaleTransform(0.2823293807641634 + 0.2498215560314061, 0.2823293807641634 + 0.2498215560314061);
fixedPage.Width = sz.Width;
fixedPage.Height = sz.Height;
// Add visual, measure/arrange page.
fixedPage.Children.Add(mar.o);
fixedPage.Measure(sz);
fixedPage.Arrange(new System.Windows.Rect(new System.Windows.Point(capabilities.PageImageableArea.OriginWidth, capabilities.PageImageableArea.OriginHeight), sz));
fixedPage.UpdateLayout();
//fixedPage.LayoutTransform = originalScale;
((IAddChild)pageContent).AddChild(fixedPage);
document.Pages.Add(pageContent);
pd.PrintDocument(document.DocumentPaginator, "My Document");
}
Here is one way of doing it i.e creating the bitmap from the visual and breaking it on multiple pages.
http://www.codeproject.com/Articles/339416/Printing-large-WPF-UserControls

Categories