summaryrefslogtreecommitdiffstats
path: root/include/tools/color.hxx
blob: 0d4990b63eab7d62fdbc7a4fc45eb8612f1bf8a6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */
#ifndef INCLUDED_TOOLS_COLOR_HXX
#define INCLUDED_TOOLS_COLOR_HXX

#include <sal/types.h>
#include <tools/toolsdllapi.h>
#include <com/sun/star/uno/Any.hxx>
#include <config_global.h>
#include <basegfx/color/bcolor.hxx>
#include <osl/endian.h>

namespace color
{

constexpr sal_uInt32 extractRGB(sal_uInt32 nColorNumber)
{
    return nColorNumber & 0x00FFFFFF;
}

constexpr sal_uInt8 ColorChannelMerge(sal_uInt8 nDst, sal_uInt8 nSrc, sal_uInt8 nSrcTrans)
{
    return sal_uInt8(((sal_Int32(nDst) - nSrc) * nSrcTrans + ((nSrc << 8) | nDst)) >> 8);
}

}

/** used to deliberately select the right constructor */
enum ColorTransparencyTag { ColorTransparency = 0 };
enum ColorAlphaTag { ColorAlpha = 0 };

// Color

class SAL_WARN_UNUSED TOOLS_DLLPUBLIC Color
{
    union
    {
        sal_uInt32 mValue;
        struct
        {
#ifdef OSL_BIGENDIAN
                sal_uInt8 T;
                sal_uInt8 R;
                sal_uInt8 G;
                sal_uInt8 B;
#else
                sal_uInt8 B;
                sal_uInt8 G;
                sal_uInt8 R;
                sal_uInt8 T;
#endif
        };
    };

public:
    constexpr Color()
        : mValue(0) // black
    {}

#if HAVE_CPP_CONSTEVAL
    consteval
#else
    constexpr
#endif
    Color(const sal_uInt32 nColor)
        : mValue(nColor)
    {
        assert(nColor <= 0xffffff && "don't pass transparency to this constructor, use the Color(ColorTransparencyTag,...) or Color(ColorAlphaTag,...) constructor to make it explicit");
    }

    constexpr Color(enum ColorTransparencyTag, sal_uInt32 nColor)
        : mValue(nColor)
    {
    }

    constexpr Color(enum ColorAlphaTag, sal_uInt32 nColor)
        : mValue((nColor & 0xffffff) | ((255 - (nColor >> 24)) << 24))
    {
    }

    constexpr Color(enum ColorTransparencyTag, sal_uInt8 nTransparency, sal_uInt8 nRed, sal_uInt8 nGreen, sal_uInt8 nBlue)
        : mValue(sal_uInt32(nBlue) | (sal_uInt32(nGreen) << 8) | (sal_uInt32(nRed) << 16) | (sal_uInt32(nTransparency) << 24))
    {}

    constexpr Color(enum ColorAlphaTag, sal_uInt8 nAlpha, sal_uInt8 nRed, sal_uInt8 nGreen, sal_uInt8 nBlue)
        : Color(ColorTransparency, 255 - nAlpha, nRed, nGreen, nBlue)
    {}

    constexpr Color(sal_uInt8 nRed, sal_uInt8 nGreen, sal_uInt8 nBlue)
        : Color(ColorTransparency, 0, nRed, nGreen, nBlue)
    {}

    // constructor to create a tools-Color from ::basegfx::BColor
    explicit Color(const basegfx::BColor& rBColor)
        : Color(ColorTransparency, 0,
                sal_uInt8(std::lround(rBColor.getRed() * 255.0)),
                sal_uInt8(std::lround(rBColor.getGreen() * 255.0)),
                sal_uInt8(std::lround(rBColor.getBlue() * 255.0)))
    {}

    /** Casts the color to corresponding uInt32.
      * Primarily used when passing Color objects to UNO API
      * @return corresponding sal_uInt32
      */
    constexpr explicit operator sal_uInt32() const
    {
        return mValue;
    }

    /** Casts the color to corresponding iInt32.
      * If there is no transparency, will be positive.
      * @return corresponding sal_Int32
      */
    constexpr explicit operator sal_Int32() const
    {
        return sal_Int32(mValue);
    }

    /* Basic RGBA operations */

    /** Gets the red value.
      * @return R
      */
    sal_uInt8 GetRed() const
    {
        return R;
    }

    /** Gets the green value.
      * @return G
      */
    sal_uInt8 GetGreen() const
    {
        return G;
    }

    /** Gets the blue value.
      * @return B
      */
    sal_uInt8 GetBlue() const
    {
        return B;
    }

