I am generating a byte array image and in order to convert it to pdf I am adding that image into a PDF document. the image size is exactly 812, 1015 DPI and even though I have document with the same size the image is being offset by about an inch (the red bar represents this offset) because of this I am missing about the same amount on the other side. Why is the PDF adding the image in this way. Here is the code:
var resizedImage = new Bitmap(812, 1015);
var drawResizedImage = Graphics.FromImage(resizedImage);
drawResizedImage.DrawImage(img, 0, 0, 812, 1015);
resizedImage.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Jpeg);
return getPDFDocument(memoryStream);
private byte[] getPDFDocument(MemoryStream inputImageStream)
{
MemoryStream workStream = new MemoryStream();
iTextSharp.text.Document document = new iTextSharp.text.Document(new iTextSharp.text.Rectangle(812, 1015));
PdfWriter.GetInstance(document, workStream).CloseStream = false;
document.Open();
iTextSharp.text.Image pdfImage = iTextSharp.text.Image.GetInstance(inputImageStream.ToArray());
document.Add(pdfImage);
document.Close();
byte[] byteInfo = workStream.ToArray();
workStream.Write(byteInfo, 0, byteInfo.Length);
workStream.Position = 0;
return workStream.ToArray();
}
This is producing this
Add this line to your code block
pdfImage.SetAbsolutePosition(0, 0);
You should see this:
document.Open();
iTextSharp.text.Image pdfImage = iTextSharp.text.Image.GetInstance(inputImageStream.ToArray());
pdfImage.SetAbsolutePosition(0, 0);
document.Add(pdfImage);
document.Close();
That should give you the desired positioning.
Related
GOAL
To open an existing PDF file with multiple pages and add background image to all pages. (Optionally the background image of the first page differs from the others)
In my current implementation (I use .NET 6 and PDFsharp btw.) I add the image to each page, which increases the size of the file dependent on the number of pages.
QUESTION
Is there a way in PDFsharp/MigraDoc to embed a background image only once into the document and then reference it for each page?
CODE
Both PDF document and the image come from a database as byte arrays.
public byte[] AddBackgroundImgToDocument(byte[] doc, byte[] imgFirstPage, byte[]? imgOtherPages=null)
{
using var ms = new MemoryStream(doc);
PdfDocument pdfDoc = PdfReader.Open(ms, PdfDocumentOpenMode.Modify);
for (int i = 0; i < pdfDoc.PageCount; i++)
{
if(i > 0 && imgOtherPages != null && imgOtherPages.Length > 0)
AddBackgroundImageFromByteArray(pdfDoc.Pages[i], imgOtherPages);
else
AddBackgroundImageFromByteArray(pdfDoc.Pages[i], imgFirstPage);
GC.Collect();
GC.WaitForPendingFinalizers();
}
using var oms = new MemoryStream();
pdfDoc.Save(oms);
ms.Dispose();
pdfDoc.Dispose();
return oms.ToArray();
}
public void AddBackgroundImageFromByteArray(PdfPage page, byte[] imgfile)
{
XGraphics gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Prepend);
MemoryStream ms = new System.IO.MemoryStream(imgfile);
ms.Position = 0;
XImage image = XImage.FromStream(() => ms);
gfx.DrawImage(image, 0, 0, page.Width, page.Height);
ms.Dispose();
}
SOLUTION
Rewriting the method above according to accepted answer, solved my problem:
public void AddBackgroundImageFromByteArray(PdfPage page, byte[] imgfile)
{
if(!ximageLoaded)
{
MemoryStream ms = new System.IO.MemoryStream(imgfile);
ms.Position = 0;
backimg = XImage.FromStream(() => ms);
ms.Dispose();
ximageLoaded = true;
}
XGraphics gfx = XGraphics.FromPdfPage(page, XGraphicsPdfPageOptions.Prepend);
gfx.DrawImage(backimg, 0, 0, page.Width, page.Height);
}
With PDFsharp and MigraDoc this optimization is done automatically if you use them as intended.
Load the image once with PDFsharp and add it to as many pages as you like, there will be only one copy of the image in the document.
I am using iTextSharp in my code to resize PDF documents and it is working very well, as shown below:
public byte[] ResizePdf(byte[] data) {
PdfReader reader = new PdfReader(data);
Document document = new Document(PageSize.A4);
MemoryStream stream = new MemoryStream();
PdfWriter writer = PdfWriter.GetInstance(document, stream);
document.Open();
PdfContentByte cb = writer.DirectContent;
for (int i = 1; i <= reader.NumberOfPages; i++) {
document.NewPage();
PdfImportedPage page = writer.GetImportedPage(reader, i);
cb.AddTemplate(page, 0.8, 0, 0, 0.8, 25f, 60f);
}
document.Close();
return stream.ToArray();
}
However, when a PDF document is signed, when I try to resize it, I lose the signature on my new resized document.
I've tried to create a copy of the document (follow the code) and it works fine, but I can't resize it.
public byte[] Test(byte[] data) {
PdfReader reader = new PdfReader(data);
Document document = new Document(PageSize.A4);
MemoryStream stream = new MemoryStream();
PdfCopy copy = new PdfCopy(document, stream);
document.Open();
PdfContentByte cb = copy.DirectContent;
for (int i = 1; i <= reader.NumberOfPages; i++) {
document.NewPage();
PdfImportedPage page = copy.GetImportedPage(reader, i);
cb.AddTemplate(page, 0.8, 0, 0, 0.8, 0, 0);
copy.AddPage(page);
}
document.Close();
return stream.ToArray();
}
Does anyone have any tips or anything that can help me?
Thanks in advance!
I'm adding an image to a iTextSharp pdf in this way:
iTextSharp.text.Document doc = new iTextSharp.text.Document(PageSize.A4, 0F,0F, 0F, 0F);
iTextSharp.text.Image img = iTextSharp.text.Image.GetInstance("https://s3-eu-west-1.amazonaws.com/foo/bar.png");
img.ScaleToFit(595, 120);
MemoryStream ms = new MemoryStream();
PdfWriter.GetInstance(doc, ms);
doc.Open();
doc.Add(img);
doc.Close();
Then I convert it to byte[] and then to base64 string, so it can be handled by AWS API Gateway.
byte[] pdf = ms.ToArray();
var headersDic = new Dictionary<string, string>();
headersDic.Add("Content-type", "application/pdf");
headersDic.Add("Content-disposition", "inline;filename=file.pdf");
return new APIGatewayProxyResponse
{
Body = Convert.ToBase64String(pdf),
IsBase64Encoded = true,
Headers = headersDic,
StatusCode = 200
};
But the image is not shown in the pdf, just an almost indistinguishable part of it, which is the line you can see here:
Any ideas? maybe the conversions to byte[] or base64 and to binary again are giving problems?
When I add text everything goes good.
Im doing a image to pdf program.
I want to set the size of the image as the size of the pdf and a extra space on top with 50
i tried this code
using (var imageStream = new FileStream(imagelocation, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
var image = Image.GetInstance(imageStream);
Document document = new Document(new Rectangle(image.Width, image.Height), 0, 0, 0, 0);
using (var stream = new FileStream(pdfOutput, FileMode.Create, FileAccess.Write, FileShare.None))
{
PdfWriter.GetInstance(document, stream);
document.Open();
document.Add(image);
document.Close();
}
}
but the problem is it doesn't have a top margin,
when i try this code
Document document = new Document(new Rectangle(image.Width, image.Height), 0, 50, 50, 0);
it crop a part of the image for the space. how can i make this work?
By setting the document margins like "0, 50, 50, 0" you are also setting a margin-right, that might not be what you want in this case. The margin top is the correct way to get some space above the image.
Alternatively you can add some empty lines to your document before adding the image, e.g.: document.Add(new Paragraph(Chunk.NewLine))
You can use image.ScaleToFit() and pass in something like document.PageSize.Height and document.PageSize.Width to make that image fit your page.
this is my solution. i didn't realize that this simple code will work
Document document = new Document(new Rectangle(image.Width, image.Height + 150), 0, 0, 150, 0);
I want to write serial number on a pdf document.
And I achieved it with below code with using itextSharp.dll.
public byte[] Sign(string path, string serialnumber)
{
PdfReader pdfReader = new PdfReader(path);
MemoryStream memoryStream = new MemoryStream();
PdfStamper pdfStamper = new PdfStamper(pdfReader, memoryStream);
//iterate through all pages in source pdf
for (int pageIndex = 1; pageIndex <= pdfReader.NumberOfPages; pageIndex++)
{
iTextSharp.text.Rectangle pageRectangle = pdfReader.GetPageSizeWithRotation(pageIndex);
PdfContentByte pdfData = pdfStamper.GetUnderContent(pageIndex);
pdfData.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 40);
PdfGState graphicsState = new PdfGState();
graphicsState.FillOpacity = 0.4F;
pdfData.SetGState(graphicsState);
pdfData.SetColorFill(iTextSharp.text.Color.BLUE);
pdfData.BeginText();
pdfData.ShowTextAligned(iTextSharp.text.Element.ALIGN_CENTER, serialnumber, pageRectangle.Width - 175, pageRectangle.Height - 50, 0);
pdfData.EndText();
}
pdfStamper.Close();
memoryStream.Close();
return memoryStream.ToArray();
}
But I save pdf documents in database which type is varbinary(max).
So how can I write a number on a document which is saved as binary in database?
As #mkl mentioned, one of the other parameters of PdfReader is byte[], so one can easily use binary data.