Convert image to pdf using itextsharp [duplicate] - c#

I have the following code but this code add only the last image into pdf.
try {
filePath = (filePath != null && filePath.endsWith(".pdf")) ? filePath
: filePath + ".pdf";
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document,
new FileOutputStream(filePath));
document.open();
// document.add(new Paragraph("Image Example"));
for (String imageIpath : imagePathsList) {
// Add Image
Image image1 = Image.getInstance(imageIpath);
// Fixed Positioning
image1.setAbsolutePosition(10f, 10f);
// Scale to new height and new width of image
image1.scaleAbsolute(600, 800);
// image1.scalePercent(0.5f);
// Add to document
document.add(image1);
//document.bottom();
}
writer.close();
} catch (Exception e) {
LOGGER.error(e.getMessage());
}
Would you give me a hint about how to update the code in order to add all the images into the exported pdf? imagePathsList contains all the paths of images that that I want to add into a single pdf.
Best Regards,
Aurelian

Take a look at the MultipleImages example and you'll discover that there are two errors in your code:
You create a page with size 595 x 842 user units, and you add every image to that page regardless of the dimensions of the image.
You claim that only one image is added, but that's not true. You are adding all the images on top of each other on the same page. The last image covers all the preceding images.
Take a look at my code:
public void createPdf(String dest) throws IOException, DocumentException {
Image img = Image.getInstance(IMAGES[0]);
Document document = new Document(img);
PdfWriter.getInstance(document, new FileOutputStream(dest));
document.open();
for (String image : IMAGES) {
img = Image.getInstance(image);
document.setPageSize(img);
document.newPage();
img.setAbsolutePosition(0, 0);
document.add(img);
}
document.close();
}
I create a Document instance using the size of the first image. I then loop over an array of images, setting the page size of the next page to the size of each image before I trigger a newPage() [*]. Then I add the image at coordinate 0, 0 because now the size of the image will match the size of each page.
[*] The newPage() method only has effect if something was added to the current page. The first time you go through the loop, nothing has been added yet, so nothing happens. This is why you need set the page size to the size of the first image when you create the Document instance.

Android has the feature "PdfDocument" to achieve this,
class Main2Activity : AppCompatActivity() {
private var imgFiles: Array<File?>? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
imgFiles= arrayOfNulls(2)
imgFiles!![0] = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString() + "/doc1.png")
imgFiles!![1] = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString() + "/doc3.png")
val file = getOutputFile(File(Environment.getExternalStorageDirectory().absolutePath)
, "/output.pdf")
val fOut = FileOutputStream(file)
val document = PdfDocument()
var i = 0
imgFiles?.forEach {
i++
val bitmap = BitmapFactory.decodeFile(it?.path)
val pageInfo = PdfDocument.PageInfo.Builder(bitmap.width, bitmap.height, i).create()
val page = document.startPage(pageInfo)
val canvas = page?.canvas
val paint = Paint()
canvas?.drawPaint(paint)
paint.color = Color.BLUE;
canvas?.drawBitmap(bitmap, 0f, 0f, null)
document.finishPage(page)
bitmap.recycle()
}
document.writeTo(fOut)
document.close()
}
private fun getOutputFile(path: File, fileName: String): File? {
if (!path.exists()) {
path.mkdirs()
}
val file = File(path, fileName)
try {
if (file.exists()) {
file.delete()
}
file.createNewFile()
} catch (e: Exception) {
e.printStackTrace()
}
return file
}
}
finally enable the storage permission in manifest, this should works

Related

How to convert a PDF to a Bitmap image using PdfiumViewer?

