Incremental PDF saving on Android

In some cases, the file size of a document will increase with each save. This could be particularly noticeable if the document contains image annotations with large images and is saved often, either explicitly or via any of the available save triggers.

Incremental saving, which is enabled by default, is the strategy PSPDFKit uses to make sure saving is as fast as possible: It always appends changes to the end of the document, but it never deletes anything. However, even though this is the fastest way of saving a document, it does come with the cost of incrementing the file size with each save. You can read more about incremental vs. full saving in PDFs here.

In most cases, the file size increase is negligible. However, there might be some cases in which you want to prioritize file size over saving performance. Below you’ll find some strategies to prevent the file size from growing unnecessarily when saving changes to a document.

Rewriting a Document When Saving

You can trigger a non-incremental document save, which will rewrite the entire document instead of appending changes at the end.

This can be done by manually saving the document and setting the incrementalSave property of DocumentSaveOptions to false as follows:

val incrementalSave = false
val options = document.defaultDocumentSaveOptions
options.isIncremental = incrementalSave
document.saveIfModified(options)
final boolean incrementalSave = false;
final DocumentSaveOptions options = document.getDefaultDocumentSaveOptions();
options.setIncremental(incrementalSave);
document.saveIfModified(options);

Keep in mind that rewriting the document does not guarantee that the file size will be the same after saving.

Optimizing Size Even Further

In addition to disabling incremental saving, you can also set the rewriteAndOptimizeFileSize property of DocumentSaveOptions to true. This will cause PSPDFKit to first determine which objects in the PDF are no longer required and then remove them from the final output:

val incrementalSave = false
val options = document.defaultDocumentSaveOptions
options.isIncremental = incrementalSave
options.setRewriteAndOptimizeFileSize(true)
document.saveIfModified(options)
final boolean incrementalSave = false;
final DocumentSaveOptions options = document.getDefaultDocumentSaveOptions();
options.setIncremental(incrementalSave);
options.setRewriteAndOptimizeFileSize(true);
document.saveIfModified(options);

While this leads to smaller file sizes, performing this operation is not free and will increase the time it takes to save documents.

When rewriteAndOptimizeFileSize is enabled, incremental saving will automatically be disabled.

Information

Do not rely on file size optimization to get to a target file size. This option does not provide any kind of guarantee that the resulting file will be smaller by a fixed number of bytes.

Disabling Incremental Save When Using Auto-Save

The method described above works only when you are saving manually. But it is also possible to disable incremental saving when using auto-save with PdfActivity or PdfFragment.

The simplest method is to disable incremental saving via DocumentListener#onDocumentSave():

override fun onDocumentSave(document: PdfDocument, saveOptions: DocumentSaveOptions): Boolean {
    saveOptions.isIncremental = false
    return super.onDocumentSave(document, saveOptions)
}
@Override
public boolean onDocumentSave(@NonNull PdfDocument document, @NonNull DocumentSaveOptions saveOptions) {
    saveOptions.setIncremental(false);
    return super.onDocumentSave(document, saveOptions);
}

Incremental saving can also be prevented by using a custom WritableDataProvider with disabled appending:

// Return `false` from `supportsAppending()` to prevent incremental saving.
val dataProvider = object: ContentResolverDataProvider(uri) {
    override fun supportsAppending(): Boolean {
        return false
    }
}

// Start the activity.
val intent = PdfActivityIntentBuilder.fromDataProvider(context, dataProvider)
    .configuration(configuration)
    .build()
context.startActivity(intent)
// Return `false` from `supportsAppending()` to prevent incremental saving.
DataProvider dataProvider = new ContentResolverDataProvider(uri) {
    @Override
    public boolean supportsAppending() {
        return false;
    }
};

// Start the activity.
Intent intent = PdfActivityIntentBuilder.fromDataProvider(context, dataProvider)
        .configuration(configuration)
        .build();
context.startActivity(intent);