Skip to content

Commit d581dc1

Browse files
committed
Fix #809
1 parent 5b7d844 commit d581dc1

File tree

4 files changed

+168
-57
lines changed

4 files changed

+168
-57
lines changed

pkg/cli/list.go

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,18 @@ import (
2121
"encoding/json"
2222
"fmt"
2323
"io"
24+
"math"
2425
"os"
2526
"sort"
27+
"strconv"
2628
"time"
2729

2830
"github.com/pdfcpu/pdfcpu/pkg/api"
2931
"github.com/pdfcpu/pdfcpu/pkg/log"
3032
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu"
3133
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/form"
3234
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model"
35+
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types"
3336
"github.com/pkg/errors"
3437
)
3538

@@ -282,6 +285,73 @@ func ListInfoFile(inFile string, selectedPages []string, conf *model.Configurati
282285
return append([]string{inFile + ":"}, ss...), err
283286
}
284287

288+
func jsonInfo(info *pdfcpu.PDFInfo, pages types.IntSet) (map[string]model.PageBoundaries, []types.Dim) {
289+
if len(pages) > 0 {
290+
pbs := map[string]model.PageBoundaries{}
291+
for i, pb := range info.PageBoundaries {
292+
if _, found := pages[i+1]; !found {
293+
continue
294+
}
295+
d := pb.CropBox().Dimensions()
296+
if pb.Rot%180 != 0 {
297+
d.Width, d.Height = d.Height, d.Width
298+
}
299+
pb.Orientation = "portrait"
300+
if d.Landscape() {
301+
pb.Orientation = "landscape"
302+
}
303+
if pb.Media != nil {
304+
pb.Media.Rect = pb.Media.Rect.ConvertToUnit(info.Unit)
305+
pb.Media.Rect.LL.X = math.Round(pb.Media.Rect.LL.X*100) / 100
306+
pb.Media.Rect.LL.Y = math.Round(pb.Media.Rect.LL.Y*100) / 100
307+
pb.Media.Rect.UR.X = math.Round(pb.Media.Rect.UR.X*100) / 100
308+
pb.Media.Rect.UR.Y = math.Round(pb.Media.Rect.UR.Y*100) / 100
309+
}
310+
if pb.Crop != nil {
311+
pb.Crop.Rect = pb.Crop.Rect.ConvertToUnit(info.Unit)
312+
pb.Crop.Rect.LL.X = math.Round(pb.Crop.Rect.LL.X*100) / 100
313+
pb.Crop.Rect.LL.Y = math.Round(pb.Crop.Rect.LL.Y*100) / 100
314+
pb.Crop.Rect.UR.X = math.Round(pb.Crop.Rect.UR.X*100) / 100
315+
pb.Crop.Rect.UR.Y = math.Round(pb.Crop.Rect.UR.Y*100) / 100
316+
}
317+
if pb.Trim != nil {
318+
pb.Trim.Rect = pb.Trim.Rect.ConvertToUnit(info.Unit)
319+
pb.Trim.Rect.LL.X = math.Round(pb.Trim.Rect.LL.X*100) / 100
320+
pb.Trim.Rect.LL.Y = math.Round(pb.Trim.Rect.LL.Y*100) / 100
321+
pb.Trim.Rect.UR.X = math.Round(pb.Trim.Rect.UR.X*100) / 100
322+
pb.Trim.Rect.UR.Y = math.Round(pb.Trim.Rect.UR.Y*100) / 100
323+
}
324+
if pb.Bleed != nil {
325+
pb.Bleed.Rect = pb.Bleed.Rect.ConvertToUnit(info.Unit)
326+
pb.Bleed.Rect.LL.X = math.Round(pb.Bleed.Rect.LL.X*100) / 100
327+
pb.Bleed.Rect.LL.Y = math.Round(pb.Bleed.Rect.LL.Y*100) / 100
328+
pb.Bleed.Rect.UR.X = math.Round(pb.Bleed.Rect.UR.X*100) / 100
329+
pb.Bleed.Rect.UR.Y = math.Round(pb.Bleed.Rect.UR.Y*100) / 100
330+
}
331+
if pb.Art != nil {
332+
pb.Art.Rect = pb.Art.Rect.ConvertToUnit(info.Unit)
333+
pb.Art.Rect.LL.X = math.Round(pb.Art.Rect.LL.X*100) / 100
334+
pb.Art.Rect.LL.Y = math.Round(pb.Art.Rect.LL.Y*100) / 100
335+
pb.Art.Rect.UR.X = math.Round(pb.Art.Rect.UR.X*100) / 100
336+
pb.Art.Rect.UR.Y = math.Round(pb.Art.Rect.UR.Y*100) / 100
337+
}
338+
pbs[strconv.Itoa(i+1)] = pb
339+
}
340+
return pbs, nil
341+
}
342+
343+
var dims []types.Dim
344+
for k, v := range info.PageDimensions {
345+
if v {
346+
dc := k.ConvertToUnit(info.Unit)
347+
dc.Width = math.Round(dc.Width*100) / 100
348+
dc.Height = math.Round(dc.Height*100) / 100
349+
dims = append(dims, dc)
350+
}
351+
}
352+
return nil, dims
353+
}
354+
285355
func listInfoFilesJSON(inFiles []string, selectedPages []string, conf *model.Configuration) ([]string, error) {
286356
var infos []*pdfcpu.PDFInfo
287357

@@ -298,12 +368,19 @@ func listInfoFilesJSON(inFiles []string, selectedPages []string, conf *model.Con
298368
return nil, err
299369
}
300370

371+
pages, err := api.PagesForPageSelection(info.PageCount, selectedPages, false, false)
372+
if err != nil {
373+
return nil, err
374+
}
375+
376+
info.Boundaries, info.Dimensions = jsonInfo(info, pages)
377+
301378
infos = append(infos, info)
302379
}
303380

