Compare commits

...

21 Commits
3.2.0 ... 4.4.0

Author SHA1 Message Date
Julien Neuhart
df357c1008 fixing typo in documentation 2019-03-26 17:37:25 +01:00
Julien Neuhart
871b52a288 adding filename form field + updating echo package to v4 (#57) 2019-03-26 17:35:38 +01:00
Julien Neuhart
8a4a043e9f fixing documentation about go library 2019-03-15 17:15:47 +01:00
Julien Neuhart
c0297aa061 removing go client library => now available at github.com/thecodingmachine/gotenberg-go-client 2019-03-15 17:07:51 +01:00
Julien Neuhart
2aaa2eeaff Merge branch 'master' of https://github.com/thecodingmachine/gotenberg 2019-03-14 16:39:18 +01:00
Julien Neuhart
5f62e5bacf removing 'v' from tag 2019-03-14 16:39:08 +01:00
Alexander Joseph Trelore
ab78559710 remove unused imports (#55)
Thanks!
2019-03-13 10:53:20 +01:00
Julien Neuhart
0d75bb1d3e improving documentation on merge 2019-03-05 11:27:25 +01:00
Julien Neuhart
6441062e7f adding Google analytics 2019-02-19 15:27:20 +01:00
Julien Neuhart
4827a45f22 adding flat open document support (fixes #47) 2019-02-18 13:46:58 +01:00
Julien Neuhart
40eef457ab adding latest tag (fixes #48) 2019-02-18 13:44:30 +01:00
Julien Neuhart
c22a4d109b minor fix in doc for web fonts 2019-02-01 11:22:06 +01:00
Julien Neuhart
571c3e04c4 adding form field web fonts timeout 2019-02-01 09:40:16 +01:00
Sergei Opletaev
f9fb97a572 Fix for #44 promise wait for fonts (#45)
`runtime.ExceptionDetails: Uncaught exception at 4:47: SyntaxError: Unexpected token %`
2019-02-01 09:21:02 +01:00
Julien Neuhart
e6484bb2d5 Trigger GitHub documentation 2019-01-28 15:56:13 +01:00
Julien Neuhart
19f51fdc1f fixing PHP documentation 2019-01-28 15:36:59 +01:00
Julien Neuhart
25f7ba3ee6 4.0.0 (#42)
* adding URL conversions

* updating gotenberg version in documentation

* pkg: input as variadic string (#39)

* pkg: input as variadic string

* pkg: fix link to github doc

* update doc about v4 client

* make doc

* fixing missing variadic inputs in doc

* adding more fonts

* updating PHP documentation
2019-01-28 15:18:12 +01:00
Julien Neuhart
a3cd1ff4e1 Merge pull request #41 from thecodingmachine/office-paperSize
removing paper size for Office conversion
2019-01-25 15:57:25 +01:00
Julien Neuhart
f62c717f79 fixing typo in docs 2019-01-25 15:50:15 +01:00
Julien Neuhart
3ed99133d4 removing paper size for Office conversion 2019-01-25 15:48:40 +01:00
Julien Neuhart
ab25cc331d fixes #35 2019-01-25 15:02:18 +01:00
56 changed files with 698 additions and 1005 deletions

View File

@@ -8,7 +8,7 @@ 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. Verify your Go version (>= 1.11) 2. Verify your Go version (>= 1.12)
3. Fork this repository 3. Fork this repository
4. Clone it outside of your `GOPATH` (we're using Go modules) 4. Clone it outside of your `GOPATH` (we're using Go modules)

View File

@@ -1,4 +1,4 @@
GOLANG_VERSION=1.11.2 GOLANG_VERSION=1.12
VERSION=snapshot VERSION=snapshot
DOCKER_USER= DOCKER_USER=
DOCKER_PASSWORD= DOCKER_PASSWORD=
@@ -11,6 +11,7 @@ doc:
# gofmt and goimports all go files. # gofmt and goimports all go files.
fmt: fmt:
go fmt ./... go fmt ./...
go mod tidy
# run all linters. # run all linters.
lint: lint:

View File

@@ -16,14 +16,14 @@ At TheCodingMachine, we build a lot of web applications (intranets, extranets an
* 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!
* Easily interact with the API using our [Go](/pkg) and [PHP](https://github.com/thecodingmachine/gotenberg-php-client) libraries * Easily interact with the API using our [Go](https://github.com/thecodingmachine/gotenberg-go-client) and [PHP](https://github.com/thecodingmachine/gotenberg-php-client) libraries
## Quick start ## Quick start
Open a terminal and run the following command: Open a terminal and run the following command:
```bash ```bash
$ docker run --rm -p 3000:3000 thecodingmachine/gotenberg:3 $ docker run --rm -p 3000:3000 thecodingmachine/gotenberg:4
``` ```
The API is now available on your host at `http://localhost:3000`. The API is now available on your host at `http://localhost:3000`.
@@ -33,7 +33,7 @@ to learn how to interact with it!
## Badges ## Badges
[![Docker image layers](https://images.microbadger.com/badges/image/thecodingmachine/gotenberg:3.svg)](https://microbadger.com/images/thecodingmachine/gotenberg:3) [![Docker image layers](https://images.microbadger.com/badges/image/thecodingmachine/gotenberg:4.svg)](https://microbadger.com/images/thecodingmachine/gotenberg:4)
[![Travis CI](https://travis-ci.org/thecodingmachine/gotenberg.svg?branch=master)](https://travis-ci.org/thecodingmachine/gotenberg) [![Travis CI](https://travis-ci.org/thecodingmachine/gotenberg.svg?branch=master)](https://travis-ci.org/thecodingmachine/gotenberg)
[![GoDoc](https://godoc.org/github.com/thecodingmachine/gotenberg?status.svg)](https://godoc.org/github.com/thecodingmachine/gotenberg) [![GoDoc](https://godoc.org/github.com/thecodingmachine/gotenberg?status.svg)](https://godoc.org/github.com/thecodingmachine/gotenberg)
[![Go Report Card](https://goreportcard.com/badge/github.com/thecodingmachine/gotenberg)](https://goreportcard.com/report/thecodingmachine/gotenberg) [![Go Report Card](https://goreportcard.com/badge/github.com/thecodingmachine/gotenberg)](https://goreportcard.com/report/thecodingmachine/gotenberg)

View File

@@ -1,3 +1,4 @@
FROM thecodingmachine/gotenberg:3.2.0 AS hack
FROM debian:9.5-slim FROM debian:9.5-slim
# |-------------------------------------------------------------------------- # |--------------------------------------------------------------------------
@@ -9,7 +10,7 @@ FROM debian:9.5-slim
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 python3-pip apt-get install -y curl wget python3-pip ttf-mscorefonts-installer
# |-------------------------------------------------------------------------- # |--------------------------------------------------------------------------
# | PM2 # | PM2
@@ -19,7 +20,19 @@ RUN echo "deb http://httpredir.debian.org/debian/ stretch main contrib non-free"
# | recovering. In our case: Chrome (headless) and Office (headless). # | recovering. In our case: Chrome (headless) and Office (headless).
# | # |
RUN curl -sL https://raw.githubusercontent.com/Unitech/pm2/master/packager/setup.deb.sh | bash - # Yep, this is dirty. The following script does not work anymore (see https://github.com/Unitech/pm2/issues/4127).
#RUN curl -sL https://raw.githubusercontent.com/Unitech/pm2/master/packager/setup.deb.sh | bash -
# Installing PM2 with Node.js and npm breaks something which prevents Google Chrome to work as expected.
# So we just copy all PM2 related files from a previous version of Gotenberg.
RUN curl -sL https://deb.nodesource.com/setup_9.x | bash - &&\
apt-get install -y nodejs
COPY --from=hack /usr/bin/pm2 /usr/bin/pm2
COPY --from=hack /usr/share/pm2 /usr/share/pm2
COPY --from=hack /etc/default/pm2 /etc/default/pm2
COPY --from=hack /etc/systemd/system/pm2.service /etc/systemd/system/pm2.service
# |-------------------------------------------------------------------------- # |--------------------------------------------------------------------------
# | Chrome # | Chrome
@@ -53,4 +66,39 @@ RUN pip3 install unoconv &&\
# | https://github.com/thecodingmachine/gotenberg/issues/29 # | https://github.com/thecodingmachine/gotenberg/issues/29
# | # |
RUN apt-get -y install pdftk RUN apt-get -y install pdftk
# |--------------------------------------------------------------------------
# | Fonts
# |--------------------------------------------------------------------------
# |
# | Installs a handful of fonts.
# | Note: ttf-mscorefonts-installer are installed on top of this Dockerfile.
# |
# Credits:
# https://github.com/arachnys/athenapdf/blob/master/cli/Dockerfile
# https://help.accusoft.com/PrizmDoc/v12.1/HTML/Installing_Asian_Fonts_on_Ubuntu_and_Debian.html
RUN apt-get install -y \
culmus \
fonts-beng \
fonts-hosny-amiri \
fonts-lklug-sinhala \
fonts-lohit-guru \
fonts-lohit-knda \
fonts-samyak-gujr \
fonts-samyak-mlym \
fonts-samyak-taml \
fonts-sarai \
fonts-sil-abyssinica \
fonts-sil-padauk \
fonts-telu \
fonts-thai-tlwg \
ttf-liberation \
ttf-wqy-zenhei \
fonts-arphic-uming \
fonts-ipafont-mincho \
fonts-ipafont-gothic \
fonts-unfonts-core
COPY build/base/fonts.conf /etc/fonts/conf.d/100-gotenberg.conf

29
build/base/fonts.conf Normal file
View File

@@ -0,0 +1,29 @@
<?xml version='1.0'?>
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>
<match target="font">
<edit mode="assign" name="rgba">
<const>rgb</const>
</edit>
</match>
<match target="font">
<edit mode="assign" name="hinting">
<bool>true</bool>
</edit>
</match>
<match target="font">
<edit mode="assign" name="hintstyle">
<const>hintslight</const>
</edit>
</match>
<match target="font">
<edit mode="assign" name="antialias">
<bool>true</bool>
</edit>
</match>
<match target="font">
<edit mode="assign" name="lcdfilter">
<const>lcddefault</const>
</edit>
</match>
</fontconfig>

View File

@@ -9,4 +9,4 @@ title: Introduction
* 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!
* Easily interact with the API using our [Go](https://github.com/thecodingmachine/gotenberg/pkg) and [PHP](https://github.com/thecodingmachine/gotenberg-php-client) libraries * Easily interact with the API using our [Go](https://github.com/thecodingmachine/gotenberg-go-client) and [PHP](https://github.com/thecodingmachine/gotenberg-php-client) libraries

View File

@@ -7,7 +7,7 @@ Gotenberg is shipped within a Docker image.
You may start it with: You may start it with:
```bash ```bash
$ docker run --rm -p 3000:3000 thecodingmachine/gotenberg:3 $ docker run --rm -p 3000:3000 thecodingmachine/gotenberg:4
``` ```
> The API will be available at [http://localhost:3000](http://localhost:3000). > The API will be available at [http://localhost:3000](http://localhost:3000).
@@ -22,7 +22,7 @@ services:
# your others services # your others services
gotenberg: gotenberg:
image: thecodingmachine/gotenberg:3 image: thecodingmachine/gotenberg:4
``` ```
> The API will be available under `gotenberg:3000` in your Docker Compose network. > The API will be available under `gotenberg:3000` in your Docker Compose network.
@@ -35,7 +35,7 @@ Gotenberg API is available at [http://localhost:3000](http://localhost:3000).
## Go client ## Go client
```bash ```bash
$ go get -u github.com/thecodingmachine/gotenberg $ go get -u github.com/thecodingmachine/gotenberg-go-client/v4
``` ```
## PHP client ## PHP client

View File

@@ -39,7 +39,7 @@ $ curl --request POST \
### Go ### Go
```golang ```golang
import "github.com/thecodingmachine/gotenberg/pkg" import "github.com/thecodingmachine/gotenberg-go-client/v4"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
@@ -113,7 +113,7 @@ $ curl --request POST \
### Go ### Go
```golang ```golang
import "github.com/thecodingmachine/gotenberg/pkg" import "github.com/thecodingmachine/gotenberg-go-client/v4"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
@@ -185,7 +185,10 @@ But this won't:
You may also use *remote* paths for Google fonts, images and so on. You may also use *remote* paths for Google fonts, images and so on.
> If you want to install fonts directly in the Gotenberg Docker image, > If you want to install fonts directly in the Gotenberg Docker image,
> see to the [fonts section](#office.fonts). > see to the [fonts section](#fonts).
>
> For web fonts (Google fonts), there is a timeout of 500ms by default. You may update
> this value thanks to the form field `webFontsTimeout`.
### cURL ### cURL
@@ -203,16 +206,12 @@ $ curl --request POST \
### Go ### Go
```golang ```golang
import "github.com/thecodingmachine/gotenberg/pkg" import "github.com/thecodingmachine/gotenberg-go-client/v4"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req, _ := gotenberg.NewHTMLRequest("index.html") req, _ := gotenberg.NewHTMLRequest("index.html")
req.SetAssets([]string{ req.SetAssets("font.woff", "img.gif", "style.css")
"font.woff",
"img.gif",
"style.css",
})
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }
@@ -234,8 +233,8 @@ $assets = [
]; ];
$request = new HTMLRequest($index); $request = new HTMLRequest($index);
$request->setAssets($assets); $request->setAssets($assets);
$dirPath = "/foo"; $dest = "result.pdf";
$filename = $client->store($request, $dirPath); $client->store($request, $dest);
``` ```
## Paper size, margins, orientation ## Paper size, margins, orientation
@@ -267,7 +266,7 @@ $ curl --request POST \
### Go ### Go
```golang ```golang
import "github.com/thecodingmachine/gotenberg/pkg" import "github.com/thecodingmachine/gotenberg-go-client/v4"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
@@ -294,6 +293,6 @@ $request = new HTMLRequest($index);
$request->setPaperSize(Request::A4); $request->setPaperSize(Request::A4);
$request->setMargins(Request::NO_MARGINS); $request->setMargins(Request::NO_MARGINS);
$request->setLandscape(true); $request->setLandscape(true);
$dirPath = "/foo"; $dest = "result.pdf";
$filename = $client->store($request, $dirPath); $client->store($request, $dest);
``` ```

View File

@@ -0,0 +1,56 @@
---
title: URL
---
Gotenberg provides the endpoint `/convert/url` for remote URL conversions.
It accepts `POST` requests with a `multipart/form-data` Content-Type.
## Basic
This endpoint does not accept an `index.html` file nor assets files but a form field
named `remoteURL` instead. Otherwise, URL conversions work the same as HTML conversions.
> **Attention:** when converting a website to PDF, you should remove all margins.
> If not, some of the content of the page might be hidden.
### cURL
```bash
$ curl --request POST \
--url http://localhost:3000/convert/url \
--header 'Content-Type: multipart/form-data' \
--form remoteURL=https://google.com
--form marginTop=0 \
--form marginBottom=0 \
--form marginLeft=0 \
--form marginRight=0 \
-o result.pdf
```
### Go
```golang
import "github.com/thecodingmachine/gotenberg-go-client/v4"
func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := gotenberg.NewURLRequest("https://google.com")
req.SetMargins(gotenberg.NoMargins)
dest := "result.pdf"
c.Store(req, dest)
}
```
### PHP
```php
use TheCodingMachine\Gotenberg\Client;
use TheCodingMachine\Gotenberg\URLRequest;
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
$request = new URLRequest('https://google.com');
$request->setMargins(Request::NO_MARGINS);
$dest = "result.pdf";
$client->store($request, $dest);
```

View File

@@ -42,11 +42,11 @@ $ curl --request POST \
### Go ### Go
```golang ```golang
import "github.com/thecodingmachine/gotenberg/pkg" import "github.com/thecodingmachine/gotenberg-go-client/v4"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req, _ := gotenberg.NewMarkdownRequest("index.html", []string{"file.md"}) req, _ := gotenberg.NewMarkdownRequest("index.html", "file.md")
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }
@@ -65,6 +65,6 @@ $markdowns = [
DocumentFactory::makeFromPath('file.md', 'file.md'), DocumentFactory::makeFromPath('file.md', 'file.md'),
]; ];
$request = new MarkdownRequest($index, $markdowns); $request = new MarkdownRequest($index, $markdowns);
$dirPath = "/foo"; $dest = "result.pdf";
$filename = $client->store($request, $dirPath); $client->store($request, $dest);
``` ```

View File

@@ -12,6 +12,7 @@ You may send one or more Office documents. Following file extensions are accepte
* `.txt` * `.txt`
* `.rtf` * `.rtf`
* `.fodt`
* `.doc` * `.doc`
* `.docx` * `.docx`
* `.odt` * `.odt`
@@ -42,11 +43,11 @@ $ curl --request POST \
### Go ### Go
```golang ```golang
import "github.com/thecodingmachine/gotenberg/pkg" import "github.com/thecodingmachine/gotenberg-go-client/v4"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req, _ := gotenberg.NewOfficeRequest([]string{"document.docx", "document2.docx"}) req, _ := gotenberg.NewOfficeRequest("document.docx", "document2.docx")
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }
@@ -65,18 +66,15 @@ $files = [
DocumentFactory::makeFromPath('document2.docx', 'document2.docx'), DocumentFactory::makeFromPath('document2.docx', 'document2.docx'),
]; ];
$request = new OfficeRequest($files); $request = new OfficeRequest($files);
$dirPath = "/foo"; $dest = "result.pdf";
$filename = $client->store($request, $dirPath); $client->store($request, $dest);
``` ```
## Paper size and orientation ## Orientation
You may also customize the resulting PDF format. You may also customize the resulting PDF format.
By default, it will be rendered with `A4` size and `portrait` orientation. By default, it will be rendered with `portrait` orientation.
> Paper size has to be provided in `inches`.
> Also, you have to set both `paperWidth` and `paperHeight`.
### cURL ### cURL
@@ -85,8 +83,6 @@ $ curl --request POST \
--url http://localhost:3000/convert/office \ --url http://localhost:3000/convert/office \
--header 'Content-Type: multipart/form-data' \ --header 'Content-Type: multipart/form-data' \
--form files=@document.docx \ --form files=@document.docx \
--form paperWidth=8.27 \
--form paperHeight=11.27 \
--form landscape=true \ --form landscape=true \
-o result.pdf -o result.pdf
``` ```
@@ -94,12 +90,11 @@ $ curl --request POST \
### Go ### Go
```golang ```golang
import "github.com/thecodingmachine/gotenberg/pkg" import "github.com/thecodingmachine/gotenberg-go-client/v4"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req, _ := gotenberg.NewOfficeRequest([]string{"document.docx"}) req, _ := gotenberg.NewOfficeRequest("document.docx")
req.SetPaperSize(gotenberg.A4)
req.SetLandscape(true) req.SetLandscape(true)
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
@@ -118,20 +113,7 @@ $files = [
DocumentFactory::makeFromPath('document.docx', 'document.docx'), DocumentFactory::makeFromPath('document.docx', 'document.docx'),
]; ];
$request = new OfficeRequest($files); $request = new OfficeRequest($files);
$request->setPaperSize(Request::A4);
$request->setLandscape(true); $request->setLandscape(true);
$dirPath = "/foo"; $dest = "result.pdf";
$filename = $client->store($request, $dirPath); $client->store($request, $dest);
```
## Fonts
By default, only `ttf-mscorefonts` fonts are installed.
If you wish to use more fonts, you will have to create your own image:
```Dockerfile
FROM thecodingmachine/gotenberg:3
RUN apt-get -y install yourfonts
``` ```

View File

@@ -8,9 +8,11 @@ It accepts `POST` requests with a `multipart/form-data` Content-Type.
## Basic ## Basic
Nothing special here: you may send one or more PDF files and the API Nothing fancy here: you may send one or more PDF files and the API
will merge them and return the resulting PDF file. will merge them and return the resulting PDF file.
> **Attention:** Gotenberg merges the PDF files alphabetically.
### cURL ### cURL
```bash ```bash
@@ -25,11 +27,11 @@ $ curl --request POST \
### Go ### Go
```golang ```golang
import "github.com/thecodingmachine/gotenberg/pkg" import "github.com/thecodingmachine/gotenberg-go-client/v4"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req, _ := gotenberg.NewMergeRequest([]string{"file.pdf", "file2.pdf"}) req, _ := gotenberg.NewMergeRequest("file.pdf", "file2.pdf")
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }
@@ -48,6 +50,6 @@ $files = [
DocumentFactory::makeFromPath('file2.pdf', 'file2.pdf'), DocumentFactory::makeFromPath('file2.pdf', 'file2.pdf'),
]; ];
$request = new MergeRequest($files); $request = new MergeRequest($files);
$dirPath = "/foo"; $dest = "result.pdf";
$filename = $client->store($request, $dirPath); $client->store($request, $dest);
``` ```

View File

@@ -24,7 +24,7 @@ $ curl --request POST \
### Go ### Go
```golang ```golang
import "github.com/thecodingmachine/gotenberg/pkg" import "github.com/thecodingmachine/gotenberg-go-client/v4"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}

View File

@@ -0,0 +1,27 @@
---
title: Filename
---
All endpoints accept a form field named `filename`.
If provided, the API will return the resulting PDF file with the given filename.
Otherwise a random filename is used.
> The Go and PHP libraries do not provide a way to set this form field.
> However, you may hijack the response from the API or store the resulting PDF
> using a custom filename.
>
> **Attention:** this feature does not work if the form field `webhookURL` is given.
## Examples
### cURL
```bash
$ curl --request POST \
--url http://localhost:3000/convert/html \
--header 'Content-Type: multipart/form-data' \
--form files=@index.html \
--form filename='result.pdf' \
-o result.pdf
```

View File

@@ -14,7 +14,7 @@ services:
# your others services # your others services
gotenberg: gotenberg:
image: thecodingmachine/gotenberg:3 image: thecodingmachine/gotenberg:4
``` ```
You may now launch your services using: You may now launch your services using:

View File

@@ -0,0 +1,13 @@
---
title: Fonts
---
By default, a handful of fonts are installed. Asian characters are also supported out of the box.
If you wish to use more fonts, you will have to create your own image:
```Dockerfile
FROM thecodingmachine/gotenberg:4
RUN apt-get -y install yourfonts
```

View File

@@ -10,7 +10,7 @@ FROM golang:${GOLANG_VERSION}-stretch
# | than gometalinter. # | than gometalinter.
# | # |
ENV GOLANGCI_LINT_VERSION 1.12.3 ENV GOLANGCI_LINT_VERSION 1.15.0
RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b /usr/local/bin v${GOLANGCI_LINT_VERSION} &&\ RUN curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b /usr/local/bin v${GOLANGCI_LINT_VERSION} &&\
golangci-lint --version golangci-lint --version

View File

@@ -45,4 +45,4 @@ COPY go.sum .
# Install module dependencies. # Install module dependencies.
RUN go mod download RUN go mod download
ENTRYPOINT ["build/tests/docker-entrypoint.sh"] ENTRYPOINT [ "build/tests/docker-entrypoint.sh" ]

View File

@@ -15,11 +15,4 @@ go test -race -cover -covermode=atomic github.com/thecodingmachine/gotenberg/int
# Finally testing processes shutdown. # Finally testing processes shutdown.
go test github.com/thecodingmachine/gotenberg/internal/pkg/pm2 -run TestChromeShutdown go test github.com/thecodingmachine/gotenberg/internal/pkg/pm2 -run TestChromeShutdown
go test github.com/thecodingmachine/gotenberg/internal/pkg/pm2 -run TestUnoconvShutdown go test github.com/thecodingmachine/gotenberg/internal/pkg/pm2 -run TestUnoconvShutdown
# Testing Go client.
go build -o /usr/local/bin/gotenberg cmd/gotenberg/main.go
gotenberg &
sleep 10
go test -race -cover -covermode=atomic github.com/thecodingmachine/gotenberg/pkg
sleep 5 # allows Gotenberg to remove generated files (concurrent requests).

View File

@@ -1,4 +1,13 @@
<!DOCTYPE html><html><head> <!DOCTYPE html><html><head>
<script async="" src="https://www.googletagmanager.com/gtag/js?id=UA-10196481-9"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-10196481-9');
</script>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<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"/>
@@ -45,6 +54,10 @@
<a href="#html">HTML</a> <a href="#html">HTML</a>
</div> </div>
<div class="item">
<a href="#url">URL</a>
</div>
<div class="item"> <div class="item">
<a href="#markdown">Markdown</a> <a href="#markdown">Markdown</a>
</div> </div>
@@ -61,6 +74,10 @@
<a href="#webhook">Webhook</a> <a href="#webhook">Webhook</a>
</div> </div>
<div class="item">
<a href="#filename">Filename</a>
</div>
<div class="item"> <div class="item">
<a href="#scalability">Scalability</a> <a href="#scalability">Scalability</a>
</div> </div>
@@ -69,6 +86,10 @@
<a href="#liveness">Liveness</a> <a href="#liveness">Liveness</a>
</div> </div>
<div class="item">
<a href="#fonts">Fonts</a>
</div>
<div class="item"> <div class="item">
<a href="#links">Links</a> <a href="#links">Links</a>
</div> </div>
@@ -90,7 +111,7 @@
<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>
<li>Easily interact with the API using our <a href="https://github.com/thecodingmachine/gotenberg/pkg">Go</a> and <a href="https://github.com/thecodingmachine/gotenberg-php-client">PHP</a> libraries</li> <li>Easily interact with the API using our <a href="https://github.com/thecodingmachine/gotenberg-go-client">Go</a> and <a href="https://github.com/thecodingmachine/gotenberg-php-client">PHP</a> libraries</li>
</ul> </ul>
</div> </div>
@@ -103,7 +124,7 @@
<p>You may start it with:</p> <p>You may start it with:</p>
<pre class="chroma">$ docker run --rm -p <span class="m">3000</span>:3000 thecodingmachine/gotenberg:3 <pre class="chroma">$ docker run --rm -p <span class="m">3000</span>:3000 thecodingmachine/gotenberg:4
</pre> </pre>
<blockquote> <blockquote>
@@ -119,7 +140,7 @@
</span><span class="w"> </span><span class="c"># your others services</span><span class="w"> </span><span class="w"> </span><span class="c"># your others services</span><span class="w">
</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">4</span><span class="w">
</span></pre> </span></pre>
<blockquote> <blockquote>
@@ -135,7 +156,7 @@ Gotenberg API is available at <a href="http://localhost:3000">http://localhost:3
<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>Go client</h2> </a>Go client</h2>
<pre class="chroma">$ go get -u github.com/thecodingmachine/gotenberg <pre class="chroma">$ go get -u github.com/thecodingmachine/gotenberg-go-client/v4
</pre> </pre>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="install.php_client" href="#install.php_client"> <h2 class="Heading"><a class="Anchor" aria-hidden="true" id="install.php_client" href="#install.php_client">
@@ -198,7 +219,7 @@ 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>Go</h3> </a>Go</h3>
<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-go-client/v4&#34;</span>
<span class="kd">func</span> <span class="nf">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>
@@ -280,7 +301,7 @@ 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>Go</h3> </a>Go</h3>
<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-go-client/v4&#34;</span>
<span class="kd">func</span> <span class="nf">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>
@@ -354,7 +375,10 @@ are on the same level as the <code>index.html</code> file.</p>
<blockquote> <blockquote>
<p>If you want to install fonts directly in the Gotenberg Docker image, <p>If you want to install fonts directly in the Gotenberg Docker image,
see to the <a href="#office.fonts">fonts section</a>.</p> see to the <a href="#fonts">fonts section</a>.</p>
<p>For web fonts (Google fonts), there is a timeout of 500ms by default. You may update
this value thanks to the form field <code>webFontsTimeout</code>.</p>
</blockquote> </blockquote>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets.c_url" href="#html.assets.c_url"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets.c_url" href="#html.assets.c_url">
@@ -375,16 +399,12 @@ 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>Go</h3> </a>Go</h3>
<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-go-client/v4&#34;</span>
<span class="kd">func</span> <span class="nf">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="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">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">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">req</span><span class="p">.</span><span class="nf">SetAssets</span><span class="p">(</span><span class="s">&#34;font.woff&#34;</span><span class="p">,</span> <span class="s">&#34;img.gif&#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="s">&#34;img.gif&#34;</span><span class="p">,</span>
<span class="s">&#34;style.css&#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="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="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>
@@ -407,8 +427,8 @@ $assets = [
]; ];
$request = new HTMLRequest($index); $request = new HTMLRequest($index);
$request-&gt;setAssets($assets); $request-&gt;setAssets($assets);
$dirPath = &#34;/foo&#34;; $dest = &#34;result.pdf&#34;;
$filename = $client-&gt;store($request, $dirPath); $client-&gt;store($request, $dest);
</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">
@@ -446,7 +466,7 @@ 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>Go</h3> </a>Go</h3>
<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-go-client/v4&#34;</span>
<span class="kd">func</span> <span class="nf">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>
@@ -474,8 +494,74 @@ $request = new HTMLRequest($index);
$request-&gt;setPaperSize(Request::A4); $request-&gt;setPaperSize(Request::A4);
$request-&gt;setMargins(Request::NO_MARGINS); $request-&gt;setMargins(Request::NO_MARGINS);
$request-&gt;setLandscape(true); $request-&gt;setLandscape(true);
$dirPath = &#34;/foo&#34;; $dest = &#34;result.pdf&#34;;
$filename = $client-&gt;store($request, $dirPath); $client-&gt;store($request, $dest);
</pre>
</div>
<div class="Page" id="url">
<h1 class="Heading"><a class="Anchor" aria-hidden="true" id="url" href="#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>URL</h1>
<p>Gotenberg provides the endpoint <code>/convert/url</code> for remote URL conversions.</p>
<p>It accepts <code>POST</code> requests with a <code>multipart/form-data</code> Content-Type.</p>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="url.basic" href="#url.basic">
<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>Basic</h2>
<p>This endpoint does not accept an <code>index.html</code> file nor assets files but a form field
named <code>remoteURL</code> instead. Otherwise, URL conversions work the same as HTML conversions.</p>
<blockquote>
<p><strong>Attention:</strong> when converting a website to PDF, you should remove all margins.
If not, some of the content of the page might be hidden.</p>
</blockquote>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="url.basic.c_url" href="#url.basic.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/url <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">remoteURL</span><span class="o">=</span>https://google.com
--form <span class="nv">marginTop</span><span class="o">=</span><span class="m">0</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">marginBottom</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> -o result.pdf
</pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="url.basic.go" href="#url.basic.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-go-client/v4&#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="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewURLRequest</span><span class="p">(</span><span class="s">&#34;https://google.com&#34;</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">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="url.basic.php" href="#url.basic.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\URLRequest;
$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
$request = new URLRequest(&#39;https://google.com&#39;);
$request-&gt;setMargins(Request::NO_MARGINS);
$dest = &#34;result.pdf&#34;;
$client-&gt;store($request, $dest);
</pre> </pre>
</div> </div>
@@ -527,11 +613,11 @@ 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>Go</h3> </a>Go</h3>
<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-go-client/v4&#34;</span>
<span class="kd">func</span> <span class="nf">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="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">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="s">&#34;file.md&#34;</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="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="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>
@@ -551,8 +637,8 @@ $markdowns = [
DocumentFactory::makeFromPath(&#39;file.md&#39;, &#39;file.md&#39;), DocumentFactory::makeFromPath(&#39;file.md&#39;, &#39;file.md&#39;),
]; ];
$request = new MarkdownRequest($index, $markdowns); $request = new MarkdownRequest($index, $markdowns);
$dirPath = &#34;/foo&#34;; $dest = &#34;result.pdf&#34;;
$filename = $client-&gt;store($request, $dirPath); $client-&gt;store($request, $dest);
</pre> </pre>
</div> </div>
@@ -574,6 +660,7 @@ $filename = $client-&gt;store($request, $dirPath);
<ul> <ul>
<li><code>.txt</code></li> <li><code>.txt</code></li>
<li><code>.rtf</code></li> <li><code>.rtf</code></li>
<li><code>.fodt</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>
@@ -609,11 +696,11 @@ 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>Go</h3> </a>Go</h3>
<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-go-client/v4&#34;</span>
<span class="kd">func</span> <span class="nf">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="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">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="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">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="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="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>
@@ -633,24 +720,19 @@ $files = [
DocumentFactory::makeFromPath(&#39;document2.docx&#39;, &#39;document2.docx&#39;), DocumentFactory::makeFromPath(&#39;document2.docx&#39;, &#39;document2.docx&#39;),
]; ];
$request = new OfficeRequest($files); $request = new OfficeRequest($files);
$dirPath = &#34;/foo&#34;; $dest = &#34;result.pdf&#34;;
$filename = $client-&gt;store($request, $dirPath); $client-&gt;store($request, $dest);
</pre> </pre>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="office.paper_size_and_orientation" href="#office.paper_size_and_orientation"> <h2 class="Heading"><a class="Anchor" aria-hidden="true" id="office.orientation" href="#office.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>
</a>Paper size and orientation</h2> </a>Orientation</h2>
<p>You may also customize the resulting PDF format.</p> <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> <p>By default, it will be rendered with <code>portrait</code> orientation.</p>
<blockquote> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.orientation.c_url" href="#office.orientation.c_url">
<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> <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> </a>cURL</h3>
@@ -658,29 +740,26 @@ Also, you have to set both <code>paperWidth</code> and <code>paperHeight</code>.
</span><span class="se"></span> --url http://localhost:3000/convert/office <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> --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">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> --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 </span><span class="se"></span> -o result.pdf
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.paper_size_and_orientation.go" href="#office.paper_size_and_orientation.go"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.orientation.go" href="#office.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> <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> </a>Go</h3>
<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-go-client/v4&#34;</span>
<span class="kd">func</span> <span class="nf">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="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="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="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">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">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="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>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.paper_size_and_orientation.php" href="#office.paper_size_and_orientation.php"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.orientation.php" href="#office.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> <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>
@@ -693,25 +772,11 @@ $files = [
DocumentFactory::makeFromPath(&#39;document.docx&#39;, &#39;document.docx&#39;), DocumentFactory::makeFromPath(&#39;document.docx&#39;, &#39;document.docx&#39;),
]; ];
$request = new OfficeRequest($files); $request = new OfficeRequest($files);
$request-&gt;setPaperSize(Request::A4);
$request-&gt;setLandscape(true); $request-&gt;setLandscape(true);
$dirPath = &#34;/foo&#34;; $dest = &#34;result.pdf&#34;;
$filename = $client-&gt;store($request, $dirPath); $client-&gt;store($request, $dest);
</pre> </pre>
<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>
</a>Fonts</h2>
<p>By default, only <code>ttf-mscorefonts</code> fonts are installed.</p>
<p>If you wish to use more fonts, you will have to create your own image:</p>
<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="k">RUN</span> apt-get -y install yourfonts<span class="err">
</span></pre>
</div> </div>
<div class="Page" id="merge"> <div class="Page" id="merge">
@@ -726,9 +791,13 @@ $filename = $client-&gt;store($request, $dirPath);
<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>Basic</h2> </a>Basic</h2>
<p>Nothing special here: you may send one or more PDF files and the API <p>Nothing fancy here: you may send one or more PDF files and the API
will merge them and return the resulting PDF file.</p> will merge them and return the resulting PDF file.</p>
<blockquote>
<p><strong>Attention:</strong> Gotenberg merges the PDF files alphabetically.</p>
</blockquote>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="merge.basic.c_url" href="#merge.basic.c_url"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="merge.basic.c_url" href="#merge.basic.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> <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> </a>cURL</h3>
@@ -745,11 +814,11 @@ 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>Go</h3> </a>Go</h3>
<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-go-client/v4&#34;</span>
<span class="kd">func</span> <span class="nf">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="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">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="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">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="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="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>
@@ -769,8 +838,8 @@ $files = [
DocumentFactory::makeFromPath(&#39;file2.pdf&#39;, &#39;file2.pdf&#39;), DocumentFactory::makeFromPath(&#39;file2.pdf&#39;, &#39;file2.pdf&#39;),
]; ];
$request = new MergeRequest($files); $request = new MergeRequest($files);
$dirPath = &#34;/foo&#34;; $dest = &#34;result.pdf&#34;;
$filename = $client-&gt;store($request, $dirPath); $client-&gt;store($request, $dest);
</pre> </pre>
</div> </div>
@@ -805,7 +874,7 @@ 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>Go</h3> </a>Go</h3>
<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-go-client/v4&#34;</span>
<span class="kd">func</span> <span class="nf">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>
@@ -833,6 +902,41 @@ $resp = $client-&gt;post($request);
</div> </div>
<div class="Page" id="filename">
<h1 class="Heading"><a class="Anchor" aria-hidden="true" id="filename" href="#filename">
<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>Filename</h1>
<p>All endpoints accept a form field named <code>filename</code>.</p>
<p>If provided, the API will return the resulting PDF file with the given filename.
Otherwise a random filename is used.</p>
<blockquote>
<p>The Go and PHP libraries do not provide a way to set this form field.
However, you may hijack the response from the API or store the resulting PDF
using a custom filename.</p>
<p><strong>Attention:</strong> this feature does not work if the form field <code>webhookURL</code> is given.</p>
</blockquote>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="filename.examples" href="#filename.examples">
<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>Examples</h2>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="filename.examples.c_url" href="#filename.examples.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/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> --form <span class="nv">files</span><span class="o">=</span>@index.html <span class="se">\
</span><span class="se"></span> --form <span class="nv">filename</span><span class="o">=</span><span class="s1">&#39;result.pdf&#39;</span> <span class="se">\
</span><span class="se"></span> -o result.pdf
</pre>
</div>
<div class="Page" id="scalability"> <div class="Page" id="scalability">
<h1 class="Heading"><a class="Anchor" aria-hidden="true" id="scalability" href="#scalability"> <h1 class="Heading"><a class="Anchor" aria-hidden="true" id="scalability" href="#scalability">
<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>
@@ -848,7 +952,7 @@ $resp = $client-&gt;post($request);
</span><span class="w"> </span><span class="c"># your others services</span><span class="w"> </span><span class="w"> </span><span class="c"># your others services</span><span class="w">
</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">4</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>
@@ -877,6 +981,21 @@ a simple <code>GET</code> request.</p>
</div> </div>
<div class="Page" id="fonts">
<h1 class="Heading"><a class="Anchor" aria-hidden="true" id="fonts" href="#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>
</a>Fonts</h1>
<p>By default, a handful of fonts are installed. Asian characters are also supported out of the box.</p>
<p>If you wish to use more fonts, you will have to create your own image:</p>
<pre class="chroma"><span class="k">FROM</span><span class="s"> thecodingmachine/gotenberg:4</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></pre>
</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>

View File

@@ -1,6 +1,15 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-10196481-9"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-10196481-9');
</script>
<meta charset="utf-8"> <meta charset="utf-8">
<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">

18
go.mod
View File

@@ -1,21 +1,25 @@
module github.com/thecodingmachine/gotenberg module github.com/thecodingmachine/gotenberg
go 1.12
require ( require (
github.com/derekparker/delve v1.1.0 github.com/davecgh/go-spew v1.1.1 // indirect
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.19 github.com/hhrutter/pdfcpu v0.1.19
github.com/labstack/echo v0.0.0-20181123063703-c7eb8da9ec73 github.com/labstack/echo/v4 v4.0.0
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
github.com/mattn/go-colorable v0.1.1 // indirect
github.com/mattn/go-isatty v0.0.7 // indirect
github.com/microcosm-cc/bluemonday v1.0.1 github.com/microcosm-cc/bluemonday v1.0.1
github.com/pkg/errors v0.8.0 // indirect github.com/pkg/errors v0.8.0 // indirect
github.com/russross/blackfriday/v2 v2.0.1 github.com/russross/blackfriday/v2 v2.0.1
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95 // indirect github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95 // indirect
github.com/stretchr/objx v0.1.1 // indirect github.com/stretchr/testify v1.3.0
github.com/stretchr/testify v1.2.2 github.com/valyala/fasttemplate v1.0.1 // indirect
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 // indirect golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c // indirect
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc golang.org/x/net v0.0.0-20181201002055-351d144fa1fc // indirect
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f // indirect golang.org/x/sync v0.0.0-20181108010431-42b317875d0f // indirect
golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 // indirect golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc // indirect
) )

40
go.sum
View File

@@ -1,30 +1,29 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/derekparker/delve v1.1.0 h1:icd65nMp7s2HiLz6y/6RCVXBdoED3xxYLwX09EMaRCc=
github.com/derekparker/delve v1.1.0/go.mod h1:pMSZMfp0Nhbm8qdZJkuE/yPGOkLpGXLS1I4poXQpuJU=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
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/go.mod h1:iaCmXGnOXPIvoGLELZZc4m/GpIopVsvLQ00thrbu8LU=
github.com/hhrutter/pdfcpu v0.1.19 h1:J6GjNFDPjurQWallPW9gmz3CcNqBfvgB7Dad9T3e8Hc= github.com/hhrutter/pdfcpu v0.1.19 h1:J6GjNFDPjurQWallPW9gmz3CcNqBfvgB7Dad9T3e8Hc=
github.com/hhrutter/pdfcpu v0.1.19/go.mod h1:iaCmXGnOXPIvoGLELZZc4m/GpIopVsvLQ00thrbu8LU= 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/v4 v4.0.0 h1:q1GH+caIXPP7H2StPIdzy/ez9CO0EepqYeUg6vi9SWM=
github.com/labstack/echo v0.0.0-20181123063703-c7eb8da9ec73/go.mod h1:rS0D1UPvC8/3sXjhSwEq+K1olh7ipbDhjDWATN2KSgA= github.com/labstack/echo/v4 v4.0.0/go.mod h1:tZv7nai5buKSg5h/8E6zz4LsD/Dqh9/91Mvs7Z5Zyno=
github.com/labstack/echo v3.3.5+incompatible h1:9PfxPUmasKzeJor9uQTaXLT6WUG/r+vSTmvXxvv3JO4=
github.com/labstack/echo v3.3.5+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
github.com/labstack/gommon v0.2.7/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4=
github.com/labstack/gommon v0.2.8 h1:JvRqmeZcfrHC5u6uVleB4NxxNbzx6gpbJiQknDbKQu0= github.com/labstack/gommon v0.2.8 h1:JvRqmeZcfrHC5u6uVleB4NxxNbzx6gpbJiQknDbKQu0=
github.com/labstack/gommon v0.2.8/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4= github.com/labstack/gommon v0.2.8/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4=
github.com/mafredri/cdp v0.20.0 h1:dRq16FwXCAAbolR4W2iyRNsL14Bp6jFHLbRp2EkICVs= github.com/mafredri/cdp v0.20.0 h1:dRq16FwXCAAbolR4W2iyRNsL14Bp6jFHLbRp2EkICVs=
github.com/mafredri/cdp v0.20.0/go.mod h1:hgdiA0yp1uqhSaDOHJWPgXpMbh+LAfUdD9vbN2AM8gE= github.com/mafredri/cdp v0.20.0/go.mod h1:hgdiA0yp1uqhSaDOHJWPgXpMbh+LAfUdD9vbN2AM8gE=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4= github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.1 h1:G1f5SKeVxmagw/IyvzvtZE4Gybcc4Tr1tf7I8z0XgOg=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs= github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7 h1:UvyT9uN+3r7yLEYSlJsbQGdsaB/a0DlgWP3pql6iwOc=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/microcosm-cc/bluemonday v1.0.1 h1:SIYunPjnlXcW+gVfvm0IlSeR5U3WZUOLfVmqg85Go44= github.com/microcosm-cc/bluemonday v1.0.1 h1:SIYunPjnlXcW+gVfvm0IlSeR5U3WZUOLfVmqg85Go44=
github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4=
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
@@ -35,21 +34,24 @@ github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95 h1:/vdW8Cb7EXrkqWGufVMES1OH2sU9gKVb2n9/1y5NMBY= github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95 h1:/vdW8Cb7EXrkqWGufVMES1OH2sU9gKVb2n9/1y5NMBY=
github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 h1:gKMu1Bf6QINDnvyZuTaACm9ofY+PRh+5vFz4oxBZeF8= github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4 h1:gKMu1Bf6QINDnvyZuTaACm9ofY+PRh+5vFz4oxBZeF8=
github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4/go.mod h1:50wTf68f99/Zt14pr046Tgt3Lp2vLyFZKzbFXTOabXw= github.com/valyala/fasttemplate v0.0.0-20170224212429-dcecefd839c4/go.mod h1:50wTf68f99/Zt14pr046Tgt3Lp2vLyFZKzbFXTOabXw=
golang.org/x/crypto v0.0.0-20181106171534-e4dc69e5b2fd/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9 h1:mKdxBk7AujPs8kU4m80U72y/zjbZ3UcXC7dClwKbUI0= github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190130090550-b01c7a725664/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsqD5/3mLDhx2NcNqyW+0= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsqD5/3mLDhx2NcNqyW+0=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f h1:Bl/8QSvNqXvPGPGXa2z5xUTmV7VDcZyvRZ+QQXkXTZQ=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 h1:YAFjXN64LMvktoUZH9zgY4lGc/msGN7HQfoSuKCgaDU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc h1:4gbWbmmPFp4ySWICouJl6emP0MyS31yy9SrTlAGFT+g=
golang.org/x/sys v0.0.0-20190322080309-f49334f85ddc/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View File

@@ -8,8 +8,8 @@ import (
"os/signal" "os/signal"
"time" "time"
"github.com/labstack/echo" "github.com/labstack/echo/v4"
"github.com/labstack/echo/middleware" "github.com/labstack/echo/v4/middleware"
"github.com/thecodingmachine/gotenberg/internal/pkg/notify" "github.com/thecodingmachine/gotenberg/internal/pkg/notify"
"github.com/thecodingmachine/gotenberg/internal/pkg/pm2" "github.com/thecodingmachine/gotenberg/internal/pkg/pm2"
"github.com/thecodingmachine/gotenberg/internal/pkg/printer" "github.com/thecodingmachine/gotenberg/internal/pkg/printer"
@@ -71,6 +71,7 @@ func setup() *echo.Echo {
e.POST("/merge", merge) e.POST("/merge", merge)
g := e.Group("/convert") g := e.Group("/convert")
g.POST("/html", convertHTML) g.POST("/html", convertHTML)
g.POST("/url", convertURL)
g.POST("/markdown", convertMarkdown) g.POST("/markdown", convertMarkdown)
g.POST("/office", convertOffice) g.POST("/office", convertOffice)
return e return e
@@ -92,14 +93,17 @@ func print(c echo.Context, p printer.Printer, r *resource) error {
} }
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 no webhook URL given, run conversion
// and directly return the resulting PDF file
// or an error.
if r.webhookURL() == "" { if r.webhookURL() == "" {
defer r.removeAll() defer r.removeAll()
// if no webhook URL given, run conversion
// and directly return the resulting PDF file
// or an error.
if err := p.Print(fpath); err != nil { if err := p.Print(fpath); err != nil {
return err return err
} }
if r.filename() != "" {
filename = r.filename()
}
return c.Attachment(fpath, filename) return c.Attachment(fpath, filename)
} }
// as a webhook URL has been given, we // as a webhook URL has been given, we

View File

@@ -5,7 +5,7 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/labstack/echo" "github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )

View File

@@ -1,7 +1,7 @@
package api package api
import ( import (
"github.com/labstack/echo" "github.com/labstack/echo/v4"
"github.com/thecodingmachine/gotenberg/internal/pkg/printer" "github.com/thecodingmachine/gotenberg/internal/pkg/printer"
) )
@@ -47,5 +47,10 @@ func convertHTML(c echo.Context) error {
return hijackErr(err, r) return hijackErr(err, r)
} }
p.Landscape = landscape p.Landscape = landscape
chromeWebFontsTimeout, err := r.webFontsTimeout()
if err != nil {
return hijackErr(err, r)
}
p.WebFontsTimeout = chromeWebFontsTimeout
return print(c, p, r) return print(c, p, r)
} }

View File

@@ -5,7 +5,7 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/labstack/echo" "github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/thecodingmachine/gotenberg/test" "github.com/thecodingmachine/gotenberg/test"
) )

View File

@@ -1,7 +1,7 @@
package api package api
import ( import (
"github.com/labstack/echo" "github.com/labstack/echo/v4"
"github.com/thecodingmachine/gotenberg/internal/pkg/printer" "github.com/thecodingmachine/gotenberg/internal/pkg/printer"
) )
@@ -46,5 +46,10 @@ func convertMarkdown(c echo.Context) error {
return hijackErr(err, r) return hijackErr(err, r)
} }
p.Landscape = landscape p.Landscape = landscape
chromeWebFontsTimeout, err := r.webFontsTimeout()
if err != nil {
return hijackErr(err, r)
}
p.WebFontsTimeout = chromeWebFontsTimeout
return print(c, p, r) return print(c, p, r)
} }

View File

@@ -5,7 +5,7 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/labstack/echo" "github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/thecodingmachine/gotenberg/test" "github.com/thecodingmachine/gotenberg/test"
) )

View File

@@ -6,7 +6,7 @@ import (
"net/http" "net/http"
"os" "os"
"github.com/labstack/echo" "github.com/labstack/echo/v4"
"github.com/thecodingmachine/gotenberg/internal/pkg/printer" "github.com/thecodingmachine/gotenberg/internal/pkg/printer"
"github.com/thecodingmachine/gotenberg/internal/pkg/rand" "github.com/thecodingmachine/gotenberg/internal/pkg/rand"
) )
@@ -29,14 +29,17 @@ func merge(c echo.Context) error {
} }
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 no webhook URL given, run merge
// and directly return the resulting PDF file
// or an error.
if r.webhookURL() == "" { if r.webhookURL() == "" {
defer r.removeAll() defer r.removeAll()
// if no webhook URL given, run merge
// and directly return the resulting PDF file
// or an error.
if err := printer.Merge(fpaths, fpath); err != nil { if err := printer.Merge(fpaths, fpath); err != nil {
return err return err
} }
if r.filename() != "" {
filename = r.filename()
}
return c.Attachment(fpath, filename) return c.Attachment(fpath, filename)
} }
// as a webhook URL has been given, we // as a webhook URL has been given, we

