Draw Lines on Image in PDF using ItextSharp - c#

I am trying to draw lines on image that needs to be loaded on pdf document, just like we draw graphics on paint event of any control, but it fails to do so.
Any Suggestions ?
Document pdfDoc = new Document(PageSize.A2, 10f, 10f, 10f, 0f);
pdfDoc.AddHeader("Batting Report - ", txtSearchBox.Text);
iTextSharp.text.Image pic = iTextSharp.text.Image.GetInstance(Properties.Resources.bgWW
, System.Drawing.Imaging.ImageFormat.Jpeg);
PdfWriter writer = PdfWriter.GetInstance(pdfDoc, stream);
pdfDoc.Open();
pdfDoc.Add(pic);
So, how do I modify the pic object of ItextSharpImage so that it can draw lines on the image?

Please take a look at the WatermarkedImages4 example. It is based on the WatermarkedImages1 example I referred to in the comments. The only different between the two examples is that we add text in the example written in answer to How to add text to an image?
whereas we add lines in the example written in answer to your question.
We add images like this:
document.add(getWatermarkedImage(cb, Image.getInstance(IMAGE1)));
The getWatermarkedImage() method looks like this:
public Image getWatermarkedImage(PdfContentByte cb, Image img) throws DocumentException {
float width = img.getScaledWidth();
float height = img.getScaledHeight();
PdfTemplate template = cb.createTemplate(width, height);
template.addImage(img, width, 0, 0, height, 0, 0);
template.saveState();
template.setColorStroke(BaseColor.GREEN);
template.setLineWidth(3);
template.moveTo(width * .25f, height * .25f);
template.lineTo(width * .75f, height * .75f);
template.moveTo(width * .25f, height * .75f);
template.lineTo(width * .25f, height * .25f);
template.stroke();
template.setColorStroke(BaseColor.WHITE);
template.ellipse(0, 0, width, height);
template.stroke();
template.restoreState();
return Image.getInstance(template);
}
As you can see, I add two green lines using moveTo(), lineTo() and stroke(). I also add a white ellipse using the ellipse() and stroke() method.
This results in a PDF that looks like this:
As you can see, the shape of the ellipse and the position of the lines are different for the different images because I defined my coordinates based on the width and the height of the image.

Related

How to fill a shape with the pattern when generating PDF?

I am using PDFsharp to draw shapes in PDF. Sadly, I can't find any information on filling shapes with a custom pattern, 45-degree stripes in this case.
Stripes
I assume, there is no tool available to do that. How can I achieve the same effect?
Possible solution might be cropping manually drawn lines or using a library that is not PDFsharp, but I am just guessing at this point.
Create a path for the shape. Then just fill a rectangle that surrounds the shape with the pattern you need.
See "Clip through path" in the Graphics sample:
http://www.pdfsharp.net/wiki/Graphics-sample.ashx#Clip_through_path_16
The sample uses text as a shape, but the path can be anything you can draw.
XGraphicsPath path = new XGraphicsPath();
path.AddString("Clip!", new XFontFamily("Verdana"), XFontStyle.Bold, 90,
new XRect(0, 0, 250, 140), XStringFormats.Center);
gfx.IntersectClip(path);
// Draw a beam of dotted lines
XPen pen = XPens.DarkRed.Clone();
pen.DashStyle = XDashStyle.Dot;
for (double r = 0; r <= 90; r += 0.5)
gfx.DrawLine(pen, 0, 0,
250 * Math.Cos(r / 90 * Math.PI), 250 * Math.Sin(r / 90 Math.PI));

iText7 - How to obtain image object data

