Skip to content

Commit

Permalink
Merge pull request #123 from yogthos/pdf-table-enhancements
Browse files Browse the repository at this point in the history
pdf-table and table element enhancements
  • Loading branch information
gered committed Mar 24, 2017
2 parents c617b9b + 713ac1f commit 95b4974
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 33 deletions.
32 changes: 29 additions & 3 deletions README.md
Expand Up @@ -996,6 +996,7 @@ metadata:
and can also be formatted via a vector of paragraphs or phrases
* :offset number
* :num-cols number
* :no-split-cells? boolean if true, will prevent cells (and rows) from being split across two pages. if a cell won't fit entirely on the current page, the row will be moved to the next page. default is false

```clojure
[:table {:header ["Row 1" "Row 2" "Row 3"] :width 50 :border false :cell-border false}
Expand Down Expand Up @@ -1065,15 +1066,20 @@ that can either be strings, images, chunks, paragraphs, phrases, pdf-cells, or o

metadata:

* :header a vector containing one or more row vectors (of the same format as normal table rows) that will be used as the header for the table
* :footer same as :header, but for footer rows
* :background-color `[r g b]`
* :spacing-before number
* :spacing-after number
* :spacing-before number spacing before the table
* :spacing-after number spacing after the table
* :cell-border boolean
* :bounding-box `[width height]`
* :horizontal-align :left, :rigth, :center, :justified
* :horizontal-align :left, :right, :center, :justified
* :title string
* :width number
* :width-percent number (0-100)
* :num-cols number manually specify the number of columns in the table. if not specified this will be automatically set to the maximum number of columns that appear in any row in the table.
* :keep-together? boolean if true, attempts to keep the entire table on the same page. if there is not enough room on the current page, the table will be moved to the next page. will not work if the table is too large for any single page. default is false
* :no-split-rows? boolean if true, if a row won't fit in the space remaining on the current page, it will be moved to the next page instead of the cells being split between two pages. default is false

```clojure
[:pdf-table
Expand All @@ -1084,6 +1090,26 @@ metadata:
["foo" [:chunk {:style :bold} "bar"] [:phrase "baz"]]
[[:pdf-cell "foo"] [:pdf-cell "foo"] [:pdf-cell "foo"]]
[[:pdf-cell "foo"] [:pdf-cell "foo"] [:pdf-cell "foo"]]]

; if the widths vector that normally would be after the metadata map is nil, the
; pdf-table's column widths will be automatically figured out (evenly spaced)
[:pdf-table
{:width-percent 100}
nil
["a" "b" "c"]
["1" "2" "3"]
["i" "ii" "iii"]]

