1 /* 2 * GraphicsDriver.cpp 3 * Copyright 1999-2000 Y.Takagi. All Rights Reserved. 4 */ 5 6 #include <algorithm> 7 #include <cstdio> 8 #include <cstdarg> 9 10 #include <Alert.h> 11 #include <Bitmap.h> 12 #include <Debug.h> 13 #include <Message.h> 14 #include <PrintJob.h> 15 #include <Region.h> 16 #include <TextControl.h> 17 #include <TextControl.h> 18 #include <StopWatch.h> 19 #include <View.h> 20 #include <Directory.h> 21 #include <File.h> 22 23 #include "GraphicsDriver.h" 24 #include "PrintProcess.h" 25 #include "JobData.h" 26 #include "PrinterData.h" 27 #include "PrinterCap.h" 28 #include "Preview.h" 29 #include "Transport.h" 30 #include "ValidRect.h" 31 #include "DbgMsg.h" 32 33 34 using namespace std; 35 36 37 // Measure printJob() time. Either true or false. 38 #define MEASURE_PRINT_JOB_TIME false 39 40 41 enum { 42 kMaxMemorySize = 4 * 1024 * 1024 43 }; 44 45 46 GraphicsDriver::GraphicsDriver(BMessage* message, PrinterData* printerData, 47 const PrinterCap* printerCap) 48 : 49 fMessage(message), 50 fView(NULL), 51 fBitmap(NULL), 52 fRotatedBitmap(NULL), 53 fTransport(NULL), 54 fOrgJobData(NULL), 55 fRealJobData(NULL), 56 fPrinterData(printerData), 57 fPrinterCap(printerCap), 58 fSpoolMetaData(NULL), 59 fPageWidth(0), 60 fPageHeight(0), 61 fBandWidth(0), 62 fBandHeight(0), 63 fPixelDepth(0), 64 fBandCount(0), 65 fInternalCopies(0), 66 fPageCount(0), 67 fStatusWindow(NULL) 68 { 69 } 70 71 72 GraphicsDriver::~GraphicsDriver() 73 { 74 } 75 76 77 static BRect 78 RotateRect(BRect rect) 79 { 80 BRect rotated(rect.top, rect.left, rect.bottom, rect.right); 81 return rotated; 82 } 83 84 85 bool 86 GraphicsDriver::_SetupData(BFile* spoolFile) 87 { 88 if (fOrgJobData != NULL) { 89 // already initialized 90 return true; 91 } 92 93 #ifndef B_BEOS_VERSION_DANO 94 print_file_header pfh; 95 #else 96 BPrintJob::print_file_header pfh; 97 #endif 98 spoolFile->Seek(0, SEEK_SET); 99 spoolFile->Read(&pfh, sizeof(pfh)); 100 101 DBGMSG(("print_file_header::version = 0x%x\n", pfh.version)); 102 DBGMSG(("print_file_header::page_count = %d\n", pfh.page_count)); 103 DBGMSG(("print_file_header::first_page = 0x%x\n", (int)pfh.first_page)); 104 105 if (pfh.page_count <= 0) { 106 // nothing to print 107 return false; 108 } 109 110 fPageCount = (uint32) pfh.page_count; 111 BMessage *msg = new BMessage(); 112 msg->Unflatten(spoolFile); 113 fOrgJobData = new JobData(msg, fPrinterCap, JobData::kJobSettings); 114 DUMP_BMESSAGE(msg); 115 delete msg; 116 117 fRealJobData = new JobData(*fOrgJobData); 118 119 switch (fOrgJobData->GetNup()) { 120 case 2: 121 case 8: 122 case 32: 123 case 128: 124 fRealJobData->SetPrintableRect( 125 RotateRect(fOrgJobData->GetPrintableRect())); 126 fRealJobData->SetScaledPrintableRect( 127 RotateRect(fOrgJobData->GetScaledPrintableRect())); 128 fRealJobData->SetPhysicalRect( 129 RotateRect(fOrgJobData->GetPhysicalRect())); 130 fRealJobData->SetScaledPhysicalRect( 131 RotateRect(fOrgJobData->GetScaledPhysicalRect())); 132 133 if (JobData::kPortrait == fOrgJobData->GetOrientation()) 134 fRealJobData->SetOrientation(JobData::kLandscape); 135 else 136 fRealJobData->SetOrientation(JobData::kPortrait); 137 break; 138 } 139 140 if (fOrgJobData->GetCollate() && fPageCount > 1) { 141 fRealJobData->SetCopies(1); 142 fInternalCopies = fOrgJobData->GetCopies(); 143 } else { 144 fInternalCopies = 1; 145 } 146 147 fSpoolMetaData = new SpoolMetaData(spoolFile); 148 return true; 149 } 150 151 152 void 153 GraphicsDriver::_CleanupData() 154 { 155 delete fRealJobData; 156 delete fOrgJobData; 157 delete fSpoolMetaData; 158 fRealJobData = NULL; 159 fOrgJobData = NULL; 160 fSpoolMetaData = NULL; 161 } 162 163 164 void 165 GraphicsDriver::_SetupBitmap() 166 { 167 fPixelDepth = color_space2pixel_depth(fOrgJobData->GetSurfaceType()); 168 169 fPageWidth = (fRealJobData->GetPhysicalRect().IntegerWidth() 170 * fOrgJobData->GetXres() + 71) / 72; 171 fPageHeight = (fRealJobData->GetPhysicalRect().IntegerHeight() 172 * fOrgJobData->GetYres() + 71) / 72; 173 174 int widthByte = (fPageWidth * fPixelDepth + 7) / 8; 175 int size = widthByte * fPageHeight; 176 #ifdef USE_PREVIEW_FOR_DEBUG 177 size = 0; 178 #endif 179 180 if (size < kMaxMemorySize) { 181 fBandCount = 0; 182 fBandWidth = fPageWidth; 183 fBandHeight = fPageHeight; 184 } else { 185 fBandCount = (size + kMaxMemorySize - 1) / kMaxMemorySize; 186 if (_NeedRotateBitmapBand()) { 187 fBandWidth = (fPageWidth + fBandCount - 1) / fBandCount; 188 fBandHeight = fPageHeight; 189 } else { 190 fBandWidth = fPageWidth; 191 fBandHeight = (fPageHeight + fBandCount - 1) / fBandCount; 192 } 193 } 194 195 DBGMSG(("****************\n")); 196 DBGMSG(("page_width = %d\n", fPageWidth)); 197 DBGMSG(("page_height = %d\n", fPageHeight)); 198 DBGMSG(("band_count = %d\n", fBandCount)); 199 DBGMSG(("band_height = %d\n", fBandHeight)); 200 DBGMSG(("****************\n")); 201 202 BRect rect; 203 rect.Set(0, 0, fBandWidth - 1, fBandHeight - 1); 204 fBitmap = new BBitmap(rect, fOrgJobData->GetSurfaceType(), true); 205 fView = new BView(rect, "", B_FOLLOW_ALL, B_WILL_DRAW); 206 fBitmap->AddChild(fView); 207 208 if (_NeedRotateBitmapBand()) { 209 BRect rotatedRect(0, 0, rect.bottom, rect.right); 210 fRotatedBitmap = new BBitmap(rotatedRect, fOrgJobData->GetSurfaceType(), 211 false); 212 } 213 } 214 215 216 void 217 GraphicsDriver::_CleanupBitmap() 218 { 219 delete fBitmap; 220 fBitmap = NULL; 221 fView = NULL; 222 223 delete fRotatedBitmap; 224 fRotatedBitmap = NULL; 225 } 226 227 228 BPoint 229 GraphicsDriver::GetScale(int32 nup, BRect physicalRect, float scaling) 230 { 231 float width; 232 float height; 233 BPoint scale; 234 235 scale.x = scale.y = 1.0f; 236 237 switch (nup) { 238 case 1: 239 scale.x = scale.y = 1.0f; 240 break; 241 case 2: /* 1x2 or 2x1 */ 242 width = physicalRect.Width(); 243 height = physicalRect.Height(); 244 if (width < height) { // portrait 245 scale.x = height / 2.0f / width; 246 scale.y = width / height; 247 } else { // landscape 248 scale.x = height / width; 249 scale.y = width / 2.0f / height; 250 } 251 break; 252 case 8: /* 2x4 or 4x2 */ 253 width = physicalRect.Width(); 254 height = physicalRect.Height(); 255 if (width < height) { 256 scale.x = height / 4.0f / width; 257 scale.y = width / height / 2.0f; 258 } else { 259 scale.x = height / width / 2.0f; 260 scale.y = width / 4.0f / height; 261 } 262 break; 263 case 32: /* 4x8 or 8x4 */ 264 width = physicalRect.Width(); 265 height = physicalRect.Height(); 266 if (width < height) { 267 scale.x = height / 8.0f / width; 268 scale.y = width / height / 4.0f; 269 } else { 270 scale.x = height / width / 4.0f; 271 scale.y = width / 8.0f / height; 272 } 273 break; 274 case 4: /* 2x2 */ 275 scale.x = scale.y = 1.0f / 2.0f; 276 break; 277 case 9: /* 3x3 */ 278 scale.x = scale.y = 1.0f / 3.0f; 279 break; 280 case 16: /* 4x4 */ 281 scale.x = scale.y = 1.0f / 4.0f; 282 break; 283 case 25: /* 5x5 */ 284 scale.x = scale.y = 1.0f / 5.0f; 285 break; 286 case 36: /* 6x6 */ 287 scale.x = scale.y = 1.0f / 6.0f; 288 break; 289 case 49: /* 7x7 */ 290 scale.x = scale.y = 1.0f / 7.0f; 291 break; 292 case 64: /* 8x8 */ 293 scale.x = scale.y = 1.0f / 8.0f; 294 break; 295 case 81: /* 9x9 */ 296 scale.x = scale.y = 1.0f / 9.0f; 297 break; 298 case 100: /* 10x10 */ 299 scale.x = scale.y = 1.0f / 10.0f; 300 break; 301 case 121: /* 11x11 */ 302 scale.x = scale.y = 1.0f / 11.0f; 303 break; 304 } 305 306 scale.x = scale.x * scaling / 100.0; 307 scale.y = scale.y * scaling / 100.0; 308 309 return scale; 310 } 311 312 313 BPoint 314 GraphicsDriver::GetOffset(int32 nup, int index, 315 JobData::Orientation orientation, const BPoint* scale, 316 BRect scaledPhysicalRect, BRect scaledPrintableRect, 317 BRect physicalRect) 318 { 319 BPoint offset; 320 offset.x = 0; 321 offset.y = 0; 322 323 float width = scaledPhysicalRect.Width(); 324 float height = scaledPhysicalRect.Height(); 325 326 switch (nup) { 327 case 1: 328 break; 329 case 2: 330 if (index == 1) { 331 if (JobData::kPortrait == orientation) { 332 offset.x = width; 333 } else { 334 offset.y = height; 335 } 336 } 337 break; 338 case 8: 339 if (JobData::kPortrait == orientation) { 340 offset.x = width * (index / 2); 341 offset.y = height * (index % 2); 342 } else { 343 offset.x = width * (index % 2); 344 offset.y = height * (index / 2); 345 } 346 break; 347 case 32: 348 if (JobData::kPortrait == orientation) { 349 offset.x = width * (index / 4); 350 offset.y = height * (index % 4); 351 } else { 352 offset.x = width * (index % 4); 353 offset.y = height * (index / 4); 354 } 355 break; 356 case 4: 357 offset.x = width * (index / 2); 358 offset.y = height * (index % 2); 359 break; 360 case 9: 361 offset.x = width * (index / 3); 362 offset.y = height * (index % 3); 363 break; 364 case 16: 365 offset.x = width * (index / 4); 366 offset.y = height * (index % 4); 367 break; 368 case 25: 369 offset.x = width * (index / 5); 370 offset.y = height * (index % 5); 371 break; 372 case 36: 373 offset.x = width * (index / 6); 374 offset.y = height * (index % 6); 375 break; 376 case 49: 377 offset.x = width * (index / 7); 378 offset.y = height * (index % 7); 379 break; 380 case 64: 381 offset.x = width * (index / 8); 382 offset.y = height * (index % 8); 383 break; 384 case 81: 385 offset.x = width * (index / 9); 386 offset.y = height * (index % 9); 387 break; 388 case 100: 389 offset.x = width * (index / 10); 390 offset.y = height * (index % 10); 391 break; 392 case 121: 393 offset.x = width * (index / 11); 394 offset.y = height * (index % 11); 395 break; 396 } 397 398 // adjust margin 399 offset.x += scaledPrintableRect.left - physicalRect.left; 400 offset.y += scaledPrintableRect.top - physicalRect.top; 401 402 float real_scale = min(scale->x, scale->y); 403 if (real_scale != scale->x) 404 offset.x *= scale->x / real_scale; 405 else 406 offset.y *= scale->y / real_scale; 407 408 return offset; 409 } 410 411 412 // print the specified pages on a physical page 413 bool 414 GraphicsDriver::_PrintPage(PageDataList* pages) 415 { 416 BPoint offset; 417 offset.x = 0.0f; 418 offset.y = 0.0f; 419 420 if (pages == NULL) { 421 return true; 422 } 423 424 do { 425 // clear the physical page 426 fView->SetScale(1.0); 427 fView->SetHighColor(255, 255, 255); 428 fView->ConstrainClippingRegion(NULL); 429 fView->FillRect(fView->Bounds()); 430 431 BPoint scale = GetScale(fOrgJobData->GetNup(), 432 fOrgJobData->GetPhysicalRect(), fOrgJobData->GetScaling()); 433 float real_scale = min(scale.x, scale.y) * fOrgJobData->GetXres() 434 / 72.0f; 435 fView->SetScale(real_scale); 436 float x = offset.x / real_scale; 437 float y = offset.y / real_scale; 438 int page_index = 0; 439 440 for (PageDataList::iterator it = pages->begin(); it != pages->end(); 441 it++) { 442 BPoint left_top(GetOffset(fOrgJobData->GetNup(), page_index++, 443 fOrgJobData->GetOrientation(), &scale, 444 fOrgJobData->GetScaledPhysicalRect(), 445 fOrgJobData->GetScaledPrintableRect(), 446 fOrgJobData->GetPhysicalRect())); 447 448 left_top.x -= x; 449 left_top.y -= y; 450 451 BRect clip(fOrgJobData->GetScaledPrintableRect()); 452 clip.OffsetTo(left_top); 453 454 BRegion *region = new BRegion(); 455 region->Set(clip); 456 fView->ConstrainClippingRegion(region); 457 delete region; 458 459 if ((*it)->startEnum()) { 460 bool more; 461 do { 462 PictureData *picture_data; 463 more = (*it)->enumObject(&picture_data); 464 BPoint real_offset = left_top + picture_data->point; 465 fView->DrawPicture(picture_data->picture, real_offset); 466 fView->Sync(); 467 delete picture_data; 468 } while (more); 469 } 470 } 471 472 if (!_PrintBand(fBitmap, &offset)) 473 return false; 474 475 } while (offset.x >= 0.0f && offset.y >= 0.0f); 476 477 return true; 478 } 479 480 481 bool 482 GraphicsDriver::_PrintBand(BBitmap* band, BPoint* offset) 483 { 484 if (!_NeedRotateBitmapBand()) 485 return NextBand(band, offset); 486 487 _RotateInto(fRotatedBitmap, band); 488 489 BPoint rotatedOffset(offset->y, offset->x); 490 bool success = NextBand(fRotatedBitmap, &rotatedOffset); 491 offset->x = rotatedOffset.y; 492 offset->y = rotatedOffset.x; 493 494 return success; 495 } 496 497 498 void 499 GraphicsDriver::_RotateInto(BBitmap* target, const BBitmap* source) 500 { 501 ASSERT(target->ColorSpace() == B_RGB32); 502 ASSERT(source->ColorSpace() == B_RGB32); 503 ASSERT(target->Bounds().IntegerWidth() == source->Bounds().IntegerHeight()); 504 ASSERT(target->Bounds().IntegerHeight() == source->Bounds().IntegerWidth()); 505 506 const int32 width = source->Bounds().IntegerWidth() + 1; 507 const int32 height = source->Bounds().IntegerHeight() + 1; 508 509 const int32 sourceBPR = source->BytesPerRow(); 510 const int32 targetBPR = target->BytesPerRow(); 511 512 const uint8_t* sourceBits = 513 reinterpret_cast<const uint8_t*>(source->Bits()); 514 uint8_t* targetBits = static_cast<uint8_t*>(target->Bits()); 515 516 for (int32 y = 0; y < height; y ++) { 517 for (int32 x = 0; x < width; x ++) { 518 const uint32_t* sourcePixel = 519 reinterpret_cast<const uint32_t*>(sourceBits + sourceBPR * y 520 + sizeof(uint32_t) * x); 521 522 int32 targetX = (height - y - 1); 523 int32 targetY = x; 524 uint32_t* targetPixel = 525 reinterpret_cast<uint32_t*>(targetBits + targetBPR * targetY 526 + sizeof(uint32_t) * targetX); 527 *targetPixel = *sourcePixel; 528 } 529 } 530 } 531 532 bool 533 GraphicsDriver::_CollectPages(SpoolData* spoolData, PageDataList* pages) 534 { 535 // collect the pages to be printed on the physical page 536 PageData *page_data; 537 int nup = fOrgJobData->GetNup(); 538 bool more; 539 do { 540 more = spoolData->enumObject(&page_data); 541 if (pages != NULL) 542 pages->push_back(page_data); 543 } while (more && --nup); 544 545 return more; 546 } 547 548 549 bool 550 GraphicsDriver::_SkipPages(SpoolData* spoolData) 551 { 552 return _CollectPages(spoolData, NULL); 553 } 554 555 556 bool 557 GraphicsDriver::_PrintDocument(SpoolData* spoolData) 558 { 559 bool more; 560 bool success; 561 int page_index; 562 int copy; 563 int copies; 564 565 more = true; 566 success = true; 567 page_index = 0; 568 569 if (fPrinterCap->Supports(PrinterCap::kCopyCommand)) 570 // let the printer perform the copy operation 571 copies = 1; 572 else 573 // send the page multiple times to the printer 574 copies = fRealJobData->GetCopies(); 575 576 fStatusWindow -> SetPageCopies(copies); 577 // inform fStatusWindow about number of copies 578 579 // printing of even/odd numbered pages only is valid in simplex mode 580 bool simplex = fRealJobData->GetPrintStyle() == JobData::kSimplex; 581 582 if (spoolData->startEnum()) { 583 do { 584 DBGMSG(("page index = %d\n", page_index)); 585 586 if (simplex 587 && fRealJobData->GetPageSelection() 588 == JobData::kEvenNumberedPages) 589 // skip odd numbered page 590 more = _SkipPages(spoolData); 591 592 if (!more) 593 // end reached 594 break; 595 596 PageDataList pages; 597 more = _CollectPages(spoolData, &pages); 598 599 if (more && simplex 600 && fRealJobData->GetPageSelection() 601 == JobData::kOddNumberedPages) 602 // skip even numbered page 603 more = _SkipPages(spoolData); 604 605 // print each physical page "copies" of times 606 for (copy = 0; success && copy < copies; copy ++) { 607 608 // Update the status / cancel job 609 if (fStatusWindow->UpdateStatusBar(page_index, copy)) 610 return false; 611 612 success = StartPage(page_index); 613 if (!success) 614 break; 615 616 // print the pages on the physical page 617 fView->Window()->Lock(); 618 success = _PrintPage(&pages); 619 fView->Window()->Unlock(); 620 621 if (success) { 622 success = EndPage(page_index); 623 } 624 } 625 626 page_index++; 627 } while (success && more); 628 } 629 630 #ifndef USE_PREVIEW_FOR_DEBUG 631 if (success 632 && fPrinterCap->Supports(PrinterCap::kPrintStyle) 633 && (fOrgJobData->GetPrintStyle() != JobData::kSimplex) 634 && (((page_index + fOrgJobData->GetNup() - 1) / fOrgJobData->GetNup()) 635 % 2)) { 636 // append an empty page on the back side of the page in duplex or 637 // booklet mode 638 success = 639 StartPage(page_index) && 640 _PrintPage(NULL) && 641 EndPage(page_index); 642 } 643 #endif 644 645 return success; 646 } 647 648 649 const JobData* 650 GraphicsDriver::GetJobData(BFile* spoolFile) 651 { 652 _SetupData(spoolFile); 653 return fOrgJobData; 654 } 655 656 657 bool 658 GraphicsDriver::_PrintJob(BFile* spoolFile) 659 { 660 bool success = true; 661 if (!_SetupData(spoolFile)) { 662 // silently exit if there is nothing to print 663 return true; 664 } 665 666 fTransport = new Transport(fPrinterData); 667 668 if (fTransport->CheckAbort()) { 669 success = false; 670 } else if (!fTransport->IsPrintToFileCanceled()) { 671 BStopWatch stopWatch("printJob", !MEASURE_PRINT_JOB_TIME); 672 _SetupBitmap(); 673 SpoolData spoolData(spoolFile, fPageCount, fOrgJobData->GetNup(), 674 fOrgJobData->GetReverse()); 675 success = StartDocument(); 676 if (success) { 677 fStatusWindow = new StatusWindow( 678 fRealJobData->GetPageSelection() == JobData::kOddNumberedPages, 679 fRealJobData->GetPageSelection() == JobData::kEvenNumberedPages, 680 fRealJobData->GetFirstPage(), 681 fPageCount, 682 fInternalCopies,fRealJobData->GetNup()); 683 684 while (fInternalCopies--) { 685 success = _PrintDocument(&spoolData); 686 if (success == false) { 687 break; 688 } 689 } 690 EndDocument(success); 691 692 fStatusWindow->Lock(); 693 fStatusWindow->Quit(); 694 } 695 _CleanupBitmap(); 696 _CleanupData(); 697 } 698 699 if (success == false) { 700 BAlert *alert; 701 if (fTransport->CheckAbort()) 702 alert = new BAlert("", fTransport->LastError().c_str(), "OK"); 703 else 704 alert = new BAlert("", "Printer not responding.", "OK"); 705 alert->Go(); 706 } 707 708 delete fTransport; 709 fTransport = NULL; 710 711 return success; 712 } 713 714 715 BMessage* 716 GraphicsDriver::TakeJob(BFile* spoolFile) 717 { 718 BMessage *msg; 719 if (_PrintJob(spoolFile)) 720 msg = new BMessage('okok'); 721 else 722 msg = new BMessage('baad'); 723 return msg; 724 } 725 726 727 bool 728 GraphicsDriver::StartDocument() 729 { 730 return true; 731 } 732 733 734 bool 735 GraphicsDriver::StartPage(int) 736 { 737 return true; 738 } 739 740 741 bool 742 GraphicsDriver::NextBand(BBitmap*, BPoint*) 743 { 744 return true; 745 } 746 747 748 bool 749 GraphicsDriver::EndPage(int) 750 { 751 return true; 752 } 753 754 755 bool 756 GraphicsDriver::EndDocument(bool) 757 { 758 return true; 759 } 760 761 762 void 763 GraphicsDriver::WriteSpoolData(const void* buffer, size_t size) 764 throw (TransportException) 765 { 766 if (fTransport == NULL) 767 return; 768 fTransport->Write(buffer, size); 769 } 770 771 772 void 773 GraphicsDriver::WriteSpoolString(const char* format, ...) 774 throw (TransportException) 775 { 776 if (fTransport == NULL) 777 return; 778 779 char buffer[256]; 780 va_list ap; 781 va_start(ap, format); 782 vsprintf(buffer, format, ap); 783 fTransport->Write(buffer, strlen(buffer)); 784 va_end(ap); 785 } 786 787 788 void 789 GraphicsDriver::WriteSpoolChar(char c) 790 throw (TransportException) 791 { 792 if (fTransport == NULL) 793 return; 794 795 fTransport->Write(&c, 1); 796 } 797 798 799 bool 800 GraphicsDriver::_NeedRotateBitmapBand() const 801 { 802 return JobData::kLandscape == fRealJobData->GetOrientation() 803 && !fPrinterCap->Supports(PrinterCap::kCanRotatePageInLandscape); 804 } 805 806 807 void 808 GraphicsDriver::_ConvertRGB32ToRGB24(const void* src, void* dst, int width) { 809 uint8* d = (uint8*)dst; 810 const rgb_color* s = static_cast<const rgb_color*>(src); 811 for (int i = width; i > 0; i --) { 812 *d ++ = s->red; 813 *d ++ = s->green; 814 *d ++ = s->blue; 815 s++; 816 } 817 } 818 819 820 void 821 GraphicsDriver::_ConvertCMAP8ToRGB24(const void* src, void* dst, int width) { 822 uint8* d = (uint8*)dst; 823 const uint8* s = static_cast<const uint8*>(src); 824 const color_map* cmap = system_colors(); 825 for (int i = width; i > 0; i --) { 826 const rgb_color* rgb = &cmap->color_list[*s]; 827 *d ++ = rgb->red; 828 *d ++ = rgb->green; 829 *d ++ = rgb->blue; 830 s ++; 831 } 832 } 833 834 835 void 836 GraphicsDriver::ConvertToRGB24(const void* src, void* dst, int width, 837 color_space cs) { 838 if (cs == B_RGB32) 839 _ConvertRGB32ToRGB24(src, dst, width); 840 else if (cs == B_CMAP8) 841 _ConvertCMAP8ToRGB24(src, dst, width); 842 else { 843 DBGMSG(("color_space %d not supported", cs)); 844 } 845 } 846 847 848 uint8 849 GraphicsDriver::_ConvertToGray(uint8 r, uint8 g, uint8 b) { 850 if (r == g && g == b) 851 return r; 852 else 853 return (r * 3 + g * 6 + b) / 10; 854 } 855 856 857 void 858 GraphicsDriver::_ConvertRGB32ToGray(const void* src, void* dst, int width) { 859 uint8* d = (uint8*)dst; 860 const rgb_color* s = static_cast<const rgb_color*>(src); 861 for (int i = width; i > 0; i--, s++, d++) 862 *d = _ConvertToGray(s->red, s->green, s->blue); 863 } 864 865 866 void 867 GraphicsDriver::_ConvertCMAP8ToGray(const void* src, void* dst, int width) { 868 uint8* d = (uint8*)dst; 869 const uint8* s = static_cast<const uint8*>(src); 870 const color_map* cmap = system_colors(); 871 for (int i = width; i > 0; i--, s++, d++) { 872 const rgb_color* rgb = &cmap->color_list[*s]; 873 *d = _ConvertToGray(rgb->red, rgb->green, rgb->blue); 874 } 875 } 876 877 878 void 879 GraphicsDriver::ConvertToGray(const void* src, void* dst, int width, 880 color_space cs) { 881 if (cs == B_RGB32) 882 _ConvertRGB32ToGray(src, dst, width); 883 else if (cs == B_CMAP8) 884 _ConvertCMAP8ToGray(src, dst, width); 885 else { 886 DBGMSG(("color_space %d not supported", cs)); 887 } 888 } 889 890