diff --git a/src/PhpSpreadsheet/Style/Color.php b/src/PhpSpreadsheet/Style/Color.php index 3c002b270..282defc0c 100644 --- a/src/PhpSpreadsheet/Style/Color.php +++ b/src/PhpSpreadsheet/Style/Color.php @@ -362,23 +362,8 @@ class Color extends Supervisor $green = self::getGreen($hexColourValue, false); /** @var int $blue */ $blue = self::getBlue($hexColourValue, false); - if ($adjustPercentage > 0) { - $red += (255 - $red) * $adjustPercentage; - $green += (255 - $green) * $adjustPercentage; - $blue += (255 - $blue) * $adjustPercentage; - } else { - $red += $red * $adjustPercentage; - $green += $green * $adjustPercentage; - $blue += $blue * $adjustPercentage; - } - $rgb = strtoupper( - str_pad(dechex((int) $red), 2, '0', 0) . - str_pad(dechex((int) $green), 2, '0', 0) . - str_pad(dechex((int) $blue), 2, '0', 0) - ); - - return (($rgba) ? 'FF' : '') . $rgb; + return (($rgba) ? 'FF' : '') . RgbTint::rgbAndTintToRgb($red, $green, $blue, $adjustPercentage); } /** diff --git a/src/PhpSpreadsheet/Style/RgbTint.php b/src/PhpSpreadsheet/Style/RgbTint.php new file mode 100644 index 000000000..582ae4839 --- /dev/null +++ b/src/PhpSpreadsheet/Style/RgbTint.php @@ -0,0 +1,175 @@ += 0.0) ? $hue : (1.0 + $hue); + } + + /** + * Convert red/green/blue to HLSMAX-based hue/luminance/saturation. + * + * @return int[] + */ + private static function rgbToMsHls(int $red, int $green, int $blue): array + { + $red01 = $red / self::RGBMAX; + $green01 = $green / self::RGBMAX; + $blue01 = $blue / self::RGBMAX; + [$hue, $luminance, $saturation] = self::rgbToHls($red01, $green01, $blue01); + + return [ + (int) round($hue * self::HLSMAX), + (int) round($luminance * self::HLSMAX), + (int) round($saturation * self::HLSMAX), + ]; + } + + /** + * Converts HLSMAX based HLS values to rgb values in the range (0,1). + * + * @return float[] + */ + private static function msHlsToRgb(int $hue, int $lightness, int $saturation): array + { + return self::hlsToRgb($hue / self::HLSMAX, $lightness / self::HLSMAX, $saturation / self::HLSMAX); + } + + /** + * Tints HLSMAX based luminance. + * + * @see http://ciintelligence.blogspot.co.uk/2012/02/converting-excel-theme-color-and-tint.html + */ + private static function tintLuminance(float $tint, float $luminance): int + { + if ($tint < 0) { + return (int) round($luminance * (1.0 + $tint)); + } + + return (int) round($luminance * (1.0 - $tint) + (self::HLSMAX - self::HLSMAX * (1.0 - $tint))); + } + + /** + * Return result of tinting supplied rgb as 6 hex digits. + */ + public static function rgbAndTintToRgb(int $red, int $green, int $blue, float $tint): string + { + [$hue, $luminance, $saturation] = self::rgbToMsHls($red, $green, $blue); + [$red, $green, $blue] = self::msHlsToRgb($hue, self::tintLuminance($tint, $luminance), $saturation); + + return sprintf( + '%02X%02X%02X', + (int) round($red * self::RGBMAX), + (int) round($green * self::RGBMAX), + (int) round($blue * self::RGBMAX) + ); + } +} diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue2387Test.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue2387Test.php index 870ea6ab0..7e59418ad 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue2387Test.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/Issue2387Test.php @@ -15,7 +15,11 @@ class Issue2387Test extends TestCase $reader = IOFactory::createReader('Xlsx'); $spreadsheet = $reader->load($filename); $sheet = $spreadsheet->getActiveSheet(); - self::assertSame('335593', $sheet->getCell('B2')->getStyle()->getFont()->getColor()->getRgb()); + // Font color being tested uses theme color with tint. + // Excel shows final color as 305496. + $expectedColor = '305496'; + $calculatedColor = $sheet->getCell('B2')->getStyle()->getFont()->getColor()->getRgb(); + self::assertSame($expectedColor, RgbTintTest::compareColors($calculatedColor, $expectedColor)); self::assertSame(Fill::FILL_NONE, $sheet->getCell('B2')->getStyle()->getFill()->getFillType()); self::assertSame('FFFFFF', $sheet->getCell('C2')->getStyle()->getFont()->getColor()->getRgb()); self::assertSame('000000', $sheet->getCell('C2')->getStyle()->getFill()->getStartColor()->getRgb()); diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/RgbTintTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/RgbTintTest.php new file mode 100644 index 000000000..96e2003bc --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/RgbTintTest.php @@ -0,0 +1,50 @@ + $maxDiff) { + return $style; + } + if (abs($styleGreen - $textGreen) > $maxDiff) { + return $style; + } + if (abs($styleBlue - $textBlue) > $maxDiff) { + return $style; + } + + return $text; + } + + public function testRgbTint(): void + { + $filename = 'tests/data/Reader/XLSX/RgbTint.xlsx'; + $reader = IOFactory::createReader('Xlsx'); + $spreadsheet = $reader->load($filename); + $sheet = $spreadsheet->getActiveSheet(); + $row = 0; + while (true) { + ++$row; + $text = (string) $sheet->getCell("B$row"); + if ($text === '') { + break; + } + $style = $sheet->getStyle("A$row")->getFill()->getStartColor()->getRgb(); + self::assertSame($text, self::compareColors($style, $text), "row $row"); + } + $spreadsheet->disconnectWorksheets(); + } +} diff --git a/tests/data/Reader/XLSX/RgbTint.xlsx b/tests/data/Reader/XLSX/RgbTint.xlsx new file mode 100644 index 000000000..0ef26da69 Binary files /dev/null and b/tests/data/Reader/XLSX/RgbTint.xlsx differ diff --git a/tests/data/Style/Color/ColorChangeBrightness.php b/tests/data/Style/Color/ColorChangeBrightness.php index 8ddf188da..1c552e157 100644 --- a/tests/data/Style/Color/ColorChangeBrightness.php +++ b/tests/data/Style/Color/ColorChangeBrightness.php @@ -9,7 +9,7 @@ return [ ], // RGBA [ - 'FF99A8B7', + 'FF92A8BE', 'FFAABBCC', -0.1, ], @@ -20,17 +20,17 @@ return [ 0.1, ], [ - '99A8B7', + '92A8BE', 'AABBCC', -0.1, ], [ - 'FF1919', + 'FF1A1A', 'FF0000', 0.1, ], [ - 'E50000', + 'E60000', 'FF0000', -0.1, ], @@ -40,7 +40,7 @@ return [ 0.1, ], [ - 'E57373', + 'FF5959', 'FF8080', -0.1, ], @@ -50,7 +50,7 @@ return [ 0.15, ], [ - 'D80000', + 'D90000', 'FF0000', -0.15, ], @@ -60,18 +60,23 @@ return [ 0.15, ], [ - 'D86C6C', + 'FF4646', 'FF8080', -0.15, ], [ - 'FFF783', + 'FFF984', 'FFF008', 0.5, ], [ - '7F7804', + '847D00', 'FFF008', -0.5, ], + 'issue 3550' => [ + '558ED5', + '1F497D', + 0.39997558519241921, + ], ];