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  }