diff options
author | Kurt Jung <kurt.w.jung@gmail.com> | 2015-07-04 13:18:12 -0400 |
---|---|---|
committer | Kurt Jung <kurt.w.jung@gmail.com> | 2015-07-04 13:18:12 -0400 |
commit | 1d655638f9c01bdf29aaee195a6628e79f963cfb (patch) | |
tree | 18d446216908d4bbddde478010c9052c6ad870ee | |
parent | 5ab948816dec877984e3c1c031f423cb7fccf30f (diff) | |
parent | f0690e7eabd6a1dc812923ce417ebdb7da490f14 (diff) |
Claudio Felber's dashed line implementation
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | def.go | 13 | ||||
-rw-r--r-- | doc.go | 3 | ||||
-rw-r--r-- | fpdf.go | 80 | ||||
-rw-r--r-- | fpdf_test.go | 4 | ||||
-rw-r--r-- | util.go | 13 |
6 files changed, 110 insertions, 4 deletions
@@ -6,3 +6,4 @@ pdf.txt *.sublime* font/Ubuntu-* *.0 +*.swp @@ -18,6 +18,7 @@ package gofpdf import ( "bytes" + "io" ) // Version of FPDF from which this package is derived @@ -132,6 +133,15 @@ type InitType struct { 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 +// does never include a path. Open returns an error if the specified file cannot be opened. +type FontLoader interface { + Open(name string) (io.Reader, error) +} + // Fpdf is the principal structure for creating a single PDF document type Fpdf struct { page int // current page number @@ -160,6 +170,7 @@ type Fpdf struct { 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 @@ -195,6 +206,8 @@ type Fpdf struct { 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 gradientList []gradientType // slice[idx] of gradient records @@ -71,7 +71,8 @@ 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. -Bruno Michel has provided valuable assistance with the code. +Claudio Felber provided implementations for dashed line drawing and generalized +font loading. Bruno Michel has provided valuable assistance with the code. The FPDF website is http://www.fpdf.org/. @@ -36,6 +36,7 @@ import ( "math" "os" "path" + "strconv" "strings" "time" ) @@ -312,6 +313,14 @@ func (f *Fpdf) SetFontLocation(fontDirStr string) { f.fontpath = fontDirStr } +// SetFontLoader sets a loader used to load font files (.json and .z) from +// arbitrary locations. If a font loader has been specified, Fpdf first tries +// to load files using the font loader. If the loading files Fpdf tries to +// load the font from the configured fonts directory (see SetFontLocation). +func (f *Fpdf) SetFontLoader(loader FontLoader) { + f.fontLoader = loader +} + // 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 @@ -565,6 +574,10 @@ func (f *Fpdf) AddPageFormat(orientationStr string, size SizeType) { // 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) @@ -775,6 +788,44 @@ func (f *Fpdf) SetLineCapStyle(styleStr string) { } } +// SetDashPattern sets the dash pattern that is used to draw lines. The +// dashArray elements are numbers, in units established in New(), that specify +// the lengths 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. +// +// See tutorial 28 for an example of this function. +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 + if !slicesEqual(scaled, f.dashArray) || dashPhase != f.dashPhase { + 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) { @@ -1319,8 +1370,19 @@ func (f *Fpdf) AddFont(familyStr, styleStr, fileStr string) { if fileStr == "" { fileStr = strings.Replace(familyStr, " ", "", -1) + strings.ToLower(styleStr) + ".json" } - fileStr = path.Join(f.fontpath, fileStr) + 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 @@ -2932,7 +2994,7 @@ func (f *Fpdf) putfonts() { f.newobj() info.n = f.n f.fontFiles[file] = info - font, err := ioutil.ReadFile(path.Join(f.fontpath, file)) + font, err := f.loadFontFile(file) if err != nil { f.err = err return @@ -3032,6 +3094,20 @@ func (f *Fpdf) putfonts() { return } +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() { for _, img := range f.images { f.putimage(img) diff --git a/fpdf_test.go b/fpdf_test.go index f8df0c3..bb69569 100644 --- a/fpdf_test.go +++ b/fpdf_test.go @@ -1415,8 +1415,10 @@ func ExampleFpdf_tutorial28() { srcPrev = src } pdf.MultiCell(wd-margin-margin, ln, msgStr, "", "C", false) - pdf.SetDrawColor(224, 224, 224) + 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") @@ -69,6 +69,19 @@ func bufferFromReader(r io.Reader) (b *bytes.Buffer, err error) { return } +// Returns true if the two specified integer 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 +} + // Returns a zlib-compressed copy of the specified byte array func sliceCompress(data []byte) []byte { var buf bytes.Buffer |