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