Compare commits

...

23 Commits
3.0.2 ... 3.2.0

Author SHA1 Message Date
Julien Neuhart
2648992a9b adding moar favicons 2019-01-03 16:02:02 +01:00
Julien Neuhart
7bcc3d081e adding liveness section in documentation 2019-01-03 15:56:53 +01:00
Julien Neuhart
affd1c45ca Merge pull request #32 from Peltoche/master
Add a /ping endpoint
2019-01-03 15:37:18 +01:00
Peltoche
8c7458812d Add a /ping endpoint
This endpoint can be used to check the service liveness. It can be used
for the kubernetes liveness and readiness probs.
2019-01-03 15:21:57 +01:00
Julien Neuhart
053908c772 Merge pull request #31 from thecodingmachine/merge-alt
adding PDFtk for merging PDF files < 1.7
2019-01-03 11:10:07 +01:00
Julien Neuhart
d623736f9f rollbacking to debian 9.5 as the 9.6 image has issue with git installation 2019-01-03 11:01:02 +01:00
Julien Neuhart
a3e416ff68 adding PDFtk for merging PDF files < 1.7 2019-01-03 10:06:56 +01:00
Julien Neuhart
8bf207b9f7 improving contributing doc 2018-12-14 16:13:52 +01:00
Julien Neuhart
e1520d5e7e Merge branch 'master' of https://github.com/thecodingmachine/gotenberg 2018-12-14 15:59:59 +01:00
Julien Neuhart
4f89c9f7c6 updating logo and documentation 2018-12-14 15:59:45 +01:00
Ben Davies
d34fb92211 docs: cURL write to a file instead of stdout (#25) 2018-12-14 09:28:18 +01:00
Julien Neuhart
3f7b006d16 fixing docs generation: was adding Dockerfile too.. 2018-12-14 09:15:51 +01:00
Julien Neuhart
a15cf33691 Dockerfiles: removing useless labels. Docs: now generating with Docker. Travis: publishing done with make 2018-12-14 09:13:04 +01:00
Julien Neuhart
4c1699df6c webhook: resulting file was deleted because of defer outside of goroutine 2018-12-13 18:15:28 +01:00
Julien Neuhart
404535c512 fixing/simplifying godoc 2018-12-13 17:06:29 +01:00
Julien Neuhart
2cedcecc38 adding concurrent testing 2018-12-13 14:46:59 +01:00
Julien Neuhart
ba7b02d8d4 fixing various typos in documentation 2018-12-12 17:44:27 +01:00
Julien Neuhart
6aa3c16646 fixing golang client README 2018-12-12 16:44:32 +01:00
Julien Neuhart
5a03e17e00 fixing introduction in documentation 2018-12-12 16:37:36 +01:00
Julien Neuhart
417d145b43 fixing documentation typos 2018-12-12 16:36:21 +01:00
Julien Neuhart
e5636a2afa adding .txt and .rtf files support (#20) 2018-12-12 16:34:34 +01:00
Julien Neuhart
5291d2d129 disabling pdfcpu logs (#22) 2018-12-12 16:24:54 +01:00
Julien Neuhart
c6f6a87499 now using latest version of unoconv, allowing to specify paper size and orientation + updating go client (#24) 2018-12-12 16:16:35 +01:00
70 changed files with 3097 additions and 615 deletions

View File

@@ -1,6 +1,6 @@
# Contributing # Contributing
Hi! Thank your for considering contributing to Gotenberg. You'll Hi! Thank you for considering contributing to Gotenberg. You'll
find below useful information about how to contribute to the Gotenberg project. find below useful information about how to contribute to the Gotenberg project.
## Contributing code ## Contributing code
@@ -8,8 +8,9 @@ find below useful information about how to contribute to the Gotenberg project.
### Install from sources ### Install from sources
1. Install and run the latest version of Docker 1. Install and run the latest version of Docker
2. Fork this repository 2. Verify your Go version (>= 1.11)
3. Clone it to your local Go environment (requires *Go* >= 1.11) 3. Fork this repository
4. Clone it outside of your `GOPATH` (we're using Go modules)
### Working with git ### Working with git

View File

@@ -22,4 +22,4 @@ jobs:
script: make tests script: make tests
- stage: publish - stage: publish
if: tag IS present if: tag IS present
script: ./scripts/publish.sh $TRAVIS_TAG $DOCKER_USER $DOCKER_PASS script: make publish VERSION=$TRAVIS_TAG DOCKER_USER=$DOCKER_USER DOCKER_PASSWORD=$DOCKER_PASS

View File

@@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2018 TheCodingMachine Copyright (c) 2019 TheCodingMachine
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,9 +1,12 @@
VERSION=snapshot
GOLANG_VERSION=1.11.2 GOLANG_VERSION=1.11.2
VERSION=snapshot
DOCKER_USER=
DOCKER_PASSWORD=
# generate documentation. # generate documentation.
doc: doc:
static-docs --in build/docs --out docs --theme gotenberg --title Gotenberg --subtitle "A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF." docker build --build-arg GOLANG_VERSION=$(GOLANG_VERSION) -t thecodingmachine/gotenberg:docs -f build/docs/Dockerfile .
docker run --rm -it -v "$(PWD):/docs" thecodingmachine/gotenberg:docs
# gofmt and goimports all go files. # gofmt and goimports all go files.
fmt: fmt:
@@ -28,3 +31,7 @@ image:
# start the API using previously built Docker image. # start the API using previously built Docker image.
gotenberg: gotenberg:
docker run -it --rm -p "3000:3000" thecodingmachine/gotenberg:$(VERSION) docker run -it --rm -p "3000:3000" thecodingmachine/gotenberg:$(VERSION)
# publish Gotenberg images according to version.
publish:
./scripts/publish.sh $(GOLANG_VERSION) $(VERSION) $(DOCKER_USER) $(DOCKER_PASSWORD)

View File

@@ -1,8 +1,9 @@
<p align="center"> <p align="center">
<img src="https://user-images.githubusercontent.com/8983173/49701110-4c8b9280-fbe8-11e8-895c-a4b9c7d2515b.png" alt="Gotenberg logo" width="250" height="250" /> <img src="https://user-images.githubusercontent.com/8983173/50009948-84b01e00-ffb8-11e8-850b-fc240382c626.png" alt="Gotenberg logo" width="250" height="250" />
</p> </p>
<h3 align="center">Gotenberg</h3> <h3 align="center">Gotenberg</h3>
<p align="center">A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.</p> <p align="center">A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.</p>
<p align="center"><a href="https://thecodingmachine.github.io/gotenberg">Documentation</a> &#183; <a href="/.github/CONTRIBUTING.md">Contributing</a></p>
--- ---
@@ -11,7 +12,7 @@ At TheCodingMachine, we build a lot of web applications (intranets, extranets an
## Features ## Features
* HTML and Markdown conversions using Google Chrome headless * HTML and Markdown conversions using Google Chrome headless
* Office conversions (.docx, .doc, .odt, .pptx, .ppt, .odp and so on) using [unoconv](https://github.com/dagwieers/unoconv) * Office conversions (.txt, .rtf, .docx, .doc, .odt, .pptx, .ppt, .odp and so on) using [unoconv](https://github.com/dagwieers/unoconv)
* Performance :zap:: Google Chrome and Libreoffice (unoconv) started once in the background thanks to PM2 * Performance :zap:: Google Chrome and Libreoffice (unoconv) started once in the background thanks to PM2
* Failure prevention :broken_heart:: PM2 automatically restarts previous processes if they fail * Failure prevention :broken_heart:: PM2 automatically restarts previous processes if they fail
* Assets :package:: send your header, footer, images, fonts, stylesheets and so on for converting your HTML and Markdown to beaufitul PDFs! * Assets :package:: send your header, footer, images, fonts, stylesheets and so on for converting your HTML and Markdown to beaufitul PDFs!

View File

@@ -1,6 +1,4 @@
FROM debian:stretch-slim FROM debian:9.5-slim
LABEL authors="Julien Neuhart <j.neuhart@thecodingmachine.com>"
# |-------------------------------------------------------------------------- # |--------------------------------------------------------------------------
# | Common libraries # | Common libraries
@@ -11,7 +9,7 @@ LABEL authors="Julien Neuhart <j.neuhart@thecodingmachine.com>"
RUN echo "deb http://httpredir.debian.org/debian/ stretch main contrib non-free" > /etc/apt/sources.list &&\ RUN echo "deb http://httpredir.debian.org/debian/ stretch main contrib non-free" > /etc/apt/sources.list &&\
apt-get update &&\ apt-get update &&\
apt-get install -y curl wget apt-get install -y curl wget python3-pip
# |-------------------------------------------------------------------------- # |--------------------------------------------------------------------------
# | PM2 # | PM2
@@ -39,7 +37,20 @@ RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add
# | Unoconv # | Unoconv
# |-------------------------------------------------------------------------- # |--------------------------------------------------------------------------
# | # |
# | Installs MS fonts and unoconv for Office documents conversions. # | Installs unoconv and LibreOffice for Office documents conversions.
# | # |
RUN apt-get -y install ttf-mscorefonts-installer unoconv RUN pip3 install unoconv &&\
# https://github.com/nextcloud/docker/issues/380
mkdir -p /usr/share/man/man1mkdir -p /usr/share/man/man1 &&\
apt-get -y install libreoffice
# |--------------------------------------------------------------------------
# | PDFtk
# |--------------------------------------------------------------------------
# |
# | Installs PDFtk as an alternative to pdfcpu for merging PDFs.
# | https://github.com/thecodingmachine/gotenberg/issues/29
# |
RUN apt-get -y install pdftk

24
build/docs/Dockerfile Normal file
View File

@@ -0,0 +1,24 @@
ARG GOLANG_VERSION
FROM golang:${GOLANG_VERSION}-stretch
# |--------------------------------------------------------------------------
# | static
# |--------------------------------------------------------------------------
# |
# | Installs the static site anti-framework general-purpose library,
# | purpose-built commands for various domains.
# |
RUN go get github.com/apex/static/cmd/static-docs
# |--------------------------------------------------------------------------
# | Final touch
# |--------------------------------------------------------------------------
# |
# | Last instructions of this build.
# |
WORKDIR /docs
CMD [ "static-docs", "--in", "build/docs/content", "--out", "docs", "--theme", "gotenberg", "--title", "Gotenberg", "--subtitle", "A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF." ]

View File

@@ -5,7 +5,7 @@ title: Introduction
[Gotenberg](https://github.com/thecodingmachine/gotenberg/) is a Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF. [Gotenberg](https://github.com/thecodingmachine/gotenberg/) is a Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.
* HTML and Markdown conversions using Google Chrome headless * HTML and Markdown conversions using Google Chrome headless
* Office conversions (.docx, .doc, .odt, .pptx, .ppt, .odp and so on) using [unoconv](https://github.com/dagwieers/unoconv) * Office conversions (.txt, .rtf, .docx, .doc, .odt, .pptx, .ppt, .odp and so on) using [unoconv](https://github.com/dagwieers/unoconv)
* Performance: Google Chrome and Libreoffice (unoconv) started once in the background thanks to PM2 * Performance: Google Chrome and Libreoffice (unoconv) started once in the background thanks to PM2
* Failure prevention: PM2 automatically restarts previous processes if they fail * Failure prevention: PM2 automatically restarts previous processes if they fail
* Assets: send your header, footer, images, fonts, stylesheets and so on for converting your HTML and Markdown to beaufitul PDFs! * Assets: send your header, footer, images, fonts, stylesheets and so on for converting your HTML and Markdown to beaufitul PDFs!

View File

@@ -33,7 +33,7 @@ $ curl --request POST \
--url http://localhost:3000/convert/html \ --url http://localhost:3000/convert/html \
--header 'Content-Type: multipart/form-data' \ --header 'Content-Type: multipart/form-data' \
--form files=@index.html \ --form files=@index.html \
> result.pdf -o result.pdf
``` ```
### Go ### Go
@@ -43,9 +43,7 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.HTMLRequest{ req, _ := gotenberg.NewHTMLRequest("index.html")
IndexFilePath: "index.html",
}
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }
@@ -109,7 +107,7 @@ $ curl --request POST \
--form files=@index.html \ --form files=@index.html \
--form files=@header.html \ --form files=@header.html \
--form files=@footer.html \ --form files=@footer.html \
> result.pdf -o result.pdf
``` ```
### Go ### Go
@@ -119,13 +117,9 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.HTMLRequest{ req, _ := gotenberg.NewHTMLRequest("index.html")
IndexFilePath: "index.html", req.SetHeader("header.html")
Options: &gotenberg.HTMLOptions{ req.SetFooter("footer.html")
HeaderFilePath: "header.html",
FooterFilePath: "footer.html",
},
}
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }
@@ -203,7 +197,7 @@ $ curl --request POST \
--form files=@style.css \ --form files=@style.css \
--form files=@img.png \ --form files=@img.png \
--form files=@font.woff \ --form files=@font.woff \
> result.pdf -o result.pdf
``` ```
### Go ### Go
@@ -213,14 +207,12 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.HTMLRequest{ req, _ := gotenberg.NewHTMLRequest("index.html")
IndexFilePath: "index.html", req.SetAssets([]string{
AssetFilePaths: []string{ "font.woff",
"style.css", "img.gif",
"img.png", "style.css",
"font.woff", })
},
}
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }
@@ -269,7 +261,7 @@ $ curl --request POST \
--form marginLeft=0 \ --form marginLeft=0 \
--form marginRight=0 \ --form marginRight=0 \
--form landscape=true \ --form landscape=true \
> result.pdf -o result.pdf
``` ```
### Go ### Go
@@ -279,14 +271,10 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.HTMLRequest{ req, _ := gotenberg.NewHTMLRequest("index.html")
IndexFilePath: "index.html", req.SetPaperSize(gotenberg.A4)
Options: &gotenberg.HTMLOptions{ req.SetMargins(gotenberg.NoMargins)
PaperSize: gotenberg.A4, req.SetLandscape(true)
PaperMargins: gotenberg.NoMargins,
Landscape: true
},
}
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }

View File

@@ -36,7 +36,7 @@ $ curl --request POST \
--header 'Content-Type: multipart/form-data' \ --header 'Content-Type: multipart/form-data' \
--form files=@index.html \ --form files=@index.html \
--form files=@file.md \ --form files=@file.md \
> result.pdf -o result.pdf
``` ```
### Go ### Go
@@ -46,12 +46,7 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.MarkdownRequest{ req, _ := gotenberg.NewMarkdownRequest("index.html", []string{"file.md"})
IndexFilePath: "index.html",
MarkdownFilePaths: []string{
"file.md",
},
}
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }

View File

@@ -10,6 +10,8 @@ It accepts `POST` requests with a `multipart/form-data` Content-Type.
You may send one or more Office documents. Following file extensions are accepted: You may send one or more Office documents. Following file extensions are accepted:
* `.txt`
* `.rtf`
* `.doc` * `.doc`
* `.docx` * `.docx`
* `.odt` * `.odt`
@@ -34,7 +36,7 @@ $ curl --request POST \
--header 'Content-Type: multipart/form-data' \ --header 'Content-Type: multipart/form-data' \
--form files=@document.docx \ --form files=@document.docx \
--form files=@document2.docx \ --form files=@document2.docx \
> result.pdf -o result.pdf
``` ```
### Go ### Go
@@ -44,12 +46,7 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.OfficeRequest{ req, _ := gotenberg.NewOfficeRequest([]string{"document.docx", "document2.docx"})
FilePaths: []string{
"document.docx",
"document2.docx",
},
}
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }
@@ -72,6 +69,61 @@ $dirPath = "/foo";
$filename = $client->store($request, $dirPath); $filename = $client->store($request, $dirPath);
``` ```
## Paper size and orientation
You may also customize the resulting PDF format.
By default, it will be rendered with `A4` size and `portrait` orientation.
> Paper size has to be provided in `inches`.
> Also, you have to set both `paperWidth` and `paperHeight`.
### cURL
```bash
$ curl --request POST \
--url http://localhost:3000/convert/office \
--header 'Content-Type: multipart/form-data' \
--form files=@document.docx \
--form paperWidth=8.27 \
--form paperHeight=11.27 \
--form landscape=true \
-o result.pdf
```
### Go
```golang
import "github.com/thecodingmachine/gotenberg/pkg"
func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req, _ := gotenberg.NewOfficeRequest([]string{"document.docx"})
req.SetPaperSize(gotenberg.A4)
req.SetLandscape(true)
dest := "result.pdf"
c.Store(req, dest)
}
```
### PHP
```php
use TheCodingMachine\Gotenberg\Client;
use TheCodingMachine\Gotenberg\DocumentFactory;
use TheCodingMachine\Gotenberg\OfficeRequest;
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
$files = [
DocumentFactory::makeFromPath('document.docx', 'document.docx'),
];
$request = new OfficeRequest($files);
$request->setPaperSize(Request::A4);
$request->setLandscape(true);
$dirPath = "/foo";
$filename = $client->store($request, $dirPath);
```
## Fonts ## Fonts
By default, only `ttf-mscorefonts` fonts are installed. By default, only `ttf-mscorefonts` fonts are installed.

View File

@@ -19,7 +19,7 @@ $ curl --request POST \
--header 'Content-Type: multipart/form-data' \ --header 'Content-Type: multipart/form-data' \
--form files=@file.pdf \ --form files=@file.pdf \
--form files=@file2.pdf \ --form files=@file2.pdf \
> result.pdf -o result.pdf
``` ```
### Go ### Go
@@ -29,12 +29,7 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.MergeRequest{ req, _ := gotenberg.NewMergeRequest([]string{"file.pdf", "file2.pdf"})
FilePaths: []string{
"file.pdf",
"file2.pdf",
},
}
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }

View File

@@ -28,14 +28,10 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.HTMLRequest{ req, _ := gotenberg.NewHTMLRequest("index.html")
IndexFilePath: "index.html", req.SetWebhookURL("http://myapp.com/webhook/")
Options: &gotenberg.HTMLOptions{
WebHookURL: "http://myapp.com/webhook/",
},
}
dest := "result.pdf" dest := "result.pdf"
resp, err := c.Post(req) resp, _ := c.Post(req)
} }
``` ```

