summaryrefslogtreecommitdiff
path: root/fpdftrans.go
blob: 86d9de84169f31d0360bde022fe7f83fc3d15aa9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package gofpdf

import (
	"fmt"
	"math"
)

// Routines in this file are translated from the work of Moritz Wagner and
// Andreas Würmser.

// The matrix used for generalized transformations of text, drawings and images.
type TransformMatrix struct {
	A, B, C, D, E, F float64
}

// Set 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.
//
// See tutorial 17 for transformation examples.
func (f *Fpdf) TransformBegin() {
	f.transformNest++
	f.out("q")
}

// Scale the width of the following text, drawings and images. scaleWd is the
// percentage scaling factor. (x, y) is center of scaling.
func (f *Fpdf) TransformScaleX(scaleWd, x, y float64) {
	f.TransformScale(scaleWd, 100, x, y)
}

// Scale the height of the following text, drawings and images. scaleHt is the
// percentage scaling factor. (x, y) is center of scaling.
func (f *Fpdf) TransformScaleY(scaleHt, x, y float64) {
	f.TransformScale(100, scaleHt, x, y)
}

// Uniformly scale 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.
func (f *Fpdf) TransformScaleXY(s, x, y float64) {
	f.TransformScale(s, s, x, y)
}

// Generally scale the following text, drawings and images. scaleWd and scaleHt
// are the percentage scaling factors for width and height. (x, y) is center of
// scaling.
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)})
}

// Horizontally mirror the following text, drawings and images. x is the axis
// of reflection.
func (f *Fpdf) TransformMirrorHorizontal(x float64) {
	f.TransformScale(-100, 100, x, f.y)
}

// Vertically mirror the following text, drawings and images. y is the axis
// of reflection.
func (f *Fpdf) TransformMirrorVertical(y float64) {
	f.TransformScale(100, -100, f.x, y)
}

// Symmetrically mirror the following text, drawings and images on the point
// specified by (x, y).
func (f *Fpdf) TransformMirrorPoint(x, y float64) {
	f.TransformScale(-100, -100, x, y)
}

// Symmetrically mirror 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.
func (f *Fpdf) TransformMirrorLine(angle, x, y float64) {
	f.TransformScale(-100, 100, x, y)
	f.TransformRotate(-2*(angle-90), x, y)
}

// Move the following text, drawings and images horizontally by the amount
// specified by tx.
func (f *Fpdf) TransformTranslateX(tx float64) {
	f.TransformTranslate(tx, 0)
}

// Move the following text, drawings and images vertically by the amount
// specified by ty.
func (f *Fpdf) TransformTranslateY(ty float64) {
	f.TransformTranslate(0, ty)
}

// Move the following text, drawings and images horizontally and vertically by
// the amounts specified by tx and ty.
func (f *Fpdf) TransformTranslate(tx, ty float64) {
	f.Transform(TransformMatrix{1, 0, 0, 1, tx * f.k, -ty * f.k})
}

// Rotate 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.
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)
}

// Horizontally skew 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).
func (f *Fpdf) TransformSkewX(angleX, x, y float64) {
	f.TransformSkew(angleX, 0, x, y)
}

// Vertically skew 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).
func (f *Fpdf) TransformSkewY(angleY, x, y float64) {
	f.TransformSkew(0, angleY, x, y)
}

// Generally skew 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).
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)
}

// Generally transform 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")
	}
}

// Apply a transformation that was begun with a call to TransformBegin().
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")
	}
}