Adding Text/Annotations into existing PDF file and View/Rendering the output in android

3.8k views Asked by At

I am working on a pdf editor.

I have made my changes on pdf files with OpenPDF core that is based on iText

And I am viewing the Pdf file with AndroidPdfViewer

My problems are:

  1. Adding new annotations like text or tags or icons into an existing pdf file. ( SOLVED )

  2. Show new changes right after annotations added into pdf file.( SOLVED )

  3. Convert user click into Pdf file coordinates to add new annotation based on user clicked location.

  4. Get click event on added annotations and read meta data that added into that annotation , for ex: read tag hash id that sets on icon annotation. ( SOLVED )

  5. Remove added annotation from PDF File.

Any help appreciated

UPDATE

========================================================================

Solution 1: Adding annotations

  • Here is my code snippet for adding icon annotation into existing pdf file.

public static void addWatermark(Context context, String filePath) throws FileNotFoundException, IOException {

        // get file and FileOutputStream
        if (filePath == null || filePath.isEmpty())
            throw new FileNotFoundException();

        File file = new File(filePath);

        if (!file.exists())
            throw new FileNotFoundException();

        try {

            // inout stream from file
            InputStream inputStream = new FileInputStream(file);

            // we create a reader for a certain document
            PdfReader reader = new PdfReader(inputStream);

            // get page file number count
            int pageNumbers = reader.getNumberOfPages();

            // we create a stamper that will copy the document to a new file
            PdfStamper stamp = new PdfStamper(reader, new FileOutputStream(file));

            // adding content to each page
            int i = 0;
            PdfContentByte under;

            // get watermark icon
            Image img = Image.getInstance(PublicFunction.getByteFromDrawable(context, R.drawable.ic_chat));
            img.setAnnotation(new Annotation("tag", "gd871394bh2c3r", 0, 0, 0, 0));
            img.setAbsolutePosition(230, 190);
            img.scaleAbsolute(50, 50);

            while (i < pageNumbers) {
                i++;
                // watermark under the existing page
                under = stamp.getUnderContent(i);
                under.addImage(img);
            }

            // closing PdfStamper will generate the new PDF file
            stamp.close();

        } catch (Exception de) {
            de.printStackTrace();
        }

    }
}

Solution 2: Show new changes

  • Here is my code snippet for refreshing the view after adding annotation, I have added this into AndroidPdfViewer core classes.
public void refresh(int currPage) {

            currentPage = currPage;

            if (!hasSize) {
                waitingDocumentConfigurator = this;
                return;
            }
            PDFView.this.recycle();
            PDFView.this.callbacks.setOnLoadComplete(onLoadCompleteListener);
            PDFView.this.callbacks.setOnError(onErrorListener);
            PDFView.this.callbacks.setOnDraw(onDrawListener);
            PDFView.this.callbacks.setOnDrawAll(onDrawAllListener);
            PDFView.this.callbacks.setOnPageChange(onPageChangeListener);
            PDFView.this.callbacks.setOnPageScroll(onPageScrollListener);
            PDFView.this.callbacks.setOnRender(onRenderListener);
            PDFView.this.callbacks.setOnTap(onTapListener);
            PDFView.this.callbacks.setOnLongPress(onLongPressListener);
            PDFView.this.callbacks.setOnPageError(onPageErrorListener);
            PDFView.this.callbacks.setLinkHandler(linkHandler);

            if (pageNumbers != null) {
                PDFView.this.load(documentSource, password, pageNumbers);
            } else {
                PDFView.this.load(documentSource, password);
            }
        }

Solution 4: Click on object in pdf

I have create annotations and set it to added image object, AndroidPdfViewer has an event handler, here is the example

@Override
public void handleLinkEvent(LinkTapEvent event) {
        // do your stuff here
}

I will add other new solutions into my question, as update parts.

1

There are 1 answers

3
mkl On BEST ANSWER

Here is my code snippet for adding text into pdf file,

Your code does not add text into an existing pdf file. It creates a new PDF, adds text to it, and appends this new PDF to the existing file presumably already containing a PDF. The result is one file containing two PDFs.

Concatenating two files of the same type only seldom results in a valid file of that type. This does works for some textual formats (plain text, csv, ...) but hardly ever for binary formats, in particular not for PDFs.

Thus, your viewer gets to show a file which is invalid as a PDF, so your viewer could simply have displayed an error and quit. But PDF viewers are notorious for trying to repair the files they are given, each viewer in its own way. Thus, depending on the viewer you could also see either only the original file, only the new file, a combination of both, an empty file, or some other repair result.

So your observation,

but this will replace with all of the Pdf file, not just inserting into it

is not surprising but may well differ from viewer to viewer.


To actually change an existing file with OpenPDF (or any iText version before 6 or other library forked from such a version) you should read the existing PDF using a PdfReader, manipulate that reader in a PdfStamper, and close that stamper.

For example:

PdfReader reader = new PdfReader("original.pdf");
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("original-stamped.pdf"));

PdfContentByte cb = stamper.getOverContent(1);
cb.beginText();
cb.setTextMatrix(100, 400);
cb.showText("Text at position 100,400.");
cb.endText();

stamper.close();
reader.close();

In particular take care to use different file names here. After closing the stamper and the reader you can delete the original PDF and replace it with the stamped version.

If it is not desired to have a second file, you can alternatively initialize the PdfStamper with a ByteArrayOutputStream and after closing the stamper and the reader replace the contents of the original file with those of the ByteArrayOutputStream.