    /** Gets the alpha value.
      * @return A
      */
    sal_uInt8 GetAlpha() const
    {
        return 255 - T;
    }

    /** Is the color transparent?
     */
    bool IsTransparent() const
    {
        return GetAlpha() != 255;
    }

    /** Is the color fully transparent i.e. 100% transparency ?
     */
    bool IsFullyTransparent() const
    {
        return T == 255;
    }

    /** Sets the red value.
      * @param nRed
      */
    void SetRed(sal_uInt8 nRed)
    {
        R = nRed;
    }

    /** Sets the green value.
      * @param nGreen
      */
    void SetGreen(sal_uInt8 nGreen)
    {
        G = nGreen;
    }

    /** Sets the blue value.
      * @param nBlue
      */
    void SetBlue(sal_uInt8 nBlue)
    {
        B = nBlue;
    }

    /** Sets the alpha value.
      * @param nAlpha
      */
    void SetAlpha(sal_uInt8 nAlpha)
    {
        T = 255 - nAlpha;
    }

    /** Returns the same color but ignoring the transparency value.
      * @return RGB version
      */
    Color GetRGBColor() const
    {
        return {R, G, B};
    }

    /* Comparison and operators */

    /** Check if the color RGB value is equal than rColor.
      * @param rColor
      * @return is equal
      */
    bool IsRGBEqual( const Color& rColor ) const
    {
        return ( mValue & 0x00FFFFFF ) == ( rColor.mValue & 0x00FFFFFF );
    }

    /** Check if the color value is lower than aCompareColor.
      * @param aCompareColor
      * @return is lower
      */
    bool operator<(const Color& aCompareColor) const
    {
        return mValue < aCompareColor.mValue;
    }

    /** Check if the color value is greater than aCompareColor.
      * @param aCompareColor
      * @return is greater
      */
    bool operator>(const Color& aCompareColor) const
    {
        return mValue > aCompareColor.mValue;
    }

    /** Check if the color value is equal than rColor.
      * @param rColor
      * @return is equal
      */
    bool operator==(const Color& rColor) const
    {
        return mValue == rColor.mValue;
    }

    /** Check if the color value is unequal than rColor.
      * @param rColor
      * @return is unequal
      */
    bool operator!=(const Color& rColor) const
    {
        return mValue != rColor.mValue;
    }

    /** Gets the color error compared to another.
      * It describes how different they are.
      * It takes the abs of differences in parameters.
      * @param rCompareColor
      * @return error
      */
    sal_uInt16 GetColorError(const Color& rCompareColor) const
    {
    return static_cast<sal_uInt16>(
        abs(static_cast<int>(GetBlue()) - rCompareColor.GetBlue()) +
        abs(static_cast<int>(GetGreen()) - rCompareColor.GetGreen()) +
        abs(static_cast<int>(GetRed()) - rCompareColor.GetRed()));
    }

    /* Light and contrast */

    /** Gets the color luminance. It means perceived brightness.
      * @return luminance
      */
    sal_uInt8 GetLuminance() const
    {
        return sal_uInt8((B * 29UL + G * 151UL + R * 76UL) >> 8);
    }

    /** Increases the color luminance by cLumInc.
      * @param cLumInc
      */
    void IncreaseLuminance(sal_uInt8 cLumInc);

    /** Decreases the color luminance by cLumDec.
      * @param cLumDec
      */
    void DecreaseLuminance(sal_uInt8 cLumDec);

    /** Decreases color contrast with white by cContDec.
      * @param cContDec
      */
    void DecreaseContrast(sal_uInt8 cContDec);

    /** Comparison with luminance thresholds.
      * @return is dark
      */
    bool IsDark() const
    {
        // 62 is the number that means it also triggers on Ubuntu in dark mode
        return GetLuminance() <= 62;
    }

    /** Comparison with luminance thresholds.
      * @return is dark
      */
    bool IsBright() const
    {
        return GetLuminance() >= 245;
    }

    /* Color filters */

    /**
     * Apply tint or shade to a color.
     *
     * The input value is the percentage (in 100th of percent) of how much the
     * color changes towards the black (shade) or white (tint). If the value
     * is positive, the color is tinted, if the value is negative, the color is
     * shaded.
     **/
    void ApplyTintOrShade(sal_Int16 n100thPercent);

    /**
     * Apply luminance offset and/or modulation.
     *
     * The input values are in percentages (in 100th percents). 100% modulation and 0% offset
     * results in no change.
     */
    void ApplyLumModOff(sal_Int16 nMod, sal_Int16 nOff);

