1 <?php
3 /*
4 * Copyleft 2002 Johann Hanne
5 *
6 * This is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This software is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this software; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place,
19 * Suite 330, Boston, MA 02111-1307 USA
20 */
22 /*
23 * This is the Spreadsheet::WriteExcel Perl package ported to PHP
24 * Spreadsheet::WriteExcel was written by John McNamara, jmcnamara@cpan.org
25 */
27 class writeexcel_format {
29 var $_xf_index;
30 var $_font_index;
31 var $_font;
32 var $_size;
33 var $_bold;
34 var $_italic;
35 var $_color;
36 var $_underline;
37 var $_font_strikeout;
38 var $_font_outline;
39 var $_font_shadow;
40 var $_font_script;
41 var $_font_family;
42 var $_font_charset;
43 var $_num_format;
44 var $_hidden;
45 var $_locked;
46 var $_text_h_align;
47 var $_text_wrap;
48 var $_text_v_align;
49 var $_text_justlast;
50 var $_rotation;
51 var $_fg_color;
52 var $_bg_color;
53 var $_pattern;
54 var $_bottom;
55 var $_top;
56 var $_left;
57 var $_right;
58 var $_bottom_color;
59 var $_top_color;
60 var $_left_color;
61 var $_right_color;
63 /*
64 * Constructor
65 */
66 function writeexcel_format() {
67 $_=func_get_args();
69 $this->_xf_index = (sizeof($_)>0) ? array_shift($_) : 0;
71 $this->_font_index = 0;
72 $this->_font = 'Arial';
73 $this->_size = 10;
74 $this->_bold = 0x0190;
75 $this->_italic = 0;
76 $this->_color = 0x7FFF;
77 $this->_underline = 0;
78 $this->_font_strikeout = 0;
79 $this->_font_outline = 0;
80 $this->_font_shadow = 0;
81 $this->_font_script = 0;
82 $this->_font_family = 0;
83 $this->_font_charset = 0;
85 $this->_num_format = 0;
87 $this->_hidden = 0;
88 $this->_locked = 1;
90 $this->_text_h_align = 0;
91 $this->_text_wrap = 0;
92 $this->_text_v_align = 2;
93 $this->_text_justlast = 0;
94 $this->_rotation = 0;
96 $this->_fg_color = 0x40;
97 $this->_bg_color = 0x41;
99 $this->_pattern = 0;
101 $this->_bottom = 0;
102 $this->_top = 0;
103 $this->_left = 0;
104 $this->_right = 0;
106 $this->_bottom_color = 0x40;
107 $this->_top_color = 0x40;
108 $this->_left_color = 0x40;
109 $this->_right_color = 0x40;
111 // Set properties passed to writeexcel_workbook::addformat()
112 if (sizeof($_)>0) {
113 call_user_func_array(array($this, 'set_properties'), $_);
114 }
115 }
117 /*
118 * Copy the attributes of another writeexcel_format object.
119 */
120 function copy($other) {
121 $xf = $this->_xf_index; // Backup XF index
123 /* A better way to copy member vars, ... won't cause fatal errors in PHP5.
124 The only thing i can understand is : For what is this function used,
125 it is never used by any object, as I can see in the source code.
126 ...
127 */
128 foreach(get_object_vars($other) as $var => $val){
129 $this->$var = $val;
130 }
131 // $this = $other; // Copy properties
132 $this->_xf_index = $xf; // Restore XF index
133 }
135 /*
136 * Generate an Excel BIFF XF record.
137 */
138 function get_xf() {
140 $_=func_get_args();
142 // $record Record identifier
143 // $length Number of bytes to follow
145 // $ifnt Index to FONT record
146 // $ifmt Index to FORMAT record
147 // $style Style and other options
148 // $align Alignment
149 // $icv fg and bg pattern colors
150 // $fill Fill and border line style
151 // $border1 Border line style and color
152 // $border2 Border color
154 // Set the type of the XF record and some of the attributes.
155 if ($_[0] == "style") {
156 $style = 0xFFF5;
157 } else {
158 $style = $this->_locked;
159 $style |= $this->_hidden << 1;
160 }
162 // Flags to indicate if attributes have been set.
163 $atr_num = ($this->_num_format != 0) ? 1 : 0;
164 $atr_fnt = ($this->_font_index != 0) ? 1 : 0;
165 $atr_alc = $this->_text_wrap ? 1 : 0;
166 $atr_bdr = ($this->_bottom ||
167 $this->_top ||
168 $this->_left ||
169 $this->_right) ? 1 : 0;
170 $atr_pat = ($this->_fg_color != 0x41 ||
171 $this->_bg_color != 0x41 ||
172 $this->_pattern != 0x00) ? 1 : 0;
173 $atr_prot = 0;
175 // Reset the default colors for the non-font properties
176 if ($this->_fg_color == 0x7FFF) $this->_fg_color = 0x40;
177 if ($this->_bg_color == 0x7FFF) $this->_bg_color = 0x41;
178 if ($this->_bottom_color == 0x7FFF) $this->_bottom_color = 0x41;
179 if ($this->_top_color == 0x7FFF) $this->_top_color = 0x41;
180 if ($this->_left_color == 0x7FFF) $this->_left_color = 0x41;
181 if ($this->_right_color == 0x7FFF) $this->_right_color = 0x41;
183 // Zero the default border colour if the border has not been set.
184 if ($this->_bottom == 0) {
185 $this->_bottom_color = 0;
186 }
187 if ($this->_top == 0) {
188 $this->_top_color = 0;
189 }
190 if ($this->_right == 0) {
191 $this->_right_color = 0;
192 }
193 if ($this->_left == 0) {
194 $this->_left_color = 0;
195 }
197 // The following 2 logical statements take care of special cases in
198 // relation to cell colors and patterns:
199 // 1. For a solid fill (_pattern == 1) Excel reverses the role of
200 // foreground and background colors
201 // 2. If the user specifies a foreground or background color
202 // without a pattern they probably wanted a solid fill, so we
203 // fill in the defaults.
204 if ($this->_pattern <= 0x01 &&
205 $this->_bg_color != 0x41 &&
206 $this->_fg_color == 0x40 )
207 {
208 $this->_fg_color = $this->_bg_color;
209 $this->_bg_color = 0x40;
210 $this->_pattern = 1;
211 }
213 if ($this->_pattern <= 0x01 &&
214 $this->_bg_color == 0x41 &&
215 $this->_fg_color != 0x40 )
216 {
217 $this->_bg_color = 0x40;
218 $this->_pattern = 1;
219 }
221 $record = 0x00E0;
222 $length = 0x0010;
224 $ifnt = $this->_font_index;
225 $ifmt = $this->_num_format;
227 $align = $this->_text_h_align;
228 $align |= $this->_text_wrap << 3;
229 $align |= $this->_text_v_align << 4;
230 $align |= $this->_text_justlast << 7;
231 $align |= $this->_rotation << 8;
232 $align |= $atr_num << 10;
233 $align |= $atr_fnt << 11;
234 $align |= $atr_alc << 12;
235 $align |= $atr_bdr << 13;
236 $align |= $atr_pat << 14;
237 $align |= $atr_prot << 15;
239 $icv = $this->_fg_color;
240 $icv |= $this->_bg_color << 7;
242 $fill = $this->_pattern;
243 $fill |= $this->_bottom << 6;
244 $fill |= $this->_bottom_color << 9;
246 $border1 = $this->_top;
247 $border1 |= $this->_left << 3;
248 $border1 |= $this->_right << 6;
249 $border1 |= $this->_top_color << 9;
251 $border2 = $this->_left_color;
252 $border2 |= $this->_right_color << 7;
254 $header = pack("vv", $record, $length);
255 $data = pack("vvvvvvvv", $ifnt, $ifmt, $style, $align,
256 $icv, $fill,
257 $border1, $border2);
259 return($header . $data);
260 }
262 /*
263 * Generate an Excel BIFF FONT record.
264 */
265 function get_font() {
267 // $record Record identifier
268 // $length Record length
270 // $dyHeight Height of font (1/20 of a point)
271 // $grbit Font attributes
272 // $icv Index to color palette
273 // $bls Bold style
274 // $sss Superscript/subscript
275 // $uls Underline
276 // $bFamily Font family
277 // $bCharSet Character set
278 // $reserved Reserved
279 // $cch Length of font name
280 // $rgch Font name
282 $dyHeight = $this->_size * 20;
283 $icv = $this->_color;
284 $bls = $this->_bold;
285 $sss = $this->_font_script;
286 $uls = $this->_underline;
287 $bFamily = $this->_font_family;
288 $bCharSet = $this->_font_charset;
289 $rgch = $this->_font;
291 $cch = strlen($rgch);
292 $record = 0x31;
293 $length = 0x0F + $cch;
294 $reserved = 0x00;
296 $grbit = 0x00;
298 if ($this->_italic) {
299 $grbit |= 0x02;
300 }
302 if ($this->_font_strikeout) {
303 $grbit |= 0x08;
304 }
306 if ($this->_font_outline) {
307 $grbit |= 0x10;
308 }
310 if ($this->_font_shadow) {
311 $grbit |= 0x20;
312 }
314 $header = pack("vv", $record, $length);
315 $data = pack("vvvvvCCCCC", $dyHeight, $grbit, $icv, $bls,
316 $sss, $uls, $bFamily,
317 $bCharSet, $reserved, $cch);
319 return($header . $data . $this->_font);
320 }
322 /*
323 * Returns a unique hash key for a font.
324 * Used by writeexcel_workbook::_store_all_fonts()
325 */
326 function get_font_key() {
328 # The following elements are arranged to increase the probability of
329 # generating a unique key. Elements that hold a large range of numbers
330 # eg. _color are placed between two binary elements such as _italic
331 #
332 $key = $this->_font.$this->_size.
333 $this->_font_script.$this->_underline.
334 $this->_font_strikeout.$this->_bold.$this->_font_outline.
335 $this->_font_family.$this->_font_charset.
336 $this->_font_shadow.$this->_color.$this->_italic;
338 $key = preg_replace('/ /', '_', $key); # Convert the key to a single word
340 return $key;
341 }
343 /*
344 * Returns the used by Worksheet->_XF()
345 */
346 function get_xf_index() {
347 return $this->_xf_index;
348 }
350 /*
351 * Used in conjunction with the set_xxx_color methods to convert a color
352 * string into a number. Color range is 0..63 but we will restrict it
353 * to 8..63 to comply with Gnumeric. Colors 0..7 are repeated in 8..15.
354 */
355 function _get_color($color=false) {
357 $colors = array(
358 'aqua' => 0x0F,
359 'cyan' => 0x0F,
360 'black' => 0x08,
361 'blue' => 0x0C,
362 'brown' => 0x10,
363 'magenta' => 0x0E,
364 'fuchsia' => 0x0E,
365 'gray' => 0x17,
366 'grey' => 0x17,
367 'green' => 0x11,
368 'lime' => 0x0B,
369 'navy' => 0x12,
370 'orange' => 0x35,
371 'purple' => 0x14,
372 'red' => 0x0A,
373 'silver' => 0x16,
374 'white' => 0x09,
375 'yellow' => 0x0D
376 );
378 // Return the default color, 0x7FFF, if undef,
379 if ($color===false) {
380 return 0x7FFF;
381 }
383 // or the color string converted to an integer,
384 if (isset($colors[strtolower($color)])) {
385 return $colors[strtolower($color)];
386 }
388 // or the default color if string is unrecognised,
389 if (preg_match('/\D/', $color)) {
390 return 0x7FFF;
391 }
393 // or an index < 8 mapped into the correct range,
394 if ($color<8) {
395 return $color + 8;
396 }
398 // or the default color if arg is outside range,
399 if ($color>63) {
400 return 0x7FFF;
401 }
403 // or an integer in the valid range
404 return $color;
405 }
407 /*
408 * Set cell alignment.
409 */
410 function set_align($location) {
412 // Ignore numbers
413 if (preg_match('/\d/', $location)) {
414 return;
415 }
417 $location = strtolower($location);
419 switch ($location) {
421 case 'left':
422 $this->set_text_h_align(1);
423 break;
425 case 'centre':
426 case 'center':
427 $this->set_text_h_align(2);
428 break;
430 case 'right':
431 $this->set_text_h_align(3);
432 break;
434 case 'fill':
435 $this->set_text_h_align(4);
436 break;
438 case 'justify':
439 $this->set_text_h_align(5);
440 break;
442 case 'merge':
443 $this->set_text_h_align(6);
444 break;
446 case 'equal_space':
447 $this->set_text_h_align(7);
448 break;
450 case 'top':
451 $this->set_text_v_align(0);
452 break;
454 case 'vcentre':
455 case 'vcenter':
456 $this->set_text_v_align(1);
457 break;
458 break;
460 case 'bottom':
461 $this->set_text_v_align(2);
462 break;
464 case 'vjustify':
465 $this->set_text_v_align(3);
466 break;
468 case 'vequal_space':
469 $this->set_text_v_align(4);
470 break;
471 }
472 }
474 /*
475 * Set vertical cell alignment. This is required by the set_properties()
476 * method to differentiate between the vertical and horizontal properties.
477 */
478 function set_valign($location) {
479 $this->set_align($location);
480 }
482 /*
483 * This is an alias for the unintuitive set_align('merge')
484 */
485 function set_merge() {
486 $this->set_text_h_align(6);
487 }
489 /*
490 * Bold has a range 0x64..0x3E8.
491 * 0x190 is normal. 0x2BC is bold.
492 */
493 function set_bold($weight=1) {
495 if ($weight == 1) {
496 // Bold text
497 $weight = 0x2BC;
498 }
500 if ($weight == 0) {
501 // Normal text
502 $weight = 0x190;
503 }
505 if ($weight < 0x064) {
506 // Lower bound
507 $weight = 0x190;
508 }
510 if ($weight > 0x3E8) {
511 // Upper bound
512 $weight = 0x190;
513 }
515 $this->_bold = $weight;
516 }
518 /*
519 * Set all cell borders (bottom, top, left, right) to the same style
520 */
521 function set_border($style) {
522 $this->set_bottom($style);
523 $this->set_top($style);
524 $this->set_left($style);
525 $this->set_right($style);
526 }
528 /*
529 * Set all cell borders (bottom, top, left, right) to the same color
530 */
531 function set_border_color($color) {
532 $this->set_bottom_color($color);
533 $this->set_top_color($color);
534 $this->set_left_color($color);
535 $this->set_right_color($color);
536 }
538 /*
539 * Convert hashes of properties to method calls.
540 */
541 function set_properties() {
543 $_=func_get_args();
545 $properties=array();
546 foreach($_ as $props) {
547 if (is_array($props)) {
548 $properties=array_merge($properties, $props);
549 } else {
550 $properties[]=$props;
551 }
552 }
554 foreach ($properties as $key=>$value) {
556 // Strip leading "-" from Tk style properties eg. -color => 'red'.
557 $key = preg_replace('/^-/', '', $key);
559 /* Make sure method names are alphanumeric characters only, in
560 case tainted data is passed to the eval(). */
561 if (preg_match('/\W/', $key)) {
562 trigger_error("Unknown property: $key.",
563 E_USER_ERROR);
564 }
566 /* Evaling all $values as a strings gets around the problem of
567 some numerical format strings being evaluated as numbers, for
568 example "00000" for a zip code. */
569 if (is_int($key)) {
570 eval("\$this->set_$value();");
571 } else {
572 eval("\$this->set_$key('$value');");
573 }
575 }
576 }
578 function set_font($font) {
579 $this->_font=$font;
580 }
582 function set_size($size) {
583 $this->_size=$size;
584 }
586 function set_italic($italic=1) {
587 $this->_italic=$italic;
588 }
590 function set_color($color) {
591 $this->_color=$this->_get_color($color);
592 }
594 function set_underline($underline=1) {
595 $this->_underline=$underline;
596 }
598 function set_font_strikeout($font_strikeout=1) {
599 $this->_font_strikeout=$font_strikeout;
600 }
602 function set_font_outline($font_outline=1) {
603 $this->_font_outline=$font_outline;
604 }
606 function set_font_shadow($font_shadow=1) {
607 $this->_font_shadow=$font_shadow;
608 }
610 function set_font_script($font_script=1) {
611 $this->_font_script=$font_script;
612 }
614 /* Undocumented */
615 function set_font_family($font_family=1) {
616 $this->_font_family=$font_family;
617 }
619 /* Undocumented */
620 function set_font_charset($font_charset=1) {
621 $this->_font_charset=$font_charset;
622 }
624 function set_num_format($num_format=1) {
625 $this->_num_format=$num_format;
626 }
628 function set_hidden($hidden=1) {
629 $this->_hidden=$hidden;
630 }
632 function set_locked($locked=1) {
633 $this->_locked=$locked;
634 }
636 function set_text_h_align($align) {
637 $this->_text_h_align=$align;
638 }
640 function set_text_wrap($wrap=1) {
641 $this->_text_wrap=$wrap;
642 }
644 function set_text_v_align($align) {
645 $this->_text_v_align=$align;
646 }
648 function set_text_justlast($text_justlast=1) {
649 $this->_text_justlast=$text_justlast;
650 }
652 function set_rotation($rotation=1) {
653 $this->_rotation=$rotation;
654 }
656 function set_fg_color($color) {
657 $this->_fg_color=$this->_get_color($color);
658 }
660 function set_bg_color($color) {
661 $this->_bg_color=$this->_get_color($color);
662 }
664 function set_pattern($pattern=1) {
665 $this->_pattern=$pattern;
666 }
668 function set_bottom($bottom=1) {
669 $this->_bottom=$bottom;
670 }
672 function set_top($top=1) {
673 $this->_top=$top;
674 }
676 function set_left($left=1) {
677 $this->_left=$left;
678 }
680 function set_right($right=1) {
681 $this->_right=$right;
682 }
684 function set_bottom_color($color) {
685 $this->_bottom_color=$this->_get_color($color);
686 }
688 function set_top_color($color) {
689 $this->_top_color=$this->_get_color($color);
690 }
692 function set_left_color($color) {
693 $this->_left_color=$this->_get_color($color);
694 }
696 function set_right_color($color) {
697 $this->_right_color=$this->_get_color($color);
698 }
700 }
702 ?>