Skip to content

Instantly share code, notes, and snippets.

@mgaffigan
Created November 12, 2025 00:36
Show Gist options
  • Select an option

  • Save mgaffigan/c5bda641ba45c8189be877eb155d773e to your computer and use it in GitHub Desktop.

Select an option

Save mgaffigan/c5bda641ba45c8189be877eb155d773e to your computer and use it in GitHub Desktop.
Stamp a PDF in Mirth
var PDDocument = org.apache.pdfbox.pdmodel.PDDocument;
var PDPage = org.apache.pdfbox.pdmodel.PDPage;
var PDPageContentStream = org.apache.pdfbox.pdmodel.PDPageContentStream;
var PDType1Font = org.apache.pdfbox.pdmodel.font.PDType1Font;
var Standard14Fonts = org.apache.pdfbox.pdmodel.font.Standard14Fonts;
var PDImageXObject = org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
var PDFTextStripper = org.apache.pdfbox.text.PDFTextStripper;
var TextPosition = org.apache.pdfbox.text.TextPosition;
var File = java.io.File;
var HashMap = java.util.HashMap;
var ArrayList = java.util.ArrayList;
/**
* BoundingPoint - represents a point in 2D space
*/
function BoundingPoint(x, y) {
this.x = x;
this.y = y;
}
/**
* BoundingBox - represents a rectangular area with type information
*/
function BoundingBox(type, bottomLeft, topRight) {
this.type = type;
// Determine the actual bottom-left and top-right coordinates
var actualBottomLeftX = Math.min(bottomLeft.x, topRight.x);
var actualBottomLeftY = Math.min(bottomLeft.y, topRight.y);
var actualTopRightX = Math.max(bottomLeft.x, topRight.x);
var actualTopRightY = Math.max(bottomLeft.y, topRight.y);
this.x = actualBottomLeftX;
this.y = actualBottomLeftY;
this.width = actualTopRightX - actualBottomLeftX;
this.height = actualTopRightY - actualBottomLeftY;
}
/**
* TextLocationStripper - extends PDFTextStripper to find markers in PDF text
*/
function TextLocationStripper() {
var symbols = ["s<", "i<", ">s", ">i"];
var unmatchedPoints = new HashMap();
var boundingRects = [];
return new JavaAdapter(PDFTextStripper, {
boundingRects: boundingRects,
writeString: function(string, textPositions) {
string = String(string);
if (string.length === 2 && symbols.indexOf(string) !== -1) {
var marker = string.replace("<", "").replace(">", "");
var pos = textPositions.get(0);
var newPoint = new BoundingPoint(pos.getX(), pos.getPageHeight() - pos.getY());
var unmatched = unmatchedPoints.remove(marker);
if (unmatched == null) {
unmatchedPoints.put(marker, newPoint);
} else {
this.boundingRects.push(new BoundingBox(marker, unmatched, newPoint));
}
}
}
});
}
/**
* Find bounding boxes on a specific page
*/
function findBoundingBoxesOnPage(document, pageIndex) {
var stripper = new TextLocationStripper();
stripper.setStartPage(pageIndex + 1);
stripper.setEndPage(pageIndex + 1);
var text = stripper.getText(document);
return stripper.boundingRects;
}
/**
* Main stamping function - equivalent to the Java stampPdf method
*
* @param {string} inputPdfPath - Path to input PDF file
* @param {string} signatureImagePath - Path to signature image file
* @param {string} metadataText - Metadata text to stamp (semicolon-separated)
* @param {string} outputPdfPath - Path for output PDF file
*/
function stampPdf(inputPdfPath, signatureImagePath, metadataText, outputPdfPath) {
var document = PDDocument.load(new File(inputPdfPath));
try {
//logger.info("Loaded PDF with " + document.getNumberOfPages() + " pages");
var signatureImage = PDImageXObject.createFromFile(signatureImagePath, document);
for (var pageIndex = 0; pageIndex < document.getNumberOfPages(); pageIndex++) {
var page = document.getPage(pageIndex);
var boxes = findBoundingBoxesOnPage(document, pageIndex);
var contentStream = new PDPageContentStream(document, page, PDPageContentStream.AppendMode.APPEND, true, true);
try {
for (var i = 0; i < boxes.length; i++) {
var box = boxes[i];
if ("i" === box.type) {
contentStream.beginText();
contentStream.setFont(PDType1Font.HELVETICA, 8.0);
contentStream.newLineAtOffset(box.x, box.y);
contentStream.showText('Hello World');
contentStream.endText();
}
}
} finally {
contentStream.close();
}
}
document.save(outputPdfPath);
} finally {
document.close();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment