PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.1.2
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.1.2
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
visualizer / vendor / phpoffice / phpexcel / Classes / PHPExcel / Writer / HTML.php

HTML.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.1.2, at vendor/phpoffice/phpexcel/Classes/PHPExcel/Writer/HTML.php

1,613 lines 58.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * PHPExcel_Writer_HTML
5 *
6 * Copyright (c) 2006 - 2015 PHPExcel
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 * @category PHPExcel
23 * @package PHPExcel_Writer_HTML
24 * @copyright Copyright (c) 2006 - 2015 PHPExcel (http://www.codeplex.com/PHPExcel)
25 * @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
26 * @version ##VERSION##, ##DATE##
27 */
28 class PHPExcel_Writer_HTML extends PHPExcel_Writer_Abstract implements PHPExcel_Writer_IWriter
29 {
30 /**
31 * PHPExcel object
32 *
33 * @var PHPExcel
34 */
35 protected $phpExcel;
36
37 /**
38 * Sheet index to write
39 *
40 * @var int
41 */
42 private $sheetIndex = 0;
43
44 /**
45 * Images root
46 *
47 * @var string
48 */
49 private $imagesRoot = '.';
50
51 /**
52 * embed images, or link to images
53 *
54 * @var boolean
55 */
56 private $embedImages = false;
57
58 /**
59 * Use inline CSS?
60 *
61 * @var boolean
62 */
63 private $useInlineCss = false;
64
65 /**
66 * Array of CSS styles
67 *
68 * @var array
69 */
70 private $cssStyles;
71
72 /**
73 * Array of column widths in points
74 *
75 * @var array
76 */
77 private $columnWidths;
78
79 /**
80 * Default font
81 *
82 * @var PHPExcel_Style_Font
83 */
84 private $defaultFont;
85
86 /**
87 * Flag whether spans have been calculated
88 *
89 * @var boolean
90 */
91 private $spansAreCalculated = false;
92
93 /**
94 * Excel cells that should not be written as HTML cells
95 *
96 * @var array
97 */
98 private $isSpannedCell = array();
99
100 /**
101 * Excel cells that are upper-left corner in a cell merge
102 *
103 * @var array
104 */
105 private $isBaseCell = array();
106
107 /**
108 * Excel rows that should not be written as HTML rows
109 *
110 * @var array
111 */
112 private $isSpannedRow = array();
113
114 /**
115 * Is the current writer creating PDF?
116 *
117 * @var boolean
118 */
119 protected $isPdf = false;
120
121 /**
122 * Generate the Navigation block
123 *
124 * @var boolean
125 */
126 private $generateSheetNavigationBlock = true;
127
128 /**
129 * Create a new PHPExcel_Writer_HTML
130 *
131 * @param PHPExcel $phpExcel PHPExcel object
132 */
133 public function __construct(PHPExcel $phpExcel)
134 {
135 $this->phpExcel = $phpExcel;
136 $this->defaultFont = $this->phpExcel->getDefaultStyle()->getFont();
137 }
138
139 /**
140 * Save PHPExcel to file
141 *
142 * @param string $pFilename
143 * @throws PHPExcel_Writer_Exception
144 */
145 public function save($pFilename = null)
146 {
147 // garbage collect
148 $this->phpExcel->garbageCollect();
149
150 $saveDebugLog = PHPExcel_Calculation::getInstance($this->phpExcel)->getDebugLog()->getWriteDebugLog();
151 PHPExcel_Calculation::getInstance($this->phpExcel)->getDebugLog()->setWriteDebugLog(false);
152 $saveArrayReturnType = PHPExcel_Calculation::getArrayReturnType();
153 PHPExcel_Calculation::setArrayReturnType(PHPExcel_Calculation::RETURN_ARRAY_AS_VALUE);
154
155 // Build CSS
156 $this->buildCSS(!$this->useInlineCss);
157
158 // Open file
159 $fileHandle = fopen($pFilename, 'wb+');
160 if ($fileHandle === false) {
161 throw new PHPExcel_Writer_Exception("Could not open file $pFilename for writing.");
162 }
163
164 // Write headers
165 fwrite($fileHandle, $this->generateHTMLHeader(!$this->useInlineCss));
166
167 // Write navigation (tabs)
168 if ((!$this->isPdf) && ($this->generateSheetNavigationBlock)) {
169 fwrite($fileHandle, $this->generateNavigation());
170 }
171
172 // Write data
173 fwrite($fileHandle, $this->generateSheetData());
174
175 // Write footer
176 fwrite($fileHandle, $this->generateHTMLFooter());
177
178 // Close file
179 fclose($fileHandle);
180
181 PHPExcel_Calculation::setArrayReturnType($saveArrayReturnType);
182 PHPExcel_Calculation::getInstance($this->phpExcel)->getDebugLog()->setWriteDebugLog($saveDebugLog);
183 }
184
185 /**
186 * Map VAlign
187 *
188 * @param string $vAlign Vertical alignment
189 * @return string
190 */
191 private function mapVAlign($vAlign)
192 {
193 switch ($vAlign) {
194 case PHPExcel_Style_Alignment::VERTICAL_BOTTOM:
195 return 'bottom';
196 case PHPExcel_Style_Alignment::VERTICAL_TOP:
197 return 'top';
198 case PHPExcel_Style_Alignment::VERTICAL_CENTER:
199 case PHPExcel_Style_Alignment::VERTICAL_JUSTIFY:
200 return 'middle';
201 default:
202 return 'baseline';
203 }
204 }
205
206 /**
207 * Map HAlign
208 *
209 * @param string $hAlign Horizontal alignment
210 * @return string|false
211 */
212 private function mapHAlign($hAlign)
213 {
214 switch ($hAlign) {
215 case PHPExcel_Style_Alignment::HORIZONTAL_GENERAL:
216 return false;
217 case PHPExcel_Style_Alignment::HORIZONTAL_LEFT:
218 return 'left';
219 case PHPExcel_Style_Alignment::HORIZONTAL_RIGHT:
220 return 'right';
221 case PHPExcel_Style_Alignment::HORIZONTAL_CENTER:
222 case PHPExcel_Style_Alignment::HORIZONTAL_CENTER_CONTINUOUS:
223 return 'center';
224 case PHPExcel_Style_Alignment::HORIZONTAL_JUSTIFY:
225 return 'justify';
226 default:
227 return false;
228 }
229 }
230
231 /**
232 * Map border style
233 *
234 * @param int $borderStyle Sheet index
235 * @return string
236 */
237 private function mapBorderStyle($borderStyle)
238 {
239 switch ($borderStyle) {
240 case PHPExcel_Style_Border::BORDER_NONE:
241 return 'none';
242 case PHPExcel_Style_Border::BORDER_DASHDOT:
243 return '1px dashed';
244 case PHPExcel_Style_Border::BORDER_DASHDOTDOT:
245 return '1px dotted';
246 case PHPExcel_Style_Border::BORDER_DASHED:
247 return '1px dashed';
248 case PHPExcel_Style_Border::BORDER_DOTTED:
249 return '1px dotted';
250 case PHPExcel_Style_Border::BORDER_DOUBLE:
251 return '3px double';
252 case PHPExcel_Style_Border::BORDER_HAIR:
253 return '1px solid';
254 case PHPExcel_Style_Border::BORDER_MEDIUM:
255 return '2px solid';
256 case PHPExcel_Style_Border::BORDER_MEDIUMDASHDOT:
257 return '2px dashed';
258 case PHPExcel_Style_Border::BORDER_MEDIUMDASHDOTDOT:
259 return '2px dotted';
260 case PHPExcel_Style_Border::BORDER_MEDIUMDASHED:
261 return '2px dashed';
262 case PHPExcel_Style_Border::BORDER_SLANTDASHDOT:
263 return '2px dashed';
264 case PHPExcel_Style_Border::BORDER_THICK:
265 return '3px solid';
266 case PHPExcel_Style_Border::BORDER_THIN:
267 return '1px solid';
268 default:
269 // map others to thin
270 return '1px solid';
271 }
272 }
273
274 /**
275 * Get sheet index
276 *
277 * @return int
278 */
279 public function getSheetIndex()
280 {
281 return $this->sheetIndex;
282 }
283
284 /**
285 * Set sheet index
286 *
287 * @param int $pValue Sheet index
288 * @return PHPExcel_Writer_HTML
289 */
290 public function setSheetIndex($pValue = 0)
291 {
292 $this->sheetIndex = $pValue;
293 return $this;
294 }
295
296 /**
297 * Get sheet index
298 *
299 * @return boolean
300 */
301 public function getGenerateSheetNavigationBlock()
302 {
303 return $this->generateSheetNavigationBlock;
304 }
305
306 /**
307 * Set sheet index
308 *
309 * @param boolean $pValue Flag indicating whether the sheet navigation block should be generated or not
310 * @return PHPExcel_Writer_HTML
311 */
312 public function setGenerateSheetNavigationBlock($pValue = true)
313 {
314 $this->generateSheetNavigationBlock = (bool) $pValue;
315 return $this;
316 }
317
318 /**
319 * Write all sheets (resets sheetIndex to NULL)
320 */
321 public function writeAllSheets()
322 {
323 $this->sheetIndex = null;
324 return $this;
325 }
326
327 /**
328 * Generate HTML header
329 *
330 * @param boolean $pIncludeStyles Include styles?
331 * @return string
332 * @throws PHPExcel_Writer_Exception
333 */
334 public function generateHTMLHeader($pIncludeStyles = false)
335 {
336 // PHPExcel object known?
337 if (is_null($this->phpExcel)) {
338 throw new PHPExcel_Writer_Exception('Internal PHPExcel object not set to an instance of an object.');
339 }
340
341 // Construct HTML
342 $properties = $this->phpExcel->getProperties();
343 $html = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">' . PHP_EOL;
344 $html .= '<!-- Generated by PHPExcel - http://www.phpexcel.net -->' . PHP_EOL;
345 $html .= '<html>' . PHP_EOL;
346 $html .= ' <head>' . PHP_EOL;
347 $html .= ' <meta http-equiv="Content-Type" content="text/html; charset=utf-8">' . PHP_EOL;
348 if ($properties->getTitle() > '') {
349 $html .= ' <title>' . htmlspecialchars($properties->getTitle()) . '</title>' . PHP_EOL;
350 }
351 if ($properties->getCreator() > '') {
352 $html .= ' <meta name="author" content="' . htmlspecialchars($properties->getCreator()) . '" />' . PHP_EOL;
353 }
354 if ($properties->getTitle() > '') {
355 $html .= ' <meta name="title" content="' . htmlspecialchars($properties->getTitle()) . '" />' . PHP_EOL;
356 }
357 if ($properties->getDescription() > '') {
358 $html .= ' <meta name="description" content="' . htmlspecialchars($properties->getDescription()) . '" />' . PHP_EOL;
359 }
360 if ($properties->getSubject() > '') {
361 $html .= ' <meta name="subject" content="' . htmlspecialchars($properties->getSubject()) . '" />' . PHP_EOL;
362 }
363 if ($properties->getKeywords() > '') {
364 $html .= ' <meta name="keywords" content="' . htmlspecialchars($properties->getKeywords()) . '" />' . PHP_EOL;
365 }
366 if ($properties->getCategory() > '') {
367 $html .= ' <meta name="category" content="' . htmlspecialchars($properties->getCategory()) . '" />' . PHP_EOL;
368 }
369 if ($properties->getCompany() > '') {
370 $html .= ' <meta name="company" content="' . htmlspecialchars($properties->getCompany()) . '" />' . PHP_EOL;
371 }
372 if ($properties->getManager() > '') {
373 $html .= ' <meta name="manager" content="' . htmlspecialchars($properties->getManager()) . '" />' . PHP_EOL;
374 }
375
376 if ($pIncludeStyles) {
377 $html .= $this->generateStyles(true);
378 }
379
380 $html .= ' </head>' . PHP_EOL;
381 $html .= '' . PHP_EOL;
382 $html .= ' <body>' . PHP_EOL;
383
384 return $html;
385 }
386
387 /**
388 * Generate sheet data
389 *
390 * @return string
391 * @throws PHPExcel_Writer_Exception
392 */
393 public function generateSheetData()
394 {
395 // PHPExcel object known?
396 if (is_null($this->phpExcel)) {
397 throw new PHPExcel_Writer_Exception('Internal PHPExcel object not set to an instance of an object.');
398 }
399
400 // Ensure that Spans have been calculated?
401 if ($this->sheetIndex !== null || !$this->spansAreCalculated) {
402 $this->calculateSpans();
403 }
404
405 // Fetch sheets
406 $sheets = array();
407 if (is_null($this->sheetIndex)) {
408 $sheets = $this->phpExcel->getAllSheets();
409 } else {
410 $sheets[] = $this->phpExcel->getSheet($this->sheetIndex);
411 }
412
413 // Construct HTML
414 $html = '';
415
416 // Loop all sheets
417 $sheetId = 0;
418 foreach ($sheets as $sheet) {
419 // Write table header
420 $html .= $this->generateTableHeader($sheet);
421
422 // Get worksheet dimension
423 $dimension = explode(':', $sheet->calculateWorksheetDimension());
424 $dimension[0] = PHPExcel_Cell::coordinateFromString($dimension[0]);
425 $dimension[0][0] = PHPExcel_Cell::columnIndexFromString($dimension[0][0]) - 1;
426 $dimension[1] = PHPExcel_Cell::coordinateFromString($dimension[1]);
427 $dimension[1][0] = PHPExcel_Cell::columnIndexFromString($dimension[1][0]) - 1;
428
429 // row min,max
430 $rowMin = $dimension[0][1];
431 $rowMax = $dimension[1][1];
432
433 // calculate start of <tbody>, <thead>
434 $tbodyStart = $rowMin;
435 $theadStart = $theadEnd = 0; // default: no <thead> no </thead>
436 if ($sheet->getPageSetup()->isRowsToRepeatAtTopSet()) {
437 $rowsToRepeatAtTop = $sheet->getPageSetup()->getRowsToRepeatAtTop();
438
439 // we can only support repeating rows that start at top row
440 if ($rowsToRepeatAtTop[0] == 1) {
441 $theadStart = $rowsToRepeatAtTop[0];
442 $theadEnd = $rowsToRepeatAtTop[1];
443 $tbodyStart = $rowsToRepeatAtTop[1] + 1;
444 }
445 }
446
447 // Loop through cells
448 $row = $rowMin-1;
449 while ($row++ < $rowMax) {
450 // <thead> ?
451 if ($row == $theadStart) {
452 $html .= ' <thead>' . PHP_EOL;
453 $cellType = 'th';
454 }
455
456 // <tbody> ?
457 if ($row == $tbodyStart) {
458 $html .= ' <tbody>' . PHP_EOL;
459 $cellType = 'td';
460 }
461
462 // Write row if there are HTML table cells in it
463 if (!isset($this->isSpannedRow[$sheet->getParent()->getIndex($sheet)][$row])) {
464 // Start a new rowData
465 $rowData = array();
466 // Loop through columns
467 $column = $dimension[0][0] - 1;
468 while ($column++ < $dimension[1][0]) {
469 // Cell exists?
470 if ($sheet->cellExistsByColumnAndRow($column, $row)) {
471 $rowData[$column] = PHPExcel_Cell::stringFromColumnIndex($column) . $row;
472 } else {
473 $rowData[$column] = '';
474 }
475 }
476 $html .= $this->generateRow($sheet, $rowData, $row - 1, $cellType);
477 }
478
479 // </thead> ?
480 if ($row == $theadEnd) {
481 $html .= ' </thead>' . PHP_EOL;
482 }
483 }
484 $html .= $this->extendRowsForChartsAndImages($sheet, $row);
485
486 // Close table body.
487 $html .= ' </tbody>' . PHP_EOL;
488
489 // Write table footer
490 $html .= $this->generateTableFooter();
491
492 // Writing PDF?
493 if ($this->isPdf) {
494 if (is_null($this->sheetIndex) && $sheetId + 1 < $this->phpExcel->getSheetCount()) {
495 $html .= '<div style="page-break-before:always" />';
496 }
497 }
498
499 // Next sheet
500 ++$sheetId;
501 }
502
503 return $html;
504 }
505
506 /**
507 * Generate sheet tabs
508 *
509 * @return string
510 * @throws PHPExcel_Writer_Exception
511 */
512 public function generateNavigation()
513 {
514 // PHPExcel object known?
515 if (is_null($this->phpExcel)) {
516 throw new PHPExcel_Writer_Exception('Internal PHPExcel object not set to an instance of an object.');
517 }
518
519 // Fetch sheets
520 $sheets = array();
521 if (is_null($this->sheetIndex)) {
522 $sheets = $this->phpExcel->getAllSheets();
523 } else {
524 $sheets[] = $this->phpExcel->getSheet($this->sheetIndex);
525 }
526
527 // Construct HTML
528 $html = '';
529
530 // Only if there are more than 1 sheets
531 if (count($sheets) > 1) {
532 // Loop all sheets
533 $sheetId = 0;
534
535 $html .= '<ul class="navigation">' . PHP_EOL;
536
537 foreach ($sheets as $sheet) {
538 $html .= ' <li class="sheet' . $sheetId . '"><a href="#sheet' . $sheetId . '">' . $sheet->getTitle() . '</a></li>' . PHP_EOL;
539 ++$sheetId;
540 }
541
542 $html .= '</ul>' . PHP_EOL;
543 }
544
545 return $html;
546 }
547
548 private function extendRowsForChartsAndImages(PHPExcel_Worksheet $pSheet, $row)
549 {
550 $rowMax = $row;
551 $colMax = 'A';
552 if ($this->includeCharts) {
553 foreach ($pSheet->getChartCollection() as $chart) {
554 if ($chart instanceof PHPExcel_Chart) {
555 $chartCoordinates = $chart->getTopLeftPosition();
556 $chartTL = PHPExcel_Cell::coordinateFromString($chartCoordinates['cell']);
557 $chartCol = PHPExcel_Cell::columnIndexFromString($chartTL[0]);
558 if ($chartTL[1] > $rowMax) {
559 $rowMax = $chartTL[1];
560 if ($chartCol > PHPExcel_Cell::columnIndexFromString($colMax)) {
561 $colMax = $chartTL[0];
562 }
563 }
564 }
565 }
566 }
567
568 foreach ($pSheet->getDrawingCollection() as $drawing) {
569 if ($drawing instanceof PHPExcel_Worksheet_Drawing) {
570 $imageTL = PHPExcel_Cell::coordinateFromString($drawing->getCoordinates());
571 $imageCol = PHPExcel_Cell::columnIndexFromString($imageTL[0]);
572 if ($imageTL[1] > $rowMax) {
573 $rowMax = $imageTL[1];
574 if ($imageCol > PHPExcel_Cell::columnIndexFromString($colMax)) {
575 $colMax = $imageTL[0];
576 }
577 }
578 }
579 }
580
581 $html = '';
582 $colMax++;
583 while ($row <= $rowMax) {
584 $html .= '<tr>';
585 for ($col = 'A'; $col != $colMax; ++$col) {
586 $html .= '<td>';
587 $html .= $this->writeImageInCell($pSheet, $col.$row);
588 if ($this->includeCharts) {
589 $html .= $this->writeChartInCell($pSheet, $col.$row);
590 }
591 $html .= '</td>';
592 }
593 ++$row;
594 $html .= '</tr>';
595 }
596 return $html;
597 }
598
599
600 /**
601 * Generate image tag in cell
602 *
603 * @param PHPExcel_Worksheet $pSheet PHPExcel_Worksheet
604 * @param string $coordinates Cell coordinates
605 * @return string
606 * @throws PHPExcel_Writer_Exception
607 */
608 private function writeImageInCell(PHPExcel_Worksheet $pSheet, $coordinates)
609 {
610 // Construct HTML
611 $html = '';
612
613 // Write images
614 foreach ($pSheet->getDrawingCollection() as $drawing) {
615 if ($drawing instanceof PHPExcel_Worksheet_Drawing) {
616 if ($drawing->getCoordinates() == $coordinates) {
617 $filename = $drawing->getPath();
618
619 // Strip off eventual '.'
620 if (substr($filename, 0, 1) == '.') {
621 $filename = substr($filename, 1);
622 }
623
624 // Prepend images root
625 $filename = $this->getImagesRoot() . $filename;
626
627 // Strip off eventual '.'
628 if (substr($filename, 0, 1) == '.' && substr($filename, 0, 2) != './') {
629 $filename = substr($filename, 1);
630 }
631
632 // Convert UTF8 data to PCDATA
633 $filename = htmlspecialchars($filename);
634
635 $html .= PHP_EOL;
636 if ((!$this->embedImages) || ($this->isPdf)) {
637 $imageData = $filename;
638 } else {
639 $imageDetails = getimagesize($filename);
640 if ($fp = fopen($filename, "rb", 0)) {
641 $picture = fread($fp, filesize($filename));
642 fclose($fp);
643 // base64 encode the binary data, then break it
644 // into chunks according to RFC 2045 semantics
645 $base64 = chunk_split(base64_encode($picture));
646 $imageData = 'data:'.$imageDetails['mime'].';base64,' . $base64;
647 } else {
648 $imageData = $filename;
649 }
650 }
651
652 $html .= '<div style="position: relative;">';
653 $html .= '<img style="position: absolute; z-index: 1; left: ' .
654 $drawing->getOffsetX() . 'px; top: ' . $drawing->getOffsetY() . 'px; width: ' .
655 $drawing->getWidth() . 'px; height: ' . $drawing->getHeight() . 'px;" src="' .
656 $imageData . '" border="0" />';
657 $html .= '</div>';
658 }
659 } elseif ($drawing instanceof PHPExcel_Worksheet_MemoryDrawing) {
660 if ($drawing->getCoordinates() != $coordinates) {
661 continue;
662 }
663 ob_start(); // Let's start output buffering.
664 imagepng($drawing->getImageResource()); // This will normally output the image, but because of ob_start(), it won't.
665 $contents = ob_get_contents(); // Instead, output above is saved to $contents
666 ob_end_clean(); // End the output buffer.
667
668 $dataUri = "data:image/jpeg;base64," . base64_encode($contents);
669
670 // Because of the nature of tables, width is more important than height.
671 // max-width: 100% ensures that image doesnt overflow containing cell
672 // width: X sets width of supplied image.
673 // As a result, images bigger than cell will be contained and images smaller will not get stretched
674 $html .= '<img src="'.$dataUri.'" style="max-width:100%;width:'.$drawing->getWidth().'px;" />';
675 }
676 }
677
678 return $html;
679 }
680
681 /**
682 * Generate chart tag in cell
683 *
684 * @param PHPExcel_Worksheet $pSheet PHPExcel_Worksheet
685 * @param string $coordinates Cell coordinates
686 * @return string
687 * @throws PHPExcel_Writer_Exception
688 */
689 private function writeChartInCell(PHPExcel_Worksheet $pSheet, $coordinates)
690 {
691 // Construct HTML
692 $html = '';
693
694 // Write charts
695 foreach ($pSheet->getChartCollection() as $chart) {
696 if ($chart instanceof PHPExcel_Chart) {
697 $chartCoordinates = $chart->getTopLeftPosition();
698 if ($chartCoordinates['cell'] == $coordinates) {
699 $chartFileName = PHPExcel_Shared_File::sys_get_temp_dir().'/'.uniqid().'.png';
700 if (!$chart->render($chartFileName)) {
701 return;
702 }
703
704 $html .= PHP_EOL;
705 $imageDetails = getimagesize($chartFileName);
706 if ($fp = fopen($chartFileName, "rb", 0)) {
707 $picture = fread($fp, filesize($chartFileName));
708 fclose($fp);
709 // base64 encode the binary data, then break it
710 // into chunks according to RFC 2045 semantics
711 $base64 = chunk_split(base64_encode($picture));
712 $imageData = 'data:'.$imageDetails['mime'].';base64,' . $base64;
713
714 $html .= '<div style="position: relative;">';
715 $html .= '<img style="position: absolute; z-index: 1; left: ' . $chartCoordinates['xOffset'] . 'px; top: ' . $chartCoordinates['yOffset'] . 'px; width: ' . $imageDetails[0] . 'px; height: ' . $imageDetails[1] . 'px;" src="' . $imageData . '" border="0" />' . PHP_EOL;
716 $html .= '</div>';
717
718 unlink($chartFileName);
719 }
720 }
721 }
722 }
723
724 // Return
725 return $html;
726 }
727
728 /**
729 * Generate CSS styles
730 *
731 * @param boolean $generateSurroundingHTML Generate surrounding HTML tags? (&lt;style&gt; and &lt;/style&gt;)
732 * @return string
733 * @throws PHPExcel_Writer_Exception
734 */
735 public function generateStyles($generateSurroundingHTML = true)
736 {
737 // PHPExcel object known?
738 if (is_null($this->phpExcel)) {
739 throw new PHPExcel_Writer_Exception('Internal PHPExcel object not set to an instance of an object.');
740 }
741
742 // Build CSS
743 $css = $this->buildCSS($generateSurroundingHTML);
744
745 // Construct HTML
746 $html = '';
747
748 // Start styles
749 if ($generateSurroundingHTML) {
750 $html .= ' <style type="text/css">' . PHP_EOL;
751 $html .= ' html { ' . $this->assembleCSS($css['html']) . ' }' . PHP_EOL;
752 }
753
754 // Write all other styles
755 foreach ($css as $styleName => $styleDefinition) {
756 if ($styleName != 'html') {
757 $html .= ' ' . $styleName . ' { ' . $this->assembleCSS($styleDefinition) . ' }' . PHP_EOL;
758 }
759 }
760
761 // End styles
762 if ($generateSurroundingHTML) {
763 $html .= ' </style>' . PHP_EOL;
764 }
765
766 // Return
767 return $html;
768 }
769
770 /**
771 * Build CSS styles
772 *
773 * @param boolean $generateSurroundingHTML Generate surrounding HTML style? (html { })
774 * @return array
775 * @throws PHPExcel_Writer_Exception
776 */
777 public function buildCSS($generateSurroundingHTML = true)
778 {
779 // PHPExcel object known?
780 if (is_null($this->phpExcel)) {
781 throw new PHPExcel_Writer_Exception('Internal PHPExcel object not set to an instance of an object.');
782 }
783
784 // Cached?
785 if (!is_null($this->cssStyles)) {
786 return $this->cssStyles;
787 }
788
789 // Ensure that spans have been calculated
790 if (!$this->spansAreCalculated) {
791 $this->calculateSpans();
792 }
793
794 // Construct CSS
795 $css = array();
796
797 // Start styles
798 if ($generateSurroundingHTML) {
799 // html { }
800 $css['html']['font-family'] = 'Calibri, Arial, Helvetica, sans-serif';
801 $css['html']['font-size'] = '11pt';
802 $css['html']['background-color'] = 'white';
803 }
804
805
806 // table { }
807 $css['table']['border-collapse'] = 'collapse';
808 if (!$this->isPdf) {
809 $css['table']['page-break-after'] = 'always';
810 }
811
812 // .gridlines td { }
813 $css['.gridlines td']['border'] = '1px dotted black';
814 $css['.gridlines th']['border'] = '1px dotted black';
815
816 // .b {}
817 $css['.b']['text-align'] = 'center'; // BOOL
818
819 // .e {}
820 $css['.e']['text-align'] = 'center'; // ERROR
821
822 // .f {}
823 $css['.f']['text-align'] = 'right'; // FORMULA
824
825 // .inlineStr {}
826 $css['.inlineStr']['text-align'] = 'left'; // INLINE
827
828 // .n {}
829 $css['.n']['text-align'] = 'right'; // NUMERIC
830
831 // .s {}
832 $css['.s']['text-align'] = 'left'; // STRING
833
834 // Calculate cell style hashes
835 foreach ($this->phpExcel->getCellXfCollection() as $index => $style) {
836 $css['td.style' . $index] = $this->createCSSStyle($style);
837 $css['th.style' . $index] = $this->createCSSStyle($style);
838 }
839
840 // Fetch sheets
841 $sheets = array();
842 if (is_null($this->sheetIndex)) {
843 $sheets = $this->phpExcel->getAllSheets();
844 } else {
845 $sheets[] = $this->phpExcel->getSheet($this->sheetIndex);
846 }
847
848 // Build styles per sheet
849 foreach ($sheets as $sheet) {
850 // Calculate hash code
851 $sheetIndex = $sheet->getParent()->getIndex($sheet);
852
853 // Build styles
854 // Calculate column widths
855 $sheet->calculateColumnWidths();
856
857 // col elements, initialize
858 $highestColumnIndex = PHPExcel_Cell::columnIndexFromString($sheet->getHighestColumn()) - 1;
859 $column = -1;
860 while ($column++ < $highestColumnIndex) {
861 $this->columnWidths[$sheetIndex][$column] = 42; // approximation
862 $css['table.sheet' . $sheetIndex . ' col.col' . $column]['width'] = '42pt';
863 }
864
865 // col elements, loop through columnDimensions and set width
866 foreach ($sheet->getColumnDimensions() as $columnDimension) {
867 if (($width = PHPExcel_Shared_Drawing::cellDimensionToPixels($columnDimension->getWidth(), $this->defaultFont)) >= 0) {
868 $width = PHPExcel_Shared_Drawing::pixelsToPoints($width);
869 $column = PHPExcel_Cell::columnIndexFromString($columnDimension->getColumnIndex()) - 1;
870 $this->columnWidths[$sheetIndex][$column] = $width;
871 $css['table.sheet' . $sheetIndex . ' col.col' . $column]['width'] = $width . 'pt';
872
873 if ($columnDimension->getVisible() === false) {
874 $css['table.sheet' . $sheetIndex . ' col.col' . $column]['visibility'] = 'collapse';
875 $css['table.sheet' . $sheetIndex . ' col.col' . $column]['*display'] = 'none'; // target IE6+7
876 }
877 }
878 }
879
880 // Default row height
881 $rowDimension = $sheet->getDefaultRowDimension();
882
883 // table.sheetN tr { }
884 $css['table.sheet' . $sheetIndex . ' tr'] = array();
885
886 if ($rowDimension->getRowHeight() == -1) {
887 $pt_height = PHPExcel_Shared_Font::getDefaultRowHeightByFont($this->phpExcel->getDefaultStyle()->getFont());
888 } else {
889 $pt_height = $rowDimension->getRowHeight();
890 }
891 $css['table.sheet' . $sheetIndex . ' tr']['height'] = $pt_height . 'pt';
892 if ($rowDimension->getVisible() === false) {
893 $css['table.sheet' . $sheetIndex . ' tr']['display'] = 'none';
894 $css['table.sheet' . $sheetIndex . ' tr']['visibility'] = 'hidden';
895 }
896
897 // Calculate row heights
898 foreach ($sheet->getRowDimensions() as $rowDimension) {
899 $row = $rowDimension->getRowIndex() - 1;
900
901 // table.sheetN tr.rowYYYYYY { }
902 $css['table.sheet' . $sheetIndex . ' tr.row' . $row] = array();
903
904 if ($rowDimension->getRowHeight() == -1) {
905 $pt_height = PHPExcel_Shared_Font::getDefaultRowHeightByFont($this->phpExcel->getDefaultStyle()->getFont());
906 } else {
907 $pt_height = $rowDimension->getRowHeight();
908 }
909 $css['table.sheet' . $sheetIndex . ' tr.row' . $row]['height'] = $pt_height . 'pt';
910 if ($rowDimension->getVisible() === false) {
911 $css['table.sheet' . $sheetIndex . ' tr.row' . $row]['display'] = 'none';
912 $css['table.sheet' . $sheetIndex . ' tr.row' . $row]['visibility'] = 'hidden';
913 }
914 }
915 }
916
917 // Cache
918 if (is_null($this->cssStyles)) {
919 $this->cssStyles = $css;
920 }
921
922 // Return
923 return $css;
924 }
925
926 /**
927 * Create CSS style
928 *
929 * @param PHPExcel_Style $pStyle PHPExcel_Style
930 * @return array
931 */
932 private function createCSSStyle(PHPExcel_Style $pStyle)
933 {
934 // Construct CSS
935 $css = '';
936
937 // Create CSS
938 $css = array_merge(
939 $this->createCSSStyleAlignment($pStyle->getAlignment()),
940 $this->createCSSStyleBorders($pStyle->getBorders()),
941 $this->createCSSStyleFont($pStyle->getFont()),
942 $this->createCSSStyleFill($pStyle->getFill())
943 );
944
945 // Return
946 return $css;
947 }
948
949 /**
950 * Create CSS style (PHPExcel_Style_Alignment)
951 *
952 * @param PHPExcel_Style_Alignment $pStyle PHPExcel_Style_Alignment
953 * @return array
954 */
955 private function createCSSStyleAlignment(PHPExcel_Style_Alignment $pStyle)
956 {
957 // Construct CSS
958 $css = array();
959
960 // Create CSS
961 $css['vertical-align'] = $this->mapVAlign($pStyle->getVertical());
962 if ($textAlign = $this->mapHAlign($pStyle->getHorizontal())) {
963 $css['text-align'] = $textAlign;
964 if (in_array($textAlign, array('left', 'right'))) {
965 $css['padding-'.$textAlign] = (string)((int)$pStyle->getIndent() * 9).'px';
966 }
967 }
968
969 return $css;
970 }
971
972 /**
973 * Create CSS style (PHPExcel_Style_Font)
974 *
975 * @param PHPExcel_Style_Font $pStyle PHPExcel_Style_Font
976 * @return array
977 */
978 private function createCSSStyleFont(PHPExcel_Style_Font $pStyle)
979 {
980 // Construct CSS
981 $css = array();
982
983 // Create CSS
984 if ($pStyle->getBold()) {
985 $css['font-weight'] = 'bold';
986 }
987 if ($pStyle->getUnderline() != PHPExcel_Style_Font::UNDERLINE_NONE && $pStyle->getStrikethrough()) {
988 $css['text-decoration'] = 'underline line-through';
989 } elseif ($pStyle->getUnderline() != PHPExcel_Style_Font::UNDERLINE_NONE) {
990 $css['text-decoration'] = 'underline';
991 } elseif ($pStyle->getStrikethrough()) {
992 $css['text-decoration'] = 'line-through';
993 }
994 if ($pStyle->getItalic()) {
995 $css['font-style'] = 'italic';
996 }
997
998 $css['color'] = '#' . $pStyle->getColor()->getRGB();
999 $css['font-family'] = '\'' . $pStyle->getName() . '\'';
1000 $css['font-size'] = $pStyle->getSize() . 'pt';
1001
1002 return $css;
1003 }
1004
1005 /**
1006 * Create CSS style (PHPExcel_Style_Borders)
1007 *
1008 * @param PHPExcel_Style_Borders $pStyle PHPExcel_Style_Borders
1009 * @return array
1010 */
1011 private function createCSSStyleBorders(PHPExcel_Style_Borders $pStyle)
1012 {
1013 // Construct CSS
1014 $css = array();
1015
1016 // Create CSS
1017 $css['border-bottom'] = $this->createCSSStyleBorder($pStyle->getBottom());
1018 $css['border-top'] = $this->createCSSStyleBorder($pStyle->getTop());
1019 $css['border-left'] = $this->createCSSStyleBorder($pStyle->getLeft());
1020 $css['border-right'] = $this->createCSSStyleBorder($pStyle->getRight());
1021
1022 return $css;
1023 }
1024
1025 /**
1026 * Create CSS style (PHPExcel_Style_Border)
1027 *
1028 * @param PHPExcel_Style_Border $pStyle PHPExcel_Style_Border
1029 * @return string
1030 */
1031 private function createCSSStyleBorder(PHPExcel_Style_Border $pStyle)
1032 {
1033 // Create CSS
1034 // $css = $this->mapBorderStyle($pStyle->getBorderStyle()) . ' #' . $pStyle->getColor()->getRGB();
1035 // Create CSS - add !important to non-none border styles for merged cells
1036 $borderStyle = $this->mapBorderStyle($pStyle->getBorderStyle());
1037 $css = $borderStyle . ' #' . $pStyle->getColor()->getRGB() . (($borderStyle == 'none') ? '' : ' !important');
1038
1039 return $css;
1040 }
1041
1042 /**
1043 * Create CSS style (PHPExcel_Style_Fill)
1044 *
1045 * @param PHPExcel_Style_Fill $pStyle PHPExcel_Style_Fill
1046 * @return array
1047 */
1048 private function createCSSStyleFill(PHPExcel_Style_Fill $pStyle)
1049 {
1050 // Construct HTML
1051 $css = array();
1052
1053 // Create CSS
1054 $value = $pStyle->getFillType() == PHPExcel_Style_Fill::FILL_NONE ?
1055 'white' : '#' . $pStyle->getStartColor()->getRGB();
1056 $css['background-color'] = $value;
1057
1058 return $css;
1059 }
1060
1061 /**
1062 * Generate HTML footer
1063 */
1064 public function generateHTMLFooter()
1065 {
1066 // Construct HTML
1067 $html = '';
1068 $html .= ' </body>' . PHP_EOL;
1069 $html .= '</html>' . PHP_EOL;
1070
1071 return $html;
1072 }
1073
1074 /**
1075 * Generate table header
1076 *
1077 * @param PHPExcel_Worksheet $pSheet The worksheet for the table we are writing
1078 * @return string
1079 * @throws PHPExcel_Writer_Exception
1080 */
1081 private function generateTableHeader($pSheet)
1082 {
1083 $sheetIndex = $pSheet->getParent()->getIndex($pSheet);
1084
1085 // Construct HTML
1086 $html = '';
1087 $html .= $this->setMargins($pSheet);
1088
1089 if (!$this->useInlineCss) {
1090 $gridlines = $pSheet->getShowGridlines() ? ' gridlines' : '';
1091 $html .= ' <table border="0" cellpadding="0" cellspacing="0" id="sheet' . $sheetIndex . '" class="sheet' . $sheetIndex . $gridlines . '">' . PHP_EOL;
1092 } else {
1093 $style = isset($this->cssStyles['table']) ?
1094 $this->assembleCSS($this->cssStyles['table']) : '';
1095
1096 if ($this->isPdf && $pSheet->getShowGridlines()) {
1097 $html .= ' <table border="1" cellpadding="1" id="sheet' . $sheetIndex . '" cellspacing="1" style="' . $style . '">' . PHP_EOL;
1098 } else {
1099 $html .= ' <table border="0" cellpadding="1" id="sheet' . $sheetIndex . '" cellspacing="0" style="' . $style . '">' . PHP_EOL;
1100 }
1101 }
1102
1103 // Write <col> elements
1104 $highestColumnIndex = PHPExcel_Cell::columnIndexFromString($pSheet->getHighestColumn()) - 1;
1105 $i = -1;
1106 while ($i++ < $highestColumnIndex) {
1107 if (!$this->isPdf) {
1108 if (!$this->useInlineCss) {
1109 $html .= ' <col class="col' . $i . '">' . PHP_EOL;
1110 } else {
1111 $style = isset($this->cssStyles['table.sheet' . $sheetIndex . ' col.col' . $i]) ?
1112 $this->assembleCSS($this->cssStyles['table.sheet' . $sheetIndex . ' col.col' . $i]) : '';
1113 $html .= ' <col style="' . $style . '">' . PHP_EOL;
1114 }
1115 }
1116 }
1117
1118 return $html;
1119 }
1120
1121 /**
1122 * Generate table footer
1123 *
1124 * @throws PHPExcel_Writer_Exception
1125 */
1126 private function generateTableFooter()
1127 {
1128 $html = ' </table>' . PHP_EOL;
1129
1130 return $html;
1131 }
1132
1133 /**
1134 * Generate row
1135 *
1136 * @param PHPExcel_Worksheet $pSheet PHPExcel_Worksheet
1137 * @param array $pValues Array containing cells in a row
1138 * @param int $pRow Row number (0-based)
1139 * @return string
1140 * @throws PHPExcel_Writer_Exception
1141 */
1142 private function generateRow(PHPExcel_Worksheet $pSheet, $pValues = null, $pRow = 0, $cellType = 'td')
1143 {
1144 if (is_array($pValues)) {
1145 // Construct HTML
1146 $html = '';
1147
1148 // Sheet index
1149 $sheetIndex = $pSheet->getParent()->getIndex($pSheet);
1150
1151 // DomPDF and breaks
1152 if ($this->isPdf && count($pSheet->getBreaks()) > 0) {
1153 $breaks = $pSheet->getBreaks();
1154
1155 // check if a break is needed before this row
1156 if (isset($breaks['A' . $pRow])) {
1157 // close table: </table>
1158 $html .= $this->generateTableFooter();
1159
1160 // insert page break
1161 $html .= '<div style="page-break-before:always" />';
1162
1163 // open table again: <table> + <col> etc.
1164 $html .= $this->generateTableHeader($pSheet);
1165 }
1166 }
1167
1168 // Write row start
1169 if (!$this->useInlineCss) {
1170 $html .= ' <tr class="row' . $pRow . '">' . PHP_EOL;
1171 } else {
1172 $style = isset($this->cssStyles['table.sheet' . $sheetIndex . ' tr.row' . $pRow])
1173 ? $this->assembleCSS($this->cssStyles['table.sheet' . $sheetIndex . ' tr.row' . $pRow]) : '';
1174
1175 $html .= ' <tr style="' . $style . '">' . PHP_EOL;
1176 }
1177
1178 // Write cells
1179 $colNum = 0;
1180 foreach ($pValues as $cellAddress) {
1181 $cell = ($cellAddress > '') ? $pSheet->getCell($cellAddress) : '';
1182 $coordinate = PHPExcel_Cell::stringFromColumnIndex($colNum) . ($pRow + 1);
1183 if (!$this->useInlineCss) {
1184 $cssClass = '';
1185 $cssClass = 'column' . $colNum;
1186 } else {
1187 $cssClass = array();
1188 if ($cellType == 'th') {
1189 if (isset($this->cssStyles['table.sheet' . $sheetIndex . ' th.column' . $colNum])) {
1190 $this->cssStyles['table.sheet' . $sheetIndex . ' th.column' . $colNum];
1191 }
1192 } else {
1193 if (isset($this->cssStyles['table.sheet' . $sheetIndex . ' td.column' . $colNum])) {
1194 $this->cssStyles['table.sheet' . $sheetIndex . ' td.column' . $colNum];
1195 }
1196 }
1197 }
1198 $colSpan = 1;
1199 $rowSpan = 1;
1200
1201 // initialize
1202 $cellData = '&nbsp;';
1203
1204 // PHPExcel_Cell
1205 if ($cell instanceof PHPExcel_Cell) {
1206 $cellData = '';
1207 if (is_null($cell->getParent())) {
1208 $cell->attach($pSheet);
1209 }
1210 // Value
1211 if ($cell->getValue() instanceof PHPExcel_RichText) {
1212 // Loop through rich text elements
1213 $elements = $cell->getValue()->getRichTextElements();
1214 foreach ($elements as $element) {
1215 // Rich text start?
1216 if ($element instanceof PHPExcel_RichText_Run) {
1217 $cellData .= '<span style="' . $this->assembleCSS($this->createCSSStyleFont($element->getFont())) . '">';
1218
1219 if ($element->getFont()->getSuperScript()) {
1220 $cellData .= '<sup>';
1221 } elseif ($element->getFont()->getSubScript()) {
1222 $cellData .= '<sub>';
1223 }
1224 }
1225
1226 // Convert UTF8 data to PCDATA
1227 $cellText = $element->getText();
1228 $cellData .= htmlspecialchars($cellText);
1229
1230 if ($element instanceof PHPExcel_RichText_Run) {
1231 if ($element->getFont()->getSuperScript()) {
1232 $cellData .= '</sup>';
1233 } elseif ($element->getFont()->getSubScript()) {
1234 $cellData .= '</sub>';
1235 }
1236
1237 $cellData .= '</span>';
1238 }
1239 }
1240 } else {
1241 if ($this->preCalculateFormulas) {
1242 $cellData = PHPExcel_Style_NumberFormat::toFormattedString(
1243 $cell->getCalculatedValue(),
1244 $pSheet->getParent()->getCellXfByIndex($cell->getXfIndex())->getNumberFormat()->getFormatCode(),
1245 array($this, 'formatColor')
1246 );
1247 } else {
1248 $cellData = PHPExcel_Style_NumberFormat::toFormattedString(
1249 $cell->getValue(),
1250 $pSheet->getParent()->getCellXfByIndex($cell->getXfIndex())->getNumberFormat()->getFormatCode(),
1251 array($this, 'formatColor')
1252 );
1253 }
1254 $cellData = htmlspecialchars($cellData);
1255 if ($pSheet->getParent()->getCellXfByIndex($cell->getXfIndex())->getFont()->getSuperScript()) {
1256 $cellData = '<sup>'.$cellData.'</sup>';
1257 } elseif ($pSheet->getParent()->getCellXfByIndex($cell->getXfIndex())->getFont()->getSubScript()) {
1258 $cellData = '<sub>'.$cellData.'</sub>';
1259 }
1260 }
1261
1262 // Converts the cell content so that spaces occuring at beginning of each new line are replaced by &nbsp;
1263 // Example: " Hello\n to the world" is converted to "&nbsp;&nbsp;Hello\n&nbsp;to the world"
1264 $cellData = preg_replace("/(?m)(?:^|\\G) /", '&nbsp;', $cellData);
1265
1266 // convert newline "\n" to '<br>'
1267 $cellData = nl2br($cellData);
1268
1269 // Extend CSS class?
1270 if (!$this->useInlineCss) {
1271 $cssClass .= ' style' . $cell->getXfIndex();
1272 $cssClass .= ' ' . $cell->getDataType();
1273 } else {
1274 if ($cellType == 'th') {
1275 if (isset($this->cssStyles['th.style' . $cell->getXfIndex()])) {
1276 $cssClass = array_merge($cssClass, $this->cssStyles['th.style' . $cell->getXfIndex()]);
1277 }
1278 } else {
1279 if (isset($this->cssStyles['td.style' . $cell->getXfIndex()])) {
1280 $cssClass = array_merge($cssClass, $this->cssStyles['td.style' . $cell->getXfIndex()]);
1281 }
1282 }
1283
1284 // General horizontal alignment: Actual horizontal alignment depends on dataType
1285 $sharedStyle = $pSheet->getParent()->getCellXfByIndex($cell->getXfIndex());
1286 if ($sharedStyle->getAlignment()->getHorizontal() == PHPExcel_Style_Alignment::HORIZONTAL_GENERAL
1287 && isset($this->cssStyles['.' . $cell->getDataType()]['text-align'])) {
1288 $cssClass['text-align'] = $this->cssStyles['.' . $cell->getDataType()]['text-align'];
1289 }
1290 }
1291 }
1292
1293 // Hyperlink?
1294 if ($pSheet->hyperlinkExists($coordinate) && !$pSheet->getHyperlink($coordinate)->isInternal()) {
1295 $cellData = '<a href="' . htmlspecialchars($pSheet->getHyperlink($coordinate)->getUrl()) . '" title="' . htmlspecialchars($pSheet->getHyperlink($coordinate)->getTooltip()) . '">' . $cellData . '</a>';
1296 }
1297
1298 // Should the cell be written or is it swallowed by a rowspan or colspan?
1299 $writeCell = !(isset($this->isSpannedCell[$pSheet->getParent()->getIndex($pSheet)][$pRow + 1][$colNum])
1300 && $this->isSpannedCell[$pSheet->getParent()->getIndex($pSheet)][$pRow + 1][$colNum]);
1301
1302 // Colspan and Rowspan
1303 $colspan = 1;
1304 $rowspan = 1;
1305 if (isset($this->isBaseCell[$pSheet->getParent()->getIndex($pSheet)][$pRow + 1][$colNum])) {
1306 $spans = $this->isBaseCell[$pSheet->getParent()->getIndex($pSheet)][$pRow + 1][$colNum];
1307 $rowSpan = $spans['rowspan'];
1308 $colSpan = $spans['colspan'];
1309
1310 // Also apply style from last cell in merge to fix borders -
1311 // relies on !important for non-none border declarations in createCSSStyleBorder
1312 $endCellCoord = PHPExcel_Cell::stringFromColumnIndex($colNum + $colSpan - 1) . ($pRow + $rowSpan);
1313 if (!$this->useInlineCss) {
1314 $cssClass .= ' style' . $pSheet->getCell($endCellCoord)->getXfIndex();
1315 }
1316 }
1317
1318 // Write
1319 if ($writeCell) {
1320 // Column start
1321 $html .= ' <' . $cellType;
1322 if (!$this->useInlineCss) {
1323 $html .= ' class="' . $cssClass . '"';
1324 } else {
1325 //** Necessary redundant code for the sake of PHPExcel_Writer_PDF **
1326 // We must explicitly write the width of the <td> element because TCPDF
1327 // does not recognize e.g. <col style="width:42pt">
1328 $width = 0;
1329 $i = $colNum - 1;
1330 $e = $colNum + $colSpan - 1;
1331 while ($i++ < $e) {
1332 if (isset($this->columnWidths[$sheetIndex][$i])) {
1333 $width += $this->columnWidths[$sheetIndex][$i];
1334 }
1335 }
1336 $cssClass['width'] = $width . 'pt';
1337
1338 // We must also explicitly write the height of the <td> element because TCPDF
1339 // does not recognize e.g. <tr style="height:50pt">
1340 if (isset($this->cssStyles['table.sheet' . $sheetIndex . ' tr.row' . $pRow]['height'])) {
1341 $height = $this->cssStyles['table.sheet' . $sheetIndex . ' tr.row' . $pRow]['height'];
1342 $cssClass['height'] = $height;
1343 }
1344 //** end of redundant code **
1345
1346 $html .= ' style="' . $this->assembleCSS($cssClass) . '"';
1347 }
1348 if ($colSpan > 1) {
1349 $html .= ' colspan="' . $colSpan . '"';
1350 }
1351 if ($rowSpan > 1) {
1352 $html .= ' rowspan="' . $rowSpan . '"';
1353 }
1354 $html .= '>';
1355
1356 // Image?
1357 $html .= $this->writeImageInCell($pSheet, $coordinate);
1358
1359 // Chart?
1360 if ($this->includeCharts) {
1361 $html .= $this->writeChartInCell($pSheet, $coordinate);
1362 }
1363
1364 // Cell data
1365 $html .= $cellData;
1366
1367 // Column end
1368 $html .= '</'.$cellType.'>' . PHP_EOL;
1369 }
1370
1371 // Next column
1372 ++$colNum;
1373 }
1374
1375 // Write row end
1376 $html .= ' </tr>' . PHP_EOL;
1377
1378 // Return
1379 return $html;
1380 } else {
1381 throw new PHPExcel_Writer_Exception("Invalid parameters passed.");
1382 }
1383 }
1384
1385 /**
1386 * Takes array where of CSS properties / values and converts to CSS string
1387 *
1388 * @param array
1389 * @return string
1390 */
1391 private function assembleCSS($pValue = array())
1392 {
1393 $pairs = array();
1394 foreach ($pValue as $property => $value) {
1395 $pairs[] = $property . ':' . $value;
1396 }
1397 $string = implode('; ', $pairs);
1398
1399 return $string;
1400 }
1401
1402 /**
1403 * Get images root
1404 *
1405 * @return string
1406 */
1407 public function getImagesRoot()
1408 {
1409 return $this->imagesRoot;
1410 }
1411
1412 /**
1413 * Set images root
1414 *
1415 * @param string $pValue
1416 * @return PHPExcel_Writer_HTML
1417 */
1418 public function setImagesRoot($pValue = '.')
1419 {
1420 $this->imagesRoot = $pValue;
1421 return $this;
1422 }
1423
1424 /**
1425 * Get embed images
1426 *
1427 * @return boolean
1428 */
1429 public function getEmbedImages()
1430 {
1431 return $this->embedImages;
1432 }
1433
1434 /**
1435 * Set embed images
1436 *
1437 * @param boolean $pValue
1438 * @return PHPExcel_Writer_HTML
1439 */
1440 public function setEmbedImages($pValue = '.')
1441 {
1442 $this->embedImages = $pValue;
1443 return $this;
1444 }
1445
1446 /**
1447 * Get use inline CSS?
1448 *
1449 * @return boolean
1450 */
1451 public function getUseInlineCss()
1452 {
1453 return $this->useInlineCss;
1454 }
1455
1456 /**
1457 * Set use inline CSS?
1458 *
1459 * @param boolean $pValue
1460 * @return PHPExcel_Writer_HTML
1461 */
1462 public function setUseInlineCss($pValue = false)
1463 {
1464 $this->useInlineCss = $pValue;
1465 return $this;
1466 }
1467
1468 /**
1469 * Add color to formatted string as inline style
1470 *
1471 * @param string $pValue Plain formatted value without color
1472 * @param string $pFormat Format code
1473 * @return string
1474 */
1475 public function formatColor($pValue, $pFormat)
1476 {
1477 // Color information, e.g. [Red] is always at the beginning
1478 $color = null; // initialize
1479 $matches = array();
1480
1481 $color_regex = '/^\\[[a-zA-Z]+\\]/';
1482 if (preg_match($color_regex, $pFormat, $matches)) {
1483 $color = str_replace('[', '', $matches[0]);
1484 $color = str_replace(']', '', $color);
1485 $color = strtolower($color);
1486 }
1487
1488 // convert to PCDATA
1489 $value = htmlspecialchars($pValue);
1490
1491 // color span tag
1492 if ($color !== null) {
1493 $value = '<span style="color:' . $color . '">' . $value . '</span>';
1494 }
1495
1496 return $value;
1497 }
1498
1499 /**
1500 * Calculate information about HTML colspan and rowspan which is not always the same as Excel's
1501 */
1502 private function calculateSpans()
1503 {
1504 // Identify all cells that should be omitted in HTML due to cell merge.
1505 // In HTML only the upper-left cell should be written and it should have
1506 // appropriate rowspan / colspan attribute
1507 $sheetIndexes = $this->sheetIndex !== null ?
1508 array($this->sheetIndex) : range(0, $this->phpExcel->getSheetCount() - 1);
1509
1510 foreach ($sheetIndexes as $sheetIndex) {
1511 $sheet = $this->phpExcel->getSheet($sheetIndex);
1512
1513 $candidateSpannedRow = array();
1514
1515 // loop through all Excel merged cells
1516 foreach ($sheet->getMergeCells() as $cells) {
1517 list($cells,) = PHPExcel_Cell::splitRange($cells);
1518 $first = $cells[0];
1519 $last = $cells[1];
1520
1521 list($fc, $fr) = PHPExcel_Cell::coordinateFromString($first);
1522 $fc = PHPExcel_Cell::columnIndexFromString($fc) - 1;
1523
1524 list($lc, $lr) = PHPExcel_Cell::coordinateFromString($last);
1525 $lc = PHPExcel_Cell::columnIndexFromString($lc) - 1;
1526
1527 // loop through the individual cells in the individual merge
1528 $r = $fr - 1;
1529 while ($r++ < $lr) {
1530 // also, flag this row as a HTML row that is candidate to be omitted
1531 $candidateSpannedRow[$r] = $r;
1532
1533 $c = $fc - 1;
1534 while ($c++ < $lc) {
1535 if (!($c == $fc && $r == $fr)) {
1536 // not the upper-left cell (should not be written in HTML)
1537 $this->isSpannedCell[$sheetIndex][$r][$c] = array(
1538 'baseCell' => array($fr, $fc),
1539 );
1540 } else {
1541 // upper-left is the base cell that should hold the colspan/rowspan attribute
1542 $this->isBaseCell[$sheetIndex][$r][$c] = array(
1543 'xlrowspan' => $lr - $fr + 1, // Excel rowspan
1544 'rowspan' => $lr - $fr + 1, // HTML rowspan, value may change
1545 'xlcolspan' => $lc - $fc + 1, // Excel colspan
1546 'colspan' => $lc - $fc + 1, // HTML colspan, value may change
1547 );
1548 }
1549 }
1550 }
1551 }
1552
1553 // Identify which rows should be omitted in HTML. These are the rows where all the cells
1554 // participate in a merge and the where base cells are somewhere above.
1555 $countColumns = PHPExcel_Cell::columnIndexFromString($sheet->getHighestColumn());
1556 foreach ($candidateSpannedRow as $rowIndex) {
1557 if (isset($this->isSpannedCell[$sheetIndex][$rowIndex])) {
1558 if (count($this->isSpannedCell[$sheetIndex][$rowIndex]) == $countColumns) {
1559 $this->isSpannedRow[$sheetIndex][$rowIndex] = $rowIndex;
1560 };
1561 }
1562 }
1563
1564 // For each of the omitted rows we found above, the affected rowspans should be subtracted by 1
1565 if (isset($this->isSpannedRow[$sheetIndex])) {
1566 foreach ($this->isSpannedRow[$sheetIndex] as $rowIndex) {
1567 $adjustedBaseCells = array();
1568 $c = -1;
1569 $e = $countColumns - 1;
1570 while ($c++ < $e) {
1571 $baseCell = $this->isSpannedCell[$sheetIndex][$rowIndex][$c]['baseCell'];
1572
1573 if (!in_array($baseCell, $adjustedBaseCells)) {
1574 // subtract rowspan by 1
1575 --$this->isBaseCell[$sheetIndex][ $baseCell[0] ][ $baseCell[1] ]['rowspan'];
1576 $adjustedBaseCells[] = $baseCell;
1577 }
1578 }
1579 }
1580 }
1581
1582 // TODO: Same for columns
1583 }
1584
1585 // We have calculated the spans
1586 $this->spansAreCalculated = true;
1587 }
1588
1589 private function setMargins(PHPExcel_Worksheet $pSheet)
1590 {
1591 $htmlPage = '@page { ';
1592 $htmlBody = 'body { ';
1593
1594 $left = PHPExcel_Shared_String::FormatNumber($pSheet->getPageMargins()->getLeft()) . 'in; ';
1595 $htmlPage .= 'margin-left: ' . $left;
1596 $htmlBody .= 'margin-left: ' . $left;
1597 $right = PHPExcel_Shared_String::FormatNumber($pSheet->getPageMargins()->getRight()) . 'in; ';
1598 $htmlPage .= 'margin-right: ' . $right;
1599 $htmlBody .= 'margin-right: ' . $right;
1600 $top = PHPExcel_Shared_String::FormatNumber($pSheet->getPageMargins()->getTop()) . 'in; ';
1601 $htmlPage .= 'margin-top: ' . $top;
1602 $htmlBody .= 'margin-top: ' . $top;
1603 $bottom = PHPExcel_Shared_String::FormatNumber($pSheet->getPageMargins()->getBottom()) . 'in; ';
1604 $htmlPage .= 'margin-bottom: ' . $bottom;
1605 $htmlBody .= 'margin-bottom: ' . $bottom;
1606
1607 $htmlPage .= "}\n";
1608 $htmlBody .= "}\n";
1609
1610 return "<style>\n" . $htmlPage . $htmlBody . "</style>\n";
1611 }
1612 }
1613