Generating PDF

One quick question: does anybody know a prolog module to generate PDF documents.
Any pointers appreciated

Have you ever looked inside a PDF, if not you might be surprised to know that they are not data but code, based on PostScript.

I personally then to think of a PDF document as a containerized web site divided up into pages with a table of contents, links, images, index, footnotes, glossary, etc. You can even do some interactive things with them as they are based on a Turing complete language but I have not reached that level.


For technical documents I would use LaTeX edited with a program such as Texmaker and then convert that to a PDF using MikTex

For simpler documents I would check if the tools/apps, such as Microsoft Word (ref) or Apache OpenOffice (ref), has the ability to export/save as PDF.

StackExchange has a site dedicated to LaTeX Q&A but they may be friendly to PDF questions, see tag: PDF

You’re entering a world of pain :slight_smile:

But I second your question. Is there anything even half working?

There are many PDF generation libraries available for Java, I have had to use several. The cleanest in terms of programming experience is Apache FOP. Prolog as a language would be very good fit for this XSL FO, esp. if one could avoid writing XSL.

In theory it would be possible to generate the PDF in almost any way, but in practice it is a huge task.

Going down the LaTeX road (there is also PDFLaTeX etc) is also a huge PITA, because of the stuff you need to install. You basically need a working TeX distribution.

Pandoc is an option but it also uses an external tool to do the PDF generation.

So what is your use case? Most importantly: do you need to distribute the PDF generator, or do you just need to programmatically generate a PDF on your own machine?

EDIT: the point is, there are endless ways to generate PDF, but I know of nothing that is both nice and free except for Apache FOP, and this is, well, Java. Once you go to Java, there are other options as well.

Pandoc

There’s also a “pack” named switex, which might be worth a try. It’s not prolog calling latex, but the other way round, latex calling prolog, but sometimes that is needed as well.

Now that I think about it, one could for example generate PostScript and use ghostscipt (distributed under AGPL). But of course, “generate PostScript” is not a weekend project, at least for me.

Actually, I was simply looking for someting in the vein of jsPDF
My feeling is that DCGs could be of great help in this context e.g

phrase(pdf(MyPdf, [page_size='A4', page_orientation=portrait]), [
   text('Hello World', 10, 10)
]).

Well, this means you are either running in a browser or with Node.js.

So we come back to, what is your use case? If you want to generate your PDF on the client-side, or run Node.js, then jsPDF seems like a good choice.

Peter Reintjes’ VHDL tools could generate PDF diagrams – I remember looking at the code and thinking that it was quite compact. As I recall, he used DCGs extensively, both for parsing VHDL and for generating output. The code is probably available somewhere online.

To add to what @EricGT said, to work on TeX personally I have found Gummi (on Ubuntu) to be a good compromise between the low level document encoding and the presentation level.

Some years ago I had a customer asking for inline presentation of PDF templates, that (their) customers then downloaded having personal data filled in, signed and then submitted (mainly as scanned images). It turned out to be a difficult problem, in the end I solved using Mozilla PDF.js, it’s open source and so I was able to customize the presentation and complete the task. Was not easy, also because at the time the library was actively developed, and the code is heavily asyncronous (but not async/await was available at the time, just promises…).

For direct, simple PDF generation there is jsPDF, maybe will try to provide a toy DDL (document description language) for SWI-Prolog running a localhost HTTP server. Should be fairly general… hope I’ll have something to submit later…

Here is a demo of a most simple usage of jsPDF, hope it’s useful despite its simplicity:

/*  File:    demo_jspdf.pl
    Author:  Carlo
    Created: Sep 19 2020
    Purpose: help on https://swi-prolog.discourse.group/t/generating-pdf/2947
*/

:- module(demo_jspdf, []).

:- use_module(library(http/http_server)).
:- use_module(library(http/http_json)).
:- use_module(library(http/http_log)).

% when `make` just reload http://localhost:8083 to get changes
:- initialization (
       Port=8083,
       catch(http_stop_server(Port,[]),_,true),
       http_server([port(Port)])
   ).

:- http_handler(root(.),
                http_redirect(moved,location_by_id(home_page)),
                []).
:- http_handler(root(home),home_page,[]).

:- http_handler(root(generate),generate,[]).

home_page(_Request) :-
    reply_html_page(
        [ title('Demo jsPDF'),
          script(src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.1.1/jspdf.umd.min.js",'')
        ],
        [ div([
            div(id=doc_definition_area,[
              div([
                label(for=header_text, 'Some header text'),
                input(id=header_text)
              ]),
              div([
                label(for=body_text,'Some text to insert in body'),
                textarea([
                  id=body_text,
                  rows=20,
                  cols=40
                ],'')
              ]),
              div([
                label(for=footer_text,'Some footer text'),
                input(id=footer_text)
              ])
            ]),
            div(id=command_area,
              button(id=generate,generate)
            )
          ]),
          \css,
          \js
        ]).

% get info from the page, reply with a set of jsPDF commands
generate(Request) :-
  http_read_json_dict(Request,Dict),
  % of course, should do something more... here just copy input
  reply_json_dict(_{
    header_text:Dict.header_text,
    body_text:Dict.body_text,
    footer_text:Dict.footer_text
  }).

css --> html(style('
  label {
      width:200px;
      background-color:lime;
  }
')).

js --> html(script("

window.onload = () => {

  var jsPDF = window.jspdf.jsPDF
console.log(jsPDF)

  const request = (url,json) => fetch(url,{
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(json)
  }).then(r => r.json())

  generate.onclick = async (ev) => {
    try {
      let result = await request('/generate', {
        header_text:header_text.value,
        body_text:body_text.value,
        footer_text:footer_text.value
      })
console.log(result)
      let doc = new jsPDF();
      doc.text(20, 20, result.header_text)
      doc.text(20, 30, result.body_text)
      doc.addPage()
      doc.text(20, 20, result.footer_text)
      doc.save('Test.pdf')
    } catch(e) {
      alert(e.message)
    }
  }
}

")).

PS: the CSS for label isn’t working… please forgive my lazyness…

1 Like