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 | |
22 | namespace app { |
23 | |
24 | gfx::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 | |
32 | gfx::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 | |
40 | gfx::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 | |
86 | doc::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 | |
111 | doc::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 | |
136 | doc::color_t color_utils::color_for_layer(const app::Color& color, Layer* layer) |
137 | { |
138 | return color_for_target(color, ColorTarget(layer)); |
139 | } |
140 | |
141 | doc::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) |
184 | doc::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 | |