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: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35:
36: abstract class QImageLabelBase extends QControl {
37:
38:
39:
40:
41:
42: protected $strForeColor = '000000';
43: protected $strBackColor = 'ffffff';
44: protected $strFontSize = 12;
45: protected $strFontNames = null;
46:
47: protected $strText = null;
48: protected $intXCoordinate = 0;
49: protected $intYCoordinate = 0;
50: protected $blnBackgroundTransparent = false;
51:
52:
53: protected $strImageType = QImageType::Png;
54: protected $intQuality = 100;
55: protected $blnSmoothFont = true;
56:
57:
58: protected $strHorizontalAlign = QHorizontalAlign::Left;
59: protected $strVerticalAlign = QVerticalAlign::Top;
60: protected $intPaddingWidth = 0;
61: protected $intPaddingHeight = 0;
62: protected $intSpace = 0;
63: protected $intTightness = 0;
64: protected $intAngle = 0;
65:
66:
67: protected $strCacheFolder = null;
68: protected $strCachedImageFilePath = null;
69:
70: public function ParsePostData() {}
71:
72: protected function GetControlHtml() {
73: if (!$this->strFontNames)
74:
75: return;
76:
77: $strSerialized = $this->Serialize();
78: if ($this->strCacheFolder) {
79: $strHash = md5($strSerialized);
80: $strFilePath = sprintf('%s%s/%s.%s',
81: __DOCROOT__,
82: str_replace(__VIRTUAL_DIRECTORY__, '', $this->strCacheFolder),
83: $strHash,
84: $this->strImageType);
85: if (!file_exists($strFilePath))
86: $this->RenderImage($strFilePath);
87:
88: $strPath = sprintf('%s/%s.%s',
89: $this->strCacheFolder,
90: $strHash,
91: $this->strImageType);
92:
93: $this->strCachedImageFilePath = $strPath;
94: } else {
95: if (strlen($strSerialized) > 255) {
96: throw new QCallerException(
97: sprintf(
98: QApplication::Translate(
99: "The filename size exceeded for the serialized QImageLabel control." .
100: " The size is %s. The maximum value is 255. Try to set the CacheFolder property to solve the problem."
101: )
102: , strlen($strSerialized)
103: )
104: );
105: }
106: $strPath = sprintf('%s/image_label.php/%s/q.%s',
107: __VIRTUAL_DIRECTORY__ . __PHP_ASSETS__,
108: $strSerialized,
109: $this->strImageType
110: );
111: }
112:
113: $attrOverrides['src'] = $strPath;
114: $attrOverrides['alt'] = QApplication::HtmlEntities($this->strText);
115: return $this->RenderTag ('img', $attrOverrides, null, null, true);
116: }
117: public function Validate() {return true;}
118:
119: public function Serialize() {
120: $objControl = clone($this);
121: $objControl->objForm = null;
122: $objControl->objParentControl = null;
123: $objControl->strCachedImageFilePath = null;
124: $strData = serialize($objControl);
125: if (function_exists('gzcompress'))
126: $strData = base64_encode(gzcompress($strData, 9));
127: else
128: $strData = base64_encode($strData);
129:
130: $strData = str_replace('+', '-', $strData);
131: $strData = str_replace('/', '_', $strData);
132:
133: return $strData;
134: }
135:
136: public static function Run() {
137: $strData = QApplication::PathInfo(0);
138: $strData = str_replace('-', '+', $strData);
139: $strData = str_replace('_', '/', $strData);
140:
141: $strData = base64_decode($strData);
142:
143: if (function_exists('gzcompress'))
144: $strData = gzuncompress($strData);
145:
146: $objLabel = unserialize($strData);
147: $objLabel->RenderImage();
148: }
149:
150: protected function RenderImage($strPath = null) {
151: $strWidth = $this->Width;
152:
153:
154: if (file_exists($this->strFontNames))
155: $strFontPath = $this->strFontNames;
156: else
157: throw new QCallerException('Cannot find font file: ' . $this->strFontNames);
158:
159:
160: $strFontExtension = substr($this->strFontNames, strlen($this->strFontNames) - 3);
161: $strFontExtension = strtolower($strFontExtension);
162:
163:
164: switch($strFontExtension) {
165: case 'ttf':
166: $blnTrueType = true;
167: $objBox = imagettfbbox($this->strFontSize, $this->intAngle, $strFontPath, $this->strText);
168:
169:
170: $intXCoordinate1 = $objBox[0];
171: $intYCoordinate1 = $objBox[5];
172: $intXCoordinate2 = $objBox[4];
173: $intYCoordinate2 = $objBox[1];
174: break;
175: case 'pfb':
176: $blnTrueType = false;
177:
178:
179: $objFont = imagepsloadfont($strFontPath);
180: $objBox = imagepsbbox($this->strText, $objFont, $this->strFontSize, $this->intSpace, $this->intTightness, $this->intAngle);
181:
182:
183: $intXCoordinate1 = $objBox[0];
184: $intYCoordinate1 = $objBox[1];
185: $intXCoordinate2 = $objBox[2];
186: $intYCoordinate2 = $objBox[3];
187: break;
188: default:
189: throw new QCallerException('Cannot Determine Font Type: ' . $this->strFontNames);
190: }
191:
192: $intBoxWidth = $intXCoordinate2 - $intXCoordinate1;
193: $intBoxHeight = $intYCoordinate2 - $intYCoordinate1;
194:
195:
196:
197:
198:
199: if (!$strWidth) {
200:
201: $intWidth = $intBoxWidth + ($this->intPaddingWidth * 2);
202: $intX = $this->intPaddingWidth;
203: } else {
204:
205: switch ($this->strHorizontalAlign) {
206: case QHorizontalAlign::Left:
207: $intX = -1 * $intXCoordinate1 + 2 + $this->intPaddingWidth;
208: break;
209: case QHorizontalAlign::Right:
210: $intX = $strWidth - $intBoxWidth - 2 - $this->intPaddingWidth;
211: break;
212: case QHorizontalAlign::Center:
213: $intX = round(($strWidth - $intBoxWidth) / 2);
214: break;
215:
216:
217: default:
218: $intX = $this->intXCoordinate;
219: break;
220: }
221:
222: $intWidth = $strWidth;
223: }
224:
225: if (!$this->Height) {
226:
227: $intHeight = $intBoxHeight + ($this->intPaddingHeight * 2);
228:
229: if ($blnTrueType)
230: $intY = $intBoxHeight - $intYCoordinate2 + $this->intPaddingHeight;
231: else
232: $intY = $intYCoordinate2 + $this->intPaddingHeight + 1;
233: } else {
234:
235: switch ($this->strVerticalAlign) {
236: case QVerticalAlign::Top:
237: if ($blnTrueType)
238: $intY = $intBoxHeight - $intYCoordinate2 + $this->intPaddingHeight;
239: else
240: $intY = $intYCoordinate2 + 2 + $this->intPaddingHeight;
241: break;
242: case QVerticalAlign::Bottom;
243: if ($blnTrueType)
244: $intY = $this->Height - $intYCoordinate2 - $this->intPaddingHeight;
245: else
246: $intY = $this->Height + $intYCoordinate1 - 2 - $this->intPaddingHeight;
247: break;
248: case QVerticalAlign::Middle:
249: if ($blnTrueType)
250: $intY = round(($this->Height - $intBoxHeight) / 2) + $intBoxHeight - $intYCoordinate2;
251: else
252: $intY = round(($this->Height - $intBoxHeight) / 2) + $intYCoordinate2;
253: break;
254:
255:
256: default:
257: $intY = $this->intYCoordinate;
258: break;
259: }
260:
261: $intHeight = $this->Height;
262: }
263:
264: if ($intWidth <= 0)
265: $intWidth = 100;
266: if ($intHeight <= 0)
267: $intHeight = 100;
268:
269: $objImage = imagecreate($intWidth, $intHeight);
270:
271:
272: $intRed = hexdec(substr($this->strBackColor, 0, 2));
273: $intGreen = hexdec(substr($this->strBackColor, 2, 2));
274: $intBlue = hexdec(substr($this->strBackColor, 4));
275: $clrBackground = imagecolorallocate($objImage, $intRed, $intGreen, $intBlue);
276:
277: $intRed = hexdec(substr($this->strForeColor, 0, 2));
278: $intGreen = hexdec(substr($this->strForeColor, 2, 2));
279: $intBlue = hexdec(substr($this->strForeColor, 4));
280: $clrForeground = imagecolorallocate($objImage, $intRed, $intGreen, $intBlue);
281:
282: if ($this->blnBackgroundTransparent)
283: imagecolortransparent($objImage, $clrBackground);
284:
285: imagefilledrectangle($objImage, 0, 0, $intWidth, $intHeight, $clrBackground);
286:
287: if ($blnTrueType) {
288: imagettftext($objImage, $this->strFontSize, $this->intAngle, $intX, $intY, $clrForeground, $strFontPath, $this->strText);
289: } else {
290:
291: if ($this->blnSmoothFont)
292: $intAntiAliasing = 16;
293: else
294: $intAntiAliasing = 4;
295:
296:
297: imagepstext($objImage, $this->strText, $objFont, $this->strFontSize, $clrForeground, $clrBackground,
298: $intX, $intY, $this->intSpace, $this->intTightness, $this->intAngle, $intAntiAliasing);
299: imagepsfreefont($objFont);
300: }
301:
302:
303: if (!$strPath) {
304:
305: QApplication::$ProcessOutput = false;
306: header('Cache-Control: cache');
307: header('Expires: Wed, 20 Mar 2019 05:00:00 GMT');
308: header('Pragma: cache');
309:
310: switch ($this->strImageType) {
311: case QImageType::Gif:
312: header('Content-type: image/gif');
313: imagegif($objImage);
314: break;
315: case QImageType::Jpeg:
316: header('Content-type: image/jpeg');
317: imagejpeg($objImage, null, $this->intQuality);
318: break;
319: default:
320: header('Content-type: image/png');
321: imagepng($objImage);
322: break;
323: }
324: } else {
325: switch ($this->strImageType) {
326: case QImageType::Gif:
327: imagegif($objImage, $strPath);
328: break;
329: case QImageType::Jpeg:
330: imagejpeg($objImage, $strPath, $this->intQuality);
331: break;
332: default:
333: imagepng($objImage, $strPath);
334: break;
335: }
336: }
337:
338: imagedestroy($objImage);
339: }
340:
341:
342:
343:
344:
345:
346: public function __get($strName) {
347: switch ($strName) {
348:
349: case "Text": return $this->strText;
350: case "XCoordinate": return $this->intXCoordinate;
351: case "YCoordinate": return $this->intYCoordinate;
352: case "BackgroundTransparent": return $this->blnBackgroundTransparent;
353:
354:
355: case "ImageType": return $this->strImageType;
356: case "Quality": return $this->intQuality;
357: case "SmoothFont": return $this->blnSmoothFont;
358:
359:
360: case "HorizontalAlign": return $this->strHorizontalAlign;
361: case "VerticalAlign": return $this->strVerticalAlign;
362: case "PaddingWidth": return $this->intYCoordinate;
363: case "PaddingHeight": return $this->intYCoordinate;
364: case "Space": return $this->intYCoordinate;
365: case "Tightness": return $this->intYCoordinate;
366: case "Angle": return $this->intYCoordinate;
367:
368: case "CacheFolder": return $this->strCacheFolder;
369:
370: case "CachedImageFilePath": return $this->strCachedImageFilePath;
371:
372: default:
373: try {
374: return parent::__get($strName);
375: } catch (QCallerException $objExc) {
376: $objExc->IncrementOffset();
377: throw $objExc;
378: }
379: }
380: }
381:
382:
383:
384:
385:
386:
387: public function __set($strName, $mixValue) {
388: $this->blnModified = true;
389:
390: switch ($strName) {
391:
392: case "Text":
393: try {
394: $this->strText = QType::Cast($mixValue, QType::String);
395: break;
396: } catch (QInvalidCastException $objExc) {
397: $objExc->IncrementOffset();
398: throw $objExc;
399: }
400:
401: case "XCoordinate":
402: try {
403: $this->intXCoordinate = QType::Cast($mixValue, QType::Integer);
404: break;
405: } catch (QInvalidCastException $objExc) {
406: $objExc->IncrementOffset();
407: throw $objExc;
408: }
409:
410: case "YCoordinate":
411: try {
412: $this->intYCoordinate = QType::Cast($mixValue, QType::Integer);
413: break;
414: } catch (QInvalidCastException $objExc) {
415: $objExc->IncrementOffset();
416: throw $objExc;
417: }
418:
419: case "BackgroundTransparent":
420: try {
421: $this->blnBackgroundTransparent = QType::Cast($mixValue, QType::Boolean);
422: break;
423: } catch (QInvalidCastException $objExc) {
424: $objExc->IncrementOffset();
425: throw $objExc;
426: }
427:
428:
429:
430: case "ImageType":
431: try {
432: $this->strImageType = QType::Cast($mixValue, QType::String);
433: break;
434: } catch (QInvalidCastException $objExc) {
435: $objExc->IncrementOffset();
436: throw $objExc;
437: }
438:
439: case "Quality":
440: try {
441: $this->intQuality = QType::Cast($mixValue, QType::Integer);
442: break;
443: } catch (QInvalidCastException $objExc) {
444: $objExc->IncrementOffset();
445: throw $objExc;
446: }
447:
448: case "SmoothFont":
449: try {
450: $this->blnSmoothFont = QType::Cast($mixValue, QType::Boolean);
451: break;
452: } catch (QInvalidCastException $objExc) {
453: $objExc->IncrementOffset();
454: throw $objExc;
455: }
456:
457:
458:
459:
460: case "HorizontalAlign":
461: try {
462: $this->strHorizontalAlign = QType::Cast($mixValue, QType::String);
463: break;
464: } catch (QInvalidCastException $objExc) {
465: $objExc->IncrementOffset();
466: throw $objExc;
467: }
468:
469: case "VerticalAlign":
470: try {
471: $this->strVerticalAlign = QType::Cast($mixValue, QType::String);
472: break;
473: } catch (QInvalidCastException $objExc) {
474: $objExc->IncrementOffset();
475: throw $objExc;
476: }
477:
478: case "PaddingWidth":
479: try {
480: $this->intPaddingWidth = QType::Cast($mixValue, QType::Integer);
481: break;
482: } catch (QInvalidCastException $objExc) {
483: $objExc->IncrementOffset();
484: throw $objExc;
485: }
486:
487: case "PaddingHeight":
488: try {
489: $this->intPaddingHeight = QType::Cast($mixValue, QType::Integer);
490: break;
491: } catch (QInvalidCastException $objExc) {
492: $objExc->IncrementOffset();
493: throw $objExc;
494: }
495:
496: case "Space":
497: try {
498: $this->intSpace = QType::Cast($mixValue, QType::Integer);
499: break;
500: } catch (QInvalidCastException $objExc) {
501: $objExc->IncrementOffset();
502: throw $objExc;
503: }
504:
505: case "Tightness":
506: try {
507: $this->intTightness = QType::Cast($mixValue, QType::Integer);
508: break;
509: } catch (QInvalidCastException $objExc) {
510: $objExc->IncrementOffset();
511: throw $objExc;
512: }
513:
514: case "Angle":
515: try {
516: $this->intAngle = QType::Cast($mixValue, QType::Integer);
517: break;
518: } catch (QInvalidCastException $objExc) {
519: $objExc->IncrementOffset();
520: throw $objExc;
521: }
522:
523:
524: case "CacheFolder":
525: try {
526: $this->strCacheFolder = QType::Cast($mixValue, QType::String);
527: break;
528: } catch (QInvalidCastException $objExc) {
529: $objExc->IncrementOffset();
530: throw $objExc;
531: }
532:
533:
534:
535: case "ForeColor":
536: try {
537: $mixValue = strtolower(QType::Cast($mixValue, QType::String));
538: } catch (QInvalidCastException $objExc) {
539: $objExc->IncrementOffset();
540: throw $objExc;
541: }
542:
543: if (strlen($mixValue) != 6)
544: throw new QInvalidCastException('ForeColor must be a 6-digit hexadecimal value');
545:
546:
547: $strMatches = array();
548: $strPattern = '/[a-f0-9]*/';
549: preg_match($strPattern, $mixValue, $strMatches);
550: if (count($strMatches) && ($strMatches[0] == $mixValue))
551: return ($this->strForeColor = $mixValue);
552: else
553: throw new QInvalidCastException('ForeColor must be a 6-digit hexadecimal value');
554:
555: break;
556:
557: case "BackColor":
558: try {
559: $mixValue = strtolower(QType::Cast($mixValue, QType::String));
560: } catch (QInvalidCastException $objExc) {
561: $objExc->IncrementOffset();
562: throw $objExc;
563: }
564:
565: if (strlen($mixValue) != 6)
566: throw new QInvalidCastException('BackColor must be a 6-digit hexadecimal value');
567:
568:
569: $strMatches = array();
570: $strPattern = '/[a-f0-9]*/';
571: preg_match($strPattern, $mixValue, $strMatches);
572: if (count($strMatches) && ($strMatches[0] == $mixValue))
573: return ($this->strBackColor = $mixValue);
574: else
575: throw new QInvalidCastException('BackColor must be a 6-digit hexadecimal value');
576:
577: break;
578:
579: case "FontSize":
580: try {
581: $this->strFontSize = QType::Cast($mixValue, QType::Integer);
582: break;
583: } catch (QInvalidCastException $objExc) {
584: $objExc->IncrementOffset();
585: throw $objExc;
586: }
587:
588: case "Width":
589: try {
590: $this->strWidth = QType::Cast($mixValue, QType::Integer);
591: break;
592: } catch (QInvalidCastException $objExc) {
593: $objExc->IncrementOffset();
594: throw $objExc;
595: }
596:
597: case "Height":
598: try {
599: $this->strHeight = QType::Cast($mixValue, QType::Integer);
600: break;
601: } catch (QInvalidCastException $objExc) {
602: $objExc->IncrementOffset();
603: throw $objExc;
604: }
605:
606: case "FontNames":
607: try {
608: $mixValue = QType::Cast($mixValue, QType::String);
609: } catch (QInvalidCastException $objExc) {
610: $objExc->IncrementOffset();
611: throw $objExc;
612: }
613:
614:
615: if (file_exists(dirname(QApplication::$ScriptFilename) . '/' . $mixValue))
616: $strFontPath = dirname(QApplication::$ScriptFilename) . '/' . $mixValue;
617: else if (file_exists(sprintf('%s/fonts/%s', __QCUBED_CORE__, $mixValue)))
618: $strFontPath = sprintf('%s/fonts/%s', __QCUBED_CORE__, $mixValue);
619: else
620: throw new QCallerException('Cannot find font file: ' . $mixValue);
621:
622: $this->strFontNames = $strFontPath;
623:
624:
625: $strFontExtension = substr($mixValue, strlen($mixValue) - 3);
626: $strFontExtension = strtolower($strFontExtension);
627:
628:
629: switch($strFontExtension) {
630: case 'ttf':
631: break;
632: case 'pfb':
633: $strFontPath = substr($strFontPath, 0, strlen($strFontPath) - 3) . 'afm';
634: if (!file_exists($strFontPath))
635: throw new QCallerException('Cannot find accompanying Font Metrics file: ' .
636: substr($mixValue, 0, strlen($mixValue) - 3) . 'afm');
637: break;
638: case 'afm':
639: throw new QCallerException('AFM is only a Font Metrics file. You must provide a PFB file for PostScript Type 1 Typefaces: ' . $mixValue);
640: default:
641: throw new QCallerException('Cannot Determine Font Type: ' . $mixValue);
642: }
643: break;
644:
645: default:
646: try {
647: parent::__set($strName, $mixValue);
648: } catch (QCallerException $objExc) {
649: $objExc->IncrementOffset();
650: throw $objExc;
651: }
652: break;
653: }
654: }
655: }