# Creating PDF Output

In the last post we generated a view on all "contemporaries" of a specified person. The data were fetched from the database with help of a Pilog query.

Now we will see how we can write this output to a .txt or .PDF file.

------------------------

We continue with our [``family-contemporaries.l``](https://gitlab.com/picolisp-blog/web-applications/-/blob/main/database/family-contemporaries-step1.l) file from the last post.

--------------------

### Requirements

In order to be able to print the PDF output, we need some additional packages.

First of all, make sure that the ``@lib/svg.l`` library and ``svg`` namespace are declared at the top of the program:

```
(load "@lib/http.l" "@lib/xhtml.l" "@lib/form.l" "@lib/svg.l")
(symbols 'family 'svg 'pico)
```

Also, we need an external package to convert SVG files to PDF called [librsvg2.bin](https://packages.debian.org/en/sid/librsvg2-bin) ("librsvg" on termux for Android). On Debian systems you can install it with

```
sudo apt-get install librsvg2.bin
```

-----------------------

### Creating a Textfile for Download with ``tmp``

First of all, let's create a new file. For this purpose we can use the ``tmp`` function: 

> ``(tmp ['any ..]) -> sym``

> Returns the path name to the ``pack``ed ``any`` arguments in a process-local temporary directory. The directory name consists of the path to ".pil/tmp/" in the user's home directory, followed by the current process ID ``*Pid``. This directory is automatically created if necessary, and removed upon termination of the process (``bye``).

Let's try in the REPL:

```
: (tmp "Testfile")
-> "/home/mia/.pil/tmp/7768/Testfile"
```

Let's name our file ``Contemporaries.txt`` and bind its path to the local variable ``Txt``:

```
'(let Txt (tmp "Contemporaries.txt")
   (out Txt (txt> (chart)))
```

-----------------------


Then we need to get all properties from our ``chart`` as text. This can be done using the ``txt>`` method of the PicoLisp GUI class. Then we pass ``txt>`` to our curent chart using the function ``(chart)`` which returns the current chart and write the output to ``Txt``.

```
'(let Txt (tmp "Contemporaries.txt")
   (out Txt (txt> (chart)))
```

------------------------

### Creating the download button

Now let's wrap the above code in a button which triggers the download. When the button is pressed, the above code is executed and the user is redirected to the URL of the file. This automatically triggers the download dialog in the browser.

The final code for the button looks like this:

```
(gui '(+Rid +Button) "Textfile"
    '(let Txt (tmp "Contemporaries.txt")
       (out Txt (txt> (chart)))
       (url Txt) ) )
```

Quite short, isn't it? If we add this to our ``family-contemporaries.l`` file (still **inside** of the ``form`` function), the result looks like this:

![Peek 2021-11-06 13-04.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1636200401449/2DQHttTcF.gif)

-------------------------

We get a textfile where each line corresponds to a row in the table. The columns are separated by ``tabs``.


------------------------

### Creating the PDF download

Now let's do the same with our PDF. However this time we the output formatted as table, like this:


![pdf.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1636201158674/XufEX0k8k.png)


----------------------

The first step for the PDF are the same, except that we don't use a simple text file, but the ``pdf`` function to create a PDF in landscape format:

```
(pdf *A4-DY *A4-DX (tmp "Contemporaries.pdf")
   (out (tmp "Contemporaries.txt")
      (txt> (chart)) )
```

For portrait format, we can write ``*A4-DX *A4-DY``.

---------------------

### Formatting the output

In the next step, let's **read** the file in again and add some formatting. First, we define the variables 
- ``Page``: 1, 
- ``Fmt``: list of width attributes in ["dots"](https://en.wikipedia.org/wiki/Dots_per_inch) (1/72 inch), and 
- ``Ttl``: the first line that is read in.

```
(in (tmp "Contemporaries.txt")
   (let (Page 1  Fmt (200 120 50 50 120 120 120)  Ttl (line T))
```

-------------------------

Then we style the format with help of the following functions:

- ``font``: takes a number and a font
- ``width``: stroke width in dots
- ``down``: margin to the top in dots
- ``indent``: margin to the left in dots

-------------------------

First we set the general font style:

```
(font (7 . "Helvetica"))
(width "0.5")
```

Every new page has a offset to top by 12 and is indented by 40. If there is more than one page, every subsequent page carries the title and page number. After that comes the table head, followed by another space.

``` 
(while
   (page
      (down 12)
      (indent 40
         (ifn (=1 *Page)
            (ps (pack Ttl ", Page " (inc 'Page)))
            (font 9 (ps Ttl)) )
         (down 12)
         (table Fmt
            "Name" "Occupation" "born" "died" "Father" "Mother" "Partner" )
         (down 6)
```

--------------------

### Generating the table content

After the table title is created, we loop over the each line of the file and split the line at the tabs (``"^I"``) and put them to a new list ``L``. 

Also we need to set the exit condition for ``loop``: either when the file ends (``eof``) or when there are less than 80 dots distance to the lower bottom of the PDF.


``` 
(loop
   (let L (mapcar pack (split (line) "^I"))
   ...
   (T (eof))
   (T (>= *Pos (- *DY 80)) T) ) )
```

Within the loop, we can write each table cell using the ``ps`` function:

```
(down 8) 
(table Fmt
   (font "Helvetica-Bold" (ps (car L)))
   (ps (cadr L))
   (ps (caddr L))
   (ps (cadddr L))
   (ps (get L 5))
   (ps (get L 6))
   (ps (get L 7)) )
(down 4) )
```

-------------------------

### Defining the button

Now the last thing we need to do is defining the button and call the ``url`` function, which we can simply wrap around the whole PDF generating code:

```
(gui '(+Rid +Button) "PDF"
   '(url
      (pdf *A4-DY *A4-DX (tmp "Contemporaries.pdf")
         (out (tmp "Contemporaries.txt")
            ...
         (in (tmp "Contemporaries.txt")
            ...
```

If we now restart our script, we get another button labelled "PDF" and can download the displayed content.


![contemp2.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1636213506259/ScS6ZGxvdx.gif)


-----------------------

You can find the finished program [here](https://gitlab.com/picolisp-blog/web-applications/-/blob/main/database/family-contemporaries.l).


-------------------------

# Sources

https://packages.debian.org/en/sid/librsvg2-bin



