How to add an SVG to a PDF using iText7 - java

I need to add an SVG graphic into PDF file.
Is it that possible using iText7?
Using iText5:
BufferedReader in = new BufferedReader(new InputStreamReader(svgUrl.openStream()));
String xmlParser = XMLResourceDescriptor.getXMLParserClassName();
SVGDocument svgDoc = new SAXSVGDocumentFactory(xmlParser).createSVGDocument(null, in);
in.close();
// Try to read embedded height and width
float svgWidth = Float.parseFloat(svgDoc.getDocumentElement().getAttribute("width").replaceAll("[^0-9.,]",""));
float svgHeight = Float.parseFloat(svgDoc.getDocumentElement().getAttribute("height").replaceAll("[^0-9.,]",""));
PdfTemplate svgTempl = PdfTemplate.createTemplate(writer, svgWidth, svgHeight);
Graphics2D g2d = svgTempl.createGraphics(svgWidth,svgHeight);
GraphicsNode chartGfx = (new GVTBuilder()).build(new BridgeContext(new UserAgentAdapter()), svgDoc);
chartGfx.paint(g2d);
g2d.dispose();
Image img = new ImgTemplate(svgTempl);
I found out that in the following page:
PdfPTable and PdfTemplate
there is a way to create something similar as Template:
PdfFormXObject svgTempl = new PdfFormXObject(new Rectangle(svgWidth, svgHeight));
How can I create Graphics2D?

Coincidentally, we're releasing our SVG implementation today. We don't support the full feature set just yet, we're still working on that in Q2 and beyond, but you can use it already. The artifact is on Maven. The repository is on Github. And the documentation is on our public wiki.
Code samples will be put on the web site, but it's a very simple API, similar to how pdfHtml works. There's an SvgConverter utility class that offers multiple ways to convert to PDF or PDF XObjects.
PdfDocument doc = new PdfDocument(
new PdfWriter(pdfOutputStream,
new WriterProperties().setCompressionLevel(0)));
doc.addNewPage();
SvgConverter.drawOnDocument(svg, doc, 1);
doc.close();
Source: I'm an iText developer working on the SVG implementation

Related

How to render part of a PDF file as an image using PDFBox?

PDFBox offer functions to render a entire page, but no way to render only a specific rectangle of the page.
This code is working for me. But as mentioned above it renders the whole page and I need a method to render a little area of the pdf file:
File file = new File("package.pdf");
PDDocument document = PDDocument.load(file);
PDFRenderer renderer = new PDFRenderer(document);
BufferedImage image = renderer.renderImageWithDPI(0, 400);
ImageIO.write(image, "PNG", new File("C:/package1.png"));
document.close();
I would be very happy about a solution, since I have not found a solution for hours
I have found a soulution by myself. CropBox was the deciding keyword i did not know about.
File file = new File("package.pdf");
PDDocument document = PDDocument.load(file);
PDPage page = document.getPage(0);
page.setCropBox(new PDRectangle(133f, 150f, 100f, 100f)); // Here you draw a rectangle around the area you want to specify
PDFRenderer renderer = new PDFRenderer(document);
BufferedImage image = renderer.renderImageWithDPI(0, 400);
ImageIO.write(image, "PNG", new File("C:/fatihabi.png"));
document.close();

How to copy/move AcroForm fields from one document to new blank one using IText5 or IText7?

I need to copy whole AcroForm including field positions and values from template PDF to a new blank PDF file. How can I do that?
In short words - I need to get rid of "background" from the template and leave only filed forms.
The whole point of this is to create a PDF with content that would be printed on pre-printed templates.
I am using IText 5 but I can switch to 7 if usefull examples would be provided
After a lot of trial and error I have found the solution to "How to copy AcfroForm fields into another PDF". It is a iText v7 version. I hope it will help somebody someday.
private byte[] copyFormElements(byte[] sourceTemplate) throws IOException {
PdfReader completeReader = new PdfReader(new ByteArrayInputStream(sourceTemplate));
PdfDocument completeDoc = new PdfDocument(completeReader);
ByteArrayOutputStream out = new ByteArrayOutputStream();
PdfWriter offsetWriter = new PdfWriter(out);
PdfDocument offsetDoc = new PdfDocument(offsetWriter);
offsetDoc.initializeOutlines();
PdfPage blank = offsetDoc.addNewPage();
PdfAcroForm originalForm = PdfAcroForm.getAcroForm(completeDoc, false);
// originalForm.getPdfObject().copyTo(offsetDoc,false);
PdfAcroForm offsetForm = PdfAcroForm.getAcroForm(offsetDoc, true);
for (String name : originalForm.getFormFields().keySet()) {
PdfFormField field = originalForm.getField(name);
PdfDictionary copied = field.getPdfObject().copyTo(offsetDoc, false);
PdfFormField copiedField = PdfFormField.makeFormField(copied, offsetDoc);
offsetForm.addField(copiedField, blank);
}
offsetDoc.close();
completeDoc.close();
return out.toByteArray();
}
Did you check the PdfCopyForms object:
Allows you to add one (or more) existing PDF document(s) to create a new PDF and add the form of another PDF document to this new PDF.
I didn't find an example, but you could try something like this:
PdfReader reader1 = new PdfReader(src1); // a document with a form
PdfReader reader2 = new PdfReader(src2); // a document without a form
PdfCopyForms copy = new PdfCopyForms(new FileOutputStream(dest));
copy.AddDocument(reader1); // add the document without the form
copy.CopyDocumentFields(reader2); // add the fields of the document with the form
copy.close();
reader1.close();
reader2.close();
I see that the class is deprecated. I'm not sure of that's because iText 7 makes it much easier to do this, or if it's because there were technical problems with the class.