I need to add a BarcodeQRCode image to a PdfCanvas but I have not found how to do it.
I have the following code
BarcodeQRCode qr;
PdfFormXObject xObject;
Image im;
PdfCanvas canvas = new PdfCanvas(page);
qr = new BarcodeQRCode(msg);
xObject = qr.CreateFormXObject(Color.BLACK, _pdfDoc);
im = new Image(xObject);
im.SetFixedPosition(10f, 10f);
At this point I need to add the image object to the canvas, but in iText7 I need to pass the image object like a iText.IO.Image.ImageData, and that's the problem, because to make this I need the Byte[] of the image.
My question is, How to obtain the Byte[] of the Image object?
I have also tried to do this to obtain the ImageData
PdfImageXObject xoi;
xoi = new PdfImageXObject(xObject.GetPdfObject());
iText.IO.Image.ImageData id = iText.IO.Image.ImageDataFactory.Create(xoi.GetImageBytes());
but I take an error, because xoi.GetImageBytes() throws a null reference exception. Is like the PdfImageXObject is not created correctly.
I am a Little crazy and I need help, please.
Thanks.
You don't have to pass the ImageData object in iText7 in order to draw on PdfCanvas. ImageData is for common images (PNG, JPG), but for barcodes you don't want to lose quality and there are other ways of adding a barcode to the canvas.
In your case, you have already created a PdfFormXObject instance and you can add it to the canvas with PdfCanvas#addXObject as follows:
BarcodeQRCode barcode = new BarcodeQRCode(messageText);
PdfFormXObject barcodeFormXObject = barcode.createFormXObject(Color.BLACK, document);
float scale = 5;
float x = 10;
float y = 10;
canvas.addXObject(barcodeFormXObject, scale, 0, 0, scale, x, y);
UPD: In order for the barcode to be of fixed size regardless of its contents, you can use the following code:
// Tweak this value for fixed width and height
float fixedWidthAndHeight = 300;
float formXobjectWidthAndHeight = barcodeFormXObject.getHeight();
float scale = fixedWidthAndHeight / formXobjectWidthAndHeight;
float x = 10;
float y = 10;
canvas.addXObject(barcodeFormXObject, scale, 0, 0, scale, x, y);
Please note that some padding is added to the barcode, so its width/height will not be equal to fixedWidthAndHeight if you measure the distance between two opposite black squares, but it will be proportional to fixedWidthAndHeight, so you can tweak this variable as needed.

How to place paragraphs in specific place using iTextSharp

