xref: /haiku/src/add-ons/translators/wonderbrush/Layer.cpp (revision 837b16251d4b2b6249ebcaa19bb319cbe82c6126)
1 /*
2  * Copyright 2006, Haiku. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  */
8 
9 
10 #include "Layer.h"
11 
12 #include <stdio.h>
13 
14 #include <Bitmap.h>
15 #include <Catalog.h>
16 #include <Message.h>
17 
18 #include "bitmap_compression.h"
19 #include "blending.h"
20 #include "lab_convert.h"
21 #include "support.h"
22 
23 
24 #undef B_TRANSLATE_CONTEXT
25 #define B_TRANSLATE_CONTEXT "Layer"
26 
27 
28 // constructor
29 Layer::Layer()
30 	: fBitmap(NULL),
31 	  fBounds(0.0, 0.0, -1.0, -1.0),
32 	  fAlpha(1.0),
33 	  fMode(MODE_NORMAL),
34 	  fFlags(0)
35 {
36 }
37 
38 
39 // destructor
40 Layer::~Layer()
41 {
42 	delete fBitmap;
43 }
44 
45 
46 // Compose
47 status_t
48 Layer::Compose(const BBitmap* into, BRect area)
49 {
50 	if (!fBitmap || !fBitmap->IsValid()
51 		|| (fBitmap->ColorSpace() != B_RGBA32
52 			&& fBitmap->ColorSpace() != B_RGB32))
53 		return B_NO_INIT;
54 
55 	status_t status = B_BAD_VALUE;
56 	if (!into || !area.IsValid() || (status = into->InitCheck()) < B_OK)
57 		return status;
58 
59 	// make sure we don't access memory outside of our bitmap
60 	area = area & fBitmap->Bounds();
61 
62 	BRect r = ActiveBounds();
63 	if (!r.IsValid() || (fFlags & FLAG_INVISIBLE) || !r.Intersects(area))
64 		return B_OK;
65 
66 	r = r & area;
67 	int32 left, top, right, bottom;
68 	rect_to_int(r, left, top, right, bottom);
69 
70 	uint8* src = (uint8*)fBitmap->Bits();
71 	uint8* dst = (uint8*)into->Bits();
72 	uint32 bpr = into->BytesPerRow();
73 	src += 4 * left + bpr * top;
74 	dst += 4 * left + bpr * top;
75 	uint8 alphaOverride = (uint8)(fAlpha * 255);
76 
77 	switch (fMode) {
78 
79 		case MODE_SOFT_LIGHT:
80 			for (; top <= bottom; top++) {
81 				uint8* srcHandle = src;
82 				uint8* dstHandle = dst;
83 				for (int32 x = left; x <= right; x++) {
84 					if (srcHandle[3] > 0) {
85 						uint8 c1 = dstHandle[0] * srcHandle[0] >> 8;
86 						c1 += dstHandle[0] * (
87 								255 - (
88 									(255 - dstHandle[0])
89 									* (255 - srcHandle[0])
90 									>> 8
91 								) - c1
92 							) >> 8;
93 						c1 = (c1 * dstHandle[3]
94 								+ srcHandle[0] * (255 - dstHandle[3])
95 							) >> 8;
96 
97 						uint8 c2 = dstHandle[1] * srcHandle[1] >> 8;
98 						c2 += dstHandle[1] * (
99 								255 - (
100 									(255 - dstHandle[1])
101 									* (255 - srcHandle[1])
102 									>> 8
103 								) - c2
104 							) >> 8;
105 						c2 = (c2 * dstHandle[3]
106 								+ srcHandle[1] * (255 - dstHandle[3])
107 							) >> 8;
108 
109 						uint8 c3 = dstHandle[2] * srcHandle[2] >> 8;
110 						c3 += dstHandle[2] * (
111 								255 - (
112 									(255 - dstHandle[2])
113 									* (255 - srcHandle[2])
114 									>> 8
115 								) - c3
116 							) >> 8;
117 						c3 = (c3 * dstHandle[3]
118 								+ srcHandle[2] * (255 - dstHandle[3])
119 							) >> 8;
120 
121 						blend_colors(dstHandle,
122 							(srcHandle[3] * alphaOverride) >> 8, c1, c2, c3);
123 					}
124 					srcHandle += 4;
125 					dstHandle += 4;
126 				}
127 				src += bpr;
128 				dst += bpr;
129 			}
130 			break;
131 
132 		case MODE_LIGHTEN:
133 			for (; top <= bottom; top++) {
134 				uint8* srcHandle = src;
135 				uint8* dstHandle = dst;
136 				for (int32 x = left; x <= right; x++) {
137 					if (srcHandle[3] > 0) {
138 						// compose
139 						uint8 c1
140 							= (max_c(srcHandle[0], dstHandle[0]) * dstHandle[3]
141 								+ srcHandle[0] * (255 - dstHandle[3])) / 255;
142 						uint8 c2
143 							= (max_c(srcHandle[1], dstHandle[1]) * dstHandle[3]
144 								+ srcHandle[1] * (255 - dstHandle[3])) / 255;
145 						uint8 c3
146 							= (max_c(srcHandle[2], dstHandle[2]) * dstHandle[3]
147 								+ srcHandle[2] * (255 - dstHandle[3])) / 255;
148 						blend_colors(dstHandle,
149 							(srcHandle[3] * alphaOverride) / 255, c1, c2, c3);
150 					}
151 					srcHandle += 4;
152 					dstHandle += 4;
153 				}
154 				src += bpr;
155 				dst += bpr;
156 			}
157 			break;
158 
159 		case MODE_DARKEN:
160 			for (; top <= bottom; top++) {
161 				uint8* srcHandle = src;
162 				uint8* dstHandle = dst;
163 				for (int32 x = left; x <= right; x++) {
164 					if (srcHandle[3] > 0) {
165 						// compose
166 						uint8 c1
167 							= (min_c(srcHandle[0], dstHandle[0]) * dstHandle[3]
168 								+ srcHandle[0] * (255 - dstHandle[3])) / 255;
169 						uint8 c2
170 							= (min_c(srcHandle[1], dstHandle[1]) * dstHandle[3]
171 								+ srcHandle[1] * (255 - dstHandle[3])) / 255;
172 						uint8 c3
173 							= (min_c(srcHandle[2], dstHandle[2]) * dstHandle[3]
174 								+ srcHandle[2] * (255 - dstHandle[3])) / 255;
175 						blend_colors(dstHandle,
176 							(srcHandle[3] * alphaOverride) / 255, c1, c2, c3);
177 					}
178 					srcHandle += 4;
179 					dstHandle += 4;
180 				}
181 				src += bpr;
182 				dst += bpr;
183 			}
184 			break;
185 
186 		case MODE_REPLACE_RED:
187 			for (; top <= bottom; top++) {
188 				uint8* srcHandle = src;
189 				uint8* dstHandle = dst;
190 				for (int32 x = left; x <= right; x++) {
191 					if (srcHandle[3] > 0) {
192 						// compose
193 						uint32 alpha = srcHandle[3] * alphaOverride;
194 						dstHandle[2] = (srcHandle[2] * alpha
195 								+ dstHandle[2] * (65025 - alpha)) / 65025;
196 					}
197 					srcHandle += 4;
198 					dstHandle += 4;
199 				}
200 				src += bpr;
201 				dst += bpr;
202 			}
203 			break;
204 
205 		case MODE_REPLACE_GREEN:
206 			for (; top <= bottom; top++) {
207 				uint8* srcHandle = src;
208 				uint8* dstHandle = dst;
209 				for (int32 x = left; x <= right; x++) {
210 					if (srcHandle[3] > 0) {
211 						// compose
212 						uint32 alpha = srcHandle[3] * alphaOverride;
213 						dstHandle[1] = (srcHandle[1] * alpha
214 								+ dstHandle[1] * (65025 - alpha)) / 65025;
215 					}
216 					srcHandle += 4;
217 					dstHandle += 4;
218 				}
219 				src += bpr;
220 				dst += bpr;
221 			}
222 			break;
223 
224 		case MODE_REPLACE_BLUE:
225 			for (; top <= bottom; top++) {
226 				uint8* srcHandle = src;
227 				uint8* dstHandle = dst;
228 				for (int32 x = left; x <= right; x++) {
229 					if (srcHandle[3] > 0) {
230 						// compose
231 						uint32 alpha = srcHandle[3] * alphaOverride;
232 						dstHandle[0] = (srcHandle[0] * alpha
233 								+ dstHandle[0] * (65025 - alpha)) / 65025;
234 					}
235 					srcHandle += 4;
236 					dstHandle += 4;
237 				}
238 				src += bpr;
239 				dst += bpr;
240 			}
241 			break;
242 
243 		case MODE_MULTIPLY_INVERSE_ALPHA:
244 			for (; top <= bottom; top++) {
245 				uint8* srcHandle = src;
246 				uint8* dstHandle = dst;
247 				for (int32 x = left; x <= right; x++) {
248 					// compose
249 					uint8 temp = min_c(dstHandle[3], 255 - srcHandle[3]);
250 					dstHandle[3] = (
251 							dstHandle[3] * (255 - alphaOverride)
252 							+ temp * alphaOverride
253 						) / 255;
254 					srcHandle += 4;
255 					dstHandle += 4;
256 				}
257 				src += bpr;
258 				dst += bpr;
259 			}
260 			break;
261 
262 		case MODE_MULTIPLY_ALPHA:
263 			for (; top <= bottom; top++) {
264 				uint8* srcHandle = src;
265 				uint8* dstHandle = dst;
266 				for (int32 x = left; x <= right; x++) {
267 					// compose
268 					uint8 temp = min_c(dstHandle[3], srcHandle[3]);
269 					dstHandle[3] = (
270 							dstHandle[3] * (255 - alphaOverride)
271 							+ temp * alphaOverride
272 						) / 255;
273 					srcHandle += 4;
274 					dstHandle += 4;
275 				}
276 				src += bpr;
277 				dst += bpr;
278 			}
279 			break;
280 
281 		case MODE_LUMINANCE:
282 			for (; top <= bottom; top++) {
283 				uint8* srcHandle = src;
284 				uint8* dstHandle = dst;
285 				for (int32 x = left; x <= right; x++) {
286 					if (srcHandle[3] > 0) {
287 						// compose
288 						uint8 r = dstHandle[2];
289 						uint8 g = dstHandle[1];
290 						uint8 b = dstHandle[0];
291 						uint8 alpha = dstHandle[3];
292 						replace_luminance(r, g, b, srcHandle[2], srcHandle[1],
293 							srcHandle[0]);
294 						blend_colors(dstHandle,
295 							(srcHandle[3] * alphaOverride) / 255, b, g, r);
296 						dstHandle[3] = alpha;
297 					}
298 					srcHandle += 4;
299 					dstHandle += 4;
300 				}
301 				src += bpr;
302 				dst += bpr;
303 			}
304 			break;
305 
306 		case MODE_INVERSE_MULTIPLY:
307 			for (; top <= bottom; top++) {
308 				uint8* srcHandle = src;
309 				uint8* dstHandle = dst;
310 				for (int32 x = left; x <= right; x++) {
311 					if (srcHandle[3] > 0) {
312 						// compose
313 						uint8 c1 = 255 - (
314 								(((255 - srcHandle[0]) * (255 - dstHandle[0]))
315 									/ 255) * dstHandle[3]
316 								+ (255 - srcHandle[0]) * (255 - dstHandle[3])
317 							) / 255;
318 						uint8 c2 = 255 - (
319 								(((255 - srcHandle[1]) * (255 - dstHandle[1]))
320 									/ 255) * dstHandle[3]
321 								+ (255 - srcHandle[1]) * (255 - dstHandle[3])
322 							) / 255;
323 						uint8 c3 = 255 - (
324 								(((255 - srcHandle[2]) * (255 - dstHandle[2]))
325 									/ 255) * dstHandle[3]
326 								+ (255 - srcHandle[2]) * (255 - dstHandle[3])
327 							) / 255;
328 						blend_colors(dstHandle,
329 							(srcHandle[3] * alphaOverride) / 255, c1, c2, c3);
330 					}
331 					srcHandle += 4;
332 					dstHandle += 4;
333 				}
334 				src += bpr;
335 				dst += bpr;
336 			}
337 			break;
338 
339 		case MODE_MULTIPLY:
340 			for (; top <= bottom; top++) {
341 				uint8* srcHandle = src;
342 				uint8* dstHandle = dst;
343 				for (int32 x = left; x <= right; x++) {
344 					if (srcHandle[3] > 0) {
345 						// compose
346 						uint8 c1 = (
347 								((srcHandle[0] * dstHandle[0]) / 255)
348 									* dstHandle[3]
349 								+ srcHandle[0] * (255 - dstHandle[3])
350 							) / 255;
351 						uint8 c2 = (
352 								((srcHandle[1] * dstHandle[1]) / 255)
353 									* dstHandle[3]
354 								+ srcHandle[1] * (255 - dstHandle[3])
355 							) / 255;
356 						uint8 c3 = (
357 								((srcHandle[2] * dstHandle[2]) / 255)
358 									* dstHandle[3]
359 								+ srcHandle[2] * (255 - dstHandle[3])
360 							) / 255;
361 						blend_colors(dstHandle,
362 							(srcHandle[3] * alphaOverride) / 255, c1, c2, c3);
363 					}
364 					srcHandle += 4;
365 					dstHandle += 4;
366 				}
367 				src += bpr;
368 				dst += bpr;
369 			}
370 			break;
371 
372 		case MODE_NORMAL:
373 		default:
374 			if (alphaOverride == 255) {
375 				// use an optimized version that composes the bitmaps directly
376 				for (; top <= bottom; top++) {
377 					uint8* srcHandle = src;
378 					uint8* dstHandle = dst;
379 					for (int32 x = left; x <= right; x++) {
380 						blend_colors(dstHandle, srcHandle);
381 						srcHandle += 4;
382 						dstHandle += 4;
383 					}
384 					src += bpr;
385 					dst += bpr;
386 				}
387 			} else {
388 				for (; top <= bottom; top++) {
389 					uint8* srcHandle = src;
390 					uint8* dstHandle = dst;
391 					for (int32 x = left; x <= right; x++) {
392 						blend_colors(dstHandle, srcHandle, alphaOverride);
393 						srcHandle += 4;
394 						dstHandle += 4;
395 					}
396 					src += bpr;
397 					dst += bpr;
398 				}
399 			}
400 			break;
401 	}
402 
403 	return status;
404 }
405 
406 
407 // Unarchive
408 status_t
409 Layer::Unarchive(const BMessage* archive)
410 {
411 	if (!archive)
412 		return B_BAD_VALUE;
413 
414 	// restore attributes
415 	float alpha;
416 	if (archive->FindFloat("alpha", &alpha) == B_OK) {
417 		constrain(alpha, 0.0, 1.0);
418 		fAlpha = alpha;
419 	} else
420 		fAlpha = 1.0;
421 	if (archive->FindInt32("mode", (int32*)&fMode) < B_OK)
422 		fMode = MODE_NORMAL;
423 	if (archive->FindInt32("flags", (int32*)&fFlags) < B_OK)
424 		fFlags = 0;
425 
426 	// delete current contents
427 	delete fBitmap;
428 	fBitmap = NULL;
429 
430 	status_t status = extract_bitmap(&fBitmap, archive, "current bitmap");
431 	if (status < B_OK)
432 		return status;
433 
434 	// "bounds" is where the layer actually has content
435 	BRect bounds;
436 	if (archive->FindRect("bounds", &bounds) == B_OK)
437 		fBounds = bounds;
438 	else
439 		fBounds.Set(0.0, 0.0, -1.0, -1.0);
440 
441 	// validate status of fBitmap
442 	if (!fBitmap)
443 		return B_ERROR;
444 
445 	status = fBitmap->InitCheck();
446 	if (status < B_OK) {
447 		delete fBitmap;
448 		fBitmap = NULL;
449 	}
450 
451 	return status;
452 }
453