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  }