react-pdf icon indicating copy to clipboard operation
react-pdf copied to clipboard

Produce Facture-x/ZUGFeRD invoices | Port reference from upstream repo

Open florianbepunkt opened this issue 1 year ago • 9 comments

This is neither a feature report / nor bug request.

Goal

Use react-pdf to issue electronic invoices (Facture-x / ZUGFeRD). This requires attaching XML data, adding some XMP markup and a valid PDF/A3 pdf.

Contribute back / my issue

To implement this I forked this repo and I would like to contribute back, as a lot of changes involve #2613.

Basically I ported the the new reference class from the upstream pdfkit repo.

This works fine except one issue: When adding custom fonts, they look like this (there should be one word "Lorem"):

Bildschirmfoto 2024-10-31 um 08 44 44

@diegomura Do you have any idea what might be happening here? The issue must be somewhere at the intersection between the upstream repo's new reference class and how custom fonts are embedded. Maybe there is some overlap with PR in #2696 by @klimeryk

Further implementation

Once the issue can be resolved and all tests run, I can split work into several more granular PRs. I have a prototype with these features implemented.

  • [ ] Port reference and PDF/A compliance from pdfkit. Might be beneficial for long-term goal to use upstream repo again.
  • [ ] Allow file attachments
  • [ ] XML component to add XML metadata
  • [ ] Fixed for the pdfkit lib to actually produce valid PDF/A3 (this is a PR I would also open against upstream, as they have a small spec derivation when attaching files)

florianbepunkt avatar Oct 31 '24 07:10 florianbepunkt

Update: Turns out the issue is related to the fontkit upgrade. Using [email protected] like the upstream repo works. Not sure how to proceed. Maintainers, please advise.

I implemented everything for Facture-x / ZUGFeRD compliance (see screenshot).

Bildschirmfoto 2024-10-31 um 12 56 57

    <Document
      attachments={[
        {
          content: exampleXml,
          creationDate: new Date(2020, 3, 1),
          description: 'ZUGFeRD Invoice Data',
          hidden: false,
          modifiedDate: new Date(2020, 3, 1),
          name: 'zugferd-invoice.xml',
          relationship: 'Alternative',
          type: 'application/xml',
        },
      ]} // new prop to add PDF attachments
      author="Test GmbH"
      creationDate={new Date()}
      creator="Test GmbH"
      keywords="test"
      onRender={onRender}
      pdfVersion="1.7"
      producer="Test"
      subject="Test"
      subset="PDF/A-3" // new prop to specify PDF subset
      tagged // new props to specify whether PDF should be tagged or not, necessary for PDF/A3 compliance
      title="Test"
    >
      <Page>
        <Text style={{ fontFamily: 'Inter' }}>Lorem</Text>
        <Xml value={`some XML metadata, shortened for brevity`}/>
      </Page>
    </Document>

florianbepunkt avatar Oct 31 '24 12:10 florianbepunkt

Thanks for working on this, @florianbepunkt! And for the ping - I've ran into font issue as well for my PR, so I'm curious and excited that you were able to fix the issues by downgrading fontkit! (https://github.com/florianbepunkt/react-pdf/commit/349c5e5af8973f5adb5c30f5be7d94ee8ef8aa33) I'll try the same for my PR and will report back if that fixes the issues.

klimeryk avatar Nov 01 '24 22:11 klimeryk

@klimeryk It might be good to check the whole commit history (it's not huge), but I was not 100% sharp in aligning my commits, as there was some back and forth. Reverting to fontkit<2.0 means, you loose browser compatibility. So this is a first step, but maybe we can find out why that is and how to fix it.

florianbepunkt avatar Nov 02 '24 05:11 florianbepunkt

@klimeryk Interesting find... I think I found the underlying issue. Missed a small point when checking fontkit's release notes (unfortunately they don't have a proper changelog):

Encoding subsets is now no longer streaming. subset.encodeStream() has been replaced with subset.encode() which returns a Uint8Array.

I believe the fix is to simply change this line https://github.com/diegomura/react-pdf/blob/c0ec5d8d434b6c936c30d36a431e53256590e0d8/packages/pdfkit/src/font/embedded.js#L152

from

fontFile.end(this.subset.encode());

to

fontFile.end(Buffer.from(this.subset.encode()));

The interesting part: How the heck did this work before?? I honestly have no clue. But with this change we should be good to go. This should solve the font issue in your PR as well. Can you check?

I would wait if we hear something from the maintainer, so we can finish this PR.

florianbepunkt avatar Nov 02 '24 07:11 florianbepunkt

Awesome find, @florianbepunkt! I've tested with my PR and it indeed fixes the font issue! 💖 See https://github.com/klimeryk/react-pdf/commit/16f14754427e47ba3b28136dcccd257f42731e20. I've only done quick test, but everything looked like it should - I'll give it a closer look and update the description of my PR tomorrow-ish 🤞 Thank you so much for connecting the dots here - I've been meaning to dig into these font issues, but never got around to it. Super stoked to see it was just a simple one line fix in the end! Though, of course, finding that one line is the tricky part - so huge kudos to you!

klimeryk avatar Nov 03 '24 23:11 klimeryk

That would be an great feature. Actually I need this!

PeterLaudel avatar Dec 05 '24 12:12 PeterLaudel

@florianbepunkt Wow, great work! I would love to see your implementation being merged! Your fork is a little behind the current react-pdf master. Any chance you can provide some yarn patches or patch package to apply your changes?

jgo80 avatar Dec 14 '24 15:12 jgo80

@diegomura Would you be interested in this? I can create a new PR that implements

  • PDF/A spec including compliant font impl
  • Spec compliant attachments
  • XML primitive to embedd xml data
  • Node 22 compatability

This would allow to create Zugferd/Facture-X invoices. Also I can start on getting rid of some outdated / unused deps (e. g. updating canvas to v3, getting rid of cross-fetch, etc.). Let me know.

florianbepunkt avatar Jan 19 '25 10:01 florianbepunkt

This would be a great feature to be added, and currently blocks us from using react pdf :)

MarcoMuellner avatar Mar 24 '25 13:03 MarcoMuellner