So, I'm trying to simply add a text annotation to a pdf at the top left corner of a pdf document. Current code is like this:
public static byte[] StampPDFDocument(byte[] pdf, string stampString) {
using (var ms = new MemoryStream()) {
var reader = new iTextSharp.text.pdf.PdfReader(pdf);
var stamper = new iTextSharp.text.pdf.PdfStamper(reader, ms);
var box = reader.GetCropBox(1);
var left = box.Left;
var top = box.Top;
iTextSharp.text.Rectangle newRectangle = new iTextSharp.text.Rectangle(left + 20, top - 20, left + 250, top - 40);
var pcb = new iTextSharp.text.pdf.PdfContentByte(stamper.Writer);
pcb.SetColorFill(iTextSharp.text.BaseColor.RED);
var annot = iTextSharp.text.pdf.PdfAnnotation.CreateFreeText(stamper.Writer, newRectangle, stampString, pcb);
annot.Flags = iTextSharp.text.pdf.PdfAnnotation.FLAGS_PRINT;
annot.BorderStyle = new iTextSharp.text.pdf.PdfBorderDictionary(0, 0);
stamper.AddAnnotation(annot, 1);
stamper.Close();
return ms.ToArray();
}
}
Now, original code was just using box = reader.GetPageSize(1). Well, that I soon realized causes problems if the document has been rotated. Ok. No problem, there is a function called reader.GetPageSizeWithRotation. That worked like a charm. However, now I'm getting documents that have a different cropbox. So the annotation that I was adding was outside the cropbox area. So this current code only works for non rotated documents. The question is, how does one get the top left corener in a pdf document regardless of whether the document is rotated or contains a different cropbox than the document?
Here's what I ended up with.
public static byte[] StampPDFDocument(byte[] pdf, string stampString) {
using (var ms = new MemoryStream()) {
var reader = new iTextSharp.text.pdf.PdfReader(pdf);
var stamper = new iTextSharp.text.pdf.PdfStamper(reader, ms);
int rotation = reader.GetPageRotation(1);
var box = reader.GetPageSizeWithRotation(1);
var cropbox = reader.GetCropBox(1);
float left = cropbox.Left;
float top = cropbox.Top;
if (rotation == 90) {
left = cropbox.Bottom;
top = box.Height - cropbox.Left;
cropbox = new iTextSharp.text.Rectangle(left, top, left + cropbox.Height, top - cropbox.Width);
}
else if (rotation == 180) {
left = box.Width - cropbox.Left - cropbox.Width;
top = box.Height - cropbox.Bottom;
cropbox = new iTextSharp.text.Rectangle(left, top, left + cropbox.Width, top - cropbox.Height);
}
else if (rotation == 270) {
left = box.Width - cropbox.Top;
top = cropbox.Right;
cropbox = new iTextSharp.text.Rectangle(left, top, left + cropbox.Height, top - cropbox.Width);
}
iTextSharp.text.Rectangle newRectangle = new iTextSharp.text.Rectangle(left + 20, top - 20, left + 250, top - 40);
var pcb = new iTextSharp.text.pdf.PdfContentByte(stamper.Writer);
pcb.SetColorFill(iTextSharp.text.BaseColor.RED);
var annot = iTextSharp.text.pdf.PdfAnnotation.CreateFreeText(stamper.Writer, newRectangle, stampString, pcb);
annot.Flags = iTextSharp.text.pdf.PdfAnnotation.FLAGS_PRINT;
annot.Rotate = reader.GetPageRotation(1);
annot.BorderStyle = new iTextSharp.text.pdf.PdfBorderDictionary(0, 0);
stamper.AddAnnotation(annot, 1);
stamper.Close();
return ms.ToArray();
}
}
Here's the source for getPageSizeWithRotation:
public Rectangle getPageSizeWithRotation(int index) {
return getPageSizeWithRotation(pageRefs.getPageNRelease(index));
}
public Rectangle getPageSizeWithRotation(PdfDictionary page) {
Rectangle rect = getPageSize(page);
int rotation = getPageRotation(page);
while (rotation > 0) {
rect = rect.rotate();
rotation -= 90;
}
return rect;
}
So all you need to do to roll your own is to write a function that calls getCropBox() instead of getPageSize().
PS: getCropBox() will return the media box if there's no crop box, so you don't have to call getCropBox and getPageSize separately.
Related
I have existing image converted to base64 and I would like to add text on top of it. However this return only the original image. Could you please advise where am I making mistake?
var signatureData = Convert.FromBase64String(signature);
var stream = new MemoryStream(signatureData);
var signatureBitmap = SKBitmap.Decode(stream);
var canvas = new SKCanvas(signatureBitmap);
var origin = new SKPoint();
var paint = new SKPaint
{
TextSize = 10,
IsAntialias = true,
Color = SKColors.Black,
IsStroke = false
};
origin.X = 10;
origin.Y = 30;
paint.TextAlign = SKTextAlign.Left;
canvas.DrawText("text", origin, paint);
canvas.Flush();
var resultImage = SKImage.FromBitmap(signatureBitmap);
var data = resultImage.Encode(SKEncodedImageFormat.Png, 100);
return Convert.ToBase64String(data.ToArray());
This posted question actually worked for me, only the position was wrong so the text was very tiny
When saving, the image has the right design but the PDF has the wrong text on it. Could you explain why the documents are different?
I'm also open to other solutions for saving a PDF of the whole document and the ability to print a selected page of a multi-page document.
thanks :)
EDIT: the image is showing the date ("24th May 2016") which is correct and what I want the PDF to show, but instead the PDF is showing "TEST TEST"
1
public static void pdf() {
DateTime now = DateTime.Now;
string filename = "MixMigraDocAndPdfSharp.pdf";
filename = Guid.NewGuid().ToString("D").ToUpper() + ".pdf";
PdfDocument document = new PdfDocument();
SamplePage1(document);
document.Save(filename);
Process.Start(filename);
}
2
static void SamplePage1(PdfDocument document) {
PdfPage page = document.AddPage();
XGraphics gfx = XGraphics.FromPdfPage(page);
gfx.MUH = PdfFontEncoding.Unicode;
gfx.MFEH = PdfFontEmbedding.Default;
XFont font = new XFont("Verdana", 13, XFontStyle.Bold);
gfx.DrawString("TEST TEST", font, XBrushes.Black,
new XRect(100, 100, page.Width - 200, 300), XStringFormats.Center);
Document doc = new Document();
Section sec = doc.AddSection();
Paragraph para = sec.AddParagraph();
header("24th May 2016");
DocumentRenderer docRenderer = new DocumentRenderer(doc);
docRenderer.PrepareDocument();
docRenderer.RenderObject(gfx, XUnit.FromCentimeter(5), XUnit.FromCentimeter(10), "12cm", para);
PageInfo info = docRenderer.FormattedDocument.GetPageInfo(1);
int dpi = 150;
int dx, dy;
if (info.Orientation == PdfSharp.PageOrientation.Portrait) {
dx = (int)(info.Width.Inch * dpi);
dy = (int)(info.Height.Inch * dpi);
} else {
dx = (int)(info.Height.Inch * dpi);
dy = (int)(info.Width.Inch * dpi);
}
Image image = new Bitmap(dx, dy, PixelFormat.Format32bppRgb);
Graphics graphics = Graphics.FromImage(image);
graphics.Clear(System.Drawing.Color.White);
float scale = dpi / 72f;
graphics.ScaleTransform(scale, scale);
gfx = XGraphics.FromGraphics(graphics, new XSize(info.Width.Point, info.Height.Point));
docRenderer.RenderPage(gfx, 1);
gfx.Dispose();
image.Save("test.png", ImageFormat.Png);
doc.BindToRenderer(docRenderer);
docRenderer.RenderObject(gfx, XUnit.FromCentimeter(5), XUnit.FromCentimeter(10), "12cm", para);
Process.Start("mspaint", "test.png");
}
3
public static void header(String date) {
Paragraph paragraph = new Paragraph();
var dateIssued = firstPage.AddTextFrame();
dateIssued.Height = "1.0cm";
dateIssued.Width = "6.0cm";
dateIssued.Left = "2.1cm";
dateIssued.RelativeHorizontal = RelativeHorizontal.Margin;
dateIssued.Top = "3.55cm";
dateIssued.RelativeVertical = RelativeVertical.Page;
paragraph = dateIssued.AddParagraph(date);
}
You call docRenderer.RenderPage(gfx, 1); for the image only. This renders the header.
You do not call docRenderer.RenderPage(gfx, 1); for the PDF. So no date there, just the "TEST TEST" you draw earlier.
I'm trying add picture on centre(middle) of page PDF file with text, but I can't do it right. I use for image SetAbsolutePosition, but text don't stand under picture.
I need in my Pdf file next format of page:
I use next code:
PdfWriter writer = PdfWriter.GetInstance(doc, fs);
ITextEvents ev = new ITextEvents();
writer.PageEvent = ev;
doc.Open();
var paragraph = new Paragraph();
var paragraph1 = new Paragraph();
var chunk = new Chunk("Text under picture", f14nb);
var chunk1 = new Chunk("Code of picture", f14);
img = ScaleImg(Image.GetInstance(imgNane_2));
img.SetAbsolutePosition((PageSize.A4.Width - img.ScaledWidth) / 2,
((PageSize.A4.Height - img.ScaledHeight) / 2));
paragraph.Add(img);
paragraph1.Add(chunk);
paragraph1.Add(chunk1);
doc.Add(paragraph);
doc.Add(paragraph1);
doc.Close();
private Image ScaleImg(Image img)
{
if (img.Height > img.Width)
{
//Maximum height is 800 pixels.
float percentage = 0.0f;
percentage = 640 / img.Height;
img.ScalePercent(percentage * 100);
}
else
{
//Maximum width is 600 pixels.
float percentage = 0.0f;
percentage = 500 / img.Width;
img.ScalePercent(percentage * 100);
}
return img;
}
I think, that I should use another way for solve my problem, but I don't know which.
Thank you.
I understood how do it.
This is for image with text:
public Image getWatermarkedImage(Document Doc, Image img, String watermarkText)
{
float width = img.ScaledWidth;
float height = img.ScaledHeight;
PdfTemplate template = cb.CreateTemplate(width, height);
template.AddImage(img, width, 0, 0, height, 0, 0);
ColumnText.ShowTextAligned(template, Element.ALIGN_RIGHT,
new Phrase(watermarkText, fontBold_14), width - 10, 10, 0);
return Image.GetInstance(template);
}
This is for adding text under image(main code):
var codeOfPicture = "*Code of picture* - *Код картинки*";
var chunk = new Chunk("Text under picture", font_14);
img = ScaleImg(Image.GetInstance(imgNane_1));//imgNane_2));
var tmpImg = getWatermarkedImage(doc, img, codeOfPicture);
var textY = ((PageSize.A4.Height - img.ScaledHeight) / 2) - 15;
var textX = PageSize.A4.Width / 2;
tmpImg.SetAbsolutePosition((PageSize.A4.Width - img.ScaledWidth) / 2,
((PageSize.A4.Height - img.ScaledHeight) / 2));
doc.Add(tmpImg);
ColumnText.ShowTextAligned(cb, Element.ALIGN_CENTER, new Phrase(chunk), textX, textY, 0);
I'm trying to print a Image in Landscape mode in Silverlight.
I found a great example here. Where most of the code comes from. The code worked perfectly as expected. When I changed the Line to an Image it failed.
Code
Canvas OuterCanvas = new Canvas();
/* a container for everything that will print */
Border OuterBorder = new Border()
{
BorderThickness = new Thickness(3),
BorderBrush = new SolidColorBrush(Colors.Red),
Margin = new Thickness(10)
};
double Width = e.PrintableArea.Width - OuterBorder.Margin.Left - OuterBorder.Margin.Right;
double Height = e.PrintableArea.Height - OuterBorder.Margin.Top - OuterBorder.Margin.Bottom;
/* NOTE: We're trying to force landscape, so swop the width and height */
OuterBorder.Width = Height;
OuterBorder.Height = Width;
/* on portrait, this line goes down (leave the printer settings, we're trying to force landscape) */
Line Line = new Line()
{
X1 = OuterBorder.Width / 2,
Y1 = 0,
X2 = OuterBorder.Width / 2,
Y2 = OuterBorder.Height,
Stroke = new SolidColorBrush(Colors.Blue),
StrokeThickness = 3
};
//
// Here is where I changed the Line to an Image
//
OuterBorder.Child = imageElementInXaml; //Line;
OuterCanvas.Children.Add(OuterBorder);
/* rotate 90 degrees, and move into place */
var transformGroup = new TransformGroup();
transformGroup.Children.Add(new RotateTransform() { Angle = 90 });
transformGroup.Children.Add(new TranslateTransform() { X = e.PrintableArea.Width });
OuterBorder.RenderTransform = transformGroup;
e.PageVisual = OuterCanvas;
e.HasMorePages = false;
I know that a Border can only contain 1 element in which I have done so, and when I printed the image on its own without trying to make it landscape this worked too. So why wont it work when I simply replace the Line with the image Element
So since posting this I found some code (cant remember where now) that has helped me get the printing working. Its not as clean as I would have liked but it works.
void pd_PrintPage(object sender, PrintPageEventArgs e)
{
Image image = new Image();
image.Source = imgPlayer.Source;
//This is important
image.Stretch = Stretch.Uniform;
// Find the full size of the page
Size pageSize = new Size(e.PrintableArea.Width + e.PageMargins.Left + e.PageMargins.Right, e.PrintableArea.Height + e.PageMargins.Top + e.PageMargins.Bottom);
var MARGIN= 10;
// Get additional margins to bring the total to MARGIN (= 96)
Thickness additionalMargin = new Thickness
{
Left = Math.Max(0, MARGIN - e.PageMargins.Left),
Top = Math.Max(0, MARGIN - e.PageMargins.Top),
Right = Math.Max(0, MARGIN - e.PageMargins.Right),
Bottom = Math.Max(0, MARGIN - e.PageMargins.Bottom)
};
// Find the area for display purposes
Size displayArea = new Size(e.PrintableArea.Width - additionalMargin.Left - additionalMargin.Right, e.PrintableArea.Height - additionalMargin.Top - additionalMargin.Bottom);
bool pageIsLandscape = displayArea.Width > displayArea.Height;
bool imageIsLandscape = image.ActualWidth > image.ActualHeight;
double displayAspectRatio = displayArea.Width / displayArea.Height;
double imageAspectRatio = (double)image.ActualWidth / image.ActualHeight;
double scaleX = Math.Min(1, imageAspectRatio / displayAspectRatio);
double scaleY = Math.Min(1, displayAspectRatio / imageAspectRatio);
// Calculate the transform matrix
MatrixTransform transform = new MatrixTransform();
if (pageIsLandscape == imageIsLandscape)
{
// Pure scaling
transform.Matrix = new Matrix(scaleX, 0, 0, scaleY, 0, 0);
}
else
{
// Scaling with rotation
scaleX *= pageIsLandscape ? displayAspectRatio : 1 / displayAspectRatio;
scaleY *= pageIsLandscape ? displayAspectRatio : 1 / displayAspectRatio;
transform.Matrix = new Matrix(0, scaleX, -scaleY, 0, 0, 0);
}
Image image2 = new Image
{
Source = image.Source,
Stretch = Stretch.Fill,
Width = displayArea.Width,
Height = displayArea.Height,
RenderTransform = transform,
RenderTransformOrigin = new Point(0.5, 0.5),
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Margin = additionalMargin,
};
Border border = new Border
{
Child = image,
};
e.PageVisual = border;
}
I have PDF where some of the text are very closed to the left and right border and I would like to add more white space at the border, top bottom left and right, for each pages in the PDF using iTextSharp.
Is this possible using iTextSharp or there is a better way?
I managed to find the answer. The code below adjusts the size of the pages:
var inputPdf = new PdfReader(inputFile); // Get input document
int pageCount = inputPdf.NumberOfPages;
if (end < start || end > pageCount)
end = pageCount;
var inputDoc = new Document(inputPdf.GetPageSizeWithRotation(1));
using (var fs = new FileStream(outputFile, FileMode.Create))
{
var outputWriter = PdfWriter.GetInstance(inputDoc, fs);
inputDoc.Open();
PdfContentByte cb1 = outputWriter.DirectContent;
// Copy pages from input to output document
for (int i = start; i <= end; i++)
{
var existingRec = inputPdf.GetPageSizeWithRotation(i);
var newRec = new Rectangle(0.0f, 0.0f, existingRec.Width + 50, existingRec.Height + 25, 0);
inputDoc.SetPageSize(newRec);
inputDoc.NewPage();
PdfImportedPage page = outputWriter.GetImportedPage(inputPdf, i);
int rotation = inputPdf.GetPageRotation(i);
if (rotation == 90 || rotation == 270)
cb1.AddTemplate(page, 0, -1f, 1f, 0, 0, inputPdf.GetPageSizeWithRotation(i).Height);
else cb1.AddTemplate(page, 1f, 0, 0, 1f, 25, 13);
}
inputDoc.Close();
}
Hope this helps someone.