From 93779987c426b8c09d620aa6bc48b95ffbef282a Mon Sep 17 00:00:00 2001 From: Claudio Felber Date: Sat, 27 Jun 2015 13:01:14 +0200 Subject: Add SetDashPattern() method --- def.go | 2 ++ fpdf.go | 39 +++++++++++++++++++++++++++++++++++++++ util.go | 13 +++++++++++++ 3 files changed, 54 insertions(+) diff --git a/def.go b/def.go index 47b399f..df21e05 100644 --- a/def.go +++ b/def.go @@ -195,6 +195,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 diff --git a/fpdf.go b/fpdf.go index 3f6f511..1508548 100644 --- a/fpdf.go +++ b/fpdf.go @@ -36,6 +36,7 @@ import ( "math" "os" "path" + "strconv" "strings" "time" ) @@ -565,6 +566,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 +780,40 @@ func (f *Fpdf) SetLineCapStyle(styleStr string) { } } +// SetDashPattern sets the dash pattern that is used to draw lines. +// The dashArray elements are numbers 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. +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) { diff --git a/util.go b/util.go index d3b114f..ed4ffdd 100644 --- a/util.go +++ b/util.go @@ -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 -- cgit v1.2.1-24-ge1ad From 5cb99b114890dc1ef96e06b70f26fe5cfae63db7 Mon Sep 17 00:00:00 2001 From: Claudio Felber Date: Sat, 27 Jun 2015 18:20:22 +0200 Subject: Add SetFontLoader() method to load fonts from arbitrary locations --- def.go | 11 +++++++++++ fpdf.go | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/def.go b/def.go index df21e05..33eca47 100644 --- a/def.go +++ b/def.go @@ -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 diff --git a/fpdf.go b/fpdf.go index 1508548..b2872e6 100644 --- a/fpdf.go +++ b/fpdf.go @@ -313,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 @@ -1358,8 +1366,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 @@ -2971,7 +2990,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 @@ -3071,6 +3090,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) -- cgit v1.2.1-24-ge1ad From f0690e7eabd6a1dc812923ce417ebdb7da490f14 Mon Sep 17 00:00:00 2001 From: Kurt Jung Date: Sat, 4 Jul 2015 13:14:40 -0400 Subject: Dashed lines: tutorial example and tip of hat to Claudio Felber --- .gitignore | 1 + doc.go | 3 ++- fpdf.go | 12 ++++++++---- fpdf_test.go | 4 +++- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index cde0305..78d0dfb 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ pdf.txt *.sublime* font/Ubuntu-* *.0 +*.swp diff --git a/doc.go b/doc.go index 55ff390..8e3c0e1 100644 --- a/doc.go +++ b/doc.go @@ -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/. diff --git a/fpdf.go b/fpdf.go index b2872e6..e516931 100644 --- a/fpdf.go +++ b/fpdf.go @@ -788,10 +788,14 @@ func (f *Fpdf) SetLineCapStyle(styleStr string) { } } -// SetDashPattern sets the dash pattern that is used to draw lines. -// The dashArray elements are numbers 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. +// 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 { 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") -- cgit v1.2.1-24-ge1ad