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