View File

@@ -5,7 +5,7 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/labstack/echo" "github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/thecodingmachine/gotenberg/test" "github.com/thecodingmachine/gotenberg/test"
) )

View File

@@ -3,13 +3,14 @@ package api
import ( import (
"errors" "errors"
"github.com/labstack/echo" "github.com/labstack/echo/v4"
"github.com/thecodingmachine/gotenberg/internal/pkg/printer" "github.com/thecodingmachine/gotenberg/internal/pkg/printer"
) )
var officeExts = []string{ var officeExts = []string{
".txt", ".txt",
".rtf", ".rtf",
".fodt",
".doc", ".doc",
".docx", ".docx",
".odt", ".odt",
@@ -38,12 +39,6 @@ func convertOffice(c echo.Context) error {
return hijackErr(errors.New("no suitable office documents to convert"), r) 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() landscape, err := r.landscape()
if err != nil { if err != nil {
return hijackErr(err, r) return hijackErr(err, r)

View File

@@ -5,7 +5,7 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/labstack/echo" "github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/thecodingmachine/gotenberg/test" "github.com/thecodingmachine/gotenberg/test"
) )

View File

@@ -1,25 +1,29 @@
package api package api
import ( import (
"errors"
"fmt" "fmt"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
"github.com/labstack/echo" "github.com/labstack/echo/v4"
"github.com/thecodingmachine/gotenberg/internal/pkg/rand" "github.com/thecodingmachine/gotenberg/internal/pkg/rand"
) )
const ( const (
webhookURL string = "webhookURL" remoteURL string = "remoteURL"
paperWidth string = "paperWidth" webhookURL string = "webhookURL"
paperHeight string = "paperHeight" paperWidth string = "paperWidth"
marginTop string = "marginTop" paperHeight string = "paperHeight"
marginBottom string = "marginBottom" marginTop string = "marginTop"
marginLeft string = "marginLeft" marginBottom string = "marginBottom"
marginRight string = "marginRight" marginLeft string = "marginLeft"
landscape string = "landscape" marginRight string = "marginRight"
landscape string = "landscape"
webFontsTimeout string = "webFontsTimeout"
filename string = "filename"
) )
// resource facilitates storing and accessing // resource facilitates storing and accessing
@@ -30,15 +34,6 @@ type resource struct {
} }
func newResource(c echo.Context) (*resource, error) { func newResource(c echo.Context) (*resource, error) {
v := make(map[string]string)
v[webhookURL] = c.FormValue(webhookURL)
v[paperWidth] = c.FormValue(paperWidth)
v[paperHeight] = c.FormValue(paperHeight)
v[marginTop] = c.FormValue(marginTop)
v[marginBottom] = c.FormValue(marginBottom)
v[marginLeft] = c.FormValue(marginLeft)
v[marginRight] = c.FormValue(marginRight)
v[landscape] = c.FormValue(landscape)
dirPath, err := rand.Get() dirPath, err := rand.Get()
if err != nil { if err != nil {
return nil, err return nil, err
@@ -46,7 +41,7 @@ func newResource(c echo.Context) (*resource, error) {
if err := os.MkdirAll(dirPath, 0755); err != nil { if err := os.MkdirAll(dirPath, 0755); err != nil {
return nil, fmt.Errorf("%s: making directory: %v", dirPath, err) return nil, fmt.Errorf("%s: making directory: %v", dirPath, err)
} }
r := &resource{values: v, dirPath: dirPath} r := &resource{values: values(c), dirPath: dirPath}
form, err := c.MultipartForm() form, err := c.MultipartForm()
if err != nil { if err != nil {
return r, fmt.Errorf("getting multipart form: %v", err) return r, fmt.Errorf("getting multipart form: %v", err)
@@ -66,6 +61,22 @@ func newResource(c echo.Context) (*resource, error) {
return r, nil return r, nil
} }
func values(c echo.Context) map[string]string {
v := make(map[string]string)
v[remoteURL] = c.FormValue(remoteURL)
v[webhookURL] = c.FormValue(webhookURL)
v[paperWidth] = c.FormValue(paperWidth)
v[paperHeight] = c.FormValue(paperHeight)
v[marginTop] = c.FormValue(marginTop)
v[marginBottom] = c.FormValue(marginBottom)
v[marginLeft] = c.FormValue(marginLeft)
v[marginRight] = c.FormValue(marginRight)
v[landscape] = c.FormValue(landscape)
v[webFontsTimeout] = c.FormValue(webFontsTimeout)
v[filename] = c.FormValue(filename)
return v
}
func (r *resource) writeFile(filename string, in io.Reader) error { func (r *resource) writeFile(filename string, in io.Reader) error {
fpath := fmt.Sprintf("%s/%s", r.dirPath, filename) fpath := fmt.Sprintf("%s/%s", r.dirPath, filename)
out, err := os.Create(fpath) out, err := os.Create(fpath)
@@ -180,5 +191,25 @@ func (r *resource) landscape() (bool, error) {
return landscape, nil return landscape, nil
} }
func (r *resource) remoteURL() (string, error) {
if r.values[remoteURL] == "" {
return "", errors.New("no remote URL")
}
return r.values[remoteURL], nil
}
func (r *resource) webFontsTimeout() (int64, error) {
webFontsTimeoutStr := r.values[webFontsTimeout]
if webFontsTimeoutStr == "" {
return 500, nil
}
timeout, err := strconv.ParseInt(webFontsTimeoutStr, 10, 64)
if err != nil {
return 500, fmt.Errorf("web fonts timeout: %v", err)
}
return timeout, nil
}
func (r *resource) webhookURL() string { return r.values[webhookURL] } func (r *resource) webhookURL() string { return r.values[webhookURL] }
func (r *resource) filename() string { return r.values[filename] }
func (r *resource) removeAll() error { return os.RemoveAll(r.dirPath) } func (r *resource) removeAll() error { return os.RemoveAll(r.dirPath) }

56
internal/app/api/url.go Normal file
View File

@@ -0,0 +1,56 @@
package api
import (
"github.com/labstack/echo/v4"
"github.com/thecodingmachine/gotenberg/internal/pkg/printer"
)
func convertURL(c echo.Context) error {
r, err := newResource(c)
if err != nil {
return hijackErr(err, r)
}
ctx, cancel := newContext(r)
if cancel != nil {
defer cancel()
}
p := &printer.HTML{Context: ctx}
URL, err := r.remoteURL()
if err != nil {
return hijackErr(err, r)
}
p.URL = URL
headerPath, _ := r.filePath("header.html")
if err := p.WithHeaderFile(headerPath); err != nil {
return hijackErr(err, r)
}
footerPath, _ := r.filePath("footer.html")
if err := p.WithFooterFile(footerPath); err != nil {
return hijackErr(err, r)
}
paperSize, err := r.paperSize()
if err != nil {
return hijackErr(err, r)
}
p.PaperWidth = paperSize[0]
p.PaperHeight = paperSize[1]
paperMargins, err := r.paperMargins()
if err != nil {
return hijackErr(err, r)
}
p.MarginTop = paperMargins[0]
p.MarginBottom = paperMargins[1]
p.MarginLeft = paperMargins[2]
p.MarginRight = paperMargins[3]
landscape, err := r.landscape()
if err != nil {
return hijackErr(err, r)
}
p.Landscape = landscape
chromeWebFontsTimeout, err := r.webFontsTimeout()
if err != nil {
return hijackErr(err, r)
}
p.WebFontsTimeout = chromeWebFontsTimeout
return print(c, p, r)
}

View File

@@ -0,0 +1,24 @@
package api
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"github.com/thecodingmachine/gotenberg/test"
)
func TestURL(t *testing.T) {
body, contentType := test.URLTestMultipartForm(t)
req := httptest.NewRequest(http.MethodPost, "/convert/url", body)
req.Header.Set(echo.HeaderContentType, contentType)
rec := httptest.NewRecorder()
e := echo.New()
c := e.NewContext(req, rec)
if assert.NoError(t, convertURL(c)) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, "application/pdf", rec.Header().Get(echo.HeaderContentType))
}
}

View File

@@ -18,17 +18,18 @@ import (
// HTML facilitates HTML to PDF conversion. // HTML facilitates HTML to PDF conversion.
type HTML struct { type HTML struct {
Context context.Context Context context.Context
URL string URL string
HeaderHTML string HeaderHTML string
FooterHTML string FooterHTML string
PaperWidth float64 PaperWidth float64
PaperHeight float64 PaperHeight float64
MarginTop float64 MarginTop float64
MarginBottom float64 MarginBottom float64
MarginLeft float64 MarginLeft float64
MarginRight float64 MarginRight float64
Landscape bool Landscape bool
WebFontsTimeout int64
} }
const defaultHeaderFooterHTML string = "<html><head></head><body></body></html>" const defaultHeaderFooterHTML string = "<html><head></head><body></body></html>"
@@ -103,14 +104,17 @@ func (html *HTML) Print(destination string) error {
return fmt.Errorf("waiting for page loading: %v", err) return fmt.Errorf("waiting for page loading: %v", err)
} }
// inject a script to make sure web fonts are loaded. // inject a script to make sure web fonts are loaded.
script := `new Promise((resolve, reject) => { script := fmt.Sprintf(`new Promise((resolve, reject) => {
document.fonts.ready.then(function () { document.fonts.ready.then(function () {
resolve('fonts loaded'); resolve('fonts loaded');
}); });
setTimeout(resolve.bind(resolve, 'timeout'), %.0f); setTimeout(resolve.bind(resolve, 'timeout'), %d);
});` });`, html.WebFontsTimeout)
scriptArg := runtime.NewEvaluateArgs(script).SetAwaitPromise(true) scriptArg := runtime.NewEvaluateArgs(script).SetAwaitPromise(true)
returnObj, _ := c.Runtime.Evaluate(html.Context, scriptArg) returnObj, _ := c.Runtime.Evaluate(html.Context, scriptArg)
if returnObj.ExceptionDetails != nil {
return fmt.Errorf("script evaluated with exception: %+v", returnObj.ExceptionDetails)
}
loadFontsResult := string(returnObj.Result.Value) loadFontsResult := string(returnObj.Result.Value)
if strings.Contains(loadFontsResult, "timeout") { if strings.Contains(loadFontsResult, "timeout") {
return errors.New("timed out loading fonts") return errors.New("timed out loading fonts")

View File

@@ -15,17 +15,18 @@ import (
// Markdown facilitates Markdown to PDF conversion. // Markdown facilitates Markdown to PDF conversion.
type Markdown struct { type Markdown struct {
Context context.Context Context context.Context
TemplatePath string TemplatePath string
HeaderHTML string HeaderHTML string
FooterHTML string FooterHTML string
PaperWidth float64 PaperWidth float64
PaperHeight float64 PaperHeight float64
MarginTop float64 MarginTop float64
MarginBottom float64 MarginBottom float64
MarginLeft float64 MarginLeft float64
MarginRight float64 MarginRight float64
Landscape bool Landscape bool
WebFontsTimeout int64
html *HTML html *HTML
} }
@@ -52,6 +53,7 @@ func (md *Markdown) Print(destination string) error {
md.html.MarginLeft = md.MarginLeft md.html.MarginLeft = md.MarginLeft
md.html.MarginRight = md.MarginRight md.html.MarginRight = md.MarginRight
md.html.Landscape = md.Landscape md.html.Landscape = md.Landscape
md.html.WebFontsTimeout = md.WebFontsTimeout
tmpl, err := template. tmpl, err := template.
New(filepath.Base(md.TemplatePath)). New(filepath.Base(md.TemplatePath)).
Funcs(template.FuncMap{"toHTML": toHTML}). Funcs(template.FuncMap{"toHTML": toHTML}).

View File

@@ -7,7 +7,6 @@ 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"
@@ -17,11 +16,9 @@ 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 Landscape bool
PaperHeight float64
Landscape bool
} }
// Print converts Office documents to PDF. // Print converts Office documents to PDF.
@@ -36,15 +33,9 @@ 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{ cmdArgs := []string{
"--format", "--format",
"pdf", "pdf",
"--printer",
paperSize,
} }
if o.Landscape { if o.Landscape {
cmdArgs = append(cmdArgs, "--printer", "PaperOrientation=landscape") cmdArgs = append(cmdArgs, "--printer", "PaperOrientation=landscape")
@@ -70,18 +61,6 @@ 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

@@ -1,35 +0,0 @@
# Gotenberg Go client
A simple Go client for interacting with a Gotenberg API.
## Install
```bash
$ go get -u github.com/thecodingmachine/gotenberg
```
## Usage
```golang
import "github.com/thecodingmachine/gotenberg/pkg"
func main() {
// HTML conversion example.
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req, _ := gotenberg.NewHTMLRequest("index.html")
req.SetHeader("header.html")
req.SetFooter("footer.html")
req.SetAssets([]string{
"font.woff",
"img.gif",
"style.css",
})
req.SetPaperSize(gotenberg.A4)
req.SetMargins(gotenberg.NormalMargins)
req.SetLandscape(false)
dest := "foo.pdf"
c.Store(req, dest)
}
```
For more complete usages, head to the [documentation](https://thecodingmachine.github.io/gotenberg).

View File

@@ -1,172 +0,0 @@
package gotenberg
import (
"bytes"
"errors"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
"path/filepath"
"runtime"
)
const (
webhookURL string = "webhookURL"
paperWidth string = "paperWidth"
paperHeight string = "paperHeight"
marginTop string = "marginTop"
marginBottom string = "marginBottom"
marginLeft string = "marginLeft"
marginRight string = "marginRight"
landscape string = "landscape"
)
var (
// A3 paper size.
A3 = [2]float64{11.7, 16.5}
// A4 paper size.
A4 = [2]float64{8.27, 11.7}
// A5 paper size.
A5 = [2]float64{5.8, 8.3}
// A6 paper size.
A6 = [2]float64{4.1, 5.8}
// Letter paper size.
Letter = [2]float64{8.5, 11}
// Legal paper size.
Legal = [2]float64{8.5, 14}
// Tabloid paper size.
Tabloid = [2]float64{11, 17}
)
var (
// NoMargins removes margins.
NoMargins = [4]float64{0, 0, 0, 0}
// NormalMargins uses 1 inche margins.
NormalMargins = [4]float64{1, 1, 1, 1}
// LargeMargins uses 2 inche margins.
LargeMargins = [4]float64{2, 2, 2, 2}
)
// Client facilitates interacting with
// the Gotenberg API.
type Client struct {
Hostname string
}
// Request is a type for sending
// form values and form files to
// the Gotenberg API.
type Request interface {
SetWebhookURL(webhookURL string)
getPostURL() string
getFormValues() 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
// and returns the response.
func (c *Client) Post(req Request) (*http.Response, error) {
body, contentType, err := multipartForm(req)
if err != nil {
return nil, err
}
URL := fmt.Sprintf("%s%s", c.Hostname, req.getPostURL())
resp, err := http.Post(URL, contentType, body)
if err != nil {
return nil, err
}
return resp, nil
}
// Store creates the resulting PDF to given destination.
func (c *Client) Store(req Request, dest string) error {
if hasWebhook(req) {
return errors.New("cannot use Store method with a webhook")
}
resp, err := c.Post(req)
if err != nil {
return err
}
return writeNewFile(dest, resp.Body)
}
func hasWebhook(req Request) bool {
webhookURL, ok := req.getFormValues()[webhookURL]
if !ok {
return false
}
return webhookURL != ""
}
func writeNewFile(fpath string, in io.Reader) error {
if err := os.MkdirAll(filepath.Dir(fpath), 0755); err != nil {
return fmt.Errorf("%s: making directory for file: %v", fpath, err)
}
out, err := os.Create(fpath)
if err != nil {
return fmt.Errorf("%s: creating new file: %v", fpath, err)
}
defer out.Close()
err = out.Chmod(0644)
if err != nil && runtime.GOOS != "windows" {
return fmt.Errorf("%s: changing file mode: %v", fpath, err)
}
_, err = io.Copy(out, in)
if err != nil {
return fmt.Errorf("%s: writing file: %v", fpath, err)
}
return nil
}
func fileExists(name string) bool {
_, err := os.Stat(name)
return !os.IsNotExist(err)
}
func multipartForm(req Request) (*bytes.Buffer, string, error) {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
defer writer.Close()
for filename, fpath := range req.getFormFiles() {
in, err := os.Open(fpath)
if err != nil {
return nil, "", fmt.Errorf("%s: opening file: %v", filename, err)
}
part, err := writer.CreateFormFile("files", filename)
if err != nil {
return nil, "", fmt.Errorf("%s: creating form file: %v", filename, err)
}
_, err = io.Copy(part, in)
if err != nil {
return nil, "", fmt.Errorf("%s: copying file: %v", filename, err)
}
}
for name, value := range req.getFormValues() {
if err := writer.WriteField(name, value); err != nil {
return nil, "", fmt.Errorf("%s: writing form field: %v", name, err)
}
}
return body, writer.FormDataContentType(), nil
}

View File

@@ -1,8 +0,0 @@
/*
Package gotenberg is a Go client for
interacting with a Gotenberg API.
For more complete usages, head to the documentation:
https://thecodingmachine.gotenberg.github.io.
*/
package gotenberg

View File

@@ -1,104 +0,0 @@
package gotenberg
import (
"fmt"
"path/filepath"
"strconv"
)
// HTMLRequest facilitates HTML conversion
// with the Gotenberg API.
type HTMLRequest struct {
indexFilePath string
headerFilePath string
footerFilePath string
assetFilePaths []string
values map[string]string
}
// NewHTMLRequest create HTMLRequest.
func NewHTMLRequest(indexFilePath string) (*HTMLRequest, error) {
if !fileExists(indexFilePath) {
return nil, fmt.Errorf("%s: index file does not exist", indexFilePath)
}
return &HTMLRequest{indexFilePath: indexFilePath, values: make(map[string]string)}, nil
}
// SetWebhookURL sets webhookURL form field.
func (html *HTMLRequest) SetWebhookURL(webhookURL string) {
html.values[webhookURL] = webhookURL
}
// SetHeader sets header form file.
func (html *HTMLRequest) SetHeader(fpath string) error {
if !fileExists(fpath) {
return fmt.Errorf("%s: header file does not exist", fpath)
}
html.headerFilePath = fpath
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 {
return "/convert/html"
}
func (html *HTMLRequest) getFormValues() map[string]string {
return html.values
}
func (html *HTMLRequest) getFormFiles() map[string]string {
files := make(map[string]string)
files["index.html"] = html.indexFilePath
files["header.html"] = html.headerFilePath
files["footer.html"] = html.footerFilePath
for _, fpath := range html.assetFilePaths {
files[filepath.Base(fpath)] = fpath
}
return files
}
// Compile-time checks to ensure type implements desired interfaces.
var (
_ = Request(new(HTMLRequest))
_ = ChromeRequest(new(HTMLRequest))
)

View File

@@ -1,47 +0,0 @@
package gotenberg
import (
"fmt"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/thecodingmachine/gotenberg/internal/pkg/rand"
"github.com/thecodingmachine/gotenberg/test"
)
func TestHTML(t *testing.T) {
c := &Client{Hostname: "http://localhost:3000"}
req, err := NewHTMLRequest(test.HTMLTestFilePath(t, "index.html"))
require.Nil(t, err)
err = req.SetHeader(test.HTMLTestFilePath(t, "header.html"))
require.Nil(t, err)
err = req.SetFooter(test.HTMLTestFilePath(t, "footer.html"))
require.Nil(t, err)
err = req.SetAssets([]string{
test.HTMLTestFilePath(t, "font.woff"),
test.HTMLTestFilePath(t, "img.gif"),
test.HTMLTestFilePath(t, "style.css"),
})
require.Nil(t, err)
req.SetPaperSize(A4)
req.SetMargins(NormalMargins)
req.SetLandscape(false)
dirPath, err := rand.Get()
require.Nil(t, err)
dest := fmt.Sprintf("%s/foo.pdf", dirPath)
err = c.Store(req, dest)
assert.Nil(t, err)
assert.FileExists(t, dest)
err = os.RemoveAll(dirPath)
assert.Nil(t, err)
}
func TestConcurrentHTML(t *testing.T) {
for i := 0; i < 10; i++ {
go func() {
TestHTML(t)
}()
}
}

View File

@@ -1,117 +0,0 @@
package gotenberg
import (
"fmt"
"path/filepath"
"strconv"
)
// MarkdownRequest facilitates Markdown conversion
// with the Gotenberg API.
type MarkdownRequest struct {
indexFilePath string
markdownFilePaths []string
headerFilePath string
footerFilePath string
assetFilePaths []string
values map[string]string
}
// NewMarkdownRequest create MarkdownRequest.
func NewMarkdownRequest(indexFilePath string, markdownFilePaths []string) (*MarkdownRequest, error) {
if !fileExists(indexFilePath) {
return nil, fmt.Errorf("%s: index file does not exist", indexFilePath)
}
for _, fpath := range markdownFilePaths {
if !fileExists(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
}
// 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 {
return "/convert/markdown"
}
func (markdown *MarkdownRequest) getFormValues() map[string]string {
return markdown.values
}
func (markdown *MarkdownRequest) getFormFiles() map[string]string {
files := make(map[string]string)
files["index.html"] = markdown.indexFilePath
files["header.html"] = markdown.headerFilePath
files["footer.html"] = markdown.footerFilePath
for _, fpath := range markdown.markdownFilePaths {
files[filepath.Base(fpath)] = fpath
}
for _, fpath := range markdown.assetFilePaths {
files[filepath.Base(fpath)] = fpath
}
return files
}
// Compile-time checks to ensure type implements desired interfaces.
var (
_ = Request(new(MarkdownRequest))
_ = ChromeRequest(new(MarkdownRequest))
)

View File

@@ -1,54 +0,0 @@
package gotenberg
import (
"fmt"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/thecodingmachine/gotenberg/internal/pkg/rand"
"github.com/thecodingmachine/gotenberg/test"
)
func TestMarkdown(t *testing.T) {
c := &Client{Hostname: "http://localhost:3000"}
req, err := NewMarkdownRequest(
test.MarkdownTestFilePath(t, "index.html"),
[]string{
test.MarkdownTestFilePath(t, "paragraph1.md"),
test.MarkdownTestFilePath(t, "paragraph2.md"),
test.MarkdownTestFilePath(t, "paragraph3.md"),
},
)
require.Nil(t, err)
err = req.SetHeader(test.MarkdownTestFilePath(t, "header.html"))
require.Nil(t, err)
err = req.SetFooter(test.MarkdownTestFilePath(t, "footer.html"))
require.Nil(t, err)
err = req.SetAssets([]string{
test.MarkdownTestFilePath(t, "font.woff"),
test.MarkdownTestFilePath(t, "img.gif"),
test.MarkdownTestFilePath(t, "style.css"),
})
require.Nil(t, err)
req.SetPaperSize(A4)
req.SetMargins(NormalMargins)
req.SetLandscape(false)
dirPath, err := rand.Get()
require.Nil(t, err)
dest := fmt.Sprintf("%s/foo.pdf", dirPath)
err = c.Store(req, dest)
assert.Nil(t, err)
assert.FileExists(t, dest)
err = os.RemoveAll(dirPath)
assert.Nil(t, err)
}
func TestConcurrentMarkdown(t *testing.T) {
for i := 0; i < 10; i++ {
go func() {
TestMarkdown(t)
}()
}
}

View File

@@ -1,49 +0,0 @@
package gotenberg
import (
"fmt"
"path/filepath"
)
// MergeRequest facilitates merging PDF
// with the Gotenberg API.
type MergeRequest struct {
filePaths []string
values map[string]string
}
// NewMergeRequest create MergeRequest.
func NewMergeRequest(fpaths []string) (*MergeRequest, error) {
for _, fpath := range fpaths {
if !fileExists(fpath) {
return nil, fmt.Errorf("%s: file does not exist", fpath)
}
}
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 {
return "/merge"
}
func (merge *MergeRequest) getFormValues() map[string]string {
return merge.values
}
func (merge *MergeRequest) getFormFiles() map[string]string {
files := make(map[string]string)
for _, fpath := range merge.filePaths {
files[filepath.Base(fpath)] = fpath
}
return files
}
// Compile-time checks to ensure type implements desired interfaces.
var (
_ = Request(new(MergeRequest))
)

View File

@@ -1,37 +0,0 @@
package gotenberg
import (
"fmt"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/thecodingmachine/gotenberg/internal/pkg/rand"
"github.com/thecodingmachine/gotenberg/test"
)
func TestMerge(t *testing.T) {
c := &Client{Hostname: "http://localhost:3000"}
req, err := NewMergeRequest([]string{
test.PDFTestFilePath(t, "gotenberg.pdf"),
test.PDFTestFilePath(t, "gotenberg.pdf"),
})
require.Nil(t, err)
dirPath, err := rand.Get()
require.Nil(t, err)
dest := fmt.Sprintf("%s/foo.pdf", dirPath)
err = c.Store(req, dest)
assert.Nil(t, err)
assert.FileExists(t, dest)
err = os.RemoveAll(dirPath)
assert.Nil(t, err)
}
func TestConcurrentMerge(t *testing.T) {
for i := 0; i < 10; i++ {
go func() {
TestMerge(t)
}()
}
}

View File

@@ -1,62 +0,0 @@
package gotenberg
import (
"fmt"
"path/filepath"
"strconv"
)
// OfficeRequest facilitates Office documents
// conversion with the Gotenberg API.
type OfficeRequest struct {
filePaths []string
values map[string]string
}
// NewOfficeRequest create OfficeRequest.
func NewOfficeRequest(fpaths []string) (*OfficeRequest, error) {
for _, fpath := range fpaths {
if !fileExists(fpath) {
return nil, fmt.Errorf("%s: file does not exist", fpath)
}
}
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 {
return "/convert/office"
}
func (office *OfficeRequest) getFormValues() map[string]string {
return office.values
}
func (office *OfficeRequest) getFormFiles() map[string]string {
files := make(map[string]string)
for _, fpath := range office.filePaths {
files[filepath.Base(fpath)] = fpath
}
return files
}
// Compile-time checks to ensure type implements desired interfaces.
var (
_ = Request(new(OfficeRequest))
_ = UnoconvRequest(new(OfficeRequest))
)

View File

@@ -1,38 +0,0 @@
package gotenberg
import (
"fmt"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/thecodingmachine/gotenberg/internal/pkg/rand"
"github.com/thecodingmachine/gotenberg/test"
)
func TestOffice(t *testing.T) {
c := &Client{Hostname: "http://localhost:3000"}
req, err := NewOfficeRequest([]string{
test.OfficeTestFilePath(t, "document.docx"),
})
require.Nil(t, err)
req.SetPaperSize(A4)
req.SetLandscape(false)
dirPath, err := rand.Get()
require.Nil(t, err)
dest := fmt.Sprintf("%s/foo.pdf", dirPath)
err = c.Store(req, dest)
assert.Nil(t, err)
assert.FileExists(t, dest)
err = os.RemoveAll(dirPath)
assert.Nil(t, err)
}
func TestConcurrentOffice(t *testing.T) {
for i := 0; i < 10; i++ {
go func() {
TestOffice(t)
}()
}
}

View File

@@ -9,6 +9,7 @@ DOCKER_PASSWORD="$4"
docker login -u "$DOCKER_USER" -p "$DOCKER_PASSWORD" docker login -u "$DOCKER_USER" -p "$DOCKER_PASSWORD"
VERSION="${VERSION//v}"
SEMVER=( ${VERSION//./ } ) SEMVER=( ${VERSION//./ } )
VERSION_LENGTH=${#SEMVER[@]} VERSION_LENGTH=${#SEMVER[@]}
@@ -21,11 +22,13 @@ docker build -t thecodingmachine/gotenberg:base -f build/base/Dockerfile .
docker build \ docker build \
--build-arg GOLANG_VERSION=${GOLANG_VERSION} \ --build-arg GOLANG_VERSION=${GOLANG_VERSION} \
--build-arg VERSION=${VERSION} \ --build-arg VERSION=${VERSION} \
-t thecodingmachine/gotenberg:latest \
-t thecodingmachine/gotenberg:${SEMVER[0]} \ -t thecodingmachine/gotenberg:${SEMVER[0]} \
-t thecodingmachine/gotenberg:${SEMVER[0]}.${SEMVER[1]} \ -t thecodingmachine/gotenberg:${SEMVER[0]}.${SEMVER[1]} \
-t thecodingmachine/gotenberg:${SEMVER[0]}.${SEMVER[1]}.${SEMVER[2]} \ -t thecodingmachine/gotenberg:${SEMVER[0]}.${SEMVER[1]}.${SEMVER[2]} \
-f build/package/Dockerfile . -f build/package/Dockerfile .
docker push "thecodingmachine/gotenberg:latest"
docker push "thecodingmachine/gotenberg:${SEMVER[0]}" docker push "thecodingmachine/gotenberg:${SEMVER[0]}"
docker push "thecodingmachine/gotenberg:${SEMVER[0]}.${SEMVER[1]}" docker push "thecodingmachine/gotenberg:${SEMVER[0]}.${SEMVER[1]}"
docker push "thecodingmachine/gotenberg:${SEMVER[0]}.${SEMVER[1]}.${SEMVER[2]}" docker push "thecodingmachine/gotenberg:${SEMVER[0]}.${SEMVER[1]}.${SEMVER[2]}"

15
test/testdata/url/footer.html vendored Normal file
View File

@@ -0,0 +1,15 @@
<html>
<head>
<style>
body {
font-size: 8rem;
margin: 4rem auto;
}
</style>
</head>
<body>
<p>
<span class="pageNumber"></span> of <span class="totalPages"></span>
</p>
</body>
</html>

13
test/testdata/url/header.html vendored Normal file
View File

@@ -0,0 +1,13 @@
<html>
<head>
<style>
body {
font-size: 8rem;
margin: 4rem auto;
}
</style>
</head>
<body>
<span class="title"></span>
</body>
</html>

View File

@@ -23,6 +23,13 @@ func HTMLTestMultipartForm(t *testing.T) (*bytes.Buffer, string) {
return multipartForm(t, "html") return multipartForm(t, "html")
} }
// URLTestMultipartForm returns the body
// for a multipate/form-data request with all
// files under "url" folder.
func URLTestMultipartForm(t *testing.T) (*bytes.Buffer, string) {
return multipartForm(t, "url")
}
// MarkdownTestMultipartForm returns the body // MarkdownTestMultipartForm returns the body
// for a multipate/form-data request with all // for a multipate/form-data request with all
// files under "markdown" folder. // files under "markdown" folder.
@@ -65,6 +72,10 @@ func multipartForm(t *testing.T, kind string) (*bytes.Buffer, string) {
_, err = io.Copy(part, file) _, err = io.Copy(part, file)
require.Nil(t, err) require.Nil(t, err)
} }
if kind == "url" {
err := writer.WriteField("remoteURL", "http://google.com")
require.Nil(t, err)
}
return body, writer.FormDataContentType() return body, writer.FormDataContentType()
} }
@@ -74,6 +85,12 @@ func HTMLTestDirPath(t *testing.T) string {
return copyDir(t, "html") return copyDir(t, "html")
} }
// URLTestDirPath creates a copy
// of "url" folder in test/testdata.
func URLTestDirPath(t *testing.T) string {
return copyDir(t, "url")
}
// MarkdownTestDirPath creates a copy // MarkdownTestDirPath creates a copy
// of "markdown" folder in test/testdata. // of "markdown" folder in test/testdata.
func MarkdownTestDirPath(t *testing.T) string { func MarkdownTestDirPath(t *testing.T) string {
@@ -121,30 +138,6 @@ func copyDir(t *testing.T, kind string) string {
return tmpDirPath return tmpDirPath
} }
// HTMLTestFilePath returns the absolute file path
// of a file in "html" folder in test/testdata.
func HTMLTestFilePath(t *testing.T, filename string) string {
return abs(t, "html", filename)
}
// MarkdownTestFilePath returns the absolute file path
// of a file in "markdown" folder in test/testdata.
func MarkdownTestFilePath(t *testing.T, filename string) string {
return abs(t, "markdown", filename)
}
// OfficeTestFilePath returns the absolute file path
// of a file in "office" folder in test/testdata.
func OfficeTestFilePath(t *testing.T, filename string) string {
return abs(t, "office", filename)
}
// PDFTestFilePath returns the absolute file path
// of a file in "pdf" folder in test/testdata.
func PDFTestFilePath(t *testing.T, filename string) string {
return abs(t, "pdf", filename)
}
func abs(t *testing.T, kind, filename string) string { func abs(t *testing.T, kind, filename string) string {
_, gofilename, _, ok := runtime.Caller(0) _, gofilename, _, ok := runtime.Caller(0)
require.Equal(t, ok, true, "got no caller information") require.Equal(t, ok, true, "got no caller information")