; table with 2 header rows, 3 regular content rows
[:pdf-table
{:header [[[:pdf-cell {:colspan 2}
[:paragraph {:align :center :style :bold} "Customer Orders"]]]
[[:phrase {:style :bold} "Name"]
[:phrase {:style :bold} "Order Amount"]]]}
[50 50]
["Joe" "$20.00"]
["Bob" "$7.50"]
["Mary" "$18.90"]]
```

#### Table Cell
Expand Down
112 changes: 82 additions & 30 deletions src/clj/clj_pdf/core.clj
Expand Up @@ -457,7 +457,19 @@
:else [:cell content])]
(.addCell tbl ^Cell (make-section meta element))))

(defn- table [{:keys [background-color spacing padding offset header border border-width cell-border width widths align num-cols]
(defn- table [{:keys [align
background-color
border
border-width
cell-border
header
no-split-cells?
num-cols
offset
padding
spacing
width
widths]
:as meta}
& rows]
(when (< (count rows) 1) (throw (new Exception "Table must contain rows!")))
Expand Down Expand Up @@ -487,6 +499,8 @@

(.setAlignment tbl ^int (get-alignment align))

(.setCellsFitPage tbl (boolean no-split-cells?))

(doseq [row rows]
(doseq [column row]
(add-table-cell tbl (dissoc meta :header :align :offset :num-cols :width :widths) column)))
Expand All @@ -504,38 +518,76 @@
:else [:pdf-cell content])]
(.addCell tbl ^PdfPCell (make-section meta element))))

(defn- pdf-table [{:keys [spacing-before spacing-after cell-border bounding-box num-cols horizontal-align table-events width width-percent]
(defn- pdf-table [{:keys [bounding-box
cell-border
footer
header
horizontal-align
keep-together?
no-split-rows?
no-split-late?
num-cols
spacing-after
spacing-before
table-events
width
width-percent]
:as meta}
widths
& rows]
(when (empty? rows) (throw (new Exception "Table must contain at least one row")))
(when (not= (count widths) (or num-cols (apply max (map count rows))))
(throw (new Exception (str "wrong number of columns specified in widths: " widths ", number of columns: " (or num-cols (apply max (map count rows)))))))

(let [^int cols (or num-cols (apply max (map count rows)))
tbl (new PdfPTable cols)]

(when width (.setTotalWidth tbl (float width)))
(when width-percent (.setWidthPercentage tbl (float width-percent)))

(if bounding-box
(let [[x y] bounding-box]
(.setWidthPercentage tbl (float-array widths) (make-section [:rectangle x y])))
(.setWidths tbl (float-array widths)))

(doseq [table-event table-events]
(.setTableEvent tbl table-event))

(if spacing-before (.setSpacingBefore tbl (float spacing-before)))
(if spacing-after (.setSpacingAfter tbl (float spacing-after)))

(.setHorizontalAlignment tbl ^int (get-alignment horizontal-align))

(doseq [row rows]
(doseq [column row]
(add-pdf-table-cell tbl (merge meta (when (= false cell-border) {:set-border []})) column)))

tbl))
(when (empty? rows)
(throw (new Exception "Table must contain at least one row")))
(let [header-size (if (seq header) (count header))
footer-size (if (seq footer) (count footer))
; with PdfPTable, the header and footer rows need to go first in the list
; of table rows provided to it
rows (concat (if header-size header) (if footer-size footer) rows)]
(when (and widths
(not= (count widths)
(or num-cols (apply max (map count rows)))))
(throw (new Exception (str "wrong number of columns specified in widths: " widths ", number of columns: " (or num-cols (apply max (map count rows)))))))

(let [^int cols (or num-cols (apply max (map count rows)))
tbl (new PdfPTable cols)]

; PdfPTable is pretty weird. setHeaderRows needs to be given a number that is
; the sum of the total number of header _and_ footer rows that this table
; will have, while setFooterRows is just the number of footer rows.
(if (or header-size footer-size)
(.setHeaderRows tbl (int (+ (or header-size 0) (or footer-size 0)))))
(if footer-size (.setFooterRows tbl (int footer-size)))

(when width (.setTotalWidth tbl (float width)))
(when width-percent (.setWidthPercentage tbl (float width-percent)))

(if bounding-box
(if-not widths
(throw (new Exception "widths must be non-nil when bounding-box is used in a pdf-table"))
(let [[x y] bounding-box]
(.setWidthPercentage tbl (float-array widths) (make-section [:rectangle x y]))))
(if widths
(.setWidths tbl (float-array widths))))

(doseq [table-event table-events]
(.setTableEvent tbl table-event))

(if spacing-before (.setSpacingBefore tbl (float spacing-before)))
(if spacing-after (.setSpacingAfter tbl (float spacing-after)))

(.setHorizontalAlignment tbl ^int (get-alignment horizontal-align))

(.setKeepTogether tbl (boolean keep-together?))

; these are inverted so the default if not specified matches
; PdfPTable default behaviour
(.setSplitRows tbl (boolean (not no-split-rows?)))
(.setSplitLate tbl (boolean (not no-split-late?)))

(doseq [row rows]
(doseq [column row]
(add-pdf-table-cell tbl (merge meta (when (= false cell-border) {:set-border []})) column)))

tbl)))

(defn load-image [img-data base64]
(cond
Expand Down

0 comments on commit 95b4974

Please sign in to comment.