# Transformations

## Performs the following 2D transformations: scaling, mirroring, translation, rotation and skewing

### Informations

Authors: Moritz Wagner & Andreas Würmser

### Description

Performs the following 2D transformations: scaling, mirroring, translation, rotation and skewing.
Use StartTransform() before, and StopTransform() after the transformations to restore the normal behavior.

`StartTransform()`

Use this before calling any tranformation.

`ScaleX(float s_x [, float x [, float y]])`
`ScaleY(float s_y [, float x [, float y]])`
`ScaleXY(float s [, float x [, float y]])`
`Scale(float s_x, float s_y [, float x [, float y]])`

s_x: scaling factor for width as percent. 0 is not allowed.
s_y: scaling factor for height as percent. 0 is not allowed.
s: scaling factor for width and height as percent. 0 is not allowed.
x: abscissa of the scaling center. Default is current x position
y: ordinate of the scaling center. Default is current y position

`MirrorH([float x])`

Alias for scaling -100% in x-direction
x: abscissa of the axis of reflection

`MirrorV([float y])`

Alias for scaling -100% in y-direction
y: ordinate of the axis of reflection

`MirrorP([float x, [float y]])`

Point reflection on point (x, y). (alias for scaling -100 in x- and y-direction)
x: abscissa of the point. Default is current x position
y: ordinate of the point. Default is current y position

`MirrorL([float angle [, float x [, float y]]])`

Reflection against a straight line through point (x, y) with the gradient angle (angle).
angle: gradient angle of the straight line. Default is 0 (horizontal line).
x: abscissa of the point. Default is current x position
y: ordinate of the point. Default is current y position

`TranslateX(float t_x)`
`TranslateY(float t_y)`
`Translate(float t_x, float t_y)`

t_x: movement to the right
t_y: movement to the bottom

`Rotate(float angle [, float x [, float y]])`

angle: angle in degrees for counter-clockwise rotation
x: abscissa of the rotation center. Default is current x position
y: ordinate of the rotation center. Default is current y position

`SkewX(float angle_x [, float x [, float y]])`
`SkewY(float angle_y [, float x [, float y]])`
`Skew(float angle_x, float angle_y [, float x [, float y]])`

angle_x: angle in degrees between -90 (skew to the left) and 90 (skew to the right)
angle_y: angle in degrees between -90 (skew to the bottom) and 90 (skew to the top)
x: abscissa of the skewing center. default is current x position
y: ordinate of the skewing center. default is current y position

`StopTransform()`

Restores the normal painting and placing behavior as it was before calling StartTransform().

### Source

