1 // Aseprite
2 // Copyright (C) 2001-2018  David Capello
3 //
4 // This program is distributed under the terms of
5 // the End-User License Agreement for Aseprite.
6 
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10 
11 #include "app/color.h"
12 
13 #include "app/color_utils.h"
14 #include "app/modules/palettes.h"
15 #include "doc/image.h"
16 #include "doc/palette.h"
17 #include "doc/primitives.h"
18 #include "gfx/hsl.h"
19 #include "gfx/hsv.h"
20 #include "gfx/rgb.h"
21 
22 #include <cmath>
23 #include <cstdlib>
24 #include <iomanip>
25 #include <sstream>
26 #include <string>
27 
28 namespace app {
29 
30 using namespace gfx;
31 
32 // static
fromMask()33 Color Color::fromMask()
34 {
35   return Color(Color::MaskType);
36 }
37 
38 // static
fromRgb(int r,int g,int b,int a)39 Color Color::fromRgb(int r, int g, int b, int a)
40 {
41   Color color(Color::RgbType);
42   color.m_value.rgb.r = r;
43   color.m_value.rgb.g = g;
44   color.m_value.rgb.b = b;
45   color.m_value.rgb.a = a;
46   return color;
47 }
48 
49 // static
fromHsv(double h,double s,double v,int a)50 Color Color::fromHsv(double h, double s, double v, int a)
51 {
52   Color color(Color::HsvType);
53   color.m_value.hsv.h = h;
54   color.m_value.hsv.s = s;
55   color.m_value.hsv.v = v;
56   color.m_value.hsv.a = a;
57   return color;
58 }
59 
60 // static
fromHsl(double h,double s,double l,int a)61 Color Color::fromHsl(double h, double s, double l, int a)
62 {
63   Color color(Color::HslType);
64   color.m_value.hsl.h = h;
65   color.m_value.hsl.s = s;
66   color.m_value.hsl.l = l;
67   color.m_value.hsl.a = a;
68   return color;
69 }
70 
71 // static
fromGray(int g,int a)72 Color Color::fromGray(int g, int a)
73 {
74   Color color(Color::GrayType);
75   color.m_value.gray.g = g;
76   color.m_value.gray.a = a;
77   return color;
78 }
79 
80 // static
fromIndex(int index)81 Color Color::fromIndex(int index)
82 {
83   assert(index >= 0);
84 
85   Color color(Color::IndexType);
86   color.m_value.index = index;
87   return color;
88 }
89 
90 // static
fromImage(PixelFormat pixelFormat,color_t c)91 Color Color::fromImage(PixelFormat pixelFormat, color_t c)
92 {
93   Color color = app::Color::fromMask();
94 
95   switch (pixelFormat) {
96 
97     case IMAGE_RGB:
98       if (rgba_geta(c) > 0) {
99         color = Color::fromRgb(rgba_getr(c),
100                                rgba_getg(c),
101                                rgba_getb(c),
102                                rgba_geta(c));
103       }
104       break;
105 
106     case IMAGE_GRAYSCALE:
107       if (graya_geta(c) > 0) {
108         color = Color::fromGray(graya_getv(c),
109                                 graya_geta(c));
110       }
111       break;
112 
113     case IMAGE_INDEXED:
114       color = Color::fromIndex(c);
115       break;
116   }
117 
118   return color;
119 }
120 
121 // static
fromImageGetPixel(Image * image,int x,int y)122 Color Color::fromImageGetPixel(Image *image, int x, int y)
123 {
124   if ((x >= 0) && (y >= 0) && (x < image->width()) && (y < image->height()))
125     return Color::fromImage(image->pixelFormat(), doc::get_pixel(image, x, y));
126   else
127     return Color::fromMask();
128 }
129 
130 // static
fromString(const std::string & str)131 Color Color::fromString(const std::string& str)
132 {
133   Color color = app::Color::fromMask();
134 
135   if (str != "mask") {
136     if (str.find("rgb{") == 0 ||
137         str.find("hsv{") == 0 ||
138         str.find("hsl{") == 0 ||
139         str.find("gray{") == 0) {
140       int c = 0;
141       double table[4] = { 0.0, 0.0, 0.0, 255.0 };
142       std::string::size_type i = str.find_first_of('{')+1, j;
143 
144       while ((j = str.find_first_of(",}", i)) != std::string::npos) {
145         std::string element = str.substr(i, j - i);
146         if (c < 4)
147           table[c++] = std::strtod(element.c_str(), NULL);
148         if (c >= 4)
149           break;
150         i = j+1;
151       }
152 
153       if (str[0] == 'r')
154         color = Color::fromRgb(int(table[0]), int(table[1]), int(table[2]), int(table[3]));
155       else if (str[0] == 'h' && str[1] == 's' && str[2] == 'v')
156         color = Color::fromHsv(table[0],
157                                table[1] / 100.0,
158                                table[2] / 100.0,
159                                int(table[3]));
160       else if (str[0] == 'h' && str[1] == 's' && str[2] == 'l')
161         color = Color::fromHsl(table[0],
162                                table[1] / 100.0,
163                                table[2] / 100.0,
164                                int(table[3]));
165       else if (str[0] == 'g')
166         color = Color::fromGray(int(table[0]), (c >= 2 ? int(table[1]): 255));
167     }
168     else if (str.find("index{") == 0) {
169       color = Color::fromIndex(std::strtol(str.c_str()+6, NULL, 10));
170     }
171   }
172 
173   return color;
174 }
175 
toRgb() const176 Color Color::toRgb() const
177 {
178   return Color::fromRgb(getRed(), getGreen(), getBlue(), getAlpha());
179 }
180 
toString() const181 std::string Color::toString() const
182 {
183   std::stringstream result;
184 
185   switch (getType()) {
186 
187     case Color::MaskType:
188       result << "mask";
189       break;
190 
191     case Color::RgbType:
192       result << "rgb{"
193              << m_value.rgb.r << ","
194              << m_value.rgb.g << ","
195              << m_value.rgb.b << ","
196              << m_value.rgb.a << "}";
197       break;
198 
199     case Color::HsvType:
200       result << "hsv{"
201              << std::setprecision(2)
202              << std::fixed
203              << m_value.hsv.h << ","
204              << MID(0.0, m_value.hsv.s*100.0, 100.0) << ","
205              << MID(0.0, m_value.hsv.v*100.0, 100.0) << ","
206              << m_value.hsv.a << "}";
207       break;
208 
209     case Color::HslType:
210       result << "hsl{"
211              << std::setprecision(2)
212              << std::fixed
213              << m_value.hsl.h << ","
214              << MID(0.0, m_value.hsl.s*100.0, 100.0) << ","
215              << MID(0.0, m_value.hsl.l*100.0, 100.0) << ","
216              << m_value.hsl.a << "}";
217       break;
218 
219     case Color::GrayType:
220       result << "gray{"
221              << m_value.gray.g << ","
222              << m_value.gray.a << "}";
223       break;
224 
225     case Color::IndexType:
226       result << "index{" << m_value.index << "}";
227       break;
228 
229   }
230 
231   return result.str();
232 }
233 
toHumanReadableString(PixelFormat pixelFormat,HumanReadableString humanReadable) const234 std::string Color::toHumanReadableString(PixelFormat pixelFormat, HumanReadableString humanReadable) const
235 {
236   std::stringstream result;
237 
238   if (humanReadable == LongHumanReadableString) {
239     switch (getType()) {
240 
241       case Color::MaskType:
242         result << "Mask";
243         break;
244 
245       case Color::RgbType:
246         if (pixelFormat == IMAGE_GRAYSCALE) {
247           result << "Gray " << getGray();
248         }
249         else {
250           result << "RGB "
251                  << m_value.rgb.r << " "
252                  << m_value.rgb.g << " "
253                  << m_value.rgb.b;
254 
255           if (pixelFormat == IMAGE_INDEXED)
256             result << " Index "
257                    << color_utils::color_for_image(*this, pixelFormat);
258         }
259         break;
260 
261       case Color::HsvType:
262         if (pixelFormat == IMAGE_GRAYSCALE) {
263           result << "Gray " << getGray();
264         }
265         else {
266           result << "HSV "
267                  << int(m_value.hsv.h) << "\xc2\xb0 "
268                  << MID(0, int(m_value.hsv.s*100.0), 100) << "% "
269                  << MID(0, int(m_value.hsv.v*100.0), 100) << "%";
270 
271           if (pixelFormat == IMAGE_INDEXED)
272             result << " Index " << color_utils::color_for_image(*this, pixelFormat);
273 
274           result << " (RGB "
275                  << getRed() << " "
276                  << getGreen() << " "
277                  << getBlue() << ")";
278         }
279         break;
280 
281       case Color::HslType:
282         if (pixelFormat == IMAGE_GRAYSCALE) {
283           result << "Gray " << getGray();
284         }
285         else {
286           result << "HSL "
287                  << int(m_value.hsl.h) << "\xc2\xb0 "
288                  << MID(0, int(m_value.hsl.s*100.0), 100) << "% "
289                  << MID(0, int(m_value.hsl.l*100.0), 100) << "%";
290 
291           if (pixelFormat == IMAGE_INDEXED)
292             result << " Index " << color_utils::color_for_image(*this, pixelFormat);
293 
294           result << " (RGB "
295                  << getRed() << " "
296                  << getGreen() << " "
297                  << getBlue() << ")";
298         }
299         break;
300 
301       case Color::GrayType:
302         result << "Gray " << m_value.gray.g;
303         break;
304 
305       case Color::IndexType: {
306         int i = m_value.index;
307         if (i >= 0 && i < (int)get_current_palette()->size()) {
308           uint32_t _c = get_current_palette()->getEntry(i);
309           result << "Index " << i
310                  << " (RGB "
311                  << (int)rgba_getr(_c) << " "
312                  << (int)rgba_getg(_c) << " "
313                  << (int)rgba_getb(_c) << ")";
314         }
315         else {
316           result << "Index "
317                  << i
318                  << " (out of range)";
319         }
320         break;
321       }
322 
323       default:
324         ASSERT(false);
325         break;
326     }
327 
328     result << " #" << std::hex << std::setfill('0')
329            << std::setw(2) << getRed()
330            << std::setw(2) << getGreen()
331            << std::setw(2) << getBlue();
332   }
333   else if (humanReadable == ShortHumanReadableString) {
334     switch (getType()) {
335 
336       case Color::MaskType:
337         result << "Mask";
338         break;
339 
340       case Color::RgbType:
341         if (pixelFormat == IMAGE_GRAYSCALE) {
342           result << "Gry-" << getGray();
343         }
344         else {
345           result << "#" << std::hex << std::setfill('0')
346                  << std::setw(2) << m_value.rgb.r
347                  << std::setw(2) << m_value.rgb.g
348                  << std::setw(2) << m_value.rgb.b;
349         }
350         break;
351 
352       case Color::HsvType:
353         if (pixelFormat == IMAGE_GRAYSCALE) {
354           result << "Gry-" << getGray();
355         }
356         else {
357           result << int(m_value.hsv.h) << "\xc2\xb0"
358                  << MID(0, int(m_value.hsv.s*100.0), 100) << ","
359                  << MID(0, int(m_value.hsv.v*100.0), 100);
360         }
361         break;
362 
363       case Color::HslType:
364         if (pixelFormat == IMAGE_GRAYSCALE) {
365           result << "Gry-" << getGray();
366         }
367         else {
368           result << int(m_value.hsl.h) << "\xc2\xb0"
369                  << MID(0, int(m_value.hsl.s*100.0), 100) << ","
370                  << MID(0, int(m_value.hsl.l*100.0), 100);
371         }
372         break;
373 
374       case Color::GrayType:
375         result << "Gry-" << m_value.gray.g;
376         break;
377 
378       case Color::IndexType:
379         result << "Idx-" << m_value.index;
380         break;
381 
382       default:
383         ASSERT(false);
384         break;
385     }
386   }
387 
388   return result.str();
389 }
390 
operator ==(const Color & other) const391 bool Color::operator==(const Color& other) const
392 {
393   if (getType() != other.getType())
394     return false;
395 
396   switch (getType()) {
397 
398     case Color::MaskType:
399       return true;
400 
401     case Color::RgbType:
402       return
403         m_value.rgb.r == other.m_value.rgb.r &&
404         m_value.rgb.g == other.m_value.rgb.g &&
405         m_value.rgb.b == other.m_value.rgb.b &&
406         m_value.rgb.a == other.m_value.rgb.a;
407 
408     case Color::HsvType:
409       return
410         (std::fabs(m_value.hsv.h - other.m_value.hsv.h) < 0.001) &&
411         (std::fabs(m_value.hsv.s - other.m_value.hsv.s) < 0.00001) &&
412         (std::fabs(m_value.hsv.v - other.m_value.hsv.v) < 0.00001) &&
413         (m_value.hsv.a == other.m_value.hsv.a);
414 
415     case Color::HslType:
416       return
417         (std::fabs(m_value.hsl.h - other.m_value.hsl.h) < 0.001) &&
418         (std::fabs(m_value.hsl.s - other.m_value.hsl.s) < 0.00001) &&
419         (std::fabs(m_value.hsl.l - other.m_value.hsl.l) < 0.00001) &&
420         (m_value.hsl.a == other.m_value.hsl.a);
421 
422     case Color::GrayType:
423       return
424         m_value.gray.g == other.m_value.gray.g &&
425         m_value.gray.a == other.m_value.gray.a;
426 
427     case Color::IndexType:
428       return m_value.index == other.m_value.index;
429 
430     default:
431       ASSERT(false);
432       return false;
433   }
434 }
435 
436 // Returns false only if the color is a index and it is outside the
437 // valid range (outside the maximum number of colors in the current
438 // palette)
isValid() const439 bool Color::isValid() const
440 {
441   switch (getType()) {
442 
443     case Color::IndexType: {
444       int i = m_value.index;
445       return (i >= 0 && i < get_current_palette()->size());
446     }
447 
448   }
449   return true;
450 }
451 
getRed() const452 int Color::getRed() const
453 {
454   switch (getType()) {
455 
456     case Color::MaskType:
457       return 0;
458 
459     case Color::RgbType:
460       return m_value.rgb.r;
461 
462     case Color::HsvType:
463       return Rgb(Hsv(m_value.hsv.h,
464                      m_value.hsv.s,
465                      m_value.hsv.v)).red();
466 
467     case Color::HslType:
468       return Rgb(Hsl(m_value.hsl.h,
469                      m_value.hsl.s,
470                      m_value.hsl.l)).red();
471 
472     case Color::GrayType:
473       return m_value.gray.g;
474 
475     case Color::IndexType: {
476       int i = m_value.index;
477       if (i >= 0 && i < get_current_palette()->size())
478         return rgba_getr(get_current_palette()->getEntry(i));
479       else
480         return 0;
481     }
482 
483   }
484 
485   ASSERT(false);
486   return -1;
487 }
488 
getGreen() const489 int Color::getGreen() const
490 {
491   switch (getType()) {
492 
493     case Color::MaskType:
494       return 0;
495 
496     case Color::RgbType:
497       return m_value.rgb.g;
498 
499     case Color::HsvType:
500       return Rgb(Hsv(m_value.hsv.h,
501                      m_value.hsv.s,
502                      m_value.hsv.v)).green();
503 
504     case Color::HslType:
505       return Rgb(Hsl(m_value.hsl.h,
506                      m_value.hsl.s,
507                      m_value.hsl.l)).green();
508 
509     case Color::GrayType:
510       return m_value.gray.g;
511 
512     case Color::IndexType: {
513       int i = m_value.index;
514       if (i >= 0 && i < get_current_palette()->size())
515         return rgba_getg(get_current_palette()->getEntry(i));
516       else
517         return 0;
518     }
519 
520   }
521 
522   ASSERT(false);
523   return -1;
524 }
525 
getBlue() const526 int Color::getBlue() const
527 {
528   switch (getType()) {
529 
530     case Color::MaskType:
531       return 0;
532 
533     case Color::RgbType:
534       return m_value.rgb.b;
535 
536     case Color::HsvType:
537       return Rgb(Hsv(m_value.hsv.h,
538                      m_value.hsv.s,
539                      m_value.hsv.v)).blue();
540 
541     case Color::HslType:
542       return Rgb(Hsl(m_value.hsl.h,
543                      m_value.hsl.s,
544                      m_value.hsl.l)).blue();
545 
546     case Color::GrayType:
547       return m_value.gray.g;
548 
549     case Color::IndexType: {
550       int i = m_value.index;
551       if (i >= 0 && i < get_current_palette()->size())
552         return rgba_getb(get_current_palette()->getEntry(i));
553       else
554         return 0;
555     }
556 
557   }
558 
559   ASSERT(false);
560   return -1;
561 }
562 
getHsvHue() const563 double Color::getHsvHue() const
564 {
565   switch (getType()) {
566 
567     case Color::MaskType:
568       return 0.0;
569 
570     case Color::RgbType:
571       return Hsv(Rgb(m_value.rgb.r,
572                      m_value.rgb.g,
573                      m_value.rgb.b)).hue();
574 
575     case Color::HsvType:
576       return m_value.hsv.h;
577 
578     case Color::HslType:
579       return m_value.hsl.h;
580 
581     case Color::GrayType:
582       return 0.0;
583 
584     case Color::IndexType: {
585       int i = m_value.index;
586       if (i >= 0 && i < get_current_palette()->size()) {
587         uint32_t c = get_current_palette()->getEntry(i);
588         return Hsv(Rgb(rgba_getr(c),
589                        rgba_getg(c),
590                        rgba_getb(c))).hue();
591       }
592       else
593         return 0.0;
594     }
595 
596   }
597 
598   ASSERT(false);
599   return -1.0;
600 }
601 
getHsvSaturation() const602 double Color::getHsvSaturation() const
603 {
604   switch (getType()) {
605 
606     case Color::MaskType:
607       return 0;
608 
609     case Color::RgbType:
610       return Hsv(Rgb(m_value.rgb.r,
611                      m_value.rgb.g,
612                      m_value.rgb.b)).saturation();
613 
614     case Color::HsvType:
615       return m_value.hsv.s;
616 
617     case Color::HslType:
618       return Hsv(Rgb(getRed(),
619                      getGreen(),
620                      getBlue())).saturation();
621 
622     case Color::GrayType:
623       return 0;
624 
625     case Color::IndexType: {
626       int i = m_value.index;
627       if (i >= 0 && i < get_current_palette()->size()) {
628         uint32_t c = get_current_palette()->getEntry(i);
629         return Hsv(Rgb(rgba_getr(c),
630                        rgba_getg(c),
631                        rgba_getb(c))).saturation();
632       }
633       else
634         return 0.0;
635     }
636 
637   }
638 
639   ASSERT(false);
640   return -1.0;
641 }
642 
getHsvValue() const643 double Color::getHsvValue() const
644 {
645   switch (getType()) {
646 
647     case Color::MaskType:
648       return 0.0;
649 
650     case Color::RgbType:
651       return Hsv(Rgb(m_value.rgb.r,
652                      m_value.rgb.g,
653                      m_value.rgb.b)).value();
654 
655     case Color::HsvType:
656       return m_value.hsv.v;
657 
658     case Color::HslType:
659       return Hsv(Rgb(getRed(),
660                      getGreen(),
661                      getBlue())).value();
662 
663     case Color::GrayType:
664       return m_value.gray.g / 255.0;
665 
666     case Color::IndexType: {
667       int i = m_value.index;
668       if (i >= 0 && i < get_current_palette()->size()) {
669         uint32_t c = get_current_palette()->getEntry(i);
670         return Hsv(Rgb(rgba_getr(c),
671                        rgba_getg(c),
672                        rgba_getb(c))).value();
673       }
674       else
675         return 0.0;
676     }
677 
678   }
679 
680   ASSERT(false);
681   return -1.0;
682 }
683 
getHslHue() const684 double Color::getHslHue() const
685 {
686   switch (getType()) {
687 
688     case Color::MaskType:
689       return 0.0;
690 
691     case Color::RgbType:
692       return Hsl(Rgb(m_value.rgb.r,
693                      m_value.rgb.g,
694                      m_value.rgb.b)).hue();
695 
696     case Color::HsvType:
697       return m_value.hsv.h;
698 
699     case Color::HslType:
700       return m_value.hsl.h;
701 
702     case Color::GrayType:
703       return 0.0;
704 
705     case Color::IndexType: {
706       int i = m_value.index;
707       if (i >= 0 && i < get_current_palette()->size()) {
708         uint32_t c = get_current_palette()->getEntry(i);
709         return Hsl(Rgb(rgba_getr(c),
710                        rgba_getg(c),
711                        rgba_getb(c))).hue();
712       }
713       else
714         return 0.0;
715     }
716 
717   }
718 
719   ASSERT(false);
720   return -1.0;
721 }
722 
getHslSaturation() const723 double Color::getHslSaturation() const
724 {
725   switch (getType()) {
726 
727     case Color::MaskType:
728       return 0;
729 
730     case Color::RgbType:
731       return Hsl(Rgb(m_value.rgb.r,
732                      m_value.rgb.g,
733                      m_value.rgb.b)).saturation();
734 
735     case Color::HsvType:
736       return Hsl(Rgb(getRed(),
737                      getGreen(),
738                      getBlue())).saturation();
739 
740     case Color::HslType:
741       return m_value.hsl.s;
742 
743     case Color::GrayType:
744       return 0;
745 
746     case Color::IndexType: {
747       int i = m_value.index;
748       if (i >= 0 && i < get_current_palette()->size()) {
749         uint32_t c = get_current_palette()->getEntry(i);
750         return Hsl(Rgb(rgba_getr(c),
751                        rgba_getg(c),
752                        rgba_getb(c))).saturation();
753       }
754       else
755         return 0.0;
756     }
757 
758   }
759 
760   ASSERT(false);
761   return -1.0;
762 }
763 
getHslLightness() const764 double Color::getHslLightness() const
765 {
766   switch (getType()) {
767 
768     case Color::MaskType:
769       return 0.0;
770 
771     case Color::RgbType:
772       return Hsl(Rgb(m_value.rgb.r,
773                      m_value.rgb.g,
774                      m_value.rgb.b)).lightness();
775 
776     case Color::HsvType:
777       return Hsl(Rgb(getRed(),
778                      getGreen(),
779                      getBlue())).lightness();
780 
781     case Color::HslType:
782       return m_value.hsl.l;
783 
784     case Color::GrayType:
785       return m_value.gray.g / 255.0;
786 
787     case Color::IndexType: {
788       int i = m_value.index;
789       if (i >= 0 && i < get_current_palette()->size()) {
790         uint32_t c = get_current_palette()->getEntry(i);
791         return Hsl(Rgb(rgba_getr(c),
792                        rgba_getg(c),
793                        rgba_getb(c))).lightness();
794       }
795       else
796         return 0.0;
797     }
798 
799   }
800 
801   ASSERT(false);
802   return -1.0;
803 }
804 
getGray() const805 int Color::getGray() const
806 {
807   switch (getType()) {
808 
809     case Color::MaskType:
810       return 0;
811 
812     case Color::RgbType:
813       return int(255.0 * Hsl(Rgb(m_value.rgb.r,
814                                  m_value.rgb.g,
815                                  m_value.rgb.b)).lightness());
816 
817     case Color::HsvType:
818       return int(255.0 * Hsl(Rgb(getRed(),
819                                  getGreen(),
820                                  getBlue())).lightness());
821 
822     case Color::HslType:
823       return int(255.0 * m_value.hsl.l);
824 
825     case Color::GrayType:
826       return m_value.gray.g;
827 
828     case Color::IndexType: {
829       int i = m_value.index;
830       if (i >= 0 && i < get_current_palette()->size()) {
831         uint32_t c = get_current_palette()->getEntry(i);
832         return int(255.0 * Hsl(Rgb(rgba_getr(c),
833                                    rgba_getg(c),
834                                    rgba_getb(c))).lightness());
835       }
836       else
837         return 0;
838     }
839 
840   }
841 
842   ASSERT(false);
843   return -1;
844 }
845 
getIndex() const846 int Color::getIndex() const
847 {
848   switch (getType()) {
849 
850     case Color::MaskType:
851       return 0;
852 
853     case Color::RgbType:
854     case Color::HsvType:
855     case Color::HslType:
856     case Color::GrayType: {
857       int i = get_current_palette()->findExactMatch(getRed(), getGreen(), getBlue(), getAlpha(), -1);
858       if (i >= 0)
859         return i;
860       else
861         return get_current_palette()->findBestfit(getRed(), getGreen(), getBlue(), getAlpha(), 0);
862     }
863 
864     case Color::IndexType:
865       return m_value.index;
866 
867   }
868 
869   ASSERT(false);
870   return -1;
871 }
872 
getAlpha() const873 int Color::getAlpha() const
874 {
875   switch (getType()) {
876 
877     case Color::MaskType:
878       return 0;
879 
880     case Color::RgbType:
881       return m_value.rgb.a;
882 
883     case Color::HsvType:
884       return m_value.hsv.a;
885 
886     case Color::HslType:
887       return m_value.hsl.a;
888 
889     case Color::GrayType:
890       return m_value.gray.a;
891 
892     case Color::IndexType: {
893       int i = m_value.index;
894       if (i >= 0 && i < get_current_palette()->size())
895         return rgba_geta(get_current_palette()->getEntry(i));
896       else
897         return 0;
898     }
899 
900   }
901 
902   ASSERT(false);
903   return -1;
904 }
905 
setAlpha(int alpha)906 void Color::setAlpha(int alpha)
907 {
908   alpha = MID(0, alpha, 255);
909 
910   switch (getType()) {
911 
912     case Color::MaskType:
913       break;
914 
915     case Color::RgbType:
916       m_value.rgb.a = alpha;
917       break;
918 
919     case Color::HsvType:
920       m_value.hsv.a = alpha;
921       break;
922 
923     case Color::HslType:
924       m_value.hsl.a = alpha;
925       break;
926 
927     case Color::GrayType:
928       m_value.gray.a = alpha;
929       break;
930 
931     case Color::IndexType:
932       *this = Color::fromRgb(getRed(),
933                              getGreen(),
934                              getBlue(), alpha);
935       break;
936   }
937 }
938 
939 } // namespace app
940