Compare commits

...

18 Commits
3.0.0 ... 3.1.0

Author SHA1 Message Date
Julien Neuhart
5a03e17e00 fixing introduction in documentation 2018-12-12 16:37:36 +01:00
Julien Neuhart
417d145b43 fixing documentation typos 2018-12-12 16:36:21 +01:00
Julien Neuhart
e5636a2afa adding .txt and .rtf files support (#20) 2018-12-12 16:34:34 +01:00
Julien Neuhart
5291d2d129 disabling pdfcpu logs (#22) 2018-12-12 16:24:54 +01:00
Julien Neuhart
c6f6a87499 now using latest version of unoconv, allowing to specify paper size and orientation + updating go client (#24) 2018-12-12 16:16:35 +01:00
Julien Neuhart
1ef21c6ed6 RPC error (#23) 2018-12-12 12:20:07 +01:00
Julien Neuhart
6ee1932cbf improving API tests: now verifying response content type and status code 2018-12-11 14:16:43 +01:00
Julien Neuhart
83cf43a314 fixing cURL commands in documentation 2018-12-11 14:09:04 +01:00
Julien Neuhart
52c14a79a1 fixing GoDoc + some test function names 2018-12-10 20:21:31 +01:00
Julien Neuhart
152db0551d fixing GoDoc links in badges 2018-12-10 20:11:20 +01:00
Julien Neuhart
3a2467ccfe improving documentation 2018-12-10 20:08:45 +01:00
Julien Neuhart
5a28f3597c fixing typos in documentation 2018-12-10 19:59:45 +01:00
Julien Neuhart
9ce179f91b adding PHP examples in documentation 2018-12-10 19:12:54 +01:00
Julien Neuhart
7aeb072cc3 fixing issue with merge endpoint: was not returning file 2018-12-10 18:42:23 +01:00
Julien Neuhart
8a652761a3 fixing Go Report Card issues (rollback gocycly) 2018-12-10 17:03:23 +01:00
Julien Neuhart
be667575d5 fixing Go Report Card issues #2 2018-12-10 17:02:48 +01:00
Julien Neuhart
59ca8a44a0 fixing Go Report Card issues 2018-12-10 16:57:08 +01:00
Julien Neuhart
c9f0d3bfd8 fixes publishing Docker images in CI 2018-12-10 16:36:34 +01:00
40 changed files with 3054 additions and 455 deletions

View File

@@ -11,13 +11,15 @@ env:
- secure: CmLh169xwt3OC7l19lDUwdZYfw+l/+XXKjTGxnuJiXHa9hAH+nc4mEUSmqHMHwjquyYE6LnSVGZ94LH8sCaGed/TMm0Lj3DZtZ0VsjYu3sKsNrVJn5WdYEah+GvNJ8i8uzvHnGk1L2fAagLpXFUB2K9UraA1CFiHs1fF5Fua7Ra0mE7lMz0MFvyvzcmc9u8nMz71K2YVsXqn+I/rv8onJCTtc/Ds0hVrBXwG5Fh0T3xHqjOhME9ZI2hRHnnQVdBojSY3USifQ//qAKowfBVc0pebEtgFpyXx/I17A6xCm0KVtnA2tNqu1+XFkjWaBzryaLE9ujhJcTRC/YK0JUZ+QxfYbD5C7jVy9Jlx1lOEjJ42B/ImNxPP+9p3wi2MWNbcbZJPxIe635fnT17lI7CLK2Qg1xjfTQ4WTEKW5IhnYMiyfRKiripFh4PCkDm8cJlTbpntsX1n0uheydbsgf/11vS7o1WGhVQ8+Jelc4DvIbBHCqienQEOLJDBwm7FiK5JbwZJ6ZAGeDM/IhGU1h9PNjVbHUyJhUxYoPYUE9QsZFT7ENCrRQpq49KOzXBRfffyJNJRh+Ep9X5YoW0dUp0MNu5B7z2+6w9X9n/C+loa11xF42bFzniCvvbSOQ37J+EngDinVxJkNPeyivR4fye2ENhIAjAEjouTJLOSXL9nAOU= - secure: CmLh169xwt3OC7l19lDUwdZYfw+l/+XXKjTGxnuJiXHa9hAH+nc4mEUSmqHMHwjquyYE6LnSVGZ94LH8sCaGed/TMm0Lj3DZtZ0VsjYu3sKsNrVJn5WdYEah+GvNJ8i8uzvHnGk1L2fAagLpXFUB2K9UraA1CFiHs1fF5Fua7Ra0mE7lMz0MFvyvzcmc9u8nMz71K2YVsXqn+I/rv8onJCTtc/Ds0hVrBXwG5Fh0T3xHqjOhME9ZI2hRHnnQVdBojSY3USifQ//qAKowfBVc0pebEtgFpyXx/I17A6xCm0KVtnA2tNqu1+XFkjWaBzryaLE9ujhJcTRC/YK0JUZ+QxfYbD5C7jVy9Jlx1lOEjJ42B/ImNxPP+9p3wi2MWNbcbZJPxIe635fnT17lI7CLK2Qg1xjfTQ4WTEKW5IhnYMiyfRKiripFh4PCkDm8cJlTbpntsX1n0uheydbsgf/11vS7o1WGhVQ8+Jelc4DvIbBHCqienQEOLJDBwm7FiK5JbwZJ6ZAGeDM/IhGU1h9PNjVbHUyJhUxYoPYUE9QsZFT7ENCrRQpq49KOzXBRfffyJNJRh+Ep9X5YoW0dUp0MNu5B7z2+6w9X9n/C+loa11xF42bFzniCvvbSOQ37J+EngDinVxJkNPeyivR4fye2ENhIAjAEjouTJLOSXL9nAOU=
stages: stages:
- lint - tests
- publish - publish
jobs: jobs:
include: include:
- stage: lint - stage: tests
script: make lint script: make lint
- stage: tests
script: make tests
- stage: publish - stage: publish
if: tag IS present if: tag IS present
script: make image VERSION=$TRAVIS_TAG && ./scripts/publish.sh $TRAVIS_TAG $DOCKER_USER $DOCKER_PASS script: ./scripts/publish.sh $TRAVIS_TAG $DOCKER_USER $DOCKER_PASS

View File

@@ -11,7 +11,7 @@ At TheCodingMachine, we build a lot of web applications (intranets, extranets an
## Features ## Features
* HTML and Markdown conversions using Google Chrome headless * HTML and Markdown conversions using Google Chrome headless
* Office conversions (.docx, .doc, .odt, .pptx, .ppt, .odp and so on) using [unoconv](https://github.com/dagwieers/unoconv) * Office conversions (.txt, .rtf, .docx, .doc, .odt, .pptx, .ppt, .odp and so on) using [unoconv](https://github.com/dagwieers/unoconv)
* Performance :zap:: Google Chrome and Libreoffice (unoconv) started once in the background thanks to PM2 * Performance :zap:: Google Chrome and Libreoffice (unoconv) started once in the background thanks to PM2
* Failure prevention :broken_heart:: PM2 automatically restarts previous processes if they fail * Failure prevention :broken_heart:: PM2 automatically restarts previous processes if they fail
* Assets :package:: send your header, footer, images, fonts, stylesheets and so on for converting your HTML and Markdown to beaufitul PDFs! * Assets :package:: send your header, footer, images, fonts, stylesheets and so on for converting your HTML and Markdown to beaufitul PDFs!
@@ -34,7 +34,7 @@ to learn how to interact with it!
[![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:3.svg)](https://microbadger.com/images/thecodingmachine/gotenberg:3)
[![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?status.svg) [![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

@@ -11,7 +11,7 @@ LABEL authors="Julien Neuhart <j.neuhart@thecodingmachine.com>"
RUN echo "deb http://httpredir.debian.org/debian/ stretch main contrib non-free" > /etc/apt/sources.list &&\ RUN echo "deb http://httpredir.debian.org/debian/ stretch main contrib non-free" > /etc/apt/sources.list &&\
apt-get update &&\ apt-get update &&\
apt-get install -y curl wget apt-get install -y curl wget python3-pip
# |-------------------------------------------------------------------------- # |--------------------------------------------------------------------------
# | PM2 # | PM2
@@ -39,7 +39,10 @@ RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add
# | Unoconv # | Unoconv
# |-------------------------------------------------------------------------- # |--------------------------------------------------------------------------
# | # |
# | Installs MS fonts and unoconv for Office documents conversions. # | Installs unoconv and LibreOffice for Office documents conversions.
# | # |
RUN apt-get -y install ttf-mscorefonts-installer unoconv RUN pip3 install unoconv &&\
# https://github.com/nextcloud/docker/issues/380
mkdir -p /usr/share/man/man1mkdir -p /usr/share/man/man1 &&\
apt-get -y install libreoffice

View File

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

View File

@@ -26,13 +26,13 @@ For instance:
</html> </html>
``` ```
### Guzzle ### cURL
```bash ```bash
$ curl --request POST \ $ curl --request POST \
--url http://localhost:3000/convert/html \ --url http://localhost:3000/convert/html \
--header 'Content-Type: multipart/form-data' \ --header 'Content-Type: multipart/form-data' \
--form files=@index.html --form files=@index.html \
> result.pdf > result.pdf
``` ```
@@ -43,9 +43,7 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.HTMLRequest{ req, _ := gotenberg.NewHTMLRequest("index.html")
IndexFilePath: "index.html",
}
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }
@@ -53,7 +51,17 @@ func main() {
### PHP ### PHP
TODO ```php
use TheCodingMachine\Gotenberg\Client;
use TheCodingMachine\Gotenberg\DocumentFactory;
use TheCodingMachine\Gotenberg\HTMLRequest;
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
$index = DocumentFactory::makeFromPath('index.html', 'index.html');
$request = new HTMLRequest($index);
$dirPath = "/foo";
$filename = $client->store($request, $dirPath);
```
## Header and footer ## Header and footer
@@ -90,15 +98,15 @@ The following classes allow you to inject printing values:
> **Attention:** the CSS properties are independant of the ones used in the `index.html` file. > **Attention:** the CSS properties are independant of the ones used in the `index.html` file.
> Also, `footer.html` CSS properties override the ones from `header.html`. > Also, `footer.html` CSS properties override the ones from `header.html`.
### Guzzle ### cURL
```bash ```bash
$ curl --request POST \ $ curl --request POST \
--url http://localhost:3000/convert/html \ --url http://localhost:3000/convert/html \
--header 'Content-Type: multipart/form-data' \ --header 'Content-Type: multipart/form-data' \
--form files=@index.html --form files=@index.html \
--form files=@header.html --form files=@header.html \
--form files=@footer.html --form files=@footer.html \
> result.pdf > result.pdf
``` ```
@@ -109,13 +117,9 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.HTMLRequest{ req, _ := gotenberg.NewHTMLRequest("index.html")
IndexFilePath: "index.html", req.SetHeader("header.html")
Options: &gotenberg.HTMLOptions{ req.SetFooter("footer.html")
HeaderFilePath: "header.html",
FooterFilePath: "footer.html",
},
}
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }
@@ -123,11 +127,25 @@ func main() {
### PHP ### PHP
TODO ```php
use TheCodingMachine\Gotenberg\Client;
use TheCodingMachine\Gotenberg\DocumentFactory;
use TheCodingMachine\Gotenberg\HTMLRequest;
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
$index = DocumentFactory::makeFromPath('index.html', 'index.html');
$header = DocumentFactory::makeFromPath('header.html', 'header.html');
$footer = DocumentFactory::makeFromPath('footer.html', 'footer.html');
$request = new HTMLRequest($index);
$request->setHeader($header);
$request->setFooter($footer);
$dirPath = "/foo";
$filename = $client->store($request, $dirPath);
```
## Assets ## Assets
You may also send additional files. For instance, images, fonts, stylesheets and so on. You may also send additional files. For instance: images, fonts, stylesheets and so on.
The only requirement is to make sure that their paths The only requirement is to make sure that their paths
are on the same level as the `index.html` file. are on the same level as the `index.html` file.
@@ -169,16 +187,16 @@ 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](#office.fonts).
### Guzzle ### cURL
```bash ```bash
$ curl --request POST \ $ curl --request POST \
--url http://localhost:3000/convert/html \ --url http://localhost:3000/convert/html \
--header 'Content-Type: multipart/form-data' \ --header 'Content-Type: multipart/form-data' \
--form files=@index.html --form files=@index.html \
--form files=@style.css --form files=@style.css \
--form files=@img.png --form files=@img.png \
--form files=@font.woff --form files=@font.woff \
> result.pdf > result.pdf
``` ```
@@ -189,14 +207,12 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.HTMLRequest{ req, _ := gotenberg.NewHTMLRequest("index.html")
IndexFilePath: "index.html", req.SetAssets([]string{
AssetFilePaths: []string{ "font.woff",
"style.css", "img.gif",
"img.png", "style.css",
"font.woff", })
},
}
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }
@@ -204,31 +220,47 @@ func main() {
### PHP ### PHP
TODO ```php
use TheCodingMachine\Gotenberg\Client;
use TheCodingMachine\Gotenberg\DocumentFactory;
use TheCodingMachine\Gotenberg\HTMLRequest;
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
$index = DocumentFactory::makeFromPath('index.html', 'index.html');
$assets = [
DocumentFactory::makeFromPath('style.css', 'style.css'),
DocumentFactory::makeFromPath('img.png', 'img.png'),
DocumentFactory::makeFromPath('font.woff', 'font.woff'),
];
$request = new HTMLRequest($index);
$request->setAssets($assets);
$dirPath = "/foo";
$filename = $client->store($request, $dirPath);
```
## Paper size, margins, orientation ## Paper size, margins, orientation
You may also customize the resulting PDF paper. You may also customize the resulting PDF format.
By default, it will be rendered in `A4` size with `1 inch` margins and `portrait` orientation. By default, it will be rendered with `A4` size, `1 inch` margins and `portrait` orientation.
> Paper size and margins have to be provided in `inches`. > Paper size and margins have to be provided in `inches`.
> Also, you have to set both `paperWidth` and `paperHeight`. Same for margins. > Also, you have to set both `paperWidth` and `paperHeight`. Same for margins.
### Guzzle ### cURL
```bash ```bash
$ curl --request POST \ $ curl --request POST \
--url http://localhost:3000/convert/html \ --url http://localhost:3000/convert/html \
--header 'Content-Type: multipart/form-data' \ --header 'Content-Type: multipart/form-data' \
--form files=@index.html --form files=@index.html \
--form paperWidth=8.27 --form paperWidth=8.27 \
--form paperHeight=11.27 --form paperHeight=11.27 \
--form marginTop=0 --form marginTop=0 \
--form marginBottom=0 --form marginBottom=0 \
--form marginLeft=0 --form marginLeft=0 \
--form marginRight=0 --form marginRight=0 \
--form landscape=true --form landscape=true \
> result.pdf > result.pdf
``` ```
@@ -239,14 +271,10 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.HTMLRequest{ req, _ := gotenberg.NewHTMLRequest("index.html")
IndexFilePath: "index.html", req.SetPaperSize(gotenberg.A4)
Options: &gotenberg.HTMLOptions{ req.SetMargins(gotenberg.NormalMargins)
PaperSize: gotenberg.A4, req.SetLandscape(true)
PaperMargins: gotenberg.NoMargins,
Landscape: true
},
}
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }
@@ -254,4 +282,18 @@ func main() {
### PHP ### PHP
TODO ```php
use TheCodingMachine\Gotenberg\Client;
use TheCodingMachine\Gotenberg\DocumentFactory;
use TheCodingMachine\Gotenberg\HTMLRequest;
use TheCodingMachine\Gotenberg\Request;
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
$index = DocumentFactory::makeFromPath('index.html', 'index.html');
$request = new HTMLRequest($index);
$request->setPaperSize(Request::A4);
$request->setMargins(Request::NO_MARGINS);
$request->setLandscape(true);
$dirPath = "/foo";
$filename = $client->store($request, $dirPath);
```

View File

@@ -11,7 +11,7 @@ It accepts `POST` requests with a `multipart/form-data` Content-Type.
Markdown conversions work the same as HTML conversions. Markdown conversions work the same as HTML conversions.
Only difference is that you have access to the Go template function `toHTML` Only difference is that you have access to the Go template function `toHTML`
in the file `index.html` which will convert a given markdown file to HTML. in the file `index.html`. This function will convert a given markdown file to HTML.
For instance: For instance:
@@ -28,14 +28,14 @@ For instance:
</html> </html>
``` ```
### Guzzle ### cURL
```bash ```bash
$ curl --request POST \ $ curl --request POST \
--url http://localhost:3000/convert/markdown \ --url http://localhost:3000/convert/markdown \
--header 'Content-Type: multipart/form-data' \ --header 'Content-Type: multipart/form-data' \
--form files=@index.html --form files=@index.html \
--form files=@file.md --form files=@file.md \
> result.pdf > result.pdf
``` ```
@@ -46,12 +46,7 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.MarkdownRequest{ req, _ := gotenberg.NewMarkdownRequest("index.html", []string{"file.md"})
IndexFilePath: "index.html",
MarkdownFilePaths: []string{
"file.md",
},
}
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }
@@ -59,4 +54,17 @@ func main() {
### PHP ### PHP
TODO ```php
use TheCodingMachine\Gotenberg\Client;
use TheCodingMachine\Gotenberg\DocumentFactory;
use TheCodingMachine\Gotenberg\MarkdownRequest;
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
$index = DocumentFactory::makeFromPath('index.html', 'index.html');
$markdowns = [
DocumentFactory::makeFromPath('file.md', 'file.md'),
];
$request = new MarkdownRequest($index, $markdowns);
$dirPath = "/foo";
$filename = $client->store($request, $dirPath);
```

View File

@@ -2,7 +2,7 @@
title: Office title: Office
--- ---
Gotenberg provides the endpoint `/convert/office` for Office documents conversions. Gotenberg provides the endpoint `/convert/office` for Office document conversions.
It accepts `POST` requests with a `multipart/form-data` Content-Type. It accepts `POST` requests with a `multipart/form-data` Content-Type.
@@ -10,6 +10,8 @@ It accepts `POST` requests with a `multipart/form-data` Content-Type.
You may send one or more Office documents. Following file extensions are accepted: You may send one or more Office documents. Following file extensions are accepted:
* `.txt`
* `.rtf`
* `.doc` * `.doc`
* `.docx` * `.docx`
* `.odt` * `.odt`
@@ -26,14 +28,14 @@ All files will be merged into a single resulting PDF.
> That's why for Office conversions, the API does only one conversion at a time. > That's why for Office conversions, the API does only one conversion at a time.
> See the [scalability section](#scalability) to find how to mitigate this issue. > See the [scalability section](#scalability) to find how to mitigate this issue.
### Guzzle ### cURL
```bash ```bash
$ curl --request POST \ $ 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 files=@document2.docx --form files=@document2.docx \
> result.pdf > result.pdf
``` ```
@@ -44,12 +46,7 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.OfficeRequest{ req, _ := gotenberg.NewOfficeRequest([]string{"document.docx", "document2.docx"})
FilePaths: []string{
"document.docx",
"document2.docx",
},
}
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }
@@ -57,7 +54,76 @@ func main() {
### PHP ### PHP
TODO ```php
use TheCodingMachine\Gotenberg\Client;
use TheCodingMachine\Gotenberg\DocumentFactory;
use TheCodingMachine\Gotenberg\OfficeRequest;
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
$files = [
DocumentFactory::makeFromPath('document.docx', 'document.docx'),
DocumentFactory::makeFromPath('document2.docx', 'document2.docx'),
];
$request = new OfficeRequest($files);
$dirPath = "/foo";
$filename = $client->store($request, $dirPath);
```
## Paper size and orientation
You may also customize the resulting PDF format.
By default, it will be rendered with `A4` size and `portrait` orientation.
> Paper size has to be provided in `inches`.
> Also, you have to set both `paperWidth` and `paperHeight`.
### cURL
```bash
$ curl --request POST \
--url http://localhost:3000/convert/office \
--header 'Content-Type: multipart/form-data' \
--form files=@document.docx \
--form paperWidth=8.27 \
--form paperHeight=11.27 \
--form landscape=true \
> result.pdf
```
### Go
```golang
import "github.com/thecodingmachine/gotenberg/pkg"
func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req, _ := gotenberg.NewOfficeRequest([]string{"document.docx"})
req.SetPaperSize(gotenberg.A4)
req.SetLandscape(true)
dest := "result.pdf"
c.Store(req, dest)
}
```
### PHP
```php
use TheCodingMachine\Gotenberg\Client;
use TheCodingMachine\Gotenberg\DocumentFactory;
use TheCodingMachine\Gotenberg\OfficeRequest;
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
$files = [
DocumentFactory::makeFromPath('document.docx', 'document.docx'),
];
$request = new OfficeRequest($files);
$request->setPaperSize(Request::A4);
$request->setMargins(Request::NO_MARGINS);
$request->setLandscape(true);
$dirPath = "/foo";
$filename = $client->store($request, $dirPath);
```
## Fonts ## Fonts

View File

@@ -11,14 +11,14 @@ It accepts `POST` requests with a `multipart/form-data` Content-Type.
Nothing special here: you may send one or more PDF files and the API Nothing special 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.
### Guzzle ### cURL
```bash ```bash
$ curl --request POST \ $ curl --request POST \
--url http://localhost:3000/merge \ --url http://localhost:3000/merge \
--header 'Content-Type: multipart/form-data' \ --header 'Content-Type: multipart/form-data' \
--form files=@file.pdf --form files=@file.pdf \
--form files=@file2.pdf --form files=@file2.pdf \
> result.pdf > result.pdf
``` ```
@@ -29,12 +29,7 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() { func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"} c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req := &gotenberg.MergeRequest{ req, _ := gotenberg.NewMergeRequest([]string{"file.pdf", "file2.pdf"})
FilePaths: []string{
"file.pdf",
"file2.pdf",
},
}
dest := "result.pdf" dest := "result.pdf"
c.Store(req, dest) c.Store(req, dest)
} }
@@ -42,4 +37,17 @@ func main() {
### PHP ### PHP
TODO ```php
use TheCodingMachine\Gotenberg\Client;
use TheCodingMachine\Gotenberg\DocumentFactory;
use TheCodingMachine\Gotenberg\MergeRequest;
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
$files = [
DocumentFactory::makeFromPath('file.pdf', 'file.pdf'),
DocumentFactory::makeFromPath('file2.pdf', 'file2.pdf'),
];
$request = new MergeRequest($files);
$dirPath = "/foo";
$filename = $client->store($request, $dirPath);
```

View File

@@ -7,19 +7,18 @@ All endpoints accept a form field named `webhookURL`.
If provided, the API will send the resulting PDF file in a `POST` request with the `application/pdf` Content-Type If provided, the API will send the resulting PDF file in a `POST` request with the `application/pdf` Content-Type
to given URL. to given URL.
By doing so, your requests to the API will be done before the conversions are actually done! By doing so, your requests to the API will be over before the conversions are actually done!
## Examples ## Examples
### Guzzle ### cURL
```bash ```bash
$ curl --request POST \ $ curl --request POST \
--url http://localhost:3000/convert/html \ --url http://localhost:3000/convert/html \
--header 'Content-Type: multipart/form-data' \ --header 'Content-Type: multipart/form-data' \
--form files=@index.html --form files=@index.html \
--form webhookURL='http://myapp.com/webhook/' --form webhookURL='http://myapp.com/webhook/'
> result.pdf
``` ```
### Go ### Go
@@ -42,4 +41,14 @@ func main() {
### PHP ### PHP
TODO ```php
use TheCodingMachine\Gotenberg\Client;
use TheCodingMachine\Gotenberg\DocumentFactory;
use TheCodingMachine\Gotenberg\HTMLRequest;
$client = new Client('http://localhost:3000', new \Http\Adapter\Guzzle6\Client());
$index = DocumentFactory::makeFromPath('index.html', 'index.html');
$request = new HTMLRequest($index);
$request->setWebhookURL('http://myapp.com/webhook/');
$resp = $client->post($request);
```

View File

@@ -71,7 +71,7 @@
<ul> <ul>
<li>HTML and Markdown conversions using Google Chrome headless</li> <li>HTML and Markdown conversions using Google Chrome headless</li>
<li>Office conversions (.docx, .doc, .odt, .pptx, .ppt, .odp and so on) using <a href="https://github.com/dagwieers/unoconv">unoconv</a></li> <li>Office conversions (.txt, .rtf, .docx, .doc, .odt, .pptx, .ppt, .odp and so on) using <a href="https://github.com/dagwieers/unoconv">unoconv</a></li>
<li>Performance: Google Chrome and Libreoffice (unoconv) started once in the background thanks to PM2</li> <li>Performance: Google Chrome and Libreoffice (unoconv) started once in the background thanks to PM2</li>
<li>Failure prevention: PM2 automatically restarts previous processes if they fail</li> <li>Failure prevention: PM2 automatically restarts previous processes if they fail</li>
<li>Assets: send your header, footer, images, fonts, stylesheets and so on for converting your HTML and Markdown to beaufitul PDFs!</li> <li>Assets: send your header, footer, images, fonts, stylesheets and so on for converting your HTML and Markdown to beaufitul PDFs!</li>
@@ -168,15 +168,15 @@ which will be converted to PDF.</p>
<span class="p">&lt;</span><span class="p">/</span><span class="nt">html</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="p">/</span><span class="nt">html</span><span class="p">&gt;</span>
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.basic.guzzle" href="#html.basic.guzzle"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.basic.c_url" href="#html.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>Guzzle</h3> </a>cURL</h3>
<pre class="chroma">$ curl --request POST <span class="se">\ <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> --url http://localhost:3000/convert/html <span class="se">\
</span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\ </span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html <span class="se">\
&gt; result.pdf </span><span class="se"></span> &gt; result.pdf
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.basic.go" href="#html.basic.go"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.basic.go" href="#html.basic.go">
@@ -187,9 +187,7 @@ which will be converted to PDF.</p>
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span> <span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLRequest</span><span class="p">{</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nx">NewHTMLRequest</span><span class="p">(</span><span class="s">&#34;index.html&#34;</span><span class="p">)</span>
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">&#34;index.html&#34;</span><span class="p">,</span>
<span class="p">}</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span> <span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span> <span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
@@ -199,7 +197,16 @@ which will be converted to PDF.</p>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3> </a>PHP</h3>
<p>TODO</p> <pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\HTMLRequest;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;);
</span><span class="x">$request = new HTMLRequest($index);
</span><span class="x">$dirPath = &#34;/foo&#34;;
</span><span class="x">$filename = $client-&gt;store($request, $dirPath);
</span><span class="x"></span></pre>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.header_and_footer" href="#html.header_and_footer"> <h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.header_and_footer" href="#html.header_and_footer">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
@@ -241,17 +248,17 @@ Respectively, a file named <code>header.html</code> and <code>footer.html</code>
Also, <code>footer.html</code> CSS properties override the ones from <code>header.html</code>.</p> Also, <code>footer.html</code> CSS properties override the ones from <code>header.html</code>.</p>
</blockquote> </blockquote>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.header_and_footer.guzzle" href="#html.header_and_footer.guzzle"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.header_and_footer.c_url" href="#html.header_and_footer.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>Guzzle</h3> </a>cURL</h3>
<pre class="chroma">$ curl --request POST <span class="se">\ <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> --url http://localhost:3000/convert/html <span class="se">\
</span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\ </span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html <span class="se">\
--form <span class="nv">files</span><span class="o">=</span>@header.html </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@header.html <span class="se">\
--form <span class="nv">files</span><span class="o">=</span>@footer.html </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@footer.html <span class="se">\
&gt; result.pdf </span><span class="se"></span> &gt; result.pdf
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.header_and_footer.go" href="#html.header_and_footer.go"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.header_and_footer.go" href="#html.header_and_footer.go">
@@ -262,13 +269,9 @@ Also, <code>footer.html</code> CSS properties override the ones from <code>heade
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span> <span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLRequest</span><span class="p">{</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nx">NewHTMLRequest</span><span class="p">(</span><span class="s">&#34;index.html&#34;</span><span class="p">)</span>
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">&#34;index.html&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">SetHeader</span><span class="p">(</span><span class="s">&#34;header.html&#34;</span><span class="p">)</span>
<span class="nx">Options</span><span class="p">:</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLOptions</span><span class="p">{</span> <span class="nx">req</span><span class="p">.</span><span class="nx">SetFooter</span><span class="p">(</span><span class="s">&#34;footer.html&#34;</span><span class="p">)</span>
<span class="nx">HeaderFilePath</span><span class="p">:</span> <span class="s">&#34;header.html&#34;</span><span class="p">,</span>
<span class="nx">FooterFilePath</span><span class="p">:</span> <span class="s">&#34;footer.html&#34;</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span> <span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span> <span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
@@ -278,13 +281,26 @@ Also, <code>footer.html</code> CSS properties override the ones from <code>heade
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3> </a>PHP</h3>
<p>TODO</p> <pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\HTMLRequest;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;);
</span><span class="x">$header = DocumentFactory::makeFromPath(&#39;header.html&#39;, &#39;header.html&#39;);
</span><span class="x">$footer = DocumentFactory::makeFromPath(&#39;footer.html&#39;, &#39;footer.html&#39;);
</span><span class="x">$request = new HTMLRequest($index);
</span><span class="x">$request-&gt;setHeader($header);
</span><span class="x">$request-&gt;setFooter($footer);
</span><span class="x">$dirPath = &#34;/foo&#34;;
</span><span class="x">$filename = $client-&gt;store($request, $dirPath);
</span><span class="x"></span></pre>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets" href="#html.assets"> <h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets" href="#html.assets">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>Assets</h2> </a>Assets</h2>
<p>You may also send additional files. For instance, images, fonts, stylesheets and so on.</p> <p>You may also send additional files. For instance: images, fonts, stylesheets and so on.</p>
<p>The only requirement is to make sure that their paths <p>The only requirement is to make sure that their paths
are on the same level as the <code>index.html</code> file.</p> are on the same level as the <code>index.html</code> file.</p>
@@ -326,18 +342,18 @@ are on the same level as the <code>index.html</code> file.</p>
see to the <a href="#office.fonts">fonts section</a>.</p> see to the <a href="#office.fonts">fonts section</a>.</p>
</blockquote> </blockquote>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets.guzzle" href="#html.assets.guzzle"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets.c_url" href="#html.assets.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>Guzzle</h3> </a>cURL</h3>
<pre class="chroma">$ curl --request POST <span class="se">\ <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> --url http://localhost:3000/convert/html <span class="se">\
</span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\ </span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html <span class="se">\
--form <span class="nv">files</span><span class="o">=</span>@style.css </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@style.css <span class="se">\
--form <span class="nv">files</span><span class="o">=</span>@img.png </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@img.png <span class="se">\
--form <span class="nv">files</span><span class="o">=</span>@font.woff </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@font.woff <span class="se">\
&gt; result.pdf </span><span class="se"></span> &gt; result.pdf
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets.go" href="#html.assets.go"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets.go" href="#html.assets.go">
@@ -348,14 +364,12 @@ see to the <a href="#office.fonts">fonts section</a>.</p>
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span> <span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLRequest</span><span class="p">{</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nx">NewHTMLRequest</span><span class="p">(</span><span class="s">&#34;index.html&#34;</span><span class="p">)</span>
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">&#34;index.html&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">SetAssets</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span>
<span class="nx">AssetFilePaths</span><span class="p">:</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span> <span class="s">&#34;font.woff&#34;</span><span class="p">,</span>
<span class="s">&#34;style.css&#34;</span><span class="p">,</span> <span class="s">&#34;img.gif&#34;</span><span class="p">,</span>
<span class="s">&#34;img.png&#34;</span><span class="p">,</span> <span class="s">&#34;style.css&#34;</span><span class="p">,</span>
<span class="s">&#34;font.woff&#34;</span><span class="p">,</span> <span class="p">})</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span> <span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span> <span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
@@ -365,37 +379,52 @@ see to the <a href="#office.fonts">fonts section</a>.</p>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3> </a>PHP</h3>
<p>TODO</p> <pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\HTMLRequest;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;);
</span><span class="x">$assets = [
</span><span class="x"> DocumentFactory::makeFromPath(&#39;style.css&#39;, &#39;style.css&#39;),
</span><span class="x"> DocumentFactory::makeFromPath(&#39;img.png&#39;, &#39;img.png&#39;),
</span><span class="x"> DocumentFactory::makeFromPath(&#39;font.woff&#39;, &#39;font.woff&#39;),
</span><span class="x">];
</span><span class="x">$request = new HTMLRequest($index);
</span><span class="x">$request-&gt;setAssets($assets);
</span><span class="x">$dirPath = &#34;/foo&#34;;
</span><span class="x">$filename = $client-&gt;store($request, $dirPath);
</span><span class="x"></span></pre>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation" href="#html.paper_size_margins_orientation"> <h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation" href="#html.paper_size_margins_orientation">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>Paper size, margins, orientation</h2> </a>Paper size, margins, orientation</h2>
<p>You may also customize the resulting PDF paper.</p> <p>You may also customize the resulting PDF format.</p>
<p>By default, it will be rendered in <code>A4</code> size with <code>1 inch</code> margins and <code>portrait</code> orientation.</p> <p>By default, it will be rendered with <code>A4</code> size, <code>1 inch</code> margins and <code>portrait</code> orientation.</p>
<blockquote> <blockquote>
<p>Paper size and margins have to be provided in <code>inches</code>. <p>Paper size and margins have to be provided in <code>inches</code>.
Also, you have to set both <code>paperWidth</code> and <code>paperHeight</code>. Same for margins.</p> Also, you have to set both <code>paperWidth</code> and <code>paperHeight</code>. Same for margins.</p>
</blockquote> </blockquote>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation.guzzle" href="#html.paper_size_margins_orientation.guzzle"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation.c_url" href="#html.paper_size_margins_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>Guzzle</h3> </a>cURL</h3>
<pre class="chroma">$ curl --request POST <span class="se">\ <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> --url http://localhost:3000/convert/html <span class="se">\
</span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\ </span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html <span class="se">\
--form <span class="nv">paperWidth</span><span class="o">=</span><span class="m">8</span>.27 </span><span class="se"></span> --form <span class="nv">paperWidth</span><span class="o">=</span><span class="m">8</span>.27 <span class="se">\
--form <span class="nv">paperHeight</span><span class="o">=</span><span class="m">11</span>.27 </span><span class="se"></span> --form <span class="nv">paperHeight</span><span class="o">=</span><span class="m">11</span>.27 <span class="se">\
--form <span class="nv">marginTop</span><span class="o">=</span><span class="m">0</span> </span><span class="se"></span> --form <span class="nv">marginTop</span><span class="o">=</span><span class="m">0</span> <span class="se">\
--form <span class="nv">marginBottom</span><span class="o">=</span><span class="m">0</span> </span><span class="se"></span> --form <span class="nv">marginBottom</span><span class="o">=</span><span class="m">0</span> <span class="se">\
--form <span class="nv">marginLeft</span><span class="o">=</span><span class="m">0</span> </span><span class="se"></span> --form <span class="nv">marginLeft</span><span class="o">=</span><span class="m">0</span> <span class="se">\
--form <span class="nv">marginRight</span><span class="o">=</span><span class="m">0</span> </span><span class="se"></span> --form <span class="nv">marginRight</span><span class="o">=</span><span class="m">0</span> <span class="se">\
--form <span class="nv">landscape</span><span class="o">=</span><span class="nb">true</span> </span><span class="se"></span> --form <span class="nv">landscape</span><span class="o">=</span><span class="nb">true</span> <span class="se">\
&gt; result.pdf </span><span class="se"></span> &gt; result.pdf
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation.go" href="#html.paper_size_margins_orientation.go"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation.go" href="#html.paper_size_margins_orientation.go">
@@ -406,14 +435,10 @@ Also, you have to set both <code>paperWidth</code> and <code>paperHeight</code>.
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span> <span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLRequest</span><span class="p">{</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nx">NewHTMLRequest</span><span class="p">(</span><span class="s">&#34;index.html&#34;</span><span class="p">)</span>
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">&#34;index.html&#34;</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">SetPaperSize</span><span class="p">(</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">A4</span><span class="p">)</span>
<span class="nx">Options</span><span class="p">:</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLOptions</span><span class="p">{</span> <span class="nx">req</span><span class="p">.</span><span class="nx">SetMargins</span><span class="p">(</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">NormalMargins</span><span class="p">)</span>
<span class="nx">PaperSize</span><span class="p">:</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nx">A4</span><span class="p">,</span> <span class="nx">req</span><span class="p">.</span><span class="nx">SetLandscape</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
<span class="nx">PaperMargins</span><span class="p">:</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nx">NoMargins</span><span class="p">,</span>
<span class="nx">Landscape</span><span class="p">:</span> <span class="kc">true</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span> <span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span> <span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
@@ -423,7 +448,20 @@ Also, you have to set both <code>paperWidth</code> and <code>paperHeight</code>.
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3> </a>PHP</h3>
<p>TODO</p> <pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\HTMLRequest;
</span><span class="x">use TheCodingMachine\Gotenberg\Request;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;);
</span><span class="x">$request = new HTMLRequest($index);
</span><span class="x">$request-&gt;setPaperSize(Request::A4);
</span><span class="x">$request-&gt;setMargins(Request::NO_MARGINS);
</span><span class="x">$request-&gt;setLandscape(true);
</span><span class="x">$dirPath = &#34;/foo&#34;;
</span><span class="x">$filename = $client-&gt;store($request, $dirPath);
</span><span class="x"></span></pre>
</div> </div>
@@ -442,7 +480,7 @@ Also, you have to set both <code>paperWidth</code> and <code>paperHeight</code>.
<p>Markdown conversions work the same as HTML conversions.</p> <p>Markdown conversions work the same as HTML conversions.</p>
<p>Only difference is that you have access to the Go template function <code>toHTML</code> <p>Only difference is that you have access to the Go template function <code>toHTML</code>
in the file <code>index.html</code> which will convert a given markdown file to HTML.</p> in the file <code>index.html</code>. This function will convert a given markdown file to HTML.</p>
<p>For instance:</p> <p>For instance:</p>
@@ -458,16 +496,16 @@ in the file <code>index.html</code> which will convert a given markdown file to
<span class="p">&lt;</span><span class="p">/</span><span class="nt">html</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="p">/</span><span class="nt">html</span><span class="p">&gt;</span>
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="markdown.basic.guzzle" href="#markdown.basic.guzzle"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="markdown.basic.c_url" href="#markdown.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>Guzzle</h3> </a>cURL</h3>
<pre class="chroma">$ curl --request POST <span class="se">\ <pre class="chroma">$ curl --request POST <span class="se">\
</span><span class="se"></span> --url http://localhost:3000/convert/markdown <span class="se">\ </span><span class="se"></span> --url http://localhost:3000/convert/markdown <span class="se">\
</span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\ </span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html <span class="se">\
--form <span class="nv">files</span><span class="o">=</span>@file.md </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@file.md <span class="se">\
&gt; result.pdf </span><span class="se"></span> &gt; result.pdf
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="markdown.basic.go" href="#markdown.basic.go"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="markdown.basic.go" href="#markdown.basic.go">
@@ -478,12 +516,7 @@ in the file <code>index.html</code> which will convert a given markdown file to
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span> <span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">MarkdownRequest</span><span class="p">{</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nx">NewMarkdownRequest</span><span class="p">(</span><span class="s">&#34;index.html&#34;</span><span class="p">,</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;file.md&#34;</span><span class="p">})</span>
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">&#34;index.html&#34;</span><span class="p">,</span>
<span class="nx">MarkdownFilePaths</span><span class="p">:</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span>
<span class="s">&#34;file.md&#34;</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span> <span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span> <span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
@@ -493,7 +526,19 @@ in the file <code>index.html</code> which will convert a given markdown file to
<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>
<p>TODO</p> <pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\MarkdownRequest;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;);
</span><span class="x">$markdowns = [
</span><span class="x"> DocumentFactory::makeFromPath(&#39;file.md&#39;, &#39;file.md&#39;),
</span><span class="x">];
</span><span class="x">$request = new MarkdownRequest($index, $markdowns);
</span><span class="x">$dirPath = &#34;/foo&#34;;
</span><span class="x">$filename = $client-&gt;store($request, $dirPath);
</span><span class="x"></span></pre>
</div> </div>
@@ -501,7 +546,7 @@ in the file <code>index.html</code> which will convert a given markdown file to
<h1 class="Heading"><a class="Anchor" aria-hidden="true" id="office" href="#office"> <h1 class="Heading"><a class="Anchor" aria-hidden="true" id="office" href="#office">
<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>Office</h1> </a>Office</h1>
<p>Gotenberg provides the endpoint <code>/convert/office</code> for Office documents conversions.</p> <p>Gotenberg provides the endpoint <code>/convert/office</code> for Office document conversions.</p>
<p>It accepts <code>POST</code> requests with a <code>multipart/form-data</code> Content-Type.</p> <p>It accepts <code>POST</code> requests with a <code>multipart/form-data</code> Content-Type.</p>
@@ -512,6 +557,8 @@ in the file <code>index.html</code> which will convert a given markdown file to
<p>You may send one or more Office documents. Following file extensions are accepted:</p> <p>You may send one or more Office documents. Following file extensions are accepted:</p>
<ul> <ul>
<li><code>.txt</code></li>
<li><code>.rtf</code></li>
<li><code>.doc</code></li> <li><code>.doc</code></li>
<li><code>.docx</code></li> <li><code>.docx</code></li>
<li><code>.odt</code></li> <li><code>.odt</code></li>
@@ -531,16 +578,16 @@ Thats why for Office conversions, the API does only one conversion at a time.
See the <a href="#scalability">scalability section</a> to find how to mitigate this issue.</p> See the <a href="#scalability">scalability section</a> to find how to mitigate this issue.</p>
</blockquote> </blockquote>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.basic.guzzle" href="#office.basic.guzzle"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.basic.c_url" href="#office.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>Guzzle</h3> </a>cURL</h3>
<pre class="chroma">$ curl --request POST <span class="se">\ <pre class="chroma">$ curl --request POST <span class="se">\
</span><span class="se"></span> --url http://localhost:3000/convert/office <span class="se">\ </span><span class="se"></span> --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><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@document.docx <span class="se">\
--form <span class="nv">files</span><span class="o">=</span>@document2.docx </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@document2.docx <span class="se">\
&gt; result.pdf </span><span class="se"></span> &gt; result.pdf
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.basic.go" href="#office.basic.go"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.basic.go" href="#office.basic.go">
@@ -551,12 +598,7 @@ See the <a href="#scalability">scalability section</a> to find how to mitigate t
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span> <span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">OfficeRequest</span><span class="p">{</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nx">NewOfficeRequest</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;document.docx&#34;</span><span class="p">,</span> <span class="s">&#34;document2.docx&#34;</span><span class="p">})</span>
<span class="nx">FilePaths</span><span class="p">:</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span>
<span class="s">&#34;document.docx&#34;</span><span class="p">,</span>
<span class="s">&#34;document2.docx&#34;</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span> <span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span> <span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
@@ -566,7 +608,82 @@ See the <a href="#scalability">scalability section</a> to find how to mitigate t
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3> </a>PHP</h3>
<p>TODO</p> <pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\OfficeRequest;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$files = [
</span><span class="x"> DocumentFactory::makeFromPath(&#39;document.docx&#39;, &#39;document.docx&#39;),
</span><span class="x"> DocumentFactory::makeFromPath(&#39;document2.docx&#39;, &#39;document2.docx&#39;),
</span><span class="x">];
</span><span class="x">$request = new OfficeRequest($files);
</span><span class="x">$dirPath = &#34;/foo&#34;;
</span><span class="x">$filename = $client-&gt;store($request, $dirPath);
</span><span class="x"></span></pre>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="office.paper_size_and_orientation" href="#office.paper_size_and_orientation">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>Paper size and orientation</h2>
<p>You may also customize the resulting PDF format.</p>
<p>By default, it will be rendered with <code>A4</code> size and <code>portrait</code> orientation.</p>
<blockquote>
<p>Paper size has to be provided in <code>inches</code>.
Also, you have to set both <code>paperWidth</code> and <code>paperHeight</code>.</p>
</blockquote>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.paper_size_and_orientation.c_url" href="#office.paper_size_and_orientation.c_url">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>cURL</h3>
<pre class="chroma">$ curl --request POST <span class="se">\
</span><span class="se"></span> --url http://localhost:3000/convert/office <span class="se">\
</span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@document.docx <span class="se">\
</span><span class="se"></span> --form <span class="nv">paperWidth</span><span class="o">=</span><span class="m">8</span>.27 <span class="se">\
</span><span class="se"></span> --form <span class="nv">paperHeight</span><span class="o">=</span><span class="m">11</span>.27 <span class="se">\
</span><span class="se"></span> --form <span class="nv">landscape</span><span class="o">=</span><span class="nb">true</span> <span class="se">\
</span><span class="se"></span> &gt; result.pdf
</pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.paper_size_and_orientation.go" href="#office.paper_size_and_orientation.go">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>Go</h3>
<pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span>
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nx">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">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="nx">SetLandscape</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span>
</pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.paper_size_and_orientation.php" href="#office.paper_size_and_orientation.php">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3>
<pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\OfficeRequest;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$files = [
</span><span class="x"> DocumentFactory::makeFromPath(&#39;document.docx&#39;, &#39;document.docx&#39;),
</span><span class="x">];
</span><span class="x">$request = new OfficeRequest($files);
</span><span class="x">$request-&gt;setPaperSize(Request::A4);
</span><span class="x">$request-&gt;setMargins(Request::NO_MARGINS);
</span><span class="x">$request-&gt;setLandscape(true);
</span><span class="x">$dirPath = &#34;/foo&#34;;
</span><span class="x">$filename = $client-&gt;store($request, $dirPath);
</span><span class="x"></span></pre>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="office.fonts" href="#office.fonts"> <h2 class="Heading"><a class="Anchor" aria-hidden="true" id="office.fonts" href="#office.fonts">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
@@ -598,16 +715,16 @@ See the <a href="#scalability">scalability section</a> to find how to mitigate t
<p>Nothing special here: you may send one or more PDF files and the API <p>Nothing special 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>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="merge.basic.guzzle" href="#merge.basic.guzzle"> <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>Guzzle</h3> </a>cURL</h3>
<pre class="chroma">$ curl --request POST <span class="se">\ <pre class="chroma">$ curl --request POST <span class="se">\
</span><span class="se"></span> --url http://localhost:3000/merge <span class="se">\ </span><span class="se"></span> --url http://localhost:3000/merge <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>@file.pdf </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@file.pdf <span class="se">\
--form <span class="nv">files</span><span class="o">=</span>@file2.pdf </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@file2.pdf <span class="se">\
&gt; result.pdf </span><span class="se"></span> &gt; result.pdf
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="merge.basic.go" href="#merge.basic.go"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="merge.basic.go" href="#merge.basic.go">
@@ -618,12 +735,7 @@ will merge them and return the resulting PDF file.</p>
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span> <span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span> <span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">MergeRequest</span><span class="p">{</span> <span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nx">NewMergeRequest</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;file.pdf&#34;</span><span class="p">,</span> <span class="s">&#34;file2.pdf&#34;</span><span class="p">})</span>
<span class="nx">FilePaths</span><span class="p">:</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span>
<span class="s">&#34;file.pdf&#34;</span><span class="p">,</span>
<span class="s">&#34;file2.pdf&#34;</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">}</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span> <span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span> <span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span> <span class="p">}</span>
@@ -633,7 +745,19 @@ will merge them and return the resulting PDF file.</p>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3> </a>PHP</h3>
<p>TODO</p> <pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\MergeRequest;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$files = [
</span><span class="x"> DocumentFactory::makeFromPath(&#39;file.pdf&#39;, &#39;file.pdf&#39;),
</span><span class="x"> DocumentFactory::makeFromPath(&#39;file2.pdf&#39;, &#39;file2.pdf&#39;),
</span><span class="x">];
</span><span class="x">$request = new MergeRequest($files);
</span><span class="x">$dirPath = &#34;/foo&#34;;
</span><span class="x">$filename = $client-&gt;store($request, $dirPath);
</span><span class="x"></span></pre>
</div> </div>
@@ -646,22 +770,21 @@ will merge them and return the resulting PDF file.</p>
<p>If provided, the API will send the resulting PDF file in a <code>POST</code> request with the <code>application/pdf</code> Content-Type <p>If provided, the API will send the resulting PDF file in a <code>POST</code> request with the <code>application/pdf</code> Content-Type
to given URL.</p> to given URL.</p>
<p>By doing so, your requests to the API will be done before the conversions are actually done!</p> <p>By doing so, your requests to the API will be over before the conversions are actually done!</p>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="webhook.examples" href="#webhook.examples"> <h2 class="Heading"><a class="Anchor" aria-hidden="true" id="webhook.examples" href="#webhook.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> <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> </a>Examples</h2>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="webhook.examples.guzzle" href="#webhook.examples.guzzle"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="webhook.examples.c_url" href="#webhook.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> <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>Guzzle</h3> </a>cURL</h3>
<pre class="chroma">$ curl --request POST <span class="se">\ <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> --url http://localhost:3000/convert/html <span class="se">\
</span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\ </span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html </span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@index.html <span class="se">\
--form <span class="nv">webhookURL</span><span class="o">=</span><span class="s1">&#39;http://myapp.com/webhook/&#39;</span> </span><span class="se"></span> --form <span class="nv">webhookURL</span><span class="o">=</span><span class="s1">&#39;http://myapp.com/webhook/&#39;</span>
&gt; result.pdf
</pre> </pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="webhook.examples.go" href="#webhook.examples.go"> <h3 class="Heading"><a class="Anchor" aria-hidden="true" id="webhook.examples.go" href="#webhook.examples.go">
@@ -687,7 +810,16 @@ to given URL.</p>
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3> </a>PHP</h3>
<p>TODO</p> <pre class="chroma"><span class="x">use TheCodingMachine\Gotenberg\Client;
</span><span class="x">use TheCodingMachine\Gotenberg\DocumentFactory;
</span><span class="x">use TheCodingMachine\Gotenberg\HTMLRequest;
</span><span class="x">
</span><span class="x">$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
</span><span class="x">$index = DocumentFactory::makeFromPath(&#39;index.html&#39;, &#39;index.html&#39;);
</span><span class="x">$request = new HTMLRequest($index);
</span><span class="x">$request-&gt;setWebhookURL(&#39;http://myapp.com/webhook/&#39;);
</span><span class="x">$resp = $client-&gt;post($request);
</span><span class="x"></span></pre>
</div> </div>

2
go.mod
View File

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

2
go.sum
View File

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

View File

@@ -11,11 +11,14 @@ import (
) )
func TestHTML(t *testing.T) { func TestHTML(t *testing.T) {
body, contentType := test.HTMLMultipartForm(t) body, contentType := test.HTMLTestMultipartForm(t)
req := httptest.NewRequest(http.MethodPost, "/convert/html", body) req := httptest.NewRequest(http.MethodPost, "/convert/html", body)
req.Header.Set(echo.HeaderContentType, contentType) req.Header.Set(echo.HeaderContentType, contentType)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
e := echo.New() e := echo.New()
c := e.NewContext(req, rec) c := e.NewContext(req, rec)
assert.NoError(t, convertHTML(c)) if assert.NoError(t, convertHTML(c)) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, "application/pdf", rec.Header().Get(echo.HeaderContentType))
}
} }

View File

@@ -11,11 +11,14 @@ import (
) )
func TestMarkdown(t *testing.T) { func TestMarkdown(t *testing.T) {
body, contentType := test.MarkdownMultipartForm(t) body, contentType := test.MarkdownTestMultipartForm(t)
req := httptest.NewRequest(http.MethodPost, "/convert/markdown", body) req := httptest.NewRequest(http.MethodPost, "/convert/markdown", body)
req.Header.Set(echo.HeaderContentType, contentType) req.Header.Set(echo.HeaderContentType, contentType)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
e := echo.New() e := echo.New()
c := e.NewContext(req, rec) c := e.NewContext(req, rec)
assert.NoError(t, convertMarkdown(c)) if assert.NoError(t, convertMarkdown(c)) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, "application/pdf", rec.Header().Get(echo.HeaderContentType))
}
} }

View File

@@ -25,22 +25,25 @@ func merge(c echo.Context) error {
return fmt.Errorf("getting result file name: %v", err) return fmt.Errorf("getting result file name: %v", err)
} }
filename := fmt.Sprintf("%s.pdf", baseFilename) filename := fmt.Sprintf("%s.pdf", baseFilename)
dest := fmt.Sprintf("%s/%s", r.dirPath, filename) fpath := fmt.Sprintf("%s/%s", r.dirPath, filename)
if r.webhookURL() == "" { if r.webhookURL() == "" {
// if no webhook URL given, run merge // if no webhook URL given, run merge
// and directly return the resulting PDF file // and directly return the resulting PDF file
// or and error. // or and error.
return printer.Merge(fpaths, dest) if err := printer.Merge(fpaths, fpath); err != nil {
return err
}
return c.Attachment(fpath, filename)
} }
// as a webhook URL has been given, we // as a webhook URL has been given, we
// run the following lines in a goroutine so that // run the following lines in a goroutine so that
// it doesn't block. // it doesn't block.
go func() { go func() {
if err := printer.Merge(fpaths, dest); err != nil { if err := printer.Merge(fpaths, fpath); err != nil {
c.Logger().Errorf("%v", err) c.Logger().Errorf("%v", err)
return return
} }
f, err := os.Open(dest) f, err := os.Open(fpath)
if err != nil { if err != nil {
c.Logger().Errorf("%v", err) c.Logger().Errorf("%v", err)
return return

View File

@@ -11,11 +11,14 @@ import (
) )
func TestMerge(t *testing.T) { func TestMerge(t *testing.T) {
body, contentType := test.PDFMultipartForm(t) body, contentType := test.PDFTestMultipartForm(t)
req := httptest.NewRequest(http.MethodPost, "/merge", body) req := httptest.NewRequest(http.MethodPost, "/merge", body)
req.Header.Set(echo.HeaderContentType, contentType) req.Header.Set(echo.HeaderContentType, contentType)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
e := echo.New() e := echo.New()
c := e.NewContext(req, rec) c := e.NewContext(req, rec)
assert.NoError(t, merge(c)) if assert.NoError(t, merge(c)) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, "application/pdf", rec.Header().Get(echo.HeaderContentType))
}
} }

View File

@@ -8,6 +8,8 @@ import (
) )
var officeExts = []string{ var officeExts = []string{
".txt",
".rtf",
".doc", ".doc",
".docx", ".docx",
".odt", ".odt",
@@ -37,5 +39,16 @@ func convertOffice(c echo.Context) error {
return errors.New("no suitable office documents to convert") return errors.New("no suitable office documents to convert")
} }
p := &printer.Office{Context: ctx, FilePaths: fpaths} p := &printer.Office{Context: ctx, FilePaths: fpaths}
paperSize, err := r.paperSize()
if err != nil {
return err
}
p.PaperWidth = paperSize[0]
p.PaperHeight = paperSize[1]
landscape, err := r.landscape()
if err != nil {
return err
}
p.Landscape = landscape
return print(c, p, r) return print(c, p, r)
} }

View File

@@ -11,11 +11,14 @@ import (
) )
func TestOffice(t *testing.T) { func TestOffice(t *testing.T) {
body, contentType := test.OfficeMultipartForm(t) body, contentType := test.OfficeTestMultipartForm(t)
req := httptest.NewRequest(http.MethodPost, "/convert/office", body) req := httptest.NewRequest(http.MethodPost, "/convert/office", body)
req.Header.Set(echo.HeaderContentType, contentType) req.Header.Set(echo.HeaderContentType, contentType)
rec := httptest.NewRecorder() rec := httptest.NewRecorder()
e := echo.New() e := echo.New()
c := e.NewContext(req, rec) c := e.NewContext(req, rec)
assert.NoError(t, convertOffice(c)) if assert.NoError(t, convertOffice(c)) {
assert.Equal(t, http.StatusOK, rec.Code)
assert.Equal(t, "application/pdf", rec.Header().Get(echo.HeaderContentType))
}
} }

View File

@@ -54,8 +54,9 @@ func (c *Chrome) getFullname() string {
func (c *Chrome) isViable() bool { func (c *Chrome) isViable() bool {
// check if Chrome is correctly running. // check if Chrome is correctly running.
devt := devtool.New("http://127.0.0.1:9222") ctx, cancel := context.WithCancel(context.Background())
_, err := devt.Create(context.TODO()) defer cancel()
_, err := devtool.New("http://localhost:9222").Version(ctx)
return err == nil return err == nil
} }

View File

@@ -36,14 +36,15 @@ const defaultHeaderFooterHTML string = "<html><head></head><body></body></html>"
// Print converts HTML to PDF. // Print converts HTML to PDF.
// Credits: https://medium.com/compass-true-north/go-service-to-convert-web-pages-to-pdf-using-headless-chrome-5fd9ffbae1af // Credits: https://medium.com/compass-true-north/go-service-to-convert-web-pages-to-pdf-using-headless-chrome-5fd9ffbae1af
func (html *HTML) Print(destination string) error { func (html *HTML) Print(destination string) error {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// use the DevTools HTTP/JSON API to manage targets (e.g. pages, webworkers). // use the DevTools HTTP/JSON API to manage targets (e.g. pages, webworkers).
devt := devtool.New("http://127.0.0.1:9222") devt, err := devtool.New("http://localhost:9222").Version(ctx)
pt, err := devt.Create(html.Context)
if err != nil { if err != nil {
return fmt.Errorf("creating DevTools target: %v", err) return fmt.Errorf("creating DevTools target: %v", err)
} }
// open a new RPC connection to the Chrome Debugging Protocol target. // open a new RPC connection to the Chrome Debugging Protocol target.
conn, err := rpcc.DialContext(html.Context, pt.WebSocketDebuggerURL) conn, err := rpcc.DialContext(html.Context, devt.WebSocketDebuggerURL)
if err != nil { if err != nil {
return fmt.Errorf("creating RPC connection: %v", err) return fmt.Errorf("creating RPC connection: %v", err)
} }

View File

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

View File

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

View File

@@ -5,9 +5,16 @@ import (
"io/ioutil" "io/ioutil"
pdfcpuAPI "github.com/hhrutter/pdfcpu/pkg/api" pdfcpuAPI "github.com/hhrutter/pdfcpu/pkg/api"
pdfcpuLog "github.com/hhrutter/pdfcpu/pkg/log"
pdfcpuConfig "github.com/hhrutter/pdfcpu/pkg/pdfcpu" pdfcpuConfig "github.com/hhrutter/pdfcpu/pkg/pdfcpu"
) )
func init() {
// disable loggers when merging
// PDFs.
pdfcpuLog.DisableLoggers()
}
// Printer is a type that can create a PDF file from a source. // Printer is a type that can create a PDF file from a source.
// The source is defined in the underlying implementation. // The source is defined in the underlying implementation.
type Printer interface { type Printer interface {
@@ -23,7 +30,7 @@ func Merge(fpaths []string, destination string) error {
func writeBytesToFile(dst string, b []byte) error { func writeBytesToFile(dst string, b []byte) error {
if err := ioutil.WriteFile(dst, b, 0644); err != nil { if err := ioutil.WriteFile(dst, b, 0644); err != nil {
return fmt.Errorf("%s: writting file: %v", dst, err) return fmt.Errorf("%s: writing file: %v", dst, err)
} }
return nil return nil
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -13,12 +13,11 @@ import (
func TestMerge(t *testing.T) { func TestMerge(t *testing.T) {
c := &Client{Hostname: "http://localhost:3000"} c := &Client{Hostname: "http://localhost:3000"}
req := &MergeRequest{ req, err := NewMergeRequest([]string{
FilePaths: []string{ test.PDFTestFilePath(t, "gotenberg.pdf"),
test.PDFTestFilePath(t, "gotenberg.pdf"), test.PDFTestFilePath(t, "gotenberg.pdf"),
test.PDFTestFilePath(t, "gotenberg.pdf"), })
}, require.Nil(t, err)
}
dirPath, err := rand.Get() dirPath, err := rand.Get()
require.Nil(t, err) require.Nil(t, err)
dest := fmt.Sprintf("%s/foo.pdf", dirPath) dest := fmt.Sprintf("%s/foo.pdf", dirPath)

View File

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

View File

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

View File

@@ -2,6 +2,7 @@
set -e set -e
GOLANG_VERSION=1.11.2
VERSION="$1" VERSION="$1"
DOCKER_USER="$2" DOCKER_USER="$2"
DOCKER_PASSWORD="$3" DOCKER_PASSWORD="$3"
@@ -16,6 +17,15 @@ if [ $VERSION_LENGTH -ne 3 ]; then
exit 1 exit 1
fi fi
docker push thecodingmachine/gotenberg:${SEMVER[0]} docker build -t thecodingmachine/gotenberg:base -f build/base/Dockerfile .
docker push thecodingmachine/gotenberg:${SEMVER[0]}.${SEMVER[1]} docker build \
docker push thecodingmachine/gotenberg:${SEMVER[0]}.${SEMVER[1]}.${SEMVER[2]} --build-arg GOLANG_VERSION=${GOLANG_VERSION} \
--build-arg VERSION=${VERSION} \
-t thecodingmachine/gotenberg:${SEMVER[0]} \
-t thecodingmachine/gotenberg:${SEMVER[0]}.${SEMVER[1]} \
-t thecodingmachine/gotenberg:${SEMVER[0]}.${SEMVER[1]}.${SEMVER[2]} \
-f build/package/Dockerfile .
docker push "thecodingmachine/gotenberg:${SEMVER[0]}"
docker push "thecodingmachine/gotenberg:${SEMVER[0]}.${SEMVER[1]}"
docker push "thecodingmachine/gotenberg:${SEMVER[0]}.${SEMVER[1]}.${SEMVER[2]}"

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

File diff suppressed because it is too large Load Diff

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

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

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

Binary file not shown.

View File

@@ -16,31 +16,31 @@ import (
"github.com/thecodingmachine/gotenberg/internal/pkg/rand" "github.com/thecodingmachine/gotenberg/internal/pkg/rand"
) )
// HTMLMultipartForm returns the body // HTMLTestMultipartForm returns the body
// for a multipate/form-data request with all // for a multipate/form-data request with all
// files under "html" folder. // files under "html" folder.
func HTMLMultipartForm(t *testing.T) (*bytes.Buffer, string) { func HTMLTestMultipartForm(t *testing.T) (*bytes.Buffer, string) {
return multipartForm(t, "html") return multipartForm(t, "html")
} }
// MarkdownMultipartForm 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.
func MarkdownMultipartForm(t *testing.T) (*bytes.Buffer, string) { func MarkdownTestMultipartForm(t *testing.T) (*bytes.Buffer, string) {
return multipartForm(t, "markdown") return multipartForm(t, "markdown")
} }
// OfficeMultipartForm returns the body // OfficeTestMultipartForm returns the body
// for a multipate/form-data request with all // for a multipate/form-data request with all
// files under "office" folder. // files under "office" folder.
func OfficeMultipartForm(t *testing.T) (*bytes.Buffer, string) { func OfficeTestMultipartForm(t *testing.T) (*bytes.Buffer, string) {
return multipartForm(t, "office") return multipartForm(t, "office")
} }
// PDFMultipartForm returns the body // PDFTestMultipartForm returns the body
// for a multipate/form-data request with all // for a multipate/form-data request with all
// files under "pdf" folder. // files under "pdf" folder.
func PDFMultipartForm(t *testing.T) (*bytes.Buffer, string) { func PDFTestMultipartForm(t *testing.T) (*bytes.Buffer, string) {
return multipartForm(t, "pdf") return multipartForm(t, "pdf")
} }