2 * Copyright 2006-2014 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
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"
22 #include <TypeConstants.h>
24 #include "AutoDeleter.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'
37 _USING_ICON_NAMESPACE
;
41 // #pragma mark - Scaling functions
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
++) {
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
;
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;
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
++) {
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
;
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;
111 scale_down(const uint8
* srcBits
, uint8
* dstBits
, int32 srcWidth
, int32 srcHeight
,
112 int32 dstWidth
, int32 dstHeight
)
119 float d1
, d2
, d3
, d4
;
121 rgb_color p1
, p2
, p3
, p4
;
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
);
132 else if (l
>= srcHeight
- 1)
136 tmp
= (float)(j
) / (float)(dstWidth
- 1) * (srcWidth
- 1);
137 c
= (int32
)floorf(tmp
);
140 else if (c
>= srcWidth
- 1)
145 d1
= (1 - t
) * (1 - u
);
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
);
157 out
.blue
= (uint8
)(p1
.blue
* d1
+ p2
.blue
* d2
+ p3
.blue
* d3
159 out
.green
= (uint8
)(p1
.green
* d1
+ p2
.green
* d2
+ p3
.green
* d3
161 out
.red
= (uint8
)(p1
.red
* d1
+ p2
.red
* d2
+ p3
.red
* d3
163 out
.alpha
= (uint8
)(p1
.alpha
* d1
+ p2
.alpha
* d2
+ p3
.alpha
* d3
166 // destination RGBA pixel
167 *((rgb_color
*)dstBits
+ (i
* dstWidth
) + j
) = out
;
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
185 * Derived from the (public domain) SDL version of the library by Pete
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
)
194 uint32 d
= *(uint32
*)(srcBits
+ (y
* srcBPR
)
195 + (4 * MAX(0, x
- 1)));
196 uint32 e
= *(uint32
*)(srcBits
+ (y
* srcBPR
)
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
;
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
229 * Derived from the (public domain) SDL version of the library by Pete
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
)
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
)
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
;
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
;
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
);
300 // #pragma mark - GetIcon()
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
)
311 status_t result
= node
->InitCheck();
315 result
= icon
->InitCheck();
319 switch (icon
->ColorSpace()) {
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)
329 if (icon
->Bounds().IntegerWidth() + 1 >= 32)
330 which
= B_LARGE_ICON
;
334 result
= GetCMAP8Icon(node
, smallIconAttrName
,
335 largeIconAttrName
, which
, icon
);
340 // prefer old B_CMAP8 icons
341 result
= GetCMAP8Icon(node
, smallIconAttrName
, largeIconAttrName
,
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
,
349 BBitmap
temp(icon
->Bounds(), B_RGBA32
);
351 result
= temp
.InitCheck();
355 result
= GetVectorIcon(node
, vectorIconAttrName
, &temp
);
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
,
368 printf("BIconUtils::GetIcon() - unsupported colorspace\n");
377 // #pragma mark - GetVectorIcon()
381 BIconUtils::GetVectorIcon(BNode
* node
, const char* attrName
, BBitmap
* icon
)
383 if (node
== NULL
|| attrName
== NULL
|| *attrName
== '\0' || icon
== NULL
)
386 status_t result
= node
->InitCheck();
390 result
= icon
->InitCheck();
394 #if TIME_VECTOR_ICONS
395 bigtime_t startTime
= system_time();
398 // get the attribute info and check type and size of the attr contents
400 result
= node
->GetAttrInfo(attrName
, &attrInfo
);
404 type_code attrType
= B_VECTOR_ICON_TYPE
;
406 if (attrInfo
.type
!= attrType
)
409 // chicken out on unrealisticly large attributes
410 if (attrInfo
.size
> 512 * 1024)
413 uint8
* buffer
= new(std::nothrow
) uint8
[attrInfo
.size
];
417 ArrayDeleter
<uint8
> deleter(buffer
);
419 ssize_t bytesRead
= node
->ReadAttr(attrName
, attrType
, 0, buffer
,
421 if (bytesRead
!= attrInfo
.size
)
424 #if TIME_VECTOR_ICONS
425 bigtime_t importTime
= system_time();
428 result
= GetVectorIcon(buffer
, attrInfo
.size
, icon
);
432 #if TIME_VECTOR_ICONS
433 bigtime_t finishTime
= system_time();
434 printf("read: %lld, import: %lld\n", importTime
- startTime
,
435 finishTime
- importTime
);
443 BIconUtils::GetVectorIcon(const uint8
* buffer
, size_t size
, BBitmap
* icon
)
445 if (buffer
== NULL
|| size
<= 0 || icon
== NULL
)
448 status_t result
= icon
->InitCheck();
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
);
459 if (temp
== NULL
|| temp
->InitCheck() != B_OK
)
464 result
= vector
.InitCheck();
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
);
479 IconRenderer
renderer(temp
);
480 renderer
.SetIcon(&vector
);
481 renderer
.SetScale((temp
->Bounds().Width() + 1.0) / 64.0);
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();
504 // #pragma mark - GetCMAP8Icon()
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
)
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'))) {
531 result
= node
->InitCheck();
535 result
= icon
->InitCheck();
539 // set some icon size related variables
540 const char* attribute
= NULL
;
546 attribute
= smallIconAttrName
;
547 bounds
.Set(0, 0, 15, 15);
548 attrType
= B_MINI_ICON_TYPE
;
553 attribute
= largeIconAttrName
;
554 bounds
.Set(0, 0, 31, 31);
555 attrType
= B_LARGE_ICON_TYPE
;
560 // can not happen, see above
561 result
= B_BAD_VALUE
;
565 // get the attribute info and check type and size of the attr contents
568 result
= node
->GetAttrInfo(attribute
, &attrInfo
);
570 if (result
== B_OK
&& attrInfo
.type
!= attrType
)
573 if (result
== B_OK
&& attrInfo
.size
!= attrSize
)
577 // currently, scaling B_CMAP8 icons is not supported
578 if (icon
->ColorSpace() == B_CMAP8
&& icon
->Bounds() != bounds
)
581 // read the attribute
582 if (result
== B_OK
) {
583 bool useBuffer
= (icon
->ColorSpace() != B_CMAP8
584 || icon
->Bounds() != bounds
);
585 uint8
* buffer
= NULL
;
588 // other color space or bitmap size than stored in attribute
589 buffer
= new(nothrow
) uint8
[attrSize
];
591 result
= B_NO_MEMORY
;
593 bytesRead
= node
->ReadAttr(attribute
, attrType
, 0, buffer
, attrSize
);
595 bytesRead
= node
->ReadAttr(attribute
, attrType
, 0, icon
->Bits(),
599 if (result
== B_OK
) {
601 result
= (status_t
)bytesRead
;
602 else if (bytesRead
!= (ssize_t
)attrSize
)
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
);
620 // #pragma mark - ConvertFromCMAP8() and ConvertToCMAP8()
624 BIconUtils::ConvertFromCMAP8(BBitmap
* source
, BBitmap
* destination
)
626 if (source
== NULL
|| source
->ColorSpace() != B_CMAP8
)
629 status_t result
= source
->InitCheck();
633 result
= destination
->InitCheck();
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
);
647 BIconUtils::ConvertToCMAP8(BBitmap
* source
, BBitmap
* destination
)
649 if (source
== NULL
|| source
->ColorSpace() != B_RGBA32
650 || destination
->ColorSpace() != B_CMAP8
) {
654 status_t result
= source
->InitCheck();
658 result
= destination
->InitCheck();
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
);
672 BIconUtils::ConvertFromCMAP8(const uint8
* src
, uint32 width
, uint32 height
,
673 uint32 srcBPR
, BBitmap
* icon
)
675 if (src
== NULL
|| icon
== NULL
|| srcBPR
== 0)
678 status_t result
= icon
->InitCheck();
682 if (icon
->ColorSpace() != B_RGBA32
&& icon
->ColorSpace() != B_RGB32
) {
683 // TODO: support other color spaces
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),
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
);
717 const rgb_color
* colorMap
= system_colors()->color_list
;
718 if (colorMap
== NULL
)
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
];
731 if (*s
== B_TRANSPARENT_MAGIC_CMAP8
)
733 *d
= (alpha
<< 24) | (c
.red
<< 16) | (c
.green
<< 8) | (c
.blue
);
739 if (width
== dstWidth
&& height
== dstHeight
)
742 // reset src and dst back to their original locations
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),
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
);
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),
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
);
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),
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
);
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),
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,
785 scale_bilinear(dst
, width
, height
, dstWidth
, dstHeight
, dstBPR
);
788 // fall back to bilinear scaling
789 scale_bilinear(dst
, width
, height
, dstWidth
, dstHeight
, dstBPR
);
797 BIconUtils::ConvertToCMAP8(const uint8
* src
, uint32 width
, uint32 height
,
798 uint32 srcBPR
, BBitmap
* icon
)
800 if (src
== NULL
|| icon
== NULL
|| srcBPR
== 0)
803 status_t result
= icon
->InitCheck();
807 if (icon
->ColorSpace() != B_CMAP8
)
810 uint32 dstWidth
= icon
->Bounds().IntegerWidth() + 1;
811 uint32 dstHeight
= icon
->Bounds().IntegerHeight() + 1;
813 if (dstWidth
< width
|| dstHeight
< height
) {
814 // TODO: down scaling
816 } else if (dstWidth
> width
|| dstHeight
> height
) {
818 // (currently copies bitmap into icon at left-top)
819 memset(icon
->Bits(), 255, icon
->BitsLength());
823 // return icon->ImportBits(src, height * srcBPR, srcBPR, 0, B_RGBA32);
825 uint8
* dst
= (uint8
*)icon
->Bits();
826 uint32 dstBPR
= icon
->BytesPerRow();
828 const color_map
* colorMap
= system_colors();
829 if (colorMap
== NULL
)
834 for (uint32 y
= 0; y
< height
; y
++) {
836 const uint8
* s
= src
;
837 for (uint32 x
= 0; x
< width
; x
++) {
839 *d
= B_TRANSPARENT_MAGIC_CMAP8
;
841 index
= ((s
[2] & 0xf8) << 7) | ((s
[1] & 0xf8) << 2)
843 *d
= colorMap
->index_map
[index
];
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; }