Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ body:
id: gpdf-version
attributes:
label: gpdf Version
placeholder: "v1.0.5"
placeholder: "v1.0.7"
validations:
required: true

Expand Down
22 changes: 21 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/).

## [Unreleased]

## [1.0.7] - 2026-04-29

### Added
- Borders and backgrounds for tables, images, and boxes
- Builder: `Border(opts...)` with `BorderWidth`, `BorderWidths`, `BorderColor`, `BorderLine`; applied via `WithTableBorder`, `WithImageBorder`, `WithBoxBorder`, `WithTextBorder`, plus `WithImageBackground` / table & box background options
- JSON / GoTemplate schema: `SchemaBorder { width, widths, color, style }`; `image.border` / `image.background`; `table.border` / `table.cellBorder` / `table.borderCollapse` / `table.background`
- Layout engine support: borders participate in box-model sizing and pagination (`document/layout/{block,engine,paging}.go`)
- Example tests: `_examples/{builder,json,gotemplate}/35_border_test.go` with shared golden

## [1.0.6] - 2026-04-20

### Added
- Minimum display size constraints for images and QR codes — raise layout overflow to the next page when the target box would render below `minWidth` / `minHeight` (#19)
- Builder: `MinDisplayWidth(v)` / `MinDisplayHeight(v)` options on Image and QR
- JSON / GoTemplate schema: `image.minWidth` / `image.minHeight` / `qr.minWidth` / `qr.minHeight`
- Layout engine propagates overflow when the constraint is violated (`document/layout/block.go`)
- Example tests: `_examples/{builder,json,gotemplate}/34_image_min_size_test.go` with shared golden

## [1.0.5] - 2026-04-19

### Fixed
Expand Down Expand Up @@ -132,7 +150,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
- Reed-Solomon coefficient order in QR code encoder
- binary.Write return value handling for errcheck lint

[Unreleased]: https://github.com/gpdf-dev/gpdf/compare/v1.0.5...HEAD
[Unreleased]: https://github.com/gpdf-dev/gpdf/compare/v1.0.7...HEAD
[1.0.7]: https://github.com/gpdf-dev/gpdf/compare/v1.0.6...v1.0.7
[1.0.6]: https://github.com/gpdf-dev/gpdf/compare/v1.0.5...v1.0.6
[1.0.5]: https://github.com/gpdf-dev/gpdf/compare/v1.0.4...v1.0.5
[1.0.4]: https://github.com/gpdf-dev/gpdf/compare/v1.0.3...v1.0.4
[1.0.3]: https://github.com/gpdf-dev/gpdf/compare/v1.0.2...v1.0.3
Expand Down
134 changes: 132 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![Go Reference](https://pkg.go.dev/badge/github.com/gpdf-dev/gpdf.svg)](https://pkg.go.dev/github.com/gpdf-dev/gpdf)
[![CI](https://github.com/gpdf-dev/gpdf/actions/workflows/check-code.yml/badge.svg)](https://github.com/gpdf-dev/gpdf/actions/workflows/check-code.yml)
![coverage](https://img.shields.io/badge/coverage-85.8%25-green)
![coverage](https://img.shields.io/badge/coverage-84.4%25-green)
[![Go Report Card](https://goreportcard.com/badge/github.com/gpdf-dev/gpdf)](https://goreportcard.com/report/github.com/gpdf-dev/gpdf)
[![Go Version](https://img.shields.io/badge/Go-%3E%3D1.22-blue)](https://go.dev/)
[![Website](https://img.shields.io/badge/Website-gpdf.dev-blue)](https://gpdf.dev/)
Expand All @@ -18,7 +18,8 @@ A pure Go, zero-dependency PDF generation library with a layered architecture an
- **12-column grid system** — Bootstrap-style responsive layout
- **TrueType font support** — embed custom fonts with subsetting
- **CJK ready** — full CJK text support from day one
- **Tables** — headers, column widths, striped rows, vertical alignment
- **Tables** — headers, column widths, striped rows, vertical alignment, outer + per-cell borders
- **Borders & backgrounds** — apply to tables, images, and box containers (solid / dashed / dotted)
- **Headers & Footers** — consistent across all pages with page numbers
- **Lists** — bulleted and numbered lists
- **QR codes** — pure Go QR code generation with error correction levels
Expand Down Expand Up @@ -297,6 +298,40 @@ c.Table(
)
```

Table borders — outer frame, per-cell grid, or both:

```go
outer := template.Border(
template.BorderWidth(document.Pt(1)),
template.BorderColor(pdf.RGBHex(0x1A237E)),
)
grid := template.Border(
template.BorderWidth(document.Pt(0.5)),
template.BorderColor(pdf.Gray(0.5)),
)

// Outer frame only
c.Table(header, rows, template.WithTableBorder(outer))

// Cell grid only (Excel-style grid lines)
c.Table(header, rows, template.WithTableCellBorder(grid))

// Outer frame + cell grid + background
c.Table(header, rows,
template.WithTableBorder(outer),
template.WithTableCellBorder(grid),
template.WithTableBackground(pdf.RGBHex(0xFAFAFA)),
)

// Dashed cell grid
dashed := template.Border(
template.BorderWidth(document.Pt(0.75)),
template.BorderColor(pdf.RGBHex(0x0D47A1)),
template.BorderLine(document.BorderDashed),
)
c.Table(header, rows, template.WithTableCellBorder(dashed))
```

### Images

Embed JPEG and PNG images with optional fit options:
Expand Down Expand Up @@ -327,6 +362,38 @@ page.AutoRow(func(r *template.RowBuilder) {
})
```

Image with a border and a solid backdrop (handy for transparent PNGs):

```go
c.Image(pngData,
template.FitWidth(document.Mm(60)),
template.WithImageBorder(template.Border(
template.BorderWidth(document.Pt(2)),
template.BorderColor(pdf.RGBHex(0xE53935)),
)),
template.WithImageBackground(pdf.RGBHex(0xFFF8E1)),
)
```

### Boxes

Wrap arbitrary column content in a styled rectangular container with a
border, fill, and padding:

```go
c.Box(func(c *template.ColBuilder) {
c.Text("Inside a box")
c.Text("with two lines of body copy")
},
template.WithBoxBorder(template.Border(
template.BorderWidth(document.Pt(1)),
template.BorderColor(pdf.RGBHex(0x1A237E)),
)),
template.WithBoxBackground(pdf.RGBHex(0xE8EAF6)),
template.WithBoxPadding(document.UniformEdges(document.Mm(4))),
)
```

### Lines & Spacers

Horizontal rules with color and thickness:
Expand Down Expand Up @@ -558,6 +625,27 @@ doc, err := template.FromJSON(schema, nil)
data, _ := doc.Generate()
```

Tables and images accept the same border / background keys as the builder API:

```jsonc
{"span": 12, "table": {
"header": ["Name", "Age", "City"],
"rows": [["Alice","30","Tokyo"], ["Bob","25","NYC"]],
"border": {"width": "1pt", "color": "#1A237E"}, // outer frame
"cellBorder": {"width": "0.5pt", "color": "gray(0.5)", "style": "dashed"}, // grid lines
"background": "#FAFAFA"
}}

{"span": 12, "image": {
"src": "...",
"width": "60mm",
"border": {"widths": ["2pt","2pt","2pt","2pt"], "color": "#E53935"},
"background": "#FFF8E1"
}}
```

`style` accepts `solid` (default), `dashed`, `dotted`, or `none`. Use `widths` for per-edge `[top, right, bottom, left]` or `width` for a uniform value.

### Go Template Integration

Use Go templates with JSON schema for dynamic content:
Expand Down Expand Up @@ -788,6 +876,7 @@ doc.Render(f)
| `c.TotalPages(opts...)` | Add total page count |
| `c.Line(opts...)` | Add a horizontal line |
| `c.Spacer(height)` | Add vertical space |
| `c.Box(fn, opts...)` | Wrap content in a styled box (border / fill / padding) |

### Page-Level Content

Expand Down Expand Up @@ -844,13 +933,54 @@ doc.Render(f)
| `template.TableHeaderStyle(opts...)` | Style the header row |
| `template.TableStripe(color)` | Set alternating row color |
| `template.TableCellVAlign(align)` | Set cell vertical alignment (Top/Middle/Bottom) |
| `template.WithTableBorder(spec)` | Draw an outer border around the table |
| `template.WithTableCellBorder(spec)` | Draw the same border around every header + body cell (grid lines) |
| `template.WithTableBorderCollapse(b)` | Mark adjacent cell borders for collapsing |
| `template.WithTableBackground(color)` | Fill the table's outer box |

### Image Options

| Option | Description |
|---|---|
| `template.FitWidth(value)` | Scale to fit width (keeps aspect ratio) |
| `template.FitHeight(value)` | Scale to fit height (keeps aspect ratio) |
| `template.MinDisplayWidth(v)` | Overflow to next page if shrunk below this width |
| `template.MinDisplayHeight(v)` | Overflow to next page if shrunk below this height |
| `template.WithImageBorder(spec)` | Draw a border around the image |
| `template.WithImageBackground(color)` | Fill the image's box (useful for transparent PNGs) |

### Box Options

| Option | Description |
|---|---|
| `template.WithBoxBorder(spec)` | Draw a border around the box |
| `template.WithBoxBackground(color)` | Fill the box |
| `template.WithBoxPadding(edges)` | Inner spacing |
| `template.WithBoxMargin(edges)` | Outer spacing |
| `template.WithBoxWidth(value)` | Explicit width |
| `template.WithBoxHeight(value)` | Explicit height |

### Border Helpers

Build a `BorderSpec` once and apply it with `WithTableBorder`,
`WithTableCellBorder`, `WithImageBorder`, `WithBoxBorder`, or
`WithTextBorder`:

```go
spec := template.Border(
template.BorderWidth(document.Pt(1)), // uniform edges
template.BorderColor(pdf.RGBHex(0x1A237E)),
template.BorderLine(document.BorderSolid), // BorderSolid | BorderDashed | BorderDotted
)
```

| Option | Description |
|---|---|
| `template.Border(opts...)` | Build a `BorderSpec` (default 1pt black solid) |
| `template.BorderWidth(v)` | Uniform width on all four edges |
| `template.BorderWidths(t, r, b, l)` | Per-edge widths in CSS order |
| `template.BorderColor(c)` | Edge color |
| `template.BorderLine(style)` | Line style: `BorderSolid`, `BorderDashed`, `BorderDotted`, `BorderNone` |

### QR Code Options

Expand Down
Loading