source-class-Com.Tecnick.Pdf.Graph.Gradient

It appears that you are using AdBlocking software. The cost of running this website is covered by advertisements. If you like it please feel free to a small amount of money to secure the future of this website.
  1: <?php
  2: /**
  3:  * Gradient.php
  4:  *
  5:  * @since       2011-05-23
  6:  * @category    Library
  7:  * @package     PdfGraph
  8:  * @author      Nicola Asuni <info@tecnick.com>
  9:  * @copyright   2011-2016 Nicola Asuni - Tecnick.com LTD
 10:  * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 11:  * @link        https://github.com/tecnickcom/tc-lib-pdf-graph
 12:  *
 13:  * This file is part of tc-lib-pdf-graph software library.
 14:  */
 15: 
 16: namespace Com\Tecnick\Pdf\Graph;
 17: 
 18: use \Com\Tecnick\Pdf\Graph\Exception as GraphException;
 19: 
 20: /**
 21:  * Com\Tecnick\Pdf\Graph\Gradient
 22:  *
 23:  * @since       2011-05-23
 24:  * @category    Library
 25:  * @package     PdfGraph
 26:  * @author      Nicola Asuni <info@tecnick.com>
 27:  * @copyright   2011-2016 Nicola Asuni - Tecnick.com LTD
 28:  * @license     http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
 29:  * @link        https://github.com/tecnickcom/tc-lib-pdf-graph
 30:  */
 31: abstract class Gradient extends \Com\Tecnick\Pdf\Graph\Raw
 32: {
 33:     /**
 34:      * Array of gradients
 35:      *
 36:      * @var array
 37:      */
 38:     protected $gradients = array();
 39: 
 40:     /**
 41:      * Returns the gradients array
 42:      *
 43:      * @return array
 44:      */
 45:     public function getGradientsArray()
 46:     {
 47:         return $this->gradients;
 48:     }
 49: 
 50:     /**
 51:      * Get a linear colour gradient command.
 52:      *
 53:      * @param float  $posx       Abscissa of the top left corner of the rectangle.
 54:      * @param float  $posy       Ordinate of the top left corner of the rectangle.
 55:      * @param float  $width      Width of the rectangle.
 56:      * @param float  $height     Height of the rectangle.
 57:      * @param string $colorstart Starting color.
 58:      * @param string $colorend   Ending color.
 59:      * @param array  $coords     Gradient vector (x1, y1, x2, y2).
 60:      *
 61:      * @return string PDF command
 62:      */
 63:     public function getLinearGradient(
 64:         $posx,
 65:         $posy,
 66:         $width,
 67:         $height,
 68:         $colorstart,
 69:         $colorend,
 70:         $coords = array(0,0,1,0)
 71:     ) {
 72:         return $this->getStartTransform()
 73:         .$this->getClippingRect($posx, $posy, $width, $height)
 74:         .$this->getGradientTransform($posx, $posy, $width, $height)
 75:         .$this->getGradient(
 76:             2,
 77:             $coords,
 78:             array(
 79:                 array(
 80:                     'color' => $colorstart,
 81:                     'offset' => 0,
 82:                     'exponent' => 1
 83:                 ),
 84:                 array(
 85:                     'color' => $colorend,
 86:                     'offset' => 1,
 87:                     'exponent' => 1
 88:                 )
 89:             ),
 90:             '',
 91:             false
 92:         )
 93:         .$this->getStopTransform();
 94:     }
 95: 
 96:     /**
 97:      * Get a radial colour gradient command.
 98:      *
 99:      * @param float  $posx       Abscissa of the top left corner of the rectangle.
100:      * @param float  $posy       Ordinate of the top left corner of the rectangle.
101:      * @param float  $width      Width of the rectangle.
102:      * @param float  $height     Height of the rectangle.
103:      * @param string $colorstart Starting color.
104:      * @param string $colorend   Ending color.
105:      * @param array  $coords     Array of the form (fx, fy, cx, cy, r) where
106:      *                           (fx, fy) is the starting point of the gradient with $colorstart (be inside the circle),
107:      *                           (cx, cy) is the center of the circle with $colorend,
108:      *                           and r is the radius of the circle.
109:      *
110:      * @return string PDF command
111:      */
112:     public function getRadialGradient(
113:         $posx,
114:         $posy,
115:         $width,
116:         $height,
117:         $colorstart,
118:         $colorend,
119:         $coords = array(0.5,0.5,0.5,0.5,1)
120:     ) {
121:         return $this->getStartTransform()
122:         .$this->getClippingRect($posx, $posy, $width, $height)
123:         .$this->getGradientTransform($posx, $posy, $width, $height)
124:         .$this->getGradient(
125:             3,
126:             $coords,
127:             array(
128:                 array(
129:                     'color' => $colorstart,
130:                     'offset' => 0,
131:                     'exponent' => 1
132:                 ),
133:                 array(
134:                     'color' => $colorend,
135:                     'offset' => 1,
136:                     'exponent' => 1
137:                 )
138:             ),
139:             '',
140:             false
141:         )
142:         .$this->getStopTransform();
143:     }
144: 
145:     /**
146:      * Rectangular clipping area.
147:      *
148:      * @param float $posx   Abscissa of the top left corner of the rectangle.
149:      * @param float $posy   Ordinate of the top left corner of the rectangle.
150:      * @param float $width  Width of the rectangle.
151:      * @param float $height Height of the rectangle.
152:      *
153:      * @return string
154:      */
155:     public function getClippingRect($posx, $posy, $width, $height)
156:     {
157:         return sprintf(
158:             '%F %F %F %F re W n'."\n",
159:             ($posx * $this->kunit),
160:             (($this->pageh - $posy) * $this->kunit),
161:             ($width * $this->kunit),
162:             (-$height * $this->kunit)
163:         );
164:     }
165: 
166:     /**
167:      * Rectangular clipping area.
168:      *
169:      * @param float $posx   Abscissa of the top left corner of the rectangle.
170:      * @param float $posy   Ordinate of the top left corner of the rectangle.
171:      * @param float $width  Width of the rectangle.
172:      * @param float $height Height of the rectangle.
173:      *
174:      * @return string
175:      */
176:     public function getGradientTransform($posx, $posy, $width, $height)
177:     {
178:         $ctm = array(
179:             ($width * $this->kunit),
180:             0,
181:             0,
182:             ($height * $this->kunit),
183:             ($posx * $this->kunit),
184:             (($this->pageh - ($posy + $height)) * $this->kunit)
185:         );
186:         return $this->getTransformation($ctm);
187:     }
188: 
189:     /**
190:      * Get a color gradient command.
191:      *
192:      * @param int   $type       Type of gradient (Not all types are currently supported):
193:      *                          1 = Function-based shading;
194:      *                          2 = Axial shading;
195:      *                          3 = Radial shading;
196:      *                          4 = Free-form Gouraud-shaded triangle mesh;
197:      *                          5 = Lattice-form Gouraud-shaded triangle mesh;
198:      *                          6 = Coons patch mesh; 7 Tensor-product patch mesh
199:      * @param array $coords     Array of coordinates.
200:      * @param array $stops      Array gradient color components:
201:      *                          color = color;
202:      *                          offset = (0 to 1) represents a location along the gradient vector;
203:      *                          exponent = exponent of the exponential interpolation function (default = 1).
204:      * @param string $bgcolor   Background color
205:      * @param bool   $antialias Flag indicating whether to filter the shading function to prevent aliasing artifacts.
206:      *
207:      * @return string PDF command
208:      */
209:     public function getGradient($type, $coords, $stops, $bgcolor, $antialias = false)
210:     {
211:         if ($this->pdfa) {
212:             return '';
213:         }
214: 
215:         $map_colspace = array('CMYK' => 'DeviceCMYK', 'RGB' => 'DeviceRGB', 'GRAY' => 'DeviceGray');
216:         $ngr = (1 + count($this->gradients));
217:         $this->gradients[$ngr] = $this->getGradientStops(
218:             array(
219:                 'type' => $type,
220:                 'coords' => $coords,
221:                 'antialias' => $antialias,
222:                 'colors' => array(),
223:                 'transparency' => false,
224:                 'background' => $this->col->getColorObject($bgcolor),
225:                 'colspace' => $map_colspace[$this->col->getColorObject($stops[0]['color'])->getType()],
226:             ),
227:             $stops
228:         );
229:         
230:         $out = '';
231:         if ($this->gradients[$ngr]['transparency']) {
232:             // paint luminosity gradient
233:             $out .= '/TGS'.$ngr.' gs'."\n";
234:         }
235:         // paint the gradient
236:         $out .= '/Sh'.$ngr.' sh'."\n";
237: 
238:         return $out;
239:     }
240: 
241:     /**
242:      * Process the gradient stops.
243:      *
244:      * @param array $grad       Array containing gradient info
245:      * @param array $stops      Array gradient color components:
246:      *                          color = color;
247:      *                          offset = (0 to 1) represents a location along the gradient vector;
248:      *                          exponent = exponent of the exponential interpolation function (default = 1).
249:      *
250:      * @return array Gradient array.
251:      */
252:     protected function getGradientStops($grad, $stops)
253:     {
254:         $num_stops = count($stops);
255:         $last_stop_id = ($num_stops - 1);
256: 
257:         foreach ($stops as $key => $stop) {
258:             $grad['colors'][$key] = array();
259:             $grad['colors'][$key]['color'] = $stop['color'];
260:             $grad['colors'][$key]['exponent'] = 1;
261:             if (isset($stop['exponent'])) {
262:                 // exponent for the interpolation function
263:                 $grad['colors'][$key]['exponent'] = $stop['exponent'];
264:             }
265:             $grad['colors'][$key]['opacity'] = 1;
266:             if (isset($stop['opacity'])) {
267:                 $grad['colors'][$key]['opacity'] = $stop['opacity'];
268:                 $grad['transparency'] = ($grad['transparency'] || ($stop['opacity'] < 1));
269:             }
270:             // offset represents a location along the gradient vector
271:             if (isset($stop['offset'])) {
272:                 $grad['colors'][$key]['offset'] = $stop['offset'];
273:             } else {
274:                 if ($key == 0) {
275:                     $grad['colors'][$key]['offset'] = 0;
276:                 } elseif ($key == $last_stop_id) {
277:                     $grad['colors'][$key]['offset'] = 1;
278:                 } else {
279:                     $offsetstep = ((1 - $grad['colors'][($key - 1)]['offset']) / ($num_stops - $key));
280:                     $grad['colors'][$key]['offset'] = ($grad['colors'][($key - 1)]['offset'] + $offsetstep);
281:                 }
282:             }
283:         }
284: 
285:         return $grad;
286:     }
287: 
288:     /**
289:      * Paints a coons patch mesh.
290:      *
291:      * @param float $posx   Abscissa of the top left corner of the rectangle.
292:      * @param float $posy   Ordinate of the top left corner of the rectangle.
293:      * @param float $width  Width of the rectangle.
294:      * @param float $height Height of the rectangle.
295:      * @param string $colll Lower-Left corner color.
296:      * @param string $collr Lower-Right corner color.
297:      * @param string $colur Upper-Right corner color.
298:      * @param string $colul Upper-Left corner color.
299:      * @param array $coords For one patch mesh:
300:      *                      array(float x1, float y1, .... float x12, float y12):
301:      *                      12 pairs of coordinates (normally from 0 to 1)
302:      *                      which specify the Bezier control points that define the patch.
303:      *                      First pair is the lower left edge point,
304:      *                      next is its right control point (control point 2).
305:      *                      Then the other points are defined in the order:
306:      *                      control point 1, edge point, control point 2 going counter-clockwise around the patch.
307:      *                      Last (x12, y12) is the first edge point's left control point (control point 1).
308:      *                      For two or more patch meshes:
309:      *                      array[number of patches] - arrays with the following keys for each patch:
310:      *                      f: where to put that patch (0 = first patch, 1, 2, 3 = right, top and left)
311:      *                      points: 12 pairs of coordinates of the Bezier control points as above for the first patch,
312:      *                      8 pairs of coordinates for the following patches,
313:      *                      ignoring the coordinates already defined by the precedent patch
314:      *                      colors: must be 4 colors for the first patch, 2 colors for the following patches
315:      * @param array $coords_min Minimum value used by the coordinates.
316:      *                          If a coordinate's value is smaller than this it will be cut to coords_min.
317:      * @param array $coords_max Maximum value used by the coordinates.
318:      *                          If a coordinate's value is greater than this it will be cut to coords_max.
319:      * @param boolean $antialias Flag indicating whether to filter the shading function to prevent aliasing artifacts.
320:      *
321:      * @return string PDF command
322:      *
323:      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
324:      */
325:     public function getCoonsPatchMesh(
326:         $posx,
327:         $posy,
328:         $width,
329:         $height,
330:         $colll = 'yellow',
331:         $collr = 'blue',
332:         $colur = 'green',
333:         $colul = 'red',
334:         $coords = array(
335:             0.00,0.00, 0.33,0.00, 0.67,0.00, 1.00,0.00, 1.00,0.33, 1.00,0.67,
336:             1.00,1.00, 0.67,1.00, 0.33,1.00, 0.00,1.00, 0.00,0.67, 0.00,0.33
337:         ),
338:         $coords_min = 0,
339:         $coords_max = 1,
340:         $antialias = false
341:     ) {
342:         if ($this->pdfa) {
343:             return '';
344:         }
345:         
346:         $ngr = (1 + count($this->gradients));
347:         $this->gradients[$ngr] = array(
348:             'type' => 6, //coons patch mesh
349:             'coords' => array(),
350:             'antialias' => $antialias,
351:             'colors' => array(),
352:             'transparency' => false,
353:             'background' => '',
354:             'colspace' => 'DeviceRGB',
355:         );
356: 
357:         // check the coords array if it is the simple array or the multi patch array
358:         if (!isset($coords[0]['f'])) {
359:             // simple array -> convert to multi patch array
360:             $patch_array[0]['f'] = 0;
361:             $patch_array[0]['points'] = $coords;
362:             $patch_array[0]['colors'][0] = $this->col->getColorObject($colll)->toRgbArray();
363:             $patch_array[0]['colors'][1] = $this->col->getColorObject($collr)->toRgbArray();
364:             $patch_array[0]['colors'][2] = $this->col->getColorObject($colur)->toRgbArray();
365:             $patch_array[0]['colors'][3] = $this->col->getColorObject($colul)->toRgbArray();
366:         } else {
367:             // multi patch array
368:             $patch_array = $coords;
369:         }
370: 
371:         $bpcd = 65535; //16 bits per coordinate
372:         //build the data stream
373:         $this->gradients[$ngr]['stream'] = '';
374:  
375:         foreach ($patch_array as $par) {
376:             $this->gradients[$ngr]['stream'] .= chr($par['f']); // start with the edge flag as 8 bit
377:             foreach ($par['points'] as $point) {
378:                 //each point as 16 bit
379:                 $point = max(0, min(
380:                     $bpcd,
381:                     ((($point - $coords_min) / ($coords_max - $coords_min)) * $bpcd)
382:                 ));
383:                 $this->gradients[$ngr]['stream'] .= chr(floor($point / 256)).chr(floor($point % 256));
384:             }
385:             foreach ($par['colors'] as $color) {
386:                 //each color component as 8 bit
387:                 $this->gradients[$ngr]['stream'] .= chr($color['red']).chr($color['green']).chr($color['blue']);
388:             }
389:         }
390: 
391:         return $this->getStartTransform()
392:             .$this->getClippingRect($posx, $posy, $width, $height)
393:             .$this->getGradientTransform($posx, $posy, $width, $height)
394:             .'/Sh'.$ngr.' sh'."\n"
395:             .$this->getStopTransform();
396:     }
397: 
398:     /**
399:      * Paints registration bars with color transtions
400:      *
401:      * @param float   $posx       Abscissa of the top left corner of the rectangle.
402:      * @param float   $posy       Ordinate of the top left corner of the rectangle.
403:      * @param float   $width      Width of the rectangle.
404:      * @param float   $height     Height of the rectangle.
405:      * @param boolean $vertical   If true prints bar vertically, otherwise horizontally.
406:      * @param array   $colors     Array of colors to print,
407:      *                            each entry is a color string or an array of two transition colors;
408:      *
409:      * @return string PDF command
410:      */
411:     public function getColorRegistrationBar(
412:         $posx,
413:         $posy,
414:         $width,
415:         $height,
416:         $vertical = false,
417:         $colors = array(
418:             array('g(0%)', 'g(100%)'),                       // GRAY : black   to white
419:             array('rgb(100%,0%,0%)', 'rgb(100%,100%,100%)'), // RGB  : red     to white
420:             array('rgb(0%,100%,0%)', 'rgb(100%,100%,100%)'), // RGB  : green   to white
421:             array('rgb(0%,0%,100%)', 'rgb(100%,100%,100%)'), // RGB  : blue    to white
422:             array('cmyk(100%,0%,0,0%)', 'cmyk(0%,0%,0,0%)'), // CMYK : cyan    to white
423:             array('cmyk(0%,100%,0,0%)', 'cmyk(0%,0%,0,0%)'), // CMYK : magenta to white
424:             array('cmyk(0%,0%,100,0%)', 'cmyk(0%,0%,0,0%)'), // CMYK : yellow  to white
425:             array('cmyk(0%,0%,0,100%)', 'cmyk(0%,0%,0,0%)'), // CMYK : black   to white
426:         )
427:     ) {
428:         $numbars = count($colors);
429:         if ($numbars <= 0) {
430:             return '';
431:         }
432: 
433:         // set bar measures
434:         if ($vertical) {
435:             $coords = array(0, 0, 0, 1); // coordinates for gradient transition
436:             $wbr = ($width / $numbars);  // bar width
437:             $hbr = $height;              // bar height
438:             $xdt = $wbr;                 // delta x
439:             $ydt = 0;                    // delta y
440:         } else {
441:             $coords = array(1, 0, 0, 0);
442:             $wbr = $width;
443:             $hbr = ($height / $numbars);
444:             $xdt = 0;
445:             $ydt = $hbr;
446:         }
447:         $xbr = $posx;
448:         $ybr = $posy;
449:         
450:         $out = '';
451:         foreach ($colors as $col) {
452:             if (!empty($col)) {
453:                 if (!is_array($col)) {
454:                     $col = array($col, $col);
455:                 }
456:                 if (!isset($col[1])) {
457:                     $col[1] = $col[0];
458:                 }
459:                 if (($col[0] != $col[1]) && (!$this->pdfa)) {
460:                     // color gradient
461:                     $out .= $this->getLinearGradient($xbr, $ybr, $wbr, $hbr, $col[0], $col[1], $coords);
462:                 } else {
463:                     // colored rectangle
464:                     $out .= $this->getStartTransform()
465:                         .$this->col->getColorObject($col[0])->getPdfColor()
466:                         .$this->getRect($xbr, $ybr, $wbr, $hbr, 'F')
467:                         .$this->getStopTransform();
468:                 }
469:             }
470:             $xbr += $xdt;
471:             $ybr += $ydt;
472:         }
473: 
474:         return $out;
475:     }
476: 
477:     /**
478:      * Get a crop-mark.
479:      *
480:      * @param float   $posx       Abscissa of the crop-mark center.
481:      * @param float   $posy       Ordinate of the crop-mark center.
482:      * @param float   $width      Width of the crop-mark.
483:      * @param float   $height     Height of the crop-mark.
484:      * @param string  $type       Type of crop mark - one symbol per type:
485:      *                            T = TOP, B = BOTTOM, L = LEFT, R = RIGHT
486:      * @param array   $style      Line style to apply.
487:      *
488:      * @return string PDF command
489:      */
490:     public function getCropMark(
491:         $posx,
492:         $posy,
493:         $width,
494:         $height,
495:         $type = 'TBLR',
496:         array $style = array()
497:     ) {
498:         $crops = array_unique(str_split(strtoupper($type), 1));
499:         $space_ratio = 4;
500:         $dhw = ($width / $space_ratio);  // horizontal space to leave before the intersection point
501:         $dvh = ($height / $space_ratio); // vertical space to leave before the intersection point
502: 
503:         $out = '';
504:         foreach ($crops as $crop) {
505:             switch ($crop) {
506:                 case 'T':
507:                     $posx1 = $posx;
508:                     $posy1 = ($posy - $height);
509:                     $posx2 = $posx;
510:                     $posy2 = ($posy - $dvh);
511:                     break;
512:                 case 'B':
513:                     $posx1 = $posx;
514:                     $posy1 = ($posy + $dvh);
515:                     $posx2 = $posx;
516:                     $posy2 = ($posy + $height);
517:                     break;
518:                 case 'L':
519:                     $posx1 = ($posx - $width);
520:                     $posy1 = $posy;
521:                     $posx2 = ($posx - $dhw);
522:                     $posy2 = $posy;
523:                     break;
524:                 case 'R':
525:                     $posx1 = ($posx + $dhw);
526:                     $posy1 = $posy;
527:                     $posx2 = ($posx + $width);
528:                     $posy2 = $posy;
529:                     break;
530:                 default:
531:                     continue 2;
532:             }
533:             $out .= $this->getRawPoint($posx1, $posy1)
534:                 .$this->getRawLine($posx2, $posy2)
535:                 .$this->getPathPaintOp('S');
536:         }
537:         
538:         if (empty($out)) {
539:             return '';
540:         }
541: 
542:         return $this->getStartTransform()
543:             .$this->getStyleCmd($style)
544:             .$out
545:             .$this->getStopTransform();
546:     }
547: 
548:     /**
549:      * Get overprint mode for stroking (OP) and non-stroking (op) painting operations.
550:      * (Check the "Entries in a Graphics State Parameter Dictionary" on PDF 32000-1:2008).
551:      *
552:      * @param boolean $stroking    If true apply overprint for stroking operations.
553:      * @param boolean $nonstroking If true apply overprint for painting operations other than stroking.
554:      * @param integer $mode        Overprint mode:
555:      *                             0 = each source colour component value replaces the value previously
556:      *                                 painted for the corresponding device colorant;
557:      *                             1 = a tint value of 0.0 for a source colour component shall leave the
558:      *                                 corresponding component of the previously painted colour unchanged.
559:      *
560:      * @return string PDF command
561:      */
562:     public function getOverprint($stroking = true, $nonstroking = '', $mode = 0)
563:     {
564:         if ($nonstroking == '') {
565:             $nonstroking = $stroking;
566:         }
567:         return $this->getExtGState(
568:             array(
569:                 'OP' => ($stroking && true),
570:                 'op' => ($nonstroking && true),
571:                 'OPM' => max(0, min(1, (int) $mode)),
572:             )
573:         );
574:     }
575: 
576:     /**
577:      * Set alpha for stroking (CA) and non-stroking (ca) operations.
578:      *
579:      * @param float  $stroking    Alpha value for stroking operations: real value from 0 (transparent) to 1 (opaque).
580:      * @param string $bmv         Blend mode, one of the following:
581:      *                            Normal, Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn,
582:      *                            HardLight, SoftLight, Difference, Exclusion, Hue, Saturation, Color, Luminosity.
583:      * @param float  $nonstroking Alpha value for non-stroking operations:
584:      *                            real value from 0 (transparent) to 1 (opaque).
585:      * @param boolean $ais
586:      *
587:      * @return string PDF command
588:      */
589:     public function getAlpha($stroking = 1, $bmv = 'Normal', $nonstroking = '', $ais = false)
590:     {
591:         if ($nonstroking == '') {
592:             $nonstroking = $stroking;
593:         }
594: 
595:         if ($bmv[0] == '/') {
596:             // remove trailing slash
597:             $bmv = substr($bmv, 1);
598:         }
599:         $map = array(
600:             'Normal',
601:             'Multiply',
602:             'Screen',
603:             'Overlay',
604:             'Darken',
605:             'Lighten',
606:             'ColorDodge',
607:             'ColorBurn',
608:             'HardLight',
609:             'SoftLight',
610:             'Difference',
611:             'Exclusion',
612:             'Hue',
613:             'Saturation',
614:             'Color',
615:             'Luminosity',
616:         );
617:         if (!in_array($bmv, $map)) {
618:             $bmv = $map[0];
619:         }
620:         return $this->getExtGState(
621:             array(
622:                 'CA' => floatval($stroking),
623:                 'ca' => floatval($nonstroking),
624:                 'BM' => '/'.$bmv,
625:                 'AIS' => ($ais && true),
626:             )
627:         );
628:     }
629: }
630: 
 

© 2004-2017 – Nicola Asuni - Tecnick.com - All rights reserved.
about - disclaimer - privacy