1: <?php
2: 3: 4: 5: 6:
7:
8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
24: abstract class QImageControlBase extends QControl {
25:
26:
27:
28:
29:
30: protected $strBackColor = 'ffffff';
31: protected $blnScaleCanvasDown = false;
32: protected $blnScaleImageUp = true;
33:
34:
35: protected $strImageType = null;
36: protected $intQuality = 100;
37:
38: protected $strImagePath;
39: protected $strAlternateText;
40:
41:
42: protected $strCacheFolder = null;
43: protected $strCacheFilename = null;
44:
45:
46: protected $strSourceImageType = null;
47: protected $strCachedActualFilePath = null;
48:
49:
50:
51: protected $strWidth;
52: protected $strHeight;
53:
54:
55:
56:
57: public function ParsePostData() {}
58: public function Validate() {return true;}
59:
60: public function __construct($objParentObject, $strControlId = null) {
61: if ($objParentObject)
62: parent::__construct($objParentObject, $strControlId);
63: }
64:
65: public function RenderAsImgSrc($blnDisplayOutput = true) {
66:
67: if (!$this->blnVisible) return;
68:
69:
70: if (!$this->strImagePath || !file_exists($this->strImagePath))
71: throw new QCallerException('ImagePath is not defined or does not exist');
72:
73:
74: $strSerialized = $this->Serialize();
75: $strHash = md5($strSerialized);
76:
77:
78: if ($this->strCacheFilename)
79: $strImageFilename = $this->strCacheFilename;
80: else if ($this->strImageType)
81: $strImageFilename = $strHash . '.' . $this->strImageType;
82: else
83: $strImageFilename = $strHash . '.' . $this->strSourceImageType;
84:
85:
86: if ($this->strCacheFolder) {
87: $strFilePath = sprintf('%s%s/%s',
88: __DOCROOT__,
89: str_replace(__VIRTUAL_DIRECTORY__, '', $this->strCacheFolder),
90: $strImageFilename);
91: if (!file_exists($strFilePath))
92: $this->RenderImage($strFilePath);
93:
94: $strPath = sprintf('%s/%s',
95: $this->strCacheFolder,
96: $strImageFilename);
97:
98:
99: $this->strCachedActualFilePath = $strFilePath;
100: } else {
101: if (strlen($strSerialized) > 255) {
102: throw new QCallerException(
103: sprintf(
104: QApplication::Translate(
105: "The filename size exceeded for the serialized QImageControl control." .
106: " The size is %s. The maximum value is 255. Try to set the CacheFolder property to solve the problem."
107: )
108: , strlen($strSerialized)
109: )
110: );
111: }
112: $strPath = sprintf('%s/image.php/%s?q=%s',
113: __VIRTUAL_DIRECTORY__ . __PHP_ASSETS__,
114: $strImageFilename,
115: $strSerialized
116: );
117: }
118:
119:
120: if ($blnDisplayOutput)
121: print($strPath);
122: else
123: return $strPath;
124: }
125:
126: protected function GetControlHtml() {
127: try {
128:
129: $strPath = $this->RenderAsImgSrc(false);
130: } catch (QCallerException $objExc) {
131: $objExc->IncrementOffset();
132: throw $objExc;
133: }
134:
135: if ($this->strCachedActualFilePath) {
136: $objDimensions = getimagesize($this->strCachedActualFilePath);
137:
138:
139:
140: $strBackColor = $this->strBackColor;
141: $strWidth = $this->strWidth;
142: $strHeight = $this->strHeight;
143: $this->strBackColor = null;
144: $this->strWidth = $objDimensions[0];
145: $this->strHeight = $objDimensions[1];
146: $strStyle = $this->GetStyleAttributes();
147: if ($strStyle)
148: $strStyle = sprintf(' style="%s"', $strStyle);
149: $this->strBackColor = $strBackColor;
150: $this->strWidth = $strWidth;
151: $this->strHeight = $strHeight;
152: } else {
153:
154: $strBackColor = $this->strBackColor;
155: $strWidth = $this->strWidth;
156: $strHeight = $this->strHeight;
157: $this->strBackColor = null;
158: $this->strWidth = null;
159: $this->strHeight = null;
160: $strStyle = $this->GetStyleAttributes();
161: if ($strStyle)
162: $strStyle = sprintf(' style="%s"', $strStyle);
163: $this->strBackColor = $strBackColor;
164: $this->strWidth= $strWidth;
165: $this->strHeight = $strHeight;
166: }
167:
168: $strAlt = null;
169: if ($this->strAlternateText)
170: $strAlt = ' alt="' . QApplication::HtmlEntities($this->strAlternateText) . '"';
171:
172:
173: $strToReturn = sprintf('<img id="%s" src="%s" %s%s%s/>',
174: $this->strControlId,
175: $strPath,
176: $this->GetAttributes(),
177: $strStyle,
178: $strAlt);
179: return $strToReturn;
180: }
181:
182: public function Serialize() {
183: $objControl = clone($this);
184: $objControl->objForm = null;
185: $objControl->objParentControl = null;
186: $objControl->strControlId = null;
187: $objControl->strCachedActualFilePath = null;
188: $strData = serialize($objControl);
189: if (function_exists('gzcompress'))
190: $strData = base64_encode(gzcompress($strData, 9));
191: else
192: $strData = base64_encode($strData);
193:
194: $strData = str_replace('+', '-', $strData);
195: $strData = str_replace('/', '_', $strData);
196:
197: return $strData;
198: }
199:
200: public static function Run() {
201: $strData = QApplication::QueryString('q');
202: $strData = str_replace('-', '+', $strData);
203: $strData = str_replace('_', '/', $strData);
204:
205: $strData = base64_decode($strData);
206:
207: if (function_exists('gzcompress'))
208: $strData = gzuncompress($strData);
209:
210: $objLabel = unserialize($strData);
211: $objLabel->RenderImage();
212: }
213:
214: protected function FlowThrough($strPath) {
215:
216: if ((!$this->strImageType) || ($this->strImageType == $this->strSourceImageType)) {
217: if ($strPath)
218: copy($this->strImagePath, $strPath);
219: else {
220: $this->SetupContentType();
221: print file_get_contents($this->strImagePath, true);
222: }
223:
224:
225: } else {
226: switch ($this->strSourceImageType) {
227: case QImageType::Jpeg:
228: $objImage = imagecreatefromjpeg($this->strImagePath);
229: break;
230: case QImageType::Png:
231: $objImage = imagecreatefrompng($this->strImagePath);
232: break;
233: case QImageType::Gif:
234: $objImage = imagecreatefromgif($this->strImagePath);
235: break;
236: default:
237: throw new QCallerException('Original image is of an invalid file path');
238: }
239:
240:
241: if (!$strPath)
242: $this->SetupContentType();
243:
244: switch ($this->strImageType) {
245: case QImageType::Jpeg:
246: if ($strPath)
247: imagejpeg($objImage, $strPath, $this->intQuality);
248: else
249: imagejpeg($objImage, null, $this->intQuality);
250: break;
251: case QImageType::Png:
252: if ($strPath)
253: imagepng($objImage, $strPath);
254: else
255: imagepng($objImage);
256: break;
257: case QImageType::Gif:
258: if ($strPath)
259: imagegif($objImage, $strPath);
260: else
261: imagegif($objImage);
262: break;
263: default:
264: throw new QCallerException('ImageType is not a known image type');
265: }
266:
267: imagedestroy($objImage);
268: }
269: }
270:
271: protected function SetupContentType() {
272:
273: QApplication::$ProcessOutput = false;
274: header('Cache-Control: cache');
275: header('Expires: Wed, 20 Mar 2019 05:00:00 GMT');
276: header('Pragma: cache');
277:
278: if (!($strImageType = $this->strImageType))
279: $strImageType = $this->strSourceImageType;
280:
281: switch ($strImageType) {
282: case QImageType::Jpeg:
283: case QImageType::Png:
284: case QImageType::Gif:
285: header('Content-Type: image/' . $strImageType);
286: break;
287: default:
288: throw new Exception('Invalid Image Type');
289: }
290: }
291:
292: public function RenderImage($strPath = null) {
293: if (!$this->strImagePath)
294: throw new QCallerException('No Image Path was set');
295:
296:
297: if ((!$this->strWidth) && (!$this->strHeight)) {
298: $this->FlowThrough($strPath);
299: return;
300: }
301:
302:
303: $objDimensions = getimagesize($this->strImagePath);
304: $intSourceWidth = $objDimensions[0];
305: $intSourceHeight = $objDimensions[1];
306:
307:
308: $intDestinationWidth = null;
309: $intDestinationHeight = null;
310:
311: $intCanvasWidth = null;
312: $intCanvasHeight = null;
313:
314:
315:
316:
317: if ($this->strWidth && !$this->strHeight) {
318:
319: if ($this->strWidth == $intSourceWidth) {
320: $this->FlowThrough($strPath);
321: return;
322: }
323:
324:
325: if ($this->strWidth > $intSourceWidth) {
326:
327: if (!$this->blnScaleImageUp) {
328:
329: if ($this->blnScaleCanvasDown) {
330: $this->FlowThrough($strPath);
331: return;
332: }
333:
334:
335: $intDestinationWidth = $intSourceWidth;
336: $intDestinationHeight = $intSourceHeight;
337: $intCanvasWidth = $this->strWidth;
338: $intCanvasHeight = $intSourceHeight;
339:
340:
341: } else {
342: $intDestinationWidth = $this->strWidth;
343: $intDestinationHeight = $intSourceHeight * $this->strWidth / $intSourceWidth;
344: $intCanvasWidth = $this->strWidth;
345: $intCanvasHeight = $intSourceHeight * $this->strWidth / $intSourceWidth;
346: }
347:
348:
349: } else {
350: $intDestinationWidth = $this->strWidth;
351: $intDestinationHeight = $intSourceHeight * $this->strWidth / $intSourceWidth;
352: $intCanvasWidth = $intDestinationWidth;
353: $intCanvasHeight = $intDestinationHeight;
354: }
355:
356:
357:
358:
359: } else if ($this->strHeight && !$this->strWidth) {
360:
361: if ($this->strHeight == $intSourceHeight) {
362: $this->FlowThrough($strPath);
363: return;
364: }
365:
366:
367: if ($this->strHeight > $intSourceHeight) {
368:
369: if (!$this->blnScaleImageUp) {
370:
371: if ($this->blnScaleCanvasDown) {
372: $this->FlowThrough($strPath);
373: return;
374: }
375:
376:
377: $intDestinationWidth = $intSourceWidth;
378: $intDestinationHeight = $intSourceHeight;
379: $intCanvasWidth = $intSourceWidth;
380: $intCanvasHeight = $this->strHeight;
381:
382:
383: } else {
384: $intDestinationWidth = $intSourceWidth * $this->strHeight / $intSourceHeight;
385: $intDestinationHeight = $this->strHeight;
386: $intCanvasWidth = $intSourceWidth * $this->strHeight / $intSourceHeight;
387: $intCanvasHeight = $this->strHeight;
388: }
389:
390:
391: } else {
392: $intDestinationWidth = $intSourceWidth * $this->strHeight / $intSourceHeight;
393: $intDestinationHeight = $this->strHeight;
394: $intCanvasWidth = $intDestinationWidth;
395: $intCanvasHeight = $intDestinationHeight;
396: }
397:
398:
399:
400:
401: } else {
402:
403: if (($this->strHeight == $intSourceHeight) && ($this->strWidth == $intSourceWidth)) {
404: $this->FlowThrough($strPath);
405: return;
406: }
407:
408:
409: if (($this->strHeight >= $intSourceHeight) && ($this->strWidth >= $intSourceWidth)) {
410:
411: if (!$this->blnScaleImageUp) {
412:
413: if ($this->blnScaleCanvasDown) {
414: $this->FlowThrough($strPath);
415: return;
416: }
417:
418:
419: $intDestinationWidth = $intSourceWidth;
420: $intDestinationHeight = $intSourceHeight;
421: $intCanvasWidth = $this->strWidth;
422: $intCanvasHeight = $this->strHeight;
423: }
424: }
425:
426:
427:
428: if (!$intDestinationWidth) {
429:
430: $fltSourceProportions = $intSourceWidth / $intSourceHeight;
431: $fltDestProportions = $this->strWidth / $this->strHeight;
432:
433:
434: if ($fltDestProportions > $fltSourceProportions) {
435: $intDestinationWidth = $intSourceWidth * $this->strHeight / $intSourceHeight;
436: $intDestinationHeight = $this->strHeight;
437:
438:
439: } else if ($fltDestProportions < $fltSourceProportions) {
440: $intDestinationWidth = $this->strWidth;
441: $intDestinationHeight = $intSourceHeight * $this->strWidth / $intSourceWidth;
442:
443:
444: } else {
445: $intDestinationWidth = $this->strWidth;
446: $intDestinationHeight = $this->strHeight;
447: $intCanvasWidth = $intDestinationWidth;
448: $intCanvasHeight = $intDestinationHeight;
449: }
450: }
451:
452:
453: if (!$intCanvasWidth) {
454: if ($this->blnScaleCanvasDown) {
455: $intCanvasWidth = $intDestinationWidth;
456: $intCanvasHeight = $intDestinationHeight;
457: } else {
458: $intCanvasWidth = $this->strWidth;
459: $intCanvasHeight = $this->strHeight;
460: }
461: }
462: }
463:
464:
465: $objFinalImage = imagecreatetruecolor($intCanvasWidth, $intCanvasHeight);
466:
467:
468: $intRed = hexdec(substr($this->strBackColor, 0, 2));
469: $intGreen = hexdec(substr($this->strBackColor, 2, 2));
470: $intBlue = hexdec(substr($this->strBackColor, 4));
471: $clrBackground = imagecolorallocate($objFinalImage, $intRed, $intGreen, $intBlue);
472:
473:
474: imagefilledrectangle($objFinalImage, 0, 0, $intCanvasWidth, $intCanvasHeight, $clrBackground);
475:
476:
477: switch ($this->strSourceImageType) {
478: case QImageType::Jpeg:
479: $objImage = imagecreatefromjpeg($this->strImagePath);
480: break;
481: case QImageType::Png:
482: $objImage = imagecreatefrompng($this->strImagePath);
483: break;
484: case QImageType::Gif:
485: $objImage = imagecreatefromgif($this->strImagePath);
486: break;
487: default:
488: throw new QCallerException('Invalid Source Image Type');
489: }
490:
491:
492: $intX = round(($intCanvasWidth - $intDestinationWidth) / 2.0);
493: $intY = round(($intCanvasHeight - $intDestinationHeight) / 2.0);
494:
495:
496: imagecopyresampled($objFinalImage, $objImage, $intX, $intY, 0, 0, $intDestinationWidth, $intDestinationHeight, $intSourceWidth, $intSourceHeight);
497:
498:
499: if (!$strPath)
500: $this->SetupContentType();
501:
502: if (!($strImageType = $this->strImageType))
503: $strImageType = $this->strSourceImageType;
504:
505: switch ($strImageType) {
506: case QImageType::Gif:
507: if ($strPath)
508: imagegif($objFinalImage, $strPath);
509: else
510: imagegif($objFinalImage);
511: break;
512: case QImageType::Jpeg:
513: if ($strPath)
514: imagejpeg($objFinalImage, $strPath, $this->intQuality);
515: else
516: imagejpeg($objFinalImage, null, $this->intQuality);
517: break;
518: case QImageType::Png:
519: if ($strPath)
520: imagepng($objFinalImage, $strPath);
521: else
522: imagepng($objFinalImage);
523: break;
524: default:
525: throw new QCallerException('Invalid Image Type');
526: }
527:
528: imagedestroy($objImage);
529: imagedestroy($objFinalImage);
530: }
531:
532:
533:
534:
535: 536: 537: 538: 539: 540: 541:
542: public function __get($strName) {
543: switch ($strName) {
544:
545: case "ScaleCanvasDown": return $this->blnScaleCanvasDown;
546: case "ScaleImageUp": return $this->blnScaleImageUp;
547:
548:
549: case "ImageType": return $this->strImageType;
550: case "Quality": return $this->intQuality;
551:
552:
553: case "CacheFolder": return $this->strCacheFolder;
554: case "CacheFilename": return $this->strCacheFilename;
555: case "ImagePath": return $this->strImagePath;
556: case "AlternateText": return $this->strAlternateText;
557:
558: default:
559: try {
560: return parent::__get($strName);
561: } catch (QCallerException $objExc) {
562: $objExc->IncrementOffset();
563: throw $objExc;
564: }
565: }
566: }
567:
568:
569:
570:
571:
572:
573: 574: 575: 576: 577: 578: 579: 580:
581: public function __set($strName, $mixValue) {
582: $this->blnModified = true;
583:
584: switch ($strName) {
585:
586: case "ScaleCanvasDown":
587: try {
588: $this->blnScaleCanvasDown = QType::Cast($mixValue, QType::Boolean);
589: break;
590: } catch (QInvalidCastException $objExc) {
591: $objExc->IncrementOffset();
592: throw $objExc;
593: }
594: case "ScaleImageUp":
595: try {
596: $this->blnScaleImageUp = QType::Cast($mixValue, QType::Boolean);
597: break;
598: } catch (QInvalidCastException $objExc) {
599: $objExc->IncrementOffset();
600: throw $objExc;
601: }
602:
603:
604:
605: case "ImageType":
606: try {
607: $this->strImageType = QType::Cast($mixValue, QType::String);
608: break;
609: } catch (QInvalidCastException $objExc) {
610: $objExc->IncrementOffset();
611: throw $objExc;
612: }
613:
614: case "Quality":
615: try {
616: $this->intQuality = QType::Cast($mixValue, QType::Integer);
617: break;
618: } catch (QInvalidCastException $objExc) {
619: $objExc->IncrementOffset();
620: throw $objExc;
621: }
622:
623: case "CacheFolder":
624: try {
625: $this->strCacheFolder = QType::Cast($mixValue, QType::String);
626: break;
627: } catch (QInvalidCastException $objExc) {
628: $objExc->IncrementOffset();
629: throw $objExc;
630: }
631:
632: case "CacheFilename":
633: try {
634: $this->strCacheFilename = QType::Cast($mixValue, QType::String);
635: break;
636: } catch (QInvalidCastException $objExc) {
637: $objExc->IncrementOffset();
638: throw $objExc;
639: }
640:
641: case "ImagePath":
642: try {
643: $this->strImagePath = QType::Cast($mixValue, QType::String);
644:
645: if (!$this->strImagePath || !is_file($this->strImagePath))
646: throw new QCallerException('ImagePath is not defined or does not exist');
647:
648: $this->strImagePath = realpath($this->strImagePath);
649:
650: $strSourceImageType = trim(strtolower(substr($this->strImagePath, strrpos($this->strImagePath, '.') + 1)));
651: switch ($strSourceImageType) {
652: case 'jpeg':
653: case 'jpg':
654: $this->strSourceImageType = QImageType::Jpeg;
655: break;
656: case 'png':
657: $this->strSourceImageType = QImageType::Png;
658: break;
659: case 'gif':
660: $this->strSourceImageType = QImageType::Gif;
661: break;
662: default:
663: throw new QCallerException('Image Type cannot be determined: ' . $mixValue);
664: }
665:
666: break;
667: } catch (QInvalidCastException $objExc) {
668: $objExc->IncrementOffset();
669: throw $objExc;
670: }
671:
672: case "AlternateText":
673: try {
674: $this->strAlternateText = QType::Cast($mixValue, QType::String);
675: break;
676: } catch (QInvalidCastException $objExc) {
677: $objExc->IncrementOffset();
678: throw $objExc;
679: }
680:
681:
682:
683: case "BackColor":
684: try {
685: $mixValue = strtolower(QType::Cast($mixValue, QType::String));
686: } catch (QInvalidCastException $objExc) {
687: $objExc->IncrementOffset();
688: throw $objExc;
689: }
690:
691: if (strlen($mixValue) != 6)
692: throw new QInvalidCastException('BackColor must be a 6-digit hexadecimal value');
693:
694:
695: $strMatches = array();
696: $strPattern = '/[a-f0-9]*/';
697: preg_match($strPattern, $mixValue, $strMatches);
698: if (count($strMatches) && ($strMatches[0] == $mixValue))
699: return ($this->strBackColor = $mixValue);
700: else
701: throw new QInvalidCastException('BackColor must be a 6-digit hexadecimal value');
702:
703: break;
704:
705: case "Width":
706: try {
707: $this->strWidth = QType::Cast($mixValue, QType::Integer);
708: break;
709: } catch (QInvalidCastException $objExc) {
710: $objExc->IncrementOffset();
711: throw $objExc;
712: }
713:
714: case "Height":
715: try {
716: $this->strHeight = QType::Cast($mixValue, QType::Integer);
717: break;
718: } catch (QInvalidCastException $objExc) {
719: $objExc->IncrementOffset();
720: throw $objExc;
721: }
722:
723: default:
724: try {
725: parent::__set($strName, $mixValue);
726: } catch (QCallerException $objExc) {
727: $objExc->IncrementOffset();
728: throw $objExc;
729: }
730: break;
731: }
732: }
733: }