1/*---------------------------------------------------------------------------* 2 | PDFlib - A library for generating PDF on the fly | 3 +---------------------------------------------------------------------------+ 4 | Copyright (c) 1997-2004 Thomas Merz and PDFlib GmbH. All rights reserved. | 5 +---------------------------------------------------------------------------+ 6 | | 7 | This software is subject to the PDFlib license. It is NOT in the | 8 | public domain. Extended versions and commercial licenses are | 9 | available, please check http://www.pdflib.com. | 10 | | 11 *---------------------------------------------------------------------------*/ 12 13/* $Id: p_annots.c 14574 2005-10-29 16:27:43Z bonefish $ 14 * 15 * PDFlib routines for annnotations 16 * 17 */ 18 19#include "p_intern.h" 20 21/* Annotation types */ 22typedef enum { 23 ann_text, ann_locallink, 24 ann_pdflink, ann_weblink, 25 ann_launchlink, ann_attach 26} pdf_annot_type; 27 28/* icons for file attachments and text annotations */ 29typedef enum { 30 icon_file_graph, icon_file_paperclip, 31 icon_file_pushpin, icon_file_tag, 32 33 icon_text_comment, icon_text_insert, 34 icon_text_note, icon_text_paragraph, 35 icon_text_newparagraph, icon_text_key, 36 icon_text_help 37} pdf_icon; 38 39/* Annotations */ 40struct pdf_annot_s { 41 pdf_annot_type type; /* used for all annotation types */ 42 pdc_rectangle rect; /* used for all annotation types */ 43 pdc_id obj_id; /* used for all annotation types */ 44 pdf_annot *next; /* used for all annotation types */ 45 46 pdf_icon icon; /* attach and text */ 47 char *filename; /* attach, launchlink, pdflink,weblink*/ 48 char *contents; /* text, attach, pdflink */ 49 char *mimetype; /* attach */ 50 char *parameters; /* launchlink */ 51 char *operation; /* launchlink */ 52 char *defaultdir; /* launchlink */ 53 54 char *title; /* text */ 55 int open; /* text */ 56 pdf_dest dest; /* locallink, pdflink */ 57 58 /* -------------- annotation border style and color -------------- */ 59 pdf_border_style border_style; 60 float border_width; 61 float border_red; 62 float border_green; 63 float border_blue; 64 float border_dash1; 65 float border_dash2; 66}; 67 68static const char *pdf_border_style_names[] = { 69 "S", /* solid border */ 70 "D", /* dashed border */ 71 "B", /* beveled (three-dimensional) border */ 72 "I", /* inset border */ 73 "U" /* underlined border */ 74}; 75 76static const char *pdf_icon_names[] = { 77 /* embedded file icon names */ 78 "Graph", "Paperclip", "Pushpin", "Tag", 79 80 /* text annotation icon names */ 81 "Comment", "Insert", "Note", "Paragraph", "NewParagraph", "Key", "Help" 82}; 83 84/* flags for annotation properties */ 85typedef enum { 86 pdf_ann_flag_invisible = 1, 87 pdf_ann_flag_hidden = 2, 88 pdf_ann_flag_print = 4, 89 pdf_ann_flag_nozoom = 8, 90 pdf_ann_flag_norotate = 16, 91 pdf_ann_flag_noview = 32, 92 pdf_ann_flag_readonly = 64 93} pdf_ann_flag; 94 95void 96pdf_init_annots(PDF *p) 97{ 98 /* annotation border style defaults */ 99 p->border_style = border_solid; 100 p->border_width = (float) 1.0; 101 p->border_red = (float) 0.0; 102 p->border_green = (float) 0.0; 103 p->border_blue = (float) 0.0; 104 p->border_dash1 = (float) 3.0; 105 p->border_dash2 = (float) 3.0; 106 107 /* auxiliary function parameters */ 108 p->launchlink_parameters = NULL; 109 p->launchlink_operation = NULL; 110 p->launchlink_defaultdir = NULL; 111} 112 113void 114pdf_cleanup_annots(PDF *p) 115{ 116 if (p->launchlink_parameters) { 117 pdc_free(p->pdc, p->launchlink_parameters); 118 p->launchlink_parameters = NULL; 119 } 120 121 if (p->launchlink_operation) { 122 pdc_free(p->pdc, p->launchlink_operation); 123 p->launchlink_operation = NULL; 124 } 125 126 if (p->launchlink_defaultdir) { 127 pdc_free(p->pdc, p->launchlink_defaultdir); 128 p->launchlink_defaultdir = NULL; 129 } 130} 131 132static void 133pdf_init_annot(PDF *p, pdf_annot *ann) 134{ 135 (void) p; 136 137 ann->next = NULL; 138 ann->filename = NULL; 139 ann->mimetype = NULL; 140 ann->contents = NULL; 141 ann->mimetype = NULL; 142 ann->parameters = NULL; 143 ann->operation = NULL; 144 ann->defaultdir = NULL; 145 ann->title = NULL; 146} 147 148 149/* Write annotation border style and color */ 150static void 151pdf_write_border_style(PDF *p, pdf_annot *ann) 152{ 153 /* don't write the default values */ 154 if (ann->border_style == border_solid && 155 ann->border_width == (float) 1.0 && 156 ann->border_red == (float) 0.0 && 157 ann->border_green == (float) 0.0 && 158 ann->border_blue == (float) 0.0 && 159 ann->border_dash1 == (float) 3.0 && 160 ann->border_dash2 == (float) 3.0) 161 return; 162 163 if (ann->type != ann_attach) { 164 pdc_puts(p->out, "/BS"); 165 pdc_begin_dict(p->out); /* BS dict */ 166 pdc_puts(p->out, "/Type/Border\n"); 167 168 /* Acrobat 6 requires this entry, and does not use /S/S as default */ 169 pdc_printf(p->out, "/S/%s\n", 170 pdf_border_style_names[ann->border_style]); 171 172 /* Acrobat 6 requires this entry */ 173 pdc_printf(p->out, "/W %f\n", ann->border_width); 174 175 if (ann->border_style == border_dashed) 176 pdc_printf(p->out, "/D[%f %f]\n", 177 ann->border_dash1, ann->border_dash2); 178 179 pdc_end_dict(p->out); /* BS dict */ 180 181 /* Write the Border key in old-style PDF 1.1 format */ 182 pdc_printf(p->out, "/Border[0 0 %f", ann->border_width); 183 184 if (ann->border_style == border_dashed && 185 (ann->border_dash1 != (float) 0.0 || ann->border_dash2 != 186 (float) 0.0)) 187 /* set dashed border */ 188 pdc_printf(p->out, "[%f %f]", ann->border_dash1, ann->border_dash2); 189 190 pdc_puts(p->out, "]\n"); 191 192 } 193 194 /* write annotation color */ 195 pdc_printf(p->out, "/C[%f %f %f]\n", 196 ann->border_red, ann->border_green, ann->border_blue); 197} 198 199void 200pdf_write_annots_root(PDF *p) 201{ 202 pdf_annot *ann; 203 204 /* Annotations array */ 205 if (p->annots) { 206 pdc_puts(p->out, "/Annots["); 207 208 for (ann = p->annots; ann != NULL; ann = ann->next) { 209 ann->obj_id = pdc_alloc_id(p->out); 210 pdc_printf(p->out, "%ld 0 R ", ann->obj_id); 211 } 212 213 pdc_puts(p->out, "]\n"); 214 } 215} 216 217void 218pdf_write_page_annots(PDF *p) 219{ 220 pdf_annot *ann; 221 222 for (ann = p->annots; ann != NULL; ann = ann->next) { 223 224 pdc_begin_obj(p->out, ann->obj_id); /* Annotation object */ 225 pdc_begin_dict(p->out); /* Annotation dict */ 226 227 228 pdc_puts(p->out, "/Type/Annot\n"); 229 switch (ann->type) { 230 case ann_text: 231 pdc_puts(p->out, "/Subtype/Text\n"); 232 pdc_printf(p->out, "/Rect[%f %f %f %f]\n", 233 ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury); 234 235 pdf_write_border_style(p, ann); 236 237 if (ann->open) 238 pdc_puts(p->out, "/Open true\n"); 239 240 if (ann->icon != icon_text_note) /* note is default */ 241 pdc_printf(p->out, "/Name/%s\n", pdf_icon_names[ann->icon]); 242 243 /* Contents key is required, but may be empty */ 244 pdc_puts(p->out, "/Contents"); 245 246 if (ann->contents) { 247 pdc_put_pdfunistring(p->out, ann->contents); 248 pdc_puts(p->out, "\n"); 249 } else 250 pdc_puts(p->out, "()\n"); /* empty contents is OK */ 251 252 /* title is optional */ 253 if (ann->title) { 254 pdc_puts(p->out, "/T"); 255 pdc_put_pdfunistring(p->out, ann->title); 256 pdc_puts(p->out, "\n"); 257 } 258 259 break; 260 261 case ann_locallink: 262 pdc_puts(p->out, "/Subtype/Link\n"); 263 pdc_printf(p->out, "/Rect[%f %f %f %f]\n", 264 ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury); 265 266 pdf_write_border_style(p, ann); 267 268 /* preallocate page object id for a later page */ 269 if (ann->dest.page > p->current_page) { 270 while (ann->dest.page >= p->pages_capacity) 271 pdf_grow_pages(p); 272 273 /* if this page has already been used as a link target 274 * it will already have an object id. 275 */ 276 if (p->pages[ann->dest.page] == PDC_BAD_ID) 277 p->pages[ann->dest.page] = pdc_alloc_id(p->out); 278 } 279 280 pdc_puts(p->out, "/Dest"); 281 pdf_write_destination(p, &ann->dest); 282 pdc_puts(p->out, "\n"); 283 284 break; 285 286 case ann_pdflink: 287 pdc_puts(p->out, "/Subtype/Link\n"); 288 pdc_printf(p->out, "/Rect[%f %f %f %f]\n", 289 ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury); 290 291 pdf_write_border_style(p, ann); 292 293 pdc_puts(p->out, "/A"); 294 pdc_begin_dict(p->out); /* A dict */ 295 pdc_puts(p->out, "/Type/Action/S/GoToR\n"); 296 297 pdc_puts(p->out, "/D"); 298 pdf_write_destination(p, &ann->dest); 299 pdc_puts(p->out, "\n"); 300 301 pdc_puts(p->out, "/F"); 302 pdc_begin_dict(p->out); /* F dict */ 303 pdc_puts(p->out, "/Type/Filespec\n"); 304 pdc_puts(p->out, "/F"); 305 pdc_put_pdfstring(p->out, ann->filename, 306 (int)strlen(ann->filename)); 307 pdc_puts(p->out, "\n"); 308 pdc_end_dict(p->out); /* F dict */ 309 310 pdc_end_dict(p->out); /* A dict */ 311 312 break; 313 314 case ann_launchlink: 315 pdc_puts(p->out, "/Subtype/Link\n"); 316 pdc_printf(p->out, "/Rect[%f %f %f %f]\n", 317 ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury); 318 319 pdf_write_border_style(p, ann); 320 321 pdc_puts(p->out, "/A"); 322 pdc_begin_dict(p->out); /* A dict */ 323 pdc_puts(p->out, "/Type/Action/S/Launch\n"); 324 325 if (ann->parameters || ann->operation || ann->defaultdir) { 326 pdc_puts(p->out, "/Win"); 327 pdc_begin_dict(p->out); /* Win dict */ 328 pdc_printf(p->out, "/F"); 329 pdc_put_pdfstring(p->out, ann->filename, 330 (int)strlen(ann->filename)); 331 pdc_puts(p->out, "\n"); 332 if (ann->parameters) { 333 pdc_printf(p->out, "/P"); 334 pdc_put_pdfstring(p->out, ann->parameters, 335 (int)strlen(ann->parameters)); 336 pdc_puts(p->out, "\n"); 337 pdc_free(p->pdc, ann->parameters); 338 ann->parameters = NULL; 339 } 340 if (ann->operation) { 341 pdc_printf(p->out, "/O"); 342 pdc_put_pdfstring(p->out, ann->operation, 343 (int)strlen(ann->operation)); 344 pdc_puts(p->out, "\n"); 345 pdc_free(p->pdc, ann->operation); 346 ann->operation = NULL; 347 } 348 if (ann->defaultdir) { 349 pdc_printf(p->out, "/D"); 350 pdc_put_pdfstring(p->out, ann->defaultdir, 351 (int)strlen(ann->defaultdir)); 352 pdc_puts(p->out, "\n"); 353 pdc_free(p->pdc, ann->defaultdir); 354 ann->defaultdir = NULL; 355 } 356 pdc_end_dict(p->out); /* Win dict */ 357 } else { 358 pdc_puts(p->out, "/F"); 359 pdc_begin_dict(p->out); /* F dict */ 360 pdc_puts(p->out, "/Type/Filespec\n"); 361 pdc_printf(p->out, "/F"); 362 pdc_put_pdfstring(p->out, ann->filename, 363 (int)strlen(ann->filename)); 364 pdc_puts(p->out, "\n"); 365 pdc_end_dict(p->out); /* F dict */ 366 } 367 368 pdc_end_dict(p->out); /* A dict */ 369 370 break; 371 372 case ann_weblink: 373 pdc_puts(p->out, "/Subtype/Link\n"); 374 pdc_printf(p->out, "/Rect[%f %f %f %f]\n", 375 ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury); 376 377 pdf_write_border_style(p, ann); 378 379 pdc_puts(p->out, "/A<</S/URI/URI"); 380 pdc_put_pdfstring(p->out, ann->filename, 381 (int)strlen(ann->filename)); 382 pdc_puts(p->out, ">>\n"); 383 break; 384 385 case ann_attach: 386 pdc_puts(p->out, "/Subtype/FileAttachment\n"); 387 pdc_printf(p->out, "/Rect[%f %f %f %f]\n", 388 ann->rect.llx, ann->rect.lly, ann->rect.urx, ann->rect.ury); 389 390 pdf_write_border_style(p, ann); 391 392 if (ann->icon != icon_file_pushpin) /* pushpin is default */ 393 pdc_printf(p->out, "/Name/%s\n", 394 pdf_icon_names[ann->icon]); 395 396 if (ann->title) { 397 pdc_puts(p->out, "/T"); 398 pdc_put_pdfunistring(p->out, ann->title); 399 pdc_puts(p->out, "\n"); 400 } 401 402 if (ann->contents) { 403 pdc_puts(p->out, "/Contents"); 404 pdc_put_pdfunistring(p->out, ann->contents); 405 pdc_puts(p->out, "\n"); 406 } 407 408 /* the icon is too small without these flags (=28) */ 409 pdc_printf(p->out, "/F %d\n", 410 pdf_ann_flag_print | 411 pdf_ann_flag_nozoom | 412 pdf_ann_flag_norotate); 413 414 pdc_puts(p->out, "/FS"); 415 pdc_begin_dict(p->out); /* FS dict */ 416 pdc_puts(p->out, "/Type/Filespec\n"); 417 418 pdc_puts(p->out, "/F"); 419 pdc_put_pdfstring(p->out, ann->filename, 420 (int)strlen(ann->filename)); 421 pdc_puts(p->out, "\n"); 422 423 /* alloc id for the actual embedded file stream */ 424 ann->obj_id = pdc_alloc_id(p->out); 425 pdc_printf(p->out, "/EF<</F %ld 0 R>>\n", ann->obj_id); 426 pdc_end_dict(p->out); /* FS dict */ 427 428 break; 429 430 default: 431 pdc_error(p->pdc, PDF_E_INT_BADANNOT, 432 pdc_errprintf(p->pdc, "%d", ann->type), 0, 0, 0); 433 } 434 435 pdc_end_dict(p->out); /* Annotation dict */ 436 pdc_end_obj(p->out); /* Annotation object */ 437 } 438 439 /* Write the actual embedded files with preallocated ids */ 440 for (ann = p->annots; ann != NULL; ann = ann->next) { 441 pdc_id length_id; 442 PDF_data_source src; 443 444 if (ann->type != ann_attach) 445 continue; 446 447 pdc_begin_obj(p->out, ann->obj_id); /* EmbeddedFile */ 448 pdc_puts(p->out, "<</Type/EmbeddedFile\n"); 449 450 if (ann->mimetype) { 451 pdc_puts(p->out, "/Subtype"); 452 pdc_put_pdfname(p->out, ann->mimetype, strlen(ann->mimetype)); 453 pdc_puts(p->out, "\n"); 454 } 455 456 if (pdc_get_compresslevel(p->out)) 457 pdc_puts(p->out, "/Filter/FlateDecode\n"); 458 459 length_id = pdc_alloc_id(p->out); 460 pdc_printf(p->out, "/Length %ld 0 R\n", length_id); 461 pdc_end_dict(p->out); /* F dict */ 462 463 /* write the file in the PDF */ 464 src.private_data = (void *) ann->filename; 465 src.init = pdf_data_source_file_init; 466 src.fill = pdf_data_source_file_fill; 467 src.terminate = pdf_data_source_file_terminate; 468 src.length = (long) 0; 469 src.offset = (long) 0; 470 471 pdf_copy_stream(p, &src, pdc_true); /* embedded file stream */ 472 473 pdc_end_obj(p->out); /* EmbeddedFile object */ 474 475 pdc_put_pdfstreamlength(p->out, length_id); 476 477 if (p->flush & pdf_flush_content) 478 pdc_flush_stream(p->out); 479 } 480} 481 482void 483pdf_init_page_annots(PDF *p) 484{ 485 p->annots = NULL; 486} 487 488void 489pdf_cleanup_page_annots(PDF *p) 490{ 491 pdf_annot *ann, *old; 492 493 for (ann = p->annots; ann != (pdf_annot *) NULL; /* */ ) { 494 switch (ann->type) { 495 case ann_text: 496 if (ann->contents) 497 pdc_free(p->pdc, ann->contents); 498 if (ann->title) 499 pdc_free(p->pdc, ann->title); 500 break; 501 502 case ann_locallink: 503 pdf_cleanup_destination(p, &ann->dest); 504 break; 505 506 case ann_launchlink: 507 pdc_free(p->pdc, ann->filename); 508 break; 509 510 case ann_pdflink: 511 pdf_cleanup_destination(p, &ann->dest); 512 pdc_free(p->pdc, ann->filename); 513 break; 514 515 case ann_weblink: 516 pdc_free(p->pdc, ann->filename); 517 break; 518 519 case ann_attach: 520 pdf_unlock_pvf(p, ann->filename); 521 pdc_free(p->pdc, ann->filename); 522 if (ann->contents) 523 pdc_free(p->pdc, ann->contents); 524 if (ann->title) 525 pdc_free(p->pdc, ann->title); 526 if (ann->mimetype) 527 pdc_free(p->pdc, ann->mimetype); 528 break; 529 530 default: 531 pdc_error(p->pdc, PDF_E_INT_BADANNOT, 532 pdc_errprintf(p->pdc, "%d", ann->type), 0, 0, 0); 533 } 534 old = ann; 535 ann = old->next; 536 pdc_free(p->pdc, old); 537 } 538 p->annots = NULL; 539} 540 541/* Insert new annotation at the end of the annots chain */ 542static void 543pdf_add_annot(PDF *p, pdf_annot *ann) 544{ 545 pdf_annot *last; 546 547 /* fetch current border state from p */ 548 ann->border_style = p->border_style; 549 ann->border_width = p->border_width; 550 ann->border_red = p->border_red; 551 ann->border_green = p->border_green; 552 ann->border_blue = p->border_blue; 553 ann->border_dash1 = p->border_dash1; 554 ann->border_dash2 = p->border_dash2; 555 556 ann->next = NULL; 557 558 if (p->annots == NULL) 559 p->annots = ann; 560 else { 561 for (last = p->annots; last->next != NULL; /* */ ) 562 last = last->next; 563 last->next = ann; 564 } 565} 566 567static void 568pdf_init_rectangle(PDF *p, pdf_annot *ann, 569 float llx, float lly, float urx, float ury) 570{ 571 pdc_rect_init(&ann->rect, llx, lly, urx, ury); 572 if (p->usercoordinates == pdc_true) 573 pdc_rect_transform(&p->gstate[p->sl].ctm, &ann->rect, &ann->rect); 574} 575 576 577 578 579/* Attach an arbitrary file to the PDF. Note that the actual 580 * embedding takes place in PDF_end_page(). 581 * description, author, and mimetype may be NULL. 582 */ 583 584static const pdc_keyconn pdf_icon_attach_keylist[] = 585{ 586 {"graph", icon_file_graph}, 587 {"paperclip", icon_file_paperclip}, 588 {"pushpin", icon_file_pushpin}, 589 {"tag", icon_file_tag}, 590 {NULL, 0} 591}; 592 593static void 594pdf__attach_file( 595 PDF *p, 596 float llx, 597 float lly, 598 float urx, 599 float ury, 600 const char *filename, 601 const char *description, 602 int len_descr, 603 const char *author, 604 int len_auth, 605 const char *mimetype, 606 const char *icon) 607{ 608 static const char fn[] = "pdf__attach_file"; 609 pdf_annot *ann; 610 pdc_file *attfile; 611 612 if (filename == NULL || *filename == '\0') 613 pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "filename", 0, 0, 0); 614 615 if ((attfile = pdf_fopen(p, filename, "attachment ", 0)) == NULL) 616 pdc_error(p->pdc, -1, 0, 0, 0, 0); 617 618 pdf_lock_pvf(p, filename); 619 pdc_fclose(attfile); 620 621 ann = (pdf_annot *) pdc_malloc(p->pdc, sizeof(pdf_annot), fn); 622 623 pdf_init_annot(p, ann); 624 625 ann->type = ann_attach; 626 pdf_init_rectangle(p, ann, llx, lly, urx, ury); 627 628 if (icon == NULL || !*icon) 629 icon = "pushpin"; 630 ann->icon = (pdf_icon) pdc_get_keycode(icon, pdf_icon_attach_keylist); 631 if (ann->icon == PDC_KEY_NOTFOUND) 632 pdc_error(p->pdc, PDC_E_ILLARG_STRING, "icon", icon, 0, 0); 633 634 ann->filename = (char *) pdc_strdup(p->pdc, filename); 635 636 ann->contents = pdf_convert_hypertext(p, description, len_descr); 637 638 ann->title = pdf_convert_hypertext(p, author, len_auth); 639 640 if (mimetype != NULL) { 641 ann->mimetype = (char *) pdc_strdup(p->pdc, mimetype); 642 } 643 644 pdf_add_annot(p, ann); 645} 646 647PDFLIB_API void PDFLIB_CALL 648PDF_attach_file( 649 PDF *p, 650 float llx, 651 float lly, 652 float urx, 653 float ury, 654 const char *filename, 655 const char *description, 656 const char *author, 657 const char *mimetype, 658 const char *icon) 659{ 660 static const char fn[] = "PDF_attach_file"; 661 662 if (pdf_enter_api(p, fn, pdf_state_page, 663 "(p[%p], %g, %g, %g, %g, \"%s\", \"%s\", \"%s\", \"%s\", \"%s\")\n", 664 (void *) p, llx, lly, urx, ury, filename, 665 pdc_strprint(p->pdc, description, 0), 666 pdc_strprint(p->pdc, author, 0), mimetype, icon)) 667 { 668 int len_descr = description ? (int) pdc_strlen(description) : 0; 669 int len_auth = author ? (int) pdc_strlen(author) : 0; 670 pdf__attach_file(p, llx, lly, urx, ury, filename, 671 description, len_descr, author, len_auth, mimetype, icon) ; 672 } 673} 674 675PDFLIB_API void PDFLIB_CALL 676PDF_attach_file2( 677 PDF *p, 678 float llx, 679 float lly, 680 float urx, 681 float ury, 682 const char *filename, 683 int reserved, 684 const char *description, 685 int len_descr, 686 const char *author, 687 int len_auth, 688 const char *mimetype, 689 const char *icon) 690{ 691 static const char fn[] = "PDF_attach_file2"; 692 693 if (pdf_enter_api(p, fn, pdf_state_page, 694 "(p[%p], %g, %g, %g, %g, \"%s\", %d, \"%s\", %d, " 695 "\"%s\", %d, \"%s\", \"%s\")\n", 696 (void *) p, llx, lly, urx, ury, filename, reserved, 697 pdc_strprint(p->pdc, description, len_descr), len_descr, 698 pdc_strprint(p->pdc, author, len_auth), len_auth, mimetype, icon)) 699 { 700 pdf__attach_file(p, llx, lly, urx, ury, filename, 701 description, len_descr, author, len_auth, mimetype, icon) ; 702 } 703} 704 705static const pdc_keyconn pdf_icon_note_keylist[] = 706{ 707 {"comment", icon_text_comment}, 708 {"insert", icon_text_insert}, 709 {"note", icon_text_note}, 710 {"paragraph", icon_text_paragraph}, 711 {"newparagraph", icon_text_newparagraph}, 712 {"key", icon_text_key}, 713 {"help", icon_text_help}, 714 {NULL, 0} 715}; 716 717static void 718pdf__add_note( 719 PDF *p, 720 float llx, 721 float lly, 722 float urx, 723 float ury, 724 const char *contents, 725 int len_cont, 726 const char *title, 727 int len_title, 728 const char *icon, 729 int open) 730{ 731 static const char fn[] = "pdf__add_note"; 732 pdf_annot *ann; 733 734 ann = (pdf_annot *) pdc_malloc(p->pdc, sizeof(pdf_annot), fn); 735 736 pdf_init_annot(p, ann); 737 738 ann->type = ann_text; 739 ann->open = open; 740 pdf_init_rectangle(p, ann, llx, lly, urx, ury); 741 742 if (icon == NULL || !*icon) 743 icon = "note"; 744 ann->icon = (pdf_icon) pdc_get_keycode(icon, pdf_icon_note_keylist); 745 if (ann->icon == PDC_KEY_NOTFOUND) 746 pdc_error(p->pdc, PDC_E_ILLARG_STRING, "icon", icon, 0, 0); 747 748 /* title may be NULL */ 749 ann->title = pdf_convert_hypertext(p, title, len_title); 750 751 /* It is legal to create an empty text annnotation */ 752 ann->contents = pdf_convert_hypertext(p, contents, len_cont); 753 754 pdf_add_annot(p, ann); 755} 756 757PDFLIB_API void PDFLIB_CALL 758PDF_add_note( 759 PDF *p, 760 float llx, 761 float lly, 762 float urx, 763 float ury, 764 const char *contents, 765 const char *title, 766 const char *icon, 767 int open) 768{ 769 static const char fn[] = "PDF_add_note"; 770 771 if (pdf_enter_api(p, fn, pdf_state_page, 772 "(p[%p], %g, %g, %g, %g, \"%s\", \"%s\", \"%s\", %d)\n", 773 (void *) p, llx, lly, urx, ury, 774 pdc_strprint(p->pdc, contents, 0), 775 pdc_strprint(p->pdc, title, 0), icon, open)) 776 { 777 int len_cont = contents ? (int) pdc_strlen(contents) : 0; 778 int len_title = title ? (int) pdc_strlen(title) : 0; 779 pdf__add_note(p, llx, lly, urx, ury, contents, len_cont, 780 title, len_title, icon, open); 781 } 782} 783 784PDFLIB_API void PDFLIB_CALL 785PDF_add_note2( 786 PDF *p, 787 float llx, 788 float lly, 789 float urx, 790 float ury, 791 const char *contents, 792 int len_cont, 793 const char *title, 794 int len_title, 795 const char *icon, 796 int open) 797{ 798 static const char fn[] = "PDF_add_note2"; 799 800 if (pdf_enter_api(p, fn, pdf_state_page, 801 "(p[%p], %g, %g, %g, %g, \"%s\", %d, \"%s\", %d, \"%s\", %d)\n", 802 (void *) p, llx, lly, urx, ury, 803 pdc_strprint(p->pdc, contents, len_cont), len_cont, 804 pdc_strprint(p->pdc, title, len_title), len_title, 805 icon, open)) 806 { 807 pdf__add_note(p, llx, lly, urx, ury, contents, len_cont, 808 title, len_title, icon, open); 809 } 810} 811 812/* Add a link to another PDF file */ 813PDFLIB_API void PDFLIB_CALL 814PDF_add_pdflink( 815 PDF *p, 816 float llx, 817 float lly, 818 float urx, 819 float ury, 820 const char *filename, 821 int page, 822 const char *optlist) 823{ 824 static const char fn[] = "PDF_add_pdflink"; 825 pdf_annot *ann; 826 827 if (!pdf_enter_api(p, fn, pdf_state_page, 828 "(p[%p], %g, %g, %g, %g, \"%s\", %d, \"%s\")\n", 829 (void *) p, llx, lly, urx, ury, filename, page, optlist)) 830 { 831 return; 832 } 833 834 if (filename == NULL) 835 pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "filename", 0, 0, 0); 836 837 ann = (pdf_annot *) pdc_malloc(p->pdc, sizeof(pdf_annot), fn); 838 839 pdf_init_annot(p, ann); 840 841 ann->filename = pdc_strdup(p->pdc, filename); 842 843 ann->type = ann_pdflink; 844 845 pdf_parse_destination_optlist(p, optlist, &ann->dest, page, pdf_remotelink); 846 847 pdf_init_rectangle(p, ann, llx, lly, urx, ury); 848 849 pdf_add_annot(p, ann); 850} 851 852/* Add a link to another file of an arbitrary type */ 853PDFLIB_API void PDFLIB_CALL 854PDF_add_launchlink( 855 PDF *p, 856 float llx, 857 float lly, 858 float urx, 859 float ury, 860 const char *filename) 861{ 862 static const char fn[] = "PDF_add_launchlink"; 863 pdf_annot *ann; 864 865 if (!pdf_enter_api(p, fn, pdf_state_page, 866 "(p[%p], %g, %g, %g, %g, \"%s\")\n", 867 (void *)p, llx, lly, urx, ury, filename)) 868 { 869 return; 870 } 871 872 if (filename == NULL) 873 pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "filename", 0, 0, 0); 874 875 ann = (pdf_annot *) pdc_malloc(p->pdc, sizeof(pdf_annot), fn); 876 877 pdf_init_annot(p, ann); 878 879 ann->filename = pdc_strdup(p->pdc, filename); 880 881 ann->type = ann_launchlink; 882 883 if (p->launchlink_parameters) { 884 ann->parameters = p->launchlink_parameters; 885 p->launchlink_parameters = NULL; 886 } 887 888 if (p->launchlink_operation) { 889 ann->operation = p->launchlink_operation; 890 p->launchlink_operation = NULL; 891 } 892 893 if (p->launchlink_defaultdir) { 894 ann->defaultdir = p->launchlink_defaultdir; 895 p->launchlink_defaultdir = NULL; 896 } 897 898 pdf_init_rectangle(p, ann, llx, lly, urx, ury); 899 900 pdf_add_annot(p, ann); 901} 902 903/* Add a link to a destination in the current PDF file */ 904PDFLIB_API void PDFLIB_CALL 905PDF_add_locallink( 906 PDF *p, 907 float llx, 908 float lly, 909 float urx, 910 float ury, 911 int page, 912 const char *optlist) 913{ 914 static const char fn[] = "PDF_add_locallink"; 915 pdf_annot *ann; 916 917 if (!pdf_enter_api(p, fn, pdf_state_page, 918 "(p[%p], %g, %g, %g, %g, %d, \"%s\")\n", 919 (void *) p, llx, lly, urx, ury, page, optlist)) 920 { 921 return; 922 } 923 924 ann = (pdf_annot *) pdc_malloc(p->pdc, sizeof(pdf_annot), fn); 925 926 pdf_init_annot(p, ann); 927 928 ann->type = ann_locallink; 929 930 pdf_parse_destination_optlist(p, optlist, &ann->dest, page, pdf_locallink); 931 932 pdf_init_rectangle(p, ann, llx, lly, urx, ury); 933 934 pdf_add_annot(p, ann); 935} 936 937/* Add a link to an arbitrary Internet resource (URL) */ 938PDFLIB_API void PDFLIB_CALL 939PDF_add_weblink( 940 PDF *p, 941 float llx, 942 float lly, 943 float urx, 944 float ury, 945 const char *url) 946{ 947 static const char fn[] = "PDF_add_weblink"; 948 pdf_annot *ann; 949 950 if (!pdf_enter_api(p, fn, pdf_state_page, 951 "(p[%p], %g, %g, %g, %g, \"%s\")\n", 952 (void *) p, llx, lly, urx, ury, url)) 953 { 954 return; 955 } 956 957 if (url == NULL || *url == '\0') 958 pdc_error(p->pdc, PDC_E_ILLARG_EMPTY, "url", 0, 0, 0); 959 960 ann = (pdf_annot *) pdc_malloc(p->pdc, sizeof(pdf_annot), fn); 961 962 pdf_init_annot(p, ann); 963 964 ann->filename = pdc_strdup(p->pdc, url); 965 966 ann->type = ann_weblink; 967 pdf_init_rectangle(p, ann, llx, lly, urx, ury); 968 969 pdf_add_annot(p, ann); 970} 971 972PDFLIB_API void PDFLIB_CALL 973PDF_set_border_style(PDF *p, const char *style, float width) 974{ 975 static const char fn[] = "PDF_set_border_style"; 976 977 if (!pdf_enter_api(p, fn, 978 (pdf_state) (pdf_state_document | pdf_state_page), 979 "(p[%p], \"%s\", %g)\n", (void *) p, style, width)) 980 { 981 return; 982 } 983 984 if (style == NULL) 985 p->border_style = border_solid; 986 else if (!strcmp(style, "solid")) 987 p->border_style = border_solid; 988 else if (!strcmp(style, "dashed")) 989 p->border_style = border_dashed; 990 else 991 pdc_error(p->pdc, PDC_E_ILLARG_STRING, "style", style, 0, 0); 992 993 if (width < 0.0) 994 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 995 "width", pdc_errprintf(p->pdc, "%f", width), 0, 0); 996 997 p->border_width = width; 998} 999 1000PDFLIB_API void PDFLIB_CALL 1001PDF_set_border_color(PDF *p, float red, float green, float blue) 1002{ 1003 static const char fn[] = "PDF_set_border_color"; 1004 1005 if (!pdf_enter_api(p, fn, 1006 (pdf_state) (pdf_state_document | pdf_state_page), 1007 "(p[%p], %g, %g, %g)\n", (void *) p, red, green, blue)) 1008 { 1009 return; 1010 } 1011 1012 if (red < 0.0 || red > 1.0) 1013 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 1014 "red", pdc_errprintf(p->pdc, "%f", red), 0, 0); 1015 if (green < 0.0 || green > 1.0) 1016 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 1017 "green", pdc_errprintf(p->pdc, "%f", green), 0, 0); 1018 if (blue < 0.0 || blue > 1.0) 1019 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 1020 "blue", pdc_errprintf(p->pdc, "%f", blue), 0, 0); 1021 1022 p->border_red = red; 1023 p->border_green = green; 1024 p->border_blue = blue; 1025} 1026 1027PDFLIB_API void PDFLIB_CALL 1028PDF_set_border_dash(PDF *p, float b, float w) 1029{ 1030 static const char fn[] = "PDF_set_border_dash"; 1031 1032 if (!pdf_enter_api(p, fn, 1033 (pdf_state) (pdf_state_document | pdf_state_page), 1034 "(p[%p], %g, %g)\n", (void *) p, b, w)) 1035 { 1036 return; 1037 } 1038 1039 if (b < 0.0) 1040 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 1041 "b", pdc_errprintf(p->pdc, "%f", b), 0, 0); 1042 1043 if (w < 0.0) 1044 pdc_error(p->pdc, PDC_E_ILLARG_FLOAT, 1045 "w", pdc_errprintf(p->pdc, "%f", w), 0, 0); 1046 1047 p->border_dash1 = b; 1048 p->border_dash2 = w; 1049} 1050