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