    /** Inverts color. 1 and 0 are switched.
      * Note that the result will be the complementary color.
      * For example, if you have red, you will get cyan: FF0000 -> 00FFFF.
      */
    void Invert()
    {
        R = ~R;
        G = ~G;
        B = ~B;
    }

    /** Merges color with rMergeColor.
      * Allows to get resulting color when superposing another.
      * @param rMergeColor
      * @param cTransparency
      */
    void Merge(const Color& rMergeColor, sal_uInt8 cTransparency)
    {
        R = color::ColorChannelMerge(R, rMergeColor.R, cTransparency);
        G = color::ColorChannelMerge(G, rMergeColor.G, cTransparency);
        B = color::ColorChannelMerge(B, rMergeColor.B, cTransparency);
    }

    /* Change of format */

    /** Color space conversion tools
      * The range for h/s/b is:
      *   - Hue: 0-360 degree
      *   - Saturation: 0-100%
      *   - Brightness: 0-100%
      * @param nHue
      * @param nSaturation
      * @param nBrightness
      * @return rgb color
      */
    static Color HSBtoRGB(sal_uInt16 nHue, sal_uInt16 nSaturation, sal_uInt16 nBrightness);

    /** Converts a string into a color. Supports:
      * #RRGGBB
      * #rrggbb
      * #RGB
      * #rgb
      * RRGGBB
      * rrggbb
      * RGB
      * rgb
      * If fails returns Color().
      */
    static Color STRtoRGB(std::u16string_view colorname);

    /** Color space conversion tools
      * @param nHue
      * @param nSaturation
      * @param nBrightness
      */
    void RGBtoHSB(sal_uInt16& nHue, sal_uInt16& nSaturation, sal_uInt16& nBrightness) const;

    /* Return color as RGB hex string: rrggbb
     * for example "00ff00" for green color
     * @return hex string
     */
    OUString AsRGBHexString() const;

    /* Return color as RGB hex string: RRGGBB
     * for example "00FF00" for green color
     * @return hex string
     */
    OUString AsRGBHEXString() const;

    /* get ::basegfx::BColor from this color
     * @return basegfx color
     */
    basegfx::BColor getBColor() const
    {
        return basegfx::BColor(R / 255.0, G / 255.0, B / 255.0);
    }
};

// to reduce the noise when moving these into and out of Any
inline bool operator >>=( const css::uno::Any & rAny, Color & value )
{
  sal_Int32 nTmp = {}; // spurious -Werror=maybe-uninitialized
  if (!(rAny >>= nTmp))
      return false;
  value = Color(ColorTransparency, nTmp);
  return true;
}

inline void operator <<=( css::uno::Any & rAny, Color value )
{
    rAny <<= sal_Int32(value);
}

namespace com::sun::star::uno {
    template<> inline Any::Any(Color const & value): Any(sal_Int32(value)) {}
}

// Test compile time conversion of Color to sal_uInt32

static_assert (sal_uInt32(Color(ColorTransparency, 0x00, 0x12, 0x34, 0x56)) == 0x00123456);
static_assert (sal_uInt32(Color(0x12, 0x34, 0x56)) == 0x00123456);

// Color types

