github.com/unidoc/unidoc@v2.2.0+incompatible/pdf/creator/creator_test.go (about) 1 /* 2 * This file is subject to the terms and conditions defined in 3 * file 'LICENSE.md', which is part of this source code package. 4 */ 5 6 package creator 7 8 // This test file contains multiple tests to generate PDFs. The outputs are written into /tmp as files. The files 9 // themselves need to be observed to check for correctness as we don't have a good way to automatically check 10 // if every detail is correct. 11 12 import ( 13 "fmt" 14 goimage "image" 15 "io/ioutil" 16 "math" 17 "testing" 18 19 "github.com/boombuler/barcode" 20 "github.com/boombuler/barcode/qr" 21 22 "github.com/unidoc/unidoc/common" 23 "github.com/unidoc/unidoc/pdf/core" 24 "github.com/unidoc/unidoc/pdf/model" 25 "github.com/unidoc/unidoc/pdf/model/fonts" 26 "github.com/unidoc/unidoc/pdf/model/textencoding" 27 ) 28 29 func init() { 30 common.SetLogger(common.NewConsoleLogger(common.LogLevelDebug)) 31 } 32 33 const testPdfFile1 = "../../testfiles/minimal.pdf" 34 const testPdfLoremIpsumFile = "../../testfiles/lorem.pdf" 35 const testPdfTemplatesFile1 = "../../testfiles/templates1.pdf" 36 const testImageFile1 = "../../testfiles/logo.png" 37 const testImageFile2 = "../../testfiles/signature.png" 38 const testRobotoRegularTTFFile = "../../testfiles/roboto/Roboto-Regular.ttf" 39 const testRobotoBoldTTFFile = "../../testfiles/roboto/Roboto-Bold.ttf" 40 41 func TestTemplate1(t *testing.T) { 42 creator := New() 43 44 pages, err := loadPagesFromFile(testPdfFile1) 45 if err != nil { 46 t.Errorf("Fail: %v\n", err) 47 return 48 } 49 50 template, err := NewBlockFromPage(pages[0]) 51 if err != nil { 52 t.Errorf("Fail: %v\n", err) 53 return 54 } 55 56 template.SetPos(0, 0) 57 creator.Draw(template) 58 59 template.SetAngle(45) 60 creator.Draw(template) 61 62 template.Scale(0.5, 0.5) 63 creator.Draw(template) 64 65 template.Scale(4, 4) 66 creator.Draw(template) 67 68 template.SetAngle(90) 69 template.SetPos(100, 200) 70 creator.Draw(template) 71 72 creator.WriteToFile("/tmp/template_1.pdf") 73 74 return 75 } 76 77 // TestImage1 tests loading an image and adding to file at an absolute position. 78 func TestImage1(t *testing.T) { 79 creator := New() 80 81 imgData, err := ioutil.ReadFile(testImageFile1) 82 if err != nil { 83 t.Errorf("Fail: %v\n", err) 84 return 85 } 86 87 img, err := NewImageFromData(imgData) 88 if err != nil { 89 t.Errorf("Fail: %v\n", err) 90 return 91 } 92 93 img.SetPos(0, 100) 94 img.ScaleToWidth(1.0 * creator.Width()) 95 96 err = creator.Draw(img) 97 if err != nil { 98 t.Errorf("Fail: %v\n", err) 99 return 100 } 101 102 err = creator.WriteToFile("/tmp/1.pdf") 103 if err != nil { 104 t.Errorf("Fail: %v\n", err) 105 return 106 } 107 } 108 109 // TestImageWithEncoder tests loading inserting an image with a specified encoder. 110 func TestImageWithEncoder(t *testing.T) { 111 creator := New() 112 113 imgData, err := ioutil.ReadFile(testImageFile1) 114 if err != nil { 115 t.Errorf("Fail: %v\n", err) 116 return 117 } 118 119 img, err := NewImageFromData(imgData) 120 if err != nil { 121 t.Errorf("Fail: %v\n", err) 122 return 123 } 124 125 // JPEG encoder (DCT) with quality factor 70. 126 encoder := core.NewDCTEncoder() 127 encoder.Quality = 70 128 encoder.Width = int(img.Width()) 129 encoder.Height = int(img.Height()) 130 img.SetEncoder(encoder) 131 132 img.SetPos(0, 100) 133 img.ScaleToWidth(1.0 * creator.Width()) 134 135 err = creator.Draw(img) 136 if err != nil { 137 t.Errorf("Fail: %v\n", err) 138 return 139 } 140 141 err = creator.WriteToFile("/tmp/1_dct.pdf") 142 if err != nil { 143 t.Errorf("Fail: %v\n", err) 144 return 145 } 146 } 147 148 func TestShapes1(t *testing.T) { 149 creator := New() 150 151 imgData, err := ioutil.ReadFile(testImageFile1) 152 if err != nil { 153 t.Errorf("Fail: %v\n", err) 154 return 155 } 156 157 img, err := NewImageFromData(imgData) 158 if err != nil { 159 t.Errorf("Fail: %v\n", err) 160 return 161 } 162 163 img.SetPos(0, 100) 164 img.ScaleToWidth(1.0 * creator.Width()) 165 166 err = creator.Draw(img) 167 if err != nil { 168 t.Errorf("Fail: %v\n", err) 169 return 170 } 171 172 // Add line. 173 line := NewLine(0, 0, 100, 100) 174 line.SetLineWidth(3.0) 175 line.SetColor(ColorRGBFromHex("#ff0000")) 176 err = creator.Draw(line) 177 if err != nil { 178 t.Errorf("Fail: %v\n", err) 179 return 180 } 181 182 // Add rect with default params. 183 rect := NewRectangle(100, 100, 100, 100) 184 err = creator.Draw(rect) 185 if err != nil { 186 t.Errorf("Fail: %v\n", err) 187 return 188 } 189 190 // Add rect with fill and large border 191 rect = NewRectangle(100, 500, 100, 100) 192 rect.SetBorderColor(ColorRGBFromHex("#00ff00")) // Green border 193 rect.SetBorderWidth(15.0) 194 rect.SetFillColor(ColorRGBFromHex("#0000ff")) // Blue fill 195 err = creator.Draw(rect) 196 if err != nil { 197 t.Errorf("Fail: %v\n", err) 198 return 199 } 200 201 // Draw a circle. (inscribed inside the previous rectangle). 202 ell := NewEllipse(100, 100, 100, 100) 203 err = creator.Draw(ell) 204 if err != nil { 205 t.Errorf("Fail: %v\n", err) 206 return 207 } 208 209 // Draw a circle around upper right page corner. 210 ell = NewEllipse(creator.Width(), 0, 100, 100) 211 err = creator.Draw(ell) 212 if err != nil { 213 t.Errorf("Fail: %v\n", err) 214 return 215 } 216 217 // Draw an ellipse with fill and border. 218 ell = NewEllipse(500, 100, 100, 200) 219 ell.SetFillColor(ColorRGBFromHex("#ccc")) // Gray fill 220 ell.SetBorderWidth(10.0) 221 err = creator.Draw(ell) 222 if err != nil { 223 t.Errorf("Fail: %v\n", err) 224 return 225 } 226 227 err = creator.WriteToFile("/tmp/1_shapes.pdf") 228 if err != nil { 229 t.Errorf("Fail: %v\n", err) 230 return 231 } 232 } 233 234 // Example drawing image and line shape on a block and applying to pages, also demonstrating block rotation. 235 func TestShapesOnBlock(t *testing.T) { 236 creator := New() 237 238 block := NewBlock(creator.Width(), 200) 239 240 imgData, err := ioutil.ReadFile(testImageFile1) 241 if err != nil { 242 t.Errorf("Fail: %v\n", err) 243 return 244 } 245 246 img, err := NewImageFromData(imgData) 247 if err != nil { 248 t.Errorf("Fail: %v\n", err) 249 return 250 } 251 252 img.SetPos(50, 75) 253 img.ScaleToHeight(100.0) 254 block.Draw(img) 255 256 // Add line. 257 line := NewLine(0, 180, creator.Width(), 180) 258 line.SetLineWidth(10.0) 259 line.SetColor(ColorRGBFromHex("#ff0000")) 260 block.Draw(line) 261 262 creator.NewPage() 263 creator.MoveTo(0, 0) 264 creator.Draw(block) 265 266 creator.NewPage() 267 creator.MoveTo(0, 200) 268 creator.Draw(block) 269 270 creator.NewPage() 271 creator.MoveTo(0, 700) 272 block.SetAngle(90) 273 creator.Draw(block) 274 275 err = creator.WriteToFile("/tmp/1_shapes_on_block.pdf") 276 if err != nil { 277 t.Errorf("Fail: %v\n", err) 278 return 279 } 280 } 281 282 // Test image wrapping between pages when using relative context mode. 283 func TestImageWrapping(t *testing.T) { 284 creator := New() 285 286 imgData, err := ioutil.ReadFile(testImageFile1) 287 if err != nil { 288 t.Errorf("Fail: %v\n", err) 289 return 290 } 291 292 img, err := NewImageFromData(imgData) 293 if err != nil { 294 t.Errorf("Fail: %v\n", err) 295 return 296 } 297 298 for j := 0; j < 40; j++ { 299 img.ScaleToWidth(100 + 10*float64(j+1)) 300 301 err = creator.Draw(img) 302 if err != nil { 303 t.Errorf("Fail: %v\n", err) 304 return 305 } 306 } 307 308 err = creator.WriteToFile("/tmp/1_wrap.pdf") 309 if err != nil { 310 t.Errorf("Fail: %v\n", err) 311 return 312 } 313 } 314 315 // Test rotating image. Rotating about upper left corner. 316 func TestImageRotation(t *testing.T) { 317 creator := New() 318 319 imgData, err := ioutil.ReadFile(testImageFile1) 320 if err != nil { 321 t.Errorf("Fail: %v\n", err) 322 return 323 } 324 325 img, err := NewImageFromData(imgData) 326 if err != nil { 327 t.Errorf("Fail: %v\n", err) 328 return 329 } 330 331 //creator.MoveTo(0, 0) 332 img.ScaleToWidth(100) 333 334 angles := []float64{0, 90, 180, 270} 335 for _, angle := range angles { 336 creator.NewPage() 337 338 creator.MoveTo(100, 100) 339 340 img.SetAngle(angle) 341 err = creator.Draw(img) 342 if err != nil { 343 t.Errorf("Fail: %v\n", err) 344 return 345 } 346 } 347 348 err = creator.WriteToFile("/tmp/1_rotate.pdf") 349 if err != nil { 350 t.Errorf("Fail: %v\n", err) 351 return 352 } 353 } 354 355 // Test image, rotation and page wrapping. Disadvantage here is that content is overlapping. May be reconsidered 356 // in the future. And actually reconsider overall how images are used in the relative context mode. 357 func TestImageRotationAndWrap(t *testing.T) { 358 creator := New() 359 360 imgData, err := ioutil.ReadFile(testImageFile1) 361 if err != nil { 362 t.Errorf("Fail: %v\n", err) 363 return 364 } 365 366 img, err := NewImageFromData(imgData) 367 if err != nil { 368 t.Errorf("Fail: %v\n", err) 369 return 370 } 371 img.ScaleToWidth(100) 372 373 creator.NewPage() 374 375 creator.MoveTo(100, 100) 376 377 angles := []float64{0, 90, 180, 270, 0, 90, 180, 270} 378 //angles := []float64{0, 0, 45, 90} 379 380 for _, angle := range angles { 381 img.SetAngle(angle) 382 383 err = creator.Draw(img) 384 if err != nil { 385 t.Errorf("Fail: %v\n", err) 386 return 387 } 388 } 389 390 err = creator.WriteToFile("/tmp/rotate_2.pdf") 391 if err != nil { 392 t.Errorf("Fail: %v\n", err) 393 return 394 } 395 } 396 397 // Test basic paragraph with default font. 398 func TestParagraph1(t *testing.T) { 399 creator := New() 400 401 p := NewParagraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt" + 402 "ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " + 403 "aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore" + 404 "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " + 405 "mollit anim id est laborum.") 406 407 err := creator.Draw(p) 408 if err != nil { 409 t.Errorf("Fail: %v\n", err) 410 return 411 } 412 413 err = creator.WriteToFile("/tmp/2_p1.pdf") 414 if err != nil { 415 t.Errorf("Fail: %v\n", err) 416 return 417 } 418 } 419 420 // Test paragraph and page and text wrapping with left, justify, center and right modes. 421 // TODO: In the future we would like the paragraph to split up between pages. Split up on line, never allowing 422 // less than 2 lines to go over (common practice). 423 // TODO: In the future we would like to implement Donald Knuth's line wrapping algorithm or something similar. 424 func TestParagraphWrapping(t *testing.T) { 425 creator := New() 426 427 p := NewParagraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt" + 428 "ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " + 429 "aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore" + 430 "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " + 431 "mollit anim id est laborum.") 432 433 p.SetMargins(0, 0, 5, 0) 434 435 alignments := []TextAlignment{TextAlignmentLeft, TextAlignmentJustify, TextAlignmentCenter, TextAlignmentRight} 436 for j := 0; j < 25; j++ { 437 //p.SetAlignment(alignments[j%4]) 438 p.SetTextAlignment(alignments[1]) 439 440 err := creator.Draw(p) 441 if err != nil { 442 t.Errorf("Fail: %v\n", err) 443 return 444 } 445 } 446 447 err := creator.WriteToFile("/tmp/2_pwrap.pdf") 448 if err != nil { 449 t.Errorf("Fail: %v\n", err) 450 return 451 } 452 } 453 454 func TestParagraphWrapping2(t *testing.T) { 455 creator := New() 456 457 p := NewParagraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt" + 458 "ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " + 459 "aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore" + 460 "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " + 461 "mollit anim id est laborum.") 462 463 alignments := []TextAlignment{TextAlignmentLeft, TextAlignmentJustify, TextAlignmentCenter, TextAlignmentRight} 464 for j := 0; j < 25; j++ { 465 //p.SetAlignment(alignments[j%4]) 466 p.SetMargins(50, 50, 50, 50) 467 p.SetTextAlignment(alignments[1]) 468 469 err := creator.Draw(p) 470 if err != nil { 471 t.Errorf("Fail: %v\n", err) 472 return 473 } 474 } 475 476 err := creator.WriteToFile("/tmp/2_pwrap2.pdf") 477 if err != nil { 478 t.Errorf("Fail: %v\n", err) 479 return 480 } 481 } 482 483 // Test writing with TTF fonts. 484 func TestParagraphFonts(t *testing.T) { 485 creator := New() 486 487 roboto, err := model.NewPdfFontFromTTFFile(testRobotoRegularTTFFile) 488 if err != nil { 489 t.Errorf("Fail: %v\n", err) 490 return 491 } 492 493 robotoBold, err := model.NewPdfFontFromTTFFile(testRobotoBoldTTFFile) 494 if err != nil { 495 t.Errorf("Fail: %v\n", err) 496 return 497 } 498 499 fonts := []fonts.Font{roboto, robotoBold, fonts.NewFontHelvetica(), roboto, robotoBold, fonts.NewFontHelvetica()} 500 for _, font := range fonts { 501 p := NewParagraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt" + 502 "ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " + 503 "aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore" + 504 "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " + 505 "mollit anim id est laborum.") 506 p.SetFont(font) 507 p.SetFontSize(14) 508 //p.SetWrapWidth(0.8 * creator.Width()) 509 p.SetTextAlignment(TextAlignmentJustify) 510 p.SetLineHeight(1.2) 511 p.SetMargins(0, 0, 5, 0) 512 513 err = creator.Draw(p) 514 if err != nil { 515 t.Errorf("Fail: %v\n", err) 516 return 517 } 518 } 519 520 err = creator.WriteToFile("/tmp/2_pArial.pdf") 521 if err != nil { 522 t.Errorf("Fail: %v\n", err) 523 return 524 } 525 } 526 527 // Test writing with the 14 built in fonts. 528 func TestParagraphStandardFonts(t *testing.T) { 529 creator := New() 530 531 names := []string{ 532 "Courier", 533 "Courier-Bold", 534 "Courier-BoldOblique", 535 "Courier-Oblique", 536 "Helvetica", 537 "Helvetica-Bold", 538 "Helvetica-BoldOblique", 539 "Helvetica-Oblique", 540 "Times-Roman", 541 "Times-Bold", 542 "Times-BoldItalic", 543 "Times-Italic", 544 "Symbol", 545 "ZapfDingbats", 546 } 547 fonts := []fonts.Font{ 548 fonts.NewFontCourier(), 549 fonts.NewFontCourierBold(), 550 fonts.NewFontCourierBoldOblique(), 551 fonts.NewFontCourierOblique(), 552 fonts.NewFontHelvetica(), 553 fonts.NewFontHelveticaBold(), 554 fonts.NewFontHelveticaBoldOblique(), 555 fonts.NewFontHelveticaOblique(), 556 fonts.NewFontTimesRoman(), 557 fonts.NewFontTimesBold(), 558 fonts.NewFontTimesBoldItalic(), 559 fonts.NewFontTimesItalic(), 560 fonts.NewFontSymbol(), 561 fonts.NewFontZapfDingbats(), 562 } 563 texts := []string{ 564 "Courier: Lorem ipsum dolor sit amet, consectetur adipiscing elit...", 565 "Courier-Bold: Lorem ipsum dolor sit amet, consectetur adipiscing elit...", 566 "Courier-BoldOblique: Lorem ipsum dolor sit amet, consectetur adipiscing elit...", 567 "Courier-Oblique: Lorem ipsum dolor sit amet, consectetur adipiscing elit...", 568 569 "Helvetica: Lorem ipsum dolor sit amet, consectetur adipiscing elit...", 570 "Helvetica-Bold: Lorem ipsum dolor sit amet, consectetur adipiscing elit...", 571 "Helvetica-BoldOblique: Lorem ipsum dolor sit amet, consectetur adipiscing elit...", 572 "Helvetica-Oblique: Lorem ipsum dolor sit amet, consectetur adipiscing elit...", 573 574 "Times-Roman: Lorem ipsum dolor sit amet, consectetur adipiscing elit...", 575 "Times-Bold: Lorem ipsum dolor sit amet, consectetur adipiscing elit...", 576 "Times-BoldItalic: Lorem ipsum dolor sit amet, consectetur adipiscing elit...", 577 "Times-Italic: Lorem ipsum dolor sit amet, consectetur adipiscing elit...", 578 "\u2206\u0393\u0020\u2192\u0020\u0030", // Delta Gamma space arrowright space zero (demonstrate Symbol font) 579 "\u2702\u0020\u2709\u261e\u2711\u2714", // a2 (scissors) space a117 (mail) a12 (finger) a17 (pen) a20 (checkmark) 580 } 581 582 for idx, font := range fonts { 583 p := NewParagraph(texts[idx]) 584 p.SetFont(font) 585 p.SetFontSize(12) 586 p.SetLineHeight(1.2) 587 p.SetMargins(0, 0, 5, 0) 588 589 if names[idx] == "Symbol" { 590 // For Symbol font, need to use Symbol encoder. 591 p.SetEncoder(textencoding.NewSymbolEncoder()) 592 } else if names[idx] == "ZapfDingbats" { 593 // Font ZapfDingbats font, need to use ZapfDingbats encoder. 594 p.SetEncoder(textencoding.NewZapfDingbatsEncoder()) 595 } 596 597 err := creator.Draw(p) 598 if err != nil { 599 t.Errorf("Fail: %v\n", err) 600 return 601 } 602 } 603 604 err := creator.WriteToFile("/tmp/2_standard14fonts.pdf") 605 if err != nil { 606 t.Errorf("Fail: %v\n", err) 607 return 608 } 609 } 610 611 // Tests creating a chapter with paragraphs. 612 func TestChapter(t *testing.T) { 613 c := New() 614 615 ch1 := c.NewChapter("Introduction") 616 617 p := NewParagraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt " + 618 "ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " + 619 "aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore " + 620 "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " + 621 "mollit anim id est laborum.") 622 p.SetMargins(0, 0, 10, 0) 623 624 for j := 0; j < 55; j++ { 625 ch1.Add(p) // Can add any drawable.. 626 } 627 628 c.Draw(ch1) 629 630 err := c.WriteToFile("/tmp/3_chapters.pdf") 631 if err != nil { 632 t.Errorf("Fail: %v\n", err) 633 return 634 } 635 } 636 637 // Tests creating a chapter with paragraphs. 638 func TestChapterMargins(t *testing.T) { 639 c := New() 640 641 for j := 0; j < 20; j++ { 642 ch := c.NewChapter(fmt.Sprintf("Chapter %d", j+1)) 643 if j < 5 { 644 ch.SetMargins(3*float64(j), 3*float64(j), 5+float64(j), 0) 645 } 646 647 p := NewParagraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt " + 648 "ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " + 649 "aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore " + 650 "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " + 651 "mollit anim id est laborum.") 652 p.SetTextAlignment(TextAlignmentJustify) 653 ch.Add(p) 654 c.Draw(ch) 655 } 656 657 err := c.WriteToFile("/tmp/3_chapters_margins.pdf") 658 if err != nil { 659 t.Errorf("Fail: %v\n", err) 660 return 661 } 662 } 663 664 // Test creating and drawing subchapters with text content. 665 // Also generates a front page, and a table of contents. 666 func TestSubchaptersSimple(t *testing.T) { 667 c := New() 668 669 ch1 := c.NewChapter("Introduction") 670 subchap1 := c.NewSubchapter(ch1, "The fundamentals of the mastery of the most genious experiment of all times in modern world history. The story of the maker and the maker bot and the genius cow.") 671 subchap1.SetMargins(0, 0, 5, 0) 672 673 //subCh1 := NewSubchapter(ch1, "Workflow") 674 675 p := NewParagraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt " + 676 "ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " + 677 "aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore " + 678 "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " + 679 "mollit anim id est laborum.") 680 p.SetTextAlignment(TextAlignmentJustify) 681 p.SetMargins(0, 0, 5, 0) 682 for j := 0; j < 1; j++ { 683 subchap1.Add(p) 684 } 685 686 subchap2 := c.NewSubchapter(ch1, "Mechanism") 687 subchap2.SetMargins(0, 0, 5, 0) 688 for j := 0; j < 1; j++ { 689 subchap2.Add(p) 690 } 691 692 subchap3 := c.NewSubchapter(ch1, "Discussion") 693 subchap3.SetMargins(0, 0, 5, 0) 694 for j := 0; j < 1; j++ { 695 subchap3.Add(p) 696 } 697 698 subchap4 := c.NewSubchapter(ch1, "Conclusion") 699 subchap4.SetMargins(0, 0, 5, 0) 700 for j := 0; j < 1; j++ { 701 subchap4.Add(p) 702 } 703 c.Draw(ch1) 704 705 ch2 := c.NewChapter("References") 706 for j := 0; j < 13; j++ { 707 ch2.Add(p) 708 } 709 c.Draw(ch2) 710 711 // Set a function to create the front Page. 712 c.CreateFrontPage(func(args FrontpageFunctionArgs) { 713 p := NewParagraph("Example Report") 714 p.SetWidth(c.Width()) 715 p.SetTextAlignment(TextAlignmentCenter) 716 p.SetFontSize(32) 717 p.SetPos(0, 300) 718 c.Draw(p) 719 720 p.SetFontSize(22) 721 p.SetText("Example Report Data Results") 722 p.SetPos(0, 340) 723 c.Draw(p) 724 }) 725 726 // Set a function to create the table of contents. 727 // Should be able to wrap.. 728 c.CreateTableOfContents(func(toc *TableOfContents) (*Chapter, error) { 729 ch := c.NewChapter("Table of contents") 730 ch.GetHeading().SetColor(ColorRGBFromArithmetic(0.5, 0.5, 0.5)) 731 ch.GetHeading().SetFontSize(28) 732 ch.GetHeading().SetMargins(0, 0, 0, 30) 733 734 table := NewTable(2) // 2 column table. 735 // Default, equal column sizes (4x0.25)... 736 table.SetColumnWidths(0.9, 0.1) 737 738 for _, entry := range toc.entries { 739 // Col 1. Chapter number, title. 740 var str string 741 if entry.Subchapter == 0 { 742 str = fmt.Sprintf("%d. %s", entry.Chapter, entry.Title) 743 } else { 744 str = fmt.Sprintf(" %d.%d. %s", entry.Chapter, entry.Subchapter, entry.Title) 745 } 746 p := NewParagraph(str) 747 p.SetFontSize(14) 748 cell := table.NewCell() 749 cell.SetContent(p) 750 // Set the paragraph width to the cell width. 751 p.SetWidth(cell.Width(c.Context())) 752 table.SetRowHeight(table.CurRow(), p.Height()*1.2) 753 754 // Col 1. Page number. 755 p = NewParagraph(fmt.Sprintf("%d", entry.PageNumber)) 756 p.SetFontSize(14) 757 cell = table.NewCell() 758 cell.SetContent(p) 759 } 760 err := ch.Add(table) 761 if err != nil { 762 fmt.Printf("Error adding table: %v\n", err) 763 return nil, err 764 } 765 766 return ch, nil 767 }) 768 769 err := c.WriteToFile("/tmp/3_subchapters_simple.pdf") 770 if err != nil { 771 t.Errorf("Fail: %v\n", err) 772 return 773 } 774 } 775 776 func TestSubchapters(t *testing.T) { 777 c := New() 778 779 ch1 := c.NewChapter("Introduction") 780 subchap1 := c.NewSubchapter(ch1, "The fundamentals") 781 subchap1.SetMargins(0, 0, 5, 0) 782 783 //subCh1 := NewSubchapter(ch1, "Workflow") 784 785 p := NewParagraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt " + 786 "ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " + 787 "aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore " + 788 "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " + 789 "mollit anim id est laborum.") 790 p.SetTextAlignment(TextAlignmentJustify) 791 p.SetMargins(0, 0, 5, 0) 792 for j := 0; j < 18; j++ { 793 subchap1.Add(p) 794 } 795 796 subchap2 := c.NewSubchapter(ch1, "Mechanism") 797 subchap2.SetMargins(0, 0, 5, 0) 798 for j := 0; j < 15; j++ { 799 subchap2.Add(p) 800 } 801 802 subchap3 := c.NewSubchapter(ch1, "Discussion") 803 subchap3.SetMargins(0, 0, 5, 0) 804 for j := 0; j < 19; j++ { 805 subchap3.Add(p) 806 } 807 808 subchap4 := c.NewSubchapter(ch1, "Conclusion") 809 subchap4.SetMargins(0, 0, 5, 0) 810 for j := 0; j < 23; j++ { 811 subchap4.Add(p) 812 } 813 814 c.Draw(ch1) 815 816 for i := 0; i < 50; i++ { 817 ch2 := c.NewChapter("References") 818 for j := 0; j < 13; j++ { 819 ch2.Add(p) 820 } 821 822 c.Draw(ch2) 823 } 824 825 // Set a function to create the front Page. 826 c.CreateFrontPage(func(args FrontpageFunctionArgs) { 827 p := NewParagraph("Example Report") 828 p.SetWidth(c.Width()) 829 p.SetTextAlignment(TextAlignmentCenter) 830 p.SetFontSize(32) 831 p.SetPos(0, 300) 832 c.Draw(p) 833 834 p.SetFontSize(22) 835 p.SetText("Example Report Data Results") 836 p.SetPos(0, 340) 837 c.Draw(p) 838 }) 839 840 // Set a function to create the table of contents. 841 c.CreateTableOfContents(func(toc *TableOfContents) (*Chapter, error) { 842 ch := c.NewChapter("Table of contents") 843 ch.GetHeading().SetColor(ColorRGBFromArithmetic(0.5, 0.5, 0.5)) 844 ch.GetHeading().SetFontSize(28) 845 ch.GetHeading().SetMargins(0, 0, 0, 30) 846 847 table := NewTable(2) 848 // Default, equal column sizes (4x0.25)... 849 table.SetColumnWidths(0.9, 0.1) 850 851 for _, entry := range toc.entries { 852 // Col 1. Chapter number, title. 853 var str string 854 if entry.Subchapter == 0 { 855 str = fmt.Sprintf("%d. %s", entry.Chapter, entry.Title) 856 } else { 857 str = fmt.Sprintf(" %d.%d. %s", entry.Chapter, entry.Subchapter, entry.Title) 858 } 859 p := NewParagraph(str) 860 p.SetFontSize(14) 861 cell := table.NewCell() 862 cell.SetContent(p) 863 // Set the paragraph width to the cell width. 864 p.SetWidth(cell.Width(c.Context())) 865 table.SetRowHeight(table.CurRow(), p.Height()*1.2) 866 867 // Col 1. Page number. 868 p = NewParagraph(fmt.Sprintf("%d", entry.PageNumber)) 869 p.SetFontSize(14) 870 cell = table.NewCell() 871 cell.SetContent(p) 872 } 873 err := ch.Add(table) 874 if err != nil { 875 fmt.Printf("Error adding table: %v\n", err) 876 return nil, err 877 } 878 879 return ch, nil 880 }) 881 882 addHeadersAndFooters(c) 883 884 err := c.WriteToFile("/tmp/3_subchapters.pdf") 885 if err != nil { 886 t.Errorf("Fail: %v\n", err) 887 return 888 } 889 } 890 891 // Test creating and drawing a table. 892 func TestTable(t *testing.T) { 893 table := NewTable(4) // Mx4 table 894 // Default, equal column sizes (4x0.25)... 895 table.SetColumnWidths(0.5, 0.2, 0.2, 0.1) 896 897 cell := table.NewCell() 898 p := NewParagraph("1,1") 899 cell.SetContent(p) 900 901 cell = table.NewCell() 902 p = NewParagraph("1,2") 903 cell.SetContent(p) 904 905 cell = table.NewCell() 906 p = NewParagraph("1,3") 907 cell.SetContent(p) 908 909 cell = table.NewCell() 910 p = NewParagraph("1,4") 911 cell.SetContent(p) 912 913 cell = table.NewCell() 914 p = NewParagraph("2,1") 915 cell.SetContent(p) 916 917 cell = table.NewCell() 918 p = NewParagraph("2,2") 919 cell.SetContent(p) 920 921 table.SkipCells(1) // Skip over 2,3. 922 923 cell = table.NewCell() 924 p = NewParagraph("2,4") 925 cell.SetContent(p) 926 927 // Skip over two rows. 928 table.SkipRows(2) 929 cell = table.NewCell() 930 p = NewParagraph("4,4") 931 cell.SetContent(p) 932 933 // Move down 3 rows, 2 to the left. 934 table.SkipOver(3, -2) 935 cell = table.NewCell() 936 p = NewParagraph("7,2") 937 cell.SetContent(p) 938 cell.SetBackgroundColor(ColorRGBFrom8bit(255, 0, 0)) 939 940 c := New() 941 c.Draw(table) 942 943 err := c.WriteToFile("/tmp/4_table.pdf") 944 if err != nil { 945 t.Errorf("Fail: %v\n", err) 946 return 947 } 948 } 949 950 func TestTableCellWrapping(t *testing.T) { 951 c := New() 952 c.NewPage() 953 954 table := NewTable(4) // Mx4 table 955 // Default, equal column sizes (4x0.25)... 956 table.SetColumnWidths(0.5, 0.2, 0.2, 0.1) 957 958 cell := table.NewCell() 959 p := NewParagraph("A Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.") 960 cell.SetContent(p) 961 cell.SetBorder(CellBorderStyleBox, 1) 962 p.SetEnableWrap(true) 963 p.SetWidth(cell.Width(c.Context())) 964 p.SetTextAlignment(TextAlignmentJustify) 965 966 cell = table.NewCell() 967 cell.SetBorder(CellBorderStyleBox, 1) 968 p = NewParagraph("B Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.") 969 p.SetEnableWrap(true) 970 p.SetTextAlignment(TextAlignmentRight) 971 cell.SetContent(p) 972 973 cell = table.NewCell() 974 p = NewParagraph("C Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.") 975 p.SetEnableWrap(true) 976 cell.SetContent(p) 977 cell.SetBorder(CellBorderStyleBox, 1) 978 979 cell = table.NewCell() 980 p = NewParagraph("1,4") 981 cell.SetContent(p) 982 cell.SetBorder(CellBorderStyleBox, 1) 983 984 cell = table.NewCell() 985 p = NewParagraph("2,1") 986 cell.SetContent(p) 987 cell.SetBorder(CellBorderStyleBox, 1) 988 989 cell = table.NewCell() 990 p = NewParagraph("2,2") 991 cell.SetContent(p) 992 cell.SetBorder(CellBorderStyleBox, 1) 993 994 cell = table.NewCell() 995 p = NewParagraph("2,2") 996 cell.SetContent(p) 997 cell.SetBorder(CellBorderStyleBox, 1) 998 999 //table.SkipCells(1) // Skip over 2,3. 1000 1001 cell = table.NewCell() 1002 cell.SetBorder(CellBorderStyleBox, 1) 1003 //p = NewParagraph("D Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.") 1004 p = NewParagraph("X") 1005 p.SetEnableWrap(true) 1006 cell.SetContent(p) 1007 1008 // Skip over two rows. 1009 table.SkipRows(2) 1010 cell = table.NewCell() 1011 cell.SetBorder(CellBorderStyleBox, 1) 1012 p = NewParagraph("4,4") 1013 cell.SetContent(p) 1014 1015 // Move down 3 rows, 2 to the left. 1016 table.SkipOver(3, -2) 1017 cell = table.NewCell() 1018 p = NewParagraph("7,2") 1019 cell.SetContent(p) 1020 cell.SetBackgroundColor(ColorRGBFrom8bit(255, 0, 0)) 1021 1022 table.SkipRows(1) 1023 cell = table.NewCell() 1024 cell.SetBorder(CellBorderStyleBox, 1) 1025 p = NewParagraph("This is\nnewline\nwrapped\n\nmulti") 1026 p.SetEnableWrap(true) 1027 cell.SetContent(p) 1028 1029 err := c.Draw(table) 1030 if err != nil { 1031 t.Fatalf("Error drawing: %v", err) 1032 } 1033 1034 err = c.WriteToFile("/tmp/tablecell_wrap.pdf") 1035 if err != nil { 1036 t.Fatalf("Fail: %v\n", err) 1037 } 1038 } 1039 1040 // Test creating and drawing a table. 1041 func TestBorderedTable(t *testing.T) { 1042 table := NewTable(4) // Mx4 table 1043 // Default, equal column sizes (4x0.25)... 1044 table.SetColumnWidths(0.5, 0.2, 0.2, 0.1) 1045 1046 cell := table.NewCell() 1047 p := NewParagraph("1,1") 1048 cell.SetContent(p) 1049 cell.SetBorder(CellBorderStyleBox, 1) 1050 1051 cell = table.NewCell() 1052 p = NewParagraph("1,2") 1053 cell.SetContent(p) 1054 cell.SetBorder(CellBorderStyleBox, 1) 1055 1056 cell = table.NewCell() 1057 p = NewParagraph("1,3") 1058 cell.SetContent(p) 1059 cell.SetBorder(CellBorderStyleBox, 1) 1060 1061 cell = table.NewCell() 1062 p = NewParagraph("1,4") 1063 cell.SetContent(p) 1064 cell.SetBorder(CellBorderStyleBox, 1) 1065 1066 cell = table.NewCell() 1067 p = NewParagraph("2,1") 1068 cell.SetContent(p) 1069 cell.SetBorder(CellBorderStyleBox, 1) 1070 1071 cell = table.NewCell() 1072 p = NewParagraph("2,2") 1073 cell.SetContent(p) 1074 cell.SetBorder(CellBorderStyleBox, 1) 1075 1076 table.SkipCells(1) // Skip over 2,3. 1077 1078 cell = table.NewCell() 1079 p = NewParagraph("2,4") 1080 cell.SetContent(p) 1081 cell.SetBorder(CellBorderStyleBox, 1) 1082 1083 // Skip over two rows. 1084 table.SkipRows(2) 1085 cell = table.NewCell() 1086 p = NewParagraph("4,4") 1087 cell.SetContent(p) 1088 cell.SetBorder(CellBorderStyleBox, 1) 1089 1090 // Move down 3 rows, 2 to the left. 1091 table.SkipOver(3, -2) 1092 cell = table.NewCell() 1093 p = NewParagraph("7,2") 1094 cell.SetContent(p) 1095 cell.SetBackgroundColor(ColorRGBFrom8bit(255, 0, 0)) 1096 cell.SetBorder(CellBorderStyleBox, 1) 1097 1098 c := New() 1099 c.Draw(table) 1100 1101 err := c.WriteToFile("/tmp/4_table_bordered.pdf") 1102 if err != nil { 1103 t.Errorf("Fail: %v\n", err) 1104 return 1105 } 1106 } 1107 1108 func TestTableInSubchapter(t *testing.T) { 1109 c := New() 1110 1111 fontRegular := fonts.NewFontHelvetica() 1112 fontBold := fonts.NewFontHelveticaBold() 1113 1114 ch := c.NewChapter("Document control") 1115 ch.SetMargins(0, 0, 40, 0) 1116 ch.GetHeading().SetFont(fontRegular) 1117 ch.GetHeading().SetFontSize(18) 1118 ch.GetHeading().SetColor(ColorRGBFrom8bit(72, 86, 95)) 1119 1120 sc := c.NewSubchapter(ch, "Issuer details") 1121 sc.SetMargins(0, 0, 5, 0) 1122 sc.GetHeading().SetFont(fontRegular) 1123 sc.GetHeading().SetFontSize(18) 1124 sc.GetHeading().SetColor(ColorRGBFrom8bit(72, 86, 95)) 1125 1126 issuerTable := NewTable(2) 1127 1128 p := NewParagraph("Non-Disclosure") 1129 p.SetFont(fontBold) 1130 p.SetFontSize(10) 1131 p.SetColor(ColorWhite) 1132 cell := issuerTable.NewCell() 1133 cell.SetContent(p) 1134 cell.SetBackgroundColor(ColorBlack) 1135 cell.SetBorder(CellBorderStyleBox, 1.0) 1136 cell.SetIndent(5) 1137 1138 p = NewParagraph("Company Inc.") 1139 p.SetFont(fontRegular) 1140 p.SetFontSize(10) 1141 p.SetColor(ColorGreen) 1142 cell = issuerTable.NewCell() 1143 cell.SetContent(p) 1144 cell.SetBackgroundColor(ColorRed) 1145 cell.SetBorder(CellBorderStyleBox, 1.0) 1146 cell.SetIndent(5) 1147 1148 p = NewParagraph("Belongs to") 1149 p.SetFont(fontBold) 1150 p.SetFontSize(10) 1151 p.SetColor(ColorWhite) 1152 cell = issuerTable.NewCell() 1153 cell.SetContent(p) 1154 cell.SetBackgroundColor(ColorBlack) 1155 cell.SetBorder(CellBorderStyleBox, 1.0) 1156 cell.SetIndent(5) 1157 1158 p = NewParagraph("Bezt business bureu") 1159 p.SetFont(fontRegular) 1160 p.SetFontSize(10) 1161 p.SetColor(ColorGreen) 1162 cell = issuerTable.NewCell() 1163 cell.SetContent(p) 1164 cell.SetBackgroundColor(ColorRed) 1165 cell.SetBorder(CellBorderStyleBox, 1.0) 1166 cell.SetIndent(5) 1167 cell.SetHorizontalAlignment(CellHorizontalAlignmentCenter) 1168 //cell.SetVerticalAlignment(CellVerticalAlignmentMiddle) 1169 1170 issuerTable.SetMargins(5, 5, 10, 10) 1171 1172 ch.Add(issuerTable) 1173 1174 sc = c.NewSubchapter(ch, "My Statement") 1175 //sc.SetMargins(0, 0, 5, 0) 1176 sc.GetHeading().SetFont(fontRegular) 1177 sc.GetHeading().SetFontSize(18) 1178 sc.GetHeading().SetColor(ColorRGBFrom8bit(72, 86, 95)) 1179 1180 myText := "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt " + 1181 "ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " + 1182 "aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore " + 1183 "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " + 1184 "mollit anim id est laborum." 1185 1186 myPara := NewParagraph(myText) 1187 myPara.SetFont(fontRegular) 1188 myPara.SetFontSize(10) 1189 myPara.SetColor(ColorRGBFrom8bit(72, 86, 95)) 1190 myPara.SetTextAlignment(TextAlignmentJustify) 1191 myPara.SetLineHeight(1.5) 1192 sc.Add(myPara) 1193 1194 err := c.Draw(ch) 1195 if err != nil { 1196 t.Errorf("Fail: %v\n", err) 1197 return 1198 } 1199 1200 err = c.WriteToFile("/tmp/4_tables_in_subchap.pdf") 1201 if err != nil { 1202 t.Errorf("Fail: %v\n", err) 1203 return 1204 } 1205 } 1206 1207 // Add headers and footers via creator. 1208 func addHeadersAndFooters(c *Creator) { 1209 c.DrawHeader(func(header *Block, args HeaderFunctionArgs) { 1210 /* 1211 if pageNum == 1 { 1212 // Skip on front Page. 1213 return 1214 } 1215 */ 1216 1217 // Add Page number 1218 p := NewParagraph(fmt.Sprintf("Page %d / %d", args.PageNum, args.TotalPages)) 1219 p.SetPos(0.8*header.Width(), 20) 1220 header.Draw(p) 1221 1222 // Draw on the template... 1223 img, err := NewImageFromFile(testImageFile1) 1224 if err != nil { 1225 fmt.Printf("ERROR : %v\n", err) 1226 } 1227 img.ScaleToHeight(0.4 * c.pageMargins.top) 1228 img.SetPos(20, 10) 1229 1230 header.Draw(img) 1231 }) 1232 1233 c.DrawFooter(func(footer *Block, args FooterFunctionArgs) { 1234 /* 1235 if pageNum == 1 { 1236 // Skip on front Page. 1237 return 1238 } 1239 */ 1240 1241 // Add company name. 1242 companyName := "Company inc." 1243 p := NewParagraph(companyName) 1244 p.SetPos(0.1*footer.Width(), 10) 1245 footer.Draw(p) 1246 1247 p = NewParagraph("July 2017") 1248 p.SetPos(0.8*footer.Width(), 10) 1249 footer.Draw(p) 1250 }) 1251 } 1252 1253 // Test creating headers and footers. 1254 func TestHeadersAndFooters(t *testing.T) { 1255 c := New() 1256 1257 ch1 := c.NewChapter("Introduction") 1258 1259 p := NewParagraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt " + 1260 "ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " + 1261 "aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore " + 1262 "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " + 1263 "mollit anim id est laborum.") 1264 p.SetMargins(0, 0, 10, 0) 1265 1266 for j := 0; j < 55; j++ { 1267 ch1.Add(p) // Can add any drawable.. 1268 } 1269 1270 c.Draw(ch1) 1271 1272 // Make unidoc headers and footers. 1273 addHeadersAndFooters(c) 1274 1275 err := c.WriteToFile("/tmp/4_headers.pdf") 1276 if err != nil { 1277 t.Errorf("Fail: %v\n", err) 1278 return 1279 } 1280 } 1281 1282 func makeQrCodeImage(text string, width float64, oversampling int) (goimage.Image, error) { 1283 qrCode, err := qr.Encode(text, qr.M, qr.Auto) 1284 if err != nil { 1285 return nil, err 1286 } 1287 1288 pixelWidth := oversampling * int(math.Ceil(width)) 1289 qrCode, err = barcode.Scale(qrCode, pixelWidth, pixelWidth) 1290 if err != nil { 1291 return nil, err 1292 } 1293 1294 return qrCode, nil 1295 } 1296 1297 func TestQRCodeOnNewPage(t *testing.T) { 1298 creator := New() 1299 1300 qrCode, err := makeQrCodeImage("HELLO", 40, 5) 1301 if err != nil { 1302 t.Errorf("Fail: %v\n", err) 1303 return 1304 } 1305 1306 img, err := NewImageFromGoImage(qrCode) 1307 if err != nil { 1308 t.Errorf("Fail: %v\n", err) 1309 return 1310 } 1311 // Sets positioning to absolute coordinates. 1312 img.SetWidth(40) 1313 img.SetHeight(40) 1314 1315 for i := 0; i < 5; i++ { 1316 img.SetPos(100.0*float64(i), 100.0*float64(i)) 1317 creator.Draw(img) 1318 } 1319 1320 creator.WriteToFile("/tmp/3_barcode_qr_newpage.pdf") 1321 } 1322 1323 // Example of using a template Page, generating and applying QR 1324 func TestQRCodeOnTemplate(t *testing.T) { 1325 pages, err := loadPagesFromFile(testPdfTemplatesFile1) 1326 if err != nil { 1327 t.Errorf("Fail: %v\n", err) 1328 return 1329 } 1330 if len(pages) < 2 { 1331 t.Errorf("Fail: %v\n", err) 1332 return 1333 } 1334 1335 // Load Page 1 as template. 1336 tpl, err := NewBlockFromPage(pages[1]) 1337 if err != nil { 1338 t.Errorf("Fail: %v\n", err) 1339 return 1340 } 1341 tpl.SetPos(0, 0) 1342 1343 // Generate QR code. 1344 qrCode, err := makeQrCodeImage("HELLO", 50, 5) 1345 if err != nil { 1346 t.Errorf("Fail: %v\n", err) 1347 return 1348 } 1349 1350 // Prepare content image. 1351 image, err := NewImageFromGoImage(qrCode) 1352 if err != nil { 1353 t.Errorf("Fail: %v\n", err) 1354 return 1355 } 1356 image.SetWidth(50) 1357 image.SetHeight(50) 1358 image.SetPos(480, 100) 1359 1360 tpl.Draw(image) 1361 1362 creator := New() 1363 creator.NewPage() 1364 creator.Draw(tpl) 1365 1366 // Add another Page where the template has been rotated. 1367 creator.NewPage() 1368 tpl.SetAngle(90) 1369 tpl.SetPos(-50, 750) 1370 1371 creator.Draw(tpl) 1372 1373 // Add another Page where the template is rotated 90 degrees. 1374 loremPages, err := loadPagesFromFile(testPdfLoremIpsumFile) 1375 if err != nil { 1376 t.Errorf("Fail: %v\n", err) 1377 return 1378 } 1379 if len(loremPages) != 1 { 1380 t.Errorf("Pages != 1") 1381 return 1382 } 1383 1384 // Add another Page where another Page is embedded on the Page. The other Page is scaled and shifted to fit 1385 // on the right of the template. 1386 loremTpl, err := NewBlockFromPage(loremPages[0]) 1387 if err != nil { 1388 t.Errorf("Fail: %v\n", err) 1389 return 1390 } 1391 loremTpl.ScaleToWidth(0.8 * creator.Width()) 1392 loremTpl.SetPos(100, 100) 1393 1394 creator.Draw(loremTpl) 1395 1396 // Write the example to file. 1397 creator.WriteToFile("/tmp/4_barcode_on_tpl.pdf") 1398 } 1399 1400 // Test adding encryption to output. 1401 func TestEncrypting1(t *testing.T) { 1402 c := New() 1403 1404 ch1 := c.NewChapter("Introduction") 1405 1406 p := NewParagraph("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt " + 1407 "ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut " + 1408 "aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore " + 1409 "eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt " + 1410 "mollit anim id est laborum.") 1411 p.SetMargins(0, 0, 10, 0) 1412 1413 for j := 0; j < 55; j++ { 1414 ch1.Add(p) // Can add any drawable.. 1415 } 1416 1417 c.Draw(ch1) 1418 1419 c.SetPdfWriterAccessFunc(func(w *model.PdfWriter) error { 1420 userPass := []byte("password") 1421 ownerPass := []byte("password") 1422 err := w.Encrypt(userPass, ownerPass, nil) 1423 return err 1424 }) 1425 1426 err := c.WriteToFile("/tmp/6_chapters_encrypted_password.pdf") 1427 if err != nil { 1428 t.Errorf("Fail: %v\n", err) 1429 return 1430 } 1431 }