304381
s := struct {
305-
Header pdfcpu.Header `json:"header"`
306-
Infos []*pdfcpu.PDFInfo
382+
Header pdfcpu.Header `json:"header"`
383+
Infos []*pdfcpu.PDFInfo `json:"infos"`
307384
}{
308385
Header: pdfcpu.Header{Version: "pdfcpu " + model.VersionStr, Creation: time.Now().Format("2006-01-02 15:04:05 MST")},
309386
Infos: infos,

pkg/pdfcpu/info.go

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ func pageInfo(info *PDFInfo, selectedPages types.IntSet) ([]string, error) {
299299
return ss, nil
300300
}
301301

302-
s := "Page size:"
302+
s := "Page sizes:"
303303
for d := range info.PageDimensions {
304304
dc := d.ConvertToUnit(info.Unit)
305305
ss = append(ss, fmt.Sprintf("%21s %.2f x %.2f %s", s, dc.Width, dc.Height, info.UnitString))
@@ -309,40 +309,42 @@ func pageInfo(info *PDFInfo, selectedPages types.IntSet) ([]string, error) {
309309
}
310310

311311
type PDFInfo struct {
312-
FileName string `json:"source,omitempty"`
313-
Version string `json:"version"`
314-
PageCount int `json:"pages"`
315-
PageBoundaries []model.PageBoundaries `json:"-"`
316-
PageDimensions map[types.Dim]bool `json:"-"`
317-
Title string `json:"title"`
318-
Author string `json:"author"`
319-
Subject string `json:"subject"`
320-
Producer string `json:"producer"`
321-
Creator string `json:"creator"`
322-
CreationDate string `json:"creationDate"`
323-
ModificationDate string `json:"modificationDate"`
324-
PageMode string `json:"pageMode,omitempty"`
325-
PageLayout string `json:"pageLayout,omitempty"`
326-
ViewerPref *model.ViewerPreferences `json:"viewerPreferences,omitempty"`
327-
Keywords []string `json:"keywords"`
328-
Properties map[string]string `json:"properties"`
329-
Tagged bool `json:"tagged"`
330-
Hybrid bool `json:"hybrid"`
331-
Linearized bool `json:"linearized"`
332-
UsingXRefStreams bool `json:"usingXRefStreams"`
333-
UsingObjectStreams bool `json:"usingObjectStreams"`
334-
Watermarked bool `json:"watermarked"`
335-
Thumbnails bool `json:"thumbnails"`
336-
Form bool `json:"form"`
337-
Signatures bool `json:"signatures"`
338-
AppendOnly bool `json:"appendOnly"`
339-
Outlines bool `json:"bookmarks"`
340-
Names bool `json:"names"`
341-
Encrypted bool `json:"encrypted"`
342-
Permissions int `json:"permissions"`
343-
Attachments []model.Attachment `json:"attachments,omitempty"`
344-
Unit types.DisplayUnit `json:"-"`
345-
UnitString string `json:"-"`
312+
FileName string `json:"source,omitempty"`
313+
Version string `json:"version"`
314+
PageCount int `json:"pageCount"`
315+
PageBoundaries []model.PageBoundaries `json:"-"`
316+
Boundaries map[string]model.PageBoundaries `json:"pageBoundaries,omitempty"`
317+
PageDimensions map[types.Dim]bool `json:"-"`
318+
Dimensions []types.Dim `json:"pageSizes,omitempty"`
319+
Title string `json:"title"`
320+
Author string `json:"author"`
321+
Subject string `json:"subject"`
322+
Producer string `json:"producer"`
323+
Creator string `json:"creator"`
324+
CreationDate string `json:"creationDate"`
325+
ModificationDate string `json:"modificationDate"`
326+
PageMode string `json:"pageMode,omitempty"`
327+
PageLayout string `json:"pageLayout,omitempty"`
328+
ViewerPref *model.ViewerPreferences `json:"viewerPreferences,omitempty"`
329+
Keywords []string `json:"keywords"`
330+
Properties map[string]string `json:"properties"`
331+
Tagged bool `json:"tagged"`
332+
Hybrid bool `json:"hybrid"`
333+
Linearized bool `json:"linearized"`
334+
UsingXRefStreams bool `json:"usingXRefStreams"`
335+
UsingObjectStreams bool `json:"usingObjectStreams"`
336+
Watermarked bool `json:"watermarked"`
337+
Thumbnails bool `json:"thumbnails"`
338+
Form bool `json:"form"`
339+
Signatures bool `json:"signatures"`
340+
AppendOnly bool `json:"appendOnly"`
341+
Outlines bool `json:"bookmarks"`
342+
Names bool `json:"names"`
343+
Encrypted bool `json:"encrypted"`
344+
Permissions int `json:"permissions"`
345+
Attachments []model.Attachment `json:"attachments,omitempty"`
346+
Unit types.DisplayUnit `json:"-"`
347+
UnitString string `json:"unit"`
346348
}
347349

348350
func (info PDFInfo) renderKeywords(ss *[]string) error {

pkg/pdfcpu/model/box.go

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,27 +31,28 @@ import (
3131
// Media box serves as parent box for crop box.
3232
// Crop box serves as parent box for trim, bleed and art box.
3333
type Box struct {
34-
Rect *types.Rectangle // Rectangle in user space.
35-
Inherited bool // Media box and Crop box may be inherited.
36-
RefBox string // Use position of another box,
34+
Rect *types.Rectangle `json:"rect"` // Rectangle in user space.
35+
Inherited bool `json:"-"` // Media box and Crop box may be inherited.
36+
RefBox string `json:"-"` // Use position of another box,
3737
// Margins to parent box in points.
3838
// Relative to parent box if 0 < x < 0.5
39-
MLeft, MRight float64
40-
MTop, MBot float64
39+
MLeft, MRight float64 `json:"-"`
40+
MTop, MBot float64 `json:"-"`
4141
// Relative position within parent box
42-
Dim *types.Dim // dimensions
43-
Pos types.Anchor // position anchor within parent box, one of tl,tc,tr,l,c,r,bl,bc,br.
44-
Dx, Dy int // anchor offset
42+
Dim *types.Dim `json:"-"` // dimensions
43+
Pos types.Anchor `json:"-"` // position anchor within parent box, one of tl,tc,tr,l,c,r,bl,bc,br.
44+
Dx, Dy int `json:"-"` // anchor offset
4545
}
4646

4747
// PageBoundaries represent the defined PDF page boundaries.
4848
type PageBoundaries struct {
49-
Media *Box
50-
Crop *Box
51-
Trim *Box
52-
Bleed *Box
53-
Art *Box
54-
Rot int // The effective page rotation.
49+
Media *Box `json:"mediaBox,omitempty"`
50+
Crop *Box `json:"cropBox,omitempty"`
51+
Trim *Box `json:"trimBox,omitempty"`
52+
Bleed *Box `json:"bleedBox,omitempty"`
53+
Art *Box `json:"artBox,omitempty"`
54+
Rot int `json:"rot"` // The effective page rotation.
55+
Orientation string `json:"orient"`
5556
}
5657

5758
// SelectAll selects all page boundaries.
@@ -727,7 +728,7 @@ func parseBoxDim(s string, b *Box, u types.DisplayUnit) error {
727728
return nil
728729
}
729730

730-
func parseBoxByPosWithinParent(s string, ss []string, u types.DisplayUnit) (*Box, error) {
731+
func parseBoxByPosWithinParent(ss []string, u types.DisplayUnit) (*Box, error) {
731732
b := &Box{Pos: types.Center}
732733
for _, s := range ss {
733734

@@ -827,7 +828,7 @@ func ParseBox(s string, u types.DisplayUnit) (*Box, error) {
827828
return nil, errors.Errorf("pdfcpu: invalid box definition: %s", s)
828829
}
829830
if len(ss) > 1 || strings.HasPrefix(ss[0], "dim") {
830-
return parseBoxByPosWithinParent(s, ss, u)
831+
return parseBoxByPosWithinParent(ss, u)
831832
}
832833

833834
// Via margins relative to parent box.

pkg/pdfcpu/types/types.go

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ func (i Integer) Value() int {
146146

147147
// Point represents a user space location.
148148
type Point struct {
149-
X, Y float64
149+
X float64 `json:"x"`
150+
Y float64 `json:"y"`
150151
}
151152

152153
// Translate modifies p's coordinates.
@@ -161,7 +162,8 @@ func (p Point) String() string {
161162

162163
// Rectangle represents a rectangular region in userspace.
163164
type Rectangle struct {
164-
LL, UR Point
165+
LL Point `json:"ll"`
166+
UR Point `json:"ur"`
165167
}
166168

167169
// NewRectangle returns a new rectangle for given corner coordinates.
@@ -274,6 +276,34 @@ func (r Rectangle) CroppedCopy(margin float64) *Rectangle {
274276
return NewRectangle(r.LL.X+margin, r.LL.Y+margin, r.UR.X-margin, r.UR.Y-margin)
275277
}
276278

279+
// ToInches converts r to inches.
280+
func (r Rectangle) ToInches() *Rectangle {
281+
return NewRectangle(r.LL.X*userSpaceToInch, r.LL.Y*userSpaceToInch, r.UR.X*userSpaceToInch, r.UR.Y*userSpaceToInch)
282+
}
283+
284+
// ToCentimetres converts r to centimetres.
285+
func (r Rectangle) ToCentimetres() *Rectangle {
286+
return NewRectangle(r.LL.X*userSpaceToCm, r.LL.Y*userSpaceToCm, r.UR.X*userSpaceToCm, r.UR.Y*userSpaceToCm)
287+
}
288+
289+
// ToMillimetres converts r to millimetres.
290+
func (r Rectangle) ToMillimetres() *Rectangle {
291+
return NewRectangle(r.LL.X*userSpaceToMm, r.LL.Y*userSpaceToMm, r.UR.X*userSpaceToMm, r.UR.Y*userSpaceToMm)
292+
}
293+
294+
// ConvertToUnit converts r to unit.
295+
func (r *Rectangle) ConvertToUnit(unit DisplayUnit) *Rectangle {
296+
switch unit {
297+
case INCHES:
298+
return r.ToInches()
299+
case CENTIMETRES:
300+
return r.ToCentimetres()
301+
case MILLIMETRES:
302+
return r.ToMillimetres()
303+
}
304+
return r
305+
}
306+
277307
func (r Rectangle) formatToInches() string {
278308
return fmt.Sprintf("(%3.2f, %3.2f, %3.2f, %3.2f) w=%.2f h=%.2f ar=%.2f",
279309
r.LL.X*userSpaceToInch,
@@ -524,7 +554,8 @@ func ToUserSpace(f float64, unit DisplayUnit) float64 {
524554
// like a PDF page, a sheet of paper or an image grid
525555
// in user space, inches, centimetres or millimetres.
526556
type Dim struct {
527-
Width, Height float64
557+
Width float64 `json:"width"`
558+
Height float64 `json:"height"`
528559
}
529560

530561
// ToInches converts d to inches.
@@ -537,7 +568,7 @@ func (d Dim) ToCentimetres() Dim {
537568
return Dim{d.Width * userSpaceToCm, d.Height * userSpaceToCm}
538569
}
539570

540-
// ToMillimetres converts d to centimetres.
571+
// ToMillimetres converts d to millimetres.
541572
func (d Dim) ToMillimetres() Dim {
542573
return Dim{d.Width * userSpaceToMm, d.Height * userSpaceToMm}
543574
}

0 commit comments

Comments
 (0)