Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
 
3
namespace PhpOffice\PhpSpreadsheet\Style;
4
 
5
/**
6
 * Class to handle tint applied to color.
7
 * Code borrows heavily from some Python projects.
8
 *
9
 * @see https://docs.python.org/3/library/colorsys.html
10
 * @see https://gist.github.com/Mike-Honey/b36e651e9a7f1d2e1d60ce1c63b9b633
11
 */
12
class RgbTint
13
{
14
    private const ONE_THIRD = 1.0 / 3.0;
15
    private const ONE_SIXTH = 1.0 / 6.0;
16
    private const TWO_THIRD = 2.0 / 3.0;
17
    private const RGBMAX = 255.0;
18
    /**
19
     * MS excel's tint function expects that HLS is base 240.
20
     *
21
     * @see https://social.msdn.microsoft.com/Forums/en-US/e9d8c136-6d62-4098-9b1b-dac786149f43/excel-color-tint-algorithm-incorrect?forum=os_binaryfile#d3c2ac95-52e0-476b-86f1-e2a697f24969
22
     */
23
    private const HLSMAX = 240.0;
24
 
25
    /**
26
     * Convert red/green/blue to hue/luminance/saturation.
27
     *
28
     * @param float $red 0.0 through 1.0
29
     * @param float $green 0.0 through 1.0
30
     * @param float $blue 0.0 through 1.0
31
     *
32
     * @return float[]
33
     */
34
    private static function rgbToHls(float $red, float $green, float $blue): array
35
    {
36
        $maxc = max($red, $green, $blue);
37
        $minc = min($red, $green, $blue);
38
        $luminance = ($minc + $maxc) / 2.0;
39
        if ($minc === $maxc) {
40
            return [0.0, $luminance, 0.0];
41
        }
42
        $maxMinusMin = $maxc - $minc;
43
        if ($luminance <= 0.5) {
44
            $s = $maxMinusMin / ($maxc + $minc);
45
        } else {
46
            $s = $maxMinusMin / (2.0 - $maxc - $minc);
47
        }
48
        $rc = ($maxc - $red) / $maxMinusMin;
49
        $gc = ($maxc - $green) / $maxMinusMin;
50
        $bc = ($maxc - $blue) / $maxMinusMin;
51
        if ($red === $maxc) {
52
            $h = $bc - $gc;
53
        } elseif ($green === $maxc) {
54
            $h = 2.0 + $rc - $bc;
55
        } else {
56
            $h = 4.0 + $gc - $rc;
57
        }
58
        $h = self::positiveDecimalPart($h / 6.0);
59
 
60
        return [$h, $luminance, $s];
61
    }
62
 
63
    /**
64
     * Convert hue/luminance/saturation to red/green/blue.
65
     *
66
     * @param float $hue 0.0 through 1.0
67
     * @param float $luminance 0.0 through 1.0
68
     * @param float $saturation 0.0 through 1.0
69
     *
70
     * @return float[]
71
     */
72
    private static function hlsToRgb(float $hue, float $luminance, float $saturation): array
73
    {
74
        if ($saturation === 0.0) {
75
            return [$luminance, $luminance, $luminance];
76
        }
77
        if ($luminance <= 0.5) {
78
            $m2 = $luminance * (1.0 + $saturation);
79
        } else {
80
            $m2 = $luminance + $saturation - ($luminance * $saturation);
81
        }
82
        $m1 = 2.0 * $luminance - $m2;
83
 
84
        return [
85
            self::vFunction($m1, $m2, $hue + self::ONE_THIRD),
86
            self::vFunction($m1, $m2, $hue),
87
            self::vFunction($m1, $m2, $hue - self::ONE_THIRD),
88
        ];
89
    }
90
 
91
    private static function vFunction(float $m1, float $m2, float $hue): float
92
    {
93
        $hue = self::positiveDecimalPart($hue);
94
        if ($hue < self::ONE_SIXTH) {
95
            return $m1 + ($m2 - $m1) * $hue * 6.0;
96
        }
97
        if ($hue < 0.5) {
98
            return $m2;
99
        }
100
        if ($hue < self::TWO_THIRD) {
101
            return $m1 + ($m2 - $m1) * (self::TWO_THIRD - $hue) * 6.0;
102
        }
103
 
104
        return $m1;
105
    }
106
 
107
    private static function positiveDecimalPart(float $hue): float
108
    {
109
        $hue = fmod($hue, 1.0);
110
 
111
        return ($hue >= 0.0) ? $hue : (1.0 + $hue);
112
    }
113
 
114
    /**
115
     * Convert red/green/blue to HLSMAX-based hue/luminance/saturation.
116
     *
117
     * @return int[]
118
     */
119
    private static function rgbToMsHls(int $red, int $green, int $blue): array
120
    {
121
        $red01 = $red / self::RGBMAX;
122
        $green01 = $green / self::RGBMAX;
123
        $blue01 = $blue / self::RGBMAX;
124
        [$hue, $luminance, $saturation] = self::rgbToHls($red01, $green01, $blue01);
125
 
126
        return [
127
            (int) round($hue * self::HLSMAX),
128
            (int) round($luminance * self::HLSMAX),
129
            (int) round($saturation * self::HLSMAX),
130
        ];
131
    }
132
 
133
    /**
134
     * Converts HLSMAX based HLS values to rgb values in the range (0,1).
135
     *
136
     * @return float[]
137
     */
138
    private static function msHlsToRgb(int $hue, int $lightness, int $saturation): array
139
    {
140
        return self::hlsToRgb($hue / self::HLSMAX, $lightness / self::HLSMAX, $saturation / self::HLSMAX);
141
    }
142
 
143
    /**
144
     * Tints HLSMAX based luminance.
145
     *
146
     * @see http://ciintelligence.blogspot.co.uk/2012/02/converting-excel-theme-color-and-tint.html
147
     */
148
    private static function tintLuminance(float $tint, float $luminance): int
149
    {
150
        if ($tint < 0) {
151
            return (int) round($luminance * (1.0 + $tint));
152
        }
153
 
154
        return (int) round($luminance * (1.0 - $tint) + (self::HLSMAX - self::HLSMAX * (1.0 - $tint)));
155
    }
156
 
157
    /**
158
     * Return result of tinting supplied rgb as 6 hex digits.
159
     */
160
    public static function rgbAndTintToRgb(int $red, int $green, int $blue, float $tint): string
161
    {
162
        [$hue, $luminance, $saturation] = self::rgbToMsHls($red, $green, $blue);
163
        [$red, $green, $blue] = self::msHlsToRgb($hue, self::tintLuminance($tint, $luminance), $saturation);
164
 
165
        return sprintf(
166
            '%02X%02X%02X',
167
            (int) round($red * self::RGBMAX),
168
            (int) round($green * self::RGBMAX),
169
            (int) round($blue * self::RGBMAX)
170
        );
171
    }
172
}