github.com/pdfcpu/pdfcpu@v0.11.1/pkg/api/page.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 "sort" 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 "github.com/pkg/errors" 29 ) 30 31 // InsertPages inserts a blank page before or after every page selected of rs and writes the result to w. 32 func InsertPages(rs io.ReadSeeker, w io.Writer, selectedPages []string, before bool, pageConf *pdfcpu.PageConfiguration, conf *model.Configuration) error { 33 if rs == nil { 34 return errors.New("pdfcpu: InsertPages: missing rs") 35 } 36 37 if conf == nil { 38 conf = model.NewDefaultConfiguration() 39 } 40 conf.Cmd = model.INSERTPAGESAFTER 41 if before { 42 conf.Cmd = model.INSERTPAGESBEFORE 43 } 44 45 ctx, err := ReadValidateAndOptimize(rs, conf) 46 if err != nil { 47 return err 48 } 49 50 pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true, true) 51 if err != nil { 52 return err 53 } 54 55 var dim *types.Dim 56 if pageConf != nil { 57 dim = pageConf.PageDim 58 } 59 60 if err = ctx.InsertBlankPages(pages, dim, before); err != nil { 61 return err 62 } 63 64 return Write(ctx, w, conf) 65 } 66 67 // InsertPagesFile inserts a blank page before or after every inFile page selected and writes the result to w. 68 func InsertPagesFile(inFile, outFile string, selectedPages []string, before bool, pageConf *pdfcpu.PageConfiguration, conf *model.Configuration) (err error) { 69 var f1, f2 *os.File 70 71 if f1, err = os.Open(inFile); err != nil { 72 return err 73 } 74 75 tmpFile := inFile + ".tmp" 76 if outFile != "" && inFile != outFile { 77 tmpFile = outFile 78 logWritingTo(outFile) 79 } else { 80 logWritingTo(inFile) 81 } 82 if f2, err = os.Create(tmpFile); err != nil { 83 f1.Close() 84 return err 85 } 86 87 defer func() { 88 if err != nil { 89 f2.Close() 90 f1.Close() 91 os.Remove(tmpFile) 92 return 93 } 94 if err = f2.Close(); err != nil { 95 return 96 } 97 if err = f1.Close(); err != nil { 98 return 99 } 100 if outFile == "" || inFile == outFile { 101 err = os.Rename(tmpFile, inFile) 102 } 103 }() 104 105 return InsertPages(f1, f2, selectedPages, before, pageConf, conf) 106 } 107 108 // RemovePages removes selected pages from rs and writes the result to w. 109 func RemovePages(rs io.ReadSeeker, w io.Writer, selectedPages []string, conf *model.Configuration) error { 110 if rs == nil { 111 return errors.New("pdfcpu: RemovePages: missing rs") 112 } 113 114 if conf == nil { 115 conf = model.NewDefaultConfiguration() 116 } 117 conf.Cmd = model.REMOVEPAGES 118 119 ctx, err := ReadValidateAndOptimize(rs, conf) 120 if err != nil { 121 return err 122 } 123 124 pages, err := RemainingPagesForPageRemoval(ctx.PageCount, selectedPages, true) 125 if err != nil { 126 return err 127 } 128 129 if len(pages) == 0 { 130 if log.CLIEnabled() { 131 log.CLI.Println("aborted: missing page numbers!") 132 } 133 return nil 134 } 135 136 var pageNrs []int 137 for k, v := range pages { 138 if v { 139 pageNrs = append(pageNrs, k) 140 } 141 } 142 sort.Ints(pageNrs) 143 144 ctxDest, err := pdfcpu.ExtractPages(ctx, pageNrs, false) 145 if err != nil { 146 return err 147 } 148 149 return Write(ctxDest, w, conf) 150 } 151 152 // RemovePagesFile removes selected inFile pages and writes the result to outFile.. 153 func RemovePagesFile(inFile, outFile string, selectedPages []string, conf *model.Configuration) (err error) { 154 var f1, f2 *os.File 155 156 if f1, err = os.Open(inFile); err != nil { 157 return err 158 } 159 160 tmpFile := inFile + ".tmp" 161 if outFile != "" && inFile != outFile { 162 tmpFile = outFile 163 logWritingTo(outFile) 164 } else { 165 logWritingTo(inFile) 166 } 167 if f2, err = os.Create(tmpFile); err != nil { 168 f1.Close() 169 return err 170 } 171 172 defer func() { 173 if err != nil { 174 f2.Close() 175 f1.Close() 176 os.Remove(tmpFile) 177 return 178 } 179 if err = f2.Close(); err != nil { 180 return 181 } 182 if err = f1.Close(); err != nil { 183 return 184 } 185 if outFile == "" || inFile == outFile { 186 err = os.Rename(tmpFile, inFile) 187 } 188 }() 189 190 return RemovePages(f1, f2, selectedPages, conf) 191 } 192 193 // PageCount returns rs's page count. 194 func PageCount(rs io.ReadSeeker, conf *model.Configuration) (int, error) { 195 if rs == nil { 196 return 0, errors.New("pdfcpu: PageCount: missing rs") 197 } 198 199 ctx, err := ReadAndValidate(rs, conf) 200 if err != nil { 201 return 0, err 202 } 203 204 return ctx.PageCount, nil 205 } 206 207 // PageCountFile returns inFile's page count. 208 func PageCountFile(inFile string) (int, error) { 209 f, err := os.Open(inFile) 210 if err != nil { 211 return 0, err 212 } 213 defer f.Close() 214 215 return PageCount(f, model.NewDefaultConfiguration()) 216 } 217 218 // PageDims returns a sorted slice of mediaBox dimensions for rs. 219 func PageDims(rs io.ReadSeeker, conf *model.Configuration) ([]types.Dim, error) { 220 if rs == nil { 221 return nil, errors.New("pdfcpu: PageDims: missing rs") 222 } 223 224 ctx, err := ReadAndValidate(rs, conf) 225 if err != nil { 226 return nil, err 227 } 228 229 pd, err := ctx.PageDims() 230 if err != nil { 231 return nil, err 232 } 233 234 if len(pd) != ctx.PageCount { 235 return nil, errors.New("pdfcpu: corrupt page dimensions") 236 } 237 238 return pd, nil 239 } 240 241 // PageDimsFile returns a sorted slice of mediaBox dimensions for inFile. 242 func PageDimsFile(inFile string) ([]types.Dim, error) { 243 f, err := os.Open(inFile) 244 if err != nil { 245 return nil, err 246 } 247 defer f.Close() 248 249 return PageDims(f, model.NewDefaultConfiguration()) 250 }