```<?php /* Version 2 Changes since version 1: - added function MirrorP() - added function MirrorL() - fixed bug in Translate(): the movement is now performed in user units instead of pts */ require('fpdf.php'); class PDF_Transform extends FPDF{ function StartTransform(){ //save the current graphic state \$this->_out('q'); } function ScaleX(\$s_x, \$x='', \$y=''){ \$this->Scale(\$s_x, 100, \$x, \$y); } function ScaleY(\$s_y, \$x='', \$y=''){ \$this->Scale(100, \$s_y, \$x, \$y); } function ScaleXY(\$s, \$x='', \$y=''){ \$this->Scale(\$s, \$s, \$x, \$y); } function Scale(\$s_x, \$s_y, \$x='', \$y=''){ if(\$x === '') \$x=\$this->x; if(\$y === '') \$y=\$this->y; if(\$s_x == 0 || \$s_y == 0) \$this->Error('Please use values unequal to zero for Scaling'); \$y=(\$this->h-\$y)*\$this->k; \$x*=\$this->k; //calculate elements of transformation matrix \$s_x/=100; \$s_y/=100; \$tm[0]=\$s_x; \$tm[1]=0; \$tm[2]=0; \$tm[3]=\$s_y; \$tm[4]=\$x*(1-\$s_x); \$tm[5]=\$y*(1-\$s_y); //scale the coordinate system \$this->Transform(\$tm); } function MirrorH(\$x=''){ \$this->Scale(-100, 100, \$x); } function MirrorV(\$y=''){ \$this->Scale(100, -100, '', \$y); } function MirrorP(\$x='', \$y=''){ \$this->Scale(-100, -100, \$x, \$y); } function MirrorL(\$angle=0, \$x='', \$y=''){ \$this->Scale(-100, 100, \$x, \$y); \$this->Rotate(-2*(\$angle-90), \$x, \$y); } function TranslateX(\$t_x){ \$this->Translate(\$t_x, 0, \$x, \$y); } function TranslateY(\$t_y){ \$this->Translate(0, \$t_y, \$x, \$y); } function Translate(\$t_x, \$t_y){ //calculate elements of transformation matrix \$tm[0]=1; \$tm[1]=0; \$tm[2]=0; \$tm[3]=1; \$tm[4]=\$t_x*\$this->k; \$tm[5]=-\$t_y*\$this->k; //translate the coordinate system \$this->Transform(\$tm); } function Rotate(\$angle, \$x='', \$y=''){ if(\$x === '') \$x=\$this->x; if(\$y === '') \$y=\$this->y; \$y=(\$this->h-\$y)*\$this->k; \$x*=\$this->k; //calculate elements of transformation matrix \$tm[0]=cos(deg2rad(\$angle)); \$tm[1]=sin(deg2rad(\$angle)); \$tm[2]=-\$tm[1]; \$tm[3]=\$tm[0]; \$tm[4]=\$x+\$tm[1]*\$y-\$tm[0]*\$x; \$tm[5]=\$y-\$tm[0]*\$y-\$tm[1]*\$x; //rotate the coordinate system around (\$x, \$y) \$this->Transform(\$tm); } function SkewX(\$angle_x, \$x='', \$y=''){ \$this->Skew(\$angle_x, 0, \$x, \$y); } function SkewY(\$angle_y, \$x='', \$y=''){ \$this->Skew(0, \$angle_y, \$x, \$y); } function Skew(\$angle_x, \$angle_y, \$x='', \$y=''){ if(\$x === '') \$x=\$this->x; if(\$y === '') \$y=\$this->y; if(\$angle_x <= -90 || \$angle_x >= 90 || \$angle_y <= -90 || \$angle_y >= 90) \$this->Error('Please use values between -90° and 90° for skewing'); \$x*=\$this->k; \$y=(\$this->h-\$y)*\$this->k; //calculate elements of transformation matrix \$tm[0]=1; \$tm[1]=tan(deg2rad(\$angle_y)); \$tm[2]=tan(deg2rad(\$angle_x)); \$tm[3]=1; \$tm[4]=-\$tm[2]*\$y; \$tm[5]=-\$tm[1]*\$x; //skew the coordinate system \$this->Transform(\$tm); } function Transform(\$tm){ \$this->_out(sprintf('%.3F %.3F %.3F %.3F %.3F %.3F cm', \$tm[0], \$tm[1], \$tm[2], \$tm[3], \$tm[4], \$tm[5])); } function StopTransform(){ //restore previous graphic state \$this->_out('Q'); } } ?>```

### Example

