1package gofpdf 2 3import ( 4 "fmt" 5 "math" 6) 7 8// Routines in this file are translated from the work of Moritz Wagner and 9// Andreas Würmser. 10 11// TransformMatrix is used for generalized transformations of text, drawings 12// and images. 13type TransformMatrix struct { 14 A, B, C, D, E, F float64 15} 16 17// TransformBegin sets up a transformation context for subsequent text, 18// drawings and images. The typical usage is to immediately follow a call to 19// this method with a call to one or more of the transformation methods such as 20// TransformScale(), TransformSkew(), etc. This is followed by text, drawing or 21// image output and finally a call to TransformEnd(). All transformation 22// contexts must be properly ended prior to outputting the document. 23func (f *Fpdf) TransformBegin() { 24 f.transformNest++ 25 f.out("q") 26} 27 28// TransformScaleX scales the width of the following text, drawings and images. 29// scaleWd is the percentage scaling factor. (x, y) is center of scaling. 30// 31// The TransformBegin() example demonstrates this method. 32func (f *Fpdf) TransformScaleX(scaleWd, x, y float64) { 33 f.TransformScale(scaleWd, 100, x, y) 34} 35 36// TransformScaleY scales the height of the following text, drawings and 37// images. scaleHt is the percentage scaling factor. (x, y) is center of 38// scaling. 39// 40// The TransformBegin() example demonstrates this method. 41func (f *Fpdf) TransformScaleY(scaleHt, x, y float64) { 42 f.TransformScale(100, scaleHt, x, y) 43} 44 45// TransformScaleXY uniformly scales the width and height of the following 46// text, drawings and images. s is the percentage scaling factor for both width 47// and height. (x, y) is center of scaling. 48// 49// The TransformBegin() example demonstrates this method. 50func (f *Fpdf) TransformScaleXY(s, x, y float64) { 51 f.TransformScale(s, s, x, y) 52} 53 54// TransformScale generally scales the following text, drawings and images. 55// scaleWd and scaleHt are the percentage scaling factors for width and height. 56// (x, y) is center of scaling. 57// 58// The TransformBegin() example demonstrates this method. 59func (f *Fpdf) TransformScale(scaleWd, scaleHt, x, y float64) { 60 if scaleWd == 0 || scaleHt == 0 { 61 f.err = fmt.Errorf("scale factor cannot be zero") 62 return 63 } 64 y = (f.h - y) * f.k 65 x *= f.k 66 scaleWd /= 100 67 scaleHt /= 100 68 f.Transform(TransformMatrix{scaleWd, 0, 0, 69 scaleHt, x * (1 - scaleWd), y * (1 - scaleHt)}) 70} 71 72// TransformMirrorHorizontal horizontally mirrors the following text, drawings 73// and images. x is the axis of reflection. 74// 75// The TransformBegin() example demonstrates this method. 76func (f *Fpdf) TransformMirrorHorizontal(x float64) { 77 f.TransformScale(-100, 100, x, f.y) 78} 79 80// TransformMirrorVertical vertically mirrors the following text, drawings and 81// images. y is the axis of reflection. 82// 83// The TransformBegin() example demonstrates this method. 84func (f *Fpdf) TransformMirrorVertical(y float64) { 85 f.TransformScale(100, -100, f.x, y) 86} 87 88// TransformMirrorPoint symmetrically mirrors the following text, drawings and 89// images on the point specified by (x, y). 90// 91// The TransformBegin() example demonstrates this method. 92func (f *Fpdf) TransformMirrorPoint(x, y float64) { 93 f.TransformScale(-100, -100, x, y) 94} 95 96// TransformMirrorLine symmetrically mirrors the following text, drawings and 97// images on the line defined by angle and the point (x, y). angles is 98// specified in degrees and measured counter-clockwise from the 3 o'clock 99// position. 100// 101// The TransformBegin() example demonstrates this method. 102func (f *Fpdf) TransformMirrorLine(angle, x, y float64) { 103 f.TransformScale(-100, 100, x, y) 104 f.TransformRotate(-2*(angle-90), x, y) 105} 106 107// TransformTranslateX moves the following text, drawings and images 108// horizontally by the amount specified by tx. 109// 110// The TransformBegin() example demonstrates this method. 111func (f *Fpdf) TransformTranslateX(tx float64) { 112 f.TransformTranslate(tx, 0) 113} 114 115// TransformTranslateY moves the following text, drawings and images vertically 116// by the amount specified by ty. 117// 118// The TransformBegin() example demonstrates this method. 119func (f *Fpdf) TransformTranslateY(ty float64) { 120 f.TransformTranslate(0, ty) 121} 122 123// TransformTranslate moves the following text, drawings and images 124// horizontally and vertically by the amounts specified by tx and ty. 125// 126// The TransformBegin() example demonstrates this method. 127func (f *Fpdf) TransformTranslate(tx, ty float64) { 128 f.Transform(TransformMatrix{1, 0, 0, 1, tx * f.k, -ty * f.k}) 129} 130 131// TransformRotate rotates the following text, drawings and images around the 132// center point (x, y). angle is specified in degrees and measured 133// counter-clockwise from the 3 o'clock position. 134// 135// The TransformBegin() example demonstrates this method. 136func (f *Fpdf) TransformRotate(angle, x, y float64) { 137 y = (f.h - y) * f.k 138 x *= f.k 139 angle = angle * math.Pi / 180 140 var tm TransformMatrix 141 tm.A = math.Cos(angle) 142 tm.B = math.Sin(angle) 143 tm.C = -tm.B 144 tm.D = tm.A 145 tm.E = x + tm.B*y - tm.A*x 146 tm.F = y - tm.A*y - tm.B*x 147 f.Transform(tm) 148} 149 150// TransformSkewX horizontally skews the following text, drawings and images 151// keeping the point (x, y) stationary. angleX ranges from -90 degrees (skew to 152// the left) to 90 degrees (skew to the right). 153// 154// The TransformBegin() example demonstrates this method. 155func (f *Fpdf) TransformSkewX(angleX, x, y float64) { 156 f.TransformSkew(angleX, 0, x, y) 157} 158 159// TransformSkewY vertically skews the following text, drawings and images 160// keeping the point (x, y) stationary. angleY ranges from -90 degrees (skew to 161// the bottom) to 90 degrees (skew to the top). 162// 163// The TransformBegin() example demonstrates this method. 164func (f *Fpdf) TransformSkewY(angleY, x, y float64) { 165 f.TransformSkew(0, angleY, x, y) 166} 167 168// TransformSkew generally skews the following text, drawings and images 169// keeping the point (x, y) stationary. angleX ranges from -90 degrees (skew to 170// the left) to 90 degrees (skew to the right). angleY ranges from -90 degrees 171// (skew to the bottom) to 90 degrees (skew to the top). 172// 173// The TransformBegin() example demonstrates this method. 174func (f *Fpdf) TransformSkew(angleX, angleY, x, y float64) { 175 if angleX <= -90 || angleX >= 90 || angleY <= -90 || angleY >= 90 { 176 f.err = fmt.Errorf("skew values must be between -90° and 90°") 177 return 178 } 179 x *= f.k 180 y = (f.h - y) * f.k 181 var tm TransformMatrix 182 tm.A = 1 183 tm.B = math.Tan(angleY * math.Pi / 180) 184 tm.C = math.Tan(angleX * math.Pi / 180) 185 tm.D = 1 186 tm.E = -tm.C * y 187 tm.F = -tm.B * x 188 f.Transform(tm) 189} 190 191// Transform generally transforms the following text, drawings and images 192// according to the specified matrix. It is typically easier to use the various 193// methods such as TransformRotate() and TransformMirrorVertical() instead. 194func (f *Fpdf) Transform(tm TransformMatrix) { 195 if f.transformNest > 0 { 196 f.outf("%.5f %.5f %.5f %.5f %.5f %.5f cm", 197 tm.A, tm.B, tm.C, tm.D, tm.E, tm.F) 198 } else if f.err == nil { 199 f.err = fmt.Errorf("transformation context is not active") 200 } 201} 202 203// TransformEnd applies a transformation that was begun with a call to TransformBegin(). 204// 205// The TransformBegin() example demonstrates this method. 206func (f *Fpdf) TransformEnd() { 207 if f.transformNest > 0 { 208 f.transformNest-- 209 f.out("Q") 210 } else { 211 f.err = fmt.Errorf("error attempting to end transformation operation out of sequence") 212 } 213} 214