How to add text watermark to pdf in Java using Apache PDFBox?

I am not getting any tutorial for adding a text watermark in a PDF file? Can you all please guide me, I am very new to PDFBOX.
Its not duplicate, the link in the comment didn't help me. I want to add text, not an image to the pdf.
Here is an example using PDFBox 2.0.2. This will load a PDF and write some text in the bottom right corner in a red transparent font. If it is a multiple page PDF the watermark will appear on every page. It might not be production ready, as I am not sure if there are some additional null conditions that need to be checked, but it should get you running in the right direction.
Keep in mind that this particular block of code will not modify the original PDF, but will create a new PDF using the Tmp_(filename) as the output.
private static void watermarkPDF (File fileStored) {
File tmpPDF;
PDDocument doc;
tmpPDF = new File(fileStored.getParent() + System.getProperty("file.separator") +"Tmp_"+fileStored.getName());
doc = PDDocument.load(fileStored);
for(PDPage page:doc.getPages()){
PDPageContentStream cs = new PDPageContentStream(doc, page, AppendMode.APPEND, true, true);
String ts = "Some sample text";
PDFont font = PDType1Font.HELVETICA_BOLD;
float fontSize = 14.0f;
PDResources resources = page.getResources();
PDExtendedGraphicsState r0 = new PDExtendedGraphicsState();
r0.setNonStrokingAlphaConstant(0.5f);
cs.setGraphicsStateParameters(r0);
cs.setNonStrokingColor(255,0,0);//Red
cs.beginText();
cs.setFont(font, fontSize);
cs.setTextMatrix(Matrix.getTranslateInstance(0f,0f));
cs.showText(ts);
cs.endText();
}
cs.close();
}
doc.save(tmpPDF);
}

Drawing vector images on PDF with PDFBox

I would like to draw a vector image on a PDF with Apache PDFBox.
This is the code I use to draw regular images
PDPage page = (PDPage) document.getDocumentCatalog().getAllPages().get(1);
PDPageContentStream contentStream = new PDPageContentStream(document, page, true, true);
BufferedImage _prevImage = ImageIO.read(new FileInputStream("path/to/image.png"));
PDPixelMap prevImage = new PDPixelMap(document, _prevImage);
contentStream.drawXObject(prevImage, prevX, prevY, imageWidth, imageHeight);
If I use a svg or wmf image instead of png, the resulting PDF document comes corrupted.
The main reason I want the image to be a vector image is that with PNG or JPG the image looks horrible, I think it gets somehow compressed so it looks bad. With vector images this shouldn't happen (well, when I export svg paths as PDF in Inkscape it doesn't happen, vector paths are preserved).
Is there a way to draw a svg or wmf (or other vector) to PDF using Apache PDFBox?
I'm currently using PDFBox 1.8, if that matters.
See the library pdfbox-graphics2d, touted in this Jira.
You can draw the SVG, via Batik or Salamander or whatever, onto the class PdfBoxGraphics2D, which is parallel to iText's template.createGraphics(). See the GitHub page for samples.
PDDocument document = ...;
PDPage page = ...; // page whereon to draw
String svgXML = "<svg>...</svg>";
double leftX = ...;
double bottomY = ...; // PDFBox coordinates are oriented bottom-up!
// I set these to the SVG size, which I calculated via Salamander.
// Maybe it doesn't matter, as long as the SVG fits on the graphic.
float graphicsWidth = ...;
float graphicsHeight = ...;
// Draw the SVG onto temporary graphics.
var graphics = new PdfBoxGraphics2D(document, graphicsWidth, graphicsHeight);
try {
int x = 0;
int y = 0;
drawSVG(svg, graphics, x, y); // with Batik, Salamander, or whatever you like
} finally {
graphics.dispose();
}
// Graphics are not visible till a PDFormXObject is added.
var xform = graphics.getXFormObject();
try (var contentWriter = new PDPageContentStream(document, page, AppendMode.APPEND, false)) { // false = don't compress
// XForm objects have to be placed via transform,
// since they cannot be placed via coordinates like images.
var transform = AffineTransform.getTranslateInstance(leftX, bottomY);
xform.setMatrix(transform);
// Now the graphics become visible.
contentWriter.drawForm(xform);
}
And ... in case you want also to scale the SVG graphics to 25% size:
// Way 1: Scale the SVG beforehand
svgXML = String.format("<svg transform=\"scale(%f)\">%s</svg>", .25, svgXML);
// Way 2: Scale in the transform (before calling xform.setMatrix())
transform.concatenate(AffineTransform.getScaleInstance(.25, .25));
I do this, but not directly.
In first transform your SVG documents in PDF documents with FOP librairy and Batik.
https://xmlgraphics.apache.org/fop/dev/design/svg.html.
In second times, you can use LayerUtility in pdfbox to transform your new pdf document in PDXObjectForm. After that, just needs to include PDXObjectForm in your final pdf documents.
The final working solution for me that loads an SVG file and overlays it on a PDF file (this renders the SVG in a 500x500 box at (0,0) coordinate which is bottom left of the PDF document):
package com.example.svgadder;
import java.io.*;
import java.nio.*;
import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.PDPageContentStream.AppendMode;
import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject;
import de.rototor.pdfbox.graphics2d.PdfBoxGraphics2D;
import java.awt.geom.AffineTransform;
import com.kitfox.svg.SVGDiagram;
import com.kitfox.svg.SVGException;
import com.kitfox.svg.SVGUniverse;
public class App
{
public static void main( String[] args ) throws Exception {
App app = new App();
}
public App() throws Exception {
// loading PDF and SVG files
File pdfFile = new File("input.pdf");
File svgFile = new File("input.svg");
PDDocument doc = PDDocument.load(pdfFile);
PDPage page = doc.getPage(0);
SVGUniverse svgUniverse = new SVGUniverse();
SVGDiagram diagram = svgUniverse.getDiagram(svgUniverse.loadSVG(f.toURL()));
PdfBoxGraphics2D graphics = new PdfBoxGraphics2D(doc, 500, 500);
try {
diagram.render(graphics);
} finally {
graphics.dispose();
}
PDFormXObject xform = graphics.getXFormObject();
try (PDPageContentStream contentWriter = new PDPageContentStream(doc, page, AppendMode.APPEND, false)) {
AffineTransform transform = AffineTransform.getTranslateInstance(0, 0);
xform.setMatrix(transform);
contentWriter.drawForm(xform);
}
doc.save("res.pdf");
doc.close();
}
}
Please use svgSalamander from here:
https://github.com/mgarin/svgSalamander
Please use what Coemgenus suggested for scaling your final overlaid SVG. I tried the 2nd option and it works well.
Nirmal

