Differences Between: [Versions 400 and 402] [Versions 401 and 402]
1 <?php 2 3 namespace PhpOffice\PhpSpreadsheet\Reader\Gnumeric; 4 5 use PhpOffice\PhpSpreadsheet\Cell\Coordinate; 6 use PhpOffice\PhpSpreadsheet\Shared\Date; 7 use PhpOffice\PhpSpreadsheet\Spreadsheet; 8 use PhpOffice\PhpSpreadsheet\Style\Alignment; 9 use PhpOffice\PhpSpreadsheet\Style\Border; 10 use PhpOffice\PhpSpreadsheet\Style\Borders; 11 use PhpOffice\PhpSpreadsheet\Style\Fill; 12 use PhpOffice\PhpSpreadsheet\Style\Font; 13 use SimpleXMLElement; 14 15 class Styles 16 { 17 /** 18 * @var Spreadsheet 19 */ 20 private $spreadsheet; 21 22 /** 23 * @var bool 24 */ 25 protected $readDataOnly = false; 26 27 /** @var array */ 28 public static $mappings = [ 29 'borderStyle' => [ 30 '0' => Border::BORDER_NONE, 31 '1' => Border::BORDER_THIN, 32 '2' => Border::BORDER_MEDIUM, 33 '3' => Border::BORDER_SLANTDASHDOT, 34 '4' => Border::BORDER_DASHED, 35 '5' => Border::BORDER_THICK, 36 '6' => Border::BORDER_DOUBLE, 37 '7' => Border::BORDER_DOTTED, 38 '8' => Border::BORDER_MEDIUMDASHED, 39 '9' => Border::BORDER_DASHDOT, 40 '10' => Border::BORDER_MEDIUMDASHDOT, 41 '11' => Border::BORDER_DASHDOTDOT, 42 '12' => Border::BORDER_MEDIUMDASHDOTDOT, 43 '13' => Border::BORDER_MEDIUMDASHDOTDOT, 44 ], 45 'fillType' => [ 46 '1' => Fill::FILL_SOLID, 47 '2' => Fill::FILL_PATTERN_DARKGRAY, 48 '3' => Fill::FILL_PATTERN_MEDIUMGRAY, 49 '4' => Fill::FILL_PATTERN_LIGHTGRAY, 50 '5' => Fill::FILL_PATTERN_GRAY125, 51 '6' => Fill::FILL_PATTERN_GRAY0625, 52 '7' => Fill::FILL_PATTERN_DARKHORIZONTAL, // horizontal stripe 53 '8' => Fill::FILL_PATTERN_DARKVERTICAL, // vertical stripe 54 '9' => Fill::FILL_PATTERN_DARKDOWN, // diagonal stripe 55 '10' => Fill::FILL_PATTERN_DARKUP, // reverse diagonal stripe 56 '11' => Fill::FILL_PATTERN_DARKGRID, // diagoanl crosshatch 57 '12' => Fill::FILL_PATTERN_DARKTRELLIS, // thick diagonal crosshatch 58 '13' => Fill::FILL_PATTERN_LIGHTHORIZONTAL, 59 '14' => Fill::FILL_PATTERN_LIGHTVERTICAL, 60 '15' => Fill::FILL_PATTERN_LIGHTUP, 61 '16' => Fill::FILL_PATTERN_LIGHTDOWN, 62 '17' => Fill::FILL_PATTERN_LIGHTGRID, // thin horizontal crosshatch 63 '18' => Fill::FILL_PATTERN_LIGHTTRELLIS, // thin diagonal crosshatch 64 ], 65 'horizontal' => [ 66 '1' => Alignment::HORIZONTAL_GENERAL, 67 '2' => Alignment::HORIZONTAL_LEFT, 68 '4' => Alignment::HORIZONTAL_RIGHT, 69 '8' => Alignment::HORIZONTAL_CENTER, 70 '16' => Alignment::HORIZONTAL_CENTER_CONTINUOUS, 71 '32' => Alignment::HORIZONTAL_JUSTIFY, 72 '64' => Alignment::HORIZONTAL_CENTER_CONTINUOUS, 73 ], 74 'underline' => [ 75 '1' => Font::UNDERLINE_SINGLE, 76 '2' => Font::UNDERLINE_DOUBLE, 77 '3' => Font::UNDERLINE_SINGLEACCOUNTING, 78 '4' => Font::UNDERLINE_DOUBLEACCOUNTING, 79 ], 80 'vertical' => [ 81 '1' => Alignment::VERTICAL_TOP, 82 '2' => Alignment::VERTICAL_BOTTOM, 83 '4' => Alignment::VERTICAL_CENTER, 84 '8' => Alignment::VERTICAL_JUSTIFY, 85 ], 86 ]; 87 88 public function __construct(Spreadsheet $spreadsheet, bool $readDataOnly) 89 { 90 $this->spreadsheet = $spreadsheet; 91 $this->readDataOnly = $readDataOnly; 92 } 93 94 public function read(SimpleXMLElement $sheet, int $maxRow, int $maxCol): void 95 { 96 if ($sheet->Styles->StyleRegion !== null) { 97 $this->readStyles($sheet->Styles->StyleRegion, $maxRow, $maxCol); 98 } 99 } 100 101 private function readStyles(SimpleXMLElement $styleRegion, int $maxRow, int $maxCol): void 102 { 103 foreach ($styleRegion as $style) { 104 /** @scrutinizer ignore-call */ 105 $styleAttributes = $style->attributes(); 106 if ($styleAttributes !== null && ($styleAttributes['startRow'] <= $maxRow) && ($styleAttributes['startCol'] <= $maxCol)) { 107 $cellRange = $this->readStyleRange($styleAttributes, $maxCol, $maxRow); 108 109 $styleAttributes = $style->Style->attributes(); 110 111 $styleArray = []; 112 // We still set the number format mask for date/time values, even if readDataOnly is true 113 // so that we can identify whether a float is a float or a date value 114 $formatCode = $styleAttributes ? (string) $styleAttributes['Format'] : null; 115 if ($formatCode && Date::isDateTimeFormatCode($formatCode)) { 116 $styleArray['numberFormat']['formatCode'] = $formatCode; 117 } 118 if ($this->readDataOnly === false && $styleAttributes !== null) { 119 // If readDataOnly is false, we set all formatting information 120 $styleArray['numberFormat']['formatCode'] = $formatCode; 121 $styleArray = $this->readStyle($styleArray, $styleAttributes, /** @scrutinizer ignore-type */ $style); 122 } 123 $this->spreadsheet->getActiveSheet()->getStyle($cellRange)->applyFromArray($styleArray); 124 } 125 } 126 } 127 128 private function addBorderDiagonal(SimpleXMLElement $srssb, array &$styleArray): void 129 { 130 if (isset($srssb->Diagonal, $srssb->{'Rev-Diagonal'})) { 131 $styleArray['borders']['diagonal'] = self::parseBorderAttributes($srssb->Diagonal->attributes()); 132 $styleArray['borders']['diagonalDirection'] = Borders::DIAGONAL_BOTH; 133 } elseif (isset($srssb->Diagonal)) { 134 $styleArray['borders']['diagonal'] = self::parseBorderAttributes($srssb->Diagonal->attributes()); 135 $styleArray['borders']['diagonalDirection'] = Borders::DIAGONAL_UP; 136 } elseif (isset($srssb->{'Rev-Diagonal'})) { 137 $styleArray['borders']['diagonal'] = self::parseBorderAttributes($srssb->{'Rev-Diagonal'}->attributes()); 138 $styleArray['borders']['diagonalDirection'] = Borders::DIAGONAL_DOWN; 139 } 140 } 141 142 private function addBorderStyle(SimpleXMLElement $srssb, array &$styleArray, string $direction): void 143 { 144 $ucDirection = ucfirst($direction); 145 if (isset($srssb->$ucDirection)) { 146 $styleArray['borders'][$direction] = self::parseBorderAttributes($srssb->$ucDirection->attributes()); 147 } 148 } 149 150 private function calcRotation(SimpleXMLElement $styleAttributes): int 151 { 152 $rotation = (int) $styleAttributes->Rotation; 153 if ($rotation >= 270 && $rotation <= 360) { 154 $rotation -= 360; 155 } 156 $rotation = (abs($rotation) > 90) ? 0 : $rotation; 157 158 return $rotation; 159 } 160 161 private static function addStyle(array &$styleArray, string $key, string $value): void 162 { 163 if (array_key_exists($value, self::$mappings[$key])) { 164 $styleArray[$key] = self::$mappings[$key][$value]; 165 } 166 } 167 168 private static function addStyle2(array &$styleArray, string $key1, string $key, string $value): void 169 { 170 if (array_key_exists($value, self::$mappings[$key])) { 171 $styleArray[$key1][$key] = self::$mappings[$key][$value]; 172 } 173 } 174 175 private static function parseBorderAttributes(?SimpleXMLElement $borderAttributes): array 176 { 177 $styleArray = []; 178 if ($borderAttributes !== null) { 179 if (isset($borderAttributes['Color'])) { 180 $styleArray['color']['rgb'] = self::parseGnumericColour($borderAttributes['Color']); 181 } 182 183 self::addStyle($styleArray, 'borderStyle', (string) $borderAttributes['Style']); 184 } 185 186 return $styleArray; 187 } 188 189 private static function parseGnumericColour(string $gnmColour): string 190 { 191 [$gnmR, $gnmG, $gnmB] = explode(':', $gnmColour); 192 $gnmR = substr(str_pad($gnmR, 4, '0', STR_PAD_RIGHT), 0, 2); 193 $gnmG = substr(str_pad($gnmG, 4, '0', STR_PAD_RIGHT), 0, 2); 194 $gnmB = substr(str_pad($gnmB, 4, '0', STR_PAD_RIGHT), 0, 2); 195 196 return $gnmR . $gnmG . $gnmB; 197 } 198 199 private function addColors(array &$styleArray, SimpleXMLElement $styleAttributes): void 200 { 201 $RGB = self::parseGnumericColour((string) $styleAttributes['Fore']); 202 $styleArray['font']['color']['rgb'] = $RGB; 203 $RGB = self::parseGnumericColour((string) $styleAttributes['Back']); 204 $shade = (string) $styleAttributes['Shade']; 205 if (($RGB !== '000000') || ($shade !== '0')) { 206 $RGB2 = self::parseGnumericColour((string) $styleAttributes['PatternColor']); 207 if ($shade === '1') { 208 $styleArray['fill']['startColor']['rgb'] = $RGB; 209 $styleArray['fill']['endColor']['rgb'] = $RGB2; 210 } else { 211 $styleArray['fill']['endColor']['rgb'] = $RGB; 212 $styleArray['fill']['startColor']['rgb'] = $RGB2; 213 } 214 self::addStyle2($styleArray, 'fill', 'fillType', $shade); 215 } 216 } 217 218 private function readStyleRange(SimpleXMLElement $styleAttributes, int $maxCol, int $maxRow): string 219 { 220 $startColumn = Coordinate::stringFromColumnIndex((int) $styleAttributes['startCol'] + 1); 221 $startRow = $styleAttributes['startRow'] + 1; 222 223 $endColumn = ($styleAttributes['endCol'] > $maxCol) ? $maxCol : (int) $styleAttributes['endCol']; 224 $endColumn = Coordinate::stringFromColumnIndex($endColumn + 1); 225 226 $endRow = 1 + (($styleAttributes['endRow'] > $maxRow) ? $maxRow : (int) $styleAttributes['endRow']); 227 $cellRange = $startColumn . $startRow . ':' . $endColumn . $endRow; 228 229 return $cellRange; 230 } 231 232 private function readStyle(array $styleArray, SimpleXMLElement $styleAttributes, SimpleXMLElement $style): array 233 { 234 self::addStyle2($styleArray, 'alignment', 'horizontal', (string) $styleAttributes['HAlign']); 235 self::addStyle2($styleArray, 'alignment', 'vertical', (string) $styleAttributes['VAlign']); 236 $styleArray['alignment']['wrapText'] = $styleAttributes['WrapText'] == '1'; 237 $styleArray['alignment']['textRotation'] = $this->calcRotation($styleAttributes); 238 $styleArray['alignment']['shrinkToFit'] = $styleAttributes['ShrinkToFit'] == '1'; 239 $styleArray['alignment']['indent'] = ((int) ($styleAttributes['Indent']) > 0) ? $styleAttributes['indent'] : 0; 240 241 $this->addColors($styleArray, $styleAttributes); 242 243 $fontAttributes = $style->Style->Font->attributes(); 244 if ($fontAttributes !== null) { 245 $styleArray['font']['name'] = (string) $style->Style->Font; 246 $styleArray['font']['size'] = (int) ($fontAttributes['Unit']); 247 $styleArray['font']['bold'] = $fontAttributes['Bold'] == '1'; 248 $styleArray['font']['italic'] = $fontAttributes['Italic'] == '1'; 249 $styleArray['font']['strikethrough'] = $fontAttributes['StrikeThrough'] == '1'; 250 self::addStyle2($styleArray, 'font', 'underline', (string) $fontAttributes['Underline']); 251 252 switch ($fontAttributes['Script']) { 253 case '1': 254 $styleArray['font']['superscript'] = true; 255 256 break; 257 case '-1': 258 $styleArray['font']['subscript'] = true; 259 260 break; 261 } 262 } 263 264 if (isset($style->Style->StyleBorder)) { 265 $srssb = $style->Style->StyleBorder; 266 $this->addBorderStyle($srssb, $styleArray, 'top'); 267 $this->addBorderStyle($srssb, $styleArray, 'bottom'); 268 $this->addBorderStyle($srssb, $styleArray, 'left'); 269 $this->addBorderStyle($srssb, $styleArray, 'right'); 270 $this->addBorderDiagonal($srssb, $styleArray); 271 } 272 // TO DO 273 /* 274 if (isset($style->Style->HyperLink)) { 275 $hyperlink = $style->Style->HyperLink->attributes(); 276 } 277 */ 278 279 return $styleArray; 280 } 281 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body