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