1/* 2 * Copyright 2001-2009, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Philippe Houdoin 7 * Simon Gauvin 8 * Michael Pfeiffer 9 */ 10 11/*! Based on: 12 - gdevbjc.c from Aladdin GhostScript 13 - LMDriver.cpp from Ryan Lockhart Lexmark 5/7xxxx BeOS driver 14*/ 15 16#include "PDFWriter.h" 17 18#include <ctype.h> 19#include <math.h> 20#include <stdio.h> 21#include <string.h> 22 23#include <Debug.h> 24#include <StorageKit.h> 25#include <TranslationKit.h> 26#include <support/UTF8.h> 27 28#include "Bezier.h" 29#include "LinePathBuilder.h" 30#include "DrawShape.h" 31#include "Log.h" 32#include "pdflib.h" 33#include "Bookmark.h" 34#include "XReferences.h" 35#include "Report.h" 36 37 38static const char* kEncodingDirectory = "PDF Writer"; 39static const char* kSettingsDirectory = "PDF Writer"; 40static const char* kBookmarksDirectory = "bookmarks"; 41static const char* kCrossReferencesDirectory = "xrefs"; 42 43 44PDFWriter::PDFWriter() 45 : 46 PrinterDriver(), 47 fTextLine(this) 48{ 49 fFontSearchOrder[0] = japanese_encoding; 50 fFontSearchOrder[1] = chinese_cns1_encoding; 51 fFontSearchOrder[2] = chinese_gb1_encoding; 52 fFontSearchOrder[3] = korean_encoding; 53 54 fPage = 0; 55 fEmbedMaxFontSize = 250 * 1024; 56 fScreen = new BScreen(); 57 fFonts = NULL; 58 fBookmark = new Bookmark(this); 59 fXRefs = new XRefDefs(); 60 fXRefDests = NULL; 61} 62 63 64PDFWriter::~PDFWriter() 65{ 66 delete fScreen; 67 delete fFonts; 68 delete fBookmark; 69 delete fXRefs; 70 delete fXRefDests; 71} 72 73 74// #pragma mark Public methods 75 76 77status_t 78PDFWriter::PrintPage(int32 pageNumber, int32 pageCount) 79{ 80 status_t status; 81 BRect r; 82 uint32 pictureCount; 83 BRect paperRect; 84 BRect printRect; 85 BRect *picRects; 86 BPoint *picPoints; 87 BRegion *picRegion; 88 BPicture **pictures; 89 uint32 i; 90 int32 orientation; 91 92 status = B_OK; 93 94 fPage = pageNumber; 95 96 if (pageNumber == 1) { 97 if (MakesPattern()) { 98 REPORT(kDebug, fPage, ">>>>> Collecting patterns..."); 99 } else if (MakesPDF()) { 100 REPORT(kDebug, fPage, ">>>>> Generating PDF..."); 101 fImageCache.NextPass(); 102 } 103 } 104 105 paperRect = JobMsg()->FindRect("paper_rect"); 106 printRect = JobMsg()->FindRect("printable_rect"); 107 if (B_OK != JobMsg()->FindInt32("orientation", &orientation)) orientation = 0; 108 if (orientation == 1) { 109 printRect.Set(printRect.top, printRect.left, 110 printRect.bottom, printRect.right); 111 } 112 113 JobFile()->Read(&pictureCount, sizeof(uint32)); 114 115 // TODO: error checking! 116 pictures = (BPicture **)malloc(pictureCount * sizeof(BPicture *)); 117 picRects = (BRect *)malloc(pictureCount * sizeof(BRect)); 118 picPoints = (BPoint *)malloc(pictureCount * sizeof(BPoint)); 119 picRegion = new BRegion(); 120 121 for (i = 0; i < pictureCount; i++) { 122 JobFile()->Seek(40 + sizeof(off_t), SEEK_CUR); 123 JobFile()->Read(&picPoints[i], sizeof(BPoint)); 124 JobFile()->Read(&picRects[i], sizeof(BRect)); 125 pictures[i] = new BPicture(); 126 pictures[i]->Unflatten(JobFile()); 127 picRegion->Include(picRects[i]); 128 } 129 130 r = picRegion->Frame(); 131 delete picRegion; 132 133 PDF_TRY(fPdf) { 134 BeginPage(paperRect, printRect); 135 for (i = 0; i < pictureCount; i++) { 136 SetOrigin(picPoints[i]); 137 PushInternalState(); 138 Iterate(pictures[i]); 139 delete pictures[i]; 140 PopInternalState(); 141 } 142 EndPage(); 143 } PDF_CATCH(fPdf) { 144 REPORT(kError, 0, PDF_get_errmsg(fPdf)); 145 } 146 147 free(pictures); 148 free(picRects); 149 free(picPoints); 150 151 return status; 152} 153 154 155status_t 156PDFWriter::BeginJob() 157{ 158 fLog = fopen("/tmp/pdf_writer.log", "w"); 159 160 PDF_boot(); 161 162 fPdf = PDF_new2(_ErrorHandler, NULL, NULL, NULL, this); 163 // set *this* as pdf cookie 164 if (fPdf == NULL) 165 return B_ERROR; 166 167 // load font embedding settings 168 fFonts = new Fonts(); 169 fFonts->CollectFonts(); 170 BMessage fonts; 171 if (B_OK == JobMsg()->FindMessage("fonts", &fonts)) 172 fFonts->SetTo(&fonts); 173 174 // set font search order 175 int j = 0; 176 font_encoding enc; 177 bool active; 178 179 for (int i = 0; j < no_of_cjk_encodings 180 && fFonts->GetCJKOrder(i, enc, active); i ++) { 181 if (active) fFontSearchOrder[j++] = enc; 182 } 183 for (; j < no_of_cjk_encodings; j ++) { 184 fFontSearchOrder[j] = invalid_encoding; 185 } 186 187 return InitWriter(); 188} 189 190 191status_t 192PDFWriter::EndJob() 193{ 194#ifdef DEBUG 195 Report* r = Report::Instance(); 196 int32 n = r->CountItems(); 197 fprintf(fLog, "Report:\n"); 198 fprintf(fLog, "=======\n"); 199 if (n == 0) { 200 fprintf(fLog, "<empty>\n"); 201 } 202 for (int32 i = 0; i < n; i++) { 203 ReportRecord* rr = r->ItemAt(i); 204 switch (rr->Kind()) { 205 case kInfo: fprintf(fLog, "Info"); break; 206 case kWarning: fprintf(fLog, "Warning"); break; 207 case kError: fprintf(fLog, "Error"); break; 208 case kDebug: fprintf(fLog, "Debug"); break; 209 } 210 fprintf(fLog, " %s", rr->Label()); 211 if (rr->Page() > 0) fprintf(fLog, " (Page %d)", (int)rr->Page()); 212 fprintf(fLog, ": %s\n", rr->Desc()); 213 } 214#endif 215 fImageCache.Flush(); 216 217 PDF_close(fPdf); 218 REPORT(kDebug, 0, ">>>> PDF_close"); 219 220 PDF_delete(fPdf); 221 PDF_shutdown(); 222 223 fclose(fLog); 224 return B_OK; 225} 226 227 228void 229PDFWriter::SetAttribute(const char* name, const char* value) 230{ 231 if (!name || !value) 232 return; 233 234 BFile *file = dynamic_cast<BFile *>(Transport()); 235 if (file != NULL) 236 file->WriteAttr(name, B_STRING_TYPE, 0, value, strlen(value) + 1); 237} 238 239 240status_t 241PDFWriter::InitWriter() 242{ 243 char buffer[512]; 244 BString s; 245 246 fState = NULL; 247 fStateDepth = 0; 248 249 // Set MIME type explicit as we *do* know it's a PDF document 250 BFile *file = dynamic_cast<BFile *>(Transport()); 251 if (file) 252 BNodeInfo(file).SetType("application/pdf"); 253 254 // pdflib scope: object 255/* 256 const char* license_key; 257 if (JobMsg()->FindString("pdflib_license_key", &license_key) == B_OK && 258 license_key[0] != 0) { 259 REPORT(kDebug, 0, "license key found %s!", license_key); 260 PDF_set_parameter(fPdf, "license", license_key); 261 } 262*/ 263 264 fPDFVersion = kPDF13; 265 const char *compatibility; 266 if (JobMsg()->FindString("pdf_compatibility", &compatibility) == B_OK) { 267 PDF_set_parameter(fPdf, "compatibility", compatibility); 268 if (strcmp(compatibility, "1.3") == 0) fPDFVersion = kPDF13; 269 else if (strcmp(compatibility, "1.4") == 0) fPDFVersion = kPDF14; 270 else if (strcmp(compatibility, "1.5") == 0) fPDFVersion = kPDF15; 271 } 272 273/* 274 // set user/master password 275 BString master_password, user_password; 276 if (JobMsg()->FindString("master_password", &master_password) == B_OK && 277 JobMsg()->FindString("user_password", &user_password) == B_OK && 278 master_password.Length() > 0 && user_password.Length() > 0) { 279 PDF_set_parameter(fPdf, "masterpassword", master_password.String()); 280 PDF_set_parameter(fPdf, "userpassword", user_password.String()); 281 } 282 283 // set permissions 284 BString permissions; 285 if (JobMsg()->FindString("permissions", &permissions) == B_OK && 286 permissions.Length() > 0) { 287 PDF_set_parameter(fPdf, "permissions", permissions.String()); 288 } 289*/ 290 291 REPORT(kDebug, 0, ">>>> PDF_open_mem"); 292 PDF_open_mem(fPdf, _WriteData); // use callback to stream PDF document data to printer transport 293 294 // pdflib scope: 295 296 PDF_set_parameter(fPdf, "flush", "content"); 297 298 // set document info 299 BMessage doc; 300 bool setTitle = true; 301 bool setCreator = true; 302 if (JobMsg()->FindMessage("doc_info", &doc) == B_OK) { 303#ifndef B_BEOS_VERSION_DANO 304 char *name; 305#else 306 const char *name; 307#endif 308 uint32 type; 309 int32 count; 310 for (int32 i = 0; doc.GetInfo(B_STRING_TYPE, i, &name, &type, &count) 311 != B_BAD_INDEX; i++) { 312 if (type == B_STRING_TYPE) { 313 BString value; 314 if (doc.FindString(name, &value) == B_OK && value != "") { 315 SetAttribute(name, value.String()); 316 BString s; 317 ToPDFUnicode(value.String(), s); 318 PDF_set_info(fPdf, name, s.String()); 319 } 320 } 321 } 322 BString s; 323 if (doc.FindString("Title", &s) == B_OK && s != "") 324 setTitle = false; 325 if (doc.FindString("Creator", &s) == B_OK && s != "") 326 setCreator = false; 327 } 328 329 // find job title 330 if (setTitle && JobFile()->ReadAttr("_spool/Description", B_STRING_TYPE, 0, 331 buffer, sizeof(buffer))) { 332 SetAttribute("Title", buffer); 333 ToPDFUnicode(buffer, s); PDF_set_info(fPdf, "Title", s.String()); 334 } 335 336 // find job creator 337 if (setCreator && JobFile()->ReadAttr("_spool/MimeType", B_STRING_TYPE, 0, 338 buffer, sizeof(buffer))) { 339 SetAttribute("Creator", buffer); 340 ToPDFUnicode(buffer, s); PDF_set_info(fPdf, "Creator", s.String()); 341 } 342 343 int32 compression; 344 if (JobMsg()->FindInt32("pdf_compression", &compression) == B_OK) { 345 PDF_set_value(fPdf, "compress", compression); 346 } 347 348 // PDF_set_parameter(fPdf, "warning", "false"); 349 350 PDF_set_parameter(fPdf, "fontwarning", "false"); 351 // PDF_set_parameter(fPdf, "native-unicode", "true"); 352 353 REPORT(kDebug, 0, "Start of declarations:"); 354 355 DeclareEncodingFiles(); 356 DeclareFonts(); 357 358 REPORT(kDebug, fPage, "End of declarations."); 359 360 // Links 361 float width; 362 if (JobMsg()->FindFloat("link_border_width", &width) != B_OK) { 363 width = 1; 364 } 365 PDF_set_border_style(fPdf, "solid", width); 366 367 if (JobMsg()->FindBool("create_web_links", &fCreateWebLinks) != B_OK) { 368 fCreateWebLinks = false; 369 } 370 371 // Bookmarks 372 if (JobMsg()->FindBool("create_bookmarks", &fCreateBookmarks) != B_OK) { 373 fCreateBookmarks = false; 374 } 375 376 if (fCreateBookmarks) { 377 BString name; 378 if (JobMsg()->FindString("bookmark_definition_file", &name) == B_OK 379 && LoadBookmarkDefinitions(name.String())) { 380 } else { 381 fCreateBookmarks = false; 382 } 383 } 384 385 // Cross References 386 if (JobMsg()->FindBool("create_xrefs", &fCreateXRefs) != B_OK) { 387 fCreateXRefs = false; 388 } 389 390 if (fCreateXRefs) { 391 BString name; 392 if (JobMsg()->FindString("xrefs_file", &name) == B_OK 393 && LoadXRefsDefinitions(name.String())) { 394 } else { 395 REPORT(kError, 0, "Could not read xrefs file!"); 396 fCreateXRefs = false; 397 } 398 } 399 400 return B_OK; 401} 402 403 404void 405PDFWriter::DeclareEncodingFiles() 406{ 407 BPath prefix; 408 if (find_directory(B_SYSTEM_DATA_DIRECTORY, &prefix) != B_OK) 409 return; 410 411 DeclareEncodingFile(&prefix, "t1enc0", "t1enc0.enc"); 412 DeclareEncodingFile(&prefix, "t1enc1", "t1enc1.enc"); 413 DeclareEncodingFile(&prefix, "t1enc2", "t1enc2.enc"); 414 DeclareEncodingFile(&prefix, "t1enc3", "t1enc3.enc"); 415 DeclareEncodingFile(&prefix, "t1enc4", "t1enc4.enc"); 416 417 DeclareEncodingFile(&prefix, "ttenc0", "ttenc0.cpg"); 418 DeclareEncodingFile(&prefix, "ttenc1", "ttenc1.cpg"); 419 DeclareEncodingFile(&prefix, "ttenc2", "ttenc2.cpg"); 420 DeclareEncodingFile(&prefix, "ttenc3", "ttenc3.cpg"); 421 DeclareEncodingFile(&prefix, "ttenc4", "ttenc4.cpg"); 422} 423 424 425void 426PDFWriter::DeclareEncodingFile(BPath* prefix, const char* id, const char* name) 427{ 428 BPath path(*prefix); 429 path.Append(kEncodingDirectory); 430 path.Append(name); 431 432 BString encodingDeclaration; 433 encodingDeclaration << id << "==" << path.Path(); 434 PDF_set_parameter(fPdf, "Encoding", encodingDeclaration.String()); 435} 436 437 438status_t 439PDFWriter::DeclareFonts() 440{ 441 char buffer[1024]; 442 const char *parameter_name; 443 444 for (int i = 0; i < fFonts->Length(); i++) { 445 FontFile* f = fFonts->At(i); 446 if (f->Type() == true_type_type) { 447 parameter_name = "FontOutline"; 448 } else { // f->Type() == type1_type 449 if (strstr(f->Path(), ".afm")) 450 parameter_name = "FontAFM"; 451 else if (strstr(f->Path(), ".pfm")) 452 parameter_name = "FontPFM"; 453 else // should not reach here! 454 continue; 455 } 456#ifndef __POWERPC__ 457 snprintf(buffer, sizeof(buffer), "%s==%s", f->Name(), f->Path()); 458#else 459 sprintf(buffer, "%s==%s", f->Name(), f->Path()); 460#endif 461 PDF_set_parameter(fPdf, parameter_name, buffer); 462 } 463 return B_OK; 464} 465 466 467bool 468PDFWriter::LoadBookmarkDefinitions(const char* name) 469{ 470 BPath path; 471 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) != B_OK) 472 return false; 473 474 path.Append(kSettingsDirectory); 475 path.Append(kBookmarksDirectory); 476 477 return fBookmark->Read(path.Path()); 478} 479 480 481bool 482PDFWriter::LoadXRefsDefinitions(const char* name) 483{ 484 BPath path; 485 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) != B_OK) 486 return false; 487 488 path.Append(kSettingsDirectory); 489 path.Append(kCrossReferencesDirectory); 490 491 if (!fXRefs->Read(path.Path())) 492 return false; 493 494 fXRefDests = new XRefDests(fXRefs->Count()); 495 return true; 496} 497 498 499status_t 500PDFWriter::BeginPage(BRect paperRect, BRect printRect) 501{ 502 float width = paperRect.Width() < 10 ? a4_width : paperRect.Width(); 503 float height = paperRect.Height() < 10 ? a4_height : paperRect.Height(); 504 505 fMode = kDrawingMode; 506 507 ASSERT(fState == NULL); 508 fState = new State(height, printRect.left, printRect.top); 509 510 if (MakesPDF()) 511 PDF_begin_page(fPdf, width, height); 512 513 REPORT(kDebug, fPage, ">>>> PDF_begin_page [%f, %f]", width, height); 514 515 if (MakesPDF()) 516 PDF_initgraphics(fPdf); 517 518 fState->penX = 0; 519 fState->penY = 0; 520 521 // TODO: should we clip to the printRect here? 522 523 PushState(); // so that fState->prev != NULL 524 525 return B_OK; 526} 527 528 529status_t 530PDFWriter::EndPage() 531{ 532 fTextLine.Flush(); 533 if (fCreateBookmarks) fBookmark->CreateBookmarks(); 534 535 while (fState->prev != NULL) PopState(); 536 537 if (MakesPDF()) 538 PDF_end_page(fPdf); 539 REPORT(kDebug, fPage, ">>>> PDF_end_page"); 540 541 delete fState; fState = NULL; 542 543 return B_OK; 544} 545 546 547// #pragma mark PDFlib callbacks 548 549 550size_t 551PDFWriter::WriteData(void *data, size_t size) 552{ 553 REPORT(kDebug, fPage, ">>>> WriteData %p, %ld", data, size); 554 555 return Transport()->Write(data, size); 556} 557 558 559void 560PDFWriter::ErrorHandler(int type, const char *msg) 561{ 562 REPORT(kError, fPage, "PDFlib %d: %s", type, msg); 563} 564 565 566// #pragma mark Generic drawing support routines 567 568 569void 570PDFWriter::PushInternalState() 571{ 572 REPORT(kDebug, fPage, "PushInternalState"); 573 fState = new State(fState); fStateDepth ++; 574} 575 576 577bool 578PDFWriter::PopInternalState() 579{ 580 REPORT(kDebug, fPage, "PopInternalState"); 581 if (fStateDepth != 0) { 582 State* s = fState; fStateDepth --; 583 fState = fState->prev; 584 delete s; 585 return true; 586 } else { 587 REPORT(kDebug, fPage, "State stack underflow!"); 588 return false; 589 } 590} 591 592 593PDFWriter::Transparency* 594PDFWriter::FindTransparency(uint8 alpha) 595{ 596 const int n = fTransparencyCache.CountItems(); 597 for (int i = 0; i < n; i ++) { 598 Transparency* t = fTransparencyCache.ItemAt(i); 599 if (t->Matches(alpha)) { 600 // return handle for existing gstate 601 return t; 602 } 603 } 604 605 // create new handle for gstate 606 char trans[256]; 607 float a = (float)alpha/255.0; 608 sprintf(trans, "opacitystroke=%f opacityfill=%f", a, a); 609 610 volatile int handle = -1; 611 PDF_TRY(fPdf) { 612 handle = PDF_create_gstate(fPdf, trans); 613 } PDF_CATCH(fPdf) { 614 REPORT(kError, 0, PDF_get_errmsg(fPdf)); 615 } 616 REPORT(kDebug, fPage, trans); 617 618 if (handle >= 0) { 619 // store in cache 620 Transparency* t = new Transparency(alpha, handle); 621 fTransparencyCache.AddItem(t); 622 return t; 623 } 624 625 return NULL; 626} 627 628 629void 630PDFWriter::BeginTransparency() 631{ 632 if (!SupportsOpacity() || !MakesPDF() || !IsDrawing()) 633 return; 634 635 REPORT(kDebug, fPage, ">>> BeginTransparency"); 636 REPORT(kDebug, fPage, "current_color(%d, %d, %d, %d)", 637 fState->currentColor.red, fState->currentColor.green, 638 fState->currentColor.blue, fState->currentColor.alpha); 639 REPORT(kDebug, fPage, "drawing_mode %d alpha %d", (int)fState->drawingMode, 640 (int)fState->currentColor.alpha); 641 642 uint8 alpha = fState->currentColor.alpha; 643 if (fState->drawingMode == B_OP_ALPHA && alpha < 255) { 644 PDF_save(fPdf); 645 Transparency* t = FindTransparency(alpha); 646 if (t != NULL) { 647 PDF_TRY(fPdf) { 648 PDF_set_gstate(fPdf, t->Handle()); 649 } PDF_CATCH(fPdf) { 650 REPORT(kError, 0, PDF_get_errmsg(fPdf)); 651 } 652 fTransparencyStack.AddItem(t); 653 return; 654 } 655 } 656 // if transparency is not set then push NULL to transparency stack 657 fTransparencyStack.AddItem(NULL); 658} 659 660 661void 662PDFWriter::EndTransparency() 663{ 664 if (!SupportsOpacity() || !MakesPDF() || !IsDrawing()) return; 665 REPORT(kDebug, fPage, "<<< EndTransparency"); 666 int lastItem = fTransparencyStack.CountItems()-1; 667 Transparency* t = fTransparencyStack.RemoveItem(lastItem); 668 669 if (t != NULL) { 670 PDF_restore(fPdf); 671 } 672} 673 674 675void 676PDFWriter::SetColor(rgb_color color) 677{ 678 if (!MakesPDF()) { 679 // create PDFlib gstate handles 680 if (SupportsOpacity() && fState->currentColor.alpha != color.alpha 681 && color.alpha < 255) { 682 FindTransparency(color.alpha); 683 } 684 } else if (fState->currentColor.red != color.red || 685 fState->currentColor.blue != color.blue || 686 fState->currentColor.green != color.green || 687 fState->currentColor.alpha != color.alpha) { 688 fState->currentColor = color; 689 float red = color.red / 255.0; 690 float green = color.green / 255.0; 691 float blue = color.blue / 255.0; 692 PDF_setcolor(fPdf, "both", "rgb", red, green, blue, 0.0); 693 REPORT(kDebug, fPage, "set_color(%f, %f, %f, %f)", red, green, blue, 694 color.alpha / 255.0); 695 } 696} 697 698 699int 700PDFWriter::FindPattern() 701{ 702 // TODO: use hashtable instead of BList for fPatterns 703 const int n = fPatterns.CountItems(); 704 for (int i = 0; i < n; i ++) { 705 Pattern* p = fPatterns.ItemAt(i); 706 if (p->Matches(fState->pattern0, fState->backgroundColor, 707 fState->foregroundColor)) 708 return p->patternId; 709 } 710 return -1; 711} 712 713 714void 715PDFWriter::CreatePattern() 716{ 717 REPORT(kDebug, fPage, "CreatePattern"); 718#if 1 719 // use filled pathes for pattern 720 // pro: see con of bitmap pattern 721 // con: not rendered (correctly) in BePDF with small zoom factor 722 int pattern = PDF_begin_pattern(fPdf, 8, 8, 8, 8, 1); 723 724 if (pattern == -1) { 725 REPORT(kError, fPage, "CreatePattern could not create pattern"); 726 return; 727 } 728 729 const int kPassForeground = 0; 730 const int kPassBackground = 1; 731 const int kNumPasses = 2; 732 733 for (int pass = 0; pass < kNumPasses; pass ++) { 734 float r, g, b; 735 bool is_transparent; 736 737 if (pass == kPassForeground) { 738 r = fState->foregroundColor.red / 255.0; 739 g = fState->foregroundColor.green / 255.0; 740 b = fState->foregroundColor.blue / 255.0; 741 is_transparent = fState->foregroundColor.alpha < 128; 742 } else { 743 r = fState->backgroundColor.red / 255.0; 744 g = fState->backgroundColor.green / 255.0; 745 b = fState->backgroundColor.blue / 255.0; 746 is_transparent = fState->backgroundColor.alpha < 128; 747 } 748 749 PDF_setcolor(fPdf, "fill", "rgb", r, g, b, 0); 750 751 if (is_transparent) continue; 752 753 uint8* data = (uint8*)fState->pattern0.data; 754 for (int8 y = 0; y <= 7; y ++, data ++) { 755 uint8 d = *data; 756 for (int8 x = 0; x <= 7; x ++, d >>= 1) { 757 if ((d & 1) == 1) { // foreground 758 if (pass != kPassForeground) continue; 759 } else { // background 760 if (pass != kPassBackground) continue; 761 } 762 763 // create rectangle for pixel 764 float x1 = x + 1, y1 = y + 1; 765 PDF_moveto(fPdf, x, y); 766 PDF_lineto(fPdf, x, y1); 767 PDF_lineto(fPdf, x1, y1); 768 PDF_lineto(fPdf, x1, y); 769 PDF_closepath(fPdf); 770 PDF_fill(fPdf); 771 } 772 } 773 } 774 775 PDF_end_pattern(fPdf); 776 777#else 778 // use bitmap for pattern 779 // pro: BePDF renders pattern also with small zoom factor 780 // con: BePDF omits mask during rendering 781 BBitmap bm(BRect(0, 0, 7, 7), B_RGBA32); 782 783 uint8* data = (uint8*)fState->pattern0.data; 784 rgb_color h = fState->foregroundColor; 785 rgb_color l = fState->backgroundColor; 786 if (h.alpha < 128) { 787 h.red = h.green = h.blue = 255; 788 } 789 if (l.alpha < 128) { 790 l.red = l.green = l.blue = 255; 791 } 792 793 uint8* row = (uint8*)bm.Bits(); 794 for (int8 y = 0; y <= 7; y ++, data ++) { 795 uint8 d = *data; 796 uint8* b = row; row += bm.BytesPerRow(); 797 for (int8 x = 0; x <= 7; x ++, d >>= 1, b += 4) { 798 if (d & 1 == 1) { 799 b[2] = h.red; //fState->foregroundColor.red; 800 b[1] = h.green; //fState->foregroundColor.green; 801 b[0] = h.blue; //fState->foregroundColor.blue; 802 b[3] = h.alpha; //fState->foregroundColor.alpha; 803 } else { 804 b[2] = l.red; //fState->backgroundColor.red; 805 b[1] = l.green; //fState->backgroundColor.green; 806 b[0] = l.blue; //fState->backgroundColor.blue; 807 b[3] = l.alpha; //fState->backgroundColor.alpha; 808 } 809 } 810 } 811 812 int mask, image; 813 814 if (!GetImages(bm.Bounds(), 8, 8, bm.BytesPerRow(), bm.ColorSpace(), 0, 815 bm.Bits(), &mask, &image)) { 816 return; 817 } 818 819 int pattern = PDF_begin_pattern(fPdf, 8, 8, 8, 8, 1); 820 if (pattern == -1) { 821 REPORT(kError, fPage, "CreatePattern could not create pattern"); 822#if !USE_IMAGE_CACHE 823 PDF_close_image(fPdf, image); 824 if (mask != -1) PDF_close_image(fPdf, mask); 825#endif 826 return; 827 } 828 PDF_setcolor(fPdf, "both", "rgb", 0, 0, 1, 0); 829 PDF_place_image(fPdf, image, 0, 0, 1); 830 PDF_end_pattern(fPdf); 831#if !USE_IMAGE_CACHE 832 PDF_close_image(fPdf, image); 833 if (mask != -1) PDF_close_image(fPdf, mask); 834#endif 835#endif 836 837 Pattern* p = new Pattern(fState->pattern0, fState->backgroundColor, 838 fState->foregroundColor, pattern); 839 fPatterns.AddItem(p); 840} 841 842 843void 844PDFWriter::SetPattern() 845{ 846 REPORT(kDebug, fPage, "SetPattern (bitmap version)"); 847 if (MakesPattern()) { 848 if (FindPattern() == -1) CreatePattern(); 849 } else { 850 int pattern = FindPattern(); 851 if (pattern != -1) { 852 PDF_setcolor(fPdf, "both", "pattern", pattern, 0, 0, 0); 853 } else { 854 // TODO: fall back to another method 855 REPORT(kError, fPage, "pattern missing!"); 856 } 857 } 858} 859 860 861void 862PDFWriter::StrokeOrClip() 863{ 864 if (IsDrawing()) { 865 PDF_stroke(fPdf); 866 } else { 867 REPORT(kError, fPage, "Clipping not implemented for this primitive!!!"); 868 PDF_closepath(fPdf); 869 } 870} 871 872 873void 874PDFWriter::FillOrClip() 875{ 876 if (IsDrawing()) { 877 PDF_fill(fPdf); 878 } else { 879 PDF_closepath(fPdf); 880 } 881} 882 883 884void 885PDFWriter::Paint(bool stroke) 886{ 887 if (stroke) { 888 StrokeOrClip(); 889 } else { 890 FillOrClip(); 891 } 892} 893 894 895void 896PDFWriter::SetColor() 897{ 898 if (IsSame(fState->pattern0, B_SOLID_HIGH)) { 899 SetColor(fState->foregroundColor); 900 } else if (IsSame(fState->pattern0, B_SOLID_LOW)) { 901 SetColor(fState->backgroundColor); 902 } else { 903 SetPattern(); 904 } 905} 906 907 908// #pragma mark Image drawing support routines 909 910 911int32 912PDFWriter::BytesPerPixel(int32 pixelFormat) 913{ 914 switch (pixelFormat) { 915 case B_RGB32: // fall through 916 case B_RGB32_BIG: // fall through 917 case B_RGBA32: // fall through 918 case B_RGBA32_BIG: 919 return 4; 920 921 case B_RGB24_BIG: // fall through 922 case B_RGB24: 923 return 3; 924 925 case B_RGB16: // fall through 926 case B_RGB16_BIG: // fall through 927 case B_RGB15: // fall through 928 case B_RGB15_BIG: // fall through 929 case B_RGBA15: // fall through 930 case B_RGBA15_BIG: 931 return 2; 932 933 case B_GRAY8: // fall through 934 case B_CMAP8: 935 return 1; 936 case B_GRAY1: 937 return 0; 938 default: return -1; 939 } 940} 941 942 943bool 944PDFWriter::HasAlphaChannel(int32 pixelFormat) 945{ 946 switch (pixelFormat) { 947 case B_RGB32: // fall through 948 case B_RGB32_BIG: // fall through 949 case B_RGBA32: // fall through 950 case B_RGBA32_BIG: // fall through 951// case B_RGB24: // fall through 952// case B_RGB24_BIG: // fall through 953// case B_RGB16: // fall through 954// case B_RGB16_BIG: // fall through 955 case B_RGB15: // fall through 956 case B_RGB15_BIG: // fall through 957 case B_RGBA15: // fall through 958 case B_RGBA15_BIG: // fall through 959 case B_CMAP8: 960 return true; 961 default: 962 return false; 963 } 964} 965 966 967bool 968PDFWriter::NeedsBPC1Mask(int32 pixelFormat) 969{ 970 switch (pixelFormat) { 971// case B_RGB32: // fall through 972// case B_RGB32_BIG: // fall through 973 case B_RGB15: // fall through 974 case B_RGB15_BIG: // fall through 975 case B_RGBA15: // fall through 976 case B_RGBA15_BIG: // fall through 977 case B_CMAP8: 978 return true; 979 default: 980 return false; 981 }; 982} 983 984 985bool 986PDFWriter::IsTransparentRGB32(uint8* in) 987{ 988 return *((uint32*)in) == B_TRANSPARENT_MAGIC_RGBA32; 989} 990 991 992bool 993PDFWriter::IsTransparentRGB32_BIG(uint8* in) 994{ 995 return *(uint32*)in == B_TRANSPARENT_MAGIC_RGBA32_BIG; 996} 997 998 999bool 1000PDFWriter::IsTransparentRGBA32(uint8* in) 1001{ 1002 return in[3] < 128 || IsTransparentRGB32(in); 1003} 1004 1005 1006bool 1007PDFWriter::IsTransparentRGBA32_BIG(uint8* in) 1008{ 1009 return in[0] < 127 || IsTransparentRGB32_BIG(in); 1010} 1011 1012 1013bool 1014PDFWriter::IsTransparentRGB15(uint8* in) 1015{ 1016 return *((uint16*)in) == B_TRANSPARENT_MAGIC_RGBA15; 1017} 1018 1019 1020bool 1021PDFWriter::IsTransparentRGB15_BIG(uint8* in) 1022{ 1023 // 01234567 01234567 1024 // 00123434 01201234 1025 // -RRRRRGG GGGBBBBB 1026 return *(uint16*)in == B_TRANSPARENT_MAGIC_RGBA15_BIG; 1027} 1028 1029 1030bool 1031PDFWriter::IsTransparentRGBA15(uint8* in) 1032{ 1033 // 01234567 01234567 1034 // 01201234 00123434 1035 // GGGBBBBB ARRRRRGG 1036 return (in[1] & 1) == 0 || IsTransparentRGB15(in); 1037} 1038 1039 1040bool 1041PDFWriter::IsTransparentRGBA15_BIG(uint8* in) 1042{ 1043 // 01234567 01234567 1044 // 00123434 01201234 1045 // ARRRRRGG GGGBBBBB 1046 return (in[0] & 1) == 0 || IsTransparentRGB15_BIG(in); 1047} 1048 1049 1050bool 1051PDFWriter::IsTransparentCMAP8(uint8* in) 1052{ 1053 return *in == B_TRANSPARENT_MAGIC_CMAP8; 1054} 1055 1056 1057uint8 * 1058PDFWriter::CreateMask(BRect src, int32 bytesPerRow, int32 pixelFormat, 1059 int32 flags, void *data) 1060{ 1061 uint8 *in; 1062 uint8 *inRow; 1063 int32 x, y; 1064 1065 uint8 *mask; 1066 uint8 *maskRow; 1067 uint8 *out; 1068 int32 maskWidth; 1069 uint8 shift; 1070 bool alpha; 1071 int32 bpp; 1072 1073 bpp = BytesPerPixel(pixelFormat); 1074 if (bpp < 0) 1075 return NULL; 1076 1077 int32 width = src.IntegerWidth() + 1; 1078 int32 height = src.IntegerHeight() + 1; 1079 1080 // Image Mask 1081 inRow = (uint8 *) data; 1082 inRow += bytesPerRow * (int) src.top + bpp * (int) src.left; 1083 1084 maskWidth = (width+7)/8; 1085 maskRow = mask = new uint8[maskWidth * height]; 1086 memset(mask, 0, maskWidth*height); 1087 alpha = false; 1088 1089 for (y = height; y > 0; y--) { 1090 in = inRow; 1091 out = maskRow; 1092 shift = 7; 1093 1094 bool a = false; 1095 1096 for (x = width; x > 0; x-- ) { 1097 // For each pixel 1098 switch (pixelFormat) { 1099 case B_RGB32: a = IsTransparentRGB32(in); break; 1100 case B_RGB32_BIG: a = IsTransparentRGB32_BIG(in); break; 1101 case B_RGBA32: a = IsTransparentRGBA32(in); break; 1102 case B_RGBA32_BIG: a = IsTransparentRGBA32_BIG(in); break; 1103 //case B_RGB24: a = IsTransparentRGB24(in); break; 1104 //case B_RGB24_BIG: a = IsTransparentRGB24_BIG(in); break; 1105 //case B_RGB16: a = IsTransparentRGB16(in); break; 1106 //case B_RGB16_BIG: a = IsTransparentRGB16_BIG(in); break; 1107 case B_RGB15: a = IsTransparentRGB15(in); break; 1108 case B_RGB15_BIG: a = IsTransparentRGB15_BIG(in); break; 1109 case B_RGBA15: a = IsTransparentRGBA15(in); break; 1110 case B_RGBA15_BIG: a = IsTransparentRGBA15_BIG(in); break; 1111 case B_CMAP8: a = IsTransparentCMAP8(in); break; 1112 //case B_GRAY8: a = IsTransparentGRAY8(in); break; 1113 //case B_GRAY1: a = false; break; 1114 default: 1115 a = false; // should not reach here 1116 REPORT(kDebug, fPage, 1117 "CreateMask: non transparentable pixelFormat"); 1118 } 1119 1120 if (a) { 1121 out[0] |= (1 << shift); 1122 alpha = true; 1123 } 1124 // next pixel 1125 if (shift == 0) out ++; 1126 shift = (shift + 7) & 0x07; 1127 in += bpp; 1128 } 1129 1130 // next row 1131 inRow += bytesPerRow; 1132 maskRow += maskWidth; 1133 } 1134 1135 if (!alpha) { 1136 delete []mask; 1137 mask = NULL; 1138 } 1139 return mask; 1140} 1141 1142 1143uint8 1144PDFWriter::AlphaFromRGBA32(uint8* in) 1145{ 1146 return in[2]; 1147} 1148 1149 1150uint8 1151PDFWriter::AlphaFromRGBA32_BIG(uint8* in) 1152{ 1153 return in[0]; 1154} 1155 1156 1157uint8 * 1158PDFWriter::CreateSoftMask(BRect src, int32 bytesPerRow, int32 pixelFormat, 1159 int32 flags, void *data) 1160{ 1161#if 1 1162 // TODO: CreateSoftMask??? 1163 return NULL; 1164#else 1165 static bool errorReported = false; 1166 1167 uint8 *in; 1168 uint8 *inRow; 1169 int32 x, y; 1170 1171 uint8 *mask; 1172 uint8 *maskRow; 1173 uint8 *out; 1174 bool alpha; 1175 int32 bpp; 1176 1177 bpp = BytesPerPixel(pixelFormat); 1178 if (bpp < 0) 1179 return NULL; 1180 1181 int32 width = src.IntegerWidth() + 1; 1182 int32 height = src.IntegerHeight() + 1; 1183 1184 // Image Mask 1185 inRow = (uint8 *) data; 1186 inRow += bytesPerRow * (int) src.top + bpp * (int) src.left; 1187 1188 // soft mask with 8 bits per component 1189 maskRow = mask = new uint8[width * height]; 1190 memset(mask, 0, width * height); 1191 alpha = false; 1192 1193 for (y = height; y > 0; y--) { 1194 in = inRow; 1195 out = maskRow; 1196 1197 uint8 a; 1198 1199 for (x = width; x > 0; x-- ) { 1200 // For each pixel 1201 switch (pixelFormat) { 1202 case B_RGB32: // fall through 1203 case B_RGBA32: 1204 a = AlphaFromRGBA32(in); 1205 break; 1206 1207 case B_RGB32_BIG: // fall through 1208 case B_RGBA32_BIG: 1209 a = AlphaFromRGBA32_BIG(in); 1210 break; 1211 1212 default: 1213 a = 255; // should not reach here 1214 if (!errorReported) { 1215 REPORT(kDebug, fPage, 1216 "CreateSoftMask: non transparentable pixelFormat"); 1217 errorReported = true; 1218 } 1219 } 1220 1221 *out = a; 1222 if (a != 255) { 1223 alpha = true; 1224 } 1225 // next pixel 1226 out ++; 1227 in += bpp; 1228 } 1229 1230 // next row 1231 inRow += bytesPerRow; 1232 maskRow += width; 1233 } 1234 1235 if (!alpha) { 1236 delete []mask; 1237 mask = NULL; 1238 } 1239 return mask; 1240#endif 1241} 1242 1243 1244void 1245PDFWriter::ConvertFromRGB32(uint8* in, uint8 *out) 1246{ 1247 *((rgb_color*)out) = *((rgb_color*)in); 1248} 1249 1250 1251void 1252PDFWriter::ConvertFromRGBA32(uint8* in, uint8 *out) 1253{ 1254 *((rgb_color*)out) = *((rgb_color*)in); 1255} 1256 1257 1258void 1259PDFWriter::ConvertFromRGB24(uint8* in, uint8 *out) 1260{ 1261 out[0] = in[0]; 1262 out[1] = in[1]; 1263 out[2] = in[2]; 1264 out[3] = 255; 1265} 1266 1267 1268void 1269PDFWriter::ConvertFromRGB16(uint8* in, uint8 *out) 1270{ 1271 // 01234567 01234567 1272 // 01201234 01234345 1273 // GGGBBBBB RRRRRGGG 1274 out[0] = in[0] & 0xf8; // blue 1275 out[1] = ((in[0] & 7) << 2) | (in[1] & 0xe0); // green 1276 out[2] = in[1] << 3; // red 1277 out[3] = 255; 1278} 1279 1280 1281void 1282PDFWriter::ConvertFromRGB15(uint8* in, uint8 *out) 1283{ 1284 // 01234567 01234567 1285 // 01201234 00123434 1286 // GGGBBBBB -RRRRRGG 1287 out[0] = in[0] & 0xf8; // blue 1288 out[1] = ((in[0] & 7) << 3) | (in[1] & 0xc0); // green 1289 out[2] = (in[1] & ~1) << 2; // red 1290 out[3] = 255; 1291} 1292 1293 1294void 1295PDFWriter::ConvertFromRGBA15(uint8* in, uint8 *out) 1296{ 1297 // 01234567 01234567 1298 // 01201234 00123434 1299 // GGGBBBBB ARRRRRGG 1300 out[0] = in[0] & 0xf8; // blue 1301 out[1] = ((in[0] & 7) << 3) | (in[1] & 0xc0); // green 1302 out[2] = (in[1] & ~1) << 2; // red 1303 out[3] = in[1] << 7; 1304} 1305 1306 1307void 1308PDFWriter::ConvertFromCMAP8(uint8* in, uint8 *out) 1309{ 1310 rgb_color c = fScreen->ColorForIndex(in[0]); 1311 out[0] = c.blue; 1312 out[1] = c.green; 1313 out[2] = c.red; 1314 out[3] = c.alpha; 1315} 1316 1317 1318void 1319PDFWriter::ConvertFromGRAY8(uint8* in, uint8 *out) 1320{ 1321 out[0] = in[0]; 1322 out[1] = in[0]; 1323 out[2] = in[0]; 1324 out[3] = 255; 1325} 1326 1327 1328void 1329PDFWriter::ConvertFromGRAY1(uint8* in, uint8 *out, int8 bit) 1330{ 1331 uint8 gray = (in[0] & (1 << bit)) ? 255 : 0; 1332 out[0] = gray; 1333 out[1] = gray; 1334 out[2] = gray; 1335 out[3] = 255; 1336} 1337 1338 1339void 1340PDFWriter::ConvertFromRGB32_BIG(uint8* in, uint8 *out) 1341{ 1342 out[0] = in[3]; 1343 out[1] = in[2]; 1344 out[2] = in[1]; 1345 out[3] = 255; 1346} 1347 1348 1349void 1350PDFWriter::ConvertFromRGBA32_BIG(uint8* in, uint8 *out) 1351{ 1352 out[0] = in[3]; 1353 out[1] = in[2]; 1354 out[2] = in[1]; 1355 out[3] = in[0]; 1356} 1357 1358 1359void 1360PDFWriter::ConvertFromRGB24_BIG(uint8* in, uint8 *out) 1361{ 1362 out[0] = in[2]; 1363 out[1] = in[1]; 1364 out[2] = in[0]; 1365 out[3] = 255; 1366} 1367 1368 1369void 1370PDFWriter::ConvertFromRGB16_BIG(uint8* in, uint8 *out) 1371{ 1372 // 01234567 01234567 1373 // 01234345 01201234 1374 // RRRRRGGG GGGBBBBB 1375 out[0] = in[2] & 0xf8; // blue 1376 out[1] = ((in[1] & 7) << 2) | (in[0] & 0xe0); // green 1377 out[2] = in[0] << 3; // red 1378 out[3] = 255; 1379} 1380 1381 1382void 1383PDFWriter::ConvertFromRGB15_BIG(uint8* in, uint8 *out) 1384{ 1385 // 01234567 01234567 1386 // 00123434 01201234 1387 // -RRRRRGG GGGBBBBB 1388 out[0] = in[1] & 0xf8; // blue 1389 out[1] = ((in[1] & 7) << 3) | (in[0] & 0xc0); // green 1390 out[2] = (in[0] & ~1) << 2; // red 1391 out[3] = 255; 1392} 1393 1394 1395void 1396PDFWriter::ConvertFromRGBA15_BIG(uint8* in, uint8 *out) 1397{ 1398 // 01234567 01234567 1399 // 00123434 01201234 1400 // ARRRRRGG GGGBBBBB 1401 out[0] = in[1] & 0xf8; // blue 1402 out[1] = ((in[1] & 7) << 3) | (in[0] & 0xc0); // green 1403 out[2] = (in[0] & ~1) << 2; // red 1404 out[3] = in[0] << 7; 1405} 1406 1407 1408//! Convert and clip bits to colorspace B_RGBA32 1409BBitmap * 1410PDFWriter::ConvertBitmap(BRect src, int32 bytesPerRow, int32 pixelFormat, 1411 int32 flags, void *data) 1412{ 1413 uint8 *in; 1414 uint8 *inLeft; 1415 uint8 *out; 1416 uint8 *outLeft; 1417 int32 x, y; 1418 int8 bit; 1419 int32 bpp = 4; 1420 1421 bpp = BytesPerPixel(pixelFormat); 1422 if (bpp < 0) 1423 return NULL; 1424 1425 int32 width = src.IntegerWidth(); 1426 int32 height = src.IntegerHeight(); 1427 BBitmap *bm = new BBitmap(BRect(0, 0, width, height), B_RGB32); 1428 if (!bm->IsValid()) { 1429 delete bm; 1430 REPORT(kError, fPage, "BBitmap constructor failed"); 1431 return NULL; 1432 } 1433 1434 inLeft = (uint8 *)data; 1435 inLeft += bytesPerRow * (int)src.top + bpp * (int)src.left; 1436 outLeft = (uint8*)bm->Bits(); 1437 1438 for (y = height; y >= 0; y--) { 1439 in = inLeft; 1440 out = outLeft; 1441 1442 for (x = 0; x <= width; x++) { 1443 // For each pixel 1444 switch (pixelFormat) { 1445 case B_RGB32: ConvertFromRGB32(in, out); break; 1446 case B_RGBA32: ConvertFromRGBA32(in, out); break; 1447 case B_RGB24: ConvertFromRGB24(in, out); break; 1448 case B_RGB16: ConvertFromRGB16(in, out); break; 1449 case B_RGB15: ConvertFromRGB15(in, out); break; 1450 case B_RGBA15: ConvertFromRGBA15(in, out); break; 1451 case B_CMAP8: ConvertFromCMAP8(in, out); break; 1452 case B_GRAY8: ConvertFromGRAY8(in, out); break; 1453 case B_GRAY1: 1454 bit = x & 7; 1455 ConvertFromGRAY1(in, out, bit); 1456 if (bit == 7) in ++; 1457 break; 1458 case B_RGB32_BIG: ConvertFromRGB32_BIG(in, out); break; 1459 case B_RGBA32_BIG: ConvertFromRGBA32_BIG(in, out); break; 1460 case B_RGB24_BIG: ConvertFromRGB24_BIG(in, out); break; 1461 case B_RGB16_BIG: ConvertFromRGB16_BIG(in, out); break; 1462 case B_RGB15_BIG: ConvertFromRGB15_BIG(in, out); break; 1463 case B_RGBA15_BIG: ConvertFromRGBA15_BIG(in, out); break; 1464 default:; // should not reach here 1465 } 1466 in += bpp; // next pixel 1467 out += 4; 1468 } 1469 1470 // next row 1471 inLeft += bytesPerRow; 1472 outLeft += bm->BytesPerRow(); 1473 } 1474 1475 return bm; 1476} 1477 1478 1479bool 1480PDFWriter::StoreTranslatorBitmap(BBitmap *bitmap, const char *filename, 1481 uint32 type) 1482{ 1483 BTranslatorRoster *roster = BTranslatorRoster::Default(); 1484 if (!roster) { 1485 REPORT(kDebug, fPage, "TranslatorRoster is NULL!"); 1486 return false; 1487 } 1488 BBitmapStream stream(bitmap); // init with contents of bitmap 1489/* 1490 translator_info info, *i = NULL; 1491 if (quality != -1.0 && roster->Identify(&stream, NULL, &info) == B_OK) { 1492 #ifdef DEBUG 1493 LOG((fLog, ">>> translator_info:\n")); 1494 LOG((fLog, " type = %4.4s\n", (char*)&info.type)); 1495 LOG((fLog, " id = %d\n", info.translator)); 1496 LOG((fLog, " group = %4.4s\n", (char*)&info.group)); 1497 LOG((fLog, " quality = %f\n", info.quality)); 1498 LOG((fLog, " capability = %f\n", info.type)); 1499 LOG((fLog, " name = %s\n", info.name)); 1500 LOG((fLog, " MIME = %s\n", info.MIME)); 1501 #endif 1502 1503 int32 numInfo; 1504 translator_info *tInfo = NULL; 1505 if (roster->GetTranslators(&stream, NULL, &tInfo, &numInfo, 1506 info.type, NULL, type) == B_OK) { 1507 1508// #ifdef DEBUG 1509 for (int j = 0; j < numInfo; j++) { 1510 LOG((fLog, ">>> translator_info [%d]:\n", j)); 1511 LOG((fLog, " type = %4.4s\n", (char*)&tInfo[j].type)); 1512 LOG((fLog, " id = %d\n", tInfo[j].translator)); 1513 LOG((fLog, " group = %4.4s\n", (char*)&tInfo[j].group)); 1514 LOG((fLog, " quality = %f\n", tInfo[j].quality)); 1515 LOG((fLog, " capability = %f\n", tInfo[j].type)); 1516 LOG((fLog, " name = %s\n", tInfo[j].name)); 1517 LOG((fLog, " MIME = %s\n", tInfo[j].MIME)); 1518 } 1519// #endif 1520 1521 BMessage m; 1522 status_t s = roster->GetConfigurationMessage(tInfo[0].translator, &m); 1523 if (s == B_OK) { 1524 fMessagePrinter.Print(&m); 1525 } else { 1526 LOG((fLog, "ERROR: could not get configuration message %d\n", s)); 1527 } 1528 1529 info = tInfo[0]; 1530 info.quality = quality; 1531 delete []tInfo; 1532 1533 i = &info; 1534 } 1535 } 1536*/ 1537 BFile file(filename, B_CREATE_FILE | B_WRITE_ONLY | B_ERASE_FILE); 1538 bool res = roster->Translate(&stream, NULL /*i*/, NULL, &file, type) == B_OK; 1539 BBitmap *bm = NULL; 1540 // detach bitmap so BBitmapStream destructor does not delete our bitmap! 1541 stream.DetachBitmap(&bm); 1542 ASSERT(bm == bitmap); 1543 return res; 1544} 1545 1546 1547bool 1548PDFWriter::GetImages(BRect src, int32 /*width*/, int32 /*height*/, 1549 int32 bytesPerRow, int32 pixelFormat, int32 flags, void *data, int* maskId, 1550 int* image) 1551{ 1552 uint8 *mask = NULL; 1553 *maskId = -1; 1554 1555 int32 width = src.IntegerWidth() + 1; 1556 int32 height = src.IntegerHeight() + 1; 1557 1558 int length = 0; 1559 int bpc = 0; 1560 1561 if (HasAlphaChannel(pixelFormat)) { 1562 if (NeedsBPC1Mask(pixelFormat) || !SupportsSoftMask()) { 1563 int32 w = (width+7)/8; 1564 length = w * height; 1565 bpc = 1; 1566 mask = CreateMask(src, bytesPerRow, pixelFormat, flags, data); 1567 REPORT(kDebug, fPage, "Mask created mask = %p", mask); 1568 } else { 1569 length = width * height; 1570 bpc = 8; 1571 mask = CreateSoftMask(src, bytesPerRow, pixelFormat, flags, data); 1572 REPORT(kDebug, fPage, "SoftMask created mask = %p", mask); 1573 } 1574 } 1575 1576 if (mask) { 1577// PDFlib deprecated: 1578// *maskId = PDF_open_image(fPdf, "raw", "memory", (const char *) mask, length, width, height, 1, bpc, "mask"); 1579#if USE_IMAGE_CACHE 1580 *maskId = fImageCache.GetMask(fPdf, (char*)mask, length, width, height, bpc); 1581#else 1582 BString options; 1583 PDF_create_pvf(fPdf, "mask", 0, mask, length, NULL); 1584 options << "width " << width << " height " << height << " components 1 bpc " << bpc; 1585 *maskId = PDF_load_image(fPdf, "raw", "mask", 0, options.String()); 1586 PDF_delete_pvf(fPdf, "mask", 0); 1587#endif 1588 delete []mask; 1589 } 1590 1591 BBitmap * bm = ConvertBitmap(src, bytesPerRow, pixelFormat, flags, data); 1592 if (!bm) { 1593 REPORT(kError, fPage, "ConvertBitmap failed!"); 1594#if !USE_IMAGE_CACHE 1595 if (*maskId != -1) PDF_close_image(fPdf, *maskId); 1596#endif 1597 return false; 1598 } 1599 1600#if USE_IMAGE_CACHE 1601 *image = fImageCache.GetImage(fPdf, bm, *maskId); 1602 delete bm; 1603#else 1604 char *pdfLibFormat = "png"; 1605 char *bitmapFileName = "/tmp/pdfwriter.png"; 1606 const uint32 beosFormat = B_PNG_FORMAT; 1607 1608 if (!StoreTranslatorBitmap(bm, bitmapFileName, beosFormat)) { 1609 delete bm; 1610 REPORT(kError, fPage, "StoreTranslatorBitmap failed"); 1611#if !USE_IMAGE_CACHE 1612 if (*maskId != -1) PDF_close_image(fPdf, *maskId); 1613#endif 1614 return false; 1615 } 1616 delete bm; 1617 1618 *image = PDF_open_image_file(fPdf, pdfLibFormat, bitmapFileName, 1619 *maskId == -1 ? "" : "masked", *maskId == -1 ? 0 : *maskId); 1620#endif 1621 1622 return *image >= 0; 1623} 1624 1625 1626// #pragma mark BPicture playback handlers 1627 1628 1629void 1630PDFWriter::Op(int number) 1631{ 1632 REPORT(kError, fPage, "Unhandled operand %d", number); 1633} 1634 1635 1636void 1637PDFWriter::MovePenBy(BPoint delta) 1638{ 1639 REPORT(kDebug, fPage, "MovePenBy delta=[%f, %f]", delta.x, delta.y); 1640 fState->penX += delta.x; 1641 fState->penY += delta.y; 1642} 1643 1644 1645void 1646PDFWriter::StrokeLine(BPoint start, BPoint end) 1647{ 1648 REPORT(kDebug, fPage, "StrokeLine start=[%f, %f], end=[%f, %f]", 1649 start.x, start.y, end.x, end.y); 1650 1651 SetColor(); 1652 if (!MakesPDF()) 1653 return; 1654 1655 if (IsClipping()) { 1656 BShape shape; 1657 shape.MoveTo(start); 1658 shape.LineTo(end); 1659 StrokeShape(&shape); 1660 } else { 1661 BeginTransparency(); 1662 PDF_moveto(fPdf, tx(start.x), ty(start.y)); 1663 PDF_lineto(fPdf, tx(end.x), ty(end.y)); 1664 StrokeOrClip(); 1665 EndTransparency(); 1666 } 1667} 1668 1669 1670void 1671PDFWriter::StrokeRect(BRect rect) 1672{ 1673 REPORT(kDebug, fPage, "StrokeRect rect=[%f, %f, %f, %f]", 1674 rect.left, rect.top, rect.right, rect.bottom); 1675 1676 SetColor(); 1677 if (!MakesPDF()) 1678 return; 1679 1680 if (IsClipping()) { 1681 BShape shape; 1682 shape.MoveTo(BPoint(rect.left, rect.top)); 1683 shape.LineTo(BPoint(rect.right, rect.top)); 1684 shape.LineTo(BPoint(rect.right, rect.bottom)); 1685 shape.LineTo(BPoint(rect.left, rect.bottom)); 1686 shape.Close(); 1687 StrokeShape(&shape); 1688 } else { 1689 BeginTransparency(); 1690 PDF_rect(fPdf, tx(rect.left), ty(rect.bottom), scale(rect.Width()), 1691 scale(rect.Height())); 1692 StrokeOrClip(); 1693 EndTransparency(); 1694 } 1695} 1696 1697 1698void 1699PDFWriter::FillRect(BRect rect) 1700{ 1701 REPORT(kDebug, fPage, "FillRect rect=[%f, %f, %f, %f]", 1702 rect.left, rect.top, rect.right, rect.bottom); 1703 1704 SetColor(); 1705 if (!MakesPDF()) 1706 return; 1707 1708 BeginTransparency(); 1709 PDF_rect(fPdf, tx(rect.left), ty(rect.bottom), scale(rect.Width()), 1710 scale(rect.Height())); 1711 FillOrClip(); 1712 EndTransparency(); 1713} 1714 1715 1716/*! The quarter ellipses in the corners of the rectangle are 1717 approximated with bezier curves. 1718 The constant 0.555... is taken from gobeProductive. 1719*/ 1720void 1721PDFWriter::PaintRoundRect(BRect rect, BPoint radii, bool stroke) 1722{ 1723 SetColor(); 1724 if (!MakesPDF()) 1725 return; 1726 1727 BPoint center; 1728 1729 float sx = radii.x; 1730 float sy = radii.y; 1731 1732 char str[256]; 1733 sprintf(str, "PaintRoundRect sx %f sy %f", sx, sy); 1734 REPORT(kDebug, fPage, str); 1735 1736 float ax = sx; 1737 float bx = 0.5555555555555 * sx; 1738 float ay = sy; 1739 float by = 0.5555555555555 * sy; 1740 1741 center.x = rect.left + sx; 1742 center.y = rect.top + sy; 1743 1744 BShape shape; 1745 shape.MoveTo(BPoint(center.x - ax, center.y)); 1746 BPoint a[3] = { 1747 BPoint(center.x - ax, center.y - by), 1748 BPoint(center.x - bx, center.y - ay), 1749 BPoint(center.x , center.y - ay)}; 1750 shape.BezierTo(a); 1751 1752 center.x = rect.right - sx; 1753 shape.LineTo(BPoint(center.x, center.y - ay)); 1754 1755 BPoint b[3] = { 1756 BPoint(center.x + bx, center.y - ay), 1757 BPoint(center.x + ax, center.y - by), 1758 BPoint(center.x + ax, center.y)}; 1759 shape.BezierTo(b); 1760 1761 center.y = rect.bottom - sy; 1762 shape.LineTo(BPoint(center.x + sx, center.y)); 1763 1764 BPoint c[3] = { 1765 BPoint(center.x + ax, center.y + by), 1766 BPoint(center.x + bx, center.y + ay), 1767 BPoint(center.x , center.y + ay)}; 1768 shape.BezierTo(c); 1769 1770 center.x = rect.left + sx; 1771 shape.LineTo(BPoint(center.x, center.y + ay)); 1772 1773 BPoint d[3] = { 1774 BPoint(center.x - bx, center.y + ay), 1775 BPoint(center.x - ax, center.y + by), 1776 BPoint(center.x - ax, center.y)}; 1777 shape.BezierTo(d); 1778 1779 shape.Close(); 1780 1781 PaintShape(&shape, stroke); 1782} 1783 1784 1785void 1786PDFWriter::StrokeRoundRect(BRect rect, BPoint radii) 1787{ 1788 REPORT(kDebug, fPage, "StrokeRoundRect center=[%f, %f, %f, %f], " 1789 "radii=[%f, %f]", rect.left, rect.top, rect.right, rect.bottom, radii.x, 1790 radii.y); 1791 PaintRoundRect(rect, radii, kStroke); 1792} 1793 1794 1795void 1796PDFWriter::FillRoundRect(BRect rect, BPoint radii) 1797{ 1798 REPORT(kDebug, fPage, "FillRoundRect rect=[%f, %f, %f, %f], radii=[%f, %f]", 1799 rect.left, rect.top, rect.right, rect.bottom, radii.x, radii.y); 1800 PaintRoundRect(rect, radii, kFill); 1801} 1802 1803 1804void 1805PDFWriter::StrokeBezier(BPoint *control) 1806{ 1807 REPORT(kDebug, fPage, "StrokeBezier"); 1808 SetColor(); 1809 if (!MakesPDF()) 1810 return; 1811 1812 BShape shape; 1813 shape.MoveTo(control[0]); 1814 shape.BezierTo(&control[1]); 1815 StrokeShape(&shape); 1816} 1817 1818 1819void 1820PDFWriter::FillBezier(BPoint *control) 1821{ 1822 REPORT(kDebug, fPage, "FillBezier"); 1823 SetColor(); 1824 if (!MakesPDF()) return; 1825 PDF_moveto(fPdf, tx(control[0].x), ty(control[0].y)); 1826 PDF_curveto(fPdf, tx(control[1].x), ty(control[1].y), 1827 tx(control[2].x), ty(control[2].y), tx(control[3].x), ty(control[3].y)); 1828 PDF_closepath(fPdf); 1829 FillOrClip(); 1830} 1831 1832 1833/*! Note the pen size is also scaled! 1834 We should approximate it with bezier curves too! 1835*/ 1836void 1837PDFWriter::PaintArc(BPoint center, BPoint radii, float startTheta, 1838 float arcTheta, int stroke) 1839{ 1840 float sx = scale(radii.x); 1841 float sy = scale(radii.y); 1842 float smax = sx > sy ? sx : sy; 1843 1844 SetColor(); 1845 if (!MakesPDF()) return; 1846 if (IsClipping()); // TODO clip to line path 1847 1848 PDF_save(fPdf); 1849 PDF_scale(fPdf, sx, sy); 1850 PDF_setlinewidth(fPdf, fState->penSize / smax); 1851 PDF_arc(fPdf, tx(center.x) / sx, ty(center.y) / sy, 1, startTheta, 1852 startTheta + arcTheta); 1853 Paint(stroke); 1854 PDF_restore(fPdf); 1855} 1856 1857 1858void 1859PDFWriter::StrokeArc(BPoint center, BPoint radii, float startTheta, 1860 float arcTheta) 1861{ 1862 REPORT(kDebug, fPage, "StrokeArc center=[%f, %f], radii=[%f, %f], " 1863 "startTheta=%f, arcTheta=%f", center.x, center.y, radii.x, radii.y, 1864 startTheta, arcTheta); 1865 PaintArc(center, radii, startTheta, arcTheta, true); 1866} 1867 1868 1869void 1870PDFWriter::FillArc(BPoint center, BPoint radii, float startTheta, float arcTheta) 1871{ 1872 REPORT(kDebug, fPage, "FillArc center=[%f, %f], radii=[%f, %f], " 1873 "startTheta=%f, arcTheta=%f", center.x, center.y, radii.x, radii.y, 1874 startTheta, arcTheta); 1875 PaintArc(center, radii, startTheta, arcTheta, false); 1876} 1877 1878 1879void 1880PDFWriter::PaintEllipse(BPoint center, BPoint radii, bool stroke) 1881{ 1882 float sx = radii.x; 1883 float sy = radii.y; 1884 1885 float ax = sx; 1886 float bx = 0.5555555555555 * sx; 1887 float ay = sy; 1888 float by = 0.5555555555555 * sy; 1889 1890 SetColor(); 1891 if (!MakesPDF()) return; 1892 1893 BShape shape; 1894 1895 shape.MoveTo(BPoint(center.x - ax, center.y)); 1896 1897 BPoint a[3] = { 1898 BPoint(center.x - ax, center.y - by), 1899 BPoint(center.x - bx, center.y - ay), 1900 BPoint(center.x , center.y - ay) }; 1901 shape.BezierTo(a); 1902 1903 BPoint b[3] = { 1904 BPoint(center.x + bx, center.y - ay), 1905 BPoint(center.x + ax, center.y - by), 1906 BPoint(center.x + ax, center.y)}; 1907 shape.BezierTo(b); 1908 1909 BPoint c[3] = { 1910 BPoint(center.x + ax, center.y + by), 1911 BPoint(center.x + bx, center.y + ay), 1912 BPoint(center.x , center.y + ay)}; 1913 shape.BezierTo(c); 1914 1915 BPoint d[3] = { 1916 BPoint(center.x - bx, center.y + ay), 1917 BPoint(center.x - ax, center.y + by), 1918 BPoint(center.x - ax, center.y)}; 1919 shape.BezierTo(d); 1920 1921 shape.Close(); 1922 1923 PaintShape(&shape, stroke); 1924} 1925 1926 1927void 1928PDFWriter::StrokeEllipse(BPoint center, BPoint radii) 1929{ 1930 REPORT(kDebug, fPage, "StrokeEllipse center=[%f, %f], radii=[%f, %f]", 1931 center.x, center.y, radii.x, radii.y); 1932 PaintEllipse(center, radii, true); 1933} 1934 1935 1936void 1937PDFWriter::FillEllipse(BPoint center, BPoint radii) 1938{ 1939 REPORT(kDebug, fPage, "FillEllipse center=[%f, %f], radii=[%f, %f]", 1940 center.x, center.y, radii.x, radii.y); 1941 PaintEllipse(center, radii, false); 1942} 1943 1944 1945void 1946PDFWriter::StrokePolygon(int32 numPoints, BPoint *points, bool isClosed) 1947{ 1948 int32 i; 1949 float x0, y0; 1950 REPORT(kDebug, fPage, "StrokePolygon numPoints=%ld, isClosed=%d\npoints=", 1951 numPoints, isClosed); 1952 1953 if (numPoints <= 1) 1954 return; 1955 1956 x0 = y0 = 0.0; 1957 1958 SetColor(); 1959 if (!MakesPDF()) 1960 return; 1961 1962 if (IsClipping()) { 1963 BShape shape; 1964 shape.MoveTo(*points); 1965 for (i = 1, points ++; i < numPoints; i++, points++) { 1966 shape.LineTo(*points); 1967 } 1968 if (isClosed) 1969 shape.Close(); 1970 StrokeShape(&shape); 1971 } else { 1972 BeginTransparency(); 1973 for ( i = 0; i < numPoints; i++, points++ ) { 1974 REPORT(kDebug, fPage, " [%f, %f]", points->x, points->y); 1975 if (i != 0) { 1976 PDF_lineto(fPdf, tx(points->x), ty(points->y)); 1977 } else { 1978 x0 = tx(points->x); 1979 y0 = ty(points->y); 1980 PDF_moveto(fPdf, x0, y0); 1981 } 1982 } 1983 if (isClosed) 1984 PDF_lineto(fPdf, x0, y0); 1985 StrokeOrClip(); 1986 EndTransparency(); 1987 } 1988} 1989 1990 1991void 1992PDFWriter::FillPolygon(int32 numPoints, BPoint *points, bool isClosed) 1993{ 1994 REPORT(kDebug, fPage, "FillPolygon numPoints=%ld, isClosed=%dpoints=", 1995 numPoints, isClosed); 1996 1997 SetColor(); 1998 if (!MakesPDF()) 1999 return; 2000 2001 BeginTransparency(); 2002 for (int32 i = 0; i < numPoints; i++, points++ ) { 2003 REPORT(kDebug, fPage, " [%f, %f]", points->x, points->y); 2004 if (i != 0) { 2005 PDF_lineto(fPdf, tx(points->x), ty(points->y)); 2006 } else { 2007 PDF_moveto(fPdf, tx(points->x), ty(points->y)); 2008 } 2009 } 2010 PDF_closepath(fPdf); 2011 FillOrClip(); 2012 EndTransparency(); 2013} 2014 2015 2016void 2017PDFWriter::PaintShape(BShape *shape, bool stroke) 2018{ 2019 if (stroke) StrokeShape(shape); else FillShape(shape); 2020} 2021 2022 2023void 2024PDFWriter::StrokeShape(BShape *shape) 2025{ 2026 REPORT(kDebug, fPage, "StrokeShape"); 2027 SetColor(); 2028 if (!MakesPDF()) 2029 return; 2030 BeginTransparency(); 2031 DrawShape iterator(this, true); 2032 iterator.Iterate(shape); 2033 EndTransparency(); 2034} 2035 2036 2037void 2038PDFWriter::FillShape(BShape *shape) 2039{ 2040 REPORT(kDebug, fPage, "FillShape"); 2041 SetColor(); 2042 if (!MakesPDF()) return; 2043 BeginTransparency(); 2044 DrawShape iterator(this, false); 2045 iterator.Iterate(shape); 2046 EndTransparency(); 2047} 2048 2049 2050void 2051PDFWriter::ClipToPicture(BPicture *picture, BPoint point, 2052 bool clipToInversePicture) 2053{ 2054 REPORT(kDebug, fPage, "ClipToPicture at (%f, %f) clip_to_inverse_picture " 2055 "= %s", point.x, point.y, clipToInversePicture ? "true" : "false"); 2056 2057 if (!MakesPDF()) 2058 return; 2059 if (clipToInversePicture) { 2060 REPORT(kError, fPage, "Clipping to inverse picture not implemented!"); 2061 return; 2062 } 2063 if (fMode == kDrawingMode) { 2064 const bool set_origin = point.x != 0 || point.y != 0; 2065 PushInternalState(); 2066 if (set_origin) { 2067 SetOrigin(point); PushInternalState(); 2068 } 2069 2070 fMode = kClippingMode; 2071 // create subpath(s) for clipping 2072 Iterate(picture); 2073 fMode = kDrawingMode; 2074 // and clip to it/them 2075 PDF_clip(fPdf); 2076 2077 if (set_origin) { 2078 PopInternalState(); 2079 } 2080 PopInternalState(); 2081 2082 REPORT(kDebug, fPage, "Returning from ClipToPicture"); 2083 } else { 2084 REPORT(kError, fPage, 2085 "Nested call of ClipToPicture not implemented yet!"); 2086 } 2087} 2088 2089 2090void 2091PDFWriter::DrawPixels(BRect src, BRect dest, int32 width, int32 height, 2092 int32 bytesPerRow, int32 pixelFormat, int32 flags, void *data) 2093{ 2094 REPORT(kDebug, fPage, "DrawPixels src=[%f, %f, %f, %f], dest=[%f, %f, %f, " 2095 "%f], width=%ld, height=%ld, bytesPerRow=%ld, pixelFormat=%ld, " 2096 "flags=%ld, data=%p", src.left, src.top, src.right, src.bottom, 2097 dest.left, dest.top, dest.right, dest.bottom, width, height, bytesPerRow, 2098 pixelFormat, flags, data); 2099 2100 SetColor(); 2101 2102 if (IsClipping()) { 2103 REPORT(kError, fPage, "DrawPixels for clipping not implemented yet!"); 2104 return; 2105 } 2106 2107 int maskId, image; 2108 2109 if (!GetImages(src, width, height, bytesPerRow, pixelFormat, flags, data, 2110 &maskId, &image)) { 2111 return; 2112 } 2113 if (!MakesPDF()) return; 2114 2115 const float scaleX = (dest.Width()+1) / (src.Width()+1); 2116 const float scaleY = (dest.Height()+1) / (src.Height()+1); 2117 2118 const bool needs_scaling = scaleX != 1.0 || scaleY != 1.0; 2119 2120 if (needs_scaling) { 2121 PDF_save(fPdf); 2122 PDF_scale(fPdf, scaleX, scaleY); 2123 } 2124 2125 // This seems to work with Gobe Productive, why? 2126 // Can use Begin/EndTransparency if the alpha value for each pixel 2127 // is the same. 2128 // Otherwise we need "SoftMasks". Don't know if PDFlib 5.x already 2129 // supports them. 2130 BeginTransparency(); 2131 2132 float x = tx(dest.left) / scaleX; 2133 float y = ty(dest.bottom) / scaleY; 2134 2135 if ( image >= 0 ) { 2136 PDF_place_image(fPdf, image, x, y, scale(1.0)); 2137#if !USE_IMAGE_CACHE 2138 PDF_close_image(fPdf, image); 2139#endif 2140 } else { 2141 REPORT(kError, fPage, "PDF_open_image_file failed!"); 2142 } 2143 2144#if !USE_IMAGE_CACHE 2145 if (maskId != -1) PDF_close_image(fPdf, maskId); 2146#endif 2147 EndTransparency(); 2148 2149 if (needs_scaling) PDF_restore(fPdf); 2150} 2151 2152 2153void 2154PDFWriter::SetClippingRects(BRect *rects, uint32 numRects) 2155{ 2156 uint32 i; 2157 2158 REPORT(kDebug, fPage, "SetClippingRects numRects=%ld\nrects=", \ 2159 numRects); 2160 2161 if (!MakesPDF()) return; 2162 2163 for ( i = 0; i < numRects; i++, rects++ ) { 2164 REPORT(kDebug, fPage, " [%f, %f, %f, %f]", \ 2165 rects->left, rects->top, rects->right, rects->bottom); 2166 PDF_moveto(fPdf, tx(rects->left), ty(rects->top)); 2167 PDF_lineto(fPdf, tx(rects->right), ty(rects->top)); 2168 PDF_lineto(fPdf, tx(rects->right), ty(rects->bottom)); 2169 PDF_lineto(fPdf, tx(rects->left), ty(rects->bottom)); 2170 PDF_closepath(fPdf); 2171 } 2172 if (numRects > 0) PDF_clip(fPdf); 2173} 2174 2175 2176void 2177PDFWriter::PushState() 2178{ 2179 REPORT(kDebug, fPage, "PushState"); 2180 PushInternalState(); 2181// LOG((fLog, "height = %f x0 = %f y0 = %f", fState->height, fState->x0, fState->y0)); 2182 if (!MakesPDF()) return; 2183 PDF_save(fPdf); 2184} 2185 2186 2187void 2188PDFWriter::PopState() 2189{ 2190 REPORT(kDebug, fPage, "PopState"); 2191 if (PopInternalState()) { 2192 if (!MakesPDF()) return; 2193 PDF_restore(fPdf); 2194 } 2195} 2196 2197 2198void 2199PDFWriter::EnterStateChange() 2200{ 2201 REPORT(kDebug, fPage, "EnterStateChange"); 2202 // nothing to do 2203} 2204 2205 2206void 2207PDFWriter::ExitStateChange() 2208{ 2209 REPORT(kDebug, fPage, "ExitStateChange"); 2210 // nothing to do 2211} 2212 2213 2214void 2215PDFWriter::EnterFontState() 2216{ 2217 REPORT(kDebug, fPage, "EnterFontState"); 2218 // nothing to do 2219} 2220 2221 2222void 2223PDFWriter::ExitFontState() 2224{ 2225 REPORT(kDebug, fPage, "ExitFontState"); 2226 // nothing to do 2227} 2228 2229 2230void 2231PDFWriter::SetOrigin(BPoint pt) 2232{ 2233 REPORT(kDebug, fPage, "SetOrigin pt=[%f, %f]", pt.x, pt.y); 2234 2235 // XXX scale pt with current scaling factor or with 2236 // scaling factor of previous state? (fState->prev->scale) 2237 BPoint o = fState->prev->pdfSystem.Origin(); 2238 pdfSystem()->SetOrigin( 2239 o.x + pdfSystem()->scale(pt.x), 2240 o.y + pdfSystem()->scale(pt.y) 2241 ); 2242} 2243 2244 2245void 2246PDFWriter::SetPenLocation(BPoint pt) 2247{ 2248 REPORT(kDebug, fPage, "SetPenLocation pt=[%f, %f]", pt.x, pt.y); 2249 2250 fState->penX = pt.x; 2251 fState->penY = pt.y; 2252} 2253 2254 2255void 2256PDFWriter::SetDrawingMode(drawing_mode mode) 2257{ 2258 REPORT(kDebug, fPage, "SetDrawingMode mode=%d", mode); 2259 fState->drawingMode = mode; 2260} 2261 2262 2263void 2264PDFWriter::SetLineMode(cap_mode capMode, join_mode joinMode, float miterLimit) 2265{ 2266 REPORT(kDebug, fPage, "SetLineMode"); 2267 fState->capMode = capMode; 2268 fState->joinMode = joinMode; 2269 fState->miterLimit = miterLimit; 2270 if (!MakesPDF()) return; 2271 int m = 0; 2272 switch (capMode) { 2273 case B_BUTT_CAP: m = 0; break; 2274 case B_ROUND_CAP: m = 1; break; 2275 case B_SQUARE_CAP: m = 2; break; 2276 } 2277 PDF_setlinecap(fPdf, m); 2278 2279 m = 0; 2280 switch (joinMode) { 2281 case B_MITER_JOIN: m = 0; break; 2282 case B_ROUND_JOIN: m = 1; break; 2283 case B_BUTT_JOIN: // fall through TODO: check this; no equivalent in PDF? 2284 case B_SQUARE_JOIN: // fall through TODO: check this too 2285 case B_BEVEL_JOIN: m = 2; break; 2286 } 2287 PDF_setlinejoin(fPdf, m); 2288 2289 PDF_setmiterlimit(fPdf, miterLimit); 2290 2291} 2292 2293 2294void 2295PDFWriter::SetPenSize(float size) 2296{ 2297 REPORT(kDebug, fPage, "SetPenSize size=%f", size); 2298 if (size <= 0.00001) 2299 size = 1; 2300 2301 // TODO: scaling required? 2302 fState->penSize = scale(size); 2303 if (!MakesPDF()) 2304 return; 2305 2306 PDF_setlinewidth(fPdf, size); 2307} 2308 2309 2310void 2311PDFWriter::SetForeColor(rgb_color color) 2312{ 2313 //if (IsClipping()) return; // ignore 2314 2315 float red = color.red / 255.0; 2316 float green = color.green / 255.0; 2317 float blue = color.blue / 255.0; 2318 2319 REPORT(kDebug, fPage, "SetForColor color=[%d, %d, %d, %d] -> [%f, %f, %f]", 2320 color.red, color.green, color.blue, color.alpha, red, green, blue); 2321 2322 fState->foregroundColor = color; 2323} 2324 2325 2326void 2327PDFWriter::SetBackColor(rgb_color color) 2328{ 2329 //if (IsClipping()) return; // ignore 2330 2331 float red, green, blue; 2332 2333 red = color.red / 255.0; 2334 green = color.green / 255.0; 2335 blue = color.blue / 255.0; 2336 2337 REPORT(kDebug, fPage, "SetBackColor color=[%d, %d, %d, %d] -> [%f, %f, %f]", 2338 color.red, color.green, color.blue, color.alpha, red, green, blue); 2339 2340 fState->backgroundColor = color; 2341} 2342 2343 2344void 2345PDFWriter::SetStipplePattern(pattern pat) 2346{ 2347 REPORT(kDebug, fPage, "SetStipplePattern"); 2348 fState->pattern0 = pat; 2349} 2350 2351 2352void 2353PDFWriter::SetScale(float scale) 2354{ 2355 REPORT(kDebug, fPage, "SetScale scale=%f", scale); 2356 pdfSystem()->SetScale(scale * fState->prev->pdfSystem.Scale()); 2357} 2358 2359 2360void 2361PDFWriter::SetFontFamily(char *family) 2362{ 2363 REPORT(kDebug, fPage, "SetFontFamily family=\"%s\"", family); 2364 2365 fState->beFont.SetFamilyAndStyle(family, NULL); 2366} 2367 2368 2369void 2370PDFWriter::SetFontStyle(char *style) 2371{ 2372 REPORT(kDebug, fPage, "SetFontStyle style=\"%s\"", style); 2373 2374 fState->beFont.SetFamilyAndStyle(NULL, style); 2375} 2376 2377 2378void 2379PDFWriter::SetFontSpacing(int32 spacing) 2380{ 2381 REPORT(kDebug, fPage, "SetFontSpacing spacing=%ld", spacing); 2382 // XXX scaling required? 2383 // if it is, do it when the font is used... 2384 fState->beFont.SetSpacing(spacing); 2385} 2386 2387 2388void 2389PDFWriter::SetFontSize(float size) 2390{ 2391 REPORT(kDebug, fPage, "SetFontSize size=%f", size); 2392 2393 fState->beFont.SetSize(size); 2394} 2395 2396 2397void 2398PDFWriter::SetFontRotate(float rotation) 2399{ 2400 REPORT(kDebug, fPage, "SetFontRotate rotation=%f", rotation); 2401 fState->beFont.SetRotation(RAD2DEGREE(rotation)); 2402} 2403 2404 2405void 2406PDFWriter::SetFontEncoding(int32 encoding) 2407{ 2408 REPORT(kDebug, fPage, "SetFontEncoding encoding=%ld", encoding); 2409 fState->beFont.SetEncoding(encoding); 2410} 2411 2412 2413void 2414PDFWriter::SetFontFlags(int32 flags) 2415{ 2416 REPORT(kDebug, fPage, "SetFontFlags flags=%ld (0x%lx)", flags, flags); 2417 fState->beFont.SetFlags(flags); 2418} 2419 2420 2421void 2422PDFWriter::SetFontShear(float shear) 2423{ 2424 REPORT(kDebug, fPage, "SetFontShear shear=%f", shear); 2425 fState->beFont.SetShear(shear); 2426} 2427 2428 2429void 2430PDFWriter::SetFontFace(int32 flags) 2431{ 2432 REPORT(kDebug, fPage, "SetFontFace flags=%ld (0x%lx)", flags, flags); 2433// fState->beFont.SetFace(flags); 2434} 2435 2436 2437// #pragma mark Redirectors to instance callbacks/handlers 2438 2439 2440size_t 2441_WriteData(PDF *pdf, void *data, size_t size) 2442{ 2443 return ((PDFWriter *)PDF_get_opaque(pdf))->WriteData(data, size); 2444} 2445 2446 2447void 2448_ErrorHandler(PDF *pdf, int type, const char *msg) 2449{ 2450 return ((PDFWriter *)PDF_get_opaque(pdf))->ErrorHandler(type, msg); 2451} 2452 2453