jung-kurt / gofpdf

A PDF document generator with high level support for text, drawing and images
http://godoc.org/github.com/jung-kurt/gofpdf
MIT License
4.34k stars 787 forks source link

introduce an io.Reader-based API for MakeFont #168

Open sbinet opened 6 years ago

sbinet commented 6 years ago

I am trying to migrate gonum/plot PDF backend to gofpdf because:

see: https://github.com/gonum/plot/pull/433

however, it would be great if we could have the feature of MakeFont exposed with an API that does not require to create files.

for our gonum/plot library, I had to resort to a few temporary files creation to be able to embed the fonts: https://github.com/gonum/plot/pull/433/files#diff-d0bfa4db82f9d65d9b4fde15d81f98c1R378

it would be great if we could have:

func MakeFontFrom(font, enc io.Reader, msg io.Writer, embed bool) (z, j []byte, err error)

(or something along these lines...)

jung-kurt commented 6 years ago

This request looks good to me. One wrinkle will be support for Type 1 fonts. These have both an .afm and .pfb file, so an extra io.Reader will be required. This will be set to nil for TrueType fonts.

Since io.Readers are used instead of files, it makes sense to use io.Writers for the output. This can be easily wrapped to provide the API that you propose.

sbinet commented 6 years ago

I see.

with the amount of arguments this new MakeFontFrom functions is now growing, perhaps introducing a proper type (a struct) or exposing fontDefType (or some version of it) would make sense ?

IIUC, MakeFont is all about creating a fontDefType value and serializing it on disk. all of this based off the informations provided by and collected into a fontInfoType. (there's also perhaps some value into re-using some of the code from golang.org/x/image/font/... ?)

jung-kurt commented 6 years ago

Good points.

I think it makes very good sense to make use of golang.org/x/image/font/.... It would be especially beneficial if it could help with embedding a font subset. This is one of the obstacles supporting Unicode.

tdewolff commented 5 years ago

I would also be interested in this feature. I have multiple drawing back-ends that I support (rasterized, SVG, PDF, EPS) which I would all like to take Type1/TrueType/OpenType as inputs directly. So the library would embed them into PDFs in-memory without the need to generate intermediate files (.json). Is this something you plan on adding soon? I might be able to do some work on this too if you like and if time allows.

jung-kurt commented 5 years ago

I have multiple drawing back-ends that I support (rasterized, SVG, PDF, EPS) which I would all like to take Type1/TrueType/OpenType as inputs directly.

Sounds like a great project, @tdewolff. I have mused about writing a PDF generator for the pandoc intermediate language.

I might be able to do some work on this too if you like and if time allows.

I have not had time to pursue this enhancement, so any ideas and work you can contribute would be greatly appreciated.

I see two approaches. One would be to work with gofpdf's limitation of using code pages, essentially indexed arrays of 256 or fewer glyphs. If a document can get by with a single code page, then a custom code page could be constructed from a unicode font and embedded into the PDF document. An extension to this idea would be to create as many custom code pages as necessary to cover all of the glyphs used in a document. The text rendering routine would then silently change code pages as needed to place text in a document. I have a hunch this would get ugly fast.

The second approach would be to carry over the high level functionality of gofpdf to a PDF generator that already does Unicode embedding, perhaps gopdf. I haven't looked at that package but it looks like it would make a good foundation. In an effort to strive for API compatibility, the original port of gofpdf from fpdf carried over a lot of details that run across the grain of Go conventions. A new port could be an opportunity to remedy that.

d1ngd0 commented 5 years ago

Could we just pull in the font code from gopdf? I would be willing to give this a try if there isn't a reason I shouldn't.

jung-kurt commented 5 years ago

Could we just pull in the font code from gopdf?

We could. I don't have a feel for whether it would be easier to do that or to transfer high-level functionality over to gopdf. I'll be interested to hear your thoughts if you look into this.

I would be willing to give this a try if there isn't a reason I shouldn't.

Much appreciated! I am happy to pitch in if you can create a roadmap.

d1ngd0 commented 5 years ago

The second approach would be to carry over the high level functionality of gofpdf to a PDF generator that already does Unicode embedding, perhaps gopdf. I haven't looked at that package but it looks like it would make a good foundation.

Have you put some serious though into something like this? Would you want to maintain the gofpdf library with this base or would you want to start PRing high level functionality into gopdf if the author wanted? Otherwise would you just create a fork of gopdf and create a new library?

jung-kurt commented 5 years ago

Have you put some serious though into something like this?

No, I have only mused about it.

Would you want to maintain the gofpdf library with this base or would you want to start PRing high level functionality into gopdf if the author wanted?

Either approach works for me. I think it makes sense to pursue the path that involves the least disruption. gopdf appears to be well-modularized, so gofpdf's high level API may carry over with very little friction. Also, it could be done incrementally, which is seldom a poor tactic.

Otherwise would you just create a fork of gopdf and create a new library?

I am reluctant to do that unless the end goal is to pull it into one or the other package. Both packages are active, so little is to be gained and much to be lost by creating a third package.

d1ngd0 commented 5 years ago

Sounds good. In the coming days I will add a branch to my fork that is just the gopdf library and I will start pulling the high level functionality over. I'll let you know how it goes. This will allow us to PR any updates so the author of gopdf can take and leave whatever they want.

In an effort to strive for API compatibility, the original port of gofpdf from fpdf carried over a lot of details that run across the grain of Go conventions. A new port could be an opportunity to remedy that.

Considering this, I think it would be nice to hear what your vision for this library is while I work on this.

jung-kurt commented 5 years ago

In the coming days I will add a branch to my fork that is just the gopdf library and I will start pulling the high level functionality over.

Terrific! I look forward to learning how it proceeds.

Considering this, I think it would be nice to hear what your vision for this library is while I work on this.

Go idioms like pdf.X() should be used rather than the original FPDF names like pdf.GetX().

Take care not to interfere with established Go interfaces like io.Writer. For example, gofpdf's current Write() has a signature that keeps Fpdf from implementing the io.Writer interface. (Ouch.)

If string buffering is needed (it might not be), use strings.Builder (which I believe can build up strings non-contiguously and therefore more efficiently) rather than bytes.Buffer.

Personally, I think the library would have the greatest value if it had all the functions needed to produce finished documents with the pandoc intermediate language (native AST). One could then create a polished document using enhanced Markdown or some other markup. Consequently, it may be worth looking at pandoc's native AST (using that program's --write=json argument). The idea would be to have a very small command program that imports the library and coordinates with pandoc.

Thanks for your interest in this project. I think a combination of the best of gofpdf and gopdf promises to be a very useful product.

d1ngd0 commented 5 years ago

I have started a new branch on my fork https://github.com/d1ngd0/gofpdf/tree/ftr/gopdf As you can see I moved all the gofpdf code into a folder called old/ and then placed all the gopdf files in the base directory. I changed the GoPdf struct to Fpdf and have added margins and units. In the next few days I will put together a plan on how to tackle this as a group.

jung-kurt commented 5 years ago

Excellent! I will follow your commits closely and lend a hand when able.