I would like to grab a PDF from my hard disc and convert it to a bitmap image.
How can I accomplish this using PdfiumViewer?
SOLUTION:
1) Add this nuget to your project: https://www.nuget.org/packages/PdfiumViewer/ (if it doesn't work, add this one too: https://www.nuget.org/packages/PdfiumViewer.Native.x86_64.v8-xfa/)
2) Add the reference "PdfiumViewer" to your project References
3) Use the following code:
using (var pdfDocument = PdfiumViewer.PdfDocument.Load(#"document.pdf"))
{
var bitmapImage = pdfDocument.Render(0, 300, 300, true);
bitmapImage.Save(#"image.bmp", ImageFormat.Bmp);
}
You can use the PdfDocument.Render method:
void renderPdfToFile(string pdfFilename, string outputImageFilename, int dpi) {
using (var doc = PdfDocument.Load(pdfFilename)) { // Load PDF Document from file
for (int page = 0; page < doc.PageCount; page++) { // Loop through pages
using (var img = doc.Render(page, dpi, dpi, false)) { // Render with dpi and with forPrinting false
img.Save($"page_{page}_{outputImageFilename}"); // Save rendered image to disc
}
}
}
}

How to embed all fonts from other PDF iText 7

I am trying to overlay two PDF files using iText7/C#.
The first one is kind of background and the second one is containing form fields.
Everything works fine and only problem is that I lose fonts from the second file.
I try as follows:
static public bool Overlay(string back_path, string front_path, string merge_path)
{
PdfReader reader;
PdfDocument pdf = null, front;
try
{
reader = new PdfReader(back_path);
pdf = new PdfDocument(reader, new PdfWriter(merge_path));
front = new PdfDocument(new PdfReader(front_path));
var form = PdfAcroForm.GetAcroForm(front, false);
PdfAcroForm dform = PdfAcroForm.GetAcroForm(pdf, true);
IDictionary<String, PdfFormField> fields = form.GetFormFields();
// copy styles
dform.SetDefaultResources(form.GetDefaultResources());
dform.SetDefaultAppearance(form.GetDefaultAppearance().GetValue());
// do overlay
foreach (KeyValuePair<string, PdfFormField> pair in fields)
{
try
{
var field = pair.Value;
PdfPage page = field.GetWidgets().First().GetPage();
int pg_no = front.GetPageNumber(page);
if (pg_no < front_start_page || pg_no > front_end_page)
continue;
PdfObject copied = field.GetPdfObject().CopyTo(pdf, true);
PdfFormField copiedField = PdfFormField.MakeFormField(copied, pdf);
// The following returns null. If it returns something, I think I could use copiedField.setFont(font).
// var font = field.GetFont();
dform.AddField(copiedField, pdf.GetPage(pg_no));
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Overlaying field {pair.Key} failed. ({ex.Message})");
}
}
pdf.Close();
return true;
}
catch (Exception ex)
{
throw new OverlayException(ex.Message);
}
}
public static PdfDictionary get_font_dict(PdfDocument pdfDoc)
{
PdfDictionary acroForm = pdfDoc.GetCatalog().GetPdfObject().GetAsDictionary(PdfName.AcroForm);
if (acroForm == null)
{
return null;
}
PdfDictionary dr = acroForm.GetAsDictionary(PdfName.DR);
if (dr == null)
{
return null;
}
PdfDictionary font = dr.GetAsDictionary(PdfName.Font);
return font;
}
So basically I get all fonts from the second PDF and copy them to the final PDF.
But it does not work.
Logically, I think setting font of the original field to the copied one is the right way.
I mean PdfFormField.GetFont() and SetFont().
But it always returns null.
In a comment you clarified:
the background PDF can be assumed not to have form fields or annotations. I mean we can assume background PDF only contains static content (scanned form) and the front PDF only contains formfields.
In that case the easiest way to implement your method is to add the background as xobject to the form PDF instead of adding the form to the background PDF.
You can simply do that like this:
PdfReader formReader = new PdfReader(front_path);
PdfReader backReader = new PdfReader(back_path);
PdfWriter writer = new PdfWriter(merge_path);
using (PdfDocument source = new PdfDocument(backReader))
using (PdfDocument target = new PdfDocument(formReader, writer))
{
PdfFormXObject xobject = source.GetPage(1).CopyAsFormXObject(target);
PdfPage targetFirstPage = target.GetFirstPage();
PdfStream stream = targetFirstPage.NewContentStreamBefore();
PdfCanvas pdfCanvas = new PdfCanvas(stream, targetFirstPage.GetResources(), target);
Rectangle cropBox = targetFirstPage.GetCropBox();
pdfCanvas.AddXObject(xobject, cropBox.GetX(), cropBox.GetY());
}
Depending on the exact static contents of the background and the form PDF, you might want to use NewContentStreamAfter instead of NewContentStreamBefore or even to use some nifty blend mode to get the exact static content look you want.

System.ObjectDisposedException: 'Cannot access a closed file.'

For the past week or so this exception is causing me a headache, I can't for the life of me fix it. I'm using iTextSharp to merge PDF files and add a watermark on them if the user chooses to do so.
Here's the code for merging :
private void CreateMergedPdf(object sender, DoWorkEventArgs e)
{
using (FileStream stream = new FileStream(pdfname, FileMode.Create)) {
Document pdfDoc = new Document(PageSize.A4);
PdfCopy pdf = new PdfCopy(pdfDoc, stream);
pdfDoc.Open();
int i = 0;
foreach (File_class newpdf in AddedPDFs)
{
(sender as BackgroundWorker).ReportProgress(i++);
if (newpdf.toMerge)
{
PdfReader reader = new PdfReader(newpdf.file_path);
pdf.AddDocument(reader); //<!> Exception here
this.Dispatcher.Invoke(() => progBtxt.Text = "Merging file #" + newpdf.file_id + "..."); //Dispatcher.Invoke since UI is on seperate thread
if (add_wtrmk)//This is called for every FILE
{
AddWatermark(reader, stream);
}
}
}
}
}
And here's the code for the watermark:
private void AddWatermark(PdfReader reader, FileStream stream)
{
using (PdfStamper pdfStamper = new PdfStamper(reader, stream))//This is called for every PAGE of the file
{
for (int pgIndex = 1; pgIndex <= reader.NumberOfPages; pgIndex++)
{
Rectangle pageRectangle = reader.GetPageSizeWithRotation(pgIndex);
PdfContentByte pdfData; //Contains graphics and text content of page returned by pdfstamper
if (this.Dispatcher.Invoke(() => dropdown.Text == "Under Content"))
{
pdfData = pdfStamper.GetUnderContent(pgIndex);
}
else if (this.Dispatcher.Invoke(() => dropdown.Text == "Over Content"))
{
pdfData = pdfStamper.GetOverContent(pgIndex);
}
else//Just in case
{
MessageBox.Show("Something went wrong when adding the watermark");
return;
}
//Set font
pdfData.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA_BOLD, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 40);
//Create new graphics state and assign opacity
PdfGState graphicsState = new PdfGState();
graphicsState.FillOpacity = 0.25F;
//Set graphics state to pdfcontentbyte
pdfData.SetGState(graphicsState);
//Color of watermark
pdfData.SetColorFill(BaseColor.GRAY);
pdfData.BeginText();
//Show text as per position and rotation
this.Dispatcher.Invoke(() => pdfData.ShowTextAligned(Element.ALIGN_CENTER, WtrmkTextbox.Text, pageRectangle.Width / 2, pageRectangle.Height / 2, 45));
pdfData.EndText();
}
}
}
The error appears on the code for merging, specifically the line " pdf.AddDocument(reader);" BUT I get this error only if I try to add watermarks on more than one files (with just one file it works perfectly).
I'm thinking either I am closing something too early, or addWatermark() does - I've tried changing our the using statemets to no avail. I must be missing something
Okay, it seems PdfStamper was the culprit, i passed the necessary arguements to AddWatermark() and added a simple if statement. Now everything works perfectly.
BIG thanks to Mark Rucker

PDFsharp does not see pages in documents

I made some file merging using PDFsharp before, and now I'm trying to change several files (insert or remove some pages) and I faced with problem, that the library does not see pages. It says that PageCount == 0 and I cannot find pages in object (while debugging). And sure, I cannot do my current work. I use this very simple code:
var destinationPdf = new PdfDocument(destinationFilePath);
Int32 count = destinationPdf.PageCount;
And also, here is the code, that I used to merge files to one PDF before:
public class PdfCreator
{
private PdfDocument document;
public PdfCreator()
{
this.document = new PdfDocument();
}
public void AddImage(String imageFilePath)
{
PdfPage newPage = this.document.AddPage();
XGraphics xGraphics = XGraphics.FromPdfPage(newPage);
XImage image = XImage.FromFile(imageFilePath);
xGraphics.DrawImage(image, 0, 0);
}
public void AddPdfFile(String pdfFilePath)
{
PdfDocument inputDocument = PdfReader.Open(pdfFilePath, PdfDocumentOpenMode.Import);
Int32 count = inputDocument.PageCount;
for (Int32 currentPage = 0; currentPage < count; currentPage++)
{
PdfPage page = inputDocument.Pages[currentPage];
this.document.AddPage(page);
}
}
public void AddTextFile(String txtFilePath)
{
PdfPage newPage = this.document.AddPage();
XGraphics xGraphics = XGraphics.FromPdfPage(newPage);
var xFont = new XFont("Times New Roman", 12, XFontStyle.Bold);
var xTextFormatter = new XTextFormatter(xGraphics);
var rect = new XRect(30, 30, 540, 740);
xGraphics.DrawRectangle(XBrushes.Transparent, rect);
xTextFormatter.Alignment = XParagraphAlignment.Left;
xTextFormatter.DrawString(File.ReadAllText(txtFilePath), xFont, XBrushes.Black, rect, XStringFormats.TopLeft);
}
public void Save(String destinationFilePath)
{
if (this.document.Pages.Count > 0)
{
this.document.Save(destinationFilePath);
this.document.Close();
}
}
}
Your code
var destinationPdf = new PdfDocument(destinationFilePath);
Int32 count = destinationPdf.PageCount;
creates a new document in memory - and surely this document is empty.
Use PdfReader.Open to create a document in memory from an existing file.
When I place the mouse cursor over PdfDocument in your code I get this tooltip:
Creates a new PDF document with the specified file name. The file is
immediately created and keeps locked until the document is closed, at
that time the document is saved automatically. Do not call Save() for
documents created with this constructor, just call Close(). To open an
existing PDF file and import it, use the PdfReader class.

issue in exporting image to pdf

m having a grid: companysnapshot.. that grid is exported to disk then its again taken from disk and exported to the pdf.
Below code is working fine and export with the image is done. bt issues is that..
-->image is saved from UI is black background..when its exported is changing in white background( may be its getting converted to png)
--> i want to align the coordinates of the image in the pdf page
is there any way to either increase the width of the image or pdf page.
m a newbie to this ...it would be helpful if someone code me out for this a little.
private void PrepareDocument(RadDocument document)
{
document.SectionDefaultPageOrientation = PageOrientation.Landscape;
document.LayoutMode = DocumentLayoutMode.Paged;
document.Measure(RadDocument.MAX_DOCUMENT_SIZE);
document.Arrange(new RectangleF(PointF.Empty, document.DesiredSize));
}
chart document part:
private void CreateChartDocumentPart(RadDocument document, Grid whGrid, Grid companysnapshot, Grid chartgridimage)
{
Telerik.Windows.Documents.Model.Section section = new Telerik.Windows.Documents.Model.Section();
Telerik.Windows.Documents.Model.Paragraph paragraph = new Telerik.Windows.Documents.Model.Paragraph();
Telerik.Windows.Documents.Model.Span span1;
using (MemoryStream ms = new MemoryStream())
{
companysnapshot.Measure(new System.Windows.Size(double.PositiveInfinity, double.PositiveInfinity));
int companywidth = (int)Math.Round(companysnapshot.ActualWidth);
int companyheight = (int)Math.Round(companysnapshot.ActualHeight);
companywidth = companywidth == 0 ? 1 : companywidth;
companyheight = companyheight == 0 ? 1 : companyheight;
RenderTargetBitmap rtbmp = new RenderTargetBitmap(companywidth, companyheight, 96d, 96d, PixelFormats.Default);
rtbmp.Render(companysnapshot);
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtbmp));
FileStream fs1 = File.Create(#"C:\Users\Admin\Desktop\Chart12xx.bmp");
encoder.Save(fs1);
fs1.Close();
// this.ExportPNGToImage(chart, ms);
paragraph.LeftIndent = 0;
paragraph.RightIndent = 0.0;
FileStream ss = File.Open(#"C:\Users\Admin\Desktop\Chart12xx.bmp", FileMode.Open);
ImageInline image = new ImageInline(ss, new Size(companywidth, companyheight), "bmp");
paragraph.FlowDirection = FlowDirection.LeftToRight;
paragraph.Inlines.Add(image);
ss.Close();
//Span spacespan = new Span(" ");
//paragraph.Inlines.Add(spacespan);
}
try
{
section1.Blocks.Add(paragraph);
document.Sections.Add(section1);
}
catch (Exception)
{
}
// paragraph.Inlines.Add(new Span(FormattingSymbolLayoutBox.LINE_BREAK));
}
issue is solved.. by switching from telerik export to itextsharp for pdf export.

Categories