How to use iText to add a watermark using an embedded font - java

I've several pdf/a documents with some embedded fonts, now I've to post-process these documents using iText to add a watermark.
I know that it's possible to embed a font with iText:
BaseFont bf = BaseFont.createFont(BaseFont.HELVETICA, BaseFont.WINANSI, BaseFont.EMBEDDED);
but I would like to use a font that is already embedded in the document to add the textual watermark (something like "SAMPLE COPY").
How can I do it?

What you want is a DocumentFont. You cannot create them directly, the constructor is package private, but BaseFont.createFont(PRIndirectReference) will do the trick.
So you just need to get a PRIndirectReference to the font you want. "PR"s come from a PdfReader. There are two ways to find the font you're looking for and get a reference to it:
1) Enumerate every object in the PdfReader, filtering out everything that's not a PRStream, from there dropping everything that's not a /Type /Font, and looking for a font with the correct name.
public PRIndirectReference findNamedFont( PdfReader myReader, String desiredFontName) {
int objNum = 0;
PdfObject curObj;
do {
//The "Release" version doesn't keep a reference
//to the object so it can be GC'd later. Quite Handy
//when dealing with Really Big PDFs.
curObj = myReader.getPdfObjectRelease( objNum++ );
if (curObj instanceof PRStream) {
PRStream stream = (PRStream)curObj;
PdfName type = stream.getAsName(PdfName.TYPE);
if (PdfName.FONT.equals(type)) {
PdfString fontName = stream.getAsString(PdfName.BASEFONT);
if (desiredFontName.equals(fontName.toString())) {
return curObj.getIndRef();
}
}
}
} while (curObj != null);
return null;
}
2) Examine your pages' resource dictionaries /Font <<>> dicts, looking for a font with the correct name. Keep in mind that XObject Form resources have resources of their own you'll have to check to:
public PRIndirectReference findFontInPage(PdfReader reader, String desiredName, int i) {
PdfDictionary page = reader.getPageN(i);
return findFontInResources(page.getAsDict(PdfName.RESOURCES), desiredName);
}
public PRIndirectReference findFontInResources(PdfDictionary resources, String desiredName) {
if (resources != null) {
PdfDictionary fonts = resources.getAsDict(PdfName.FONTS);
if (fonts != null) {
for (PdfName curFontName : fonts.keySet()) {
PRStream curFont (PRStream)= fonts.getAsStream(curFontName);
if (desiredName.equals(curFont.getAsString(PdfName.BASEFONT).toString()) {
return (PRIndirectReference) curFont.getIndirectReference();
}
}
}
PdfDictionary xobjs = resources.getAsDict(PdfName.XOBJECTS);
if (xobjs != null) {
for (PdfName curXObjName : xobjs.keySet()) {
PRStream curXObj = (PRStream)xobjs.getAsStream(curXObjName);
if (curXObj != null && PdfName.FORM.equals(curXObj.getAsName(PdfName.SUBTYPE)) {
PdfDictionary resources = curXObj.getAsDict(PdfName.RESOURCES);
PRIndirectReference ref = findFontInResources(resources, desiredName);
if (ref != null) {
return ref;
}
}
}
}
}
return null;
}
Either one of those will get you the PRIndirectReference you're after. Then you call BaseFont.createFont(myPRRef) and you'll have the DocumentFont you need. The first method will find any font in the PDF, while the second will only find fonts That Are Actually Used.
Also, subsetted fonts are supposed to have a "6-random-letters-plus-sign" tag prepended to the font name. DO NOT use a font subset. The characters you're using may not be in the subset, leading to what I call the " arry ole" problem. It sounds nice and dirty, but it was really just our sales guy's name: "Harry Vole" missing the upper case letters because I'd subsetted some font I shouldn't have Many Moons Ago.
PS: never embed subsets of fonts you intend to be used in a form field. No Bueno.
The usual "I wrote all that code in the answer box here" disclaimer applies, but I've written a LOT of this sort of code, so it just might work out of the box. Cross your fingers. ;)

An entirely different approach: Use Line Art instead of Text.
If you create a "line art only" PdfGraphics2D object from the page's overContent, you can use an AWT font and need not worry about embedding at all. With a relatively short string you don't have to worry about the PDF's size exploding either.
PdfContentByte overcontent = stamper.getOverContent(1);
Graphics2D g2d = overcontent.createGraphicsShapes(pageWid, pageHei);
drawStuffToTheGraphic(g2d);
g2d.dispose();
This will result in "text" that is actually line art. It cannot be selected, searched, etc. That could be good or bad depending on what you're after.

Using plain jPod (BSD, SourceForge) you could base on the "Watermark" example. WIth
PDFontTools.getFonts(doc)
you can enumerate the fonts and then use one of them in the "createForm" method...

Related

Fill out field for pdf revision when signing with PDFbox

I am trying to add input to my existing field in a pdf that should be signed at the end. I used the library from swisscom (https://github.com/SwisscomTrustServices/pdfbox-ais-client/blob/8d52c759ade267b0c443fcd6f15bc9635c745d72/src/main/java/com/swisscom/ais/client/impl/PdfDocument.java#L97) with PDFbox (v2.0.24) and added these lines
try {
PDAcroForm acroForm = pdDocument.getDocumentCatalog().getAcroForm();
acroForm.setSignaturesExist(true);
acroForm.setAppendOnly(true);
acroForm.getCOSObject().setDirect(true);
acroForm.getCOSObject().setNeedToBeUpdated(true);
FieldInput[] fields = new FieldInput[1];
COSObject pdfFields = acroForm.getCOSObject().getCOSObject(COSName.FIELDS);
if (pdfFields != null) {
pdfFields.setNeedToBeUpdated(true);
}
fields[0] = new FieldInput("1", "foobar");
for (int i = 0; i < fields.length; i++) {
PDField field = acroForm.getField(fields[0].id);
if (field != null) {
field.setValue(fields[0].value);
Log.info("set field: " + field.getFullyQualifiedName());
}
}
pdDocument.getDocumentCatalog().getCOSObject().setNeedToBeUpdated(true);
} catch (Exception e) {
Log.warn(e);
}
I get the log output that the field was set, but in the final document the field is still empty. Using this answer from PDFBox 2.0 create signature field and save incremental with already signed document was no luck for me, I think I messed up the form handling since pdfFields is null.
Update:
I added the suggestion from Tilman, now the entry gets set with
field.getCOSObject().setNeedToBeUpdated(true);
But when looking at the signature I have no information which fields are filled out:
Is it possible with pdfbox to achieve the same output as AdobeSign like where you can store more detailed information in the revision metadata? I am not able to open the file with itext rups because the pdf gets locked with a password at the end....
And what would be the best way to look the fields when everyone is done (so the fields are not shown as editable fields anymore):
setting a lock like in Adobe
setting some protection after the field was filled
The update flag must be set on the field itself
field.getCOSObject().setNeedToBeUpdated(true);
and on the appearance of the widget of the field
field.getWidgets().get(0).getAppearance().getCOSObject().setNeedToBeUpdated(true);
(this assumes that the field is its own widget and that there is only one)
It might still work if the second code part is missing because Adobe Reader updates the appearance when displaying.

PDFbox saying PDDocument closed when its not

I am trying to populate repeated forms with PDFbox. I am using a TreeMap and populating the forms with individual records. The format of the pdf form is such that there are six records listed on page one and a static page inserted on page two. (For a TreeMap larger than six records, the process repeats). The error Im getting is specific to the size of the TreeMap. Therein lies my problem. I can't figure out why when I populate the TreeMap with more than 35 entries I get this warning:
Apr 23, 2018 2:36:25 AM org.apache.pdfbox.cos.COSDocument finalize
WARNING: Warning: You did not close a PDF Document
public class test {
public static void main(String[] args) throws IOException, IOException {
// TODO Auto-generated method stub
File dataFile = new File("dataFile.csv");
File fi = new File("form.pdf");
Scanner fileScanner = new Scanner(dataFile);
fileScanner.nextLine();
TreeMap<String, String[]> assetTable = new TreeMap<String, String[]>();
int x = 0;
while (x <= 36) {
String lineIn = fileScanner.nextLine();
String[] elements = lineIn.split(",");
elements[0] = elements[0].toUpperCase().replaceAll(" ", "");
String key = elements[0];
key = key.replaceAll(" ", "");
assetTable.put(key, elements);
x++;
}
PDDocument newDoc = new PDDocument();
int control = 1;
PDDocument doc = PDDocument.load(fi);
PDDocumentCatalog cat = doc.getDocumentCatalog();
PDAcroForm form = cat.getAcroForm();
for (String s : assetTable.keySet()) {
if (control <= 6) {
PDField IDno1 = (form.getField("IDno" + control));
PDField Locno1 = (form.getField("locNo" + control));
PDField serno1 = (form.getField("serNo" + control));
PDField typeno1 = (form.getField("typeNo" + control));
PDField maintno1 = (form.getField("maintNo" + control));
String IDnoOne = assetTable.get(s)[1];
//System.out.println(IDnoOne);
IDno1.setValue(assetTable.get(s)[0]);
IDno1.setReadOnly(true);
Locno1.setValue(assetTable.get(s)[1]);
Locno1.setReadOnly(true);
serno1.setValue(assetTable.get(s)[2]);
serno1.setReadOnly(true);
typeno1.setValue(assetTable.get(s)[3]);
typeno1.setReadOnly(true);
String type = "";
if (assetTable.get(s)[5].equals("1"))
type += "Hydrotest";
if (assetTable.get(s)[5].equals("6"))
type += "6 Year Maintenance";
String maint = assetTable.get(s)[4] + " - " + type;
maintno1.setValue(maint);
maintno1.setReadOnly(true);
control++;
} else {
PDField dateIn = form.getField("dateIn");
dateIn.setValue("1/2019 Yearlies");
dateIn.setReadOnly(true);
PDField tagDate = form.getField("tagDate");
tagDate.setValue("2019 / 2020");
tagDate.setReadOnly(true);
newDoc.addPage(doc.getPage(0));
newDoc.addPage(doc.getPage(1));
control = 1;
doc = PDDocument.load(fi);
cat = doc.getDocumentCatalog();
form = cat.getAcroForm();
}
}
PDField dateIn = form.getField("dateIn");
dateIn.setValue("1/2019 Yearlies");
dateIn.setReadOnly(true);
PDField tagDate = form.getField("tagDate");
tagDate.setValue("2019 / 2020");
tagDate.setReadOnly(true);
newDoc.addPage(doc.getPage(0));
newDoc.addPage(doc.getPage(1));
newDoc.save("PDFtest.pdf");
Desktop.getDesktop().open(new File("PDFtest.pdf"));
}
I cant figure out for the life of me what I'm doing wrong. This is the first week I've been working with PDFbox so I'm hoping its something simple.
Updated Error Message
WARNING: Warning: You did not close a PDF Document
Exception in thread "main" java.io.IOException: COSStream has been closed and cannot be read. Perhaps its enclosing PDDocument has been closed?
at org.apache.pdfbox.cos.COSStream.checkClosed(COSStream.java:77)
at org.apache.pdfbox.cos.COSStream.createRawInputStream(COSStream.java:125)
at org.apache.pdfbox.pdfwriter.COSWriter.visitFromStream(COSWriter.java:1200)
at org.apache.pdfbox.cos.COSStream.accept(COSStream.java:383)
at org.apache.pdfbox.cos.COSObject.accept(COSObject.java:158)
at org.apache.pdfbox.pdfwriter.COSWriter.doWriteObject(COSWriter.java:522)
at org.apache.pdfbox.pdfwriter.COSWriter.doWriteObjects(COSWriter.java:460)
at org.apache.pdfbox.pdfwriter.COSWriter.doWriteBody(COSWriter.java:444)
at org.apache.pdfbox.pdfwriter.COSWriter.visitFromDocument(COSWriter.java:1096)
at org.apache.pdfbox.cos.COSDocument.accept(COSDocument.java:419)
at org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1367)
at org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1254)
at org.apache.pdfbox.pdmodel.PDDocument.save(PDDocument.java:1232)
at org.apache.pdfbox.pdmodel.PDDocument.save(PDDocument.java:1204)
at org.apache.pdfbox.pdmodel.PDDocument.save(PDDocument.java:1192)
at test.test.main(test.java:87)
The warning by itself
You appear to get the warning wrong. It says:
Warning: You did not close a PDF Document
So in contrast to what you think, "PDFbox saying PDDocument closed when its not", PDFBox says that you did not close a document!
After your edit one sees that it actually says that a COSStream has been closed and that a possible cause is that the enclosing PDDocument already has been closed. This is a mere possibility!
The warning in your case
That been said, by adding pages from one document to another you probably end up having references to those pages from both documents. In that case in the course of closing both documents (e.g. automatically via garbage collection), the second one closing may indeed stumble across some already closed COSStream instances.
So my first advice to simply do close the documents at the end by
doc.close();
newDoc.close();
probably won't remove the warnings, merely change their timing.
Actually you don't merely create two documents doc and newDoc, you even create new PDDocument instances and assign them to doc again and again, in the process setting the former document objects in that variable free for garbage collection. So you eventually have a big bunch of documents to be closed as soon as not referenced anymore.
I don't think it would be a good idea to close all those documents in doc early, in particular not before saving newDoc.
But if your code will eventually be run as part of a larger application instead of as a small, one-shot test application, you should collect all those PDDocument instances in some Collection and explicitly close them right after saving newDoc and then clear the collection.
Actually your exception looks like one of those lost PDDocument instances has already been closed by garbage collection, so you should collect the documents even in case of a simple one-shot utility to keep them from being GC disposed.
(#Tilman, please correct me if I'm wrong...)
Importing pages
To prevent problems with different documents sharing pages, you can try and import the pages to the target document and thereafter add the imported page to the target document page tree. I.e. replace
newDoc.addPage(doc.getPage(0));
newDoc.addPage(doc.getPage(1));
by
newDoc.addPage(newDoc.importPage(doc.getPage(0)));
newDoc.addPage(newDoc.importPage(doc.getPage(1)));
This should allow you to close each PDDocument instance in doc before losing it.
There are certain drawbacks to this, though, cf. the method JavaDoc and this answer here.
An actual issue in your code
In your combined document you will have many fields with the same name (at least in case of a sufficiently high number of entries in your CSV file) which you initially set to different values. And you access the fields from the PDAcroForm of the respective original document but don't add them to the PDAcroForm of the combined result document.
This is asking for trouble! The PDF format does consider forms to be document-wide with all fields referenced (directly or indirectly) from the AcroForm dictionary of the document, and it expects fields with the same name to effectively be different visualizations of the same field and therefore to all have the same value.
Thus, PDF processors might handle your document fields in unexpected ways, e.g.
by showing the same value in all fields with the same name (as they are expected to have the same value) or
by ignoring your fields (as they are not in the document AcroForm structure).
In particular programmatic reading of your PDF field values will fail because in that context the form is definitively considered document-wide and based in AcroForm. PDF viewers on the other hand might first show your set values and make look things ok.
To prevent this you should rename the fields before merging. You might consider using the PDFMergerUtility which does such a renaming under the hood. For an example usage of that utility class have a look at the PDFMergerExample.
Even though the above answer was marked as the solution to the problem, since the solution is buried in the comments, I wanted to add this answer at this level. I spent several hours searching for the solution.
My code snippets and comments.
// Collection solely for purpose of preventing premature garbage collection
List<PDDocument> sourceDocuments = new ArrayList<>( );
...
// Source document (actually inside a loop)
PDDocument docIn = PDDocument.load( artifactBytes );
// Add document to collection before using it to prevent the problem
sourceDocuments.add( docIn );
// Extract from source document
PDPage extractedPage = docIn.getPage( 0 );
// Add page to destination document
docOut.addPage( extractedPage );
...
// This was failing with "COSStream has been closed and cannot be read."
// Now it works.
docOut.save( bundleStream );

Change order pages of PDF document in iTextSharp

I'm trying to change reorder pages of my PDF document, but i can't and I don't know why.
I read several articals about changing order, it's java(iText) and i have got few problems with it.(exampl1, exampl2, example3). This example on c#, but there is using other method(exampl4)
I want take my TOC on 12 page and put to 2 page. After 12 page I have other content. This is my template for change order of pages:
String.Format("1,%s, 2-%s, %s-%s", toc, toc-1, toc+1, n)
This is my method for changing order of pages:
public void ChangePageOrder(string path)
{
MemoryStream baos = new MemoryStream();
PdfReader sourcePDFReader = new PdfReader(path);
int toc = 12;
int n = sourcePDFReader.NumberOfPages;
sourcePDFReader.SelectPages(String.Format("1,%s, 2-%s, %s-%s", toc, toc-1, toc+1, n));
using (var fs = new FileStream(path, FileMode.Open, FileAccess.ReadWrite))
{
PdfStamper stamper = new PdfStamper(sourcePDFReader, fs);
stamper.Close();
}
}
Here is call to method:
...
doc.Close();
ChangePageOrder(filePath);
What am I doing not right?
Thank you.
Your code can't work because you are using path to create the PdfReader as well as to create the FileStream. You probably get an error such as "The file is in use" or "The file can't be accessed".
This is explained here:
StackOverflow: How to update a PDF without creating a new PDF?
Official web site:
How to update a PDF without creating a new PDF?
You create a MemoryStream() named baos, but you aren't using that object anywhere. One way to solve your problem, is to replace the FileStream when you first create your PDF by that MemoryStream, and then use the bytes stored in that memory stream to create a PdfReader instance. In that case, PdfStamper won't be writing to a file that is in use.
Another option would be to use a different path. For instance: first you write the document to a file named my_story_unordered.pdf (created by PdfWriter), then you write the document to a file named my_story_reordered.pdf (created by PdfStamper).
It's also possible to create the final document in one go. In that case, you need to switch to linear mode. There's an example in my book "iText in Action - Second Edition" that shows how to do this: MovieHistory1
In the C# port of this example, you have:
writer.SetLinearPageMode();
In normal circumstances, iText will create a page tree with branches and leaves. As soon a a branch has more than 10 leaves, a new branch is created. With setLinearPageMode(), you tell iText not to do this. The complete page tree will consist of one branch with nothing but leaves (no extra branches). This is bad from the point of view of performance when viewing the document, but it's acceptable if the number of pages in your document is limited.
Once you've switched to page mode, you can reorder the pages like this:
document.NewPage();
// get the total number of pages that needs to be reordered
int total = writer.ReorderPages(null);
// change the order
int[] order = new int[total];
for (int i = 0; i < total; i++) {
order[i] = i + toc;
if (order[i] > total) {
order[i] -= total;
}
}
// apply the new order
writer.ReorderPages(order);
Summarized: if your document doesn't have many pages, use the ReorderPages method. If your document has many pages, use the method you've been experimenting with, but do it correctly. Don't try to write to the file that you are still trying to read.
Without going into details about what you should do you can loop through all pages from a pdf, put them into a new pdf doc with all the pages. You can put your logic inside the for loop.
reader = new PdfReader(sourcePDFpath);
sourceDocument = new Document(reader.GetPageSizeWithRotation(startpage));
pdfCopyProvider = new PdfCopy(sourceDocument, new System.IO.FileStream(outputPDFpath, System.IO.FileMode.Create));
sourceDocument.Open();
for (int i = startpage; i <= endpage; i++)
{
importedPage = pdfCopyProvider.GetImportedPage(reader, i);
pdfCopyProvider.AddPage(importedPage);
}
sourceDocument.Close();
reader.Close();

Error: org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm cannot be cast to org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage

I am trying to extract image from the pdf using pdfbox. I have taken help from this post . It worked for some of the pdfs but for others/most it did not. For example, I am not able to extract the figures in this file
After doing some research I found that PDResources.getImages is deprecated. So, I am using PDResources.getXObjects(). With this, I am not able to extract any image from the PDF and instead get this message at the console:
org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectForm cannot be cast to org.apache.pdfbox.pdmodel.graphics.xobject.PDXObjectImage
Now I am stuck and unable to find the solution. Please assist if anyone can.
//////UPDATE AS REPLY ON COMMENTS///
I am using pdfbox-1.8.10
Here is the code:
public void getimg ()throws Exception {
try {
String sourceDir = "C:/Users/admin/Desktop/pdfbox/mypdfbox/pdfbox/inputs/Yavaa.pdf";
String destinationDir = "C:/Users/admin/Desktop/pdfbox/mypdfbox/pdfbox/outputs/";
File oldFile = new File(sourceDir);
if (oldFile.exists()){
PDDocument document = PDDocument.load(sourceDir);
List<PDPage> list = document.getDocumentCatalog().getAllPages();
String fileName = oldFile.getName().replace(".pdf", "_cover");
int totalImages = 1;
for (PDPage page : list) {
PDResources pdResources = page.getResources();
Map pageImages = pdResources.getXObjects();
if (pageImages != null){
Iterator imageIter = pageImages.keySet().iterator();
while (imageIter.hasNext()){
String key = (String) imageIter.next();
Object obj = pageImages.get(key);
if(obj instanceof PDXObjectImage) {
PDXObjectImage pdxObjectImage = (PDXObjectImage) obj;
pdxObjectImage.write2file(destinationDir + fileName+ "_" + totalImages);
totalImages++;
}
}
}
}
} else {
System.err.println("File not exist");
}
}
catch (Exception e){
System.err.println(e.getMessage());
}
}
//// PARTIAL SOLUTION/////
I have solved the problem of the error message. I have updated the correct code in the post as well. However, the problem remains the same. I am still not able to extract the images from few of the files. Like the one, I have mentioned in this post. Any solution in that regards.
The first problem with the original code is that XObjects can be PDXObjectImage or PDXObjectForm, so it is needed to check the instance. The second problem is that the code doesn't walk PDXObjectForm recursively, forms can have resources too. The third problem (only in 1.8) is that you used getResources() instead of findResources(), getResources() doesn't check higher levels.
Code for 1.8 can be found here:
https://svn.apache.org/viewvc/pdfbox/branches/1.8/pdfbox/src/main/java/org/apache/pdfbox/ExtractImages.java?view=markup
Code for 2.0 can be found here:
https://svn.apache.org/viewvc/pdfbox/trunk/tools/src/main/java/org/apache/pdfbox/tools/ExtractImages.java?view=markup&sortby=date
(Even these are not always perfect, see this answer)
The fourth problem is that your file doesn't have any XObjects at all. All "graphics" were really vector drawings, these can't be "extracted" like embedded images. All you could do is to convert the PDF pages to images, and then mark and cut what you need.

Replace a placeholder with image in word?

I need to replace the placeholder with image in the word document using Apache POI. I am able to insert the picture in the word document using Apache poi. But i don't know how to replace the placeholder with image. Can anyone please help in this?
I know it will be easy if we do it through docx4j or some other API, i am allowed to use only the Apache poi.
It can be done but I believe you must insert raw XML to accomplish it currently. This linked question "Insert picture in word document" has the basic idea. You can do it using only the libraries that POI requires, not dom4j. If you look at the source for the method on the XWPFRun that adds a picture it too is trying to add raw XML. But if you use that method it renders your doc unreadable when written back to disk. So you have to add the picture to the document using the XWPFDocument level method, which returns a generated ID for the picture. And then add raw XML to the run with that ID in it, as the example link does.
The way we solved the problem was to instead have our users insert a placeholder image into their Word doc file instead of text. We then: add the replacement image to be inserted at the document level, find the run that contains the placeholder image using the size of the image as criteria, then get and replace the XML for that run with the new image's ID swapped in. As long as the placeholder and the replacement image are the same size this works. If you need to adjust the size of the image after replacing, you could manipulate the XML size values in the same manner. I like our solution better because it is less susceptible to changes in the Word doc XML format then inserting your own full XML for the picture. Cheers
InputStream newImageIS = getImageForCorporation(corporationID);
String relationID = run.getParagraph().getDocument().addPictureData(newImageIS, Document.PICTURE_TYPE_GIF);
replaceRunImageData(run, relationID);
private void replaceRunImageData(XWPFRun run, String relationID) {
CTGraphicalObjectData graph = run.getCTR().getDrawingArray(0).getInlineArray(0).getGraphic()
.getGraphicData();
String currentGraphicXML = graph.toString();
String originalID = RegularExpressionUtil.capture("<a:blip r:embed=\"(\\w+)\"", currentGraphicXML);
String newXML = StringUtils.replace(currentGraphicXML, originalID, relationID);
try {
graph.set(XmlToken.Factory.parse(newXML));
} catch (XmlException e) {
throw new RuntimeException(e);
}
replaced = true;
}
We identified the run of the image to replace by search each run's list of embedded pictures which met the below criteria. We tried using the name of the image as the criteria, but we found that if the placeholder image was copied from one Word doc to another Word doc on a different PC, the name was lost.
private boolean isRunForExistingImage(XWPFPicture pic) {
if (pic == null || pic.getCTPicture() == null || pic.getCTPicture().getSpPr() == null
|| pic.getCTPicture().getSpPr().getXfrm() == null
|| pic.getCTPicture().getSpPr().getXfrm().getExt() == null) {
return false;
}
long x = pic.getCTPicture().getSpPr().getXfrm().getExt().getCx();
long y = pic.getCTPicture().getSpPr().getXfrm().getExt().getCy();
return x == 2066925 && y == 590550;
}

Categories

Resources