github.com/pdfcpu/pdfcpu@v0.11.1/pkg/api/importImage.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  	"bufio"
    21  	"io"
    22  	"os"
    23  
    24  	"github.com/pdfcpu/pdfcpu/pkg/log"
    25  	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu"
    26  	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model"
    27  	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types"
    28  )
    29  
    30  // Import parses an Import command string into an internal structure.
    31  func Import(s string, u types.DisplayUnit) (*pdfcpu.Import, error) {
    32  	return pdfcpu.ParseImportDetails(s, u)
    33  }
    34  
    35  // ImportImages appends PDF pages containing images to rs and writes the result to w.
    36  // If rs == nil a new PDF file will be written to w.
    37  func ImportImages(rs io.ReadSeeker, w io.Writer, imgs []io.Reader, imp *pdfcpu.Import, conf *model.Configuration) error {
    38  	if conf == nil {
    39  		conf = model.NewDefaultConfiguration()
    40  	}
    41  	conf.Cmd = model.IMPORTIMAGES
    42  
    43  	if imp == nil {
    44  		imp = pdfcpu.DefaultImportConfig()
    45  	}
    46  
    47  	var (
    48  		ctx *model.Context
    49  		err error
    50  	)
    51  
    52  	if rs != nil {
    53  		ctx, err = ReadAndValidate(rs, conf)
    54  	} else {
    55  		ctx, err = pdfcpu.CreateContextWithXRefTable(conf, imp.PageDim)
    56  	}
    57  	if err != nil {
    58  		return err
    59  	}
    60  
    61  	pagesIndRef, err := ctx.Pages()
    62  	if err != nil {
    63  		return err
    64  	}
    65  
    66  	// Page tree root.
    67  	pagesDict, err := ctx.DereferenceDict(*pagesIndRef)
    68  	if err != nil {
    69  		return err
    70  	}
    71  
    72  	for _, r := range imgs {
    73  
    74  		indRefs, err := pdfcpu.NewPagesForImage(ctx.XRefTable, r, pagesIndRef, imp)
    75  		if err != nil {
    76  			return err
    77  		}
    78  
    79  		for _, indRef := range indRefs {
    80  			if err := ctx.SetValid(*indRef); err != nil {
    81  				return err
    82  			}
    83  			if err = model.AppendPageTree(indRef, 1, pagesDict); err != nil {
    84  				return err
    85  			}
    86  			ctx.PageCount++
    87  		}
    88  	}
    89  
    90  	return Write(ctx, w, conf)
    91  }
    92  
    93  func fileExists(filename string) bool {
    94  	var ret bool
    95  	f, err := os.Open(filename)
    96  	if err == nil {
    97  		ret = true
    98  	}
    99  	defer f.Close()
   100  	return ret
   101  
   102  }
   103  
   104  func prepImgFiles(imgFiles []string, f1 *os.File) ([]io.ReadCloser, []io.Reader, error) {
   105  	rc := make([]io.ReadCloser, len(imgFiles))
   106  	rr := make([]io.Reader, len(imgFiles))
   107  
   108  	for i, fn := range imgFiles {
   109  		f, err := os.Open(fn)
   110  		if err != nil {
   111  			if f1 != nil {
   112  				f1.Close()
   113  			}
   114  			return nil, nil, err
   115  		}
   116  		rc[i] = f
   117  		rr[i] = bufio.NewReader(f)
   118  	}
   119  
   120  	return rc, rr, nil
   121  }
   122  
   123  func logImportImages(s, outFile string) {
   124  	if log.CLIEnabled() {
   125  		log.CLI.Printf("%s to %s...\n", s, outFile)
   126  	}
   127  }
   128  
   129  // ImportImagesFile appends PDF pages containing images to outFile which will be created if necessary.
   130  func ImportImagesFile(imgFiles []string, outFile string, imp *pdfcpu.Import, conf *model.Configuration) (err error) {
   131  	var f1, f2 *os.File
   132  
   133  	rs := io.ReadSeeker(nil)
   134  	f1 = nil
   135  	tmpFile := outFile
   136  	if fileExists(outFile) {
   137  		if f1, err = os.Open(outFile); err != nil {
   138  			return err
   139  		}
   140  		rs = f1
   141  		tmpFile += ".tmp"
   142  		logImportImages("appending", outFile)
   143  	} else {
   144  		logImportImages("writing", outFile)
   145  	}
   146  
   147  	rc, rr, err := prepImgFiles(imgFiles, f1)
   148  	if err != nil {
   149  		return err
   150  	}
   151  
   152  	if f2, err = os.Create(tmpFile); err != nil {
   153  		if f1 != nil {
   154  			f1.Close()
   155  		}
   156  		return err
   157  	}
   158  
   159  	defer func() {
   160  		if err != nil {
   161  			f2.Close()
   162  			if f1 != nil {
   163  				f1.Close()
   164  				os.Remove(tmpFile)
   165  			}
   166  			for _, f := range rc {
   167  				f.Close()
   168  			}
   169  			return
   170  		}
   171  		if err = f2.Close(); err != nil {
   172  			return
   173  		}
   174  		if f1 != nil {
   175  			if err = f1.Close(); err != nil {
   176  				return
   177  			}
   178  			if err = os.Rename(tmpFile, outFile); err != nil {
   179  				return
   180  			}
   181  		}
   182  		for _, f := range rc {
   183  			if err := f.Close(); err != nil {
   184  				return
   185  			}
   186  		}
   187  	}()
   188  
   189  	return ImportImages(rs, f2, rr, imp, conf)
   190  }