I am making a program that can write in Bengali (a virtual keyboard) or in English. Everything was perfect until I started programming the printing. The user should be able to select any text and change the font and color. Because every character could be different, I need to print character by character. Here is my code:
private void printToolStripMenuItem_Click(object sender, EventArgs e)
{
PrintDialog print = new PrintDialog();
doc = new System.Drawing.Printing.PrintDocument();
print.Document = doc;
doc.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(printDoc);
if (print.ShowDialog() == DialogResult.OK)
{
doc.Print();
}
}
private void printDoc(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
System.IO.StringReader reader = new System.IO.StringReader(richTextBox1.Text);
float linesPerPage = 0;
float yPosition = 0;
int count = 0;
float leftMargin = e.MarginBounds.Left;
float rightMargin = e.MarginBounds.Right;
float topMargin = e.MarginBounds.Top;
string line = null;
Font printFont = this.richTextBox1.Font;
SolidBrush printBrush = new SolidBrush(Color.Black);
int charpos = 0;
int xPosition = (int)leftMargin;
linesPerPage = e.MarginBounds.Height / printFont.GetHeight(e.Graphics);
while (count < linesPerPage && ((line = reader.ReadLine()) != null))
{
xPosition = (int)leftMargin;
yPosition = topMargin + (count * printFont.GetHeight(e.Graphics));
count++;
for (int i = 0; i < line.Length; i++)
{
richTextBox1.Select(charpos, 1);
if ((xPosition + ((int)e.Graphics.MeasureString(richTextBox1.SelectedText, richTextBox1.SelectionFont).Width)) > rightMargin)
{
count++;
if (!(count < linesPerPage))
{
break;
}
xPosition = (int)leftMargin;
yPosition = topMargin + (count * printFont.GetHeight(e.Graphics));
}
printBrush = new SolidBrush(richTextBox1.SelectionColor);
e.Graphics.DrawString(richTextBox1.SelectedText, richTextBox1.SelectionFont, printBrush, new PointF(xPosition, yPosition));
xPosition += ((int)e.Graphics.MeasureString(richTextBox1.SelectedText, richTextBox1.SelectionFont).Width);
charpos++;
}
}
if (line != null)
{
e.HasMorePages = true;
}
else
{
e.HasMorePages = false;
printBrush.Dispose();
}
}
However, when I get a print preview, it shows a space between each of the the characters:
I think this is because e.Graphics.MeasureString() is not giving me the tightest bounding box possible, or it's not giving me the exact width of the character as specified by the font. I'm quite new to C# Anyone know of a way to get the exact width of a character? It's been stumping me for a long time.
According to this MSDN article:
The (Graphics Class) MeasureString method is designed for use with individual string and includes a small amount of extra space before and after the string to allow for overhanging glyphs
You can instead use TextRenderer.MeasureString() to get the precise font width.
GOT IT. Finally. You need to use e.Graphics.MeasureString() after all. Just another overload of it. Use this:
e.Graphics.MeasureString(richTextBox1.SelectedText, richTextBox1.SelectionFont, new PointF(xPosition, yPosition), StringFormat.GenericTypographic).Width;
To remove the space you need to pass StringFormat.GenericTypographic. Hope it helps. (you can use my code for printing text with different color and text if you replace e.Graphics.MeasureString(string, Font) with the above).
Related
using C#, I wrote the below code to print out images in an array (size = totalToPrint) of Picturebox pictureBoxArr[] each in size of 100x100 pixel. I want to print them vertically with the 20-pixel distance between them heightDistanceBetweenImages the problem is that it only prints on 1 page (say letter size) no matter how many images ( then it only prints 8 images and dismisses the rest). How can I solve this problem, and print it on multiple pages?
int totalToPrint;
int xFirstAncorPoint = 100;
int yFirstAncorPoint = 100;
int ImagSize = 100; // Squre of 100x100 pixel
int heightDistanceBetweenImages = 20;
PrintDialog pd = new PrintDialog();
PrintDocument pDoc = new PrintDocument();
pDoc.PrintPage += PrintPicture;
pd.Document = pDoc;
if (pd.ShowDialog() == DialogResult.OK)
{
pDoc.Print();
}
}
public void PrintPicture(Object sender, PrintPageEventArgs e)
{
Bitmap bmp1 = new Bitmap(ImagSize , totalToPrint * (ImagSize + heightDistanceBetweenImages));
for (int i = 0; i < totalToPrint; i++)
{
pictureBoxArr[i].DrawToBitmap(bmp1, new Rectangle(0, i * (heightDistanceBetweenImages + ImagSize), pictureBoxArr[0].Width, pictureBoxArr[0].Height));
}
e.Graphics.DrawImage(bmp1, xFirstAncorPoint, yFirstAncorPoint);
bmp1.Dispose();
}
You are about half way there. PrintDocument would be your future reference.
The PrintPage gives you more than just a drawing space; it also has your page bounds, page margins, etc. It also has HasMorePages property that you set if you need to print more pages. This property defaults to false, so you were only printing 1 page. Also if anything is outside the bounds of the page, it would not print that. With a little change here and there, you would end up with something like this.
// using queue to manage images to print
Queue<Image> printImages = new Queue<Image>();
int totalToPrint;
int xFirstAncorPoint = 100;
int yFirstAncorPoint = 100;
int ImagSize = 100; // Squre of 100x100 pixel
int heightDistanceBetweenImages = 20;
private void btnPrintTest_Click(object sender, EventArgs e) {
PrintDialog pd = new PrintDialog();
PrintDocument pDoc = new PrintDocument();
pDoc.PrintPage += PrintPicture;
pd.Document = pDoc;
if (pd.ShowDialog() == DialogResult.OK) {
// add image references to printImages queue.
for (int i = 0; i < pictureBoxArr.Length; i++) {
printImages.Enqueue(pictureBoxArr[i].Image);
}
pDoc.Print();
}
}
private void PrintPicture(object sender, PrintPageEventArgs e) {
int boundsHeight = e.MarginBounds.Height; // Get height of bounds that we are expected to print in.
int currentHeight = yFirstAncorPoint;
while (currentHeight <= boundsHeight && printImages.Count > 0) {
var nextImg = printImages.Peek();
int nextElementHeight = nextImg.Height + heightDistanceBetweenImages;
if (nextElementHeight + currentHeight <= boundsHeight) {
e.Graphics.DrawImage(nextImg, new PointF(xFirstAncorPoint, currentHeight + heightDistanceBetweenImages));
printImages.Dequeue();
}
currentHeight += nextElementHeight;
}
// how we specify if we may have more pages to print
e.HasMorePages = printImages.Count > 0;
}
Hopefully this gets you on the right path and with some minor tweaks for your code, you will have what you need.
I have the following issue when trying to draw a string and then printing it to PDF by Amyuni Printer :
where I couldn't select the text when pressing (Ctrl+A) , I need this PDF file to use it into another PDF reader , and it seems that the reader , tries to read the selected area not the actual text area .
I'm using the following code to do this stuff :
Font printFont = new Font("Simplified Arabic Fixed", (float)11, FontStyle.Regular);
StreamReader Printfile;
using (StreamReader Printfile = new StreamReader(#"C:\20_2.txt", Encoding.Default))
{
try
{
PrintDocument docToPrint = new PrintDocument();
PaperSize ps = new PaperSize("A4", 827, 1169);
bool bolFirstPage = true;
docToPrint.DefaultPageSettings.PaperSize = ps;
docToPrint.DefaultPageSettings.Landscape = true;
docToPrint.DocumentName = "docName" + DateTime.Now.Ticks.ToString(); //Name that appears in the printer queue
string FirstLine = Printfile.ReadLine();
bool bIsArabic = true;
docToPrint.PrintPage += (s, ev) =>
{
float nFontHight = printFont.GetHeight(ev.Graphics);
bIsArabic = true;
float linesPerPage = 0;
float yPos = 0;
int count = 0;
float leftMargin = 1008;
float topMargin = 120;
string line = null;
//Calculate the number of lines per page.
linesPerPage = ev.MarginBounds.Height / printFont.GetHeight(ev.Graphics) + 2;
Image img = Image.FromFile(#"C:\image.bmp");
ev.Graphics.DrawImage(img, 6, 1, 1095, 728);
//***Image Reslution is Working good -->***
StringFormat format = new StringFormat()/*arabic*/;
line = Printfile.ReadLine();
format = new StringFormat(StringFormatFlags.DisplayFormatControl | StringFormatFlags.DirectionRightToLeft)/*arabic*/;
do
{
yPos = topMargin + ((count) * printFont.GetHeight(ev.Graphics) * (float)0.91);
line = " تجربة تجربة تجربة تجربة تجربة";
ev.Graphics.DrawString(line, printFont, Brushes.DeepPink, leftMargin, yPos, format);
count++;
} while ((line = Printfile.ReadLine()) != null && !line.Contains(''));// lines contains \0 as UniCode
// If more lines exist, print another page.
if (line != null)
ev.HasMorePages = true;
else
ev.HasMorePages = false;
};
docToPrint.Print();
}
catch (System.Exception f)
{
MessageBox.Show(f.Message);
}
}
}
when I'm using another font type like "Arial" I can select near to 90% of the text, but unfortunately I have to use only the font type "Simplified Arabic Fixed" , and I'm using windows server 2003.
one more thing , when i try to print directly Arabic text from notepad it's work fine.
I've got the following code, and looked at as many similar questions on here and google, but all solutions have the same flaw, when the content in the RTB is longer than one page, or more than one or two lines, it prints an infinite number of pages. What should be changed to only print the correct number of pages?
private void PrintButton_Click(object sender, EventArgs e)
{
if (MainTabSet.TabCount > 0)
{
RichTextBox textbox = (RichTextBox)MainTabSet.SelectedTab.Controls["TabTextBox"];
PrintDocument docToPrint = new PrintDocument();
docToPrint.PrintPage += new PrintPageEventHandler(PrintPageHandler);
docToPrint.DocumentName = MainTabSet.SelectedTab.Text;
PrintDialog.Document = docToPrint;
if(PrintDialog.ShowDialog() == DialogResult.OK)
{
docToPrint.Print();
}
}
}
private void PrintPageHandler(object sender, PrintPageEventArgs e)
{
if (MainTabSet.TabCount > 0)
{
RichTextBox textbox = (RichTextBox)MainTabSet.SelectedTab.Controls["TabTextBox"];
StringReader reader = new StringReader(textbox.Text);
float linesPerPage = 0.0f;
float yPosition = 0.0f;
int count = 0;
float leftMargin = e.MarginBounds.Left;
float rightMargin = e.MarginBounds.Right;
float topMargin = e.MarginBounds.Top;
string line = null;
Font printFont = textbox.Font; //maybe do selection font
SolidBrush printBrush = new SolidBrush(textbox.ForeColor);//Maybe do selection color
int charPos = 0;
int xPosition = (int)leftMargin;
linesPerPage = e.MarginBounds.Height / printFont.GetHeight(e.Graphics);
while (count < linesPerPage && ((line = reader.ReadLine()) != null))
{
xPosition = (int)leftMargin;
yPosition = topMargin + (count * printFont.GetHeight(e.Graphics));
count++;
for (int i = 0; i < line.Length; i++)
{
textbox.Select(charPos, 1);
if ((xPosition + ((int)e.Graphics.MeasureString(textbox.SelectedText, textbox.SelectionFont).Width)) > rightMargin)
{
count++;
if (!(count < linesPerPage))
{
break;
}
xPosition = (int)leftMargin;
yPosition = topMargin + (count * printFont.GetHeight(e.Graphics));
}
printBrush = new SolidBrush(textbox.SelectionColor);
e.Graphics.DrawString(textbox.SelectedText, textbox.SelectionFont, printBrush, new PointF(xPosition, yPosition));
xPosition += ((int)e.Graphics.MeasureString(textbox.SelectedText, textbox.SelectionFont).Width);
charPos++;
}
}
if (line != null)
{
e.HasMorePages = true;
}
else
{
e.HasMorePages = false;
printBrush.Dispose();
}
}
}
Thanks in advance for the help.
//Nodnarb3
Add this code in PrintPageHandler
private void PrintPageHandler(object sender, PrintPageEventArgs e)
{
int charactersOnPage = 0;
int linesPerPage = 0;
// Sets the value of charactersOnPage to the number of characters
// of stringToPrint that will fit within the bounds of the page.
e.Graphics.MeasureString(stringToPrint, font1,
e.MarginBounds.Size, StringFormat.GenericTypographic,
out charactersOnPage, out linesPerPage);
// Draws the string within the bounds of the page
e.Graphics.DrawString(stringToPrint, font1, Brushes.Black,
e.MarginBounds, StringFormat.GenericTypographic);
// Remove the portion of the string that has been printed.
stringToPrint = stringToPrint.Substring(charactersOnPage);
// Check to see if more pages are to be printed.
e.HasMorePages = (stringToPrint.Length > 0);
}
And the PrintButton Code
private void PrintButton_Click(object sender, EventArgs e)
{
stringToPrint = tabsProperties[tabsProperties.IndexOf(new TabProperties(this.tabControl1.SelectedIndex))].TabHtml;
printDialog1.ShowDialog();
printDocument1.Print();
}
I Have written this code to formats textbox
for (int i = 0; i < datGrid.Rows.Count - 1; i++)
{
String data = String.Format(
"{0,-18} {1,-10} {2,-10} {3,-7} {4,-10} | {5,5} ",
datGrid.Rows[i].Cells[0].Value.ToString(),
datGrid.Rows[i].Cells[1].Value.ToString(),
datGrid.Rows[i].Cells[2].Value.ToString(),
datGrid.Rows[i].Cells[3].Value.ToString(),
datGrid.Rows[i].Cells[4].Value.ToString(),
datGrid.Rows[i].Cells[5].Value.ToString());
textBox1.Text += "\n" + data;
data = "";
}
textBox1.Text += "\n------------------------------------";
textBox1.Text += "\n" +
String.Format("{0,-1}{1,-10}{2,-2}{3,-10}{4,-2}{5,-1}",
"Total :" + " ", labelTotal.Text+" ",
"Paid :" + " ", labelPaid.Text + " ",
"Balance:" + " ", labelBalance.Text);
I Used followiing code to print
streamToPrint = new StringReader(textBox1.Text);
streamToPrint.InitializeLifetimeService();
try
{
printFont = new Font("Arial", 8);
dialog.Document = pd;
PaperSize paperSize = new PaperSize("My Envelope",410,420);
pd.DefaultPageSettings.PaperSize = paperSize;
// pd.DefaultPageSettings.Landscape = true;
pd.DefaultPageSettings.Margins = new Margins(5, 5,5, 10);
pd.PrintPage += new PrintPageEventHandler (this.pd_PrintPage);
if (dialog.ShowDialog() == DialogResult.OK)
{
pd.Print();
}
}
finally
{
streamToPrint.Close();
}
And to print text following code
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 - 3,
yPos - 5, new StringFormat(StringFormatFlags.LineLimit));
count++;
}
// If more lines exist, print another page.
if (line != null)
ev.HasMorePages = true;
else
ev.HasMorePages = false;
//ev.Graphics.DrawString(textBox1.Text,
// new Font("Arial", 20, FontStyle.Regular), Brushes.Black, 20,20);
}
private void btnClose_Click(object sender, EventArgs e)
{
this.Close();
}
But I want to print in tabular format that I have given. This code is not working.
Your printFont is a proportional font (Arial) and therefore will not work with your type of tabular formatting. You have two options:
Pick a fixed size font like Consolas. This will fix the problem without hassle.
Print those chunks you feed into your formatted string separately to their respective horizontal positions. This allows you to use any Font you like.
BTW: You write that you put the same text into a TextBox. It should have the same problems, but only the first option will work there without being a pain..!
Have been looking for this from past 2days couldn't sort out, finally im here.
Now starting with the Question,
How to Print a reciept on dot matrix printer and stop after printing one reciept with out continuing to prnt complete page with white spaces from C#, iam able to print using the below JScript code, but continues to print whole page even after reciept is completed.
function Print-content() {
var DocumentContainer = document.getElementById('div2');
var WindowObject = window.open('', "PanelDetails"
,"width=1000,height=550,top=100
,left=150,toolbars=no,scrollbars=yes
,status=no,resizable=no");
WindowObject.document.writeln(DocumentContainer.innerHTML);
WindowObject.document.close();
WindowObject.focus();
WindowObject.open();
WindowObject.print();
}
But after printing half page, printer doesnt stop it proceeds and prints complete page with white spaces, well thats a usual problem seen on many sites but didn't come up with a solution, So have shifted to server side coding, using ITextSharp Dll.
Can some one please help me with complete solution for printing a reciept half Page and stop the printer after printing last line of the page, which is vertical half of the Letter Fanfold 8-1/2'' 11'' size.
for more clarity if required i will post C# code aswell, but in order not to mess i ignored the code
Thanks in advance
Here's my C# code
StringReader sr;
private void ExportDataListToPDF()
{
using (PrintDocument doc = new PrintDocument())
{
StringWriter sw = new StringWriter();
HtmlTextWriter hw = new HtmlTextWriter(sw);
this.div2.RenderControl(hw);
sr = new StringReader(sw.ToString());
doc.DocumentName = "Hello";
doc.DefaultPageSettings.Landscape = false;
PaperSize psize = new PaperSize("MyCustomSize", 216, 279);
doc.DefaultPageSettings.PaperSize = psize;
doc.PrinterSettings.DefaultPageSettings.PaperSize = psize;
psize.RawKind = (int)PaperKind.Custom;
doc.PrinterSettings.DefaultPageSettings.PaperSize.Height = doc.PrinterSettings.DefaultPageSettings.PaperSize.Height / 2;
doc.PrintPage += new PrintPageEventHandler(doc_PrintPage);
doc.PrinterSettings.PrinterName = "EPSON LQ-1150II";
doc.PrintController = new StandardPrintController();
// doc.PrinterSettings.PrintFileName = sw.ToString();
doc.Print();
}
}
public void doc_PrintPage(object sender, PrintPageEventArgs ev)
{
System.Drawing.Font printFont = new System.Drawing.Font(FontFamily.GenericSerif, 12);
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 = sr.ReadLine()) != null))
{
yPos = topMargin + (count *
printFont.GetHeight(ev.Graphics));
ev.Graphics.DrawString(line, printFont, Brushes.Black,
leftMargin, yPos, new StringFormat());
count++;
}
// If more lines exist, print another page.
if (line != null)
ev.HasMorePages = true;
else
ev.HasMorePages = false;
}