Skip to content

Commit cdf1449

Browse files
Store alpha preserve of a layer in ORA files
For compatibility with Krita and maybe other applications. In Drawpile, alpha preserve is implicit depending on the blend mode, but e.g. in Krita, it has to be enabled separately. This adds an `alpha-preserve="true"` attribute to layers with affected blend mdoes so that Krita can restore them properly, once the attribute is implemented on their side. Drawpile doesn't read the attribute, since it can't do anything with the information, except for the special case of the Normal blend mode, which becomes Recolor when alpha preserve is enabled. Normally this is saved as a separate blend mode, but since it's a valid way to represent it, we handle it too.
1 parent efad791 commit cdf1449

5 files changed

Lines changed: 49 additions & 20 deletions

File tree

ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Unreleased Version 2.2.0-pre
3838
* Fix: Show own user marker again when using the laser pointer.
3939
* Fix: Use previous avatar when using the reconnect button after a disconnect.
4040
* Fix: Don't trigger a cacophony of notifications after joining a session, just play a single notification once catchup is done instead.
41+
* Feature: Store alpha preserve state of layers in ORA files for better Krita compatibility (will be in Krita 5.2.1 probably.)
4142

4243
2023-09-30 Version 2.2.0-beta.8
4344
* Fix: Apply color wheel direction to color dialogs too. Thanks Blozzom for reporting.

src/drawdance/libengine/dpengine/load.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,17 @@ static DP_TransientLayerProps *ora_make_layer_props(DP_XmlElement *element,
422422
DP_BlendMode blend_mode = DP_blend_mode_by_svg_name(
423423
DP_xml_element_attribute(element, NULL, "composite-op"),
424424
DP_BLEND_MODE_NORMAL);
425+
426+
// Normal with alpha preserve is Recolor. Drawpile doesn't save it this way,
427+
// but it's a valid way to represent it, so we handle it.
428+
if (blend_mode == DP_BLEND_MODE_NORMAL) {
429+
const char *alpha_preserve =
430+
DP_xml_element_attribute(element, NULL, "alpha-preserve");
431+
if (DP_str_equal_lowercase(alpha_preserve, "true")) {
432+
blend_mode = DP_BLEND_MODE_RECOLOR;
433+
}
434+
}
435+
425436
DP_transient_layer_props_blend_mode_set(tlp, (int)blend_mode);
426437

427438
const char *censored =

src/drawdance/libengine/dpengine/save.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,15 @@ static void ora_write_layer_props_xml(DP_SaveOraContext *c, DP_Output *output,
392392
DP_blend_mode_svg_name(blend_mode));
393393
}
394394

395+
// Drawpile doesn't itself need the alpha preserve property, since its alpha
396+
// preserve behavior depends on the blend mode, but other software cares.
397+
// The Recolor blend mode is saved as src-atop, which is alpha-preserving
398+
// per its definition, so it doesn't get the extra attribute.
399+
if (DP_blend_mode_preserves_alpha(blend_mode)
400+
&& blend_mode != DP_BLEND_MODE_RECOLOR) {
401+
DP_OUTPUT_PRINT_LITERAL(output, " alpha-preserve=\"true\"");
402+
}
403+
395404
if (DP_layer_props_censored(lp)) {
396405
DP_OUTPUT_PRINT_LITERAL(output, " drawpile:censored=\"true\"");
397406
}

src/drawdance/libmsg/dpmsg/blend_mode.c

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#define DECREASE_OPACITY (1 << 2)
2929
#define INCREASE_OPACITY (1 << 3)
3030
#define BLEND_BLANK (1 << 4)
31+
#define PRESERVES_ALPHA (1 << 5)
3132

