github.com/pdfcpu/pdfcpu@v0.11.1/pkg/api/box.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/log" 24 "github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model" 25 "github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types" 26 "github.com/pkg/errors" 27 ) 28 29 // PageBoundariesFromBoxList parses a list of box types. 30 func PageBoundariesFromBoxList(s string) (*model.PageBoundaries, error) { 31 return model.ParseBoxList(s) 32 } 33 34 // PageBoundaries parses a list of box definitions and assignments. 35 func PageBoundaries(s string, unit types.DisplayUnit) (*model.PageBoundaries, error) { 36 return model.ParsePageBoundaries(s, unit) 37 } 38 39 // Box parses a box definition. 40 func Box(s string, u types.DisplayUnit) (*model.Box, error) { 41 return model.ParseBox(s, u) 42 } 43 44 // Boxes returns rs's page boundaries for selected pages of rs. 45 func Boxes(rs io.ReadSeeker, selectedPages []string, conf *model.Configuration) ([]model.PageBoundaries, error) { 46 if rs == nil { 47 return nil, errors.New("pdfcpu: Boxes: missing rs") 48 } 49 50 if conf == nil { 51 conf = model.NewDefaultConfiguration() 52 } 53 conf.Cmd = model.LISTBOXES 54 55 ctx, err := ReadValidateAndOptimize(rs, conf) 56 if err != nil { 57 return nil, err 58 } 59 60 pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true, true) 61 if err != nil { 62 return nil, err 63 } 64 65 return ctx.PageBoundaries(pages) 66 } 67 68 // AddBoxes adds page boundaries for selected pages of rs and writes result to w. 69 func AddBoxes(rs io.ReadSeeker, w io.Writer, selectedPages []string, pb *model.PageBoundaries, conf *model.Configuration) error { 70 if rs == nil { 71 return errors.New("pdfcpu: AddBoxes: missing rs") 72 } 73 74 if conf == nil { 75 conf = model.NewDefaultConfiguration() 76 } 77 conf.Cmd = model.ADDBOXES 78 79 ctx, err := ReadValidateAndOptimize(rs, conf) 80 if err != nil { 81 return err 82 } 83 84 pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true, true) 85 if err != nil { 86 return err 87 } 88 89 if err = ctx.AddPageBoundaries(pages, pb); err != nil { 90 return err 91 } 92 93 return Write(ctx, w, conf) 94 } 95 96 // AddBoxesFile adds page boundaries for selected pages of inFile and writes result to outFile. 97 func AddBoxesFile(inFile, outFile string, selectedPages []string, pb *model.PageBoundaries, conf *model.Configuration) (err error) { 98 var f1, f2 *os.File 99 if log.CLIEnabled() { 100 log.CLI.Printf("adding %s for %s\n", pb, inFile) 101 } 102 103 if f1, err = os.Open(inFile); err != nil { 104 return err 105 } 106 107 tmpFile := inFile + ".tmp" 108 if outFile != "" && inFile != outFile { 109 tmpFile = outFile 110 logWritingTo(outFile) 111 } else { 112 logWritingTo(inFile) 113 } 114 115 if f2, err = os.Create(tmpFile); err != nil { 116 f1.Close() 117 return err 118 } 119 120 defer func() { 121 if err != nil { 122 f2.Close() 123 f1.Close() 124 os.Remove(tmpFile) 125 return 126 } 127 if err = f2.Close(); err != nil { 128 return 129 } 130 if err = f1.Close(); err != nil { 131 return 132 } 133 if outFile == "" || inFile == outFile { 134 err = os.Rename(tmpFile, inFile) 135 } 136 }() 137 138 return AddBoxes(f1, f2, selectedPages, pb, conf) 139 } 140 141 // RemoveBoxes removes page boundaries as specified in pb for selected pages of rs and writes result to w. 142 func RemoveBoxes(rs io.ReadSeeker, w io.Writer, selectedPages []string, pb *model.PageBoundaries, conf *model.Configuration) error { 143 if rs == nil { 144 return errors.New("pdfcpu: RemoveBoxes: missing rs") 145 } 146 147 if conf == nil { 148 conf = model.NewDefaultConfiguration() 149 } 150 conf.Cmd = model.REMOVEBOXES 151 152 ctx, err := ReadValidateAndOptimize(rs, conf) 153 if err != nil { 154 return err 155 } 156 157 pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true, true) 158 if err != nil { 159 return err 160 } 161 162 if err = ctx.RemovePageBoundaries(pages, pb); err != nil { 163 return err 164 } 165 166 return Write(ctx, w, conf) 167 } 168 169 // RemoveBoxesFile removes page boundaries as specified in pb for selected pages of inFile and writes result to outFile. 170 func RemoveBoxesFile(inFile, outFile string, selectedPages []string, pb *model.PageBoundaries, conf *model.Configuration) (err error) { 171 var f1, f2 *os.File 172 173 if log.CLIEnabled() { 174 log.CLI.Printf("removing %s for %s\n", pb, inFile) 175 } 176 177 if f1, err = os.Open(inFile); err != nil { 178 return err 179 } 180 181 tmpFile := inFile + ".tmp" 182 if outFile != "" && inFile != outFile { 183 tmpFile = outFile 184 logWritingTo(outFile) 185 } else { 186 logWritingTo(inFile) 187 } 188 189 if f2, err = os.Create(tmpFile); err != nil { 190 f1.Close() 191 return err 192 } 193 194 defer func() { 195 if err != nil { 196 f2.Close() 197 f1.Close() 198 os.Remove(tmpFile) 199 return 200 } 201 if err = f2.Close(); err != nil { 202 return 203 } 204 if err = f1.Close(); err != nil { 205 return 206 } 207 if outFile == "" || inFile == outFile { 208 err = os.Rename(tmpFile, inFile) 209 } 210 }() 211 212 return RemoveBoxes(f1, f2, selectedPages, pb, conf) 213 } 214 215 // Crop adds crop boxes for selected pages of rs and writes result to w. 216 func Crop(rs io.ReadSeeker, w io.Writer, selectedPages []string, b *model.Box, conf *model.Configuration) error { 217 if rs == nil { 218 return errors.New("pdfcpu: Crop: missing rs") 219 } 220 221 if conf == nil { 222 conf = model.NewDefaultConfiguration() 223 } 224 conf.Cmd = model.CROP 225 226 ctx, err := ReadValidateAndOptimize(rs, conf) 227 if err != nil { 228 return err 229 } 230 231 pages, err := PagesForPageSelection(ctx.PageCount, selectedPages, true, true) 232 if err != nil { 233 return err 234 } 235 236 if err = ctx.Crop(pages, b); err != nil { 237 return err 238 } 239 240 return Write(ctx, w, conf) 241 } 242 243 // CropFile adds crop boxes for selected pages of inFile and writes result to outFile. 244 func CropFile(inFile, outFile string, selectedPages []string, b *model.Box, conf *model.Configuration) (err error) { 245 var f1, f2 *os.File 246 247 if log.CLIEnabled() { 248 log.CLI.Printf("cropping %s\n", inFile) 249 } 250 251 if f1, err = os.Open(inFile); err != nil { 252 return err 253 } 254 255 tmpFile := inFile + ".tmp" 256 if outFile != "" && inFile != outFile { 257 tmpFile = outFile 258 logWritingTo(outFile) 259 } else { 260 logWritingTo(inFile) 261 } 262 263 if f2, err = os.Create(tmpFile); err != nil { 264 f1.Close() 265 return err 266 } 267 268 defer func() { 269 if err != nil { 270 f2.Close() 271 f1.Close() 272 os.Remove(tmpFile) 273 return 274 } 275 if err = f2.Close(); err != nil { 276 return 277 } 278 if err = f1.Close(); err != nil { 279 return 280 } 281 if outFile == "" || inFile == outFile { 282 err = os.Rename(tmpFile, inFile) 283 } 284 }() 285 286 if conf == nil { 287 conf = model.NewDefaultConfiguration() 288 } 289 conf.Cmd = model.CROP 290 291 return Crop(f1, f2, selectedPages, b, conf) 292 }