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