Add QR Code to PDF Java - Complete Guide with GroupDocs.Signature
Ever needed to add a digital signature to a PDF but wanted something more than just a scribbled image? QR code signatures offer a clever middle ground—they’re visually scannable, contain encrypted data, and can be verified programmatically. Perfect for contracts, invoices, or any document where you need both human-readable and machine-verifiable authentication.
If you’re working with Java and need to implement document signing, you’ve probably hit the same wall many developers face: building signature functionality from scratch is time-consuming and error-prone. That’s where GroupDocs.Signature comes in—it handles the heavy lifting so you can focus on your application logic.
In this guide, you’ll learn how to add QR code signatures to PDFs and other documents using Java, verify those signatures to ensure authenticity, and manage existing signatures (search, update, delete). We’ll cover everything from initial setup to production-ready best practices, with real code examples and troubleshooting tips along the way.
Why Use QR Code Signatures?
Before we dive into the code, let’s talk about why QR codes make sense for document signatures (and when they might not).
The Benefits:
- Dual verification: Humans can scan them with a phone, machines can verify them programmatically
- Space efficient: Contain much more data than traditional signatures in a small visual footprint
- Easy tracking: Store signature IDs, timestamps, or even encrypted metadata
- Hard to forge: When properly implemented, they’re cryptographically secure
- Universal compatibility: Work across different devices and platforms
When to choose QR codes over other signature types:
- You need both visual and automated verification
- Documents will be printed and scanned (QR codes survive this better than some digital signatures)
- You want to store additional metadata beyond just “signed by John”
- Your workflow involves mobile devices for verification
When to consider alternatives:
- You need full PKI (Public Key Infrastructure) compliance—use digital certificates instead
- Visual appearance doesn’t matter—text signatures might be simpler
- You’re signing extremely sensitive documents—consider combining QR codes with certificate-based signatures
What You’ll Learn
By the end of this tutorial, you’ll know how to:
- Sign documents using QR codes with custom styling and positioning
- Verify signatures to confirm document authenticity and detect tampering
- Search for signatures within multi-page documents
- Update existing signatures when you need to change their properties
- Delete signatures programmatically when they’re no longer needed
The best part? All of this works with PDFs, Word documents, Excel spreadsheets, and more—GroupDocs.Signature supports over 50 file formats.
Prerequisites
Before we get started, make sure you have these basics covered:
Required Libraries and Dependencies
You’ll need GroupDocs.Signature for Java. The library is available through Maven, Gradle, or direct download—choose whichever fits your build system.
Maven
<dependency>
<groupId>com.groupdocs</groupId>
<artifactId>groupdocs-signature</artifactId>
<version>23.12</version>
</dependency>
Gradle
implementation 'com.groupdocs:groupdocs-signature:23.12'
Direct Download If you prefer manual setup, grab the latest version from GroupDocs.Signature for Java releases.
Environment Setup Requirements
- Java Development Kit (JDK) 8 or higher: The library uses modern Java features, so make sure you’re not stuck on Java 7
- IDE of your choice: IntelliJ IDEA, Eclipse, NetBeans—whatever you’re comfortable with
- Basic project structure: A working Java project where you can add dependencies
Knowledge Prerequisites
You should have:
- Working knowledge of Java programming (classes, methods, imports—the usual stuff)
- Basic understanding of document processing concepts
- Familiarity with file I/O operations
If you’re comfortable writing Java applications and handling files, you’re all set.
Setting Up GroupDocs.Signature for Java
Getting the library into your project is straightforward, but there are a few setup steps worth mentioning.
Installation
Choose your dependency management approach: If you’re using Maven or Gradle, just add the dependency shown above. For manual setup, download the JAR and add it to your project’s build path.
License Acquisition (important for production use):
- Start with the free trial available on the GroupDocs website to test features
- For development and testing beyond the trial limits, grab a temporary license
- When you’re ready to go live, you’ll need to purchase a full license
Basic Initialization: Once the library is in your classpath, initializing it is dead simple:
Signature signature = new Signature("YOUR_DOCUMENT_PATH");
Replace
YOUR_DOCUMENT_PATH
with the actual path to your PDF or document file. This creates aSignature
object that you’ll use for all signing, verifying, searching, and updating operations.
Pro tip: Always use try-with-resources or properly close the Signature object when you’re done to avoid memory leaks:
try (Signature signature = new Signature("path/to/document.pdf")) {
// Your signing/verification code here
}
Implementation Guide
Now let’s get into the practical stuff—actually working with QR code signatures.
Sign Document with QR-Code Signature
Overview
Adding a QR code signature to a document involves creating a unique code that embeds your signature data (like a name, timestamp, or custom text), positioning it on the document, and styling it to match your needs. The library handles the QR code generation—you just configure how it should look and where it should go.
Think of this as stamping a scannable badge on your document. Once signed, the QR code becomes part of the document and can be verified later to confirm authenticity.
Step 1: Set Up Your Signing Options
import com.groupdocs.signature.Signature;
import com.groupdocs.signature.domain.enums.HorizontalAlignment;
import com.groupdocs.signature.domain.enums.VerticalAlignment;
import com.groupdocs.signature.options.sign.QrCodeSignOptions;
Signature signature = new Signature("YOUR_DOCUMENT_PATH");
QrCodeSignOptions signOptions = new QrCodeSignOptions("John Smith", com.groupdocs.signature.domain.qrcodes.QrCodeTypes.QR);
signOptions.setVerticalAlignment(VerticalAlignment.Top);
signOptions.setHorizontalAlignment(HorizontalAlignment.Center);
signOptions.setWidth(100);
signOptions.setHeight(40);
What’s happening here: You’re creating a QrCodeSignOptions
object that tells the library what to encode (“John Smith” in this case) and what type of QR code to generate. The alignment settings position it at the top center of the page, and the width/height define its size in pixels.
Customization tips:
- Use
VerticalAlignment.Bottom
andHorizontalAlignment.Right
for signature blocks in the lower right (common for contracts) - Adjust width/height based on how much data you’re encoding—more data = bigger QR code needed
- The text can be anything: names, IDs, JSON strings, even encrypted tokens
Step 2: Customize Signature Appearance
import java.awt.Color;
signOptions.setForeColor(Color.RED); // Set QR code color
com.groupdocs.signature.domain.SignatureFont signatureFont = new com.groupdocs.signature.domain.SignatureFont();
signatureFont.setSize(12);
signatureFont.setFamilyName("Comic Sans MS");
signOptions.setFont(signatureFont);
What’s happening here: The setForeColor()
method changes the QR code’s color from the default black. The font settings apply to any text label that accompanies the QR code (not the QR code itself).
Styling best practices:
- Color choice: Stick with high-contrast colors (dark on light backgrounds) for reliable scanning. Avoid red or orange on white—many QR readers struggle with those
- Font selection: Use readable fonts for labels. Comic Sans might not be your best choice for professional documents (we just used it as an example!)
- Size considerations: Larger QR codes scan more reliably, especially if documents will be printed. Aim for at least 100x100 pixels
Common mistake: Setting a light color (like yellow or light blue) makes the QR code hard to scan. Always test your styled QR codes with a real scanner.
Step 3: Sign the Document
import java.util.ArrayList;
import java.util.List;
List<String> signatureIds = new ArrayList<>();
List<com.groupdocs.signature.domain.BaseSignature> signedSignatures = signature.sign("YOUR_OUTPUT_PATH", signOptions).getSucceeded();
for (com.groupdocs.signature.domain.BaseSignature temp : signedSignatures) {
signatureIds.add(temp.getSignatureId());
}
What’s happening here: The sign()
method applies your QR code to the document and saves it to the output path. It returns a list of successfully applied signatures (usually just one, but you can add multiple in a single operation). The signature IDs are unique identifiers you can use later for updating or deleting specific signatures.
Important notes:
- The output path should be different from the input path—don’t overwrite your original document directly (unless you really want to)
- Store those signature IDs somewhere persistent (database, config file) if you need to manage signatures later
- The
getSucceeded()
method filters out any signatures that failed to apply (rare, but possible with corrupted files)
Troubleshooting: If signing fails silently, check:
- File permissions on the output path
- Whether the input document is open in another program
- If your trial license has expired
Verify Document with QR-Code Signature
Overview
Verification is where QR codes really shine—you can programmatically confirm that a document was signed with a specific signature, hasn’t been tampered with, and contains the expected data. This is crucial for automated workflows where human review isn’t practical.
The verification process searches for QR codes matching your criteria and confirms they’re present and intact.
Step 1: Set Up Verification Options
import com.groupdocs.signature.Signature;
import com.groupdocs.signature.options.verify.QrCodeVerifyOptions;
Signature signature2 = new Signature("YOUR_OUTPUT_PATH");
QrCodeVerifyOptions verifyOptions = new QrCodeVerifyOptions();
verifyOptions.setEncodeType(QrCodeTypes.QR);
verifyOptions.setText("John Smith"); // Text to verify
verifyOptions.setAllPages(false);
verifyOptions.setPageNumber(1);
What’s happening here: The QrCodeVerifyOptions
object defines what you’re looking for. In this example, you’re checking page 1 for a QR code that encodes “John Smith”. The verification will only pass if both the QR type and text match exactly.
Configuration tips:
- Set
setAllPages(true)
if signatures might be on any page (useful for multi-page contracts) - The text comparison is case-sensitive by default—“john smith” won’t match “John Smith”
- For partial matches, you’ll need to search first and then check each signature’s text programmatically
Real-world scenario: Imagine you’re processing invoices. You can verify that each invoice has been signed by an authorized person by checking for their specific signature text or ID.
Step 2: Perform Verification
boolean isValid = signature2.verify(verifyOptions).isValid();
System.out.println("Is Signature Valid? " + isValid);
What’s happening here: The verify()
method returns a result object with an isValid()
boolean. True means the signature was found and matches your criteria; false means it’s missing or doesn’t match.
Important considerations:
- Verification doesn’t detect tampering automatically—it only confirms the signature exists
- For tamper detection, you’d need to combine this with hash checking or digital certificates
- If multiple signatures match, verification passes (it’s an “exists at least one” check, not “exists only one”)
Troubleshooting: If verification unexpectedly fails:
- Double-check the text exactly matches (including whitespace)
- Ensure you’re checking the right page number
- Verify the document hasn’t been converted to a different format (some conversions strip signatures)
Search Document for QR-Code Signature
Overview
Sometimes you don’t know what signatures are in a document, or you need to inventory all existing signatures before updating or deleting them. The search functionality lets you discover what’s there without needing to know the exact details upfront.
This is especially useful when inheriting documents from other systems or auditing signature usage.
Step 1: Configure Search Options
import com.groupdocs.signature.domain.signatures.QrCodeSignature;
import com.groupdocs.signature.options.search.QrCodeSearchOptions;
Signature signature2 = new Signature("YOUR_OUTPUT_PATH");
QrCodeSearchOptions searchOptions = new QrCodeSearchOptions();
searchOptions.setAllPages(true);
What’s happening here: The QrCodeSearchOptions
object tells the library to scan all pages for any QR code signatures. You can narrow this down by page number, signature type, or other criteria if needed.
Search optimization:
- Searching all pages on large documents (100+ pages) can take a few seconds—be patient or add a progress indicator
- If you know signatures are only on the first or last page, limit the search to improve performance
- You can search for multiple signature types at once by casting the results to
BaseSignature
Step 2: Execute Search
List<QrCodeSignature> signatures = signature2.search(QrCodeSignature.class, searchOptions);
for (QrCodeSignature qrSignature : signatures) {
System.out.println("Found Signature ID: " + qrSignature.getSignatureId());
}
What’s happening here: The search()
method returns a list of all QR code signatures found. Each signature object contains metadata like position, size, encoded text, and the unique signature ID.
Working with search results:
- Access the encoded text:
qrSignature.getText()
- Get position:
qrSignature.getLeft()
,qrSignature.getTop()
- Check which page:
qrSignature.getPageNumber()
- Use the signature ID for update or delete operations
Use cases:
- Audit trails: Log all signatures found in a batch of documents
- Signature cleanup: Find and remove outdated signatures before re-signing
- Multi-signature workflows: Confirm all required parties have signed before processing
Performance note: On documents with dozens of signatures, searching returns results almost instantly. The bottleneck is usually I/O (reading the file), not signature detection.
Update Document QR-Code Signature
Overview
Need to move a signature to a different position? Change its size? Update its appearance? The update operation lets you modify existing signatures without removing and re-adding them, which preserves the signature ID and creation timestamp.
Think of this as editing a sticky note on a document rather than throwing it away and writing a new one.
Step 1: Prepare Signatures for Update
import com.groupdocs.signature.domain.signatures.QrCodeSignature;
import java.io.ByteArrayOutputStream;
Signature signature2 = new Signature("YOUR_OUTPUT_PATH");
List<QrCodeSignature> signaturesToUpdate = new ArrayList<>();
// Assuming 'signatures' is a list of QrCodeSignature objects obtained from searching
for (QrCodeSignature qrSignature : signatures) {
qrSignature.setLeft(qrSignature.getLeft() + 100);
qrSignature.setTop(qrSignature.getTop() + 100);
qrSignature.setWidth(200);
qrSignature.setHeight(50);
signaturesToUpdate.add(qrSignature);
}
What’s happening here: You first need to search for the signatures you want to update (using the search method from the previous section). Then you modify their properties—in this example, moving each signature 100 pixels right and down, and resizing them to 200x50 pixels.
Update patterns:
- Repositioning all signatures: Useful when template layouts change
- Resizing based on content: If you’re updating the encoded text, you might need a larger QR code
- Batch updates: Process multiple signatures in one operation for efficiency
Important limitation: You can’t change the encoded text during an update—that would invalidate the signature. To change the text, you need to delete the old signature and create a new one.
Step 2: Update the Document
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
signature2.update(outputStream, signaturesToUpdate);
What’s happening here: The update()
method applies all modifications and writes the result to an output stream. You can then save that stream to a file or send it directly to a client.
Output handling options:
- Write to a file:
Files.write(Paths.get("updated-document.pdf"), outputStream.toByteArray())
- Return to user: Send the byte array as an HTTP response in a web application
- Store in memory: Keep the
outputStream
for further processing
Why use ByteArrayOutputStream?: It’s more flexible than writing directly to a file—you can easily duplicate the output, send it to multiple destinations, or perform additional operations before saving.
Troubleshooting: If updates don’t appear:
- Verify you’re actually saving the output stream to a file (it’s easy to forget!)
- Check that the signature IDs in your list match signatures that actually exist in the document
- Ensure the modified positions are within the page boundaries
Delete Document QR-Code Signature by ID
Overview
Sometimes you need to remove signatures entirely—maybe they’re expired, incorrect, or the document is being re-signed. Deleting by signature ID is the safest approach because it targets exactly the signature you want gone, even if multiple similar signatures exist.
Step 1: Identify Signatures to Delete
import com.groupdocs.signature.domain.SignatureCollection;
import java.util.Arrays;
SignatureCollection signaturesToDelete = signature2.search(QrCodeSignature.class);
Arrays.stream(signaturesToDelete).forEach(signature -> {
if (signature.getSignatureId().equals("YOUR_SIGNATURE_ID")) {
signature.delete();
}
});
What’s happening here: This code searches for all QR code signatures, then filters by signature ID and deletes the matching one(s). The delete()
method marks the signature for removal—it’s actually deleted when you save the document.
Deletion strategies:
- By ID: Most precise—use this when you know exactly which signature to remove
- By text match: Delete all signatures containing specific text
- By date: Remove signatures older than a certain timestamp (requires custom filtering)
- Selective deletion: Use conditional logic to decide which signatures to keep or remove
Example use case: In a document approval workflow, you might delete all pending approval signatures once the document is fully approved, leaving only the final authorized signature.
Critical warning: Deletion is permanent once you save the document. Always keep a backup of the original signed document before performing batch deletions, especially in production systems.
Alternative approach: Instead of deleting signatures from the original file, some workflows create a “stripped” version by copying all content except signatures to a new document. This preserves the original signed version for audit purposes.
Common Issues & Solutions
Here are some problems you’ll likely encounter and how to fix them:
Issue: QR code doesn’t appear in signed document
- Cause: Output path is the same as input path, and the file is locked
- Solution: Always use a different output filename, or close the input file before signing
Issue: Verification always returns false
- Cause: Text mismatch (often whitespace or case sensitivity)
- Solution: Trim your verification text and match the exact case used when signing
Issue: Search returns no results but signatures are visible
- Cause: Searching for wrong signature type (e.g., searching for QR codes but document has text signatures)
- Solution: Use
BaseSignature.class
in search to find all signature types, then filter
Issue: OutOfMemoryError with large documents
- Cause: Loading entire document into memory for multi-page operations
- Solution: Process pages individually or increase JVM heap size with
-Xmx
flag
Issue: Updated signatures look distorted
- Cause: Aspect ratio changed during resize (width and height scaled differently)
- Solution: Calculate new dimensions maintaining the original aspect ratio
Best Practices for Production Use
Security Considerations
- Don’t encode sensitive data in plain text: QR codes are easily decoded. Encrypt sensitive information before encoding
- Validate signature IDs: When accepting signature IDs from user input, validate they’re in the expected format to prevent injection attacks
- Implement access control: Ensure only authorized users can sign, verify, or modify documents
- Use HTTPS: When transmitting signed documents, always use secure connections
Performance Optimization
- Cache Signature objects: Creating a new
Signature
instance for every operation is expensive. Reuse them when processing multiple documents - Limit search scope: If you know signatures are only on certain pages, don’t search the entire document
- Process in batches: When signing multiple documents, process them in parallel using Java’s ExecutorService
- Monitor memory usage: Large PDFs can consume significant memory—set appropriate JVM limits
Code Organization
- Create wrapper methods: Don’t repeat the same signing/verification logic everywhere. Wrap common operations in reusable methods
- Use configuration files: Store signature options (colors, sizes, positions) in config files rather than hardcoding them
- Implement logging: Log all signature operations for audit trails and debugging
- Handle exceptions gracefully: Wrap operations in try-catch blocks and provide meaningful error messages
Testing Strategies
- Test with various formats: Don’t assume all PDFs behave the same—test with PDFs from different sources
- Verify across devices: Test QR code scanning with multiple phone models and reader apps
- Check edge cases: Test with very long text, special characters, and non-English text in your QR codes
- Automate verification tests: Set up unit tests that sign and verify documents to catch regressions
Real-World Use Cases
To help you understand when and how to apply these techniques, here are some practical scenarios:
Contract Management System
Scenario: Your company processes hundreds of contracts daily, each requiring multiple signatures.
Implementation:
- Use unique QR codes containing contract IDs and signer information
- Position signatures in the bottom right of the signature page
- Verify all required signatures exist before marking contracts as “fully executed”
- Store signature IDs in your database linked to contract records
Why QR codes: They’re harder to forge than simple text signatures and contain metadata useful for tracking.
Invoice Authentication
Scenario: You need to ensure invoices haven’t been tampered with between creation and payment.
Implementation:
- Embed QR codes containing invoice hashes and payment terms
- Verify signatures before processing payments automatically
- Allow customers to scan QR codes with their phones to confirm invoice authenticity
Why QR codes: Customers can quickly verify invoices without needing specialized software.
Document Version Control
Scenario: Track which version of a document is being circulated.
Implementation:
- Add QR codes with version numbers and timestamps to each document
- Search for version signatures when documents are uploaded
- Update version signatures when documents are revised rather than creating duplicates
Why QR codes: Visual version indicators that are also machine-readable for automated systems.
Compliance and Audit Trails
Scenario: Regulated industries need to prove who signed what and when.
Implementation:
- Encode signer names, roles, and ISO timestamps in QR codes
- Use consistent positioning for easy automated scanning during audits
- Store signature IDs and metadata in an immutable audit log
Why QR codes: They survive document printing and scanning better than some digital signature methods.
Conclusion
You’ve now learned how to implement a complete QR code signature workflow in Java using GroupDocs.Signature. From signing documents with customized QR codes to verifying authenticity, searching for existing signatures, and managing them programmatically—you’ve got all the pieces to build a robust document signing system.
Frequently Asked Questions
Q: Can I add multiple QR code signatures to the same document?
Yes! Just call the sign()
method multiple times with different QrCodeSignOptions
, or add multiple options to a list and sign them all at once. Each signature gets a unique ID.
Q: Do QR code signatures work on scanned documents? They work on PDFs created from scans, but keep in mind that scanning a document with existing QR codes and then trying to verify those codes programmatically won’t work—the QR code in the scan is just an image, not a real signature object. You’d need OCR and QR decoding to read scanned signatures.
Q: What’s the maximum amount of data I can encode in a QR code signature? Standard QR codes support up to about 4,000 alphanumeric characters, but practical limits are lower (around 500-1,000 characters) because larger QR codes become harder to scan reliably. For large data, consider encoding a reference ID and storing the actual data elsewhere.
Q: Can I change the encoded text without deleting and re-creating the signature? No—changing the encoded text invalidates the signature. You must delete the old signature and create a new one. This is by design to prevent tampering.
Q: How do I sign password-protected PDFs?
You’ll need to provide the password when creating the Signature
object. GroupDocs.Signature supports this, but it’s outside the scope of this tutorial. Check the API documentation for LoadOptions
parameters.
Q: Is there a limit to how many signatures I can add to a document? No hard limit from the library, but performance degrades with hundreds of signatures. More importantly, the document becomes cluttered. If you need that many signatures, consider alternative approaches like signature pages or external signature databases.
Q: Can I use QR codes for legally binding signatures? That depends on your jurisdiction’s laws around electronic signatures. In many places, yes—QR codes can be part of legally binding e-signatures if implemented correctly (with proper authentication, consent, and audit trails). Consult a lawyer familiar with e-signature laws in your region.
Q: Do I need a GroupDocs license for production use? Yes. The free trial and temporary license are for testing only. For production deployment, you’ll need to purchase a license. Pricing depends on your deployment model (single application, SaaS, etc.).