Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
571c3e04c4 | ||
|
|
f9fb97a572 | ||
|
|
e6484bb2d5 | ||
|
|
19f51fdc1f | ||
|
|
25f7ba3ee6 | ||
|
|
a3cd1ff4e1 | ||
|
|
f62c717f79 | ||
|
|
3ed99133d4 | ||
|
|
ab25cc331d | ||
|
|
2648992a9b | ||
|
|
7bcc3d081e | ||
|
|
affd1c45ca | ||
|
|
8c7458812d | ||
|
|
053908c772 | ||
|
|
d623736f9f | ||
|
|
a3e416ff68 | ||
|
|
8bf207b9f7 | ||
|
|
e1520d5e7e | ||
|
|
4f89c9f7c6 | ||
|
|
d34fb92211 | ||
|
|
3f7b006d16 | ||
|
|
a15cf33691 | ||
|
|
4c1699df6c | ||
|
|
404535c512 | ||
|
|
2cedcecc38 | ||
|
|
ba7b02d8d4 | ||
|
|
6aa3c16646 | ||
|
|
5a03e17e00 | ||
|
|
417d145b43 | ||
|
|
e5636a2afa | ||
|
|
5291d2d129 | ||
|
|
c6f6a87499 | ||
|
|
1ef21c6ed6 | ||
|
|
6ee1932cbf | ||
|
|
83cf43a314 | ||
|
|
52c14a79a1 | ||
|
|
152db0551d | ||
|
|
3a2467ccfe | ||
|
|
5a28f3597c | ||
|
|
9ce179f91b | ||
|
|
7aeb072cc3 | ||
|
|
8a652761a3 | ||
|
|
be667575d5 | ||
|
|
59ca8a44a0 | ||
|
|
c9f0d3bfd8 |
7
.github/CONTRIBUTING.md
vendored
@@ -1,6 +1,6 @@
|
|||||||
# Contributing
|
# Contributing
|
||||||
|
|
||||||
Hi! Thank your for considering contributing to Gotenberg. You'll
|
Hi! Thank you for considering contributing to Gotenberg. You'll
|
||||||
find below useful information about how to contribute to the Gotenberg project.
|
find below useful information about how to contribute to the Gotenberg project.
|
||||||
|
|
||||||
## Contributing code
|
## Contributing code
|
||||||
@@ -8,8 +8,9 @@ find below useful information about how to contribute to the Gotenberg project.
|
|||||||
### Install from sources
|
### Install from sources
|
||||||
|
|
||||||
1. Install and run the latest version of Docker
|
1. Install and run the latest version of Docker
|
||||||
2. Fork this repository
|
2. Verify your Go version (>= 1.11)
|
||||||
3. Clone it to your local Go environment (requires *Go* >= 1.11)
|
3. Fork this repository
|
||||||
|
4. Clone it outside of your `GOPATH` (we're using Go modules)
|
||||||
|
|
||||||
### Working with git
|
### Working with git
|
||||||
|
|
||||||
|
|||||||
@@ -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: make publish VERSION=$TRAVIS_TAG DOCKER_USER=$DOCKER_USER DOCKER_PASSWORD=$DOCKER_PASS
|
||||||
2
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2018 TheCodingMachine
|
Copyright (c) 2019 TheCodingMachine
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
13
Makefile
@@ -1,9 +1,12 @@
|
|||||||
VERSION=snapshot
|
|
||||||
GOLANG_VERSION=1.11.2
|
GOLANG_VERSION=1.11.2
|
||||||
|
VERSION=snapshot
|
||||||
|
DOCKER_USER=
|
||||||
|
DOCKER_PASSWORD=
|
||||||
|
|
||||||
# generate documentation.
|
# generate documentation.
|
||||||
doc:
|
doc:
|
||||||
static-docs --in build/docs --out docs --theme gotenberg --title Gotenberg --subtitle "A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF."
|
docker build --build-arg GOLANG_VERSION=$(GOLANG_VERSION) -t thecodingmachine/gotenberg:docs -f build/docs/Dockerfile .
|
||||||
|
docker run --rm -it -v "$(PWD):/docs" thecodingmachine/gotenberg:docs
|
||||||
|
|
||||||
# gofmt and goimports all go files.
|
# gofmt and goimports all go files.
|
||||||
fmt:
|
fmt:
|
||||||
@@ -27,4 +30,8 @@ image:
|
|||||||
|
|
||||||
# start the API using previously built Docker image.
|
# start the API using previously built Docker image.
|
||||||
gotenberg:
|
gotenberg:
|
||||||
docker run -it --rm -p "3000:3000" thecodingmachine/gotenberg:$(VERSION)
|
docker run -it --rm -p "3000:3000" thecodingmachine/gotenberg:$(VERSION)
|
||||||
|
|
||||||
|
# publish Gotenberg images according to version.
|
||||||
|
publish:
|
||||||
|
./scripts/publish.sh $(GOLANG_VERSION) $(VERSION) $(DOCKER_USER) $(DOCKER_PASSWORD)
|
||||||
11
README.md
@@ -1,8 +1,9 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://user-images.githubusercontent.com/8983173/49701110-4c8b9280-fbe8-11e8-895c-a4b9c7d2515b.png" alt="Gotenberg logo" width="250" height="250" />
|
<img src="https://user-images.githubusercontent.com/8983173/50009948-84b01e00-ffb8-11e8-850b-fc240382c626.png" alt="Gotenberg logo" width="250" height="250" />
|
||||||
</p>
|
</p>
|
||||||
<h3 align="center">Gotenberg</h3>
|
<h3 align="center">Gotenberg</h3>
|
||||||
<p align="center">A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.</p>
|
<p align="center">A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.</p>
|
||||||
|
<p align="center"><a href="https://thecodingmachine.github.io/gotenberg">Documentation</a> · <a href="/.github/CONTRIBUTING.md">Contributing</a></p>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -11,7 +12,7 @@ At TheCodingMachine, we build a lot of web applications (intranets, extranets an
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
* HTML and Markdown conversions using Google Chrome headless
|
* HTML and Markdown conversions using Google Chrome headless
|
||||||
* Office conversions (.docx, .doc, .odt, .pptx, .ppt, .odp and so on) using [unoconv](https://github.com/dagwieers/unoconv)
|
* Office conversions (.txt, .rtf, .docx, .doc, .odt, .pptx, .ppt, .odp and so on) using [unoconv](https://github.com/dagwieers/unoconv)
|
||||||
* Performance :zap:: Google Chrome and Libreoffice (unoconv) started once in the background thanks to PM2
|
* Performance :zap:: Google Chrome and Libreoffice (unoconv) started once in the background thanks to PM2
|
||||||
* Failure prevention :broken_heart:: PM2 automatically restarts previous processes if they fail
|
* Failure prevention :broken_heart:: PM2 automatically restarts previous processes if they fail
|
||||||
* Assets :package:: send your header, footer, images, fonts, stylesheets and so on for converting your HTML and Markdown to beaufitul PDFs!
|
* Assets :package:: send your header, footer, images, fonts, stylesheets and so on for converting your HTML and Markdown to beaufitul PDFs!
|
||||||
@@ -22,7 +23,7 @@ At TheCodingMachine, we build a lot of web applications (intranets, extranets an
|
|||||||
Open a terminal and run the following command:
|
Open a terminal and run the following command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ docker run --rm -p 3000:3000 thecodingmachine/gotenberg:3
|
$ docker run --rm -p 3000:3000 thecodingmachine/gotenberg:4
|
||||||
```
|
```
|
||||||
|
|
||||||
The API is now available on your host at `http://localhost:3000`.
|
The API is now available on your host at `http://localhost:3000`.
|
||||||
@@ -32,9 +33,9 @@ to learn how to interact with it!
|
|||||||
|
|
||||||
## Badges
|
## Badges
|
||||||
|
|
||||||
[](https://microbadger.com/images/thecodingmachine/gotenberg:3)
|
[](https://microbadger.com/images/thecodingmachine/gotenberg:4)
|
||||||
[](https://travis-ci.org/thecodingmachine/gotenberg)
|
[](https://travis-ci.org/thecodingmachine/gotenberg)
|
||||||
[](https://godoc.org/github.com/thecodingmachine/gotenberg?status.svg)
|
[](https://godoc.org/github.com/thecodingmachine/gotenberg)
|
||||||
[](https://goreportcard.com/report/thecodingmachine/gotenberg)
|
[](https://goreportcard.com/report/thecodingmachine/gotenberg)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
FROM debian:stretch-slim
|
FROM thecodingmachine/gotenberg:3.2.0 AS hack
|
||||||
|
FROM debian:9.5-slim
|
||||||
LABEL authors="Julien Neuhart <j.neuhart@thecodingmachine.com>"
|
|
||||||
|
|
||||||
# |--------------------------------------------------------------------------
|
# |--------------------------------------------------------------------------
|
||||||
# | Common libraries
|
# | Common libraries
|
||||||
@@ -11,7 +10,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 ttf-mscorefonts-installer
|
||||||
|
|
||||||
# |--------------------------------------------------------------------------
|
# |--------------------------------------------------------------------------
|
||||||
# | PM2
|
# | PM2
|
||||||
@@ -21,7 +20,19 @@ RUN echo "deb http://httpredir.debian.org/debian/ stretch main contrib non-free"
|
|||||||
# | recovering. In our case: Chrome (headless) and Office (headless).
|
# | recovering. In our case: Chrome (headless) and Office (headless).
|
||||||
# |
|
# |
|
||||||
|
|
||||||
RUN curl -sL https://raw.githubusercontent.com/Unitech/pm2/master/packager/setup.deb.sh | bash -
|
# Yep, this is dirty. The following script does not work anymore (see https://github.com/Unitech/pm2/issues/4127).
|
||||||
|
#RUN curl -sL https://raw.githubusercontent.com/Unitech/pm2/master/packager/setup.deb.sh | bash -
|
||||||
|
|
||||||
|
# Installing PM2 with Node.js and npm breaks something which prevents Google Chrome to work as expected.
|
||||||
|
# So we just copy all PM2 related files from a previous version of Gotenberg.
|
||||||
|
|
||||||
|
RUN curl -sL https://deb.nodesource.com/setup_9.x | bash - &&\
|
||||||
|
apt-get install -y nodejs
|
||||||
|
|
||||||
|
COPY --from=hack /usr/bin/pm2 /usr/bin/pm2
|
||||||
|
COPY --from=hack /usr/share/pm2 /usr/share/pm2
|
||||||
|
COPY --from=hack /etc/default/pm2 /etc/default/pm2
|
||||||
|
COPY --from=hack /etc/systemd/system/pm2.service /etc/systemd/system/pm2.service
|
||||||
|
|
||||||
# |--------------------------------------------------------------------------
|
# |--------------------------------------------------------------------------
|
||||||
# | Chrome
|
# | Chrome
|
||||||
@@ -39,7 +50,55 @@ RUN wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add
|
|||||||
# | Unoconv
|
# | Unoconv
|
||||||
# |--------------------------------------------------------------------------
|
# |--------------------------------------------------------------------------
|
||||||
# |
|
# |
|
||||||
# | Installs MS fonts and unoconv for Office documents conversions.
|
# | Installs unoconv and LibreOffice for Office documents conversions.
|
||||||
# |
|
# |
|
||||||
|
|
||||||
RUN apt-get -y install ttf-mscorefonts-installer unoconv
|
RUN pip3 install unoconv &&\
|
||||||
|
# https://github.com/nextcloud/docker/issues/380
|
||||||
|
mkdir -p /usr/share/man/man1mkdir -p /usr/share/man/man1 &&\
|
||||||
|
apt-get -y install libreoffice
|
||||||
|
|
||||||
|
# |--------------------------------------------------------------------------
|
||||||
|
# | PDFtk
|
||||||
|
# |--------------------------------------------------------------------------
|
||||||
|
# |
|
||||||
|
# | Installs PDFtk as an alternative to pdfcpu for merging PDFs.
|
||||||
|
# | https://github.com/thecodingmachine/gotenberg/issues/29
|
||||||
|
# |
|
||||||
|
|
||||||
|
RUN apt-get -y install pdftk
|
||||||
|
|
||||||
|
# |--------------------------------------------------------------------------
|
||||||
|
# | 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
@@ -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>
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
---
|
|
||||||
title: Office
|
|
||||||
---
|
|
||||||
|
|
||||||
Gotenberg provides the endpoint `/convert/office` for Office documents conversions.
|
|
||||||
|
|
||||||
It accepts `POST` requests with a `multipart/form-data` Content-Type.
|
|
||||||
|
|
||||||
## Basic
|
|
||||||
|
|
||||||
You may send one or more Office documents. Following file extensions are accepted:
|
|
||||||
|
|
||||||
* `.doc`
|
|
||||||
* `.docx`
|
|
||||||
* `.odt`
|
|
||||||
* `.xls`
|
|
||||||
* `.xlsx`
|
|
||||||
* `.ods`
|
|
||||||
* `.ppt`
|
|
||||||
* `.pptx`
|
|
||||||
* `.odp`
|
|
||||||
|
|
||||||
All files will be merged into a single resulting PDF.
|
|
||||||
|
|
||||||
> **Attention:** currently, `unoconv` cannot perform concurrent conversions.
|
|
||||||
> 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.
|
|
||||||
|
|
||||||
### Guzzle
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ curl --request POST \
|
|
||||||
--url http://localhost:3000/convert/office \
|
|
||||||
--header 'Content-Type: multipart/form-data' \
|
|
||||||
--form files=@document.docx
|
|
||||||
--form files=@document2.docx
|
|
||||||
> result.pdf
|
|
||||||
```
|
|
||||||
|
|
||||||
### Go
|
|
||||||
|
|
||||||
```golang
|
|
||||||
import "github.com/thecodingmachine/gotenberg/pkg"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
|
|
||||||
req := &gotenberg.OfficeRequest{
|
|
||||||
FilePaths: []string{
|
|
||||||
"document.docx",
|
|
||||||
"document2.docx",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
dest := "result.pdf"
|
|
||||||
c.Store(req, dest)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### PHP
|
|
||||||
|
|
||||||
TODO
|
|
||||||
|
|
||||||
## 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
|
|
||||||
```
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
---
|
|
||||||
title: Webhook
|
|
||||||
---
|
|
||||||
|
|
||||||
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
|
|
||||||
to given URL.
|
|
||||||
|
|
||||||
By doing so, your requests to the API will be done before the conversions are actually done!
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
### Guzzle
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ curl --request POST \
|
|
||||||
--url http://localhost:3000/convert/html \
|
|
||||||
--header 'Content-Type: multipart/form-data' \
|
|
||||||
--form files=@index.html
|
|
||||||
--form webhookURL='http://myapp.com/webhook/'
|
|
||||||
> result.pdf
|
|
||||||
```
|
|
||||||
|
|
||||||
### Go
|
|
||||||
|
|
||||||
```golang
|
|
||||||
import "github.com/thecodingmachine/gotenberg/pkg"
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
|
|
||||||
req := &gotenberg.HTMLRequest{
|
|
||||||
IndexFilePath: "index.html",
|
|
||||||
Options: &gotenberg.HTMLOptions{
|
|
||||||
WebHookURL: "http://myapp.com/webhook/",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
dest := "result.pdf"
|
|
||||||
resp, err := c.Post(req)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### PHP
|
|
||||||
|
|
||||||
TODO
|
|
||||||
24
build/docs/Dockerfile
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
ARG GOLANG_VERSION
|
||||||
|
|
||||||
|
FROM golang:${GOLANG_VERSION}-stretch
|
||||||
|
|
||||||
|
# |--------------------------------------------------------------------------
|
||||||
|
# | static
|
||||||
|
# |--------------------------------------------------------------------------
|
||||||
|
# |
|
||||||
|
# | Installs the static site anti-framework – general-purpose library,
|
||||||
|
# | purpose-built commands for various domains.
|
||||||
|
# |
|
||||||
|
|
||||||
|
RUN go get github.com/apex/static/cmd/static-docs
|
||||||
|
|
||||||
|
# |--------------------------------------------------------------------------
|
||||||
|
# | Final touch
|
||||||
|
# |--------------------------------------------------------------------------
|
||||||
|
# |
|
||||||
|
# | Last instructions of this build.
|
||||||
|
# |
|
||||||
|
|
||||||
|
WORKDIR /docs
|
||||||
|
|
||||||
|
CMD [ "static-docs", "--in", "build/docs/content", "--out", "docs", "--theme", "gotenberg", "--title", "Gotenberg", "--subtitle", "A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF." ]
|
||||||
@@ -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!
|
||||||
@@ -7,7 +7,7 @@ Gotenberg is shipped within a Docker image.
|
|||||||
You may start it with:
|
You may start it with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ docker run --rm -p 3000:3000 thecodingmachine/gotenberg:3
|
$ docker run --rm -p 3000:3000 thecodingmachine/gotenberg:4
|
||||||
```
|
```
|
||||||
|
|
||||||
> The API will be available at [http://localhost:3000](http://localhost:3000).
|
> The API will be available at [http://localhost:3000](http://localhost:3000).
|
||||||
@@ -22,7 +22,7 @@ services:
|
|||||||
# your others services
|
# your others services
|
||||||
|
|
||||||
gotenberg:
|
gotenberg:
|
||||||
image: thecodingmachine/gotenberg:3
|
image: thecodingmachine/gotenberg:4
|
||||||
```
|
```
|
||||||
|
|
||||||
> The API will be available under `gotenberg:3000` in your Docker Compose network.
|
> The API will be available under `gotenberg:3000` in your Docker Compose network.
|
||||||
@@ -26,14 +26,14 @@ 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
|
-o result.pdf
|
||||||
```
|
```
|
||||||
|
|
||||||
### Go
|
### Go
|
||||||
@@ -43,9 +43,7 @@ import "github.com/thecodingmachine/gotenberg/pkg"
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
|
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
|
||||||
req := &gotenberg.HTMLRequest{
|
req, _ := gotenberg.NewHTMLRequest("index.html")
|
||||||
IndexFilePath: "index.html",
|
|
||||||
}
|
|
||||||
dest := "result.pdf"
|
dest := "result.pdf"
|
||||||
c.Store(req, dest)
|
c.Store(req, dest)
|
||||||
}
|
}
|
||||||
@@ -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,16 +98,16 @@ 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
|
-o result.pdf
|
||||||
```
|
```
|
||||||
|
|
||||||
### Go
|
### Go
|
||||||
@@ -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.
|
||||||
@@ -167,19 +185,22 @@ But this won't:
|
|||||||
You may also use *remote* paths for Google fonts, images and so on.
|
You may also use *remote* paths for Google fonts, images and so on.
|
||||||
|
|
||||||
> If you want to install fonts directly in the Gotenberg Docker image,
|
> If you want to install fonts directly in the Gotenberg Docker image,
|
||||||
> see to the [fonts section](#office.fonts).
|
> see to the [fonts section](#fonts).
|
||||||
|
|
||||||
### Guzzle
|
> For web fonts, there is a timeout of 500ms by default. You may update
|
||||||
|
> this value thanks to the form field `webFontsTimeout`.
|
||||||
|
|
||||||
|
### 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
|
-o result.pdf
|
||||||
```
|
```
|
||||||
|
|
||||||
### Go
|
### Go
|
||||||
@@ -189,14 +210,8 @@ 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("font.woff", "img.gif", "style.css")
|
||||||
AssetFilePaths: []string{
|
|
||||||
"style.css",
|
|
||||||
"img.png",
|
|
||||||
"font.woff",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
dest := "result.pdf"
|
dest := "result.pdf"
|
||||||
c.Store(req, dest)
|
c.Store(req, dest)
|
||||||
}
|
}
|
||||||
@@ -204,32 +219,48 @@ 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);
|
||||||
|
$dest = "result.pdf";
|
||||||
|
$client->store($request, $dest);
|
||||||
|
```
|
||||||
|
|
||||||
## 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
|
-o result.pdf
|
||||||
```
|
```
|
||||||
|
|
||||||
### Go
|
### Go
|
||||||
@@ -239,14 +270,10 @@ import "github.com/thecodingmachine/gotenberg/pkg"
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
|
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
|
||||||
req := &gotenberg.HTMLRequest{
|
req, _ := gotenberg.NewHTMLRequest("index.html")
|
||||||
IndexFilePath: "index.html",
|
req.SetPaperSize(gotenberg.A4)
|
||||||
Options: &gotenberg.HTMLOptions{
|
req.SetMargins(gotenberg.NoMargins)
|
||||||
PaperSize: gotenberg.A4,
|
req.SetLandscape(true)
|
||||||
PaperMargins: gotenberg.NoMargins,
|
|
||||||
Landscape: true
|
|
||||||
},
|
|
||||||
}
|
|
||||||
dest := "result.pdf"
|
dest := "result.pdf"
|
||||||
c.Store(req, dest)
|
c.Store(req, dest)
|
||||||
}
|
}
|
||||||
@@ -254,4 +281,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);
|
||||||
|
$dest = "result.pdf";
|
||||||
|
$client->store($request, $dest);
|
||||||
|
```
|
||||||
56
build/docs/content/03-url.md
Normal 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);
|
||||||
|
```
|
||||||
@@ -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,15 +28,15 @@ 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
|
-o result.pdf
|
||||||
```
|
```
|
||||||
|
|
||||||
### Go
|
### Go
|
||||||
@@ -46,12 +46,7 @@ import "github.com/thecodingmachine/gotenberg/pkg"
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
|
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
|
||||||
req := &gotenberg.MarkdownRequest{
|
req, _ := gotenberg.NewMarkdownRequest("index.html", "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);
|
||||||
|
$dest = "result.pdf";
|
||||||
|
$client->store($request, $dest);
|
||||||
|
```
|
||||||
118
build/docs/content/05-office.md
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
---
|
||||||
|
title: Office
|
||||||
|
---
|
||||||
|
|
||||||
|
Gotenberg provides the endpoint `/convert/office` for Office document conversions.
|
||||||
|
|
||||||
|
It accepts `POST` requests with a `multipart/form-data` Content-Type.
|
||||||
|
|
||||||
|
## Basic
|
||||||
|
|
||||||
|
You may send one or more Office documents. Following file extensions are accepted:
|
||||||
|
|
||||||
|
* `.txt`
|
||||||
|
* `.rtf`
|
||||||
|
* `.doc`
|
||||||
|
* `.docx`
|
||||||
|
* `.odt`
|
||||||
|
* `.xls`
|
||||||
|
* `.xlsx`
|
||||||
|
* `.ods`
|
||||||
|
* `.ppt`
|
||||||
|
* `.pptx`
|
||||||
|
* `.odp`
|
||||||
|
|
||||||
|
All files will be merged into a single resulting PDF.
|
||||||
|
|
||||||
|
> **Attention:** currently, `unoconv` cannot perform concurrent conversions.
|
||||||
|
> 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.
|
||||||
|
|
||||||
|
### cURL
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ curl --request POST \
|
||||||
|
--url http://localhost:3000/convert/office \
|
||||||
|
--header 'Content-Type: multipart/form-data' \
|
||||||
|
--form files=@document.docx \
|
||||||
|
--form files=@document2.docx \
|
||||||
|
-o result.pdf
|
||||||
|
```
|
||||||
|
|
||||||
|
### Go
|
||||||
|
|
||||||
|
```golang
|
||||||
|
import "github.com/thecodingmachine/gotenberg/pkg"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
|
||||||
|
req, _ := gotenberg.NewOfficeRequest("document.docx", "document2.docx")
|
||||||
|
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'),
|
||||||
|
DocumentFactory::makeFromPath('document2.docx', 'document2.docx'),
|
||||||
|
];
|
||||||
|
$request = new OfficeRequest($files);
|
||||||
|
$dest = "result.pdf";
|
||||||
|
$client->store($request, $dest);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Orientation
|
||||||
|
|
||||||
|
You may also customize the resulting PDF format.
|
||||||
|
|
||||||
|
By default, it will be rendered with `portrait` orientation.
|
||||||
|
|
||||||
|
### cURL
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ curl --request POST \
|
||||||
|
--url http://localhost:3000/convert/office \
|
||||||
|
--header 'Content-Type: multipart/form-data' \
|
||||||
|
--form files=@document.docx \
|
||||||
|
--form landscape=true \
|
||||||
|
-o result.pdf
|
||||||
|
```
|
||||||
|
|
||||||
|
### Go
|
||||||
|
|
||||||
|
```golang
|
||||||
|
import "github.com/thecodingmachine/gotenberg/pkg"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
|
||||||
|
req, _ := gotenberg.NewOfficeRequest("document.docx")
|
||||||
|
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->setLandscape(true);
|
||||||
|
$dest = "result.pdf";
|
||||||
|
$client->store($request, $dest);
|
||||||
|
```
|
||||||
@@ -11,15 +11,15 @@ 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
|
-o result.pdf
|
||||||
```
|
```
|
||||||
|
|
||||||
### Go
|
### Go
|
||||||
@@ -29,12 +29,7 @@ import "github.com/thecodingmachine/gotenberg/pkg"
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
|
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
|
||||||
req := &gotenberg.MergeRequest{
|
req, _ := gotenberg.NewMergeRequest("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);
|
||||||
|
$dest = "result.pdf";
|
||||||
|
$client->store($request, $dest);
|
||||||
|
```
|
||||||
50
build/docs/content/07-webhook.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
---
|
||||||
|
title: Webhook
|
||||||
|
---
|
||||||
|
|
||||||
|
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
|
||||||
|
to given URL.
|
||||||
|
|
||||||
|
By doing so, your requests to the API will be over before the conversions are actually done!
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### cURL
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ curl --request POST \
|
||||||
|
--url http://localhost:3000/convert/html \
|
||||||
|
--header 'Content-Type: multipart/form-data' \
|
||||||
|
--form files=@index.html \
|
||||||
|
--form webhookURL='http://myapp.com/webhook/'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Go
|
||||||
|
|
||||||
|
```golang
|
||||||
|
import "github.com/thecodingmachine/gotenberg/pkg"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
c := &gotenberg.Client{Hostname: "http://localhost:3000"}
|
||||||
|
req, _ := gotenberg.NewHTMLRequest("index.html")
|
||||||
|
req.SetWebhookURL("http://myapp.com/webhook/")
|
||||||
|
dest := "result.pdf"
|
||||||
|
resp, _ := c.Post(req)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### PHP
|
||||||
|
|
||||||
|
```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);
|
||||||
|
```
|
||||||
@@ -14,7 +14,7 @@ services:
|
|||||||
# your others services
|
# your others services
|
||||||
|
|
||||||
gotenberg:
|
gotenberg:
|
||||||
image: thecodingmachine/gotenberg:3
|
image: thecodingmachine/gotenberg:4
|
||||||
```
|
```
|
||||||
|
|
||||||
You may now launch your services using:
|
You may now launch your services using:
|
||||||
11
build/docs/content/09-liveness.md
Normal 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/)
|
||||||
13
build/docs/content/10-fonts.md
Normal 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
|
||||||
|
```
|
||||||
@@ -2,8 +2,6 @@ ARG GOLANG_VERSION
|
|||||||
|
|
||||||
FROM golang:${GOLANG_VERSION}-stretch
|
FROM golang:${GOLANG_VERSION}-stretch
|
||||||
|
|
||||||
LABEL authors="Julien Neuhart <j.neuhart@thecodingmachine.com>"
|
|
||||||
|
|
||||||
# |--------------------------------------------------------------------------
|
# |--------------------------------------------------------------------------
|
||||||
# | GolangCI-Lint
|
# | GolangCI-Lint
|
||||||
# |--------------------------------------------------------------------------
|
# |--------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ FROM golang:${GOLANG_VERSION}-stretch AS golang
|
|||||||
|
|
||||||
FROM thecodingmachine/gotenberg:base
|
FROM thecodingmachine/gotenberg:base
|
||||||
|
|
||||||
LABEL authors="Julien Neuhart <j.neuhart@thecodingmachine.com>"
|
|
||||||
|
|
||||||
# |--------------------------------------------------------------------------
|
# |--------------------------------------------------------------------------
|
||||||
# | Common libraries
|
# | Common libraries
|
||||||
# |--------------------------------------------------------------------------
|
# |--------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -21,4 +21,5 @@ go test github.com/thecodingmachine/gotenberg/internal/pkg/pm2 -run TestUnoconvS
|
|||||||
go build -o /usr/local/bin/gotenberg cmd/gotenberg/main.go
|
go build -o /usr/local/bin/gotenberg cmd/gotenberg/main.go
|
||||||
gotenberg &
|
gotenberg &
|
||||||
sleep 10
|
sleep 10
|
||||||
go test -race -cover -covermode=atomic github.com/thecodingmachine/gotenberg/pkg
|
go test -race -cover -covermode=atomic github.com/thecodingmachine/gotenberg/pkg
|
||||||
|
sleep 5 # allows Gotenberg to remove generated files (concurrent requests).
|
||||||
610
docs/index.html
@@ -3,8 +3,19 @@
|
|||||||
<meta http-equiv="x-ua-compatible" content="ie=edge"/>
|
<meta http-equiv="x-ua-compatible" content="ie=edge"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
<title>Gotenberg · A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.</title>
|
<title>Gotenberg · A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.</title>
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="57x57" href="theme/gotenberg/img/apple-touch-icon-57x57.png"/>
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="theme/gotenberg/img/apple-touch-icon-114x114.png"/>
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="theme/gotenberg/img/apple-touch-icon-72x72.png"/>
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="theme/gotenberg/img/apple-touch-icon-144x144.png"/>
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="60x60" href="theme/gotenberg/img/apple-touch-icon-60x60.png"/>
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="120x120" href="theme/gotenberg/img/apple-touch-icon-120x120.png"/>
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="76x76" href="theme/gotenberg/img/apple-touch-icon-76x76.png"/>
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="theme/gotenberg/img/apple-touch-icon-152x152.png"/>
|
||||||
|
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-196x196.png" sizes="196x196"/>
|
||||||
|
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-96x96.png" sizes="96x96"/>
|
||||||
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-32x32.png" sizes="32x32"/>
|
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-32x32.png" sizes="32x32"/>
|
||||||
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-16x16.png" sizes="16x16"/>
|
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-16x16.png" sizes="16x16"/>
|
||||||
|
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-128.png" sizes="128x128"/>
|
||||||
<link rel="stylesheet" href="theme/gotenberg/css/index.css"/>
|
<link rel="stylesheet" href="theme/gotenberg/css/index.css"/>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -12,7 +23,7 @@
|
|||||||
<div class="Container">
|
<div class="Container">
|
||||||
<div class="Header">
|
<div class="Header">
|
||||||
<div class="Title center">
|
<div class="Title center">
|
||||||
<img src="https://user-images.githubusercontent.com/8983173/49701110-4c8b9280-fbe8-11e8-895c-a4b9c7d2515b.png" alt="Gotenberg logo" width="250" height="250"/>
|
<img src="https://user-images.githubusercontent.com/8983173/50009948-84b01e00-ffb8-11e8-850b-fc240382c626.png" alt="Gotenberg logo" width="250" height="250"/>
|
||||||
<span class="text">Gotenberg</span>
|
<span class="text">Gotenberg</span>
|
||||||
<span class="subtext">A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.</span>
|
<span class="subtext">A Docker-powered stateless API for converting HTML, Markdown and Office documents to PDF.</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -34,6 +45,10 @@
|
|||||||
<a href="#html">HTML</a>
|
<a href="#html">HTML</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="item">
|
||||||
|
<a href="#url">URL</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<a href="#markdown">Markdown</a>
|
<a href="#markdown">Markdown</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -54,6 +69,14 @@
|
|||||||
<a href="#scalability">Scalability</a>
|
<a href="#scalability">Scalability</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="item">
|
||||||
|
<a href="#liveness">Liveness</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="item">
|
||||||
|
<a href="#fonts">Fonts</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<a href="#links">Links</a>
|
<a href="#links">Links</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -71,7 +94,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>
|
||||||
@@ -88,7 +111,7 @@
|
|||||||
|
|
||||||
<p>You may start it with:</p>
|
<p>You may start it with:</p>
|
||||||
|
|
||||||
<pre class="chroma">$ docker run --rm -p <span class="m">3000</span>:3000 thecodingmachine/gotenberg:3
|
<pre class="chroma">$ docker run --rm -p <span class="m">3000</span>:3000 thecodingmachine/gotenberg:4
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
@@ -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="c"># your others services</span><span class="w">
|
||||||
</span><span class="w">
|
</span><span class="w">
|
||||||
</span><span class="w"> </span>gotenberg<span class="p">:</span><span class="w">
|
</span><span class="w"> </span>gotenberg<span class="p">:</span><span class="w">
|
||||||
</span><span class="w"> </span>image<span class="p">:</span><span class="w"> </span>thecodingmachine/gotenberg<span class="p">:</span><span class="m">3</span><span class="w">
|
</span><span class="w"> </span>image<span class="p">:</span><span class="w"> </span>thecodingmachine/gotenberg<span class="p">:</span><span class="m">4</span><span class="w">
|
||||||
</span><span class="w"></span></pre>
|
</span></pre>
|
||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<p>The API will be available under <code>gotenberg:3000</code> in your Docker Compose network.</p>
|
<p>The API will be available under <code>gotenberg:3000</code> in your Docker Compose network.</p>
|
||||||
@@ -157,26 +180,26 @@ which will be converted to PDF.</p>
|
|||||||
<p>For instance:</p>
|
<p>For instance:</p>
|
||||||
|
|
||||||
<pre class="chroma"><span class="cp"><!doctype html></span>
|
<pre class="chroma"><span class="cp"><!doctype html></span>
|
||||||
<span class="p"><</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">"en"</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">"en"</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">head</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">head</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">"utf-8"</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">"utf-8"</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">title</span><span class="p"></span><span class="p">></span>My PDF<span class="p"><</span><span class="p">/</span><span class="nt">title</span><span class="p">></span>
|
<span class="p"><</span><span class="nt">title</span><span class="p">></span>My PDF<span class="p"></</span><span class="nt">title</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">head</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">head</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">body</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">body</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">h1</span><span class="p"></span><span class="p">></span>Hello world!<span class="p"><</span><span class="p">/</span><span class="nt">h1</span><span class="p">></span>
|
<span class="p"><</span><span class="nt">h1</span><span class="p">></span>Hello world!<span class="p"></</span><span class="nt">h1</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">body</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">body</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">html</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">html</span><span class="p">></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">'Content-Type: multipart/form-data'</span> <span class="se">\
|
</span><span class="se"></span> --header <span class="s1">'Content-Type: multipart/form-data'</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">\
|
||||||
> result.pdf
|
</span><span class="se"></span> -o result.pdf
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.basic.go" href="#html.basic.go">
|
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.basic.go" href="#html.basic.go">
|
||||||
@@ -185,13 +208,11 @@ which will be converted to PDF.</p>
|
|||||||
|
|
||||||
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</span>
|
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</span>
|
||||||
|
|
||||||
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
|
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
|
||||||
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&</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">"http://localhost:3000"</span><span class="p">}</span>
|
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&</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">"http://localhost:3000"</span><span class="p">}</span>
|
||||||
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLRequest</span><span class="p">{</span>
|
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewHTMLRequest</span><span class="p">(</span><span class="s">"index.html"</span><span class="p">)</span>
|
||||||
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">"index.html"</span><span class="p">,</span>
|
|
||||||
<span class="p">}</span>
|
|
||||||
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">"result.pdf"</span>
|
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">"result.pdf"</span>
|
||||||
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
|
<span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
|
||||||
<span class="p">}</span>
|
<span class="p">}</span>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@@ -199,7 +220,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">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);
|
||||||
|
</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>
|
||||||
@@ -210,21 +240,21 @@ Respectively, a file named <code>header.html</code> and <code>footer.html</code>
|
|||||||
|
|
||||||
<p>Each of them <strong>has to be a complete HTML document</strong>:</p>
|
<p>Each of them <strong>has to be a complete HTML document</strong>:</p>
|
||||||
|
|
||||||
<pre class="chroma"><span class="p"><</span><span class="nt">html</span><span class="p"></span><span class="p">></span>
|
<pre class="chroma"><span class="p"><</span><span class="nt">html</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">head</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">head</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">style</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">style</span><span class="p">></span>
|
||||||
<span class="nt">body</span> <span class="p">{</span>
|
<span class="nt">body</span> <span class="p">{</span>
|
||||||
<span class="k">font-size</span><span class="p">:</span> <span class="mi">8</span><span class="kt">rem</span><span class="p">;</span>
|
<span class="k">font-size</span><span class="p">:</span> <span class="mi">8</span><span class="kt">rem</span><span class="p">;</span>
|
||||||
<span class="k">margin</span><span class="p">:</span> <span class="mi">4</span><span class="kt">rem</span> <span class="kc">auto</span><span class="p">;</span>
|
<span class="k">margin</span><span class="p">:</span> <span class="mi">4</span><span class="kt">rem</span> <span class="kc">auto</span><span class="p">;</span>
|
||||||
<span class="p">}</span>
|
<span class="p">}</span>
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">style</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">style</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">head</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">head</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">body</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">body</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">p</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">p</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"pageNumber"</span><span class="p"></span><span class="p">><</span><span class="p">/</span><span class="nt">span</span><span class="p">></span> of <span class="p"><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"totalPages"</span><span class="p"></span><span class="p">><</span><span class="p">/</span><span class="nt">span</span><span class="p">></span>
|
<span class="p"><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"pageNumber"</span><span class="p">></</span><span class="nt">span</span><span class="p">></span> of <span class="p"><</span><span class="nt">span</span> <span class="na">class</span><span class="o">=</span><span class="s">"totalPages"</span><span class="p">></</span><span class="nt">span</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">p</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">p</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">body</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">body</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">html</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">html</span><span class="p">></span>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>The following classes allow you to inject printing values:</p>
|
<p>The following classes allow you to inject printing values:</p>
|
||||||
@@ -241,17 +271,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">'Content-Type: multipart/form-data'</span> <span class="se">\
|
</span><span class="se"></span> --header <span class="s1">'Content-Type: multipart/form-data'</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">\
|
||||||
> result.pdf
|
</span><span class="se"></span> -o result.pdf
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.header_and_footer.go" href="#html.header_and_footer.go">
|
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.header_and_footer.go" href="#html.header_and_footer.go">
|
||||||
@@ -260,17 +290,13 @@ Also, <code>footer.html</code> CSS properties override the ones from <code>heade
|
|||||||
|
|
||||||
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</span>
|
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</span>
|
||||||
|
|
||||||
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
|
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
|
||||||
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&</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">"http://localhost:3000"</span><span class="p">}</span>
|
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&</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">"http://localhost:3000"</span><span class="p">}</span>
|
||||||
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLRequest</span><span class="p">{</span>
|
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewHTMLRequest</span><span class="p">(</span><span class="s">"index.html"</span><span class="p">)</span>
|
||||||
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">"index.html"</span><span class="p">,</span>
|
<span class="nx">req</span><span class="p">.</span><span class="nf">SetHeader</span><span class="p">(</span><span class="s">"header.html"</span><span class="p">)</span>
|
||||||
<span class="nx">Options</span><span class="p">:</span> <span class="o">&</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLOptions</span><span class="p">{</span>
|
<span class="nx">req</span><span class="p">.</span><span class="nf">SetFooter</span><span class="p">(</span><span class="s">"footer.html"</span><span class="p">)</span>
|
||||||
<span class="nx">HeaderFilePath</span><span class="p">:</span> <span class="s">"header.html"</span><span class="p">,</span>
|
|
||||||
<span class="nx">FooterFilePath</span><span class="p">:</span> <span class="s">"footer.html"</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">"result.pdf"</span>
|
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">"result.pdf"</span>
|
||||||
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
|
<span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
|
||||||
<span class="p">}</span>
|
<span class="p">}</span>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@@ -278,13 +304,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">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);
|
||||||
|
</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>
|
||||||
@@ -292,52 +331,55 @@ are on the same level as the <code>index.html</code> file.</p>
|
|||||||
<p>In others words, this will work:</p>
|
<p>In others words, this will work:</p>
|
||||||
|
|
||||||
<pre class="chroma"><span class="cp"><!doctype html></span>
|
<pre class="chroma"><span class="cp"><!doctype html></span>
|
||||||
<span class="p"><</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">"en"</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">"en"</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">head</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">head</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">"utf-8"</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">"utf-8"</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">title</span><span class="p"></span><span class="p">></span>My PDF<span class="p"><</span><span class="p">/</span><span class="nt">title</span><span class="p">></span>
|
<span class="p"><</span><span class="nt">title</span><span class="p">></span>My PDF<span class="p"></</span><span class="nt">title</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">head</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">head</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">body</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">body</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">h1</span><span class="p"></span><span class="p">></span>Hello world!<span class="p"><</span><span class="p">/</span><span class="nt">h1</span><span class="p">></span>
|
<span class="p"><</span><span class="nt">h1</span><span class="p">></span>Hello world!<span class="p"></</span><span class="nt">h1</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"img.png"</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"img.png"</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">body</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">body</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">html</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">html</span><span class="p">></span>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>But this won’t:</p>
|
<p>But this won’t:</p>
|
||||||
|
|
||||||
<pre class="chroma"><span class="cp"><!doctype html></span>
|
<pre class="chroma"><span class="cp"><!doctype html></span>
|
||||||
<span class="p"><</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">"en"</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">"en"</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">head</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">head</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">"utf-8"</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">"utf-8"</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">title</span><span class="p"></span><span class="p">></span>My PDF<span class="p"><</span><span class="p">/</span><span class="nt">title</span><span class="p">></span>
|
<span class="p"><</span><span class="nt">title</span><span class="p">></span>My PDF<span class="p"></</span><span class="nt">title</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">head</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">head</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">body</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">body</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">h1</span><span class="p"></span><span class="p">></span>Hello world!<span class="p"><</span><span class="p">/</span><span class="nt">h1</span><span class="p">></span>
|
<span class="p"><</span><span class="nt">h1</span><span class="p">></span>Hello world!<span class="p"></</span><span class="nt">h1</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"/foo/img.png"</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">img</span> <span class="na">src</span><span class="o">=</span><span class="s">"/foo/img.png"</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">body</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">body</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">html</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">html</span><span class="p">></span>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<p>You may also use <em>remote</em> paths for Google fonts, images and so on.</p>
|
<p>You may also use <em>remote</em> paths for Google fonts, images and so on.</p>
|
||||||
|
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<p>If you want to install fonts directly in the Gotenberg Docker image,
|
<p>If you want to install fonts directly in the Gotenberg Docker image,
|
||||||
see to the <a href="#office.fonts">fonts section</a>.</p>
|
see to the <a href="#fonts">fonts section</a>.</p>
|
||||||
|
|
||||||
|
<p>For web fonts, there is a timeout of 500ms by default. You may update
|
||||||
|
this value thanks to the form field <code>webFontsTimeout</code>.</p>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets.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">'Content-Type: multipart/form-data'</span> <span class="se">\
|
</span><span class="se"></span> --header <span class="s1">'Content-Type: multipart/form-data'</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">\
|
||||||
> result.pdf
|
</span><span class="se"></span> -o result.pdf
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets.go" href="#html.assets.go">
|
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.assets.go" href="#html.assets.go">
|
||||||
@@ -346,18 +388,12 @@ see to the <a href="#office.fonts">fonts section</a>.</p>
|
|||||||
|
|
||||||
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</span>
|
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</span>
|
||||||
|
|
||||||
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
|
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
|
||||||
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&</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">"http://localhost:3000"</span><span class="p">}</span>
|
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&</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">"http://localhost:3000"</span><span class="p">}</span>
|
||||||
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLRequest</span><span class="p">{</span>
|
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewHTMLRequest</span><span class="p">(</span><span class="s">"index.html"</span><span class="p">)</span>
|
||||||
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">"index.html"</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">"font.woff"</span><span class="p">,</span> <span class="s">"img.gif"</span><span class="p">,</span> <span class="s">"style.css"</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">"style.css"</span><span class="p">,</span>
|
|
||||||
<span class="s">"img.png"</span><span class="p">,</span>
|
|
||||||
<span class="s">"font.woff"</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">"result.pdf"</span>
|
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">"result.pdf"</span>
|
||||||
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
|
<span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
|
||||||
<span class="p">}</span>
|
<span class="p">}</span>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@@ -365,37 +401,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">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);
|
||||||
|
$dest = "result.pdf";
|
||||||
|
$client->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">
|
<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">'Content-Type: multipart/form-data'</span> <span class="se">\
|
</span><span class="se"></span> --header <span class="s1">'Content-Type: multipart/form-data'</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">\
|
||||||
> result.pdf
|
</span><span class="se"></span> -o result.pdf
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation.go" href="#html.paper_size_margins_orientation.go">
|
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="html.paper_size_margins_orientation.go" href="#html.paper_size_margins_orientation.go">
|
||||||
@@ -404,18 +455,14 @@ Also, you have to set both <code>paperWidth</code> and <code>paperHeight</code>.
|
|||||||
|
|
||||||
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</span>
|
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</span>
|
||||||
|
|
||||||
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
|
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
|
||||||
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&</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">"http://localhost:3000"</span><span class="p">}</span>
|
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&</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">"http://localhost:3000"</span><span class="p">}</span>
|
||||||
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLRequest</span><span class="p">{</span>
|
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewHTMLRequest</span><span class="p">(</span><span class="s">"index.html"</span><span class="p">)</span>
|
||||||
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">"index.html"</span><span class="p">,</span>
|
<span class="nx">req</span><span class="p">.</span><span class="nf">SetPaperSize</span><span class="p">(</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">A4</span><span class="p">)</span>
|
||||||
<span class="nx">Options</span><span class="p">:</span> <span class="o">&</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLOptions</span><span class="p">{</span>
|
<span class="nx">req</span><span class="p">.</span><span class="nf">SetMargins</span><span class="p">(</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">NoMargins</span><span class="p">)</span>
|
||||||
<span class="nx">PaperSize</span><span class="p">:</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nx">A4</span><span class="p">,</span>
|
<span class="nx">req</span><span class="p">.</span><span class="nf">SetLandscape</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span>
|
||||||
<span class="nx">PaperMargins</span><span class="p">:</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nx">NoMargins</span><span class="p">,</span>
|
|
||||||
<span class="nx">Landscape</span><span class="p">:</span> <span class="kc">true</span>
|
|
||||||
<span class="p">},</span>
|
|
||||||
<span class="p">}</span>
|
|
||||||
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">"result.pdf"</span>
|
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">"result.pdf"</span>
|
||||||
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
|
<span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
|
||||||
<span class="p">}</span>
|
<span class="p">}</span>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@@ -423,7 +470,86 @@ 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">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);
|
||||||
|
$dest = "result.pdf";
|
||||||
|
$client->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">'Content-Type: multipart/form-data'</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">"github.com/thecodingmachine/gotenberg/pkg"</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">&</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">"http://localhost:3000"</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">"https://google.com"</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">"result.pdf"</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('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);
|
||||||
|
</pre>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -442,32 +568,32 @@ 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>
|
||||||
|
|
||||||
<pre class="chroma"><span class="cp"><!doctype html></span>
|
<pre class="chroma"><span class="cp"><!doctype html></span>
|
||||||
<span class="p"><</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">"en"</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">html</span> <span class="na">lang</span><span class="o">=</span><span class="s">"en"</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">head</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">head</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">"utf-8"</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">meta</span> <span class="na">charset</span><span class="o">=</span><span class="s">"utf-8"</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">title</span><span class="p"></span><span class="p">></span>My PDF<span class="p"><</span><span class="p">/</span><span class="nt">title</span><span class="p">></span>
|
<span class="p"><</span><span class="nt">title</span><span class="p">></span>My PDF<span class="p"></</span><span class="nt">title</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">head</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">head</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="nt">body</span><span class="p"></span><span class="p">></span>
|
<span class="p"><</span><span class="nt">body</span><span class="p">></span>
|
||||||
{{ toHTML .DirPath "file.md" }}
|
{{ toHTML .DirPath "file.md" }}
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">body</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">body</span><span class="p">></span>
|
||||||
<span class="p"><</span><span class="p">/</span><span class="nt">html</span><span class="p">></span>
|
<span class="p"></</span><span class="nt">html</span><span class="p">></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">'Content-Type: multipart/form-data'</span> <span class="se">\
|
</span><span class="se"></span> --header <span class="s1">'Content-Type: multipart/form-data'</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">\
|
||||||
> result.pdf
|
</span><span class="se"></span> -o result.pdf
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="markdown.basic.go" href="#markdown.basic.go">
|
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="markdown.basic.go" href="#markdown.basic.go">
|
||||||
@@ -476,16 +602,11 @@ in the file <code>index.html</code> which will convert a given markdown file to
|
|||||||
|
|
||||||
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</span>
|
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</span>
|
||||||
|
|
||||||
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
|
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
|
||||||
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&</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">"http://localhost:3000"</span><span class="p">}</span>
|
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&</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">"http://localhost:3000"</span><span class="p">}</span>
|
||||||
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">MarkdownRequest</span><span class="p">{</span>
|
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewMarkdownRequest</span><span class="p">(</span><span class="s">"index.html"</span><span class="p">,</span> <span class="s">"file.md"</span><span class="p">)</span>
|
||||||
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">"index.html"</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">"file.md"</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">"result.pdf"</span>
|
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">"result.pdf"</span>
|
||||||
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
|
<span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
|
||||||
<span class="p">}</span>
|
<span class="p">}</span>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@@ -493,7 +614,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">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);
|
||||||
|
$dest = "result.pdf";
|
||||||
|
$client->store($request, $dest);
|
||||||
|
</pre>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -501,7 +634,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 +645,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 +666,16 @@ That’s 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">'Content-Type: multipart/form-data'</span> <span class="se">\
|
</span><span class="se"></span> --header <span class="s1">'Content-Type: multipart/form-data'</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">\
|
||||||
> result.pdf
|
</span><span class="se"></span> -o result.pdf
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.basic.go" href="#office.basic.go">
|
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.basic.go" href="#office.basic.go">
|
||||||
@@ -549,16 +684,11 @@ See the <a href="#scalability">scalability section</a> to find how to mitigate t
|
|||||||
|
|
||||||
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</span>
|
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</span>
|
||||||
|
|
||||||
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
|
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
|
||||||
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&</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">"http://localhost:3000"</span><span class="p">}</span>
|
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&</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">"http://localhost:3000"</span><span class="p">}</span>
|
||||||
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">OfficeRequest</span><span class="p">{</span>
|
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewOfficeRequest</span><span class="p">(</span><span class="s">"document.docx"</span><span class="p">,</span> <span class="s">"document2.docx"</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">"document.docx"</span><span class="p">,</span>
|
|
||||||
<span class="s">"document2.docx"</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">"result.pdf"</span>
|
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">"result.pdf"</span>
|
||||||
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
|
<span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
|
||||||
<span class="p">}</span>
|
<span class="p">}</span>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@@ -566,20 +696,72 @@ 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">use TheCodingMachine\Gotenberg\Client;
|
||||||
|
use TheCodingMachine\Gotenberg\DocumentFactory;
|
||||||
|
use TheCodingMachine\Gotenberg\OfficeRequest;
|
||||||
|
|
||||||
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="office.fonts" href="#office.fonts">
|
$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);
|
||||||
|
$dest = "result.pdf";
|
||||||
|
$client->store($request, $dest);
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h2 class="Heading"><a class="Anchor" aria-hidden="true" id="office.orientation" href="#office.orientation">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||||
</a>Fonts</h2>
|
</a>Orientation</h2>
|
||||||
|
|
||||||
<p>By default, only <code>ttf-mscorefonts</code> fonts are installed.</p>
|
<p>You may also customize the resulting PDF format.</p>
|
||||||
|
|
||||||
<p>If you wish to use more fonts, you will have to create your own image:</p>
|
<p>By default, it will be rendered with <code>portrait</code> orientation.</p>
|
||||||
|
|
||||||
<pre class="chroma"><span class="k">FROM</span><span class="s"> thecodingmachine/gotenberg:3</span><span class="err">
|
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="office.orientation.c_url" href="#office.orientation.c_url">
|
||||||
</span><span class="err">
|
<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>
|
||||||
</span><span class="err"></span><span class="k">RUN</span> apt-get -y install yourfonts<span class="err">
|
</a>cURL</h3>
|
||||||
</span><span class="err"></span></pre>
|
|
||||||
|
<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">'Content-Type: multipart/form-data'</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">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.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>
|
||||||
|
|
||||||
|
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</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">&</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">"http://localhost:3000"</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">"document.docx"</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">"result.pdf"</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.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>
|
||||||
|
|
||||||
|
<pre class="chroma">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->setLandscape(true);
|
||||||
|
$dest = "result.pdf";
|
||||||
|
$client->store($request, $dest);
|
||||||
|
</pre>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -598,16 +780,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">'Content-Type: multipart/form-data'</span> <span class="se">\
|
</span><span class="se"></span> --header <span class="s1">'Content-Type: multipart/form-data'</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">\
|
||||||
> result.pdf
|
</span><span class="se"></span> -o result.pdf
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="merge.basic.go" href="#merge.basic.go">
|
<h3 class="Heading"><a class="Anchor" aria-hidden="true" id="merge.basic.go" href="#merge.basic.go">
|
||||||
@@ -616,16 +798,11 @@ will merge them and return the resulting PDF file.</p>
|
|||||||
|
|
||||||
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</span>
|
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</span>
|
||||||
|
|
||||||
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
|
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
|
||||||
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&</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">"http://localhost:3000"</span><span class="p">}</span>
|
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&</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">"http://localhost:3000"</span><span class="p">}</span>
|
||||||
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">MergeRequest</span><span class="p">{</span>
|
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewMergeRequest</span><span class="p">(</span><span class="s">"file.pdf"</span><span class="p">,</span> <span class="s">"file2.pdf"</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">"file.pdf"</span><span class="p">,</span>
|
|
||||||
<span class="s">"file2.pdf"</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">"result.pdf"</span>
|
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">"result.pdf"</span>
|
||||||
<span class="nx">c</span><span class="p">.</span><span class="nx">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
|
<span class="nx">c</span><span class="p">.</span><span class="nf">Store</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">dest</span><span class="p">)</span>
|
||||||
<span class="p">}</span>
|
<span class="p">}</span>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@@ -633,7 +810,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">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);
|
||||||
|
$dest = "result.pdf";
|
||||||
|
$client->store($request, $dest);
|
||||||
|
</pre>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -646,22 +835,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">'Content-Type: multipart/form-data'</span> <span class="se">\
|
</span><span class="se"></span> --header <span class="s1">'Content-Type: multipart/form-data'</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">'http://myapp.com/webhook/'</span>
|
</span><span class="se"></span> --form <span class="nv">webhookURL</span><span class="o">=</span><span class="s1">'http://myapp.com/webhook/'</span>
|
||||||
> 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">
|
||||||
@@ -670,16 +858,12 @@ to given URL.</p>
|
|||||||
|
|
||||||
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</span>
|
<pre class="chroma"><span class="kn">import</span> <span class="s">"github.com/thecodingmachine/gotenberg/pkg"</span>
|
||||||
|
|
||||||
<span class="kd">func</span> <span class="nx">main</span><span class="p">()</span> <span class="p">{</span>
|
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
|
||||||
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&</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">"http://localhost:3000"</span><span class="p">}</span>
|
<span class="nx">c</span> <span class="o">:=</span> <span class="o">&</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">"http://localhost:3000"</span><span class="p">}</span>
|
||||||
<span class="nx">req</span> <span class="o">:=</span> <span class="o">&</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLRequest</span><span class="p">{</span>
|
<span class="nx">req</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">gotenberg</span><span class="p">.</span><span class="nf">NewHTMLRequest</span><span class="p">(</span><span class="s">"index.html"</span><span class="p">)</span>
|
||||||
<span class="nx">IndexFilePath</span><span class="p">:</span> <span class="s">"index.html"</span><span class="p">,</span>
|
<span class="nx">req</span><span class="p">.</span><span class="nf">SetWebhookURL</span><span class="p">(</span><span class="s">"http://myapp.com/webhook/"</span><span class="p">)</span>
|
||||||
<span class="nx">Options</span><span class="p">:</span> <span class="o">&</span><span class="nx">gotenberg</span><span class="p">.</span><span class="nx">HTMLOptions</span><span class="p">{</span>
|
|
||||||
<span class="nx">WebHookURL</span><span class="p">:</span> <span class="s">"http://myapp.com/webhook/"</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">"result.pdf"</span>
|
<span class="nx">dest</span> <span class="o">:=</span> <span class="s">"result.pdf"</span>
|
||||||
<span class="nx">resp</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="nx">c</span><span class="p">.</span><span class="nx">Post</span><span class="p">(</span><span class="nx">req</span><span class="p">)</span>
|
<span class="nx">resp</span><span class="p">,</span> <span class="nx">_</span> <span class="o">:=</span> <span class="nx">c</span><span class="p">.</span><span class="nf">Post</span><span class="p">(</span><span class="nx">req</span><span class="p">)</span>
|
||||||
<span class="p">}</span>
|
<span class="p">}</span>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@@ -687,7 +871,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">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);
|
||||||
|
</pre>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -706,8 +899,8 @@ to given URL.</p>
|
|||||||
</span><span class="w"> </span><span class="c"># your others services</span><span class="w">
|
</span><span class="w"> </span><span class="c"># your others services</span><span class="w">
|
||||||
</span><span class="w">
|
</span><span class="w">
|
||||||
</span><span class="w"> </span>gotenberg<span class="p">:</span><span class="w">
|
</span><span class="w"> </span>gotenberg<span class="p">:</span><span class="w">
|
||||||
</span><span class="w"> </span>image<span class="p">:</span><span class="w"> </span>thecodingmachine/gotenberg<span class="p">:</span><span class="m">3</span><span class="w">
|
</span><span class="w"> </span>image<span class="p">:</span><span class="w"> </span>thecodingmachine/gotenberg<span class="p">:</span><span class="m">4</span><span class="w">
|
||||||
</span><span class="w"></span></pre>
|
</span></pre>
|
||||||
|
|
||||||
<p>You may now launch your services using:</p>
|
<p>You may now launch your services using:</p>
|
||||||
|
|
||||||
@@ -719,6 +912,37 @@ redirect a request to a Gotenberg container according to the round-robin strateg
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="Page" id="liveness">
|
||||||
|
<h1 class="Heading"><a class="Anchor" aria-hidden="true" id="liveness" href="#liveness">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||||
|
</a>Liveness</h1>
|
||||||
|
<p>Gotenberg provides the endpoint <code>/ping</code> for checking the API availability with
|
||||||
|
a simple <code>GET</code> request.</p>
|
||||||
|
|
||||||
|
<p>This feature is especially useful for liveness/readiness probes in Kubernetes:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes">Pod lifecycle</a></li>
|
||||||
|
<li><a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/">Configure Liveness and Readiness Probes</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="Page" id="fonts">
|
||||||
|
<h1 class="Heading"><a class="Anchor" aria-hidden="true" id="fonts" href="#fonts">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||||
|
</a>Fonts</h1>
|
||||||
|
<p>By default, a handful of fonts are installed. Asian characters are also supported out of the box.</p>
|
||||||
|
|
||||||
|
<p>If you wish to use more fonts, you will have to create your own image:</p>
|
||||||
|
|
||||||
|
<pre class="chroma"><span class="k">FROM</span><span class="s"> thecodingmachine/gotenberg:4</span><span class="err">
|
||||||
|
</span><span class="err">
|
||||||
|
</span><span class="err"></span><span class="k">RUN</span> apt-get -y install yourfonts<span class="err">
|
||||||
|
</span></pre>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="Page" id="links">
|
<div class="Page" id="links">
|
||||||
<h1 class="Heading"><a class="Anchor" aria-hidden="true" id="links" href="#links">
|
<h1 class="Heading"><a class="Anchor" aria-hidden="true" id="links" href="#links">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
|
||||||
|
|||||||
BIN
docs/theme/gotenberg/img/apple-touch-icon-114x114.png
vendored
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
docs/theme/gotenberg/img/apple-touch-icon-120x120.png
vendored
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
docs/theme/gotenberg/img/apple-touch-icon-144x144.png
vendored
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
docs/theme/gotenberg/img/apple-touch-icon-152x152.png
vendored
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/theme/gotenberg/img/apple-touch-icon-57x57.png
vendored
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
docs/theme/gotenberg/img/apple-touch-icon-60x60.png
vendored
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
docs/theme/gotenberg/img/apple-touch-icon-72x72.png
vendored
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
docs/theme/gotenberg/img/apple-touch-icon-76x76.png
vendored
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
docs/theme/gotenberg/img/favicon-128.png
vendored
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
docs/theme/gotenberg/img/favicon-16x16.png
vendored
|
Before Width: | Height: | Size: 923 B After Width: | Height: | Size: 917 B |
BIN
docs/theme/gotenberg/img/favicon-196x196.png
vendored
Normal file
|
After Width: | Height: | Size: 53 KiB |
BIN
docs/theme/gotenberg/img/favicon-32x32.png
vendored
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
BIN
docs/theme/gotenberg/img/favicon-96x96.png
vendored
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
docs/theme/gotenberg/img/favicon.ico
vendored
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 34 KiB |
BIN
docs/theme/gotenberg/img/mstile-144x144.png
vendored
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
docs/theme/gotenberg/img/mstile-150x150.png
vendored
Normal file
|
After Width: | Height: | Size: 95 KiB |
BIN
docs/theme/gotenberg/img/mstile-310x150.png
vendored
Normal file
|
After Width: | Height: | Size: 182 KiB |
BIN
docs/theme/gotenberg/img/mstile-310x310.png
vendored
Normal file
|
After Width: | Height: | Size: 372 KiB |
BIN
docs/theme/gotenberg/img/mstile-70x70.png
vendored
Normal file
|
After Width: | Height: | Size: 24 KiB |
15
docs/theme/gotenberg/views/index.html
vendored
@@ -5,8 +5,19 @@
|
|||||||
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>{{.Title}} · {{.Subtitle}}</title>
|
<title>{{.Title}} · {{.Subtitle}}</title>
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="57x57" href="theme/gotenberg/img/apple-touch-icon-57x57.png" />
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="114x114" href="theme/gotenberg/img/apple-touch-icon-114x114.png" />
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="72x72" href="theme/gotenberg/img/apple-touch-icon-72x72.png" />
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="144x144" href="theme/gotenberg/img/apple-touch-icon-144x144.png" />
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="60x60" href="theme/gotenberg/img/apple-touch-icon-60x60.png" />
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="120x120" href="theme/gotenberg/img/apple-touch-icon-120x120.png" />
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="76x76" href="theme/gotenberg/img/apple-touch-icon-76x76.png" />
|
||||||
|
<link rel="apple-touch-icon-precomposed" sizes="152x152" href="theme/gotenberg/img/apple-touch-icon-152x152.png" />
|
||||||
|
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-196x196.png" sizes="196x196" />
|
||||||
|
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-96x96.png" sizes="96x96" />
|
||||||
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-32x32.png" sizes="32x32" />
|
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-32x32.png" sizes="32x32" />
|
||||||
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-16x16.png" sizes="16x16" />
|
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-16x16.png" sizes="16x16" />
|
||||||
|
<link rel="icon" type="image/png" href="theme/gotenberg/img/favicon-128.png" sizes="128x128" />
|
||||||
<link rel="stylesheet" href="theme/gotenberg/css/index.css">
|
<link rel="stylesheet" href="theme/gotenberg/css/index.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -14,7 +25,7 @@
|
|||||||
<div class="Container">
|
<div class="Container">
|
||||||
<div class="Header">
|
<div class="Header">
|
||||||
<div class="Title center">
|
<div class="Title center">
|
||||||
<img src="https://user-images.githubusercontent.com/8983173/49701110-4c8b9280-fbe8-11e8-895c-a4b9c7d2515b.png" alt="Gotenberg logo" width="250" height="250" />
|
<img src="https://user-images.githubusercontent.com/8983173/50009948-84b01e00-ffb8-11e8-850b-fc240382c626.png" alt="Gotenberg logo" width="250" height="250" />
|
||||||
<span class="text">{{.Title}}</span>
|
<span class="text">{{.Title}}</span>
|
||||||
<span class="subtext">{{.Subtitle}}</span>
|
<span class="subtext">{{.Subtitle}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
4
go.mod
@@ -4,8 +4,8 @@ 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-20190126223945-739700bf4ef7
|
||||||
github.com/labstack/gommon v0.2.8
|
github.com/labstack/gommon v0.2.8
|
||||||
github.com/mafredri/cdp v0.20.0
|
github.com/mafredri/cdp v0.20.0
|
||||||
github.com/microcosm-cc/bluemonday v1.0.1
|
github.com/microcosm-cc/bluemonday v1.0.1
|
||||||
|
|||||||
4
go.sum
@@ -10,8 +10,12 @@ 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 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 h1:9PfxPUmasKzeJor9uQTaXLT6WUG/r+vSTmvXxvv3JO4=
|
||||||
github.com/labstack/echo v3.3.5+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
|
github.com/labstack/echo v3.3.5+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
|
||||||
github.com/labstack/gommon v0.2.7/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4=
|
github.com/labstack/gommon v0.2.7/go.mod h1:/tj9csK2iPSBvn+3NLM9e52usepMtrd5ilFYA+wQNJ4=
|
||||||
|
|||||||
@@ -67,9 +67,11 @@ func setup() *echo.Echo {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
e.GET("/ping", func(c echo.Context) error { return nil })
|
||||||
e.POST("/merge", merge)
|
e.POST("/merge", merge)
|
||||||
g := e.Group("/convert")
|
g := e.Group("/convert")
|
||||||
g.POST("/html", convertHTML)
|
g.POST("/html", convertHTML)
|
||||||
|
g.POST("/url", convertURL)
|
||||||
g.POST("/markdown", convertMarkdown)
|
g.POST("/markdown", convertMarkdown)
|
||||||
g.POST("/office", convertOffice)
|
g.POST("/office", convertOffice)
|
||||||
return e
|
return e
|
||||||
@@ -87,14 +89,15 @@ func newContext(r *resource) (context.Context, context.CancelFunc) {
|
|||||||
func print(c echo.Context, p printer.Printer, r *resource) error {
|
func print(c echo.Context, p printer.Printer, r *resource) error {
|
||||||
baseFilename, err := rand.Get()
|
baseFilename, err := rand.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("getting result file name: %v", err)
|
return hijackErr(fmt.Errorf("getting result file name: %v", err), r)
|
||||||
}
|
}
|
||||||
filename := fmt.Sprintf("%s.pdf", baseFilename)
|
filename := fmt.Sprintf("%s.pdf", baseFilename)
|
||||||
fpath := fmt.Sprintf("%s/%s", r.dirPath, filename)
|
fpath := fmt.Sprintf("%s/%s", r.dirPath, filename)
|
||||||
if r.webhookURL() == "" {
|
if r.webhookURL() == "" {
|
||||||
|
defer r.removeAll()
|
||||||
// if no webhook URL given, run conversion
|
// if no webhook URL given, run conversion
|
||||||
// and directly return the resulting PDF file
|
// and directly return the resulting PDF file
|
||||||
// or and error.
|
// or an error.
|
||||||
if err := p.Print(fpath); err != nil {
|
if err := p.Print(fpath); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -104,6 +107,7 @@ func print(c echo.Context, p printer.Printer, r *resource) error {
|
|||||||
// run the following lines in a goroutine so that
|
// run the following lines in a goroutine so that
|
||||||
// it doesn't block.
|
// it doesn't block.
|
||||||
go func() {
|
go func() {
|
||||||
|
defer r.removeAll()
|
||||||
if err := p.Print(fpath); err != nil {
|
if err := p.Print(fpath); err != nil {
|
||||||
c.Logger().Errorf("%v", err)
|
c.Logger().Errorf("%v", err)
|
||||||
return
|
return
|
||||||
@@ -123,3 +127,10 @@ func print(c echo.Context, p printer.Printer, r *resource) error {
|
|||||||
}()
|
}()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hijackErr(err error, r *resource) error {
|
||||||
|
if r != nil {
|
||||||
|
defer r.removeAll()
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|||||||
18
internal/app/api/api_test.go
Normal 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)
|
||||||
|
}
|
||||||
@@ -8,9 +8,8 @@ import (
|
|||||||
func convertHTML(c echo.Context) error {
|
func convertHTML(c echo.Context) error {
|
||||||
r, err := newResource(c)
|
r, err := newResource(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
defer r.removeAll()
|
|
||||||
ctx, cancel := newContext(r)
|
ctx, cancel := newContext(r)
|
||||||
if cancel != nil {
|
if cancel != nil {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
@@ -18,26 +17,26 @@ func convertHTML(c echo.Context) error {
|
|||||||
p := &printer.HTML{Context: ctx}
|
p := &printer.HTML{Context: ctx}
|
||||||
indexPath, err := r.filePath("index.html")
|
indexPath, err := r.filePath("index.html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
p.WithLocalURL(indexPath)
|
p.WithLocalURL(indexPath)
|
||||||
headerPath, _ := r.filePath("header.html")
|
headerPath, _ := r.filePath("header.html")
|
||||||
if err := p.WithHeaderFile(headerPath); err != nil {
|
if err := p.WithHeaderFile(headerPath); err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
footerPath, _ := r.filePath("footer.html")
|
footerPath, _ := r.filePath("footer.html")
|
||||||
if err := p.WithFooterFile(footerPath); err != nil {
|
if err := p.WithFooterFile(footerPath); err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
paperSize, err := r.paperSize()
|
paperSize, err := r.paperSize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
p.PaperWidth = paperSize[0]
|
p.PaperWidth = paperSize[0]
|
||||||
p.PaperHeight = paperSize[1]
|
p.PaperHeight = paperSize[1]
|
||||||
paperMargins, err := r.paperMargins()
|
paperMargins, err := r.paperMargins()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
p.MarginTop = paperMargins[0]
|
p.MarginTop = paperMargins[0]
|
||||||
p.MarginBottom = paperMargins[1]
|
p.MarginBottom = paperMargins[1]
|
||||||
@@ -45,8 +44,13 @@ func convertHTML(c echo.Context) error {
|
|||||||
p.MarginRight = paperMargins[3]
|
p.MarginRight = paperMargins[3]
|
||||||
landscape, err := r.landscape()
|
landscape, err := r.landscape()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
p.Landscape = landscape
|
p.Landscape = landscape
|
||||||
|
chromeWebFontsTimeout, err := r.webFontsTimeout()
|
||||||
|
if err != nil {
|
||||||
|
return hijackErr(err, r)
|
||||||
|
}
|
||||||
|
p.WebFontsTimeout = chromeWebFontsTimeout
|
||||||
return print(c, p, r)
|
return print(c, p, r)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,35 +8,34 @@ import (
|
|||||||
func convertMarkdown(c echo.Context) error {
|
func convertMarkdown(c echo.Context) error {
|
||||||
r, err := newResource(c)
|
r, err := newResource(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
defer r.removeAll()
|
|
||||||
ctx, cancel := newContext(r)
|
ctx, cancel := newContext(r)
|
||||||
if cancel != nil {
|
if cancel != nil {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
}
|
}
|
||||||
indexPath, err := r.filePath("index.html")
|
indexPath, err := r.filePath("index.html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
p := &printer.Markdown{Context: ctx, TemplatePath: indexPath}
|
p := &printer.Markdown{Context: ctx, TemplatePath: indexPath}
|
||||||
headerPath, _ := r.filePath("header.html")
|
headerPath, _ := r.filePath("header.html")
|
||||||
if err := p.WithHeaderFile(headerPath); err != nil {
|
if err := p.WithHeaderFile(headerPath); err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
footerPath, _ := r.filePath("footer.html")
|
footerPath, _ := r.filePath("footer.html")
|
||||||
if err := p.WithFooterFile(footerPath); err != nil {
|
if err := p.WithFooterFile(footerPath); err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
paperSize, err := r.paperSize()
|
paperSize, err := r.paperSize()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
p.PaperWidth = paperSize[0]
|
p.PaperWidth = paperSize[0]
|
||||||
p.PaperHeight = paperSize[1]
|
p.PaperHeight = paperSize[1]
|
||||||
paperMargins, err := r.paperMargins()
|
paperMargins, err := r.paperMargins()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
p.MarginTop = paperMargins[0]
|
p.MarginTop = paperMargins[0]
|
||||||
p.MarginBottom = paperMargins[1]
|
p.MarginBottom = paperMargins[1]
|
||||||
@@ -44,8 +43,13 @@ func convertMarkdown(c echo.Context) error {
|
|||||||
p.MarginRight = paperMargins[3]
|
p.MarginRight = paperMargins[3]
|
||||||
landscape, err := r.landscape()
|
landscape, err := r.landscape()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
p.Landscape = landscape
|
p.Landscape = landscape
|
||||||
|
chromeWebFontsTimeout, err := r.webFontsTimeout()
|
||||||
|
if err != nil {
|
||||||
|
return hijackErr(err, r)
|
||||||
|
}
|
||||||
|
p.WebFontsTimeout = chromeWebFontsTimeout
|
||||||
return print(c, p, r)
|
return print(c, p, r)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -13,34 +14,41 @@ import (
|
|||||||
func merge(c echo.Context) error {
|
func merge(c echo.Context) error {
|
||||||
r, err := newResource(c)
|
r, err := newResource(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
defer r.removeAll()
|
|
||||||
fpaths, err := r.filePaths([]string{".pdf"})
|
fpaths, err := r.filePaths([]string{".pdf"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
|
}
|
||||||
|
if len(fpaths) == 0 {
|
||||||
|
return hijackErr(errors.New("no suitable PDF files to merge"), r)
|
||||||
}
|
}
|
||||||
baseFilename, err := rand.Get()
|
baseFilename, err := rand.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("getting result file name: %v", err)
|
return hijackErr(fmt.Errorf("getting result file name: %v", err), r)
|
||||||
}
|
}
|
||||||
filename := fmt.Sprintf("%s.pdf", baseFilename)
|
filename := fmt.Sprintf("%s.pdf", baseFilename)
|
||||||
dest := fmt.Sprintf("%s/%s", r.dirPath, filename)
|
fpath := fmt.Sprintf("%s/%s", r.dirPath, filename)
|
||||||
if r.webhookURL() == "" {
|
if r.webhookURL() == "" {
|
||||||
|
defer r.removeAll()
|
||||||
// if no webhook URL given, run merge
|
// if no webhook URL given, run merge
|
||||||
// and directly return the resulting PDF file
|
// and directly return the resulting PDF file
|
||||||
// or and error.
|
// or an error.
|
||||||
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 {
|
defer r.removeAll()
|
||||||
|
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
|
||||||
|
|||||||
@@ -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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var officeExts = []string{
|
var officeExts = []string{
|
||||||
|
".txt",
|
||||||
|
".rtf",
|
||||||
".doc",
|
".doc",
|
||||||
".docx",
|
".docx",
|
||||||
".odt",
|
".odt",
|
||||||
@@ -22,20 +24,24 @@ var officeExts = []string{
|
|||||||
func convertOffice(c echo.Context) error {
|
func convertOffice(c echo.Context) error {
|
||||||
r, err := newResource(c)
|
r, err := newResource(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
defer r.removeAll()
|
|
||||||
ctx, cancel := newContext(r)
|
ctx, cancel := newContext(r)
|
||||||
if cancel != nil {
|
if cancel != nil {
|
||||||
defer cancel()
|
defer cancel()
|
||||||
}
|
}
|
||||||
fpaths, err := r.filePaths(officeExts)
|
fpaths, err := r.filePaths(officeExts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return hijackErr(err, r)
|
||||||
}
|
}
|
||||||
if len(fpaths) == 0 {
|
if len(fpaths) == 0 {
|
||||||
return errors.New("no suitable office documents to convert")
|
return hijackErr(errors.New("no suitable office documents to convert"), r)
|
||||||
}
|
}
|
||||||
p := &printer.Office{Context: ctx, FilePaths: fpaths}
|
p := &printer.Office{Context: ctx, FilePaths: fpaths}
|
||||||
|
landscape, err := r.landscape()
|
||||||
|
if err != nil {
|
||||||
|
return hijackErr(err, r)
|
||||||
|
}
|
||||||
|
p.Landscape = landscape
|
||||||
return print(c, p, r)
|
return print(c, p, r)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
@@ -12,14 +13,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
webhookURL string = "webhookURL"
|
remoteURL string = "remoteURL"
|
||||||
paperWidth string = "paperWidth"
|
webhookURL string = "webhookURL"
|
||||||
paperHeight string = "paperHeight"
|
paperWidth string = "paperWidth"
|
||||||
marginTop string = "marginTop"
|
paperHeight string = "paperHeight"
|
||||||
marginBottom string = "marginBottom"
|
marginTop string = "marginTop"
|
||||||
marginLeft string = "marginLeft"
|
marginBottom string = "marginBottom"
|
||||||
marginRight string = "marginRight"
|
marginLeft string = "marginLeft"
|
||||||
landscape string = "landscape"
|
marginRight string = "marginRight"
|
||||||
|
landscape string = "landscape"
|
||||||
|
webFontsTimeout string = "webFontsTimeout"
|
||||||
)
|
)
|
||||||
|
|
||||||
// resource facilitates storing and accessing
|
// resource facilitates storing and accessing
|
||||||
@@ -31,6 +34,7 @@ type resource struct {
|
|||||||
|
|
||||||
func newResource(c echo.Context) (*resource, error) {
|
func newResource(c echo.Context) (*resource, error) {
|
||||||
v := make(map[string]string)
|
v := make(map[string]string)
|
||||||
|
v[remoteURL] = c.FormValue(remoteURL)
|
||||||
v[webhookURL] = c.FormValue(webhookURL)
|
v[webhookURL] = c.FormValue(webhookURL)
|
||||||
v[paperWidth] = c.FormValue(paperWidth)
|
v[paperWidth] = c.FormValue(paperWidth)
|
||||||
v[paperHeight] = c.FormValue(paperHeight)
|
v[paperHeight] = c.FormValue(paperHeight)
|
||||||
@@ -39,6 +43,7 @@ func newResource(c echo.Context) (*resource, error) {
|
|||||||
v[marginLeft] = c.FormValue(marginLeft)
|
v[marginLeft] = c.FormValue(marginLeft)
|
||||||
v[marginRight] = c.FormValue(marginRight)
|
v[marginRight] = c.FormValue(marginRight)
|
||||||
v[landscape] = c.FormValue(landscape)
|
v[landscape] = c.FormValue(landscape)
|
||||||
|
v[webFontsTimeout] = c.FormValue(webFontsTimeout)
|
||||||
dirPath, err := rand.Get()
|
dirPath, err := rand.Get()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -49,17 +54,17 @@ func newResource(c echo.Context) (*resource, error) {
|
|||||||
r := &resource{values: v, dirPath: dirPath}
|
r := &resource{values: v, dirPath: dirPath}
|
||||||
form, err := c.MultipartForm()
|
form, err := c.MultipartForm()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("getting multipart form: %v", err)
|
return r, fmt.Errorf("getting multipart form: %v", err)
|
||||||
}
|
}
|
||||||
for _, files := range form.File {
|
for _, files := range form.File {
|
||||||
for _, fh := range files {
|
for _, fh := range files {
|
||||||
in, err := fh.Open()
|
in, err := fh.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("%s: opening file: %v", fh.Filename, err)
|
return r, fmt.Errorf("%s: opening file: %v", fh.Filename, err)
|
||||||
}
|
}
|
||||||
defer in.Close()
|
defer in.Close()
|
||||||
if err := r.writeFile(fh.Filename, in); err != nil {
|
if err := r.writeFile(fh.Filename, in); err != nil {
|
||||||
return nil, err
|
return r, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,5 +185,24 @@ func (r *resource) landscape() (bool, error) {
|
|||||||
return landscape, nil
|
return landscape, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *resource) remoteURL() (string, error) {
|
||||||
|
if r.values[remoteURL] == "" {
|
||||||
|
return "", errors.New("no remote URL")
|
||||||
|
}
|
||||||
|
return r.values[remoteURL], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *resource) webFontsTimeout() (int64, error) {
|
||||||
|
webFontsTimeoutStr := r.values[webFontsTimeout]
|
||||||
|
if webFontsTimeoutStr == "" {
|
||||||
|
return 500, nil
|
||||||
|
}
|
||||||
|
timeout, err := strconv.ParseInt(webFontsTimeoutStr, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 500, fmt.Errorf("web fonts timeout: %v", err)
|
||||||
|
}
|
||||||
|
return timeout, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *resource) webhookURL() string { return r.values[webhookURL] }
|
func (r *resource) webhookURL() string { return r.values[webhookURL] }
|
||||||
func (r *resource) removeAll() error { return os.RemoveAll(r.dirPath) }
|
func (r *resource) removeAll() error { return os.RemoveAll(r.dirPath) }
|
||||||
|
|||||||
56
internal/app/api/url.go
Normal file
@@ -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)
|
||||||
|
}
|
||||||
24
internal/app/api/url_test.go
Normal 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,52 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
Package printer contains structs which convert
|
Package printer contains structs which convert
|
||||||
a specific file type to PDF:
|
a specific file type to PDF.
|
||||||
|
|
||||||
// converting HTML to PDF.
|
It is also able to merge a list of PDF files.
|
||||||
p := &printer.HTML{
|
|
||||||
Context: context.Background(),
|
|
||||||
PaperWidth: 8.27,
|
|
||||||
PaperHeight: 11.7,
|
|
||||||
Landscape: false,
|
|
||||||
}
|
|
||||||
p.WithLocalURL("index.html")
|
|
||||||
if err := p.Print("result.pdf"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// converting Markdown to PDF:
|
|
||||||
// it assumes here that our template "index.html"
|
|
||||||
// will call toHTML method to convert
|
|
||||||
// markdown files to HTML.
|
|
||||||
p := &printer.Markdown{
|
|
||||||
Context: context.Background(),
|
|
||||||
TemplatePath: "index.html",
|
|
||||||
PaperWidth: 8.27,
|
|
||||||
PaperHeight: 11.7,
|
|
||||||
Landscape: false,
|
|
||||||
}
|
|
||||||
if err := p.Print("result.pdf"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// converting Office documents to PDF:
|
|
||||||
// it converts each files independently and
|
|
||||||
// then merge them.
|
|
||||||
//
|
|
||||||
// Also, as unoconv cannot perform
|
|
||||||
// concurrent conversions, a lock is applied.
|
|
||||||
p := &printer.Office{
|
|
||||||
Context: ctx,
|
|
||||||
FilePaths: []string{"document.docx", "presentation.pptx"}
|
|
||||||
}
|
|
||||||
if err := p.Print("result.pdf"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
It is also able to merge a list of PDF files:
|
|
||||||
|
|
||||||
if err := printer.Merge([]string{"foo.pdf", "bar.pdf"}, "result.pdf"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
package printer
|
package printer
|
||||||
|
|||||||
@@ -18,17 +18,18 @@ import (
|
|||||||
|
|
||||||
// HTML facilitates HTML to PDF conversion.
|
// HTML facilitates HTML to PDF conversion.
|
||||||
type HTML struct {
|
type HTML struct {
|
||||||
Context context.Context
|
Context context.Context
|
||||||
URL string
|
URL string
|
||||||
HeaderHTML string
|
HeaderHTML string
|
||||||
FooterHTML string
|
FooterHTML string
|
||||||
PaperWidth float64
|
PaperWidth float64
|
||||||
PaperHeight float64
|
PaperHeight float64
|
||||||
MarginTop float64
|
MarginTop float64
|
||||||
MarginBottom float64
|
MarginBottom float64
|
||||||
MarginLeft float64
|
MarginLeft float64
|
||||||
MarginRight float64
|
MarginRight float64
|
||||||
Landscape bool
|
Landscape bool
|
||||||
|
WebFontsTimeout int64
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultHeaderFooterHTML string = "<html><head></head><body></body></html>"
|
const defaultHeaderFooterHTML string = "<html><head></head><body></body></html>"
|
||||||
@@ -36,14 +37,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)
|
||||||
}
|
}
|
||||||
@@ -102,14 +104,17 @@ func (html *HTML) Print(destination string) error {
|
|||||||
return fmt.Errorf("waiting for page loading: %v", err)
|
return fmt.Errorf("waiting for page loading: %v", err)
|
||||||
}
|
}
|
||||||
// inject a script to make sure web fonts are loaded.
|
// inject a script to make sure web fonts are loaded.
|
||||||
script := `new Promise((resolve, reject) => {
|
script := fmt.Sprintf(`new Promise((resolve, reject) => {
|
||||||
document.fonts.ready.then(function () {
|
document.fonts.ready.then(function () {
|
||||||
resolve('fonts loaded');
|
resolve('fonts loaded');
|
||||||
});
|
});
|
||||||
setTimeout(resolve.bind(resolve, 'timeout'), %.0f);
|
setTimeout(resolve.bind(resolve, 'timeout'), %d);
|
||||||
});`
|
});`, html.WebFontsTimeout)
|
||||||
scriptArg := runtime.NewEvaluateArgs(script).SetAwaitPromise(true)
|
scriptArg := runtime.NewEvaluateArgs(script).SetAwaitPromise(true)
|
||||||
returnObj, _ := c.Runtime.Evaluate(html.Context, scriptArg)
|
returnObj, _ := c.Runtime.Evaluate(html.Context, scriptArg)
|
||||||
|
if returnObj.ExceptionDetails != nil {
|
||||||
|
return fmt.Errorf("script evaluated with exception: %+v", returnObj.ExceptionDetails)
|
||||||
|
}
|
||||||
loadFontsResult := string(returnObj.Result.Value)
|
loadFontsResult := string(returnObj.Result.Value)
|
||||||
if strings.Contains(loadFontsResult, "timeout") {
|
if strings.Contains(loadFontsResult, "timeout") {
|
||||||
return errors.New("timed out loading fonts")
|
return errors.New("timed out loading fonts")
|
||||||
|
|||||||
@@ -15,17 +15,18 @@ import (
|
|||||||
|
|
||||||
// Markdown facilitates Markdown to PDF conversion.
|
// Markdown facilitates Markdown to PDF conversion.
|
||||||
type Markdown struct {
|
type Markdown struct {
|
||||||
Context context.Context
|
Context context.Context
|
||||||
TemplatePath string
|
TemplatePath string
|
||||||
HeaderHTML string
|
HeaderHTML string
|
||||||
FooterHTML string
|
FooterHTML string
|
||||||
PaperWidth float64
|
PaperWidth float64
|
||||||
PaperHeight float64
|
PaperHeight float64
|
||||||
MarginTop float64
|
MarginTop float64
|
||||||
MarginBottom float64
|
MarginBottom float64
|
||||||
MarginLeft float64
|
MarginLeft float64
|
||||||
MarginRight float64
|
MarginRight float64
|
||||||
Landscape bool
|
Landscape bool
|
||||||
|
WebFontsTimeout int64
|
||||||
|
|
||||||
html *HTML
|
html *HTML
|
||||||
}
|
}
|
||||||
@@ -52,6 +53,7 @@ func (md *Markdown) Print(destination string) error {
|
|||||||
md.html.MarginLeft = md.MarginLeft
|
md.html.MarginLeft = md.MarginLeft
|
||||||
md.html.MarginRight = md.MarginRight
|
md.html.MarginRight = md.MarginRight
|
||||||
md.html.Landscape = md.Landscape
|
md.html.Landscape = md.Landscape
|
||||||
|
md.html.WebFontsTimeout = md.WebFontsTimeout
|
||||||
tmpl, err := template.
|
tmpl, err := template.
|
||||||
New(filepath.Base(md.TemplatePath)).
|
New(filepath.Base(md.TemplatePath)).
|
||||||
Funcs(template.FuncMap{"toHTML": toHTML}).
|
Funcs(template.FuncMap{"toHTML": toHTML}).
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ var mu sync.Mutex
|
|||||||
type Office struct {
|
type Office struct {
|
||||||
Context context.Context
|
Context context.Context
|
||||||
FilePaths []string
|
FilePaths []string
|
||||||
|
Landscape bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Print converts Office documents to PDF.
|
// Print converts Office documents to PDF.
|
||||||
@@ -32,14 +33,18 @@ 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)
|
||||||
|
cmdArgs := []string{
|
||||||
|
"--format",
|
||||||
|
"pdf",
|
||||||
|
}
|
||||||
|
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 {
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -3,11 +3,19 @@ package printer
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
pdfcpuAPI "github.com/hhrutter/pdfcpu/pkg/api"
|
pdfcpuAPI "github.com/hhrutter/pdfcpu/pkg/api"
|
||||||
|
pdfcpuLog "github.com/hhrutter/pdfcpu/pkg/log"
|
||||||
pdfcpuConfig "github.com/hhrutter/pdfcpu/pkg/pdfcpu"
|
pdfcpuConfig "github.com/hhrutter/pdfcpu/pkg/pdfcpu"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// disable loggers when merging
|
||||||
|
// PDFs.
|
||||||
|
pdfcpuLog.DisableLoggers()
|
||||||
|
}
|
||||||
|
|
||||||
// Printer is a type that can create a PDF file from a source.
|
// Printer is a type that can create a PDF file from a source.
|
||||||
// The source is defined in the underlying implementation.
|
// The source is defined in the underlying implementation.
|
||||||
type Printer interface {
|
type Printer interface {
|
||||||
@@ -16,14 +24,23 @@ type Printer interface {
|
|||||||
|
|
||||||
// Merge merges PDF files.
|
// Merge merges PDF files.
|
||||||
func Merge(fpaths []string, destination string) error {
|
func Merge(fpaths []string, destination string) error {
|
||||||
cmd := pdfcpuAPI.MergeCommand(fpaths, destination, pdfcpuConfig.NewDefaultConfiguration())
|
cmdcpu := pdfcpuAPI.MergeCommand(fpaths, destination, pdfcpuConfig.NewDefaultConfiguration())
|
||||||
_, err := pdfcpuAPI.Merge(cmd)
|
_, err := pdfcpuAPI.Merge(cmdcpu)
|
||||||
return err
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// if pdfcpu failed to merge PDF files...
|
||||||
|
// https://github.com/thecodingmachine/gotenberg/issues/29
|
||||||
|
var cmdArgs []string
|
||||||
|
cmdArgs = append(cmdArgs, fpaths...)
|
||||||
|
cmdArgs = append(cmdArgs, "cat", "output", destination)
|
||||||
|
cmd := exec.Command("pdftk", cmdArgs...)
|
||||||
|
return cmd.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeBytesToFile(dst string, b []byte) error {
|
func writeBytesToFile(dst string, b []byte) error {
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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(
|
||||||
"img.png",
|
"font.woff",
|
||||||
},
|
"img.gif",
|
||||||
Options: &gotenberg.HTMLOptions{
|
"style.css",
|
||||||
HeaderFilePath: "header.html",
|
)
|
||||||
FooterFilePath: "footer.html",
|
req.SetPaperSize(gotenberg.A4)
|
||||||
PaperSize: gotenberg.A4,
|
req.SetMargins(gotenberg.NormalMargins)
|
||||||
PaperMargins: gotenberg.NormalMargins,
|
req.SetLandscape(false)
|
||||||
},
|
|
||||||
}
|
|
||||||
dest := "foo.pdf"
|
dest := "foo.pdf"
|
||||||
c.Store(req, dest)
|
c.Store(req, dest)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,14 +13,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
webhookURL string = "webhookURL"
|
remoteURL string = "remoteURL"
|
||||||
paperWidth string = "paperWidth"
|
webhookURL string = "webhookURL"
|
||||||
paperHeight string = "paperHeight"
|
paperWidth string = "paperWidth"
|
||||||
marginTop string = "marginTop"
|
paperHeight string = "paperHeight"
|
||||||
marginBottom string = "marginBottom"
|
marginTop string = "marginTop"
|
||||||
marginLeft string = "marginLeft"
|
marginBottom string = "marginBottom"
|
||||||
marginRight string = "marginRight"
|
marginLeft string = "marginLeft"
|
||||||
landscape string = "landscape"
|
marginRight string = "marginRight"
|
||||||
|
landscape string = "landscape"
|
||||||
|
webFontsTimeout string = "webFontsTimeout"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -59,18 +61,34 @@ 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
|
||||||
|
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 {
|
||||||
|
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 +166,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
|
||||||
|
|||||||
27
pkg/doc.go
@@ -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.github.io/gotenberg/
|
||||||
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
|
||||||
|
|||||||
113
pkg/html.go
@@ -9,64 +9,94 @@ 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWebFontsTimeout sets webFontsTimeout form field.
|
||||||
|
func (html *HTMLRequest) SetWebFontsTimeout(timeout int64) {
|
||||||
|
html.values[webFontsTimeout] = strconv.FormatInt(timeout, 10)
|
||||||
|
}
|
||||||
|
|
||||||
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 +105,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))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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(
|
||||||
Options: &HTMLOptions{
|
test.HTMLTestFilePath(t, "font.woff"),
|
||||||
HeaderFilePath: test.HTMLTestFilePath(t, "header.html"),
|
test.HTMLTestFilePath(t, "img.gif"),
|
||||||
FooterFilePath: test.HTMLTestFilePath(t, "footer.html"),
|
test.HTMLTestFilePath(t, "style.css"),
|
||||||
PaperSize: A4,
|
)
|
||||||
PaperMargins: NormalMargins,
|
require.Nil(t, err)
|
||||||
},
|
req.SetPaperSize(A4)
|
||||||
}
|
req.SetMargins(NormalMargins)
|
||||||
|
req.SetLandscape(false)
|
||||||
dirPath, err := rand.Get()
|
dirPath, err := rand.Get()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
dest := fmt.Sprintf("%s/foo.pdf", dirPath)
|
dest := fmt.Sprintf("%s/foo.pdf", dirPath)
|
||||||
@@ -36,3 +37,11 @@ func TestHTML(t *testing.T) {
|
|||||||
err = os.RemoveAll(dirPath)
|
err = os.RemoveAll(dirPath)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConcurrentHTML(t *testing.T) {
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
go func() {
|
||||||
|
TestHTML(t)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
129
pkg/markdown.go
@@ -9,73 +9,107 @@ 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWebFontsTimeout sets webFontsTimeout form field.
|
||||||
|
func (markdown *MarkdownRequest) SetWebFontsTimeout(timeout int64) {
|
||||||
|
markdown.values[webFontsTimeout] = strconv.FormatInt(timeout, 10)
|
||||||
|
}
|
||||||
|
|
||||||
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 +118,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))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,25 +13,26 @@ 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{
|
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"),
|
)
|
||||||
},
|
require.Nil(t, err)
|
||||||
AssetFilePaths: []string{
|
err = req.SetHeader(test.MarkdownTestFilePath(t, "header.html"))
|
||||||
test.HTMLTestFilePath(t, "font.woff"),
|
require.Nil(t, err)
|
||||||
test.HTMLTestFilePath(t, "img.gif"),
|
err = req.SetFooter(test.MarkdownTestFilePath(t, "footer.html"))
|
||||||
test.HTMLTestFilePath(t, "style.css"),
|
require.Nil(t, err)
|
||||||
},
|
err = req.SetAssets(
|
||||||
Options: &MarkdownOptions{
|
test.MarkdownTestFilePath(t, "font.woff"),
|
||||||
HeaderFilePath: test.MarkdownTestFilePath(t, "header.html"),
|
test.MarkdownTestFilePath(t, "img.gif"),
|
||||||
FooterFilePath: test.MarkdownTestFilePath(t, "footer.html"),
|
test.MarkdownTestFilePath(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)
|
||||||
@@ -41,3 +42,11 @@ func TestMarkdown(t *testing.T) {
|
|||||||
err = os.RemoveAll(dirPath)
|
err = os.RemoveAll(dirPath)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConcurrentMarkdown(t *testing.T) {
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
go func() {
|
||||||
|
TestMarkdown(t)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
34
pkg/merge.go
@@ -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
|
||||||
|
|||||||
@@ -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(
|
||||||
FilePaths: []string{
|
test.PDFTestFilePath(t, "gotenberg.pdf"),
|
||||||
test.PDFTestFilePath(t, "gotenberg.pdf"),
|
test.PDFTestFilePath(t, "gotenberg.pdf"),
|
||||||
test.PDFTestFilePath(t, "gotenberg.pdf"),
|
)
|
||||||
},
|
require.Nil(t, err)
|
||||||
}
|
|
||||||
dirPath, err := rand.Get()
|
dirPath, err := rand.Get()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
dest := fmt.Sprintf("%s/foo.pdf", dirPath)
|
dest := fmt.Sprintf("%s/foo.pdf", dirPath)
|
||||||
@@ -28,3 +27,11 @@ func TestMerge(t *testing.T) {
|
|||||||
err = os.RemoveAll(dirPath)
|
err = os.RemoveAll(dirPath)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConcurrentMerge(t *testing.T) {
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
go func() {
|
||||||
|
TestMerge(t)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,29 +3,34 @@ 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 +38,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 +52,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))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,11 +13,9 @@ 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(test.OfficeTestFilePath(t, "document.docx"))
|
||||||
FilePaths: []string{
|
require.Nil(t, err)
|
||||||
test.OfficeTestFilePath(t, "document.docx"),
|
req.SetLandscape(false)
|
||||||
},
|
|
||||||
}
|
|
||||||
dirPath, err := rand.Get()
|
dirPath, err := rand.Get()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
dest := fmt.Sprintf("%s/foo.pdf", dirPath)
|
dest := fmt.Sprintf("%s/foo.pdf", dirPath)
|
||||||
@@ -27,3 +25,11 @@ func TestOffice(t *testing.T) {
|
|||||||
err = os.RemoveAll(dirPath)
|
err = os.RemoveAll(dirPath)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConcurrentOffice(t *testing.T) {
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
go func() {
|
||||||
|
TestOffice(t)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
90
pkg/url.go
Normal 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
@@ -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)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,9 +2,10 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
VERSION="$1"
|
GOLANG_VERSION="$1"
|
||||||
DOCKER_USER="$2"
|
VERSION="$2"
|
||||||
DOCKER_PASSWORD="$3"
|
DOCKER_USER="$3"
|
||||||
|
DOCKER_PASSWORD="$4"
|
||||||
|
|
||||||
docker login -u "$DOCKER_USER" -p "$DOCKER_PASSWORD"
|
docker login -u "$DOCKER_USER" -p "$DOCKER_PASSWORD"
|
||||||
|
|
||||||
@@ -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
3
test/testdata/office/document.txt
vendored
Normal 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
15
test/testdata/url/footer.html
vendored
Normal 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
@@ -0,0 +1,13 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-size: 8rem;
|
||||||
|
margin: 4rem auto;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<span class="title"></span>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -16,31 +16,38 @@ 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
|
// 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
|
// 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")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +72,10 @@ func multipartForm(t *testing.T, kind string) (*bytes.Buffer, string) {
|
|||||||
_, err = io.Copy(part, file)
|
_, err = io.Copy(part, file)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
if kind == "url" {
|
||||||
|
err := writer.WriteField("remoteURL", "http://google.com")
|
||||||
|
require.Nil(t, err)
|
||||||
|
}
|
||||||
return body, writer.FormDataContentType()
|
return body, writer.FormDataContentType()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,6 +85,12 @@ func HTMLTestDirPath(t *testing.T) string {
|
|||||||
return copyDir(t, "html")
|
return copyDir(t, "html")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// URLTestDirPath creates a copy
|
||||||
|
// of "url" folder in test/testdata.
|
||||||
|
func URLTestDirPath(t *testing.T) string {
|
||||||
|
return copyDir(t, "url")
|
||||||
|
}
|
||||||
|
|
||||||
// MarkdownTestDirPath creates a copy
|
// MarkdownTestDirPath creates a copy
|
||||||
// of "markdown" folder in test/testdata.
|
// of "markdown" folder in test/testdata.
|
||||||
func MarkdownTestDirPath(t *testing.T) string {
|
func MarkdownTestDirPath(t *testing.T) string {
|
||||||
@@ -127,6 +144,12 @@ func HTMLTestFilePath(t *testing.T, filename string) string {
|
|||||||
return abs(t, "html", filename)
|
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
|
// MarkdownTestFilePath returns the absolute file path
|
||||||
// of a file in "markdown" folder in test/testdata.
|
// of a file in "markdown" folder in test/testdata.
|
||||||
func MarkdownTestFilePath(t *testing.T, filename string) string {
|
func MarkdownTestFilePath(t *testing.T, filename string) string {
|
||||||
|
|||||||