1 /* 2 * Copyright 2006-2013, Haiku. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 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 10 */ 11 12 13 #include "IconUtils.h" 14 15 #include <new> 16 #include <fs_attr.h> 17 #include <stdio.h> 18 #include <string.h> 19 20 #include <Bitmap.h> 21 #include <Node.h> 22 #include <TypeConstants.h> 23 24 #include "AutoDeleter.h" 25 #include "Icon.h" 26 #include "IconRenderer.h" 27 #include "FlatIconImporter.h" 28 #include "MessageImporter.h" 29 30 #ifndef HAIKU_TARGET_PLATFORM_HAIKU 31 # define B_MINI_ICON_TYPE 'MICN' 32 # define B_LARGE_ICON_TYPE 'ICON' 33 #endif 34 35 _USING_ICON_NAMESPACE; 36 using std::nothrow; 37 38 39 static void 40 scale_bilinear(uint8* bits, int32 srcWidth, int32 srcHeight, int32 dstWidth, 41 int32 dstHeight, uint32 bpr) 42 { 43 // first pass: scale bottom to top 44 45 uint8* dst = bits + (dstHeight - 1) * bpr; 46 // offset to bottom left pixel in target size 47 for (int32 x = 0; x < srcWidth; x++) { 48 uint8* d = dst; 49 for (int32 y = dstHeight - 1; y >= 0; y--) { 50 int32 lineF = (y << 8) * (srcHeight - 1) / (dstHeight - 1); 51 int32 lineI = lineF >> 8; 52 uint8 weight = (uint8)(lineF & 0xff); 53 uint8* s1 = bits + lineI * bpr + 4 * x; 54 if (weight == 0) { 55 d[0] = s1[0]; 56 d[1] = s1[1]; 57 d[2] = s1[2]; 58 d[3] = s1[3]; 59 } else { 60 uint8* s2 = s1 + bpr; 61 62 d[0] = (((s2[0] - s1[0]) * weight) + (s1[0] << 8)) >> 8; 63 d[1] = (((s2[1] - s1[1]) * weight) + (s1[1] << 8)) >> 8; 64 d[2] = (((s2[2] - s1[2]) * weight) + (s1[2] << 8)) >> 8; 65 d[3] = (((s2[3] - s1[3]) * weight) + (s1[3] << 8)) >> 8; 66 } 67 68 d -= bpr; 69 } 70 dst += 4; 71 } 72 73 // second pass: scale right to left 74 75 dst = bits + (dstWidth - 1) * 4; 76 // offset to top left pixel in target size 77 for (int32 y = 0; y < dstWidth; y++) { 78 uint8* d = dst; 79 for (int32 x = dstWidth - 1; x >= 0; x--) { 80 int32 columnF = (x << 8) * (srcWidth - 1) / (dstWidth - 1); 81 int32 columnI = columnF >> 8; 82 uint8 weight = (uint8)(columnF & 0xff); 83 uint8* s1 = bits + y * bpr + 4 * columnI; 84 if (weight == 0) { 85 d[0] = s1[0]; 86 d[1] = s1[1]; 87 d[2] = s1[2]; 88 d[3] = s1[3]; 89 } else { 90 uint8* s2 = s1 + 4; 91 92 d[0] = (((s2[0] - s1[0]) * weight) + (s1[0] << 8)) >> 8; 93 d[1] = (((s2[1] - s1[1]) * weight) + (s1[1] << 8)) >> 8; 94 d[2] = (((s2[2] - s1[2]) * weight) + (s1[2] << 8)) >> 8; 95 d[3] = (((s2[3] - s1[3]) * weight) + (s1[3] << 8)) >> 8; 96 } 97 98 d -= 4; 99 } 100 dst += bpr; 101 } 102 } 103 104 105 static void 106 scale_down(const uint8* srcBits, uint8* dstBits, int32 srcWidth, int32 srcHeight, 107 int32 dstWidth, int32 dstHeight) 108 { 109 int32 l; 110 int32 c; 111 float t; 112 float u; 113 float tmp; 114 float d1, d2, d3, d4; 115 // coefficients 116 rgb_color p1, p2, p3, p4; 117 // nearby pixels 118 rgb_color out; 119 // color components 120 121 for (int32 i = 0; i < dstHeight; i++) { 122 for (int32 j = 0; j < dstWidth; j++) { 123 tmp = (float)(i) / (float)(dstHeight - 1) * (srcHeight - 1); 124 l = (int32)floorf(tmp); 125 if (l < 0) 126 l = 0; 127 else if (l >= srcHeight - 1) 128 l = srcHeight - 2; 129 u = tmp - l; 130 131 tmp = (float)(j) / (float)(dstWidth - 1) * (srcWidth - 1); 132 c = (int32)floorf(tmp); 133 if (c < 0) 134 c = 0; 135 else if (c >= srcWidth - 1) 136 c = srcWidth - 2; 137 t = tmp - c; 138 139 // coefficients 140 d1 = (1 - t) * (1 - u); 141 d2 = t * (1 - u); 142 d3 = t * u; 143 d4 = (1 - t) * u; 144 145 // nearby pixels 146 p1 = *((rgb_color*)srcBits + (l * srcWidth) + c); 147 p2 = *((rgb_color*)srcBits + (l * srcWidth) + c + 1); 148 p3 = *((rgb_color*)srcBits + ((l + 1)* srcWidth) + c + 1); 149 p4 = *((rgb_color*)srcBits + ((l + 1)* srcWidth) + c); 150 151 // color components 152 out.blue = (uint8)(p1.blue * d1 + p2.blue * d2 + p3.blue * d3 153 + p4.blue * d4); 154 out.green = (uint8)(p1.green * d1 + p2.green * d2 + p3.green * d3 155 + p4.green * d4); 156 out.red = (uint8)(p1.red * d1 + p2.red * d2 + p3.red * d3 157 + p4.red * d4); 158 out.alpha = (uint8)(p1.alpha * d1 + p2.alpha * d2 + p3.alpha * d3 159 + p4.alpha * d4); 160 161 // destination RGBA pixel 162 *((rgb_color*)dstBits + (i * dstWidth) + j) = out; 163 } 164 } 165 } 166 167 168 static void 169 scale2x(const uint8* srcBits, uint8* dstBits, int32 srcWidth, int32 srcHeight, 170 int32 srcBPR, int32 dstBPR) 171 { 172 /* 173 * This implements the AdvanceMAME Scale2x algorithm found on: 174 * http://scale2x.sourceforge.net/ 175 * 176 * It is an incredibly simple and powerful image doubling routine that does 177 * an astonishing job of doubling game graphic data while interpolating out 178 * the jaggies. 179 * 180 * Derived from the (public domain) SDL version of the library by Pete 181 * Shinners 182 */ 183 184 // Assume that both src and dst are 4 BPP (B_RGBA32) 185 for (int32 y = 0; y < srcHeight; ++y) { 186 for (int32 x = 0; x < srcWidth; ++x) { 187 uint32 b = *(uint32*)(srcBits + (MAX(0, y - 1) * srcBPR) 188 + (4 * x)); 189 uint32 d = *(uint32*)(srcBits + (y * srcBPR) 190 + (4 * MAX(0, x - 1))); 191 uint32 e = *(uint32*)(srcBits + (y * srcBPR) 192 + (4 * x)); 193 uint32 f = *(uint32*)(srcBits + (y * srcBPR) 194 + (4 * MIN(srcWidth - 1, x + 1))); 195 uint32 h = *(uint32*)(srcBits + (MIN(srcHeight - 1, y + 1) 196 * srcBPR) + (4 * x)); 197 198 uint32 e0 = d == b && b != f && d != h ? d : e; 199 uint32 e1 = b == f && b != d && f != h ? f : e; 200 uint32 e2 = d == h && d != b && h != f ? d : e; 201 uint32 e3 = h == f && d != h && b != f ? f : e; 202 203 *(uint32*)(dstBits + y * 2 * dstBPR + x * 2 * 4) = e0; 204 *(uint32*)(dstBits + y * 2 * dstBPR + (x * 2 + 1) * 4) = e1; 205 *(uint32*)(dstBits + (y * 2 + 1) * dstBPR + x * 2 * 4) = e2; 206 *(uint32*)(dstBits + (y * 2 + 1) * dstBPR + (x * 2 + 1) * 4) = e3; 207 } 208 } 209 } 210 211 212 static void 213 scale3x(const uint8* srcBits, uint8* dstBits, int32 srcWidth, int32 srcHeight, 214 int32 srcBPR, int32 dstBPR) 215 { 216 /* 217 * This implements the AdvanceMAME Scale3x algorithm found on: 218 * http://scale2x.sourceforge.net/ 219 * 220 * It is an incredibly simple and powerful image tripling routine that does 221 * an astonishing job of tripling game graphic data while interpolating out 222 * the jaggies. 223 * 224 * Derived from the (public domain) SDL version of the library by Pete 225 * Shinners 226 */ 227 228 // Assume that both src and dst are 4 BPP (B_RGBA32) 229 for (int32 y = 0; y < srcHeight; ++y) { 230 for (int32 x = 0; x < srcWidth; ++x) { 231 uint32 a = *(uint32*)(srcBits + (MAX(0, y - 1) * srcBPR) 232 + (4 * MAX(0, x - 1))); 233 uint32 b = *(uint32*)(srcBits + (MAX(0, y - 1) * srcBPR) 234 + (4 * x)); 235 uint32 c = *(uint32*)(srcBits + (MAX(0, y - 1) * srcBPR) 236 + (4 * MIN(srcWidth - 1, x + 1))); 237 uint32 d = *(uint32*)(srcBits + (y * srcBPR) 238 + (4 * MAX(0, x - 1))); 239 uint32 e = *(uint32*)(srcBits + (y * srcBPR) 240 + (4 * x)); 241 uint32 f = *(uint32*)(srcBits + (y * srcBPR) 242 + (4 * MIN(srcWidth - 1,x + 1))); 243 uint32 g = *(uint32*)(srcBits + (MIN(srcHeight - 1, y + 1) 244 * srcBPR) + (4 * MAX(0, x - 1))); 245 uint32 h = *(uint32*)(srcBits + (MIN(srcHeight - 1, y + 1) 246 * srcBPR) + (4 * x)); 247 uint32 i = *(uint32*)(srcBits + (MIN(srcHeight - 1, y + 1) 248 * srcBPR) + (4 * MIN(srcWidth - 1, x + 1))); 249 250 uint32 e0 = d == b && b != f && d != h ? d : e; 251 uint32 e1 = (d == b && b != f && d != h && e != c) 252 || (b == f && b != d && f != h && e != a) ? b : e; 253 uint32 e2 = b == f && b != d && f != h ? f : e; 254 uint32 e3 = (d == b && b != f && d != h && e != g) 255 || (d == b && b != f && d != h && e != a) ? d : e; 256 uint32 e4 = e; 257 uint32 e5 = (b == f && b != d && f != h && e != i) 258 || (h == f && d != h && b != f && e != c) ? f : e; 259 uint32 e6 = d == h && d != b && h != f ? d : e; 260 uint32 e7 = (d == h && d != b && h != f && e != i) 261 || (h == f && d != h && b != f && e != g) ? h : e; 262 uint32 e8 = h == f && d != h && b != f ? f : e; 263 264 *(uint32*)(dstBits + y * 3 * dstBPR + x * 3 * 4) = e0; 265 *(uint32*)(dstBits + y * 3 * dstBPR + (x * 3 + 1) * 4) = e1; 266 *(uint32*)(dstBits + y * 3 * dstBPR + (x * 3 + 2) * 4) = e2; 267 *(uint32*)(dstBits + (y * 3 + 1) * dstBPR + x * 3 * 4) = e3; 268 *(uint32*)(dstBits + (y * 3 + 1) * dstBPR + (x * 3 + 1) * 4) = e4; 269 *(uint32*)(dstBits + (y * 3 + 1) * dstBPR + (x * 3 + 2) * 4) = e5; 270 *(uint32*)(dstBits + (y * 3 + 2) * dstBPR + x * 3 * 4) = e6; 271 *(uint32*)(dstBits + (y * 3 + 2) * dstBPR + (x * 3 + 1) * 4) = e7; 272 *(uint32*)(dstBits + (y * 3 + 2) * dstBPR + (x * 3 + 2) * 4) = e8; 273 } 274 } 275 } 276 277 278 static void 279 scale4x(const uint8* srcBits, uint8* dstBits, int32 srcWidth, int32 srcHeight, 280 int32 srcBPR, int32 dstBPR) 281 { 282 // scale4x is just scale2x twice 283 BBitmap* tmp = new BBitmap(BRect(0, 0, srcWidth * 2 - 1, 284 srcHeight * 2 - 1), B_RGBA32); 285 uint8* tmpBits = (uint8*)tmp->Bits(); 286 int32 tmpBPR = tmp->BytesPerRow(); 287 288 scale2x(srcBits, tmpBits, srcWidth, srcHeight, srcBPR, tmpBPR); 289 scale2x(tmpBits, dstBits, srcWidth * 2, srcHeight * 2, tmpBPR, dstBPR); 290 291 delete tmp; 292 } 293 294 295 // #pragma mark - 296 297 298 status_t 299 BIconUtils::GetIcon(BNode* node, const char* vectorIconAttrName, 300 const char* smallIconAttrName, const char* largeIconAttrName, 301 icon_size size, BBitmap* result) 302 { 303 if (!result || result->InitCheck()) 304 return B_BAD_VALUE; 305 306 status_t ret = B_ERROR; 307 308 switch (result->ColorSpace()) { 309 case B_RGBA32: 310 case B_RGB32: 311 // prefer vector icon 312 ret = GetVectorIcon(node, vectorIconAttrName, result); 313 if (ret < B_OK) { 314 // try to fallback to B_CMAP8 icons 315 // (converting to B_RGBA32 is handled) 316 317 // override size 318 if (result->Bounds().IntegerWidth() + 1 >= 32) 319 size = B_LARGE_ICON; 320 else 321 size = B_MINI_ICON; 322 323 ret = GetCMAP8Icon(node, smallIconAttrName, largeIconAttrName, 324 size, result); 325 } 326 break; 327 328 case B_CMAP8: 329 // prefer old B_CMAP8 icons 330 ret = GetCMAP8Icon(node, smallIconAttrName, largeIconAttrName, 331 size, result); 332 if (ret < B_OK) { 333 // try to fallback to vector icon 334 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 335 BBitmap temp(result->Bounds(), B_BITMAP_NO_SERVER_LINK, 336 B_RGBA32); 337 #else 338 BBitmap temp(result->Bounds(), B_RGBA32); 339 #endif 340 ret = temp.InitCheck(); 341 if (ret < B_OK) 342 break; 343 ret = GetVectorIcon(node, vectorIconAttrName, &temp); 344 if (ret < B_OK) 345 break; 346 uint32 width = temp.Bounds().IntegerWidth() + 1; 347 uint32 height = temp.Bounds().IntegerHeight() + 1; 348 uint32 bytesPerRow = temp.BytesPerRow(); 349 ret = ConvertToCMAP8((uint8*)temp.Bits(), width, height, 350 bytesPerRow, result); 351 } 352 break; 353 default: 354 printf("BIconUtils::GetIcon() - unsupported colorspace\n"); 355 break; 356 } 357 358 return ret; 359 } 360 361 362 // #pragma mark - 363 364 365 status_t 366 BIconUtils::GetVectorIcon(BNode* node, const char* attrName, BBitmap* result) 367 { 368 if (!node || node->InitCheck() < B_OK || !attrName) 369 return B_BAD_VALUE; 370 371 #if TIME_VECTOR_ICONS 372 bigtime_t startTime = system_time(); 373 #endif 374 375 // get the attribute info and check type and size of the attr contents 376 attr_info attrInfo; 377 status_t ret = node->GetAttrInfo(attrName, &attrInfo); 378 if (ret < B_OK) 379 return ret; 380 381 type_code attrType = B_VECTOR_ICON_TYPE; 382 383 if (attrInfo.type != attrType) 384 return B_BAD_TYPE; 385 386 // chicken out on unrealisticly large attributes 387 if (attrInfo.size > 512 * 1024) 388 return B_BAD_VALUE; 389 390 uint8* buffer = new(std::nothrow) uint8[attrInfo.size]; 391 if (buffer == NULL) 392 return B_NO_MEMORY; 393 394 ArrayDeleter<uint8> _(buffer); 395 396 ssize_t read = node->ReadAttr(attrName, attrType, 0, buffer, 397 attrInfo.size); 398 if (read != attrInfo.size) 399 return B_ERROR; 400 401 #if TIME_VECTOR_ICONS 402 bigtime_t importTime = system_time(); 403 #endif 404 405 ret = GetVectorIcon(buffer, attrInfo.size, result); 406 if (ret < B_OK) 407 return ret; 408 409 #if TIME_VECTOR_ICONS 410 bigtime_t finishTime = system_time(); 411 printf("read: %lld, import: %lld\n", importTime - startTime, finishTime - importTime); 412 #endif 413 414 return B_OK; 415 } 416 417 418 status_t 419 BIconUtils::GetVectorIcon(const uint8* buffer, size_t size, BBitmap* result) 420 { 421 if (!result) 422 return B_BAD_VALUE; 423 424 status_t ret = result->InitCheck(); 425 if (ret < B_OK) 426 return ret; 427 428 BBitmap* temp = result; 429 ObjectDeleter<BBitmap> deleter; 430 431 if (result->ColorSpace() != B_RGBA32 && result->ColorSpace() != B_RGB32) { 432 temp = new (nothrow) BBitmap(result->Bounds(), 433 B_BITMAP_NO_SERVER_LINK, B_RGBA32); 434 deleter.SetTo(temp); 435 if (!temp || temp->InitCheck() != B_OK) 436 return B_NO_MEMORY; 437 } 438 439 Icon icon; 440 ret = icon.InitCheck(); 441 if (ret < B_OK) 442 return ret; 443 444 FlatIconImporter importer; 445 ret = importer.Import(&icon, const_cast<uint8*>(buffer), size); 446 if (ret < B_OK) { 447 // try the message based format used by Icon-O-Matic 448 MessageImporter messageImporter; 449 BMemoryIO memoryIO(const_cast<uint8*>(buffer), size); 450 ret = messageImporter.Import(&icon, &memoryIO); 451 if (ret < B_OK) 452 return ret; 453 } 454 455 IconRenderer renderer(temp); 456 renderer.SetIcon(&icon); 457 renderer.SetScale((temp->Bounds().Width() + 1.0) / 64.0); 458 renderer.Render(); 459 460 if (temp != result) { 461 uint8* src = (uint8*)temp->Bits(); 462 uint32 width = temp->Bounds().IntegerWidth() + 1; 463 uint32 height = temp->Bounds().IntegerHeight() + 1; 464 uint32 srcBPR = temp->BytesPerRow(); 465 ret = ConvertToCMAP8(src, width, height, srcBPR, result); 466 } 467 468 // TODO: would be nice to get rid of this 469 // (B_RGBA32_PREMULTIPLIED or better yet, new blending_mode) 470 // NOTE: probably not necessary only because 471 // transparent colors are "black" in all existing icons 472 // lighter transparent colors should be too dark if 473 // app_server uses correct blending 474 // renderer.Demultiply(); 475 476 return ret; 477 } 478 479 480 // #pragma mark - 481 482 483 status_t 484 BIconUtils::GetCMAP8Icon(BNode* node, const char* smallIconAttrName, 485 const char* largeIconAttrName, icon_size size, BBitmap* icon) 486 { 487 // check parameters and initialization 488 if (!icon || icon->InitCheck() != B_OK 489 || !node || node->InitCheck() != B_OK 490 || !smallIconAttrName || !largeIconAttrName) 491 return B_BAD_VALUE; 492 493 status_t ret = B_OK; 494 495 // NOTE: this might be changed if other icon 496 // sizes are supported in B_CMAP8 attributes, 497 // but this is currently not the case, so we 498 // relax the requirement to pass an icon 499 // of just the right size 500 if (size < B_LARGE_ICON) 501 size = B_MINI_ICON; 502 else 503 size = B_LARGE_ICON; 504 505 // set some icon size related variables 506 const char *attribute = NULL; 507 BRect bounds; 508 uint32 attrType = 0; 509 size_t attrSize = 0; 510 switch (size) { 511 case B_MINI_ICON: 512 attribute = smallIconAttrName; 513 bounds.Set(0, 0, 15, 15); 514 attrType = B_MINI_ICON_TYPE; 515 attrSize = 16 * 16; 516 break; 517 case B_LARGE_ICON: 518 attribute = largeIconAttrName; 519 bounds.Set(0, 0, 31, 31); 520 attrType = B_LARGE_ICON_TYPE; 521 attrSize = 32 * 32; 522 break; 523 default: 524 // can not happen, see above 525 ret = B_BAD_VALUE; 526 break; 527 } 528 529 // get the attribute info and check type and size of the attr contents 530 attr_info attrInfo; 531 if (ret == B_OK) 532 ret = node->GetAttrInfo(attribute, &attrInfo); 533 if (ret == B_OK && attrInfo.type != attrType) 534 ret = B_BAD_TYPE; 535 if (ret == B_OK && attrInfo.size != attrSize) 536 ret = B_BAD_DATA; 537 538 // check parameters 539 // currently, scaling B_CMAP8 icons is not supported 540 if (icon->ColorSpace() == B_CMAP8 && icon->Bounds() != bounds) 541 return B_BAD_VALUE; 542 543 // read the attribute 544 if (ret == B_OK) { 545 bool tempBuffer = (icon->ColorSpace() != B_CMAP8 546 || icon->Bounds() != bounds); 547 uint8* buffer = NULL; 548 ssize_t read; 549 if (tempBuffer) { 550 // other color space or bitmap size than stored in attribute 551 buffer = new(nothrow) uint8[attrSize]; 552 if (!buffer) { 553 ret = B_NO_MEMORY; 554 } else { 555 read = node->ReadAttr(attribute, attrType, 0, buffer, attrSize); 556 } 557 } else { 558 read = node->ReadAttr(attribute, attrType, 0, icon->Bits(), 559 attrSize); 560 } 561 if (ret == B_OK) { 562 if (read < 0) 563 ret = read; 564 else if (read != (ssize_t)attrSize) 565 ret = B_ERROR; 566 } 567 if (tempBuffer) { 568 // other color space than stored in attribute 569 if (ret == B_OK) { 570 ret = ConvertFromCMAP8(buffer, (uint32)size, (uint32)size, 571 (uint32)size, icon); 572 } 573 delete[] buffer; 574 } 575 } 576 return ret; 577 } 578 579 580 // #pragma mark - 581 582 583 status_t 584 BIconUtils::ConvertFromCMAP8(BBitmap* source, BBitmap* result) 585 { 586 if (source == NULL || source->ColorSpace() != B_CMAP8) 587 return B_BAD_VALUE; 588 589 status_t status = source->InitCheck(); 590 if (status < B_OK) 591 return status; 592 593 status = result->InitCheck(); 594 if (status < B_OK) 595 return status; 596 597 uint8* src = (uint8*)source->Bits(); 598 uint32 srcBPR = source->BytesPerRow(); 599 uint32 width = source->Bounds().IntegerWidth() + 1; 600 uint32 height = source->Bounds().IntegerHeight() + 1; 601 602 return ConvertFromCMAP8(src, width, height, srcBPR, result); 603 } 604 605 606 status_t 607 BIconUtils::ConvertToCMAP8(BBitmap* source, BBitmap* result) 608 { 609 if (source == NULL || source->ColorSpace() != B_RGBA32 610 || result->ColorSpace() != B_CMAP8) 611 return B_BAD_VALUE; 612 613 status_t status = source->InitCheck(); 614 if (status < B_OK) 615 return status; 616 617 status = result->InitCheck(); 618 if (status < B_OK) 619 return status; 620 621 uint8* src = (uint8*)source->Bits(); 622 uint32 srcBPR = source->BytesPerRow(); 623 uint32 width = source->Bounds().IntegerWidth() + 1; 624 uint32 height = source->Bounds().IntegerHeight() + 1; 625 626 return ConvertToCMAP8(src, width, height, srcBPR, result); 627 } 628 629 630 status_t 631 BIconUtils::ConvertFromCMAP8(const uint8* src, uint32 width, uint32 height, 632 uint32 srcBPR, BBitmap* result) 633 { 634 if (src == NULL || result == NULL || srcBPR == 0) 635 return B_BAD_VALUE; 636 637 status_t ret = result->InitCheck(); 638 if (ret < B_OK) 639 return ret; 640 641 if (result->ColorSpace() != B_RGBA32 && result->ColorSpace() != B_RGB32) { 642 // TODO: support other color spaces 643 return B_BAD_VALUE; 644 } 645 646 uint32 dstWidth = result->Bounds().IntegerWidth() + 1; 647 uint32 dstHeight = result->Bounds().IntegerHeight() + 1; 648 649 uint8* dst = (uint8*)result->Bits(); 650 uint32 dstBPR = result->BytesPerRow(); 651 652 // check for downscaling or integer multiple scaling 653 if (dstWidth < width || dstHeight < height 654 || (dstWidth == 2 * width && dstHeight == 2 * height) 655 || (dstWidth == 3 * width && dstHeight == 3 * height) 656 || (dstWidth == 4 * width && dstHeight == 4 * height)) { 657 BBitmap* converted = new BBitmap(BRect(0, 0, width - 1, height - 1), 658 result->ColorSpace()); 659 converted->ImportBits(src, height * srcBPR, srcBPR, 0, B_CMAP8); 660 uint8* convertedBits = (uint8*)converted->Bits(); 661 int32 convertedBPR = converted->BytesPerRow(); 662 663 if (dstWidth < width || dstHeight < height) 664 scale_down(convertedBits, dst, width, height, dstWidth, dstHeight); 665 else if (dstWidth == 2 * width && dstHeight == 2 * height) 666 scale2x(convertedBits, dst, width, height, convertedBPR, dstBPR); 667 else if (dstWidth == 3 * width && dstHeight == 3 * height) 668 scale3x(convertedBits, dst, width, height, convertedBPR, dstBPR); 669 else if (dstWidth == 4 * width && dstHeight == 4 * height) 670 scale4x(convertedBits, dst, width, height, convertedBPR, dstBPR); 671 672 delete converted; 673 return B_OK; 674 } 675 676 const rgb_color* colorMap = system_colors()->color_list; 677 if (colorMap == NULL) 678 return B_NO_INIT; 679 680 const uint8* srcStart = src; 681 uint8* dstStart = dst; 682 683 // convert from B_CMAP8 to B_RGB(A)32 without scaling 684 for (uint32 y = 0; y < height; y++) { 685 uint32* d = (uint32*)dst; 686 const uint8* s = src; 687 for (uint32 x = 0; x < width; x++, s++, d++) { 688 const rgb_color c = colorMap[*s]; 689 uint8 alpha = 0xff; 690 if (*s == B_TRANSPARENT_MAGIC_CMAP8) 691 alpha = 0; 692 *d = (alpha << 24) | (c.red << 16) | (c.green << 8) | (c.blue); 693 } 694 src += srcBPR; 695 dst += dstBPR; 696 } 697 698 if (width == dstWidth && height == dstHeight) 699 return B_OK; 700 701 // reset src and dst back to their original locations 702 src = srcStart; 703 dst = dstStart; 704 705 if (dstWidth > width && dstHeight > height 706 && dstWidth < 2 * width && dstHeight < 2 * height) { 707 // scale2x then downscale 708 BBitmap* temp = new BBitmap(BRect(0, 0, width * 2 - 1, height * 2 - 1), 709 result->ColorSpace()); 710 uint8* tempBits = (uint8*)temp->Bits(); 711 uint32 tempBPR = temp->BytesPerRow(); 712 scale2x(dst, tempBits, width, height, dstBPR, tempBPR); 713 scale_down(tempBits, dst, width * 2, height * 2, dstWidth, dstHeight); 714 delete temp; 715 } else if (dstWidth > 2 * width && dstHeight > 2 * height 716 && dstWidth < 3 * width && dstHeight < 3 * height) { 717 // scale3x then downscale 718 BBitmap* temp = new BBitmap(BRect(0, 0, width * 3 - 1, height * 3 - 1), 719 result->ColorSpace()); 720 uint8* tempBits = (uint8*)temp->Bits(); 721 uint32 tempBPR = temp->BytesPerRow(); 722 scale3x(dst, tempBits, width, height, dstBPR, tempBPR); 723 scale_down(tempBits, dst, width * 3, height * 3, dstWidth, dstHeight); 724 delete temp; 725 } else if (dstWidth > 3 * width && dstHeight > 3 * height 726 && dstWidth < 4 * width && dstHeight < 4 * height) { 727 // scale4x then downscale 728 BBitmap* temp = new BBitmap(BRect(0, 0, width * 4 - 1, height * 4 - 1), 729 result->ColorSpace()); 730 uint8* tempBits = (uint8*)temp->Bits(); 731 uint32 tempBPR = temp->BytesPerRow(); 732 scale4x(dst, tempBits, width, height, dstBPR, tempBPR); 733 scale_down(tempBits, dst, width * 3, height * 3, dstWidth, dstHeight); 734 delete temp; 735 } else if (dstWidth > 4 * width && dstHeight > 4 * height) { 736 // scale4x then bilinear 737 BBitmap* temp = new BBitmap(BRect(0, 0, width * 4 - 1, height * 4 - 1), 738 result->ColorSpace()); 739 uint8* tempBits = (uint8*)temp->Bits(); 740 uint32 tempBPR = temp->BytesPerRow(); 741 scale4x(dst, tempBits, width, height, dstBPR, tempBPR); 742 result->ImportBits(tempBits, height * tempBPR, tempBPR, 0, 743 temp->ColorSpace()); 744 scale_bilinear(dst, width, height, dstWidth, dstHeight, dstBPR); 745 delete temp; 746 } else { 747 // fall back to bilinear scaling 748 scale_bilinear(dst, width, height, dstWidth, dstHeight, dstBPR); 749 } 750 751 return B_OK; 752 } 753 754 755 status_t 756 BIconUtils::ConvertToCMAP8(const uint8* src, uint32 width, uint32 height, 757 uint32 srcBPR, BBitmap* result) 758 { 759 if (!src || !result || srcBPR == 0) 760 return B_BAD_VALUE; 761 762 status_t ret = result->InitCheck(); 763 if (ret < B_OK) 764 return ret; 765 766 if (result->ColorSpace() != B_CMAP8) 767 return B_BAD_VALUE; 768 769 uint32 dstWidth = result->Bounds().IntegerWidth() + 1; 770 uint32 dstHeight = result->Bounds().IntegerHeight() + 1; 771 772 if (dstWidth < width || dstHeight < height) { 773 // TODO: down scaling 774 return B_ERROR; 775 } else if (dstWidth > width || dstHeight > height) { 776 // TODO: up scaling 777 // (currently copies bitmap into result at left-top) 778 memset(result->Bits(), 255, result->BitsLength()); 779 } 780 781 //#if __HAIKU__ 782 // 783 // return result->ImportBits(src, height * srcBPR, srcBPR, 0, B_RGBA32); 784 // 785 //#else 786 787 uint8* dst = (uint8*)result->Bits(); 788 uint32 dstBPR = result->BytesPerRow(); 789 790 const color_map* colorMap = system_colors(); 791 if (colorMap == NULL) 792 return B_NO_INIT; 793 794 uint16 index; 795 796 for (uint32 y = 0; y < height; y++) { 797 uint8* d = dst; 798 const uint8* s = src; 799 for (uint32 x = 0; x < width; x++) { 800 if (s[3] < 128) { 801 *d = B_TRANSPARENT_MAGIC_CMAP8; 802 } else { 803 index = ((s[2] & 0xf8) << 7) | ((s[1] & 0xf8) << 2) 804 | (s[0] >> 3); 805 *d = colorMap->index_map[index]; 806 } 807 s += 4; 808 d += 1; 809 } 810 src += srcBPR; 811 dst += dstBPR; 812 } 813 814 return B_OK; 815 816 //#endif // __HAIKU__ 817 } 818 819 820 // #pragma mark - forbidden 821 822 823 BIconUtils::BIconUtils() {} 824 BIconUtils::~BIconUtils() {} 825 BIconUtils::BIconUtils(const BIconUtils&) {} 826 BIconUtils& BIconUtils::operator=(const BIconUtils&) { return *this; } 827 828