I am creating a Postscript file from C# by printing to a Postscript printer set up to print to a file. I'm using the .NET PrintDocument class and Graphics.DrawString to render the text.
If I use a symbol or pictograph font such as Symbol or WingDings, the text is rasterized in the Postscript file. If I use e.g. Arial, then the text is not rasterized. My aim is to produce a Postscript file from my application where text using a symbol font is not rasterized.
If I print the same text using symbol font from e.g. notepad the text is not rasterized, so it doesn't at first glance appear to be a printer driver limitation.
What am I doing wrong/different that's causing the rasterization?
The printer's font substitution table is set to not substitute the font.
Symbol font is available on the printers I have tried.
Choosing another Postscript printer driver makes no difference.
Using the TextRenderer.DrawText produces the same result.
Printing using the Symbol font from other applications (Notepad, Word, etc) does not result in rasterized output.
#region Usings
using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Printing;
using System.IO;
using System.Windows.Forms;
#endregion
public class PrintingExample
{
private string _fontName;
private string _printerName;
private string _textToPrint;
//private bool endPrintFired = false;
// private bool keepGoing = true;
private Font printFont;
public PrintingExample(string fontName, string printerName, string textToPrint)
{
_fontName = fontName;
_printerName = printerName;
_textToPrint = textToPrint;
}
// The PrintPage event is raised for each page to be printed.
private void pd_PrintPage(object sender, PrintPageEventArgs ev)
{
const float fontSize = 14.0f;
var fFamily = new FontFamily(_fontName);
printFont = new Font(fFamily, fontSize, FontStyle.Regular, GraphicsUnit.Point);
var leftMargin = ev.MarginBounds.Left;
var topMargin = ev.MarginBounds.Top;
ev.Graphics.DrawString(_textToPrint, printFont, Brushes.Black, new Point(leftMargin, topMargin), new StringFormat());
// Only printing one page
ev.HasMorePages = false;
}
// Print the file.
public void Printing()
{
try
{
var outputFile = string.Empty;
try
{
outputFile = Path.Combine(#"c:\temp\print\", Path.GetRandomFileName() + ".ps");
var pd = new PrintDocument {PrinterSettings = {
PrinterName = _printerName,
PrintToFile = true,
PrintFileName = outputFile}
};
pd.PrintPage += pd_PrintPage;
PrintController pc = new StandardPrintController();
PrintController printController = new PrintControllerWithStatusDialog(pc);
pd.PrintController = printController;
// Print the document.
pd.Print();
}
finally
{
// For debugging, loads in default associated application
if (File.Exists(outputFile))
Process.Start(outputFile);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
// This is the main entry point for the application.
public static void Main(string[] args)
{
const string fontName = "Symbol";
const string printerName = "<Choose an installed Postscript printer here>";
const string textToPrint = "1234567890\r\nabcdefghijklmnopqrstuvwxyz";
var p = new PrintingExample(fontName, printerName, textToPrint);
p.Printing();
}
}
This turned out to be a bug in Windows 2012R2, 10, Server 2016, and Server 2019 (server 2008R2 was unaffected, which led us to open an MS case). Only some fonts were affected. It was resolved in the March 2021 OS updates for Windows 10, Server 2016 and Server 2019
Related
I have a requirement for a project at work to print to a thermal printer (specifically a Citizen CT-S651) that is attached to the computer via USB from ASP.NET C# Webforms. So far, I have tried a few things and did a lot of research. The main three things I have tried was using QZ Tray (formerly known as JZebra, found here https://qz.io/), however the non-free version costs too much right now, and the free version is too annoying in its popups to be of much use right now. I also tried to generate a PDF using MigraDoc (http://www.pdfsharp.net/), but when I try to print to the printer, it uses far too much paper before it even prints "Hello World" code for that shown below:
private void print()
{
Document document = CreateDocument();
document.UseCmykColor = true;
const bool unicode = false;
const PdfFontEmbedding embedding = PdfFontEmbedding.Always;
PdfDocumentRenderer pdfRenderer = new PdfDocumentRenderer(unicode, embedding);
pdfRenderer.Document = document;
pdfRenderer.RenderDocument();
//pdfRenderer.Save("C:/Users/jamesl/Documents/Visual Studio 2013/Projects/TestCheckScanner/TestCheckScanner/TestDocument.pdf");
MemoryStream stream = new MemoryStream();
pdfRenderer.PdfDocument.Save(stream, false);
Response.Clear();
Response.ContentType = "application/pdf";
Response.AddHeader("content-length", stream.Length.ToString());
Response.BinaryWrite(stream.ToArray());
Response.Flush();
stream.Close();
Response.End();
}
private Document CreateDocument()
{
Document document = new Document();
MigraDoc.DocumentObjectModel.Unit width, height;
width = MigraDoc.DocumentObjectModel.Unit.FromMillimeter(80);
height = MigraDoc.DocumentObjectModel.Unit.FromMillimeter(50);
Section section = document.AddSection();
section.PageSetup.PageHeight = height;
section.PageSetup.PageWidth = width;
section.PageSetup.PageHeight = height;
section.PageSetup.PageWidth = width;
section.PageSetup.LeftMargin = 0;
section.PageSetup.RightMargin = 0;
section.PageSetup.TopMargin = 0;
Paragraph paragraph = section.AddParagraph();
paragraph.Format.Font.Color = MigraDoc.DocumentObjectModel.Colors.Black; //Same as System.Drawing.Color
paragraph.AddFormattedText("Hello, World!");
return document;
}
Since that hasn't worked very well, I have gotten it to print a little bit using PrintDocument, however, the main problems I have with this way are twofold: 1. Formatting it print a proper receipt is going to be very tedious although if it is ends up being the best way with my current constraints I am all for it. 2. This method only works if I print from Visual Studio, when I try it on the test web app I have set up on a server, I get an error of "Settings to access printer 'CITIZEN CT-S651' are not valid." Here is my code for that:
private void print()
{
try
{
PrintDocument pd = new PrintDocument();
pd.PrintPage += new PrintPageEventHandler(pd_PrintPage);
pd.PrinterSettings.PrinterName = "CITIZEN CT-S651";
pd.Print();
}
catch (Exception ex)
{
Response.Write(ex.Message);
Response.End();
}
}
void pd_PrintPage(object sender, PrintPageEventArgs e)
{
e.Graphics.DrawString("Test Print", new System.Drawing.Font("Arial", 12), new SolidBrush(Color.Black), 60, 0);
e.Graphics.DrawString("Test Again", new System.Drawing.Font("Arial", 12), new SolidBrush(Color.Black), 60, 20);
}
Any help you can give on this matter would be awesome!
I have the following code to print something:
class Print
{
public static void print(string titel, string text, short i, Color color) {
PrintDocument doc = new PrintDocument();
doc.PrintController = new StandardPrintController();
doc.PrintPage += delegate(object sender1, PrintPageEventArgs e1)
{
e1.Graphics.DrawString(titel, new Font("Microsoft Sans Serif", 20), new SolidBrush(color), new PointF(30, 40));
PrivateFontCollection pfc = new PrivateFontCollection();
Stream fontStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(Assembly.GetExecutingAssembly().GetName().Name + ".Barc.ttf");
byte[] fontdata = new byte[fontStream.Length];
fontStream.Read(fontdata, 0, (int)fontStream.Length);
fontStream.Close();
unsafe
{
fixed (byte * pFontData = fontdata)
{
pfc.AddMemoryFont((System.IntPtr)pFontData, fontdata.Length);
}
}
e1.Graphics.DrawString("*" + text + "*", new Font(pfc.Families[0], 20), new SolidBrush(Color.Black), new PointF(30, 120));
};
doc.PrinterSettings.Copies = i;
try
{
fd.BeginInvoke(doc, null, null);
}
catch (Exception ex)
{
MessageBox.Show("error while printing: " + ex.ToString());
}
}
private delegate void FunctionDelegate(PrintDocument doc);
private static FunctionDelegate fd = new FunctionDelegate(doprint);
private static void doprint(PrintDocument doc)
{
doc.Print();
}
}
When I print something from my computer using (for example) Print.print("A1439213616", "A1439213616", 1, Color.Black) it will work correctly, using the barcode font to print the second line.
But when i copied my program onto another pc, it still printed the first line correctly, but the second line printed, in the default font instead of the custom font, #3) , +1*) +. ) . #. (the only pattern I've been able to spot so far is that the * are getting replaced with # everytime) Whats going wrong here? I am using .NET framework 3.5.
update: without changing anything, now 50% of the time it suddenly does print it correctly and 50% of the time its still the same as before.
I have SSRS report runnig on a web application. I want to print SSRS report data directly on the client's printer. The application works well in my pc but when I publish the application on IIS web server, instead of retrieving the printer settings of client pc, the application is trying to look for printers that are installed in the server machine.
I am using System.Drawing.Printing, Is there any way to get the settings of installed printer in the client computer or can we print SSRS reports from Web using C# ?
I am using following code.
using System;
using System.IO;
using System.Text;
using System.Globalization;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Printing;
using System.Collections.Specialized;
using System.Collections.Generic;
using Microsoft.Reporting.WebForms;
using SeaWorld.Common.Helper;
namespace SeaWorld.BusinessObjects.BAL.Generated
{
public class ReportPrintDocument : PrintDocument
{
private PageSettings m_pageSettings;
private int m_currentPage;
private List<Stream> m_pages = new List<Stream>();
public ReportPrintDocument(ServerReport serverReport): this((Report)serverReport)
{
RenderAllServerReportPages(serverReport);
}
//public ReportPrintDocument(LocalReport localReport): this((Report)localReport)
//{
// RenderAllLocalReportPages(localReport);
//}
private ReportPrintDocument(Report report)
{
// Set the page settings to the default defined in the report
ReportPageSettings reportPageSettings = report.GetDefaultPageSettings();
// The page settings object will use the default printer unless
// PageSettings.PrinterSettings is changed. This assumes there
// is a default printer.
m_pageSettings = new PageSettings();
m_pageSettings.PaperSize = reportPageSettings.PaperSize;
m_pageSettings.Margins = reportPageSettings.Margins;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
foreach (Stream s in m_pages)
{
s.Dispose();
}
m_pages.Clear();
}
}
protected override void OnBeginPrint(PrintEventArgs e)
{
base.OnBeginPrint(e);
m_currentPage = 0;
}
protected override void OnPrintPage(PrintPageEventArgs e)
{
base.OnPrintPage(e);
Stream pageToPrint = m_pages[m_currentPage];
pageToPrint.Position = 0;
// Load each page into a Metafile to draw it.
using (Metafile pageMetaFile = new Metafile(pageToPrint))
{
Rectangle adjustedRect = new Rectangle(
e.PageBounds.Left - (int)e.PageSettings.HardMarginX,
e.PageBounds.Top - (int)e.PageSettings.HardMarginY,
e.PageBounds.Width,
e.PageBounds.Height);
// Draw a white background for the report
e.Graphics.FillRectangle(Brushes.White, adjustedRect);
// Draw the report content
e.Graphics.DrawImage(pageMetaFile, adjustedRect);
// Prepare for next page. Make sure we haven't hit the end.
m_currentPage++;
e.HasMorePages = m_currentPage < m_pages.Count;
}
}
protected override void OnQueryPageSettings(QueryPageSettingsEventArgs e)
{
e.PageSettings = (PageSettings)m_pageSettings.Clone();
}
private void RenderAllServerReportPages(ServerReport serverReport)
{
string deviceInfo = CreateEMFDeviceInfo();
// Generating Image renderer pages one at a time can be expensive. In order
// to generate page 2, the server would need to recalculate page 1 and throw it
// away. Using PersistStreams causes the server to generate all the pages in
// the background but return as soon as page 1 is complete.
NameValueCollection firstPageParameters = new NameValueCollection();
firstPageParameters.Add("rs:PersistStreams", "True");
// GetNextStream returns the next page in the sequence from the background process
// started by PersistStreams.
NameValueCollection nonFirstPageParameters = new NameValueCollection();
nonFirstPageParameters.Add("rs:GetNextStream", "True");
string mimeType;
string fileExtension;
Stream pageStream = serverReport.Render("IMAGE", deviceInfo, firstPageParameters, out mimeType, out fileExtension);
// The server returns an empty stream when moving beyond the last page.
while (pageStream.Length > 0)
{
m_pages.Add(pageStream);
pageStream = serverReport.Render("IMAGE", deviceInfo, nonFirstPageParameters, out mimeType, out fileExtension);
}
}
private void RenderAllLocalReportPages(LocalReport localReport)
{
string deviceInfo = CreateEMFDeviceInfo();
Warning[] warnings;
localReport.Render("IMAGE", deviceInfo, LocalReportCreateStreamCallback, out warnings);
}
private Stream LocalReportCreateStreamCallback(
string name,
string extension,
Encoding encoding,
string mimeType,
bool willSeek)
{
MemoryStream stream = new MemoryStream();
m_pages.Add(stream);
return stream;
}
private string CreateEMFDeviceInfo()
{
PaperSize paperSize = m_pageSettings.PaperSize;
Margins margins = m_pageSettings.Margins;
// The device info string defines the page range to print as well as the size of the page.
// A start and end page of 0 means generate all pages.
return string.Format(
CultureInfo.InvariantCulture,
"<DeviceInfo><OutputFormat>emf</OutputFormat><StartPage>0</StartPage><EndPage>0</EndPage><MarginTop>{0}</MarginTop><MarginLeft>{1}</MarginLeft><MarginRight>{2}</MarginRight><MarginBottom>{3}</MarginBottom><PageHeight>{4}</PageHeight><PageWidth>{5}</PageWidth></DeviceInfo>",
ToInches(margins.Top),
ToInches(margins.Left),
ToInches(margins.Right),
ToInches(margins.Bottom),
ToInches(paperSize.Height),
ToInches(paperSize.Width));
}
private static string ToInches(int hundrethsOfInch)
{
double inches = hundrethsOfInch / 100.0;
return inches.ToString(CultureInfo.InvariantCulture) + "in";
}
}
}
On print button click
void ctrlSettingToolbar_btnPrintPressed(object sender, EventArgs e)
{
try
{
ReportPrintDocument rp = new ReportPrintDocument(rptBillOfLoadings.ServerReport);
rp.Print();
}
catch (Exception ex)
{
LogHelper.PrintError("Error:", ex);
}
}
You can use javascript function window.Print()
This will list you client machine printers and print your page.
Hope below code will help..try
<html>
<head>
<script>
function page()
{
window.print()
}
</script>
</head>
<body>
<input type="button" value="Print page" onclick="page()">
</body>
</html>
But this will print the whole page..in your case its a report to print
hope this link can guide you
print crystal report to client printer
print report to client default printer
What I'm trying to do is create a Windows Journal (.jrn) file from a .txt. This conversion can be done by printing to a virtual "Journal Note Writer" printer. I've been struggling with a few different methods of getting this to work for a while now, so I've decided to try to simplify things (I hope).
What I Currently Have
Process p = new Process();
p.StartInfo = new ProcessStartInfo()
{
FileName = fileToOpen, // My .txt file I'd like to convert to a .jrn
CreateNoWindow = true,
Arguments = "-print-dialog -exit-on-print"
};
p.Start();
This opens the file in Notepad, but does not open the print dialog. I'd like for the print dialog to open and ideally to be able to specify some default options in the print dialog.
Another thing I've tried is this (found in another SO question):
Process p = new Process( );
p.StartInfo = new ProcessStartInfo( )
{
CreateNoWindow = true,
Verb = "print",
FileName = fileToOpen
};
p.Start( );
The problem with this is that it just automatically prints the file to the default printer (a physical one) without giving me the option to change it.
What I'm Looking For
At this point I'm just looking for any way to print a .txt to "Windows Note Writer." I've tried doing the printing without going through an external application, and had some trouble with that as well. I haven't been able to find any other references to converting to a .jrn file, so I'm open to ANY ideas.
To get Journal Note Writer as printer you would have to add it into the printer preferences -> Add Printer (I wonder whether it could be done programmatically).
Anyways you can always get a print of a plain .txt file as described here at MSDN.
After struggling with this issue for a while, I decided to go back to trying the handle the printing directly through the application without going through Notepad. The issue I was having before when I tried this was that changing the paper size would break the resulting .jrn file (the printout would be blank). It turns out that changing some paper size settings was necessary to print on a non-native paper size.
Below is the final code in case anybody else struggles with this issue. Thanks for everybody's help.
private void btnOpenAsJRN_Click(object sender, EventArgs e) {
string fileToOpen = this.localDownloadPath + "\\" + this.filenameToDownload;
//Create a StreamReader object
reader = new StreamReader(fileToOpen);
//Create a Verdana font with size 10
lucida10Font = new Font("Lucida Console", 10);
//Create a PrintDocument object
PrintDocument pd = new PrintDocument();
PaperSize paperSize = new PaperSize("Custom", 400, 1097);
paperSize.RawKind = (int)PaperKind.Custom;
pd.DefaultPageSettings.PaperSize = paperSize;
pd.DefaultPageSettings.Margins = new Margins(20, 20, 30, 30);
pd.PrinterSettings.PrinterName = ConfigurationManager.AppSettings["journalNotePrinter"];
pd.DocumentName = this.filenameToDownload;
//Add PrintPage event handler
pd.PrintPage += new PrintPageEventHandler(this.PrintTextFileHandler);
//Call Print Method
try {
pd.Print();
}
finally {
//Close the reader
if (reader != null) {
reader.Close();
}
this.savedJnt = fileToOpen.Replace("txt", "jnt");
System.Threading.Thread.Sleep(1000);
if (File.Exists(this.savedJnt)) {
lblJntSaved.Visible = true;
lblJntSaved.ForeColor = Color.Green;
lblJntSaved.Text = "File successfully located.";
// If the file can be found, show all of the buttons for completing
// the final steps.
lblFinalStep.Visible = true;
btnMoveToSmoketown.Visible = true;
btnEmail.Visible = true;
txbEmailAddress.Visible = true;
}
else {
lblJntSaved.Visible = true;
lblJntSaved.ForeColor = Color.Red;
lblJntSaved.Text = "File could not be located. Please check your .jnt location.";
}
}
}
private void PrintTextFileHandler(object sender, PrintPageEventArgs ppeArgs) {
//Get the Graphics object
Graphics g = ppeArgs.Graphics;
float linesPerPage = 0;
float yPos = 0;
int count = 0;
//Read margins from PrintPageEventArgs
float leftMargin = ppeArgs.MarginBounds.Left;
float topMargin = ppeArgs.MarginBounds.Top;
string line = null;
//Calculate the lines per page on the basis of the height of the page and the height of the font
linesPerPage = ppeArgs.MarginBounds.Height /
lucida10Font.GetHeight(g);
//Now read lines one by one, using StreamReader
while (count < linesPerPage &&
((line = reader.ReadLine()) != null)) {
//Calculate the starting position
yPos = topMargin + (count *
lucida10Font.GetHeight(g));
//Draw text
g.DrawString(line, lucida10Font, Brushes.Black,
leftMargin, yPos, new StringFormat());
//Move to next line
count++;
}
//If PrintPageEventArgs has more pages to print
if (line != null) {
ppeArgs.HasMorePages = true;
}
else {
ppeArgs.HasMorePages = false;
}
}
how to print a text file based on given filename through a printer automatically with out any manual hand work it was doing in C sharp window services, it was not working for me , any one give me suggestions .
using System.Management;
private Font printFont;
private StreamReader streamToPrint;
private void GetPrinters(string fileName)
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_Printer");
string printerName = "";
foreach (ManagementObject printer in searcher.Get())
{
printerName = printer["Name"].ToString().ToLower();
if (printerName.Equals(#"\\chenraqdc1.raqmiyat.local\hp laserjet black chennai"))
{
Console.WriteLine("Printer = " + printer["Name"]);
if (printer["WorkOffline"].ToString().ToLower().Equals("true"))
{
// printer is offline by user
label1.Text = "Your Plug-N-Play printer is not connected.";
}
else
{streamToPrint = new StreamReader(fileName);
printFont = new Font("Arial", 10);
PrintDocument pd = new PrintDocument();
pd.PrintPage += new PrintPageEventHandler
(this.pd_PrintPage);
pd.Print();
streamToPrint.Close();
}
}
}
}
private void pd_PrintPage(object sender, PrintPageEventArgs ev)
{
float linesPerPage = 0;
float yPos = 0;
int count = 0;
float leftMargin = ev.MarginBounds.Left;
float topMargin = ev.MarginBounds.Top;
string line = null;
// Calculate the number of lines per page.
linesPerPage = ev.MarginBounds.Height /
printFont.GetHeight(ev.Graphics);
// Print each line of the file.
while (count < linesPerPage &&
((line = streamToPrint.ReadLine()) != null))
{
yPos = topMargin + (count *
printFont.GetHeight(ev.Graphics));
ev.Graphics.DrawString(line, printFont, Brushes.Black,
leftMargin, yPos, new StringFormat());
count++;
}
You can do something like this...
Note : this is sample code how to print pdf file using c# window services, if you want to print the text files you can change this code
Windows Form with a Button (cmdGetPrinters) and a ListView
(lstPrinters). The list view has two columns defined - "Property" and
"Value" which would describe the printers installed on the local
machine. The following code does the magic.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data; System.Drawing;
using System.Text; System.Windows.Forms;
using System.Management;
using System.Management.Instrumentation;
public partial class frmPrintDisplay : Form
{
public frmPrintDisplay()
{
InitializeComponent();
}
private void cmdGetPrinters_Click(object sender, EventArgs e)
{
ObjectQuery query = new ObjectQuery("SELECT * FROM Win32_Printer");
ManagementObjectSearcher mo = new ManagementObjectSearcher(query);
ManagementObjectCollection printers = mo.Get();
foreach (ManagementObject printer in printers)
{
PropertyDataCollection printerProperties = printer.Properties;
string printerPath = printer.Path.ToString() ;
PropertyDataCollection.PropertyDataEnumerator test =
printer.Properties.GetEnumerator();
while(! (test.MoveNext()== false ))
{
lstPrinters.Items.Add(
new ListViewItem( new string[]
{
test.Current.Name,
(
(test.Current.Value == null) ?
"n/a" : test.Current.Value.ToString()
)
})
);
}
}
}
}
This image shows the result of this small windows app. Note the "Name" property, this will be used to send the text file to the printer. This is shown under the "ShareName" property of the printer. On a test machine, which is also in the same domain/workgroup,you have to install a new network printer, and pointed the installation to look at the shared printer on the first computer. This in effect made the first computer a printer server, and you able to closelly replicate the setup for the client.
Now onto the test machine... The application above mentioned code building saves the text files into a temporary directory called C:\Program Files[Application Name]\Temp\
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data; System.Drawing;
using System.IO;
using System.Text; System.Windows.Forms;
using System.Management;
using System.Management.Instrumentation;
private void print(ref DirectoryInfo tempDir)
{
try
{
foreach(FileInfo file in tempDir.GetFiles("*.pdf"))
{
file.CopyTo("\\\\XYZ\\Phaser77\\" + file.Name);
}
}
catch(Exception ee){ }
}
i hope it will helps you