From 81c1b14048a377a05722de457cf10e3c10b62f19 Mon Sep 17 00:00:00 2001 From: all-lala <16253336+al-lala@users.noreply.github.com> Date: Sat, 9 Sep 2017 12:33:57 +0200 Subject: [PATCH] Re-use original palette color when possible This is to prevent color changing when copy/pasting xls files written by PhpSpreadsheet to another file. Closes #218 --- src/PhpSpreadsheet/Writer/Xls/Workbook.php | 35 +++-- .../Writer/Xls/WorkbookTest.php | 143 ++++++++++++++++++ 2 files changed, 166 insertions(+), 12 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Writer/Xls/WorkbookTest.php diff --git a/src/PhpSpreadsheet/Writer/Xls/Workbook.php b/src/PhpSpreadsheet/Writer/Xls/Workbook.php index a493a8bf..c9b4bd0f 100644 --- a/src/PhpSpreadsheet/Writer/Xls/Workbook.php +++ b/src/PhpSpreadsheet/Writer/Xls/Workbook.php @@ -332,20 +332,31 @@ class Workbook extends BIFFwriter private function addColor($rgb) { if (!isset($this->colors[$rgb])) { - if (count($this->colors) < 57) { - // then we add a custom color altering the palette - $colorIndex = 8 + count($this->colors); - $this->palette[$colorIndex] = - [ - hexdec(substr($rgb, 0, 2)), - hexdec(substr($rgb, 2, 2)), - hexdec(substr($rgb, 4)), - 0, - ]; + $color = + [ + hexdec(substr($rgb, 0, 2)), + hexdec(substr($rgb, 2, 2)), + hexdec(substr($rgb, 4)), + 0, + ]; + $colorIndex = array_search($color, $this->palette); + if ($colorIndex) { $this->colors[$rgb] = $colorIndex; } else { - // no room for more custom colors, just map to black - $colorIndex = 0; + if (count($this->colors) == 0) { + $lastColor = 7; + } else { + $lastColor = end($this->colors); + } + if ($lastColor < 57) { + // then we add a custom color altering the palette + $colorIndex = $lastColor + 1; + $this->palette[$colorIndex] = $color; + $this->colors[$rgb] = $colorIndex; + } else { + // no room for more custom colors, just map to black + $colorIndex = 0; + } } } else { // fetch already added custom color diff --git a/tests/PhpSpreadsheetTests/Writer/Xls/WorkbookTest.php b/tests/PhpSpreadsheetTests/Writer/Xls/WorkbookTest.php new file mode 100644 index 00000000..72c2f470 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Writer/Xls/WorkbookTest.php @@ -0,0 +1,143 @@ +workbook = new Workbook($spreadsheet, $strTotal, $strUnique, $str_table, $colors, $parser); + } + + /** + * @dataProvider providerAddColor + * + * @param array $testColors + * @param array $expectedResult + */ + public function testAddColor(array $testColors, array $expectedResult) + { + $workbookReflection = new \ReflectionClass(Workbook::class); + $methodAddColor = $workbookReflection->getMethod('addColor'); + $propertyPalette = $workbookReflection->getProperty('palette'); + $methodAddColor->setAccessible(true); + $propertyPalette->setAccessible(true); + + foreach ($testColors as $testColor) { + $methodAddColor->invoke($this->workbook, $testColor); + } + + $palette = $propertyPalette->getValue($this->workbook); + + $this->assertEquals($expectedResult, $palette); + } + + public function providerAddColor() + { + $this->setUp(); + + $workbookReflection = new \ReflectionClass(Workbook::class); + $propertyPalette = $workbookReflection->getProperty('palette'); + $propertyPalette->setAccessible(true); + + $palette = $propertyPalette->getValue($this->workbook); + + $newColor1 = [0x00, 0x00, 0x01, 0x00]; + $newColor2 = [0x00, 0x00, 0x02, 0x00]; + $newColor3 = [0x00, 0x00, 0x03, 0x00]; + + // Add one new color + $paletteTestOne = $palette; + $paletteTestOne[8] = $newColor1; + + // Add one new color + one existing color after index 8 + $paletteTestTwo = $paletteTestOne; + + // Add one new color + one existing color before index 9 + $paletteTestThree = $paletteTestOne; + $paletteTestThree[9] = $palette[8]; + + // Add three new color + $paletteTestFour = $palette; + $paletteTestFour[8] = $newColor1; + $paletteTestFour[9] = $newColor2; + $paletteTestFour[10] = $newColor3; + + // Add all existing color + $colorsAdd = array_map([$this, 'paletteToColor'], $palette); + $paletteTestFive = $palette; + + // Add new color after all existing color + $colorsAddTwo = array_map([$this, 'paletteToColor'], $palette); + array_push($colorsAddTwo, $this->paletteToColor($newColor1)); + $paletteTestSix = $palette; + + // Add one existing color + $paletteTestSeven = $palette; + + // Add two existing color + $paletteTestHeight = $palette; + + // Add last existing color and add one new color + $keyPalette = array_keys($palette); + $last = end($keyPalette); + $lastColor = $this->paletteToColor($palette[$last]); + $paletteTestNine = $palette; + + return [ + [[$this->paletteToColor($newColor1)], $paletteTestOne], + [[$this->paletteToColor($newColor1), $this->paletteToColor($palette[12])], $paletteTestTwo], + [[$this->paletteToColor($newColor1), $this->paletteToColor($palette[8])], $paletteTestThree], + [[$this->paletteToColor($newColor1), $this->paletteToColor($newColor2), $this->paletteToColor($newColor3)], $paletteTestFour], + [$colorsAdd, $paletteTestFive], + [$colorsAddTwo, $paletteTestSix], + [[$this->paletteToColor($palette[8])], $paletteTestSeven], + [[$this->paletteToColor($palette[25]), $this->paletteToColor($palette[10])], $paletteTestHeight], + [[$lastColor, $this->paletteToColor($newColor1)], $paletteTestNine], + ]; + } + + /** + * Change palette color to rgb string. + * + * @param array $palette palette color + * + * @return string rgb string + */ + private function paletteToColor($palette) + { + return $this->right('00' . dechex((int) ($palette[0])), 2) + . $this->right('00' . dechex((int) ($palette[1])), 2) + . $this->right('00' . dechex((int) ($palette[2])), 2); + } + + /** + * Return n right character in string. + * + * @param string $value text to get right character + * @param int $nbchar number of char at right of string + * + * @return string + */ + private function right($value, $nbchar) + { + return mb_substr($value, mb_strlen($value) - $nbchar, $nbchar); + } +}