Skip to content

Instantly share code, notes, and snippets.

@JamoCA
Last active October 8, 2024 18:32
Show Gist options
  • Save JamoCA/607e2b1b28f2a55006ba9bdf26d4df9b to your computer and use it in GitHub Desktop.
Save JamoCA/607e2b1b28f2a55006ba9bdf26d4df9b to your computer and use it in GitHub Desktop.
enableWKHTMLTOPDFForms - ColdFusion UDF to modify WKHTMLTOPDF binary file so that editable fields can be accessed when using Adobe Acrobat.
<!--- enableWKHTMLTOPDFForms 2024-10-07
ColdFusion/CFML UDF to modify WKHTMLTOPDF binary file so that editable fields can be accessed when using Adobe Acrobat.
GIST: https://gist.github.com/JamoCA/607e2b1b28f2a55006ba9bdf26d4df9b
BLOG: https://dev.to/gamesover/hack-wkhtmltopdf-pdf-to-enable-adobe-acrobat-field-editing-2f6
TWEET: https://x.com/gamesover/status/1843460127757873524
LinkedIn: https://www.linkedin.com/posts/jamesmoberg_hack-wkhtmltopdf-pdf-to-enable-adobe-acrobat-activity-7249486444040175616-jWXh
--->
<cfscript>
public boolean function enableWKHTMLTOPDFForms(required string pdfIn, string pdfOut="", boolean onlyWKFiles=true) hint="Modify a WKHTMLTOPDF binary file so editable fields can be accessed when using Adobe Acrobat." {
local.pdfData = fileread(arguments.pdfIn, "utf-8");
local.destination = (len(arguments.pdfOut)) ? arguments.pdfOut : arguments.pdfIn;
local.isWKPDF = findnocase("creatorwkhtmltopdf", local.pdfData.replaceAll("[^a-zA-Z]", ""));
local.performOperation = (arguments.onlyWKFiles && local.isWKPDF) || !arguments.onlyWKFiles;
local.regexData = refind("Annot\s.{1,5}Parent\s+\d+", local.pdfData, 1, true, "all");
local.isMatches = arraylen(local.regexData) && len(local.regexData[1].match[1]);
if (local.performOperation && local.isMatches){
local.s1 = listlast(local.regexData[1].match[1], "/");
local.s2 = replacenocase(local.s1, "Parent", "Papent");
// encode the strings for hex replacement
local.s1 = binaryencode(tobinary(toBase64(local.s1)), "hex");
local.s2 = binaryencode(tobinary(toBase64(local.s2)), "hex");
local.fileString = binaryencode(filereadbinary(arguments.pdfIn), "hex");
local.updatedContent = local.fileString.replaceAll(local.s1, local.s2);
if (arguments.pdfIn eq local.destination){
sleep(100); // sleep in case CF still has a lock on the file
}
filewrite(local.destination, binarydecode(local.updatedContent, "hex"));
return true;
} else if (arguments.pdfIn neq local.destination){
filecopy(arguments.pdfIn, local.destination);
}
return false;
}
</cfscript>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment