Stamp Annotations Configuration

To change the default set of stamp annotations available for your application you'll have to override getStampsForPicker() in StampAnnotationDefaultsProvider class.

Copy
1
2
3
4
5
6
7
8
9
10
11
12
// Defaults can be configured for each annotation type through PdfFragment.
pdfFragment.setAnnotationDefaultsProvider(AnnotationType.STAMP, object : StampAnnotationDefaultsProvider(this) {
    override fun getStampsForPicker(): List<StampPickerItem> {
        // Here you can specify which stamps are going to be available in the stamp picker.
        val stamps = ArrayList<StampPickerItem>()

        stamps.add(StampPickerItem.fromSubject(context, "Great!").build())
        stamps.add(StampPickerItem.fromSubject(context, "Stamp").build())
        stamps.add(StampPickerItem.fromSubject(context, "Like").build())
        return stamps
    }
})
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
// Defaults can be configured for each annotation type through PdfFragment.
getPdfFragment().setAnnotationDefaultsProvider(AnnotationType.STAMP, new StampAnnotationDefaultsProvider(this) {
    @NonNull @Override public List<StampPickerItem> getStampsForPicker() {
        // Here you can specify which stamps are going to be available in the stamp picker.
        final List<StampPickerItem> stamps = new ArrayList<>();

        stamps.add(StampPickerItem.fromSubject(context, "Great!").build());
        stamps.add(StampPickerItem.fromSubject(context, "Stamp").build());
        stamps.add(StampPickerItem.fromSubject(context, "Like").build());

        return stamps;
    }
});

Tip: Call super.getStampsForPicker() to retrieve the default set already bundled in the library.

Stamp picker dialog with a custom set of default stamps

Default Stamp Annotations

PSPDFKit comes with some out-of-the-box stamp annotations available in the stamp picker dialog.

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
val items = mutableListOf<StampPickerItem>()

// Standard stamps.
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.APPROVED).build())
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.NOT_APPROVED).build())
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.DRAFT).build())
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.FINAL).build())
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.COMPLETED).build())
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.CONFIDENTIAL).build())
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.FOR_PUBLIC_RELEASE).build())
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.NOT_FOR_PUBLIC_RELEASE).build())
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.FOR_COMMENT).build())
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.VOID).build())
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.PRELIMINARY_RESULTS).build())
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.INFORMATION_ONLY).build())

// Tick and cross stamps.
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.ACCEPTED).build())
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.REJECTED).build())

// Signature stamps.
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.INITIAL_HERE).build())
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.SIGN_HERE).build())
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.WITNESS).build())

// Custom stamp.
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.CUSTOM).build())

// Revised/rejected stamps with localized datetime subtext.
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.REVISED).withDateTimeSubtext(true, true).build())
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.REJECTED).withDateTimeSubtext(true, true).build())
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
final List<StampPickerItem> items = new ArrayList<>();

// Standard stamps.
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.APPROVED).build());
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.NOT_APPROVED).build());
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.DRAFT).build());
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.FINAL).build());
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.COMPLETED).build());
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.CONFIDENTIAL).build());
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.FOR_PUBLIC_RELEASE).build());
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.NOT_FOR_PUBLIC_RELEASE).build());
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.FOR_COMMENT).build());
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.VOID).build());
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.PRELIMINARY_RESULTS).build());
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.INFORMATION_ONLY).build());

// Tick and cross stamps.
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.ACCEPTED).build());
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.REJECTED).build());

// Signature stamps.
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.INITIAL_HERE).build());
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.SIGN_HERE).build());
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.WITNESS).build());

// Custom stamp.
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.CUSTOM).build());

// Revised/rejected stamps with localized datetime subtext.
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.REVISED).withDateTimeSubtext(true, true).build());
items.add(StampPickerItem.fromPredefinedType(context, PredefinedStampType.REJECTED).withDateTimeSubtext(true, true).build());

Note: PredefinedStampType.CUSTOM is a special stamp type that will guide to the creation of a custom stamp the final user can generate at runtime.

Image Stamp Annotations

PSPDFKit supports stamp annotations generated from a bitmap image. These annotations with supplied bitmap cannot have localized subject, subtext or text color. Use StampPickerItem#fromBitmap(android.graphics.Bitmap) to create a builder for bitmap stamp annotations.

Copy
1
2
3
4
5
6
7
8
9
10
11
val items = ArrayList<StampPickerItem>()
...
try {
    val bitmap = BitmapFactory.decodeStream(getAssets().open("inline-media/images/exampleimage.jpg"))
    items.add(StampPickerItem.fromBitmap(bitmap)
                // Specifying only single size dimension will produce bitmap stamps preserving the original aspect ratio.  
                .withSize(StampAnnotationDefaultsProvider.DEFAULT_STAMP_ANNOTATION_PDF_WIDTH)
                .build())
} catch (e: IOException) {
    e.printStackTrace()
}
Copy
1
2
3
4
5
6
7
8
9
10
11
final List<StampPickerItem> items = new ArrayList<>();
...
try {
    final Bitmap bitmap = BitmapFactory.decodeStream(getAssets().open("inline-media/images/exampleimage.jpg"));
    items.add(StampPickerItem.fromBitmap(bitmap)
                // Specifying only single size dimension will produce bitmap stamps preserving the original aspect ratio.  
                .withSize(StampAnnotationDefaultsProvider.DEFAULT_STAMP_ANNOTATION_PDF_WIDTH)
                .build());
} catch (IOException e) {
    e.printStackTrace();
}

Note: Stamp images are encoded to JPEG format which does not allow transparency.

Vector Stamp Annotations

PSPDFKit allows you to override the appearance stream of any annotation. This is especially useful for stamp annotations. Unlike bitmap stamp annotations, stamp annotations with custom appearance streams allow transparency and high-resolution zooming.

Here's how to define a stamp picker item with a custom appearance stream generator set:

Copy
1
2
3
4
5
6
7
8
9
10
val items = ArrayList<StampPickerItem>()
...
// Create appearance stream generator with a PDF containing vector logo.
val appearanceStreamGenerator = AssetAppearanceStreamGenerator("PSPDFKit Logo.pdf")

// Create picker item with custom subject and custom appearance stream generator set.
items.add(StampPickerItem.fromSubject(context, "Custom subject")
    .withSize(StampAnnotationDefaultsProvider.DEFAULT_STAMP_ANNOTATION_PDF_WIDTH)
    .withAppearanceStreamGenerator(appearanceStreamGenerator)
    .build())
Copy
1
2
3
4
5
6
7
8
9
10
final List<StampPickerItem> items = new ArrayList<>();
...
// Create appearance stream generator with a PDF containing vector logo.
AssetAppearanceStreamGenerator appearanceStreamGenerator = new AssetAppearanceStreamGenerator("PSPDFKit Logo.pdf");

// Create picker item with custom subject and custom appearance stream generator set.
items.add(StampPickerItem.fromSubject(context, "Custom subject")
    .withSize(StampAnnotationDefaultsProvider.DEFAULT_STAMP_ANNOTATION_PDF_WIDTH)
    .withAppearanceStreamGenerator(appearanceStreamGenerator)
    .build());

Apperance streams of created stamps are going to be saved into the document when saving. However, they will need to be regenerated whenever stamp annotations are modified after the document is reloaded. For this case, we register a global appearance stream generator on a document that will generate custom appearance streams for stamp annotations based on their subject.

Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
override fun onDocumentLoaded(document: PdfDocument) {
    super.onDocumentLoaded(document)

    // Register custom stamp appearance stream generator as a global appearance stream generator.
    val customStampAppearanceStreamGenerator = CustomStampAppearanceStreamGenerator()
    document.annotationProvider.addAppearanceStreamGenerator(customStampAppearanceStreamGenerator)

    // Create appearance stream generator with a PDF containing vector logo.
    val appearanceStreamGenerator = AssetAppearanceStreamGenerator("PSPDFKit Logo.pdf")

    // Register created appearance stream generator for the custom subject.
    customStampAppearanceStreamGenerator.addAppearanceStreamGenerator("Custom subject", appearanceStreamGenerator)
}
Copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public void onDocumentLoaded(@NonNull PdfDocument document) {
    super.onDocumentLoaded(document);

    // Register custom stamp appearance stream generator as a global appearance stream generator.
    CustomStampAppearanceStreamGenerator customStampAppearanceStreamGenerator = new CustomStampAppearanceStreamGenerator();
    document.getAnnotationProvider().addAppearanceStreamGenerator(customStampAppearanceStreamGenerator);

    // Create appearance stream generator with a PDF containing vector logo.
    AssetAppearanceStreamGenerator appearanceStreamGenerator = new AssetAppearanceStreamGenerator("PSPDFKit Logo.pdf");

    // Register created appearance stream generator for the custom subject.
    customStampAppearanceStreamGenerator.addAppearanceStreamGenerator("Custom subject", appearanceStreamGenerator);
}

For a comprehensive example, take a look at the CustomStampAnnotationsExample inside the catalog app, which shows how to create a different set of default stamp annotations.