Skip to content

Commit

Permalink
Fix #809
Browse files Browse the repository at this point in the history
  • Loading branch information
hhrutter committed Mar 3, 2024
1 parent 5b7d844 commit d581dc1
Show file tree
Hide file tree
Showing 4 changed files with 168 additions and 57 deletions.
81 changes: 79 additions & 2 deletions pkg/cli/list.go
Expand Up @@ -21,15 +21,18 @@ import (
"encoding/json"
"fmt"
"io"
"math"
"os"
"sort"
"strconv"
"time"

"github.com/pdfcpu/pdfcpu/pkg/api"
"github.com/pdfcpu/pdfcpu/pkg/log"
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu"
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/form"
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model"
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types"
"github.com/pkg/errors"
)

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

func jsonInfo(info *pdfcpu.PDFInfo, pages types.IntSet) (map[string]model.PageBoundaries, []types.Dim) {
if len(pages) > 0 {
pbs := map[string]model.PageBoundaries{}
for i, pb := range info.PageBoundaries {
if _, found := pages[i+1]; !found {
continue
}
d := pb.CropBox().Dimensions()
if pb.Rot%180 != 0 {
d.Width, d.Height = d.Height, d.Width
}
pb.Orientation = "portrait"
if d.Landscape() {
pb.Orientation = "landscape"
}
if pb.Media != nil {
pb.Media.Rect = pb.Media.Rect.ConvertToUnit(info.Unit)
pb.Media.Rect.LL.X = math.Round(pb.Media.Rect.LL.X*100) / 100
pb.Media.Rect.LL.Y = math.Round(pb.Media.Rect.LL.Y*100) / 100
pb.Media.Rect.UR.X = math.Round(pb.Media.Rect.UR.X*100) / 100
pb.Media.Rect.UR.Y = math.Round(pb.Media.Rect.UR.Y*100) / 100
}
if pb.Crop != nil {
pb.Crop.Rect = pb.Crop.Rect.ConvertToUnit(info.Unit)
pb.Crop.Rect.LL.X = math.Round(pb.Crop.Rect.LL.X*100) / 100
pb.Crop.Rect.LL.Y = math.Round(pb.Crop.Rect.LL.Y*100) / 100
pb.Crop.Rect.UR.X = math.Round(pb.Crop.Rect.UR.X*100) / 100
pb.Crop.Rect.UR.Y = math.Round(pb.Crop.Rect.UR.Y*100) / 100
}
if pb.Trim != nil {
pb.Trim.Rect = pb.Trim.Rect.ConvertToUnit(info.Unit)
pb.Trim.Rect.LL.X = math.Round(pb.Trim.Rect.LL.X*100) / 100
pb.Trim.Rect.LL.Y = math.Round(pb.Trim.Rect.LL.Y*100) / 100
pb.Trim.Rect.UR.X = math.Round(pb.Trim.Rect.UR.X*100) / 100
pb.Trim.Rect.UR.Y = math.Round(pb.Trim.Rect.UR.Y*100) / 100
}
if pb.Bleed != nil {
pb.Bleed.Rect = pb.Bleed.Rect.ConvertToUnit(info.Unit)
pb.Bleed.Rect.LL.X = math.Round(pb.Bleed.Rect.LL.X*100) / 100
pb.Bleed.Rect.LL.Y = math.Round(pb.Bleed.Rect.LL.Y*100) / 100
pb.Bleed.Rect.UR.X = math.Round(pb.Bleed.Rect.UR.X*100) / 100
pb.Bleed.Rect.UR.Y = math.Round(pb.Bleed.Rect.UR.Y*100) / 100
}
if pb.Art != nil {
pb.Art.Rect = pb.Art.Rect.ConvertToUnit(info.Unit)
pb.Art.Rect.LL.X = math.Round(pb.Art.Rect.LL.X*100) / 100
pb.Art.Rect.LL.Y = math.Round(pb.Art.Rect.LL.Y*100) / 100
pb.Art.Rect.UR.X = math.Round(pb.Art.Rect.UR.X*100) / 100
pb.Art.Rect.UR.Y = math.Round(pb.Art.Rect.UR.Y*100) / 100
}
pbs[strconv.Itoa(i+1)] = pb
}
return pbs, nil
}

var dims []types.Dim
for k, v := range info.PageDimensions {
if v {
dc := k.ConvertToUnit(info.Unit)
dc.Width = math.Round(dc.Width*100) / 100
dc.Height = math.Round(dc.Height*100) / 100
dims = append(dims, dc)
}
}
return nil, dims
}