```<?php require('transform.php'); \$pdf = new PDF_Transform(); \$pdf->AddPage(); \$pdf->SetFont('Arial', '', 12); //Scaling \$pdf->SetDrawColor(200); \$pdf->SetTextColor(200); \$pdf->Rect(50, 20, 40, 10, 'D'); \$pdf->Text(50, 19, 'Scale'); \$pdf->SetDrawColor(0); \$pdf->SetTextColor(0); //Start Transformation \$pdf->StartTransform(); //Scale by 150% centered by (50, 30) which is the lower left corner of the rectangle \$pdf->ScaleXY(150, 50, 30); \$pdf->Rect(50, 20, 40, 10, 'D'); \$pdf->Text(50, 19, 'Scale'); //Stop Transformation \$pdf->StopTransform(); //Translation \$pdf->SetDrawColor(200); \$pdf->SetTextColor(200); \$pdf->Rect(125, 20, 40, 10, 'D'); \$pdf->Text(125, 19, 'Translate'); \$pdf->SetDrawColor(0); \$pdf->SetTextColor(0); //Start Transformation \$pdf->StartTransform(); //Translate 7 to the right, 5 to the bottom \$pdf->Translate(7, 5); \$pdf->Rect(125, 20, 40, 10, 'D'); \$pdf->Text(125, 19, 'Translate'); //Stop Transformation \$pdf->StopTransform(); //Rotation \$pdf->SetDrawColor(200); \$pdf->SetTextColor(200); \$pdf->Rect(50, 50, 40, 10, 'D'); \$pdf->Text(50, 49, 'Rotate'); \$pdf->SetDrawColor(0); \$pdf->SetTextColor(0); //Start Transformation \$pdf->StartTransform(); //Rotate 20 degrees counter-clockwise centered by (50, 60) which is the lower left corner of the rectangle \$pdf->Rotate(20, 50, 60); \$pdf->Rect(50, 50, 40, 10, 'D'); \$pdf->Text(50, 49, 'Rotate'); //Stop Transformation \$pdf->StopTransform(); //Skewing \$pdf->SetDrawColor(200); \$pdf->SetTextColor(200); \$pdf->Rect(125, 50, 40, 10, 'D'); \$pdf->Text(125, 49, 'Skew'); \$pdf->SetDrawColor(0); \$pdf->SetTextColor(0); //Start Transformation \$pdf->StartTransform(); //skew 30 degrees along the x-axis centered by (125, 60) which is the lower left corner of the rectangle \$pdf->SkewX(30, 125, 60); \$pdf->Rect(125, 50, 40, 10, 'D'); \$pdf->Text(125, 49, 'Skew'); //Stop Transformation \$pdf->StopTransform(); //Mirroring horizontally \$pdf->SetDrawColor(200); \$pdf->SetTextColor(200); \$pdf->Rect(50, 80, 40, 10, 'D'); \$pdf->Text(50, 79, 'MirrorH'); \$pdf->SetDrawColor(0); \$pdf->SetTextColor(0); //Start Transformation \$pdf->StartTransform(); //mirror horizontally with axis of reflection at x-position 50 (left side of the rectangle) \$pdf->MirrorH(50); \$pdf->Rect(50, 80, 40, 10, 'D'); \$pdf->Text(50, 79, 'MirrorH'); //Stop Transformation \$pdf->StopTransform(); //Mirroring vertically \$pdf->SetDrawColor(200); \$pdf->SetTextColor(200); \$pdf->Rect(125, 80, 40, 10, 'D'); \$pdf->Text(125, 79, 'MirrorV'); \$pdf->SetDrawColor(0); \$pdf->SetTextColor(0); //Start Transformation \$pdf->StartTransform(); //mirror vertically with axis of reflection at y-position 90 (bottom side of the rectangle) \$pdf->MirrorV(90); \$pdf->Rect(125, 80, 40, 10, 'D'); \$pdf->Text(125, 79, 'MirrorV'); //Stop Transformation \$pdf->StopTransform(); //Point reflection \$pdf->SetDrawColor(200); \$pdf->SetTextColor(200); \$pdf->Rect(50, 110, 40, 10, 'D'); \$pdf->Text(50, 109, 'MirrorP'); \$pdf->SetDrawColor(0); \$pdf->SetTextColor(0); //Start Transformation \$pdf->StartTransform(); //point reflection at the lower left point of rectangle \$pdf->MirrorP(50, 120); \$pdf->Rect(50, 110, 40, 10, 'D'); \$pdf->Text(50, 109, 'MirrorP'); //Stop Transformation \$pdf->StopTransform(); //Mirroring against a straigth line described by a point (120, 120) and an angle -20° \$angle=-20; \$px=120; \$py=120; /* */ //just vor visualisation: the straight line to mirror against /* */ \$pdf->SetDrawColor(200); /* */ \$pdf->Line(\$px-1, \$py-1, \$px+1, \$py+1); /* */ \$pdf->Line(\$px-1, \$py+1, \$px+1, \$py-1); /* */ \$pdf->StartTransform(); /* */ \$pdf->Rotate(\$angle, \$px, \$py); /* */ \$pdf->Line(\$px-5, \$py, \$px+60, \$py); /* */ \$pdf->StopTransform(); \$pdf->SetDrawColor(200); \$pdf->SetTextColor(200); \$pdf->Rect(125, 110, 40, 10, 'D'); \$pdf->Text(125, 109, 'MirrorL'); \$pdf->SetDrawColor(0); \$pdf->SetTextColor(0); //Start Transformation \$pdf->StartTransform(); //mirror against the straight line \$pdf->MirrorL(\$angle, \$px, \$py); \$pdf->Rect(125, 110, 40, 10, 'D'); \$pdf->Text(125, 109, 'MirrorL'); //Stop Transformation \$pdf->StopTransform(); \$pdf->Output(); ?>```
View the result here.