Rotate text / Vertical text in itextsharp - c#

I need vertical text or just a way to rotate a ColumnText in ITextSharp.
(It needs to be absolute position)
Until now i have tried a lot of diffrent solution, but with no luck.
Here is a couple of tries:
1.
_cb.SetFontAndSize(BaseFont.CreateFont(), 12f);
_cb.ShowTextAligned(Element.ALIGN_CENTER, "Hello World", 50, 50, 90);
2.
var vt = new VerticalText(_cb);
vt.SetVerticalLayout(50, 50, 400, 8, 30);
vt.AddText(new Chunk("asdasd",_sf.ChildBackPageTextOneFont()));
vt.Go();
3.
System.Drawing.Drawing2D.Matrix foo = new System.Drawing.Drawing2D.Matrix();
foo.Rotate(90);
_cb.ConcatCTM(foo);
I have also tried to draw it with System.Drawing.Graphics, but the quality is VERY poor.
Any solution? Thanks.

I have tried a lot of methods from the web for this rotate issue. But none of them worked. Finally I figured out a simple solution. Maybe we can do it like this. We can draw a table with no borders, and just with one cell. And we add text in the cell, finally rotate the cell.
Every is ok then.
table = new PdfPTable(1);
table.TotalWidth = 72;
paragraph = new Paragraph("123");
cell = new PdfPCell(paragraph);
cell.Rotation = 270;
cell.BorderWidth = 0;
table.AddCell(cell);
table.WriteSelectedRows(0, -1, 72, 72, writer.DirectContent);
Besides, the WriteSelectedRows method can position this cell.

Actually, the easiest way is similar to your first try. You just needed to add a call to BeginText() and EndText() like this
_cb.SetFontAndSize(BaseFont.CreateFont(), 12f);
_cb.BeginText();
_cb.ShowTextAligned(Element.ALIGN_CENTER, "Hello World", 50, 50, 90);
_cb.EndText();
_cb.Stroke();

Found the answer:
Use something like this:
Imports System.Drawing, System.Drawing.Drawing2D
Dim transf as new Matrix
transf.RotateAt(30,New PointF(100,100), MatrixOrder.Append)
writer.DirectContent.Transform(transf)
transf.Invert()
writer.DirectContent.Transform(transf)
Rotate the canvas, write some text, rotate it back.

Related

iTextSharp - draw rectangle - border width issue