func listInfoFilesJSON(inFiles []string, selectedPages []string, conf *model.Configuration) ([]string, error) {
var infos []*pdfcpu.PDFInfo

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

pages, err := api.PagesForPageSelection(info.PageCount, selectedPages, false, false)
if err != nil {
return nil, err
}

info.Boundaries, info.Dimensions = jsonInfo(info, pages)

infos = append(infos, info)
}

s := struct {
Header pdfcpu.Header `json:"header"`
Infos []*pdfcpu.PDFInfo
Header pdfcpu.Header `json:"header"`
Infos []*pdfcpu.PDFInfo `json:"infos"`
}{
Header: pdfcpu.Header{Version: "pdfcpu " + model.VersionStr, Creation: time.Now().Format("2006-01-02 15:04:05 MST")},
Infos: infos,
Expand Down
72 changes: 37 additions & 35 deletions pkg/pdfcpu/info.go
Expand Up @@ -299,7 +299,7 @@ func pageInfo(info *PDFInfo, selectedPages types.IntSet) ([]string, error) {
return ss, nil
}

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

type PDFInfo struct {
FileName string `json:"source,omitempty"`
Version string `json:"version"`
PageCount int `json:"pages"`
PageBoundaries []model.PageBoundaries `json:"-"`
PageDimensions map[types.Dim]bool `json:"-"`
Title string `json:"title"`
Author string `json:"author"`
Subject string `json:"subject"`
Producer string `json:"producer"`
Creator string `json:"creator"`
CreationDate string `json:"creationDate"`
ModificationDate string `json:"modificationDate"`
PageMode string `json:"pageMode,omitempty"`
PageLayout string `json:"pageLayout,omitempty"`
ViewerPref *model.ViewerPreferences `json:"viewerPreferences,omitempty"`
Keywords []string `json:"keywords"`
Properties map[string]string `json:"properties"`
Tagged bool `json:"tagged"`
Hybrid bool `json:"hybrid"`
Linearized bool `json:"linearized"`
UsingXRefStreams bool `json:"usingXRefStreams"`
UsingObjectStreams bool `json:"usingObjectStreams"`
Watermarked bool `json:"watermarked"`
Thumbnails bool `json:"thumbnails"`
Form bool `json:"form"`
Signatures bool `json:"signatures"`
AppendOnly bool `json:"appendOnly"`
Outlines bool `json:"bookmarks"`
Names bool `json:"names"`
Encrypted bool `json:"encrypted"`
Permissions int `json:"permissions"`
Attachments []model.Attachment `json:"attachments,omitempty"`
Unit types.DisplayUnit `json:"-"`
UnitString string `json:"-"`
FileName string `json:"source,omitempty"`
Version string `json:"version"`
PageCount int `json:"pageCount"`
PageBoundaries []model.PageBoundaries `json:"-"`
Boundaries map[string]model.PageBoundaries `json:"pageBoundaries,omitempty"`
PageDimensions map[types.Dim]bool `json:"-"`
Dimensions []types.Dim `json:"pageSizes,omitempty"`
Title string `json:"title"`
Author string `json:"author"`
Subject string `json:"subject"`
Producer string `json:"producer"`
Creator string `json:"creator"`
CreationDate string `json:"creationDate"`
ModificationDate string `json:"modificationDate"`
PageMode string `json:"pageMode,omitempty"`
PageLayout string `json:"pageLayout,omitempty"`
ViewerPref *model.ViewerPreferences `json:"viewerPreferences,omitempty"`
Keywords []string `json:"keywords"`
Properties map[string]string `json:"properties"`
Tagged bool `json:"tagged"`
Hybrid bool `json:"hybrid"`
Linearized bool `json:"linearized"`
UsingXRefStreams bool `json:"usingXRefStreams"`
UsingObjectStreams bool `json:"usingObjectStreams"`
Watermarked bool `json:"watermarked"`
Thumbnails bool `json:"thumbnails"`
Form bool `json:"form"`
Signatures bool `json:"signatures"`
AppendOnly bool `json:"appendOnly"`
Outlines bool `json:"bookmarks"`
Names bool `json:"names"`
Encrypted bool `json:"encrypted"`
Permissions int `json:"permissions"`
Attachments []model.Attachment `json:"attachments,omitempty"`
Unit types.DisplayUnit `json:"-"`
UnitString string `json:"unit"`
}

func (info PDFInfo) renderKeywords(ss *[]string) error {
Expand Down
33 changes: 17 additions & 16 deletions pkg/pdfcpu/model/box.go
Expand Up @@ -31,27 +31,28 @@ import (
// Media box serves as parent box for crop box.
// Crop box serves as parent box for trim, bleed and art box.
type Box struct {
Rect *types.Rectangle // Rectangle in user space.
Inherited bool // Media box and Crop box may be inherited.
RefBox string // Use position of another box,
Rect *types.Rectangle `json:"rect"` // Rectangle in user space.
Inherited bool `json:"-"` // Media box and Crop box may be inherited.
RefBox string `json:"-"` // Use position of another box,
// Margins to parent box in points.
// Relative to parent box if 0 < x < 0.5
MLeft, MRight float64
MTop, MBot float64
MLeft, MRight float64 `json:"-"`
MTop, MBot float64 `json:"-"`
// Relative position within parent box
Dim *types.Dim // dimensions
Pos types.Anchor // position anchor within parent box, one of tl,tc,tr,l,c,r,bl,bc,br.
Dx, Dy int // anchor offset
Dim *types.Dim `json:"-"` // dimensions
Pos types.Anchor `json:"-"` // position anchor within parent box, one of tl,tc,tr,l,c,r,bl,bc,br.
Dx, Dy int `json:"-"` // anchor offset
}

// PageBoundaries represent the defined PDF page boundaries.
type PageBoundaries struct {
Media *Box
Crop *Box
Trim *Box
Bleed *Box
Art *Box
Rot int // The effective page rotation.
Media *Box `json:"mediaBox,omitempty"`
Crop *Box `json:"cropBox,omitempty"`
Trim *Box `json:"trimBox,omitempty"`
Bleed *Box `json:"bleedBox,omitempty"`
Art *Box `json:"artBox,omitempty"`
Rot int `json:"rot"` // The effective page rotation.
Orientation string `json:"orient"`
}

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

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

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

// Via margins relative to parent box.
Expand Down
39 changes: 35 additions & 4 deletions pkg/pdfcpu/types/types.go
Expand Up @@ -146,7 +146,8 @@ func (i Integer) Value() int {

// Point represents a user space location.
type Point struct {
X, Y float64
X float64 `json:"x"`
Y float64 `json:"y"`
}

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

// Rectangle represents a rectangular region in userspace.
type Rectangle struct {
LL, UR Point
LL Point `json:"ll"`
UR Point `json:"ur"`
}

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

// ToInches converts r to inches.
func (r Rectangle) ToInches() *Rectangle {
return NewRectangle(r.LL.X*userSpaceToInch, r.LL.Y*userSpaceToInch, r.UR.X*userSpaceToInch, r.UR.Y*userSpaceToInch)
}

// ToCentimetres converts r to centimetres.
func (r Rectangle) ToCentimetres() *Rectangle {
return NewRectangle(r.LL.X*userSpaceToCm, r.LL.Y*userSpaceToCm, r.UR.X*userSpaceToCm, r.UR.Y*userSpaceToCm)
}

// ToMillimetres converts r to millimetres.
func (r Rectangle) ToMillimetres() *Rectangle {
return NewRectangle(r.LL.X*userSpaceToMm, r.LL.Y*userSpaceToMm, r.UR.X*userSpaceToMm, r.UR.Y*userSpaceToMm)
}

// ConvertToUnit converts r to unit.
func (r *Rectangle) ConvertToUnit(unit DisplayUnit) *Rectangle {
switch unit {
case INCHES:
return r.ToInches()
case CENTIMETRES:
return r.ToCentimetres()
case MILLIMETRES:
return r.ToMillimetres()
}
return r
}

func (r Rectangle) formatToInches() string {
return fmt.Sprintf("(%3.2f, %3.2f, %3.2f, %3.2f) w=%.2f h=%.2f ar=%.2f",
r.LL.X*userSpaceToInch,
Expand Down Expand Up @@ -524,7 +554,8 @@ func ToUserSpace(f float64, unit DisplayUnit) float64 {
// like a PDF page, a sheet of paper or an image grid
// in user space, inches, centimetres or millimetres.
type Dim struct {
Width, Height float64
Width float64 `json:"width"`
Height float64 `json:"height"`
}

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

// ToMillimetres converts d to centimetres.
// ToMillimetres converts d to millimetres.
func (d Dim) ToMillimetres() Dim {
return Dim{d.Width * userSpaceToMm, d.Height * userSpaceToMm}
}
Expand Down

0 comments on commit d581dc1

Please sign in to comment.