Hopding / pdf-lib

Create and modify PDF documents in any JavaScript environment
https://pdf-lib.js.org
MIT License
6.95k stars 666 forks source link

Not really a bug, but a feature request or implementation issue re: flattening fields and sending to backend ? #964

Closed sscotti closed 3 years ago

sscotti commented 3 years ago

I have had a question on Stack Overflow for some time now about something that I have had trouble implementing with my setup: SO Question

I am using a PDF editor to create my forms and to create the form fields. Works quite nicely now and no real issues with pdf-lib. I also have a fairly generic .php script that I'm using in an MVC framework to basically take:

  1. A path to a .pdf with form fields.
  2. A JSON object with a description of the field data in a format that I am still playing with.
  3. Optionally a QR code image.

I am attaching that file for reference, but as an example in PHP, which is then passed to the index.php that I am attaching. It also passed in the path to the form to fill.

$this->PDFFormData = 
'{"PatientName": {"value":"' . $PatientName . '","type": "text", "font":12},
"Age": {"value":"' . $Age . '","type": "text"},
"PatientBirthDate": {"value":"' . DateTime::createFromFormat('Y-m-d', $PatientDOB)->format('d/m/Y') . '","type": "text"},
"MemberID": {"value":"' . $MemberID . '","type": "text"},
"ReferringPhysicianName": {"value":"' . $ReferringPhysicianName . '","type": "text"}}';

It all mostly works fine in that I can prepopulate a form partially or fully as shown in the attached image:

image

That just embeds the document in an iframe in the browser, and then I can use the browser pdf viewer to either download (in which case the forms fields are still editable, or print to PDF, in which case they are flattened with the data preserved).

What I would like to do is programmatically send the flattened but filled form as a POST to a backend controller, possibly along with a few other items, e.g. as a multi-part form submission. I have not been able to figure out how to do that using this library.

Attachments: index.php script.

sscotti commented 3 years ago

Apparently cannot attach a .php document, so posting the code from that script:

<button class="uibuttonsmallred pdf-lib" id="flatten">Flatten</button>
<button class="uibuttonsmallred pdf-lib" id="saveform">Save</button>
<iframe style="display:none;border:0;margin:5px;padding:5px;" src="" id="pdf"></iframe>
<script nonce="<?php echo $_SESSION['nonce'] ?>">

    var pdfDoc;
    var pdfBytes;
    var formfields;

// $("[src='https://unpkg.com/pdf-lib@1.16.0/dist/pdf-lib.min.js']").on("load", function(e) {
$(function() {
//    e.preventDefault();

    const { PDFDocument, PDFDocumentWriter, rgb } = PDFLib;

      RenderData('<?php echo $data["formurl"] ?>', <?php echo $data['formdata'] ?>, '<?php echo $data["QRCode"] ?>' );
      console.log( "ready!" );

      async function RenderData(formurl, fields, QRCode) {

      const formPdfBytes = await fetch(formurl, {
        headers: {
        'csrf-token': '<?php echo Csrf::makeToken() ?>',
        'nonce': '<?php echo $_SESSION["nonce"] ?>'
        }
      })
        .then(res => res.arrayBuffer())
        const PDFDocument = PDFLib.PDFDocument
        // Load a PDFDocument from the existing PDF bytes
        pdfDoc = await PDFDocument.load(formPdfBytes)

      const url = 'https://pdf-lib.js.org/assets/ubuntu/Ubuntu-R.ttf'
      const fontBytes = await fetch(url).then((res) => res.arrayBuffer())
      pdfDoc.registerFontkit(fontkit)
      const ubuntuFont = await pdfDoc.embedFont(fontBytes);

        if (QRCode != '') {
        const  QRCodeEmbed = await pdfDoc.embedPng(QRCode)
        const page = pdfDoc.getPage(0)
        page.drawImage(QRCodeEmbed, {
            width: 60,
            height: 60,
            y: 700,
            x:480
      })
      console.log(page.getSize())
      }
        // Get the form containing all the fields
        formfields = pdfDoc.getForm()

        // Iterate through the form data and fill based on type.
        // formfields.getTextField('QRCode').setText(QRCodeEmbed)

        $.each(fields, function(fieldname, fielddata) {

            console.log(fieldname);
            console.log(fielddata);

            switch(fielddata.type) {
                case "text":
                    try {

                    formfields.getTextField(fieldname).setText(fielddata.value);
                    if (fielddata.font) {

                      formfields.getTextField(fieldname).setFontSize(fielddata.font);
                    }
                    else {
                      formfields.getTextField(fieldname).setFontSize(10);
                    }
                    }
                    catch(err) {
                        console.log(err.message);
                    }
                    break;
                case "radio":
                    try {
                    let button = formfields.getRadioGroup(fieldname);
                    button.select(fielddata.value);
                    //console.log("set radio to " + fielddata.value);
                    }
                    catch(err) {
                        console.log(err.message);
                    }
                    break;                
                case "check":
                    try {
                    if (fielddata.value == "0") {
                        formfields.getCheckBox(fieldname).uncheck();
                    }
                    else formfields.getCheckBox(fieldname).check();
                    //console.log("set check to " + fielddata.value);
                    }
                    catch(err) {
                        console.log(err.message);
                    }
                    break; 
                default:
            }

        });
        formfields.updateFieldAppearances(ubuntuFont);
        pdfBytes = await pdfDoc.saveAsBase64({ dataUri: true })
        document.getElementById('pdf').src = pdfBytes;

    }

    });   

$("#flatten").on("click", function(e) {

async function Flatten() {

 pdfDoc = await PDFLib.PDFDocument.load(document.getElementById('pdf').src)
 form = pdfDoc.getForm()
 form.updateFieldAppearances();
 form.flatten()
 pdfBytes = await pdfDoc.saveAsBase64({ dataUri: true })
 document.getElementById('pdf').src = pdfBytes
}

Flatten();
});

$("#pdf").on("load", function(e) {
  autoResize($(this));
});

function autoResize(iframe) {

  //     iframe.height($(iframe).contents().find('html').height());
  iframe.height("1650px");
  iframe.width("1275px");
  iframe.show();
}

$("#saveform").on("click", function(e) {
    alert ("Use Print as PDF");
//     download(document.getElementById('pdf').src, "pdf-lib_creation_example.pdf", "application/pdf");
});
</script>
sscotti commented 3 years ago

Closing. See related issue: https://github.com/Hopding/pdf-lib/issues/965