summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--def.go1
-rw-r--r--doc.go6
-rw-r--r--fpdf.go4
-rw-r--r--fpdf_test.go119
4 files changed, 128 insertions, 2 deletions
diff --git a/def.go b/def.go
index ed37f11..45ec09a 100644
--- a/def.go
+++ b/def.go
@@ -171,6 +171,7 @@ type Fpdf struct {
blendMap map[string]int // map into blendList
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
}
diff --git a/doc.go b/doc.go
index 85f34d4..6f960d9 100644
--- a/doc.go
+++ b/doc.go
@@ -23,7 +23,9 @@ directly from it. 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.
+adapted from Olivier Plathey by Manuel Cornes. Support for transformations is
+adapted from the FPDF transformation script by Moritz Wagner and Andreas
+Würmser.
The FPDF website is http://www.fpdf.org/.
@@ -51,6 +53,8 @@ Features
• Drawing support (lines, Bézier curves, arcs, ellipses)
+• Transformation support (rotation, scaling, skewing, translation, mirroring)
+
• Clipping
gofpdf has no dependencies other than the Go standard library. All tests pass
diff --git a/fpdf.go b/fpdf.go
index 50d1763..51dfad1 100644
--- a/fpdf.go
+++ b/fpdf.go
@@ -428,6 +428,8 @@ 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 {
@@ -1148,7 +1150,7 @@ func (f *Fpdf) ClipEnd() {
f.clipNest--
f.out("Q")
} else {
- f.err = fmt.Errorf("Error attempting to end clip operation")
+ f.err = fmt.Errorf("Error attempting to end clip operation out of sequence")
}
}
}
diff --git a/fpdf_test.go b/fpdf_test.go
index fad67bc..ccdf1bf 100644
--- a/fpdf_test.go
+++ b/fpdf_test.go
@@ -964,3 +964,122 @@ func ExampleFpdf_tutorial16() {
// Output:
// Successfully generated pdf/tutorial16.pdf
}
+
+// Transformation test adapted from an example script by Moritz Wagner and
+// Andreas Würmser.
+func ExampleFpdf_tutorial17() {
+ const (
+ light = 200
+ dark = 0
+ )
+ var refX, refY float64
+ var refStr string
+ pdf := gofpdf.New("P", "mm", "A4", FONT_DIR)
+ 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 := titlePt * 25.4 / 72.0
+ 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()
+
+ pdf.OutputAndClose(docWriter(pdf, 17))
+ // Output:
+ // Successfully generated pdf/tutorial17.pdf
+}