github.com/pdfcpu/pdfcpu@v0.11.1/pkg/api/stamp.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 api
    18  
    19  import (
    20  	"io"
    21  	"os"
    22  
    23  	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu"
    24  	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model"
    25  	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types"
    26  	"github.com/pkg/errors"
    27  )
    28  
    29  // WatermarkContext applies wm for selected pages to ctx.
    30  func WatermarkContext(ctx *model.Context, selectedPages types.IntSet, wm *model.Watermark) error {
    31  	return pdfcpu.AddWatermarks(ctx, selectedPages, wm)
    32  }
    33  
    34  // AddWatermarksMap adds watermarks in m to corresponding pages in rs and writes the result to w.
    35  func AddWatermarksMap(rs io.ReadSeeker, w io.Writer, m map[int]*model.Watermark, conf *model.Configuration) error {
    36  	if rs == nil {
    37  		return errors.New("pdfcpu: AddWatermarksMap: missing rs")
    38  	}
    39  
    40  	if conf == nil {
    41  		conf = model.NewDefaultConfiguration()
    42  	}
    43  	conf.Cmd = model.ADDWATERMARKS
    44  
    45  	if len(m) == 0 {
    46  		return errors.New("pdfcpu: missing watermarks")
    47  	}
    48  
    49  	ctx, err := ReadValidateAndOptimize(rs, conf)
    50  	if err != nil {
    51  		return err
    52  	}
    53  
    54  	if err = pdfcpu.AddWatermarksMap(ctx, m); err != nil {
    55  		return err
    56  	}
    57  
    58  	return Write(ctx, w, conf)
    59  }
    60  
    61  // AddWatermarksMapFile adds watermarks to corresponding pages in m of inFile and writes the result to outFile.
    62  func AddWatermarksMapFile(inFile, outFile string, m map[int]*model.Watermark, conf *model.Configuration) (err error) {
    63  	var f1, f2 *os.File
    64  
    65  	if f1, err = os.Open(inFile); err != nil {
    66  		return err
    67  	}
    68  
    69  	tmpFile := inFile + ".tmp"
    70  	if outFile != "" && inFile != outFile {
    71  		tmpFile = outFile
    72  		logWritingTo(outFile)
    73  	} else {
    74  		logWritingTo(inFile)
    75  	}
    76  	if f2, err = os.Create(tmpFile); err != nil {
    77  		f1.Close()
    78  		return err
    79  	}
    80  
    81  	defer func() {
    82  		if err != nil {
    83  			f2.Close()
    84  			f1.Close()
    85  			os.Remove(tmpFile)
    86  			return
    87  		}
    88  		if err = f2.Close(); err != nil {
    89  			return
    90  		}
    91  		if err = f1.Close(); err != nil {
    92  			return
    93  		}
    94  		if outFile == "" || inFile == outFile {
    95  			err = os.Rename(tmpFile, inFile)
    96  		}
    97  	}()
    98  
    99  	return AddWatermarksMap(f1, f2, m, conf)
   100  }
   101  
   102  // AddWatermarksSliceMap adds watermarks in m to corresponding pages in rs and writes the result to w.
   103  func AddWatermarksSliceMap(rs io.ReadSeeker, w io.Writer, m map[int][]*model.Watermark, conf *model.Configuration) error {
   104  	if rs == nil {
   105  		return errors.New("pdfcpu: AddWatermarksSliceMap: missing rs")
   106  	}
   107  
   108  	if conf == nil {
   109  		conf = model.NewDefaultConfiguration()
   110  	}
   111  	conf.Cmd = model.ADDWATERMARKS
   112  
   113  	if len(m) == 0 {
   114  		return errors.New("pdfcpu: missing watermarks")
   115  	}
   116  
   117  	ctx, err := ReadValidateAndOptimize(rs, conf)
   118  	if err != nil {
   119  		return err
   120  	}
   121  
   122  	if err = pdfcpu.AddWatermarksSliceMap(ctx, m); err != nil {
   123  		return err
   124  	}
   125  
   126  	return Write(ctx, w, conf)
   127  }
   128  
   129  // AddWatermarksSliceMapFile adds watermarks to corresponding pages in m of inFile and writes the result to outFile.
   130  func AddWatermarksSliceMapFile(inFile, outFile string, m map[int][]*model.Watermark, conf *model.Configuration) (err error) {
   131  	var f1, f2 *os.File
   132  
   133  	if f1, err = os.Open(inFile); err != nil {
   134  		return err
   135  	}
   136  
   137  	tmpFile := inFile + ".tmp"
   138  	if outFile != "" && inFile != outFile {
   139  		tmpFile = outFile
   140  		logWritingTo(outFile)
   141  	} else {
   142  		logWritingTo(inFile)
   143  	}
   144  	if f2, err = os.Create(tmpFile); err != nil {
   145  		f1.Close()
   146  		return err
   147  	}
   148  
   149  	defer func() {
   150  		if err != nil {
   151  			f2.Close()
   152  			f1.Close()
   153  			os.Remove(tmpFile)
   154  			return
   155  		}
   156  		if err = f2.Close(); err != nil {
   157  			return
   158  		}
   159  		if err = f1.Close(); err != nil {
   160  			return
   161  		}
   162  		if outFile == "" || inFile == outFile {
   163  			err = os.Rename(tmpFile, inFile)
   164  		}
   165  	}()
   166  
   167  	return AddWatermarksSliceMap(f1, f2, m, conf)
   168  }
   169  
   170  // AddWatermarks adds watermarks to all pages selected in rs and writes the result to w.
   171  func AddWatermarks(rs io.ReadSeeker, w io.Writer, selectedPages []string, wm *model.Watermark, conf *model.Configuration) error {
   172  	if rs == nil {
   173  		return errors.New("pdfcpu: AddWatermarks: missing rs")
   174  	}
   175  
   176  	if conf == nil {
   177  		conf = model.NewDefaultConfiguration()
   178  	}
   179  	conf.Cmd = model.ADDWATERMARKS
   180  	conf.OptimizeDuplicateContentStreams = false
   181  
   182  	if wm == nil {
   183  		return errors.New("pdfcpu: missing watermark configuration")
   184  	}
   185  
   186  	ctx, err := ReadValidateAndOptimize(rs, conf)
   187  	if err != nil {
   188  		return err
   189  	}
   190  
   191  	var pages types.IntSet
   192  	pages, err = PagesForPageSelection(ctx.PageCount, selectedPages, true, true)
   193  	if err != nil {
   194  		return err
   195  	}
   196  
   197  	if err = pdfcpu.AddWatermarks(ctx, pages, wm); err != nil {
   198  		return err
   199  	}
   200  
   201  	return Write(ctx, w, conf)
   202  }
   203  
   204  // AddWatermarksFile adds watermarks to all selected pages of inFile and writes the result to outFile.
   205  func AddWatermarksFile(inFile, outFile string, selectedPages []string, wm *model.Watermark, conf *model.Configuration) (err error) {
   206  	var f1, f2 *os.File
   207  
   208  	if f1, err = os.Open(inFile); err != nil {
   209  		return err
   210  	}
   211  
   212  	tmpFile := inFile + ".tmp"
   213  	if outFile != "" && inFile != outFile {
   214  		tmpFile = outFile
   215  		logWritingTo(outFile)
   216  	} else {
   217  		logWritingTo(inFile)
   218  	}
   219  	if f2, err = os.Create(tmpFile); err != nil {
   220  		f1.Close()
   221  		return err
   222  	}
   223  
   224  	defer func() {
   225  		if err != nil {
   226  			f2.Close()
   227  			f1.Close()
   228  			os.Remove(tmpFile)
   229  			return
   230  		}
   231  		if err = f2.Close(); err != nil {
   232  			return
   233  		}
   234  		if err = f1.Close(); err != nil {
   235  			return
   236  		}
   237  		if outFile == "" || inFile == outFile {
   238  			err = os.Rename(tmpFile, inFile)
   239  		}
   240  	}()
   241  
   242  	return AddWatermarks(f1, f2, selectedPages, wm, conf)
   243  }
   244  
   245  // RemoveWatermarks removes watermarks from all pages selected in rs and writes the result to w.
   246  func RemoveWatermarks(rs io.ReadSeeker, w io.Writer, selectedPages []string, conf *model.Configuration) error {
   247  	if rs == nil {
   248  		return errors.New("pdfcpu: RemoveWatermarks: missing rs")
   249  	}
   250  
   251  	if conf == nil {
   252  		conf = model.NewDefaultConfiguration()
   253  	}
   254  	conf.Cmd = model.REMOVEWATERMARKS
   255  
   256  	ctx, err := ReadValidateAndOptimize(rs, conf)
   257  	if err != nil {
   258  		return err
   259  	}
   260  
   261  	pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true, true)
   262  	if err != nil {
   263  		return err
   264  	}
   265  
   266  	if err = pdfcpu.RemoveWatermarks(ctx, pages); err != nil {
   267  		return err
   268  	}
   269  
   270  	return Write(ctx, w, conf)
   271  }
   272  
   273  // RemoveWatermarksFile removes watermarks from all selected pages of inFile and writes the result to outFile.
   274  func RemoveWatermarksFile(inFile, outFile string, selectedPages []string, conf *model.Configuration) (err error) {
   275  	var f1, f2 *os.File
   276  
   277  	if f1, err = os.Open(inFile); err != nil {
   278  		return err
   279  	}
   280  
   281  	tmpFile := inFile + ".tmp"
   282  	if outFile != "" && inFile != outFile {
   283  		tmpFile = outFile
   284  		logWritingTo(outFile)
   285  	} else {
   286  		logWritingTo(inFile)
   287  	}
   288  	if f2, err = os.Create(tmpFile); err != nil {
   289  		f1.Close()
   290  		return err
   291  	}
   292  
   293  	defer func() {
   294  		if err != nil {
   295  			f2.Close()
   296  			f1.Close()
   297  			os.Remove(tmpFile)
   298  			return
   299  		}
   300  		if err = f2.Close(); err != nil {
   301  			return
   302  		}
   303  		if err = f1.Close(); err != nil {
   304  			return
   305  		}
   306  		if outFile == "" || inFile == outFile {
   307  			err = os.Rename(tmpFile, inFile)
   308  		}
   309  	}()
   310  
   311  	return RemoveWatermarks(f1, f2, selectedPages, conf)
   312  }
   313  
   314  // HasWatermarks checks rs for watermarks.
   315  func HasWatermarks(rs io.ReadSeeker, conf *model.Configuration) (bool, error) {
   316  	if rs == nil {
   317  		return false, errors.New("pdfcpu: HasWatermarks: missing rs")
   318  	}
   319  
   320  	ctx, err := ReadContext(rs, conf)
   321  	if err != nil {
   322  		return false, err
   323  	}
   324  
   325  	if err := pdfcpu.DetectWatermarks(ctx); err != nil {
   326  		return false, err
   327  	}
   328  
   329  	return ctx.Watermarked, nil
   330  }
   331  
   332  // HasWatermarksFile checks inFile for watermarks.
   333  func HasWatermarksFile(inFile string, conf *model.Configuration) (bool, error) {
   334  	if conf == nil {
   335  		conf = model.NewDefaultConfiguration()
   336  	}
   337  
   338  	f, err := os.Open(inFile)
   339  	if err != nil {
   340  		return false, err
   341  	}
   342  
   343  	defer f.Close()
   344  
   345  	return HasWatermarks(f, conf)
   346  }
   347  
   348  // TextWatermark returns a text watermark configuration.
   349  func TextWatermark(text, desc string, onTop, update bool, u types.DisplayUnit) (*model.Watermark, error) {
   350  	wm, err := pdfcpu.ParseTextWatermarkDetails(text, desc, onTop, u)
   351  	if err != nil {
   352  		return nil, err
   353  	}
   354  
   355  	wm.Update = update
   356  
   357  	return wm, nil
   358  }
   359  
   360  // ImageWatermark returns an image watermark configuration.
   361  func ImageWatermark(fileName, desc string, onTop, update bool, u types.DisplayUnit) (*model.Watermark, error) {
   362  	wm, err := pdfcpu.ParseImageWatermarkDetails(fileName, desc, onTop, u)
   363  	if err != nil {
   364  		return nil, err
   365  	}
   366  
   367  	wm.Update = update
   368  
   369  	return wm, nil
   370  }
   371  
   372  // ImageWatermarkForReader returns an image watermark configuration for r.
   373  func ImageWatermarkForReader(r io.Reader, desc string, onTop, update bool, u types.DisplayUnit) (*model.Watermark, error) {
   374  	wm, err := pdfcpu.ParseImageWatermarkDetails("", desc, onTop, u)
   375  	if err != nil {
   376  		return nil, err
   377  	}
   378  
   379  	wm.Update = update
   380  	wm.Image = r
   381  
   382  	return wm, nil
   383  }
   384  
   385  // PDFWatermark returns a PDF watermark configuration.
   386  func PDFWatermark(fileName, desc string, onTop, update bool, u types.DisplayUnit) (*model.Watermark, error) {
   387  	wm, err := pdfcpu.ParsePDFWatermarkDetails(fileName, desc, onTop, u)
   388  	if err != nil {
   389  		return nil, err
   390  	}
   391  
   392  	wm.Update = update
   393  
   394  	return wm, nil
   395  }
   396  
   397  // PDFWatermarkForReadSeeker returns a PDF watermark configuration.
   398  // Apply watermark/stamp to destination file with pageNrSrc of rs for selected pages.
   399  // If pageNr == 0 apply a multi watermark/stamp applying all src pages in ascending manner to destination pages.
   400  func PDFWatermarkForReadSeeker(rs io.ReadSeeker, pageNrSrc int, desc string, onTop, update bool, u types.DisplayUnit) (*model.Watermark, error) {
   401  	wm, err := pdfcpu.ParsePDFWatermarkDetails("", desc, onTop, u)
   402  	if err != nil {
   403  		return nil, err
   404  	}
   405  
   406  	wm.Update = update
   407  	wm.PDF = rs
   408  	wm.PdfPageNrSrc = pageNrSrc
   409  
   410  	return wm, nil
   411  }
   412  
   413  // PDFMultiWatermarkForReadSeeker returns a PDF watermark configuration.
   414  // Define a source PDF watermark/stamp sequence using rs from page startPageNrSrc thru the last page of rs.
   415  // Apply this sequence to the destination PDF file starting at page startPageNrDest for selected pages.
   416  func PDFMultiWatermarkForReadSeeker(rs io.ReadSeeker, startPageNrSrc, startPageNrDest int, desc string, onTop, update bool, u types.DisplayUnit) (*model.Watermark, error) {
   417  	wm, err := pdfcpu.ParsePDFWatermarkDetails("", desc, onTop, u)
   418  	if err != nil {
   419  		return nil, err
   420  	}
   421  
   422  	wm.Update = update
   423  	wm.PDF = rs
   424  	wm.PdfMultiStartPageNrSrc = startPageNrSrc
   425  	wm.PdfMultiStartPageNrDest = startPageNrDest
   426  
   427  	return wm, nil
   428  }
   429  
   430  // AddTextWatermarksFile adds text stamps/watermarks to all selected pages of inFile and writes the result to outFile.
   431  func AddTextWatermarksFile(inFile, outFile string, selectedPages []string, onTop bool, text, desc string, conf *model.Configuration) error {
   432  	unit := types.POINTS
   433  	if conf != nil {
   434  		unit = conf.Unit
   435  	}
   436  
   437  	wm, err := TextWatermark(text, desc, onTop, false, unit)
   438  	if err != nil {
   439  		return err
   440  	}
   441  
   442  	return AddWatermarksFile(inFile, outFile, selectedPages, wm, conf)
   443  }
   444  
   445  // AddImageWatermarksFile adds image stamps/watermarks to all selected pages of inFile and writes the result to outFile.
   446  func AddImageWatermarksFile(inFile, outFile string, selectedPages []string, onTop bool, fileName, desc string, conf *model.Configuration) error {
   447  	unit := types.POINTS
   448  	if conf != nil {
   449  		unit = conf.Unit
   450  	}
   451  
   452  	wm, err := ImageWatermark(fileName, desc, onTop, false, unit)
   453  	if err != nil {
   454  		return err
   455  	}
   456  
   457  	return AddWatermarksFile(inFile, outFile, selectedPages, wm, conf)
   458  }
   459  
   460  // AddImageWatermarksForReaderFile adds image stamps/watermarks to all selected pages of inFile for r and writes the result to outFile.
   461  func AddImageWatermarksForReaderFile(inFile, outFile string, selectedPages []string, onTop bool, r io.Reader, desc string, conf *model.Configuration) error {
   462  	unit := types.POINTS
   463  	if conf != nil {
   464  		unit = conf.Unit
   465  	}
   466  
   467  	wm, err := ImageWatermarkForReader(r, desc, onTop, false, unit)
   468  	if err != nil {
   469  		return err
   470  	}
   471  
   472  	return AddWatermarksFile(inFile, outFile, selectedPages, wm, conf)
   473  }
   474  
   475  // AddPDFWatermarksFile adds PDF stamps/watermarks to inFile and writes the result to outFile.
   476  func AddPDFWatermarksFile(inFile, outFile string, selectedPages []string, onTop bool, fileName, desc string, conf *model.Configuration) error {
   477  	unit := types.POINTS
   478  	if conf != nil {
   479  		unit = conf.Unit
   480  	}
   481  
   482  	wm, err := PDFWatermark(fileName, desc, onTop, false, unit)
   483  	if err != nil {
   484  		return err
   485  	}
   486  
   487  	return AddWatermarksFile(inFile, outFile, selectedPages, wm, conf)
   488  }
   489  
   490  // UpdateTextWatermarksFile adds text stamps/watermarks to all selected pages of inFile and writes the result to outFile.
   491  func UpdateTextWatermarksFile(inFile, outFile string, selectedPages []string, onTop bool, text, desc string, conf *model.Configuration) error {
   492  	unit := types.POINTS
   493  	if conf != nil {
   494  		unit = conf.Unit
   495  	}
   496  
   497  	wm, err := TextWatermark(text, desc, onTop, true, unit)
   498  	if err != nil {
   499  		return err
   500  	}
   501  
   502  	return AddWatermarksFile(inFile, outFile, selectedPages, wm, conf)
   503  }
   504  
   505  // UpdateImageWatermarksFile adds image stamps/watermarks to all selected pages of inFile and writes the result to outFile.
   506  func UpdateImageWatermarksFile(inFile, outFile string, selectedPages []string, onTop bool, fileName, desc string, conf *model.Configuration) error {
   507  	unit := types.POINTS
   508  	if conf != nil {
   509  		unit = conf.Unit
   510  	}
   511  	wm, err := ImageWatermark(fileName, desc, onTop, true, unit)
   512  	if err != nil {
   513  		return err
   514  	}
   515  	return AddWatermarksFile(inFile, outFile, selectedPages, wm, conf)
   516  }
   517  
   518  // UpdatePDFWatermarksFile adds PDF stamps/watermarks to all selected pages of inFile and writes the result to outFile.
   519  func UpdatePDFWatermarksFile(inFile, outFile string, selectedPages []string, onTop bool, fileName, desc string, conf *model.Configuration) error {
   520  	unit := types.POINTS
   521  	if conf != nil {
   522  		unit = conf.Unit
   523  	}
   524  
   525  	wm, err := PDFWatermark(fileName, desc, onTop, true, unit)
   526  	if err != nil {
   527  		return err
   528  	}
   529  
   530  	return AddWatermarksFile(inFile, outFile, selectedPages, wm, conf)
   531  }