From 4c9d4cde86495128201e05dfdcee37db69f23659 Mon Sep 17 00:00:00 2001 From: DarkFreedman Date: Fri, 4 Oct 2019 12:14:19 +0300 Subject: Update to latest version --- README.md | 358 +++++----- README.md.template | 9 - check | 3 - contrib/barcode/barcode.go | 10 +- contrib/barcode/barcode_test.go | 21 + cov | 1 - def.go | 39 +- doc.go | 357 +++++----- font/calligra.json | 2 +- font/calligra.z | Bin 25609 -> 25812 bytes fpdf.go | 340 ++++++++-- fpdf_test.go | 210 +++++- go.mod | 11 + image/signature.svg | 72 +- mkdoc | 23 - pdf/reference/Fpdf_SVGBasicWrite.pdf | 1207 +++++++++++++++++++++++++--------- svgbasic.go | 40 +- svgwrite.go | 29 +- template.go | 11 + template_impl.go | 4 + utf8fontfile.go | 21 +- util.go | 24 +- 22 files changed, 1968 insertions(+), 824 deletions(-) delete mode 100644 README.md.template delete mode 100755 check delete mode 100755 cov delete mode 100755 mkdoc diff --git a/README.md b/README.md index 9f0ef59..b402678 100644 --- a/README.md +++ b/README.md @@ -1,65 +1,69 @@ -# gofpdf +# GoFPDF document generator -![gofpdf](image/logo_gofpdf.jpg?raw=true "gofpdf") +[![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) -[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/jung-kurt/gofpdf/master/license.txt) -[![GoDoc](https://godoc.org/github.com/jung-kurt/gofpdf?status.svg)](https://godoc.org/github.com/jung-kurt/gofpdf) -[![Build Status](https://travis-ci.org/jung-kurt/gofpdf.svg?branch=master)](https://travis-ci.org/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. +Package gofpdf implements a PDF document generator with high level +support for text, drawing and images. ## Features -* 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 -* UTF-8 support - -gofpdf has no dependencies other than the Go standard library. All tests pass -on Linux, Mac and Windows platforms. - -gofpdf supports UTF-8 fonts and "right to left" languages. - -Also, support is provided to automatically translate -UTF-8 runes to code page encodings for languages that have fewer than 256 -glyphs. + - 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) @@ -67,171 +71,187 @@ 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. +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(). +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. +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, you'll 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. +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, you’ll 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()`. -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. -You should use AddUTF8Font or AddUTF8FontFromBytes to add UTF-8 TTF font. -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. -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](http://www.google.com/fonts/) and [DejaVu Fonts](http://dejavu-fonts.org/). +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. +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. +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://godoc.org/golang.org/x/tools/cmd/vet), that is, `golint .` and -`go vet .` should not generate any warnings -* not diminish [test coverage](https://blog.golang.org/cover) + - 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/) work -nicely as a means of contributing your changes. +[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. +gofpdf is released under the MIT License. It is copyrighted by Kurt Jung +and the contributors acknowledged below. ## Acknowledgments - -This package's 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 +This package’s 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 image's 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. +protection is adapted from the work of Klemen Vodopivec for the FPDF +product. Lawrence Kesteloot provided code to allow an image’s 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. Joe Westcott added underline +functionality and optimized image storage. ## Roadmap -* Improve test coverage as reported by the coverage tool. - - + - Improve test coverage as reported by the coverage tool. diff --git a/README.md.template b/README.md.template deleted file mode 100644 index 8caf572..0000000 --- a/README.md.template +++ /dev/null @@ -1,9 +0,0 @@ -# gofpdf - -![gofpdf](image/logo_gofpdf.jpg?raw=true "gofpdf") - -[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/jung-kurt/gofpdf/master/license.txt) -[![GoDoc](https://godoc.org/github.com/jung-kurt/gofpdf?status.svg)](https://godoc.org/github.com/jung-kurt/gofpdf) -[![Build Status](https://travis-ci.org/jung-kurt/gofpdf.svg?branch=master)](https://travis-ci.org/jung-kurt/gofpdf) - -{{.Doc}} diff --git a/check b/check deleted file mode 100755 index dcc2519..0000000 --- a/check +++ /dev/null @@ -1,3 +0,0 @@ -golint . -go vet -all . -gofmt -s -l . diff --git a/contrib/barcode/barcode.go b/contrib/barcode/barcode.go index ad84fe5..7e0ac0d 100644 --- a/contrib/barcode/barcode.go +++ b/contrib/barcode/barcode.go @@ -93,13 +93,17 @@ func printBarcode(pdf barcodePdf, code string, x, y float64, w, h *float64, flow } } + scaleToWidthF := float64(scaleToWidth) + scaleToHeightF := float64(scaleToHeight) + if w != nil { - scaleToWidth = int(*w) + scaleToWidthF = *w } if h != nil { - scaleToHeight = int(*h) + scaleToHeightF = *h } - pdf.Image(bname, x, y, float64(scaleToWidth), float64(scaleToHeight), flow, "jpg", 0, "") + + pdf.Image(bname, x, y, scaleToWidthF, scaleToHeightF, flow, "jpg", 0, "") } diff --git a/contrib/barcode/barcode_test.go b/contrib/barcode/barcode_test.go index 2b402a3..066ac41 100644 --- a/contrib/barcode/barcode_test.go +++ b/contrib/barcode/barcode_test.go @@ -199,3 +199,24 @@ func TestGetUnscaledBarcodeDimensions(t *testing.T) { // Output: // Successfully generated ../../pdf/contrib_barcode_GetBarcodeDimensions.pdf } + +// TestBarcodeNonIntegerScalingFactors shows that the barcode may be scaled to non-integer sizes +func TestBarcodeNonIntegerScalingFactors(t *testing.T) { + pdf := gofpdf.New("L", "in", "A4", "") + pdf.SetFont("Helvetica", "", 12) + pdf.SetFillColor(200, 200, 220) + pdf.AddPage() + + key := barcode.RegisterQR(pdf, "qrcode", qr.H, qr.Unicode) + var scale float64 = 1.5 + barcode.BarcodeUnscalable(pdf, key, 0.5, 0.5, &scale, &scale, false) + + pdf.SetDrawColor(255, 0, 0) + pdf.Line(0.5, 0.5, 0.5+scale, 0.5+scale) + + fileStr := example.Filename("contrib_barcode_BarcodeScaling") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated ../../pdf/contrib_barcode_BarcodeScaling.pdf +} diff --git a/cov b/cov deleted file mode 100755 index a07edce..0000000 --- a/cov +++ /dev/null @@ -1 +0,0 @@ -go test -coverprofile=coverage && go tool cover -html=coverage diff --git a/def.go b/def.go index 205389b..8e2bea5 100644 --- a/def.go +++ b/def.go @@ -165,20 +165,20 @@ func (p PointType) XY() (float64, float64) { // 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 + data []byte // Raw image data + smask []byte // Soft Mask, an 8bit per-pixel transparency mask + n int // Image object number + w float64 // Width + h float64 // Height + cs string // Color space + pal []byte // Image color palette + bpc int // Bits Per Component + f string // Image filter + dp string // DecodeParms + trns []int // Transparency mask + scale float64 // Document scale factor + dpi float64 // Dots-per-inch found from image file (png only) + i string // SHA-1 checksum of the above values. } func generateImageID(info *ImageInfoType) (string, error) { @@ -427,6 +427,7 @@ type Pdf interface { SetFontLoader(loader FontLoader) SetFontLocation(fontDirStr string) SetFontSize(size float64) + SetFontStyle(styleStr string) SetFontUnitSize(size float64) SetFooterFunc(fnc func()) SetFooterFuncLpi(fnc func(lastPage bool)) @@ -451,6 +452,7 @@ type Pdf interface { 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) @@ -503,6 +505,10 @@ type Fpdf struct { 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 @@ -536,6 +542,7 @@ type Fpdf struct { fontFamily string // current font family fontStyle string // current font style underline bool // underlining flag + strikeout bool // strike out flag currentFont fontDefType // current font info fontSizePt float64 // current font size in points fontSize float64 // current font size in user unit @@ -558,6 +565,7 @@ type Fpdf struct { 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 @@ -589,7 +597,8 @@ type Fpdf struct { // Composite values of colors draw, fill, text colorType } - spotColorMap map[string]spotColorType // Map of named ink-based colors + spotColorMap map[string]spotColorType // Map of named ink-based colors + userUnderlineThickness float64 // A custom user underline thickness multiplier. } type encType struct { diff --git a/doc.go b/doc.go index 6492f7e..16cf4ba 100644 --- a/doc.go +++ b/doc.go @@ -1,252 +1,269 @@ /* - * Copyright (c) 2013-2017 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 implements a PDF document generator with high level +support for text, drawing and images. -/* -Package gofpdf implements a PDF document generator with high level support for -text, drawing and images. Features -• Choice of measurement unit, page format and margins -• Page header and footer management +- 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 -• Automatic page breaks, line breaks, and text justification +- Colors, gradients and alpha channel transparency -• Inclusion of JPEG, PNG, GIF, TIFF and basic path-only SVG images +- Outline bookmarks -• Colors, gradients and alpha channel transparency +- Internal and external links -• Outline bookmarks +- TrueType, Type1 and encoding support -• Internal and external links +- Page compression -• TrueType, Type1 and encoding support +- Lines, Bézier curves, arcs, and ellipses -• Page compression +- Rotation, scaling, skewing, translation, and mirroring -• Lines, Bézier curves, arcs, and ellipses +- Clipping -• Rotation, scaling, skewing, translation, and mirroring +- Document protection -• Clipping +- Layers -• Document protection +- Templates -• Layers +- Barcodes -• Templates +- Charting facility -• Barcodes +- Import PDFs as templates -• Charting facility +gofpdf has no dependencies other than the Go standard library. All tests +pass on Linux, Mac and Windows platforms. -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. -Like FPDF version 1.7, from which gofpdf is derived, this package does not yet -support UTF-8 fonts. In particular, languages that require more than one code -page such as Chinese, Japanese, and Arabic are not currently supported. This is -explained in issue 109. However, 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 + go get github.com/jung-kurt/gofpdf Later, to receive updates, run - go get -u -v github.com/jung-kurt/gofpdf/... + 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") + 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 +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. +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, you'll 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. +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, you’ll 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(). +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. -In order to use a different 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 - ./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. -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 http://www.google.com/fonts/ and http://dejavu-fonts.org/. Related Packages -The draw2d package (https://github.com/llgcode/draw2d) is a two dimensional -vector graphics library that can generate output in different forms. It uses -gofpdf for its document production mode. +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. +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 compatible with the MIT License + +- be properly documented -• be formatted with `go fmt` +- be formatted with go fmt -• include an example in fpdf_test.go if appropriate +- include an example in fpdf_test.go if appropriate -• conform to the standards of golint (https://github.com/golang/lint) and -go vet (https://godoc.org/golang.org/x/tools/cmd/vet), that is, `golint .` and -`go vet .` should not generate any warnings +- conform to the standards of golint and go vet, that is, golint . and +go vet . should not generate any warnings -• not diminish test coverage (https://blog.golang.org/cover) +- not diminish test coverage + +Pull requests are the preferred means of accepting your changes. -Pull requests (https://help.github.com/articles/using-pull-requests/) work -nicely as a means of contributing your changes. License -gofpdf is released under the MIT License. It is copyrighted by Kurt Jung and -the contributors acknowledged below. +gofpdf is released under the MIT License. It is copyrighted by Kurt Jung +and the contributors acknowledged below. + Acknowledgments -This package's code and documentation are closely derived from the FPDF library -(http://www.fpdf.org/) 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 image's 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. +This package’s 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 image’s 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. Joe Westcott added underline +functionality and optimized image storage. -Roadmap -• Handle UTF-8 source text natively. Until then, automatic translation of -UTF-8 runes to code page bytes is provided. +Roadmap -• Improve test coverage as reported by the coverage tool. +- Improve test coverage as reported by the coverage tool. */ package gofpdf diff --git a/font/calligra.json b/font/calligra.json index b968074..e49c9bd 100644 --- a/font/calligra.json +++ b/font/calligra.json @@ -1 +1 @@ -{"Tp":"TrueType","Name":"CalligrapherRegular","Desc":{"Ascent":899,"Descent":-234,"CapHeight":899,"Flags":32,"FontBBox":{"Xmin":-173,"Ymin":-234,"Xmax":1328,"Ymax":899},"ItalicAngle":0,"StemV":70,"MissingWidth":800},"Up":-200,"Ut":20,"Cw":[800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,282,324,405,584,632,980,776,259,299,299,377,600,259,432,254,597,529,298,451,359,525,423,464,417,457,479,275,282,600,600,600,501,800,743,636,598,712,608,562,680,756,308,314,676,552,1041,817,729,569,698,674,618,673,805,753,1238,716,754,599,315,463,315,600,547,278,581,564,440,571,450,347,628,611,283,283,560,252,976,595,508,549,540,395,441,307,614,556,915,559,597,452,315,222,315,600,800,800,800,0,0,0,780,0,0,278,0,0,0,1064,800,0,800,800,259,259,470,470,500,300,600,278,990,0,0,790,800,800,754,282,324,450,640,518,603,0,519,254,800,349,0,0,432,800,278,0,0,0,0,278,614,0,254,278,0,305,0,0,0,0,501,743,743,743,743,743,743,1060,598,608,608,608,608,308,308,308,308,0,817,729,729,729,729,729,0,729,805,805,805,805,0,0,688,581,581,581,581,581,581,792,440,450,450,450,450,283,283,283,283,0,595,508,508,508,508,508,0,508,614,614,614,614,0,0,597],"Enc":"cp1252","Diff":"","File":"calligra.z","Size1":0,"Size2":0,"OriginalSize":40120,"I":0,"N":0,"DiffN":0} \ No newline at end of file +{"Tp":"TrueType","Name":"CalligrapherRegular","Desc":{"Ascent":899,"Descent":-234,"CapHeight":899,"Flags":32,"FontBBox":{"Xmin":-173,"Ymin":-234,"Xmax":1328,"Ymax":899},"ItalicAngle":0,"StemV":70,"MissingWidth":800},"Up":-200,"Ut":20,"Cw":[800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,800,282,324,405,584,632,980,776,259,299,299,377,600,259,432,254,597,529,298,451,359,525,423,464,417,457,479,275,282,600,600,600,501,800,743,636,598,712,608,562,680,756,308,314,676,552,1041,817,729,569,698,674,618,673,805,753,1238,716,754,599,315,463,315,600,547,278,581,564,440,571,450,347,628,611,283,283,560,252,976,595,508,549,540,395,441,307,614,556,915,559,597,452,315,222,315,600,800,800,800,0,0,0,780,0,0,278,0,0,0,1064,800,0,800,800,259,259,470,470,500,300,600,278,990,0,0,790,800,800,754,282,324,450,640,518,603,0,519,254,800,349,0,0,432,800,278,0,0,0,0,278,614,0,254,278,0,305,0,0,0,0,501,743,743,743,743,743,743,1060,598,608,608,608,608,308,308,308,308,0,817,729,729,729,729,729,0,729,805,805,805,805,0,0,688,581,581,581,581,581,581,792,440,450,450,450,450,283,283,283,283,0,595,508,508,508,508,508,0,508,614,614,614,614,0,0,597],"Enc":"cp1252","Diff":"","File":"calligra.z","Size1":0,"Size2":0,"OriginalSize":40120,"N":0,"DiffN":0} \ No newline at end of file diff --git a/font/calligra.z b/font/calligra.z index c64353f..b6c5c07 100644 Binary files a/font/calligra.z and b/font/calligra.z differ diff --git a/fpdf.go b/fpdf.go index fa79033..f5062cc 100644 --- a/fpdf.go +++ b/fpdf.go @@ -85,6 +85,10 @@ func fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr string, size SizeType) f.diffs = make([]string, 0, 8) f.templates = make(map[string]Template) f.templateObjects = make(map[string]int) + f.importedObjs = make(map[string][]byte, 0) + f.importedObjPos = make(map[string]map[int]string, 0) + f.importedTplObjs = make(map[string]string) + f.importedTplIDs = make(map[string]int, 0) f.images = make(map[string]*ImageInfoType) f.pageLinks = make([][]linkType, 0, 8) f.pageLinks = append(f.pageLinks, make([]linkType, 0, 0)) // pageLinks[0] is unused (1-based) @@ -98,6 +102,7 @@ func fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr string, size SizeType) f.fontStyle = "" f.SetFontSize(12) f.underline = false + f.strikeout = false f.setDrawColor(0, 0, 0) f.setFillColor(0, 0, 0) f.setTextColor(0, 0, 0) @@ -194,9 +199,11 @@ func fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr string, size SizeType) f.gradientList = append(f.gradientList, gradientType{}) // gradientList[0] is unused // Set default PDF version number f.pdfVersion = "1.3" + f.SetProducer("FPDF "+cnFpdfVersion, true) f.layerInit() f.catalogSort = gl.catalogSort f.creationDate = gl.creationDate + f.userUnderlineThickness = 1 return } @@ -555,6 +562,15 @@ func (f *Fpdf) SetCompression(compress bool) { f.compress = compress } +// SetProducer defines the producer of the document. isUTF8 indicates if the string +// is encoded in ISO-8859-1 (false) or UTF-8 (true). +func (f *Fpdf) SetProducer(producerStr string, isUTF8 bool) { + if isUTF8 { + producerStr = utf8toutf16(producerStr) + } + f.producer = producerStr +} + // SetTitle defines the title of the document. isUTF8 indicates if the string // is encoded in ISO-8859-1 (false) or UTF-8 (true). func (f *Fpdf) SetTitle(titleStr string, isUTF8 bool) { @@ -618,12 +634,12 @@ func (f *Fpdf) AliasNbPages(aliasStr string) { f.aliasNbPagesStr = aliasStr } -// enable right to left mode +// RTL enables right-to-left mode func (f *Fpdf) RTL() { f.isRTL = true } -// disable right to left mode +// LTR disables right-to-left mode func (f *Fpdf) LTR() { f.isRTL = false } @@ -711,6 +727,9 @@ func (f *Fpdf) AddPageFormat(orientationStr string, size SizeType) { if f.underline { style += "U" } + if f.strikeout { + style += "S" + } fontsize := f.fontSizePt lw := f.lineWidth dc := f.color.draw @@ -1099,6 +1118,58 @@ func (f *Fpdf) Rect(x, y, w, h float64, styleStr string) { f.outf("%.2f %.2f %.2f %.2f re %s", x*f.k, (f.h-y)*f.k, w*f.k, -h*f.k, fillDrawOp(styleStr)) } +// RoundedRect outputs a rectangle of width w and height h with the upper left +// corner positioned at point (x, y). It can be drawn (border only), filled +// (with no border) or both. styleStr can be "F" for filled, "D" for outlined +// only, or "DF" or "FD" for outlined and filled. An empty string will be +// replaced with "D". Drawing uses the current draw color and line width +// centered on the rectangle's perimeter. Filling uses the current fill color. +// The rounded corners of the rectangle are specified by radius r. corners is a +// string that includes "1" to round the upper left corner, "2" to round the +// upper right corner, "3" to round the lower right corner, and "4" to round +// the lower left corner. The RoundedRect example demonstrates this method. +func (f *Fpdf) RoundedRect(x, y, w, h, r float64, corners string, stylestr string) { + // This routine was adapted by Brigham Thompson from a script by Christophe Prugnaud + k := f.k + hp := f.h + myArc := r * (4.0 / 3.0) * (math.Sqrt2 - 1.0) + f.outf("q %.5f %.5f m", (x+r)*k, (hp-y)*k) + xc := x + w - r + yc := y + r + f.outf("%.5f %.5f l", xc*k, (hp-y)*k) + if strings.Contains(corners, "2") == false { + f.outf("%.5f %.5f l", (x+w)*k, (hp-y)*k) + } else { + f.clipArc(xc+myArc, yc-r, xc+r, yc-myArc, xc+r, yc) + } + xc = x + w - r + yc = y + h - r + f.outf("%.5f %.5f l", (x+w)*k, (hp-yc)*k) + if strings.Contains(corners, "3") == false { + f.outf("%.5f %.5f l", (x+w)*k, (hp-(y+h))*k) + } else { + f.clipArc(xc+r, yc+myArc, xc+myArc, yc+r, xc, yc+r) + } + xc = x + r + yc = y + h - r + f.outf("%.5f %.5f l", xc*k, (hp-(y+h))*k) + if strings.Contains(corners, "4") == false { + f.outf("%.5f %.5f l", x*k, (hp-(y+h))*k) + } else { + f.clipArc(xc-myArc, yc+r, xc-r, yc+myArc, xc-r, yc) + } + xc = x + r + yc = y + r + f.outf("%.5f %.5f l", x*k, (hp-yc)*k) + if strings.Contains(corners, "1") == false { + f.outf("%.5f %.5f l", x*k, (hp-y)*k) + f.outf("%.5f %.5f l", (x+r)*k, (hp-y)*k) + } else { + f.clipArc(xc-r, yc-myArc, xc-myArc, yc-r, xc, yc-r) + } + f.out(fillDrawOp(stylestr)) +} + // Circle draws a circle centered on point (x, y) with radius r. // // styleStr can be "F" for filled, "D" for outlined only, or "DF" or "FD" for @@ -1558,7 +1629,7 @@ func (f *Fpdf) ClipEnd() { // definition file to be added. The file will be loaded from the font directory // specified in the call to New() or SetFontLocation(). func (f *Fpdf) AddFont(familyStr, styleStr, fileStr string) { - f.addFont(familyStr, styleStr, fileStr, false) + f.addFont(fontFamilyEscape(familyStr), styleStr, fileStr, false) } // AddUTF8Font imports a TrueType font with utf-8 symbols and makes it available. @@ -1582,7 +1653,7 @@ func (f *Fpdf) AddFont(familyStr, styleStr, fileStr string) { // definition file to be added. The file will be loaded from the font directory // specified in the call to New() or SetFontLocation(). func (f *Fpdf) AddUTF8Font(familyStr, styleStr, fileStr string) { - f.addFont(familyStr, styleStr, fileStr, true) + f.addFont(fontFamilyEscape(familyStr), styleStr, fileStr, true) } func (f *Fpdf) addFont(familyStr, styleStr, fileStr string, isUTF8 bool) { @@ -1599,17 +1670,27 @@ func (f *Fpdf) addFont(familyStr, styleStr, fileStr string, isUTF8 bool) { if ok { return } - ttfStat, _ := os.Stat(fileStr) + var ttfStat os.FileInfo + var err error + fileStr = path.Join(f.fontpath, fileStr) + ttfStat, err = os.Stat(fileStr) + if err != nil { + f.SetError(err) + return + } originalSize := ttfStat.Size() Type := "UTF8" - - utf8Bytes, _ := ioutil.ReadFile(fileStr) + var utf8Bytes []byte + utf8Bytes, err = ioutil.ReadFile(fileStr) + if err != nil { + f.SetError(err) + return + } reader := fileReader{readerPosition: 0, array: utf8Bytes} utf8File := newUTF8Font(&reader) - - err := utf8File.parseFile() + err = utf8File.parseFile() if err != nil { - fmt.Printf("get metrics Error: %e\n", err) + f.SetError(err) return } @@ -1698,7 +1779,7 @@ func makeSubsetRange(end int) map[int]int { // // zFileBytes contain all bytes of Z file. func (f *Fpdf) AddFontFromBytes(familyStr, styleStr string, jsonFileBytes, zFileBytes []byte) { - f.addFontFromBytes(familyStr, styleStr, jsonFileBytes, zFileBytes, nil) + f.addFontFromBytes(fontFamilyEscape(familyStr), styleStr, jsonFileBytes, zFileBytes, nil) } // AddUTF8FontFromBytes imports a TrueType font with utf-8 symbols from static @@ -1717,7 +1798,7 @@ func (f *Fpdf) AddFontFromBytes(familyStr, styleStr string, jsonFileBytes, zFile // // zFileBytes contain all bytes of Z file. func (f *Fpdf) AddUTF8FontFromBytes(familyStr, styleStr string, utf8Bytes []byte) { - f.addFontFromBytes(familyStr, styleStr, nil, nil, utf8Bytes) + f.addFontFromBytes(fontFamilyEscape(familyStr), styleStr, nil, nil, utf8Bytes) } func (f *Fpdf) addFontFromBytes(familyStr, styleStr string, jsonFileBytes, zFileBytes, utf8Bytes []byte) { @@ -1736,9 +1817,9 @@ func (f *Fpdf) addFontFromBytes(familyStr, styleStr string, jsonFileBytes, zFile if utf8Bytes != nil { - if styleStr == "IB" { - styleStr = "BI" - } + // if styleStr == "IB" { + // styleStr = "BI" + // } Type := "UTF8" reader := fileReader{readerPosition: 0, array: utf8Bytes} @@ -1856,6 +1937,7 @@ func (f *Fpdf) AddFontFromReader(familyStr, styleStr string, r io.Reader) { return } // dbg("Adding family [%s], style [%s]", familyStr, styleStr) + familyStr = fontFamilyEscape(familyStr) var ok bool fontkey := getFontKey(familyStr, styleStr) _, ok = f.fonts[fontkey] @@ -1904,7 +1986,7 @@ func (f *Fpdf) GetFontDesc(familyStr, styleStr string) FontDescType { if familyStr == "" { return f.currentFont.Desc } - return f.fonts[getFontKey(familyStr, styleStr)].Desc + return f.fonts[getFontKey(fontFamilyEscape(familyStr), styleStr)].Desc } // SetFont sets the font used to print character strings. It is mandatory to @@ -1927,9 +2009,9 @@ func (f *Fpdf) GetFontDesc(familyStr, styleStr string) FontDescType { // insensitive): "Courier" for fixed-width, "Helvetica" or "Arial" for sans // serif, "Times" for serif, "Symbol" or "ZapfDingbats" for symbolic. // -// styleStr can be "B" (bold), "I" (italic), "U" (underscore) or any -// combination. The default value (specified with an empty string) is regular. -// Bold and italic styles do not apply to Symbol and ZapfDingbats. +// styleStr can be "B" (bold), "I" (italic), "U" (underscore), "S" (strike-out) +// or any combination. The default value (specified with an empty string) is +// regular. Bold and italic styles do not apply to Symbol and ZapfDingbats. // // size is the font size measured in points. The default value is the current // size. If no size has been specified since the beginning of the document, the @@ -1941,6 +2023,7 @@ func (f *Fpdf) SetFont(familyStr, styleStr string, size float64) { return } // dbg("SetFont") + familyStr = fontFamilyEscape(familyStr) var ok bool if familyStr == "" { familyStr = f.fontFamily @@ -1952,6 +2035,10 @@ func (f *Fpdf) SetFont(familyStr, styleStr string, size float64) { if f.underline { styleStr = strings.Replace(styleStr, "U", "", -1) } + f.strikeout = strings.Contains(styleStr, "S") + if f.strikeout { + styleStr = strings.Replace(styleStr, "S", "", -1) + } if styleStr == "IB" { styleStr = "BI" } @@ -2008,6 +2095,11 @@ func (f *Fpdf) SetFont(familyStr, styleStr string, size float64) { return } +// SetFontStyle sets the style of the current font. See also SetFont() +func (f *Fpdf) SetFontStyle(styleStr string) { + f.SetFont(f.fontFamily, styleStr, f.fontSizePt) +} + // SetFontSize defines the size of the current font. Size is specified in // points (1/ 72 inch). See also SetFontUnitSize(). func (f *Fpdf) SetFontSize(size float64) { @@ -2091,6 +2183,9 @@ func (f *Fpdf) Bookmark(txtStr string, level int, y float64) { if y == -1 { y = f.y } + if f.isCurrentUTF8 { + txtStr = utf8toutf16(txtStr) + } f.outlines = append(f.outlines, outlineType{text: txtStr, level: level, y: y, p: f.PageNo(), prev: -1, last: -1, next: -1, first: -1}) } @@ -2102,7 +2197,7 @@ func (f *Fpdf) Text(x, y float64, txtStr string) { var txt2 string if f.isCurrentUTF8 { if f.isRTL { - txtStr = revertText(txtStr) + txtStr = reverseText(txtStr) x -= f.GetStringWidth(txtStr) } txt2 = f.escape(utf8toutf16(txtStr, false)) @@ -2116,6 +2211,9 @@ func (f *Fpdf) Text(x, y float64, txtStr string) { if f.underline && txtStr != "" { s += " " + f.dounderline(x, y, txtStr) } + if f.strikeout && txtStr != "" { + s += " " + f.dostrikeout(x, y, txtStr) + } if f.colorFlag { s = sprintf("q %s %s Q", f.color.text.str, s) } @@ -2294,7 +2392,7 @@ func (f *Fpdf) CellFormat(w, h float64, txtStr, borderStr string, ln int, //If multibyte, Tw has no effect - do word spacing using an adjustment before each space if (f.ws != 0 || alignStr == "J") && f.isCurrentUTF8 { // && f.ws != 0 if f.isRTL { - txtStr = revertText(txtStr) + txtStr = reverseText(txtStr) } wmax := int(math.Ceil((w - 2*f.cMargin) * 1000 / f.fontSize)) for _, uni := range []rune(txtStr) { @@ -2319,7 +2417,7 @@ func (f *Fpdf) CellFormat(w, h float64, txtStr, borderStr string, ln int, var txt2 string if f.isCurrentUTF8 { if f.isRTL { - txtStr = revertText(txtStr) + txtStr = reverseText(txtStr) } txt2 = f.escape(utf8toutf16(txtStr, false)) for _, uni := range []rune(txtStr) { @@ -2340,6 +2438,9 @@ func (f *Fpdf) CellFormat(w, h float64, txtStr, borderStr string, ln int, if f.underline { s.printf(" %s", f.dounderline(f.x+dx, f.y+dy+.5*h+.3*f.fontSize, txtStr)) } + if f.strikeout { + s.printf(" %s", f.dostrikeout(f.x+dx, f.y+dy+.5*h+.3*f.fontSize, txtStr)) + } if f.colorFlag { s.printf(" Q") } @@ -2365,18 +2466,18 @@ func (f *Fpdf) CellFormat(w, h float64, txtStr, borderStr string, ln int, } // Revert string to use in RTL languages -func revertText(text string) string { +func reverseText(text string) string { oldText := []rune(text) newText := make([]rune, len(oldText)) - lenght := len(oldText) - 1 + length := len(oldText) - 1 for i, r := range oldText { - newText[lenght-i] = r + newText[length-i] = r } return string(newText) } // Cell is a simpler version of CellFormat with no fill, border, links or -// special alignment. +// special alignment. The Cell_strikeout() example demonstrates this method. func (f *Fpdf) Cell(w, h float64, txtStr string) { f.CellFormat(w, h, txtStr, "", 0, "L", false, 0, "") } @@ -2393,6 +2494,9 @@ func (f *Fpdf) Cellf(w, h float64, fmtStr string, args ...interface{}) { // used to determine the total height of wrapped text for vertical placement // purposes. // +// This method is useful for codepage-based fonts only. For UTF-8 encoded text, +// use SplitText(). +// // You can use MultiCell if you want to print a text on several lines in a // simple way. func (f *Fpdf) SplitLines(txt []byte, w float64) [][]byte { @@ -2454,6 +2558,9 @@ func (f *Fpdf) SplitLines(txt []byte, w float64) [][]byte { // // h indicates the line height of each cell in the unit of measure specified in New(). func (f *Fpdf) MultiCell(w, h float64, txtStr, borderStr, alignStr string, fill bool) { + if f.err != nil { + return + } // dbg("MultiCell") if alignStr == "" { alignStr = "J" @@ -2464,20 +2571,23 @@ func (f *Fpdf) MultiCell(w, h float64, txtStr, borderStr, alignStr string, fill } wmax := int(math.Ceil((w - 2*f.cMargin) * 1000 / f.fontSize)) s := strings.Replace(txtStr, "\r", "", -1) + srune := []rune(s) + // remove extra line breaks var nb int if f.isCurrentUTF8 { - nb = len([]rune(s)) - for nb > 0 && []rune(s)[nb-1] == '\n' { + nb = len(srune) + for nb > 0 && srune[nb-1] == '\n' { nb-- - s = string([]rune(s)[0:nb]) } + srune = srune[0:nb] } else { nb = len(s) - if nb > 0 && []byte(s)[nb-1] == '\n' { + bytes2 := []byte(s) + for nb > 0 && bytes2[nb-1] == '\n' { nb-- - s = s[0:nb] } + s = s[0:nb] } // dbg("[%s]\n", s) var b, b2 string @@ -2513,9 +2623,9 @@ func (f *Fpdf) MultiCell(w, h float64, txtStr, borderStr, alignStr string, fill // Get next character var c rune if f.isCurrentUTF8 { - c = []rune(s)[i] + c = srune[i] } else { - c = rune([]byte(s)[i]) + c = rune(s[i]) } if c == '\n' { // Explicit line break @@ -2533,7 +2643,7 @@ func (f *Fpdf) MultiCell(w, h float64, txtStr, borderStr, alignStr string, fill newAlignStr = "L" } } - f.CellFormat(w, h, string([]rune(s)[j:i]), b, 2, newAlignStr, fill, 0, "") + f.CellFormat(w, h, string(srune[j:i]), b, 2, newAlignStr, fill, 0, "") } else { f.CellFormat(w, h, s[j:i], b, 2, alignStr, fill, 0, "") } @@ -2548,7 +2658,7 @@ func (f *Fpdf) MultiCell(w, h float64, txtStr, borderStr, alignStr string, fill } continue } - if c == ' ' { + if c == ' ' || isChinese(c) { sep = i ls = l ns++ @@ -2569,7 +2679,7 @@ func (f *Fpdf) MultiCell(w, h float64, txtStr, borderStr, alignStr string, fill f.out("0 Tw") } if f.isCurrentUTF8 { - f.CellFormat(w, h, string([]rune(s)[j:i]), b, 2, alignStr, fill, 0, "") + f.CellFormat(w, h, string(srune[j:i]), b, 2, alignStr, fill, 0, "") } else { f.CellFormat(w, h, s[j:i], b, 2, alignStr, fill, 0, "") } @@ -2583,7 +2693,7 @@ func (f *Fpdf) MultiCell(w, h float64, txtStr, borderStr, alignStr string, fill f.outf("%.3f Tw", f.ws*f.k) } if f.isCurrentUTF8 { - f.CellFormat(w, h, string([]rune(s)[j:sep]), b, 2, alignStr, fill, 0, "") + f.CellFormat(w, h, string(srune[j:sep]), b, 2, alignStr, fill, 0, "") } else { f.CellFormat(w, h, s[j:sep], b, 2, alignStr, fill, 0, "") } @@ -2617,7 +2727,7 @@ func (f *Fpdf) MultiCell(w, h float64, txtStr, borderStr, alignStr string, fill alignStr = "" } } - f.CellFormat(w, h, string([]rune(s)[j:i]), b, 2, alignStr, fill, 0, "") + f.CellFormat(w, h, string(srune[j:i]), b, 2, alignStr, fill, 0, "") } else { f.CellFormat(w, h, s[j:i], b, 2, alignStr, fill, 0, "") } @@ -2652,7 +2762,7 @@ func (f *Fpdf) write(h float64, txtStr string, link int, linkStr string) { if f.isCurrentUTF8 { c = []rune(s)[i] } else { - c = rune([]byte(s)[i]) + c = rune(byte(s[i])) } if c == '\n' { // Explicit line break @@ -2775,12 +2885,20 @@ func (f *Fpdf) WriteLinkID(h float64, displayStr string, linkID int) { func (f *Fpdf) WriteAligned(width, lineHeight float64, textStr, alignStr string) { lMargin, _, rMargin, _ := f.GetMargins() + pageWidth, _ := f.GetPageSize() if width == 0 { - pageWidth, _ := f.GetPageSize() width = pageWidth - (lMargin + rMargin) } - lines := f.SplitLines([]byte(textStr), width) + var lines []string + + if f.isCurrentUTF8 { + lines = f.SplitText(textStr, width) + } else { + for _, line := range f.SplitLines([]byte(textStr), width) { + lines = append(lines, string(line)) + } + } for _, lineBt := range lines { lineStr := string(lineBt) @@ -2796,7 +2914,9 @@ func (f *Fpdf) WriteAligned(width, lineHeight float64, textStr, alignStr string) f.Write(lineHeight, lineStr) f.SetLeftMargin(lMargin) default: + f.SetRightMargin(pageWidth - lMargin - width) f.Write(lineHeight, lineStr) + f.SetRightMargin(rMargin) } } } @@ -3084,6 +3204,88 @@ func (f *Fpdf) GetImageInfo(imageStr string) (info *ImageInfoType) { return f.images[imageStr] } +// ImportObjects imports objects from gofpdi into current document +func (f *Fpdf) ImportObjects(objs map[string][]byte) { + for k, v := range objs { + f.importedObjs[k] = v + } +} + +// ImportObjPos imports object hash positions from gofpdi +func (f *Fpdf) ImportObjPos(objPos map[string]map[int]string) { + for k, v := range objPos { + f.importedObjPos[k] = v + } +} + +// putImportedTemplates writes the imported template objects to the PDF +func (f *Fpdf) putImportedTemplates() { + nOffset := f.n + 1 + + // keep track of list of sha1 hashes (to be replaced with integers) + objsIDHash := make([]string, len(f.importedObjs)) + + // actual object data with new id + objsIDData := make([][]byte, len(f.importedObjs)) + + // Populate hash slice and data slice + i := 0 + for k, v := range f.importedObjs { + objsIDHash[i] = k + objsIDData[i] = v + + i++ + } + + // Populate a lookup table to get an object id from a hash + hashToObjID := make(map[string]int, len(f.importedObjs)) + for i = 0; i < len(objsIDHash); i++ { + hashToObjID[objsIDHash[i]] = i + nOffset + } + + // Now, replace hashes inside data with %040d object id + for i = 0; i < len(objsIDData); i++ { + // get hash + hash := objsIDHash[i] + + for pos, h := range f.importedObjPos[hash] { + // Convert object id into a 40 character string padded with spaces + objIDPadded := fmt.Sprintf("%40s", fmt.Sprintf("%d", hashToObjID[h])) + + // Convert objIDPadded into []byte + objIDBytes := []byte(objIDPadded) + + // Replace sha1 hash with object id padded + for j := pos; j < pos+40; j++ { + objsIDData[i][j] = objIDBytes[j-pos] + } + } + + // Save objsIDHash so that procset dictionary has the correct object ids + f.importedTplIDs[hash] = i + nOffset + } + + // Now, put objects + for i = 0; i < len(objsIDData); i++ { + f.newobj() + f.out(string(objsIDData[i])) + } +} + +// UseImportedTemplate uses imported template from gofpdi. It draws imported +// PDF page onto page. +func (f *Fpdf) UseImportedTemplate(tplName string, scaleX float64, scaleY float64, tX float64, tY float64) { + f.outf("q 0 J 1 w 0 j 0 G 0 g q %.4F 0 0 %.4F %.4F %.4F cm %s Do Q Q\n", scaleX*f.k, scaleY*f.k, tX*f.k, (tY+f.h)*f.k, tplName) +} + +// ImportTemplates imports gofpdi template names into importedTplObjs for +// inclusion in the procset dictionary +func (f *Fpdf) ImportTemplates(tpls map[string]string) { + for tplName, tplID := range tpls { + f.importedTplObjs[tplName] = tplID + } +} + // GetConversionRatio returns the conversion ratio based on the unit given when // creating the PDF. func (f *Fpdf) GetConversionRatio() float64 { @@ -3356,15 +3558,29 @@ func blankCount(str string) (count int) { return } +// SetUnderlineThickness accepts a multiplier for adjusting the text underline +// thickness, defaulting to 1. See SetUnderlineThickness example. +func (f *Fpdf) SetUnderlineThickness(thickness float64) { + f.userUnderlineThickness = thickness +} + // Underline text func (f *Fpdf) dounderline(x, y float64, txt string) string { up := float64(f.currentFont.Up) - ut := float64(f.currentFont.Ut) + ut := float64(f.currentFont.Ut) * f.userUnderlineThickness w := f.GetStringWidth(txt) + f.ws*float64(blankCount(txt)) return sprintf("%.2f %.2f %.2f %.2f re f", x*f.k, (f.h-(y-up/1000*f.fontSize))*f.k, w*f.k, -ut/1000*f.fontSizePt) } +func (f *Fpdf) dostrikeout(x, y float64, txt string) string { + up := float64(f.currentFont.Up) + ut := float64(f.currentFont.Ut) + w := f.GetStringWidth(txt) + f.ws*float64(blankCount(txt)) + return sprintf("%.2f %.2f %.2f %.2f re f", x*f.k, + (f.h-(y+4*up/1000*f.fontSize))*f.k, w*f.k, -ut/1000*f.fontSizePt) +} + func bufEqual(buf []byte, str string) bool { return string(buf[0:len(str)]) == str } @@ -3939,8 +4155,6 @@ func (f *Fpdf) generateCIDFontMap(font *fontDefType, LastRune int) { } interval = true cidArray[rangeID].put("interval", 1) - ui := 0 - ui = ui + 1 } else { if interval { // new range @@ -3990,8 +4204,8 @@ func (f *Fpdf) generateCIDFontMap(font *fontDefType, LastRune int) { previousKey = key } nextKey = key + cws - ui := ws.getIndex("interval") - ui = ui + 1 + // ui := ws.getIndex("interval") + // ui = ui + 1 if ws.getIndex("interval") >= 0 { if cws > 3 { isInterval = true @@ -4028,6 +4242,7 @@ func implode(sep string, arr []int) string { return s.String() } +// arrayCountValues counts the occurrences of each item in the $mp array. func arrayCountValues(mp []int) map[int]int { answer := make(map[int]int) for _, v := range mp { @@ -4056,11 +4271,31 @@ func (f *Fpdf) putimages() { for key = range f.images { keyList = append(keyList, key) } + + // Sort the keyList []string by the corresponding image's width. if f.catalogSort { sort.SliceStable(keyList, func(i, j int) bool { return f.images[keyList[i]].w < f.images[keyList[j]].w }) } + + // Maintain a list of inserted image SHA-1 hashes, with their + // corresponding object ID number. + insertedImages := map[string]int{} + for _, key = range keyList { - f.putimage(f.images[key]) + image := f.images[key] + + // Check if this image has already been inserted using it's SHA-1 hash. + insertedImageObjN, isFound := insertedImages[image.i] + + // If found, skip inserting the image as a new object, and + // use the object ID from the insertedImages map. + // If not, insert the image into the PDF and store the object ID. + if isFound { + image.n = insertedImageObjN + } else { + f.putimage(image) + insertedImages[image.i] = image.n + } } } @@ -4158,6 +4393,12 @@ func (f *Fpdf) putxobjectdict() { } } } + { + for tplName, objID := range f.importedTplObjs { + // here replace obj id hash with n + f.outf("%s %d 0 R", tplName, f.importedTplIDs[objID]) + } + } } func (f *Fpdf) putresourcedict() { @@ -4273,6 +4514,7 @@ func (f *Fpdf) putresources() { } f.putimages() f.putTemplates() + f.putImportedTemplates() // gofpdi // Resource dictionary f.offsets[2] = f.buffer.Len() f.out("2 0 obj") @@ -4299,7 +4541,9 @@ func (f *Fpdf) putresources() { func (f *Fpdf) putinfo() { var tm time.Time - f.outf("/Producer %s", f.textstring("FPDF "+cnFpdfVersion)) + if len(f.producer) > 0 { + f.outf("/Producer %s", f.textstring(f.producer)) + } if len(f.title) > 0 { f.outf("/Title %s", f.textstring(f.title)) } diff --git a/fpdf_test.go b/fpdf_test.go index 6042fab..5035bd8 100644 --- a/fpdf_test.go +++ b/fpdf_test.go @@ -858,7 +858,37 @@ func ExampleFpdf_ImageOptions() { // Successfully generated pdf/Fpdf_ImageOptions.pdf } -// This examples demonstrates Landscape mode with images. +// ExampleFpdf_RegisterImageOptionsReader demonstrates how to load an image +// from a io.Reader (in this case, a file) and register it with options. +func ExampleFpdf_RegisterImageOptionsReader() { + var ( + opt gofpdf.ImageOptions + pdfStr string + fl *os.File + err error + ) + + pdfStr = example.Filename("Fpdf_RegisterImageOptionsReader") + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + pdf.SetFont("Arial", "", 11) + fl, err = os.Open(example.ImageFile("logo.png")) + if err == nil { + opt.ImageType = "png" + opt.AllowNegativePosition = true + _ = pdf.RegisterImageOptionsReader("logo", opt, fl) + fl.Close() + for x := -20.0; x <= 40.0; x += 5 { + pdf.ImageOptions("logo", x, x+30, 0, 0, false, opt, 0, "") + } + err = pdf.OutputFileAndClose(pdfStr) + } + example.Summary(err, pdfStr) + // Output: + // Successfully generated pdf/Fpdf_RegisterImageOptionsReader.pdf +} + +// This example demonstrates Landscape mode with images. func ExampleFpdf_SetAcceptPageBreakFunc() { var y0 float64 var crrntCol int @@ -918,7 +948,7 @@ func ExampleFpdf_SetAcceptPageBreakFunc() { // Successfully generated pdf/Fpdf_SetAcceptPageBreakFunc_landscape.pdf } -// This examples tests corner cases as reported by the gocov tool. +// This example tests corner cases as reported by the gocov tool. func ExampleFpdf_SetKeywords() { var err error fileStr := example.Filename("Fpdf_SetKeywords") @@ -2389,7 +2419,7 @@ func ExampleFpdf_SubWrite() { // ExampleFpdf_SetPage demomstrates the SetPage() method, allowing content // generation to be deferred until all pages have been added. func ExampleFpdf_SetPage() { - rnd := rand.New(rand.NewSource(0)) // Make reproducable documents + rnd := rand.New(rand.NewSource(0)) // Make reproducible documents pdf := gofpdf.New("L", "cm", "A4", "") pdf.SetFont("Times", "", 12) @@ -2523,6 +2553,10 @@ func ExampleFpdf_TransformRotate() { // ExampleFpdf_AddUTF8Font demonstrates how use the font // with utf-8 mode func ExampleFpdf_AddUTF8Font() { + var fileStr string + var txtStr []byte + var err error + pdf := gofpdf.New("P", "mm", "A4", "") pdf.AddPage() @@ -2532,23 +2566,167 @@ func ExampleFpdf_AddUTF8Font() { pdf.AddUTF8Font("dejavu", "I", example.FontFile("DejaVuSansCondensed-Oblique.ttf")) pdf.AddUTF8Font("dejavu", "BI", example.FontFile("DejaVuSansCondensed-BoldOblique.ttf")) - txtStr, _ := ioutil.ReadFile(example.TextFile("utf-8test.txt")) + fileStr = example.Filename("Fpdf_AddUTF8Font") + txtStr, err = ioutil.ReadFile(example.TextFile("utf-8test.txt")) + if err == nil { + + pdf.SetFont("dejavu", "B", 17) + pdf.MultiCell(100, 8, "Text in different languages :", "", "C", false) + pdf.SetFont("dejavu", "", 14) + pdf.MultiCell(100, 5, string(txtStr), "", "C", false) + pdf.Ln(15) - pdf.SetFont("dejavu", "B", 17) - pdf.MultiCell(100, 8, "Text in different languages :", "", "C", false) - pdf.SetFont("dejavu", "", 14) - pdf.MultiCell(100, 5, string(txtStr), "", "C", false) - pdf.Ln(15) + txtStr, err = ioutil.ReadFile(example.TextFile("utf-8test2.txt")) + if err == nil { - txtStr, _ = ioutil.ReadFile(example.TextFile("utf-8test2.txt")) - pdf.SetFont("dejavu", "BI", 17) - pdf.MultiCell(100, 8, "Greek text with alignStr = \"J\":", "", "C", false) - pdf.SetFont("dejavu", "I", 14) - pdf.MultiCell(100, 5, string(txtStr), "", "J", false) + pdf.SetFont("dejavu", "BI", 17) + pdf.MultiCell(100, 8, "Greek text with alignStr = \"J\":", "", "C", false) + pdf.SetFont("dejavu", "I", 14) + pdf.MultiCell(100, 5, string(txtStr), "", "J", false) + err = pdf.OutputFileAndClose(fileStr) - fileStr := example.Filename("Fpdf_AddUTF8Font") - err := pdf.OutputFileAndClose(fileStr) + } + } example.Summary(err, fileStr) // Output: // Successfully generated pdf/Fpdf_AddUTF8Font.pdf } + +// ExampleUTF8CutFont demonstrates how generate a TrueType font subset. +func ExampleUTF8CutFont() { + var pdfFileStr, fullFontFileStr, subFontFileStr string + var subFont, fullFont []byte + var err error + + pdfFileStr = example.Filename("Fpdf_UTF8CutFont") + fullFontFileStr = example.FontFile("calligra.ttf") + fullFont, err = ioutil.ReadFile(fullFontFileStr) + if err == nil { + subFontFileStr = "calligra_abcde.ttf" + subFont = gofpdf.UTF8CutFont(fullFont, "abcde") + err = ioutil.WriteFile(subFontFileStr, subFont, 0600) + if err == nil { + y := 24.0 + pdf := gofpdf.New("P", "mm", "A4", "") + fontHt := 17.0 + lineHt := pdf.PointConvert(fontHt) + write := func(format string, args ...interface{}) { + pdf.SetXY(24.0, y) + pdf.Cell(200.0, lineHt, fmt.Sprintf(format, args...)) + y += lineHt + } + writeSize := func(fileStr string) { + var info os.FileInfo + var err error + info, err = os.Stat(fileStr) + if err == nil { + write("%6d: size of %s", info.Size(), fileStr) + } + } + pdf.AddPage() + pdf.AddUTF8Font("calligra", "", subFontFileStr) + pdf.SetFont("calligra", "", fontHt) + write("cabbed") + write("vwxyz") + pdf.SetFont("courier", "", fontHt) + writeSize(fullFontFileStr) + writeSize(subFontFileStr) + err = pdf.OutputFileAndClose(pdfFileStr) + os.Remove(subFontFileStr) + } + } + example.Summary(err, pdfFileStr) + // Output: + // Successfully generated pdf/Fpdf_UTF8CutFont.pdf +} + +func ExampleFpdf_RoundedRect() { + const ( + wd = 40.0 + hgap = 10.0 + radius = 10.0 + ht = 60.0 + vgap = 10.0 + ) + corner := func(b1, b2, b3, b4 bool) (cstr string) { + if b1 { + cstr = "1" + } + if b2 { + cstr += "2" + } + if b3 { + cstr += "3" + } + if b4 { + cstr += "4" + } + return + } + pdf := gofpdf.New("P", "mm", "A4", "") // 210 x 297 + pdf.AddPage() + pdf.SetLineWidth(0.5) + y := vgap + r := 40 + g := 30 + b := 20 + for row := 0; row < 4; row++ { + x := hgap + for col := 0; col < 4; col++ { + pdf.SetFillColor(r, g, b) + pdf.RoundedRect(x, y, wd, ht, radius, corner(row&1 == 1, row&2 == 2, col&1 == 1, col&2 == 2), "FD") + r += 8 + g += 10 + b += 12 + x += wd + hgap + } + y += ht + vgap + } + fileStr := example.Filename("Fpdf_RoundedRect") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_RoundedRect.pdf +} + +// ExampleFpdf_SetUnderlineThickness demonstrates how to adjust the text +// underline thickness. +func ExampleFpdf_SetUnderlineThickness() { + pdf := gofpdf.New("P", "mm", "A4", "") // 210mm x 297mm + pdf.AddPage() + pdf.SetFont("Arial", "U", 12) + + pdf.SetUnderlineThickness(0.5) + pdf.CellFormat(0, 10, "Thin underline", "", 1, "", false, 0, "") + + pdf.SetUnderlineThickness(1) + pdf.CellFormat(0, 10, "Normal underline", "", 1, "", false, 0, "") + + pdf.SetUnderlineThickness(2) + pdf.CellFormat(0, 10, "Thicker underline", "", 1, "", false, 0, "") + + fileStr := example.Filename("Fpdf_UnderlineThickness") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_UnderlineThickness.pdf +} + +// ExampleFpdf_Cell_strikeout demonstrates striked-out text +func ExampleFpdf_Cell_strikeout() { + + pdf := gofpdf.New("P", "mm", "A4", "") // 210mm x 297mm + pdf.AddPage() + + for fontSize := 4; fontSize < 40; fontSize += 10 { + pdf.SetFont("Arial", "S", float64(fontSize)) + pdf.SetXY(0, float64(fontSize)) + pdf.Cell(40, 10, "Hello World") + } + + fileStr := example.Filename("Fpdf_Cell_strikeout") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_Cell_strikeout.pdf +} diff --git a/go.mod b/go.mod index c7a180d..dee309c 100644 --- a/go.mod +++ b/go.mod @@ -1 +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-20190902063713-cb417be4ba39 +) + +replace gofpdf => ./ diff --git a/image/signature.svg b/image/signature.svg index cdbb4af..956c3c6 100644 --- a/image/signature.svg +++ b/image/signature.svg @@ -1,43 +1,73 @@ - + + d="m 234.43804,111.69821 c 50.21866,26.50627 126.75595,-3.87395 151.46369,-35.941621 24.70774,-32.067668 10.41159,-51.980992 -16.41089,-58.072772 -26.82248,-6.09178 -42.17661,10.494756 -57.68933,33.13636 -15.51272,22.641602 -22.3395,49.640453 -26.04984,89.319923 -3.71034,39.67947 -2.57151,103.67609 -16.65175,144.69433 -14.08024,41.01824 -40.79012,59.98014 -80.0876,71.50199 -39.29748,11.52185 -96.607494,6.67866 -126.372407,-24.20296 -29.764916,-30.88162 -24.693439,-84.55794 0.62001,-107.05538 25.313453,-22.49744 49.916587,-21.8463 53.386947,18.74456 3.47036,40.59086 -77.347635,106.99944 -102.157295,102.59574 -24.80966,-4.4037 -9.1930819,0 -13.78962288,0" /> + d="m 535.44946,262.31206 c 16.02735,-13.54645 29.98118,-31.39768 32.51139,-52.84016 1.4974,-10.24434 -1.94415,-22.06454 -11.64632,-27.13714 -22.66026,-14.31032 -51.37591,-9.68663 -75.27088,-1.12303 -29.57925,11.19994 -56.66841,28.48168 -80.87983,48.69857 -15.56749,13.48245 -30.31327,28.65126 -40.17476,46.87113 -10.56334,25.04076 5.93271,58.80187 33.76392,62.35287 20.97698,3.69753 41.31134,-5.15667 59.15595,-15.26739 23.68053,-12.07041 45.37059,-27.68722 65.11773,-45.42392 5.85816,-4.99109 11.66007,-10.04795 17.4228,-15.14884" /> + d="m 605.17805,221.06416 c -39.71057,22.89155 -90.21146,57.33437 -110.62013,81.46882 -20.40867,24.13445 1.74636,32.16167 21.51346,33.96557 19.7671,1.8039 40.22731,-5.81242 63.90833,-18.83825 23.68102,-13.02583 54.88215,-39.05314 73.09016,-60.24005 18.20801,-21.18691 37.84165,-41.69088 43.78312,-57.46575 5.94147,-15.77487 6.81292,-20.38898 -2.3045,-26.03079" /> + d="m 576.69736,336.95111 c 59.46452,-49.53559 110.50457,-110.94455 181.15663,-145.53797 21.55772,-14.53068 69.21456,-30.38164 74.52476,8.12435 2.15457,32.87115 -24.99905,56.36851 -41.3729,81.85669 -11.33394,14.91071 -34.85688,47.22341 -38.29416,51.12061 38.40925,-59.07476 94.0006,-105.23813 152.94098,-142.74425 21.53324,-14.17578 76.3474,-17.732 63.14039,22.44093 -6.44013,30.30909 -29.58192,52.20309 -51.31162,72.13403 -22.35245,20.18703 -11.93986,55.81184 21.21245,48.89199 28.04358,-1.72994 49.86098,-21.80465 73.62851,-34.51546 51.0484,-39.90132 89.3284,-97.12351 150.3008,-123.60116 30.7216,-12.02494 70.5868,-23.14241 98.2954,1.38478 22.9075,21.32517 9.8573,56.2678 -7.0675,76.93906 -18.1931,26.99594 -44.6741,46.96256 -74.8471,58.94304 -34.0583,20.33195 -79.3725,18.48794 -110.8061,-6.03301 -1.0838,-0.69666 -2.2533,-1.23366 -3.4004,-1.81269" /> + d="m 1145.2696,144.64925 c -19.2615,48.72397 -39.2763,98.0821 -71.8076,139.71403 -28.4578,44.00142 -46.4445,94.33551 -79.72453,135.30113 -23.78316,32.93768 -48.80204,65.54924 -80.01549,91.86673 -19.47895,6.1922 -20.04137,-20.7923 -14.66105,-32.91267 12.83153,-36.25521 37.22095,-66.57625 54.90924,-100.3885 22.07476,-38.69659 54.05253,-69.56182 85.74383,-100.24739" /> + d="m 1067.4918,308.53814 c 41.6055,37.74324 106.1656,40.87499 155.2476,16.47425 79.7307,-33.80513 147.627,-88.69981 215.7912,-140.91414 38.5692,-31.19936 75.8068,-66.58379 98.2999,-111.442691 5.2858,-16.340836 11.2358,-38.191353 -2.3042,-51.988823 -24.8579,-9.392422 -44.7459,19.21292 -62.7133,32.466761 -42.206,41.159272 -75.9104,90.348773 -105.7076,140.969903 -18.1332,33.9424 -36.3441,60.40033 -45.1009,105.84746 -4.8684,25.26636 17.3519,40.01019 38.489,36.24378 27.2382,-1.27906 52.1821,-14.06224 77.2642,-23.5167 20.2617,-9.77194 38.052,-23.75443 55.7341,-37.47313" /> + d="m 1509.1585,216.87147 c 45.3671,35.48031 84.7434,37.23796 135.7328,25.17331 14.925,-4.86754 25.7515,-17.97315 30.1445,-32.73996 6.2047,-12.9545 -0.2899,-27.91555 -12.929,-33.8982 -19.5006,-12.36806 -44.6888,-10.55607 -64.9092,-0.92535 -33.4028,14.45512 -59.4353,40.93033 -84.563,66.45243 -13.9248,16.55902 -22.671,38.06079 -22.9956,59.74639 0.7543,12.73146 10.7427,22.65661 22.5942,25.94215 28.6381,11.95988 61.6748,18.05546 91.8527,8.36881 20.1474,-7.27059 39.868,-15.91987 58.8894,-25.73255 22.7573,-13.36221 41.3454,-32.41648 60.072,-50.72036" /> + d="m 1779.9918,343.26036 c 28.6993,3.03127 63.3496,2.62457 82.7159,-22.45172 21.6447,-19.99229 43.1941,-48.10952 35.6329,-79.45221 -4.1368,-22.17497 -33.5802,-38.22486 -52.1616,-22.03003 -31.7488,22.47063 -31.372,70.25063 -12.8813,101.12391 23.6727,38.55114 74.0602,50.51158 116.164,41.35476 54.0203,-10.31179 104.4208,-53.87389 110.9357,-110.27278 0.7888,-32.83995 0.7757,-65.72269 4.9445,-98.36663 3.9298,-42.7466 9.9471,-89.084405 39.2166,-122.675002 17.104,-18.491716 51.2258,-26.9233518 69.4545,-5.555968 14.6931,19.194858 3.0296,45.294939 -10.7419,61.486039 -16.3416,25.138501 -48.7197,29.136431 -75.3811,36.237431 -26.4792,5.77658 -58.6276,2.75073 -76.1034,-20.51069 -9.6512,-10.713121 -20.4603,-22.768271 -20.6837,-38.053993" /> + d="m 2245.2696,122.42703 c -3.9166,0.81691 -6.5582,5.39919 -5.219,9.18763 1.2777,3.63173 4.3682,6.64885 8.1357,7.58096 2.108,0.12035 4.1149,-1.67454 4.2375,-3.78089 0.7885,-3.73488 0.2701,-7.91813 -2.1144,-10.99661 -1.2461,-1.37634 -3.1464,-2.37225 -5.0398,-1.99109" /> + d="m 2219.5751,170.3437 c -29.9457,39.95653 -58.8628,80.7409 -86.118,122.56461 -5.4378,11.43956 -6.9218,27.24913 2.6137,36.94004 11.5344,8.50012 26.6093,3.95387 39.1614,0.62975 31.967,-8.46295 63.2786,-21.86206 88.264,-43.97857 15.2095,-12.48824 29.1196,-26.55137 41.4956,-41.85028" /> + d="m 2487.38,203.45563 c -3.3292,-19.2489 -24.4513,-30.55681 -42.8081,-28.63327 -39.0192,-1.47124 -74.6768,18.22839 -106.1126,39.27122 -27.4601,19.28281 -52.9628,45.12902 -62.0025,78.30592 -2.9108,24.00347 18.676,49.02117 43.417,46.57579 41.4005,-0.49369 78.4941,-23.55071 108.3115,-50.5202 26.5153,-22.3804 52.8121,-49.50782 59.1947,-84.99946" /> + d="m 2515.4085,226.5937 c -48.3542,24.84206 -95.4271,57.89871 -121.9801,106.67545 -38.548,57.86235 -85.0736,109.83278 -130.7587,162.02483 -14.3416,13.79585 -31.8449,28.78802 -52.8206,28.38924 -22.4201,-5.81296 -20.145,-35.44311 -3.7589,-46.92382 18.3472,-20.65863 39.7594,-38.46949 61.3752,-55.55681 37.3089,-27.01631 74.2659,-55.34905 116.5753,-74.2272 45.8819,-21.27356 92.5741,-41.44894 133.4511,-71.77058" /> + d="m 2561.9362,176.5937 c -11.728,39.55572 -31.7885,76.05727 -54.1537,110.51619 -11.367,17.27415 -23.5479,34.0347 -36.8185,49.90047" /> + d="m 2471.6585,334.92703 c 39.4203,-54.93792 84.2673,-108.82208 144.2119,-142.13528 20.4555,-10.53089 43.6781,-13.18946 66.1233,-16.24748 15.4075,-2.13385 35.1588,8.90133 33.4692,26.24623 -2.9508,16.37726 -14.16,29.73489 -22.9962,43.3486 -13.3021,19.00229 -30.5436,36.66009 -36.611,59.58253 -4.3581,18.38699 14.1449,34.91044 31.9547,29.10574 16.8023,-4.83584 31.073,-15.60156 46.3125,-23.86514 23.356,-14.17855 45.5509,-30.69352 63.9244,-51.0352" /> + d="m 2945.2696,276.5937 c 22.3825,-18.04222 43.6601,-40.96167 49.1836,-70.14766 1.6596,-16.7076 -14.1662,-31.70685 -30.5059,-31.31677 -38.4972,-6.9588 -76.9683,9.1156 -108.0208,30.84253 -27.6063,19.08076 -55.1974,41.48489 -69.2262,72.82154 -7.1903,18.94072 -2.0574,44.40278 17.325,53.92146 22.3966,12.66022 50.5757,7.55107 71.8376,-5.02642 25.3952,-13.7463 46.7256,-33.50699 69.4067,-51.09468" /> + d="m 3032.0751,221.03814 c -34.9663,24.39777 -159.9904,94.46573 -91.1404,111.19476 49.5078,12.02932 120.689,-54.55505 178.2367,-101.75128 57.5477,-47.19623 164.1423,-136.348841 176.2724,-205.706175 12.1301,-69.357335 -35.8274,25.038279 -57.6617,62.402284 -21.8343,37.364011 -53.1817,114.582201 -93.4244,175.681151 -55.9422,84.93494 14.2268,97.70016 78.695,54.07139 43.4593,-29.41104 56.0463,-39.23804 79.8558,-64.64213" /> + d="m 3119.5751,163.39925 c 51.3284,2.8018 102.806,4.27265 154.1667,1.38889" /> + d="m 3359.1585,166.17703 c -26.0554,38.94967 -53.443,76.90675 -75.3826,118.80876 -8.2374,15.73252 -12.8945,40.55439 6.2938,47.64921 25.3545,6.43589 34.5616,-2.95338 49.294,-7.34667 48.0292,-19.31164 87.8533,-54.50776 122.854,-93.37814 15.42,-20.923 30.5124,-42.09003 46.9408,-62.26134" /> + d="m 3511.2418,168.95481 c -31.3786,34.96488 -59.3857,72.92099 -84.9995,112.24284 -6.288,13.61689 -16.1644,29.28735 -9.8599,44.58789 7.0942,13.41865 25.2642,10.69636 37.6171,7.93765 31.8778,-9.70921 58.1068,-31.49347 83.8755,-51.77583 20.5616,-16.72078 38.3203,-36.60992 53.5974,-58.18739 14.5478,-17.73424 29.2159,-35.93086 39.6787,-56.3568 4.934,-18.95097 -28.1547,-19.20088 -17.7187,-0.12487 9.5405,17.82935 32.3392,18.53167 50.1021,19.48194 16.3122,-3.37266 23.3898,15.5346 12.9603,26.5127 -6.8718,8.02389 -13.7478,15.769 -19.1588,24.9829 -16.8576,24.69747 -36.847,48.68268 -44.6449,78.10881 -3.0723,19.33042 19.5849,33.62972 36.7818,27.38476 35.6706,-8.34057 67.9833,-26.49985 99.2689,-44.93349" /> + d="m 3763.3251,216.87147 c 33.1817,22.33062 74.828,35.62344 114.8149,27.5851 15.6821,-3.20582 30.2525,-10.71137 43.1524,-19.942 17.3248,-14.2012 16.9209,-44.79145 -2.1675,-57.28603 -13.4925,-8.89012 -30.6833,-5.87659 -45.6599,-3.46265 -33.5763,7.00049 -61.9142,28.29846 -85.8989,51.8761 -25.4017,22.73023 -42.112,57.70516 -36.9155,92.17467 6.3894,18.1743 25.3211,28.36102 43.6991,29.78005 26.397,2.30348 52.8197,-3.96515 77.6246,-12.547 39.816,-14.49663 75.2011,-38.73414 108.0175,-65.12268" /> + + + + + + + + + + + + + + + diff --git a/mkdoc b/mkdoc deleted file mode 100755 index 8c082c3..0000000 --- a/mkdoc +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -# https://github.com/jimmyfrasche/autoreadme -autoreadme -f -template README.md.template -# Improve the appearance of the markdown document with features unavailable in godoc -cat README.md | tr '\n' '\v' | sed \ - -e 's/\v##\([^\v]*\)/\v## \1\v\v/g' \ - -e 's/\v• /* /g' \ - -e 's/\(http:\/\/www\.google\.com\/fonts\/\)/[Google Fonts](\1)/g' \ - -e 's/\(http:\/\/dejavu-fonts\.org\/\)/[DejaVu Fonts](\1)/g' \ - -e 's/draw2d.package.(\(https:\/\/github\.com\/llgcode\/draw2d\))/[draw2d](\1) package/g' \ - -e 's/FPDF.library.(\(http:\/\/www\.fpdf\.org\/\))/[FPDF](\1) library/g' \ - -e 's/original.FPDF.library/original [FPDF](http:\/\/www.fpdf.org\/) library/g' \ - -e 's/\(Effective.Go\)/[\1](https:\/\/golang.org\/doc\/effective_go.html)/g' \ - -e 's/\(fpdf_test.go\)/[\1](https:\/\/github.com\/jung-kurt\/gofpdf\/blob\/master\/fpdf_test.go)/g' \ - -e 's/golint.(\(https:\/\/github\.com\/golang\/lint\))/[golint](\1)/g' \ - -e 's/go.vet.(\(https:\/\/godoc\.org\/golang\.org\/x\/tools\/cmd\/vet\))/[go vet](\1)/g' \ - -e 's/test.coverage.(\(https:\/\/blog\.golang\.org\/cover\))/[test coverage](\1)/g' \ - -e 's/Pull.requests.(\(https:\/\/help\.github\.com\/articles\/using\-pull\-requests\/\))/[Pull requests](\1)/g' \ - -e 's/Your change should\v/Your change should\v\v/g' \ - -e 's/issue 109/[issue 109](https:\/\/github.com\/jung-kurt\/gofpdf\/issues\/109)/g' \ - | tr '\v' '\n' > _0 -mv _0 README.md diff --git a/pdf/reference/Fpdf_SVGBasicWrite.pdf b/pdf/reference/Fpdf_SVGBasicWrite.pdf index bc05a2b..b6cc82a 100644 --- a/pdf/reference/Fpdf_SVGBasicWrite.pdf +++ b/pdf/reference/Fpdf_SVGBasicWrite.pdf @@ -7,335 +7,884 @@ /Contents 4 0 R>> endobj 4 0 obj -<> +<> stream 0 J 0 j 0.57 w -BT /F0 16.00 Tf ET +BT /Fd08375f64eb9861c6eae4dfcfdbd3500fbdbe33e 16.00 Tf ET 0.000 G 0.000 g -BT 31.19 800.74 Td (This example renders a simple ) Tj ET -q 0.000 0.000 0.502 rg BT 230.70 800.74 Td (SVG) Tj ET 230.70 799.14 32.00 -0.80 re f Q -BT 262.70 800.74 Td ( \(scalable vector graphics\) image that contains) Tj ET -BT 31.18 784.74 Td (only basic path commands without any styling, color fill, reflection or endpoint) Tj ET -BT 31.18 768.74 Td (closures. In particular, the type of vector graphic returned from a ) Tj ET -q 0.000 0.000 0.502 rg BT 450.17 768.74 Td (jSignature) Tj ET 450.17 767.14 65.78 -0.80 re f Q -BT 515.95 768.74 Td ( web) Tj ET -BT 31.18 752.74 Td (control is supported and is used in this example.) Tj ET +BT /Fd08375f64eb9861c6eae4dfcfdbd3500fbdbe33e 16.00 Tf ET +BT 31.19 800.74 Td (This example renders a simple )Tj ET +BT /Fd08375f64eb9861c6eae4dfcfdbd3500fbdbe33e 16.00 Tf ET +q 0.000 0.000 0.502 rg BT 230.70 800.74 Td (SVG)Tj ET 230.70 799.14 32.00 -0.80 re f Q +BT /Fd08375f64eb9861c6eae4dfcfdbd3500fbdbe33e 16.00 Tf ET +BT 262.70 800.74 Td ( \(scalable vector graphics\) image that contains)Tj ET +BT 31.18 784.74 Td (only basic path commands without any styling, color fill, reflection or endpoint)Tj ET +BT 31.18 768.74 Td (closures. In particular, the type of vector graphic returned from a )Tj ET +BT /Fd08375f64eb9861c6eae4dfcfdbd3500fbdbe33e 16.00 Tf ET +q 0.000 0.000 0.502 rg BT 450.17 768.74 Td (jSignature)Tj ET 450.17 767.14 65.78 -0.80 re f Q +BT /Fd08375f64eb9861c6eae4dfcfdbd3500fbdbe33e 16.00 Tf ET +BT 515.95 768.74 Td ( web)Tj ET +BT 31.18 752.74 Td (control is supported and is used in this example.)Tj ET 1 J 0.71 w 0.000 0.000 0.502 RG -173.14 728.26 m -176.69201 726.39095 182.10238 728.53851 183.84896 730.80536 c S -183.85 730.81 m -185.59553 733.07220 184.58495 734.47986 182.68888 734.91049 c S -182.69 734.91 m -180.79282 735.34111 179.70744 734.16862 178.61086 732.56810 c S -178.61 732.57 m -177.51427 730.96757 177.03169 729.05904 176.76941 726.25412 c S -176.77 726.25 m -176.50713 723.44920 176.58763 718.92532 175.59231 716.02576 c S -175.59 716.03 m -174.59698 713.12621 172.70888 711.78580 169.93096 710.97133 c S -169.93 710.97 m -167.15304 710.15686 163.10183 710.49922 160.99777 712.68222 c S -161.00 712.68 m -158.89370 714.86523 159.25220 718.65958 161.04160 720.24991 c S -161.04 720.25 m -162.83099 721.84024 164.57017 721.79421 164.81549 718.92486 c S -164.82 718.92 m -165.06081 716.05552 159.34783 711.36114 157.59405 711.67243 c S -157.59 711.67 m -155.84027 711.98373 156.94420 711.67243 156.61927 711.67243 c S -194.42 717.62 m -195.55336 718.57545 196.53975 719.83734 196.71861 721.35310 c S -196.72 721.35 m -196.82446 722.07726 196.58118 722.91283 195.89534 723.27141 c S -195.90 723.27 m -194.29350 724.28299 192.26361 723.95615 190.57449 723.35079 c S -190.57 723.35 m -188.48355 722.55908 186.56863 721.33744 184.85714 719.90832 c S -184.86 719.91 m -183.75668 718.95525 182.71431 717.88298 182.01721 716.59503 c S -182.02 716.60 m -181.27049 714.82491 182.43659 712.43836 184.40396 712.18734 c S -184.40 712.19 m -185.88681 711.92596 187.32423 712.55186 188.58566 713.26658 c S -188.59 713.27 m -190.25962 714.11983 191.79288 715.22377 193.18879 716.47757 c S -193.19 716.48 m -193.60290 716.83039 194.01304 717.18786 194.42040 717.54843 c S -199.35 720.53 m -196.54236 718.91546 192.97248 716.48071 191.52980 714.77466 c S -191.53 714.77 m -190.08712 713.06861 191.65325 712.50117 193.05058 712.37366 c S -193.05 712.37 m -194.44790 712.24614 195.89422 712.78453 197.56822 713.70532 c S -197.57 713.71 m -199.24222 714.62611 201.44780 716.46597 202.73492 717.96366 c S -202.73 717.96 m -204.02203 719.46135 205.40992 720.91076 205.82992 722.02588 c S -205.83 722.03 m -206.24992 723.14099 206.31152 723.46716 205.66702 723.86598 c S -197.34 712.34 m -201.53970 715.84331 205.14769 720.18427 210.14205 722.62966 c S -210.14 722.63 m -211.66595 723.65683 215.03478 724.77732 215.41016 722.05536 c S -215.41 722.06 m -215.56246 719.73171 213.64299 718.07070 212.48553 716.26895 c S -212.49 716.27 m -211.68434 715.21492 210.02152 712.93076 209.77854 712.65527 c S -209.78 712.66 m -212.49367 716.83123 216.42339 720.09449 220.58985 722.74578 c S -220.59 722.75 m -222.11202 723.74785 225.98680 723.99924 225.05321 721.15944 c S -225.05 721.16 m -224.59796 719.01691 222.96208 717.46923 221.42602 716.06033 c S -221.43 716.06 m -219.84594 714.63332 220.58200 712.11502 222.92551 712.60418 c S -222.93 712.60 m -224.90790 712.72647 226.45016 714.14554 228.13027 715.04406 c S -228.13 715.04 m -231.73885 717.86466 234.44484 721.90966 238.75494 723.78135 c S -238.75 723.78 m -240.92664 724.63139 243.74468 725.41728 245.70339 723.68346 c S -245.70 723.68 m -247.32271 722.17600 246.40020 719.70592 245.20379 718.24469 c S -245.20 718.24 m -243.91773 716.33636 242.04581 714.92493 239.91289 714.07804 c S -239.91 714.08 m -237.50533 712.64078 234.30210 712.77113 232.08008 714.50451 c S -232.08 714.50 m -232.00346 714.55375 231.92079 714.59171 231.83970 714.63264 c S -237.53 725.94 m -236.16664 722.49110 234.75181 719.00201 232.45219 716.05907 c S -232.45 716.06 m -230.44053 712.94864 229.16906 709.39055 226.81651 706.49471 c S -226.82 706.49 m -225.13530 704.16637 223.36673 701.86107 221.16026 700.00071 c S -221.16 700.00 m -219.78331 699.56298 219.74355 701.47050 220.12388 702.32728 c S -220.12 702.33 m -221.03094 704.89014 222.75501 707.03352 224.00539 709.42369 c S -224.01 709.42 m -225.56584 712.15913 227.82633 714.34097 230.06657 716.51012 c S -232.03 714.35 m -234.97123 711.68212 239.53495 711.46073 243.00452 713.18561 c S -243.00 713.19 m -248.64064 715.57527 253.44019 719.45575 258.25868 723.14675 c S -258.26 723.15 m -260.98511 725.35221 263.61742 727.85352 265.20744 731.02457 c S -265.21 731.02 m -265.58109 732.17969 266.00169 733.72429 265.04456 734.69963 c S -265.04 734.70 m -263.28737 735.36357 261.88150 733.34147 260.61139 732.40457 c S -260.61 732.40 m -257.62787 729.49504 255.24533 726.01787 253.13898 722.43949 c S -253.14 722.44 m -251.85716 720.04012 250.56984 718.16982 249.95083 714.95719 c S -249.95 714.96 m -249.60668 713.17113 251.17742 712.12890 252.67159 712.39514 c S -252.67 712.40 m -254.59704 712.48556 256.36031 713.38919 258.13335 714.05752 c S -258.13 714.06 m -259.56564 714.74830 260.82323 715.73671 262.07316 716.70648 c S -263.25 720.83 m -266.45830 718.32194 269.24179 718.19770 272.84620 719.05054 c S -272.85 719.05 m -273.90124 719.39462 274.66655 720.32105 274.97709 721.36491 c S -274.98 721.36 m -275.41570 722.28065 274.95660 723.33824 274.06315 723.76115 c S -274.06 723.76 m -272.68466 724.63544 270.90412 724.50736 269.47476 723.82657 c S -269.47 723.83 m -267.11353 722.80474 265.27331 720.93322 263.49705 719.12908 c S -263.50 719.13 m -262.51271 717.95853 261.89445 716.43859 261.87150 714.90564 c S -261.87 714.91 m -261.92482 714.00566 262.63090 713.30406 263.46867 713.07181 c S -263.47 713.07 m -265.49308 712.22637 267.82843 711.79548 269.96169 712.48022 c S -269.96 712.48 m -271.38589 712.99418 272.77993 713.60559 274.12454 714.29924 c S -274.12 714.30 m -275.73324 715.24381 277.04723 716.59074 278.37100 717.88463 c S -282.40 711.90 m -284.42511 711.68139 286.87452 711.71014 288.24351 713.48277 c S -288.24 713.48 m -289.77356 714.89601 291.29688 716.88360 290.76238 719.09920 c S -290.76 719.10 m -290.46995 720.66673 288.38862 721.80129 287.07511 720.65649 c S -287.08 720.66 m -284.83080 719.06805 284.85744 715.69051 286.16454 713.50810 c S -286.16 713.51 m -287.83794 710.78294 291.39981 709.93746 294.37610 710.58475 c S -294.38 710.58 m -298.19476 711.31369 301.75755 714.39307 302.21808 718.37987 c S -302.22 718.38 m -302.27384 720.70131 302.27291 723.02577 302.56760 725.33335 c S -302.57 725.33 m -302.84540 728.35509 303.27076 731.63068 305.33980 734.00518 c S -305.34 734.01 m -306.54888 735.31235 308.96093 735.90837 310.24950 734.39793 c S -310.25 734.40 m -311.28815 733.04105 310.46366 731.19605 309.49016 730.05151 c S -309.49 730.05 m -308.33498 728.27449 306.04620 727.99188 304.16152 727.48991 c S -304.16 727.49 m -302.28972 727.08157 300.01717 727.29546 298.78181 728.93980 c S -298.78 728.94 m -298.09957 729.69710 297.33548 730.54928 297.31969 731.62981 c S -315.29 727.51 m -315.00973 727.44850 314.82299 727.12458 314.91766 726.85678 c S -314.92 726.86 m -315.00798 726.60006 315.22645 726.38678 315.49277 726.32089 c S -315.49 726.32 m -315.64178 726.31238 315.78365 726.43926 315.79232 726.58816 c S -315.79 726.59 m -315.84805 726.85217 315.81141 727.14788 315.64285 727.36550 c S -315.64 727.37 m -315.55476 727.46279 315.42043 727.53319 315.28659 727.50625 c S -313.47 724.12 m -311.35342 721.29454 309.30928 718.41152 307.38263 715.45503 c S -307.38 715.46 m -306.99823 714.64637 306.89333 713.52880 307.56739 712.84376 c S -307.57 712.84 m -308.38275 712.24289 309.44839 712.56426 310.33569 712.79924 c S -310.34 712.80 m -312.59541 713.39748 314.80881 714.34466 316.57502 715.90806 c S -316.58 715.91 m -317.65017 716.79085 318.63346 717.78496 319.50832 718.86643 c S -332.40 721.78 m -332.16589 723.13908 330.67278 723.93843 329.37515 723.80245 c S -329.38 723.80 m -326.61691 723.90645 324.09629 722.51390 321.87411 721.02639 c S -321.87 721.03 m -319.93298 719.66330 318.13021 717.83625 317.49119 715.49099 c S -317.49 715.49 m -317.28543 713.79420 318.81139 712.02572 320.56032 712.19858 c S -320.56 712.20 m -323.48689 712.23348 326.10902 713.86336 328.21679 715.76982 c S -328.22 715.77 m -330.09114 717.35188 331.95005 719.26950 332.40123 721.77838 c S -334.38 720.14 m -330.96442 718.38670 327.63686 716.04994 325.75985 712.60194 c S -325.76 712.60 m -323.03491 708.51169 319.74605 704.83793 316.51659 701.14850 c S -316.52 701.15 m -315.50279 700.17328 314.26549 699.11349 312.78273 699.14168 c S -312.78 699.14 m -311.19787 699.55260 311.35870 701.64714 312.51702 702.45870 c S -312.52 702.46 m -313.81397 703.91905 315.32759 705.17809 316.85560 706.38598 c S -316.86 706.39 m -319.49294 708.29575 322.10541 710.29857 325.09624 711.63306 c S -325.10 711.63 m -328.33960 713.13687 331.64025 714.56306 334.52982 716.70648 c S -337.67 723.68 m -336.84252 720.88107 335.42446 718.30079 333.84347 715.86491 c S -333.84 715.86 m -333.03995 714.64381 332.17889 713.45902 331.24079 712.33748 c S -331.29 712.48 m -334.07649 716.36828 337.24670 720.17732 341.48414 722.53221 c S -341.48 722.53 m -342.93013 723.27663 344.57172 723.46456 346.15836 723.68073 c S -346.16 723.68 m -347.24751 723.83157 348.64372 723.05150 348.52428 721.82540 c S -348.52 721.83 m -348.31569 720.66770 347.52332 719.72346 346.89869 718.76111 c S -346.90 718.76 m -345.95837 717.41785 344.73958 716.16963 344.31068 714.54926 c S -344.31 714.55 m -344.00261 713.24949 345.31058 712.08146 346.56954 712.49179 c S -346.57 712.49 m -347.75729 712.83364 348.76607 713.59466 349.84334 714.17881 c S -349.84 714.18 m -351.49437 715.18108 353.06331 716.34851 354.36212 717.78645 c S -364.77 716.61 m -366.35139 717.88369 367.85549 719.50385 368.24594 721.56699 c S -368.25 721.57 m -368.36326 722.74804 367.24454 723.80833 366.08950 723.78076 c S -366.09 723.78 m -363.36815 724.27267 360.64865 723.13638 358.45357 721.60052 c S -358.45 721.60 m -356.50210 720.25171 354.55170 718.66798 353.56001 716.45281 c S -353.56 716.45 m -353.05173 715.11390 353.41457 713.31400 354.78470 712.64113 c S -354.78 712.64 m -356.36791 711.74619 358.35987 712.10735 359.86286 712.99644 c S -359.86 713.00 m -361.65803 713.96816 363.16587 715.36503 364.76918 716.60830 c S -370.91 720.54 m -368.43366 718.81082 359.59578 713.85776 364.46275 712.67519 c S -364.46 712.68 m -367.96243 711.82485 372.99419 716.53166 377.06220 719.86793 c S -377.06 719.87 m -381.13021 723.20421 388.66532 729.50635 389.52279 734.40918 c S -389.52 734.41 m -390.38026 739.31201 386.99017 732.63924 385.44672 729.99800 c S -385.45 730.00 m -383.90327 727.35676 381.68734 721.89825 378.84260 717.57920 c S -378.84 717.58 m -374.88808 711.57520 379.84829 710.67284 384.40551 713.75693 c S -384.41 713.76 m -387.47762 715.83598 388.36739 716.53064 390.05047 718.32644 c S -377.09 724.61 m -380.71911 724.41189 384.35803 724.30792 387.98869 724.51177 c S -394.03 724.41 m -392.18491 721.66026 390.24889 718.97709 388.69800 716.01507 c S -388.70 716.02 m -388.11570 714.90294 387.78649 713.14830 389.14290 712.64677 c S -389.14 712.65 m -390.93520 712.19182 391.58604 712.85554 392.62746 713.16610 c S -392.63 713.17 m -396.02262 714.53123 398.83776 717.01922 401.31194 719.76695 c S -401.31 719.77 m -402.40197 721.24598 403.46885 722.74227 404.63016 724.16817 c S -404.78 724.22 m -402.55929 721.74558 400.57949 719.06249 398.76886 716.28285 c S -398.77 716.28 m -398.32437 715.32028 397.62621 714.21254 398.07187 713.13095 c S -398.07 713.13 m -398.57336 712.18240 399.85778 712.37483 400.73100 712.56985 c S -400.73 712.57 m -402.98443 713.25618 404.83854 714.79610 406.66011 716.22985 c S -406.66 716.23 m -408.11360 717.41183 409.36895 718.81778 410.44888 720.34308 c S -410.45 720.34 m -411.47726 721.59671 412.51414 722.88301 413.25375 724.32691 c S -413.25 724.33 m -413.60253 725.66655 411.26351 725.68421 412.00122 724.33574 c S -412.00 724.34 m -412.67563 723.07539 414.28726 723.02575 415.54291 722.95857 c S -415.54 722.96 m -416.69601 723.19698 417.19632 721.86044 416.45907 721.08440 c S -416.46 721.08 m -415.97330 720.51720 415.48724 719.96970 415.10474 719.31838 c S -415.10 719.32 m -413.91309 717.57253 412.50005 715.87703 411.94882 713.79691 c S -411.95 713.80 m -411.73164 712.43046 413.33326 711.41965 414.54890 711.86110 c S -414.55 711.86 m -417.07044 712.45069 419.35460 713.73436 421.56616 715.03742 c S -422.60 720.83 m -424.94264 719.25149 427.88660 718.31183 430.71325 718.88005 c S -430.71 718.88 m -431.82181 719.10667 432.85178 719.63723 433.76367 720.28974 c S -433.76 720.29 m -434.98835 721.29361 434.95979 723.45602 433.61045 724.33926 c S -433.61 724.34 m -432.65667 724.96769 431.44146 724.75467 430.38277 724.58403 c S -430.38 724.58 m -428.00929 724.08917 426.00610 722.58363 424.31063 720.91694 c S -424.31 720.92 m -422.51500 719.31015 421.33376 716.83779 421.70110 714.40116 c S -421.70 714.40 m -422.15276 713.11643 423.49103 712.39634 424.79016 712.29603 c S -424.79 712.30 m -426.65615 712.13320 428.52395 712.57632 430.27740 713.18297 c S -430.28 713.18 m -433.09197 714.20773 435.59332 715.92106 437.91309 717.78645 c S +172.56 729.26 m +176.12859 727.37498 181.56609 729.53330 183.32142 731.81151 c S +183.32 731.81 m +185.07675 734.08972 184.06110 735.50444 182.15553 735.93722 c S +182.16 735.94 m +180.24996 736.37000 179.15914 735.19163 178.05706 733.58309 c S +178.06 733.58 m +176.95498 731.97454 176.46998 730.05644 176.20638 727.23746 c S +176.21 727.24 m +175.94279 724.41849 176.02369 719.87193 175.02338 716.95784 c S +175.02 716.96 m +174.02307 714.04375 172.12550 712.69662 169.33366 711.87807 c S +169.33 711.88 m +166.54182 711.05951 162.47030 711.40359 160.35569 713.59754 c S +160.36 713.60 m +158.24107 715.79148 158.60137 719.60485 160.39973 721.20315 c S +160.40 721.20 m +162.19810 722.80145 163.94600 722.75520 164.19254 719.87147 c S +164.19 719.87 m +164.43909 716.98774 158.69748 712.26983 156.93491 712.58268 c S +156.93 712.58 m +155.17233 712.89554 156.28179 712.58268 155.95524 712.58268 c S +193.95 718.56 m +195.08449 719.52030 196.07583 720.78852 196.25558 722.31187 c S +196.26 722.31 m +196.36196 723.03967 196.11746 723.87942 195.42818 724.23980 c S +195.43 724.24 m +193.81831 725.25646 191.77825 724.92797 190.08066 724.31958 c S +190.08 724.32 m +187.97924 723.52390 186.05472 722.29614 184.33465 720.85985 c S +184.33 720.86 m +183.22868 719.90201 182.18108 718.82436 181.48048 717.52995 c S +181.48 717.53 m +180.73003 715.75096 181.90197 713.35245 183.87920 713.10017 c S +183.88 713.10 m +185.36948 712.83748 186.81411 713.46652 188.08186 714.18482 c S +188.08 714.18 m +189.76421 715.04235 191.30516 716.15183 192.70807 717.41191 c S +192.71 717.41 m +193.12425 717.76649 193.53644 718.12575 193.94585 718.48814 c S +198.90 721.49 m +196.07844 719.86201 192.49067 717.41507 191.04076 715.70047 c S +191.04 715.70 m +189.59085 713.98586 191.16483 713.41558 192.56916 713.28742 c S +192.57 713.29 m +193.97349 713.15927 195.42706 713.70036 197.10945 714.62576 c S +197.11 714.63 m +198.79183 715.55117 201.00848 717.40025 202.30205 718.90544 c S +202.30 718.91 m +203.59561 720.41064 204.99046 721.86732 205.41256 722.98803 c S +205.41 722.99 m +205.83467 724.10873 205.89658 724.43654 205.24884 724.83735 c S +196.88 713.26 m +201.10084 716.77447 204.72691 721.13719 209.74630 723.59484 c S +209.75 723.59 m +211.27784 724.62715 214.66356 725.75326 215.04082 723.01765 c S +215.04 723.02 m +215.19389 720.68236 213.26479 719.01302 212.10153 717.20225 c S +212.10 717.20 m +211.29633 716.14293 209.62517 713.84732 209.38097 713.57045 c S +209.38 713.57 m +212.10971 717.76734 216.05913 721.04696 220.24647 723.71153 c S +220.25 723.71 m +221.77628 724.71863 225.67048 724.97128 224.73220 722.11724 c S +224.73 722.12 m +224.27467 719.96397 222.63059 718.40854 221.08683 716.99257 c S +221.09 716.99 m +219.49883 715.55841 220.23858 713.02749 222.59385 713.51910 c S +222.59 713.52 m +224.58617 713.64200 226.13616 715.06819 227.82469 715.97121 c S +227.82 715.97 m +231.45136 718.80595 234.17092 722.87123 238.50263 724.75230 c S +238.50 724.75 m +240.68520 725.60660 243.51738 726.39642 245.48590 724.65392 c S +245.49 724.65 m +247.11333 723.13890 246.18620 720.65644 244.98380 719.18788 c S +244.98 719.19 m +243.69129 717.26999 241.80998 715.85148 239.66638 715.00035 c S +239.67 715.00 m +237.24675 713.55589 234.02746 713.68689 231.79430 715.42895 c S +231.79 715.43 m +231.71730 715.47845 231.63421 715.51660 231.55272 715.55773 c S +237.27 726.92 m +235.90135 723.45558 234.47942 719.94900 232.16828 716.99131 c S +232.17 716.99 m +230.14653 713.86528 228.86869 710.28936 226.50435 707.37901 c S +226.50 707.38 m +224.81470 705.03899 223.03727 702.72215 220.81975 700.85245 c S +220.82 700.85 m +219.43589 700.41254 219.39593 702.32962 219.77817 703.19069 c S +219.78 703.19 m +220.68977 705.76640 222.42249 707.92052 223.67913 710.32267 c S +223.68 710.32 m +225.24740 713.07182 227.51923 715.26460 229.77069 717.44462 c S +231.74 715.27 m +234.69994 712.59242 239.28654 712.36992 242.77351 714.10344 c S +242.77 714.10 m +248.43787 716.50509 253.26148 720.40501 258.10412 724.11451 c S +258.10 724.11 m +260.84422 726.33103 263.48972 728.84488 265.08772 732.03182 c S +265.09 732.03 m +265.46324 733.19273 265.88595 734.74508 264.92402 735.72530 c S +264.92 735.73 m +263.15802 736.39257 261.74510 734.36034 260.46863 733.41874 c S +260.47 733.42 m +257.47016 730.49463 255.07567 727.00002 252.95876 723.40371 c S +252.96 723.40 m +251.67051 720.99231 250.37674 719.11264 249.75463 715.88391 c S +249.75 715.88 m +249.40876 714.08889 250.98737 713.04144 252.48903 713.30901 c S +252.49 713.31 m +254.42413 713.39988 256.19624 714.30805 257.97817 714.97973 c S +257.98 714.98 m +259.41764 715.67396 260.68153 716.66733 261.93773 717.64196 c S +263.12 721.79 m +266.34484 719.26553 269.14228 719.14066 272.76476 719.99777 c S +272.76 720.00 m +273.82509 720.34358 274.59424 721.27465 274.90634 722.32374 c S +274.91 722.32 m +275.34714 723.24408 274.88574 724.30697 273.98781 724.73200 c S +273.99 724.73 m +272.60242 725.61067 270.81295 725.48194 269.37642 724.79774 c S +269.38 724.80 m +267.00336 723.77079 265.15391 721.88990 263.36875 720.07671 c S +263.37 720.08 m +262.37948 718.90029 261.75811 717.37273 261.73505 715.83210 c S +261.74 715.83 m +261.78864 714.92761 262.49826 714.22249 263.34023 713.98907 c S +263.34 713.99 m +265.37479 713.13940 267.72184 712.70635 269.86579 713.39452 c S +269.87 713.39 m +271.29714 713.91105 272.69816 714.52553 274.04952 715.22266 c S +274.05 715.22 m +275.66628 716.17196 276.98685 717.52565 278.31726 718.82602 c S +282.36 712.81 m +284.40171 712.59169 286.86340 712.62058 288.23925 714.40209 c S +288.24 714.40 m +289.77697 715.82242 291.30792 717.81997 290.77075 720.04668 c S +290.77 720.05 m +290.47686 721.62207 288.38509 722.76231 287.06499 721.61177 c S +287.06 721.61 m +284.80944 720.01538 284.83621 716.62090 286.14986 714.42755 c S +286.15 714.43 m +287.83165 711.68873 291.41137 710.83902 294.40258 711.48955 c S +294.40 711.49 m +298.24039 712.22214 301.82103 715.31696 302.28387 719.32375 c S +302.28 719.32 m +302.33991 721.65682 302.33898 723.99293 302.63515 726.31208 c S +302.64 726.31 m +302.91434 729.34896 303.34183 732.64097 305.42124 735.02737 c S +305.42 735.03 m +306.63637 736.34109 309.06052 736.94011 310.35555 735.42209 c S +310.36 735.42 m +311.39940 734.05841 310.57078 732.20417 309.59241 731.05389 c S +309.59 731.05 m +308.43144 729.26796 306.13118 728.98393 304.23705 728.47945 c S +304.24 728.48 m +302.35587 728.06906 300.07192 728.28403 298.83038 729.93660 c S +298.83 729.94 m +298.14472 730.69770 297.37680 731.55415 297.36093 732.64010 c S +315.42 728.50 m +315.13964 728.43783 314.95197 728.11229 315.04711 727.84314 c S +315.05 727.84 m +315.13788 727.58513 315.35744 727.37078 315.62510 727.30456 c S +315.63 727.30 m +315.77486 727.29601 315.91744 727.42353 315.92615 727.57317 c S +315.93 727.57 m +315.98217 727.83851 315.94534 728.13571 315.77593 728.35441 c S +315.78 728.35 m +315.68741 728.45219 315.55240 728.52295 315.41789 728.49587 c S +313.59 725.09 m +311.46500 722.25303 309.41062 719.35555 307.47431 716.38424 c S +307.47 716.38 m +307.08799 715.57153 306.98256 714.44836 307.65999 713.75988 c S +307.66 713.76 m +308.47944 713.15600 309.55042 713.47898 310.44217 713.71514 c S +310.44 713.72 m +312.71322 714.31638 314.93772 715.26830 316.71277 716.83954 c S +316.71 716.84 m +317.79331 717.72675 318.78154 718.72585 319.66078 719.81274 c S +332.62 722.74 m +332.38180 724.10681 330.88121 724.91016 329.57707 724.77351 c S +329.58 724.77 m +326.80500 724.87803 324.27175 723.47849 322.03843 721.98353 c S +322.04 721.98 m +320.08756 720.61361 318.27576 718.77740 317.63354 716.42039 c S +317.63 716.42 m +317.42675 714.71509 318.96036 712.93774 320.71805 713.11147 c S +320.72 713.11 m +323.65930 713.14654 326.29456 714.78460 328.41290 716.70061 c S +328.41 716.70 m +330.29665 718.29060 332.16487 720.21783 332.61832 722.73929 c S +334.61 721.10 m +331.17430 719.33060 327.83007 716.98214 325.94364 713.51685 c S +325.94 713.52 m +323.20505 709.40609 319.89970 705.71392 316.65405 702.00600 c S +316.65 702.01 m +315.63517 701.02589 314.39167 699.96079 312.90148 699.98912 c S +312.90 699.99 m +311.30867 700.40210 311.47030 702.50713 312.63443 703.32277 c S +312.63 703.32 m +313.93789 704.79043 315.45909 706.05578 316.99476 707.26973 c S +316.99 707.27 m +319.64532 709.18907 322.27089 711.20194 325.27671 712.54311 c S +325.28 712.54 m +328.53633 714.05446 331.85352 715.48780 334.75757 717.64196 c S +337.92 724.65 m +337.08187 721.83748 335.65670 719.24427 334.06779 716.79618 c S +334.07 716.80 m +333.26023 715.56896 332.39486 714.37823 331.45206 713.25106 c S +331.50 713.40 m +334.30197 717.30207 337.48807 721.13020 341.74676 723.49689 c S +341.75 723.50 m +343.19999 724.24505 344.84981 724.43392 346.44440 724.65118 c S +346.44 724.65 m +347.53901 724.80277 348.94222 724.01879 348.82218 722.78655 c S +348.82 722.79 m +348.61255 721.62304 347.81620 720.67407 347.18845 719.70690 c S +347.19 719.71 m +346.24341 718.35690 345.01851 717.10243 344.58746 715.47393 c S +344.59 715.47 m +344.27785 714.16765 345.59237 712.99376 346.85764 713.40615 c S +346.86 713.41 m +348.05134 713.74971 349.06519 714.51454 350.14786 715.10162 c S +350.15 715.10 m +351.80716 716.10892 353.38397 717.28220 354.68929 718.72735 c S +365.15 717.54 m +366.73865 718.82508 368.25029 720.45336 368.64270 722.52684 c S +368.64 722.53 m +368.76060 723.71381 367.63628 724.77942 366.47545 724.75170 c S +366.48 724.75 m +363.74046 725.24608 361.00733 724.10410 358.80124 722.56053 c S +358.80 722.56 m +356.83999 721.20497 354.87981 719.61329 353.88315 717.38702 c S +353.88 717.39 m +353.37233 716.04140 353.73699 714.23248 355.11399 713.55624 c S +355.11 713.56 m +356.70513 712.65681 358.70707 713.01978 360.21760 713.91333 c S +360.22 713.91 m +362.02177 714.88992 363.53716 716.29379 365.14851 717.54329 c S +371.32 721.49 m +368.83136 719.75686 359.94918 714.77896 364.84054 713.59047 c S +364.84 713.59 m +368.35776 712.73586 373.41474 717.46627 377.50315 720.81926 c S +377.50 720.82 m +381.59155 724.17226 389.16443 730.50600 390.02620 735.43340 c S +390.03 735.43 m +390.88797 740.36081 387.48089 733.65459 385.92970 731.00011 c S +385.93 731.00 m +384.37851 728.34563 382.15147 722.85976 379.29248 718.51906 c S +379.29 718.52 m +375.31813 712.48497 380.30320 711.57808 384.88327 714.67763 c S +384.88 714.68 m +387.97078 716.76710 388.86501 717.46525 390.55652 719.27005 c S +377.53 725.59 m +381.17839 725.38600 384.83555 725.28150 388.48441 725.48638 c S +394.55 725.39 m +392.70166 722.62057 390.75594 719.92396 389.19727 716.94708 c S +389.20 716.95 m +388.61205 715.82939 388.28120 714.06595 389.64440 713.56191 c S +389.64 713.56 m +391.44568 713.10468 392.09979 713.77172 393.14644 714.08384 c S +393.15 714.08 m +396.55861 715.45581 399.38786 717.95628 401.87444 720.71777 c S +401.87 720.72 m +402.96994 722.20422 404.04216 723.70801 405.20929 725.14105 c S +405.36 725.19 m +403.12805 722.70632 401.13832 720.00978 399.31862 717.21621 c S +399.32 717.22 m +398.87189 716.24881 398.17024 715.13552 398.61813 714.04852 c S +398.62 714.05 m +399.12213 713.09521 400.41300 713.28861 401.29059 713.48460 c S +401.29 713.48 m +403.55531 714.17437 405.41872 715.72201 407.24942 717.16295 c S +407.25 717.16 m +408.71020 718.35085 409.97184 719.76385 411.05718 721.29680 c S +411.06 721.30 m +412.09071 722.55670 413.13279 723.84946 413.87611 725.30059 c S +413.88 725.30 m +414.22664 726.64694 411.87589 726.66470 412.61730 725.30947 c S +412.62 725.31 m +413.29510 724.04280 414.91480 723.99291 416.17675 723.92540 c S +416.18 723.93 m +417.33562 724.16500 417.83844 722.82176 417.09749 722.04183 c S +417.10 722.04 m +416.60929 721.47179 416.12080 720.92154 415.73638 720.26695 c S +415.74 720.27 m +414.53875 718.51235 413.11863 716.80835 412.56464 714.71781 c S +412.56 714.72 m +412.34637 713.34451 413.95602 712.32863 415.17776 712.77230 c S +415.18 712.77 m +417.71193 713.36484 420.00754 714.65494 422.23019 715.96454 c S +423.27 721.79 m +425.62360 720.19973 428.58231 719.25536 431.42312 719.82643 c S +431.42 719.83 m +432.53724 720.05419 433.57238 720.58741 434.48883 721.24319 c S +434.49 721.24 m +435.71965 722.25209 435.69096 724.42534 434.33485 725.31300 c S +434.33 725.31 m +433.37629 725.94459 432.15499 725.73050 431.09100 725.55900 c S +431.09 725.56 m +428.70561 725.06166 426.69238 723.54857 424.98842 721.87353 c S +424.99 721.87 m +423.18378 720.25869 421.99662 717.77394 422.36580 715.32509 c S +422.37 715.33 m +422.81973 714.03392 424.16471 713.31022 425.47035 713.20941 c S +425.47 713.21 m +427.34569 713.04576 429.22286 713.49111 430.98509 714.10079 c S +430.99 714.10 m +433.81377 715.13069 436.32766 716.85261 438.65906 718.72735 c S +165.00 666.86 m +162.81903 666.86099 160.67485 667.46404 v S +160.67 667.46 m +158.56417 668.10060 157.15705 669.13919 v S +157.16 669.14 m 158.06 674.50 l S +158.06 674.50 m 158.26 674.50 l S +158.26 674.50 m +159.73677 673.42756 161.44541 672.82450 v S +161.45 672.82 m +163.15406 672.22145 164.76220 672.22145 v S +164.76 672.22 m +167.91147 672.22145 167.91147 674.49965 v S +167.91 674.50 m +167.91147 675.37072 167.44243 675.94027 v S +167.44 675.94 m +167.00689 676.54332 165.86779 677.04587 v S +165.87 677.05 m 162.38 678.62 l S +162.38 678.62 m +160.00479 679.69259 158.69818 681.53525 v S +158.70 681.54 m +157.42507 683.37791 157.42507 685.82362 v S +157.43 685.82 m +157.42507 688.06831 158.46366 689.70996 v S +158.46 689.71 m +159.53575 691.38510 161.44541 692.28968 v S +161.45 692.29 m +163.38858 693.19425 165.96830 693.19425 v S +165.97 693.19 m +167.87797 693.19425 169.75413 692.69171 v S +169.75 692.69 m +171.63029 692.18917 172.80289 691.38510 v S +172.80 691.39 m 171.93 686.33 l S +171.93 686.33 m 171.73 686.33 l S +171.73 686.33 m +170.69221 687.06323 169.25158 687.46526 v S +169.25 687.47 m +167.84446 687.90080 166.47085 687.90080 v S +166.47 687.90 m +163.52259 687.90080 163.52259 685.89063 v S +163.52 685.89 m +163.52259 685.08656 163.99163 684.51701 v S +163.99 684.52 m +164.49418 683.94746 165.56627 683.47842 v S +165.57 683.48 m 168.58 682.10 l S +168.58 682.10 m +171.46278 680.79819 172.73588 679.05604 v S +172.74 679.06 m +174.00899 677.34739 174.00899 674.80117 v S +174.01 674.80 m +174.00899 672.38897 172.86990 670.57981 v S +172.87 670.58 m +171.76430 668.80416 169.75413 667.83258 v S +169.75 667.83 m +167.74396 666.86099 164.99672 666.86099 v S +165.00 666.86 m 165.00 666.86 l S +181.18 667.20 m +178.76635 667.19602 177.35922 668.53614 v S +177.36 668.54 m +175.95210 669.87625 175.95210 672.12094 v S +175.95 672.12 m +175.95210 676.87835 182.28415 677.44790 v S +182.28 677.45 m 186.41 677.82 l S +186.41 677.82 m 186.41 677.98 l S +186.41 677.98 m +186.40500 679.15655 185.70144 679.65909 v S +185.70 679.66 m +185.03138 680.19514 183.55726 680.19514 v S +183.56 680.20 m +182.08313 680.19514 180.44149 679.82661 v S +180.44 679.83 m +178.79985 679.49158 177.82827 678.92203 v S +177.83 678.92 m 177.59 678.92 l S +177.59 678.92 m 178.46 683.68 l S +178.46 683.68 m +181.41307 684.88554 184.69636 684.88554 v S +184.70 684.89 m +192.23450 684.88554 192.23450 677.54841 v S +192.23 677.55 m 192.23 672.32 l S +192.23 672.32 m +192.23450 670.91484 192.43552 669.67523 v S +192.44 669.68 m +192.67004 668.43563 193.03857 667.73207 v S +193.04 667.73 m 193.04 667.46 l S +193.04 667.46 m 187.61 667.46 l S +187.61 667.46 m +187.10856 668.60314 187.00805 669.97676 v S +187.01 669.98 m 186.77 669.98 l S +186.77 669.98 m +186.13698 668.70365 184.62935 667.93308 v S +184.63 667.93 m +183.12172 667.19602 181.17855 667.19602 v S +181.18 667.20 m 181.18 667.20 l S +181.61 672.66 m +181.61409 671.28337 183.25573 671.28337 v S +183.26 671.28 m +184.66285 671.28337 185.53393 672.08744 v S +185.53 672.09 m +186.40500 672.89151 186.40500 674.13112 v S +186.41 674.13 m 186.41 674.53 l S +186.41 674.53 m 183.69 674.30 l S +183.69 674.30 m +181.61409 674.09761 181.61409 672.65699 v S +181.61 672.66 m 181.61 672.66 l S +196.09 667.46 m 196.09 684.48 l S +196.09 684.48 m 201.51 684.48 l S +201.51 684.48 m 201.51 681.50 l S +201.51 681.50 m 201.75 681.50 l S +201.75 681.50 m +202.35234 683.10989 203.65895 683.98096 v S +203.66 683.98 m +204.99907 684.88554 206.74121 684.88554 v S +206.74 684.89 m +210.39303 684.88554 211.73314 681.73627 v S +211.73 681.74 m 211.87 681.74 l S +211.87 681.74 m +212.63772 683.31091 214.01134 684.08147 v S +214.01 684.08 m +215.38496 684.88554 217.22762 684.88554 v S +217.23 684.89 m +220.17587 684.88554 221.71700 682.94237 v S +221.72 682.94 m +223.29164 681.03271 223.29164 677.54841 v S +223.29 677.55 m 223.29 667.46 l S +223.29 667.46 m 217.26 667.46 l S +217.26 667.46 m 217.26 677.01 l S +217.26 677.01 m +217.26112 679.79310 215.11693 679.79310 v S +215.12 679.79 m +214.01134 679.79310 213.34128 678.95553 v S +213.34 678.96 m +212.70473 678.15146 212.70473 676.77784 v S +212.70 676.78 m 212.70 667.46 l S +212.70 667.46 m 206.67 667.46 l S +206.67 667.46 m 206.67 676.98 l S +206.67 676.98 m +206.67421 679.79310 204.53002 679.79310 v S +204.53 679.79 m +203.42443 679.79310 202.75437 678.95553 v S +202.75 678.96 m +202.11782 678.11796 202.11782 676.64383 v S +202.12 676.64 m 202.12 667.46 l S +202.12 667.46 m 196.09 667.46 l S +227.08 659.09 m 227.08 684.48 l S +227.08 684.48 m 232.81 684.48 l S +232.81 684.48 m 232.81 681.97 l S +232.81 681.97 m 233.07 681.97 l S +233.07 681.97 m +234.64908 684.88554 238.06638 684.88554 v S +238.07 684.89 m +240.27757 684.88554 241.91921 683.77995 v S +241.92 683.78 m +243.56085 682.67435 244.46543 680.66418 v S +244.47 680.66 m +245.37001 678.68751 245.37001 675.97377 v S +245.37 675.97 m +245.37001 673.29354 244.46543 671.28337 v S +244.47 671.28 m +243.56085 669.27320 241.91921 668.16760 v S +241.92 668.17 m +240.27757 667.06201 238.06638 667.06201 v S +238.07 667.06 m +235.01762 667.06201 233.37598 669.40721 v S +233.38 669.41 m 233.11 669.41 l S +233.11 669.41 m 233.11 659.09 l S +233.11 659.09 m 227.08 659.09 l S +242.05 672.15 m +243.56085 672.15445 244.43192 673.15953 v S +244.43 673.16 m +245.30300 674.19812 245.30300 675.94027 v S +245.30 675.94 m +245.30300 677.74943 244.43192 678.75451 v S +244.43 678.75 m +243.59435 679.79310 242.05322 679.79310 v S +242.05 679.79 m +240.57909 679.79310 239.70802 678.75451 v S +239.71 678.75 m +238.83694 677.74943 238.83694 675.97377 v S +238.84 675.97 m +238.83694 674.23162 239.70802 673.19304 v S +239.71 673.19 m +240.57909 672.15445 242.05322 672.15445 v S +242.05 672.15 m 242.05 672.15 l S +248.42 667.46 m 248.42 693.60 l S +248.42 693.60 m 254.45 693.60 l S +254.45 693.60 m 254.45 667.46 l S +254.45 667.46 m 248.42 667.46 l S +266.58 667.06 m +262.38939 667.06201 259.94368 669.44071 v S +259.94 669.44 m +257.53147 671.81942 257.53147 675.97377 v S +257.53 675.97 m +257.53147 678.78802 258.67057 680.76469 v S +258.67 680.76 m +259.84317 682.77486 261.85335 683.81345 v S +261.85 683.81 m +263.89702 684.88554 266.47674 684.88554 v S +266.48 684.89 m +270.43008 684.88554 272.47376 682.54034 v S +272.47 682.54 m +274.55093 680.22864 274.55093 675.94027 v S +274.55 675.94 m 274.55 675.04 l S +274.55 675.04 m 263.63 673.96 l S +263.63 673.96 m +264.03103 672.75750 265.03612 672.25496 v S +265.04 672.25 m +266.07470 671.75241 267.58234 671.75241 v S +267.58 671.75 m +269.29098 671.75241 270.86562 672.15445 v S +270.87 672.15 m +272.47376 672.58998 273.27783 673.02552 v S +273.28 673.03 m 273.51 673.03 l S +273.51 673.03 m 272.64 668.27 l S +272.64 668.27 m +271.63619 667.83258 269.96104 667.46404 v S +269.96 667.46 m +268.28590 667.06201 266.57725 667.06201 v S +266.58 667.06 m 266.58 667.06 l S +266.38 680.46 m +265.27064 680.46316 264.46657 679.79310 v S +264.47 679.79 m +263.69600 679.12305 263.42798 677.51491 v S +263.43 677.51 m 269.06 678.05 l S +269.06 678.05 m +268.82195 679.32406 268.11838 679.89361 v S +268.12 679.89 m +267.41482 680.46316 266.37624 680.46316 v S +266.38 680.46 m 266.38 680.46 l S +291.77 666.86 m +289.59362 666.86099 287.44943 667.46404 v S +287.45 667.46 m +285.33875 668.10060 283.93163 669.13919 v S +283.93 669.14 m 284.84 674.50 l S +284.84 674.50 m 285.04 674.50 l S +285.04 674.50 m +286.51135 673.42756 288.22000 672.82450 v S +288.22 672.82 m +289.92865 672.22145 291.53679 672.22145 v S +291.54 672.22 m +294.68606 672.22145 294.68606 674.49965 v S +294.69 674.50 m +294.68606 675.37072 294.21701 675.94027 v S +294.22 675.94 m +293.78148 676.54332 292.64238 677.04587 v S +292.64 677.05 m 289.16 678.62 l S +289.16 678.62 m +286.77938 679.69259 285.47276 681.53525 v S +285.47 681.54 m +284.19965 683.37791 284.19965 685.82362 v S +284.20 685.82 m +284.19965 688.06831 285.23825 689.70996 v S +285.24 689.71 m +286.31033 691.38510 288.22000 692.28968 v S +288.22 692.29 m +290.16317 693.19425 292.74289 693.19425 v S +292.74 693.19 m +294.65255 693.19425 296.52871 692.69171 v S +296.53 692.69 m +298.40488 692.18917 299.57747 691.38510 v S +299.58 691.39 m 298.71 686.33 l S +298.71 686.33 m 298.51 686.33 l S +298.51 686.33 m +297.46679 687.06323 296.02617 687.46526 v S +296.03 687.47 m +294.61905 687.90080 293.24543 687.90080 v S +293.25 687.90 m +290.29718 687.90080 290.29718 685.89063 v S +290.30 685.89 m +290.29718 685.08656 290.76622 684.51701 v S +290.77 684.52 m +291.26876 683.94746 292.34085 683.47842 v S +292.34 683.48 m 295.36 682.10 l S +295.36 682.10 m +298.23736 680.79819 299.51047 679.05604 v S +299.51 679.06 m +300.78358 677.34739 300.78358 674.80117 v S +300.78 674.80 m +300.78358 672.38897 299.64448 670.57981 v S +299.64 670.58 m +298.53889 668.80416 296.52871 667.83258 v S +296.53 667.83 m +294.51854 666.86099 291.77130 666.86099 v S +291.77 666.86 m 291.77 666.86 l S +306.85 686.46 m +305.20589 686.46018 304.20081 687.43176 v S +304.20 687.43 m +303.19573 688.43685 303.19573 689.94448 v S +303.20 689.94 m +303.19573 691.45210 304.20081 692.42369 v S +304.20 692.42 m +305.20589 693.42877 306.84754 693.42877 v S +306.85 693.43 m +308.48918 693.42877 309.49427 692.42369 v S +309.49 692.42 m +310.49935 691.45210 310.49935 689.94448 v S +310.50 689.94 m +310.49935 688.43685 309.49427 687.43176 v S +309.49 687.43 m +308.48918 686.46018 306.84754 686.46018 v S +306.85 686.46 m 306.85 686.46 l S +303.83 667.46 m 303.83 684.48 l S +303.83 684.48 m 309.86 684.48 l S +309.86 684.48 m 309.86 667.46 l S +309.86 667.46 m 303.83 667.46 l S +321.42 658.69 m +319.44458 658.68629 317.60192 659.15533 v S +317.60 659.16 m +315.75926 659.59087 314.62016 660.32793 v S +314.62 660.33 m 315.63 665.05 l S +315.63 665.05 m 315.86 665.05 l S +315.86 665.05 m +316.79785 664.48229 318.03745 664.14726 v S +318.04 664.15 m +319.31057 663.77873 320.51667 663.77873 v S +320.52 663.78 m +322.76136 663.77873 323.96747 665.01834 v S +323.97 665.02 m +325.17357 666.25794 325.17357 668.56964 v S +325.17 668.57 m 325.17 669.81 l S +325.17 669.81 m 324.91 669.81 l S +324.91 669.81 m +323.26391 667.46404 320.21514 667.46404 v S +320.22 667.46 m +318.00396 667.46404 316.36231 668.53614 v S +316.36 668.54 m +314.72067 669.64173 313.81609 671.58490 v S +313.82 671.58 m +312.91152 673.56157 312.91152 676.17479 v S +312.91 676.17 m +312.91152 678.82152 313.81609 680.76469 v S +313.82 680.76 m +314.72067 682.70785 316.36231 683.77995 v S +316.36 683.78 m +318.00396 684.88554 320.21514 684.88554 v S +320.22 684.89 m +321.99080 684.88554 323.39792 684.08147 v S +323.40 684.08 m +324.80504 683.27740 325.47510 681.90378 v S +325.48 681.90 m 325.71 681.90 l S +325.71 681.90 m +325.77662 682.64085 325.94413 683.34441 v S +325.94 683.34 m +326.11165 684.04797 326.31267 684.48351 v S +326.31 684.48 m 332.01 684.48 l S +332.01 684.48 m 332.01 684.22 l S +332.01 684.22 m +331.57262 683.41141 331.37160 682.10480 v S +331.37 682.10 m +331.20409 680.79819 331.20409 679.62559 v S +331.20 679.63 m 331.20 668.64 l S +331.20 668.64 m +331.20409 663.84573 328.65787 661.26601 v S +328.66 661.27 m +326.14515 658.68629 321.42125 658.68629 v S +321.42 658.69 m 321.42 658.69 l S +322.26 672.49 m +323.73295 672.48948 324.60402 673.49456 v S +324.60 673.49 m +325.47510 674.49965 325.47510 676.17479 v S +325.48 676.17 m +325.47510 677.84994 324.60402 678.85502 v S +324.60 678.86 m +323.73295 679.86011 322.25882 679.86011 v S +322.26 679.86 m +320.71769 679.86011 319.84661 678.85502 v S +319.85 678.86 m +319.00904 677.88344 319.00904 676.14129 v S +319.01 676.14 m +319.00904 674.46615 319.88012 673.46106 v S +319.88 673.46 m +320.75119 672.48948 322.25882 672.48948 v S +322.26 672.49 m 322.26 672.49 l S +335.16 667.46 m 335.16 684.48 l S +335.16 684.48 m 340.58 684.48 l S +340.58 684.48 m 340.58 681.50 l S +340.58 681.50 m 340.82 681.50 l S +340.82 681.50 m +341.42244 683.10989 342.79606 683.98096 v S +342.80 683.98 m +344.16968 684.88554 346.11284 684.88554 v S +346.11 684.89 m +348.99409 684.88554 350.63574 682.94237 v S +350.64 682.94 m +352.31088 680.99921 352.31088 677.54841 v S +352.31 677.55 m 352.31 667.46 l S +352.31 667.46 m 346.28 667.46 l S +346.28 667.46 m 346.28 676.84 l S +346.28 676.84 m +346.28036 679.79310 343.86815 679.79310 v S +343.87 679.79 m +342.62855 679.79310 341.89148 678.92203 v S +341.89 678.92 m +341.18792 678.05095 341.18792 676.50982 v S +341.19 676.51 m 341.19 667.46 l S +341.19 667.46 m 335.16 667.46 l S +360.22 667.20 m +357.80528 667.19602 356.39816 668.53614 v S +356.40 668.54 m +354.99104 669.87625 354.99104 672.12094 v S +354.99 672.12 m +354.99104 676.87835 361.32308 677.44790 v S +361.32 677.45 m 365.44 677.82 l S +365.44 677.82 m 365.44 677.98 l S +365.44 677.98 m +365.44393 679.15655 364.74037 679.65909 v S +364.74 679.66 m +364.07032 680.19514 362.59619 680.19514 v S +362.60 680.20 m +361.12207 680.19514 359.48042 679.82661 v S +359.48 679.83 m +357.83878 679.49158 356.86720 678.92203 v S +356.87 678.92 m 356.63 678.92 l S +356.63 678.92 m 357.50 683.68 l S +357.50 683.68 m +360.45200 684.88554 363.73529 684.88554 v S +363.74 684.89 m +371.27344 684.88554 371.27344 677.54841 v S +371.27 677.55 m 371.27 672.32 l S +371.27 672.32 m +371.27344 670.91484 371.47445 669.67523 v S +371.47 669.68 m +371.70897 668.43563 372.07750 667.73207 v S +372.08 667.73 m 372.08 667.46 l S +372.08 667.46 m 366.65 667.46 l S +366.65 667.46 m +366.14749 668.60314 366.04699 669.97676 v S +366.05 669.98 m 365.81 669.98 l S +365.81 669.98 m +365.17591 668.70365 363.66828 667.93308 v S +363.67 667.93 m +362.16065 667.19602 360.21749 667.19602 v S +360.22 667.20 m 360.22 667.20 l S +360.65 672.66 m +360.65302 671.28337 362.29466 671.28337 v S +362.29 671.28 m +363.70178 671.28337 364.57286 672.08744 v S +364.57 672.09 m +365.44393 672.89151 365.44393 674.13112 v S +365.44 674.13 m 365.44 674.53 l S +365.44 674.53 m 362.73 674.30 l S +362.73 674.30 m +360.65302 674.09761 360.65302 672.65699 v S +360.65 672.66 m 360.65 672.66 l S +373.35 679.79 m 373.35 684.48 l S +373.35 684.48 m 376.23 684.48 l S +376.23 684.48 m 376.23 689.31 l S +376.23 689.31 m 382.26 689.31 l S +382.26 689.31 m 382.26 684.48 l S +382.26 684.48 m 386.45 684.48 l S +386.45 684.48 m 385.68 679.79 l S +385.68 679.79 m 382.26 679.79 l S +382.26 679.79 m 382.26 675.87 l S +382.26 675.87 m +382.26234 672.25496 385.44512 672.25496 v S +385.45 672.25 m 386.45 672.25 l S +386.45 672.25 m 385.68 667.36 l S +385.68 667.36 m 383.17 667.36 l S +383.17 667.36 m +379.91714 667.36353 378.07448 669.27320 v S +378.07 669.27 m +376.23182 671.18286 376.23182 674.60016 v S +376.23 674.60 m 376.23 679.79 l S +376.23 679.79 m 373.35 679.79 l S +397.04 667.06 m +393.15074 667.06201 390.93955 669.23970 v S +390.94 669.24 m +388.72836 671.45089 388.72836 675.40423 v S +388.73 675.40 m 388.73 684.48 l S +388.73 684.48 m 394.76 684.48 l S +394.76 684.48 m 394.76 675.27 l S +394.76 675.27 m +394.75888 673.76258 395.36193 672.95852 v S +395.36 672.96 m +395.96498 672.15445 397.03708 672.15445 v S +397.04 672.15 m +398.10916 672.15445 398.71222 672.95852 v S +398.71 672.96 m +399.31527 673.76258 399.31527 675.27021 v S +399.32 675.27 m 399.32 684.48 l S +399.32 684.48 m 405.35 684.48 l S +405.35 684.48 m 405.35 675.40 l S +405.35 675.40 m +405.34578 671.45089 403.13460 669.23970 v S +403.13 669.24 m +400.92340 667.06201 397.03708 667.06201 v S +397.04 667.06 m 397.04 667.06 l S +409.00 667.46 m 409.00 684.48 l S +409.00 684.48 m 414.43 684.48 l S +414.43 684.48 m 414.43 681.17 l S +414.43 681.17 m 414.66 681.17 l S +414.66 681.17 m +415.83215 684.88554 419.28295 684.88554 v S +419.28 684.89 m +420.28804 684.88554 420.92459 684.48351 v S +420.92 684.48 m 420.92 678.52 l S +420.92 678.52 m 420.69 678.52 l S +420.69 678.52 m +419.78549 678.88853 418.71340 678.88853 v S +418.71 678.89 m +416.93775 678.88853 415.96616 677.71592 v S +415.97 677.72 m +415.02809 676.54332 415.02809 674.56665 v S +415.03 674.57 m 415.03 667.46 l S +415.03 667.46 m 409.00 667.46 l S +431.34 667.06 m +427.15607 667.06201 424.71036 669.44071 v S +424.71 669.44 m +422.29816 671.81942 422.29816 675.97377 v S +422.30 675.97 m +422.29816 678.78802 423.43726 680.76469 v S +423.44 680.76 m +424.60986 682.77486 426.62003 683.81345 v S +426.62 683.81 m +428.66371 684.88554 431.24343 684.88554 v S +431.24 684.89 m +435.19677 684.88554 437.24044 682.54034 v S +437.24 682.54 m +439.31762 680.22864 439.31762 675.94027 v S +439.32 675.94 m 439.32 675.04 l S +439.32 675.04 m 428.40 673.96 l S +428.40 673.96 m +428.79772 672.75750 429.80280 672.25496 v S +429.80 672.25 m +430.84139 671.75241 432.34902 671.75241 v S +432.35 671.75 m +434.05767 671.75241 435.63230 672.15445 v S +435.63 672.15 m +437.24044 672.58998 438.04451 673.02552 v S +438.04 673.03 m 438.28 673.03 l S +438.28 673.03 m 437.41 668.27 l S +437.41 668.27 m +436.40287 667.83258 434.72772 667.46404 v S +434.73 667.46 m +433.05258 667.06201 431.34394 667.06201 v S +431.34 667.06 m 431.34 667.06 l S +431.14 680.46 m +430.03732 680.46316 429.23326 679.79310 v S +429.23 679.79 m +428.46269 679.12305 428.19466 677.51491 v S +428.19 677.51 m 433.82 678.05 l S +433.82 678.05 m +433.58863 679.32406 432.88507 679.89361 v S +432.89 679.89 m +432.18151 680.46316 431.14292 680.46316 v S +431.14 680.46 m 431.14 680.46 l S endstream endobj @@ -357,15 +906,17 @@ endobj << /ProcSet [/PDF /Text /ImageB /ImageC /ImageI] /Font << -/F0 5 0 R +/Fd08375f64eb9861c6eae4dfcfdbd3500fbdbe33e 5 0 R >> /XObject << >> +/ColorSpace << +>> >> endobj 6 0 obj << -/Producer (FPDF 1.7) +/Producer (�F�P�D�F� �1�.�7) /CreationDate (D:20000101000000) >> endobj @@ -378,13 +929,13 @@ endobj xref 0 8 0000000000 65535 f -0000013550 00000 n -0000013735 00000 n +0000030711 00000 n +0000030896 00000 n 0000000009 00000 n 0000000384 00000 n -0000013637 00000 n -0000013839 00000 n -0000013914 00000 n +0000030798 00000 n +0000031057 00000 n +0000031142 00000 n trailer << /Size 8 @@ -392,5 +943,5 @@ trailer /Info 6 0 R >> startxref -13963 +31191 %%EOF diff --git a/svgbasic.go b/svgbasic.go index cc35073..f75d69f 100644 --- a/svgbasic.go +++ b/svgbasic.go @@ -31,7 +31,11 @@ func init() { pathCmdSub = strings.NewReplacer(",", " ", "L", " L ", "l", " l ", "C", " C ", "c", " c ", - "M", " M ", "m", " m ") + "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 @@ -79,6 +83,29 @@ func absolutizePath(segs []SVGBasicSegmentType) { 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' } } } @@ -127,10 +154,16 @@ func pathParse(pathStr string) (segs []SVGBasicSegmentType, err error) { 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) - break + segs = append(segs, seg) default: err = fmt.Errorf("expecting SVG path command at position %d, got %s", j, str) } @@ -168,7 +201,8 @@ type SVGBasicType struct { // 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) and 'Z' (closepath). +// 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"` diff --git a/svgwrite.go b/svgwrite.go index 7e455fb..398a6da 100644 --- a/svgwrite.go +++ b/svgwrite.go @@ -29,8 +29,18 @@ func (f *Fpdf) SVGBasicWrite(sb *SVGBasicType, scale 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 originX + scale*seg.Arg[arg], originY + scale*seg.Arg[arg+1] + return xval(arg), yval(arg + 1) } for j := 0; j < len(sb.Segments) && f.Ok(); j++ { path = sb.Segments[j] @@ -39,6 +49,7 @@ func (f *Fpdf) SVGBasicWrite(sb *SVGBasicType, scale float64) { switch seg.Cmd { case 'M': x, y = val(0) + startX, startY = x, y f.SetXY(x, y) case 'L': newX, newY = val(0) @@ -50,8 +61,22 @@ func (f *Fpdf) SVGBasicWrite(sb *SVGBasicType, scale float64) { 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, originX, originY) + f.Line(x, y, startX, startY) + x, y = startX, startY default: f.SetErrorf("Unexpected path command '%c'", seg.Cmd) } diff --git a/template.go b/template.go index 31204c2..c0d3933 100644 --- a/template.go +++ b/template.go @@ -84,7 +84,18 @@ func (f *Fpdf) UseTemplateScaled(t Template, corner PointType, size SizeType) { for _, tt := range t.Templates() { f.templates[tt.ID()] = tt } + + // Create a list of existing image SHA-1 hashes. + existingImages := map[string]bool{} + for _, image := range f.images { + existingImages[image.i] = true + } + + // Add each template image to $f, unless already present. for name, ti := range t.Images() { + if _, found := existingImages[ti.i]; found { + continue + } name = sprintf("t%s-%s", t.ID(), name) f.images[name] = ti } diff --git a/template_impl.go b/template_impl.go index c5d7be8..c1e2dff 100644 --- a/template_impl.go +++ b/template_impl.go @@ -296,4 +296,8 @@ func (t *Tpl) loadParamsFromFpdf(f *Fpdf) { t.Fpdf.fontSizePt = f.fontSizePt t.Fpdf.fontStyle = f.fontStyle t.Fpdf.ws = f.ws + + for key, value := range f.images { + t.Fpdf.images[key] = value + } } diff --git a/utf8fontfile.go b/utf8fontfile.go index 964e919..4d90f28 100644 --- a/utf8fontfile.go +++ b/utf8fontfile.go @@ -377,7 +377,7 @@ func (utf *utf8FontFile) parseHHEATable() int { } func (utf *utf8FontFile) parseOS2Table() int { - weightType := 0 + var weightType int scale := 1000.0 / float64(utf.fontElementSize) if _, OK := utf.tableDescriptions["OS/2"]; OK { utf.SeekTable("OS/2") @@ -831,9 +831,9 @@ func (utf *utf8FontFile) getSymbols(originalSymbolIdx int, start *int, symbolSet } func (utf *utf8FontFile) parseHMTXTable(numberOfHMetrics, numSymbols int, symbolToChar map[int][]int, scale float64) { + var widths int start := utf.SeekTable("hmtx") arrayWidths := 0 - widths := 0 var arr []int utf.CharWidths = make([]int, 256*256) charCount := 0 @@ -863,8 +863,6 @@ func (utf *utf8FontFile) parseHMTXTable(numberOfHMetrics, numSymbols int, symbol } } } - data := utf.getRange(start+numberOfHMetrics*4, numSymbols*2) - arr = unpackUint16Array(data) diff := numSymbols - numberOfHMetrics for pos := 0; pos < diff; pos++ { symbol := pos + numberOfHMetrics @@ -949,7 +947,7 @@ func (utf *utf8FontFile) generateSCCSDictionaries(runeCmapPosition int, symbolCh for i := 0; i < segmentSize; i++ { positions = append(positions, utf.readUint16()) } - symbol := 0 + var symbol int for n := 0; n < segmentSize; n++ { completePosition := completers[n] + 1 for char := beginners[n]; char < completePosition; char++ { @@ -1140,3 +1138,16 @@ func keySortArrayRangeMap(s map[int][]int) []int { sort.Ints(keys) return keys } + +// UTF8CutFont is a utility function that generates a TrueType font composed +// only of the runes included in cutset. The rune glyphs are copied from This +// function is demonstrated in ExampleUTF8CutFont(). +func UTF8CutFont(inBuf []byte, cutset string) (outBuf []byte) { + f := newUTF8Font(&fileReader{readerPosition: 0, array: inBuf}) + runes := map[int]int{} + for i, r := range cutset { + runes[i] = int(r) + } + outBuf = f.GenerateСutFont(runes) + return +} diff --git a/util.go b/util.go index e96cdd8..351d319 100644 --- a/util.go +++ b/util.go @@ -344,7 +344,7 @@ func (pa *untypedKeyMap) getIndex(key interface{}) int { //Put key=>value in PHP Array func (pa *untypedKeyMap) put(key interface{}, value int) { if key == nil { - i := 0 + var i int for n := 0; ; n++ { i = pa.getIndex(n) if i < 0 { @@ -419,14 +419,8 @@ func arrayMerge(arr1, arr2 *untypedKeyMap) *untypedKeyMap { answer.valueSet = arr1.valueSet[:] for i := 0; i < len(arr2.keySet); i++ { if arr2.keySet[i] == "interval" { - u := 0 - u = u + 1 if arr1.getIndex("interval") < 0 { answer.put("interval", arr2.valueSet[i]) - } else { - - u := 0 - u = u + 1 } } else { answer.put(nil, arr2.valueSet[i]) @@ -450,3 +444,19 @@ func remove(arr []int, key int) []int { } 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 +} + +// Condition font family string to PDF name compliance. See section 5.3 (Names) +// in https://resources.infosecinstitute.com/pdf-file-format-basic-structure/ +func fontFamilyEscape(familyStr string) (escStr string) { + escStr = strings.Replace(familyStr, " ", "#20", -1) + // Additional replacements can take place here + return +} -- cgit v1.2.1-24-ge1ad From 40ff7316bd16354f5eee3d0fc1e55c8ac727c741 Mon Sep 17 00:00:00 2001 From: DarkFreedman Date: Fri, 4 Oct 2019 12:20:01 +0300 Subject: Unchangeable font byte array --- fpdf.go | 2 +- utf8fontfile.go | 23 +++++++++++++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/fpdf.go b/fpdf.go index f5062cc..5486842 100644 --- a/fpdf.go +++ b/fpdf.go @@ -4033,7 +4033,7 @@ func (f *Fpdf) putfonts() { fontName := "utf8" + font.Name usedRunes := font.usedRunes delete(usedRunes, 0) - utf8FontStream := font.utf8File.GenerateСutFont(usedRunes) + utf8FontStream := font.utf8File.GenerateCutFont(usedRunes) utf8FontSize := len(utf8FontStream) compressedFontStream := sliceCompress(utf8FontStream) CodeSignDictionary := font.utf8File.CodeSymbolDictionary diff --git a/utf8fontfile.go b/utf8fontfile.go index 4d90f28..85b3ce4 100644 --- a/utf8fontfile.go +++ b/utf8fontfile.go @@ -75,6 +75,13 @@ func (fr *fileReader) Read(s int) []byte { return b } +func (fr *fileReader) ReadLikeCopy(s int) []byte { + b := make([]byte, 0, s) + b = append(b, fr.array[fr.readerPosition:fr.readerPosition+int64(s)]...) + fr.readerPosition += int64(s) + return b +} + func (fr *fileReader) seek(shift int64, flag int) (int64, error) { if flag == 0 { fr.readerPosition = shift @@ -225,7 +232,7 @@ func (utf *utf8FontFile) insertUint16(stream []byte, offset int, value int) []by } func (utf *utf8FontFile) getRange(pos, length int) []byte { - utf.fileReader.seek(int64(pos), 0) + _, _ = utf.fileReader.seek(int64(pos), 0) if length < 1 { return make([]byte, 0) } @@ -241,8 +248,8 @@ func (utf *utf8FontFile) getTableData(name string) []byte { if desckrip.size == 0 { return nil } - utf.fileReader.seek(int64(desckrip.position), 0) - s := utf.fileReader.Read(desckrip.size) + _, _ = utf.fileReader.seek(int64(desckrip.position), 0) + s := utf.fileReader.ReadLikeCopy(desckrip.size) return s } @@ -634,8 +641,8 @@ func (utf *utf8FontFile) generateCMAPTable(cidSymbolPairCollection map[int]int, return cmapstr } -//GenerateСutFont fill utf8FontFile from .utf file, only with runes from usedRunes -func (utf *utf8FontFile) GenerateСutFont(usedRunes map[int]int) []byte { +//GenerateCutFont fill utf8FontFile from .utf file, only with runes from usedRunes +func (utf *utf8FontFile) GenerateCutFont(usedRunes map[int]int) []byte { utf.fileReader.readerPosition = 0 utf.symbolPosition = make([]int, 0) utf.charSymbolDictionary = make(map[int]int) @@ -889,10 +896,10 @@ func (utf *utf8FontFile) getMetrics(metricCount, gid int) []byte { var metrics []byte if gid < metricCount { utf.seek(start + (gid * 4)) - metrics = utf.fileReader.Read(4) + metrics = utf.fileReader.ReadLikeCopy(4) } else { utf.seek(start + ((metricCount - 1) * 4)) - metrics = utf.fileReader.Read(2) + metrics = utf.fileReader.ReadLikeCopy(2) utf.seek(start + (metricCount * 2) + (gid * 2)) metrics = append(metrics, utf.fileReader.Read(2)...) } @@ -1148,6 +1155,6 @@ func UTF8CutFont(inBuf []byte, cutset string) (outBuf []byte) { for i, r := range cutset { runes[i] = int(r) } - outBuf = f.GenerateСutFont(runes) + outBuf = f.GenerateCutFont(runes) return } -- cgit v1.2.1-24-ge1ad From 2e803db13067e702208818c79d70bd0ad1b13370 Mon Sep 17 00:00:00 2001 From: DarkFreedman Date: Fri, 4 Oct 2019 13:24:05 +0300 Subject: Pre Merge --- fpdf.go | 2 +- utf8fontfile.go | 23 ++++++++--------------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/fpdf.go b/fpdf.go index 5486842..f5062cc 100644 --- a/fpdf.go +++ b/fpdf.go @@ -4033,7 +4033,7 @@ func (f *Fpdf) putfonts() { fontName := "utf8" + font.Name usedRunes := font.usedRunes delete(usedRunes, 0) - utf8FontStream := font.utf8File.GenerateCutFont(usedRunes) + utf8FontStream := font.utf8File.GenerateСutFont(usedRunes) utf8FontSize := len(utf8FontStream) compressedFontStream := sliceCompress(utf8FontStream) CodeSignDictionary := font.utf8File.CodeSymbolDictionary diff --git a/utf8fontfile.go b/utf8fontfile.go index 85b3ce4..4d90f28 100644 --- a/utf8fontfile.go +++ b/utf8fontfile.go @@ -75,13 +75,6 @@ func (fr *fileReader) Read(s int) []byte { return b } -func (fr *fileReader) ReadLikeCopy(s int) []byte { - b := make([]byte, 0, s) - b = append(b, fr.array[fr.readerPosition:fr.readerPosition+int64(s)]...) - fr.readerPosition += int64(s) - return b -} - func (fr *fileReader) seek(shift int64, flag int) (int64, error) { if flag == 0 { fr.readerPosition = shift @@ -232,7 +225,7 @@ func (utf *utf8FontFile) insertUint16(stream []byte, offset int, value int) []by } func (utf *utf8FontFile) getRange(pos, length int) []byte { - _, _ = utf.fileReader.seek(int64(pos), 0) + utf.fileReader.seek(int64(pos), 0) if length < 1 { return make([]byte, 0) } @@ -248,8 +241,8 @@ func (utf *utf8FontFile) getTableData(name string) []byte { if desckrip.size == 0 { return nil } - _, _ = utf.fileReader.seek(int64(desckrip.position), 0) - s := utf.fileReader.ReadLikeCopy(desckrip.size) + utf.fileReader.seek(int64(desckrip.position), 0) + s := utf.fileReader.Read(desckrip.size) return s } @@ -641,8 +634,8 @@ func (utf *utf8FontFile) generateCMAPTable(cidSymbolPairCollection map[int]int, return cmapstr } -//GenerateCutFont fill utf8FontFile from .utf file, only with runes from usedRunes -func (utf *utf8FontFile) GenerateCutFont(usedRunes map[int]int) []byte { +//GenerateСutFont fill utf8FontFile from .utf file, only with runes from usedRunes +func (utf *utf8FontFile) GenerateСutFont(usedRunes map[int]int) []byte { utf.fileReader.readerPosition = 0 utf.symbolPosition = make([]int, 0) utf.charSymbolDictionary = make(map[int]int) @@ -896,10 +889,10 @@ func (utf *utf8FontFile) getMetrics(metricCount, gid int) []byte { var metrics []byte if gid < metricCount { utf.seek(start + (gid * 4)) - metrics = utf.fileReader.ReadLikeCopy(4) + metrics = utf.fileReader.Read(4) } else { utf.seek(start + ((metricCount - 1) * 4)) - metrics = utf.fileReader.ReadLikeCopy(2) + metrics = utf.fileReader.Read(2) utf.seek(start + (metricCount * 2) + (gid * 2)) metrics = append(metrics, utf.fileReader.Read(2)...) } @@ -1155,6 +1148,6 @@ func UTF8CutFont(inBuf []byte, cutset string) (outBuf []byte) { for i, r := range cutset { runes[i] = int(r) } - outBuf = f.GenerateCutFont(runes) + outBuf = f.GenerateСutFont(runes) return } -- cgit v1.2.1-24-ge1ad From e318fd80c1330e11155bfaa5ff5cfb809454b021 Mon Sep 17 00:00:00 2001 From: DarkFreedman Date: Fri, 4 Oct 2019 13:27:57 +0300 Subject: Fix Unedit font array --- fpdf.go | 2 +- utf8fontfile.go | 23 +++++++++++++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/fpdf.go b/fpdf.go index f5062cc..5486842 100644 --- a/fpdf.go +++ b/fpdf.go @@ -4033,7 +4033,7 @@ func (f *Fpdf) putfonts() { fontName := "utf8" + font.Name usedRunes := font.usedRunes delete(usedRunes, 0) - utf8FontStream := font.utf8File.GenerateСutFont(usedRunes) + utf8FontStream := font.utf8File.GenerateCutFont(usedRunes) utf8FontSize := len(utf8FontStream) compressedFontStream := sliceCompress(utf8FontStream) CodeSignDictionary := font.utf8File.CodeSymbolDictionary diff --git a/utf8fontfile.go b/utf8fontfile.go index 4d90f28..85b3ce4 100644 --- a/utf8fontfile.go +++ b/utf8fontfile.go @@ -75,6 +75,13 @@ func (fr *fileReader) Read(s int) []byte { return b } +func (fr *fileReader) ReadLikeCopy(s int) []byte { + b := make([]byte, 0, s) + b = append(b, fr.array[fr.readerPosition:fr.readerPosition+int64(s)]...) + fr.readerPosition += int64(s) + return b +} + func (fr *fileReader) seek(shift int64, flag int) (int64, error) { if flag == 0 { fr.readerPosition = shift @@ -225,7 +232,7 @@ func (utf *utf8FontFile) insertUint16(stream []byte, offset int, value int) []by } func (utf *utf8FontFile) getRange(pos, length int) []byte { - utf.fileReader.seek(int64(pos), 0) + _, _ = utf.fileReader.seek(int64(pos), 0) if length < 1 { return make([]byte, 0) } @@ -241,8 +248,8 @@ func (utf *utf8FontFile) getTableData(name string) []byte { if desckrip.size == 0 { return nil } - utf.fileReader.seek(int64(desckrip.position), 0) - s := utf.fileReader.Read(desckrip.size) + _, _ = utf.fileReader.seek(int64(desckrip.position), 0) + s := utf.fileReader.ReadLikeCopy(desckrip.size) return s } @@ -634,8 +641,8 @@ func (utf *utf8FontFile) generateCMAPTable(cidSymbolPairCollection map[int]int, return cmapstr } -//GenerateСutFont fill utf8FontFile from .utf file, only with runes from usedRunes -func (utf *utf8FontFile) GenerateСutFont(usedRunes map[int]int) []byte { +//GenerateCutFont fill utf8FontFile from .utf file, only with runes from usedRunes +func (utf *utf8FontFile) GenerateCutFont(usedRunes map[int]int) []byte { utf.fileReader.readerPosition = 0 utf.symbolPosition = make([]int, 0) utf.charSymbolDictionary = make(map[int]int) @@ -889,10 +896,10 @@ func (utf *utf8FontFile) getMetrics(metricCount, gid int) []byte { var metrics []byte if gid < metricCount { utf.seek(start + (gid * 4)) - metrics = utf.fileReader.Read(4) + metrics = utf.fileReader.ReadLikeCopy(4) } else { utf.seek(start + ((metricCount - 1) * 4)) - metrics = utf.fileReader.Read(2) + metrics = utf.fileReader.ReadLikeCopy(2) utf.seek(start + (metricCount * 2) + (gid * 2)) metrics = append(metrics, utf.fileReader.Read(2)...) } @@ -1148,6 +1155,6 @@ func UTF8CutFont(inBuf []byte, cutset string) (outBuf []byte) { for i, r := range cutset { runes[i] = int(r) } - outBuf = f.GenerateСutFont(runes) + outBuf = f.GenerateCutFont(runes) return } -- cgit v1.2.1-24-ge1ad