commit 5afea81825528668c66deae694ef5790b19befe9 Author: Barpfotenbaer Date: Tue Mar 2 13:27:45 2021 +0100 Kurt Jungs Auslieferungszustand diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..946bb79 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Kurt Jung and contributors acknowledged in the documentation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..90624c5 --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +all : documentation + +documentation : doc/index.html doc.go README.md + +cov : all + go test -v -coverprofile=coverage && go tool cover -html=coverage -o=coverage.html + +check : + golint . + go vet -all . + gofmt -s -l . + goreportcard-cli -v | grep -v cyclomatic + +README.md : doc/document.md + pandoc --read=markdown --write=gfm < $< > $@ + +doc/index.html : doc/document.md doc/html.txt + pandoc --read=markdown --write=html --template=doc/html.txt \ + --metadata pagetitle="GoFPDF Document Generator" < $< > $@ + +doc.go : doc/document.md doc/go.awk + pandoc --read=markdown --write=plain $< | awk --assign=package_name=gofpdf --file=doc/go.awk > $@ + gofmt -s -w $@ + +build : + go build -v + +clean : + rm -f coverage.html coverage doc/index.html doc.go README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..e1725da --- /dev/null +++ b/README.md @@ -0,0 +1,282 @@ +# GoFPDF document generator + +[![No Maintenance +Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/) +[![MIT +licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/jung-kurt/gofpdf/master/LICENSE) +[![Report](https://goreportcard.com/badge/github.com/jung-kurt/gofpdf)](https://goreportcard.com/report/github.com/jung-kurt/gofpdf) +[![GoDoc](https://img.shields.io/badge/godoc-GoFPDF-blue.svg)](https://godoc.org/github.com/jung-kurt/gofpdf) + +![](https://github.com/jung-kurt/gofpdf/raw/master/image/logo_gofpdf.jpg?raw=true) + +Package gofpdf implements a PDF document generator with high level +support for text, drawing and images. + +## Features + + - UTF-8 support + - Choice of measurement unit, page format and margins + - Page header and footer management + - Automatic page breaks, line breaks, and text justification + - Inclusion of JPEG, PNG, GIF, TIFF and basic path-only SVG images + - Colors, gradients and alpha channel transparency + - Outline bookmarks + - Internal and external links + - TrueType, Type1 and encoding support + - Page compression + - Lines, Bézier curves, arcs, and ellipses + - Rotation, scaling, skewing, translation, and mirroring + - Clipping + - Document protection + - Layers + - Templates + - Barcodes + - Charting facility + - Import PDFs as templates + +gofpdf has no dependencies other than the Go standard library. All tests +pass on Linux, Mac and Windows platforms. + +gofpdf supports UTF-8 TrueType fonts and “right-to-left” languages. Note +that Chinese, Japanese, and Korean characters may not be included in +many general purpose fonts. For these languages, a specialized font (for +example, +[NotoSansSC](https://github.com/jsntn/webfonts/blob/master/NotoSansSC-Regular.ttf) +for simplified Chinese) can be used. + +Also, support is provided to automatically translate UTF-8 runes to code +page encodings for languages that have fewer than 256 glyphs. + +## We Are Closed + +This repository will not be maintained, at least for some unknown +duration. But it is hoped that gofpdf has a bright future in the open +source world. Due to Go’s promise of compatibility, gofpdf should +continue to function without modification for a longer time than would +be the case with many other languages. + +Forks should be based on the [last viable +commit](https://github.com/jung-kurt/gofpdf/commit/603f56990463f011cb1dbb64ef7f872c1adc009a). +Tools such as +[active-forks](https://techgaun.github.io/active-forks/index.html#jung-kurt/gofpdf) +can be used to select a fork that looks promising for your needs. If a +particular fork looks like it has taken the lead in attracting +followers, this README will be updated to point people in that +direction. + +The efforts of all contributors to this project have been deeply +appreciated. Best wishes to all of you. + +## Installation + +To install the package on your system, run + +``` shell +go get github.com/jung-kurt/gofpdf +``` + +Later, to receive updates, run + +``` shell +go get -u -v github.com/jung-kurt/gofpdf/... +``` + +## Quick Start + +The following Go code generates a simple PDF file. + +``` go +pdf := gofpdf.New("P", "mm", "A4", "") +pdf.AddPage() +pdf.SetFont("Arial", "B", 16) +pdf.Cell(40, 10, "Hello, world") +err := pdf.OutputFileAndClose("hello.pdf") +``` + +See the functions in the +[fpdf\_test.go](https://github.com/jung-kurt/gofpdf/blob/master/fpdf_test.go) +file (shown as examples in this documentation) for more advanced PDF +examples. + +## Errors + +If an error occurs in an Fpdf method, an internal error field is set. +After this occurs, Fpdf method calls typically return without performing +any operations and the error state is retained. This error management +scheme facilitates PDF generation since individual method calls do not +need to be examined for failure; it is generally sufficient to wait +until after `Output()` is called. For the same reason, if an error +occurs in the calling application during PDF generation, it may be +desirable for the application to transfer the error to the Fpdf instance +by calling the `SetError()` method or the `SetErrorf()` method. At any +time during the life cycle of the Fpdf instance, the error state can be +determined with a call to `Ok()` or `Err()`. The error itself can be +retrieved with a call to `Error()`. + +## Conversion Notes + +This package is a relatively straightforward translation from the +original [FPDF](http://www.fpdf.org/) library written in PHP (despite +the caveat in the introduction to [Effective +Go](https://golang.org/doc/effective_go.html)). The API names have been +retained even though the Go idiom would suggest otherwise (for example, +`pdf.GetX()` is used rather than simply `pdf.X()`). The similarity of +the two libraries makes the original FPDF website a good source of +information. It includes a forum and FAQ. + +However, some internal changes have been made. Page content is built up +using buffers (of type bytes.Buffer) rather than repeated string +concatenation. Errors are handled as explained above rather than +panicking. Output is generated through an interface of type io.Writer or +io.WriteCloser. A number of the original PHP methods behave differently +based on the type of the arguments that are passed to them; in these +cases additional methods have been exported to provide similar +functionality. Font definition files are produced in JSON rather than +PHP. + +## Example PDFs + +A side effect of running `go test ./...` is the production of a number +of example PDFs. These can be found in the gofpdf/pdf directory after +the tests complete. + +Please note that these examples run in the context of a test. In order +run an example as a standalone application, 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()`. + +You should use `AddUTF8Font()` or `AddUTF8FontFromBytes()` to add a +TrueType UTF-8 encoded font. Use `RTL()` and `LTR()` methods switch +between “right-to-left” and “left-to-right” mode. + +In order to use a different non-UTF-8 TrueType or Type1 font, you will +need to generate a font definition file and, if the font will be +embedded into PDFs, a compressed version of the font file. This is done +by calling the MakeFont function or using the included makefont command +line utility. To create the utility, cd into the makefont subdirectory +and run “go build”. This will produce a standalone executable named +makefont. Select the appropriate encoding file from the font +subdirectory and run the command as in the following example. + +``` shell +./makefont --embed --enc=../font/cp1252.map --dst=../font ../font/calligra.ttf +``` + +In your PDF generation code, call `AddFont()` to load the font and, as +with the standard fonts, SetFont() to begin using it. Most examples, +including the package example, demonstrate this method. Good sources of +free, open-source fonts include [Google +Fonts](https://fonts.google.com/) and [DejaVu +Fonts](http://dejavu-fonts.org/). + +## Related Packages + +The [draw2d](https://github.com/llgcode/draw2d) package is a two +dimensional vector graphics library that can generate output in +different forms. It uses gofpdf for its document production mode. + +## Contributing Changes + +gofpdf is a global community effort and you are invited to make it even +better. If you have implemented a new feature or corrected a problem, +please consider contributing your change to the project. A contribution +that does not directly pertain to the core functionality of gofpdf +should be placed in its own directory directly beneath the `contrib` +directory. + +Here are guidelines for making submissions. Your change should + + - be compatible with the MIT License + - be properly documented + - be formatted with `go fmt` + - include an example in + [fpdf\_test.go](https://github.com/jung-kurt/gofpdf/blob/master/fpdf_test.go) + if appropriate + - conform to the standards of [golint](https://github.com/golang/lint) + and [go vet](https://golang.org/cmd/vet/), that is, `golint .` and + `go vet .` should not generate any warnings + - not diminish [test coverage](https://blog.golang.org/cover) + +[Pull requests](https://help.github.com/articles/using-pull-requests/) +are the preferred means of accepting your changes. + +## License + +gofpdf is released under the MIT License. It is copyrighted by Kurt Jung +and the contributors acknowledged below. + +## Acknowledgments + +This 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. 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. Benoit KUGLER contributed +support for rectangles with corners of unequal radius, modification +times, and for file attachments and annotations. + +## Roadmap + + - Remove all legacy code page font support; use UTF-8 exclusively + - Improve test coverage as reported by the coverage tool. diff --git a/attachments.go b/attachments.go new file mode 100644 index 0000000..6e397b7 --- /dev/null +++ b/attachments.go @@ -0,0 +1,157 @@ +package gofpdf + +import ( + "crypto/md5" + "encoding/hex" + "fmt" + "strings" +) + +// Attachment defines a content to be included in the pdf, in one +// of the following ways : +// - associated with the document as a whole : see SetAttachments() +// - accessible via a link localized on a page : see AddAttachmentAnnotation() +type Attachment struct { + Content []byte + + // Filename is the displayed name of the attachment + Filename string + + // Description is only displayed when using AddAttachmentAnnotation(), + // and might be modified by the pdf reader. + Description string + + objectNumber int // filled when content is included +} + +// return the hex encoded checksum of `data` +func checksum(data []byte) string { + tmp := md5.Sum(data) + sl := make([]byte, len(tmp)) + for i, v := range tmp { + sl[i] = v + } + return hex.EncodeToString(sl) +} + +// Writes a compressed file like object as ``/EmbeddedFile``. Compressing is +// done with deflate. Includes length, compressed length and MD5 checksum. +func (f *Fpdf) writeCompressedFileObject(content []byte) { + lenUncompressed := len(content) + sum := checksum(content) + compressed := sliceCompress(content) + lenCompressed := len(compressed) + f.newobj() + f.outf("<< /Type /EmbeddedFile /Length %d /Filter /FlateDecode /Params << /CheckSum <%s> /Size %d >> >>\n", + lenCompressed, sum, lenUncompressed) + f.putstream(compressed) + f.out("endobj") +} + +// Embed includes the content of `a`, and update its internal reference. +func (f *Fpdf) embed(a *Attachment) { + if a.objectNumber != 0 { // already embedded (objectNumber start at 2) + return + } + oldState := f.state + f.state = 1 // we write file content in the main buffer + f.writeCompressedFileObject(a.Content) + streamID := f.n + f.newobj() + f.outf("<< /Type /Filespec /F () /UF %s /EF << /F %d 0 R >> /Desc %s\n>>", + f.textstring(utf8toutf16(a.Filename)), + streamID, + f.textstring(utf8toutf16(a.Description))) + f.out("endobj") + a.objectNumber = f.n + f.state = oldState +} + +// SetAttachments writes attachments as embedded files (document attachment). +// These attachments are global, see AddAttachmentAnnotation() for a link +// anchored in a page. Note that only the last call of SetAttachments is +// useful, previous calls are discarded. Be aware that not all PDF readers +// support document attachments. See the SetAttachment example for a +// demonstration of this method. +func (f *Fpdf) SetAttachments(as []Attachment) { + f.attachments = as +} + +// embed current attachments. store object numbers +// for later use by getEmbeddedFiles() +func (f *Fpdf) putAttachments() { + for i, a := range f.attachments { + f.embed(&a) + f.attachments[i] = a + } +} + +// return /EmbeddedFiles tree name catalog entry. +func (f Fpdf) getEmbeddedFiles() string { + names := make([]string, len(f.attachments)) + for i, as := range f.attachments { + names[i] = fmt.Sprintf("(Attachement%d) %d 0 R ", i+1, as.objectNumber) + } + nameTree := fmt.Sprintf("<< /Names [\n %s \n] >>", strings.Join(names, "\n")) + return nameTree +} + +// ---------------------------------- Annotations ---------------------------------- + +type annotationAttach struct { + *Attachment + + x, y, w, h float64 // fpdf coordinates (y diff and scaling done) +} + +// AddAttachmentAnnotation puts a link on the current page, on the rectangle +// defined by `x`, `y`, `w`, `h`. This link points towards the content defined +// in `a`, which is embedded in the document. Note than no drawing is done by +// this method : a method like `Cell()` or `Rect()` should be called to +// indicate to the reader that there is a link here. Requiring a pointer to an +// Attachment avoids useless copies in the resulting pdf: attachment pointing +// to the same data will have their content only be included once, and be +// shared amongst all links. Be aware that not all PDF readers support +// annotated attachments. See the AddAttachmentAnnotation example for a +// demonstration of this method. +func (f *Fpdf) AddAttachmentAnnotation(a *Attachment, x, y, w, h float64) { + if a == nil { + return + } + f.pageAttachments[f.page] = append(f.pageAttachments[f.page], annotationAttach{ + Attachment: a, + x: x * f.k, y: f.hPt - y*f.k, w: w * f.k, h: h * f.k, + }) +} + +// embed current annotations attachments. store object numbers +// for later use by putAttachmentAnnotationLinks(), which is +// called for each page. +func (f *Fpdf) putAnnotationsAttachments() { + // avoid duplication + m := map[*Attachment]bool{} + for _, l := range f.pageAttachments { + for _, an := range l { + if m[an.Attachment] { // already embedded + continue + } + f.embed(an.Attachment) + } + } +} + +func (f *Fpdf) putAttachmentAnnotationLinks(out *fmtBuffer, page int) { + for _, an := range f.pageAttachments[page] { + x1, y1, x2, y2 := an.x, an.y, an.x+an.w, an.y-an.h + as := fmt.Sprintf("<< /Type /XObject /Subtype /Form /BBox [%.2f %.2f %.2f %.2f] /Length 0 >>", + x1, y1, x2, y2) + as += "\nstream\nendstream" + + out.printf("<< /Type /Annot /Subtype /FileAttachment /Rect [%.2f %.2f %.2f %.2f] /Border [0 0 0]\n", + x1, y1, x2, y2) + out.printf("/Contents %s ", f.textstring(utf8toutf16(an.Description))) + out.printf("/T %s ", f.textstring(utf8toutf16(an.Filename))) + out.printf("/AP << /N %s>>", as) + out.printf("/FS %d 0 R >>\n", an.objectNumber) + } +} diff --git a/compare.go b/compare.go new file mode 100644 index 0000000..f0c286e --- /dev/null +++ b/compare.go @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2015 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "sort" +) + +type sortType struct { + length int + less func(int, int) bool + swap func(int, int) +} + +func (s *sortType) Len() int { + return s.length +} + +func (s *sortType) Less(i, j int) bool { + return s.less(i, j) +} + +func (s *sortType) Swap(i, j int) { + s.swap(i, j) +} + +func gensort(Len int, Less func(int, int) bool, Swap func(int, int)) { + sort.Sort(&sortType{length: Len, less: Less, swap: Swap}) +} + +func writeBytes(leadStr string, startPos int, sl []byte) { + var pos, max int + var b byte + fmt.Printf("%s %07x", leadStr, startPos) + max = len(sl) + for pos < max { + fmt.Printf(" ") + for k := 0; k < 8; k++ { + if pos < max { + fmt.Printf(" %02x", sl[pos]) + } else { + fmt.Printf(" ") + } + pos++ + } + } + fmt.Printf(" |") + pos = 0 + for pos < max { + b = sl[pos] + if b < 32 || b >= 128 { + b = '.' + } + fmt.Printf("%c", b) + pos++ + } + fmt.Printf("|\n") +} + +func checkBytes(pos int, sl1, sl2 []byte, printDiff bool) (eq bool) { + eq = bytes.Equal(sl1, sl2) + if !eq && printDiff { + writeBytes("<", pos, sl1) + writeBytes(">", pos, sl2) + } + return +} + +// CompareBytes compares the bytes referred to by sl1 with those referred to by +// sl2. Nil is returned if the buffers are equal, otherwise an error. +func CompareBytes(sl1, sl2 []byte, printDiff bool) (err error) { + var posStart, posEnd, len1, len2, length int + var diffs bool + + len1 = len(sl1) + len2 = len(sl2) + length = len1 + if length > len2 { + length = len2 + } + for posStart < length-1 { + posEnd = posStart + 16 + if posEnd > length { + posEnd = length + } + if !checkBytes(posStart, sl1[posStart:posEnd], sl2[posStart:posEnd], printDiff) { + diffs = true + } + posStart = posEnd + } + if diffs { + err = fmt.Errorf("documents are different") + } + return +} + +// ComparePDFs reads and compares the full contents of the two specified +// readers byte-for-byte. Nil is returned if the buffers are equal, otherwise +// an error. +func ComparePDFs(rdr1, rdr2 io.Reader, printDiff bool) (err error) { + var b1, b2 *bytes.Buffer + _, err = b1.ReadFrom(rdr1) + if err == nil { + _, err = b2.ReadFrom(rdr2) + if err == nil { + err = CompareBytes(b1.Bytes(), b2.Bytes(), printDiff) + } + } + return +} + +// ComparePDFFiles reads and compares the full contents of the two specified +// files byte-for-byte. Nil is returned if the file contents are equal, or if +// the second file is missing, otherwise an error. +func ComparePDFFiles(file1Str, file2Str string, printDiff bool) (err error) { + var sl1, sl2 []byte + sl1, err = ioutil.ReadFile(file1Str) + if err == nil { + sl2, err = ioutil.ReadFile(file2Str) + if err == nil { + err = CompareBytes(sl1, sl2, printDiff) + } else { + // Second file is missing; treat this as success + err = nil + } + } + return +} diff --git a/contrib/barcode/barcode.go b/contrib/barcode/barcode.go new file mode 100644 index 0000000..7e0ac0d --- /dev/null +++ b/contrib/barcode/barcode.go @@ -0,0 +1,302 @@ +// Copyright (c) 2015 Jelmer Snoeck (Gmail: jelmer.snoeck) +// +// 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 barcode provides helper methods for adding barcodes of different +// types to your pdf document. It relies on the github.com/boombuler/barcode +// package for the barcode creation. +package barcode + +import ( + "bytes" + "errors" + "image/jpeg" + "io" + "strconv" + "sync" + + "github.com/boombuler/barcode" + "github.com/boombuler/barcode/aztec" + "github.com/boombuler/barcode/codabar" + "github.com/boombuler/barcode/code128" + "github.com/boombuler/barcode/code39" + "github.com/boombuler/barcode/datamatrix" + "github.com/boombuler/barcode/ean" + "github.com/boombuler/barcode/qr" + "github.com/boombuler/barcode/twooffive" + "github.com/jung-kurt/gofpdf" + "github.com/ruudk/golang-pdf417" +) + +// barcodes represents the barcodes that have been registered through this +// package. They will later be used to be scaled and put on the page. +// RubenN: made this a struct with a mutex to prevent race condition +var barcodes struct { + sync.Mutex + cache map[string]barcode.Barcode +} + +// barcodePdf is a partial PDF implementation that only implements a subset of +// functions that are required to add the barcode to the PDF. +type barcodePdf interface { + GetConversionRatio() float64 + GetImageInfo(imageStr string) *gofpdf.ImageInfoType + Image(imageNameStr string, x, y, w, h float64, flow bool, tp string, link int, linkStr string) + RegisterImageReader(imgName, tp string, r io.Reader) *gofpdf.ImageInfoType + SetError(err error) +} + +// printBarcode internally prints the scaled or unscaled barcode to the PDF. Used by both +// Barcode() and BarcodeUnscalable(). +func printBarcode(pdf barcodePdf, code string, x, y float64, w, h *float64, flow bool) { + barcodes.Lock() + unscaled, ok := barcodes.cache[code] + barcodes.Unlock() + + if !ok { + err := errors.New("Barcode not found") + pdf.SetError(err) + return + } + + bname := uniqueBarcodeName(code, x, y) + info := pdf.GetImageInfo(bname) + scaleToWidth := unscaled.Bounds().Dx() + scaleToHeight := unscaled.Bounds().Dy() + + if info == nil { + bcode, err := barcode.Scale( + unscaled, + scaleToWidth, + scaleToHeight, + ) + + if err != nil { + pdf.SetError(err) + return + } + + err = registerScaledBarcode(pdf, bname, bcode) + if err != nil { + pdf.SetError(err) + return + } + } + + scaleToWidthF := float64(scaleToWidth) + scaleToHeightF := float64(scaleToHeight) + + if w != nil { + scaleToWidthF = *w + } + if h != nil { + scaleToHeightF = *h + } + + pdf.Image(bname, x, y, scaleToWidthF, scaleToHeightF, flow, "jpg", 0, "") + +} + +// BarcodeUnscalable puts a registered barcode in the current page. +// +// Its arguments work in the same way as that of Barcode(). However, it allows for an unscaled +// barcode in the width and/or height dimensions. This can be useful if you want to prevent +// side effects of upscaling. +func BarcodeUnscalable(pdf barcodePdf, code string, x, y float64, w, h *float64, flow bool) { + printBarcode(pdf, code, x, y, w, h, flow) +} + +// Barcode puts a registered barcode in the current page. +// +// The size should be specified in the units used to create the PDF document. +// If width or height are left unspecfied, the barcode is not scaled in the unspecified dimensions. +// +// Positioning with x, y and flow is inherited from Fpdf.Image(). +func Barcode(pdf barcodePdf, code string, x, y, w, h float64, flow bool) { + printBarcode(pdf, code, x, y, &w, &h, flow) +} + +// GetUnscaledBarcodeDimensions returns the width and height of the +// unscaled barcode associated with the given code. +func GetUnscaledBarcodeDimensions(pdf barcodePdf, code string) (w, h float64) { + barcodes.Lock() + unscaled, ok := barcodes.cache[code] + barcodes.Unlock() + + if !ok { + err := errors.New("Barcode not found") + pdf.SetError(err) + return + } + + return convertFrom96Dpi(pdf, float64(unscaled.Bounds().Dx())), + convertFrom96Dpi(pdf, float64(unscaled.Bounds().Dy())) +} + +// Register registers a barcode but does not put it on the page. Use Barcode() +// with the same code to put the barcode on the PDF page. +func Register(bcode barcode.Barcode) string { + barcodes.Lock() + if len(barcodes.cache) == 0 { + barcodes.cache = make(map[string]barcode.Barcode) + } + + key := barcodeKey(bcode) + barcodes.cache[key] = bcode + barcodes.Unlock() + + return key +} + +// RegisterAztec registers a barcode of type Aztec to the PDF, but not to +// the page. Use Barcode() with the return value to put the barcode on the page. +// code is the string to be encoded. minECCPercent is the error correction percentage. 33 is the default. +// userSpecifiedLayers can be a value between -4 and 32 inclusive. +func RegisterAztec(pdf barcodePdf, code string, minECCPercent int, userSpecifiedLayers int) string { + bcode, err := aztec.Encode([]byte(code), minECCPercent, userSpecifiedLayers) + return registerBarcode(pdf, bcode, err) +} + +// RegisterCodabar registers a barcode of type Codabar to the PDF, but not to +// the page. Use Barcode() with the return value to put the barcode on the page. +func RegisterCodabar(pdf barcodePdf, code string) string { + bcode, err := codabar.Encode(code) + return registerBarcode(pdf, bcode, err) +} + +// RegisterCode128 registers a barcode of type Code128 to the PDF, but not to +// the page. Use Barcode() with the return value to put the barcode on the page. +func RegisterCode128(pdf barcodePdf, code string) string { + bcode, err := code128.Encode(code) + return registerBarcode(pdf, bcode, err) +} + +// RegisterCode39 registers a barcode of type Code39 to the PDF, but not to +// the page. Use Barcode() with the return value to put the barcode on the page. +// +// includeChecksum and fullASCIIMode are inherited from code39.Encode(). +func RegisterCode39(pdf barcodePdf, code string, includeChecksum, fullASCIIMode bool) string { + bcode, err := code39.Encode(code, includeChecksum, fullASCIIMode) + return registerBarcode(pdf, bcode, err) +} + +// RegisterDataMatrix registers a barcode of type DataMatrix to the PDF, but not +// to the page. Use Barcode() with the return value to put the barcode on the +// page. +func RegisterDataMatrix(pdf barcodePdf, code string) string { + bcode, err := datamatrix.Encode(code) + return registerBarcode(pdf, bcode, err) +} + +// RegisterPdf417 registers a barcode of type Pdf417 to the PDF, but not to the +// page. code is the string to be encoded. columns specifies the number of +// barcode columns; this should be a value between 1 and 30 inclusive. +// securityLevel specifies an error correction level between zero and 8 +// inclusive. Barcodes for use with FedEx must set columns to 10 and +// securityLevel to 5. Use Barcode() with the return value to put the barcode +// on the page. +func RegisterPdf417(pdf barcodePdf, code string, columns int, securityLevel int) string { + bcode := pdf417.Encode(code, columns, securityLevel) + return registerBarcode(pdf, bcode, nil) +} + +// RegisterEAN registers a barcode of type EAN to the PDF, but not to the page. +// It will automatically detect if the barcode is EAN8 or EAN13. Use Barcode() +// with the return value to put the barcode on the page. +func RegisterEAN(pdf barcodePdf, code string) string { + bcode, err := ean.Encode(code) + return registerBarcode(pdf, bcode, err) +} + +// RegisterQR registers a barcode of type QR to the PDF, but not to the page. +// Use Barcode() with the return value to put the barcode on the page. +// +// The ErrorCorrectionLevel and Encoding mode are inherited from qr.Encode(). +func RegisterQR(pdf barcodePdf, code string, ecl qr.ErrorCorrectionLevel, mode qr.Encoding) string { + bcode, err := qr.Encode(code, ecl, mode) + return registerBarcode(pdf, bcode, err) +} + +// RegisterTwoOfFive registers a barcode of type TwoOfFive to the PDF, but not +// to the page. Use Barcode() with the return value to put the barcode on the +// page. +// +// The interleaved bool is inherited from twooffive.Encode(). +func RegisterTwoOfFive(pdf barcodePdf, code string, interleaved bool) string { + bcode, err := twooffive.Encode(code, interleaved) + return registerBarcode(pdf, bcode, err) +} + +// registerBarcode registers a barcode internally using the Register() function. +// In case of an error generating the barcode it will not be registered and will +// set an error on the PDF. It will return a unique key for the barcode type and +// content that can be used to put the barcode on the page. +func registerBarcode(pdf barcodePdf, bcode barcode.Barcode, err error) string { + if err != nil { + pdf.SetError(err) + return "" + } + + return Register(bcode) +} + +// uniqueBarcodeName makes sure every barcode has a unique name for its +// dimensions. Scaling a barcode image results in quality loss, which could be +// a problem for barcode readers. +func uniqueBarcodeName(code string, x, y float64) string { + xStr := strconv.FormatFloat(x, 'E', -1, 64) + yStr := strconv.FormatFloat(y, 'E', -1, 64) + + return "barcode-" + code + "-" + xStr + yStr +} + +// barcodeKey combines the code type and code value into a unique identifier for +// a barcode type. This is so that we can store several barcodes with the same +// code but different type in the barcodes map. +func barcodeKey(bcode barcode.Barcode) string { + return bcode.Metadata().CodeKind + bcode.Content() +} + +// registerScaledBarcode registers a barcode with its exact dimensions to the +// PDF but does not put it on the page. Use Fpdf.Image() with the same code to +// add the barcode to the page. +func registerScaledBarcode(pdf barcodePdf, code string, bcode barcode.Barcode) error { + buf := new(bytes.Buffer) + err := jpeg.Encode(buf, bcode, nil) + + if err != nil { + return err + } + + reader := bytes.NewReader(buf.Bytes()) + pdf.RegisterImageReader(code, "jpg", reader) + + return nil +} + +// convertTo96DPI converts the given value, which is based on a 72 DPI value +// like the rest of the PDF document, to a 96 DPI value that is required for +// an Image. +// +// Doing this through the Fpdf.Image() function would mean that it uses a 72 DPI +// value and stretches it to a 96 DPI value. This results in quality loss which +// could be problematic for barcode scanners. +func convertTo96Dpi(pdf barcodePdf, value float64) float64 { + return value * pdf.GetConversionRatio() / 72 * 96 +} + +// convertFrom96Dpi converts the given value, which is based on a 96 DPI value +// required for an Image, to a 72 DPI value like the rest of the PDF document. +func convertFrom96Dpi(pdf barcodePdf, value float64) float64 { + return value / pdf.GetConversionRatio() * 72 / 96 +} diff --git a/contrib/barcode/barcode_test.go b/contrib/barcode/barcode_test.go new file mode 100644 index 0000000..066ac41 --- /dev/null +++ b/contrib/barcode/barcode_test.go @@ -0,0 +1,222 @@ +package barcode_test + +import ( + "testing" + + "github.com/boombuler/barcode/code128" + "github.com/boombuler/barcode/qr" + "github.com/jung-kurt/gofpdf" + "github.com/jung-kurt/gofpdf/contrib/barcode" + "github.com/jung-kurt/gofpdf/internal/example" +) + +func createPdf() (pdf *gofpdf.Fpdf) { + pdf = gofpdf.New("L", "mm", "A4", "") + pdf.SetFont("Helvetica", "", 12) + pdf.SetFillColor(200, 200, 220) + pdf.AddPage() + return +} + +func ExampleRegister() { + pdf := createPdf() + + fileStr := example.Filename("contrib_barcode_Register") + + bcode, err := code128.Encode("gofpdf") + + if err == nil { + key := barcode.Register(bcode) + var width float64 = 100 + var height float64 = 10.0 + barcode.BarcodeUnscalable(pdf, key, 15, 15, &width, &height, false) + } + + err = pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated ../../pdf/contrib_barcode_Register.pdf +} + +func ExampleRegisterCodabar() { + pdf := createPdf() + + key := barcode.RegisterCode128(pdf, "codabar") + var width float64 = 100 + var height float64 = 10 + barcode.BarcodeUnscalable(pdf, key, 15, 15, &width, &height, false) + + fileStr := example.Filename("contrib_barcode_RegisterCodabar") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated ../../pdf/contrib_barcode_RegisterCodabar.pdf +} + +func ExampleRegisterAztec() { + pdf := createPdf() + + key := barcode.RegisterAztec(pdf, "aztec", 33, 0) + barcode.Barcode(pdf, key, 15, 15, 100, 100, false) + + fileStr := example.Filename("contrib_barcode_RegisterAztec") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated ../../pdf/contrib_barcode_RegisterAztec.pdf +} + +func ExampleRegisterCode128() { + pdf := createPdf() + + key := barcode.RegisterCode128(pdf, "code128") + barcode.Barcode(pdf, key, 15, 15, 100, 10, false) + + fileStr := example.Filename("contrib_barcode_RegisterCode128") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated ../../pdf/contrib_barcode_RegisterCode128.pdf +} + +func ExampleRegisterCode39() { + pdf := createPdf() + + key := barcode.RegisterCode39(pdf, "CODE39", false, true) + barcode.Barcode(pdf, key, 15, 15, 100, 10, false) + + fileStr := example.Filename("contrib_barcode_RegisterCode39") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated ../../pdf/contrib_barcode_RegisterCode39.pdf +} + +func ExampleRegisterDataMatrix() { + pdf := createPdf() + + key := barcode.RegisterDataMatrix(pdf, "datamatrix") + barcode.Barcode(pdf, key, 15, 15, 20, 20, false) + + fileStr := example.Filename("contrib_barcode_RegisterDataMatrix") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated ../../pdf/contrib_barcode_RegisterDataMatrix.pdf +} + +func ExampleRegisterEAN() { + pdf := createPdf() + + key := barcode.RegisterEAN(pdf, "96385074") + barcode.Barcode(pdf, key, 15, 15, 100, 10, false) + + fileStr := example.Filename("contrib_barcode_RegisterEAN") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated ../../pdf/contrib_barcode_RegisterEAN.pdf +} + +func ExampleRegisterQR() { + pdf := createPdf() + + key := barcode.RegisterQR(pdf, "qrcode", qr.H, qr.Unicode) + barcode.Barcode(pdf, key, 15, 15, 100, 10, false) + + fileStr := example.Filename("contrib_barcode_RegisterQR") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated ../../pdf/contrib_barcode_RegisterQR.pdf +} + +func ExampleRegisterTwoOfFive() { + pdf := createPdf() + + key := barcode.RegisterTwoOfFive(pdf, "1234567895", true) + barcode.Barcode(pdf, key, 15, 15, 100, 10, false) + + fileStr := example.Filename("contrib_barcode_RegisterTwoOfFive") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated ../../pdf/contrib_barcode_RegisterTwoOfFive.pdf +} + +func ExampleRegisterPdf417() { + pdf := createPdf() + + key := barcode.RegisterPdf417(pdf, "1234567895", 10, 5) + barcode.Barcode(pdf, key, 15, 15, 100, 10, false) + + fileStr := example.Filename("contrib_barcode_RegisterPdf417") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated ../../pdf/contrib_barcode_RegisterPdf417.pdf +} + +// TestRegisterCode128 ensures that no panic arises when an invalid barcode is registered. +func TestRegisterCode128(t *testing.T) { + pdf := createPdf() + barcode.RegisterCode128(pdf, "Invalid character: é") +} + +// TestBarcodeUnscalable shows that the barcode may be scaled or not by providing optional heights and widths. +func TestBarcodeUnscalable(t *testing.T) { + pdf := createPdf() + + key := barcode.RegisterCode128(pdf, "code128") + var width float64 = 100 + var height float64 = 10 + barcode.BarcodeUnscalable(pdf, key, 15, 15, &width, &height, false) + barcode.BarcodeUnscalable(pdf, key, 15, 35, nil, &height, false) + barcode.BarcodeUnscalable(pdf, key, 15, 55, &width, nil, false) + barcode.BarcodeUnscalable(pdf, key, 15, 75, nil, nil, false) + + fileStr := example.Filename("contrib_barcode_Barcode") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated ../../pdf/contrib_barcode_Barcode.pdf +} + +// TestGetUnscaledBarcodeDimensions shows that the width and height returned by the function match that of the barcode +func TestGetUnscaledBarcodeDimensions(t *testing.T) { + pdf := createPdf() + + key := barcode.RegisterQR(pdf, "qrcode", qr.H, qr.Unicode) + barcode.BarcodeUnscalable(pdf, key, 15, 15, nil, nil, false) + w, h := barcode.GetUnscaledBarcodeDimensions(pdf, key) + + pdf.SetDrawColor(255, 0, 0) + pdf.Line(15, 15, 15+w, 15+h) + + fileStr := example.Filename("contrib_barcode_GetBarcodeDimensions") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // 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/contrib/ghostscript/ghostscript.go b/contrib/ghostscript/ghostscript.go new file mode 100644 index 0000000..3196c34 --- /dev/null +++ b/contrib/ghostscript/ghostscript.go @@ -0,0 +1,68 @@ +package main + +// This command demonstrates the use of ghotscript to reduce the size +// of generated PDFs. This is based on a comment made by farkerhaiku: +// https://github.com/jung-kurt/gofpdf/issues/57#issuecomment-185843315 + +import ( + "fmt" + "os" + "os/exec" + + "github.com/jung-kurt/gofpdf" +) + +func report(fileStr string, err error) { + if err == nil { + var info os.FileInfo + info, err = os.Stat(fileStr) + if err == nil { + fmt.Printf("%s: OK, size %d\n", fileStr, info.Size()) + } else { + fmt.Printf("%s: bad stat\n", fileStr) + } + } else { + fmt.Printf("%s: %s\n", fileStr, err) + } +} + +func newPdf() (pdf *gofpdf.Fpdf) { + pdf = gofpdf.New("P", "mm", "A4", "../../font") + pdf.SetCompression(false) + pdf.AddFont("Calligrapher", "", "calligra.json") + pdf.AddPage() + pdf.SetFont("Calligrapher", "", 35) + pdf.Cell(0, 10, "Enjoy new fonts with FPDF!") + return +} + +func full(name string) { + report(name, newPdf().OutputFileAndClose(name)) +} + +func min(name string) { + cmd := exec.Command("gs", "-sDEVICE=pdfwrite", + "-dCompatibilityLevel=1.4", + "-dPDFSETTINGS=/screen", "-dNOPAUSE", "-dQUIET", + "-dBATCH", "-sOutputFile="+name, "-") + inPipe, err := cmd.StdinPipe() + if err == nil { + errChan := make(chan error, 1) + go func() { + errChan <- cmd.Start() + }() + err = newPdf().Output(inPipe) + if err == nil { + report(name, <-errChan) + } else { + report(name, err) + } + } else { + report(name, err) + } +} + +func main() { + full("full.pdf") + min("min.pdf") +} diff --git a/contrib/gofpdi/gofpdi.go b/contrib/gofpdi/gofpdi.go new file mode 100644 index 0000000..7b9c822 --- /dev/null +++ b/contrib/gofpdi/gofpdi.go @@ -0,0 +1,143 @@ +/* +Package gofpdi wraps the gofpdi PDF library to import existing PDFs as templates. See github.com/phpdave11/gofpdi +for further information and examples. + +Users should call NewImporter() to obtain their own Importer instance to work with. +To retain backwards compatibility, the package offers a default Importer that may be used via global functions. Note +however that use of the default Importer is not thread safe. +*/ +package gofpdi + +import ( + realgofpdi "github.com/phpdave11/gofpdi" + "io" +) + +// gofpdiPdf is a partial interface that only implements the functions we need +// from the PDF generator to put the imported PDF templates on the PDF. +type gofpdiPdf interface { + ImportObjects(objs map[string][]byte) + ImportObjPos(objs map[string]map[int]string) + ImportTemplates(tpls map[string]string) + UseImportedTemplate(tplName string, x float64, y float64, w float64, h float64) + SetError(err error) +} + +// Importer wraps an Importer from the gofpdi library. +type Importer struct { + fpdi *realgofpdi.Importer +} + +// NewImporter creates a new Importer wrapping functionality from the gofpdi library. +func NewImporter() *Importer { + return &Importer{ + fpdi: realgofpdi.NewImporter(), + } +} + +// ImportPage imports a page of a PDF file with the specified box (/MediaBox, +// /TrimBox, /ArtBox, /CropBox, or /BleedBox). Returns a template id that can +// be used with UseImportedTemplate to draw the template onto the page. +func (i *Importer) ImportPage(f gofpdiPdf, sourceFile string, pageno int, box string) int { + // Set source file for fpdi + i.fpdi.SetSourceFile(sourceFile) + // return template id + return i.getTemplateID(f, pageno, box) +} + +// ImportPageFromStream imports a page of a PDF with the specified box +// (/MediaBox, TrimBox, /ArtBox, /CropBox, or /BleedBox). Returns a template id +// that can be used with UseImportedTemplate to draw the template onto the +// page. +func (i *Importer) ImportPageFromStream(f gofpdiPdf, rs *io.ReadSeeker, pageno int, box string) int { + // Set source stream for fpdi + i.fpdi.SetSourceStream(rs) + // return template id + return i.getTemplateID(f, pageno, box) +} + +func (i *Importer) getTemplateID(f gofpdiPdf, pageno int, box string) int { + // Import page + tpl := i.fpdi.ImportPage(pageno, box) + + // Import objects into current pdf document + // Unordered means that the objects will be returned with a sha1 hash instead of an integer + // The objects themselves may have references to other hashes which will be replaced in ImportObjects() + tplObjIDs := i.fpdi.PutFormXobjectsUnordered() + + // Set template names and ids (hashes) in gofpdf + f.ImportTemplates(tplObjIDs) + + // Get a map[string]string of the imported objects. + // The map keys will be the ID of each object. + imported := i.fpdi.GetImportedObjectsUnordered() + + // Import gofpdi objects into gofpdf + f.ImportObjects(imported) + + // Get a map[string]map[int]string of the object hashes and their positions within each object, + // to be replaced with object ids (integers). + importedObjPos := i.fpdi.GetImportedObjHashPos() + + // Import gofpdi object hashes and their positions into gopdf + f.ImportObjPos(importedObjPos) + + return tpl +} + +// UseImportedTemplate draws the template onto the page at x,y. If w is 0, the +// template will be scaled to fit based on h. If h is 0, the template will be +// scaled to fit based on w. +func (i *Importer) UseImportedTemplate(f gofpdiPdf, tplid int, x float64, y float64, w float64, h float64) { + // Get values from fpdi + tplName, scaleX, scaleY, tX, tY := i.fpdi.UseTemplate(tplid, x, y, w, h) + + f.UseImportedTemplate(tplName, scaleX, scaleY, tX, tY) +} + +// GetPageSizes returns page dimensions for all pages of the imported pdf. +// Result consists of map[]map[]map[]. +// : page number, note that page numbers start at 1 +// : box identifier, e.g. "/MediaBox" +// : dimension string, either "w" or "h" +func (i *Importer) GetPageSizes() map[int]map[string]map[string]float64 { + return i.fpdi.GetPageSizes() +} + +// Default Importer used by global functions +var fpdi = NewImporter() + +// ImportPage imports a page of a PDF file with the specified box (/MediaBox, +// /TrimBox, /ArtBox, /CropBox, or /BleedBox). Returns a template id that can +// be used with UseImportedTemplate to draw the template onto the page. +// Note: This uses the default Importer. Call NewImporter() to obtain a custom Importer. +func ImportPage(f gofpdiPdf, sourceFile string, pageno int, box string) int { + return fpdi.ImportPage(f, sourceFile, pageno, box) +} + +// ImportPageFromStream imports a page of a PDF with the specified box +// (/MediaBox, TrimBox, /ArtBox, /CropBox, or /BleedBox). Returns a template id +// that can be used with UseImportedTemplate to draw the template onto the +// page. +// Note: This uses the default Importer. Call NewImporter() to obtain a custom Importer. +func ImportPageFromStream(f gofpdiPdf, rs *io.ReadSeeker, pageno int, box string) int { + return fpdi.ImportPageFromStream(f, rs, pageno, box) +} + +// UseImportedTemplate draws the template onto the page at x,y. If w is 0, the +// template will be scaled to fit based on h. If h is 0, the template will be +// scaled to fit based on w. +// Note: This uses the default Importer. Call NewImporter() to obtain a custom Importer. +func UseImportedTemplate(f gofpdiPdf, tplid int, x float64, y float64, w float64, h float64) { + fpdi.UseImportedTemplate(f, tplid, x, y, w, h) +} + +// GetPageSizes returns page dimensions for all pages of the imported pdf. +// Result consists of map[]map[]map[]. +// : page number, note that page numbers start at 1 +// : box identifier, e.g. "/MediaBox" +// : dimension string, either "w" or "h" +// Note: This uses the default Importer. Call NewImporter() to obtain a custom Importer. +func GetPageSizes() map[int]map[string]map[string]float64 { + return fpdi.GetPageSizes() +} diff --git a/contrib/gofpdi/gofpdi_test.go b/contrib/gofpdi/gofpdi_test.go new file mode 100644 index 0000000..70ef6cc --- /dev/null +++ b/contrib/gofpdi/gofpdi_test.go @@ -0,0 +1,76 @@ +package gofpdi + +import ( + "bytes" + "github.com/jung-kurt/gofpdf" + "github.com/jung-kurt/gofpdf/internal/example" + "io" + "sync" + "testing" +) + +func ExampleNewImporter() { + // create new pdf + pdf := gofpdf.New("P", "pt", "A4", "") + + // for testing purposes, get an arbitrary template pdf as stream + rs, _ := getTemplatePdf() + + // create a new Importer instance + imp := NewImporter() + + // import first page and determine page sizes + tpl := imp.ImportPageFromStream(pdf, &rs, 1, "/MediaBox") + pageSizes := imp.GetPageSizes() + nrPages := len(imp.GetPageSizes()) + + // add all pages from template pdf + for i := 1; i <= nrPages; i++ { + pdf.AddPage() + if i > 1 { + tpl = imp.ImportPageFromStream(pdf, &rs, i, "/MediaBox") + } + imp.UseImportedTemplate(pdf, tpl, 0, 0, pageSizes[i]["/MediaBox"]["w"], pageSizes[i]["/MediaBox"]["h"]) + } + + // output + fileStr := example.Filename("contrib_gofpdi_Importer") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated ../../pdf/contrib_gofpdi_Importer.pdf +} + +func TestGofpdiConcurrent(t *testing.T) { + wg := sync.WaitGroup{} + for i := 0; i < 100; i++ { + wg.Add(1) + go func() { + defer wg.Done() + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + rs, _ := getTemplatePdf() + imp := NewImporter() + tpl := imp.ImportPageFromStream(pdf, &rs, 1, "/MediaBox") + imp.UseImportedTemplate(pdf, tpl, 0, 0, 210.0, 297.0) + // write to bytes buffer + buf := bytes.Buffer{} + if err := pdf.Output(&buf); err != nil { + t.Fail() + } + }() + } + wg.Wait() +} + +func getTemplatePdf() (io.ReadSeeker, error) { + tpdf := gofpdf.New("P", "pt", "A4", "") + tpdf.AddPage() + tpdf.SetFont("Arial", "", 12) + tpdf.Text(20, 20, "Example Page 1") + tpdf.AddPage() + tpdf.Text(20, 20, "Example Page 2") + tbuf := bytes.Buffer{} + err := tpdf.Output(&tbuf) + return bytes.NewReader(tbuf.Bytes()), err +} diff --git a/contrib/httpimg/httpimg.go b/contrib/httpimg/httpimg.go new file mode 100644 index 0000000..7cbf281 --- /dev/null +++ b/contrib/httpimg/httpimg.go @@ -0,0 +1,43 @@ +package httpimg + +import ( + "io" + "net/http" + + "github.com/jung-kurt/gofpdf" +) + +// httpimgPdf is a partial interface that only implements the functions we need +// from the PDF generator to put the HTTP images on the PDF. +type httpimgPdf interface { + GetImageInfo(imageStr string) *gofpdf.ImageInfoType + ImageTypeFromMime(mimeStr string) string + RegisterImageReader(imgName, tp string, r io.Reader) *gofpdf.ImageInfoType + SetError(err error) +} + +// Register registers a HTTP image. Downloading the image from the provided URL +// and adding it to the PDF but not adding it to the page. Use Image() with the +// same URL to add the image to the page. +func Register(f httpimgPdf, urlStr, tp string) (info *gofpdf.ImageInfoType) { + info = f.GetImageInfo(urlStr) + + if info != nil { + return + } + + resp, err := http.Get(urlStr) + + if err != nil { + f.SetError(err) + return + } + + defer resp.Body.Close() + + if tp == "" { + tp = f.ImageTypeFromMime(resp.Header["Content-Type"][0]) + } + + return f.RegisterImageReader(urlStr, tp, resp.Body) +} diff --git a/contrib/httpimg/httpimg_test.go b/contrib/httpimg/httpimg_test.go new file mode 100644 index 0000000..bf13492 --- /dev/null +++ b/contrib/httpimg/httpimg_test.go @@ -0,0 +1,23 @@ +package httpimg_test + +import ( + "github.com/jung-kurt/gofpdf" + "github.com/jung-kurt/gofpdf/contrib/httpimg" + "github.com/jung-kurt/gofpdf/internal/example" +) + +func ExampleRegister() { + pdf := gofpdf.New("L", "mm", "A4", "") + pdf.SetFont("Helvetica", "", 12) + pdf.SetFillColor(200, 200, 220) + pdf.AddPage() + + url := "https://github.com/jung-kurt/gofpdf/raw/master/image/logo_gofpdf.jpg?raw=true" + httpimg.Register(pdf, url, "") + pdf.Image(url, 15, 15, 267, 0, false, "", 0, "") + fileStr := example.Filename("contrib_httpimg_Register") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated ../../pdf/contrib_httpimg_Register.pdf +} diff --git a/contrib/tiff/tiff.go b/contrib/tiff/tiff.go new file mode 100644 index 0000000..3f13a38 --- /dev/null +++ b/contrib/tiff/tiff.go @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2016 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +// Package tiff allows standard (LZW-compressed) TIFF images to be used in +// documents generated with gofpdf. +package tiff + +import ( + "bytes" + "fmt" + "image" + "image/png" + "io" + "os" + + "github.com/jung-kurt/gofpdf" + "golang.org/x/image/tiff" +) + +// RegisterReader registers a TIFF image, adding it to the PDF file but not +// adding it to the page. imgName specifies the name that will be used in the +// call to Image() that actually places the image in the document. options +// specifies various image properties; in this case, the ImageType property +// should be set to "tiff". The TIFF image is a reader from the reader +// specified by r. +func RegisterReader(fpdf *gofpdf.Fpdf, imgName string, options gofpdf.ImageOptions, r io.Reader) (info *gofpdf.ImageInfoType) { + var err error + var img image.Image + var buf bytes.Buffer + if fpdf.Ok() { + if options.ImageType == "tiff" || options.ImageType == "tif" { + img, err = tiff.Decode(r) + if err == nil { + err = png.Encode(&buf, img) + if err == nil { + options.ImageType = "png" + info = fpdf.RegisterImageOptionsReader(imgName, options, &buf) + } + } + } else { + err = fmt.Errorf("expecting \"tiff\" or \"tif\" as image type, got \"%s\"", options.ImageType) + } + if err != nil { + fpdf.SetError(err) + } + } + return +} + +// RegisterFile registers a TIFF image, adding it to the PDF file but not +// adding it to the page. imgName specifies the name that will be used in the +// call to Image() that actually places the image in the document. options +// specifies various image properties; in this case, the ImageType property +// should be set to "tiff". The TIFF image is read from the file specified by +// tiffFileStr. +func RegisterFile(fpdf *gofpdf.Fpdf, imgName string, options gofpdf.ImageOptions, tiffFileStr string) (info *gofpdf.ImageInfoType) { + var f *os.File + var err error + + if fpdf.Ok() { + f, err = os.Open(tiffFileStr) + if err == nil { + info = RegisterReader(fpdf, imgName, options, f) + f.Close() + } else { + fpdf.SetError(err) + } + } + return +} diff --git a/contrib/tiff/tiff_test.go b/contrib/tiff/tiff_test.go new file mode 100644 index 0000000..33b294b --- /dev/null +++ b/contrib/tiff/tiff_test.go @@ -0,0 +1,23 @@ +package tiff_test + +import ( + "github.com/jung-kurt/gofpdf" + "github.com/jung-kurt/gofpdf/contrib/tiff" + "github.com/jung-kurt/gofpdf/internal/example" +) + +// ExampleRegisterFile demonstrates the loading and display of a TIFF image. +func ExampleRegisterFile() { + pdf := gofpdf.New("L", "mm", "A4", "") + pdf.SetFont("Helvetica", "", 12) + pdf.SetFillColor(200, 200, 220) + pdf.AddPageFormat("L", gofpdf.SizeType{Wd: 200, Ht: 200}) + opt := gofpdf.ImageOptions{ImageType: "tiff", ReadDpi: false} + _ = tiff.RegisterFile(pdf, "sample", opt, "../../image/golang-gopher.tiff") + pdf.Image("sample", 0, 0, 200, 200, false, "", 0, "") + fileStr := example.Filename("Fpdf_Contrib_Tiff") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated ../../pdf/Fpdf_Contrib_Tiff.pdf +} diff --git a/def.go b/def.go new file mode 100644 index 0000000..6a7030f --- /dev/null +++ b/def.go @@ -0,0 +1,738 @@ +/* + * Copyright (c) 2013-2014 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf + +import ( + "bytes" + "crypto/sha1" + "encoding/gob" + "encoding/json" + "fmt" + "io" + "time" +) + +// Version of FPDF from which this package is derived +const ( + cnFpdfVersion = "1.7" +) + +type blendModeType struct { + strokeStr, fillStr, modeStr string + objNum int +} + +type gradientType struct { + tp int // 2: linear, 3: radial + clr1Str, clr2Str string + x1, y1, x2, y2, r float64 + objNum int +} + +const ( + // OrientationPortrait represents the portrait orientation. + OrientationPortrait = "portrait" + + // OrientationLandscape represents the landscape orientation. + OrientationLandscape = "landscape" +) + +const ( + // UnitPoint represents the size unit point + UnitPoint = "pt" + // UnitMillimeter represents the size unit millimeter + UnitMillimeter = "mm" + // UnitCentimeter represents the size unit centimeter + UnitCentimeter = "cm" + // UnitInch represents the size unit inch + UnitInch = "inch" +) + +const ( + // PageSizeA3 represents DIN/ISO A3 page size + PageSizeA3 = "A3" + // PageSizeA4 represents DIN/ISO A4 page size + PageSizeA4 = "A4" + // PageSizeA5 represents DIN/ISO A5 page size + PageSizeA5 = "A5" + // PageSizeLetter represents US Letter page size + PageSizeLetter = "Letter" + // PageSizeLegal represents US Legal page size + PageSizeLegal = "Legal" +) + +const ( + // BorderNone set no border + BorderNone = "" + // BorderFull sets a full border + BorderFull = "1" + // BorderLeft sets the border on the left side + BorderLeft = "L" + // BorderTop sets the border at the top + BorderTop = "T" + // BorderRight sets the border on the right side + BorderRight = "R" + // BorderBottom sets the border on the bottom + BorderBottom = "B" +) + +const ( + // LineBreakNone disables linebreak + LineBreakNone = 0 + // LineBreakNormal enables normal linebreak + LineBreakNormal = 1 + // LineBreakBelow enables linebreak below + LineBreakBelow = 2 +) + +const ( + // AlignLeft left aligns the cell + AlignLeft = "L" + // AlignRight right aligns the cell + AlignRight = "R" + // AlignCenter centers the cell + AlignCenter = "C" + // AlignTop aligns the cell to the top + AlignTop = "T" + // AlignBottom aligns the cell to the bottom + AlignBottom = "B" + // AlignMiddle aligns the cell to the middle + AlignMiddle = "M" + // AlignBaseline aligns the cell to the baseline + AlignBaseline = "B" +) + +type colorMode int + +const ( + colorModeRGB colorMode = iota + colorModeSpot + colorModeCMYK +) + +type colorType struct { + r, g, b float64 + ir, ig, ib int + mode colorMode + spotStr string // name of current spot color + gray bool + str string +} + +// SpotColorType specifies a named spot color value +type spotColorType struct { + id, objID int + val cmykColorType +} + +// CMYKColorType specifies an ink-based CMYK color value +type cmykColorType struct { + c, m, y, k byte // 0% to 100% +} + +// SizeType fields Wd and Ht specify the horizontal and vertical extents of a +// document element such as a page. +type SizeType struct { + Wd, Ht float64 +} + +// PointType fields X and Y specify the horizontal and vertical coordinates of +// a point, typically used in drawing. +type PointType struct { + X, Y float64 +} + +// XY returns the X and Y components of the receiver point. +func (p PointType) XY() (float64, float64) { + return p.X, p.Y +} + +// ImageInfoType contains size, color and other information about an image. +// Changes to this structure should be reflected in its GobEncode and GobDecode +// methods. +type ImageInfoType struct { + data []byte // 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) { + b, err := info.GobEncode() + return fmt.Sprintf("%x", sha1.Sum(b)), err +} + +// GobEncode encodes the receiving image to a byte slice. +func (info *ImageInfoType) GobEncode() (buf []byte, err error) { + fields := []interface{}{info.data, info.smask, info.n, info.w, info.h, info.cs, + info.pal, info.bpc, info.f, info.dp, info.trns, info.scale, info.dpi} + w := new(bytes.Buffer) + encoder := gob.NewEncoder(w) + for j := 0; j < len(fields) && err == nil; j++ { + err = encoder.Encode(fields[j]) + } + if err == nil { + buf = w.Bytes() + } + return +} + +// GobDecode decodes the specified byte buffer (generated by GobEncode) into +// the receiving image. +func (info *ImageInfoType) GobDecode(buf []byte) (err error) { + fields := []interface{}{&info.data, &info.smask, &info.n, &info.w, &info.h, + &info.cs, &info.pal, &info.bpc, &info.f, &info.dp, &info.trns, &info.scale, &info.dpi} + r := bytes.NewBuffer(buf) + decoder := gob.NewDecoder(r) + for j := 0; j < len(fields) && err == nil; j++ { + err = decoder.Decode(fields[j]) + } + + info.i, err = generateImageID(info) + return +} + +// PointConvert returns the value of pt, expressed in points (1/72 inch), as a +// value expressed in the unit of measure specified in New(). Since font +// management in Fpdf uses points, this method can help with line height +// calculations and other methods that require user units. +func (f *Fpdf) PointConvert(pt float64) (u float64) { + return pt / f.k +} + +// PointToUnitConvert is an alias for PointConvert. +func (f *Fpdf) PointToUnitConvert(pt float64) (u float64) { + return pt / f.k +} + +// UnitToPointConvert returns the value of u, expressed in the unit of measure +// specified in New(), as a value expressed in points (1/72 inch). Since font +// management in Fpdf uses points, this method can help with setting font sizes +// based on the sizes of other non-font page elements. +func (f *Fpdf) UnitToPointConvert(u float64) (pt float64) { + return u * f.k +} + +// Extent returns the width and height of the image in the units of the Fpdf +// object. +func (info *ImageInfoType) Extent() (wd, ht float64) { + return info.Width(), info.Height() +} + +// Width returns the width of the image in the units of the Fpdf object. +func (info *ImageInfoType) Width() float64 { + return info.w / (info.scale * info.dpi / 72) +} + +// Height returns the height of the image in the units of the Fpdf object. +func (info *ImageInfoType) Height() float64 { + return info.h / (info.scale * info.dpi / 72) +} + +// SetDpi sets the dots per inch for an image. PNG images MAY have their dpi +// set automatically, if the image specifies it. DPI information is not +// currently available automatically for JPG and GIF images, so if it's +// important to you, you can set it here. It defaults to 72 dpi. +func (info *ImageInfoType) SetDpi(dpi float64) { + info.dpi = dpi +} + +type fontFileType struct { + length1, length2 int64 + n int + embedded bool + content []byte + fontType string +} + +type linkType struct { + x, y, wd, ht float64 + link int // Auto-generated internal link ID or... + linkStr string // ...application-provided external link string +} + +type intLinkType struct { + page int + y float64 +} + +// outlineType is used for a sidebar outline of bookmarks +type outlineType struct { + text string + level, parent, first, last, next, prev int + y float64 + p int +} + +// InitType is used with NewCustom() to customize an Fpdf instance. +// OrientationStr, UnitStr, SizeStr and FontDirStr correspond to the arguments +// accepted by New(). If the Wd and Ht fields of Size are each greater than +// zero, Size will be used to set the default page size rather than SizeStr. Wd +// and Ht are specified in the units of measure indicated by UnitStr. +type InitType struct { + OrientationStr string + UnitStr string + SizeStr string + Size SizeType + FontDirStr string +} + +// FontLoader is used to read fonts (JSON font specification and zlib compressed font binaries) +// from arbitrary locations (e.g. files, zip files, embedded font resources). +// +// Open provides an io.Reader for the specified font file (.json or .z). The file name +// never includes a path. Open returns an error if the specified file cannot be opened. +type FontLoader interface { + Open(name string) (io.Reader, error) +} + +// Pdf defines the interface used for various methods. It is implemented by the +// main FPDF instance as well as templates. +type Pdf interface { + AddFont(familyStr, styleStr, fileStr string) + AddFontFromBytes(familyStr, styleStr string, jsonFileBytes, zFileBytes []byte) + AddFontFromReader(familyStr, styleStr string, r io.Reader) + AddLayer(name string, visible bool) (layerID int) + AddLink() int + AddPage() + AddPageFormat(orientationStr string, size SizeType) + AddSpotColor(nameStr string, c, m, y, k byte) + AliasNbPages(aliasStr string) + ArcTo(x, y, rx, ry, degRotate, degStart, degEnd float64) + Arc(x, y, rx, ry, degRotate, degStart, degEnd float64, styleStr string) + BeginLayer(id int) + Beziergon(points []PointType, styleStr string) + Bookmark(txtStr string, level int, y float64) + CellFormat(w, h float64, txtStr, borderStr string, ln int, alignStr string, fill bool, link int, linkStr string) + Cellf(w, h float64, fmtStr string, args ...interface{}) + Cell(w, h float64, txtStr string) + Circle(x, y, r float64, styleStr string) + ClearError() + ClipCircle(x, y, r float64, outline bool) + ClipEllipse(x, y, rx, ry float64, outline bool) + ClipEnd() + ClipPolygon(points []PointType, outline bool) + ClipRect(x, y, w, h float64, outline bool) + ClipRoundedRect(x, y, w, h, r float64, outline bool) + ClipText(x, y float64, txtStr string, outline bool) + Close() + ClosePath() + CreateTemplateCustom(corner PointType, size SizeType, fn func(*Tpl)) Template + CreateTemplate(fn func(*Tpl)) Template + CurveBezierCubicTo(cx0, cy0, cx1, cy1, x, y float64) + CurveBezierCubic(x0, y0, cx0, cy0, cx1, cy1, x1, y1 float64, styleStr string) + CurveCubic(x0, y0, cx0, cy0, x1, y1, cx1, cy1 float64, styleStr string) + CurveTo(cx, cy, x, y float64) + Curve(x0, y0, cx, cy, x1, y1 float64, styleStr string) + DrawPath(styleStr string) + Ellipse(x, y, rx, ry, degRotate float64, styleStr string) + EndLayer() + Err() bool + Error() error + GetAlpha() (alpha float64, blendModeStr string) + GetAutoPageBreak() (auto bool, margin float64) + GetCellMargin() float64 + GetConversionRatio() float64 + GetDrawColor() (int, int, int) + GetDrawSpotColor() (name string, c, m, y, k byte) + GetFillColor() (int, int, int) + GetFillSpotColor() (name string, c, m, y, k byte) + GetFontDesc(familyStr, styleStr string) FontDescType + GetFontSize() (ptSize, unitSize float64) + GetImageInfo(imageStr string) (info *ImageInfoType) + GetLineWidth() float64 + GetMargins() (left, top, right, bottom float64) + GetPageSizeStr(sizeStr string) (size SizeType) + GetPageSize() (width, height float64) + GetStringWidth(s string) float64 + GetTextColor() (int, int, int) + GetTextSpotColor() (name string, c, m, y, k byte) + GetX() float64 + GetXY() (float64, float64) + GetY() float64 + HTMLBasicNew() (html HTMLBasicType) + Image(imageNameStr string, x, y, w, h float64, flow bool, tp string, link int, linkStr string) + ImageOptions(imageNameStr string, x, y, w, h float64, flow bool, options ImageOptions, link int, linkStr string) + ImageTypeFromMime(mimeStr string) (tp string) + LinearGradient(x, y, w, h float64, r1, g1, b1, r2, g2, b2 int, x1, y1, x2, y2 float64) + LineTo(x, y float64) + Line(x1, y1, x2, y2 float64) + LinkString(x, y, w, h float64, linkStr string) + Link(x, y, w, h float64, link int) + Ln(h float64) + MoveTo(x, y float64) + MultiCell(w, h float64, txtStr, borderStr, alignStr string, fill bool) + Ok() bool + OpenLayerPane() + OutputAndClose(w io.WriteCloser) error + OutputFileAndClose(fileStr string) error + Output(w io.Writer) error + PageCount() int + PageNo() int + PageSize(pageNum int) (wd, ht float64, unitStr string) + PointConvert(pt float64) (u float64) + PointToUnitConvert(pt float64) (u float64) + Polygon(points []PointType, styleStr string) + RadialGradient(x, y, w, h float64, r1, g1, b1, r2, g2, b2 int, x1, y1, x2, y2, r float64) + RawWriteBuf(r io.Reader) + RawWriteStr(str string) + Rect(x, y, w, h float64, styleStr string) + RegisterAlias(alias, replacement string) + RegisterImage(fileStr, tp string) (info *ImageInfoType) + RegisterImageOptions(fileStr string, options ImageOptions) (info *ImageInfoType) + RegisterImageOptionsReader(imgName string, options ImageOptions, r io.Reader) (info *ImageInfoType) + RegisterImageReader(imgName, tp string, r io.Reader) (info *ImageInfoType) + SetAcceptPageBreakFunc(fnc func() bool) + SetAlpha(alpha float64, blendModeStr string) + SetAuthor(authorStr string, isUTF8 bool) + SetAutoPageBreak(auto bool, margin float64) + SetCatalogSort(flag bool) + SetCellMargin(margin float64) + SetCompression(compress bool) + SetCreationDate(tm time.Time) + SetCreator(creatorStr string, isUTF8 bool) + SetDashPattern(dashArray []float64, dashPhase float64) + SetDisplayMode(zoomStr, layoutStr string) + SetDrawColor(r, g, b int) + SetDrawSpotColor(nameStr string, tint byte) + SetError(err error) + SetErrorf(fmtStr string, args ...interface{}) + SetFillColor(r, g, b int) + SetFillSpotColor(nameStr string, tint byte) + SetFont(familyStr, styleStr string, size float64) + SetFontLoader(loader FontLoader) + SetFontLocation(fontDirStr string) + SetFontSize(size float64) + SetFontStyle(styleStr string) + SetFontUnitSize(size float64) + SetFooterFunc(fnc func()) + SetFooterFuncLpi(fnc func(lastPage bool)) + SetHeaderFunc(fnc func()) + SetHeaderFuncMode(fnc func(), homeMode bool) + SetHomeXY() + SetJavascript(script string) + SetKeywords(keywordsStr string, isUTF8 bool) + SetLeftMargin(margin float64) + SetLineCapStyle(styleStr string) + SetLineJoinStyle(styleStr string) + SetLineWidth(width float64) + SetLink(link int, y float64, page int) + SetMargins(left, top, right float64) + SetPageBoxRec(t string, pb PageBox) + SetPageBox(t string, x, y, wd, ht float64) + SetPage(pageNum int) + SetProtection(actionFlag byte, userPassStr, ownerPassStr string) + SetRightMargin(margin float64) + SetSubject(subjectStr string, isUTF8 bool) + SetTextColor(r, g, b int) + SetTextSpotColor(nameStr string, tint byte) + SetTitle(titleStr string, isUTF8 bool) + SetTopMargin(margin float64) + SetUnderlineThickness(thickness float64) + SetXmpMetadata(xmpStream []byte) + SetX(x float64) + SetXY(x, y float64) + SetY(y float64) + SplitLines(txt []byte, w float64) [][]byte + String() string + SVGBasicWrite(sb *SVGBasicType, scale float64) + Text(x, y float64, txtStr string) + TransformBegin() + TransformEnd() + TransformMirrorHorizontal(x float64) + TransformMirrorLine(angle, x, y float64) + TransformMirrorPoint(x, y float64) + TransformMirrorVertical(y float64) + TransformRotate(angle, x, y float64) + TransformScale(scaleWd, scaleHt, x, y float64) + TransformScaleX(scaleWd, x, y float64) + TransformScaleXY(s, x, y float64) + TransformScaleY(scaleHt, x, y float64) + TransformSkew(angleX, angleY, x, y float64) + TransformSkewX(angleX, x, y float64) + TransformSkewY(angleY, x, y float64) + Transform(tm TransformMatrix) + TransformTranslate(tx, ty float64) + TransformTranslateX(tx float64) + TransformTranslateY(ty float64) + UnicodeTranslatorFromDescriptor(cpStr string) (rep func(string) string) + UnitToPointConvert(u float64) (pt float64) + UseTemplateScaled(t Template, corner PointType, size SizeType) + UseTemplate(t Template) + WriteAligned(width, lineHeight float64, textStr, alignStr string) + Writef(h float64, fmtStr string, args ...interface{}) + Write(h float64, txtStr string) + WriteLinkID(h float64, displayStr string, linkID int) + WriteLinkString(h float64, displayStr, targetStr string) +} + +// PageBox defines the coordinates and extent of the various page box types +type PageBox struct { + SizeType + PointType +} + +// Fpdf is the principal structure for creating a single PDF document +type Fpdf struct { + isCurrentUTF8 bool // is current font used in utf-8 mode + isRTL bool // is is right to left mode enabled + page int // current page number + n int // current object number + offsets []int // array of object offsets + templates map[string]Template // templates used in this document + templateObjects map[string]int // template object IDs within this document + importedObjs map[string][]byte // imported template objects (gofpdi) + importedObjPos map[string]map[int]string // imported template objects hashes and their positions (gofpdi) + importedTplObjs map[string]string // imported template names and IDs (hashed) (gofpdi) + importedTplIDs map[string]int // imported template ids hash to object id int (gofpdi) + buffer fmtBuffer // buffer holding in-memory PDF + pages []*bytes.Buffer // slice[page] of page content; 1-based + state int // current document state + compress bool // compression flag + k float64 // scale factor (number of points in user unit) + defOrientation string // default orientation + curOrientation string // current orientation + stdPageSizes map[string]SizeType // standard page sizes + defPageSize SizeType // default page size + defPageBoxes map[string]PageBox // default page size + curPageSize SizeType // current page size + pageSizes map[int]SizeType // used for pages with non default sizes or orientations + pageBoxes map[int]map[string]PageBox // used to define the crop, trim, bleed and art boxes + unitStr string // unit of measure for all rendered objects except fonts + wPt, hPt float64 // dimensions of current page in points + w, h float64 // dimensions of current page in user unit + lMargin float64 // left margin + tMargin float64 // top margin + rMargin float64 // right margin + bMargin float64 // page break margin + cMargin float64 // cell margin + x, y float64 // current position in user unit + lasth float64 // height of last printed cell + lineWidth float64 // line width in user unit + fontpath string // path containing fonts + fontLoader FontLoader // used to load font files from arbitrary locations + coreFonts map[string]bool // array of core font names + fonts map[string]fontDefType // array of used fonts + fontFiles map[string]fontFileType // array of font files + diffs []string // array of encoding differences + fontFamily string // current font family + fontStyle string // current font style + underline bool // underlining flag + 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 + ws float64 // word spacing + images map[string]*ImageInfoType // array of used images + aliasMap map[string]string // map of alias->replacement + pageLinks [][]linkType // pageLinks[page][link], both 1-based + links []intLinkType // array of internal links + attachments []Attachment // slice of content to embed globally + pageAttachments [][]annotationAttach // 1-based array of annotation for file attachments (per page) + outlines []outlineType // array of outlines + outlineRoot int // root of outlines + autoPageBreak bool // automatic page breaking + acceptPageBreak func() bool // returns true to accept page break + pageBreakTrigger float64 // threshold used to trigger page breaks + inHeader bool // flag set when processing header + headerFnc func() // function provided by app and called to write header + headerHomeMode bool // set position to home after headerFnc is called + inFooter bool // flag set when processing footer + footerFnc func() // function provided by app and called to write footer + footerFncLpi func(bool) // function provided by app and called to write footer with last page flag + zoomMode string // zoom display mode + layoutMode string // layout display mode + xmp []byte // XMP metadata + producer string // producer + title string // title + subject string // subject + author string // author + keywords string // keywords + creator string // creator + creationDate time.Time // override for document CreationDate value + modDate time.Time // override for document ModDate value + aliasNbPagesStr string // alias for total number of pages + pdfVersion string // PDF version number + fontDirStr string // location of font definition files + capStyle int // line cap style: butt 0, round 1, square 2 + joinStyle int // line segment join style: miter 0, round 1, bevel 2 + dashArray []float64 // dash array + dashPhase float64 // dash phase + blendList []blendModeType // slice[idx] of alpha transparency modes, 1-based + blendMap map[string]int // map into blendList + blendMode string // current blend mode + alpha float64 // current transpacency + gradientList []gradientType // slice[idx] of gradient records + clipNest int // Number of active clipping contexts + transformNest int // Number of active transformation contexts + err error // Set if error occurs during life cycle of instance + protect protectType // document protection structure + layer layerRecType // manages optional layers in document + catalogSort bool // sort resource catalogs in document + nJs int // JavaScript object number + javascript *string // JavaScript code to include in the PDF + colorFlag bool // indicates whether fill and text colors are different + color struct { + // Composite values of colors + draw, fill, text colorType + } + spotColorMap map[string]spotColorType // Map of named ink-based colors + userUnderlineThickness float64 // A custom user underline thickness multiplier. +} + +type encType struct { + uv int + name string +} + +type encListType [256]encType + +type fontBoxType struct { + Xmin, Ymin, Xmax, Ymax int +} + +// Font flags for FontDescType.Flags as defined in the pdf specification. +const ( + // FontFlagFixedPitch is set if all glyphs have the same width (as + // opposed to proportional or variable-pitch fonts, which have + // different widths). + FontFlagFixedPitch = 1 << 0 + // FontFlagSerif is set if glyphs have serifs, which are short + // strokes drawn at an angle on the top and bottom of glyph stems. + // (Sans serif fonts do not have serifs.) + FontFlagSerif = 1 << 1 + // FontFlagSymbolic is set if font contains glyphs outside the + // Adobe standard Latin character set. This flag and the + // Nonsymbolic flag shall not both be set or both be clear. + FontFlagSymbolic = 1 << 2 + // FontFlagScript is set if glyphs resemble cursive handwriting. + FontFlagScript = 1 << 3 + // FontFlagNonsymbolic is set if font uses the Adobe standard + // Latin character set or a subset of it. + FontFlagNonsymbolic = 1 << 5 + // FontFlagItalic is set if glyphs have dominant vertical strokes + // that are slanted. + FontFlagItalic = 1 << 6 + // FontFlagAllCap is set if font contains no lowercase letters; + // typically used for display purposes, such as for titles or + // headlines. + FontFlagAllCap = 1 << 16 + // SmallCap is set if font contains both uppercase and lowercase + // letters. The uppercase letters are similar to those in the + // regular version of the same typeface family. The glyphs for the + // lowercase letters have the same shapes as the corresponding + // uppercase letters, but they are sized and their proportions + // adjusted so that they have the same size and stroke weight as + // lowercase glyphs in the same typeface family. + SmallCap = 1 << 18 + // ForceBold determines whether bold glyphs shall be painted with + // extra pixels even at very small text sizes by a conforming + // reader. If the ForceBold flag is set, features of bold glyphs + // may be thickened at small text sizes. + ForceBold = 1 << 18 +) + +// FontDescType (font descriptor) specifies metrics and other +// attributes of a font, as distinct from the metrics of individual +// glyphs (as defined in the pdf specification). +type FontDescType struct { + // The maximum height above the baseline reached by glyphs in this + // font (for example for "S"). The height of glyphs for accented + // characters shall be excluded. + Ascent int + // The maximum depth below the baseline reached by glyphs in this + // font. The value shall be a negative number. + Descent int + // The vertical coordinate of the top of flat capital letters, + // measured from the baseline (for example "H"). + CapHeight int + // A collection of flags defining various characteristics of the + // font. (See the FontFlag* constants.) + Flags int + // A rectangle, expressed in the glyph coordinate system, that + // shall specify the font bounding box. This should be the smallest + // rectangle enclosing the shape that would result if all of the + // glyphs of the font were placed with their origins coincident + // and then filled. + FontBBox fontBoxType + // The angle, expressed in degrees counterclockwise from the + // vertical, of the dominant vertical strokes of the font. (The + // 9-o’clock position is 90 degrees, and the 3-o’clock position + // is –90 degrees.) The value shall be negative for fonts that + // slope to the right, as almost all italic fonts do. + ItalicAngle int + // The thickness, measured horizontally, of the dominant vertical + // stems of glyphs in the font. + StemV int + // The width to use for character codes whose widths are not + // specified in a font dictionary’s Widths array. This shall have + // a predictable effect only if all such codes map to glyphs whose + // actual widths are the same as the value of the MissingWidth + // entry. (Default value: 0.) + MissingWidth int +} + +type fontDefType struct { + Tp string // "Core", "TrueType", ... + Name string // "Courier-Bold", ... + Desc FontDescType // Font descriptor + Up int // Underline position + Ut int // Underline thickness + Cw []int // Character width by ordinal + Enc string // "cp1252", ... + Diff string // Differences from reference encoding + File string // "Redressed.z" + Size1, Size2 int // Type1 values + OriginalSize int // Size of uncompressed font file + N int // Set by font loader + DiffN int // Position of diff in app array, set by font loader + i string // 1-based position in font list, set by font loader, not this program + utf8File *utf8FontFile // UTF-8 font + usedRunes map[int]int // Array of used runes +} + +// generateFontID generates a font Id from the font definition +func generateFontID(fdt fontDefType) (string, error) { + // file can be different if generated in different instance + fdt.File = "" + b, err := json.Marshal(&fdt) + return fmt.Sprintf("%x", sha1.Sum(b)), err +} + +type fontInfoType struct { + Data []byte + File string + OriginalSize int + FontName string + Bold bool + IsFixedPitch bool + UnderlineThickness int + UnderlinePosition int + Widths []int + Size1, Size2 uint32 + Desc FontDescType +} diff --git a/doc.go b/doc.go new file mode 100644 index 0000000..cb46a70 --- /dev/null +++ b/doc.go @@ -0,0 +1,291 @@ +/* +Package gofpdf implements a PDF document generator with high level +support for text, drawing and images. + + +Features + + +- UTF-8 support + +- Choice of measurement unit, page format and margins + +- Page header and footer management + +- Automatic page breaks, line breaks, and text justification + +- Inclusion of JPEG, PNG, GIF, TIFF and basic path-only SVG images + +- Colors, gradients and alpha channel transparency + +- Outline bookmarks + +- Internal and external links + +- TrueType, Type1 and encoding support + +- Page compression + +- Lines, Bézier curves, arcs, and ellipses + +- Rotation, scaling, skewing, translation, and mirroring + +- Clipping + +- Document protection + +- Layers + +- Templates + +- Barcodes + +- Charting facility + +- Import PDFs as templates + +gofpdf has no dependencies other than the Go standard library. All tests +pass on Linux, Mac and Windows platforms. + +gofpdf supports UTF-8 TrueType fonts and “right-to-left” languages. Note +that Chinese, Japanese, and Korean characters may not be included in +many general purpose fonts. For these languages, a specialized font (for +example, NotoSansSC for simplified Chinese) can be used. + +Also, support is provided to automatically translate UTF-8 runes to code +page encodings for languages that have fewer than 256 glyphs. + + +We Are Closed + +This repository will not be maintained, at least for some unknown +duration. But it is hoped that gofpdf has a bright future in the open +source world. Due to Go’s promise of compatibility, gofpdf should +continue to function without modification for a longer time than would +be the case with many other languages. + +Forks should be based on the last viable commit. Tools such as +active-forks can be used to select a fork that looks promising for your +needs. If a particular fork looks like it has taken the lead in +attracting followers, this README will be updated to point people in +that direction. + +The efforts of all contributors to this project have been deeply +appreciated. Best wishes to all of you. + + +Installation + +To install the package on your system, run + + go get github.com/jung-kurt/gofpdf + +Later, to receive updates, run + + go get -u -v github.com/jung-kurt/gofpdf/... + + +Quick Start + +The following Go code generates a simple PDF file. + + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + pdf.SetFont("Arial", "B", 16) + pdf.Cell(40, 10, "Hello, world") + err := pdf.OutputFileAndClose("hello.pdf") + +See the functions in the fpdf_test.go file (shown as examples in this +documentation) for more advanced PDF examples. + + +Errors + +If an error occurs in an Fpdf method, an internal error field is set. +After this occurs, Fpdf method calls typically return without performing +any operations and the error state is retained. This error management +scheme facilitates PDF generation since individual method calls do not +need to be examined for failure; it is generally sufficient to wait +until after Output() is called. For the same reason, if an error occurs +in the calling application during PDF generation, it may be desirable +for the application to transfer the error to the Fpdf instance by +calling the SetError() method or the SetErrorf() method. At any time +during the life cycle of the Fpdf instance, the error state can be +determined with a call to Ok() or Err(). The error itself can be +retrieved with a call to Error(). + + +Conversion Notes + +This package is a relatively straightforward translation from the +original FPDF library written in PHP (despite the caveat in the +introduction to Effective Go). The API names have been retained even +though the Go idiom would suggest otherwise (for example, pdf.GetX() is +used rather than simply pdf.X()). The similarity of the two libraries +makes the original FPDF website a good source of information. It +includes a forum and FAQ. + +However, some internal changes have been made. Page content is built up +using buffers (of type bytes.Buffer) rather than repeated string +concatenation. Errors are handled as explained above rather than +panicking. Output is generated through an interface of type io.Writer or +io.WriteCloser. A number of the original PHP methods behave differently +based on the type of the arguments that are passed to them; in these +cases additional methods have been exported to provide similar +functionality. Font definition files are produced in JSON rather than +PHP. + + +Example PDFs + +A side effect of running go test ./... is the production of a number of +example PDFs. These can be found in the gofpdf/pdf directory after the +tests complete. + +Please note that these examples run in the context of a test. In order +run an example as a standalone application, 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(). + +You should use AddUTF8Font() or AddUTF8FontFromBytes() to add a TrueType +UTF-8 encoded font. Use RTL() and LTR() methods switch between +“right-to-left” and “left-to-right” mode. + +In order to use a different non-UTF-8 TrueType or Type1 font, you will +need to generate a font definition file and, if the font will be +embedded into PDFs, a compressed version of the font file. This is done +by calling the MakeFont function or using the included makefont command +line utility. To create the utility, cd into the makefont subdirectory +and run “go build”. This will produce a standalone executable named +makefont. Select the appropriate encoding file from the font +subdirectory and run the command as in the following example. + + ./makefont --embed --enc=../font/cp1252.map --dst=../font ../font/calligra.ttf + +In your PDF generation code, call AddFont() to load the font and, as +with the standard fonts, SetFont() to begin using it. Most examples, +including the package example, demonstrate this method. Good sources of +free, open-source fonts include Google Fonts and DejaVu Fonts. + + +Related Packages + +The draw2d package is a two dimensional vector graphics library that can +generate output in different forms. It uses gofpdf for its document +production mode. + + +Contributing Changes + +gofpdf is a global community effort and you are invited to make it even +better. If you have implemented a new feature or corrected a problem, +please consider contributing your change to the project. A contribution +that does not directly pertain to the core functionality of gofpdf +should be placed in its own directory directly beneath the contrib +directory. + +Here are guidelines for making submissions. Your change should + + +- be compatible with the MIT License + +- be properly documented + +- be formatted with go fmt + +- include an example in fpdf_test.go if appropriate + +- conform to the standards of golint and go vet, that is, golint . and +go vet . should not generate any warnings + +- not diminish test coverage + +Pull requests are the preferred means of accepting your changes. + + +License + +gofpdf is released under the MIT License. It is copyrighted by Kurt Jung +and the contributors acknowledged below. + + +Acknowledgments + +This 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. Benoit KUGLER contributed +support for rectangles with corners of unequal radius, modification +times, and for file attachments and annotations. + + +Roadmap + + +- Remove all legacy code page font support; use UTF-8 exclusively + +- Improve test coverage as reported by the coverage tool. +*/ +package gofpdf diff --git a/doc/document.md b/doc/document.md new file mode 100644 index 0000000..145fc16 --- /dev/null +++ b/doc/document.md @@ -0,0 +1,288 @@ +# GoFPDF document generator + +[![No Maintenance Intended][badge-no-maintain]][unmaintained] +[![MIT licensed][badge-mit]][license] +[![Report][badge-report]][report] +[![GoDoc][badge-doc]][godoc] + +![][logo] + +Package gofpdf implements a PDF document generator with high level support for +text, drawing and images. + +## Features + +* UTF-8 support +* Choice of measurement unit, page format and margins +* Page header and footer management +* Automatic page breaks, line breaks, and text justification +* Inclusion of JPEG, PNG, GIF, TIFF and basic path-only SVG images +* Colors, gradients and alpha channel transparency +* Outline bookmarks +* Internal and external links +* TrueType, Type1 and encoding support +* Page compression +* Lines, Bézier curves, arcs, and ellipses +* Rotation, scaling, skewing, translation, and mirroring +* Clipping +* Document protection +* Layers +* Templates +* Barcodes +* Charting facility +* Import PDFs as templates + +gofpdf has no dependencies other than the Go standard library. All tests pass +on Linux, Mac and Windows platforms. + +gofpdf supports UTF-8 TrueType fonts and "right-to-left" languages. Note that +Chinese, Japanese, and Korean characters may not be included in many general +purpose fonts. For these languages, a specialized font (for example, +[NotoSansSC][noto] 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. + +## We Are Closed + +This repository will not be maintained, at least for some unknown duration. But +it is hoped that gofpdf has a bright future in the open source world. Due to +Go's promise of compatibility, gofpdf should continue to function without +modification for a longer time than would be the case with many other +languages. + +Forks should be based on the [last viable commit][last-commit]. Tools such as +[active-forks][gofpdf-fork] can be used to select a fork that looks promising +for your needs. If a particular fork looks like it has taken the lead in +attracting followers, this README will be updated to point people in that +direction. + +The efforts of all contributors to this project have been deeply appreciated. +Best wishes to all of you. + +## Installation + +To install the package on your system, run + +```shell +go get github.com/jung-kurt/gofpdf +``` + +Later, to receive updates, run + +```shell +go get -u -v github.com/jung-kurt/gofpdf/... +``` + +## Quick Start + +The following Go code generates a simple PDF file. + +```go +pdf := gofpdf.New("P", "mm", "A4", "") +pdf.AddPage() +pdf.SetFont("Arial", "B", 16) +pdf.Cell(40, 10, "Hello, world") +err := pdf.OutputFileAndClose("hello.pdf") +``` + +See the functions in the [fpdf_test.go][fpdf-test] file (shown as examples in +this documentation) for more advanced PDF examples. + +## Errors + +If an error occurs in an Fpdf method, an internal error field is set. After +this occurs, Fpdf method calls typically return without performing any +operations and the error state is retained. This error management scheme +facilitates PDF generation since individual method calls do not need to be +examined for failure; it is generally sufficient to wait until after `Output()` +is called. For the same reason, if an error occurs in the calling application +during PDF generation, it may be desirable for the application to transfer the +error to the Fpdf instance by calling the `SetError()` method or the +`SetErrorf()` method. At any time during the life cycle of the Fpdf instance, +the error state can be determined with a call to `Ok()` or `Err()`. The error +itself can be retrieved with a call to `Error()`. + +## Conversion Notes + +This package is a relatively straightforward translation from the original +[FPDF][fpdf-site] library written in PHP (despite the caveat in the +introduction to [Effective Go][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][fpdf-test] for some helper routines, for example +`exampleFilename()` and `summary()`. + +Example PDFs can be compared with reference copies in order to verify that they +have been generated as expected. This comparison will be performed if a PDF +with the same name as the example PDF is placed in the gofpdf/pdf/reference +directory and if the third argument to `ComparePDFFiles()` in +internal/example/example.go is true. (By default it is false.) The routine that +summarizes an example will look for this file and, if found, will call +`ComparePDFFiles()` to check the example PDF for equality with its reference PDF. +If differences exist between the two files they will be printed to standard +output and the test will fail. If the reference file is missing, the comparison +is considered to succeed. In order to successfully compare two PDFs, the +placement of internal resources must be consistent and the internal creation +timestamps must be the same. To do this, the methods `SetCatalogSort()` and +`SetCreationDate()` need to be called for both files. This is done automatically +for all examples. + +## Nonstandard Fonts + +Nothing special is required to use the standard PDF fonts (courier, helvetica, +times, zapfdingbats) in your documents other than calling `SetFont()`. + +You should use `AddUTF8Font()` or `AddUTF8FontFromBytes()` to add a TrueType +UTF-8 encoded font. Use `RTL()` and `LTR()` methods switch between +"right-to-left" and "left-to-right" mode. + +In order to use a different non-UTF-8 TrueType or Type1 font, you will need to +generate a font definition file and, if the font will be embedded into PDFs, a +compressed version of the font file. This is done by calling the MakeFont +function or using the included makefont command line utility. To create the +utility, cd into the makefont subdirectory and run "go build". This will +produce a standalone executable named makefont. Select the appropriate encoding +file from the font subdirectory and run the command as in the following +example. + +```shell +./makefont --embed --enc=../font/cp1252.map --dst=../font ../font/calligra.ttf +``` + +In your PDF generation code, call `AddFont()` to load the font and, as with the +standard fonts, SetFont() to begin using it. Most examples, including the +package example, demonstrate this method. Good sources of free, open-source +fonts include [Google Fonts][gfont] and [DejaVu Fonts][dfont]. + +## Related Packages + +The [draw2d][draw2d-site] package is a two dimensional vector graphics library that +can generate output in different forms. It uses gofpdf for its document +production mode. + +## Contributing Changes + +gofpdf is a global community effort and you are invited to make it even better. +If you have implemented a new feature or corrected a problem, please consider +contributing your change to the project. A contribution that does not directly +pertain to the core functionality of gofpdf should be placed in its own +directory directly beneath the `contrib` directory. + +Here are guidelines for making submissions. Your change should + +* be compatible with the MIT License +* be properly documented +* be formatted with `go fmt` +* include an example in [fpdf_test.go][test] if appropriate +* conform to the standards of [golint][lint] and +[go vet][vet], that is, `golint .` and +`go vet .` should not generate any warnings +* not diminish [test coverage][coverage] + +[Pull requests][pr] are the preferred means of accepting your changes. + +## License + +gofpdf is released under the MIT License. It is copyrighted by Kurt Jung and +the contributors acknowledged below. + +## Acknowledgments + +This package's code and documentation are closely derived from the [FPDF][fpdf-site] +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. Benoit KUGLER contributed +support for rectangles with corners of unequal radius, modification times, and +for file attachments and annotations. + +## Roadmap + +* Remove all legacy code page font support; use UTF-8 exclusively +* Improve test coverage as reported by the coverage tool. + +[badge-author]: https://img.shields.io/badge/author-Kurt_Jung-blue.svg +[badge-doc]: https://img.shields.io/badge/godoc-GoFPDF-blue.svg +[badge-github]: https://img.shields.io/badge/project-Git_Hub-blue.svg +[badge-mit]: https://img.shields.io/badge/license-MIT-blue.svg +[badge-no-maintain]: http://unmaintained.tech/badge.svg +[badge-report]: https://goreportcard.com/badge/github.com/jung-kurt/gofpdf +[badge-status]: https://travis-ci.org/jung-kurt/gofpdf.svg?branch=master +[coverage]: https://blog.golang.org/cover +[dfont]: http://dejavu-fonts.org/ +[draw2d-site]: https://github.com/llgcode/draw2d +[effective-go]: https://golang.org/doc/effective_go.html +[fpdf-site]: http://www.fpdf.org/ +[fpdf-test]: https://github.com/jung-kurt/gofpdf/blob/master/fpdf_test.go +[gfont]: https://fonts.google.com/ +[github]: https://github.com/jung-kurt/gofpdf +[godoc]: https://godoc.org/github.com/jung-kurt/gofpdf +[gofpdf-fork]: https://techgaun.github.io/active-forks/index.html#jung-kurt/gofpdf +[issue109]: https://github.com/jung-kurt/gofpdf/issues/109 +[jung]: https://github.com/jung-kurt/ +[last-commit]: https://github.com/jung-kurt/gofpdf/commit/603f56990463f011cb1dbb64ef7f872c1adc009a +[license]: https://raw.githubusercontent.com/jung-kurt/gofpdf/master/LICENSE +[lint]: https://github.com/golang/lint +[logo]: https://github.com/jung-kurt/gofpdf/raw/master/image/logo_gofpdf.jpg?raw=true +[noto]: https://github.com/jsntn/webfonts/blob/master/NotoSansSC-Regular.ttf +[pr]: https://help.github.com/articles/using-pull-requests/ +[report]: https://goreportcard.com/report/github.com/jung-kurt/gofpdf +[status]: https://travis-ci.org/jung-kurt/gofpdf +[test]: https://github.com/jung-kurt/gofpdf/blob/master/fpdf_test.go +[unmaintained]: http://unmaintained.tech/ +[vet]: https://golang.org/cmd/vet/ diff --git a/doc/go.awk b/doc/go.awk new file mode 100644 index 0000000..bcd4a7c --- /dev/null +++ b/doc/go.awk @@ -0,0 +1,13 @@ +BEGIN { show = 0 ; print "/*" } + +/^\-/ { trim = 1 ; print "" } + +/^Package/ { show = 1 } + +!NF { trim = 0 } + +trim { sub("^ +", "", $0) } + +show { print $0 } + +END { print "*/\npackage " package_name } diff --git a/doc/html.txt b/doc/html.txt new file mode 100644 index 0000000..7a89bb1 --- /dev/null +++ b/doc/html.txt @@ -0,0 +1,68 @@ + + + + + + + + GoFPDF Document Generator + + + + +$body$ + + + diff --git a/embedded.go b/embedded.go new file mode 100644 index 0000000..1d947b0 --- /dev/null +++ b/embedded.go @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2014 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf + +// Embedded standard fonts + +import ( + "strings" +) + +var embeddedFontList = map[string]string{ + "courierBI": `{"Tp":"Core","Name":"Courier-BoldOblique","Up":-100,"Ut":50,"I":256,"Cw":[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600]}`, + "courierB": `{"Tp":"Core","Name":"Courier-Bold","Up":-100,"Ut":50,"I":256,"Cw":[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600]}`, + "courierI": `{"Tp":"Core","Name":"Courier-Oblique","Up":-100,"Ut":50,"I":256,"Cw":[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600]}`, + "courier": `{"Tp":"Core","Name":"Courier","Up":-100,"Ut":50,"I":256,"Cw":[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600]}`, + "helveticaBI": `{"Tp":"Core","Name":"Helvetica-BoldOblique","Up":-100,"Ut":50,"Cw":[278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,333,474,556,556,889,722,238,333,333,389,584,278,333,278,278,556,556,556,556,556,556,556,556,556,556,333,333,584,584,584,611,975,722,722,722,722,667,611,778,722,278,556,722,611,833,722,778,667,778,722,667,611,722,667,944,667,667,611,333,278,333,584,556,333,556,611,556,611,556,333,611,611,278,278,556,278,889,611,611,611,611,389,556,333,611,556,778,556,556,500,389,280,389,584,350,556,350,278,556,500,1000,556,556,333,1000,667,333,1000,350,611,350,350,278,278,500,500,350,556,1000,333,1000,556,333,944,350,500,667,278,333,556,556,556,556,280,556,333,737,370,556,584,333,737,333,400,584,333,333,333,611,556,278,333,333,365,556,834,834,834,611,722,722,722,722,722,722,1000,722,667,667,667,667,278,278,278,278,722,722,778,778,778,778,778,584,778,722,722,722,722,667,667,611,556,556,556,556,556,556,889,556,556,556,556,556,278,278,278,278,611,611,611,611,611,611,611,584,611,611,611,611,611,556,611,556]}`, + "helveticaB": `{"Tp":"Core","Name":"Helvetica-Bold","Up":-100,"Ut":50,"Cw":[278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,333,474,556,556,889,722,238,333,333,389,584,278,333,278,278,556,556,556,556,556,556,556,556,556,556,333,333,584,584,584,611,975,722,722,722,722,667,611,778,722,278,556,722,611,833,722,778,667,778,722,667,611,722,667,944,667,667,611,333,278,333,584,556,333,556,611,556,611,556,333,611,611,278,278,556,278,889,611,611,611,611,389,556,333,611,556,778,556,556,500,389,280,389,584,350,556,350,278,556,500,1000,556,556,333,1000,667,333,1000,350,611,350,350,278,278,500,500,350,556,1000,333,1000,556,333,944,350,500,667,278,333,556,556,556,556,280,556,333,737,370,556,584,333,737,333,400,584,333,333,333,611,556,278,333,333,365,556,834,834,834,611,722,722,722,722,722,722,1000,722,667,667,667,667,278,278,278,278,722,722,778,778,778,778,778,584,778,722,722,722,722,667,667,611,556,556,556,556,556,556,889,556,556,556,556,556,278,278,278,278,611,611,611,611,611,611,611,584,611,611,611,611,611,556,611,556]}`, + "helveticaI": `{"Tp":"Core","Name":"Helvetica-Oblique","Up":-100,"Ut":50,"Cw":[278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,355,556,556,889,667,191,333,333,389,584,278,333,278,278,556,556,556,556,556,556,556,556,556,556,278,278,584,584,584,556,1015,667,667,722,722,667,611,778,722,278,500,667,556,833,722,778,667,778,722,667,611,722,667,944,667,667,611,278,278,278,469,556,333,556,556,500,556,556,278,556,556,222,222,500,222,833,556,556,556,556,333,500,278,556,500,722,500,500,500,334,260,334,584,350,556,350,222,556,333,1000,556,556,333,1000,667,333,1000,350,611,350,350,222,222,333,333,350,556,1000,333,1000,500,333,944,350,500,667,278,333,556,556,556,556,260,556,333,737,370,556,584,333,737,333,400,584,333,333,333,556,537,278,333,333,365,556,834,834,834,611,667,667,667,667,667,667,1000,722,667,667,667,667,278,278,278,278,722,722,778,778,778,778,778,584,778,722,722,722,722,667,667,611,556,556,556,556,556,556,889,500,556,556,556,556,278,278,278,278,556,556,556,556,556,556,556,584,611,556,556,556,556,500,556,500]}`, + "helvetica": `{"Tp":"Core","Name":"Helvetica","Up":-100,"Ut":50,"Cw":[278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,355,556,556,889,667,191,333,333,389,584,278,333,278,278,556,556,556,556,556,556,556,556,556,556,278,278,584,584,584,556,1015,667,667,722,722,667,611,778,722,278,500,667,556,833,722,778,667,778,722,667,611,722,667,944,667,667,611,278,278,278,469,556,333,556,556,500,556,556,278,556,556,222,222,500,222,833,556,556,556,556,333,500,278,556,500,722,500,500,500,334,260,334,584,350,556,350,222,556,333,1000,556,556,333,1000,667,333,1000,350,611,350,350,222,222,333,333,350,556,1000,333,1000,500,333,944,350,500,667,278,333,556,556,556,556,260,556,333,737,370,556,584,333,737,333,400,584,333,333,333,556,537,278,333,333,365,556,834,834,834,611,667,667,667,667,667,667,1000,722,667,667,667,667,278,278,278,278,722,722,778,778,778,778,778,584,778,722,722,722,722,667,667,611,556,556,556,556,556,556,889,500,556,556,556,556,278,278,278,278,556,556,556,556,556,556,556,584,611,556,556,556,556,500,556,500]}`, + "timesBI": `{"Tp":"Core","Name":"Times-BoldItalic","Up":-100,"Ut":50,"Cw":[250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,389,555,500,500,833,778,278,333,333,500,570,250,333,250,278,500,500,500,500,500,500,500,500,500,500,333,333,570,570,570,500,832,667,667,667,722,667,667,722,778,389,500,667,611,889,722,722,611,722,667,556,611,722,667,889,667,611,611,333,278,333,570,500,333,500,500,444,500,444,333,500,556,278,278,500,278,778,556,500,500,500,389,389,278,556,444,667,500,444,389,348,220,348,570,350,500,350,333,500,500,1000,500,500,333,1000,556,333,944,350,611,350,350,333,333,500,500,350,500,1000,333,1000,389,333,722,350,389,611,250,389,500,500,500,500,220,500,333,747,266,500,606,333,747,333,400,570,300,300,333,576,500,250,333,300,300,500,750,750,750,500,667,667,667,667,667,667,944,667,667,667,667,667,389,389,389,389,722,722,722,722,722,722,722,570,722,722,722,722,722,611,611,500,500,500,500,500,500,500,722,444,444,444,444,444,278,278,278,278,500,556,500,500,500,500,500,570,500,556,556,556,556,444,500,444]}`, + "timesB": `{"Tp":"Core","Name":"Times-Bold","Up":-100,"Ut":50,"Cw":[250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,333,555,500,500,1000,833,278,333,333,500,570,250,333,250,278,500,500,500,500,500,500,500,500,500,500,333,333,570,570,570,500,930,722,667,722,722,667,611,778,778,389,500,778,667,944,722,778,611,778,722,556,667,722,722,1000,722,722,667,333,278,333,581,500,333,500,556,444,556,444,333,500,556,278,333,556,278,833,556,500,556,556,444,389,333,556,500,722,500,500,444,394,220,394,520,350,500,350,333,500,500,1000,500,500,333,1000,556,333,1000,350,667,350,350,333,333,500,500,350,500,1000,333,1000,389,333,722,350,444,722,250,333,500,500,500,500,220,500,333,747,300,500,570,333,747,333,400,570,300,300,333,556,540,250,333,300,330,500,750,750,750,500,722,722,722,722,722,722,1000,722,667,667,667,667,389,389,389,389,722,722,778,778,778,778,778,570,778,722,722,722,722,722,611,556,500,500,500,500,500,500,722,444,444,444,444,444,278,278,278,278,500,556,500,500,500,500,500,570,500,556,556,556,556,500,556,500]}`, + "timesI": `{"Tp":"Core","Name":"Times-Italic","Up":-100,"Ut":50,"Cw":[250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,333,420,500,500,833,778,214,333,333,500,675,250,333,250,278,500,500,500,500,500,500,500,500,500,500,333,333,675,675,675,500,920,611,611,667,722,611,611,722,722,333,444,667,556,833,667,722,611,722,611,500,556,722,611,833,611,556,556,389,278,389,422,500,333,500,500,444,500,444,278,500,500,278,278,444,278,722,500,500,500,500,389,389,278,500,444,667,444,444,389,400,275,400,541,350,500,350,333,500,556,889,500,500,333,1000,500,333,944,350,556,350,350,333,333,556,556,350,500,889,333,980,389,333,667,350,389,556,250,389,500,500,500,500,275,500,333,760,276,500,675,333,760,333,400,675,300,300,333,500,523,250,333,300,310,500,750,750,750,500,611,611,611,611,611,611,889,667,611,611,611,611,333,333,333,333,722,667,722,722,722,722,722,675,722,722,722,722,722,556,611,500,500,500,500,500,500,500,667,444,444,444,444,444,278,278,278,278,500,500,500,500,500,500,500,675,500,500,500,500,500,444,500,444]}`, + "times": `{"Tp":"Core","Name":"Times-Roman","Up":-100,"Ut":50,"Cw":[250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,333,408,500,500,833,778,180,333,333,500,564,250,333,250,278,500,500,500,500,500,500,500,500,500,500,278,278,564,564,564,444,921,722,667,667,722,611,556,722,722,333,389,722,611,889,722,722,556,722,667,556,611,722,722,944,722,722,611,333,278,333,469,500,333,444,500,444,500,444,333,500,500,278,278,500,278,778,500,500,500,500,333,389,278,500,500,722,500,500,444,480,200,480,541,350,500,350,333,500,444,1000,500,500,333,1000,556,333,889,350,611,350,350,333,333,444,444,350,500,1000,333,980,389,333,722,350,444,722,250,333,500,500,500,500,200,500,333,760,276,500,564,333,760,333,400,564,300,300,333,500,453,250,333,300,310,500,750,750,750,444,722,722,722,722,722,722,889,667,611,611,611,611,333,333,333,333,722,722,722,722,722,722,722,564,722,722,722,722,722,722,556,500,444,444,444,444,444,444,667,444,444,444,444,444,278,278,278,278,500,500,500,500,500,500,500,564,500,500,500,500,500,500,500,500]}`, + "zapfdingbats": `{"Tp":"Core","Name":"ZapfDingbats","Up":-100,"Ut":50,"Cw":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,278,974,961,974,980,719,789,790,791,690,960,939,549,855,911,933,911,945,974,755,846,762,761,571,677,763,760,759,754,494,552,537,577,692,786,788,788,790,793,794,816,823,789,841,823,833,816,831,923,744,723,749,790,792,695,776,768,792,759,707,708,682,701,826,815,789,789,707,687,696,689,786,787,713,791,785,791,873,761,762,762,759,759,892,892,788,784,438,138,277,415,392,392,668,668,0,390,390,317,317,276,276,509,509,410,410,234,234,334,334,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,732,544,544,910,667,760,760,776,595,694,626,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,894,838,1016,458,748,924,748,918,927,928,928,834,873,828,924,924,917,930,931,463,883,836,836,867,867,696,696,874,0,874,760,946,771,865,771,888,967,888,831,873,927,970,918,0]}`, +} + +func (f *Fpdf) coreFontReader(familyStr, styleStr string) (r *strings.Reader) { + key := familyStr + styleStr + str, ok := embeddedFontList[key] + if ok { + r = strings.NewReader(str) + } else { + f.SetErrorf("could not locate \"%s\" among embedded core font definition files", key) + } + return +} + +var embeddedMapList = map[string]string{ + "cp1250": ` +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!89 U+2030 perthousand +!8A U+0160 Scaron +!8B U+2039 guilsinglleft +!8C U+015A Sacute +!8D U+0164 Tcaron +!8E U+017D Zcaron +!8F U+0179 Zacute +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9A U+0161 scaron +!9B U+203A guilsinglright +!9C U+015B sacute +!9D U+0165 tcaron +!9E U+017E zcaron +!9F U+017A zacute +!A0 U+00A0 space +!A1 U+02C7 caron +!A2 U+02D8 breve +!A3 U+0141 Lslash +!A4 U+00A4 currency +!A5 U+0104 Aogonek +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+015E Scedilla +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+017B Zdotaccent +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+02DB ogonek +!B3 U+0142 lslash +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+0105 aogonek +!BA U+015F scedilla +!BB U+00BB guillemotright +!BC U+013D Lcaron +!BD U+02DD hungarumlaut +!BE U+013E lcaron +!BF U+017C zdotaccent +!C0 U+0154 Racute +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+0102 Abreve +!C4 U+00C4 Adieresis +!C5 U+0139 Lacute +!C6 U+0106 Cacute +!C7 U+00C7 Ccedilla +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0118 Eogonek +!CB U+00CB Edieresis +!CC U+011A Ecaron +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+010E Dcaron +!D0 U+0110 Dcroat +!D1 U+0143 Nacute +!D2 U+0147 Ncaron +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+0150 Ohungarumlaut +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+0158 Rcaron +!D9 U+016E Uring +!DA U+00DA Uacute +!DB U+0170 Uhungarumlaut +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+0162 Tcommaaccent +!DF U+00DF germandbls +!E0 U+0155 racute +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+0103 abreve +!E4 U+00E4 adieresis +!E5 U+013A lacute +!E6 U+0107 cacute +!E7 U+00E7 ccedilla +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+0119 eogonek +!EB U+00EB edieresis +!EC U+011B ecaron +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+010F dcaron +!F0 U+0111 dcroat +!F1 U+0144 nacute +!F2 U+0148 ncaron +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+0151 ohungarumlaut +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+0159 rcaron +!F9 U+016F uring +!FA U+00FA uacute +!FB U+0171 uhungarumlaut +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+0163 tcommaaccent +!FF U+02D9 dotaccent + `, + "cp1252": ` +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+02C6 circumflex +!89 U+2030 perthousand +!8A U+0160 Scaron +!8B U+2039 guilsinglleft +!8C U+0152 OE +!8E U+017D Zcaron +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!98 U+02DC tilde +!99 U+2122 trademark +!9A U+0161 scaron +!9B U+203A guilsinglright +!9C U+0153 oe +!9E U+017E zcaron +!9F U+0178 Ydieresis +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+00D0 Eth +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+00DE Thorn +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+00F0 eth +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+00FE thorn +!FF U+00FF ydieresis + `, +} diff --git a/font.go b/font.go new file mode 100644 index 0000000..29417bb --- /dev/null +++ b/font.go @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2013 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf + +// Utility to generate font definition files + +// Version: 1.2 +// Date: 2011-06-18 +// Author: Olivier PLATHEY +// Port to Go: Kurt Jung, 2013-07-15 + +import ( + "bufio" + "compress/zlib" + "encoding/binary" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strconv" + "strings" +) + +func baseNoExt(fileStr string) string { + str := filepath.Base(fileStr) + extLen := len(filepath.Ext(str)) + if extLen > 0 { + str = str[:len(str)-extLen] + } + return str +} + +func loadMap(encodingFileStr string) (encList encListType, err error) { + // printf("Encoding file string [%s]\n", encodingFileStr) + var f *os.File + // f, err = os.Open(encodingFilepath(encodingFileStr)) + f, err = os.Open(encodingFileStr) + if err == nil { + defer f.Close() + for j := range encList { + encList[j].uv = -1 + encList[j].name = ".notdef" + } + scanner := bufio.NewScanner(f) + var enc encType + var pos int + for scanner.Scan() { + // "!3F U+003F question" + _, err = fmt.Sscanf(scanner.Text(), "!%x U+%x %s", &pos, &enc.uv, &enc.name) + if err == nil { + if pos < 256 { + encList[pos] = enc + } else { + err = fmt.Errorf("map position 0x%2X exceeds 0xFF", pos) + return + } + } else { + return + } + } + if err = scanner.Err(); err != nil { + return + } + } + return +} + +// getInfoFromTrueType returns information from a TrueType font +func getInfoFromTrueType(fileStr string, msgWriter io.Writer, embed bool, encList encListType) (info fontInfoType, err error) { + info.Widths = make([]int, 256) + var ttf TtfType + ttf, err = TtfParse(fileStr) + if err != nil { + return + } + if embed { + if !ttf.Embeddable { + err = fmt.Errorf("font license does not allow embedding") + return + } + info.Data, err = ioutil.ReadFile(fileStr) + if err != nil { + return + } + info.OriginalSize = len(info.Data) + } + k := 1000.0 / float64(ttf.UnitsPerEm) + info.FontName = ttf.PostScriptName + info.Bold = ttf.Bold + info.Desc.ItalicAngle = int(ttf.ItalicAngle) + info.IsFixedPitch = ttf.IsFixedPitch + info.Desc.Ascent = round(k * float64(ttf.TypoAscender)) + info.Desc.Descent = round(k * float64(ttf.TypoDescender)) + info.UnderlineThickness = round(k * float64(ttf.UnderlineThickness)) + info.UnderlinePosition = round(k * float64(ttf.UnderlinePosition)) + info.Desc.FontBBox = fontBoxType{ + round(k * float64(ttf.Xmin)), + round(k * float64(ttf.Ymin)), + round(k * float64(ttf.Xmax)), + round(k * float64(ttf.Ymax)), + } + // printf("FontBBox\n") + // dump(info.Desc.FontBBox) + info.Desc.CapHeight = round(k * float64(ttf.CapHeight)) + info.Desc.MissingWidth = round(k * float64(ttf.Widths[0])) + var wd int + for j := 0; j < len(info.Widths); j++ { + wd = info.Desc.MissingWidth + if encList[j].name != ".notdef" { + uv := encList[j].uv + pos, ok := ttf.Chars[uint16(uv)] + if ok { + wd = round(k * float64(ttf.Widths[pos])) + } else { + fmt.Fprintf(msgWriter, "Character %s is missing\n", encList[j].name) + } + } + info.Widths[j] = wd + } + // printf("getInfoFromTrueType/FontBBox\n") + // dump(info.Desc.FontBBox) + return +} + +type segmentType struct { + marker uint8 + tp uint8 + size uint32 + data []byte +} + +func segmentRead(r io.Reader) (s segmentType, err error) { + if err = binary.Read(r, binary.LittleEndian, &s.marker); err != nil { + return + } + if s.marker != 128 { + err = fmt.Errorf("font file is not a valid binary Type1") + return + } + if err = binary.Read(r, binary.LittleEndian, &s.tp); err != nil { + return + } + if err = binary.Read(r, binary.LittleEndian, &s.size); err != nil { + return + } + s.data = make([]byte, s.size) + _, err = r.Read(s.data) + return +} + +// -rw-r--r-- 1 root root 9532 2010-04-22 11:27 /usr/share/fonts/type1/mathml/Symbol.afm +// -rw-r--r-- 1 root root 37744 2010-04-22 11:27 /usr/share/fonts/type1/mathml/Symbol.pfb + +// getInfoFromType1 return information from a Type1 font +func getInfoFromType1(fileStr string, msgWriter io.Writer, embed bool, encList encListType) (info fontInfoType, err error) { + info.Widths = make([]int, 256) + if embed { + var f *os.File + f, err = os.Open(fileStr) + if err != nil { + return + } + defer f.Close() + // Read first segment + var s1, s2 segmentType + s1, err = segmentRead(f) + if err != nil { + return + } + s2, err = segmentRead(f) + if err != nil { + return + } + info.Data = s1.data + info.Data = append(info.Data, s2.data...) + info.Size1 = s1.size + info.Size2 = s2.size + } + afmFileStr := fileStr[0:len(fileStr)-3] + "afm" + size, ok := fileSize(afmFileStr) + if !ok { + err = fmt.Errorf("font file (ATM) %s not found", afmFileStr) + return + } else if size == 0 { + err = fmt.Errorf("font file (AFM) %s empty or not readable", afmFileStr) + return + } + var f *os.File + f, err = os.Open(afmFileStr) + if err != nil { + return + } + defer f.Close() + scanner := bufio.NewScanner(f) + var fields []string + var wd int + var wt, name string + wdMap := make(map[string]int) + for scanner.Scan() { + fields = strings.Fields(strings.TrimSpace(scanner.Text())) + // Comment Generated by FontForge 20080203 + // FontName Symbol + // C 32 ; WX 250 ; N space ; B 0 0 0 0 ; + if len(fields) >= 2 { + switch fields[0] { + case "C": + if wd, err = strconv.Atoi(fields[4]); err == nil { + name = fields[7] + wdMap[name] = wd + } + case "FontName": + info.FontName = fields[1] + case "Weight": + wt = strings.ToLower(fields[1]) + case "ItalicAngle": + info.Desc.ItalicAngle, err = strconv.Atoi(fields[1]) + case "Ascender": + info.Desc.Ascent, err = strconv.Atoi(fields[1]) + case "Descender": + info.Desc.Descent, err = strconv.Atoi(fields[1]) + case "UnderlineThickness": + info.UnderlineThickness, err = strconv.Atoi(fields[1]) + case "UnderlinePosition": + info.UnderlinePosition, err = strconv.Atoi(fields[1]) + case "IsFixedPitch": + info.IsFixedPitch = fields[1] == "true" + case "FontBBox": + if info.Desc.FontBBox.Xmin, err = strconv.Atoi(fields[1]); err == nil { + if info.Desc.FontBBox.Ymin, err = strconv.Atoi(fields[2]); err == nil { + if info.Desc.FontBBox.Xmax, err = strconv.Atoi(fields[3]); err == nil { + info.Desc.FontBBox.Ymax, err = strconv.Atoi(fields[4]) + } + } + } + case "CapHeight": + info.Desc.CapHeight, err = strconv.Atoi(fields[1]) + case "StdVW": + info.Desc.StemV, err = strconv.Atoi(fields[1]) + } + } + if err != nil { + return + } + } + if err = scanner.Err(); err != nil { + return + } + if info.FontName == "" { + err = fmt.Errorf("the field FontName missing in AFM file %s", afmFileStr) + return + } + info.Bold = wt == "bold" || wt == "black" + var missingWd int + missingWd, ok = wdMap[".notdef"] + if ok { + info.Desc.MissingWidth = missingWd + } + for j := 0; j < len(info.Widths); j++ { + info.Widths[j] = info.Desc.MissingWidth + } + for j := 0; j < len(info.Widths); j++ { + name = encList[j].name + if name != ".notdef" { + wd, ok = wdMap[name] + if ok { + info.Widths[j] = wd + } else { + fmt.Fprintf(msgWriter, "Character %s is missing\n", name) + } + } + } + // printf("getInfoFromType1/FontBBox\n") + // dump(info.Desc.FontBBox) + return +} + +func makeFontDescriptor(info *fontInfoType) { + if info.Desc.CapHeight == 0 { + info.Desc.CapHeight = info.Desc.Ascent + } + info.Desc.Flags = 1 << 5 + if info.IsFixedPitch { + info.Desc.Flags |= 1 + } + if info.Desc.ItalicAngle != 0 { + info.Desc.Flags |= 1 << 6 + } + if info.Desc.StemV == 0 { + if info.Bold { + info.Desc.StemV = 120 + } else { + info.Desc.StemV = 70 + } + } + // printf("makeFontDescriptor/FontBBox\n") + // dump(info.Desc.FontBBox) +} + +// makeFontEncoding builds differences from reference encoding +func makeFontEncoding(encList encListType, refEncFileStr string) (diffStr string, err error) { + var refList encListType + if refList, err = loadMap(refEncFileStr); err != nil { + return + } + var buf fmtBuffer + last := 0 + for j := 32; j < 256; j++ { + if encList[j].name != refList[j].name { + if j != last+1 { + buf.printf("%d ", j) + } + last = j + buf.printf("/%s ", encList[j].name) + } + } + diffStr = strings.TrimSpace(buf.String()) + return +} + +func makeDefinitionFile(fileStr, tpStr, encodingFileStr string, embed bool, encList encListType, info fontInfoType) error { + var err error + var def fontDefType + def.Tp = tpStr + def.Name = info.FontName + makeFontDescriptor(&info) + def.Desc = info.Desc + // printf("makeDefinitionFile/FontBBox\n") + // dump(def.Desc.FontBBox) + def.Up = info.UnderlinePosition + def.Ut = info.UnderlineThickness + def.Cw = info.Widths + def.Enc = baseNoExt(encodingFileStr) + // fmt.Printf("encodingFileStr [%s], def.Enc [%s]\n", encodingFileStr, def.Enc) + // fmt.Printf("reference [%s]\n", filepath.Join(filepath.Dir(encodingFileStr), "cp1252.map")) + def.Diff, err = makeFontEncoding(encList, filepath.Join(filepath.Dir(encodingFileStr), "cp1252.map")) + if err != nil { + return err + } + def.File = info.File + def.Size1 = int(info.Size1) + def.Size2 = int(info.Size2) + def.OriginalSize = info.OriginalSize + // printf("Font definition file [%s]\n", fileStr) + var buf []byte + buf, err = json.Marshal(def) + if err != nil { + return err + } + var f *os.File + f, err = os.Create(fileStr) + if err != nil { + return err + } + defer f.Close() + _, err = f.Write(buf) + if err != nil { + return err + } + err = f.Close() + if err != nil { + return err + } + + return err +} + +// MakeFont generates a font definition file in JSON format. A definition file +// of this type is required to use non-core fonts in the PDF documents that +// gofpdf generates. See the makefont utility in the gofpdf package for a +// command line interface to this function. +// +// fontFileStr is the name of the TrueType file (extension .ttf), OpenType file +// (extension .otf) or binary Type1 file (extension .pfb) from which to +// generate a definition file. If an OpenType file is specified, it must be one +// that is based on TrueType outlines, not PostScript outlines; this cannot be +// determined from the file extension alone. If a Type1 file is specified, a +// metric file with the same pathname except with the extension .afm must be +// present. +// +// encodingFileStr is the name of the encoding file that corresponds to the +// font. +// +// dstDirStr is the name of the directory in which to save the definition file +// and, if embed is true, the compressed font file. +// +// msgWriter is the writer that is called to display messages throughout the +// process. Use nil to turn off messages. +// +// embed is true if the font is to be embedded in the PDF files. +func MakeFont(fontFileStr, encodingFileStr, dstDirStr string, msgWriter io.Writer, embed bool) error { + if msgWriter == nil { + msgWriter = ioutil.Discard + } + if !fileExist(fontFileStr) { + return fmt.Errorf("font file not found: %s", fontFileStr) + } + extStr := strings.ToLower(fontFileStr[len(fontFileStr)-3:]) + // printf("Font file extension [%s]\n", extStr) + var tpStr string + switch extStr { + case "ttf": + fallthrough + case "otf": + tpStr = "TrueType" + case "pfb": + tpStr = "Type1" + default: + return fmt.Errorf("unrecognized font file extension: %s", extStr) + } + + var info fontInfoType + encList, err := loadMap(encodingFileStr) + if err != nil { + return err + } + // printf("Encoding table\n") + // dump(encList) + if tpStr == "TrueType" { + info, err = getInfoFromTrueType(fontFileStr, msgWriter, embed, encList) + if err != nil { + return err + } + } else { + info, err = getInfoFromType1(fontFileStr, msgWriter, embed, encList) + if err != nil { + return err + } + } + baseStr := baseNoExt(fontFileStr) + // fmt.Printf("Base [%s]\n", baseStr) + if embed { + var f *os.File + info.File = baseStr + ".z" + zFileStr := filepath.Join(dstDirStr, info.File) + f, err = os.Create(zFileStr) + if err != nil { + return err + } + defer f.Close() + cmp := zlib.NewWriter(f) + _, err = cmp.Write(info.Data) + if err != nil { + return err + } + err = cmp.Close() + if err != nil { + return err + } + fmt.Fprintf(msgWriter, "Font file compressed: %s\n", zFileStr) + } + defFileStr := filepath.Join(dstDirStr, baseStr+".json") + err = makeDefinitionFile(defFileStr, tpStr, encodingFileStr, embed, encList, info) + if err != nil { + return err + } + fmt.Fprintf(msgWriter, "Font definition file successfully generated: %s\n", defFileStr) + return nil +} diff --git a/font/CalligrapherRegular.afm b/font/CalligrapherRegular.afm new file mode 100644 index 0000000..5e24959 --- /dev/null +++ b/font/CalligrapherRegular.afm @@ -0,0 +1,272 @@ +StartFontMetrics 2.0 +Comment Generated by FontForge 20141024 +Comment Creation Date: Thu Jul 23 17:38:06 2015 +FontName CalligrapherRegular +FullName Calligrapher Regular +FamilyName Calligrapher +Weight Thin +Notice (Generated by Fontographer 3.5) +ItalicAngle 0 +IsFixedPitch false +UnderlinePosition -190 +UnderlineThickness 20 +Version Altsys Fontographer 3.5 5/26/92 +EncodingScheme ISO10646-1 +FontBBox -173 -234 1328 899 +CapHeight 677 +XHeight 677 +Ascender 756 +Descender -219 +StartCharMetrics 250 +C 32 ; WX 282 ; N space ; B 0 0 0 0 ; +C 33 ; WX 324 ; N exclam ; B 67 -16 251 718 ; +C 34 ; WX 405 ; N quotedbl ; B 60 460 353 718 ; +C 35 ; WX 584 ; N numbersign ; B 35 0 549 701 ; +C 36 ; WX 632 ; N dollar ; B 32 -126 595 814 ; +C 37 ; WX 980 ; N percent ; B 35 -16 945 703 ; +C 38 ; WX 776 ; N ampersand ; B 41 -17 811 670 ; +C 39 ; WX 259 ; N quotesingle ; B 72 460 206 718 ; +C 40 ; WX 299 ; N parenleft ; B 57 -119 299 785 ; +C 41 ; WX 299 ; N parenright ; B 0 -119 242 785 ; +C 42 ; WX 377 ; N asterisk ; B 35 407 342 714 ; +C 43 ; WX 600 ; N plus ; B 47 0 553 506 ; +C 44 ; WX 259 ; N comma ; B 35 -67 224 162 ; +C 45 ; WX 432 ; N hyphen ; B 28 249 404 377 ; +C 46 ; WX 254 ; N period ; B 43 -16 227 162 ; +C 47 ; WX 597 ; N slash ; B 7 -14 591 714 ; +C 48 ; WX 529 ; N zero ; B 21 -18 508 583 ; +C 49 ; WX 298 ; N one ; B 8 -15 233 582 ; +C 50 ; WX 451 ; N two ; B 17 -8 430 588 ; +C 51 ; WX 359 ; N three ; B 11 -54 337 582 ; +C 52 ; WX 525 ; N four ; B 18 -20 519 602 ; +C 53 ; WX 423 ; N five ; B 10 -55 420 582 ; +C 54 ; WX 464 ; N six ; B 23 -14 447 589 ; +C 55 ; WX 417 ; N seven ; B 8 -18 415 589 ; +C 56 ; WX 457 ; N eight ; B 19 -16 432 583 ; +C 57 ; WX 479 ; N nine ; B 26 -16 450 588 ; +C 58 ; WX 275 ; N colon ; B 59 -16 242 491 ; +C 59 ; WX 282 ; N semicolon ; B 54 -67 245 491 ; +C 60 ; WX 600 ; N less ; B 47 -8 553 514 ; +C 61 ; WX 600 ; N equal ; B 47 98 553 408 ; +C 62 ; WX 600 ; N greater ; B 47 -8 553 514 ; +C 63 ; WX 501 ; N question ; B 21 -16 473 721 ; +C 64 ; WX 800 ; N at ; B 29 -12 771 730 ; +C 65 ; WX 743 ; N A ; B -23 -14 754 721 ; +C 66 ; WX 636 ; N B ; B -42 -7 608 706 ; +C 67 ; WX 598 ; N C ; B 27 -12 572 712 ; +C 68 ; WX 712 ; N D ; B -42 -11 684 705 ; +C 69 ; WX 608 ; N E ; B -21 0 608 708 ; +C 70 ; WX 562 ; N F ; B -21 -18 584 716 ; +C 71 ; WX 680 ; N G ; B 29 -8 668 714 ; +C 72 ; WX 756 ; N H ; B 70 -17 777 728 ; +C 73 ; WX 308 ; N I ; B 14 -15 238 718 ; +C 74 ; WX 314 ; N J ; B 7 -223 244 727 ; +C 75 ; WX 676 ; N K ; B 14 -16 683 725 ; +C 76 ; WX 552 ; N L ; B 14 -8 580 713 ; +C 77 ; WX 1041 ; N M ; B 42 -17 1017 739 ; +C 78 ; WX 817 ; N N ; B -42 -17 747 736 ; +C 79 ; WX 729 ; N O ; B 32 -16 698 709 ; +C 80 ; WX 569 ; N P ; B -35 -15 570 716 ; +C 81 ; WX 698 ; N Q ; B 27 -201 1328 715 ; +C 82 ; WX 674 ; N R ; B -35 -20 696 712 ; +C 83 ; WX 618 ; N S ; B 31 -16 589 709 ; +C 84 ; WX 673 ; N T ; B -21 -20 702 714 ; +C 85 ; WX 805 ; N U ; B 0 -19 804 722 ; +C 86 ; WX 753 ; N V ; B -28 -20 788 729 ; +C 87 ; WX 1238 ; N W ; B -28 -17 1273 736 ; +C 88 ; WX 716 ; N X ; B 7 -38 709 731 ; +C 89 ; WX 754 ; N Y ; B -35 -17 789 747 ; +C 90 ; WX 599 ; N Z ; B 30 -5 584 748 ; +C 91 ; WX 315 ; N bracketleft ; B 93 -124 322 718 ; +C 92 ; WX 463 ; N backslash ; B -21 -18 484 736 ; +C 93 ; WX 315 ; N bracketright ; B -7 -124 222 718 ; +C 94 ; WX 600 ; N asciicircum ; B 63 266 537 658 ; +C 95 ; WX 547 ; N underscore ; B -7 -198 554 -163 ; +C 96 ; WX 278 ; N grave ; B -1 541 214 693 ; +C 97 ; WX 581 ; N a ; B 21 -16 581 494 ; +C 98 ; WX 564 ; N b ; B -24 -17 543 792 ; +C 99 ; WX 440 ; N c ; B 21 -17 422 490 ; +C 100 ; WX 571 ; N d ; B 0 -15 550 659 ; +C 101 ; WX 450 ; N e ; B 28 -23 428 493 ; +C 102 ; WX 347 ; N f ; B -35 -14 474 785 ; +C 103 ; WX 628 ; N g ; B 19 -219 612 496 ; +C 104 ; WX 611 ; N h ; B -29 -18 569 785 ; +C 105 ; WX 283 ; N i ; B -14 -15 241 679 ; +C 106 ; WX 283 ; N j ; B -14 -234 241 679 ; +C 107 ; WX 560 ; N k ; B -24 -15 582 789 ; +C 108 ; WX 252 ; N l ; B -28 -15 210 789 ; +C 109 ; WX 976 ; N m ; B -21 -16 927 494 ; +C 110 ; WX 595 ; N n ; B -28 -15 574 493 ; +C 111 ; WX 508 ; N o ; B 27 -17 485 490 ; +C 112 ; WX 549 ; N p ; B -28 -216 526 496 ; +C 113 ; WX 540 ; N q ; B 28 -219 491 493 ; +C 114 ; WX 395 ; N r ; B -21 -19 430 492 ; +C 115 ; WX 441 ; N s ; B 34 -15 413 493 ; +C 116 ; WX 307 ; N t ; B -21 -16 378 621 ; +C 117 ; WX 614 ; N u ; B -14 -18 558 501 ; +C 118 ; WX 556 ; N v ; B -28 -20 569 483 ; +C 119 ; WX 915 ; N w ; B -28 -17 928 495 ; +C 120 ; WX 559 ; N x ; B 14 -17 546 500 ; +C 121 ; WX 597 ; N y ; B -21 -227 541 500 ; +C 122 ; WX 452 ; N z ; B 28 -5 442 515 ; +C 123 ; WX 315 ; N braceleft ; B 6 -118 309 718 ; +C 124 ; WX 222 ; N bar ; B 63 -18 159 730 ; +C 125 ; WX 315 ; N braceright ; B 6 -118 309 718 ; +C 126 ; WX 600 ; N asciitilde ; B 69 166 531 340 ; +C 160 ; WX 282 ; N nonbreakingspace ; B 0 0 0 0 ; +C 161 ; WX 324 ; N exclamdown ; B 69 -203 253 531 ; +C 162 ; WX 450 ; N cent ; B 27 -122 437 592 ; +C 163 ; WX 640 ; N sterling ; B 0 -9 619 716 ; +C 164 ; WX 518 ; N currency ; B 3 72 515 586 ; +C 165 ; WX 603 ; N yen ; B -28 -65 631 747 ; +C 166 ; WX 0 ; N brokenbar ; B 0 0 0 0 ; +C 167 ; WX 519 ; N section ; B -50 -216 524 762 ; +C 168 ; WX 254 ; N dieresis ; B -20 554 308 682 ; +C 169 ; WX 800 ; N copyright ; B 29 -12 771 730 ; +C 170 ; WX 349 ; N ordfeminine ; B 13 385 349 717 ; +C 171 ; WX 0 ; N guillemotleft ; B 0 0 0 0 ; +C 172 ; WX 0 ; N logicalnot ; B 0 0 0 0 ; +C 173 ; WX 432 ; N hyphen ; B 28 249 404 377 ; +C 174 ; WX 800 ; N registered ; B 29 -12 771 730 ; +C 175 ; WX 278 ; N macron ; B -47 584 325 665 ; +C 176 ; WX 0 ; N degree ; B 0 0 0 0 ; +C 177 ; WX 0 ; N plusminus ; B 0 0 0 0 ; +C 178 ; WX 0 ; N twosuperior ; B 0 0 0 0 ; +C 179 ; WX 0 ; N threesuperior ; B 0 0 0 0 ; +C 180 ; WX 278 ; N acute ; B 49 536 279 693 ; +C 181 ; WX 614 ; N mu ; B -14 -231 558 501 ; +C 182 ; WX 0 ; N paragraph ; B 0 0 0 0 ; +C 183 ; WX 254 ; N periodcentered ; B 43 278 227 456 ; +C 184 ; WX 278 ; N cedilla ; B -8 -216 231 6 ; +C 185 ; WX 0 ; N onesuperior ; B 0 0 0 0 ; +C 186 ; WX 305 ; N ordmasculine ; B 16 373 291 702 ; +C 187 ; WX 0 ; N guillemotright ; B 0 0 0 0 ; +C 188 ; WX 0 ; N onequarter ; B 0 0 0 0 ; +C 189 ; WX 0 ; N onehalf ; B 0 0 0 0 ; +C 190 ; WX 0 ; N threequarters ; B 0 0 0 0 ; +C 191 ; WX 501 ; N questiondown ; B 15 -196 467 541 ; +C 192 ; WX 743 ; N Agrave ; B -23 -14 754 893 ; +C 193 ; WX 743 ; N Aacute ; B -23 -14 754 893 ; +C 194 ; WX 743 ; N Acircumflex ; B -23 -14 754 877 ; +C 195 ; WX 743 ; N Atilde ; B -23 -14 754 889 ; +C 196 ; WX 743 ; N Adieresis ; B -23 -14 754 882 ; +C 197 ; WX 743 ; N Aring ; B -23 -14 754 899 ; +C 198 ; WX 1060 ; N AE ; B -29 -14 1053 708 ; +C 199 ; WX 598 ; N Ccedilla ; B 27 -183 572 712 ; +C 200 ; WX 608 ; N Egrave ; B -21 0 608 893 ; +C 201 ; WX 608 ; N Eacute ; B -21 0 608 893 ; +C 202 ; WX 608 ; N Ecircumflex ; B -21 0 608 877 ; +C 203 ; WX 608 ; N Edieresis ; B -21 0 608 882 ; +C 204 ; WX 308 ; N Igrave ; B 14 -15 264 893 ; +C 205 ; WX 308 ; N Iacute ; B 14 -15 274 893 ; +C 206 ; WX 308 ; N Icircumflex ; B 1 -15 307 877 ; +C 207 ; WX 308 ; N Idieresis ; B -15 -15 313 882 ; +C 208 ; WX 0 ; N Eth ; B 0 0 0 0 ; +C 209 ; WX 817 ; N Ntilde ; B -42 -17 747 889 ; +C 210 ; WX 729 ; N Ograve ; B 32 -16 698 893 ; +C 211 ; WX 729 ; N Oacute ; B 32 -16 698 893 ; +C 212 ; WX 729 ; N Ocircumflex ; B 32 -16 698 877 ; +C 213 ; WX 729 ; N Otilde ; B 32 -16 698 889 ; +C 214 ; WX 729 ; N Odieresis ; B 32 -16 698 882 ; +C 215 ; WX 0 ; N multiply ; B 0 0 0 0 ; +C 216 ; WX 729 ; N Oslash ; B 14 -24 724 709 ; +C 217 ; WX 805 ; N Ugrave ; B 0 -19 804 893 ; +C 218 ; WX 805 ; N Uacute ; B 0 -19 804 893 ; +C 219 ; WX 805 ; N Ucircumflex ; B 0 -19 804 877 ; +C 220 ; WX 805 ; N Udieresis ; B 0 -19 804 882 ; +C 221 ; WX 0 ; N Yacute ; B 0 0 0 0 ; +C 222 ; WX 0 ; N Thorn ; B 0 0 0 0 ; +C 223 ; WX 688 ; N germandbls ; B -35 -15 668 785 ; +C 224 ; WX 581 ; N agrave ; B 21 -16 581 693 ; +C 225 ; WX 581 ; N aacute ; B 21 -16 581 693 ; +C 226 ; WX 581 ; N acircumflex ; B 21 -16 581 677 ; +C 227 ; WX 581 ; N atilde ; B 21 -16 581 689 ; +C 228 ; WX 581 ; N adieresis ; B 21 -16 581 682 ; +C 229 ; WX 581 ; N aring ; B 21 -16 581 734 ; +C 230 ; WX 792 ; N ae ; B 21 -23 773 494 ; +C 231 ; WX 440 ; N ccedilla ; B 21 -183 422 490 ; +C 232 ; WX 450 ; N egrave ; B 28 -23 428 693 ; +C 233 ; WX 450 ; N eacute ; B 28 -23 428 693 ; +C 234 ; WX 450 ; N ecircumflex ; B 28 -23 432 677 ; +C 235 ; WX 450 ; N edieresis ; B 28 -23 428 682 ; +C 236 ; WX 283 ; N igrave ; B -14 -15 244 693 ; +C 237 ; WX 283 ; N iacute ; B -14 -15 269 693 ; +C 238 ; WX 283 ; N icircumflex ; B -14 -15 297 677 ; +C 239 ; WX 283 ; N idieresis ; B -25 -15 303 682 ; +C 240 ; WX 0 ; N eth ; B 0 0 0 0 ; +C 241 ; WX 595 ; N ntilde ; B -28 -15 574 689 ; +C 242 ; WX 508 ; N ograve ; B 27 -17 485 693 ; +C 243 ; WX 508 ; N oacute ; B 27 -17 485 693 ; +C 244 ; WX 508 ; N ocircumflex ; B 27 -17 485 677 ; +C 245 ; WX 508 ; N otilde ; B 27 -17 485 689 ; +C 246 ; WX 508 ; N odieresis ; B 27 -17 485 682 ; +C 247 ; WX 0 ; N divide ; B 0 0 0 0 ; +C 248 ; WX 508 ; N oslash ; B -8 -54 496 589 ; +C 249 ; WX 614 ; N ugrave ; B -14 -18 558 693 ; +C 250 ; WX 614 ; N uacute ; B -14 -18 558 693 ; +C 251 ; WX 614 ; N ucircumflex ; B -14 -18 558 677 ; +C 252 ; WX 614 ; N udieresis ; B -14 -18 558 682 ; +C 253 ; WX 0 ; N yacute ; B 0 0 0 0 ; +C 254 ; WX 0 ; N thorn ; B 0 0 0 0 ; +C 255 ; WX 597 ; N ydieresis ; B -21 -227 541 682 ; +C -1 ; WX 283 ; N dotlessi ; B -14 -15 227 499 ; +C -1 ; WX 0 ; N Lslash ; B 0 0 0 0 ; +C -1 ; WX 0 ; N lslash ; B 0 0 0 0 ; +C -1 ; WX 1064 ; N OE ; B 32 -16 1055 709 ; +C -1 ; WX 790 ; N oe ; B 27 -23 764 493 ; +C -1 ; WX 0 ; N Scaron ; B 0 0 0 0 ; +C -1 ; WX 0 ; N scaron ; B 0 0 0 0 ; +C -1 ; WX 754 ; N Ydieresis ; B -35 -17 789 882 ; +C -1 ; WX 0 ; N Zcaron ; B 0 0 0 0 ; +C -1 ; WX 0 ; N zcaron ; B 0 0 0 0 ; +C -1 ; WX 0 ; N florin ; B 0 0 0 0 ; +C -1 ; WX 278 ; N hungarumlaut ; B -51 531 379 693 ; +C -1 ; WX 278 ; N circumflex ; B -14 557 292 677 ; +C -1 ; WX 278 ; N caron ; B -14 557 292 677 ; +C -1 ; WX 278 ; N macron ; B -47 584 325 665 ; +C -1 ; WX 278 ; N breve ; B -32 545 310 698 ; +C -1 ; WX 254 ; N dotaccent ; B 88 554 220 682 ; +C -1 ; WX 278 ; N ring ; B 11 532 267 734 ; +C -1 ; WX 278 ; N ogonek ; B 32 -216 226 6 ; +C -1 ; WX 278 ; N tilde ; B -44 563 326 689 ; +C -1 ; WX 611 ; N summation ; B -29 -18 569 785 ; +C -1 ; WX 411 ; N Omega ; B 34 -15 413 677 ; +C -1 ; WX 283 ; N pi ; B -14 -234 297 677 ; +C -1 ; WX 300 ; N endash ; B 0 245 300 350 ; +C -1 ; WX 600 ; N emdash ; B 0 245 600 350 ; +C -1 ; WX 259 ; N quoteleft ; B 35 489 224 717 ; +C -1 ; WX 259 ; N quoteright ; B 35 489 224 717 ; +C -1 ; WX 0 ; N quotesinglbase ; B 0 0 0 0 ; +C -1 ; WX 470 ; N quotedblleft ; B 35 489 443 717 ; +C -1 ; WX 470 ; N quotedblright ; B 35 487 443 717 ; +C -1 ; WX 0 ; N quotedblbase ; B 0 0 0 0 ; +C -1 ; WX 0 ; N dagger ; B 0 0 0 0 ; +C -1 ; WX 0 ; N daggerdbl ; B 0 0 0 0 ; +C -1 ; WX 500 ; N bullet ; B 70 179 430 539 ; +C -1 ; WX 780 ; N ellipsis ; B 43 -16 747 162 ; +C -1 ; WX 0 ; N perthousand ; B 0 0 0 0 ; +C -1 ; WX 0 ; N guilsinglleft ; B 0 0 0 0 ; +C -1 ; WX 0 ; N guilsinglright ; B 0 0 0 0 ; +C -1 ; WX 990 ; N trademark ; B 62 306 928 718 ; +C -1 ; WX 756 ; N partialdiff ; B 70 -17 777 877 ; +C -1 ; WX 614 ; N Delta ; B -14 -18 558 698 ; +C -1 ; WX 314 ; N product ; B 7 -223 317 877 ; +C -1 ; WX 0 ; N minus ; B 0 0 0 0 ; +C -1 ; WX 167 ; N fraction ; B -173 -28 310 686 ; +C -1 ; WX 254 ; N periodcentered ; B 43 278 227 456 ; +C -1 ; WX 760 ; N radical ; B 30 0 730 700 ; +C -1 ; WX 440 ; N infinity ; B 21 -17 422 677 ; +C -1 ; WX 618 ; N integral ; B 31 -16 589 877 ; +C -1 ; WX 805 ; N approxequal ; B 0 -19 804 854 ; +C -1 ; WX 598 ; N notequal ; B 27 -12 572 877 ; +C -1 ; WX 680 ; N lessequal ; B 29 -8 668 877 ; +C -1 ; WX 628 ; N greaterequal ; B 19 -219 612 677 ; +C -1 ; WX 795 ; N lozenge ; B 35 0 760 727 ; +C -1 ; WX 795 ; N apple ; B 35 0 760 727 ; +C -1 ; WX 0 ; N fi ; B 0 0 0 0 ; +C -1 ; WX 0 ; N fl ; B 0 0 0 0 ; +C -1 ; WX 800 ; N .notdef ; B 50 0 750 800 ; +C -1 ; WX 0 ; N .null ; B 0 0 0 0 ; +C -1 ; WX 282 ; N nonmarkingreturn ; B 0 0 0 0 ; +EndCharMetrics +EndFontMetrics diff --git a/font/CalligrapherRegular.pfb b/font/CalligrapherRegular.pfb new file mode 100644 index 0000000..d958c0d Binary files /dev/null and b/font/CalligrapherRegular.pfb differ diff --git a/font/DejaVuSansCondensed-Bold.ttf b/font/DejaVuSansCondensed-Bold.ttf new file mode 100644 index 0000000..22987c6 Binary files /dev/null and b/font/DejaVuSansCondensed-Bold.ttf differ diff --git a/font/DejaVuSansCondensed-BoldOblique.ttf b/font/DejaVuSansCondensed-BoldOblique.ttf new file mode 100644 index 0000000..f5fa0ca Binary files /dev/null and b/font/DejaVuSansCondensed-BoldOblique.ttf differ diff --git a/font/DejaVuSansCondensed-Oblique.ttf b/font/DejaVuSansCondensed-Oblique.ttf new file mode 100644 index 0000000..7fde907 Binary files /dev/null and b/font/DejaVuSansCondensed-Oblique.ttf differ diff --git a/font/DejaVuSansCondensed.json b/font/DejaVuSansCondensed.json new file mode 100644 index 0000000..f833dff --- /dev/null +++ b/font/DejaVuSansCondensed.json @@ -0,0 +1 @@ +{"Tp":"TrueType","Name":"DejaVuSansCondensed","Desc":{"Ascent":760,"Descent":-240,"CapHeight":760,"Flags":32,"FontBBox":{"Xmin":-918,"Ymin":-463,"Xmax":1614,"Ymax":1232},"ItalicAngle":0,"StemV":70,"MissingWidth":540},"Up":-63,"Ut":44,"Cw":[540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,540,286,360,414,754,572,855,702,247,351,351,450,754,286,325,286,303,572,572,572,572,572,572,572,572,572,572,303,303,754,754,754,478,900,615,617,628,693,568,518,697,677,265,265,590,501,776,673,708,542,708,625,571,549,659,615,890,616,549,616,351,303,351,754,450,450,551,571,495,571,554,316,571,570,250,250,521,250,876,570,550,571,571,370,469,353,570,532,736,532,532,472,572,303,572,754,540,708,549,286,473,466,900,450,450,572,1208,984,360,940,639,708,677,563,286,286,466,466,531,450,900,540,900,812,360,809,543,586,588,286,548,532,265,572,549,303,450,568,900,628,550,754,325,900,265,450,754,265,250,473,572,572,286,554,936,494,550,250,571,469,250,615,617,617,549,703,568,969,577,673,673,639,677,776,677,708,677,542,628,549,548,774,616,699,617,962,984,749,794,617,628,971,625,551,555,530,473,622,554,811,479,584,584,543,575,679,588,550,588,571,495,524,532,769,532,612,532,823,848,636,710,530,494,757,541],"Enc":"cp1251","Diff":"128 /afii10051 /afii10052 131 /afii10100 136 /Euro 138 /afii10058 140 /afii10059 /afii10061 /afii10060 /afii10145 /afii10099 152 /.notdef 154 /afii10106 156 /afii10107 /afii10109 /afii10108 /afii10193 161 /afii10062 /afii10110 /afii10057 165 /afii10050 168 /afii10023 170 /afii10053 175 /afii10056 178 /afii10055 /afii10103 /afii10098 184 /afii10071 /afii61352 /afii10101 188 /afii10105 /afii10054 /afii10102 /afii10104 /afii10017 /afii10018 /afii10019 /afii10020 /afii10021 /afii10022 /afii10024 /afii10025 /afii10026 /afii10027 /afii10028 /afii10029 /afii10030 /afii10031 /afii10032 /afii10033 /afii10034 /afii10035 /afii10036 /afii10037 /afii10038 /afii10039 /afii10040 /afii10041 /afii10042 /afii10043 /afii10044 /afii10045 /afii10046 /afii10047 /afii10048 /afii10049 /afii10065 /afii10066 /afii10067 /afii10068 /afii10069 /afii10070 /afii10072 /afii10073 /afii10074 /afii10075 /afii10076 /afii10077 /afii10078 /afii10079 /afii10080 /afii10081 /afii10082 /afii10083 /afii10084 /afii10085 /afii10086 /afii10087 /afii10088 /afii10089 /afii10090 /afii10091 /afii10092 /afii10093 /afii10094 /afii10095 /afii10096 /afii10097","File":"","Size1":0,"Size2":0,"OriginalSize":0,"N":0,"DiffN":0} \ No newline at end of file diff --git a/font/DejaVuSansCondensed.ttf b/font/DejaVuSansCondensed.ttf new file mode 100644 index 0000000..3259bc2 Binary files /dev/null and b/font/DejaVuSansCondensed.ttf differ diff --git a/font/calligra.json b/font/calligra.json new file mode 100644 index 0000000..e49c9bd --- /dev/null +++ b/font/calligra.json @@ -0,0 +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,"N":0,"DiffN":0} \ No newline at end of file diff --git a/font/calligra.ttf b/font/calligra.ttf new file mode 100644 index 0000000..9713c46 Binary files /dev/null and b/font/calligra.ttf differ diff --git a/font/calligra.z b/font/calligra.z new file mode 100644 index 0000000..b6c5c07 Binary files /dev/null and b/font/calligra.z differ diff --git a/font/courier.json b/font/courier.json new file mode 100644 index 0000000..d979da5 --- /dev/null +++ b/font/courier.json @@ -0,0 +1 @@ +{"Tp":"Core","Name":"Courier","Up":-100,"Ut":50,"I":256,"Cw":[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600]} \ No newline at end of file diff --git a/font/courierb.json b/font/courierb.json new file mode 100644 index 0000000..ab15c59 --- /dev/null +++ b/font/courierb.json @@ -0,0 +1 @@ +{"Tp":"Core","Name":"Courier-Bold","Up":-100,"Ut":50,"I":256,"Cw":[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600]} \ No newline at end of file diff --git a/font/courierbi.json b/font/courierbi.json new file mode 100644 index 0000000..535b2a2 --- /dev/null +++ b/font/courierbi.json @@ -0,0 +1 @@ +{"Tp":"Core","Name":"Courier-BoldOblique","Up":-100,"Ut":50,"I":256,"Cw":[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600]} \ No newline at end of file diff --git a/font/courieri.json b/font/courieri.json new file mode 100644 index 0000000..9624d6e --- /dev/null +++ b/font/courieri.json @@ -0,0 +1 @@ +{"Tp":"Core","Name":"Courier-Oblique","Up":-100,"Ut":50,"I":256,"Cw":[600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600,600]} \ No newline at end of file diff --git a/font/cp1250.map b/font/cp1250.map new file mode 100644 index 0000000..ec110af --- /dev/null +++ b/font/cp1250.map @@ -0,0 +1,251 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!89 U+2030 perthousand +!8A U+0160 Scaron +!8B U+2039 guilsinglleft +!8C U+015A Sacute +!8D U+0164 Tcaron +!8E U+017D Zcaron +!8F U+0179 Zacute +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9A U+0161 scaron +!9B U+203A guilsinglright +!9C U+015B sacute +!9D U+0165 tcaron +!9E U+017E zcaron +!9F U+017A zacute +!A0 U+00A0 space +!A1 U+02C7 caron +!A2 U+02D8 breve +!A3 U+0141 Lslash +!A4 U+00A4 currency +!A5 U+0104 Aogonek +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+015E Scedilla +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+017B Zdotaccent +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+02DB ogonek +!B3 U+0142 lslash +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+0105 aogonek +!BA U+015F scedilla +!BB U+00BB guillemotright +!BC U+013D Lcaron +!BD U+02DD hungarumlaut +!BE U+013E lcaron +!BF U+017C zdotaccent +!C0 U+0154 Racute +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+0102 Abreve +!C4 U+00C4 Adieresis +!C5 U+0139 Lacute +!C6 U+0106 Cacute +!C7 U+00C7 Ccedilla +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0118 Eogonek +!CB U+00CB Edieresis +!CC U+011A Ecaron +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+010E Dcaron +!D0 U+0110 Dcroat +!D1 U+0143 Nacute +!D2 U+0147 Ncaron +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+0150 Ohungarumlaut +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+0158 Rcaron +!D9 U+016E Uring +!DA U+00DA Uacute +!DB U+0170 Uhungarumlaut +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+0162 Tcommaaccent +!DF U+00DF germandbls +!E0 U+0155 racute +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+0103 abreve +!E4 U+00E4 adieresis +!E5 U+013A lacute +!E6 U+0107 cacute +!E7 U+00E7 ccedilla +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+0119 eogonek +!EB U+00EB edieresis +!EC U+011B ecaron +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+010F dcaron +!F0 U+0111 dcroat +!F1 U+0144 nacute +!F2 U+0148 ncaron +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+0151 ohungarumlaut +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+0159 rcaron +!F9 U+016F uring +!FA U+00FA uacute +!FB U+0171 uhungarumlaut +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+0163 tcommaaccent +!FF U+02D9 dotaccent diff --git a/font/cp1251.map b/font/cp1251.map new file mode 100644 index 0000000..de6a198 --- /dev/null +++ b/font/cp1251.map @@ -0,0 +1,255 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0402 afii10051 +!81 U+0403 afii10052 +!82 U+201A quotesinglbase +!83 U+0453 afii10100 +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+20AC Euro +!89 U+2030 perthousand +!8A U+0409 afii10058 +!8B U+2039 guilsinglleft +!8C U+040A afii10059 +!8D U+040C afii10061 +!8E U+040B afii10060 +!8F U+040F afii10145 +!90 U+0452 afii10099 +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9A U+0459 afii10106 +!9B U+203A guilsinglright +!9C U+045A afii10107 +!9D U+045C afii10109 +!9E U+045B afii10108 +!9F U+045F afii10193 +!A0 U+00A0 space +!A1 U+040E afii10062 +!A2 U+045E afii10110 +!A3 U+0408 afii10057 +!A4 U+00A4 currency +!A5 U+0490 afii10050 +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+0401 afii10023 +!A9 U+00A9 copyright +!AA U+0404 afii10053 +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+0407 afii10056 +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+0406 afii10055 +!B3 U+0456 afii10103 +!B4 U+0491 afii10098 +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+0451 afii10071 +!B9 U+2116 afii61352 +!BA U+0454 afii10101 +!BB U+00BB guillemotright +!BC U+0458 afii10105 +!BD U+0405 afii10054 +!BE U+0455 afii10102 +!BF U+0457 afii10104 +!C0 U+0410 afii10017 +!C1 U+0411 afii10018 +!C2 U+0412 afii10019 +!C3 U+0413 afii10020 +!C4 U+0414 afii10021 +!C5 U+0415 afii10022 +!C6 U+0416 afii10024 +!C7 U+0417 afii10025 +!C8 U+0418 afii10026 +!C9 U+0419 afii10027 +!CA U+041A afii10028 +!CB U+041B afii10029 +!CC U+041C afii10030 +!CD U+041D afii10031 +!CE U+041E afii10032 +!CF U+041F afii10033 +!D0 U+0420 afii10034 +!D1 U+0421 afii10035 +!D2 U+0422 afii10036 +!D3 U+0423 afii10037 +!D4 U+0424 afii10038 +!D5 U+0425 afii10039 +!D6 U+0426 afii10040 +!D7 U+0427 afii10041 +!D8 U+0428 afii10042 +!D9 U+0429 afii10043 +!DA U+042A afii10044 +!DB U+042B afii10045 +!DC U+042C afii10046 +!DD U+042D afii10047 +!DE U+042E afii10048 +!DF U+042F afii10049 +!E0 U+0430 afii10065 +!E1 U+0431 afii10066 +!E2 U+0432 afii10067 +!E3 U+0433 afii10068 +!E4 U+0434 afii10069 +!E5 U+0435 afii10070 +!E6 U+0436 afii10072 +!E7 U+0437 afii10073 +!E8 U+0438 afii10074 +!E9 U+0439 afii10075 +!EA U+043A afii10076 +!EB U+043B afii10077 +!EC U+043C afii10078 +!ED U+043D afii10079 +!EE U+043E afii10080 +!EF U+043F afii10081 +!F0 U+0440 afii10082 +!F1 U+0441 afii10083 +!F2 U+0442 afii10084 +!F3 U+0443 afii10085 +!F4 U+0444 afii10086 +!F5 U+0445 afii10087 +!F6 U+0446 afii10088 +!F7 U+0447 afii10089 +!F8 U+0448 afii10090 +!F9 U+0449 afii10091 +!FA U+044A afii10092 +!FB U+044B afii10093 +!FC U+044C afii10094 +!FD U+044D afii10095 +!FE U+044E afii10096 +!FF U+044F afii10097 diff --git a/font/cp1252.map b/font/cp1252.map new file mode 100644 index 0000000..dd490e5 --- /dev/null +++ b/font/cp1252.map @@ -0,0 +1,251 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+02C6 circumflex +!89 U+2030 perthousand +!8A U+0160 Scaron +!8B U+2039 guilsinglleft +!8C U+0152 OE +!8E U+017D Zcaron +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!98 U+02DC tilde +!99 U+2122 trademark +!9A U+0161 scaron +!9B U+203A guilsinglright +!9C U+0153 oe +!9E U+017E zcaron +!9F U+0178 Ydieresis +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+00D0 Eth +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+00DE Thorn +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+00F0 eth +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+00FE thorn +!FF U+00FF ydieresis diff --git a/font/cp1253.map b/font/cp1253.map new file mode 100644 index 0000000..4bd826f --- /dev/null +++ b/font/cp1253.map @@ -0,0 +1,239 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!89 U+2030 perthousand +!8B U+2039 guilsinglleft +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9B U+203A guilsinglright +!A0 U+00A0 space +!A1 U+0385 dieresistonos +!A2 U+0386 Alphatonos +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+2015 afii00208 +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+0384 tonos +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+0388 Epsilontonos +!B9 U+0389 Etatonos +!BA U+038A Iotatonos +!BB U+00BB guillemotright +!BC U+038C Omicrontonos +!BD U+00BD onehalf +!BE U+038E Upsilontonos +!BF U+038F Omegatonos +!C0 U+0390 iotadieresistonos +!C1 U+0391 Alpha +!C2 U+0392 Beta +!C3 U+0393 Gamma +!C4 U+0394 Delta +!C5 U+0395 Epsilon +!C6 U+0396 Zeta +!C7 U+0397 Eta +!C8 U+0398 Theta +!C9 U+0399 Iota +!CA U+039A Kappa +!CB U+039B Lambda +!CC U+039C Mu +!CD U+039D Nu +!CE U+039E Xi +!CF U+039F Omicron +!D0 U+03A0 Pi +!D1 U+03A1 Rho +!D3 U+03A3 Sigma +!D4 U+03A4 Tau +!D5 U+03A5 Upsilon +!D6 U+03A6 Phi +!D7 U+03A7 Chi +!D8 U+03A8 Psi +!D9 U+03A9 Omega +!DA U+03AA Iotadieresis +!DB U+03AB Upsilondieresis +!DC U+03AC alphatonos +!DD U+03AD epsilontonos +!DE U+03AE etatonos +!DF U+03AF iotatonos +!E0 U+03B0 upsilondieresistonos +!E1 U+03B1 alpha +!E2 U+03B2 beta +!E3 U+03B3 gamma +!E4 U+03B4 delta +!E5 U+03B5 epsilon +!E6 U+03B6 zeta +!E7 U+03B7 eta +!E8 U+03B8 theta +!E9 U+03B9 iota +!EA U+03BA kappa +!EB U+03BB lambda +!EC U+03BC mu +!ED U+03BD nu +!EE U+03BE xi +!EF U+03BF omicron +!F0 U+03C0 pi +!F1 U+03C1 rho +!F2 U+03C2 sigma1 +!F3 U+03C3 sigma +!F4 U+03C4 tau +!F5 U+03C5 upsilon +!F6 U+03C6 phi +!F7 U+03C7 chi +!F8 U+03C8 psi +!F9 U+03C9 omega +!FA U+03CA iotadieresis +!FB U+03CB upsilondieresis +!FC U+03CC omicrontonos +!FD U+03CD upsilontonos +!FE U+03CE omegatonos diff --git a/font/cp1254.map b/font/cp1254.map new file mode 100644 index 0000000..829473b --- /dev/null +++ b/font/cp1254.map @@ -0,0 +1,249 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+02C6 circumflex +!89 U+2030 perthousand +!8A U+0160 Scaron +!8B U+2039 guilsinglleft +!8C U+0152 OE +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!98 U+02DC tilde +!99 U+2122 trademark +!9A U+0161 scaron +!9B U+203A guilsinglright +!9C U+0153 oe +!9F U+0178 Ydieresis +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+011E Gbreve +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+0130 Idotaccent +!DE U+015E Scedilla +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+011F gbreve +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+0131 dotlessi +!FE U+015F scedilla +!FF U+00FF ydieresis diff --git a/font/cp1255.map b/font/cp1255.map new file mode 100644 index 0000000..079e10c --- /dev/null +++ b/font/cp1255.map @@ -0,0 +1,233 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+02C6 circumflex +!89 U+2030 perthousand +!8B U+2039 guilsinglleft +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!98 U+02DC tilde +!99 U+2122 trademark +!9B U+203A guilsinglright +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+20AA afii57636 +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00D7 multiply +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD sfthyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 middot +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00F7 divide +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+05B0 afii57799 +!C1 U+05B1 afii57801 +!C2 U+05B2 afii57800 +!C3 U+05B3 afii57802 +!C4 U+05B4 afii57793 +!C5 U+05B5 afii57794 +!C6 U+05B6 afii57795 +!C7 U+05B7 afii57798 +!C8 U+05B8 afii57797 +!C9 U+05B9 afii57806 +!CB U+05BB afii57796 +!CC U+05BC afii57807 +!CD U+05BD afii57839 +!CE U+05BE afii57645 +!CF U+05BF afii57841 +!D0 U+05C0 afii57842 +!D1 U+05C1 afii57804 +!D2 U+05C2 afii57803 +!D3 U+05C3 afii57658 +!D4 U+05F0 afii57716 +!D5 U+05F1 afii57717 +!D6 U+05F2 afii57718 +!D7 U+05F3 gereshhebrew +!D8 U+05F4 gershayimhebrew +!E0 U+05D0 afii57664 +!E1 U+05D1 afii57665 +!E2 U+05D2 afii57666 +!E3 U+05D3 afii57667 +!E4 U+05D4 afii57668 +!E5 U+05D5 afii57669 +!E6 U+05D6 afii57670 +!E7 U+05D7 afii57671 +!E8 U+05D8 afii57672 +!E9 U+05D9 afii57673 +!EA U+05DA afii57674 +!EB U+05DB afii57675 +!EC U+05DC afii57676 +!ED U+05DD afii57677 +!EE U+05DE afii57678 +!EF U+05DF afii57679 +!F0 U+05E0 afii57680 +!F1 U+05E1 afii57681 +!F2 U+05E2 afii57682 +!F3 U+05E3 afii57683 +!F4 U+05E4 afii57684 +!F5 U+05E5 afii57685 +!F6 U+05E6 afii57686 +!F7 U+05E7 afii57687 +!F8 U+05E8 afii57688 +!F9 U+05E9 afii57689 +!FA U+05EA afii57690 +!FD U+200E afii299 +!FE U+200F afii300 diff --git a/font/cp1257.map b/font/cp1257.map new file mode 100644 index 0000000..2f2ecfa --- /dev/null +++ b/font/cp1257.map @@ -0,0 +1,244 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!89 U+2030 perthousand +!8B U+2039 guilsinglleft +!8D U+00A8 dieresis +!8E U+02C7 caron +!8F U+00B8 cedilla +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!99 U+2122 trademark +!9B U+203A guilsinglright +!9D U+00AF macron +!9E U+02DB ogonek +!A0 U+00A0 space +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00D8 Oslash +!A9 U+00A9 copyright +!AA U+0156 Rcommaaccent +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00C6 AE +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00F8 oslash +!B9 U+00B9 onesuperior +!BA U+0157 rcommaaccent +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00E6 ae +!C0 U+0104 Aogonek +!C1 U+012E Iogonek +!C2 U+0100 Amacron +!C3 U+0106 Cacute +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+0118 Eogonek +!C7 U+0112 Emacron +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0179 Zacute +!CB U+0116 Edotaccent +!CC U+0122 Gcommaaccent +!CD U+0136 Kcommaaccent +!CE U+012A Imacron +!CF U+013B Lcommaaccent +!D0 U+0160 Scaron +!D1 U+0143 Nacute +!D2 U+0145 Ncommaaccent +!D3 U+00D3 Oacute +!D4 U+014C Omacron +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+0172 Uogonek +!D9 U+0141 Lslash +!DA U+015A Sacute +!DB U+016A Umacron +!DC U+00DC Udieresis +!DD U+017B Zdotaccent +!DE U+017D Zcaron +!DF U+00DF germandbls +!E0 U+0105 aogonek +!E1 U+012F iogonek +!E2 U+0101 amacron +!E3 U+0107 cacute +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+0119 eogonek +!E7 U+0113 emacron +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+017A zacute +!EB U+0117 edotaccent +!EC U+0123 gcommaaccent +!ED U+0137 kcommaaccent +!EE U+012B imacron +!EF U+013C lcommaaccent +!F0 U+0161 scaron +!F1 U+0144 nacute +!F2 U+0146 ncommaaccent +!F3 U+00F3 oacute +!F4 U+014D omacron +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+0173 uogonek +!F9 U+0142 lslash +!FA U+015B sacute +!FB U+016B umacron +!FC U+00FC udieresis +!FD U+017C zdotaccent +!FE U+017E zcaron +!FF U+02D9 dotaccent diff --git a/font/cp1258.map b/font/cp1258.map new file mode 100644 index 0000000..fed915f --- /dev/null +++ b/font/cp1258.map @@ -0,0 +1,247 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!82 U+201A quotesinglbase +!83 U+0192 florin +!84 U+201E quotedblbase +!85 U+2026 ellipsis +!86 U+2020 dagger +!87 U+2021 daggerdbl +!88 U+02C6 circumflex +!89 U+2030 perthousand +!8B U+2039 guilsinglleft +!8C U+0152 OE +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!98 U+02DC tilde +!99 U+2122 trademark +!9B U+203A guilsinglright +!9C U+0153 oe +!9F U+0178 Ydieresis +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+0102 Abreve +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+0300 gravecomb +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+0110 Dcroat +!D1 U+00D1 Ntilde +!D2 U+0309 hookabovecomb +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+01A0 Ohorn +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+01AF Uhorn +!DE U+0303 tildecomb +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+0103 abreve +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+0301 acutecomb +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+0111 dcroat +!F1 U+00F1 ntilde +!F2 U+0323 dotbelowcomb +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+01A1 ohorn +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+01B0 uhorn +!FE U+20AB dong +!FF U+00FF ydieresis diff --git a/font/cp874.map b/font/cp874.map new file mode 100644 index 0000000..1006e6b --- /dev/null +++ b/font/cp874.map @@ -0,0 +1,225 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+20AC Euro +!85 U+2026 ellipsis +!91 U+2018 quoteleft +!92 U+2019 quoteright +!93 U+201C quotedblleft +!94 U+201D quotedblright +!95 U+2022 bullet +!96 U+2013 endash +!97 U+2014 emdash +!A0 U+00A0 space +!A1 U+0E01 kokaithai +!A2 U+0E02 khokhaithai +!A3 U+0E03 khokhuatthai +!A4 U+0E04 khokhwaithai +!A5 U+0E05 khokhonthai +!A6 U+0E06 khorakhangthai +!A7 U+0E07 ngonguthai +!A8 U+0E08 chochanthai +!A9 U+0E09 chochingthai +!AA U+0E0A chochangthai +!AB U+0E0B sosothai +!AC U+0E0C chochoethai +!AD U+0E0D yoyingthai +!AE U+0E0E dochadathai +!AF U+0E0F topatakthai +!B0 U+0E10 thothanthai +!B1 U+0E11 thonangmonthothai +!B2 U+0E12 thophuthaothai +!B3 U+0E13 nonenthai +!B4 U+0E14 dodekthai +!B5 U+0E15 totaothai +!B6 U+0E16 thothungthai +!B7 U+0E17 thothahanthai +!B8 U+0E18 thothongthai +!B9 U+0E19 nonuthai +!BA U+0E1A bobaimaithai +!BB U+0E1B poplathai +!BC U+0E1C phophungthai +!BD U+0E1D fofathai +!BE U+0E1E phophanthai +!BF U+0E1F fofanthai +!C0 U+0E20 phosamphaothai +!C1 U+0E21 momathai +!C2 U+0E22 yoyakthai +!C3 U+0E23 roruathai +!C4 U+0E24 ruthai +!C5 U+0E25 lolingthai +!C6 U+0E26 luthai +!C7 U+0E27 wowaenthai +!C8 U+0E28 sosalathai +!C9 U+0E29 sorusithai +!CA U+0E2A sosuathai +!CB U+0E2B hohipthai +!CC U+0E2C lochulathai +!CD U+0E2D oangthai +!CE U+0E2E honokhukthai +!CF U+0E2F paiyannoithai +!D0 U+0E30 saraathai +!D1 U+0E31 maihanakatthai +!D2 U+0E32 saraaathai +!D3 U+0E33 saraamthai +!D4 U+0E34 saraithai +!D5 U+0E35 saraiithai +!D6 U+0E36 sarauethai +!D7 U+0E37 saraueethai +!D8 U+0E38 sarauthai +!D9 U+0E39 sarauuthai +!DA U+0E3A phinthuthai +!DF U+0E3F bahtthai +!E0 U+0E40 saraethai +!E1 U+0E41 saraaethai +!E2 U+0E42 saraothai +!E3 U+0E43 saraaimaimuanthai +!E4 U+0E44 saraaimaimalaithai +!E5 U+0E45 lakkhangyaothai +!E6 U+0E46 maiyamokthai +!E7 U+0E47 maitaikhuthai +!E8 U+0E48 maiekthai +!E9 U+0E49 maithothai +!EA U+0E4A maitrithai +!EB U+0E4B maichattawathai +!EC U+0E4C thanthakhatthai +!ED U+0E4D nikhahitthai +!EE U+0E4E yamakkanthai +!EF U+0E4F fongmanthai +!F0 U+0E50 zerothai +!F1 U+0E51 onethai +!F2 U+0E52 twothai +!F3 U+0E53 threethai +!F4 U+0E54 fourthai +!F5 U+0E55 fivethai +!F6 U+0E56 sixthai +!F7 U+0E57 seventhai +!F8 U+0E58 eightthai +!F9 U+0E59 ninethai +!FA U+0E5A angkhankhuthai +!FB U+0E5B khomutthai diff --git a/font/helvetica.json b/font/helvetica.json new file mode 100644 index 0000000..2a8a93f --- /dev/null +++ b/font/helvetica.json @@ -0,0 +1 @@ +{"Tp":"Core","Name":"Helvetica","Up":-100,"Ut":50,"Cw":[278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,355,556,556,889,667,191,333,333,389,584,278,333,278,278,556,556,556,556,556,556,556,556,556,556,278,278,584,584,584,556,1015,667,667,722,722,667,611,778,722,278,500,667,556,833,722,778,667,778,722,667,611,722,667,944,667,667,611,278,278,278,469,556,333,556,556,500,556,556,278,556,556,222,222,500,222,833,556,556,556,556,333,500,278,556,500,722,500,500,500,334,260,334,584,350,556,350,222,556,333,1000,556,556,333,1000,667,333,1000,350,611,350,350,222,222,333,333,350,556,1000,333,1000,500,333,944,350,500,667,278,333,556,556,556,556,260,556,333,737,370,556,584,333,737,333,400,584,333,333,333,556,537,278,333,333,365,556,834,834,834,611,667,667,667,667,667,667,1000,722,667,667,667,667,278,278,278,278,722,722,778,778,778,778,778,584,778,722,722,722,722,667,667,611,556,556,556,556,556,556,889,500,556,556,556,556,278,278,278,278,556,556,556,556,556,556,556,584,611,556,556,556,556,500,556,500]} \ No newline at end of file diff --git a/font/helvetica_1251.json b/font/helvetica_1251.json new file mode 100644 index 0000000..3adff6a --- /dev/null +++ b/font/helvetica_1251.json @@ -0,0 +1 @@ +{"Tp":"TrueType","Name":"ArialMT","Desc":{"Ascent":728,"Descent":-210,"CapHeight":728,"Flags":32,"FontBBox":{"Xmin":-665,"Ymin":-325,"Xmax":2028,"Ymax":1037},"ItalicAngle":0,"StemV":70,"MissingWidth":750},"Up":-106,"Ut":73,"Cw":[750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,278,278,355,556,556,889,667,191,333,333,389,584,278,333,278,278,556,556,556,556,556,556,556,556,556,556,278,278,584,584,584,556,1015,667,667,722,722,667,611,778,722,278,500,667,556,833,722,778,667,778,722,667,611,722,667,944,667,667,611,278,278,278,469,556,333,556,556,500,556,556,278,556,556,222,222,500,222,833,556,556,556,556,333,500,278,556,500,722,500,500,500,334,260,334,584,750,865,542,222,365,333,1000,556,556,556,1000,1057,333,1010,583,854,719,556,222,222,333,333,350,556,1000,750,1000,906,333,813,438,556,552,278,635,500,500,556,489,260,556,667,737,719,556,584,333,737,278,400,549,278,222,411,576,537,278,556,1073,510,556,222,667,500,278,667,656,667,542,677,667,923,604,719,719,583,656,833,722,778,719,667,722,611,635,760,667,740,667,917,938,792,885,656,719,1010,722,556,573,531,365,583,556,669,458,559,559,438,583,688,552,556,542,556,500,458,500,823,500,573,521,802,823,625,719,521,510,750,542],"Enc":"cp1251","Diff":"128 /afii10051 /afii10052 131 /afii10100 136 /Euro 138 /afii10058 140 /afii10059 /afii10061 /afii10060 /afii10145 /afii10099 152 /.notdef 154 /afii10106 156 /afii10107 /afii10109 /afii10108 /afii10193 161 /afii10062 /afii10110 /afii10057 165 /afii10050 168 /afii10023 170 /afii10053 175 /afii10056 178 /afii10055 /afii10103 /afii10098 184 /afii10071 /afii61352 /afii10101 188 /afii10105 /afii10054 /afii10102 /afii10104 /afii10017 /afii10018 /afii10019 /afii10020 /afii10021 /afii10022 /afii10024 /afii10025 /afii10026 /afii10027 /afii10028 /afii10029 /afii10030 /afii10031 /afii10032 /afii10033 /afii10034 /afii10035 /afii10036 /afii10037 /afii10038 /afii10039 /afii10040 /afii10041 /afii10042 /afii10043 /afii10044 /afii10045 /afii10046 /afii10047 /afii10048 /afii10049 /afii10065 /afii10066 /afii10067 /afii10068 /afii10069 /afii10070 /afii10072 /afii10073 /afii10074 /afii10075 /afii10076 /afii10077 /afii10078 /afii10079 /afii10080 /afii10081 /afii10082 /afii10083 /afii10084 /afii10085 /afii10086 /afii10087 /afii10088 /afii10089 /afii10090 /afii10091 /afii10092 /afii10093 /afii10094 /afii10095 /afii10096 /afii10097","File":"helvetica_1251.z","Size1":0,"Size2":0,"OriginalSize":275572,"I":0,"N":0,"DiffN":0} \ No newline at end of file diff --git a/font/helvetica_1251.z b/font/helvetica_1251.z new file mode 100644 index 0000000..91f0455 Binary files /dev/null and b/font/helvetica_1251.z differ diff --git a/font/helvetica_1253.json b/font/helvetica_1253.json new file mode 100644 index 0000000..c4cd2e3 --- /dev/null +++ b/font/helvetica_1253.json @@ -0,0 +1 @@ +{"Tp":"TrueType","Name":"ArialMT","Desc":{"Ascent":728,"Descent":-210,"CapHeight":728,"Flags":32,"FontBBox":{"Xmin":-665,"Ymin":-325,"Xmax":2028,"Ymax":1037},"ItalicAngle":0,"StemV":70,"MissingWidth":750},"Up":-106,"Ut":73,"Cw":[750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,750,278,278,355,556,556,889,667,191,333,333,389,584,278,333,278,278,556,556,556,556,556,556,556,556,556,556,278,278,584,584,584,556,1015,667,667,722,722,667,611,778,722,278,500,667,556,833,722,778,667,778,722,667,611,722,667,944,667,667,611,278,278,278,469,556,333,556,556,500,556,556,278,556,556,222,222,500,222,833,556,556,556,556,333,500,278,556,500,722,500,500,500,334,260,334,584,750,556,750,222,556,333,1000,556,556,750,1000,750,333,750,750,750,750,750,222,222,333,333,350,556,1000,750,1000,750,333,750,750,750,750,278,333,667,556,556,556,260,556,333,737,750,556,584,333,737,1000,400,549,333,333,333,576,537,278,784,838,384,556,774,834,855,752,222,667,667,551,668,667,611,722,778,278,667,668,833,722,650,778,722,667,750,618,611,667,798,667,835,748,278,667,578,446,556,222,547,578,575,500,557,446,441,556,556,222,500,500,576,500,448,556,690,569,482,617,395,547,648,525,713,781,222,547,556,547,781,750],"Enc":"cp1253","Diff":"136 /.notdef 138 /.notdef 140 /.notdef 142 /.notdef 152 /.notdef 154 /.notdef 156 /.notdef 158 /.notdef /.notdef 161 /dieresistonos /Alphatonos 170 /.notdef 175 /afii00208 180 /tonos 184 /Epsilontonos /Etatonos /Iotatonos 188 /Omicrontonos 190 /Upsilontonos /Omegatonos /iotadieresistonos /Alpha /Beta /Gamma /Delta /Epsilon /Zeta /Eta /Theta /Iota /Kappa /Lambda /Mu /Nu /Xi /Omicron /Pi /Rho /.notdef /Sigma /Tau /Upsilon /Phi /Chi /Psi /Omega /Iotadieresis /Upsilondieresis /alphatonos /epsilontonos /etatonos /iotatonos /upsilondieresistonos /alpha /beta /gamma /delta /epsilon /zeta /eta /theta /iota /kappa /lambda /mu /nu /xi /omicron /pi /rho /sigma1 /sigma /tau /upsilon /phi /chi /psi /omega /iotadieresis /upsilondieresis /omicrontonos /upsilontonos /omegatonos /.notdef","File":"helvetica_1253.z","Size1":0,"Size2":0,"OriginalSize":275572,"I":0,"N":0,"DiffN":0} \ No newline at end of file diff --git a/font/helvetica_1253.z b/font/helvetica_1253.z new file mode 100644 index 0000000..91f0455 Binary files /dev/null and b/font/helvetica_1253.z differ diff --git a/font/helveticab.json b/font/helveticab.json new file mode 100644 index 0000000..198c2a2 --- /dev/null +++ b/font/helveticab.json @@ -0,0 +1 @@ +{"Tp":"Core","Name":"Helvetica-Bold","Up":-100,"Ut":50,"Cw":[278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,333,474,556,556,889,722,238,333,333,389,584,278,333,278,278,556,556,556,556,556,556,556,556,556,556,333,333,584,584,584,611,975,722,722,722,722,667,611,778,722,278,556,722,611,833,722,778,667,778,722,667,611,722,667,944,667,667,611,333,278,333,584,556,333,556,611,556,611,556,333,611,611,278,278,556,278,889,611,611,611,611,389,556,333,611,556,778,556,556,500,389,280,389,584,350,556,350,278,556,500,1000,556,556,333,1000,667,333,1000,350,611,350,350,278,278,500,500,350,556,1000,333,1000,556,333,944,350,500,667,278,333,556,556,556,556,280,556,333,737,370,556,584,333,737,333,400,584,333,333,333,611,556,278,333,333,365,556,834,834,834,611,722,722,722,722,722,722,1000,722,667,667,667,667,278,278,278,278,722,722,778,778,778,778,778,584,778,722,722,722,722,667,667,611,556,556,556,556,556,556,889,556,556,556,556,556,278,278,278,278,611,611,611,611,611,611,611,584,611,611,611,611,611,556,611,556]} \ No newline at end of file diff --git a/font/helveticabi.json b/font/helveticabi.json new file mode 100644 index 0000000..afc3024 --- /dev/null +++ b/font/helveticabi.json @@ -0,0 +1 @@ +{"Tp":"Core","Name":"Helvetica-BoldOblique","Up":-100,"Ut":50,"Cw":[278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,333,474,556,556,889,722,238,333,333,389,584,278,333,278,278,556,556,556,556,556,556,556,556,556,556,333,333,584,584,584,611,975,722,722,722,722,667,611,778,722,278,556,722,611,833,722,778,667,778,722,667,611,722,667,944,667,667,611,333,278,333,584,556,333,556,611,556,611,556,333,611,611,278,278,556,278,889,611,611,611,611,389,556,333,611,556,778,556,556,500,389,280,389,584,350,556,350,278,556,500,1000,556,556,333,1000,667,333,1000,350,611,350,350,278,278,500,500,350,556,1000,333,1000,556,333,944,350,500,667,278,333,556,556,556,556,280,556,333,737,370,556,584,333,737,333,400,584,333,333,333,611,556,278,333,333,365,556,834,834,834,611,722,722,722,722,722,722,1000,722,667,667,667,667,278,278,278,278,722,722,778,778,778,778,778,584,778,722,722,722,722,667,667,611,556,556,556,556,556,556,889,556,556,556,556,556,278,278,278,278,611,611,611,611,611,611,611,584,611,611,611,611,611,556,611,556]} \ No newline at end of file diff --git a/font/helveticai.json b/font/helveticai.json new file mode 100644 index 0000000..502f938 --- /dev/null +++ b/font/helveticai.json @@ -0,0 +1 @@ +{"Tp":"Core","Name":"Helvetica-Oblique","Up":-100,"Ut":50,"Cw":[278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,355,556,556,889,667,191,333,333,389,584,278,333,278,278,556,556,556,556,556,556,556,556,556,556,278,278,584,584,584,556,1015,667,667,722,722,667,611,778,722,278,500,667,556,833,722,778,667,778,722,667,611,722,667,944,667,667,611,278,278,278,469,556,333,556,556,500,556,556,278,556,556,222,222,500,222,833,556,556,556,556,333,500,278,556,500,722,500,500,500,334,260,334,584,350,556,350,222,556,333,1000,556,556,333,1000,667,333,1000,350,611,350,350,222,222,333,333,350,556,1000,333,1000,500,333,944,350,500,667,278,333,556,556,556,556,260,556,333,737,370,556,584,333,737,333,400,584,333,333,333,556,537,278,333,333,365,556,834,834,834,611,667,667,667,667,667,667,1000,722,667,667,667,667,278,278,278,278,722,722,778,778,778,778,778,584,778,722,722,722,722,667,667,611,556,556,556,556,556,556,889,500,556,556,556,556,278,278,278,278,556,556,556,556,556,556,556,584,611,556,556,556,556,500,556,500]} \ No newline at end of file diff --git a/font/iso-8859-1.map b/font/iso-8859-1.map new file mode 100644 index 0000000..61740a3 --- /dev/null +++ b/font/iso-8859-1.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+00D0 Eth +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+00DE Thorn +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+00F0 eth +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+00FE thorn +!FF U+00FF ydieresis diff --git a/font/iso-8859-11.map b/font/iso-8859-11.map new file mode 100644 index 0000000..9168812 --- /dev/null +++ b/font/iso-8859-11.map @@ -0,0 +1,248 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0E01 kokaithai +!A2 U+0E02 khokhaithai +!A3 U+0E03 khokhuatthai +!A4 U+0E04 khokhwaithai +!A5 U+0E05 khokhonthai +!A6 U+0E06 khorakhangthai +!A7 U+0E07 ngonguthai +!A8 U+0E08 chochanthai +!A9 U+0E09 chochingthai +!AA U+0E0A chochangthai +!AB U+0E0B sosothai +!AC U+0E0C chochoethai +!AD U+0E0D yoyingthai +!AE U+0E0E dochadathai +!AF U+0E0F topatakthai +!B0 U+0E10 thothanthai +!B1 U+0E11 thonangmonthothai +!B2 U+0E12 thophuthaothai +!B3 U+0E13 nonenthai +!B4 U+0E14 dodekthai +!B5 U+0E15 totaothai +!B6 U+0E16 thothungthai +!B7 U+0E17 thothahanthai +!B8 U+0E18 thothongthai +!B9 U+0E19 nonuthai +!BA U+0E1A bobaimaithai +!BB U+0E1B poplathai +!BC U+0E1C phophungthai +!BD U+0E1D fofathai +!BE U+0E1E phophanthai +!BF U+0E1F fofanthai +!C0 U+0E20 phosamphaothai +!C1 U+0E21 momathai +!C2 U+0E22 yoyakthai +!C3 U+0E23 roruathai +!C4 U+0E24 ruthai +!C5 U+0E25 lolingthai +!C6 U+0E26 luthai +!C7 U+0E27 wowaenthai +!C8 U+0E28 sosalathai +!C9 U+0E29 sorusithai +!CA U+0E2A sosuathai +!CB U+0E2B hohipthai +!CC U+0E2C lochulathai +!CD U+0E2D oangthai +!CE U+0E2E honokhukthai +!CF U+0E2F paiyannoithai +!D0 U+0E30 saraathai +!D1 U+0E31 maihanakatthai +!D2 U+0E32 saraaathai +!D3 U+0E33 saraamthai +!D4 U+0E34 saraithai +!D5 U+0E35 saraiithai +!D6 U+0E36 sarauethai +!D7 U+0E37 saraueethai +!D8 U+0E38 sarauthai +!D9 U+0E39 sarauuthai +!DA U+0E3A phinthuthai +!DF U+0E3F bahtthai +!E0 U+0E40 saraethai +!E1 U+0E41 saraaethai +!E2 U+0E42 saraothai +!E3 U+0E43 saraaimaimuanthai +!E4 U+0E44 saraaimaimalaithai +!E5 U+0E45 lakkhangyaothai +!E6 U+0E46 maiyamokthai +!E7 U+0E47 maitaikhuthai +!E8 U+0E48 maiekthai +!E9 U+0E49 maithothai +!EA U+0E4A maitrithai +!EB U+0E4B maichattawathai +!EC U+0E4C thanthakhatthai +!ED U+0E4D nikhahitthai +!EE U+0E4E yamakkanthai +!EF U+0E4F fongmanthai +!F0 U+0E50 zerothai +!F1 U+0E51 onethai +!F2 U+0E52 twothai +!F3 U+0E53 threethai +!F4 U+0E54 fourthai +!F5 U+0E55 fivethai +!F6 U+0E56 sixthai +!F7 U+0E57 seventhai +!F8 U+0E58 eightthai +!F9 U+0E59 ninethai +!FA U+0E5A angkhankhuthai +!FB U+0E5B khomutthai diff --git a/font/iso-8859-15.map b/font/iso-8859-15.map new file mode 100644 index 0000000..6c2b571 --- /dev/null +++ b/font/iso-8859-15.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+20AC Euro +!A5 U+00A5 yen +!A6 U+0160 Scaron +!A7 U+00A7 section +!A8 U+0161 scaron +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+017D Zcaron +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+017E zcaron +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+0152 OE +!BD U+0153 oe +!BE U+0178 Ydieresis +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+00D0 Eth +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+00DE Thorn +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+00F0 eth +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+00FE thorn +!FF U+00FF ydieresis diff --git a/font/iso-8859-16.map b/font/iso-8859-16.map new file mode 100644 index 0000000..202c8fe --- /dev/null +++ b/font/iso-8859-16.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0104 Aogonek +!A2 U+0105 aogonek +!A3 U+0141 Lslash +!A4 U+20AC Euro +!A5 U+201E quotedblbase +!A6 U+0160 Scaron +!A7 U+00A7 section +!A8 U+0161 scaron +!A9 U+00A9 copyright +!AA U+0218 Scommaaccent +!AB U+00AB guillemotleft +!AC U+0179 Zacute +!AD U+00AD hyphen +!AE U+017A zacute +!AF U+017B Zdotaccent +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+010C Ccaron +!B3 U+0142 lslash +!B4 U+017D Zcaron +!B5 U+201D quotedblright +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+017E zcaron +!B9 U+010D ccaron +!BA U+0219 scommaaccent +!BB U+00BB guillemotright +!BC U+0152 OE +!BD U+0153 oe +!BE U+0178 Ydieresis +!BF U+017C zdotaccent +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+0102 Abreve +!C4 U+00C4 Adieresis +!C5 U+0106 Cacute +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+0110 Dcroat +!D1 U+0143 Nacute +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+0150 Ohungarumlaut +!D6 U+00D6 Odieresis +!D7 U+015A Sacute +!D8 U+0170 Uhungarumlaut +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+0118 Eogonek +!DE U+021A Tcommaaccent +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+0103 abreve +!E4 U+00E4 adieresis +!E5 U+0107 cacute +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+0111 dcroat +!F1 U+0144 nacute +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+0151 ohungarumlaut +!F6 U+00F6 odieresis +!F7 U+015B sacute +!F8 U+0171 uhungarumlaut +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+0119 eogonek +!FE U+021B tcommaaccent +!FF U+00FF ydieresis diff --git a/font/iso-8859-2.map b/font/iso-8859-2.map new file mode 100644 index 0000000..65ae09f --- /dev/null +++ b/font/iso-8859-2.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0104 Aogonek +!A2 U+02D8 breve +!A3 U+0141 Lslash +!A4 U+00A4 currency +!A5 U+013D Lcaron +!A6 U+015A Sacute +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+0160 Scaron +!AA U+015E Scedilla +!AB U+0164 Tcaron +!AC U+0179 Zacute +!AD U+00AD hyphen +!AE U+017D Zcaron +!AF U+017B Zdotaccent +!B0 U+00B0 degree +!B1 U+0105 aogonek +!B2 U+02DB ogonek +!B3 U+0142 lslash +!B4 U+00B4 acute +!B5 U+013E lcaron +!B6 U+015B sacute +!B7 U+02C7 caron +!B8 U+00B8 cedilla +!B9 U+0161 scaron +!BA U+015F scedilla +!BB U+0165 tcaron +!BC U+017A zacute +!BD U+02DD hungarumlaut +!BE U+017E zcaron +!BF U+017C zdotaccent +!C0 U+0154 Racute +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+0102 Abreve +!C4 U+00C4 Adieresis +!C5 U+0139 Lacute +!C6 U+0106 Cacute +!C7 U+00C7 Ccedilla +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0118 Eogonek +!CB U+00CB Edieresis +!CC U+011A Ecaron +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+010E Dcaron +!D0 U+0110 Dcroat +!D1 U+0143 Nacute +!D2 U+0147 Ncaron +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+0150 Ohungarumlaut +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+0158 Rcaron +!D9 U+016E Uring +!DA U+00DA Uacute +!DB U+0170 Uhungarumlaut +!DC U+00DC Udieresis +!DD U+00DD Yacute +!DE U+0162 Tcommaaccent +!DF U+00DF germandbls +!E0 U+0155 racute +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+0103 abreve +!E4 U+00E4 adieresis +!E5 U+013A lacute +!E6 U+0107 cacute +!E7 U+00E7 ccedilla +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+0119 eogonek +!EB U+00EB edieresis +!EC U+011B ecaron +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+010F dcaron +!F0 U+0111 dcroat +!F1 U+0144 nacute +!F2 U+0148 ncaron +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+0151 ohungarumlaut +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+0159 rcaron +!F9 U+016F uring +!FA U+00FA uacute +!FB U+0171 uhungarumlaut +!FC U+00FC udieresis +!FD U+00FD yacute +!FE U+0163 tcommaaccent +!FF U+02D9 dotaccent diff --git a/font/iso-8859-4.map b/font/iso-8859-4.map new file mode 100644 index 0000000..a7d87bf --- /dev/null +++ b/font/iso-8859-4.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0104 Aogonek +!A2 U+0138 kgreenlandic +!A3 U+0156 Rcommaaccent +!A4 U+00A4 currency +!A5 U+0128 Itilde +!A6 U+013B Lcommaaccent +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+0160 Scaron +!AA U+0112 Emacron +!AB U+0122 Gcommaaccent +!AC U+0166 Tbar +!AD U+00AD hyphen +!AE U+017D Zcaron +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+0105 aogonek +!B2 U+02DB ogonek +!B3 U+0157 rcommaaccent +!B4 U+00B4 acute +!B5 U+0129 itilde +!B6 U+013C lcommaaccent +!B7 U+02C7 caron +!B8 U+00B8 cedilla +!B9 U+0161 scaron +!BA U+0113 emacron +!BB U+0123 gcommaaccent +!BC U+0167 tbar +!BD U+014A Eng +!BE U+017E zcaron +!BF U+014B eng +!C0 U+0100 Amacron +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+012E Iogonek +!C8 U+010C Ccaron +!C9 U+00C9 Eacute +!CA U+0118 Eogonek +!CB U+00CB Edieresis +!CC U+0116 Edotaccent +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+012A Imacron +!D0 U+0110 Dcroat +!D1 U+0145 Ncommaaccent +!D2 U+014C Omacron +!D3 U+0136 Kcommaaccent +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+0172 Uogonek +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+0168 Utilde +!DE U+016A Umacron +!DF U+00DF germandbls +!E0 U+0101 amacron +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+012F iogonek +!E8 U+010D ccaron +!E9 U+00E9 eacute +!EA U+0119 eogonek +!EB U+00EB edieresis +!EC U+0117 edotaccent +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+012B imacron +!F0 U+0111 dcroat +!F1 U+0146 ncommaaccent +!F2 U+014D omacron +!F3 U+0137 kcommaaccent +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+0173 uogonek +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+0169 utilde +!FE U+016B umacron +!FF U+02D9 dotaccent diff --git a/font/iso-8859-5.map b/font/iso-8859-5.map new file mode 100644 index 0000000..f9cd4ed --- /dev/null +++ b/font/iso-8859-5.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+0401 afii10023 +!A2 U+0402 afii10051 +!A3 U+0403 afii10052 +!A4 U+0404 afii10053 +!A5 U+0405 afii10054 +!A6 U+0406 afii10055 +!A7 U+0407 afii10056 +!A8 U+0408 afii10057 +!A9 U+0409 afii10058 +!AA U+040A afii10059 +!AB U+040B afii10060 +!AC U+040C afii10061 +!AD U+00AD hyphen +!AE U+040E afii10062 +!AF U+040F afii10145 +!B0 U+0410 afii10017 +!B1 U+0411 afii10018 +!B2 U+0412 afii10019 +!B3 U+0413 afii10020 +!B4 U+0414 afii10021 +!B5 U+0415 afii10022 +!B6 U+0416 afii10024 +!B7 U+0417 afii10025 +!B8 U+0418 afii10026 +!B9 U+0419 afii10027 +!BA U+041A afii10028 +!BB U+041B afii10029 +!BC U+041C afii10030 +!BD U+041D afii10031 +!BE U+041E afii10032 +!BF U+041F afii10033 +!C0 U+0420 afii10034 +!C1 U+0421 afii10035 +!C2 U+0422 afii10036 +!C3 U+0423 afii10037 +!C4 U+0424 afii10038 +!C5 U+0425 afii10039 +!C6 U+0426 afii10040 +!C7 U+0427 afii10041 +!C8 U+0428 afii10042 +!C9 U+0429 afii10043 +!CA U+042A afii10044 +!CB U+042B afii10045 +!CC U+042C afii10046 +!CD U+042D afii10047 +!CE U+042E afii10048 +!CF U+042F afii10049 +!D0 U+0430 afii10065 +!D1 U+0431 afii10066 +!D2 U+0432 afii10067 +!D3 U+0433 afii10068 +!D4 U+0434 afii10069 +!D5 U+0435 afii10070 +!D6 U+0436 afii10072 +!D7 U+0437 afii10073 +!D8 U+0438 afii10074 +!D9 U+0439 afii10075 +!DA U+043A afii10076 +!DB U+043B afii10077 +!DC U+043C afii10078 +!DD U+043D afii10079 +!DE U+043E afii10080 +!DF U+043F afii10081 +!E0 U+0440 afii10082 +!E1 U+0441 afii10083 +!E2 U+0442 afii10084 +!E3 U+0443 afii10085 +!E4 U+0444 afii10086 +!E5 U+0445 afii10087 +!E6 U+0446 afii10088 +!E7 U+0447 afii10089 +!E8 U+0448 afii10090 +!E9 U+0449 afii10091 +!EA U+044A afii10092 +!EB U+044B afii10093 +!EC U+044C afii10094 +!ED U+044D afii10095 +!EE U+044E afii10096 +!EF U+044F afii10097 +!F0 U+2116 afii61352 +!F1 U+0451 afii10071 +!F2 U+0452 afii10099 +!F3 U+0453 afii10100 +!F4 U+0454 afii10101 +!F5 U+0455 afii10102 +!F6 U+0456 afii10103 +!F7 U+0457 afii10104 +!F8 U+0458 afii10105 +!F9 U+0459 afii10106 +!FA U+045A afii10107 +!FB U+045B afii10108 +!FC U+045C afii10109 +!FD U+00A7 section +!FE U+045E afii10110 +!FF U+045F afii10193 diff --git a/font/iso-8859-7.map b/font/iso-8859-7.map new file mode 100644 index 0000000..e163796 --- /dev/null +++ b/font/iso-8859-7.map @@ -0,0 +1,250 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+2018 quoteleft +!A2 U+2019 quoteright +!A3 U+00A3 sterling +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AF U+2015 afii00208 +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+0384 tonos +!B5 U+0385 dieresistonos +!B6 U+0386 Alphatonos +!B7 U+00B7 periodcentered +!B8 U+0388 Epsilontonos +!B9 U+0389 Etatonos +!BA U+038A Iotatonos +!BB U+00BB guillemotright +!BC U+038C Omicrontonos +!BD U+00BD onehalf +!BE U+038E Upsilontonos +!BF U+038F Omegatonos +!C0 U+0390 iotadieresistonos +!C1 U+0391 Alpha +!C2 U+0392 Beta +!C3 U+0393 Gamma +!C4 U+0394 Delta +!C5 U+0395 Epsilon +!C6 U+0396 Zeta +!C7 U+0397 Eta +!C8 U+0398 Theta +!C9 U+0399 Iota +!CA U+039A Kappa +!CB U+039B Lambda +!CC U+039C Mu +!CD U+039D Nu +!CE U+039E Xi +!CF U+039F Omicron +!D0 U+03A0 Pi +!D1 U+03A1 Rho +!D3 U+03A3 Sigma +!D4 U+03A4 Tau +!D5 U+03A5 Upsilon +!D6 U+03A6 Phi +!D7 U+03A7 Chi +!D8 U+03A8 Psi +!D9 U+03A9 Omega +!DA U+03AA Iotadieresis +!DB U+03AB Upsilondieresis +!DC U+03AC alphatonos +!DD U+03AD epsilontonos +!DE U+03AE etatonos +!DF U+03AF iotatonos +!E0 U+03B0 upsilondieresistonos +!E1 U+03B1 alpha +!E2 U+03B2 beta +!E3 U+03B3 gamma +!E4 U+03B4 delta +!E5 U+03B5 epsilon +!E6 U+03B6 zeta +!E7 U+03B7 eta +!E8 U+03B8 theta +!E9 U+03B9 iota +!EA U+03BA kappa +!EB U+03BB lambda +!EC U+03BC mu +!ED U+03BD nu +!EE U+03BE xi +!EF U+03BF omicron +!F0 U+03C0 pi +!F1 U+03C1 rho +!F2 U+03C2 sigma1 +!F3 U+03C3 sigma +!F4 U+03C4 tau +!F5 U+03C5 upsilon +!F6 U+03C6 phi +!F7 U+03C7 chi +!F8 U+03C8 psi +!F9 U+03C9 omega +!FA U+03CA iotadieresis +!FB U+03CB upsilondieresis +!FC U+03CC omicrontonos +!FD U+03CD upsilontonos +!FE U+03CE omegatonos diff --git a/font/iso-8859-9.map b/font/iso-8859-9.map new file mode 100644 index 0000000..48c123a --- /dev/null +++ b/font/iso-8859-9.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+0080 .notdef +!81 U+0081 .notdef +!82 U+0082 .notdef +!83 U+0083 .notdef +!84 U+0084 .notdef +!85 U+0085 .notdef +!86 U+0086 .notdef +!87 U+0087 .notdef +!88 U+0088 .notdef +!89 U+0089 .notdef +!8A U+008A .notdef +!8B U+008B .notdef +!8C U+008C .notdef +!8D U+008D .notdef +!8E U+008E .notdef +!8F U+008F .notdef +!90 U+0090 .notdef +!91 U+0091 .notdef +!92 U+0092 .notdef +!93 U+0093 .notdef +!94 U+0094 .notdef +!95 U+0095 .notdef +!96 U+0096 .notdef +!97 U+0097 .notdef +!98 U+0098 .notdef +!99 U+0099 .notdef +!9A U+009A .notdef +!9B U+009B .notdef +!9C U+009C .notdef +!9D U+009D .notdef +!9E U+009E .notdef +!9F U+009F .notdef +!A0 U+00A0 space +!A1 U+00A1 exclamdown +!A2 U+00A2 cent +!A3 U+00A3 sterling +!A4 U+00A4 currency +!A5 U+00A5 yen +!A6 U+00A6 brokenbar +!A7 U+00A7 section +!A8 U+00A8 dieresis +!A9 U+00A9 copyright +!AA U+00AA ordfeminine +!AB U+00AB guillemotleft +!AC U+00AC logicalnot +!AD U+00AD hyphen +!AE U+00AE registered +!AF U+00AF macron +!B0 U+00B0 degree +!B1 U+00B1 plusminus +!B2 U+00B2 twosuperior +!B3 U+00B3 threesuperior +!B4 U+00B4 acute +!B5 U+00B5 mu +!B6 U+00B6 paragraph +!B7 U+00B7 periodcentered +!B8 U+00B8 cedilla +!B9 U+00B9 onesuperior +!BA U+00BA ordmasculine +!BB U+00BB guillemotright +!BC U+00BC onequarter +!BD U+00BD onehalf +!BE U+00BE threequarters +!BF U+00BF questiondown +!C0 U+00C0 Agrave +!C1 U+00C1 Aacute +!C2 U+00C2 Acircumflex +!C3 U+00C3 Atilde +!C4 U+00C4 Adieresis +!C5 U+00C5 Aring +!C6 U+00C6 AE +!C7 U+00C7 Ccedilla +!C8 U+00C8 Egrave +!C9 U+00C9 Eacute +!CA U+00CA Ecircumflex +!CB U+00CB Edieresis +!CC U+00CC Igrave +!CD U+00CD Iacute +!CE U+00CE Icircumflex +!CF U+00CF Idieresis +!D0 U+011E Gbreve +!D1 U+00D1 Ntilde +!D2 U+00D2 Ograve +!D3 U+00D3 Oacute +!D4 U+00D4 Ocircumflex +!D5 U+00D5 Otilde +!D6 U+00D6 Odieresis +!D7 U+00D7 multiply +!D8 U+00D8 Oslash +!D9 U+00D9 Ugrave +!DA U+00DA Uacute +!DB U+00DB Ucircumflex +!DC U+00DC Udieresis +!DD U+0130 Idotaccent +!DE U+015E Scedilla +!DF U+00DF germandbls +!E0 U+00E0 agrave +!E1 U+00E1 aacute +!E2 U+00E2 acircumflex +!E3 U+00E3 atilde +!E4 U+00E4 adieresis +!E5 U+00E5 aring +!E6 U+00E6 ae +!E7 U+00E7 ccedilla +!E8 U+00E8 egrave +!E9 U+00E9 eacute +!EA U+00EA ecircumflex +!EB U+00EB edieresis +!EC U+00EC igrave +!ED U+00ED iacute +!EE U+00EE icircumflex +!EF U+00EF idieresis +!F0 U+011F gbreve +!F1 U+00F1 ntilde +!F2 U+00F2 ograve +!F3 U+00F3 oacute +!F4 U+00F4 ocircumflex +!F5 U+00F5 otilde +!F6 U+00F6 odieresis +!F7 U+00F7 divide +!F8 U+00F8 oslash +!F9 U+00F9 ugrave +!FA U+00FA uacute +!FB U+00FB ucircumflex +!FC U+00FC udieresis +!FD U+0131 dotlessi +!FE U+015F scedilla +!FF U+00FF ydieresis diff --git a/font/koi8-r.map b/font/koi8-r.map new file mode 100644 index 0000000..6ad5d05 --- /dev/null +++ b/font/koi8-r.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+2500 SF100000 +!81 U+2502 SF110000 +!82 U+250C SF010000 +!83 U+2510 SF030000 +!84 U+2514 SF020000 +!85 U+2518 SF040000 +!86 U+251C SF080000 +!87 U+2524 SF090000 +!88 U+252C SF060000 +!89 U+2534 SF070000 +!8A U+253C SF050000 +!8B U+2580 upblock +!8C U+2584 dnblock +!8D U+2588 block +!8E U+258C lfblock +!8F U+2590 rtblock +!90 U+2591 ltshade +!91 U+2592 shade +!92 U+2593 dkshade +!93 U+2320 integraltp +!94 U+25A0 filledbox +!95 U+2219 periodcentered +!96 U+221A radical +!97 U+2248 approxequal +!98 U+2264 lessequal +!99 U+2265 greaterequal +!9A U+00A0 space +!9B U+2321 integralbt +!9C U+00B0 degree +!9D U+00B2 twosuperior +!9E U+00B7 periodcentered +!9F U+00F7 divide +!A0 U+2550 SF430000 +!A1 U+2551 SF240000 +!A2 U+2552 SF510000 +!A3 U+0451 afii10071 +!A4 U+2553 SF520000 +!A5 U+2554 SF390000 +!A6 U+2555 SF220000 +!A7 U+2556 SF210000 +!A8 U+2557 SF250000 +!A9 U+2558 SF500000 +!AA U+2559 SF490000 +!AB U+255A SF380000 +!AC U+255B SF280000 +!AD U+255C SF270000 +!AE U+255D SF260000 +!AF U+255E SF360000 +!B0 U+255F SF370000 +!B1 U+2560 SF420000 +!B2 U+2561 SF190000 +!B3 U+0401 afii10023 +!B4 U+2562 SF200000 +!B5 U+2563 SF230000 +!B6 U+2564 SF470000 +!B7 U+2565 SF480000 +!B8 U+2566 SF410000 +!B9 U+2567 SF450000 +!BA U+2568 SF460000 +!BB U+2569 SF400000 +!BC U+256A SF540000 +!BD U+256B SF530000 +!BE U+256C SF440000 +!BF U+00A9 copyright +!C0 U+044E afii10096 +!C1 U+0430 afii10065 +!C2 U+0431 afii10066 +!C3 U+0446 afii10088 +!C4 U+0434 afii10069 +!C5 U+0435 afii10070 +!C6 U+0444 afii10086 +!C7 U+0433 afii10068 +!C8 U+0445 afii10087 +!C9 U+0438 afii10074 +!CA U+0439 afii10075 +!CB U+043A afii10076 +!CC U+043B afii10077 +!CD U+043C afii10078 +!CE U+043D afii10079 +!CF U+043E afii10080 +!D0 U+043F afii10081 +!D1 U+044F afii10097 +!D2 U+0440 afii10082 +!D3 U+0441 afii10083 +!D4 U+0442 afii10084 +!D5 U+0443 afii10085 +!D6 U+0436 afii10072 +!D7 U+0432 afii10067 +!D8 U+044C afii10094 +!D9 U+044B afii10093 +!DA U+0437 afii10073 +!DB U+0448 afii10090 +!DC U+044D afii10095 +!DD U+0449 afii10091 +!DE U+0447 afii10089 +!DF U+044A afii10092 +!E0 U+042E afii10048 +!E1 U+0410 afii10017 +!E2 U+0411 afii10018 +!E3 U+0426 afii10040 +!E4 U+0414 afii10021 +!E5 U+0415 afii10022 +!E6 U+0424 afii10038 +!E7 U+0413 afii10020 +!E8 U+0425 afii10039 +!E9 U+0418 afii10026 +!EA U+0419 afii10027 +!EB U+041A afii10028 +!EC U+041B afii10029 +!ED U+041C afii10030 +!EE U+041D afii10031 +!EF U+041E afii10032 +!F0 U+041F afii10033 +!F1 U+042F afii10049 +!F2 U+0420 afii10034 +!F3 U+0421 afii10035 +!F4 U+0422 afii10036 +!F5 U+0423 afii10037 +!F6 U+0416 afii10024 +!F7 U+0412 afii10019 +!F8 U+042C afii10046 +!F9 U+042B afii10045 +!FA U+0417 afii10025 +!FB U+0428 afii10042 +!FC U+042D afii10047 +!FD U+0429 afii10043 +!FE U+0427 afii10041 +!FF U+042A afii10044 diff --git a/font/koi8-u.map b/font/koi8-u.map new file mode 100644 index 0000000..40a7e4f --- /dev/null +++ b/font/koi8-u.map @@ -0,0 +1,256 @@ +!00 U+0000 .notdef +!01 U+0001 .notdef +!02 U+0002 .notdef +!03 U+0003 .notdef +!04 U+0004 .notdef +!05 U+0005 .notdef +!06 U+0006 .notdef +!07 U+0007 .notdef +!08 U+0008 .notdef +!09 U+0009 .notdef +!0A U+000A .notdef +!0B U+000B .notdef +!0C U+000C .notdef +!0D U+000D .notdef +!0E U+000E .notdef +!0F U+000F .notdef +!10 U+0010 .notdef +!11 U+0011 .notdef +!12 U+0012 .notdef +!13 U+0013 .notdef +!14 U+0014 .notdef +!15 U+0015 .notdef +!16 U+0016 .notdef +!17 U+0017 .notdef +!18 U+0018 .notdef +!19 U+0019 .notdef +!1A U+001A .notdef +!1B U+001B .notdef +!1C U+001C .notdef +!1D U+001D .notdef +!1E U+001E .notdef +!1F U+001F .notdef +!20 U+0020 space +!21 U+0021 exclam +!22 U+0022 quotedbl +!23 U+0023 numbersign +!24 U+0024 dollar +!25 U+0025 percent +!26 U+0026 ampersand +!27 U+0027 quotesingle +!28 U+0028 parenleft +!29 U+0029 parenright +!2A U+002A asterisk +!2B U+002B plus +!2C U+002C comma +!2D U+002D hyphen +!2E U+002E period +!2F U+002F slash +!30 U+0030 zero +!31 U+0031 one +!32 U+0032 two +!33 U+0033 three +!34 U+0034 four +!35 U+0035 five +!36 U+0036 six +!37 U+0037 seven +!38 U+0038 eight +!39 U+0039 nine +!3A U+003A colon +!3B U+003B semicolon +!3C U+003C less +!3D U+003D equal +!3E U+003E greater +!3F U+003F question +!40 U+0040 at +!41 U+0041 A +!42 U+0042 B +!43 U+0043 C +!44 U+0044 D +!45 U+0045 E +!46 U+0046 F +!47 U+0047 G +!48 U+0048 H +!49 U+0049 I +!4A U+004A J +!4B U+004B K +!4C U+004C L +!4D U+004D M +!4E U+004E N +!4F U+004F O +!50 U+0050 P +!51 U+0051 Q +!52 U+0052 R +!53 U+0053 S +!54 U+0054 T +!55 U+0055 U +!56 U+0056 V +!57 U+0057 W +!58 U+0058 X +!59 U+0059 Y +!5A U+005A Z +!5B U+005B bracketleft +!5C U+005C backslash +!5D U+005D bracketright +!5E U+005E asciicircum +!5F U+005F underscore +!60 U+0060 grave +!61 U+0061 a +!62 U+0062 b +!63 U+0063 c +!64 U+0064 d +!65 U+0065 e +!66 U+0066 f +!67 U+0067 g +!68 U+0068 h +!69 U+0069 i +!6A U+006A j +!6B U+006B k +!6C U+006C l +!6D U+006D m +!6E U+006E n +!6F U+006F o +!70 U+0070 p +!71 U+0071 q +!72 U+0072 r +!73 U+0073 s +!74 U+0074 t +!75 U+0075 u +!76 U+0076 v +!77 U+0077 w +!78 U+0078 x +!79 U+0079 y +!7A U+007A z +!7B U+007B braceleft +!7C U+007C bar +!7D U+007D braceright +!7E U+007E asciitilde +!7F U+007F .notdef +!80 U+2500 SF100000 +!81 U+2502 SF110000 +!82 U+250C SF010000 +!83 U+2510 SF030000 +!84 U+2514 SF020000 +!85 U+2518 SF040000 +!86 U+251C SF080000 +!87 U+2524 SF090000 +!88 U+252C SF060000 +!89 U+2534 SF070000 +!8A U+253C SF050000 +!8B U+2580 upblock +!8C U+2584 dnblock +!8D U+2588 block +!8E U+258C lfblock +!8F U+2590 rtblock +!90 U+2591 ltshade +!91 U+2592 shade +!92 U+2593 dkshade +!93 U+2320 integraltp +!94 U+25A0 filledbox +!95 U+2022 bullet +!96 U+221A radical +!97 U+2248 approxequal +!98 U+2264 lessequal +!99 U+2265 greaterequal +!9A U+00A0 space +!9B U+2321 integralbt +!9C U+00B0 degree +!9D U+00B2 twosuperior +!9E U+00B7 periodcentered +!9F U+00F7 divide +!A0 U+2550 SF430000 +!A1 U+2551 SF240000 +!A2 U+2552 SF510000 +!A3 U+0451 afii10071 +!A4 U+0454 afii10101 +!A5 U+2554 SF390000 +!A6 U+0456 afii10103 +!A7 U+0457 afii10104 +!A8 U+2557 SF250000 +!A9 U+2558 SF500000 +!AA U+2559 SF490000 +!AB U+255A SF380000 +!AC U+255B SF280000 +!AD U+0491 afii10098 +!AE U+255D SF260000 +!AF U+255E SF360000 +!B0 U+255F SF370000 +!B1 U+2560 SF420000 +!B2 U+2561 SF190000 +!B3 U+0401 afii10023 +!B4 U+0404 afii10053 +!B5 U+2563 SF230000 +!B6 U+0406 afii10055 +!B7 U+0407 afii10056 +!B8 U+2566 SF410000 +!B9 U+2567 SF450000 +!BA U+2568 SF460000 +!BB U+2569 SF400000 +!BC U+256A SF540000 +!BD U+0490 afii10050 +!BE U+256C SF440000 +!BF U+00A9 copyright +!C0 U+044E afii10096 +!C1 U+0430 afii10065 +!C2 U+0431 afii10066 +!C3 U+0446 afii10088 +!C4 U+0434 afii10069 +!C5 U+0435 afii10070 +!C6 U+0444 afii10086 +!C7 U+0433 afii10068 +!C8 U+0445 afii10087 +!C9 U+0438 afii10074 +!CA U+0439 afii10075 +!CB U+043A afii10076 +!CC U+043B afii10077 +!CD U+043C afii10078 +!CE U+043D afii10079 +!CF U+043E afii10080 +!D0 U+043F afii10081 +!D1 U+044F afii10097 +!D2 U+0440 afii10082 +!D3 U+0441 afii10083 +!D4 U+0442 afii10084 +!D5 U+0443 afii10085 +!D6 U+0436 afii10072 +!D7 U+0432 afii10067 +!D8 U+044C afii10094 +!D9 U+044B afii10093 +!DA U+0437 afii10073 +!DB U+0448 afii10090 +!DC U+044D afii10095 +!DD U+0449 afii10091 +!DE U+0447 afii10089 +!DF U+044A afii10092 +!E0 U+042E afii10048 +!E1 U+0410 afii10017 +!E2 U+0411 afii10018 +!E3 U+0426 afii10040 +!E4 U+0414 afii10021 +!E5 U+0415 afii10022 +!E6 U+0424 afii10038 +!E7 U+0413 afii10020 +!E8 U+0425 afii10039 +!E9 U+0418 afii10026 +!EA U+0419 afii10027 +!EB U+041A afii10028 +!EC U+041B afii10029 +!ED U+041C afii10030 +!EE U+041D afii10031 +!EF U+041E afii10032 +!F0 U+041F afii10033 +!F1 U+042F afii10049 +!F2 U+0420 afii10034 +!F3 U+0421 afii10035 +!F4 U+0422 afii10036 +!F5 U+0423 afii10037 +!F6 U+0416 afii10024 +!F7 U+0412 afii10019 +!F8 U+042C afii10046 +!F9 U+042B afii10045 +!FA U+0417 afii10025 +!FB U+0428 afii10042 +!FC U+042D afii10047 +!FD U+0429 afii10043 +!FE U+0427 afii10041 +!FF U+042A afii10044 diff --git a/font/times.json b/font/times.json new file mode 100644 index 0000000..6b99ae0 --- /dev/null +++ b/font/times.json @@ -0,0 +1 @@ +{"Tp":"Core","Name":"Times-Roman","Up":-100,"Ut":50,"Cw":[250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,333,408,500,500,833,778,180,333,333,500,564,250,333,250,278,500,500,500,500,500,500,500,500,500,500,278,278,564,564,564,444,921,722,667,667,722,611,556,722,722,333,389,722,611,889,722,722,556,722,667,556,611,722,722,944,722,722,611,333,278,333,469,500,333,444,500,444,500,444,333,500,500,278,278,500,278,778,500,500,500,500,333,389,278,500,500,722,500,500,444,480,200,480,541,350,500,350,333,500,444,1000,500,500,333,1000,556,333,889,350,611,350,350,333,333,444,444,350,500,1000,333,980,389,333,722,350,444,722,250,333,500,500,500,500,200,500,333,760,276,500,564,333,760,333,400,564,300,300,333,500,453,250,333,300,310,500,750,750,750,444,722,722,722,722,722,722,889,667,611,611,611,611,333,333,333,333,722,722,722,722,722,722,722,564,722,722,722,722,722,722,556,500,444,444,444,444,444,444,667,444,444,444,444,444,278,278,278,278,500,500,500,500,500,500,500,564,500,500,500,500,500,500,500,500]} \ No newline at end of file diff --git a/font/timesb.json b/font/timesb.json new file mode 100644 index 0000000..727970f --- /dev/null +++ b/font/timesb.json @@ -0,0 +1 @@ +{"Tp":"Core","Name":"Times-Bold","Up":-100,"Ut":50,"Cw":[250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,333,555,500,500,1000,833,278,333,333,500,570,250,333,250,278,500,500,500,500,500,500,500,500,500,500,333,333,570,570,570,500,930,722,667,722,722,667,611,778,778,389,500,778,667,944,722,778,611,778,722,556,667,722,722,1000,722,722,667,333,278,333,581,500,333,500,556,444,556,444,333,500,556,278,333,556,278,833,556,500,556,556,444,389,333,556,500,722,500,500,444,394,220,394,520,350,500,350,333,500,500,1000,500,500,333,1000,556,333,1000,350,667,350,350,333,333,500,500,350,500,1000,333,1000,389,333,722,350,444,722,250,333,500,500,500,500,220,500,333,747,300,500,570,333,747,333,400,570,300,300,333,556,540,250,333,300,330,500,750,750,750,500,722,722,722,722,722,722,1000,722,667,667,667,667,389,389,389,389,722,722,778,778,778,778,778,570,778,722,722,722,722,722,611,556,500,500,500,500,500,500,722,444,444,444,444,444,278,278,278,278,500,556,500,500,500,500,500,570,500,556,556,556,556,500,556,500]} \ No newline at end of file diff --git a/font/timesbi.json b/font/timesbi.json new file mode 100644 index 0000000..e49b917 --- /dev/null +++ b/font/timesbi.json @@ -0,0 +1 @@ +{"Tp":"Core","Name":"Times-BoldItalic","Up":-100,"Ut":50,"Cw":[250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,389,555,500,500,833,778,278,333,333,500,570,250,333,250,278,500,500,500,500,500,500,500,500,500,500,333,333,570,570,570,500,832,667,667,667,722,667,667,722,778,389,500,667,611,889,722,722,611,722,667,556,611,722,667,889,667,611,611,333,278,333,570,500,333,500,500,444,500,444,333,500,556,278,278,500,278,778,556,500,500,500,389,389,278,556,444,667,500,444,389,348,220,348,570,350,500,350,333,500,500,1000,500,500,333,1000,556,333,944,350,611,350,350,333,333,500,500,350,500,1000,333,1000,389,333,722,350,389,611,250,389,500,500,500,500,220,500,333,747,266,500,606,333,747,333,400,570,300,300,333,576,500,250,333,300,300,500,750,750,750,500,667,667,667,667,667,667,944,667,667,667,667,667,389,389,389,389,722,722,722,722,722,722,722,570,722,722,722,722,722,611,611,500,500,500,500,500,500,500,722,444,444,444,444,444,278,278,278,278,500,556,500,500,500,500,500,570,500,556,556,556,556,444,500,444]} \ No newline at end of file diff --git a/font/timesi.json b/font/timesi.json new file mode 100644 index 0000000..19cae41 --- /dev/null +++ b/font/timesi.json @@ -0,0 +1 @@ +{"Tp":"Core","Name":"Times-Italic","Up":-100,"Ut":50,"Cw":[250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,333,420,500,500,833,778,214,333,333,500,675,250,333,250,278,500,500,500,500,500,500,500,500,500,500,333,333,675,675,675,500,920,611,611,667,722,611,611,722,722,333,444,667,556,833,667,722,611,722,611,500,556,722,611,833,611,556,556,389,278,389,422,500,333,500,500,444,500,444,278,500,500,278,278,444,278,722,500,500,500,500,389,389,278,500,444,667,444,444,389,400,275,400,541,350,500,350,333,500,556,889,500,500,333,1000,500,333,944,350,556,350,350,333,333,556,556,350,500,889,333,980,389,333,667,350,389,556,250,389,500,500,500,500,275,500,333,760,276,500,675,333,760,333,400,675,300,300,333,500,523,250,333,300,310,500,750,750,750,500,611,611,611,611,611,611,889,667,611,611,611,611,333,333,333,333,722,667,722,722,722,722,722,675,722,722,722,722,722,556,611,500,500,500,500,500,500,500,667,444,444,444,444,444,278,278,278,278,500,500,500,500,500,500,500,675,500,500,500,500,500,444,500,444]} \ No newline at end of file diff --git a/font/zapfdingbats.json b/font/zapfdingbats.json new file mode 100644 index 0000000..f65f7b2 --- /dev/null +++ b/font/zapfdingbats.json @@ -0,0 +1 @@ +{"Tp":"Core","Name":"ZapfDingbats","Up":-100,"Ut":50,"Cw":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,278,974,961,974,980,719,789,790,791,690,960,939,549,855,911,933,911,945,974,755,846,762,761,571,677,763,760,759,754,494,552,537,577,692,786,788,788,790,793,794,816,823,789,841,823,833,816,831,923,744,723,749,790,792,695,776,768,792,759,707,708,682,701,826,815,789,789,707,687,696,689,786,787,713,791,785,791,873,761,762,762,759,759,892,892,788,784,438,138,277,415,392,392,668,668,0,390,390,317,317,276,276,509,509,410,410,234,234,334,334,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,732,544,544,910,667,760,760,776,595,694,626,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,788,894,838,1016,458,748,924,748,918,927,928,928,834,873,828,924,924,917,930,931,463,883,836,836,867,867,696,696,874,0,874,760,946,771,865,771,888,967,888,831,873,927,970,918,0]} \ No newline at end of file diff --git a/fpdf.go b/fpdf.go new file mode 100644 index 0000000..3be1cdc --- /dev/null +++ b/fpdf.go @@ -0,0 +1,4998 @@ +/* + * Copyright (c) 2013-2014 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf + +// Version: 1.7 +// Date: 2011-06-18 +// Author: Olivier PLATHEY +// Port to Go: Kurt Jung, 2013-07-15 + +import ( + "bytes" + "encoding/binary" + "encoding/json" + "fmt" + "image" + "image/color" + "image/gif" + "image/jpeg" + "image/png" + "io" + "io/ioutil" + "math" + "os" + "path" + "sort" + "strconv" + "strings" + "time" +) + +var gl struct { + catalogSort bool + noCompress bool // Initial zero value indicates compression + creationDate time.Time + modDate time.Time +} + +type fmtBuffer struct { + bytes.Buffer +} + +func (b *fmtBuffer) printf(fmtStr string, args ...interface{}) { + b.Buffer.WriteString(fmt.Sprintf(fmtStr, args...)) +} + +func fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr string, size SizeType) (f *Fpdf) { + f = new(Fpdf) + if orientationStr == "" { + orientationStr = "p" + } else { + orientationStr = strings.ToLower(orientationStr) + } + if unitStr == "" { + unitStr = "mm" + } + if sizeStr == "" { + sizeStr = "A4" + } + if fontDirStr == "" { + fontDirStr = "." + } + f.page = 0 + f.n = 2 + f.pages = make([]*bytes.Buffer, 0, 8) + f.pages = append(f.pages, bytes.NewBufferString("")) // pages[0] is unused (1-based) + f.pageSizes = make(map[int]SizeType) + f.pageBoxes = make(map[int]map[string]PageBox) + f.defPageBoxes = make(map[string]PageBox) + f.state = 0 + f.fonts = make(map[string]fontDefType) + f.fontFiles = make(map[string]fontFileType) + 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) + f.links = make([]intLinkType, 0, 8) + f.links = append(f.links, intLinkType{}) // links[0] is unused (1-based) + f.pageAttachments = make([][]annotationAttach, 0, 8) + f.pageAttachments = append(f.pageAttachments, []annotationAttach{}) // + f.aliasMap = make(map[string]string) + f.inHeader = false + f.inFooter = false + f.lasth = 0 + f.fontFamily = "" + 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) + f.colorFlag = false + f.ws = 0 + f.fontpath = fontDirStr + // Core fonts + f.coreFonts = map[string]bool{ + "courier": true, + "helvetica": true, + "times": true, + "symbol": true, + "zapfdingbats": true, + } + // Scale factor + switch unitStr { + case "pt", "point": + f.k = 1.0 + case "mm": + f.k = 72.0 / 25.4 + case "cm": + f.k = 72.0 / 2.54 + case "in", "inch": + f.k = 72.0 + default: + f.err = fmt.Errorf("incorrect unit %s", unitStr) + return + } + f.unitStr = unitStr + // Page sizes + f.stdPageSizes = make(map[string]SizeType) + f.stdPageSizes["a3"] = SizeType{841.89, 1190.55} + f.stdPageSizes["a4"] = SizeType{595.28, 841.89} + f.stdPageSizes["a5"] = SizeType{420.94, 595.28} + f.stdPageSizes["a6"] = SizeType{297.64, 420.94} + f.stdPageSizes["a2"] = SizeType{1190.55, 1683.78} + f.stdPageSizes["a1"] = SizeType{1683.78, 2383.94} + f.stdPageSizes["letter"] = SizeType{612, 792} + f.stdPageSizes["legal"] = SizeType{612, 1008} + f.stdPageSizes["tabloid"] = SizeType{792, 1224} + if size.Wd > 0 && size.Ht > 0 { + f.defPageSize = size + } else { + f.defPageSize = f.getpagesizestr(sizeStr) + if f.err != nil { + return + } + } + f.curPageSize = f.defPageSize + // Page orientation + switch orientationStr { + case "p", "portrait": + f.defOrientation = "P" + f.w = f.defPageSize.Wd + f.h = f.defPageSize.Ht + // dbg("Assign h: %8.2f", f.h) + case "l", "landscape": + f.defOrientation = "L" + f.w = f.defPageSize.Ht + f.h = f.defPageSize.Wd + default: + f.err = fmt.Errorf("incorrect orientation: %s", orientationStr) + return + } + f.curOrientation = f.defOrientation + f.wPt = f.w * f.k + f.hPt = f.h * f.k + // Page margins (1 cm) + margin := 28.35 / f.k + f.SetMargins(margin, margin, margin) + // Interior cell margin (1 mm) + f.cMargin = margin / 10 + // Line width (0.2 mm) + f.lineWidth = 0.567 / f.k + // Automatic page break + f.SetAutoPageBreak(true, 2*margin) + // Default display mode + f.SetDisplayMode("default", "default") + if f.err != nil { + return + } + f.acceptPageBreak = func() bool { + return f.autoPageBreak + } + // Enable compression + f.SetCompression(!gl.noCompress) + f.spotColorMap = make(map[string]spotColorType) + f.blendList = make([]blendModeType, 0, 8) + f.blendList = append(f.blendList, blendModeType{}) // blendList[0] is unused (1-based) + f.blendMap = make(map[string]int) + f.blendMode = "Normal" + f.alpha = 1 + f.gradientList = make([]gradientType, 0, 8) + 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.modDate = gl.modDate + f.userUnderlineThickness = 1 + return +} + +// NewCustom returns a pointer to a new Fpdf instance. Its methods are +// subsequently called to produce a single PDF document. NewCustom() is an +// alternative to New() that provides additional customization. The PageSize() +// example demonstrates this method. +func NewCustom(init *InitType) (f *Fpdf) { + return fpdfNew(init.OrientationStr, init.UnitStr, init.SizeStr, init.FontDirStr, init.Size) +} + +// New returns a pointer to a new Fpdf instance. Its methods are subsequently +// called to produce a single PDF document. +// +// orientationStr specifies the default page orientation. For portrait mode, +// specify "P" or "Portrait". For landscape mode, specify "L" or "Landscape". +// An empty string will be replaced with "P". +// +// unitStr specifies the unit of length used in size parameters for elements +// other than fonts, which are always measured in points. Specify "pt" for +// point, "mm" for millimeter, "cm" for centimeter, or "in" for inch. An empty +// string will be replaced with "mm". +// +// sizeStr specifies the page size. Acceptable values are "A3", "A4", "A5", +// "Letter", "Legal", or "Tabloid". An empty string will be replaced with "A4". +// +// fontDirStr specifies the file system location in which font resources will +// be found. An empty string is replaced with ".". This argument only needs to +// reference an actual directory if a font other than one of the core +// fonts is used. The core fonts are "courier", "helvetica" (also called +// "arial"), "times", and "zapfdingbats" (also called "symbol"). +func New(orientationStr, unitStr, sizeStr, fontDirStr string) (f *Fpdf) { + return fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr, SizeType{0, 0}) +} + +// Ok returns true if no processing errors have occurred. +func (f *Fpdf) Ok() bool { + return f.err == nil +} + +// Err returns true if a processing error has occurred. +func (f *Fpdf) Err() bool { + return f.err != nil +} + +// ClearError unsets the internal Fpdf error. This method should be used with +// care, as an internal error condition usually indicates an unrecoverable +// problem with the generation of a document. It is intended to deal with cases +// in which an error is used to select an alternate form of the document. +func (f *Fpdf) ClearError() { + f.err = nil +} + +// SetErrorf sets the internal Fpdf error with formatted text to halt PDF +// generation; this may facilitate error handling by application. If an error +// condition is already set, this call is ignored. +// +// See the documentation for printing in the standard fmt package for details +// about fmtStr and args. +func (f *Fpdf) SetErrorf(fmtStr string, args ...interface{}) { + if f.err == nil { + f.err = fmt.Errorf(fmtStr, args...) + } +} + +// String satisfies the fmt.Stringer interface and summarizes the Fpdf +// instance. +func (f *Fpdf) String() string { + return "Fpdf " + cnFpdfVersion +} + +// SetError sets an error to halt PDF generation. This may facilitate error +// handling by application. See also Ok(), Err() and Error(). +func (f *Fpdf) SetError(err error) { + if f.err == nil && err != nil { + f.err = err + } +} + +// Error returns the internal Fpdf error; this will be nil if no error has occurred. +func (f *Fpdf) Error() error { + return f.err +} + +// GetPageSize returns the current page's width and height. This is the paper's +// size. To compute the size of the area being used, subtract the margins (see +// GetMargins()). +func (f *Fpdf) GetPageSize() (width, height float64) { + width = f.w + height = f.h + return +} + +// GetMargins returns the left, top, right, and bottom margins. The first three +// are set with the SetMargins() method. The bottom margin is set with the +// SetAutoPageBreak() method. +func (f *Fpdf) GetMargins() (left, top, right, bottom float64) { + left = f.lMargin + top = f.tMargin + right = f.rMargin + bottom = f.bMargin + return +} + +// SetMargins defines the left, top and right margins. By default, they equal 1 +// cm. Call this method to change them. If the value of the right margin is +// less than zero, it is set to the same as the left margin. +func (f *Fpdf) SetMargins(left, top, right float64) { + f.lMargin = left + f.tMargin = top + if right < 0 { + right = left + } + f.rMargin = right +} + +// SetLeftMargin defines the left margin. The method can be called before +// creating the first page. If the current abscissa gets out of page, it is +// brought back to the margin. +func (f *Fpdf) SetLeftMargin(margin float64) { + f.lMargin = margin + if f.page > 0 && f.x < margin { + f.x = margin + } +} + +// GetCellMargin returns the cell margin. This is the amount of space before +// and after the text within a cell that's left blank, and is in units passed +// to New(). It defaults to 1mm. +func (f *Fpdf) GetCellMargin() float64 { + return f.cMargin +} + +// SetCellMargin sets the cell margin. This is the amount of space before and +// after the text within a cell that's left blank, and is in units passed to +// New(). +func (f *Fpdf) SetCellMargin(margin float64) { + f.cMargin = margin +} + +// SetPageBoxRec sets the page box for the current page, and any following +// pages. Allowable types are trim, trimbox, crop, cropbox, bleed, bleedbox, +// art and artbox box types are case insensitive. See SetPageBox() for a method +// that specifies the coordinates and extent of the page box individually. +func (f *Fpdf) SetPageBoxRec(t string, pb PageBox) { + switch strings.ToLower(t) { + case "trim": + fallthrough + case "trimbox": + t = "TrimBox" + case "crop": + fallthrough + case "cropbox": + t = "CropBox" + case "bleed": + fallthrough + case "bleedbox": + t = "BleedBox" + case "art": + fallthrough + case "artbox": + t = "ArtBox" + default: + f.err = fmt.Errorf("%s is not a valid page box type", t) + return + } + + pb.X = pb.X * f.k + pb.Y = pb.Y * f.k + pb.Wd = (pb.Wd * f.k) + pb.X + pb.Ht = (pb.Ht * f.k) + pb.Y + + if f.page > 0 { + f.pageBoxes[f.page][t] = pb + } + + // always override. page defaults are supplied in addPage function + f.defPageBoxes[t] = pb +} + +// SetPageBox sets the page box for the current page, and any following pages. +// Allowable types are trim, trimbox, crop, cropbox, bleed, bleedbox, art and +// artbox box types are case insensitive. +func (f *Fpdf) SetPageBox(t string, x, y, wd, ht float64) { + f.SetPageBoxRec(t, PageBox{SizeType{Wd: wd, Ht: ht}, PointType{X: x, Y: y}}) +} + +// SetPage sets the current page to that of a valid page in the PDF document. +// pageNum is one-based. The SetPage() example demonstrates this method. +func (f *Fpdf) SetPage(pageNum int) { + if (pageNum > 0) && (pageNum < len(f.pages)) { + f.page = pageNum + } +} + +// PageCount returns the number of pages currently in the document. Since page +// numbers in gofpdf are one-based, the page count is the same as the page +// number of the current last page. +func (f *Fpdf) PageCount() int { + return len(f.pages) - 1 +} + +// SetFontLocation sets the location in the file system of the font and font +// definition files. +func (f *Fpdf) SetFontLocation(fontDirStr string) { + f.fontpath = fontDirStr +} + +// SetFontLoader sets a loader used to read font files (.json and .z) from an +// arbitrary source. If a font loader has been specified, it is used to load +// the named font resources when AddFont() is called. If this operation fails, +// an attempt is made to load the resources from the configured font directory +// (see SetFontLocation()). +func (f *Fpdf) SetFontLoader(loader FontLoader) { + f.fontLoader = loader +} + +// SetHeaderFuncMode sets the function that lets the application render the +// page header. See SetHeaderFunc() for more details. The value for homeMode +// should be set to true to have the current position set to the left and top +// margin after the header function is called. +func (f *Fpdf) SetHeaderFuncMode(fnc func(), homeMode bool) { + f.headerFnc = fnc + f.headerHomeMode = homeMode +} + +// SetHeaderFunc sets the function that lets the application render the page +// header. The specified function is automatically called by AddPage() and +// should not be called directly by the application. The implementation in Fpdf +// is empty, so you have to provide an appropriate function if you want page +// headers. fnc will typically be a closure that has access to the Fpdf +// instance and other document generation variables. +// +// A header is a convenient place to put background content that repeats on +// each page such as a watermark. When this is done, remember to reset the X +// and Y values so the normal content begins where expected. Including a +// watermark on each page is demonstrated in the example for TransformRotate. +// +// This method is demonstrated in the example for AddPage(). +func (f *Fpdf) SetHeaderFunc(fnc func()) { + f.headerFnc = fnc +} + +// SetFooterFunc sets the function that lets the application render the page +// footer. The specified function is automatically called by AddPage() and +// Close() and should not be called directly by the application. The +// implementation in Fpdf is empty, so you have to provide an appropriate +// function if you want page footers. fnc will typically be a closure that has +// access to the Fpdf instance and other document generation variables. See +// SetFooterFuncLpi for a similar function that passes a last page indicator. +// +// This method is demonstrated in the example for AddPage(). +func (f *Fpdf) SetFooterFunc(fnc func()) { + f.footerFnc = fnc + f.footerFncLpi = nil +} + +// SetFooterFuncLpi sets the function that lets the application render the page +// footer. The specified function is automatically called by AddPage() and +// Close() and should not be called directly by the application. It is passed a +// boolean that is true if the last page of the document is being rendered. The +// implementation in Fpdf is empty, so you have to provide an appropriate +// function if you want page footers. fnc will typically be a closure that has +// access to the Fpdf instance and other document generation variables. +func (f *Fpdf) SetFooterFuncLpi(fnc func(lastPage bool)) { + f.footerFncLpi = fnc + f.footerFnc = nil +} + +// SetTopMargin defines the top margin. The method can be called before +// creating the first page. +func (f *Fpdf) SetTopMargin(margin float64) { + f.tMargin = margin +} + +// SetRightMargin defines the right margin. The method can be called before +// creating the first page. +func (f *Fpdf) SetRightMargin(margin float64) { + f.rMargin = margin +} + +// GetAutoPageBreak returns true if automatic pages breaks are enabled, false +// otherwise. This is followed by the triggering limit from the bottom of the +// page. This value applies only if automatic page breaks are enabled. +func (f *Fpdf) GetAutoPageBreak() (auto bool, margin float64) { + auto = f.autoPageBreak + margin = f.bMargin + return +} + +// SetAutoPageBreak enables or disables the automatic page breaking mode. When +// enabling, the second parameter is the distance from the bottom of the page +// that defines the triggering limit. By default, the mode is on and the margin +// is 2 cm. +func (f *Fpdf) SetAutoPageBreak(auto bool, margin float64) { + f.autoPageBreak = auto + f.bMargin = margin + f.pageBreakTrigger = f.h - margin +} + +// SetDisplayMode sets advisory display directives for the document viewer. +// Pages can be displayed entirely on screen, occupy the full width of the +// window, use real size, be scaled by a specific zooming factor or use viewer +// default (configured in the Preferences menu of Adobe Reader). The page +// layout can be specified so that pages are displayed individually or in +// pairs. +// +// zoomStr can be "fullpage" to display the entire page on screen, "fullwidth" +// to use maximum width of window, "real" to use real size (equivalent to 100% +// zoom) or "default" to use viewer default mode. +// +// layoutStr can be "single" (or "SinglePage") to display one page at once, +// "continuous" (or "OneColumn") to display pages continuously, "two" (or +// "TwoColumnLeft") to display two pages on two columns with odd-numbered pages +// on the left, or "TwoColumnRight" to display two pages on two columns with +// odd-numbered pages on the right, or "TwoPageLeft" to display pages two at a +// time with odd-numbered pages on the left, or "TwoPageRight" to display pages +// two at a time with odd-numbered pages on the right, or "default" to use +// viewer default mode. +func (f *Fpdf) SetDisplayMode(zoomStr, layoutStr string) { + if f.err != nil { + return + } + if layoutStr == "" { + layoutStr = "default" + } + switch zoomStr { + case "fullpage", "fullwidth", "real", "default": + f.zoomMode = zoomStr + default: + f.err = fmt.Errorf("incorrect zoom display mode: %s", zoomStr) + return + } + switch layoutStr { + case "single", "continuous", "two", "default", "SinglePage", "OneColumn", + "TwoColumnLeft", "TwoColumnRight", "TwoPageLeft", "TwoPageRight": + f.layoutMode = layoutStr + default: + f.err = fmt.Errorf("incorrect layout display mode: %s", layoutStr) + return + } +} + +// SetDefaultCompression controls the default setting of the internal +// compression flag. See SetCompression() for more details. Compression is on +// by default. +func SetDefaultCompression(compress bool) { + gl.noCompress = !compress +} + +// SetCompression activates or deactivates page compression with zlib. When +// activated, the internal representation of each page is compressed, which +// leads to a compression ratio of about 2 for the resulting document. +// Compression is on by default. +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) { + if isUTF8 { + titleStr = utf8toutf16(titleStr) + } + f.title = titleStr +} + +// SetSubject defines the subject of the document. isUTF8 indicates if the +// string is encoded in ISO-8859-1 (false) or UTF-8 (true). +func (f *Fpdf) SetSubject(subjectStr string, isUTF8 bool) { + if isUTF8 { + subjectStr = utf8toutf16(subjectStr) + } + f.subject = subjectStr +} + +// SetAuthor defines the author of the document. isUTF8 indicates if the string +// is encoded in ISO-8859-1 (false) or UTF-8 (true). +func (f *Fpdf) SetAuthor(authorStr string, isUTF8 bool) { + if isUTF8 { + authorStr = utf8toutf16(authorStr) + } + f.author = authorStr +} + +// SetKeywords defines the keywords of the document. keywordStr is a +// space-delimited string, for example "invoice August". isUTF8 indicates if +// the string is encoded +func (f *Fpdf) SetKeywords(keywordsStr string, isUTF8 bool) { + if isUTF8 { + keywordsStr = utf8toutf16(keywordsStr) + } + f.keywords = keywordsStr +} + +// SetCreator defines the creator of the document. isUTF8 indicates if the +// string is encoded in ISO-8859-1 (false) or UTF-8 (true). +func (f *Fpdf) SetCreator(creatorStr string, isUTF8 bool) { + if isUTF8 { + creatorStr = utf8toutf16(creatorStr) + } + f.creator = creatorStr +} + +// SetXmpMetadata defines XMP metadata that will be embedded with the document. +func (f *Fpdf) SetXmpMetadata(xmpStream []byte) { + f.xmp = xmpStream +} + +// AliasNbPages defines an alias for the total number of pages. It will be +// substituted as the document is closed. An empty string is replaced with the +// string "{nb}". +// +// See the example for AddPage() for a demonstration of this method. +func (f *Fpdf) AliasNbPages(aliasStr string) { + if aliasStr == "" { + aliasStr = "{nb}" + } + f.aliasNbPagesStr = aliasStr +} + +// RTL enables right-to-left mode +func (f *Fpdf) RTL() { + f.isRTL = true +} + +// LTR disables right-to-left mode +func (f *Fpdf) LTR() { + f.isRTL = false +} + +// open begins a document +func (f *Fpdf) open() { + f.state = 1 +} + +// Close terminates the PDF document. It is not necessary to call this method +// explicitly because Output(), OutputAndClose() and OutputFileAndClose() do it +// automatically. If the document contains no page, AddPage() is called to +// prevent the generation of an invalid document. +func (f *Fpdf) Close() { + if f.err == nil { + if f.clipNest > 0 { + f.err = fmt.Errorf("clip procedure must be explicitly ended") + } else if f.transformNest > 0 { + f.err = fmt.Errorf("transformation procedure must be explicitly ended") + } + } + if f.err != nil { + return + } + if f.state == 3 { + return + } + if f.page == 0 { + f.AddPage() + if f.err != nil { + return + } + } + // Page footer + f.inFooter = true + if f.footerFnc != nil { + f.footerFnc() + } else if f.footerFncLpi != nil { + f.footerFncLpi(true) + } + f.inFooter = false + + // Close page + f.endpage() + // Close document + f.enddoc() + return +} + +// PageSize returns the width and height of the specified page in the units +// established in New(). These return values are followed by the unit of +// measure itself. If pageNum is zero or otherwise out of bounds, it returns +// the default page size, that is, the size of the page that would be added by +// AddPage(). +func (f *Fpdf) PageSize(pageNum int) (wd, ht float64, unitStr string) { + sz, ok := f.pageSizes[pageNum] + if ok { + sz.Wd, sz.Ht = sz.Wd/f.k, sz.Ht/f.k + } else { + sz = f.defPageSize // user units + } + return sz.Wd, sz.Ht, f.unitStr +} + +// AddPageFormat adds a new page with non-default orientation or size. See +// AddPage() for more details. +// +// See New() for a description of orientationStr. +// +// size specifies the size of the new page in the units established in New(). +// +// The PageSize() example demonstrates this method. +func (f *Fpdf) AddPageFormat(orientationStr string, size SizeType) { + if f.err != nil { + return + } + if f.page != len(f.pages)-1 { + f.page = len(f.pages) - 1 + } + if f.state == 0 { + f.open() + } + familyStr := f.fontFamily + style := f.fontStyle + if f.underline { + style += "U" + } + if f.strikeout { + style += "S" + } + fontsize := f.fontSizePt + lw := f.lineWidth + dc := f.color.draw + fc := f.color.fill + tc := f.color.text + cf := f.colorFlag + + if f.page > 0 { + f.inFooter = true + // Page footer avoid double call on footer. + if f.footerFnc != nil { + f.footerFnc() + + } else if f.footerFncLpi != nil { + f.footerFncLpi(false) // not last page. + } + f.inFooter = false + // Close page + f.endpage() + } + // Start new page + f.beginpage(orientationStr, size) + // Set line cap style to current value + // f.out("2 J") + f.outf("%d J", f.capStyle) + // Set line join style to current value + f.outf("%d j", f.joinStyle) + // Set line width + f.lineWidth = lw + f.outf("%.2f w", lw*f.k) + // Set dash pattern + if len(f.dashArray) > 0 { + f.outputDashPattern() + } + // Set font + if familyStr != "" { + f.SetFont(familyStr, style, fontsize) + if f.err != nil { + return + } + } + // Set colors + f.color.draw = dc + if dc.str != "0 G" { + f.out(dc.str) + } + f.color.fill = fc + if fc.str != "0 g" { + f.out(fc.str) + } + f.color.text = tc + f.colorFlag = cf + // Page header + if f.headerFnc != nil { + f.inHeader = true + f.headerFnc() + f.inHeader = false + if f.headerHomeMode { + f.SetHomeXY() + } + } + // Restore line width + if f.lineWidth != lw { + f.lineWidth = lw + f.outf("%.2f w", lw*f.k) + } + // Restore font + if familyStr != "" { + f.SetFont(familyStr, style, fontsize) + if f.err != nil { + return + } + } + // Restore colors + if f.color.draw.str != dc.str { + f.color.draw = dc + f.out(dc.str) + } + if f.color.fill.str != fc.str { + f.color.fill = fc + f.out(fc.str) + } + f.color.text = tc + f.colorFlag = cf + return +} + +// AddPage adds a new page to the document. If a page is already present, the +// Footer() method is called first to output the footer. Then the page is +// added, the current position set to the top-left corner according to the left +// and top margins, and Header() is called to display the header. +// +// The font which was set before calling is automatically restored. There is no +// need to call SetFont() again if you want to continue with the same font. The +// same is true for colors and line width. +// +// The origin of the coordinate system is at the top-left corner and increasing +// ordinates go downwards. +// +// See AddPageFormat() for a version of this method that allows the page size +// and orientation to be different than the default. +func (f *Fpdf) AddPage() { + if f.err != nil { + return + } + // dbg("AddPage") + f.AddPageFormat(f.defOrientation, f.defPageSize) + return +} + +// PageNo returns the current page number. +// +// See the example for AddPage() for a demonstration of this method. +func (f *Fpdf) PageNo() int { + return f.page +} + +func colorComp(v int) (int, float64) { + if v < 0 { + v = 0 + } else if v > 255 { + v = 255 + } + return v, float64(v) / 255.0 +} + +func rgbColorValue(r, g, b int, grayStr, fullStr string) (clr colorType) { + clr.ir, clr.r = colorComp(r) + clr.ig, clr.g = colorComp(g) + clr.ib, clr.b = colorComp(b) + clr.mode = colorModeRGB + clr.gray = clr.ir == clr.ig && clr.r == clr.b + if len(grayStr) > 0 { + if clr.gray { + clr.str = sprintf("%.3f %s", clr.r, grayStr) + } else { + clr.str = sprintf("%.3f %.3f %.3f %s", clr.r, clr.g, clr.b, fullStr) + } + } else { + clr.str = sprintf("%.3f %.3f %.3f", clr.r, clr.g, clr.b) + } + return +} + +// SetDrawColor defines the color used for all drawing operations (lines, +// rectangles and cell borders). It is expressed in RGB components (0 - 255). +// The method can be called before the first page is created. The value is +// retained from page to page. +func (f *Fpdf) SetDrawColor(r, g, b int) { + f.setDrawColor(r, g, b) +} + +func (f *Fpdf) setDrawColor(r, g, b int) { + f.color.draw = rgbColorValue(r, g, b, "G", "RG") + if f.page > 0 { + f.out(f.color.draw.str) + } +} + +// GetDrawColor returns the most recently set draw color as RGB components (0 - +// 255). This will not be the current value if a draw color of some other type +// (for example, spot) has been more recently set. +func (f *Fpdf) GetDrawColor() (int, int, int) { + return f.color.draw.ir, f.color.draw.ig, f.color.draw.ib +} + +// SetFillColor defines the color used for all filling operations (filled +// rectangles and cell backgrounds). It is expressed in RGB components (0 +// -255). The method can be called before the first page is created and the +// value is retained from page to page. +func (f *Fpdf) SetFillColor(r, g, b int) { + f.setFillColor(r, g, b) +} + +func (f *Fpdf) setFillColor(r, g, b int) { + f.color.fill = rgbColorValue(r, g, b, "g", "rg") + f.colorFlag = f.color.fill.str != f.color.text.str + if f.page > 0 { + f.out(f.color.fill.str) + } +} + +// GetFillColor returns the most recently set fill color as RGB components (0 - +// 255). This will not be the current value if a fill color of some other type +// (for example, spot) has been more recently set. +func (f *Fpdf) GetFillColor() (int, int, int) { + return f.color.fill.ir, f.color.fill.ig, f.color.fill.ib +} + +// SetTextColor defines the color used for text. It is expressed in RGB +// components (0 - 255). The method can be called before the first page is +// created. The value is retained from page to page. +func (f *Fpdf) SetTextColor(r, g, b int) { + f.setTextColor(r, g, b) +} + +func (f *Fpdf) setTextColor(r, g, b int) { + f.color.text = rgbColorValue(r, g, b, "g", "rg") + f.colorFlag = f.color.fill.str != f.color.text.str +} + +// GetTextColor returns the most recently set text color as RGB components (0 - +// 255). This will not be the current value if a text color of some other type +// (for example, spot) has been more recently set. +func (f *Fpdf) GetTextColor() (int, int, int) { + return f.color.text.ir, f.color.text.ig, f.color.text.ib +} + +// GetStringWidth returns the length of a string in user units. A font must be +// currently selected. +func (f *Fpdf) GetStringWidth(s string) float64 { + if f.err != nil { + return 0 + } + w := f.GetStringSymbolWidth(s) + return float64(w) * f.fontSize / 1000 +} + +// GetStringSymbolWidth returns the length of a string in glyf units. A font must be +// currently selected. +func (f *Fpdf) GetStringSymbolWidth(s string) int { + if f.err != nil { + return 0 + } + w := 0 + if f.isCurrentUTF8 { + unicode := []rune(s) + for _, char := range unicode { + intChar := int(char) + if len(f.currentFont.Cw) >= intChar && f.currentFont.Cw[intChar] > 0 { + if f.currentFont.Cw[intChar] != 65535 { + w += f.currentFont.Cw[intChar] + } + } else if f.currentFont.Desc.MissingWidth != 0 { + w += f.currentFont.Desc.MissingWidth + } else { + w += 500 + } + } + } else { + for _, ch := range []byte(s) { + if ch == 0 { + break + } + w += f.currentFont.Cw[ch] + } + } + return w +} + +// SetLineWidth defines the line width. By default, the value equals 0.2 mm. +// The method can be called before the first page is created. The value is +// retained from page to page. +func (f *Fpdf) SetLineWidth(width float64) { + f.setLineWidth(width) +} + +func (f *Fpdf) setLineWidth(width float64) { + f.lineWidth = width + if f.page > 0 { + f.outf("%.2f w", width*f.k) + } +} + +// GetLineWidth returns the current line thickness. +func (f *Fpdf) GetLineWidth() float64 { + return f.lineWidth +} + +// SetLineCapStyle defines the line cap style. styleStr should be "butt", +// "round" or "square". A square style projects from the end of the line. The +// method can be called before the first page is created. The value is +// retained from page to page. +func (f *Fpdf) SetLineCapStyle(styleStr string) { + var capStyle int + switch styleStr { + case "round": + capStyle = 1 + case "square": + capStyle = 2 + default: + capStyle = 0 + } + f.capStyle = capStyle + if f.page > 0 { + f.outf("%d J", f.capStyle) + } +} + +// SetLineJoinStyle defines the line cap style. styleStr should be "miter", +// "round" or "bevel". The method can be called before the first page +// is created. The value is retained from page to page. +func (f *Fpdf) SetLineJoinStyle(styleStr string) { + var joinStyle int + switch styleStr { + case "round": + joinStyle = 1 + case "bevel": + joinStyle = 2 + default: + joinStyle = 0 + } + f.joinStyle = joinStyle + if f.page > 0 { + f.outf("%d j", f.joinStyle) + } +} + +// SetDashPattern sets the dash pattern that is used to draw lines. The +// dashArray elements are numbers that specify the lengths, in units +// established in New(), of alternating dashes and gaps. The dash phase +// specifies the distance into the dash pattern at which to start the dash. The +// dash pattern is retained from page to page. Call this method with an empty +// array to restore solid line drawing. +// +// The Beziergon() example demonstrates this method. +func (f *Fpdf) SetDashPattern(dashArray []float64, dashPhase float64) { + scaled := make([]float64, len(dashArray)) + for i, value := range dashArray { + scaled[i] = value * f.k + } + dashPhase *= f.k + + f.dashArray = scaled + f.dashPhase = dashPhase + if f.page > 0 { + f.outputDashPattern() + } + +} + +func (f *Fpdf) outputDashPattern() { + var buf bytes.Buffer + buf.WriteByte('[') + for i, value := range f.dashArray { + if i > 0 { + buf.WriteByte(' ') + } + buf.WriteString(strconv.FormatFloat(value, 'f', 2, 64)) + } + buf.WriteString("] ") + buf.WriteString(strconv.FormatFloat(f.dashPhase, 'f', 2, 64)) + buf.WriteString(" d") + f.outbuf(&buf) +} + +// Line draws a line between points (x1, y1) and (x2, y2) using the current +// draw color, line width and cap style. +func (f *Fpdf) Line(x1, y1, x2, y2 float64) { + f.outf("%.2f %.2f m %.2f %.2f l S", x1*f.k, (f.h-y1)*f.k, x2*f.k, (f.h-y2)*f.k) +} + +// fillDrawOp corrects path painting operators +func fillDrawOp(styleStr string) (opStr string) { + switch strings.ToUpper(styleStr) { + case "", "D": + // Stroke the path. + opStr = "S" + case "F": + // fill the path, using the nonzero winding number rule + opStr = "f" + case "F*": + // fill the path, using the even-odd rule + opStr = "f*" + case "FD", "DF": + // fill and then stroke the path, using the nonzero winding number rule + opStr = "B" + case "FD*", "DF*": + // fill and then stroke the path, using the even-odd rule + opStr = "B*" + default: + opStr = styleStr + } + return +} + +// Rect 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. +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 + var rTL, rTR, rBR, rBL float64 // zero means no rounded corner + if strings.Contains(corners, "1") { + rTL = r + } + if strings.Contains(corners, "2") { + rTR = r + } + if strings.Contains(corners, "3") { + rBR = r + } + if strings.Contains(corners, "4") { + rBL = r + } + f.RoundedRectExt(x, y, w, h, rTL, rTR, rBR, rBL, stylestr) +} + +// RoundedRectExt behaves the same as RoundedRect() but supports a different +// radius for each corner. A zero radius means squared corner. See +// RoundedRect() for more details. This method is demonstrated in the +// RoundedRect() example. +func (f *Fpdf) RoundedRectExt(x, y, w, h, rTL, rTR, rBR, rBL float64, stylestr string) { + f.roundedRectPath(x, y, w, h, rTL, rTR, rBR, rBL) + 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 +// outlined and filled. An empty string will be replaced with "D". Drawing uses +// the current draw color and line width centered on the circle's perimeter. +// Filling uses the current fill color. +func (f *Fpdf) Circle(x, y, r float64, styleStr string) { + f.Ellipse(x, y, r, r, 0, styleStr) +} + +// Ellipse draws an ellipse centered at point (x, y). rx and ry specify its +// horizontal and vertical radii. +// +// degRotate specifies the counter-clockwise angle in degrees that the ellipse +// will be rotated. +// +// 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 ellipse's perimeter. +// Filling uses the current fill color. +// +// The Circle() example demonstrates this method. +func (f *Fpdf) Ellipse(x, y, rx, ry, degRotate float64, styleStr string) { + f.arc(x, y, rx, ry, degRotate, 0, 360, styleStr, false) +} + +// Polygon draws a closed figure defined by a series of vertices specified by +// points. The x and y fields of the points use the units established in New(). +// The last point in the slice will be implicitly joined to the first to close +// the polygon. +// +// 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 ellipse's perimeter. +// Filling uses the current fill color. +func (f *Fpdf) Polygon(points []PointType, styleStr string) { + if len(points) > 2 { + for j, pt := range points { + if j == 0 { + f.point(pt.X, pt.Y) + } else { + f.outf("%.5f %.5f l ", pt.X*f.k, (f.h-pt.Y)*f.k) + } + } + f.outf("%.5f %.5f l ", points[0].X*f.k, (f.h-points[0].Y)*f.k) + f.DrawPath(styleStr) + } +} + +// Beziergon draws a closed figure defined by a series of cubic Bézier curve +// segments. The first point in the slice defines the starting point of the +// figure. Each three following points p1, p2, p3 represent a curve segment to +// the point p3 using p1 and p2 as the Bézier control points. +// +// The x and y fields of the points use the units established in New(). +// +// 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 ellipse's perimeter. +// Filling uses the current fill color. +func (f *Fpdf) Beziergon(points []PointType, styleStr string) { + + // Thanks, Robert Lillack, for contributing this function. + + if len(points) < 4 { + return + } + f.point(points[0].XY()) + + points = points[1:] + for len(points) >= 3 { + cx0, cy0 := points[0].XY() + cx1, cy1 := points[1].XY() + x1, y1 := points[2].XY() + f.curve(cx0, cy0, cx1, cy1, x1, y1) + points = points[3:] + } + + f.DrawPath(styleStr) +} + +// point outputs current point +func (f *Fpdf) point(x, y float64) { + f.outf("%.2f %.2f m", x*f.k, (f.h-y)*f.k) +} + +// curve outputs a single cubic Bézier curve segment from current point +func (f *Fpdf) curve(cx0, cy0, cx1, cy1, x, y float64) { + // Thanks, Robert Lillack, for straightening this out + f.outf("%.5f %.5f %.5f %.5f %.5f %.5f c", cx0*f.k, (f.h-cy0)*f.k, cx1*f.k, + (f.h-cy1)*f.k, x*f.k, (f.h-y)*f.k) +} + +// Curve draws a single-segment quadratic Bézier curve. The curve starts at +// the point (x0, y0) and ends at the point (x1, y1). The control point (cx, +// cy) specifies the curvature. At the start point, the curve is tangent to the +// straight line between the start point and the control point. At the end +// point, the curve is tangent to the straight line between the end point and +// the control point. +// +// 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, line width, and cap style centered on the curve's +// path. Filling uses the current fill color. +// +// The Circle() example demonstrates this method. +func (f *Fpdf) Curve(x0, y0, cx, cy, x1, y1 float64, styleStr string) { + f.point(x0, y0) + f.outf("%.5f %.5f %.5f %.5f v %s", cx*f.k, (f.h-cy)*f.k, x1*f.k, (f.h-y1)*f.k, + fillDrawOp(styleStr)) +} + +// CurveCubic draws a single-segment cubic Bézier curve. This routine performs +// the same function as CurveBezierCubic() but has a nonstandard argument order. +// It is retained to preserve backward compatibility. +func (f *Fpdf) CurveCubic(x0, y0, cx0, cy0, x1, y1, cx1, cy1 float64, styleStr string) { + // f.point(x0, y0) + // f.outf("%.5f %.5f %.5f %.5f %.5f %.5f c %s", cx0*f.k, (f.h-cy0)*f.k, + // cx1*f.k, (f.h-cy1)*f.k, x1*f.k, (f.h-y1)*f.k, fillDrawOp(styleStr)) + f.CurveBezierCubic(x0, y0, cx0, cy0, cx1, cy1, x1, y1, styleStr) +} + +// CurveBezierCubic draws a single-segment cubic Bézier curve. The curve starts at +// the point (x0, y0) and ends at the point (x1, y1). The control points (cx0, +// cy0) and (cx1, cy1) specify the curvature. At the start point, the curve is +// tangent to the straight line between the start point and the control point +// (cx0, cy0). At the end point, the curve is tangent to the straight line +// between the end point and the control point (cx1, cy1). +// +// 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, line width, and cap style centered on the curve's +// path. Filling uses the current fill color. +// +// This routine performs the same function as CurveCubic() but uses standard +// argument order. +// +// The Circle() example demonstrates this method. +func (f *Fpdf) CurveBezierCubic(x0, y0, cx0, cy0, cx1, cy1, x1, y1 float64, styleStr string) { + f.point(x0, y0) + f.outf("%.5f %.5f %.5f %.5f %.5f %.5f c %s", cx0*f.k, (f.h-cy0)*f.k, + cx1*f.k, (f.h-cy1)*f.k, x1*f.k, (f.h-y1)*f.k, fillDrawOp(styleStr)) +} + +// Arc draws an elliptical arc centered at point (x, y). rx and ry specify its +// horizontal and vertical radii. +// +// degRotate specifies the angle that the arc will be rotated. degStart and +// degEnd specify the starting and ending angle of the arc. All angles are +// specified in degrees and measured counter-clockwise from the 3 o'clock +// position. +// +// 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, line width, and cap style centered on the arc's +// path. Filling uses the current fill color. +// +// The Circle() example demonstrates this method. +func (f *Fpdf) Arc(x, y, rx, ry, degRotate, degStart, degEnd float64, styleStr string) { + f.arc(x, y, rx, ry, degRotate, degStart, degEnd, styleStr, false) +} + +// GetAlpha returns the alpha blending channel, which consists of the +// alpha transparency value and the blend mode. See SetAlpha for more +// details. +func (f *Fpdf) GetAlpha() (alpha float64, blendModeStr string) { + return f.alpha, f.blendMode +} + +// SetAlpha sets the alpha blending channel. The blending effect applies to +// text, drawings and images. +// +// alpha must be a value between 0.0 (fully transparent) to 1.0 (fully opaque). +// Values outside of this range result in an error. +// +// blendModeStr must be one of "Normal", "Multiply", "Screen", "Overlay", +// "Darken", "Lighten", "ColorDodge", "ColorBurn","HardLight", "SoftLight", +// "Difference", "Exclusion", "Hue", "Saturation", "Color", or "Luminosity". An +// empty string is replaced with "Normal". +// +// To reset normal rendering after applying a blending mode, call this method +// with alpha set to 1.0 and blendModeStr set to "Normal". +func (f *Fpdf) SetAlpha(alpha float64, blendModeStr string) { + if f.err != nil { + return + } + var bl blendModeType + switch blendModeStr { + case "Normal", "Multiply", "Screen", "Overlay", + "Darken", "Lighten", "ColorDodge", "ColorBurn", "HardLight", "SoftLight", + "Difference", "Exclusion", "Hue", "Saturation", "Color", "Luminosity": + bl.modeStr = blendModeStr + case "": + bl.modeStr = "Normal" + default: + f.err = fmt.Errorf("unrecognized blend mode \"%s\"", blendModeStr) + return + } + if alpha < 0.0 || alpha > 1.0 { + f.err = fmt.Errorf("alpha value (0.0 - 1.0) is out of range: %.3f", alpha) + return + } + f.alpha = alpha + f.blendMode = blendModeStr + alphaStr := sprintf("%.3f", alpha) + keyStr := sprintf("%s %s", alphaStr, blendModeStr) + pos, ok := f.blendMap[keyStr] + if !ok { + pos = len(f.blendList) // at least 1 + f.blendList = append(f.blendList, blendModeType{alphaStr, alphaStr, blendModeStr, 0}) + f.blendMap[keyStr] = pos + } + f.outf("/GS%d gs", pos) +} + +func (f *Fpdf) gradientClipStart(x, y, w, h float64) { + // Save current graphic state and set clipping area + f.outf("q %.2f %.2f %.2f %.2f re W n", x*f.k, (f.h-y)*f.k, w*f.k, -h*f.k) + // Set up transformation matrix for gradient + f.outf("%.5f 0 0 %.5f %.5f %.5f cm", w*f.k, h*f.k, x*f.k, (f.h-(y+h))*f.k) +} + +func (f *Fpdf) gradientClipEnd() { + // Restore previous graphic state + f.out("Q") +} + +func (f *Fpdf) gradient(tp, r1, g1, b1, r2, g2, b2 int, x1, y1, x2, y2, r float64) { + pos := len(f.gradientList) + clr1 := rgbColorValue(r1, g1, b1, "", "") + clr2 := rgbColorValue(r2, g2, b2, "", "") + f.gradientList = append(f.gradientList, gradientType{tp, clr1.str, clr2.str, + x1, y1, x2, y2, r, 0}) + f.outf("/Sh%d sh", pos) +} + +// LinearGradient draws a rectangular area with a blending of one color to +// another. The rectangle is of width w and height h. Its upper left corner is +// positioned at point (x, y). +// +// Each color is specified with three component values, one each for red, green +// and blue. The values range from 0 to 255. The first color is specified by +// (r1, g1, b1) and the second color by (r2, g2, b2). +// +// The blending is controlled with a gradient vector that uses normalized +// coordinates in which the lower left corner is position (0, 0) and the upper +// right corner is (1, 1). The vector's origin and destination are specified by +// the points (x1, y1) and (x2, y2). In a linear gradient, blending occurs +// perpendicularly to the vector. The vector does not necessarily need to be +// anchored on the rectangle edge. Color 1 is used up to the origin of the +// vector and color 2 is used beyond the vector's end point. Between the points +// the colors are gradually blended. +func (f *Fpdf) LinearGradient(x, y, w, h float64, r1, g1, b1, r2, g2, b2 int, x1, y1, x2, y2 float64) { + f.gradientClipStart(x, y, w, h) + f.gradient(2, r1, g1, b1, r2, g2, b2, x1, y1, x2, y2, 0) + f.gradientClipEnd() +} + +// RadialGradient draws a rectangular area with a blending of one color to +// another. The rectangle is of width w and height h. Its upper left corner is +// positioned at point (x, y). +// +// Each color is specified with three component values, one each for red, green +// and blue. The values range from 0 to 255. The first color is specified by +// (r1, g1, b1) and the second color by (r2, g2, b2). +// +// The blending is controlled with a point and a circle, both specified with +// normalized coordinates in which the lower left corner of the rendered +// rectangle is position (0, 0) and the upper right corner is (1, 1). Color 1 +// begins at the origin point specified by (x1, y1). Color 2 begins at the +// circle specified by the center point (x2, y2) and radius r. Colors are +// gradually blended from the origin to the circle. The origin and the circle's +// center do not necessarily have to coincide, but the origin must be within +// the circle to avoid rendering problems. +// +// The LinearGradient() example demonstrates this method. +func (f *Fpdf) RadialGradient(x, y, w, h float64, r1, g1, b1, r2, g2, b2 int, x1, y1, x2, y2, r float64) { + f.gradientClipStart(x, y, w, h) + f.gradient(3, r1, g1, b1, r2, g2, b2, x1, y1, x2, y2, r) + f.gradientClipEnd() +} + +// ClipRect begins a rectangular clipping operation. The rectangle is of width +// w and height h. Its upper left corner is positioned at point (x, y). outline +// is true to draw a border with the current draw color and line width centered +// on the rectangle's perimeter. Only the outer half of the border will be +// shown. After calling this method, all rendering operations (for example, +// Image(), LinearGradient(), etc) will be clipped by the specified rectangle. +// Call ClipEnd() to restore unclipped operations. +// +// This ClipText() example demonstrates this method. +func (f *Fpdf) ClipRect(x, y, w, h float64, outline bool) { + f.clipNest++ + f.outf("q %.2f %.2f %.2f %.2f re W %s", x*f.k, (f.h-y)*f.k, w*f.k, -h*f.k, strIf(outline, "S", "n")) +} + +// ClipText begins a clipping operation in which rendering is confined to the +// character string specified by txtStr. The origin (x, y) is on the left of +// the first character at the baseline. The current font is used. outline is +// true to draw a border with the current draw color and line width centered on +// the perimeters of the text characters. Only the outer half of the border +// will be shown. After calling this method, all rendering operations (for +// example, Image(), LinearGradient(), etc) will be clipped. Call ClipEnd() to +// restore unclipped operations. +func (f *Fpdf) ClipText(x, y float64, txtStr string, outline bool) { + f.clipNest++ + f.outf("q BT %.5f %.5f Td %d Tr (%s) Tj ET", x*f.k, (f.h-y)*f.k, intIf(outline, 5, 7), f.escape(txtStr)) +} + +func (f *Fpdf) clipArc(x1, y1, x2, y2, x3, y3 float64) { + h := f.h + f.outf("%.5f %.5f %.5f %.5f %.5f %.5f c ", x1*f.k, (h-y1)*f.k, + x2*f.k, (h-y2)*f.k, x3*f.k, (h-y3)*f.k) +} + +// ClipRoundedRect begins a rectangular clipping operation. The rectangle is of +// width w and height h. Its upper left corner is positioned at point (x, y). +// The rounded corners of the rectangle are specified by radius r. outline is +// true to draw a border with the current draw color and line width centered on +// the rectangle's perimeter. Only the outer half of the border will be shown. +// After calling this method, all rendering operations (for example, Image(), +// LinearGradient(), etc) will be clipped by the specified rectangle. Call +// ClipEnd() to restore unclipped operations. +// +// This ClipText() example demonstrates this method. +func (f *Fpdf) ClipRoundedRect(x, y, w, h, r float64, outline bool) { + f.ClipRoundedRectExt(x, y, w, h, r, r, r, r, outline) +} + +// ClipRoundedRectExt behaves the same as ClipRoundedRect() but supports a +// different radius for each corner, given by rTL (top-left), rTR (top-right) +// rBR (bottom-right), rBL (bottom-left). See ClipRoundedRect() for more +// details. This method is demonstrated in the ClipText() example. +func (f *Fpdf) ClipRoundedRectExt(x, y, w, h, rTL, rTR, rBR, rBL float64, outline bool) { + f.clipNest++ + f.roundedRectPath(x, y, w, h, rTL, rTR, rBR, rBL) + f.outf(" W %s", strIf(outline, "S", "n")) +} + +// add a rectangle path with rounded corners. +// routine shared by RoundedRect() and ClipRoundedRect(), which add the +// drawing operation +func (f *Fpdf) roundedRectPath(x, y, w, h, rTL, rTR, rBR, rBL float64) { + k := f.k + hp := f.h + myArc := (4.0 / 3.0) * (math.Sqrt2 - 1.0) + f.outf("q %.5f %.5f m", (x+rTL)*k, (hp-y)*k) + xc := x + w - rTR + yc := y + rTR + f.outf("%.5f %.5f l", xc*k, (hp-y)*k) + if rTR != 0 { + f.clipArc(xc+rTR*myArc, yc-rTR, xc+rTR, yc-rTR*myArc, xc+rTR, yc) + } + xc = x + w - rBR + yc = y + h - rBR + f.outf("%.5f %.5f l", (x+w)*k, (hp-yc)*k) + if rBR != 0 { + f.clipArc(xc+rBR, yc+rBR*myArc, xc+rBR*myArc, yc+rBR, xc, yc+rBR) + } + xc = x + rBL + yc = y + h - rBL + f.outf("%.5f %.5f l", xc*k, (hp-(y+h))*k) + if rBL != 0 { + f.clipArc(xc-rBL*myArc, yc+rBL, xc-rBL, yc+rBL*myArc, xc-rBL, yc) + } + xc = x + rTL + yc = y + rTL + f.outf("%.5f %.5f l", x*k, (hp-yc)*k) + if rTL != 0 { + f.clipArc(xc-rTL, yc-rTL*myArc, xc-rTL*myArc, yc-rTL, xc, yc-rTL) + } +} + +// ClipEllipse begins an elliptical clipping operation. The ellipse is centered +// at (x, y). Its horizontal and vertical radii are specified by rx and ry. +// outline is true to draw a border with the current draw color and line width +// centered on the ellipse's perimeter. Only the outer half of the border will +// be shown. After calling this method, all rendering operations (for example, +// Image(), LinearGradient(), etc) will be clipped by the specified ellipse. +// Call ClipEnd() to restore unclipped operations. +// +// This ClipText() example demonstrates this method. +func (f *Fpdf) ClipEllipse(x, y, rx, ry float64, outline bool) { + f.clipNest++ + lx := (4.0 / 3.0) * rx * (math.Sqrt2 - 1) + ly := (4.0 / 3.0) * ry * (math.Sqrt2 - 1) + k := f.k + h := f.h + f.outf("q %.5f %.5f m %.5f %.5f %.5f %.5f %.5f %.5f c", + (x+rx)*k, (h-y)*k, + (x+rx)*k, (h-(y-ly))*k, + (x+lx)*k, (h-(y-ry))*k, + x*k, (h-(y-ry))*k) + f.outf("%.5f %.5f %.5f %.5f %.5f %.5f c", + (x-lx)*k, (h-(y-ry))*k, + (x-rx)*k, (h-(y-ly))*k, + (x-rx)*k, (h-y)*k) + f.outf("%.5f %.5f %.5f %.5f %.5f %.5f c", + (x-rx)*k, (h-(y+ly))*k, + (x-lx)*k, (h-(y+ry))*k, + x*k, (h-(y+ry))*k) + f.outf("%.5f %.5f %.5f %.5f %.5f %.5f c W %s", + (x+lx)*k, (h-(y+ry))*k, + (x+rx)*k, (h-(y+ly))*k, + (x+rx)*k, (h-y)*k, + strIf(outline, "S", "n")) +} + +// ClipCircle begins a circular clipping operation. The circle is centered at +// (x, y) and has radius r. outline is true to draw a border with the current +// draw color and line width centered on the circle's perimeter. Only the outer +// half of the border will be shown. After calling this method, all rendering +// operations (for example, Image(), LinearGradient(), etc) will be clipped by +// the specified circle. Call ClipEnd() to restore unclipped operations. +// +// The ClipText() example demonstrates this method. +func (f *Fpdf) ClipCircle(x, y, r float64, outline bool) { + f.ClipEllipse(x, y, r, r, outline) +} + +// ClipPolygon begins a clipping operation within a polygon. The figure is +// defined by a series of vertices specified by points. The x and y fields of +// the points use the units established in New(). The last point in the slice +// will be implicitly joined to the first to close the polygon. outline is true +// to draw a border with the current draw color and line width centered on the +// polygon's perimeter. Only the outer half of the border will be shown. After +// calling this method, all rendering operations (for example, Image(), +// LinearGradient(), etc) will be clipped by the specified polygon. Call +// ClipEnd() to restore unclipped operations. +// +// The ClipText() example demonstrates this method. +func (f *Fpdf) ClipPolygon(points []PointType, outline bool) { + f.clipNest++ + var s fmtBuffer + h := f.h + k := f.k + s.printf("q ") + for j, pt := range points { + s.printf("%.5f %.5f %s ", pt.X*k, (h-pt.Y)*k, strIf(j == 0, "m", "l")) + } + s.printf("h W %s", strIf(outline, "S", "n")) + f.out(s.String()) +} + +// ClipEnd ends a clipping operation that was started with a call to +// ClipRect(), ClipRoundedRect(), ClipText(), ClipEllipse(), ClipCircle() or +// ClipPolygon(). Clipping operations can be nested. The document cannot be +// successfully output while a clipping operation is active. +// +// The ClipText() example demonstrates this method. +func (f *Fpdf) ClipEnd() { + if f.err == nil { + if f.clipNest > 0 { + f.clipNest-- + f.out("Q") + } else { + f.err = fmt.Errorf("error attempting to end clip operation out of sequence") + } + } +} + +// AddFont imports a TrueType, OpenType or Type1 font and makes it available. +// It is necessary to generate a font definition file first with the makefont +// utility. It is not necessary to call this function for the core PDF fonts +// (courier, helvetica, times, zapfdingbats). +// +// The JSON definition file (and the font file itself when embedding) must be +// present in the font directory. If it is not found, the error "Could not +// include font definition file" is set. +// +// family specifies the font family. The name can be chosen arbitrarily. If it +// is a standard family name, it will override the corresponding font. This +// string is used to subsequently set the font with the SetFont method. +// +// style specifies the font style. Acceptable values are (case insensitive) the +// empty string for regular style, "B" for bold, "I" for italic, or "BI" or +// "IB" for bold and italic combined. +// +// fileStr specifies the base name with ".json" extension of the font +// 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(fontFamilyEscape(familyStr), styleStr, fileStr, false) +} + +// AddUTF8Font imports a TrueType font with utf-8 symbols and makes it available. +// It is necessary to generate a font definition file first with the makefont +// utility. It is not necessary to call this function for the core PDF fonts +// (courier, helvetica, times, zapfdingbats). +// +// The JSON definition file (and the font file itself when embedding) must be +// present in the font directory. If it is not found, the error "Could not +// include font definition file" is set. +// +// family specifies the font family. The name can be chosen arbitrarily. If it +// is a standard family name, it will override the corresponding font. This +// string is used to subsequently set the font with the SetFont method. +// +// style specifies the font style. Acceptable values are (case insensitive) the +// empty string for regular style, "B" for bold, "I" for italic, or "BI" or +// "IB" for bold and italic combined. +// +// fileStr specifies the base name with ".json" extension of the font +// 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(fontFamilyEscape(familyStr), styleStr, fileStr, true) +} + +func (f *Fpdf) addFont(familyStr, styleStr, fileStr string, isUTF8 bool) { + if fileStr == "" { + if isUTF8 { + fileStr = strings.Replace(familyStr, " ", "", -1) + strings.ToLower(styleStr) + ".ttf" + } else { + fileStr = strings.Replace(familyStr, " ", "", -1) + strings.ToLower(styleStr) + ".json" + } + } + if isUTF8 { + fontKey := getFontKey(familyStr, styleStr) + _, ok := f.fonts[fontKey] + if ok { + return + } + 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" + 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() + if err != nil { + f.SetError(err) + return + } + + desc := FontDescType{ + Ascent: int(utf8File.Ascent), + Descent: int(utf8File.Descent), + CapHeight: utf8File.CapHeight, + Flags: utf8File.Flags, + FontBBox: utf8File.Bbox, + ItalicAngle: utf8File.ItalicAngle, + StemV: utf8File.StemV, + MissingWidth: round(utf8File.DefaultWidth), + } + + var sbarr map[int]int + if f.aliasNbPagesStr == "" { + sbarr = makeSubsetRange(57) + } else { + sbarr = makeSubsetRange(32) + } + def := fontDefType{ + Tp: Type, + Name: fontKey, + Desc: desc, + Up: int(round(utf8File.UnderlinePosition)), + Ut: round(utf8File.UnderlineThickness), + Cw: utf8File.CharWidths, + usedRunes: sbarr, + File: fileStr, + utf8File: utf8File, + } + def.i, _ = generateFontID(def) + f.fonts[fontKey] = def + f.fontFiles[fontKey] = fontFileType{ + length1: originalSize, + fontType: "UTF8", + } + f.fontFiles[fileStr] = fontFileType{ + fontType: "UTF8", + } + } else { + if f.fontLoader != nil { + reader, err := f.fontLoader.Open(fileStr) + if err == nil { + f.AddFontFromReader(familyStr, styleStr, reader) + if closer, ok := reader.(io.Closer); ok { + closer.Close() + } + return + } + } + + fileStr = path.Join(f.fontpath, fileStr) + file, err := os.Open(fileStr) + if err != nil { + f.err = err + return + } + defer file.Close() + + f.AddFontFromReader(familyStr, styleStr, file) + } +} + +func makeSubsetRange(end int) map[int]int { + answer := make(map[int]int) + for i := 0; i < end; i++ { + answer[i] = 0 + } + return answer +} + +// AddFontFromBytes imports a TrueType, OpenType or Type1 font from static +// bytes within the executable and makes it available for use in the generated +// document. +// +// family specifies the font family. The name can be chosen arbitrarily. If it +// is a standard family name, it will override the corresponding font. This +// string is used to subsequently set the font with the SetFont method. +// +// style specifies the font style. Acceptable values are (case insensitive) the +// empty string for regular style, "B" for bold, "I" for italic, or "BI" or +// "IB" for bold and italic combined. +// +// jsonFileBytes contain all bytes of JSON file. +// +// zFileBytes contain all bytes of Z file. +func (f *Fpdf) AddFontFromBytes(familyStr, styleStr string, jsonFileBytes, zFileBytes []byte) { + f.addFontFromBytes(fontFamilyEscape(familyStr), styleStr, jsonFileBytes, zFileBytes, nil) +} + +// AddUTF8FontFromBytes imports a TrueType font with utf-8 symbols from static +// bytes within the executable and makes it available for use in the generated +// document. +// +// family specifies the font family. The name can be chosen arbitrarily. If it +// is a standard family name, it will override the corresponding font. This +// string is used to subsequently set the font with the SetFont method. +// +// style specifies the font style. Acceptable values are (case insensitive) the +// empty string for regular style, "B" for bold, "I" for italic, or "BI" or +// "IB" for bold and italic combined. +// +// jsonFileBytes contain all bytes of JSON file. +// +// zFileBytes contain all bytes of Z file. +func (f *Fpdf) AddUTF8FontFromBytes(familyStr, styleStr string, utf8Bytes []byte) { + f.addFontFromBytes(fontFamilyEscape(familyStr), styleStr, nil, nil, utf8Bytes) +} + +func (f *Fpdf) addFontFromBytes(familyStr, styleStr string, jsonFileBytes, zFileBytes, utf8Bytes []byte) { + if f.err != nil { + return + } + + // load font key + var ok bool + fontkey := getFontKey(familyStr, styleStr) + _, ok = f.fonts[fontkey] + + if ok { + return + } + + if utf8Bytes != nil { + + // if styleStr == "IB" { + // styleStr = "BI" + // } + + Type := "UTF8" + reader := fileReader{readerPosition: 0, array: utf8Bytes} + + utf8File := newUTF8Font(&reader) + + err := utf8File.parseFile() + if err != nil { + fmt.Printf("get metrics Error: %e\n", err) + return + } + desc := FontDescType{ + Ascent: int(utf8File.Ascent), + Descent: int(utf8File.Descent), + CapHeight: utf8File.CapHeight, + Flags: utf8File.Flags, + FontBBox: utf8File.Bbox, + ItalicAngle: utf8File.ItalicAngle, + StemV: utf8File.StemV, + MissingWidth: round(utf8File.DefaultWidth), + } + + var sbarr map[int]int + if f.aliasNbPagesStr == "" { + sbarr = makeSubsetRange(57) + } else { + sbarr = makeSubsetRange(32) + } + def := fontDefType{ + Tp: Type, + Name: fontkey, + Desc: desc, + Up: int(round(utf8File.UnderlinePosition)), + Ut: round(utf8File.UnderlineThickness), + Cw: utf8File.CharWidths, + utf8File: utf8File, + usedRunes: sbarr, + } + def.i, _ = generateFontID(def) + f.fonts[fontkey] = def + } else { + // load font definitions + var info fontDefType + err := json.Unmarshal(jsonFileBytes, &info) + + if err != nil { + f.err = err + } + + if f.err != nil { + return + } + + if info.i, err = generateFontID(info); err != nil { + f.err = err + return + } + + // search existing encodings + if len(info.Diff) > 0 { + n := -1 + + for j, str := range f.diffs { + if str == info.Diff { + n = j + 1 + break + } + } + + if n < 0 { + f.diffs = append(f.diffs, info.Diff) + n = len(f.diffs) + } + + info.DiffN = n + } + + // embed font + if len(info.File) > 0 { + if info.Tp == "TrueType" { + f.fontFiles[info.File] = fontFileType{ + length1: int64(info.OriginalSize), + embedded: true, + content: zFileBytes, + } + } else { + f.fontFiles[info.File] = fontFileType{ + length1: int64(info.Size1), + length2: int64(info.Size2), + embedded: true, + content: zFileBytes, + } + } + } + + f.fonts[fontkey] = info + } +} + +// getFontKey is used by AddFontFromReader and GetFontDesc +func getFontKey(familyStr, styleStr string) string { + familyStr = strings.ToLower(familyStr) + styleStr = strings.ToUpper(styleStr) + if styleStr == "IB" { + styleStr = "BI" + } + return familyStr + styleStr +} + +// AddFontFromReader imports a TrueType, OpenType or Type1 font and makes it +// available using a reader that satisifies the io.Reader interface. See +// AddFont for details about familyStr and styleStr. +func (f *Fpdf) AddFontFromReader(familyStr, styleStr string, r io.Reader) { + if f.err != nil { + return + } + // dbg("Adding family [%s], style [%s]", familyStr, styleStr) + familyStr = fontFamilyEscape(familyStr) + var ok bool + fontkey := getFontKey(familyStr, styleStr) + _, ok = f.fonts[fontkey] + if ok { + return + } + var info fontDefType + info = f.loadfont(r) + if f.err != nil { + return + } + if len(info.Diff) > 0 { + // Search existing encodings + n := -1 + for j, str := range f.diffs { + if str == info.Diff { + n = j + 1 + break + } + } + if n < 0 { + f.diffs = append(f.diffs, info.Diff) + n = len(f.diffs) + } + info.DiffN = n + } + // dbg("font [%s], type [%s]", info.File, info.Tp) + if len(info.File) > 0 { + // Embedded font + if info.Tp == "TrueType" { + f.fontFiles[info.File] = fontFileType{length1: int64(info.OriginalSize)} + } else { + f.fontFiles[info.File] = fontFileType{length1: int64(info.Size1), length2: int64(info.Size2)} + } + } + f.fonts[fontkey] = info + return +} + +// GetFontDesc returns the font descriptor, which can be used for +// example to find the baseline of a font. If familyStr is empty +// current font descriptor will be returned. +// See FontDescType for documentation about the font descriptor. +// See AddFont for details about familyStr and styleStr. +func (f *Fpdf) GetFontDesc(familyStr, styleStr string) FontDescType { + if familyStr == "" { + return f.currentFont.Desc + } + return f.fonts[getFontKey(fontFamilyEscape(familyStr), styleStr)].Desc +} + +// SetFont sets the font used to print character strings. It is mandatory to +// call this method at least once before printing text or the resulting +// document will not be valid. +// +// The font can be either a standard one or a font added via the AddFont() +// method or AddFontFromReader() method. Standard fonts use the Windows +// encoding cp1252 (Western Europe). +// +// The method can be called before the first page is created and the font is +// kept from page to page. If you just wish to change the current font size, it +// is simpler to call SetFontSize(). +// +// Note: the font definition file must be accessible. An error is set if the +// file cannot be read. +// +// familyStr specifies the font family. It can be either a name defined by +// AddFont(), AddFontFromReader() or one of the standard families (case +// 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), "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 +// value taken is 12. +func (f *Fpdf) SetFont(familyStr, styleStr string, size float64) { + // dbg("SetFont x %.2f, lMargin %.2f", f.x, f.lMargin) + + if f.err != nil { + return + } + // dbg("SetFont") + familyStr = fontFamilyEscape(familyStr) + var ok bool + if familyStr == "" { + familyStr = f.fontFamily + } else { + familyStr = strings.ToLower(familyStr) + } + styleStr = strings.ToUpper(styleStr) + f.underline = strings.Contains(styleStr, "U") + 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" + } + if size == 0.0 { + size = f.fontSizePt + } + + // Test if font is already loaded + fontKey := familyStr + styleStr + _, ok = f.fonts[fontKey] + if !ok { + // Test if one of the core fonts + if familyStr == "arial" { + familyStr = "helvetica" + } + _, ok = f.coreFonts[familyStr] + if ok { + if familyStr == "symbol" { + familyStr = "zapfdingbats" + } + if familyStr == "zapfdingbats" { + styleStr = "" + } + fontKey = familyStr + styleStr + _, ok = f.fonts[fontKey] + if !ok { + rdr := f.coreFontReader(familyStr, styleStr) + if f.err == nil { + f.AddFontFromReader(familyStr, styleStr, rdr) + } + if f.err != nil { + return + } + } + } else { + f.err = fmt.Errorf("undefined font: %s %s", familyStr, styleStr) + return + } + } + // Select it + f.fontFamily = familyStr + f.fontStyle = styleStr + f.fontSizePt = size + f.fontSize = size / f.k + f.currentFont = f.fonts[fontKey] + if f.currentFont.Tp == "UTF8" { + f.isCurrentUTF8 = true + } else { + f.isCurrentUTF8 = false + } + if f.page > 0 { + f.outf("BT /F%s %.2f Tf ET", f.currentFont.i, f.fontSizePt) + } + 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) { + f.fontSizePt = size + f.fontSize = size / f.k + if f.page > 0 { + f.outf("BT /F%s %.2f Tf ET", f.currentFont.i, f.fontSizePt) + } +} + +// SetFontUnitSize defines the size of the current font. Size is specified in +// the unit of measure specified in New(). See also SetFontSize(). +func (f *Fpdf) SetFontUnitSize(size float64) { + f.fontSizePt = size * f.k + f.fontSize = size + if f.page > 0 { + f.outf("BT /F%s %.2f Tf ET", f.currentFont.i, f.fontSizePt) + } +} + +// GetFontSize returns the size of the current font in points followed by the +// size in the unit of measure specified in New(). The second value can be used +// as a line height value in drawing operations. +func (f *Fpdf) GetFontSize() (ptSize, unitSize float64) { + return f.fontSizePt, f.fontSize +} + +// AddLink creates a new internal link and returns its identifier. An internal +// link is a clickable area which directs to another place within the document. +// The identifier can then be passed to Cell(), Write(), Image() or Link(). The +// destination is defined with SetLink(). +func (f *Fpdf) AddLink() int { + f.links = append(f.links, intLinkType{}) + return len(f.links) - 1 +} + +// SetLink defines the page and position a link points to. See AddLink(). +func (f *Fpdf) SetLink(link int, y float64, page int) { + if y == -1 { + y = f.y + } + if page == -1 { + page = f.page + } + f.links[link] = intLinkType{page, y} +} + +// newLink adds a new clickable link on current page +func (f *Fpdf) newLink(x, y, w, h float64, link int, linkStr string) { + // linkList, ok := f.pageLinks[f.page] + // if !ok { + // linkList = make([]linkType, 0, 8) + // f.pageLinks[f.page] = linkList + // } + f.pageLinks[f.page] = append(f.pageLinks[f.page], + linkType{x * f.k, f.hPt - y*f.k, w * f.k, h * f.k, link, linkStr}) +} + +// Link puts a link on a rectangular area of the page. Text or image links are +// generally put via Cell(), Write() or Image(), but this method can be useful +// for instance to define a clickable area inside an image. link is the value +// returned by AddLink(). +func (f *Fpdf) Link(x, y, w, h float64, link int) { + f.newLink(x, y, w, h, link, "") +} + +// LinkString puts a link on a rectangular area of the page. Text or image +// links are generally put via Cell(), Write() or Image(), but this method can +// be useful for instance to define a clickable area inside an image. linkStr +// is the target URL. +func (f *Fpdf) LinkString(x, y, w, h float64, linkStr string) { + f.newLink(x, y, w, h, 0, linkStr) +} + +// Bookmark sets a bookmark that will be displayed in a sidebar outline. txtStr +// is the title of the bookmark. level specifies the level of the bookmark in +// the outline; 0 is the top level, 1 is just below, and so on. y specifies the +// vertical position of the bookmark destination in the current page; -1 +// indicates the current position. +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}) +} + +// Text prints a character string. The origin (x, y) is on the left of the +// first character at the baseline. This method permits a string to be placed +// precisely on the page, but it is usually easier to use Cell(), MultiCell() +// or Write() which are the standard methods to print text. +func (f *Fpdf) Text(x, y float64, txtStr string) { + var txt2 string + if f.isCurrentUTF8 { + if f.isRTL { + txtStr = reverseText(txtStr) + x -= f.GetStringWidth(txtStr) + } + txt2 = f.escape(utf8toutf16(txtStr, false)) + for _, uni := range []rune(txtStr) { + f.currentFont.usedRunes[int(uni)] = int(uni) + } + } else { + txt2 = f.escape(txtStr) + } + s := sprintf("BT %.2f %.2f Td (%s) Tj ET", x*f.k, (f.h-y)*f.k, txt2) + 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) + } + f.out(s) +} + +// SetWordSpacing sets spacing between words of following text. See the +// WriteAligned() example for a demonstration of its use. +func (f *Fpdf) SetWordSpacing(space float64) { + f.out(sprintf("%.5f Tw", space*f.k)) +} + +// SetTextRenderingMode sets the rendering mode of following text. +// The mode can be as follows: +// 0: Fill text +// 1: Stroke text +// 2: Fill, then stroke text +// 3: Neither fill nor stroke text (invisible) +// 4: Fill text and add to path for clipping +// 5: Stroke text and add to path for clipping +// 6: Fills then stroke text and add to path for clipping +// 7: Add text to path for clipping +// This method is demonstrated in the SetTextRenderingMode example. +func (f *Fpdf) SetTextRenderingMode(mode int) { + if mode >= 0 && mode <= 7 { + f.out(sprintf("%d Tr", mode)) + } +} + +// SetAcceptPageBreakFunc allows the application to control where page breaks +// occur. +// +// fnc is an application function (typically a closure) that is called by the +// library whenever a page break condition is met. The break is issued if true +// is returned. The default implementation returns a value according to the +// mode selected by SetAutoPageBreak. The function provided should not be +// called by the application. +// +// See the example for SetLeftMargin() to see how this function can be used to +// manage multiple columns. +func (f *Fpdf) SetAcceptPageBreakFunc(fnc func() bool) { + f.acceptPageBreak = fnc +} + +// CellFormat prints a rectangular cell with optional borders, background color +// and character string. The upper-left corner of the cell corresponds to the +// current position. The text can be aligned or centered. After the call, the +// current position moves to the right or to the next line. It is possible to +// put a link on the text. +// +// An error will be returned if a call to SetFont() has not already taken +// place before this method is called. +// +// If automatic page breaking is enabled and the cell goes beyond the limit, a +// page break is done before outputting. +// +// w and h specify the width and height of the cell. If w is 0, the cell +// extends up to the right margin. Specifying 0 for h will result in no output, +// but the current position will be advanced by w. +// +// txtStr specifies the text to display. +// +// borderStr specifies how the cell border will be drawn. An empty string +// indicates no border, "1" indicates a full border, and one or more of "L", +// "T", "R" and "B" indicate the left, top, right and bottom sides of the +// border. +// +// ln indicates where the current position should go after the call. Possible +// values are 0 (to the right), 1 (to the beginning of the next line), and 2 +// (below). Putting 1 is equivalent to putting 0 and calling Ln() just after. +// +// alignStr specifies how the text is to be positioned within the cell. +// Horizontal alignment is controlled by including "L", "C" or "R" (left, +// center, right) in alignStr. Vertical alignment is controlled by including +// "T", "M", "B" or "A" (top, middle, bottom, baseline) in alignStr. The default +// alignment is left middle. +// +// fill is true to paint the cell background or false to leave it transparent. +// +// link is the identifier returned by AddLink() or 0 for no internal link. +// +// linkStr is a target URL or empty for no external link. A non--zero value for +// link takes precedence over linkStr. +func (f *Fpdf) CellFormat(w, h float64, txtStr, borderStr string, ln int, + alignStr string, fill bool, link int, linkStr string) { + // dbg("CellFormat. h = %.2f, borderStr = %s", h, borderStr) + if f.err != nil { + return + } + + if f.currentFont.Name == "" { + f.err = fmt.Errorf("font has not been set; unable to render text") + return + } + + borderStr = strings.ToUpper(borderStr) + k := f.k + if f.y+h > f.pageBreakTrigger && !f.inHeader && !f.inFooter && f.acceptPageBreak() { + // Automatic page break + x := f.x + ws := f.ws + // dbg("auto page break, x %.2f, ws %.2f", x, ws) + if ws > 0 { + f.ws = 0 + f.out("0 Tw") + } + f.AddPageFormat(f.curOrientation, f.curPageSize) + if f.err != nil { + return + } + f.x = x + if ws > 0 { + f.ws = ws + f.outf("%.3f Tw", ws*k) + } + } + if w == 0 { + w = f.w - f.rMargin - f.x + } + var s fmtBuffer + if fill || borderStr == "1" { + var op string + if fill { + if borderStr == "1" { + op = "B" + // dbg("border is '1', fill") + } else { + op = "f" + // dbg("border is empty, fill") + } + } else { + // dbg("border is '1', no fill") + op = "S" + } + /// dbg("(CellFormat) f.x %.2f f.k %.2f", f.x, f.k) + s.printf("%.2f %.2f %.2f %.2f re %s ", f.x*k, (f.h-f.y)*k, w*k, -h*k, op) + } + if len(borderStr) > 0 && borderStr != "1" { + // fmt.Printf("border is '%s', no fill\n", borderStr) + x := f.x + y := f.y + left := x * k + top := (f.h - y) * k + right := (x + w) * k + bottom := (f.h - (y + h)) * k + if strings.Contains(borderStr, "L") { + s.printf("%.2f %.2f m %.2f %.2f l S ", left, top, left, bottom) + } + if strings.Contains(borderStr, "T") { + s.printf("%.2f %.2f m %.2f %.2f l S ", left, top, right, top) + } + if strings.Contains(borderStr, "R") { + s.printf("%.2f %.2f m %.2f %.2f l S ", right, top, right, bottom) + } + if strings.Contains(borderStr, "B") { + s.printf("%.2f %.2f m %.2f %.2f l S ", left, bottom, right, bottom) + } + } + if len(txtStr) > 0 { + var dx, dy float64 + // Horizontal alignment + switch { + case strings.Contains(alignStr, "R"): + dx = w - f.cMargin - f.GetStringWidth(txtStr) + case strings.Contains(alignStr, "C"): + dx = (w - f.GetStringWidth(txtStr)) / 2 + default: + dx = f.cMargin + } + + // Vertical alignment + switch { + case strings.Contains(alignStr, "T"): + dy = (f.fontSize - h) / 2.0 + case strings.Contains(alignStr, "B"): + dy = (h - f.fontSize) / 2.0 + case strings.Contains(alignStr, "A"): + var descent float64 + d := f.currentFont.Desc + if d.Descent == 0 { + // not defined (standard font?), use average of 19% + descent = -0.19 * f.fontSize + } else { + descent = float64(d.Descent) * f.fontSize / float64(d.Ascent-d.Descent) + } + dy = (h-f.fontSize)/2.0 - descent + default: + dy = 0 + } + if f.colorFlag { + s.printf("q %s ", f.color.text.str) + } + //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 = reverseText(txtStr) + } + wmax := int(math.Ceil((w - 2*f.cMargin) * 1000 / f.fontSize)) + for _, uni := range []rune(txtStr) { + f.currentFont.usedRunes[int(uni)] = int(uni) + } + space := f.escape(utf8toutf16(" ", false)) + strSize := f.GetStringSymbolWidth(txtStr) + s.printf("BT 0 Tw %.2f %.2f Td [", (f.x+dx)*k, (f.h-(f.y+.5*h+.3*f.fontSize))*k) + t := strings.Split(txtStr, " ") + shift := float64((wmax - strSize)) / float64(len(t)-1) + numt := len(t) + for i := 0; i < numt; i++ { + tx := t[i] + tx = "(" + f.escape(utf8toutf16(tx, false)) + ")" + s.printf("%s ", tx) + if (i + 1) < numt { + s.printf("%.3f(%s) ", -shift, space) + } + } + s.printf("] TJ ET") + } else { + var txt2 string + if f.isCurrentUTF8 { + if f.isRTL { + txtStr = reverseText(txtStr) + } + txt2 = f.escape(utf8toutf16(txtStr, false)) + for _, uni := range []rune(txtStr) { + f.currentFont.usedRunes[int(uni)] = int(uni) + } + } else { + + txt2 = strings.Replace(txtStr, "\\", "\\\\", -1) + txt2 = strings.Replace(txt2, "(", "\\(", -1) + txt2 = strings.Replace(txt2, ")", "\\)", -1) + } + bt := (f.x + dx) * k + td := (f.h - (f.y + dy + .5*h + .3*f.fontSize)) * k + s.printf("BT %.2f %.2f Td (%s)Tj ET", bt, td, txt2) + //BT %.2F %.2F Td (%s) Tj ET',(f.x+dx)*k,(f.h-(f.y+.5*h+.3*f.FontSize))*k,txt2); + } + + 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") + } + if link > 0 || len(linkStr) > 0 { + f.newLink(f.x+dx, f.y+dy+.5*h-.5*f.fontSize, f.GetStringWidth(txtStr), f.fontSize, link, linkStr) + } + } + str := s.String() + if len(str) > 0 { + f.out(str) + } + f.lasth = h + if ln > 0 { + // Go to next line + f.y += h + if ln == 1 { + f.x = f.lMargin + } + } else { + f.x += w + } + return +} + +// Revert string to use in RTL languages +func reverseText(text string) string { + oldText := []rune(text) + newText := make([]rune, len(oldText)) + length := len(oldText) - 1 + for i, r := range oldText { + newText[length-i] = r + } + return string(newText) +} + +// Cell is a simpler version of CellFormat with no fill, border, links or +// 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, "") +} + +// Cellf is a simpler printf-style version of CellFormat with no fill, border, +// links or special alignment. See documentation for the fmt package for +// details on fmtStr and args. +func (f *Fpdf) Cellf(w, h float64, fmtStr string, args ...interface{}) { + f.CellFormat(w, h, sprintf(fmtStr, args...), "", 0, "L", false, 0, "") +} + +// SplitLines splits text into several lines using the current font. Each line +// has its length limited to a maximum width given by w. This function can be +// used to determine the total height of wrapped text for vertical placement +// purposes. +// +// 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 { + // Function contributed by Bruno Michel + lines := [][]byte{} + cw := f.currentFont.Cw + wmax := int(math.Ceil((w - 2*f.cMargin) * 1000 / f.fontSize)) + s := bytes.Replace(txt, []byte("\r"), []byte{}, -1) + nb := len(s) + for nb > 0 && s[nb-1] == '\n' { + nb-- + } + s = s[0:nb] + sep := -1 + i := 0 + j := 0 + l := 0 + for i < nb { + c := s[i] + l += cw[c] + if c == ' ' || c == '\t' || c == '\n' { + sep = i + } + if c == '\n' || l > wmax { + if sep == -1 { + if i == j { + i++ + } + sep = i + } else { + i = sep + 1 + } + lines = append(lines, s[j:sep]) + sep = -1 + j = i + l = 0 + } else { + i++ + } + } + if i != j { + lines = append(lines, s[j:i]) + } + return lines +} + +// MultiCell supports printing text with line breaks. They can be automatic (as +// soon as the text reaches the right border of the cell) or explicit (via the +// \n character). As many cells as necessary are output, one below the other. +// +// Text can be aligned, centered or justified. The cell block can be framed and +// the background painted. See CellFormat() for more details. +// +// The current position after calling MultiCell() is the beginning of the next +// line, equivalent to calling CellFormat with ln equal to 1. +// +// w is the width of the cells. A value of zero indicates cells that reach to +// the right margin. +// +// h indicates the line height of each cell in the unit of measure specified in New(). +// +// Note: this method has a known bug that treats UTF-8 fonts differently than +// non-UTF-8 fonts. With UTF-8 fonts, all trailing newlines in txtStr are +// removed. With a non-UTF-8 font, if txtStr has one or more trailing newlines, +// only the last is removed. In the next major module version, the UTF-8 logic +// will be changed to match the non-UTF-8 logic. To prepare for that change, +// applications that use UTF-8 fonts and depend on having all trailing newlines +// removed should call strings.TrimRight(txtStr, "\r\n") before calling this +// method. +func (f *Fpdf) MultiCell(w, h float64, txtStr, borderStr, alignStr string, fill bool) { + if f.err != nil { + return + } + // dbg("MultiCell") + if alignStr == "" { + alignStr = "J" + } + cw := f.currentFont.Cw + if w == 0 { + w = f.w - f.rMargin - f.x + } + 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(srune) + for nb > 0 && srune[nb-1] == '\n' { + nb-- + } + srune = srune[0:nb] + } else { + nb = len(s) + bytes2 := []byte(s) + + // for nb > 0 && bytes2[nb-1] == '\n' { + + // Prior to August 2019, if s ended with a newline, this code stripped it. + // After that date, to be compatible with the UTF-8 code above, *all* + // trailing newlines were removed. Because this regression caused at least + // one application to break (see issue #333), the original behavior has been + // reinstated with a caveat included in the documentation. + if nb > 0 && bytes2[nb-1] == '\n' { + nb-- + } + s = s[0:nb] + } + // dbg("[%s]\n", s) + var b, b2 string + b = "0" + if len(borderStr) > 0 { + if borderStr == "1" { + borderStr = "LTRB" + b = "LRT" + b2 = "LR" + } else { + b2 = "" + if strings.Contains(borderStr, "L") { + b2 += "L" + } + if strings.Contains(borderStr, "R") { + b2 += "R" + } + if strings.Contains(borderStr, "T") { + b = b2 + "T" + } else { + b = b2 + } + } + } + sep := -1 + i := 0 + j := 0 + l := 0 + ls := 0 + ns := 0 + nl := 1 + for i < nb { + // Get next character + var c rune + if f.isCurrentUTF8 { + c = srune[i] + } else { + c = rune(s[i]) + } + if c == '\n' { + // Explicit line break + if f.ws > 0 { + f.ws = 0 + f.out("0 Tw") + } + + if f.isCurrentUTF8 { + newAlignStr := alignStr + if newAlignStr == "J" { + if f.isRTL { + newAlignStr = "R" + } else { + newAlignStr = "L" + } + } + 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, "") + } + i++ + sep = -1 + j = i + l = 0 + ns = 0 + nl++ + if len(borderStr) > 0 && nl == 2 { + b = b2 + } + continue + } + if c == ' ' || isChinese(c) { + sep = i + ls = l + ns++ + } + if int(c) >= len(cw) { + f.err = fmt.Errorf("character outside the supported range: %s", string(c)) + return + } + if cw[int(c)] == 0 { //Marker width 0 used for missing symbols + l += f.currentFont.Desc.MissingWidth + } else if cw[int(c)] != 65535 { //Marker width 65535 used for zero width symbols + l += cw[int(c)] + } + if l > wmax { + // Automatic line break + if sep == -1 { + if i == j { + i++ + } + if f.ws > 0 { + f.ws = 0 + f.out("0 Tw") + } + if f.isCurrentUTF8 { + 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, "") + } + } else { + if alignStr == "J" { + if ns > 1 { + f.ws = float64((wmax-ls)/1000) * f.fontSize / float64(ns-1) + } else { + f.ws = 0 + } + f.outf("%.3f Tw", f.ws*f.k) + } + if f.isCurrentUTF8 { + 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, "") + } + i = sep + 1 + } + sep = -1 + j = i + l = 0 + ns = 0 + nl++ + if len(borderStr) > 0 && nl == 2 { + b = b2 + } + } else { + i++ + } + } + // Last chunk + if f.ws > 0 { + f.ws = 0 + f.out("0 Tw") + } + if len(borderStr) > 0 && strings.Contains(borderStr, "B") { + b += "B" + } + if f.isCurrentUTF8 { + if alignStr == "J" { + if f.isRTL { + alignStr = "R" + } else { + alignStr = "" + } + } + 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, "") + } + f.x = f.lMargin +} + +// write outputs text in flowing mode +func (f *Fpdf) write(h float64, txtStr string, link int, linkStr string) { + // dbg("Write") + cw := f.currentFont.Cw + w := f.w - f.rMargin - f.x + wmax := (w - 2*f.cMargin) * 1000 / f.fontSize + s := strings.Replace(txtStr, "\r", "", -1) + var nb int + if f.isCurrentUTF8 { + nb = len([]rune(s)) + if nb == 1 && s == " " { + f.x += f.GetStringWidth(s) + return + } + } else { + nb = len(s) + } + sep := -1 + i := 0 + j := 0 + l := 0.0 + nl := 1 + for i < nb { + // Get next character + var c rune + if f.isCurrentUTF8 { + c = []rune(s)[i] + } else { + c = rune(byte(s[i])) + } + if c == '\n' { + // Explicit line break + if f.isCurrentUTF8 { + f.CellFormat(w, h, string([]rune(s)[j:i]), "", 2, "", false, link, linkStr) + } else { + f.CellFormat(w, h, s[j:i], "", 2, "", false, link, linkStr) + } + i++ + sep = -1 + j = i + l = 0.0 + if nl == 1 { + f.x = f.lMargin + w = f.w - f.rMargin - f.x + wmax = (w - 2*f.cMargin) * 1000 / f.fontSize + } + nl++ + continue + } + if c == ' ' { + sep = i + } + l += float64(cw[int(c)]) + if l > wmax { + // Automatic line break + if sep == -1 { + if f.x > f.lMargin { + // Move to next line + f.x = f.lMargin + f.y += h + w = f.w - f.rMargin - f.x + wmax = (w - 2*f.cMargin) * 1000 / f.fontSize + i++ + nl++ + continue + } + if i == j { + i++ + } + if f.isCurrentUTF8 { + f.CellFormat(w, h, string([]rune(s)[j:i]), "", 2, "", false, link, linkStr) + } else { + f.CellFormat(w, h, s[j:i], "", 2, "", false, link, linkStr) + } + } else { + if f.isCurrentUTF8 { + f.CellFormat(w, h, string([]rune(s)[j:sep]), "", 2, "", false, link, linkStr) + } else { + f.CellFormat(w, h, s[j:sep], "", 2, "", false, link, linkStr) + } + i = sep + 1 + } + sep = -1 + j = i + l = 0.0 + if nl == 1 { + f.x = f.lMargin + w = f.w - f.rMargin - f.x + wmax = (w - 2*f.cMargin) * 1000 / f.fontSize + } + nl++ + } else { + i++ + } + } + // Last chunk + if i != j { + if f.isCurrentUTF8 { + f.CellFormat(l/1000*f.fontSize, h, string([]rune(s)[j:]), "", 0, "", false, link, linkStr) + } else { + f.CellFormat(l/1000*f.fontSize, h, s[j:], "", 0, "", false, link, linkStr) + } + } +} + +// Write prints text from the current position. When the right margin is +// reached (or the \n character is met) a line break occurs and text continues +// from the left margin. Upon method exit, the current position is left just at +// the end of the text. +// +// It is possible to put a link on the text. +// +// h indicates the line height in the unit of measure specified in New(). +func (f *Fpdf) Write(h float64, txtStr string) { + f.write(h, txtStr, 0, "") +} + +// Writef is like Write but uses printf-style formatting. See the documentation +// for package fmt for more details on fmtStr and args. +func (f *Fpdf) Writef(h float64, fmtStr string, args ...interface{}) { + f.write(h, sprintf(fmtStr, args...), 0, "") +} + +// WriteLinkString writes text that when clicked launches an external URL. See +// Write() for argument details. +func (f *Fpdf) WriteLinkString(h float64, displayStr, targetStr string) { + f.write(h, displayStr, 0, targetStr) +} + +// WriteLinkID writes text that when clicked jumps to another location in the +// PDF. linkID is an identifier returned by AddLink(). See Write() for argument +// details. +func (f *Fpdf) WriteLinkID(h float64, displayStr string, linkID int) { + f.write(h, displayStr, linkID, "") +} + +// WriteAligned is an implementation of Write that makes it possible to align +// text. +// +// width indicates the width of the box the text will be drawn in. This is in +// the unit of measure specified in New(). If it is set to 0, the bounding box +//of the page will be taken (pageWidth - leftMargin - rightMargin). +// +// lineHeight indicates the line height in the unit of measure specified in +// New(). +// +// alignStr sees to horizontal alignment of the given textStr. The options are +// "L", "C" and "R" (Left, Center, Right). The default is "L". +func (f *Fpdf) WriteAligned(width, lineHeight float64, textStr, alignStr string) { + lMargin, _, rMargin, _ := f.GetMargins() + + pageWidth, _ := f.GetPageSize() + if width == 0 { + width = pageWidth - (lMargin + rMargin) + } + + 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) + lineWidth := f.GetStringWidth(lineStr) + + switch alignStr { + case "C": + f.SetLeftMargin(lMargin + ((width - lineWidth) / 2)) + f.Write(lineHeight, lineStr) + f.SetLeftMargin(lMargin) + case "R": + f.SetLeftMargin(lMargin + (width - lineWidth) - 2.01*f.cMargin) + f.Write(lineHeight, lineStr) + f.SetLeftMargin(lMargin) + default: + f.SetRightMargin(pageWidth - lMargin - width) + f.Write(lineHeight, lineStr) + f.SetRightMargin(rMargin) + } + } +} + +// Ln performs a line break. The current abscissa goes back to the left margin +// and the ordinate increases by the amount passed in parameter. A negative +// value of h indicates the height of the last printed cell. +// +// This method is demonstrated in the example for MultiCell. +func (f *Fpdf) Ln(h float64) { + f.x = f.lMargin + if h < 0 { + f.y += f.lasth + } else { + f.y += h + } +} + +// ImageTypeFromMime returns the image type used in various image-related +// functions (for example, Image()) that is associated with the specified MIME +// type. For example, "jpg" is returned if mimeStr is "image/jpeg". An error is +// set if the specified MIME type is not supported. +func (f *Fpdf) ImageTypeFromMime(mimeStr string) (tp string) { + switch mimeStr { + case "image/png": + tp = "png" + case "image/jpg": + tp = "jpg" + case "image/jpeg": + tp = "jpg" + case "image/gif": + tp = "gif" + default: + f.SetErrorf("unsupported image type: %s", mimeStr) + } + return +} + +func (f *Fpdf) imageOut(info *ImageInfoType, x, y, w, h float64, allowNegativeX, flow bool, link int, linkStr string) { + // Automatic width and height calculation if needed + if w == 0 && h == 0 { + // Put image at 96 dpi + w = -96 + h = -96 + } + if w == -1 { + // Set image width to whatever value for dpi we read + // from the image or that was set manually + w = -info.dpi + } + if h == -1 { + // Set image height to whatever value for dpi we read + // from the image or that was set manually + h = -info.dpi + } + if w < 0 { + w = -info.w * 72.0 / w / f.k + } + if h < 0 { + h = -info.h * 72.0 / h / f.k + } + if w == 0 { + w = h * info.w / info.h + } + if h == 0 { + h = w * info.h / info.w + } + // Flowing mode + if flow { + if f.y+h > f.pageBreakTrigger && !f.inHeader && !f.inFooter && f.acceptPageBreak() { + // Automatic page break + x2 := f.x + f.AddPageFormat(f.curOrientation, f.curPageSize) + if f.err != nil { + return + } + f.x = x2 + } + y = f.y + f.y += h + } + if !allowNegativeX { + if x < 0 { + x = f.x + } + } + // dbg("h %.2f", h) + // q 85.04 0 0 NaN 28.35 NaN cm /I2 Do Q + f.outf("q %.5f 0 0 %.5f %.5f %.5f cm /I%s Do Q", w*f.k, h*f.k, x*f.k, (f.h-(y+h))*f.k, info.i) + if link > 0 || len(linkStr) > 0 { + f.newLink(x, y, w, h, link, linkStr) + } +} + +// Image puts a JPEG, PNG or GIF image in the current page. +// +// Deprecated in favor of ImageOptions -- see that function for +// details on the behavior of arguments +func (f *Fpdf) Image(imageNameStr string, x, y, w, h float64, flow bool, tp string, link int, linkStr string) { + options := ImageOptions{ + ReadDpi: false, + ImageType: tp, + } + f.ImageOptions(imageNameStr, x, y, w, h, flow, options, link, linkStr) +} + +// ImageOptions puts a JPEG, PNG or GIF image in the current page. The size it +// will take on the page can be specified in different ways. If both w and h +// are 0, the image is rendered at 96 dpi. If either w or h is zero, it will be +// calculated from the other dimension so that the aspect ratio is maintained. +// If w and/or h are -1, the dpi for that dimension will be read from the +// ImageInfoType object. PNG files can contain dpi information, and if present, +// this information will be populated in the ImageInfoType object and used in +// Width, Height, and Extent calculations. Otherwise, the SetDpi function can +// be used to change the dpi from the default of 72. +// +// If w and h are any other negative value, their absolute values +// indicate their dpi extents. +// +// Supported JPEG formats are 24 bit, 32 bit and gray scale. Supported PNG +// formats are 24 bit, indexed color, and 8 bit indexed gray scale. If a GIF +// image is animated, only the first frame is rendered. Transparency is +// supported. It is possible to put a link on the image. +// +// imageNameStr may be the name of an image as registered with a call to either +// RegisterImageReader() or RegisterImage(). In the first case, the image is +// loaded using an io.Reader. This is generally useful when the image is +// obtained from some other means than as a disk-based file. In the second +// case, the image is loaded as a file. Alternatively, imageNameStr may +// directly specify a sufficiently qualified filename. +// +// However the image is loaded, if it is used more than once only one copy is +// embedded in the file. +// +// If x is negative, the current abscissa is used. +// +// If flow is true, the current y value is advanced after placing the image and +// a page break may be made if necessary. +// +// If link refers to an internal page anchor (that is, it is non-zero; see +// AddLink()), the image will be a clickable internal link. Otherwise, if +// linkStr specifies a URL, the image will be a clickable external link. +func (f *Fpdf) ImageOptions(imageNameStr string, x, y, w, h float64, flow bool, options ImageOptions, link int, linkStr string) { + if f.err != nil { + return + } + info := f.RegisterImageOptions(imageNameStr, options) + if f.err != nil { + return + } + f.imageOut(info, x, y, w, h, options.AllowNegativePosition, flow, link, linkStr) + return +} + +// RegisterImageReader registers an image, reading it from Reader r, adding it +// to the PDF file but not adding it to the page. +// +// This function is now deprecated in favor of RegisterImageOptionsReader +func (f *Fpdf) RegisterImageReader(imgName, tp string, r io.Reader) (info *ImageInfoType) { + options := ImageOptions{ + ReadDpi: false, + ImageType: tp, + } + return f.RegisterImageOptionsReader(imgName, options, r) +} + +// ImageOptions provides a place to hang any options we want to use while +// parsing an image. +// +// ImageType's possible values are (case insensitive): +// "JPG", "JPEG", "PNG" and "GIF". If empty, the type is inferred from +// the file extension. +// +// ReadDpi defines whether to attempt to automatically read the image +// dpi information from the image file. Normally, this should be set +// to true (understanding that not all images will have this info +// available). However, for backwards compatibility with previous +// versions of the API, it defaults to false. +// +// AllowNegativePosition can be set to true in order to prevent the default +// coercion of negative x values to the current x position. +type ImageOptions struct { + ImageType string + ReadDpi bool + AllowNegativePosition bool +} + +// RegisterImageOptionsReader registers an image, reading it from Reader r, adding it +// to the PDF file but not adding it to the page. Use Image() with the same +// name to add the image to the page. Note that tp should be specified in this +// case. +// +// See Image() for restrictions on the image and the options parameters. +func (f *Fpdf) RegisterImageOptionsReader(imgName string, options ImageOptions, r io.Reader) (info *ImageInfoType) { + // Thanks, Ivan Daniluk, for generalizing this code to use the Reader interface. + if f.err != nil { + return + } + info, ok := f.images[imgName] + if ok { + return + } + + // First use of this image, get info + if options.ImageType == "" { + f.err = fmt.Errorf("image type should be specified if reading from custom reader") + return + } + options.ImageType = strings.ToLower(options.ImageType) + if options.ImageType == "jpeg" { + options.ImageType = "jpg" + } + switch options.ImageType { + case "jpg": + info = f.parsejpg(r) + case "png": + info = f.parsepng(r, options.ReadDpi) + case "gif": + info = f.parsegif(r) + default: + f.err = fmt.Errorf("unsupported image type: %s", options.ImageType) + } + if f.err != nil { + return + } + + if info.i, f.err = generateImageID(info); f.err != nil { + return + } + f.images[imgName] = info + + return +} + +// RegisterImage registers an image, adding it to the PDF file but not adding +// it to the page. Use Image() with the same filename to add the image to the +// page. Note that Image() calls this function, so this function is only +// necessary if you need information about the image before placing it. +// +// This function is now deprecated in favor of RegisterImageOptions. +// See Image() for restrictions on the image and the "tp" parameters. +func (f *Fpdf) RegisterImage(fileStr, tp string) (info *ImageInfoType) { + options := ImageOptions{ + ReadDpi: false, + ImageType: tp, + } + return f.RegisterImageOptions(fileStr, options) +} + +// RegisterImageOptions registers an image, adding it to the PDF file but not +// adding it to the page. Use Image() with the same filename to add the image +// to the page. Note that Image() calls this function, so this function is only +// necessary if you need information about the image before placing it. See +// Image() for restrictions on the image and the "tp" parameters. +func (f *Fpdf) RegisterImageOptions(fileStr string, options ImageOptions) (info *ImageInfoType) { + info, ok := f.images[fileStr] + if ok { + return + } + + file, err := os.Open(fileStr) + if err != nil { + f.err = err + return + } + defer file.Close() + + // First use of this image, get info + if options.ImageType == "" { + pos := strings.LastIndex(fileStr, ".") + if pos < 0 { + f.err = fmt.Errorf("image file has no extension and no type was specified: %s", fileStr) + return + } + options.ImageType = fileStr[pos+1:] + } + + return f.RegisterImageOptionsReader(fileStr, options, file) +} + +// GetImageInfo returns information about the registered image specified by +// imageStr. If the image has not been registered, nil is returned. The +// internal error is not modified by this method. +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 { + return f.k +} + +// GetXY returns the abscissa and ordinate of the current position. +// +// Note: the value returned for the abscissa will be affected by the current +// cell margin. To account for this, you may need to either add the value +// returned by GetCellMargin() to it or call SetCellMargin(0) to remove the +// cell margin. +func (f *Fpdf) GetXY() (float64, float64) { + return f.x, f.y +} + +// GetX returns the abscissa of the current position. +// +// Note: the value returned will be affected by the current cell margin. To +// account for this, you may need to either add the value returned by +// GetCellMargin() to it or call SetCellMargin(0) to remove the cell margin. +func (f *Fpdf) GetX() float64 { + return f.x +} + +// SetX defines the abscissa of the current position. If the passed value is +// negative, it is relative to the right of the page. +func (f *Fpdf) SetX(x float64) { + if x >= 0 { + f.x = x + } else { + f.x = f.w + x + } +} + +// GetY returns the ordinate of the current position. +func (f *Fpdf) GetY() float64 { + return f.y +} + +// SetY moves the current abscissa back to the left margin and sets the +// ordinate. If the passed value is negative, it is relative to the bottom of +// the page. +func (f *Fpdf) SetY(y float64) { + // dbg("SetY x %.2f, lMargin %.2f", f.x, f.lMargin) + f.x = f.lMargin + if y >= 0 { + f.y = y + } else { + f.y = f.h + y + } +} + +// SetHomeXY is a convenience method that sets the current position to the left +// and top margins. +func (f *Fpdf) SetHomeXY() { + f.SetY(f.tMargin) + f.SetX(f.lMargin) +} + +// SetXY defines the abscissa and ordinate of the current position. If the +// passed values are negative, they are relative respectively to the right and +// bottom of the page. +func (f *Fpdf) SetXY(x, y float64) { + f.SetY(y) + f.SetX(x) +} + +// SetProtection applies certain constraints on the finished PDF document. +// +// actionFlag is a bitflag that controls various document operations. +// CnProtectPrint allows the document to be printed. CnProtectModify allows a +// document to be modified by a PDF editor. CnProtectCopy allows text and +// images to be copied into the system clipboard. CnProtectAnnotForms allows +// annotations and forms to be added by a PDF editor. These values can be +// combined by or-ing them together, for example, +// CnProtectCopy|CnProtectModify. This flag is advisory; not all PDF readers +// implement the constraints that this argument attempts to control. +// +// userPassStr specifies the password that will need to be provided to view the +// contents of the PDF. The permissions specified by actionFlag will apply. +// +// ownerPassStr specifies the password that will need to be provided to gain +// full access to the document regardless of the actionFlag value. An empty +// string for this argument will be replaced with a random value, effectively +// prohibiting full access to the document. +func (f *Fpdf) SetProtection(actionFlag byte, userPassStr, ownerPassStr string) { + if f.err != nil { + return + } + f.protect.setProtection(actionFlag, userPassStr, ownerPassStr) +} + +// OutputAndClose sends the PDF document to the writer specified by w. This +// method will close both f and w, even if an error is detected and no document +// is produced. +func (f *Fpdf) OutputAndClose(w io.WriteCloser) error { + f.Output(w) + w.Close() + return f.err +} + +// OutputFileAndClose creates or truncates the file specified by fileStr and +// writes the PDF document to it. This method will close f and the newly +// written file, even if an error is detected and no document is produced. +// +// Most examples demonstrate the use of this method. +func (f *Fpdf) OutputFileAndClose(fileStr string) error { + if f.err == nil { + pdfFile, err := os.Create(fileStr) + if err == nil { + f.Output(pdfFile) + pdfFile.Close() + } else { + f.err = err + } + } + return f.err +} + +// Output sends the PDF document to the writer specified by w. No output will +// take place if an error has occurred in the document generation process. w +// remains open after this function returns. After returning, f is in a closed +// state and its methods should not be called. +func (f *Fpdf) Output(w io.Writer) error { + if f.err != nil { + return f.err + } + // dbg("Output") + if f.state < 3 { + f.Close() + } + _, err := f.buffer.WriteTo(w) + if err != nil { + f.err = err + } + return f.err +} + +func (f *Fpdf) getpagesizestr(sizeStr string) (size SizeType) { + if f.err != nil { + return + } + sizeStr = strings.ToLower(sizeStr) + // dbg("Size [%s]", sizeStr) + var ok bool + size, ok = f.stdPageSizes[sizeStr] + if ok { + // dbg("found %s", sizeStr) + size.Wd /= f.k + size.Ht /= f.k + + } else { + f.err = fmt.Errorf("unknown page size %s", sizeStr) + } + return +} + +// GetPageSizeStr returns the SizeType for the given sizeStr (that is A4, A3, etc..) +func (f *Fpdf) GetPageSizeStr(sizeStr string) (size SizeType) { + return f.getpagesizestr(sizeStr) +} + +func (f *Fpdf) _getpagesize(size SizeType) SizeType { + if size.Wd > size.Ht { + size.Wd, size.Ht = size.Ht, size.Wd + } + return size +} + +func (f *Fpdf) beginpage(orientationStr string, size SizeType) { + if f.err != nil { + return + } + f.page++ + // add the default page boxes, if any exist, to the page + f.pageBoxes[f.page] = make(map[string]PageBox) + for box, pb := range f.defPageBoxes { + f.pageBoxes[f.page][box] = pb + } + f.pages = append(f.pages, bytes.NewBufferString("")) + f.pageLinks = append(f.pageLinks, make([]linkType, 0, 0)) + f.pageAttachments = append(f.pageAttachments, []annotationAttach{}) + f.state = 2 + f.x = f.lMargin + f.y = f.tMargin + f.fontFamily = "" + // Check page size and orientation + if orientationStr == "" { + orientationStr = f.defOrientation + } else { + orientationStr = strings.ToUpper(orientationStr[0:1]) + } + if orientationStr != f.curOrientation || size.Wd != f.curPageSize.Wd || size.Ht != f.curPageSize.Ht { + // New size or orientation + if orientationStr == "P" { + f.w = size.Wd + f.h = size.Ht + } else { + f.w = size.Ht + f.h = size.Wd + } + f.wPt = f.w * f.k + f.hPt = f.h * f.k + f.pageBreakTrigger = f.h - f.bMargin + f.curOrientation = orientationStr + f.curPageSize = size + } + if orientationStr != f.defOrientation || size.Wd != f.defPageSize.Wd || size.Ht != f.defPageSize.Ht { + f.pageSizes[f.page] = SizeType{f.wPt, f.hPt} + } + return +} + +func (f *Fpdf) endpage() { + f.EndLayer() + f.state = 1 +} + +// Load a font definition file from the given Reader +func (f *Fpdf) loadfont(r io.Reader) (def fontDefType) { + if f.err != nil { + return + } + // dbg("Loading font [%s]", fontStr) + var buf bytes.Buffer + _, err := buf.ReadFrom(r) + if err != nil { + f.err = err + return + } + err = json.Unmarshal(buf.Bytes(), &def) + if err != nil { + f.err = err + return + } + + if def.i, err = generateFontID(def); err != nil { + f.err = err + } + // dump(def) + return +} + +// Escape special characters in strings +func (f *Fpdf) escape(s string) string { + s = strings.Replace(s, "\\", "\\\\", -1) + s = strings.Replace(s, "(", "\\(", -1) + s = strings.Replace(s, ")", "\\)", -1) + s = strings.Replace(s, "\r", "\\r", -1) + return s +} + +// textstring formats a text string +func (f *Fpdf) textstring(s string) string { + if f.protect.encrypted { + b := []byte(s) + f.protect.rc4(uint32(f.n), &b) + s = string(b) + } + return "(" + f.escape(s) + ")" +} + +func blankCount(str string) (count int) { + l := len(str) + for j := 0; j < l; j++ { + if byte(' ') == str[j] { + count++ + } + } + 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) * 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 +} + +func be16(buf []byte) int { + return 256*int(buf[0]) + int(buf[1]) +} + +func (f *Fpdf) newImageInfo() *ImageInfoType { + // default dpi to 72 unless told otherwise + return &ImageInfoType{scale: f.k, dpi: 72} +} + +// parsejpg extracts info from io.Reader with JPEG data +// Thank you, Bruno Michel, for providing this code. +func (f *Fpdf) parsejpg(r io.Reader) (info *ImageInfoType) { + info = f.newImageInfo() + var ( + data bytes.Buffer + err error + ) + _, err = data.ReadFrom(r) + if err != nil { + f.err = err + return + } + info.data = data.Bytes() + + config, err := jpeg.DecodeConfig(bytes.NewReader(info.data)) + if err != nil { + f.err = err + return + } + info.w = float64(config.Width) + info.h = float64(config.Height) + info.f = "DCTDecode" + info.bpc = 8 + switch config.ColorModel { + case color.GrayModel: + info.cs = "DeviceGray" + case color.YCbCrModel: + info.cs = "DeviceRGB" + case color.CMYKModel: + info.cs = "DeviceCMYK" + default: + f.err = fmt.Errorf("image JPEG buffer has unsupported color space (%v)", config.ColorModel) + return + } + return +} + +// parsepng extracts info from a PNG data +func (f *Fpdf) parsepng(r io.Reader, readdpi bool) (info *ImageInfoType) { + buf, err := bufferFromReader(r) + if err != nil { + f.err = err + return + } + return f.parsepngstream(buf, readdpi) +} + +func (f *Fpdf) readBeInt32(r io.Reader) (val int32) { + err := binary.Read(r, binary.BigEndian, &val) + if err != nil && err != io.EOF { + f.err = err + } + return +} + +func (f *Fpdf) readByte(r io.Reader) (val byte) { + err := binary.Read(r, binary.BigEndian, &val) + if err != nil { + f.err = err + } + return +} + +// parsegif extracts info from a GIF data (via PNG conversion) +func (f *Fpdf) parsegif(r io.Reader) (info *ImageInfoType) { + data, err := bufferFromReader(r) + if err != nil { + f.err = err + return + } + var img image.Image + img, err = gif.Decode(data) + if err != nil { + f.err = err + return + } + pngBuf := new(bytes.Buffer) + err = png.Encode(pngBuf, img) + if err != nil { + f.err = err + return + } + return f.parsepngstream(pngBuf, false) +} + +// newobj begins a new object +func (f *Fpdf) newobj() { + // dbg("newobj") + f.n++ + for j := len(f.offsets); j <= f.n; j++ { + f.offsets = append(f.offsets, 0) + } + f.offsets[f.n] = f.buffer.Len() + f.outf("%d 0 obj", f.n) +} + +func (f *Fpdf) putstream(b []byte) { + // dbg("putstream") + if f.protect.encrypted { + f.protect.rc4(uint32(f.n), &b) + } + f.out("stream") + f.out(string(b)) + f.out("endstream") +} + +// out; Add a line to the document +func (f *Fpdf) out(s string) { + if f.state == 2 { + f.pages[f.page].WriteString(s) + f.pages[f.page].WriteString("\n") + } else { + f.buffer.WriteString(s) + f.buffer.WriteString("\n") + } +} + +// outbuf adds a buffered line to the document +func (f *Fpdf) outbuf(r io.Reader) { + if f.state == 2 { + f.pages[f.page].ReadFrom(r) + f.pages[f.page].WriteString("\n") + } else { + f.buffer.ReadFrom(r) + f.buffer.WriteString("\n") + } +} + +// RawWriteStr writes a string directly to the PDF generation buffer. This is a +// low-level function that is not required for normal PDF construction. An +// understanding of the PDF specification is needed to use this method +// correctly. +func (f *Fpdf) RawWriteStr(str string) { + f.out(str) +} + +// RawWriteBuf writes the contents of the specified buffer directly to the PDF +// generation buffer. This is a low-level function that is not required for +// normal PDF construction. An understanding of the PDF specification is needed +// to use this method correctly. +func (f *Fpdf) RawWriteBuf(r io.Reader) { + f.outbuf(r) +} + +// outf adds a formatted line to the document +func (f *Fpdf) outf(fmtStr string, args ...interface{}) { + f.out(sprintf(fmtStr, args...)) +} + +// SetDefaultCatalogSort sets the default value of the catalog sort flag that +// will be used when initializing a new Fpdf instance. See SetCatalogSort() for +// more details. +func SetDefaultCatalogSort(flag bool) { + gl.catalogSort = flag +} + +// SetCatalogSort sets a flag that will be used, if true, to consistently order +// the document's internal resource catalogs. This method is typically only +// used for test purposes to facilitate PDF comparison. +func (f *Fpdf) SetCatalogSort(flag bool) { + f.catalogSort = flag +} + +// SetDefaultCreationDate sets the default value of the document creation date +// that will be used when initializing a new Fpdf instance. See +// SetCreationDate() for more details. +func SetDefaultCreationDate(tm time.Time) { + gl.creationDate = tm +} + +// SetDefaultModificationDate sets the default value of the document modification date +// that will be used when initializing a new Fpdf instance. See +// SetCreationDate() for more details. +func SetDefaultModificationDate(tm time.Time) { + gl.modDate = tm +} + +// SetCreationDate fixes the document's internal CreationDate value. By +// default, the time when the document is generated is used for this value. +// This method is typically only used for testing purposes to facilitate PDF +// comparison. Specify a zero-value time to revert to the default behavior. +func (f *Fpdf) SetCreationDate(tm time.Time) { + f.creationDate = tm +} + +// SetModificationDate fixes the document's internal ModDate value. +// See `SetCreationDate` for more details. +func (f *Fpdf) SetModificationDate(tm time.Time) { + f.modDate = tm +} + +// SetJavascript adds Adobe JavaScript to the document. +func (f *Fpdf) SetJavascript(script string) { + f.javascript = &script +} + +// RegisterAlias adds an (alias, replacement) pair to the document so we can +// replace all occurrences of that alias after writing but before the document +// is closed. Functions ExampleFpdf_RegisterAlias() and +// ExampleFpdf_RegisterAlias_utf8() in fpdf_test.go demonstrate this method. +func (f *Fpdf) RegisterAlias(alias, replacement string) { + // Note: map[string]string assignments embed literal escape ("\00") sequences + // into utf16 key and value strings. Consequently, subsequent search/replace + // operations will fail unexpectedly if utf8toutf16() conversions take place + // here. Instead, conversions are deferred until the actual search/replace + // operation takes place when the PDF output is generated. + f.aliasMap[alias] = replacement +} + +func (f *Fpdf) replaceAliases() { + for mode := 0; mode < 2; mode++ { + for alias, replacement := range f.aliasMap { + if mode == 1 { + alias = utf8toutf16(alias, false) + replacement = utf8toutf16(replacement, false) + } + for n := 1; n <= f.page; n++ { + s := f.pages[n].String() + if strings.Contains(s, alias) { + s = strings.Replace(s, alias, replacement, -1) + f.pages[n].Truncate(0) + f.pages[n].WriteString(s) + } + } + } + } +} + +func (f *Fpdf) putpages() { + var wPt, hPt float64 + var pageSize SizeType + var ok bool + nb := f.page + if len(f.aliasNbPagesStr) > 0 { + // Replace number of pages + f.RegisterAlias(f.aliasNbPagesStr, sprintf("%d", nb)) + } + f.replaceAliases() + if f.defOrientation == "P" { + wPt = f.defPageSize.Wd * f.k + hPt = f.defPageSize.Ht * f.k + } else { + wPt = f.defPageSize.Ht * f.k + hPt = f.defPageSize.Wd * f.k + } + pagesObjectNumbers := make([]int, nb+1) // 1-based + for n := 1; n <= nb; n++ { + // Page + f.newobj() + pagesObjectNumbers[n] = f.n // save for /Kids + f.out("< 0 { + var annots fmtBuffer + annots.printf("/Annots [") + for _, pl := range f.pageLinks[n] { + annots.printf("<>>>", f.textstring(pl.linkStr)) + } else { + l := f.links[pl.link] + var sz SizeType + var h float64 + sz, ok = f.pageSizes[l.page] + if ok { + h = sz.Ht + } else { + h = hPt + } + // dbg("h [%.2f], l.y [%.2f] f.k [%.2f]\n", h, l.y, f.k) + annots.printf("/Dest [%d 0 R /XYZ 0 %.2f null]>>", 1+2*l.page, h-l.y*f.k) + } + } + f.putAttachmentAnnotationLinks(&annots, n) + annots.printf("]") + f.out(annots.String()) + } + if f.pdfVersion > "1.3" { + f.out("/Group <>") + } + f.outf("/Contents %d 0 R>>", f.n+1) + f.out("endobj") + // Page content + f.newobj() + if f.compress { + data := sliceCompress(f.pages[n].Bytes()) + f.outf("<>", len(data)) + f.putstream(data) + } else { + f.outf("<>", f.pages[n].Len()) + f.putstream(f.pages[n].Bytes()) + } + f.out("endobj") + } + // Pages root + f.offsets[1] = f.buffer.Len() + f.out("1 0 obj") + f.out("<>") + f.out("endobj") +} + +func (f *Fpdf) putfonts() { + if f.err != nil { + return + } + nf := f.n + for _, diff := range f.diffs { + // Encodings + f.newobj() + f.outf("<>", diff) + f.out("endobj") + } + { + var fileList []string + var info fontFileType + var file string + for file = range f.fontFiles { + fileList = append(fileList, file) + } + if f.catalogSort { + sort.SliceStable(fileList, func(i, j int) bool { return fileList[i] < fileList[j] }) + } + for _, file = range fileList { + info = f.fontFiles[file] + if info.fontType != "UTF8" { + f.newobj() + info.n = f.n + f.fontFiles[file] = info + + var font []byte + + if info.embedded { + font = info.content + } else { + var err error + font, err = f.loadFontFile(file) + if err != nil { + f.err = err + return + } + } + compressed := file[len(file)-2:] == ".z" + if !compressed && info.length2 > 0 { + buf := font[6:info.length1] + buf = append(buf, font[6+info.length1+6:info.length2]...) + font = buf + } + f.outf("< 0 { + f.outf("/Length2 %d /Length3 0", info.length2) + } + f.out(">>") + f.putstream(font) + f.out("endobj") + } + } + } + { + var keyList []string + var font fontDefType + var key string + for key = range f.fonts { + keyList = append(keyList, key) + } + if f.catalogSort { + sort.SliceStable(keyList, func(i, j int) bool { return keyList[i] < keyList[j] }) + } + for _, key = range keyList { + font = f.fonts[key] + // Font objects + font.N = f.n + 1 + f.fonts[key] = font + tp := font.Tp + name := font.Name + switch tp { + case "Core": + // Core font + f.newobj() + f.out("<>") + f.out("endobj") + case "Type1": + fallthrough + case "TrueType": + // Additional Type1 or TrueType/OpenType font + f.newobj() + f.out("< 0 { + f.outf("/Encoding %d 0 R", nf+font.DiffN) + } else { + f.out("/Encoding /WinAnsiEncoding") + } + f.out(">>") + f.out("endobj") + // Widths + f.newobj() + var s fmtBuffer + s.WriteString("[") + for j := 32; j < 256; j++ { + s.printf("%d ", font.Cw[j]) + } + s.WriteString("]") + f.out(s.String()) + f.out("endobj") + // Descriptor + f.newobj() + s.Truncate(0) + s.printf("<>", suffix, f.fontFiles[font.File].n) + f.out(s.String()) + f.out("endobj") + case "UTF8": + fontName := "utf8" + font.Name + usedRunes := font.usedRunes + delete(usedRunes, 0) + utf8FontStream := font.utf8File.GenerateCutFont(usedRunes) + utf8FontSize := len(utf8FontStream) + compressedFontStream := sliceCompress(utf8FontStream) + CodeSignDictionary := font.utf8File.CodeSymbolDictionary + delete(CodeSignDictionary, 0) + + f.newobj() + f.out(fmt.Sprintf("<>\n"+"endobj", fontName, f.n+1, f.n+2)) + + f.newobj() + f.out("<>") + f.out("endobj") + + f.newobj() + f.out("<>") + f.putstream([]byte(toUnicode)) + f.out("endobj") + + // CIDInfo + f.newobj() + f.out("<>") + f.out("endobj") + + // Font descriptor + f.newobj() + var s fmtBuffer + s.printf("<>") + f.out(s.String()) + f.out("endobj") + + // Embed CIDToGIDMap + cidToGidMap := make([]byte, 256*256*2) + + for cc, glyph := range CodeSignDictionary { + cidToGidMap[cc*2] = byte(glyph >> 8) + cidToGidMap[cc*2+1] = byte(glyph & 0xFF) + } + + cidToGidMap = sliceCompress(cidToGidMap) + f.newobj() + f.out("<>") + f.putstream(cidToGidMap) + f.out("endobj") + + //Font file + f.newobj() + f.out("<>") + f.putstream(compressedFontStream) + f.out("endobj") + default: + f.err = fmt.Errorf("unsupported font type: %s", tp) + return + } + } + } + return +} + +func (f *Fpdf) generateCIDFontMap(font *fontDefType, LastRune int) { + rangeID := 0 + cidArray := make(map[int]*untypedKeyMap) + cidArrayKeys := make([]int, 0) + prevCid := -2 + prevWidth := -1 + interval := false + startCid := 1 + cwLen := LastRune + 1 + + // for each character + for cid := startCid; cid < cwLen; cid++ { + if font.Cw[cid] == 0x00 { + continue + } + width := font.Cw[cid] + if width == 65535 { + width = 0 + } + if numb, OK := font.usedRunes[cid]; cid > 255 && (!OK || numb == 0) { + continue + } + + if cid == prevCid+1 { + if width == prevWidth { + + if width == cidArray[rangeID].get(0) { + cidArray[rangeID].put(nil, width) + } else { + cidArray[rangeID].pop() + rangeID = prevCid + r := untypedKeyMap{ + valueSet: make([]int, 0), + keySet: make([]interface{}, 0), + } + cidArray[rangeID] = &r + cidArrayKeys = append(cidArrayKeys, rangeID) + cidArray[rangeID].put(nil, prevWidth) + cidArray[rangeID].put(nil, width) + } + interval = true + cidArray[rangeID].put("interval", 1) + } else { + if interval { + // new range + rangeID = cid + r := untypedKeyMap{ + valueSet: make([]int, 0), + keySet: make([]interface{}, 0), + } + cidArray[rangeID] = &r + cidArrayKeys = append(cidArrayKeys, rangeID) + cidArray[rangeID].put(nil, width) + } else { + cidArray[rangeID].put(nil, width) + } + interval = false + } + } else { + rangeID = cid + r := untypedKeyMap{ + valueSet: make([]int, 0), + keySet: make([]interface{}, 0), + } + cidArray[rangeID] = &r + cidArrayKeys = append(cidArrayKeys, rangeID) + cidArray[rangeID].put(nil, width) + interval = false + } + prevCid = cid + prevWidth = width + + } + previousKey := -1 + nextKey := -1 + isInterval := false + for g := 0; g < len(cidArrayKeys); { + key := cidArrayKeys[g] + ws := *cidArray[key] + cws := len(ws.keySet) + if (key == nextKey) && (!isInterval) && (ws.getIndex("interval") < 0 || cws < 4) { + if cidArray[key].getIndex("interval") >= 0 { + cidArray[key].delete("interval") + } + cidArray[previousKey] = arrayMerge(cidArray[previousKey], cidArray[key]) + cidArrayKeys = remove(cidArrayKeys, key) + } else { + g++ + previousKey = key + } + nextKey = key + cws + // ui := ws.getIndex("interval") + // ui = ui + 1 + if ws.getIndex("interval") >= 0 { + if cws > 3 { + isInterval = true + } else { + isInterval = false + } + cidArray[key].delete("interval") + nextKey-- + } else { + isInterval = false + } + } + var w fmtBuffer + for _, k := range cidArrayKeys { + ws := cidArray[k] + if len(arrayCountValues(ws.valueSet)) == 1 { + w.printf(" %d %d %d", k, k+len(ws.valueSet)-1, ws.get(0)) + } else { + w.printf(" %d [ %s ]\n", k, implode(" ", ws.valueSet)) + } + } + f.out("/W [" + w.String() + " ]") +} + +func implode(sep string, arr []int) string { + var s fmtBuffer + for i := 0; i < len(arr)-1; i++ { + s.printf("%v", arr[i]) + s.printf(sep) + } + if len(arr) > 0 { + s.printf("%v", arr[len(arr)-1]) + } + 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 { + answer[v] = answer[v] + 1 + } + return answer +} + +func (f *Fpdf) loadFontFile(name string) ([]byte, error) { + if f.fontLoader != nil { + reader, err := f.fontLoader.Open(name) + if err == nil { + data, err := ioutil.ReadAll(reader) + if closer, ok := reader.(io.Closer); ok { + closer.Close() + } + return data, err + } + } + return ioutil.ReadFile(path.Join(f.fontpath, name)) +} + +func (f *Fpdf) putimages() { + var keyList []string + var key string + 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 { + 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 + } + } +} + +func (f *Fpdf) putimage(info *ImageInfoType) { + f.newobj() + info.n = f.n + f.out("< 0 { + f.outf("/Filter /%s", info.f) + } + if len(info.dp) > 0 { + f.outf("/DecodeParms <<%s>>", info.dp) + } + if len(info.trns) > 0 { + var trns fmtBuffer + for _, v := range info.trns { + trns.printf("%d %d ", v, v) + } + f.outf("/Mask [%s]", trns.String()) + } + if info.smask != nil { + f.outf("/SMask %d 0 R", f.n+1) + } + f.outf("/Length %d>>", len(info.data)) + f.putstream(info.data) + f.out("endobj") + // Soft mask + if len(info.smask) > 0 { + smask := &ImageInfoType{ + w: info.w, + h: info.h, + cs: "DeviceGray", + bpc: 8, + f: info.f, + dp: sprintf("/Predictor 15 /Colors 1 /BitsPerComponent 8 /Columns %d", int(info.w)), + data: info.smask, + scale: f.k, + } + f.putimage(smask) + } + // Palette + if info.cs == "Indexed" { + f.newobj() + if f.compress { + pal := sliceCompress(info.pal) + f.outf("<>", len(pal)) + f.putstream(pal) + } else { + f.outf("<>", len(info.pal)) + f.putstream(info.pal) + } + f.out("endobj") + } +} + +func (f *Fpdf) putxobjectdict() { + { + var image *ImageInfoType + var key string + var keyList []string + for key = range f.images { + keyList = append(keyList, key) + } + if f.catalogSort { + sort.SliceStable(keyList, func(i, j int) bool { return f.images[keyList[i]].i < f.images[keyList[j]].i }) + } + for _, key = range keyList { + image = f.images[key] + f.outf("/I%s %d 0 R", image.i, image.n) + } + } + { + var keyList []string + var key string + var tpl Template + keyList = templateKeyList(f.templates, f.catalogSort) + for _, key = range keyList { + tpl = f.templates[key] + // for _, tpl := range f.templates { + id := tpl.ID() + if objID, ok := f.templateObjects[id]; ok { + f.outf("/TPL%s %d 0 R", id, objID) + } + } + } + { + 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() { + f.out("/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]") + f.out("/Font <<") + { + var keyList []string + var font fontDefType + var key string + for key = range f.fonts { + keyList = append(keyList, key) + } + if f.catalogSort { + sort.SliceStable(keyList, func(i, j int) bool { return f.fonts[keyList[i]].i < f.fonts[keyList[j]].i }) + } + for _, key = range keyList { + font = f.fonts[key] + f.outf("/F%s %d 0 R", font.i, font.N) + } + } + f.out(">>") + f.out("/XObject <<") + f.putxobjectdict() + f.out(">>") + count := len(f.blendList) + if count > 1 { + f.out("/ExtGState <<") + for j := 1; j < count; j++ { + f.outf("/GS%d %d 0 R", j, f.blendList[j].objNum) + } + f.out(">>") + } + count = len(f.gradientList) + if count > 1 { + f.out("/Shading <<") + for j := 1; j < count; j++ { + f.outf("/Sh%d %d 0 R", j, f.gradientList[j].objNum) + } + f.out(">>") + } + // Layers + f.layerPutResourceDict() + f.spotColorPutResourceDict() +} + +func (f *Fpdf) putBlendModes() { + count := len(f.blendList) + for j := 1; j < count; j++ { + bl := f.blendList[j] + f.newobj() + f.blendList[j].objNum = f.n + f.outf("<>", + bl.fillStr, bl.strokeStr, bl.modeStr) + f.out("endobj") + } +} + +func (f *Fpdf) putGradients() { + count := len(f.gradientList) + for j := 1; j < count; j++ { + var f1 int + gr := f.gradientList[j] + if gr.tp == 2 || gr.tp == 3 { + f.newobj() + f.outf("<>", gr.clr1Str, gr.clr2Str) + f.out("endobj") + f1 = f.n + } + f.newobj() + f.outf("<>", + gr.x1, gr.y1, gr.x2, gr.y2, f1) + } else if gr.tp == 3 { + f.outf("/Coords [%.5f %.5f 0 %.5f %.5f %.5f] /Function %d 0 R /Extend [true true]>>", + gr.x1, gr.y1, gr.x2, gr.y2, gr.r, f1) + } + f.out("endobj") + f.gradientList[j].objNum = f.n + } +} + +func (f *Fpdf) putjavascript() { + if f.javascript == nil { + return + } + + f.newobj() + f.nJs = f.n + f.out("<<") + f.outf("/Names [(EmbeddedJS) %d 0 R]", f.n+1) + f.out(">>") + f.out("endobj") + f.newobj() + f.out("<<") + f.out("/S /JavaScript") + f.outf("/JS %s", f.textstring(*f.javascript)) + f.out(">>") + f.out("endobj") +} + +func (f *Fpdf) putresources() { + if f.err != nil { + return + } + f.layerPutLayers() + f.putBlendModes() + f.putGradients() + f.putSpotColors() + f.putfonts() + if f.err != nil { + return + } + f.putimages() + f.putTemplates() + f.putImportedTemplates() // gofpdi + // Resource dictionary + f.offsets[2] = f.buffer.Len() + f.out("2 0 obj") + f.out("<<") + f.putresourcedict() + f.out(">>") + f.out("endobj") + f.putjavascript() + if f.protect.encrypted { + f.newobj() + f.protect.objNum = f.n + f.out("<<") + f.out("/Filter /Standard") + f.out("/V 1") + f.out("/R 2") + f.outf("/O (%s)", f.escape(string(f.protect.oValue))) + f.outf("/U (%s)", f.escape(string(f.protect.uValue))) + f.outf("/P %d", f.protect.pValue) + f.out(">>") + f.out("endobj") + } + return +} + +// returns Now() if tm is zero +func timeOrNow(tm time.Time) time.Time { + if tm.IsZero() { + return time.Now() + } + return tm +} + +func (f *Fpdf) putinfo() { + 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)) + } + if len(f.subject) > 0 { + f.outf("/Subject %s", f.textstring(f.subject)) + } + if len(f.author) > 0 { + f.outf("/Author %s", f.textstring(f.author)) + } + if len(f.keywords) > 0 { + f.outf("/Keywords %s", f.textstring(f.keywords)) + } + if len(f.creator) > 0 { + f.outf("/Creator %s", f.textstring(f.creator)) + } + creation := timeOrNow(f.creationDate) + f.outf("/CreationDate %s", f.textstring("D:"+creation.Format("20060102150405"))) + mod := timeOrNow(f.modDate) + f.outf("/ModDate %s", f.textstring("D:"+mod.Format("20060102150405"))) +} + +func (f *Fpdf) putcatalog() { + f.out("/Type /Catalog") + f.out("/Pages 1 0 R") + switch f.zoomMode { + case "fullpage": + f.out("/OpenAction [3 0 R /Fit]") + case "fullwidth": + f.out("/OpenAction [3 0 R /FitH null]") + case "real": + f.out("/OpenAction [3 0 R /XYZ null null 1]") + } + // } else if !is_string($this->zoomMode)) + // $this->out('/OpenAction [3 0 R /XYZ null null '.sprintf('%.2f',$this->zoomMode/100).']'); + switch f.layoutMode { + case "single", "SinglePage": + f.out("/PageLayout /SinglePage") + case "continuous", "OneColumn": + f.out("/PageLayout /OneColumn") + case "two", "TwoColumnLeft": + f.out("/PageLayout /TwoColumnLeft") + case "TwoColumnRight": + f.out("/PageLayout /TwoColumnRight") + case "TwoPageLeft", "TwoPageRight": + if f.pdfVersion < "1.5" { + f.pdfVersion = "1.5" + } + f.out("/PageLayout /" + f.layoutMode) + } + // Bookmarks + if len(f.outlines) > 0 { + f.outf("/Outlines %d 0 R", f.outlineRoot) + f.out("/PageMode /UseOutlines") + } + // Layers + f.layerPutCatalog() + // Name dictionary : + // -> Javascript + // -> Embedded files + f.out("/Names <<") + // JavaScript + if f.javascript != nil { + f.outf("/JavaScript %d 0 R", f.nJs) + } + // Embedded files + f.outf("/EmbeddedFiles %s", f.getEmbeddedFiles()) + f.out(">>") +} + +func (f *Fpdf) putheader() { + if len(f.blendMap) > 0 && f.pdfVersion < "1.4" { + f.pdfVersion = "1.4" + } + f.outf("%%PDF-%s", f.pdfVersion) +} + +func (f *Fpdf) puttrailer() { + f.outf("/Size %d", f.n+1) + f.outf("/Root %d 0 R", f.n) + f.outf("/Info %d 0 R", f.n-1) + if f.protect.encrypted { + f.outf("/Encrypt %d 0 R", f.protect.objNum) + f.out("/ID [()()]") + } +} + +func (f *Fpdf) putxmp() { + if len(f.xmp) == 0 { + return + } + f.newobj() + f.outf("<< /Type /Metadata /Subtype /XML /Length %d >>", len(f.xmp)) + f.putstream(f.xmp) + f.out("endobj") +} + +func (f *Fpdf) putbookmarks() { + nb := len(f.outlines) + if nb > 0 { + lru := make(map[int]int) + level := 0 + for i, o := range f.outlines { + if o.level > 0 { + parent := lru[o.level-1] + f.outlines[i].parent = parent + f.outlines[parent].last = i + if o.level > level { + f.outlines[parent].first = i + } + } else { + f.outlines[i].parent = nb + } + if o.level <= level && i > 0 { + prev := lru[o.level] + f.outlines[prev].next = i + f.outlines[i].prev = prev + } + lru[o.level] = i + level = o.level + } + n := f.n + 1 + for _, o := range f.outlines { + f.newobj() + f.outf("<>") + f.out("endobj") + } + f.newobj() + f.outlineRoot = f.n + f.outf("<>", n+lru[0]) + f.out("endobj") + } +} + +func (f *Fpdf) enddoc() { + if f.err != nil { + return + } + f.layerEndDoc() + f.putheader() + // Embedded files + f.putAttachments() + f.putAnnotationsAttachments() + f.putpages() + f.putresources() + if f.err != nil { + return + } + // Bookmarks + f.putbookmarks() + // Metadata + f.putxmp() + // Info + f.newobj() + f.out("<<") + f.putinfo() + f.out(">>") + f.out("endobj") + // Catalog + f.newobj() + f.out("<<") + f.putcatalog() + f.out(">>") + f.out("endobj") + // Cross-ref + o := f.buffer.Len() + f.out("xref") + f.outf("0 %d", f.n+1) + f.out("0000000000 65535 f ") + for j := 1; j <= f.n; j++ { + f.outf("%010d 00000 n ", f.offsets[j]) + } + // Trailer + f.out("trailer") + f.out("<<") + f.puttrailer() + f.out(">>") + f.out("startxref") + f.outf("%d", o) + f.out("%%EOF") + f.state = 3 + return +} + +// Path Drawing + +// MoveTo moves the stylus to (x, y) without drawing the path from the +// previous point. Paths must start with a MoveTo to set the original +// stylus location or the result is undefined. +// +// Create a "path" by moving a virtual stylus around the page (with +// MoveTo, LineTo, CurveTo, CurveBezierCubicTo, ArcTo & ClosePath) +// then draw it or fill it in (with DrawPath). The main advantage of +// using the path drawing routines rather than multiple Fpdf.Line is +// that PDF creates nice line joins at the angles, rather than just +// overlaying the lines. +func (f *Fpdf) MoveTo(x, y float64) { + f.point(x, y) + f.x, f.y = x, y +} + +// LineTo creates a line from the current stylus location to (x, y), which +// becomes the new stylus location. Note that this only creates the line in +// the path; it does not actually draw the line on the page. +// +// The MoveTo() example demonstrates this method. +func (f *Fpdf) LineTo(x, y float64) { + f.outf("%.2f %.2f l", x*f.k, (f.h-y)*f.k) + f.x, f.y = x, y +} + +// CurveTo creates a single-segment quadratic Bézier curve. The curve starts at +// the current stylus location and ends at the point (x, y). The control point +// (cx, cy) specifies the curvature. At the start point, the curve is tangent +// to the straight line between the current stylus location and the control +// point. At the end point, the curve is tangent to the straight line between +// the end point and the control point. +// +// The MoveTo() example demonstrates this method. +func (f *Fpdf) CurveTo(cx, cy, x, y float64) { + f.outf("%.5f %.5f %.5f %.5f v", cx*f.k, (f.h-cy)*f.k, x*f.k, (f.h-y)*f.k) + f.x, f.y = x, y +} + +// CurveBezierCubicTo creates a single-segment cubic Bézier curve. The curve +// starts at the current stylus location and ends at the point (x, y). The +// control points (cx0, cy0) and (cx1, cy1) specify the curvature. At the +// current stylus, the curve is tangent to the straight line between the +// current stylus location and the control point (cx0, cy0). At the end point, +// the curve is tangent to the straight line between the end point and the +// control point (cx1, cy1). +// +// The MoveTo() example demonstrates this method. +func (f *Fpdf) CurveBezierCubicTo(cx0, cy0, cx1, cy1, x, y float64) { + f.curve(cx0, cy0, cx1, cy1, x, y) + f.x, f.y = x, y +} + +// ClosePath creates a line from the current location to the last MoveTo point +// (if not the same) and mark the path as closed so the first and last lines +// join nicely. +// +// The MoveTo() example demonstrates this method. +func (f *Fpdf) ClosePath() { + f.outf("h") +} + +// DrawPath actually draws the path on the page. +// +// 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". +// Path-painting operators as defined in the PDF specification are also +// allowed: "S" (Stroke the path), "s" (Close and stroke the path), +// "f" (fill the path, using the nonzero winding number), "f*" +// (Fill the path, using the even-odd rule), "B" (Fill and then stroke +// the path, using the nonzero winding number rule), "B*" (Fill and +// then stroke the path, using the even-odd rule), "b" (Close, fill, +// and then stroke the path, using the nonzero winding number rule) and +// "b*" (Close, fill, and then stroke the path, using the even-odd +// rule). +// Drawing uses the current draw color, line width, and cap style +// centered on the +// path. Filling uses the current fill color. +// +// The MoveTo() example demonstrates this method. +func (f *Fpdf) DrawPath(styleStr string) { + f.outf(fillDrawOp(styleStr)) +} + +// ArcTo draws an elliptical arc centered at point (x, y). rx and ry specify its +// horizontal and vertical radii. If the start of the arc is not at +// the current position, a connecting line will be drawn. +// +// degRotate specifies the angle that the arc will be rotated. degStart and +// degEnd specify the starting and ending angle of the arc. All angles are +// specified in degrees and measured counter-clockwise from the 3 o'clock +// position. +// +// 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, line width, and cap style centered on the arc's +// path. Filling uses the current fill color. +// +// The MoveTo() example demonstrates this method. +func (f *Fpdf) ArcTo(x, y, rx, ry, degRotate, degStart, degEnd float64) { + f.arc(x, y, rx, ry, degRotate, degStart, degEnd, "", true) +} + +func (f *Fpdf) arc(x, y, rx, ry, degRotate, degStart, degEnd float64, + styleStr string, path bool) { + x *= f.k + y = (f.h - y) * f.k + rx *= f.k + ry *= f.k + segments := int(degEnd-degStart) / 60 + if segments < 2 { + segments = 2 + } + angleStart := degStart * math.Pi / 180 + angleEnd := degEnd * math.Pi / 180 + angleTotal := angleEnd - angleStart + dt := angleTotal / float64(segments) + dtm := dt / 3 + if degRotate != 0 { + a := -degRotate * math.Pi / 180 + f.outf("q %.5f %.5f %.5f %.5f %.5f %.5f cm", + math.Cos(a), -1*math.Sin(a), + math.Sin(a), math.Cos(a), x, y) + x = 0 + y = 0 + } + t := angleStart + a0 := x + rx*math.Cos(t) + b0 := y + ry*math.Sin(t) + c0 := -rx * math.Sin(t) + d0 := ry * math.Cos(t) + sx := a0 / f.k // start point of arc + sy := f.h - (b0 / f.k) + if path { + if f.x != sx || f.y != sy { + // Draw connecting line to start point + f.LineTo(sx, sy) + } + } else { + f.point(sx, sy) + } + for j := 1; j <= segments; j++ { + // Draw this bit of the total curve + t = (float64(j) * dt) + angleStart + a1 := x + rx*math.Cos(t) + b1 := y + ry*math.Sin(t) + c1 := -rx * math.Sin(t) + d1 := ry * math.Cos(t) + f.curve((a0+(c0*dtm))/f.k, + f.h-((b0+(d0*dtm))/f.k), + (a1-(c1*dtm))/f.k, + f.h-((b1-(d1*dtm))/f.k), + a1/f.k, + f.h-(b1/f.k)) + a0 = a1 + b0 = b1 + c0 = c1 + d0 = d1 + if path { + f.x = a1 / f.k + f.y = f.h - (b1 / f.k) + } + } + if !path { + f.out(fillDrawOp(styleStr)) + } + if degRotate != 0 { + f.out("Q") + } +} diff --git a/fpdf_test.go b/fpdf_test.go new file mode 100644 index 0000000..7ce59e9 --- /dev/null +++ b/fpdf_test.go @@ -0,0 +1,2924 @@ +/* + * Copyright (c) 2013-2015 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf_test + +import ( + "bufio" + "bytes" + "fmt" + "io" + "io/ioutil" + "math" + "math/rand" + "net/http" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + "time" + + "github.com/jung-kurt/gofpdf" + "github.com/jung-kurt/gofpdf/internal/example" + "github.com/jung-kurt/gofpdf/internal/files" +) + +func init() { + cleanup() +} + +func cleanup() { + filepath.Walk(example.PdfDir(), + func(path string, info os.FileInfo, err error) (reterr error) { + if info.Mode().IsRegular() { + dir, _ := filepath.Split(path) + if "reference" != filepath.Base(dir) { + if len(path) > 3 { + if path[len(path)-4:] == ".pdf" { + os.Remove(path) + } + } + } + } + return + }) +} + +func TestFpdfImplementPdf(t *testing.T) { + // this will not compile if Fpdf and Tpl + // do not implement Pdf + var _ gofpdf.Pdf = (*gofpdf.Fpdf)(nil) + var _ gofpdf.Pdf = (*gofpdf.Tpl)(nil) +} + +// TestPagedTemplate ensures new paged templates work +func TestPagedTemplate(t *testing.T) { + pdf := gofpdf.New("P", "mm", "A4", "") + tpl := pdf.CreateTemplate(func(t *gofpdf.Tpl) { + // this will be the second page, as a page is already + // created by default + t.AddPage() + t.AddPage() + t.AddPage() + }) + + if tpl.NumPages() != 4 { + t.Fatalf("The template does not have the correct number of pages %d", tpl.NumPages()) + } + + tplPages := tpl.FromPages() + for x := 0; x < len(tplPages); x++ { + pdf.AddPage() + pdf.UseTemplate(tplPages[x]) + } + + // get the last template + tpl2, err := tpl.FromPage(tpl.NumPages()) + if err != nil { + t.Fatal(err) + } + + // the objects should be the exact same, as the + // template will represent the last page by default + // therefore no new id should be set, and the object + // should be the same object + if fmt.Sprintf("%p", tpl2) != fmt.Sprintf("%p", tpl) { + t.Fatal("Template no longer respecting initial template object") + } +} + +// TestIssue0116 addresses issue 116 in which library silently fails after +// calling CellFormat when no font has been set. +func TestIssue0116(t *testing.T) { + var pdf *gofpdf.Fpdf + + pdf = gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + pdf.SetFont("Arial", "B", 16) + pdf.Cell(40, 10, "OK") + if pdf.Error() != nil { + t.Fatalf("not expecting error when rendering text") + } + + pdf = gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + pdf.Cell(40, 10, "Not OK") // Font not set + if pdf.Error() == nil { + t.Fatalf("expecting error when rendering text without having set font") + } +} + +// TestIssue0193 addresses issue 193 in which the error io.EOF is incorrectly +// assigned to the FPDF instance error. +func TestIssue0193(t *testing.T) { + var png []byte + var pdf *gofpdf.Fpdf + var err error + var rdr *bytes.Reader + + png, err = ioutil.ReadFile(example.ImageFile("sweden.png")) + if err == nil { + rdr = bytes.NewReader(png) + pdf = gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + _ = pdf.RegisterImageOptionsReader("sweden", gofpdf.ImageOptions{ImageType: "png", ReadDpi: true}, rdr) + err = pdf.Error() + } + if err != nil { + t.Fatalf("issue 193 error: %s", err) + } + +} + +// TestIssue0209SplitLinesEqualMultiCell addresses issue 209 +// make SplitLines and MultiCell split at the same place +func TestIssue0209SplitLinesEqualMultiCell(t *testing.T) { + var pdf *gofpdf.Fpdf + + pdf = gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + pdf.SetFont("Arial", "", 8) + // this sentence should not be splited + str := "Guochin Amandine" + lines := pdf.SplitLines([]byte(str), 26) + _, FontSize := pdf.GetFontSize() + y_start := pdf.GetY() + pdf.MultiCell(26, FontSize, str, "", "L", false) + y_end := pdf.GetY() + + if len(lines) != 1 { + t.Fatalf("expect SplitLines split in one line") + } + if int(y_end-y_start) != int(FontSize) { + t.Fatalf("expect MultiCell split in one line %.2f != %.2f", y_end-y_start, FontSize) + } + + // this sentence should be splited in two lines + str = "Guiochini Amandine" + lines = pdf.SplitLines([]byte(str), 26) + y_start = pdf.GetY() + pdf.MultiCell(26, FontSize, str, "", "L", false) + y_end = pdf.GetY() + + if len(lines) != 2 { + t.Fatalf("expect SplitLines split in two lines") + } + if int(y_end-y_start) != int(FontSize*2) { + t.Fatalf("expect MultiCell split in two lines %.2f != %.2f", y_end-y_start, FontSize*2) + } +} + +// TestFooterFuncLpi tests to make sure the footer is not call twice and SetFooterFuncLpi can work +// without SetFooterFunc. +func TestFooterFuncLpi(t *testing.T) { + pdf := gofpdf.New("P", "mm", "A4", "") + var ( + oldFooterFnc = "oldFooterFnc" + bothPages = "bothPages" + firstPageOnly = "firstPageOnly" + lastPageOnly = "lastPageOnly" + ) + + // This set just for testing, only set SetFooterFuncLpi. + pdf.SetFooterFunc(func() { + pdf.SetY(-15) + pdf.SetFont("Arial", "I", 8) + pdf.CellFormat(0, 10, oldFooterFnc, + "", 0, "C", false, 0, "") + }) + pdf.SetFooterFuncLpi(func(lastPage bool) { + pdf.SetY(-15) + pdf.SetFont("Arial", "I", 8) + pdf.CellFormat(0, 10, bothPages, "", 0, "L", false, 0, "") + if !lastPage { + pdf.CellFormat(0, 10, firstPageOnly, "", 0, "C", false, 0, "") + } else { + pdf.CellFormat(0, 10, lastPageOnly, "", 0, "C", false, 0, "") + } + }) + pdf.AddPage() + pdf.SetFont("Arial", "B", 16) + for j := 1; j <= 40; j++ { + pdf.CellFormat(0, 10, fmt.Sprintf("Printing line number %d", j), + "", 1, "", false, 0, "") + } + if pdf.Error() != nil { + t.Fatalf("not expecting error when rendering text") + } + w := &bytes.Buffer{} + if err := pdf.Output(w); err != nil { + t.Errorf("unexpected err: %s", err) + } + b := w.Bytes() + if bytes.Contains(b, []byte(oldFooterFnc)) { + t.Errorf("not expecting %s render on pdf when FooterFncLpi is set", oldFooterFnc) + } + got := bytes.Count(b, []byte("bothPages")) + if got != 2 { + t.Errorf("footer %s should render on two page got:%d", bothPages, got) + } + got = bytes.Count(b, []byte(firstPageOnly)) + if got != 1 { + t.Errorf("footer %s should render only on first page got: %d", firstPageOnly, got) + } + got = bytes.Count(b, []byte(lastPageOnly)) + if got != 1 { + t.Errorf("footer %s should render only on first page got: %d", lastPageOnly, got) + } + f := bytes.Index(b, []byte(firstPageOnly)) + l := bytes.Index(b, []byte(lastPageOnly)) + if f > l { + t.Errorf("index %d (%s) should less than index %d (%s)", f, firstPageOnly, l, lastPageOnly) + } +} + +type fontResourceType struct { +} + +func (f fontResourceType) Open(name string) (rdr io.Reader, err error) { + var buf []byte + buf, err = ioutil.ReadFile(example.FontFile(name)) + if err == nil { + rdr = bytes.NewReader(buf) + fmt.Printf("Generalized font loader reading %s\n", name) + } + return +} + +// strDelimit converts 'ABCDEFG' to, for example, 'A,BCD,EFG' +func strDelimit(str string, sepstr string, sepcount int) string { + pos := len(str) - sepcount + for pos > 0 { + str = str[:pos] + sepstr + str[pos:] + pos = pos - sepcount + } + return str +} + +func loremList() []string { + return []string{ + "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod " + + "tempor incididunt ut labore et dolore magna aliqua.", + "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " + + "aliquip ex ea commodo consequat.", + "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum " + + "dolore eu fugiat nulla pariatur.", + "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui " + + "officia deserunt mollit anim id est laborum.", + } +} + +func lorem() string { + return strings.Join(loremList(), " ") +} + +// Example demonstrates the generation of a simple PDF document. Note that +// since only core fonts are used (in this case Arial, a synonym for +// Helvetica), an empty string can be specified for the font directory in the +// call to New(). Note also that the example.Filename() and example.Summary() +// functions belong to a separate, internal package and are not part of the +// gofpdf library. If an error occurs at some point during the construction of +// the document, subsequent method calls exit immediately and the error is +// finally retrieved with the output call where it can be handled by the +// application. +func Example() { + pdf := gofpdf.New(gofpdf.OrientationPortrait, "mm", "A4", "") + pdf.AddPage() + pdf.SetFont("Arial", "B", 16) + pdf.Cell(40, 10, "Hello World!") + fileStr := example.Filename("basic") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/basic.pdf +} + +// ExampleFpdf_AddPage demonsrates the generation of headers, footers and page breaks. +func ExampleFpdf_AddPage() { + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.SetTopMargin(30) + pdf.SetHeaderFuncMode(func() { + pdf.Image(example.ImageFile("logo.png"), 10, 6, 30, 0, false, "", 0, "") + pdf.SetY(5) + pdf.SetFont("Arial", "B", 15) + pdf.Cell(80, 0, "") + pdf.CellFormat(30, 10, "Title", "1", 0, "C", false, 0, "") + pdf.Ln(20) + }, true) + pdf.SetFooterFunc(func() { + pdf.SetY(-15) + pdf.SetFont("Arial", "I", 8) + pdf.CellFormat(0, 10, fmt.Sprintf("Page %d/{nb}", pdf.PageNo()), + "", 0, "C", false, 0, "") + }) + pdf.AliasNbPages("") + pdf.AddPage() + pdf.SetFont("Times", "", 12) + for j := 1; j <= 40; j++ { + pdf.CellFormat(0, 10, fmt.Sprintf("Printing line number %d", j), + "", 1, "", false, 0, "") + } + fileStr := example.Filename("Fpdf_AddPage") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_AddPage.pdf +} + +// ExampleFpdf_MultiCell demonstrates word-wrapping, line justification and +// page-breaking. +func ExampleFpdf_MultiCell() { + pdf := gofpdf.New("P", "mm", "A4", "") + titleStr := "20000 Leagues Under the Seas" + pdf.SetTitle(titleStr, false) + pdf.SetAuthor("Jules Verne", false) + pdf.SetHeaderFunc(func() { + // Arial bold 15 + pdf.SetFont("Arial", "B", 15) + // Calculate width of title and position + wd := pdf.GetStringWidth(titleStr) + 6 + pdf.SetX((210 - wd) / 2) + // Colors of frame, background and text + pdf.SetDrawColor(0, 80, 180) + pdf.SetFillColor(230, 230, 0) + pdf.SetTextColor(220, 50, 50) + // Thickness of frame (1 mm) + pdf.SetLineWidth(1) + // Title + pdf.CellFormat(wd, 9, titleStr, "1", 1, "C", true, 0, "") + // Line break + pdf.Ln(10) + }) + pdf.SetFooterFunc(func() { + // Position at 1.5 cm from bottom + pdf.SetY(-15) + // Arial italic 8 + pdf.SetFont("Arial", "I", 8) + // Text color in gray + pdf.SetTextColor(128, 128, 128) + // Page number + pdf.CellFormat(0, 10, fmt.Sprintf("Page %d", pdf.PageNo()), + "", 0, "C", false, 0, "") + }) + chapterTitle := func(chapNum int, titleStr string) { + // // Arial 12 + pdf.SetFont("Arial", "", 12) + // Background color + pdf.SetFillColor(200, 220, 255) + // Title + pdf.CellFormat(0, 6, fmt.Sprintf("Chapter %d : %s", chapNum, titleStr), + "", 1, "L", true, 0, "") + // Line break + pdf.Ln(4) + } + chapterBody := func(fileStr string) { + // Read text file + txtStr, err := ioutil.ReadFile(fileStr) + if err != nil { + pdf.SetError(err) + } + // Times 12 + pdf.SetFont("Times", "", 12) + // Output justified text + pdf.MultiCell(0, 5, string(txtStr), "", "", false) + // Line break + pdf.Ln(-1) + // Mention in italics + pdf.SetFont("", "I", 0) + pdf.Cell(0, 5, "(end of excerpt)") + } + printChapter := func(chapNum int, titleStr, fileStr string) { + pdf.AddPage() + chapterTitle(chapNum, titleStr) + chapterBody(fileStr) + } + printChapter(1, "A RUNAWAY REEF", example.TextFile("20k_c1.txt")) + printChapter(2, "THE PROS AND CONS", example.TextFile("20k_c2.txt")) + fileStr := example.Filename("Fpdf_MultiCell") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_MultiCell.pdf +} + +// ExampleFpdf_SetLeftMargin demonstrates the generation of a PDF document that has multiple +// columns. This is accomplished with the SetLeftMargin() and Cell() methods. +func ExampleFpdf_SetLeftMargin() { + var y0 float64 + var crrntCol int + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.SetDisplayMode("fullpage", "TwoColumnLeft") + titleStr := "20000 Leagues Under the Seas" + pdf.SetTitle(titleStr, false) + pdf.SetAuthor("Jules Verne", false) + setCol := func(col int) { + // Set position at a given column + crrntCol = col + x := 10.0 + float64(col)*65.0 + pdf.SetLeftMargin(x) + pdf.SetX(x) + } + chapterTitle := func(chapNum int, titleStr string) { + // Arial 12 + pdf.SetFont("Arial", "", 12) + // Background color + pdf.SetFillColor(200, 220, 255) + // Title + pdf.CellFormat(0, 6, fmt.Sprintf("Chapter %d : %s", chapNum, titleStr), + "", 1, "L", true, 0, "") + // Line break + pdf.Ln(4) + y0 = pdf.GetY() + } + chapterBody := func(fileStr string) { + // Read text file + txtStr, err := ioutil.ReadFile(fileStr) + if err != nil { + pdf.SetError(err) + } + // Font + pdf.SetFont("Times", "", 12) + // Output text in a 6 cm width column + pdf.MultiCell(60, 5, string(txtStr), "", "", false) + pdf.Ln(-1) + // Mention + pdf.SetFont("", "I", 0) + pdf.Cell(0, 5, "(end of excerpt)") + // Go back to first column + setCol(0) + } + printChapter := func(num int, titleStr, fileStr string) { + // Add chapter + pdf.AddPage() + chapterTitle(num, titleStr) + chapterBody(fileStr) + } + pdf.SetAcceptPageBreakFunc(func() bool { + // Method accepting or not automatic page break + if crrntCol < 2 { + // Go to next column + setCol(crrntCol + 1) + // Set ordinate to top + pdf.SetY(y0) + // Keep on page + return false + } + // Go back to first column + setCol(0) + // Page break + return true + }) + pdf.SetHeaderFunc(func() { + // Arial bold 15 + pdf.SetFont("Arial", "B", 15) + // Calculate width of title and position + wd := pdf.GetStringWidth(titleStr) + 6 + pdf.SetX((210 - wd) / 2) + // Colors of frame, background and text + pdf.SetDrawColor(0, 80, 180) + pdf.SetFillColor(230, 230, 0) + pdf.SetTextColor(220, 50, 50) + // Thickness of frame (1 mm) + pdf.SetLineWidth(1) + // Title + pdf.CellFormat(wd, 9, titleStr, "1", 1, "C", true, 0, "") + // Line break + pdf.Ln(10) + // Save ordinate + y0 = pdf.GetY() + }) + pdf.SetFooterFunc(func() { + // Position at 1.5 cm from bottom + pdf.SetY(-15) + // Arial italic 8 + pdf.SetFont("Arial", "I", 8) + // Text color in gray + pdf.SetTextColor(128, 128, 128) + // Page number + pdf.CellFormat(0, 10, fmt.Sprintf("Page %d", pdf.PageNo()), + "", 0, "C", false, 0, "") + }) + printChapter(1, "A RUNAWAY REEF", example.TextFile("20k_c1.txt")) + printChapter(2, "THE PROS AND CONS", example.TextFile("20k_c2.txt")) + fileStr := example.Filename("Fpdf_SetLeftMargin_multicolumn") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_SetLeftMargin_multicolumn.pdf +} + +// ExampleFpdf_SplitLines_tables demonstrates word-wrapped table cells +func ExampleFpdf_SplitLines_tables() { + const ( + colCount = 3 + colWd = 60.0 + marginH = 15.0 + lineHt = 5.5 + cellGap = 2.0 + ) + // var colStrList [colCount]string + type cellType struct { + str string + list [][]byte + ht float64 + } + var ( + cellList [colCount]cellType + cell cellType + ) + + pdf := gofpdf.New("P", "mm", "A4", "") // 210 x 297 + header := [colCount]string{"Column A", "Column B", "Column C"} + alignList := [colCount]string{"L", "C", "R"} + strList := loremList() + pdf.SetMargins(marginH, 15, marginH) + pdf.SetFont("Arial", "", 14) + pdf.AddPage() + + // Headers + pdf.SetTextColor(224, 224, 224) + pdf.SetFillColor(64, 64, 64) + for colJ := 0; colJ < colCount; colJ++ { + pdf.CellFormat(colWd, 10, header[colJ], "1", 0, "CM", true, 0, "") + } + pdf.Ln(-1) + pdf.SetTextColor(24, 24, 24) + pdf.SetFillColor(255, 255, 255) + + // Rows + y := pdf.GetY() + count := 0 + for rowJ := 0; rowJ < 2; rowJ++ { + maxHt := lineHt + // Cell height calculation loop + for colJ := 0; colJ < colCount; colJ++ { + count++ + if count > len(strList) { + count = 1 + } + cell.str = strings.Join(strList[0:count], " ") + cell.list = pdf.SplitLines([]byte(cell.str), colWd-cellGap-cellGap) + cell.ht = float64(len(cell.list)) * lineHt + if cell.ht > maxHt { + maxHt = cell.ht + } + cellList[colJ] = cell + } + // Cell render loop + x := marginH + for colJ := 0; colJ < colCount; colJ++ { + pdf.Rect(x, y, colWd, maxHt+cellGap+cellGap, "D") + cell = cellList[colJ] + cellY := y + cellGap + (maxHt-cell.ht)/2 + for splitJ := 0; splitJ < len(cell.list); splitJ++ { + pdf.SetXY(x+cellGap, cellY) + pdf.CellFormat(colWd-cellGap-cellGap, lineHt, string(cell.list[splitJ]), "", 0, + alignList[colJ], false, 0, "") + cellY += lineHt + } + x += colWd + } + y += maxHt + cellGap + cellGap + } + + fileStr := example.Filename("Fpdf_SplitLines_tables") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_SplitLines_tables.pdf +} + +// ExampleFpdf_CellFormat_tables demonstrates various table styles. +func ExampleFpdf_CellFormat_tables() { + pdf := gofpdf.New("P", "mm", "A4", "") + type countryType struct { + nameStr, capitalStr, areaStr, popStr string + } + countryList := make([]countryType, 0, 8) + header := []string{"Country", "Capital", "Area (sq km)", "Pop. (thousands)"} + loadData := func(fileStr string) { + fl, err := os.Open(fileStr) + if err == nil { + scanner := bufio.NewScanner(fl) + var c countryType + for scanner.Scan() { + // Austria;Vienna;83859;8075 + lineStr := scanner.Text() + list := strings.Split(lineStr, ";") + if len(list) == 4 { + c.nameStr = list[0] + c.capitalStr = list[1] + c.areaStr = list[2] + c.popStr = list[3] + countryList = append(countryList, c) + } else { + err = fmt.Errorf("error tokenizing %s", lineStr) + } + } + fl.Close() + if len(countryList) == 0 { + err = fmt.Errorf("error loading data from %s", fileStr) + } + } + if err != nil { + pdf.SetError(err) + } + } + // Simple table + basicTable := func() { + left := (210.0 - 4*40) / 2 + pdf.SetX(left) + for _, str := range header { + pdf.CellFormat(40, 7, str, "1", 0, "", false, 0, "") + } + pdf.Ln(-1) + for _, c := range countryList { + pdf.SetX(left) + pdf.CellFormat(40, 6, c.nameStr, "1", 0, "", false, 0, "") + pdf.CellFormat(40, 6, c.capitalStr, "1", 0, "", false, 0, "") + pdf.CellFormat(40, 6, c.areaStr, "1", 0, "", false, 0, "") + pdf.CellFormat(40, 6, c.popStr, "1", 0, "", false, 0, "") + pdf.Ln(-1) + } + } + // Better table + improvedTable := func() { + // Column widths + w := []float64{40.0, 35.0, 40.0, 45.0} + wSum := 0.0 + for _, v := range w { + wSum += v + } + left := (210 - wSum) / 2 + // Header + pdf.SetX(left) + for j, str := range header { + pdf.CellFormat(w[j], 7, str, "1", 0, "C", false, 0, "") + } + pdf.Ln(-1) + // Data + for _, c := range countryList { + pdf.SetX(left) + pdf.CellFormat(w[0], 6, c.nameStr, "LR", 0, "", false, 0, "") + pdf.CellFormat(w[1], 6, c.capitalStr, "LR", 0, "", false, 0, "") + pdf.CellFormat(w[2], 6, strDelimit(c.areaStr, ",", 3), + "LR", 0, "R", false, 0, "") + pdf.CellFormat(w[3], 6, strDelimit(c.popStr, ",", 3), + "LR", 0, "R", false, 0, "") + pdf.Ln(-1) + } + pdf.SetX(left) + pdf.CellFormat(wSum, 0, "", "T", 0, "", false, 0, "") + } + // Colored table + fancyTable := func() { + // Colors, line width and bold font + pdf.SetFillColor(255, 0, 0) + pdf.SetTextColor(255, 255, 255) + pdf.SetDrawColor(128, 0, 0) + pdf.SetLineWidth(.3) + pdf.SetFont("", "B", 0) + // Header + w := []float64{40, 35, 40, 45} + wSum := 0.0 + for _, v := range w { + wSum += v + } + left := (210 - wSum) / 2 + pdf.SetX(left) + for j, str := range header { + pdf.CellFormat(w[j], 7, str, "1", 0, "C", true, 0, "") + } + pdf.Ln(-1) + // Color and font restoration + pdf.SetFillColor(224, 235, 255) + pdf.SetTextColor(0, 0, 0) + pdf.SetFont("", "", 0) + // Data + fill := false + for _, c := range countryList { + pdf.SetX(left) + pdf.CellFormat(w[0], 6, c.nameStr, "LR", 0, "", fill, 0, "") + pdf.CellFormat(w[1], 6, c.capitalStr, "LR", 0, "", fill, 0, "") + pdf.CellFormat(w[2], 6, strDelimit(c.areaStr, ",", 3), + "LR", 0, "R", fill, 0, "") + pdf.CellFormat(w[3], 6, strDelimit(c.popStr, ",", 3), + "LR", 0, "R", fill, 0, "") + pdf.Ln(-1) + fill = !fill + } + pdf.SetX(left) + pdf.CellFormat(wSum, 0, "", "T", 0, "", false, 0, "") + } + loadData(example.TextFile("countries.txt")) + pdf.SetFont("Arial", "", 14) + pdf.AddPage() + basicTable() + pdf.AddPage() + improvedTable() + pdf.AddPage() + fancyTable() + fileStr := example.Filename("Fpdf_CellFormat_tables") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_CellFormat_tables.pdf +} + +// ExampleFpdf_HTMLBasicNew demonstrates internal and external links with and without basic +// HTML. +func ExampleFpdf_HTMLBasicNew() { + pdf := gofpdf.New("P", "mm", "A4", "") + // First page: manual local link + pdf.AddPage() + pdf.SetFont("Helvetica", "", 20) + _, lineHt := pdf.GetFontSize() + pdf.Write(lineHt, "To find out what's new in this tutorial, click ") + pdf.SetFont("", "U", 0) + link := pdf.AddLink() + pdf.WriteLinkID(lineHt, "here", link) + pdf.SetFont("", "", 0) + // Second page: image link and basic HTML with link + pdf.AddPage() + pdf.SetLink(link, 0, -1) + pdf.Image(example.ImageFile("logo.png"), 10, 12, 30, 0, false, "", 0, "http://www.fpdf.org") + pdf.SetLeftMargin(45) + pdf.SetFontSize(14) + _, lineHt = pdf.GetFontSize() + htmlStr := `You can now easily print text mixing different styles: bold, ` + + `italic, underlined, or all at once!

` + + `
You can also center text.
` + + `Or align it to the right.` + + `You can also insert links on text, such as ` + + `www.fpdf.org, or on an image: click on the logo.` + html := pdf.HTMLBasicNew() + html.Write(lineHt, htmlStr) + fileStr := example.Filename("Fpdf_HTMLBasicNew") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_HTMLBasicNew.pdf +} + +// ExampleFpdf_AddFont demonstrates the use of a non-standard font. +func ExampleFpdf_AddFont() { + pdf := gofpdf.New("P", "mm", "A4", example.FontDir()) + pdf.AddFont("Calligrapher", "", "calligra.json") + pdf.AddPage() + pdf.SetFont("Calligrapher", "", 35) + pdf.Cell(0, 10, "Enjoy new fonts with FPDF!") + fileStr := example.Filename("Fpdf_AddFont") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_AddFont.pdf +} + +// ExampleFpdf_WriteAligned demonstrates how to align text with the Write function. +func ExampleFpdf_WriteAligned() { + pdf := gofpdf.New("P", "mm", "A4", example.FontDir()) + pdf.SetLeftMargin(50.0) + pdf.SetRightMargin(50.0) + pdf.AddPage() + pdf.SetFont("Helvetica", "", 12) + pdf.WriteAligned(0, 35, "This text is the default alignment, Left", "") + pdf.Ln(35) + pdf.WriteAligned(0, 35, "This text is aligned Left", "L") + pdf.Ln(35) + pdf.WriteAligned(0, 35, "This text is aligned Center", "C") + pdf.Ln(35) + pdf.WriteAligned(0, 35, "This text is aligned Right", "R") + pdf.Ln(35) + line := "This can by used to write justified text" + leftMargin, _, rightMargin, _ := pdf.GetMargins() + pageWidth, _ := pdf.GetPageSize() + pageWidth -= leftMargin + rightMargin + pdf.SetWordSpacing((pageWidth - pdf.GetStringWidth(line)) / float64(strings.Count(line, " "))) + pdf.WriteAligned(pageWidth, 35, line, "L") + fileStr := example.Filename("Fpdf_WriteAligned") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_WriteAligned.pdf +} + +// ExampleFpdf_Image demonstrates how images are included in documents. +func ExampleFpdf_Image() { + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + pdf.SetFont("Arial", "", 11) + pdf.Image(example.ImageFile("logo.png"), 10, 10, 30, 0, false, "", 0, "") + pdf.Text(50, 20, "logo.png") + pdf.Image(example.ImageFile("logo.gif"), 10, 40, 30, 0, false, "", 0, "") + pdf.Text(50, 50, "logo.gif") + pdf.Image(example.ImageFile("logo-gray.png"), 10, 70, 30, 0, false, "", 0, "") + pdf.Text(50, 80, "logo-gray.png") + pdf.Image(example.ImageFile("logo-rgb.png"), 10, 100, 30, 0, false, "", 0, "") + pdf.Text(50, 110, "logo-rgb.png") + pdf.Image(example.ImageFile("logo.jpg"), 10, 130, 30, 0, false, "", 0, "") + pdf.Text(50, 140, "logo.jpg") + fileStr := example.Filename("Fpdf_Image") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_Image.pdf +} + +// ExampleFpdf_ImageOptions demonstrates how the AllowNegativePosition field of the +// ImageOption struct can be used to affect horizontal image placement. +func ExampleFpdf_ImageOptions() { + var opt gofpdf.ImageOptions + + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + pdf.SetFont("Arial", "", 11) + pdf.SetX(60) + opt.ImageType = "png" + pdf.ImageOptions(example.ImageFile("logo.png"), -10, 10, 30, 0, false, opt, 0, "") + opt.AllowNegativePosition = true + pdf.ImageOptions(example.ImageFile("logo.png"), -10, 50, 30, 0, false, opt, 0, "") + fileStr := example.Filename("Fpdf_ImageOptions") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_ImageOptions.pdf +} + +// 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 + loremStr := lorem() + pdf := gofpdf.New("L", "mm", "A4", "") + const ( + pageWd = 297.0 // A4 210.0 x 297.0 + margin = 10.0 + gutter = 4 + colNum = 3 + colWd = (pageWd - 2*margin - (colNum-1)*gutter) / colNum + ) + setCol := func(col int) { + crrntCol = col + x := margin + float64(col)*(colWd+gutter) + pdf.SetLeftMargin(x) + pdf.SetX(x) + } + pdf.SetHeaderFunc(func() { + titleStr := "gofpdf" + pdf.SetFont("Helvetica", "B", 48) + wd := pdf.GetStringWidth(titleStr) + 6 + pdf.SetX((pageWd - wd) / 2) + pdf.SetTextColor(128, 128, 160) + pdf.Write(12, titleStr[:2]) + pdf.SetTextColor(128, 128, 128) + pdf.Write(12, titleStr[2:]) + pdf.Ln(20) + y0 = pdf.GetY() + }) + pdf.SetAcceptPageBreakFunc(func() bool { + if crrntCol < colNum-1 { + setCol(crrntCol + 1) + pdf.SetY(y0) + // Start new column, not new page + return false + } + setCol(0) + return true + }) + pdf.AddPage() + pdf.SetFont("Times", "", 12) + for j := 0; j < 20; j++ { + if j == 1 { + pdf.Image(example.ImageFile("fpdf.png"), -1, 0, colWd, 0, true, "", 0, "") + } else if j == 5 { + pdf.Image(example.ImageFile("golang-gopher.png"), + -1, 0, colWd, 0, true, "", 0, "") + } + pdf.MultiCell(colWd, 5, loremStr, "", "", false) + pdf.Ln(-1) + } + fileStr := example.Filename("Fpdf_SetAcceptPageBreakFunc_landscape") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_SetAcceptPageBreakFunc_landscape.pdf +} + +// This example tests corner cases as reported by the gocov tool. +func ExampleFpdf_SetKeywords() { + var err error + fileStr := example.Filename("Fpdf_SetKeywords") + err = gofpdf.MakeFont(example.FontFile("CalligrapherRegular.pfb"), + example.FontFile("cp1252.map"), example.FontDir(), nil, true) + if err == nil { + pdf := gofpdf.New("", "", "", "") + pdf.SetFontLocation(example.FontDir()) + pdf.SetTitle("世界", true) + pdf.SetAuthor("世界", true) + pdf.SetSubject("世界", true) + pdf.SetCreator("世界", true) + pdf.SetKeywords("世界", true) + pdf.AddFont("Calligrapher", "", "CalligrapherRegular.json") + pdf.AddPage() + pdf.SetFont("Calligrapher", "", 16) + pdf.Writef(5, "\x95 %s \x95", pdf) + err = pdf.OutputFileAndClose(fileStr) + } + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_SetKeywords.pdf +} + +// ExampleFpdf_Circle demonstrates the construction of various geometric figures, +func ExampleFpdf_Circle() { + const ( + thin = 0.2 + thick = 3.0 + ) + pdf := gofpdf.New("", "", "", "") + pdf.SetFont("Helvetica", "", 12) + pdf.SetFillColor(200, 200, 220) + pdf.AddPage() + + y := 15.0 + pdf.Text(10, y, "Circles") + pdf.SetFillColor(200, 200, 220) + pdf.SetLineWidth(thin) + pdf.Circle(20, y+15, 10, "D") + pdf.Circle(45, y+15, 10, "F") + pdf.Circle(70, y+15, 10, "FD") + pdf.SetLineWidth(thick) + pdf.Circle(95, y+15, 10, "FD") + pdf.SetLineWidth(thin) + + y += 40.0 + pdf.Text(10, y, "Ellipses") + pdf.SetFillColor(220, 200, 200) + pdf.Ellipse(30, y+15, 20, 10, 0, "D") + pdf.Ellipse(75, y+15, 20, 10, 0, "F") + pdf.Ellipse(120, y+15, 20, 10, 0, "FD") + pdf.SetLineWidth(thick) + pdf.Ellipse(165, y+15, 20, 10, 0, "FD") + pdf.SetLineWidth(thin) + + y += 40.0 + pdf.Text(10, y, "Curves (quadratic)") + pdf.SetFillColor(220, 220, 200) + pdf.Curve(10, y+30, 15, y-20, 40, y+30, "D") + pdf.Curve(45, y+30, 50, y-20, 75, y+30, "F") + pdf.Curve(80, y+30, 85, y-20, 110, y+30, "FD") + pdf.SetLineWidth(thick) + pdf.Curve(115, y+30, 120, y-20, 145, y+30, "FD") + pdf.SetLineCapStyle("round") + pdf.Curve(150, y+30, 155, y-20, 180, y+30, "FD") + pdf.SetLineWidth(thin) + pdf.SetLineCapStyle("butt") + + y += 40.0 + pdf.Text(10, y, "Curves (cubic)") + pdf.SetFillColor(220, 200, 220) + pdf.CurveBezierCubic(10, y+30, 15, y-20, 10, y+30, 40, y+30, "D") + pdf.CurveBezierCubic(45, y+30, 50, y-20, 45, y+30, 75, y+30, "F") + pdf.CurveBezierCubic(80, y+30, 85, y-20, 80, y+30, 110, y+30, "FD") + pdf.SetLineWidth(thick) + pdf.CurveBezierCubic(115, y+30, 120, y-20, 115, y+30, 145, y+30, "FD") + pdf.SetLineCapStyle("round") + pdf.CurveBezierCubic(150, y+30, 155, y-20, 150, y+30, 180, y+30, "FD") + pdf.SetLineWidth(thin) + pdf.SetLineCapStyle("butt") + + y += 40.0 + pdf.Text(10, y, "Arcs") + pdf.SetFillColor(200, 220, 220) + pdf.SetLineWidth(thick) + pdf.Arc(45, y+35, 20, 10, 0, 0, 180, "FD") + pdf.SetLineWidth(thin) + pdf.Arc(45, y+35, 25, 15, 0, 90, 270, "D") + pdf.SetLineWidth(thick) + pdf.Arc(45, y+35, 30, 20, 0, 0, 360, "D") + pdf.SetLineCapStyle("round") + pdf.Arc(135, y+35, 20, 10, 135, 0, 180, "FD") + pdf.SetLineWidth(thin) + pdf.Arc(135, y+35, 25, 15, 135, 90, 270, "D") + pdf.SetLineWidth(thick) + pdf.Arc(135, y+35, 30, 20, 135, 0, 360, "D") + pdf.SetLineWidth(thin) + pdf.SetLineCapStyle("butt") + + fileStr := example.Filename("Fpdf_Circle_figures") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_Circle_figures.pdf +} + +// ExampleFpdf_SetAlpha demonstrates alpha transparency. +func ExampleFpdf_SetAlpha() { + const ( + gapX = 10.0 + gapY = 9.0 + rectW = 40.0 + rectH = 58.0 + pageW = 210 + pageH = 297 + ) + modeList := []string{"Normal", "Multiply", "Screen", "Overlay", + "Darken", "Lighten", "ColorDodge", "ColorBurn", "HardLight", "SoftLight", + "Difference", "Exclusion", "Hue", "Saturation", "Color", "Luminosity"} + pdf := gofpdf.New("", "", "", "") + pdf.SetLineWidth(2) + pdf.SetAutoPageBreak(false, 0) + pdf.AddPage() + pdf.SetFont("Helvetica", "", 18) + pdf.SetXY(0, gapY) + pdf.SetTextColor(0, 0, 0) + pdf.CellFormat(pageW, gapY, "Alpha Blending Modes", "", 0, "C", false, 0, "") + j := 0 + y := 3 * gapY + for col := 0; col < 4; col++ { + x := gapX + for row := 0; row < 4; row++ { + pdf.Rect(x, y, rectW, rectH, "D") + pdf.SetFont("Helvetica", "B", 12) + pdf.SetFillColor(0, 0, 0) + pdf.SetTextColor(250, 250, 230) + pdf.SetXY(x, y+rectH-4) + pdf.CellFormat(rectW, 5, modeList[j], "", 0, "C", true, 0, "") + pdf.SetFont("Helvetica", "I", 150) + pdf.SetTextColor(80, 80, 120) + pdf.SetXY(x, y+2) + pdf.CellFormat(rectW, rectH, "A", "", 0, "C", false, 0, "") + pdf.SetAlpha(0.5, modeList[j]) + pdf.Image(example.ImageFile("golang-gopher.png"), + x-gapX, y, rectW+2*gapX, 0, false, "", 0, "") + pdf.SetAlpha(1.0, "Normal") + x += rectW + gapX + j++ + } + y += rectH + gapY + } + fileStr := example.Filename("Fpdf_SetAlpha_transparency") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_SetAlpha_transparency.pdf +} + +// ExampleFpdf_LinearGradient deomstrates various gradients. +func ExampleFpdf_LinearGradient() { + pdf := gofpdf.New("", "", "", "") + pdf.SetFont("Helvetica", "", 12) + pdf.AddPage() + pdf.LinearGradient(0, 0, 210, 100, 250, 250, 255, 220, 220, 225, 0, 0, 0, .5) + pdf.LinearGradient(20, 25, 75, 75, 220, 220, 250, 80, 80, 220, 0, .2, 0, .8) + pdf.Rect(20, 25, 75, 75, "D") + pdf.LinearGradient(115, 25, 75, 75, 220, 220, 250, 80, 80, 220, 0, 0, 1, 1) + pdf.Rect(115, 25, 75, 75, "D") + pdf.RadialGradient(20, 120, 75, 75, 220, 220, 250, 80, 80, 220, + 0.25, 0.75, 0.25, 0.75, 1) + pdf.Rect(20, 120, 75, 75, "D") + pdf.RadialGradient(115, 120, 75, 75, 220, 220, 250, 80, 80, 220, + 0.25, 0.75, 0.75, 0.75, 0.75) + pdf.Rect(115, 120, 75, 75, "D") + fileStr := example.Filename("Fpdf_LinearGradient_gradient") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_LinearGradient_gradient.pdf +} + +// ExampleFpdf_ClipText demonstrates clipping. +func ExampleFpdf_ClipText() { + pdf := gofpdf.New("", "", "", "") + y := 10.0 + pdf.AddPage() + + pdf.SetFont("Helvetica", "", 24) + pdf.SetXY(0, y) + pdf.ClipText(10, y+12, "Clipping examples", false) + pdf.RadialGradient(10, y, 100, 20, 128, 128, 160, 32, 32, 48, + 0.25, 0.5, 0.25, 0.5, 0.2) + pdf.ClipEnd() + + y += 12 + pdf.SetFont("Helvetica", "B", 120) + pdf.SetDrawColor(64, 80, 80) + pdf.SetLineWidth(.5) + pdf.ClipText(10, y+40, pdf.String(), true) + pdf.RadialGradient(10, y, 200, 50, 220, 220, 250, 80, 80, 220, + 0.25, 0.5, 0.25, 0.5, 1) + pdf.ClipEnd() + + y += 55 + pdf.ClipRect(10, y, 105, 20, true) + pdf.SetFillColor(255, 255, 255) + pdf.Rect(10, y, 105, 20, "F") + pdf.ClipCircle(40, y+10, 15, false) + pdf.RadialGradient(25, y, 30, 30, 220, 250, 220, 40, 60, 40, 0.3, + 0.85, 0.3, 0.85, 0.5) + pdf.ClipEnd() + pdf.ClipEllipse(80, y+10, 20, 15, false) + pdf.RadialGradient(60, y, 40, 30, 250, 220, 220, 60, 40, 40, 0.3, + 0.85, 0.3, 0.85, 0.5) + pdf.ClipEnd() + pdf.ClipEnd() + + y += 28 + pdf.ClipEllipse(26, y+10, 16, 10, true) + pdf.Image(example.ImageFile("logo.jpg"), 10, y, 32, 0, false, "JPG", 0, "") + pdf.ClipEnd() + + pdf.ClipCircle(60, y+10, 10, true) + pdf.RadialGradient(50, y, 20, 20, 220, 220, 250, 40, 40, 60, 0.3, + 0.7, 0.3, 0.7, 0.5) + pdf.ClipEnd() + + pdf.ClipPolygon([]gofpdf.PointType{{X: 80, Y: y + 20}, {X: 90, Y: y}, + {X: 100, Y: y + 20}}, true) + pdf.LinearGradient(80, y, 20, 20, 250, 220, 250, 60, 40, 60, 0.5, + 1, 0.5, 0.5) + pdf.ClipEnd() + + y += 30 + pdf.SetLineWidth(.1) + pdf.SetDrawColor(180, 180, 180) + pdf.ClipRoundedRect(10, y, 120, 20, 5, true) + pdf.RadialGradient(10, y, 120, 20, 255, 255, 255, 240, 240, 220, + 0.25, 0.75, 0.25, 0.75, 0.5) + pdf.SetXY(5, y-5) + pdf.SetFont("Times", "", 12) + pdf.MultiCell(130, 5, lorem(), "", "", false) + pdf.ClipEnd() + + y += 30 + pdf.SetDrawColor(180, 100, 180) + pdf.ClipRoundedRectExt(10, y, 120, 20, 5, 10, 5, 10, true) + pdf.RadialGradient(10, y, 120, 20, 255, 255, 255, 240, 240, 220, + 0.25, 0.75, 0.25, 0.75, 0.5) + pdf.SetXY(5, y-5) + pdf.SetFont("Times", "", 12) + pdf.MultiCell(130, 5, lorem(), "", "", false) + pdf.ClipEnd() + + fileStr := example.Filename("Fpdf_ClipText") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_ClipText.pdf +} + +// ExampleFpdf_PageSize generates a PDF document with various page sizes. +func ExampleFpdf_PageSize() { + pdf := gofpdf.NewCustom(&gofpdf.InitType{ + UnitStr: "in", + Size: gofpdf.SizeType{Wd: 6, Ht: 6}, + FontDirStr: example.FontDir(), + }) + pdf.SetMargins(0.5, 1, 0.5) + pdf.SetFont("Times", "", 14) + pdf.AddPageFormat("L", gofpdf.SizeType{Wd: 3, Ht: 12}) + pdf.SetXY(0.5, 1.5) + pdf.CellFormat(11, 0.2, "12 in x 3 in", "", 0, "C", false, 0, "") + pdf.AddPage() // Default size established in NewCustom() + pdf.SetXY(0.5, 3) + pdf.CellFormat(5, 0.2, "6 in x 6 in", "", 0, "C", false, 0, "") + pdf.AddPageFormat("P", gofpdf.SizeType{Wd: 3, Ht: 12}) + pdf.SetXY(0.5, 6) + pdf.CellFormat(2, 0.2, "3 in x 12 in", "", 0, "C", false, 0, "") + for j := 0; j <= 3; j++ { + wd, ht, u := pdf.PageSize(j) + fmt.Printf("%d: %6.2f %s, %6.2f %s\n", j, wd, u, ht, u) + } + fileStr := example.Filename("Fpdf_PageSize") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // 0: 6.00 in, 6.00 in + // 1: 12.00 in, 3.00 in + // 2: 6.00 in, 6.00 in + // 3: 3.00 in, 12.00 in + // Successfully generated pdf/Fpdf_PageSize.pdf +} + +// ExampleFpdf_Bookmark demonstrates the Bookmark method. +func ExampleFpdf_Bookmark() { + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + pdf.SetFont("Arial", "", 15) + pdf.Bookmark("Page 1", 0, 0) + pdf.Bookmark("Paragraph 1", 1, -1) + pdf.Cell(0, 6, "Paragraph 1") + pdf.Ln(50) + pdf.Bookmark("Paragraph 2", 1, -1) + pdf.Cell(0, 6, "Paragraph 2") + pdf.AddPage() + pdf.Bookmark("Page 2", 0, 0) + pdf.Bookmark("Paragraph 3", 1, -1) + pdf.Cell(0, 6, "Paragraph 3") + fileStr := example.Filename("Fpdf_Bookmark") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_Bookmark.pdf +} + +// ExampleFpdf_TransformBegin demonstrates various transformations. It is adapted from an +// example script by Moritz Wagner and Andreas Würmser. +func ExampleFpdf_TransformBegin() { + const ( + light = 200 + dark = 0 + ) + var refX, refY float64 + var refStr string + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + color := func(val int) { + pdf.SetDrawColor(val, val, val) + pdf.SetTextColor(val, val, val) + } + reference := func(str string, x, y float64, val int) { + color(val) + pdf.Rect(x, y, 40, 10, "D") + pdf.Text(x, y-1, str) + } + refDraw := func(str string, x, y float64) { + refStr = str + refX = x + refY = y + reference(str, x, y, light) + } + refDupe := func() { + reference(refStr, refX, refY, dark) + } + + titleStr := "Transformations" + titlePt := 36.0 + titleHt := pdf.PointConvert(titlePt) + pdf.SetFont("Helvetica", "", titlePt) + titleWd := pdf.GetStringWidth(titleStr) + titleX := (210 - titleWd) / 2 + pdf.Text(titleX, 10+titleHt, titleStr) + pdf.TransformBegin() + pdf.TransformMirrorVertical(10 + titleHt + 0.5) + pdf.ClipText(titleX, 10+titleHt, titleStr, false) + // Remember that the transform will mirror the gradient box too + pdf.LinearGradient(titleX, 10, titleWd, titleHt+4, 120, 120, 120, + 255, 255, 255, 0, 0, 0, 0.6) + pdf.ClipEnd() + pdf.TransformEnd() + + pdf.SetFont("Helvetica", "", 12) + + // Scale by 150% centered by lower left corner of the rectangle + refDraw("Scale", 50, 60) + pdf.TransformBegin() + pdf.TransformScaleXY(150, 50, 70) + refDupe() + pdf.TransformEnd() + + // Translate 7 to the right, 5 to the bottom + refDraw("Translate", 125, 60) + pdf.TransformBegin() + pdf.TransformTranslate(7, 5) + refDupe() + pdf.TransformEnd() + + // Rotate 20 degrees counter-clockwise centered by the lower left corner of + // the rectangle + refDraw("Rotate", 50, 110) + pdf.TransformBegin() + pdf.TransformRotate(20, 50, 120) + refDupe() + pdf.TransformEnd() + + // Skew 30 degrees along the x-axis centered by the lower left corner of the + // rectangle + refDraw("Skew", 125, 110) + pdf.TransformBegin() + pdf.TransformSkewX(30, 125, 110) + refDupe() + pdf.TransformEnd() + + // Mirror horizontally with axis of reflection at left side of the rectangle + refDraw("Mirror horizontal", 50, 160) + pdf.TransformBegin() + pdf.TransformMirrorHorizontal(50) + refDupe() + pdf.TransformEnd() + + // Mirror vertically with axis of reflection at bottom side of the rectangle + refDraw("Mirror vertical", 125, 160) + pdf.TransformBegin() + pdf.TransformMirrorVertical(170) + refDupe() + pdf.TransformEnd() + + // Reflect against a point at the lower left point of rectangle + refDraw("Mirror point", 50, 210) + pdf.TransformBegin() + pdf.TransformMirrorPoint(50, 220) + refDupe() + pdf.TransformEnd() + + // Mirror against a straight line described by a point and an angle + angle := -20.0 + px := 120.0 + py := 220.0 + refDraw("Mirror line", 125, 210) + pdf.TransformBegin() + pdf.TransformRotate(angle, px, py) + pdf.Line(px-1, py-1, px+1, py+1) + pdf.Line(px-1, py+1, px+1, py-1) + pdf.Line(px-5, py, px+60, py) + pdf.TransformEnd() + pdf.TransformBegin() + pdf.TransformMirrorLine(angle, px, py) + refDupe() + pdf.TransformEnd() + + fileStr := example.Filename("Fpdf_TransformBegin") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_TransformBegin.pdf +} + +// ExampleFpdf_RegisterImage demonstrates Lawrence Kesteloot's image registration code. +func ExampleFpdf_RegisterImage() { + const ( + margin = 10 + wd = 210 + ht = 297 + ) + fileList := []string{ + "logo-gray.png", + "logo.jpg", + "logo.png", + "logo-rgb.png", + "logo-progressive.jpg", + } + var infoPtr *gofpdf.ImageInfoType + var imageFileStr string + var imgWd, imgHt, lf, tp float64 + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + pdf.SetMargins(10, 10, 10) + pdf.SetFont("Helvetica", "", 15) + for j, str := range fileList { + imageFileStr = example.ImageFile(str) + infoPtr = pdf.RegisterImage(imageFileStr, "") + imgWd, imgHt = infoPtr.Extent() + switch j { + case 0: + lf = margin + tp = margin + case 1: + lf = wd - margin - imgWd + tp = margin + case 2: + lf = (wd - imgWd) / 2.0 + tp = (ht - imgHt) / 2.0 + case 3: + lf = margin + tp = ht - imgHt - margin + case 4: + lf = wd - imgWd - margin + tp = ht - imgHt - margin + } + pdf.Image(imageFileStr, lf, tp, imgWd, imgHt, false, "", 0, "") + } + fileStr := example.Filename("Fpdf_RegisterImage") + // Test the image information retrieval method + infoShow := func(imageStr string) { + imageStr = example.ImageFile(imageStr) + info := pdf.GetImageInfo(imageStr) + if info != nil { + if info.Width() > 0.0 { + fmt.Printf("Image %s is registered\n", filepath.ToSlash(imageStr)) + } else { + fmt.Printf("Incorrect information for image %s\n", filepath.ToSlash(imageStr)) + } + } else { + fmt.Printf("Image %s is not registered\n", filepath.ToSlash(imageStr)) + } + } + infoShow(fileList[0]) + infoShow("foo.png") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Image image/logo-gray.png is registered + // Image image/foo.png is not registered + // Successfully generated pdf/Fpdf_RegisterImage.pdf +} + +// ExampleFpdf_SplitLines demonstrates Bruno Michel's line splitting function. +func ExampleFpdf_SplitLines() { + const ( + fontPtSize = 18.0 + wd = 100.0 + ) + pdf := gofpdf.New("P", "mm", "A4", "") // A4 210.0 x 297.0 + pdf.SetFont("Times", "", fontPtSize) + _, lineHt := pdf.GetFontSize() + pdf.AddPage() + pdf.SetMargins(10, 10, 10) + lines := pdf.SplitLines([]byte(lorem()), wd) + ht := float64(len(lines)) * lineHt + y := (297.0 - ht) / 2.0 + pdf.SetDrawColor(128, 128, 128) + pdf.SetFillColor(255, 255, 210) + x := (210.0 - (wd + 40.0)) / 2.0 + pdf.Rect(x, y-20.0, wd+40.0, ht+40.0, "FD") + pdf.SetY(y) + for _, line := range lines { + pdf.CellFormat(190.0, lineHt, string(line), "", 1, "C", false, 0, "") + } + fileStr := example.Filename("Fpdf_Splitlines") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_Splitlines.pdf +} + +// ExampleFpdf_SVGBasicWrite demonstrates how to render a simple path-only SVG image of the +// type generated by the jSignature web control. +func ExampleFpdf_SVGBasicWrite() { + const ( + fontPtSize = 16.0 + wd = 100.0 + sigFileStr = "signature.svg" + ) + var ( + sig gofpdf.SVGBasicType + err error + ) + pdf := gofpdf.New("P", "mm", "A4", "") // A4 210.0 x 297.0 + pdf.SetFont("Times", "", fontPtSize) + lineHt := pdf.PointConvert(fontPtSize) + pdf.AddPage() + pdf.SetMargins(10, 10, 10) + htmlStr := `This example renders a simple ` + + `SVG (scalable vector graphics) ` + + `image that contains only basic path commands without any styling, ` + + `color fill, reflection or endpoint closures. In particular, the ` + + `type of vector graphic returned from a ` + + `jSignature ` + + `web control is supported and is used in this example.` + html := pdf.HTMLBasicNew() + html.Write(lineHt, htmlStr) + sig, err = gofpdf.SVGBasicFileParse(example.ImageFile(sigFileStr)) + if err == nil { + scale := 100 / sig.Wd + scaleY := 30 / sig.Ht + if scale > scaleY { + scale = scaleY + } + pdf.SetLineCapStyle("round") + pdf.SetLineWidth(0.25) + pdf.SetDrawColor(0, 0, 128) + pdf.SetXY((210.0-scale*sig.Wd)/2.0, pdf.GetY()+10) + pdf.SVGBasicWrite(&sig, scale) + } else { + pdf.SetError(err) + } + fileStr := example.Filename("Fpdf_SVGBasicWrite") + err = pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_SVGBasicWrite.pdf +} + +// ExampleFpdf_CellFormat_align demonstrates Stefan Schroeder's code to control vertical +// alignment. +func ExampleFpdf_CellFormat_align() { + type recType struct { + align, txt string + } + recList := []recType{ + {"TL", "top left"}, + {"TC", "top center"}, + {"TR", "top right"}, + {"LM", "middle left"}, + {"CM", "middle center"}, + {"RM", "middle right"}, + {"BL", "bottom left"}, + {"BC", "bottom center"}, + {"BR", "bottom right"}, + } + recListBaseline := []recType{ + {"AL", "baseline left"}, + {"AC", "baseline center"}, + {"AR", "baseline right"}, + } + var formatRect = func(pdf *gofpdf.Fpdf, recList []recType) { + linkStr := "" + for pageJ := 0; pageJ < 2; pageJ++ { + pdf.AddPage() + pdf.SetMargins(10, 10, 10) + pdf.SetAutoPageBreak(false, 0) + borderStr := "1" + for _, rec := range recList { + pdf.SetXY(20, 20) + pdf.CellFormat(170, 257, rec.txt, borderStr, 0, rec.align, false, 0, linkStr) + borderStr = "" + } + linkStr = "https://github.com/jung-kurt/gofpdf" + } + } + pdf := gofpdf.New("P", "mm", "A4", "") // A4 210.0 x 297.0 + pdf.SetFont("Helvetica", "", 16) + formatRect(pdf, recList) + formatRect(pdf, recListBaseline) + var fr fontResourceType + pdf.SetFontLoader(fr) + pdf.AddFont("Calligrapher", "", "calligra.json") + pdf.SetFont("Calligrapher", "", 16) + formatRect(pdf, recListBaseline) + fileStr := example.Filename("Fpdf_CellFormat_align") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Generalized font loader reading calligra.json + // Generalized font loader reading calligra.z + // Successfully generated pdf/Fpdf_CellFormat_align.pdf +} + +// ExampleFpdf_CellFormat_codepageescape demonstrates the use of characters in the high range of the +// Windows-1252 code page (gofdpf default). See the example for CellFormat (4) +// for a way to do this automatically. +func ExampleFpdf_CellFormat_codepageescape() { + pdf := gofpdf.New("P", "mm", "A4", "") // A4 210.0 x 297.0 + fontSize := 16.0 + pdf.SetFont("Helvetica", "", fontSize) + ht := pdf.PointConvert(fontSize) + write := func(str string) { + pdf.CellFormat(190, ht, str, "", 1, "C", false, 0, "") + pdf.Ln(ht) + } + pdf.AddPage() + htmlStr := `Until gofpdf supports UTF-8 encoded source text, source text needs ` + + `to be specified with all special characters escaped to match the code page ` + + `layout of the currently selected font. By default, gofdpf uses code page 1252.` + + ` See Wikipedia for ` + + `a table of this layout.` + html := pdf.HTMLBasicNew() + html.Write(ht, htmlStr) + pdf.Ln(2 * ht) + write("Voix ambigu\xeb d'un c\x9cur qui au z\xe9phyr pr\xe9f\xe8re les jattes de kiwi.") + write("Falsches \xdcben von Xylophonmusik qu\xe4lt jeden gr\xf6\xdferen Zwerg.") + write("Heiz\xf6lr\xfccksto\xdfabd\xe4mpfung") + write("For\xe5rsj\xe6vnd\xf8gn / Efter\xe5rsj\xe6vnd\xf8gn") + fileStr := example.Filename("Fpdf_CellFormat_codepageescape") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_CellFormat_codepageescape.pdf +} + +// ExampleFpdf_CellFormat_codepage demonstrates the automatic conversion of UTF-8 strings to an +// 8-bit font encoding. +func ExampleFpdf_CellFormat_codepage() { + pdf := gofpdf.New("P", "mm", "A4", example.FontDir()) // A4 210.0 x 297.0 + // See documentation for details on how to generate fonts + pdf.AddFont("Helvetica-1251", "", "helvetica_1251.json") + pdf.AddFont("Helvetica-1253", "", "helvetica_1253.json") + fontSize := 16.0 + pdf.SetFont("Helvetica", "", fontSize) + ht := pdf.PointConvert(fontSize) + tr := pdf.UnicodeTranslatorFromDescriptor("") // "" defaults to "cp1252" + write := func(str string) { + // pdf.CellFormat(190, ht, tr(str), "", 1, "C", false, 0, "") + pdf.MultiCell(190, ht, tr(str), "", "C", false) + pdf.Ln(ht) + } + pdf.AddPage() + str := `Gofpdf provides a translator that will convert any UTF-8 code point ` + + `that is present in the specified code page.` + pdf.MultiCell(190, ht, str, "", "L", false) + pdf.Ln(2 * ht) + write("Voix ambiguë d'un cœur qui au zéphyr préfère les jattes de kiwi.") + write("Falsches Üben von Xylophonmusik quält jeden größeren Zwerg.") + write("Heizölrückstoßabdämpfung") + write("Forårsjævndøgn / Efterårsjævndøgn") + write("À noite, vovô Kowalsky vê o ímã cair no pé do pingüim queixoso e vovó" + + "põe açúcar no chá de tâmaras do jabuti feliz.") + pdf.SetFont("Helvetica-1251", "", fontSize) // Name matches one specified in AddFont() + tr = pdf.UnicodeTranslatorFromDescriptor("cp1251") + write("Съешь же ещё этих мягких французских булок, да выпей чаю.") + + pdf.SetFont("Helvetica-1253", "", fontSize) + tr = pdf.UnicodeTranslatorFromDescriptor("cp1253") + write("Θέλει αρετή και τόλμη η ελευθερία. (Ανδρέας Κάλβος)") + + fileStr := example.Filename("Fpdf_CellFormat_codepage") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_CellFormat_codepage.pdf +} + +// ExampleFpdf_SetProtection demonstrates password protection for documents. +func ExampleFpdf_SetProtection() { + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.SetProtection(gofpdf.CnProtectPrint, "123", "abc") + pdf.AddPage() + pdf.SetFont("Arial", "", 12) + pdf.Write(10, "Password-protected.") + fileStr := example.Filename("Fpdf_SetProtection") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_SetProtection.pdf +} + +// ExampleFpdf_Polygon displays equilateral polygons in a demonstration of the Polygon +// function. +func ExampleFpdf_Polygon() { + const rowCount = 5 + const colCount = 4 + const ptSize = 36 + var x, y, radius, gap, advance float64 + var rgVal int + var pts []gofpdf.PointType + vertices := func(count int) (res []gofpdf.PointType) { + var pt gofpdf.PointType + res = make([]gofpdf.PointType, 0, count) + mlt := 2.0 * math.Pi / float64(count) + for j := 0; j < count; j++ { + pt.Y, pt.X = math.Sincos(float64(j) * mlt) + res = append(res, gofpdf.PointType{ + X: x + radius*pt.X, + Y: y + radius*pt.Y}) + } + return + } + pdf := gofpdf.New("P", "mm", "A4", "") // A4 210.0 x 297.0 + pdf.AddPage() + pdf.SetFont("Helvetica", "", ptSize) + pdf.SetDrawColor(0, 80, 180) + gap = 12.0 + pdf.SetY(gap) + pdf.CellFormat(190.0, gap, "Equilateral polygons", "", 1, "C", false, 0, "") + radius = (210.0 - float64(colCount+1)*gap) / (2.0 * float64(colCount)) + advance = gap + 2.0*radius + y = 2*gap + pdf.PointConvert(ptSize) + radius + rgVal = 230 + for row := 0; row < rowCount; row++ { + pdf.SetFillColor(rgVal, rgVal, 0) + rgVal -= 12 + x = gap + radius + for col := 0; col < colCount; col++ { + pts = vertices(row*colCount + col + 3) + pdf.Polygon(pts, "FD") + x += advance + } + y += advance + } + fileStr := example.Filename("Fpdf_Polygon") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_Polygon.pdf +} + +// ExampleFpdf_AddLayer demonstrates document layers. The initial visibility of a layer +// is specified with the second parameter to AddLayer(). The layer list +// displayed by the document reader allows layer visibility to be controlled +// interactively. +func ExampleFpdf_AddLayer() { + + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + pdf.SetFont("Arial", "", 15) + pdf.Write(8, "This line doesn't belong to any layer.\n") + + // Define layers + l1 := pdf.AddLayer("Layer 1", true) + l2 := pdf.AddLayer("Layer 2", true) + + // Open layer pane in PDF viewer + pdf.OpenLayerPane() + + // First layer + pdf.BeginLayer(l1) + pdf.Write(8, "This line belongs to layer 1.\n") + pdf.EndLayer() + + // Second layer + pdf.BeginLayer(l2) + pdf.Write(8, "This line belongs to layer 2.\n") + pdf.EndLayer() + + // First layer again + pdf.BeginLayer(l1) + pdf.Write(8, "This line belongs to layer 1 again.\n") + pdf.EndLayer() + + fileStr := example.Filename("Fpdf_AddLayer") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_AddLayer.pdf +} + +// ExampleFpdf_RegisterImageReader demonstrates the use of an image that is retrieved from a web +// server. +func ExampleFpdf_RegisterImageReader() { + + const ( + margin = 10 + wd = 210 + ht = 297 + fontSize = 15 + urlStr = "https://github.com/jung-kurt/gofpdf/blob/master/image/gofpdf.png?raw=true" + msgStr = `Images from the web can be easily embedded when a PDF document is generated.` + ) + + var ( + rsp *http.Response + err error + tp string + ) + + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + pdf.SetFont("Helvetica", "", fontSize) + ln := pdf.PointConvert(fontSize) + pdf.MultiCell(wd-margin-margin, ln, msgStr, "", "L", false) + rsp, err = http.Get(urlStr) + if err == nil { + tp = pdf.ImageTypeFromMime(rsp.Header["Content-Type"][0]) + infoPtr := pdf.RegisterImageReader(urlStr, tp, rsp.Body) + if pdf.Ok() { + imgWd, imgHt := infoPtr.Extent() + pdf.Image(urlStr, (wd-imgWd)/2.0, pdf.GetY()+ln, + imgWd, imgHt, false, tp, 0, "") + } + } else { + pdf.SetError(err) + } + fileStr := example.Filename("Fpdf_RegisterImageReader_url") + err = pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_RegisterImageReader_url.pdf + +} + +// ExampleFpdf_Beziergon demonstrates the Beziergon function. +func ExampleFpdf_Beziergon() { + + const ( + margin = 10 + wd = 210 + unit = (wd - 2*margin) / 6 + ht = 297 + fontSize = 15 + msgStr = `Demonstration of Beziergon function` + coefficient = 0.6 + delta = coefficient * unit + ln = fontSize * 25.4 / 72 + offsetX = (wd - 4*unit) / 2.0 + offsetY = offsetX + 2*ln + ) + + srcList := []gofpdf.PointType{ + {X: 0, Y: 0}, + {X: 1, Y: 0}, + {X: 1, Y: 1}, + {X: 2, Y: 1}, + {X: 2, Y: 2}, + {X: 3, Y: 2}, + {X: 3, Y: 3}, + {X: 4, Y: 3}, + {X: 4, Y: 4}, + {X: 1, Y: 4}, + {X: 1, Y: 3}, + {X: 0, Y: 3}, + } + + ctrlList := []gofpdf.PointType{ + {X: 1, Y: -1}, + {X: 1, Y: 1}, + {X: 1, Y: 1}, + {X: 1, Y: 1}, + {X: 1, Y: 1}, + {X: 1, Y: 1}, + {X: 1, Y: 1}, + {X: 1, Y: 1}, + {X: -1, Y: 1}, + {X: -1, Y: -1}, + {X: -1, Y: -1}, + {X: -1, Y: -1}, + } + + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + pdf.SetFont("Helvetica", "", fontSize) + for j, src := range srcList { + srcList[j].X = offsetX + src.X*unit + srcList[j].Y = offsetY + src.Y*unit + } + for j, ctrl := range ctrlList { + ctrlList[j].X = ctrl.X * delta + ctrlList[j].Y = ctrl.Y * delta + } + jPrev := len(srcList) - 1 + srcPrev := srcList[jPrev] + curveList := []gofpdf.PointType{srcPrev} // point [, control 0, control 1, point]* + control := func(x, y float64) { + curveList = append(curveList, gofpdf.PointType{X: x, Y: y}) + } + for j, src := range srcList { + ctrl := ctrlList[jPrev] + control(srcPrev.X+ctrl.X, srcPrev.Y+ctrl.Y) // Control 0 + ctrl = ctrlList[j] + control(src.X-ctrl.X, src.Y-ctrl.Y) // Control 1 + curveList = append(curveList, src) // Destination + jPrev = j + srcPrev = src + } + pdf.MultiCell(wd-margin-margin, ln, msgStr, "", "C", false) + pdf.SetDashPattern([]float64{0.8, 0.8}, 0) + pdf.SetDrawColor(160, 160, 160) + pdf.Polygon(srcList, "D") + pdf.SetDashPattern([]float64{}, 0) + pdf.SetDrawColor(64, 64, 128) + pdf.SetLineWidth(pdf.GetLineWidth() * 3) + pdf.Beziergon(curveList, "D") + fileStr := example.Filename("Fpdf_Beziergon") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_Beziergon.pdf + +} + +// ExampleFpdf_SetFontLoader demonstrates loading a non-standard font using a generalized +// font loader. fontResourceType implements the FontLoader interface and is +// defined locally in the test source code. +func ExampleFpdf_SetFontLoader() { + var fr fontResourceType + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.SetFontLoader(fr) + pdf.AddFont("Calligrapher", "", "calligra.json") + pdf.AddPage() + pdf.SetFont("Calligrapher", "", 35) + pdf.Cell(0, 10, "Load fonts from any source") + fileStr := example.Filename("Fpdf_SetFontLoader") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Generalized font loader reading calligra.json + // Generalized font loader reading calligra.z + // Successfully generated pdf/Fpdf_SetFontLoader.pdf +} + +// ExampleFpdf_MoveTo demonstrates the Path Drawing functions, such as: MoveTo, +// LineTo, CurveTo, ..., ClosePath and DrawPath. +func ExampleFpdf_MoveTo() { + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + pdf.MoveTo(20, 20) + pdf.LineTo(170, 20) + pdf.ArcTo(170, 40, 20, 20, 0, 90, 0) + pdf.CurveTo(190, 100, 105, 100) + pdf.CurveBezierCubicTo(20, 100, 105, 200, 20, 200) + pdf.ClosePath() + pdf.SetFillColor(200, 200, 200) + pdf.SetLineWidth(3) + pdf.DrawPath("DF") + fileStr := example.Filename("Fpdf_MoveTo_path") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_MoveTo_path.pdf +} + +// ExampleFpdf_SetLineJoinStyle demonstrates various line cap and line join styles. +func ExampleFpdf_SetLineJoinStyle() { + const offset = 75.0 + pdf := gofpdf.New("L", "mm", "A4", "") + pdf.AddPage() + var draw = func(cap, join string, x0, y0, x1, y1 float64) { + // transform begin & end needed to isolate caps and joins + pdf.SetLineCapStyle(cap) + pdf.SetLineJoinStyle(join) + + // Draw thick line + pdf.SetDrawColor(0x33, 0x33, 0x33) + pdf.SetLineWidth(30.0) + pdf.MoveTo(x0, y0) + pdf.LineTo((x0+x1)/2+offset, (y0+y1)/2) + pdf.LineTo(x1, y1) + pdf.DrawPath("D") + + // Draw thin helping line + pdf.SetDrawColor(0xFF, 0x33, 0x33) + pdf.SetLineWidth(2.56) + pdf.MoveTo(x0, y0) + pdf.LineTo((x0+x1)/2+offset, (y0+y1)/2) + pdf.LineTo(x1, y1) + pdf.DrawPath("D") + + } + x := 35.0 + caps := []string{"butt", "square", "round"} + joins := []string{"bevel", "miter", "round"} + for i := range caps { + draw(caps[i], joins[i], x, 50, x, 160) + x += offset + } + fileStr := example.Filename("Fpdf_SetLineJoinStyle_caps") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_SetLineJoinStyle_caps.pdf +} + +// ExampleFpdf_DrawPath demonstrates various fill modes. +func ExampleFpdf_DrawPath() { + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.SetDrawColor(0xff, 0x00, 0x00) + pdf.SetFillColor(0x99, 0x99, 0x99) + pdf.SetFont("Helvetica", "", 15) + pdf.AddPage() + pdf.SetAlpha(1, "Multiply") + var ( + polygon = func(cx, cy, r, n, dir float64) { + da := 2 * math.Pi / n + pdf.MoveTo(cx+r, cy) + pdf.Text(cx+r, cy, "0") + i := 1 + for a := da; a < 2*math.Pi; a += da { + x, y := cx+r*math.Cos(dir*a), cy+r*math.Sin(dir*a) + pdf.LineTo(x, y) + pdf.Text(x, y, strconv.Itoa(i)) + i++ + } + pdf.ClosePath() + } + polygons = func(cx, cy, r, n, dir float64) { + d := 1.0 + for rf := r; rf > 0; rf -= 10 { + polygon(cx, cy, rf, n, d) + d *= dir + } + } + star = func(cx, cy, r, n float64) { + da := 4 * math.Pi / n + pdf.MoveTo(cx+r, cy) + for a := da; a < 4*math.Pi+da; a += da { + x, y := cx+r*math.Cos(a), cy+r*math.Sin(a) + pdf.LineTo(x, y) + } + pdf.ClosePath() + } + ) + // triangle + polygons(55, 45, 40, 3, 1) + pdf.DrawPath("B") + pdf.Text(15, 95, "B (same direction, non zero winding)") + + // square + polygons(155, 45, 40, 4, 1) + pdf.DrawPath("B*") + pdf.Text(115, 95, "B* (same direction, even odd)") + + // pentagon + polygons(55, 145, 40, 5, -1) + pdf.DrawPath("B") + pdf.Text(15, 195, "B (different direction, non zero winding)") + + // hexagon + polygons(155, 145, 40, 6, -1) + pdf.DrawPath("B*") + pdf.Text(115, 195, "B* (different direction, even odd)") + + // star + star(55, 245, 40, 5) + pdf.DrawPath("B") + pdf.Text(15, 290, "B (non zero winding)") + + // star + star(155, 245, 40, 5) + pdf.DrawPath("B*") + pdf.Text(115, 290, "B* (even odd)") + + fileStr := example.Filename("Fpdf_DrawPath_fill") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_DrawPath_fill.pdf +} + +// ExampleFpdf_CreateTemplate demonstrates creating and using templates +func ExampleFpdf_CreateTemplate() { + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.SetCompression(false) + // pdf.SetFont("Times", "", 12) + template := pdf.CreateTemplate(func(tpl *gofpdf.Tpl) { + tpl.Image(example.ImageFile("logo.png"), 6, 6, 30, 0, false, "", 0, "") + tpl.SetFont("Arial", "B", 16) + tpl.Text(40, 20, "Template says hello") + tpl.SetDrawColor(0, 100, 200) + tpl.SetLineWidth(2.5) + tpl.Line(95, 12, 105, 22) + }) + _, tplSize := template.Size() + // fmt.Println("Size:", tplSize) + // fmt.Println("Scaled:", tplSize.ScaleBy(1.5)) + + template2 := pdf.CreateTemplate(func(tpl *gofpdf.Tpl) { + tpl.UseTemplate(template) + subtemplate := tpl.CreateTemplate(func(tpl2 *gofpdf.Tpl) { + tpl2.Image(example.ImageFile("logo.png"), 6, 86, 30, 0, false, "", 0, "") + tpl2.SetFont("Arial", "B", 16) + tpl2.Text(40, 100, "Subtemplate says hello") + tpl2.SetDrawColor(0, 200, 100) + tpl2.SetLineWidth(2.5) + tpl2.Line(102, 92, 112, 102) + }) + tpl.UseTemplate(subtemplate) + }) + + pdf.SetDrawColor(200, 100, 0) + pdf.SetLineWidth(2.5) + pdf.SetFont("Arial", "B", 16) + + // serialize and deserialize template + b, _ := template2.Serialize() + template3, _ := gofpdf.DeserializeTemplate(b) + + pdf.AddPage() + pdf.UseTemplate(template3) + pdf.UseTemplateScaled(template3, gofpdf.PointType{X: 0, Y: 30}, tplSize) + pdf.Line(40, 210, 60, 210) + pdf.Text(40, 200, "Template example page 1") + + pdf.AddPage() + pdf.UseTemplate(template2) + pdf.UseTemplateScaled(template3, gofpdf.PointType{X: 0, Y: 30}, tplSize.ScaleBy(1.4)) + pdf.Line(60, 210, 80, 210) + pdf.Text(40, 200, "Template example page 2") + + fileStr := example.Filename("Fpdf_CreateTemplate") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_CreateTemplate.pdf +} + +// ExampleFpdf_AddFontFromBytes demonstrate how to use embedded fonts from byte array +func ExampleFpdf_AddFontFromBytes() { + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + pdf.AddFontFromBytes("calligra", "", files.CalligraJson, files.CalligraZ) + pdf.SetFont("calligra", "", 16) + pdf.Cell(40, 10, "Hello World With Embedded Font!") + fileStr := example.Filename("Fpdf_EmbeddedFont") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_EmbeddedFont.pdf +} + +// This example demonstrate Clipped table cells +func ExampleFpdf_ClipRect() { + marginCell := 2. // margin of top/bottom of cell + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.SetFont("Arial", "", 12) + pdf.AddPage() + pagew, pageh := pdf.GetPageSize() + mleft, mright, _, mbottom := pdf.GetMargins() + + cols := []float64{60, 100, pagew - mleft - mright - 100 - 60} + rows := [][]string{} + for i := 1; i <= 50; i++ { + word := fmt.Sprintf("%d:%s", i, strings.Repeat("A", i%100)) + rows = append(rows, []string{word, word, word}) + } + + for _, row := range rows { + _, lineHt := pdf.GetFontSize() + height := lineHt + marginCell + + x, y := pdf.GetXY() + // add a new page if the height of the row doesn't fit on the page + if y+height >= pageh-mbottom { + pdf.AddPage() + x, y = pdf.GetXY() + } + for i, txt := range row { + width := cols[i] + pdf.Rect(x, y, width, height, "") + pdf.ClipRect(x, y, width, height, false) + pdf.Cell(width, height, txt) + pdf.ClipEnd() + x += width + } + pdf.Ln(-1) + } + fileStr := example.Filename("Fpdf_ClippedTableCells") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_ClippedTableCells.pdf +} + +// This example demonstrate wrapped table cells +func ExampleFpdf_Rect() { + marginCell := 2. // margin of top/bottom of cell + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.SetFont("Arial", "", 12) + pdf.AddPage() + pagew, pageh := pdf.GetPageSize() + mleft, mright, _, mbottom := pdf.GetMargins() + + cols := []float64{60, 100, pagew - mleft - mright - 100 - 60} + rows := [][]string{} + for i := 1; i <= 30; i++ { + word := fmt.Sprintf("%d:%s", i, strings.Repeat("A", i%100)) + rows = append(rows, []string{word, word, word}) + } + + for _, row := range rows { + curx, y := pdf.GetXY() + x := curx + + height := 0. + _, lineHt := pdf.GetFontSize() + + for i, txt := range row { + lines := pdf.SplitLines([]byte(txt), cols[i]) + h := float64(len(lines))*lineHt + marginCell*float64(len(lines)) + if h > height { + height = h + } + } + // add a new page if the height of the row doesn't fit on the page + if pdf.GetY()+height > pageh-mbottom { + pdf.AddPage() + y = pdf.GetY() + } + for i, txt := range row { + width := cols[i] + pdf.Rect(x, y, width, height, "") + pdf.MultiCell(width, lineHt+marginCell, txt, "", "", false) + x += width + pdf.SetXY(x, y) + } + pdf.SetXY(curx, y+height) + } + fileStr := example.Filename("Fpdf_WrappedTableCells") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_WrappedTableCells.pdf +} + +// ExampleFpdf_SetJavascript demonstrates including JavaScript in the document. +func ExampleFpdf_SetJavascript() { + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.SetJavascript("print(true);") + pdf.AddPage() + pdf.SetFont("Arial", "", 12) + pdf.Write(10, "Auto-print.") + fileStr := example.Filename("Fpdf_SetJavascript") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_SetJavascript.pdf +} + +// ExampleFpdf_AddSpotColor demonstrates spot color use +func ExampleFpdf_AddSpotColor() { + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddSpotColor("PANTONE 145 CVC", 0, 42, 100, 25) + pdf.AddPage() + pdf.SetFillSpotColor("PANTONE 145 CVC", 90) + pdf.Rect(80, 40, 50, 50, "F") + fileStr := example.Filename("Fpdf_AddSpotColor") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_AddSpotColor.pdf +} + +// ExampleFpdf_RegisterAlias demonstrates how to use `RegisterAlias` to create a table of +// contents. +func ExampleFpdf_RegisterAlias() { + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.SetFont("Arial", "", 12) + pdf.AliasNbPages("") + pdf.AddPage() + + // Write the table of contents. We use aliases instead of the page number + // because we don't know which page the section will begin on. + numSections := 3 + for i := 1; i <= numSections; i++ { + pdf.Cell(0, 10, fmt.Sprintf("Section %d begins on page {mark %d}", i, i)) + pdf.Ln(10) + } + + // Write the sections. Before we start writing, we use `RegisterAlias` to + // ensure that the alias written in the table of contents will be replaced + // by the current page number. + for i := 1; i <= numSections; i++ { + pdf.AddPage() + pdf.RegisterAlias(fmt.Sprintf("{mark %d}", i), fmt.Sprintf("%d", pdf.PageNo())) + pdf.Write(10, fmt.Sprintf("Section %d, page %d of {nb}", i, pdf.PageNo())) + } + + fileStr := example.Filename("Fpdf_RegisterAlias") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_RegisterAlias.pdf +} + +// ExampleFpdf_RegisterAlias_utf8 demonstrates how to use `RegisterAlias` to +// create a table of contents. This particular example demonstrates the use of +// UTF-8 aliases. +func ExampleFpdf_RegisterAlias_utf8() { + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddUTF8Font("dejavu", "", example.FontFile("DejaVuSansCondensed.ttf")) + pdf.SetFont("dejavu", "", 12) + pdf.AliasNbPages("{entute}") + pdf.AddPage() + + // Write the table of contents. We use aliases instead of the page number + // because we don't know which page the section will begin on. + numSections := 3 + for i := 1; i <= numSections; i++ { + pdf.Cell(0, 10, fmt.Sprintf("Sekcio %d komenciĝas ĉe paĝo {ĉi tiu marko %d}", i, i)) + pdf.Ln(10) + } + + // Write the sections. Before we start writing, we use `RegisterAlias` to + // ensure that the alias written in the table of contents will be replaced + // by the current page number. + for i := 1; i <= numSections; i++ { + pdf.AddPage() + pdf.RegisterAlias(fmt.Sprintf("{ĉi tiu marko %d}", i), fmt.Sprintf("%d", pdf.PageNo())) + pdf.Write(10, fmt.Sprintf("Sekcio %d, paĝo %d de {entute}", i, pdf.PageNo())) + } + + fileStr := example.Filename("Fpdf_RegisterAliasUTF8") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_RegisterAliasUTF8.pdf +} + +// ExampleNewGrid demonstrates the generation of graph grids. +func ExampleNewGrid() { + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.SetFont("Arial", "", 12) + pdf.AddPage() + + gr := gofpdf.NewGrid(13, 10, 187, 130) + gr.TickmarksExtentX(0, 10, 4) + gr.TickmarksExtentY(0, 10, 3) + gr.Grid(pdf) + + gr = gofpdf.NewGrid(13, 154, 187, 128) + gr.XLabelRotate = true + gr.TickmarksExtentX(0, 1, 12) + gr.XDiv = 5 + gr.TickmarksContainY(0, 1.1) + gr.YDiv = 20 + // Replace X label formatter with month abbreviation + gr.XTickStr = func(val float64, precision int) string { + return time.Month(math.Mod(val, 12) + 1).String()[0:3] + } + gr.Grid(pdf) + dot := func(x, y float64) { + pdf.Circle(gr.X(x), gr.Y(y), 0.5, "F") + } + pts := []float64{0.39, 0.457, 0.612, 0.84, 0.998, 1.037, 1.015, 0.918, 0.772, 0.659, 0.593, 0.164} + for month, val := range pts { + dot(float64(month)+0.5, val) + } + pdf.SetDrawColor(255, 64, 64) + pdf.SetAlpha(0.5, "Normal") + pdf.SetLineWidth(1.2) + gr.Plot(pdf, 0.5, 11.5, 50, func(x float64) float64 { + // http://www.xuru.org/rt/PR.asp + return 0.227 * math.Exp(-0.0373*x*x+0.471*x) + }) + pdf.SetAlpha(1.0, "Normal") + pdf.SetXY(gr.X(0.5), gr.Y(1.35)) + pdf.SetFontSize(14) + pdf.Write(0, "Solar energy (MWh) per month, 2016") + pdf.AddPage() + + gr = gofpdf.NewGrid(13, 10, 187, 274) + gr.TickmarksContainX(2.3, 3.4) + gr.TickmarksContainY(10.4, 56.8) + gr.Grid(pdf) + + fileStr := example.Filename("Fpdf_Grid") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_Grid.pdf +} + +// ExampleFpdf_SetPageBox demonstrates the use of a page box +func ExampleFpdf_SetPageBox() { + // pdfinfo (from http://www.xpdfreader.com) reports the following for this example: + // ~ pdfinfo -box pdf/Fpdf_PageBox.pdf + // Producer: FPDF 1.7 + // CreationDate: Sat Jan 1 00:00:00 2000 + // ModDate: Sat Jan 1 00:00:00 2000 + // Tagged: no + // Form: none + // Pages: 1 + // Encrypted: no + // Page size: 493.23 x 739.85 pts (rotated 0 degrees) + // MediaBox: 0.00 0.00 595.28 841.89 + // CropBox: 51.02 51.02 544.25 790.87 + // BleedBox: 51.02 51.02 544.25 790.87 + // TrimBox: 51.02 51.02 544.25 790.87 + // ArtBox: 51.02 51.02 544.25 790.87 + // File size: 1053 bytes + // Optimized: no + // PDF version: 1.3 + const ( + wd = 210 + ht = 297 + fontsize = 6 + boxmargin = 3 * fontsize + ) + pdf := gofpdf.New("P", "mm", "A4", "") // 210mm x 297mm + pdf.SetPageBox("crop", boxmargin, boxmargin, wd-2*boxmargin, ht-2*boxmargin) + pdf.SetFont("Arial", "", pdf.UnitToPointConvert(fontsize)) + pdf.AddPage() + pdf.MoveTo(fontsize, fontsize) + pdf.Write(fontsize, "This will be cropped from printed output") + pdf.MoveTo(boxmargin+fontsize, boxmargin+fontsize) + pdf.Write(fontsize, "This will be displayed in cropped output") + fileStr := example.Filename("Fpdf_PageBox") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_PageBox.pdf +} + +// ExampleFpdf_SubWrite demonstrates subscripted and superscripted text +// Adapted from http://www.fpdf.org/en/script/script61.php +func ExampleFpdf_SubWrite() { + + const ( + fontSize = 12 + halfX = 105 + ) + + pdf := gofpdf.New("P", "mm", "A4", "") // 210mm x 297mm + pdf.AddPage() + pdf.SetFont("Arial", "", fontSize) + _, lineHt := pdf.GetFontSize() + + pdf.Write(lineHt, "Hello World!") + pdf.SetX(halfX) + pdf.Write(lineHt, "This is standard text.\n") + pdf.Ln(lineHt * 2) + + pdf.SubWrite(10, "H", 33, 0, 0, "") + pdf.Write(10, "ello World!") + pdf.SetX(halfX) + pdf.Write(10, "This is text with a capital first letter.\n") + pdf.Ln(lineHt * 2) + + pdf.SubWrite(lineHt, "Y", 6, 0, 0, "") + pdf.Write(lineHt, "ou can also begin the sentence with a small letter. And word wrap also works if the line is too long, like this one is.") + pdf.SetX(halfX) + pdf.Write(lineHt, "This is text with a small first letter.\n") + pdf.Ln(lineHt * 2) + + pdf.Write(lineHt, "The world has a lot of km") + pdf.SubWrite(lineHt, "2", 6, 4, 0, "") + pdf.SetX(halfX) + pdf.Write(lineHt, "This is text with a superscripted letter.\n") + pdf.Ln(lineHt * 2) + + pdf.Write(lineHt, "The world has a lot of H") + pdf.SubWrite(lineHt, "2", 6, -3, 0, "") + pdf.Write(lineHt, "O") + pdf.SetX(halfX) + pdf.Write(lineHt, "This is text with a subscripted letter.\n") + + fileStr := example.Filename("Fpdf_SubWrite") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_SubWrite.pdf +} + +// 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 reproducible documents + pdf := gofpdf.New("L", "cm", "A4", "") + pdf.SetFont("Times", "", 12) + + var time []float64 + temperaturesFromSensors := make([][]float64, 5) + maxs := []float64{25, 41, 89, 62, 11} + for i := range temperaturesFromSensors { + temperaturesFromSensors[i] = make([]float64, 0) + } + + for i := 0.0; i < 100; i += 0.5 { + time = append(time, i) + for j, sensor := range temperaturesFromSensors { + dataValue := rnd.Float64() * maxs[j] + sensor = append(sensor, dataValue) + temperaturesFromSensors[j] = sensor + } + } + var graphs []gofpdf.GridType + var pageNums []int + xMax := time[len(time)-1] + for i := range temperaturesFromSensors { + //Create a new page and graph for each sensor we want to graph. + pdf.AddPage() + pdf.Ln(1) + //Custom label per sensor + pdf.WriteAligned(0, 0, "Temperature Sensor "+strconv.Itoa(i+1)+" (C) vs Time (min)", "C") + pdf.Ln(0.5) + graph := gofpdf.NewGrid(pdf.GetX(), pdf.GetY(), 20, 10) + graph.TickmarksContainX(0, xMax) + //Custom Y axis + graph.TickmarksContainY(0, maxs[i]) + graph.Grid(pdf) + //Save references and locations. + graphs = append(graphs, graph) + pageNums = append(pageNums, pdf.PageNo()) + } + // For each X, graph the Y in each sensor. + for i, currTime := range time { + for j, sensor := range temperaturesFromSensors { + pdf.SetPage(pageNums[j]) + graph := graphs[j] + temperature := sensor[i] + pdf.Circle(graph.X(currTime), graph.Y(temperature), 0.04, "D") + } + } + + fileStr := example.Filename("Fpdf_SetPage") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_SetPage.pdf +} + +// ExampleFpdf_SetFillColor demonstrates how graphic attributes are properly +// assigned within multiple transformations. See issue #234. +func ExampleFpdf_SetFillColor() { + pdf := gofpdf.New("P", "mm", "A4", "") + + pdf.AddPage() + pdf.SetFont("Arial", "", 8) + + draw := func(trX, trY float64) { + pdf.TransformBegin() + pdf.TransformTranslateX(trX) + pdf.TransformTranslateY(trY) + pdf.SetLineJoinStyle("round") + pdf.SetLineWidth(0.5) + pdf.SetDrawColor(128, 64, 0) + pdf.SetFillColor(255, 127, 0) + pdf.SetAlpha(0.5, "Normal") + pdf.SetDashPattern([]float64{5, 10}, 0) + pdf.Rect(0, 0, 40, 40, "FD") + pdf.SetFontSize(12) + pdf.SetXY(5, 5) + pdf.Write(0, "Test") + pdf.TransformEnd() + } + + draw(5, 5) + draw(50, 50) + + fileStr := example.Filename("Fpdf_SetFillColor") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_SetFillColor.pdf +} + +// ExampleFpdf_TransformRotate demonstrates how to rotate text within a header +// to make a watermark that appears on each page. +func ExampleFpdf_TransformRotate() { + + loremStr := lorem() + "\n\n" + pdf := gofpdf.New("P", "mm", "A4", "") + margin := 25.0 + pdf.SetMargins(margin, margin, margin) + + fontHt := 13.0 + lineHt := pdf.PointToUnitConvert(fontHt) + markFontHt := 50.0 + markLineHt := pdf.PointToUnitConvert(markFontHt) + markY := (297.0 - markLineHt) / 2.0 + ctrX := 210.0 / 2.0 + ctrY := 297.0 / 2.0 + + pdf.SetHeaderFunc(func() { + pdf.SetFont("Arial", "B", markFontHt) + pdf.SetTextColor(206, 216, 232) + pdf.SetXY(margin, markY) + pdf.TransformBegin() + pdf.TransformRotate(45, ctrX, ctrY) + pdf.CellFormat(0, markLineHt, "W A T E R M A R K D E M O", "", 0, "C", false, 0, "") + pdf.TransformEnd() + pdf.SetXY(margin, margin) + }) + + pdf.AddPage() + pdf.SetFont("Arial", "", 8) + for j := 0; j < 25; j++ { + pdf.MultiCell(0, lineHt, loremStr, "", "L", false) + } + + fileStr := example.Filename("Fpdf_RotateText") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_RotateText.pdf +} + +// 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() + + pdf.AddUTF8Font("dejavu", "", example.FontFile("DejaVuSansCondensed.ttf")) + pdf.AddUTF8Font("dejavu", "B", example.FontFile("DejaVuSansCondensed-Bold.ttf")) + pdf.AddUTF8Font("dejavu", "I", example.FontFile("DejaVuSansCondensed-Oblique.ttf")) + pdf.AddUTF8Font("dejavu", "BI", example.FontFile("DejaVuSansCondensed-BoldOblique.ttf")) + + 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) + + txtStr, err = ioutil.ReadFile(example.TextFile("utf-8test2.txt")) + if err == nil { + + 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) + + } + } + 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 + } + pdf.AddPage() + pdf.RoundedRectExt(10, 20, 40, 80, 4., 0., 20, 0., "FD") + + 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 +} + +// ExampleFpdf_SetTextRenderingMode demonstrates rendering modes in PDFs. +func ExampleFpdf_SetTextRenderingMode() { + + pdf := gofpdf.New("P", "mm", "A4", "") // 210mm x 297mm + pdf.AddPage() + fontSz := float64(16) + lineSz := pdf.PointToUnitConvert(fontSz) + pdf.SetFont("Times", "", fontSz) + pdf.Write(lineSz, "This document demonstrates various modes of text rendering. Search for \"Mode 3\" "+ + "to locate text that has been rendered invisibly. This selection can be copied "+ + "into the clipboard as usual and is useful for overlaying onto non-textual elements such "+ + "as images to make them searchable.\n\n") + fontSz = float64(125) + lineSz = pdf.PointToUnitConvert(fontSz) + pdf.SetFontSize(fontSz) + pdf.SetTextColor(170, 170, 190) + pdf.SetDrawColor(50, 60, 90) + + write := func(mode int) { + pdf.SetTextRenderingMode(mode) + pdf.CellFormat(210, lineSz, fmt.Sprintf("Mode %d", mode), "", 1, "", false, 0, "") + } + + for mode := 0; mode < 4; mode++ { + write(mode) + } + write(0) + + fileStr := example.Filename("Fpdf_TextRenderingMode") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_TextRenderingMode.pdf +} + +// TestIssue0316 addresses issue 316 in which AddUTF8FromBytes modifies its argument +// utf8bytes resulting in a panic if you generate two PDFs with the "same" font bytes. +func TestIssue0316(t *testing.T) { + pdf := gofpdf.New(gofpdf.OrientationPortrait, "mm", "A4", "") + pdf.AddPage() + fontBytes, _ := ioutil.ReadFile(example.FontFile("DejaVuSansCondensed.ttf")) + ofontBytes := append([]byte{}, fontBytes...) + pdf.AddUTF8FontFromBytes("dejavu", "", fontBytes) + pdf.SetFont("dejavu", "", 16) + pdf.Cell(40, 10, "Hello World!") + fileStr := example.Filename("TestIssue0316") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + pdf.AddPage() + if !bytes.Equal(fontBytes, ofontBytes) { + t.Fatal("Font data changed during pdf generation") + } +} + +func TestMultiCellUnsupportedChar(t *testing.T) { + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.AddPage() + fontBytes, _ := ioutil.ReadFile(example.FontFile("DejaVuSansCondensed.ttf")) + pdf.AddUTF8FontFromBytes("dejavu", "", fontBytes) + pdf.SetFont("dejavu", "", 16) + + defer func() { + if r := recover(); r != nil { + t.Errorf("unexpected panic: %v", r) + } + }() + + pdf.MultiCell(0, 5, "😀", "", "", false) + + fileStr := example.Filename("TestMultiCellUnsupportedChar") + pdf.OutputFileAndClose(fileStr) +} + +// ExampleFpdf_SetTextRenderingMode demonstrates embedding files in PDFs, +// at the top-level. +func ExampleFpdf_SetAttachments() { + pdf := gofpdf.New("P", "mm", "A4", "") + + // Global attachments + file, err := ioutil.ReadFile("grid.go") + if err != nil { + pdf.SetError(err) + } + a1 := gofpdf.Attachment{Content: file, Filename: "grid.go"} + file, err = ioutil.ReadFile("LICENSE") + if err != nil { + pdf.SetError(err) + } + a2 := gofpdf.Attachment{Content: file, Filename: "License"} + pdf.SetAttachments([]gofpdf.Attachment{a1, a2}) + + fileStr := example.Filename("Fpdf_EmbeddedFiles") + err = pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_EmbeddedFiles.pdf +} + +func ExampleFpdf_AddAttachmentAnnotation() { + pdf := gofpdf.New("P", "mm", "A4", "") + pdf.SetFont("Arial", "", 12) + pdf.AddPage() + + // Per page attachment + file, err := ioutil.ReadFile("grid.go") + if err != nil { + pdf.SetError(err) + } + a := gofpdf.Attachment{Content: file, Filename: "grid.go", Description: "Some amazing code !"} + + pdf.SetXY(5, 10) + pdf.Rect(2, 10, 50, 15, "D") + pdf.AddAttachmentAnnotation(&a, 2, 10, 50, 15) + pdf.Cell(50, 15, "A first link") + + pdf.SetXY(5, 80) + pdf.Rect(2, 80, 50, 15, "D") + pdf.AddAttachmentAnnotation(&a, 2, 80, 50, 15) + pdf.Cell(50, 15, "A second link (no copy)") + + fileStr := example.Filename("Fpdf_FileAnnotations") + err = pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_FileAnnotations.pdf +} + +func ExampleFpdf_SetModificationDate() { + // pdfinfo (from http://www.xpdfreader.com) reports the following for this example : + // ~ pdfinfo -box pdf/Fpdf_PageBox.pdf + // Producer: FPDF 1.7 + // CreationDate: Sat Jan 1 00:00:00 2000 + // ModDate: Sun Jan 2 10:22:30 2000 + pdf := gofpdf.New("", "", "", "") + pdf.AddPage() + pdf.SetModificationDate(time.Date(2000, 1, 2, 10, 22, 30, 0, time.UTC)) + fileStr := example.Filename("Fpdf_SetModificationDate") + err := pdf.OutputFileAndClose(fileStr) + example.Summary(err, fileStr) + // Output: + // Successfully generated pdf/Fpdf_SetModificationDate.pdf +} diff --git a/fpdftrans.go b/fpdftrans.go new file mode 100644 index 0000000..9cda397 --- /dev/null +++ b/fpdftrans.go @@ -0,0 +1,213 @@ +package gofpdf + +import ( + "fmt" + "math" +) + +// Routines in this file are translated from the work of Moritz Wagner and +// Andreas Würmser. + +// TransformMatrix is used for generalized transformations of text, drawings +// and images. +type TransformMatrix struct { + A, B, C, D, E, F float64 +} + +// TransformBegin sets up a transformation context for subsequent text, +// drawings and images. The typical usage is to immediately follow a call to +// this method with a call to one or more of the transformation methods such as +// TransformScale(), TransformSkew(), etc. This is followed by text, drawing or +// image output and finally a call to TransformEnd(). All transformation +// contexts must be properly ended prior to outputting the document. +func (f *Fpdf) TransformBegin() { + f.transformNest++ + f.out("q") +} + +// TransformScaleX scales the width of the following text, drawings and images. +// scaleWd is the percentage scaling factor. (x, y) is center of scaling. +// +// The TransformBegin() example demonstrates this method. +func (f *Fpdf) TransformScaleX(scaleWd, x, y float64) { + f.TransformScale(scaleWd, 100, x, y) +} + +// TransformScaleY scales the height of the following text, drawings and +// images. scaleHt is the percentage scaling factor. (x, y) is center of +// scaling. +// +// The TransformBegin() example demonstrates this method. +func (f *Fpdf) TransformScaleY(scaleHt, x, y float64) { + f.TransformScale(100, scaleHt, x, y) +} + +// TransformScaleXY uniformly scales the width and height of the following +// text, drawings and images. s is the percentage scaling factor for both width +// and height. (x, y) is center of scaling. +// +// The TransformBegin() example demonstrates this method. +func (f *Fpdf) TransformScaleXY(s, x, y float64) { + f.TransformScale(s, s, x, y) +} + +// TransformScale generally scales the following text, drawings and images. +// scaleWd and scaleHt are the percentage scaling factors for width and height. +// (x, y) is center of scaling. +// +// The TransformBegin() example demonstrates this method. +func (f *Fpdf) TransformScale(scaleWd, scaleHt, x, y float64) { + if scaleWd == 0 || scaleHt == 0 { + f.err = fmt.Errorf("scale factor cannot be zero") + return + } + y = (f.h - y) * f.k + x *= f.k + scaleWd /= 100 + scaleHt /= 100 + f.Transform(TransformMatrix{scaleWd, 0, 0, + scaleHt, x * (1 - scaleWd), y * (1 - scaleHt)}) +} + +// TransformMirrorHorizontal horizontally mirrors the following text, drawings +// and images. x is the axis of reflection. +// +// The TransformBegin() example demonstrates this method. +func (f *Fpdf) TransformMirrorHorizontal(x float64) { + f.TransformScale(-100, 100, x, f.y) +} + +// TransformMirrorVertical vertically mirrors the following text, drawings and +// images. y is the axis of reflection. +// +// The TransformBegin() example demonstrates this method. +func (f *Fpdf) TransformMirrorVertical(y float64) { + f.TransformScale(100, -100, f.x, y) +} + +// TransformMirrorPoint symmetrically mirrors the following text, drawings and +// images on the point specified by (x, y). +// +// The TransformBegin() example demonstrates this method. +func (f *Fpdf) TransformMirrorPoint(x, y float64) { + f.TransformScale(-100, -100, x, y) +} + +// TransformMirrorLine symmetrically mirrors the following text, drawings and +// images on the line defined by angle and the point (x, y). angles is +// specified in degrees and measured counter-clockwise from the 3 o'clock +// position. +// +// The TransformBegin() example demonstrates this method. +func (f *Fpdf) TransformMirrorLine(angle, x, y float64) { + f.TransformScale(-100, 100, x, y) + f.TransformRotate(-2*(angle-90), x, y) +} + +// TransformTranslateX moves the following text, drawings and images +// horizontally by the amount specified by tx. +// +// The TransformBegin() example demonstrates this method. +func (f *Fpdf) TransformTranslateX(tx float64) { + f.TransformTranslate(tx, 0) +} + +// TransformTranslateY moves the following text, drawings and images vertically +// by the amount specified by ty. +// +// The TransformBegin() example demonstrates this method. +func (f *Fpdf) TransformTranslateY(ty float64) { + f.TransformTranslate(0, ty) +} + +// TransformTranslate moves the following text, drawings and images +// horizontally and vertically by the amounts specified by tx and ty. +// +// The TransformBegin() example demonstrates this method. +func (f *Fpdf) TransformTranslate(tx, ty float64) { + f.Transform(TransformMatrix{1, 0, 0, 1, tx * f.k, -ty * f.k}) +} + +// TransformRotate rotates the following text, drawings and images around the +// center point (x, y). angle is specified in degrees and measured +// counter-clockwise from the 3 o'clock position. +// +// The TransformBegin() example demonstrates this method. +func (f *Fpdf) TransformRotate(angle, x, y float64) { + y = (f.h - y) * f.k + x *= f.k + angle = angle * math.Pi / 180 + var tm TransformMatrix + tm.A = math.Cos(angle) + tm.B = math.Sin(angle) + tm.C = -tm.B + tm.D = tm.A + tm.E = x + tm.B*y - tm.A*x + tm.F = y - tm.A*y - tm.B*x + f.Transform(tm) +} + +// TransformSkewX horizontally skews the following text, drawings and images +// keeping the point (x, y) stationary. angleX ranges from -90 degrees (skew to +// the left) to 90 degrees (skew to the right). +// +// The TransformBegin() example demonstrates this method. +func (f *Fpdf) TransformSkewX(angleX, x, y float64) { + f.TransformSkew(angleX, 0, x, y) +} + +// TransformSkewY vertically skews the following text, drawings and images +// keeping the point (x, y) stationary. angleY ranges from -90 degrees (skew to +// the bottom) to 90 degrees (skew to the top). +// +// The TransformBegin() example demonstrates this method. +func (f *Fpdf) TransformSkewY(angleY, x, y float64) { + f.TransformSkew(0, angleY, x, y) +} + +// TransformSkew generally skews the following text, drawings and images +// keeping the point (x, y) stationary. angleX ranges from -90 degrees (skew to +// the left) to 90 degrees (skew to the right). angleY ranges from -90 degrees +// (skew to the bottom) to 90 degrees (skew to the top). +// +// The TransformBegin() example demonstrates this method. +func (f *Fpdf) TransformSkew(angleX, angleY, x, y float64) { + if angleX <= -90 || angleX >= 90 || angleY <= -90 || angleY >= 90 { + f.err = fmt.Errorf("skew values must be between -90° and 90°") + return + } + x *= f.k + y = (f.h - y) * f.k + var tm TransformMatrix + tm.A = 1 + tm.B = math.Tan(angleY * math.Pi / 180) + tm.C = math.Tan(angleX * math.Pi / 180) + tm.D = 1 + tm.E = -tm.C * y + tm.F = -tm.B * x + f.Transform(tm) +} + +// Transform generally transforms the following text, drawings and images +// according to the specified matrix. It is typically easier to use the various +// methods such as TransformRotate() and TransformMirrorVertical() instead. +func (f *Fpdf) Transform(tm TransformMatrix) { + if f.transformNest > 0 { + f.outf("%.5f %.5f %.5f %.5f %.5f %.5f cm", + tm.A, tm.B, tm.C, tm.D, tm.E, tm.F) + } else if f.err == nil { + f.err = fmt.Errorf("transformation context is not active") + } +} + +// TransformEnd applies a transformation that was begun with a call to TransformBegin(). +// +// The TransformBegin() example demonstrates this method. +func (f *Fpdf) TransformEnd() { + if f.transformNest > 0 { + f.transformNest-- + f.out("Q") + } else { + f.err = fmt.Errorf("error attempting to end transformation operation out of sequence") + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..4a2cde9 --- /dev/null +++ b/go.mod @@ -0,0 +1,12 @@ +module github.com/jung-kurt/gofpdf + +go 1.12 + +require ( + github.com/boombuler/barcode v1.0.0 + github.com/phpdave11/gofpdi v1.0.7 + github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58 + golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a +) + +replace gofpdf => ./ diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..669c15a --- /dev/null +++ b/go.sum @@ -0,0 +1,20 @@ +github.com/boombuler/barcode v1.0.0 h1:s1TvRnXwL2xJRaccrdcBQMZxq6X7DvsMogtmJeHDdrc= +github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/phpdave11/gofpdi v1.0.7 h1:k2oy4yhkQopCK+qW8KjCla0iU2RpDow+QUDmH9DDt44= +github.com/phpdave11/gofpdi v1.0.7/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= +github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58 h1:nlG4Wa5+minh3S9LVFtNoY+GVRiudA2e3EVfcCi3RCA= +github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= +github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +golang.org/x/image v0.0.0-20190902063713-cb417be4ba39 h1:4dQcAORh9oYBwVSBVIkP489LUPC+f1HBkTYXgmqfR+o= +golang.org/x/image v0.0.0-20190902063713-cb417be4ba39/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a h1:gHevYm0pO4QUbwy8Dmdr01R5r1BuKtfYqRqF0h/Cbh0= +golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/grid.go b/grid.go new file mode 100644 index 0000000..aca8508 --- /dev/null +++ b/grid.go @@ -0,0 +1,446 @@ +package gofpdf + +import ( + "math" + "strconv" +) + +func unused(args ...interface{}) { +} + +// RGBType holds fields for red, green and blue color components (0..255) +type RGBType struct { + R, G, B int +} + +// RGBAType holds fields for red, green and blue color components (0..255) and +// an alpha transparency value (0..1) +type RGBAType struct { + R, G, B int + Alpha float64 +} + +// StateType holds various commonly used drawing values for convenient +// retrieval (StateGet()) and restore (Put) methods. +type StateType struct { + clrDraw, clrText, clrFill RGBType + lineWd float64 + fontSize float64 + alpha float64 + blendStr string + cellMargin float64 +} + +// StateGet returns a variable that contains common state values. +func StateGet(pdf *Fpdf) (st StateType) { + st.clrDraw.R, st.clrDraw.G, st.clrDraw.B = pdf.GetDrawColor() + st.clrFill.R, st.clrFill.G, st.clrFill.B = pdf.GetFillColor() + st.clrText.R, st.clrText.G, st.clrText.B = pdf.GetTextColor() + st.lineWd = pdf.GetLineWidth() + _, st.fontSize = pdf.GetFontSize() + st.alpha, st.blendStr = pdf.GetAlpha() + st.cellMargin = pdf.GetCellMargin() + return +} + +// Put sets the common state values contained in the state structure +// specified by st. +func (st StateType) Put(pdf *Fpdf) { + pdf.SetDrawColor(st.clrDraw.R, st.clrDraw.G, st.clrDraw.B) + pdf.SetFillColor(st.clrFill.R, st.clrFill.G, st.clrFill.B) + pdf.SetTextColor(st.clrText.R, st.clrText.G, st.clrText.B) + pdf.SetLineWidth(st.lineWd) + pdf.SetFontUnitSize(st.fontSize) + pdf.SetAlpha(st.alpha, st.blendStr) + pdf.SetCellMargin(st.cellMargin) +} + +// TickFormatFncType defines a callback for label drawing. +type TickFormatFncType func(val float64, precision int) string + +// defaultFormatter returns the string form of val with precision decimal places. +func defaultFormatter(val float64, precision int) string { + return strconv.FormatFloat(val, 'f', precision, 64) +} + +// GridType assists with the generation of graphs. It allows the application to +// work with logical data coordinates rather than page coordinates and assists +// with the drawing of a background grid. +type GridType struct { + // Chart coordinates in page units + x, y, w, h float64 + // X, Y, Wd, Ht float64 + // Slopes and intercepts scale data points to graph coordinates linearly + xm, xb, ym, yb float64 + // Tickmarks + xTicks, yTicks []float64 + // Labels are inside of graph boundary + XLabelIn, YLabelIn bool + // Labels on X-axis should be rotated + XLabelRotate bool + // Formatters; use nil to eliminate labels + XTickStr, YTickStr TickFormatFncType + // Subdivisions between tickmarks + XDiv, YDiv int + // Formatting precision + xPrecision, yPrecision int + // Line and label colors + ClrText, ClrMain, ClrSub RGBAType + // Line thickness + WdMain, WdSub float64 + // Label height in points + TextSize float64 +} + +// linear returns the slope and y-intercept of the straight line joining the +// two specified points. For scaling purposes, associate the arguments as +// follows: x1: observed low value, y1: desired low value, x2: observed high +// value, y2: desired high value. +func linear(x1, y1, x2, y2 float64) (slope, intercept float64) { + if x2 != x1 { + slope = (y2 - y1) / (x2 - x1) + intercept = y2 - x2*slope + } + return +} + +// linearTickmark returns the slope and intercept that will linearly map data +// values (the range of which is specified by the tickmark slice tm) to page +// values (the range of which is specified by lo and hi). +func linearTickmark(tm []float64, lo, hi float64) (slope, intercept float64) { + ln := len(tm) + if ln > 0 { + slope, intercept = linear(tm[0], lo, tm[ln-1], hi) + } + return +} + +// NewGrid returns a variable of type GridType that is initialized to draw on a +// rectangle of width w and height h with the upper left corner positioned at +// point (x, y). The coordinates are in page units, that is, the same as those +// specified in New(). +// +// The returned variable is initialized with a very simple default tickmark +// layout that ranges from 0 to 1 in both axes. Prior to calling Grid(), the +// application may establish a more suitable tickmark layout by calling the +// methods TickmarksContainX() and TickmarksContainY(). These methods bound the +// data range with appropriate boundaries and divisions. Alternatively, if the +// exact extent and divisions of the tickmark layout are known, the methods +// TickmarksExtentX() and TickmarksExtentY may be called instead. +func NewGrid(x, y, w, h float64) (grid GridType) { + grid.x = x + grid.y = y + grid.w = w + grid.h = h + grid.TextSize = 7 // Points + grid.TickmarksExtentX(0, 1, 1) + grid.TickmarksExtentY(0, 1, 1) + grid.XLabelIn = false + grid.YLabelIn = false + grid.XLabelRotate = false + grid.XDiv = 10 + grid.YDiv = 10 + grid.ClrText = RGBAType{R: 0, G: 0, B: 0, Alpha: 1} + grid.ClrMain = RGBAType{R: 128, G: 160, B: 128, Alpha: 1} + grid.ClrSub = RGBAType{R: 192, G: 224, B: 192, Alpha: 1} + grid.WdMain = 0.1 + grid.WdSub = 0.1 + grid.YTickStr = defaultFormatter + grid.XTickStr = defaultFormatter + return +} + +// WdAbs returns the absolute value of dataWd, specified in logical data units, +// that has been converted to the unit of measure specified in New(). +func (g GridType) WdAbs(dataWd float64) float64 { + return math.Abs(g.xm * dataWd) +} + +// Wd converts dataWd, specified in logical data units, to the unit of measure +// specified in New(). +func (g GridType) Wd(dataWd float64) float64 { + return g.xm * dataWd +} + +// XY converts dataX and dataY, specified in logical data units, to the X and Y +// position on the current page. +func (g GridType) XY(dataX, dataY float64) (x, y float64) { + return g.xm*dataX + g.xb, g.ym*dataY + g.yb +} + +// Pos returns the point, in page units, indicated by the relative positions +// xRel and yRel. These are values between 0 and 1. xRel specifies the relative +// position between the grid's left and right edges. yRel specifies the +// relative position between the grid's bottom and top edges. +func (g GridType) Pos(xRel, yRel float64) (x, y float64) { + x = g.w*xRel + g.x + y = g.h*(1-yRel) + g.y + return +} + +// X converts dataX, specified in logical data units, to the X position on the +// current page. +func (g GridType) X(dataX float64) float64 { + return g.xm*dataX + g.xb +} + +// HtAbs returns the absolute value of dataHt, specified in logical data units, +// that has been converted to the unit of measure specified in New(). +func (g GridType) HtAbs(dataHt float64) float64 { + return math.Abs(g.ym * dataHt) +} + +// Ht converts dataHt, specified in logical data units, to the unit of measure +// specified in New(). +func (g GridType) Ht(dataHt float64) float64 { + return g.ym * dataHt +} + +// Y converts dataY, specified in logical data units, to the Y position on the +// current page. +func (g GridType) Y(dataY float64) float64 { + return g.ym*dataY + g.yb +} + +// XRange returns the minimum and maximum values for the current tickmark +// sequence. These correspond to the data values of the graph's left and right +// edges. +func (g GridType) XRange() (min, max float64) { + min = g.xTicks[0] + max = g.xTicks[len(g.xTicks)-1] + return +} + +// YRange returns the minimum and maximum values for the current tickmark +// sequence. These correspond to the data values of the graph's bottom and top +// edges. +func (g GridType) YRange() (min, max float64) { + min = g.yTicks[0] + max = g.yTicks[len(g.yTicks)-1] + return +} + +// TickmarksContainX sets the tickmarks to be shown by Grid() in the horizontal +// dimension. The argument min and max specify the minimum and maximum values +// to be contained within the grid. The tickmark values that are generated are +// suitable for general purpose graphs. +// +// See TickmarkExtentX() for an alternative to this method to be used when the +// exact values of the tickmarks are to be set by the application. +func (g *GridType) TickmarksContainX(min, max float64) { + g.xTicks, g.xPrecision = Tickmarks(min, max) + g.xm, g.xb = linearTickmark(g.xTicks, g.x, g.x+g.w) +} + +// TickmarksContainY sets the tickmarks to be shown by Grid() in the vertical +// dimension. The argument min and max specify the minimum and maximum values +// to be contained within the grid. The tickmark values that are generated are +// suitable for general purpose graphs. +// +// See TickmarkExtentY() for an alternative to this method to be used when the +// exact values of the tickmarks are to be set by the application. +func (g *GridType) TickmarksContainY(min, max float64) { + g.yTicks, g.yPrecision = Tickmarks(min, max) + g.ym, g.yb = linearTickmark(g.yTicks, g.y+g.h, g.y) +} + +func extent(min, div float64, count int) (tm []float64, precision int) { + tm = make([]float64, count+1) + for j := 0; j <= count; j++ { + tm[j] = min + min += div + } + precision = TickmarkPrecision(div) + return +} + +// TickmarksExtentX sets the tickmarks to be shown by Grid() in the horizontal +// dimension. count specifies number of major tickmark subdivisions to be +// graphed. min specifies the leftmost data value. div specifies, in data +// units, the extent of each major tickmark subdivision. +// +// See TickmarkContainX() for an alternative to this method to be used when +// viewer-friendly tickmarks are to be determined automatically. +func (g *GridType) TickmarksExtentX(min, div float64, count int) { + g.xTicks, g.xPrecision = extent(min, div, count) + g.xm, g.xb = linearTickmark(g.xTicks, g.x, g.x+g.w) +} + +// TickmarksExtentY sets the tickmarks to be shown by Grid() in the vertical +// dimension. count specifies number of major tickmark subdivisions to be +// graphed. min specifies the bottommost data value. div specifies, in data +// units, the extent of each major tickmark subdivision. +// +// See TickmarkContainY() for an alternative to this method to be used when +// viewer-friendly tickmarks are to be determined automatically. +func (g *GridType) TickmarksExtentY(min, div float64, count int) { + g.yTicks, g.yPrecision = extent(min, div, count) + g.ym, g.yb = linearTickmark(g.yTicks, g.y+g.h, g.y) +} + +// func (g *GridType) SetXExtent(dataLf, paperLf, dataRt, paperRt float64) { +// g.xm, g.xb = linear(dataLf, paperLf, dataRt, paperRt) +// } + +// func (g *GridType) SetYExtent(dataTp, paperTp, dataBt, paperBt float64) { +// g.ym, g.yb = linear(dataTp, paperTp, dataBt, paperBt) +// } + +func lineAttr(pdf *Fpdf, clr RGBAType, lineWd float64) { + pdf.SetLineWidth(lineWd) + pdf.SetAlpha(clr.Alpha, "Normal") + pdf.SetDrawColor(clr.R, clr.G, clr.B) +} + +// Grid generates a graph-paperlike set of grid lines on the current page. +func (g GridType) Grid(pdf *Fpdf) { + var st StateType + var yLen, xLen int + var textSz, halfTextSz, yMin, yMax, xMin, xMax, yDiv, xDiv float64 + var str string + var strOfs, strWd, tp, bt, lf, rt, drawX, drawY float64 + + xLen = len(g.xTicks) + yLen = len(g.yTicks) + if xLen > 1 && yLen > 1 { + + st = StateGet(pdf) + + line := func(x1, y1, x2, y2 float64, heavy bool) { + if heavy { + lineAttr(pdf, g.ClrMain, g.WdMain) + } else { + lineAttr(pdf, g.ClrSub, g.WdSub) + } + pdf.Line(x1, y1, x2, y2) + } + + textSz = pdf.PointToUnitConvert(g.TextSize) + halfTextSz = textSz / 2 + + pdf.SetAutoPageBreak(false, 0) + pdf.SetFontUnitSize(textSz) + strOfs = pdf.GetStringWidth("0") + pdf.SetFillColor(255, 255, 255) + pdf.SetCellMargin(0) + + xMin = g.xTicks[0] + xMax = g.xTicks[xLen-1] + + yMin = g.yTicks[0] + yMax = g.yTicks[yLen-1] + + lf = g.X(xMin) + rt = g.X(xMax) + bt = g.Y(yMin) + tp = g.Y(yMax) + + // Verticals along X axis + xDiv = g.xTicks[1] - g.xTicks[0] + if g.XDiv > 0 { + xDiv = xDiv / float64(g.XDiv) + } + xDiv = g.Wd(xDiv) + for j, x := range g.xTicks { + drawX = g.X(x) + line(drawX, tp, drawX, bt, true) + if j < xLen-1 { + for k := 1; k < g.XDiv; k++ { + drawX += xDiv + line(drawX, tp, drawX, bt, false) + } + } + } + + // Horizontals along Y axis + yDiv = g.yTicks[1] - g.yTicks[0] + if g.YDiv > 0 { + yDiv = yDiv / float64(g.YDiv) + } + yDiv = g.Ht(yDiv) + for j, y := range g.yTicks { + drawY = g.Y(y) + line(lf, drawY, rt, drawY, true) + if j < yLen-1 { + for k := 1; k < g.YDiv; k++ { + drawY += yDiv + line(lf, drawY, rt, drawY, false) + } + } + } + + // X labels + if g.XTickStr != nil { + drawY = bt + for _, x := range g.xTicks { + str = g.XTickStr(x, g.xPrecision) + strWd = pdf.GetStringWidth(str) + drawX = g.X(x) + if g.XLabelRotate { + pdf.TransformBegin() + pdf.TransformRotate(90, drawX, drawY) + if g.XLabelIn { + pdf.SetXY(drawX+strOfs, drawY-halfTextSz) + } else { + pdf.SetXY(drawX-strOfs-strWd, drawY-halfTextSz) + } + pdf.CellFormat(strWd, textSz, str, "", 0, "L", true, 0, "") + pdf.TransformEnd() + } else { + drawX -= strWd / 2.0 + if g.XLabelIn { + pdf.SetXY(drawX, drawY-textSz-strOfs) + } else { + pdf.SetXY(drawX, drawY+strOfs) + } + pdf.CellFormat(strWd, textSz, str, "", 0, "L", true, 0, "") + } + } + } + + // Y labels + if g.YTickStr != nil { + drawX = lf + for _, y := range g.yTicks { + // str = strconv.FormatFloat(y, 'f', g.yPrecision, 64) + str = g.YTickStr(y, g.yPrecision) + strWd = pdf.GetStringWidth(str) + if g.YLabelIn { + pdf.SetXY(drawX+strOfs, g.Y(y)-halfTextSz) + } else { + pdf.SetXY(lf-strOfs-strWd, g.Y(y)-halfTextSz) + } + pdf.CellFormat(strWd, textSz, str, "", 0, "L", true, 0, "") + } + } + + // Restore drawing attributes + st.Put(pdf) + + } + +} + +// Plot plots a series of count line segments from xMin to xMax. It repeatedly +// calls fnc(x) to retrieve the y value associate with x. The currently +// selected line drawing attributes are used. +func (g GridType) Plot(pdf *Fpdf, xMin, xMax float64, count int, fnc func(x float64) (y float64)) { + if count > 0 { + var x, delta, drawX0, drawY0, drawX1, drawY1 float64 + delta = (xMax - xMin) / float64(count) + x = xMin + for j := 0; j <= count; j++ { + if j == 0 { + drawX1 = g.X(x) + drawY1 = g.Y(fnc(x)) + } else { + pdf.Line(drawX0, drawY0, drawX1, drawY1) + } + x += delta + drawX0 = drawX1 + drawY0 = drawY1 + drawX1 = g.X(x) + drawY1 = g.Y(fnc(x)) + } + } +} diff --git a/htmlbasic.go b/htmlbasic.go new file mode 100644 index 0000000..9e4eca4 --- /dev/null +++ b/htmlbasic.go @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2014 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf + +import ( + "regexp" + "strings" +) + +// HTMLBasicSegmentType defines a segment of literal text in which the current +// attributes do not vary, or an open tag or a close tag. +type HTMLBasicSegmentType struct { + Cat byte // 'O' open tag, 'C' close tag, 'T' text + Str string // Literal text unchanged, tags are lower case + Attr map[string]string // Attribute keys are lower case +} + +// HTMLBasicTokenize returns a list of HTML tags and literal elements. This is +// done with regular expressions, so the result is only marginally better than +// useless. +func HTMLBasicTokenize(htmlStr string) (list []HTMLBasicSegmentType) { + // This routine is adapted from http://www.fpdf.org/ + list = make([]HTMLBasicSegmentType, 0, 16) + htmlStr = strings.Replace(htmlStr, "\n", " ", -1) + htmlStr = strings.Replace(htmlStr, "\r", "", -1) + tagRe, _ := regexp.Compile(`(?U)<.*>`) + attrRe, _ := regexp.Compile(`([^=]+)=["']?([^"']+)`) + capList := tagRe.FindAllStringIndex(htmlStr, -1) + if capList != nil { + var seg HTMLBasicSegmentType + var parts []string + pos := 0 + for _, cap := range capList { + if pos < cap[0] { + seg.Cat = 'T' + seg.Str = htmlStr[pos:cap[0]] + seg.Attr = nil + list = append(list, seg) + } + if htmlStr[cap[0]+1] == '/' { + seg.Cat = 'C' + seg.Str = strings.ToLower(htmlStr[cap[0]+2 : cap[1]-1]) + seg.Attr = nil + list = append(list, seg) + } else { + // Extract attributes + parts = strings.Split(htmlStr[cap[0]+1:cap[1]-1], " ") + if len(parts) > 0 { + for j, part := range parts { + if j == 0 { + seg.Cat = 'O' + seg.Str = strings.ToLower(parts[0]) + seg.Attr = make(map[string]string) + } else { + attrList := attrRe.FindAllStringSubmatch(part, -1) + if attrList != nil { + for _, attr := range attrList { + seg.Attr[strings.ToLower(attr[1])] = attr[2] + } + } + } + } + list = append(list, seg) + } + } + pos = cap[1] + } + if len(htmlStr) > pos { + seg.Cat = 'T' + seg.Str = htmlStr[pos:] + seg.Attr = nil + list = append(list, seg) + } + } else { + list = append(list, HTMLBasicSegmentType{Cat: 'T', Str: htmlStr, Attr: nil}) + } + return +} + +// HTMLBasicType is used for rendering a very basic subset of HTML. It supports +// only hyperlinks and bold, italic and underscore attributes. In the Link +// structure, the ClrR, ClrG and ClrB fields (0 through 255) define the color +// of hyperlinks. The Bold, Italic and Underscore values define the hyperlink +// style. +type HTMLBasicType struct { + pdf *Fpdf + Link struct { + ClrR, ClrG, ClrB int + Bold, Italic, Underscore bool + } +} + +// HTMLBasicNew returns an instance that facilitates writing basic HTML in the +// specified PDF file. +func (f *Fpdf) HTMLBasicNew() (html HTMLBasicType) { + html.pdf = f + html.Link.ClrR, html.Link.ClrG, html.Link.ClrB = 0, 0, 128 + html.Link.Bold, html.Link.Italic, html.Link.Underscore = false, false, true + return +} + +// Write prints text from the current position using the currently selected +// font. See HTMLBasicNew() to create a receiver that is associated with the +// PDF document instance. The text can be encoded with a basic subset of HTML +// that includes hyperlinks and tags for italic (I), bold (B), underscore +// (U) and center (CENTER) attributes. When the right margin is reached a line +// break occurs and text continues from the left margin. Upon method exit, the +// current position is left at the end of the text. +// +// lineHt indicates the line height in the unit of measure specified in New(). +func (html *HTMLBasicType) Write(lineHt float64, htmlStr string) { + var boldLvl, italicLvl, underscoreLvl, linkBold, linkItalic, linkUnderscore int + var textR, textG, textB = html.pdf.GetTextColor() + var hrefStr string + if html.Link.Bold { + linkBold = 1 + } + if html.Link.Italic { + linkItalic = 1 + } + if html.Link.Underscore { + linkUnderscore = 1 + } + setStyle := func(boldAdj, italicAdj, underscoreAdj int) { + styleStr := "" + boldLvl += boldAdj + if boldLvl > 0 { + styleStr += "B" + } + italicLvl += italicAdj + if italicLvl > 0 { + styleStr += "I" + } + underscoreLvl += underscoreAdj + if underscoreLvl > 0 { + styleStr += "U" + } + html.pdf.SetFont("", styleStr, 0) + } + putLink := func(urlStr, txtStr string) { + // Put a hyperlink + html.pdf.SetTextColor(html.Link.ClrR, html.Link.ClrG, html.Link.ClrB) + setStyle(linkBold, linkItalic, linkUnderscore) + html.pdf.WriteLinkString(lineHt, txtStr, urlStr) + setStyle(-linkBold, -linkItalic, -linkUnderscore) + html.pdf.SetTextColor(textR, textG, textB) + } + list := HTMLBasicTokenize(htmlStr) + var ok bool + alignStr := "L" + for _, el := range list { + switch el.Cat { + case 'T': + if len(hrefStr) > 0 { + putLink(hrefStr, el.Str) + hrefStr = "" + } else { + if alignStr == "C" || alignStr == "R" { + html.pdf.WriteAligned(0, lineHt, el.Str, alignStr) + } else { + html.pdf.Write(lineHt, el.Str) + } + } + case 'O': + switch el.Str { + case "b": + setStyle(1, 0, 0) + case "i": + setStyle(0, 1, 0) + case "u": + setStyle(0, 0, 1) + case "br": + html.pdf.Ln(lineHt) + case "center": + html.pdf.Ln(lineHt) + alignStr = "C" + case "right": + html.pdf.Ln(lineHt) + alignStr = "R" + case "left": + html.pdf.Ln(lineHt) + alignStr = "L" + case "a": + hrefStr, ok = el.Attr["href"] + if !ok { + hrefStr = "" + } + } + case 'C': + switch el.Str { + case "b": + setStyle(-1, 0, 0) + case "i": + setStyle(0, -1, 0) + case "u": + setStyle(0, 0, -1) + case "center": + html.pdf.Ln(lineHt) + alignStr = "L" + case "right": + html.pdf.Ln(lineHt) + alignStr = "L" + } + } + } +} diff --git a/image/doc.png b/image/doc.png new file mode 100644 index 0000000..8260776 Binary files /dev/null and b/image/doc.png differ diff --git a/image/doc.svg b/image/doc.svg new file mode 100644 index 0000000..1543a7e --- /dev/null +++ b/image/doc.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + godoc + godoc + + reference + reference + + diff --git a/image/fpdf.png b/image/fpdf.png new file mode 100644 index 0000000..b8a570f Binary files /dev/null and b/image/fpdf.png differ diff --git a/image/gofpdf.png b/image/gofpdf.png new file mode 100644 index 0000000..29d8401 Binary files /dev/null and b/image/gofpdf.png differ diff --git a/image/golang-gopher.png b/image/golang-gopher.png new file mode 100644 index 0000000..3626d01 Binary files /dev/null and b/image/golang-gopher.png differ diff --git a/image/golang-gopher.tiff b/image/golang-gopher.tiff new file mode 100644 index 0000000..d5d1600 Binary files /dev/null and b/image/golang-gopher.tiff differ diff --git a/image/logo-gray.png b/image/logo-gray.png new file mode 100644 index 0000000..addc3a3 Binary files /dev/null and b/image/logo-gray.png differ diff --git a/image/logo-progressive.jpg b/image/logo-progressive.jpg new file mode 100644 index 0000000..add0a8f Binary files /dev/null and b/image/logo-progressive.jpg differ diff --git a/image/logo-rgb.png b/image/logo-rgb.png new file mode 100644 index 0000000..81140e2 Binary files /dev/null and b/image/logo-rgb.png differ diff --git a/image/logo.gif b/image/logo.gif new file mode 100644 index 0000000..85d6cf0 Binary files /dev/null and b/image/logo.gif differ diff --git a/image/logo.jpg b/image/logo.jpg new file mode 100644 index 0000000..60a144e Binary files /dev/null and b/image/logo.jpg differ diff --git a/image/logo.png b/image/logo.png new file mode 100644 index 0000000..284a007 Binary files /dev/null and b/image/logo.png differ diff --git a/image/logo_gofpdf.jpg b/image/logo_gofpdf.jpg new file mode 100644 index 0000000..9a59747 Binary files /dev/null and b/image/logo_gofpdf.jpg differ diff --git a/image/mit.png b/image/mit.png new file mode 100644 index 0000000..153eca1 Binary files /dev/null and b/image/mit.png differ diff --git a/image/mit.svg b/image/mit.svg new file mode 100644 index 0000000..c8ed53f --- /dev/null +++ b/image/mit.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + license + license + + MIT + MIT + + diff --git a/image/signature.svg b/image/signature.svg new file mode 100644 index 0000000..956c3c6 --- /dev/null +++ b/image/signature.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/image/sweden.png b/image/sweden.png new file mode 100644 index 0000000..22f6e7e Binary files /dev/null and b/image/sweden.png differ diff --git a/internal/example/example.go b/internal/example/example.go new file mode 100644 index 0000000..953bf31 --- /dev/null +++ b/internal/example/example.go @@ -0,0 +1,143 @@ +// Copyright (c) 2015 Kurt Jung (Gmail: kurt.w.jung) +// +// Permission to use, copy, modify, and distribute this software for any purpose +// with or without fee is hereby granted, provided that the above copyright notice +// and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +// FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +// PERFORMANCE OF THIS SOFTWARE. + +// Package example provides some helper routines for the test packages of +// gofpdf and its various contributed packages located beneath the contrib +// directory. +package example + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "time" + + "github.com/jung-kurt/gofpdf" +) + +var gofpdfDir string + +func init() { + setRoot() + gofpdf.SetDefaultCompression(false) + gofpdf.SetDefaultCatalogSort(true) + gofpdf.SetDefaultCreationDate(time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)) + gofpdf.SetDefaultModificationDate(time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)) +} + +// setRoot assigns the relative path to the gofpdfDir directory based on current working +// directory +func setRoot() { + wdStr, err := os.Getwd() + if err == nil { + gofpdfDir = "" + list := strings.Split(filepath.ToSlash(wdStr), "/") + for j := len(list) - 1; j >= 0 && list[j] != "gofpdf"; j-- { + gofpdfDir = filepath.Join(gofpdfDir, "..") + } + } else { + panic(err) + } +} + +// ImageFile returns a qualified filename in which the path to the image +// directory is prepended to the specified filename. +func ImageFile(fileStr string) string { + return filepath.Join(gofpdfDir, "image", fileStr) +} + +// FontDir returns the path to the font directory. +func FontDir() string { + return filepath.Join(gofpdfDir, "font") +} + +// FontFile returns a qualified filename in which the path to the font +// directory is prepended to the specified filename. +func FontFile(fileStr string) string { + return filepath.Join(FontDir(), fileStr) +} + +// TextFile returns a qualified filename in which the path to the text +// directory is prepended to the specified filename. +func TextFile(fileStr string) string { + return filepath.Join(gofpdfDir, "text", fileStr) +} + +// PdfDir returns the path to the PDF output directory. +func PdfDir() string { + return filepath.Join(gofpdfDir, "pdf") +} + +// PdfFile returns a qualified filename in which the path to the PDF output +// directory is prepended to the specified filename. +func PdfFile(fileStr string) string { + return filepath.Join(PdfDir(), fileStr) +} + +// Filename returns a qualified filename in which the example PDF directory +// path is prepended and the suffix ".pdf" is appended to the specified +// filename. +func Filename(baseStr string) string { + return PdfFile(baseStr + ".pdf") +} + +// referenceCompare compares the specified file with the file's reference copy +// located in the 'reference' subdirectory. All bytes of the two files are +// compared except for the value of the /CreationDate field in the PDF. This +// function succeeds if both files are equivalent except for their +// /CreationDate values or if the reference file does not exist. +func referenceCompare(fileStr string) (err error) { + var refFileStr, refDirStr, dirStr, baseFileStr string + dirStr, baseFileStr = filepath.Split(fileStr) + refDirStr = filepath.Join(dirStr, "reference") + err = os.MkdirAll(refDirStr, 0755) + if err == nil { + refFileStr = filepath.Join(refDirStr, baseFileStr) + err = gofpdf.ComparePDFFiles(fileStr, refFileStr, false) + } + return +} + +// Summary generates a predictable report for use by test examples. If the +// specified error is nil, the filename delimiters are normalized and the +// filename printed to standard output with a success message. If the specified +// error is not nil, its String() value is printed to standard output. +func Summary(err error, fileStr string) { + if err == nil { + fileStr = filepath.ToSlash(fileStr) + fmt.Printf("Successfully generated %s\n", fileStr) + } else { + fmt.Println(err) + } +} + +// SummaryCompare generates a predictable report for use by test examples. If +// the specified error is nil, the generated file is compared with a reference +// copy for byte-for-byte equality. If the files match, then the filename +// delimiters are normalized and the filename printed to standard output with a +// success message. If the files do not match, this condition is reported on +// standard output. If the specified error is not nil, its String() value is +// printed to standard output. +func SummaryCompare(err error, fileStr string) { + if err == nil { + err = referenceCompare(fileStr) + } + if err == nil { + fileStr = filepath.ToSlash(fileStr) + fmt.Printf("Successfully generated %s\n", fileStr) + } else { + fmt.Println(err) + } +} diff --git a/internal/example/example_test.go b/internal/example/example_test.go new file mode 100644 index 0000000..b985778 --- /dev/null +++ b/internal/example/example_test.go @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2015 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package example_test + +import ( + "errors" + + "github.com/jung-kurt/gofpdf/internal/example" +) + +// ExampleFilename tests the Filename() and Summary() functions. +func ExampleFilename() { + fileStr := example.Filename("example") + example.Summary(errors.New("printer on fire"), fileStr) + // Output: + // printer on fire +} diff --git a/internal/files/bin/Makefile b/internal/files/bin/Makefile new file mode 100644 index 0000000..3aff64c --- /dev/null +++ b/internal/files/bin/Makefile @@ -0,0 +1,24 @@ +TRG= ../files.go +JSON= ../../../font/calligra.json +Z= ../../../font/calligra.z + +${TRG} : ${JSON} ${Z} ./bin + echo "package files" > ${TRG} + echo "" >> ${TRG} + echo "// CalligraJson is embedded byte slice for calligra.json" >> ${TRG} + echo "var CalligraJson = []byte{" >> ${TRG} + ./bin < ${JSON} >> ${TRG} + echo "}" >> ${TRG} + echo "" >> ${TRG} + echo "// CalligraZ is embedded byte slice for calligra.z" >> ${TRG} + echo "var CalligraZ = []byte{" >> ${TRG} + ./bin < ${Z} >> ${TRG} + echo "}" >> ${TRG} + gofmt -s -w ${TRG} + +./bin : bin.go + go build -v + +clean : + rm -f ./bin ${TRG} + diff --git a/internal/files/bin/bin.go b/internal/files/bin/bin.go new file mode 100644 index 0000000..5b56313 --- /dev/null +++ b/internal/files/bin/bin.go @@ -0,0 +1,28 @@ +package main + +import ( + "fmt" + "io/ioutil" + "os" +) + +func main() { + var buf []byte + var pos int + var b byte + var err error + buf, err = ioutil.ReadAll(os.Stdin) + if err == nil { + for _, b = range buf { + fmt.Printf("0x%02X, ", b) + pos++ + if pos >= 16 { + fmt.Println("") + pos = 0 + } + } + } + if err != nil { + fmt.Fprintf(os.Stderr, "%s\n", err) + } +} diff --git a/internal/files/files.go b/internal/files/files.go new file mode 100644 index 0000000..7f73413 --- /dev/null +++ b/internal/files/files.go @@ -0,0 +1,1691 @@ +package files + +// CalligraJson is embedded byte slice for calligra.json +var CalligraJson = []byte{ + 0x7B, 0x22, 0x54, 0x70, 0x22, 0x3A, 0x22, 0x54, 0x72, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, + 0x2C, 0x22, 0x4E, 0x61, 0x6D, 0x65, 0x22, 0x3A, 0x22, 0x43, 0x61, 0x6C, 0x6C, 0x69, 0x67, 0x72, + 0x61, 0x70, 0x68, 0x65, 0x72, 0x52, 0x65, 0x67, 0x75, 0x6C, 0x61, 0x72, 0x22, 0x2C, 0x22, 0x44, + 0x65, 0x73, 0x63, 0x22, 0x3A, 0x7B, 0x22, 0x41, 0x73, 0x63, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x38, + 0x39, 0x39, 0x2C, 0x22, 0x44, 0x65, 0x73, 0x63, 0x65, 0x6E, 0x74, 0x22, 0x3A, 0x2D, 0x32, 0x33, + 0x34, 0x2C, 0x22, 0x43, 0x61, 0x70, 0x48, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x3A, 0x38, 0x39, + 0x39, 0x2C, 0x22, 0x46, 0x6C, 0x61, 0x67, 0x73, 0x22, 0x3A, 0x33, 0x32, 0x2C, 0x22, 0x46, 0x6F, + 0x6E, 0x74, 0x42, 0x42, 0x6F, 0x78, 0x22, 0x3A, 0x7B, 0x22, 0x58, 0x6D, 0x69, 0x6E, 0x22, 0x3A, + 0x2D, 0x31, 0x37, 0x33, 0x2C, 0x22, 0x59, 0x6D, 0x69, 0x6E, 0x22, 0x3A, 0x2D, 0x32, 0x33, 0x34, + 0x2C, 0x22, 0x58, 0x6D, 0x61, 0x78, 0x22, 0x3A, 0x31, 0x33, 0x32, 0x38, 0x2C, 0x22, 0x59, 0x6D, + 0x61, 0x78, 0x22, 0x3A, 0x38, 0x39, 0x39, 0x7D, 0x2C, 0x22, 0x49, 0x74, 0x61, 0x6C, 0x69, 0x63, + 0x41, 0x6E, 0x67, 0x6C, 0x65, 0x22, 0x3A, 0x30, 0x2C, 0x22, 0x53, 0x74, 0x65, 0x6D, 0x56, 0x22, + 0x3A, 0x37, 0x30, 0x2C, 0x22, 0x4D, 0x69, 0x73, 0x73, 0x69, 0x6E, 0x67, 0x57, 0x69, 0x64, 0x74, + 0x68, 0x22, 0x3A, 0x38, 0x30, 0x30, 0x7D, 0x2C, 0x22, 0x55, 0x70, 0x22, 0x3A, 0x2D, 0x32, 0x30, + 0x30, 0x2C, 0x22, 0x55, 0x74, 0x22, 0x3A, 0x32, 0x30, 0x2C, 0x22, 0x43, 0x77, 0x22, 0x3A, 0x5B, + 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, + 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, + 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, + 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, + 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, + 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, + 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, + 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, + 0x32, 0x38, 0x32, 0x2C, 0x33, 0x32, 0x34, 0x2C, 0x34, 0x30, 0x35, 0x2C, 0x35, 0x38, 0x34, 0x2C, + 0x36, 0x33, 0x32, 0x2C, 0x39, 0x38, 0x30, 0x2C, 0x37, 0x37, 0x36, 0x2C, 0x32, 0x35, 0x39, 0x2C, + 0x32, 0x39, 0x39, 0x2C, 0x32, 0x39, 0x39, 0x2C, 0x33, 0x37, 0x37, 0x2C, 0x36, 0x30, 0x30, 0x2C, + 0x32, 0x35, 0x39, 0x2C, 0x34, 0x33, 0x32, 0x2C, 0x32, 0x35, 0x34, 0x2C, 0x35, 0x39, 0x37, 0x2C, + 0x35, 0x32, 0x39, 0x2C, 0x32, 0x39, 0x38, 0x2C, 0x34, 0x35, 0x31, 0x2C, 0x33, 0x35, 0x39, 0x2C, + 0x35, 0x32, 0x35, 0x2C, 0x34, 0x32, 0x33, 0x2C, 0x34, 0x36, 0x34, 0x2C, 0x34, 0x31, 0x37, 0x2C, + 0x34, 0x35, 0x37, 0x2C, 0x34, 0x37, 0x39, 0x2C, 0x32, 0x37, 0x35, 0x2C, 0x32, 0x38, 0x32, 0x2C, + 0x36, 0x30, 0x30, 0x2C, 0x36, 0x30, 0x30, 0x2C, 0x36, 0x30, 0x30, 0x2C, 0x35, 0x30, 0x31, 0x2C, + 0x38, 0x30, 0x30, 0x2C, 0x37, 0x34, 0x33, 0x2C, 0x36, 0x33, 0x36, 0x2C, 0x35, 0x39, 0x38, 0x2C, + 0x37, 0x31, 0x32, 0x2C, 0x36, 0x30, 0x38, 0x2C, 0x35, 0x36, 0x32, 0x2C, 0x36, 0x38, 0x30, 0x2C, + 0x37, 0x35, 0x36, 0x2C, 0x33, 0x30, 0x38, 0x2C, 0x33, 0x31, 0x34, 0x2C, 0x36, 0x37, 0x36, 0x2C, + 0x35, 0x35, 0x32, 0x2C, 0x31, 0x30, 0x34, 0x31, 0x2C, 0x38, 0x31, 0x37, 0x2C, 0x37, 0x32, 0x39, + 0x2C, 0x35, 0x36, 0x39, 0x2C, 0x36, 0x39, 0x38, 0x2C, 0x36, 0x37, 0x34, 0x2C, 0x36, 0x31, 0x38, + 0x2C, 0x36, 0x37, 0x33, 0x2C, 0x38, 0x30, 0x35, 0x2C, 0x37, 0x35, 0x33, 0x2C, 0x31, 0x32, 0x33, + 0x38, 0x2C, 0x37, 0x31, 0x36, 0x2C, 0x37, 0x35, 0x34, 0x2C, 0x35, 0x39, 0x39, 0x2C, 0x33, 0x31, + 0x35, 0x2C, 0x34, 0x36, 0x33, 0x2C, 0x33, 0x31, 0x35, 0x2C, 0x36, 0x30, 0x30, 0x2C, 0x35, 0x34, + 0x37, 0x2C, 0x32, 0x37, 0x38, 0x2C, 0x35, 0x38, 0x31, 0x2C, 0x35, 0x36, 0x34, 0x2C, 0x34, 0x34, + 0x30, 0x2C, 0x35, 0x37, 0x31, 0x2C, 0x34, 0x35, 0x30, 0x2C, 0x33, 0x34, 0x37, 0x2C, 0x36, 0x32, + 0x38, 0x2C, 0x36, 0x31, 0x31, 0x2C, 0x32, 0x38, 0x33, 0x2C, 0x32, 0x38, 0x33, 0x2C, 0x35, 0x36, + 0x30, 0x2C, 0x32, 0x35, 0x32, 0x2C, 0x39, 0x37, 0x36, 0x2C, 0x35, 0x39, 0x35, 0x2C, 0x35, 0x30, + 0x38, 0x2C, 0x35, 0x34, 0x39, 0x2C, 0x35, 0x34, 0x30, 0x2C, 0x33, 0x39, 0x35, 0x2C, 0x34, 0x34, + 0x31, 0x2C, 0x33, 0x30, 0x37, 0x2C, 0x36, 0x31, 0x34, 0x2C, 0x35, 0x35, 0x36, 0x2C, 0x39, 0x31, + 0x35, 0x2C, 0x35, 0x35, 0x39, 0x2C, 0x35, 0x39, 0x37, 0x2C, 0x34, 0x35, 0x32, 0x2C, 0x33, 0x31, + 0x35, 0x2C, 0x32, 0x32, 0x32, 0x2C, 0x33, 0x31, 0x35, 0x2C, 0x36, 0x30, 0x30, 0x2C, 0x38, 0x30, + 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x37, 0x38, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x32, 0x37, 0x38, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x31, 0x30, 0x36, 0x34, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x30, 0x2C, 0x38, 0x30, 0x30, + 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x32, 0x35, 0x39, 0x2C, 0x32, 0x35, 0x39, 0x2C, 0x34, 0x37, 0x30, + 0x2C, 0x34, 0x37, 0x30, 0x2C, 0x35, 0x30, 0x30, 0x2C, 0x33, 0x30, 0x30, 0x2C, 0x36, 0x30, 0x30, + 0x2C, 0x32, 0x37, 0x38, 0x2C, 0x39, 0x39, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x37, 0x39, 0x30, + 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x2C, 0x37, 0x35, 0x34, 0x2C, 0x32, 0x38, 0x32, + 0x2C, 0x33, 0x32, 0x34, 0x2C, 0x34, 0x35, 0x30, 0x2C, 0x36, 0x34, 0x30, 0x2C, 0x35, 0x31, 0x38, + 0x2C, 0x36, 0x30, 0x33, 0x2C, 0x30, 0x2C, 0x35, 0x31, 0x39, 0x2C, 0x32, 0x35, 0x34, 0x2C, 0x38, + 0x30, 0x30, 0x2C, 0x33, 0x34, 0x39, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x34, 0x33, 0x32, 0x2C, 0x38, + 0x30, 0x30, 0x2C, 0x32, 0x37, 0x38, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x32, + 0x37, 0x38, 0x2C, 0x36, 0x31, 0x34, 0x2C, 0x30, 0x2C, 0x32, 0x35, 0x34, 0x2C, 0x32, 0x37, 0x38, + 0x2C, 0x30, 0x2C, 0x33, 0x30, 0x35, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x35, + 0x30, 0x31, 0x2C, 0x37, 0x34, 0x33, 0x2C, 0x37, 0x34, 0x33, 0x2C, 0x37, 0x34, 0x33, 0x2C, 0x37, + 0x34, 0x33, 0x2C, 0x37, 0x34, 0x33, 0x2C, 0x37, 0x34, 0x33, 0x2C, 0x31, 0x30, 0x36, 0x30, 0x2C, + 0x35, 0x39, 0x38, 0x2C, 0x36, 0x30, 0x38, 0x2C, 0x36, 0x30, 0x38, 0x2C, 0x36, 0x30, 0x38, 0x2C, + 0x36, 0x30, 0x38, 0x2C, 0x33, 0x30, 0x38, 0x2C, 0x33, 0x30, 0x38, 0x2C, 0x33, 0x30, 0x38, 0x2C, + 0x33, 0x30, 0x38, 0x2C, 0x30, 0x2C, 0x38, 0x31, 0x37, 0x2C, 0x37, 0x32, 0x39, 0x2C, 0x37, 0x32, + 0x39, 0x2C, 0x37, 0x32, 0x39, 0x2C, 0x37, 0x32, 0x39, 0x2C, 0x37, 0x32, 0x39, 0x2C, 0x30, 0x2C, + 0x37, 0x32, 0x39, 0x2C, 0x38, 0x30, 0x35, 0x2C, 0x38, 0x30, 0x35, 0x2C, 0x38, 0x30, 0x35, 0x2C, + 0x38, 0x30, 0x35, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x36, 0x38, 0x38, 0x2C, 0x35, 0x38, 0x31, 0x2C, + 0x35, 0x38, 0x31, 0x2C, 0x35, 0x38, 0x31, 0x2C, 0x35, 0x38, 0x31, 0x2C, 0x35, 0x38, 0x31, 0x2C, + 0x35, 0x38, 0x31, 0x2C, 0x37, 0x39, 0x32, 0x2C, 0x34, 0x34, 0x30, 0x2C, 0x34, 0x35, 0x30, 0x2C, + 0x34, 0x35, 0x30, 0x2C, 0x34, 0x35, 0x30, 0x2C, 0x34, 0x35, 0x30, 0x2C, 0x32, 0x38, 0x33, 0x2C, + 0x32, 0x38, 0x33, 0x2C, 0x32, 0x38, 0x33, 0x2C, 0x32, 0x38, 0x33, 0x2C, 0x30, 0x2C, 0x35, 0x39, + 0x35, 0x2C, 0x35, 0x30, 0x38, 0x2C, 0x35, 0x30, 0x38, 0x2C, 0x35, 0x30, 0x38, 0x2C, 0x35, 0x30, + 0x38, 0x2C, 0x35, 0x30, 0x38, 0x2C, 0x30, 0x2C, 0x35, 0x30, 0x38, 0x2C, 0x36, 0x31, 0x34, 0x2C, + 0x36, 0x31, 0x34, 0x2C, 0x36, 0x31, 0x34, 0x2C, 0x36, 0x31, 0x34, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x35, 0x39, 0x37, 0x5D, 0x2C, 0x22, 0x45, 0x6E, 0x63, 0x22, 0x3A, 0x22, 0x63, 0x70, 0x31, 0x32, + 0x35, 0x32, 0x22, 0x2C, 0x22, 0x44, 0x69, 0x66, 0x66, 0x22, 0x3A, 0x22, 0x22, 0x2C, 0x22, 0x46, + 0x69, 0x6C, 0x65, 0x22, 0x3A, 0x22, 0x63, 0x61, 0x6C, 0x6C, 0x69, 0x67, 0x72, 0x61, 0x2E, 0x7A, + 0x22, 0x2C, 0x22, 0x53, 0x69, 0x7A, 0x65, 0x31, 0x22, 0x3A, 0x30, 0x2C, 0x22, 0x53, 0x69, 0x7A, + 0x65, 0x32, 0x22, 0x3A, 0x30, 0x2C, 0x22, 0x4F, 0x72, 0x69, 0x67, 0x69, 0x6E, 0x61, 0x6C, 0x53, + 0x69, 0x7A, 0x65, 0x22, 0x3A, 0x34, 0x30, 0x31, 0x32, 0x30, 0x2C, 0x22, 0x49, 0x22, 0x3A, 0x30, + 0x2C, 0x22, 0x4E, 0x22, 0x3A, 0x30, 0x2C, 0x22, 0x44, 0x69, 0x66, 0x66, 0x4E, 0x22, 0x3A, 0x30, + 0x7D} + +// CalligraZ is embedded byte slice for calligra.z +var CalligraZ = []byte{ + 0x78, 0x9C, 0xA4, 0xFC, 0x07, 0x80, 0x5C, 0x57, 0x7D, 0x2F, 0x8E, 0x9F, 0x73, 0x6E, 0xEF, 0xFD, + 0xDE, 0xE9, 0xBD, 0xF7, 0x9D, 0xD9, 0x99, 0xD9, 0xDD, 0x99, 0xDD, 0x99, 0xED, 0xAB, 0xDE, 0x65, + 0xAD, 0xEC, 0xB5, 0x25, 0x4B, 0xB2, 0xE4, 0x22, 0x5B, 0x96, 0x6D, 0x59, 0xC6, 0x35, 0xB8, 0x51, + 0x0D, 0xBC, 0x47, 0x4B, 0x80, 0x40, 0x02, 0x06, 0x02, 0x04, 0x4C, 0x7B, 0x0F, 0xF1, 0x02, 0xA4, + 0x40, 0x02, 0x04, 0x0C, 0x8F, 0xBC, 0x88, 0x16, 0x02, 0xFF, 0x07, 0x8F, 0x7F, 0x78, 0x18, 0x1B, + 0x1B, 0x48, 0x20, 0x41, 0xDA, 0xDF, 0xB9, 0x77, 0x66, 0x57, 0x2B, 0xD9, 0x3C, 0x7E, 0x65, 0x77, + 0xEE, 0xCC, 0x9D, 0x33, 0x33, 0xF7, 0x9E, 0xF2, 0x2D, 0x9F, 0x6F, 0x3B, 0x00, 0x02, 0x00, 0x64, + 0x50, 0x03, 0x04, 0x78, 0x6A, 0xC7, 0x9E, 0x6A, 0xFD, 0x1E, 0xA6, 0x29, 0x02, 0xF0, 0x9A, 0x77, + 0xE1, 0xD6, 0xED, 0x47, 0x4E, 0x1E, 0x3E, 0xE5, 0xFF, 0xD5, 0xB1, 0xDF, 0x00, 0xF0, 0x07, 0xAF, + 0x07, 0x80, 0xBC, 0xE6, 0xC8, 0x99, 0x3B, 0x63, 0xAF, 0xFF, 0xCD, 0xC7, 0x9E, 0x01, 0xE0, 0x95, + 0x5F, 0x04, 0x00, 0x9D, 0xBF, 0xE1, 0xD4, 0xF1, 0x93, 0xEF, 0xFB, 0xF6, 0xB5, 0xFF, 0xD9, 0xFD, + 0x0C, 0x7F, 0xFF, 0xE8, 0xF1, 0x5B, 0xEE, 0xB9, 0x21, 0xF2, 0x96, 0x57, 0x75, 0xF1, 0x7B, 0xFC, + 0xF9, 0x99, 0xF3, 0x27, 0x8E, 0x9E, 0x3C, 0x7B, 0xEC, 0x0B, 0xC2, 0xF5, 0xF8, 0x7A, 0x3F, 0x07, + 0x40, 0xF9, 0xE2, 0x89, 0x63, 0x87, 0x8F, 0x1E, 0x2F, 0xDE, 0xF5, 0x49, 0xFC, 0x5D, 0x7C, 0x0D, + 0xD0, 0x3A, 0x81, 0x1B, 0x58, 0x0E, 0xDD, 0x0A, 0x00, 0x4C, 0xE1, 0xF7, 0xA9, 0x13, 0x27, 0xEF, + 0x3C, 0xFB, 0x5F, 0xF6, 0x33, 0x0D, 0x00, 0x1E, 0xC5, 0x9F, 0x13, 0xFF, 0x74, 0xCB, 0x6D, 0x47, + 0x0E, 0x83, 0x4D, 0xF4, 0x5F, 0x00, 0x70, 0x2F, 0xEE, 0x0F, 0xF1, 0x83, 0x93, 0x87, 0xCF, 0x9E, + 0x82, 0xF7, 0xC0, 0x1F, 0xE0, 0xEF, 0x2F, 0xE1, 0xEF, 0xC7, 0x6E, 0x3D, 0x7C, 0xF2, 0x58, 0x3D, + 0x7D, 0xF4, 0x53, 0xF8, 0xFD, 0x09, 0xDC, 0x9F, 0xE7, 0x4F, 0xDD, 0x76, 0xC7, 0x9D, 0x9D, 0xCD, + 0x9D, 0x3F, 0x03, 0xE0, 0xC1, 0x87, 0xF0, 0x7B, 0xF5, 0xD4, 0xE9, 0x63, 0xA7, 0x7E, 0x4D, 0x40, + 0x1D, 0xF7, 0xE7, 0x2F, 0xF1, 0xF7, 0x59, 0x6F, 0xAC, 0xF8, 0x58, 0xFA, 0x8F, 0x7F, 0x50, 0xAE, + 0x53, 0xBA, 0xBF, 0xC2, 0xD7, 0xFC, 0x17, 0xDC, 0x02, 0xDE, 0xBB, 0x84, 0x9E, 0x5C, 0x7B, 0x5D, + 0xDD, 0xB3, 0x6A, 0x53, 0x35, 0xE2, 0x61, 0xFC, 0x96, 0x00, 0xC8, 0xFB, 0x85, 0xF7, 0x1B, 0xE2, + 0xE1, 0x55, 0x1B, 0x5F, 0xE7, 0xFC, 0xEA, 0x9E, 0x0B, 0xAF, 0xA2, 0x6A, 0xC3, 0xF6, 0x4B, 0x7F, + 0xFF, 0xE6, 0xB5, 0xFC, 0x1B, 0xB8, 0x19, 0x90, 0xE0, 0x30, 0x3E, 0x10, 0xBE, 0x5B, 0x1F, 0xF0, + 0xB8, 0xED, 0x18, 0xF8, 0x1A, 0x7E, 0x47, 0xE0, 0x33, 0x0B, 0xA2, 0xF5, 0xEF, 0x4F, 0x80, 0xF0, + 0xF0, 0x0C, 0x02, 0x1F, 0x38, 0x32, 0x3C, 0x47, 0x78, 0x25, 0x5E, 0x3E, 0x3C, 0x27, 0xC0, 0x41, + 0xF0, 0x99, 0xE1, 0x39, 0x09, 0x72, 0xB0, 0x38, 0x3C, 0xA7, 0x40, 0x1F, 0xDE, 0x31, 0x3C, 0xA7, + 0x71, 0xFB, 0xDF, 0xAD, 0xF7, 0x25, 0x3C, 0xE8, 0xA9, 0xF7, 0x2C, 0x82, 0xAB, 0x86, 0xE7, 0x08, + 0x30, 0xE0, 0xDE, 0xE1, 0x39, 0x01, 0xCA, 0xE0, 0xF5, 0xC3, 0x73, 0x12, 0x98, 0xD0, 0x19, 0x9E, + 0x53, 0x20, 0x06, 0xF7, 0x0C, 0xCF, 0x69, 0xDC, 0xFE, 0x71, 0xFC, 0x4D, 0x48, 0x72, 0xC3, 0x7E, + 0x0E, 0xCE, 0x07, 0xFD, 0x1C, 0x9C, 0x0F, 0xFA, 0x39, 0x38, 0x1F, 0xF4, 0x73, 0x70, 0x3E, 0xE8, + 0xE7, 0xE0, 0x7C, 0xD0, 0xCF, 0xC1, 0xB9, 0xD7, 0xCF, 0xC5, 0x63, 0xB7, 0x1E, 0x3B, 0x7D, 0xF8, + 0xCE, 0x63, 0x47, 0x63, 0xD7, 0xDF, 0x13, 0x5B, 0xB8, 0xED, 0xD6, 0x3B, 0x6F, 0x3B, 0x7E, 0xFA, + 0xF0, 0xA9, 0x13, 0xC7, 0x4E, 0xC7, 0x1A, 0x95, 0x26, 0x58, 0xC4, 0x13, 0x75, 0x2B, 0x3E, 0x4E, + 0xE3, 0xE9, 0xBB, 0x13, 0xBF, 0x1E, 0x05, 0x31, 0x70, 0x3D, 0xB8, 0x07, 0x3F, 0x2F, 0x80, 0xDB, + 0xF0, 0x27, 0x77, 0xE2, 0xE7, 0xE3, 0xDE, 0xA7, 0xA7, 0xC0, 0x09, 0xEF, 0x7B, 0x31, 0xD0, 0x00, + 0x15, 0xD0, 0x9C, 0x3D, 0x7C, 0xCB, 0x2D, 0x37, 0x0E, 0xAF, 0x04, 0x66, 0xF1, 0xE7, 0xB7, 0xE0, + 0xFF, 0x1B, 0x2F, 0xFF, 0xEE, 0xEE, 0x63, 0xC7, 0xEF, 0xBA, 0xE5, 0xF0, 0x69, 0xB0, 0x1B, 0xBF, + 0x39, 0x0E, 0xEE, 0xC2, 0x5F, 0x38, 0x0C, 0x4E, 0x4F, 0xDF, 0x72, 0xE7, 0x1D, 0xF7, 0xDC, 0xF1, + 0xA2, 0x9E, 0xC4, 0x62, 0x1B, 0xAF, 0x18, 0x5B, 0xFB, 0xE9, 0x34, 0xFE, 0xD1, 0x9D, 0xE0, 0x0E, + 0xDC, 0xA3, 0x3B, 0x7E, 0x7F, 0x9F, 0xF0, 0x6B, 0xEC, 0x77, 0xF5, 0x05, 0x7F, 0x72, 0x59, 0x37, + 0x5E, 0xF2, 0x6E, 0xFF, 0x37, 0x7F, 0xFB, 0x3B, 0x87, 0xD0, 0xAC, 0xD6, 0x5B, 0xD5, 0xF1, 0xFA, + 0xFF, 0x8B, 0x5E, 0x37, 0x41, 0x15, 0xD4, 0x41, 0x0B, 0x3F, 0x8F, 0x83, 0xFA, 0xFF, 0x97, 0xBE, + 0x61, 0xE2, 0xE9, 0x53, 0x14, 0x49, 0x20, 0x50, 0x3A, 0x33, 0x1F, 0x7B, 0x8A, 0x48, 0xCF, 0x27, + 0x0F, 0x9F, 0xF0, 0x25, 0x4F, 0x1C, 0x9A, 0x2B, 0x97, 0xD6, 0xDF, 0x0F, 0xDE, 0xC6, 0x62, 0x9F, + 0x5A, 0xFD, 0xCB, 0x31, 0xFD, 0xA3, 0x7D, 0xD8, 0x1A, 0x73, 0xDF, 0x3D, 0xD5, 0x1F, 0xD3, 0x9F, + 0x82, 0x2D, 0xB7, 0xB1, 0x5C, 0x82, 0x4F, 0x2D, 0x9C, 0x89, 0x2D, 0xE2, 0x5F, 0x2E, 0x1C, 0x3E, + 0x11, 0x3B, 0xE0, 0xFE, 0x30, 0x39, 0xF6, 0x14, 0x4A, 0xBB, 0x5F, 0x38, 0x36, 0xB6, 0x5C, 0xEE, + 0x43, 0xF8, 0xDA, 0x4F, 0xC1, 0xD5, 0x47, 0x31, 0x4D, 0xD6, 0x31, 0xB1, 0x3F, 0x4B, 0xC4, 0x30, + 0xCD, 0x31, 0x60, 0xB2, 0x1F, 0x64, 0xC8, 0xBF, 0x03, 0x34, 0xF5, 0x77, 0x90, 0x22, 0x11, 0x81, + 0x18, 0x1A, 0x41, 0x80, 0xE0, 0x3F, 0x62, 0x7A, 0x84, 0x60, 0xE1, 0x4C, 0xB5, 0xED, 0x03, 0xBD, + 0x6E, 0xAF, 0x0B, 0xAB, 0xDD, 0x0B, 0x5D, 0xF7, 0x00, 0xEA, 0x85, 0x2E, 0x7E, 0x8C, 0xD4, 0x3E, + 0xC6, 0x02, 0xAA, 0xD8, 0xD0, 0xE2, 0x5A, 0x16, 0x1F, 0x75, 0xF4, 0x17, 0xF5, 0x0B, 0xEF, 0x27, + 0x62, 0xBF, 0xFD, 0x01, 0x3E, 0xBB, 0x30, 0x87, 0xEF, 0x31, 0xBB, 0xFA, 0x73, 0xF0, 0x1F, 0xE8, + 0x69, 0xCC, 0xD9, 0x3E, 0x30, 0xDB, 0x0F, 0x09, 0xC0, 0x86, 0x0C, 0x81, 0x1F, 0xB4, 0xDF, 0xA6, + 0xFC, 0x1A, 0x03, 0x11, 0x03, 0x98, 0x15, 0x51, 0x66, 0xA1, 0xB6, 0x76, 0x93, 0x33, 0x3D, 0x1F, + 0xAC, 0x5E, 0x50, 0xCF, 0xE3, 0x3B, 0xA8, 0x17, 0xA0, 0xA6, 0x8F, 0xE3, 0x07, 0xAC, 0x54, 0xF0, + 0x9D, 0xFC, 0x1A, 0x55, 0x34, 0x14, 0x54, 0x25, 0x7A, 0xC8, 0x60, 0xE8, 0x64, 0x22, 0xD3, 0x1C, + 0xED, 0x11, 0x8E, 0xFD, 0x0C, 0x45, 0x9F, 0x16, 0x05, 0x8E, 0xCB, 0x17, 0x0A, 0x63, 0x47, 0x78, + 0x3A, 0x9A, 0x89, 0xC5, 0x89, 0x14, 0xED, 0xA0, 0xA7, 0xFF, 0xE9, 0x17, 0x5B, 0xCE, 0xDC, 0x75, + 0xCD, 0x35, 0xE1, 0x70, 0xE4, 0xC2, 0x63, 0xB3, 0xA8, 0x6D, 0x05, 0x7C, 0x3E, 0x14, 0x30, 0xA6, + 0x70, 0xAF, 0xBA, 0xF0, 0x2B, 0xF0, 0x30, 0xEE, 0x95, 0x3B, 0xF2, 0x64, 0x5F, 0xA4, 0x49, 0x84, + 0x59, 0x91, 0x59, 0xA1, 0x11, 0x77, 0x16, 0x9C, 0x71, 0xBB, 0xD0, 0xF5, 0x01, 0x7C, 0x4F, 0xEF, + 0xAE, 0x2C, 0x4D, 0x15, 0xA1, 0x02, 0xDB, 0x59, 0x7C, 0xC0, 0xC3, 0xF5, 0xBD, 0x62, 0x1A, 0x1F, + 0xE8, 0xE9, 0x5F, 0xF3, 0x2F, 0xA8, 0xF8, 0x70, 0xE5, 0x45, 0x12, 0x3F, 0xA5, 0xD1, 0x67, 0x40, + 0x10, 0x44, 0xC1, 0xD7, 0xFA, 0x47, 0x74, 0x99, 0x04, 0x8E, 0x8D, 0x7C, 0x7E, 0xBF, 0x2F, 0xCA, + 0xB1, 0x21, 0x14, 0xE1, 0x85, 0x70, 0x58, 0xC0, 0x2D, 0x96, 0x7B, 0x86, 0x4C, 0x4D, 0x95, 0x44, + 0xCB, 0x12, 0x7D, 0x7E, 0x14, 0xF0, 0x3E, 0x0F, 0xD2, 0x78, 0xBA, 0x03, 0x01, 0x26, 0x1C, 0xD2, + 0x35, 0x44, 0x41, 0x3E, 0xE8, 0x73, 0x4C, 0x83, 0x02, 0xE3, 0xD1, 0x88, 0xAA, 0x90, 0x14, 0xC1, + 0xCB, 0x12, 0xCF, 0xD1, 0x14, 0x15, 0xF0, 0xDB, 0x84, 0x25, 0x89, 0x02, 0x4B, 0x30, 0x10, 0xF4, + 0x9C, 0x2E, 0x7E, 0x80, 0xAA, 0xD3, 0xBD, 0xE0, 0x9D, 0xE1, 0xE7, 0xC7, 0x2B, 0xF2, 0xE7, 0xD7, + 0xFF, 0x7F, 0x3B, 0x78, 0xAD, 0xB8, 0x27, 0xBF, 0xFF, 0x83, 0x61, 0xA3, 0xF7, 0x1E, 0x9F, 0xAF, + 0x8D, 0x3C, 0x26, 0xE3, 0x91, 0x33, 0x49, 0xA6, 0x81, 0x8F, 0x64, 0xDB, 0x3B, 0xDA, 0x0D, 0xEF, + 0x68, 0x30, 0xF8, 0x50, 0x20, 0xFE, 0x08, 0xA5, 0x95, 0x53, 0xA9, 0x53, 0xF2, 0xA9, 0xC2, 0x42, + 0x61, 0x1F, 0x3E, 0x4E, 0x79, 0xEF, 0x6E, 0xCF, 0x2F, 0xE4, 0xF7, 0xBA, 0x2D, 0x7B, 0x93, 0x7B, + 0xE0, 0xAF, 0x17, 0xDE, 0xB7, 0xF0, 0x05, 0xFC, 0xB7, 0xFE, 0x82, 0x67, 0x3D, 0xB6, 0xFA, 0x72, + 0xB4, 0x87, 0xA8, 0x80, 0xAD, 0x60, 0x2F, 0x38, 0x04, 0x5E, 0xD1, 0x9F, 0x3D, 0xB0, 0x6D, 0x22, + 0x29, 0x6F, 0xDF, 0xA6, 0x14, 0xEA, 0x33, 0x33, 0xD5, 0x2A, 0xA7, 0x1C, 0xB8, 0xE6, 0x68, 0xDF, + 0xD7, 0x7C, 0xD3, 0x4A, 0xC4, 0xD1, 0x67, 0x66, 0xCC, 0xFA, 0x03, 0xD7, 0x1D, 0xDC, 0x5D, 0x10, + 0x78, 0x96, 0xE0, 0xB6, 0x17, 0x0B, 0x68, 0x2E, 0x1A, 0x51, 0xD0, 0xD5, 0x07, 0x17, 0xEB, 0xE4, + 0xB2, 0x4F, 0xD9, 0x72, 0xA0, 0x1A, 0x92, 0xC3, 0xD0, 0x37, 0x24, 0x9F, 0x1E, 0x54, 0xBF, 0xA7, + 0x7E, 0x6F, 0xC4, 0x9D, 0x98, 0x6E, 0xB7, 0xEA, 0x1E, 0x4E, 0x57, 0x3D, 0x8F, 0xA9, 0xA9, 0x77, + 0xA1, 0x77, 0xA1, 0x8B, 0x9F, 0xCE, 0xBB, 0x24, 0xA5, 0x76, 0x01, 0x7E, 0x06, 0x78, 0x98, 0xDE, + 0x58, 0xDD, 0xC1, 0x1E, 0xF6, 0x51, 0xC5, 0xB4, 0x0C, 0x15, 0x84, 0x0F, 0x68, 0x39, 0x32, 0x64, + 0xDA, 0x32, 0x4C, 0x26, 0xAA, 0xB0, 0x02, 0x31, 0x99, 0x41, 0xC7, 0x76, 0x9A, 0x55, 0x88, 0x29, + 0xAE, 0xD5, 0x9E, 0x82, 0x3D, 0x98, 0xED, 0x11, 0x32, 0xB4, 0xA6, 0x60, 0xA3, 0x1E, 0x41, 0x96, + 0xE9, 0xFE, 0x2C, 0x93, 0xA5, 0x2D, 0xD3, 0x8E, 0x22, 0xDB, 0x32, 0xD3, 0xD9, 0x04, 0xFE, 0xD0, + 0x74, 0x8C, 0x0A, 0xCC, 0x46, 0xF1, 0xB5, 0xDA, 0xAD, 0xE6, 0x28, 0x1A, 0xE5, 0xA2, 0x8E, 0x42, + 0x45, 0xDA, 0x09, 0x88, 0x7C, 0x39, 0x93, 0xD2, 0x55, 0x2D, 0x5B, 0x0B, 0x96, 0x0B, 0xCE, 0xCB, + 0xF8, 0xE8, 0xCC, 0x13, 0xEA, 0x96, 0x50, 0xCE, 0x8A, 0x4A, 0xD7, 0x42, 0x4D, 0xF3, 0xF9, 0x48, + 0x12, 0x7F, 0x18, 0x1E, 0x8B, 0x15, 0x03, 0x69, 0xDD, 0x09, 0x07, 0xCB, 0x1C, 0x24, 0x5F, 0x6F, + 0x6F, 0xBD, 0xF8, 0x45, 0x4A, 0xF6, 0xA5, 0x3B, 0x4F, 0x11, 0x63, 0x61, 0x84, 0xA0, 0xD5, 0xFB, + 0xB8, 0x9C, 0x30, 0x24, 0xCA, 0x9F, 0x50, 0x75, 0xA3, 0x2D, 0xF8, 0xB5, 0xBB, 0x08, 0x24, 0xF3, + 0x6A, 0xC1, 0x17, 0x14, 0x17, 0xEC, 0xBE, 0xF6, 0x74, 0x91, 0xC9, 0xCC, 0x06, 0x36, 0xA7, 0x2C, + 0x87, 0xAE, 0x2D, 0x0A, 0xBC, 0x22, 0xDB, 0xED, 0x00, 0x81, 0x44, 0x21, 0x6A, 0x6A, 0xBA, 0xC9, + 0x09, 0x62, 0xCE, 0xDF, 0x6C, 0x29, 0x81, 0x4C, 0x95, 0x4B, 0x2F, 0x16, 0xFE, 0xF7, 0xFB, 0x84, + 0x74, 0xBC, 0x19, 0xB8, 0xF8, 0x4C, 0xA4, 0x4E, 0xD6, 0xEA, 0xC5, 0x02, 0x1D, 0x6C, 0xB2, 0xAE, + 0xE6, 0x4B, 0xAE, 0xFE, 0x9C, 0xF8, 0x28, 0xFA, 0x1C, 0x28, 0x61, 0x01, 0x76, 0x13, 0x78, 0xA0, + 0xDF, 0xD8, 0xB7, 0x7B, 0x5B, 0xD9, 0xD4, 0xF9, 0xCD, 0xE5, 0x80, 0xC6, 0x64, 0xF2, 0xF1, 0xA3, + 0xC7, 0x0F, 0x8D, 0xB5, 0xC7, 0x5B, 0xA8, 0x3B, 0x39, 0xD9, 0xDD, 0x75, 0x30, 0x76, 0x73, 0x2A, + 0x1E, 0xCD, 0x1F, 0x8A, 0xAC, 0x20, 0xCC, 0xF5, 0xE1, 0x7C, 0xA2, 0xD3, 0x65, 0x21, 0xBF, 0x2E, + 0x37, 0x30, 0x43, 0x57, 0x2F, 0x80, 0x73, 0xE0, 0x38, 0x5C, 0xE9, 0x5D, 0xF0, 0x24, 0xC7, 0x39, + 0x70, 0x04, 0xCE, 0xF4, 0xCE, 0xAF, 0x91, 0x9C, 0xFB, 0x0F, 0x06, 0xBC, 0x0E, 0xBC, 0x15, 0x19, + 0xAC, 0x8B, 0xB7, 0x32, 0x37, 0xF3, 0x98, 0x0C, 0x4D, 0x19, 0x0D, 0x59, 0xBE, 0x39, 0x85, 0xF0, + 0x72, 0x28, 0xD0, 0x8C, 0x10, 0x8D, 0x7A, 0x0F, 0x8E, 0x56, 0xF0, 0x2A, 0xD1, 0x49, 0x26, 0xDB, + 0x6E, 0xE1, 0xC5, 0x80, 0x69, 0x85, 0xC4, 0xAB, 0x41, 0xD2, 0x98, 0x59, 0x5B, 0x3A, 0x5E, 0xAA, + 0xB6, 0x61, 0xCA, 0x84, 0xF7, 0xBB, 0x29, 0x18, 0x85, 0x0C, 0x5E, 0xA3, 0x08, 0x6A, 0xD4, 0xF1, + 0x82, 0x64, 0x92, 0x09, 0x05, 0x0E, 0x7F, 0x04, 0xBF, 0x14, 0x1B, 0xE3, 0xED, 0xA5, 0xFE, 0x35, + 0x9B, 0x11, 0xED, 0x73, 0x0A, 0x32, 0xC5, 0xF9, 0x23, 0x7A, 0x39, 0xD4, 0xD3, 0x48, 0x7A, 0xEE, + 0x5A, 0x46, 0xA5, 0x7C, 0xAC, 0x7F, 0x53, 0x73, 0x74, 0x77, 0x06, 0xF6, 0x17, 0x3A, 0xD7, 0xFB, + 0xAB, 0x62, 0x49, 0x8B, 0x97, 0x7C, 0x4A, 0x24, 0x66, 0x9D, 0xB9, 0xED, 0x2F, 0x36, 0xD1, 0x11, + 0xF6, 0xAB, 0x47, 0x9D, 0x62, 0x37, 0x72, 0xD5, 0x96, 0x7A, 0x5E, 0x94, 0x19, 0xBD, 0x56, 0x49, + 0x2B, 0x8D, 0xF8, 0xF4, 0x71, 0x45, 0xB7, 0x18, 0x7B, 0x6F, 0x21, 0xBA, 0x6B, 0x1A, 0xB1, 0xE3, + 0x3B, 0xA6, 0x59, 0xBD, 0xFE, 0xEA, 0x3C, 0x4D, 0xB3, 0xB9, 0x74, 0xB0, 0x41, 0xE7, 0x97, 0x7C, + 0xDD, 0x9C, 0x1E, 0xD9, 0x16, 0x8D, 0x4F, 0x3E, 0x8A, 0x48, 0x5E, 0xCD, 0xF7, 0xB6, 0x3C, 0x72, + 0xFD, 0x9E, 0x57, 0x26, 0x66, 0xD5, 0xBE, 0xBF, 0x36, 0x9B, 0x76, 0x38, 0x02, 0xFD, 0xC9, 0x5B, + 0xA0, 0x72, 0x3B, 0xC1, 0xA2, 0x8B, 0xF3, 0xFB, 0x0F, 0x19, 0x61, 0xF3, 0xE1, 0x46, 0xFE, 0xAA, + 0x34, 0x49, 0x2A, 0x85, 0x74, 0x79, 0x6F, 0x56, 0x3E, 0x90, 0x2C, 0xBF, 0x97, 0x20, 0x65, 0xA1, + 0x90, 0xBC, 0xDA, 0x95, 0x40, 0xF9, 0xD5, 0xE7, 0x88, 0x22, 0xFA, 0x63, 0x8C, 0xA0, 0x76, 0x82, + 0x53, 0xFD, 0x56, 0xBF, 0x97, 0xA7, 0x41, 0xC3, 0xE9, 0xCE, 0xF4, 0xFA, 0xA5, 0x5C, 0x9A, 0x22, + 0xB3, 0x60, 0xEB, 0x96, 0x8C, 0x30, 0x6D, 0xA7, 0xFB, 0xB3, 0x33, 0xC9, 0xC9, 0xEE, 0x11, 0x23, + 0xBC, 0xD0, 0xDE, 0xB9, 0x63, 0x86, 0x98, 0x46, 0x54, 0x1B, 0x85, 0xD3, 0xC9, 0xA2, 0x50, 0x82, + 0xC6, 0x1A, 0x03, 0x75, 0xBD, 0xC5, 0x5A, 0xE3, 0x1A, 0x57, 0xDC, 0x7B, 0x92, 0xDE, 0x7B, 0xC6, + 0x2D, 0xDE, 0x0A, 0xAD, 0x73, 0xCD, 0x2E, 0xC3, 0x15, 0x8E, 0x44, 0xD2, 0xC1, 0xEB, 0x93, 0x4C, + 0x54, 0x28, 0xCC, 0x1F, 0x98, 0x39, 0x2A, 0x84, 0xF7, 0x8A, 0xE7, 0xD6, 0xC1, 0xB3, 0x6B, 0x99, + 0x0A, 0xAC, 0x50, 0x49, 0x8F, 0x27, 0xF0, 0xE4, 0xF7, 0x10, 0x9E, 0x77, 0xBC, 0x64, 0xDE, 0x1B, + 0x8F, 0x99, 0x88, 0xA2, 0x3F, 0x10, 0x8F, 0x1D, 0x80, 0x63, 0xAF, 0xDA, 0x52, 0x34, 0x5B, 0x39, + 0x7F, 0x2B, 0x67, 0x8F, 0x76, 0x45, 0x35, 0x91, 0x30, 0xC5, 0xCD, 0xDB, 0xA6, 0x3A, 0x55, 0x95, + 0x29, 0xB6, 0x8C, 0xDC, 0x66, 0x9E, 0xB3, 0x43, 0xC1, 0x08, 0x14, 0x4B, 0x89, 0xC8, 0xFC, 0xE8, + 0xA6, 0xAD, 0xE8, 0x15, 0xD4, 0xAB, 0xD0, 0x1D, 0x27, 0x16, 0x26, 0x37, 0xDB, 0x5A, 0xA2, 0x90, + 0xA0, 0x20, 0xFC, 0x40, 0x20, 0x10, 0x4F, 0xDA, 0x13, 0xFB, 0xEE, 0x4D, 0xF2, 0x02, 0x1F, 0xCA, + 0xD4, 0x7D, 0xE9, 0xA5, 0x22, 0xC7, 0x1A, 0xC1, 0x68, 0x42, 0xCB, 0xEF, 0x2F, 0x85, 0x4C, 0xE8, + 0x0B, 0xB3, 0xAA, 0xAF, 0xAA, 0x8A, 0x86, 0xCE, 0x22, 0x21, 0x1F, 0x72, 0x26, 0x4C, 0x04, 0x23, + 0xBB, 0x6E, 0xBA, 0x9D, 0xC8, 0xD5, 0x13, 0x1D, 0x9B, 0x44, 0x54, 0x20, 0xA2, 0x60, 0xDC, 0xB6, + 0x04, 0xBF, 0x02, 0x9E, 0xF6, 0xB4, 0x43, 0xB0, 0xCF, 0x62, 0x08, 0xCA, 0xAC, 0x0C, 0xF4, 0x02, + 0xD6, 0x4C, 0x60, 0xA0, 0x89, 0xF0, 0x57, 0xB1, 0x26, 0x82, 0xED, 0xA7, 0xD7, 0x54, 0x01, 0xFE, + 0xD5, 0xF8, 0xEA, 0x2B, 0x61, 0x91, 0xD0, 0x30, 0xFE, 0x8B, 0xF7, 0x05, 0x13, 0xF8, 0x91, 0x68, + 0x56, 0x56, 0xC8, 0xEA, 0xF0, 0x87, 0x78, 0x52, 0x87, 0xBF, 0x8D, 0x88, 0x54, 0x91, 0x62, 0xB0, + 0x7C, 0xA9, 0x40, 0x2C, 0x5C, 0x10, 0x26, 0x4C, 0x84, 0x85, 0x09, 0x81, 0xA7, 0x03, 0x3A, 0xB0, + 0xD8, 0xF5, 0x8B, 0x72, 0x30, 0x67, 0x88, 0x02, 0x2F, 0xDA, 0x41, 0x9F, 0xC8, 0x70, 0x8F, 0xA8, + 0xF1, 0x82, 0x9D, 0x4A, 0xA7, 0x7C, 0x55, 0x5B, 0x50, 0x12, 0xDB, 0xC7, 0x33, 0xD9, 0xFA, 0x9D, + 0xD5, 0xE6, 0x7D, 0x57, 0x4D, 0x07, 0x04, 0xB5, 0x17, 0x59, 0x38, 0x75, 0xDB, 0xD2, 0xF2, 0x1F, + 0x5F, 0x33, 0xEE, 0x62, 0xD1, 0xD5, 0x57, 0x82, 0x17, 0xD6, 0xEE, 0x6F, 0x09, 0x0A, 0x42, 0xBE, + 0xCA, 0x8A, 0xF0, 0x12, 0xF7, 0xB7, 0x70, 0xDF, 0xB1, 0x94, 0x92, 0x09, 0x85, 0x98, 0xC2, 0xB7, + 0xAF, 0xA0, 0x2A, 0xC4, 0x8B, 0x15, 0xC1, 0xEC, 0x61, 0xFF, 0x84, 0xD3, 0x39, 0x3B, 0x20, 0xD0, + 0xDC, 0xA3, 0xA9, 0x31, 0x9B, 0x0F, 0x64, 0x52, 0x62, 0x24, 0xDC, 0x08, 0xE6, 0x0D, 0x41, 0x87, + 0x5F, 0xDC, 0x59, 0x6B, 0x5F, 0x9F, 0xDA, 0x32, 0xEB, 0x13, 0xD5, 0x7E, 0xFF, 0x8D, 0xB7, 0x2D, + 0x15, 0xF7, 0xDD, 0xBD, 0x32, 0x66, 0x58, 0x81, 0x6A, 0x62, 0xDB, 0x58, 0x66, 0x12, 0xDF, 0x3F, + 0x09, 0xDF, 0x02, 0xF7, 0xA3, 0x2F, 0x83, 0x49, 0xF0, 0x70, 0xBF, 0x5B, 0x4F, 0xA7, 0xA2, 0x41, + 0x9E, 0x03, 0x9D, 0x6C, 0x54, 0x46, 0x80, 0x2E, 0x44, 0x4B, 0x4D, 0x55, 0x05, 0x25, 0x7B, 0xB4, + 0x24, 0x33, 0x0C, 0x28, 0x75, 0x40, 0x49, 0xB5, 0x9A, 0xCF, 0xC7, 0x47, 0x0A, 0x7B, 0xAB, 0x95, + 0x52, 0x53, 0x1B, 0x45, 0x25, 0x0C, 0xC0, 0x56, 0xEC, 0xF6, 0x59, 0x98, 0x1A, 0xD0, 0xA1, 0xDB, + 0xE9, 0xAE, 0xDB, 0xEB, 0x2E, 0x26, 0xC4, 0xAE, 0x27, 0xBD, 0x87, 0x58, 0x40, 0xED, 0x0E, 0xE5, + 0xC4, 0x46, 0x71, 0xB1, 0x2E, 0x2F, 0xDC, 0x11, 0x4E, 0xA5, 0x30, 0x51, 0x62, 0xFE, 0xC6, 0x42, + 0x00, 0x8B, 0x6D, 0xCB, 0x9D, 0xEB, 0x4C, 0xD6, 0x15, 0xEC, 0x4C, 0x85, 0xC8, 0xBA, 0x32, 0x81, + 0x76, 0xE5, 0x7A, 0xB3, 0xD5, 0x76, 0xEC, 0x46, 0xBD, 0x9D, 0x99, 0x84, 0xF5, 0x56, 0x83, 0x66, + 0xB0, 0x34, 0x77, 0x3F, 0x73, 0x6C, 0xB8, 0x5F, 0x65, 0xC5, 0x90, 0xE4, 0x04, 0x53, 0x3E, 0x89, + 0xD7, 0x0D, 0xA3, 0x46, 0x12, 0x18, 0x18, 0x48, 0x52, 0xC4, 0xB2, 0x59, 0xC3, 0xEF, 0xD0, 0x56, + 0xC0, 0x0E, 0x4A, 0x94, 0x22, 0xA5, 0x03, 0x2C, 0x17, 0xD1, 0xE6, 0x74, 0x8D, 0x62, 0x1C, 0x41, + 0xB6, 0x15, 0xD5, 0x46, 0x58, 0x7E, 0x50, 0x22, 0x67, 0xA6, 0x38, 0x53, 0x33, 0xF5, 0x89, 0xA2, + 0x4F, 0x88, 0xF1, 0xBA, 0x42, 0x8A, 0x92, 0xC6, 0x48, 0x7A, 0xD4, 0xE2, 0x39, 0x32, 0x98, 0x4B, + 0x8B, 0x71, 0x22, 0x9D, 0x0D, 0xA1, 0x78, 0xD1, 0x2F, 0x38, 0x1C, 0x27, 0x50, 0x56, 0xCC, 0xB5, + 0x3F, 0xAA, 0x98, 0x8D, 0xF3, 0xF0, 0xDF, 0x81, 0x00, 0x76, 0xF6, 0x53, 0x14, 0x09, 0x09, 0x60, + 0x09, 0x3C, 0x43, 0x08, 0x00, 0xD2, 0x18, 0x02, 0x70, 0x88, 0x80, 0x88, 0x65, 0x48, 0x82, 0xE0, + 0xD8, 0x71, 0x02, 0x41, 0x48, 0x6D, 0x84, 0x64, 0x9E, 0xFA, 0x57, 0xBF, 0xE7, 0x3E, 0x46, 0xB0, + 0x90, 0xA5, 0xE1, 0xE8, 0x00, 0x11, 0xE0, 0xA9, 0x10, 0x29, 0xAC, 0xD5, 0x92, 0x56, 0xB2, 0x99, + 0x6C, 0x36, 0x9A, 0x0D, 0xAB, 0x81, 0xF2, 0x5F, 0x3D, 0xF4, 0x55, 0xF7, 0xE1, 0x3D, 0xB9, 0xAB, + 0xB6, 0xFA, 0x19, 0xF0, 0x03, 0xF0, 0xA7, 0xC0, 0x04, 0xD1, 0x3E, 0x6F, 0x88, 0x1C, 0xAD, 0x76, + 0x56, 0xA8, 0xEE, 0x06, 0x6A, 0xF7, 0x66, 0xD4, 0xC2, 0x34, 0xDB, 0x56, 0xC8, 0xAC, 0xAB, 0xC9, + 0xAA, 0xDE, 0x34, 0xB9, 0x6C, 0xFD, 0x05, 0x95, 0x0E, 0x4B, 0x2D, 0x4D, 0x08, 0x56, 0x75, 0xD9, + 0xA8, 0xF8, 0xF5, 0x59, 0x41, 0x22, 0x35, 0x36, 0xA5, 0x09, 0x11, 0x2B, 0x94, 0x11, 0x05, 0x2D, + 0x2A, 0x09, 0xCD, 0xA4, 0xE3, 0x8E, 0x2E, 0x04, 0x7E, 0x03, 0xDF, 0x08, 0xEF, 0x01, 0x1A, 0xE8, + 0xF4, 0x7D, 0x02, 0xD0, 0x54, 0x00, 0x44, 0x4E, 0xE0, 0xB9, 0xC7, 0x44, 0x4D, 0x55, 0x26, 0x69, + 0xB1, 0xB7, 0x42, 0xF7, 0xD7, 0xEE, 0xA9, 0xBA, 0x4B, 0x8E, 0x0F, 0xE0, 0xAD, 0x75, 0xD7, 0x15, + 0x36, 0xB8, 0x07, 0xBA, 0xE0, 0x0A, 0x1A, 0x6F, 0x0D, 0x21, 0x06, 0x25, 0xF8, 0xFE, 0x8D, 0x1E, + 0x84, 0x6F, 0x34, 0xF9, 0x06, 0x62, 0xA9, 0x50, 0x27, 0xB7, 0xB0, 0xE7, 0xB8, 0x93, 0xDF, 0x39, + 0xD2, 0x84, 0xB7, 0xFA, 0xA4, 0x09, 0x24, 0x70, 0x34, 0x09, 0xEF, 0xE6, 0x49, 0x8C, 0x5D, 0xF1, + 0xDD, 0x8B, 0x18, 0x83, 0xFE, 0x10, 0x8F, 0x51, 0x02, 0x85, 0xBE, 0x22, 0x60, 0xE3, 0x0A, 0xD1, + 0x42, 0x67, 0x05, 0x12, 0x2C, 0xA4, 0x2F, 0x07, 0x9D, 0xC0, 0x25, 0x31, 0x7C, 0x33, 0x19, 0x43, + 0xBE, 0xF6, 0x06, 0x84, 0xF9, 0xC3, 0x0D, 0xB0, 0xB2, 0xB9, 0x11, 0x49, 0x42, 0xC0, 0xAC, 0xBE, + 0x80, 0x76, 0x60, 0xAA, 0xD7, 0x81, 0xDD, 0xA7, 0x45, 0x6C, 0xA3, 0x8B, 0x33, 0x58, 0x86, 0x0E, + 0x59, 0xCD, 0x10, 0x3D, 0xE8, 0x88, 0x39, 0x0D, 0x77, 0x3C, 0xD9, 0xF6, 0x08, 0x0C, 0xED, 0xF0, + 0x27, 0x13, 0x57, 0xBF, 0xFD, 0x70, 0x44, 0x31, 0x9C, 0xAC, 0x79, 0xEC, 0x83, 0x6F, 0xDB, 0x66, + 0x65, 0xD1, 0x97, 0xD3, 0xD5, 0xF2, 0x03, 0xFF, 0xF4, 0xDA, 0x8A, 0x13, 0x66, 0x98, 0x57, 0xFF, + 0xE4, 0xFB, 0x67, 0x69, 0xC6, 0xED, 0xB7, 0xB5, 0xFA, 0x2C, 0xFC, 0x2D, 0x5A, 0x04, 0x35, 0x90, + 0xEB, 0x2B, 0x69, 0x53, 0xE1, 0xD3, 0xC1, 0x32, 0x1D, 0x45, 0xA8, 0x34, 0x4B, 0xCF, 0xB9, 0x48, + 0x07, 0x77, 0x58, 0xBD, 0x30, 0x14, 0xC6, 0xF8, 0x6E, 0x23, 0xAE, 0x9E, 0x74, 0x19, 0x1B, 0x2B, + 0x44, 0x17, 0xB4, 0xB8, 0xA2, 0xD5, 0x93, 0x2B, 0x64, 0xA3, 0x3E, 0x85, 0xDF, 0x57, 0x88, 0x24, + 0x96, 0xC9, 0xED, 0x01, 0x68, 0x81, 0xDF, 0x0F, 0x8F, 0x7F, 0x70, 0xA9, 0x73, 0xDC, 0x3F, 0x5E, + 0xAB, 0xE8, 0x94, 0x22, 0xB2, 0x08, 0xA9, 0xB9, 0x76, 0x28, 0x97, 0xE1, 0x47, 0xA7, 0xF7, 0x06, + 0x14, 0x96, 0x56, 0x94, 0xE2, 0xB8, 0x8F, 0xE6, 0xC7, 0x17, 0xE1, 0x67, 0xFA, 0xA3, 0xCD, 0x9B, + 0xFF, 0xDB, 0x6D, 0xFB, 0x12, 0xAD, 0x03, 0x59, 0x8B, 0xD6, 0xFD, 0x66, 0x22, 0xC0, 0xE8, 0x91, + 0xE2, 0x64, 0xBA, 0xDE, 0xC8, 0xD6, 0x4E, 0x76, 0xC3, 0x14, 0x4B, 0x29, 0x6C, 0x38, 0x00, 0xC5, + 0x69, 0xDC, 0x67, 0x76, 0xF5, 0x79, 0xF0, 0x13, 0xB4, 0x00, 0xFC, 0xA0, 0xD4, 0xD7, 0x6C, 0x0C, + 0x56, 0x11, 0x44, 0x7E, 0x9F, 0x43, 0x00, 0x63, 0x01, 0x2E, 0xBA, 0x4B, 0xEC, 0xEB, 0xC1, 0x01, + 0x38, 0x03, 0x5E, 0xCF, 0x71, 0xBF, 0x03, 0x82, 0x3B, 0xDB, 0x93, 0x58, 0x93, 0x63, 0x15, 0xC2, + 0x64, 0x7B, 0x70, 0x0A, 0x77, 0xD8, 0xB6, 0x30, 0x72, 0xFA, 0xC9, 0x2B, 0x08, 0xDE, 0x51, 0x05, + 0x5E, 0x95, 0x74, 0xC1, 0x48, 0x8D, 0x84, 0x78, 0xD5, 0x42, 0x68, 0xE9, 0xAA, 0xDA, 0x77, 0x9A, + 0xDD, 0xB1, 0x18, 0xA3, 0x89, 0x32, 0xA7, 0xF8, 0x63, 0x92, 0xDF, 0xDA, 0xF3, 0xF6, 0xBF, 0x77, + 0xE7, 0x4B, 0x5B, 0xFD, 0x35, 0xFC, 0x30, 0xDA, 0x8A, 0x79, 0x69, 0xB2, 0x1F, 0x28, 0x65, 0xC3, + 0x1A, 0x08, 0x39, 0x2C, 0xE4, 0xB8, 0x12, 0x05, 0xB6, 0xD6, 0xAA, 0x95, 0xF2, 0x12, 0x05, 0xE3, + 0xDB, 0xD0, 0xC3, 0xEE, 0xFA, 0xF4, 0x3C, 0x22, 0x1B, 0x90, 0xD8, 0x65, 0x30, 0xB0, 0xC6, 0x61, + 0x86, 0xC1, 0xFA, 0xCA, 0x05, 0x15, 0x83, 0xBE, 0x60, 0xC4, 0xE1, 0x76, 0x8C, 0x56, 0x50, 0x76, + 0x0A, 0x43, 0x07, 0xDB, 0x71, 0x49, 0xDF, 0x05, 0x89, 0x3D, 0x04, 0x3F, 0xBC, 0x23, 0x92, 0xDF, + 0xBF, 0x57, 0xCB, 0x09, 0x7E, 0x95, 0xD1, 0x4A, 0xDD, 0x76, 0x8C, 0xF0, 0xDD, 0x8A, 0x25, 0x09, + 0xAD, 0x62, 0xF9, 0x6D, 0xDE, 0x52, 0x93, 0x23, 0xA6, 0xB5, 0x48, 0x15, 0x3A, 0x7B, 0xC6, 0x26, + 0x66, 0xFE, 0xE0, 0x48, 0x46, 0xA4, 0x68, 0x18, 0xD1, 0x28, 0xA3, 0x38, 0xBE, 0x34, 0x1F, 0xA3, + 0x68, 0xE9, 0x90, 0x4C, 0x40, 0x82, 0x30, 0x38, 0x75, 0x33, 0xCB, 0xF0, 0x13, 0x5B, 0x94, 0xF2, + 0xA6, 0xC5, 0x1B, 0x20, 0x26, 0x59, 0x08, 0x84, 0xD5, 0x2F, 0xC3, 0x5D, 0x78, 0x16, 0x47, 0x40, + 0xB1, 0xAF, 0xD6, 0xCA, 0xB9, 0xA8, 0xCF, 0x90, 0x98, 0x48, 0x50, 0x57, 0x93, 0x0B, 0xF4, 0x0E, + 0xB7, 0xFF, 0xE0, 0x4A, 0x99, 0x57, 0x8F, 0xBA, 0xF0, 0x95, 0x70, 0x21, 0x0D, 0x26, 0xB3, 0x01, + 0xBE, 0x71, 0x31, 0x51, 0xFB, 0x12, 0xD4, 0xD9, 0x80, 0x56, 0xB1, 0x5C, 0xB4, 0x4C, 0xB8, 0x85, + 0x8A, 0xD6, 0x3B, 0x0B, 0x51, 0x23, 0x91, 0x2B, 0x33, 0xE2, 0x49, 0x93, 0x95, 0x99, 0xF1, 0x80, + 0x69, 0xF5, 0x6D, 0x4B, 0xD7, 0xB4, 0x93, 0x42, 0xCC, 0xA4, 0x63, 0xE5, 0x74, 0xC6, 0x54, 0x55, + 0xFF, 0x91, 0x77, 0xF9, 0xAA, 0x95, 0x5C, 0x4E, 0xF3, 0x59, 0xE1, 0x9A, 0x19, 0x0C, 0xEE, 0xC8, + 0x21, 0x2B, 0xAA, 0x9A, 0x01, 0xAC, 0x1A, 0x18, 0x56, 0xDB, 0xC3, 0xF0, 0xA4, 0x5E, 0x8F, 0xA6, + 0xAA, 0xA6, 0x24, 0x71, 0xD5, 0xFD, 0xB6, 0xBB, 0x12, 0xFA, 0xEA, 0x33, 0x88, 0x41, 0x07, 0x31, + 0xE5, 0xDE, 0xD2, 0xAF, 0x57, 0x42, 0x96, 0x04, 0x6A, 0x15, 0x2D, 0x58, 0x2B, 0x53, 0x7B, 0x46, + 0x8A, 0x85, 0x8C, 0x5E, 0x2C, 0x4D, 0x1A, 0x7A, 0x27, 0x5B, 0xE6, 0x30, 0x32, 0x45, 0xBC, 0xAA, + 0x68, 0x88, 0x2F, 0xA3, 0x6A, 0x2D, 0xB8, 0x77, 0x45, 0xDA, 0x77, 0x16, 0x5A, 0x97, 0x34, 0x80, + 0xCF, 0xB5, 0x37, 0xAB, 0x03, 0x81, 0xB0, 0x8E, 0x47, 0x3C, 0xFC, 0x08, 0xAF, 0xC4, 0xEF, 0x23, + 0x58, 0xAD, 0x41, 0x17, 0x88, 0xE3, 0x95, 0x22, 0x68, 0xA6, 0x47, 0x30, 0xC9, 0x04, 0xE6, 0x01, + 0xA2, 0x8D, 0xA1, 0xA2, 0x87, 0x08, 0x31, 0x3A, 0x6F, 0x44, 0x31, 0x4B, 0x28, 0xD8, 0xE6, 0x14, + 0xFD, 0x92, 0xA6, 0x73, 0x16, 0xCD, 0x93, 0x81, 0x46, 0x0B, 0xC3, 0x69, 0xF8, 0xA0, 0xB5, 0xA2, + 0xE5, 0x8E, 0x6E, 0x2B, 0xFA, 0xCD, 0x92, 0xA4, 0xEA, 0xB4, 0x41, 0x69, 0xAC, 0x63, 0x06, 0xF2, + 0xE4, 0x83, 0xF8, 0xC3, 0xA4, 0x9E, 0x51, 0x1D, 0x1F, 0x5E, 0xAA, 0x9B, 0xB5, 0x78, 0xA8, 0x54, + 0x29, 0x14, 0x51, 0x47, 0xAF, 0xCC, 0xBE, 0x7A, 0x7F, 0xC2, 0xF1, 0x8D, 0xA9, 0x76, 0x98, 0x4F, + 0x70, 0x29, 0x5D, 0x32, 0x1C, 0x04, 0x5F, 0xB5, 0xEB, 0x6D, 0x13, 0xEE, 0xE8, 0xF9, 0xD5, 0x2F, + 0xC1, 0xF7, 0xE0, 0xD5, 0x2B, 0x81, 0x91, 0xBE, 0x1A, 0x0F, 0xF9, 0x14, 0x1E, 0x70, 0x80, 0xDA, + 0x5C, 0xC8, 0x2C, 0x38, 0x57, 0x0D, 0x58, 0x00, 0x4B, 0xE9, 0x3C, 0x3C, 0x8C, 0x07, 0x03, 0xD6, + 0x57, 0x11, 0x0F, 0xA1, 0x1C, 0x1F, 0x88, 0x0B, 0x8F, 0x7F, 0xB3, 0x8C, 0xE3, 0x2D, 0x16, 0xE1, + 0xD1, 0x1D, 0x16, 0xBB, 0x04, 0xE6, 0x67, 0x14, 0x81, 0x1D, 0xAC, 0xAD, 0xE0, 0x7B, 0x46, 0x05, + 0x3D, 0x1E, 0x96, 0x1B, 0xD9, 0x02, 0x93, 0x2A, 0x76, 0xBB, 0x6C, 0xA4, 0xD5, 0x4D, 0x27, 0x13, + 0xA6, 0x11, 0xBD, 0x7A, 0xBF, 0x14, 0x2B, 0x27, 0x4B, 0x0D, 0x45, 0xB1, 0x27, 0xCC, 0x40, 0xB3, + 0x84, 0xFA, 0xCB, 0x8A, 0xA5, 0xD3, 0x94, 0x9C, 0xD5, 0x9C, 0xD2, 0xA6, 0x86, 0x92, 0xAD, 0xB4, + 0x2B, 0x3E, 0xCB, 0x0C, 0x63, 0xB4, 0x3B, 0xB3, 0xD4, 0x64, 0x8D, 0xC0, 0xE8, 0xD2, 0xBE, 0x80, + 0x9F, 0xE2, 0x09, 0xB7, 0xDF, 0xCE, 0xEA, 0x0B, 0xF0, 0x73, 0x68, 0x1B, 0x18, 0x03, 0xF9, 0xBE, + 0x52, 0xF2, 0x89, 0x44, 0x2B, 0xB7, 0x3C, 0x6E, 0xD4, 0x63, 0xCE, 0x41, 0x66, 0xC6, 0x93, 0x37, + 0xE7, 0xBB, 0x97, 0x09, 0x9C, 0x71, 0x2C, 0xDE, 0xD2, 0xB6, 0xB9, 0x26, 0x71, 0x46, 0xDD, 0xE9, + 0xEE, 0x51, 0x8E, 0x8B, 0xC0, 0xAD, 0x10, 0x8C, 0x20, 0x57, 0xBD, 0xBA, 0x82, 0x07, 0xDB, 0x4D, + 0x55, 0xE8, 0xC1, 0x41, 0x1B, 0x7E, 0x06, 0xCD, 0x3F, 0x5A, 0x1E, 0x3B, 0x66, 0x2A, 0x9D, 0x05, + 0x4E, 0xE0, 0x66, 0x0C, 0xC2, 0x6F, 0xF0, 0x9A, 0xC1, 0x46, 0xEA, 0x23, 0xE6, 0x58, 0x44, 0xE2, + 0x65, 0xCD, 0x47, 0x08, 0x6C, 0x74, 0xC6, 0x9A, 0x92, 0x32, 0xA1, 0x91, 0xF6, 0x2F, 0x18, 0x89, + 0x19, 0xB9, 0x66, 0xF9, 0xE8, 0xB2, 0x46, 0xDB, 0xFB, 0xAE, 0x5B, 0xE2, 0x58, 0x6E, 0x5C, 0x45, + 0x6A, 0x88, 0x91, 0x15, 0x26, 0xDC, 0x3C, 0xD1, 0x10, 0xD4, 0x7D, 0x13, 0x3E, 0x92, 0x72, 0x6C, + 0xDE, 0x8C, 0xD9, 0x13, 0x3E, 0xA6, 0xCC, 0x38, 0x47, 0x3C, 0x19, 0xF4, 0x2C, 0x7C, 0x27, 0x1E, + 0x47, 0x0C, 0x6C, 0xEF, 0x87, 0xF8, 0x98, 0x13, 0x96, 0x41, 0x58, 0xA6, 0x48, 0x6C, 0x66, 0x4B, + 0xA2, 0x2C, 0x8B, 0xBA, 0x26, 0x5F, 0x1D, 0x38, 0xB8, 0x22, 0xCE, 0xAD, 0x69, 0x9C, 0x73, 0x20, + 0x8C, 0x11, 0x10, 0xA6, 0xB2, 0xA1, 0x41, 0x7C, 0xA5, 0x3D, 0xE2, 0x29, 0xA0, 0xB8, 0x33, 0xA0, + 0x2F, 0x42, 0x46, 0x96, 0x02, 0x8D, 0x36, 0xB6, 0x39, 0xAA, 0x30, 0xE1, 0x0E, 0x0C, 0x2F, 0x0A, + 0xB6, 0x28, 0xDA, 0xF0, 0x9D, 0xA2, 0xC8, 0x13, 0xF9, 0xC5, 0xA0, 0xC2, 0xED, 0xDC, 0xFC, 0xF1, + 0x54, 0xB0, 0x15, 0xD4, 0xA3, 0xA9, 0x92, 0xC5, 0x3B, 0xCE, 0x16, 0xBB, 0xBF, 0xC5, 0x19, 0x0D, + 0xA2, 0xB0, 0xAC, 0xAB, 0xF4, 0xAE, 0xD7, 0x4D, 0xD5, 0xC6, 0x63, 0xC5, 0x2C, 0x3C, 0xB5, 0x09, + 0x42, 0xC2, 0xB0, 0x04, 0xCB, 0x9E, 0xB7, 0xB0, 0xC2, 0xC1, 0x28, 0xDE, 0x58, 0xFD, 0x39, 0x7C, + 0x0A, 0xCB, 0xFB, 0x16, 0x58, 0x04, 0x9B, 0xFA, 0xC1, 0x54, 0x24, 0xE8, 0x88, 0x6C, 0x21, 0x59, + 0x40, 0xB5, 0xCE, 0x54, 0xBB, 0x9C, 0xAD, 0x21, 0x80, 0x46, 0x67, 0x0D, 0x16, 0x3A, 0xEB, 0xB6, + 0xAE, 0xCB, 0x1D, 0xE7, 0xAB, 0xE7, 0xF1, 0x08, 0x66, 0xE0, 0x35, 0x03, 0xD3, 0xF6, 0x32, 0x8A, + 0x5A, 0x72, 0x06, 0x2A, 0x81, 0x71, 0x79, 0x3E, 0xEA, 0x29, 0x07, 0x72, 0xA0, 0x1C, 0x5C, 0x98, + 0x9E, 0x19, 0xE8, 0x08, 0xC7, 0xB5, 0x8A, 0x6C, 0x67, 0x5D, 0xB7, 0xE3, 0x65, 0x22, 0x46, 0xF1, + 0xC0, 0x3C, 0x63, 0xC9, 0x1B, 0xDA, 0x14, 0x84, 0xEF, 0x84, 0x2C, 0xC6, 0x35, 0x85, 0x05, 0xA9, + 0x96, 0x5D, 0x58, 0x0A, 0x74, 0x42, 0x5C, 0xBB, 0xAD, 0x07, 0x97, 0xED, 0xEB, 0x82, 0x8A, 0x6F, + 0x93, 0xC2, 0x85, 0x96, 0xFD, 0x8A, 0xDC, 0xD4, 0x3B, 0x66, 0x44, 0x0A, 0xE5, 0x6E, 0x69, 0x34, + 0x78, 0x23, 0x22, 0x26, 0x23, 0x54, 0x55, 0xA7, 0x59, 0x8C, 0x88, 0x58, 0xDD, 0x32, 0x02, 0x18, + 0xA2, 0x33, 0x99, 0x42, 0xB0, 0x3B, 0x59, 0x51, 0x23, 0x4C, 0xBB, 0xA4, 0x4F, 0x05, 0x76, 0xF0, + 0xD5, 0x6E, 0xB8, 0xA0, 0x98, 0x93, 0x82, 0x58, 0x88, 0x8D, 0x54, 0x09, 0x23, 0x60, 0x95, 0x03, + 0x4C, 0x5D, 0xE5, 0x53, 0x17, 0x6F, 0x8D, 0x77, 0x55, 0x42, 0x8B, 0xE7, 0x98, 0x46, 0x92, 0xF5, + 0xF1, 0x2A, 0x5E, 0xD3, 0x00, 0x9E, 0x9B, 0xBF, 0xC6, 0xB2, 0xBD, 0x09, 0x32, 0x7D, 0xA9, 0x1A, + 0x8B, 0x48, 0x28, 0xC8, 0x66, 0xAD, 0xC6, 0x36, 0x91, 0x5D, 0xA3, 0xCC, 0x0D, 0x56, 0x49, 0xAB, + 0xBA, 0xA6, 0x09, 0x15, 0x3A, 0xDB, 0x23, 0x87, 0xCA, 0x0F, 0x9B, 0x1C, 0x9E, 0x89, 0x0E, 0xF1, + 0x43, 0x81, 0xF4, 0x9A, 0x92, 0x74, 0xA9, 0xF2, 0x2F, 0x68, 0x6D, 0x62, 0x22, 0xCA, 0xCD, 0x1A, + 0x84, 0xCF, 0xE4, 0x0D, 0x8D, 0xC3, 0xE4, 0xA8, 0x8F, 0xC5, 0x02, 0xBC, 0x11, 0xC0, 0xF0, 0x8B, + 0x0F, 0xCE, 0xD9, 0x3D, 0x31, 0x19, 0xAD, 0x4D, 0x50, 0x2E, 0xED, 0x1E, 0x85, 0xEF, 0x0F, 0xDA, + 0x81, 0x5D, 0xD7, 0x75, 0xC3, 0xEC, 0x84, 0x47, 0x8C, 0x8A, 0xCC, 0x44, 0x46, 0x4F, 0xD4, 0xAD, + 0x03, 0x53, 0x3E, 0xDE, 0x36, 0x78, 0x8A, 0x0B, 0x68, 0xF6, 0xB8, 0x9F, 0x2E, 0xB3, 0xF6, 0x91, + 0x2A, 0x5B, 0xBB, 0x76, 0xF9, 0x98, 0x6B, 0xA1, 0x75, 0x30, 0x06, 0x79, 0x01, 0xFE, 0x14, 0x63, + 0x90, 0x20, 0x98, 0xE8, 0x3B, 0x84, 0x5F, 0xC0, 0x40, 0xC4, 0x4F, 0x85, 0x4C, 0x1A, 0xC9, 0x40, + 0x38, 0xB4, 0xA2, 0x68, 0x57, 0xA2, 0x91, 0x81, 0x93, 0x6D, 0xE8, 0xAD, 0x70, 0x47, 0x15, 0xC2, + 0xA8, 0x64, 0xA3, 0xDF, 0x6B, 0xE3, 0xF9, 0x0B, 0x47, 0x28, 0x21, 0xE2, 0x21, 0x14, 0xCA, 0x69, + 0x1C, 0xE1, 0xA9, 0xE8, 0xF0, 0x1C, 0xDE, 0x3F, 0x83, 0xDA, 0x66, 0xD0, 0x83, 0x2B, 0x93, 0x17, + 0xFF, 0x68, 0x76, 0xFD, 0x8D, 0xEB, 0x05, 0x6B, 0x61, 0xEC, 0xF7, 0x2B, 0xAF, 0x4F, 0x09, 0xB0, + 0xD8, 0x0F, 0xC7, 0x1D, 0x13, 0xE3, 0x4D, 0x3A, 0x02, 0x68, 0x03, 0x3F, 0x53, 0x49, 0x80, 0x02, + 0x34, 0xEE, 0x99, 0xD1, 0x3D, 0xBB, 0xD6, 0xB3, 0x75, 0x91, 0x0C, 0xD6, 0x3D, 0x73, 0xEB, 0xE6, + 0x20, 0xEE, 0x60, 0xF2, 0xCA, 0x0E, 0x5E, 0x86, 0x18, 0x5D, 0x95, 0xF3, 0xB3, 0x0D, 0xDD, 0x8C, + 0xA9, 0x54, 0x44, 0x6C, 0xAB, 0xBC, 0x87, 0x1E, 0xCB, 0xC1, 0x68, 0xF3, 0xF2, 0xBE, 0x9E, 0xBA, + 0x1C, 0x4B, 0x46, 0x64, 0xBB, 0x98, 0xF0, 0x7B, 0x48, 0x79, 0xF5, 0xD7, 0x28, 0x8F, 0xB0, 0x51, + 0x01, 0x16, 0xFA, 0x3E, 0x8A, 0x44, 0x88, 0x20, 0x30, 0x8D, 0x21, 0xD7, 0x4F, 0x49, 0x61, 0x69, + 0x4D, 0x5C, 0xBF, 0x02, 0x1E, 0x3E, 0xBB, 0xA1, 0xAB, 0x2E, 0x53, 0x9F, 0xFB, 0xC2, 0xF6, 0x1F, + 0x3F, 0x28, 0xAC, 0xB9, 0xBC, 0x7E, 0x8B, 0xDF, 0xFA, 0xFF, 0x40, 0xF8, 0x3C, 0xEE, 0x32, 0x03, + 0xB1, 0x31, 0x96, 0x6E, 0xA6, 0x2D, 0x09, 0xA2, 0xFC, 0x45, 0x1A, 0xFE, 0xFB, 0xC5, 0x97, 0xC3, + 0x07, 0xD8, 0xEF, 0xED, 0xFC, 0xDE, 0x75, 0xEF, 0x7D, 0x2F, 0x9E, 0xA1, 0x2A, 0xB8, 0x1E, 0xA3, + 0xF2, 0xB7, 0x7A, 0x7E, 0xC2, 0xD1, 0xBE, 0xCD, 0xD0, 0xAE, 0x7F, 0x16, 0x83, 0x3E, 0xDA, 0x22, + 0x31, 0x3C, 0x43, 0x04, 0x3A, 0x42, 0x91, 0x47, 0x3D, 0x14, 0x3E, 0xF4, 0x87, 0x6E, 0x54, 0xC9, + 0x2C, 0xBE, 0x36, 0x8C, 0x37, 0xE3, 0x1A, 0x3E, 0x86, 0x17, 0xC7, 0x07, 0x1C, 0x3B, 0x74, 0xF1, + 0xCB, 0x87, 0xAE, 0x1C, 0x07, 0x41, 0xE2, 0x31, 0x50, 0x34, 0x72, 0xAF, 0x0E, 0x20, 0x1E, 0x10, + 0xA0, 0xAE, 0x5F, 0x81, 0x2F, 0x1E, 0xC7, 0xC4, 0xC7, 0x2E, 0x1B, 0xC7, 0xC4, 0xC7, 0x36, 0x8C, + 0x23, 0x4D, 0x35, 0xCB, 0xB0, 0x49, 0x79, 0xB7, 0x7A, 0x00, 0x8F, 0xE3, 0xDF, 0xFF, 0xD1, 0x1D, + 0xC5, 0x75, 0xDF, 0xC3, 0xE3, 0xB0, 0x30, 0xF7, 0x7C, 0x1B, 0xFD, 0x77, 0xBC, 0xCE, 0x75, 0x2C, + 0x59, 0xA2, 0x3E, 0xDE, 0x31, 0xAA, 0xC9, 0x02, 0x87, 0x1F, 0xC7, 0x1A, 0x55, 0xAA, 0x91, 0x44, + 0x05, 0x6C, 0x2E, 0x06, 0x6F, 0x48, 0x65, 0xD8, 0xB3, 0x6B, 0x9E, 0x34, 0xD7, 0xFC, 0x1A, 0xFA, + 0x6D, 0x36, 0x38, 0x62, 0x07, 0xD2, 0x05, 0xDF, 0xB0, 0xE1, 0x5B, 0x67, 0x31, 0x22, 0xEB, 0xDA, + 0xFA, 0x4D, 0xCF, 0x11, 0x83, 0xF1, 0xB9, 0xE7, 0x53, 0xB1, 0x1B, 0x11, 0x82, 0x60, 0x86, 0x3C, + 0x86, 0x69, 0x21, 0x02, 0xE1, 0x37, 0xD1, 0xE8, 0xA6, 0xF1, 0x71, 0x49, 0x76, 0xD2, 0x59, 0x27, + 0xDD, 0xDF, 0x11, 0xD3, 0xAD, 0xBA, 0x2D, 0xDD, 0x9A, 0xEF, 0x68, 0x36, 0x9D, 0xC8, 0xCD, 0xD6, + 0xDE, 0x73, 0x8C, 0xA7, 0xE4, 0x60, 0xC8, 0x03, 0xD9, 0x7C, 0x16, 0x85, 0x45, 0xAB, 0xBA, 0x77, + 0x53, 0xB9, 0xC0, 0xF2, 0xA1, 0x50, 0x39, 0xD2, 0x1C, 0x6B, 0xEE, 0xF5, 0x21, 0x9E, 0x35, 0x0F, + 0xC4, 0x49, 0x5A, 0xAE, 0xCC, 0x5F, 0x78, 0x6E, 0x16, 0xC9, 0xF9, 0x21, 0xAD, 0x84, 0x2B, 0x78, + 0x84, 0xE1, 0xD5, 0x5F, 0x62, 0x3A, 0xF8, 0x0E, 0x18, 0x05, 0x7D, 0x70, 0xAC, 0x5F, 0xC9, 0x3B, + 0xB4, 0x1E, 0xC5, 0xFA, 0x30, 0x77, 0x72, 0x7A, 0xEC, 0x16, 0xFF, 0xCD, 0x1C, 0x11, 0x5D, 0xAE, + 0xA7, 0x97, 0x4B, 0x53, 0x37, 0xD1, 0xCD, 0x8E, 0x19, 0xEA, 0x20, 0x31, 0x81, 0xAA, 0x21, 0x04, + 0xEA, 0xB7, 0x97, 0x4E, 0xC3, 0xEA, 0x25, 0x71, 0x7A, 0xC1, 0xFD, 0xF7, 0x80, 0x06, 0x7E, 0xC1, + 0xFF, 0x78, 0xDE, 0xCF, 0x01, 0x05, 0x1E, 0x72, 0x9D, 0x56, 0xD8, 0x0C, 0x55, 0xCF, 0x0F, 0x29, + 0x7D, 0xDA, 0x15, 0x30, 0xA6, 0x47, 0xE9, 0xAE, 0xEE, 0x73, 0xDD, 0x82, 0x2E, 0x32, 0x6C, 0x37, + 0x08, 0x2C, 0x61, 0xD6, 0xDC, 0x4B, 0x1E, 0xE2, 0xC0, 0xD2, 0xB3, 0xB1, 0xE1, 0x2B, 0xD4, 0x86, + 0x0F, 0x08, 0xE2, 0xCF, 0x0F, 0xF8, 0x62, 0xF6, 0x78, 0x68, 0x6A, 0xF9, 0xBE, 0xFD, 0x99, 0x31, + 0x53, 0xD9, 0x31, 0x49, 0xFB, 0xAB, 0x9B, 0xFF, 0xF0, 0x81, 0x57, 0xBC, 0xF3, 0x7D, 0xAF, 0x59, + 0xBA, 0x23, 0xBB, 0xAB, 0xFE, 0xCE, 0x13, 0xEF, 0xFF, 0xFE, 0xF7, 0x9E, 0x7C, 0xCB, 0x57, 0x2F, + 0xFE, 0x28, 0x17, 0x1F, 0x5D, 0x28, 0xA4, 0xEA, 0xB3, 0xF0, 0x93, 0x6F, 0x78, 0x6B, 0x28, 0xE4, + 0x8B, 0x1D, 0x99, 0x3F, 0xFE, 0xC6, 0x68, 0xAA, 0x75, 0x71, 0xD5, 0x56, 0x83, 0x37, 0x6E, 0xBB, + 0xF3, 0xE5, 0xEF, 0x7B, 0xE8, 0x91, 0x77, 0x16, 0x73, 0xDB, 0xF7, 0xFC, 0xC3, 0xBB, 0xFE, 0xF8, + 0x1F, 0xDF, 0xF6, 0x97, 0xE9, 0x91, 0x83, 0x13, 0xD9, 0xD1, 0xC3, 0x58, 0xEE, 0xAC, 0xFE, 0x04, + 0xDB, 0x27, 0x2F, 0xA0, 0x7F, 0x00, 0x65, 0x8C, 0x25, 0xFB, 0x7D, 0xBB, 0x56, 0x31, 0x40, 0x95, + 0x38, 0x5C, 0xAF, 0xDC, 0xC5, 0xD5, 0xEE, 0x1C, 0x31, 0x79, 0x36, 0xF6, 0x5F, 0x8D, 0x99, 0x75, + 0x4C, 0xC2, 0xC1, 0x48, 0xAF, 0xEB, 0x0E, 0xB9, 0x80, 0x4F, 0xBC, 0x09, 0xB8, 0xA4, 0xEC, 0xEB, + 0x86, 0xE7, 0x1F, 0xCD, 0x62, 0x95, 0x47, 0x78, 0x88, 0xCA, 0xB5, 0xC5, 0xA6, 0xC8, 0x1E, 0xC2, + 0x10, 0xAB, 0x85, 0x25, 0x6A, 0x84, 0x8E, 0xC2, 0x74, 0x96, 0x70, 0xD0, 0x0B, 0xE9, 0x7D, 0x96, + 0x3F, 0x16, 0x0B, 0xD9, 0x6F, 0x79, 0x0D, 0x4D, 0xD2, 0x88, 0x3A, 0x29, 0x15, 0x34, 0x2D, 0xD3, + 0x1D, 0xED, 0xC9, 0x51, 0x83, 0x89, 0x26, 0x62, 0x1A, 0xEB, 0xA3, 0x05, 0x42, 0x1A, 0x5F, 0x72, + 0x4A, 0x35, 0x2D, 0x74, 0xF1, 0xAF, 0x6F, 0x39, 0x71, 0x70, 0x5B, 0x78, 0x02, 0xE5, 0x9A, 0x95, + 0x3C, 0x82, 0x58, 0x82, 0x2A, 0x85, 0x1A, 0x2D, 0xD3, 0xFE, 0xA9, 0xC7, 0xEF, 0x7E, 0x75, 0xF5, + 0xC0, 0x38, 0x21, 0x9B, 0x2A, 0x4B, 0xF2, 0x5A, 0x46, 0xC8, 0x3E, 0xFE, 0xA1, 0xCA, 0xAE, 0x05, + 0x82, 0xFA, 0xD0, 0xEA, 0x2A, 0x5E, 0x6F, 0xB4, 0x7A, 0x7E, 0xF5, 0x37, 0xE8, 0x10, 0xFA, 0x6B, + 0x90, 0x03, 0x9B, 0xC1, 0x74, 0x3F, 0xB4, 0xA9, 0x9A, 0x74, 0x34, 0xE4, 0x58, 0xB3, 0xC9, 0x2D, + 0x9D, 0xA9, 0x60, 0x13, 0xC5, 0xA6, 0x3A, 0xC8, 0x08, 0xBE, 0x4C, 0x78, 0x78, 0xA3, 0xBA, 0x74, + 0xDD, 0x58, 0x60, 0x30, 0xAE, 0x0D, 0x5A, 0x72, 0xCB, 0x50, 0x4B, 0xD2, 0x0C, 0x06, 0xF9, 0x1E, + 0xCD, 0x56, 0x11, 0x5E, 0x42, 0xD7, 0xE1, 0xBF, 0x86, 0x99, 0xB1, 0xF6, 0xC4, 0x6A, 0x9E, 0xA9, + 0xA0, 0x2A, 0xC2, 0x36, 0x01, 0xF2, 0xF4, 0x89, 0xA9, 0x5B, 0xAE, 0x31, 0xD0, 0xA8, 0x37, 0xDC, + 0x06, 0xB4, 0x42, 0xA4, 0x47, 0x04, 0x25, 0x18, 0x3C, 0xD4, 0x13, 0xC2, 0x93, 0x9B, 0x74, 0x49, + 0xE3, 0x67, 0x26, 0xEF, 0x0F, 0x4F, 0x07, 0x6F, 0xB9, 0x7B, 0x5F, 0xA9, 0x29, 0x63, 0x50, 0x6D, + 0x05, 0x5E, 0x6D, 0x54, 0xC2, 0x01, 0xBF, 0x00, 0xD5, 0x7C, 0x4E, 0xAF, 0xC6, 0xD2, 0x85, 0x18, + 0x32, 0xA4, 0xF8, 0xAC, 0x46, 0xD3, 0x6C, 0x32, 0x0F, 0x73, 0x9A, 0x12, 0xEF, 0x96, 0x45, 0xC1, + 0x30, 0x17, 0x09, 0xC6, 0xA2, 0xA8, 0xC7, 0x6E, 0xFD, 0xE1, 0x76, 0x82, 0xBE, 0x93, 0xE6, 0x95, + 0xEA, 0x4C, 0xAA, 0x53, 0x11, 0x25, 0x59, 0x31, 0x2B, 0x53, 0xB1, 0xB8, 0xCC, 0xD0, 0x84, 0x41, + 0x8A, 0x99, 0x9C, 0x51, 0x0D, 0x2B, 0x12, 0xB5, 0xF5, 0xE2, 0xD7, 0xB7, 0x70, 0x48, 0xE0, 0x11, + 0x55, 0x4F, 0x46, 0x5D, 0xF9, 0x18, 0x5C, 0xFD, 0x25, 0xEA, 0xA2, 0x2F, 0x62, 0x4E, 0x2F, 0xF5, + 0xF5, 0x62, 0x58, 0x01, 0x99, 0x7A, 0xB9, 0x51, 0xBB, 0xBF, 0x91, 0xBC, 0xD7, 0xEF, 0x7F, 0x80, + 0x3E, 0xED, 0x5A, 0x0F, 0xEA, 0x15, 0x6B, 0xDB, 0x50, 0xF0, 0xDA, 0xBA, 0x6E, 0x12, 0x3C, 0xF8, + 0xA4, 0xEB, 0xC4, 0x73, 0x2D, 0x55, 0xB2, 0xE1, 0xF9, 0xEE, 0x3C, 0xE8, 0x30, 0x60, 0x6D, 0x73, + 0xE0, 0x3C, 0x6D, 0xA3, 0x6E, 0xAC, 0xDE, 0xCE, 0x58, 0x58, 0x1C, 0x72, 0x3B, 0x5F, 0xDE, 0x71, + 0x24, 0x3B, 0xC1, 0x09, 0x76, 0xF9, 0xE0, 0x1F, 0x8C, 0x96, 0xEB, 0x61, 0x51, 0xAA, 0xEA, 0x21, + 0x63, 0x6F, 0x7A, 0x6C, 0x2B, 0xC7, 0xF4, 0xFF, 0xAA, 0x99, 0xCD, 0xDF, 0xE8, 0xCF, 0x25, 0x14, + 0x02, 0x31, 0xFB, 0x8E, 0x4E, 0x4C, 0x65, 0x72, 0x5B, 0x27, 0x54, 0x31, 0x9C, 0xED, 0x16, 0x94, + 0x90, 0x80, 0xD1, 0x52, 0x56, 0x32, 0xC2, 0xC9, 0xED, 0xDB, 0x54, 0xD2, 0x1A, 0xFB, 0xF4, 0xA2, + 0xE0, 0xAD, 0xE9, 0xAF, 0xD0, 0x87, 0xD0, 0x5F, 0x61, 0x39, 0x35, 0x06, 0xB6, 0xF5, 0x13, 0x96, + 0xA5, 0xB5, 0x26, 0xC7, 0x8B, 0x95, 0x07, 0x43, 0xB6, 0xA8, 0xD4, 0x6B, 0x23, 0x95, 0x6A, 0x05, + 0x69, 0xAA, 0x92, 0x41, 0xC0, 0x1F, 0x7A, 0x39, 0xF7, 0xF0, 0x9A, 0xA5, 0x30, 0xF4, 0x59, 0x76, + 0x5D, 0xDB, 0xE0, 0xFC, 0xC0, 0x5F, 0xE4, 0x49, 0x63, 0x6F, 0x91, 0x5D, 0x9C, 0x6A, 0x79, 0xDC, + 0xCA, 0xB8, 0xD8, 0xA7, 0x0A, 0x47, 0xF5, 0x26, 0x06, 0x6E, 0xF4, 0x60, 0x71, 0x27, 0x60, 0xBB, + 0x1E, 0x21, 0x19, 0x0F, 0x21, 0xA0, 0x64, 0x26, 0x91, 0xB4, 0xF0, 0x3A, 0xBB, 0x0E, 0x62, 0xF4, + 0x21, 0x25, 0xAC, 0x4E, 0x14, 0xAE, 0xDB, 0x53, 0xAD, 0x1E, 0x6F, 0x0A, 0x10, 0xC6, 0x6A, 0x81, + 0xFC, 0xAB, 0x04, 0x43, 0x0D, 0x34, 0xFC, 0x8B, 0xAF, 0x3E, 0x39, 0x99, 0xB1, 0x1F, 0x86, 0xB0, + 0xFF, 0x67, 0x8E, 0xC1, 0x5A, 0x34, 0x01, 0x61, 0x65, 0x8F, 0x9F, 0x9E, 0x9F, 0x86, 0x77, 0x95, + 0xEB, 0x8D, 0x58, 0x2F, 0x35, 0x97, 0xF5, 0xCB, 0x93, 0x70, 0x7E, 0xAA, 0x57, 0x43, 0x24, 0xFB, + 0x00, 0x22, 0x60, 0x60, 0x7C, 0xBE, 0xB3, 0xED, 0x3D, 0xBC, 0x4A, 0x8D, 0x7C, 0x0E, 0xCB, 0xE7, + 0xC7, 0x9E, 0xE8, 0x1C, 0x09, 0xB2, 0xB0, 0x0F, 0xE0, 0xEA, 0x4F, 0x31, 0x8B, 0x1E, 0x42, 0x9F, + 0x07, 0xE3, 0xE0, 0xC9, 0xFE, 0x8E, 0xE6, 0x68, 0x23, 0x1F, 0xB3, 0x34, 0x1E, 0xB0, 0x46, 0xA6, + 0x2A, 0x8E, 0x51, 0xD5, 0xB4, 0xC1, 0xA6, 0x0D, 0x7F, 0xDA, 0x68, 0x6A, 0xE0, 0x15, 0x13, 0xE9, + 0x87, 0x42, 0x95, 0xB2, 0xF6, 0x60, 0x26, 0x55, 0x56, 0xCB, 0x99, 0x4A, 0xF5, 0xB1, 0xCC, 0xF8, + 0xD8, 0x63, 0x94, 0x65, 0x3E, 0x12, 0xF5, 0x27, 0x42, 0xC8, 0xA8, 0x65, 0xD2, 0xC8, 0x54, 0x15, + 0x91, 0x34, 0x62, 0x4F, 0xF0, 0x14, 0x09, 0x2F, 0x85, 0xD3, 0xBA, 0x6B, 0xF6, 0x36, 0x9E, 0x8F, + 0xA1, 0xF5, 0x54, 0x1D, 0x38, 0xE0, 0x43, 0x70, 0xA7, 0xE7, 0x8C, 0xEF, 0x7A, 0xE4, 0x70, 0x7E, + 0x83, 0x42, 0xDF, 0xA8, 0xD7, 0xD7, 0xB9, 0x64, 0x42, 0x1B, 0x04, 0x48, 0x5C, 0x11, 0x80, 0x59, + 0xA3, 0x07, 0x47, 0x5B, 0x93, 0x90, 0x69, 0xB5, 0xB3, 0xCC, 0xC0, 0x1F, 0x84, 0x27, 0xAD, 0xD1, + 0xC6, 0xD4, 0x92, 0x64, 0x1C, 0x2C, 0xF4, 0x64, 0x84, 0xE1, 0xB1, 0x83, 0x61, 0x25, 0x63, 0xB9, + 0xED, 0xE8, 0x90, 0x95, 0x8B, 0xF8, 0x26, 0x8E, 0xDC, 0x37, 0x6E, 0x85, 0x11, 0x24, 0x1F, 0xDD, + 0x34, 0x01, 0x1F, 0x2A, 0x66, 0xE2, 0x76, 0xE4, 0x20, 0x9D, 0xF9, 0x1B, 0x67, 0xAB, 0xBE, 0x67, + 0xE4, 0xE0, 0x0A, 0x9C, 0x79, 0x78, 0x46, 0x9F, 0x99, 0xDF, 0x12, 0xA5, 0x5D, 0x0F, 0xD7, 0xE8, + 0x93, 0xE2, 0xEC, 0x7D, 0x81, 0x72, 0xD4, 0x76, 0xCD, 0x33, 0x54, 0x4C, 0x86, 0xDE, 0xA0, 0xA7, + 0x51, 0x75, 0xE6, 0x23, 0x30, 0x82, 0x61, 0x31, 0x81, 0x48, 0x5A, 0xDF, 0xEF, 0x27, 0xDF, 0x88, + 0x60, 0x70, 0x31, 0x80, 0x60, 0x3E, 0x33, 0x17, 0xA3, 0x39, 0x0C, 0x02, 0xDC, 0x39, 0x5D, 0x7D, + 0x16, 0x2D, 0xA1, 0xAF, 0x80, 0x06, 0xB8, 0xBF, 0x3F, 0x56, 0xCC, 0x06, 0x35, 0x50, 0xCC, 0x67, + 0x93, 0xB1, 0x68, 0x32, 0x29, 0xD9, 0x29, 0xC9, 0x2E, 0x89, 0x29, 0xC7, 0x7E, 0x85, 0x2C, 0xD1, + 0xAF, 0x28, 0xD5, 0x5F, 0xC6, 0xB1, 0xCC, 0x43, 0x3E, 0x14, 0x76, 0x24, 0x11, 0x45, 0x23, 0xE1, + 0x10, 0x99, 0x02, 0x6F, 0x0A, 0xCE, 0x9D, 0x85, 0xC5, 0x35, 0x15, 0xE8, 0xDB, 0x30, 0x79, 0xE7, + 0x40, 0x15, 0xCE, 0xBA, 0x56, 0x02, 0x9E, 0x45, 0x17, 0x9C, 0xC1, 0x4B, 0x33, 0xE5, 0xB9, 0xA9, + 0x36, 0x1A, 0xA3, 0xA3, 0xC5, 0xA1, 0xB7, 0x2A, 0xE9, 0x3E, 0x85, 0x3D, 0x10, 0xED, 0x19, 0x76, + 0x0C, 0x06, 0xDB, 0x4C, 0x0F, 0x7A, 0x14, 0x98, 0x6C, 0x8F, 0x66, 0x9A, 0x5E, 0x68, 0x71, 0x38, + 0x79, 0x68, 0x69, 0x06, 0x43, 0xCE, 0x74, 0xE4, 0xA0, 0x93, 0x81, 0xE8, 0x40, 0xA5, 0xBF, 0xB5, + 0x25, 0xE7, 0x6A, 0xD7, 0x3A, 0x4C, 0xBA, 0xD1, 0x86, 0x10, 0x86, 0xD5, 0xBE, 0x7A, 0x3F, 0xE5, + 0xF7, 0xA7, 0xD3, 0x8F, 0x85, 0xAA, 0x89, 0xCC, 0x87, 0xD2, 0x5B, 0xD1, 0x57, 0x7A, 0x01, 0x41, + 0x57, 0xF0, 0x6A, 0x73, 0xC5, 0xD8, 0x34, 0xCD, 0x4E, 0x28, 0x15, 0x03, 0xFE, 0x4F, 0x27, 0x9A, + 0x3F, 0x10, 0xB8, 0x7F, 0x05, 0xA1, 0xE3, 0xB9, 0xFB, 0x78, 0x08, 0xEF, 0x26, 0x11, 0x45, 0xBB, + 0x72, 0x21, 0x8C, 0xF1, 0xC6, 0xDB, 0xD1, 0x97, 0x41, 0x0F, 0x94, 0xFB, 0xFA, 0x78, 0x23, 0x84, + 0xA6, 0x6A, 0x66, 0x3F, 0xF6, 0x66, 0x5F, 0x0E, 0xA9, 0xBE, 0x96, 0xF8, 0xF0, 0xBA, 0x43, 0x69, + 0xA3, 0x60, 0xE8, 0xAB, 0x43, 0x2D, 0x4F, 0x0C, 0x05, 0x63, 0x76, 0x74, 0x8A, 0x6A, 0x78, 0x02, + 0x11, 0xB9, 0x4E, 0x11, 0xCF, 0xA5, 0x4F, 0x79, 0x0A, 0xCF, 0x33, 0xF2, 0xDA, 0xAE, 0x87, 0x04, + 0xBD, 0x85, 0xAA, 0xC7, 0x5A, 0x96, 0x5F, 0xD7, 0xA6, 0xA7, 0x6E, 0xB9, 0x67, 0x82, 0x2D, 0xEE, + 0xDB, 0xB4, 0x75, 0x77, 0x53, 0x6B, 0xE4, 0xA3, 0xDA, 0x9E, 0x00, 0x1B, 0x6E, 0x95, 0xAA, 0x8B, + 0x41, 0x5A, 0x43, 0xCD, 0x87, 0xC7, 0x84, 0x6C, 0x95, 0x60, 0x7C, 0xDB, 0x84, 0x30, 0x63, 0x37, + 0x33, 0x9B, 0xE1, 0xBC, 0xAD, 0x56, 0x76, 0x64, 0xAB, 0x8A, 0x2C, 0x70, 0xC9, 0xC7, 0x8F, 0xEC, + 0xBE, 0xEA, 0xDE, 0x03, 0x95, 0xBC, 0x4A, 0x51, 0x9C, 0xA3, 0x69, 0x62, 0x53, 0xE1, 0xFD, 0xC9, + 0xCE, 0x72, 0xD9, 0x37, 0xD2, 0x67, 0xEE, 0xDE, 0xCE, 0x8E, 0x14, 0x25, 0xCD, 0x37, 0x1F, 0x20, + 0x1C, 0x46, 0x4D, 0xE1, 0xB1, 0x2D, 0xAC, 0x3E, 0x47, 0x70, 0xE8, 0x5B, 0x60, 0x19, 0xFC, 0x97, + 0xFE, 0x72, 0xAB, 0x91, 0x53, 0xC0, 0xF2, 0x44, 0x16, 0x4C, 0x44, 0x46, 0xE4, 0x07, 0x0F, 0x8A, + 0x6F, 0x3B, 0x98, 0x36, 0x0F, 0x5A, 0xD3, 0x07, 0x47, 0xB7, 0x6D, 0x4D, 0xEC, 0xD8, 0xB5, 0xF3, + 0xF9, 0xDE, 0xD4, 0xEC, 0xFD, 0xC1, 0xDE, 0x54, 0x3F, 0x15, 0x0E, 0xB1, 0x34, 0x45, 0x2C, 0xB3, + 0x8B, 0x0B, 0x73, 0xB3, 0xE4, 0x3C, 0xC2, 0x86, 0x30, 0xDA, 0xBF, 0x6F, 0xF7, 0xAE, 0x9D, 0x3B, + 0xB6, 0x6F, 0xDB, 0xBA, 0x85, 0xA5, 0x45, 0x66, 0xAA, 0x13, 0x25, 0x22, 0x68, 0x64, 0xCB, 0xDB, + 0x57, 0xCA, 0x25, 0xD8, 0x18, 0x72, 0xD4, 0xC0, 0x55, 0xE8, 0x74, 0x3D, 0xC2, 0x50, 0xBD, 0x40, + 0x89, 0xD3, 0xC5, 0xD4, 0x11, 0x84, 0xD7, 0xBA, 0xCA, 0x73, 0xE0, 0xBC, 0xEC, 0x9D, 0x3F, 0x07, + 0xB6, 0xC3, 0xEB, 0x7B, 0xE7, 0xDD, 0x93, 0x26, 0xB6, 0x2E, 0xCF, 0x0F, 0x64, 0xEE, 0x25, 0xC7, + 0xC5, 0x25, 0x62, 0x39, 0xD8, 0xC0, 0x93, 0x4C, 0xBB, 0x72, 0x16, 0x39, 0x9E, 0xC1, 0xE5, 0xB9, + 0x2C, 0xF0, 0xEC, 0x56, 0xC9, 0xA4, 0xE2, 0x5A, 0xD2, 0xB6, 0xE7, 0xA7, 0x76, 0xE8, 0x35, 0xA3, + 0xA5, 0x0A, 0x27, 0x91, 0x6B, 0xB8, 0x31, 0x98, 0xBD, 0x1A, 0x98, 0xD9, 0x7A, 0x68, 0x12, 0xF6, + 0x88, 0x30, 0x6D, 0xD2, 0x61, 0x68, 0xDA, 0x16, 0xC1, 0x25, 0x52, 0x02, 0xB6, 0x2B, 0x20, 0x54, + 0x82, 0xB4, 0xCC, 0x0B, 0xD3, 0x44, 0xAD, 0xA0, 0x33, 0x41, 0x8A, 0xA0, 0x60, 0xE1, 0x7C, 0x38, + 0xCA, 0x50, 0xAC, 0x2C, 0xB0, 0xE2, 0x26, 0x73, 0x9C, 0x67, 0x0C, 0x8E, 0xA4, 0x90, 0x95, 0x65, + 0x97, 0x30, 0x7D, 0xA5, 0x33, 0x9D, 0x33, 0x1D, 0x08, 0x33, 0x99, 0x78, 0x1C, 0x52, 0xF0, 0x91, + 0x7C, 0x44, 0x50, 0x28, 0x55, 0x29, 0xB6, 0xD3, 0x1C, 0xAF, 0x97, 0x88, 0x64, 0x88, 0x49, 0xC5, + 0x1E, 0xDD, 0x47, 0x20, 0x62, 0xDC, 0x29, 0x26, 0x79, 0x81, 0x55, 0xB3, 0x6A, 0x8E, 0x0A, 0xD4, + 0x02, 0xDF, 0x7F, 0x63, 0x61, 0x7C, 0x93, 0xE0, 0xA3, 0x46, 0x37, 0x4F, 0x3D, 0xBC, 0x00, 0x11, + 0xEC, 0x74, 0x7A, 0xFD, 0x60, 0xC0, 0xF1, 0xF9, 0x2D, 0x43, 0x53, 0x24, 0x41, 0x4B, 0x68, 0x7C, + 0xFC, 0xB8, 0x9B, 0x49, 0x24, 0xAF, 0x3E, 0x0F, 0x9E, 0x45, 0x4F, 0x83, 0x00, 0x68, 0xF5, 0x2D, + 0x6C, 0x46, 0x8B, 0x24, 0x02, 0x01, 0x1A, 0xF9, 0x1D, 0x9F, 0xC9, 0x10, 0x8B, 0x67, 0xA1, 0xB2, + 0x91, 0xE9, 0xBA, 0x1E, 0x8F, 0x81, 0x75, 0xB8, 0x19, 0x54, 0x5C, 0x07, 0x34, 0x6A, 0x67, 0x06, + 0x96, 0x1C, 0x93, 0xED, 0x21, 0x0C, 0xA7, 0xA2, 0xC8, 0x32, 0x9E, 0x8D, 0xC7, 0xB6, 0x41, 0x92, + 0xA2, 0x69, 0x49, 0x92, 0x38, 0x99, 0xBE, 0x3B, 0x22, 0x89, 0x41, 0x1A, 0x21, 0x6A, 0x97, 0x6D, + 0x35, 0xBF, 0xF4, 0xC9, 0x4C, 0x67, 0xB4, 0xE8, 0x98, 0x82, 0x4E, 0xED, 0xD0, 0x99, 0x98, 0xDE, + 0x63, 0x2F, 0x1E, 0xF3, 0x7C, 0xB6, 0x71, 0xF0, 0x4B, 0xF4, 0x4D, 0x90, 0x05, 0x53, 0xFD, 0xA0, + 0xCD, 0x00, 0x4B, 0xCB, 0x66, 0x12, 0x71, 0x32, 0x92, 0x96, 0x50, 0x5A, 0x44, 0x89, 0x78, 0x3A, + 0xF8, 0x0E, 0xFA, 0x8F, 0xA1, 0xBD, 0xC1, 0xCA, 0xEE, 0x7A, 0x12, 0xD2, 0xE9, 0x0E, 0x3B, 0xE4, + 0xF6, 0x28, 0x67, 0x53, 0x45, 0xC7, 0x03, 0x41, 0xD9, 0x29, 0xA2, 0x99, 0xF5, 0xD0, 0xAF, 0x82, + 0xB2, 0x83, 0xB0, 0x97, 0x0B, 0x26, 0xF0, 0x5A, 0xD0, 0x56, 0x14, 0xFE, 0x52, 0x67, 0x6F, 0xE0, + 0x42, 0x61, 0x59, 0xB5, 0x1C, 0x9E, 0x10, 0x75, 0x9D, 0xE3, 0x44, 0x42, 0x59, 0x8A, 0xCC, 0x29, + 0x92, 0x9F, 0x83, 0x18, 0xEF, 0xB7, 0x14, 0x66, 0x2F, 0x13, 0x88, 0xF8, 0xB5, 0xCC, 0xC2, 0xC9, + 0x9B, 0xDE, 0xFA, 0xE8, 0x5D, 0x93, 0x24, 0x05, 0xCD, 0x8C, 0x59, 0xE6, 0xCA, 0x71, 0x5F, 0xD1, + 0xD0, 0xAA, 0xCF, 0x4F, 0x2C, 0x6D, 0x76, 0xF3, 0x87, 0x56, 0x7F, 0x8E, 0x3E, 0x88, 0xFE, 0x11, + 0xE4, 0xC1, 0x1C, 0xB8, 0xB9, 0x5F, 0xE9, 0x34, 0x42, 0xB6, 0xC6, 0x32, 0x60, 0x62, 0xCC, 0xC7, + 0xC6, 0xA2, 0x48, 0x92, 0x65, 0x29, 0xFF, 0x27, 0xF3, 0xD9, 0x33, 0xF3, 0xCC, 0xBB, 0xE6, 0xC9, + 0x77, 0xCE, 0x57, 0x46, 0xE6, 0x0A, 0xB3, 0x68, 0xA4, 0xF7, 0xA7, 0x15, 0x0C, 0xE8, 0x3B, 0x1B, + 0x27, 0xD6, 0x8B, 0xA7, 0x80, 0x35, 0x62, 0x7C, 0xBC, 0x72, 0xEE, 0xBB, 0x7B, 0x47, 0xCF, 0x0A, + 0x9E, 0xCF, 0xE3, 0x45, 0x3E, 0xC5, 0xF9, 0xCE, 0x00, 0x16, 0x60, 0xF4, 0x9A, 0x75, 0xDC, 0x30, + 0x91, 0x07, 0xF3, 0xB3, 0x58, 0x0A, 0xF4, 0x06, 0xCE, 0x04, 0x05, 0x45, 0x49, 0x97, 0x34, 0xBD, + 0x70, 0xD6, 0x68, 0x0B, 0xAF, 0x4E, 0xD5, 0x83, 0x0A, 0xCC, 0xD0, 0xD9, 0x08, 0x2D, 0x07, 0x7D, + 0x30, 0x58, 0x19, 0x53, 0xA5, 0x30, 0x6F, 0x26, 0xFC, 0xBB, 0x2A, 0xD3, 0x6F, 0x49, 0x1B, 0x65, + 0xC1, 0xCF, 0x6F, 0x6A, 0xDA, 0xA9, 0x49, 0xDF, 0x89, 0x43, 0x12, 0x73, 0x92, 0xD9, 0xEE, 0x37, + 0x04, 0xF1, 0xE2, 0x96, 0x8C, 0x83, 0x97, 0x13, 0x32, 0x90, 0x26, 0x54, 0x55, 0x12, 0xF8, 0xAB, + 0x93, 0x15, 0xDE, 0x96, 0x09, 0xB8, 0xDB, 0x4A, 0xC7, 0x35, 0xC9, 0x28, 0xA7, 0xEE, 0x9E, 0x5F, + 0x79, 0x20, 0x65, 0x1A, 0x41, 0x93, 0x16, 0x50, 0xB5, 0x40, 0xCB, 0xE1, 0x98, 0x19, 0xBC, 0xFA, + 0x2A, 0x99, 0x7B, 0x2B, 0x77, 0x3C, 0x46, 0x87, 0x4C, 0x29, 0xEA, 0xDF, 0xFA, 0xDA, 0x85, 0xBF, + 0x2F, 0x30, 0x29, 0x15, 0x63, 0xC8, 0xF1, 0x60, 0x24, 0x73, 0xE2, 0x7F, 0xFD, 0x17, 0x8F, 0xEA, + 0x7E, 0x8D, 0xE6, 0xD0, 0x97, 0x40, 0x1A, 0xEC, 0xEC, 0x67, 0x1C, 0x89, 0x06, 0xB6, 0x01, 0x36, + 0x65, 0x38, 0xF6, 0x68, 0xFA, 0xDD, 0x64, 0xE2, 0x71, 0xAC, 0x29, 0x13, 0x88, 0x89, 0xC7, 0x10, + 0xCF, 0xB1, 0x04, 0x13, 0x7A, 0x92, 0xBE, 0x0C, 0x2D, 0x0E, 0x18, 0xDC, 0xD5, 0x9A, 0xEA, 0x05, + 0x97, 0x81, 0xD7, 0x40, 0x23, 0x9E, 0x9A, 0x8C, 0x33, 0x44, 0x4C, 0x71, 0xA6, 0x3D, 0x89, 0x46, + 0x33, 0x59, 0x3C, 0x2D, 0x68, 0xE8, 0x66, 0x45, 0xEE, 0xC8, 0xC3, 0x10, 0x33, 0x66, 0x03, 0x61, + 0x28, 0x90, 0x0F, 0x5E, 0xFC, 0xDB, 0x34, 0x24, 0x20, 0x41, 0x71, 0x18, 0xF2, 0x28, 0x14, 0xE7, + 0xAB, 0x75, 0x53, 0x4C, 0x4C, 0x40, 0x64, 0xE1, 0x13, 0x63, 0x8F, 0x66, 0x7C, 0xA5, 0x18, 0x31, + 0x36, 0x3A, 0x76, 0x55, 0x75, 0x5B, 0xAE, 0xEB, 0xF3, 0x55, 0xFD, 0x1C, 0x61, 0xD8, 0xA5, 0x9C, + 0xB4, 0xEB, 0x0D, 0xFF, 0x8D, 0xFF, 0x73, 0xDE, 0x95, 0xDB, 0x05, 0x2C, 0xDB, 0x7E, 0x83, 0x7E, + 0x08, 0x66, 0xC0, 0x4C, 0xDF, 0x37, 0x3D, 0x39, 0xDE, 0x6A, 0xA6, 0x62, 0xC1, 0xBC, 0x49, 0x3B, + 0x55, 0xA5, 0x7A, 0xD2, 0x37, 0xFE, 0xDE, 0x15, 0x14, 0x2C, 0x0D, 0xB3, 0x56, 0x5C, 0x57, 0x96, + 0x02, 0xAF, 0x71, 0xFD, 0x8A, 0x97, 0xB9, 0x47, 0x07, 0x7D, 0x9E, 0x0D, 0x7A, 0xAE, 0x6D, 0x77, + 0xFD, 0x30, 0xFB, 0x11, 0x1E, 0xCE, 0xC5, 0x3A, 0xC9, 0x8B, 0x8F, 0xF5, 0xC8, 0xEC, 0xC0, 0x52, + 0xF3, 0x82, 0x05, 0x04, 0x96, 0x27, 0x5E, 0x1E, 0x84, 0x2B, 0xE9, 0x89, 0x5F, 0x04, 0x6F, 0x32, + 0xC2, 0x39, 0xC1, 0xCF, 0x36, 0x1D, 0x3A, 0x9C, 0x6B, 0x07, 0x52, 0x0B, 0xBD, 0xEA, 0x2C, 0x27, + 0x14, 0x92, 0xE3, 0x49, 0x9B, 0xD5, 0x03, 0x6A, 0xC0, 0x67, 0x4B, 0xD2, 0x78, 0x9D, 0x8D, 0x9F, + 0xBA, 0x67, 0x77, 0xA2, 0x33, 0x17, 0xD0, 0xD8, 0xD3, 0xE5, 0x8A, 0xE9, 0x08, 0x9A, 0x38, 0xDE, + 0x5C, 0x50, 0x17, 0x5A, 0x07, 0xDE, 0x35, 0x9B, 0x15, 0xF7, 0xC5, 0x30, 0xC6, 0x4D, 0xD4, 0x7A, + 0xCD, 0x6D, 0xF5, 0xBB, 0xAB, 0x3E, 0x3B, 0x1D, 0x78, 0xB0, 0x7C, 0xCD, 0x83, 0x3B, 0xCB, 0xE5, + 0x96, 0xAC, 0xC9, 0x42, 0x22, 0x5A, 0xD9, 0xFA, 0xB9, 0xC7, 0xC6, 0xEE, 0xD9, 0xBC, 0x69, 0x2E, + 0x1F, 0xEA, 0x07, 0x83, 0x23, 0xDD, 0x68, 0xF1, 0xC4, 0x0F, 0x1E, 0xE1, 0xDD, 0x28, 0x08, 0xC6, + 0x84, 0xCF, 0xA1, 0x9F, 0xA2, 0x1F, 0x60, 0xBB, 0xEE, 0x54, 0xBF, 0x59, 0x8A, 0x31, 0x34, 0xE8, + 0x54, 0x8B, 0x79, 0x53, 0xEC, 0x74, 0x88, 0x5E, 0x97, 0xE8, 0x89, 0xD3, 0xD3, 0xF1, 0x44, 0x32, + 0x15, 0x0A, 0x5A, 0x44, 0xD8, 0xEA, 0x21, 0x44, 0x84, 0x82, 0x01, 0xBF, 0x45, 0xD9, 0x28, 0x05, + 0xDE, 0xB7, 0x12, 0x2B, 0x9D, 0x85, 0xA5, 0xCB, 0x7C, 0x17, 0xAE, 0xE0, 0xEE, 0x7A, 0xBC, 0xAC, + 0xBA, 0x8E, 0x33, 0xF5, 0x52, 0x54, 0x71, 0x63, 0xDE, 0x81, 0x6B, 0xE2, 0x95, 0x86, 0x2A, 0x3C, + 0x0C, 0x15, 0x3C, 0x39, 0xC8, 0xB5, 0x7A, 0x3C, 0x86, 0xB6, 0x3C, 0x15, 0x4E, 0xAC, 0x53, 0xBA, + 0x2B, 0x87, 0x06, 0xD1, 0xD3, 0x28, 0x81, 0x35, 0x7A, 0xB6, 0x8D, 0x7E, 0x8A, 0x01, 0x0B, 0x49, + 0x51, 0xA1, 0x70, 0x38, 0xCC, 0xF9, 0x1B, 0xA7, 0x1B, 0x73, 0xBA, 0x49, 0x60, 0xC9, 0x48, 0xC0, + 0xF4, 0xD8, 0x38, 0x4D, 0xD3, 0x14, 0x6B, 0x66, 0x6B, 0xA6, 0x28, 0x89, 0x0F, 0x49, 0x82, 0x1E, + 0x8A, 0x07, 0x66, 0x83, 0xCD, 0x1B, 0xC7, 0xAA, 0x4A, 0x08, 0x72, 0xF2, 0x16, 0xF4, 0x83, 0x6C, + 0x7C, 0x76, 0xF9, 0xAB, 0x2F, 0x97, 0xAF, 0x36, 0x4D, 0xD3, 0xF6, 0x75, 0x36, 0x3F, 0x50, 0xEF, + 0x29, 0x9A, 0x5F, 0x71, 0x4E, 0x07, 0xF4, 0x79, 0x2E, 0x61, 0x25, 0x8A, 0x0F, 0x3D, 0xF4, 0x9A, + 0x27, 0x18, 0x2D, 0x16, 0xA0, 0xD4, 0xEB, 0x58, 0xDD, 0x36, 0x3A, 0xFE, 0xDA, 0xA1, 0x6E, 0x43, + 0xF5, 0x77, 0xEE, 0xBB, 0x6D, 0xB4, 0x8D, 0xA9, 0x25, 0x86, 0xE5, 0xC4, 0xA7, 0xD1, 0x17, 0xC0, + 0x04, 0x28, 0xF4, 0xD5, 0x7A, 0xCA, 0xEF, 0x68, 0xC4, 0x48, 0xD9, 0x8E, 0xBD, 0xBF, 0xD3, 0xFE, + 0x33, 0x81, 0x1D, 0x60, 0xFF, 0x0D, 0x74, 0x81, 0xC7, 0xD9, 0xD1, 0x5C, 0x15, 0x6F, 0xBA, 0x26, + 0x8E, 0x47, 0x13, 0xC4, 0xD0, 0x29, 0x48, 0x6F, 0x08, 0x1C, 0xD1, 0x5E, 0x2C, 0x75, 0x8D, 0xB4, + 0xD1, 0x39, 0xB8, 0x1C, 0xB4, 0xFC, 0xFB, 0x0F, 0x8F, 0xDD, 0xBB, 0x9F, 0x0B, 0xEB, 0xD5, 0xA9, + 0x11, 0xD9, 0x2C, 0xA7, 0xCC, 0xE2, 0x64, 0xC3, 0xC9, 0x4D, 0x25, 0x10, 0xAB, 0x95, 0x16, 0xFA, + 0x11, 0xC3, 0xAC, 0xE8, 0xAA, 0x94, 0x93, 0x53, 0xCB, 0x55, 0x67, 0xEB, 0x87, 0xE1, 0x07, 0x58, + 0x9D, 0xBD, 0xFB, 0xB6, 0x98, 0xE5, 0xF4, 0x33, 0xA7, 0xA4, 0x91, 0x6B, 0x23, 0x95, 0x95, 0x99, + 0x04, 0x2B, 0x77, 0xB6, 0x4F, 0xEC, 0x8A, 0x4F, 0x94, 0xF4, 0xD2, 0xFE, 0xBE, 0x66, 0x4E, 0x35, + 0x77, 0xCC, 0xFA, 0x19, 0x86, 0x20, 0x4C, 0x87, 0xD3, 0x0B, 0xF2, 0x8D, 0xEE, 0xDA, 0x7F, 0x6F, + 0xF5, 0x79, 0x34, 0x81, 0xB1, 0x5C, 0x1E, 0x6C, 0xED, 0xC7, 0xA3, 0x61, 0x5F, 0x94, 0x0D, 0xEB, + 0xDA, 0x43, 0x19, 0xCE, 0x94, 0x10, 0x32, 0x2D, 0x14, 0x30, 0x75, 0x03, 0xF9, 0x03, 0x99, 0x37, + 0xF9, 0xB0, 0xFE, 0x88, 0x5E, 0xA6, 0x3F, 0x06, 0x7A, 0x78, 0x98, 0x47, 0xE6, 0xC1, 0xB3, 0xA1, + 0xDC, 0x2E, 0x44, 0x87, 0x90, 0x06, 0x0D, 0x62, 0x22, 0x9E, 0xDF, 0x82, 0x89, 0xBA, 0x82, 0x1C, + 0x43, 0xDA, 0x4C, 0x33, 0xC1, 0xB8, 0x7E, 0x76, 0x2F, 0x2D, 0x04, 0x8D, 0x70, 0x13, 0x7B, 0xC7, + 0xC3, 0x29, 0x26, 0x30, 0x52, 0x10, 0xF6, 0x4C, 0x05, 0x21, 0x42, 0xD1, 0x7D, 0x31, 0x0E, 0x52, + 0x8B, 0x1D, 0x5F, 0xC5, 0xEF, 0x9B, 0x19, 0xAB, 0x6E, 0xBB, 0xFD, 0x18, 0x6A, 0x05, 0x03, 0xC5, + 0xCD, 0x55, 0x93, 0x13, 0x2D, 0x29, 0xD0, 0x4E, 0xCB, 0x93, 0x13, 0xE8, 0xD9, 0xC7, 0x1E, 0x35, + 0x26, 0x7C, 0x9F, 0x19, 0x79, 0xEC, 0xFB, 0xA2, 0x60, 0x56, 0x82, 0x41, 0x8E, 0x0E, 0xCE, 0x0E, + 0x2C, 0xB3, 0x36, 0x55, 0x43, 0x7F, 0x8F, 0x25, 0xF8, 0x78, 0xDF, 0xD7, 0x2C, 0x64, 0x31, 0xE2, + 0x54, 0x46, 0xC0, 0x34, 0x99, 0xD9, 0x3A, 0x3F, 0xF7, 0xE7, 0xF3, 0xD3, 0xEF, 0x27, 0x7D, 0x1F, + 0x26, 0x3F, 0xB2, 0xC1, 0x3E, 0xBB, 0x0C, 0x83, 0xBB, 0xF2, 0x58, 0x19, 0x64, 0x0E, 0xE0, 0x55, + 0x62, 0xDD, 0xB4, 0x81, 0xE1, 0x7A, 0x38, 0x61, 0x37, 0x3B, 0x46, 0x21, 0x3C, 0x5F, 0x5B, 0xA6, + 0x3A, 0x34, 0xD6, 0xF0, 0xF2, 0x71, 0x2E, 0xEC, 0xA4, 0x6A, 0xA5, 0x7B, 0x5F, 0xFF, 0x64, 0xFF, + 0xF0, 0x6B, 0xC6, 0x4E, 0x6D, 0xBD, 0x71, 0x76, 0x36, 0xDF, 0xED, 0xE9, 0xBE, 0x4C, 0x6F, 0x31, + 0x7B, 0xCB, 0xC9, 0x34, 0x8D, 0xB8, 0xE2, 0x98, 0x8F, 0x0C, 0xC9, 0x5A, 0x24, 0xE6, 0x77, 0xD2, + 0xBB, 0x0B, 0xDB, 0xEB, 0x8C, 0x3F, 0x56, 0xEB, 0x1D, 0x3C, 0x7D, 0xDB, 0xD6, 0x7B, 0x9F, 0xD8, + 0x74, 0xFD, 0xAD, 0xFD, 0xFB, 0x94, 0x82, 0x29, 0x26, 0xD4, 0x42, 0x7A, 0xB1, 0xB3, 0xEF, 0x68, + 0x7D, 0xEA, 0xD5, 0x5B, 0x74, 0x27, 0x9E, 0xB5, 0xEE, 0xB9, 0x7A, 0x32, 0x29, 0x52, 0xE2, 0xC4, + 0xB6, 0xAE, 0x8F, 0x08, 0xF2, 0xD1, 0xDE, 0x58, 0xE3, 0xFA, 0x7C, 0xB4, 0x5A, 0xDE, 0x53, 0xCD, + 0x87, 0xAE, 0xEA, 0x4E, 0x4E, 0xCC, 0x4D, 0x15, 0x03, 0x51, 0x9B, 0xE2, 0xBD, 0xF5, 0x7B, 0x06, + 0x7D, 0x0A, 0xDB, 0xA2, 0xD3, 0xE0, 0xFA, 0x7E, 0xB9, 0x95, 0x0E, 0x83, 0x74, 0x72, 0xFA, 0xA3, + 0x33, 0x3D, 0x6B, 0x86, 0xBA, 0x67, 0xC6, 0xD6, 0x9D, 0x12, 0x6F, 0xFB, 0xED, 0x64, 0x22, 0x12, + 0x97, 0xD1, 0x88, 0xCF, 0xB1, 0xB1, 0x00, 0x8D, 0x97, 0x1E, 0x08, 0xEF, 0x3B, 0x0B, 0xD3, 0x57, + 0x60, 0x81, 0xAE, 0xB7, 0x92, 0xDD, 0x41, 0x0C, 0xC8, 0xB3, 0xED, 0x36, 0x1A, 0xF1, 0x78, 0x6A, + 0x66, 0xD2, 0xAE, 0x6C, 0xF3, 0x30, 0x2A, 0xCA, 0xAE, 0x7B, 0xA3, 0x92, 0x74, 0x52, 0x8B, 0x42, + 0x05, 0xB3, 0x65, 0xAB, 0x5D, 0x75, 0x23, 0x76, 0xC4, 0x9A, 0x3D, 0x8F, 0x0D, 0x7D, 0x0C, 0xED, + 0x08, 0xD7, 0x98, 0xFD, 0x94, 0xEF, 0x08, 0x2D, 0x0A, 0xA1, 0x4D, 0xCB, 0x71, 0xA5, 0xAF, 0x8D, + 0x4D, 0xEF, 0x0E, 0xD2, 0x34, 0x47, 0x22, 0x22, 0x9F, 0x4B, 0xA6, 0x48, 0x8C, 0xA1, 0xE0, 0xEC, + 0x42, 0x04, 0xFF, 0xE5, 0x9B, 0x81, 0xBB, 0x97, 0xAF, 0x3A, 0x10, 0x4F, 0x55, 0x74, 0x8D, 0x4D, + 0x62, 0x83, 0xB7, 0x9E, 0x12, 0x49, 0x76, 0xB7, 0xD2, 0x27, 0xE9, 0xFD, 0x6F, 0x5C, 0xCA, 0x27, + 0xF8, 0xE2, 0x68, 0x61, 0x5A, 0x46, 0x17, 0xEF, 0xE8, 0x74, 0x83, 0x41, 0x9F, 0x6F, 0xDB, 0xC7, + 0x9F, 0x3E, 0xE4, 0xF3, 0x41, 0x32, 0x1C, 0x0E, 0x85, 0x59, 0x96, 0x09, 0x6E, 0xE9, 0xC4, 0xA6, + 0xE2, 0x49, 0x3E, 0x20, 0xB4, 0x9A, 0xB2, 0x36, 0x9D, 0x72, 0xF3, 0xA4, 0xA3, 0x98, 0x53, 0xB7, + 0x61, 0x4E, 0xED, 0x81, 0xF9, 0x7E, 0x64, 0xAA, 0xE4, 0x97, 0x1A, 0x5A, 0x3B, 0xA9, 0x7D, 0xB2, + 0x6F, 0x7E, 0xA2, 0x6F, 0x7F, 0xBC, 0x5F, 0xFB, 0x58, 0xBE, 0x8D, 0x92, 0xF9, 0x3F, 0x63, 0x59, + 0x28, 0x6D, 0xF0, 0x5F, 0x80, 0xCB, 0x61, 0xE4, 0x3A, 0x4E, 0x97, 0x5C, 0xDB, 0xCC, 0x1B, 0xBD, + 0xE7, 0xDA, 0xC7, 0x28, 0xD2, 0xF6, 0x50, 0xB9, 0xEB, 0xCA, 0xF0, 0x72, 0x4C, 0x08, 0x0F, 0x94, + 0x60, 0x80, 0x92, 0x19, 0x10, 0xC7, 0x20, 0x53, 0x0D, 0x4D, 0x0A, 0xE5, 0x96, 0x53, 0x9B, 0xDB, + 0x56, 0x28, 0x2D, 0x15, 0xD4, 0x7A, 0x37, 0x26, 0xEC, 0xCF, 0xD1, 0x42, 0xA3, 0x27, 0x15, 0x1B, + 0xF6, 0xC7, 0x45, 0x67, 0x7C, 0x76, 0xD9, 0x7F, 0x7A, 0xAE, 0xBF, 0x95, 0x4F, 0xEC, 0x12, 0xEB, + 0x3D, 0x66, 0xB3, 0x7F, 0x74, 0x9C, 0xFD, 0xA3, 0x97, 0x7F, 0xC5, 0x6E, 0x8D, 0x68, 0xD1, 0xB0, + 0xEE, 0x4B, 0xDB, 0x82, 0x5E, 0x48, 0x1B, 0xB9, 0x25, 0xD8, 0xCA, 0x31, 0xB5, 0x8C, 0xC1, 0x8C, + 0x90, 0x52, 0x65, 0xB4, 0x7C, 0x6D, 0x5B, 0x2A, 0x8D, 0x38, 0x12, 0x63, 0x95, 0xB4, 0xAE, 0x34, + 0xA5, 0x86, 0x6B, 0x36, 0x2A, 0x24, 0xAF, 0x8E, 0x0D, 0x6C, 0xB3, 0x67, 0xD0, 0x67, 0xB1, 0x0D, + 0xE2, 0x07, 0x4B, 0xFD, 0x98, 0x2E, 0x01, 0x9D, 0x66, 0x5E, 0x8F, 0x71, 0xED, 0xEB, 0x9C, 0x97, + 0x09, 0x48, 0x61, 0x90, 0xC2, 0x22, 0x59, 0xB1, 0x41, 0xCB, 0x8D, 0x02, 0xEA, 0x97, 0x48, 0xC0, + 0xCB, 0x3A, 0xF5, 0x16, 0xBC, 0xE7, 0xD9, 0xAF, 0xEB, 0x0E, 0xE7, 0x80, 0xEE, 0x26, 0x28, 0xBA, + 0xD0, 0x19, 0x03, 0x65, 0x0C, 0x86, 0x69, 0xA6, 0x6D, 0x24, 0x32, 0x49, 0x0C, 0x88, 0x9D, 0x7A, + 0x0A, 0x7D, 0xF6, 0x84, 0x9C, 0x55, 0x4A, 0xC1, 0x49, 0x82, 0x66, 0xAF, 0xDA, 0x43, 0xC1, 0xF2, + 0xC7, 0x8A, 0xAD, 0x29, 0x55, 0x39, 0x39, 0x0F, 0xA7, 0xD1, 0x97, 0x6F, 0x90, 0x05, 0x82, 0x84, + 0x67, 0x8F, 0x7F, 0xE0, 0x60, 0x7D, 0xA6, 0x8B, 0x22, 0x6A, 0xBD, 0xCC, 0x0B, 0x0C, 0xE3, 0x65, + 0xD1, 0xFC, 0x8C, 0x48, 0xA1, 0x6F, 0x80, 0x11, 0x37, 0x06, 0x56, 0x2E, 0x15, 0x0B, 0x36, 0xF0, + 0xA7, 0x5E, 0x57, 0x07, 0xFF, 0x75, 0x45, 0xFE, 0x14, 0x18, 0xE6, 0x27, 0x80, 0x0D, 0xE2, 0xB3, + 0x6E, 0x0F, 0x62, 0x76, 0xFC, 0x20, 0xFB, 0xC9, 0x05, 0x46, 0x11, 0x14, 0xF5, 0x42, 0x42, 0xAE, + 0x1A, 0xCD, 0x36, 0x7B, 0x04, 0x91, 0x22, 0x29, 0x46, 0x0C, 0x1B, 0x05, 0xB9, 0x3F, 0x3F, 0x51, + 0x2C, 0x1A, 0xA9, 0x2D, 0xDB, 0x67, 0xCB, 0xA1, 0x6A, 0xEA, 0x5E, 0x44, 0x72, 0xC1, 0x80, 0x0A, + 0xB5, 0xF2, 0x81, 0x7A, 0x71, 0x2E, 0xA9, 0x62, 0x3B, 0xAE, 0x5C, 0x1A, 0x45, 0xDF, 0x08, 0xD8, + 0xD9, 0xCA, 0xA1, 0xF6, 0xE1, 0xC8, 0xD9, 0x1B, 0xA7, 0xA2, 0x62, 0xFB, 0xF0, 0xE9, 0x83, 0xBD, + 0xFB, 0xAA, 0x65, 0x73, 0x4B, 0x30, 0xBE, 0x74, 0xC3, 0x62, 0x92, 0x8C, 0x5D, 0x73, 0xE6, 0x86, + 0xE5, 0x5D, 0x53, 0xD9, 0x78, 0x89, 0xF1, 0x07, 0x02, 0xAE, 0xC7, 0x67, 0xF5, 0x47, 0xAB, 0xCF, + 0x10, 0x26, 0xFA, 0x36, 0xA8, 0xBA, 0xB1, 0x91, 0x72, 0x48, 0xE4, 0x41, 0x2C, 0x18, 0x00, 0xE7, + 0x56, 0xB4, 0x7D, 0x83, 0x1E, 0x5F, 0x1E, 0xE0, 0x0E, 0x0D, 0xF5, 0x9A, 0x6B, 0x8F, 0x5A, 0xA6, + 0x17, 0x1D, 0x65, 0xAA, 0x44, 0x85, 0x58, 0x0B, 0x11, 0xDB, 0x51, 0xD7, 0xA9, 0x07, 0x9B, 0x3D, + 0x48, 0x98, 0xA6, 0x1A, 0xD9, 0x77, 0x75, 0xD4, 0x12, 0x59, 0x1E, 0x43, 0xFA, 0x54, 0x42, 0x12, + 0xFA, 0xBB, 0x2B, 0xE3, 0x31, 0x83, 0xF5, 0xF1, 0x0F, 0x92, 0x16, 0x6B, 0xE4, 0x73, 0x07, 0x1B, + 0x21, 0x4B, 0xE2, 0x0A, 0xF9, 0x50, 0x24, 0x82, 0xBE, 0x9D, 0x0C, 0xB6, 0xFE, 0xE8, 0x13, 0xF3, + 0xB5, 0x70, 0x40, 0x52, 0x1C, 0x51, 0x12, 0x2C, 0x23, 0x19, 0xFA, 0xCF, 0x1F, 0x3A, 0x7C, 0x24, + 0xCE, 0x43, 0xD1, 0xDE, 0x4F, 0xF0, 0xA3, 0x8B, 0x4F, 0x9D, 0x98, 0x28, 0x87, 0xF4, 0x23, 0xD7, + 0x9F, 0x6A, 0xAA, 0x8A, 0xD7, 0xEF, 0xE7, 0xC8, 0xDF, 0x60, 0xCD, 0x7E, 0x35, 0x18, 0xE9, 0x1B, + 0x9D, 0x4C, 0x4A, 0x91, 0xC0, 0xF6, 0xA9, 0x89, 0xB1, 0x90, 0x39, 0x7D, 0x0D, 0x78, 0x5F, 0xBE, + 0x34, 0x74, 0x4B, 0x0E, 0x14, 0xD6, 0x46, 0x95, 0x75, 0x4D, 0xC7, 0x0D, 0xC5, 0x51, 0x5E, 0x4C, + 0x77, 0xD8, 0x7F, 0x54, 0x21, 0xB2, 0x5E, 0xDC, 0x11, 0x37, 0xA0, 0x2A, 0x8D, 0xC9, 0x9E, 0xC8, + 0xAC, 0x69, 0x67, 0x97, 0xD4, 0x1D, 0x37, 0xD1, 0x8C, 0x72, 0xF0, 0xD8, 0xDC, 0x13, 0x44, 0xFE, + 0x86, 0x09, 0x4C, 0x6C, 0xEB, 0xE5, 0x05, 0x24, 0x49, 0x58, 0x2F, 0xAB, 0x9A, 0x3D, 0xA6, 0x92, + 0x28, 0x2B, 0x76, 0x26, 0x8D, 0x80, 0xAE, 0x09, 0xB9, 0x58, 0x34, 0x80, 0x2C, 0x6B, 0xBF, 0xE4, + 0x08, 0x04, 0x52, 0xE4, 0x70, 0xAB, 0x99, 0x21, 0x2C, 0xD3, 0x47, 0xB2, 0xE8, 0x6E, 0x96, 0x51, + 0x32, 0x23, 0x85, 0x6E, 0xBA, 0x1A, 0x2B, 0x36, 0x28, 0xD7, 0x5D, 0xFF, 0x9A, 0xCC, 0xF1, 0x9C, + 0x98, 0x40, 0x42, 0xBA, 0x99, 0xA3, 0xB1, 0xDE, 0xFF, 0x81, 0x54, 0xBA, 0xE9, 0x3F, 0xDD, 0x7F, + 0x55, 0x88, 0x8C, 0x27, 0x49, 0x51, 0xE6, 0x29, 0x91, 0x57, 0x53, 0x3C, 0x8D, 0x6E, 0x8C, 0x3F, + 0x78, 0x57, 0xB2, 0x1C, 0x8D, 0x5B, 0x5B, 0xA7, 0xA7, 0x17, 0x4C, 0x5A, 0x16, 0xC5, 0x5A, 0xAA, + 0x1B, 0x66, 0xA8, 0x68, 0x6A, 0xF6, 0xD6, 0xEB, 0xE7, 0x99, 0x64, 0x12, 0xF9, 0x77, 0xD3, 0xA3, + 0x07, 0xB6, 0xDF, 0xBD, 0xE9, 0xF8, 0xCC, 0x75, 0xAF, 0x49, 0x48, 0x8E, 0x23, 0xEE, 0x99, 0xFB, + 0xCC, 0x35, 0x81, 0xDD, 0xA4, 0x6F, 0xCB, 0x99, 0xFB, 0x7B, 0x6E, 0xC2, 0x8C, 0x6B, 0xB7, 0x7C, + 0x07, 0x7D, 0x01, 0x7D, 0x17, 0x4B, 0xD3, 0xCD, 0xFD, 0x48, 0x3D, 0x13, 0x8F, 0xCA, 0xA0, 0x39, + 0x52, 0x2D, 0x4C, 0xF8, 0xE9, 0x09, 0xBF, 0x94, 0x99, 0x11, 0xDE, 0x32, 0x63, 0xFC, 0xB7, 0x19, + 0xFF, 0xA7, 0xA7, 0x3F, 0x93, 0xFE, 0xAC, 0xAB, 0x45, 0xCE, 0x81, 0x89, 0x41, 0xBA, 0xE5, 0x9A, + 0x32, 0xB9, 0x1C, 0x13, 0xBA, 0x52, 0x33, 0xE3, 0xF2, 0x8F, 0x67, 0x78, 0x7A, 0x8E, 0x3D, 0x47, + 0x26, 0x3C, 0xFF, 0xAE, 0xEC, 0x36, 0x86, 0x3D, 0x1A, 0xF1, 0xD2, 0x09, 0x36, 0x62, 0x9D, 0x08, + 0x72, 0xDC, 0x84, 0x35, 0xF4, 0x85, 0xF1, 0xF2, 0xF5, 0x7E, 0x5F, 0x30, 0xBC, 0x7F, 0x53, 0x52, + 0x17, 0x24, 0x2E, 0x99, 0xEE, 0xE9, 0xBC, 0x20, 0x2B, 0x77, 0x71, 0x79, 0x46, 0xA2, 0x72, 0x56, + 0x71, 0x25, 0xDB, 0x96, 0xDF, 0xEE, 0xF4, 0xF3, 0xEC, 0x43, 0xE1, 0xA2, 0x2A, 0xC8, 0xDC, 0xEB, + 0x59, 0x5A, 0xAE, 0x4C, 0xC6, 0x32, 0x62, 0xC6, 0x4F, 0x13, 0xF5, 0x8F, 0xA2, 0xAF, 0xF5, 0x47, + 0xCF, 0xC4, 0xC2, 0x89, 0xC2, 0xD9, 0x6B, 0x43, 0x82, 0x6D, 0xFB, 0x1A, 0x22, 0x26, 0x92, 0xF7, + 0x8B, 0xF3, 0x9C, 0xC6, 0x4F, 0x37, 0x22, 0x1A, 0xAB, 0x64, 0xAC, 0xA0, 0xF1, 0x89, 0xC0, 0xDE, + 0x2E, 0xFF, 0x54, 0x36, 0xCD, 0xA9, 0xB7, 0xD0, 0x53, 0x47, 0xEB, 0x6D, 0x71, 0xBC, 0x9D, 0x30, + 0x7C, 0x7B, 0x06, 0xC8, 0xE0, 0x39, 0xC2, 0x42, 0x3F, 0x05, 0x6D, 0xD0, 0xEF, 0xFB, 0x1B, 0xB5, + 0x18, 0x28, 0x24, 0xA3, 0xE1, 0x82, 0x60, 0x6A, 0x26, 0x92, 0x44, 0xA1, 0xFD, 0x39, 0x0D, 0x23, + 0xBF, 0xD8, 0x95, 0x5A, 0x04, 0x5C, 0x6E, 0x7C, 0xE3, 0x19, 0x18, 0x8B, 0x0D, 0xA2, 0xBA, 0x14, + 0x26, 0x9D, 0xA8, 0x3B, 0x6A, 0xA6, 0x0B, 0xDB, 0x1E, 0xE0, 0xD9, 0x88, 0xEC, 0xDC, 0x24, 0x90, + 0x4C, 0x16, 0x73, 0xB2, 0x65, 0x97, 0x53, 0x9A, 0xD1, 0x31, 0x2A, 0x39, 0x13, 0xC2, 0x44, 0x70, + 0x2C, 0x01, 0x39, 0xAB, 0xB2, 0x35, 0x37, 0x55, 0xD3, 0x38, 0x59, 0xB0, 0xEF, 0xF0, 0x07, 0x37, + 0x05, 0xFA, 0x99, 0x31, 0x53, 0xF5, 0x8D, 0xD8, 0x0A, 0x41, 0x8E, 0x8F, 0xB7, 0xC6, 0xD0, 0xF7, + 0x9D, 0xB9, 0xB1, 0x40, 0xF4, 0xDA, 0xF0, 0xC2, 0x54, 0x77, 0xA2, 0x62, 0xFB, 0xF4, 0x9C, 0x5F, + 0x89, 0x28, 0x3B, 0xF6, 0x4C, 0x6C, 0xBD, 0x61, 0x64, 0x21, 0x4F, 0x6B, 0xDA, 0xBE, 0x03, 0x89, + 0x3D, 0xED, 0x83, 0x09, 0x2B, 0x75, 0xB0, 0x5C, 0xB3, 0x39, 0x5D, 0xC4, 0xA0, 0x31, 0x8C, 0xD7, + 0x3A, 0xB2, 0xFA, 0x1F, 0x68, 0x09, 0x3D, 0x03, 0x3A, 0x58, 0x52, 0x26, 0x1A, 0x79, 0x8C, 0x7D, + 0x14, 0x16, 0x64, 0xD2, 0x71, 0x05, 0xFC, 0x4D, 0xD7, 0x34, 0x34, 0x42, 0xFF, 0x58, 0x42, 0x53, + 0xFF, 0x32, 0xF1, 0xF5, 0x76, 0x8E, 0x0C, 0x7D, 0x9E, 0x84, 0x03, 0xD4, 0xD0, 0x1B, 0x3A, 0x24, + 0x2E, 0xBC, 0xC8, 0x94, 0xEB, 0xB2, 0x58, 0x41, 0xD0, 0xCC, 0x7A, 0xD0, 0xB3, 0x47, 0x28, 0xA8, + 0x08, 0x07, 0xD1, 0x19, 0xE4, 0x62, 0x3D, 0xD7, 0x8F, 0xD0, 0xC6, 0xBC, 0xE2, 0xB9, 0x7B, 0x65, + 0x72, 0x10, 0xF9, 0x9D, 0x42, 0x68, 0x69, 0x71, 0x72, 0xBC, 0x78, 0xF7, 0x43, 0x5B, 0xEC, 0xAD, + 0xCB, 0x57, 0x25, 0x32, 0x95, 0xDA, 0x44, 0x4F, 0x8D, 0x28, 0x5D, 0x4B, 0x3E, 0x60, 0xA3, 0xE2, + 0xF6, 0xFD, 0x5B, 0x96, 0x4C, 0x9A, 0x45, 0x50, 0x49, 0xF4, 0x27, 0x36, 0xD7, 0x83, 0xBE, 0xE8, + 0x64, 0xA9, 0x92, 0xDF, 0xE2, 0x7B, 0xFF, 0xB5, 0x9B, 0x68, 0x29, 0x99, 0xD1, 0xC7, 0x8E, 0x1D, + 0x3D, 0x9A, 0xAB, 0x22, 0x04, 0x91, 0x12, 0x31, 0xC3, 0xFA, 0x21, 0x8E, 0xE4, 0x42, 0x04, 0x45, + 0x8B, 0x2C, 0xA3, 0x27, 0xB7, 0x6F, 0x3E, 0xBC, 0x29, 0xDB, 0xD2, 0x0C, 0x4B, 0x20, 0x58, 0x0A, + 0x8F, 0x77, 0x65, 0xF5, 0x11, 0x38, 0x83, 0x9E, 0x06, 0x11, 0xB0, 0xAD, 0x9F, 0xB4, 0x54, 0xF0, + 0x45, 0x8C, 0x49, 0xDF, 0x6A, 0x30, 0xA1, 0xED, 0xE4, 0x45, 0x03, 0xD8, 0x21, 0xDB, 0x2F, 0x31, + 0xBC, 0x1F, 0xF1, 0x12, 0xB3, 0xC2, 0xC0, 0x2F, 0x41, 0xE6, 0xCA, 0x62, 0x81, 0xEE, 0xE0, 0x31, + 0xC8, 0xF2, 0xF6, 0xC6, 0x8F, 0x07, 0x1D, 0x65, 0x5C, 0xBC, 0x34, 0x48, 0xE5, 0x19, 0xD5, 0xDD, + 0x25, 0x1C, 0x84, 0xB3, 0x99, 0x2C, 0x63, 0x62, 0x0C, 0xA0, 0x5B, 0xF5, 0x16, 0xC4, 0x30, 0xA4, + 0x1D, 0x71, 0x3A, 0x36, 0xE6, 0x64, 0x7B, 0xD2, 0x1F, 0x9E, 0xB7, 0xC4, 0x5A, 0x03, 0x43, 0xF7, + 0xB9, 0xE6, 0x22, 0x22, 0x49, 0x74, 0x0B, 0x9C, 0x65, 0x1E, 0xF8, 0xEC, 0x01, 0xF7, 0x74, 0x9C, + 0x20, 0xF6, 0x5E, 0xFC, 0xAD, 0xBE, 0xFB, 0xE2, 0x45, 0x87, 0x1E, 0x78, 0x19, 0xE1, 0x8F, 0xB0, + 0xEC, 0xD2, 0x41, 0xAC, 0xCF, 0xF3, 0x80, 0x07, 0xD2, 0xFB, 0x56, 0x88, 0xF5, 0x8C, 0x82, 0x75, + 0xBF, 0x85, 0xC1, 0x53, 0xC5, 0x38, 0xBE, 0x7D, 0x85, 0xCA, 0xE2, 0x1B, 0x47, 0x48, 0xF8, 0xA3, + 0xD8, 0x48, 0x36, 0xD8, 0x98, 0xBC, 0x7E, 0x6B, 0x5B, 0x0B, 0xCD, 0xFA, 0xF5, 0xEA, 0xF6, 0x6B, + 0x6F, 0x66, 0xF9, 0xB9, 0xE3, 0xB7, 0x7E, 0xE8, 0x55, 0x37, 0xE6, 0x04, 0x66, 0xFC, 0xA6, 0xD7, + 0xBF, 0xF7, 0x33, 0xF8, 0xEA, 0xBF, 0x59, 0x7D, 0x04, 0xFC, 0x33, 0x9E, 0x8D, 0x30, 0xD8, 0xDD, + 0xCF, 0x12, 0x8F, 0x45, 0xD8, 0x58, 0x44, 0xFF, 0xB2, 0xC1, 0x31, 0x31, 0xFA, 0x4B, 0xCA, 0xDF, + 0x5A, 0x0F, 0xD0, 0x3A, 0xA7, 0x70, 0xA2, 0x0F, 0x04, 0x45, 0x14, 0xF4, 0x19, 0x0C, 0xF8, 0xD2, + 0x95, 0xEA, 0xF2, 0xC5, 0x33, 0xE2, 0xFE, 0xBB, 0xC9, 0x9F, 0x58, 0x63, 0x3A, 0x83, 0x19, 0x69, + 0x3B, 0x6D, 0x77, 0x52, 0x50, 0xD3, 0x3D, 0xF7, 0x02, 0x55, 0xEE, 0xA4, 0xD8, 0xFF, 0xAC, 0x56, + 0xC3, 0x91, 0xDD, 0xCE, 0x70, 0x1A, 0x34, 0x3B, 0x35, 0x1E, 0x9C, 0x33, 0x08, 0x74, 0x9F, 0x3B, + 0x07, 0x98, 0x03, 0xF6, 0x42, 0x52, 0xDF, 0x0D, 0x31, 0xC9, 0x50, 0xD3, 0x34, 0x89, 0x6E, 0xBC, + 0xF8, 0x57, 0xEC, 0xFD, 0x7F, 0xED, 0xCA, 0xA6, 0x1E, 0xE4, 0x91, 0x1F, 0xFD, 0x27, 0x2F, 0x9A, + 0x19, 0x20, 0x90, 0x6B, 0xFF, 0x90, 0xD0, 0x8D, 0x6E, 0xD2, 0x00, 0x59, 0x14, 0x4D, 0xFD, 0x3D, + 0x89, 0x2D, 0x60, 0xF0, 0x15, 0xAF, 0x70, 0xC1, 0x75, 0xCF, 0x7B, 0xD1, 0xCC, 0xE0, 0xE3, 0xE3, + 0x5F, 0x5E, 0x8B, 0x66, 0x9E, 0xFB, 0xD1, 0x3D, 0x83, 0x37, 0x6E, 0x34, 0x93, 0xC4, 0x5C, 0x99, + 0x14, 0x60, 0xD2, 0x68, 0x20, 0xFF, 0xA1, 0xD7, 0xBE, 0xF6, 0xD0, 0x5F, 0x1D, 0x80, 0x3C, 0xCC, + 0x5D, 0xFC, 0x16, 0x7C, 0x05, 0xF0, 0x66, 0x67, 0x02, 0x15, 0x56, 0x57, 0x00, 0x01, 0x22, 0x7D, + 0xDE, 0x8D, 0x98, 0x12, 0xE8, 0x69, 0x08, 0xBE, 0x36, 0x88, 0xC3, 0xAE, 0x71, 0x36, 0xE9, 0x46, + 0x76, 0xDD, 0xC8, 0x6B, 0xE1, 0xC2, 0xD7, 0xD0, 0xC8, 0xDF, 0x26, 0xF1, 0xEF, 0x56, 0x51, 0x18, + 0x9C, 0x47, 0x9F, 0x5C, 0xCB, 0xEB, 0x25, 0xBE, 0xBE, 0x02, 0xFF, 0xFB, 0x4B, 0xE4, 0xF5, 0x62, + 0xCE, 0x3F, 0x5F, 0x7F, 0x72, 0x1F, 0x1A, 0x75, 0x0E, 0xB7, 0xBD, 0x2C, 0xBC, 0x9F, 0xA3, 0x79, + 0xF8, 0x2C, 0xB6, 0xA8, 0x1A, 0x7D, 0xBB, 0x96, 0x8F, 0xDB, 0x12, 0xA8, 0x96, 0x2D, 0xBB, 0x63, + 0xDC, 0xD1, 0x19, 0xFD, 0x46, 0x24, 0x04, 0x89, 0x20, 0xEB, 0x8D, 0xEA, 0xC5, 0x71, 0xA5, 0x4E, + 0xDC, 0x75, 0x12, 0xB8, 0xC2, 0x64, 0x90, 0xFA, 0x5C, 0x1F, 0xBA, 0xF6, 0xA0, 0x9B, 0x9D, 0xEA, + 0x25, 0x61, 0xB4, 0x5B, 0x3D, 0x22, 0xBB, 0xD1, 0x63, 0x42, 0x38, 0x68, 0xFE, 0x1E, 0x86, 0x4F, + 0x8D, 0x4F, 0xA5, 0xF2, 0x9C, 0x9C, 0x34, 0xF9, 0x56, 0x49, 0x64, 0x0A, 0x11, 0x11, 0x55, 0xD3, + 0xCD, 0x88, 0x4C, 0x13, 0xBD, 0xB9, 0xE2, 0x52, 0xB6, 0x2A, 0x99, 0x49, 0x31, 0xD8, 0xF2, 0x19, + 0x2A, 0x3B, 0x17, 0xCE, 0x2B, 0xD1, 0x83, 0xF9, 0x72, 0x21, 0x35, 0xBF, 0xD7, 0xF2, 0x6D, 0xE9, + 0x87, 0x38, 0x8A, 0xB6, 0x65, 0x32, 0x92, 0xA6, 0x15, 0x19, 0x95, 0x92, 0x21, 0xC8, 0x8C, 0x65, + 0xEC, 0x9D, 0x65, 0x5B, 0x42, 0xD8, 0xEA, 0x2C, 0x14, 0x78, 0x61, 0xDC, 0xE7, 0x3F, 0xD3, 0xDD, + 0xB4, 0x63, 0xD1, 0x9D, 0xC7, 0x7F, 0xC1, 0x96, 0x75, 0x94, 0xF0, 0x83, 0x71, 0x2C, 0x43, 0x83, + 0xED, 0xBC, 0x55, 0xAF, 0x94, 0x4D, 0x2D, 0x63, 0x4E, 0x54, 0xE3, 0x71, 0x24, 0x45, 0x63, 0x48, + 0x0A, 0xFD, 0x23, 0x53, 0xBA, 0x14, 0x64, 0x81, 0x6B, 0x29, 0xE0, 0x1B, 0x35, 0xB2, 0x1B, 0x18, + 0xB0, 0xBC, 0xC0, 0x00, 0xE3, 0x65, 0x80, 0x13, 0x6E, 0x95, 0x84, 0xE7, 0x08, 0xF1, 0xCC, 0xA8, + 0x76, 0xCB, 0xB6, 0x1C, 0x63, 0x2D, 0xE7, 0xDE, 0xB5, 0xB4, 0x86, 0x62, 0xD5, 0xF5, 0x90, 0x21, + 0x99, 0x2F, 0x56, 0xE4, 0xE0, 0xB5, 0xE3, 0xED, 0x1D, 0x26, 0x47, 0x10, 0x18, 0x64, 0x70, 0x8A, + 0xC0, 0x07, 0xE7, 0x04, 0x31, 0x26, 0xA8, 0xAA, 0x0F, 0xD1, 0x74, 0x62, 0x97, 0xB4, 0xA0, 0xA7, + 0x16, 0x47, 0x34, 0x7A, 0x7F, 0x38, 0x36, 0xDB, 0x50, 0x0C, 0xF6, 0x7C, 0x64, 0x2C, 0x2F, 0x3B, + 0xB3, 0x3B, 0x46, 0xF7, 0x3C, 0x79, 0x7A, 0x6C, 0x5B, 0x9B, 0x22, 0x15, 0xBD, 0xCE, 0xF2, 0x3E, + 0x0E, 0x21, 0x5D, 0xCD, 0x5C, 0x3C, 0xDC, 0xAD, 0x1F, 0x54, 0x0E, 0x6A, 0xF1, 0xE3, 0x93, 0x50, + 0x19, 0xD3, 0x17, 0x82, 0xE9, 0x8A, 0x59, 0x19, 0x64, 0x52, 0x3E, 0x07, 0xDF, 0x0B, 0xFF, 0x37, + 0x28, 0xB9, 0x31, 0xB1, 0xA4, 0xC9, 0x81, 0x48, 0xE9, 0xCF, 0xCB, 0x05, 0xB3, 0x1C, 0x3C, 0xAF, + 0x28, 0xDF, 0x24, 0x4A, 0x2F, 0x15, 0x13, 0x2B, 0xBB, 0x89, 0x80, 0x9E, 0xC0, 0x24, 0x86, 0xF0, + 0xD9, 0x4D, 0x60, 0x50, 0x28, 0xCF, 0xCF, 0x07, 0x87, 0xD6, 0x71, 0x1B, 0xBE, 0x79, 0x64, 0x77, + 0x6F, 0xFB, 0x6E, 0x85, 0xA7, 0x0B, 0x2B, 0xA3, 0xD3, 0x11, 0x5F, 0xC9, 0x8A, 0xC4, 0x7D, 0x9C, + 0xC4, 0x05, 0x89, 0x4E, 0xDA, 0x6F, 0x8B, 0x9A, 0x3D, 0x5D, 0xCA, 0xC5, 0x60, 0x28, 0xB0, 0x33, + 0x35, 0x79, 0x67, 0x34, 0x95, 0x54, 0xB2, 0xC7, 0x77, 0x46, 0x2D, 0x55, 0x76, 0x02, 0xC1, 0x80, + 0x4E, 0x73, 0x8C, 0x1C, 0x9B, 0x37, 0x05, 0x27, 0xEE, 0xEC, 0xDD, 0x1C, 0x13, 0x11, 0xE7, 0x55, + 0x23, 0x62, 0x8B, 0x37, 0x83, 0xFE, 0x33, 0xE8, 0x82, 0x6C, 0x5F, 0xE9, 0x94, 0x8B, 0x99, 0x90, + 0x2A, 0xF3, 0xBE, 0xF7, 0x4F, 0x16, 0xBE, 0xC5, 0x2C, 0x0E, 0xBA, 0xB9, 0x51, 0xAC, 0x4F, 0x66, + 0xDC, 0xA9, 0xA7, 0x06, 0x19, 0x17, 0x03, 0x9B, 0x1D, 0x7A, 0xAA, 0xDC, 0xB3, 0x6B, 0x99, 0x35, + 0xE1, 0x8E, 0x4D, 0x1D, 0x37, 0x7E, 0x89, 0xD9, 0x1B, 0x89, 0x7C, 0xA3, 0x6D, 0xCE, 0x8D, 0x87, + 0x77, 0xDD, 0x70, 0x4B, 0x5C, 0x08, 0x70, 0x0C, 0x9F, 0x68, 0x86, 0xB9, 0xE4, 0x08, 0x87, 0x98, + 0xA9, 0xE5, 0xE0, 0x99, 0xFD, 0x11, 0x95, 0x7D, 0x50, 0x55, 0x33, 0x5A, 0x90, 0x8B, 0x64, 0xF3, + 0x9A, 0x9D, 0x28, 0xEC, 0xF9, 0x92, 0x3D, 0x51, 0xD7, 0xAA, 0xF6, 0xA3, 0xDD, 0x23, 0xB3, 0x1A, + 0x9B, 0x6F, 0xE8, 0x59, 0xCD, 0x1C, 0x75, 0xE8, 0x7C, 0x5D, 0x65, 0xB4, 0xA9, 0x85, 0x9C, 0x50, + 0x48, 0xFA, 0x74, 0xCD, 0x60, 0x0F, 0x89, 0x92, 0x19, 0x0E, 0xF0, 0x32, 0x2D, 0xAB, 0x0A, 0xC3, + 0x4A, 0x76, 0x6F, 0x73, 0xD5, 0xCB, 0xFB, 0x5D, 0xFD, 0x09, 0xFC, 0x10, 0xFC, 0x19, 0x28, 0x63, + 0xDE, 0xB1, 0x82, 0x3A, 0x28, 0x3F, 0x56, 0x29, 0x7C, 0xA7, 0x12, 0xCB, 0x64, 0x10, 0xAF, 0x7C, + 0x97, 0xFA, 0xA7, 0xF5, 0x0A, 0x91, 0xDE, 0x86, 0x8A, 0xAF, 0xC1, 0xC8, 0x2A, 0xBC, 0xE7, 0x60, + 0x43, 0x03, 0x93, 0xC6, 0x4B, 0xBC, 0xF4, 0x92, 0x0D, 0xC8, 0x4B, 0x39, 0x8D, 0xC3, 0xF4, 0xA4, + 0x1E, 0x84, 0x1F, 0xD2, 0x3B, 0xB9, 0x66, 0xB8, 0xD2, 0x17, 0x76, 0x4E, 0xDD, 0xB8, 0x2D, 0xD3, + 0x9E, 0x92, 0xE2, 0xB1, 0x02, 0x99, 0x2B, 0x49, 0x52, 0x51, 0x14, 0xB7, 0xB1, 0xA1, 0x54, 0xFC, + 0xE0, 0x62, 0x32, 0x23, 0x1D, 0x55, 0x9B, 0x51, 0xA7, 0xCA, 0xEF, 0xD9, 0x3F, 0x7E, 0xDB, 0x72, + 0xBC, 0x9E, 0x56, 0xE3, 0x09, 0x27, 0x42, 0xF8, 0xC3, 0x1A, 0x97, 0xB6, 0x34, 0xB5, 0x6C, 0x55, + 0x72, 0xA5, 0x6D, 0xD7, 0x28, 0xB4, 0x87, 0x2D, 0x5E, 0x80, 0xDF, 0x21, 0x34, 0x8C, 0xB3, 0x8E, + 0xF4, 0x6B, 0x05, 0x03, 0x54, 0xB2, 0x06, 0x4B, 0x7E, 0xAF, 0x53, 0x48, 0xDF, 0x35, 0x22, 0xD7, + 0x7F, 0x19, 0x41, 0xC9, 0xA8, 0x2C, 0x11, 0x22, 0x6A, 0xA4, 0x53, 0x44, 0x3D, 0x18, 0x40, 0x49, + 0x3F, 0x4A, 0xC4, 0x93, 0x9D, 0x4A, 0x7C, 0xE6, 0x2C, 0x2C, 0x5C, 0x01, 0x39, 0x5C, 0x1F, 0xC4, + 0x20, 0x3D, 0xDB, 0xF5, 0x23, 0x76, 0x2F, 0x6C, 0xD4, 0xCD, 0x2E, 0x00, 0x2B, 0x78, 0xE5, 0x13, + 0xD9, 0xA1, 0xC9, 0xEE, 0x58, 0xAE, 0x33, 0x5F, 0xA1, 0xA2, 0xAE, 0x31, 0xA3, 0xA0, 0x66, 0x96, + 0xC8, 0xD2, 0xC9, 0x82, 0x5B, 0x6C, 0x14, 0x25, 0x9A, 0x53, 0xB4, 0xC7, 0x37, 0x8E, 0x0D, 0xBF, + 0x13, 0x8D, 0x88, 0x51, 0xC9, 0xA8, 0x49, 0x21, 0x6C, 0x33, 0x38, 0xED, 0xA8, 0xAA, 0xF1, 0x5C, + 0x42, 0xB0, 0x9B, 0x24, 0xE2, 0xC9, 0x40, 0xF0, 0x20, 0xE4, 0x50, 0x24, 0xAA, 0xA7, 0x74, 0x6C, + 0x77, 0x32, 0xC1, 0xB0, 0xE3, 0xA3, 0xE2, 0xB3, 0xE1, 0x6A, 0x32, 0xC9, 0x59, 0x4A, 0xC1, 0x8F, + 0xF9, 0xE4, 0x1F, 0x7C, 0x21, 0x3E, 0xA4, 0x98, 0xD1, 0xE9, 0xA9, 0x6A, 0x4C, 0xC6, 0x52, 0x19, + 0x89, 0x42, 0x5E, 0x0C, 0x32, 0xBB, 0xF2, 0x23, 0xD7, 0x24, 0x74, 0x6D, 0x32, 0x6E, 0x42, 0x6D, + 0x91, 0x80, 0x41, 0xBF, 0x3F, 0x88, 0xF0, 0x5F, 0xB1, 0x39, 0x31, 0xEF, 0x4F, 0x19, 0x14, 0xED, + 0xC8, 0x9C, 0xAB, 0xA7, 0x8D, 0xD5, 0x34, 0x3A, 0x0A, 0x7F, 0x0E, 0xAE, 0x02, 0x33, 0xFD, 0xD0, + 0xD6, 0xD9, 0xF1, 0x56, 0x2D, 0x21, 0x92, 0x04, 0xD8, 0xBB, 0x67, 0x97, 0x31, 0xF9, 0xBA, 0x03, + 0xCD, 0xFB, 0x0E, 0x2C, 0x28, 0x6D, 0x07, 0x7C, 0x3F, 0xFF, 0x83, 0x81, 0xE3, 0xDC, 0x0B, 0xC5, + 0x5E, 0x89, 0x47, 0xBC, 0xA1, 0x1F, 0xA8, 0x79, 0x76, 0x88, 0x6B, 0x8A, 0x0F, 0xB2, 0x84, 0xD6, + 0xDC, 0x16, 0x78, 0x51, 0x3C, 0xDB, 0xD4, 0x8D, 0xD6, 0x26, 0xD7, 0xDD, 0x51, 0x5E, 0x8E, 0x5A, + 0xDD, 0x5D, 0x6D, 0x97, 0xB4, 0x33, 0x43, 0xAB, 0x16, 0x35, 0xA2, 0x9E, 0x46, 0x47, 0x47, 0x8B, + 0xE5, 0x39, 0xDD, 0xF1, 0x91, 0xAA, 0x28, 0x33, 0xC4, 0x44, 0x8A, 0x97, 0x32, 0x71, 0x96, 0xE6, + 0x03, 0xD1, 0xDC, 0xA7, 0x95, 0xEB, 0xA6, 0x77, 0x1D, 0x58, 0xDE, 0x15, 0x67, 0x59, 0x3E, 0xE3, + 0xE4, 0x6D, 0x7F, 0x72, 0x42, 0x63, 0xE9, 0xDD, 0x12, 0x5B, 0xCA, 0x86, 0xF0, 0xAA, 0x35, 0x2A, + 0x8F, 0x67, 0xED, 0x4D, 0x53, 0x8F, 0x6D, 0x69, 0x09, 0x51, 0xD9, 0x29, 0xCF, 0xC1, 0x9F, 0xD7, + 0x9B, 0x94, 0x1E, 0x4D, 0x99, 0x0E, 0xA1, 0xF0, 0x92, 0x26, 0x8B, 0xA5, 0x1A, 0xC9, 0x17, 0x03, + 0xAA, 0xCA, 0xC9, 0xB6, 0xC8, 0x44, 0xC8, 0xD8, 0x5C, 0x7E, 0xDF, 0xCC, 0x48, 0xC2, 0xC0, 0xB2, + 0xC9, 0x17, 0xC0, 0x8B, 0x14, 0xA9, 0x89, 0xA2, 0x2C, 0x36, 0x44, 0x5D, 0xB1, 0x4B, 0x66, 0x3A, + 0x21, 0x30, 0x26, 0x4D, 0xE7, 0x46, 0xB3, 0x2B, 0x77, 0xC5, 0xBC, 0x24, 0x1E, 0xB8, 0xFA, 0xC3, + 0xD5, 0x67, 0x31, 0x74, 0xD0, 0x30, 0x3F, 0x2F, 0xF6, 0xC3, 0x85, 0x98, 0x4F, 0x23, 0x41, 0xB3, + 0x1A, 0x0D, 0xF1, 0x6A, 0xD9, 0xAE, 0x56, 0xCA, 0xC8, 0x31, 0xEC, 0x5C, 0x45, 0x25, 0xE7, 0xD6, + 0xB0, 0xAA, 0x57, 0x2B, 0xE5, 0x39, 0x3C, 0x2E, 0x61, 0xD5, 0x0D, 0x1A, 0x65, 0x32, 0xE6, 0xBA, + 0x39, 0x08, 0x2F, 0x06, 0x22, 0x13, 0x6E, 0x7E, 0x72, 0xD7, 0x45, 0xE7, 0x83, 0xE0, 0x03, 0xCC, + 0x66, 0xB0, 0x3A, 0xC1, 0xD2, 0xD5, 0xCD, 0xE6, 0x0B, 0xC3, 0xB6, 0x2B, 0xB4, 0x30, 0xDF, 0x13, + 0x68, 0x3C, 0x1A, 0x49, 0xC4, 0x29, 0x51, 0xF4, 0x85, 0xAC, 0x82, 0xAF, 0x74, 0x43, 0xDA, 0x71, + 0xE3, 0xAB, 0x34, 0xA3, 0x59, 0xB2, 0xC5, 0x51, 0x70, 0x53, 0x51, 0xD3, 0xFD, 0x34, 0x53, 0x40, + 0x28, 0xD1, 0x49, 0xCF, 0x35, 0x34, 0x5F, 0xD0, 0xE0, 0x69, 0x02, 0xCD, 0x1A, 0x96, 0xED, 0x64, + 0xA6, 0x8E, 0x77, 0x66, 0x13, 0x76, 0xE5, 0x91, 0x15, 0x6E, 0x74, 0xFC, 0xAA, 0x77, 0x2C, 0x06, + 0xAE, 0xCD, 0xE4, 0x46, 0x79, 0xDA, 0x20, 0xAA, 0x21, 0x41, 0x10, 0x89, 0xB9, 0xC2, 0x7C, 0xFA, + 0x87, 0x37, 0xE4, 0x16, 0xF2, 0xBD, 0x44, 0xEF, 0xEA, 0x9D, 0xFD, 0x62, 0xC6, 0xCD, 0x38, 0x79, + 0x61, 0xF5, 0x79, 0xF0, 0x3C, 0x7A, 0x1F, 0x90, 0x41, 0xDA, 0x1D, 0x73, 0x50, 0x89, 0x05, 0x1C, + 0x42, 0x48, 0x9B, 0x21, 0xD6, 0x02, 0x29, 0x0B, 0xA5, 0x30, 0x42, 0x4F, 0x0B, 0xFF, 0x3F, 0x6D, + 0xF1, 0x2C, 0x0C, 0x5E, 0x1E, 0x98, 0x18, 0x64, 0xDE, 0x5C, 0x0E, 0xD2, 0x5D, 0x57, 0x7B, 0x70, + 0x98, 0x55, 0xE6, 0xBA, 0xAB, 0x5B, 0x98, 0x14, 0x22, 0xD0, 0xC0, 0x78, 0x2E, 0xD3, 0xCC, 0x8E, + 0x6E, 0x74, 0xB8, 0x5B, 0xCE, 0xF3, 0xFB, 0x25, 0x1F, 0x1F, 0xB0, 0x25, 0x3A, 0x57, 0x8E, 0xC9, + 0x56, 0x90, 0x59, 0x9C, 0x45, 0x5C, 0x5E, 0xC0, 0xC8, 0xBC, 0x1D, 0xED, 0xFB, 0x38, 0x22, 0xA4, + 0x32, 0xE8, 0xE8, 0xAC, 0x40, 0xEB, 0x96, 0x94, 0x8C, 0x99, 0x4A, 0xC0, 0xBC, 0xF0, 0xE3, 0x7C, + 0x2B, 0x71, 0x9B, 0xFD, 0x86, 0x1D, 0x34, 0x69, 0x46, 0xAD, 0xB2, 0x4A, 0x27, 0x8A, 0xEF, 0xF0, + 0xFA, 0x6F, 0x0F, 0xFB, 0x9F, 0x01, 0xBD, 0xBE, 0x3F, 0x11, 0x54, 0x22, 0x6E, 0xFF, 0x75, 0x56, + 0x07, 0x69, 0x43, 0x47, 0x19, 0xDC, 0x79, 0xFD, 0x7F, 0xAE, 0xF5, 0x7D, 0x90, 0x83, 0x39, 0xF0, + 0x4B, 0x6D, 0x4C, 0x49, 0xC6, 0xFD, 0xCE, 0xBE, 0xB8, 0xDF, 0xAE, 0x61, 0xA5, 0xAD, 0x2D, 0xD6, + 0xA0, 0xF4, 0xCC, 0x4B, 0x48, 0xBC, 0xA2, 0xE7, 0x64, 0x71, 0x3E, 0x4E, 0xEB, 0xBA, 0xC8, 0x72, + 0xF2, 0xBB, 0x59, 0x4E, 0xB5, 0x68, 0x8C, 0xA0, 0x2F, 0xEF, 0xFA, 0x6F, 0x7F, 0x2A, 0x45, 0x0D, + 0x78, 0xDF, 0x03, 0x5B, 0x22, 0x0C, 0x6B, 0xDC, 0x42, 0xD9, 0xB5, 0xA9, 0x5D, 0x5F, 0x3A, 0xBC, + 0xDB, 0x9D, 0xFD, 0x7F, 0xC1, 0xFA, 0x63, 0x81, 0xB0, 0x40, 0x02, 0xCC, 0x83, 0x95, 0x7E, 0xA1, + 0xD7, 0x1D, 0x1D, 0xC1, 0x30, 0x20, 0x18, 0x50, 0x89, 0x76, 0x56, 0x11, 0xE7, 0xEF, 0x5F, 0x98, + 0x7D, 0xCB, 0x42, 0x1C, 0x24, 0x10, 0x1D, 0x8F, 0x21, 0x3A, 0x82, 0x34, 0xDA, 0xFE, 0xA1, 0x1B, + 0x7C, 0x53, 0x2F, 0x77, 0x9E, 0x0E, 0x92, 0xD9, 0x5E, 0x9A, 0x77, 0xDD, 0xB1, 0x2D, 0xA8, 0x54, + 0xB1, 0x3D, 0x88, 0xF9, 0xB8, 0x1E, 0xC7, 0x81, 0xC2, 0xF7, 0x68, 0x0F, 0xEB, 0x1F, 0xCB, 0xD1, + 0xAD, 0x28, 0x31, 0x74, 0x54, 0x42, 0x2F, 0x28, 0x8C, 0x39, 0x96, 0xC1, 0xAA, 0x68, 0xA0, 0x42, + 0xA1, 0x97, 0x34, 0xD3, 0x3E, 0x9F, 0x9E, 0xCE, 0x22, 0x48, 0x88, 0x14, 0x1D, 0x94, 0x74, 0x8E, + 0x39, 0x42, 0x07, 0x0C, 0x5D, 0x0C, 0x70, 0x98, 0x34, 0x31, 0x16, 0xC0, 0xCF, 0xB7, 0xEF, 0xE5, + 0x6D, 0x21, 0x74, 0x28, 0xA4, 0x76, 0x77, 0x90, 0x92, 0xD1, 0xE7, 0xA6, 0x03, 0x01, 0x27, 0x9C, + 0x08, 0x95, 0x0E, 0x5D, 0x5B, 0x2A, 0x68, 0x14, 0xBB, 0xD5, 0x28, 0x44, 0xA6, 0xEE, 0x9B, 0xBA, + 0xF3, 0xD6, 0x87, 0x0B, 0x69, 0x9A, 0x54, 0x17, 0x49, 0x43, 0x64, 0xA3, 0x2A, 0x37, 0x32, 0x72, + 0xF1, 0x47, 0xFD, 0x42, 0x33, 0x9F, 0x0C, 0xCE, 0xB1, 0xCA, 0x99, 0x84, 0xB5, 0xAD, 0x4F, 0x4A, + 0x7E, 0x25, 0x6C, 0xC0, 0xBA, 0x65, 0x13, 0x8C, 0xAE, 0xD9, 0xC1, 0xF4, 0xAE, 0x9B, 0x1A, 0x09, + 0x34, 0xF0, 0x9B, 0x3C, 0x0F, 0xBE, 0x81, 0xE7, 0x2A, 0x86, 0xB5, 0x93, 0xA1, 0x20, 0x20, 0x0B, + 0x2A, 0x85, 0x02, 0xFE, 0xA0, 0xF5, 0x43, 0xF4, 0x12, 0xF1, 0xC8, 0x8D, 0xC1, 0xBF, 0xB8, 0x1B, + 0x8E, 0xA4, 0x7F, 0xD7, 0xF0, 0x8D, 0x28, 0xF1, 0x8D, 0xF9, 0x25, 0x77, 0x6C, 0x24, 0x1D, 0x92, + 0xB0, 0x1C, 0xC6, 0x63, 0x33, 0x75, 0xE1, 0xD2, 0xD8, 0xB6, 0xA6, 0x5B, 0x2F, 0xDD, 0xF5, 0xF7, + 0xB8, 0x3D, 0xF7, 0xAC, 0x8B, 0x9F, 0x13, 0xEF, 0xC4, 0x98, 0x73, 0x27, 0x68, 0xF5, 0xED, 0x62, + 0x2A, 0x99, 0x50, 0xC1, 0x4C, 0xAB, 0x56, 0xC8, 0x05, 0x94, 0x1F, 0xED, 0x5A, 0x9C, 0xFC, 0x46, + 0x22, 0x4E, 0xB2, 0x5E, 0x6A, 0x47, 0x77, 0x1D, 0x8B, 0x6D, 0x10, 0x12, 0xBB, 0x8A, 0xAE, 0xAD, + 0xA7, 0x20, 0x2F, 0x22, 0xE5, 0xB9, 0xB9, 0x71, 0x27, 0xC9, 0x01, 0xD5, 0xC9, 0x88, 0x49, 0xB6, + 0x07, 0xB2, 0xD6, 0x8B, 0xA1, 0xBA, 0xA9, 0x5B, 0xC4, 0xBA, 0xC3, 0x1B, 0x5B, 0xBA, 0x03, 0x99, + 0x41, 0x11, 0xEF, 0x6C, 0xB4, 0x78, 0x8E, 0x16, 0xF5, 0x60, 0x44, 0x2F, 0x54, 0xB7, 0xD4, 0x74, + 0xC3, 0xCD, 0xE4, 0x45, 0x2C, 0x1D, 0xD0, 0x34, 0xD9, 0x4E, 0x97, 0xAF, 0x89, 0x87, 0xA1, 0x1C, + 0x93, 0x04, 0x56, 0xEB, 0xCD, 0xB3, 0xAC, 0xE2, 0x04, 0x19, 0x8C, 0xFF, 0xAB, 0x7B, 0x37, 0x13, + 0x92, 0xA6, 0x07, 0x22, 0x36, 0x83, 0xDA, 0xD7, 0xE7, 0xEA, 0x76, 0x42, 0x63, 0x79, 0xCD, 0xCD, + 0x3F, 0x58, 0x88, 0xE4, 0x58, 0xB6, 0x7B, 0xFC, 0x86, 0x4D, 0xE1, 0xFA, 0xD1, 0xFD, 0x71, 0x32, + 0xD1, 0xA8, 0xAA, 0x71, 0x21, 0xEB, 0x0F, 0xF2, 0x6A, 0x7C, 0xF4, 0xD5, 0xDB, 0xEA, 0x6F, 0x5D, + 0xEE, 0x66, 0x24, 0xBB, 0x50, 0xA7, 0x19, 0x44, 0x95, 0xBA, 0xE2, 0x2D, 0x81, 0xC9, 0xE5, 0x59, + 0x7C, 0xA5, 0xD6, 0xA1, 0x6D, 0xE1, 0xC5, 0x9B, 0x32, 0xD9, 0x4A, 0xBC, 0x79, 0x34, 0xA0, 0x54, + 0xA6, 0x86, 0x6B, 0x86, 0xA6, 0x30, 0xA2, 0x68, 0xBB, 0x95, 0x11, 0x99, 0x88, 0xA5, 0x83, 0x42, + 0x38, 0xC0, 0xD5, 0xE2, 0xDF, 0xD5, 0x35, 0x62, 0x71, 0x38, 0x27, 0x97, 0x87, 0xD7, 0xC7, 0x22, + 0x1E, 0x90, 0x63, 0xDC, 0x62, 0x3B, 0x57, 0x6A, 0xE2, 0x89, 0xC1, 0xC2, 0xA3, 0x8A, 0x36, 0x14, + 0x80, 0x22, 0x4C, 0xAF, 0x83, 0x7C, 0x27, 0x2C, 0x2D, 0xA7, 0x22, 0xAD, 0x1C, 0x32, 0x38, 0x3E, + 0x14, 0x30, 0x5B, 0x57, 0x35, 0x74, 0x6C, 0x8B, 0x04, 0x39, 0x01, 0x11, 0x74, 0x4A, 0x12, 0x38, + 0xE1, 0x6D, 0x0C, 0xCB, 0x19, 0x06, 0x0F, 0x49, 0x48, 0x9A, 0x46, 0xBB, 0x37, 0x1F, 0x88, 0x04, + 0x0D, 0x41, 0xA5, 0xD1, 0x82, 0x9A, 0x48, 0xCA, 0xAF, 0xEC, 0x8D, 0x4C, 0x16, 0x4E, 0xAE, 0xA4, + 0x6C, 0x5E, 0x44, 0xA5, 0x37, 0xA3, 0x13, 0xBA, 0x55, 0x60, 0x68, 0xE3, 0x34, 0x25, 0x85, 0xEB, + 0x01, 0x7A, 0x4E, 0xCD, 0x07, 0xFD, 0xD3, 0xB3, 0xD3, 0xF3, 0xFB, 0x16, 0x4E, 0x55, 0x0D, 0x2F, + 0x1A, 0xF0, 0x1C, 0xFC, 0x5F, 0x18, 0x93, 0x16, 0xDD, 0x7C, 0x8C, 0x74, 0x40, 0x57, 0x78, 0x94, + 0x52, 0x92, 0xD1, 0xB6, 0xEF, 0xFD, 0xA5, 0xDC, 0x37, 0xE9, 0x21, 0x26, 0xED, 0x75, 0xCF, 0x6F, + 0xF4, 0x36, 0x96, 0xAE, 0x2C, 0xF1, 0x41, 0x6D, 0x66, 0x98, 0xD3, 0x8C, 0x39, 0xCA, 0x2B, 0xA0, + 0x49, 0x5E, 0xAA, 0x85, 0x85, 0x5F, 0xB7, 0x6A, 0xEF, 0xD8, 0x35, 0xBF, 0xCB, 0xCE, 0x6C, 0x09, + 0x71, 0xA2, 0x14, 0x9E, 0x31, 0x34, 0xB5, 0xC3, 0x0A, 0xD5, 0xBD, 0x75, 0x86, 0xE6, 0x48, 0x8B, + 0xC8, 0xED, 0x6B, 0x8F, 0x2C, 0x86, 0xE0, 0xED, 0xF5, 0xF2, 0xC8, 0x35, 0x6F, 0xBE, 0x71, 0x3A, + 0x5A, 0x9A, 0xEC, 0xEA, 0x54, 0x3A, 0x17, 0x76, 0x4E, 0xA4, 0x78, 0x66, 0x6B, 0xB2, 0xBD, 0x3C, + 0x8E, 0x28, 0x3D, 0x3C, 0xDA, 0xCA, 0x78, 0xF3, 0x9E, 0x43, 0x32, 0xD6, 0xFB, 0xA3, 0xD8, 0x3E, + 0x8F, 0xE3, 0xF9, 0x2C, 0xA7, 0xE2, 0x6A, 0xA9, 0x5C, 0x76, 0x82, 0xF4, 0x5F, 0x34, 0x7D, 0x8E, + 0x80, 0x90, 0xE9, 0xA0, 0x70, 0xA8, 0x96, 0xFB, 0x7E, 0xF0, 0xC7, 0x6B, 0xDE, 0xFB, 0xDE, 0xDA, + 0x76, 0x01, 0x03, 0x68, 0x07, 0x2F, 0x45, 0xD9, 0x86, 0x5C, 0xD4, 0x4C, 0xAF, 0x8D, 0x86, 0x19, + 0x46, 0x62, 0x86, 0x29, 0x25, 0xB6, 0x57, 0x7F, 0x7D, 0x49, 0xAF, 0x79, 0x5E, 0x3C, 0x2B, 0x0A, + 0x87, 0xA6, 0x03, 0xE6, 0xD4, 0xD9, 0xBB, 0xBA, 0xB2, 0xD1, 0xAA, 0x71, 0xC9, 0x86, 0xE6, 0x64, + 0x78, 0x84, 0xF5, 0x72, 0x82, 0x80, 0xB4, 0xED, 0xC8, 0x16, 0xCD, 0x7F, 0x90, 0x16, 0x7C, 0x0A, + 0x82, 0x99, 0xD3, 0xF9, 0x28, 0x36, 0x93, 0xE0, 0x2D, 0xF5, 0x74, 0x67, 0x79, 0xC1, 0x32, 0x84, + 0x78, 0x37, 0xA7, 0x15, 0xAF, 0x8B, 0x26, 0x46, 0x4B, 0x91, 0x77, 0x57, 0x3E, 0x47, 0x5B, 0xEA, + 0x0F, 0xEA, 0x7F, 0xBA, 0x69, 0x87, 0x44, 0x39, 0xA7, 0xA9, 0x8C, 0x1C, 0x89, 0x84, 0xF6, 0xE6, + 0xE5, 0x8C, 0x87, 0x59, 0xD3, 0xF0, 0xA7, 0x98, 0xC2, 0xBC, 0x98, 0x53, 0xC0, 0x64, 0xD4, 0x3F, + 0x2A, 0xC8, 0xDF, 0x29, 0x70, 0x84, 0x86, 0x62, 0x58, 0x0C, 0xE7, 0x73, 0x04, 0x89, 0xF2, 0x20, + 0x15, 0xFB, 0x2E, 0xFC, 0xC1, 0x59, 0x18, 0xB8, 0x52, 0x46, 0x78, 0x09, 0xF9, 0xC3, 0x28, 0xC5, + 0xA5, 0x04, 0xB4, 0x42, 0xC0, 0x75, 0x44, 0x18, 0x3D, 0xCF, 0x8D, 0x36, 0x4C, 0xA2, 0x73, 0x18, + 0x7A, 0xAD, 0xBA, 0xDC, 0xB3, 0x2E, 0x30, 0xE6, 0x73, 0x11, 0x20, 0xFC, 0xE9, 0x1B, 0xB0, 0xF2, + 0x2D, 0xED, 0xA0, 0x17, 0x55, 0x63, 0xB2, 0x46, 0xCB, 0xAC, 0xB4, 0x3B, 0x1F, 0xCA, 0x9A, 0xF5, + 0x50, 0xBF, 0xB7, 0xD2, 0x0A, 0xFA, 0xE7, 0x72, 0x6E, 0x14, 0xEA, 0xA3, 0x05, 0x78, 0xF7, 0x75, + 0xD7, 0x06, 0xF8, 0x2D, 0xE6, 0x4C, 0x71, 0x27, 0xD2, 0x84, 0xF9, 0xA0, 0x5C, 0xDA, 0x1F, 0x69, + 0x1E, 0xEC, 0xF6, 0x7C, 0xB2, 0xC8, 0xEF, 0x7C, 0xF7, 0x37, 0xDB, 0xD3, 0x03, 0x6F, 0xFB, 0xCF, + 0xE0, 0x87, 0xE1, 0x33, 0x60, 0xC4, 0xF5, 0x17, 0xC6, 0x08, 0x50, 0x88, 0x86, 0x58, 0xA2, 0x90, + 0xCB, 0xE7, 0x15, 0x47, 0x15, 0x15, 0xE4, 0x33, 0x9D, 0x4A, 0xF2, 0xA7, 0xE6, 0xA7, 0x2E, 0x73, + 0x94, 0x75, 0x37, 0xC2, 0x8F, 0xB5, 0xBC, 0xA6, 0xB5, 0x05, 0xAB, 0xC7, 0x3C, 0xCC, 0x36, 0xEA, + 0x89, 0x3C, 0xAF, 0xC8, 0xC3, 0xB1, 0x14, 0x02, 0x43, 0x90, 0xE6, 0xE5, 0x4A, 0x2D, 0x8A, 0xAC, + 0x41, 0xF5, 0xAF, 0x0D, 0x3F, 0x6C, 0x3B, 0x4B, 0xA6, 0xC3, 0x70, 0x7E, 0x8B, 0x82, 0xC1, 0x40, + 0x26, 0x0B, 0x65, 0xC3, 0x60, 0x54, 0x5E, 0xF8, 0x53, 0x96, 0x15, 0x74, 0x1A, 0x11, 0xF0, 0x66, + 0x36, 0xAE, 0x3A, 0x11, 0x01, 0xDE, 0x67, 0x18, 0x6D, 0x35, 0x6A, 0x93, 0x13, 0x99, 0x74, 0xBC, + 0x17, 0x4E, 0x68, 0x86, 0x3F, 0x10, 0x9A, 0x08, 0xEB, 0xD3, 0x8F, 0xB7, 0x19, 0xC6, 0x39, 0x49, + 0xC9, 0x8A, 0x2F, 0x42, 0xE6, 0x0F, 0x31, 0xFE, 0x69, 0x13, 0xAF, 0x51, 0x62, 0xF5, 0x79, 0xF8, + 0x0E, 0xBC, 0x46, 0xB3, 0x6E, 0x56, 0xF6, 0xE4, 0x68, 0x25, 0x1F, 0x31, 0x08, 0x55, 0xAA, 0x7F, + 0x62, 0xAE, 0xF2, 0xB3, 0x14, 0xFF, 0xCC, 0xCC, 0xCC, 0x77, 0x53, 0x8B, 0x1B, 0x6D, 0xBA, 0x8D, + 0x41, 0xB4, 0xB9, 0x3C, 0x1E, 0x83, 0xAB, 0x77, 0x31, 0xEE, 0xC4, 0x9D, 0xCE, 0x24, 0x3C, 0x43, + 0xC2, 0x05, 0x9D, 0x5E, 0xAB, 0x17, 0x03, 0xF5, 0x82, 0x28, 0xC8, 0xB3, 0x2E, 0xBC, 0x10, 0x0A, + 0x91, 0x19, 0x98, 0x20, 0xF0, 0x76, 0x4D, 0x31, 0x7C, 0xBA, 0xC4, 0x5B, 0x7C, 0x39, 0xC9, 0x0A, + 0x04, 0xEB, 0x63, 0x28, 0x39, 0xEA, 0x37, 0x96, 0xC5, 0xCE, 0xE8, 0xB5, 0xA5, 0x7A, 0x40, 0x48, + 0x64, 0xC3, 0x99, 0x3A, 0xE1, 0x98, 0x8D, 0x52, 0x49, 0x6D, 0xB6, 0x6B, 0x9C, 0x3A, 0x5B, 0x8E, + 0x3C, 0xD8, 0x4B, 0xC2, 0x6F, 0xC9, 0xA6, 0x20, 0xDA, 0xBA, 0xC4, 0xD2, 0x52, 0x38, 0x0E, 0x69, + 0x9D, 0x63, 0x59, 0xC9, 0xE4, 0x31, 0x0B, 0xA6, 0x32, 0x91, 0x85, 0xED, 0x41, 0x99, 0x32, 0x4B, + 0xAA, 0x99, 0x8A, 0x22, 0xC5, 0x29, 0x06, 0x82, 0x5C, 0x3A, 0xC1, 0x73, 0x88, 0x8A, 0x94, 0x63, + 0x0D, 0xFF, 0x75, 0x83, 0x75, 0xFC, 0x39, 0x7C, 0x19, 0x3A, 0x09, 0xAA, 0xE0, 0x9A, 0x7E, 0xA9, + 0x54, 0x4C, 0xE8, 0x20, 0x93, 0x00, 0x19, 0x3A, 0xA2, 0x3D, 0x57, 0x53, 0x9E, 0xAD, 0x45, 0x23, + 0x24, 0x41, 0xDC, 0x5F, 0x4E, 0x97, 0x7E, 0x19, 0x8E, 0xF0, 0x1C, 0x45, 0x92, 0x34, 0x8A, 0x14, + 0x9F, 0xF7, 0xB3, 0x30, 0xB1, 0xC1, 0xB8, 0x72, 0xC3, 0xDD, 0x9E, 0x01, 0xE2, 0x74, 0x37, 0x26, + 0x21, 0x5D, 0x8A, 0x0A, 0x24, 0x06, 0x7E, 0x50, 0x68, 0x31, 0x21, 0x38, 0x48, 0x81, 0x6C, 0x3B, + 0xAE, 0x63, 0x78, 0xE0, 0x31, 0x6C, 0xBB, 0x25, 0xF6, 0x58, 0x81, 0xF7, 0x48, 0x06, 0xC3, 0x6D, + 0xF8, 0xB2, 0x78, 0x2B, 0x90, 0x77, 0x31, 0x24, 0xA9, 0xF9, 0x49, 0x86, 0xC7, 0xD0, 0xC5, 0xA4, + 0xC3, 0x49, 0x23, 0x1E, 0x26, 0xC9, 0xA8, 0x38, 0x2A, 0xB7, 0x15, 0x39, 0x4A, 0xE4, 0x72, 0xE1, + 0x30, 0xD3, 0xD3, 0x4A, 0xF0, 0xC7, 0xE1, 0x56, 0x0C, 0xCA, 0xF3, 0xB5, 0x1C, 0x47, 0x67, 0x22, + 0x7E, 0x8C, 0xB5, 0x0C, 0x55, 0x20, 0x55, 0xE3, 0xBA, 0xAB, 0xEF, 0xDE, 0x89, 0x16, 0x4D, 0x93, + 0x68, 0x07, 0x03, 0x86, 0xF1, 0x04, 0x89, 0xC7, 0xF9, 0x02, 0xC6, 0xCA, 0x15, 0xF8, 0x2B, 0x8C, + 0x95, 0x37, 0xF7, 0x63, 0xA9, 0x48, 0x3C, 0x1C, 0xA0, 0x4A, 0x7F, 0x33, 0x09, 0xBA, 0x13, 0x14, + 0x9A, 0x20, 0x51, 0xBB, 0x8E, 0x3A, 0x13, 0xED, 0x17, 0x56, 0x74, 0x72, 0xEE, 0x2C, 0x8C, 0xAC, + 0x27, 0xA9, 0xAF, 0x17, 0x89, 0x79, 0x19, 0xDA, 0xE0, 0x12, 0x5E, 0x71, 0xE1, 0x72, 0x64, 0x98, + 0xA5, 0xE1, 0x15, 0x60, 0x2A, 0xD4, 0x10, 0x8C, 0xAD, 0xD3, 0xAA, 0xE3, 0x4A, 0x15, 0x84, 0x75, + 0xB6, 0x2B, 0x3D, 0x31, 0x4A, 0x99, 0x22, 0xDA, 0x6E, 0xBC, 0xDF, 0x41, 0x95, 0x4C, 0x21, 0x1E, + 0xA5, 0x4D, 0x24, 0x68, 0xE9, 0x6C, 0x84, 0x20, 0x52, 0x11, 0x41, 0x09, 0x6B, 0x34, 0x1D, 0xA6, + 0x35, 0xBF, 0xC4, 0x32, 0xD4, 0x9B, 0x31, 0xF8, 0xD5, 0x04, 0x56, 0x84, 0x04, 0x45, 0xDB, 0xA2, + 0xE4, 0x4F, 0xCF, 0x53, 0xDA, 0xB4, 0x3F, 0x49, 0x10, 0xE4, 0x0E, 0x27, 0x68, 0xFB, 0xA1, 0xE2, + 0x47, 0x96, 0xBF, 0x5A, 0x4A, 0x92, 0x28, 0xEA, 0x67, 0x93, 0x7A, 0xF4, 0xC7, 0x8D, 0x30, 0x84, + 0xE6, 0x01, 0x0A, 0x2A, 0xFC, 0xED, 0xA3, 0xFB, 0x28, 0x85, 0xD5, 0x18, 0x35, 0x75, 0x64, 0x33, + 0x25, 0xD5, 0x54, 0x23, 0xBA, 0x58, 0x39, 0x7B, 0xE3, 0x30, 0x8A, 0x83, 0xC6, 0xE1, 0x0F, 0x41, + 0x01, 0x64, 0xFA, 0x72, 0x3A, 0xAE, 0x10, 0x72, 0xF8, 0x17, 0xC5, 0xBC, 0xFE, 0x4B, 0x9A, 0xD9, + 0xB7, 0x56, 0x61, 0x70, 0xC9, 0x3B, 0x51, 0x54, 0x86, 0x54, 0xAC, 0xA0, 0x0A, 0x95, 0x1C, 0x86, + 0x39, 0x5C, 0x5F, 0x35, 0xE9, 0x05, 0x3F, 0xAB, 0xC8, 0x4B, 0xC4, 0x0B, 0x68, 0xF2, 0x43, 0x1F, + 0x8A, 0x18, 0xF1, 0xC9, 0x6A, 0x26, 0x65, 0x0B, 0xAF, 0x64, 0x59, 0xA3, 0x9C, 0xB1, 0x9C, 0x30, + 0x03, 0x25, 0x48, 0x37, 0xC2, 0x7A, 0x2B, 0x69, 0x26, 0x0B, 0x95, 0x40, 0x08, 0x7E, 0x1E, 0x8F, + 0x26, 0xFA, 0x27, 0xCF, 0xA2, 0xFA, 0xF6, 0x07, 0xF7, 0xD7, 0x6C, 0x6B, 0x96, 0x6C, 0xCC, 0x66, + 0x4B, 0x93, 0x26, 0x91, 0xA1, 0x94, 0xA5, 0x91, 0x0C, 0x36, 0xEC, 0x05, 0xD2, 0x1F, 0x4F, 0x0D, + 0x22, 0x36, 0xC4, 0xBB, 0xE0, 0x73, 0x60, 0x0B, 0xA8, 0xF4, 0x8D, 0x4D, 0x33, 0xBD, 0xD4, 0xDC, + 0x68, 0x32, 0x3E, 0x91, 0xDB, 0x9A, 0xFD, 0x55, 0x30, 0x40, 0x11, 0xAE, 0xD2, 0x1A, 0x38, 0xC2, + 0x2E, 0xF3, 0xB1, 0x6F, 0x4D, 0x0D, 0xCB, 0xDA, 0x14, 0x88, 0x61, 0x88, 0x5B, 0xE3, 0x49, 0x7B, + 0xCB, 0x81, 0x01, 0x0A, 0xB9, 0x21, 0x46, 0xE3, 0x5A, 0x76, 0x9E, 0xD4, 0x70, 0xC7, 0xE1, 0x78, + 0xA0, 0x11, 0xE3, 0xE6, 0xB6, 0x67, 0x0B, 0xD2, 0xC4, 0x1B, 0xF2, 0xCB, 0xC9, 0x43, 0x82, 0x5F, + 0x26, 0x0B, 0x82, 0x22, 0x84, 0x32, 0x7E, 0x7F, 0x5E, 0x4E, 0x71, 0xBA, 0xA2, 0x89, 0x58, 0x3D, + 0x0B, 0xB1, 0x46, 0xB5, 0x64, 0xF2, 0x1C, 0xF7, 0x88, 0xC4, 0xF9, 0x67, 0xC6, 0x09, 0xD5, 0x66, + 0x03, 0xD5, 0x34, 0x1D, 0x75, 0x92, 0xD3, 0x5A, 0x22, 0xA9, 0x45, 0xCC, 0x30, 0xB7, 0x57, 0xAE, + 0x75, 0x8C, 0x48, 0xA1, 0xC4, 0xC1, 0x07, 0xBA, 0x0F, 0x34, 0xDE, 0xA0, 0xC2, 0x08, 0x7B, 0xD8, + 0x1F, 0xB1, 0xCB, 0x8D, 0x86, 0xD2, 0xD3, 0x13, 0xB1, 0x74, 0x58, 0xD4, 0x50, 0xFE, 0xBA, 0xFB, + 0x0F, 0x56, 0x48, 0xDF, 0x3E, 0xF6, 0xD4, 0x6B, 0xE9, 0x28, 0x86, 0x27, 0x4B, 0x13, 0x6C, 0xEE, + 0x64, 0xA4, 0xBB, 0xA9, 0x52, 0x8A, 0x94, 0xE3, 0x72, 0x2D, 0x48, 0xB6, 0x4A, 0xB4, 0xA0, 0xEB, + 0x16, 0x6D, 0x78, 0x79, 0x45, 0xCF, 0xA1, 0x04, 0xFC, 0x25, 0x98, 0x03, 0x3B, 0xFB, 0x49, 0x3C, + 0xBF, 0x31, 0xBF, 0xA9, 0x81, 0x52, 0x3E, 0x9D, 0xA2, 0x1B, 0x63, 0x75, 0xF1, 0x67, 0xF3, 0x73, + 0x7F, 0x34, 0x3F, 0x73, 0xD7, 0x7C, 0x1D, 0x8D, 0x35, 0xFE, 0xD5, 0x2A, 0xC1, 0xCC, 0x8B, 0x43, + 0xB8, 0x2F, 0x32, 0xEF, 0x06, 0x21, 0xFE, 0xCC, 0x30, 0xC9, 0x96, 0x66, 0x68, 0x37, 0x10, 0x43, + 0x58, 0x66, 0x14, 0x6B, 0x47, 0x57, 0x4B, 0x78, 0x81, 0xAB, 0xAC, 0x5B, 0xFD, 0x3C, 0x74, 0xA1, + 0x79, 0x6E, 0x90, 0x6C, 0xDB, 0x2B, 0x13, 0x54, 0x88, 0x41, 0x04, 0x07, 0x25, 0xFC, 0xA1, 0xB4, + 0x8F, 0xD6, 0x35, 0xDD, 0x6C, 0x18, 0x05, 0xDE, 0xF6, 0xCB, 0x2D, 0xF3, 0x78, 0x3A, 0x53, 0xD4, + 0x7D, 0x99, 0xB8, 0xBC, 0xA9, 0x56, 0x8F, 0x65, 0x82, 0xF2, 0xEB, 0x04, 0x4E, 0x0F, 0x1E, 0x93, + 0x5A, 0x4D, 0xF1, 0x06, 0x8D, 0xD3, 0x5B, 0x6A, 0x72, 0xD3, 0xD8, 0xD6, 0x48, 0x30, 0xC4, 0x08, + 0xCA, 0x0E, 0x49, 0x0F, 0x1A, 0x14, 0x42, 0x62, 0x68, 0xD1, 0xDF, 0xA5, 0x55, 0xCB, 0x62, 0xB1, + 0x5C, 0xDD, 0xCD, 0xB1, 0x61, 0x55, 0xD1, 0x8C, 0x88, 0x8F, 0x1F, 0x9F, 0x5F, 0x0C, 0xD8, 0x3B, + 0xE8, 0xEC, 0x9B, 0x98, 0x82, 0x6D, 0x87, 0xC9, 0x25, 0x86, 0x64, 0xC2, 0xB6, 0x24, 0x85, 0x27, + 0x2A, 0x27, 0x2A, 0x3E, 0x92, 0x1A, 0xC8, 0xAA, 0x30, 0x0A, 0xE3, 0x79, 0x19, 0x71, 0xFD, 0x03, + 0xB5, 0x00, 0xAC, 0xF9, 0x9D, 0xDC, 0xAF, 0xEB, 0xE2, 0xBF, 0xD5, 0xC1, 0x08, 0x85, 0x46, 0x10, + 0x1A, 0x89, 0xFF, 0x2B, 0xFC, 0xCD, 0x15, 0x8A, 0xF3, 0x82, 0x7A, 0xE1, 0x92, 0xC2, 0x5C, 0xD7, + 0x35, 0x9E, 0xCE, 0x74, 0x53, 0x64, 0x31, 0xB1, 0x20, 0x8F, 0x71, 0x89, 0x61, 0x81, 0x30, 0x31, + 0x08, 0x53, 0x22, 0xB7, 0xBC, 0xD0, 0xDD, 0x0B, 0x08, 0x85, 0x5F, 0x83, 0xB8, 0xC4, 0x5E, 0x5E, + 0x74, 0x02, 0x46, 0xCC, 0x92, 0x39, 0x41, 0xA6, 0x14, 0x41, 0x35, 0xB1, 0xB8, 0x35, 0x4D, 0xB3, + 0xE1, 0x04, 0x78, 0xD9, 0x20, 0x4A, 0xBC, 0x68, 0x8B, 0x69, 0x27, 0x37, 0x16, 0x0D, 0x24, 0xD1, + 0xC7, 0x6B, 0xF7, 0xCC, 0xFE, 0x42, 0xAA, 0xDE, 0x24, 0xCA, 0x8E, 0x55, 0xE9, 0xE6, 0x6A, 0x8B, + 0xDA, 0x78, 0x22, 0xA0, 0x5A, 0xAA, 0x24, 0x27, 0x64, 0x41, 0xE6, 0xBF, 0x9F, 0xCE, 0x44, 0x7C, + 0x8D, 0xEB, 0xBA, 0x2D, 0x78, 0x71, 0xD7, 0xC0, 0x8B, 0xF5, 0x1F, 0xF0, 0xD3, 0x88, 0x00, 0x0D, + 0x3C, 0xA6, 0x70, 0xD1, 0x52, 0x44, 0x10, 0x57, 0x12, 0x11, 0x05, 0xFC, 0x62, 0xB4, 0xE2, 0x1F, + 0xAD, 0x3D, 0x3E, 0xAA, 0xA9, 0xFF, 0xEE, 0x8F, 0x04, 0x2E, 0x90, 0xEE, 0xBE, 0x3C, 0x98, 0xFC, + 0x3D, 0x83, 0x70, 0x43, 0x06, 0xC7, 0x86, 0xB4, 0x60, 0x6B, 0xB8, 0xBA, 0x05, 0xC8, 0x78, 0x5A, + 0xA6, 0xE7, 0xAE, 0x2D, 0x1A, 0x56, 0xC8, 0x34, 0xB0, 0x80, 0x55, 0x48, 0x19, 0x0D, 0x0A, 0x55, + 0xDD, 0x8A, 0xC2, 0x4F, 0x87, 0xA7, 0xB3, 0xA9, 0xE0, 0x88, 0x1D, 0x8B, 0x8B, 0xE3, 0xC5, 0x0F, + 0xFE, 0xA1, 0xA1, 0xDA, 0x9A, 0x14, 0x8C, 0xF4, 0x90, 0x60, 0x25, 0xF6, 0xCB, 0xBB, 0x29, 0x81, + 0x21, 0x0F, 0x85, 0x63, 0xFE, 0x60, 0x4C, 0xCD, 0x53, 0x66, 0xB1, 0xF6, 0x9A, 0xC4, 0x7C, 0x86, + 0x80, 0x14, 0x61, 0xC5, 0xA3, 0xCD, 0x6F, 0x30, 0x90, 0x10, 0x34, 0x49, 0x95, 0x82, 0xBE, 0x0A, + 0xE7, 0x13, 0x48, 0xC8, 0x98, 0x0A, 0x47, 0x9D, 0x4A, 0xE6, 0xE2, 0x45, 0xC5, 0x10, 0x08, 0x2C, + 0xBA, 0xF1, 0xB8, 0xE8, 0xD5, 0x57, 0xC1, 0x26, 0x7A, 0x1A, 0xDB, 0x8A, 0xCB, 0x7D, 0xAC, 0x55, + 0x34, 0x10, 0xC0, 0x7A, 0x69, 0x99, 0x5B, 0x35, 0xF4, 0x11, 0x35, 0x11, 0x1F, 0x01, 0x91, 0xB0, + 0x43, 0xD8, 0x48, 0x12, 0x29, 0x82, 0x0C, 0x20, 0x8E, 0xD5, 0x54, 0x3C, 0xC0, 0x8B, 0x90, 0xBD, + 0x7C, 0x37, 0xA8, 0x81, 0x7B, 0x6B, 0x58, 0xFE, 0xD4, 0xF3, 0x86, 0xBC, 0xC6, 0xF8, 0x49, 0x16, + 0x2F, 0x61, 0x32, 0x91, 0x99, 0x84, 0xA3, 0x99, 0x64, 0xB3, 0xDE, 0xC2, 0xAF, 0xAD, 0x0E, 0xB4, + 0xB0, 0x2E, 0x71, 0x73, 0x23, 0x19, 0x37, 0x49, 0xCE, 0xB4, 0x3B, 0x10, 0x36, 0xAF, 0xCB, 0x6F, + 0x9B, 0x88, 0xC5, 0x26, 0xB6, 0x16, 0xAE, 0x6B, 0x46, 0xEC, 0x6E, 0xAA, 0x51, 0x0E, 0xF9, 0x9A, + 0x67, 0x96, 0xA6, 0xDE, 0x5C, 0x1C, 0xDD, 0xDE, 0x28, 0xBD, 0x79, 0x6A, 0x69, 0xA9, 0x9C, 0x78, + 0xFD, 0x44, 0x8B, 0xD7, 0x27, 0xCB, 0xAF, 0x2F, 0x25, 0xBD, 0x68, 0xC3, 0xEA, 0xB3, 0xE0, 0x9D, + 0xE8, 0x3B, 0x80, 0x00, 0xD1, 0xBE, 0x80, 0xAD, 0x63, 0x02, 0x10, 0xE8, 0x76, 0x88, 0x99, 0x71, + 0x7D, 0x8F, 0x2A, 0x30, 0x0C, 0x01, 0x38, 0x49, 0xAD, 0xF1, 0xCE, 0x43, 0x87, 0x74, 0xF4, 0x0C, + 0xB8, 0x72, 0xC4, 0x01, 0x3F, 0x1E, 0x53, 0x02, 0x80, 0xE5, 0xC4, 0xAA, 0xDF, 0x37, 0x12, 0xE0, + 0xB9, 0x11, 0xC6, 0xD5, 0xFF, 0x12, 0xF2, 0x34, 0xAA, 0x86, 0x12, 0x20, 0x18, 0x60, 0x58, 0xE6, + 0xFF, 0xE9, 0x88, 0xE1, 0x60, 0x78, 0x45, 0xD8, 0x6C, 0x0C, 0x86, 0xDC, 0xAE, 0x40, 0x77, 0x06, + 0xBC, 0x06, 0xDB, 0x1D, 0x72, 0x03, 0x36, 0xAF, 0x18, 0xAC, 0x37, 0x01, 0x90, 0x7A, 0xF1, 0x60, + 0x97, 0xBC, 0x59, 0xC0, 0x3D, 0x9F, 0x07, 0xEF, 0x45, 0x06, 0xDC, 0x0B, 0x1C, 0xD0, 0xEC, 0xAB, + 0xA2, 0x49, 0x00, 0x93, 0x60, 0x2D, 0x65, 0xD5, 0xB4, 0x9C, 0xD5, 0x95, 0xB3, 0xE0, 0xCC, 0x39, + 0x20, 0x40, 0x30, 0x2C, 0x66, 0x25, 0xA0, 0x17, 0xF4, 0x19, 0x46, 0x7C, 0x71, 0xAF, 0x7C, 0xA2, + 0xA7, 0xDC, 0x5D, 0x60, 0xE3, 0x55, 0xB5, 0x0F, 0x92, 0x60, 0x3C, 0xBF, 0x99, 0x61, 0x4E, 0x54, + 0xC3, 0xD5, 0xAB, 0xC3, 0x5A, 0x20, 0x67, 0xA7, 0x36, 0x9C, 0x43, 0x98, 0xAD, 0x2A, 0x45, 0x3E, + 0x93, 0xDC, 0x33, 0x7C, 0x05, 0xAB, 0xAB, 0x83, 0x5A, 0x22, 0xE2, 0x34, 0xC8, 0x00, 0x77, 0xF7, + 0x41, 0x06, 0x3C, 0x01, 0xBE, 0x09, 0xBE, 0xB8, 0xDE, 0xFE, 0xF0, 0x7A, 0xFB, 0xF7, 0xC0, 0x3F, + 0x81, 0x27, 0x3D, 0x0B, 0x67, 0x93, 0x57, 0x89, 0x32, 0x0D, 0xEE, 0xEF, 0x8F, 0x4C, 0x8C, 0x97, + 0xA3, 0x7E, 0xD0, 0x92, 0x69, 0x91, 0xE6, 0x7C, 0x0A, 0x27, 0xFB, 0x74, 0x8A, 0xA4, 0x95, 0x57, + 0xCC, 0x4C, 0x97, 0x67, 0x7A, 0xF7, 0xCF, 0x34, 0xEE, 0xCD, 0x8B, 0xA2, 0x8C, 0x38, 0x1F, 0xE2, + 0x2C, 0xC4, 0xE5, 0x1F, 0x58, 0xCB, 0xE6, 0x3A, 0x07, 0x44, 0xC8, 0xF4, 0x86, 0x32, 0x02, 0x8B, + 0xCE, 0x73, 0x40, 0x87, 0xC4, 0x05, 0xD5, 0xDD, 0xE4, 0x82, 0xBC, 0xB0, 0x96, 0x0B, 0x33, 0xA8, + 0xCC, 0xBA, 0x54, 0xBB, 0xB0, 0xD1, 0x62, 0x9A, 0x89, 0x0E, 0x21, 0x40, 0x92, 0xF1, 0xB2, 0x72, + 0x93, 0x89, 0xEC, 0x20, 0xDD, 0xDE, 0x75, 0x21, 0xB7, 0x2B, 0xE4, 0x4B, 0xD7, 0xBA, 0xD0, 0x8C, + 0xB3, 0xB1, 0xD4, 0x25, 0xA8, 0x86, 0x73, 0xF5, 0x6C, 0xB3, 0xE4, 0x57, 0x63, 0xA6, 0xA4, 0x67, + 0xEC, 0xC8, 0xB6, 0x47, 0x7E, 0x67, 0xD9, 0x0B, 0x8B, 0xA4, 0xF6, 0x7A, 0xDD, 0x4B, 0x09, 0x9B, + 0x15, 0x85, 0xAC, 0x29, 0x49, 0x3A, 0x66, 0xC6, 0x5D, 0xCC, 0xFE, 0x23, 0xBF, 0xAB, 0x06, 0x66, + 0x71, 0x93, 0x9A, 0x7B, 0xD7, 0xA2, 0xE0, 0xCE, 0xB2, 0x57, 0x13, 0x42, 0xDC, 0x8F, 0x67, 0x33, + 0xE7, 0xCD, 0xE6, 0x6B, 0xC1, 0xDB, 0xBC, 0x59, 0xF6, 0xF2, 0x20, 0x89, 0x7B, 0x70, 0xFB, 0x88, + 0xD7, 0xFE, 0x6D, 0x70, 0xC1, 0x6D, 0x1F, 0x64, 0xFC, 0x79, 0xAB, 0x52, 0xDF, 0xB8, 0x2A, 0x83, + 0x4C, 0x16, 0xAF, 0x7D, 0x6C, 0xD8, 0xFE, 0x2B, 0xAF, 0xDD, 0x8B, 0x67, 0xA1, 0x4F, 0xE2, 0xF6, + 0x39, 0x6F, 0xF7, 0xC2, 0xD7, 0xDE, 0x01, 0x5E, 0xD4, 0xCA, 0x60, 0x64, 0xFD, 0x66, 0x70, 0xA9, + 0xFD, 0xC9, 0xF5, 0xF6, 0x6F, 0x81, 0xD7, 0x6C, 0x68, 0xFF, 0xC0, 0x7A, 0xFB, 0x13, 0x97, 0x7D, + 0xFF, 0xA3, 0xEB, 0xED, 0xDF, 0x06, 0xAF, 0xDA, 0xD0, 0xFE, 0xCF, 0xEB, 0xED, 0xDF, 0x73, 0xDB, + 0xBD, 0xC8, 0xCC, 0x26, 0x2F, 0x32, 0x33, 0x03, 0xCE, 0xF4, 0xCB, 0xF9, 0x08, 0x18, 0x15, 0x49, + 0x9E, 0x64, 0x6C, 0x87, 0xB1, 0x25, 0x46, 0x74, 0xA4, 0x2F, 0xD9, 0xEA, 0xCC, 0x9F, 0xCF, 0xF6, + 0xCD, 0xD9, 0xDA, 0xF9, 0x14, 0xCF, 0xD7, 0xC6, 0x6D, 0xC4, 0x18, 0x88, 0x49, 0x7D, 0x73, 0x0D, + 0x00, 0x9E, 0x03, 0xFC, 0x3A, 0x7D, 0xB8, 0xE9, 0x9C, 0xE7, 0x80, 0x3A, 0xA0, 0x0F, 0xF2, 0x12, + 0x7D, 0x9C, 0xEF, 0x5D, 0x51, 0xDB, 0xB2, 0x9E, 0x3F, 0x34, 0x3B, 0x70, 0x0D, 0x28, 0xF0, 0x25, + 0x48, 0x23, 0xE1, 0xD1, 0xC6, 0xA5, 0xB8, 0xCF, 0xE8, 0x8B, 0x02, 0x3F, 0xBD, 0x86, 0x7C, 0x39, + 0x59, 0x04, 0xD3, 0xB3, 0xD5, 0x17, 0x47, 0x82, 0x94, 0xEA, 0x15, 0x91, 0xA0, 0x1A, 0x9F, 0xDD, + 0x48, 0x16, 0x9B, 0x47, 0x66, 0x5F, 0x2A, 0x32, 0x24, 0x47, 0xC7, 0x36, 0x84, 0x86, 0xF0, 0x0C, + 0x7A, 0xB1, 0x14, 0x6F, 0x85, 0x96, 0x06, 0xEB, 0x76, 0x2B, 0x78, 0x51, 0xEB, 0xA5, 0x75, 0x73, + 0xDB, 0x9F, 0xF2, 0xD6, 0x6D, 0xE9, 0xB2, 0x75, 0x1B, 0x7C, 0xFF, 0x03, 0xEB, 0x57, 0x79, 0xC2, + 0x5D, 0x7D, 0xD7, 0x67, 0x0B, 0x25, 0xEF, 0x2A, 0xDF, 0x1C, 0x5C, 0xFB, 0x5F, 0x87, 0xAD, 0xE0, + 0x97, 0x1B, 0x5A, 0x67, 0x23, 0x6B, 0xDF, 0xCD, 0x7B, 0x57, 0x1E, 0xB4, 0x7E, 0x8B, 0x72, 0x5B, + 0xFF, 0xFF, 0xB8, 0xB5, 0xEA, 0x5D, 0x77, 0xD0, 0xFA, 0xC4, 0x7F, 0xB8, 0xAD, 0x9E, 0xB7, 0xC6, + 0xA3, 0x86, 0x5D, 0x43, 0x6A, 0x78, 0x9B, 0xD7, 0x0B, 0xCF, 0xF7, 0xE1, 0x5D, 0x79, 0xF7, 0xE0, + 0x7E, 0xFB, 0x5E, 0xDC, 0x7A, 0x69, 0x2C, 0x83, 0xF6, 0x27, 0xD7, 0xDB, 0xBF, 0xE5, 0xEE, 0xF9, + 0xB9, 0xDE, 0xFE, 0x81, 0xF5, 0xAB, 0x3C, 0x71, 0xF6, 0x52, 0xEB, 0x47, 0xD7, 0x5B, 0xBF, 0x7D, + 0xEB, 0xA0, 0xD7, 0xD8, 0xB6, 0xF0, 0xAE, 0x7D, 0x60, 0xC8, 0x55, 0x6F, 0x00, 0x2F, 0xD5, 0x3E, + 0x8B, 0x49, 0xEA, 0x52, 0xFB, 0x93, 0xEB, 0xED, 0xDF, 0xC2, 0x12, 0xED, 0x52, 0xFB, 0x07, 0xD6, + 0xDB, 0x9F, 0x00, 0xEF, 0xF2, 0xF6, 0x0C, 0x0D, 0xAE, 0x3E, 0x06, 0x3F, 0x89, 0x76, 0x82, 0x1A, + 0xE8, 0x80, 0x07, 0xFB, 0xA5, 0xB0, 0xA5, 0x50, 0xA0, 0x5E, 0xCE, 0x18, 0x76, 0xC6, 0xB6, 0xBA, + 0xDD, 0x92, 0xD5, 0x0D, 0x7C, 0xA3, 0x55, 0x37, 0x0D, 0x8E, 0x25, 0x19, 0x54, 0xB0, 0x8D, 0x3A, + 0x22, 0x47, 0x50, 0x21, 0x4B, 0xAE, 0xAC, 0xB9, 0x19, 0xCF, 0x01, 0x06, 0xDA, 0x3D, 0x2C, 0xC7, + 0x2D, 0x68, 0x79, 0x16, 0xCD, 0x20, 0x76, 0xD4, 0x1D, 0x5A, 0x6E, 0xE7, 0x40, 0x12, 0x6A, 0x2E, + 0x31, 0x9F, 0x03, 0x35, 0xA8, 0xBB, 0x2F, 0x1D, 0x68, 0xAC, 0x6F, 0xC7, 0xB5, 0x01, 0x62, 0x74, + 0xD7, 0x4A, 0xF9, 0x1C, 0x05, 0x6B, 0x9D, 0x4C, 0x76, 0x98, 0x10, 0x98, 0x6D, 0x33, 0xC3, 0x18, + 0x1A, 0x36, 0xE9, 0x18, 0x77, 0x77, 0x09, 0x6C, 0xBB, 0x63, 0xDD, 0x5B, 0xC7, 0xAC, 0x03, 0x33, + 0x83, 0xF0, 0xB4, 0x03, 0xDF, 0x1D, 0xAF, 0x96, 0x03, 0x74, 0x4E, 0x99, 0x6A, 0xB2, 0xDA, 0xE8, + 0x8E, 0x9D, 0x49, 0xD4, 0x84, 0xA4, 0xA2, 0xCA, 0xA5, 0x4D, 0xC9, 0x04, 0xA9, 0x5B, 0xBC, 0xDF, + 0x44, 0x30, 0x55, 0x12, 0x59, 0xD9, 0xFE, 0x18, 0x69, 0x25, 0x02, 0xB4, 0x94, 0x0D, 0x5C, 0x15, + 0x48, 0x84, 0xF8, 0xF9, 0x38, 0x97, 0xDE, 0x24, 0xD6, 0x69, 0x73, 0xF3, 0xEC, 0xD4, 0xCB, 0x5A, + 0xCE, 0xCE, 0xC4, 0x09, 0x48, 0xA0, 0x91, 0x70, 0x30, 0xE0, 0x43, 0x92, 0xE0, 0x4F, 0xA9, 0xFD, + 0xE6, 0x8D, 0x0D, 0x0B, 0x91, 0x1F, 0x79, 0x8C, 0xD0, 0x8B, 0xB6, 0x14, 0xAF, 0x2D, 0x4A, 0x83, + 0x48, 0xE7, 0xBF, 0xA1, 0x9B, 0xD1, 0x57, 0xF0, 0x8C, 0x9F, 0xEE, 0x8F, 0x4D, 0x34, 0xE2, 0xAA, + 0x22, 0x0B, 0x40, 0xE0, 0x19, 0xBE, 0xEA, 0xEB, 0x4D, 0x4E, 0x29, 0x19, 0x0D, 0xBC, 0x6E, 0x6E, + 0x72, 0x66, 0x2B, 0x31, 0x3E, 0xA6, 0x12, 0xCA, 0xA3, 0x0D, 0xCB, 0x34, 0x74, 0x8D, 0xAE, 0x1D, + 0x99, 0xAC, 0x55, 0x91, 0x63, 0xFB, 0x42, 0x6F, 0x22, 0x1E, 0x5E, 0xF3, 0x5A, 0xF7, 0xD6, 0x63, + 0x26, 0xBD, 0x61, 0xAC, 0xCD, 0x8B, 0x53, 0xBB, 0x09, 0xA3, 0xF0, 0x25, 0xF2, 0xE0, 0xE7, 0x54, + 0xCF, 0x3F, 0x8A, 0xF1, 0xA4, 0xBB, 0x6F, 0xDC, 0x14, 0x9E, 0xA6, 0x64, 0xDB, 0xE9, 0xA0, 0x76, + 0xB3, 0x3D, 0xBA, 0x71, 0x8B, 0x94, 0x81, 0xFB, 0x14, 0x63, 0x94, 0x7A, 0xAB, 0xC1, 0x78, 0xB8, + 0x9B, 0x71, 0x1D, 0x6D, 0x58, 0x3E, 0xF4, 0x20, 0xBA, 0xB9, 0x58, 0xCD, 0xB5, 0xB7, 0x24, 0x59, + 0x73, 0x61, 0x24, 0x25, 0x71, 0xEF, 0x3E, 0x25, 0x49, 0x9A, 0x82, 0xE0, 0xD5, 0x6F, 0x6A, 0xAB, + 0xD3, 0x75, 0xC9, 0x97, 0x09, 0xA5, 0x68, 0x4E, 0x8D, 0xC4, 0x4A, 0x31, 0x39, 0xFF, 0xFE, 0xE2, + 0xCB, 0x2C, 0x3B, 0xE3, 0x0B, 0x61, 0xF3, 0x28, 0xA0, 0x8E, 0x5E, 0x5D, 0xD8, 0x7C, 0xFF, 0x78, + 0x31, 0x41, 0xBA, 0x99, 0xA5, 0x68, 0xF4, 0xD8, 0xCD, 0x95, 0x53, 0x30, 0x20, 0x56, 0x42, 0x27, + 0xF6, 0x32, 0x71, 0x47, 0xD4, 0x8C, 0x80, 0xA6, 0x69, 0x56, 0x38, 0x39, 0x39, 0xD9, 0xE8, 0xA0, + 0x97, 0xE1, 0x2F, 0xD5, 0xAA, 0x9D, 0x18, 0x42, 0x90, 0x74, 0x3D, 0xFB, 0x4F, 0xAF, 0xE6, 0x90, + 0x88, 0xFE, 0x1D, 0x4B, 0xF3, 0x05, 0x3C, 0x63, 0xB9, 0x5A, 0x50, 0x07, 0x91, 0x39, 0x2B, 0x03, + 0xAD, 0xCC, 0x14, 0xDB, 0x88, 0xB0, 0x8D, 0xC5, 0x56, 0xFC, 0x4E, 0x5F, 0x6B, 0x1A, 0x95, 0x59, + 0xD4, 0xC8, 0x20, 0x6B, 0x1C, 0x29, 0xBE, 0x1F, 0xAF, 0x87, 0x29, 0xCE, 0x81, 0x16, 0x0C, 0xAE, + 0x15, 0x38, 0x57, 0x3D, 0x45, 0x4A, 0x42, 0xDF, 0x80, 0xA0, 0x20, 0xF4, 0xBB, 0x2F, 0x73, 0x30, + 0xB0, 0xA1, 0xA8, 0xFF, 0xB2, 0xF4, 0xD2, 0xC5, 0xA0, 0x9B, 0x27, 0x86, 0x05, 0x20, 0x3D, 0xF4, + 0x36, 0x7A, 0xFE, 0x13, 0xC6, 0x7B, 0x76, 0x8B, 0x43, 0xD6, 0xEA, 0xFF, 0xD6, 0x13, 0x90, 0x9B, + 0x1E, 0xEA, 0x19, 0x94, 0x3C, 0x13, 0x5E, 0xC5, 0x88, 0x4B, 0x62, 0xA4, 0x33, 0x05, 0x91, 0xF8, + 0x40, 0x6B, 0x2C, 0x19, 0x8D, 0x58, 0xD3, 0x73, 0x37, 0x34, 0xC7, 0x5B, 0x71, 0x8A, 0x3E, 0x77, + 0xCB, 0xF6, 0x9B, 0x24, 0xED, 0x0C, 0x52, 0xAE, 0x4B, 0xD6, 0xE2, 0xBA, 0x91, 0x6B, 0x3F, 0x3A, + 0xDF, 0x9E, 0x29, 0xC9, 0xD2, 0x67, 0x6F, 0x9D, 0xEA, 0x6E, 0x4B, 0xD5, 0x1F, 0x9A, 0xC5, 0x98, + 0x89, 0x4F, 0x48, 0x06, 0xFA, 0xC8, 0xCE, 0x66, 0x50, 0x55, 0x8C, 0x78, 0xB9, 0x9E, 0x6E, 0x87, + 0x16, 0x9B, 0x8D, 0x43, 0x21, 0x35, 0x1B, 0x38, 0xF8, 0x78, 0x79, 0xCC, 0x3C, 0x88, 0xCA, 0x5B, + 0xFC, 0x92, 0x9E, 0x8E, 0xB7, 0xF4, 0x8A, 0x6F, 0x4F, 0xAD, 0x73, 0x34, 0xAA, 0x55, 0xFD, 0x57, + 0xDF, 0x99, 0xBE, 0x48, 0x86, 0xED, 0xC0, 0xFC, 0x84, 0x92, 0xF3, 0x37, 0xEE, 0x0F, 0xE9, 0x59, + 0x97, 0xEA, 0x16, 0xC0, 0xC7, 0xE1, 0x87, 0x51, 0x10, 0x08, 0x20, 0xD4, 0x47, 0x34, 0xF0, 0xE0, + 0x52, 0xA4, 0xE7, 0x96, 0x3E, 0x87, 0xD7, 0x76, 0x6D, 0x12, 0xE9, 0xF5, 0xE2, 0x6E, 0x6F, 0x00, + 0xF0, 0xC3, 0x37, 0x6D, 0xD9, 0x7C, 0xE3, 0x8D, 0x9B, 0xB7, 0xDC, 0x04, 0x8F, 0x6F, 0xBE, 0xE9, + 0xC6, 0x2D, 0x5B, 0x6E, 0x3C, 0xB1, 0x96, 0x9B, 0xFE, 0x76, 0x42, 0x03, 0xC7, 0xC0, 0x6D, 0xFD, + 0xD6, 0x35, 0x07, 0xA6, 0x7D, 0xBA, 0x84, 0xE6, 0xA7, 0xF2, 0xF6, 0x27, 0x6E, 0xD0, 0x7F, 0xC6, + 0x4E, 0x77, 0xEF, 0x5A, 0xDA, 0xF4, 0xCB, 0x4C, 0x2D, 0x5E, 0x6F, 0xA2, 0x89, 0x4A, 0x15, 0x6D, + 0xDE, 0xD4, 0x25, 0x3A, 0xF5, 0x11, 0x34, 0x51, 0x43, 0xE3, 0x63, 0x13, 0xBB, 0x2B, 0x63, 0xEC, + 0x22, 0x9C, 0xBE, 0x3C, 0xE4, 0x37, 0x0C, 0x15, 0x0F, 0x49, 0x77, 0x58, 0xAB, 0x79, 0x59, 0xB6, + 0xBE, 0xDB, 0xB9, 0x1B, 0xA6, 0xD7, 0x2A, 0xF2, 0x7E, 0x87, 0x9F, 0x6A, 0x2D, 0x3A, 0x2E, 0xBB, + 0x4E, 0xED, 0xDF, 0x19, 0x46, 0x1E, 0xEC, 0x61, 0x34, 0xF4, 0x7B, 0xD9, 0xE8, 0x96, 0xDA, 0xEF, + 0xF0, 0x5F, 0xCD, 0x6D, 0xC9, 0x2A, 0xD7, 0x84, 0xB2, 0x96, 0x44, 0x42, 0xE2, 0xF7, 0x87, 0x97, + 0x53, 0x9B, 0x4F, 0x05, 0xD7, 0x3C, 0x62, 0x50, 0x09, 0xFF, 0x9F, 0x7C, 0x5B, 0xF1, 0x5D, 0xC5, + 0xC8, 0xE8, 0xE2, 0x49, 0x63, 0x6C, 0xAA, 0x1A, 0x3B, 0xFD, 0x7B, 0x63, 0xCF, 0xE6, 0xE9, 0x69, + 0xF9, 0xF5, 0xCC, 0x25, 0xB7, 0x99, 0xBB, 0x1B, 0xF3, 0x5A, 0xC5, 0xBF, 0x80, 0x31, 0x71, 0x1A, + 0x54, 0x30, 0x7E, 0x68, 0xFA, 0x03, 0xC8, 0x97, 0x4E, 0xFB, 0xC2, 0x21, 0x3F, 0xE1, 0xB3, 0xD2, + 0x79, 0x6B, 0x99, 0x50, 0x96, 0xB9, 0x60, 0x20, 0x52, 0x2A, 0xE4, 0x23, 0x51, 0x11, 0x01, 0x1D, + 0xD1, 0xC5, 0x42, 0x88, 0x08, 0xA2, 0x48, 0x38, 0x83, 0x12, 0xDC, 0xED, 0xC4, 0xE9, 0xF5, 0x3D, + 0x37, 0x3C, 0xDE, 0x70, 0x85, 0xC7, 0x70, 0xA7, 0xCA, 0x88, 0xB7, 0x3D, 0x4F, 0xF7, 0x1C, 0x28, + 0xC2, 0x99, 0xB5, 0xA5, 0x70, 0xD7, 0x65, 0xB8, 0xCF, 0xEA, 0x20, 0x4F, 0xA9, 0x7A, 0x05, 0xA5, + 0x30, 0x1B, 0xAA, 0xFB, 0x99, 0x64, 0x36, 0x69, 0x61, 0xE3, 0x63, 0x00, 0x2D, 0xDA, 0x2E, 0xFE, + 0xB7, 0xBC, 0xA2, 0xFF, 0xEF, 0xFC, 0xE1, 0x5B, 0xBF, 0xFB, 0xDD, 0xB7, 0xFE, 0xE1, 0x77, 0xF6, + 0xBE, 0xF7, 0x9E, 0x7B, 0xDE, 0xEB, 0x1E, 0xF7, 0xED, 0x3D, 0x52, 0xDF, 0xFE, 0x91, 0xB1, 0xAD, + 0x63, 0xB5, 0x40, 0x29, 0x3B, 0xB7, 0x54, 0x48, 0xC3, 0xE3, 0xEF, 0xF9, 0xDA, 0xD7, 0xDE, 0xF3, + 0x9E, 0xAF, 0x3D, 0xFD, 0xE4, 0xBD, 0x1F, 0xF8, 0xC0, 0xBD, 0xF8, 0xD8, 0xFB, 0x89, 0x4F, 0xC0, + 0x77, 0x34, 0xA6, 0xC6, 0x27, 0x4E, 0x47, 0x7C, 0xB7, 0xFB, 0xB0, 0xD5, 0xB3, 0x71, 0xEC, 0x23, + 0x60, 0x5B, 0x3F, 0x3D, 0xE2, 0x4B, 0xA7, 0x06, 0xC3, 0xAD, 0x2C, 0x07, 0x73, 0xCB, 0xF1, 0x85, + 0x94, 0xE8, 0x13, 0x8B, 0x28, 0x82, 0x47, 0x8C, 0xC7, 0xFD, 0xE2, 0x91, 0xAE, 0x6D, 0x73, 0xD0, + 0xBB, 0xB0, 0xB6, 0xD1, 0xC1, 0x79, 0x77, 0xBB, 0xB8, 0xFA, 0xFF, 0x61, 0x40, 0xD9, 0x8D, 0x3B, + 0x1D, 0x24, 0x3D, 0x94, 0x3C, 0xDC, 0xE0, 0xE0, 0xD2, 0x98, 0xB6, 0x7F, 0xF0, 0x65, 0x2F, 0xFB, + 0xA0, 0x7B, 0x9C, 0x14, 0x8F, 0xCC, 0x1E, 0x3C, 0x7D, 0xEB, 0xB5, 0xF3, 0x87, 0xF8, 0xAD, 0x74, + 0x3B, 0xD3, 0xEA, 0x76, 0x5B, 0x85, 0x26, 0x79, 0x69, 0x60, 0x83, 0x6F, 0x7D, 0xB0, 0xB3, 0x69, + 0xDF, 0x03, 0xD7, 0x5D, 0x7F, 0xDF, 0xCE, 0xCD, 0xC9, 0xFC, 0xF6, 0xFE, 0xD4, 0x9E, 0x42, 0x06, + 0x6B, 0xD2, 0x29, 0x58, 0x27, 0xDE, 0x85, 0x6D, 0x34, 0x11, 0x98, 0xE0, 0xAD, 0xFD, 0x19, 0x5E, + 0x40, 0x04, 0x42, 0xEE, 0x16, 0x78, 0x6E, 0x4A, 0x19, 0x40, 0xF7, 0xB3, 0xBA, 0x86, 0x8D, 0xB4, + 0x65, 0xD6, 0x94, 0x64, 0x45, 0x46, 0x9A, 0xCA, 0x32, 0xC8, 0x0D, 0x90, 0x02, 0x43, 0x67, 0x44, + 0x40, 0x99, 0x86, 0x28, 0x70, 0x14, 0xCB, 0xA8, 0x0A, 0x43, 0x93, 0x04, 0x64, 0xD6, 0x12, 0xE3, + 0xB0, 0x56, 0xF7, 0xB6, 0xC5, 0xC3, 0x0F, 0x38, 0xDC, 0x2A, 0x6F, 0x50, 0x09, 0x3D, 0x08, 0xDF, + 0xBA, 0xE6, 0x9C, 0xE7, 0x1A, 0x75, 0x01, 0x65, 0xE3, 0xC2, 0x70, 0x7B, 0x8D, 0x9F, 0xDC, 0xFB, + 0x79, 0x47, 0x58, 0xDB, 0x6B, 0xC3, 0x7E, 0xD4, 0x7D, 0xE3, 0x6E, 0x86, 0xE7, 0x66, 0x9D, 0x27, + 0x35, 0xC2, 0x4D, 0x50, 0xD3, 0x1A, 0x41, 0xD8, 0xA0, 0x92, 0x1A, 0xFE, 0x6F, 0xC6, 0x89, 0x77, + 0x1D, 0xBC, 0x7D, 0xFE, 0x36, 0x74, 0xF0, 0xF1, 0xE3, 0xC7, 0x1F, 0xBB, 0xF0, 0xEC, 0xD9, 0x43, + 0x67, 0xE1, 0x4E, 0x58, 0x87, 0xB5, 0x8B, 0x5F, 0xF7, 0x8E, 0xB7, 0x5F, 0x7C, 0x16, 0xEA, 0xDB, + 0x2F, 0x7E, 0x0C, 0x6E, 0xDF, 0x8E, 0xE5, 0xD0, 0x08, 0xF2, 0x41, 0xC7, 0xCB, 0x45, 0x8B, 0xF4, + 0x69, 0x2F, 0x17, 0xCD, 0xB3, 0xE2, 0xB0, 0x31, 0x7C, 0x45, 0x3A, 0x9A, 0x1B, 0x1B, 0x81, 0xCE, + 0x47, 0xDA, 0x6F, 0x40, 0x0F, 0xDC, 0xE0, 0x3C, 0x86, 0xF5, 0xC0, 0x33, 0xA8, 0x00, 0x47, 0x31, + 0x02, 0x11, 0x81, 0x1F, 0x4C, 0xF7, 0x2D, 0x1E, 0xD0, 0x8E, 0x64, 0x48, 0xC8, 0xC0, 0x57, 0x71, + 0x56, 0x54, 0x19, 0x12, 0x6B, 0x5B, 0x79, 0xBA, 0xA2, 0xAD, 0x85, 0xC7, 0x7B, 0xC6, 0x1D, 0x93, + 0x30, 0xD8, 0x4D, 0x71, 0xB8, 0xC7, 0xDD, 0xC0, 0x2E, 0x0C, 0x18, 0x5E, 0xFA, 0xFC, 0x20, 0x7B, + 0x08, 0x2B, 0x55, 0xAF, 0xBE, 0x74, 0x78, 0x0E, 0x47, 0x17, 0x59, 0xCA, 0x0A, 0x62, 0x45, 0x4B, + 0x69, 0xEF, 0xBA, 0x74, 0x8A, 0xAE, 0xA9, 0xA1, 0x9C, 0x62, 0xAA, 0xBA, 0x21, 0x95, 0xAC, 0x4B, + 0xA7, 0x03, 0xDC, 0xF5, 0x4B, 0xD4, 0x25, 0x4E, 0x62, 0x64, 0x94, 0x19, 0x22, 0xA6, 0x73, 0xE0, + 0x8B, 0xB8, 0xBF, 0x3F, 0x5C, 0x7D, 0x81, 0x0C, 0xA3, 0xCF, 0x83, 0xBD, 0x18, 0x31, 0xBD, 0xAF, + 0xBF, 0x7D, 0x76, 0x2C, 0x19, 0x92, 0xC0, 0x62, 0xB3, 0x3E, 0x52, 0x2A, 0x64, 0x93, 0xD9, 0xFE, + 0xBE, 0x42, 0x7F, 0xDF, 0xE2, 0xE4, 0xBE, 0x78, 0x02, 0xED, 0xDF, 0xB7, 0x6F, 0x7F, 0x7F, 0x12, + 0xBC, 0x62, 0x99, 0xFD, 0x83, 0xE5, 0xBD, 0x7B, 0x1E, 0x23, 0x29, 0x38, 0xB9, 0x54, 0xED, 0xA6, + 0xAB, 0x5F, 0x3F, 0x70, 0x97, 0x7E, 0x95, 0x69, 0x68, 0xDB, 0x26, 0xFB, 0xDA, 0x01, 0xD4, 0x57, + 0xF7, 0xA1, 0xCD, 0xFD, 0xB1, 0x27, 0x42, 0x33, 0x67, 0x61, 0xE8, 0x8A, 0x92, 0x1F, 0x75, 0xB0, + 0x94, 0xAE, 0x91, 0xE8, 0x6D, 0x64, 0xE1, 0x66, 0xC4, 0xBA, 0x31, 0xB4, 0x35, 0xF6, 0x5D, 0xDF, + 0xE0, 0x78, 0x83, 0x8E, 0xAB, 0x5C, 0x19, 0x3E, 0x5D, 0x0E, 0xAD, 0xD7, 0xB9, 0xBB, 0x26, 0x01, + 0x9D, 0xF1, 0xC2, 0x85, 0xF0, 0xD2, 0x9E, 0x17, 0x44, 0x0F, 0x7A, 0x25, 0xEF, 0x75, 0xBB, 0xE1, + 0xED, 0x74, 0x52, 0x6F, 0xBB, 0xD5, 0xDB, 0x2E, 0x4A, 0x70, 0x0B, 0xBC, 0x4D, 0xDA, 0x2D, 0x78, + 0x97, 0x51, 0x92, 0x36, 0xDD, 0x40, 0x56, 0xC4, 0xAB, 0x03, 0x6C, 0x43, 0xC2, 0x69, 0x93, 0x61, + 0xAF, 0x06, 0x3E, 0xF7, 0x69, 0xCE, 0x2F, 0xF8, 0x15, 0x9E, 0x25, 0xDE, 0xFC, 0x5A, 0x95, 0xF4, + 0x51, 0xBE, 0x97, 0x2B, 0x23, 0x46, 0x70, 0xE1, 0xCE, 0x8F, 0xED, 0x9F, 0xBE, 0xCA, 0x2D, 0x89, + 0x57, 0xFB, 0x22, 0xC9, 0xD2, 0x31, 0x5E, 0x12, 0x9C, 0xC2, 0xA3, 0xAC, 0x54, 0x97, 0xDC, 0xE2, + 0xF8, 0x1D, 0x64, 0xE3, 0xB3, 0x92, 0xDE, 0x3F, 0xB8, 0x13, 0x22, 0x4A, 0x60, 0x8A, 0x6F, 0xA2, + 0x66, 0x2F, 0x6E, 0xFB, 0xCE, 0xF2, 0xBD, 0x83, 0x02, 0x79, 0x2C, 0x9C, 0xF3, 0xA3, 0x5C, 0x88, + 0x73, 0xF7, 0xCF, 0xA0, 0x63, 0xDC, 0x60, 0xFF, 0x8C, 0xE9, 0x47, 0xBE, 0x7A, 0x74, 0x97, 0x57, + 0x2C, 0x8F, 0xF9, 0x83, 0xA4, 0xDD, 0x72, 0x79, 0x22, 0x72, 0x16, 0x52, 0xC1, 0xF9, 0x10, 0x2D, + 0x91, 0x6C, 0x4E, 0xAA, 0x56, 0x64, 0x0A, 0xC1, 0x37, 0xAC, 0x02, 0x44, 0x78, 0xF5, 0xA5, 0xFF, + 0x82, 0xFE, 0x07, 0xFA, 0x02, 0xB6, 0xCE, 0xF6, 0x62, 0x79, 0x12, 0xDA, 0xBD, 0x79, 0xAC, 0x92, + 0x49, 0x85, 0x1D, 0x9B, 0x21, 0xC0, 0x52, 0x23, 0x09, 0xE2, 0xED, 0xBD, 0xDB, 0xDF, 0xBF, 0x6F, + 0x9F, 0x42, 0xEE, 0x9B, 0xFC, 0x33, 0x3C, 0xBF, 0x36, 0xEC, 0x0C, 0xC2, 0x2B, 0xE7, 0x80, 0x06, + 0xC7, 0xBD, 0xF2, 0xC8, 0x17, 0xA5, 0x09, 0xB8, 0x73, 0xB9, 0xCF, 0xAB, 0x8E, 0x40, 0x11, 0xB8, + 0x5E, 0x5F, 0x96, 0xF5, 0xCA, 0xE0, 0xD7, 0x0C, 0xEF, 0x56, 0x63, 0x98, 0xB3, 0x36, 0x85, 0xDA, + 0xDE, 0x0E, 0x4D, 0x97, 0xF2, 0x39, 0xDC, 0x8C, 0x7D, 0xC2, 0x2D, 0x55, 0x84, 0x6B, 0xF9, 0x6C, + 0x19, 0xF4, 0x3F, 0xA2, 0x45, 0x63, 0x4C, 0x18, 0x16, 0x9F, 0x5D, 0x3D, 0xAB, 0x3B, 0xFE, 0xAC, + 0x79, 0x90, 0xE1, 0x06, 0x45, 0x68, 0x1C, 0x65, 0x96, 0x13, 0x12, 0xB9, 0xF5, 0x50, 0xBA, 0xE8, + 0xEB, 0xB4, 0x2F, 0x2F, 0x40, 0x5B, 0x30, 0x2A, 0x76, 0xFE, 0x4F, 0x28, 0x4D, 0x7D, 0xE4, 0x4C, + 0xAC, 0x31, 0x28, 0x53, 0x43, 0x7F, 0x99, 0xAE, 0x9A, 0x73, 0xA7, 0xD7, 0xCB, 0xD2, 0xC6, 0xED, + 0x30, 0xC3, 0x1C, 0xE5, 0x84, 0xCB, 0xAA, 0xD3, 0xB6, 0x3A, 0xF4, 0xDE, 0x9B, 0x0B, 0x8D, 0xC4, + 0x88, 0x75, 0xA9, 0x30, 0xAD, 0xA0, 0xB5, 0x69, 0xE6, 0xE2, 0x9B, 0xD3, 0xCD, 0xC8, 0x9B, 0x1E, + 0x4F, 0xA7, 0x07, 0xB5, 0x6B, 0x03, 0x0B, 0xF7, 0x39, 0xF8, 0x5E, 0xCF, 0x62, 0x58, 0x18, 0xD8, + 0x45, 0x9E, 0x5D, 0xED, 0x55, 0xDD, 0x7B, 0x5C, 0x51, 0x18, 0x72, 0xC5, 0x37, 0x3C, 0x2B, 0xDC, + 0xCB, 0xA3, 0xF2, 0xBE, 0xBD, 0x79, 0xD8, 0xFE, 0x06, 0x30, 0x88, 0x02, 0x7C, 0x0E, 0xDD, 0x8D, + 0x7E, 0x8A, 0x51, 0xF1, 0xAB, 0xFB, 0xD3, 0xBD, 0x6E, 0x39, 0x9D, 0x4A, 0x86, 0x43, 0x41, 0x5D, + 0x53, 0x64, 0x89, 0x63, 0x19, 0xD0, 0xAE, 0x95, 0x0A, 0x46, 0xBB, 0xAD, 0x06, 0x1C, 0xDB, 0x56, + 0x03, 0xC9, 0x04, 0x4F, 0x70, 0x13, 0xE9, 0x14, 0x4B, 0x30, 0x47, 0xC2, 0x21, 0x2C, 0x15, 0x27, + 0xDC, 0x44, 0x0F, 0x25, 0x1A, 0x08, 0x20, 0x75, 0xF6, 0x73, 0xB0, 0xBC, 0x26, 0x07, 0x6C, 0xD8, + 0x5D, 0x4B, 0xB1, 0xDB, 0xB8, 0x63, 0x38, 0x5C, 0xDB, 0x4D, 0x55, 0xED, 0xBE, 0x78, 0xF5, 0x2E, + 0xC1, 0xE5, 0xF2, 0x20, 0x34, 0x44, 0x36, 0xAC, 0x24, 0x43, 0x33, 0xF8, 0x79, 0xB0, 0xA5, 0x2A, + 0x5E, 0x10, 0x77, 0x57, 0xD1, 0x4C, 0x13, 0x2F, 0x12, 0x7E, 0x1D, 0x94, 0x65, 0x6F, 0xC8, 0x99, + 0x27, 0x06, 0x39, 0xF3, 0xE8, 0x6E, 0x55, 0x1B, 0x91, 0x95, 0xAA, 0x70, 0xC7, 0x5B, 0xA8, 0x3C, + 0xF5, 0xE5, 0xAF, 0xC0, 0xA0, 0x59, 0xF3, 0x53, 0x1F, 0xFB, 0x10, 0x49, 0xFB, 0xEC, 0x3B, 0xB7, + 0x59, 0xF6, 0x58, 0x52, 0x66, 0x05, 0x4E, 0x5F, 0xD1, 0xAD, 0xAE, 0x59, 0x2A, 0xE6, 0x54, 0x67, + 0x44, 0xC3, 0x12, 0xBF, 0x52, 0x2E, 0x96, 0xD1, 0xF7, 0xAD, 0xC8, 0xA1, 0x40, 0xF4, 0x5A, 0x7B, + 0x96, 0xDF, 0x5E, 0x9B, 0xDD, 0x65, 0xFB, 0xD4, 0x92, 0xD3, 0x4D, 0x9D, 0xA4, 0x66, 0x35, 0xCA, + 0x6A, 0x65, 0x67, 0x93, 0x89, 0xED, 0xD9, 0x41, 0xFE, 0xFC, 0xE2, 0xF6, 0x1D, 0x89, 0xEC, 0xAD, + 0xA5, 0x8A, 0x4F, 0x90, 0x25, 0x2F, 0x7D, 0xDE, 0x8B, 0x25, 0xF9, 0xBD, 0x58, 0xD2, 0x34, 0xB8, + 0xB6, 0x9F, 0xCD, 0x25, 0xFC, 0xB6, 0xA9, 0xA6, 0x93, 0xF1, 0x08, 0x35, 0xF2, 0x37, 0x33, 0xE4, + 0xB5, 0x33, 0x65, 0x0A, 0x4C, 0xF7, 0x28, 0xD4, 0x23, 0x51, 0xB7, 0x8D, 0xFA, 0xBD, 0xEE, 0x0B, + 0x2B, 0x67, 0xD7, 0xC2, 0x65, 0x67, 0xDC, 0xE9, 0x9A, 0xEC, 0x5D, 0x1E, 0x56, 0xDA, 0xE0, 0x9E, + 0xBE, 0xAC, 0x7E, 0x22, 0x71, 0x79, 0x7C, 0x29, 0x4A, 0xB8, 0x39, 0x21, 0xCD, 0x0D, 0x11, 0xA6, + 0x41, 0xDC, 0xDA, 0x45, 0x5B, 0xBF, 0x37, 0xC6, 0x44, 0xBB, 0x1B, 0x5D, 0xCC, 0x2F, 0x69, 0x84, + 0xBA, 0x16, 0x65, 0x92, 0x59, 0x37, 0xCA, 0x44, 0xD3, 0xDC, 0xEF, 0x0B, 0x32, 0xD1, 0xC9, 0x7C, + 0x32, 0x97, 0x6E, 0xE5, 0x9F, 0x8A, 0xBE, 0xF9, 0xE1, 0x41, 0xA8, 0xE9, 0xFF, 0xA2, 0xEE, 0xCB, + 0xE3, 0xE4, 0x2A, 0xCA, 0x76, 0xDF, 0xAA, 0xD3, 0x67, 0xDF, 0x7B, 0x9D, 0xE9, 0xD9, 0xF7, 0xC9, + 0x64, 0x9B, 0x25, 0x99, 0xC9, 0x3E, 0x93, 0x7D, 0x21, 0x84, 0x09, 0x21, 0x3B, 0x43, 0x86, 0x24, + 0x06, 0x0C, 0x04, 0x48, 0x08, 0x18, 0x64, 0x5F, 0x8C, 0x88, 0x80, 0x88, 0x8A, 0x44, 0x81, 0x0F, + 0x90, 0x25, 0x0A, 0x22, 0x28, 0x2E, 0xEC, 0x88, 0xC8, 0x26, 0xAB, 0x22, 0x84, 0x45, 0xE4, 0x13, + 0xAE, 0xEC, 0x08, 0x08, 0x5C, 0xF4, 0x23, 0xF4, 0x7D, 0xAA, 0x4E, 0x77, 0x4F, 0x27, 0x99, 0x28, + 0xF7, 0xFE, 0xBE, 0xFB, 0xC7, 0x77, 0xA6, 0x6B, 0xBA, 0xBB, 0xBA, 0x4E, 0x55, 0x3D, 0x55, 0x6F, + 0x3D, 0xEF, 0x5B, 0xCB, 0xA9, 0x8A, 0x89, 0x99, 0xA6, 0xFA, 0x46, 0xDF, 0x09, 0xF6, 0x9E, 0x6A, + 0x82, 0xEC, 0xC9, 0xDD, 0x12, 0xA4, 0x4C, 0x8E, 0xCC, 0xCB, 0xDE, 0x5B, 0x72, 0x84, 0xA9, 0xB0, + 0x56, 0xAD, 0x99, 0x0E, 0x88, 0xFC, 0x99, 0x29, 0xFB, 0xD9, 0x7A, 0xAE, 0x8E, 0x4D, 0x95, 0xE1, + 0x47, 0xE7, 0xC3, 0x97, 0x4B, 0x66, 0xFF, 0x20, 0x97, 0x96, 0x23, 0x01, 0x19, 0xAA, 0xA6, 0x65, + 0x7D, 0x35, 0x95, 0x09, 0xF2, 0x8D, 0x6C, 0x5A, 0xA9, 0xAC, 0x80, 0xF9, 0xD5, 0x52, 0x55, 0xE5, + 0x28, 0x65, 0xE9, 0x4C, 0x9A, 0xC7, 0x94, 0x6A, 0xE5, 0x2F, 0xCC, 0x29, 0x76, 0x44, 0x60, 0xCD, + 0xE7, 0xC7, 0x68, 0xE5, 0x4E, 0xED, 0xA2, 0x2B, 0x92, 0x65, 0x7D, 0xBB, 0x83, 0xBC, 0x40, 0x0E, + 0x2D, 0xB2, 0xA9, 0x71, 0xD4, 0x91, 0x99, 0xFD, 0xAC, 0x98, 0x4A, 0x34, 0xB4, 0xE8, 0x0D, 0x3D, + 0x5D, 0xBB, 0x86, 0x59, 0x29, 0xB5, 0xE4, 0x84, 0xF6, 0xA9, 0xFD, 0x47, 0x6C, 0xB8, 0x61, 0xB8, + 0x15, 0x52, 0xFC, 0xA2, 0x95, 0x2B, 0xB7, 0x01, 0x91, 0x7C, 0xF6, 0x4E, 0x22, 0xEA, 0xCE, 0x23, + 0xFA, 0x11, 0x10, 0x31, 0x72, 0xD9, 0x99, 0x6C, 0x80, 0x3F, 0x86, 0x5E, 0xFC, 0xDC, 0xBE, 0x74, + 0x6B, 0x3D, 0x35, 0x85, 0xBE, 0x11, 0xC6, 0xB3, 0x4E, 0x4B, 0x4B, 0x3C, 0x1B, 0xE7, 0x59, 0x56, + 0x98, 0xB7, 0x10, 0x32, 0x02, 0xB3, 0x50, 0x58, 0x87, 0xD3, 0x7B, 0x0B, 0x1B, 0xC7, 0xCA, 0xA6, + 0x54, 0xBA, 0xBE, 0xA1, 0x23, 0x2B, 0xD5, 0xB7, 0x98, 0xE5, 0xF2, 0xF2, 0x8B, 0x9E, 0x32, 0xFA, + 0xD0, 0xD2, 0x8D, 0x5E, 0xA5, 0xA5, 0xB9, 0xE4, 0xA9, 0x1A, 0x36, 0x30, 0xDF, 0x4D, 0xD4, 0x8D, + 0x48, 0xC6, 0x0D, 0xBD, 0x3C, 0x50, 0xED, 0x6E, 0xAB, 0x3C, 0xAE, 0x57, 0xA5, 0x6B, 0x12, 0xE6, + 0xC8, 0xD6, 0xF2, 0xEE, 0xF2, 0xC0, 0x70, 0x52, 0x7A, 0x5D, 0xB5, 0xE9, 0xA8, 0x23, 0x1A, 0x82, + 0x44, 0x6F, 0x5B, 0x59, 0x86, 0xDD, 0xD6, 0xD3, 0x30, 0x72, 0x44, 0x52, 0x55, 0x62, 0x81, 0x5F, + 0x6F, 0xDA, 0x56, 0x55, 0x59, 0x5C, 0x6B, 0x2C, 0x0F, 0x3A, 0x1B, 0x6D, 0x95, 0xC5, 0x54, 0xB7, + 0x47, 0xD7, 0x9B, 0x6A, 0x57, 0x2C, 0xEC, 0x68, 0x17, 0xBD, 0x9E, 0x80, 0x9D, 0xC0, 0x1A, 0xF8, + 0xDD, 0xC0, 0xDB, 0xD2, 0xA7, 0xD7, 0x96, 0x05, 0xAE, 0xA9, 0xB8, 0x72, 0xA7, 0xE0, 0x59, 0x72, + 0x64, 0x61, 0x66, 0x2F, 0x95, 0x8E, 0x99, 0xB6, 0x98, 0x85, 0x29, 0xF2, 0xC8, 0xE0, 0xEB, 0x65, + 0x7B, 0x2C, 0x32, 0x29, 0xAD, 0x0C, 0xF4, 0x1D, 0xEC, 0x93, 0xDB, 0xDB, 0xA6, 0xA5, 0x1B, 0x6B, + 0x75, 0x23, 0xDE, 0xE2, 0x98, 0x56, 0xA3, 0xAA, 0xB7, 0x4F, 0xB5, 0x54, 0x97, 0x97, 0x75, 0x34, + 0x54, 0xB7, 0x85, 0xFC, 0x38, 0xAD, 0x35, 0x9C, 0x76, 0xDA, 0x8A, 0x91, 0x55, 0xCD, 0x35, 0x65, + 0x65, 0x65, 0x29, 0x7F, 0x56, 0x46, 0x8F, 0x75, 0x64, 0x1A, 0xD6, 0x30, 0xC5, 0x49, 0xD4, 0x35, + 0x94, 0x0B, 0xF9, 0x92, 0xB3, 0xF9, 0x92, 0x0B, 0x97, 0x45, 0xCC, 0xB9, 0x26, 0x1A, 0x19, 0x7C, + 0x43, 0x51, 0xD9, 0xBB, 0xB4, 0x56, 0x3C, 0xF7, 0xBD, 0x70, 0xE6, 0xF8, 0x66, 0x74, 0x78, 0xA7, + 0x8C, 0xEB, 0xAC, 0x9B, 0xB2, 0x7C, 0x4C, 0x76, 0xF9, 0x98, 0x85, 0x87, 0xAC, 0xDD, 0xBE, 0x6E, + 0x4D, 0x66, 0x5D, 0x36, 0xBD, 0x6E, 0xE0, 0xF9, 0x75, 0x65, 0xC7, 0xAF, 0xAB, 0x8D, 0xAD, 0x6B, + 0x98, 0xBD, 0x6E, 0xF1, 0xF2, 0xE5, 0x7C, 0x4C, 0xDF, 0xC4, 0xDF, 0xAB, 0x2F, 0x0E, 0xCD, 0xB9, + 0x4D, 0x19, 0x5A, 0x5C, 0x3C, 0xF4, 0x37, 0xF6, 0x19, 0x56, 0x62, 0x01, 0x94, 0x74, 0xB0, 0xD6, + 0x35, 0x0F, 0x2D, 0x3C, 0x6E, 0xC1, 0x4B, 0xFF, 0xBC, 0x6B, 0xF7, 0x41, 0x79, 0x25, 0xAB, 0x94, + 0x3B, 0x4B, 0x56, 0x29, 0xCB, 0x99, 0xAA, 0x1E, 0x61, 0x28, 0xAB, 0x85, 0x85, 0xCA, 0x9D, 0xF1, + 0x8A, 0x39, 0x8D, 0xE5, 0x13, 0xE2, 0x9F, 0x6F, 0x81, 0xFF, 0x82, 0xC6, 0x9A, 0xA5, 0xA5, 0xEB, + 0x9A, 0x63, 0xE3, 0xA2, 0x75, 0xCD, 0x41, 0x22, 0x3B, 0x6D, 0x6E, 0x43, 0xB3, 0xA2, 0xC5, 0xF2, + 0x6B, 0x9B, 0xC7, 0x8F, 0xAD, 0xA9, 0x35, 0x15, 0xA6, 0xFC, 0xBB, 0x47, 0x00, 0x0E, 0xEF, 0x6A, + 0x9B, 0x57, 0xBA, 0x04, 0x7A, 0x4C, 0x7E, 0x05, 0xF4, 0xC8, 0xD6, 0x86, 0xDA, 0x5E, 0x3F, 0xC6, + 0xC5, 0x78, 0xC3, 0x27, 0xB9, 0x47, 0x18, 0x5A, 0x09, 0xF5, 0x40, 0x9F, 0x9D, 0xDB, 0x37, 0xAD, + 0xB1, 0x26, 0x11, 0x37, 0x68, 0xDC, 0x98, 0x96, 0xCE, 0xA9, 0x63, 0x3B, 0xA7, 0x2A, 0x9D, 0x53, + 0x2B, 0x7B, 0x33, 0x63, 0xEA, 0x32, 0x5E, 0x5D, 0xA6, 0x72, 0xE4, 0x88, 0x9E, 0xC6, 0x77, 0xE6, + 0xCE, 0xDC, 0x3A, 0x77, 0xF6, 0xCE, 0xB9, 0x73, 0x9D, 0x1D, 0x73, 0xA7, 0xFE, 0x57, 0xE7, 0xB3, + 0x13, 0x7A, 0x61, 0x45, 0xD6, 0xF1, 0x0C, 0xAD, 0x8A, 0x1F, 0x54, 0xB0, 0xC1, 0x7B, 0x8B, 0x73, + 0x7D, 0xBD, 0xD1, 0xC8, 0x83, 0xC7, 0xE6, 0xE6, 0xAB, 0xA3, 0x77, 0xCA, 0xBE, 0xFB, 0x0F, 0xED, + 0xBD, 0x99, 0xE5, 0xDC, 0xB8, 0x34, 0x26, 0xA2, 0x6D, 0x51, 0x51, 0xEE, 0xA2, 0x6A, 0x1A, 0x7A, + 0x5A, 0x4A, 0xD6, 0x41, 0x65, 0x60, 0x70, 0xC1, 0xAA, 0x68, 0x6E, 0x10, 0x0F, 0xAC, 0x47, 0xB3, + 0xE2, 0xD2, 0x8C, 0x18, 0x87, 0x7A, 0x94, 0x76, 0x04, 0xEA, 0x81, 0xBD, 0x57, 0xDE, 0xD0, 0xA8, + 0xA4, 0x2A, 0xEB, 0xDA, 0x2F, 0x5F, 0xDC, 0x39, 0xAA, 0x26, 0xD3, 0x92, 0x5C, 0xAC, 0xA4, 0xF2, + 0x2B, 0xA4, 0x4C, 0xBD, 0x65, 0x7C, 0x66, 0x6C, 0x6F, 0x68, 0xC4, 0x7C, 0xAE, 0xB4, 0x2E, 0xED, + 0xAE, 0xA8, 0x98, 0x9C, 0x6A, 0x39, 0xC6, 0xAE, 0x54, 0x6D, 0xFE, 0xA5, 0x54, 0x9B, 0x19, 0x0B, + 0x83, 0xC9, 0xFC, 0xC0, 0xA6, 0xB1, 0x5D, 0x3C, 0x68, 0x3E, 0x48, 0xAC, 0x99, 0x6A, 0x99, 0xA6, + 0xEB, 0xC7, 0x29, 0x15, 0x25, 0x2B, 0xA7, 0x6A, 0x95, 0x90, 0x77, 0x1F, 0xD8, 0x30, 0x52, 0x2E, + 0x9C, 0x72, 0xD6, 0xC2, 0x50, 0x58, 0x0A, 0x9A, 0x32, 0x3D, 0xE5, 0xC6, 0xCA, 0x32, 0x4D, 0x87, + 0x9D, 0xE5, 0xE7, 0xA6, 0xB0, 0x3F, 0xF0, 0x2A, 0x0A, 0xA8, 0x93, 0xFA, 0xFB, 0xCA, 0x9A, 0x42, + 0x5D, 0xE7, 0x76, 0x23, 0xB7, 0xBB, 0x3A, 0x97, 0x75, 0xD9, 0x9C, 0xB7, 0xF1, 0x2A, 0x67, 0x80, + 0x55, 0x15, 0x58, 0x26, 0xC9, 0x16, 0x88, 0x31, 0x41, 0x8F, 0xCD, 0x2F, 0x9A, 0xEF, 0xB2, 0xE0, + 0xC6, 0xB0, 0xB2, 0xA1, 0x1D, 0xF9, 0xF2, 0x1B, 0xF2, 0x55, 0x45, 0x03, 0x03, 0x72, 0x35, 0x79, + 0xA4, 0x79, 0x12, 0x25, 0xFB, 0x79, 0xF5, 0x2A, 0x72, 0xFF, 0x98, 0xFC, 0x73, 0x5D, 0xAC, 0x87, + 0xAD, 0x8D, 0xE7, 0xB7, 0xDA, 0xCB, 0xCA, 0x8D, 0xF7, 0x4E, 0x3E, 0x66, 0xC4, 0x64, 0xD7, 0x75, + 0x5B, 0x5B, 0x67, 0xB6, 0x1B, 0xFB, 0xEE, 0xD3, 0xC7, 0x29, 0x5B, 0xDC, 0x6C, 0xCF, 0x9F, 0xC9, + 0xBD, 0xDD, 0xD7, 0xAD, 0xA8, 0x53, 0x74, 0x6F, 0xCC, 0xEC, 0xF1, 0xC3, 0xED, 0xD2, 0x27, 0xC6, + 0x43, 0x67, 0xE7, 0xC6, 0xD3, 0x6E, 0x9E, 0x20, 0x0F, 0xBA, 0x62, 0x56, 0x5F, 0x32, 0x61, 0xA5, + 0x75, 0x1D, 0x9D, 0x05, 0x3F, 0xC9, 0xC5, 0xCB, 0xDE, 0x56, 0x58, 0xFA, 0x0F, 0x74, 0x09, 0xB6, + 0xB0, 0xB7, 0xEC, 0x36, 0x70, 0xEF, 0x01, 0x85, 0xA6, 0xBA, 0xF7, 0x66, 0x83, 0x59, 0x2B, 0xDA, + 0xB2, 0x1E, 0xD8, 0x9A, 0x25, 0xB4, 0x84, 0xAF, 0xF4, 0xF2, 0x1A, 0xFE, 0x66, 0x22, 0xDA, 0x93, + 0xBB, 0x4B, 0xEC, 0xCF, 0xDD, 0x30, 0xA2, 0xAD, 0x6D, 0x44, 0x74, 0x14, 0x0C, 0xFB, 0x38, 0x5B, + 0xD8, 0xA2, 0xBB, 0x72, 0x26, 0xDF, 0xBD, 0xA3, 0xAA, 0xAA, 0xBA, 0x26, 0x3A, 0x0C, 0x06, 0x39, + 0xAB, 0x46, 0xF6, 0x9E, 0xE7, 0x77, 0xCA, 0x3D, 0x1D, 0xE7, 0xF4, 0x41, 0x65, 0xE8, 0x24, 0x4E, + 0xBC, 0x21, 0x5D, 0x28, 0x60, 0x85, 0xA1, 0x0B, 0xC6, 0x0A, 0x03, 0x33, 0xB7, 0x11, 0x67, 0x8B, + 0xF6, 0x38, 0xF4, 0x46, 0x0C, 0x9B, 0x1D, 0x08, 0xCD, 0x75, 0x1B, 0xA9, 0xE2, 0x3D, 0xBF, 0xCB, + 0xE3, 0x08, 0x16, 0xD6, 0x29, 0x61, 0x5D, 0xC8, 0x9F, 0xDF, 0x3D, 0x8B, 0xDF, 0x59, 0xBE, 0xFB, + 0x44, 0x7E, 0xE7, 0xEE, 0x01, 0x7E, 0xDE, 0xEE, 0x13, 0xA9, 0x38, 0x0F, 0xB3, 0xAC, 0x38, 0x0F, + 0xF3, 0x02, 0x33, 0xE8, 0xB2, 0xE2, 0x48, 0xF2, 0xED, 0xC5, 0x91, 0xE4, 0x17, 0xE8, 0x6A, 0x79, + 0xE2, 0xD4, 0x48, 0xE8, 0xA6, 0xB7, 0xE4, 0x6E, 0xE5, 0x15, 0x34, 0x82, 0x96, 0xF4, 0x35, 0x8B, + 0x8D, 0x42, 0xBD, 0x64, 0x4B, 0x65, 0x7D, 0x25, 0xAF, 0x47, 0x27, 0x8F, 0xBC, 0xFA, 0xA4, 0xC7, + 0x93, 0x2D, 0xE5, 0xF6, 0xE4, 0x81, 0x9A, 0xAA, 0xD0, 0x67, 0xAA, 0x32, 0xB4, 0xD6, 0x27, 0x23, + 0xCE, 0xAE, 0x91, 0xA2, 0x22, 0x95, 0xAB, 0x34, 0x5A, 0x86, 0x1A, 0x96, 0x58, 0x8A, 0x56, 0x9F, + 0x7F, 0xAC, 0x25, 0xBF, 0x47, 0x67, 0xB1, 0xCF, 0xB7, 0xD7, 0x67, 0xFE, 0x56, 0xC9, 0x9E, 0xE7, + 0x4F, 0xED, 0xE7, 0x73, 0xE9, 0x5E, 0xE8, 0x95, 0xFB, 0xF9, 0x5C, 0x9C, 0x1F, 0x3C, 0xB5, 0x38, + 0x3F, 0x38, 0x33, 0x9A, 0x89, 0xCA, 0xFB, 0x9F, 0x54, 0xF4, 0x7F, 0x8E, 0x9E, 0x2C, 0x99, 0xD1, + 0x3A, 0xA9, 0x38, 0xA3, 0xF5, 0x1C, 0x3D, 0x20, 0xB5, 0x33, 0xFC, 0x63, 0x35, 0xE8, 0xA3, 0xAC, + 0xA3, 0x1F, 0xF4, 0xF5, 0x0F, 0xAC, 0x5E, 0xBA, 0x70, 0x52, 0x5D, 0x4D, 0x99, 0x45, 0xF3, 0x67, + 0xCE, 0x18, 0x5F, 0x6D, 0xCC, 0x5C, 0x3D, 0xDA, 0x58, 0x3D, 0x7A, 0xCE, 0xA1, 0xA3, 0xD7, 0xAC, + 0x74, 0xD5, 0xCA, 0x89, 0x87, 0xD0, 0xB9, 0xEB, 0x5B, 0x77, 0xAE, 0x5F, 0x7C, 0xC6, 0x9C, 0x55, + 0x2B, 0x4F, 0x3F, 0xB8, 0x7F, 0xF4, 0xAA, 0xD5, 0xDB, 0x0F, 0x5E, 0xB7, 0x76, 0xBB, 0x65, 0xC6, + 0xA0, 0x54, 0x5C, 0xC7, 0x56, 0x46, 0xF3, 0x35, 0x87, 0x1D, 0xBC, 0x38, 0x76, 0xE8, 0xC2, 0xDE, + 0x1F, 0xC6, 0x8D, 0xA1, 0xE3, 0x63, 0x0A, 0xDB, 0xE9, 0xCB, 0xA1, 0x64, 0x31, 0x3E, 0x70, 0x1B, + 0xCD, 0xC9, 0xEF, 0x93, 0x96, 0x67, 0x2A, 0xB9, 0xBC, 0x6F, 0x9F, 0x1E, 0xE4, 0x9E, 0x0F, 0x37, + 0xAC, 0x2F, 0xDB, 0x6B, 0xAF, 0xB4, 0xF1, 0x43, 0x7B, 0x6B, 0x14, 0x3A, 0x3D, 0x62, 0x73, 0x0D, + 0xB1, 0x91, 0xA0, 0x5A, 0xD2, 0xED, 0x49, 0x67, 0xF2, 0x7B, 0x81, 0x15, 0x7A, 0x93, 0xC5, 0xAD, + 0xD4, 0x6A, 0x58, 0xB4, 0x91, 0x5A, 0xAC, 0xA6, 0x74, 0x23, 0x35, 0xC5, 0x5F, 0x3E, 0xB4, 0x0B, + 0x87, 0xE8, 0x00, 0x15, 0xB6, 0xE1, 0xC8, 0xFA, 0x46, 0xD0, 0xBD, 0xD7, 0x36, 0x1C, 0x73, 0xEA, + 0xAB, 0xA2, 0xED, 0xD6, 0xF2, 0x7D, 0xCA, 0xD2, 0x0D, 0xD7, 0x94, 0x7D, 0xF6, 0x5B, 0x2B, 0x53, + 0xDC, 0x19, 0xC3, 0xEE, 0xD5, 0x31, 0x7B, 0x46, 0x5D, 0x6A, 0x52, 0xD3, 0xE1, 0xA5, 0x7B, 0x75, + 0x24, 0x2A, 0xF6, 0xD9, 0x90, 0xED, 0x3C, 0xB9, 0x1D, 0x9B, 0x98, 0x03, 0x7E, 0x83, 0x7F, 0xCA, + 0xDE, 0xA1, 0x35, 0x74, 0x78, 0xDF, 0xD8, 0xA5, 0x07, 0xCE, 0xEB, 0x6D, 0x47, 0x8F, 0x26, 0x9B, + 0x89, 0xD3, 0x84, 0xAE, 0xB1, 0xF3, 0x46, 0x65, 0xFA, 0x47, 0xB5, 0xF5, 0xAC, 0xD9, 0x3E, 0x78, + 0x68, 0x66, 0x70, 0xD5, 0xF3, 0x83, 0xD6, 0x09, 0x83, 0x35, 0x5B, 0x07, 0xEB, 0x76, 0x0E, 0x7A, + 0x3B, 0x06, 0xA7, 0xBC, 0xA0, 0xBE, 0x38, 0xB4, 0x84, 0x2F, 0x28, 0xAA, 0x89, 0x29, 0x62, 0xD4, + 0x6A, 0x98, 0x9E, 0xE6, 0x60, 0xBC, 0x44, 0x6D, 0xD7, 0xEF, 0xB5, 0x3E, 0x36, 0x62, 0xFE, 0x1E, + 0xB1, 0x4B, 0x13, 0x2F, 0xD5, 0x0D, 0x51, 0x2F, 0x73, 0x18, 0xA5, 0x2D, 0xF7, 0x3A, 0x8C, 0x2C, + 0x36, 0x31, 0x4B, 0xFE, 0x69, 0x41, 0x6D, 0xD7, 0xF9, 0x5C, 0x3F, 0xAA, 0x64, 0x45, 0xED, 0x3C, + 0xA9, 0x13, 0x0C, 0xE6, 0x8E, 0x3A, 0xA4, 0x33, 0x34, 0x23, 0xAD, 0xD1, 0xD3, 0xD1, 0x19, 0x4F, + 0x5B, 0x0D, 0x23, 0xF7, 0x55, 0xD8, 0x99, 0x3A, 0x4D, 0x0F, 0x0F, 0xDF, 0x43, 0x61, 0xD7, 0x67, + 0x8D, 0x23, 0xF6, 0x58, 0x79, 0xDB, 0xAA, 0xE9, 0x0B, 0xE3, 0xF1, 0x54, 0xEB, 0xC1, 0xD1, 0xDA, + 0xDB, 0x66, 0xBF, 0x3C, 0x55, 0xD7, 0xB8, 0xAF, 0xAA, 0xAE, 0x69, 0x8A, 0xC7, 0x6A, 0xAB, 0x3A, + 0xD6, 0x49, 0x5D, 0x2D, 0xCE, 0xA1, 0xFB, 0x88, 0x8D, 0x62, 0x87, 0x81, 0x3D, 0x1A, 0xFB, 0x34, + 0xF9, 0x44, 0x24, 0x93, 0x23, 0x5E, 0x87, 0x44, 0x1C, 0xB6, 0x64, 0xAF, 0xE7, 0x22, 0x9B, 0xEA, + 0xC6, 0xD7, 0xB1, 0x51, 0x9F, 0x3D, 0xCD, 0x46, 0x7D, 0xF4, 0xC5, 0xE8, 0x6E, 0xBE, 0xE2, 0xFF, + 0xEE, 0x6E, 0xBE, 0x62, 0xF7, 0x4E, 0xBE, 0x02, 0x77, 0x73, 0x98, 0x8F, 0x6F, 0xB0, 0x3B, 0x60, + 0x33, 0x27, 0xD1, 0x9B, 0xE8, 0xEC, 0x73, 0x46, 0x34, 0x57, 0xC7, 0x7D, 0xD2, 0x53, 0x4D, 0x03, + 0xE5, 0x72, 0x44, 0x4B, 0x61, 0xCB, 0x7A, 0xA7, 0x48, 0x1D, 0x36, 0x5D, 0xEA, 0xB0, 0x67, 0xA8, + 0x64, 0x39, 0x73, 0x75, 0xB4, 0x7F, 0x83, 0x5C, 0x02, 0xA3, 0xCA, 0x67, 0x7C, 0xA2, 0xE7, 0xF9, + 0xC7, 0xC8, 0xCD, 0xA9, 0xF3, 0x5E, 0x69, 0x76, 0x87, 0x37, 0x6A, 0x8C, 0xE9, 0xF4, 0x55, 0x14, + 0xCF, 0x9B, 0x78, 0xD8, 0x4B, 0x8C, 0xC9, 0x9A, 0x96, 0xDD, 0x2D, 0xBC, 0x9C, 0x1E, 0x78, 0x75, + 0xF1, 0x0E, 0xB7, 0x29, 0xAD, 0xEA, 0xE3, 0xEA, 0x33, 0x55, 0x4E, 0x2C, 0x61, 0x34, 0xC4, 0xED, + 0xAA, 0x74, 0x45, 0xB3, 0x2D, 0x76, 0x0E, 0x56, 0x75, 0xAB, 0xAD, 0xA1, 0x3C, 0xEB, 0xC5, 0x42, + 0xA3, 0x21, 0xB4, 0xAA, 0x53, 0x95, 0x6D, 0xF2, 0xD4, 0x2E, 0xF6, 0x5A, 0x69, 0xBE, 0xDB, 0xAA, + 0x2B, 0x1C, 0x53, 0x4B, 0xD4, 0x35, 0x0D, 0xA8, 0x32, 0xDF, 0x59, 0xB6, 0x5C, 0xE6, 0xDB, 0x1F, + 0x2E, 0xDF, 0x8E, 0x38, 0xFE, 0xA5, 0xB8, 0xB9, 0x71, 0x77, 0x8F, 0x30, 0x49, 0x32, 0x79, 0x8F, + 0xE6, 0x96, 0x68, 0x3F, 0x44, 0x31, 0x6D, 0x5C, 0x7A, 0x42, 0x86, 0x84, 0x70, 0x6F, 0x31, 0xBF, + 0x5E, 0x01, 0x02, 0xEF, 0x29, 0xCD, 0x6F, 0x01, 0x44, 0x4D, 0x49, 0x6E, 0x8D, 0x21, 0x10, 0xF2, + 0x9C, 0x95, 0x37, 0xE8, 0x65, 0xE4, 0x3B, 0x4D, 0x4D, 0x7D, 0x5A, 0x32, 0x34, 0x29, 0x1A, 0x39, + 0x8C, 0xA1, 0x9C, 0x4F, 0x14, 0xD3, 0xDF, 0xD3, 0x4B, 0xCE, 0xED, 0xC8, 0x98, 0xE2, 0x19, 0x94, + 0x7D, 0x0A, 0xF4, 0xE5, 0xE1, 0x8A, 0x6F, 0x7F, 0x25, 0x35, 0x94, 0x62, 0x52, 0xA4, 0x28, 0xCE, + 0x08, 0x89, 0x52, 0x54, 0xA3, 0x14, 0xFD, 0x3D, 0x52, 0x4C, 0x0D, 0x57, 0x34, 0xFB, 0x14, 0xC3, + 0xF0, 0x98, 0x65, 0x5A, 0xA8, 0x9A, 0x4F, 0xF8, 0xB3, 0xA5, 0xCF, 0xF6, 0x5E, 0x2E, 0x4E, 0x44, + 0xD8, 0xE7, 0xD9, 0x5E, 0xA1, 0x73, 0xF9, 0x27, 0xBB, 0x47, 0xF2, 0x3F, 0xF2, 0x67, 0xC5, 0xAA, + 0x09, 0xB1, 0xEE, 0x4C, 0xCE, 0xCB, 0x1E, 0x9A, 0x9F, 0x97, 0x95, 0x33, 0xCD, 0xD1, 0x3E, 0x01, + 0x72, 0x15, 0xC4, 0x94, 0xA1, 0x55, 0x10, 0xC4, 0x72, 0x4B, 0x72, 0xAF, 0xB2, 0x6E, 0x7E, 0x13, + 0xD2, 0x69, 0xEB, 0x33, 0x8B, 0xDB, 0x2E, 0x93, 0x18, 0x81, 0x5D, 0x25, 0xC4, 0x9E, 0xD8, 0x4A, + 0x24, 0x58, 0x32, 0xD6, 0x2F, 0xC6, 0x62, 0x4D, 0xD6, 0xC0, 0x58, 0xF7, 0x67, 0xC7, 0x1E, 0xCC, + 0xBE, 0xC9, 0x6F, 0xDA, 0xDD, 0xCD, 0x1F, 0x21, 0x79, 0x52, 0xE5, 0x3C, 0xDC, 0xBF, 0x00, 0x39, + 0x1F, 0x4B, 0xDB, 0xFA, 0x46, 0x57, 0x86, 0xB6, 0x95, 0x4D, 0xC6, 0x33, 0x2D, 0x34, 0x5A, 0x6D, + 0x40, 0x5F, 0xBC, 0xB6, 0xD1, 0x6C, 0xF3, 0xF8, 0xC2, 0xF6, 0x96, 0x54, 0x66, 0xCE, 0xE8, 0x14, + 0x6F, 0xE4, 0xB5, 0xC9, 0x36, 0xEE, 0x55, 0x0C, 0x98, 0xA5, 0x26, 0x10, 0x13, 0x9B, 0x76, 0x49, + 0x53, 0x68, 0x75, 0xFE, 0xD4, 0x1B, 0xBC, 0x48, 0x14, 0xF1, 0xA1, 0xBD, 0x72, 0x0C, 0x93, 0x0D, + 0x6D, 0x34, 0xB9, 0xA7, 0x65, 0x2C, 0xD6, 0xEE, 0xCA, 0x47, 0x25, 0xA3, 0xE1, 0xF9, 0x16, 0x74, + 0x46, 0xA2, 0xDE, 0x49, 0x4B, 0x4F, 0x46, 0x52, 0x5B, 0x06, 0x7D, 0xCE, 0x68, 0xBA, 0xAE, 0xA5, + 0x64, 0x30, 0x9F, 0x2B, 0x3D, 0x13, 0xB2, 0x8B, 0x46, 0xB4, 0x1D, 0x50, 0x39, 0xA1, 0x07, 0xFD, + 0x81, 0xB2, 0xF2, 0x89, 0x7B, 0x7D, 0x1F, 0xBF, 0x74, 0xEA, 0x94, 0x65, 0xC2, 0x9D, 0xDE, 0x33, + 0x31, 0x0D, 0x55, 0x3E, 0xB1, 0x67, 0x52, 0xD9, 0xA2, 0xB6, 0xD1, 0x0B, 0xCA, 0x27, 0xED, 0xF5, + 0xFD, 0xA2, 0xA9, 0xAB, 0x57, 0x4D, 0x83, 0x13, 0xE7, 0xAC, 0xB0, 0x34, 0xBD, 0xC2, 0x1E, 0x82, + 0xE5, 0xD2, 0xDE, 0x67, 0x47, 0xE7, 0xAC, 0x0C, 0xB0, 0xC2, 0xBC, 0x83, 0x60, 0x82, 0xC3, 0x24, + 0x48, 0x9B, 0x0D, 0xEC, 0x73, 0xDA, 0x4A, 0x62, 0x3F, 0xA7, 0xAD, 0xB0, 0xD5, 0xA5, 0xC7, 0xAD, + 0x14, 0x6D, 0x86, 0x4D, 0x45, 0x9B, 0x61, 0x17, 0xBD, 0x28, 0x6D, 0x89, 0x68, 0xD5, 0xCC, 0xA6, + 0xE2, 0xAA, 0x19, 0x39, 0xFA, 0x3C, 0x8C, 0xED, 0x71, 0x01, 0x6A, 0x7F, 0x28, 0xFC, 0x96, 0x62, + 0xF8, 0x0B, 0xE9, 0x27, 0x25, 0xFE, 0x43, 0xAB, 0x6F, 0x66, 0x46, 0xE1, 0xC5, 0xEE, 0x85, 0x2C, + 0x2E, 0xFD, 0x47, 0x45, 0xF1, 0xE4, 0xFE, 0x4B, 0xFA, 0x33, 0xF8, 0x77, 0xC9, 0x74, 0x47, 0xE5, + 0xD3, 0xF5, 0x65, 0x3C, 0xEF, 0xC3, 0x7F, 0xA2, 0x8C, 0x7F, 0x54, 0x3E, 0x7E, 0xB5, 0x18, 0x8F, + 0x51, 0x12, 0xCF, 0x4C, 0xD8, 0x38, 0x43, 0x36, 0xCF, 0xA9, 0x45, 0x9B, 0xE7, 0x02, 0xBA, 0xB5, + 0xC4, 0x7F, 0x53, 0xD1, 0x7F, 0x97, 0xC8, 0xCF, 0xFF, 0x7B, 0x3B, 0xD9, 0x27, 0x9D, 0x99, 0xD1, + 0xD8, 0x4F, 0xDE, 0x4A, 0x3D, 0xB5, 0x68, 0xA5, 0x5E, 0x40, 0xEF, 0x95, 0xF8, 0x6F, 0x2A, 0xFA, + 0x8B, 0x31, 0xA1, 0xE1, 0xC2, 0xCF, 0x64, 0x2D, 0xB2, 0x5D, 0x89, 0x35, 0x23, 0xAF, 0xB0, 0xBF, + 0x83, 0x9D, 0x7A, 0xFA, 0xE2, 0x0E, 0xD9, 0x86, 0xC6, 0x53, 0x5C, 0xE5, 0xE9, 0x01, 0xF1, 0x48, + 0x95, 0x53, 0xDC, 0x8A, 0x4D, 0x8C, 0x1B, 0xAF, 0xE9, 0xCD, 0x4B, 0xFA, 0xD0, 0x76, 0x09, 0x19, + 0x27, 0x7A, 0xAE, 0x6A, 0xDF, 0x87, 0xFB, 0x5E, 0xD9, 0xF7, 0x69, 0xBE, 0xFE, 0x61, 0x1E, 0xDF, + 0x13, 0x39, 0xE0, 0xA3, 0x59, 0x23, 0xBF, 0x16, 0xE2, 0x37, 0xAA, 0xCF, 0x88, 0x91, 0xAA, 0xC9, + 0x9D, 0x07, 0x44, 0x8B, 0x1E, 0x84, 0x4D, 0x27, 0xDA, 0x94, 0xD5, 0x2B, 0x2D, 0x79, 0xCE, 0xFA, + 0x76, 0x47, 0xC9, 0x46, 0xFB, 0x0D, 0xC8, 0x11, 0x25, 0xD6, 0x18, 0x0D, 0x1F, 0xF1, 0xD1, 0x2B, + 0x57, 0x6E, 0x43, 0x6C, 0x4F, 0xF3, 0x2E, 0x36, 0x87, 0xDF, 0x02, 0xEE, 0xEB, 0xE9, 0x0B, 0xC8, + 0xD3, 0xED, 0x30, 0xA6, 0x1F, 0xE5, 0x85, 0x47, 0xC5, 0xBC, 0x81, 0x98, 0x64, 0x41, 0x4B, 0x4C, + 0x14, 0x9E, 0x28, 0xBA, 0x6A, 0x8E, 0x38, 0x35, 0xB2, 0x64, 0xAF, 0x15, 0xC1, 0x86, 0xB6, 0xDC, + 0xDA, 0x53, 0xC8, 0x76, 0x71, 0xE5, 0x9D, 0x9C, 0x32, 0x63, 0x73, 0x32, 0x99, 0xEA, 0xD6, 0xD4, + 0x39, 0x61, 0xA2, 0xDC, 0xAD, 0xA8, 0x68, 0x6F, 0x4C, 0x9D, 0x56, 0x11, 0xAF, 0x74, 0xF9, 0x95, + 0x0D, 0x0D, 0xCD, 0xAD, 0xA9, 0x64, 0xB2, 0xB3, 0xA7, 0x15, 0x26, 0x12, 0xCB, 0x3D, 0xC5, 0xE7, + 0xB1, 0xD9, 0x7C, 0x07, 0x7A, 0x51, 0x6D, 0x7D, 0xE8, 0x57, 0x39, 0x1D, 0xAA, 0x61, 0x99, 0xBB, + 0x06, 0x24, 0x33, 0xAC, 0x13, 0xA5, 0x48, 0x6C, 0x2D, 0xC8, 0xB7, 0x37, 0x7A, 0x6E, 0x1A, 0x09, + 0xFA, 0x62, 0x01, 0xA2, 0x3C, 0xF0, 0xAE, 0x21, 0xB2, 0x24, 0xD9, 0x6C, 0x2F, 0x3B, 0x62, 0x4D, + 0x75, 0xDD, 0x96, 0x44, 0x7D, 0x7C, 0x70, 0xC2, 0xE8, 0x95, 0x7C, 0xC7, 0xD8, 0xCA, 0x18, 0xD7, + 0xE6, 0x70, 0xF9, 0x74, 0xEA, 0xCB, 0xBC, 0x0E, 0x2C, 0x78, 0x3B, 0xD9, 0xD4, 0xDC, 0xA7, 0xAB, + 0x64, 0xAC, 0x54, 0xEC, 0x01, 0xD9, 0x52, 0xD7, 0x8B, 0xC8, 0x35, 0x18, 0xBE, 0x12, 0x52, 0x7E, + 0x5E, 0x5C, 0xCD, 0x2F, 0x23, 0x6C, 0x89, 0xB6, 0x8B, 0x60, 0xDD, 0xC9, 0x55, 0x53, 0xCF, 0x1A, + 0x51, 0xDF, 0xB6, 0x7E, 0xD4, 0xFC, 0x80, 0x5F, 0x39, 0x75, 0xC6, 0xE9, 0xD9, 0x03, 0x9A, 0x9B, + 0x20, 0x83, 0x2B, 0x78, 0x1B, 0xBD, 0x28, 0x67, 0xA8, 0xC0, 0x03, 0xD6, 0x30, 0x3C, 0xD0, 0xDD, + 0x5B, 0x98, 0x94, 0x2A, 0xE5, 0x01, 0xB7, 0x94, 0x07, 0x78, 0x26, 0xFD, 0xE2, 0xF0, 0xD3, 0x4E, + 0x82, 0x73, 0x6D, 0x9E, 0x64, 0x36, 0x7F, 0x49, 0xCE, 0x7F, 0x76, 0xF5, 0xF9, 0xFE, 0x46, 0x33, + 0xB5, 0x51, 0x89, 0xE6, 0x3A, 0x4B, 0xD3, 0xD9, 0x20, 0x27, 0xF6, 0xDD, 0x92, 0x6D, 0xEC, 0xC5, + 0x6A, 0xC8, 0x7F, 0x31, 0xC7, 0xC9, 0xEC, 0xF9, 0x3D, 0xDD, 0x0B, 0xE6, 0xF7, 0x4C, 0x98, 0x37, + 0xAF, 0xAC, 0xB6, 0x3A, 0x2B, 0x1C, 0x3F, 0xA9, 0x63, 0xDC, 0xF8, 0xF6, 0xAE, 0xCE, 0xCE, 0xAE, + 0xDA, 0x86, 0xC6, 0x1A, 0x38, 0x21, 0x63, 0x9F, 0xE4, 0x5A, 0xE9, 0x35, 0x00, 0x4B, 0xD0, 0xDC, + 0xBE, 0xCA, 0x40, 0x0D, 0xC9, 0xF3, 0x8C, 0x64, 0x88, 0x8E, 0xD8, 0x03, 0x8A, 0x27, 0x72, 0x47, + 0x81, 0x4F, 0xCA, 0x5F, 0x8B, 0xA7, 0x74, 0x45, 0xFD, 0xDA, 0xFC, 0xCA, 0x6F, 0x51, 0xAE, 0x47, + 0xE4, 0xF7, 0x5B, 0x8E, 0x0A, 0x36, 0x89, 0x82, 0xCD, 0x44, 0xEB, 0xCF, 0xD2, 0x85, 0xE5, 0x67, + 0x5D, 0x7A, 0x67, 0xFA, 0xB5, 0xD9, 0x1D, 0x33, 0xBB, 0x6B, 0xEA, 0xBB, 0xC2, 0x74, 0x4B, 0x63, + 0x7B, 0x47, 0x45, 0xE3, 0xF8, 0x33, 0x1B, 0xC6, 0xB5, 0x57, 0x54, 0x04, 0x6E, 0x90, 0x3A, 0x7A, + 0x4A, 0x8B, 0x18, 0xA3, 0x79, 0x8C, 0x27, 0xD8, 0xC9, 0x72, 0x16, 0x51, 0xA7, 0x8E, 0x3E, 0x5F, + 0xE3, 0xE8, 0xC9, 0x0A, 0x4D, 0xA6, 0x2B, 0x4F, 0xE6, 0xCD, 0x18, 0xC6, 0xBE, 0x98, 0x3F, 0xCF, + 0xB4, 0xE4, 0x74, 0xCF, 0x8E, 0xFC, 0xA9, 0xA6, 0x50, 0x16, 0xA2, 0x8D, 0xB1, 0x93, 0xEF, 0x6E, + 0xFD, 0xE6, 0xF1, 0x70, 0xFC, 0xB4, 0xA3, 0x2A, 0xB7, 0xF7, 0xC0, 0x91, 0xEC, 0x6D, 0xB5, 0xD2, + 0x5F, 0x80, 0x31, 0x14, 0xCF, 0xA7, 0x99, 0xE4, 0xF3, 0xF0, 0x92, 0xB8, 0xFF, 0x00, 0x77, 0xB8, + 0x6A, 0x1A, 0xC4, 0xFF, 0x9A, 0x47, 0x55, 0x14, 0xF8, 0xE8, 0x94, 0x2E, 0x81, 0x24, 0x5F, 0xB4, + 0x62, 0xDF, 0x7B, 0x59, 0xAA, 0x3D, 0x7F, 0x19, 0xD9, 0xD9, 0x3A, 0x75, 0x46, 0xC7, 0xD8, 0xB6, + 0xC6, 0xB2, 0x54, 0x55, 0xD9, 0xDD, 0xD9, 0x8E, 0xD6, 0xC6, 0xB9, 0xD9, 0xD6, 0xB1, 0xD5, 0xC9, + 0xA6, 0x70, 0xEF, 0xF6, 0xAA, 0xA0, 0xFE, 0x62, 0x4A, 0x5E, 0x11, 0x0F, 0x46, 0x8A, 0xD8, 0x12, + 0x27, 0x9D, 0xCA, 0x1E, 0xF7, 0xC6, 0x42, 0x7B, 0x55, 0xE4, 0xC1, 0xA4, 0x2D, 0x5D, 0x99, 0x1E, + 0xD6, 0xB8, 0xE6, 0xE8, 0x23, 0x4E, 0x68, 0xEF, 0xE0, 0xD7, 0x6E, 0xDB, 0xB6, 0x64, 0x09, 0x15, + 0xAF, 0xF5, 0x7B, 0xB9, 0x7F, 0x46, 0x67, 0x60, 0xF3, 0x2F, 0x13, 0xC5, 0xAA, 0x89, 0x54, 0xA8, + 0x6E, 0xBD, 0x0C, 0x6E, 0x11, 0xDC, 0xE3, 0x44, 0x06, 0xDE, 0xCD, 0xF3, 0x89, 0xAC, 0x18, 0xDC, + 0x46, 0xB8, 0xD7, 0x89, 0xEC, 0x59, 0x70, 0x57, 0x12, 0x39, 0x87, 0xC0, 0x3D, 0x49, 0xE4, 0x7E, + 0x0F, 0x7D, 0xEF, 0x55, 0x44, 0x3E, 0xFA, 0xEB, 0x41, 0x00, 0xB7, 0x8B, 0x28, 0xBC, 0x88, 0x28, + 0x7E, 0x23, 0x51, 0xE2, 0x68, 0x02, 0x45, 0xC0, 0xFD, 0x82, 0x28, 0x55, 0x0F, 0x77, 0x1A, 0xDC, + 0x9B, 0x44, 0xE9, 0x47, 0x89, 0x32, 0xAF, 0x12, 0x95, 0xDD, 0x4D, 0x54, 0xFE, 0x0C, 0x51, 0xF6, + 0x62, 0xA2, 0x8A, 0xB3, 0x88, 0x2A, 0xF1, 0xB9, 0xEA, 0x5D, 0xA2, 0xEA, 0x47, 0xC4, 0xB1, 0xDC, + 0x70, 0x9F, 0x10, 0xD5, 0x21, 0x9E, 0x7A, 0x84, 0x6D, 0xB8, 0x8E, 0xA8, 0x11, 0xAE, 0xE9, 0x69, + 0xA2, 0xE6, 0xAB, 0x89, 0x5A, 0x8E, 0x23, 0x6A, 0x5D, 0x4B, 0x34, 0x02, 0x71, 0xB6, 0x6D, 0x21, + 0x1A, 0x89, 0x84, 0x46, 0x3E, 0x44, 0x34, 0xEA, 0x0C, 0xA2, 0xD1, 0x37, 0x83, 0x3C, 0xEF, 0x24, + 0x1A, 0x7B, 0x19, 0x51, 0x3B, 0xF2, 0xDF, 0x01, 0x2B, 0xA7, 0x03, 0xF9, 0xEC, 0x5C, 0x08, 0xF7, + 0x2B, 0xB8, 0xF7, 0x88, 0xBA, 0x9A, 0x89, 0xC6, 0x21, 0x6F, 0xE3, 0x90, 0x9F, 0xF1, 0xDF, 0x26, + 0xEA, 0x46, 0x5C, 0x90, 0x4A, 0x9A, 0x00, 0xCF, 0x89, 0x28, 0x9B, 0x49, 0xCB, 0x88, 0x26, 0xA7, + 0xE1, 0x90, 0xDE, 0x54, 0x84, 0x9B, 0x8A, 0xFB, 0xA7, 0xDD, 0x4A, 0xD4, 0x8B, 0xF4, 0xFA, 0xD0, + 0xDC, 0xA6, 0xE3, 0xB7, 0xE9, 0x2F, 0x13, 0xCD, 0xB8, 0x9D, 0x68, 0xE6, 0x4E, 0xA2, 0x59, 0xC0, + 0x3C, 0xFB, 0x42, 0xA2, 0x39, 0xD0, 0x20, 0x73, 0x91, 0xDE, 0x3C, 0x94, 0xCF, 0x7C, 0x68, 0x4B, + 0x31, 0x91, 0xB5, 0x00, 0x61, 0x16, 0x7C, 0x40, 0x74, 0x00, 0xB0, 0x2C, 0x6C, 0x87, 0x43, 0x99, + 0x2F, 0x1C, 0x24, 0x3A, 0xF0, 0x12, 0xB8, 0x9B, 0xE0, 0x1E, 0x80, 0x7B, 0x09, 0xEE, 0x63, 0xA2, + 0x45, 0x0E, 0x1C, 0x9A, 0xD3, 0x22, 0xC4, 0xB1, 0x08, 0x71, 0x2C, 0x42, 0x19, 0x2E, 0x3A, 0x87, + 0xE8, 0x20, 0x84, 0x3B, 0xE8, 0x7E, 0xB8, 0x17, 0xE1, 0x3E, 0x24, 0xEA, 0xB7, 0xE0, 0x6A, 0xE1, + 0xBA, 0xE1, 0x80, 0xAB, 0x1F, 0xF9, 0xEF, 0x47, 0x3D, 0xF6, 0x23, 0x1F, 0xFD, 0xC8, 0x4F, 0xFF, + 0xBD, 0x70, 0x28, 0xCF, 0xFE, 0xB7, 0x89, 0x16, 0xA3, 0xFE, 0x16, 0x57, 0xC2, 0x01, 0xDB, 0xE2, + 0x85, 0x43, 0xEE, 0x60, 0x60, 0x59, 0x82, 0x78, 0x0F, 0x41, 0x7C, 0x4B, 0xA7, 0x45, 0x6E, 0x19, + 0xEA, 0x64, 0x39, 0xF2, 0xBB, 0x02, 0x79, 0x5B, 0x79, 0x0A, 0x1C, 0xEA, 0x6E, 0x15, 0xE4, 0x60, + 0xD5, 0x06, 0xA2, 0x43, 0x91, 0xB7, 0x01, 0x7C, 0x1E, 0x58, 0x9F, 0x77, 0xF8, 0x7D, 0x00, 0x65, + 0x77, 0x18, 0xF2, 0xB4, 0x06, 0x75, 0x35, 0x88, 0xFA, 0x1F, 0x04, 0xE6, 0xC1, 0x3E, 0x38, 0xC8, + 0xD6, 0xE1, 0x71, 0x38, 0x94, 0xEF, 0xDA, 0x73, 0xE1, 0xAE, 0x80, 0xC8, 0x41, 0xC6, 0xBE, 0xB0, + 0x95, 0x68, 0x03, 0xAC, 0xD1, 0x0D, 0x1F, 0x47, 0xEE, 0x88, 0x0D, 0x79, 0x87, 0xBC, 0x1C, 0x71, + 0xC9, 0x90, 0x3B, 0xF2, 0xC8, 0xBC, 0x43, 0x7D, 0x1E, 0x79, 0x29, 0x1C, 0xEA, 0x74, 0x23, 0xD2, + 0x3C, 0x0A, 0xB2, 0x71, 0xB4, 0x01, 0x37, 0x07, 0xEE, 0x33, 0xA2, 0x4D, 0xC8, 0xDF, 0x31, 0x48, + 0xF3, 0x98, 0x6F, 0xE7, 0x1D, 0x64, 0xEB, 0x18, 0xC8, 0xCB, 0x31, 0x9F, 0x12, 0x1D, 0x8B, 0x30, + 0xC7, 0xF5, 0xEF, 0xC7, 0xDD, 0xBA, 0x97, 0xC3, 0x7D, 0xC7, 0xE1, 0xBE, 0xE3, 0x70, 0xDF, 0x66, + 0xC8, 0xD2, 0x66, 0xD4, 0xF1, 0x66, 0xC8, 0xFA, 0x66, 0xE4, 0x75, 0x33, 0xF2, 0xBC, 0x19, 0x72, + 0xB4, 0xF9, 0x1A, 0x38, 0xC8, 0xD5, 0x66, 0x94, 0xD7, 0x16, 0x94, 0xC5, 0x16, 0xD4, 0xD3, 0x16, + 0xD4, 0xD3, 0x16, 0xD4, 0xD3, 0x16, 0x94, 0xF5, 0xF1, 0xF8, 0x7E, 0x3C, 0x64, 0x73, 0x2B, 0xBA, + 0x9F, 0x5B, 0xD1, 0x1E, 0xB6, 0xA2, 0x1C, 0x4F, 0x98, 0x04, 0x77, 0x1F, 0xD1, 0x89, 0xC0, 0x7E, + 0xE2, 0x76, 0x71, 0x9E, 0xFD, 0xFF, 0x17, 0x97, 0x3F, 0x13, 0x3E, 0x37, 0x41, 0x36, 0xB8, 0x7D, + 0xAF, 0xFF, 0x2D, 0xD7, 0x15, 0x0B, 0xBB, 0x1C, 0xCA, 0x1F, 0xAC, 0xA2, 0x93, 0x41, 0x26, 0x59, + 0xD0, 0x15, 0x0E, 0x2C, 0x53, 0x0F, 0xF6, 0x59, 0x00, 0x4E, 0x8B, 0x83, 0xBB, 0x93, 0x94, 0x82, + 0x9D, 0x92, 0xA1, 0x32, 0x2A, 0xA7, 0x2C, 0x55, 0x50, 0x25, 0x55, 0x51, 0x35, 0xD5, 0x50, 0x2D, + 0xD5, 0x51, 0x3D, 0x2C, 0xAC, 0x46, 0x6A, 0x12, 0x33, 0x26, 0xB0, 0x04, 0x47, 0x50, 0x1B, 0x7A, + 0x89, 0xA3, 0x68, 0x34, 0x8D, 0x81, 0x95, 0xDF, 0x4E, 0x1D, 0xB0, 0x9E, 0xBA, 0xD0, 0xA8, 0xC6, + 0x53, 0x37, 0xF5, 0xC0, 0x02, 0x9A, 0x48, 0x93, 0x68, 0x32, 0x7A, 0x18, 0x53, 0x69, 0x1A, 0xF5, + 0x52, 0x1F, 0x4D, 0xA7, 0x19, 0xB0, 0xAC, 0x66, 0xD1, 0x6C, 0x9A, 0x43, 0x73, 0x69, 0x1E, 0xCD, + 0x47, 0xE3, 0x38, 0x80, 0x16, 0xD2, 0x81, 0xB4, 0x88, 0x0E, 0xA2, 0x7E, 0x5A, 0x4C, 0x07, 0xD3, + 0x12, 0x3A, 0x84, 0x96, 0xD2, 0x32, 0x5A, 0x4E, 0x2B, 0x68, 0x25, 0xAD, 0xA2, 0xD5, 0xE8, 0xB9, + 0x0C, 0xD0, 0x61, 0xB4, 0x86, 0x06, 0xE9, 0x70, 0x5A, 0x4B, 0xEB, 0xC0, 0x5B, 0x5F, 0xA0, 0x0D, + 0x74, 0x04, 0x1D, 0x49, 0x5F, 0xA4, 0x8D, 0x74, 0x14, 0x1D, 0x4D, 0x9B, 0xE8, 0x18, 0x3A, 0x96, + 0x8E, 0xA3, 0xCD, 0xB4, 0x85, 0x8E, 0xA7, 0xAD, 0x74, 0x02, 0x9D, 0x48, 0x5F, 0xA2, 0x6D, 0x74, + 0x12, 0x7D, 0x99, 0x4E, 0xA6, 0x53, 0xE8, 0x54, 0x3A, 0x8D, 0x4E, 0xA7, 0x33, 0xE8, 0x4C, 0x3A, + 0x8B, 0xCE, 0xA6, 0x73, 0xE8, 0x2B, 0xB4, 0x9D, 0xBE, 0x4A, 0xE7, 0xD2, 0xD7, 0xE8, 0x3C, 0xFA, + 0x3A, 0x9D, 0x0F, 0xAB, 0xEE, 0x42, 0xFA, 0x06, 0x5D, 0x44, 0xDF, 0xA4, 0x8B, 0xE9, 0x5B, 0xF4, + 0x6D, 0xFA, 0x0E, 0x5D, 0x42, 0xDF, 0xA5, 0x4B, 0x69, 0x07, 0x7D, 0x0F, 0xFD, 0xA5, 0xCB, 0xE8, + 0x72, 0xBA, 0x82, 0xFE, 0x83, 0xAE, 0xA4, 0xAB, 0xE8, 0x6A, 0xFA, 0x01, 0x5D, 0x43, 0xD7, 0xD2, + 0x75, 0x74, 0x3D, 0xED, 0xA4, 0x1F, 0xD2, 0x8F, 0xE8, 0x06, 0xBA, 0x91, 0x7E, 0x4C, 0x37, 0xC1, + 0x4E, 0xBE, 0x99, 0x6E, 0xA1, 0x9F, 0xD2, 0xCF, 0x60, 0xA1, 0xFE, 0x9C, 0x7E, 0x41, 0xBF, 0xA4, + 0x5F, 0x81, 0xAD, 0x6F, 0xA7, 0x3B, 0xE8, 0x4E, 0xBA, 0x8B, 0xEE, 0xA6, 0x7B, 0xE8, 0x5E, 0xFA, + 0x35, 0xDD, 0x47, 0xBF, 0xA1, 0xFB, 0xE9, 0xB7, 0xF4, 0x00, 0x3D, 0x08, 0xBB, 0xF0, 0x61, 0x7A, + 0x84, 0x7E, 0x47, 0x8F, 0xD2, 0x63, 0xF4, 0x38, 0x3D, 0x41, 0x4F, 0xD2, 0x53, 0xF4, 0x7B, 0xFA, + 0x03, 0x3D, 0x4D, 0x7F, 0xA4, 0x67, 0xE8, 0x59, 0xD8, 0xB4, 0xCF, 0xD1, 0xF3, 0xF4, 0x02, 0x2C, + 0xF9, 0x3F, 0xD1, 0x4B, 0xF4, 0x67, 0x7A, 0x99, 0xFE, 0x13, 0x9A, 0xE7, 0x15, 0x7A, 0x95, 0xFE, + 0x17, 0xFD, 0x15, 0x7A, 0xF6, 0x75, 0x7A, 0x03, 0x56, 0xEA, 0x5B, 0xF4, 0x36, 0xBD, 0x43, 0xEF, + 0xD2, 0xDF, 0x60, 0x99, 0xBE, 0x4F, 0x1F, 0xD0, 0xDF, 0xE9, 0x43, 0xF4, 0xE5, 0x3E, 0x96, 0x63, + 0xA6, 0xF2, 0x62, 0x8D, 0xF9, 0x13, 0xF9, 0x2B, 0xC5, 0x29, 0xFA, 0xF2, 0x3B, 0xB4, 0x09, 0x15, + 0x8F, 0xFB, 0x67, 0x8A, 0x5C, 0xA9, 0xBB, 0xE7, 0x85, 0x1F, 0x95, 0x98, 0xAA, 0xE9, 0x06, 0xBA, + 0xC3, 0xE2, 0x88, 0x8D, 0x20, 0x8C, 0x27, 0x92, 0xA9, 0x74, 0xA6, 0xAC, 0x3C, 0x5B, 0x51, 0x59, + 0x55, 0x5D, 0x53, 0x2B, 0x36, 0x17, 0x6E, 0x6A, 0x6E, 0x69, 0x1D, 0xD1, 0x36, 0x72, 0xD4, 0xE8, + 0x31, 0x63, 0xDB, 0x3B, 0x3A, 0xBB, 0xC6, 0x8D, 0xEF, 0xEE, 0x99, 0x30, 0x71, 0xD2, 0xE4, 0x29, + 0x53, 0xA7, 0xF5, 0xF6, 0x4D, 0x9F, 0x31, 0x73, 0xD6, 0xEC, 0x39, 0x73, 0xE7, 0xCD, 0x5F, 0x70, + 0xC0, 0xC2, 0x03, 0x17, 0x1D, 0xD4, 0xBF, 0xF8, 0xE0, 0x25, 0x87, 0x2C, 0x5D, 0xB6, 0x7C, 0xC5, + 0xCA, 0x55, 0xAB, 0x0F, 0x1D, 0x38, 0x6C, 0xCD, 0x20, 0xAA, 0x72, 0xDD, 0xFA, 0x2F, 0x6C, 0x38, + 0xE2, 0xC8, 0x2F, 0x6E, 0x3C, 0xEA, 0xE8, 0x4D, 0xC7, 0x1C, 0x7B, 0xDC, 0xE6, 0x2D, 0xC7, 0x6F, + 0x3D, 0xE1, 0xC4, 0x2F, 0x6D, 0x3B, 0xE9, 0xCB, 0x27, 0x9F, 0x72, 0xEA, 0x69, 0xA7, 0x9F, 0x71, + 0xE6, 0x59, 0x67, 0x9F, 0xF3, 0x95, 0xED, 0x5F, 0x3D, 0xF7, 0x6B, 0xE7, 0x7D, 0xFD, 0xFC, 0x0B, + 0x2E, 0xFC, 0xC6, 0x45, 0xDF, 0xBC, 0xF8, 0x5B, 0xDF, 0xFE, 0xCE, 0x25, 0xDF, 0xBD, 0x74, 0xC7, + 0xF7, 0xBE, 0x7F, 0xD9, 0xE5, 0x57, 0xFC, 0xC7, 0x95, 0x57, 0x5D, 0xFD, 0x83, 0x6B, 0xAE, 0xBD, + 0xEE, 0xFA, 0x9D, 0x3F, 0xFC, 0xD1, 0x0D, 0x37, 0xFE, 0xF8, 0xA6, 0x9F, 0xDC, 0x7C, 0xCB, 0x4F, + 0x7F, 0x76, 0xEB, 0xCF, 0x7F, 0xF1, 0xCB, 0x5F, 0xDD, 0x76, 0xFB, 0x1D, 0x77, 0xDE, 0x75, 0xF7, + 0x3D, 0xF7, 0xFE, 0xFA, 0xBE, 0xDF, 0xDC, 0xFF, 0xDB, 0x07, 0x1E, 0x7C, 0xE8, 0xE1, 0x47, 0x7E, + 0xF7, 0xE8, 0x63, 0x8F, 0x3F, 0xF1, 0xE4, 0x53, 0xBF, 0xFF, 0xC3, 0xD3, 0x7F, 0x7C, 0xE6, 0xD9, + 0x5D, 0xCF, 0x3D, 0xFF, 0xC2, 0x8B, 0x7F, 0x7A, 0xE9, 0xCF, 0x2F, 0xFF, 0x27, 0x50, 0xC6, 0x14, + 0x61, 0xA5, 0x2F, 0x82, 0x64, 0xAA, 0x68, 0x01, 0xA7, 0x51, 0x8E, 0x75, 0xB0, 0x19, 0x6C, 0x09, + 0x3B, 0x9C, 0x6D, 0x63, 0xA7, 0xB2, 0xD3, 0xD9, 0xC5, 0xFC, 0x76, 0xFE, 0x20, 0x7F, 0x98, 0xBF, + 0xA8, 0xFC, 0x40, 0xF9, 0xA1, 0x72, 0x6F, 0x6D, 0xB2, 0x36, 0x5B, 0x5B, 0x5D, 0x5B, 0x5F, 0xDB, + 0x5C, 0xDB, 0x5E, 0x3B, 0xA9, 0xAE, 0xBE, 0x9E, 0xD7, 0x6B, 0xF5, 0x7E, 0x7D, 0xBC, 0x3E, 0x55, + 0x9F, 0xAD, 0xAF, 0xAE, 0x1F, 0x59, 0x3F, 0xAF, 0x7E, 0xB0, 0xFE, 0x0B, 0x4D, 0x8F, 0xBC, 0xC7, + 0x45, 0x4F, 0x00, 0xED, 0xE5, 0x4A, 0xC4, 0x37, 0x9D, 0x1D, 0xCC, 0x06, 0x4B, 0xE2, 0x7B, 0x00, + 0xF1, 0xED, 0xCA, 0xC7, 0x97, 0xA8, 0x2D, 0xAB, 0xAD, 0xAC, 0xAD, 0x95, 0xF1, 0x4D, 0xDC, 0x23, + 0xBE, 0xF2, 0x62, 0x7C, 0xEB, 0x11, 0x9F, 0x1C, 0x2F, 0xFF, 0x6F, 0xBC, 0x18, 0x2D, 0x62, 0x16, + 0x7B, 0x08, 0x7F, 0x8F, 0xB0, 0x47, 0xD9, 0xE3, 0x25, 0x7F, 0x4F, 0xE2, 0x6F, 0x57, 0xFE, 0xEF, + 0x79, 0xF6, 0x12, 0xFB, 0x0B, 0xFB, 0xAB, 0xFC, 0x7B, 0x7D, 0x8F, 0xBF, 0x37, 0x8B, 0x7F, 0x6F, + 0xB3, 0xB7, 0xA5, 0xA4, 0xFD, 0x4F, 0xE6, 0x94, 0x1B, 0xD1, 0xA6, 0x05, 0x27, 0xDC, 0x85, 0x56, + 0xFF, 0x3A, 0x98, 0xE1, 0x42, 0x70, 0xC2, 0xE5, 0x68, 0xDB, 0xD7, 0x20, 0xF7, 0xE7, 0xA1, 0x05, + 0x9E, 0x0D, 0x4E, 0x10, 0xED, 0xEA, 0x02, 0x70, 0xC2, 0xB9, 0x68, 0xBF, 0x2F, 0xA1, 0x9D, 0x5D, + 0x81, 0x96, 0xFF, 0x11, 0x5A, 0xDA, 0xC7, 0x60, 0x84, 0x1F, 0xA3, 0x1D, 0x3F, 0x08, 0x06, 0x10, + 0xDC, 0x74, 0x11, 0xD8, 0xE9, 0x77, 0xE0, 0xA7, 0x87, 0xD0, 0xB2, 0x9F, 0xC8, 0xB7, 0xEC, 0x37, + 0xC0, 0x56, 0x7F, 0x90, 0xAD, 0xFB, 0x27, 0x60, 0xAD, 0xF7, 0xC0, 0x32, 0xCF, 0xC8, 0x36, 0x7E, + 0x24, 0xDA, 0xEE, 0x3B, 0xE0, 0xA0, 0x8D, 0xE0, 0xB1, 0xA3, 0xC0, 0x61, 0x47, 0x83, 0xC5, 0xAE, + 0x04, 0x8F, 0x6D, 0x06, 0x93, 0x09, 0x1E, 0x3B, 0x01, 0x4C, 0x26, 0x78, 0xEC, 0x4D, 0x30, 0xD9, + 0x97, 0xC1, 0x65, 0x27, 0x83, 0xC7, 0x4E, 0x01, 0xAB, 0x5C, 0x05, 0x2E, 0x3B, 0x4D, 0xB2, 0xD9, + 0xDB, 0x68, 0xF7, 0xB7, 0x83, 0x29, 0x04, 0x2B, 0x08, 0xF6, 0x11, 0xCC, 0x70, 0x87, 0xE4, 0x86, + 0xEB, 0xC0, 0x17, 0xBB, 0xC0, 0x17, 0x05, 0xFE, 0x78, 0x19, 0x5C, 0xB2, 0x03, 0x1C, 0xF6, 0x7D, + 0xC9, 0x50, 0x82, 0x9D, 0xEE, 0x97, 0x3C, 0xF5, 0x5B, 0x30, 0xE2, 0x7D, 0xE0, 0xC2, 0x1B, 0xC0, + 0x48, 0x82, 0xA3, 0xCE, 0x07, 0xEB, 0xED, 0x04, 0xEB, 0xFD, 0x0D, 0xAC, 0xF5, 0x1B, 0xF0, 0xDC, + 0xC5, 0x60, 0xBF, 0xEB, 0xC1, 0x8D, 0x82, 0x13, 0x6F, 0x03, 0x3B, 0x81, 0xC3, 0xCE, 0xFE, 0x54, + 0xA9, 0x95, 0xBD, 0x64, 0x62, 0xD9, 0xBC, 0x9B, 0x85, 0x7E, 0xEE, 0x77, 0x68, 0x0A, 0x9F, 0x47, + 0x0D, 0x7C, 0x1B, 0xD5, 0x2A, 0x4F, 0x53, 0x83, 0x62, 0xD0, 0x08, 0x30, 0xCB, 0x3C, 0x36, 0x92, + 0x26, 0xC2, 0x11, 0x3B, 0x09, 0xBF, 0xAD, 0xA0, 0xB1, 0xF0, 0x6B, 0x60, 0x37, 0xA3, 0xFE, 0x3F, + 0xA3, 0x91, 0x7C, 0x29, 0xE9, 0x3C, 0xA4, 0x14, 0x6B, 0x23, 0x83, 0xFD, 0x06, 0x5D, 0xDF, 0x23, + 0xD0, 0x47, 0x70, 0x29, 0xCE, 0xAE, 0x47, 0x27, 0xE8, 0x49, 0xCA, 0xB0, 0xAB, 0xE0, 0xFF, 0x30, + 0x25, 0xD8, 0x9F, 0x29, 0xCB, 0x12, 0x34, 0x19, 0x69, 0x75, 0x8B, 0x38, 0x0A, 0x8E, 0x7D, 0x44, + 0x29, 0xE4, 0xA5, 0x8A, 0xBF, 0x96, 0x7B, 0x83, 0x9F, 0x92, 0x7B, 0x86, 0x2F, 0xA3, 0x0A, 0xFE, + 0x10, 0xDE, 0x07, 0x73, 0x6F, 0xF1, 0x4E, 0xB8, 0x9D, 0xF8, 0xED, 0x43, 0x9A, 0xC3, 0xC6, 0x91, + 0xC7, 0x26, 0x21, 0xAD, 0x6B, 0xC8, 0xE3, 0xAD, 0xE4, 0xC5, 0x42, 0x6A, 0x53, 0x3A, 0x10, 0xEE, + 0x39, 0xAA, 0xE5, 0x13, 0x73, 0x7F, 0x42, 0x4F, 0xAF, 0x82, 0x5F, 0x8D, 0xF7, 0x8D, 0x54, 0xC3, + 0xAF, 0xCA, 0xBD, 0xA5, 0x34, 0x81, 0x10, 0xDF, 0xCF, 0xBD, 0x1A, 0x7B, 0x26, 0xF7, 0x2A, 0x7F, + 0x14, 0xF7, 0x7D, 0x80, 0xDF, 0x96, 0x53, 0x35, 0x9B, 0x4C, 0x03, 0xEC, 0x89, 0xDC, 0x5B, 0x6C, + 0x72, 0xEE, 0x1F, 0x48, 0xBF, 0x97, 0x37, 0xE4, 0xFE, 0xC1, 0xD2, 0xB9, 0x1C, 0x9F, 0x4D, 0x29, + 0x3E, 0x2E, 0xF7, 0x3A, 0xFB, 0x15, 0xDE, 0x27, 0x03, 0xEB, 0x7D, 0x54, 0xC9, 0x56, 0xE3, 0x9E, + 0xAD, 0x94, 0xE0, 0xEB, 0x72, 0xAF, 0xB0, 0x8A, 0xDC, 0x07, 0xC2, 0xF1, 0xF6, 0xDC, 0xEB, 0xF4, + 0x69, 0xEE, 0x55, 0xE5, 0x49, 0xE4, 0x4D, 0x8C, 0xB4, 0x7D, 0x8A, 0x74, 0x9B, 0x90, 0x46, 0x25, + 0xC2, 0x7F, 0x1D, 0xF1, 0xDE, 0x46, 0xF5, 0xAC, 0x0B, 0xBF, 0x6D, 0x40, 0xD8, 0x51, 0x08, 0xF7, + 0x2D, 0xFC, 0x36, 0x16, 0x79, 0x5E, 0x8A, 0xDF, 0xEE, 0x47, 0x98, 0xC9, 0x68, 0x63, 0x2F, 0x51, + 0xAF, 0x78, 0x47, 0xFA, 0xB3, 0x25, 0x6E, 0xE1, 0x04, 0x6E, 0x60, 0x2E, 0x60, 0x92, 0xF9, 0x17, + 0x79, 0x1A, 0xC6, 0x89, 0x3C, 0xCA, 0xFC, 0x95, 0xBA, 0x7C, 0xFE, 0xF2, 0xEE, 0xB5, 0x42, 0xDE, + 0xF6, 0x76, 0x32, 0x5F, 0x25, 0xAE, 0x48, 0x27, 0xF7, 0xE1, 0xB7, 0x33, 0x90, 0xA6, 0x9E, 0x7B, + 0x9C, 0x7D, 0x28, 0xD7, 0x79, 0x11, 0xBF, 0x39, 0xF7, 0x27, 0x51, 0x37, 0xD2, 0xBD, 0x44, 0xD3, + 0x58, 0x1A, 0x2D, 0xF9, 0xB3, 0xDC, 0xDB, 0x22, 0xAF, 0xB1, 0xC6, 0xDC, 0x2B, 0xC8, 0xA7, 0x27, + 0xF2, 0x22, 0xC3, 0x8A, 0x7A, 0x12, 0x65, 0xB5, 0x1A, 0x78, 0x45, 0xDC, 0x88, 0x43, 0x96, 0x1B, + 0xEA, 0x4C, 0x96, 0x1B, 0xEA, 0x85, 0x0D, 0x90, 0xCB, 0x3A, 0x28, 0x60, 0xDF, 0xA7, 0x7A, 0xA5, + 0x0C, 0x18, 0x3E, 0xCD, 0x7D, 0x82, 0xFA, 0xF7, 0x99, 0x68, 0xF9, 0x22, 0x8E, 0x4F, 0xC4, 0x0C, + 0x26, 0xA8, 0x48, 0x60, 0x2F, 0xC9, 0x9B, 0xE2, 0xD0, 0x48, 0x21, 0xA3, 0xC5, 0xB2, 0x42, 0xF9, + 0xC4, 0x5A, 0x51, 0x46, 0x69, 0x60, 0x12, 0x9D, 0x66, 0x58, 0x69, 0xEC, 0x19, 0xC8, 0xA4, 0x70, + 0x4A, 0xE4, 0xE4, 0x7D, 0x15, 0x90, 0x57, 0x94, 0xBB, 0xA8, 0x7B, 0xBA, 0x3E, 0xB7, 0x84, 0x6B, + 0x05, 0x7D, 0xBA, 0xD7, 0xF5, 0x99, 0x5C, 0x2D, 0x54, 0xBC, 0x64, 0x1A, 0x42, 0xFE, 0x0A, 0xEF, + 0x70, 0x52, 0xFE, 0xC6, 0xA1, 0xE7, 0x36, 0x2E, 0xF7, 0xBE, 0xF8, 0x2C, 0xE5, 0x4E, 0xD4, 0x93, + 0x48, 0x23, 0x5F, 0x5F, 0x05, 0x27, 0xEB, 0x20, 0x2D, 0xDD, 0xD3, 0x70, 0x4F, 0xC1, 0xBD, 0x8C, + 0x34, 0x56, 0xA0, 0xFC, 0x6C, 0x7C, 0xFE, 0x04, 0xEE, 0x31, 0x7C, 0xAE, 0x15, 0x61, 0xFE, 0x1B, + 0x35, 0x42, 0xC9, 0x05, 0x5D, 0x73, 0x15, 0xB0, 0x06, 0x60, 0xB6, 0x5B, 0xF9, 0xE3, 0xB9, 0xF7, + 0xD8, 0xA3, 0xA8, 0xD1, 0xEB, 0x69, 0x16, 0xBF, 0x0B, 0x8C, 0xF7, 0x29, 0xB8, 0xB5, 0x1F, 0x5C, + 0xBA, 0x1C, 0x1C, 0x3A, 0x08, 0xD6, 0x3A, 0x0E, 0x61, 0x4F, 0x03, 0xAB, 0xFD, 0x52, 0x19, 0x93, + 0x3B, 0x4B, 0xB2, 0x72, 0x2F, 0xDA, 0xE6, 0x3D, 0xD2, 0x36, 0xDB, 0x0C, 0x06, 0xDB, 0x06, 0xE6, + 0x58, 0x47, 0x1B, 0xF9, 0x15, 0xB9, 0xBF, 0xD1, 0x97, 0x94, 0x30, 0xF7, 0x35, 0xB0, 0xF6, 0x3C, + 0x70, 0xAB, 0x98, 0xAD, 0x3C, 0x86, 0x3F, 0xC2, 0xBE, 0x4B, 0x8F, 0xB1, 0x7F, 0x82, 0xBF, 0xAF, + 0xCE, 0xDD, 0x25, 0x38, 0x0F, 0x2C, 0xF1, 0x0F, 0xF2, 0x50, 0xE3, 0x73, 0x73, 0xEF, 0xA2, 0x6B, + 0x3D, 0x27, 0xF7, 0x3E, 0x38, 0x30, 0xB2, 0xD6, 0xCE, 0xE4, 0x0B, 0xA9, 0x3B, 0xF7, 0x08, 0x38, + 0x72, 0x0B, 0xB4, 0xC9, 0x8D, 0x7C, 0x55, 0xEE, 0x6D, 0xEA, 0xC9, 0x3D, 0x0C, 0x26, 0x5A, 0xC4, + 0x0F, 0x04, 0x47, 0x0B, 0x8B, 0x2C, 0x4E, 0xDF, 0x60, 0x6F, 0x91, 0xC1, 0x39, 0xBB, 0x14, 0x6C, + 0xFC, 0x20, 0x7F, 0x0A, 0x5A, 0xE0, 0x20, 0xF0, 0x58, 0x3D, 0xF8, 0x7F, 0x15, 0x18, 0x6C, 0x01, + 0x58, 0xFF, 0x2C, 0xFE, 0x7C, 0xEE, 0xC3, 0x02, 0xFF, 0xF3, 0x27, 0xC0, 0x7A, 0x3A, 0xBF, 0x0F, + 0xCC, 0xE8, 0xD0, 0xD1, 0xFC, 0x21, 0xC9, 0xB2, 0x36, 0xFF, 0x75, 0xEE, 0x23, 0x69, 0x53, 0x9E, + 0x08, 0xDE, 0x3D, 0x05, 0x08, 0x2E, 0x05, 0x33, 0xC2, 0x76, 0xE3, 0xF7, 0x83, 0x81, 0xCF, 0xC8, + 0x5B, 0x87, 0xDF, 0x07, 0x33, 0x7C, 0x17, 0xDC, 0x3D, 0x11, 0x1A, 0x6E, 0x1D, 0x1D, 0xCB, 0x77, + 0xF1, 0x67, 0x73, 0x75, 0xD0, 0x7E, 0x29, 0xFA, 0x02, 0xFF, 0x23, 0xF4, 0xC9, 0x04, 0xE8, 0xF9, + 0x57, 0xF8, 0xCB, 0xB4, 0x4C, 0xEE, 0x65, 0x3E, 0x1D, 0x9C, 0xBB, 0x9E, 0xFF, 0x2E, 0xD7, 0x03, + 0x4D, 0xB1, 0x16, 0xDA, 0x45, 0x68, 0xA5, 0xFB, 0x20, 0xF1, 0xBF, 0xCF, 0xBD, 0x03, 0x09, 0xB8, + 0x05, 0xDA, 0xB2, 0x99, 0xBF, 0x90, 0x7B, 0x9E, 0xBF, 0x05, 0xEE, 0xBD, 0x0C, 0x5A, 0x60, 0x27, + 0x7F, 0x1B, 0xE5, 0xD7, 0x0E, 0xCD, 0x37, 0x37, 0x77, 0x0E, 0x4D, 0xE7, 0x17, 0x33, 0x8B, 0x1A, + 0x72, 0x03, 0xB9, 0x49, 0xFC, 0xE7, 0xBC, 0x8A, 0xBD, 0x0B, 0x99, 0xEB, 0x50, 0x32, 0x74, 0x3B, + 0x7B, 0x93, 0x7F, 0x0B, 0x5A, 0xF5, 0x70, 0xF6, 0x4E, 0xEE, 0x0D, 0xE4, 0xF2, 0x4E, 0xF6, 0x5E, + 0xAE, 0x89, 0x5F, 0x9F, 0x4B, 0x2B, 0x29, 0x68, 0xDA, 0x6C, 0xAE, 0x15, 0x79, 0xCB, 0x88, 0x59, + 0x62, 0x68, 0xE9, 0x2B, 0xA0, 0xDF, 0x96, 0x42, 0xFB, 0x5D, 0xC8, 0x37, 0xA1, 0xDD, 0x9C, 0xCF, + 0x5E, 0x61, 0x7F, 0x43, 0x5B, 0xD5, 0xE8, 0xA7, 0xB9, 0x2A, 0xE8, 0x93, 0x6B, 0xE8, 0x06, 0xAE, + 0xE4, 0xCE, 0x63, 0x87, 0xD0, 0x75, 0xCA, 0x16, 0xE5, 0x6C, 0x68, 0xE5, 0xB3, 0xA0, 0x83, 0x27, + 0xE7, 0xE6, 0x2B, 0xA7, 0x2A, 0x27, 0xF1, 0x6B, 0xF9, 0x8F, 0xF8, 0x2D, 0xFC, 0x25, 0xD4, 0xF7, + 0x57, 0x90, 0xF3, 0x9F, 0x43, 0x9F, 0xED, 0xA0, 0x23, 0x79, 0x7F, 0x6E, 0x3B, 0x4A, 0xE3, 0x00, + 0xE8, 0x94, 0xAF, 0xF1, 0x7F, 0xD2, 0xCF, 0x78, 0x05, 0x34, 0xCB, 0x24, 0xC8, 0x40, 0x9F, 0xB4, + 0x70, 0xBF, 0x0E, 0xED, 0xB1, 0x13, 0xBA, 0x71, 0x19, 0xB4, 0xEC, 0x26, 0xC8, 0x89, 0xD0, 0xCD, + 0x67, 0xC3, 0x06, 0xFA, 0x2A, 0x64, 0xA2, 0x87, 0xCE, 0x63, 0x9D, 0xBC, 0x8C, 0xB7, 0x29, 0x9B, + 0x80, 0x77, 0x04, 0x2D, 0xCC, 0xBD, 0x9E, 0xBB, 0x27, 0x57, 0x8E, 0xFC, 0xF5, 0x83, 0x81, 0x1F, + 0x63, 0x67, 0xF2, 0xBB, 0xD9, 0x09, 0xB0, 0x26, 0x02, 0xD8, 0x0C, 0xF7, 0xF3, 0xAA, 0xDC, 0x14, + 0x9E, 0xC8, 0x8D, 0xA7, 0x72, 0x7E, 0xA7, 0xB2, 0x8C, 0xDF, 0xCE, 0x62, 0xB4, 0x81, 0x1D, 0x06, + 0x59, 0xAC, 0x66, 0x6F, 0xB0, 0xD7, 0xA8, 0x92, 0xDF, 0x04, 0xD6, 0x58, 0x00, 0x4D, 0xF3, 0x10, + 0x4B, 0xB3, 0xBF, 0xF3, 0xD1, 0xBC, 0x8B, 0xEF, 0xE0, 0xF3, 0x78, 0x1D, 0x6D, 0xE7, 0x49, 0xE8, + 0xEC, 0x19, 0x3C, 0x01, 0xDB, 0x42, 0x5C, 0xF7, 0xC0, 0x46, 0x51, 0x87, 0x11, 0x78, 0xF6, 0xAF, + 0xDB, 0xC3, 0xF4, 0xA3, 0xB7, 0x1E, 0x0F, 0x4C, 0xB5, 0xEF, 0x71, 0xE5, 0xEC, 0x1C, 0xFA, 0xFC, + 0x28, 0x9D, 0x37, 0xE5, 0x0F, 0xE8, 0xEB, 0xD2, 0xA7, 0xA6, 0xAD, 0x93, 0xA2, 0x08, 0x5B, 0xD9, + 0xD4, 0x39, 0x3E, 0xA8, 0x3C, 0xC6, 0x55, 0x55, 0x89, 0x29, 0x6A, 0x4C, 0x5C, 0x5C, 0x51, 0x71, + 0xE9, 0xBA, 0xA6, 0x8A, 0x73, 0x2C, 0x75, 0x45, 0xD1, 0x54, 0x53, 0xD7, 0x55, 0x0D, 0x97, 0xAE, + 0xDB, 0x9A, 0x2E, 0x43, 0xAA, 0x78, 0xC5, 0xD4, 0x18, 0x7E, 0x13, 0xF7, 0x9B, 0xE2, 0x8E, 0x98, + 0xF8, 0x66, 0xA8, 0xE2, 0x5C, 0x4D, 0x05, 0xB7, 0x8B, 0x28, 0x74, 0x55, 0x8D, 0x7E, 0xC1, 0xA5, + 0x88, 0x94, 0xE4, 0x25, 0x62, 0x82, 0x21, 0x8B, 0xD8, 0x09, 0x31, 0x9A, 0x0A, 0x57, 0x2D, 0x3D, + 0x46, 0x1A, 0xD2, 0x43, 0xDC, 0x8A, 0x86, 0x9C, 0xE1, 0x3E, 0x31, 0x0E, 0xA6, 0x23, 0x98, 0xAE, + 0x20, 0x1A, 0x4B, 0x17, 0x79, 0xE3, 0x9C, 0x74, 0x55, 0xE7, 0x51, 0x79, 0x08, 0xEB, 0x1F, 0xDF, + 0x10, 0x10, 0x97, 0x1E, 0x5D, 0xE2, 0xA3, 0xC2, 0xE5, 0xFF, 0xFD, 0x95, 0x8C, 0xE5, 0x18, 0x12, + 0xBB, 0xA6, 0x59, 0x86, 0x7C, 0x57, 0x24, 0x06, 0x81, 0x05, 0x7F, 0x22, 0x79, 0x71, 0xAA, 0x87, + 0x0E, 0xA8, 0x78, 0x19, 0xE2, 0xE0, 0x4B, 0x0B, 0xDF, 0x50, 0x18, 0xBA, 0x61, 0x38, 0xBA, 0xA1, + 0x29, 0xAA, 0x08, 0xAE, 0x69, 0x31, 0xF9, 0x5F, 0xE4, 0xD6, 0xD2, 0xF2, 0xD8, 0x35, 0x13, 0xB7, + 0x22, 0x79, 0x11, 0x5A, 0x33, 0x10, 0x56, 0x5E, 0x31, 0x81, 0x58, 0xE4, 0x48, 0x2B, 0xC1, 0x2E, + 0x4A, 0x96, 0x10, 0xA3, 0x05, 0x6F, 0x1B, 0xD8, 0x71, 0x83, 0x66, 0x68, 0x11, 0x76, 0x43, 0x60, + 0x37, 0xC8, 0x40, 0x30, 0x43, 0x00, 0xB3, 0x0D, 0x71, 0x2B, 0x10, 0x19, 0x9A, 0x91, 0xC7, 0x2E, + 0xD0, 0xE9, 0x22, 0x87, 0x11, 0x76, 0xA4, 0x65, 0x18, 0xCA, 0xD0, 0xB5, 0x3F, 0xEC, 0xB6, 0x67, + 0x02, 0x7B, 0x2C, 0xA6, 0xE9, 0xB6, 0x29, 0xB0, 0xA3, 0x50, 0x81, 0x0F, 0xD8, 0xA3, 0xAC, 0xC9, + 0x62, 0xD4, 0x4C, 0x43, 0x44, 0x98, 0xC7, 0x6E, 0x9B, 0x48, 0x14, 0xBE, 0xA6, 0xE1, 0x19, 0x46, + 0x3E, 0xB8, 0xA8, 0x27, 0x35, 0x26, 0x0A, 0x5B, 0x53, 0x6C, 0x5D, 0x22, 0x14, 0xA5, 0x24, 0xEA, + 0x8E, 0x2B, 0xBA, 0x78, 0x94, 0xC8, 0x34, 0xCC, 0x08, 0xBB, 0x5A, 0xC0, 0xAE, 0x6B, 0x91, 0xF4, + 0xE8, 0x3A, 0xB0, 0xE3, 0x0B, 0x19, 0xA6, 0x69, 0xC3, 0xDB, 0x31, 0x50, 0x0C, 0xBA, 0x48, 0x10, + 0x5F, 0x20, 0x55, 0xB8, 0x2F, 0x26, 0xEC, 0x71, 0x04, 0x33, 0x15, 0x80, 0x72, 0x4C, 0x45, 0xD6, + 0x30, 0x7C, 0x0C, 0xF1, 0x88, 0x57, 0x1E, 0x3B, 0x00, 0x47, 0x95, 0x6D, 0x18, 0x48, 0xCB, 0x34, + 0x3F, 0x07, 0x76, 0xC7, 0xB7, 0x04, 0x76, 0x55, 0x17, 0x71, 0xC6, 0xF0, 0x2E, 0xC1, 0xC4, 0x04, + 0x76, 0x21, 0xE5, 0x11, 0x76, 0x0B, 0xE0, 0x21, 0xEA, 0x86, 0x19, 0x8B, 0x19, 0xBA, 0x63, 0x99, + 0x02, 0x8D, 0x61, 0x99, 0xBE, 0x69, 0xEA, 0x31, 0x4D, 0x40, 0xD6, 0x85, 0xC4, 0xC5, 0x64, 0x6E, + 0x15, 0x47, 0xD4, 0x80, 0x2A, 0x4A, 0xC2, 0x86, 0x77, 0x0C, 0xC5, 0x89, 0x60, 0xBA, 0x65, 0x5A, + 0x91, 0x2C, 0x0E, 0x8F, 0xDD, 0x10, 0xD8, 0x2D, 0xCB, 0x81, 0xB7, 0x6B, 0xAA, 0x24, 0x4B, 0x0B, + 0xC0, 0x75, 0xE4, 0xC8, 0x12, 0xD8, 0xD1, 0x13, 0x91, 0xD8, 0x01, 0xCA, 0x35, 0x63, 0xB2, 0x86, + 0xE1, 0x63, 0x96, 0x60, 0x37, 0x45, 0x0E, 0x45, 0x7B, 0x32, 0x4D, 0xA4, 0x65, 0x59, 0x9F, 0x03, + 0xBB, 0x1B, 0x58, 0x84, 0x1B, 0x54, 0xC3, 0x70, 0x2D, 0x81, 0x1D, 0x02, 0xA5, 0x18, 0x40, 0x04, + 0x2C, 0x40, 0xAF, 0x01, 0x2C, 0xF2, 0x61, 0x59, 0xA2, 0x30, 0x75, 0xD3, 0x42, 0xCC, 0xBA, 0x67, + 0x23, 0x19, 0x14, 0xAD, 0x65, 0x05, 0xA6, 0x65, 0x00, 0x3B, 0x82, 0x1B, 0x12, 0xAF, 0x61, 0xC4, + 0x20, 0x37, 0xAE, 0x10, 0x0A, 0x55, 0x78, 0x8B, 0x36, 0x01, 0xEC, 0x86, 0xB8, 0xDD, 0x46, 0x58, + 0x79, 0x45, 0x82, 0x1F, 0x13, 0xA5, 0x28, 0x6B, 0x17, 0x17, 0x91, 0x10, 0x24, 0x42, 0x8C, 0x6E, + 0x4C, 0x31, 0x3C, 0x53, 0x23, 0x13, 0xBE, 0x88, 0x1B, 0xF2, 0x0E, 0xEC, 0x80, 0x84, 0x3E, 0x98, + 0x58, 0x6F, 0x66, 0xC5, 0x2C, 0xCB, 0xF4, 0xAC, 0x98, 0x11, 0x61, 0x37, 0x2C, 0xAE, 0x17, 0xB1, + 0xE3, 0x9B, 0x48, 0xBF, 0x88, 0x3D, 0xE2, 0x15, 0xF9, 0x7F, 0x7F, 0xD8, 0xBD, 0xD0, 0x06, 0x76, + 0x55, 0x33, 0x4C, 0xCF, 0x96, 0x65, 0x10, 0x81, 0xD1, 0x54, 0x59, 0x2D, 0x7A, 0x84, 0xDD, 0x46, + 0xC5, 0x8B, 0x17, 0x42, 0x98, 0x86, 0x6F, 0x23, 0x19, 0x94, 0xBF, 0x6D, 0x87, 0x96, 0x2D, 0x83, + 0x1B, 0x78, 0xA1, 0x79, 0xAA, 0xA6, 0x90, 0x8B, 0x98, 0x27, 0x9A, 0x1B, 0xE0, 0x99, 0x86, 0x6B, + 0x14, 0xB1, 0x9B, 0x36, 0xC2, 0x0E, 0x87, 0x1D, 0x11, 0x99, 0xC0, 0x8E, 0x3A, 0x23, 0xCB, 0xB6, + 0x3D, 0x78, 0xFB, 0x96, 0x46, 0x48, 0xCC, 0xB4, 0x11, 0x9B, 0x09, 0xF9, 0x13, 0xD2, 0x83, 0xDE, + 0xA7, 0x8D, 0x60, 0x36, 0xB0, 0x5B, 0xBE, 0x2D, 0x6E, 0x05, 0x22, 0xDB, 0xB0, 0xF3, 0xD8, 0x05, + 0x3A, 0x00, 0x16, 0xE9, 0xC7, 0x10, 0x04, 0x69, 0xD9, 0x76, 0x6C, 0xE8, 0xDA, 0x1F, 0x76, 0x3F, + 0xE1, 0x48, 0xEC, 0xA6, 0xE9, 0x3B, 0x08, 0xA6, 0x99, 0x31, 0x91, 0x6B, 0x90, 0xAB, 0xA1, 0x09, + 0x4A, 0x13, 0xC5, 0x68, 0x1A, 0x0E, 0xC0, 0xDB, 0x02, 0xBB, 0xAA, 0x5A, 0x46, 0xE0, 0xA0, 0x0E, + 0x91, 0x92, 0x63, 0x27, 0x6C, 0xDB, 0x84, 0x7C, 0x20, 0xB8, 0x6C, 0x13, 0x79, 0xEC, 0xBE, 0xA8, + 0x34, 0x4D, 0x78, 0x7B, 0x06, 0x3C, 0xD1, 0x60, 0x11, 0xCC, 0x74, 0x6C, 0xC7, 0x94, 0x97, 0x44, + 0x2C, 0xEB, 0x47, 0x16, 0x45, 0x84, 0x5D, 0x47, 0x9D, 0x81, 0x76, 0x1D, 0x1F, 0xDE, 0x01, 0x34, + 0x8F, 0x2C, 0x5B, 0x00, 0x87, 0xCE, 0xD0, 0x1C, 0xC3, 0x10, 0xD8, 0x1D, 0x04, 0x73, 0x62, 0x00, + 0x15, 0x38, 0xAA, 0x94, 0x6E, 0xF8, 0xD8, 0xE8, 0x8D, 0x15, 0xB0, 0xDB, 0xB8, 0x41, 0xAA, 0x18, + 0xDB, 0x46, 0x5A, 0x8E, 0xF3, 0x39, 0xB0, 0x07, 0x49, 0x97, 0x04, 0xDD, 0x9A, 0x56, 0xE0, 0x80, + 0x82, 0x35, 0x2B, 0xA6, 0xC7, 0x2C, 0x03, 0xB5, 0x2E, 0xAB, 0xC5, 0x80, 0xC8, 0xA1, 0xD6, 0x5C, + 0x47, 0x14, 0xA6, 0x69, 0x3B, 0x88, 0xD9, 0x0C, 0x5D, 0x24, 0x8A, 0xA2, 0x75, 0x9D, 0xA4, 0xED, + 0x58, 0xC0, 0x6E, 0x99, 0x28, 0x20, 0x60, 0xD7, 0x2C, 0x4B, 0x55, 0xCD, 0x58, 0x80, 0x5A, 0x36, + 0x35, 0xE1, 0xED, 0xA3, 0x8D, 0x0B, 0xA1, 0x75, 0x70, 0xBB, 0xEB, 0xB8, 0x25, 0xD8, 0x45, 0x1E, + 0xA3, 0x36, 0x80, 0xE8, 0xAD, 0x3C, 0x76, 0xDB, 0x75, 0x03, 0x54, 0x5B, 0xE8, 0xE8, 0x64, 0xC3, + 0x17, 0x71, 0xA3, 0xAD, 0xAB, 0xBA, 0x2B, 0xB0, 0x3B, 0xE4, 0x22, 0x98, 0xA3, 0x02, 0x54, 0xE8, + 0xAA, 0x52, 0xBA, 0xE1, 0xE3, 0x94, 0x60, 0x77, 0x70, 0x83, 0x25, 0xE2, 0x75, 0x1C, 0xA4, 0xE5, + 0xBA, 0xEA, 0xBF, 0xC7, 0x1E, 0xA6, 0x3C, 0x12, 0x9A, 0xDB, 0xB2, 0x43, 0xB7, 0x88, 0xDD, 0x44, + 0xAD, 0x9B, 0x52, 0x55, 0xA8, 0x02, 0xBB, 0xE9, 0xB9, 0xB6, 0x88, 0xD9, 0x71, 0x05, 0xF6, 0xB8, + 0x87, 0x64, 0x50, 0xFE, 0x9E, 0x9B, 0x72, 0x5C, 0x0B, 0x4A, 0x1C, 0xC1, 0x2D, 0x0B, 0xB9, 0xD7, + 0x6C, 0x91, 0xDB, 0x58, 0x68, 0x49, 0x84, 0xF0, 0x0E, 0x50, 0x6C, 0x02, 0xBB, 0xEB, 0x5A, 0x96, + 0xE7, 0x78, 0x96, 0xBC, 0x64, 0x0B, 0x97, 0xD8, 0x65, 0x51, 0x44, 0xD8, 0x41, 0x07, 0x26, 0x39, + 0x9E, 0x17, 0xAA, 0x31, 0x2B, 0x0E, 0xEC, 0x10, 0x34, 0x0B, 0x71, 0xAB, 0xB6, 0xC0, 0x8E, 0x92, + 0x14, 0xA3, 0x2D, 0x08, 0xE6, 0xAA, 0xAE, 0xEB, 0xC4, 0x0B, 0xD8, 0x3D, 0xCB, 0x55, 0xCC, 0x22, + 0x76, 0x17, 0x37, 0xE4, 0xB1, 0x23, 0x2D, 0xCF, 0x8B, 0x8C, 0x09, 0xF9, 0x7F, 0x7F, 0xD8, 0xE3, + 0xE9, 0x08, 0xBB, 0x6D, 0xC7, 0x45, 0x70, 0xDD, 0x06, 0x18, 0x60, 0x00, 0x76, 0x29, 0x91, 0x42, + 0x84, 0x6C, 0x81, 0xDD, 0x16, 0xF0, 0x3D, 0x4D, 0x73, 0xAC, 0x84, 0x8F, 0x64, 0x20, 0x56, 0x9E, + 0x97, 0x76, 0x3D, 0x5B, 0x93, 0x90, 0x2D, 0xC1, 0x34, 0x9A, 0x2D, 0xDA, 0x84, 0x1A, 0x17, 0x4D, + 0x42, 0x17, 0xDE, 0x01, 0xDA, 0x38, 0x14, 0x3F, 0xEA, 0xD3, 0xB6, 0x7D, 0x37, 0x8F, 0xDD, 0x28, + 0x60, 0xB7, 0x25, 0x76, 0x44, 0x6F, 0x03, 0xBB, 0x13, 0x61, 0x8F, 0xC3, 0x3B, 0xE1, 0x1A, 0x24, + 0xCB, 0x16, 0xC0, 0x05, 0x76, 0x4F, 0x60, 0xF7, 0xC8, 0x43, 0x30, 0x0F, 0xD8, 0xDD, 0x84, 0xA7, + 0xDA, 0x22, 0x06, 0xF8, 0x78, 0x79, 0xEC, 0x02, 0x9D, 0x8B, 0x1C, 0xDA, 0x82, 0x4B, 0x5C, 0xD7, + 0x73, 0x0B, 0xD8, 0xD5, 0x7F, 0x89, 0x3D, 0x51, 0xE6, 0x0B, 0xEC, 0x86, 0xED, 0x24, 0x7C, 0xF0, + 0x7A, 0x1E, 0x3B, 0x6A, 0xDD, 0x92, 0x6A, 0x52, 0x62, 0xB7, 0x7C, 0xCF, 0xB1, 0xF1, 0x72, 0x81, + 0xDD, 0xB5, 0x92, 0x81, 0x07, 0x34, 0x8E, 0xEB, 0x7B, 0x65, 0x1E, 0xF2, 0x67, 0x0A, 0xEC, 0x36, + 0x78, 0xC7, 0xD4, 0x1D, 0xD1, 0x26, 0xD4, 0x84, 0x2D, 0x11, 0x6A, 0x8E, 0x1D, 0xA2, 0xD8, 0x04, + 0x76, 0x04, 0x73, 0x02, 0xCF, 0xB7, 0xE5, 0x25, 0x5B, 0xB8, 0xC4, 0x2E, 0x8B, 0x02, 0x42, 0xEC, + 0x40, 0x41, 0x41, 0xAA, 0xC8, 0xF5, 0xFD, 0x04, 0xBC, 0x93, 0x9E, 0x41, 0xB2, 0x6C, 0x1D, 0x4D, + 0x85, 0xBE, 0x04, 0xF7, 0x59, 0x02, 0xBB, 0x8F, 0x60, 0xBE, 0x0A, 0x50, 0x49, 0x5F, 0x93, 0x2D, + 0x9B, 0x7C, 0x60, 0xB7, 0x8A, 0xD8, 0x51, 0xD9, 0x8E, 0x23, 0xB0, 0x7B, 0x9E, 0xEF, 0xF9, 0xBE, + 0xFF, 0x39, 0xB0, 0x27, 0xCB, 0x03, 0x12, 0x46, 0x94, 0xE3, 0x26, 0x03, 0x55, 0xBC, 0xAB, 0xA6, + 0xEA, 0x00, 0x11, 0xCC, 0x27, 0xA1, 0xC7, 0x50, 0xD1, 0x68, 0xAD, 0x81, 0xEF, 0x3A, 0x02, 0xBE, + 0x8F, 0x98, 0xED, 0x54, 0x80, 0x44, 0x81, 0x3D, 0xF0, 0xCB, 0x3D, 0xDF, 0x01, 0x76, 0x04, 0x77, + 0x04, 0xD3, 0xE8, 0x2E, 0xD2, 0xB6, 0xD5, 0xA4, 0x63, 0x09, 0x84, 0xF0, 0x8B, 0x83, 0xDF, 0x80, + 0xDD, 0xF1, 0x7D, 0xC7, 0x09, 0xFC, 0xC0, 0x91, 0x97, 0xAC, 0x6D, 0x91, 0x47, 0xA7, 0x14, 0x3B, + 0xE4, 0x95, 0xBC, 0x20, 0x48, 0x02, 0x6E, 0xCA, 0x37, 0x09, 0xF1, 0x3B, 0x88, 0x5B, 0x13, 0xD8, + 0x03, 0x81, 0xDD, 0xA7, 0x00, 0xC1, 0x02, 0x0D, 0xA0, 0x52, 0x81, 0xE6, 0x48, 0xEC, 0x81, 0xE3, + 0x97, 0x60, 0xF7, 0x71, 0x83, 0xC4, 0xEE, 0xFB, 0x48, 0x2B, 0x08, 0x22, 0x43, 0x4A, 0x8B, 0xEC, + 0xC6, 0xE1, 0xAF, 0x54, 0x36, 0x04, 0x76, 0xDD, 0x74, 0xDC, 0x94, 0xC4, 0xEE, 0x02, 0xBB, 0x0B, + 0xEC, 0x42, 0x21, 0x43, 0x76, 0xE5, 0x79, 0x9A, 0x76, 0x18, 0xB8, 0xAE, 0x80, 0x1F, 0x68, 0xBA, + 0xE7, 0xA4, 0x43, 0x24, 0x03, 0xB1, 0x0A, 0x83, 0xAC, 0x1F, 0xB8, 0x30, 0xAF, 0x11, 0x1C, 0x90, + 0x1C, 0x60, 0x77, 0x91, 0x5B, 0x60, 0x07, 0xD1, 0x02, 0xBB, 0xEB, 0x24, 0xC4, 0x52, 0x7A, 0x34, + 0xD8, 0x20, 0x10, 0xFB, 0x22, 0x84, 0x7B, 0x63, 0x97, 0x62, 0x80, 0xE8, 0x5D, 0x81, 0x1D, 0x92, + 0xEF, 0x85, 0x61, 0x4A, 0x53, 0xDD, 0xB4, 0xC4, 0x0E, 0xDE, 0x73, 0x75, 0x0D, 0x2F, 0x13, 0xD2, + 0x23, 0x7A, 0x46, 0xA1, 0x2B, 0xB0, 0x07, 0x81, 0x9F, 0x0E, 0x35, 0xD9, 0xB2, 0xE1, 0x13, 0xC4, + 0xEC, 0x22, 0xF6, 0x00, 0x37, 0xB8, 0x11, 0x76, 0xA4, 0x15, 0x86, 0x9F, 0x03, 0x7B, 0xBA, 0x22, + 0x2E, 0xB1, 0xBB, 0x1E, 0xE2, 0x04, 0xB1, 0xBB, 0xB0, 0x44, 0x5D, 0x07, 0x12, 0xEF, 0x08, 0xEC, + 0x76, 0x84, 0x3D, 0x1E, 0x78, 0x88, 0xD9, 0xF1, 0x43, 0x5D, 0xF7, 0x9D, 0x4C, 0x3C, 0x80, 0x74, + 0x7A, 0x7E, 0x3C, 0xAC, 0x08, 0x42, 0x89, 0xDD, 0xC1, 0x1D, 0x60, 0x1A, 0xC3, 0x13, 0xD8, 0xB5, + 0x94, 0x0B, 0x15, 0x03, 0x86, 0xF7, 0x9C, 0x24, 0xB8, 0xB0, 0x80, 0x3D, 0x1E, 0xC4, 0x5D, 0x79, + 0xC9, 0xDA, 0x96, 0xED, 0x52, 0x62, 0x87, 0x10, 0x7B, 0x50, 0xCE, 0x1E, 0xB0, 0xFB, 0xF1, 0x78, + 0x1A, 0xDE, 0x19, 0x58, 0x5B, 0xB2, 0x6C, 0x01, 0x1C, 0xB6, 0x42, 0x84, 0x3D, 0xA4, 0x38, 0x82, + 0x85, 0xC0, 0x1E, 0x64, 0x42, 0xDD, 0x15, 0x31, 0x00, 0x7B, 0x98, 0xC7, 0xAE, 0x15, 0xB0, 0x0B, + 0x1D, 0x12, 0x04, 0x61, 0x10, 0x8F, 0xC7, 0xB5, 0xA1, 0x6B, 0x7F, 0xD8, 0x33, 0x95, 0x79, 0xEC, + 0x7E, 0x26, 0x2E, 0x3A, 0x52, 0x1E, 0xB0, 0x7B, 0x12, 0xBB, 0x34, 0x11, 0x44, 0xF3, 0xF1, 0x1C, + 0xF1, 0xBC, 0xA1, 0x80, 0x0F, 0xEC, 0x81, 0x5B, 0x96, 0x40, 0x81, 0xA3, 0xF9, 0x26, 0xC2, 0xCA, + 0x20, 0xF4, 0x60, 0xB8, 0x02, 0xB2, 0xEB, 0x4A, 0xEC, 0x9E, 0xAE, 0xBB, 0x5A, 0xDA, 0x83, 0x92, + 0x11, 0xD8, 0xDD, 0x14, 0xF8, 0x0D, 0xD8, 0x51, 0x9F, 0x9E, 0x97, 0x08, 0x13, 0x25, 0xD8, 0x45, + 0x1E, 0x3D, 0x29, 0x06, 0x79, 0xEC, 0x90, 0x57, 0x42, 0x8E, 0x33, 0x48, 0xAF, 0x2C, 0xB4, 0x28, + 0x80, 0x2F, 0xE2, 0xD6, 0x05, 0xF6, 0xB8, 0xE3, 0x08, 0xEC, 0x09, 0x04, 0x8B, 0x6B, 0xA8, 0xD0, + 0xB2, 0x38, 0x4C, 0x4B, 0x64, 0x0C, 0xA5, 0x11, 0xC6, 0x9C, 0x22, 0xF6, 0x10, 0x37, 0x78, 0x22, + 0xDE, 0x30, 0x8C, 0x87, 0x89, 0x44, 0x42, 0xFF, 0xF7, 0xD8, 0xCB, 0xAA, 0x13, 0xE8, 0x39, 0x18, + 0x96, 0xE7, 0x97, 0x25, 0x8A, 0xD8, 0x5D, 0x74, 0x6C, 0x5C, 0x89, 0x1D, 0xC9, 0x03, 0x7B, 0x22, + 0xEE, 0x7B, 0xA1, 0xEF, 0x06, 0x71, 0xDD, 0x08, 0xDC, 0xF2, 0x24, 0x92, 0x41, 0x93, 0x4A, 0xC4, + 0xAB, 0xC3, 0xB8, 0x67, 0xD8, 0xA8, 0x6E, 0x04, 0x02, 0x2D, 0x1B, 0xBE, 0x2F, 0xB0, 0x67, 0x80, + 0xDD, 0x45, 0xD7, 0xD8, 0x77, 0x85, 0x1E, 0x30, 0x54, 0xC3, 0x8B, 0xC7, 0x3D, 0x3F, 0x19, 0x26, + 0x3C, 0x79, 0xC9, 0xDA, 0x1E, 0xC2, 0x8E, 0x06, 0xEC, 0xC3, 0x30, 0x11, 0xD8, 0x91, 0xE3, 0x32, + 0x54, 0x75, 0x39, 0x2C, 0xCD, 0x40, 0xC8, 0x95, 0x6F, 0xE8, 0x78, 0x59, 0x09, 0x07, 0x5D, 0xCD, + 0x38, 0x25, 0x10, 0x2C, 0xA1, 0xC7, 0xE3, 0x61, 0x36, 0x91, 0xC7, 0x9E, 0xF0, 0xE2, 0x25, 0xD8, + 0xE3, 0xB8, 0xC1, 0x8F, 0xB0, 0x27, 0x24, 0x76, 0x71, 0xC9, 0xEE, 0x82, 0xBE, 0x3F, 0xEC, 0xFF, + 0x27, 0x00, 0x00, 0xFF, 0xFF, 0xA4, 0xB4, 0xB8, 0xA4} diff --git a/label.go b/label.go new file mode 100644 index 0000000..b90d8f3 --- /dev/null +++ b/label.go @@ -0,0 +1,82 @@ +package gofpdf + +// Adapted from Nice Numbers for Graph Labels by Paul Heckbert from "Graphics +// Gems", Academic Press, 1990 + +// Paul Heckbert 2 Dec 88 + +// https://github.com/erich666/GraphicsGems + +// LICENSE + +// This code repository predates the concept of Open Source, and predates most +// licenses along such lines. As such, the official license truly is: + +// EULA: The Graphics Gems code is copyright-protected. In other words, you +// cannot claim the text of the code as your own and resell it. Using the code +// is permitted in any program, product, or library, non-commercial or +// commercial. Giving credit is not required, though is a nice gesture. The +// code comes as-is, and if there are any flaws or problems with any Gems code, +// nobody involved with Gems - authors, editors, publishers, or webmasters - +// are to be held responsible. Basically, don't be a jerk, and remember that +// anything free comes with no guarantee. + +import ( + "math" +) + +// niceNum returns a "nice" number approximately equal to x. The number is +// rounded if round is true, converted to its ceiling otherwise. +func niceNum(val float64, round bool) float64 { + var nf float64 + + exp := int(math.Floor(math.Log10(val))) + f := val / math.Pow10(exp) + if round { + switch { + case f < 1.5: + nf = 1 + case f < 3.0: + nf = 2 + case f < 7.0: + nf = 5 + default: + nf = 10 + } + } else { + switch { + case f <= 1: + nf = 1 + case f <= 2.0: + nf = 2 + case f <= 5.0: + nf = 5 + default: + nf = 10 + } + } + return nf * math.Pow10(exp) +} + +// TickmarkPrecision returns an appropriate precision value for label +// formatting. +func TickmarkPrecision(div float64) int { + return int(math.Max(-math.Floor(math.Log10(div)), 0)) +} + +// Tickmarks returns a slice of tickmarks appropriate for a chart axis and an +// appropriate precision for formatting purposes. The values min and max will +// be contained within the tickmark range. +func Tickmarks(min, max float64) (list []float64, precision int) { + if max > min { + spread := niceNum(max-min, false) + d := niceNum((spread / 4), true) + graphMin := math.Floor(min/d) * d + graphMax := math.Ceil(max/d) * d + precision = TickmarkPrecision(d) + for x := graphMin; x < graphMax+0.5*d; x += d { + list = append(list, x) + } + } + return +} diff --git a/layer.go b/layer.go new file mode 100644 index 0000000..bca364f --- /dev/null +++ b/layer.go @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2014 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf + +// Routines in this file are translated from +// http://www.fpdf.org/en/script/script97.php + +type layerType struct { + name string + visible bool + objNum int // object number +} + +type layerRecType struct { + list []layerType + currentLayer int + openLayerPane bool +} + +func (f *Fpdf) layerInit() { + f.layer.list = make([]layerType, 0) + f.layer.currentLayer = -1 + f.layer.openLayerPane = false +} + +// AddLayer defines a layer that can be shown or hidden when the document is +// displayed. name specifies the layer name that the document reader will +// display in the layer list. visible specifies whether the layer will be +// initially visible. The return value is an integer ID that is used in a call +// to BeginLayer(). +func (f *Fpdf) AddLayer(name string, visible bool) (layerID int) { + layerID = len(f.layer.list) + f.layer.list = append(f.layer.list, layerType{name: name, visible: visible}) + return +} + +// BeginLayer is called to begin adding content to the specified layer. All +// content added to the page between a call to BeginLayer and a call to +// EndLayer is added to the layer specified by id. See AddLayer for more +// details. +func (f *Fpdf) BeginLayer(id int) { + f.EndLayer() + if id >= 0 && id < len(f.layer.list) { + f.outf("/OC /OC%d BDC", id) + f.layer.currentLayer = id + } +} + +// EndLayer is called to stop adding content to the currently active layer. See +// BeginLayer for more details. +func (f *Fpdf) EndLayer() { + if f.layer.currentLayer >= 0 { + f.out("EMC") + f.layer.currentLayer = -1 + } +} + +// OpenLayerPane advises the document reader to open the layer pane when the +// document is initially displayed. +func (f *Fpdf) OpenLayerPane() { + f.layer.openLayerPane = true +} + +func (f *Fpdf) layerEndDoc() { + if len(f.layer.list) > 0 { + if f.pdfVersion < "1.5" { + f.pdfVersion = "1.5" + } + } +} + +func (f *Fpdf) layerPutLayers() { + for j, l := range f.layer.list { + f.newobj() + f.layer.list[j].objNum = f.n + f.outf("<>", f.textstring(utf8toutf16(l.name))) + f.out("endobj") + } +} + +func (f *Fpdf) layerPutResourceDict() { + if len(f.layer.list) > 0 { + f.out("/Properties <<") + for j, layer := range f.layer.list { + f.outf("/OC%d %d 0 R", j, layer.objNum) + } + f.out(">>") + } + +} + +func (f *Fpdf) layerPutCatalog() { + if len(f.layer.list) > 0 { + onStr := "" + offStr := "" + for _, layer := range f.layer.list { + onStr += sprintf("%d 0 R ", layer.objNum) + if !layer.visible { + offStr += sprintf("%d 0 R ", layer.objNum) + } + } + f.outf("/OCProperties <>>>", onStr, offStr, onStr) + if f.layer.openLayerPane { + f.out("/PageMode /UseOC") + } + } +} diff --git a/list/list.go b/list/list.go new file mode 100644 index 0000000..8099404 --- /dev/null +++ b/list/list.go @@ -0,0 +1,59 @@ +package main + +import ( + "fmt" + "os" + "path/filepath" + "strings" +) + +func matchTail(str, tailStr string) (match bool, headStr string) { + sln := len(str) + ln := len(tailStr) + if sln > ln { + match = str[sln-ln:] == tailStr + if match { + headStr = str[:sln-ln] + } + } + return +} + +func matchHead(str, headStr string) (match bool, tailStr string) { + ln := len(headStr) + if len(str) > ln { + match = str[:ln] == headStr + if match { + tailStr = str[ln:] + } + } + return +} + +func main() { + var err error + var ok bool + var showStr, name string + err = filepath.Walk("pdf/reference", func(path string, info os.FileInfo, err error) error { + if info.Mode().IsRegular() { + name = filepath.Base(path) + ok, name = matchTail(name, ".pdf") + if ok { + name = strings.Replace(name, "_", " ", -1) + ok, showStr = matchHead(name, "Fpdf ") + if ok { + fmt.Printf("[%s](%s)\n", showStr, path) + } else { + ok, showStr = matchHead(name, "contrib ") + if ok { + fmt.Printf("[%s](%s)\n", showStr, path) + } + } + } + } + return nil + }) + if err != nil { + fmt.Println(err) + } +} diff --git a/makefont/doc.go b/makefont/doc.go new file mode 100644 index 0000000..306ead2 --- /dev/null +++ b/makefont/doc.go @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2013 Kurt 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. + */ + +/* +Command makefont generates a font definition file. + +This utility is used to generate a font definition file that allows TrueType +and Type1 fonts to be used in PDFs produced with the fpdf package. +*/ +package main diff --git a/makefont/makefont.go b/makefont/makefont.go new file mode 100644 index 0000000..eb2993e --- /dev/null +++ b/makefont/makefont.go @@ -0,0 +1,71 @@ +package main + +import ( + "flag" + "fmt" + "github.com/jung-kurt/gofpdf" + "os" +) + +func errPrintf(fmtStr string, args ...interface{}) { + fmt.Fprintf(os.Stderr, fmtStr, args...) +} + +func showHelp() { + errPrintf("Usage: %s [options] font_file [font_file...]\n", os.Args[0]) + flag.PrintDefaults() + fmt.Fprintln(os.Stderr, "\n"+ + "font_file is the name of the TrueType file (extension .ttf), OpenType file\n"+ + "(extension .otf) or binary Type1 file (extension .pfb) from which to\n"+ + "generate a definition file. If an OpenType file is specified, it must be one\n"+ + "that is based on TrueType outlines, not PostScript outlines; this cannot be\n"+ + "determined from the file extension alone. If a Type1 file is specified, a\n"+ + "metric file with the same pathname except with the extension .afm must be\n"+ + "present.") + errPrintf("\nExample: %s --embed --enc=../font/cp1252.map --dst=../font calligra.ttf /opt/font/symbol.pfb\n", os.Args[0]) +} + +func tutorialSummary(f *gofpdf.Fpdf, fileStr string) { + if f.Ok() { + fl, err := os.Create(fileStr) + defer fl.Close() + if err == nil { + f.Output(fl) + } else { + f.SetError(err) + } + } + if f.Ok() { + fmt.Printf("Successfully generated %s\n", fileStr) + } else { + errPrintf("%s\n", f.Error()) + } +} + +func main() { + var dstDirStr, encodingFileStr string + var err error + var help, embed bool + flag.StringVar(&dstDirStr, "dst", ".", "directory for output files (*.z, *.json)") + flag.StringVar(&encodingFileStr, "enc", "cp1252.map", "code page file") + flag.BoolVar(&embed, "embed", false, "embed font into PDF") + flag.BoolVar(&help, "help", false, "command line usage") + flag.Parse() + if help { + showHelp() + } else { + args := flag.Args() + if len(args) > 0 { + for _, fileStr := range args { + err = gofpdf.MakeFont(fileStr, encodingFileStr, dstDirStr, os.Stderr, embed) + if err != nil { + errPrintf("%s\n", err) + } + // errPrintf("Font file [%s], Encoding file [%s], Embed [%v]\n", fileStr, encodingFileStr, embed) + } + } else { + errPrintf("At least one Type1 or TrueType font must be specified\n") + showHelp() + } + } +} diff --git a/makefont/makefont_test.go b/makefont/makefont_test.go new file mode 100644 index 0000000..df63aa8 --- /dev/null +++ b/makefont/makefont_test.go @@ -0,0 +1,26 @@ +package main + +import ( + "os/exec" + "strings" + "testing" +) + +func TestMakefont(t *testing.T) { + var out []byte + var err error + const expect = "Font definition file successfully generated" + // Make sure makefont utility has been built before generating font definition file + err = exec.Command("go", "build").Run() + if err != nil { + t.Fatal(err) + } + out, err = exec.Command("./makefont", "--dst=../font", "--embed", + "--enc=../font/cp1252.map", "../font/calligra.ttf").CombinedOutput() + if err != nil { + t.Fatal(err) + } + if !strings.Contains(string(out), expect) { + t.Fatalf("Unexpected output from makefont") + } +} diff --git a/pdf/.empty b/pdf/.empty new file mode 100644 index 0000000..e69de29 diff --git a/pdf/reference/Fpdf_AddFont.pdf b/pdf/reference/Fpdf_AddFont.pdf new file mode 100644 index 0000000..f6a7404 Binary files /dev/null and b/pdf/reference/Fpdf_AddFont.pdf differ diff --git a/pdf/reference/Fpdf_AddLayer.pdf b/pdf/reference/Fpdf_AddLayer.pdf new file mode 100644 index 0000000..d0edbe7 Binary files /dev/null and b/pdf/reference/Fpdf_AddLayer.pdf differ diff --git a/pdf/reference/Fpdf_AddPage.pdf b/pdf/reference/Fpdf_AddPage.pdf new file mode 100644 index 0000000..cfeafea Binary files /dev/null and b/pdf/reference/Fpdf_AddPage.pdf differ diff --git a/pdf/reference/Fpdf_AddUTF8Font.pdf b/pdf/reference/Fpdf_AddUTF8Font.pdf new file mode 100644 index 0000000..cb2b6e2 Binary files /dev/null and b/pdf/reference/Fpdf_AddUTF8Font.pdf differ diff --git a/pdf/reference/Fpdf_Beziergon.pdf b/pdf/reference/Fpdf_Beziergon.pdf new file mode 100644 index 0000000..d0ac598 --- /dev/null +++ b/pdf/reference/Fpdf_Beziergon.pdf @@ -0,0 +1,108 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +0.000 G +0.000 g +BT /F0 15.00 Tf ET +BT 176.34 801.54 Td (Demonstration of Beziergon function) Tj ET +[2.27 2.27] 0.00 d +0.627 G +121.89 690.00 m +209.76378 690.00024 l +209.76378 602.12622 l +297.63780 602.12622 l +297.63780 514.25220 l +385.51181 514.25220 l +385.51181 426.37819 l +473.38583 426.37819 l +473.38583 338.50417 l +209.76378 338.50417 l +209.76378 426.37819 l +121.88976 426.37819 l +121.88976 690.00024 l +S +[] 0.00 d +0.251 0.251 0.502 RG +1.70 w +121.89 426.38 m +69.16535 479.10260 69.16535 637.27583 121.88976 690.00024 c +174.61417 742.72465 157.03937 742.72465 209.76378 690.00024 c +262.48819 637.27583 157.03937 654.85063 209.76378 602.12622 c +262.48819 549.40181 244.91339 654.85063 297.63780 602.12622 c +350.36220 549.40181 244.91339 566.97661 297.63780 514.25220 c +350.36220 461.52780 332.78740 566.97661 385.51181 514.25220 c +438.23622 461.52780 332.78740 479.10260 385.51181 426.37819 c +438.23622 373.65378 420.66142 479.10260 473.38583 426.37819 c +526.11024 373.65378 526.11024 391.22858 473.38583 338.50417 c +420.66142 285.77976 262.48819 285.77976 209.76378 338.50417 c +157.03937 391.22858 262.48819 373.65378 209.76378 426.37819 c +157.03937 479.10260 174.61417 373.65378 121.88976 426.37819 c +S + +endstream +endobj +1 0 obj +<> +endobj +5 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F0 5 0 R +>> +/XObject << +>> +>> +endobj +6 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +7 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 8 +0000000000 65535 f +0000001370 00000 n +0000001553 00000 n +0000000009 00000 n +0000000087 00000 n +0000001457 00000 n +0000001657 00000 n +0000001732 00000 n +trailer +<< +/Size 8 +/Root 7 0 R +/Info 6 0 R +>> +startxref +1781 +%%EOF diff --git a/pdf/reference/Fpdf_Bookmark.pdf b/pdf/reference/Fpdf_Bookmark.pdf new file mode 100644 index 0000000..a7d8c7c --- /dev/null +++ b/pdf/reference/Fpdf_Bookmark.pdf @@ -0,0 +1,147 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +0.000 G +0.000 g +BT /F0 15.00 Tf ET +BT 31.19 800.54 Td (Paragraph 1) Tj ET +BT 31.19 658.80 Td (Paragraph 2) Tj ET + +endstream +endobj +5 0 obj +<> +endobj +6 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0 15.00 Tf ET +0.000 G +0.000 g +BT 31.19 800.54 Td (Paragraph 3) Tj ET + +endstream +endobj +1 0 obj +<> +endobj +7 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F0 7 0 R +>> +/XObject << +>> +>> +endobj +8 0 obj +<> +endobj +9 0 obj +<> +endobj +10 0 obj +<> +endobj +11 0 obj +<> +endobj +12 0 obj +<> +endobj +13 0 obj +<> +endobj +14 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +15 0 obj +<< +/Type /Catalog +/Pages 1 0 R +/Outlines 13 0 R +/PageMode /UseOutlines +>> +endobj +xref +0 16 +0000000000 65535 f +0000000479 00000 n +0000000668 00000 n +0000000009 00000 n +0000000087 00000 n +0000000264 00000 n +0000000342 00000 n +0000000572 00000 n +0000000772 00000 n +0000000903 00000 n +0000001012 00000 n +0000001121 00000 n +0000001253 00000 n +0000001351 00000 n +0000001413 00000 n +0000001489 00000 n +trailer +<< +/Size 16 +/Root 15 0 R +/Info 14 0 R +>> +startxref +1579 +%%EOF diff --git a/pdf/reference/Fpdf_CellFormat_align.pdf b/pdf/reference/Fpdf_CellFormat_align.pdf new file mode 100644 index 0000000..e197a42 Binary files /dev/null and b/pdf/reference/Fpdf_CellFormat_align.pdf differ diff --git a/pdf/reference/Fpdf_CellFormat_codepage.pdf b/pdf/reference/Fpdf_CellFormat_codepage.pdf new file mode 100644 index 0000000..045caf6 Binary files /dev/null and b/pdf/reference/Fpdf_CellFormat_codepage.pdf differ diff --git a/pdf/reference/Fpdf_CellFormat_codepageescape.pdf b/pdf/reference/Fpdf_CellFormat_codepageescape.pdf new file mode 100644 index 0000000..a59ed43 --- /dev/null +++ b/pdf/reference/Fpdf_CellFormat_codepageescape.pdf @@ -0,0 +1,85 @@ +%PDF-1.3 +3 0 obj +<>>>] +/Contents 4 0 R>> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0 16.00 Tf ET +0.000 G +0.000 g +BT 31.19 800.74 Td (Until gofpdf supports UTF-8 encoded source text, source text needs to be) Tj ET +BT 31.19 784.74 Td (specified with all special characters escaped to match the code page) Tj ET +BT 31.19 768.74 Td (layout of the currently selected font. By default, gofdpf uses code page) Tj ET +BT 31.19 752.74 Td (1252. See ) Tj ET +q 0.000 0.000 0.502 rg BT 108.58 752.74 Td (Wikipedia) Tj ET 108.58 751.14 69.34 -0.80 re f Q +BT 177.92 752.74 Td ( for a table of this layout.) Tj ET +BT 70.69 720.74 Td (Voix ambigu d'un cur qui au zphyr prfre les jattes de kiwi.) Tj ET +BT 69.99 688.74 Td (Falsches ben von Xylophonmusik qult jeden greren Zwerg.) Tj ET +BT 200.27 656.74 Td (Heizlrckstoabdmpfung) Tj ET +BT 168.71 624.74 Td (Forrsjvndgn / Efterrsjvndgn) Tj ET + +endstream +endobj +1 0 obj +<> +endobj +5 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F0 5 0 R +>> +/XObject << +>> +>> +endobj +6 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +7 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 8 +0000000000 65535 f +0000001123 00000 n +0000001306 00000 n +0000000009 00000 n +0000000245 00000 n +0000001210 00000 n +0000001410 00000 n +0000001485 00000 n +trailer +<< +/Size 8 +/Root 7 0 R +/Info 6 0 R +>> +startxref +1534 +%%EOF diff --git a/pdf/reference/Fpdf_CellFormat_tables.pdf b/pdf/reference/Fpdf_CellFormat_tables.pdf new file mode 100644 index 0000000..ccb45f4 --- /dev/null +++ b/pdf/reference/Fpdf_CellFormat_tables.pdf @@ -0,0 +1,323 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0 14.00 Tf ET +0.000 G +0.000 g +28.35 813.54 113.39 -19.84 re S BT 31.19 799.42 Td (Country) Tj ET +141.74 813.54 113.39 -19.84 re S BT 144.57 799.42 Td (Capital) Tj ET +255.12 813.54 113.39 -19.84 re S BT 257.96 799.42 Td (Area \(sq km\)) Tj ET +368.51 813.54 113.39 -19.84 re S BT 371.34 799.42 Td (Pop. \(thousands\)) Tj ET +28.35 793.70 113.39 -17.01 re S BT 31.19 780.99 Td (Austria) Tj ET +141.74 793.70 113.39 -17.01 re S BT 144.57 780.99 Td (Vienna) Tj ET +255.12 793.70 113.39 -17.01 re S BT 257.96 780.99 Td (83859) Tj ET +368.51 793.70 113.39 -17.01 re S BT 371.34 780.99 Td (8075) Tj ET +28.35 776.69 113.39 -17.01 re S BT 31.19 763.99 Td (Belgium) Tj ET +141.74 776.69 113.39 -17.01 re S BT 144.57 763.99 Td (Brussels) Tj ET +255.12 776.69 113.39 -17.01 re S BT 257.96 763.99 Td (30518) Tj ET +368.51 776.69 113.39 -17.01 re S BT 371.34 763.99 Td (10192) Tj ET +28.35 759.68 113.39 -17.01 re S BT 31.19 746.98 Td (Denmark) Tj ET +141.74 759.68 113.39 -17.01 re S BT 144.57 746.98 Td (Copenhagen) Tj ET +255.12 759.68 113.39 -17.01 re S BT 257.96 746.98 Td (43094) Tj ET +368.51 759.68 113.39 -17.01 re S BT 371.34 746.98 Td (5295) Tj ET +28.35 742.67 113.39 -17.01 re S BT 31.19 729.97 Td (Finland) Tj ET +141.74 742.67 113.39 -17.01 re S BT 144.57 729.97 Td (Helsinki) Tj ET +255.12 742.67 113.39 -17.01 re S BT 257.96 729.97 Td (304529) Tj ET +368.51 742.67 113.39 -17.01 re S BT 371.34 729.97 Td (5147) Tj ET +28.35 725.67 113.39 -17.01 re S BT 31.19 712.96 Td (France) Tj ET +141.74 725.67 113.39 -17.01 re S BT 144.57 712.96 Td (Paris) Tj ET +255.12 725.67 113.39 -17.01 re S BT 257.96 712.96 Td (543965) Tj ET +368.51 725.67 113.39 -17.01 re S BT 371.34 712.96 Td (58728) Tj ET +28.35 708.66 113.39 -17.01 re S BT 31.19 695.95 Td (Germany) Tj ET +141.74 708.66 113.39 -17.01 re S BT 144.57 695.95 Td (Berlin) Tj ET +255.12 708.66 113.39 -17.01 re S BT 257.96 695.95 Td (357022) Tj ET +368.51 708.66 113.39 -17.01 re S BT 371.34 695.95 Td (82057) Tj ET +28.35 691.65 113.39 -17.01 re S BT 31.19 678.95 Td (Greece) Tj ET +141.74 691.65 113.39 -17.01 re S BT 144.57 678.95 Td (Athens) Tj ET +255.12 691.65 113.39 -17.01 re S BT 257.96 678.95 Td (131625) Tj ET +368.51 691.65 113.39 -17.01 re S BT 371.34 678.95 Td (10511) Tj ET +28.35 674.64 113.39 -17.01 re S BT 31.19 661.94 Td (Ireland) Tj ET +141.74 674.64 113.39 -17.01 re S BT 144.57 661.94 Td (Dublin) Tj ET +255.12 674.64 113.39 -17.01 re S BT 257.96 661.94 Td (70723) Tj ET +368.51 674.64 113.39 -17.01 re S BT 371.34 661.94 Td (3694) Tj ET +28.35 657.63 113.39 -17.01 re S BT 31.19 644.93 Td (Italy) Tj ET +141.74 657.63 113.39 -17.01 re S BT 144.57 644.93 Td (Roma) Tj ET +255.12 657.63 113.39 -17.01 re S BT 257.96 644.93 Td (301316) Tj ET +368.51 657.63 113.39 -17.01 re S BT 371.34 644.93 Td (57563) Tj ET +28.35 640.63 113.39 -17.01 re S BT 31.19 627.92 Td (Luxembourg) Tj ET +141.74 640.63 113.39 -17.01 re S BT 144.57 627.92 Td (Luxembourg) Tj ET +255.12 640.63 113.39 -17.01 re S BT 257.96 627.92 Td (2586) Tj ET +368.51 640.63 113.39 -17.01 re S BT 371.34 627.92 Td (424) Tj ET +28.35 623.62 113.39 -17.01 re S BT 31.19 610.91 Td (Netherlands) Tj ET +141.74 623.62 113.39 -17.01 re S BT 144.57 610.91 Td (Amsterdam) Tj ET +255.12 623.62 113.39 -17.01 re S BT 257.96 610.91 Td (41526) Tj ET +368.51 623.62 113.39 -17.01 re S BT 371.34 610.91 Td (15654) Tj ET +28.35 606.61 113.39 -17.01 re S BT 31.19 593.91 Td (Portugal) Tj ET +141.74 606.61 113.39 -17.01 re S BT 144.57 593.91 Td (Lisbon) Tj ET +255.12 606.61 113.39 -17.01 re S BT 257.96 593.91 Td (91906) Tj ET +368.51 606.61 113.39 -17.01 re S BT 371.34 593.91 Td (9957) Tj ET +28.35 589.60 113.39 -17.01 re S BT 31.19 576.90 Td (Spain) Tj ET +141.74 589.60 113.39 -17.01 re S BT 144.57 576.90 Td (Madrid) Tj ET +255.12 589.60 113.39 -17.01 re S BT 257.96 576.90 Td (504790) Tj ET +368.51 589.60 113.39 -17.01 re S BT 371.34 576.90 Td (39348) Tj ET +28.35 572.60 113.39 -17.01 re S BT 31.19 559.89 Td (Sweden) Tj ET +141.74 572.60 113.39 -17.01 re S BT 144.57 559.89 Td (Stockholm) Tj ET +255.12 572.60 113.39 -17.01 re S BT 257.96 559.89 Td (410934) Tj ET +368.51 572.60 113.39 -17.01 re S BT 371.34 559.89 Td (8839) Tj ET +28.35 555.59 113.39 -17.01 re S BT 31.19 542.88 Td (United Kingdom) Tj ET +141.74 555.59 113.39 -17.01 re S BT 144.57 542.88 Td (London) Tj ET +255.12 555.59 113.39 -17.01 re S BT 257.96 542.88 Td (243820) Tj ET +368.51 555.59 113.39 -17.01 re S BT 371.34 542.88 Td (58862) Tj ET + +endstream +endobj +5 0 obj +<> +endobj +6 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0 14.00 Tf ET +0.000 G +0.000 g +28.35 813.54 113.39 -19.84 re S BT 60.54 799.42 Td (Country) Tj ET +141.74 813.54 99.21 -19.84 re S BT 169.56 799.42 Td (Capital) Tj ET +240.95 813.54 113.39 -19.84 re S BT 257.58 799.42 Td (Area \(sq km\)) Tj ET +354.33 813.54 127.56 -19.84 re S BT 364.81 799.42 Td (Pop. \(thousands\)) Tj ET +28.35 793.70 m 28.35 776.69 l S 141.74 793.70 m 141.74 776.69 l S BT 31.19 780.99 Td (Austria) Tj ET +141.74 793.70 m 141.74 776.69 l S 240.95 793.70 m 240.95 776.69 l S BT 144.57 780.99 Td (Vienna) Tj ET +240.95 793.70 m 240.95 776.69 l S 354.33 793.70 m 354.33 776.69 l S BT 308.69 780.99 Td (83,859) Tj ET +354.33 793.70 m 354.33 776.69 l S 481.89 793.70 m 481.89 776.69 l S BT 444.03 780.99 Td (8,075) Tj ET +28.35 776.69 m 28.35 759.68 l S 141.74 776.69 m 141.74 759.68 l S BT 31.19 763.99 Td (Belgium) Tj ET +141.74 776.69 m 141.74 759.68 l S 240.95 776.69 m 240.95 759.68 l S BT 144.57 763.99 Td (Brussels) Tj ET +240.95 776.69 m 240.95 759.68 l S 354.33 776.69 m 354.33 759.68 l S BT 308.69 763.99 Td (30,518) Tj ET +354.33 776.69 m 354.33 759.68 l S 481.89 776.69 m 481.89 759.68 l S BT 436.25 763.99 Td (10,192) Tj ET +28.35 759.68 m 28.35 742.67 l S 141.74 759.68 m 141.74 742.67 l S BT 31.19 746.98 Td (Denmark) Tj ET +141.74 759.68 m 141.74 742.67 l S 240.95 759.68 m 240.95 742.67 l S BT 144.57 746.98 Td (Copenhagen) Tj ET +240.95 759.68 m 240.95 742.67 l S 354.33 759.68 m 354.33 742.67 l S BT 308.69 746.98 Td (43,094) Tj ET +354.33 759.68 m 354.33 742.67 l S 481.89 759.68 m 481.89 742.67 l S BT 444.03 746.98 Td (5,295) Tj ET +28.35 742.67 m 28.35 725.67 l S 141.74 742.67 m 141.74 725.67 l S BT 31.19 729.97 Td (Finland) Tj ET +141.74 742.67 m 141.74 725.67 l S 240.95 742.67 m 240.95 725.67 l S BT 144.57 729.97 Td (Helsinki) Tj ET +240.95 742.67 m 240.95 725.67 l S 354.33 742.67 m 354.33 725.67 l S BT 300.90 729.97 Td (304,529) Tj ET +354.33 742.67 m 354.33 725.67 l S 481.89 742.67 m 481.89 725.67 l S BT 444.03 729.97 Td (5,147) Tj ET +28.35 725.67 m 28.35 708.66 l S 141.74 725.67 m 141.74 708.66 l S BT 31.19 712.96 Td (France) Tj ET +141.74 725.67 m 141.74 708.66 l S 240.95 725.67 m 240.95 708.66 l S BT 144.57 712.96 Td (Paris) Tj ET +240.95 725.67 m 240.95 708.66 l S 354.33 725.67 m 354.33 708.66 l S BT 300.90 712.96 Td (543,965) Tj ET +354.33 725.67 m 354.33 708.66 l S 481.89 725.67 m 481.89 708.66 l S BT 436.25 712.96 Td (58,728) Tj ET +28.35 708.66 m 28.35 691.65 l S 141.74 708.66 m 141.74 691.65 l S BT 31.19 695.95 Td (Germany) Tj ET +141.74 708.66 m 141.74 691.65 l S 240.95 708.66 m 240.95 691.65 l S BT 144.57 695.95 Td (Berlin) Tj ET +240.95 708.66 m 240.95 691.65 l S 354.33 708.66 m 354.33 691.65 l S BT 300.90 695.95 Td (357,022) Tj ET +354.33 708.66 m 354.33 691.65 l S 481.89 708.66 m 481.89 691.65 l S BT 436.25 695.95 Td (82,057) Tj ET +28.35 691.65 m 28.35 674.64 l S 141.74 691.65 m 141.74 674.64 l S BT 31.19 678.95 Td (Greece) Tj ET +141.74 691.65 m 141.74 674.64 l S 240.95 691.65 m 240.95 674.64 l S BT 144.57 678.95 Td (Athens) Tj ET +240.95 691.65 m 240.95 674.64 l S 354.33 691.65 m 354.33 674.64 l S BT 300.90 678.95 Td (131,625) Tj ET +354.33 691.65 m 354.33 674.64 l S 481.89 691.65 m 481.89 674.64 l S BT 436.25 678.95 Td (10,511) Tj ET +28.35 674.64 m 28.35 657.63 l S 141.74 674.64 m 141.74 657.63 l S BT 31.19 661.94 Td (Ireland) Tj ET +141.74 674.64 m 141.74 657.63 l S 240.95 674.64 m 240.95 657.63 l S BT 144.57 661.94 Td (Dublin) Tj ET +240.95 674.64 m 240.95 657.63 l S 354.33 674.64 m 354.33 657.63 l S BT 308.69 661.94 Td (70,723) Tj ET +354.33 674.64 m 354.33 657.63 l S 481.89 674.64 m 481.89 657.63 l S BT 444.03 661.94 Td (3,694) Tj ET +28.35 657.63 m 28.35 640.63 l S 141.74 657.63 m 141.74 640.63 l S BT 31.19 644.93 Td (Italy) Tj ET +141.74 657.63 m 141.74 640.63 l S 240.95 657.63 m 240.95 640.63 l S BT 144.57 644.93 Td (Roma) Tj ET +240.95 657.63 m 240.95 640.63 l S 354.33 657.63 m 354.33 640.63 l S BT 300.90 644.93 Td (301,316) Tj ET +354.33 657.63 m 354.33 640.63 l S 481.89 657.63 m 481.89 640.63 l S BT 436.25 644.93 Td (57,563) Tj ET +28.35 640.63 m 28.35 623.62 l S 141.74 640.63 m 141.74 623.62 l S BT 31.19 627.92 Td (Luxembourg) Tj ET +141.74 640.63 m 141.74 623.62 l S 240.95 640.63 m 240.95 623.62 l S BT 144.57 627.92 Td (Luxembourg) Tj ET +240.95 640.63 m 240.95 623.62 l S 354.33 640.63 m 354.33 623.62 l S BT 316.47 627.92 Td (2,586) Tj ET +354.33 640.63 m 354.33 623.62 l S 481.89 640.63 m 481.89 623.62 l S BT 455.71 627.92 Td (424) Tj ET +28.35 623.62 m 28.35 606.61 l S 141.74 623.62 m 141.74 606.61 l S BT 31.19 610.91 Td (Netherlands) Tj ET +141.74 623.62 m 141.74 606.61 l S 240.95 623.62 m 240.95 606.61 l S BT 144.57 610.91 Td (Amsterdam) Tj ET +240.95 623.62 m 240.95 606.61 l S 354.33 623.62 m 354.33 606.61 l S BT 308.69 610.91 Td (41,526) Tj ET +354.33 623.62 m 354.33 606.61 l S 481.89 623.62 m 481.89 606.61 l S BT 436.25 610.91 Td (15,654) Tj ET +28.35 606.61 m 28.35 589.60 l S 141.74 606.61 m 141.74 589.60 l S BT 31.19 593.91 Td (Portugal) Tj ET +141.74 606.61 m 141.74 589.60 l S 240.95 606.61 m 240.95 589.60 l S BT 144.57 593.91 Td (Lisbon) Tj ET +240.95 606.61 m 240.95 589.60 l S 354.33 606.61 m 354.33 589.60 l S BT 308.69 593.91 Td (91,906) Tj ET +354.33 606.61 m 354.33 589.60 l S 481.89 606.61 m 481.89 589.60 l S BT 444.03 593.91 Td (9,957) Tj ET +28.35 589.60 m 28.35 572.60 l S 141.74 589.60 m 141.74 572.60 l S BT 31.19 576.90 Td (Spain) Tj ET +141.74 589.60 m 141.74 572.60 l S 240.95 589.60 m 240.95 572.60 l S BT 144.57 576.90 Td (Madrid) Tj ET +240.95 589.60 m 240.95 572.60 l S 354.33 589.60 m 354.33 572.60 l S BT 300.90 576.90 Td (504,790) Tj ET +354.33 589.60 m 354.33 572.60 l S 481.89 589.60 m 481.89 572.60 l S BT 436.25 576.90 Td (39,348) Tj ET +28.35 572.60 m 28.35 555.59 l S 141.74 572.60 m 141.74 555.59 l S BT 31.19 559.89 Td (Sweden) Tj ET +141.74 572.60 m 141.74 555.59 l S 240.95 572.60 m 240.95 555.59 l S BT 144.57 559.89 Td (Stockholm) Tj ET +240.95 572.60 m 240.95 555.59 l S 354.33 572.60 m 354.33 555.59 l S BT 300.90 559.89 Td (410,934) Tj ET +354.33 572.60 m 354.33 555.59 l S 481.89 572.60 m 481.89 555.59 l S BT 444.03 559.89 Td (8,839) Tj ET +28.35 555.59 m 28.35 538.58 l S 141.74 555.59 m 141.74 538.58 l S BT 31.19 542.88 Td (United Kingdom) Tj ET +141.74 555.59 m 141.74 538.58 l S 240.95 555.59 m 240.95 538.58 l S BT 144.57 542.88 Td (London) Tj ET +240.95 555.59 m 240.95 538.58 l S 354.33 555.59 m 354.33 538.58 l S BT 300.90 542.88 Td (243,820) Tj ET +354.33 555.59 m 354.33 538.58 l S 481.89 555.59 m 481.89 538.58 l S BT 436.25 542.88 Td (58,862) Tj ET +28.35 538.58 m 481.89 538.58 l S + +endstream +endobj +7 0 obj +<> +endobj +8 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0 14.00 Tf ET +0.000 G +0.000 g +1.000 0.000 0.000 rg +0.502 0.000 0.000 RG +0.85 w +BT /F1 14.00 Tf ET +28.35 813.54 113.39 -19.84 re B q 1.000 g BT 58.21 799.42 Td (Country) Tj ET Q +141.74 813.54 99.21 -19.84 re B q 1.000 g BT 168.00 799.42 Td (Capital) Tj ET Q +240.95 813.54 113.39 -19.84 re B q 1.000 g BT 255.24 799.42 Td (Area \(sq km\)) Tj ET Q +354.33 813.54 127.56 -19.84 re B q 1.000 g BT 360.94 799.42 Td (Pop. \(thousands\)) Tj ET Q +0.878 0.922 1.000 rg +BT /F0 14.00 Tf ET +28.35 793.70 m 28.35 776.69 l S 141.74 793.70 m 141.74 776.69 l S q 0.000 g BT 31.19 780.99 Td (Austria) Tj ET Q +141.74 793.70 m 141.74 776.69 l S 240.95 793.70 m 240.95 776.69 l S q 0.000 g BT 144.57 780.99 Td (Vienna) Tj ET Q +240.95 793.70 m 240.95 776.69 l S 354.33 793.70 m 354.33 776.69 l S q 0.000 g BT 308.69 780.99 Td (83,859) Tj ET Q +354.33 793.70 m 354.33 776.69 l S 481.89 793.70 m 481.89 776.69 l S q 0.000 g BT 444.03 780.99 Td (8,075) Tj ET Q +28.35 776.69 113.39 -17.01 re f 28.35 776.69 m 28.35 759.68 l S 141.74 776.69 m 141.74 759.68 l S q 0.000 g BT 31.19 763.99 Td (Belgium) Tj ET Q +141.74 776.69 99.21 -17.01 re f 141.74 776.69 m 141.74 759.68 l S 240.95 776.69 m 240.95 759.68 l S q 0.000 g BT 144.57 763.99 Td (Brussels) Tj ET Q +240.95 776.69 113.39 -17.01 re f 240.95 776.69 m 240.95 759.68 l S 354.33 776.69 m 354.33 759.68 l S q 0.000 g BT 308.69 763.99 Td (30,518) Tj ET Q +354.33 776.69 127.56 -17.01 re f 354.33 776.69 m 354.33 759.68 l S 481.89 776.69 m 481.89 759.68 l S q 0.000 g BT 436.25 763.99 Td (10,192) Tj ET Q +28.35 759.68 m 28.35 742.67 l S 141.74 759.68 m 141.74 742.67 l S q 0.000 g BT 31.19 746.98 Td (Denmark) Tj ET Q +141.74 759.68 m 141.74 742.67 l S 240.95 759.68 m 240.95 742.67 l S q 0.000 g BT 144.57 746.98 Td (Copenhagen) Tj ET Q +240.95 759.68 m 240.95 742.67 l S 354.33 759.68 m 354.33 742.67 l S q 0.000 g BT 308.69 746.98 Td (43,094) Tj ET Q +354.33 759.68 m 354.33 742.67 l S 481.89 759.68 m 481.89 742.67 l S q 0.000 g BT 444.03 746.98 Td (5,295) Tj ET Q +28.35 742.67 113.39 -17.01 re f 28.35 742.67 m 28.35 725.67 l S 141.74 742.67 m 141.74 725.67 l S q 0.000 g BT 31.19 729.97 Td (Finland) Tj ET Q +141.74 742.67 99.21 -17.01 re f 141.74 742.67 m 141.74 725.67 l S 240.95 742.67 m 240.95 725.67 l S q 0.000 g BT 144.57 729.97 Td (Helsinki) Tj ET Q +240.95 742.67 113.39 -17.01 re f 240.95 742.67 m 240.95 725.67 l S 354.33 742.67 m 354.33 725.67 l S q 0.000 g BT 300.90 729.97 Td (304,529) Tj ET Q +354.33 742.67 127.56 -17.01 re f 354.33 742.67 m 354.33 725.67 l S 481.89 742.67 m 481.89 725.67 l S q 0.000 g BT 444.03 729.97 Td (5,147) Tj ET Q +28.35 725.67 m 28.35 708.66 l S 141.74 725.67 m 141.74 708.66 l S q 0.000 g BT 31.19 712.96 Td (France) Tj ET Q +141.74 725.67 m 141.74 708.66 l S 240.95 725.67 m 240.95 708.66 l S q 0.000 g BT 144.57 712.96 Td (Paris) Tj ET Q +240.95 725.67 m 240.95 708.66 l S 354.33 725.67 m 354.33 708.66 l S q 0.000 g BT 300.90 712.96 Td (543,965) Tj ET Q +354.33 725.67 m 354.33 708.66 l S 481.89 725.67 m 481.89 708.66 l S q 0.000 g BT 436.25 712.96 Td (58,728) Tj ET Q +28.35 708.66 113.39 -17.01 re f 28.35 708.66 m 28.35 691.65 l S 141.74 708.66 m 141.74 691.65 l S q 0.000 g BT 31.19 695.95 Td (Germany) Tj ET Q +141.74 708.66 99.21 -17.01 re f 141.74 708.66 m 141.74 691.65 l S 240.95 708.66 m 240.95 691.65 l S q 0.000 g BT 144.57 695.95 Td (Berlin) Tj ET Q +240.95 708.66 113.39 -17.01 re f 240.95 708.66 m 240.95 691.65 l S 354.33 708.66 m 354.33 691.65 l S q 0.000 g BT 300.90 695.95 Td (357,022) Tj ET Q +354.33 708.66 127.56 -17.01 re f 354.33 708.66 m 354.33 691.65 l S 481.89 708.66 m 481.89 691.65 l S q 0.000 g BT 436.25 695.95 Td (82,057) Tj ET Q +28.35 691.65 m 28.35 674.64 l S 141.74 691.65 m 141.74 674.64 l S q 0.000 g BT 31.19 678.95 Td (Greece) Tj ET Q +141.74 691.65 m 141.74 674.64 l S 240.95 691.65 m 240.95 674.64 l S q 0.000 g BT 144.57 678.95 Td (Athens) Tj ET Q +240.95 691.65 m 240.95 674.64 l S 354.33 691.65 m 354.33 674.64 l S q 0.000 g BT 300.90 678.95 Td (131,625) Tj ET Q +354.33 691.65 m 354.33 674.64 l S 481.89 691.65 m 481.89 674.64 l S q 0.000 g BT 436.25 678.95 Td (10,511) Tj ET Q +28.35 674.64 113.39 -17.01 re f 28.35 674.64 m 28.35 657.63 l S 141.74 674.64 m 141.74 657.63 l S q 0.000 g BT 31.19 661.94 Td (Ireland) Tj ET Q +141.74 674.64 99.21 -17.01 re f 141.74 674.64 m 141.74 657.63 l S 240.95 674.64 m 240.95 657.63 l S q 0.000 g BT 144.57 661.94 Td (Dublin) Tj ET Q +240.95 674.64 113.39 -17.01 re f 240.95 674.64 m 240.95 657.63 l S 354.33 674.64 m 354.33 657.63 l S q 0.000 g BT 308.69 661.94 Td (70,723) Tj ET Q +354.33 674.64 127.56 -17.01 re f 354.33 674.64 m 354.33 657.63 l S 481.89 674.64 m 481.89 657.63 l S q 0.000 g BT 444.03 661.94 Td (3,694) Tj ET Q +28.35 657.63 m 28.35 640.63 l S 141.74 657.63 m 141.74 640.63 l S q 0.000 g BT 31.19 644.93 Td (Italy) Tj ET Q +141.74 657.63 m 141.74 640.63 l S 240.95 657.63 m 240.95 640.63 l S q 0.000 g BT 144.57 644.93 Td (Roma) Tj ET Q +240.95 657.63 m 240.95 640.63 l S 354.33 657.63 m 354.33 640.63 l S q 0.000 g BT 300.90 644.93 Td (301,316) Tj ET Q +354.33 657.63 m 354.33 640.63 l S 481.89 657.63 m 481.89 640.63 l S q 0.000 g BT 436.25 644.93 Td (57,563) Tj ET Q +28.35 640.63 113.39 -17.01 re f 28.35 640.63 m 28.35 623.62 l S 141.74 640.63 m 141.74 623.62 l S q 0.000 g BT 31.19 627.92 Td (Luxembourg) Tj ET Q +141.74 640.63 99.21 -17.01 re f 141.74 640.63 m 141.74 623.62 l S 240.95 640.63 m 240.95 623.62 l S q 0.000 g BT 144.57 627.92 Td (Luxembourg) Tj ET Q +240.95 640.63 113.39 -17.01 re f 240.95 640.63 m 240.95 623.62 l S 354.33 640.63 m 354.33 623.62 l S q 0.000 g BT 316.47 627.92 Td (2,586) Tj ET Q +354.33 640.63 127.56 -17.01 re f 354.33 640.63 m 354.33 623.62 l S 481.89 640.63 m 481.89 623.62 l S q 0.000 g BT 455.71 627.92 Td (424) Tj ET Q +28.35 623.62 m 28.35 606.61 l S 141.74 623.62 m 141.74 606.61 l S q 0.000 g BT 31.19 610.91 Td (Netherlands) Tj ET Q +141.74 623.62 m 141.74 606.61 l S 240.95 623.62 m 240.95 606.61 l S q 0.000 g BT 144.57 610.91 Td (Amsterdam) Tj ET Q +240.95 623.62 m 240.95 606.61 l S 354.33 623.62 m 354.33 606.61 l S q 0.000 g BT 308.69 610.91 Td (41,526) Tj ET Q +354.33 623.62 m 354.33 606.61 l S 481.89 623.62 m 481.89 606.61 l S q 0.000 g BT 436.25 610.91 Td (15,654) Tj ET Q +28.35 606.61 113.39 -17.01 re f 28.35 606.61 m 28.35 589.60 l S 141.74 606.61 m 141.74 589.60 l S q 0.000 g BT 31.19 593.91 Td (Portugal) Tj ET Q +141.74 606.61 99.21 -17.01 re f 141.74 606.61 m 141.74 589.60 l S 240.95 606.61 m 240.95 589.60 l S q 0.000 g BT 144.57 593.91 Td (Lisbon) Tj ET Q +240.95 606.61 113.39 -17.01 re f 240.95 606.61 m 240.95 589.60 l S 354.33 606.61 m 354.33 589.60 l S q 0.000 g BT 308.69 593.91 Td (91,906) Tj ET Q +354.33 606.61 127.56 -17.01 re f 354.33 606.61 m 354.33 589.60 l S 481.89 606.61 m 481.89 589.60 l S q 0.000 g BT 444.03 593.91 Td (9,957) Tj ET Q +28.35 589.60 m 28.35 572.60 l S 141.74 589.60 m 141.74 572.60 l S q 0.000 g BT 31.19 576.90 Td (Spain) Tj ET Q +141.74 589.60 m 141.74 572.60 l S 240.95 589.60 m 240.95 572.60 l S q 0.000 g BT 144.57 576.90 Td (Madrid) Tj ET Q +240.95 589.60 m 240.95 572.60 l S 354.33 589.60 m 354.33 572.60 l S q 0.000 g BT 300.90 576.90 Td (504,790) Tj ET Q +354.33 589.60 m 354.33 572.60 l S 481.89 589.60 m 481.89 572.60 l S q 0.000 g BT 436.25 576.90 Td (39,348) Tj ET Q +28.35 572.60 113.39 -17.01 re f 28.35 572.60 m 28.35 555.59 l S 141.74 572.60 m 141.74 555.59 l S q 0.000 g BT 31.19 559.89 Td (Sweden) Tj ET Q +141.74 572.60 99.21 -17.01 re f 141.74 572.60 m 141.74 555.59 l S 240.95 572.60 m 240.95 555.59 l S q 0.000 g BT 144.57 559.89 Td (Stockholm) Tj ET Q +240.95 572.60 113.39 -17.01 re f 240.95 572.60 m 240.95 555.59 l S 354.33 572.60 m 354.33 555.59 l S q 0.000 g BT 300.90 559.89 Td (410,934) Tj ET Q +354.33 572.60 127.56 -17.01 re f 354.33 572.60 m 354.33 555.59 l S 481.89 572.60 m 481.89 555.59 l S q 0.000 g BT 444.03 559.89 Td (8,839) Tj ET Q +28.35 555.59 m 28.35 538.58 l S 141.74 555.59 m 141.74 538.58 l S q 0.000 g BT 31.19 542.88 Td (United Kingdom) Tj ET Q +141.74 555.59 m 141.74 538.58 l S 240.95 555.59 m 240.95 538.58 l S q 0.000 g BT 144.57 542.88 Td (London) Tj ET Q +240.95 555.59 m 240.95 538.58 l S 354.33 555.59 m 354.33 538.58 l S q 0.000 g BT 300.90 542.88 Td (243,820) Tj ET Q +354.33 555.59 m 354.33 538.58 l S 481.89 555.59 m 481.89 538.58 l S q 0.000 g BT 436.25 542.88 Td (58,862) Tj ET Q +28.35 538.58 m 481.89 538.58 l S + +endstream +endobj +1 0 obj +<> +endobj +9 0 obj +<> +endobj +10 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F0 9 0 R +/F1 10 0 R +>> +/XObject << +>> +>> +endobj +11 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +12 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 13 +0000000000 65535 f +0000019670 00000 n +0000019967 00000 n +0000000009 00000 n +0000000087 00000 n +0000004536 00000 n +0000004614 00000 n +0000011210 00000 n +0000011288 00000 n +0000019769 00000 n +0000019865 00000 n +0000020082 00000 n +0000020158 00000 n +trailer +<< +/Size 13 +/Root 12 0 R +/Info 11 0 R +>> +startxref +20208 +%%EOF diff --git a/pdf/reference/Fpdf_Circle_figures.pdf b/pdf/reference/Fpdf_Circle_figures.pdf new file mode 100644 index 0000000..a13ba38 --- /dev/null +++ b/pdf/reference/Fpdf_Circle_figures.pdf @@ -0,0 +1,231 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0 12.00 Tf ET +0.000 G +0.784 0.784 0.863 rg +q 0.000 g BT 28.35 799.37 Td (Circles) Tj ET Q +0.784 0.784 0.863 rg +0.57 w +85.04 756.85 m +85.03937 766.74541 79.43527 776.45199 70.86614 781.39938 c +62.29701 786.34677 51.08882 786.34677 42.51969 781.39938 c +33.95055 776.45199 28.34646 766.74541 28.34646 756.85063 c +28.34646 746.95585 33.95055 737.24927 42.51969 732.30188 c +51.08882 727.35449 62.29701 727.35449 70.86614 732.30188 c +79.43527 737.24927 85.03937 746.95585 85.03937 756.85063 c +S +155.91 756.85 m +155.90551 766.74541 150.30141 776.45199 141.73228 781.39938 c +133.16315 786.34677 121.95496 786.34677 113.38583 781.39938 c +104.81670 776.45199 99.21260 766.74541 99.21260 756.85063 c +99.21260 746.95585 104.81670 737.24927 113.38583 732.30188 c +121.95496 727.35449 133.16315 727.35449 141.73228 732.30188 c +150.30141 737.24927 155.90551 746.95585 155.90551 756.85063 c +f +226.77 756.85 m +226.77165 766.74541 221.16756 776.45199 212.59843 781.39938 c +204.02929 786.34677 192.82110 786.34677 184.25197 781.39938 c +175.68284 776.45199 170.07874 766.74541 170.07874 756.85063 c +170.07874 746.95585 175.68284 737.24927 184.25197 732.30188 c +192.82110 727.35449 204.02929 727.35449 212.59843 732.30188 c +221.16756 737.24927 226.77165 746.95585 226.77165 756.85063 c +B +8.50 w +297.64 756.85 m +297.63780 766.74541 292.03370 776.45199 283.46457 781.39938 c +274.89544 786.34677 263.68724 786.34677 255.11811 781.39938 c +246.54898 776.45199 240.94488 766.74541 240.94488 756.85063 c +240.94488 746.95585 246.54898 737.24927 255.11811 732.30188 c +263.68724 727.35449 274.89544 727.35449 283.46457 732.30188 c +292.03370 737.24927 297.63780 746.95585 297.63780 756.85063 c +B +0.57 w +q 0.000 g BT 28.35 685.98 Td (Ellipses) Tj ET Q +0.863 0.784 0.784 rg +141.73 643.46 m +141.73228 653.35958 130.52409 663.06616 113.38583 668.01355 c +96.24757 672.96094 73.83118 672.96094 56.69291 668.01355 c +39.55465 663.06616 28.34646 653.35958 28.34646 643.46480 c +28.34646 633.57002 39.55465 623.86344 56.69291 618.91605 c +73.83118 613.96866 96.24757 613.96866 113.38583 618.91605 c +130.52409 623.86344 141.73228 633.57002 141.73228 643.46480 c +S +269.29 643.46 m +269.29134 653.35958 258.08314 663.06616 240.94488 668.01355 c +223.80662 672.96094 201.39023 672.96094 184.25197 668.01355 c +167.11371 663.06616 155.90551 653.35958 155.90551 643.46480 c +155.90551 633.57002 167.11371 623.86344 184.25197 618.91605 c +201.39023 613.96866 223.80662 613.96866 240.94488 618.91605 c +258.08314 623.86344 269.29134 633.57002 269.29134 643.46480 c +f +396.85 643.46 m +396.85039 653.35958 385.64220 663.06616 368.50394 668.01355 c +351.36568 672.96094 328.94929 672.96094 311.81102 668.01355 c +294.67276 663.06616 283.46457 653.35958 283.46457 643.46480 c +283.46457 633.57002 294.67276 623.86344 311.81102 618.91605 c +328.94929 613.96866 351.36568 613.96866 368.50394 618.91605 c +385.64220 623.86344 396.85039 633.57002 396.85039 643.46480 c +B +8.50 w +524.41 643.46 m +524.40945 653.35958 513.20125 663.06616 496.06299 668.01355 c +478.92473 672.96094 456.50834 672.96094 439.37008 668.01355 c +422.23182 663.06616 411.02362 653.35958 411.02362 643.46480 c +411.02362 633.57002 422.23182 623.86344 439.37008 618.91605 c +456.50834 613.96866 478.92473 613.96866 496.06299 618.91605 c +513.20125 623.86344 524.40945 633.57002 524.40945 643.46480 c +B +0.57 w +q 0.000 g BT 28.35 572.60 Td (Curves \(quadratic\)) Tj ET Q +0.863 0.863 0.784 rg +28.35 487.56 m +42.51969 629.29157 113.38583 487.55929 v S +127.56 487.56 m +141.73228 629.29157 212.59843 487.55929 v f +226.77 487.56 m +240.94488 629.29157 311.81102 487.55929 v B +8.50 w +325.98 487.56 m +340.15748 629.29157 411.02362 487.55929 v B +1 J +425.20 487.56 m +439.37008 629.29157 510.23622 487.55929 v B +0.57 w +0 J +q 0.000 g BT 28.35 459.21 Td (Curves \(cubic\)) Tj ET Q +0.863 0.784 0.863 rg +28.35 374.17 m +42.51969 515.90575 28.34646 374.17346 113.38583 374.17346 c S +127.56 374.17 m +141.73228 515.90575 127.55906 374.17346 212.59843 374.17346 c f +226.77 374.17 m +240.94488 515.90575 226.77165 374.17346 311.81102 374.17346 c B +8.50 w +325.98 374.17 m +340.15748 515.90575 325.98425 374.17346 411.02362 374.17346 c B +1 J +425.20 374.17 m +439.37008 515.90575 425.19685 374.17346 510.23622 374.17346 c B +0.57 w +0 J +q 0.000 g BT 28.35 345.83 Td (Arcs) Tj ET Q +0.784 0.863 0.863 rg +8.50 w +184.25 246.61 m +184.25197 256.50919 173.04377 266.21577 155.90551 271.16316 c +138.76725 276.11055 116.35086 276.11055 99.21260 271.16316 c +82.07434 266.21577 70.86614 256.50919 70.86614 246.61441 c +B +0.57 w +127.56 289.13 m +102.82211 289.13409 78.55565 280.72795 66.18718 267.87425 c +53.81870 255.02056 53.81870 238.20826 66.18718 225.35457 c +78.55565 212.50087 102.82211 204.09472 127.55906 204.09472 c +S +8.50 w +212.60 246.61 m +212.59843 266.40397 195.78613 285.81713 170.07874 295.71191 c +144.37135 305.60669 110.74676 305.60669 85.03937 295.71191 c +59.33198 285.81713 42.51969 266.40397 42.51969 246.61441 c +42.51969 226.82485 59.33198 207.41169 85.03937 197.51691 c +110.74676 187.62213 144.37135 187.62213 170.07874 197.51691 c +195.78613 207.41169 212.59843 226.82485 212.59843 246.61441 c +S +1 J +q -0.70711 0.70711 -0.70711 -0.70711 382.67717 246.61441 cm +56.69 0.00 m +56.69291 9.89478 45.48472 19.60136 28.34646 24.54875 c +11.20819 29.49614 -11.20819 29.49614 -28.34646 24.54875 c +-45.48472 19.60136 -56.69291 9.89478 -56.69291 0.00000 c +B +Q +0.57 w +q -0.70711 0.70711 -0.70711 -0.70711 382.67717 246.61441 cm +0.00 42.52 m +-24.73695 42.51969 -49.00340 34.11354 -61.37188 21.25984 c +-73.74035 8.40615 -73.74035 -8.40615 -61.37188 -21.25984 c +-49.00340 -34.11354 -24.73695 -42.51969 -0.00000 -42.51969 c +S +Q +8.50 w +q -0.70711 0.70711 -0.70711 -0.70711 382.67717 246.61441 cm +85.04 0.00 m +85.03937 19.78956 68.22708 39.20272 42.51969 49.09750 c +16.81229 58.99228 -16.81229 58.99228 -42.51969 49.09750 c +-68.22708 39.20272 -85.03937 19.78956 -85.03937 0.00000 c +-85.03937 -19.78956 -68.22708 -39.20272 -42.51969 -49.09750 c +-16.81229 -58.99228 16.81229 -58.99228 42.51969 -49.09750 c +68.22708 -39.20272 85.03937 -19.78956 85.03937 0.00000 c +S +Q +0.57 w +0 J + +endstream +endobj +1 0 obj +<> +endobj +5 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F0 5 0 R +>> +/XObject << +>> +>> +endobj +6 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +7 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 8 +0000000000 65535 f +0000006183 00000 n +0000006366 00000 n +0000000009 00000 n +0000000087 00000 n +0000006270 00000 n +0000006470 00000 n +0000006545 00000 n +trailer +<< +/Size 8 +/Root 7 0 R +/Info 6 0 R +>> +startxref +6594 +%%EOF diff --git a/pdf/reference/Fpdf_ClipText.pdf b/pdf/reference/Fpdf_ClipText.pdf new file mode 100644 index 0000000..2b1ed00 Binary files /dev/null and b/pdf/reference/Fpdf_ClipText.pdf differ diff --git a/pdf/reference/Fpdf_ClippedTableCells.pdf b/pdf/reference/Fpdf_ClippedTableCells.pdf new file mode 100644 index 0000000..69a84c3 --- /dev/null +++ b/pdf/reference/Fpdf_ClippedTableCells.pdf @@ -0,0 +1,694 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0 12.00 Tf ET +0.000 G +0.000 g +28.35 813.54 170.08 -17.67 re S +q 28.35 813.54 170.08 -17.67 re W n +BT 31.19 801.11 Td (1:A) Tj ET +Q +198.43 813.54 283.46 -17.67 re S +q 198.43 813.54 283.46 -17.67 re W n +BT 201.26 801.11 Td (1:A) Tj ET +Q +481.89 813.54 85.04 -17.67 re S +q 481.89 813.54 85.04 -17.67 re W n +BT 484.73 801.11 Td (1:A) Tj ET +Q +28.35 795.87 170.08 -17.67 re S +q 28.35 795.87 170.08 -17.67 re W n +BT 31.19 783.44 Td (2:AA) Tj ET +Q +198.43 795.87 283.46 -17.67 re S +q 198.43 795.87 283.46 -17.67 re W n +BT 201.26 783.44 Td (2:AA) Tj ET +Q +481.89 795.87 85.04 -17.67 re S +q 481.89 795.87 85.04 -17.67 re W n +BT 484.73 783.44 Td (2:AA) Tj ET +Q +28.35 778.20 170.08 -17.67 re S +q 28.35 778.20 170.08 -17.67 re W n +BT 31.19 765.77 Td (3:AAA) Tj ET +Q +198.43 778.20 283.46 -17.67 re S +q 198.43 778.20 283.46 -17.67 re W n +BT 201.26 765.77 Td (3:AAA) Tj ET +Q +481.89 778.20 85.04 -17.67 re S +q 481.89 778.20 85.04 -17.67 re W n +BT 484.73 765.77 Td (3:AAA) Tj ET +Q +28.35 760.53 170.08 -17.67 re S +q 28.35 760.53 170.08 -17.67 re W n +BT 31.19 748.10 Td (4:AAAA) Tj ET +Q +198.43 760.53 283.46 -17.67 re S +q 198.43 760.53 283.46 -17.67 re W n +BT 201.26 748.10 Td (4:AAAA) Tj ET +Q +481.89 760.53 85.04 -17.67 re S +q 481.89 760.53 85.04 -17.67 re W n +BT 484.73 748.10 Td (4:AAAA) Tj ET +Q +28.35 742.86 170.08 -17.67 re S +q 28.35 742.86 170.08 -17.67 re W n +BT 31.19 730.43 Td (5:AAAAA) Tj ET +Q +198.43 742.86 283.46 -17.67 re S +q 198.43 742.86 283.46 -17.67 re W n +BT 201.26 730.43 Td (5:AAAAA) Tj ET +Q +481.89 742.86 85.04 -17.67 re S +q 481.89 742.86 85.04 -17.67 re W n +BT 484.73 730.43 Td (5:AAAAA) Tj ET +Q +28.35 725.19 170.08 -17.67 re S +q 28.35 725.19 170.08 -17.67 re W n +BT 31.19 712.76 Td (6:AAAAAA) Tj ET +Q +198.43 725.19 283.46 -17.67 re S +q 198.43 725.19 283.46 -17.67 re W n +BT 201.26 712.76 Td (6:AAAAAA) Tj ET +Q +481.89 725.19 85.04 -17.67 re S +q 481.89 725.19 85.04 -17.67 re W n +BT 484.73 712.76 Td (6:AAAAAA) Tj ET +Q +28.35 707.52 170.08 -17.67 re S +q 28.35 707.52 170.08 -17.67 re W n +BT 31.19 695.09 Td (7:AAAAAAA) Tj ET +Q +198.43 707.52 283.46 -17.67 re S +q 198.43 707.52 283.46 -17.67 re W n +BT 201.26 695.09 Td (7:AAAAAAA) Tj ET +Q +481.89 707.52 85.04 -17.67 re S +q 481.89 707.52 85.04 -17.67 re W n +BT 484.73 695.09 Td (7:AAAAAAA) Tj ET +Q +28.35 689.85 170.08 -17.67 re S +q 28.35 689.85 170.08 -17.67 re W n +BT 31.19 677.42 Td (8:AAAAAAAA) Tj ET +Q +198.43 689.85 283.46 -17.67 re S +q 198.43 689.85 283.46 -17.67 re W n +BT 201.26 677.42 Td (8:AAAAAAAA) Tj ET +Q +481.89 689.85 85.04 -17.67 re S +q 481.89 689.85 85.04 -17.67 re W n +BT 484.73 677.42 Td (8:AAAAAAAA) Tj ET +Q +28.35 672.19 170.08 -17.67 re S +q 28.35 672.19 170.08 -17.67 re W n +BT 31.19 659.75 Td (9:AAAAAAAAA) Tj ET +Q +198.43 672.19 283.46 -17.67 re S +q 198.43 672.19 283.46 -17.67 re W n +BT 201.26 659.75 Td (9:AAAAAAAAA) Tj ET +Q +481.89 672.19 85.04 -17.67 re S +q 481.89 672.19 85.04 -17.67 re W n +BT 484.73 659.75 Td (9:AAAAAAAAA) Tj ET +Q +28.35 654.52 170.08 -17.67 re S +q 28.35 654.52 170.08 -17.67 re W n +BT 31.19 642.08 Td (10:AAAAAAAAAA) Tj ET +Q +198.43 654.52 283.46 -17.67 re S +q 198.43 654.52 283.46 -17.67 re W n +BT 201.26 642.08 Td (10:AAAAAAAAAA) Tj ET +Q +481.89 654.52 85.04 -17.67 re S +q 481.89 654.52 85.04 -17.67 re W n +BT 484.73 642.08 Td (10:AAAAAAAAAA) Tj ET +Q +28.35 636.85 170.08 -17.67 re S +q 28.35 636.85 170.08 -17.67 re W n +BT 31.19 624.41 Td (11:AAAAAAAAAAA) Tj ET +Q +198.43 636.85 283.46 -17.67 re S +q 198.43 636.85 283.46 -17.67 re W n +BT 201.26 624.41 Td (11:AAAAAAAAAAA) Tj ET +Q +481.89 636.85 85.04 -17.67 re S +q 481.89 636.85 85.04 -17.67 re W n +BT 484.73 624.41 Td (11:AAAAAAAAAAA) Tj ET +Q +28.35 619.18 170.08 -17.67 re S +q 28.35 619.18 170.08 -17.67 re W n +BT 31.19 606.74 Td (12:AAAAAAAAAAAA) Tj ET +Q +198.43 619.18 283.46 -17.67 re S +q 198.43 619.18 283.46 -17.67 re W n +BT 201.26 606.74 Td (12:AAAAAAAAAAAA) Tj ET +Q +481.89 619.18 85.04 -17.67 re S +q 481.89 619.18 85.04 -17.67 re W n +BT 484.73 606.74 Td (12:AAAAAAAAAAAA) Tj ET +Q +28.35 601.51 170.08 -17.67 re S +q 28.35 601.51 170.08 -17.67 re W n +BT 31.19 589.07 Td (13:AAAAAAAAAAAAA) Tj ET +Q +198.43 601.51 283.46 -17.67 re S +q 198.43 601.51 283.46 -17.67 re W n +BT 201.26 589.07 Td (13:AAAAAAAAAAAAA) Tj ET +Q +481.89 601.51 85.04 -17.67 re S +q 481.89 601.51 85.04 -17.67 re W n +BT 484.73 589.07 Td (13:AAAAAAAAAAAAA) Tj ET +Q +28.35 583.84 170.08 -17.67 re S +q 28.35 583.84 170.08 -17.67 re W n +BT 31.19 571.40 Td (14:AAAAAAAAAAAAAA) Tj ET +Q +198.43 583.84 283.46 -17.67 re S +q 198.43 583.84 283.46 -17.67 re W n +BT 201.26 571.40 Td (14:AAAAAAAAAAAAAA) Tj ET +Q +481.89 583.84 85.04 -17.67 re S +q 481.89 583.84 85.04 -17.67 re W n +BT 484.73 571.40 Td (14:AAAAAAAAAAAAAA) Tj ET +Q +28.35 566.17 170.08 -17.67 re S +q 28.35 566.17 170.08 -17.67 re W n +BT 31.19 553.74 Td (15:AAAAAAAAAAAAAAA) Tj ET +Q +198.43 566.17 283.46 -17.67 re S +q 198.43 566.17 283.46 -17.67 re W n +BT 201.26 553.74 Td (15:AAAAAAAAAAAAAAA) Tj ET +Q +481.89 566.17 85.04 -17.67 re S +q 481.89 566.17 85.04 -17.67 re W n +BT 484.73 553.74 Td (15:AAAAAAAAAAAAAAA) Tj ET +Q +28.35 548.50 170.08 -17.67 re S +q 28.35 548.50 170.08 -17.67 re W n +BT 31.19 536.07 Td (16:AAAAAAAAAAAAAAAA) Tj ET +Q +198.43 548.50 283.46 -17.67 re S +q 198.43 548.50 283.46 -17.67 re W n +BT 201.26 536.07 Td (16:AAAAAAAAAAAAAAAA) Tj ET +Q +481.89 548.50 85.04 -17.67 re S +q 481.89 548.50 85.04 -17.67 re W n +BT 484.73 536.07 Td (16:AAAAAAAAAAAAAAAA) Tj ET +Q +28.35 530.83 170.08 -17.67 re S +q 28.35 530.83 170.08 -17.67 re W n +BT 31.19 518.40 Td (17:AAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 530.83 283.46 -17.67 re S +q 198.43 530.83 283.46 -17.67 re W n +BT 201.26 518.40 Td (17:AAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 530.83 85.04 -17.67 re S +q 481.89 530.83 85.04 -17.67 re W n +BT 484.73 518.40 Td (17:AAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 513.16 170.08 -17.67 re S +q 28.35 513.16 170.08 -17.67 re W n +BT 31.19 500.73 Td (18:AAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 513.16 283.46 -17.67 re S +q 198.43 513.16 283.46 -17.67 re W n +BT 201.26 500.73 Td (18:AAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 513.16 85.04 -17.67 re S +q 481.89 513.16 85.04 -17.67 re W n +BT 484.73 500.73 Td (18:AAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 495.49 170.08 -17.67 re S +q 28.35 495.49 170.08 -17.67 re W n +BT 31.19 483.06 Td (19:AAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 495.49 283.46 -17.67 re S +q 198.43 495.49 283.46 -17.67 re W n +BT 201.26 483.06 Td (19:AAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 495.49 85.04 -17.67 re S +q 481.89 495.49 85.04 -17.67 re W n +BT 484.73 483.06 Td (19:AAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 477.82 170.08 -17.67 re S +q 28.35 477.82 170.08 -17.67 re W n +BT 31.19 465.39 Td (20:AAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 477.82 283.46 -17.67 re S +q 198.43 477.82 283.46 -17.67 re W n +BT 201.26 465.39 Td (20:AAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 477.82 85.04 -17.67 re S +q 481.89 477.82 85.04 -17.67 re W n +BT 484.73 465.39 Td (20:AAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 460.15 170.08 -17.67 re S +q 28.35 460.15 170.08 -17.67 re W n +BT 31.19 447.72 Td (21:AAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 460.15 283.46 -17.67 re S +q 198.43 460.15 283.46 -17.67 re W n +BT 201.26 447.72 Td (21:AAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 460.15 85.04 -17.67 re S +q 481.89 460.15 85.04 -17.67 re W n +BT 484.73 447.72 Td (21:AAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 442.48 170.08 -17.67 re S +q 28.35 442.48 170.08 -17.67 re W n +BT 31.19 430.05 Td (22:AAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 442.48 283.46 -17.67 re S +q 198.43 442.48 283.46 -17.67 re W n +BT 201.26 430.05 Td (22:AAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 442.48 85.04 -17.67 re S +q 481.89 442.48 85.04 -17.67 re W n +BT 484.73 430.05 Td (22:AAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 424.82 170.08 -17.67 re S +q 28.35 424.82 170.08 -17.67 re W n +BT 31.19 412.38 Td (23:AAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 424.82 283.46 -17.67 re S +q 198.43 424.82 283.46 -17.67 re W n +BT 201.26 412.38 Td (23:AAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 424.82 85.04 -17.67 re S +q 481.89 424.82 85.04 -17.67 re W n +BT 484.73 412.38 Td (23:AAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 407.15 170.08 -17.67 re S +q 28.35 407.15 170.08 -17.67 re W n +BT 31.19 394.71 Td (24:AAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 407.15 283.46 -17.67 re S +q 198.43 407.15 283.46 -17.67 re W n +BT 201.26 394.71 Td (24:AAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 407.15 85.04 -17.67 re S +q 481.89 407.15 85.04 -17.67 re W n +BT 484.73 394.71 Td (24:AAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 389.48 170.08 -17.67 re S +q 28.35 389.48 170.08 -17.67 re W n +BT 31.19 377.04 Td (25:AAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 389.48 283.46 -17.67 re S +q 198.43 389.48 283.46 -17.67 re W n +BT 201.26 377.04 Td (25:AAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 389.48 85.04 -17.67 re S +q 481.89 389.48 85.04 -17.67 re W n +BT 484.73 377.04 Td (25:AAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 371.81 170.08 -17.67 re S +q 28.35 371.81 170.08 -17.67 re W n +BT 31.19 359.37 Td (26:AAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 371.81 283.46 -17.67 re S +q 198.43 371.81 283.46 -17.67 re W n +BT 201.26 359.37 Td (26:AAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 371.81 85.04 -17.67 re S +q 481.89 371.81 85.04 -17.67 re W n +BT 484.73 359.37 Td (26:AAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 354.14 170.08 -17.67 re S +q 28.35 354.14 170.08 -17.67 re W n +BT 31.19 341.70 Td (27:AAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 354.14 283.46 -17.67 re S +q 198.43 354.14 283.46 -17.67 re W n +BT 201.26 341.70 Td (27:AAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 354.14 85.04 -17.67 re S +q 481.89 354.14 85.04 -17.67 re W n +BT 484.73 341.70 Td (27:AAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 336.47 170.08 -17.67 re S +q 28.35 336.47 170.08 -17.67 re W n +BT 31.19 324.03 Td (28:AAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 336.47 283.46 -17.67 re S +q 198.43 336.47 283.46 -17.67 re W n +BT 201.26 324.03 Td (28:AAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 336.47 85.04 -17.67 re S +q 481.89 336.47 85.04 -17.67 re W n +BT 484.73 324.03 Td (28:AAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 318.80 170.08 -17.67 re S +q 28.35 318.80 170.08 -17.67 re W n +BT 31.19 306.37 Td (29:AAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 318.80 283.46 -17.67 re S +q 198.43 318.80 283.46 -17.67 re W n +BT 201.26 306.37 Td (29:AAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 318.80 85.04 -17.67 re S +q 481.89 318.80 85.04 -17.67 re W n +BT 484.73 306.37 Td (29:AAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 301.13 170.08 -17.67 re S +q 28.35 301.13 170.08 -17.67 re W n +BT 31.19 288.70 Td (30:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 301.13 283.46 -17.67 re S +q 198.43 301.13 283.46 -17.67 re W n +BT 201.26 288.70 Td (30:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 301.13 85.04 -17.67 re S +q 481.89 301.13 85.04 -17.67 re W n +BT 484.73 288.70 Td (30:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 283.46 170.08 -17.67 re S +q 28.35 283.46 170.08 -17.67 re W n +BT 31.19 271.03 Td (31:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 283.46 283.46 -17.67 re S +q 198.43 283.46 283.46 -17.67 re W n +BT 201.26 271.03 Td (31:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 283.46 85.04 -17.67 re S +q 481.89 283.46 85.04 -17.67 re W n +BT 484.73 271.03 Td (31:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 265.79 170.08 -17.67 re S +q 28.35 265.79 170.08 -17.67 re W n +BT 31.19 253.36 Td (32:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 265.79 283.46 -17.67 re S +q 198.43 265.79 283.46 -17.67 re W n +BT 201.26 253.36 Td (32:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 265.79 85.04 -17.67 re S +q 481.89 265.79 85.04 -17.67 re W n +BT 484.73 253.36 Td (32:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 248.12 170.08 -17.67 re S +q 28.35 248.12 170.08 -17.67 re W n +BT 31.19 235.69 Td (33:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 248.12 283.46 -17.67 re S +q 198.43 248.12 283.46 -17.67 re W n +BT 201.26 235.69 Td (33:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 248.12 85.04 -17.67 re S +q 481.89 248.12 85.04 -17.67 re W n +BT 484.73 235.69 Td (33:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 230.45 170.08 -17.67 re S +q 28.35 230.45 170.08 -17.67 re W n +BT 31.19 218.02 Td (34:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 230.45 283.46 -17.67 re S +q 198.43 230.45 283.46 -17.67 re W n +BT 201.26 218.02 Td (34:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 230.45 85.04 -17.67 re S +q 481.89 230.45 85.04 -17.67 re W n +BT 484.73 218.02 Td (34:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 212.78 170.08 -17.67 re S +q 28.35 212.78 170.08 -17.67 re W n +BT 31.19 200.35 Td (35:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 212.78 283.46 -17.67 re S +q 198.43 212.78 283.46 -17.67 re W n +BT 201.26 200.35 Td (35:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 212.78 85.04 -17.67 re S +q 481.89 212.78 85.04 -17.67 re W n +BT 484.73 200.35 Td (35:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 195.11 170.08 -17.67 re S +q 28.35 195.11 170.08 -17.67 re W n +BT 31.19 182.68 Td (36:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 195.11 283.46 -17.67 re S +q 198.43 195.11 283.46 -17.67 re W n +BT 201.26 182.68 Td (36:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 195.11 85.04 -17.67 re S +q 481.89 195.11 85.04 -17.67 re W n +BT 484.73 182.68 Td (36:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 177.45 170.08 -17.67 re S +q 28.35 177.45 170.08 -17.67 re W n +BT 31.19 165.01 Td (37:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 177.45 283.46 -17.67 re S +q 198.43 177.45 283.46 -17.67 re W n +BT 201.26 165.01 Td (37:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 177.45 85.04 -17.67 re S +q 481.89 177.45 85.04 -17.67 re W n +BT 484.73 165.01 Td (37:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 159.78 170.08 -17.67 re S +q 28.35 159.78 170.08 -17.67 re W n +BT 31.19 147.34 Td (38:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 159.78 283.46 -17.67 re S +q 198.43 159.78 283.46 -17.67 re W n +BT 201.26 147.34 Td (38:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 159.78 85.04 -17.67 re S +q 481.89 159.78 85.04 -17.67 re W n +BT 484.73 147.34 Td (38:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 142.11 170.08 -17.67 re S +q 28.35 142.11 170.08 -17.67 re W n +BT 31.19 129.67 Td (39:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 142.11 283.46 -17.67 re S +q 198.43 142.11 283.46 -17.67 re W n +BT 201.26 129.67 Td (39:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 142.11 85.04 -17.67 re S +q 481.89 142.11 85.04 -17.67 re W n +BT 484.73 129.67 Td (39:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 124.44 170.08 -17.67 re S +q 28.35 124.44 170.08 -17.67 re W n +BT 31.19 112.00 Td (40:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 124.44 283.46 -17.67 re S +q 198.43 124.44 283.46 -17.67 re W n +BT 201.26 112.00 Td (40:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 124.44 85.04 -17.67 re S +q 481.89 124.44 85.04 -17.67 re W n +BT 484.73 112.00 Td (40:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 106.77 170.08 -17.67 re S +q 28.35 106.77 170.08 -17.67 re W n +BT 31.19 94.33 Td (41:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 106.77 283.46 -17.67 re S +q 198.43 106.77 283.46 -17.67 re W n +BT 201.26 94.33 Td (41:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 106.77 85.04 -17.67 re S +q 481.89 106.77 85.04 -17.67 re W n +BT 484.73 94.33 Td (41:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 89.10 170.08 -17.67 re S +q 28.35 89.10 170.08 -17.67 re W n +BT 31.19 76.66 Td (42:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 89.10 283.46 -17.67 re S +q 198.43 89.10 283.46 -17.67 re W n +BT 201.26 76.66 Td (42:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 89.10 85.04 -17.67 re S +q 481.89 89.10 85.04 -17.67 re W n +BT 484.73 76.66 Td (42:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q + +endstream +endobj +5 0 obj +<> +endobj +6 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0 12.00 Tf ET +0.000 G +0.000 g +28.35 813.54 170.08 -17.67 re S +q 28.35 813.54 170.08 -17.67 re W n +BT 31.19 801.11 Td (43:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 813.54 283.46 -17.67 re S +q 198.43 813.54 283.46 -17.67 re W n +BT 201.26 801.11 Td (43:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 813.54 85.04 -17.67 re S +q 481.89 813.54 85.04 -17.67 re W n +BT 484.73 801.11 Td (43:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 795.87 170.08 -17.67 re S +q 28.35 795.87 170.08 -17.67 re W n +BT 31.19 783.44 Td (44:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 795.87 283.46 -17.67 re S +q 198.43 795.87 283.46 -17.67 re W n +BT 201.26 783.44 Td (44:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 795.87 85.04 -17.67 re S +q 481.89 795.87 85.04 -17.67 re W n +BT 484.73 783.44 Td (44:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 778.20 170.08 -17.67 re S +q 28.35 778.20 170.08 -17.67 re W n +BT 31.19 765.77 Td (45:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 778.20 283.46 -17.67 re S +q 198.43 778.20 283.46 -17.67 re W n +BT 201.26 765.77 Td (45:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 778.20 85.04 -17.67 re S +q 481.89 778.20 85.04 -17.67 re W n +BT 484.73 765.77 Td (45:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 760.53 170.08 -17.67 re S +q 28.35 760.53 170.08 -17.67 re W n +BT 31.19 748.10 Td (46:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 760.53 283.46 -17.67 re S +q 198.43 760.53 283.46 -17.67 re W n +BT 201.26 748.10 Td (46:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 760.53 85.04 -17.67 re S +q 481.89 760.53 85.04 -17.67 re W n +BT 484.73 748.10 Td (46:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 742.86 170.08 -17.67 re S +q 28.35 742.86 170.08 -17.67 re W n +BT 31.19 730.43 Td (47:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 742.86 283.46 -17.67 re S +q 198.43 742.86 283.46 -17.67 re W n +BT 201.26 730.43 Td (47:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 742.86 85.04 -17.67 re S +q 481.89 742.86 85.04 -17.67 re W n +BT 484.73 730.43 Td (47:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 725.19 170.08 -17.67 re S +q 28.35 725.19 170.08 -17.67 re W n +BT 31.19 712.76 Td (48:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 725.19 283.46 -17.67 re S +q 198.43 725.19 283.46 -17.67 re W n +BT 201.26 712.76 Td (48:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 725.19 85.04 -17.67 re S +q 481.89 725.19 85.04 -17.67 re W n +BT 484.73 712.76 Td (48:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 707.52 170.08 -17.67 re S +q 28.35 707.52 170.08 -17.67 re W n +BT 31.19 695.09 Td (49:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 707.52 283.46 -17.67 re S +q 198.43 707.52 283.46 -17.67 re W n +BT 201.26 695.09 Td (49:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 707.52 85.04 -17.67 re S +q 481.89 707.52 85.04 -17.67 re W n +BT 484.73 695.09 Td (49:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +28.35 689.85 170.08 -17.67 re S +q 28.35 689.85 170.08 -17.67 re W n +BT 31.19 677.42 Td (50:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +198.43 689.85 283.46 -17.67 re S +q 198.43 689.85 283.46 -17.67 re W n +BT 201.26 677.42 Td (50:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q +481.89 689.85 85.04 -17.67 re S +q 481.89 689.85 85.04 -17.67 re W n +BT 484.73 677.42 Td (50:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +Q + +endstream +endobj +1 0 obj +<> +endobj +7 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F0 7 0 R +>> +/XObject << +>> +>> +endobj +8 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +9 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 10 +0000000000 65535 f +0000019502 00000 n +0000019691 00000 n +0000000009 00000 n +0000000087 00000 n +0000015752 00000 n +0000015830 00000 n +0000019595 00000 n +0000019795 00000 n +0000019870 00000 n +trailer +<< +/Size 10 +/Root 9 0 R +/Info 8 0 R +>> +startxref +19919 +%%EOF diff --git a/pdf/reference/Fpdf_CreateTemplate.pdf b/pdf/reference/Fpdf_CreateTemplate.pdf new file mode 100644 index 0000000..bc0d34c Binary files /dev/null and b/pdf/reference/Fpdf_CreateTemplate.pdf differ diff --git a/pdf/reference/Fpdf_DrawPath_fill.pdf b/pdf/reference/Fpdf_DrawPath_fill.pdf new file mode 100644 index 0000000..488d72d --- /dev/null +++ b/pdf/reference/Fpdf_DrawPath_fill.pdf @@ -0,0 +1,277 @@ +%PDF-1.4 +3 0 obj +<> +/Contents 4 0 R>> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0 15.00 Tf ET +1.000 0.000 0.000 RG +0.600 g +/GS1 gs +269.29 714.33 m +q 0.000 g BT 269.29 714.33 Td (0) Tj ET Q +99.21 616.14 l +q 0.000 g BT 99.21 616.14 Td (1) Tj ET Q +99.21 812.53 l +q 0.000 g BT 99.21 812.53 Td (2) Tj ET Q +h +240.94 714.33 m +q 0.000 g BT 240.94 714.33 Td (0) Tj ET Q +113.39 640.68 l +q 0.000 g BT 113.39 640.68 Td (1) Tj ET Q +113.39 787.98 l +q 0.000 g BT 113.39 787.98 Td (2) Tj ET Q +h +212.60 714.33 m +q 0.000 g BT 212.60 714.33 Td (0) Tj ET Q +127.56 665.23 l +q 0.000 g BT 127.56 665.23 Td (1) Tj ET Q +127.56 763.43 l +q 0.000 g BT 127.56 763.43 Td (2) Tj ET Q +h +184.25 714.33 m +q 0.000 g BT 184.25 714.33 Td (0) Tj ET Q +141.73 689.78 l +q 0.000 g BT 141.73 689.78 Td (1) Tj ET Q +141.73 738.88 l +q 0.000 g BT 141.73 738.88 Td (2) Tj ET Q +h +B +q 0.000 g BT 42.52 572.60 Td (B \(same direction, non zero winding\)) Tj ET Q +552.76 714.33 m +q 0.000 g BT 552.76 714.33 Td (0) Tj ET Q +439.37 600.95 l +q 0.000 g BT 439.37 600.95 Td (1) Tj ET Q +325.98 714.33 l +q 0.000 g BT 325.98 714.33 Td (2) Tj ET Q +439.37 827.72 l +q 0.000 g BT 439.37 827.72 Td (3) Tj ET Q +h +524.41 714.33 m +q 0.000 g BT 524.41 714.33 Td (0) Tj ET Q +439.37 629.29 l +q 0.000 g BT 439.37 629.29 Td (1) Tj ET Q +354.33 714.33 l +q 0.000 g BT 354.33 714.33 Td (2) Tj ET Q +439.37 799.37 l +q 0.000 g BT 439.37 799.37 Td (3) Tj ET Q +h +496.06 714.33 m +q 0.000 g BT 496.06 714.33 Td (0) Tj ET Q +439.37 657.64 l +q 0.000 g BT 439.37 657.64 Td (1) Tj ET Q +382.68 714.33 l +q 0.000 g BT 382.68 714.33 Td (2) Tj ET Q +439.37 771.02 l +q 0.000 g BT 439.37 771.02 Td (3) Tj ET Q +h +467.72 714.33 m +q 0.000 g BT 467.72 714.33 Td (0) Tj ET Q +439.37 685.98 l +q 0.000 g BT 439.37 685.98 Td (1) Tj ET Q +411.02 714.33 l +q 0.000 g BT 411.02 714.33 Td (2) Tj ET Q +439.37 742.68 l +q 0.000 g BT 439.37 742.68 Td (3) Tj ET Q +h +B* +q 0.000 g BT 325.98 572.60 Td (B* \(same direction, even odd\)) Tj ET Q +269.29 430.87 m +q 0.000 g BT 269.29 430.87 Td (0) Tj ET Q +190.94 323.03 l +q 0.000 g BT 190.94 323.03 Td (1) Tj ET Q +64.17 364.22 l +q 0.000 g BT 64.17 364.22 Td (2) Tj ET Q +64.17 497.51 l +q 0.000 g BT 64.17 497.51 Td (3) Tj ET Q +190.94 538.70 l +q 0.000 g BT 190.94 538.70 Td (4) Tj ET Q +h +240.94 430.87 m +q 0.000 g BT 240.94 430.87 Td (0) Tj ET Q +182.18 511.74 l +q 0.000 g BT 182.18 511.74 Td (1) Tj ET Q +87.11 480.85 l +q 0.000 g BT 87.11 480.85 Td (2) Tj ET Q +87.11 380.88 l +q 0.000 g BT 87.11 380.88 Td (3) Tj ET Q +182.18 349.99 l +q 0.000 g BT 182.18 349.99 Td (4) Tj ET Q +h +212.60 430.87 m +q 0.000 g BT 212.60 430.87 Td (0) Tj ET Q +173.42 376.95 l +q 0.000 g BT 173.42 376.95 Td (1) Tj ET Q +110.04 397.54 l +q 0.000 g BT 110.04 397.54 Td (2) Tj ET Q +110.04 464.19 l +q 0.000 g BT 110.04 464.19 Td (3) Tj ET Q +173.42 484.78 l +q 0.000 g BT 173.42 484.78 Td (4) Tj ET Q +h +184.25 430.87 m +q 0.000 g BT 184.25 430.87 Td (0) Tj ET Q +164.67 457.83 l +q 0.000 g BT 164.67 457.83 Td (1) Tj ET Q +132.97 447.53 l +q 0.000 g BT 132.97 447.53 Td (2) Tj ET Q +132.97 414.20 l +q 0.000 g BT 132.97 414.20 Td (3) Tj ET Q +164.67 403.91 l +q 0.000 g BT 164.67 403.91 Td (4) Tj ET Q +h +B +q 0.000 g BT 42.52 289.13 Td (B \(different direction, non zero winding\)) Tj ET Q +552.76 430.87 m +q 0.000 g BT 552.76 430.87 Td (0) Tj ET Q +496.06 332.67 l +q 0.000 g BT 496.06 332.67 Td (1) Tj ET Q +382.68 332.67 l +q 0.000 g BT 382.68 332.67 Td (2) Tj ET Q +325.98 430.87 l +q 0.000 g BT 325.98 430.87 Td (3) Tj ET Q +382.68 529.06 l +q 0.000 g BT 382.68 529.06 Td (4) Tj ET Q +496.06 529.06 l +q 0.000 g BT 496.06 529.06 Td (5) Tj ET Q +552.76 430.87 l +q 0.000 g BT 552.76 430.87 Td (6) Tj ET Q +h +524.41 430.87 m +q 0.000 g BT 524.41 430.87 Td (0) Tj ET Q +481.89 504.51 l +q 0.000 g BT 481.89 504.51 Td (1) Tj ET Q +396.85 504.51 l +q 0.000 g BT 396.85 504.51 Td (2) Tj ET Q +354.33 430.87 l +q 0.000 g BT 354.33 430.87 Td (3) Tj ET Q +396.85 357.22 l +q 0.000 g BT 396.85 357.22 Td (4) Tj ET Q +481.89 357.22 l +q 0.000 g BT 481.89 357.22 Td (5) Tj ET Q +524.41 430.87 l +q 0.000 g BT 524.41 430.87 Td (6) Tj ET Q +h +496.06 430.87 m +q 0.000 g BT 496.06 430.87 Td (0) Tj ET Q +467.72 381.77 l +q 0.000 g BT 467.72 381.77 Td (1) Tj ET Q +411.02 381.77 l +q 0.000 g BT 411.02 381.77 Td (2) Tj ET Q +382.68 430.87 l +q 0.000 g BT 382.68 430.87 Td (3) Tj ET Q +411.02 479.96 l +q 0.000 g BT 411.02 479.96 Td (4) Tj ET Q +467.72 479.96 l +q 0.000 g BT 467.72 479.96 Td (5) Tj ET Q +496.06 430.87 l +q 0.000 g BT 496.06 430.87 Td (6) Tj ET Q +h +467.72 430.87 m +q 0.000 g BT 467.72 430.87 Td (0) Tj ET Q +453.54 455.42 l +q 0.000 g BT 453.54 455.42 Td (1) Tj ET Q +425.20 455.42 l +q 0.000 g BT 425.20 455.42 Td (2) Tj ET Q +411.02 430.87 l +q 0.000 g BT 411.02 430.87 Td (3) Tj ET Q +425.20 406.32 l +q 0.000 g BT 425.20 406.32 Td (4) Tj ET Q +453.54 406.32 l +q 0.000 g BT 453.54 406.32 Td (5) Tj ET Q +467.72 430.87 l +q 0.000 g BT 467.72 430.87 Td (6) Tj ET Q +h +B* +q 0.000 g BT 325.98 289.13 Td (B* \(different direction, even odd\)) Tj ET Q +269.29 147.40 m +64.17 80.76 l +190.94 255.24 l +190.94 39.57 l +64.17 214.05 l +269.29 147.40 l +h +B +q 0.000 g BT 42.52 19.84 Td (B \(non zero winding\)) Tj ET Q +552.76 147.40 m +347.64 80.76 l +474.41 255.24 l +474.41 39.57 l +347.64 214.05 l +552.76 147.40 l +h +B* +q 0.000 g BT 325.98 19.84 Td (B* \(even odd\)) Tj ET Q + +endstream +endobj +1 0 obj +<> +endobj +5 0 obj +<> +endobj +6 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F0 6 0 R +>> +/XObject << +>> +/ExtGState << +/GS1 5 0 R +>> +>> +endobj +7 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +8 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 9 +0000000000 65535 f +0000005323 00000 n +0000005576 00000 n +0000000009 00000 n +0000000143 00000 n +0000005410 00000 n +0000005480 00000 n +0000005708 00000 n +0000005783 00000 n +trailer +<< +/Size 9 +/Root 8 0 R +/Info 7 0 R +>> +startxref +5832 +%%EOF diff --git a/pdf/reference/Fpdf_EmbeddedFont.pdf b/pdf/reference/Fpdf_EmbeddedFont.pdf new file mode 100644 index 0000000..108986a Binary files /dev/null and b/pdf/reference/Fpdf_EmbeddedFont.pdf differ diff --git a/pdf/reference/Fpdf_HTMLBasicNew.pdf b/pdf/reference/Fpdf_HTMLBasicNew.pdf new file mode 100644 index 0000000..bb88f2e Binary files /dev/null and b/pdf/reference/Fpdf_HTMLBasicNew.pdf differ diff --git a/pdf/reference/Fpdf_LinearGradient_gradient.pdf b/pdf/reference/Fpdf_LinearGradient_gradient.pdf new file mode 100644 index 0000000..67728d7 --- /dev/null +++ b/pdf/reference/Fpdf_LinearGradient_gradient.pdf @@ -0,0 +1,150 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0 12.00 Tf ET +0.000 G +0.000 g +q 0.00 841.89 595.28 -283.46 re W n +595.27559 0 0 283.46457 0.00000 558.42543 cm +/Sh1 sh +Q +q 56.69 771.02 212.60 -212.60 re W n +212.59843 0 0 212.59843 56.69291 558.42543 cm +/Sh2 sh +Q +56.69 771.02 212.60 -212.60 re S +q 325.98 771.02 212.60 -212.60 re W n +212.59843 0 0 212.59843 325.98425 558.42543 cm +/Sh3 sh +Q +325.98 771.02 212.60 -212.60 re S +q 56.69 501.73 212.60 -212.60 re W n +212.59843 0 0 212.59843 56.69291 289.13409 cm +/Sh4 sh +Q +56.69 501.73 212.60 -212.60 re S +q 325.98 501.73 212.60 -212.60 re W n +212.59843 0 0 212.59843 325.98425 289.13409 cm +/Sh5 sh +Q +325.98 501.73 212.60 -212.60 re S + +endstream +endobj +1 0 obj +<> +endobj +5 0 obj +<> +endobj +6 0 obj +<> +endobj +7 0 obj +<> +endobj +8 0 obj +<> +endobj +9 0 obj +<> +endobj +10 0 obj +<> +endobj +11 0 obj +<> +endobj +12 0 obj +<> +endobj +13 0 obj +<> +endobj +14 0 obj +<> +endobj +15 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F0 15 0 R +>> +/XObject << +>> +/Shading << +/Sh1 6 0 R +/Sh2 8 0 R +/Sh3 10 0 R +/Sh4 12 0 R +/Sh5 14 0 R +>> +>> +endobj +16 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +17 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 18 +0000000000 65535 f +0000000787 00000 n +0000002203 00000 n +0000000009 00000 n +0000000087 00000 n +0000000874 00000 n +0000000980 00000 n +0000001115 00000 n +0000001221 00000 n +0000001356 00000 n +0000001462 00000 n +0000001598 00000 n +0000001705 00000 n +0000001852 00000 n +0000001959 00000 n +0000002106 00000 n +0000002381 00000 n +0000002457 00000 n +trailer +<< +/Size 18 +/Root 17 0 R +/Info 16 0 R +>> +startxref +2507 +%%EOF diff --git a/pdf/reference/Fpdf_MoveTo_path.pdf b/pdf/reference/Fpdf_MoveTo_path.pdf new file mode 100644 index 0000000..b73aee4 --- /dev/null +++ b/pdf/reference/Fpdf_MoveTo_path.pdf @@ -0,0 +1,75 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +0.000 G +0.000 g +56.69 785.20 m +481.89 785.20 l +481.89 785.20 l +496.73193 785.19709 511.48271 779.08712 521.97771 768.59212 c +532.47271 758.09712 538.58268 743.34634 538.58268 728.50417 c +538.58268 558.42543 297.63780 558.42543 v +56.69291 558.42543 297.63780 274.96087 56.69291 274.96087 c +h +0.784 g +8.50 w +B + +endstream +endobj +1 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +>> +/XObject << +>> +>> +endobj +5 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +6 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 7 +0000000000 65535 f +0000000459 00000 n +0000000546 00000 n +0000000009 00000 n +0000000087 00000 n +0000000640 00000 n +0000000715 00000 n +trailer +<< +/Size 7 +/Root 6 0 R +/Info 5 0 R +>> +startxref +764 +%%EOF diff --git a/pdf/reference/Fpdf_MultiCell.pdf b/pdf/reference/Fpdf_MultiCell.pdf new file mode 100644 index 0000000..50c82b5 --- /dev/null +++ b/pdf/reference/Fpdf_MultiCell.pdf @@ -0,0 +1,499 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +0.000 G +0.000 g +BT /F0 15.00 Tf ET +0.000 0.314 0.706 RG +0.902 0.902 0.000 rg +2.83 w +179.09 813.54 237.10 -25.51 re B q 0.863 0.196 0.196 rg BT 187.59 796.28 Td (20000 Leagues Under the Seas) Tj ET Q +0.57 w +0.000 G +0.000 g +BT /F1 12.00 Tf ET +0.784 0.863 1.000 rg +28.35 759.68 538.58 -17.01 re f q 0.000 g BT 31.19 747.58 Td (Chapter 1 : A RUNAWAY REEF) Tj ET Q +BT /F2 12.00 Tf ET +0.002 Tw +q 0.000 g BT 31.19 720.65 Td (The year 1866 was marked by a bizarre development, an unexplained and downright inexplicable phenomenon) Tj ET Q +1.585 Tw +q 0.000 g BT 31.19 706.48 Td (that surely no one has forgotten. Without getting into those rumors that upset civilians in the seaports and) Tj ET Q +1.022 Tw +q 0.000 g BT 31.19 692.30 Td (deranged the public mind even far inland, it must be said that professional seamen were especially alarmed.) Tj ET Q +2.336 Tw +q 0.000 g BT 31.19 678.13 Td (Traders, shipowners, captains of vessels, skippers, and master mariners from Europe and America, naval) Tj ET Q +0.314 Tw +q 0.000 g BT 31.19 663.96 Td (officers from every country, and at their heels the various national governments on these two continents, were) Tj ET Q +0 Tw +q 0.000 g BT 31.19 649.78 Td (all extremely disturbed by the business.) Tj ET Q +3.660 Tw +q 0.000 g BT 31.19 635.61 Td (In essence, over a period of time several ships had encountered "an enormous thing" at sea, a long) Tj ET Q +2.306 Tw +q 0.000 g BT 31.19 621.44 Td (spindle-shaped object, sometimes giving off a phosphorescent glow, infinitely bigger and faster than any) Tj ET Q +0 Tw +q 0.000 g BT 31.19 607.26 Td (whale.) Tj ET Q +0.589 Tw +q 0.000 g BT 31.19 593.09 Td (The relevant data on this apparition, as recorded in various logbooks, agreed pretty closely as to the structure) Tj ET Q +0.125 Tw +q 0.000 g BT 31.19 578.92 Td (of the object or creature in question, its unprecedented speed of movement, its startling locomotive power, and) Tj ET Q +1.556 Tw +q 0.000 g BT 31.19 564.74 Td (the unique vitality with which it seemed to be gifted. If it was a cetacean, it exceeded in bulk any whale) Tj ET Q +1.192 Tw +q 0.000 g BT 31.19 550.57 Td (previously classified by science. No naturalist, neither Cuvier nor Lacpde, neither Professor Dumeril nor) Tj ET Q +1.159 Tw +q 0.000 g BT 31.19 536.40 Td (Professor de Quatrefages, would have accepted the existence of such a monster sight unseen -- specifically,) Tj ET Q +0 Tw +q 0.000 g BT 31.19 522.22 Td (unseen by their own scientific eyes.) Tj ET Q +1.520 Tw +q 0.000 g BT 31.19 508.05 Td (Striking an average of observations taken at different times -- rejecting those timid estimates that gave the) Tj ET Q +2.544 Tw +q 0.000 g BT 31.19 493.88 Td (object a length of 200 feet, and ignoring those exaggerated views that saw it as a mile wide and three) Tj ET Q +1.356 Tw +q 0.000 g BT 31.19 479.70 Td (long--you could still assert that this phenomenal creature greatly exceeded the dimensions of anything then) Tj ET Q +0 Tw +q 0.000 g BT 31.19 465.53 Td (known to ichthyologists, if it existed at all.) Tj ET Q +0.232 Tw +q 0.000 g BT 31.19 451.36 Td (Now then, it did exist, this was an undeniable fact; and since the human mind dotes on objects of wonder, you) Tj ET Q +0.292 Tw +q 0.000 g BT 31.19 437.18 Td (can understand the worldwide excitement caused by this unearthly apparition. As for relegating it to the realm) Tj ET Q +0 Tw +q 0.000 g BT 31.19 423.01 Td (of fiction, that charge had to be dropped.) Tj ET Q +3.687 Tw +q 0.000 g BT 31.19 408.84 Td (In essence, on July 20, 1866, the steamer Governor Higginson, from the Calcutta & Burnach Steam) Tj ET Q +0.332 Tw +q 0.000 g BT 31.19 394.66 Td (Navigation Co., encountered this moving mass five miles off the eastern shores of Australia. Captain Baker at) Tj ET Q +0.413 Tw +q 0.000 g BT 31.19 380.49 Td (first thought he was in the presence of an unknown reef; he was even about to fix its exact position when two) Tj ET Q +0.593 Tw +q 0.000 g BT 31.19 366.32 Td (waterspouts shot out of this inexplicable object and sprang hissing into the air some 150 feet. So, unless this) Tj ET Q +0.177 Tw +q 0.000 g BT 31.19 352.14 Td (reef was subject to the intermittent eruptions of a geyser, the Governor Higginson had fair and honest dealings) Tj ET Q +0.662 Tw +q 0.000 g BT 31.19 337.97 Td (with some aquatic mammal, until then unknown, that could spurt from its blowholes waterspouts mixed with) Tj ET Q +0 Tw +q 0.000 g BT 31.19 323.80 Td (air and steam.) Tj ET Q +2.548 Tw +q 0.000 g BT 31.19 309.63 Td (Similar events were likewise observed in Pacific seas, on July 23 of the same year, by the Christopher) Tj ET Q +1.355 Tw +q 0.000 g BT 31.19 295.45 Td (Columbus from the West India & Pacific Steam Navigation Co. Consequently, this extraordinary cetacean) Tj ET Q +0.567 Tw +q 0.000 g BT 31.19 281.28 Td (could transfer itself from one locality to another with startling swiftness, since within an interval of just three) Tj ET Q +1.163 Tw +q 0.000 g BT 31.19 267.11 Td (days, the Governor Higginson and the Christopher Columbus had observed it at two positions on the charts) Tj ET Q +0 Tw +q 0.000 g BT 31.19 252.93 Td (separated by a distance of more than 700 nautical leagues.) Tj ET Q +1.734 Tw +q 0.000 g BT 31.19 238.76 Td (Fifteen days later and 2,000 leagues farther, the Helvetia from the Compagnie Nationale and the Shannon) Tj ET Q +0.050 Tw +q 0.000 g BT 31.19 224.59 Td (from the Royal Mail line, running on opposite tacks in that part of the Atlantic lying between the United States) Tj ET Q +0.167 Tw +q 0.000 g BT 31.19 210.41 Td (and Europe, respectively signaled each other that the monster had been sighted in latitude 42 degrees 15' north) Tj ET Q +0.551 Tw +q 0.000 g BT 31.19 196.24 Td (and longitude 60 degrees 35' west of the meridian of Greenwich. From their simultaneous observations, they) Tj ET Q +0.341 Tw +q 0.000 g BT 31.19 182.07 Td (were able to estimate the mammal's minimum length at more than 350 English feet; this was because both the) Tj ET Q +0.146 Tw +q 0.000 g BT 31.19 167.89 Td (Shannon and the Helvetia were of smaller dimensions, although each measured 100 meters stem to stern. Now) Tj ET Q +0.377 Tw +q 0.000 g BT 31.19 153.72 Td (then, the biggest whales, those rorqual whales that frequent the waterways of the Aleutian Islands, have never) Tj ET Q +0 Tw +q 0.000 g BT 31.19 139.55 Td (exceeded a length of 56 meters--if they reach even that.) Tj ET Q +0.293 Tw +q 0.000 g BT 31.19 125.37 Td (One after another, reports arrived that would profoundly affect public opinion: new observations taken by the) Tj ET Q +0.893 Tw +q 0.000 g BT 31.19 111.20 Td (transatlantic liner Pereire, the Inman line's Etna running afoul of the monster, an official report drawn up by) Tj ET Q +0.051 Tw +q 0.000 g BT 31.19 97.03 Td (officers on the French frigate Normandy, dead-earnest reckonings obtained by the general staff of Commodore) Tj ET Q +1.236 Tw +q 0.000 g BT 31.19 82.85 Td (Fitz-James aboard the Lord Clyde. In lighthearted countries, people joked about this phenomenon, but such) Tj ET Q +0 Tw +q 0.000 g BT 31.19 68.68 Td (serious, practical countries as England, America, and Germany were deeply concerned.) Tj ET Q +0.060 Tw +0 Tw +BT /F3 8.00 Tf ET +q 0.502 g BT 284.96 25.95 Td (Page 1) Tj ET Q + +endstream +endobj +5 0 obj +<> +endobj +6 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F2 12.00 Tf ET +0.000 G +0.784 0.863 1.000 rg +BT /F0 15.00 Tf ET +0.000 0.314 0.706 RG +0.902 0.902 0.000 rg +2.83 w +179.09 813.54 237.10 -25.51 re B q 0.863 0.196 0.196 rg BT 187.59 796.28 Td (20000 Leagues Under the Seas) Tj ET Q +0.57 w +BT /F2 12.00 Tf ET +0.000 G +0.784 0.863 1.000 rg +0.060 Tw +q 0.000 g BT 31.19 749.00 Td (In every big city the monster was the latest rage; they sang about it in the coffee houses, they ridiculed it in the) Tj ET Q +0.034 Tw +q 0.000 g BT 31.19 734.82 Td (newspapers, they dramatized it in the theaters. The tabloids found it a fine opportunity for hatching all sorts of) Tj ET Q +1.315 Tw +q 0.000 g BT 31.19 720.65 Td (hoaxes. In those newspapers short of copy, you saw the reappearance of every gigantic imaginary creature,) Tj ET Q +0.742 Tw +q 0.000 g BT 31.19 706.48 Td (from "Moby Dick," that dreadful white whale from the High Arctic regions, to the stupendous kraken whose) Tj ET Q +1.315 Tw +q 0.000 g BT 31.19 692.30 Td (tentacles could entwine a 500-ton craft and drag it into the ocean depths. They even reprinted reports from) Tj ET Q +0.707 Tw +q 0.000 g BT 31.19 678.13 Td (ancient times: the views of Aristotle and Pliny accepting the existence of such monsters, then the Norwegian) Tj ET Q +0.936 Tw +q 0.000 g BT 31.19 663.96 Td (stories of Bishop Pontoppidan, the narratives of Paul Egede, and finally the reports of Captain Harrington --) Tj ET Q +0.980 Tw +q 0.000 g BT 31.19 649.78 Td (whose good faith is above suspicion--in which he claims he saw, while aboard the Castilian in 1857, one of) Tj ET Q +1.389 Tw +q 0.000 g BT 31.19 635.61 Td (those enormous serpents that, until then, had frequented only the seas of France's old extremist newspaper,) Tj ET Q +0 Tw +q 0.000 g BT 31.19 621.44 Td (The Constitutionalist.) Tj ET Q +BT /F4 12.00 Tf ET +q 0.000 g BT 31.19 593.09 Td (\(end of excerpt\)) Tj ET Q +BT /F3 8.00 Tf ET +q 0.502 g BT 284.96 25.95 Td (Page 2) Tj ET Q + +endstream +endobj +7 0 obj +<> +endobj +8 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F4 12.00 Tf ET +0.000 G +0.784 0.863 1.000 rg +BT /F0 15.00 Tf ET +0.000 0.314 0.706 RG +0.902 0.902 0.000 rg +2.83 w +179.09 813.54 237.10 -25.51 re B q 0.863 0.196 0.196 rg BT 187.59 796.28 Td (20000 Leagues Under the Seas) Tj ET Q +0.57 w +BT /F4 12.00 Tf ET +0.000 G +0.784 0.863 1.000 rg +BT /F1 12.00 Tf ET +0.784 0.863 1.000 rg +28.35 759.68 538.58 -17.01 re f q 0.000 g BT 31.19 747.58 Td (Chapter 2 : THE PROS AND CONS) Tj ET Q +BT /F2 12.00 Tf ET +1.002 Tw +q 0.000 g BT 31.19 720.65 Td (During the period in which these developments were occurring, I had returned from a scientific undertaking) Tj ET Q +0.608 Tw +q 0.000 g BT 31.19 706.48 Td (organized to explore the Nebraska badlands in the United States. In my capacity as Assistant Professor at the) Tj ET Q +1.687 Tw +q 0.000 g BT 31.19 692.30 Td (Paris Museum of Natural History, I had been attached to this expedition by the French government. After) Tj ET Q +2.020 Tw +q 0.000 g BT 31.19 678.13 Td (spending six months in Nebraska, I arrived in New York laden with valuable collections near the end of) Tj ET Q +1.649 Tw +q 0.000 g BT 31.19 663.96 Td (March. My departure for France was set for early May. In the meantime, then, I was busy classifying my) Tj ET Q +0 Tw +q 0.000 g BT 31.19 649.78 Td (mineralogical, botanical, and zoological treasures when that incident took place with the Scotia.) Tj ET Q +0.471 Tw +q 0.000 g BT 31.19 635.61 Td (I was perfectly abreast of this question, which was the big news of the day, and how could I not have been? I) Tj ET Q +0.782 Tw +q 0.000 g BT 31.19 621.44 Td (had read and reread every American and European newspaper without being any farther along. This mystery) Tj ET Q +0.516 Tw +q 0.000 g BT 31.19 607.26 Td (puzzled me. Finding it impossible to form any views, I drifted from one extreme to the other. Something was) Tj ET Q +1.601 Tw +q 0.000 g BT 31.19 593.09 Td (out there, that much was certain, and any doubting Thomas was invited to place his finger on the Scotia's) Tj ET Q +0 Tw +q 0.000 g BT 31.19 578.92 Td (wound.) Tj ET Q +1.249 Tw +q 0.000 g BT 31.19 564.74 Td (When I arrived in New York, the question was at the boiling point. The hypothesis of a drifting islet or an) Tj ET Q +1.561 Tw +q 0.000 g BT 31.19 550.57 Td (elusive reef, put forward by people not quite in their right minds, was completely eliminated. And indeed,) Tj ET Q +0 Tw +q 0.000 g BT 31.19 536.40 Td (unless this reef had an engine in its belly, how could it move about with such prodigious speed?) Tj ET Q +0.779 Tw +q 0.000 g BT 31.19 522.22 Td (Also discredited was the idea of a floating hull or some other enormous wreckage, and again because of this) Tj ET Q +0 Tw +q 0.000 g BT 31.19 508.05 Td (speed of movement.) Tj ET Q +1.114 Tw +q 0.000 g BT 31.19 493.88 Td (So only two possible solutions to the question were left, creating two very distinct groups of supporters: on) Tj ET Q +0.914 Tw +q 0.000 g BT 31.19 479.70 Td (one side, those favoring a monster of colossal strength; on the other, those favoring an "underwater boat" of) Tj ET Q +0 Tw +q 0.000 g BT 31.19 465.53 Td (tremendous motor power.) Tj ET Q +3.674 Tw +q 0.000 g BT 31.19 451.36 Td (Now then, although the latter hypothesis was completely admissible, it couldn't stand up to inquiries) Tj ET Q +0.227 Tw +q 0.000 g BT 31.19 437.18 Td (conducted in both the New World and the Old. That a private individual had such a mechanism at his disposal) Tj ET Q +0 Tw +q 0.000 g BT 31.19 423.01 Td (was less than probable. Where and when had he built it, and how could he have built it in secret?) Tj ET Q +0.395 Tw +q 0.000 g BT 31.19 408.84 Td (Only some government could own such an engine of destruction, and in these disaster-filled times, when men) Tj ET Q +1.331 Tw +q 0.000 g BT 31.19 394.66 Td (tax their ingenuity to build increasingly powerful aggressive weapons, it was possible that, unknown to the) Tj ET Q +0.106 Tw +q 0.000 g BT 31.19 380.49 Td (rest of the world, some nation could have been testing such a fearsome machine. The Chassepot rifle led to the) Tj ET Q +0.490 Tw +q 0.000 g BT 31.19 366.32 Td (torpedo, and the torpedo has led to this underwater battering ram, which in turn will lead to the world putting) Tj ET Q +0 Tw +q 0.000 g BT 31.19 352.14 Td (its foot down. At least I hope it will.) Tj ET Q +1.078 Tw +q 0.000 g BT 31.19 337.97 Td (But this hypothesis of a war machine collapsed in the face of formal denials from the various governments.) Tj ET Q +0.251 Tw +q 0.000 g BT 31.19 323.80 Td (Since the public interest was at stake and transoceanic travel was suffering, the sincerity of these governments) Tj ET Q +0.979 Tw +q 0.000 g BT 31.19 309.63 Td (could not be doubted. Besides, how could the assembly of this underwater boat have escaped public notice?) Tj ET Q +3.430 Tw +q 0.000 g BT 31.19 295.45 Td (Keeping a secret under such circumstances would be difficult enough for an individual, and certainly) Tj ET Q +0 Tw +q 0.000 g BT 31.19 281.28 Td (impossible for a nation whose every move is under constant surveillance by rival powers.) Tj ET Q +0.422 Tw +q 0.000 g BT 31.19 267.11 Td (So, after inquiries conducted in England, France, Russia, Prussia, Spain, Italy, America, and even Turkey, the) Tj ET Q +0 Tw +q 0.000 g BT 31.19 252.93 Td (hypothesis of an underwater Monitor was ultimately rejected.) Tj ET Q +2.481 Tw +q 0.000 g BT 31.19 238.76 Td (After I arrived in New York, several people did me the honor of consulting me on the phenomenon in) Tj ET Q +0.569 Tw +q 0.000 g BT 31.19 224.59 Td (question. In France I had published a two-volume work, in quarto, entitled The Mysteries of the Great Ocean) Tj ET Q +0.862 Tw +q 0.000 g BT 31.19 210.41 Td (Depths. Well received in scholarly circles, this book had established me as a specialist in this pretty obscure) Tj ET Q +1.833 Tw +q 0.000 g BT 31.19 196.24 Td (field of natural history. My views were in demand. As long as I could deny the reality of the business, I) Tj ET Q +0.058 Tw +q 0.000 g BT 31.19 182.07 Td (confined myself to a flat "no comment." But soon, pinned to the wall, I had to explain myself straight out. And) Tj ET Q +1.637 Tw +q 0.000 g BT 31.19 167.89 Td (in this vein, "the honorable Pierre Aronnax, Professor at the Paris Museum," was summoned by The New) Tj ET Q +0 Tw +q 0.000 g BT 31.19 153.72 Td (York Herald to formulate his views no matter what.) Tj ET Q +0.697 Tw +q 0.000 g BT 31.19 139.55 Td (I complied. Since I could no longer hold my tongue, I let it wag. I discussed the question in its every aspect,) Tj ET Q +0.017 Tw +q 0.000 g BT 31.19 125.37 Td (both political and scientific, and this is an excerpt from the well-padded article I published in the issue of April) Tj ET Q +0 Tw +q 0.000 g BT 31.19 111.20 Td (30.) Tj ET Q +2.226 Tw +q 0.000 g BT 31.19 82.85 Td ("Therefore," I wrote, "after examining these different hypotheses one by one, we are forced, every other) Tj ET Q +0 Tw +q 0.000 g BT 31.19 68.68 Td (supposition having been refuted, to accept the existence of an extremely powerful marine animal.) Tj ET Q +0.550 Tw +0 Tw +BT /F3 8.00 Tf ET +q 0.502 g BT 284.96 25.95 Td (Page 3) Tj ET Q + +endstream +endobj +9 0 obj +<> +endobj +10 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F2 12.00 Tf ET +0.000 G +0.784 0.863 1.000 rg +BT /F0 15.00 Tf ET +0.000 0.314 0.706 RG +0.902 0.902 0.000 rg +2.83 w +179.09 813.54 237.10 -25.51 re B q 0.863 0.196 0.196 rg BT 187.59 796.28 Td (20000 Leagues Under the Seas) Tj ET Q +0.57 w +BT /F2 12.00 Tf ET +0.000 G +0.784 0.863 1.000 rg +0.550 Tw +q 0.000 g BT 31.19 749.00 Td ("The deepest parts of the ocean are totally unknown to us. No soundings have been able to reach them. What) Tj ET Q +0.352 Tw +q 0.000 g BT 31.19 734.82 Td (goes on in those distant depths? What creatures inhabit, or could inhabit, those regions twelve or fifteen miles) Tj ET Q +0 Tw +q 0.000 g BT 31.19 720.65 Td (beneath the surface of the water? What is the constitution of these animals? It's almost beyond conjecture.) Tj ET Q +3.495 Tw +q 0.000 g BT 31.19 706.48 Td ("However, the solution to this problem submitted to me can take the form of a choice between two) Tj ET Q +0 Tw +q 0.000 g BT 31.19 692.30 Td (alternatives.) Tj ET Q +q 0.000 g BT 31.19 678.13 Td ("Either we know every variety of creature populating our planet, or we do not.) Tj ET Q +1.250 Tw +q 0.000 g BT 31.19 663.96 Td ("If we do not know every one of them, if nature still keeps ichthyological secrets from us, nothing is more) Tj ET Q +0.231 Tw +q 0.000 g BT 31.19 649.78 Td (admissible than to accept the existence of fish or cetaceans of new species or even new genera, animals with a) Tj ET Q +3.022 Tw +q 0.000 g BT 31.19 635.61 Td (basically 'cast-iron' constitution that inhabit strata beyond the reach of our soundings, and which some) Tj ET Q +1.589 Tw +q 0.000 g BT 31.19 621.44 Td (development or other, an urge or a whim if you prefer, can bring to the upper level of the ocean for long) Tj ET Q +0 Tw +q 0.000 g BT 31.19 607.26 Td (intervals.) Tj ET Q +0.321 Tw +q 0.000 g BT 31.19 593.09 Td ("If, on the other hand, we do know every living species, we must look for the animal in question among those) Tj ET Q +1.409 Tw +q 0.000 g BT 31.19 578.92 Td (marine creatures already cataloged, and in this event I would be inclined to accept the existence of a giant) Tj ET Q +0 Tw +q 0.000 g BT 31.19 564.74 Td (narwhale.) Tj ET Q +0.008 Tw +q 0.000 g BT 31.19 550.57 Td ("The common narwhale, or sea unicorn, often reaches a length of sixty feet. Increase its dimensions fivefold or) Tj ET Q +0.352 Tw +q 0.000 g BT 31.19 536.40 Td (even tenfold, then give this cetacean a strength in proportion to its size while enlarging its offensive weapons,) Tj ET Q +1.251 Tw +q 0.000 g BT 31.19 522.22 Td (and you have the animal we're looking for. It would have the proportions determined by the officers of the) Tj ET Q +0 Tw +q 0.000 g BT 31.19 508.05 Td (Shannon, the instrument needed to perforate the Scotia, and the power to pierce a steamer's hull.) Tj ET Q +0.130 Tw +q 0.000 g BT 31.19 493.88 Td ("In essence, the narwhale is armed with a sort of ivory sword, or lance, as certain naturalists have expressed it.) Tj ET Q +1.326 Tw +q 0.000 g BT 31.19 479.70 Td (It's a king-sized tooth as hard as steel. Some of these teeth have been found buried in the bodies of baleen) Tj ET Q +3.771 Tw +q 0.000 g BT 31.19 465.53 Td (whales, which the narwhale attacks with invariable success. Others have been wrenched, not without) Tj ET Q +0.119 Tw +q 0.000 g BT 31.19 451.36 Td (difficulty, from the undersides of vessels that narwhales have pierced clean through, as a gimlet pierces a wine) Tj ET Q +0.649 Tw +q 0.000 g BT 31.19 437.18 Td (barrel. The museum at the Faculty of Medicine in Paris owns one of these tusks with a length of 2.25 meters) Tj ET Q +0 Tw +q 0.000 g BT 31.19 423.01 Td (and a width at its base of forty-eight centimeters!) Tj ET Q +0.467 Tw +q 0.000 g BT 31.19 408.84 Td ("All right then! Imagine this weapon to be ten times stronger and the animal ten times more powerful, launch) Tj ET Q +0.980 Tw +q 0.000 g BT 31.19 394.66 Td (it at a speed of twenty miles per hour, multiply its mass times its velocity, and you get just the collision we) Tj ET Q +0 Tw +q 0.000 g BT 31.19 380.49 Td (need to cause the specified catastrophe.) Tj ET Q +1.067 Tw +q 0.000 g BT 31.19 366.32 Td ("So, until information becomes more abundant, I plump for a sea unicorn of colossal dimensions, no longer) Tj ET Q +0.631 Tw +q 0.000 g BT 31.19 352.14 Td (armed with a mere lance but with an actual spur, like ironclad frigates or those warships called 'rams,' whose) Tj ET Q +0 Tw +q 0.000 g BT 31.19 337.97 Td (mass and motor power it would possess simultaneously.) Tj ET Q +1.992 Tw +q 0.000 g BT 31.19 323.80 Td ("This inexplicable phenomenon is thus explained away--unless it's something else entirely, which, despite) Tj ET Q +0 Tw +q 0.000 g BT 31.19 309.63 Td (everything that has been sighted, studied, explored and experienced, is still possible!") Tj ET Q +BT /F4 12.00 Tf ET +q 0.000 g BT 31.19 281.28 Td (\(end of excerpt\)) Tj ET Q +BT /F3 8.00 Tf ET +q 0.502 g BT 284.96 25.95 Td (Page 4) Tj ET Q + +endstream +endobj +1 0 obj +<> +endobj +11 0 obj +<> +endobj +12 0 obj +<> +endobj +13 0 obj +<> +endobj +14 0 obj +<> +endobj +15 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F1 11 0 R +/F0 12 0 R +/F3 13 0 R +/F2 14 0 R +/F4 15 0 R +>> +/XObject << +>> +>> +endobj +16 0 obj +<< +/Producer (FPDF 1.7) +/Title (20000 Leagues Under the Seas) +/Author (Jules Verne) +/CreationDate (D:20000101000000) +>> +endobj +17 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 18 +0000000000 65535 f +0000021545 00000 n +0000022153 00000 n +0000000009 00000 n +0000000087 00000 n +0000007319 00000 n +0000007397 00000 n +0000009374 00000 n +0000009452 00000 n +0000016540 00000 n +0000016619 00000 n +0000021650 00000 n +0000021747 00000 n +0000021849 00000 n +0000021954 00000 n +0000022053 00000 n +0000022302 00000 n +0000022438 00000 n +trailer +<< +/Size 18 +/Root 17 0 R +/Info 16 0 R +>> +startxref +22488 +%%EOF diff --git a/pdf/reference/Fpdf_PageSize.pdf b/pdf/reference/Fpdf_PageSize.pdf new file mode 100644 index 0000000..e3e7e56 --- /dev/null +++ b/pdf/reference/Fpdf_PageSize.pdf @@ -0,0 +1,119 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0 14.00 Tf ET +0.000 G +0.000 g +BT 400.11 96.60 Td (12 in x 3 in) Tj ET + +endstream +endobj +5 0 obj +<> +endobj +6 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0 14.00 Tf ET +0.000 G +0.000 g +BT 187.61 204.60 Td (6 in x 6 in) Tj ET + +endstream +endobj +7 0 obj +<> +endobj +8 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0 14.00 Tf ET +0.000 G +0.000 g +BT 76.11 420.60 Td (3 in x 12 in) Tj ET + +endstream +endobj +1 0 obj +<> +endobj +9 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F0 9 0 R +>> +/XObject << +>> +>> +endobj +10 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +11 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 12 +0000000000 65535 f +0000000717 00000 n +0000000914 00000 n +0000000009 00000 n +0000000117 00000 n +0000000255 00000 n +0000000333 00000 n +0000000471 00000 n +0000000579 00000 n +0000000816 00000 n +0000001018 00000 n +0000001094 00000 n +trailer +<< +/Size 12 +/Root 11 0 R +/Info 10 0 R +>> +startxref +1144 +%%EOF diff --git a/pdf/reference/Fpdf_Polygon.pdf b/pdf/reference/Fpdf_Polygon.pdf new file mode 100644 index 0000000..c16719e --- /dev/null +++ b/pdf/reference/Fpdf_Polygon.pdf @@ -0,0 +1,371 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +0.000 G +0.000 g +BT /F0 36.00 Tf ET +0.000 0.314 0.706 RG +BT 135.57 780.07 Td (Equilateral polygons) Tj ET +0.902 0.902 0.000 rg +140.31 684.71 m +60.59055 638.67999 l +60.59055 730.73781 l +140.31496 684.70890 l +B +280.63 684.71 m +227.48031 631.55929 l +174.33071 684.70890 l +227.48031 737.85850 l +280.62992 684.70890 l +B +420.94 684.71 m +384.21941 634.16062 l +324.79634 653.46834 l +324.79634 715.94945 l +384.21941 735.25718 l +420.94488 684.70890 l +B +561.26 684.71 m +534.68504 638.67999 l +481.53543 638.67999 l +454.96063 684.70890 l +481.53543 730.73781 l +534.68504 730.73781 l +561.25984 684.70890 l +B +0.855 0.855 0.000 rg +140.31 544.39 m +120.30359 502.83990 l +75.33845 492.57690 l +39.27921 521.33319 l +39.27921 567.45469 l +75.33845 596.21097 l +120.30359 585.94797 l +140.31496 544.39394 l +B +280.63 544.39 m +265.06276 506.81149 l +227.48031 491.24433 l +189.89787 506.81149 l +174.33071 544.39394 l +189.89787 581.97638 l +227.48031 597.54354 l +265.06276 581.97638 l +280.62992 544.39394 l +B +420.94 544.39 m +408.51024 510.23003 l +377.02461 492.05179 l +341.22047 498.36503 l +317.85098 526.21570 l +317.85098 562.57217 l +341.22047 590.42285 l +377.02461 596.73608 l +408.51024 578.55785 l +420.94488 544.39394 l +B +561.26 544.39 m +551.10917 513.15338 l +524.53437 493.84566 l +491.68610 493.84566 l +465.11130 513.15338 l +454.96063 544.39394 l +465.11130 575.63449 l +491.68610 594.94222 l +524.53437 594.94222 l +551.10917 575.63449 l +561.25984 544.39394 l +B +0.808 0.808 0.000 rg +140.31 404.08 m +131.87765 375.34413 l +109.24450 355.73239 l +79.60138 351.47036 l +52.35976 363.91118 l +36.16868 389.10500 l +36.16868 419.05295 l +52.35976 444.24677 l +79.60138 456.68760 l +109.24450 452.42556 l +131.87765 432.81382 l +140.31496 404.07898 l +B +280.63 404.08 m +273.50922 377.50417 l +254.05512 358.05007 l +227.48031 350.92937 l +200.90551 358.05007 l +181.45141 377.50417 l +174.33071 404.07898 l +181.45141 430.65378 l +200.90551 450.10789 l +227.48031 457.22858 l +254.05512 450.10789 l +273.50922 430.65378 l +280.62992 404.07898 l +B +420.94 404.08 m +414.85691 379.37912 l +397.98769 360.33771 l +374.20175 351.31689 l +348.94817 354.38323 l +328.01222 368.83427 l +316.19010 391.35944 l +316.19010 416.79851 l +328.01222 439.32368 l +348.94817 453.77472 l +374.20175 456.84106 l +397.98769 447.82024 l +414.85691 428.77883 l +420.94488 404.07898 l +B +561.26 404.08 m +555.99638 381.01823 l +541.24847 362.52494 l +519.93714 352.26194 l +496.28334 352.26194 l +474.97200 362.52494 l +460.22410 381.01823 l +454.96063 404.07898 l +460.22410 427.13973 l +474.97200 445.63301 l +496.28334 455.89601 l +519.93714 455.89601 l +541.24847 445.63301 l +555.99638 427.13973 l +561.25984 404.07898 l +B +0.761 0.761 0.000 rg +140.31 263.76 m +135.71994 242.14612 l +122.72938 224.26616 l +103.58949 213.21574 l +81.60971 210.90557 l +60.59055 217.73511 l +44.16642 232.52346 l +35.17719 252.71359 l +35.17719 274.81444 l +44.16642 295.00457 l +60.59055 309.79293 l +81.60971 316.62246 l +103.58949 314.31230 l +122.72938 303.26187 l +135.71994 285.38191 l +140.31496 263.76402 l +B +280.63 263.76 m +276.58415 243.42454 l +265.06276 226.18157 l +247.81979 214.66018 l +227.48031 210.61441 l +207.14084 214.66018 l +189.89787 226.18157 l +178.37648 243.42454 l +174.33071 263.76402 l +178.37648 284.10349 l +189.89787 301.34646 l +207.14084 312.86785 l +227.48031 316.91362 l +247.81979 312.86785 l +265.06276 301.34646 l +276.58415 284.10349 l +280.62992 263.76402 l +B +420.94 263.76 m +417.35581 244.56416 l +407.07331 227.95736 l +391.48609 216.18644 l +372.69930 210.84114 l +353.25020 212.64336 l +335.76548 221.34971 l +322.60657 235.78435 l +315.55064 253.99780 l +315.55064 273.53023 l +322.60657 291.74368 l +335.76548 306.17832 l +353.25020 314.88467 l +372.69930 316.68690 l +391.48609 311.34159 l +407.07331 299.57067 l +417.35581 282.96387 l +420.94488 263.76402 l +B +561.26 263.76 m +558.05453 245.58578 l +548.82520 229.60011 l +534.68504 217.73511 l +517.33957 211.42187 l +498.88090 211.42187 l +481.53543 217.73511 l +467.39528 229.60011 l +458.16594 245.58578 l +454.96063 263.76402 l +458.16594 281.94225 l +467.39528 297.92792 l +481.53543 309.79293 l +498.88090 316.10616 l +517.33957 316.10616 l +534.68504 309.79293 l +548.82520 297.92792 l +558.05453 281.94225 l +561.25984 263.76402 l +B +0.714 0.714 0.000 rg +140.31 123.45 m +137.43517 106.19141 l +129.10786 90.80389 l +116.23543 78.95399 l +100.21281 71.92581 l +82.77629 70.48098 l +65.81540 74.77606 l +51.16811 84.34562 l +40.42167 98.15264 l +34.74064 114.70092 l +34.74064 132.19719 l +40.42167 148.74547 l +51.16811 162.55249 l +65.81540 172.12205 l +82.77629 176.41713 l +100.21281 174.97230 l +116.23543 167.94412 l +129.10786 156.09422 l +137.43517 140.70670 l +140.31496 123.44906 l +B +280.63 123.45 m +278.02859 107.02492 l +270.47925 92.20850 l +258.72087 80.45012 l +243.90445 72.90078 l +227.48031 70.29945 l +211.05618 72.90078 l +196.23976 80.45012 l +184.48138 92.20850 l +176.93204 107.02492 l +174.33071 123.44906 l +176.93204 139.87319 l +184.48138 154.68961 l +196.23976 166.44799 l +211.05618 173.99733 l +227.48031 176.59866 l +243.90445 173.99733 l +258.72087 166.44799 l +270.47925 154.68961 l +278.02859 139.87319 l +280.62992 123.44906 l +B +420.94 123.45 m +418.58359 107.78293 l +411.70954 93.50882 l +400.93351 81.89502 l +387.21301 73.97348 l +371.76715 70.44807 l +355.96838 71.63202 l +341.22047 77.42015 l +328.83386 87.29814 l +319.90913 100.38831 l +315.23931 115.52752 l +315.23931 131.37059 l +319.90913 146.50981 l +328.83386 159.59997 l +341.22047 169.47796 l +355.96838 175.26609 l +371.76715 176.45004 l +387.21301 172.92463 l +400.93351 165.00309 l +411.70954 153.38929 l +418.58359 139.11518 l +420.94488 123.44906 l +B +561.26 123.45 m +559.10691 108.47508 l +552.82253 94.71421 l +542.91583 83.28126 l +530.18938 75.10247 l +515.67421 70.84044 l +500.54626 70.84044 l +486.03109 75.10247 l +473.30465 83.28126 l +463.39794 94.71421 l +457.11356 108.47508 l +454.96063 123.44906 l +457.11356 138.42303 l +463.39794 152.18390 l +473.30465 163.61685 l +486.03109 171.79564 l +500.54626 176.05768 l +515.67421 176.05768 l +530.18938 171.79564 l +542.91583 163.61685 l +552.82253 152.18390 l +559.10691 138.42303 l +561.25984 123.44906 l +B + +endstream +endobj +1 0 obj +<> +endobj +5 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F0 5 0 R +>> +/XObject << +>> +>> +endobj +6 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +7 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 8 +0000000000 65535 f +0000006413 00000 n +0000006596 00000 n +0000000009 00000 n +0000000087 00000 n +0000006500 00000 n +0000006700 00000 n +0000006775 00000 n +trailer +<< +/Size 8 +/Root 7 0 R +/Info 6 0 R +>> +startxref +6824 +%%EOF diff --git a/pdf/reference/Fpdf_SVGBasicWrite.pdf b/pdf/reference/Fpdf_SVGBasicWrite.pdf new file mode 100644 index 0000000..b6cc82a --- /dev/null +++ b/pdf/reference/Fpdf_SVGBasicWrite.pdf @@ -0,0 +1,947 @@ +%PDF-1.3 +3 0 obj +<>>><>>>] +/Contents 4 0 R>> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +BT /Fd08375f64eb9861c6eae4dfcfdbd3500fbdbe33e 16.00 Tf ET +0.000 G +0.000 g +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 +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 +1 0 obj +<> +endobj +5 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/Fd08375f64eb9861c6eae4dfcfdbd3500fbdbe33e 5 0 R +>> +/XObject << +>> +/ColorSpace << +>> +>> +endobj +6 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +7 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 8 +0000000000 65535 f +0000030711 00000 n +0000030896 00000 n +0000000009 00000 n +0000000384 00000 n +0000030798 00000 n +0000031057 00000 n +0000031142 00000 n +trailer +<< +/Size 8 +/Root 7 0 R +/Info 6 0 R +>> +startxref +31191 +%%EOF diff --git a/pdf/reference/Fpdf_SetFontLoader.pdf b/pdf/reference/Fpdf_SetFontLoader.pdf new file mode 100644 index 0000000..9af78e2 Binary files /dev/null and b/pdf/reference/Fpdf_SetFontLoader.pdf differ diff --git a/pdf/reference/Fpdf_SetLeftMargin_multicolumn.pdf b/pdf/reference/Fpdf_SetLeftMargin_multicolumn.pdf new file mode 100644 index 0000000..6ba28c8 --- /dev/null +++ b/pdf/reference/Fpdf_SetLeftMargin_multicolumn.pdf @@ -0,0 +1,1082 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +0.000 G +0.000 g +BT /F0 15.00 Tf ET +0.000 0.314 0.706 RG +0.902 0.902 0.000 rg +2.83 w +179.09 813.54 237.10 -25.51 re B q 0.863 0.196 0.196 rg BT 187.59 796.28 Td (20000 Leagues Under the Seas) Tj ET Q +0.57 w +0.000 G +0.000 g +BT /F1 12.00 Tf ET +0.784 0.863 1.000 rg +28.35 759.68 538.58 -17.01 re f q 0.000 g BT 31.19 747.58 Td (Chapter 1 : A RUNAWAY REEF) Tj ET Q +BT /F2 12.00 Tf ET +1.853 Tw +q 0.000 g BT 31.19 720.65 Td (The year 1866 was marked by a) Tj ET Q +24.388 Tw +q 0.000 g BT 31.19 706.48 Td (bizarre development, an) Tj ET Q +16.546 Tw +q 0.000 g BT 31.19 692.30 Td (unexplained and downright) Tj ET Q +9.880 Tw +q 0.000 g BT 31.19 678.13 Td (inexplicable phenomenon that) Tj ET Q +7.691 Tw +q 0.000 g BT 31.19 663.96 Td (surely no one has forgotten.) Tj ET Q +0.434 Tw +q 0.000 g BT 31.19 649.78 Td (Without getting into those rumors) Tj ET Q +0.417 Tw +q 0.000 g BT 31.19 635.61 Td (that upset civilians in the seaports) Tj ET Q +5.441 Tw +q 0.000 g BT 31.19 621.44 Td (and deranged the public mind) Tj ET Q +2.793 Tw +q 0.000 g BT 31.19 607.26 Td (even far inland, it must be said) Tj ET Q +6.483 Tw +q 0.000 g BT 31.19 593.09 Td (that professional seamen were) Tj ET Q +14.560 Tw +q 0.000 g BT 31.19 578.92 Td (especially alarmed. Traders,) Tj ET Q +3.811 Tw +q 0.000 g BT 31.19 564.74 Td (shipowners, captains of vessels,) Tj ET Q +7.035 Tw +q 0.000 g BT 31.19 550.57 Td (skippers, and master mariners) Tj ET Q +1.697 Tw +q 0.000 g BT 31.19 536.40 Td (from Europe and America, naval) Tj ET Q +2.198 Tw +q 0.000 g BT 31.19 522.22 Td (officers from every country, and) Tj ET Q +1.087 Tw +q 0.000 g BT 31.19 508.05 Td (at their heels the various national) Tj ET Q +12.919 Tw +q 0.000 g BT 31.19 493.88 Td (governments on these two) Tj ET Q +6.591 Tw +q 0.000 g BT 31.19 479.70 Td (continents, were all extremely) Tj ET Q +0 Tw +q 0.000 g BT 31.19 465.53 Td (disturbed by the business.) Tj ET Q +1.353 Tw +q 0.000 g BT 31.19 451.36 Td (In essence, over a period of time) Tj ET Q +0.389 Tw +q 0.000 g BT 31.19 437.18 Td (several ships had encountered "an) Tj ET Q +3.772 Tw +q 0.000 g BT 31.19 423.01 Td (enormous thing" at sea, a long) Tj ET Q +1.378 Tw +q 0.000 g BT 31.19 408.84 Td (spindle-shaped object, sometimes) Tj ET Q +0.191 Tw +q 0.000 g BT 31.19 394.66 Td (giving off a phosphorescent glow,) Tj ET Q +3.275 Tw +q 0.000 g BT 31.19 380.49 Td (infinitely bigger and faster than) Tj ET Q +0 Tw +q 0.000 g BT 31.19 366.32 Td (any whale.) Tj ET Q +11.441 Tw +q 0.000 g BT 31.19 352.14 Td (The relevant data on this) Tj ET Q +1.028 Tw +q 0.000 g BT 31.19 337.97 Td (apparition, as recorded in various) Tj ET Q +0.359 Tw +q 0.000 g BT 31.19 323.80 Td (logbooks, agreed pretty closely as) Tj ET Q +2.739 Tw +q 0.000 g BT 31.19 309.63 Td (to the structure of the object or) Tj ET Q +17.475 Tw +q 0.000 g BT 31.19 295.45 Td (creature in question, its) Tj ET Q +25.558 Tw +q 0.000 g BT 31.19 281.28 Td (unprecedented speed of) Tj ET Q +27.034 Tw +q 0.000 g BT 31.19 267.11 Td (movement, its startling) Tj ET Q +0.191 Tw +q 0.000 g BT 31.19 252.93 Td (locomotive power, and the unique) Tj ET Q +2.548 Tw +q 0.000 g BT 31.19 238.76 Td (vitality with which it seemed to) Tj ET Q +1.057 Tw +q 0.000 g BT 31.19 224.59 Td (be gifted. If it was a cetacean, it) Tj ET Q +7.778 Tw +q 0.000 g BT 31.19 210.41 Td (exceeded in bulk any whale) Tj ET Q +1.526 Tw +q 0.000 g BT 31.19 196.24 Td (previously classified by science. ) Tj ET Q +2.024 Tw +q 0.000 g BT 31.19 182.07 Td (No naturalist, neither Cuvier nor) Tj ET Q +15.394 Tw +q 0.000 g BT 31.19 167.89 Td (Lacpde, neither Professor) Tj ET Q +14.255 Tw +q 0.000 g BT 31.19 153.72 Td (Dumeril nor Professor de) Tj ET Q +22.390 Tw +q 0.000 g BT 31.19 139.55 Td (Quatrefages, would have) Tj ET Q +2.159 Tw +q 0.000 g BT 31.19 125.37 Td (accepted the existence of such a) Tj ET Q +17.363 Tw +q 0.000 g BT 31.19 111.20 Td (monster sight unseen --) Tj ET Q +1.526 Tw +q 0.000 g BT 31.19 97.03 Td (specifically, unseen by their own) Tj ET Q +0 Tw +q 0.000 g BT 31.19 82.85 Td (scientific eyes.) Tj ET Q +19.367 Tw +q 0.000 g BT 31.19 68.68 Td (Striking an average of) Tj ET Q +6.259 Tw +q 0.000 g BT 215.43 720.65 Td (observations taken at different) Tj ET Q +6.437 Tw +q 0.000 g BT 215.43 706.48 Td (times -- rejecting those timid) Tj ET Q +2.954 Tw +q 0.000 g BT 215.43 692.30 Td (estimates that gave the object a) Tj ET Q +2.486 Tw +q 0.000 g BT 215.43 678.13 Td (length of 200 feet, and ignoring) Tj ET Q +1.112 Tw +q 0.000 g BT 215.43 663.96 Td (those exaggerated views that saw) Tj ET Q +6.405 Tw +q 0.000 g BT 215.43 649.78 Td (it as a mile wide and three) Tj ET Q +3.770 Tw +q 0.000 g BT 215.43 635.61 Td (long--you could still assert that) Tj ET Q +2.483 Tw +q 0.000 g BT 215.43 621.44 Td (this phenomenal creature greatly) Tj ET Q +10.479 Tw +q 0.000 g BT 215.43 607.26 Td (exceeded the dimensions of) Tj ET Q +16.915 Tw +q 0.000 g BT 215.43 593.09 Td (anything then known to) Tj ET Q +0 Tw +q 0.000 g BT 215.43 578.92 Td (ichthyologists, if it existed at all.) Tj ET Q +0.202 Tw +q 0.000 g BT 215.43 564.74 Td (Now then, it did exist, this was an) Tj ET Q +5.444 Tw +q 0.000 g BT 215.43 550.57 Td (undeniable fact; and since the) Tj ET Q +2.150 Tw +q 0.000 g BT 215.43 536.40 Td (human mind dotes on objects of) Tj ET Q +2.861 Tw +q 0.000 g BT 215.43 522.22 Td (wonder, you can understand the) Tj ET Q +2.259 Tw +q 0.000 g BT 215.43 508.05 Td (worldwide excitement caused by) Tj ET Q +2.690 Tw +q 0.000 g BT 215.43 493.88 Td (this unearthly apparition. As for) Tj ET Q +6.686 Tw +q 0.000 g BT 215.43 479.70 Td (relegating it to the realm of) Tj ET Q +5.421 Tw +q 0.000 g BT 215.43 465.53 Td (fiction, that charge had to be) Tj ET Q +0 Tw +q 0.000 g BT 215.43 451.36 Td (dropped.) Tj ET Q +1.349 Tw +q 0.000 g BT 215.43 437.18 Td (In essence, on July 20, 1866, the) Tj ET Q +11.050 Tw +q 0.000 g BT 215.43 423.01 Td (steamer Governor Higginson,) Tj ET Q +6.107 Tw +q 0.000 g BT 215.43 408.84 Td (from the Calcutta & Burnach) Tj ET Q +27.538 Tw +q 0.000 g BT 215.43 394.66 Td (Steam Navigation Co.,) Tj ET Q +6.251 Tw +q 0.000 g BT 215.43 380.49 Td (encountered this moving mass) Tj ET Q +2.289 Tw +q 0.000 g BT 215.43 366.32 Td (five miles off the eastern shores) Tj ET Q +5.192 Tw +q 0.000 g BT 215.43 352.14 Td (of Australia. Captain Baker at) Tj ET Q +7.883 Tw +q 0.000 g BT 215.43 337.97 Td (first thought he was in the) Tj ET Q +1.627 Tw +q 0.000 g BT 215.43 323.80 Td (presence of an unknown reef; he) Tj ET Q +3.183 Tw +q 0.000 g BT 215.43 309.63 Td (was even about to fix its exact) Tj ET Q +5.139 Tw +q 0.000 g BT 215.43 295.45 Td (position when two waterspouts) Tj ET Q +7.769 Tw +q 0.000 g BT 215.43 281.28 Td (shot out of this inexplicable) Tj ET Q +0.683 Tw +q 0.000 g BT 215.43 267.11 Td (object and sprang hissing into the) Tj ET Q +0.488 Tw +q 0.000 g BT 215.43 252.93 Td (air some 150 feet. So, unless this) Tj ET Q +14.276 Tw +q 0.000 g BT 215.43 238.76 Td (reef was subject to the) Tj ET Q +0.524 Tw +q 0.000 g BT 215.43 224.59 Td (intermittent eruptions of a geyser,) Tj ET Q +1.943 Tw +q 0.000 g BT 215.43 210.41 Td (the Governor Higginson had fair) Tj ET Q +4.271 Tw +q 0.000 g BT 215.43 196.24 Td (and honest dealings with some) Tj ET Q +11.027 Tw +q 0.000 g BT 215.43 182.07 Td (aquatic mammal, until then) Tj ET Q +3.188 Tw +q 0.000 g BT 215.43 167.89 Td (unknown, that could spurt from) Tj ET Q +2.471 Tw +q 0.000 g BT 215.43 153.72 Td (its blowholes waterspouts mixed) Tj ET Q +0 Tw +q 0.000 g BT 215.43 139.55 Td (with air and steam.) Tj ET Q +8.699 Tw +q 0.000 g BT 215.43 125.37 Td (Similar events were likewise) Tj ET Q +1.687 Tw +q 0.000 g BT 215.43 111.20 Td (observed in Pacific seas, on July) Tj ET Q +5.795 Tw +q 0.000 g BT 215.43 97.03 Td (23 of the same year, by the) Tj ET Q +3.803 Tw +q 0.000 g BT 215.43 82.85 Td (Christopher Columbus from the) Tj ET Q +7.607 Tw +q 0.000 g BT 215.43 68.68 Td (West India & Pacific Steam) Tj ET Q +5.359 Tw +q 0.000 g BT 399.69 720.65 Td (Navigation Co. Consequently,) Tj ET Q +1.819 Tw +q 0.000 g BT 399.69 706.48 Td (this extraordinary cetacean could) Tj ET Q +0.554 Tw +q 0.000 g BT 399.69 692.30 Td (transfer itself from one locality to) Tj ET Q +3.695 Tw +q 0.000 g BT 399.69 678.13 Td (another with startling swiftness,) Tj ET Q +3.751 Tw +q 0.000 g BT 399.69 663.96 Td (since within an interval of just) Tj ET Q +15.259 Tw +q 0.000 g BT 399.69 649.78 Td (three days, the Governor) Tj ET Q +5.583 Tw +q 0.000 g BT 399.69 635.61 Td (Higginson and the Christopher) Tj ET Q +1.216 Tw +q 0.000 g BT 399.69 621.44 Td (Columbus had observed it at two) Tj ET Q +2.108 Tw +q 0.000 g BT 399.69 607.26 Td (positions on the charts separated) Tj ET Q +2.739 Tw +q 0.000 g BT 399.69 593.09 Td (by a distance of more than 700) Tj ET Q +0 Tw +q 0.000 g BT 399.69 578.92 Td (nautical leagues.) Tj ET Q +7.691 Tw +q 0.000 g BT 399.69 564.74 Td (Fifteen days later and 2,000) Tj ET Q +0.698 Tw +q 0.000 g BT 399.69 550.57 Td (leagues farther, the Helvetia from) Tj ET Q +0.941 Tw +q 0.000 g BT 399.69 536.40 Td (the Compagnie Nationale and the) Tj ET Q +5.270 Tw +q 0.000 g BT 399.69 522.22 Td (Shannon from the Royal Mail) Tj ET Q +0.883 Tw +q 0.000 g BT 399.69 508.05 Td (line, running on opposite tacks in) Tj ET Q +4.951 Tw +q 0.000 g BT 399.69 493.88 Td (that part of the Atlantic lying) Tj ET Q +4.775 Tw +q 0.000 g BT 399.69 479.70 Td (between the United States and) Tj ET Q +11.386 Tw +q 0.000 g BT 399.69 465.53 Td (Europe, respectively signaled) Tj ET Q +2.822 Tw +q 0.000 g BT 399.69 451.36 Td (each other that the monster had) Tj ET Q +9.437 Tw +q 0.000 g BT 399.69 437.18 Td (been sighted in latitude 42) Tj ET Q +3.401 Tw +q 0.000 g BT 399.69 423.01 Td (degrees 15' north and longitude) Tj ET Q +7.989 Tw +q 0.000 g BT 399.69 408.84 Td (60 degrees 35' west of the) Tj ET Q +4.526 Tw +q 0.000 g BT 399.69 394.66 Td (meridian of Greenwich. From) Tj ET Q +4.708 Tw +q 0.000 g BT 399.69 380.49 Td (their simultaneous observations,) Tj ET Q +4.288 Tw +q 0.000 g BT 399.69 366.32 Td (they were able to estimate the) Tj ET Q +7.079 Tw +q 0.000 g BT 399.69 352.14 Td (mammal's minimum length at) Tj ET Q +2.150 Tw +q 0.000 g BT 399.69 337.97 Td (more than 350 English feet; this) Tj ET Q +4.442 Tw +q 0.000 g BT 399.69 323.80 Td (was because both the Shannon) Tj ET Q +1.624 Tw +q 0.000 g BT 399.69 309.63 Td (and the Helvetia were of smaller) Tj ET Q +18.376 Tw +q 0.000 g BT 399.69 295.45 Td (dimensions, although each) Tj ET Q +6.107 Tw +q 0.000 g BT 399.69 281.28 Td (measured 100 meters stem to) Tj ET Q +7.439 Tw +q 0.000 g BT 399.69 267.11 Td (stern. Now then, the biggest) Tj ET Q +1.193 Tw +q 0.000 g BT 399.69 252.93 Td (whales, those rorqual whales that) Tj ET Q +5.447 Tw +q 0.000 g BT 399.69 238.76 Td (frequent the waterways of the) Tj ET Q +9.259 Tw +q 0.000 g BT 399.69 224.59 Td (Aleutian Islands, have never) Tj ET Q +0.026 Tw +q 0.000 g BT 399.69 210.41 Td (exceeded a length of 56 meters--if) Tj ET Q +0 Tw +q 0.000 g BT 399.69 196.24 Td (they reach even that.) Tj ET Q +1.034 Tw +q 0.000 g BT 399.69 182.07 Td (One after another, reports arrived) Tj ET Q +8.923 Tw +q 0.000 g BT 399.69 167.89 Td (that would profoundly affect) Tj ET Q +0.437 Tw +q 0.000 g BT 399.69 153.72 Td (public opinion: new observations) Tj ET Q +4.775 Tw +q 0.000 g BT 399.69 139.55 Td (taken by the transatlantic liner) Tj ET Q +5.819 Tw +q 0.000 g BT 399.69 125.37 Td (Pereire, the Inman line's Etna) Tj ET Q +1.953 Tw +q 0.000 g BT 399.69 111.20 Td (running afoul of the monster, an) Tj ET Q +8.777 Tw +q 0.000 g BT 399.69 97.03 Td (official report drawn up by) Tj ET Q +6.113 Tw +q 0.000 g BT 399.69 82.85 Td (officers on the French frigate) Tj ET Q +46.449 Tw +q 0.000 g BT 399.69 68.68 Td (Normandy, dead-earnest) Tj ET Q +11.587 Tw +0 Tw +BT /F3 8.00 Tf ET +q 0.502 g BT 284.96 25.95 Td (Page 1) Tj ET Q + +endstream +endobj +5 0 obj +<> +endobj +6 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F2 12.00 Tf ET +0.000 G +0.784 0.863 1.000 rg +BT /F0 15.00 Tf ET +0.000 0.314 0.706 RG +0.902 0.902 0.000 rg +2.83 w +179.09 813.54 237.10 -25.51 re B q 0.863 0.196 0.196 rg BT 187.59 796.28 Td (20000 Leagues Under the Seas) Tj ET Q +0.57 w +BT /F2 12.00 Tf ET +0.000 G +0.784 0.863 1.000 rg +11.587 Tw +q 0.000 g BT 31.18 749.00 Td (reckonings obtained by the) Tj ET Q +9.591 Tw +q 0.000 g BT 31.18 734.82 Td (general staff of Commodore) Tj ET Q +10.923 Tw +q 0.000 g BT 31.18 720.65 Td (Fitz-James aboard the Lord) Tj ET Q +3.143 Tw +q 0.000 g BT 31.18 706.48 Td (Clyde. In lighthearted countries,) Tj ET Q +17.583 Tw +q 0.000 g BT 31.18 692.30 Td (people joked about this) Tj ET Q +5.363 Tw +q 0.000 g BT 31.18 678.13 Td (phenomenon, but such serious,) Tj ET Q +5.703 Tw +q 0.000 g BT 31.18 663.96 Td (practical countries as England,) Tj ET Q +8.599 Tw +q 0.000 g BT 31.18 649.78 Td (America, and Germany were) Tj ET Q +0 Tw +q 0.000 g BT 31.18 635.61 Td (deeply concerned.) Tj ET Q +0.739 Tw +q 0.000 g BT 31.18 621.44 Td (In every big city the monster was) Tj ET Q +1.071 Tw +q 0.000 g BT 31.18 607.26 Td (the latest rage; they sang about it) Tj ET Q +10.526 Tw +q 0.000 g BT 31.18 593.09 Td (in the coffee houses, they) Tj ET Q +5.024 Tw +q 0.000 g BT 31.18 578.92 Td (ridiculed it in the newspapers,) Tj ET Q +0.239 Tw +q 0.000 g BT 31.18 564.74 Td (they dramatized it in the theaters. ) Tj ET Q +6.818 Tw +q 0.000 g BT 31.18 550.57 Td (The tabloids found it a fine) Tj ET Q +1.604 Tw +q 0.000 g BT 31.18 536.40 Td (opportunity for hatching all sorts) Tj ET Q +3.695 Tw +q 0.000 g BT 31.18 522.22 Td (of hoaxes. In those newspapers) Tj ET Q +7.552 Tw +q 0.000 g BT 31.18 508.05 Td (short of copy, you saw the) Tj ET Q +5.603 Tw +q 0.000 g BT 31.18 493.88 Td (reappearance of every gigantic) Tj ET Q +2.739 Tw +q 0.000 g BT 31.18 479.70 Td (imaginary creature, from "Moby) Tj ET Q +1.970 Tw +q 0.000 g BT 31.18 465.53 Td (Dick," that dreadful white whale) Tj ET Q +1.953 Tw +q 0.000 g BT 31.18 451.36 Td (from the High Arctic regions, to) Tj ET Q +7.811 Tw +q 0.000 g BT 31.18 437.18 Td (the stupendous kraken whose) Tj ET Q +0.776 Tw +q 0.000 g BT 31.18 423.01 Td (tentacles could entwine a 500-ton) Tj ET Q +2.963 Tw +q 0.000 g BT 31.18 408.84 Td (craft and drag it into the ocean) Tj ET Q +10.147 Tw +q 0.000 g BT 31.18 394.66 Td (depths. They even reprinted) Tj ET Q +4.274 Tw +q 0.000 g BT 31.18 380.49 Td (reports from ancient times: the) Tj ET Q +7.436 Tw +q 0.000 g BT 31.18 366.32 Td (views of Aristotle and Pliny) Tj ET Q +3.779 Tw +q 0.000 g BT 31.18 352.14 Td (accepting the existence of such) Tj ET Q +6.811 Tw +q 0.000 g BT 31.18 337.97 Td (monsters, then the Norwegian) Tj ET Q +5.467 Tw +q 0.000 g BT 31.18 323.80 Td (stories of Bishop Pontoppidan,) Tj ET Q +1.156 Tw +q 0.000 g BT 31.18 309.63 Td (the narratives of Paul Egede, and) Tj ET Q +6.440 Tw +q 0.000 g BT 31.18 295.45 Td (finally the reports of Captain) Tj ET Q +0.820 Tw +q 0.000 g BT 31.18 281.28 Td (Harrington -- whose good faith is) Tj ET Q +7.811 Tw +q 0.000 g BT 31.18 267.11 Td (above suspicion--in which he) Tj ET Q +2.222 Tw +q 0.000 g BT 31.18 252.93 Td (claims he saw, while aboard the) Tj ET Q +3.549 Tw +q 0.000 g BT 31.18 238.76 Td (Castilian in 1857, one of those) Tj ET Q +8.583 Tw +q 0.000 g BT 31.18 224.59 Td (enormous serpents that, until) Tj ET Q +0.223 Tw +q 0.000 g BT 31.18 210.41 Td (then, had frequented only the seas) Tj ET Q +15.311 Tw +q 0.000 g BT 31.18 196.24 Td (of France's old extremist) Tj ET Q +0 Tw +q 0.000 g BT 31.18 182.07 Td (newspaper, The Constitutionalist.) Tj ET Q +BT /F4 12.00 Tf ET +q 0.000 g BT 31.18 153.72 Td (\(end of excerpt\)) Tj ET Q +BT /F3 8.00 Tf ET +q 0.502 g BT 284.96 25.95 Td (Page 2) Tj ET Q + +endstream +endobj +7 0 obj +<> +endobj +8 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F4 12.00 Tf ET +0.000 G +0.784 0.863 1.000 rg +BT /F0 15.00 Tf ET +0.000 0.314 0.706 RG +0.902 0.902 0.000 rg +2.83 w +179.09 813.54 237.10 -25.51 re B q 0.863 0.196 0.196 rg BT 187.59 796.28 Td (20000 Leagues Under the Seas) Tj ET Q +0.57 w +BT /F4 12.00 Tf ET +0.000 G +0.784 0.863 1.000 rg +BT /F1 12.00 Tf ET +0.784 0.863 1.000 rg +28.35 759.68 538.58 -17.01 re f q 0.000 g BT 31.18 747.58 Td (Chapter 2 : THE PROS AND CONS) Tj ET Q +BT /F2 12.00 Tf ET +1.353 Tw +q 0.000 g BT 31.18 720.65 Td (During the period in which these) Tj ET Q +4.151 Tw +q 0.000 g BT 31.18 706.48 Td (developments were occurring, I) Tj ET Q +5.612 Tw +q 0.000 g BT 31.18 692.30 Td (had returned from a scientific) Tj ET Q +1.815 Tw +q 0.000 g BT 31.18 678.13 Td (undertaking organized to explore) Tj ET Q +6.443 Tw +q 0.000 g BT 31.18 663.96 Td (the Nebraska badlands in the) Tj ET Q +1.953 Tw +q 0.000 g BT 31.18 649.78 Td (United States. In my capacity as) Tj ET Q +3.938 Tw +q 0.000 g BT 31.18 635.61 Td (Assistant Professor at the Paris) Tj ET Q +0.220 Tw +q 0.000 g BT 31.18 621.44 Td (Museum of Natural History, I had) Tj ET Q +3.107 Tw +q 0.000 g BT 31.18 607.26 Td (been attached to this expedition) Tj ET Q +1.694 Tw +q 0.000 g BT 31.18 593.09 Td (by the French government. After) Tj ET Q +0.521 Tw +q 0.000 g BT 31.18 578.92 Td (spending six months in Nebraska,) Tj ET Q +0.741 Tw +q 0.000 g BT 31.18 564.74 Td (I arrived in New York laden with) Tj ET Q +1.778 Tw +q 0.000 g BT 31.18 550.57 Td (valuable collections near the end) Tj ET Q +8.030 Tw +q 0.000 g BT 31.18 536.40 Td (of March. My departure for) Tj ET Q +1.465 Tw +q 0.000 g BT 31.18 522.22 Td (France was set for early May. In) Tj ET Q +3.086 Tw +q 0.000 g BT 31.18 508.05 Td (the meantime, then, I was busy) Tj ET Q +11.044 Tw +q 0.000 g BT 31.18 493.88 Td (classifying my mineralogical,) Tj ET Q +22.048 Tw +q 0.000 g BT 31.18 479.70 Td (botanical, and zoological) Tj ET Q +1.442 Tw +q 0.000 g BT 31.18 465.53 Td (treasures when that incident took) Tj ET Q +0 Tw +q 0.000 g BT 31.18 451.36 Td (place with the Scotia.) Tj ET Q +4.557 Tw +q 0.000 g BT 31.18 437.18 Td (I was perfectly abreast of this) Tj ET Q +0.619 Tw +q 0.000 g BT 31.18 423.01 Td (question, which was the big news) Tj ET Q +2.062 Tw +q 0.000 g BT 31.18 408.84 Td (of the day, and how could I not) Tj ET Q +1.081 Tw +q 0.000 g BT 31.18 394.66 Td (have been? I had read and reread) Tj ET Q +6.043 Tw +q 0.000 g BT 31.18 380.49 Td (every American and European) Tj ET Q +7.811 Tw +q 0.000 g BT 31.18 366.32 Td (newspaper without being any) Tj ET Q +11.255 Tw +q 0.000 g BT 31.18 352.14 Td (farther along. This mystery) Tj ET Q +0.350 Tw +q 0.000 g BT 31.18 337.97 Td (puzzled me. Finding it impossible) Tj ET Q +1.017 Tw +q 0.000 g BT 31.18 323.80 Td (to form any views, I drifted from) Tj ET Q +11.192 Tw +q 0.000 g BT 31.18 309.63 Td (one extreme to the other.) Tj ET Q +5.354 Tw +q 0.000 g BT 31.18 295.45 Td (Something was out there, that) Tj ET Q +9.194 Tw +q 0.000 g BT 31.18 281.28 Td (much was certain, and any) Tj ET Q +2.435 Tw +q 0.000 g BT 31.18 267.11 Td (doubting Thomas was invited to) Tj ET Q +3.587 Tw +q 0.000 g BT 31.18 252.93 Td (place his finger on the Scotia's) Tj ET Q +0 Tw +q 0.000 g BT 31.18 238.76 Td (wound.) Tj ET Q +0.909 Tw +q 0.000 g BT 31.18 224.59 Td (When I arrived in New York, the) Tj ET Q +1.015 Tw +q 0.000 g BT 31.18 210.41 Td (question was at the boiling point.) Tj ET Q +1.617 Tw +q 0.000 g BT 31.18 196.24 Td (The hypothesis of a drifting islet) Tj ET Q +0.687 Tw +q 0.000 g BT 31.18 182.07 Td (or an elusive reef, put forward by) Tj ET Q +4.816 Tw +q 0.000 g BT 31.18 167.89 Td (people not quite in their right) Tj ET Q +27.040 Tw +q 0.000 g BT 31.18 153.72 Td (minds, was completely) Tj ET Q +5.363 Tw +q 0.000 g BT 31.18 139.55 Td (eliminated. And indeed, unless) Tj ET Q +4.849 Tw +q 0.000 g BT 31.18 125.37 Td (this reef had an engine in its) Tj ET Q +3.016 Tw +q 0.000 g BT 31.18 111.20 Td (belly, how could it move about) Tj ET Q +0 Tw +q 0.000 g BT 31.18 97.03 Td (with such prodigious speed?) Tj ET Q +0.407 Tw +q 0.000 g BT 31.18 82.85 Td (Also discredited was the idea of a) Tj ET Q +9.104 Tw +q 0.000 g BT 31.18 68.68 Td (floating hull or some other) Tj ET Q +5.263 Tw +q 0.000 g BT 215.43 720.65 Td (enormous wreckage, and again) Tj ET Q +12.443 Tw +q 0.000 g BT 215.43 706.48 Td (because of this speed of) Tj ET Q +0 Tw +q 0.000 g BT 215.43 692.30 Td (movement.) Tj ET Q +1.077 Tw +q 0.000 g BT 215.43 678.13 Td (So only two possible solutions to) Tj ET Q +4.028 Tw +q 0.000 g BT 215.43 663.96 Td (the question were left, creating) Tj ET Q +8.771 Tw +q 0.000 g BT 215.43 649.78 Td (two very distinct groups of) Tj ET Q +5.522 Tw +q 0.000 g BT 215.43 635.61 Td (supporters: on one side, those) Tj ET Q +4.775 Tw +q 0.000 g BT 215.43 621.44 Td (favoring a monster of colossal) Tj ET Q +7.688 Tw +q 0.000 g BT 215.43 607.26 Td (strength; on the other, those) Tj ET Q +1.499 Tw +q 0.000 g BT 215.43 593.09 Td (favoring an "underwater boat" of) Tj ET Q +0 Tw +q 0.000 g BT 215.43 578.92 Td (tremendous motor power.) Tj ET Q +6.023 Tw +q 0.000 g BT 215.43 564.74 Td (Now then, although the latter) Tj ET Q +17.542 Tw +q 0.000 g BT 215.43 550.57 Td (hypothesis was completely) Tj ET Q +0.715 Tw +q 0.000 g BT 215.43 536.40 Td (admissible, it couldn't stand up to) Tj ET Q +3.938 Tw +q 0.000 g BT 215.43 522.22 Td (inquiries conducted in both the) Tj ET Q +2.129 Tw +q 0.000 g BT 215.43 508.05 Td (New World and the Old. That a) Tj ET Q +6.440 Tw +q 0.000 g BT 215.43 493.88 Td (private individual had such a) Tj ET Q +4.271 Tw +q 0.000 g BT 215.43 479.70 Td (mechanism at his disposal was) Tj ET Q +4.862 Tw +q 0.000 g BT 215.43 465.53 Td (less than probable. Where and) Tj ET Q +3.681 Tw +q 0.000 g BT 215.43 451.36 Td (when had he built it, and how) Tj ET Q +0 Tw +q 0.000 g BT 215.43 437.18 Td (could he have built it in secret?) Tj ET Q +7.363 Tw +q 0.000 g BT 215.43 423.01 Td (Only some government could) Tj ET Q +14.108 Tw +q 0.000 g BT 215.43 408.84 Td (own such an engine of) Tj ET Q +15.919 Tw +q 0.000 g BT 215.43 394.66 Td (destruction, and in these) Tj ET Q +4.587 Tw +q 0.000 g BT 215.43 380.49 Td (disaster-filled times, when men) Tj ET Q +9.101 Tw +q 0.000 g BT 215.43 366.32 Td (tax their ingenuity to build) Tj ET Q +2.890 Tw +q 0.000 g BT 215.43 352.14 Td (increasingly powerful aggressive) Tj ET Q +5.438 Tw +q 0.000 g BT 215.43 337.97 Td (weapons, it was possible that,) Tj ET Q +0.793 Tw +q 0.000 g BT 215.43 323.80 Td (unknown to the rest of the world,) Tj ET Q +6.275 Tw +q 0.000 g BT 215.43 309.63 Td (some nation could have been) Tj ET Q +1.361 Tw +q 0.000 g BT 215.43 295.45 Td (testing such a fearsome machine.) Tj ET Q +4.552 Tw +q 0.000 g BT 215.43 281.28 Td (The Chassepot rifle led to the) Tj ET Q +2.087 Tw +q 0.000 g BT 215.43 267.11 Td (torpedo, and the torpedo has led) Tj ET Q +1.859 Tw +q 0.000 g BT 215.43 252.93 Td (to this underwater battering ram,) Tj ET Q +4.291 Tw +q 0.000 g BT 215.43 238.76 Td (which in turn will lead to the) Tj ET Q +3.014 Tw +q 0.000 g BT 215.43 224.59 Td (world putting its foot down. At) Tj ET Q +0 Tw +q 0.000 g BT 215.43 210.41 Td (least I hope it will.) Tj ET Q +6.016 Tw +q 0.000 g BT 215.43 196.24 Td (But this hypothesis of a war) Tj ET Q +1.891 Tw +q 0.000 g BT 215.43 182.07 Td (machine collapsed in the face of) Tj ET Q +3.275 Tw +q 0.000 g BT 215.43 167.89 Td (formal denials from the various) Tj ET Q +6.363 Tw +q 0.000 g BT 215.43 153.72 Td (governments. Since the public) Tj ET Q +11.942 Tw +q 0.000 g BT 215.43 139.55 Td (interest was at stake and) Tj ET Q +1.043 Tw +q 0.000 g BT 215.43 125.37 Td (transoceanic travel was suffering,) Tj ET Q +21.587 Tw +q 0.000 g BT 215.43 111.20 Td (the sincerity of these) Tj ET Q +13.363 Tw +q 0.000 g BT 215.43 97.03 Td (governments could not be) Tj ET Q +2.105 Tw +q 0.000 g BT 215.43 82.85 Td (doubted. Besides, how could the) Tj ET Q +1.442 Tw +q 0.000 g BT 215.43 68.68 Td (assembly of this underwater boat) Tj ET Q +10.039 Tw +q 0.000 g BT 399.69 720.65 Td (have escaped public notice?) Tj ET Q +7.280 Tw +q 0.000 g BT 399.69 706.48 Td (Keeping a secret under such) Tj ET Q +2.479 Tw +q 0.000 g BT 399.69 692.30 Td (circumstances would be difficult) Tj ET Q +5.690 Tw +q 0.000 g BT 399.69 678.13 Td (enough for an individual, and) Tj ET Q +2.273 Tw +q 0.000 g BT 399.69 663.96 Td (certainly impossible for a nation) Tj ET Q +8.276 Tw +q 0.000 g BT 399.69 649.78 Td (whose every move is under) Tj ET Q +7.811 Tw +q 0.000 g BT 399.69 635.61 Td (constant surveillance by rival) Tj ET Q +0 Tw +q 0.000 g BT 399.69 621.44 Td (powers.) Tj ET Q +3.524 Tw +q 0.000 g BT 399.69 607.26 Td (So, after inquiries conducted in) Tj ET Q +1.363 Tw +q 0.000 g BT 399.69 593.09 Td (England, France, Russia, Prussia,) Tj ET Q +3.194 Tw +q 0.000 g BT 399.69 578.92 Td (Spain, Italy, America, and even) Tj ET Q +6.857 Tw +q 0.000 g BT 399.69 564.74 Td (Turkey, the hypothesis of an) Tj ET Q +23.218 Tw +q 0.000 g BT 399.69 550.57 Td (underwater Monitor was) Tj ET Q +0 Tw +q 0.000 g BT 399.69 536.40 Td (ultimately rejected.) Tj ET Q +5.291 Tw +q 0.000 g BT 399.69 522.22 Td (After I arrived in New York,) Tj ET Q +2.155 Tw +q 0.000 g BT 399.69 508.05 Td (several people did me the honor) Tj ET Q +12.770 Tw +q 0.000 g BT 399.69 493.88 Td (of consulting me on the) Tj ET Q +10.139 Tw +q 0.000 g BT 399.69 479.70 Td (phenomenon in question. In) Tj ET Q +11.609 Tw +q 0.000 g BT 399.69 465.53 Td (France I had published a) Tj ET Q +8.919 Tw +q 0.000 g BT 399.69 451.36 Td (two-volume work, in quarto,) Tj ET Q +6.440 Tw +q 0.000 g BT 399.69 437.18 Td (entitled The Mysteries of the) Tj ET Q +12.595 Tw +q 0.000 g BT 399.69 423.01 Td (Great Ocean Depths. Well) Tj ET Q +1.694 Tw +q 0.000 g BT 399.69 408.84 Td (received in scholarly circles, this) Tj ET Q +4.953 Tw +q 0.000 g BT 399.69 394.66 Td (book had established me as a) Tj ET Q +3.938 Tw +q 0.000 g BT 399.69 380.49 Td (specialist in this pretty obscure) Tj ET Q +0.619 Tw +q 0.000 g BT 399.69 366.32 Td (field of natural history. My views) Tj ET Q +4.017 Tw +q 0.000 g BT 399.69 352.14 Td (were in demand. As long as I) Tj ET Q +5.887 Tw +q 0.000 g BT 399.69 337.97 Td (could deny the reality of the) Tj ET Q +2.486 Tw +q 0.000 g BT 399.69 323.80 Td (business, I confined myself to a) Tj ET Q +5.987 Tw +q 0.000 g BT 399.69 309.63 Td (flat "no comment." But soon,) Tj ET Q +5.903 Tw +q 0.000 g BT 399.69 295.45 Td (pinned to the wall, I had to) Tj ET Q +2.354 Tw +q 0.000 g BT 399.69 281.28 Td (explain myself straight out. And) Tj ET Q +0.573 Tw +q 0.000 g BT 399.69 267.11 Td (in this vein, "the honorable Pierre) Tj ET Q +3.692 Tw +q 0.000 g BT 399.69 252.93 Td (Aronnax, Professor at the Paris) Tj ET Q +0.131 Tw +q 0.000 g BT 399.69 238.76 Td (Museum," was summoned by The) Tj ET Q +4.112 Tw +q 0.000 g BT 399.69 224.59 Td (New York Herald to formulate) Tj ET Q +0 Tw +q 0.000 g BT 399.69 210.41 Td (his views no matter what.) Tj ET Q +5.685 Tw +q 0.000 g BT 399.69 196.24 Td (I complied. Since I could no) Tj ET Q +3.457 Tw +q 0.000 g BT 399.69 182.07 Td (longer hold my tongue, I let it) Tj ET Q +2.351 Tw +q 0.000 g BT 399.69 167.89 Td (wag. I discussed the question in) Tj ET Q +0.086 Tw +q 0.000 g BT 399.69 153.72 Td (its every aspect, both political and) Tj ET Q +2.620 Tw +q 0.000 g BT 399.69 139.55 Td (scientific, and this is an excerpt) Tj ET Q +5.279 Tw +q 0.000 g BT 399.69 125.37 Td (from the well-padded article I) Tj ET Q +0 Tw +q 0.000 g BT 399.69 111.20 Td (published in the issue of April 30.) Tj ET Q +11.371 Tw +q 0.000 g BT 399.69 82.85 Td ("Therefore," I wrote, "after) Tj ET Q +20.884 Tw +q 0.000 g BT 399.69 68.68 Td (examining these different) Tj ET Q +3.556 Tw +0 Tw +BT /F3 8.00 Tf ET +q 0.502 g BT 284.96 25.95 Td (Page 3) Tj ET Q + +endstream +endobj +9 0 obj +<> +endobj +10 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F2 12.00 Tf ET +0.000 G +0.784 0.863 1.000 rg +BT /F0 15.00 Tf ET +0.000 0.314 0.706 RG +0.902 0.902 0.000 rg +2.83 w +179.09 813.54 237.10 -25.51 re B q 0.863 0.196 0.196 rg BT 187.59 796.28 Td (20000 Leagues Under the Seas) Tj ET Q +0.57 w +BT /F2 12.00 Tf ET +0.000 G +0.784 0.863 1.000 rg +3.556 Tw +q 0.000 g BT 31.18 749.00 Td (hypotheses one by one, we are) Tj ET Q +5.035 Tw +q 0.000 g BT 31.18 734.82 Td (forced, every other supposition) Tj ET Q +0.491 Tw +q 0.000 g BT 31.18 720.65 Td (having been refuted, to accept the) Tj ET Q +13.815 Tw +q 0.000 g BT 31.18 706.48 Td (existence of an extremely) Tj ET Q +0 Tw +q 0.000 g BT 31.18 692.30 Td (powerful marine animal.) Tj ET Q +2.779 Tw +q 0.000 g BT 31.18 678.13 Td ("The deepest parts of the ocean) Tj ET Q +4.351 Tw +q 0.000 g BT 31.18 663.96 Td (are totally unknown to us. No) Tj ET Q +0.023 Tw +q 0.000 g BT 31.18 649.78 Td (soundings have been able to reach) Tj ET Q +5.551 Tw +q 0.000 g BT 31.18 635.61 Td (them. What goes on in those) Tj ET Q +5.815 Tw +q 0.000 g BT 31.18 621.44 Td (distant depths? What creatures) Tj ET Q +4.436 Tw +q 0.000 g BT 31.18 607.26 Td (inhabit, or could inhabit, those) Tj ET Q +4.442 Tw +q 0.000 g BT 31.18 593.09 Td (regions twelve or fifteen miles) Tj ET Q +1.228 Tw +q 0.000 g BT 31.18 578.92 Td (beneath the surface of the water?) Tj ET Q +1.883 Tw +q 0.000 g BT 31.18 564.74 Td (What is the constitution of these) Tj ET Q +10.419 Tw +q 0.000 g BT 31.18 550.57 Td (animals? It's almost beyond) Tj ET Q +0 Tw +q 0.000 g BT 31.18 536.40 Td (conjecture.) Tj ET Q +5.129 Tw +q 0.000 g BT 31.18 522.22 Td ("However, the solution to this) Tj ET Q +0.285 Tw +q 0.000 g BT 31.18 508.05 Td (problem submitted to me can take) Tj ET Q +0.631 Tw +q 0.000 g BT 31.18 493.88 Td (the form of a choice between two) Tj ET Q +0 Tw +q 0.000 g BT 31.18 479.70 Td (alternatives.) Tj ET Q +0.911 Tw +q 0.000 g BT 31.18 465.53 Td ("Either we know every variety of) Tj ET Q +1.028 Tw +q 0.000 g BT 31.18 451.36 Td (creature populating our planet, or) Tj ET Q +0 Tw +q 0.000 g BT 31.18 437.18 Td (we do not.) Tj ET Q +1.222 Tw +q 0.000 g BT 31.18 423.01 Td ("If we do not know every one of) Tj ET Q +10.688 Tw +q 0.000 g BT 31.18 408.84 Td (them, if nature still keeps) Tj ET Q +5.699 Tw +q 0.000 g BT 31.18 394.66 Td (ichthyological secrets from us,) Tj ET Q +2.768 Tw +q 0.000 g BT 31.18 380.49 Td (nothing is more admissible than) Tj ET Q +1.519 Tw +q 0.000 g BT 31.18 366.32 Td (to accept the existence of fish or) Tj ET Q +1.228 Tw +q 0.000 g BT 31.18 352.14 Td (cetaceans of new species or even) Tj ET Q +8.360 Tw +q 0.000 g BT 31.18 337.97 Td (new genera, animals with a) Tj ET Q +6.382 Tw +q 0.000 g BT 31.18 323.80 Td (basically 'cast-iron' constitution) Tj ET Q +6.272 Tw +q 0.000 g BT 31.18 309.63 Td (that inhabit strata beyond the) Tj ET Q +7.859 Tw +q 0.000 g BT 31.18 295.45 Td (reach of our soundings, and) Tj ET Q +9.587 Tw +q 0.000 g BT 31.18 281.28 Td (which some development or) Tj ET Q +2.158 Tw +q 0.000 g BT 31.18 267.11 Td (other, an urge or a whim if you) Tj ET Q +4.891 Tw +q 0.000 g BT 31.18 252.93 Td (prefer, can bring to the upper) Tj ET Q +7.622 Tw +q 0.000 g BT 31.18 238.76 Td (level of the ocean for long) Tj ET Q +0 Tw +q 0.000 g BT 31.18 224.59 Td (intervals.) Tj ET Q +4.479 Tw +q 0.000 g BT 31.18 210.41 Td ("If, on the other hand, we do) Tj ET Q +4.859 Tw +q 0.000 g BT 31.18 196.24 Td (know every living species, we) Tj ET Q +6.815 Tw +q 0.000 g BT 31.18 182.07 Td (must look for the animal in) Tj ET Q +7.807 Tw +q 0.000 g BT 31.18 167.89 Td (question among those marine) Tj ET Q +3.491 Tw +q 0.000 g BT 31.18 153.72 Td (creatures already cataloged, and) Tj ET Q +1.625 Tw +q 0.000 g BT 31.18 139.55 Td (in this event I would be inclined) Tj ET Q +1.297 Tw +q 0.000 g BT 31.18 125.37 Td (to accept the existence of a giant) Tj ET Q +0 Tw +q 0.000 g BT 31.18 111.20 Td (narwhale.) Tj ET Q +3.638 Tw +q 0.000 g BT 31.18 97.03 Td ("The common narwhale, or sea) Tj ET Q +0.758 Tw +q 0.000 g BT 31.18 82.85 Td (unicorn, often reaches a length of) Tj ET Q +0.524 Tw +q 0.000 g BT 31.18 68.68 Td (sixty feet. Increase its dimensions) Tj ET Q +0.088 Tw +q 0.000 g BT 215.43 749.00 Td (fivefold or even tenfold, then give) Tj ET Q +10.109 Tw +q 0.000 g BT 215.43 734.82 Td (this cetacean a strength in) Tj ET Q +8.936 Tw +q 0.000 g BT 215.43 720.65 Td (proportion to its size while) Tj ET Q +3.035 Tw +q 0.000 g BT 215.43 706.48 Td (enlarging its offensive weapons,) Tj ET Q +3.724 Tw +q 0.000 g BT 215.43 692.30 Td (and you have the animal we're) Tj ET Q +4.219 Tw +q 0.000 g BT 215.43 678.13 Td (looking for. It would have the) Tj ET Q +6.475 Tw +q 0.000 g BT 215.43 663.96 Td (proportions determined by the) Tj ET Q +7.859 Tw +q 0.000 g BT 215.43 649.78 Td (officers of the Shannon, the) Tj ET Q +5.815 Tw +q 0.000 g BT 215.43 635.61 Td (instrument needed to perforate) Tj ET Q +6.086 Tw +q 0.000 g BT 215.43 621.44 Td (the Scotia, and the power to) Tj ET Q +0 Tw +q 0.000 g BT 215.43 607.26 Td (pierce a steamer's hull.) Tj ET Q +7.805 Tw +q 0.000 g BT 215.43 593.09 Td ("In essence, the narwhale is) Tj ET Q +0.683 Tw +q 0.000 g BT 215.43 578.92 Td (armed with a sort of ivory sword,) Tj ET Q +5.528 Tw +q 0.000 g BT 215.43 564.74 Td (or lance, as certain naturalists) Tj ET Q +0.057 Tw +q 0.000 g BT 215.43 550.57 Td (have expressed it. It's a king-sized) Tj ET Q +3.015 Tw +q 0.000 g BT 215.43 536.40 Td (tooth as hard as steel. Some of) Tj ET Q +7.778 Tw +q 0.000 g BT 215.43 522.22 Td (these teeth have been found) Tj ET Q +4.420 Tw +q 0.000 g BT 215.43 508.05 Td (buried in the bodies of baleen) Tj ET Q +10.371 Tw +q 0.000 g BT 215.43 493.88 Td (whales, which the narwhale) Tj ET Q +4.591 Tw +q 0.000 g BT 215.43 479.70 Td (attacks with invariable success.) Tj ET Q +2.531 Tw +q 0.000 g BT 215.43 465.53 Td (Others have been wrenched, not) Tj ET Q +11.027 Tw +q 0.000 g BT 215.43 451.36 Td (without difficulty, from the) Tj ET Q +14.031 Tw +q 0.000 g BT 215.43 437.18 Td (undersides of vessels that) Tj ET Q +7.823 Tw +q 0.000 g BT 215.43 423.01 Td (narwhales have pierced clean) Tj ET Q +4.754 Tw +q 0.000 g BT 215.43 408.84 Td (through, as a gimlet pierces a) Tj ET Q +2.488 Tw +q 0.000 g BT 215.43 394.66 Td (wine barrel. The museum at the) Tj ET Q +6.938 Tw +q 0.000 g BT 215.43 380.49 Td (Faculty of Medicine in Paris) Tj ET Q +2.959 Tw +q 0.000 g BT 215.43 366.32 Td (owns one of these tusks with a) Tj ET Q +0.571 Tw +q 0.000 g BT 215.43 352.14 Td (length of 2.25 meters and a width) Tj ET Q +12.440 Tw +q 0.000 g BT 215.43 337.97 Td (at its base of forty-eight) Tj ET Q +0 Tw +q 0.000 g BT 215.43 323.80 Td (centimeters!) Tj ET Q +7.046 Tw +q 0.000 g BT 215.43 309.63 Td ("All right then! Imagine this) Tj ET Q +2.287 Tw +q 0.000 g BT 215.43 295.45 Td (weapon to be ten times stronger) Tj ET Q +3.885 Tw +q 0.000 g BT 215.43 281.28 Td (and the animal ten times more) Tj ET Q +1.685 Tw +q 0.000 g BT 215.43 267.11 Td (powerful, launch it at a speed of) Tj ET Q +3.185 Tw +q 0.000 g BT 215.43 252.93 Td (twenty miles per hour, multiply) Tj ET Q +3.547 Tw +q 0.000 g BT 215.43 238.76 Td (its mass times its velocity, and) Tj ET Q +0.625 Tw +q 0.000 g BT 215.43 224.59 Td (you get just the collision we need) Tj ET Q +0 Tw +q 0.000 g BT 215.43 210.41 Td (to cause the specified catastrophe.) Tj ET Q +4.727 Tw +q 0.000 g BT 215.43 196.24 Td ("So, until information becomes) Tj ET Q +0.907 Tw +q 0.000 g BT 215.43 182.07 Td (more abundant, I plump for a sea) Tj ET Q +4.139 Tw +q 0.000 g BT 215.43 167.89 Td (unicorn of colossal dimensions,) Tj ET Q +5.222 Tw +q 0.000 g BT 215.43 153.72 Td (no longer armed with a mere) Tj ET Q +0.461 Tw +q 0.000 g BT 215.43 139.55 Td (lance but with an actual spur, like) Tj ET Q +14.923 Tw +q 0.000 g BT 215.43 125.37 Td (ironclad frigates or those) Tj ET Q +7.595 Tw +q 0.000 g BT 215.43 111.20 Td (warships called 'rams,' whose) Tj ET Q +2.551 Tw +q 0.000 g BT 215.43 97.03 Td (mass and motor power it would) Tj ET Q +0 Tw +q 0.000 g BT 215.43 82.85 Td (possess simultaneously.) Tj ET Q +0.175 Tw +q 0.000 g BT 215.43 68.68 Td ("This inexplicable phenomenon is) Tj ET Q +3.979 Tw +q 0.000 g BT 399.69 749.00 Td (thus explained away--unless it's) Tj ET Q +4.919 Tw +q 0.000 g BT 399.69 734.82 Td (something else entirely, which,) Tj ET Q +2.609 Tw +q 0.000 g BT 399.69 720.65 Td (despite everything that has been) Tj ET Q +6.919 Tw +q 0.000 g BT 399.69 706.48 Td (sighted, studied, explored and) Tj ET Q +0 Tw +q 0.000 g BT 399.69 692.30 Td (experienced, is still possible!") Tj ET Q +BT /F4 12.00 Tf ET +q 0.000 g BT 399.69 663.96 Td (\(end of excerpt\)) Tj ET Q +BT /F3 8.00 Tf ET +q 0.502 g BT 284.96 25.95 Td (Page 4) Tj ET Q + +endstream +endobj +1 0 obj +<> +endobj +11 0 obj +<> +endobj +12 0 obj +<> +endobj +13 0 obj +<> +endobj +14 0 obj +<> +endobj +15 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F1 11 0 R +/F0 12 0 R +/F3 13 0 R +/F2 14 0 R +/F4 15 0 R +>> +/XObject << +>> +>> +endobj +16 0 obj +<< +/Producer (FPDF 1.7) +/Title (20000 Leagues Under the Seas) +/Author (Jules Verne) +/CreationDate (D:20000101000000) +>> +endobj +17 0 obj +<< +/Type /Catalog +/Pages 1 0 R +/OpenAction [3 0 R /Fit] +/PageLayout /TwoColumnLeft +>> +endobj +xref +0 18 +0000000000 65535 f +0000035755 00000 n +0000036363 00000 n +0000000009 00000 n +0000000087 00000 n +0000011703 00000 n +0000011781 00000 n +0000015493 00000 n +0000015571 00000 n +0000027136 00000 n +0000027215 00000 n +0000035860 00000 n +0000035957 00000 n +0000036059 00000 n +0000036164 00000 n +0000036263 00000 n +0000036512 00000 n +0000036648 00000 n +trailer +<< +/Size 18 +/Root 17 0 R +/Info 16 0 R +>> +startxref +36750 +%%EOF diff --git a/pdf/reference/Fpdf_SetLineJoinStyle_caps.pdf b/pdf/reference/Fpdf_SetLineJoinStyle_caps.pdf new file mode 100644 index 0000000..94f3a9b --- /dev/null +++ b/pdf/reference/Fpdf_SetLineJoinStyle_caps.pdf @@ -0,0 +1,105 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +0.000 G +0.000 g +2 j +0.200 G +85.04 w +99.21 453.55 m +311.81 297.64 l +99.21 141.74 l +S +1.000 0.200 0.200 RG +7.26 w +99.21 453.55 m +311.81 297.64 l +99.21 141.74 l +S +2 J +0 j +0.200 G +85.04 w +311.81 453.55 m +524.41 297.64 l +311.81 141.74 l +S +1.000 0.200 0.200 RG +7.26 w +311.81 453.55 m +524.41 297.64 l +311.81 141.74 l +S +1 J +1 j +0.200 G +85.04 w +524.41 453.55 m +737.01 297.64 l +524.41 141.74 l +S +1.000 0.200 0.200 RG +7.26 w +524.41 453.55 m +737.01 297.64 l +524.41 141.74 l +S + +endstream +endobj +1 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +>> +/XObject << +>> +>> +endobj +5 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +6 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 7 +0000000000 65535 f +0000000615 00000 n +0000000702 00000 n +0000000009 00000 n +0000000087 00000 n +0000000796 00000 n +0000000871 00000 n +trailer +<< +/Size 7 +/Root 6 0 R +/Info 5 0 R +>> +startxref +920 +%%EOF diff --git a/pdf/reference/Fpdf_SetProtection.pdf b/pdf/reference/Fpdf_SetProtection.pdf new file mode 100644 index 0000000..1432cde Binary files /dev/null and b/pdf/reference/Fpdf_SetProtection.pdf differ diff --git a/pdf/reference/Fpdf_SplitLines_tables.pdf b/pdf/reference/Fpdf_SplitLines_tables.pdf new file mode 100644 index 0000000..f0d3635 --- /dev/null +++ b/pdf/reference/Fpdf_SplitLines_tables.pdf @@ -0,0 +1,159 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0a76705d18e0494dd24cb573e53aa0a8c710ec99 14.00 Tf ET +0.000 G +0.000 g +BT /F0a76705d18e0494dd24cb573e53aa0a8c710ec99 14.00 Tf ET +0.251 g +42.52 799.37 170.08 -28.35 re B q 0.878 g BT 96.83 781.00 Td (Column A)Tj ET Q +212.60 799.37 170.08 -28.35 re B q 0.878 g BT 266.91 781.00 Td (Column B)Tj ET Q +382.68 799.37 170.08 -28.35 re B q 0.878 g BT 436.60 781.00 Td (Column C)Tj ET Q +1.000 g +42.52 771.02 170.08 -260.79 re S +q 0.094 g BT 51.02 675.41 Td (Lorem ipsum dolor sit)Tj ET Q +q 0.094 g BT 51.02 659.82 Td (amet, consectetur)Tj ET Q +q 0.094 g BT 51.02 644.23 Td (adipisicing elit, sed do)Tj ET Q +q 0.094 g BT 51.02 628.63 Td (eiusmod tempor)Tj ET Q +q 0.094 g BT 51.02 613.04 Td (incididunt ut labore et)Tj ET Q +q 0.094 g BT 51.02 597.45 Td (dolore magna aliqua.)Tj ET Q +212.60 771.02 170.08 -260.79 re S +q 0.094 g BT 230.73 714.38 Td (Lorem ipsum dolor sit)Tj ET Q +q 0.094 g BT 242.00 698.79 Td (amet, consectetur)Tj ET Q +q 0.094 g BT 229.16 683.20 Td (adipisicing elit, sed do)Tj ET Q +q 0.094 g BT 247.45 667.61 Td (eiusmod tempor)Tj ET Q +q 0.094 g BT 231.10 652.02 Td (incididunt ut labore et)Tj ET Q +q 0.094 g BT 223.33 636.43 Td (dolore magna aliqua. Ut)Tj ET Q +q 0.094 g BT 225.68 620.84 Td (enim ad minim veniam,)Tj ET Q +q 0.094 g BT 221.77 605.25 Td (quis nostrud exercitation)Tj ET Q +q 0.094 g BT 230.73 589.66 Td (ullamco laboris nisi ut)Tj ET Q +q 0.094 g BT 225.66 574.07 Td (aliquip ex ea commodo)Tj ET Q +q 0.094 g BT 263.39 558.48 Td (consequat.)Tj ET Q +382.68 771.02 170.08 -260.79 re S +q 0.094 g BT 410.44 753.36 Td (Lorem ipsum dolor sit)Tj ET Q +q 0.094 g BT 432.98 737.77 Td (amet, consectetur)Tj ET Q +q 0.094 g BT 407.30 722.18 Td (adipisicing elit, sed do)Tj ET Q +q 0.094 g BT 443.89 706.59 Td (eiusmod tempor)Tj ET Q +q 0.094 g BT 411.18 691.00 Td (incididunt ut labore et)Tj ET Q +q 0.094 g BT 395.63 675.41 Td (dolore magna aliqua. Ut)Tj ET Q +q 0.094 g BT 400.33 659.82 Td (enim ad minim veniam,)Tj ET Q +q 0.094 g BT 392.52 644.23 Td (quis nostrud exercitation)Tj ET Q +q 0.094 g BT 410.44 628.63 Td (ullamco laboris nisi ut)Tj ET Q +q 0.094 g BT 400.30 613.04 Td (aliquip ex ea commodo)Tj ET Q +q 0.094 g BT 412.74 597.45 Td (consequat. Duis aute)Tj ET Q +q 0.094 g BT 466.45 581.86 Td (irure dolor in)Tj ET Q +q 0.094 g BT 446.21 566.27 Td (reprehenderit in)Tj ET Q +q 0.094 g BT 425.20 550.68 Td (voluptate velit esse)Tj ET Q +q 0.094 g BT 408.09 535.09 Td (cillum dolore eu fugiat)Tj ET Q +q 0.094 g BT 459.44 519.50 Td (nulla pariatur.)Tj ET Q +42.52 510.24 170.08 -338.74 re S +q 0.094 g BT 51.02 492.57 Td (Lorem ipsum dolor sit)Tj ET Q +q 0.094 g BT 51.02 476.98 Td (amet, consectetur)Tj ET Q +q 0.094 g BT 51.02 461.39 Td (adipisicing elit, sed do)Tj ET Q +q 0.094 g BT 51.02 445.80 Td (eiusmod tempor)Tj ET Q +q 0.094 g BT 51.02 430.21 Td (incididunt ut labore et)Tj ET Q +q 0.094 g BT 51.02 414.62 Td (dolore magna aliqua. Ut)Tj ET Q +q 0.094 g BT 51.02 399.03 Td (enim ad minim veniam,)Tj ET Q +q 0.094 g BT 51.02 383.44 Td (quis nostrud exercitation)Tj ET Q +q 0.094 g BT 51.02 367.85 Td (ullamco laboris nisi ut)Tj ET Q +q 0.094 g BT 51.02 352.26 Td (aliquip ex ea commodo)Tj ET Q +q 0.094 g BT 51.02 336.67 Td (consequat. Duis aute)Tj ET Q +q 0.094 g BT 51.02 321.08 Td (irure dolor in)Tj ET Q +q 0.094 g BT 51.02 305.49 Td (reprehenderit in)Tj ET Q +q 0.094 g BT 51.02 289.89 Td (voluptate velit esse)Tj ET Q +q 0.094 g BT 51.02 274.30 Td (cillum dolore eu fugiat)Tj ET Q +q 0.094 g BT 51.02 258.71 Td (nulla pariatur. Excepteur)Tj ET Q +q 0.094 g BT 51.02 243.12 Td (sint occaecat cupidatat)Tj ET Q +q 0.094 g BT 51.02 227.53 Td (non proident, sunt in)Tj ET Q +q 0.094 g BT 51.02 211.94 Td (culpa qui officia)Tj ET Q +q 0.094 g BT 51.02 196.35 Td (deserunt mollit anim id)Tj ET Q +q 0.094 g BT 51.02 180.76 Td (est laborum.)Tj ET Q +212.60 510.24 170.08 -338.74 re S +q 0.094 g BT 230.73 375.64 Td (Lorem ipsum dolor sit)Tj ET Q +q 0.094 g BT 242.00 360.05 Td (amet, consectetur)Tj ET Q +q 0.094 g BT 229.16 344.46 Td (adipisicing elit, sed do)Tj ET Q +q 0.094 g BT 247.45 328.87 Td (eiusmod tempor)Tj ET Q +q 0.094 g BT 231.10 313.28 Td (incididunt ut labore et)Tj ET Q +q 0.094 g BT 232.27 297.69 Td (dolore magna aliqua.)Tj ET Q +382.68 510.24 170.08 -338.74 re S +q 0.094 g BT 410.44 414.62 Td (Lorem ipsum dolor sit)Tj ET Q +q 0.094 g BT 432.98 399.03 Td (amet, consectetur)Tj ET Q +q 0.094 g BT 407.30 383.44 Td (adipisicing elit, sed do)Tj ET Q +q 0.094 g BT 443.89 367.85 Td (eiusmod tempor)Tj ET Q +q 0.094 g BT 411.18 352.26 Td (incididunt ut labore et)Tj ET Q +q 0.094 g BT 395.63 336.67 Td (dolore magna aliqua. Ut)Tj ET Q +q 0.094 g BT 400.33 321.08 Td (enim ad minim veniam,)Tj ET Q +q 0.094 g BT 392.52 305.49 Td (quis nostrud exercitation)Tj ET Q +q 0.094 g BT 410.44 289.89 Td (ullamco laboris nisi ut)Tj ET Q +q 0.094 g BT 400.30 274.30 Td (aliquip ex ea commodo)Tj ET Q +q 0.094 g BT 475.76 258.71 Td (consequat.)Tj ET Q + +endstream +endobj +1 0 obj +<> +endobj +5 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F0a76705d18e0494dd24cb573e53aa0a8c710ec99 5 0 R +>> +/XObject << +>> +/ColorSpace << +>> +>> +endobj +6 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +7 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 8 +0000000000 65535 f +0000004984 00000 n +0000005167 00000 n +0000000009 00000 n +0000000087 00000 n +0000005071 00000 n +0000005328 00000 n +0000005403 00000 n +trailer +<< +/Size 8 +/Root 7 0 R +/Info 6 0 R +>> +startxref +5452 +%%EOF diff --git a/pdf/reference/Fpdf_Splitlines.pdf b/pdf/reference/Fpdf_Splitlines.pdf new file mode 100644 index 0000000..e9acfd1 --- /dev/null +++ b/pdf/reference/Fpdf_Splitlines.pdf @@ -0,0 +1,90 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0 18.00 Tf ET +0.000 G +0.000 g +0.502 G +1.000 1.000 0.824 rg +99.21 594.64 396.85 -347.39 re B +q 0.000 g BT 195.39 523.55 Td (Lorem ipsum dolor sit amet,) Tj ET Q +q 0.000 g BT 173.40 505.55 Td (consectetur adipisicing elit, sed do) Tj ET Q +q 0.000 g BT 166.64 487.55 Td (eiusmod tempor incididunt ut labore) Tj ET Q +q 0.000 g BT 170.91 469.55 Td (et dolore magna aliqua. Ut enim ad) Tj ET Q +q 0.000 g BT 196.63 451.55 Td (minim veniam, quis nostrud) Tj ET Q +q 0.000 g BT 172.65 433.55 Td (exercitation ullamco laboris nisi ut) Tj ET Q +q 0.000 g BT 172.91 415.55 Td (aliquip ex ea commodo consequat.) Tj ET Q +q 0.000 g BT 163.42 397.55 Td (Duis aute irure dolor in reprehenderit) Tj ET Q +q 0.000 g BT 168.89 379.55 Td (in voluptate velit esse cillum dolore) Tj ET Q +q 0.000 g BT 159.16 361.55 Td (eu fugiat nulla pariatur. Excepteur sint) Tj ET Q +q 0.000 g BT 163.92 343.55 Td (occaecat cupidatat non proident, sunt) Tj ET Q +q 0.000 g BT 172.90 325.55 Td (in culpa qui officia deserunt mollit) Tj ET Q +q 0.000 g BT 223.64 307.55 Td (anim id est laborum.) Tj ET Q + +endstream +endobj +1 0 obj +<> +endobj +5 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F0 5 0 R +>> +/XObject << +>> +>> +endobj +6 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +7 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 8 +0000000000 65535 f +0000001216 00000 n +0000001401 00000 n +0000000009 00000 n +0000000087 00000 n +0000001303 00000 n +0000001505 00000 n +0000001580 00000 n +trailer +<< +/Size 8 +/Root 7 0 R +/Info 6 0 R +>> +startxref +1629 +%%EOF diff --git a/pdf/reference/Fpdf_TransformBegin.pdf b/pdf/reference/Fpdf_TransformBegin.pdf new file mode 100644 index 0000000..008d421 --- /dev/null +++ b/pdf/reference/Fpdf_TransformBegin.pdf @@ -0,0 +1,176 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +0.000 G +0.000 g +BT /F0 36.00 Tf ET +BT 167.61 777.54 Td (Transformations) Tj ET +q +1.00000 0.00000 0.00000 -1.00000 0.00000 1552.25244 cm +q BT 167.60580 777.54354 Td 7 Tr (Transformations) Tj ET +q 167.61 813.54 260.06 -47.34 re W n +260.06400 0 0 47.33858 167.60580 766.20496 cm +/Sh1 sh +Q +Q +Q +BT /F0 12.00 Tf ET +0.784 G +141.73 671.81 113.39 -28.35 re S +q 0.784 g BT 141.73 674.65 Td (Scale) Tj ET Q +q +1.50000 0.00000 0.00000 1.50000 -70.86614 -321.73240 cm +0.000 G +141.73 671.81 113.39 -28.35 re S +BT 141.73 674.65 Td (Scale) Tj ET +Q +0.784 G +354.33 671.81 113.39 -28.35 re S +q 0.784 g BT 354.33 674.65 Td (Translate) Tj ET Q +q +1.00000 0.00000 0.00000 1.00000 19.84252 -14.17323 cm +0.000 G +354.33 671.81 113.39 -28.35 re S +BT 354.33 674.65 Td (Translate) Tj ET +Q +0.784 G +141.73 530.08 113.39 -28.35 re S +q 0.784 g BT 141.73 532.91 Td (Rotate) Tj ET Q +q +0.93969 0.34202 -0.34202 0.93969 180.15013 -18.21712 cm +0.000 G +141.73 530.08 113.39 -28.35 re S +BT 141.73 532.91 Td (Rotate) Tj ET +Q +0.784 G +354.33 530.08 113.39 -28.35 re S +q 0.784 g BT 354.33 532.91 Td (Skew) Tj ET Q +q +1.00000 0.00000 0.57735 1.00000 -306.04124 -0.00000 cm +0.000 G +354.33 530.08 113.39 -28.35 re S +BT 354.33 532.91 Td (Skew) Tj ET +Q +0.784 G +141.73 388.35 113.39 -28.35 re S +q 0.784 g BT 141.73 391.18 Td (Mirror horizontal) Tj ET Q +q +-1.00000 0.00000 0.00000 1.00000 283.46457 0.00000 cm +0.000 G +141.73 388.35 113.39 -28.35 re S +BT 141.73 391.18 Td (Mirror horizontal) Tj ET +Q +0.784 G +354.33 388.35 113.39 -28.35 re S +q 0.784 g BT 354.33 391.18 Td (Mirror vertical) Tj ET Q +q +1.00000 0.00000 0.00000 -1.00000 0.00000 720.00047 cm +0.000 G +354.33 388.35 113.39 -28.35 re S +BT 354.33 391.18 Td (Mirror vertical) Tj ET +Q +0.784 G +141.73 246.61 113.39 -28.35 re S +q 0.784 g BT 141.73 249.45 Td (Mirror point) Tj ET Q +q +-1.00000 0.00000 0.00000 -1.00000 283.46457 436.53591 cm +0.000 G +141.73 246.61 113.39 -28.35 re S +BT 141.73 249.45 Td (Mirror point) Tj ET +Q +0.784 G +354.33 246.61 113.39 -28.35 re S +q 0.784 g BT 354.33 249.45 Td (Mirror line) Tj ET Q +q +0.93969 -0.34202 0.34202 0.93969 -54.13803 129.50388 cm +337.32 221.10 m 342.99 215.43 l S +337.32 215.43 m 342.99 221.10 l S +325.98 218.27 m 510.24 218.27 l S +Q +q +-1.00000 0.00000 0.00000 1.00000 680.31496 0.00000 cm +-0.76604 -0.64279 0.64279 -0.76604 460.43329 604.11992 cm +0.000 G +354.33 246.61 113.39 -28.35 re S +BT 354.33 249.45 Td (Mirror line) Tj ET +Q + +endstream +endobj +1 0 obj +<> +endobj +5 0 obj +<> +endobj +6 0 obj +<> +endobj +7 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F0 7 0 R +>> +/XObject << +>> +/Shading << +/Sh1 6 0 R +>> +>> +endobj +8 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +9 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 10 +0000000000 65535 f +0000002527 00000 n +0000002951 00000 n +0000000009 00000 n +0000000087 00000 n +0000002614 00000 n +0000002720 00000 n +0000002855 00000 n +0000003081 00000 n +0000003156 00000 n +trailer +<< +/Size 10 +/Root 9 0 R +/Info 8 0 R +>> +startxref +3205 +%%EOF diff --git a/pdf/reference/Fpdf_UnderlineThickness.pdf b/pdf/reference/Fpdf_UnderlineThickness.pdf new file mode 100644 index 0000000..49ad9b1 Binary files /dev/null and b/pdf/reference/Fpdf_UnderlineThickness.pdf differ diff --git a/pdf/reference/Fpdf_WrappedTableCells.pdf b/pdf/reference/Fpdf_WrappedTableCells.pdf new file mode 100644 index 0000000..cb2a19d --- /dev/null +++ b/pdf/reference/Fpdf_WrappedTableCells.pdf @@ -0,0 +1,327 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0 12.00 Tf ET +0.000 G +0.000 g +28.35 813.54 170.08 -17.67 re S +BT 31.19 801.11 Td (1:A) Tj ET +198.43 813.54 283.46 -17.67 re S +BT 201.26 801.11 Td (1:A) Tj ET +481.89 813.54 85.04 -17.67 re S +BT 484.73 801.11 Td (1:A) Tj ET +28.35 795.87 170.08 -17.67 re S +BT 31.19 783.44 Td (2:AA) Tj ET +198.43 795.87 283.46 -17.67 re S +BT 201.26 783.44 Td (2:AA) Tj ET +481.89 795.87 85.04 -17.67 re S +BT 484.73 783.44 Td (2:AA) Tj ET +28.35 778.20 170.08 -17.67 re S +BT 31.19 765.77 Td (3:AAA) Tj ET +198.43 778.20 283.46 -17.67 re S +BT 201.26 765.77 Td (3:AAA) Tj ET +481.89 778.20 85.04 -17.67 re S +BT 484.73 765.77 Td (3:AAA) Tj ET +28.35 760.53 170.08 -17.67 re S +BT 31.19 748.10 Td (4:AAAA) Tj ET +198.43 760.53 283.46 -17.67 re S +BT 201.26 748.10 Td (4:AAAA) Tj ET +481.89 760.53 85.04 -17.67 re S +BT 484.73 748.10 Td (4:AAAA) Tj ET +28.35 742.86 170.08 -17.67 re S +BT 31.19 730.43 Td (5:AAAAA) Tj ET +198.43 742.86 283.46 -17.67 re S +BT 201.26 730.43 Td (5:AAAAA) Tj ET +481.89 742.86 85.04 -17.67 re S +BT 484.73 730.43 Td (5:AAAAA) Tj ET +28.35 725.19 170.08 -17.67 re S +BT 31.19 712.76 Td (6:AAAAAA) Tj ET +198.43 725.19 283.46 -17.67 re S +BT 201.26 712.76 Td (6:AAAAAA) Tj ET +481.89 725.19 85.04 -17.67 re S +BT 484.73 712.76 Td (6:AAAAAA) Tj ET +28.35 707.52 170.08 -17.67 re S +BT 31.19 695.09 Td (7:AAAAAAA) Tj ET +198.43 707.52 283.46 -17.67 re S +BT 201.26 695.09 Td (7:AAAAAAA) Tj ET +481.89 707.52 85.04 -17.67 re S +BT 484.73 695.09 Td (7:AAAAAAA) Tj ET +28.35 689.85 170.08 -17.67 re S +BT 31.19 677.42 Td (8:AAAAAAAA) Tj ET +198.43 689.85 283.46 -17.67 re S +BT 201.26 677.42 Td (8:AAAAAAAA) Tj ET +481.89 689.85 85.04 -17.67 re S +BT 484.73 677.42 Td (8:AAAAAAAA) Tj ET +28.35 672.19 170.08 -35.34 re S +BT 31.19 659.75 Td (9:AAAAAAAAA) Tj ET +198.43 672.19 283.46 -35.34 re S +BT 201.26 659.75 Td (9:AAAAAAAAA) Tj ET +481.89 672.19 85.04 -35.34 re S +BT 484.73 659.75 Td (9:AAAAAAAA) Tj ET +BT 484.73 642.08 Td (A) Tj ET +28.35 636.85 170.08 -35.34 re S +BT 31.19 624.41 Td (10:AAAAAAAAAA) Tj ET +198.43 636.85 283.46 -35.34 re S +BT 201.26 624.41 Td (10:AAAAAAAAAA) Tj ET +481.89 636.85 85.04 -35.34 re S +BT 484.73 624.41 Td (10:AAAAAAA) Tj ET +BT 484.73 606.74 Td (AAA) Tj ET +28.35 601.51 170.08 -35.34 re S +BT 31.19 589.07 Td (11:AAAAAAAAAAA) Tj ET +198.43 601.51 283.46 -35.34 re S +BT 201.26 589.07 Td (11:AAAAAAAAAAA) Tj ET +481.89 601.51 85.04 -35.34 re S +BT 484.73 589.07 Td (11:AAAAAAA) Tj ET +BT 484.73 571.40 Td (AAAA) Tj ET +28.35 566.17 170.08 -35.34 re S +BT 31.19 553.74 Td (12:AAAAAAAAAAAA) Tj ET +198.43 566.17 283.46 -35.34 re S +BT 201.26 553.74 Td (12:AAAAAAAAAAAA) Tj ET +481.89 566.17 85.04 -35.34 re S +BT 484.73 553.74 Td (12:AAAAAAA) Tj ET +BT 484.73 536.07 Td (AAAAA) Tj ET +28.35 530.83 170.08 -35.34 re S +BT 31.19 518.40 Td (13:AAAAAAAAAAAAA) Tj ET +198.43 530.83 283.46 -35.34 re S +BT 201.26 518.40 Td (13:AAAAAAAAAAAAA) Tj ET +481.89 530.83 85.04 -35.34 re S +BT 484.73 518.40 Td (13:AAAAAAA) Tj ET +BT 484.73 500.73 Td (AAAAAA) Tj ET +28.35 495.49 170.08 -35.34 re S +BT 31.19 483.06 Td (14:AAAAAAAAAAAAAA) Tj ET +198.43 495.49 283.46 -35.34 re S +BT 201.26 483.06 Td (14:AAAAAAAAAAAAAA) Tj ET +481.89 495.49 85.04 -35.34 re S +BT 484.73 483.06 Td (14:AAAAAAA) Tj ET +BT 484.73 465.39 Td (AAAAAAA) Tj ET +28.35 460.15 170.08 -35.34 re S +BT 31.19 447.72 Td (15:AAAAAAAAAAAAAAA) Tj ET +198.43 460.15 283.46 -35.34 re S +BT 201.26 447.72 Td (15:AAAAAAAAAAAAAAA) Tj ET +481.89 460.15 85.04 -35.34 re S +BT 484.73 447.72 Td (15:AAAAAAA) Tj ET +BT 484.73 430.05 Td (AAAAAAAA) Tj ET +28.35 424.82 170.08 -35.34 re S +BT 31.19 412.38 Td (16:AAAAAAAAAAAAAAAA) Tj ET +198.43 424.82 283.46 -35.34 re S +BT 201.26 412.38 Td (16:AAAAAAAAAAAAAAAA) Tj ET +481.89 424.82 85.04 -35.34 re S +BT 484.73 412.38 Td (16:AAAAAAA) Tj ET +BT 484.73 394.71 Td (AAAAAAAAA) Tj ET +28.35 389.48 170.08 -53.01 re S +BT 31.19 377.04 Td (17:AAAAAAAAAAAAAAAAA) Tj ET +198.43 389.48 283.46 -53.01 re S +BT 201.26 377.04 Td (17:AAAAAAAAAAAAAAAAA) Tj ET +481.89 389.48 85.04 -53.01 re S +BT 484.73 377.04 Td (17:AAAAAAA) Tj ET +BT 484.73 359.37 Td (AAAAAAAAA) Tj ET +BT 484.73 341.70 Td (A) Tj ET +28.35 336.47 170.08 -53.01 re S +BT 31.19 324.03 Td (18:AAAAAAAAAAAAAAAAAA) Tj ET +198.43 336.47 283.46 -53.01 re S +BT 201.26 324.03 Td (18:AAAAAAAAAAAAAAAAAA) Tj ET +481.89 336.47 85.04 -53.01 re S +BT 484.73 324.03 Td (18:AAAAAAA) Tj ET +BT 484.73 306.37 Td (AAAAAAAAA) Tj ET +BT 484.73 288.70 Td (AA) Tj ET +28.35 283.46 170.08 -53.01 re S +BT 31.19 271.03 Td (19:AAAAAAAAAAAAAAAAAA) Tj ET +BT 31.19 253.36 Td (A) Tj ET +198.43 283.46 283.46 -53.01 re S +BT 201.26 271.03 Td (19:AAAAAAAAAAAAAAAAAAA) Tj ET +481.89 283.46 85.04 -53.01 re S +BT 484.73 271.03 Td (19:AAAAAAA) Tj ET +BT 484.73 253.36 Td (AAAAAAAAA) Tj ET +BT 484.73 235.69 Td (AAA) Tj ET +28.35 230.45 170.08 -53.01 re S +BT 31.19 218.02 Td (20:AAAAAAAAAAAAAAAAAA) Tj ET +BT 31.19 200.35 Td (AA) Tj ET +198.43 230.45 283.46 -53.01 re S +BT 201.26 218.02 Td (20:AAAAAAAAAAAAAAAAAAAA) Tj ET +481.89 230.45 85.04 -53.01 re S +BT 484.73 218.02 Td (20:AAAAAAA) Tj ET +BT 484.73 200.35 Td (AAAAAAAAA) Tj ET +BT 484.73 182.68 Td (AAAA) Tj ET +28.35 177.45 170.08 -53.01 re S +BT 31.19 165.01 Td (21:AAAAAAAAAAAAAAAAAA) Tj ET +BT 31.19 147.34 Td (AAA) Tj ET +198.43 177.45 283.46 -53.01 re S +BT 201.26 165.01 Td (21:AAAAAAAAAAAAAAAAAAAAA) Tj ET +481.89 177.45 85.04 -53.01 re S +BT 484.73 165.01 Td (21:AAAAAAA) Tj ET +BT 484.73 147.34 Td (AAAAAAAAA) Tj ET +BT 484.73 129.67 Td (AAAAA) Tj ET +28.35 124.44 170.08 -53.01 re S +BT 31.19 112.00 Td (22:AAAAAAAAAAAAAAAAAA) Tj ET +BT 31.19 94.33 Td (AAAA) Tj ET +198.43 124.44 283.46 -53.01 re S +BT 201.26 112.00 Td (22:AAAAAAAAAAAAAAAAAAAAAA) Tj ET +481.89 124.44 85.04 -53.01 re S +BT 484.73 112.00 Td (22:AAAAAAA) Tj ET +BT 484.73 94.33 Td (AAAAAAAAA) Tj ET +BT 484.73 76.66 Td (AAAAAA) Tj ET + +endstream +endobj +5 0 obj +<> +endobj +6 0 obj +<> +stream +0 J +0 j +0.57 w +BT /F0 12.00 Tf ET +0.000 G +0.000 g +28.35 813.54 170.08 -53.01 re S +BT 31.19 801.11 Td (23:AAAAAAAAAAAAAAAAAA) Tj ET +BT 31.19 783.44 Td (AAAAA) Tj ET +198.43 813.54 283.46 -53.01 re S +BT 201.26 801.11 Td (23:AAAAAAAAAAAAAAAAAAAAAAA) Tj ET +481.89 813.54 85.04 -53.01 re S +BT 484.73 801.11 Td (23:AAAAAAA) Tj ET +BT 484.73 783.44 Td (AAAAAAAAA) Tj ET +BT 484.73 765.77 Td (AAAAAAA) Tj ET +28.35 760.53 170.08 -53.01 re S +BT 31.19 748.10 Td (24:AAAAAAAAAAAAAAAAAA) Tj ET +BT 31.19 730.43 Td (AAAAAA) Tj ET +198.43 760.53 283.46 -53.01 re S +BT 201.26 748.10 Td (24:AAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +481.89 760.53 85.04 -53.01 re S +BT 484.73 748.10 Td (24:AAAAAAA) Tj ET +BT 484.73 730.43 Td (AAAAAAAAA) Tj ET +BT 484.73 712.76 Td (AAAAAAAA) Tj ET +28.35 707.52 170.08 -53.01 re S +BT 31.19 695.09 Td (25:AAAAAAAAAAAAAAAAAA) Tj ET +BT 31.19 677.42 Td (AAAAAAA) Tj ET +198.43 707.52 283.46 -53.01 re S +BT 201.26 695.09 Td (25:AAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +481.89 707.52 85.04 -53.01 re S +BT 484.73 695.09 Td (25:AAAAAAA) Tj ET +BT 484.73 677.42 Td (AAAAAAAAA) Tj ET +BT 484.73 659.75 Td (AAAAAAAAA) Tj ET +28.35 654.52 170.08 -70.68 re S +BT 31.19 642.08 Td (26:AAAAAAAAAAAAAAAAAA) Tj ET +BT 31.19 624.41 Td (AAAAAAAA) Tj ET +198.43 654.52 283.46 -70.68 re S +BT 201.26 642.08 Td (26:AAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +481.89 654.52 85.04 -70.68 re S +BT 484.73 642.08 Td (26:AAAAAAA) Tj ET +BT 484.73 624.41 Td (AAAAAAAAA) Tj ET +BT 484.73 606.74 Td (AAAAAAAAA) Tj ET +BT 484.73 589.07 Td (A) Tj ET +28.35 583.84 170.08 -70.68 re S +BT 31.19 571.40 Td (27:AAAAAAAAAAAAAAAAAA) Tj ET +BT 31.19 553.74 Td (AAAAAAAAA) Tj ET +198.43 583.84 283.46 -70.68 re S +BT 201.26 571.40 Td (27:AAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +481.89 583.84 85.04 -70.68 re S +BT 484.73 571.40 Td (27:AAAAAAA) Tj ET +BT 484.73 553.74 Td (AAAAAAAAA) Tj ET +BT 484.73 536.07 Td (AAAAAAAAA) Tj ET +BT 484.73 518.40 Td (AA) Tj ET +28.35 513.16 170.08 -70.68 re S +BT 31.19 500.73 Td (28:AAAAAAAAAAAAAAAAAA) Tj ET +BT 31.19 483.06 Td (AAAAAAAAAA) Tj ET +198.43 513.16 283.46 -70.68 re S +BT 201.26 500.73 Td (28:AAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +481.89 513.16 85.04 -70.68 re S +BT 484.73 500.73 Td (28:AAAAAAA) Tj ET +BT 484.73 483.06 Td (AAAAAAAAA) Tj ET +BT 484.73 465.39 Td (AAAAAAAAA) Tj ET +BT 484.73 447.72 Td (AAA) Tj ET +28.35 442.48 170.08 -70.68 re S +BT 31.19 430.05 Td (29:AAAAAAAAAAAAAAAAAA) Tj ET +BT 31.19 412.38 Td (AAAAAAAAAAA) Tj ET +198.43 442.48 283.46 -70.68 re S +BT 201.26 430.05 Td (29:AAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +481.89 442.48 85.04 -70.68 re S +BT 484.73 430.05 Td (29:AAAAAAA) Tj ET +BT 484.73 412.38 Td (AAAAAAAAA) Tj ET +BT 484.73 394.71 Td (AAAAAAAAA) Tj ET +BT 484.73 377.04 Td (AAAA) Tj ET +28.35 371.81 170.08 -70.68 re S +BT 31.19 359.37 Td (30:AAAAAAAAAAAAAAAAAA) Tj ET +BT 31.19 341.70 Td (AAAAAAAAAAAA) Tj ET +198.43 371.81 283.46 -70.68 re S +BT 201.26 359.37 Td (30:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA) Tj ET +481.89 371.81 85.04 -70.68 re S +BT 484.73 359.37 Td (30:AAAAAAA) Tj ET +BT 484.73 341.70 Td (AAAAAAAAA) Tj ET +BT 484.73 324.03 Td (AAAAAAAAA) Tj ET +BT 484.73 306.37 Td (AAAAA) Tj ET + +endstream +endobj +1 0 obj +<> +endobj +7 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F0 7 0 R +>> +/XObject << +>> +>> +endobj +8 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +9 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 10 +0000000000 65535 f +0000009015 00000 n +0000009204 00000 n +0000000009 00000 n +0000000087 00000 n +0000005832 00000 n +0000005910 00000 n +0000009108 00000 n +0000009308 00000 n +0000009383 00000 n +trailer +<< +/Size 10 +/Root 9 0 R +/Info 8 0 R +>> +startxref +9432 +%%EOF diff --git a/pdf/reference/Fpdf_WriteAligned.pdf b/pdf/reference/Fpdf_WriteAligned.pdf new file mode 100644 index 0000000..0daf8fe Binary files /dev/null and b/pdf/reference/Fpdf_WriteAligned.pdf differ diff --git a/pdf/reference/basic.pdf b/pdf/reference/basic.pdf new file mode 100644 index 0000000..803212f --- /dev/null +++ b/pdf/reference/basic.pdf @@ -0,0 +1,75 @@ +%PDF-1.3 +3 0 obj +<> +endobj +4 0 obj +<> +stream +0 J +0 j +0.57 w +0.000 G +0.000 g +BT /F0 16.00 Tf ET +BT 31.19 794.57 Td (Hello World!) Tj ET + +endstream +endobj +1 0 obj +<> +endobj +5 0 obj +<> +endobj +2 0 obj +<< +/ProcSet [/PDF /Text /ImageB /ImageC /ImageI] +/Font << +/F0 5 0 R +>> +/XObject << +>> +>> +endobj +6 0 obj +<< +/Producer (FPDF 1.7) +/CreationDate (D:20000101000000) +>> +endobj +7 0 obj +<< +/Type /Catalog +/Pages 1 0 R +>> +endobj +xref +0 8 +0000000000 65535 f +0000000225 00000 n +0000000413 00000 n +0000000009 00000 n +0000000087 00000 n +0000000312 00000 n +0000000517 00000 n +0000000592 00000 n +trailer +<< +/Size 8 +/Root 7 0 R +/Info 6 0 R +>> +startxref +641 +%%EOF diff --git a/png.go b/png.go new file mode 100644 index 0000000..15002b3 --- /dev/null +++ b/png.go @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2013-2016 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf + +import ( + "bytes" + "fmt" + "strings" +) + +func (f *Fpdf) pngColorSpace(ct byte) (colspace string, colorVal int) { + colorVal = 1 + switch ct { + case 0, 4: + colspace = "DeviceGray" + case 2, 6: + colspace = "DeviceRGB" + colorVal = 3 + case 3: + colspace = "Indexed" + default: + f.err = fmt.Errorf("unknown color type in PNG buffer: %d", ct) + } + return +} + +func (f *Fpdf) parsepngstream(buf *bytes.Buffer, readdpi bool) (info *ImageInfoType) { + info = f.newImageInfo() + // Check signature + if string(buf.Next(8)) != "\x89PNG\x0d\x0a\x1a\x0a" { + f.err = fmt.Errorf("not a PNG buffer") + return + } + // Read header chunk + _ = buf.Next(4) + if string(buf.Next(4)) != "IHDR" { + f.err = fmt.Errorf("incorrect PNG buffer") + return + } + w := f.readBeInt32(buf) + h := f.readBeInt32(buf) + bpc := f.readByte(buf) + if bpc > 8 { + f.err = fmt.Errorf("16-bit depth not supported in PNG file") + } + ct := f.readByte(buf) + var colspace string + var colorVal int + colspace, colorVal = f.pngColorSpace(ct) + if f.err != nil { + return + } + if f.readByte(buf) != 0 { + f.err = fmt.Errorf("'unknown compression method in PNG buffer") + return + } + if f.readByte(buf) != 0 { + f.err = fmt.Errorf("'unknown filter method in PNG buffer") + return + } + if f.readByte(buf) != 0 { + f.err = fmt.Errorf("interlacing not supported in PNG buffer") + return + } + _ = buf.Next(4) + dp := sprintf("/Predictor 15 /Colors %d /BitsPerComponent %d /Columns %d", colorVal, bpc, w) + // Scan chunks looking for palette, transparency and image data + pal := make([]byte, 0, 32) + var trns []int + data := make([]byte, 0, 32) + loop := true + for loop { + n := int(f.readBeInt32(buf)) + // dbg("Loop [%d]", n) + switch string(buf.Next(4)) { + case "PLTE": + // dbg("PLTE") + // Read palette + pal = buf.Next(n) + _ = buf.Next(4) + case "tRNS": + // dbg("tRNS") + // Read transparency info + t := buf.Next(n) + switch ct { + case 0: + trns = []int{int(t[1])} // ord(substr($t,1,1))); + case 2: + trns = []int{int(t[1]), int(t[3]), int(t[5])} // array(ord(substr($t,1,1)), ord(substr($t,3,1)), ord(substr($t,5,1))); + default: + pos := strings.Index(string(t), "\x00") + if pos >= 0 { + trns = []int{pos} // array($pos); + } + } + _ = buf.Next(4) + case "IDAT": + // dbg("IDAT") + // Read image data block + data = append(data, buf.Next(n)...) + _ = buf.Next(4) + case "IEND": + // dbg("IEND") + loop = false + case "pHYs": + // dbg("pHYs") + // png files theoretically support different x/y dpi + // but we ignore files like this + // but if they're the same then we can stamp our info + // object with it + x := int(f.readBeInt32(buf)) + y := int(f.readBeInt32(buf)) + units := buf.Next(1)[0] + // fmt.Printf("got a pHYs block, x=%d, y=%d, u=%d, readdpi=%t\n", + // x, y, int(units), readdpi) + // only modify the info block if the user wants us to + if x == y && readdpi { + switch units { + // if units is 1 then measurement is px/meter + case 1: + info.dpi = float64(x) / 39.3701 // inches per meter + default: + info.dpi = float64(x) + } + } + _ = buf.Next(4) + default: + // dbg("default") + _ = buf.Next(n + 4) + } + if loop { + loop = n > 0 + } + } + if colspace == "Indexed" && len(pal) == 0 { + f.err = fmt.Errorf("missing palette in PNG buffer") + } + info.w = float64(w) + info.h = float64(h) + info.cs = colspace + info.bpc = int(bpc) + info.f = "FlateDecode" + info.dp = dp + info.pal = pal + info.trns = trns + // dbg("ct [%d]", ct) + if ct >= 4 { + // Separate alpha and color channels + var err error + data, err = sliceUncompress(data) + if err != nil { + f.err = err + return + } + var color, alpha bytes.Buffer + if ct == 4 { + // Gray image + width := int(w) + height := int(h) + length := 2 * width + var pos, elPos int + for i := 0; i < height; i++ { + pos = (1 + length) * i + color.WriteByte(data[pos]) + alpha.WriteByte(data[pos]) + elPos = pos + 1 + for k := 0; k < width; k++ { + color.WriteByte(data[elPos]) + alpha.WriteByte(data[elPos+1]) + elPos += 2 + } + } + } else { + // RGB image + width := int(w) + height := int(h) + length := 4 * width + var pos, elPos int + for i := 0; i < height; i++ { + pos = (1 + length) * i + color.WriteByte(data[pos]) + alpha.WriteByte(data[pos]) + elPos = pos + 1 + for k := 0; k < width; k++ { + color.Write(data[elPos : elPos+3]) + alpha.WriteByte(data[elPos+3]) + elPos += 4 + } + } + } + data = sliceCompress(color.Bytes()) + info.smask = sliceCompress(alpha.Bytes()) + if f.pdfVersion < "1.4" { + f.pdfVersion = "1.4" + } + } + info.data = data + return +} diff --git a/protect.go b/protect.go new file mode 100644 index 0000000..9a33534 --- /dev/null +++ b/protect.go @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2013-2014 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +// PDF protection is adapted from the work of Klemen VODOPIVEC for the fpdf +// product. + +package gofpdf + +import ( + "crypto/md5" + "crypto/rc4" + "encoding/binary" + "math/rand" +) + +// Advisory bitflag constants that control document activities +const ( + CnProtectPrint = 4 + CnProtectModify = 8 + CnProtectCopy = 16 + CnProtectAnnotForms = 32 +) + +type protectType struct { + encrypted bool + uValue []byte + oValue []byte + pValue int + padding []byte + encryptionKey []byte + objNum int + rc4cipher *rc4.Cipher + rc4n uint32 // Object number associated with rc4 cipher +} + +func (p *protectType) rc4(n uint32, buf *[]byte) { + if p.rc4cipher == nil || p.rc4n != n { + p.rc4cipher, _ = rc4.NewCipher(p.objectKey(n)) + p.rc4n = n + } + p.rc4cipher.XORKeyStream(*buf, *buf) +} + +func (p *protectType) objectKey(n uint32) []byte { + var nbuf, b []byte + nbuf = make([]byte, 8, 8) + binary.LittleEndian.PutUint32(nbuf, n) + b = append(b, p.encryptionKey...) + b = append(b, nbuf[0], nbuf[1], nbuf[2], 0, 0) + s := md5.Sum(b) + return s[0:10] +} + +func oValueGen(userPass, ownerPass []byte) (v []byte) { + var c *rc4.Cipher + tmp := md5.Sum(ownerPass) + c, _ = rc4.NewCipher(tmp[0:5]) + size := len(userPass) + v = make([]byte, size, size) + c.XORKeyStream(v, userPass) + return +} + +func (p *protectType) uValueGen() (v []byte) { + var c *rc4.Cipher + c, _ = rc4.NewCipher(p.encryptionKey) + size := len(p.padding) + v = make([]byte, size, size) + c.XORKeyStream(v, p.padding) + return +} + +func (p *protectType) setProtection(privFlag byte, userPassStr, ownerPassStr string) { + privFlag = 192 | (privFlag & (CnProtectCopy | CnProtectModify | CnProtectPrint | CnProtectAnnotForms)) + p.padding = []byte{ + 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, + 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, + 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, + 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A, + } + userPass := []byte(userPassStr) + var ownerPass []byte + if ownerPassStr == "" { + ownerPass = make([]byte, 8, 8) + binary.LittleEndian.PutUint64(ownerPass, uint64(rand.Int63())) + } else { + ownerPass = []byte(ownerPassStr) + } + userPass = append(userPass, p.padding...)[0:32] + ownerPass = append(ownerPass, p.padding...)[0:32] + p.encrypted = true + p.oValue = oValueGen(userPass, ownerPass) + var buf []byte + buf = append(buf, userPass...) + buf = append(buf, p.oValue...) + buf = append(buf, privFlag, 0xff, 0xff, 0xff) + sum := md5.Sum(buf) + p.encryptionKey = sum[0:5] + p.uValue = p.uValueGen() + p.pValue = -(int(privFlag^255) + 1) +} diff --git a/splittext.go b/splittext.go new file mode 100644 index 0000000..525f93b --- /dev/null +++ b/splittext.go @@ -0,0 +1,53 @@ +package gofpdf + +import ( + "math" + // "strings" + "unicode" +) + +// SplitText splits UTF-8 encoded text into several lines using the current +// font. Each line has its length limited to a maximum width given by w. This +// function can be used to determine the total height of wrapped text for +// vertical placement purposes. +func (f *Fpdf) SplitText(txt string, w float64) (lines []string) { + cw := f.currentFont.Cw + wmax := int(math.Ceil((w - 2*f.cMargin) * 1000 / f.fontSize)) + s := []rune(txt) // Return slice of UTF-8 runes + nb := len(s) + for nb > 0 && s[nb-1] == '\n' { + nb-- + } + s = s[0:nb] + sep := -1 + i := 0 + j := 0 + l := 0 + for i < nb { + c := s[i] + l += cw[c] + if unicode.IsSpace(c) || isChinese(c) { + sep = i + } + if c == '\n' || l > wmax { + if sep == -1 { + if i == j { + i++ + } + sep = i + } else { + i = sep + 1 + } + lines = append(lines, string(s[j:sep])) + sep = -1 + j = i + l = 0 + } else { + i++ + } + } + if i != j { + lines = append(lines, string(s[j:i])) + } + return lines +} diff --git a/spotcolor.go b/spotcolor.go new file mode 100644 index 0000000..33aca82 --- /dev/null +++ b/spotcolor.go @@ -0,0 +1,184 @@ +// Copyright (c) Kurt Jung (Gmail: kurt.w.jung) +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +// Adapted from http://www.fpdf.org/en/script/script89.php by Olivier PLATHEY + +package gofpdf + +import ( + "fmt" + "strings" +) + +func byteBound(v byte) byte { + if v > 100 { + return 100 + } + return v +} + +// AddSpotColor adds an ink-based CMYK color to the gofpdf instance and +// associates it with the specified name. The individual components specify +// percentages ranging from 0 to 100. Values above this are quietly capped to +// 100. An error occurs if the specified name is already associated with a +// color. +func (f *Fpdf) AddSpotColor(nameStr string, c, m, y, k byte) { + if f.err == nil { + _, ok := f.spotColorMap[nameStr] + if !ok { + id := len(f.spotColorMap) + 1 + f.spotColorMap[nameStr] = spotColorType{ + id: id, + val: cmykColorType{ + c: byteBound(c), + m: byteBound(m), + y: byteBound(y), + k: byteBound(k), + }, + } + } else { + f.err = fmt.Errorf("name \"%s\" is already associated with a spot color", nameStr) + } + } +} + +func (f *Fpdf) getSpotColor(nameStr string) (clr spotColorType, ok bool) { + if f.err == nil { + clr, ok = f.spotColorMap[nameStr] + if !ok { + f.err = fmt.Errorf("spot color name \"%s\" is not registered", nameStr) + } + } + return +} + +// SetDrawSpotColor sets the current draw color to the spot color associated +// with nameStr. An error occurs if the name is not associated with a color. +// The value for tint ranges from 0 (no intensity) to 100 (full intensity). It +// is quietly bounded to this range. +func (f *Fpdf) SetDrawSpotColor(nameStr string, tint byte) { + var clr spotColorType + var ok bool + + clr, ok = f.getSpotColor(nameStr) + if ok { + f.color.draw.mode = colorModeSpot + f.color.draw.spotStr = nameStr + f.color.draw.str = sprintf("/CS%d CS %.3f SCN", clr.id, float64(byteBound(tint))/100) + if f.page > 0 { + f.out(f.color.draw.str) + } + } +} + +// SetFillSpotColor sets the current fill color to the spot color associated +// with nameStr. An error occurs if the name is not associated with a color. +// The value for tint ranges from 0 (no intensity) to 100 (full intensity). It +// is quietly bounded to this range. +func (f *Fpdf) SetFillSpotColor(nameStr string, tint byte) { + var clr spotColorType + var ok bool + + clr, ok = f.getSpotColor(nameStr) + if ok { + f.color.fill.mode = colorModeSpot + f.color.fill.spotStr = nameStr + f.color.fill.str = sprintf("/CS%d cs %.3f scn", clr.id, float64(byteBound(tint))/100) + f.colorFlag = f.color.fill.str != f.color.text.str + if f.page > 0 { + f.out(f.color.fill.str) + } + } +} + +// SetTextSpotColor sets the current text color to the spot color associated +// with nameStr. An error occurs if the name is not associated with a color. +// The value for tint ranges from 0 (no intensity) to 100 (full intensity). It +// is quietly bounded to this range. +func (f *Fpdf) SetTextSpotColor(nameStr string, tint byte) { + var clr spotColorType + var ok bool + + clr, ok = f.getSpotColor(nameStr) + if ok { + f.color.text.mode = colorModeSpot + f.color.text.spotStr = nameStr + f.color.text.str = sprintf("/CS%d cs %.3f scn", clr.id, float64(byteBound(tint))/100) + f.colorFlag = f.color.text.str != f.color.text.str + } +} + +func (f *Fpdf) returnSpotColor(clr colorType) (name string, c, m, y, k byte) { + var spotClr spotColorType + var ok bool + + name = clr.spotStr + if name != "" { + spotClr, ok = f.getSpotColor(name) + if ok { + c = spotClr.val.c + m = spotClr.val.m + y = spotClr.val.y + k = spotClr.val.k + } + } + return +} + +// GetDrawSpotColor returns the most recently used spot color information for +// drawing. This will not be the current drawing color if some other color type +// such as RGB is active. If no spot color has been set for drawing, zero +// values are returned. +func (f *Fpdf) GetDrawSpotColor() (name string, c, m, y, k byte) { + return f.returnSpotColor(f.color.draw) +} + +// GetTextSpotColor returns the most recently used spot color information for +// text output. This will not be the current text color if some other color +// type such as RGB is active. If no spot color has been set for text, zero +// values are returned. +func (f *Fpdf) GetTextSpotColor() (name string, c, m, y, k byte) { + return f.returnSpotColor(f.color.text) +} + +// GetFillSpotColor returns the most recently used spot color information for +// fill output. This will not be the current fill color if some other color +// type such as RGB is active. If no fill spot color has been set, zero values +// are returned. +func (f *Fpdf) GetFillSpotColor() (name string, c, m, y, k byte) { + return f.returnSpotColor(f.color.fill) +} + +func (f *Fpdf) putSpotColors() { + for k, v := range f.spotColorMap { + f.newobj() + f.outf("[/Separation /%s", strings.Replace(k, " ", "#20", -1)) + f.out("/DeviceCMYK <<") + f.out("/Range [0 1 0 1 0 1 0 1] /C0 [0 0 0 0] ") + f.outf("/C1 [%.3f %.3f %.3f %.3f] ", float64(v.val.c)/100, float64(v.val.m)/100, + float64(v.val.y)/100, float64(v.val.k)/100) + f.out("/FunctionType 2 /Domain [0 1] /N 1>>]") + f.out("endobj") + v.objID = f.n + f.spotColorMap[k] = v + } +} + +func (f *Fpdf) spotColorPutResourceDict() { + f.out("/ColorSpace <<") + for _, clr := range f.spotColorMap { + f.outf("/CS%d %d 0 R", clr.id, clr.objID) + } + f.out(">>") +} diff --git a/subwrite.go b/subwrite.go new file mode 100644 index 0000000..e7ebd77 --- /dev/null +++ b/subwrite.go @@ -0,0 +1,35 @@ +package gofpdf + +// Adapted from http://www.fpdf.org/en/script/script61.php by Wirus and released with the FPDF license. + +// SubWrite prints text from the current position in the same way as Write(). +// ht is the line height in the unit of measure specified in New(). str +// specifies the text to write. subFontSize is the size of the font in points. +// subOffset is the vertical offset of the text in points; a positive value +// indicates a superscript, a negative value indicates a subscript. link is the +// identifier returned by AddLink() or 0 for no internal link. linkStr is a +// target URL or empty for no external link. A non--zero value for link takes +// precedence over linkStr. +// +// The SubWrite example demonstrates this method. +func (f *Fpdf) SubWrite(ht float64, str string, subFontSize, subOffset float64, link int, linkStr string) { + if f.err != nil { + return + } + // resize font + subFontSizeOld := f.fontSizePt + f.SetFontSize(subFontSize) + // reposition y + subOffset = (((subFontSize - subFontSizeOld) / f.k) * 0.3) + (subOffset / f.k) + subX := f.x + subY := f.y + f.SetXY(subX, subY-subOffset) + //Output text + f.write(ht, str, link, linkStr) + // restore y position + subX = f.x + subY = f.y + f.SetXY(subX, subY+subOffset) + // restore font size + f.SetFontSize(subFontSizeOld) +} diff --git a/svgbasic.go b/svgbasic.go new file mode 100644 index 0000000..f75d69f --- /dev/null +++ b/svgbasic.go @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2014 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf + +import ( + "encoding/xml" + "fmt" + "io/ioutil" + "strconv" + "strings" +) + +var pathCmdSub *strings.Replacer + +func init() { + // Handle permitted constructions like "100L200,230" + pathCmdSub = strings.NewReplacer(",", " ", + "L", " L ", "l", " l ", + "C", " C ", "c", " c ", + "M", " M ", "m", " m ", + "H", " H ", "h", " h ", + "V", " V ", "v", " v ", + "Q", " Q ", "q", " q ", + "Z", " Z ", "z", " z ") +} + +// SVGBasicSegmentType describes a single curve or position segment +type SVGBasicSegmentType struct { + Cmd byte // See http://www.w3.org/TR/SVG/paths.html for path command structure + Arg [6]float64 +} + +func absolutizePath(segs []SVGBasicSegmentType) { + var x, y float64 + var segPtr *SVGBasicSegmentType + adjust := func(pos int, adjX, adjY float64) { + segPtr.Arg[pos] += adjX + segPtr.Arg[pos+1] += adjY + } + for j, seg := range segs { + segPtr = &segs[j] + if j == 0 && seg.Cmd == 'm' { + segPtr.Cmd = 'M' + } + switch segPtr.Cmd { + case 'M': + x = seg.Arg[0] + y = seg.Arg[1] + case 'm': + adjust(0, x, y) + segPtr.Cmd = 'M' + x = segPtr.Arg[0] + y = segPtr.Arg[1] + case 'L': + x = seg.Arg[0] + y = seg.Arg[1] + case 'l': + adjust(0, x, y) + segPtr.Cmd = 'L' + x = segPtr.Arg[0] + y = segPtr.Arg[1] + case 'C': + x = seg.Arg[4] + y = seg.Arg[5] + case 'c': + adjust(0, x, y) + adjust(2, x, y) + adjust(4, x, y) + segPtr.Cmd = 'C' + x = segPtr.Arg[4] + y = segPtr.Arg[5] + case 'Q': + x = seg.Arg[2] + y = seg.Arg[3] + case 'q': + adjust(0, x, y) + adjust(2, x, y) + segPtr.Cmd = 'Q' + x = segPtr.Arg[2] + y = segPtr.Arg[3] + case 'H': + x = seg.Arg[0] + case 'h': + segPtr.Arg[0] += x + segPtr.Cmd = 'H' + x += seg.Arg[0] + case 'V': + y = seg.Arg[0] + case 'v': + segPtr.Arg[0] += y + segPtr.Cmd = 'V' + y += seg.Arg[0] + case 'z': + segPtr.Cmd = 'Z' + } + } +} + +func pathParse(pathStr string) (segs []SVGBasicSegmentType, err error) { + var seg SVGBasicSegmentType + var j, argJ, argCount, prevArgCount int + setup := func(n int) { + // It is not strictly necessary to clear arguments, but result may be clearer + // to caller + for j := 0; j < len(seg.Arg); j++ { + seg.Arg[j] = 0.0 + } + argJ = 0 + argCount = n + prevArgCount = n + } + var str string + var c byte + pathStr = pathCmdSub.Replace(pathStr) + strList := strings.Fields(pathStr) + count := len(strList) + for j = 0; j < count && err == nil; j++ { + str = strList[j] + if argCount == 0 { // Look for path command or argument continuation + c = str[0] + if c == '-' || (c >= '0' && c <= '9') { // More arguments + if j > 0 { + setup(prevArgCount) + // Repeat previous action + if seg.Cmd == 'M' { + seg.Cmd = 'L' + } else if seg.Cmd == 'm' { + seg.Cmd = 'l' + } + } else { + err = fmt.Errorf("expecting SVG path command at first position, got %s", str) + } + } + } + if err == nil { + if argCount == 0 { + seg.Cmd = str[0] + switch seg.Cmd { + case 'M', 'm': // Absolute/relative moveto: x, y + setup(2) + case 'C', 'c': // Absolute/relative Bézier curve: cx0, cy0, cx1, cy1, x1, y1 + setup(6) + case 'H', 'h': // Absolute/relative horizontal line to: x + setup(1) + case 'L', 'l': // Absolute/relative lineto: x, y + setup(2) + case 'Q', 'q': // Absolute/relative quadratic curve: x0, y0, x1, y1 + setup(4) + case 'V', 'v': // Absolute/relative vertical line to: y + setup(1) + case 'Z', 'z': // closepath instruction (takes no arguments) + segs = append(segs, seg) + default: + err = fmt.Errorf("expecting SVG path command at position %d, got %s", j, str) + } + } else { + seg.Arg[argJ], err = strconv.ParseFloat(str, 64) + if err == nil { + argJ++ + argCount-- + if argCount == 0 { + segs = append(segs, seg) + } + } + } + } + } + if err == nil { + if argCount == 0 { + absolutizePath(segs) + } else { + err = fmt.Errorf("expecting additional (%d) numeric arguments", argCount) + } + } + return +} + +// SVGBasicType aggregates the information needed to describe a multi-segment +// basic vector image +type SVGBasicType struct { + Wd, Ht float64 + Segments [][]SVGBasicSegmentType +} + +// SVGBasicParse parses a simple scalable vector graphics (SVG) buffer into a +// descriptor. Only a small subset of the SVG standard, in particular the path +// information generated by jSignature, is supported. The returned path data +// includes only the commands 'M' (absolute moveto: x, y), 'L' (absolute +// lineto: x, y), 'C' (absolute cubic Bézier curve: cx0, cy0, cx1, cy1, +// x1,y1), 'Q' (absolute quadratic Bézier curve: x0, y0, x1, y1) and 'Z' +// (closepath). +func SVGBasicParse(buf []byte) (sig SVGBasicType, err error) { + type pathType struct { + D string `xml:"d,attr"` + } + type srcType struct { + Wd float64 `xml:"width,attr"` + Ht float64 `xml:"height,attr"` + Paths []pathType `xml:"path"` + } + var src srcType + err = xml.Unmarshal(buf, &src) + if err == nil { + if src.Wd > 0 && src.Ht > 0 { + sig.Wd, sig.Ht = src.Wd, src.Ht + var segs []SVGBasicSegmentType + for _, path := range src.Paths { + if err == nil { + segs, err = pathParse(path.D) + if err == nil { + sig.Segments = append(sig.Segments, segs) + } + } + } + } else { + err = fmt.Errorf("unacceptable values for basic SVG extent: %.2f x %.2f", + sig.Wd, sig.Ht) + } + } + return +} + +// SVGBasicFileParse parses a simple scalable vector graphics (SVG) file into a +// basic descriptor. The SVGBasicWrite() example demonstrates this method. +func SVGBasicFileParse(svgFileStr string) (sig SVGBasicType, err error) { + var buf []byte + buf, err = ioutil.ReadFile(svgFileStr) + if err == nil { + sig, err = SVGBasicParse(buf) + } + return +} diff --git a/svgwrite.go b/svgwrite.go new file mode 100644 index 0000000..398a6da --- /dev/null +++ b/svgwrite.go @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2014 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf + +// SVGBasicWrite renders the paths encoded in the basic SVG image specified by +// sb. The scale value is used to convert the coordinates in the path to the +// unit of measure specified in New(). The current position (as set with a call +// to SetXY()) is used as the origin of the image. The current line cap style +// (as set with SetLineCapStyle()), line width (as set with SetLineWidth()), +// and draw color (as set with SetDrawColor()) are used in drawing the image +// paths. +func (f *Fpdf) SVGBasicWrite(sb *SVGBasicType, scale float64) { + originX, originY := f.GetXY() + var x, y, newX, newY float64 + var cx0, cy0, cx1, cy1 float64 + var path []SVGBasicSegmentType + var seg SVGBasicSegmentType + var startX, startY float64 + sval := func(origin float64, arg int) float64 { + return origin + scale*seg.Arg[arg] + } + xval := func(arg int) float64 { + return sval(originX, arg) + } + yval := func(arg int) float64 { + return sval(originY, arg) + } + val := func(arg int) (float64, float64) { + return xval(arg), yval(arg + 1) + } + for j := 0; j < len(sb.Segments) && f.Ok(); j++ { + path = sb.Segments[j] + for k := 0; k < len(path) && f.Ok(); k++ { + seg = path[k] + switch seg.Cmd { + case 'M': + x, y = val(0) + startX, startY = x, y + f.SetXY(x, y) + case 'L': + newX, newY = val(0) + f.Line(x, y, newX, newY) + x, y = newX, newY + case 'C': + cx0, cy0 = val(0) + cx1, cy1 = val(2) + newX, newY = val(4) + f.CurveCubic(x, y, cx0, cy0, newX, newY, cx1, cy1, "D") + x, y = newX, newY + case 'Q': + cx0, cy0 = val(0) + newX, newY = val(2) + f.Curve(x, y, cx0, cy0, newX, newY, "D") + x, y = newX, newY + case 'H': + newX = xval(0) + f.Line(x, y, newX, y) + x = newX + case 'V': + newY = yval(0) + f.Line(x, y, x, newY) + y = newY + case 'Z': + f.Line(x, y, startX, startY) + x, y = startX, startY + default: + f.SetErrorf("Unexpected path command '%c'", seg.Cmd) + } + } + } +} diff --git a/template.go b/template.go new file mode 100644 index 0000000..c0d3933 --- /dev/null +++ b/template.go @@ -0,0 +1,284 @@ +package gofpdf + +/* + * Copyright (c) 2015 Kurt Jung (Gmail: kurt.w.jung), + * Marcus Downing, Jan Slabon (Setasign) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +import ( + "encoding/gob" + "sort" +) + +// CreateTemplate defines a new template using the current page size. +func (f *Fpdf) CreateTemplate(fn func(*Tpl)) Template { + return newTpl(PointType{0, 0}, f.curPageSize, f.defOrientation, f.unitStr, f.fontDirStr, fn, f) +} + +// CreateTemplateCustom starts a template, using the given bounds. +func (f *Fpdf) CreateTemplateCustom(corner PointType, size SizeType, fn func(*Tpl)) Template { + return newTpl(corner, size, f.defOrientation, f.unitStr, f.fontDirStr, fn, f) +} + +// CreateTemplate creates a template that is not attached to any document. +// +// This function is deprecated; it incorrectly assumes that a page with a width +// smaller than its height is oriented in portrait mode, otherwise it assumes +// landscape mode. This causes problems when placing the template in a master +// document where this condition does not apply. CreateTpl() is a similar +// function that lets you specify the orientation to avoid this problem. +func CreateTemplate(corner PointType, size SizeType, unitStr, fontDirStr string, fn func(*Tpl)) Template { + orientationStr := "p" + if size.Wd > size.Ht { + orientationStr = "l" + } + + return CreateTpl(corner, size, orientationStr, unitStr, fontDirStr, fn) +} + +// CreateTpl creates a template not attached to any document +func CreateTpl(corner PointType, size SizeType, orientationStr, unitStr, fontDirStr string, fn func(*Tpl)) Template { + return newTpl(corner, size, orientationStr, unitStr, fontDirStr, fn, nil) +} + +// UseTemplate adds a template to the current page or another template, +// using the size and position at which it was originally written. +func (f *Fpdf) UseTemplate(t Template) { + if t == nil { + f.SetErrorf("template is nil") + return + } + corner, size := t.Size() + f.UseTemplateScaled(t, corner, size) +} + +// UseTemplateScaled adds a template to the current page or another template, +// using the given page coordinates. +func (f *Fpdf) UseTemplateScaled(t Template, corner PointType, size SizeType) { + if t == nil { + f.SetErrorf("template is nil") + return + } + + // You have to add at least a page first + if f.page <= 0 { + f.SetErrorf("cannot use a template without first adding a page") + return + } + + // make a note of the fact that we actually use this template, as well as any other templates, + // images or fonts it uses + f.templates[t.ID()] = t + for _, tt := range t.Templates() { + f.templates[tt.ID()] = tt + } + + // 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 + } + + // template data + _, templateSize := t.Size() + scaleX := size.Wd / templateSize.Wd + scaleY := size.Ht / templateSize.Ht + tx := corner.X * f.k + ty := (f.curPageSize.Ht - corner.Y - size.Ht) * f.k + + f.outf("q %.4f 0 0 %.4f %.4f %.4f cm", scaleX, scaleY, tx, ty) // Translate + f.outf("/TPL%s Do Q", t.ID()) +} + +// Template is an object that can be written to, then used and re-used any number of times within a document. +type Template interface { + ID() string + Size() (PointType, SizeType) + Bytes() []byte + Images() map[string]*ImageInfoType + Templates() []Template + NumPages() int + FromPage(int) (Template, error) + FromPages() []Template + Serialize() ([]byte, error) + gob.GobDecoder + gob.GobEncoder +} + +func (f *Fpdf) templateFontCatalog() { + var keyList []string + var font fontDefType + var key string + f.out("/Font <<") + for key = range f.fonts { + keyList = append(keyList, key) + } + if f.catalogSort { + sort.Strings(keyList) + } + for _, key = range keyList { + font = f.fonts[key] + f.outf("/F%s %d 0 R", font.i, font.N) + } + f.out(">>") +} + +// putTemplates writes the templates to the PDF +func (f *Fpdf) putTemplates() { + filter := "" + if f.compress { + filter = "/Filter /FlateDecode " + } + + templates := sortTemplates(f.templates, f.catalogSort) + var t Template + for _, t = range templates { + corner, size := t.Size() + + f.newobj() + f.templateObjects[t.ID()] = f.n + f.outf("<<%s/Type /XObject", filter) + f.out("/Subtype /Form") + f.out("/Formtype 1") + f.outf("/BBox [%.2f %.2f %.2f %.2f]", corner.X*f.k, corner.Y*f.k, (corner.X+size.Wd)*f.k, (corner.Y+size.Ht)*f.k) + if corner.X != 0 || corner.Y != 0 { + f.outf("/Matrix [1 0 0 1 %.5f %.5f]", -corner.X*f.k*2, corner.Y*f.k*2) + } + + // Template's resource dictionary + f.out("/Resources ") + f.out("< 0 || len(tTemplates) > 0 { + f.out("/XObject <<") + { + var key string + var keyList []string + var ti *ImageInfoType + for key = range tImages { + keyList = append(keyList, key) + } + if gl.catalogSort { + sort.Strings(keyList) + } + for _, key = range keyList { + // for _, ti := range tImages { + ti = tImages[key] + f.outf("/I%s %d 0 R", ti.i, ti.n) + } + } + for _, tt := range tTemplates { + id := tt.ID() + if objID, ok := f.templateObjects[id]; ok { + f.outf("/TPL%s %d 0 R", id, objID) + } + } + f.out(">>") + } + + f.out(">>") + + // Write the template's byte stream + buffer := t.Bytes() + // fmt.Println("Put template bytes", string(buffer[:])) + if f.compress { + buffer = sliceCompress(buffer) + } + f.outf("/Length %d >>", len(buffer)) + f.putstream(buffer) + f.out("endobj") + } +} + +func templateKeyList(mp map[string]Template, sort bool) (keyList []string) { + var key string + for key = range mp { + keyList = append(keyList, key) + } + if sort { + gensort(len(keyList), + func(a, b int) bool { + return keyList[a] < keyList[b] + }, + func(a, b int) { + keyList[a], keyList[b] = keyList[b], keyList[a] + }) + } + return +} + +// sortTemplates puts templates in a suitable order based on dependices +func sortTemplates(templates map[string]Template, catalogSort bool) []Template { + chain := make([]Template, 0, len(templates)*2) + + // build a full set of dependency chains + var keyList []string + var key string + var t Template + keyList = templateKeyList(templates, catalogSort) + for _, key = range keyList { + t = templates[key] + tlist := templateChainDependencies(t) + for _, tt := range tlist { + if tt != nil { + chain = append(chain, tt) + } + } + } + + // reduce that to make a simple list + sorted := make([]Template, 0, len(templates)) +chain: + for _, t := range chain { + for _, already := range sorted { + if t == already { + continue chain + } + } + sorted = append(sorted, t) + } + + return sorted +} + +// templateChainDependencies is a recursive function for determining the full chain of template dependencies +func templateChainDependencies(template Template) []Template { + requires := template.Templates() + chain := make([]Template, len(requires)*2) + for _, req := range requires { + chain = append(chain, templateChainDependencies(req)...) + } + chain = append(chain, template) + return chain +} + +// < 0002640 31 20 31 32 20 30 20 52 0a 2f 54 50 4c 32 20 31 |1 12 0 R./TPL2 1| +// < 0002650 35 20 30 20 52 0a 2f 54 50 4c 31 20 31 34 20 30 |5 0 R./TPL1 14 0| + +// > 0002640 31 20 31 32 20 30 20 52 0a 2f 54 50 4c 31 20 31 |1 12 0 R./TPL1 1| +// > 0002650 34 20 30 20 52 0a 2f 54 50 4c 32 20 31 35 20 30 |4 0 R./TPL2 15 0| diff --git a/template_impl.go b/template_impl.go new file mode 100644 index 0000000..c1e2dff --- /dev/null +++ b/template_impl.go @@ -0,0 +1,303 @@ +package gofpdf + +import ( + "bytes" + "crypto/sha1" + "encoding/gob" + "errors" + "fmt" +) + +/* + * Copyright (c) 2015 Kurt Jung (Gmail: kurt.w.jung), + * Marcus Downing, Jan Slabon (Setasign) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +// newTpl creates a template, copying graphics settings from a template if one is given +func newTpl(corner PointType, size SizeType, orientationStr, unitStr, fontDirStr string, fn func(*Tpl), copyFrom *Fpdf) Template { + sizeStr := "" + + fpdf := fpdfNew(orientationStr, unitStr, sizeStr, fontDirStr, size) + tpl := Tpl{*fpdf} + if copyFrom != nil { + tpl.loadParamsFromFpdf(copyFrom) + } + tpl.Fpdf.AddPage() + fn(&tpl) + + bytes := make([][]byte, len(tpl.Fpdf.pages)) + // skip the first page as it will always be empty + for x := 1; x < len(bytes); x++ { + bytes[x] = tpl.Fpdf.pages[x].Bytes() + } + + templates := make([]Template, 0, len(tpl.Fpdf.templates)) + for _, key := range templateKeyList(tpl.Fpdf.templates, true) { + templates = append(templates, tpl.Fpdf.templates[key]) + } + images := tpl.Fpdf.images + + template := FpdfTpl{corner, size, bytes, images, templates, tpl.Fpdf.page} + return &template +} + +// FpdfTpl is a concrete implementation of the Template interface. +type FpdfTpl struct { + corner PointType + size SizeType + bytes [][]byte + images map[string]*ImageInfoType + templates []Template + page int +} + +// ID returns the global template identifier +func (t *FpdfTpl) ID() string { + return fmt.Sprintf("%x", sha1.Sum(t.Bytes())) +} + +// Size gives the bounding dimensions of this template +func (t *FpdfTpl) Size() (corner PointType, size SizeType) { + return t.corner, t.size +} + +// Bytes returns the actual template data, not including resources +func (t *FpdfTpl) Bytes() []byte { + return t.bytes[t.page] +} + +// FromPage creates a new template from a specific Page +func (t *FpdfTpl) FromPage(page int) (Template, error) { + // pages start at 1 + if page == 0 { + return nil, errors.New("Pages start at 1 No template will have a page 0") + } + + if page > t.NumPages() { + return nil, fmt.Errorf("The template does not have a page %d", page) + } + // if it is already pointing to the correct page + // there is no need to create a new template + if t.page == page { + return t, nil + } + + t2 := *t + t2.page = page + return &t2, nil +} + +// FromPages creates a template slice with all the pages within a template. +func (t *FpdfTpl) FromPages() []Template { + p := make([]Template, t.NumPages()) + for x := 1; x <= t.NumPages(); x++ { + // the only error is when accessing a + // non existing template... that can't happen + // here + p[x-1], _ = t.FromPage(x) + } + + return p +} + +// Images returns a list of the images used in this template +func (t *FpdfTpl) Images() map[string]*ImageInfoType { + return t.images +} + +// Templates returns a list of templates used in this template +func (t *FpdfTpl) Templates() []Template { + return t.templates +} + +// NumPages returns the number of available pages within the template. Look at FromPage and FromPages on access to that content. +func (t *FpdfTpl) NumPages() int { + // the first page is empty to + // make the pages begin at one + return len(t.bytes) - 1 +} + +// Serialize turns a template into a byte string for later deserialization +func (t *FpdfTpl) Serialize() ([]byte, error) { + b := new(bytes.Buffer) + enc := gob.NewEncoder(b) + err := enc.Encode(t) + + return b.Bytes(), err +} + +// DeserializeTemplate creaties a template from a previously serialized +// template +func DeserializeTemplate(b []byte) (Template, error) { + tpl := new(FpdfTpl) + dec := gob.NewDecoder(bytes.NewBuffer(b)) + err := dec.Decode(tpl) + return tpl, err +} + +// childrenImages returns the next layer of children images, it doesn't dig into +// children of children. Applies template namespace to keys to ensure +// no collisions. See UseTemplateScaled +func (t *FpdfTpl) childrenImages() map[string]*ImageInfoType { + childrenImgs := make(map[string]*ImageInfoType) + + for x := 0; x < len(t.templates); x++ { + imgs := t.templates[x].Images() + for key, val := range imgs { + name := sprintf("t%s-%s", t.templates[x].ID(), key) + childrenImgs[name] = val + } + } + + return childrenImgs +} + +// childrensTemplates returns the next layer of children templates, it doesn't dig into +// children of children. +func (t *FpdfTpl) childrensTemplates() []Template { + childrenTmpls := make([]Template, 0) + + for x := 0; x < len(t.templates); x++ { + tmpls := t.templates[x].Templates() + childrenTmpls = append(childrenTmpls, tmpls...) + } + + return childrenTmpls +} + +// GobEncode encodes the receiving template into a byte buffer. Use GobDecode +// to decode the byte buffer back to a template. +func (t *FpdfTpl) GobEncode() ([]byte, error) { + w := new(bytes.Buffer) + encoder := gob.NewEncoder(w) + + childrensTemplates := t.childrensTemplates() + firstClassTemplates := make([]Template, 0) + +found_continue: + for x := 0; x < len(t.templates); x++ { + for y := 0; y < len(childrensTemplates); y++ { + if childrensTemplates[y].ID() == t.templates[x].ID() { + continue found_continue + } + } + + firstClassTemplates = append(firstClassTemplates, t.templates[x]) + } + err := encoder.Encode(firstClassTemplates) + + childrenImgs := t.childrenImages() + firstClassImgs := make(map[string]*ImageInfoType) + + for key, img := range t.images { + if _, ok := childrenImgs[key]; !ok { + firstClassImgs[key] = img + } + } + + if err == nil { + err = encoder.Encode(firstClassImgs) + } + if err == nil { + err = encoder.Encode(t.corner) + } + if err == nil { + err = encoder.Encode(t.size) + } + if err == nil { + err = encoder.Encode(t.bytes) + } + if err == nil { + err = encoder.Encode(t.page) + } + + return w.Bytes(), err +} + +// GobDecode decodes the specified byte buffer into the receiving template. +func (t *FpdfTpl) GobDecode(buf []byte) error { + r := bytes.NewBuffer(buf) + decoder := gob.NewDecoder(r) + + firstClassTemplates := make([]*FpdfTpl, 0) + err := decoder.Decode(&firstClassTemplates) + t.templates = make([]Template, len(firstClassTemplates)) + + for x := 0; x < len(t.templates); x++ { + t.templates[x] = Template(firstClassTemplates[x]) + } + + firstClassImages := t.childrenImages() + + t.templates = append(t.childrensTemplates(), t.templates...) + + t.images = make(map[string]*ImageInfoType) + if err == nil { + err = decoder.Decode(&t.images) + } + + for k, v := range firstClassImages { + t.images[k] = v + } + + if err == nil { + err = decoder.Decode(&t.corner) + } + if err == nil { + err = decoder.Decode(&t.size) + } + if err == nil { + err = decoder.Decode(&t.bytes) + } + if err == nil { + err = decoder.Decode(&t.page) + } + + return err +} + +// Tpl is an Fpdf used for writing a template. It has most of the facilities of +// an Fpdf, but cannot add more pages. Tpl is used directly only during the +// limited time a template is writable. +type Tpl struct { + Fpdf +} + +func (t *Tpl) loadParamsFromFpdf(f *Fpdf) { + t.Fpdf.compress = false + + t.Fpdf.k = f.k + t.Fpdf.x = f.x + t.Fpdf.y = f.y + t.Fpdf.lineWidth = f.lineWidth + t.Fpdf.capStyle = f.capStyle + t.Fpdf.joinStyle = f.joinStyle + + t.Fpdf.color.draw = f.color.draw + t.Fpdf.color.fill = f.color.fill + t.Fpdf.color.text = f.color.text + + t.Fpdf.fonts = f.fonts + t.Fpdf.currentFont = f.currentFont + t.Fpdf.fontFamily = f.fontFamily + t.Fpdf.fontSize = f.fontSize + t.Fpdf.fontSizePt = f.fontSizePt + t.Fpdf.fontStyle = f.fontStyle + t.Fpdf.ws = f.ws + + for key, value := range f.images { + t.Fpdf.images[key] = value + } +} diff --git a/text/20k_c1.txt b/text/20k_c1.txt new file mode 100644 index 0000000..6d5b295 --- /dev/null +++ b/text/20k_c1.txt @@ -0,0 +1,10 @@ +The year 1866 was marked by a bizarre development, an unexplained and downright inexplicable phenomenon that surely no one has forgotten. Without getting into those rumors that upset civilians in the seaports and deranged the public mind even far inland, it must be said that professional seamen were especially alarmed. Traders, shipowners, captains of vessels, skippers, and master mariners from Europe and America, naval officers from every country, and at their heels the various national governments on these two continents, were all extremely disturbed by the business. +In essence, over a period of time several ships had encountered "an enormous thing" at sea, a long spindle-shaped object, sometimes giving off a phosphorescent glow, infinitely bigger and faster than any whale. +The relevant data on this apparition, as recorded in various logbooks, agreed pretty closely as to the structure of the object or creature in question, its unprecedented speed of movement, its startling locomotive power, and the unique vitality with which it seemed to be gifted. If it was a cetacean, it exceeded in bulk any whale previously classified by science. No naturalist, neither Cuvier nor Lacpde, neither Professor Dumeril nor Professor de Quatrefages, would have accepted the existence of such a monster sight unseen -- specifically, unseen by their own scientific eyes. +Striking an average of observations taken at different times -- rejecting those timid estimates that gave the object a length of 200 feet, and ignoring those exaggerated views that saw it as a mile wide and three long--you could still assert that this phenomenal creature greatly exceeded the dimensions of anything then known to ichthyologists, if it existed at all. +Now then, it did exist, this was an undeniable fact; and since the human mind dotes on objects of wonder, you can understand the worldwide excitement caused by this unearthly apparition. As for relegating it to the realm of fiction, that charge had to be dropped. +In essence, on July 20, 1866, the steamer Governor Higginson, from the Calcutta & Burnach Steam Navigation Co., encountered this moving mass five miles off the eastern shores of Australia. Captain Baker at first thought he was in the presence of an unknown reef; he was even about to fix its exact position when two waterspouts shot out of this inexplicable object and sprang hissing into the air some 150 feet. So, unless this reef was subject to the intermittent eruptions of a geyser, the Governor Higginson had fair and honest dealings with some aquatic mammal, until then unknown, that could spurt from its blowholes waterspouts mixed with air and steam. +Similar events were likewise observed in Pacific seas, on July 23 of the same year, by the Christopher Columbus from the West India & Pacific Steam Navigation Co. Consequently, this extraordinary cetacean could transfer itself from one locality to another with startling swiftness, since within an interval of just three days, the Governor Higginson and the Christopher Columbus had observed it at two positions on the charts separated by a distance of more than 700 nautical leagues. +Fifteen days later and 2,000 leagues farther, the Helvetia from the Compagnie Nationale and the Shannon from the Royal Mail line, running on opposite tacks in that part of the Atlantic lying between the United States and Europe, respectively signaled each other that the monster had been sighted in latitude 42 degrees 15' north and longitude 60 degrees 35' west of the meridian of Greenwich. From their simultaneous observations, they were able to estimate the mammal's minimum length at more than 350 English feet; this was because both the Shannon and the Helvetia were of smaller dimensions, although each measured 100 meters stem to stern. Now then, the biggest whales, those rorqual whales that frequent the waterways of the Aleutian Islands, have never exceeded a length of 56 meters--if they reach even that. +One after another, reports arrived that would profoundly affect public opinion: new observations taken by the transatlantic liner Pereire, the Inman line's Etna running afoul of the monster, an official report drawn up by officers on the French frigate Normandy, dead-earnest reckonings obtained by the general staff of Commodore Fitz-James aboard the Lord Clyde. In lighthearted countries, people joked about this phenomenon, but such serious, practical countries as England, America, and Germany were deeply concerned. +In every big city the monster was the latest rage; they sang about it in the coffee houses, they ridiculed it in the newspapers, they dramatized it in the theaters. The tabloids found it a fine opportunity for hatching all sorts of hoaxes. In those newspapers short of copy, you saw the reappearance of every gigantic imaginary creature, from "Moby Dick," that dreadful white whale from the High Arctic regions, to the stupendous kraken whose tentacles could entwine a 500-ton craft and drag it into the ocean depths. They even reprinted reports from ancient times: the views of Aristotle and Pliny accepting the existence of such monsters, then the Norwegian stories of Bishop Pontoppidan, the narratives of Paul Egede, and finally the reports of Captain Harrington -- whose good faith is above suspicion--in which he claims he saw, while aboard the Castilian in 1857, one of those enormous serpents that, until then, had frequented only the seas of France's old extremist newspaper, The Constitutionalist. diff --git a/text/20k_c2.txt b/text/20k_c2.txt new file mode 100644 index 0000000..7b5c565 --- /dev/null +++ b/text/20k_c2.txt @@ -0,0 +1,23 @@ +During the period in which these developments were occurring, I had returned from a scientific undertaking organized to explore the Nebraska badlands in the United States. In my capacity as Assistant Professor at the Paris Museum of Natural History, I had been attached to this expedition by the French government. After spending six months in Nebraska, I arrived in New York laden with valuable collections near the end of March. My departure for France was set for early May. In the meantime, then, I was busy classifying my mineralogical, botanical, and zoological treasures when that incident took place with the Scotia. +I was perfectly abreast of this question, which was the big news of the day, and how could I not have been? I had read and reread every American and European newspaper without being any farther along. This mystery puzzled me. Finding it impossible to form any views, I drifted from one extreme to the other. Something was out there, that much was certain, and any doubting Thomas was invited to place his finger on the Scotia's wound. +When I arrived in New York, the question was at the boiling point. The hypothesis of a drifting islet or an elusive reef, put forward by people not quite in their right minds, was completely eliminated. And indeed, unless this reef had an engine in its belly, how could it move about with such prodigious speed? +Also discredited was the idea of a floating hull or some other enormous wreckage, and again because of this speed of movement. +So only two possible solutions to the question were left, creating two very distinct groups of supporters: on one side, those favoring a monster of colossal strength; on the other, those favoring an "underwater boat" of tremendous motor power. +Now then, although the latter hypothesis was completely admissible, it couldn't stand up to inquiries conducted in both the New World and the Old. That a private individual had such a mechanism at his disposal was less than probable. Where and when had he built it, and how could he have built it in secret? +Only some government could own such an engine of destruction, and in these disaster-filled times, when men tax their ingenuity to build increasingly powerful aggressive weapons, it was possible that, unknown to the rest of the world, some nation could have been testing such a fearsome machine. The Chassepot rifle led to the torpedo, and the torpedo has led to this underwater battering ram, which in turn will lead to the world putting its foot down. At least I hope it will. +But this hypothesis of a war machine collapsed in the face of formal denials from the various governments. Since the public interest was at stake and transoceanic travel was suffering, the sincerity of these governments could not be doubted. Besides, how could the assembly of this underwater boat have escaped public notice? Keeping a secret under such circumstances would be difficult enough for an individual, and certainly impossible for a nation whose every move is under constant surveillance by rival powers. +So, after inquiries conducted in England, France, Russia, Prussia, Spain, Italy, America, and even Turkey, the hypothesis of an underwater Monitor was ultimately rejected. +After I arrived in New York, several people did me the honor of consulting me on the phenomenon in question. In France I had published a two-volume work, in quarto, entitled The Mysteries of the Great Ocean Depths. Well received in scholarly circles, this book had established me as a specialist in this pretty obscure field of natural history. My views were in demand. As long as I could deny the reality of the business, I confined myself to a flat "no comment." But soon, pinned to the wall, I had to explain myself straight out. And in this vein, "the honorable Pierre Aronnax, Professor at the Paris Museum," was summoned by The New York Herald to formulate his views no matter what. +I complied. Since I could no longer hold my tongue, I let it wag. I discussed the question in its every aspect, both political and scientific, and this is an excerpt from the well-padded article I published in the issue of April 30. + +"Therefore," I wrote, "after examining these different hypotheses one by one, we are forced, every other supposition having been refuted, to accept the existence of an extremely powerful marine animal. +"The deepest parts of the ocean are totally unknown to us. No soundings have been able to reach them. What goes on in those distant depths? What creatures inhabit, or could inhabit, those regions twelve or fifteen miles beneath the surface of the water? What is the constitution of these animals? It's almost beyond conjecture. +"However, the solution to this problem submitted to me can take the form of a choice between two alternatives. +"Either we know every variety of creature populating our planet, or we do not. +"If we do not know every one of them, if nature still keeps ichthyological secrets from us, nothing is more admissible than to accept the existence of fish or cetaceans of new species or even new genera, animals with a basically 'cast-iron' constitution that inhabit strata beyond the reach of our soundings, and which some development or other, an urge or a whim if you prefer, can bring to the upper level of the ocean for long intervals. +"If, on the other hand, we do know every living species, we must look for the animal in question among those marine creatures already cataloged, and in this event I would be inclined to accept the existence of a giant narwhale. +"The common narwhale, or sea unicorn, often reaches a length of sixty feet. Increase its dimensions fivefold or even tenfold, then give this cetacean a strength in proportion to its size while enlarging its offensive weapons, and you have the animal we're looking for. It would have the proportions determined by the officers of the Shannon, the instrument needed to perforate the Scotia, and the power to pierce a steamer's hull. +"In essence, the narwhale is armed with a sort of ivory sword, or lance, as certain naturalists have expressed it. It's a king-sized tooth as hard as steel. Some of these teeth have been found buried in the bodies of baleen whales, which the narwhale attacks with invariable success. Others have been wrenched, not without difficulty, from the undersides of vessels that narwhales have pierced clean through, as a gimlet pierces a wine barrel. The museum at the Faculty of Medicine in Paris owns one of these tusks with a length of 2.25 meters and a width at its base of forty-eight centimeters! +"All right then! Imagine this weapon to be ten times stronger and the animal ten times more powerful, launch it at a speed of twenty miles per hour, multiply its mass times its velocity, and you get just the collision we need to cause the specified catastrophe. +"So, until information becomes more abundant, I plump for a sea unicorn of colossal dimensions, no longer armed with a mere lance but with an actual spur, like ironclad frigates or those warships called 'rams,' whose mass and motor power it would possess simultaneously. +"This inexplicable phenomenon is thus explained away--unless it's something else entirely, which, despite everything that has been sighted, studied, explored and experienced, is still possible!" diff --git a/text/countries.txt b/text/countries.txt new file mode 100644 index 0000000..5a48a42 --- /dev/null +++ b/text/countries.txt @@ -0,0 +1,15 @@ +Austria;Vienna;83859;8075 +Belgium;Brussels;30518;10192 +Denmark;Copenhagen;43094;5295 +Finland;Helsinki;304529;5147 +France;Paris;543965;58728 +Germany;Berlin;357022;82057 +Greece;Athens;131625;10511 +Ireland;Dublin;70723;3694 +Italy;Roma;301316;57563 +Luxembourg;Luxembourg;2586;424 +Netherlands;Amsterdam;41526;15654 +Portugal;Lisbon;91906;9957 +Spain;Madrid;504790;39348 +Sweden;Stockholm;410934;8839 +United Kingdom;London;243820;58862 diff --git a/text/utf-8test.txt b/text/utf-8test.txt new file mode 100644 index 0000000..c9596a3 --- /dev/null +++ b/text/utf-8test.txt @@ -0,0 +1,38 @@ +English: +Eat some more of these soft French buns and drink some tea. + +Greek: +Φάτε μερικά από αυτά τα μαλακά γαλλικά κουλουράκια και πίνετε λίγο τσάι. + +Polish: +Zjedz trochę tych miękkich francuskich bułeczek i wypij herbatę. + +Portuguese: +Coma um pouco mais desses delicados pãezinhos franceses e beba um pouco de chá. + +Russian: +Ешьте еще эти мягкие французские булочки и пейте чай. + +Vietnamese: +Ăn thêm một số bánh Pháp mềm và uống một ít trà. + +Arabic: +أكل بعض أكثر من هذه الكعك الفرنسي لينة وشرب بعض الشاي. + +Armenian: +Կերեք այս փափուկ ֆրանսիական բանջարեղեններից մի քանիսը եւ մի քանի թեյ խմեք: + +Georgian: +ჭამე კიდევ უფრო ამ რბილი ფრანგული buns და ვსვავ გარკვეული ჩაი. + +Hebrew: +לאכול קצת יותר אלה לחמניות צרפתית רכה לשתות תה. + +Icelandic: +Borða meira af þessum mjúka franska bollum og drekkaðu te. + +Igbo: +Rie ụfọdụ n'ime ndị na-asụ French bun ma ṅụọ ụfọdụ tii. + +Kazakh: +Осы жұмсақ француз көкөністерінің кейбіреулерін жеп, кейбір шай ішіңіз. diff --git a/text/utf-8test2.txt b/text/utf-8test2.txt new file mode 100644 index 0000000..cc83e14 --- /dev/null +++ b/text/utf-8test2.txt @@ -0,0 +1 @@ +Η μορφή φορητού εγγράφου (PDF) είναι μια ανοικτή ηλεκτρονική μορφή εγγράφων, η οποία αναπτύχθηκε αρχικά από την Adobe Systems, χρησιμοποιώντας μια ποικιλία λειτουργιών γλώσσας PostScript. Πρώτα απ 'όλα προορίζεται για την παρουσίαση έντυπων προϊόντων σε ηλεκτρονική μορφή. Για να δείτε υπάρχουν πολλά προγράμματα, καθώς και το επίσημο δωρεάν πρόγραμμα Adobe Reader. Ένα σημαντικό μέρος του σύγχρονου επαγγελματικού εξοπλισμού εκτύπωσης έχει υποστήριξη υλικού για τη μορφή PDF, η οποία επιτρέπει την εκτύπωση εγγράφων σε αυτή τη μορφή χωρίς τη χρήση λογισμικού. Ο παραδοσιακός τρόπος δημιουργίας εγγράφων PDF είναι ένας εικονικός εκτυπωτής, δηλαδή το ίδιο το έγγραφο είναι έτοιμο στο εξειδικευμένο του πρόγραμμα - ένα γραφικό πρόγραμμα ή ένα πρόγραμμα επεξεργασίας κειμένου. diff --git a/ttfparser.go b/ttfparser.go new file mode 100644 index 0000000..669ab4d --- /dev/null +++ b/ttfparser.go @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2013 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf + +// Utility to parse TTF font files +// Version: 1.0 +// Date: 2011-06-18 +// Author: Olivier PLATHEY +// Port to Go: Kurt Jung, 2013-07-15 + +import ( + "encoding/binary" + "fmt" + "os" + "regexp" + "strings" +) + +// TtfType contains metrics of a TrueType font. +type TtfType struct { + Embeddable bool + UnitsPerEm uint16 + PostScriptName string + Bold bool + ItalicAngle int16 + IsFixedPitch bool + TypoAscender int16 + TypoDescender int16 + UnderlinePosition int16 + UnderlineThickness int16 + Xmin, Ymin, Xmax, Ymax int16 + CapHeight int16 + Widths []uint16 + Chars map[uint16]uint16 +} + +type ttfParser struct { + rec TtfType + f *os.File + tables map[string]uint32 + numberOfHMetrics uint16 + numGlyphs uint16 +} + +// TtfParse extracts various metrics from a TrueType font file. +func TtfParse(fileStr string) (TtfRec TtfType, err error) { + var t ttfParser + t.f, err = os.Open(fileStr) + if err != nil { + return + } + version, err := t.ReadStr(4) + if err != nil { + return + } + if version == "OTTO" { + err = fmt.Errorf("fonts based on PostScript outlines are not supported") + return + } + if version != "\x00\x01\x00\x00" { + err = fmt.Errorf("unrecognized file format") + return + } + numTables := int(t.ReadUShort()) + t.Skip(3 * 2) // searchRange, entrySelector, rangeShift + t.tables = make(map[string]uint32) + var tag string + for j := 0; j < numTables; j++ { + tag, err = t.ReadStr(4) + if err != nil { + return + } + t.Skip(4) // checkSum + offset := t.ReadULong() + t.Skip(4) // length + t.tables[tag] = offset + } + err = t.ParseComponents() + if err != nil { + return + } + t.f.Close() + TtfRec = t.rec + return +} + +func (t *ttfParser) ParseComponents() (err error) { + err = t.ParseHead() + if err == nil { + err = t.ParseHhea() + if err == nil { + err = t.ParseMaxp() + if err == nil { + err = t.ParseHmtx() + if err == nil { + err = t.ParseCmap() + if err == nil { + err = t.ParseName() + if err == nil { + err = t.ParseOS2() + if err == nil { + err = t.ParsePost() + } + } + } + } + } + } + } + return +} + +func (t *ttfParser) ParseHead() (err error) { + err = t.Seek("head") + t.Skip(3 * 4) // version, fontRevision, checkSumAdjustment + magicNumber := t.ReadULong() + if magicNumber != 0x5F0F3CF5 { + err = fmt.Errorf("incorrect magic number") + return + } + t.Skip(2) // flags + t.rec.UnitsPerEm = t.ReadUShort() + t.Skip(2 * 8) // created, modified + t.rec.Xmin = t.ReadShort() + t.rec.Ymin = t.ReadShort() + t.rec.Xmax = t.ReadShort() + t.rec.Ymax = t.ReadShort() + return +} + +func (t *ttfParser) ParseHhea() (err error) { + err = t.Seek("hhea") + if err == nil { + t.Skip(4 + 15*2) + t.numberOfHMetrics = t.ReadUShort() + } + return +} + +func (t *ttfParser) ParseMaxp() (err error) { + err = t.Seek("maxp") + if err == nil { + t.Skip(4) + t.numGlyphs = t.ReadUShort() + } + return +} + +func (t *ttfParser) ParseHmtx() (err error) { + err = t.Seek("hmtx") + if err == nil { + t.rec.Widths = make([]uint16, 0, 8) + for j := uint16(0); j < t.numberOfHMetrics; j++ { + t.rec.Widths = append(t.rec.Widths, t.ReadUShort()) + t.Skip(2) // lsb + } + if t.numberOfHMetrics < t.numGlyphs { + lastWidth := t.rec.Widths[t.numberOfHMetrics-1] + for j := t.numberOfHMetrics; j < t.numGlyphs; j++ { + t.rec.Widths = append(t.rec.Widths, lastWidth) + } + } + } + return +} + +func (t *ttfParser) ParseCmap() (err error) { + var offset int64 + if err = t.Seek("cmap"); err != nil { + return + } + t.Skip(2) // version + numTables := int(t.ReadUShort()) + offset31 := int64(0) + for j := 0; j < numTables; j++ { + platformID := t.ReadUShort() + encodingID := t.ReadUShort() + offset = int64(t.ReadULong()) + if platformID == 3 && encodingID == 1 { + offset31 = offset + } + } + if offset31 == 0 { + err = fmt.Errorf("no Unicode encoding found") + return + } + startCount := make([]uint16, 0, 8) + endCount := make([]uint16, 0, 8) + idDelta := make([]int16, 0, 8) + idRangeOffset := make([]uint16, 0, 8) + t.rec.Chars = make(map[uint16]uint16) + t.f.Seek(int64(t.tables["cmap"])+offset31, os.SEEK_SET) + format := t.ReadUShort() + if format != 4 { + err = fmt.Errorf("unexpected subtable format: %d", format) + return + } + t.Skip(2 * 2) // length, language + segCount := int(t.ReadUShort() / 2) + t.Skip(3 * 2) // searchRange, entrySelector, rangeShift + for j := 0; j < segCount; j++ { + endCount = append(endCount, t.ReadUShort()) + } + t.Skip(2) // reservedPad + for j := 0; j < segCount; j++ { + startCount = append(startCount, t.ReadUShort()) + } + for j := 0; j < segCount; j++ { + idDelta = append(idDelta, t.ReadShort()) + } + offset, _ = t.f.Seek(int64(0), os.SEEK_CUR) + for j := 0; j < segCount; j++ { + idRangeOffset = append(idRangeOffset, t.ReadUShort()) + } + for j := 0; j < segCount; j++ { + c1 := startCount[j] + c2 := endCount[j] + d := idDelta[j] + ro := idRangeOffset[j] + if ro > 0 { + t.f.Seek(offset+2*int64(j)+int64(ro), os.SEEK_SET) + } + for c := c1; c <= c2; c++ { + if c == 0xFFFF { + break + } + var gid int32 + if ro > 0 { + gid = int32(t.ReadUShort()) + if gid > 0 { + gid += int32(d) + } + } else { + gid = int32(c) + int32(d) + } + if gid >= 65536 { + gid -= 65536 + } + if gid > 0 { + t.rec.Chars[c] = uint16(gid) + } + } + } + return +} + +func (t *ttfParser) ParseName() (err error) { + err = t.Seek("name") + if err == nil { + tableOffset, _ := t.f.Seek(0, os.SEEK_CUR) + t.rec.PostScriptName = "" + t.Skip(2) // format + count := t.ReadUShort() + stringOffset := t.ReadUShort() + for j := uint16(0); j < count && t.rec.PostScriptName == ""; j++ { + t.Skip(3 * 2) // platformID, encodingID, languageID + nameID := t.ReadUShort() + length := t.ReadUShort() + offset := t.ReadUShort() + if nameID == 6 { + // PostScript name + t.f.Seek(int64(tableOffset)+int64(stringOffset)+int64(offset), os.SEEK_SET) + var s string + s, err = t.ReadStr(int(length)) + if err != nil { + return + } + s = strings.Replace(s, "\x00", "", -1) + var re *regexp.Regexp + if re, err = regexp.Compile("[(){}<> /%[\\]]"); err != nil { + return + } + t.rec.PostScriptName = re.ReplaceAllString(s, "") + } + } + if t.rec.PostScriptName == "" { + err = fmt.Errorf("the name PostScript was not found") + } + } + return +} + +func (t *ttfParser) ParseOS2() (err error) { + err = t.Seek("OS/2") + if err == nil { + version := t.ReadUShort() + t.Skip(3 * 2) // xAvgCharWidth, usWeightClass, usWidthClass + fsType := t.ReadUShort() + t.rec.Embeddable = (fsType != 2) && (fsType&0x200) == 0 + t.Skip(11*2 + 10 + 4*4 + 4) + fsSelection := t.ReadUShort() + t.rec.Bold = (fsSelection & 32) != 0 + t.Skip(2 * 2) // usFirstCharIndex, usLastCharIndex + t.rec.TypoAscender = t.ReadShort() + t.rec.TypoDescender = t.ReadShort() + if version >= 2 { + t.Skip(3*2 + 2*4 + 2) + t.rec.CapHeight = t.ReadShort() + } else { + t.rec.CapHeight = 0 + } + } + return +} + +func (t *ttfParser) ParsePost() (err error) { + err = t.Seek("post") + if err == nil { + t.Skip(4) // version + t.rec.ItalicAngle = t.ReadShort() + t.Skip(2) // Skip decimal part + t.rec.UnderlinePosition = t.ReadShort() + t.rec.UnderlineThickness = t.ReadShort() + t.rec.IsFixedPitch = t.ReadULong() != 0 + } + return +} + +func (t *ttfParser) Seek(tag string) (err error) { + ofs, ok := t.tables[tag] + if ok { + t.f.Seek(int64(ofs), os.SEEK_SET) + } else { + err = fmt.Errorf("table not found: %s", tag) + } + return +} + +func (t *ttfParser) Skip(n int) { + t.f.Seek(int64(n), os.SEEK_CUR) +} + +func (t *ttfParser) ReadStr(length int) (str string, err error) { + var n int + buf := make([]byte, length) + n, err = t.f.Read(buf) + if err == nil { + if n == length { + str = string(buf) + } else { + err = fmt.Errorf("unable to read %d bytes", length) + } + } + return +} + +func (t *ttfParser) ReadUShort() (val uint16) { + binary.Read(t.f, binary.BigEndian, &val) + return +} + +func (t *ttfParser) ReadShort() (val int16) { + binary.Read(t.f, binary.BigEndian, &val) + return +} + +func (t *ttfParser) ReadULong() (val uint32) { + binary.Read(t.f, binary.BigEndian, &val) + return +} diff --git a/ttfparser_test.go b/ttfparser_test.go new file mode 100644 index 0000000..3286db2 --- /dev/null +++ b/ttfparser_test.go @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2013-2015 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf_test + +import ( + "bytes" + "fmt" + + "github.com/jung-kurt/gofpdf" + "github.com/jung-kurt/gofpdf/internal/example" +) + +func ExampleTtfParse() { + ttf, err := gofpdf.TtfParse(example.FontDir() + "/calligra.ttf") + if err == nil { + fmt.Printf("Postscript name: %s\n", ttf.PostScriptName) + fmt.Printf("unitsPerEm: %8d\n", ttf.UnitsPerEm) + fmt.Printf("Xmin: %8d\n", ttf.Xmin) + fmt.Printf("Ymin: %8d\n", ttf.Ymin) + fmt.Printf("Xmax: %8d\n", ttf.Xmax) + fmt.Printf("Ymax: %8d\n", ttf.Ymax) + } else { + fmt.Printf("%s\n", err) + } + // Output: + // Postscript name: CalligrapherRegular + // unitsPerEm: 1000 + // Xmin: -173 + // Ymin: -234 + // Xmax: 1328 + // Ymax: 899 +} + +func hexStr(s string) string { + var b bytes.Buffer + b.WriteString("\"") + for _, ch := range []byte(s) { + b.WriteString(fmt.Sprintf("\\x%02x", ch)) + } + b.WriteString("\":") + return b.String() +} + +func ExampleFpdf_GetStringWidth() { + pdf := gofpdf.New("", "", "", example.FontDir()) + pdf.SetFont("Helvetica", "", 12) + pdf.AddPage() + for _, s := range []string{"Hello", "世界", "\xe7a va?"} { + fmt.Printf("%-32s width %5.2f, bytes %2d, runes %2d\n", + hexStr(s), pdf.GetStringWidth(s), len(s), len([]rune(s))) + if pdf.Err() { + fmt.Println(pdf.Error()) + } + } + pdf.Close() + // Output: + // "\x48\x65\x6c\x6c\x6f": width 9.64, bytes 5, runes 5 + // "\xe4\xb8\x96\xe7\x95\x8c": width 13.95, bytes 6, runes 2 + // "\xe7\x61\x20\x76\x61\x3f": width 12.47, bytes 6, runes 6 +} diff --git a/utf8fontfile.go b/utf8fontfile.go new file mode 100644 index 0000000..0e1a17a --- /dev/null +++ b/utf8fontfile.go @@ -0,0 +1,1154 @@ +/* + * Copyright (c) 2019 Arteom Korotkiy (Gmail: arteomkorotkiy) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf + +import ( + "bytes" + "encoding/binary" + "fmt" + "math" + "sort" +) + +// flags +const symbolWords = 1 << 0 +const symbolScale = 1 << 3 +const symbolContinue = 1 << 5 +const symbolAllScale = 1 << 6 +const symbol2x2 = 1 << 7 + +// CID map Init +const toUnicode = "/CIDInit /ProcSet findresource begin\n12 dict begin\nbegincmap\n/CIDSystemInfo\n<> def\n/CMapName /Adobe-Identity-UCS def\n/CMapType 2 def\n1 begincodespacerange\n<0000> \nendcodespacerange\n1 beginbfrange\n<0000> <0000>\nendbfrange\nendcmap\nCMapName currentdict /CMap defineresource pop\nend\nend" + +type utf8FontFile struct { + fileReader *fileReader + LastRune int + tableDescriptions map[string]*tableDescription + outTablesData map[string][]byte + symbolPosition []int + charSymbolDictionary map[int]int + Ascent int + Descent int + fontElementSize int + Bbox fontBoxType + CapHeight int + StemV int + ItalicAngle int + Flags int + UnderlinePosition float64 + UnderlineThickness float64 + CharWidths []int + DefaultWidth float64 + symbolData map[int]map[string][]int + CodeSymbolDictionary map[int]int +} + +type tableDescription struct { + name string + checksum []int + position int + size int +} + +type fileReader struct { + readerPosition int64 + array []byte +} + +func (fr *fileReader) Read(s int) []byte { + 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 + } else if flag == 1 { + fr.readerPosition += shift + } else if flag == 2 { + fr.readerPosition = int64(len(fr.array)) - shift + } + return int64(fr.readerPosition), nil +} + +func newUTF8Font(reader *fileReader) *utf8FontFile { + utf := utf8FontFile{ + fileReader: reader, + } + return &utf +} + +func (utf *utf8FontFile) parseFile() error { + utf.fileReader.readerPosition = 0 + utf.symbolPosition = make([]int, 0) + utf.charSymbolDictionary = make(map[int]int) + utf.tableDescriptions = make(map[string]*tableDescription) + utf.outTablesData = make(map[string][]byte) + utf.Ascent = 0 + utf.Descent = 0 + codeType := uint32(utf.readUint32()) + if codeType == 0x4F54544F { + return fmt.Errorf("not supported\n ") + } + if codeType == 0x74746366 { + return fmt.Errorf("not supported\n ") + } + if codeType != 0x00010000 && codeType != 0x74727565 { + return fmt.Errorf("Not a TrueType font: codeType=%v\n ", codeType) + } + utf.generateTableDescriptions() + utf.parseTables() + return nil +} + +func (utf *utf8FontFile) generateTableDescriptions() { + + tablesCount := utf.readUint16() + _ = utf.readUint16() + _ = utf.readUint16() + _ = utf.readUint16() + utf.tableDescriptions = make(map[string]*tableDescription) + + for i := 0; i < tablesCount; i++ { + record := tableDescription{ + name: utf.readTableName(), + checksum: []int{utf.readUint16(), utf.readUint16()}, + position: utf.readUint32(), + size: utf.readUint32(), + } + utf.tableDescriptions[record.name] = &record + } +} + +func (utf *utf8FontFile) readTableName() string { + return string(utf.fileReader.Read(4)) +} + +func (utf *utf8FontFile) readUint16() int { + s := utf.fileReader.Read(2) + return (int(s[0]) << 8) + int(s[1]) +} + +func (utf *utf8FontFile) readUint32() int { + s := utf.fileReader.Read(4) + return (int(s[0]) * 16777216) + (int(s[1]) << 16) + (int(s[2]) << 8) + int(s[3]) // 16777216 = 1<<24 +} + +func (utf *utf8FontFile) calcInt32(x, y []int) []int { + answer := make([]int, 2) + if y[1] > x[1] { + x[1] += 1 << 16 + x[0]++ + } + answer[1] = x[1] - y[1] + if y[0] > x[0] { + x[0] += 1 << 16 + } + answer[0] = x[0] - y[0] + answer[0] = answer[0] & 0xFFFF + return answer +} + +func (utf *utf8FontFile) generateChecksum(data []byte) []int { + if (len(data) % 4) != 0 { + for i := 0; (len(data) % 4) != 0; i++ { + data = append(data, 0) + } + } + answer := []int{0x0000, 0x0000} + for i := 0; i < len(data); i += 4 { + answer[0] += (int(data[i]) << 8) + int(data[i+1]) + answer[1] += (int(data[i+2]) << 8) + int(data[i+3]) + answer[0] += answer[1] >> 16 + answer[1] = answer[1] & 0xFFFF + answer[0] = answer[0] & 0xFFFF + } + return answer +} + +func (utf *utf8FontFile) seek(shift int) { + _, _ = utf.fileReader.seek(int64(shift), 0) +} + +func (utf *utf8FontFile) skip(delta int) { + _, _ = utf.fileReader.seek(int64(delta), 1) +} + +//SeekTable position +func (utf *utf8FontFile) SeekTable(name string) int { + return utf.seekTable(name, 0) +} + +func (utf *utf8FontFile) seekTable(name string, offsetInTable int) int { + _, _ = utf.fileReader.seek(int64(utf.tableDescriptions[name].position+offsetInTable), 0) + return int(utf.fileReader.readerPosition) +} + +func (utf *utf8FontFile) readInt16() int16 { + s := utf.fileReader.Read(2) + a := (int16(s[0]) << 8) + int16(s[1]) + if (int(a) & (1 << 15)) == 0 { + a = int16(int(a) - (1 << 16)) + } + return a +} + +func (utf *utf8FontFile) getUint16(pos int) int { + _, _ = utf.fileReader.seek(int64(pos), 0) + s := utf.fileReader.Read(2) + return (int(s[0]) << 8) + int(s[1]) +} + +func (utf *utf8FontFile) splice(stream []byte, offset int, value []byte) []byte { + stream = append([]byte{}, stream...) + return append(append(stream[:offset], value...), stream[offset+len(value):]...) +} + +func (utf *utf8FontFile) insertUint16(stream []byte, offset int, value int) []byte { + up := make([]byte, 2) + binary.BigEndian.PutUint16(up, uint16(value)) + return utf.splice(stream, offset, up) +} + +func (utf *utf8FontFile) getRange(pos, length int) []byte { + _, _ = utf.fileReader.seek(int64(pos), 0) + if length < 1 { + return make([]byte, 0) + } + s := utf.fileReader.Read(length) + return s +} + +func (utf *utf8FontFile) getTableData(name string) []byte { + desckrip := utf.tableDescriptions[name] + if desckrip == nil { + return nil + } + if desckrip.size == 0 { + return nil + } + _, _ = utf.fileReader.seek(int64(desckrip.position), 0) + s := utf.fileReader.Read(desckrip.size) + return s +} + +func (utf *utf8FontFile) setOutTable(name string, data []byte) { + if data == nil { + return + } + if name == "head" { + data = utf.splice(data, 8, []byte{0, 0, 0, 0}) + } + utf.outTablesData[name] = data +} + +func arrayKeys(arr map[int]string) []int { + answer := make([]int, len(arr)) + i := 0 + for key := range arr { + answer[i] = key + i++ + } + return answer +} + +func inArray(s int, arr []int) bool { + for _, i := range arr { + if s == i { + return true + } + } + return false +} + +func (utf *utf8FontFile) parseNAMETable() int { + namePosition := utf.SeekTable("name") + format := utf.readUint16() + if format != 0 { + fmt.Printf("Illegal format %d\n", format) + return format + } + nameCount := utf.readUint16() + stringDataPosition := namePosition + utf.readUint16() + names := map[int]string{1: "", 2: "", 3: "", 4: "", 6: ""} + keys := arrayKeys(names) + counter := len(names) + for i := 0; i < nameCount; i++ { + system := utf.readUint16() + code := utf.readUint16() + local := utf.readUint16() + nameID := utf.readUint16() + size := utf.readUint16() + position := utf.readUint16() + if !inArray(nameID, keys) { + continue + } + currentName := "" + if system == 3 && code == 1 && local == 0x409 { + oldPos := utf.fileReader.readerPosition + utf.seek(stringDataPosition + position) + if size%2 != 0 { + fmt.Printf("name is not binar byte format\n") + return format + } + size /= 2 + currentName = "" + for size > 0 { + char := utf.readUint16() + currentName += string(rune(char)) + size-- + } + utf.fileReader.readerPosition = oldPos + utf.seek(int(oldPos)) + } else if system == 1 && code == 0 && local == 0 { + oldPos := utf.fileReader.readerPosition + currentName = string(utf.getRange(stringDataPosition+position, size)) + utf.fileReader.readerPosition = oldPos + utf.seek(int(oldPos)) + } + if currentName != "" && names[nameID] == "" { + names[nameID] = currentName + counter-- + if counter == 0 { + break + } + } + } + return format +} + +func (utf *utf8FontFile) parseHEADTable() { + utf.SeekTable("head") + utf.skip(18) + utf.fontElementSize = utf.readUint16() + scale := 1000.0 / float64(utf.fontElementSize) + utf.skip(16) + xMin := utf.readInt16() + yMin := utf.readInt16() + xMax := utf.readInt16() + yMax := utf.readInt16() + utf.Bbox = fontBoxType{int(float64(xMin) * scale), int(float64(yMin) * scale), int(float64(xMax) * scale), int(float64(yMax) * scale)} + utf.skip(3 * 2) + _ = utf.readUint16() + symbolDataFormat := utf.readUint16() + if symbolDataFormat != 0 { + fmt.Printf("Unknown symbol data format %d\n", symbolDataFormat) + return + } +} + +func (utf *utf8FontFile) parseHHEATable() int { + metricsCount := 0 + if _, OK := utf.tableDescriptions["hhea"]; OK { + scale := 1000.0 / float64(utf.fontElementSize) + utf.SeekTable("hhea") + utf.skip(4) + hheaAscender := utf.readInt16() + hheaDescender := utf.readInt16() + utf.Ascent = int(float64(hheaAscender) * scale) + utf.Descent = int(float64(hheaDescender) * scale) + utf.skip(24) + metricDataFormat := utf.readUint16() + if metricDataFormat != 0 { + fmt.Printf("Unknown horizontal metric data format %d\n", metricDataFormat) + return 0 + } + metricsCount = utf.readUint16() + if metricsCount == 0 { + fmt.Printf("Number of horizontal metrics is 0\n") + return 0 + } + } + return metricsCount +} + +func (utf *utf8FontFile) parseOS2Table() int { + var weightType int + scale := 1000.0 / float64(utf.fontElementSize) + if _, OK := utf.tableDescriptions["OS/2"]; OK { + utf.SeekTable("OS/2") + version := utf.readUint16() + utf.skip(2) + weightType = utf.readUint16() + utf.skip(2) + fsType := utf.readUint16() + if fsType == 0x0002 || (fsType&0x0300) != 0 { + fmt.Printf("ERROR - copyright restrictions.\n") + return 0 + } + utf.skip(20) + _ = utf.readInt16() + + utf.skip(36) + sTypoAscender := utf.readInt16() + sTypoDescender := utf.readInt16() + if utf.Ascent == 0 { + utf.Ascent = int(float64(sTypoAscender) * scale) + } + if utf.Descent == 0 { + utf.Descent = int(float64(sTypoDescender) * scale) + } + if version > 1 { + utf.skip(16) + sCapHeight := utf.readInt16() + utf.CapHeight = int(float64(sCapHeight) * scale) + } else { + utf.CapHeight = utf.Ascent + } + } else { + weightType = 500 + if utf.Ascent == 0 { + utf.Ascent = int(float64(utf.Bbox.Ymax) * scale) + } + if utf.Descent == 0 { + utf.Descent = int(float64(utf.Bbox.Ymin) * scale) + } + utf.CapHeight = utf.Ascent + } + utf.StemV = 50 + int(math.Pow(float64(weightType)/65.0, 2)) + return weightType +} + +func (utf *utf8FontFile) parsePOSTTable(weight int) { + utf.SeekTable("post") + utf.skip(4) + utf.ItalicAngle = int(utf.readInt16()) + utf.readUint16()/65536.0 + scale := 1000.0 / float64(utf.fontElementSize) + utf.UnderlinePosition = float64(utf.readInt16()) * scale + utf.UnderlineThickness = float64(utf.readInt16()) * scale + fixed := utf.readUint32() + + utf.Flags = 4 + + if utf.ItalicAngle != 0 { + utf.Flags = utf.Flags | 64 + } + if weight >= 600 { + utf.Flags = utf.Flags | 262144 + } + if fixed != 0 { + utf.Flags = utf.Flags | 1 + } +} + +func (utf *utf8FontFile) parseCMAPTable(format int) int { + cmapPosition := utf.SeekTable("cmap") + utf.skip(2) + cmapTableCount := utf.readUint16() + cidCMAPPosition := 0 + for i := 0; i < cmapTableCount; i++ { + system := utf.readUint16() + coded := utf.readUint16() + position := utf.readUint32() + oldReaderPosition := utf.fileReader.readerPosition + if (system == 3 && coded == 1) || system == 0 { // Microsoft, Unicode + format = utf.getUint16(cmapPosition + position) + if format == 4 { + if cidCMAPPosition == 0 { + cidCMAPPosition = cmapPosition + position + } + break + } + } + utf.seek(int(oldReaderPosition)) + } + if cidCMAPPosition == 0 { + fmt.Printf("Font does not have cmap for Unicode\n") + return cidCMAPPosition + } + return cidCMAPPosition +} + +func (utf *utf8FontFile) parseTables() { + f := utf.parseNAMETable() + utf.parseHEADTable() + n := utf.parseHHEATable() + w := utf.parseOS2Table() + utf.parsePOSTTable(w) + runeCMAPPosition := utf.parseCMAPTable(f) + + utf.SeekTable("maxp") + utf.skip(4) + numSymbols := utf.readUint16() + + symbolCharDictionary := make(map[int][]int) + charSymbolDictionary := make(map[int]int) + utf.generateSCCSDictionaries(runeCMAPPosition, symbolCharDictionary, charSymbolDictionary) + + scale := 1000.0 / float64(utf.fontElementSize) + utf.parseHMTXTable(n, numSymbols, symbolCharDictionary, scale) +} + +func (utf *utf8FontFile) generateCMAP() map[int][]int { + cmapPosition := utf.SeekTable("cmap") + utf.skip(2) + cmapTableCount := utf.readUint16() + runeCmapPosition := 0 + for i := 0; i < cmapTableCount; i++ { + system := utf.readUint16() + coder := utf.readUint16() + position := utf.readUint32() + oldPosition := utf.fileReader.readerPosition + if (system == 3 && coder == 1) || system == 0 { + format := utf.getUint16(cmapPosition + position) + if format == 4 { + runeCmapPosition = cmapPosition + position + break + } + } + utf.seek(int(oldPosition)) + } + + if runeCmapPosition == 0 { + fmt.Printf("Font does not have cmap for Unicode\n") + return nil + } + + symbolCharDictionary := make(map[int][]int) + charSymbolDictionary := make(map[int]int) + utf.generateSCCSDictionaries(runeCmapPosition, symbolCharDictionary, charSymbolDictionary) + + utf.charSymbolDictionary = charSymbolDictionary + + return symbolCharDictionary +} + +func (utf *utf8FontFile) parseSymbols(usedRunes map[int]int) (map[int]int, map[int]int, map[int]int, []int) { + symbolCollection := map[int]int{0: 0} + charSymbolPairCollection := make(map[int]int) + for _, char := range usedRunes { + if _, OK := utf.charSymbolDictionary[char]; OK { + symbolCollection[utf.charSymbolDictionary[char]] = char + charSymbolPairCollection[char] = utf.charSymbolDictionary[char] + + } + utf.LastRune = max(utf.LastRune, char) + } + + begin := utf.tableDescriptions["glyf"].position + + symbolArray := make(map[int]int) + symbolCollectionKeys := keySortInt(symbolCollection) + + symbolCounter := 0 + maxRune := 0 + for _, oldSymbolIndex := range symbolCollectionKeys { + maxRune = max(maxRune, symbolCollection[oldSymbolIndex]) + symbolArray[oldSymbolIndex] = symbolCounter + symbolCounter++ + } + charSymbolPairCollectionKeys := keySortInt(charSymbolPairCollection) + runeSymbolPairCollection := make(map[int]int) + for _, runa := range charSymbolPairCollectionKeys { + runeSymbolPairCollection[runa] = symbolArray[charSymbolPairCollection[runa]] + } + utf.CodeSymbolDictionary = runeSymbolPairCollection + + symbolCollectionKeys = keySortInt(symbolCollection) + for _, oldSymbolIndex := range symbolCollectionKeys { + _, symbolArray, symbolCollection, symbolCollectionKeys = utf.getSymbols(oldSymbolIndex, &begin, symbolArray, symbolCollection, symbolCollectionKeys) + } + + return runeSymbolPairCollection, symbolArray, symbolCollection, symbolCollectionKeys +} + +func (utf *utf8FontFile) generateCMAPTable(cidSymbolPairCollection map[int]int, numSymbols int) []byte { + cidSymbolPairCollectionKeys := keySortInt(cidSymbolPairCollection) + cidID := 0 + cidArray := make(map[int][]int) + prevCid := -2 + prevSymbol := -1 + for _, cid := range cidSymbolPairCollectionKeys { + if cid == (prevCid+1) && cidSymbolPairCollection[cid] == (prevSymbol+1) { + if n, OK := cidArray[cidID]; !OK || n == nil { + cidArray[cidID] = make([]int, 0) + } + cidArray[cidID] = append(cidArray[cidID], cidSymbolPairCollection[cid]) + } else { + cidID = cid + cidArray[cidID] = make([]int, 0) + cidArray[cidID] = append(cidArray[cidID], cidSymbolPairCollection[cid]) + } + prevCid = cid + prevSymbol = cidSymbolPairCollection[cid] + } + cidArrayKeys := keySortArrayRangeMap(cidArray) + segCount := len(cidArray) + 1 + + searchRange := 1 + entrySelector := 0 + for searchRange*2 <= segCount { + searchRange = searchRange * 2 + entrySelector = entrySelector + 1 + } + searchRange = searchRange * 2 + rangeShift := segCount*2 - searchRange + length := 16 + (8 * segCount) + (numSymbols + 1) + cmap := []int{0, 1, 3, 1, 0, 12, 4, length, 0, segCount * 2, searchRange, entrySelector, rangeShift} + + for _, start := range cidArrayKeys { + endCode := start + (len(cidArray[start]) - 1) + cmap = append(cmap, endCode) + } + cmap = append(cmap, 0xFFFF) + cmap = append(cmap, 0) + + for _, cidKey := range cidArrayKeys { + cmap = append(cmap, cidKey) + } + cmap = append(cmap, 0xFFFF) + for _, cidKey := range cidArrayKeys { + idDelta := -(cidKey - cidArray[cidKey][0]) + cmap = append(cmap, idDelta) + } + cmap = append(cmap, 1) + for range cidArray { + cmap = append(cmap, 0) + + } + cmap = append(cmap, 0) + for _, start := range cidArrayKeys { + for _, glidx := range cidArray[start] { + cmap = append(cmap, glidx) + } + } + cmap = append(cmap, 0) + cmapstr := make([]byte, 0) + for _, cm := range cmap { + cmapstr = append(cmapstr, packUint16(cm)...) + } + return cmapstr +} + +//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) + utf.tableDescriptions = make(map[string]*tableDescription) + utf.outTablesData = make(map[string][]byte) + utf.Ascent = 0 + utf.Descent = 0 + utf.skip(4) + utf.LastRune = 0 + utf.generateTableDescriptions() + + utf.SeekTable("head") + utf.skip(50) + LocaFormat := utf.readUint16() + + utf.SeekTable("hhea") + utf.skip(34) + metricsCount := utf.readUint16() + oldMetrics := metricsCount + + utf.SeekTable("maxp") + utf.skip(4) + numSymbols := utf.readUint16() + + symbolCharDictionary := utf.generateCMAP() + if symbolCharDictionary == nil { + return nil + } + + utf.parseHMTXTable(metricsCount, numSymbols, symbolCharDictionary, 1.0) + + utf.parseLOCATable(LocaFormat, numSymbols) + + cidSymbolPairCollection, symbolArray, symbolCollection, symbolCollectionKeys := utf.parseSymbols(usedRunes) + + metricsCount = len(symbolCollection) + numSymbols = metricsCount + + utf.setOutTable("name", utf.getTableData("name")) + utf.setOutTable("cvt ", utf.getTableData("cvt ")) + utf.setOutTable("fpgm", utf.getTableData("fpgm")) + utf.setOutTable("prep", utf.getTableData("prep")) + utf.setOutTable("gasp", utf.getTableData("gasp")) + + postTable := utf.getTableData("post") + postTable = append(append([]byte{0x00, 0x03, 0x00, 0x00}, postTable[4:16]...), []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}...) + utf.setOutTable("post", postTable) + + delete(cidSymbolPairCollection, 0) + + utf.setOutTable("cmap", utf.generateCMAPTable(cidSymbolPairCollection, numSymbols)) + + symbolData := utf.getTableData("glyf") + + offsets := make([]int, 0) + glyfData := make([]byte, 0) + pos := 0 + hmtxData := make([]byte, 0) + utf.symbolData = make(map[int]map[string][]int, 0) + + for _, originalSymbolIdx := range symbolCollectionKeys { + hm := utf.getMetrics(oldMetrics, originalSymbolIdx) + hmtxData = append(hmtxData, hm...) + + offsets = append(offsets, pos) + symbolPos := utf.symbolPosition[originalSymbolIdx] + symbolLen := utf.symbolPosition[originalSymbolIdx+1] - symbolPos + data := symbolData[symbolPos : symbolPos+symbolLen] + var up int + if symbolLen > 0 { + up = unpackUint16(data[0:2]) + } + + if symbolLen > 2 && (up&(1<<15)) != 0 { + posInSymbol := 10 + flags := symbolContinue + nComponentElements := 0 + for (flags & symbolContinue) != 0 { + nComponentElements++ + up = unpackUint16(data[posInSymbol : posInSymbol+2]) + flags = up + up = unpackUint16(data[posInSymbol+2 : posInSymbol+4]) + symbolIdx := up + if _, OK := utf.symbolData[originalSymbolIdx]; !OK { + utf.symbolData[originalSymbolIdx] = make(map[string][]int) + } + if _, OK := utf.symbolData[originalSymbolIdx]["compSymbols"]; !OK { + utf.symbolData[originalSymbolIdx]["compSymbols"] = make([]int, 0) + } + utf.symbolData[originalSymbolIdx]["compSymbols"] = append(utf.symbolData[originalSymbolIdx]["compSymbols"], symbolIdx) + data = utf.insertUint16(data, posInSymbol+2, symbolArray[symbolIdx]) + posInSymbol += 4 + if (flags & symbolWords) != 0 { + posInSymbol += 4 + } else { + posInSymbol += 2 + } + if (flags & symbolScale) != 0 { + posInSymbol += 2 + } else if (flags & symbolAllScale) != 0 { + posInSymbol += 4 + } else if (flags & symbol2x2) != 0 { + posInSymbol += 8 + } + } + } + + glyfData = append(glyfData, data...) + pos += symbolLen + if pos%4 != 0 { + padding := 4 - (pos % 4) + glyfData = append(glyfData, make([]byte, padding)...) + pos += padding + } + } + + offsets = append(offsets, pos) + utf.setOutTable("glyf", glyfData) + + utf.setOutTable("hmtx", hmtxData) + + locaData := make([]byte, 0) + if ((pos + 1) >> 1) > 0xFFFF { + LocaFormat = 1 + for _, offset := range offsets { + locaData = append(locaData, packUint32(offset)...) + } + } else { + LocaFormat = 0 + for _, offset := range offsets { + locaData = append(locaData, packUint16(offset/2)...) + } + } + utf.setOutTable("loca", locaData) + + headData := utf.getTableData("head") + headData = utf.insertUint16(headData, 50, LocaFormat) + utf.setOutTable("head", headData) + + hheaData := utf.getTableData("hhea") + hheaData = utf.insertUint16(hheaData, 34, metricsCount) + utf.setOutTable("hhea", hheaData) + + maxp := utf.getTableData("maxp") + maxp = utf.insertUint16(maxp, 4, numSymbols) + utf.setOutTable("maxp", maxp) + + os2Data := utf.getTableData("OS/2") + utf.setOutTable("OS/2", os2Data) + + return utf.assembleTables() +} + +func (utf *utf8FontFile) getSymbols(originalSymbolIdx int, start *int, symbolSet map[int]int, SymbolsCollection map[int]int, SymbolsCollectionKeys []int) (*int, map[int]int, map[int]int, []int) { + symbolPos := utf.symbolPosition[originalSymbolIdx] + symbolSize := utf.symbolPosition[originalSymbolIdx+1] - symbolPos + if symbolSize == 0 { + return start, symbolSet, SymbolsCollection, SymbolsCollectionKeys + } + utf.seek(*start + symbolPos) + + lineCount := utf.readInt16() + + if lineCount < 0 { + utf.skip(8) + flags := symbolContinue + for flags&symbolContinue != 0 { + flags = utf.readUint16() + symbolIndex := utf.readUint16() + if _, OK := symbolSet[symbolIndex]; !OK { + symbolSet[symbolIndex] = len(SymbolsCollection) + SymbolsCollection[symbolIndex] = 1 + SymbolsCollectionKeys = append(SymbolsCollectionKeys, symbolIndex) + } + oldPosition, _ := utf.fileReader.seek(0, 1) + _, _, _, SymbolsCollectionKeys = utf.getSymbols(symbolIndex, start, symbolSet, SymbolsCollection, SymbolsCollectionKeys) + utf.seek(int(oldPosition)) + if flags&symbolWords != 0 { + utf.skip(4) + } else { + utf.skip(2) + } + if flags&symbolScale != 0 { + utf.skip(2) + } else if flags&symbolAllScale != 0 { + utf.skip(4) + } else if flags&symbol2x2 != 0 { + utf.skip(8) + } + } + } + return start, symbolSet, SymbolsCollection, SymbolsCollectionKeys +} + +func (utf *utf8FontFile) parseHMTXTable(numberOfHMetrics, numSymbols int, symbolToChar map[int][]int, scale float64) { + var widths int + start := utf.SeekTable("hmtx") + arrayWidths := 0 + var arr []int + utf.CharWidths = make([]int, 256*256) + charCount := 0 + arr = unpackUint16Array(utf.getRange(start, numberOfHMetrics*4)) + for symbol := 0; symbol < numberOfHMetrics; symbol++ { + arrayWidths = arr[(symbol*2)+1] + if _, OK := symbolToChar[symbol]; OK || symbol == 0 { + + if arrayWidths >= (1 << 15) { + arrayWidths = 0 + } + if symbol == 0 { + utf.DefaultWidth = scale * float64(arrayWidths) + continue + } + for _, char := range symbolToChar[symbol] { + if char != 0 && char != 65535 { + widths = int(math.Round(scale * float64(arrayWidths))) + if widths == 0 { + widths = 65535 + } + if char < 196608 { + utf.CharWidths[char] = widths + charCount++ + } + } + } + } + } + diff := numSymbols - numberOfHMetrics + for pos := 0; pos < diff; pos++ { + symbol := pos + numberOfHMetrics + if _, OK := symbolToChar[symbol]; OK { + for _, char := range symbolToChar[symbol] { + if char != 0 && char != 65535 { + widths = int(math.Round(scale * float64(arrayWidths))) + if widths == 0 { + widths = 65535 + } + if char < 196608 { + utf.CharWidths[char] = widths + charCount++ + } + } + } + } + } + utf.CharWidths[0] = charCount +} + +func (utf *utf8FontFile) getMetrics(metricCount, gid int) []byte { + start := utf.SeekTable("hmtx") + var metrics []byte + if gid < metricCount { + utf.seek(start + (gid * 4)) + metrics = utf.fileReader.Read(4) + } else { + utf.seek(start + ((metricCount - 1) * 4)) + metrics = utf.fileReader.Read(2) + utf.seek(start + (metricCount * 2) + (gid * 2)) + metrics = append(metrics, utf.fileReader.Read(2)...) + } + return metrics +} + +func (utf *utf8FontFile) parseLOCATable(format, numSymbols int) { + start := utf.SeekTable("loca") + utf.symbolPosition = make([]int, 0) + if format == 0 { + data := utf.getRange(start, (numSymbols*2)+2) + arr := unpackUint16Array(data) + for n := 0; n <= numSymbols; n++ { + utf.symbolPosition = append(utf.symbolPosition, arr[n+1]*2) + } + } else if format == 1 { + data := utf.getRange(start, (numSymbols*4)+4) + arr := unpackUint32Array(data) + for n := 0; n <= numSymbols; n++ { + utf.symbolPosition = append(utf.symbolPosition, arr[n+1]) + } + } else { + fmt.Printf("Unknown loca table format %d\n", format) + return + } +} + +func (utf *utf8FontFile) generateSCCSDictionaries(runeCmapPosition int, symbolCharDictionary map[int][]int, charSymbolDictionary map[int]int) { + maxRune := 0 + utf.seek(runeCmapPosition + 2) + size := utf.readUint16() + rim := runeCmapPosition + size + utf.skip(2) + + segmentSize := utf.readUint16() / 2 + utf.skip(6) + completers := make([]int, 0) + for i := 0; i < segmentSize; i++ { + completers = append(completers, utf.readUint16()) + } + utf.skip(2) + beginners := make([]int, 0) + for i := 0; i < segmentSize; i++ { + beginners = append(beginners, utf.readUint16()) + } + sizes := make([]int, 0) + for i := 0; i < segmentSize; i++ { + sizes = append(sizes, int(utf.readInt16())) + } + readerPositionStart := utf.fileReader.readerPosition + positions := make([]int, 0) + for i := 0; i < segmentSize; i++ { + positions = append(positions, utf.readUint16()) + } + var symbol int + for n := 0; n < segmentSize; n++ { + completePosition := completers[n] + 1 + for char := beginners[n]; char < completePosition; char++ { + if positions[n] == 0 { + symbol = (char + sizes[n]) & 0xFFFF + } else { + position := (char-beginners[n])*2 + positions[n] + position = int(readerPositionStart) + 2*n + position + if position >= rim { + symbol = 0 + } else { + symbol = utf.getUint16(position) + if symbol != 0 { + symbol = (symbol + sizes[n]) & 0xFFFF + } + } + } + charSymbolDictionary[char] = symbol + if char < 196608 { + maxRune = max(char, maxRune) + } + symbolCharDictionary[symbol] = append(symbolCharDictionary[symbol], char) + } + } +} + +func max(i, n int) int { + if n > i { + return n + } + return i +} + +func (utf *utf8FontFile) assembleTables() []byte { + answer := make([]byte, 0) + tablesCount := len(utf.outTablesData) + findSize := 1 + writer := 0 + for findSize*2 <= tablesCount { + findSize = findSize * 2 + writer = writer + 1 + } + findSize = findSize * 16 + rOffset := tablesCount*16 - findSize + + answer = append(answer, packHeader(0x00010000, tablesCount, findSize, writer, rOffset)...) + + tables := utf.outTablesData + tablesNames := keySortStrings(tables) + + offset := 12 + tablesCount*16 + begin := 0 + + for _, name := range tablesNames { + if name == "head" { + begin = offset + } + answer = append(answer, []byte(name)...) + checksum := utf.generateChecksum(tables[name]) + answer = append(answer, pack2Uint16(checksum[0], checksum[1])...) + answer = append(answer, pack2Uint32(offset, len(tables[name]))...) + paddedLength := (len(tables[name]) + 3) &^ 3 + offset = offset + paddedLength + } + + for _, key := range tablesNames { + data := append([]byte{}, tables[key]...) + data = append(data, []byte{0, 0, 0}...) + answer = append(answer, data[:(len(data)&^3)]...) + } + + checksum := utf.generateChecksum([]byte(answer)) + checksum = utf.calcInt32([]int{0xB1B0, 0xAFBA}, checksum) + answer = utf.splice(answer, (begin + 8), pack2Uint16(checksum[0], checksum[1])) + return answer +} + +func unpackUint16Array(data []byte) []int { + answer := make([]int, 1) + r := bytes.NewReader(data) + bs := make([]byte, 2) + var e error + var c int + c, e = r.Read(bs) + for e == nil && c > 0 { + answer = append(answer, int(binary.BigEndian.Uint16(bs))) + c, e = r.Read(bs) + } + return answer +} + +func unpackUint32Array(data []byte) []int { + answer := make([]int, 1) + r := bytes.NewReader(data) + bs := make([]byte, 4) + var e error + var c int + c, e = r.Read(bs) + for e == nil && c > 0 { + answer = append(answer, int(binary.BigEndian.Uint32(bs))) + c, e = r.Read(bs) + } + return answer +} + +func unpackUint16(data []byte) int { + return int(binary.BigEndian.Uint16(data)) +} + +func packHeader(N uint32, n1, n2, n3, n4 int) []byte { + answer := make([]byte, 0) + bs4 := make([]byte, 4) + binary.BigEndian.PutUint32(bs4, N) + answer = append(answer, bs4...) + bs := make([]byte, 2) + binary.BigEndian.PutUint16(bs, uint16(n1)) + answer = append(answer, bs...) + binary.BigEndian.PutUint16(bs, uint16(n2)) + answer = append(answer, bs...) + binary.BigEndian.PutUint16(bs, uint16(n3)) + answer = append(answer, bs...) + binary.BigEndian.PutUint16(bs, uint16(n4)) + answer = append(answer, bs...) + return answer +} + +func pack2Uint16(n1, n2 int) []byte { + answer := make([]byte, 0) + bs := make([]byte, 2) + binary.BigEndian.PutUint16(bs, uint16(n1)) + answer = append(answer, bs...) + binary.BigEndian.PutUint16(bs, uint16(n2)) + answer = append(answer, bs...) + return answer +} + +func pack2Uint32(n1, n2 int) []byte { + answer := make([]byte, 0) + bs := make([]byte, 4) + binary.BigEndian.PutUint32(bs, uint32(n1)) + answer = append(answer, bs...) + binary.BigEndian.PutUint32(bs, uint32(n2)) + answer = append(answer, bs...) + return answer +} + +func packUint32(n1 int) []byte { + bs := make([]byte, 4) + binary.BigEndian.PutUint32(bs, uint32(n1)) + return bs +} + +func packUint16(n1 int) []byte { + bs := make([]byte, 2) + binary.BigEndian.PutUint16(bs, uint16(n1)) + return bs +} + +func keySortStrings(s map[string][]byte) []string { + keys := make([]string, len(s)) + i := 0 + for key := range s { + keys[i] = key + i++ + } + sort.Strings(keys) + return keys +} + +func keySortInt(s map[int]int) []int { + keys := make([]int, len(s)) + i := 0 + for key := range s { + keys[i] = key + i++ + } + sort.Ints(keys) + return keys +} + +func keySortArrayRangeMap(s map[int][]int) []int { + keys := make([]int, len(s)) + i := 0 + for key := range s { + keys[i] = key + i++ + } + 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.GenerateCutFont(runes) + return +} diff --git a/util.go b/util.go new file mode 100644 index 0000000..351d319 --- /dev/null +++ b/util.go @@ -0,0 +1,462 @@ +/* + * Copyright (c) 2013 Kurt Jung (Gmail: kurt.w.jung) + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +package gofpdf + +import ( + "bufio" + "bytes" + "compress/zlib" + "fmt" + "io" + "math" + "os" + "path/filepath" + "strings" +) + +func round(f float64) int { + if f < 0 { + return -int(math.Floor(-f + 0.5)) + } + return int(math.Floor(f + 0.5)) +} + +func sprintf(fmtStr string, args ...interface{}) string { + return fmt.Sprintf(fmtStr, args...) +} + +// fileExist returns true if the specified normal file exists +func fileExist(filename string) (ok bool) { + info, err := os.Stat(filename) + if err == nil { + if ^os.ModePerm&info.Mode() == 0 { + ok = true + } + } + return ok +} + +// fileSize returns the size of the specified file; ok will be false +// if the file does not exist or is not an ordinary file +func fileSize(filename string) (size int64, ok bool) { + info, err := os.Stat(filename) + ok = err == nil + if ok { + size = info.Size() + } + return +} + +// bufferFromReader returns a new buffer populated with the contents of the specified Reader +func bufferFromReader(r io.Reader) (b *bytes.Buffer, err error) { + b = new(bytes.Buffer) + _, err = b.ReadFrom(r) + return +} + +// slicesEqual returns true if the two specified float slices are equal +func slicesEqual(a, b []float64) bool { + if len(a) != len(b) { + return false + } + for i := range a { + if a[i] != b[i] { + return false + } + } + return true +} + +// sliceCompress returns a zlib-compressed copy of the specified byte array +func sliceCompress(data []byte) []byte { + var buf bytes.Buffer + cmp, _ := zlib.NewWriterLevel(&buf, zlib.BestSpeed) + cmp.Write(data) + cmp.Close() + return buf.Bytes() +} + +// sliceUncompress returns an uncompressed copy of the specified zlib-compressed byte array +func sliceUncompress(data []byte) (outData []byte, err error) { + inBuf := bytes.NewReader(data) + r, err := zlib.NewReader(inBuf) + defer r.Close() + if err == nil { + var outBuf bytes.Buffer + _, err = outBuf.ReadFrom(r) + if err == nil { + outData = outBuf.Bytes() + } + } + return +} + +// utf8toutf16 converts UTF-8 to UTF-16BE; from http://www.fpdf.org/ +func utf8toutf16(s string, withBOM ...bool) string { + bom := true + if len(withBOM) > 0 { + bom = withBOM[0] + } + res := make([]byte, 0, 8) + if bom { + res = append(res, 0xFE, 0xFF) + } + nb := len(s) + i := 0 + for i < nb { + c1 := byte(s[i]) + i++ + switch { + case c1 >= 224: + // 3-byte character + c2 := byte(s[i]) + i++ + c3 := byte(s[i]) + i++ + res = append(res, ((c1&0x0F)<<4)+((c2&0x3C)>>2), + ((c2&0x03)<<6)+(c3&0x3F)) + case c1 >= 192: + // 2-byte character + c2 := byte(s[i]) + i++ + res = append(res, ((c1 & 0x1C) >> 2), + ((c1&0x03)<<6)+(c2&0x3F)) + default: + // Single-byte character + res = append(res, 0, c1) + } + } + return string(res) +} + +// intIf returns a if cnd is true, otherwise b +func intIf(cnd bool, a, b int) int { + if cnd { + return a + } + return b +} + +// strIf returns aStr if cnd is true, otherwise bStr +func strIf(cnd bool, aStr, bStr string) string { + if cnd { + return aStr + } + return bStr +} + +// doNothing returns the passed string with no translation. +func doNothing(s string) string { + return s +} + +// Dump the internals of the specified values +// func dump(fileStr string, a ...interface{}) { +// fl, err := os.OpenFile(fileStr, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600) +// if err == nil { +// fmt.Fprintf(fl, "----------------\n") +// spew.Fdump(fl, a...) +// fl.Close() +// } +// } + +func repClosure(m map[rune]byte) func(string) string { + var buf bytes.Buffer + return func(str string) string { + var ch byte + var ok bool + buf.Truncate(0) + for _, r := range str { + if r < 0x80 { + ch = byte(r) + } else { + ch, ok = m[r] + if !ok { + ch = byte('.') + } + } + buf.WriteByte(ch) + } + return buf.String() + } +} + +// UnicodeTranslator returns a function that can be used to translate, where +// possible, utf-8 strings to a form that is compatible with the specified code +// page. The returned function accepts a string and returns a string. +// +// r is a reader that should read a buffer made up of content lines that +// pertain to the code page of interest. Each line is made up of three +// whitespace separated fields. The first begins with "!" and is followed by +// two hexadecimal digits that identify the glyph position in the code page of +// interest. The second field begins with "U+" and is followed by the unicode +// code point value. The third is the glyph name. A number of these code page +// map files are packaged with the gfpdf library in the font directory. +// +// An error occurs only if a line is read that does not conform to the expected +// format. In this case, the returned function is valid but does not perform +// any rune translation. +func UnicodeTranslator(r io.Reader) (f func(string) string, err error) { + m := make(map[rune]byte) + var uPos, cPos uint32 + var lineStr, nameStr string + sc := bufio.NewScanner(r) + for sc.Scan() { + lineStr = sc.Text() + lineStr = strings.TrimSpace(lineStr) + if len(lineStr) > 0 { + _, err = fmt.Sscanf(lineStr, "!%2X U+%4X %s", &cPos, &uPos, &nameStr) + if err == nil { + if cPos >= 0x80 { + m[rune(uPos)] = byte(cPos) + } + } + } + } + if err == nil { + f = repClosure(m) + } else { + f = doNothing + } + return +} + +// UnicodeTranslatorFromFile returns a function that can be used to translate, +// where possible, utf-8 strings to a form that is compatible with the +// specified code page. See UnicodeTranslator for more details. +// +// fileStr identifies a font descriptor file that maps glyph positions to names. +// +// If an error occurs reading the file, the returned function is valid but does +// not perform any rune translation. +func UnicodeTranslatorFromFile(fileStr string) (f func(string) string, err error) { + var fl *os.File + fl, err = os.Open(fileStr) + if err == nil { + f, err = UnicodeTranslator(fl) + fl.Close() + } else { + f = doNothing + } + return +} + +// UnicodeTranslatorFromDescriptor returns a function that can be used to +// translate, where possible, utf-8 strings to a form that is compatible with +// the specified code page. See UnicodeTranslator for more details. +// +// cpStr identifies a code page. A descriptor file in the font directory, set +// with the fontDirStr argument in the call to New(), should have this name +// plus the extension ".map". If cpStr is empty, it will be replaced with +// "cp1252", the gofpdf code page default. +// +// If an error occurs reading the descriptor, the returned function is valid +// but does not perform any rune translation. +// +// The CellFormat_codepage example demonstrates this method. +func (f *Fpdf) UnicodeTranslatorFromDescriptor(cpStr string) (rep func(string) string) { + var str string + var ok bool + if f.err == nil { + if len(cpStr) == 0 { + cpStr = "cp1252" + } + str, ok = embeddedMapList[cpStr] + if ok { + rep, f.err = UnicodeTranslator(strings.NewReader(str)) + } else { + rep, f.err = UnicodeTranslatorFromFile(filepath.Join(f.fontpath, cpStr) + ".map") + } + } else { + rep = doNothing + } + return +} + +// Transform moves a point by given X, Y offset +func (p *PointType) Transform(x, y float64) PointType { + return PointType{p.X + x, p.Y + y} +} + +// Orientation returns the orientation of a given size: +// "P" for portrait, "L" for landscape +func (s *SizeType) Orientation() string { + if s == nil || s.Ht == s.Wd { + return "" + } + if s.Wd > s.Ht { + return "L" + } + return "P" +} + +// ScaleBy expands a size by a certain factor +func (s *SizeType) ScaleBy(factor float64) SizeType { + return SizeType{s.Wd * factor, s.Ht * factor} +} + +// ScaleToWidth adjusts the height of a size to match the given width +func (s *SizeType) ScaleToWidth(width float64) SizeType { + height := s.Ht * width / s.Wd + return SizeType{width, height} +} + +// ScaleToHeight adjusts the width of a size to match the given height +func (s *SizeType) ScaleToHeight(height float64) SizeType { + width := s.Wd * height / s.Ht + return SizeType{width, height} +} + +//The untypedKeyMap structure and its methods are copyrighted 2019 by Arteom Korotkiy (Gmail: arteomkorotkiy). +//Imitation of untyped Map Array +type untypedKeyMap struct { + keySet []interface{} + valueSet []int +} + +//Get position of key=>value in PHP Array +func (pa *untypedKeyMap) getIndex(key interface{}) int { + if key != nil { + for i, mKey := range pa.keySet { + if mKey == key { + return i + } + } + return -1 + } + return -1 +} + +//Put key=>value in PHP Array +func (pa *untypedKeyMap) put(key interface{}, value int) { + if key == nil { + var i int + for n := 0; ; n++ { + i = pa.getIndex(n) + if i < 0 { + key = n + break + } + } + pa.keySet = append(pa.keySet, key) + pa.valueSet = append(pa.valueSet, value) + } else { + i := pa.getIndex(key) + if i < 0 { + pa.keySet = append(pa.keySet, key) + pa.valueSet = append(pa.valueSet, value) + } else { + pa.valueSet[i] = value + } + } +} + +//Delete value in PHP Array +func (pa *untypedKeyMap) delete(key interface{}) { + if pa == nil || pa.keySet == nil || pa.valueSet == nil { + return + } + i := pa.getIndex(key) + if i >= 0 { + if i == 0 { + pa.keySet = pa.keySet[1:] + pa.valueSet = pa.valueSet[1:] + } else if i == len(pa.keySet)-1 { + pa.keySet = pa.keySet[:len(pa.keySet)-1] + pa.valueSet = pa.valueSet[:len(pa.valueSet)-1] + } else { + pa.keySet = append(pa.keySet[:i], pa.keySet[i+1:]...) + pa.valueSet = append(pa.valueSet[:i], pa.valueSet[i+1:]...) + } + } +} + +//Get value from PHP Array +func (pa *untypedKeyMap) get(key interface{}) int { + i := pa.getIndex(key) + if i >= 0 { + return pa.valueSet[i] + } + return 0 +} + +//Imitation of PHP function pop() +func (pa *untypedKeyMap) pop() { + pa.keySet = pa.keySet[:len(pa.keySet)-1] + pa.valueSet = pa.valueSet[:len(pa.valueSet)-1] +} + +//Imitation of PHP function array_merge() +func arrayMerge(arr1, arr2 *untypedKeyMap) *untypedKeyMap { + answer := untypedKeyMap{} + if arr1 == nil && arr2 == nil { + answer = untypedKeyMap{ + make([]interface{}, 0), + make([]int, 0), + } + } else if arr2 == nil { + answer.keySet = arr1.keySet[:] + answer.valueSet = arr1.valueSet[:] + } else if arr1 == nil { + answer.keySet = arr2.keySet[:] + answer.valueSet = arr2.valueSet[:] + } else { + answer.keySet = arr1.keySet[:] + answer.valueSet = arr1.valueSet[:] + for i := 0; i < len(arr2.keySet); i++ { + if arr2.keySet[i] == "interval" { + if arr1.getIndex("interval") < 0 { + answer.put("interval", arr2.valueSet[i]) + } + } else { + answer.put(nil, arr2.valueSet[i]) + } + } + } + return &answer +} + +func remove(arr []int, key int) []int { + n := 0 + for i, mKey := range arr { + if mKey == key { + n = i + } + } + if n == 0 { + return arr[1:] + } else if n == len(arr)-1 { + return arr[:len(arr)-1] + } + return append(arr[:n], arr[n+1:]...) +} + +func isChinese(rune2 rune) bool { + // chinese unicode: 4e00-9fa5 + if rune2 >= rune(0x4e00) && rune2 <= rune(0x9fa5) { + return true + } + return false +} + +// 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 +}