How do I place text at a specific location on the pdf? I did a little bit of searching but didn't find anything too good. I have document.Add(new Paragraph("Date:" + DateTime.Now)); and I wanted to place that on a specific area on the pdf file.
My code:
private void savePDF_Click(object sender, EventArgs e)
{
FileStream fileStream = new FileStream(nameTxtB.Text + "Repair.pdf", FileMode.Create, FileAccess.Write, FileShare.None);
Document document = new Document();
document.Open();
iTextSharp.text.Rectangle rectangle = new iTextSharp.text.Rectangle(PageSize.LETTER);
PdfWriter pdfWriter = PdfWriter.GetInstance(document, fileStream);
iTextSharp.text.Image r3tsLogo = iTextSharp.text.Image.GetInstance("rt3slogo.PNG"); //creates r3ts logo
iTextSharp.text.Image r3Info = iTextSharp.text.Image.GetInstance("R3 Information.PNG"); //creates r3 information text below r3ts logo
r3tsLogo.SetAbsolutePosition(document.PageSize.Width - 375 - 0f, document.PageSize.Height - 130 - 0f);
r3Info.SetAbsolutePosition(document.PageSize.Width - 365 - 0f, document.PageSize.Height - 170 - 0f); //higher the number in height the lower the place of text on paper
//less number will result in text more to right in width
//increase size of picture
r3tsLogo.ScalePercent(120);
r3Info.ScalePercent(65);
//---------------adds all images to pdf file ---------------------------------
document.Add(r3tsLogo);
document.Add(r3Info);
document.Add(new Paragraph("Date:" + DateTime.Now));
document.Close();
}
Assuming that you know how to add images at an absolute position (see Joris' answer), but looking at how to add text, then the answer to your question is: use ColumnText.
If you only need to add a single line that doesn't need to be wrapped, you can use the ShowTextAligned() method:
ColumnText.showTextAligned(writer.DirectContent,
Element.ALIGN_CENTER, new Phrase("single line"), x, y, rotation);
In this line of code, x and y are the coordinates for the middle of the text (other possible alignment values are ALIGN_LEFT and ALIGN_RIGHT). The rotation parameter defines a rotation in degrees. Note that the text "single line" won't be wrapped. You can add text that "falls off the page" this way if the text you're adding is too long.
If you want to add text inside a specific rectangle, then you need to define the column using a Rectangle object:
ColumnText ct = new ColumnText(writer.DirectContent);
ct.setSimpleColumn(new Rectangle(0, 0, 523, 50));
ct.addElement(new Paragraph("This could be a very long sentence that needs to be wrapped"));
ct.go();
If you provide more text than fits the rectangle, that text will not be rendered. However, it will still be available in the ct object so that you can add that remaining text at another position.
All of this has been asked and answered before:
Single line:
http://stackoverflow.com/questions/16370428/how-to-write-in-a-specific-location-the-zapfdingbatslist-in-a-pdf-document-using
http://stackoverflow.com/questions/17998306/rotating-text-using-center-in-itext
Multiple lines:
http://stackoverflow.com/questions/33609447
http://stackoverflow.com/questions/31152874/how-to-add-text-in-pdfcontentbyte-rectangle-using-itextsharp
http://stackoverflow.com/questions/15414923/rotate-paragraphs-or-cells-some-arbitrary-number-of-degrees-itext
Did I have to search long for these examples? No, I found them on the official web site under Absolute Positioning of text.
Wisdom is there for those who search...
This concept is thoroughly explained in the book 'iText in action'. Which can be found on the website.
http://developers.itextpdf.com/examples/itext-action-second-edition/chapter-3
Short code sample (check the site for other examples):
// step 1
Document document = new Document(PageSize.POSTCARD, 30, 30, 30, 30);
// step 2
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(RESULT));
// step 3
document.open();
// step 4
// Create and add a Paragraph
Paragraph p = new Paragraph("Foobar Film Festival", new Font(FontFamily.HELVETICA, 22));
p.setAlignment(Element.ALIGN_CENTER);
document.add(p);
// Create and add an Image
Image img = Image.getInstance(RESOURCE);
img.setAbsolutePosition(
(PageSize.POSTCARD.getWidth() - img.getScaledWidth()) / 2,
(PageSize.POSTCARD.getHeight() - img.getScaledHeight()) / 2);
document.add(img);

How to Draw a given Character in exact height?

