summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKurt Jung <kurt.w.jung@gmail.com>2015-07-04 13:18:12 -0400
committerKurt Jung <kurt.w.jung@gmail.com>2015-07-04 13:18:12 -0400
commit1d655638f9c01bdf29aaee195a6628e79f963cfb (patch)
tree18d446216908d4bbddde478010c9052c6ad870ee
parent5ab948816dec877984e3c1c031f423cb7fccf30f (diff)
parentf0690e7eabd6a1dc812923ce417ebdb7da490f14 (diff)
Claudio Felber's dashed line implementation
-rw-r--r--.gitignore1
-rw-r--r--def.go13
-rw-r--r--doc.go3
-rw-r--r--fpdf.go80
-rw-r--r--fpdf_test.go4
-rw-r--r--util.go13
6 files changed, 110 insertions, 4 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/def.go b/def.go
index 47b399f..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
@@ -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
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 3f6f511..e516931 100644
--- a/fpdf.go
+++ b/fpdf.go
@@ -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")
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