github.com/pdfcpu/pdfcpu@v0.11.1/pkg/api/test/stamp_test.go (about) 1 /* 2 Copyright 2020 The pdfcpu Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package test 18 19 import ( 20 "fmt" 21 "path/filepath" 22 "testing" 23 24 "github.com/pdfcpu/pdfcpu/pkg/api" 25 "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" 26 "github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types" 27 ) 28 29 func testAddWatermarks(t *testing.T, msg, inFile, outFile string, selectedPages []string, mode, modeParam, desc string, onTop bool) { 30 t.Helper() 31 inFile = filepath.Join(inDir, inFile) 32 s := "watermark" 33 if onTop { 34 s = "stamp" 35 } 36 outFile = filepath.Join(samplesDir, s, mode, outFile) 37 38 var err error 39 switch mode { 40 case "text": 41 err = api.AddTextWatermarksFile(inFile, outFile, selectedPages, onTop, modeParam, desc, nil) 42 case "image": 43 err = api.AddImageWatermarksFile(inFile, outFile, selectedPages, onTop, modeParam, desc, nil) 44 case "pdf": 45 err = api.AddPDFWatermarksFile(inFile, outFile, selectedPages, onTop, modeParam, desc, nil) 46 } 47 if err != nil { 48 t.Fatalf("%s %s: %v\n", msg, outFile, err) 49 } 50 if err := api.ValidateFile(outFile, nil); err != nil { 51 t.Fatalf("%s: %v\n", msg, err) 52 } 53 } 54 55 func TestAddWatermarks(t *testing.T) { 56 for _, tt := range []struct { 57 msg string 58 inFile, outFile string 59 selectedPages []string 60 mode string 61 modeParm string 62 wmConf string 63 }{ 64 65 // Avoid font embedding for CJK fonts like so: 66 67 // Any font name ending with GB2312 will be recognized as using HANS: 68 69 // {"TestWatermarkText", 70 // "sample.pdf", 71 // "chinese.pdf", 72 // []string{"1-"}, 73 // "text", 74 // "测试中文字体水印增加的文件大小\n2023-10-16", 75 // "font: KaiTi_GB2312, points: 36, scale: 1 abs, color: #ff0000, op: 0.3, ro: 30"}, 76 77 // Configure script manually: 78 79 // {"TestWatermarkText", 80 // "sample.pdf", 81 // "chinese1.pdf", 82 // []string{"1-"}, 83 // "text", 84 // "测试中文字体水印增加的文件大小\n2023-10-16", 85 // "font: KaiTi_GB2312, script: hans, points: 36, scale: 1 abs, color: #ff0000, op: 0.3, ro: 30"}, 86 87 {"TestWatermarkText", 88 "Walden.pdf", 89 "TextDefaults.pdf", 90 []string{"1-"}, 91 "text", 92 "A simple text watermark using defaults:\n" + 93 "\"font:Helvetica, points:24, aligntext:center,\n" + 94 "position:c, offset:0 0, scale:0.5 rel, diagonal:1,\n" + 95 "opacity:1, rendermode:0, fillcolor: 0.5 0.5 0.5,\n" + 96 "strokecol: 0.5 0.5 0.5\"", 97 ""}, 98 99 {"TestWatermarkText", 100 "Walden.pdf", 101 "TextDefaultsAbbr.pdf", 102 []string{"1-"}, 103 "text", 104 `A simple text watermark using defaults: 105 Unique abbreviations also work: 106 "fo:Helvetica, poi:24, align:c, 107 pos:c, off:0 0, scale:0.5 rel, d:1, 108 op:1, mode:0, fillc: 0.5 0.5 0.5, 109 strokec: #808080"`, 110 ""}, 111 112 {"TestWatermarkText", 113 "Walden.pdf", 114 "TextAlongLeftBorder.pdf", 115 []string{"1-"}, 116 "text", 117 "Welcome to pdfcpu", 118 "pos:l, off:0 0, rot:-90"}, 119 120 {"TestWatermarkText", 121 "Walden.pdf", 122 "TextPagenumbers.pdf", 123 []string{"1-"}, 124 "text", 125 "Page %p of %P", 126 "scale:1 abs, pos:bc, rot:0"}, 127 128 {"TestWatermarkText", 129 "Walden.pdf", 130 "TextRenderMode0.pdf", 131 []string{"1-"}, 132 "text", 133 "Rendermode 0 fills text using fill color.\n" + 134 "\"rendermode\" or \"mode\" works - also abbreviated: \n" + 135 "\"mode:0, fillc:#3277d3, rot:0, scale:.8\"", 136 "mode:0, fillc:#3277d3, rot:0, scale:.8"}, 137 138 {"TestWatermarkText", 139 "Walden.pdf", 140 "TextRenderMode1.pdf", 141 []string{"1-"}, 142 "text", 143 "Rendermode 1 strokes text using stroke color.\n" + 144 "\"rendermode\" or \"mode\" works - also abbreviated: \n" + 145 "\"mo:1, strokec:#335522, rot:0, scale:.8\"", 146 "mo:1, strokec:#335522, rot:0, scale:.8"}, 147 148 {"TestWatermarkText", 149 "Walden.pdf", 150 "TextRenderMode2.pdf", 151 []string{"1-"}, 152 "text", 153 "Rendermode 2 strokes text using stroke color\n" + 154 "and fills text using fill color\n" + 155 "\"rendermode\" or \"mode\" works - also abbreviated: \n" + 156 "\"re:2, fillc:#3277d3, strokec:#335522, rot:0, scale:.8\"", 157 "re:2, fillc:#3277d3, strokec:#335522, rot:0, scale:.8"}, 158 159 {"TestWatermarkText", 160 "Walden.pdf", 161 "TextAlignLeft.pdf", 162 []string{"1-"}, 163 "text", 164 "Here we have\n" + 165 "some left aligned text lines\n" + 166 "\"align:l, fillc:#3277d3, rot:0\"", 167 "align:l, fillc:#3277d3, rot:0"}, 168 169 {"TestWatermarkText", 170 "Walden.pdf", 171 "TextAlignRight.pdf", 172 []string{"1-"}, 173 "text", 174 "Here we have\n" + 175 "some right aligned text lines\n" + 176 "with background color\n" + 177 "\"align:l, fillc:#3277d3, bgcol:#f7e6c7, rot:0\"", 178 "align:r, fillc:#3277d3, bgcol:#f7e6c7, rot:0"}, 179 180 {"TestWatermarkText", 181 "Walden.pdf", 182 "TextAlignCenter.pdf", 183 []string{"1-"}, 184 "text", 185 "Here we have\n" + 186 "some centered text lines\n" + 187 "with background color\n" + 188 "\"fillc:#3277d3, bgcol:#beded9, rot:0\"", 189 "fillc:#3277d3, bgcol:#beded9, rot:0"}, 190 191 {"TestWatermarkText", 192 "Walden.pdf", 193 "TextAlignJustify.pdf", 194 []string{"1-"}, 195 "text", 196 "Here we have\n" + 197 "some justified text lines\n" + 198 "with background color\n" + 199 "\"al:j, fillc:#3277d3, bgcol:#000000, rot:0\"", 200 "al:j, fillc:#3277d3, bgcol:#000000, rot:0"}, 201 202 {"TestWatermarkText", 203 "Walden.pdf", 204 "TextScaleRel25.pdf", 205 []string{"1-"}, 206 "text", 207 "Relative scale factor: .25\n" + 208 "scales relative to page dimensions.\n" + 209 "\"scale:.25 rel, fillc:#3277d3, rot:0\"", 210 "scale:.25 rel, fillc:#3277d3, rot:0"}, 211 212 {"TestWatermarkText", 213 "Walden.pdf", 214 "TextScaleRel50.pdf", 215 []string{"1-"}, 216 "text", 217 "Relative scale factor: .5\n" + 218 "scales relative to page dimensions.\n" + 219 "\"scale:.5, fillc:#3277d3, rot:0\"", 220 "scale:.5, fillc:#3277d3, rot:0"}, 221 222 {"TestWatermarkText", 223 "Walden.pdf", 224 "TextScaleRel100.pdf", 225 []string{"1-"}, 226 "text", 227 "Relative scale factor: 1\n" + 228 "scales relative to page dimensions.\n" + 229 "\"scale:1, fillc:#3277d3, rot:0\"", 230 "scale:1, fillc:#3277d3, rot:0"}, 231 232 {"TestWatermarkText", 233 "Walden.pdf", 234 "TextScaleAbs50.pdf", 235 []string{"1-"}, 236 "text", 237 "Absolute scale factor: .5\n" + 238 "scales fontsize\n" + 239 "(here using the 24 points default)\n" + 240 "\"scale:.5 abs, font:Courier, rot:0\"", 241 "scale:.5 abs, font:Courier, rot:0"}, 242 243 {"TestWatermarkText", 244 "Walden.pdf", 245 "TextScaleAbs100.pdf", 246 []string{"1-"}, 247 "text", 248 "Absolute scale factor: 1\n" + 249 "scales fontsize\n" + 250 "(here using the 24 points default)\n" + 251 "\"scale:1 abs, font:Courier, rot:0\"", 252 "scale:1 abs, font:Courier, rot:0"}, 253 254 {"TestWatermarkText", 255 "Walden.pdf", 256 "TextScaleAbs150.pdf", 257 []string{"1-"}, 258 "text", 259 "Absolute scale factor: 1.5\n" + 260 "scales fontsize\n" + 261 "(here using the 24 points default)\n" + 262 "\"scale:1.5 abs, font:Courier, rot:0\"", 263 "scale:1.5 abs, font:Courier, rot:0"}, 264 265 {"TestWatermarkText", 266 "Walden.pdf", 267 "TextPosBotLeft.pdf", 268 []string{"1-"}, 269 "text", 270 "Positioning using anchors:\n" + 271 "bottom left corner with left alignment\n" + 272 "\"pos:bl, bgcol:#f7e6c7, rot:0\"", 273 "pos:bl, bgcol:#f7e6c7, rot:0"}, 274 275 {"TestWatermarkText", 276 "Walden.pdf", 277 "TextPosBotRightWithOffset.pdf", 278 []string{"1-"}, 279 "text", 280 "Positioning using anchors and offset:\n" + 281 "bottom right corner with right alignment\n" + 282 "\"pos:br, off: -10 10, align:r, bgcol:#f7e6c7, rot:0\"", 283 "pos:br, off: -10 10, align:r, bgcol:#f7e6c7, rot:0"}, 284 285 {"TestWatermarkText", 286 "Walden.pdf", 287 "TextOffAndRot.pdf", 288 []string{"1-"}, 289 "text", 290 "Confidential\n\"scale:1 abs, points:20, pos:c, off:0 50, fillc:#000000, rot:20\"", 291 "scale:1 abs, points:20, pos:c, off:0 50, fillc:#000000, rot:20"}, 292 293 {"TestWatermarkText", 294 "Walden.pdf", 295 "TextMargins1Value.pdf", 296 []string{"1-"}, 297 "text", 298 "Set all margins:\n" + 299 "(needs \"bgcol\")\n" + 300 "\"margins: 10, fillc:#3277d3, bgcol:#beded9, rot:0\"", 301 "margins: 10,fillc:#3277d3, bgcol:#beded9, rot:0"}, 302 303 {"TestWatermarkText", 304 "Walden.pdf", 305 "TextMargins2Values.pdf", 306 []string{"1-"}, 307 "text", 308 "Set top/bottom and left/right margins:\n" + 309 "(needs \"bgcol\")\n" + 310 "\"ma: 5 10, fillc:#3277d3, bgcol:#beded9, rot:0\"", 311 "ma: 5 10, fillc:#3277d3, bgcol:#beded9, rot:0"}, 312 313 {"TestWatermarkText", 314 "Walden.pdf", 315 "TextMargins3Values.pdf", 316 []string{"1-"}, 317 "text", 318 "Set top, left/right and bottom margins:\n" + 319 "(needs \"bgcol\")\n" + 320 "\"ma: 5 10 15, fillc:#3277d3, bgcol:#beded9, rot:0\"", 321 "ma: 5 10 15, fillc:#3277d3, bgcol:#beded9, rot:0"}, 322 323 {"TestWatermarkText", 324 "Walden.pdf", 325 "TextMargins4Values.pdf", 326 []string{"1-"}, 327 "text", 328 "Set all margins individually:\n" + 329 "(needs \"bgcol\")\n" + 330 "\"ma: 5 10 15 20, fillc:#3277d3, bgcol:#beded9, rot:0\"", 331 "ma: 5 10 15 20, fillc:#3277d3, bgcol:#beded9, rot:0"}, 332 333 {"TestWatermarkText", 334 "Walden.pdf", 335 "TextRoundCornersAndBorder5.pdf", 336 []string{"1-"}, 337 "text", 338 "Set round corners and border:\n" + 339 "(needs \"bgcol\" and a border)\n" + 340 "round corner effect depends on border width\n" + 341 "\"border: 5 round, fillc:#3277d3, bgcol:#beded9, rot:0\"", 342 "border: 5 round, fillc:#3277d3, bgcol:#beded9, rot:0"}, 343 344 {"TestWatermarkText", 345 "Walden.pdf", 346 "TextRoundCornersAndBorder10.pdf", 347 []string{"1-"}, 348 "text", 349 "Set round corners and border:\n" + 350 "(needs \"bgcol\" and a border)\n" + 351 "round corner effect depends on border width\n" + 352 "\"border: 10 round, fillc:#3277d3, bgcol:#beded9, rot:0\"", 353 "border: 10 round, fillc:#3277d3, bgcol:#beded9, rot:0"}, 354 355 {"TestWatermarkText", 356 "Walden.pdf", 357 "TextRoundCornersAndColoredBorder.pdf", 358 []string{"1-"}, 359 "text", 360 "Set round corners and colored border:\n" + 361 "(needs \"bgcol\")\n" + 362 "round corner effect depends on border width\n" + 363 "\"border: 10 round #f7e6c7, fillc:#3277d3, bgcol:#beded9, rot:0\"", 364 "border: 10 round #f7e6c7, fillc:#3277d3, bgcol:#beded9, rot:0"}, 365 366 {"TestWatermarkText", 367 "Walden.pdf", 368 "TextMarginsAndColoredBorder.pdf", 369 []string{"1-"}, 370 "text", 371 "Set margins and colored border:\n" + 372 "(needs \"bgcol\")\n" + 373 "\"ma: 10, bo: 5 .3 .7 .7, fillc:#3277d3, bgcol:#beded9, rot:0\"", 374 "ma: 10, bo: 5 .3 .7 .7, fillc:#3277d3, bgcol:#beded9, rot:0"}, 375 376 {"TestWatermarkText", 377 "Walden.pdf", 378 "TextMarginsRoundCornersAndColoredBorder.pdf", 379 []string{"1-"}, 380 "text", 381 "Set margins and round colored border:\n" + 382 "(needs \"bgcol\")\n" + 383 "round corner effect depends on border width\n" + 384 "\"ma: 5, bo: 7 round .3 .7 .7, fillc:#3277d3, bgcol:#beded9, rot:0\"", 385 "ma: 5, bo: 7 round .3 .7 .7, fillc:#3277d3, bgcol:#beded9, rot:0"}, 386 387 // Add image watermark to inFile starting at page 1 using no rotation. 388 {"TestWatermarkImage", 389 "Walden.pdf", 390 "ImageRotate90.pdf", 391 []string{"1-"}, 392 "image", 393 filepath.Join(resDir, "logoSmall.png"), 394 "scale:.25, rot:90"}, 395 396 // Add image watermark to inFile for all pages using defaults.. 397 {"TestWatermarkImage2", 398 "Walden.pdf", 399 "ImagePosBottomLeftWithOffset.pdf", 400 nil, 401 "image", 402 filepath.Join(resDir, "logoSmall.png"), 403 "scale:.1, pos:bl, off:15 20, rot:0"}, 404 405 // Add image stamp to inFile using absolute scaling and a rotation of 45 degrees. 406 {"TestStampImageAbsScaling", 407 "Walden.pdf", 408 "ImageAbsScaling.pdf", 409 []string{"1-"}, 410 "image", 411 filepath.Join(resDir, "logoSmall.png"), 412 "scale:.33 abs, rot:45"}, 413 414 // Add a PDF stamp to all pages of inFile using the 1st page of pdfFile 415 // and rotate along the 2nd diagonal running from upper left to lower right corner. 416 {"TestWatermarkPDF", 417 "Walden.pdf", 418 "PdfSingleStampDefault.pdf", 419 nil, 420 "pdf", 421 filepath.Join(inDir, "Walden.pdf:1"), 422 "d:2"}, 423 424 // Add a PDF multistamp in the top right corner to all pages of inFile. 425 {"TestWatermarkPDF", 426 "Walden.pdf", 427 "PdfMultistampDefault.pdf", 428 nil, 429 "pdf", 430 filepath.Join(inDir, "Walden.pdf"), 431 "scale:.2, pos:tr, off:-10 -10, rot:0"}, 432 433 // Add a PDF multistamp to all pages of inFile. 434 // Start by stamping page 3 with page 1. 435 // You may filter stamping by defining selected Pages. 436 {"TestWatermarkPDF", 437 "zineTest.pdf", 438 "PdfMultistamp13.pdf", 439 nil, 440 "pdf", 441 filepath.Join(inDir, "zineTest.pdf:1:3"), 442 "scale:.2, pos:tr, off:-10 -10, rot:0"}, 443 444 // Add a PDF multistamp to all pages of inFile. 445 // Start by stamping page 1 with page 3. 446 // You may filter stamping by defining selected Pages. 447 {"TestWatermarkPDF", 448 "zineTest.pdf", 449 "PdfMultistamp31.pdf", 450 nil, 451 "pdf", 452 filepath.Join(inDir, "zineTest.pdf:3:1"), 453 "scale:.2, pos:tr, off:-10 -10, rot:0"}, 454 455 // Add a PDF multistamp to all pages of inFile. 456 // Start by stamping page 3 with page 3. 457 // You may filter stamping by defining selected Pages. 458 {"TestWatermarkPDF", 459 "zineTest.pdf", 460 "PdfMultistamp33.pdf", 461 nil, 462 "pdf", 463 filepath.Join(inDir, "zineTest.pdf:3:3"), 464 "scale:.2, pos:tr, off:-10 -10, rot:0"}, 465 } { 466 testAddWatermarks(t, tt.msg, tt.inFile, tt.outFile, tt.selectedPages, tt.mode, tt.modeParm, tt.wmConf, false) 467 testAddWatermarks(t, tt.msg, tt.inFile, tt.outFile, tt.selectedPages, tt.mode, tt.modeParm, tt.wmConf, true) 468 } 469 } 470 471 func TestAddStampWithLink(t *testing.T) { 472 for _, tt := range []struct { 473 msg string 474 inFile, outFile string 475 selectedPages []string 476 mode string 477 modeParm string 478 wmConf string 479 }{ 480 {"TestStampTextWithLink", 481 "Walden.pdf", 482 "TextWithLink.pdf", 483 []string{"1-"}, 484 "text", 485 "A simple text watermark with link", 486 "url:pdfcpu.io"}, 487 488 {"TestStampImageWithLink", 489 "Walden.pdf", 490 "ImageWithLink.pdf", 491 []string{"1-"}, 492 "image", 493 filepath.Join(resDir, "logoSmall.png"), 494 "url:pdfcpu.io, scale:.33 abs, rot:45"}, 495 } { 496 // Links supported for stamps only (watermark onTop:true). 497 testAddWatermarks(t, tt.msg, tt.inFile, tt.outFile, tt.selectedPages, tt.mode, tt.modeParm, tt.wmConf, true) 498 } 499 500 } 501 502 func TestCropBox(t *testing.T) { 503 msg := "TestCropBox" 504 inFile := filepath.Join(inDir, "empty.pdf") 505 outFile := filepath.Join(samplesDir, "stamp", "pdf", "PdfWithCropBox.pdf") 506 pdfFile := filepath.Join(inDir, "grid_example.pdf") 507 508 // Create a context. 509 ctx, err := api.ReadContextFile(inFile) 510 if err != nil { 511 t.Fatalf("%s readContext: %v\n", msg, err) 512 } 513 514 for _, pos := range []string{"tl", "tc", "tr", "l", "c", "r", "bl", "bc", "br"} { 515 wm, err := api.PDFWatermark(pdfFile+":1", fmt.Sprintf("scale:.25 rel, pos:%s, rot:0", pos), true, false, types.POINTS) 516 if err != nil { 517 t.Fatalf("%s %s: %v\n", msg, outFile, err) 518 } 519 if err := pdfcpu.AddWatermarks(ctx, nil, wm); err != nil { 520 t.Fatalf("%s %s: %v\n", msg, outFile, err) 521 } 522 } 523 524 // Write context to file. 525 if err := api.WriteContextFile(ctx, outFile); err != nil { 526 t.Fatalf("%s write: %v\n", msg, err) 527 } 528 529 if err := api.ValidateFile(outFile, nil); err != nil { 530 t.Fatalf("%s: %v\n", msg, err) 531 } 532 } 533 534 func hasWatermarks(inFile string, t *testing.T) bool { 535 t.Helper() 536 ok, err := api.HasWatermarksFile(inFile, nil) 537 if err != nil { 538 t.Fatalf("Checking for watermarks: %s: %v\n", inFile, err) 539 } 540 return ok 541 } 542 543 func TestStampingLifecycle(t *testing.T) { 544 msg := "TestStampingLifecycle" 545 inFile := filepath.Join(inDir, "Acroforms2.pdf") 546 outFile := filepath.Join(outDir, "stampLC.pdf") 547 onTop := true // we are testing stamps 548 549 // Check for existing stamps. 550 if ok := hasWatermarks(inFile, t); ok { 551 t.Fatalf("Watermarks found: %s\n", inFile) 552 } 553 554 unit := types.POINTS 555 556 // Stamp all pages. 557 wm, err := api.TextWatermark("Demo", "", onTop, false, unit) 558 if err != nil { 559 t.Fatalf("%s %s: %v\n", msg, outFile, err) 560 } 561 if err := api.AddWatermarksFile(inFile, outFile, nil, wm, nil); err != nil { 562 t.Fatalf("%s %s: %v\n", msg, outFile, err) 563 } 564 565 // Check for existing stamps. 566 if ok := hasWatermarks(outFile, t); !ok { 567 t.Fatalf("No watermarks found: %s\n", outFile) 568 } 569 570 // // Update stamp on page 1. 571 wm, err = api.TextWatermark("Confidential", "", onTop, true, unit) 572 if err != nil { 573 t.Fatalf("%s %s: %v\n", msg, outFile, err) 574 } 575 if err := api.AddWatermarksFile(outFile, "", []string{"1"}, wm, nil); err != nil { 576 t.Fatalf("%s %s: %v\n", msg, outFile, err) 577 } 578 579 // Add another stamp on top for all pages. 580 // This is a redish transparent footer. 581 wm, err = api.TextWatermark("Footer", "pos:bc, c:0.8 0 0, op:.6, rot:0", onTop, false, unit) 582 if err != nil { 583 t.Fatalf("%s %s: %v\n", msg, outFile, err) 584 } 585 if err := api.AddWatermarksFile(outFile, "", nil, wm, nil); err != nil { 586 t.Fatalf("%s %s: %v\n", msg, outFile, err) 587 } 588 589 // Remove stamp on page 1. 590 if err := api.RemoveWatermarksFile(outFile, "", []string{"1"}, nil); err != nil { 591 t.Fatalf("%s %s: %v\n", msg, outFile, err) 592 } 593 594 // Check for existing stamps. 595 if ok := hasWatermarks(outFile, t); !ok { 596 t.Fatalf("No watermarks found: %s\n", outFile) 597 } 598 599 // Remove all stamps. 600 if err := api.RemoveWatermarksFile(outFile, "", nil, nil); err != nil { 601 t.Fatalf("%s %s: %v\n", msg, outFile, err) 602 } 603 604 // Validate the result. 605 if err := api.ValidateFile(outFile, nil); err != nil { 606 t.Fatalf("%s: %v\n", msg, err) 607 } 608 609 // Check for existing stamps. 610 if ok := hasWatermarks(outFile, t); ok { 611 t.Fatalf("Watermarks found: %s\n", outFile) 612 } 613 } 614 615 func TestRecycleWM(t *testing.T) { 616 msg := "TestRecycleWM" 617 inFile := filepath.Join(inDir, "test.pdf") 618 outFile := filepath.Join(samplesDir, "watermark", "text", "TextRecycled.pdf") 619 onTop := false // we are testing watermarks 620 621 desc := "pos:tl, points:22, rot:0, scale:1 abs, off:0 -5, opacity:0.3" 622 wm, err := api.TextWatermark("This is a watermark", desc, onTop, false, types.POINTS) 623 if err != nil { 624 t.Fatalf("%s %s: %v\n", msg, outFile, err) 625 } 626 627 if err = api.AddWatermarksFile(inFile, outFile, nil, wm, nil); err != nil { 628 t.Fatalf("%s %s: %v\n", msg, outFile, err) 629 } 630 631 wm.Recycle() 632 633 // Shift down watermark. 634 wm.Dy = -55 635 636 if err = api.AddWatermarksFile(outFile, outFile, nil, wm, nil); err != nil { 637 t.Fatalf("%s %s: %v\n", msg, outFile, err) 638 } 639 }