2 Commits

Author SHA1 Message Date
Adrian Zürcher
aafa89a703 uncomment function 2026-01-01 11:01:42 +01:00
Adrian Zürcher
ef0778c8b3 some improvments 2026-01-01 11:00:23 +01:00
20 changed files with 297 additions and 377 deletions

View File

@@ -19,22 +19,22 @@ type Logger interface {
// Dummy Logger does nothing. // Dummy Logger does nothing.
type DummyLogger struct{} type DummyLogger struct{}
func (this DummyLogger) Error(format string, args ...any) { func (DummyLogger) Error(format string, args ...any) {
} }
func (this DummyLogger) Warning(format string, args ...any) { func (DummyLogger) Warning(format string, args ...any) {
} }
func (this DummyLogger) Notice(format string, args ...any) { func (DummyLogger) Notice(format string, args ...any) {
} }
func (this DummyLogger) Info(format string, args ...any) { func (DummyLogger) Info(format string, args ...any) {
} }
func (this DummyLogger) Debug(format string, args ...any) { func (DummyLogger) Debug(format string, args ...any) {
} }
func (this DummyLogger) Trace(format string, args ...any) { func (DummyLogger) Trace(format string, args ...any) {
} }
// Simple Console Logger that the tests use. // Simple Console Logger that the tests use.
@@ -59,45 +59,39 @@ func NewConsoleLogger(logLevel LogLevel) *ConsoleLogger {
return &logger return &logger
} }
func (this ConsoleLogger) Error(format string, args ...any) { func (cL ConsoleLogger) Error(format string, args ...any) {
if this.LogLevel >= LogLevelError { if cL.LogLevel >= LogLevelError {
prefix := "[ERROR] " cL.output(os.Stdout, "[ERROR] ", format, args...)
this.output(os.Stdout, prefix, format, args...)
} }
} }
func (this ConsoleLogger) Warning(format string, args ...any) { func (cL ConsoleLogger) Warning(format string, args ...any) {
if this.LogLevel >= LogLevelWarning { if cL.LogLevel >= LogLevelWarning {
prefix := "[WARNING] " cL.output(os.Stdout, "[WARNING] ", format, args...)
this.output(os.Stdout, prefix, format, args...)
} }
} }
func (this ConsoleLogger) Notice(format string, args ...any) { func (cL ConsoleLogger) Notice(format string, args ...any) {
if this.LogLevel >= LogLevelNotice { if cL.LogLevel >= LogLevelNotice {
prefix := "[NOTICE] " cL.output(os.Stdout, "[NOTICE] ", format, args...)
this.output(os.Stdout, prefix, format, args...)
} }
} }
func (this ConsoleLogger) Info(format string, args ...any) { func (cL ConsoleLogger) Info(format string, args ...any) {
if this.LogLevel >= LogLevelInfo { if cL.LogLevel >= LogLevelInfo {
prefix := "[INFO] " cL.output(os.Stdout, "[INFO] ", format, args...)
this.output(os.Stdout, prefix, format, args...)
} }
} }
func (this ConsoleLogger) Debug(format string, args ...any) { func (cL ConsoleLogger) Debug(format string, args ...any) {
if this.LogLevel >= LogLevelDebug { if cL.LogLevel >= LogLevelDebug {
prefix := "[DEBUG] " cL.output(os.Stdout, "[DEBUG] ", format, args...)
this.output(os.Stdout, prefix, format, args...)
} }
} }
func (this ConsoleLogger) Trace(format string, args ...any) { func (cL ConsoleLogger) Trace(format string, args ...any) {
if this.LogLevel >= LogLevelTrace { if cL.LogLevel >= LogLevelTrace {
prefix := "[TRACE] " cL.output(os.Stdout, "[TRACE] ", format, args...)
this.output(os.Stdout, prefix, format, args...)
} }
} }
@@ -108,7 +102,7 @@ func SetLogger(logger Logger) {
} }
// output writes `format`, `args` log message prefixed by the source file name, line and `prefix` // output writes `format`, `args` log message prefixed by the source file name, line and `prefix`
func (this ConsoleLogger) output(f *os.File, prefix string, format string, args ...any) { func (ConsoleLogger) output(f *os.File, prefix string, format string, args ...any) {
_, file, line, ok := runtime.Caller(3) _, file, line, ok := runtime.Caller(3)
if !ok { if !ok {
file = "???" file = "???"

View File

@@ -1,11 +0,0 @@
package common
import (
"time"
)
const timeFormat = "2 January 2006 at 15:04"
func UtcTimeFormat(t time.Time) string {
return t.Format(timeFormat) + " UTC"
}

View File

@@ -1,17 +0,0 @@
// Package common contains common properties used by the subpackages.
package common
import (
"time"
)
const releaseYear = 2018
const releaseMonth = 11
const releaseDay = 17
const releaseHour = 11
const releaseMin = 30
// Holds version information, when bumping this make sure to bump the released at stamp also.
const Version = "2.2.0"
var ReleasedAt = time.Date(releaseYear, releaseMonth, releaseDay, releaseHour, releaseMin, 0, 0, time.UTC)

View File

@@ -3,6 +3,7 @@ package contentstream
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"strings"
"gitea.tecamino.com/paadi/pdfmerge/internal/pdf/core" "gitea.tecamino.com/paadi/pdfmerge/internal/pdf/core"
) )
@@ -111,7 +112,7 @@ func (s *ContentStreamParser) ExtractText() (string, error) {
} }
inText := false inText := false
xPos, yPos := float64(-1), float64(-1) xPos, yPos := float64(-1), float64(-1)
txt := "" var txt strings.Builder
for _, op := range *operations { for _, op := range *operations {
switch op.Operand { switch op.Operand {
case "BT": case "BT":
@@ -122,7 +123,7 @@ func (s *ContentStreamParser) ExtractText() (string, error) {
if op.Operand == "Td" || op.Operand == "TD" || op.Operand == "T*" { if op.Operand == "Td" || op.Operand == "TD" || op.Operand == "T*" {
// Move to next line... // Move to next line...
txt += "\n" txt.WriteString("\n")
} }
if op.Operand == "Tm" { if op.Operand == "Tm" {
if len(op.Params) != 6 { if len(op.Params) != 6 {
@@ -147,7 +148,7 @@ func (s *ContentStreamParser) ExtractText() (string, error) {
if yPos == -1 { if yPos == -1 {
yPos = float64(*yfloat) yPos = float64(*yfloat)
} else if yPos > float64(*yfloat) { } else if yPos > float64(*yfloat) {
txt += "\n" txt.WriteString("\n")
xPos = float64(*xfloat) xPos = float64(*xfloat)
yPos = float64(*yfloat) yPos = float64(*yfloat)
continue continue
@@ -155,7 +156,7 @@ func (s *ContentStreamParser) ExtractText() (string, error) {
if xPos == -1 { if xPos == -1 {
xPos = float64(*xfloat) xPos = float64(*xfloat)
} else if xPos < float64(*xfloat) { } else if xPos < float64(*xfloat) {
txt += "\t" txt.WriteString("\t")
xPos = float64(*xfloat) xPos = float64(*xfloat)
} }
} }
@@ -170,14 +171,14 @@ func (s *ContentStreamParser) ExtractText() (string, error) {
for _, obj := range *paramList { for _, obj := range *paramList {
switch v := obj.(type) { switch v := obj.(type) {
case *core.PdfObjectString: case *core.PdfObjectString:
txt += string(*v) txt.WriteString(string(*v))
case *core.PdfObjectFloat: case *core.PdfObjectFloat:
if *v < -100 { if *v < -100 {
txt += " " txt.WriteString(" ")
} }
case *core.PdfObjectInteger: case *core.PdfObjectInteger:
if *v < -100 { if *v < -100 {
txt += " " txt.WriteString(" ")
} }
} }
} }
@@ -189,9 +190,9 @@ func (s *ContentStreamParser) ExtractText() (string, error) {
if !ok { if !ok {
return "", fmt.Errorf("invalid parameter type, not string (%T)", op.Params[0]) return "", fmt.Errorf("invalid parameter type, not string (%T)", op.Params[0])
} }
txt += string(*param) txt.WriteString(string(*param))
} }
} }
return txt, nil return txt.String(), nil
} }

View File

@@ -89,9 +89,9 @@ func NewCubicBezierPath() CubicBezierPath {
return bpath return bpath
} }
func (this CubicBezierPath) AppendCurve(curve CubicBezierCurve) CubicBezierPath { func (c CubicBezierPath) AppendCurve(curve CubicBezierCurve) CubicBezierPath {
this.Curves = append(this.Curves, curve) c.Curves = append(c.Curves, curve)
return this return c
} }
func (bpath CubicBezierPath) Copy() CubicBezierPath { func (bpath CubicBezierPath) Copy() CubicBezierPath {

View File

@@ -11,36 +11,36 @@ func NewPath() Path {
return path return path
} }
func (this Path) AppendPoint(point Point) Path { func (p Path) AppendPoint(point Point) Path {
this.Points = append(this.Points, point) p.Points = append(p.Points, point)
return this return p
} }
func (this Path) RemovePoint(number int) Path { func (p Path) RemovePoint(number int) Path {
if number < 1 || number > len(this.Points) { if number < 1 || number > len(p.Points) {
return this return p
} }
idx := number - 1 idx := number - 1
this.Points = append(this.Points[:idx], this.Points[idx+1:]...) p.Points = append(p.Points[:idx], p.Points[idx+1:]...)
return this return p
} }
func (this Path) Length() int { func (p Path) Length() int {
return len(this.Points) return len(p.Points)
} }
func (this Path) GetPointNumber(number int) Point { func (p Path) GetPointNumber(number int) Point {
if number < 1 || number > len(this.Points) { if number < 1 || number > len(p.Points) {
return Point{} return Point{}
} }
return this.Points[number-1] return p.Points[number-1]
} }
func (path Path) Copy() Path { func (p Path) Copy() Path {
pathcopy := Path{} pathcopy := Path{}
pathcopy.Points = []Point{} pathcopy.Points = []Point{}
for _, p := range path.Points { for _, p := range p.Points {
pathcopy.Points = append(pathcopy.Points, p) pathcopy.Points = append(pathcopy.Points, p)
} }
return pathcopy return pathcopy

View File

@@ -21,10 +21,10 @@ func (p Point) Add(dx, dy float64) Point {
} }
// Add vector to a point. // Add vector to a point.
func (this Point) AddVector(v Vector) Point { func (p Point) AddVector(v Vector) Point {
this.X += v.Dx p.X += v.Dx
this.Y += v.Dy p.Y += v.Dy
return this return p
} }
func (p Point) String() string { func (p Point) String() string {

View File

@@ -43,13 +43,13 @@ func (v Vector) Rotate(phi float64) Vector {
} }
// Change the sign of the vector: -vector. // Change the sign of the vector: -vector.
func (this Vector) Flip() Vector { func (v Vector) Flip() Vector {
mag := this.Magnitude() mag := v.Magnitude()
theta := this.GetPolarAngle() theta := v.GetPolarAngle()
this.Dx = mag * math.Cos(theta+math.Pi) v.Dx = mag * math.Cos(theta+math.Pi)
this.Dy = mag * math.Sin(theta+math.Pi) v.Dy = mag * math.Sin(theta+math.Pi)
return this return v
} }
func (v Vector) FlipY() Vector { func (v Vector) FlipY() Vector {
@@ -62,19 +62,19 @@ func (v Vector) FlipX() Vector {
return v return v
} }
func (this Vector) Scale(factor float64) Vector { func (v Vector) Scale(factor float64) Vector {
mag := this.Magnitude() mag := v.Magnitude()
theta := this.GetPolarAngle() theta := v.GetPolarAngle()
this.Dx = factor * mag * math.Cos(theta) v.Dx = factor * mag * math.Cos(theta)
this.Dy = factor * mag * math.Sin(theta) v.Dy = factor * mag * math.Sin(theta)
return this return v
} }
func (this Vector) Magnitude() float64 { func (v Vector) Magnitude() float64 {
return math.Sqrt(math.Pow(this.Dx, 2.0) + math.Pow(this.Dy, 2.0)) return math.Sqrt(math.Pow(v.Dx, 2.0) + math.Pow(v.Dy, 2.0))
} }
func (this Vector) GetPolarAngle() float64 { func (v Vector) GetPolarAngle() float64 {
return math.Atan2(this.Dy, this.Dx) return math.Atan2(v.Dy, v.Dx)
} }

View File

@@ -10,21 +10,18 @@ import (
"gitea.tecamino.com/paadi/pdfmerge/internal/pdf/common" "gitea.tecamino.com/paadi/pdfmerge/internal/pdf/common"
) )
// TODO (v3): Create a new type xrefType which can be an integer and can be used for improved type checking.
// TODO (v3): Unexport these constants and rename with camelCase.
const ( const (
// XREF_TABLE_ENTRY indicates a normal xref table entry. // xRefTableEntry indicates a normal xref table entry.
XREF_TABLE_ENTRY = iota xRefTableEntry = iota
// XREF_OBJECT_STREAM indicates an xref entry in an xref object stream. // xRefObjectStream indicates an xref entry in an xref object stream.
XREF_OBJECT_STREAM = iota xRefObjectStream = iota
) )
// XrefObject defines a cross reference entry which is a map between object number (with generation number) and the // XrefObject defines a cross reference entry which is a map between object number (with generation number) and the
// location of the actual object, either as a file offset (xref table entry), or as a location within an xref // location of the actual object, either as a file offset (xref table entry), or as a location within an xref
// stream object (xref object stream). // stream object (xref object stream).
// TODO (v3): Unexport. type xRefObject struct {
type XrefObject struct {
xtype int xtype int
objectNumber int objectNumber int
generation int generation int
@@ -36,32 +33,28 @@ type XrefObject struct {
} }
// XrefTable is a map between object number and corresponding XrefObject. // XrefTable is a map between object number and corresponding XrefObject.
// TODO (v3): Unexport. type xRefTable map[int]xRefObject
// TODO: Consider changing to a slice, so can maintain the object order without sorting when analyzing.
type XrefTable map[int]XrefObject
// ObjectStream represents an object stream's information which can contain multiple indirect objects. // ObjectStream represents an object stream's information which can contain multiple indirect objects.
// The information specifies the number of objects and has information about offset locations for // The information specifies the number of objects and has information about offset locations for
// each object. // each object.
// TODO (v3): Unexport. type objectStream struct {
type ObjectStream struct { n int
N int // TODO (v3): Unexport.
ds []byte ds []byte
offsets map[int]int64 offsets map[int]int64
} }
// ObjectStreams defines a map between object numbers (object streams only) and underlying ObjectStream information. // ObjectStreams defines a map between object numbers (object streams only) and underlying ObjectStream information.
type ObjectStreams map[int]ObjectStream type ObjectStreams map[int]objectStream
// ObjectCache defines a map between object numbers and corresponding PdfObject. Serves as a cache for PdfObjects that // ObjectCache defines a map between object numbers and corresponding PdfObject. Serves as a cache for PdfObjects that
// have already been parsed. // have already been parsed.
// TODO (v3): Unexport. type objectCache map[int]PdfObject
type ObjectCache map[int]PdfObject
// Get an object from an object stream. // Get an object from an object stream.
func (parser *PdfParser) lookupObjectViaOS(sobjNumber int, objNum int) (PdfObject, error) { func (parser *PdfParser) lookupObjectViaOS(sobjNumber int, objNum int) (PdfObject, error) {
var bufReader *bytes.Reader var bufReader *bytes.Reader
var objstm ObjectStream var objstm objectStream
var cached bool var cached bool
objstm, cached = parser.objstms[sobjNumber] objstm, cached = parser.objstms[sobjNumber]
@@ -149,7 +142,7 @@ func (parser *PdfParser) lookupObjectViaOS(sobjNumber int, objNum int) (PdfObjec
offsets[int(*onum)] = int64(*firstOffset + *offset) offsets[int(*onum)] = int64(*firstOffset + *offset)
} }
objstm = ObjectStream{N: int(*N), ds: ds, offsets: offsets} objstm = objectStream{n: int(*N), ds: ds, offsets: offsets}
parser.objstms[sobjNumber] = objstm parser.objstms[sobjNumber] = objstm
} else { } else {
// Temporarily change the reader object to this decoded buffer. // Temporarily change the reader object to this decoded buffer.
@@ -246,7 +239,7 @@ func (parser *PdfParser) lookupByNumber(objNumber int, attemptRepairs bool) (Pdf
common.Log.Trace("Lookup obj number %d", objNumber) common.Log.Trace("Lookup obj number %d", objNumber)
switch xref.xtype { switch xref.xtype {
case XREF_TABLE_ENTRY: case xRefTableEntry:
common.Log.Trace("xrefobj obj num %d", xref.objectNumber) common.Log.Trace("xrefobj obj num %d", xref.objectNumber)
common.Log.Trace("xrefobj gen %d", xref.generation) common.Log.Trace("xrefobj gen %d", xref.generation)
common.Log.Trace("xrefobj offset %d", xref.offset) common.Log.Trace("xrefobj offset %d", xref.offset)
@@ -283,7 +276,7 @@ func (parser *PdfParser) lookupByNumber(objNumber int, attemptRepairs bool) (Pdf
return nil, false, err return nil, false, err
} }
// Empty the cache. // Empty the cache.
parser.ObjCache = ObjectCache{} parser.ObjCache = objectCache{}
// Try looking up again and return. // Try looking up again and return.
return parser.lookupByNumberWrapper(objNumber, false) return parser.lookupByNumberWrapper(objNumber, false)
} }
@@ -292,7 +285,7 @@ func (parser *PdfParser) lookupByNumber(objNumber int, attemptRepairs bool) (Pdf
common.Log.Trace("Returning obj") common.Log.Trace("Returning obj")
parser.ObjCache[objNumber] = obj parser.ObjCache[objNumber] = obj
return obj, false, nil return obj, false, nil
case XREF_OBJECT_STREAM: case xRefObjectStream:
common.Log.Trace("xref from object stream!") common.Log.Trace("xref from object stream!")
common.Log.Trace(">Load via OS!") common.Log.Trace(">Load via OS!")
common.Log.Trace("Object stream available in object %d/%d", xref.osObjNumber, xref.osObjIndex) common.Log.Trace("Object stream available in object %d/%d", xref.osObjNumber, xref.osObjIndex)
@@ -361,7 +354,7 @@ func (parser *PdfParser) Trace(obj PdfObject) (PdfObject, error) {
return o, nil return o, nil
} }
func printXrefTable(xrefTable XrefTable) { func printXrefTable(xrefTable xRefTable) {
common.Log.Debug("=X=X=X=") common.Log.Debug("=X=X=X=")
common.Log.Debug("Xref table:") common.Log.Debug("Xref table:")
i := 0 i := 0

View File

@@ -35,10 +35,10 @@ type PdfParser struct {
rs io.ReadSeeker rs io.ReadSeeker
reader *bufio.Reader reader *bufio.Reader
fileSize int64 fileSize int64
xrefs XrefTable xrefs xRefTable
objstms ObjectStreams objstms ObjectStreams
trailer *PdfObjectDictionary trailer *PdfObjectDictionary
ObjCache ObjectCache // TODO: Unexport (v3). ObjCache objectCache
crypter *PdfCrypt crypter *PdfCrypt
repairsAttempted bool // Avoid multiple attempts for repair. repairsAttempted bool // Avoid multiple attempts for repair.
@@ -740,8 +740,8 @@ func (parser *PdfParser) parseXrefTable() (*PdfObjectDictionary, error) {
// would be marked as free. But can still happen! // would be marked as free. But can still happen!
x, ok := parser.xrefs[curObjNum] x, ok := parser.xrefs[curObjNum]
if !ok || gen > x.generation { if !ok || gen > x.generation {
obj := XrefObject{objectNumber: curObjNum, obj := xRefObject{objectNumber: curObjNum,
xtype: XREF_TABLE_ENTRY, xtype: xRefTableEntry,
offset: first, generation: gen} offset: first, generation: gen}
parser.xrefs[curObjNum] = obj parser.xrefs[curObjNum] = obj
} }
@@ -1000,16 +1000,16 @@ func (parser *PdfParser) parseXrefStream(xstm *PdfObjectInteger) (*PdfObjectDict
if xr, ok := parser.xrefs[objNum]; !ok || int(n3) > xr.generation { if xr, ok := parser.xrefs[objNum]; !ok || int(n3) > xr.generation {
// Only overload if not already loaded! // Only overload if not already loaded!
// or has a newer generation number. (should not happen) // or has a newer generation number. (should not happen)
obj := XrefObject{objectNumber: objNum, obj := xRefObject{objectNumber: objNum,
xtype: XREF_TABLE_ENTRY, offset: n2, generation: int(n3)} xtype: xRefTableEntry, offset: n2, generation: int(n3)}
parser.xrefs[objNum] = obj parser.xrefs[objNum] = obj
} }
case 2: case 2:
// Object type 2: Compressed object. // Object type 2: Compressed object.
common.Log.Trace("- In use - compressed object") common.Log.Trace("- In use - compressed object")
if _, ok := parser.xrefs[objNum]; !ok { if _, ok := parser.xrefs[objNum]; !ok {
obj := XrefObject{objectNumber: objNum, obj := xRefObject{objectNumber: objNum,
xtype: XREF_OBJECT_STREAM, osObjNumber: int(n2), osObjIndex: int(n3)} xtype: xRefObjectStream, osObjNumber: int(n2), osObjIndex: int(n3)}
parser.xrefs[objNum] = obj parser.xrefs[objNum] = obj
common.Log.Trace("entry: %s", parser.xrefs[objNum]) common.Log.Trace("entry: %s", parser.xrefs[objNum])
} }
@@ -1128,7 +1128,7 @@ func (parser *PdfParser) seekToEOFMarker(fSize int64) error {
// The earlier xrefs have higher precedence. If objects already // The earlier xrefs have higher precedence. If objects already
// loaded will ignore older versions. // loaded will ignore older versions.
func (parser *PdfParser) loadXrefs() (*PdfObjectDictionary, error) { func (parser *PdfParser) loadXrefs() (*PdfObjectDictionary, error) {
parser.xrefs = make(XrefTable) parser.xrefs = make(xRefTable)
parser.objstms = make(ObjectStreams) parser.objstms = make(ObjectStreams)
// Get the file size. // Get the file size.
@@ -1482,30 +1482,13 @@ func (parser *PdfParser) ParseIndirectObject() (PdfObject, error) {
return &indirect, nil return &indirect, nil
} }
// For testing purposes.
// TODO: Unexport (v3) or move to test files, if needed by external test cases.
func NewParserFromString(txt string) *PdfParser {
parser := PdfParser{}
buf := []byte(txt)
bufReader := bytes.NewReader(buf)
parser.rs = bufReader
bufferedReader := bufio.NewReader(bufReader)
parser.reader = bufferedReader
parser.fileSize = int64(len(txt))
return &parser
}
// NewParser creates a new parser for a PDF file via ReadSeeker. Loads the cross reference stream and trailer. // NewParser creates a new parser for a PDF file via ReadSeeker. Loads the cross reference stream and trailer.
// An error is returned on failure. // An error is returned on failure.
func NewParser(rs io.ReadSeeker) (*PdfParser, error) { func NewParser(rs io.ReadSeeker) (*PdfParser, error) {
parser := &PdfParser{} parser := &PdfParser{}
parser.rs = rs parser.rs = rs
parser.ObjCache = make(ObjectCache) parser.ObjCache = make(objectCache)
parser.streamLengthReferenceLookupInProgress = map[int64]bool{} parser.streamLengthReferenceLookupInProgress = map[int64]bool{}
// Start by reading the xrefs (from bottom). // Start by reading the xrefs (from bottom).

View File

@@ -3,6 +3,7 @@ package core
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"strings"
"gitea.tecamino.com/paadi/pdfmerge/internal/pdf/common" "gitea.tecamino.com/paadi/pdfmerge/internal/pdf/common"
) )
@@ -315,15 +316,16 @@ func (array *PdfObjectArray) String() string {
// DefaultWriteString outputs the object as it is to be written to file. // DefaultWriteString outputs the object as it is to be written to file.
func (array *PdfObjectArray) DefaultWriteString() string { func (array *PdfObjectArray) DefaultWriteString() string {
outStr := "[" var outStr strings.Builder
outStr.WriteString("[")
for ind, o := range *array { for ind, o := range *array {
outStr += o.DefaultWriteString() outStr.WriteString(o.DefaultWriteString())
if ind < (len(*array) - 1) { if ind < (len(*array) - 1) {
outStr += " " outStr.WriteString(" ")
} }
} }
outStr += "]" outStr.WriteString("]")
return outStr return outStr.String()
} }
// Append adds an PdfObject to the array. // Append adds an PdfObject to the array.

View File

@@ -45,7 +45,7 @@ func (parser *PdfParser) repairLocateXref() (int64, error) {
// Useful when the cross reference is pointing to an object with the wrong number. // Useful when the cross reference is pointing to an object with the wrong number.
// Update the table. // Update the table.
func (parser *PdfParser) rebuildXrefTable() error { func (parser *PdfParser) rebuildXrefTable() error {
newXrefs := XrefTable{} newXrefs := xRefTable{}
for objNum, xref := range parser.xrefs { for objNum, xref := range parser.xrefs {
obj, _, err := parser.lookupByNumberWrapper(objNum, false) obj, _, err := parser.lookupByNumberWrapper(objNum, false)
if err != nil { if err != nil {
@@ -92,7 +92,7 @@ func parseObjectNumberFromString(str string) (int, int, error) {
// Parse the entire file from top down. // Parse the entire file from top down.
// Goes through the file byte-by-byte looking for "<num> <generation> obj" patterns. // Goes through the file byte-by-byte looking for "<num> <generation> obj" patterns.
// N.B. This collects the XREF_TABLE_ENTRY data only. // N.B. This collects the XREF_TABLE_ENTRY data only.
func (parser *PdfParser) repairRebuildXrefsTopDown() (*XrefTable, error) { func (parser *PdfParser) repairRebuildXrefsTopDown() (*xRefTable, error) {
if parser.repairsAttempted { if parser.repairsAttempted {
// Avoid multiple repairs (only try once). // Avoid multiple repairs (only try once).
return nil, fmt.Errorf("repair failed") return nil, fmt.Errorf("repair failed")
@@ -107,7 +107,7 @@ func (parser *PdfParser) repairRebuildXrefsTopDown() (*XrefTable, error) {
bufLen := 20 bufLen := 20
last := make([]byte, bufLen) last := make([]byte, bufLen)
xrefTable := XrefTable{} xrefTable := xRefTable{}
for { for {
b, err := parser.reader.ReadByte() b, err := parser.reader.ReadByte()
if err != nil { if err != nil {
@@ -164,8 +164,8 @@ func (parser *PdfParser) repairRebuildXrefsTopDown() (*XrefTable, error) {
// Create and insert the XREF entry if not existing, or the generation number is higher. // Create and insert the XREF entry if not existing, or the generation number is higher.
if curXref, has := xrefTable[objNum]; !has || curXref.generation < genNum { if curXref, has := xrefTable[objNum]; !has || curXref.generation < genNum {
// Make the entry for the cross ref table. // Make the entry for the cross ref table.
xrefEntry := XrefObject{} xrefEntry := xRefObject{}
xrefEntry.xtype = XREF_TABLE_ENTRY xrefEntry.xtype = xRefTableEntry
xrefEntry.objectNumber = int(objNum) xrefEntry.objectNumber = int(objNum)
xrefEntry.generation = int(genNum) xrefEntry.generation = int(genNum)
xrefEntry.offset = objOffset xrefEntry.offset = objOffset

View File

@@ -49,7 +49,6 @@ func IsPrintable(char byte) bool {
} }
// IsDelimiter checks if a character represents a delimiter. // IsDelimiter checks if a character represents a delimiter.
// TODO (v3): Unexport.
func IsDelimiter(char byte) bool { func IsDelimiter(char byte) bool {
if char == '(' || char == ')' { if char == '(' || char == ')' {
return true return true

View File

@@ -1,3 +0,0 @@
package extractor
var isTesting = false

View File

@@ -1619,33 +1619,6 @@ func (pc *PdfColorspaceLab) ImageToRGB(img Image) (Image, error) {
// ICC Based colors. // ICC Based colors.
// Each component is defined in the range 0.0 - 1.0 where 1.0 is the primary intensity. // Each component is defined in the range 0.0 - 1.0 where 1.0 is the primary intensity.
/*
type PdfColorICCBased []float64
func NewPdfColorICCBased(vals []float64) *PdfColorICCBased {
color := PdfColorICCBased{}
for _, val := range vals {
color = append(color, val)
}
return &color
}
func (this *PdfColorICCBased) GetNumComponents() int {
return len(*this)
}
// Convert to an integer format.
func (this *PdfColorICCBased) ToInteger(bits int) []uint32 {
maxVal := math.Pow(2, float64(bits)) - 1
ints := []uint32{}
for _, val := range *this {
ints = append(ints, uint32(maxVal*val))
}
return ints
}
*/
// See p. 157 for calculations... // See p. 157 for calculations...
// format [/ICCBased stream] // format [/ICCBased stream]

View File

@@ -157,7 +157,6 @@ func (im *Image) ToGoImage() (goimage.Image, error) {
aidx := 0 aidx := 0
samples := im.GetSamples() samples := im.GetSamples()
//bytesPerColor := colorComponents * int(this.BitsPerComponent) / 8
bytesPerColor := im.ColorComponents bytesPerColor := im.ColorComponents
for i := 0; i+bytesPerColor-1 < len(samples); i += bytesPerColor { for i := 0; i+bytesPerColor-1 < len(samples); i += bytesPerColor {
var c gocolor.Color var c gocolor.Color

View File

@@ -37,24 +37,24 @@ func PSObjectArrayToFloat64Array(objects []PSObject) ([]float64, error) {
return vals, nil return vals, nil
} }
func (this *PSExecutor) Execute(objects []PSObject) ([]PSObject, error) { func (pE *PSExecutor) Execute(objects []PSObject) ([]PSObject, error) {
// Add the arguments on stack // Add the arguments on stack
// [obj1 obj2 ...] // [obj1 obj2 ...]
for _, obj := range objects { for _, obj := range objects {
err := this.Stack.Push(obj) err := pE.Stack.Push(obj)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
err := this.program.Exec(this.Stack) err := pE.program.Exec(pE.Stack)
if err != nil { if err != nil {
common.Log.Debug("Exec failed: %v", err) common.Log.Debug("Exec failed: %v", err)
return nil, err return nil, err
} }
result := []PSObject(*this.Stack) result := []PSObject(*pE.Stack)
this.Stack.Empty() pE.Stack.Empty()
return result, nil return result, nil
} }

View File

@@ -4,6 +4,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"math" "math"
"strings"
) )
type PSObject interface { type PSObject interface {
@@ -17,18 +18,18 @@ type PSInteger struct {
Val int Val int
} }
func (this *PSInteger) Duplicate() PSObject { func (pI *PSInteger) Duplicate() PSObject {
obj := PSInteger{} obj := PSInteger{}
obj.Val = this.Val obj.Val = pI.Val
return &obj return &obj
} }
func (this *PSInteger) DebugString() string { func (pI *PSInteger) DebugString() string {
return fmt.Sprintf("int:%d", this.Val) return fmt.Sprintf("int:%d", pI.Val)
} }
func (this *PSInteger) String() string { func (pI *PSInteger) String() string {
return fmt.Sprintf("%d", this.Val) return fmt.Sprintf("%d", pI.Val)
} }
// Real number. // Real number.
@@ -36,17 +37,17 @@ type PSReal struct {
Val float64 Val float64
} }
func (this *PSReal) DebugString() string { func (pR *PSReal) DebugString() string {
return fmt.Sprintf("real:%.5f", this.Val) return fmt.Sprintf("real:%.5f", pR.Val)
} }
func (this *PSReal) String() string { func (pR *PSReal) String() string {
return fmt.Sprintf("%.5f", this.Val) return fmt.Sprintf("%.5f", pR.Val)
} }
func (this *PSReal) Duplicate() PSObject { func (pR *PSReal) Duplicate() PSObject {
obj := PSReal{} obj := PSReal{}
obj.Val = this.Val obj.Val = pR.Val
return &obj return &obj
} }
@@ -55,17 +56,17 @@ type PSBoolean struct {
Val bool Val bool
} }
func (this *PSBoolean) DebugString() string { func (pB *PSBoolean) DebugString() string {
return fmt.Sprintf("bool:%v", this.Val) return fmt.Sprintf("bool:%v", pB.Val)
} }
func (this *PSBoolean) String() string { func (pB *PSBoolean) String() string {
return fmt.Sprintf("%v", this.Val) return fmt.Sprintf("%v", pB.Val)
} }
func (this *PSBoolean) Duplicate() PSObject { func (pB *PSBoolean) Duplicate() PSObject {
obj := PSBoolean{} obj := PSBoolean{}
obj.Val = this.Val obj.Val = pB.Val
return &obj return &obj
} }
@@ -76,42 +77,44 @@ func NewPSProgram() *PSProgram {
return &PSProgram{} return &PSProgram{}
} }
func (this *PSProgram) Append(obj PSObject) { func (pP *PSProgram) Append(obj PSObject) {
*this = append(*this, obj) *pP = append(*pP, obj)
} }
func (this *PSProgram) DebugString() string { func (pP *PSProgram) DebugString() string {
s := "{ " var s strings.Builder
for _, obj := range *this { s.WriteString("{ ")
s += obj.DebugString() for _, obj := range *pP {
s += " " s.WriteString(obj.DebugString())
s.WriteString(" ")
} }
s += "}" s.WriteString("}")
return s return s.String()
} }
func (this *PSProgram) String() string { func (pP *PSProgram) String() string {
s := "{ " var s strings.Builder
for _, obj := range *this { s.WriteString("{ ")
s += obj.String() for _, obj := range *pP {
s += " " s.WriteString(obj.String())
s.WriteString(" ")
} }
s += "}" s.WriteString("}")
return s return s.String()
} }
func (this *PSProgram) Duplicate() PSObject { func (pP *PSProgram) Duplicate() PSObject {
prog := &PSProgram{} prog := &PSProgram{}
for _, obj := range *this { for _, obj := range *pP {
prog.Append(obj.Duplicate()) prog.Append(obj.Duplicate())
} }
return prog return prog
} }
func (this *PSProgram) Exec(stack *PSStack) error { func (pP *PSProgram) Exec(stack *PSStack) error {
for _, obj := range *this { for _, obj := range *pP {
var err error var err error
if number, isInt := obj.(*PSInteger); isInt { if number, isInt := obj.(*PSInteger); isInt {
err = stack.Push(number) err = stack.Push(number)
@@ -136,118 +139,118 @@ func (this *PSProgram) Exec(stack *PSStack) error {
// Operand. // Operand.
type PSOperand string type PSOperand string
func (this *PSOperand) DebugString() string { func (pO *PSOperand) DebugString() string {
return fmt.Sprintf("op:'%s'", *this) return fmt.Sprintf("op:'%s'", *pO)
} }
func (this *PSOperand) String() string { func (pO *PSOperand) String() string {
return fmt.Sprintf("%s", *this) return fmt.Sprintf("%s", *pO)
} }
func (this *PSOperand) Duplicate() PSObject { func (pO *PSOperand) Duplicate() PSObject {
s := *this s := *pO
return &s return &s
} }
func (this *PSOperand) Exec(stack *PSStack) error { func (pO *PSOperand) Exec(stack *PSStack) error {
err := errors.New("Unsupported operand") err := errors.New("Unsupported operand")
switch *this { switch *pO {
case "abs": case "abs":
err = this.Abs(stack) err = pO.Abs(stack)
case "add": case "add":
err = this.Add(stack) err = pO.Add(stack)
case "and": case "and":
err = this.And(stack) err = pO.And(stack)
case "atan": case "atan":
err = this.Atan(stack) err = pO.Atan(stack)
case "bitshift": case "bitshift":
err = this.Bitshift(stack) err = pO.Bitshift(stack)
case "ceiling": case "ceiling":
err = this.Ceiling(stack) err = pO.Ceiling(stack)
case "copy": case "copy":
err = this.Copy(stack) err = pO.Copy(stack)
case "cos": case "cos":
err = this.Cos(stack) err = pO.Cos(stack)
case "cvi": case "cvi":
err = this.Cvi(stack) err = pO.Cvi(stack)
case "cvr": case "cvr":
err = this.Cvr(stack) err = pO.Cvr(stack)
case "div": case "div":
err = this.Div(stack) err = pO.Div(stack)
case "dup": case "dup":
err = this.Dup(stack) err = pO.Dup(stack)
case "eq": case "eq":
err = this.Eq(stack) err = pO.Eq(stack)
case "exch": case "exch":
err = this.Exch(stack) err = pO.Exch(stack)
case "exp": case "exp":
err = this.Exp(stack) err = pO.Exp(stack)
case "floor": case "floor":
err = this.Floor(stack) err = pO.Floor(stack)
case "ge": case "ge":
err = this.Ge(stack) err = pO.Ge(stack)
case "gt": case "gt":
err = this.Gt(stack) err = pO.Gt(stack)
case "idiv": case "idiv":
err = this.IDiv(stack) err = pO.IDiv(stack)
case "if": case "if":
err = this.If(stack) err = pO.If(stack)
case "ifelse": case "ifelse":
err = this.IfElse(stack) err = pO.IfElse(stack)
case "index": case "index":
err = this.Index(stack) err = pO.Index(stack)
case "le": case "le":
err = this.Le(stack) err = pO.Le(stack)
case "log": case "log":
err = this.Log(stack) err = pO.Log(stack)
case "ln": case "ln":
err = this.Ln(stack) err = pO.Ln(stack)
case "lt": case "lt":
err = this.Lt(stack) err = pO.Lt(stack)
case "mod": case "mod":
err = this.Mod(stack) err = pO.Mod(stack)
case "mul": case "mul":
err = this.Mul(stack) err = pO.Mul(stack)
case "ne": case "ne":
err = this.Ne(stack) err = pO.Ne(stack)
case "neg": case "neg":
err = this.Neg(stack) err = pO.Neg(stack)
case "not": case "not":
err = this.Not(stack) err = pO.Not(stack)
case "or": case "or":
err = this.Or(stack) err = pO.Or(stack)
case "pop": case "pop":
err = this.Pop(stack) err = pO.Pop(stack)
case "round": case "round":
err = this.Round(stack) err = pO.Round(stack)
case "roll": case "roll":
err = this.Roll(stack) err = pO.Roll(stack)
case "sin": case "sin":
err = this.Sin(stack) err = pO.Sin(stack)
case "sqrt": case "sqrt":
err = this.Sqrt(stack) err = pO.Sqrt(stack)
case "sub": case "sub":
err = this.Sub(stack) err = pO.Sub(stack)
case "truncate": case "truncate":
err = this.Truncate(stack) err = pO.Truncate(stack)
case "xor": case "xor":
err = this.Xor(stack) err = pO.Xor(stack)
} }
return err return err
@@ -257,7 +260,7 @@ func (this *PSOperand) Exec(stack *PSStack) error {
// Operation implementations // Operation implementations
// Absolute value. // Absolute value.
func (this *PSOperand) Abs(stack *PSStack) error { func (*PSOperand) Abs(stack *PSStack) error {
obj, err := stack.Pop() obj, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -285,7 +288,7 @@ func (this *PSOperand) Abs(stack *PSStack) error {
} }
// 5 27 add -> 32 // 5 27 add -> 32
func (this *PSOperand) Add(stack *PSStack) error { func (*PSOperand) Add(stack *PSStack) error {
obj1, err := stack.Pop() obj1, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -338,7 +341,7 @@ func (this *PSOperand) Add(stack *PSStack) error {
// bool1 bool2 and -> bool3 // bool1 bool2 and -> bool3
// if int: returns the bitwise "and" of the inputs // if int: returns the bitwise "and" of the inputs
// int1 int2 and -> int3 // int1 int2 and -> int3
func (this *PSOperand) And(stack *PSStack) error { func (*PSOperand) And(stack *PSStack) error {
obj1, err := stack.Pop() obj1, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -374,7 +377,7 @@ func (this *PSOperand) And(stack *PSStack) error {
// den num atan -> atan(num/den) in degrees. // den num atan -> atan(num/den) in degrees.
// result is a real value. // result is a real value.
func (this *PSOperand) Atan(stack *PSStack) error { func (*PSOperand) Atan(stack *PSStack) error {
// Denominator // Denominator
den, err := stack.PopNumberAsFloat64() den, err := stack.PopNumberAsFloat64()
if err != nil { if err != nil {
@@ -409,7 +412,7 @@ func (this *PSOperand) Atan(stack *PSStack) error {
// bitshift // bitshift
// int1 shift bitshift -> int2 // int1 shift bitshift -> int2
func (this *PSOperand) Bitshift(stack *PSStack) error { func (*PSOperand) Bitshift(stack *PSStack) error {
shift, err := stack.PopInteger() shift, err := stack.PopInteger()
if err != nil { if err != nil {
return err return err
@@ -435,7 +438,7 @@ func (this *PSOperand) Bitshift(stack *PSStack) error {
// Ceiling of number. // Ceiling of number.
// num1 ceiling -> num2 // num1 ceiling -> num2
// The type of the result is the same as of the operand. // The type of the result is the same as of the operand.
func (this *PSOperand) Ceiling(stack *PSStack) error { func (*PSOperand) Ceiling(stack *PSStack) error {
obj, err := stack.Pop() obj, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -454,7 +457,7 @@ func (this *PSOperand) Ceiling(stack *PSStack) error {
// Copy // Copy
// any1 ... anyn n copy -> any1 ... anyn any1 ... anyn // any1 ... anyn n copy -> any1 ... anyn any1 ... anyn
func (this *PSOperand) Copy(stack *PSStack) error { func (*PSOperand) Copy(stack *PSStack) error {
n, err := stack.PopInteger() n, err := stack.PopInteger()
if err != nil { if err != nil {
return err return err
@@ -475,7 +478,7 @@ func (this *PSOperand) Copy(stack *PSStack) error {
// Cosine // Cosine
// angle cos -> real // angle cos -> real
// Angle is in degrees // Angle is in degrees
func (this *PSOperand) Cos(stack *PSStack) error { func (*PSOperand) Cos(stack *PSStack) error {
angle, err := stack.PopNumberAsFloat64() angle, err := stack.PopNumberAsFloat64()
if err != nil { if err != nil {
return err return err
@@ -487,7 +490,7 @@ func (this *PSOperand) Cos(stack *PSStack) error {
} }
// Convert to integer // Convert to integer
func (this *PSOperand) Cvi(stack *PSStack) error { func (*PSOperand) Cvi(stack *PSStack) error {
obj, err := stack.Pop() obj, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -507,7 +510,7 @@ func (this *PSOperand) Cvi(stack *PSStack) error {
} }
// Convert number tor real // Convert number tor real
func (this *PSOperand) Cvr(stack *PSStack) error { func (*PSOperand) Cvr(stack *PSStack) error {
obj, err := stack.Pop() obj, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -524,7 +527,7 @@ func (this *PSOperand) Cvr(stack *PSStack) error {
return err return err
} }
func (this *PSOperand) Div(stack *PSStack) error { func (*PSOperand) Div(stack *PSStack) error {
obj1, err := stack.Pop() obj1, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -573,7 +576,7 @@ func (this *PSOperand) Div(stack *PSStack) error {
} }
// Duplicates the top object on the stack (dup) // Duplicates the top object on the stack (dup)
func (this *PSOperand) Dup(stack *PSStack) error { func (*PSOperand) Dup(stack *PSStack) error {
obj, err := stack.Pop() obj, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -591,7 +594,7 @@ func (this *PSOperand) Dup(stack *PSStack) error {
// Check for equality. // Check for equality.
// any1 any2 eq bool // any1 any2 eq bool
func (this *PSOperand) Eq(stack *PSStack) error { func (*PSOperand) Eq(stack *PSStack) error {
obj1, err := stack.Pop() obj1, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -646,7 +649,7 @@ func (this *PSOperand) Eq(stack *PSStack) error {
} }
// Exchange the top two elements of the stack (exch) // Exchange the top two elements of the stack (exch)
func (this *PSOperand) Exch(stack *PSStack) error { func (*PSOperand) Exch(stack *PSStack) error {
top, err := stack.Pop() top, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -669,7 +672,7 @@ func (this *PSOperand) Exch(stack *PSStack) error {
// base exponent exp -> base^exp // base exponent exp -> base^exp
// Raises base to exponent power. // Raises base to exponent power.
// The result is a real number. // The result is a real number.
func (this *PSOperand) Exp(stack *PSStack) error { func (*PSOperand) Exp(stack *PSStack) error {
exponent, err := stack.PopNumberAsFloat64() exponent, err := stack.PopNumberAsFloat64()
if err != nil { if err != nil {
return err return err
@@ -691,7 +694,7 @@ func (this *PSOperand) Exp(stack *PSStack) error {
} }
// Floor of number. // Floor of number.
func (this *PSOperand) Floor(stack *PSStack) error { func (*PSOperand) Floor(stack *PSStack) error {
obj, err := stack.Pop() obj, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -710,7 +713,7 @@ func (this *PSOperand) Floor(stack *PSStack) error {
// Greater than or equal // Greater than or equal
// num1 num2 ge -> bool; num1 >= num2 // num1 num2 ge -> bool; num1 >= num2
func (this *PSOperand) Ge(stack *PSStack) error { func (*PSOperand) Ge(stack *PSStack) error {
num2, err := stack.PopNumberAsFloat64() num2, err := stack.PopNumberAsFloat64()
if err != nil { if err != nil {
return err return err
@@ -736,7 +739,7 @@ func (this *PSOperand) Ge(stack *PSStack) error {
// Greater than // Greater than
// num1 num2 gt -> bool; num1 > num2 // num1 num2 gt -> bool; num1 > num2
func (this *PSOperand) Gt(stack *PSStack) error { func (*PSOperand) Gt(stack *PSStack) error {
num2, err := stack.PopNumberAsFloat64() num2, err := stack.PopNumberAsFloat64()
if err != nil { if err != nil {
return err return err
@@ -762,7 +765,7 @@ func (this *PSOperand) Gt(stack *PSStack) error {
// Integral division // Integral division
// 25 3 div -> 8 // 25 3 div -> 8
func (this *PSOperand) IDiv(stack *PSStack) error { func (*PSOperand) IDiv(stack *PSStack) error {
obj1, err := stack.Pop() obj1, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -794,7 +797,7 @@ func (this *PSOperand) IDiv(stack *PSStack) error {
// If conditional // If conditional
// bool proc if -> run proc() if bool is true // bool proc if -> run proc() if bool is true
func (this *PSOperand) If(stack *PSStack) error { func (*PSOperand) If(stack *PSStack) error {
obj1, err := stack.Pop() obj1, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -825,7 +828,7 @@ func (this *PSOperand) If(stack *PSStack) error {
// If else conditional // If else conditional
// bool proc1 proc2 ifelse -> execute proc1() if bool is true, otherwise proc2() // bool proc1 proc2 ifelse -> execute proc1() if bool is true, otherwise proc2()
func (this *PSOperand) IfElse(stack *PSStack) error { func (*PSOperand) IfElse(stack *PSStack) error {
obj1, err := stack.Pop() obj1, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -866,7 +869,7 @@ func (this *PSOperand) IfElse(stack *PSStack) error {
// Add a copy of the nth object in the stack to the top. // Add a copy of the nth object in the stack to the top.
// any_n ... any_0 n index -> any_n ... any_0 any_n // any_n ... any_0 n index -> any_n ... any_0 any_n
// index from 0 // index from 0
func (this *PSOperand) Index(stack *PSStack) error { func (*PSOperand) Index(stack *PSStack) error {
obj, err := stack.Pop() obj, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -893,7 +896,7 @@ func (this *PSOperand) Index(stack *PSStack) error {
// Less or equal // Less or equal
// num1 num2 le -> bool; num1 <= num2 // num1 num2 le -> bool; num1 <= num2
func (this *PSOperand) Le(stack *PSStack) error { func (*PSOperand) Le(stack *PSStack) error {
num2, err := stack.PopNumberAsFloat64() num2, err := stack.PopNumberAsFloat64()
if err != nil { if err != nil {
return err return err
@@ -918,7 +921,7 @@ func (this *PSOperand) Le(stack *PSStack) error {
} }
// num log -> real // num log -> real
func (this *PSOperand) Log(stack *PSStack) error { func (*PSOperand) Log(stack *PSStack) error {
// Value // Value
val, err := stack.PopNumberAsFloat64() val, err := stack.PopNumberAsFloat64()
if err != nil { if err != nil {
@@ -932,7 +935,7 @@ func (this *PSOperand) Log(stack *PSStack) error {
// num ln -> ln(num) // num ln -> ln(num)
// The result is a real number. // The result is a real number.
func (this *PSOperand) Ln(stack *PSStack) error { func (*PSOperand) Ln(stack *PSStack) error {
// Value // Value
val, err := stack.PopNumberAsFloat64() val, err := stack.PopNumberAsFloat64()
if err != nil { if err != nil {
@@ -946,7 +949,7 @@ func (this *PSOperand) Ln(stack *PSStack) error {
// Less than // Less than
// num1 num2 lt -> bool; num1 < num2 // num1 num2 lt -> bool; num1 < num2
func (this *PSOperand) Lt(stack *PSStack) error { func (*PSOperand) Lt(stack *PSStack) error {
num2, err := stack.PopNumberAsFloat64() num2, err := stack.PopNumberAsFloat64()
if err != nil { if err != nil {
return err return err
@@ -971,7 +974,7 @@ func (this *PSOperand) Lt(stack *PSStack) error {
} }
// 12 10 mod -> 2 // 12 10 mod -> 2
func (this *PSOperand) Mod(stack *PSStack) error { func (*PSOperand) Mod(stack *PSStack) error {
obj1, err := stack.Pop() obj1, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -1001,7 +1004,7 @@ func (this *PSOperand) Mod(stack *PSStack) error {
} }
// 6 8 mul -> 48 // 6 8 mul -> 48
func (this *PSOperand) Mul(stack *PSStack) error { func (*PSOperand) Mul(stack *PSStack) error {
obj1, err := stack.Pop() obj1, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -1051,21 +1054,21 @@ func (this *PSOperand) Mul(stack *PSStack) error {
// Not equal (inverse of eq) // Not equal (inverse of eq)
// any1 any2 ne -> bool // any1 any2 ne -> bool
func (this *PSOperand) Ne(stack *PSStack) error { func (pO *PSOperand) Ne(stack *PSStack) error {
// Simply call equate and then negate the result. // Simply call equate and then negate the result.
// Implementing directly could be more efficient, but probably not a big deal in most cases. // Implementing directly could be more efficient, but probably not a big deal in most cases.
err := this.Eq(stack) err := pO.Eq(stack)
if err != nil { if err != nil {
return err return err
} }
err = this.Not(stack) err = pO.Not(stack)
return err return err
} }
// Negate // Negate
// 6 neg -> -6 // 6 neg -> -6
func (this *PSOperand) Neg(stack *PSStack) error { func (*PSOperand) Neg(stack *PSStack) error {
obj, err := stack.Pop() obj, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -1086,7 +1089,7 @@ func (this *PSOperand) Neg(stack *PSStack) error {
// Logical/bitwise negation // Logical/bitwise negation
// bool1 not -> bool2 (logical) // bool1 not -> bool2 (logical)
// int1 not -> int2 (bitwise) // int1 not -> int2 (bitwise)
func (this *PSOperand) Not(stack *PSStack) error { func (*PSOperand) Not(stack *PSStack) error {
obj, err := stack.Pop() obj, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -1106,7 +1109,7 @@ func (this *PSOperand) Not(stack *PSStack) error {
// OR logical/bitwise operation. // OR logical/bitwise operation.
// bool1 bool2 or -> bool3 (logical or) // bool1 bool2 or -> bool3 (logical or)
// int1 int2 or -> int3 (bitwise or) // int1 int2 or -> int3 (bitwise or)
func (this *PSOperand) Or(stack *PSStack) error { func (*PSOperand) Or(stack *PSStack) error {
obj1, err := stack.Pop() obj1, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -1141,7 +1144,7 @@ func (this *PSOperand) Or(stack *PSStack) error {
} }
// Remove the top element on the stack (pop) // Remove the top element on the stack (pop)
func (this *PSOperand) Pop(stack *PSStack) error { func (*PSOperand) Pop(stack *PSStack) error {
_, err := stack.Pop() _, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -1151,7 +1154,7 @@ func (this *PSOperand) Pop(stack *PSStack) error {
// Round number off. // Round number off.
// num1 round -> num2 // num1 round -> num2
func (this *PSOperand) Round(stack *PSStack) error { func (*PSOperand) Round(stack *PSStack) error {
obj, err := stack.Pop() obj, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -1173,7 +1176,7 @@ func (this *PSOperand) Round(stack *PSStack) error {
// 7 8 9 3 1 roll -> 9 7 8 // 7 8 9 3 1 roll -> 9 7 8
// 7 8 9 3 -1 roll -> 8 9 7 // 7 8 9 3 -1 roll -> 8 9 7
// n j roll // n j roll
func (this *PSOperand) Roll(stack *PSStack) error { func (*PSOperand) Roll(stack *PSStack) error {
obj1, err := stack.Pop() obj1, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -1228,7 +1231,7 @@ func (this *PSOperand) Roll(stack *PSStack) error {
// Sine. // Sine.
// angle sin -> real // angle sin -> real
// Angle is in degrees // Angle is in degrees
func (this *PSOperand) Sin(stack *PSStack) error { func (*PSOperand) Sin(stack *PSStack) error {
angle, err := stack.PopNumberAsFloat64() angle, err := stack.PopNumberAsFloat64()
if err != nil { if err != nil {
return err return err
@@ -1242,7 +1245,7 @@ func (this *PSOperand) Sin(stack *PSStack) error {
// Square root. // Square root.
// num sqrt -> real; real=sqrt(num) // num sqrt -> real; real=sqrt(num)
// The result is a real number. // The result is a real number.
func (this *PSOperand) Sqrt(stack *PSStack) error { func (*PSOperand) Sqrt(stack *PSStack) error {
val, err := stack.PopNumberAsFloat64() val, err := stack.PopNumberAsFloat64()
if err != nil { if err != nil {
return err return err
@@ -1260,7 +1263,7 @@ func (this *PSOperand) Sqrt(stack *PSStack) error {
// 8.3 6.6 sub -> 1.7 (real) // 8.3 6.6 sub -> 1.7 (real)
// 8 6.3 sub -> 1.7 (real) // 8 6.3 sub -> 1.7 (real)
// 8 6 sub -> 2 (int) // 8 6 sub -> 2 (int)
func (this *PSOperand) Sub(stack *PSStack) error { func (*PSOperand) Sub(stack *PSStack) error {
obj1, err := stack.Pop() obj1, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -1311,7 +1314,7 @@ func (this *PSOperand) Sub(stack *PSStack) error {
// Truncate number. // Truncate number.
// num1 truncate -> num2 // num1 truncate -> num2
// The resulting number is the same type as the input. // The resulting number is the same type as the input.
func (this *PSOperand) Truncate(stack *PSStack) error { func (*PSOperand) Truncate(stack *PSStack) error {
obj, err := stack.Pop() obj, err := stack.Pop()
if err != nil { if err != nil {
return err return err
@@ -1332,7 +1335,7 @@ func (this *PSOperand) Truncate(stack *PSStack) error {
// XOR logical/bitwise operation. // XOR logical/bitwise operation.
// bool1 bool2 xor -> bool3 (logical xor) // bool1 bool2 xor -> bool3 (logical xor)
// int1 int2 xor -> int3 (bitwise xor) // int1 int2 xor -> int3 (bitwise xor)
func (this *PSOperand) Xor(stack *PSStack) error { func (*PSOperand) Xor(stack *PSStack) error {
obj1, err := stack.Pop() obj1, err := stack.Pop()
if err != nil { if err != nil {
return err return err

View File

@@ -28,9 +28,9 @@ func NewPSParser(content []byte) *PSParser {
} }
// Parse the postscript and store as a program that can be executed. // Parse the postscript and store as a program that can be executed.
func (this *PSParser) Parse() (*PSProgram, error) { func (pP *PSParser) Parse() (*PSProgram, error) {
this.skipSpaces() pP.skipSpaces()
bb, err := this.reader.Peek(2) bb, err := pP.reader.Peek(2)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -38,7 +38,7 @@ func (this *PSParser) Parse() (*PSProgram, error) {
return nil, fmt.Errorf("invalid PS Program not starting with {") return nil, fmt.Errorf("invalid PS Program not starting with {")
} }
program, err := this.parseFunction() program, err := pP.parseFunction()
if err != nil && err != io.EOF { if err != nil && err != io.EOF {
return nil, err return nil, err
} }
@@ -48,8 +48,8 @@ func (this *PSParser) Parse() (*PSProgram, error) {
// Detect the signature at the current parse position and parse // Detect the signature at the current parse position and parse
// the corresponding object. // the corresponding object.
func (this *PSParser) parseFunction() (*PSProgram, error) { func (pP *PSParser) parseFunction() (*PSProgram, error) {
c, _ := this.reader.ReadByte() c, _ := pP.reader.ReadByte()
if c != '{' { if c != '{' {
return nil, errors.New("invalid function") return nil, errors.New("invalid function")
} }
@@ -57,8 +57,8 @@ func (this *PSParser) parseFunction() (*PSProgram, error) {
function := NewPSProgram() function := NewPSProgram()
for { for {
this.skipSpaces() pP.skipSpaces()
bb, err := this.reader.Peek(2) bb, err := pP.reader.Peek(2)
if err != nil { if err != nil {
if err == io.EOF { if err == io.EOF {
break break
@@ -70,18 +70,18 @@ func (this *PSParser) parseFunction() (*PSProgram, error) {
// Determine type. // Determine type.
if bb[0] == '}' { if bb[0] == '}' {
common.Log.Trace("EOF function") common.Log.Trace("EOF function")
this.reader.ReadByte() pP.reader.ReadByte()
break break
} else if bb[0] == '{' { } else if bb[0] == '{' {
common.Log.Trace("Function!") common.Log.Trace("Function!")
inlineF, err := this.parseFunction() inlineF, err := pP.parseFunction()
if err != nil { if err != nil {
return nil, err return nil, err
} }
function.Append(inlineF) function.Append(inlineF)
} else if pdfcore.IsDecimalDigit(bb[0]) || (bb[0] == '-' && pdfcore.IsDecimalDigit(bb[1])) { } else if pdfcore.IsDecimalDigit(bb[0]) || (bb[0] == '-' && pdfcore.IsDecimalDigit(bb[1])) {
common.Log.Trace("->Number!") common.Log.Trace("->Number!")
number, err := this.parseNumber() number, err := pP.parseNumber()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -89,24 +89,24 @@ func (this *PSParser) parseFunction() (*PSProgram, error) {
} else { } else {
common.Log.Trace("->Operand or bool?") common.Log.Trace("->Operand or bool?")
// Let's peek farther to find out. // Let's peek farther to find out.
bb, _ = this.reader.Peek(5) bb, _ = pP.reader.Peek(5)
peekStr := string(bb) peekStr := string(bb)
common.Log.Trace("Peek str: %s", peekStr) common.Log.Trace("Peek str: %s", peekStr)
if (len(peekStr) > 4) && (peekStr[:5] == "false") { if (len(peekStr) > 4) && (peekStr[:5] == "false") {
b, err := this.parseBool() b, err := pP.parseBool()
if err != nil { if err != nil {
return nil, err return nil, err
} }
function.Append(b) function.Append(b)
} else if (len(peekStr) > 3) && (peekStr[:4] == "true") { } else if (len(peekStr) > 3) && (peekStr[:4] == "true") {
b, err := this.parseBool() b, err := pP.parseBool()
if err != nil { if err != nil {
return nil, err return nil, err
} }
function.Append(b) function.Append(b)
} else { } else {
operand, err := this.parseOperand() operand, err := pP.parseOperand()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -120,15 +120,15 @@ func (this *PSParser) parseFunction() (*PSProgram, error) {
// Skip over any spaces. Returns the number of spaces skipped and // Skip over any spaces. Returns the number of spaces skipped and
// an error if any. // an error if any.
func (this *PSParser) skipSpaces() (int, error) { func (pP *PSParser) skipSpaces() (int, error) {
cnt := 0 cnt := 0
for { for {
bb, err := this.reader.Peek(1) bb, err := pP.reader.Peek(1)
if err != nil { if err != nil {
return 0, err return 0, err
} }
if pdfcore.IsWhiteSpace(bb[0]) { if pdfcore.IsWhiteSpace(bb[0]) {
this.reader.ReadByte() pP.reader.ReadByte()
cnt++ cnt++
} else { } else {
break break
@@ -140,13 +140,13 @@ func (this *PSParser) skipSpaces() (int, error) {
// Numeric objects. // Numeric objects.
// Integer or Real numbers. // Integer or Real numbers.
func (this *PSParser) parseNumber() (PSObject, error) { func (pP *PSParser) parseNumber() (PSObject, error) {
isFloat := false isFloat := false
allowSigns := true allowSigns := true
numStr := "" numStr := ""
for { for {
common.Log.Trace("Parsing number \"%s\"", numStr) common.Log.Trace("Parsing number \"%s\"", numStr)
bb, err := this.reader.Peek(1) bb, err := pP.reader.Peek(1)
if err == io.EOF { if err == io.EOF {
// GH: EOF handling. Handle EOF like end of line. Can happen with // GH: EOF handling. Handle EOF like end of line. Can happen with
// encoded object streams that the object is at the end. // encoded object streams that the object is at the end.
@@ -159,20 +159,20 @@ func (this *PSParser) parseNumber() (PSObject, error) {
} }
if allowSigns && (bb[0] == '-' || bb[0] == '+') { if allowSigns && (bb[0] == '-' || bb[0] == '+') {
// Only appear in the beginning, otherwise serves as a delimiter. // Only appear in the beginning, otherwise serves as a delimiter.
b, _ := this.reader.ReadByte() b, _ := pP.reader.ReadByte()
numStr += string(b) numStr += string(b)
allowSigns = false // Only allowed in beginning, and after e (exponential). allowSigns = false // Only allowed in beginning, and after e (exponential).
} else if pdfcore.IsDecimalDigit(bb[0]) { } else if pdfcore.IsDecimalDigit(bb[0]) {
b, _ := this.reader.ReadByte() b, _ := pP.reader.ReadByte()
numStr += string(b) numStr += string(b)
} else if bb[0] == '.' { } else if bb[0] == '.' {
b, _ := this.reader.ReadByte() b, _ := pP.reader.ReadByte()
numStr += string(b) numStr += string(b)
isFloat = true isFloat = true
} else if bb[0] == 'e' { } else if bb[0] == 'e' {
// Exponential number format. // Exponential number format.
// XXX Is this supported in PS? // XXX Is this supported in PS?
b, _ := this.reader.ReadByte() b, _ := pP.reader.ReadByte()
numStr += string(b) numStr += string(b)
isFloat = true isFloat = true
allowSigns = true allowSigns = true
@@ -193,22 +193,22 @@ func (this *PSParser) parseNumber() (PSObject, error) {
} }
// Parse bool object. // Parse bool object.
func (this *PSParser) parseBool() (*PSBoolean, error) { func (pP *PSParser) parseBool() (*PSBoolean, error) {
bb, err := this.reader.Peek(4) bb, err := pP.reader.Peek(4)
if err != nil { if err != nil {
return MakeBool(false), err return MakeBool(false), err
} }
if (len(bb) >= 4) && (string(bb[:4]) == "true") { if (len(bb) >= 4) && (string(bb[:4]) == "true") {
this.reader.Discard(4) pP.reader.Discard(4)
return MakeBool(true), nil return MakeBool(true), nil
} }
bb, err = this.reader.Peek(5) bb, err = pP.reader.Peek(5)
if err != nil { if err != nil {
return MakeBool(false), err return MakeBool(false), err
} }
if (len(bb) >= 5) && (string(bb[:5]) == "false") { if (len(bb) >= 5) && (string(bb[:5]) == "false") {
this.reader.Discard(5) pP.reader.Discard(5)
return MakeBool(false), nil return MakeBool(false), nil
} }
@@ -216,10 +216,10 @@ func (this *PSParser) parseBool() (*PSBoolean, error) {
} }
// An operand is a text command represented by a word. // An operand is a text command represented by a word.
func (this *PSParser) parseOperand() (*PSOperand, error) { func (pP *PSParser) parseOperand() (*PSOperand, error) {
bytes := []byte{} bytes := []byte{}
for { for {
bb, err := this.reader.Peek(1) bb, err := pP.reader.Peek(1)
if err != nil { if err != nil {
if err == io.EOF { if err == io.EOF {
break break
@@ -233,7 +233,7 @@ func (this *PSParser) parseOperand() (*PSOperand, error) {
break break
} }
b, _ := this.reader.ReadByte() b, _ := pP.reader.ReadByte()
bytes = append(bytes, b) bytes = append(bytes, b)
} }

View File

@@ -1,5 +1,7 @@
package ps package ps
import "strings"
type PSStack []PSObject type PSStack []PSObject
func NewPSStack() *PSStack { func NewPSStack() *PSStack {
@@ -60,24 +62,26 @@ func (stack *PSStack) PopNumberAsFloat64() (float64, error) {
} }
} }
func (this *PSStack) String() string { func (pS *PSStack) String() string {
s := "[ " var s strings.Builder
for _, obj := range *this { s.WriteString("[ ")
s += obj.String() for _, obj := range *pS {
s += " " s.WriteString(obj.String())
s.WriteString(" ")
} }
s += "]" s.WriteString("]")
return s return s.String()
} }
func (this *PSStack) DebugString() string { func (pS *PSStack) DebugString() string {
s := "[ " var s strings.Builder
for _, obj := range *this { s.WriteString("[ ")
s += obj.DebugString() for _, obj := range *pS {
s += " " s.WriteString(obj.DebugString())
s.WriteString(" ")
} }
s += "]" s.WriteString("]")
return s return s.String()
} }