Enterprise: add dependencies for upcoming features (#18793)

* Enterprise: add dependencies for upcoming features

See enterprise issues
This commit is contained in:
Oleg Gaidarenko 2019-08-30 18:14:32 +02:00 committed by GitHub
parent d6fb48c0ff
commit 1a4be4af8c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 13594 additions and 1 deletions

4
go.mod
View File

@ -40,7 +40,9 @@ require (
github.com/hashicorp/go-plugin v0.0.0-20190220160451-3f118e8ee104
github.com/hashicorp/go-version v1.1.0
github.com/inconshreveable/log15 v0.0.0-20180818164646-67afb5ed74ec
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af
github.com/jonboulle/clockwork v0.1.0 // indirect
github.com/jung-kurt/gofpdf v1.10.1
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
github.com/klauspost/compress v1.4.1 // indirect
github.com/klauspost/cpuid v1.2.0 // indirect
@ -52,12 +54,12 @@ require (
github.com/onsi/gomega v1.5.0 // indirect
github.com/opentracing/opentracing-go v1.1.0
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pkg/errors v0.8.1
github.com/prometheus/client_golang v0.9.2
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90
github.com/prometheus/common v0.2.0
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be // indirect
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967
github.com/robfig/cron/v3 v3.0.0
github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7 // indirect
github.com/sergi/go-diff v1.0.0 // indirect
github.com/smartystreets/assertions v0.0.0-20190401211740-f487f9de1cd3 // indirect

9
go.sum
View File

@ -16,6 +16,7 @@ github.com/benbjohnson/clock v0.0.0-20161215174838-7dc76406b6d3 h1:wOysYcIdqv3Wn
github.com/benbjohnson/clock v0.0.0-20161215174838-7dc76406b6d3/go.mod h1:UMqtWQTnOe4byzwe7Zhwh8f8s+36uszN51sJrSIZlTE=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737 h1:rRISKWyXfVxvoa702s91Zl5oREZTrR3yv+tXrrX7G/g=
github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
@ -117,6 +118,9 @@ github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVY
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/jung-kurt/gofpdf v1.10.1 h1:mbprTswkr0n86clAmJ4NGCFC4fdGySCAshWzrYb3xbE=
github.com/jung-kurt/gofpdf v1.10.1/go.mod h1:s/VXv+TdctEOx2wCEguezYaR7f0OwUAd6H9VGfRkcSs=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM=
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
github.com/klauspost/compress v1.4.1 h1:8VMb5+0wMgdBykOV96DwNwKFQ+WTI4pzYURP99CcB9E=
@ -158,6 +162,7 @@ github.com/opentracing/opentracing-go v1.1.0 h1:pWlfV3Bxv7k65HYwkikxat0+s3pV4bsq
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/phpdave11/gofpdi v1.0.7/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -179,8 +184,11 @@ github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be h1:ta7tUOvsPHV
github.com/rainycape/unidecode v0.0.0-20150907023854-cb7f23ec59be/go.mod h1:MIDFMn7db1kT65GmV94GzpX9Qdi7N/pQlwb+AN8wh+Q=
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967 h1:x7xEyJDP7Hv3LVgvWhzioQqbC/KtuUhTigKlH/8ehhE=
github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k=
github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E=
github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7 h1:J4AOUcOh/t1XbQcJfkEqhzgvMJ2tDxdCVvmHxW5QXao=
github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7/go.mod h1:Oz4y6ImuOQZxynhbSXk7btjEfNBtGlj2dcaOvXl2FSM=
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
@ -227,6 +235,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90Pveol
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a h1:Igim7XhdOpBnWPuYJ70XcNpq8q3BCACtVgNfoJxOV7g=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/image v0.0.0-20190507092727-e4e5bf290fec/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=

View File

@ -1,9 +1,14 @@
package extensions
import (
// Upgrade ldapsync from cron to cron.v3 and
// remove the cron (v1) dependency
_ "github.com/crewjam/saml"
_ "github.com/gobwas/glob"
_ "github.com/jung-kurt/gofpdf"
_ "github.com/robfig/cron"
_ "github.com/robfig/cron/v3"
_ "github.com/stretchr/testify/require"
_ "gopkg.in/square/go-jose.v2"
)

1
vendor/github.com/jung-kurt/gofpdf/.gitattribute generated vendored Normal file
View File

@ -0,0 +1 @@
*.pdf binary

25
vendor/github.com/jung-kurt/gofpdf/.gitignore generated vendored Normal file
View File

@ -0,0 +1,25 @@
*.0
coverage
font/CalligrapherRegular.json
font/CalligrapherRegular.z
font/Ubuntu-*
internal/files/bin/bin
look
makefont/makefont
open
**/*.out
pdf/*.pdf
pdf.txt
private
*.sublime*
*.swp
**/*.test
.idea/
doc/body.html
doc/body.md
doc/index.html
doc/index.html.ok
coverage.html
# macOS
.DS_Store

21
vendor/github.com/jung-kurt/gofpdf/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Kurt Jung and contributors acknowledged in the documentation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

29
vendor/github.com/jung-kurt/gofpdf/Makefile generated vendored Normal file
View File

@ -0,0 +1,29 @@
all : documentation
documentation : doc/index.html doc.go README.md
cov : all
go test -v -coverprofile=coverage && go tool cover -html=coverage -o=coverage.html
check :
golint .
go vet -all .
gofmt -s -l .
goreportcard-cli -v | grep -v cyclomatic
README.md : doc/document.md
pandoc --read=markdown --write=gfm < $< > $@
doc/index.html : doc/document.md doc/html.txt
pandoc --read=markdown --write=html --template=doc/html.txt \
--metadata pagetitle="GoFPDF Document Generator" < $< > $@
doc.go : doc/document.md doc/go.awk
pandoc --read=markdown --write=plain $< | awk --assign=package_name=gofpdf --file=doc/go.awk > $@
gofmt -s -w $@
build :
go build -v
clean :
rm -f coverage.html coverage doc/index.html doc.go README.md

256
vendor/github.com/jung-kurt/gofpdf/README.md generated vendored Normal file
View File

@ -0,0 +1,256 @@
# GoFPDF document generator
[![MIT
licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/jung-kurt/gofpdf/master/LICENSE)
[![Report](https://goreportcard.com/badge/github.com/jung-kurt/gofpdf)](https://goreportcard.com/report/github.com/jung-kurt/gofpdf)
[![GoDoc](https://img.shields.io/badge/godoc-GoFPDF-blue.svg)](https://godoc.org/github.com/jung-kurt/gofpdf)
![](https://github.com/jung-kurt/gofpdf/raw/master/image/logo_gofpdf.jpg?raw=true)
Package gofpdf implements a PDF document generator with high level
support for text, drawing and images.
## Features
- UTF-8 support
- Choice of measurement unit, page format and margins
- Page header and footer management
- Automatic page breaks, line breaks, and text justification
- Inclusion of JPEG, PNG, GIF, TIFF and basic path-only SVG images
- Colors, gradients and alpha channel transparency
- Outline bookmarks
- Internal and external links
- TrueType, Type1 and encoding support
- Page compression
- Lines, Bézier curves, arcs, and ellipses
- Rotation, scaling, skewing, translation, and mirroring
- Clipping
- Document protection
- Layers
- Templates
- Barcodes
- Charting facility
- Import PDFs as templates
gofpdf has no dependencies other than the Go standard library. All tests
pass on Linux, Mac and Windows platforms.
gofpdf supports UTF-8 TrueType fonts and “right-to-left” languages. Note
that Chinese, Japanese, and Korean characters may not be included in
many general purpose fonts. For these languages, a specialized font (for
example,
[NotoSansSC](https://github.com/jsntn/webfonts/blob/master/NotoSansSC-Regular.ttf)
for simplified Chinese) can be used.
Also, support is provided to automatically translate UTF-8 runes to code
page encodings for languages that have fewer than 256 glyphs.
## Installation
To install the package on your system, run
``` shell
go get github.com/jung-kurt/gofpdf
```
Later, to receive updates, run
``` shell
go get -u -v github.com/jung-kurt/gofpdf/...
```
## Quick Start
The following Go code generates a simple PDF file.
``` go
pdf := gofpdf.New("P", "mm", "A4", "")
pdf.AddPage()
pdf.SetFont("Arial", "B", 16)
pdf.Cell(40, 10, "Hello, world")
err := pdf.OutputFileAndClose("hello.pdf")
```
See the functions in the
[fpdf\_test.go](https://github.com/jung-kurt/gofpdf/blob/master/fpdf_test.go)
file (shown as examples in this documentation) for more advanced PDF
examples.
## Errors
If an error occurs in an Fpdf method, an internal error field is set.
After this occurs, Fpdf method calls typically return without performing
any operations and the error state is retained. This error management
scheme facilitates PDF generation since individual method calls do not
need to be examined for failure; it is generally sufficient to wait
until after `Output()` is called. For the same reason, if an error
occurs in the calling application during PDF generation, it may be
desirable for the application to transfer the error to the Fpdf instance
by calling the `SetError()` method or the `SetErrorf()` method. At any
time during the life cycle of the Fpdf instance, the error state can be
determined with a call to `Ok()` or `Err()`. The error itself can be
retrieved with a call to `Error()`.
## Conversion Notes
This package is a relatively straightforward translation from the
original [FPDF](http://www.fpdf.org/) library written in PHP (despite
the caveat in the introduction to [Effective
Go](https://golang.org/doc/effective_go.html)). The API names have been
retained even though the Go idiom would suggest otherwise (for example,
`pdf.GetX()` is used rather than simply `pdf.X()`). The similarity of
the two libraries makes the original FPDF website a good source of
information. It includes a forum and FAQ.
However, some internal changes have been made. Page content is built up
using buffers (of type bytes.Buffer) rather than repeated string
concatenation. Errors are handled as explained above rather than
panicking. Output is generated through an interface of type io.Writer or
io.WriteCloser. A number of the original PHP methods behave differently
based on the type of the arguments that are passed to them; in these
cases additional methods have been exported to provide similar
functionality. Font definition files are produced in JSON rather than
PHP.
## Example PDFs
A side effect of running `go test ./...` is the production of a number
of example PDFs. These can be found in the gofpdf/pdf directory after
the tests complete.
Please note that these examples run in the context of a test. In order
run an example as a standalone application, youll need to examine
[fpdf\_test.go](https://github.com/jung-kurt/gofpdf/blob/master/fpdf_test.go)
for some helper routines, for example `exampleFilename()` and
`summary()`.
Example PDFs can be compared with reference copies in order to verify
that they have been generated as expected. This comparison will be
performed if a PDF with the same name as the example PDF is placed in
the gofpdf/pdf/reference directory and if the third argument to
`ComparePDFFiles()` in internal/example/example.go is true. (By default
it is false.) The routine that summarizes an example will look for this
file and, if found, will call `ComparePDFFiles()` to check the example
PDF for equality with its reference PDF. If differences exist between
the two files they will be printed to standard output and the test will
fail. If the reference file is missing, the comparison is considered to
succeed. In order to successfully compare two PDFs, the placement of
internal resources must be consistent and the internal creation
timestamps must be the same. To do this, the methods `SetCatalogSort()`
and `SetCreationDate()` need to be called for both files. This is done
automatically for all examples.
## Nonstandard Fonts
Nothing special is required to use the standard PDF fonts (courier,
helvetica, times, zapfdingbats) in your documents other than calling
`SetFont()`.
You should use `AddUTF8Font()` or `AddUTF8FontFromBytes()` to add a
TrueType UTF-8 encoded font. Use `RTL()` and `LTR()` methods switch
between “right-to-left” and “left-to-right” mode.
In order to use a different non-UTF-8 TrueType or Type1 font, you will
need to generate a font definition file and, if the font will be
embedded into PDFs, a compressed version of the font file. This is done
by calling the MakeFont function or using the included makefont command
line utility. To create the utility, cd into the makefont subdirectory
and run “go build”. This will produce a standalone executable named
makefont. Select the appropriate encoding file from the font
subdirectory and run the command as in the following example.
``` shell
./makefont --embed --enc=../font/cp1252.map --dst=../font ../font/calligra.ttf
```
In your PDF generation code, call `AddFont()` to load the font and, as
with the standard fonts, SetFont() to begin using it. Most examples,
including the package example, demonstrate this method. Good sources of
free, open-source fonts include [Google
Fonts](https://fonts.google.com/) and [DejaVu
Fonts](http://dejavu-fonts.org/).
## Related Packages
The [draw2d](https://github.com/llgcode/draw2d) package is a two
dimensional vector graphics library that can generate output in
different forms. It uses gofpdf for its document production mode.
## Contributing Changes
gofpdf is a global community effort and you are invited to make it even
better. If you have implemented a new feature or corrected a problem,
please consider contributing your change to the project. A contribution
that does not directly pertain to the core functionality of gofpdf
should be placed in its own directory directly beneath the `contrib`
directory.
Here are guidelines for making submissions. Your change should
- be compatible with the MIT License
- be properly documented
- be formatted with `go fmt`
- include an example in
[fpdf\_test.go](https://github.com/jung-kurt/gofpdf/blob/master/fpdf_test.go)
if appropriate
- conform to the standards of [golint](https://github.com/golang/lint)
and [go vet](https://golang.org/cmd/vet/), that is, `golint .` and
`go vet .` should not generate any warnings
- not diminish [test coverage](https://blog.golang.org/cover)
[Pull requests](https://help.github.com/articles/using-pull-requests/)
are the preferred means of accepting your changes.
## License
gofpdf is released under the MIT License. It is copyrighted by Kurt Jung
and the contributors acknowledged below.
## Acknowledgments
This packages code and documentation are closely derived from the
[FPDF](http://www.fpdf.org/) library created by Olivier Plathey, and a
number of font and image resources are copied directly from it. Bruno
Michel has provided valuable assistance with the code. Drawing support
is adapted from the FPDF geometric figures script by David Hernández
Sanz. Transparency support is adapted from the FPDF transparency script
by Martin Hall-May. Support for gradients and clipping is adapted from
FPDF scripts by Andreas Würmser. Support for outline bookmarks is
adapted from Olivier Plathey by Manuel Cornes. Layer support is adapted
from Olivier Plathey. Support for transformations is adapted from the
FPDF transformation script by Moritz Wagner and Andreas Würmser. PDF
protection is adapted from the work of Klemen Vodopivec for the FPDF
product. Lawrence Kesteloot provided code to allow an images extent to
be determined prior to placement. Support for vertical alignment within
a cell was provided by Stefan Schroeder. Ivan Daniluk generalized the
font and image loading code to use the Reader interface while
maintaining backward compatibility. Anthony Starks provided code for the
Polygon function. Robert Lillack provided the Beziergon function and
corrected some naming issues with the internal curve function. Claudio
Felber provided implementations for dashed line drawing and generalized
font loading. Stani Michiels provided support for multi-segment path
drawing with smooth line joins, line join styles, enhanced fill modes,
and has helped greatly with package presentation and tests. Templating
is adapted by Marcus Downing from the FPDF\_Tpl library created by Jan
Slabon and Setasign. Jelmer Snoeck contributed packages that generate a
variety of barcodes and help with registering images on the web. Jelmer
Snoek and Guillermo Pascual augmented the basic HTML functionality with
aligned text. Kent Quirk implemented backwards-compatible support for
reading DPI from images that support it, and for setting DPI manually
and then having it properly taken into account when calculating image
size. Paulo Coutinho provided support for static embedded fonts. Dan
Meyers added support for embedded JavaScript. David Fish added a generic
alias-replacement function to enable, among other things, table of
contents functionality. Andy Bakun identified and corrected a problem in
which the internal catalogs were not sorted stably. Paul Montag added
encoding and decoding functionality for templates, including images that
are embedded in templates; this allows templates to be stored
independently of gofpdf. Paul also added support for page boxes used in
printing PDF documents. Wojciech Matusiak added supported for word
spacing. Artem Korotkiy added support of UTF-8 fonts. Dave Barnes added
support for imported objects and templates. Brigham Thompson added
support for rounded rectangles.
## Roadmap
- Improve test coverage as reported by the coverage tool.

146
vendor/github.com/jung-kurt/gofpdf/compare.go generated vendored Normal file
View File

@ -0,0 +1,146 @@
/*
* Copyright (c) 2015 Kurt Jung (Gmail: kurt.w.jung)
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package gofpdf
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"sort"
)
type sortType struct {
length int
less func(int, int) bool
swap func(int, int)
}
func (s *sortType) Len() int {
return s.length
}
func (s *sortType) Less(i, j int) bool {
return s.less(i, j)
}
func (s *sortType) Swap(i, j int) {
s.swap(i, j)
}
func gensort(Len int, Less func(int, int) bool, Swap func(int, int)) {
sort.Sort(&sortType{length: Len, less: Less, swap: Swap})
}
func writeBytes(leadStr string, startPos int, sl []byte) {
var pos, max int
var b byte
fmt.Printf("%s %07x", leadStr, startPos)
max = len(sl)
for pos < max {
fmt.Printf(" ")
for k := 0; k < 8; k++ {
if pos < max {
fmt.Printf(" %02x", sl[pos])
} else {
fmt.Printf(" ")
}
pos++
}
}
fmt.Printf(" |")
pos = 0
for pos < max {
b = sl[pos]
if b < 32 || b >= 128 {
b = '.'
}
fmt.Printf("%c", b)
pos++
}
fmt.Printf("|\n")
}
func checkBytes(pos int, sl1, sl2 []byte, printDiff bool) (eq bool) {
eq = bytes.Equal(sl1, sl2)
if !eq && printDiff {
writeBytes("<", pos, sl1)
writeBytes(">", pos, sl2)
}
return
}
// CompareBytes compares the bytes referred to by sl1 with those referred to by
// sl2. Nil is returned if the buffers are equal, otherwise an error.
func CompareBytes(sl1, sl2 []byte, printDiff bool) (err error) {
var posStart, posEnd, len1, len2, length int
var diffs bool
len1 = len(sl1)
len2 = len(sl2)
length = len1
if length > len2 {
length = len2
}
for posStart < length-1 {
posEnd = posStart + 16
if posEnd > length {
posEnd = length
}
if !checkBytes(posStart, sl1[posStart:posEnd], sl2[posStart:posEnd], printDiff) {
diffs = true
}
posStart = posEnd
}
if diffs {
err = fmt.Errorf("documents are different")
}
return
}
// ComparePDFs reads and compares the full contents of the two specified
// readers byte-for-byte. Nil is returned if the buffers are equal, otherwise
// an error.
func ComparePDFs(rdr1, rdr2 io.Reader, printDiff bool) (err error) {
var b1, b2 *bytes.Buffer
_, err = b1.ReadFrom(rdr1)
if err == nil {
_, err = b2.ReadFrom(rdr2)
if err == nil {
err = CompareBytes(b1.Bytes(), b2.Bytes(), printDiff)
}
}
return
}
// ComparePDFFiles reads and compares the full contents of the two specified
// files byte-for-byte. Nil is returned if the file contents are equal, or if
// the second file is missing, otherwise an error.
func ComparePDFFiles(file1Str, file2Str string, printDiff bool) (err error) {
var sl1, sl2 []byte
sl1, err = ioutil.ReadFile(file1Str)
if err == nil {
sl2, err = ioutil.ReadFile(file2Str)
if err == nil {
err = CompareBytes(sl1, sl2, printDiff)
} else {
// Second file is missing; treat this as success
err = nil
}
}
return
}

734
vendor/github.com/jung-kurt/gofpdf/def.go generated vendored Normal file
View File

@ -0,0 +1,734 @@
/*
* Copyright (c) 2013-2014 Kurt Jung (Gmail: kurt.w.jung)
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package gofpdf
import (
"bytes"
"crypto/sha1"
"encoding/gob"
"encoding/json"
"fmt"
"io"
"time"
)
// Version of FPDF from which this package is derived
const (
cnFpdfVersion = "1.7"
)
type blendModeType struct {
strokeStr, fillStr, modeStr string
objNum int
}
type gradientType struct {
tp int // 2: linear, 3: radial
clr1Str, clr2Str string
x1, y1, x2, y2, r float64
objNum int
}
const (
// OrientationPortrait represents the portrait orientation.
OrientationPortrait = "portrait"
// OrientationLandscape represents the landscape orientation.
OrientationLandscape = "landscape"
)
const (
// UnitPoint represents the size unit point
UnitPoint = "pt"
// UnitMillimeter represents the size unit millimeter
UnitMillimeter = "mm"
// UnitCentimeter represents the size unit centimeter
UnitCentimeter = "cm"
// UnitInch represents the size unit inch
UnitInch = "inch"
)
const (
// PageSizeA3 represents DIN/ISO A3 page size
PageSizeA3 = "A3"
// PageSizeA4 represents DIN/ISO A4 page size
PageSizeA4 = "A4"
// PageSizeA5 represents DIN/ISO A5 page size
PageSizeA5 = "A5"
// PageSizeLetter represents US Letter page size
PageSizeLetter = "Letter"
// PageSizeLegal represents US Legal page size
PageSizeLegal = "Legal"
)
const (
// BorderNone set no border
BorderNone = ""
// BorderFull sets a full border
BorderFull = "1"
// BorderLeft sets the border on the left side
BorderLeft = "L"
// BorderTop sets the border at the top
BorderTop = "T"
// BorderRight sets the border on the right side
BorderRight = "R"
// BorderBottom sets the border on the bottom
BorderBottom = "B"
)
const (
// LineBreakNone disables linebreak
LineBreakNone = 0
// LineBreakNormal enables normal linebreak
LineBreakNormal = 1
// LineBreakBelow enables linebreak below
LineBreakBelow = 2
)
const (
// AlignLeft left aligns the cell
AlignLeft = "L"
// AlignRight right aligns the cell
AlignRight = "R"
// AlignCenter centers the cell
AlignCenter = "C"
// AlignTop aligns the cell to the top
AlignTop = "T"
// AlignBottom aligns the cell to the bottom
AlignBottom = "B"
// AlignMiddle aligns the cell to the middle
AlignMiddle = "M"
// AlignBaseline aligns the cell to the baseline
AlignBaseline = "B"
)
type colorMode int
const (
colorModeRGB colorMode = iota
colorModeSpot
colorModeCMYK
)
type colorType struct {
r, g, b float64
ir, ig, ib int
mode colorMode
spotStr string // name of current spot color
gray bool
str string
}
// SpotColorType specifies a named spot color value
type spotColorType struct {
id, objID int
val cmykColorType
}
// CMYKColorType specifies an ink-based CMYK color value
type cmykColorType struct {
c, m, y, k byte // 0% to 100%
}
// SizeType fields Wd and Ht specify the horizontal and vertical extents of a
// document element such as a page.
type SizeType struct {
Wd, Ht float64
}
// PointType fields X and Y specify the horizontal and vertical coordinates of
// a point, typically used in drawing.
type PointType struct {
X, Y float64
}
// XY returns the X and Y components of the receiver point.
func (p PointType) XY() (float64, float64) {
return p.X, p.Y
}
// ImageInfoType contains size, color and other information about an image.
// Changes to this structure should be reflected in its GobEncode and GobDecode
// methods.
type ImageInfoType struct {
data []byte
smask []byte
n int
w float64
h float64
cs string
pal []byte
bpc int
f string
dp string
trns []int
scale float64 // document scaling factor
dpi float64
i string
}
func generateImageID(info *ImageInfoType) (string, error) {
b, err := info.GobEncode()
return fmt.Sprintf("%x", sha1.Sum(b)), err
}
// GobEncode encodes the receiving image to a byte slice.
func (info *ImageInfoType) GobEncode() (buf []byte, err error) {
fields := []interface{}{info.data, info.smask, info.n, info.w, info.h, info.cs,
info.pal, info.bpc, info.f, info.dp, info.trns, info.scale, info.dpi}
w := new(bytes.Buffer)
encoder := gob.NewEncoder(w)
for j := 0; j < len(fields) && err == nil; j++ {
err = encoder.Encode(fields[j])
}
if err == nil {
buf = w.Bytes()
}
return
}
// GobDecode decodes the specified byte buffer (generated by GobEncode) into
// the receiving image.
func (info *ImageInfoType) GobDecode(buf []byte) (err error) {
fields := []interface{}{&info.data, &info.smask, &info.n, &info.w, &info.h,
&info.cs, &info.pal, &info.bpc, &info.f, &info.dp, &info.trns, &info.scale, &info.dpi}
r := bytes.NewBuffer(buf)
decoder := gob.NewDecoder(r)
for j := 0; j < len(fields) && err == nil; j++ {
err = decoder.Decode(fields[j])
}
info.i, err = generateImageID(info)
return
}
// PointConvert returns the value of pt, expressed in points (1/72 inch), as a
// value expressed in the unit of measure specified in New(). Since font
// management in Fpdf uses points, this method can help with line height
// calculations and other methods that require user units.
func (f *Fpdf) PointConvert(pt float64) (u float64) {
return pt / f.k
}
// PointToUnitConvert is an alias for PointConvert.
func (f *Fpdf) PointToUnitConvert(pt float64) (u float64) {
return pt / f.k
}
// UnitToPointConvert returns the value of u, expressed in the unit of measure
// specified in New(), as a value expressed in points (1/72 inch). Since font
// management in Fpdf uses points, this method can help with setting font sizes
// based on the sizes of other non-font page elements.
func (f *Fpdf) UnitToPointConvert(u float64) (pt float64) {
return u * f.k
}
// Extent returns the width and height of the image in the units of the Fpdf
// object.
func (info *ImageInfoType) Extent() (wd, ht float64) {
return info.Width(), info.Height()
}
// Width returns the width of the image in the units of the Fpdf object.
func (info *ImageInfoType) Width() float64 {
return info.w / (info.scale * info.dpi / 72)
}
// Height returns the height of the image in the units of the Fpdf object.
func (info *ImageInfoType) Height() float64 {
return info.h / (info.scale * info.dpi / 72)
}
// SetDpi sets the dots per inch for an image. PNG images MAY have their dpi
// set automatically, if the image specifies it. DPI information is not
// currently available automatically for JPG and GIF images, so if it's
// important to you, you can set it here. It defaults to 72 dpi.
func (info *ImageInfoType) SetDpi(dpi float64) {
info.dpi = dpi
}
type fontFileType struct {
length1, length2 int64
n int
embedded bool
content []byte
fontType string
}
type linkType struct {
x, y, wd, ht float64
link int // Auto-generated internal link ID or...
linkStr string // ...application-provided external link string
}
type intLinkType struct {
page int
y float64
}
// outlineType is used for a sidebar outline of bookmarks
type outlineType struct {
text string
level, parent, first, last, next, prev int
y float64
p int
}
// InitType is used with NewCustom() to customize an Fpdf instance.
// OrientationStr, UnitStr, SizeStr and FontDirStr correspond to the arguments
// accepted by New(). If the Wd and Ht fields of Size are each greater than
// zero, Size will be used to set the default page size rather than SizeStr. Wd
// and Ht are specified in the units of measure indicated by UnitStr.
type InitType struct {
OrientationStr string
UnitStr string
SizeStr string
Size SizeType
FontDirStr string
}
// FontLoader is used to read fonts (JSON font specification and zlib compressed font binaries)
// from arbitrary locations (e.g. files, zip files, embedded font resources).
//
// Open provides an io.Reader for the specified font file (.json or .z). The file name
// never includes a path. Open returns an error if the specified file cannot be opened.
type FontLoader interface {
Open(name string) (io.Reader, error)
}
// Pdf defines the interface used for various methods. It is implemented by the
// main FPDF instance as well as templates.
type Pdf interface {
AddFont(familyStr, styleStr, fileStr string)
AddFontFromBytes(familyStr, styleStr string, jsonFileBytes, zFileBytes []byte)
AddFontFromReader(familyStr, styleStr string, r io.Reader)
AddLayer(name string, visible bool) (layerID int)
AddLink() int
AddPage()
AddPageFormat(orientationStr string, size SizeType)
AddSpotColor(nameStr string, c, m, y, k byte)
AliasNbPages(aliasStr string)
ArcTo(x, y, rx, ry, degRotate, degStart, degEnd float64)
Arc(x, y, rx, ry, degRotate, degStart, degEnd float64, styleStr string)
BeginLayer(id int)
Beziergon(points []PointType, styleStr string)
Bookmark(txtStr string, level int, y float64)
CellFormat(w, h float64, txtStr, borderStr string, ln int, alignStr string, fill bool, link int, linkStr string)
Cellf(w, h float64, fmtStr string, args ...interface{})
Cell(w, h float64, txtStr string)
Circle(x, y, r float64, styleStr string)
ClearError()
ClipCircle(x, y, r float64, outline bool)
ClipEllipse(x, y, rx, ry float64, outline bool)
ClipEnd()
ClipPolygon(points []PointType, outline bool)
ClipRect(x, y, w, h float64, outline bool)
ClipRoundedRect(x, y, w, h, r float64, outline bool)
ClipText(x, y float64, txtStr string, outline bool)
Close()
ClosePath()
CreateTemplateCustom(corner PointType, size SizeType, fn func(*Tpl)) Template
CreateTemplate(fn func(*Tpl)) Template
CurveBezierCubicTo(cx0, cy0, cx1, cy1, x, y float64)
CurveBezierCubic(x0, y0, cx0, cy0, cx1, cy1, x1, y1 float64, styleStr string)
CurveCubic(x0, y0, cx0, cy0, x1, y1, cx1, cy1 float64, styleStr string)
CurveTo(cx, cy, x, y float64)
Curve(x0, y0, cx, cy, x1, y1 float64, styleStr string)
DrawPath(styleStr string)
Ellipse(x, y, rx, ry, degRotate float64, styleStr string)
EndLayer()
Err() bool
Error() error
GetAlpha() (alpha float64, blendModeStr string)
GetAutoPageBreak() (auto bool, margin float64)
GetCellMargin() float64
GetConversionRatio() float64
GetDrawColor() (int, int, int)
GetDrawSpotColor() (name string, c, m, y, k byte)
GetFillColor() (int, int, int)
GetFillSpotColor() (name string, c, m, y, k byte)
GetFontDesc(familyStr, styleStr string) FontDescType
GetFontSize() (ptSize, unitSize float64)
GetImageInfo(imageStr string) (info *ImageInfoType)
GetLineWidth() float64
GetMargins() (left, top, right, bottom float64)
GetPageSizeStr(sizeStr string) (size SizeType)
GetPageSize() (width, height float64)
GetStringWidth(s string) float64
GetTextColor() (int, int, int)
GetTextSpotColor() (name string, c, m, y, k byte)
GetX() float64
GetXY() (float64, float64)
GetY() float64
HTMLBasicNew() (html HTMLBasicType)
Image(imageNameStr string, x, y, w, h float64, flow bool, tp string, link int, linkStr string)
ImageOptions(imageNameStr string, x, y, w, h float64, flow bool, options ImageOptions, link int, linkStr string)
ImageTypeFromMime(mimeStr string) (tp string)
LinearGradient(x, y, w, h float64, r1, g1, b1, r2, g2, b2 int, x1, y1, x2, y2 float64)
LineTo(x, y float64)
Line(x1, y1, x2, y2 float64)
LinkString(x, y, w, h float64, linkStr string)
Link(x, y, w, h float64, link int)
Ln(h float64)
MoveTo(x, y float64)
MultiCell(w, h float64, txtStr, borderStr, alignStr string, fill bool)
Ok() bool
OpenLayerPane()
OutputAndClose(w io.WriteCloser) error
OutputFileAndClose(fileStr string) error
Output(w io.Writer) error
PageCount() int
PageNo() int
PageSize(pageNum int) (wd, ht float64, unitStr string)
PointConvert(pt float64) (u float64)
PointToUnitConvert(pt float64) (u float64)
Polygon(points []PointType, styleStr string)
RadialGradient(x, y, w, h float64, r1, g1, b1, r2, g2, b2 int, x1, y1, x2, y2, r float64)
RawWriteBuf(r io.Reader)
RawWriteStr(str string)
Rect(x, y, w, h float64, styleStr string)
RegisterAlias(alias, replacement string)
RegisterImage(fileStr, tp string) (info *ImageInfoType)
RegisterImageOptions(fileStr string, options ImageOptions) (info *ImageInfoType)
RegisterImageOptionsReader(imgName string, options ImageOptions, r io.Reader) (info *ImageInfoType)
RegisterImageReader(imgName, tp string, r io.Reader) (info *ImageInfoType)
SetAcceptPageBreakFunc(fnc func() bool)
SetAlpha(alpha float64, blendModeStr string)
SetAuthor(authorStr string, isUTF8 bool)
SetAutoPageBreak(auto bool, margin float64)
SetCatalogSort(flag bool)
SetCellMargin(margin float64)
SetCompression(compress bool)
SetCreationDate(tm time.Time)
SetCreator(creatorStr string, isUTF8 bool)
SetDashPattern(dashArray []float64, dashPhase float64)
SetDisplayMode(zoomStr, layoutStr string)
SetDrawColor(r, g, b int)
SetDrawSpotColor(nameStr string, tint byte)
SetError(err error)
SetErrorf(fmtStr string, args ...interface{})
SetFillColor(r, g, b int)
SetFillSpotColor(nameStr string, tint byte)
SetFont(familyStr, styleStr string, size float64)
SetFontLoader(loader FontLoader)
SetFontLocation(fontDirStr string)
SetFontSize(size float64)
SetFontStyle(styleStr string)
SetFontUnitSize(size float64)
SetFooterFunc(fnc func())
SetFooterFuncLpi(fnc func(lastPage bool))
SetHeaderFunc(fnc func())
SetHeaderFuncMode(fnc func(), homeMode bool)
SetHomeXY()
SetJavascript(script string)
SetKeywords(keywordsStr string, isUTF8 bool)
SetLeftMargin(margin float64)
SetLineCapStyle(styleStr string)
SetLineJoinStyle(styleStr string)
SetLineWidth(width float64)
SetLink(link int, y float64, page int)
SetMargins(left, top, right float64)
SetPageBoxRec(t string, pb PageBox)
SetPageBox(t string, x, y, wd, ht float64)
SetPage(pageNum int)
SetProtection(actionFlag byte, userPassStr, ownerPassStr string)
SetRightMargin(margin float64)
SetSubject(subjectStr string, isUTF8 bool)
SetTextColor(r, g, b int)
SetTextSpotColor(nameStr string, tint byte)
SetTitle(titleStr string, isUTF8 bool)
SetTopMargin(margin float64)
SetUnderlineThickness(thickness float64)
SetXmpMetadata(xmpStream []byte)
SetX(x float64)
SetXY(x, y float64)
SetY(y float64)
SplitLines(txt []byte, w float64) [][]byte
String() string
SVGBasicWrite(sb *SVGBasicType, scale float64)
Text(x, y float64, txtStr string)
TransformBegin()
TransformEnd()
TransformMirrorHorizontal(x float64)
TransformMirrorLine(angle, x, y float64)
TransformMirrorPoint(x, y float64)
TransformMirrorVertical(y float64)
TransformRotate(angle, x, y float64)
TransformScale(scaleWd, scaleHt, x, y float64)
TransformScaleX(scaleWd, x, y float64)
TransformScaleXY(s, x, y float64)
TransformScaleY(scaleHt, x, y float64)
TransformSkew(angleX, angleY, x, y float64)
TransformSkewX(angleX, x, y float64)
TransformSkewY(angleY, x, y float64)
Transform(tm TransformMatrix)
TransformTranslate(tx, ty float64)
TransformTranslateX(tx float64)
TransformTranslateY(ty float64)
UnicodeTranslatorFromDescriptor(cpStr string) (rep func(string) string)
UnitToPointConvert(u float64) (pt float64)
UseTemplateScaled(t Template, corner PointType, size SizeType)
UseTemplate(t Template)
WriteAligned(width, lineHeight float64, textStr, alignStr string)
Writef(h float64, fmtStr string, args ...interface{})
Write(h float64, txtStr string)
WriteLinkID(h float64, displayStr string, linkID int)
WriteLinkString(h float64, displayStr, targetStr string)
}
// PageBox defines the coordinates and extent of the various page box types
type PageBox struct {
SizeType
PointType
}
// Fpdf is the principal structure for creating a single PDF document
type Fpdf struct {
isCurrentUTF8 bool // is current font used in utf-8 mode
isRTL bool // is is right to left mode enabled
page int // current page number
n int // current object number
offsets []int // array of object offsets
templates map[string]Template // templates used in this document
templateObjects map[string]int // template object IDs within this document
importedObjs map[string][]byte // imported template objects (gofpdi)
importedObjPos map[string]map[int]string // imported template objects hashes and their positions (gofpdi)
importedTplObjs map[string]string // imported template names and IDs (hashed) (gofpdi)
importedTplIDs map[string]int // imported template ids hash to object id int (gofpdi)
buffer fmtBuffer // buffer holding in-memory PDF
pages []*bytes.Buffer // slice[page] of page content; 1-based
state int // current document state
compress bool // compression flag
k float64 // scale factor (number of points in user unit)
defOrientation string // default orientation
curOrientation string // current orientation
stdPageSizes map[string]SizeType // standard page sizes
defPageSize SizeType // default page size
defPageBoxes map[string]PageBox // default page size
curPageSize SizeType // current page size
pageSizes map[int]SizeType // used for pages with non default sizes or orientations
pageBoxes map[int]map[string]PageBox // used to define the crop, trim, bleed and art boxes
unitStr string // unit of measure for all rendered objects except fonts
wPt, hPt float64 // dimensions of current page in points
w, h float64 // dimensions of current page in user unit
lMargin float64 // left margin
tMargin float64 // top margin
rMargin float64 // right margin
bMargin float64 // page break margin
cMargin float64 // cell margin
x, y float64 // current position in user unit
lasth float64 // height of last printed cell
lineWidth float64 // line width in user unit
fontpath string // path containing fonts
fontLoader FontLoader // used to load font files from arbitrary locations
coreFonts map[string]bool // array of core font names
fonts map[string]fontDefType // array of used fonts
fontFiles map[string]fontFileType // array of font files
diffs []string // array of encoding differences
fontFamily string // current font family
fontStyle string // current font style
underline bool // underlining flag
currentFont fontDefType // current font info
fontSizePt float64 // current font size in points
fontSize float64 // current font size in user unit
ws float64 // word spacing
images map[string]*ImageInfoType // array of used images
aliasMap map[string]string // map of alias->replacement
pageLinks [][]linkType // pageLinks[page][link], both 1-based
links []intLinkType // array of internal links
outlines []outlineType // array of outlines
outlineRoot int // root of outlines
autoPageBreak bool // automatic page breaking
acceptPageBreak func() bool // returns true to accept page break
pageBreakTrigger float64 // threshold used to trigger page breaks
inHeader bool // flag set when processing header
headerFnc func() // function provided by app and called to write header
headerHomeMode bool // set position to home after headerFnc is called
inFooter bool // flag set when processing footer
footerFnc func() // function provided by app and called to write footer
footerFncLpi func(bool) // function provided by app and called to write footer with last page flag
zoomMode string // zoom display mode
layoutMode string // layout display mode
xmp []byte // XMP metadata
producer string // producer
title string // title
subject string // subject
author string // author
keywords string // keywords
creator string // creator
creationDate time.Time // override for dcoument CreationDate value
aliasNbPagesStr string // alias for total number of pages
pdfVersion string // PDF version number
fontDirStr string // location of font definition files
capStyle int // line cap style: butt 0, round 1, square 2
joinStyle int // line segment join style: miter 0, round 1, bevel 2
dashArray []float64 // dash array
dashPhase float64 // dash phase
blendList []blendModeType // slice[idx] of alpha transparency modes, 1-based
blendMap map[string]int // map into blendList
blendMode string // current blend mode
alpha float64 // current transpacency
gradientList []gradientType // slice[idx] of gradient records
clipNest int // Number of active clipping contexts
transformNest int // Number of active transformation contexts
err error // Set if error occurs during life cycle of instance
protect protectType // document protection structure
layer layerRecType // manages optional layers in document
catalogSort bool // sort resource catalogs in document
nJs int // JavaScript object number
javascript *string // JavaScript code to include in the PDF
colorFlag bool // indicates whether fill and text colors are different
color struct {
// Composite values of colors
draw, fill, text colorType
}
spotColorMap map[string]spotColorType // Map of named ink-based colors
userUnderlineThickness float64 // A custom user underline thickness multiplier.
}
type encType struct {
uv int
name string
}
type encListType [256]encType
type fontBoxType struct {
Xmin, Ymin, Xmax, Ymax int
}
// Font flags for FontDescType.Flags as defined in the pdf specification.
const (
// FontFlagFixedPitch is set if all glyphs have the same width (as
// opposed to proportional or variable-pitch fonts, which have
// different widths).
FontFlagFixedPitch = 1 << 0
// FontFlagSerif is set if glyphs have serifs, which are short
// strokes drawn at an angle on the top and bottom of glyph stems.
// (Sans serif fonts do not have serifs.)
FontFlagSerif = 1 << 1
// FontFlagSymbolic is set if font contains glyphs outside the
// Adobe standard Latin character set. This flag and the
// Nonsymbolic flag shall not both be set or both be clear.
FontFlagSymbolic = 1 << 2
// FontFlagScript is set if glyphs resemble cursive handwriting.
FontFlagScript = 1 << 3
// FontFlagNonsymbolic is set if font uses the Adobe standard
// Latin character set or a subset of it.
FontFlagNonsymbolic = 1 << 5
// FontFlagItalic is set if glyphs have dominant vertical strokes
// that are slanted.
FontFlagItalic = 1 << 6
// FontFlagAllCap is set if font contains no lowercase letters;
// typically used for display purposes, such as for titles or
// headlines.
FontFlagAllCap = 1 << 16
// SmallCap is set if font contains both uppercase and lowercase
// letters. The uppercase letters are similar to those in the
// regular version of the same typeface family. The glyphs for the
// lowercase letters have the same shapes as the corresponding
// uppercase letters, but they are sized and their proportions
// adjusted so that they have the same size and stroke weight as
// lowercase glyphs in the same typeface family.
SmallCap = 1 << 18
// ForceBold determines whether bold glyphs shall be painted with
// extra pixels even at very small text sizes by a conforming
// reader. If the ForceBold flag is set, features of bold glyphs
// may be thickened at small text sizes.
ForceBold = 1 << 18
)
// FontDescType (font descriptor) specifies metrics and other
// attributes of a font, as distinct from the metrics of individual
// glyphs (as defined in the pdf specification).
type FontDescType struct {
// The maximum height above the baseline reached by glyphs in this
// font (for example for "S"). The height of glyphs for accented
// characters shall be excluded.
Ascent int
// The maximum depth below the baseline reached by glyphs in this
// font. The value shall be a negative number.
Descent int
// The vertical coordinate of the top of flat capital letters,
// measured from the baseline (for example "H").
CapHeight int
// A collection of flags defining various characteristics of the
// font. (See the FontFlag* constants.)
Flags int
// A rectangle, expressed in the glyph coordinate system, that
// shall specify the font bounding box. This should be the smallest
// rectangle enclosing the shape that would result if all of the
// glyphs of the font were placed with their origins coincident
// and then filled.
FontBBox fontBoxType
// The angle, expressed in degrees counterclockwise from the
// vertical, of the dominant vertical strokes of the font. (The
// 9-oclock position is 90 degrees, and the 3-oclock position
// is 90 degrees.) The value shall be negative for fonts that
// slope to the right, as almost all italic fonts do.
ItalicAngle int
// The thickness, measured horizontally, of the dominant vertical
// stems of glyphs in the font.
StemV int
// The width to use for character codes whose widths are not
// specified in a font dictionarys Widths array. This shall have
// a predictable effect only if all such codes map to glyphs whose
// actual widths are the same as the value of the MissingWidth
// entry. (Default value: 0.)
MissingWidth int
}
type fontDefType struct {
Tp string // "Core", "TrueType", ...
Name string // "Courier-Bold", ...
Desc FontDescType // Font descriptor
Up int // Underline position
Ut int // Underline thickness
Cw []int // Character width by ordinal
Enc string // "cp1252", ...
Diff string // Differences from reference encoding
File string // "Redressed.z"
Size1, Size2 int // Type1 values
OriginalSize int // Size of uncompressed font file
N int // Set by font loader
DiffN int // Position of diff in app array, set by font loader
i string // 1-based position in font list, set by font loader, not this program
utf8File *utf8FontFile // UTF-8 font
usedRunes map[int]int // Array of used runes
}
// generateFontID generates a font Id from the font definition
func generateFontID(fdt fontDefType) (string, error) {
// file can be different if generated in different instance
fdt.File = ""
b, err := json.Marshal(&fdt)
return fmt.Sprintf("%x", sha1.Sum(b)), err
}
type fontInfoType struct {
Data []byte
File string
OriginalSize int
FontName string
Bold bool
IsFixedPitch bool
UnderlineThickness int
UnderlinePosition int
Widths []int
Size1, Size2 uint32
Desc FontDescType
}

268
vendor/github.com/jung-kurt/gofpdf/doc.go generated vendored Normal file
View File

@ -0,0 +1,268 @@
/*
Package gofpdf implements a PDF document generator with high level
support for text, drawing and images.
Features
- UTF-8 support
- Choice of measurement unit, page format and margins
- Page header and footer management
- Automatic page breaks, line breaks, and text justification
- Inclusion of JPEG, PNG, GIF, TIFF and basic path-only SVG images
- Colors, gradients and alpha channel transparency
- Outline bookmarks
- Internal and external links
- TrueType, Type1 and encoding support
- Page compression
- Lines, Bézier curves, arcs, and ellipses
- Rotation, scaling, skewing, translation, and mirroring
- Clipping
- Document protection
- Layers
- Templates
- Barcodes
- Charting facility
- Import PDFs as templates
gofpdf has no dependencies other than the Go standard library. All tests
pass on Linux, Mac and Windows platforms.
gofpdf supports UTF-8 TrueType fonts and right-to-left languages. Note
that Chinese, Japanese, and Korean characters may not be included in
many general purpose fonts. For these languages, a specialized font (for
example, NotoSansSC for simplified Chinese) can be used.
Also, support is provided to automatically translate UTF-8 runes to code
page encodings for languages that have fewer than 256 glyphs.
Installation
To install the package on your system, run
go get github.com/jung-kurt/gofpdf
Later, to receive updates, run
go get -u -v github.com/jung-kurt/gofpdf/...
Quick Start
The following Go code generates a simple PDF file.
pdf := gofpdf.New("P", "mm", "A4", "")
pdf.AddPage()
pdf.SetFont("Arial", "B", 16)
pdf.Cell(40, 10, "Hello, world")
err := pdf.OutputFileAndClose("hello.pdf")
See the functions in the fpdf_test.go file (shown as examples in this
documentation) for more advanced PDF examples.
Errors
If an error occurs in an Fpdf method, an internal error field is set.
After this occurs, Fpdf method calls typically return without performing
any operations and the error state is retained. This error management
scheme facilitates PDF generation since individual method calls do not
need to be examined for failure; it is generally sufficient to wait
until after Output() is called. For the same reason, if an error occurs
in the calling application during PDF generation, it may be desirable
for the application to transfer the error to the Fpdf instance by
calling the SetError() method or the SetErrorf() method. At any time
during the life cycle of the Fpdf instance, the error state can be
determined with a call to Ok() or Err(). The error itself can be
retrieved with a call to Error().
Conversion Notes
This package is a relatively straightforward translation from the
original FPDF library written in PHP (despite the caveat in the
introduction to Effective Go). The API names have been retained even
though the Go idiom would suggest otherwise (for example, pdf.GetX() is
used rather than simply pdf.X()). The similarity of the two libraries
makes the original FPDF website a good source of information. It
includes a forum and FAQ.
However, some internal changes have been made. Page content is built up
using buffers (of type bytes.Buffer) rather than repeated string
concatenation. Errors are handled as explained above rather than
panicking. Output is generated through an interface of type io.Writer or
io.WriteCloser. A number of the original PHP methods behave differently
based on the type of the arguments that are passed to them; in these
cases additional methods have been exported to provide similar
functionality. Font definition files are produced in JSON rather than
PHP.
Example PDFs
A side effect of running go test ./... is the production of a number of
example PDFs. These can be found in the gofpdf/pdf directory after the
tests complete.
Please note that these examples run in the context of a test. In order
run an example as a standalone application, youll need to examine
fpdf_test.go for some helper routines, for example exampleFilename() and
summary().
Example PDFs can be compared with reference copies in order to verify
that they have been generated as expected. This comparison will be
performed if a PDF with the same name as the example PDF is placed in
the gofpdf/pdf/reference directory and if the third argument to
ComparePDFFiles() in internal/example/example.go is true. (By default it
is false.) The routine that summarizes an example will look for this
file and, if found, will call ComparePDFFiles() to check the example PDF
for equality with its reference PDF. If differences exist between the
two files they will be printed to standard output and the test will
fail. If the reference file is missing, the comparison is considered to
succeed. In order to successfully compare two PDFs, the placement of
internal resources must be consistent and the internal creation
timestamps must be the same. To do this, the methods SetCatalogSort()
and SetCreationDate() need to be called for both files. This is done
automatically for all examples.
Nonstandard Fonts
Nothing special is required to use the standard PDF fonts (courier,
helvetica, times, zapfdingbats) in your documents other than calling
SetFont().
You should use AddUTF8Font() or AddUTF8FontFromBytes() to add a TrueType
UTF-8 encoded font. Use RTL() and LTR() methods switch between
right-to-left and left-to-right mode.
In order to use a different non-UTF-8 TrueType or Type1 font, you will
need to generate a font definition file and, if the font will be
embedded into PDFs, a compressed version of the font file. This is done
by calling the MakeFont function or using the included makefont command
line utility. To create the utility, cd into the makefont subdirectory
and run go build. This will produce a standalone executable named
makefont. Select the appropriate encoding file from the font
subdirectory and run the command as in the following example.
./makefont --embed --enc=../font/cp1252.map --dst=../font ../font/calligra.ttf
In your PDF generation code, call AddFont() to load the font and, as
with the standard fonts, SetFont() to begin using it. Most examples,
including the package example, demonstrate this method. Good sources of
free, open-source fonts include Google Fonts and DejaVu Fonts.
Related Packages
The draw2d package is a two dimensional vector graphics library that can
generate output in different forms. It uses gofpdf for its document
production mode.
Contributing Changes
gofpdf is a global community effort and you are invited to make it even
better. If you have implemented a new feature or corrected a problem,
please consider contributing your change to the project. A contribution
that does not directly pertain to the core functionality of gofpdf
should be placed in its own directory directly beneath the contrib
directory.
Here are guidelines for making submissions. Your change should
- be compatible with the MIT License
- be properly documented
- be formatted with go fmt
- include an example in fpdf_test.go if appropriate
- conform to the standards of golint and go vet, that is, golint . and
go vet . should not generate any warnings
- not diminish test coverage
Pull requests are the preferred means of accepting your changes.
License
gofpdf is released under the MIT License. It is copyrighted by Kurt Jung
and the contributors acknowledged below.
Acknowledgments
This packages code and documentation are closely derived from the FPDF
library created by Olivier Plathey, and a number of font and image
resources are copied directly from it. Bruno Michel has provided
valuable assistance with the code. Drawing support is adapted from the
FPDF geometric figures script by David Hernández Sanz. Transparency
support is adapted from the FPDF transparency script by Martin Hall-May.
Support for gradients and clipping is adapted from FPDF scripts by
Andreas Würmser. Support for outline bookmarks is adapted from Olivier
Plathey by Manuel Cornes. Layer support is adapted from Olivier Plathey.
Support for transformations is adapted from the FPDF transformation
script by Moritz Wagner and Andreas Würmser. PDF protection is adapted
from the work of Klemen Vodopivec for the FPDF product. Lawrence
Kesteloot provided code to allow an images extent to be determined
prior to placement. Support for vertical alignment within a cell was
provided by Stefan Schroeder. Ivan Daniluk generalized the font and
image loading code to use the Reader interface while maintaining
backward compatibility. Anthony Starks provided code for the Polygon
function. Robert Lillack provided the Beziergon function and corrected
some naming issues with the internal curve function. Claudio Felber
provided implementations for dashed line drawing and generalized font
loading. Stani Michiels provided support for multi-segment path drawing
with smooth line joins, line join styles, enhanced fill modes, and has
helped greatly with package presentation and tests. Templating is
adapted by Marcus Downing from the FPDF_Tpl library created by Jan
Slabon and Setasign. Jelmer Snoeck contributed packages that generate a
variety of barcodes and help with registering images on the web. Jelmer
Snoek and Guillermo Pascual augmented the basic HTML functionality with
aligned text. Kent Quirk implemented backwards-compatible support for
reading DPI from images that support it, and for setting DPI manually
and then having it properly taken into account when calculating image
size. Paulo Coutinho provided support for static embedded fonts. Dan
Meyers added support for embedded JavaScript. David Fish added a generic
alias-replacement function to enable, among other things, table of
contents functionality. Andy Bakun identified and corrected a problem in
which the internal catalogs were not sorted stably. Paul Montag added
encoding and decoding functionality for templates, including images that
are embedded in templates; this allows templates to be stored
independently of gofpdf. Paul also added support for page boxes used in
printing PDF documents. Wojciech Matusiak added supported for word
spacing. Artem Korotkiy added support of UTF-8 fonts. Dave Barnes added
support for imported objects and templates. Brigham Thompson added
support for rounded rectangles.
Roadmap
- Improve test coverage as reported by the coverage tool.
*/
package gofpdf

559
vendor/github.com/jung-kurt/gofpdf/embedded.go generated vendored Normal file
View File

@ -0,0 +1,559 @@
/*
* Copyright (c) 2014 Kurt Jung (Gmail: kurt.w.jung)
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package gofpdf
// Embedded standard fonts
import (
"strings"
)
var embeddedFontList = map[string]string{
"courierBI": `{"Tp":"Core","Name":"Courier-BoldOblique","Up":-100,"Ut":50,"I":256,"Cw":[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600]}`,
"courierB": `{"Tp":"Core","Name":"Courier-Bold","Up":-100,"Ut":50,"I":256,"Cw":[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600]}`,
"courierI": `{"Tp":"Core","Name":"Courier-Oblique","Up":-100,"Ut":50,"I":256,"Cw":[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600]}`,
"courier": `{"Tp":"Core","Name":"Courier","Up":-100,"Ut":50,"I":256,"Cw":[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600]}`,
"helveticaBI": `{"Tp":"Core","Name":"Helvetica-BoldOblique","Up":-100,"Ut":50,"Cw":[278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,333,474,556,556,889,722,238,333,333,389,584,278,333,278,278,556,556,556,556,556,556,556,556,556,556,333,333,584,584,584,611,975,722,722,722,722,667,611,778,722,278,556,722,611,833,722,778,667,778,722,667,611,722,667,944,667,667,611,333,278,333,584,556,333,556,611,556,611,556,333,611,611,278,278,556,278,889,611,611,611,611,389,556,333,611,556,778,556,556,500,389,280,389,584,350,556,350,278,556,500,1000,556,556,333,1000,667,333,1000,350,611,350,350,278,278,500,500,350,556,1000,333,1000,556,333,944,350,500,667,278,333,556,556,556,556,280,556,333,737,370,556,584,333,737,333,400,584,333,333,333,611,556,278,333,333,365,556,834,834,834,611,722,722,722,722,722,722,1000,722,667,667,667,667,278,278,278,278,722,722,778,778,778,778,778,584,778,722,722,722,722,667,667,611,556,556,556,556,556,556,889,556,556,556,556,556,278,278,278,278,611,611,611,611,611,611,611,584,611,611,611,611,611,556,611,556]}`,
"helveticaB": `{"Tp":"Core","Name":"Helvetica-Bold","Up":-100,"Ut":50,"Cw":[278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,333,474,556,556,889,722,238,333,333,389,584,278,333,278,278,556,556,556,556,556,556,556,556,556,556,333,333,584,584,584,611,975,722,722,722,722,667,611,778,722,278,556,722,611,833,722,778,667,778,722,667,611,722,667,944,667,667,611,333,278,333,584,556,333,556,611,556,611,556,333,611,611,278,278,556,278,889,611,611,611,611,389,556,333,611,556,778,556,556,500,389,280,389,584,350,556,350,278,556,500,1000,556,556,333,1000,667,333,1000,350,611,350,350,278,278,500,500,350,556,1000,333,1000,556,333,944,350,500,667,278,333,556,556,556,556,280,556,333,737,370,556,584,333,737,333,400,584,333,333,333,611,556,278,333,333,365,556,834,834,834,611,722,722,722,722,722,722,1000,722,667,667,667,667,278,278,278,278,722,722,778,778,778,778,778,584,778,722,722,722,722,667,667,611,556,556,556,556,556,556,889,556,556,556,556,556,278,278,278,278,611,611,611,611,611,611,611,584,611,611,611,611,611,556,611,556]}`,
"helveticaI": `{"Tp":"Core","Name":"Helvetica-Oblique","Up":-100,"Ut":50,"Cw":[278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,355,556,556,889,667,191,333,333,389,584,278,333,278,278,556,556,556,556,556,556,556,556,556,556,278,278,584,584,584,556,1015,667,667,722,722,667,611,778,722,278,500,667,556,833,722,778,667,778,722,667,611,722,667,944,667,667,611,278,278,278,469,556,333,556,556,500,556,556,278,556,556,222,222,500,222,833,556,556,556,556,333,500,278,556,500,722,500,500,500,334,260,334,584,350,556,350,222,556,333,1000,556,556,333,1000,667,333,1000,350,611,350,350,222,222,333,333,350,556,1000,333,1000,500,333,944,350,500,667,278,333,556,556,556,556,260,556,333,737,370,556,584,333,737,333,400,584,333,333,333,556,537,278,333,333,365,556,834,834,834,611,667,667,667,667,667,667,1000,722,667,667,667,667,278,278,278,278,722,722,778,778,778,778,778,584,778,722,722,722,722,667,667,611,556,556,556,556,556,556,889,500,556,556,556,556,278,278,278,278,556,556,556,556,556,556,556,584,611,556,556,556,556,500,556,500]}`,
"helvetica": `{"Tp":"Core","Name":"Helvetica","Up":-100,"Ut":50,"Cw":[278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,355,556,556,889,667,191,333,333,389,584,278,333,278,278,556,556,556,556,556,556,556,556,556,556,278,278,584,584,584,556,1015,667,667,722,722,667,611,778,722,278,500,667,556,833,722,778,667,778,722,667,611,722,667,944,667,667,611,278,278,278,469,556,333,556,556,500,556,556,278,556,556,222,222,500,222,833,556,556,556,556,333,500,278,556,500,722,500,500,500,334,260,334,584,350,556,350,222,556,333,1000,556,556,333,1000,667,333,1000,350,611,350,350,222,222,333,333,350,556,1000,333,1000,500,333,944,350,500,667,278,333,556,556,556,556,260,556,333,737,370,556,584,333,737,333,400,584,333,333,333,556,537,278,333,333,365,556,834,834,834,611,667,667,667,667,667,667,1000,722,667,667,667,667,278,278,278,278,722,722,778,778,778,778,778,584,778,722,722,722,722,667,667,611,556,556,556,556,556,556,889,500,556,556,556,556,278,278,278,278,556,556,556,556,556,556,556,584,611,556,556,556,556,500,556,500]}`,
"timesBI": `{"Tp":"Core","Name":"Times-BoldItalic","Up":-100,"Ut":50,"Cw":[250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,389,555,500,500,833,778,278,333,333,500,570,250,333,250,278,500,500,500,500,500,500,500,500,500,500,333,333,570,570,570,500,832,667,667,667,722,667,667,722,778,389,500,667,611,889,722,722,611,722,667,556,611,722,667,889,667,611,611,333,278,333,570,500,333,500,500,444,500,444,333,500,556,278,278,500,278,778,556,500,500,500,389,389,278,556,444,667,500,444,389,348,220,348,570,350,500,350,333,500,500,1000,500,500,333,1000,556,333,944,350,611,350,350,333,333,500,500,350,500,1000,333,1000,389,333,722,350,389,611,250,389,500,500,500,500,220,500,333,747,266,500,606,333,747,333,400,570,300,300,333,576,500,250,333,300,300,500,750,750,750,500,667,667,667,667,667,667,944,667,667,667,667,667,389,389,389,389,722,722,722,722,722,722,722,570,722,722,722,722,722,611,611,500,500,500,500,500,500,500,722,444,444,444,444,444,278,278,278,278,500,556,500,500,500,500,500,570,500,556,556,556,556,444,500,444]}`,
"timesB": `{"Tp":"Core","Name":"Times-Bold","Up":-100,"Ut":50,"Cw":[250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,333,555,500,500,1000,833,278,333,333,500,570,250,333,250,278,500,500,500,500,500,500,500,500,500,500,333,333,570,570,570,500,930,722,667,722,722,667,611,778,778,389,500,778,667,944,722,778,611,778,722,556,667,722,722,1000,722,722,667,333,278,333,581,500,333,500,556,444,556,444,333,500,556,278,333,556,278,833,556,500,556,556,444,389,333,556,500,722,500,500,444,394,220,394,520,350,500,350,333,500,500,1000,500,500,333,1000,556,333,1000,350,667,350,350,333,333,500,500,350,500,1000,333,1000,389,333,722,350,444,722,250,333,500,500,500,500,220,500,333,747,300,500,570,333,747,333,400,570,300,300,333,556,540,250,333,300,330,500,750,750,750,500,722,722,722,722,722,722,1000,722,667,667,667,667,389,389,389,389,722,722,778,778,778,778,778,570,778,722,722,722,722,722,611,556,500,500,500,500,500,500,722,444,444,444,444,444,278,278,278,278,500,556,500,500,500,500,500,570,500,556,556,556,556,500,556,500]}`,
"timesI": `{"Tp":"Core","Name":"Times-Italic","Up":-100,"Ut":50,"Cw":[250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,333,420,500,500,833,778,214,333,333,500,675,250,333,250,278,500,500,500,500,500,500,500,500,500,500,333,333,675,675,675,500,920,611,611,667,722,611,611,722,722,333,444,667,556,833,667,722,611,722,611,500,556,722,611,833,611,556,556,389,278,389,422,500,333,500,500,444,500,444,278,500,500,278,278,444,278,722,500,500,500,500,389,389,278,500,444,667,444,444,389,400,275,400,541,350,500,350,333,500,556,889,500,500,333,1000,500,333,944,350,556,350,350,333,333,556,556,350,500,889,333,980,389,333,667,350,389,556,250,389,500,500,500,500,275,500,333,760,276,500,675,333,760,333,400,675,300,300,333,500,523,250,333,300,310,500,750,750,750,500,611,611,611,611,611,611,889,667,611,611,611,611,333,333,333,333,722,667,722,722,722,722,722,675,722,722,722,722,722,556,611,500,500,500,500,500,500,500,667,444,444,444,444,444,278,278,278,278,500,500,500,500,500,500,500,675,500,500,500,500,500,444,500,444]}`,
"times": `{"Tp":"Core","Name":"Times-Roman","Up":-100,"Ut":50,"Cw":[250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,333,408,500,500,833,778,180,333,333,500,564,250,333,250,278,500,500,500,500,500,500,500,500,500,500,278,278,564,564,564,444,921,722,667,667,722,611,556,722,722,333,389,722,611,889,722,722,556,722,667,556,611,722,722,944,722,722,611,333,278,333,469,500,333,444,500,444,500,444,333,500,500,278,278,500,278,778,500,500,500,500,333,389,278,500,500,722,500,500,444,480,200,480,541,350,500,350,333,500,444,1000,500,500,333,1000,556,333,889,350,611,350,350,333,333,444,444,350,500,1000,333,980,389,333,722,350,444,722,250,333,500,500,500,500,200,500,333,760,276,500,564,333,760,333,400,564,300,300,333,500,453,250,333,300,310,500,750,750,750,444,722,722,722,722,722,722,889,667,611,611,611,611,333,333,333,333,722,722,722,722,722,722,722,564,722,722,722,722,722,722,556,500,444,444,444,444,444,444,667,444,444,444,444,444,278,278,278,278,500,500,500,500,500,500,500,564,500,500,500,500,500,500,500,500]}`,
"zapfdingbats": `{"Tp":"Core","Name":"ZapfDingbats","Up":-100,"Ut":50,"Cw":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,278,974,961,974,980,719,789,790,791,690,960,939,549,855,911,933,911,945,974,755,846,762,761,571,677,763,760,759,754,494,552,537,577,692,786,788,788,790,793,794,816,823,789,841,823,833,816,831,923,744,723,749,790,792,695,776,768,792,759,707,708,682,701,826,815,789,789,707,687,696,689,786,787,713,791,785,791,873,761,762,762,759,759,892,892,788,784,438,138,277,415,392,392,668,668,0,390,390,317,317,276,276,509,509,410,410,234,234,334,334,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,732,544,544,910,667,760,760,776,595,694,626,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,894,838,1016,458,748,924,748,918,927,928,928,834,873,828,924,924,917,930,931,463,883,836,836,867,867,696,696,874,0,874,760,946,771,865,771,888,967,888,831,873,927,970,918,0]}`,
}
func (f *Fpdf) coreFontReader(familyStr, styleStr string) (r *strings.Reader) {
key := familyStr + styleStr
str, ok := embeddedFontList[key]
if ok {
r = strings.NewReader(str)
} else {
f.SetErrorf("could not locate \"%s\" among embedded core font definition files", key)
}
return
}
var embeddedMapList = map[string]string{
"cp1250": `
!00 U+0000 .notdef
!01 U+0001 .notdef
!02 U+0002 .notdef
!03 U+0003 .notdef
!04 U+0004 .notdef
!05 U+0005 .notdef
!06 U+0006 .notdef
!07 U+0007 .notdef
!08 U+0008 .notdef
!09 U+0009 .notdef
!0A U+000A .notdef
!0B U+000B .notdef
!0C U+000C .notdef
!0D U+000D .notdef
!0E U+000E .notdef
!0F U+000F .notdef
!10 U+0010 .notdef
!11 U+0011 .notdef
!12 U+0012 .notdef
!13 U+0013 .notdef
!14 U+0014 .notdef
!15 U+0015 .notdef
!16 U+0016 .notdef
!17 U+0017 .notdef
!18 U+0018 .notdef
!19 U+0019 .notdef
!1A U+001A .notdef
!1B U+001B .notdef
!1C U+001C .notdef
!1D U+001D .notdef
!1E U+001E .notdef
!1F U+001F .notdef
!20 U+0020 space
!21 U+0021 exclam
!22 U+0022 quotedbl
!23 U+0023 numbersign
!24 U+0024 dollar
!25 U+0025 percent
!26 U+0026 ampersand
!27 U+0027 quotesingle
!28 U+0028 parenleft
!29 U+0029 parenright
!2A U+002A asterisk
!2B U+002B plus
!2C U+002C comma
!2D U+002D hyphen
!2E U+002E period
!2F U+002F slash
!30 U+0030 zero
!31 U+0031 one
!32 U+0032 two
!33 U+0033 three
!34 U+0034 four
!35 U+0035 five
!36 U+0036 six
!37 U+0037 seven
!38 U+0038 eight
!39 U+0039 nine
!3A U+003A colon
!3B U+003B semicolon
!3C U+003C less
!3D U+003D equal
!3E U+003E greater
!3F U+003F question
!40 U+0040 at
!41 U+0041 A
!42 U+0042 B
!43 U+0043 C
!44 U+0044 D
!45 U+0045 E
!46 U+0046 F
!47 U+0047 G
!48 U+0048 H
!49 U+0049 I
!4A U+004A J
!4B U+004B K
!4C U+004C L
!4D U+004D M
!4E U+004E N
!4F U+004F O
!50 U+0050 P
!51 U+0051 Q
!52 U+0052 R
!53 U+0053 S
!54 U+0054 T
!55 U+0055 U
!56 U+0056 V
!57 U+0057 W
!58 U+0058 X
!59 U+0059 Y
!5A U+005A Z
!5B U+005B bracketleft
!5C U+005C backslash
!5D U+005D bracketright
!5E U+005E asciicircum
!5F U+005F underscore
!60 U+0060 grave
!61 U+0061 a
!62 U+0062 b
!63 U+0063 c
!64 U+0064 d
!65 U+0065 e
!66 U+0066 f
!67 U+0067 g
!68 U+0068 h
!69 U+0069 i
!6A U+006A j
!6B U+006B k
!6C U+006C l
!6D U+006D m
!6E U+006E n
!6F U+006F o
!70 U+0070 p
!71 U+0071 q
!72 U+0072 r
!73 U+0073 s
!74 U+0074 t
!75 U+0075 u
!76 U+0076 v
!77 U+0077 w
!78 U+0078 x
!79 U+0079 y
!7A U+007A z
!7B U+007B braceleft
!7C U+007C bar
!7D U+007D braceright
!7E U+007E asciitilde
!7F U+007F .notdef
!80 U+20AC Euro
!82 U+201A quotesinglbase
!84 U+201E quotedblbase
!85 U+2026 ellipsis
!86 U+2020 dagger
!87 U+2021 daggerdbl
!89 U+2030 perthousand
!8A U+0160 Scaron
!8B U+2039 guilsinglleft
!8C U+015A Sacute
!8D U+0164 Tcaron
!8E U+017D Zcaron
!8F U+0179 Zacute
!91 U+2018 quoteleft
!92 U+2019 quoteright
!93 U+201C quotedblleft
!94 U+201D quotedblright
!95 U+2022 bullet
!96 U+2013 endash
!97 U+2014 emdash
!99 U+2122 trademark
!9A U+0161 scaron
!9B U+203A guilsinglright
!9C U+015B sacute
!9D U+0165 tcaron
!9E U+017E zcaron
!9F U+017A zacute
!A0 U+00A0 space
!A1 U+02C7 caron
!A2 U+02D8 breve
!A3 U+0141 Lslash
!A4 U+00A4 currency
!A5 U+0104 Aogonek
!A6 U+00A6 brokenbar
!A7 U+00A7 section
!A8 U+00A8 dieresis
!A9 U+00A9 copyright
!AA U+015E Scedilla
!AB U+00AB guillemotleft
!AC U+00AC logicalnot
!AD U+00AD hyphen
!AE U+00AE registered
!AF U+017B Zdotaccent
!B0 U+00B0 degree
!B1 U+00B1 plusminus
!B2 U+02DB ogonek
!B3 U+0142 lslash
!B4 U+00B4 acute
!B5 U+00B5 mu
!B6 U+00B6 paragraph
!B7 U+00B7 periodcentered
!B8 U+00B8 cedilla
!B9 U+0105 aogonek
!BA U+015F scedilla
!BB U+00BB guillemotright
!BC U+013D Lcaron
!BD U+02DD hungarumlaut
!BE U+013E lcaron
!BF U+017C zdotaccent
!C0 U+0154 Racute
!C1 U+00C1 Aacute
!C2 U+00C2 Acircumflex
!C3 U+0102 Abreve
!C4 U+00C4 Adieresis
!C5 U+0139 Lacute
!C6 U+0106 Cacute
!C7 U+00C7 Ccedilla
!C8 U+010C Ccaron
!C9 U+00C9 Eacute
!CA U+0118 Eogonek
!CB U+00CB Edieresis
!CC U+011A Ecaron
!CD U+00CD Iacute
!CE U+00CE Icircumflex
!CF U+010E Dcaron
!D0 U+0110 Dcroat
!D1 U+0143 Nacute
!D2 U+0147 Ncaron
!D3 U+00D3 Oacute
!D4 U+00D4 Ocircumflex
!D5 U+0150 Ohungarumlaut
!D6 U+00D6 Odieresis
!D7 U+00D7 multiply
!D8 U+0158 Rcaron
!D9 U+016E Uring
!DA U+00DA Uacute
!DB U+0170 Uhungarumlaut
!DC U+00DC Udieresis
!DD U+00DD Yacute
!DE U+0162 Tcommaaccent
!DF U+00DF germandbls
!E0 U+0155 racute
!E1 U+00E1 aacute
!E2 U+00E2 acircumflex
!E3 U+0103 abreve
!E4 U+00E4 adieresis
!E5 U+013A lacute
!E6 U+0107 cacute
!E7 U+00E7 ccedilla
!E8 U+010D ccaron
!E9 U+00E9 eacute
!EA U+0119 eogonek
!EB U+00EB edieresis
!EC U+011B ecaron
!ED U+00ED iacute
!EE U+00EE icircumflex
!EF U+010F dcaron
!F0 U+0111 dcroat
!F1 U+0144 nacute
!F2 U+0148 ncaron
!F3 U+00F3 oacute
!F4 U+00F4 ocircumflex
!F5 U+0151 ohungarumlaut
!F6 U+00F6 odieresis
!F7 U+00F7 divide
!F8 U+0159 rcaron
!F9 U+016F uring
!FA U+00FA uacute
!FB U+0171 uhungarumlaut
!FC U+00FC udieresis
!FD U+00FD yacute
!FE U+0163 tcommaaccent
!FF U+02D9 dotaccent
`,
"cp1252": `
!00 U+0000 .notdef
!01 U+0001 .notdef
!02 U+0002 .notdef
!03 U+0003 .notdef
!04 U+0004 .notdef
!05 U+0005 .notdef
!06 U+0006 .notdef
!07 U+0007 .notdef
!08 U+0008 .notdef
!09 U+0009 .notdef
!0A U+000A .notdef
!0B U+000B .notdef
!0C U+000C .notdef
!0D U+000D .notdef
!0E U+000E .notdef
!0F U+000F .notdef
!10 U+0010 .notdef
!11 U+0011 .notdef
!12 U+0012 .notdef
!13 U+0013 .notdef
!14 U+0014 .notdef
!15 U+0015 .notdef
!16 U+0016 .notdef
!17 U+0017 .notdef
!18 U+0018 .notdef
!19 U+0019 .notdef
!1A U+001A .notdef
!1B U+001B .notdef
!1C U+001C .notdef
!1D U+001D .notdef
!1E U+001E .notdef
!1F U+001F .notdef
!20 U+0020 space
!21 U+0021 exclam
!22 U+0022 quotedbl
!23 U+0023 numbersign
!24 U+0024 dollar
!25 U+0025 percent
!26 U+0026 ampersand
!27 U+0027 quotesingle
!28 U+0028 parenleft
!29 U+0029 parenright
!2A U+002A asterisk
!2B U+002B plus
!2C U+002C comma
!2D U+002D hyphen
!2E U+002E period
!2F U+002F slash
!30 U+0030 zero
!31 U+0031 one
!32 U+0032 two
!33 U+0033 three
!34 U+0034 four
!35 U+0035 five
!36 U+0036 six
!37 U+0037 seven
!38 U+0038 eight
!39 U+0039 nine
!3A U+003A colon
!3B U+003B semicolon
!3C U+003C less
!3D U+003D equal
!3E U+003E greater
!3F U+003F question
!40 U+0040 at
!41 U+0041 A
!42 U+0042 B
!43 U+0043 C
!44 U+0044 D
!45 U+0045 E
!46 U+0046 F
!47 U+0047 G
!48 U+0048 H
!49 U+0049 I
!4A U+004A J
!4B U+004B K
!4C U+004C L
!4D U+004D M
!4E U+004E N
!4F U+004F O
!50 U+0050 P
!51 U+0051 Q
!52 U+0052 R
!53 U+0053 S
!54 U+0054 T
!55 U+0055 U
!56 U+0056 V
!57 U+0057 W
!58 U+0058 X
!59 U+0059 Y
!5A U+005A Z
!5B U+005B bracketleft
!5C U+005C backslash
!5D U+005D bracketright
!5E U+005E asciicircum
!5F U+005F underscore
!60 U+0060 grave
!61 U+0061 a
!62 U+0062 b
!63 U+0063 c
!64 U+0064 d
!65 U+0065 e
!66 U+0066 f
!67 U+0067 g
!68 U+0068 h
!69 U+0069 i
!6A U+006A j
!6B U+006B k
!6C U+006C l
!6D U+006D m
!6E U+006E n
!6F U+006F o
!70 U+0070 p
!71 U+0071 q
!72 U+0072 r
!73 U+0073 s
!74 U+0074 t
!75 U+0075 u
!76 U+0076 v
!77 U+0077 w
!78 U+0078 x
!79 U+0079 y
!7A U+007A z
!7B U+007B braceleft
!7C U+007C bar
!7D U+007D braceright
!7E U+007E asciitilde
!7F U+007F .notdef
!80 U+20AC Euro
!82 U+201A quotesinglbase
!83 U+0192 florin
!84 U+201E quotedblbase
!85 U+2026 ellipsis
!86 U+2020 dagger
!87 U+2021 daggerdbl
!88 U+02C6 circumflex
!89 U+2030 perthousand
!8A U+0160 Scaron
!8B U+2039 guilsinglleft
!8C U+0152 OE
!8E U+017D Zcaron
!91 U+2018 quoteleft
!92 U+2019 quoteright
!93 U+201C quotedblleft
!94 U+201D quotedblright
!95 U+2022 bullet
!96 U+2013 endash
!97 U+2014 emdash
!98 U+02DC tilde
!99 U+2122 trademark
!9A U+0161 scaron
!9B U+203A guilsinglright
!9C U+0153 oe
!9E U+017E zcaron
!9F U+0178 Ydieresis
!A0 U+00A0 space
!A1 U+00A1 exclamdown
!A2 U+00A2 cent
!A3 U+00A3 sterling
!A4 U+00A4 currency
!A5 U+00A5 yen
!A6 U+00A6 brokenbar
!A7 U+00A7 section
!A8 U+00A8 dieresis
!A9 U+00A9 copyright
!AA U+00AA ordfeminine
!AB U+00AB guillemotleft
!AC U+00AC logicalnot
!AD U+00AD hyphen
!AE U+00AE registered
!AF U+00AF macron
!B0 U+00B0 degree
!B1 U+00B1 plusminus
!B2 U+00B2 twosuperior
!B3 U+00B3 threesuperior
!B4 U+00B4 acute
!B5 U+00B5 mu
!B6 U+00B6 paragraph
!B7 U+00B7 periodcentered
!B8 U+00B8 cedilla
!B9 U+00B9 onesuperior
!BA U+00BA ordmasculine
!BB U+00BB guillemotright
!BC U+00BC onequarter
!BD U+00BD onehalf
!BE U+00BE threequarters
!BF U+00BF questiondown
!C0 U+00C0 Agrave
!C1 U+00C1 Aacute
!C2 U+00C2 Acircumflex
!C3 U+00C3 Atilde
!C4 U+00C4 Adieresis
!C5 U+00C5 Aring
!C6 U+00C6 AE
!C7 U+00C7 Ccedilla
!C8 U+00C8 Egrave
!C9 U+00C9 Eacute
!CA U+00CA Ecircumflex
!CB U+00CB Edieresis
!CC U+00CC Igrave
!CD U+00CD Iacute
!CE U+00CE Icircumflex
!CF U+00CF Idieresis
!D0 U+00D0 Eth
!D1 U+00D1 Ntilde
!D2 U+00D2 Ograve
!D3 U+00D3 Oacute
!D4 U+00D4 Ocircumflex
!D5 U+00D5 Otilde
!D6 U+00D6 Odieresis
!D7 U+00D7 multiply
!D8 U+00D8 Oslash
!D9 U+00D9 Ugrave
!DA U+00DA Uacute
!DB U+00DB Ucircumflex
!DC U+00DC Udieresis
!DD U+00DD Yacute
!DE U+00DE Thorn
!DF U+00DF germandbls
!E0 U+00E0 agrave
!E1 U+00E1 aacute
!E2 U+00E2 acircumflex
!E3 U+00E3 atilde
!E4 U+00E4 adieresis
!E5 U+00E5 aring
!E6 U+00E6 ae
!E7 U+00E7 ccedilla
!E8 U+00E8 egrave
!E9 U+00E9 eacute
!EA U+00EA ecircumflex
!EB U+00EB edieresis
!EC U+00EC igrave
!ED U+00ED iacute
!EE U+00EE icircumflex
!EF U+00EF idieresis
!F0 U+00F0 eth
!F1 U+00F1 ntilde
!F2 U+00F2 ograve
!F3 U+00F3 oacute
!F4 U+00F4 ocircumflex
!F5 U+00F5 otilde
!F6 U+00F6 odieresis
!F7 U+00F7 divide
!F8 U+00F8 oslash
!F9 U+00F9 ugrave
!FA U+00FA uacute
!FB U+00FB ucircumflex
!FC U+00FC udieresis
!FD U+00FD yacute
!FE U+00FE thorn
!FF U+00FF ydieresis
`,
}

474
vendor/github.com/jung-kurt/gofpdf/font.go generated vendored Normal file
View File

@ -0,0 +1,474 @@
/*
* Copyright (c) 2013 Kurt Jung (Gmail: kurt.w.jung)
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package gofpdf
// Utility to generate font definition files
// Version: 1.2
// Date: 2011-06-18
// Author: Olivier PLATHEY
// Port to Go: Kurt Jung, 2013-07-15
import (
"bufio"
"compress/zlib"
"encoding/binary"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
)
func baseNoExt(fileStr string) string {
str := filepath.Base(fileStr)
extLen := len(filepath.Ext(str))
if extLen > 0 {
str = str[:len(str)-extLen]
}
return str
}
func loadMap(encodingFileStr string) (encList encListType, err error) {
// printf("Encoding file string [%s]\n", encodingFileStr)
var f *os.File
// f, err = os.Open(encodingFilepath(encodingFileStr))
f, err = os.Open(encodingFileStr)
if err == nil {
defer f.Close()
for j := range encList {
encList[j].uv = -1
encList[j].name = ".notdef"
}
scanner := bufio.NewScanner(f)
var enc encType
var pos int
for scanner.Scan() {
// "!3F U+003F question"
_, err = fmt.Sscanf(scanner.Text(), "!%x U+%x %s", &pos, &enc.uv, &enc.name)
if err == nil {
if pos < 256 {
encList[pos] = enc
} else {
err = fmt.Errorf("map position 0x%2X exceeds 0xFF", pos)
return
}
} else {
return
}
}
if err = scanner.Err(); err != nil {
return
}
}
return
}
// getInfoFromTrueType returns information from a TrueType font
func getInfoFromTrueType(fileStr string, msgWriter io.Writer, embed bool, encList encListType) (info fontInfoType, err error) {
info.Widths = make([]int, 256)
var ttf TtfType
ttf, err = TtfParse(fileStr)
if err != nil {
return
}
if embed {
if !ttf.Embeddable {
err = fmt.Errorf("font license does not allow embedding")
return
}
info.Data, err = ioutil.ReadFile(fileStr)
if err != nil {
return
}
info.OriginalSize = len(info.Data)
}
k := 1000.0 / float64(ttf.UnitsPerEm)
info.FontName = ttf.PostScriptName
info.Bold = ttf.Bold
info.Desc.ItalicAngle = int(ttf.ItalicAngle)
info.IsFixedPitch = ttf.IsFixedPitch
info.Desc.Ascent = round(k * float64(ttf.TypoAscender))
info.Desc.Descent = round(k * float64(ttf.TypoDescender))
info.UnderlineThickness = round(k * float64(ttf.UnderlineThickness))
info.UnderlinePosition = round(k * float64(ttf.UnderlinePosition))
info.Desc.FontBBox = fontBoxType{
round(k * float64(ttf.Xmin)),
round(k * float64(ttf.Ymin)),
round(k * float64(ttf.Xmax)),
round(k * float64(ttf.Ymax)),
}
// printf("FontBBox\n")
// dump(info.Desc.FontBBox)
info.Desc.CapHeight = round(k * float64(ttf.CapHeight))
info.Desc.MissingWidth = round(k * float64(ttf.Widths[0]))
var wd int
for j := 0; j < len(info.Widths); j++ {
wd = info.Desc.MissingWidth
if encList[j].name != ".notdef" {
uv := encList[j].uv
pos, ok := ttf.Chars[uint16(uv)]
if ok {
wd = round(k * float64(ttf.Widths[pos]))
} else {
fmt.Fprintf(msgWriter, "Character %s is missing\n", encList[j].name)
}
}
info.Widths[j] = wd
}
// printf("getInfoFromTrueType/FontBBox\n")
// dump(info.Desc.FontBBox)
return
}
type segmentType struct {
marker uint8
tp uint8
size uint32
data []byte
}
func segmentRead(r io.Reader) (s segmentType, err error) {
if err = binary.Read(r, binary.LittleEndian, &s.marker); err != nil {
return
}
if s.marker != 128 {
err = fmt.Errorf("font file is not a valid binary Type1")
return
}
if err = binary.Read(r, binary.LittleEndian, &s.tp); err != nil {
return
}
if err = binary.Read(r, binary.LittleEndian, &s.size); err != nil {
return
}
s.data = make([]byte, s.size)
_, err = r.Read(s.data)
return
}
// -rw-r--r-- 1 root root 9532 2010-04-22 11:27 /usr/share/fonts/type1/mathml/Symbol.afm
// -rw-r--r-- 1 root root 37744 2010-04-22 11:27 /usr/share/fonts/type1/mathml/Symbol.pfb
// getInfoFromType1 return information from a Type1 font
func getInfoFromType1(fileStr string, msgWriter io.Writer, embed bool, encList encListType) (info fontInfoType, err error) {
info.Widths = make([]int, 256)
if embed {
var f *os.File
f, err = os.Open(fileStr)
if err != nil {
return
}
defer f.Close()
// Read first segment
var s1, s2 segmentType
s1, err = segmentRead(f)
if err != nil {
return
}
s2, err = segmentRead(f)
if err != nil {
return
}
info.Data = s1.data
info.Data = append(info.Data, s2.data...)
info.Size1 = s1.size
info.Size2 = s2.size
}
afmFileStr := fileStr[0:len(fileStr)-3] + "afm"
size, ok := fileSize(afmFileStr)
if !ok {
err = fmt.Errorf("font file (ATM) %s not found", afmFileStr)
return
} else if size == 0 {
err = fmt.Errorf("font file (AFM) %s empty or not readable", afmFileStr)
return
}
var f *os.File
f, err = os.Open(afmFileStr)
if err != nil {
return
}
defer f.Close()
scanner := bufio.NewScanner(f)
var fields []string
var wd int
var wt, name string
wdMap := make(map[string]int)
for scanner.Scan() {
fields = strings.Fields(strings.TrimSpace(scanner.Text()))
// Comment Generated by FontForge 20080203
// FontName Symbol
// C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
if len(fields) >= 2 {
switch fields[0] {
case "C":
if wd, err = strconv.Atoi(fields[4]); err == nil {
name = fields[7]
wdMap[name] = wd
}
case "FontName":
info.FontName = fields[1]
case "Weight":
wt = strings.ToLower(fields[1])
case "ItalicAngle":
info.Desc.ItalicAngle, err = strconv.Atoi(fields[1])
case "Ascender":
info.Desc.Ascent, err = strconv.Atoi(fields[1])
case "Descender":
info.Desc.Descent, err = strconv.Atoi(fields[1])
case "UnderlineThickness":
info.UnderlineThickness, err = strconv.Atoi(fields[1])
case "UnderlinePosition":
info.UnderlinePosition, err = strconv.Atoi(fields[1])
case "IsFixedPitch":
info.IsFixedPitch = fields[1] == "true"
case "FontBBox":
if info.Desc.FontBBox.Xmin, err = strconv.Atoi(fields[1]); err == nil {
if info.Desc.FontBBox.Ymin, err = strconv.Atoi(fields[2]); err == nil {
if info.Desc.FontBBox.Xmax, err = strconv.Atoi(fields[3]); err == nil {
info.Desc.FontBBox.Ymax, err = strconv.Atoi(fields[4])
}
}
}
case "CapHeight":
info.Desc.CapHeight, err = strconv.Atoi(fields[1])
case "StdVW":
info.Desc.StemV, err = strconv.Atoi(fields[1])
}
}
if err != nil {
return
}
}
if err = scanner.Err(); err != nil {
return
}
if info.FontName == "" {
err = fmt.Errorf("the field FontName missing in AFM file %s", afmFileStr)
return
}
info.Bold = wt == "bold" || wt == "black"
var missingWd int
missingWd, ok = wdMap[".notdef"]
if ok {
info.Desc.MissingWidth = missingWd
}
for j := 0; j < len(info.Widths); j++ {
info.Widths[j] = info.Desc.MissingWidth
}
for j := 0; j < len(info.Widths); j++ {
name = encList[j].name
if name != ".notdef" {
wd, ok = wdMap[name]
if ok {
info.Widths[j] = wd
} else {
fmt.Fprintf(msgWriter, "Character %s is missing\n", name)
}
}
}
// printf("getInfoFromType1/FontBBox\n")
// dump(info.Desc.FontBBox)
return
}
func makeFontDescriptor(info *fontInfoType) {
if info.Desc.CapHeight == 0 {
info.Desc.CapHeight = info.Desc.Ascent
}
info.Desc.Flags = 1 << 5
if info.IsFixedPitch {
info.Desc.Flags |= 1
}
if info.Desc.ItalicAngle != 0 {
info.Desc.Flags |= 1 << 6
}
if info.Desc.StemV == 0 {
if info.Bold {
info.Desc.StemV = 120
} else {
info.Desc.StemV = 70
}
}
// printf("makeFontDescriptor/FontBBox\n")
// dump(info.Desc.FontBBox)
}
// makeFontEncoding builds differences from reference encoding
func makeFontEncoding(encList encListType, refEncFileStr string) (diffStr string, err error) {
var refList encListType
if refList, err = loadMap(refEncFileStr); err != nil {
return
}
var buf fmtBuffer
last := 0
for j := 32; j < 256; j++ {
if encList[j].name != refList[j].name {
if j != last+1 {
buf.printf("%d ", j)
}
last = j
buf.printf("/%s ", encList[j].name)
}
}
diffStr = strings.TrimSpace(buf.String())
return
}
func makeDefinitionFile(fileStr, tpStr, encodingFileStr string, embed bool, encList encListType, info fontInfoType) error {
var err error
var def fontDefType
def.Tp = tpStr
def.Name = info.FontName
makeFontDescriptor(&info)
def.Desc = info.Desc
// printf("makeDefinitionFile/FontBBox\n")
// dump(def.Desc.FontBBox)
def.Up = info.UnderlinePosition
def.Ut = info.UnderlineThickness
def.Cw = info.Widths
def.Enc = baseNoExt(encodingFileStr)
// fmt.Printf("encodingFileStr [%s], def.Enc [%s]\n", encodingFileStr, def.Enc)
// fmt.Printf("reference [%s]\n", filepath.Join(filepath.Dir(encodingFileStr), "cp1252.map"))
def.Diff, err = makeFontEncoding(encList, filepath.Join(filepath.Dir(encodingFileStr), "cp1252.map"))
if err != nil {
return err
}
def.File = info.File
def.Size1 = int(info.Size1)
def.Size2 = int(info.Size2)
def.OriginalSize = info.OriginalSize
// printf("Font definition file [%s]\n", fileStr)
var buf []byte
buf, err = json.Marshal(def)
if err != nil {
return err
}
var f *os.File
f, err = os.Create(fileStr)
if err != nil {
return err
}
defer f.Close()
_, err = f.Write(buf)
if err != nil {
return err
}
err = f.Close()
if err != nil {
return err
}
return err
}
// MakeFont generates a font definition file in JSON format. A definition file
// of this type is required to use non-core fonts in the PDF documents that
// gofpdf generates. See the makefont utility in the gofpdf package for a
// command line interface to this function.
//
// fontFileStr is the name of the TrueType file (extension .ttf), OpenType file
// (extension .otf) or binary Type1 file (extension .pfb) from which to
// generate a definition file. If an OpenType file is specified, it must be one
// that is based on TrueType outlines, not PostScript outlines; this cannot be
// determined from the file extension alone. If a Type1 file is specified, a
// metric file with the same pathname except with the extension .afm must be
// present.
//
// encodingFileStr is the name of the encoding file that corresponds to the
// font.
//
// dstDirStr is the name of the directory in which to save the definition file
// and, if embed is true, the compressed font file.
//
// msgWriter is the writer that is called to display messages throughout the
// process. Use nil to turn off messages.
//
// embed is true if the font is to be embedded in the PDF files.
func MakeFont(fontFileStr, encodingFileStr, dstDirStr string, msgWriter io.Writer, embed bool) error {
if msgWriter == nil {
msgWriter = ioutil.Discard
}
if !fileExist(fontFileStr) {
return fmt.Errorf("font file not found: %s", fontFileStr)
}
extStr := strings.ToLower(fontFileStr[len(fontFileStr)-3:])
// printf("Font file extension [%s]\n", extStr)
var tpStr string
switch extStr {
case "ttf":
fallthrough
case "otf":
tpStr = "TrueType"
case "pfb":
tpStr = "Type1"
default:
return fmt.Errorf("unrecognized font file extension: %s", extStr)
}
var info fontInfoType
encList, err := loadMap(encodingFileStr)
if err != nil {
return err
}
// printf("Encoding table\n")
// dump(encList)
if tpStr == "TrueType" {
info, err = getInfoFromTrueType(fontFileStr, msgWriter, embed, encList)
if err != nil {
return err
}
} else {
info, err = getInfoFromType1(fontFileStr, msgWriter, embed, encList)
if err != nil {
return err
}
}
baseStr := baseNoExt(fontFileStr)
// fmt.Printf("Base [%s]\n", baseStr)
if embed {
var f *os.File
info.File = baseStr + ".z"
zFileStr := filepath.Join(dstDirStr, info.File)
f, err = os.Create(zFileStr)
if err != nil {
return err
}
defer f.Close()
cmp := zlib.NewWriter(f)
_, err = cmp.Write(info.Data)
if err != nil {
return err
}
err = cmp.Close()
if err != nil {
return err
}
fmt.Fprintf(msgWriter, "Font file compressed: %s\n", zFileStr)
}
defFileStr := filepath.Join(dstDirStr, baseStr+".json")
err = makeDefinitionFile(defFileStr, tpStr, encodingFileStr, embed, encList, info)
if err != nil {
return err
}
fmt.Fprintf(msgWriter, "Font definition file successfully generated: %s\n", defFileStr)
return nil
}

4860
vendor/github.com/jung-kurt/gofpdf/fpdf.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

213
vendor/github.com/jung-kurt/gofpdf/fpdftrans.go generated vendored Normal file
View File

@ -0,0 +1,213 @@
package gofpdf
import (
"fmt"
"math"
)
// Routines in this file are translated from the work of Moritz Wagner and
// Andreas Würmser.
// TransformMatrix is used for generalized transformations of text, drawings
// and images.
type TransformMatrix struct {
A, B, C, D, E, F float64
}
// TransformBegin sets up a transformation context for subsequent text,
// drawings and images. The typical usage is to immediately follow a call to
// this method with a call to one or more of the transformation methods such as
// TransformScale(), TransformSkew(), etc. This is followed by text, drawing or
// image output and finally a call to TransformEnd(). All transformation
// contexts must be properly ended prior to outputting the document.
func (f *Fpdf) TransformBegin() {
f.transformNest++
f.out("q")
}
// TransformScaleX scales the width of the following text, drawings and images.
// scaleWd is the percentage scaling factor. (x, y) is center of scaling.
//
// The TransformBegin() example demonstrates this method.
func (f *Fpdf) TransformScaleX(scaleWd, x, y float64) {
f.TransformScale(scaleWd, 100, x, y)
}
// TransformScaleY scales the height of the following text, drawings and
// images. scaleHt is the percentage scaling factor. (x, y) is center of
// scaling.
//
// The TransformBegin() example demonstrates this method.
func (f *Fpdf) TransformScaleY(scaleHt, x, y float64) {
f.TransformScale(100, scaleHt, x, y)
}
// TransformScaleXY uniformly scales the width and height of the following
// text, drawings and images. s is the percentage scaling factor for both width
// and height. (x, y) is center of scaling.
//
// The TransformBegin() example demonstrates this method.
func (f *Fpdf) TransformScaleXY(s, x, y float64) {
f.TransformScale(s, s, x, y)
}
// TransformScale generally scales the following text, drawings and images.
// scaleWd and scaleHt are the percentage scaling factors for width and height.
// (x, y) is center of scaling.
//
// The TransformBegin() example demonstrates this method.
func (f *Fpdf) TransformScale(scaleWd, scaleHt, x, y float64) {
if scaleWd == 0 || scaleHt == 0 {
f.err = fmt.Errorf("scale factor cannot be zero")
return
}
y = (f.h - y) * f.k
x *= f.k
scaleWd /= 100
scaleHt /= 100
f.Transform(TransformMatrix{scaleWd, 0, 0,
scaleHt, x * (1 - scaleWd), y * (1 - scaleHt)})
}
// TransformMirrorHorizontal horizontally mirrors the following text, drawings
// and images. x is the axis of reflection.
//
// The TransformBegin() example demonstrates this method.
func (f *Fpdf) TransformMirrorHorizontal(x float64) {
f.TransformScale(-100, 100, x, f.y)
}
// TransformMirrorVertical vertically mirrors the following text, drawings and
// images. y is the axis of reflection.
//
// The TransformBegin() example demonstrates this method.
func (f *Fpdf) TransformMirrorVertical(y float64) {
f.TransformScale(100, -100, f.x, y)
}
// TransformMirrorPoint symmetrically mirrors the following text, drawings and
// images on the point specified by (x, y).
//
// The TransformBegin() example demonstrates this method.
func (f *Fpdf) TransformMirrorPoint(x, y float64) {
f.TransformScale(-100, -100, x, y)
}
// TransformMirrorLine symmetrically mirrors the following text, drawings and
// images on the line defined by angle and the point (x, y). angles is
// specified in degrees and measured counter-clockwise from the 3 o'clock
// position.
//
// The TransformBegin() example demonstrates this method.
func (f *Fpdf) TransformMirrorLine(angle, x, y float64) {
f.TransformScale(-100, 100, x, y)
f.TransformRotate(-2*(angle-90), x, y)
}
// TransformTranslateX moves the following text, drawings and images
// horizontally by the amount specified by tx.
//
// The TransformBegin() example demonstrates this method.
func (f *Fpdf) TransformTranslateX(tx float64) {
f.TransformTranslate(tx, 0)
}
// TransformTranslateY moves the following text, drawings and images vertically
// by the amount specified by ty.
//
// The TransformBegin() example demonstrates this method.
func (f *Fpdf) TransformTranslateY(ty float64) {
f.TransformTranslate(0, ty)
}
// TransformTranslate moves the following text, drawings and images
// horizontally and vertically by the amounts specified by tx and ty.
//
// The TransformBegin() example demonstrates this method.
func (f *Fpdf) TransformTranslate(tx, ty float64) {
f.Transform(TransformMatrix{1, 0, 0, 1, tx * f.k, -ty * f.k})
}
// TransformRotate rotates the following text, drawings and images around the
// center point (x, y). angle is specified in degrees and measured
// counter-clockwise from the 3 o'clock position.
//
// The TransformBegin() example demonstrates this method.
func (f *Fpdf) TransformRotate(angle, x, y float64) {
y = (f.h - y) * f.k
x *= f.k
angle = angle * math.Pi / 180
var tm TransformMatrix
tm.A = math.Cos(angle)
tm.B = math.Sin(angle)
tm.C = -tm.B
tm.D = tm.A
tm.E = x + tm.B*y - tm.A*x
tm.F = y - tm.A*y - tm.B*x
f.Transform(tm)
}
// TransformSkewX horizontally skews the following text, drawings and images
// keeping the point (x, y) stationary. angleX ranges from -90 degrees (skew to
// the left) to 90 degrees (skew to the right).
//
// The TransformBegin() example demonstrates this method.
func (f *Fpdf) TransformSkewX(angleX, x, y float64) {
f.TransformSkew(angleX, 0, x, y)
}
// TransformSkewY vertically skews the following text, drawings and images
// keeping the point (x, y) stationary. angleY ranges from -90 degrees (skew to
// the bottom) to 90 degrees (skew to the top).
//
// The TransformBegin() example demonstrates this method.
func (f *Fpdf) TransformSkewY(angleY, x, y float64) {
f.TransformSkew(0, angleY, x, y)
}
// TransformSkew generally skews the following text, drawings and images
// keeping the point (x, y) stationary. angleX ranges from -90 degrees (skew to
// the left) to 90 degrees (skew to the right). angleY ranges from -90 degrees
// (skew to the bottom) to 90 degrees (skew to the top).
//
// The TransformBegin() example demonstrates this method.
func (f *Fpdf) TransformSkew(angleX, angleY, x, y float64) {
if angleX <= -90 || angleX >= 90 || angleY <= -90 || angleY >= 90 {
f.err = fmt.Errorf("skew values must be between -90° and 90°")
return
}
x *= f.k
y = (f.h - y) * f.k
var tm TransformMatrix
tm.A = 1
tm.B = math.Tan(angleY * math.Pi / 180)
tm.C = math.Tan(angleX * math.Pi / 180)
tm.D = 1
tm.E = -tm.C * y
tm.F = -tm.B * x
f.Transform(tm)
}
// Transform generally transforms the following text, drawings and images
// according to the specified matrix. It is typically easier to use the various
// methods such as TransformRotate() and TransformMirrorVertical() instead.
func (f *Fpdf) Transform(tm TransformMatrix) {
if f.transformNest > 0 {
f.outf("%.5f %.5f %.5f %.5f %.5f %.5f cm",
tm.A, tm.B, tm.C, tm.D, tm.E, tm.F)
} else if f.err == nil {
f.err = fmt.Errorf("transformation context is not active")
}
}
// TransformEnd applies a transformation that was begun with a call to TransformBegin().
//
// The TransformBegin() example demonstrates this method.
func (f *Fpdf) TransformEnd() {
if f.transformNest > 0 {
f.transformNest--
f.out("Q")
} else {
f.err = fmt.Errorf("error attempting to end transformation operation out of sequence")
}
}

12
vendor/github.com/jung-kurt/gofpdf/go.mod generated vendored Normal file
View File

@ -0,0 +1,12 @@
module github.com/jung-kurt/gofpdf
go 1.12
require (
github.com/boombuler/barcode v1.0.0
github.com/phpdave11/gofpdi v1.0.7
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58
golang.org/x/image v0.0.0-20190507092727-e4e5bf290fec
)
replace github.com/jung-kurt/gopdf => ./

18
vendor/github.com/jung-kurt/gofpdf/go.sum generated vendored Normal file
View File

@ -0,0 +1,18 @@
github.com/boombuler/barcode v1.0.0 h1:s1TvRnXwL2xJRaccrdcBQMZxq6X7DvsMogtmJeHDdrc=
github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/phpdave11/gofpdi v1.0.7 h1:k2oy4yhkQopCK+qW8KjCla0iU2RpDow+QUDmH9DDt44=
github.com/phpdave11/gofpdi v1.0.7/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58 h1:nlG4Wa5+minh3S9LVFtNoY+GVRiudA2e3EVfcCi3RCA=
github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
golang.org/x/image v0.0.0-20190507092727-e4e5bf290fec h1:arXJwtMuk5vqI1NHX0UTnNw977rYk5Sl4jQqHj+hun4=
golang.org/x/image v0.0.0-20190507092727-e4e5bf290fec/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

446
vendor/github.com/jung-kurt/gofpdf/grid.go generated vendored Normal file
View File

@ -0,0 +1,446 @@
package gofpdf
import (
"math"
"strconv"
)
func unused(args ...interface{}) {
}
// RGBType holds fields for red, green and blue color components (0..255)
type RGBType struct {
R, G, B int
}
// RGBAType holds fields for red, green and blue color components (0..255) and
// an alpha transparency value (0..1)
type RGBAType struct {
R, G, B int
Alpha float64
}
// StateType holds various commonly used drawing values for convenient
// retrieval (StateGet()) and restore (Put) methods.
type StateType struct {
clrDraw, clrText, clrFill RGBType
lineWd float64
fontSize float64
alpha float64
blendStr string
cellMargin float64
}
// StateGet returns a variable that contains common state values.
func StateGet(pdf *Fpdf) (st StateType) {
st.clrDraw.R, st.clrDraw.G, st.clrDraw.B = pdf.GetDrawColor()
st.clrFill.R, st.clrFill.G, st.clrFill.B = pdf.GetFillColor()
st.clrText.R, st.clrText.G, st.clrText.B = pdf.GetTextColor()
st.lineWd = pdf.GetLineWidth()
_, st.fontSize = pdf.GetFontSize()
st.alpha, st.blendStr = pdf.GetAlpha()
st.cellMargin = pdf.GetCellMargin()
return
}
// Put sets the common state values contained in the state structure
// specified by st.
func (st StateType) Put(pdf *Fpdf) {
pdf.SetDrawColor(st.clrDraw.R, st.clrDraw.G, st.clrDraw.B)
pdf.SetFillColor(st.clrFill.R, st.clrFill.G, st.clrFill.B)
pdf.SetTextColor(st.clrText.R, st.clrText.G, st.clrText.B)
pdf.SetLineWidth(st.lineWd)
pdf.SetFontUnitSize(st.fontSize)
pdf.SetAlpha(st.alpha, st.blendStr)
pdf.SetCellMargin(st.cellMargin)
}
// TickFormatFncType defines a callback for label drawing.
type TickFormatFncType func(val float64, precision int) string
// defaultFormatter returns the string form of val with precision decimal places.
func defaultFormatter(val float64, precision int) string {
return strconv.FormatFloat(val, 'f', precision, 64)
}
// GridType assists with the generation of graphs. It allows the application to
// work with logical data coordinates rather than page coordinates and assists
// with the drawing of a background grid.
type GridType struct {
// Chart coordinates in page units
x, y, w, h float64
// X, Y, Wd, Ht float64
// Slopes and intercepts scale data points to graph coordinates linearly
xm, xb, ym, yb float64
// Tickmarks
xTicks, yTicks []float64
// Labels are inside of graph boundary
XLabelIn, YLabelIn bool
// Labels on X-axis should be rotated
XLabelRotate bool
// Formatters; use nil to eliminate labels
XTickStr, YTickStr TickFormatFncType
// Subdivisions between tickmarks
XDiv, YDiv int
// Formatting precision
xPrecision, yPrecision int
// Line and label colors
ClrText, ClrMain, ClrSub RGBAType
// Line thickness
WdMain, WdSub float64
// Label height in points
TextSize float64
}
// linear returns the slope and y-intercept of the straight line joining the
// two specified points. For scaling purposes, associate the arguments as
// follows: x1: observed low value, y1: desired low value, x2: observed high
// value, y2: desired high value.
func linear(x1, y1, x2, y2 float64) (slope, intercept float64) {
if x2 != x1 {
slope = (y2 - y1) / (x2 - x1)
intercept = y2 - x2*slope
}
return
}
// linearTickmark returns the slope and intercept that will linearly map data
// values (the range of which is specified by the tickmark slice tm) to page
// values (the range of which is specified by lo and hi).
func linearTickmark(tm []float64, lo, hi float64) (slope, intercept float64) {
ln := len(tm)
if ln > 0 {
slope, intercept = linear(tm[0], lo, tm[ln-1], hi)
}
return
}
// NewGrid returns a variable of type GridType that is initialized to draw on a
// rectangle of width w and height h with the upper left corner positioned at
// point (x, y). The coordinates are in page units, that is, the same as those
// specified in New().
//
// The returned variable is initialized with a very simple default tickmark
// layout that ranges from 0 to 1 in both axes. Prior to calling Grid(), the
// application may establish a more suitable tickmark layout by calling the
// methods TickmarksContainX() and TickmarksContainY(). These methods bound the
// data range with appropriate boundaries and divisions. Alternatively, if the
// exact extent and divisions of the tickmark layout are known, the methods
// TickmarksExtentX() and TickmarksExtentY may be called instead.
func NewGrid(x, y, w, h float64) (grid GridType) {
grid.x = x
grid.y = y
grid.w = w
grid.h = h
grid.TextSize = 7 // Points
grid.TickmarksExtentX(0, 1, 1)
grid.TickmarksExtentY(0, 1, 1)
grid.XLabelIn = false
grid.YLabelIn = false
grid.XLabelRotate = false
grid.XDiv = 10
grid.YDiv = 10
grid.ClrText = RGBAType{R: 0, G: 0, B: 0, Alpha: 1}
grid.ClrMain = RGBAType{R: 128, G: 160, B: 128, Alpha: 1}
grid.ClrSub = RGBAType{R: 192, G: 224, B: 192, Alpha: 1}
grid.WdMain = 0.1
grid.WdSub = 0.1
grid.YTickStr = defaultFormatter
grid.XTickStr = defaultFormatter
return
}
// WdAbs returns the absolute value of dataWd, specified in logical data units,
// that has been converted to the unit of measure specified in New().
func (g GridType) WdAbs(dataWd float64) float64 {
return math.Abs(g.xm * dataWd)
}
// Wd converts dataWd, specified in logical data units, to the unit of measure
// specified in New().
func (g GridType) Wd(dataWd float64) float64 {
return g.xm * dataWd
}
// XY converts dataX and dataY, specified in logical data units, to the X and Y
// position on the current page.
func (g GridType) XY(dataX, dataY float64) (x, y float64) {
return g.xm*dataX + g.xb, g.ym*dataY + g.yb
}
// Pos returns the point, in page units, indicated by the relative positions
// xRel and yRel. These are values between 0 and 1. xRel specifies the relative
// position between the grid's left and right edges. yRel specifies the
// relative position between the grid's bottom and top edges.
func (g GridType) Pos(xRel, yRel float64) (x, y float64) {
x = g.w*xRel + g.x
y = g.h*(1-yRel) + g.y
return
}
// X converts dataX, specified in logical data units, to the X position on the
// current page.
func (g GridType) X(dataX float64) float64 {
return g.xm*dataX + g.xb
}
// HtAbs returns the absolute value of dataHt, specified in logical data units,
// that has been converted to the unit of measure specified in New().
func (g GridType) HtAbs(dataHt float64) float64 {
return math.Abs(g.ym * dataHt)
}
// Ht converts dataHt, specified in logical data units, to the unit of measure
// specified in New().
func (g GridType) Ht(dataHt float64) float64 {
return g.ym * dataHt
}
// Y converts dataY, specified in logical data units, to the Y position on the
// current page.
func (g GridType) Y(dataY float64) float64 {
return g.ym*dataY + g.yb
}
// XRange returns the minimum and maximum values for the current tickmark
// sequence. These correspond to the data values of the graph's left and right
// edges.
func (g GridType) XRange() (min, max float64) {
min = g.xTicks[0]
max = g.xTicks[len(g.xTicks)-1]
return
}
// YRange returns the minimum and maximum values for the current tickmark
// sequence. These correspond to the data values of the graph's bottom and top
// edges.
func (g GridType) YRange() (min, max float64) {
min = g.yTicks[0]
max = g.yTicks[len(g.yTicks)-1]
return
}
// TickmarksContainX sets the tickmarks to be shown by Grid() in the horizontal
// dimension. The argument min and max specify the minimum and maximum values
// to be contained within the grid. The tickmark values that are generated are
// suitable for general purpose graphs.
//
// See TickmarkExtentX() for an alternative to this method to be used when the
// exact values of the tickmarks are to be set by the application.
func (g *GridType) TickmarksContainX(min, max float64) {
g.xTicks, g.xPrecision = Tickmarks(min, max)
g.xm, g.xb = linearTickmark(g.xTicks, g.x, g.x+g.w)
}
// TickmarksContainY sets the tickmarks to be shown by Grid() in the vertical
// dimension. The argument min and max specify the minimum and maximum values
// to be contained within the grid. The tickmark values that are generated are
// suitable for general purpose graphs.
//
// See TickmarkExtentY() for an alternative to this method to be used when the
// exact values of the tickmarks are to be set by the application.
func (g *GridType) TickmarksContainY(min, max float64) {
g.yTicks, g.yPrecision = Tickmarks(min, max)
g.ym, g.yb = linearTickmark(g.yTicks, g.y+g.h, g.y)
}
func extent(min, div float64, count int) (tm []float64, precision int) {
tm = make([]float64, count+1)
for j := 0; j <= count; j++ {
tm[j] = min
min += div
}
precision = TickmarkPrecision(div)
return
}
// TickmarksExtentX sets the tickmarks to be shown by Grid() in the horizontal
// dimension. count specifies number of major tickmark subdivisions to be
// graphed. min specifies the leftmost data value. div specifies, in data
// units, the extent of each major tickmark subdivision.
//
// See TickmarkContainX() for an alternative to this method to be used when
// viewer-friendly tickmarks are to be determined automatically.
func (g *GridType) TickmarksExtentX(min, div float64, count int) {
g.xTicks, g.xPrecision = extent(min, div, count)
g.xm, g.xb = linearTickmark(g.xTicks, g.x, g.x+g.w)
}
// TickmarksExtentY sets the tickmarks to be shown by Grid() in the vertical
// dimension. count specifies number of major tickmark subdivisions to be
// graphed. min specifies the bottommost data value. div specifies, in data
// units, the extent of each major tickmark subdivision.
//
// See TickmarkContainY() for an alternative to this method to be used when
// viewer-friendly tickmarks are to be determined automatically.
func (g *GridType) TickmarksExtentY(min, div float64, count int) {
g.yTicks, g.yPrecision = extent(min, div, count)
g.ym, g.yb = linearTickmark(g.yTicks, g.y+g.h, g.y)
}
// func (g *GridType) SetXExtent(dataLf, paperLf, dataRt, paperRt float64) {
// g.xm, g.xb = linear(dataLf, paperLf, dataRt, paperRt)
// }
// func (g *GridType) SetYExtent(dataTp, paperTp, dataBt, paperBt float64) {
// g.ym, g.yb = linear(dataTp, paperTp, dataBt, paperBt)
// }
func lineAttr(pdf *Fpdf, clr RGBAType, lineWd float64) {
pdf.SetLineWidth(lineWd)
pdf.SetAlpha(clr.Alpha, "Normal")
pdf.SetDrawColor(clr.R, clr.G, clr.B)
}
// Grid generates a graph-paperlike set of grid lines on the current page.
func (g GridType) Grid(pdf *Fpdf) {
var st StateType
var yLen, xLen int
var textSz, halfTextSz, yMin, yMax, xMin, xMax, yDiv, xDiv float64
var str string
var strOfs, strWd, tp, bt, lf, rt, drawX, drawY float64
xLen = len(g.xTicks)
yLen = len(g.yTicks)
if xLen > 1 && yLen > 1 {
st = StateGet(pdf)
line := func(x1, y1, x2, y2 float64, heavy bool) {
if heavy {
lineAttr(pdf, g.ClrMain, g.WdMain)
} else {
lineAttr(pdf, g.ClrSub, g.WdSub)
}
pdf.Line(x1, y1, x2, y2)
}
textSz = pdf.PointToUnitConvert(g.TextSize)
halfTextSz = textSz / 2
pdf.SetAutoPageBreak(false, 0)
pdf.SetFontUnitSize(textSz)
strOfs = pdf.GetStringWidth("0")
pdf.SetFillColor(255, 255, 255)
pdf.SetCellMargin(0)
xMin = g.xTicks[0]
xMax = g.xTicks[xLen-1]
yMin = g.yTicks[0]
yMax = g.yTicks[yLen-1]
lf = g.X(xMin)
rt = g.X(xMax)
bt = g.Y(yMin)
tp = g.Y(yMax)
// Verticals along X axis
xDiv = g.xTicks[1] - g.xTicks[0]
if g.XDiv > 0 {
xDiv = xDiv / float64(g.XDiv)
}
xDiv = g.Wd(xDiv)
for j, x := range g.xTicks {
drawX = g.X(x)
line(drawX, tp, drawX, bt, true)
if j < xLen-1 {
for k := 1; k < g.XDiv; k++ {
drawX += xDiv
line(drawX, tp, drawX, bt, false)
}
}
}
// Horizontals along Y axis
yDiv = g.yTicks[1] - g.yTicks[0]
if g.YDiv > 0 {
yDiv = yDiv / float64(g.YDiv)
}
yDiv = g.Ht(yDiv)
for j, y := range g.yTicks {
drawY = g.Y(y)
line(lf, drawY, rt, drawY, true)
if j < yLen-1 {
for k := 1; k < g.YDiv; k++ {
drawY += yDiv
line(lf, drawY, rt, drawY, false)
}
}
}
// X labels
if g.XTickStr != nil {
drawY = bt
for _, x := range g.xTicks {
str = g.XTickStr(x, g.xPrecision)
strWd = pdf.GetStringWidth(str)
drawX = g.X(x)
if g.XLabelRotate {
pdf.TransformBegin()
pdf.TransformRotate(90, drawX, drawY)
if g.XLabelIn {
pdf.SetXY(drawX+strOfs, drawY-halfTextSz)
} else {
pdf.SetXY(drawX-strOfs-strWd, drawY-halfTextSz)
}
pdf.CellFormat(strWd, textSz, str, "", 0, "L", true, 0, "")
pdf.TransformEnd()
} else {
drawX -= strWd / 2.0
if g.XLabelIn {
pdf.SetXY(drawX, drawY-textSz-strOfs)
} else {
pdf.SetXY(drawX, drawY+strOfs)
}
pdf.CellFormat(strWd, textSz, str, "", 0, "L", true, 0, "")
}
}
}
// Y labels
if g.YTickStr != nil {
drawX = lf
for _, y := range g.yTicks {
// str = strconv.FormatFloat(y, 'f', g.yPrecision, 64)
str = g.YTickStr(y, g.yPrecision)
strWd = pdf.GetStringWidth(str)
if g.YLabelIn {
pdf.SetXY(drawX+strOfs, g.Y(y)-halfTextSz)
} else {
pdf.SetXY(lf-strOfs-strWd, g.Y(y)-halfTextSz)
}
pdf.CellFormat(strWd, textSz, str, "", 0, "L", true, 0, "")
}
}
// Restore drawing attributes
st.Put(pdf)
}
}
// Plot plots a series of count line segments from xMin to xMax. It repeatedly
// calls fnc(x) to retrieve the y value associate with x. The currently
// selected line drawing attributes are used.
func (g GridType) Plot(pdf *Fpdf, xMin, xMax float64, count int, fnc func(x float64) (y float64)) {
if count > 0 {
var x, delta, drawX0, drawY0, drawX1, drawY1 float64
delta = (xMax - xMin) / float64(count)
x = xMin
for j := 0; j <= count; j++ {
if j == 0 {
drawX1 = g.X(x)
drawY1 = g.Y(fnc(x))
} else {
pdf.Line(drawX0, drawY0, drawX1, drawY1)
}
x += delta
drawX0 = drawX1
drawY0 = drawY1
drawX1 = g.X(x)
drawY1 = g.Y(fnc(x))
}
}
}

220
vendor/github.com/jung-kurt/gofpdf/htmlbasic.go generated vendored Normal file
View File

@ -0,0 +1,220 @@
/*
* Copyright (c) 2014 Kurt Jung (Gmail: kurt.w.jung)
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package gofpdf
import (
"regexp"
"strings"
)
// HTMLBasicSegmentType defines a segment of literal text in which the current
// attributes do not vary, or an open tag or a close tag.
type HTMLBasicSegmentType struct {
Cat byte // 'O' open tag, 'C' close tag, 'T' text
Str string // Literal text unchanged, tags are lower case
Attr map[string]string // Attribute keys are lower case
}
// HTMLBasicTokenize returns a list of HTML tags and literal elements. This is
// done with regular expressions, so the result is only marginally better than
// useless.
func HTMLBasicTokenize(htmlStr string) (list []HTMLBasicSegmentType) {
// This routine is adapted from http://www.fpdf.org/
list = make([]HTMLBasicSegmentType, 0, 16)
htmlStr = strings.Replace(htmlStr, "\n", " ", -1)
htmlStr = strings.Replace(htmlStr, "\r", "", -1)
tagRe, _ := regexp.Compile(`(?U)<.*>`)
attrRe, _ := regexp.Compile(`([^=]+)=["']?([^"']+)`)
capList := tagRe.FindAllStringIndex(htmlStr, -1)
if capList != nil {
var seg HTMLBasicSegmentType
var parts []string
pos := 0
for _, cap := range capList {
if pos < cap[0] {
seg.Cat = 'T'
seg.Str = htmlStr[pos:cap[0]]
seg.Attr = nil
list = append(list, seg)
}
if htmlStr[cap[0]+1] == '/' {
seg.Cat = 'C'
seg.Str = strings.ToLower(htmlStr[cap[0]+2 : cap[1]-1])
seg.Attr = nil
list = append(list, seg)
} else {
// Extract attributes
parts = strings.Split(htmlStr[cap[0]+1:cap[1]-1], " ")
if len(parts) > 0 {
for j, part := range parts {
if j == 0 {
seg.Cat = 'O'
seg.Str = strings.ToLower(parts[0])
seg.Attr = make(map[string]string)
} else {
attrList := attrRe.FindAllStringSubmatch(part, -1)
if attrList != nil {
for _, attr := range attrList {
seg.Attr[strings.ToLower(attr[1])] = attr[2]
}
}
}
}
list = append(list, seg)
}
}
pos = cap[1]
}
if len(htmlStr) > pos {
seg.Cat = 'T'
seg.Str = htmlStr[pos:]
seg.Attr = nil
list = append(list, seg)
}
} else {
list = append(list, HTMLBasicSegmentType{Cat: 'T', Str: htmlStr, Attr: nil})
}
return
}
// HTMLBasicType is used for rendering a very basic subset of HTML. It supports
// only hyperlinks and bold, italic and underscore attributes. In the Link
// structure, the ClrR, ClrG and ClrB fields (0 through 255) define the color
// of hyperlinks. The Bold, Italic and Underscore values define the hyperlink
// style.
type HTMLBasicType struct {
pdf *Fpdf
Link struct {
ClrR, ClrG, ClrB int
Bold, Italic, Underscore bool
}
}
// HTMLBasicNew returns an instance that facilitates writing basic HTML in the
// specified PDF file.
func (f *Fpdf) HTMLBasicNew() (html HTMLBasicType) {
html.pdf = f
html.Link.ClrR, html.Link.ClrG, html.Link.ClrB = 0, 0, 128
html.Link.Bold, html.Link.Italic, html.Link.Underscore = false, false, true
return
}
// Write prints text from the current position using the currently selected
// font. See HTMLBasicNew() to create a receiver that is associated with the
// PDF document instance. The text can be encoded with a basic subset of HTML
// that includes hyperlinks and tags for italic (I), bold (B), underscore
// (U) and center (CENTER) attributes. When the right margin is reached a line
// break occurs and text continues from the left margin. Upon method exit, the
// current position is left at the end of the text.
//
// lineHt indicates the line height in the unit of measure specified in New().
func (html *HTMLBasicType) Write(lineHt float64, htmlStr string) {
var boldLvl, italicLvl, underscoreLvl, linkBold, linkItalic, linkUnderscore int
var textR, textG, textB = html.pdf.GetTextColor()
var hrefStr string
if html.Link.Bold {
linkBold = 1
}
if html.Link.Italic {
linkItalic = 1
}
if html.Link.Underscore {
linkUnderscore = 1
}
setStyle := func(boldAdj, italicAdj, underscoreAdj int) {
styleStr := ""
boldLvl += boldAdj
if boldLvl > 0 {
styleStr += "B"
}
italicLvl += italicAdj
if italicLvl > 0 {
styleStr += "I"
}
underscoreLvl += underscoreAdj
if underscoreLvl > 0 {
styleStr += "U"
}
html.pdf.SetFont("", styleStr, 0)
}
putLink := func(urlStr, txtStr string) {
// Put a hyperlink
html.pdf.SetTextColor(html.Link.ClrR, html.Link.ClrG, html.Link.ClrB)
setStyle(linkBold, linkItalic, linkUnderscore)
html.pdf.WriteLinkString(lineHt, txtStr, urlStr)
setStyle(-linkBold, -linkItalic, -linkUnderscore)
html.pdf.SetTextColor(textR, textG, textB)
}
list := HTMLBasicTokenize(htmlStr)
var ok bool
alignStr := "L"
for _, el := range list {
switch el.Cat {
case 'T':
if len(hrefStr) > 0 {
putLink(hrefStr, el.Str)
hrefStr = ""
} else {
if alignStr == "C" || alignStr == "R" {
html.pdf.WriteAligned(0, lineHt, el.Str, alignStr)
} else {
html.pdf.Write(lineHt, el.Str)
}
}
case 'O':
switch el.Str {
case "b":
setStyle(1, 0, 0)
case "i":
setStyle(0, 1, 0)
case "u":
setStyle(0, 0, 1)
case "br":
html.pdf.Ln(lineHt)
case "center":
html.pdf.Ln(lineHt)
alignStr = "C"
case "right":
html.pdf.Ln(lineHt)
alignStr = "R"
case "left":
html.pdf.Ln(lineHt)
alignStr = "L"
case "a":
hrefStr, ok = el.Attr["href"]
if !ok {
hrefStr = ""
}
}
case 'C':
switch el.Str {
case "b":
setStyle(-1, 0, 0)
case "i":
setStyle(0, -1, 0)
case "u":
setStyle(0, 0, -1)
case "center":
html.pdf.Ln(lineHt)
alignStr = "L"
case "right":
html.pdf.Ln(lineHt)
alignStr = "L"
}
}
}
}

82
vendor/github.com/jung-kurt/gofpdf/label.go generated vendored Normal file
View File

@ -0,0 +1,82 @@
package gofpdf
// Adapted from Nice Numbers for Graph Labels by Paul Heckbert from "Graphics
// Gems", Academic Press, 1990
// Paul Heckbert 2 Dec 88
// https://github.com/erich666/GraphicsGems
// LICENSE
// This code repository predates the concept of Open Source, and predates most
// licenses along such lines. As such, the official license truly is:
// EULA: The Graphics Gems code is copyright-protected. In other words, you
// cannot claim the text of the code as your own and resell it. Using the code
// is permitted in any program, product, or library, non-commercial or
// commercial. Giving credit is not required, though is a nice gesture. The
// code comes as-is, and if there are any flaws or problems with any Gems code,
// nobody involved with Gems - authors, editors, publishers, or webmasters -
// are to be held responsible. Basically, don't be a jerk, and remember that
// anything free comes with no guarantee.
import (
"math"
)
// niceNum returns a "nice" number approximately equal to x. The number is
// rounded if round is true, converted to its ceiling otherwise.
func niceNum(val float64, round bool) float64 {
var nf float64
exp := int(math.Floor(math.Log10(val)))
f := val / math.Pow10(exp)
if round {
switch {
case f < 1.5:
nf = 1
case f < 3.0:
nf = 2
case f < 7.0:
nf = 5
default:
nf = 10
}
} else {
switch {
case f <= 1:
nf = 1
case f <= 2.0:
nf = 2
case f <= 5.0:
nf = 5
default:
nf = 10
}
}
return nf * math.Pow10(exp)
}
// TickmarkPrecision returns an appropriate precision value for label
// formatting.
func TickmarkPrecision(div float64) int {
return int(math.Max(-math.Floor(math.Log10(div)), 0))
}
// Tickmarks returns a slice of tickmarks appropriate for a chart axis and an
// appropriate precision for formatting purposes. The values min and max will
// be contained within the tickmark range.
func Tickmarks(min, max float64) (list []float64, precision int) {
if max > min {
spread := niceNum(max-min, false)
d := niceNum((spread / 4), true)
graphMin := math.Floor(min/d) * d
graphMax := math.Ceil(max/d) * d
precision = TickmarkPrecision(d)
for x := graphMin; x < graphMax+0.5*d; x += d {
list = append(list, x)
}
}
return
}

121
vendor/github.com/jung-kurt/gofpdf/layer.go generated vendored Normal file
View File

@ -0,0 +1,121 @@
/*
* Copyright (c) 2014 Kurt Jung (Gmail: kurt.w.jung)
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package gofpdf
// Routines in this file are translated from
// http://www.fpdf.org/en/script/script97.php
type layerType struct {
name string
visible bool
objNum int // object number
}
type layerRecType struct {
list []layerType
currentLayer int
openLayerPane bool
}
func (f *Fpdf) layerInit() {
f.layer.list = make([]layerType, 0)
f.layer.currentLayer = -1
f.layer.openLayerPane = false
}
// AddLayer defines a layer that can be shown or hidden when the document is
// displayed. name specifies the layer name that the document reader will
// display in the layer list. visible specifies whether the layer will be
// initially visible. The return value is an integer ID that is used in a call
// to BeginLayer().
func (f *Fpdf) AddLayer(name string, visible bool) (layerID int) {
layerID = len(f.layer.list)
f.layer.list = append(f.layer.list, layerType{name: name, visible: visible})
return
}
// BeginLayer is called to begin adding content to the specified layer. All
// content added to the page between a call to BeginLayer and a call to
// EndLayer is added to the layer specified by id. See AddLayer for more
// details.
func (f *Fpdf) BeginLayer(id int) {
f.EndLayer()
if id >= 0 && id < len(f.layer.list) {
f.outf("/OC /OC%d BDC", id)
f.layer.currentLayer = id
}
}
// EndLayer is called to stop adding content to the currently active layer. See
// BeginLayer for more details.
func (f *Fpdf) EndLayer() {
if f.layer.currentLayer >= 0 {
f.out("EMC")
f.layer.currentLayer = -1
}
}
// OpenLayerPane advises the document reader to open the layer pane when the
// document is initially displayed.
func (f *Fpdf) OpenLayerPane() {
f.layer.openLayerPane = true
}
func (f *Fpdf) layerEndDoc() {
if len(f.layer.list) > 0 {
if f.pdfVersion < "1.5" {
f.pdfVersion = "1.5"
}
}
}
func (f *Fpdf) layerPutLayers() {
for j, l := range f.layer.list {
f.newobj()
f.layer.list[j].objNum = f.n
f.outf("<</Type /OCG /Name %s>>", f.textstring(utf8toutf16(l.name)))
f.out("endobj")
}
}
func (f *Fpdf) layerPutResourceDict() {
if len(f.layer.list) > 0 {
f.out("/Properties <<")
for j, layer := range f.layer.list {
f.outf("/OC%d %d 0 R", j, layer.objNum)
}
f.out(">>")
}
}
func (f *Fpdf) layerPutCatalog() {
if len(f.layer.list) > 0 {
onStr := ""
offStr := ""
for _, layer := range f.layer.list {
onStr += sprintf("%d 0 R ", layer.objNum)
if !layer.visible {
offStr += sprintf("%d 0 R ", layer.objNum)
}
}
f.outf("/OCProperties <</OCGs [%s] /D <</OFF [%s] /Order [%s]>>>>", onStr, offStr, onStr)
if f.layer.openLayerPane {
f.out("/PageMode /UseOC")
}
}
}

213
vendor/github.com/jung-kurt/gofpdf/png.go generated vendored Normal file
View File

@ -0,0 +1,213 @@
/*
* Copyright (c) 2013-2016 Kurt Jung (Gmail: kurt.w.jung)
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package gofpdf
import (
"bytes"
"fmt"
"strings"
)
func (f *Fpdf) pngColorSpace(ct byte) (colspace string, colorVal int) {
colorVal = 1
switch ct {
case 0, 4:
colspace = "DeviceGray"
case 2, 6:
colspace = "DeviceRGB"
colorVal = 3
case 3:
colspace = "Indexed"
default:
f.err = fmt.Errorf("unknown color type in PNG buffer: %d", ct)
}
return
}
func (f *Fpdf) parsepngstream(buf *bytes.Buffer, readdpi bool) (info *ImageInfoType) {
info = f.newImageInfo()
// Check signature
if string(buf.Next(8)) != "\x89PNG\x0d\x0a\x1a\x0a" {
f.err = fmt.Errorf("not a PNG buffer")
return
}
// Read header chunk
_ = buf.Next(4)
if string(buf.Next(4)) != "IHDR" {
f.err = fmt.Errorf("incorrect PNG buffer")
return
}
w := f.readBeInt32(buf)
h := f.readBeInt32(buf)
bpc := f.readByte(buf)
if bpc > 8 {
f.err = fmt.Errorf("16-bit depth not supported in PNG file")
}
ct := f.readByte(buf)
var colspace string
var colorVal int
colspace, colorVal = f.pngColorSpace(ct)
if f.err != nil {
return
}
if f.readByte(buf) != 0 {
f.err = fmt.Errorf("'unknown compression method in PNG buffer")
return
}
if f.readByte(buf) != 0 {
f.err = fmt.Errorf("'unknown filter method in PNG buffer")
return
}
if f.readByte(buf) != 0 {
f.err = fmt.Errorf("interlacing not supported in PNG buffer")
return
}
_ = buf.Next(4)
dp := sprintf("/Predictor 15 /Colors %d /BitsPerComponent %d /Columns %d", colorVal, bpc, w)
// Scan chunks looking for palette, transparency and image data
pal := make([]byte, 0, 32)
var trns []int
data := make([]byte, 0, 32)
loop := true
for loop {
n := int(f.readBeInt32(buf))
// dbg("Loop [%d]", n)
switch string(buf.Next(4)) {
case "PLTE":
// dbg("PLTE")
// Read palette
pal = buf.Next(n)
_ = buf.Next(4)
case "tRNS":
// dbg("tRNS")
// Read transparency info
t := buf.Next(n)
switch ct {
case 0:
trns = []int{int(t[1])} // ord(substr($t,1,1)));
case 2:
trns = []int{int(t[1]), int(t[3]), int(t[5])} // array(ord(substr($t,1,1)), ord(substr($t,3,1)), ord(substr($t,5,1)));
default:
pos := strings.Index(string(t), "\x00")
if pos >= 0 {
trns = []int{pos} // array($pos);
}
}
_ = buf.Next(4)
case "IDAT":
// dbg("IDAT")
// Read image data block
data = append(data, buf.Next(n)...)
_ = buf.Next(4)
case "IEND":
// dbg("IEND")
loop = false
case "pHYs":
// dbg("pHYs")
// png files theoretically support different x/y dpi
// but we ignore files like this
// but if they're the same then we can stamp our info
// object with it
x := int(f.readBeInt32(buf))
y := int(f.readBeInt32(buf))
units := buf.Next(1)[0]
// fmt.Printf("got a pHYs block, x=%d, y=%d, u=%d, readdpi=%t\n",
// x, y, int(units), readdpi)
// only modify the info block if the user wants us to
if x == y && readdpi {
switch units {
// if units is 1 then measurement is px/meter
case 1:
info.dpi = float64(x) / 39.3701 // inches per meter
default:
info.dpi = float64(x)
}
}
_ = buf.Next(4)
default:
// dbg("default")
_ = buf.Next(n + 4)
}
if loop {
loop = n > 0
}
}
if colspace == "Indexed" && len(pal) == 0 {
f.err = fmt.Errorf("missing palette in PNG buffer")
}
info.w = float64(w)
info.h = float64(h)
info.cs = colspace
info.bpc = int(bpc)
info.f = "FlateDecode"
info.dp = dp
info.pal = pal
info.trns = trns
// dbg("ct [%d]", ct)
if ct >= 4 {
// Separate alpha and color channels
var err error
data, err = sliceUncompress(data)
if err != nil {
f.err = err
return
}
var color, alpha bytes.Buffer
if ct == 4 {
// Gray image
width := int(w)
height := int(h)
length := 2 * width
var pos, elPos int
for i := 0; i < height; i++ {
pos = (1 + length) * i
color.WriteByte(data[pos])
alpha.WriteByte(data[pos])
elPos = pos + 1
for k := 0; k < width; k++ {
color.WriteByte(data[elPos])
alpha.WriteByte(data[elPos+1])
elPos += 2
}
}
} else {
// RGB image
width := int(w)
height := int(h)
length := 4 * width
var pos, elPos int
for i := 0; i < height; i++ {
pos = (1 + length) * i
color.WriteByte(data[pos])
alpha.WriteByte(data[pos])
elPos = pos + 1
for k := 0; k < width; k++ {
color.Write(data[elPos : elPos+3])
alpha.WriteByte(data[elPos+3])
elPos += 4
}
}
}
data = sliceCompress(color.Bytes())
info.smask = sliceCompress(alpha.Bytes())
if f.pdfVersion < "1.4" {
f.pdfVersion = "1.4"
}
}
info.data = data
return
}

114
vendor/github.com/jung-kurt/gofpdf/protect.go generated vendored Normal file
View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2013-2014 Kurt Jung (Gmail: kurt.w.jung)
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// PDF protection is adapted from the work of Klemen VODOPIVEC for the fpdf
// product.
package gofpdf
import (
"crypto/md5"
"crypto/rc4"
"encoding/binary"
"math/rand"
)
// Advisory bitflag constants that control document activities
const (
CnProtectPrint = 4
CnProtectModify = 8
CnProtectCopy = 16
CnProtectAnnotForms = 32
)
type protectType struct {
encrypted bool
uValue []byte
oValue []byte
pValue int
padding []byte
encryptionKey []byte
objNum int
rc4cipher *rc4.Cipher
rc4n uint32 // Object number associated with rc4 cipher
}
func (p *protectType) rc4(n uint32, buf *[]byte) {
if p.rc4cipher == nil || p.rc4n != n {
p.rc4cipher, _ = rc4.NewCipher(p.objectKey(n))
p.rc4n = n
}
p.rc4cipher.XORKeyStream(*buf, *buf)
}
func (p *protectType) objectKey(n uint32) []byte {
var nbuf, b []byte
nbuf = make([]byte, 8, 8)
binary.LittleEndian.PutUint32(nbuf, n)
b = append(b, p.encryptionKey...)
b = append(b, nbuf[0], nbuf[1], nbuf[2], 0, 0)
s := md5.Sum(b)
return s[0:10]
}
func oValueGen(userPass, ownerPass []byte) (v []byte) {
var c *rc4.Cipher
tmp := md5.Sum(ownerPass)
c, _ = rc4.NewCipher(tmp[0:5])
size := len(userPass)
v = make([]byte, size, size)
c.XORKeyStream(v, userPass)
return
}
func (p *protectType) uValueGen() (v []byte) {
var c *rc4.Cipher
c, _ = rc4.NewCipher(p.encryptionKey)
size := len(p.padding)
v = make([]byte, size, size)
c.XORKeyStream(v, p.padding)
return
}
func (p *protectType) setProtection(privFlag byte, userPassStr, ownerPassStr string) {
privFlag = 192 | (privFlag & (CnProtectCopy | CnProtectModify | CnProtectPrint | CnProtectAnnotForms))
p.padding = []byte{
0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41,
0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08,
0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80,
0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A,
}
userPass := []byte(userPassStr)
var ownerPass []byte
if ownerPassStr == "" {
ownerPass = make([]byte, 8, 8)
binary.LittleEndian.PutUint64(ownerPass, uint64(rand.Int63()))
} else {
ownerPass = []byte(ownerPassStr)
}
userPass = append(userPass, p.padding...)[0:32]
ownerPass = append(ownerPass, p.padding...)[0:32]
p.encrypted = true
p.oValue = oValueGen(userPass, ownerPass)
var buf []byte
buf = append(buf, userPass...)
buf = append(buf, p.oValue...)
buf = append(buf, privFlag, 0xff, 0xff, 0xff)
sum := md5.Sum(buf)
p.encryptionKey = sum[0:5]
p.uValue = p.uValueGen()
p.pValue = -(int(privFlag^255) + 1)
}

53
vendor/github.com/jung-kurt/gofpdf/splittext.go generated vendored Normal file
View File

@ -0,0 +1,53 @@
package gofpdf
import (
"math"
// "strings"
"unicode"
)
// SplitText splits UTF-8 encoded text into several lines using the current
// font. Each line has its length limited to a maximum width given by w. This
// function can be used to determine the total height of wrapped text for
// vertical placement purposes.
func (f *Fpdf) SplitText(txt string, w float64) (lines []string) {
cw := f.currentFont.Cw
wmax := int(math.Ceil((w - 2*f.cMargin) * 1000 / f.fontSize))
s := []rune(txt) // Return slice of UTF-8 runes
nb := len(s)
for nb > 0 && s[nb-1] == '\n' {
nb--
}
s = s[0:nb]
sep := -1
i := 0
j := 0
l := 0
for i < nb {
c := s[i]
l += cw[c]
if unicode.IsSpace(c) || isChinese(c) {
sep = i
}
if c == '\n' || l > wmax {
if sep == -1 {
if i == j {
i++
}
sep = i
} else {
i = sep + 1
}
lines = append(lines, string(s[j:sep]))
sep = -1
j = i
l = 0
} else {
i++
}
}
if i != j {
lines = append(lines, string(s[j:i]))
}
return lines
}

184
vendor/github.com/jung-kurt/gofpdf/spotcolor.go generated vendored Normal file
View File

@ -0,0 +1,184 @@
// Copyright (c) Kurt Jung (Gmail: kurt.w.jung)
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// Adapted from http://www.fpdf.org/en/script/script89.php by Olivier PLATHEY
package gofpdf
import (
"fmt"
"strings"
)
func byteBound(v byte) byte {
if v > 100 {
return 100
}
return v
}
// AddSpotColor adds an ink-based CMYK color to the gofpdf instance and
// associates it with the specified name. The individual components specify
// percentages ranging from 0 to 100. Values above this are quietly capped to
// 100. An error occurs if the specified name is already associated with a
// color.
func (f *Fpdf) AddSpotColor(nameStr string, c, m, y, k byte) {
if f.err == nil {
_, ok := f.spotColorMap[nameStr]
if !ok {
id := len(f.spotColorMap) + 1
f.spotColorMap[nameStr] = spotColorType{
id: id,
val: cmykColorType{
c: byteBound(c),
m: byteBound(m),
y: byteBound(y),
k: byteBound(k),
},
}
} else {
f.err = fmt.Errorf("name \"%s\" is already associated with a spot color", nameStr)
}
}
}
func (f *Fpdf) getSpotColor(nameStr string) (clr spotColorType, ok bool) {
if f.err == nil {
clr, ok = f.spotColorMap[nameStr]
if !ok {
f.err = fmt.Errorf("spot color name \"%s\" is not registered", nameStr)
}
}
return
}
// SetDrawSpotColor sets the current draw color to the spot color associated
// with nameStr. An error occurs if the name is not associated with a color.
// The value for tint ranges from 0 (no intensity) to 100 (full intensity). It
// is quietly bounded to this range.
func (f *Fpdf) SetDrawSpotColor(nameStr string, tint byte) {
var clr spotColorType
var ok bool
clr, ok = f.getSpotColor(nameStr)
if ok {
f.color.draw.mode = colorModeSpot
f.color.draw.spotStr = nameStr
f.color.draw.str = sprintf("/CS%d CS %.3f SCN", clr.id, float64(byteBound(tint))/100)
if f.page > 0 {
f.out(f.color.draw.str)
}
}
}
// SetFillSpotColor sets the current fill color to the spot color associated
// with nameStr. An error occurs if the name is not associated with a color.
// The value for tint ranges from 0 (no intensity) to 100 (full intensity). It
// is quietly bounded to this range.
func (f *Fpdf) SetFillSpotColor(nameStr string, tint byte) {
var clr spotColorType
var ok bool
clr, ok = f.getSpotColor(nameStr)
if ok {
f.color.fill.mode = colorModeSpot
f.color.fill.spotStr = nameStr
f.color.fill.str = sprintf("/CS%d cs %.3f scn", clr.id, float64(byteBound(tint))/100)
f.colorFlag = f.color.fill.str != f.color.text.str
if f.page > 0 {
f.out(f.color.fill.str)
}
}
}
// SetTextSpotColor sets the current text color to the spot color associated
// with nameStr. An error occurs if the name is not associated with a color.
// The value for tint ranges from 0 (no intensity) to 100 (full intensity). It
// is quietly bounded to this range.
func (f *Fpdf) SetTextSpotColor(nameStr string, tint byte) {
var clr spotColorType
var ok bool
clr, ok = f.getSpotColor(nameStr)
if ok {
f.color.text.mode = colorModeSpot
f.color.text.spotStr = nameStr
f.color.text.str = sprintf("/CS%d cs %.3f scn", clr.id, float64(byteBound(tint))/100)
f.colorFlag = f.color.text.str != f.color.text.str
}
}
func (f *Fpdf) returnSpotColor(clr colorType) (name string, c, m, y, k byte) {
var spotClr spotColorType
var ok bool
name = clr.spotStr
if name != "" {
spotClr, ok = f.getSpotColor(name)
if ok {
c = spotClr.val.c
m = spotClr.val.m
y = spotClr.val.y
k = spotClr.val.k
}
}
return
}
// GetDrawSpotColor returns the most recently used spot color information for
// drawing. This will not be the current drawing color if some other color type
// such as RGB is active. If no spot color has been set for drawing, zero
// values are returned.
func (f *Fpdf) GetDrawSpotColor() (name string, c, m, y, k byte) {
return f.returnSpotColor(f.color.draw)
}
// GetTextSpotColor returns the most recently used spot color information for
// text output. This will not be the current text color if some other color
// type such as RGB is active. If no spot color has been set for text, zero
// values are returned.
func (f *Fpdf) GetTextSpotColor() (name string, c, m, y, k byte) {
return f.returnSpotColor(f.color.text)
}
// GetFillSpotColor returns the most recently used spot color information for
// fill output. This will not be the current fill color if some other color
// type such as RGB is active. If no fill spot color has been set, zero values
// are returned.
func (f *Fpdf) GetFillSpotColor() (name string, c, m, y, k byte) {
return f.returnSpotColor(f.color.fill)
}
func (f *Fpdf) putSpotColors() {
for k, v := range f.spotColorMap {
f.newobj()
f.outf("[/Separation /%s", strings.Replace(k, " ", "#20", -1))
f.out("/DeviceCMYK <<")
f.out("/Range [0 1 0 1 0 1 0 1] /C0 [0 0 0 0] ")
f.outf("/C1 [%.3f %.3f %.3f %.3f] ", float64(v.val.c)/100, float64(v.val.m)/100,
float64(v.val.y)/100, float64(v.val.k)/100)
f.out("/FunctionType 2 /Domain [0 1] /N 1>>]")
f.out("endobj")
v.objID = f.n
f.spotColorMap[k] = v
}
}
func (f *Fpdf) spotColorPutResourceDict() {
f.out("/ColorSpace <<")
for _, clr := range f.spotColorMap {
f.outf("/CS%d %d 0 R", clr.id, clr.objID)
}
f.out(">>")
}

35
vendor/github.com/jung-kurt/gofpdf/subwrite.go generated vendored Normal file
View File

@ -0,0 +1,35 @@
package gofpdf
// Adapted from http://www.fpdf.org/en/script/script61.php by Wirus and released with the FPDF license.
// SubWrite prints text from the current position in the same way as Write().
// ht is the line height in the unit of measure specified in New(). str
// specifies the text to write. subFontSize is the size of the font in points.
// subOffset is the vertical offset of the text in points; a positive value
// indicates a superscript, a negative value indicates a subscript. link is the
// identifier returned by AddLink() or 0 for no internal link. linkStr is a
// target URL or empty for no external link. A non--zero value for link takes
// precedence over linkStr.
//
// The SubWrite example demonstrates this method.
func (f *Fpdf) SubWrite(ht float64, str string, subFontSize, subOffset float64, link int, linkStr string) {
if f.err != nil {
return
}
// resize font
subFontSizeOld := f.fontSizePt
f.SetFontSize(subFontSize)
// reposition y
subOffset = (((subFontSize - subFontSizeOld) / f.k) * 0.3) + (subOffset / f.k)
subX := f.x
subY := f.y
f.SetXY(subX, subY-subOffset)
//Output text
f.write(ht, str, link, linkStr)
// restore y position
subX = f.x
subY = f.y
f.SetXY(subX, subY+subOffset)
// restore font size
f.SetFontSize(subFontSizeOld)
}

246
vendor/github.com/jung-kurt/gofpdf/svgbasic.go generated vendored Normal file
View File

@ -0,0 +1,246 @@
/*
* Copyright (c) 2014 Kurt Jung (Gmail: kurt.w.jung)
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package gofpdf
import (
"encoding/xml"
"fmt"
"io/ioutil"
"strconv"
"strings"
)
var pathCmdSub *strings.Replacer
func init() {
// Handle permitted constructions like "100L200,230"
pathCmdSub = strings.NewReplacer(",", " ",
"L", " L ", "l", " l ",
"C", " C ", "c", " c ",
"M", " M ", "m", " m ",
"H", " H ", "h", " h ",
"V", " V ", "v", " v ",
"Q", " Q ", "q", " q ",
"Z", " Z ", "z", " z ")
}
// SVGBasicSegmentType describes a single curve or position segment
type SVGBasicSegmentType struct {
Cmd byte // See http://www.w3.org/TR/SVG/paths.html for path command structure
Arg [6]float64
}
func absolutizePath(segs []SVGBasicSegmentType) {
var x, y float64
var segPtr *SVGBasicSegmentType
adjust := func(pos int, adjX, adjY float64) {
segPtr.Arg[pos] += adjX
segPtr.Arg[pos+1] += adjY
}
for j, seg := range segs {
segPtr = &segs[j]
if j == 0 && seg.Cmd == 'm' {
segPtr.Cmd = 'M'
}
switch segPtr.Cmd {
case 'M':
x = seg.Arg[0]
y = seg.Arg[1]
case 'm':
adjust(0, x, y)
segPtr.Cmd = 'M'
x = segPtr.Arg[0]
y = segPtr.Arg[1]
case 'L':
x = seg.Arg[0]
y = seg.Arg[1]
case 'l':
adjust(0, x, y)
segPtr.Cmd = 'L'
x = segPtr.Arg[0]
y = segPtr.Arg[1]
case 'C':
x = seg.Arg[4]
y = seg.Arg[5]
case 'c':
adjust(0, x, y)
adjust(2, x, y)
adjust(4, x, y)
segPtr.Cmd = 'C'
x = segPtr.Arg[4]
y = segPtr.Arg[5]
case 'Q':
x = seg.Arg[2]
y = seg.Arg[3]
case 'q':
adjust(0, x, y)
adjust(2, x, y)
segPtr.Cmd = 'Q'
x = segPtr.Arg[2]
y = segPtr.Arg[3]
case 'H':
x = seg.Arg[0]
case 'h':
segPtr.Arg[0] += x
segPtr.Cmd = 'H'
x += seg.Arg[0]
case 'V':
y = seg.Arg[0]
case 'v':
segPtr.Arg[0] += y
segPtr.Cmd = 'V'
y += seg.Arg[0]
case 'z':
segPtr.Cmd = 'Z'
}
}
}
func pathParse(pathStr string) (segs []SVGBasicSegmentType, err error) {
var seg SVGBasicSegmentType
var j, argJ, argCount, prevArgCount int
setup := func(n int) {
// It is not strictly necessary to clear arguments, but result may be clearer
// to caller
for j := 0; j < len(seg.Arg); j++ {
seg.Arg[j] = 0.0
}
argJ = 0
argCount = n
prevArgCount = n
}
var str string
var c byte
pathStr = pathCmdSub.Replace(pathStr)
strList := strings.Fields(pathStr)
count := len(strList)
for j = 0; j < count && err == nil; j++ {
str = strList[j]
if argCount == 0 { // Look for path command or argument continuation
c = str[0]
if c == '-' || (c >= '0' && c <= '9') { // More arguments
if j > 0 {
setup(prevArgCount)
// Repeat previous action
if seg.Cmd == 'M' {
seg.Cmd = 'L'
} else if seg.Cmd == 'm' {
seg.Cmd = 'l'
}
} else {
err = fmt.Errorf("expecting SVG path command at first position, got %s", str)
}
}
}
if err == nil {
if argCount == 0 {
seg.Cmd = str[0]
switch seg.Cmd {
case 'M', 'm': // Absolute/relative moveto: x, y
setup(2)
case 'C', 'c': // Absolute/relative Bézier curve: cx0, cy0, cx1, cy1, x1, y1
setup(6)
case 'H', 'h': // Absolute/relative horizontal line to: x
setup(1)
case 'L', 'l': // Absolute/relative lineto: x, y
setup(2)
case 'Q', 'q': // Absolute/relative quadratic curve: x0, y0, x1, y1
setup(4)
case 'V', 'v': // Absolute/relative vertical line to: y
setup(1)
case 'Z', 'z': // closepath instruction (takes no arguments)
segs = append(segs, seg)
default:
err = fmt.Errorf("expecting SVG path command at position %d, got %s", j, str)
}
} else {
seg.Arg[argJ], err = strconv.ParseFloat(str, 64)
if err == nil {
argJ++
argCount--
if argCount == 0 {
segs = append(segs, seg)
}
}
}
}
}
if err == nil {
if argCount == 0 {
absolutizePath(segs)
} else {
err = fmt.Errorf("expecting additional (%d) numeric arguments", argCount)
}
}
return
}
// SVGBasicType aggregates the information needed to describe a multi-segment
// basic vector image
type SVGBasicType struct {
Wd, Ht float64
Segments [][]SVGBasicSegmentType
}
// SVGBasicParse parses a simple scalable vector graphics (SVG) buffer into a
// descriptor. Only a small subset of the SVG standard, in particular the path
// information generated by jSignature, is supported. The returned path data
// includes only the commands 'M' (absolute moveto: x, y), 'L' (absolute
// lineto: x, y), 'C' (absolute cubic Bézier curve: cx0, cy0, cx1, cy1,
// x1,y1), 'Q' (absolute quadratic Bézier curve: x0, y0, x1, y1) and 'Z'
// (closepath).
func SVGBasicParse(buf []byte) (sig SVGBasicType, err error) {
type pathType struct {
D string `xml:"d,attr"`
}
type srcType struct {
Wd float64 `xml:"width,attr"`
Ht float64 `xml:"height,attr"`
Paths []pathType `xml:"path"`
}
var src srcType
err = xml.Unmarshal(buf, &src)
if err == nil {
if src.Wd > 0 && src.Ht > 0 {
sig.Wd, sig.Ht = src.Wd, src.Ht
var segs []SVGBasicSegmentType
for _, path := range src.Paths {
if err == nil {
segs, err = pathParse(path.D)
if err == nil {
sig.Segments = append(sig.Segments, segs)
}
}
}
} else {
err = fmt.Errorf("unacceptable values for basic SVG extent: %.2f x %.2f",
sig.Wd, sig.Ht)
}
}
return
}
// SVGBasicFileParse parses a simple scalable vector graphics (SVG) file into a
// basic descriptor. The SVGBasicWrite() example demonstrates this method.
func SVGBasicFileParse(svgFileStr string) (sig SVGBasicType, err error) {
var buf []byte
buf, err = ioutil.ReadFile(svgFileStr)
if err == nil {
sig, err = SVGBasicParse(buf)
}
return
}

85
vendor/github.com/jung-kurt/gofpdf/svgwrite.go generated vendored Normal file
View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2014 Kurt Jung (Gmail: kurt.w.jung)
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package gofpdf
// SVGBasicWrite renders the paths encoded in the basic SVG image specified by
// sb. The scale value is used to convert the coordinates in the path to the
// unit of measure specified in New(). The current position (as set with a call
// to SetXY()) is used as the origin of the image. The current line cap style
// (as set with SetLineCapStyle()), line width (as set with SetLineWidth()),
// and draw color (as set with SetDrawColor()) are used in drawing the image
// paths.
func (f *Fpdf) SVGBasicWrite(sb *SVGBasicType, scale float64) {
originX, originY := f.GetXY()
var x, y, newX, newY float64
var cx0, cy0, cx1, cy1 float64
var path []SVGBasicSegmentType
var seg SVGBasicSegmentType
var startX, startY float64
sval := func(origin float64, arg int) float64 {
return origin + scale*seg.Arg[arg]
}
xval := func(arg int) float64 {
return sval(originX, arg)
}
yval := func(arg int) float64 {
return sval(originY, arg)
}
val := func(arg int) (float64, float64) {
return xval(arg), yval(arg + 1)
}
for j := 0; j < len(sb.Segments) && f.Ok(); j++ {
path = sb.Segments[j]
for k := 0; k < len(path) && f.Ok(); k++ {
seg = path[k]
switch seg.Cmd {
case 'M':
x, y = val(0)
startX, startY = x, y
f.SetXY(x, y)
case 'L':
newX, newY = val(0)
f.Line(x, y, newX, newY)
x, y = newX, newY
case 'C':
cx0, cy0 = val(0)
cx1, cy1 = val(2)
newX, newY = val(4)
f.CurveCubic(x, y, cx0, cy0, newX, newY, cx1, cy1, "D")
x, y = newX, newY
case 'Q':
cx0, cy0 = val(0)
newX, newY = val(2)
f.Curve(x, y, cx0, cy0, newX, newY, "D")
x, y = newX, newY
case 'H':
newX = xval(0)
f.Line(x, y, newX, y)
x = newX
case 'V':
newY = yval(0)
f.Line(x, y, x, newY)
y = newY
case 'Z':
f.Line(x, y, startX, startY)
x, y = startX, startY
default:
f.SetErrorf("Unexpected path command '%c'", seg.Cmd)
}
}
}
}

273
vendor/github.com/jung-kurt/gofpdf/template.go generated vendored Normal file
View File

@ -0,0 +1,273 @@
package gofpdf
/*
* Copyright (c) 2015 Kurt Jung (Gmail: kurt.w.jung),
* Marcus Downing, Jan Slabon (Setasign)
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
import (
"encoding/gob"
"sort"
)
// CreateTemplate defines a new template using the current page size.
func (f *Fpdf) CreateTemplate(fn func(*Tpl)) Template {
return newTpl(PointType{0, 0}, f.curPageSize, f.defOrientation, f.unitStr, f.fontDirStr, fn, f)
}
// CreateTemplateCustom starts a template, using the given bounds.
func (f *Fpdf) CreateTemplateCustom(corner PointType, size SizeType, fn func(*Tpl)) Template {
return newTpl(corner, size, f.defOrientation, f.unitStr, f.fontDirStr, fn, f)
}
// CreateTemplate creates a template that is not attached to any document.
//
// This function is deprecated; it incorrectly assumes that a page with a width
// smaller than its height is oriented in portrait mode, otherwise it assumes
// landscape mode. This causes problems when placing the template in a master
// document where this condition does not apply. CreateTpl() is a similar
// function that lets you specify the orientation to avoid this problem.
func CreateTemplate(corner PointType, size SizeType, unitStr, fontDirStr string, fn func(*Tpl)) Template {
orientationStr := "p"
if size.Wd > size.Ht {
orientationStr = "l"
}
return CreateTpl(corner, size, orientationStr, unitStr, fontDirStr, fn)
}
// CreateTpl creates a template not attached to any document
func CreateTpl(corner PointType, size SizeType, orientationStr, unitStr, fontDirStr string, fn func(*Tpl)) Template {
return newTpl(corner, size, orientationStr, unitStr, fontDirStr, fn, nil)
}
// UseTemplate adds a template to the current page or another template,
// using the size and position at which it was originally written.
func (f *Fpdf) UseTemplate(t Template) {
if t == nil {
f.SetErrorf("template is nil")
return
}
corner, size := t.Size()
f.UseTemplateScaled(t, corner, size)
}
// UseTemplateScaled adds a template to the current page or another template,
// using the given page coordinates.
func (f *Fpdf) UseTemplateScaled(t Template, corner PointType, size SizeType) {
if t == nil {
f.SetErrorf("template is nil")
return
}
// You have to add at least a page first
if f.page <= 0 {
f.SetErrorf("cannot use a template without first adding a page")
return
}
// make a note of the fact that we actually use this template, as well as any other templates,
// images or fonts it uses
f.templates[t.ID()] = t
for _, tt := range t.Templates() {
f.templates[tt.ID()] = tt
}
for name, ti := range t.Images() {
name = sprintf("t%s-%s", t.ID(), name)
f.images[name] = ti
}
// template data
_, templateSize := t.Size()
scaleX := size.Wd / templateSize.Wd
scaleY := size.Ht / templateSize.Ht
tx := corner.X * f.k
ty := (f.curPageSize.Ht - corner.Y - size.Ht) * f.k
f.outf("q %.4f 0 0 %.4f %.4f %.4f cm", scaleX, scaleY, tx, ty) // Translate
f.outf("/TPL%s Do Q", t.ID())
}
// Template is an object that can be written to, then used and re-used any number of times within a document.
type Template interface {
ID() string
Size() (PointType, SizeType)
Bytes() []byte
Images() map[string]*ImageInfoType
Templates() []Template
NumPages() int
FromPage(int) (Template, error)
FromPages() []Template
Serialize() ([]byte, error)
gob.GobDecoder
gob.GobEncoder
}
func (f *Fpdf) templateFontCatalog() {
var keyList []string
var font fontDefType
var key string
f.out("/Font <<")
for key = range f.fonts {
keyList = append(keyList, key)
}
if f.catalogSort {
sort.Strings(keyList)
}
for _, key = range keyList {
font = f.fonts[key]
f.outf("/F%s %d 0 R", font.i, font.N)
}
f.out(">>")
}
// putTemplates writes the templates to the PDF
func (f *Fpdf) putTemplates() {
filter := ""
if f.compress {
filter = "/Filter /FlateDecode "
}
templates := sortTemplates(f.templates, f.catalogSort)
var t Template
for _, t = range templates {
corner, size := t.Size()
f.newobj()
f.templateObjects[t.ID()] = f.n
f.outf("<<%s/Type /XObject", filter)
f.out("/Subtype /Form")
f.out("/Formtype 1")
f.outf("/BBox [%.2f %.2f %.2f %.2f]", corner.X*f.k, corner.Y*f.k, (corner.X+size.Wd)*f.k, (corner.Y+size.Ht)*f.k)
if corner.X != 0 || corner.Y != 0 {
f.outf("/Matrix [1 0 0 1 %.5f %.5f]", -corner.X*f.k*2, corner.Y*f.k*2)
}
// Template's resource dictionary
f.out("/Resources ")
f.out("<</ProcSet [/PDF /Text /ImageB /ImageC /ImageI]")
f.templateFontCatalog()
tImages := t.Images()
tTemplates := t.Templates()
if len(tImages) > 0 || len(tTemplates) > 0 {
f.out("/XObject <<")
{
var key string
var keyList []string
var ti *ImageInfoType
for key = range tImages {
keyList = append(keyList, key)
}
if gl.catalogSort {
sort.Strings(keyList)
}
for _, key = range keyList {
// for _, ti := range tImages {
ti = tImages[key]
f.outf("/I%s %d 0 R", ti.i, ti.n)
}
}
for _, tt := range tTemplates {
id := tt.ID()
if objID, ok := f.templateObjects[id]; ok {
f.outf("/TPL%s %d 0 R", id, objID)
}
}
f.out(">>")
}
f.out(">>")
// Write the template's byte stream
buffer := t.Bytes()
// fmt.Println("Put template bytes", string(buffer[:]))
if f.compress {
buffer = sliceCompress(buffer)
}
f.outf("/Length %d >>", len(buffer))
f.putstream(buffer)
f.out("endobj")
}
}
func templateKeyList(mp map[string]Template, sort bool) (keyList []string) {
var key string
for key = range mp {
keyList = append(keyList, key)
}
if sort {
gensort(len(keyList),
func(a, b int) bool {
return keyList[a] < keyList[b]
},
func(a, b int) {
keyList[a], keyList[b] = keyList[b], keyList[a]
})
}
return
}
// sortTemplates puts templates in a suitable order based on dependices
func sortTemplates(templates map[string]Template, catalogSort bool) []Template {
chain := make([]Template, 0, len(templates)*2)
// build a full set of dependency chains
var keyList []string
var key string
var t Template
keyList = templateKeyList(templates, catalogSort)
for _, key = range keyList {
t = templates[key]
tlist := templateChainDependencies(t)
for _, tt := range tlist {
if tt != nil {
chain = append(chain, tt)
}
}
}
// reduce that to make a simple list
sorted := make([]Template, 0, len(templates))
chain:
for _, t := range chain {
for _, already := range sorted {
if t == already {
continue chain
}
}
sorted = append(sorted, t)
}
return sorted
}
// templateChainDependencies is a recursive function for determining the full chain of template dependencies
func templateChainDependencies(template Template) []Template {
requires := template.Templates()
chain := make([]Template, len(requires)*2)
for _, req := range requires {
chain = append(chain, templateChainDependencies(req)...)
}
chain = append(chain, template)
return chain
}
// < 0002640 31 20 31 32 20 30 20 52 0a 2f 54 50 4c 32 20 31 |1 12 0 R./TPL2 1|
// < 0002650 35 20 30 20 52 0a 2f 54 50 4c 31 20 31 34 20 30 |5 0 R./TPL1 14 0|
// > 0002640 31 20 31 32 20 30 20 52 0a 2f 54 50 4c 31 20 31 |1 12 0 R./TPL1 1|
// > 0002650 34 20 30 20 52 0a 2f 54 50 4c 32 20 31 35 20 30 |4 0 R./TPL2 15 0|

299
vendor/github.com/jung-kurt/gofpdf/template_impl.go generated vendored Normal file
View File

@ -0,0 +1,299 @@
package gofpdf
import (
"bytes"
"crypto/sha1"
"encoding/gob"
"errors"
"fmt"
)
/*
* Copyright (c) 2015 Kurt Jung (Gmail: kurt.w.jung),
* Marcus Downing, Jan Slabon (Setasign)
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// newTpl creates a template, copying graphics settings from a template if one is given
func newTpl(corner PointType, size SizeType, orientationStr, unitStr, fontDirStr string, fn func(*Tpl), copyFrom *Fpdf) Template {
sizeStr := ""
fpdf := fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr, size)
tpl := Tpl{*fpdf}
if copyFrom != nil {
tpl.loadParamsFromFpdf(copyFrom)
}
tpl.Fpdf.AddPage()
fn(&tpl)
bytes := make([][]byte, len(tpl.Fpdf.pages))
// skip the first page as it will always be empty
for x := 1; x < len(bytes); x++ {
bytes[x] = tpl.Fpdf.pages[x].Bytes()
}
templates := make([]Template, 0, len(tpl.Fpdf.templates))
for _, key := range templateKeyList(tpl.Fpdf.templates, true) {
templates = append(templates, tpl.Fpdf.templates[key])
}
images := tpl.Fpdf.images
template := FpdfTpl{corner, size, bytes, images, templates, tpl.Fpdf.page}
return &template
}
// FpdfTpl is a concrete implementation of the Template interface.
type FpdfTpl struct {
corner PointType
size SizeType
bytes [][]byte
images map[string]*ImageInfoType
templates []Template
page int
}
// ID returns the global template identifier
func (t *FpdfTpl) ID() string {
return fmt.Sprintf("%x", sha1.Sum(t.Bytes()))
}
// Size gives the bounding dimensions of this template
func (t *FpdfTpl) Size() (corner PointType, size SizeType) {
return t.corner, t.size
}
// Bytes returns the actual template data, not including resources
func (t *FpdfTpl) Bytes() []byte {
return t.bytes[t.page]
}
// FromPage creates a new template from a specific Page
func (t *FpdfTpl) FromPage(page int) (Template, error) {
// pages start at 1
if page == 0 {
return nil, errors.New("Pages start at 1 No template will have a page 0")
}
if page > t.NumPages() {
return nil, fmt.Errorf("The template does not have a page %d", page)
}
// if it is already pointing to the correct page
// there is no need to create a new template
if t.page == page {
return t, nil
}
t2 := *t
t2.page = page
return &t2, nil
}
// FromPages creates a template slice with all the pages within a template.
func (t *FpdfTpl) FromPages() []Template {
p := make([]Template, t.NumPages())
for x := 1; x <= t.NumPages(); x++ {
// the only error is when accessing a
// non existing template... that can't happen
// here
p[x-1], _ = t.FromPage(x)
}
return p
}
// Images returns a list of the images used in this template
func (t *FpdfTpl) Images() map[string]*ImageInfoType {
return t.images
}
// Templates returns a list of templates used in this template
func (t *FpdfTpl) Templates() []Template {
return t.templates
}
// NumPages returns the number of available pages within the template. Look at FromPage and FromPages on access to that content.
func (t *FpdfTpl) NumPages() int {
// the first page is empty to
// make the pages begin at one
return len(t.bytes) - 1
}
// Serialize turns a template into a byte string for later deserialization
func (t *FpdfTpl) Serialize() ([]byte, error) {
b := new(bytes.Buffer)
enc := gob.NewEncoder(b)
err := enc.Encode(t)
return b.Bytes(), err
}
// DeserializeTemplate creaties a template from a previously serialized
// template
func DeserializeTemplate(b []byte) (Template, error) {
tpl := new(FpdfTpl)
dec := gob.NewDecoder(bytes.NewBuffer(b))
err := dec.Decode(tpl)
return tpl, err
}
// childrenImages returns the next layer of children images, it doesn't dig into
// children of children. Applies template namespace to keys to ensure
// no collisions. See UseTemplateScaled
func (t *FpdfTpl) childrenImages() map[string]*ImageInfoType {
childrenImgs := make(map[string]*ImageInfoType)
for x := 0; x < len(t.templates); x++ {
imgs := t.templates[x].Images()
for key, val := range imgs {
name := sprintf("t%s-%s", t.templates[x].ID(), key)
childrenImgs[name] = val
}
}
return childrenImgs
}
// childrensTemplates returns the next layer of children templates, it doesn't dig into
// children of children.
func (t *FpdfTpl) childrensTemplates() []Template {
childrenTmpls := make([]Template, 0)
for x := 0; x < len(t.templates); x++ {
tmpls := t.templates[x].Templates()
childrenTmpls = append(childrenTmpls, tmpls...)
}
return childrenTmpls
}
// GobEncode encodes the receiving template into a byte buffer. Use GobDecode
// to decode the byte buffer back to a template.
func (t *FpdfTpl) GobEncode() ([]byte, error) {
w := new(bytes.Buffer)
encoder := gob.NewEncoder(w)
childrensTemplates := t.childrensTemplates()
firstClassTemplates := make([]Template, 0)
found_continue:
for x := 0; x < len(t.templates); x++ {
for y := 0; y < len(childrensTemplates); y++ {
if childrensTemplates[y].ID() == t.templates[x].ID() {
continue found_continue
}
}
firstClassTemplates = append(firstClassTemplates, t.templates[x])
}
err := encoder.Encode(firstClassTemplates)
childrenImgs := t.childrenImages()
firstClassImgs := make(map[string]*ImageInfoType)
for key, img := range t.images {
if _, ok := childrenImgs[key]; !ok {
firstClassImgs[key] = img
}
}
if err == nil {
err = encoder.Encode(firstClassImgs)
}
if err == nil {
err = encoder.Encode(t.corner)
}
if err == nil {
err = encoder.Encode(t.size)
}
if err == nil {
err = encoder.Encode(t.bytes)
}
if err == nil {
err = encoder.Encode(t.page)
}
return w.Bytes(), err
}
// GobDecode decodes the specified byte buffer into the receiving template.
func (t *FpdfTpl) GobDecode(buf []byte) error {
r := bytes.NewBuffer(buf)
decoder := gob.NewDecoder(r)
firstClassTemplates := make([]*FpdfTpl, 0)
err := decoder.Decode(&firstClassTemplates)
t.templates = make([]Template, len(firstClassTemplates))
for x := 0; x < len(t.templates); x++ {
t.templates[x] = Template(firstClassTemplates[x])
}
firstClassImages := t.childrenImages()
t.templates = append(t.childrensTemplates(), t.templates...)
t.images = make(map[string]*ImageInfoType)
if err == nil {
err = decoder.Decode(&t.images)
}
for k, v := range firstClassImages {
t.images[k] = v
}
if err == nil {
err = decoder.Decode(&t.corner)
}
if err == nil {
err = decoder.Decode(&t.size)
}
if err == nil {
err = decoder.Decode(&t.bytes)
}
if err == nil {
err = decoder.Decode(&t.page)
}
return err
}
// Tpl is an Fpdf used for writing a template. It has most of the facilities of
// an Fpdf, but cannot add more pages. Tpl is used directly only during the
// limited time a template is writable.
type Tpl struct {
Fpdf
}
func (t *Tpl) loadParamsFromFpdf(f *Fpdf) {
t.Fpdf.compress = false
t.Fpdf.k = f.k
t.Fpdf.x = f.x
t.Fpdf.y = f.y
t.Fpdf.lineWidth = f.lineWidth
t.Fpdf.capStyle = f.capStyle
t.Fpdf.joinStyle = f.joinStyle
t.Fpdf.color.draw = f.color.draw
t.Fpdf.color.fill = f.color.fill
t.Fpdf.color.text = f.color.text
t.Fpdf.fonts = f.fonts
t.Fpdf.currentFont = f.currentFont
t.Fpdf.fontFamily = f.fontFamily
t.Fpdf.fontSize = f.fontSize
t.Fpdf.fontSizePt = f.fontSizePt
t.Fpdf.fontStyle = f.fontStyle
t.Fpdf.ws = f.ws
}

374
vendor/github.com/jung-kurt/gofpdf/ttfparser.go generated vendored Normal file
View File

@ -0,0 +1,374 @@
/*
* Copyright (c) 2013 Kurt Jung (Gmail: kurt.w.jung)
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package gofpdf
// Utility to parse TTF font files
// Version: 1.0
// Date: 2011-06-18
// Author: Olivier PLATHEY
// Port to Go: Kurt Jung, 2013-07-15
import (
"encoding/binary"
"fmt"
"os"
"regexp"
"strings"
)
// TtfType contains metrics of a TrueType font.
type TtfType struct {
Embeddable bool
UnitsPerEm uint16
PostScriptName string
Bold bool
ItalicAngle int16
IsFixedPitch bool
TypoAscender int16
TypoDescender int16
UnderlinePosition int16
UnderlineThickness int16
Xmin, Ymin, Xmax, Ymax int16
CapHeight int16
Widths []uint16
Chars map[uint16]uint16
}
type ttfParser struct {
rec TtfType
f *os.File
tables map[string]uint32
numberOfHMetrics uint16
numGlyphs uint16
}
// TtfParse extracts various metrics from a TrueType font file.
func TtfParse(fileStr string) (TtfRec TtfType, err error) {
var t ttfParser
t.f, err = os.Open(fileStr)
if err != nil {
return
}
version, err := t.ReadStr(4)
if err != nil {
return
}
if version == "OTTO" {
err = fmt.Errorf("fonts based on PostScript outlines are not supported")
return
}
if version != "\x00\x01\x00\x00" {
err = fmt.Errorf("unrecognized file format")
return
}
numTables := int(t.ReadUShort())
t.Skip(3 * 2) // searchRange, entrySelector, rangeShift
t.tables = make(map[string]uint32)
var tag string
for j := 0; j < numTables; j++ {
tag, err = t.ReadStr(4)
if err != nil {
return
}
t.Skip(4) // checkSum
offset := t.ReadULong()
t.Skip(4) // length
t.tables[tag] = offset
}
err = t.ParseComponents()
if err != nil {
return
}
t.f.Close()
TtfRec = t.rec
return
}
func (t *ttfParser) ParseComponents() (err error) {
err = t.ParseHead()
if err == nil {
err = t.ParseHhea()
if err == nil {
err = t.ParseMaxp()
if err == nil {
err = t.ParseHmtx()
if err == nil {
err = t.ParseCmap()
if err == nil {
err = t.ParseName()
if err == nil {
err = t.ParseOS2()
if err == nil {
err = t.ParsePost()
}
}
}
}
}
}
}
return
}
func (t *ttfParser) ParseHead() (err error) {
err = t.Seek("head")
t.Skip(3 * 4) // version, fontRevision, checkSumAdjustment
magicNumber := t.ReadULong()
if magicNumber != 0x5F0F3CF5 {
err = fmt.Errorf("incorrect magic number")
return
}
t.Skip(2) // flags
t.rec.UnitsPerEm = t.ReadUShort()
t.Skip(2 * 8) // created, modified
t.rec.Xmin = t.ReadShort()
t.rec.Ymin = t.ReadShort()
t.rec.Xmax = t.ReadShort()
t.rec.Ymax = t.ReadShort()
return
}
func (t *ttfParser) ParseHhea() (err error) {
err = t.Seek("hhea")
if err == nil {
t.Skip(4 + 15*2)
t.numberOfHMetrics = t.ReadUShort()
}
return
}
func (t *ttfParser) ParseMaxp() (err error) {
err = t.Seek("maxp")
if err == nil {
t.Skip(4)
t.numGlyphs = t.ReadUShort()
}
return
}
func (t *ttfParser) ParseHmtx() (err error) {
err = t.Seek("hmtx")
if err == nil {
t.rec.Widths = make([]uint16, 0, 8)
for j := uint16(0); j < t.numberOfHMetrics; j++ {
t.rec.Widths = append(t.rec.Widths, t.ReadUShort())
t.Skip(2) // lsb
}
if t.numberOfHMetrics < t.numGlyphs {
lastWidth := t.rec.Widths[t.numberOfHMetrics-1]
for j := t.numberOfHMetrics; j < t.numGlyphs; j++ {
t.rec.Widths = append(t.rec.Widths, lastWidth)
}
}
}
return
}
func (t *ttfParser) ParseCmap() (err error) {
var offset int64
if err = t.Seek("cmap"); err != nil {
return
}
t.Skip(2) // version
numTables := int(t.ReadUShort())
offset31 := int64(0)
for j := 0; j < numTables; j++ {
platformID := t.ReadUShort()
encodingID := t.ReadUShort()
offset = int64(t.ReadULong())
if platformID == 3 && encodingID == 1 {
offset31 = offset
}
}
if offset31 == 0 {
err = fmt.Errorf("no Unicode encoding found")
return
}
startCount := make([]uint16, 0, 8)
endCount := make([]uint16, 0, 8)
idDelta := make([]int16, 0, 8)
idRangeOffset := make([]uint16, 0, 8)
t.rec.Chars = make(map[uint16]uint16)
t.f.Seek(int64(t.tables["cmap"])+offset31, os.SEEK_SET)
format := t.ReadUShort()
if format != 4 {
err = fmt.Errorf("unexpected subtable format: %d", format)
return
}
t.Skip(2 * 2) // length, language
segCount := int(t.ReadUShort() / 2)
t.Skip(3 * 2) // searchRange, entrySelector, rangeShift
for j := 0; j < segCount; j++ {
endCount = append(endCount, t.ReadUShort())
}
t.Skip(2) // reservedPad
for j := 0; j < segCount; j++ {
startCount = append(startCount, t.ReadUShort())
}
for j := 0; j < segCount; j++ {
idDelta = append(idDelta, t.ReadShort())
}
offset, _ = t.f.Seek(int64(0), os.SEEK_CUR)
for j := 0; j < segCount; j++ {
idRangeOffset = append(idRangeOffset, t.ReadUShort())
}
for j := 0; j < segCount; j++ {
c1 := startCount[j]
c2 := endCount[j]
d := idDelta[j]
ro := idRangeOffset[j]
if ro > 0 {
t.f.Seek(offset+2*int64(j)+int64(ro), os.SEEK_SET)
}
for c := c1; c <= c2; c++ {
if c == 0xFFFF {
break
}
var gid int32
if ro > 0 {
gid = int32(t.ReadUShort())
if gid > 0 {
gid += int32(d)
}
} else {
gid = int32(c) + int32(d)
}
if gid >= 65536 {
gid -= 65536
}
if gid > 0 {
t.rec.Chars[c] = uint16(gid)
}
}
}
return
}
func (t *ttfParser) ParseName() (err error) {
err = t.Seek("name")
if err == nil {
tableOffset, _ := t.f.Seek(0, os.SEEK_CUR)
t.rec.PostScriptName = ""
t.Skip(2) // format
count := t.ReadUShort()
stringOffset := t.ReadUShort()
for j := uint16(0); j < count && t.rec.PostScriptName == ""; j++ {
t.Skip(3 * 2) // platformID, encodingID, languageID
nameID := t.ReadUShort()
length := t.ReadUShort()
offset := t.ReadUShort()
if nameID == 6 {
// PostScript name
t.f.Seek(int64(tableOffset)+int64(stringOffset)+int64(offset), os.SEEK_SET)
var s string
s, err = t.ReadStr(int(length))
if err != nil {
return
}
s = strings.Replace(s, "\x00", "", -1)
var re *regexp.Regexp
if re, err = regexp.Compile("[(){}<> /%[\\]]"); err != nil {
return
}
t.rec.PostScriptName = re.ReplaceAllString(s, "")
}
}
if t.rec.PostScriptName == "" {
err = fmt.Errorf("the name PostScript was not found")
}
}
return
}
func (t *ttfParser) ParseOS2() (err error) {
err = t.Seek("OS/2")
if err == nil {
version := t.ReadUShort()
t.Skip(3 * 2) // xAvgCharWidth, usWeightClass, usWidthClass
fsType := t.ReadUShort()
t.rec.Embeddable = (fsType != 2) && (fsType&0x200) == 0
t.Skip(11*2 + 10 + 4*4 + 4)
fsSelection := t.ReadUShort()
t.rec.Bold = (fsSelection & 32) != 0
t.Skip(2 * 2) // usFirstCharIndex, usLastCharIndex
t.rec.TypoAscender = t.ReadShort()
t.rec.TypoDescender = t.ReadShort()
if version >= 2 {
t.Skip(3*2 + 2*4 + 2)
t.rec.CapHeight = t.ReadShort()
} else {
t.rec.CapHeight = 0
}
}
return
}
func (t *ttfParser) ParsePost() (err error) {
err = t.Seek("post")
if err == nil {
t.Skip(4) // version
t.rec.ItalicAngle = t.ReadShort()
t.Skip(2) // Skip decimal part
t.rec.UnderlinePosition = t.ReadShort()
t.rec.UnderlineThickness = t.ReadShort()
t.rec.IsFixedPitch = t.ReadULong() != 0
}
return
}
func (t *ttfParser) Seek(tag string) (err error) {
ofs, ok := t.tables[tag]
if ok {
t.f.Seek(int64(ofs), os.SEEK_SET)
} else {
err = fmt.Errorf("table not found: %s", tag)
}
return
}
func (t *ttfParser) Skip(n int) {
t.f.Seek(int64(n), os.SEEK_CUR)
}
func (t *ttfParser) ReadStr(length int) (str string, err error) {
var n int
buf := make([]byte, length)
n, err = t.f.Read(buf)
if err == nil {
if n == length {
str = string(buf)
} else {
err = fmt.Errorf("unable to read %d bytes", length)
}
}
return
}
func (t *ttfParser) ReadUShort() (val uint16) {
binary.Read(t.f, binary.BigEndian, &val)
return
}
func (t *ttfParser) ReadShort() (val int16) {
binary.Read(t.f, binary.BigEndian, &val)
return
}
func (t *ttfParser) ReadULong() (val uint32) {
binary.Read(t.f, binary.BigEndian, &val)
return
}

1153
vendor/github.com/jung-kurt/gofpdf/utf8fontfile.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

454
vendor/github.com/jung-kurt/gofpdf/util.go generated vendored Normal file
View File

@ -0,0 +1,454 @@
/*
* Copyright (c) 2013 Kurt Jung (Gmail: kurt.w.jung)
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
package gofpdf
import (
"bufio"
"bytes"
"compress/zlib"
"fmt"
"io"
"math"
"os"
"path/filepath"
"strings"
)
func round(f float64) int {
if f < 0 {
return -int(math.Floor(-f + 0.5))
}
return int(math.Floor(f + 0.5))
}
func sprintf(fmtStr string, args ...interface{}) string {
return fmt.Sprintf(fmtStr, args...)
}
// fileExist returns true if the specified normal file exists
func fileExist(filename string) (ok bool) {
info, err := os.Stat(filename)
if err == nil {
if ^os.ModePerm&info.Mode() == 0 {
ok = true
}
}
return ok
}
// fileSize returns the size of the specified file; ok will be false
// if the file does not exist or is not an ordinary file
func fileSize(filename string) (size int64, ok bool) {
info, err := os.Stat(filename)
ok = err == nil
if ok {
size = info.Size()
}
return
}
// bufferFromReader returns a new buffer populated with the contents of the specified Reader
func bufferFromReader(r io.Reader) (b *bytes.Buffer, err error) {
b = new(bytes.Buffer)
_, err = b.ReadFrom(r)
return
}
// slicesEqual returns true if the two specified float slices are equal
func slicesEqual(a, b []float64) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
// sliceCompress returns a zlib-compressed copy of the specified byte array
func sliceCompress(data []byte) []byte {
var buf bytes.Buffer
cmp, _ := zlib.NewWriterLevel(&buf, zlib.BestSpeed)
cmp.Write(data)
cmp.Close()
return buf.Bytes()
}
// sliceUncompress returns an uncompressed copy of the specified zlib-compressed byte array
func sliceUncompress(data []byte) (outData []byte, err error) {
inBuf := bytes.NewReader(data)
r, err := zlib.NewReader(inBuf)
defer r.Close()
if err == nil {
var outBuf bytes.Buffer
_, err = outBuf.ReadFrom(r)
if err == nil {
outData = outBuf.Bytes()
}
}
return
}
// utf8toutf16 converts UTF-8 to UTF-16BE; from http://www.fpdf.org/
func utf8toutf16(s string, withBOM ...bool) string {
bom := true
if len(withBOM) > 0 {
bom = withBOM[0]
}
res := make([]byte, 0, 8)
if bom {
res = append(res, 0xFE, 0xFF)
}
nb := len(s)
i := 0
for i < nb {
c1 := byte(s[i])
i++
switch {
case c1 >= 224:
// 3-byte character
c2 := byte(s[i])
i++
c3 := byte(s[i])
i++
res = append(res, ((c1&0x0F)<<4)+((c2&0x3C)>>2),
((c2&0x03)<<6)+(c3&0x3F))
case c1 >= 192:
// 2-byte character
c2 := byte(s[i])
i++
res = append(res, ((c1 & 0x1C) >> 2),
((c1&0x03)<<6)+(c2&0x3F))
default:
// Single-byte character
res = append(res, 0, c1)
}
}
return string(res)
}
// intIf returns a if cnd is true, otherwise b
func intIf(cnd bool, a, b int) int {
if cnd {
return a
}
return b
}
// strIf returns aStr if cnd is true, otherwise bStr
func strIf(cnd bool, aStr, bStr string) string {
if cnd {
return aStr
}
return bStr
}
// doNothing returns the passed string with no translation.
func doNothing(s string) string {
return s
}
// Dump the internals of the specified values
// func dump(fileStr string, a ...interface{}) {
// fl, err := os.OpenFile(fileStr, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
// if err == nil {
// fmt.Fprintf(fl, "----------------\n")
// spew.Fdump(fl, a...)
// fl.Close()
// }
// }
func repClosure(m map[rune]byte) func(string) string {
var buf bytes.Buffer
return func(str string) string {
var ch byte
var ok bool
buf.Truncate(0)
for _, r := range str {
if r < 0x80 {
ch = byte(r)
} else {
ch, ok = m[r]
if !ok {
ch = byte('.')
}
}
buf.WriteByte(ch)
}
return buf.String()
}
}
// UnicodeTranslator returns a function that can be used to translate, where
// possible, utf-8 strings to a form that is compatible with the specified code
// page. The returned function accepts a string and returns a string.
//
// r is a reader that should read a buffer made up of content lines that
// pertain to the code page of interest. Each line is made up of three
// whitespace separated fields. The first begins with "!" and is followed by
// two hexadecimal digits that identify the glyph position in the code page of
// interest. The second field begins with "U+" and is followed by the unicode
// code point value. The third is the glyph name. A number of these code page
// map files are packaged with the gfpdf library in the font directory.
//
// An error occurs only if a line is read that does not conform to the expected
// format. In this case, the returned function is valid but does not perform
// any rune translation.
func UnicodeTranslator(r io.Reader) (f func(string) string, err error) {
m := make(map[rune]byte)
var uPos, cPos uint32
var lineStr, nameStr string
sc := bufio.NewScanner(r)
for sc.Scan() {
lineStr = sc.Text()
lineStr = strings.TrimSpace(lineStr)
if len(lineStr) > 0 {
_, err = fmt.Sscanf(lineStr, "!%2X U+%4X %s", &cPos, &uPos, &nameStr)
if err == nil {
if cPos >= 0x80 {
m[rune(uPos)] = byte(cPos)
}
}
}
}
if err == nil {
f = repClosure(m)
} else {
f = doNothing
}
return
}
// UnicodeTranslatorFromFile returns a function that can be used to translate,
// where possible, utf-8 strings to a form that is compatible with the
// specified code page. See UnicodeTranslator for more details.
//
// fileStr identifies a font descriptor file that maps glyph positions to names.
//
// If an error occurs reading the file, the returned function is valid but does
// not perform any rune translation.
func UnicodeTranslatorFromFile(fileStr string) (f func(string) string, err error) {
var fl *os.File
fl, err = os.Open(fileStr)
if err == nil {
f, err = UnicodeTranslator(fl)
fl.Close()
} else {
f = doNothing
}
return
}
// UnicodeTranslatorFromDescriptor returns a function that can be used to
// translate, where possible, utf-8 strings to a form that is compatible with
// the specified code page. See UnicodeTranslator for more details.
//
// cpStr identifies a code page. A descriptor file in the font directory, set
// with the fontDirStr argument in the call to New(), should have this name
// plus the extension ".map". If cpStr is empty, it will be replaced with
// "cp1252", the gofpdf code page default.
//
// If an error occurs reading the descriptor, the returned function is valid
// but does not perform any rune translation.
//
// The CellFormat_codepage example demonstrates this method.
func (f *Fpdf) UnicodeTranslatorFromDescriptor(cpStr string) (rep func(string) string) {
var str string
var ok bool
if f.err == nil {
if len(cpStr) == 0 {
cpStr = "cp1252"
}
str, ok = embeddedMapList[cpStr]
if ok {
rep, f.err = UnicodeTranslator(strings.NewReader(str))
} else {
rep, f.err = UnicodeTranslatorFromFile(filepath.Join(f.fontpath, cpStr) + ".map")
}
} else {
rep = doNothing
}
return
}
// Transform moves a point by given X, Y offset
func (p *PointType) Transform(x, y float64) PointType {
return PointType{p.X + x, p.Y + y}
}
// Orientation returns the orientation of a given size:
// "P" for portrait, "L" for landscape
func (s *SizeType) Orientation() string {
if s == nil || s.Ht == s.Wd {
return ""
}
if s.Wd > s.Ht {
return "L"
}
return "P"
}
// ScaleBy expands a size by a certain factor
func (s *SizeType) ScaleBy(factor float64) SizeType {
return SizeType{s.Wd * factor, s.Ht * factor}
}
// ScaleToWidth adjusts the height of a size to match the given width
func (s *SizeType) ScaleToWidth(width float64) SizeType {
height := s.Ht * width / s.Wd
return SizeType{width, height}
}
// ScaleToHeight adjusts the width of a size to match the given height
func (s *SizeType) ScaleToHeight(height float64) SizeType {
width := s.Wd * height / s.Ht
return SizeType{width, height}
}
//The untypedKeyMap structure and its methods are copyrighted 2019 by Arteom Korotkiy (Gmail: arteomkorotkiy).
//Imitation of untyped Map Array
type untypedKeyMap struct {
keySet []interface{}
valueSet []int
}
//Get position of key=>value in PHP Array
func (pa *untypedKeyMap) getIndex(key interface{}) int {
if key != nil {
for i, mKey := range pa.keySet {
if mKey == key {
return i
}
}
return -1
}
return -1
}
//Put key=>value in PHP Array
func (pa *untypedKeyMap) put(key interface{}, value int) {
if key == nil {
var i int
for n := 0; ; n++ {
i = pa.getIndex(n)
if i < 0 {
key = n
break
}
}
pa.keySet = append(pa.keySet, key)
pa.valueSet = append(pa.valueSet, value)
} else {
i := pa.getIndex(key)
if i < 0 {
pa.keySet = append(pa.keySet, key)
pa.valueSet = append(pa.valueSet, value)
} else {
pa.valueSet[i] = value
}
}
}
//Delete value in PHP Array
func (pa *untypedKeyMap) delete(key interface{}) {
if pa == nil || pa.keySet == nil || pa.valueSet == nil {
return
}
i := pa.getIndex(key)
if i >= 0 {
if i == 0 {
pa.keySet = pa.keySet[1:]
pa.valueSet = pa.valueSet[1:]
} else if i == len(pa.keySet)-1 {
pa.keySet = pa.keySet[:len(pa.keySet)-1]
pa.valueSet = pa.valueSet[:len(pa.valueSet)-1]
} else {
pa.keySet = append(pa.keySet[:i], pa.keySet[i+1:]...)
pa.valueSet = append(pa.valueSet[:i], pa.valueSet[i+1:]...)
}
}
}
//Get value from PHP Array
func (pa *untypedKeyMap) get(key interface{}) int {
i := pa.getIndex(key)
if i >= 0 {
return pa.valueSet[i]
}
return 0
}
//Imitation of PHP function pop()
func (pa *untypedKeyMap) pop() {
pa.keySet = pa.keySet[:len(pa.keySet)-1]
pa.valueSet = pa.valueSet[:len(pa.valueSet)-1]
}
//Imitation of PHP function array_merge()
func arrayMerge(arr1, arr2 *untypedKeyMap) *untypedKeyMap {
answer := untypedKeyMap{}
if arr1 == nil && arr2 == nil {
answer = untypedKeyMap{
make([]interface{}, 0),
make([]int, 0),
}
} else if arr2 == nil {
answer.keySet = arr1.keySet[:]
answer.valueSet = arr1.valueSet[:]
} else if arr1 == nil {
answer.keySet = arr2.keySet[:]
answer.valueSet = arr2.valueSet[:]
} else {
answer.keySet = arr1.keySet[:]
answer.valueSet = arr1.valueSet[:]
for i := 0; i < len(arr2.keySet); i++ {
if arr2.keySet[i] == "interval" {
if arr1.getIndex("interval") < 0 {
answer.put("interval", arr2.valueSet[i])
}
} else {
answer.put(nil, arr2.valueSet[i])
}
}
}
return &answer
}
func remove(arr []int, key int) []int {
n := 0
for i, mKey := range arr {
if mKey == key {
n = i
}
}
if n == 0 {
return arr[1:]
} else if n == len(arr)-1 {
return arr[:len(arr)-1]
}
return append(arr[:n], arr[n+1:]...)
}
func isChinese(rune2 rune) bool {
// chinese unicode: 4e00-9fa5
if rune2 >= rune(0x4e00) && rune2 <= rune(0x9fa5) {
return true
}
return false
}

22
vendor/github.com/robfig/cron/v3/.gitignore generated vendored Normal file
View File

@ -0,0 +1,22 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe

21
vendor/github.com/robfig/cron/v3/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
Copyright (C) 2012 Rob Figueiredo
All Rights Reserved.
MIT LICENSE
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

125
vendor/github.com/robfig/cron/v3/README.md generated vendored Normal file
View File

@ -0,0 +1,125 @@
[![GoDoc](http://godoc.org/github.com/robfig/cron?status.png)](http://godoc.org/github.com/robfig/cron)
[![Build Status](https://travis-ci.org/robfig/cron.svg?branch=master)](https://travis-ci.org/robfig/cron)
# cron
Cron V3 has been released!
To download the specific tagged release, run:
go get github.com/robfig/cron/v3@v3.0.0
Import it in your program as:
import "github.com/robfig/cron/v3"
It requires Go 1.11 or later due to usage of Go Modules.
Refer to the documentation here:
http://godoc.org/github.com/robfig/cron
The rest of this document describes the the advances in v3 and a list of
breaking changes for users that wish to upgrade from an earlier version.
## Upgrading to v3 (June 2019)
cron v3 is a major upgrade to the library that addresses all outstanding bugs,
feature requests, and rough edges. It is based on a merge of master which
contains various fixes to issues found over the years and the v2 branch which
contains some backwards-incompatible features like the ability to remove cron
jobs. In addition, v3 adds support for Go Modules, cleans up rough edges like
the timezone support, and fixes a number of bugs.
New features:
- Support for Go modules. Callers must now import this library as
`github.com/robfig/cron/v3`, instead of `gopkg.in/...`
- Fixed bugs:
- 0f01e6b parser: fix combining of Dow and Dom (#70)
- dbf3220 adjust times when rolling the clock forward to handle non-existent midnight (#157)
- eeecf15 spec_test.go: ensure an error is returned on 0 increment (#144)
- 70971dc cron.Entries(): update request for snapshot to include a reply channel (#97)
- 1cba5e6 cron: fix: removing a job causes the next scheduled job to run too late (#206)
- Standard cron spec parsing by default (first field is "minute"), with an easy
way to opt into the seconds field (quartz-compatible). Although, note that the
year field (optional in Quartz) is not supported.
- Extensible, key/value logging via an interface that complies with
the https://github.com/go-logr/logr project.
- The new Chain & JobWrapper types allow you to install "interceptors" to add
cross-cutting behavior like the following:
- Recover any panics from jobs
- Delay a job's execution if the previous run hasn't completed yet
- Skip a job's execution if the previous run hasn't completed yet
- Log each job's invocations
- Notification when jobs are completed
It is backwards incompatible with both v1 and v2. These updates are required:
- The v1 branch accepted an optional seconds field at the beginning of the cron
spec. This is non-standard and has led to a lot of confusion. The new default
parser conforms to the standard as described by [the Cron wikipedia page].
UPDATING: To retain the old behavior, construct your Cron with a custom
parser:
// Seconds field, required
cron.New(cron.WithSeconds())
// Seconds field, optional
cron.New(
cron.WithParser(
cron.SecondOptional | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor))
- The Cron type now accepts functional options on construction rather than the
previous ad-hoc behavior modification mechanisms (setting a field, calling a setter).
UPDATING: Code that sets Cron.ErrorLogger or calls Cron.SetLocation must be
updated to provide those values on construction.
- CRON_TZ is now the recommended way to specify the timezone of a single
schedule, which is sanctioned by the specification. The legacy "TZ=" prefix
will continue to be supported since it is unambiguous and easy to do so.
UPDATING: No update is required.
- By default, cron will no longer recover panics in jobs that it runs.
Recovering can be surprising (see issue #192) and seems to be at odds with
typical behavior of libraries. Relatedly, the `cron.WithPanicLogger` option
has been removed to accommodate the more general JobWrapper type.
UPDATING: To opt into panic recovery and configure the panic logger:
cron.New(cron.WithChain(
cron.Recover(logger), // or use cron.DefaultLogger
))
- In adding support for https://github.com/go-logr/logr, `cron.WithVerboseLogger` was
removed, since it is duplicative with the leveled logging.
UPDATING: Callers should use `WithLogger` and specify a logger that does not
discard `Info` logs. For convenience, one is provided that wraps `*log.Logger`:
cron.New(
cron.WithLogger(cron.VerbosePrintfLogger(logger)))
### Background - Cron spec format
There are two cron spec formats in common usage:
- The "standard" cron format, described on [the Cron wikipedia page] and used by
the cron Linux system utility.
- The cron format used by [the Quartz Scheduler], commonly used for scheduled
jobs in Java software
[the Cron wikipedia page]: https://en.wikipedia.org/wiki/Cron
[the Quartz Scheduler]: http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/crontrigger.html
The original version of this package included an optional "seconds" field, which
made it incompatible with both of these formats. Now, the "standard" format is
the default format accepted, and the Quartz format is opt-in.

92
vendor/github.com/robfig/cron/v3/chain.go generated vendored Normal file
View File

@ -0,0 +1,92 @@
package cron
import (
"fmt"
"runtime"
"sync"
"time"
)
// JobWrapper decorates the given Job with some behavior.
type JobWrapper func(Job) Job
// Chain is a sequence of JobWrappers that decorates submitted jobs with
// cross-cutting behaviors like logging or synchronization.
type Chain struct {
wrappers []JobWrapper
}
// NewChain returns a Chain consisting of the given JobWrappers.
func NewChain(c ...JobWrapper) Chain {
return Chain{c}
}
// Then decorates the given job with all JobWrappers in the chain.
//
// This:
// NewChain(m1, m2, m3).Then(job)
// is equivalent to:
// m1(m2(m3(job)))
func (c Chain) Then(j Job) Job {
for i := range c.wrappers {
j = c.wrappers[len(c.wrappers)-i-1](j)
}
return j
}
// Recover panics in wrapped jobs and log them with the provided logger.
func Recover(logger Logger) JobWrapper {
return func(j Job) Job {
return FuncJob(func() {
defer func() {
if r := recover(); r != nil {
const size = 64 << 10
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
err, ok := r.(error)
if !ok {
err = fmt.Errorf("%v", r)
}
logger.Error(err, "panic", "stack", "...\n"+string(buf))
}
}()
j.Run()
})
}
}
// DelayIfStillRunning serializes jobs, delaying subsequent runs until the
// previous one is complete. Jobs running after a delay of more than a minute
// have the delay logged at Info.
func DelayIfStillRunning(logger Logger) JobWrapper {
return func(j Job) Job {
var mu sync.Mutex
return FuncJob(func() {
start := time.Now()
mu.Lock()
defer mu.Unlock()
if dur := time.Since(start); dur > time.Minute {
logger.Info("delay", "duration", dur)
}
j.Run()
})
}
}
// SkipIfStillRunning skips an invocation of the Job if a previous invocation is
// still running. It logs skips to the given logger at Info level.
func SkipIfStillRunning(logger Logger) JobWrapper {
var ch = make(chan struct{}, 1)
ch <- struct{}{}
return func(j Job) Job {
return FuncJob(func() {
select {
case v := <-ch:
j.Run()
ch <- v
default:
logger.Info("skip")
}
})
}
}

27
vendor/github.com/robfig/cron/v3/constantdelay.go generated vendored Normal file
View File

@ -0,0 +1,27 @@
package cron
import "time"
// ConstantDelaySchedule represents a simple recurring duty cycle, e.g. "Every 5 minutes".
// It does not support jobs more frequent than once a second.
type ConstantDelaySchedule struct {
Delay time.Duration
}
// Every returns a crontab Schedule that activates once every duration.
// Delays of less than a second are not supported (will round up to 1 second).
// Any fields less than a Second are truncated.
func Every(duration time.Duration) ConstantDelaySchedule {
if duration < time.Second {
duration = time.Second
}
return ConstantDelaySchedule{
Delay: duration - time.Duration(duration.Nanoseconds())%time.Second,
}
}
// Next returns the next time this should be run.
// This rounds so that the next activation time will be on the second.
func (schedule ConstantDelaySchedule) Next(t time.Time) time.Time {
return t.Add(schedule.Delay - time.Duration(t.Nanosecond())*time.Nanosecond)
}

350
vendor/github.com/robfig/cron/v3/cron.go generated vendored Normal file
View File

@ -0,0 +1,350 @@
package cron
import (
"context"
"sort"
"sync"
"time"
)
// Cron keeps track of any number of entries, invoking the associated func as
// specified by the schedule. It may be started, stopped, and the entries may
// be inspected while running.
type Cron struct {
entries []*Entry
chain Chain
stop chan struct{}
add chan *Entry
remove chan EntryID
snapshot chan chan []Entry
running bool
logger Logger
runningMu sync.Mutex
location *time.Location
parser Parser
nextID EntryID
jobWaiter sync.WaitGroup
}
// Job is an interface for submitted cron jobs.
type Job interface {
Run()
}
// Schedule describes a job's duty cycle.
type Schedule interface {
// Next returns the next activation time, later than the given time.
// Next is invoked initially, and then each time the job is run.
Next(time.Time) time.Time
}
// EntryID identifies an entry within a Cron instance
type EntryID int
// Entry consists of a schedule and the func to execute on that schedule.
type Entry struct {
// ID is the cron-assigned ID of this entry, which may be used to look up a
// snapshot or remove it.
ID EntryID
// Schedule on which this job should be run.
Schedule Schedule
// Next time the job will run, or the zero time if Cron has not been
// started or this entry's schedule is unsatisfiable
Next time.Time
// Prev is the last time this job was run, or the zero time if never.
Prev time.Time
// WrappedJob is the thing to run when the Schedule is activated.
WrappedJob Job
// Job is the thing that was submitted to cron.
// It is kept around so that user code that needs to get at the job later,
// e.g. via Entries() can do so.
Job Job
}
// Valid returns true if this is not the zero entry.
func (e Entry) Valid() bool { return e.ID != 0 }
// byTime is a wrapper for sorting the entry array by time
// (with zero time at the end).
type byTime []*Entry
func (s byTime) Len() int { return len(s) }
func (s byTime) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
func (s byTime) Less(i, j int) bool {
// Two zero times should return false.
// Otherwise, zero is "greater" than any other time.
// (To sort it at the end of the list.)
if s[i].Next.IsZero() {
return false
}
if s[j].Next.IsZero() {
return true
}
return s[i].Next.Before(s[j].Next)
}
// New returns a new Cron job runner, modified by the given options.
//
// Available Settings
//
// Time Zone
// Description: The time zone in which schedules are interpreted
// Default: time.Local
//
// Parser
// Description: Parser converts cron spec strings into cron.Schedules.
// Default: Accepts this spec: https://en.wikipedia.org/wiki/Cron
//
// Chain
// Description: Wrap submitted jobs to customize behavior.
// Default: A chain that recovers panics and logs them to stderr.
//
// See "cron.With*" to modify the default behavior.
func New(opts ...Option) *Cron {
c := &Cron{
entries: nil,
chain: NewChain(),
add: make(chan *Entry),
stop: make(chan struct{}),
snapshot: make(chan chan []Entry),
remove: make(chan EntryID),
running: false,
runningMu: sync.Mutex{},
logger: DefaultLogger,
location: time.Local,
parser: standardParser,
}
for _, opt := range opts {
opt(c)
}
return c
}
// FuncJob is a wrapper that turns a func() into a cron.Job
type FuncJob func()
func (f FuncJob) Run() { f() }
// AddFunc adds a func to the Cron to be run on the given schedule.
// The spec is parsed using the time zone of this Cron instance as the default.
// An opaque ID is returned that can be used to later remove it.
func (c *Cron) AddFunc(spec string, cmd func()) (EntryID, error) {
return c.AddJob(spec, FuncJob(cmd))
}
// AddJob adds a Job to the Cron to be run on the given schedule.
// The spec is parsed using the time zone of this Cron instance as the default.
// An opaque ID is returned that can be used to later remove it.
func (c *Cron) AddJob(spec string, cmd Job) (EntryID, error) {
schedule, err := c.parser.Parse(spec)
if err != nil {
return 0, err
}
return c.Schedule(schedule, cmd), nil
}
// Schedule adds a Job to the Cron to be run on the given schedule.
// The job is wrapped with the configured Chain.
func (c *Cron) Schedule(schedule Schedule, cmd Job) EntryID {
c.runningMu.Lock()
defer c.runningMu.Unlock()
c.nextID++
entry := &Entry{
ID: c.nextID,
Schedule: schedule,
WrappedJob: c.chain.Then(cmd),
Job: cmd,
}
if !c.running {
c.entries = append(c.entries, entry)
} else {
c.add <- entry
}
return entry.ID
}
// Entries returns a snapshot of the cron entries.
func (c *Cron) Entries() []Entry {
c.runningMu.Lock()
defer c.runningMu.Unlock()
if c.running {
replyChan := make(chan []Entry, 1)
c.snapshot <- replyChan
return <-replyChan
}
return c.entrySnapshot()
}
// Location gets the time zone location
func (c *Cron) Location() *time.Location {
return c.location
}
// Entry returns a snapshot of the given entry, or nil if it couldn't be found.
func (c *Cron) Entry(id EntryID) Entry {
for _, entry := range c.Entries() {
if id == entry.ID {
return entry
}
}
return Entry{}
}
// Remove an entry from being run in the future.
func (c *Cron) Remove(id EntryID) {
c.runningMu.Lock()
defer c.runningMu.Unlock()
if c.running {
c.remove <- id
} else {
c.removeEntry(id)
}
}
// Start the cron scheduler in its own goroutine, or no-op if already started.
func (c *Cron) Start() {
c.runningMu.Lock()
defer c.runningMu.Unlock()
if c.running {
return
}
c.running = true
go c.run()
}
// Run the cron scheduler, or no-op if already running.
func (c *Cron) Run() {
c.runningMu.Lock()
if c.running {
c.runningMu.Unlock()
return
}
c.running = true
c.runningMu.Unlock()
c.run()
}
// run the scheduler.. this is private just due to the need to synchronize
// access to the 'running' state variable.
func (c *Cron) run() {
c.logger.Info("start")
// Figure out the next activation times for each entry.
now := c.now()
for _, entry := range c.entries {
entry.Next = entry.Schedule.Next(now)
c.logger.Info("schedule", "now", now, "entry", entry.ID, "next", entry.Next)
}
for {
// Determine the next entry to run.
sort.Sort(byTime(c.entries))
var timer *time.Timer
if len(c.entries) == 0 || c.entries[0].Next.IsZero() {
// If there are no entries yet, just sleep - it still handles new entries
// and stop requests.
timer = time.NewTimer(100000 * time.Hour)
} else {
timer = time.NewTimer(c.entries[0].Next.Sub(now))
}
for {
select {
case now = <-timer.C:
now = now.In(c.location)
c.logger.Info("wake", "now", now)
// Run every entry whose next time was less than now
for _, e := range c.entries {
if e.Next.After(now) || e.Next.IsZero() {
break
}
c.startJob(e.WrappedJob)
e.Prev = e.Next
e.Next = e.Schedule.Next(now)
c.logger.Info("run", "now", now, "entry", e.ID, "next", e.Next)
}
case newEntry := <-c.add:
timer.Stop()
now = c.now()
newEntry.Next = newEntry.Schedule.Next(now)
c.entries = append(c.entries, newEntry)
c.logger.Info("added", "now", now, "entry", newEntry.ID, "next", newEntry.Next)
case replyChan := <-c.snapshot:
replyChan <- c.entrySnapshot()
continue
case <-c.stop:
timer.Stop()
c.logger.Info("stop")
return
case id := <-c.remove:
timer.Stop()
now = c.now()
c.removeEntry(id)
c.logger.Info("removed", "entry", id)
}
break
}
}
}
// startJob runs the given job in a new goroutine.
func (c *Cron) startJob(j Job) {
c.jobWaiter.Add(1)
go func() {
defer c.jobWaiter.Done()
j.Run()
}()
}
// now returns current time in c location
func (c *Cron) now() time.Time {
return time.Now().In(c.location)
}
// Stop stops the cron scheduler if it is running; otherwise it does nothing.
// A context is returned so the caller can wait for running jobs to complete.
func (c *Cron) Stop() context.Context {
c.runningMu.Lock()
defer c.runningMu.Unlock()
if c.running {
c.stop <- struct{}{}
c.running = false
}
ctx, cancel := context.WithCancel(context.Background())
go func() {
c.jobWaiter.Wait()
cancel()
}()
return ctx
}
// entrySnapshot returns a copy of the current cron entry list.
func (c *Cron) entrySnapshot() []Entry {
var entries = make([]Entry, len(c.entries))
for i, e := range c.entries {
entries[i] = *e
}
return entries
}
func (c *Cron) removeEntry(id EntryID) {
var entries []*Entry
for _, e := range c.entries {
if e.ID != id {
entries = append(entries, e)
}
}
c.entries = entries
}

212
vendor/github.com/robfig/cron/v3/doc.go generated vendored Normal file
View File

@ -0,0 +1,212 @@
/*
Package cron implements a cron spec parser and job runner.
Usage
Callers may register Funcs to be invoked on a given schedule. Cron will run
them in their own goroutines.
c := cron.New()
c.AddFunc("30 * * * *", func() { fmt.Println("Every hour on the half hour") })
c.AddFunc("30 3-6,20-23 * * *", func() { fmt.Println(".. in the range 3-6am, 8-11pm") })
c.AddFunc("CRON_TZ=Asia/Tokyo 30 04 * * * *", func() { fmt.Println("Runs at 04:30 Tokyo time every day") })
c.AddFunc("@hourly", func() { fmt.Println("Every hour, starting an hour from now") })
c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty, starting an hour thirty from now") })
c.Start()
..
// Funcs are invoked in their own goroutine, asynchronously.
...
// Funcs may also be added to a running Cron
c.AddFunc("@daily", func() { fmt.Println("Every day") })
..
// Inspect the cron job entries' next and previous run times.
inspect(c.Entries())
..
c.Stop() // Stop the scheduler (does not stop any jobs already running).
CRON Expression Format
A cron expression represents a set of times, using 5 space-separated fields.
Field name | Mandatory? | Allowed values | Allowed special characters
---------- | ---------- | -------------- | --------------------------
Minutes | Yes | 0-59 | * / , -
Hours | Yes | 0-23 | * / , -
Day of month | Yes | 1-31 | * / , - ?
Month | Yes | 1-12 or JAN-DEC | * / , -
Day of week | Yes | 0-6 or SUN-SAT | * / , - ?
Month and Day-of-week field values are case insensitive. "SUN", "Sun", and
"sun" are equally accepted.
The specific interpretation of the format is based on the Cron Wikipedia page:
https://en.wikipedia.org/wiki/Cron
Alternative Formats
Alternative Cron expression formats support other fields like seconds. You can
implement that by creating a custom Parser as follows.
cron.New(
cron.WithParser(
cron.SecondOptional | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor))
The most popular alternative Cron expression format is Quartz:
http://www.quartz-scheduler.org/documentation/quartz-2.x/tutorials/crontrigger.html
Special Characters
Asterisk ( * )
The asterisk indicates that the cron expression will match for all values of the
field; e.g., using an asterisk in the 5th field (month) would indicate every
month.
Slash ( / )
Slashes are used to describe increments of ranges. For example 3-59/15 in the
1st field (minutes) would indicate the 3rd minute of the hour and every 15
minutes thereafter. The form "*\/..." is equivalent to the form "first-last/...",
that is, an increment over the largest possible range of the field. The form
"N/..." is accepted as meaning "N-MAX/...", that is, starting at N, use the
increment until the end of that specific range. It does not wrap around.
Comma ( , )
Commas are used to separate items of a list. For example, using "MON,WED,FRI" in
the 5th field (day of week) would mean Mondays, Wednesdays and Fridays.
Hyphen ( - )
Hyphens are used to define ranges. For example, 9-17 would indicate every
hour between 9am and 5pm inclusive.
Question mark ( ? )
Question mark may be used instead of '*' for leaving either day-of-month or
day-of-week blank.
Predefined schedules
You may use one of several pre-defined schedules in place of a cron expression.
Entry | Description | Equivalent To
----- | ----------- | -------------
@yearly (or @annually) | Run once a year, midnight, Jan. 1st | 0 0 1 1 *
@monthly | Run once a month, midnight, first of month | 0 0 1 * *
@weekly | Run once a week, midnight between Sat/Sun | 0 0 * * 0
@daily (or @midnight) | Run once a day, midnight | 0 0 * * *
@hourly | Run once an hour, beginning of hour | 0 * * * *
Intervals
You may also schedule a job to execute at fixed intervals, starting at the time it's added
or cron is run. This is supported by formatting the cron spec like this:
@every <duration>
where "duration" is a string accepted by time.ParseDuration
(http://golang.org/pkg/time/#ParseDuration).
For example, "@every 1h30m10s" would indicate a schedule that activates after
1 hour, 30 minutes, 10 seconds, and then every interval after that.
Note: The interval does not take the job runtime into account. For example,
if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes,
it will have only 2 minutes of idle time between each run.
Time zones
By default, all interpretation and scheduling is done in the machine's local
time zone (time.Local). You can specify a different time zone on construction:
cron.New(
cron.WithLocation(time.UTC))
Individual cron schedules may also override the time zone they are to be
interpreted in by providing an additional space-separated field at the beginning
of the cron spec, of the form "CRON_TZ=Asia/Tokyo".
For example:
# Runs at 6am in time.Local
cron.New().AddFunc("0 6 * * ?", ...)
# Runs at 6am in America/New_York
nyc, _ := time.LoadLocation("America/New_York")
c := cron.New(cron.WithLocation(nyc))
c.AddFunc("0 6 * * ?", ...)
# Runs at 6am in Asia/Tokyo
cron.New().AddFunc("CRON_TZ=Asia/Tokyo 0 6 * * ?", ...)
# Runs at 6am in Asia/Tokyo
c := cron.New(cron.WithLocation(nyc))
c.SetLocation("America/New_York")
c.AddFunc("CRON_TZ=Asia/Tokyo 0 6 * * ?", ...)
The prefix "TZ=(TIME ZONE)" is also supported for legacy compatibility.
Be aware that jobs scheduled during daylight-savings leap-ahead transitions will
not be run!
Job Wrappers / Chain
A Cron runner may be configured with a chain of job wrappers to add
cross-cutting functionality to all submitted jobs. For example, they may be used
to achieve the following effects:
- Recover any panics from jobs (activated by default)
- Delay a job's execution if the previous run hasn't completed yet
- Skip a job's execution if the previous run hasn't completed yet
- Log each job's invocations
Install wrappers for all jobs added to a cron using the `cron.WithChain` option:
cron.New(cron.WithChain(
cron.SkipIfStillRunning(logger),
))
Install wrappers for individual jobs by explicitly wrapping them:
job = cron.NewChain(
cron.SkipIfStillRunning(logger),
).Then(job)
Thread safety
Since the Cron service runs concurrently with the calling code, some amount of
care must be taken to ensure proper synchronization.
All cron methods are designed to be correctly synchronized as long as the caller
ensures that invocations have a clear happens-before ordering between them.
Logging
Cron defines a Logger interface that is a subset of the one defined in
github.com/go-logr/logr. It has two logging levels (Info and Error), and
parameters are key/value pairs. This makes it possible for cron logging to plug
into structured logging systems. An adapter, [Verbose]PrintfLogger, is provided
to wrap the standard library *log.Logger.
For additional insight into Cron operations, verbose logging may be activated
which will record job runs, scheduling decisions, and added or removed jobs.
Activate it with a one-off logger as follows:
cron.New(
cron.WithLogger(
cron.VerbosePrintfLogger(log.New(os.Stdout, "cron: ", log.LstdFlags))))
Implementation
Cron entries are stored in an array, sorted by their next activation time. Cron
sleeps until the next job is due to be run.
Upon waking:
- it runs each entry that is active on that second
- it calculates the next run times for the jobs that were run
- it re-sorts the array of entries by next activation time.
- it goes to sleep until the soonest job.
*/
package cron

3
vendor/github.com/robfig/cron/v3/go.mod generated vendored Normal file
View File

@ -0,0 +1,3 @@
module github.com/robfig/cron/v3
go 1.12

86
vendor/github.com/robfig/cron/v3/logger.go generated vendored Normal file
View File

@ -0,0 +1,86 @@
package cron
import (
"io/ioutil"
"log"
"os"
"strings"
"time"
)
// DefaultLogger is used by Cron if none is specified.
var DefaultLogger Logger = PrintfLogger(log.New(os.Stdout, "cron: ", log.LstdFlags))
// DiscardLogger can be used by callers to discard all log messages.
var DiscardLogger Logger = PrintfLogger(log.New(ioutil.Discard, "", 0))
// Logger is the interface used in this package for logging, so that any backend
// can be plugged in. It is a subset of the github.com/go-logr/logr interface.
type Logger interface {
// Info logs routine messages about cron's operation.
Info(msg string, keysAndValues ...interface{})
// Error logs an error condition.
Error(err error, msg string, keysAndValues ...interface{})
}
// PrintfLogger wraps a Printf-based logger (such as the standard library "log")
// into an implementation of the Logger interface which logs errors only.
func PrintfLogger(l interface{ Printf(string, ...interface{}) }) Logger {
return printfLogger{l, false}
}
// VerbosePrintfLogger wraps a Printf-based logger (such as the standard library
// "log") into an implementation of the Logger interface which logs everything.
func VerbosePrintfLogger(l interface{ Printf(string, ...interface{}) }) Logger {
return printfLogger{l, true}
}
type printfLogger struct {
logger interface{ Printf(string, ...interface{}) }
logInfo bool
}
func (pl printfLogger) Info(msg string, keysAndValues ...interface{}) {
if pl.logInfo {
keysAndValues = formatTimes(keysAndValues)
pl.logger.Printf(
formatString(len(keysAndValues)),
append([]interface{}{msg}, keysAndValues...)...)
}
}
func (pl printfLogger) Error(err error, msg string, keysAndValues ...interface{}) {
keysAndValues = formatTimes(keysAndValues)
pl.logger.Printf(
formatString(len(keysAndValues)+2),
append([]interface{}{msg, "error", err}, keysAndValues...)...)
}
// formatString returns a logfmt-like format string for the number of
// key/values.
func formatString(numKeysAndValues int) string {
var sb strings.Builder
sb.WriteString("%s")
if numKeysAndValues > 0 {
sb.WriteString(", ")
}
for i := 0; i < numKeysAndValues/2; i++ {
if i > 0 {
sb.WriteString(", ")
}
sb.WriteString("%v=%v")
}
return sb.String()
}
// formatTimes formats any time.Time values as RFC3339.
func formatTimes(keysAndValues []interface{}) []interface{} {
var formattedArgs []interface{}
for _, arg := range keysAndValues {
if t, ok := arg.(time.Time); ok {
arg = t.Format(time.RFC3339)
}
formattedArgs = append(formattedArgs, arg)
}
return formattedArgs
}

45
vendor/github.com/robfig/cron/v3/option.go generated vendored Normal file
View File

@ -0,0 +1,45 @@
package cron
import (
"time"
)
// Option represents a modification to the default behavior of a Cron.
type Option func(*Cron)
// WithLocation overrides the timezone of the cron instance.
func WithLocation(loc *time.Location) Option {
return func(c *Cron) {
c.location = loc
}
}
// WithSeconds overrides the parser used for interpreting job schedules to
// include a seconds field as the first one.
func WithSeconds() Option {
return WithParser(NewParser(
Second | Minute | Hour | Dom | Month | Dow | Descriptor,
))
}
// WithParser overrides the parser used for interpreting job schedules.
func WithParser(p Parser) Option {
return func(c *Cron) {
c.parser = p
}
}
// WithChain specifies Job wrappers to apply to all jobs added to this cron.
// Refer to the Chain* functions in this package for provided wrappers.
func WithChain(wrappers ...JobWrapper) Option {
return func(c *Cron) {
c.chain = NewChain(wrappers...)
}
}
// WithLogger uses the provided logger.
func WithLogger(logger Logger) Option {
return func(c *Cron) {
c.logger = logger
}
}

434
vendor/github.com/robfig/cron/v3/parser.go generated vendored Normal file
View File

@ -0,0 +1,434 @@
package cron
import (
"fmt"
"math"
"strconv"
"strings"
"time"
)
// Configuration options for creating a parser. Most options specify which
// fields should be included, while others enable features. If a field is not
// included the parser will assume a default value. These options do not change
// the order fields are parse in.
type ParseOption int
const (
Second ParseOption = 1 << iota // Seconds field, default 0
SecondOptional // Optional seconds field, default 0
Minute // Minutes field, default 0
Hour // Hours field, default 0
Dom // Day of month field, default *
Month // Month field, default *
Dow // Day of week field, default *
DowOptional // Optional day of week field, default *
Descriptor // Allow descriptors such as @monthly, @weekly, etc.
)
var places = []ParseOption{
Second,
Minute,
Hour,
Dom,
Month,
Dow,
}
var defaults = []string{
"0",
"0",
"0",
"*",
"*",
"*",
}
// A custom Parser that can be configured.
type Parser struct {
options ParseOption
}
// NewParser creates a Parser with custom options.
//
// It panics if more than one Optional is given, since it would be impossible to
// correctly infer which optional is provided or missing in general.
//
// Examples
//
// // Standard parser without descriptors
// specParser := NewParser(Minute | Hour | Dom | Month | Dow)
// sched, err := specParser.Parse("0 0 15 */3 *")
//
// // Same as above, just excludes time fields
// subsParser := NewParser(Dom | Month | Dow)
// sched, err := specParser.Parse("15 */3 *")
//
// // Same as above, just makes Dow optional
// subsParser := NewParser(Dom | Month | DowOptional)
// sched, err := specParser.Parse("15 */3")
//
func NewParser(options ParseOption) Parser {
optionals := 0
if options&DowOptional > 0 {
optionals++
}
if options&SecondOptional > 0 {
optionals++
}
if optionals > 1 {
panic("multiple optionals may not be configured")
}
return Parser{options}
}
// Parse returns a new crontab schedule representing the given spec.
// It returns a descriptive error if the spec is not valid.
// It accepts crontab specs and features configured by NewParser.
func (p Parser) Parse(spec string) (Schedule, error) {
if len(spec) == 0 {
return nil, fmt.Errorf("empty spec string")
}
// Extract timezone if present
var loc = time.Local
if strings.HasPrefix(spec, "TZ=") || strings.HasPrefix(spec, "CRON_TZ=") {
var err error
i := strings.Index(spec, " ")
eq := strings.Index(spec, "=")
if loc, err = time.LoadLocation(spec[eq+1 : i]); err != nil {
return nil, fmt.Errorf("provided bad location %s: %v", spec[eq+1:i], err)
}
spec = strings.TrimSpace(spec[i:])
}
// Handle named schedules (descriptors), if configured
if strings.HasPrefix(spec, "@") {
if p.options&Descriptor == 0 {
return nil, fmt.Errorf("parser does not accept descriptors: %v", spec)
}
return parseDescriptor(spec, loc)
}
// Split on whitespace.
fields := strings.Fields(spec)
// Validate & fill in any omitted or optional fields
var err error
fields, err = normalizeFields(fields, p.options)
if err != nil {
return nil, err
}
field := func(field string, r bounds) uint64 {
if err != nil {
return 0
}
var bits uint64
bits, err = getField(field, r)
return bits
}
var (
second = field(fields[0], seconds)
minute = field(fields[1], minutes)
hour = field(fields[2], hours)
dayofmonth = field(fields[3], dom)
month = field(fields[4], months)
dayofweek = field(fields[5], dow)
)
if err != nil {
return nil, err
}
return &SpecSchedule{
Second: second,
Minute: minute,
Hour: hour,
Dom: dayofmonth,
Month: month,
Dow: dayofweek,
Location: loc,
}, nil
}
// normalizeFields takes a subset set of the time fields and returns the full set
// with defaults (zeroes) populated for unset fields.
//
// As part of performing this function, it also validates that the provided
// fields are compatible with the configured options.
func normalizeFields(fields []string, options ParseOption) ([]string, error) {
// Validate optionals & add their field to options
optionals := 0
if options&SecondOptional > 0 {
options |= Second
optionals++
}
if options&DowOptional > 0 {
options |= Dow
optionals++
}
if optionals > 1 {
return nil, fmt.Errorf("multiple optionals may not be configured")
}
// Figure out how many fields we need
max := 0
for _, place := range places {
if options&place > 0 {
max++
}
}
min := max - optionals
// Validate number of fields
if count := len(fields); count < min || count > max {
if min == max {
return nil, fmt.Errorf("expected exactly %d fields, found %d: %s", min, count, fields)
}
return nil, fmt.Errorf("expected %d to %d fields, found %d: %s", min, max, count, fields)
}
// Populate the optional field if not provided
if min < max && len(fields) == min {
switch {
case options&DowOptional > 0:
fields = append(fields, defaults[5]) // TODO: improve access to default
case options&SecondOptional > 0:
fields = append([]string{defaults[0]}, fields...)
default:
return nil, fmt.Errorf("unknown optional field")
}
}
// Populate all fields not part of options with their defaults
n := 0
expandedFields := make([]string, len(places))
copy(expandedFields, defaults)
for i, place := range places {
if options&place > 0 {
expandedFields[i] = fields[n]
n++
}
}
return expandedFields, nil
}
var standardParser = NewParser(
Minute | Hour | Dom | Month | Dow | Descriptor,
)
// ParseStandard returns a new crontab schedule representing the given
// standardSpec (https://en.wikipedia.org/wiki/Cron). It requires 5 entries
// representing: minute, hour, day of month, month and day of week, in that
// order. It returns a descriptive error if the spec is not valid.
//
// It accepts
// - Standard crontab specs, e.g. "* * * * ?"
// - Descriptors, e.g. "@midnight", "@every 1h30m"
func ParseStandard(standardSpec string) (Schedule, error) {
return standardParser.Parse(standardSpec)
}
// getField returns an Int with the bits set representing all of the times that
// the field represents or error parsing field value. A "field" is a comma-separated
// list of "ranges".
func getField(field string, r bounds) (uint64, error) {
var bits uint64
ranges := strings.FieldsFunc(field, func(r rune) bool { return r == ',' })
for _, expr := range ranges {
bit, err := getRange(expr, r)
if err != nil {
return bits, err
}
bits |= bit
}
return bits, nil
}
// getRange returns the bits indicated by the given expression:
// number | number "-" number [ "/" number ]
// or error parsing range.
func getRange(expr string, r bounds) (uint64, error) {
var (
start, end, step uint
rangeAndStep = strings.Split(expr, "/")
lowAndHigh = strings.Split(rangeAndStep[0], "-")
singleDigit = len(lowAndHigh) == 1
err error
)
var extra uint64
if lowAndHigh[0] == "*" || lowAndHigh[0] == "?" {
start = r.min
end = r.max
extra = starBit
} else {
start, err = parseIntOrName(lowAndHigh[0], r.names)
if err != nil {
return 0, err
}
switch len(lowAndHigh) {
case 1:
end = start
case 2:
end, err = parseIntOrName(lowAndHigh[1], r.names)
if err != nil {
return 0, err
}
default:
return 0, fmt.Errorf("too many hyphens: %s", expr)
}
}
switch len(rangeAndStep) {
case 1:
step = 1
case 2:
step, err = mustParseInt(rangeAndStep[1])
if err != nil {
return 0, err
}
// Special handling: "N/step" means "N-max/step".
if singleDigit {
end = r.max
}
if step > 1 {
extra = 0
}
default:
return 0, fmt.Errorf("too many slashes: %s", expr)
}
if start < r.min {
return 0, fmt.Errorf("beginning of range (%d) below minimum (%d): %s", start, r.min, expr)
}
if end > r.max {
return 0, fmt.Errorf("end of range (%d) above maximum (%d): %s", end, r.max, expr)
}
if start > end {
return 0, fmt.Errorf("beginning of range (%d) beyond end of range (%d): %s", start, end, expr)
}
if step == 0 {
return 0, fmt.Errorf("step of range should be a positive number: %s", expr)
}
return getBits(start, end, step) | extra, nil
}
// parseIntOrName returns the (possibly-named) integer contained in expr.
func parseIntOrName(expr string, names map[string]uint) (uint, error) {
if names != nil {
if namedInt, ok := names[strings.ToLower(expr)]; ok {
return namedInt, nil
}
}
return mustParseInt(expr)
}
// mustParseInt parses the given expression as an int or returns an error.
func mustParseInt(expr string) (uint, error) {
num, err := strconv.Atoi(expr)
if err != nil {
return 0, fmt.Errorf("failed to parse int from %s: %s", expr, err)
}
if num < 0 {
return 0, fmt.Errorf("negative number (%d) not allowed: %s", num, expr)
}
return uint(num), nil
}
// getBits sets all bits in the range [min, max], modulo the given step size.
func getBits(min, max, step uint) uint64 {
var bits uint64
// If step is 1, use shifts.
if step == 1 {
return ^(math.MaxUint64 << (max + 1)) & (math.MaxUint64 << min)
}
// Else, use a simple loop.
for i := min; i <= max; i += step {
bits |= 1 << i
}
return bits
}
// all returns all bits within the given bounds. (plus the star bit)
func all(r bounds) uint64 {
return getBits(r.min, r.max, 1) | starBit
}
// parseDescriptor returns a predefined schedule for the expression, or error if none matches.
func parseDescriptor(descriptor string, loc *time.Location) (Schedule, error) {
switch descriptor {
case "@yearly", "@annually":
return &SpecSchedule{
Second: 1 << seconds.min,
Minute: 1 << minutes.min,
Hour: 1 << hours.min,
Dom: 1 << dom.min,
Month: 1 << months.min,
Dow: all(dow),
Location: loc,
}, nil
case "@monthly":
return &SpecSchedule{
Second: 1 << seconds.min,
Minute: 1 << minutes.min,
Hour: 1 << hours.min,
Dom: 1 << dom.min,
Month: all(months),
Dow: all(dow),
Location: loc,
}, nil
case "@weekly":
return &SpecSchedule{
Second: 1 << seconds.min,
Minute: 1 << minutes.min,
Hour: 1 << hours.min,
Dom: all(dom),
Month: all(months),
Dow: 1 << dow.min,
Location: loc,
}, nil
case "@daily", "@midnight":
return &SpecSchedule{
Second: 1 << seconds.min,
Minute: 1 << minutes.min,
Hour: 1 << hours.min,
Dom: all(dom),
Month: all(months),
Dow: all(dow),
Location: loc,
}, nil
case "@hourly":
return &SpecSchedule{
Second: 1 << seconds.min,
Minute: 1 << minutes.min,
Hour: all(hours),
Dom: all(dom),
Month: all(months),
Dow: all(dow),
Location: loc,
}, nil
}
const every = "@every "
if strings.HasPrefix(descriptor, every) {
duration, err := time.ParseDuration(descriptor[len(every):])
if err != nil {
return nil, fmt.Errorf("failed to parse duration %s: %s", descriptor, err)
}
return Every(duration), nil
}
return nil, fmt.Errorf("unrecognized descriptor: %s", descriptor)
}

188
vendor/github.com/robfig/cron/v3/spec.go generated vendored Normal file
View File

@ -0,0 +1,188 @@
package cron
import "time"
// SpecSchedule specifies a duty cycle (to the second granularity), based on a
// traditional crontab specification. It is computed initially and stored as bit sets.
type SpecSchedule struct {
Second, Minute, Hour, Dom, Month, Dow uint64
// Override location for this schedule.
Location *time.Location
}
// bounds provides a range of acceptable values (plus a map of name to value).
type bounds struct {
min, max uint
names map[string]uint
}
// The bounds for each field.
var (
seconds = bounds{0, 59, nil}
minutes = bounds{0, 59, nil}
hours = bounds{0, 23, nil}
dom = bounds{1, 31, nil}
months = bounds{1, 12, map[string]uint{
"jan": 1,
"feb": 2,
"mar": 3,
"apr": 4,
"may": 5,
"jun": 6,
"jul": 7,
"aug": 8,
"sep": 9,
"oct": 10,
"nov": 11,
"dec": 12,
}}
dow = bounds{0, 6, map[string]uint{
"sun": 0,
"mon": 1,
"tue": 2,
"wed": 3,
"thu": 4,
"fri": 5,
"sat": 6,
}}
)
const (
// Set the top bit if a star was included in the expression.
starBit = 1 << 63
)
// Next returns the next time this schedule is activated, greater than the given
// time. If no time can be found to satisfy the schedule, return the zero time.
func (s *SpecSchedule) Next(t time.Time) time.Time {
// General approach
//
// For Month, Day, Hour, Minute, Second:
// Check if the time value matches. If yes, continue to the next field.
// If the field doesn't match the schedule, then increment the field until it matches.
// While incrementing the field, a wrap-around brings it back to the beginning
// of the field list (since it is necessary to re-verify previous field
// values)
// Convert the given time into the schedule's timezone, if one is specified.
// Save the original timezone so we can convert back after we find a time.
// Note that schedules without a time zone specified (time.Local) are treated
// as local to the time provided.
origLocation := t.Location()
loc := s.Location
if loc == time.Local {
loc = t.Location()
}
if s.Location != time.Local {
t = t.In(s.Location)
}
// Start at the earliest possible time (the upcoming second).
t = t.Add(1*time.Second - time.Duration(t.Nanosecond())*time.Nanosecond)
// This flag indicates whether a field has been incremented.
added := false
// If no time is found within five years, return zero.
yearLimit := t.Year() + 5
WRAP:
if t.Year() > yearLimit {
return time.Time{}
}
// Find the first applicable month.
// If it's this month, then do nothing.
for 1<<uint(t.Month())&s.Month == 0 {
// If we have to add a month, reset the other parts to 0.
if !added {
added = true
// Otherwise, set the date at the beginning (since the current time is irrelevant).
t = time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, loc)
}
t = t.AddDate(0, 1, 0)
// Wrapped around.
if t.Month() == time.January {
goto WRAP
}
}
// Now get a day in that month.
//
// NOTE: This causes issues for daylight savings regimes where midnight does
// not exist. For example: Sao Paulo has DST that transforms midnight on
// 11/3 into 1am. Handle that by noticing when the Hour ends up != 0.
for !dayMatches(s, t) {
if !added {
added = true
t = time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, loc)
}
t = t.AddDate(0, 0, 1)
// Notice if the hour is no longer midnight due to DST.
// Add an hour if it's 23, subtract an hour if it's 1.
if t.Hour() != 0 {
if t.Hour() > 12 {
t = t.Add(time.Duration(24-t.Hour()) * time.Hour)
} else {
t = t.Add(time.Duration(-t.Hour()) * time.Hour)
}
}
if t.Day() == 1 {
goto WRAP
}
}
for 1<<uint(t.Hour())&s.Hour == 0 {
if !added {
added = true
t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), 0, 0, 0, loc)
}
t = t.Add(1 * time.Hour)
if t.Hour() == 0 {
goto WRAP
}
}
for 1<<uint(t.Minute())&s.Minute == 0 {
if !added {
added = true
t = t.Truncate(time.Minute)
}
t = t.Add(1 * time.Minute)
if t.Minute() == 0 {
goto WRAP
}
}
for 1<<uint(t.Second())&s.Second == 0 {
if !added {
added = true
t = t.Truncate(time.Second)
}
t = t.Add(1 * time.Second)
if t.Second() == 0 {
goto WRAP
}
}
return t.In(origLocation)
}
// dayMatches returns true if the schedule's day-of-week and day-of-month
// restrictions are satisfied by the given time.
func dayMatches(s *SpecSchedule, t time.Time) bool {
var (
domMatch bool = 1<<uint(t.Day())&s.Dom > 0
dowMatch bool = 1<<uint(t.Weekday())&s.Dow > 0
)
if s.Dom&starBit > 0 || s.Dow&starBit > 0 {
return domMatch && dowMatch
}
return domMatch || dowMatch
}

4
vendor/modules.txt vendored
View File

@ -134,6 +134,8 @@ github.com/jmespath/go-jmespath
github.com/jonboulle/clockwork
# github.com/jtolds/gls v4.20.0+incompatible
github.com/jtolds/gls
# github.com/jung-kurt/gofpdf v1.10.1
github.com/jung-kurt/gofpdf
# github.com/klauspost/compress v1.4.1
github.com/klauspost/compress/gzip
github.com/klauspost/compress/flate
@ -186,6 +188,8 @@ github.com/prometheus/procfs/internal/util
github.com/rainycape/unidecode
# github.com/robfig/cron v0.0.0-20180505203441-b41be1df6967
github.com/robfig/cron
# github.com/robfig/cron/v3 v3.0.0
github.com/robfig/cron/v3
# github.com/russellhaering/goxmldsig v0.0.0-20180430223755-7acd5e4a6ef7
github.com/russellhaering/goxmldsig
github.com/russellhaering/goxmldsig/etreeutils