constexpr ::Color COL_TRANSPARENT             ( ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF );
constexpr ::Color COL_AUTO                    ( ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF );
constexpr ::Color COL_BLACK                   ( 0x00, 0x00, 0x00 );
constexpr ::Color COL_BLUE                    ( 0x00, 0x00, 0x80 );
constexpr ::Color COL_GREEN                   ( 0x00, 0x80, 0x00 );
constexpr ::Color COL_CYAN                    ( 0x00, 0x80, 0x80 );
constexpr ::Color COL_RED                     ( 0x80, 0x00, 0x00 );
constexpr ::Color COL_MAGENTA                 ( 0x80, 0x00, 0x80 );
constexpr ::Color COL_BROWN                   ( 0x80, 0x80, 0x00 );
constexpr ::Color COL_GRAY                    ( 0x80, 0x80, 0x80 );
constexpr ::Color COL_GRAY3                   ( 0xCC, 0xCC, 0xCC );
constexpr ::Color COL_GRAY7                   ( 0x66, 0x66, 0x66 );
constexpr ::Color COL_LIGHTGRAY               ( 0xC0, 0xC0, 0xC0 );
constexpr ::Color COL_LIGHTBLUE               ( 0x00, 0x00, 0xFF );
constexpr ::Color COL_LIGHTGREEN              ( 0x00, 0xFF, 0x00 );
constexpr ::Color COL_LIGHTCYAN               ( 0x00, 0xFF, 0xFF );
constexpr ::Color COL_LIGHTRED                ( 0xFF, 0x00, 0x00 );
constexpr ::Color COL_LIGHTMAGENTA            ( 0xFF, 0x00, 0xFF );
constexpr ::Color COL_LIGHTGRAYBLUE           ( 0xE0, 0xE0, 0xFF );
constexpr ::Color COL_YELLOW                  ( 0xFF, 0xFF, 0x00 );
constexpr ::Color COL_WHITE                   ( 0xFF, 0xFF, 0xFF );
constexpr ::Color COL_AUTHOR1_DARK            ( 0xC6, 0x92, 0x00 );
constexpr ::Color COL_AUTHOR1_NORMAL          ( 0xFF, 0xFF, 0x9E );
constexpr ::Color COL_AUTHOR1_LIGHT           ( 0xFF, 0xFF, 0xC3 );
constexpr ::Color COL_AUTHOR2_DARK            ( 0x06, 0x46, 0xA2 );
constexpr ::Color COL_AUTHOR2_NORMAL          ( 0xD8, 0xE8, 0xFF );
constexpr ::Color COL_AUTHOR2_LIGHT           ( 0xE9, 0xF2, 0xFF );
constexpr ::Color COL_AUTHOR3_DARK            ( 0x57, 0x9D, 0x1C );
constexpr ::Color COL_AUTHOR3_NORMAL          ( 0xDA, 0xF8, 0xC1 );
constexpr ::Color COL_AUTHOR3_LIGHT           ( 0xE2, 0xFA, 0xCF );
constexpr ::Color COL_AUTHOR4_DARK            ( 0x69, 0x2B, 0x9D );
constexpr ::Color COL_AUTHOR4_NORMAL          ( 0xE4, 0xD2, 0xF5 );
constexpr ::Color COL_AUTHOR4_LIGHT           ( 0xEF, 0xE4, 0xF8 );
constexpr ::Color COL_AUTHOR5_DARK            ( 0xC5, 0x00, 0x0B );
constexpr ::Color COL_AUTHOR5_NORMAL          ( 0xFE, 0xCD, 0xD0 );
constexpr ::Color COL_AUTHOR5_LIGHT           ( 0xFF, 0xE3, 0xE5 );
constexpr ::Color COL_AUTHOR6_DARK            ( 0x00, 0x80, 0x80 );
constexpr ::Color COL_AUTHOR6_NORMAL          ( 0xD2, 0xF6, 0xF6 );
constexpr ::Color COL_AUTHOR6_LIGHT           ( 0xE6, 0xFA, 0xFA );
constexpr ::Color COL_AUTHOR7_DARK            ( 0x8C, 0x84, 0x00 );
constexpr ::Color COL_AUTHOR7_NORMAL          ( 0xED, 0xFC, 0xA3 );
constexpr ::Color COL_AUTHOR7_LIGHT           ( 0xF2, 0xFE, 0xB5 );
constexpr ::Color COL_AUTHOR8_DARK            ( 0x35, 0x55, 0x6B );
constexpr ::Color COL_AUTHOR8_NORMAL          ( 0xD3, 0xDE, 0xE8 );
constexpr ::Color COL_AUTHOR8_LIGHT           ( 0xE2, 0xEA, 0xF1 );
constexpr ::Color COL_AUTHOR9_DARK            ( 0xD1, 0x76, 0x00 );
constexpr ::Color COL_AUTHOR9_NORMAL          ( 0xFF, 0xE2, 0xB9 );
constexpr ::Color COL_AUTHOR9_LIGHT           ( 0xFF, 0xE7, 0xC7 );
constexpr ::Color COL_AUTHOR_TABLE_INS        ( 0xE1, 0xF2, 0xFA );
constexpr ::Color COL_AUTHOR_TABLE_DEL        ( 0xFC, 0xE6, 0xF4 );

template<typename charT, typename traits>
inline std::basic_ostream<charT, traits>& operator <<(std::basic_ostream<charT, traits>& rStream, const Color& rColor)
{
    std::ios_base::fmtflags nOrigFlags = rStream.flags();
    rStream << "rgba[" << std::hex << std::setfill ('0')
            << std::setw(2) << static_cast<int>(rColor.GetRed())
            << std::setw(2) << static_cast<int>(rColor.GetGreen())
            << std::setw(2) << static_cast<int>(rColor.GetBlue())
            << std::setw(2) << static_cast<int>(rColor.GetAlpha()) << "]";
    rStream.setf(nOrigFlags);
    return rStream;
}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */