# clj-htmltopdf A Clojure wrapper for the [Open HTML to PDF](https://github.com/danfickle/openhtmltopdf) library. Includes some extra niceties to make generating PDF content such as reports and other basic "print" content simple. ## Leiningen [![](https://clojars.org/clj-htmltopdf/latest-version.svg)](https://clojars.org/clj-htmltopdf) ## Usage ```clojure (use 'clj-htmltopdf.core) (->pdf [:div [:h1 "HTML to PDF"] [:p "Glorious!"]] "output.pdf") ``` `clj-htmltopdf.core/->pdf` can take a variety of different input and output argument types, such as strings, `java.io.File` objects, `java.net.URL` objects, streams, etc. As shown in the above example, a special case is made when the input argument is [Hiccup](https://github.com/weavejester/hiccup)-style HTML where it will be automatically converted to an HTML string before being rendered as a PDF. Remember, that when rendering HTML to PDFs, you should not just expect that any HTML you throw at it will render perfectly fine onto the resulting PDF (just the same as when you print some HTML page from your browser, not everything will be printed exactly the same as you see on your screen). ### Options The third and optional argument to `clj-htmltopdf.core/->pdf` is a map of options. If you don't include this some basic defaults will be used that should be suitable for most basic "report-like" PDFs. The majority of the options supported are implemented by injecting small bits of HTML and/or some extra CSS styling into your HTML just before it is rendered as a PDF. However if you wish (or your PDF styling requirements are complex enough that you've outgrown the simple built-in options available), you are free to ignore these options and have your PDF rendered using the exact HTML/CSS you want if you're more comfortable writing things such as @page CSS styles yourself. Since Open HTML to PDF is based on [Flying-saucer](https://github.com/flyingsaucerproject/flyingsaucer), it supports it's [CSS extensions](https://flyingsaucerproject.github.io/flyingsaucer/r8/guide/users-guide-R8.html#xil_43) as well. A description of the keys supported in the options map follows: #### `:doc` Allows you to embed metadata information about the document into resulting PDFs such as title, author, etc. ```clojure {:title "My Awesome PDF" :author "Gered" :subject "Only Testing" :keywords "clojure,html,to,pdf"} ``` #### `:page` Allows for control over CSS @page rule styles. This lets you set properties such as headers/footers, page layout and orientation, margins and more. ```clojure {:margin "1.0in" :size :letter :orientation :portrait :margin-box {:top-left {:element "my-top-left-box"} :top-right {:paging [:page " of " :pages]} :bottom-center {:element "the-bottom-center-box"} :bottom-right-corner {:text "this is in the corner!"}}} ``` `:margin` sets page margins and can either a string containing a raw CSS `margin` definition, a map containing `:left`, `:top`, `:right`, `:bottom` attributes, or a keyword to specify a predefined page margin: * `:normal` - `"1.0in"` * `:narrow` - `"0.5in"` * `:moderate` - `"1.0in 0.75in"` * `:wide` - `"1.0in 2.0in"` `:size` and `:orientation` together set the [@page size](https://developer.mozilla.org/en-US/docs/Web/CSS/@page/size) property. By default this will be `:size :letter` and `:orientation :portrait`. `:margin-box` is a map containing definitions for your headers/footers. The keys of the map should correspond to the margin box names listed [here](https://www.w3.org/TR/css3-page/#margin-boxes) (if you make a typo, you won't get an error, but the margin box you typo'd also won't be visible anywhere, so be careful). The values should be maps that allow you to specify the content. These can take a few different formats allowing you a good amount of flexibility: * `{:text "this is in the corner!"}` The simplest format, allows you to place some aribtrary constant text value in a margin box. * `{:paging [:page " of " :pages]}` Similar to `:text`, it allows you to write out a simple line of text, but the text is specified as a vector of values that are all concatenated together where the values `:page` and `:pages` are replaced with the current page number and total number of pages respectively. * `{:element "your-element-id-here"}` The string here should correspond to an element located anywhere in your HTML that has the same element ID. This element will be turned into a running element, which is then taken out of the flow of the rest of the HTML and will be rendered on to each page at that margin box location instead. This format is really helpful when you want to include complex elements in your margin boxes, as it allows you to set any arbitrary HTML as the content. * `{:content "\"Page \" counter(page)"}` Can be used to emit a raw value into the CSS `content` property for that margin box. You'll probably want to use this format the least often, but it can sometimes be useful. #### `:styles` > **NOTE** This property is likely to get somewhat of an overhaul in the near future to allow for more flexibility and control over basic styling. Please keep this in mind when upgrading to new versions of clj-htmltopdf. Allows control over what (non-@page) CSS styles are included in your HTML. Can be a filename or vector of filenames, a map of CSS styles, or a boolean to toggle on or off default basic style inclusion. The default value is `true`. When set to `true`, the following basic styles are set in your HTML: ```clojure {:font-family "sans-serif" :font-size "12pt" :line-height "1.3" :background-color "#fff" :color "#000"} ``` In addition, the CSS stylesheet `htmltopdf-base.css` will be included, which sets up a number of basic styles and helper CSS class definitions that are mostly intended to make generating simple report-like PDFs a little easier. When set to a map, the map should include CSS styles for the HTML `
` tag only, and it will be merged with the default styles shown above. Two additional keys can be set in this map: * `:styles` a single file or vector of filenames pointing to any additional CSS stylesheets to be included. * `:fonts` a sequence of maps of the form `{:font-family "font-family-name-here" :src "/path/to/custom-font.ttf"}` which allows you to use custom fonts in other CSS style definitions using the `:font-family` name specified here. If you want to include your own custom CSS styles without the base `htmltopdf-base.css` stylesheet being included nor any other base styles being injected, then you can specify either a single CSS filename or a vector of multiple CSS files to be included in your HTML. Alternatively, if you know that your HTML will already include links to the external CSS files you want to include, then you can just specify `nil` or `false` for the `:styles` option to get the same behaviour. #### `:watermark` Either a map containing various properties for rendering text or image based watermarks onto all pages of the PDF, or a function that will be called for each page that allows you to implement custom watermark rendering. For simple text watermarks, the map can use any of the following: ```clojure {:text "My Watermark Text" :font "helvetica-bold" :font-size 36.0 :color [255 0 0] :rotation 45.0 :x :center :y :center :opacity 0.5} ``` `:font` is limited at the moment to be one of the built-in PDFbox supported fonts: times-roman, times-bold, times-italic, times-bolditalic, helvetica, helvetica-bold, helvetica-oblique, helvetica-boldoblique, courier, courier-bold, courier-oblique, courier-boldoblique `:x` and `:y` can either be an X/Y coordinate (relative to the origin 0,0 at the bottom left of the page), or `:center` which will center the text on that axis. For simple image watermarks, the map uses most of the same properties: ```clojure {:image "/path/to/image-file" :rotation 45.0 :x :center :y :center :scale-x 2.0 :scale-y 2.0 :opacity 0.5} ``` Finally, as mentioned, you can specify a function to implement your own watermark rendering. ```clojure (fn [^org.apache.pdfbox.pdmodel.PDDocument doc ^org.apache.pdfbox.pdmodel.PDPage page ^org.apache.pdfbox.pdmodel.PDPageContentStream cs] ; render your watermark onto 'cs' here ! ) ``` The `cs` instance of a [`PDPageContentStream`](https://pdfbox.apache.org/docs/2.0.5/javadocs/org/apache/pdfbox/pdmodel/PDPageContentStream.html) object contains a bunch of methods that can be used to render onto the current page. #### `:objects` You can include `