1/* colorspace.cpp */ 2/* 3 Copyright 1999, Be Incorporated. All Rights Reserved. 4 This file may be used under the terms of the Be Sample Code License. 5*/ 6 7 8#include <Debug.h> 9#include <GraphicsDefs.h> 10#include <InterfaceDefs.h> 11 12#include <stdio.h> 13#include <stdlib.h> 14#include <string.h> 15 16#include "colorspace.h" 17 18 19/* expands to BGRA in the output buffer from <whatever> in the input buffer */ 20int 21expand_data(color_space from_space, unsigned char* in_data, int rowbytes, 22 unsigned char* out_buf) 23{ 24 ASSERT(in_data != out_buf); 25 26 /* We don't do YUV and friends yet. */ 27 /* It's important to replicate the most significant component bits to LSB 28 * when going 15->24 */ 29 unsigned char* in_out = out_buf; 30 switch (from_space) { 31 case B_RGB32: 32 while (rowbytes > 3) { 33 out_buf[0] = in_data[0]; 34 out_buf[1] = in_data[1]; 35 out_buf[2] = in_data[2]; 36 out_buf[3] = 255; 37 out_buf += 4; 38 in_data += 4; 39 rowbytes -= 4; 40 } 41 break; 42 case B_RGBA32: 43 memcpy(out_buf, in_data, rowbytes); 44 break; 45 case B_RGB24: 46 while (rowbytes > 2) { 47 out_buf[0] = in_data[0]; 48 out_buf[1] = in_data[1]; 49 out_buf[2] = in_data[2]; 50 out_buf[3] = 255; 51 out_buf += 4; 52 in_data += 3; 53 rowbytes -= 3; 54 } 55 break; 56 case B_RGB15: 57 while (rowbytes > 1) { 58 uint16 val = in_data[0] + (in_data[1] << 8); 59 out_buf[0] = ((val & 0x1f) << 3) | ((val & 0x1f) >> 2); 60 out_buf[1] = ((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7); 61 out_buf[2] = ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12); 62 out_buf[3] = 255; 63 out_buf += 4; 64 in_data += 2; 65 rowbytes -= 2; 66 } 67 break; 68 case B_RGBA15: 69 while (rowbytes > 1) { 70 uint16 val = in_data[0] + (in_data[1] << 8); 71 out_buf[0] = ((val & 0x1f) << 3) | ((val & 0x1f) >> 2); 72 out_buf[1] = ((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7); 73 out_buf[2] = ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12); 74 out_buf[3] = (val & 0x8000) ? 255 : 0; 75 out_buf += 4; 76 in_data += 2; 77 rowbytes -= 2; 78 } 79 break; 80 case B_RGB16: 81 while (rowbytes > 1) { 82 uint16 val = in_data[0] + (in_data[1] << 8); 83 out_buf[0] = ((val & 0x1f) << 3) | ((val & 0x1f) >> 2); 84 out_buf[1] = ((val & 0x7e0) >> 3) | ((val & 0x7e0) >> 9); 85 out_buf[2] = ((val & 0xf800) >> 8) | ((val & 0xf800) >> 13); 86 out_buf[3] = 255; 87 out_buf += 4; 88 in_data += 2; 89 rowbytes -= 2; 90 } 91 break; 92 case B_RGB32_BIG: 93 while (rowbytes > 3) { 94 out_buf[0] = in_data[3]; 95 out_buf[1] = in_data[2]; 96 out_buf[2] = in_data[1]; 97 out_buf[3] = 255; 98 out_buf += 4; 99 in_data += 4; 100 rowbytes -= 4; 101 } 102 break; 103 case B_RGBA32_BIG: 104 while (rowbytes > 3) { 105 out_buf[0] = in_data[3]; 106 out_buf[1] = in_data[2]; 107 out_buf[2] = in_data[1]; 108 out_buf[3] = in_data[0]; 109 out_buf += 4; 110 in_data += 4; 111 rowbytes -= 4; 112 } 113 break; 114 case B_RGB24_BIG: 115 while (rowbytes > 2) { 116 out_buf[0] = in_data[2]; 117 out_buf[1] = in_data[1]; 118 out_buf[2] = in_data[0]; 119 out_buf[3] = 255; 120 out_buf += 4; 121 in_data += 3; 122 rowbytes -= 3; 123 } 124 break; 125 case B_RGB15_BIG: 126 while (rowbytes > 1) { 127 uint16 val = in_data[1] + (in_data[0] << 8); 128 out_buf[0] = ((val & 0x1f) << 3) | ((val & 0x1f) >> 2); 129 out_buf[1] = ((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7); 130 out_buf[2] = ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12); 131 out_buf[3] = 255; 132 out_buf += 4; 133 in_data += 2; 134 rowbytes -= 2; 135 } 136 break; 137 case B_RGBA15_BIG: 138 while (rowbytes > 1) { 139 uint16 val = in_data[1] + (in_data[0] << 8); 140 out_buf[0] = ((val & 0x1f) << 3) | ((val & 0x1f) >> 2); 141 out_buf[1] = ((val & 0x3e0) >> 2) | ((val & 0x3e0) >> 7); 142 out_buf[2] = ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12); 143 out_buf[3] = (val & 0x8000) ? 255 : 0; 144 out_buf += 4; 145 in_data += 2; 146 rowbytes -= 2; 147 } 148 break; 149 case B_RGB16_BIG: 150 while (rowbytes > 1) { 151 uint16 val = in_data[1] + (in_data[0] << 8); 152 out_buf[0] = ((val & 0x1f) << 3) | ((val & 0x1f) >> 2); 153 out_buf[1] = ((val & 0x7e0) >> 3) | ((val & 0x7e0) >> 9); 154 out_buf[2] = ((val & 0xf800) >> 8) | ((val & 0xf800) >> 13); 155 out_buf[3] = 255; 156 out_buf += 4; 157 in_data += 2; 158 rowbytes -= 2; 159 } 160 break; 161 case B_CMAP8: { 162 const color_map* map = system_colors(); 163 while (rowbytes > 0) { 164 rgb_color c = map->color_list[in_data[0]]; 165 out_buf[0] = c.blue; 166 out_buf[1] = c.green; 167 out_buf[2] = c.red; 168 out_buf[3] = c.alpha; 169 out_buf += 4; 170 in_data += 1; 171 rowbytes -= 1; 172 } 173 } break; 174 case B_GRAY8: 175 while (rowbytes > 0) { 176 unsigned char ch = *in_data; 177 out_buf[0] = ch; 178 out_buf[1] = ch; 179 out_buf[2] = ch; 180 out_buf[3] = 255; 181 out_buf += 4; 182 in_data += 1; 183 rowbytes -= 1; 184 } 185 break; 186 case B_GRAY1: 187 while (rowbytes > 0) { /* expansion 1->32 is pretty good :-) */ 188 unsigned char c1 = *in_data; 189 for (int b = 128; b; b = b >> 1) { 190 unsigned char ch; 191 if (c1 & b) { 192 ch = 0; 193 } else { 194 ch = 255; 195 } 196 out_buf[0] = ch; 197 out_buf[1] = ch; 198 out_buf[2] = ch; 199 out_buf[3] = 255; 200 out_buf += 4; 201 } 202 in_data += 1; 203 rowbytes -= 1; 204 } 205 break; 206 case B_CMY24: /* We do the "clean" inversion which doesn't correct 207 for printing ink deficiencies. */ 208 while (rowbytes > 2) { 209 out_buf[0] = 255 - in_data[2]; 210 out_buf[1] = 255 - in_data[1]; 211 out_buf[2] = 255 - in_data[0]; 212 out_buf[3] = 255; 213 out_buf += 4; 214 in_data += 3; 215 rowbytes -= 3; 216 } 217 break; 218 case B_CMY32: 219 while (rowbytes > 3) { 220 out_buf[0] = 255 - in_data[2]; 221 out_buf[1] = 255 - in_data[1]; 222 out_buf[2] = 255 - in_data[0]; 223 out_buf[3] = 255; 224 out_buf += 4; 225 in_data += 4; 226 rowbytes -= 4; 227 } 228 break; 229 case B_CMYA32: 230 while (rowbytes > 3) { 231 out_buf[0] = 255 - in_data[2]; 232 out_buf[1] = 255 - in_data[1]; 233 out_buf[2] = 255 - in_data[0]; 234 out_buf[3] = in_data[3]; 235 out_buf += 4; 236 in_data += 4; 237 rowbytes -= 4; 238 } 239 break; 240 case B_CMYK32: /* We assume uniform gray removal, and no 241 under-color-removal. */ 242 while (rowbytes > 3) { 243 int comp = 255 - in_data[2] - in_data[3]; 244 out_buf[0] = comp < 0 ? 0 : comp; 245 comp = 255 - in_data[1] - in_data[3]; 246 out_buf[1] = comp < 0 ? 0 : comp; 247 comp = 255 - in_data[0] - in_data[3]; 248 out_buf[2] = comp < 0 ? 0 : comp; 249 out_buf[3] = 255; 250 out_buf += 4; 251 in_data += 4; 252 rowbytes -= 4; 253 } 254 break; 255 default: 256 break; 257 } 258 return out_buf - in_out; 259} 260 261 262int 263collapse_data(unsigned char* in_buf, int num_bytes, color_space out_space, 264 unsigned char* out_buf) 265{ 266 ASSERT(in_buf != out_buf); 267 268 unsigned char* in_out = out_buf; 269 /* We could increase perceived image quality of down conversions by 270 * implementing */ 271 /* dithering. However, someone might want to operate on the images after 272 */ 273 /* conversion, in which case dithering would be un-good. Besides, good 274 * error */ 275 /* diffusion requires more than one scan line to propagate errors to. */ 276 switch (out_space) { 277 case B_RGB32: 278 memcpy(out_buf, in_buf, num_bytes); 279 break; 280 case B_RGBA32: 281 memcpy(out_buf, in_buf, num_bytes); 282 break; 283 case B_RGB24: 284 while (num_bytes > 3) { 285 out_buf[0] = in_buf[0]; 286 out_buf[1] = in_buf[1]; 287 out_buf[2] = in_buf[2]; 288 out_buf += 3; 289 in_buf += 4; 290 num_bytes -= 4; 291 } 292 break; 293 case B_RGB16: 294 while (num_bytes > 3) { 295 uint16 val = (in_buf[0] >> 3) | ((in_buf[1] << 3) & 0x7e0) 296 | ((in_buf[2] << 8) & 0xf800); 297 out_buf[0] = val; 298 out_buf[1] = val >> 8; 299 out_buf += 2; 300 in_buf += 4; 301 num_bytes -= 4; 302 } 303 break; 304 case B_RGB15: 305 while (num_bytes > 3) { 306 uint16 val = (in_buf[0] >> 3) | ((in_buf[1] << 2) & 0x3e0) 307 | ((in_buf[2] << 7) & 0x7c00) | 0x8000; 308 out_buf[0] = val; 309 out_buf[1] = val >> 8; 310 out_buf += 2; 311 in_buf += 4; 312 num_bytes -= 4; 313 } 314 break; 315 case B_RGBA15: 316 while (num_bytes > 3) { 317 uint16 val = (in_buf[0] >> 3) | ((in_buf[1] << 2) & 0x3e0) 318 | ((in_buf[2] << 7) & 0x7c00); 319 if (in_buf[3] > 127) { 320 val = val | 0x8000; 321 } 322 out_buf[0] = val; 323 out_buf[1] = val >> 8; 324 out_buf += 2; 325 in_buf += 4; 326 num_bytes -= 4; 327 } 328 break; 329 case B_CMAP8: { 330 const color_map* map = system_colors(); 331 while (num_bytes > 3) { 332 if (in_buf[3] < 128) { 333 out_buf[0] = B_TRANSPARENT_8_BIT; 334 } else { 335 uint16 val = (in_buf[0] >> 3) | ((in_buf[1] << 2) & 0x3e0) 336 | ((in_buf[2] << 7) & 0x7c00); 337 out_buf[0] = map->index_map[val]; 338 } 339 out_buf += 1; 340 in_buf += 4; 341 num_bytes -= 4; 342 } 343 } break; 344 case B_GRAY8: 345 while (num_bytes > 3) { /* There are better algorithms than Y = 346 .25B+.50G+.25R */ 347 /* but hardly faster -- and it's still better than (B+G+R)/3 ! 348 */ 349 out_buf[0] = (in_buf[0] + in_buf[1] * 2 + in_buf[2]) >> 2; 350 out_buf += 1; 351 in_buf += 4; 352 num_bytes -= 4; 353 } 354 break; 355 case B_GRAY1: { 356 uchar ob = 0; 357 int cnt = 0; 358 uchar c = 0; 359 while (num_bytes > 3) { 360 if (cnt == 8) { 361 out_buf[0] = ob; 362 out_buf += 1; 363 cnt = 0; 364 ob = 0; 365 } 366 c = ((in_buf[0] + in_buf[1] * 2 + in_buf[2]) & 0x200) 367 >> (2 + cnt); 368 ob = ob | c; 369 cnt++; 370 in_buf += 4; 371 num_bytes -= 4; 372 } 373 if (cnt > 0) { 374 out_buf[0] = ob; 375 out_buf += 1; 376 } 377 } break; 378 /* big endian version, when the encoding is not endianess independant */ 379 case B_RGB32_BIG: 380 while (num_bytes > 3) { 381 out_buf[3] = in_buf[0]; 382 out_buf[2] = in_buf[1]; 383 out_buf[1] = in_buf[2]; 384 out_buf += 4; 385 in_buf += 4; 386 num_bytes -= 4; 387 } 388 break; 389 case B_RGBA32_BIG: 390 while (num_bytes > 3) { 391 out_buf[3] = in_buf[0]; 392 out_buf[2] = in_buf[1]; 393 out_buf[1] = in_buf[2]; 394 out_buf[0] = in_buf[3]; 395 out_buf += 4; 396 in_buf += 4; 397 num_bytes -= 4; 398 } 399 break; 400 case B_RGB24_BIG: 401 while (num_bytes > 3) { 402 out_buf[2] = in_buf[0]; 403 out_buf[1] = in_buf[1]; 404 out_buf[0] = in_buf[2]; 405 out_buf += 3; 406 in_buf += 4; 407 num_bytes -= 4; 408 } 409 break; 410 case B_RGB16_BIG: 411 while (num_bytes > 3) { 412 uint16 val = (in_buf[0] >> 3) | ((in_buf[1] << 3) & 0x7e0) 413 | ((in_buf[2] << 8) & 0xf800); 414 out_buf[0] = val >> 8; 415 out_buf[1] = val; 416 out_buf += 2; 417 in_buf += 4; 418 num_bytes -= 4; 419 } 420 break; 421 case B_RGB15_BIG: 422 while (num_bytes > 3) { 423 uint16 val = (in_buf[0] >> 3) | ((in_buf[1] << 2) & 0x3e0) 424 | ((in_buf[2] << 7) & 0x7c00) | 0x8000; 425 out_buf[0] = val >> 8; 426 out_buf[1] = val; 427 out_buf += 2; 428 in_buf += 4; 429 num_bytes -= 4; 430 } 431 break; 432 case B_RGBA15_BIG: 433 while (num_bytes > 3) { 434 uint16 val = (in_buf[0] >> 3) | ((in_buf[1] << 2) & 0x3e0) 435 | ((in_buf[2] << 7) & 0x7c00); 436 if (in_buf[3] > 127) { 437 val = val | 0x8000; 438 } 439 out_buf[0] = val >> 8; 440 out_buf[1] = val; 441 out_buf += 2; 442 in_buf += 4; 443 num_bytes -= 4; 444 } 445 break; 446 case B_CMY24: 447 while (num_bytes > 3) { 448 out_buf[0] = 255 - in_buf[2]; 449 out_buf[1] = 255 - in_buf[1]; 450 out_buf[2] = 255 - in_buf[0]; 451 out_buf += 3; 452 in_buf += 4; 453 num_bytes -= 4; 454 } 455 break; 456 case B_CMY32: 457 while (num_bytes > 3) { 458 out_buf[0] = 255 - in_buf[2]; 459 out_buf[1] = 255 - in_buf[1]; 460 out_buf[2] = 255 - in_buf[0]; 461 out_buf += 4; 462 in_buf += 4; 463 num_bytes -= 4; 464 } 465 break; 466 case B_CMYA32: 467 while (num_bytes > 3) { 468 out_buf[0] = 255 - in_buf[2]; 469 out_buf[1] = 255 - in_buf[1]; 470 out_buf[2] = 255 - in_buf[0]; 471 out_buf[3] = in_buf[3]; 472 out_buf += 4; 473 in_buf += 4; 474 num_bytes -= 4; 475 } 476 break; 477 case B_CMYK32: 478 while (num_bytes > 3) { /* We do direct gray removal */ 479 int c = 255 - in_buf[2]; 480 int m = 255 - in_buf[1]; 481 int y = 255 - in_buf[0]; 482 int k = (c > m) ? ((y > c) ? y : c) : ((y > m) ? y : m); 483 out_buf[0] = c - k; 484 out_buf[1] = m - k; 485 out_buf[2] = y - k; 486 out_buf[3] = k; 487 out_buf += 4; 488 in_buf += 4; 489 num_bytes -= 4; 490 } 491 break; 492 default: 493 break; 494 } 495 return out_buf - in_out; 496} 497 498 499#if DEBUG_DATA 500static void 501print_data(unsigned char* ptr, int n) 502{ 503 while (n-- > 0) { 504 printf("%02x ", *(ptr++)); 505 } 506 printf("\n"); 507} 508#endif 509 510 511status_t 512convert_space(color_space in_space, color_space out_space, 513 unsigned char* in_data, int rowbytes, unsigned char* out_data) 514{ 515 ASSERT(in_data != out_data); 516 517 /* Instead of coding each transformation separately, which would create 518 */ 519 /* a very large number of conversion functions, we write one function to 520 */ 521 /* convert to RGBA32, and another function to convert from RGBA32, and */ 522 /* put them together to get a manageable program, at a slight expense in 523 */ 524 /* conversion speed. */ 525 526 int n; 527#if DEBUG_DATA 528 printf("convert_space(%x, %x, %x)\n", in_space, out_space, rowbytes); 529 printf("raw data: "); 530 print_data(in_data, rowbytes); 531#endif 532 /* If we convert from a format to itself, well... */ 533 if (in_space == out_space) { 534 memcpy(out_data, in_data, rowbytes); 535 return B_OK; 536 } 537 /* When the input format is RGBA32, we don't need the first conversion. 538 */ 539 if (in_space == B_RGBA32) { 540 n = collapse_data(in_data, rowbytes, out_space, out_data); 541#if DEBUG_DATA 542 printf("collapsed data: "); 543 print_data(out_data, n); 544#endif 545 return B_OK; 546 } 547 /* When the output format is RGBA32, we don't need any second conversion. 548 */ 549 if (out_space == B_RGB32 || out_space == B_RGBA32) { 550 n = expand_data(in_space, in_data, rowbytes, out_data); 551#if DEBUG_DATA 552 printf("expanded data: "); 553 print_data(out_data, n); 554#endif 555 return B_OK; 556 } 557 /* Figure out byte expansion rate -- usually isn't more than 4 */ 558 int mul = 4; 559 if (in_space == B_GRAY1) { 560 mul = 32; 561 } 562 unsigned char* buf = (unsigned char*) malloc(rowbytes * mul); 563 if (buf == NULL) { 564 /* oops! */ 565 return B_NO_MEMORY; 566 } 567 n = expand_data(in_space, in_data, rowbytes, buf); 568#if DEBUG_DATA 569 printf("expanded data: "); 570 print_data(out_data, n); 571#endif 572 n = collapse_data(buf, n, out_space, out_data); 573#if DEBUG_DATA 574 printf("collapsed data: "); 575 print_data(out_data, n); 576#endif 577 free(buf); 578 return B_OK; 579} 580 581 582/* Figure out what the rowbytes is for a given width in a given color space. 583 */ 584/* Rowbytes is bytes per pixel times width, rounded up to nearest multiple 585 * of 4. */ 586int 587calc_rowbytes(color_space space, int width) 588{ 589 int v = width * 4; 590 switch (space) { 591 default: 592 /* 4 is fine */ 593 break; 594 case B_RGB24: 595 case B_CMY24: 596 case B_RGB24_BIG: 597 v = width * 3; 598 break; 599 case B_RGB15: 600 case B_RGBA15: 601 case B_RGB16: 602 case B_RGB15_BIG: 603 case B_RGBA15_BIG: 604 case B_RGB16_BIG: 605 v = width * 2; 606 break; 607 case B_CMAP8: 608 case B_GRAY8: 609 v = width; 610 break; 611 case B_GRAY1: 612 v = (width + 7) / 8; /* whole bytes only, please */ 613 break; 614 } 615 v = (v + 3) & ~3; 616 return v; 617} 618