I am drawing the text using Graphics.DrawString() method, But the text height drawn is not same as which i gave.
For Eg:
Font F=new Font("Arial", 1f,GraphicUnit.Inch);
g.DrawString("M", F,Brushes.red,new Point(0,0));
By using the above code, i'm drawing the text with height 1 inch, but the text drawn is not exactly in 1 inch.
I need to Draw the text in Exact height which i'm giving. Thanks in advance..
The simplest solution will be to use a GraphicsPath. Here are the steps necessary:
Calculate the height you want in pixels: To get 1.0f inches at, say 150 dpi you need 150 pixels.
Then create a GraphicsPath and add the character or string in the font and font style you want to use, using the calculated height
Now measure the resulting height, using GetBounds.
Then scale the height up to the necessary number of pixels
Finally clear the path and add the string again with the new height
Now you can use FillPath to output the pixels..
Here is a code example. It writes the test string to a file. If you want to write it to a printer or a control using their Graphics objects, you can do it the same way; just get/set the dpi before you calculate the first estimate of the height..
The code below creates this file; the Consolas 'x' is 150 pixels tall as is the 2nd character (ox95) from the Wingdings font. (Note that I did not center the output):
// we are using these test data:
int Dpi = 150;
float targetHeight = 1.00f;
FontFamily ff = new FontFamily("Consolas");
int fs = (int) FontStyle.Regular;
string targetString = "X";
// this would be the height without the white space
int targetPixels = (int) targetHeight * Dpi;
// we write to a Btimpap. I make it large enough..
// Instead you can write to a printer or a Control surface..
using (Bitmap bmp = new Bitmap(targetPixels * 2, targetPixels * 2))
{
// either set the resolution here
// or get and use it above from the Graphics!
bmp.SetResolution(Dpi, Dpi);
using (Graphics G = Graphics.FromImage(bmp))
{
// good quality, please!
G.SmoothingMode = SmoothingMode.AntiAlias;
G.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
// target position (in pixels)
PointF p0 = new PointF(0, 0);
GraphicsPath gp = new GraphicsPath();
// first try:
gp.AddString(targetString, ff, fs, targetPixels, p0,
StringFormat.GenericDefault);
// this is the 1st result
RectangleF gbBounds = gp.GetBounds();
// now we correct the height:
float tSize = targetPixels * targetPixels / gbBounds.Height;
// and if needed the location:
p0 = new PointF(p0.X - gbBounds.X, p0.X - gbBounds.Y);
// and retry
gp.Reset();
gp.AddString(targetString, ff, fs, tSize, p0, StringFormat.GenericDefault);
// this should be good
G.Clear(Color.White);
G.FillPath(Brushes.Black, gp);
}
//now we save the image
bmp.Save("D:\\testString.png", ImageFormat.Png);
}
You may want to try using the correction factor to scale up a Font size and use DrawString after all.
There is also a way to calculate the numbers ahead using FontMetrics, but I understand the link to mean that such an approach could be font-dependent..

Drawing shapes with a translucent fill in iTextSharp 4.1.6.0

I am using a deprecated version of iTextSharp (4.1.6.0) to produce PDFs form my MVC3 application, and really need to be able to lay translucent shapes over the top of other shapes and images, the goal being to fade the colours of the image underneath it, or grey it out. I would have thought this would be as simple as setting the alpha channel when choosing a colour for the shapes fill, so i tried this:
Document doc = new Document();
PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(#"C:/Filepath/doc.pdf", FileMode.Create))
doc.Open();
PdfContentByte over = writer.DirectContent;
// draw shape to be faded out
over.Rectangle(10, 10, 50, 50);
over.SetColorFill(Color.BLUE);
over.Fill();
// draw shape over the top to do the fading (red so i can easily see where it is)
over.Rectangle(0, 0, 60, 60);
over.SetColorFill(new Color(255,0,0,150)); // rgba
over.Fill();
doc.Close();
I would expect this to draw two rectangles near the bottom left of the page, a small blue one overlaid with a larger red, translucent one, but the red one is not translucent!
So i did some googling and found this page, which is actually about iText not iTextSharp, where they suggest using PdfGstate to set the fill opacity like this:
PdfGState gstate = new PdfGState();
gstate.setFillOpacity(0.3);
but when i try that the gstate object has no method that is anything like .setFillOpacity()! If anyone can point me in the right direction I would be most grateful.
One of the rules of converting Java libraries to C# libraries is that all of the getXYZ and setXYZ methods should be converted to simple C# properties.
So gstate.setFillOpacity(0.3); will be come gstate.FillOpacity = 0.3f;
using (Document doc = new Document())
{
PdfWriter writer = PdfWriter.GetInstance(doc, new FileStream(#"mod.pdf", FileMode.Create));
doc.Open();
PdfContentByte over = writer.DirectContent;
over.SaveState();
over.Rectangle(10, 10, 50, 50);
over.SetColorFill(BaseColor.BLUE);
over.Fill();
PdfGState gs1 = new PdfGState();
gs1.FillOpacity = 0.5f;
over.SetGState(gs1);
over.Rectangle(0, 0, 60, 60);
over.SetColorFill(new BaseColor(255, 0, 0, 150));
over.Fill();
over.RestoreState();
doc.Close();
}

Categories