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