github.com/pdfcpu/pdfcpu@v0.11.1/pkg/api/image.go (about)

     1  /*
     2  Copyright 2021 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  	"path/filepath"
    23  	"strconv"
    24  	"strings"
    25  
    26  	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu"
    27  	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model"
    28  	"github.com/pkg/errors"
    29  )
    30  
    31  // Images returns all embedded images of rs.
    32  func Images(rs io.ReadSeeker, selectedPages []string, conf *model.Configuration) ([]map[int]model.Image, error) {
    33  	if rs == nil {
    34  		return nil, errors.New("pdfcpu: ListImages: missing rs")
    35  	}
    36  
    37  	if conf == nil {
    38  		conf = model.NewDefaultConfiguration()
    39  	}
    40  	conf.Cmd = model.LISTIMAGES
    41  
    42  	ctx, err := ReadValidateAndOptimize(rs, conf)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  
    47  	pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true, true)
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  
    52  	ii, _, err := pdfcpu.Images(ctx, pages)
    53  
    54  	return ii, err
    55  }
    56  
    57  // UpdateImages replaces the XObject identified by objNr or (pageNr and resourceId).
    58  func UpdateImages(rs io.ReadSeeker, rd io.Reader, w io.Writer, objNr, pageNr int, id string, conf *model.Configuration) error {
    59  
    60  	if rs == nil {
    61  		return errors.New("pdfcpu: UpdateImages: missing rs")
    62  	}
    63  
    64  	if conf == nil {
    65  		conf = model.NewDefaultConfiguration()
    66  	}
    67  	conf.Cmd = model.UPDATEIMAGES
    68  
    69  	ctx, err := ReadValidateAndOptimize(rs, conf)
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	if objNr > 0 {
    75  		if err := pdfcpu.UpdateImagesByObjNr(ctx, rd, objNr); err != nil {
    76  			return err
    77  		}
    78  
    79  		return Write(ctx, w, conf)
    80  	}
    81  
    82  	if pageNr == 0 || id == "" {
    83  		return errors.New("pdfcpu: UpdateImages: missing pageNr or id ")
    84  	}
    85  
    86  	if err := pdfcpu.UpdateImagesByPageNrAndId(ctx, rd, pageNr, id); err != nil {
    87  		return err
    88  	}
    89  
    90  	return Write(ctx, w, conf)
    91  }
    92  
    93  func ensurePageNrAndId(pageNr *int, id *string, imageFile string) (err error) {
    94  	// If objNr and pageNr and id are not set, we assume an image filename produced by "pdfcpu image list" and parse this info.
    95  	// eg. mountain_1_Im0.png => pageNr:1, id:Im0
    96  
    97  	if *pageNr > 0 && *id != "" {
    98  		return nil
    99  	}
   100  
   101  	s := strings.TrimSuffix(imageFile, filepath.Ext(imageFile))
   102  
   103  	ss := strings.Split(s, "_")
   104  
   105  	if len(ss) < 3 {
   106  		return errors.Errorf("pdfcpu: invalid image filename:%s - must conform to output filename of \"pdfcpu extract\"", imageFile)
   107  	}
   108  
   109  	*id = ss[len(ss)-1]
   110  
   111  	*pageNr, err = strconv.Atoi(ss[len(ss)-2])
   112  	if err != nil {
   113  		return err
   114  	}
   115  
   116  	return nil
   117  }
   118  
   119  // UpdateImagesFile replaces the XObject identified by objNr or (pageNr and resourceId).
   120  func UpdateImagesFile(inFile, imageFile, outFile string, objNr, pageNr int, id string, conf *model.Configuration) (err error) {
   121  
   122  	if objNr < 1 {
   123  		if err = ensurePageNrAndId(&pageNr, &id, imageFile); err != nil {
   124  			return err
   125  		}
   126  	}
   127  
   128  	var f0, f1, f2 *os.File
   129  
   130  	if f0, err = os.Open(inFile); err != nil {
   131  		return err
   132  	}
   133  
   134  	if f1, err = os.Open(imageFile); err != nil {
   135  		return err
   136  	}
   137  
   138  	tmpFile := inFile + ".tmp"
   139  	if outFile != "" && inFile != outFile {
   140  		tmpFile = outFile
   141  		logWritingTo(outFile)
   142  	} else {
   143  		logWritingTo(inFile)
   144  	}
   145  	if f2, err = os.Create(tmpFile); err != nil {
   146  		f1.Close()
   147  		return err
   148  	}
   149  
   150  	defer func() {
   151  		if err != nil {
   152  			f2.Close()
   153  			f1.Close()
   154  			f0.Close()
   155  			os.Remove(tmpFile)
   156  			return
   157  		}
   158  		if err = f2.Close(); err != nil {
   159  			return
   160  		}
   161  		if err = f1.Close(); err != nil {
   162  			return
   163  		}
   164  		if err = f0.Close(); err != nil {
   165  			return
   166  		}
   167  		if outFile == "" || inFile == outFile {
   168  			err = os.Rename(tmpFile, inFile)
   169  		}
   170  	}()
   171  
   172  	return UpdateImages(f0, f1, f2, objNr, pageNr, id, conf)
   173  }