3233
// The Krita name for the linear light blend mode contains a space, which isn't
3334
// supported in draw dabs messages, since they already use the curly brace body
@@ -66,63 +67,63 @@ static const DP_BlendModeAttributes mode_attributes[DP_BLEND_MODE_COUNT] = {
6667
},
6768
[DP_BLEND_MODE_MULTIPLY] =
6869
{
69-
LAYER | BRUSH,
70+
LAYER | BRUSH | PRESERVES_ALPHA,
7071
"DP_BLEND_MODE_MULTIPLY",
7172
"svg:multiply",
7273
"Multiply",
7374
},
7475
[DP_BLEND_MODE_DIVIDE] =
7576
{
76-
LAYER | BRUSH,
77+
LAYER | BRUSH | PRESERVES_ALPHA,
7778
"DP_BLEND_MODE_DIVIDE",
7879
"krita:divide",
7980
"Divide",
8081
},
8182
[DP_BLEND_MODE_BURN] =
8283
{
83-
LAYER | BRUSH,
84+
LAYER | BRUSH | PRESERVES_ALPHA,
8485
"DP_BLEND_MODE_BURN",
8586
"svg:color-burn",
8687
"Burn",
8788
},
8889
[DP_BLEND_MODE_DODGE] =
8990
{
90-
LAYER | BRUSH,
91+
LAYER | BRUSH | PRESERVES_ALPHA,
9192
"DP_BLEND_MODE_DODGE",
9293
"svg:color-dodge",
9394
"Dodge",
9495
},
9596
[DP_BLEND_MODE_DARKEN] =
9697
{
97-
LAYER | BRUSH,
98+
LAYER | BRUSH | PRESERVES_ALPHA,
9899
"DP_BLEND_MODE_DARKEN",
99100
"svg:darken",
100101
"Darken",
101102
},
102103
[DP_BLEND_MODE_LIGHTEN] =
103104
{
104-
LAYER | BRUSH,
105+
LAYER | BRUSH | PRESERVES_ALPHA,
105106
"DP_BLEND_MODE_LIGHTEN",
106107
"svg:lighten",
107108
"Lighten",
108109
},
109110
[DP_BLEND_MODE_SUBTRACT] =
110111
{
111-
LAYER | BRUSH,
112+
LAYER | BRUSH | PRESERVES_ALPHA,
112113
"DP_BLEND_MODE_SUBTRACT",
113114
"krita:subtract",
114115
"Subtract",
115116
},
116117
[DP_BLEND_MODE_ADD] =
117118
{
118-
LAYER | BRUSH,
119+
LAYER | BRUSH | PRESERVES_ALPHA,
119120
"DP_BLEND_MODE_ADD",
120121
"svg:plus",
121122
"Add",
122123
},
123124
[DP_BLEND_MODE_RECOLOR] =
124125
{
125-
LAYER | BRUSH,
126+
LAYER | BRUSH | PRESERVES_ALPHA,
126127
"DP_BLEND_MODE_RECOLOR",
127128
"svg:src-atop",
128129
"Recolor",
@@ -143,7 +144,7 @@ static const DP_BlendModeAttributes mode_attributes[DP_BLEND_MODE_COUNT] = {
143144
},
144145
[DP_BLEND_MODE_SCREEN] =
145146
{
146-
LAYER | BRUSH,
147+
LAYER | BRUSH | PRESERVES_ALPHA,
147148
"DP_BLEND_MODE_SCREEN",
148149
"svg:screen",
149150
"Screen",
@@ -157,70 +158,70 @@ static const DP_BlendModeAttributes mode_attributes[DP_BLEND_MODE_COUNT] = {
157158
},
158159
[DP_BLEND_MODE_LUMINOSITY_SHINE_SAI] =
159160
{
160-
LAYER | BRUSH,
161+
LAYER | BRUSH | PRESERVES_ALPHA,
161162
"DP_BLEND_MODE_LUMINOSITY_SHINE_SAI",
162163
"krita:luminosity_sai",
163164
"Luminosity/Shine (SAI)",
164165
},
165166
[DP_BLEND_MODE_OVERLAY] =
166167
{
167-
LAYER | BRUSH,
168+
LAYER | BRUSH | PRESERVES_ALPHA,
168169
"DP_BLEND_MODE_OVERLAY",
169170
"svg:overlay",
170171
"Overlay",
171172
},
172173
[DP_BLEND_MODE_HARD_LIGHT] =
173174
{
174-
LAYER | BRUSH,
175+
LAYER | BRUSH | PRESERVES_ALPHA,
175176
"DP_BLEND_MODE_HARD_LIGHT",
176177
"svg:hard-light",
177178
"Hard Light",
178179
},
179180
[DP_BLEND_MODE_SOFT_LIGHT] =
180181
{
181-
LAYER | BRUSH,
182+
LAYER | BRUSH | PRESERVES_ALPHA,
182183
"DP_BLEND_MODE_SOFT_LIGHT",
183184
"svg:soft-light",
184185
"Soft Light",
185186
},
186187
[DP_BLEND_MODE_LINEAR_BURN] =
187188
{
188-
LAYER | BRUSH,
189+
LAYER | BRUSH | PRESERVES_ALPHA,
189190
"DP_BLEND_MODE_LINEAR_BURN",
190191
"krita:linear_burn",
191192
"Linear Burn",
192193
},
193194
[DP_BLEND_MODE_LINEAR_LIGHT] =
194195
{
195-
LAYER | BRUSH,
196+
LAYER | BRUSH | PRESERVES_ALPHA,
196197
"DP_BLEND_MODE_LINEAR_LIGHT",
197198
"krita:linear light",
198199
"Linear Light",
199200
},
200201
[DP_BLEND_MODE_HUE] =
201202
{
202-
LAYER | BRUSH,
203+
LAYER | BRUSH | PRESERVES_ALPHA,
203204
"DP_BLEND_MODE_HUE",
204205
"svg:hue",
205206
"Hue",
206207
},
207208
[DP_BLEND_MODE_SATURATION] =
208209
{
209-
LAYER | BRUSH,
210+
LAYER | BRUSH | PRESERVES_ALPHA,
210211
"DP_BLEND_MODE_SATURATION",
211212
"svg:saturation",
212213
"Saturation",
213214
},
214215
[DP_BLEND_MODE_LUMINOSITY] =
215216
{
216-
LAYER | BRUSH,
217+
LAYER | BRUSH | PRESERVES_ALPHA,
217218
"DP_BLEND_MODE_LUMINOSITY",
218219
"svg:luminosity",
219220
"Luminosity",
220221
},
221222
[DP_BLEND_MODE_COLOR] =
222223
{
223-
LAYER | BRUSH,
224+
LAYER | BRUSH | PRESERVES_ALPHA,
224225
"DP_BLEND_MODE_COLOR",
225226
"svg:color",
226227
"Color",
@@ -311,6 +312,11 @@ bool DP_blend_mode_blend_blank(int blend_mode)
311312
return get_attributes(blend_mode)->flags & BLEND_BLANK;
312313
}
313314

315+
bool DP_blend_mode_preserves_alpha(int blend_mode)
316+
{
317+
return get_attributes(blend_mode)->flags & PRESERVES_ALPHA;
318+
}
319+
314320
DP_BlendMode DP_blend_mode_by_svg_name(const char *svg_name,
315321
DP_BlendMode not_found_value)
316322
{

src/drawdance/libmsg/dpmsg/blend_mode.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ bool DP_blend_mode_can_decrease_opacity(int blend_mode);
7979

8080
bool DP_blend_mode_blend_blank(int blend_mode);
8181

82+
bool DP_blend_mode_preserves_alpha(int blend_mode);
83+
8284
DP_BlendMode DP_blend_mode_by_svg_name(const char *svg_name,
8385
DP_BlendMode not_found_value);
8486

0 commit comments

Comments
 (0)