Compare commits

...

16 Commits
3.1.2 ... 4.2.0

Author SHA1 Message Date
Julien Neuhart
4827a45f22 adding flat open document support (fixes #47) 2019-02-18 13:46:58 +01:00
Julien Neuhart
40eef457ab adding latest tag (fixes #48) 2019-02-18 13:44:30 +01:00
Julien Neuhart
c22a4d109b minor fix in doc for web fonts 2019-02-01 11:22:06 +01:00
Julien Neuhart
571c3e04c4 adding form field web fonts timeout 2019-02-01 09:40:16 +01:00
Sergei Opletaev
f9fb97a572 Fix for #44 promise wait for fonts (#45)
`runtime.ExceptionDetails: Uncaught exception at 4:47: SyntaxError: Unexpected token %`
2019-02-01 09:21:02 +01:00
Julien Neuhart
e6484bb2d5 Trigger GitHub documentation 2019-01-28 15:56:13 +01:00
Julien Neuhart
19f51fdc1f fixing PHP documentation 2019-01-28 15:36:59 +01:00
Julien Neuhart
25f7ba3ee6 4.0.0 (#42)
* adding URL conversions

* updating gotenberg version in documentation

* pkg: input as variadic string (#39)

* pkg: input as variadic string

* pkg: fix link to github doc

* update doc about v4 client

* make doc

* fixing missing variadic inputs in doc

* adding more fonts

* updating PHP documentation
2019-01-28 15:18:12 +01:00
Julien Neuhart
a3cd1ff4e1 Merge pull request #41 from thecodingmachine/office-paperSize
removing paper size for Office conversion
2019-01-25 15:57:25 +01:00
Julien Neuhart
f62c717f79 fixing typo in docs 2019-01-25 15:50:15 +01:00
Julien Neuhart
3ed99133d4 removing paper size for Office conversion 2019-01-25 15:48:40 +01:00
Julien Neuhart
ab25cc331d fixes #35 2019-01-25 15:02:18 +01:00
Julien Neuhart
2648992a9b adding moar favicons 2019-01-03 16:02:02 +01:00
Julien Neuhart
7bcc3d081e adding liveness section in documentation 2019-01-03 15:56:53 +01:00
Julien Neuhart
affd1c45ca Merge pull request #32 from Peltoche/master
Add a /ping endpoint
2019-01-03 15:37:18 +01:00
Peltoche
8c7458812d Add a /ping endpoint
This endpoint can be used to check the service liveness. It can be used
for the kubernetes liveness and readiness probs.
2019-01-03 15:21:57 +01:00
65 changed files with 758 additions and 211 deletions

View File

@@ -23,7 +23,7 @@ At TheCodingMachine, we build a lot of web applications (intranets, extranets an
Open a terminal and run the following command:
```bash
$ docker run --rm -p 3000:3000 thecodingmachine/gotenberg:3
$ docker run --rm -p 3000:3000 thecodingmachine/gotenberg:4
```
The API is now available on your host at `http://localhost:3000`.
@@ -33,7 +33,7 @@ to learn how to interact with it!
## Badges
[![Docker image layers](https://images.microbadger.com/badges/image/thecodingmachine/gotenberg:3.svg)](https://microbadger.com/images/thecodingmachine/gotenberg:3)
[![Docker image layers](https://images.microbadger.com/badges/image/thecodingmachine/gotenberg:4.svg)](https://microbadger.com/images/thecodingmachine/gotenberg:4)
[![Travis CI](https://travis-ci.org/thecodingmachine/gotenberg.svg?branch=master)](https://travis-ci.org/thecodingmachine/gotenberg)
[![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)

View File

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

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

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

View File

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

View File

@@ -185,7 +185,10 @@ But this won't:
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,
> see to the [fonts section](#office.fonts).
> see to the [fonts section](#fonts).
>
> For web fonts (Google fonts), there is a timeout of 500ms by default. You may update
> this value thanks to the form field `webFontsTimeout`.
### cURL
@@ -208,11 +211,7 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req, _ := gotenberg.NewHTMLRequest("index.html")
req.SetAssets([]string{
"font.woff",
"img.gif",
"style.css",
})
req.SetAssets("font.woff", "img.gif", "style.css")
dest := "result.pdf"
c.Store(req, dest)
}
@@ -234,8 +233,8 @@ $assets = [
];
$request = new HTMLRequest($index);
$request->setAssets($assets);
$dirPath = "/foo";
$filename = $client->store($request, $dirPath);
$dest = "result.pdf";
$client->store($request, $dest);
```
## Paper size, margins, orientation
@@ -294,6 +293,6 @@ $request = new HTMLRequest($index);
$request->setPaperSize(Request::A4);
$request->setMargins(Request::NO_MARGINS);
$request->setLandscape(true);
$dirPath = "/foo";
$filename = $client->store($request, $dirPath);
$dest = "result.pdf";
$client->store($request, $dest);
```

View File

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

View File

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

View File

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

View File

@@ -29,7 +29,7 @@ import "github.com/thecodingmachine/gotenberg/pkg"
func main() {
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
req, _ := gotenberg.NewMergeRequest([]string{"file.pdf", "file2.pdf"})
req, _ := gotenberg.NewMergeRequest("file.pdf", "file2.pdf")
dest := "result.pdf"
c.Store(req, dest)
}
@@ -48,6 +48,6 @@ $files = [
DocumentFactory::makeFromPath('file2.pdf', 'file2.pdf'),
];
$request = new MergeRequest($files);
$dirPath = "/foo";
$filename = $client->store($request, $dirPath);
$dest = "result.pdf";
$client->store($request, $dest);
```

View File

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

View File

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

View File

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

View File

@@ -3,8 +3,19 @@
<meta http-equiv="x-ua-compatible" content="ie=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Gotenberg · A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.</title>
<link rel="apple-touch-icon-precomposed" sizes="57x57" href="theme/gotenberg/img/apple-touch-icon-57x57.png"/>
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="theme/gotenberg/img/apple-touch-icon-114x114.png"/>
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="theme/gotenberg/img/apple-touch-icon-72x72.png"/>
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="theme/gotenberg/img/apple-touch-icon-144x144.png"/>
<link rel="apple-touch-icon-precomposed" sizes="60x60" href="theme/gotenberg/img/apple-touch-icon-60x60.png"/>
<link rel="apple-touch-icon-precomposed" sizes="120x120" href="theme/gotenberg/img/apple-touch-icon-120x120.png"/>
<link rel="apple-touch-icon-precomposed" sizes="76x76" href="theme/gotenberg/img/apple-touch-icon-76x76.png"/>
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="theme/gotenberg/img/apple-touch-icon-152x152.png"/>
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-196x196.png" sizes="196x196"/>
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-96x96.png" sizes="96x96"/>
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-32x32.png" sizes="32x32"/>
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-16x16.png" sizes="16x16"/>
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-16x16.png" sizes="16x16"/>
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-128.png" sizes="128x128"/>
<link rel="stylesheet" href="theme/gotenberg/css/index.css"/>
</head>
<body>
@@ -34,6 +45,10 @@
<a href="#html">HTML</a>
</div>
<div class="item">
<a href="#url">URL</a>
</div>
<div class="item">
<a href="#markdown">Markdown</a>
</div>
@@ -54,6 +69,14 @@
<a href="#scalability">Scalability</a>
</div>
<div class="item">
<a href="#liveness">Liveness</a>
</div>
<div class="item">
<a href="#fonts">Fonts</a>
</div>
<div class="item">
<a href="#links">Links</a>
</div>
@@ -88,7 +111,7 @@
<p>You may start it with:</p>
<pre class="chroma">$ docker run --rm -p <span class="m">3000</span>:3000 thecodingmachine/gotenberg:3
<pre class="chroma">$ docker run --rm -p <span class="m">3000</span>:3000 thecodingmachine/gotenberg:4
</pre>
<blockquote>
@@ -104,8 +127,8 @@
</span><span class="w"> </span><span class="c"># your others services</span><span class="w">
</span><span class="w">
</span><span class="w"> </span>gotenberg<span class="p">:</span><span class="w">
</span><span class="w"> </span>image<span class="p">:</span><span class="w"> </span>thecodingmachine/gotenberg<span class="p">:</span><span class="m">3</span><span class="w">
</span><span class="w"></span></pre>
</span><span class="w"> </span>image<span class="p">:</span><span class="w"> </span>thecodingmachine/gotenberg<span class="p">:</span><span class="m">4</span><span class="w">
</span></pre>
<blockquote>
<p>The API will be available under <code>gotenberg:3000</code> in your Docker Compose network.</p>
@@ -339,7 +362,10 @@ are on the same level as the <code>index.html</code> file.</p>
<blockquote>
<p>If you want to install fonts directly in the Gotenberg Docker image,
see to the <a href="#office.fonts">fonts section</a>.</p>
see to the <a href="#fonts">fonts section</a>.</p>
<p>For web fonts (Google fonts), there is a timeout of 500ms by default. You may update
this value thanks to the form field <code>webFontsTimeout</code>.</p>
</blockquote>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets.c_url" href="#html.assets.c_url">
@@ -365,11 +391,7 @@ see to the <a href="#office.fonts">fonts section</a>.</p>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewHTMLRequest</span><span class="p">(</span><span class="s">&#34;index.html&#34;</span><span class="p">)</span>
<span class="nx">req</span><span class="p">.</span><span class="nf">SetAssets</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span>
<span class="s">&#34;font.woff&#34;</span><span class="p">,</span>
<span class="s">&#34;img.gif&#34;</span><span class="p">,</span>
<span class="s">&#34;style.css&#34;</span><span class="p">,</span>
<span class="p">})</span>
<span class="nx">req</span><span class="p">.</span><span class="nf">SetAssets</span><span class="p">(</span><span class="s">&#34;font.woff&#34;</span><span class="p">,</span> <span class="s">&#34;img.gif&#34;</span><span class="p">,</span> <span class="s">&#34;style.css&#34;</span><span class="p">)</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span>
@@ -392,8 +414,8 @@ $assets = [
];
$request = new HTMLRequest($index);
$request-&gt;setAssets($assets);
$dirPath = &#34;/foo&#34;;
$filename = $client-&gt;store($request, $dirPath);
$dest = &#34;result.pdf&#34;;
$client-&gt;store($request, $dest);
</pre>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation" href="#html.paper_size_margins_orientation">
@@ -459,8 +481,74 @@ $request = new HTMLRequest($index);
$request-&gt;setPaperSize(Request::A4);
$request-&gt;setMargins(Request::NO_MARGINS);
$request-&gt;setLandscape(true);
$dirPath = &#34;/foo&#34;;
$filename = $client-&gt;store($request, $dirPath);
$dest = &#34;result.pdf&#34;;
$client-&gt;store($request, $dest);
</pre>
</div>
<div class="Page" id="url">
<h1 class="Heading"><a class="Anchor" aria-hidden="true" id="url" href="#url">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>URL</h1>
<p>Gotenberg provides the endpoint <code>/convert/url</code> for remote URL conversions.</p>
<p>It accepts <code>POST</code> requests with a <code>multipart/form-data</code> Content-Type.</p>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="url.basic" href="#url.basic">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>Basic</h2>
<p>This endpoint does not accept an <code>index.html</code> file nor assets files but a form field
named <code>remoteURL</code> instead. Otherwise, URL conversions work the same as HTML conversions.</p>
<blockquote>
<p><strong>Attention:</strong> when converting a website to PDF, you should remove all margins.
If not, some of the content of the page might be hidden.</p>
</blockquote>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="url.basic.c_url" href="#url.basic.c_url">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>cURL</h3>
<pre class="chroma">$ curl --request POST <span class="se">\
</span><span class="se"></span> --url http://localhost:3000/convert/url <span class="se">\
</span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">remoteURL</span><span class="o">=</span>https://google.com
--form <span class="nv">marginTop</span><span class="o">=</span><span class="m">0</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">marginBottom</span><span class="o">=</span><span class="m">0</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">marginLeft</span><span class="o">=</span><span class="m">0</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">marginRight</span><span class="o">=</span><span class="m">0</span> <span class="se">\
</span><span class="se"></span> -o result.pdf
</pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="url.basic.go" href="#url.basic.go">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>Go</h3>
<pre class="chroma"><span class="kn">import</span> <span class="s">&#34;github.com/thecodingmachine/gotenberg/pkg&#34;</span>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewURLRequest</span><span class="p">(</span><span class="s">&#34;https://google.com&#34;</span><span class="p">)</span>
<span class="nx">req</span><span class="p">.</span><span class="nf">SetMargins</span><span class="p">(</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">NoMargins</span><span class="p">)</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span>
</pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="url.basic.php" href="#url.basic.php">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3>
<pre class="chroma">use TheCodingMachine\Gotenberg\Client;
use TheCodingMachine\Gotenberg\URLRequest;
$client = new Client(&#39;http://localhost:3000&#39;, new \Http\Adapter\Guzzle6\Client());
$request = new URLRequest(&#39;https://google.com&#39;);
$request-&gt;setMargins(Request::NO_MARGINS);
$dest = &#34;result.pdf&#34;;
$client-&gt;store($request, $dest);
</pre>
</div>
@@ -516,7 +604,7 @@ in the file <code>index.html</code>. This function will convert a given markdown
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewMarkdownRequest</span><span class="p">(</span><span class="s">&#34;index.html&#34;</span><span class="p">,</span> <span class="p">[]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;file.md&#34;</span><span class="p">})</span>
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewMarkdownRequest</span><span class="p">(</span><span class="s">&#34;index.html&#34;</span><span class="p">,</span> <span class="s">&#34;file.md&#34;</span><span class="p">)</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span>
@@ -536,8 +624,8 @@ $markdowns = [
DocumentFactory::makeFromPath(&#39;file.md&#39;, &#39;file.md&#39;),
];
$request = new MarkdownRequest($index, $markdowns);
$dirPath = &#34;/foo&#34;;
$filename = $client-&gt;store($request, $dirPath);
$dest = &#34;result.pdf&#34;;
$client-&gt;store($request, $dest);
</pre>
</div>
@@ -559,6 +647,7 @@ $filename = $client-&gt;store($request, $dirPath);
<ul>
<li><code>.txt</code></li>
<li><code>.rtf</code></li>
<li><code>.fodt</code></li>
<li><code>.doc</code></li>
<li><code>.docx</code></li>
<li><code>.odt</code></li>
@@ -598,7 +687,7 @@ See the <a href="#scalability">scalability section</a> to find how to mitigate t
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewOfficeRequest</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;document.docx&#34;</span><span class="p">,</span> <span class="s">&#34;document2.docx&#34;</span><span class="p">})</span>
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewOfficeRequest</span><span class="p">(</span><span class="s">&#34;document.docx&#34;</span><span class="p">,</span> <span class="s">&#34;document2.docx&#34;</span><span class="p">)</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span>
@@ -618,24 +707,19 @@ $files = [
DocumentFactory::makeFromPath(&#39;document2.docx&#39;, &#39;document2.docx&#39;),
];
$request = new OfficeRequest($files);
$dirPath = &#34;/foo&#34;;
$filename = $client-&gt;store($request, $dirPath);
$dest = &#34;result.pdf&#34;;
$client-&gt;store($request, $dest);
</pre>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="office.paper_size_and_orientation" href="#office.paper_size_and_orientation">
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="office.orientation" href="#office.orientation">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>Paper size and orientation</h2>
</a>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>
<p>By default, it will be rendered with <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">
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.orientation.c_url" href="#office.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>
@@ -643,13 +727,11 @@ Also, you have to set both <code>paperWidth</code> and <code>paperHeight</code>.
</span><span class="se"></span> --url http://localhost:3000/convert/office <span class="se">\
</span><span class="se"></span> --header <span class="s1">&#39;Content-Type: multipart/form-data&#39;</span> <span class="se">\
</span><span class="se"></span> --form <span class="nv">files</span><span class="o">=</span>@document.docx <span class="se">\
</span><span class="se"></span> --form <span class="nv">paperWidth</span><span class="o">=</span><span class="m">8</span>.27 <span class="se">\
</span><span class="se"></span> --form <span class="nv">paperHeight</span><span class="o">=</span><span class="m">11</span>.27 <span class="se">\
</span><span class="se"></span> --form <span class="nv">landscape</span><span class="o">=</span><span class="nb">true</span> <span class="se">\
</span><span class="se"></span> -o result.pdf
</pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.paper_size_and_orientation.go" href="#office.paper_size_and_orientation.go">
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.orientation.go" href="#office.orientation.go">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>Go</h3>
@@ -657,15 +739,14 @@ Also, you have to set both <code>paperWidth</code> and <code>paperHeight</code>.
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewOfficeRequest</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;document.docx&#34;</span><span class="p">})</span>
<span class="nx">req</span><span class="p">.</span><span class="nf">SetPaperSize</span><span class="p">(</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">A4</span><span class="p">)</span>
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewOfficeRequest</span><span class="p">(</span><span class="s">&#34;document.docx&#34;</span><span class="p">)</span>
<span class="nx">req</span><span class="p">.</span><span class="nf">SetLandscape</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span>
</pre>
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.paper_size_and_orientation.php" href="#office.paper_size_and_orientation.php">
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.orientation.php" href="#office.orientation.php">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>PHP</h3>
@@ -678,25 +759,11 @@ $files = [
DocumentFactory::makeFromPath(&#39;document.docx&#39;, &#39;document.docx&#39;),
];
$request = new OfficeRequest($files);
$request-&gt;setPaperSize(Request::A4);
$request-&gt;setLandscape(true);
$dirPath = &#34;/foo&#34;;
$filename = $client-&gt;store($request, $dirPath);
$dest = &#34;result.pdf&#34;;
$client-&gt;store($request, $dest);
</pre>
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="office.fonts" href="#office.fonts">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>Fonts</h2>
<p>By default, only <code>ttf-mscorefonts</code> fonts are installed.</p>
<p>If you wish to use more fonts, you will have to create your own image:</p>
<pre class="chroma"><span class="k">FROM</span><span class="s"> thecodingmachine/gotenberg:3</span><span class="err">
</span><span class="err">
</span><span class="err"></span><span class="k">RUN</span> apt-get -y install yourfonts<span class="err">
</span><span class="err"></span></pre>
</div>
<div class="Page" id="merge">
@@ -734,7 +801,7 @@ will merge them and return the resulting PDF file.</p>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&amp;</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">Client</span><span class="p">{</span><span class="nx">Hostname</span><span class="p">:</span> <span class="s">&#34;http://localhost:3000&#34;</span><span class="p">}</span>
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewMergeRequest</span><span class="p">([]</span><span class="kt">string</span><span class="p">{</span><span class="s">&#34;file.pdf&#34;</span><span class="p">,</span> <span class="s">&#34;file2.pdf&#34;</span><span class="p">})</span>
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewMergeRequest</span><span class="p">(</span><span class="s">&#34;file.pdf&#34;</span><span class="p">,</span> <span class="s">&#34;file2.pdf&#34;</span><span class="p">)</span>
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">&#34;result.pdf&#34;</span>
<span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
<span class="p">}</span>
@@ -754,8 +821,8 @@ $files = [
DocumentFactory::makeFromPath(&#39;file2.pdf&#39;, &#39;file2.pdf&#39;),
];
$request = new MergeRequest($files);
$dirPath = &#34;/foo&#34;;
$filename = $client-&gt;store($request, $dirPath);
$dest = &#34;result.pdf&#34;;
$client-&gt;store($request, $dest);
</pre>
</div>
@@ -833,8 +900,8 @@ $resp = $client-&gt;post($request);
</span><span class="w"> </span><span class="c"># your others services</span><span class="w">
</span><span class="w">
</span><span class="w"> </span>gotenberg<span class="p">:</span><span class="w">
</span><span class="w"> </span>image<span class="p">:</span><span class="w"> </span>thecodingmachine/gotenberg<span class="p">:</span><span class="m">3</span><span class="w">
</span><span class="w"></span></pre>
</span><span class="w"> </span>image<span class="p">:</span><span class="w"> </span>thecodingmachine/gotenberg<span class="p">:</span><span class="m">4</span><span class="w">
</span></pre>
<p>You may now launch your services using:</p>
@@ -846,6 +913,37 @@ redirect a request to a Gotenberg container according to the round-robin strateg
</div>
<div class="Page" id="liveness">
<h1 class="Heading"><a class="Anchor" aria-hidden="true" id="liveness" href="#liveness">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>Liveness</h1>
<p>Gotenberg provides the endpoint <code>/ping</code> for checking the API availability with
a simple <code>GET</code> request.</p>
<p>This feature is especially useful for liveness/readiness probes in Kubernetes:</p>
<ul>
<li><a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes">Pod lifecycle</a></li>
<li><a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/">Configure Liveness and Readiness Probes</a></li>
</ul>
</div>
<div class="Page" id="fonts">
<h1 class="Heading"><a class="Anchor" aria-hidden="true" id="fonts" href="#fonts">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
</a>Fonts</h1>
<p>By default, a handful of fonts are installed. Asian characters are also supported out of the box.</p>
<p>If you wish to use more fonts, you will have to create your own image:</p>
<pre class="chroma"><span class="k">FROM</span><span class="s"> thecodingmachine/gotenberg:4</span><span class="err">
</span><span class="err">
</span><span class="err"></span><span class="k">RUN</span> apt-get -y install yourfonts<span class="err">
</span></pre>
</div>
<div class="Page" id="links">
<h1 class="Heading"><a class="Anchor" aria-hidden="true" id="links" href="#links">
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 923 B

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -5,8 +5,19 @@
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{.Title}} &#183; {{.Subtitle}}</title>
<link rel="apple-touch-icon-precomposed" sizes="57x57" href="theme/gotenberg/img/apple-touch-icon-57x57.png" />
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="theme/gotenberg/img/apple-touch-icon-114x114.png" />
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="theme/gotenberg/img/apple-touch-icon-72x72.png" />
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="theme/gotenberg/img/apple-touch-icon-144x144.png" />
<link rel="apple-touch-icon-precomposed" sizes="60x60" href="theme/gotenberg/img/apple-touch-icon-60x60.png" />
<link rel="apple-touch-icon-precomposed" sizes="120x120" href="theme/gotenberg/img/apple-touch-icon-120x120.png" />
<link rel="apple-touch-icon-precomposed" sizes="76x76" href="theme/gotenberg/img/apple-touch-icon-76x76.png" />
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="theme/gotenberg/img/apple-touch-icon-152x152.png" />
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-196x196.png" sizes="196x196" />
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-16x16.png" sizes="16x16" />
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-16x16.png" sizes="16x16" />
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-128.png" sizes="128x128" />
<link rel="stylesheet" href="theme/gotenberg/css/index.css">
</head>
<body>

2
go.mod
View File

@@ -5,7 +5,7 @@ require (
github.com/google/go-cmp v0.2.0 // indirect
github.com/gorilla/websocket v1.4.0 // indirect
github.com/hhrutter/pdfcpu v0.1.19
github.com/labstack/echo v0.0.0-20181123063703-c7eb8da9ec73
github.com/labstack/echo v0.0.0-20190126223945-739700bf4ef7
github.com/labstack/gommon v0.2.8
github.com/mafredri/cdp v0.20.0
github.com/microcosm-cc/bluemonday v1.0.1

2
go.sum
View File

@@ -14,6 +14,8 @@ github.com/hhrutter/pdfcpu v0.1.19 h1:J6GjNFDPjurQWallPW9gmz3CcNqBfvgB7Dad9T3e8H
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/go.mod h1:rS0D1UPvC8/3sXjhSwEq+K1olh7ipbDhjDWATN2KSgA=
github.com/labstack/echo v0.0.0-20190126223945-739700bf4ef7 h1:kFheQLunLP9dCBrmg3D7y9FD44tlk/nvZQ7JCNvvWEA=
github.com/labstack/echo v0.0.0-20190126223945-739700bf4ef7/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/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
github.com/labstack/gommon v0.2.7/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4=

View File

@@ -67,9 +67,11 @@ func setup() *echo.Echo {
return nil
}
})
e.GET("/ping", func(c echo.Context) error { return nil })
e.POST("/merge", merge)
g := e.Group("/convert")
g.POST("/html", convertHTML)
g.POST("/url", convertURL)
g.POST("/markdown", convertMarkdown)
g.POST("/office", convertOffice)
return e

View File

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

View File

@@ -47,5 +47,10 @@ func convertHTML(c echo.Context) error {
return hijackErr(err, r)
}
p.Landscape = landscape
chromeWebFontsTimeout, err := r.webFontsTimeout()
if err != nil {
return hijackErr(err, r)
}
p.WebFontsTimeout = chromeWebFontsTimeout
return print(c, p, r)
}

View File

@@ -46,5 +46,10 @@ func convertMarkdown(c echo.Context) error {
return hijackErr(err, r)
}
p.Landscape = landscape
chromeWebFontsTimeout, err := r.webFontsTimeout()
if err != nil {
return hijackErr(err, r)
}
p.WebFontsTimeout = chromeWebFontsTimeout
return print(c, p, r)
}

View File

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

View File

@@ -1,6 +1,7 @@
package api
import (
"errors"
"fmt"
"io"
"os"
@@ -12,14 +13,16 @@ import (
)
const (
webhookURL string = "webhookURL"
paperWidth string = "paperWidth"
paperHeight string = "paperHeight"
marginTop string = "marginTop"
marginBottom string = "marginBottom"
marginLeft string = "marginLeft"
marginRight string = "marginRight"
landscape string = "landscape"
remoteURL string = "remoteURL"
webhookURL string = "webhookURL"
paperWidth string = "paperWidth"
paperHeight string = "paperHeight"
marginTop string = "marginTop"
marginBottom string = "marginBottom"
marginLeft string = "marginLeft"
marginRight string = "marginRight"
landscape string = "landscape"
webFontsTimeout string = "webFontsTimeout"
)
// resource facilitates storing and accessing
@@ -31,6 +34,7 @@ type resource struct {
func newResource(c echo.Context) (*resource, error) {
v := make(map[string]string)
v[remoteURL] = c.FormValue(remoteURL)
v[webhookURL] = c.FormValue(webhookURL)
v[paperWidth] = c.FormValue(paperWidth)
v[paperHeight] = c.FormValue(paperHeight)
@@ -39,6 +43,7 @@ func newResource(c echo.Context) (*resource, error) {
v[marginLeft] = c.FormValue(marginLeft)
v[marginRight] = c.FormValue(marginRight)
v[landscape] = c.FormValue(landscape)
v[webFontsTimeout] = c.FormValue(webFontsTimeout)
dirPath, err := rand.Get()
if err != nil {
return nil, err
@@ -180,5 +185,24 @@ func (r *resource) landscape() (bool, error) {
return landscape, nil
}
func (r *resource) remoteURL() (string, error) {
if r.values[remoteURL] == "" {
return "", errors.New("no remote URL")
}
return r.values[remoteURL], nil
}
func (r *resource) webFontsTimeout() (int64, error) {
webFontsTimeoutStr := r.values[webFontsTimeout]
if webFontsTimeoutStr == "" {
return 500, nil
}
timeout, err := strconv.ParseInt(webFontsTimeoutStr, 10, 64)
if err != nil {
return 500, fmt.Errorf("web fonts timeout: %v", err)
}
return timeout, nil
}
func (r *resource) webhookURL() string { return r.values[webhookURL] }
func (r *resource) removeAll() error { return os.RemoveAll(r.dirPath) }

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

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

View File

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

View File

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

View File

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

View File

@@ -7,7 +7,6 @@ import (
"os"
"os/exec"
"path/filepath"
"strconv"
"sync"
"github.com/thecodingmachine/gotenberg/internal/pkg/rand"
@@ -17,11 +16,9 @@ var mu sync.Mutex
// Office facilitates Office documents to PDF conversion.
type Office struct {
Context context.Context
FilePaths []string
PaperWidth float64
PaperHeight float64
Landscape bool
Context context.Context
FilePaths []string
Landscape bool
}
// Print converts Office documents to PDF.
@@ -36,15 +33,9 @@ func (o *Office) Print(destination string) error {
return err
}
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")
@@ -70,18 +61,6 @@ func (o *Office) Print(destination string) error {
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.
var (
_ = Printer(new(Office))

View File

@@ -19,11 +19,11 @@ func main() {
req, _ := gotenberg.NewHTMLRequest("index.html")
req.SetHeader("header.html")
req.SetFooter("footer.html")
req.SetAssets([]string{
req.SetAssets(
"font.woff",
"img.gif",
"style.css",
})
)
req.SetPaperSize(gotenberg.A4)
req.SetMargins(gotenberg.NormalMargins)
req.SetLandscape(false)

View File

@@ -13,14 +13,16 @@ import (
)
const (
webhookURL string = "webhookURL"
paperWidth string = "paperWidth"
paperHeight string = "paperHeight"
marginTop string = "marginTop"
marginBottom string = "marginBottom"
marginLeft string = "marginLeft"
marginRight string = "marginRight"
landscape string = "landscape"
remoteURL string = "remoteURL"
webhookURL string = "webhookURL"
paperWidth string = "paperWidth"
paperHeight string = "paperHeight"
marginTop string = "marginTop"
marginBottom string = "marginBottom"
marginLeft string = "marginLeft"
marginRight string = "marginRight"
landscape string = "landscape"
webFontsTimeout string = "webFontsTimeout"
)
var (
@@ -71,17 +73,16 @@ type Request interface {
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)
SetWebFontsTimeout(timeout int64)
}
// UnoconvRequest is a type for sending
// conversion requests which will be
// handle by unoconv.
type UnoconvRequest interface {
SetPaperSize(size [2]float64)
SetLandscape(landscape bool)
}

View File

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

View File

@@ -48,7 +48,7 @@ func (html *HTMLRequest) SetFooter(fpath string) error {
}
// SetAssets sets assets form files.
func (html *HTMLRequest) SetAssets(fpaths []string) error {
func (html *HTMLRequest) SetAssets(fpaths ...string) error {
for _, fpath := range fpaths {
if !fileExists(fpath) {
return fmt.Errorf("%s: file does not exist", fpath)
@@ -78,6 +78,11 @@ func (html *HTMLRequest) SetLandscape(isLandscape bool) {
html.values[landscape] = strconv.FormatBool(isLandscape)
}
// SetWebFontsTimeout sets webFontsTimeout form field.
func (html *HTMLRequest) SetWebFontsTimeout(timeout int64) {
html.values[webFontsTimeout] = strconv.FormatInt(timeout, 10)
}
func (html *HTMLRequest) getPostURL() string {
return "/convert/html"
}

View File

@@ -19,11 +19,11 @@ func TestHTML(t *testing.T) {
require.Nil(t, err)
err = req.SetFooter(test.HTMLTestFilePath(t, "footer.html"))
require.Nil(t, err)
err = req.SetAssets([]string{
err = req.SetAssets(
test.HTMLTestFilePath(t, "font.woff"),
test.HTMLTestFilePath(t, "img.gif"),
test.HTMLTestFilePath(t, "style.css"),
})
)
require.Nil(t, err)
req.SetPaperSize(A4)
req.SetMargins(NormalMargins)

View File

@@ -18,7 +18,7 @@ type MarkdownRequest struct {
}
// NewMarkdownRequest create MarkdownRequest.
func NewMarkdownRequest(indexFilePath string, markdownFilePaths []string) (*MarkdownRequest, error) {
func NewMarkdownRequest(indexFilePath string, markdownFilePaths ...string) (*MarkdownRequest, error) {
if !fileExists(indexFilePath) {
return nil, fmt.Errorf("%s: index file does not exist", indexFilePath)
}
@@ -58,7 +58,7 @@ func (markdown *MarkdownRequest) SetFooter(fpath string) error {
}
// SetAssets sets assets form files.
func (markdown *MarkdownRequest) SetAssets(fpaths []string) error {
func (markdown *MarkdownRequest) SetAssets(fpaths ...string) error {
for _, fpath := range fpaths {
if !fileExists(fpath) {
return fmt.Errorf("%s: file does not exist", fpath)
@@ -88,6 +88,11 @@ func (markdown *MarkdownRequest) SetLandscape(isLandscape bool) {
markdown.values[landscape] = strconv.FormatBool(isLandscape)
}
// SetWebFontsTimeout sets webFontsTimeout form field.
func (markdown *MarkdownRequest) SetWebFontsTimeout(timeout int64) {
markdown.values[webFontsTimeout] = strconv.FormatInt(timeout, 10)
}
func (markdown *MarkdownRequest) getPostURL() string {
return "/convert/markdown"
}

View File

@@ -15,22 +15,20 @@ func TestMarkdown(t *testing.T) {
c := &Client{Hostname: "http://localhost:3000"}
req, err := NewMarkdownRequest(
test.MarkdownTestFilePath(t, "index.html"),
[]string{
test.MarkdownTestFilePath(t, "paragraph1.md"),
test.MarkdownTestFilePath(t, "paragraph2.md"),
test.MarkdownTestFilePath(t, "paragraph3.md"),
},
test.MarkdownTestFilePath(t, "paragraph1.md"),
test.MarkdownTestFilePath(t, "paragraph2.md"),
test.MarkdownTestFilePath(t, "paragraph3.md"),
)
require.Nil(t, err)
err = req.SetHeader(test.MarkdownTestFilePath(t, "header.html"))
require.Nil(t, err)
err = req.SetFooter(test.MarkdownTestFilePath(t, "footer.html"))
require.Nil(t, err)
err = req.SetAssets([]string{
err = req.SetAssets(
test.MarkdownTestFilePath(t, "font.woff"),
test.MarkdownTestFilePath(t, "img.gif"),
test.MarkdownTestFilePath(t, "style.css"),
})
)
require.Nil(t, err)
req.SetPaperSize(A4)
req.SetMargins(NormalMargins)

View File

@@ -13,7 +13,7 @@ type MergeRequest struct {
}
// NewMergeRequest create MergeRequest.
func NewMergeRequest(fpaths []string) (*MergeRequest, error) {
func NewMergeRequest(fpaths ...string) (*MergeRequest, error) {
for _, fpath := range fpaths {
if !fileExists(fpath) {
return nil, fmt.Errorf("%s: file does not exist", fpath)

View File

@@ -13,10 +13,10 @@ import (
func TestMerge(t *testing.T) {
c := &Client{Hostname: "http://localhost:3000"}
req, err := NewMergeRequest([]string{
req, err := NewMergeRequest(
test.PDFTestFilePath(t, "gotenberg.pdf"),
test.PDFTestFilePath(t, "gotenberg.pdf"),
})
)
require.Nil(t, err)
dirPath, err := rand.Get()
require.Nil(t, err)

View File

@@ -14,7 +14,7 @@ type OfficeRequest struct {
}
// NewOfficeRequest create OfficeRequest.
func NewOfficeRequest(fpaths []string) (*OfficeRequest, error) {
func NewOfficeRequest(fpaths ...string) (*OfficeRequest, error) {
for _, fpath := range fpaths {
if !fileExists(fpath) {
return nil, fmt.Errorf("%s: file does not exist", fpath)
@@ -28,12 +28,6 @@ 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)

View File

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

90
pkg/url.go Normal file
View File

@@ -0,0 +1,90 @@
package gotenberg
import (
"fmt"
"strconv"
)
// URLRequest facilitates remote URL conversion
// with the Gotenberg API.
type URLRequest struct {
headerFilePath string
footerFilePath string
values map[string]string
}
// NewURLRequest create URLRequest.
func NewURLRequest(URL string) *URLRequest {
req := &URLRequest{values: make(map[string]string)}
req.values[remoteURL] = URL
return req
}
// SetWebhookURL sets webhookURL form field.
func (url *URLRequest) SetWebhookURL(webhookURL string) {
url.values[webhookURL] = webhookURL
}
// SetHeader sets header form file.
func (url *URLRequest) SetHeader(fpath string) error {
if !fileExists(fpath) {
return fmt.Errorf("%s: header file does not exist", fpath)
}
url.headerFilePath = fpath
return nil
}
// SetFooter sets footer form file.
func (url *URLRequest) SetFooter(fpath string) error {
if !fileExists(fpath) {
return fmt.Errorf("%s: footer file does not exist", fpath)
}
url.footerFilePath = fpath
return nil
}
// SetPaperSize sets paperWidth and paperHeight form fields.
func (url *URLRequest) SetPaperSize(size [2]float64) {
url.values[paperWidth] = fmt.Sprintf("%f", size[0])
url.values[paperHeight] = fmt.Sprintf("%f", size[1])
}
// SetMargins sets marginTop, marginBottom,
// marginLeft and marginRight form fields.
func (url *URLRequest) SetMargins(margins [4]float64) {
url.values[marginTop] = fmt.Sprintf("%f", margins[0])
url.values[marginBottom] = fmt.Sprintf("%f", margins[1])
url.values[marginLeft] = fmt.Sprintf("%f", margins[2])
url.values[marginRight] = fmt.Sprintf("%f", margins[3])
}
// SetLandscape sets landscape form field.
func (url *URLRequest) SetLandscape(isLandscape bool) {
url.values[landscape] = strconv.FormatBool(isLandscape)
}
// SetWebFontsTimeout sets webFontsTimeout form field.
func (url *URLRequest) SetWebFontsTimeout(timeout int64) {
url.values[webFontsTimeout] = strconv.FormatInt(timeout, 10)
}
func (url *URLRequest) getPostURL() string {
return "/convert/url"
}
func (url *URLRequest) getFormValues() map[string]string {
return url.values
}
func (url *URLRequest) getFormFiles() map[string]string {
files := make(map[string]string)
files["header.html"] = url.headerFilePath
files["footer.html"] = url.footerFilePath
return files
}
// Compile-time checks to ensure type implements desired interfaces.
var (
_ = Request(new(URLRequest))
_ = ChromeRequest(new(URLRequest))
)

41
pkg/url_test.go Normal file
View File

@@ -0,0 +1,41 @@
package gotenberg
import (
"fmt"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/thecodingmachine/gotenberg/internal/pkg/rand"
"github.com/thecodingmachine/gotenberg/test"
)
func TestURL(t *testing.T) {
c := &Client{Hostname: "http://localhost:3000"}
req := NewURLRequest("http://google.com")
err := req.SetHeader(test.URLTestFilePath(t, "header.html"))
require.Nil(t, err)
err = req.SetFooter(test.URLTestFilePath(t, "footer.html"))
require.Nil(t, err)
require.Nil(t, err)
req.SetPaperSize(A4)
req.SetMargins(NormalMargins)
req.SetLandscape(false)
dirPath, err := rand.Get()
require.Nil(t, err)
dest := fmt.Sprintf("%s/foo.pdf", dirPath)
err = c.Store(req, dest)
assert.Nil(t, err)
assert.FileExists(t, dest)
err = os.RemoveAll(dirPath)
assert.Nil(t, err)
}
func TestConcurrentURL(t *testing.T) {
for i := 0; i < 10; i++ {
go func() {
TestURL(t)
}()
}
}

View File

@@ -21,11 +21,13 @@ docker build -t thecodingmachine/gotenberg:base -f build/base/Dockerfile .
docker build \
--build-arg GOLANG_VERSION=${GOLANG_VERSION} \
--build-arg VERSION=${VERSION} \
-t thecodingmachine/gotenberg:latest \
-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:latest"
docker push "thecodingmachine/gotenberg:${SEMVER[0]}"
docker push "thecodingmachine/gotenberg:${SEMVER[0]}.${SEMVER[1]}"
docker push "thecodingmachine/gotenberg:${SEMVER[0]}.${SEMVER[1]}.${SEMVER[2]}"

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

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

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

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

View File

@@ -23,6 +23,13 @@ func HTMLTestMultipartForm(t *testing.T) (*bytes.Buffer, string) {
return multipartForm(t, "html")
}
// URLTestMultipartForm returns the body
// for a multipate/form-data request with all
// files under "url" folder.
func URLTestMultipartForm(t *testing.T) (*bytes.Buffer, string) {
return multipartForm(t, "url")
}
// MarkdownTestMultipartForm returns the body
// for a multipate/form-data request with all
// files under "markdown" folder.
@@ -65,6 +72,10 @@ func multipartForm(t *testing.T, kind string) (*bytes.Buffer, string) {
_, err = io.Copy(part, file)
require.Nil(t, err)
}
if kind == "url" {
err := writer.WriteField("remoteURL", "http://google.com")
require.Nil(t, err)
}
return body, writer.FormDataContentType()
}
@@ -74,6 +85,12 @@ func HTMLTestDirPath(t *testing.T) string {
return copyDir(t, "html")
}
// URLTestDirPath creates a copy
// of "url" folder in test/testdata.
func URLTestDirPath(t *testing.T) string {
return copyDir(t, "url")
}
// MarkdownTestDirPath creates a copy
// of "markdown" folder in test/testdata.
func MarkdownTestDirPath(t *testing.T) string {
@@ -127,6 +144,12 @@ func HTMLTestFilePath(t *testing.T, filename string) string {
return abs(t, "html", filename)
}
// URLTestFilePath returns the absolute file path
// of a file in "url" folder in test/testdata.
func URLTestFilePath(t *testing.T, filename string) string {
return abs(t, "url", filename)
}
// MarkdownTestFilePath returns the absolute file path
// of a file in "markdown" folder in test/testdata.
func MarkdownTestFilePath(t *testing.T, filename string) string {