github.com/pdfcpu/pdfcpu@v0.11.1/pkg/api/test/stampVersatile_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 "os" 22 "path/filepath" 23 "testing" 24 "time" 25 26 "github.com/pdfcpu/pdfcpu/pkg/api" 27 "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" 28 "github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model" 29 "github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types" 30 ) 31 32 func TestAlternatingPageNumbersViaWatermarkMap(t *testing.T) { 33 msg := "TestAlternatingPageNumbersViaWatermarkMap" 34 inFile := filepath.Join(inDir, "WaldenFull.pdf") 35 outFile := filepath.Join(samplesDir, "stamp", "mixed", "AlternatingPageNumbersViaWatermarkMap.pdf") 36 37 pageCount, err := api.PageCountFile(inFile) 38 if err != nil { 39 t.Fatalf("%s: %v\n", msg, err) 40 } 41 42 // Prepare a map of watermarks. 43 // This maps pages to corresponding watermarks. 44 // Any page may be assigned a single watermark of type text, image or PDF. 45 m := map[int]*model.Watermark{} 46 47 // Start stamping with page 2. 48 // For odd page numbers add a blue stamp on the bottom right corner using Roboto-Regular 49 // For even page numbers add a green stamp on the bottom left corner using Times-Italic 50 for i := 2; i <= pageCount; i++ { 51 text := fmt.Sprintf("%d of %d", i, pageCount) 52 fontName := "Times-Italic" 53 pos := "bl" 54 dx := 10 55 fillCol := "#008000" 56 if i%2 > 0 { 57 fontName = "Roboto-Regular" 58 pos = "br" 59 dx = -10 60 fillCol = "#0000E0" 61 } 62 desc := fmt.Sprintf("font:%s, points:12, scale:1 abs, pos:%s, off:%d 10, fillcol:%s, rot:0", fontName, pos, dx, fillCol) 63 wm, err := api.TextWatermark(text, desc, true, false, types.POINTS) 64 if err != nil { 65 t.Fatalf("%s: %v\n", msg, err) 66 } 67 m[i] = wm 68 } 69 70 if err := api.AddWatermarksMapFile(inFile, outFile, m, nil); err != nil { 71 t.Fatalf("%s %s: %v\n", msg, outFile, err) 72 } 73 74 // Add a stamp with the creation date on the center of the bottom of every page. 75 text := fmt.Sprintf("%%p of %%P - Creation date: %v", time.Now().Format("2006-01-02 15:04")) 76 if err := api.AddTextWatermarksFile(outFile, outFile, nil, true, text, "fo:Roboto-Regular, points:12, scale:1 abs, pos:bc, off:0 10, rot:0", nil); err != nil { 77 t.Fatalf("%s %s: %v\n", msg, outFile, err) 78 } 79 80 // Add a "Draft" stamp with opacity 0.6 along the 1st diagonal in light blue using Courier. 81 if err := api.AddTextWatermarksFile(outFile, outFile, nil, true, "Draft", "fo:Courier, scale:.9, fillcol:#00aacc, op:.6", nil); err != nil { 82 t.Fatalf("%s %s: %v\n", msg, outFile, err) 83 } 84 } 85 86 func TestAlternatingPageNumbersViaWatermarkMapLowLevel(t *testing.T) { 87 msg := "TestAlternatingPageNumbersViaWatermarkMapLowLevel" 88 inFile := filepath.Join(inDir, "WaldenFull.pdf") 89 outFile := filepath.Join(samplesDir, "stamp", "mixed", "AlternatingPageNumbersViaWatermarkMapLowLevel.pdf") 90 91 // Create a context. 92 ctx, err := api.ReadContextFile(inFile) 93 if err != nil { 94 t.Fatalf("%s readContext: %v\n", msg, err) 95 } 96 97 m := map[int]*model.Watermark{} 98 unit := types.POINTS 99 100 // Start stamping with page 2. 101 // For odd page numbers add a blue stamp on the bottom right corner using Roboto-Regular 102 // For even page numbers add a green stamp on the bottom left corner using Times-Italic 103 for i := 2; i <= ctx.PageCount; i++ { 104 text := fmt.Sprintf("%d of %d", i, ctx.PageCount) 105 fontName := "Times-Italic" 106 pos := "bl" 107 dx := 10 108 fillCol := "#008000" 109 if i%2 > 0 { 110 fontName = "Roboto-Regular" 111 pos = "br" 112 dx = -10 113 fillCol = "#0000E0" 114 } 115 desc := fmt.Sprintf("font:%s, points:12, scale:1 abs, pos:%s, off:%d 10, fillcol:%s, rot:0", fontName, pos, dx, fillCol) 116 wm, err := api.TextWatermark(text, desc, true, false, unit) 117 if err != nil { 118 t.Fatalf("%s: %v\n", msg, err) 119 } 120 m[i] = wm 121 } 122 123 if err := pdfcpu.AddWatermarksMap(ctx, m); err != nil { 124 t.Fatalf("%s %s: %v\n", msg, outFile, err) 125 } 126 127 // Add a stamp with the creation date on the center of the bottom of every page. 128 text := fmt.Sprintf("%%p of %%P - Creation date: %v", time.Now().Format("2006-01-02 15:04")) 129 wm, err := api.TextWatermark(text, "fo:Roboto-Regular, points:12, scale:1 abs, pos:bc, off:0 10, rot:0", true, false, unit) 130 if err != nil { 131 t.Fatalf("%s %s: %v\n", msg, outFile, err) 132 } 133 if err := pdfcpu.AddWatermarks(ctx, nil, wm); err != nil { 134 t.Fatalf("%s %s: %v\n", msg, outFile, err) 135 } 136 137 // Add a "Draft" stamp with opacity 0.6 along the 1st diagonal in light blue using Courier. 138 wm, err = api.TextWatermark("Draft", "fo:Courier, scale:.9, fillcol:#00aacc, op:.6", true, false, unit) 139 if err != nil { 140 t.Fatalf("%s %s: %v\n", msg, outFile, err) 141 } 142 if err := pdfcpu.AddWatermarks(ctx, nil, wm); err != nil { 143 t.Fatalf("%s %s: %v\n", msg, outFile, err) 144 } 145 146 // Write context to file. 147 if err := api.WriteContextFile(ctx, outFile); err != nil { 148 t.Fatalf("%s write: %v\n", msg, err) 149 } 150 } 151 152 func TestAlternatingPageNumbersViaWatermarkSliceMap(t *testing.T) { 153 msg := "TestAlternatingPageNumbersViaWatermarkSliceMap" 154 inFile := filepath.Join(inDir, "WaldenFull.pdf") 155 outFile := filepath.Join(samplesDir, "stamp", "mixed", "AlternatingPageNumbersViaWatermarkSliceMap.pdf") 156 157 pageCount, err := api.PageCountFile(inFile) 158 if err != nil { 159 t.Fatalf("%s: %v\n", msg, err) 160 } 161 162 m := map[int][]*model.Watermark{} 163 opacity := 1.0 164 onTop := true // All stamps! 165 update := false 166 unit := types.POINTS 167 168 // Prepare a map of watermark slices. 169 // This maps pages to corresponding watermarks. 170 // Each page may be assigned an arbitrary number of watermarks of type text, image or PDF. 171 for i := 2; i <= pageCount; i++ { 172 173 wms := []*model.Watermark{} 174 175 // 1st watermark on page 176 // For odd page numbers add a blue stamp on the bottom right corner using Roboto-Regular 177 // For even page numbers add a green stamp on the bottom left corner using Times-Italic 178 text := fmt.Sprintf("%d of %d", i, pageCount) 179 fontName := "Times-Italic" 180 pos := "bl" 181 dx := 10 182 fillCol := "#008000" 183 if i%2 > 0 { 184 fontName = "Roboto-Regular" 185 pos = "br" 186 dx = -10 187 fillCol = "#0000E0" 188 } 189 desc := fmt.Sprintf("font:%s, points:12, scale:1 abs, pos:%s, off:%d 10, fillcol:%s, rot:0, op:%f", fontName, pos, dx, fillCol, opacity) 190 wm, err := api.TextWatermark(text, desc, onTop, update, unit) 191 if err != nil { 192 t.Fatalf("%s: %v\n", msg, err) 193 } 194 wms = append(wms, wm) 195 196 // 2nd watermark on page 197 // Add a stamp with the creation date on the center of the bottom of every page. 198 text = fmt.Sprintf("%%p of %%P - Creation date: %v", time.Now().Format("2006-01-02 15:04")) 199 desc = fmt.Sprintf("fo:Roboto-Regular, points:12, scale:1 abs, pos:bc, off:0 10, rot:0, op:%f", opacity) 200 wm, err = api.TextWatermark(text, desc, onTop, update, unit) 201 if err != nil { 202 t.Fatalf("%s: %v\n", msg, err) 203 } 204 wms = append(wms, wm) 205 206 // 3rd watermark on page 207 // Add a "Draft" stamp with opacity 0.6 along the 1st diagonal in light blue using Courier. 208 text = "Draft" 209 desc = fmt.Sprintf("fo:Courier, scale:.9, fillcol:#00aacc, op:%f", opacity) 210 wm, err = api.TextWatermark(text, desc, onTop, update, unit) 211 if err != nil { 212 t.Fatalf("%s: %v\n", msg, err) 213 } 214 wms = append(wms, wm) 215 216 m[i] = wms 217 } 218 219 // Apply all watermarks in one Go. 220 // Assumption: All watermarks share the same opacity and onTop (all stamps or watermarks). 221 // If you cannot ensure this you have to do something along the lines of func TestAlternatingPageNumbersViaWatermarkMap 222 if err := api.AddWatermarksSliceMapFile(inFile, outFile, m, nil); err != nil { 223 t.Fatalf("%s %s: %v\n", msg, outFile, err) 224 } 225 } 226 227 func TestImagesTextAndPDFWMViaWatermarkMap(t *testing.T) { 228 msg := "TestImagesTextAndPDFWMViaWatermarkMap" 229 inFile := filepath.Join(inDir, "WaldenFull.pdf") 230 outFile := filepath.Join(samplesDir, "stamp", "mixed", "ImagesTextAndPDFWMViaWatermarkMap.pdf") 231 232 pageCount, err := api.PageCountFile(inFile) 233 if err != nil { 234 t.Fatalf("%s: %v\n", msg, err) 235 } 236 237 m := map[int]*model.Watermark{} 238 fileNames := imageFileNames(t, resDir) 239 240 opacity := 1.0 241 onTop := true // All stamps! 242 update := false 243 unit := types.POINTS 244 245 // Apply a mix of image, text and PDF watermarks in one go. 246 for i := 1; i <= pageCount; i++ { 247 if i <= len(fileNames) { 248 desc := fmt.Sprintf("pos:bl, scale:.25, rot:0, op:%f", opacity) 249 wm, err := api.ImageWatermark(fileNames[i-1], desc, onTop, update, unit) 250 if err != nil { 251 t.Fatalf("%s: %v\n", msg, err) 252 } 253 m[i] = wm 254 continue 255 } 256 257 if i%2 > 0 { 258 desc := fmt.Sprintf("scale:.25, pos:br, rot:0, op:%f", opacity) 259 wm, err := api.PDFWatermark(inFile+":1", desc, onTop, update, unit) 260 if err != nil { 261 t.Fatalf("%s: %v\n", msg, err) 262 } 263 m[i] = wm 264 continue 265 } 266 267 desc := fmt.Sprintf("rot:0, op:%f", opacity) 268 wm, err := api.TextWatermark("Even page number", desc, onTop, update, unit) 269 if err != nil { 270 t.Fatalf("%s: %v\n", msg, err) 271 } 272 m[i] = wm 273 } 274 275 // Apply all watermarks in one Go. 276 // Assumption: All watermarks share the same opacity and onTop (all stamps or watermarks). 277 // If you cannot ensure this you have to do something along the lines of func TestAlternatingPageNumbersViaWatermarkMap 278 if err := api.AddWatermarksMapFile(inFile, outFile, m, nil); err != nil { 279 t.Fatalf("%s %s: %v\n", msg, outFile, err) 280 } 281 } 282 283 func TestPdfSingleStampVariations(t *testing.T) { 284 msg := "TestPdfSingleStampVariations" 285 inFile := filepath.Join(inDir, "zineTest.pdf") 286 stampFile := inFile 287 288 // Stamp selected pages of inFile with one specific page of some PDF file - the stampFile. 289 290 rs, err := os.Open(stampFile) 291 if err != nil { 292 t.Fatalf("%s %s: %v\n", msg, stampFile, err) 293 } 294 defer rs.Close() 295 296 for _, tt := range []struct { 297 msg, outFile string 298 pageNrSrc int 299 }{ 300 {"TestPdfSingleStampDefault", // Use page 2 of stampFile to stamp inFile pages. 301 "PdfSingleStampDefault.pdf", 302 2, 303 }, 304 {"TestPdfMultiStampDefault", // Start stamping at page 1 using page 1 of stampFile. 305 "TestPdfMultiStampDefault.pdf", 306 0, // special case defaulting to multistamping 307 }, 308 } { 309 wm, err := api.PDFWatermarkForReadSeeker( 310 rs, 311 tt.pageNrSrc, 312 "scale:.2, pos:tr, off:-10 -10, rot:0", // scaled @ top right corner using some offset and 0 rotation. 313 true, // stamp 314 false, // no update 315 conf.Unit, 316 ) 317 318 if err != nil { 319 t.Fatalf("%s: %v\n", tt.msg, err) 320 } 321 322 outFile := filepath.Join(samplesDir, "stamp", "mixed", tt.outFile) 323 324 if err = api.AddWatermarksFile(inFile, outFile, nil, wm, conf); err != nil { 325 t.Fatalf("%s %s: %v\n", tt.msg, outFile, err) 326 } 327 } 328 } 329 330 func TestPdfMultiStampVariations(t *testing.T) { 331 msg := "TestPdfMultiStampVariations" 332 inFile := filepath.Join(inDir, "zineTest.pdf") 333 stampFile := inFile 334 335 // Stamp selected pages of inFile with different pages of some PDF file - the stampFile. 336 // Stamping proceeds in ascending manner where each new inFile page gets stamped with the next page of stampFile. 337 // Set the first page of the stampFile initiating the sequence = startPageNrSrc 338 // Set the first page of inFile that gets stamped = startPageNrDest 339 340 rs, err := os.Open(stampFile) 341 if err != nil { 342 t.Fatalf("%s %s: %v\n", msg, stampFile, err) 343 } 344 defer rs.Close() 345 346 for _, tt := range []struct { 347 msg, outFile string 348 startPageNrSrc int 349 startPageNrDest int 350 }{ 351 {"TestPdfMultiStamp11", // Start stamping at page 1 using page 1 of stampFile. (=TestPdfMultiStampDefault) 352 "PdfMultiStamp11.pdf", 353 1, 354 1, 355 }, 356 {"TestPdfMultiStamp13", // Skip first 2 page and start stamping at page 3 using page 1 of stampFile. 357 "PdfMultiStamp13.pdf", 358 1, 359 3, 360 }, 361 {"TestPdfMultiStamp31", // Start stamping at page 1 using page 3 of stampFile. 362 "PdfMultiStamp31.pdf", 363 3, 364 1, 365 }, 366 {"TestPdfMultiStamp33", // Skip first 2 page and start stamping at page 3 using page 3 of stampFile. 367 "PdfMultiStamp33.pdf", 368 3, 369 3, 370 }, 371 } { 372 wm, err := api.PDFMultiWatermarkForReadSeeker( 373 rs, 374 tt.startPageNrSrc, 375 tt.startPageNrDest, 376 "scale:.2, pos:tr, off:-10 -10, rot:0", // scaled @ top right corner using some offset and 0 rotation. 377 true, // stamp 378 false, // no update 379 conf.Unit, 380 ) 381 382 if err != nil { 383 t.Fatalf("%s: %v\n", tt.msg, err) 384 } 385 386 outFile := filepath.Join(samplesDir, "stamp", "mixed", tt.outFile) 387 388 if err = api.AddWatermarksFile(inFile, outFile, nil, wm, conf); err != nil { 389 t.Fatalf("%s %s: %v\n", tt.msg, outFile, err) 390 } 391 } 392 }