summaryrefslogtreecommitdiff
path: root/fpdftrans.go
blob: b87d9b969da78d6e3a900167cda8e1c5f4c5c5dc (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
181
182
183
package gofpdf

import (
	"fmt"
	"math"
)

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

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

// TransformBegin sets 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")
}

// TransformScaleX scales 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)
}

// TransformScaleY scales 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)
}

// TransformScaleXY uniformly scales 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)
}

// TransformScale generally scales 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)})
}

// TransformMirrorHorizontal horizontally mirrors 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)
}

// TransformMirrorVertical vertically mirrors 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)
}

// TransformMirrorPoint symmetrically mirrors 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)
}

// TransformMirrorLine symmetrically mirrors 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)
}

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

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

// TransformTranslate moves 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})
}

// TransformRotate rotates 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)
}

// TransformSkewX horizontally skews 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)
}

// TransformSkewY vertically skews 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)
}

// TransformSkew generally skews 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)
}

// Transform generally transforms 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")
	}
}

// TransformEnd applies 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")
	}
}