here's a simple code:
var w = Utilities.MillimetersToPoints(420);
var h = Utilities.MillimetersToPoints(210);
var doc1 = new Document(new Rectangle(w, h));
PdfWriter writer = PdfWriter.GetInstance(doc1, new FileStream("Doc1.pdf", FileMode.Create));
doc1.Open();
PdfContentByte cb = writer.DirectContent;
var rect = new Rectangle(200, 200, 100, 100);
and now, if I do the following:
cb.Rectangle(200, 200, 100, 100);
cb.Stroke();
then I see the rectangle. But I need to set its border width, so I do
rect.BorderWidth = 5;
rect.BorderColor = new BaseColor(0,0,0);
cb.Rectangle(rect);
cb.Stroke();
and now the rectangle is not visible. Why ?
The Rectangle() method on PdfContentByte has a couple of overloads and they behave quite differently depending on what you pass in.
Your first example is using the very simple overload that just takes 4 floats. If you look at the source for that you'll see that beyond some sanity checking it just writes those coordinates directly to the PDF stream and no actual Rectangle objects are created in the process. Later when you call Stroke() iText writes the stroke command to the stream and that's it. When a PDF renderer (like Adobe's) actually parses the stroke command it looks backwards in the buffer and sees the coordinates that it needs to stroke and performs the action.
Your second example uses the much more complex overload that you can see here which takes an actual Rectangle object. Besides representing four points in space a Rectangle has concepts like background colors and borders and, most importantly for you, these borders can be drawn per side and you need to tell it which sides to draw on.
For instance, for just left and right you'd do:
var rect = new iTextSharp.text.Rectangle(200, 200, 100, 100);
rect.Border = iTextSharp.text.Rectangle.LEFT_BORDER | iTextSharp.text.Rectangle.RIGHT_BORDER;
rect.BorderWidth = 5;
rect.BorderColor = new BaseColor(0, 0, 0);
cb.Rectangle(rect);
And for all borders you'd change it to:
rect.Border = iTextSharp.text.Rectangle.BOX;
Also, when calling this overload it is actually incorrect to call Stroke() immediately after because this overload takes care of that for you (and might have done it more than once, actually.)
(an Addendum to #Chris' answer)
If you want to implement your task (to set its border width) using the simple means of the first example, you can explicitly set the width of lines to stroke:
cb.SetLineWidth(5);
cb.Rectangle(200, 200, 100, 100);
cb.Stroke();
You may want to envelope these lines in cb.SaveState() ... cb.RestoreState() to prevent the changed line width to influence later operations.
Document document = new Document(PageSize.A4, 25, 25, 30, 30);
PdfContentByte cb = writer.DirectContent;
cb.Rectangle(30,660, 280,80);
cb.Stroke();
the function writer is start to write in pdf and rectangle function is create rectangle and stroke is to draw above rectangle specification. so you have to write the stroke() function.
PdfContentByte cb = pdfwrite.DirectContent;
var Rectangular = new Rectangle(55, 620, 540,375);
Rectangular.BorderWidthLeft = 0.1f;
Rectangular.BorderWidthRight = 0.1f;
Rectangular.BorderWidthTop = 0.1f;
Rectangular.BorderWidthBottom = 0.1f;
cb.Rectangle(Rectangular);
cb.Stroke();

itextsharp add text over a circle image in a table cell

I need to have a table with multiple columns where I have different coloured circles in different cells with a number in the middle of the circle.
Similar to the mockup below but with everything centralized and equal.
I have tried the following:
PdfContentByte canvas = writer.DirectContent;
PdfTemplate template = canvas.CreateTemplate(40, 40);
template.SetLineWidth(1f);
template.Circle(15f, 15f, 15);
template.Stroke();
iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance(template);
img.Alignment = iTextSharp.text.Image.UNDERLYING | iTextSharp.text.Image.ALIGN_CENTER;
Phrase imgPhrase = new Paragraph(new Chunk(img, 1f, 1f));
PdfPCell meAnswerCell = new PdfPCell();
meAnswerCell.Colspan = 1;
meAnswerCell.BorderWidthBottom = 0;
meAnswerCell.HorizontalAlignment = Element.ALIGN_CENTER;
string meAnswerText = "1;
Phrase phrase = new Phrase(meAnswerText, questionFont);
Paragraph para = new Paragraph();
para.Add(imgPhrase);
para.Add(phrase);
para.Alignment = Element.ALIGN_CENTER;
meAnswerCell.AddElement(para);
answersTable.AddCell(meAnswerCell);
but I end up with something like this. (I haven't tried setting the colour yet). I cannot get the image and the text to sit in the same place.
I have also tried following this post:
iTextSharp - Text overlapping image
which explains how to put an event on the cell to set the background image of the cell but my circle appears half way down the page.
Has anyone go an example of this working?
There are many different ways to achieve what you want.
Actually, I just voted to close a question https://stackoverflow.com/questions/28066639/how-to-get-text-on-image-in-itext-using-java because it was a duplicate of How to add text to an image?
In your case, you may also benefit from the documentation. There are some examples in The Best iText Questions on StackOverflow that explain how to use cell events, but your requirement is very similar to what was done in a couple of examples from the book iText in Action - Second Edition.
You could use cell events to draw the background of a cell, as shown in the Calendar examples: calendar.pdf, but your requirement can also be met using a generic tag event: movie_years.pdf
Do you see how the word IMDB nicely fits inside an ellipse? You could fit a number inside a circle in the exact same way.
With this code, one draws an ellipse (changing it into a circle is fairly easy):
class GenericTags : PdfPageEventHelper {
public override void OnGenericTag(
PdfWriter writer, Document pdfDocument, Rectangle rect, String text) {
PdfContentByte content = writer.DirectContentUnder, rect);
content.SaveState();
content.SetRGBColorFill(0x00, 0x00, 0xFF);
content.Ellipse(
rect.Left - 3f, rect.Bottom - 5f,
rect.Right + 3f, rect.Top + 3f
);
content.Fill();
content.RestoreState();
}
}
With this snippet, you introduce this event:
GenericTags gevent = new GenericTags();
writer.PageEvent = gevent;
With this snippet, you mark a Chunk with the generic tag:
chunk.SetGenericTag("circle");

itextsharp columntext overlapping with table

I have a columntext that comes before a pdftable, how do I stop the two elements from overlapping?
ColumnText addressHeader = new ColumnText(cb);
Phrase addressText = new Phrase("Lorem ipsum");
addressHeader.SetSimpleColumn(addressText, 34, 750, 580, 317, 15, Element.ALIGN_LEFT);
addressHeader.FollowingIndent = 10f;
addressHeader.Go();
PdfPTable contactTable = new PdfPTable(2);
float[] contactWidths = new float[] { 1f, 1f };
contactTable.TotalWidth = 400f;
contactTable.LockedWidth = true;
contactTable.SpacingBefore = 10f;
contactTable.SetWidths(contactWidths);
PdfPCell contactInfoCell = new PdfPCell();
contactInfoCell.AddElement(new Chunk("Date Requested));
doc.Add(contactTable);
ColumnText.SetSimpleColumn() is used to absolutely position things whereas the Document.Add() method is used to relatively position things. Absolute and relative objects aren't aware of each other, that's just their nature.
So if you can use relative positioning then get rid of the ColumnText and add the Phrase to the document normally.
If you need absolute positioning then you'll need to absolutely position the table as well. This can be done using the table's WriteSelectedRows() method where you tell how many rows to write and what's the upper left corner to start drawing at.
A third possible option is that if you're using the ColumnText.SetSimpleColumn() to draw a page header then you can just change the document's margins. You can still absolutely position things outside of the margins but when you use Document.Add() it will respect those margins.

draw multiple curves in WinForms picturebox

I am working on a program which I want to draw diode curves in a WinForms application. I have a list of diode names and I have theire points as you can see at the right side of the picture. That is Voltage as X and Current as Y ( A curve contains like 50 points).
What I want to do is by selecting one or more diodes from the list theire curve show up on my plot. What you see is just a picture box at the moment filled with a bmp. I know that this is not a reliable solution, so I am asking you what can be the best approach to do such thing? I dont know any good component which can make me do this. So I just need to know what can be the best approuch for this task?
A diode curve is something like:
I might have up to 100 of diode curves in my program which all of them (single or multiple) should be drawn by clicking on them in the list.
So what you think?
UPDATE
ALSO important thing is by deselecting a pin in the curve, its curve should be removed from the plot!
I am drawing that axis you see using the code below:
Bitmap xyCords = new Bitmap(500, 500);
Graphics g = Graphics.FromImage(xyCords);
g.DrawLine(penAxis, 250, 0, 250, 500);
g.DrawLine(penAxis, 0, 250, 500, 250);
curveBox.Image = xyCords;
how is it possible later if I made a new Graphics I append it like:
curveBox.Image += newGraphic;
** Please let me know if there is any component or something which already can do what I want. or else show me a good approach! Thanks!
Try using Graphics.DrawCurve. You just put all of the points you want in an array, and pass that and a pen to the method.
Edit:
Add this after your code to prove to yourself that both graphs coexist. To erase one or the other, just plot the same points, but in the background color of the bitmap (test for it, I don't remember what it is).
Point[] ptarray = new Point[3];
ptarray[0] = new Point(250, 250);
ptarray[1] = new Point(300, 300);
ptarray[2] = new Point(350, 400);
Pen pengraph = new Pen(Color.Green, 0.75F);
g.DrawCurve(pengraph, ptarray);
Point[] ptarray2 = new Point[3];
ptarray2[0] = new Point(100, 100);
ptarray2[1] = new Point(200, 150);
ptarray2[2] = new Point(250, 250);
Pen pengraph2 = new Pen(Color.Yellow, 1.25F);
g.DrawCurve(pengraph2, ptarray2);

How do I fill a rectangle with the exception of a area

I am trying to fill a rectangle in a winforms application less a ellipse in the center that allows the image in the background to show through.
can anyone give me a hint on which way to go on this,
thanks.
this is what I have come up with so far:
path.AddRectangle(new Rectangle(30, 30, 100, 100));
path.AddEllipse(new Rectangle(50, 50, 60, 60));
gfx.FillPath(new SolidBrush(Color.Black), path);
protected override void OnPaint(PaintEventArgs e){
var rgn = new Region(new Rectangle(50, 50, 200, 100));
var path = new GraphicsPath();
path.AddEllipse(60, 60, 180, 80);
rgn.Exclude(path);
e.Graphics.FillRegion(Brushes.Blue, rgn);
}
The easy way:
Fill the Reacngle first
Then Fill the Ellipse (with a Transparant brush)
It isn't clear enough what kind of transparency is required there. The simple way is to invert the problem. Use a TextureBrush to draw the image with Graphics.FillEllipse().
You could try to use regions. Create a rectangle region, exclude an ellipse and then fill it.

Categories

Resources