1// Aseprite
2// Copyright (C) 2020 Igara Studio S.A.
3// Copyright (C) 2001-2017 David Capello
4//
5// This program is distributed under the terms of
6// the End-User License Agreement for Aseprite.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "app/color.h"
13#include "app/color_utils.h"
14#include "app/modules/palettes.h"
15#include "gfx/hsv.h"
16#include "gfx/rgb.h"
17#include "doc/image.h"
18#include "doc/layer.h"
19#include "doc/palette.h"
20#include "doc/sprite.h"
21
22namespace app {
23
24gfx::Color color_utils::blackandwhite(gfx::Color color)
25{
26 if ((gfx::getr(color)*30+gfx::getg(color)*59+gfx::getb(color)*11)/100 < 128)
27 return gfx::rgba(0, 0, 0);
28 else
29 return gfx::rgba(255, 255, 255);
30}
31
32gfx::Color color_utils::blackandwhite_neg(gfx::Color color)
33{
34 if ((gfx::getr(color)*30+gfx::getg(color)*59+gfx::getb(color)*11)/100 < 128)
35 return gfx::rgba(255, 255, 255);
36 else
37 return gfx::rgba(0, 0, 0);
38}
39
40gfx::Color color_utils::color_for_ui(const app::Color& color)
41{
42 gfx::Color c = gfx::ColorNone;
43
44 switch (color.getType()) {
45
46 case app::Color::MaskType:
47 c = gfx::ColorNone;
48 break;
49
50 case app::Color::RgbType:
51 case app::Color::HsvType:
52 case app::Color::HslType:
53 c = gfx::rgba(
54 color.getRed(),
55 color.getGreen(),
56 color.getBlue(),
57 color.getAlpha());
58 break;
59
60 case app::Color::GrayType:
61 c = gfx::rgba(
62 color.getGray(),
63 color.getGray(),
64 color.getGray(),
65 color.getAlpha());
66 break;
67
68 case app::Color::IndexType: {
69 int i = color.getIndex();
70 ASSERT(i >= 0 && i < (int)get_current_palette()->size());
71
72 uint32_t _c = get_current_palette()->getEntry(i);
73 c = gfx::rgba(
74 rgba_getr(_c),
75 rgba_getg(_c),
76 rgba_getb(_c),
77 color.getAlpha());
78 break;
79 }
80
81 }
82
83 return c;
84}
85
86doc::color_t color_utils::color_for_image(const app::Color& color, PixelFormat format)
87{
88 if (color.getType() == app::Color::MaskType)
89 return 0;
90
91 doc::color_t c = -1;
92
93 switch (format) {
94 case IMAGE_RGB:
95 c = doc::rgba(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
96 break;
97 case IMAGE_GRAYSCALE:
98 c = doc::graya(color.getGray(), color.getAlpha());
99 break;
100 case IMAGE_INDEXED:
101 c = color.getIndex();
102 break;
103 case IMAGE_TILEMAP:
104 c = color.getIndex(); // TODO Add app::Color::getTile() ?
105 break;
106 }
107
108 return c;
109}
110
111doc::color_t color_utils::color_for_image_without_alpha(const app::Color& color, PixelFormat format)
112{
113 if (color.getType() == app::Color::MaskType)
114 return 0;
115
116 doc::color_t c = -1;
117
118 switch (format) {
119 case IMAGE_RGB:
120 c = doc::rgba(color.getRed(), color.getGreen(), color.getBlue(), 255);
121 break;
122 case IMAGE_GRAYSCALE:
123 c = doc::graya(color.getGray(), 255);
124 break;
125 case IMAGE_INDEXED:
126 c = color.getIndex();
127 break;
128 case IMAGE_TILEMAP:
129 c = color.getIndex(); // TODO Add app::Color::getTile() ?
130 break;
131 }
132
133 return c;
134}
135
136doc::color_t color_utils::color_for_layer(const app::Color& color, Layer* layer)
137{
138 return color_for_target(color, ColorTarget(layer));
139}
140
141doc::color_t color_utils::color_for_target_mask(const app::Color& color, const ColorTarget& colorTarget)
142{
143 int c = -1;
144
145 if (color.getType() == app::Color::MaskType) {
146 c = colorTarget.maskColor();
147 }
148 else {
149 switch (colorTarget.pixelFormat()) {
150 case IMAGE_RGB:
151 c = doc::rgba(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
152 break;
153 case IMAGE_GRAYSCALE:
154 c = doc::graya(color.getGray(), color.getAlpha());
155 break;
156 case IMAGE_INDEXED:
157 if (color.getType() == app::Color::IndexType) {
158 c = color.getIndex();
159 }
160 else {
161 int r = color.getRed();
162 int g = color.getGreen();
163 int b = color.getBlue();
164 int a = color.getAlpha();
165 int mask = (colorTarget.isTransparent() ?
166 colorTarget.maskColor(): // Don't return the mask color
167 -1);
168
169 c = get_current_palette()->findExactMatch(r, g, b, a, mask);
170 if (c < 0)
171 c = get_current_palette()->findBestfit(r, g, b, a, mask);
172 }
173 break;
174 case IMAGE_TILEMAP:
175 c = color.getIndex(); // TODO Add app::Color::getTile() ?
176 break;
177 }
178 }
179
180 return (doc::color_t)c;
181}
182
183// TODO remove this function using a special RGB background layer (24bpp or 32bpp ignoring alpha)
184doc::color_t color_utils::color_for_target(const app::Color& color, const ColorTarget& colorTarget)
185{
186 doc::color_t c = color_utils::color_for_target_mask(color, colorTarget);
187
188 if (colorTarget.isBackground()) {
189 switch (colorTarget.pixelFormat()) {
190 case IMAGE_RGB: c |= doc::rgba_a_mask; break;
191 case IMAGE_GRAYSCALE: c |= doc::graya_a_mask; break;
192 }
193 }
194
195 return c;
196}
197
198} // namespace app
199