View File

@@ -0,0 +1,11 @@
---
title: Liveness
---
Gotenberg provides the endpoint `/ping` for checking the API availability with
a simple `GET` request.
This feature is especially useful for liveness/readiness probes in Kubernetes:
* [Pod lifecycle](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes)
* [Configure Liveness and Readiness Probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/)

View File

@@ -2,8 +2,6 @@ ARG GOLANG_VERSION
FROM golang:${GOLANG_VERSION}-stretch FROM golang:${GOLANG_VERSION}-stretch
LABEL authors="Julien Neuhart <j.neuhart@thecodingmachine.com>"
# |-------------------------------------------------------------------------- # |--------------------------------------------------------------------------
# | GolangCI-Lint # | GolangCI-Lint
# |-------------------------------------------------------------------------- # |--------------------------------------------------------------------------

View File

@@ -4,8 +4,6 @@ FROM golang:${GOLANG_VERSION}-stretch AS golang
FROM thecodingmachine/gotenberg:base FROM thecodingmachine/gotenberg:base
LABEL authors="Julien Neuhart <j.neuhart@thecodingmachine.com>"
# |-------------------------------------------------------------------------- # |--------------------------------------------------------------------------
# | Common libraries # | Common libraries
# |-------------------------------------------------------------------------- # |--------------------------------------------------------------------------

View File

@@ -22,3 +22,4 @@ go build -o /usr/local/bin/gotenberg cmd/gotenberg/main.go
gotenberg & gotenberg &
sleep 10 sleep 10
go test -race -cover -covermode=atomic github.com/thecodingmachine/gotenberg/pkg go test -race -cover -covermode=atomic github.com/thecodingmachine/gotenberg/pkg
sleep 5 # allows Gotenberg to remove generated files (concurrent requests).

View File

@@ -3,8 +3,19 @@
<meta http-equiv="x-ua-compatible" content="ie=edge"/> <meta http-equiv="x-ua-compatible" content="ie=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/> <meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Gotenberg · A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.</title> <title>Gotenberg · A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.</title>
<link rel="apple-touch-icon-precomposed" sizes="57x57" href="theme/gotenberg/img/apple-touch-icon-57x57.png"/>
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="theme/gotenberg/img/apple-touch-icon-114x114.png"/>
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="theme/gotenberg/img/apple-touch-icon-72x72.png"/>
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="theme/gotenberg/img/apple-touch-icon-144x144.png"/>
<link rel="apple-touch-icon-precomposed" sizes="60x60" href="theme/gotenberg/img/apple-touch-icon-60x60.png"/>
<link rel="apple-touch-icon-precomposed" sizes="120x120" href="theme/gotenberg/img/apple-touch-icon-120x120.png"/>
<link rel="apple-touch-icon-precomposed" sizes="76x76" href="theme/gotenberg/img/apple-touch-icon-76x76.png"/>
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="theme/gotenberg/img/apple-touch-icon-152x152.png"/>
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-196x196.png" sizes="196x196"/>
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-96x96.png" sizes="96x96"/>
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-32x32.png" sizes="32x32"/> <link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-32x32.png" sizes="32x32"/>
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-16x16.png" sizes="16x16"/> <link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-16x16.png" sizes="16x16"/>
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-128.png" sizes="128x128"/>
<link rel="stylesheet" href="theme/gotenberg/css/index.css"/> <link rel="stylesheet" href="theme/gotenberg/css/index.css"/>
</head> </head>
<body> <body>
@@ -12,7 +23,7 @@
<div class="Container"> <div class="Container">
<div class="Header"> <div class="Header">
<div class="Title center"> <div class="Title center">
<img src="https://user-images.githubusercontent.com/8983173/49701110-4c8b9280-fbe8-11e8-895c-a4b9c7d2515b.png" alt="Gotenberg logo" width="250" height="250"/> <img src="https://user-images.githubusercontent.com/8983173/50009948-84b01e00-ffb8-11e8-850b-fc240382c626.png" alt="Gotenberg logo" width="250" height="250"/>
<span class="text">Gotenberg</span> <span class="text">Gotenberg</span>
<span class="subtext">A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.</span> <span class="subtext">A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.</span>
</div> </div>
@@ -54,6 +65,10 @@
<a href="#scalability">Scalability</a> <a href="#scalability">Scalability</a>
</div> </div>
<div class="item">
<a href="#liveness">Liveness</a>
</div>
<div class="item"> <div class="item">
<a href="#links">Links</a> <a href="#links">Links</a>
</div> </div>
@@ -71,7 +86,7 @@
<ul> <ul>
<li>HTML and Markdown conversions using Google Chrome headless</li> <li>HTML and Markdown conversions using Google Chrome headless</li>
<li>Office conversions (.docx, .doc, .odt, .pptx, .ppt, .odp and so on) using <a href="https://github.com/dagwieers/unoconv">unoconv</a></li> <li>Office conversions (.txt, .rtf, .docx, .doc, .odt, .pptx, .ppt, .odp and so on) using <a href="https://github.com/dagwieers/unoconv">unoconv</a></li>
<li>Performance: Google Chrome and Libreoffice (unoconv) started once in the background thanks to PM2</li> <li>Performance: Google Chrome and Libreoffice (unoconv) started once in the background thanks to PM2</li>
<li>Failure prevention: PM2 automatically restarts previous processes if they fail</li> <li>Failure prevention: PM2 automatically restarts previous processes if they fail</li>
<li>Assets: send your header, footer, images, fonts, stylesheets and so on for converting your HTML and Markdown to beaufitul PDFs!</li> <li>Assets: send your header, footer, images, fonts, stylesheets and so on for converting your HTML and Markdown to beaufitul PDFs!</li>
@@ -105,7 +120,7 @@
</span><span class="w"> </span><span class="w">
</span><span class="w"> </span>gotenberg<span class="p">:</span><span class="w"> </span><span class="w"> </span>gotenberg<span class="p">:</span><span class="w">
</span><span class="w"> </span>image<span class="p">:</span><span class="w"> </span>thecodingmachine/gotenberg<span class="p">:</span><span class="m">3</span><span class="w"> </span><span class="w"> </span>image<span class="p">:</span><span class="w"> </span>thecodingmachine/gotenberg<span class="p">:</span><span class="m">3</span><span class="w">
</span><span class="w"></span></pre> </span></pre>
<blockquote> <blockquote>
<p>The API will be available under <code>gotenberg:3000</code> in your Docker Compose network.</p> <p>The API will be available under <code>gotenberg:3000</code> in your Docker Compose network.</p>
@@ -157,15 +172,15 @@ which will be converted to PDF.</p>
<p>For instance:</p> <p>For instance:</p>
<pre class="chroma"><span class="cp">&lt;!doctype html&gt;</span> <pre class="chroma"><span class="cp">&lt;!doctype html&gt;</span>
<span class="p">&lt;</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;en&#34;</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;en&#34;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">head</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;utf-8&#34;</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;utf-8&#34;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">title</span><span class="p"></span><span class="p">&gt;</span>My PDF<span class="p">&lt;</span><span class="p">/</span><span class="nt">title</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>My PDF<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">head</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">body</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">h1</span><span class="p"></span><span class="p">&gt;</span>Hello world!<span class="p">&lt;</span><span class="p">/</span><span class="nt">h1</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>Hello world!<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">body</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">html</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.basic.c_url" href="#html.basic.c_url"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.basic.c_url" href="#html.basic.c_url">
@@ -176,7 +191,7 @@ which will be converted to PDF.</p>
</span><span class="se"></span> --url http://localhost:3000/convert/html <span class="se">\ </span><span class="se"></span> --url http://localhost:3000/convert/html <span class="se">\
</span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\ </span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html <span class="se">\ </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html <span class="se">\
</span><span class="se"></span> &gt; result.pdf </span><span class="se"></span> -o result.pdf
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.basic.go" href="#html.basic.go"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.basic.go" href="#html.basic.go">
@@ -185,13 +200,11 @@ which will be converted to PDF.</p>
<pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span> <pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span>
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span> <span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLRequest</span><span class="p">{</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewHTMLRequest</span><span class="p">(</span><span class="s">&#34;index.html&#34;</span><span class="p">)</span>
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">&#34;index.html&#34;</span><span class="p">,</span>
<span class="p">}</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span> <span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span> <span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
</pre> </pre>
@@ -199,16 +212,16 @@ which will be converted to PDF.</p>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3> </a>PHP</h3>
<pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client; <pre class="chroma">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory; use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\HTMLRequest; use TheCodingMachine\Gotenberg\HTMLRequest;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client()); $client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;); $index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;);
</span><span class="x">$request = new HTMLRequest($index); $request = new HTMLRequest($index);
</span><span class="x">$dirPath = &#34;/foo&#34;; $dirPath = &#34;/foo&#34;;
</span><span class="x">$filename = $client-&gt;store($request, $dirPath); $filename = $client-&gt;store($request, $dirPath);
</span><span class="x"></span></pre> </pre>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.header_and_footer" href="#html.header_and_footer"> <h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.header_and_footer" href="#html.header_and_footer">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
@@ -219,21 +232,21 @@ Respectively, a file named <code>header.html</code> and <code>footer.html</code>
<p>Each of them <strong>has to be a complete HTML document</strong>:</p> <p>Each of them <strong>has to be a complete HTML document</strong>:</p>
<pre class="chroma"><span class="p">&lt;</span><span class="nt">html</span><span class="p"></span><span class="p">&gt;</span> <pre class="chroma"><span class="p">&lt;</span><span class="nt">html</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">head</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">style</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">style</span><span class="p">&gt;</span>
<span class="nt">body</span> <span class="p">{</span> <span class="nt">body</span> <span class="p">{</span>
<span class="k">font-size</span><span class="p">:</span> <span class="mi">8</span><span class="kt">rem</span><span class="p">;</span> <span class="k">font-size</span><span class="p">:</span> <span class="mi">8</span><span class="kt">rem</span><span class="p">;</span>
<span class="k">margin</span><span class="p">:</span> <span class="mi">4</span><span class="kt">rem</span> <span class="kc">auto</span><span class="p">;</span> <span class="k">margin</span><span class="p">:</span> <span class="mi">4</span><span class="kt">rem</span> <span class="kc">auto</span><span class="p">;</span>
<span class="p">}</span> <span class="p">}</span>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">style</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">style</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">head</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">body</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">p</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">p</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;pageNumber&#34;</span><span class="p"></span><span class="p">&gt;&lt;</span><span class="p">/</span><span class="nt">span</span><span class="p">&gt;</span> of <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;totalPages&#34;</span><span class="p"></span><span class="p">&gt;&lt;</span><span class="p">/</span><span class="nt">span</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;pageNumber&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">span</span><span class="p">&gt;</span> of <span class="p">&lt;</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">&#34;totalPages&#34;</span><span class="p">&gt;&lt;/</span><span class="nt">span</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">p</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">p</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">body</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">html</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</pre> </pre>
<p>The following classes allow you to inject printing values:</p> <p>The following classes allow you to inject printing values:</p>
@@ -260,7 +273,7 @@ Also, <code>footer.html</code> CSS properties override the ones from <code>heade
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html <span class="se">\ </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@header.html <span class="se">\ </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@header.html <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@footer.html <span class="se">\ </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@footer.html <span class="se">\
</span><span class="se"></span> &gt; result.pdf </span><span class="se"></span> -o result.pdf
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.header_and_footer.go" href="#html.header_and_footer.go"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.header_and_footer.go" href="#html.header_and_footer.go">
@@ -269,17 +282,13 @@ Also, <code>footer.html</code> CSS properties override the ones from <code>heade
<pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span> <pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span>
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span> <span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLRequest</span><span class="p">{</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewHTMLRequest</span><span class="p">(</span><span class="s">&#34;index.html&#34;</span><span class="p">)</span>
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">&#34;index.html&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nf">SetHeader</span><span class="p">(</span><span class="s">&#34;header.html&#34;</span><span class="p">)</span>
<span class="nx">Options</span><span class="p">:</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLOptions</span><span class="p">{</span> <span class="nx">req</span><span class="p">.</span><span class="nf">SetFooter</span><span class="p">(</span><span class="s">&#34;footer.html&#34;</span><span class="p">)</span>
<span class="nx">HeaderFilePath</span><span class="p">:</span> <span class="s">&#34;header.html&#34;</span><span class="p">,</span>
<span class="nx">FooterFilePath</span><span class="p">:</span> <span class="s">&#34;footer.html&#34;</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span> <span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span> <span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
</pre> </pre>
@@ -287,20 +296,20 @@ Also, <code>footer.html</code> CSS properties override the ones from <code>heade
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3> </a>PHP</h3>
<pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client; <pre class="chroma">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory; use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\HTMLRequest; use TheCodingMachine\Gotenberg\HTMLRequest;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client()); $client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;); $index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;);
</span><span class="x">$header = DocumentFactory::makeFromPath(&#39;header.html&#39;, &#39;header.html&#39;); $header = DocumentFactory::makeFromPath(&#39;header.html&#39;, &#39;header.html&#39;);
</span><span class="x">$footer = DocumentFactory::makeFromPath(&#39;footer.html&#39;, &#39;footer.html&#39;); $footer = DocumentFactory::makeFromPath(&#39;footer.html&#39;, &#39;footer.html&#39;);
</span><span class="x">$request = new HTMLRequest($index); $request = new HTMLRequest($index);
</span><span class="x">$request-&gt;setHeader($header); $request-&gt;setHeader($header);
</span><span class="x">$request-&gt;setFooter($footer); $request-&gt;setFooter($footer);
</span><span class="x">$dirPath = &#34;/foo&#34;; $dirPath = &#34;/foo&#34;;
</span><span class="x">$filename = $client-&gt;store($request, $dirPath); $filename = $client-&gt;store($request, $dirPath);
</span><span class="x"></span></pre> </pre>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets" href="#html.assets"> <h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets" href="#html.assets">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
@@ -314,31 +323,31 @@ are on the same level as the <code>index.html</code> file.</p>
<p>In others words, this will work:</p> <p>In others words, this will work:</p>
<pre class="chroma"><span class="cp">&lt;!doctype html&gt;</span> <pre class="chroma"><span class="cp">&lt;!doctype html&gt;</span>
<span class="p">&lt;</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;en&#34;</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;en&#34;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">head</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;utf-8&#34;</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;utf-8&#34;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">title</span><span class="p"></span><span class="p">&gt;</span>My PDF<span class="p">&lt;</span><span class="p">/</span><span class="nt">title</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>My PDF<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">head</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">body</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">h1</span><span class="p"></span><span class="p">&gt;</span>Hello world!<span class="p">&lt;</span><span class="p">/</span><span class="nt">h1</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>Hello world!<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;img.png&#34;</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;img.png&#34;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">body</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">html</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</pre> </pre>
<p>But this wont:</p> <p>But this wont:</p>
<pre class="chroma"><span class="cp">&lt;!doctype html&gt;</span> <pre class="chroma"><span class="cp">&lt;!doctype html&gt;</span>
<span class="p">&lt;</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;en&#34;</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;en&#34;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">head</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;utf-8&#34;</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;utf-8&#34;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">title</span><span class="p"></span><span class="p">&gt;</span>My PDF<span class="p">&lt;</span><span class="p">/</span><span class="nt">title</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>My PDF<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">head</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">body</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">h1</span><span class="p"></span><span class="p">&gt;</span>Hello world!<span class="p">&lt;</span><span class="p">/</span><span class="nt">h1</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">h1</span><span class="p">&gt;</span>Hello world!<span class="p">&lt;/</span><span class="nt">h1</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;/foo/img.png&#34;</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">&#34;/foo/img.png&#34;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">body</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">html</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</pre> </pre>
<p>You may also use <em>remote</em> paths for Google fonts, images and so on.</p> <p>You may also use <em>remote</em> paths for Google fonts, images and so on.</p>
@@ -359,7 +368,7 @@ see to the <a href="#office.fonts">fonts section</a>.</p>
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@style.css <span class="se">\ </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@style.css <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@img.png <span class="se">\ </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@img.png <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@font.woff <span class="se">\ </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@font.woff <span class="se">\
</span><span class="se"></span> &gt; result.pdf </span><span class="se"></span> -o result.pdf
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets.go" href="#html.assets.go"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets.go" href="#html.assets.go">
@@ -368,18 +377,16 @@ see to the <a href="#office.fonts">fonts section</a>.</p>
<pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span> <pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span>
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span> <span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLRequest</span><span class="p">{</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewHTMLRequest</span><span class="p">(</span><span class="s">&#34;index.html&#34;</span><span class="p">)</span>
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">&#34;index.html&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nf">SetAssets</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span>
<span class="nx">AssetFilePaths</span><span class="p">:</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span> <span class="s">&#34;font.woff&#34;</span><span class="p">,</span>
<span class="s">&#34;style.css&#34;</span><span class="p">,</span> <span class="s">&#34;img.gif&#34;</span><span class="p">,</span>
<span class="s">&#34;img.png&#34;</span><span class="p">,</span> <span class="s">&#34;style.css&#34;</span><span class="p">,</span>
<span class="s">&#34;font.woff&#34;</span><span class="p">,</span> <span class="p">})</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span> <span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span> <span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
</pre> </pre>
@@ -387,22 +394,22 @@ see to the <a href="#office.fonts">fonts section</a>.</p>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3> </a>PHP</h3>
<pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client; <pre class="chroma">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory; use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\HTMLRequest; use TheCodingMachine\Gotenberg\HTMLRequest;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client()); $client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;); $index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;);
</span><span class="x">$assets = [ $assets = [
</span><span class="x"> DocumentFactory::makeFromPath(&#39;style.css&#39;, &#39;style.css&#39;), DocumentFactory::makeFromPath(&#39;style.css&#39;, &#39;style.css&#39;),
</span><span class="x"> DocumentFactory::makeFromPath(&#39;img.png&#39;, &#39;img.png&#39;), DocumentFactory::makeFromPath(&#39;img.png&#39;, &#39;img.png&#39;),
</span><span class="x"> DocumentFactory::makeFromPath(&#39;font.woff&#39;, &#39;font.woff&#39;), DocumentFactory::makeFromPath(&#39;font.woff&#39;, &#39;font.woff&#39;),
</span><span class="x">]; ];
</span><span class="x">$request = new HTMLRequest($index); $request = new HTMLRequest($index);
</span><span class="x">$request-&gt;setAssets($assets); $request-&gt;setAssets($assets);
</span><span class="x">$dirPath = &#34;/foo&#34;; $dirPath = &#34;/foo&#34;;
</span><span class="x">$filename = $client-&gt;store($request, $dirPath); $filename = $client-&gt;store($request, $dirPath);
</span><span class="x"></span></pre> </pre>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation" href="#html.paper_size_margins_orientation"> <h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation" href="#html.paper_size_margins_orientation">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
@@ -432,7 +439,7 @@ Also, you have to set both <code>paperWidth</code> and <code>paperHeight</code>.
</span><span class="se"></span> --form <span class="nv">marginLeft</span><span class="o">=</span><span class="m">0</span> <span class="se">\ </span><span class="se"></span> --form <span class="nv">marginLeft</span><span class="o">=</span><span class="m">0</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">marginRight</span><span class="o">=</span><span class="m">0</span> <span class="se">\ </span><span class="se"></span> --form <span class="nv">marginRight</span><span class="o">=</span><span class="m">0</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">landscape</span><span class="o">=</span><span class="nb">true</span> <span class="se">\ </span><span class="se"></span> --form <span class="nv">landscape</span><span class="o">=</span><span class="nb">true</span> <span class="se">\
</span><span class="se"></span> &gt; result.pdf </span><span class="se"></span> -o result.pdf
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation.go" href="#html.paper_size_margins_orientation.go"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation.go" href="#html.paper_size_margins_orientation.go">
@@ -441,18 +448,14 @@ Also, you have to set both <code>paperWidth</code> and <code>paperHeight</code>.
<pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span> <pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span>
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span> <span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLRequest</span><span class="p">{</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewHTMLRequest</span><span class="p">(</span><span class="s">&#34;index.html&#34;</span><span class="p">)</span>
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">&#34;index.html&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nf">SetPaperSize</span><span class="p">(</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">A4</span><span class="p">)</span>
<span class="nx">Options</span><span class="p">:</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLOptions</span><span class="p">{</span> <span class="nx">req</span><span class="p">.</span><span class="nf">SetMargins</span><span class="p">(</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">NoMargins</span><span class="p">)</span>
<span class="nx">PaperSize</span><span class="p">:</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nx">A4</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nf">SetLandscape</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
<span class="nx">PaperMargins</span><span class="p">:</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nx">NoMargins</span><span class="p">,</span>
<span class="nx">Landscape</span><span class="p">:</span> <span class="kc">true</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span> <span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span> <span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
</pre> </pre>
@@ -460,20 +463,20 @@ Also, you have to set both <code>paperWidth</code> and <code>paperHeight</code>.
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3> </a>PHP</h3>
<pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client; <pre class="chroma">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory; use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\HTMLRequest; use TheCodingMachine\Gotenberg\HTMLRequest;
</span><span class="x">use TheCodingMachine\Gotenberg\Request; use TheCodingMachine\Gotenberg\Request;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client()); $client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;); $index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;);
</span><span class="x">$request = new HTMLRequest($index); $request = new HTMLRequest($index);
</span><span class="x">$request-&gt;setPaperSize(Request::A4); $request-&gt;setPaperSize(Request::A4);
</span><span class="x">$request-&gt;setMargins(Request::NO_MARGINS); $request-&gt;setMargins(Request::NO_MARGINS);
</span><span class="x">$request-&gt;setLandscape(true); $request-&gt;setLandscape(true);
</span><span class="x">$dirPath = &#34;/foo&#34;; $dirPath = &#34;/foo&#34;;
</span><span class="x">$filename = $client-&gt;store($request, $dirPath); $filename = $client-&gt;store($request, $dirPath);
</span><span class="x"></span></pre> </pre>
</div> </div>
@@ -497,15 +500,15 @@ in the file <code>index.html</code>. This function will convert a given markdown
<p>For instance:</p> <p>For instance:</p>
<pre class="chroma"><span class="cp">&lt;!doctype html&gt;</span> <pre class="chroma"><span class="cp">&lt;!doctype html&gt;</span>
<span class="p">&lt;</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;en&#34;</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">&#34;en&#34;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">head</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">head</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;utf-8&#34;</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">&#34;utf-8&#34;</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">title</span><span class="p"></span><span class="p">&gt;</span>My PDF<span class="p">&lt;</span><span class="p">/</span><span class="nt">title</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">title</span><span class="p">&gt;</span>My PDF<span class="p">&lt;/</span><span class="nt">title</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">head</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">head</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">body</span><span class="p"></span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">body</span><span class="p">&gt;</span>
{{ toHTML .DirPath &#34;file.md&#34; }} {{ toHTML .DirPath &#34;file.md&#34; }}
<span class="p">&lt;</span><span class="p">/</span><span class="nt">body</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">body</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">html</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">html</span><span class="p">&gt;</span>
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="markdown.basic.c_url" href="#markdown.basic.c_url"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="markdown.basic.c_url" href="#markdown.basic.c_url">
@@ -517,7 +520,7 @@ in the file <code>index.html</code>. This function will convert a given markdown
</span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\ </span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html <span class="se">\ </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@file.md <span class="se">\ </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@file.md <span class="se">\
</span><span class="se"></span> &gt; result.pdf </span><span class="se"></span> -o result.pdf
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="markdown.basic.go" href="#markdown.basic.go"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="markdown.basic.go" href="#markdown.basic.go">
@@ -526,16 +529,11 @@ in the file <code>index.html</code>. This function will convert a given markdown
<pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span> <pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span>
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span> <span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">MarkdownRequest</span><span class="p">{</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewMarkdownRequest</span><span class="p">(</span><span class="s">&#34;index.html&#34;</span><span class="p">,</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;file.md&#34;</span><span class="p">})</span>
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">&#34;index.html&#34;</span><span class="p">,</span>
<span class="nx">MarkdownFilePaths</span><span class="p">:</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span>
<span class="s">&#34;file.md&#34;</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span> <span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span> <span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
</pre> </pre>
@@ -543,19 +541,19 @@ in the file <code>index.html</code>. This function will convert a given markdown
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3> </a>PHP</h3>
<pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client; <pre class="chroma">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory; use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\MarkdownRequest; use TheCodingMachine\Gotenberg\MarkdownRequest;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client()); $client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;); $index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;);
</span><span class="x">$markdowns = [ $markdowns = [
</span><span class="x"> DocumentFactory::makeFromPath(&#39;file.md&#39;, &#39;file.md&#39;), DocumentFactory::makeFromPath(&#39;file.md&#39;, &#39;file.md&#39;),
</span><span class="x">]; ];
</span><span class="x">$request = new MarkdownRequest($index, $markdowns); $request = new MarkdownRequest($index, $markdowns);
</span><span class="x">$dirPath = &#34;/foo&#34;; $dirPath = &#34;/foo&#34;;
</span><span class="x">$filename = $client-&gt;store($request, $dirPath); $filename = $client-&gt;store($request, $dirPath);
</span><span class="x"></span></pre> </pre>
</div> </div>
@@ -574,6 +572,8 @@ in the file <code>index.html</code>. This function will convert a given markdown
<p>You may send one or more Office documents. Following file extensions are accepted:</p> <p>You may send one or more Office documents. Following file extensions are accepted:</p>
<ul> <ul>
<li><code>.txt</code></li>
<li><code>.rtf</code></li>
<li><code>.doc</code></li> <li><code>.doc</code></li>
<li><code>.docx</code></li> <li><code>.docx</code></li>
<li><code>.odt</code></li> <li><code>.odt</code></li>
@@ -602,7 +602,7 @@ See the <a href="#scalability">scalability section</a> to find how to mitigate t
</span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\ </span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@document.docx <span class="se">\ </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@document.docx <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@document2.docx <span class="se">\ </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@document2.docx <span class="se">\
</span><span class="se"></span> &gt; result.pdf </span><span class="se"></span> -o result.pdf
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.basic.go" href="#office.basic.go"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.basic.go" href="#office.basic.go">
@@ -611,16 +611,11 @@ See the <a href="#scalability">scalability section</a> to find how to mitigate t
<pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span> <pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span>
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span> <span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">OfficeRequest</span><span class="p">{</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewOfficeRequest</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;document.docx&#34;</span><span class="p">,</span> <span class="s">&#34;document2.docx&#34;</span><span class="p">})</span>
<span class="nx">FilePaths</span><span class="p">:</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span>
<span class="s">&#34;document.docx&#34;</span><span class="p">,</span>
<span class="s">&#34;document2.docx&#34;</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span> <span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span> <span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
</pre> </pre>
@@ -628,19 +623,81 @@ See the <a href="#scalability">scalability section</a> to find how to mitigate t
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3> </a>PHP</h3>
<pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client; <pre class="chroma">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory; use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\OfficeRequest; use TheCodingMachine\Gotenberg\OfficeRequest;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client()); $client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$files = [ $files = [
</span><span class="x"> DocumentFactory::makeFromPath(&#39;document.docx&#39;, &#39;document.docx&#39;), DocumentFactory::makeFromPath(&#39;document.docx&#39;, &#39;document.docx&#39;),
</span><span class="x"> DocumentFactory::makeFromPath(&#39;document2.docx&#39;, &#39;document2.docx&#39;), DocumentFactory::makeFromPath(&#39;document2.docx&#39;, &#39;document2.docx&#39;),
</span><span class="x">]; ];
</span><span class="x">$request = new OfficeRequest($files); $request = new OfficeRequest($files);
</span><span class="x">$dirPath = &#34;/foo&#34;; $dirPath = &#34;/foo&#34;;
</span><span class="x">$filename = $client-&gt;store($request, $dirPath); $filename = $client-&gt;store($request, $dirPath);
</span><span class="x"></span></pre> </pre>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="office.paper_size_and_orientation" href="#office.paper_size_and_orientation">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>Paper size and orientation</h2>
<p>You may also customize the resulting PDF format.</p>
<p>By default, it will be rendered with <code>A4</code> size and <code>portrait</code> orientation.</p>
<blockquote>
<p>Paper size has to be provided in <code>inches</code>.
Also, you have to set both <code>paperWidth</code> and <code>paperHeight</code>.</p>
</blockquote>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.paper_size_and_orientation.c_url" href="#office.paper_size_and_orientation.c_url">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>cURL</h3>
<pre class="chroma">$ curl --request POST <span class="se">\
</span><span class="se"></span> --url http://localhost:3000/convert/office <span class="se">\
</span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@document.docx <span class="se">\
</span><span class="se"></span> --form <span class="nv">paperWidth</span><span class="o">=</span><span class="m">8</span>.27 <span class="se">\
</span><span class="se"></span> --form <span class="nv">paperHeight</span><span class="o">=</span><span class="m">11</span>.27 <span class="se">\
</span><span class="se"></span> --form <span class="nv">landscape</span><span class="o">=</span><span class="nb">true</span> <span class="se">\
</span><span class="se"></span> -o result.pdf
</pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.paper_size_and_orientation.go" href="#office.paper_size_and_orientation.go">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>Go</h3>
<pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewOfficeRequest</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;document.docx&#34;</span><span class="p">})</span>
<span class="nx">req</span><span class="p">.</span><span class="nf">SetPaperSize</span><span class="p">(</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">A4</span><span class="p">)</span>
<span class="nx">req</span><span class="p">.</span><span class="nf">SetLandscape</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span>
</pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.paper_size_and_orientation.php" href="#office.paper_size_and_orientation.php">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3>
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
use TheCodingMachine\Gotenberg\DocumentFactory;
use TheCodingMachine\Gotenberg\OfficeRequest;
$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
$files = [
DocumentFactory::makeFromPath(&#39;document.docx&#39;, &#39;document.docx&#39;),
];
$request = new OfficeRequest($files);
$request-&gt;setPaperSize(Request::A4);
$request-&gt;setLandscape(true);
$dirPath = &#34;/foo&#34;;
$filename = $client-&gt;store($request, $dirPath);
</pre>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="office.fonts" href="#office.fonts"> <h2 class="Heading"><a class="Anchor" aria-hidden="true" id="office.fonts" href="#office.fonts">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
@@ -653,7 +710,7 @@ See the <a href="#scalability">scalability section</a> to find how to mitigate t
<pre class="chroma"><span class="k">FROM</span><span class="s"> thecodingmachine/gotenberg:3</span><span class="err"> <pre class="chroma"><span class="k">FROM</span><span class="s"> thecodingmachine/gotenberg:3</span><span class="err">
</span><span class="err"> </span><span class="err">
</span><span class="err"></span><span class="k">RUN</span> apt-get -y install yourfonts<span class="err"> </span><span class="err"></span><span class="k">RUN</span> apt-get -y install yourfonts<span class="err">
</span><span class="err"></span></pre> </span></pre>
</div> </div>
@@ -681,7 +738,7 @@ will merge them and return the resulting PDF file.</p>
</span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\ </span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@file.pdf <span class="se">\ </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@file.pdf <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@file2.pdf <span class="se">\ </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@file2.pdf <span class="se">\
</span><span class="se"></span> &gt; result.pdf </span><span class="se"></span> -o result.pdf
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="merge.basic.go" href="#merge.basic.go"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="merge.basic.go" href="#merge.basic.go">
@@ -690,16 +747,11 @@ will merge them and return the resulting PDF file.</p>
<pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span> <pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span>
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span> <span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">MergeRequest</span><span class="p">{</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewMergeRequest</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;file.pdf&#34;</span><span class="p">,</span> <span class="s">&#34;file2.pdf&#34;</span><span class="p">})</span>
<span class="nx">FilePaths</span><span class="p">:</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span>
<span class="s">&#34;file.pdf&#34;</span><span class="p">,</span>
<span class="s">&#34;file2.pdf&#34;</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span> <span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span> <span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
</pre> </pre>
@@ -707,19 +759,19 @@ will merge them and return the resulting PDF file.</p>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3> </a>PHP</h3>
<pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client; <pre class="chroma">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory; use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\MergeRequest; use TheCodingMachine\Gotenberg\MergeRequest;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client()); $client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$files = [ $files = [
</span><span class="x"> DocumentFactory::makeFromPath(&#39;file.pdf&#39;, &#39;file.pdf&#39;), DocumentFactory::makeFromPath(&#39;file.pdf&#39;, &#39;file.pdf&#39;),
</span><span class="x"> DocumentFactory::makeFromPath(&#39;file2.pdf&#39;, &#39;file2.pdf&#39;), DocumentFactory::makeFromPath(&#39;file2.pdf&#39;, &#39;file2.pdf&#39;),
</span><span class="x">]; ];
</span><span class="x">$request = new MergeRequest($files); $request = new MergeRequest($files);
</span><span class="x">$dirPath = &#34;/foo&#34;; $dirPath = &#34;/foo&#34;;
</span><span class="x">$filename = $client-&gt;store($request, $dirPath); $filename = $client-&gt;store($request, $dirPath);
</span><span class="x"></span></pre> </pre>
</div> </div>
@@ -755,16 +807,12 @@ to given URL.</p>
<pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span> <pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span>
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span> <span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLRequest</span><span class="p">{</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewHTMLRequest</span><span class="p">(</span><span class="s">&#34;index.html&#34;</span><span class="p">)</span>
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">&#34;index.html&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nf">SetWebhookURL</span><span class="p">(</span><span class="s">&#34;http://myapp.com/webhook/&#34;</span><span class="p">)</span>
<span class="nx">Options</span><span class="p">:</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLOptions</span><span class="p">{</span>
<span class="nx">WebHookURL</span><span class="p">:</span> <span class="s">&#34;http://myapp.com/webhook/&#34;</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span> <span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">resp</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">c</span><span class="p">.</span><span class="nx">Post</span><span class="p">(</span><span class="nx">req</span><span class="p">)</span> <span class="nx">resp</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">c</span><span class="p">.</span><span class="nf">Post</span><span class="p">(</span><span class="nx">req</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
</pre> </pre>
@@ -772,16 +820,16 @@ to given URL.</p>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3> </a>PHP</h3>
<pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client; <pre class="chroma">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory; use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\HTMLRequest; use TheCodingMachine\Gotenberg\HTMLRequest;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client()); $client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;); $index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;);
</span><span class="x">$request = new HTMLRequest($index); $request = new HTMLRequest($index);
</span><span class="x">$request-&gt;setWebhookURL(&#39;http://myapp.com/webhook/&#39;); $request-&gt;setWebhookURL(&#39;http://myapp.com/webhook/&#39;);
</span><span class="x">$resp = $client-&gt;post($request); $resp = $client-&gt;post($request);
</span><span class="x"></span></pre> </pre>
</div> </div>
@@ -801,7 +849,7 @@ to given URL.</p>
</span><span class="w"> </span><span class="w">
</span><span class="w"> </span>gotenberg<span class="p">:</span><span class="w"> </span><span class="w"> </span>gotenberg<span class="p">:</span><span class="w">
</span><span class="w"> </span>image<span class="p">:</span><span class="w"> </span>thecodingmachine/gotenberg<span class="p">:</span><span class="m">3</span><span class="w"> </span><span class="w"> </span>image<span class="p">:</span><span class="w"> </span>thecodingmachine/gotenberg<span class="p">:</span><span class="m">3</span><span class="w">
</span><span class="w"></span></pre> </span></pre>
<p>You may now launch your services using:</p> <p>You may now launch your services using:</p>
@@ -813,6 +861,22 @@ redirect a request to a Gotenberg container according to the round-robin strateg
</div> </div>
<div class="Page" id="liveness">
<h1 class="Heading"><a class="Anchor" aria-hidden="true" id="liveness" href="#liveness">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>Liveness</h1>
<p>Gotenberg provides the endpoint <code>/ping</code> for checking the API availability with
a simple <code>GET</code> request.</p>
<p>This feature is especially useful for liveness/readiness probes in Kubernetes:</p>
<ul>
<li><a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes">Pod lifecycle</a></li>
<li><a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/">Configure Liveness and Readiness Probes</a></li>
</ul>
</div>
<div class="Page" id="links"> <div class="Page" id="links">
<h1 class="Heading"><a class="Anchor" aria-hidden="true" id="links" href="#links"> <h1 class="Heading"><a class="Anchor" aria-hidden="true" id="links" href="#links">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
docs/theme/gotenberg/img/favicon-128.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 923 B

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -5,8 +5,19 @@
<meta http-equiv="x-ua-compatible" content="ie=edge"> <meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{.Title}} &#183; {{.Subtitle}}</title> <title>{{.Title}} &#183; {{.Subtitle}}</title>
<link rel="apple-touch-icon-precomposed" sizes="57x57" href="theme/gotenberg/img/apple-touch-icon-57x57.png" />
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="theme/gotenberg/img/apple-touch-icon-114x114.png" />
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="theme/gotenberg/img/apple-touch-icon-72x72.png" />
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="theme/gotenberg/img/apple-touch-icon-144x144.png" />
<link rel="apple-touch-icon-precomposed" sizes="60x60" href="theme/gotenberg/img/apple-touch-icon-60x60.png" />
<link rel="apple-touch-icon-precomposed" sizes="120x120" href="theme/gotenberg/img/apple-touch-icon-120x120.png" />
<link rel="apple-touch-icon-precomposed" sizes="76x76" href="theme/gotenberg/img/apple-touch-icon-76x76.png" />
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="theme/gotenberg/img/apple-touch-icon-152x152.png" />
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-196x196.png" sizes="196x196" />
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-32x32.png" sizes="32x32" /> <link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-16x16.png" sizes="16x16" /> <link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-16x16.png" sizes="16x16" />
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-128.png" sizes="128x128" />
<link rel="stylesheet" href="theme/gotenberg/css/index.css"> <link rel="stylesheet" href="theme/gotenberg/css/index.css">
</head> </head>
<body> <body>
@@ -14,7 +25,7 @@
<div class="Container"> <div class="Container">
<div class="Header"> <div class="Header">
<div class="Title center"> <div class="Title center">
<img src="https://user-images.githubusercontent.com/8983173/49701110-4c8b9280-fbe8-11e8-895c-a4b9c7d2515b.png" alt="Gotenberg logo" width="250" height="250" /> <img src="https://user-images.githubusercontent.com/8983173/50009948-84b01e00-ffb8-11e8-850b-fc240382c626.png" alt="Gotenberg logo" width="250" height="250" />
<span class="text">{{.Title}}</span> <span class="text">{{.Title}}</span>
<span class="subtext">{{.Subtitle}}</span> <span class="subtext">{{.Subtitle}}</span>
</div> </div>

2
go.mod
View File

@@ -4,7 +4,7 @@ require (
github.com/derekparker/delve v1.1.0 github.com/derekparker/delve v1.1.0
github.com/google/go-cmp v0.2.0 // indirect github.com/google/go-cmp v0.2.0 // indirect
github.com/gorilla/websocket v1.4.0 // indirect github.com/gorilla/websocket v1.4.0 // indirect
github.com/hhrutter/pdfcpu v0.1.18 github.com/hhrutter/pdfcpu v0.1.19
github.com/labstack/echo v0.0.0-20181123063703-c7eb8da9ec73 github.com/labstack/echo v0.0.0-20181123063703-c7eb8da9ec73
github.com/labstack/gommon v0.2.8 github.com/labstack/gommon v0.2.8
github.com/mafredri/cdp v0.20.0 github.com/mafredri/cdp v0.20.0

2
go.sum
View File

@@ -10,6 +10,8 @@ github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/hhrutter/pdfcpu v0.1.18 h1:GX3d6tZxmQlmB5X9VUyOtx7+HZZpR+8ISLqBineP6dc= github.com/hhrutter/pdfcpu v0.1.18 h1:GX3d6tZxmQlmB5X9VUyOtx7+HZZpR+8ISLqBineP6dc=
github.com/hhrutter/pdfcpu v0.1.18/go.mod h1:iaCmXGnOXPIvoGLELZZc4m/GpIopVsvLQ00thrbu8LU= github.com/hhrutter/pdfcpu v0.1.18/go.mod h1:iaCmXGnOXPIvoGLELZZc4m/GpIopVsvLQ00thrbu8LU=
github.com/hhrutter/pdfcpu v0.1.19 h1:J6GjNFDPjurQWallPW9gmz3CcNqBfvgB7Dad9T3e8Hc=
github.com/hhrutter/pdfcpu v0.1.19/go.mod h1:iaCmXGnOXPIvoGLELZZc4m/GpIopVsvLQ00thrbu8LU=
github.com/labstack/echo v0.0.0-20181123063703-c7eb8da9ec73 h1:oQvA3Xy8274W5Ldgo6Nogy4lX8XO5AaIBsjF5Ggk0IU= github.com/labstack/echo v0.0.0-20181123063703-c7eb8da9ec73 h1:oQvA3Xy8274W5Ldgo6Nogy4lX8XO5AaIBsjF5Ggk0IU=
github.com/labstack/echo v0.0.0-20181123063703-c7eb8da9ec73/go.mod h1:rS0D1UPvC8/3sXjhSwEq+K1olh7ipbDhjDWATN2KSgA= github.com/labstack/echo v0.0.0-20181123063703-c7eb8da9ec73/go.mod h1:rS0D1UPvC8/3sXjhSwEq+K1olh7ipbDhjDWATN2KSgA=
github.com/labstack/echo v3.3.5+incompatible h1:9PfxPUmasKzeJor9uQTaXLT6WUG/r+vSTmvXxvv3JO4= github.com/labstack/echo v3.3.5+incompatible h1:9PfxPUmasKzeJor9uQTaXLT6WUG/r+vSTmvXxvv3JO4=

View File

@@ -67,6 +67,7 @@ func setup() *echo.Echo {
return nil return nil
} }
}) })
e.GET("/ping", func(c echo.Context) error { return nil })
e.POST("/merge", merge) e.POST("/merge", merge)
g := e.Group("/convert") g := e.Group("/convert")
g.POST("/html", convertHTML) g.POST("/html", convertHTML)
@@ -87,14 +88,15 @@ func newContext(r *resource) (context.Context, context.CancelFunc) {
func print(c echo.Context, p printer.Printer, r *resource) error { func print(c echo.Context, p printer.Printer, r *resource) error {
baseFilename, err := rand.Get() baseFilename, err := rand.Get()
if err != nil { if err != nil {
return fmt.Errorf("getting result file name: %v", err) return hijackErr(fmt.Errorf("getting result file name: %v", err), r)
} }
filename := fmt.Sprintf("%s.pdf", baseFilename) filename := fmt.Sprintf("%s.pdf", baseFilename)
fpath := fmt.Sprintf("%s/%s", r.dirPath, filename) fpath := fmt.Sprintf("%s/%s", r.dirPath, filename)
if r.webhookURL() == "" { if r.webhookURL() == "" {
defer r.removeAll()
// if no webhook URL given, run conversion // if no webhook URL given, run conversion
// and directly return the resulting PDF file // and directly return the resulting PDF file
// or and error. // or an error.
if err := p.Print(fpath); err != nil { if err := p.Print(fpath); err != nil {
return err return err
} }
@@ -104,6 +106,7 @@ func print(c echo.Context, p printer.Printer, r *resource) error {
// run the following lines in a goroutine so that // run the following lines in a goroutine so that
// it doesn't block. // it doesn't block.
go func() { go func() {
defer r.removeAll()
if err := p.Print(fpath); err != nil { if err := p.Print(fpath); err != nil {
c.Logger().Errorf("%v", err) c.Logger().Errorf("%v", err)
return return
@@ -123,3 +126,10 @@ func print(c echo.Context, p printer.Printer, r *resource) error {
}() }()
return nil return nil
} }
func hijackErr(err error, r *resource) error {
if r != nil {
defer r.removeAll()
}
return err
}

View File

@@ -0,0 +1,18 @@
package api
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/labstack/echo"
"github.com/stretchr/testify/assert"
)
func TestPing(t *testing.T) {
req := httptest.NewRequest(http.MethodGet, "/ping", nil)
rec := httptest.NewRecorder()
e := echo.New()
_ = e.NewContext(req, rec)
assert.Equal(t, http.StatusOK, rec.Code)
}

View File

@@ -8,9 +8,8 @@ import (
func convertHTML(c echo.Context) error { func convertHTML(c echo.Context) error {
r, err := newResource(c) r, err := newResource(c)
if err != nil { if err != nil {
return err return hijackErr(err, r)
} }
defer r.removeAll()
ctx, cancel := newContext(r) ctx, cancel := newContext(r)
if cancel != nil { if cancel != nil {
defer cancel() defer cancel()
@@ -18,26 +17,26 @@ func convertHTML(c echo.Context) error {
p := &printer.HTML{Context: ctx} p := &printer.HTML{Context: ctx}
indexPath, err := r.filePath("index.html") indexPath, err := r.filePath("index.html")
if err != nil { if err != nil {
return err return hijackErr(err, r)
} }
p.WithLocalURL(indexPath) p.WithLocalURL(indexPath)
headerPath, _ := r.filePath("header.html") headerPath, _ := r.filePath("header.html")
if err := p.WithHeaderFile(headerPath); err != nil { if err := p.WithHeaderFile(headerPath); err != nil {
return err return hijackErr(err, r)
} }
footerPath, _ := r.filePath("footer.html") footerPath, _ := r.filePath("footer.html")
if err := p.WithFooterFile(footerPath); err != nil { if err := p.WithFooterFile(footerPath); err != nil {
return err return hijackErr(err, r)
} }
paperSize, err := r.paperSize() paperSize, err := r.paperSize()
if err != nil { if err != nil {
return err return hijackErr(err, r)
} }
p.PaperWidth = paperSize[0] p.PaperWidth = paperSize[0]
p.PaperHeight = paperSize[1] p.PaperHeight = paperSize[1]
paperMargins, err := r.paperMargins() paperMargins, err := r.paperMargins()
if err != nil { if err != nil {
return err return hijackErr(err, r)
} }
p.MarginTop = paperMargins[0] p.MarginTop = paperMargins[0]
p.MarginBottom = paperMargins[1] p.MarginBottom = paperMargins[1]
@@ -45,7 +44,7 @@ func convertHTML(c echo.Context) error {
p.MarginRight = paperMargins[3] p.MarginRight = paperMargins[3]
landscape, err := r.landscape() landscape, err := r.landscape()
if err != nil { if err != nil {
return err return hijackErr(err, r)
} }
p.Landscape = landscape p.Landscape = landscape
return print(c, p, r) return print(c, p, r)

View File

@@ -8,35 +8,34 @@ import (
func convertMarkdown(c echo.Context) error { func convertMarkdown(c echo.Context) error {
r, err := newResource(c) r, err := newResource(c)
if err != nil { if err != nil {
return err return hijackErr(err, r)
} }
defer r.removeAll()
ctx, cancel := newContext(r) ctx, cancel := newContext(r)
if cancel != nil { if cancel != nil {
defer cancel() defer cancel()
} }
indexPath, err := r.filePath("index.html") indexPath, err := r.filePath("index.html")
if err != nil { if err != nil {
return err return hijackErr(err, r)
} }
p := &printer.Markdown{Context: ctx, TemplatePath: indexPath} p := &printer.Markdown{Context: ctx, TemplatePath: indexPath}
headerPath, _ := r.filePath("header.html") headerPath, _ := r.filePath("header.html")
if err := p.WithHeaderFile(headerPath); err != nil { if err := p.WithHeaderFile(headerPath); err != nil {
return err return hijackErr(err, r)
} }
footerPath, _ := r.filePath("footer.html") footerPath, _ := r.filePath("footer.html")
if err := p.WithFooterFile(footerPath); err != nil { if err := p.WithFooterFile(footerPath); err != nil {
return err return hijackErr(err, r)
} }
paperSize, err := r.paperSize() paperSize, err := r.paperSize()
if err != nil { if err != nil {
return err return hijackErr(err, r)
} }
p.PaperWidth = paperSize[0] p.PaperWidth = paperSize[0]
p.PaperHeight = paperSize[1] p.PaperHeight = paperSize[1]
paperMargins, err := r.paperMargins() paperMargins, err := r.paperMargins()
if err != nil { if err != nil {
return err return hijackErr(err, r)
} }
p.MarginTop = paperMargins[0] p.MarginTop = paperMargins[0]
p.MarginBottom = paperMargins[1] p.MarginBottom = paperMargins[1]
@@ -44,7 +43,7 @@ func convertMarkdown(c echo.Context) error {
p.MarginRight = paperMargins[3] p.MarginRight = paperMargins[3]
landscape, err := r.landscape() landscape, err := r.landscape()
if err != nil { if err != nil {
return err return hijackErr(err, r)
} }
p.Landscape = landscape p.Landscape = landscape
return print(c, p, r) return print(c, p, r)

View File

@@ -1,6 +1,7 @@
package api package api
import ( import (
"errors"
"fmt" "fmt"
"net/http" "net/http"
"os" "os"
@@ -13,23 +14,26 @@ import (
func merge(c echo.Context) error { func merge(c echo.Context) error {
r, err := newResource(c) r, err := newResource(c)
if err != nil { if err != nil {
return err return hijackErr(err, r)
} }
defer r.removeAll()
fpaths, err := r.filePaths([]string{".pdf"}) fpaths, err := r.filePaths([]string{".pdf"})
if err != nil { if err != nil {
return err return hijackErr(err, r)
}
if len(fpaths) == 0 {
return hijackErr(errors.New("no suitable PDF files to merge"), r)
} }
baseFilename, err := rand.Get() baseFilename, err := rand.Get()
if err != nil { if err != nil {
return fmt.Errorf("getting result file name: %v", err) return hijackErr(fmt.Errorf("getting result file name: %v", err), r)
} }
filename := fmt.Sprintf("%s.pdf", baseFilename) filename := fmt.Sprintf("%s.pdf", baseFilename)
fpath := fmt.Sprintf("%s/%s", r.dirPath, filename) fpath := fmt.Sprintf("%s/%s", r.dirPath, filename)
if r.webhookURL() == "" { if r.webhookURL() == "" {
defer r.removeAll()
// if no webhook URL given, run merge // if no webhook URL given, run merge
// and directly return the resulting PDF file // and directly return the resulting PDF file
// or and error. // or an error.
if err := printer.Merge(fpaths, fpath); err != nil { if err := printer.Merge(fpaths, fpath); err != nil {
return err return err
} }
@@ -39,6 +43,7 @@ func merge(c echo.Context) error {
// run the following lines in a goroutine so that // run the following lines in a goroutine so that
// it doesn't block. // it doesn't block.
go func() { go func() {
defer r.removeAll()
if err := printer.Merge(fpaths, fpath); err != nil { if err := printer.Merge(fpaths, fpath); err != nil {
c.Logger().Errorf("%v", err) c.Logger().Errorf("%v", err)
return return

View File

@@ -8,6 +8,8 @@ import (
) )
var officeExts = []string{ var officeExts = []string{
".txt",
".rtf",
".doc", ".doc",
".docx", ".docx",
".odt", ".odt",
@@ -22,20 +24,30 @@ var officeExts = []string{
func convertOffice(c echo.Context) error { func convertOffice(c echo.Context) error {
r, err := newResource(c) r, err := newResource(c)
if err != nil { if err != nil {
return err return hijackErr(err, r)
} }
defer r.removeAll()
ctx, cancel := newContext(r) ctx, cancel := newContext(r)
if cancel != nil { if cancel != nil {
defer cancel() defer cancel()
} }
fpaths, err := r.filePaths(officeExts) fpaths, err := r.filePaths(officeExts)
if err != nil { if err != nil {
return err return hijackErr(err, r)
} }
if len(fpaths) == 0 { if len(fpaths) == 0 {
return errors.New("no suitable office documents to convert") return hijackErr(errors.New("no suitable office documents to convert"), r)
} }
p := &printer.Office{Context: ctx, FilePaths: fpaths} p := &printer.Office{Context: ctx, FilePaths: fpaths}
paperSize, err := r.paperSize()
if err != nil {
return hijackErr(err, r)
}
p.PaperWidth = paperSize[0]
p.PaperHeight = paperSize[1]
landscape, err := r.landscape()
if err != nil {
return hijackErr(err, r)
}
p.Landscape = landscape
return print(c, p, r) return print(c, p, r)
} }

View File

@@ -49,17 +49,17 @@ func newResource(c echo.Context) (*resource, error) {
r := &resource{values: v, dirPath: dirPath} r := &resource{values: v, dirPath: dirPath}
form, err := c.MultipartForm() form, err := c.MultipartForm()
if err != nil { if err != nil {
return nil, fmt.Errorf("getting multipart form: %v", err) return r, fmt.Errorf("getting multipart form: %v", err)
} }
for _, files := range form.File { for _, files := range form.File {
for _, fh := range files { for _, fh := range files {
in, err := fh.Open() in, err := fh.Open()
if err != nil { if err != nil {
return nil, fmt.Errorf("%s: opening file: %v", fh.Filename, err) return r, fmt.Errorf("%s: opening file: %v", fh.Filename, err)
} }
defer in.Close() defer in.Close()
if err := r.writeFile(fh.Filename, in); err != nil { if err := r.writeFile(fh.Filename, in); err != nil {
return nil, err return r, err
} }
} }
} }

View File

@@ -1,52 +1,7 @@
/* /*
Package printer contains structs which convert Package printer contains structs which convert
a specific file type to PDF: a specific file type to PDF.
// converting HTML to PDF. It is also able to merge a list of PDF files.
p := &printer.HTML{
Context: context.Background(),
PaperWidth: 8.27,
PaperHeight: 11.7,
Landscape: false,
}
p.WithLocalURL("index.html")
if err := p.Print("result.pdf"); err != nil {
return err
}
// converting Markdown to PDF:
// it assumes here that our template "index.html"
// will call toHTML method to convert
// markdown files to HTML.
p := &printer.Markdown{
Context: context.Background(),
TemplatePath: "index.html",
PaperWidth: 8.27,
PaperHeight: 11.7,
Landscape: false,
}
if err := p.Print("result.pdf"); err != nil {
return err
}
// converting Office documents to PDF:
// it converts each files independently and
// then merge them.
//
// Also, as unoconv cannot perform
// concurrent conversions, a lock is applied.
p := &printer.Office{
Context: ctx,
FilePaths: []string{"document.docx", "presentation.pptx"}
}
if err := p.Print("result.pdf"); err != nil {
return err
}
It is also able to merge a list of PDF files:
if err := printer.Merge([]string{"foo.pdf", "bar.pdf"}, "result.pdf"); err != nil {
return err
}
*/ */
package printer package printer

View File

@@ -7,6 +7,7 @@ import (
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"strconv"
"sync" "sync"
"github.com/thecodingmachine/gotenberg/internal/pkg/rand" "github.com/thecodingmachine/gotenberg/internal/pkg/rand"
@@ -16,8 +17,11 @@ var mu sync.Mutex
// Office facilitates Office documents to PDF conversion. // Office facilitates Office documents to PDF conversion.
type Office struct { type Office struct {
Context context.Context Context context.Context
FilePaths []string FilePaths []string
PaperWidth float64
PaperHeight float64
Landscape bool
} }
// Print converts Office documents to PDF. // Print converts Office documents to PDF.
@@ -32,14 +36,24 @@ func (o *Office) Print(destination string) error {
return err return err
} }
tmpDest := fmt.Sprintf("%s/%s.pdf", dirPath, baseFilename) tmpDest := fmt.Sprintf("%s/%s.pdf", dirPath, baseFilename)
paperSize, err := unoconvPaperSize(o.PaperWidth, o.PaperHeight)
if err != nil {
return err
}
cmdArgs := []string{
"--format",
"pdf",
"--printer",
paperSize,
}
if o.Landscape {
cmdArgs = append(cmdArgs, "--printer", "PaperOrientation=landscape")
}
cmdArgs = append(cmdArgs, "--output", tmpDest, fpath)
cmd := exec.CommandContext( cmd := exec.CommandContext(
o.Context, o.Context,
"unoconv", "unoconv",
"--format", cmdArgs...,
"pdf",
"--output",
tmpDest,
fpath,
) )
_, err = cmd.Output() _, err = cmd.Output()
if o.Context.Err() == context.DeadlineExceeded { if o.Context.Err() == context.DeadlineExceeded {
@@ -56,6 +70,18 @@ func (o *Office) Print(destination string) error {
return Merge(fpaths, destination) return Merge(fpaths, destination)
} }
func unoconvPaperSize(paperWidth, paperHeight float64) (string, error) {
width, err := strconv.Atoi(fmt.Sprintf("%.0f", paperWidth*25.4))
if err != nil {
return "", fmt.Errorf("%0.f: converting width to millimiter: %v", paperWidth, err)
}
height, err := strconv.Atoi(fmt.Sprintf("%.0f", paperHeight*25.4))
if err != nil {
return "", fmt.Errorf("%0.f: converting height to millimiter: %v", paperHeight, err)
}
return fmt.Sprintf("PaperSize=%dx%d", width, height), nil
}
// Compile-time checks to ensure type implements desired interfaces. // Compile-time checks to ensure type implements desired interfaces.
var ( var (
_ = Printer(new(Office)) _ = Printer(new(Office))

View File

@@ -20,6 +20,8 @@ func TestOffice(t *testing.T) {
Context: ctx, Context: ctx,
FilePaths: []string{ FilePaths: []string{
fmt.Sprintf("%s/%s", dirPath, "document.docx"), fmt.Sprintf("%s/%s", dirPath, "document.docx"),
fmt.Sprintf("%s/%s", dirPath, "document.txt"),
fmt.Sprintf("%s/%s", dirPath, "document.rtf"),
}, },
} }
dst := fmt.Sprintf("%s/%s", dirPath, "foo.pdf") dst := fmt.Sprintf("%s/%s", dirPath, "foo.pdf")

View File

@@ -3,11 +3,19 @@ package printer
import ( import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os/exec"
pdfcpuAPI "github.com/hhrutter/pdfcpu/pkg/api" pdfcpuAPI "github.com/hhrutter/pdfcpu/pkg/api"
pdfcpuLog "github.com/hhrutter/pdfcpu/pkg/log"
pdfcpuConfig "github.com/hhrutter/pdfcpu/pkg/pdfcpu" pdfcpuConfig "github.com/hhrutter/pdfcpu/pkg/pdfcpu"
) )
func init() {
// disable loggers when merging
// PDFs.
pdfcpuLog.DisableLoggers()
}
// Printer is a type that can create a PDF file from a source. // Printer is a type that can create a PDF file from a source.
// The source is defined in the underlying implementation. // The source is defined in the underlying implementation.
type Printer interface { type Printer interface {
@@ -16,9 +24,18 @@ type Printer interface {
// Merge merges PDF files. // Merge merges PDF files.
func Merge(fpaths []string, destination string) error { func Merge(fpaths []string, destination string) error {
cmd := pdfcpuAPI.MergeCommand(fpaths, destination, pdfcpuConfig.NewDefaultConfiguration()) cmdcpu := pdfcpuAPI.MergeCommand(fpaths, destination, pdfcpuConfig.NewDefaultConfiguration())
_, err := pdfcpuAPI.Merge(cmd) _, err := pdfcpuAPI.Merge(cmdcpu)
return err if err == nil {
return nil
}
// if pdfcpu failed to merge PDF files...
// https://github.com/thecodingmachine/gotenberg/issues/29
var cmdArgs []string
cmdArgs = append(cmdArgs, fpaths...)
cmdArgs = append(cmdArgs, "cat", "output", destination)
cmd := exec.Command("pdftk", cmdArgs...)
return cmd.Run()
} }
func writeBytesToFile(dst string, b []byte) error { func writeBytesToFile(dst string, b []byte) error {

View File

@@ -16,7 +16,7 @@ func TestMerge(t *testing.T) {
err := Merge( err := Merge(
[]string{ []string{
fmt.Sprintf("%s/%s", dirPath, "gotenberg.pdf"), fmt.Sprintf("%s/%s", dirPath, "gotenberg.pdf"),
fmt.Sprintf("%s/%s", dirPath, "gotenberg.pdf"), fmt.Sprintf("%s/%s", dirPath, "gotenberg_bis.pdf"),
}, },
dst, dst,
) )

View File

@@ -16,19 +16,17 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() { func main() {
// HTML conversion example. // HTML conversion example.
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.HTMLRequest{ req, _ := gotenberg.NewHTMLRequest("index.html")
IndexFilePath: "index.html", req.SetHeader("header.html")
AssetFilePaths: []string{ req.SetFooter("footer.html")
"style.css", req.SetAssets([]string{
"img.png", "font.woff",
}, "img.gif",
Options: &gotenberg.HTMLOptions{ "style.css",
HeaderFilePath: "header.html", })
FooterFilePath: "footer.html", req.SetPaperSize(gotenberg.A4)
PaperSize: gotenberg.A4, req.SetMargins(gotenberg.NormalMargins)
PaperMargins: gotenberg.NormalMargins, req.SetLandscape(false)
},
}
dest := "foo.pdf" dest := "foo.pdf"
c.Store(req, dest) c.Store(req, dest)
} }

View File

@@ -59,18 +59,35 @@ type Client struct {
// form values and form files to // form values and form files to
// the Gotenberg API. // the Gotenberg API.
type Request interface { type Request interface {
validate() error SetWebhookURL(webhookURL string)
getPostURL() string getPostURL() string
getFormValues() map[string]string getFormValues() map[string]string
getFormFiles() map[string]string getFormFiles() map[string]string
} }
// ChromeRequest is a type for sending
// conversion requests which will be
// handle by Google Chrome.
type ChromeRequest interface {
SetHeader(fpath string) error
SetFooter(fpath string) error
SetAssets(fpaths []string) error
SetPaperSize(size [2]float64)
SetMargins(margins [4]float64)
SetLandscape(isLandscape bool)
}
// UnoconvRequest is a type for sending
// conversion requests which will be
// handle by unoconv.
type UnoconvRequest interface {
SetPaperSize(size [2]float64)
SetLandscape(landscape bool)
}
// Post sends a request to the Gotenberg API // Post sends a request to the Gotenberg API
// and returns the response. // and returns the response.
func (c *Client) Post(req Request) (*http.Response, error) { func (c *Client) Post(req Request) (*http.Response, error) {
if err := req.validate(); err != nil {
return nil, err
}
body, contentType, err := multipartForm(req) body, contentType, err := multipartForm(req)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -2,30 +2,7 @@
Package gotenberg is a Go client for Package gotenberg is a Go client for
interacting with a Gotenberg API. interacting with a Gotenberg API.
For instance, if you want to convert HTML: For more complete usages, head to the documentation:
https://thecodingmachine.gotenberg.github.io.
import "github.com/thecodingmachine/gotenberg/pkg"
func main() {
// HTML conversion example.
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.HTMLRequest{
IndexFilePath: "index.html",
AssetFilePaths: []string{
"style.css",
"img.png",
},
Options: &gotenberg.HTMLOptions{
HeaderFilePath: "header.html",
FooterFilePath: "footer.html",
PaperSize: gotenberg.A4,
PaperMargins: gotenberg.NormalMargins,
},
}
dest := "foo.pdf"
c.Store(req, dest)
}
For more complete usages, head to the https://thecodingmachine.gotenberg.github.io.
*/ */
package gotenberg package gotenberg

View File

@@ -9,64 +9,89 @@ import (
// HTMLRequest facilitates HTML conversion // HTMLRequest facilitates HTML conversion
// with the Gotenberg API. // with the Gotenberg API.
type HTMLRequest struct { type HTMLRequest struct {
IndexFilePath string indexFilePath string
AssetFilePaths []string headerFilePath string
Options *HTMLOptions footerFilePath string
assetFilePaths []string
values map[string]string
} }
// HTMLOptions gathers all options // NewHTMLRequest create HTMLRequest.
// for HTML conversion with the Gotenberg API. func NewHTMLRequest(indexFilePath string) (*HTMLRequest, error) {
type HTMLOptions struct { if !fileExists(indexFilePath) {
WebHookURL string return nil, fmt.Errorf("%s: index file does not exist", indexFilePath)
HeaderFilePath string }
FooterFilePath string return &HTMLRequest{indexFilePath: indexFilePath, values: make(map[string]string)}, nil
PaperSize [2]float64
PaperMargins [4]float64
Landscape bool
} }
func (html *HTMLRequest) validate() error { // SetWebhookURL sets webhookURL form field.
if !fileExists(html.IndexFilePath) { func (html *HTMLRequest) SetWebhookURL(webhookURL string) {
return fmt.Errorf("%s: index file does not exist", html.IndexFilePath) html.values[webhookURL] = webhookURL
} }
if html.Options.HeaderFilePath != "" && !fileExists(html.Options.HeaderFilePath) {
return fmt.Errorf("%s: header file does not exist", html.Options.HeaderFilePath) // SetHeader sets header form file.
} func (html *HTMLRequest) SetHeader(fpath string) error {
if html.Options.FooterFilePath != "" && !fileExists(html.Options.FooterFilePath) { if !fileExists(fpath) {
return fmt.Errorf("%s: footer file does not exist", html.Options.FooterFilePath) return fmt.Errorf("%s: header file does not exist", fpath)
} }
html.headerFilePath = fpath
return nil return nil
} }
// SetFooter sets footer form file.
func (html *HTMLRequest) SetFooter(fpath string) error {
if !fileExists(fpath) {
return fmt.Errorf("%s: footer file does not exist", fpath)
}
html.footerFilePath = fpath
return nil
}
// SetAssets sets assets form files.
func (html *HTMLRequest) SetAssets(fpaths []string) error {
for _, fpath := range fpaths {
if !fileExists(fpath) {
return fmt.Errorf("%s: file does not exist", fpath)
}
}
html.assetFilePaths = fpaths
return nil
}
// SetPaperSize sets paperWidth and paperHeight form fields.
func (html *HTMLRequest) SetPaperSize(size [2]float64) {
html.values[paperWidth] = fmt.Sprintf("%f", size[0])
html.values[paperHeight] = fmt.Sprintf("%f", size[1])
}
// SetMargins sets marginTop, marginBottom,
// marginLeft and marginRight form fields.
func (html *HTMLRequest) SetMargins(margins [4]float64) {
html.values[marginTop] = fmt.Sprintf("%f", margins[0])
html.values[marginBottom] = fmt.Sprintf("%f", margins[1])
html.values[marginLeft] = fmt.Sprintf("%f", margins[2])
html.values[marginRight] = fmt.Sprintf("%f", margins[3])
}
// SetLandscape sets landscape form field.
func (html *HTMLRequest) SetLandscape(isLandscape bool) {
html.values[landscape] = strconv.FormatBool(isLandscape)
}
func (html *HTMLRequest) getPostURL() string { func (html *HTMLRequest) getPostURL() string {
return "/convert/html" return "/convert/html"
} }
func (html *HTMLRequest) getFormValues() map[string]string { func (html *HTMLRequest) getFormValues() map[string]string {
if html.Options == nil { return html.values
html.Options = &HTMLOptions{}
}
values := make(map[string]string)
values[webhookURL] = html.Options.WebHookURL
values[paperWidth] = fmt.Sprintf("%f", html.Options.PaperSize[0])
values[paperHeight] = fmt.Sprintf("%f", html.Options.PaperSize[1])
values[marginTop] = fmt.Sprintf("%f", html.Options.PaperMargins[0])
values[marginBottom] = fmt.Sprintf("%f", html.Options.PaperMargins[1])
values[marginLeft] = fmt.Sprintf("%f", html.Options.PaperMargins[2])
values[marginRight] = fmt.Sprintf("%f", html.Options.PaperMargins[3])
values[landscape] = strconv.FormatBool(html.Options.Landscape)
return values
} }
func (html *HTMLRequest) getFormFiles() map[string]string { func (html *HTMLRequest) getFormFiles() map[string]string {
if html.Options == nil {
html.Options = &HTMLOptions{}
}
files := make(map[string]string) files := make(map[string]string)
files["index.html"] = html.IndexFilePath files["index.html"] = html.indexFilePath
files["header.html"] = html.Options.HeaderFilePath files["header.html"] = html.headerFilePath
files["footer.html"] = html.Options.FooterFilePath files["footer.html"] = html.footerFilePath
for _, fpath := range html.AssetFilePaths { for _, fpath := range html.assetFilePaths {
files[filepath.Base(fpath)] = fpath files[filepath.Base(fpath)] = fpath
} }
return files return files
@@ -75,4 +100,5 @@ func (html *HTMLRequest) getFormFiles() map[string]string {
// Compile-time checks to ensure type implements desired interfaces. // Compile-time checks to ensure type implements desired interfaces.
var ( var (
_ = Request(new(HTMLRequest)) _ = Request(new(HTMLRequest))
_ = ChromeRequest(new(HTMLRequest))
) )

View File

@@ -13,20 +13,21 @@ import (
func TestHTML(t *testing.T) { func TestHTML(t *testing.T) {
c := &Client{Hostname: "http://localhost:3000"} c := &Client{Hostname: "http://localhost:3000"}
req := &HTMLRequest{ req, err := NewHTMLRequest(test.HTMLTestFilePath(t, "index.html"))
IndexFilePath: test.HTMLTestFilePath(t, "index.html"), require.Nil(t, err)
AssetFilePaths: []string{ err = req.SetHeader(test.HTMLTestFilePath(t, "header.html"))
test.HTMLTestFilePath(t, "font.woff"), require.Nil(t, err)
test.HTMLTestFilePath(t, "img.gif"), err = req.SetFooter(test.HTMLTestFilePath(t, "footer.html"))
test.HTMLTestFilePath(t, "style.css"), require.Nil(t, err)
}, err = req.SetAssets([]string{
Options: &HTMLOptions{ test.HTMLTestFilePath(t, "font.woff"),
HeaderFilePath: test.HTMLTestFilePath(t, "header.html"), test.HTMLTestFilePath(t, "img.gif"),
FooterFilePath: test.HTMLTestFilePath(t, "footer.html"), test.HTMLTestFilePath(t, "style.css"),
PaperSize: A4, })
PaperMargins: NormalMargins, require.Nil(t, err)
}, req.SetPaperSize(A4)
} req.SetMargins(NormalMargins)
req.SetLandscape(false)
dirPath, err := rand.Get() dirPath, err := rand.Get()
require.Nil(t, err) require.Nil(t, err)
dest := fmt.Sprintf("%s/foo.pdf", dirPath) dest := fmt.Sprintf("%s/foo.pdf", dirPath)
@@ -36,3 +37,11 @@ func TestHTML(t *testing.T) {
err = os.RemoveAll(dirPath) err = os.RemoveAll(dirPath)
assert.Nil(t, err) assert.Nil(t, err)
} }
func TestConcurrentHTML(t *testing.T) {
for i := 0; i < 10; i++ {
go func() {
TestHTML(t)
}()
}
}

View File

@@ -9,73 +9,102 @@ import (
// MarkdownRequest facilitates Markdown conversion // MarkdownRequest facilitates Markdown conversion
// with the Gotenberg API. // with the Gotenberg API.
type MarkdownRequest struct { type MarkdownRequest struct {
IndexFilePath string indexFilePath string
MarkdownFilePaths []string markdownFilePaths []string
AssetFilePaths []string headerFilePath string
Options *MarkdownOptions footerFilePath string
assetFilePaths []string
values map[string]string
} }
// MarkdownOptions gathers all options // NewMarkdownRequest create MarkdownRequest.
// for Markdown conversion with the Gotenberg API. func NewMarkdownRequest(indexFilePath string, markdownFilePaths []string) (*MarkdownRequest, error) {
type MarkdownOptions struct { if !fileExists(indexFilePath) {
WebHookURL string return nil, fmt.Errorf("%s: index file does not exist", indexFilePath)
HeaderFilePath string
FooterFilePath string
PaperSize [2]float64
PaperMargins [4]float64
Landscape bool
}
func (markdown *MarkdownRequest) validate() error {
if !fileExists(markdown.IndexFilePath) {
return fmt.Errorf("%s: index file does not exist", markdown.IndexFilePath)
} }
if markdown.Options.HeaderFilePath != "" && !fileExists(markdown.Options.HeaderFilePath) { for _, fpath := range markdownFilePaths {
return fmt.Errorf("%s: header file does not exist", markdown.Options.HeaderFilePath)
}
if markdown.Options.FooterFilePath != "" && !fileExists(markdown.Options.FooterFilePath) {
return fmt.Errorf("%s: footer file does not exist", markdown.Options.FooterFilePath)
}
for _, fpath := range markdown.MarkdownFilePaths {
if !fileExists(fpath) { if !fileExists(fpath) {
return fmt.Errorf("%s: markdown file does not exist", fpath) return nil, fmt.Errorf("%s: markdown file does not exist", fpath)
} }
} }
return &MarkdownRequest{
indexFilePath: indexFilePath,
markdownFilePaths: markdownFilePaths,
values: make(map[string]string),
}, nil
}
// SetWebhookURL sets webhookURL form field.
func (markdown *MarkdownRequest) SetWebhookURL(webhookURL string) {
markdown.values[webhookURL] = webhookURL
}
// SetHeader sets header form file.
func (markdown *MarkdownRequest) SetHeader(fpath string) error {
if !fileExists(fpath) {
return fmt.Errorf("%s: header file does not exist", fpath)
}
markdown.headerFilePath = fpath
return nil return nil
} }
// SetFooter sets footer form file.
func (markdown *MarkdownRequest) SetFooter(fpath string) error {
if !fileExists(fpath) {
return fmt.Errorf("%s: footer file does not exist", fpath)
}
markdown.footerFilePath = fpath
return nil
}
// SetAssets sets assets form files.
func (markdown *MarkdownRequest) SetAssets(fpaths []string) error {
for _, fpath := range fpaths {
if !fileExists(fpath) {
return fmt.Errorf("%s: file does not exist", fpath)
}
}
markdown.assetFilePaths = fpaths
return nil
}
// SetPaperSize sets paperWidth and paperHeight form fields.
func (markdown *MarkdownRequest) SetPaperSize(size [2]float64) {
markdown.values[paperWidth] = fmt.Sprintf("%f", size[0])
markdown.values[paperHeight] = fmt.Sprintf("%f", size[1])
}
// SetMargins sets marginTop, marginBottom,
// marginLeft and marginRight form fields.
func (markdown *MarkdownRequest) SetMargins(margins [4]float64) {
markdown.values[marginTop] = fmt.Sprintf("%f", margins[0])
markdown.values[marginBottom] = fmt.Sprintf("%f", margins[1])
markdown.values[marginLeft] = fmt.Sprintf("%f", margins[2])
markdown.values[marginRight] = fmt.Sprintf("%f", margins[3])
}
// SetLandscape sets landscape form field.
func (markdown *MarkdownRequest) SetLandscape(isLandscape bool) {
markdown.values[landscape] = strconv.FormatBool(isLandscape)
}
func (markdown *MarkdownRequest) getPostURL() string { func (markdown *MarkdownRequest) getPostURL() string {
return "/convert/markdown" return "/convert/markdown"
} }
func (markdown *MarkdownRequest) getFormValues() map[string]string { func (markdown *MarkdownRequest) getFormValues() map[string]string {
if markdown.Options == nil { return markdown.values
markdown.Options = &MarkdownOptions{}
}
values := make(map[string]string)
values[webhookURL] = markdown.Options.WebHookURL
values[paperWidth] = fmt.Sprintf("%f", markdown.Options.PaperSize[0])
values[paperHeight] = fmt.Sprintf("%f", markdown.Options.PaperSize[1])
values[marginTop] = fmt.Sprintf("%f", markdown.Options.PaperMargins[0])
values[marginBottom] = fmt.Sprintf("%f", markdown.Options.PaperMargins[1])
values[marginLeft] = fmt.Sprintf("%f", markdown.Options.PaperMargins[2])
values[marginRight] = fmt.Sprintf("%f", markdown.Options.PaperMargins[3])
values[landscape] = strconv.FormatBool(markdown.Options.Landscape)
return values
} }
func (markdown *MarkdownRequest) getFormFiles() map[string]string { func (markdown *MarkdownRequest) getFormFiles() map[string]string {
if markdown.Options == nil {
markdown.Options = &MarkdownOptions{}
}
files := make(map[string]string) files := make(map[string]string)
files["index.html"] = markdown.IndexFilePath files["index.html"] = markdown.indexFilePath
files["header.html"] = markdown.Options.HeaderFilePath files["header.html"] = markdown.headerFilePath
files["footer.html"] = markdown.Options.FooterFilePath files["footer.html"] = markdown.footerFilePath
for _, fpath := range markdown.MarkdownFilePaths { for _, fpath := range markdown.markdownFilePaths {
files[filepath.Base(fpath)] = fpath files[filepath.Base(fpath)] = fpath
} }
for _, fpath := range markdown.AssetFilePaths { for _, fpath := range markdown.assetFilePaths {
files[filepath.Base(fpath)] = fpath files[filepath.Base(fpath)] = fpath
} }
return files return files
@@ -84,4 +113,5 @@ func (markdown *MarkdownRequest) getFormFiles() map[string]string {
// Compile-time checks to ensure type implements desired interfaces. // Compile-time checks to ensure type implements desired interfaces.
var ( var (
_ = Request(new(MarkdownRequest)) _ = Request(new(MarkdownRequest))
_ = ChromeRequest(new(MarkdownRequest))
) )

View File

@@ -13,25 +13,28 @@ import (
func TestMarkdown(t *testing.T) { func TestMarkdown(t *testing.T) {
c := &Client{Hostname: "http://localhost:3000"} c := &Client{Hostname: "http://localhost:3000"}
req := &MarkdownRequest{ req, err := NewMarkdownRequest(
IndexFilePath: test.MarkdownTestFilePath(t, "index.html"), test.MarkdownTestFilePath(t, "index.html"),
MarkdownFilePaths: []string{ []string{
test.MarkdownTestFilePath(t, "paragraph1.md"), test.MarkdownTestFilePath(t, "paragraph1.md"),
test.MarkdownTestFilePath(t, "paragraph2.md"), test.MarkdownTestFilePath(t, "paragraph2.md"),
test.MarkdownTestFilePath(t, "paragraph3.md"), test.MarkdownTestFilePath(t, "paragraph3.md"),
}, },
AssetFilePaths: []string{ )
test.HTMLTestFilePath(t, "font.woff"), require.Nil(t, err)
test.HTMLTestFilePath(t, "img.gif"), err = req.SetHeader(test.MarkdownTestFilePath(t, "header.html"))
test.HTMLTestFilePath(t, "style.css"), require.Nil(t, err)
}, err = req.SetFooter(test.MarkdownTestFilePath(t, "footer.html"))
Options: &MarkdownOptions{ require.Nil(t, err)
HeaderFilePath: test.MarkdownTestFilePath(t, "header.html"), err = req.SetAssets([]string{
FooterFilePath: test.MarkdownTestFilePath(t, "footer.html"), test.MarkdownTestFilePath(t, "font.woff"),
PaperSize: A4, test.MarkdownTestFilePath(t, "img.gif"),
PaperMargins: NormalMargins, test.MarkdownTestFilePath(t, "style.css"),
}, })
} require.Nil(t, err)
req.SetPaperSize(A4)
req.SetMargins(NormalMargins)
req.SetLandscape(false)
dirPath, err := rand.Get() dirPath, err := rand.Get()
require.Nil(t, err) require.Nil(t, err)
dest := fmt.Sprintf("%s/foo.pdf", dirPath) dest := fmt.Sprintf("%s/foo.pdf", dirPath)
@@ -41,3 +44,11 @@ func TestMarkdown(t *testing.T) {
err = os.RemoveAll(dirPath) err = os.RemoveAll(dirPath)
assert.Nil(t, err) assert.Nil(t, err)
} }
func TestConcurrentMarkdown(t *testing.T) {
for i := 0; i < 10; i++ {
go func() {
TestMarkdown(t)
}()
}
}

View File

@@ -8,24 +8,23 @@ import (
// MergeRequest facilitates merging PDF // MergeRequest facilitates merging PDF
// with the Gotenberg API. // with the Gotenberg API.
type MergeRequest struct { type MergeRequest struct {
FilePaths []string filePaths []string
Options *MergeOptions values map[string]string
} }
// MergeOptions gathers all options // NewMergeRequest create MergeRequest.
// for merging PDF func NewMergeRequest(fpaths []string) (*MergeRequest, error) {
// with the Gotenberg API. for _, fpath := range fpaths {
type MergeOptions struct {
WebHookURL string
}
func (merge *MergeRequest) validate() error {
for _, fpath := range merge.FilePaths {
if !fileExists(fpath) { if !fileExists(fpath) {
return fmt.Errorf("%s: PDF file does not exist", fpath) return nil, fmt.Errorf("%s: file does not exist", fpath)
} }
} }
return nil return &MergeRequest{filePaths: fpaths, values: make(map[string]string)}, nil
}
// SetWebhookURL sets webhookURL form field.
func (merge *MergeRequest) SetWebhookURL(webhookURL string) {
merge.values[webhookURL] = webhookURL
} }
func (merge *MergeRequest) getPostURL() string { func (merge *MergeRequest) getPostURL() string {
@@ -33,17 +32,12 @@ func (merge *MergeRequest) getPostURL() string {
} }
func (merge *MergeRequest) getFormValues() map[string]string { func (merge *MergeRequest) getFormValues() map[string]string {
if merge.Options == nil { return merge.values
merge.Options = &MergeOptions{}
}
values := make(map[string]string)
values[webhookURL] = merge.Options.WebHookURL
return values
} }
func (merge *MergeRequest) getFormFiles() map[string]string { func (merge *MergeRequest) getFormFiles() map[string]string {
files := make(map[string]string) files := make(map[string]string)
for _, fpath := range merge.FilePaths { for _, fpath := range merge.filePaths {
files[filepath.Base(fpath)] = fpath files[filepath.Base(fpath)] = fpath
} }
return files return files

View File

@@ -13,12 +13,11 @@ import (
func TestMerge(t *testing.T) { func TestMerge(t *testing.T) {
c := &Client{Hostname: "http://localhost:3000"} c := &Client{Hostname: "http://localhost:3000"}
req := &MergeRequest{ req, err := NewMergeRequest([]string{
FilePaths: []string{ test.PDFTestFilePath(t, "gotenberg.pdf"),
test.PDFTestFilePath(t, "gotenberg.pdf"), test.PDFTestFilePath(t, "gotenberg.pdf"),
test.PDFTestFilePath(t, "gotenberg.pdf"), })
}, require.Nil(t, err)
}
dirPath, err := rand.Get() dirPath, err := rand.Get()
require.Nil(t, err) require.Nil(t, err)
dest := fmt.Sprintf("%s/foo.pdf", dirPath) dest := fmt.Sprintf("%s/foo.pdf", dirPath)
@@ -28,3 +27,11 @@ func TestMerge(t *testing.T) {
err = os.RemoveAll(dirPath) err = os.RemoveAll(dirPath)
assert.Nil(t, err) assert.Nil(t, err)
} }
func TestConcurrentMerge(t *testing.T) {
for i := 0; i < 10; i++ {
go func() {
TestMerge(t)
}()
}
}

View File

@@ -3,29 +3,40 @@ package gotenberg
import ( import (
"fmt" "fmt"
"path/filepath" "path/filepath"
"strconv"
) )
// OfficeRequest facilitates Office documents // OfficeRequest facilitates Office documents
// conversion with the Gotenberg API. // conversion with the Gotenberg API.
type OfficeRequest struct { type OfficeRequest struct {
FilePaths []string filePaths []string
Options *OfficeOptions values map[string]string
} }
// OfficeOptions gathers all options // NewOfficeRequest create OfficeRequest.
// for Office documents conversion func NewOfficeRequest(fpaths []string) (*OfficeRequest, error) {
// with the Gotenberg API. for _, fpath := range fpaths {
type OfficeOptions struct {
WebHookURL string
}
func (office *OfficeRequest) validate() error {
for _, fpath := range office.FilePaths {
if !fileExists(fpath) { if !fileExists(fpath) {
return fmt.Errorf("%s: office file does not exist", fpath) return nil, fmt.Errorf("%s: file does not exist", fpath)
} }
} }
return nil return &OfficeRequest{filePaths: fpaths, values: make(map[string]string)}, nil
}
// SetWebhookURL sets webhookURL form field.
func (office *OfficeRequest) SetWebhookURL(webhookURL string) {
office.values[webhookURL] = webhookURL
}
// SetPaperSize sets paperWidth and paperHeight form fields.
func (office *OfficeRequest) SetPaperSize(size [2]float64) {
office.values[paperWidth] = fmt.Sprintf("%f", size[0])
office.values[paperHeight] = fmt.Sprintf("%f", size[1])
}
// SetLandscape sets landscape form field.
func (office *OfficeRequest) SetLandscape(isLandscape bool) {
office.values[landscape] = strconv.FormatBool(isLandscape)
} }
func (office *OfficeRequest) getPostURL() string { func (office *OfficeRequest) getPostURL() string {
@@ -33,17 +44,12 @@ func (office *OfficeRequest) getPostURL() string {
} }
func (office *OfficeRequest) getFormValues() map[string]string { func (office *OfficeRequest) getFormValues() map[string]string {
if office.Options == nil { return office.values
office.Options = &OfficeOptions{}
}
values := make(map[string]string)
values[webhookURL] = office.Options.WebHookURL
return values
} }
func (office *OfficeRequest) getFormFiles() map[string]string { func (office *OfficeRequest) getFormFiles() map[string]string {
files := make(map[string]string) files := make(map[string]string)
for _, fpath := range office.FilePaths { for _, fpath := range office.filePaths {
files[filepath.Base(fpath)] = fpath files[filepath.Base(fpath)] = fpath
} }
return files return files
@@ -52,4 +58,5 @@ func (office *OfficeRequest) getFormFiles() map[string]string {
// Compile-time checks to ensure type implements desired interfaces. // Compile-time checks to ensure type implements desired interfaces.
var ( var (
_ = Request(new(OfficeRequest)) _ = Request(new(OfficeRequest))
_ = UnoconvRequest(new(OfficeRequest))
) )

View File

@@ -13,11 +13,12 @@ import (
func TestOffice(t *testing.T) { func TestOffice(t *testing.T) {
c := &Client{Hostname: "http://localhost:3000"} c := &Client{Hostname: "http://localhost:3000"}
req := &OfficeRequest{ req, err := NewOfficeRequest([]string{
FilePaths: []string{ test.OfficeTestFilePath(t, "document.docx"),
test.OfficeTestFilePath(t, "document.docx"), })
}, require.Nil(t, err)
} req.SetPaperSize(A4)
req.SetLandscape(false)
dirPath, err := rand.Get() dirPath, err := rand.Get()
require.Nil(t, err) require.Nil(t, err)
dest := fmt.Sprintf("%s/foo.pdf", dirPath) dest := fmt.Sprintf("%s/foo.pdf", dirPath)
@@ -27,3 +28,11 @@ func TestOffice(t *testing.T) {
err = os.RemoveAll(dirPath) err = os.RemoveAll(dirPath)
assert.Nil(t, err) assert.Nil(t, err)
} }
func TestConcurrentOffice(t *testing.T) {
for i := 0; i < 10; i++ {
go func() {
TestOffice(t)
}()
}
}

View File

@@ -2,10 +2,10 @@
set -e set -e
GOLANG_VERSION=1.11.2 GOLANG_VERSION="$1"
VERSION="$1" VERSION="$2"
DOCKER_USER="$2" DOCKER_USER="$3"
DOCKER_PASSWORD="$3" DOCKER_PASSWORD="$4"
docker login -u "$DOCKER_USER" -p "$DOCKER_PASSWORD" docker login -u "$DOCKER_USER" -p "$DOCKER_PASSWORD"

2196
test/testdata/office/document.rtf vendored Normal file

File diff suppressed because it is too large Load Diff

3
test/testdata/office/document.txt vendored Normal file
View File

@@ -0,0 +1,3 @@
Gutenberg
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

BIN
test/testdata/pdf/gotenberg_bis.pdf vendored Normal file

Binary file not shown.