TCP: Fixed RTO update and dup ACKs generation.
[haiku.git] / src / libs / icon / IconUtils.cpp
blobc37cff1fb01129d5ea19128b5e815ecfe81bdad3
1 /*
2 * Copyright 2006-2014 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Stephan Aßmus, superstippi@gmx.de
7 * Axel Dörfler, axeld@pinc-software.de
8 * John Scipione, jscipione@gmail.com
9 * Ingo Weinhold, bonefish@cs.tu-berlin.de
13 #include "IconUtils.h"
15 #include <new>
16 #include <fs_attr.h>
17 #include <stdio.h>
18 #include <string.h>
20 #include <Bitmap.h>
21 #include <Node.h>
22 #include <TypeConstants.h>
24 #include "AutoDeleter.h"
25 #include "Icon.h"
26 #include "IconRenderer.h"
27 #include "FlatIconImporter.h"
28 #include "MessageImporter.h"
31 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
32 # define B_MINI_ICON_TYPE 'MICN'
33 # define B_LARGE_ICON_TYPE 'ICON'
34 #endif
37 _USING_ICON_NAMESPACE;
38 using std::nothrow;
41 // #pragma mark - Scaling functions
44 static void
45 scale_bilinear(uint8* bits, int32 srcWidth, int32 srcHeight, int32 dstWidth,
46 int32 dstHeight, uint32 bpr)
48 // first pass: scale bottom to top
50 uint8* dst = bits + (dstHeight - 1) * bpr;
51 // offset to bottom left pixel in target size
52 for (int32 x = 0; x < srcWidth; x++) {
53 uint8* d = dst;
54 for (int32 y = dstHeight - 1; y >= 0; y--) {
55 int32 lineF = (y << 8) * (srcHeight - 1) / (dstHeight - 1);
56 int32 lineI = lineF >> 8;
57 uint8 weight = (uint8)(lineF & 0xff);
58 uint8* s1 = bits + lineI * bpr + 4 * x;
59 if (weight == 0) {
60 d[0] = s1[0];
61 d[1] = s1[1];
62 d[2] = s1[2];
63 d[3] = s1[3];
64 } else {
65 uint8* s2 = s1 + bpr;
67 d[0] = (((s2[0] - s1[0]) * weight) + (s1[0] << 8)) >> 8;
68 d[1] = (((s2[1] - s1[1]) * weight) + (s1[1] << 8)) >> 8;
69 d[2] = (((s2[2] - s1[2]) * weight) + (s1[2] << 8)) >> 8;
70 d[3] = (((s2[3] - s1[3]) * weight) + (s1[3] << 8)) >> 8;
73 d -= bpr;
75 dst += 4;
78 // second pass: scale right to left
80 dst = bits + (dstWidth - 1) * 4;
81 // offset to top left pixel in target size
82 for (int32 y = 0; y < dstWidth; y++) {
83 uint8* d = dst;
84 for (int32 x = dstWidth - 1; x >= 0; x--) {
85 int32 columnF = (x << 8) * (srcWidth - 1) / (dstWidth - 1);
86 int32 columnI = columnF >> 8;
87 uint8 weight = (uint8)(columnF & 0xff);
88 uint8* s1 = bits + y * bpr + 4 * columnI;
89 if (weight == 0) {
90 d[0] = s1[0];
91 d[1] = s1[1];
92 d[2] = s1[2];
93 d[3] = s1[3];
94 } else {
95 uint8* s2 = s1 + 4;
97 d[0] = (((s2[0] - s1[0]) * weight) + (s1[0] << 8)) >> 8;
98 d[1] = (((s2[1] - s1[1]) * weight) + (s1[1] << 8)) >> 8;
99 d[2] = (((s2[2] - s1[2]) * weight) + (s1[2] << 8)) >> 8;
100 d[3] = (((s2[3] - s1[3]) * weight) + (s1[3] << 8)) >> 8;
103 d -= 4;
105 dst += bpr;
110 static void
111 scale_down(const uint8* srcBits, uint8* dstBits, int32 srcWidth, int32 srcHeight,
112 int32 dstWidth, int32 dstHeight)
114 int32 l;
115 int32 c;
116 float t;
117 float u;
118 float tmp;
119 float d1, d2, d3, d4;
120 // coefficients
121 rgb_color p1, p2, p3, p4;
122 // nearby pixels
123 rgb_color out;
124 // color components
126 for (int32 i = 0; i < dstHeight; i++) {
127 for (int32 j = 0; j < dstWidth; j++) {
128 tmp = (float)(i) / (float)(dstHeight - 1) * (srcHeight - 1);
129 l = (int32)floorf(tmp);
130 if (l < 0)
131 l = 0;
132 else if (l >= srcHeight - 1)
133 l = srcHeight - 2;
134 u = tmp - l;
136 tmp = (float)(j) / (float)(dstWidth - 1) * (srcWidth - 1);
137 c = (int32)floorf(tmp);
138 if (c < 0)
139 c = 0;
140 else if (c >= srcWidth - 1)
141 c = srcWidth - 2;
142 t = tmp - c;
144 // coefficients
145 d1 = (1 - t) * (1 - u);
146 d2 = t * (1 - u);
147 d3 = t * u;
148 d4 = (1 - t) * u;
150 // nearby pixels
151 p1 = *((rgb_color*)srcBits + (l * srcWidth) + c);
152 p2 = *((rgb_color*)srcBits + (l * srcWidth) + c + 1);
153 p3 = *((rgb_color*)srcBits + ((l + 1)* srcWidth) + c + 1);
154 p4 = *((rgb_color*)srcBits + ((l + 1)* srcWidth) + c);
156 // color components
157 out.blue = (uint8)(p1.blue * d1 + p2.blue * d2 + p3.blue * d3
158 + p4.blue * d4);
159 out.green = (uint8)(p1.green * d1 + p2.green * d2 + p3.green * d3
160 + p4.green * d4);
161 out.red = (uint8)(p1.red * d1 + p2.red * d2 + p3.red * d3
162 + p4.red * d4);
163 out.alpha = (uint8)(p1.alpha * d1 + p2.alpha * d2 + p3.alpha * d3
164 + p4.alpha * d4);
166 // destination RGBA pixel
167 *((rgb_color*)dstBits + (i * dstWidth) + j) = out;
173 static void
174 scale2x(const uint8* srcBits, uint8* dstBits, int32 srcWidth, int32 srcHeight,
175 int32 srcBPR, int32 dstBPR)
178 * This implements the AdvanceMAME Scale2x algorithm found on:
179 * http://scale2x.sourceforge.net/
181 * It is an incredibly simple and powerful image doubling routine that does
182 * an astonishing job of doubling game graphic data while interpolating out
183 * the jaggies.
185 * Derived from the (public domain) SDL version of the library by Pete
186 * Shinners.
189 // Assume that both src and dst are 4 BPP (B_RGBA32)
190 for (int32 y = 0; y < srcHeight; ++y) {
191 for (int32 x = 0; x < srcWidth; ++x) {
192 uint32 b = *(uint32*)(srcBits + (MAX(0, y - 1) * srcBPR)
193 + (4 * x));
194 uint32 d = *(uint32*)(srcBits + (y * srcBPR)
195 + (4 * MAX(0, x - 1)));
196 uint32 e = *(uint32*)(srcBits + (y * srcBPR)
197 + (4 * x));
198 uint32 f = *(uint32*)(srcBits + (y * srcBPR)
199 + (4 * MIN(srcWidth - 1, x + 1)));
200 uint32 h = *(uint32*)(srcBits + (MIN(srcHeight - 1, y + 1)
201 * srcBPR) + (4 * x));
203 uint32 e0 = d == b && b != f && d != h ? d : e;
204 uint32 e1 = b == f && b != d && f != h ? f : e;
205 uint32 e2 = d == h && d != b && h != f ? d : e;
206 uint32 e3 = h == f && d != h && b != f ? f : e;
208 *(uint32*)(dstBits + y * 2 * dstBPR + x * 2 * 4) = e0;
209 *(uint32*)(dstBits + y * 2 * dstBPR + (x * 2 + 1) * 4) = e1;
210 *(uint32*)(dstBits + (y * 2 + 1) * dstBPR + x * 2 * 4) = e2;
211 *(uint32*)(dstBits + (y * 2 + 1) * dstBPR + (x * 2 + 1) * 4) = e3;
217 static void
218 scale3x(const uint8* srcBits, uint8* dstBits, int32 srcWidth, int32 srcHeight,
219 int32 srcBPR, int32 dstBPR)
222 * This implements the AdvanceMAME Scale3x algorithm found on:
223 * http://scale2x.sourceforge.net/
225 * It is an incredibly simple and powerful image tripling routine that does
226 * an astonishing job of tripling game graphic data while interpolating out
227 * the jaggies.
229 * Derived from the (public domain) SDL version of the library by Pete
230 * Shinners.
233 // Assume that both src and dst are 4 BPP (B_RGBA32)
234 for (int32 y = 0; y < srcHeight; ++y) {
235 for (int32 x = 0; x < srcWidth; ++x) {
236 uint32 a = *(uint32*)(srcBits + (MAX(0, y - 1) * srcBPR)
237 + (4 * MAX(0, x - 1)));
238 uint32 b = *(uint32*)(srcBits + (MAX(0, y - 1) * srcBPR)
239 + (4 * x));
240 uint32 c = *(uint32*)(srcBits + (MAX(0, y - 1) * srcBPR)
241 + (4 * MIN(srcWidth - 1, x + 1)));
242 uint32 d = *(uint32*)(srcBits + (y * srcBPR)
243 + (4 * MAX(0, x - 1)));
244 uint32 e = *(uint32*)(srcBits + (y * srcBPR)
245 + (4 * x));
246 uint32 f = *(uint32*)(srcBits + (y * srcBPR)
247 + (4 * MIN(srcWidth - 1,x + 1)));
248 uint32 g = *(uint32*)(srcBits + (MIN(srcHeight - 1, y + 1)
249 * srcBPR) + (4 * MAX(0, x - 1)));
250 uint32 h = *(uint32*)(srcBits + (MIN(srcHeight - 1, y + 1)
251 * srcBPR) + (4 * x));
252 uint32 i = *(uint32*)(srcBits + (MIN(srcHeight - 1, y + 1)
253 * srcBPR) + (4 * MIN(srcWidth - 1, x + 1)));
255 uint32 e0 = d == b && b != f && d != h ? d : e;
256 uint32 e1 = (d == b && b != f && d != h && e != c)
257 || (b == f && b != d && f != h && e != a) ? b : e;
258 uint32 e2 = b == f && b != d && f != h ? f : e;
259 uint32 e3 = (d == b && b != f && d != h && e != g)
260 || (d == b && b != f && d != h && e != a) ? d : e;
261 uint32 e4 = e;
262 uint32 e5 = (b == f && b != d && f != h && e != i)
263 || (h == f && d != h && b != f && e != c) ? f : e;
264 uint32 e6 = d == h && d != b && h != f ? d : e;
265 uint32 e7 = (d == h && d != b && h != f && e != i)
266 || (h == f && d != h && b != f && e != g) ? h : e;
267 uint32 e8 = h == f && d != h && b != f ? f : e;
269 *(uint32*)(dstBits + y * 3 * dstBPR + x * 3 * 4) = e0;
270 *(uint32*)(dstBits + y * 3 * dstBPR + (x * 3 + 1) * 4) = e1;
271 *(uint32*)(dstBits + y * 3 * dstBPR + (x * 3 + 2) * 4) = e2;
272 *(uint32*)(dstBits + (y * 3 + 1) * dstBPR + x * 3 * 4) = e3;
273 *(uint32*)(dstBits + (y * 3 + 1) * dstBPR + (x * 3 + 1) * 4) = e4;
274 *(uint32*)(dstBits + (y * 3 + 1) * dstBPR + (x * 3 + 2) * 4) = e5;
275 *(uint32*)(dstBits + (y * 3 + 2) * dstBPR + x * 3 * 4) = e6;
276 *(uint32*)(dstBits + (y * 3 + 2) * dstBPR + (x * 3 + 1) * 4) = e7;
277 *(uint32*)(dstBits + (y * 3 + 2) * dstBPR + (x * 3 + 2) * 4) = e8;
283 static void
284 scale4x(const uint8* srcBits, uint8* dstBits, int32 srcWidth, int32 srcHeight,
285 int32 srcBPR, int32 dstBPR)
287 // scale4x is just scale2x twice
288 BBitmap* tmp = new BBitmap(BRect(0, 0, srcWidth * 2 - 1,
289 srcHeight * 2 - 1), B_RGBA32);
290 uint8* tmpBits = (uint8*)tmp->Bits();
291 int32 tmpBPR = tmp->BytesPerRow();
293 scale2x(srcBits, tmpBits, srcWidth, srcHeight, srcBPR, tmpBPR);
294 scale2x(tmpBits, dstBits, srcWidth * 2, srcHeight * 2, tmpBPR, dstBPR);
296 delete tmp;
300 // #pragma mark - GetIcon()
303 status_t
304 BIconUtils::GetIcon(BNode* node, const char* vectorIconAttrName,
305 const char* smallIconAttrName, const char* largeIconAttrName,
306 icon_size which, BBitmap* icon)
308 if (node == NULL || icon == NULL)
309 return B_BAD_VALUE;
311 status_t result = node->InitCheck();
312 if (result != B_OK)
313 return result;
315 result = icon->InitCheck();
316 if (result != B_OK)
317 return result;
319 switch (icon->ColorSpace()) {
320 case B_RGBA32:
321 case B_RGB32:
322 // prefer vector icon
323 result = GetVectorIcon(node, vectorIconAttrName, icon);
324 if (result != B_OK) {
325 // try to fallback to B_CMAP8 icons
326 // (converting to B_RGBA32 is handled)
328 // override size
329 if (icon->Bounds().IntegerWidth() + 1 >= 32)
330 which = B_LARGE_ICON;
331 else
332 which = B_MINI_ICON;
334 result = GetCMAP8Icon(node, smallIconAttrName,
335 largeIconAttrName, which, icon);
337 break;
339 case B_CMAP8:
340 // prefer old B_CMAP8 icons
341 result = GetCMAP8Icon(node, smallIconAttrName, largeIconAttrName,
342 which, icon);
343 if (result != B_OK) {
344 // try to fallback to vector icon
345 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
346 BBitmap temp(icon->Bounds(), B_BITMAP_NO_SERVER_LINK,
347 B_RGBA32);
348 #else
349 BBitmap temp(icon->Bounds(), B_RGBA32);
350 #endif
351 result = temp.InitCheck();
352 if (result != B_OK)
353 break;
355 result = GetVectorIcon(node, vectorIconAttrName, &temp);
356 if (result != B_OK)
357 break;
359 uint32 width = temp.Bounds().IntegerWidth() + 1;
360 uint32 height = temp.Bounds().IntegerHeight() + 1;
361 uint32 bytesPerRow = temp.BytesPerRow();
362 result = ConvertToCMAP8((uint8*)temp.Bits(), width, height,
363 bytesPerRow, icon);
365 break;
367 default:
368 printf("BIconUtils::GetIcon() - unsupported colorspace\n");
369 result = B_ERROR;
370 break;
373 return result;
377 // #pragma mark - GetVectorIcon()
380 status_t
381 BIconUtils::GetVectorIcon(BNode* node, const char* attrName, BBitmap* icon)
383 if (node == NULL || attrName == NULL || *attrName == '\0' || icon == NULL)
384 return B_BAD_VALUE;
386 status_t result = node->InitCheck();
387 if (result != B_OK)
388 return result;
390 result = icon->InitCheck();
391 if (result != B_OK)
392 return result;
394 #if TIME_VECTOR_ICONS
395 bigtime_t startTime = system_time();
396 #endif
398 // get the attribute info and check type and size of the attr contents
399 attr_info attrInfo;
400 result = node->GetAttrInfo(attrName, &attrInfo);
401 if (result != B_OK)
402 return result;
404 type_code attrType = B_VECTOR_ICON_TYPE;
406 if (attrInfo.type != attrType)
407 return B_BAD_TYPE;
409 // chicken out on unrealisticly large attributes
410 if (attrInfo.size > 512 * 1024)
411 return B_BAD_VALUE;
413 uint8* buffer = new(std::nothrow) uint8[attrInfo.size];
414 if (buffer == NULL)
415 return B_NO_MEMORY;
417 ArrayDeleter<uint8> deleter(buffer);
419 ssize_t bytesRead = node->ReadAttr(attrName, attrType, 0, buffer,
420 attrInfo.size);
421 if (bytesRead != attrInfo.size)
422 return B_ERROR;
424 #if TIME_VECTOR_ICONS
425 bigtime_t importTime = system_time();
426 #endif
428 result = GetVectorIcon(buffer, attrInfo.size, icon);
429 if (result != B_OK)
430 return result;
432 #if TIME_VECTOR_ICONS
433 bigtime_t finishTime = system_time();
434 printf("read: %lld, import: %lld\n", importTime - startTime,
435 finishTime - importTime);
436 #endif
438 return B_OK;
442 status_t
443 BIconUtils::GetVectorIcon(const uint8* buffer, size_t size, BBitmap* icon)
445 if (buffer == NULL || size <= 0 || icon == NULL)
446 return B_BAD_VALUE;
448 status_t result = icon->InitCheck();
449 if (result != B_OK)
450 return result;
452 BBitmap* temp = icon;
453 ObjectDeleter<BBitmap> deleter;
455 if (icon->ColorSpace() != B_RGBA32 && icon->ColorSpace() != B_RGB32) {
456 temp = new (nothrow) BBitmap(icon->Bounds(),
457 B_BITMAP_NO_SERVER_LINK, B_RGBA32);
458 deleter.SetTo(temp);
459 if (temp == NULL || temp->InitCheck() != B_OK)
460 return B_NO_MEMORY;
463 Icon vector;
464 result = vector.InitCheck();
465 if (result != B_OK)
466 return result;
468 FlatIconImporter importer;
469 result = importer.Import(&vector, const_cast<uint8*>(buffer), size);
470 if (result != B_OK) {
471 // try the message based format used by Icon-O-Matic
472 MessageImporter messageImporter;
473 BMemoryIO memoryIO(const_cast<uint8*>(buffer), size);
474 result = messageImporter.Import(&vector, &memoryIO);
475 if (result != B_OK)
476 return result;
479 IconRenderer renderer(temp);
480 renderer.SetIcon(&vector);
481 renderer.SetScale((temp->Bounds().Width() + 1.0) / 64.0);
482 renderer.Render();
484 if (temp != icon) {
485 uint8* src = (uint8*)temp->Bits();
486 uint32 width = temp->Bounds().IntegerWidth() + 1;
487 uint32 height = temp->Bounds().IntegerHeight() + 1;
488 uint32 srcBPR = temp->BytesPerRow();
489 result = ConvertToCMAP8(src, width, height, srcBPR, icon);
492 // TODO: would be nice to get rid of this
493 // (B_RGBA32_PREMULTIPLIED or better yet, new blending_mode)
494 // NOTE: probably not necessary only because
495 // transparent colors are "black" in all existing icons
496 // lighter transparent colors should be too dark if
497 // app_server uses correct blending
498 //renderer.Demultiply();
500 return result;
504 // #pragma mark - GetCMAP8Icon()
507 status_t
508 BIconUtils::GetCMAP8Icon(BNode* node, const char* smallIconAttrName,
509 const char* largeIconAttrName, icon_size which, BBitmap* icon)
511 // NOTE: this might be changed if other icon
512 // sizes are supported in B_CMAP8 attributes,
513 // but this is currently not the case, so we
514 // relax the requirement to pass an icon
515 // of just the right size
516 if (which < B_LARGE_ICON)
517 which = B_MINI_ICON;
518 else
519 which = B_LARGE_ICON;
521 // check parameters and initialization
522 if (node == NULL || icon == NULL
523 || (which == B_MINI_ICON
524 && (smallIconAttrName == NULL || *smallIconAttrName == '\0'))
525 || (which == B_LARGE_ICON
526 && (largeIconAttrName == NULL || *largeIconAttrName == '\0'))) {
527 return B_BAD_VALUE;
530 status_t result;
531 result = node->InitCheck();
532 if (result != B_OK)
533 return result;
535 result = icon->InitCheck();
536 if (result != B_OK)
537 return result;
539 // set some icon size related variables
540 const char* attribute = NULL;
541 BRect bounds;
542 uint32 attrType = 0;
543 off_t attrSize = 0;
544 switch (which) {
545 case B_MINI_ICON:
546 attribute = smallIconAttrName;
547 bounds.Set(0, 0, 15, 15);
548 attrType = B_MINI_ICON_TYPE;
549 attrSize = 16 * 16;
550 break;
552 case B_LARGE_ICON:
553 attribute = largeIconAttrName;
554 bounds.Set(0, 0, 31, 31);
555 attrType = B_LARGE_ICON_TYPE;
556 attrSize = 32 * 32;
557 break;
559 default:
560 // can not happen, see above
561 result = B_BAD_VALUE;
562 break;
565 // get the attribute info and check type and size of the attr contents
566 attr_info attrInfo;
567 if (result == B_OK)
568 result = node->GetAttrInfo(attribute, &attrInfo);
570 if (result == B_OK && attrInfo.type != attrType)
571 result = B_BAD_TYPE;
573 if (result == B_OK && attrInfo.size != attrSize)
574 result = B_BAD_DATA;
576 // check parameters
577 // currently, scaling B_CMAP8 icons is not supported
578 if (icon->ColorSpace() == B_CMAP8 && icon->Bounds() != bounds)
579 return B_BAD_VALUE;
581 // read the attribute
582 if (result == B_OK) {
583 bool useBuffer = (icon->ColorSpace() != B_CMAP8
584 || icon->Bounds() != bounds);
585 uint8* buffer = NULL;
586 ssize_t bytesRead;
587 if (useBuffer) {
588 // other color space or bitmap size than stored in attribute
589 buffer = new(nothrow) uint8[attrSize];
590 if (buffer == NULL)
591 result = B_NO_MEMORY;
592 else
593 bytesRead = node->ReadAttr(attribute, attrType, 0, buffer, attrSize);
594 } else {
595 bytesRead = node->ReadAttr(attribute, attrType, 0, icon->Bits(),
596 attrSize);
599 if (result == B_OK) {
600 if (bytesRead < 0)
601 result = (status_t)bytesRead;
602 else if (bytesRead != (ssize_t)attrSize)
603 result = B_ERROR;
606 if (useBuffer) {
607 // other color space than stored in attribute
608 if (result == B_OK) {
609 result = ConvertFromCMAP8(buffer, (uint32)which, (uint32)which,
610 (uint32)which, icon);
612 delete[] buffer;
616 return result;
620 // #pragma mark - ConvertFromCMAP8() and ConvertToCMAP8()
623 status_t
624 BIconUtils::ConvertFromCMAP8(BBitmap* source, BBitmap* destination)
626 if (source == NULL || source->ColorSpace() != B_CMAP8)
627 return B_BAD_VALUE;
629 status_t result = source->InitCheck();
630 if (result != B_OK)
631 return result;
633 result = destination->InitCheck();
634 if (result != B_OK)
635 return result;
637 uint8* src = (uint8*)source->Bits();
638 uint32 srcBPR = source->BytesPerRow();
639 uint32 width = source->Bounds().IntegerWidth() + 1;
640 uint32 height = source->Bounds().IntegerHeight() + 1;
642 return ConvertFromCMAP8(src, width, height, srcBPR, destination);
646 status_t
647 BIconUtils::ConvertToCMAP8(BBitmap* source, BBitmap* destination)
649 if (source == NULL || source->ColorSpace() != B_RGBA32
650 || destination->ColorSpace() != B_CMAP8) {
651 return B_BAD_VALUE;
654 status_t result = source->InitCheck();
655 if (result != B_OK)
656 return result;
658 result = destination->InitCheck();
659 if (result != B_OK)
660 return result;
662 uint8* src = (uint8*)source->Bits();
663 uint32 srcBPR = source->BytesPerRow();
664 uint32 width = source->Bounds().IntegerWidth() + 1;
665 uint32 height = source->Bounds().IntegerHeight() + 1;
667 return ConvertToCMAP8(src, width, height, srcBPR, destination);
671 status_t
672 BIconUtils::ConvertFromCMAP8(const uint8* src, uint32 width, uint32 height,
673 uint32 srcBPR, BBitmap* icon)
675 if (src == NULL || icon == NULL || srcBPR == 0)
676 return B_BAD_VALUE;
678 status_t result = icon->InitCheck();
679 if (result != B_OK)
680 return result;
682 if (icon->ColorSpace() != B_RGBA32 && icon->ColorSpace() != B_RGB32) {
683 // TODO: support other color spaces
684 return B_BAD_VALUE;
687 uint32 dstWidth = icon->Bounds().IntegerWidth() + 1;
688 uint32 dstHeight = icon->Bounds().IntegerHeight() + 1;
690 uint8* dst = (uint8*)icon->Bits();
691 uint32 dstBPR = icon->BytesPerRow();
693 // check for downscaling or integer multiple scaling
694 if (dstWidth < width || dstHeight < height
695 || (dstWidth == 2 * width && dstHeight == 2 * height)
696 || (dstWidth == 3 * width && dstHeight == 3 * height)
697 || (dstWidth == 4 * width && dstHeight == 4 * height)) {
698 BBitmap* converted = new BBitmap(BRect(0, 0, width - 1, height - 1),
699 icon->ColorSpace());
700 converted->ImportBits(src, height * srcBPR, srcBPR, 0, B_CMAP8);
701 uint8* convertedBits = (uint8*)converted->Bits();
702 int32 convertedBPR = converted->BytesPerRow();
704 if (dstWidth < width || dstHeight < height)
705 scale_down(convertedBits, dst, width, height, dstWidth, dstHeight);
706 else if (dstWidth == 2 * width && dstHeight == 2 * height)
707 scale2x(convertedBits, dst, width, height, convertedBPR, dstBPR);
708 else if (dstWidth == 3 * width && dstHeight == 3 * height)
709 scale3x(convertedBits, dst, width, height, convertedBPR, dstBPR);
710 else if (dstWidth == 4 * width && dstHeight == 4 * height)
711 scale4x(convertedBits, dst, width, height, convertedBPR, dstBPR);
713 delete converted;
714 return B_OK;
717 const rgb_color* colorMap = system_colors()->color_list;
718 if (colorMap == NULL)
719 return B_NO_INIT;
721 const uint8* srcStart = src;
722 uint8* dstStart = dst;
724 // convert from B_CMAP8 to B_RGB(A)32 without scaling
725 for (uint32 y = 0; y < height; y++) {
726 uint32* d = (uint32*)dst;
727 const uint8* s = src;
728 for (uint32 x = 0; x < width; x++, s++, d++) {
729 const rgb_color c = colorMap[*s];
730 uint8 alpha = 0xff;
731 if (*s == B_TRANSPARENT_MAGIC_CMAP8)
732 alpha = 0;
733 *d = (alpha << 24) | (c.red << 16) | (c.green << 8) | (c.blue);
735 src += srcBPR;
736 dst += dstBPR;
739 if (width == dstWidth && height == dstHeight)
740 return B_OK;
742 // reset src and dst back to their original locations
743 src = srcStart;
744 dst = dstStart;
746 if (dstWidth > width && dstHeight > height
747 && dstWidth < 2 * width && dstHeight < 2 * height) {
748 // scale2x then downscale
749 BBitmap* temp = new BBitmap(BRect(0, 0, width * 2 - 1, height * 2 - 1),
750 icon->ColorSpace());
751 uint8* tempBits = (uint8*)temp->Bits();
752 uint32 tempBPR = temp->BytesPerRow();
753 scale2x(dst, tempBits, width, height, dstBPR, tempBPR);
754 scale_down(tempBits, dst, width * 2, height * 2, dstWidth, dstHeight);
755 delete temp;
756 } else if (dstWidth > 2 * width && dstHeight > 2 * height
757 && dstWidth < 3 * width && dstHeight < 3 * height) {
758 // scale3x then downscale
759 BBitmap* temp = new BBitmap(BRect(0, 0, width * 3 - 1, height * 3 - 1),
760 icon->ColorSpace());
761 uint8* tempBits = (uint8*)temp->Bits();
762 uint32 tempBPR = temp->BytesPerRow();
763 scale3x(dst, tempBits, width, height, dstBPR, tempBPR);
764 scale_down(tempBits, dst, width * 3, height * 3, dstWidth, dstHeight);
765 delete temp;
766 } else if (dstWidth > 3 * width && dstHeight > 3 * height
767 && dstWidth < 4 * width && dstHeight < 4 * height) {
768 // scale4x then downscale
769 BBitmap* temp = new BBitmap(BRect(0, 0, width * 4 - 1, height * 4 - 1),
770 icon->ColorSpace());
771 uint8* tempBits = (uint8*)temp->Bits();
772 uint32 tempBPR = temp->BytesPerRow();
773 scale4x(dst, tempBits, width, height, dstBPR, tempBPR);
774 scale_down(tempBits, dst, width * 3, height * 3, dstWidth, dstHeight);
775 delete temp;
776 } else if (dstWidth > 4 * width && dstHeight > 4 * height) {
777 // scale4x then bilinear
778 BBitmap* temp = new BBitmap(BRect(0, 0, width * 4 - 1, height * 4 - 1),
779 icon->ColorSpace());
780 uint8* tempBits = (uint8*)temp->Bits();
781 uint32 tempBPR = temp->BytesPerRow();
782 scale4x(dst, tempBits, width, height, dstBPR, tempBPR);
783 icon->ImportBits(tempBits, height * tempBPR, tempBPR, 0,
784 temp->ColorSpace());
785 scale_bilinear(dst, width, height, dstWidth, dstHeight, dstBPR);
786 delete temp;
787 } else {
788 // fall back to bilinear scaling
789 scale_bilinear(dst, width, height, dstWidth, dstHeight, dstBPR);
792 return B_OK;
796 status_t
797 BIconUtils::ConvertToCMAP8(const uint8* src, uint32 width, uint32 height,
798 uint32 srcBPR, BBitmap* icon)
800 if (src == NULL || icon == NULL || srcBPR == 0)
801 return B_BAD_VALUE;
803 status_t result = icon->InitCheck();
804 if (result != B_OK)
805 return result;
807 if (icon->ColorSpace() != B_CMAP8)
808 return B_BAD_VALUE;
810 uint32 dstWidth = icon->Bounds().IntegerWidth() + 1;
811 uint32 dstHeight = icon->Bounds().IntegerHeight() + 1;
813 if (dstWidth < width || dstHeight < height) {
814 // TODO: down scaling
815 return B_ERROR;
816 } else if (dstWidth > width || dstHeight > height) {
817 // TODO: up scaling
818 // (currently copies bitmap into icon at left-top)
819 memset(icon->Bits(), 255, icon->BitsLength());
822 //#if __HAIKU__
823 // return icon->ImportBits(src, height * srcBPR, srcBPR, 0, B_RGBA32);
824 //#else
825 uint8* dst = (uint8*)icon->Bits();
826 uint32 dstBPR = icon->BytesPerRow();
828 const color_map* colorMap = system_colors();
829 if (colorMap == NULL)
830 return B_NO_INIT;
832 uint16 index;
834 for (uint32 y = 0; y < height; y++) {
835 uint8* d = dst;
836 const uint8* s = src;
837 for (uint32 x = 0; x < width; x++) {
838 if (s[3] < 128) {
839 *d = B_TRANSPARENT_MAGIC_CMAP8;
840 } else {
841 index = ((s[2] & 0xf8) << 7) | ((s[1] & 0xf8) << 2)
842 | (s[0] >> 3);
843 *d = colorMap->index_map[index];
845 s += 4;
846 d += 1;
848 src += srcBPR;
849 dst += dstBPR;
852 return B_OK;
853 //#endif // __HAIKU__
857 // #pragma mark - Forbidden
860 BIconUtils::BIconUtils() {}
861 BIconUtils::~BIconUtils() {}
862 BIconUtils::BIconUtils(const BIconUtils&) {}
863 BIconUtils& BIconUtils::operator=(const BIconUtils&) { return *this; }