Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
    /** @var mixed */
64
    private static $scrutinizerZeroPointZero = 0.0;
65
 
66
    /**
67
     * Convert hue/luminance/saturation to red/green/blue.
68
     *
69
     * @param float $hue 0.0 through 1.0
70
     * @param float $luminance 0.0 through 1.0
71
     * @param float $saturation 0.0 through 1.0
72
     *
73
     * @return float[]
74
     */
75
    private static function hlsToRgb($hue, $luminance, $saturation): array
76
    {
77
        if ($saturation === self::$scrutinizerZeroPointZero) {
78
            return [$luminance, $luminance, $luminance];
79
        }
80
        if ($luminance <= 0.5) {
81
            $m2 = $luminance * (1.0 + $saturation);
82
        } else {
83
            $m2 = $luminance + $saturation - ($luminance * $saturation);
84
        }
85
        $m1 = 2.0 * $luminance - $m2;
86
 
87
        return [
88
            self::vFunction($m1, $m2, $hue + self::ONE_THIRD),
89
            self::vFunction($m1, $m2, $hue),
90
            self::vFunction($m1, $m2, $hue - self::ONE_THIRD),
91
        ];
92
    }
93
 
94
    private static function vFunction(float $m1, float $m2, float $hue): float
95
    {
96
        $hue = self::positiveDecimalPart($hue);
97
        if ($hue < self::ONE_SIXTH) {
98
            return $m1 + ($m2 - $m1) * $hue * 6.0;
99
        }
100
        if ($hue < 0.5) {
101
            return $m2;
102
        }
103
        if ($hue < self::TWO_THIRD) {
104
            return $m1 + ($m2 - $m1) * (self::TWO_THIRD - $hue) * 6.0;
105
        }
106
 
107
        return $m1;
108
    }
109
 
110
    private static function positiveDecimalPart(float $hue): float
111
    {
112
        $hue = fmod($hue, 1.0);
113
 
114
        return ($hue >= 0.0) ? $hue : (1.0 + $hue);
115
    }
116
 
117
    /**
118
     * Convert red/green/blue to HLSMAX-based hue/luminance/saturation.
119
     *
120
     * @return int[]
121
     */
122
    private static function rgbToMsHls(int $red, int $green, int $blue): array
123
    {
124
        $red01 = $red / self::RGBMAX;
125
        $green01 = $green / self::RGBMAX;
126
        $blue01 = $blue / self::RGBMAX;
127
        [$hue, $luminance, $saturation] = self::rgbToHls($red01, $green01, $blue01);
128
 
129
        return [
130
            (int) round($hue * self::HLSMAX),
131
            (int) round($luminance * self::HLSMAX),
132
            (int) round($saturation * self::HLSMAX),
133
        ];
134
    }
135
 
136
    /**
137
     * Converts HLSMAX based HLS values to rgb values in the range (0,1).
138
     *
139
     * @return float[]
140
     */
141
    private static function msHlsToRgb(int $hue, int $lightness, int $saturation): array
142
    {
143
        return self::hlsToRgb($hue / self::HLSMAX, $lightness / self::HLSMAX, $saturation / self::HLSMAX);
144
    }
145
 
146
    /**
147
     * Tints HLSMAX based luminance.
148
     *
149
     * @see http://ciintelligence.blogspot.co.uk/2012/02/converting-excel-theme-color-and-tint.html
150
     */
151
    private static function tintLuminance(float $tint, float $luminance): int
152
    {
153
        if ($tint < 0) {
154
            return (int) round($luminance * (1.0 + $tint));
155
        }
156
 
157
        return (int) round($luminance * (1.0 - $tint) + (self::HLSMAX - self::HLSMAX * (1.0 - $tint)));
158
    }
159
 
160
    /**
161
     * Return result of tinting supplied rgb as 6 hex digits.
162
     */
163
    public static function rgbAndTintToRgb(int $red, int $green, int $blue, float $tint): string
164
    {
165
        [$hue, $luminance, $saturation] = self::rgbToMsHls($red, $green, $blue);
166
        [$red, $green, $blue] = self::msHlsToRgb($hue, self::tintLuminance($tint, $luminance), $saturation);
167
 
168
        return sprintf(
169
            '%02X%02X%02X',
170
            (int) round($red * self::RGBMAX),
171
            (int) round($green * self::RGBMAX),
172
            (int) round($blue * self::RGBMAX)
173
        );
174
    }
175
}