Convert WMF to PNG/BMP/JPG

How can I convert one WMF file to PNG/BMP/JPG format with custom output resolution?
Example: Take WMF file and outputs PNG file with 2000x2000 px.
Thanks in advance.
You can use the excelent Batik ( http://xmlgraphics.apache.org/batik/ ) lib to achieve this. But you will need to follow this steps:
Convert the WMF file to SVG using the WMFTranscoder
Convert the SVG to JGP using the JPGTranscoder
WMF >> SVG >> JPG
Here is a discussion on coderanch about it: http://www.coderanch.com/t/422868/java/java/converting-WMF-Windows-Meta-File
WMF, EMF and EMF+ are integral parts of slideshows, therefore I've developed a renderer for those as part of Apache POI. As for the upcoming POI-4.1.2 this is still work in progress - if you have any rendering issues, please upload your file in a new bug report in our bugzilla.
The main description can be found in the POI documentation.
Here is an excerpt:
#1 - Use PPTX2PNG via file or stdin
For file system access, you need to save your slideshow/WMF/EMF/EMF+ first to disc and then call PPTX2PNG.main() with the corresponding parameters.
for stdin access, you need to redirect System.in before:
/* the file content */
InputStream is = ...;
/* Save and set System.in */
InputStream oldIn = System.in;
try {
System.setIn(is);
String[] args = {
"-format", "png", // png,gif,jpg,svg or null for test
"-outdir", new File("out/").getCanonicalPath(),
"-outfile", "export.png",
"-fixside", "long",
"-scale", "800",
"-ignoreParse",
"stdin"
};
PPTX2PNG.main(args);
} finally {
System.setIn(oldIn);
}
#2 - Render WMF / EMF / EMF+ via the *Picture classes
File f = samples.getFile("santa.wmf");
try (FileInputStream fis = new FileInputStream(f)) {
// for WMF
HwmfPicture wmf = new HwmfPicture(fis);
// for EMF / EMF+
HemfPicture emf = new HemfPicture(fis);
Dimension dim = wmf.getSize();
int width = Units.pointsToPixel(dim.getWidth());
// keep aspect ratio for height
int height = Units.pointsToPixel(dim.getHeight());
double max = Math.max(width, height);
if (max > 1500) {
width *= 1500/max;
height *= 1500/max;
}
BufferedImage bufImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = bufImg.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
wmf.draw(g, new Rectangle2D.Double(0,0,width,height));
g.dispose();
ImageIO.write(bufImg, "PNG", new File("bla.png"));
}
You can use different tools for this format. You can choose for example GIMP. In Java you have a library for converting WMF files.
I wrote a walkaround here, for Java I learned that I can run shell command following answers in this question. For WMF, convert it to EMF first following this answer.

Categories

Resources