I have problems with printing typing Arabic letters in C# using printdocument.
Here's my code:
PrintDocument pd;
PaperSize ps;
void pd_Factor(object sender, PrintPageEventArgs e)
{
Graphics g = e.Graphics;
Font vazir = new Font("Vazir Code FD", 12, FontStyle.Regular);
SolidBrush sb = new SolidBrush(Color.Black);
string a = "سلام";
g.DrawString(a, vazir, sb, 200, 330);
}
private void btnDone_Click(object sender, EventArgs e)
{
PrintDocument pd = new PrintDocument();
PaperSize ps = new PaperSize("Factor", 723, 1024);
pd.PrintPage += new PrintPageEventHandler(pd_Factor);
pd.PrintController = new StandardPrintController();
pd.DefaultPageSettings.Margins.Left = 0;
pd.DefaultPageSettings.Margins.Right = 0;
pd.DefaultPageSettings.Margins.Top = 0;
pd.DefaultPageSettings.Margins.Bottom = 0;
pd.DefaultPageSettings.PaperSize = ps;
printDialog1.Document = pd;
if (printDialog1.ShowDialog() == DialogResult.OK)
{
try
{
pd.Print();
}
catch (Exception)
{
}
}
}
Sadly, the above code prints this way:
By the way, I tried
StringFormat format = new StringFormat();
format.FormatFlags = StringFormatFlags.DirectionRightToLeft;
g.DrawString(a, vazir, sb, 200, 330, format);
It just make the position of anchor going from up-left to up-right this way:
So, I thought with myself, I should reverse it:
string a = "سلام";
string b = "";
for (int i = a.Length - 1; i > -1; i--)
{
b += Convert.ToString(a[i]);
}
And it made the text looks like this:
It still looks wrong but it goes better.
However I tried adding characters from left-to-right using character map.
And my code changed to:
string a = "ﻡﺎﻠﺳ";
And it prints correctly:
By the way, I have an input and I don't know what is the text going to be; so, I can't use character map for that.
Also it looks impossible or hard to code to replace the text; at least I need these characters:
My question is: How to print correctly?
Note: The font I'm using is this; However I tried using Tahoma too, but the problem still persists.
Seems strange, But magically Problem Solved!
I tried using another app to test called "Print2Pdf" and the text prints correctly, Maybe it's a bug of Microsoft XPS writer/reader that cannot print/read Arabic/Persian letters.
*Sorry for not providing link to Print2Pdf as I couldn't find the original website; If someone knows the original please add link; Thanks
Related
I am trying to figure out a way to use the StringFormat class to add new line to a given TreeNode text. For example, the string ID1:123456, ID2:789000, can be split by comma and insert a newline in between, so it has two lines.
I understand there is no need to make a TreeNode text into multiple lines, but this is required by my supervisor and I have no choice.
My current solution is to override a DrawNode function, and use the DrawString function to customize TreeNode text format, but my question is I don't know how to insert newline at this stage.
private void TreeView_SO_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
e.DrawDefault = false;
string drawString = e.Node.Text;
Font drawFont = ((TreeView)sender).Font;
SolidBrush drawBrush = new SolidBrush(Color.Black);
StringFormat drawFormat = new StringFormat();
// what to put in here to insert a new line?
e.Graphics.DrawString(drawString, drawFont, drawBrush, e.Node.Bounds, drawFormat);
}
Update
Thank you for everyone's help. I ended up finding this is quite easy, thanks to EskeRahn's codes posted on: WINDOWS TREEVIEW WITH E.G. MULTI-LINE TREE CONTENT. This code is quite useful; however, I only need part of EskeRnhn's code to perform my ideal operation. So my code ended up like this,
private void TreeView_SO_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
e.DrawDefault = false;
string drawString = e.Node.Text;
Font drawFont = ((TreeView)sender).Font;
SolidBrush drawBrush = new SolidBrush(Color.Black);
Rectangle eNodeBounds = NodeBounds(e.Node);
e.Graphics.DrawString(drawString, drawFont, drawBrush, eNodeBounds);
}
private Rectangle NodeBounds(TreeNode node)
{
if (node?.TreeView != null && node?.Text != null && (0 < node.Bounds.Location.X || 0 < node.Bounds.Location.Y))
{
using (Graphics g = node.TreeView.CreateGraphics())
{
SizeF textSize = g.MeasureString(node.Text, node.NodeFont ?? node.TreeView.Font);
return Rectangle.Ceiling(new RectangleF(PointF.Add(node.Bounds.Location,
new SizeF(0, (node.TreeView.ItemHeight - textSize.Height) / 2)),
textSize));
}
}
else
{
return node?.Bounds ?? new Rectangle();
}
}
, where I don't need to worry about the the StringFormat class at all, because I already override the a DrawNode function, so when I pass the string to TreeNode text, I just need to add newline symbols. I have tested multiple cases and this piece of code works well.
You can split the text by comma, and then join using new line.
var splitText = e.Node.Text.Split(new char[] { ',' }, System.StringSplitOptions.RemoveEmptyEntries);
var newString = string.Join(System.Environment.NewLine, splitText);
I see many reports of this and I have tried a few things that are suggested but none work in my case. I think in my case I do not understand how the PrintPreviewDialog works so I am not connecting the document with the print button correctly.
I create a document in a richtextbox that is many A4 print pages long. I then use the following from a button in the Winform. The second function is event where the pages are made. (Some of the code below comes from others so thanks to them)
private void btn_SaveBitmap_Click(object sender, EventArgs e)
{
PrintDocument printDocument1 = new PrintDocument();
PrintPreviewDialog printPreviewDialog1 = new PrintPreviewDialog();
printPreviewDialog1.Icon = new Icon("..\\..\\braille.ico");
printDocument1.PrintPage += PrintDocument_PrintPage;
printPreviewDialog1.Document = printDocument1;
printPreviewDialog1.ShowDialog();
}
private void PrintDocument_PrintPage(object sender, PrintPageEventArgs e)
{
//comes in here for every page it needs to make
int charactersOnPage = 0;
int linesPerPage = 0;
Font drawFont = new Font(rchtxtbx_braille.Font.ToString(), rchtxtbx_braille.Font.Size);
// Sets the value of charactersOnPage to the number of characters
// of stringToPrint that will fit within the bounds of the page.
e.Graphics.MeasureString(rchtxtbx_braille.Text, drawFont,
e.MarginBounds.Size, StringFormat.GenericTypographic,
out charactersOnPage, out linesPerPage);
// Draws the string within the bounds of the page
e.Graphics.DrawString(rchtxtbx_braille.Text, drawFont, Brushes.Black,
e.MarginBounds, StringFormat.GenericTypographic);
// Remove the portion of the string that has been printed.
rchtxtbx_braille.Text = rchtxtbx_braille.Text.Substring(charactersOnPage);
// Check to see if more pages are to be printed.
e.HasMorePages = (rchtxtbx_braille.Text.Length > 0);
}
This all looks good in the preview dialog and I can see I have many pages and they all look correct. In the preview in top left I press the print icon and then I see although the laptop has access to 7 printers all I get here is PDF printer. If I click to run and I get a page printed but it is blank.
So two issues
Why do I not see all 7 printers in the preview dialog?
How do you make the dialog print the actual page rather than ignore it a print blank?
Any ideas please on how to make it print the correct pages. Thanks.
After much head scratching it dawned on me that can work it just needs to put the text back into the richtextbox. I thought once it made the preview that it printed the preview. Apparently not the preview only gives it the figures for the print and not the image to print. It gets the print image from the original source. So now at the end when the Richtextbox is empty I say there are no more pages and then replace the text. It is now working.
private StringBuilder sb = new StringBuilder(); //needed to replace text into richtextbox after preview
private void btn_SaveBitmap_Click(object sender, EventArgs e)
{
PrintDocument printDocument1 = new PrintDocument();
PrintPreviewDialog printPreviewDialog1 = new PrintPreviewDialog();
printPreviewDialog1.Icon = new Icon("..\\..\\braille.ico");
sb.Append(rchtxtbx_braille.Text);
printDocument1.PrintPage += PrintDocument_PrintPage;
printPreviewDialog1.Document = printDocument1;
printPreviewDialog1.ShowDialog();
printDocument1.Dispose();
printPreviewDialog1.Dispose();
}
private void PrintDocument_PrintPage(object sender, PrintPageEventArgs e)
{
//comes in here for every page it needs to make
int charactersOnPage = 0;
int linesPerPage = 0;
Font drawFont = new Font(rchtxtbx_braille.Font.ToString(), rchtxtbx_braille.Font.Size);
// Sets the value of charactersOnPage to the number of characters
// of stringToPrint that will fit within the bounds of the page.
e.Graphics.MeasureString(rchtxtbx_braille.Text, drawFont,
e.MarginBounds.Size, StringFormat.GenericTypographic,
out charactersOnPage, out linesPerPage);
// Draws the string within the bounds of the page
e.Graphics.DrawString(rchtxtbx_braille.Text, drawFont, Brushes.Black,
e.MarginBounds, StringFormat.GenericTypographic);
// Remove the portion of the string that has been printed.
rchtxtbx_braille.Text = rchtxtbx_braille.Text.Substring(charactersOnPage);
// Check to see if more pages are to be printed.
// replace the text when the window is empty so we have something to print
// otherwise we print a blank document.
if (rchtxtbx_braille.Text.Length > 0)
{
e.HasMorePages = true;
}
else
{
e.HasMorePages = false; //say no more pages
rchtxtbx_braille.Text = sb.ToString(); //replace text
}
}
I am using mono-develop under Ubuntu 14.04.
In my project I need to print Persian documents.
We are using native .net package system.drawing.
I ran the following code under Windows (mono which was installed on Windows) and
I had absolutely NO PROBLEM, but here under Ubuntu letters are not going to be joined together to create words. The output is something like this:
I know somehow it is related to my OS. Please help me to solve this.
Here is my code:
namespace printPage{
public class PrintClass
{
PrintDialog printDialog;
PrintDocument printDocument;
PageSetupDialog psd;
public PrintClass()
{
printDialog = new PrintDialog ();
printDocument = new PrintDocument();
printDialog.Document = printDocument;
printDocument.PrintPage +=
new System.Drawing.Printing.PrintPageEventHandler(CreateReceipt);
DialogResult result = printDialog.ShowDialog();
if (result == DialogResult.OK)
printDocument.Print();
}
public void CreateReceipt(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
//string to be printed out
string txt = "با سلام و خسته نباشید";
Graphics graphic = e.Graphics;
Font font = new Font("Arial unicode MS", 20, FontStyle.Regular); //must use a mono spaced font as the spaces need to line up
float fontHeight = font.GetHeight();
int startX = 100;
int startY = 100;
StringFormat sf = new StringFormat();
sf.FormatFlags = StringFormatFlags.DirectionRightToLeft;
sf.FormatFlags = StringFormatFlags.DisplayFormatControl;
int faLCID = new System.Globalization.CultureInfo("fa-IR").LCID;
sf.SetDigitSubstitution(faLCID, StringDigitSubstitute.National);
graphic.DrawString( txt, font, new SolidBrush(Color.Black), startX, startY, sf);
e.HasMorePages = false;
}
}
class MainClass
{
static void Main()
{
PrintClass p = new PrintClass ();
}
}
}
I am attempting to print something using a C# Winforms application. I can't seem to understand how multiple pages works. Let's say I have the following code in my constructor:
private string _stringToPrint;
_stringToPrint = "";
for (int i = 0; i < 120; i++)
{
_stringToPrint = _stringToPrint + "Line " + i.ToString() + Environment.NewLine;
}
Then I have this code on my button click event:
private void MnuFilePrintClick(object sender, EventArgs e)
{
var pd = new PrintDocument();
pd.PrintPage += pd_PrintPage;
var z = new PrintPreviewDialog { Document = pd };
z.ShowDialog(this);
}
void pd_PrintPage(object sender, PrintPageEventArgs e)
{
Graphics g = e.Graphics;
var font = new Font("Arial", 10f, FontStyle.Regular);
g.DrawString(_stringToPrint, font, Brushes.Black, new PointF(10f, 10f));
}
Right now, when I run this code, it is giving me one page and after like 70 lines, it just runs off the paper. How would I print this string so that it prints enough for one page, then runs over to the second page, etc..?
You could have a counter and set the amount of lines you want per page like so:
private string[] _stringToPrint = new string[100]; // 100 is the amount of lines
private int counter = 0;
private int amtleft = _stringToPrint.Length;
private int amtperpage = 40; // The amount of lines per page
for (int i = 0; i < 120; i++)
{
_stringToPrint[i] ="Line " + i.ToString();
}
Then in pd_PrintPage:
void pd_PrintPage(object sender, PrintPageEventArgs e)
{
int currentamt = (amtleft > 40)?40:amtleft;
Graphics g = e.Graphics;
var font = new Font("Arial", 10f, FontStyle.Regular);
for(int x = counter; x < (currentamt+counter); x++)
{
g.DrawString(_stringToPrint[x], font, Brushes.Black, new PointF(10f, (float)x*10));
// x*10 is just so the lines are printed downwards and not on top of each other
// For example Line 2 would be printed below Line 1 etc
}
counter+=currentamt;
amtleft-=currentamt;
if(amtleft<0)
e.HasMorePages = true;
else
e.HasMorePages = false;
// If e.HasMorePages is set to true and the 'PrintPage' has finished, it will print another page, else it wont
}
I have had bad experiences with e.HasMorePages so this may not work.
Let me know if this works and I hope it helps!
I am able to print a chart from my c# project using:
chart1.Printing.PrintDocument.DocumentName = "Graph of data";
But is it possible to add a title to this? I was hoping the document name would achieve this, but apparently not!
You can print whatever you want directly to the page and then invoke the chart PrintPaint(). Note that if you don't switch the PageUnit to Pixels that the chart scaling gets confused.
void PrintChart(object sender, PrintPageEventArgs ev)
{
using (var f = new System.Drawing.Font("Arial", 10))
{
var size = ev.Graphics.MeasureString(Text, f);
ev.Graphics.DrawString("Whatever text you want", f, Brushes.Black, ev.PageBounds.X + (ev.PageBounds.Width - size.Width) / 2, ev.PageBounds.Y);
}
//Note, the chart printing code wants to print in pixels.
Rectangle marginBounds = ev.MarginBounds;
if (ev.Graphics.PageUnit != GraphicsUnit.Pixel)
{
ev.Graphics.PageUnit = GraphicsUnit.Pixel;
marginBounds.X = (int)(marginBounds.X * (ev.Graphics.DpiX / 100f));
marginBounds.Y = (int)(marginBounds.Y * (ev.Graphics.DpiY / 100f));
marginBounds.Width = (int)(marginBounds.Width * (ev.Graphics.DpiX / 100f));
marginBounds.Height = (int)(marginBounds.Height * (ev.Graphics.DpiY / 100f));
}
chart1.Printing.PrintPaint(ev.Graphics, marginBounds);
}
This menu handler opens a PrintDialog(). If you don't want a dialog you can just call pd.Print().
private void printToolStripMenuItem_Click(object sender, EventArgs e)
{
var pd = new System.Drawing.Printing.PrintDocument();
pd.PrintPage += new PrintPageEventHandler(PrintChart);
PrintDialog pdi = new PrintDialog();
pdi.Document = pd;
if (pdi.ShowDialog() == DialogResult.OK)
pdi.Document.Print();
}
Here is a workaround solution to your problem, if you place the ChartingControl inside a Panel control on the Windows Form. You can then print the panel, inside the panel you can add the document heading as a label and whatever other stuff you want to add.
Firstly from the toolbox add a PrintDocument control and call it MyPrintDocument
Then add a Panel control and put your chart inside it.
Make sure you have imported the System.Drawing namespace, then you can print the panel like this.
Bitmap MyChartPanel = new Bitmap(panel1.Width, panel1.Height);
panel1.DrawToBitmap(MyChartPanel, new Rectangle(0, 0, panel1.Width, panel1.Height));
PrintDialog MyPrintDialog = new PrintDialog();
if (MyPrintDialog.ShowDialog() == DialogResult.OK)
{
System.Drawing.Printing.PrinterSettings values;
values = MyPrintDialog.PrinterSettings;
MyPrintDialog.Document = MyPrintDocument;
MyPrintDocument.PrintController = new System.Drawing.Printing.StandardPrintController();
MyPrintDocument.Print();
}
MyPrintDocument.Dispose();
This code converts the panel into a Bitmap and then prints that Bitmap.
You could condense this into a function like:
public void PrintPanel(Panel MyPanel)
{
// Add code from above in here, changing panel1 to MyPanel...
}