@ -40,92 +40,92 @@ type LicenseKey struct {
|
||||
CreatorEmail string `json:"creator_email"`
|
||||
}
|
||||
|
||||
func (this *LicenseKey) isExpired() bool {
|
||||
if this.ExpiresAt == nil {
|
||||
func (k *LicenseKey) isExpired() bool {
|
||||
if k.ExpiresAt == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if this.CreatedAt.Before(startCheckingExpiry) {
|
||||
if k.CreatedAt.Before(startCheckingExpiry) {
|
||||
return false
|
||||
}
|
||||
|
||||
utcNow := time.Now().UTC()
|
||||
return utcNow.After(*this.ExpiresAt)
|
||||
return utcNow.After(*k.ExpiresAt)
|
||||
}
|
||||
|
||||
func (this *LicenseKey) Validate() error {
|
||||
if len(this.LicenseId) < 10 {
|
||||
func (k *LicenseKey) Validate() error {
|
||||
if len(k.LicenseId) < 10 {
|
||||
return fmt.Errorf("Invalid license: License Id")
|
||||
}
|
||||
|
||||
if len(this.CustomerId) < 10 {
|
||||
if len(k.CustomerId) < 10 {
|
||||
return fmt.Errorf("Invalid license: Customer Id")
|
||||
}
|
||||
|
||||
if len(this.CustomerName) < 1 {
|
||||
if len(k.CustomerName) < 1 {
|
||||
return fmt.Errorf("Invalid license: Customer Name")
|
||||
}
|
||||
|
||||
if testTime.After(this.CreatedAt) {
|
||||
if testTime.After(k.CreatedAt) {
|
||||
return fmt.Errorf("Invalid license: Created At is invalid")
|
||||
}
|
||||
|
||||
if this.ExpiresAt != nil {
|
||||
if this.CreatedAt.After(*this.ExpiresAt) {
|
||||
if k.ExpiresAt != nil {
|
||||
if k.CreatedAt.After(*k.ExpiresAt) {
|
||||
return fmt.Errorf("Invalid license: Created At cannot be Greater than Expires At")
|
||||
}
|
||||
}
|
||||
|
||||
if this.isExpired() {
|
||||
if k.isExpired() {
|
||||
return fmt.Errorf("Invalid license: The license has already expired")
|
||||
}
|
||||
|
||||
if len(this.CreatorName) < 1 {
|
||||
if len(k.CreatorName) < 1 {
|
||||
return fmt.Errorf("Invalid license: Creator name")
|
||||
}
|
||||
|
||||
if len(this.CreatorEmail) < 1 {
|
||||
if len(k.CreatorEmail) < 1 {
|
||||
return fmt.Errorf("Invalid license: Creator email")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (this *LicenseKey) TypeToString() string {
|
||||
if this.Tier == LicenseTierUnlicensed {
|
||||
func (k *LicenseKey) TypeToString() string {
|
||||
if k.Tier == LicenseTierUnlicensed {
|
||||
return "Unlicensed"
|
||||
}
|
||||
|
||||
if this.Tier == LicenseTierCommunity {
|
||||
if k.Tier == LicenseTierCommunity {
|
||||
return "AGPLv3 Open Source Community License"
|
||||
}
|
||||
|
||||
if this.Tier == LicenseTierIndividual || this.Tier == "indie" {
|
||||
if k.Tier == LicenseTierIndividual || k.Tier == "indie" {
|
||||
return "Commercial License - Individual"
|
||||
}
|
||||
|
||||
return "Commercial License - Business"
|
||||
}
|
||||
|
||||
func (this *LicenseKey) ToString() string {
|
||||
str := fmt.Sprintf("License Id: %s\n", this.LicenseId)
|
||||
str += fmt.Sprintf("Customer Id: %s\n", this.CustomerId)
|
||||
str += fmt.Sprintf("Customer Name: %s\n", this.CustomerName)
|
||||
str += fmt.Sprintf("Tier: %s\n", this.Tier)
|
||||
str += fmt.Sprintf("Created At: %s\n", common.UtcTimeFormat(this.CreatedAt))
|
||||
func (k *LicenseKey) ToString() string {
|
||||
str := fmt.Sprintf("License Id: %s\n", k.LicenseId)
|
||||
str += fmt.Sprintf("Customer Id: %s\n", k.CustomerId)
|
||||
str += fmt.Sprintf("Customer Name: %s\n", k.CustomerName)
|
||||
str += fmt.Sprintf("Tier: %s\n", k.Tier)
|
||||
str += fmt.Sprintf("Created At: %s\n", common.UtcTimeFormat(k.CreatedAt))
|
||||
|
||||
if this.ExpiresAt == nil {
|
||||
if k.ExpiresAt == nil {
|
||||
str += fmt.Sprintf("Expires At: Never\n")
|
||||
} else {
|
||||
str += fmt.Sprintf("Expires At: %s\n", common.UtcTimeFormat(*this.ExpiresAt))
|
||||
str += fmt.Sprintf("Expires At: %s\n", common.UtcTimeFormat(*k.ExpiresAt))
|
||||
}
|
||||
|
||||
str += fmt.Sprintf("Creator: %s <%s>\n", this.CreatorName, this.CreatorEmail)
|
||||
str += fmt.Sprintf("Creator: %s <%s>\n", k.CreatorName, k.CreatorEmail)
|
||||
return str
|
||||
}
|
||||
|
||||
func (lk *LicenseKey) IsLicensed() bool {
|
||||
return lk.Tier != LicenseTierUnlicensed
|
||||
func (k *LicenseKey) IsLicensed() bool {
|
||||
return k.Tier != LicenseTierUnlicensed
|
||||
}
|
||||
|
||||
func MakeUnlicensedKey() *LicenseKey {
|
||||
|
@ -12,9 +12,9 @@ import (
|
||||
)
|
||||
|
||||
// Defaults to the open source license.
|
||||
var licenseKey *LicenseKey = MakeUnlicensedKey()
|
||||
var licenseKey = MakeUnlicensedKey()
|
||||
|
||||
// Sets and validates the license key.
|
||||
// SetLicenseKey sets and validates the license key.
|
||||
func SetLicenseKey(content string, customerName string) error {
|
||||
lk, err := licenseKeyDecode(content)
|
||||
if err != nil {
|
||||
|
@ -21,28 +21,28 @@ type Logger interface {
|
||||
Trace(format string, args ...interface{})
|
||||
}
|
||||
|
||||
// Dummy Logger does nothing.
|
||||
// DummyLogger does nothing.
|
||||
type DummyLogger struct{}
|
||||
|
||||
func (this DummyLogger) Error(format string, args ...interface{}) {
|
||||
func (DummyLogger) Error(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (this DummyLogger) Warning(format string, args ...interface{}) {
|
||||
func (DummyLogger) Warning(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (this DummyLogger) Notice(format string, args ...interface{}) {
|
||||
func (DummyLogger) Notice(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (this DummyLogger) Info(format string, args ...interface{}) {
|
||||
func (DummyLogger) Info(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (this DummyLogger) Debug(format string, args ...interface{}) {
|
||||
func (DummyLogger) Debug(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
func (this DummyLogger) Trace(format string, args ...interface{}) {
|
||||
func (DummyLogger) Trace(format string, args ...interface{}) {
|
||||
}
|
||||
|
||||
// Simple Console Logger that the tests use.
|
||||
// LogLevel is the verbosity level for logging.
|
||||
type LogLevel int
|
||||
|
||||
const (
|
||||
@ -64,45 +64,45 @@ func NewConsoleLogger(logLevel LogLevel) *ConsoleLogger {
|
||||
return &logger
|
||||
}
|
||||
|
||||
func (this ConsoleLogger) Error(format string, args ...interface{}) {
|
||||
if this.LogLevel >= LogLevelError {
|
||||
func (l ConsoleLogger) Error(format string, args ...interface{}) {
|
||||
if l.LogLevel >= LogLevelError {
|
||||
prefix := "[ERROR] "
|
||||
this.output(os.Stdout, prefix, format, args...)
|
||||
l.output(os.Stdout, prefix, format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (this ConsoleLogger) Warning(format string, args ...interface{}) {
|
||||
if this.LogLevel >= LogLevelWarning {
|
||||
func (l ConsoleLogger) Warning(format string, args ...interface{}) {
|
||||
if l.LogLevel >= LogLevelWarning {
|
||||
prefix := "[WARNING] "
|
||||
this.output(os.Stdout, prefix, format, args...)
|
||||
l.output(os.Stdout, prefix, format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (this ConsoleLogger) Notice(format string, args ...interface{}) {
|
||||
if this.LogLevel >= LogLevelNotice {
|
||||
func (l ConsoleLogger) Notice(format string, args ...interface{}) {
|
||||
if l.LogLevel >= LogLevelNotice {
|
||||
prefix := "[NOTICE] "
|
||||
this.output(os.Stdout, prefix, format, args...)
|
||||
l.output(os.Stdout, prefix, format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (this ConsoleLogger) Info(format string, args ...interface{}) {
|
||||
if this.LogLevel >= LogLevelInfo {
|
||||
func (l ConsoleLogger) Info(format string, args ...interface{}) {
|
||||
if l.LogLevel >= LogLevelInfo {
|
||||
prefix := "[INFO] "
|
||||
this.output(os.Stdout, prefix, format, args...)
|
||||
l.output(os.Stdout, prefix, format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (this ConsoleLogger) Debug(format string, args ...interface{}) {
|
||||
if this.LogLevel >= LogLevelDebug {
|
||||
func (l ConsoleLogger) Debug(format string, args ...interface{}) {
|
||||
if l.LogLevel >= LogLevelDebug {
|
||||
prefix := "[DEBUG] "
|
||||
this.output(os.Stdout, prefix, format, args...)
|
||||
l.output(os.Stdout, prefix, format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
func (this ConsoleLogger) Trace(format string, args ...interface{}) {
|
||||
if this.LogLevel >= LogLevelTrace {
|
||||
func (l ConsoleLogger) Trace(format string, args ...interface{}) {
|
||||
if l.LogLevel >= LogLevelTrace {
|
||||
prefix := "[TRACE] "
|
||||
this.output(os.Stdout, prefix, format, args...)
|
||||
l.output(os.Stdout, prefix, format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
@ -113,7 +113,7 @@ func SetLogger(logger Logger) {
|
||||
}
|
||||
|
||||
// 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 ...interface{}) {
|
||||
func (l ConsoleLogger) output(f *os.File, prefix string, format string, args ...interface{}) {
|
||||
_, file, line, ok := runtime.Caller(2)
|
||||
if !ok {
|
||||
file = "???"
|
||||
|
@ -16,7 +16,7 @@ const releaseDay = 14
|
||||
const releaseHour = 19
|
||||
const releaseMin = 40
|
||||
|
||||
// Holds version information, when bumping this make sure to bump the released at stamp also.
|
||||
// Version holds version information, when bumping this make sure to bump the released at stamp also.
|
||||
const Version = "2.1.1"
|
||||
|
||||
var ReleasedAt = time.Date(releaseYear, releaseMonth, releaseDay, releaseHour, releaseMin, 0, 0, time.UTC)
|
||||
|
2
doc.go
@ -3,7 +3,7 @@
|
||||
* file 'LICENSE.md', which is part of this source code package.
|
||||
*/
|
||||
|
||||
// UniDoc is a comprehensive PDF library for Go (golang). The library has advanced capabilities for generating,
|
||||
// Package unidoc is a comprehensive PDF library for Go (golang). The library has advanced capabilities for generating,
|
||||
// processing and modifying PDFs. UniDoc is written and supported by the owners of the
|
||||
// FoxyUtils.com website, where the library is used to power many of the PDF services offered.
|
||||
//
|
||||
|
@ -26,7 +26,8 @@ type CircleAnnotationDef struct {
|
||||
Opacity float64 // Alpha value (0-1).
|
||||
}
|
||||
|
||||
// Creates a circle/ellipse annotation object with appearance stream that can be added to page PDF annotations.
|
||||
// CreateCircleAnnotation creates a circle/ellipse annotation object with appearance stream that can be added to
|
||||
// page PDF annotations.
|
||||
func CreateCircleAnnotation(circDef CircleAnnotationDef) (*pdf.PdfAnnotation, error) {
|
||||
circAnnotation := pdf.NewPdfAnnotationCircle()
|
||||
|
||||
|
@ -731,6 +731,8 @@ func genFieldTextCombAppearance(wa *model.PdfAnnotationWidget, ftxt *model.PdfFi
|
||||
// genFieldCheckboxAppearance generates an appearance dictionary for a widget annotation `wa` referenced by
|
||||
// a button field `fbtn` with form resources `dr` (DR).
|
||||
func genFieldCheckboxAppearance(wa *model.PdfAnnotationWidget, fbtn *model.PdfFieldButton, dr *model.PdfPageResources, style AppearanceStyle) (*core.PdfObjectDictionary, error) {
|
||||
// TODO(dennwc): unused parameters
|
||||
|
||||
// Get bounding Rect.
|
||||
array, ok := core.GetArray(wa.Rect)
|
||||
if !ok {
|
||||
|
@ -12,8 +12,8 @@ import (
|
||||
pdf "github.com/unidoc/unidoc/pdf/model"
|
||||
)
|
||||
|
||||
// Defines a line between point 1 (X1,Y1) and point 2 (X2,Y2). The line ending styles can be none (regular line),
|
||||
// or arrows at either end. The line also has a specified width, color and opacity.
|
||||
// LineAnnotationDef defines a line between point 1 (X1,Y1) and point 2 (X2,Y2). The line ending styles can be none
|
||||
// (regular line), or arrows at either end. The line also has a specified width, color and opacity.
|
||||
type LineAnnotationDef struct {
|
||||
X1 float64
|
||||
Y1 float64
|
||||
@ -26,7 +26,7 @@ type LineAnnotationDef struct {
|
||||
LineEndingStyle2 draw.LineEndingStyle // Line ending style of point 2.
|
||||
}
|
||||
|
||||
// Creates a line annotation object that can be added to page PDF annotations.
|
||||
// CreateLineAnnotation creates a line annotation object that can be added to page PDF annotations.
|
||||
func CreateLineAnnotation(lineDef LineAnnotationDef) (*pdf.PdfAnnotation, error) {
|
||||
// Line annotation.
|
||||
lineAnnotation := pdf.NewPdfAnnotationLine()
|
||||
|
@ -13,8 +13,8 @@ import (
|
||||
pdf "github.com/unidoc/unidoc/pdf/model"
|
||||
)
|
||||
|
||||
// A rectangle defined with a specified Width and Height and a lower left corner at (X,Y). The rectangle can
|
||||
// optionally have a border and a filling color.
|
||||
// RectangleAnnotationDef is a rectangle defined with a specified Width and Height and a lower left corner at (X,Y).
|
||||
// The rectangle can optionally have a border and a filling color.
|
||||
// The Width/Height includes the border (if any specified).
|
||||
type RectangleAnnotationDef struct {
|
||||
X float64
|
||||
@ -29,7 +29,7 @@ type RectangleAnnotationDef struct {
|
||||
Opacity float64 // Alpha value (0-1).
|
||||
}
|
||||
|
||||
// Creates a rectangle annotation object that can be added to page PDF annotations.
|
||||
// CreateRectangleAnnotation creates a rectangle annotation object that can be added to page PDF annotations.
|
||||
func CreateRectangleAnnotation(rectDef RectangleAnnotationDef) (*pdf.PdfAnnotation, error) {
|
||||
rectAnnotation := pdf.NewPdfAnnotationSquare()
|
||||
|
||||
|
@ -89,12 +89,12 @@ func (ops *ContentStreamOperations) Bytes() []byte {
|
||||
if op.Operand == "BI" {
|
||||
// Inline image requires special handling.
|
||||
buf.WriteString(op.Operand + "\n")
|
||||
buf.WriteString(op.Params[0].DefaultWriteString())
|
||||
buf.WriteString(op.Params[0].WriteString())
|
||||
|
||||
} else {
|
||||
// Default handler.
|
||||
for _, param := range op.Params {
|
||||
buf.WriteString(param.DefaultWriteString())
|
||||
buf.WriteString(param.WriteString())
|
||||
buf.WriteString(" ")
|
||||
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ import (
|
||||
"github.com/unidoc/unidoc/pdf/model"
|
||||
)
|
||||
|
||||
// Cubic bezier curves are defined by:
|
||||
// CubicBezierCurve is defined by:
|
||||
// R(t) = P0*(1-t)^3 + P1*3*t*(1-t)^2 + P2*3*t^2*(1-t) + P3*t^3
|
||||
// where P0 is the current point, P1, P2 control points and P3 the final point.
|
||||
type CubicBezierCurve struct {
|
||||
@ -30,7 +30,7 @@ func NewCubicBezierCurve(x0, y0, x1, y1, x2, y2, x3, y3 float64) CubicBezierCurv
|
||||
return curve
|
||||
}
|
||||
|
||||
// Add X,Y offset to all points on a curve.
|
||||
// AddOffsetXY adds X,Y offset to all points on a curve.
|
||||
func (curve CubicBezierCurve) AddOffsetXY(offX, offY float64) CubicBezierCurve {
|
||||
curve.P0.X += offX
|
||||
curve.P1.X += offX
|
||||
@ -94,35 +94,35 @@ func NewCubicBezierPath() CubicBezierPath {
|
||||
return bpath
|
||||
}
|
||||
|
||||
func (this CubicBezierPath) AppendCurve(curve CubicBezierCurve) CubicBezierPath {
|
||||
this.Curves = append(this.Curves, curve)
|
||||
return this
|
||||
func (p CubicBezierPath) AppendCurve(curve CubicBezierCurve) CubicBezierPath {
|
||||
p.Curves = append(p.Curves, curve)
|
||||
return p
|
||||
}
|
||||
|
||||
func (bpath CubicBezierPath) Copy() CubicBezierPath {
|
||||
func (p CubicBezierPath) Copy() CubicBezierPath {
|
||||
bpathcopy := CubicBezierPath{}
|
||||
bpathcopy.Curves = []CubicBezierCurve{}
|
||||
for _, c := range bpath.Curves {
|
||||
for _, c := range p.Curves {
|
||||
bpathcopy.Curves = append(bpathcopy.Curves, c)
|
||||
}
|
||||
return bpathcopy
|
||||
}
|
||||
|
||||
func (bpath CubicBezierPath) Offset(offX, offY float64) CubicBezierPath {
|
||||
for i, c := range bpath.Curves {
|
||||
bpath.Curves[i] = c.AddOffsetXY(offX, offY)
|
||||
func (p CubicBezierPath) Offset(offX, offY float64) CubicBezierPath {
|
||||
for i, c := range p.Curves {
|
||||
p.Curves[i] = c.AddOffsetXY(offX, offY)
|
||||
}
|
||||
return bpath
|
||||
return p
|
||||
}
|
||||
|
||||
func (bpath CubicBezierPath) GetBoundingBox() Rectangle {
|
||||
func (p CubicBezierPath) GetBoundingBox() Rectangle {
|
||||
bbox := Rectangle{}
|
||||
|
||||
minX := 0.0
|
||||
maxX := 0.0
|
||||
minY := 0.0
|
||||
maxY := 0.0
|
||||
for idx, c := range bpath.Curves {
|
||||
for idx, c := range p.Curves {
|
||||
curveBounds := c.GetBounds()
|
||||
if idx == 0 {
|
||||
minX = curveBounds.Llx
|
||||
|
@ -5,67 +5,65 @@
|
||||
|
||||
package draw
|
||||
|
||||
// A path consists of straight line connections between each point defined in an array of points.
|
||||
// Path consists of straight line connections between each point defined in an array of points.
|
||||
type Path struct {
|
||||
Points []Point
|
||||
}
|
||||
|
||||
func NewPath() Path {
|
||||
path := Path{}
|
||||
path.Points = []Point{}
|
||||
return path
|
||||
return Path{}
|
||||
}
|
||||
|
||||
func (this Path) AppendPoint(point Point) Path {
|
||||
this.Points = append(this.Points, point)
|
||||
return this
|
||||
func (p Path) AppendPoint(point Point) Path {
|
||||
p.Points = append(p.Points, point)
|
||||
return p
|
||||
}
|
||||
|
||||
func (this Path) RemovePoint(number int) Path {
|
||||
if number < 1 || number > len(this.Points) {
|
||||
return this
|
||||
func (p Path) RemovePoint(number int) Path {
|
||||
if number < 1 || number > len(p.Points) {
|
||||
return p
|
||||
}
|
||||
|
||||
idx := number - 1
|
||||
this.Points = append(this.Points[:idx], this.Points[idx+1:]...)
|
||||
return this
|
||||
p.Points = append(p.Points[:idx], p.Points[idx+1:]...)
|
||||
return p
|
||||
}
|
||||
|
||||
func (this Path) Length() int {
|
||||
return len(this.Points)
|
||||
func (p Path) Length() int {
|
||||
return len(p.Points)
|
||||
}
|
||||
|
||||
func (this Path) GetPointNumber(number int) Point {
|
||||
if number < 1 || number > len(this.Points) {
|
||||
func (p Path) GetPointNumber(number int) Point {
|
||||
if number < 1 || number > len(p.Points) {
|
||||
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.Points = []Point{}
|
||||
for _, p := range path.Points {
|
||||
for _, p := range p.Points {
|
||||
pathcopy.Points = append(pathcopy.Points, p)
|
||||
}
|
||||
return pathcopy
|
||||
}
|
||||
|
||||
func (path Path) Offset(offX, offY float64) Path {
|
||||
for i, p := range path.Points {
|
||||
path.Points[i] = p.Add(offX, offY)
|
||||
func (p Path) Offset(offX, offY float64) Path {
|
||||
for i, pt := range p.Points {
|
||||
p.Points[i] = pt.Add(offX, offY)
|
||||
}
|
||||
return path
|
||||
return p
|
||||
}
|
||||
|
||||
func (path Path) GetBoundingBox() BoundingBox {
|
||||
func (p Path) GetBoundingBox() BoundingBox {
|
||||
bbox := BoundingBox{}
|
||||
|
||||
minX := 0.0
|
||||
maxX := 0.0
|
||||
minY := 0.0
|
||||
maxY := 0.0
|
||||
for idx, p := range path.Points {
|
||||
for idx, p := range p.Points {
|
||||
if idx == 0 {
|
||||
minX = p.X
|
||||
maxX = p.X
|
||||
|
@ -13,10 +13,7 @@ type Point struct {
|
||||
}
|
||||
|
||||
func NewPoint(x, y float64) Point {
|
||||
point := Point{}
|
||||
point.X = x
|
||||
point.Y = y
|
||||
return point
|
||||
return Point{X: x, Y: y}
|
||||
}
|
||||
|
||||
func (p Point) Add(dx, dy float64) Point {
|
||||
@ -25,11 +22,11 @@ func (p Point) Add(dx, dy float64) Point {
|
||||
return p
|
||||
}
|
||||
|
||||
// Add vector to a point.
|
||||
func (this Point) AddVector(v Vector) Point {
|
||||
this.X += v.Dx
|
||||
this.Y += v.Dy
|
||||
return this
|
||||
// AddVector adds vector to a point.
|
||||
func (p Point) AddVector(v Vector) Point {
|
||||
p.X += v.Dx
|
||||
p.Y += v.Dy
|
||||
return p
|
||||
}
|
||||
|
||||
func (p Point) String() string {
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
pdfcontent "github.com/unidoc/unidoc/pdf/contentstream"
|
||||
)
|
||||
|
||||
// Make the path with the content creator.
|
||||
// DrawPathWithCreator makes the path with the content creator.
|
||||
// Adds the PDF commands to draw the path to the creator instance.
|
||||
func DrawPathWithCreator(path Path, creator *pdfcontent.ContentCreator) {
|
||||
for idx, p := range path.Points {
|
||||
@ -16,7 +16,7 @@ func DrawPathWithCreator(path Path, creator *pdfcontent.ContentCreator) {
|
||||
}
|
||||
}
|
||||
|
||||
// Make the bezier path with the content creator.
|
||||
// DrawBezierPathWithCreator makes the bezier path with the content creator.
|
||||
// Adds the PDF commands to draw the path to the creator instance.
|
||||
func DrawBezierPathWithCreator(bpath CubicBezierPath, creator *pdfcontent.ContentCreator) {
|
||||
for idx, c := range bpath.Curves {
|
||||
|
@ -47,14 +47,14 @@ func (v Vector) Rotate(phi float64) Vector {
|
||||
return NewVectorPolar(mag, angle+phi)
|
||||
}
|
||||
|
||||
// Change the sign of the vector: -vector.
|
||||
func (this Vector) Flip() Vector {
|
||||
mag := this.Magnitude()
|
||||
theta := this.GetPolarAngle()
|
||||
// Flip changes the sign of the vector: -vector.
|
||||
func (v Vector) Flip() Vector {
|
||||
mag := v.Magnitude()
|
||||
theta := v.GetPolarAngle()
|
||||
|
||||
this.Dx = mag * math.Cos(theta+math.Pi)
|
||||
this.Dy = mag * math.Sin(theta+math.Pi)
|
||||
return this
|
||||
v.Dx = mag * math.Cos(theta+math.Pi)
|
||||
v.Dy = mag * math.Sin(theta+math.Pi)
|
||||
return v
|
||||
}
|
||||
|
||||
func (v Vector) FlipY() Vector {
|
||||
@ -67,19 +67,19 @@ func (v Vector) FlipX() Vector {
|
||||
return v
|
||||
}
|
||||
|
||||
func (this Vector) Scale(factor float64) Vector {
|
||||
mag := this.Magnitude()
|
||||
theta := this.GetPolarAngle()
|
||||
func (v Vector) Scale(factor float64) Vector {
|
||||
mag := v.Magnitude()
|
||||
theta := v.GetPolarAngle()
|
||||
|
||||
this.Dx = factor * mag * math.Cos(theta)
|
||||
this.Dy = factor * mag * math.Sin(theta)
|
||||
return this
|
||||
v.Dx = factor * mag * math.Cos(theta)
|
||||
v.Dy = factor * mag * math.Sin(theta)
|
||||
return v
|
||||
}
|
||||
|
||||
func (this Vector) Magnitude() float64 {
|
||||
return math.Sqrt(math.Pow(this.Dx, 2.0) + math.Pow(this.Dy, 2.0))
|
||||
func (v Vector) Magnitude() float64 {
|
||||
return math.Sqrt(math.Pow(v.Dx, 2.0) + math.Pow(v.Dy, 2.0))
|
||||
}
|
||||
|
||||
func (this Vector) GetPolarAngle() float64 {
|
||||
return math.Atan2(this.Dy, this.Dx)
|
||||
func (v Vector) GetPolarAngle() float64 {
|
||||
return math.Atan2(v.Dy, v.Dx)
|
||||
}
|
||||
|
@ -301,7 +301,7 @@ func newMultiEncoderFromInlineImage(inlineImage *ContentStreamInlineImage) (*cor
|
||||
// Prepare the decode params array (one for each filter type)
|
||||
// Optional, not always present.
|
||||
var decodeParamsDict *core.PdfObjectDictionary
|
||||
decodeParamsArray := []core.PdfObject{}
|
||||
var decodeParamsArray []core.PdfObject
|
||||
if obj := inlineImage.DecodeParms; obj != nil {
|
||||
// If it is a dictionary, assume it applies to all
|
||||
dict, isDict := obj.(*core.PdfObjectDictionary)
|
||||
@ -360,7 +360,7 @@ func newMultiEncoderFromInlineImage(inlineImage *ContentStreamInlineImage) (*cor
|
||||
}
|
||||
|
||||
if *name == core.StreamEncodingFilterNameFlate || *name == "Fl" {
|
||||
// XXX: need to separate out the DecodeParms..
|
||||
// TODO: need to separate out the DecodeParms..
|
||||
encoder, err := newFlateEncoderFromInlineImage(inlineImage, dParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -15,7 +15,7 @@ import (
|
||||
"github.com/unidoc/unidoc/pdf/model"
|
||||
)
|
||||
|
||||
// A representation of an inline image in a Content stream. Everything between the BI and EI operands.
|
||||
// ContentStreamInlineImage is a representation of an inline image in a Content stream. Everything between the BI and EI operands.
|
||||
// ContentStreamInlineImage implements the core.PdfObject interface although strictly it is not a PDF object.
|
||||
type ContentStreamInlineImage struct {
|
||||
BitsPerComponent core.PdfObject
|
||||
@ -31,7 +31,7 @@ type ContentStreamInlineImage struct {
|
||||
stream []byte
|
||||
}
|
||||
|
||||
// Make a new content stream inline image object from an image.
|
||||
// NewInlineImageFromImage makes a new content stream inline image object from an image.
|
||||
func NewInlineImageFromImage(img model.Image, encoder core.StreamEncoder) (*ContentStreamInlineImage, error) {
|
||||
if encoder == nil {
|
||||
encoder = core.NewRawEncoder()
|
||||
@ -63,7 +63,7 @@ func NewInlineImageFromImage(img model.Image, encoder core.StreamEncoder) (*Cont
|
||||
if filterName != core.StreamEncodingFilterNameRaw {
|
||||
inlineImage.Filter = core.MakeName(filterName)
|
||||
}
|
||||
// XXX/FIXME: Add decode params?
|
||||
// FIXME: Add decode params?
|
||||
|
||||
return &inlineImage, nil
|
||||
}
|
||||
@ -71,39 +71,39 @@ func NewInlineImageFromImage(img model.Image, encoder core.StreamEncoder) (*Cont
|
||||
func (img *ContentStreamInlineImage) String() string {
|
||||
s := fmt.Sprintf("InlineImage(len=%d)\n", len(img.stream))
|
||||
if img.BitsPerComponent != nil {
|
||||
s += "- BPC " + img.BitsPerComponent.DefaultWriteString() + "\n"
|
||||
s += "- BPC " + img.BitsPerComponent.WriteString() + "\n"
|
||||
}
|
||||
if img.ColorSpace != nil {
|
||||
s += "- CS " + img.ColorSpace.DefaultWriteString() + "\n"
|
||||
s += "- CS " + img.ColorSpace.WriteString() + "\n"
|
||||
}
|
||||
if img.Decode != nil {
|
||||
s += "- D " + img.Decode.DefaultWriteString() + "\n"
|
||||
s += "- D " + img.Decode.WriteString() + "\n"
|
||||
}
|
||||
if img.DecodeParms != nil {
|
||||
s += "- DP " + img.DecodeParms.DefaultWriteString() + "\n"
|
||||
s += "- DP " + img.DecodeParms.WriteString() + "\n"
|
||||
}
|
||||
if img.Filter != nil {
|
||||
s += "- F " + img.Filter.DefaultWriteString() + "\n"
|
||||
s += "- F " + img.Filter.WriteString() + "\n"
|
||||
}
|
||||
if img.Height != nil {
|
||||
s += "- H " + img.Height.DefaultWriteString() + "\n"
|
||||
s += "- H " + img.Height.WriteString() + "\n"
|
||||
}
|
||||
if img.ImageMask != nil {
|
||||
s += "- IM " + img.ImageMask.DefaultWriteString() + "\n"
|
||||
s += "- IM " + img.ImageMask.WriteString() + "\n"
|
||||
}
|
||||
if img.Intent != nil {
|
||||
s += "- Intent " + img.Intent.DefaultWriteString() + "\n"
|
||||
s += "- Intent " + img.Intent.WriteString() + "\n"
|
||||
}
|
||||
if img.Interpolate != nil {
|
||||
s += "- I " + img.Interpolate.DefaultWriteString() + "\n"
|
||||
s += "- I " + img.Interpolate.WriteString() + "\n"
|
||||
}
|
||||
if img.Width != nil {
|
||||
s += "- W " + img.Width.DefaultWriteString() + "\n"
|
||||
s += "- W " + img.Width.WriteString() + "\n"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (img *ContentStreamInlineImage) DefaultWriteString() string {
|
||||
func (img *ContentStreamInlineImage) WriteString() string {
|
||||
var output bytes.Buffer
|
||||
|
||||
// We do not start with "BI" as that is the operand and is written out separately.
|
||||
@ -111,34 +111,34 @@ func (img *ContentStreamInlineImage) DefaultWriteString() string {
|
||||
s := ""
|
||||
|
||||
if img.BitsPerComponent != nil {
|
||||
s += "/BPC " + img.BitsPerComponent.DefaultWriteString() + "\n"
|
||||
s += "/BPC " + img.BitsPerComponent.WriteString() + "\n"
|
||||
}
|
||||
if img.ColorSpace != nil {
|
||||
s += "/CS " + img.ColorSpace.DefaultWriteString() + "\n"
|
||||
s += "/CS " + img.ColorSpace.WriteString() + "\n"
|
||||
}
|
||||
if img.Decode != nil {
|
||||
s += "/D " + img.Decode.DefaultWriteString() + "\n"
|
||||
s += "/D " + img.Decode.WriteString() + "\n"
|
||||
}
|
||||
if img.DecodeParms != nil {
|
||||
s += "/DP " + img.DecodeParms.DefaultWriteString() + "\n"
|
||||
s += "/DP " + img.DecodeParms.WriteString() + "\n"
|
||||
}
|
||||
if img.Filter != nil {
|
||||
s += "/F " + img.Filter.DefaultWriteString() + "\n"
|
||||
s += "/F " + img.Filter.WriteString() + "\n"
|
||||
}
|
||||
if img.Height != nil {
|
||||
s += "/H " + img.Height.DefaultWriteString() + "\n"
|
||||
s += "/H " + img.Height.WriteString() + "\n"
|
||||
}
|
||||
if img.ImageMask != nil {
|
||||
s += "/IM " + img.ImageMask.DefaultWriteString() + "\n"
|
||||
s += "/IM " + img.ImageMask.WriteString() + "\n"
|
||||
}
|
||||
if img.Intent != nil {
|
||||
s += "/Intent " + img.Intent.DefaultWriteString() + "\n"
|
||||
s += "/Intent " + img.Intent.WriteString() + "\n"
|
||||
}
|
||||
if img.Interpolate != nil {
|
||||
s += "/I " + img.Interpolate.DefaultWriteString() + "\n"
|
||||
s += "/I " + img.Interpolate.WriteString() + "\n"
|
||||
}
|
||||
if img.Width != nil {
|
||||
s += "/W " + img.Width.DefaultWriteString() + "\n"
|
||||
s += "/W " + img.Width.WriteString() + "\n"
|
||||
}
|
||||
output.WriteString(s)
|
||||
|
||||
@ -198,7 +198,7 @@ func (img *ContentStreamInlineImage) GetEncoder() (core.StreamEncoder, error) {
|
||||
return newEncoderFromInlineImage(img)
|
||||
}
|
||||
|
||||
// Is a mask ?
|
||||
// IsMask checks if an image is a mask.
|
||||
// The image mask entry in the image dictionary specifies that the image data shall be used as a stencil
|
||||
// mask for painting in the current color. The mask data is 1bpc, grayscale.
|
||||
func (img *ContentStreamInlineImage) IsMask() (bool, error) {
|
||||
@ -216,7 +216,7 @@ func (img *ContentStreamInlineImage) IsMask() (bool, error) {
|
||||
|
||||
}
|
||||
|
||||
// Export the inline image to Image which can be transformed or exported easily.
|
||||
// ToImage exports the inline image to Image which can be transformed or exported easily.
|
||||
// Page resources are needed to look up colorspace information.
|
||||
func (img *ContentStreamInlineImage) ToImage(resources *model.PdfPageResources) (*model.Image, error) {
|
||||
// Decode the imaging data if encoded.
|
||||
@ -297,7 +297,7 @@ func (img *ContentStreamInlineImage) ToImage(resources *model.PdfPageResources)
|
||||
return image, nil
|
||||
}
|
||||
|
||||
// Parse an inline image from a content stream, both read its properties and binary data.
|
||||
// ParseInlineImage parses an inline image from a content stream, both reading its properties and binary data.
|
||||
// When called, "BI" has already been read from the stream. This function
|
||||
// finishes reading through "EI" and then returns the ContentStreamInlineImage.
|
||||
func (csp *ContentStreamParser) ParseInlineImage() (*ContentStreamInlineImage, error) {
|
||||
|
@ -255,7 +255,7 @@ func (csp *ContentStreamParser) parseNumber() (core.PdfObject, error) {
|
||||
func (csp *ContentStreamParser) parseString() (*core.PdfObjectString, error) {
|
||||
csp.reader.ReadByte()
|
||||
|
||||
bytes := []byte{}
|
||||
var bytes []byte
|
||||
count := 1
|
||||
for {
|
||||
bb, err := csp.reader.Peek(1)
|
||||
@ -277,7 +277,7 @@ func (csp *ContentStreamParser) parseString() (*core.PdfObjectString, error) {
|
||||
return core.MakeString(string(bytes)), err
|
||||
}
|
||||
|
||||
numeric := []byte{}
|
||||
var numeric []byte
|
||||
numeric = append(numeric, b)
|
||||
for _, val := range bb {
|
||||
if core.IsOctalDigit(val) {
|
||||
@ -340,7 +340,7 @@ func (csp *ContentStreamParser) parseHexString() (*core.PdfObjectString, error)
|
||||
|
||||
hextable := []byte("0123456789abcdefABCDEF")
|
||||
|
||||
tmp := []byte{}
|
||||
var tmp []byte
|
||||
for {
|
||||
csp.skipSpaces()
|
||||
|
||||
@ -495,7 +495,7 @@ func (csp *ContentStreamParser) parseDict() (*core.PdfObjectDictionary, error) {
|
||||
|
||||
// An operand is a text command represented by a word.
|
||||
func (csp *ContentStreamParser) parseOperand() (*core.PdfObjectString, error) {
|
||||
bytes := []byte{}
|
||||
var bytes []byte
|
||||
for {
|
||||
bb, err := csp.reader.Peek(1)
|
||||
if err != nil {
|
||||
|
@ -13,7 +13,7 @@ import (
|
||||
"github.com/unidoc/unidoc/pdf/model"
|
||||
)
|
||||
|
||||
// Basic graphics state implementation.
|
||||
// GraphicsState is a basic graphics state implementation.
|
||||
// Initially only implementing and tracking a portion of the information specified. Easy to add more.
|
||||
type GraphicsState struct {
|
||||
ColorspaceStroking model.PdfColorspace
|
||||
@ -56,12 +56,12 @@ type HandlerEntry struct {
|
||||
|
||||
type HandlerConditionEnum int
|
||||
|
||||
func (this HandlerConditionEnum) All() bool {
|
||||
return this == HandlerConditionEnumAllOperands
|
||||
func (e HandlerConditionEnum) All() bool {
|
||||
return e == HandlerConditionEnumAllOperands
|
||||
}
|
||||
|
||||
func (this HandlerConditionEnum) Operand() bool {
|
||||
return this == HandlerConditionEnumOperand
|
||||
func (e HandlerConditionEnum) Operand() bool {
|
||||
return e == HandlerConditionEnumOperand
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
func makeParamsFromFloats(vals []float64) []core.PdfObject {
|
||||
params := []core.PdfObject{}
|
||||
var params []core.PdfObject
|
||||
for _, val := range vals {
|
||||
params = append(params, core.MakeFloat(val))
|
||||
}
|
||||
@ -22,7 +22,7 @@ func makeParamsFromFloats(vals []float64) []core.PdfObject {
|
||||
}
|
||||
|
||||
func makeParamsFromNames(vals []core.PdfObjectName) []core.PdfObject {
|
||||
params := []core.PdfObject{}
|
||||
var params []core.PdfObject
|
||||
for _, val := range vals {
|
||||
params = append(params, core.MakeName(string(val)))
|
||||
}
|
||||
@ -30,7 +30,7 @@ func makeParamsFromNames(vals []core.PdfObjectName) []core.PdfObject {
|
||||
}
|
||||
|
||||
func makeParamsFromStrings(vals []core.PdfObjectString) []core.PdfObject {
|
||||
params := []core.PdfObject{}
|
||||
var params []core.PdfObject
|
||||
for _, val := range vals {
|
||||
params = append(params, core.MakeString(val.Str()))
|
||||
}
|
||||
@ -38,7 +38,7 @@ func makeParamsFromStrings(vals []core.PdfObjectString) []core.PdfObject {
|
||||
}
|
||||
|
||||
func makeParamsFromInts(vals []int64) []core.PdfObject {
|
||||
params := []core.PdfObject{}
|
||||
var params []core.PdfObject
|
||||
for _, val := range vals {
|
||||
params = append(params, core.MakeInteger(val))
|
||||
}
|
||||
|
@ -315,7 +315,7 @@ func (crypt *PdfCrypt) loadCryptFilters(ed *PdfObjectDictionary) error {
|
||||
crypt.cryptFilters = cryptFilters{}
|
||||
|
||||
obj := ed.Get("CF")
|
||||
obj = TraceToDirectObject(obj) // XXX may need to resolve reference...
|
||||
obj = TraceToDirectObject(obj) // TODO: may need to resolve reference...
|
||||
if ref, isRef := obj.(*PdfObjectReference); isRef {
|
||||
o, err := crypt.parser.LookupByReference(*ref)
|
||||
if err != nil {
|
||||
|
@ -343,7 +343,7 @@ func (parser *PdfParser) parseString() (*PdfObjectString, error) {
|
||||
return MakeString(r.String()), err
|
||||
}
|
||||
|
||||
numeric := []byte{}
|
||||
var numeric []byte
|
||||
numeric = append(numeric, b)
|
||||
for _, val := range bb {
|
||||
if IsOctalDigit(val) {
|
||||
@ -595,7 +595,7 @@ func (parser *PdfParser) parseObject() (PdfObject, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Reads and parses a PDF dictionary object enclosed with '<<' and '>>'
|
||||
// ParseDict reads and parses a PDF dictionary object enclosed with '<<' and '>>'
|
||||
// TODO: Unexport (v3).
|
||||
func (parser *PdfParser) ParseDict() (*PdfObjectDictionary, error) {
|
||||
common.Log.Trace("Reading PDF Dict!")
|
||||
@ -904,7 +904,7 @@ func (parser *PdfParser) parseXrefStream(xstm *PdfObjectInteger) (*PdfObjectDict
|
||||
// Subsections cannot overlap; an object number may have at most
|
||||
// one entry in a section.
|
||||
// Default value: [0 Size].
|
||||
indexList := []int{}
|
||||
var indexList []int
|
||||
if indexObj != nil {
|
||||
common.Log.Trace("Index: %b", indexObj)
|
||||
indicesArray, ok := indexObj.(*PdfObjectArray)
|
||||
@ -1241,7 +1241,7 @@ func (parser *PdfParser) loadXrefs() (*PdfObjectDictionary, error) {
|
||||
}
|
||||
|
||||
// Load old objects also. Only if not already specified.
|
||||
prevList := []int64{}
|
||||
var prevList []int64
|
||||
intInSlice := func(val int64, list []int64) bool {
|
||||
for _, b := range list {
|
||||
if b == val {
|
||||
@ -1331,7 +1331,7 @@ func (parser *PdfParser) traceStreamLength(lengthObj PdfObject) (PdfObject, erro
|
||||
return slo, nil
|
||||
}
|
||||
|
||||
// Parse an indirect object from the input stream. Can also be an object stream.
|
||||
// ParseIndirectObject parses an indirect object from the input stream. Can also be an object stream.
|
||||
// Returns the indirect object (*PdfIndirectObject) or the stream object (*PdfObjectStream).
|
||||
// TODO: Unexport (v3).
|
||||
func (parser *PdfParser) ParseIndirectObject() (PdfObject, error) {
|
||||
@ -1511,7 +1511,7 @@ func (parser *PdfParser) ParseIndirectObject() (PdfObject, error) {
|
||||
return &indirect, nil
|
||||
}
|
||||
|
||||
// For testing purposes.
|
||||
// NewParserFromString is used for testing purposes.
|
||||
// TODO: Unexport (v3) or move to test files, if needed by external test cases.
|
||||
func NewParserFromString(txt string) *PdfParser {
|
||||
parser := PdfParser{}
|
||||
|
@ -92,11 +92,6 @@ func TestNameParsing(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type testStringEntry struct {
|
||||
raw string
|
||||
expected string
|
||||
}
|
||||
|
||||
func BenchmarkStringParsing(b *testing.B) {
|
||||
entry := "(Strings may contain balanced parenthesis () and\nspecial characters (*!&}^% and so on).)"
|
||||
parser := makeParserForText(entry)
|
||||
|
@ -17,11 +17,12 @@ import (
|
||||
|
||||
// PdfObject is an interface which all primitive PDF objects must implement.
|
||||
type PdfObject interface {
|
||||
// Output a string representation of the primitive (for debugging).
|
||||
// String outputs a string representation of the primitive (for debugging).
|
||||
String() string
|
||||
|
||||
// Output the PDF primitive as written to file as expected by the standard.
|
||||
DefaultWriteString() string
|
||||
// WriteString outputs the PDF primitive as written to file as expected by the standard.
|
||||
// TODO(dennwc): it should return a byte slice, or accept a writer
|
||||
WriteString() string
|
||||
}
|
||||
|
||||
// PdfObjectBool represents the primitive PDF boolean object.
|
||||
@ -249,8 +250,8 @@ func (bool *PdfObjectBool) String() string {
|
||||
return "false"
|
||||
}
|
||||
|
||||
// DefaultWriteString outputs the object as it is to be written to file.
|
||||
func (bool *PdfObjectBool) DefaultWriteString() string {
|
||||
// WriteString outputs the object as it is to be written to file.
|
||||
func (bool *PdfObjectBool) WriteString() string {
|
||||
if *bool {
|
||||
return "true"
|
||||
}
|
||||
@ -261,8 +262,8 @@ func (int *PdfObjectInteger) String() string {
|
||||
return fmt.Sprintf("%d", *int)
|
||||
}
|
||||
|
||||
// DefaultWriteString outputs the object as it is to be written to file.
|
||||
func (int *PdfObjectInteger) DefaultWriteString() string {
|
||||
// WriteString outputs the object as it is to be written to file.
|
||||
func (int *PdfObjectInteger) WriteString() string {
|
||||
return fmt.Sprintf("%d", *int)
|
||||
}
|
||||
|
||||
@ -270,8 +271,8 @@ func (float *PdfObjectFloat) String() string {
|
||||
return fmt.Sprintf("%f", *float)
|
||||
}
|
||||
|
||||
// DefaultWriteString outputs the object as it is to be written to file.
|
||||
func (float *PdfObjectFloat) DefaultWriteString() string {
|
||||
// WriteString outputs the object as it is to be written to file.
|
||||
func (float *PdfObjectFloat) WriteString() string {
|
||||
return fmt.Sprintf("%f", *float)
|
||||
}
|
||||
|
||||
@ -305,8 +306,8 @@ func (str *PdfObjectString) Bytes() []byte {
|
||||
return []byte(str.val)
|
||||
}
|
||||
|
||||
// DefaultWriteString outputs the object as it is to be written to file.
|
||||
func (str *PdfObjectString) DefaultWriteString() string {
|
||||
// WriteString outputs the object as it is to be written to file.
|
||||
func (str *PdfObjectString) WriteString() string {
|
||||
var output bytes.Buffer
|
||||
|
||||
// Handle hex representation.
|
||||
@ -350,8 +351,8 @@ func (name *PdfObjectName) String() string {
|
||||
return string(*name)
|
||||
}
|
||||
|
||||
// DefaultWriteString outputs the object as it is to be written to file.
|
||||
func (name *PdfObjectName) DefaultWriteString() string {
|
||||
// WriteString outputs the object as it is to be written to file.
|
||||
func (name *PdfObjectName) WriteString() string {
|
||||
var output bytes.Buffer
|
||||
|
||||
if len(*name) > 127 {
|
||||
@ -429,7 +430,7 @@ func (array *PdfObjectArray) Clear() {
|
||||
// returned if the array contains non-numeric objects (each element can be either PdfObjectInteger
|
||||
// or PdfObjectFloat).
|
||||
func (array *PdfObjectArray) ToFloat64Array() ([]float64, error) {
|
||||
vals := []float64{}
|
||||
var vals []float64
|
||||
|
||||
for _, obj := range array.Elements() {
|
||||
switch t := obj.(type) {
|
||||
@ -448,7 +449,7 @@ func (array *PdfObjectArray) ToFloat64Array() ([]float64, error) {
|
||||
// ToIntegerArray returns a slice of all array elements as an int slice. An error is returned if the
|
||||
// array non-integer objects. Each element can only be PdfObjectInteger.
|
||||
func (array *PdfObjectArray) ToIntegerArray() ([]int, error) {
|
||||
vals := []int{}
|
||||
var vals []int
|
||||
|
||||
for _, obj := range array.Elements() {
|
||||
if number, is := obj.(*PdfObjectInteger); is {
|
||||
@ -464,7 +465,7 @@ func (array *PdfObjectArray) ToIntegerArray() ([]int, error) {
|
||||
// ToInt64Slice returns a slice of all array elements as an int64 slice. An error is returned if the
|
||||
// array non-integer objects. Each element can only be PdfObjectInteger.
|
||||
func (array *PdfObjectArray) ToInt64Slice() ([]int64, error) {
|
||||
vals := []int64{}
|
||||
var vals []int64
|
||||
|
||||
for _, obj := range array.Elements() {
|
||||
if number, is := obj.(*PdfObjectInteger); is {
|
||||
@ -490,11 +491,11 @@ func (array *PdfObjectArray) String() string {
|
||||
return outStr
|
||||
}
|
||||
|
||||
// DefaultWriteString outputs the object as it is to be written to file.
|
||||
func (array *PdfObjectArray) DefaultWriteString() string {
|
||||
// WriteString outputs the object as it is to be written to file.
|
||||
func (array *PdfObjectArray) WriteString() string {
|
||||
outStr := "["
|
||||
for ind, o := range array.Elements() {
|
||||
outStr += o.DefaultWriteString()
|
||||
outStr += o.WriteString()
|
||||
if ind < (array.Len() - 1) {
|
||||
outStr += " "
|
||||
}
|
||||
@ -567,7 +568,7 @@ func getNumberAsFloatOrNull(obj PdfObject) (*float64, error) {
|
||||
// GetAsFloat64Slice returns the array as []float64 slice.
|
||||
// Returns an error if not entirely numeric (only PdfObjectIntegers, PdfObjectFloats).
|
||||
func (array *PdfObjectArray) GetAsFloat64Slice() ([]float64, error) {
|
||||
slice := []float64{}
|
||||
var slice []float64
|
||||
|
||||
for _, obj := range array.Elements() {
|
||||
number, err := GetNumberAsFloat(TraceToDirectObject(obj))
|
||||
@ -601,15 +602,15 @@ func (d *PdfObjectDictionary) String() string {
|
||||
return outStr
|
||||
}
|
||||
|
||||
// DefaultWriteString outputs the object as it is to be written to file.
|
||||
func (d *PdfObjectDictionary) DefaultWriteString() string {
|
||||
// WriteString outputs the object as it is to be written to file.
|
||||
func (d *PdfObjectDictionary) WriteString() string {
|
||||
outStr := "<<"
|
||||
for _, k := range d.keys {
|
||||
v := d.dict[k]
|
||||
common.Log.Trace("Writing k: %s %T %v %v", k, v, k, v)
|
||||
outStr += k.DefaultWriteString()
|
||||
outStr += k.WriteString()
|
||||
outStr += " "
|
||||
outStr += v.DefaultWriteString()
|
||||
outStr += v.WriteString()
|
||||
}
|
||||
outStr += ">>"
|
||||
return outStr
|
||||
@ -742,8 +743,8 @@ func (ref *PdfObjectReference) String() string {
|
||||
return fmt.Sprintf("Ref(%d %d)", ref.ObjectNumber, ref.GenerationNumber)
|
||||
}
|
||||
|
||||
// DefaultWriteString outputs the object as it is to be written to file.
|
||||
func (ref *PdfObjectReference) DefaultWriteString() string {
|
||||
// WriteString outputs the object as it is to be written to file.
|
||||
func (ref *PdfObjectReference) WriteString() string {
|
||||
return fmt.Sprintf("%d %d R", ref.ObjectNumber, ref.GenerationNumber)
|
||||
}
|
||||
|
||||
@ -754,8 +755,8 @@ func (ind *PdfIndirectObject) String() string {
|
||||
return fmt.Sprintf("IObject:%d", (*ind).ObjectNumber)
|
||||
}
|
||||
|
||||
// DefaultWriteString outputs the object as it is to be written to file.
|
||||
func (ind *PdfIndirectObject) DefaultWriteString() string {
|
||||
// WriteString outputs the object as it is to be written to file.
|
||||
func (ind *PdfIndirectObject) WriteString() string {
|
||||
outStr := fmt.Sprintf("%d 0 R", (*ind).ObjectNumber)
|
||||
return outStr
|
||||
}
|
||||
@ -765,8 +766,8 @@ func (stream *PdfObjectStream) String() string {
|
||||
return fmt.Sprintf("Object stream %d: %s", stream.ObjectNumber, stream.PdfObjectDictionary)
|
||||
}
|
||||
|
||||
// DefaultWriteString outputs the object as it is to be written to file.
|
||||
func (stream *PdfObjectStream) DefaultWriteString() string {
|
||||
// WriteString outputs the object as it is to be written to file.
|
||||
func (stream *PdfObjectStream) WriteString() string {
|
||||
outStr := fmt.Sprintf("%d 0 R", (*stream).ObjectNumber)
|
||||
return outStr
|
||||
}
|
||||
@ -776,8 +777,8 @@ func (null *PdfObjectNull) String() string {
|
||||
return "null"
|
||||
}
|
||||
|
||||
// DefaultWriteString outputs the object as it is to be written to file.
|
||||
func (null *PdfObjectNull) DefaultWriteString() string {
|
||||
// WriteString outputs the object as it is to be written to file.
|
||||
func (null *PdfObjectNull) WriteString() string {
|
||||
return "null"
|
||||
}
|
||||
|
||||
@ -876,7 +877,7 @@ func GetStringVal(obj PdfObject) (val string, found bool) {
|
||||
return
|
||||
}
|
||||
|
||||
// GetStringVal is like GetStringVal except that it returns the string as a []byte.
|
||||
// GetStringBytes is like GetStringVal except that it returns the string as a []byte.
|
||||
// It is for convenience.
|
||||
func GetStringBytes(obj PdfObject) (val []byte, found bool) {
|
||||
so, found := TraceToDirectObject(obj).(*PdfObjectString)
|
||||
@ -985,8 +986,8 @@ func (streams *PdfObjectStreams) Len() int {
|
||||
return len(streams.vec)
|
||||
}
|
||||
|
||||
// DefaultWriteString outputs the object as it is to be written to file.
|
||||
func (streams *PdfObjectStreams) DefaultWriteString() string {
|
||||
// WriteString outputs the object as it is to be written to file.
|
||||
func (streams *PdfObjectStreams) WriteString() string {
|
||||
outStr := fmt.Sprintf("%d 0 R", (*streams).ObjectNumber)
|
||||
return outStr
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ func TestHexStringWriteBasic(t *testing.T) {
|
||||
|
||||
for src, expected := range testcases {
|
||||
strObj := MakeHexString(src)
|
||||
ws := strObj.DefaultWriteString()
|
||||
ws := strObj.WriteString()
|
||||
|
||||
if ws != expected {
|
||||
t.Fatalf("%s: '%s' != '%s'\n", src, ws, expected)
|
||||
@ -39,8 +39,8 @@ func TestHexStringMulti(t *testing.T) {
|
||||
shex := MakeHexString(testcase)
|
||||
|
||||
// Write out.
|
||||
writestr := s.DefaultWriteString()
|
||||
writestrhex := shex.DefaultWriteString()
|
||||
writestr := s.WriteString()
|
||||
writestrhex := shex.WriteString()
|
||||
|
||||
// Parse back.
|
||||
parser1 := makeParserForText(writestr)
|
||||
|
@ -38,7 +38,7 @@ func (parser *PdfParser) Inspect() (map[string]int, error) {
|
||||
|
||||
// GetObjectNums returns a sorted list of object numbers of the PDF objects in the file.
|
||||
func (parser *PdfParser) GetObjectNums() []int {
|
||||
objNums := []int{}
|
||||
var objNums []int
|
||||
for _, x := range parser.xrefs {
|
||||
objNums = append(objNums, x.ObjectNumber)
|
||||
}
|
||||
@ -67,7 +67,7 @@ func (parser *PdfParser) inspect() (map[string]int, error) {
|
||||
objCount := 0
|
||||
failedCount := 0
|
||||
|
||||
keys := []int{}
|
||||
var keys []int
|
||||
for k := range parser.xrefs {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ func (blk *Block) duplicate() *Block {
|
||||
// GeneratePageBlocks draws the block contents on a template Page block.
|
||||
// Implements the Drawable interface.
|
||||
func (blk *Block) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||
blocks := []*Block{}
|
||||
var blocks []*Block
|
||||
|
||||
if blk.positioning.isRelative() {
|
||||
// Draw at current ctx.X, ctx.Y position
|
||||
@ -135,7 +135,7 @@ func (blk *Block) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, er
|
||||
cc.Translate(ctx.X, ctx.PageHeight-ctx.Y-blk.height)
|
||||
if blk.angle != 0 {
|
||||
// Make the rotation about the upper left corner.
|
||||
// XXX/TODO: Account for rotation origin. (Consider).
|
||||
// TODO: Account for rotation origin. (Consider).
|
||||
cc.Translate(0, blk.Height())
|
||||
cc.RotateDeg(blk.angle)
|
||||
cc.Translate(0, -blk.Height())
|
||||
@ -154,7 +154,7 @@ func (blk *Block) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, er
|
||||
cc.Translate(blk.xPos, ctx.PageHeight-blk.yPos-blk.height)
|
||||
if blk.angle != 0 {
|
||||
// Make the rotation about the upper left corner.
|
||||
// XXX/TODO: Consider supporting specification of rotation origin.
|
||||
// TODO: Consider supporting specification of rotation origin.
|
||||
cc.Translate(0, blk.Height())
|
||||
cc.RotateDeg(blk.angle)
|
||||
cc.Translate(0, -blk.Height())
|
||||
|
@ -399,7 +399,7 @@ func (c *Creator) finalize() error {
|
||||
}
|
||||
|
||||
blocks, _, _ := c.toc.GeneratePageBlocks(c.context)
|
||||
tocpages := []*model.PdfPage{}
|
||||
var tocpages []*model.PdfPage
|
||||
for _, block := range blocks {
|
||||
block.SetPos(0, 0)
|
||||
totPages++
|
||||
|
@ -60,7 +60,7 @@ const testRobotoRegularTTFFile = "./testdata/roboto/Roboto-Regular.ttf"
|
||||
const testRobotoBoldTTFFile = "./testdata/roboto/Roboto-Bold.ttf"
|
||||
const testWts11TTFFile = "./testdata/wts11.ttf"
|
||||
|
||||
// XXX(peterwilliams97): /tmp/2_p_multi.pdf which is created in this test gives an error message
|
||||
// TODO(peterwilliams97): /tmp/2_p_multi.pdf which is created in this test gives an error message
|
||||
// when opened in Adobe Reader: The font FreeSans contains bad Widths.
|
||||
// This problem did not occur when I replaced FreeSans.ttf with LiberationSans-Regular.ttf
|
||||
const testFreeSansTTFFile = "./testdata/FreeSans.ttf"
|
||||
|
@ -103,7 +103,7 @@ func (div *Division) Width() float64 {
|
||||
// GeneratePageBlocks generates the page blocks for the Division component.
|
||||
// Multiple blocks are generated if the contents wrap over multiple pages.
|
||||
func (div *Division) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||
pageblocks := []*Block{}
|
||||
var pageblocks []*Block
|
||||
|
||||
origCtx := ctx
|
||||
|
||||
|
@ -7,7 +7,7 @@ package creator
|
||||
|
||||
// Drawable is a widget that can be used to draw with the Creator.
|
||||
type Drawable interface {
|
||||
// Draw onto blocks representing Page contents. As the content can wrap over many pages, multiple
|
||||
// GeneratePageBlocks draw onto blocks representing Page contents. As the content can wrap over many pages, multiple
|
||||
// templates are returned, one per Page. The function also takes a draw context containing information
|
||||
// where to draw (if relative positioning) and the available height to draw on accounting for Margins etc.
|
||||
GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error)
|
||||
|
@ -168,7 +168,7 @@ func (img *Image) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, er
|
||||
img.makeXObject()
|
||||
}
|
||||
|
||||
blocks := []*Block{}
|
||||
var blocks []*Block
|
||||
origCtx := ctx
|
||||
|
||||
blk := NewBlock(ctx.PageWidth, ctx.PageHeight)
|
||||
@ -212,7 +212,7 @@ func (img *Image) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, er
|
||||
// Absolute drawing should not affect context.
|
||||
ctx = origCtx
|
||||
} else {
|
||||
// XXX/TODO: Use projected height.
|
||||
// TODO: Use projected height.
|
||||
ctx.Y += img.margins.bottom
|
||||
ctx.Height -= img.margins.bottom
|
||||
}
|
||||
|
@ -69,6 +69,8 @@ type Paragraph struct {
|
||||
// newParagraph create a new text paragraph. Uses default parameters: Helvetica, WinAnsiEncoding and
|
||||
// wrap enabled with a wrap width of 100 points.
|
||||
func newParagraph(text string, style TextStyle) *Paragraph {
|
||||
// TODO(dennwc): style is unused
|
||||
|
||||
p := &Paragraph{}
|
||||
p.text = text
|
||||
|
||||
@ -215,7 +217,7 @@ func (p *Paragraph) getTextWidth() float64 {
|
||||
glyph, found := p.textFont.Encoder().RuneToGlyph(r)
|
||||
if !found {
|
||||
common.Log.Debug("ERROR: Glyph not found for rune: 0x%04x=%c", r, r)
|
||||
return -1 // XXX/FIXME: return error.
|
||||
return -1 // FIXME: return error.
|
||||
}
|
||||
|
||||
// Ignore newline for this.. Handles as if all in one line.
|
||||
@ -226,7 +228,7 @@ func (p *Paragraph) getTextWidth() float64 {
|
||||
metrics, found := p.textFont.GetGlyphCharMetrics(glyph)
|
||||
if !found {
|
||||
common.Log.Debug("ERROR: Glyph char metrics not found! %q (rune 0x%04x=%c)", glyph, r, r)
|
||||
return -1 // XXX/FIXME: return error.
|
||||
return -1 // FIXME: return error.
|
||||
}
|
||||
w += p.fontSize * metrics.Wx
|
||||
}
|
||||
@ -241,7 +243,7 @@ func (p *Paragraph) getTextLineWidth(line string) float64 {
|
||||
glyph, found := p.textFont.Encoder().RuneToGlyph(r)
|
||||
if !found {
|
||||
common.Log.Debug("ERROR: Glyph not found for rune: 0x%04x=%c", r, r)
|
||||
return -1 // XXX/FIXME: return error.
|
||||
return -1 // FIXME: return error.
|
||||
}
|
||||
|
||||
// Ignore newline for this.. Handles as if all in one line.
|
||||
@ -252,7 +254,7 @@ func (p *Paragraph) getTextLineWidth(line string) float64 {
|
||||
metrics, found := p.textFont.GetGlyphCharMetrics(glyph)
|
||||
if !found {
|
||||
common.Log.Debug("ERROR: Glyph char metrics not found! %q (rune 0x%04x=%c)", glyph, r, r)
|
||||
return -1 // XXX/FIXME: return error.
|
||||
return -1 // FIXME: return error.
|
||||
}
|
||||
|
||||
width += p.fontSize * metrics.Wx
|
||||
@ -279,7 +281,7 @@ func (p *Paragraph) getMaxLineWidth() float64 {
|
||||
}
|
||||
|
||||
// Simple algorithm to wrap the text into lines (greedy algorithm - fill the lines).
|
||||
// XXX/TODO: Consider the Knuth/Plass algorithm or an alternative.
|
||||
// TODO: Consider the Knuth/Plass algorithm or an alternative.
|
||||
func (p *Paragraph) wrapText() error {
|
||||
if !p.enableWrap || int(p.wrapWidth) <= 0 {
|
||||
p.textLines = []string{p.text}
|
||||
@ -329,7 +331,7 @@ func (p *Paragraph) wrapText() error {
|
||||
// Breaks on the character.
|
||||
idx := -1
|
||||
for i := len(glyphs) - 1; i >= 0; i-- {
|
||||
if glyphs[i] == "space" { // XXX: What about other space glyphs like controlHT?
|
||||
if glyphs[i] == "space" { // TODO: What about other space glyphs like controlHT?
|
||||
idx = i
|
||||
break
|
||||
}
|
||||
@ -378,7 +380,7 @@ func sum(widths []float64) float64 {
|
||||
// over multiple pages. Implements the Drawable interface.
|
||||
func (p *Paragraph) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||
origContext := ctx
|
||||
blocks := []*Block{}
|
||||
var blocks []*Block
|
||||
|
||||
blk := NewBlock(ctx.PageWidth, ctx.PageHeight)
|
||||
if p.positioning.isRelative() {
|
||||
@ -394,7 +396,7 @@ func (p *Paragraph) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext,
|
||||
if p.Height() > ctx.Height {
|
||||
// Goes out of the bounds. Write on a new template instead and create a new context at
|
||||
// upper left corner.
|
||||
// XXX/TODO: Handle case when Paragraph is larger than the Page...
|
||||
// TODO: Handle case when Paragraph is larger than the Page...
|
||||
// Should be fine if we just break on the paragraph, i.e. splitting it up over 2+ pages
|
||||
|
||||
blocks = append(blocks, blk)
|
||||
@ -507,7 +509,7 @@ func drawParagraphOnBlock(blk *Block, p *Paragraph, ctx DrawContext) (DrawContex
|
||||
w += p.fontSize * metrics.Wx
|
||||
}
|
||||
|
||||
objs := []core.PdfObject{}
|
||||
var objs []core.PdfObject
|
||||
|
||||
spaceMetrics, found := p.textFont.GetGlyphCharMetrics("space")
|
||||
if !found {
|
||||
@ -530,7 +532,7 @@ func drawParagraphOnBlock(blk *Block, p *Paragraph, ctx DrawContext) (DrawContex
|
||||
objs = append(objs, core.MakeFloat(-shift))
|
||||
}
|
||||
|
||||
encoded := []byte{}
|
||||
var encoded []byte
|
||||
isCID := p.textFont.IsCID()
|
||||
for _, r := range runes {
|
||||
glyph, ok := p.textFont.Encoder().RuneToGlyph(r)
|
||||
@ -539,7 +541,7 @@ func drawParagraphOnBlock(blk *Block, p *Paragraph, ctx DrawContext) (DrawContex
|
||||
return ctx, errors.New("Unsupported rune in text encoding")
|
||||
}
|
||||
|
||||
if glyph == "space" { // XXX: What about \t and other spaces.
|
||||
if glyph == "space" { // TODO: What about \t and other spaces.
|
||||
if len(encoded) > 0 {
|
||||
objs = append(objs, core.MakeStringFromBytes(encoded))
|
||||
encoded = []byte{}
|
||||
|
@ -238,7 +238,7 @@ func (p *StyledParagraph) getTextWidth() float64 {
|
||||
if !found {
|
||||
common.Log.Debug("Error! Glyph not found for rune: %s\n", rune)
|
||||
|
||||
// XXX/FIXME: return error.
|
||||
// FIXME: return error.
|
||||
return -1
|
||||
}
|
||||
|
||||
@ -251,7 +251,7 @@ func (p *StyledParagraph) getTextWidth() float64 {
|
||||
if !found {
|
||||
common.Log.Debug("Glyph char metrics not found! %s\n", glyph)
|
||||
|
||||
// XXX/FIXME: return error.
|
||||
// FIXME: return error.
|
||||
return -1
|
||||
}
|
||||
|
||||
@ -273,7 +273,7 @@ func (p *StyledParagraph) getTextLineWidth(line []*TextChunk) float64 {
|
||||
if !found {
|
||||
common.Log.Debug("Error! Glyph not found for rune: %s\n", r)
|
||||
|
||||
// XXX/FIXME: return error.
|
||||
// FIXME: return error.
|
||||
return -1
|
||||
}
|
||||
|
||||
@ -286,7 +286,7 @@ func (p *StyledParagraph) getTextLineWidth(line []*TextChunk) float64 {
|
||||
if !found {
|
||||
common.Log.Debug("Glyph char metrics not found! %s\n", glyph)
|
||||
|
||||
// XXX/FIXME: return error.
|
||||
// FIXME: return error.
|
||||
return -1
|
||||
}
|
||||
|
||||
@ -329,7 +329,7 @@ func (p *StyledParagraph) getTextHeight() float64 {
|
||||
|
||||
// wrapText splits text into lines. It uses a simple greedy algorithm to wrap
|
||||
// fill the lines.
|
||||
// XXX/TODO: Consider the Knuth/Plass algorithm or an alternative.
|
||||
// TODO: Consider the Knuth/Plass algorithm or an alternative.
|
||||
func (p *StyledParagraph) wrapText() error {
|
||||
if !p.enableWrap || int(p.wrapWidth) <= 0 {
|
||||
p.lines = [][]*TextChunk{p.chunks}
|
||||
@ -362,7 +362,7 @@ func (p *StyledParagraph) wrapText() error {
|
||||
if !found {
|
||||
common.Log.Debug("Error! Glyph not found for rune: %v\n", r)
|
||||
|
||||
// XXX/FIXME: return error.
|
||||
// FIXME: return error.
|
||||
return errors.New("Glyph not found for rune")
|
||||
}
|
||||
|
||||
@ -387,8 +387,6 @@ func (p *StyledParagraph) wrapText() error {
|
||||
metrics, found := style.Font.GetGlyphCharMetrics(glyph)
|
||||
if !found {
|
||||
common.Log.Debug("Glyph char metrics not found! %s\n", glyph)
|
||||
|
||||
// XXX/FIXME: return error.
|
||||
return errors.New("Glyph char metrics missing")
|
||||
}
|
||||
|
||||
@ -396,7 +394,7 @@ func (p *StyledParagraph) wrapText() error {
|
||||
if lineWidth+w > p.wrapWidth*1000.0 {
|
||||
// Goes out of bounds: Wrap.
|
||||
// Breaks on the character.
|
||||
// XXX/TODO: when goes outside: back up to next space,
|
||||
// TODO: when goes outside: back up to next space,
|
||||
// otherwise break on the character.
|
||||
idx := -1
|
||||
for j := len(glyphs) - 1; j >= 0; j-- {
|
||||
@ -463,7 +461,7 @@ func (p *StyledParagraph) wrapText() error {
|
||||
// if the contents wrap over multiple pages. Implements the Drawable interface.
|
||||
func (p *StyledParagraph) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||
origContext := ctx
|
||||
blocks := []*Block{}
|
||||
var blocks []*Block
|
||||
|
||||
blk := NewBlock(ctx.PageWidth, ctx.PageHeight)
|
||||
if p.positioning.isRelative() {
|
||||
@ -479,7 +477,7 @@ func (p *StyledParagraph) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawCon
|
||||
if p.Height() > ctx.Height {
|
||||
// Goes out of the bounds. Write on a new template instead and create a new context at upper
|
||||
// left corner.
|
||||
// XXX/TODO: Handle case when Paragraph is larger than the Page...
|
||||
// TODO: Handle case when Paragraph is larger than the Page...
|
||||
// Should be fine if we just break on the paragraph, i.e. splitting it up over 2+ pages
|
||||
|
||||
blocks = append(blocks, blk)
|
||||
@ -549,10 +547,10 @@ func drawStyledParagraphOnBlock(blk *Block, p *StyledParagraph, ctx DrawContext)
|
||||
p.wrapText()
|
||||
|
||||
// Add the fonts of all chunks to the page resources.
|
||||
fonts := [][]core.PdfObjectName{}
|
||||
var fonts [][]core.PdfObjectName
|
||||
|
||||
for _, line := range p.lines {
|
||||
fontLine := []core.PdfObjectName{}
|
||||
var fontLine []core.PdfObjectName
|
||||
|
||||
for _, chunk := range line {
|
||||
fontName = core.PdfObjectName(fmt.Sprintf("Font%d", num))
|
||||
@ -647,7 +645,7 @@ func drawStyledParagraphOnBlock(blk *Block, p *StyledParagraph, ctx DrawContext)
|
||||
height *= p.lineHeight
|
||||
|
||||
// Add line shifts.
|
||||
objs := []core.PdfObject{}
|
||||
var objs []core.PdfObject
|
||||
|
||||
wrapWidth := p.wrapWidth * 1000.0
|
||||
if p.alignment == TextAlignmentJustify {
|
||||
|
@ -65,7 +65,7 @@ func newTable(cols int) *Table {
|
||||
t.rowHeights = []float64{}
|
||||
|
||||
// Default row height
|
||||
// XXX/TODO: Base on contents instead?
|
||||
// TODO: Base on contents instead?
|
||||
t.defaultRowHeight = 10.0
|
||||
|
||||
t.cells = []*TableCell{}
|
||||
@ -152,7 +152,7 @@ func (table *Table) SetPos(x, y float64) {
|
||||
// over multiple pages.
|
||||
// Implements the Drawable interface.
|
||||
func (table *Table) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
|
||||
blocks := []*Block{}
|
||||
var blocks []*Block
|
||||
block := NewBlock(ctx.PageWidth, ctx.PageHeight)
|
||||
|
||||
origCtx := ctx
|
||||
@ -468,10 +468,10 @@ type CellBorderStyle int
|
||||
|
||||
// Currently supported table styles are: None (no border) and boxed (line along each side).
|
||||
const (
|
||||
// No border
|
||||
CellBorderStyleNone CellBorderStyle = iota
|
||||
CellBorderStyleNone CellBorderStyle = iota // no border
|
||||
|
||||
// Borders along all sides (boxed).
|
||||
|
||||
CellBorderStyleSingle
|
||||
CellBorderStyleDouble
|
||||
)
|
||||
@ -501,13 +501,13 @@ type CellHorizontalAlignment int
|
||||
|
||||
// Table cells have three horizontal alignment modes: left, center and right.
|
||||
const (
|
||||
// Align cell content on the left (with specified indent); unused space on the right.
|
||||
// CellHorizontalAlignmentLeft aligns cell content on the left (with specified indent); unused space on the right.
|
||||
CellHorizontalAlignmentLeft CellHorizontalAlignment = iota
|
||||
|
||||
// Align cell content in the middle (unused space divided equally on the left/right).
|
||||
// CellHorizontalAlignmentCenter aligns cell content in the middle (unused space divided equally on the left/right).
|
||||
CellHorizontalAlignmentCenter
|
||||
|
||||
// Align the cell content on the right; unsued space on the left.
|
||||
// CellHorizontalAlignmentRight aligns the cell content on the right; unsued space on the left.
|
||||
CellHorizontalAlignmentRight
|
||||
)
|
||||
|
||||
@ -516,13 +516,13 @@ type CellVerticalAlignment int
|
||||
|
||||
// Table cells have three vertical alignment modes: top, middle and bottom.
|
||||
const (
|
||||
// Align cell content vertically to the top; unused space below.
|
||||
// CellVerticalAlignmentTop aligns cell content vertically to the top; unused space below.
|
||||
CellVerticalAlignmentTop CellVerticalAlignment = iota
|
||||
|
||||
// Align cell content in the middle; unused space divided equally above and below.
|
||||
// CellVerticalAlignmentMiddle aligns cell content in the middle; unused space divided equally above and below.
|
||||
CellVerticalAlignmentMiddle
|
||||
|
||||
// Align cell content on the bottom; unused space above.
|
||||
// CellVerticalAlignmentBottom aligns cell content on the bottom; unused space above.
|
||||
CellVerticalAlignmentBottom
|
||||
)
|
||||
|
||||
|
BIN
pdf/creator/testdata/1-1.png
vendored
Normal file
After Width: | Height: | Size: 83 KiB |
BIN
pdf/creator/testdata/1_dct-1.png
vendored
Normal file
After Width: | Height: | Size: 158 KiB |
BIN
pdf/creator/testdata/1_rotate-1.png
vendored
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
pdf/creator/testdata/1_rotate-2.png
vendored
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
pdf/creator/testdata/1_rotate-3.png
vendored
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
pdf/creator/testdata/1_rotate-4.png
vendored
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
pdf/creator/testdata/1_shapes-1.png
vendored
Normal file
After Width: | Height: | Size: 90 KiB |
BIN
pdf/creator/testdata/1_shapes_on_block-1.png
vendored
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
pdf/creator/testdata/1_shapes_on_block-2.png
vendored
Normal file
After Width: | Height: | Size: 39 KiB |
BIN
pdf/creator/testdata/1_shapes_on_block-3.png
vendored
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
pdf/creator/testdata/1_wrap-1.png
vendored
Normal file
After Width: | Height: | Size: 142 KiB |
BIN
pdf/creator/testdata/1_wrap-2.png
vendored
Normal file
After Width: | Height: | Size: 148 KiB |
BIN
pdf/creator/testdata/1_wrap-3.png
vendored
Normal file
After Width: | Height: | Size: 188 KiB |
BIN
pdf/creator/testdata/1_wrap-4.png
vendored
Normal file
After Width: | Height: | Size: 196 KiB |
BIN
pdf/creator/testdata/1_wrap-5.png
vendored
Normal file
After Width: | Height: | Size: 184 KiB |
BIN
pdf/creator/testdata/1_wrap-6.png
vendored
Normal file
After Width: | Height: | Size: 208 KiB |
BIN
pdf/creator/testdata/1_wrap-7.png
vendored
Normal file
After Width: | Height: | Size: 119 KiB |
BIN
pdf/creator/testdata/2_p1-1.png
vendored
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
pdf/creator/testdata/2_pArial-1.png
vendored
Normal file
After Width: | Height: | Size: 249 KiB |
BIN
pdf/creator/testdata/2_p_multi-1.png
vendored
Normal file
After Width: | Height: | Size: 107 KiB |
BIN
pdf/creator/testdata/2_p_nihao-1.png
vendored
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
pdf/creator/testdata/2_standard14fonts-1.png
vendored
Normal file
After Width: | Height: | Size: 93 KiB |
BIN
pdf/creator/testdata/3_barcode_qr_newpage-1.png
vendored
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
pdf/creator/testdata/3_chapters_margins-1.png
vendored
Normal file
After Width: | Height: | Size: 273 KiB |
BIN
pdf/creator/testdata/3_chapters_margins-2.png
vendored
Normal file
After Width: | Height: | Size: 304 KiB |
BIN
pdf/creator/testdata/3_chapters_margins-3.png
vendored
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
pdf/creator/testdata/3_subchapters_simple-1.png
vendored
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
pdf/creator/testdata/3_subchapters_simple-2.png
vendored
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
pdf/creator/testdata/3_subchapters_simple-3.png
vendored
Normal file
After Width: | Height: | Size: 280 KiB |
BIN
pdf/creator/testdata/3_subchapters_simple-4.png
vendored
Normal file
After Width: | Height: | Size: 225 KiB |
BIN
pdf/creator/testdata/4_barcode_on_tpl-1.png
vendored
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
pdf/creator/testdata/4_barcode_on_tpl-2.png
vendored
Normal file
After Width: | Height: | Size: 224 KiB |
BIN
pdf/creator/testdata/4_headers-1.png
vendored
Normal file
After Width: | Height: | Size: 281 KiB |
BIN
pdf/creator/testdata/4_headers-2.png
vendored
Normal file
After Width: | Height: | Size: 306 KiB |
BIN
pdf/creator/testdata/4_headers-3.png
vendored
Normal file
After Width: | Height: | Size: 306 KiB |
BIN
pdf/creator/testdata/4_headers-4.png
vendored
Normal file
After Width: | Height: | Size: 306 KiB |
BIN
pdf/creator/testdata/4_headers-5.png
vendored
Normal file
After Width: | Height: | Size: 306 KiB |
BIN
pdf/creator/testdata/4_headers-6.png
vendored
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
pdf/creator/testdata/4_table-1.png
vendored
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
pdf/creator/testdata/4_table_bordered-1.png
vendored
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
pdf/creator/testdata/4_table_bordered2-1.png
vendored
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
pdf/creator/testdata/4_tables_in_subchap-1.png
vendored
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
pdf/creator/testdata/cell-1.png
vendored
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
pdf/creator/testdata/diff.png
vendored
Normal file
After Width: | Height: | Size: 106 KiB |
BIN
pdf/creator/testdata/hendricks-1.png
vendored
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
pdf/creator/testdata/rotate_2-1.png
vendored
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
pdf/creator/testdata/table_border_req1_test-1.png
vendored
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
pdf/creator/testdata/tablecell_wrap-1.png
vendored
Normal file
After Width: | Height: | Size: 101 KiB |
BIN
pdf/creator/testdata/tablecell_wrap_out_p001.png
vendored
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
pdf/creator/testdata/template_1-1.png
vendored
Normal file
After Width: | Height: | Size: 31 KiB |
@ -156,11 +156,11 @@ func (tl *TOCLine) prepareParagraph(sp *StyledParagraph, ctx DrawContext) {
|
||||
|
||||
sp.chunks = []*TextChunk{
|
||||
&tl.Number,
|
||||
&TextChunk{
|
||||
{
|
||||
Text: title,
|
||||
Style: tl.Title.Style,
|
||||
},
|
||||
&TextChunk{
|
||||
{
|
||||
Text: page,
|
||||
Style: tl.Page.Style,
|
||||
},
|
||||
|
@ -31,7 +31,7 @@ func loadPagesFromFile(path string) ([]*model.PdfPage, error) {
|
||||
}
|
||||
|
||||
// Load the pages.
|
||||
pages := []*model.PdfPage{}
|
||||
var pages []*model.PdfPage
|
||||
for i := 0; i < numPages; i++ {
|
||||
page, err := pdfReader.GetPage(i + 1)
|
||||
if err != nil {
|
||||
|
@ -380,7 +380,7 @@ func (to *textObject) setFont(name string, size float64) error {
|
||||
(*to.fontStack)[len(*to.fontStack)-1] = font
|
||||
}
|
||||
} else if err == model.ErrFontNotSupported {
|
||||
// XXX: Do we need to handle this case in a special way?
|
||||
// TODO: Do we need to handle this case in a special way?
|
||||
return err
|
||||
} else {
|
||||
return err
|
||||
@ -644,7 +644,7 @@ func (to *textObject) getFont(name string) (*model.PdfFont, error) {
|
||||
|
||||
// Eject a victim if the cache is full.
|
||||
if len(to.e.fontCache) >= maxFontCache {
|
||||
names := []string{}
|
||||
var names []string
|
||||
for name := range to.e.fontCache {
|
||||
names = append(names, name)
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ func (fdf *Data) FieldValues() (map[string]core.PdfObject, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keys := []string{}
|
||||
var keys []string
|
||||
for fieldName := range fieldDictMap {
|
||||
keys = append(keys, fieldName)
|
||||
}
|
||||
|
@ -28,7 +28,6 @@ var reNumeric = regexp.MustCompile(`^[\+-.]*([0-9.]+)`)
|
||||
var reExponential = regexp.MustCompile(`^[\+-.]*([0-9.]+)e[\+-.]*([0-9.]+)`)
|
||||
var reReference = regexp.MustCompile(`^\s*(\d+)\s+(\d+)\s+R`)
|
||||
var reIndirectObject = regexp.MustCompile(`(\d+)\s+(\d+)\s+obj`)
|
||||
var reTrailer = regexp.MustCompile(`trailer`)
|
||||
|
||||
// fdfParser parses a FDF file and provides access to the object structure of the FDF.
|
||||
type fdfParser struct {
|
||||
|
@ -68,7 +68,7 @@ func NewToUnicodeCMap(codeToUnicode map[CharCode]rune) *CMap {
|
||||
Ordering: "UCS",
|
||||
Supplement: 0,
|
||||
},
|
||||
codespaces: []Codespace{Codespace{Low: 0, High: 0xffff}},
|
||||
codespaces: []Codespace{{Low: 0, High: 0xffff}},
|
||||
codeToUnicode: codeToUnicode,
|
||||
}
|
||||
}
|
||||
@ -318,14 +318,14 @@ func (cmap *CMap) toBfData() string {
|
||||
}
|
||||
|
||||
// codes is a sorted list of the codeToUnicode keys.
|
||||
codes := []CharCode{}
|
||||
var codes []CharCode
|
||||
for code := range cmap.codeToUnicode {
|
||||
codes = append(codes, code)
|
||||
}
|
||||
sort.Slice(codes, func(i, j int) bool { return codes[i] < codes[j] })
|
||||
|
||||
// charRanges is a list of the contiguous character code ranges in `codes`.
|
||||
charRanges := []charRange{}
|
||||
var charRanges []charRange
|
||||
c0, c1 := codes[0], codes[0]+1
|
||||
for _, c := range codes[1:] {
|
||||
if c != c1 {
|
||||
@ -339,8 +339,8 @@ func (cmap *CMap) toBfData() string {
|
||||
}
|
||||
|
||||
// fbChars is a list of single character ranges. fbRanges is a list of multiple character ranges.
|
||||
fbChars := []CharCode{}
|
||||
fbRanges := []fbRange{}
|
||||
var fbChars []CharCode
|
||||
var fbRanges []fbRange
|
||||
for _, cr := range charRanges {
|
||||
if cr.code0+1 == cr.code1 {
|
||||
fbChars = append(fbChars, cr.code0)
|
||||
@ -355,7 +355,7 @@ func (cmap *CMap) toBfData() string {
|
||||
common.Log.Trace("charRanges=%d fbChars=%d fbRanges=%d", len(charRanges), len(fbChars),
|
||||
len(fbRanges))
|
||||
|
||||
lines := []string{}
|
||||
var lines []string
|
||||
if len(fbChars) > 0 {
|
||||
numRanges := (len(fbChars) + maxBfEntries - 1) / maxBfEntries
|
||||
for i := 0; i < numRanges; i++ {
|
||||
|
@ -672,12 +672,12 @@ func checkCmapWriteRead(t *testing.T, codeToUnicode map[CharCode]rune) {
|
||||
return
|
||||
}
|
||||
|
||||
codes0 := []CharCode{}
|
||||
codes0 := make([]CharCode, 0, len(codeToUnicode))
|
||||
for code := range codeToUnicode {
|
||||
codes0 = append(codes0, code)
|
||||
}
|
||||
sort.Slice(codes0, func(i, j int) bool { return codes0[i] < codes0[j] })
|
||||
codes := []CharCode{}
|
||||
codes := make([]CharCode, 0, len(cmap.codeToUnicode))
|
||||
for code := range cmap.codeToUnicode {
|
||||
codes = append(codes, code)
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ package cmap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -34,5 +33,3 @@ const (
|
||||
cmaptype = "CMapType"
|
||||
cmapversion = "CMapVersion"
|
||||
)
|
||||
|
||||
var reNumeric = regexp.MustCompile(`^[\+-.]*([0-9.]+)`)
|
||||
|
@ -203,7 +203,7 @@ func (p *cMapParser) parseString() (cmapString, error) {
|
||||
return cmapString{buf.String()}, err
|
||||
}
|
||||
|
||||
numeric := []byte{}
|
||||
var numeric []byte
|
||||
numeric = append(numeric, b)
|
||||
for _, val := range bb {
|
||||
if core.IsOctalDigit(val) {
|
||||
|
@ -5,10 +5,10 @@
|
||||
|
||||
package sampling
|
||||
|
||||
// Resample the raw data which is in 8-bit (byte) format as a different
|
||||
// ResampleBytes resamples the raw data which is in 8-bit (byte) format as a different
|
||||
// bit count per sample, up to 32 bits (uint32).
|
||||
func ResampleBytes(data []byte, bitsPerSample int) []uint32 {
|
||||
samples := []uint32{}
|
||||
var samples []uint32
|
||||
|
||||
bitsLeftPerSample := bitsPerSample
|
||||
var sample uint32
|
||||
@ -96,13 +96,13 @@ func ResampleBytes(data []byte, bitsPerSample int) []uint32 {
|
||||
return samples
|
||||
}
|
||||
|
||||
// Resample the raw data which is in <=32-bit (uint32) format as a different
|
||||
// ResampleUint32 resamples the raw data which is in <=32-bit (uint32) format as a different
|
||||
// bit count per sample, up to 32 bits (uint32).
|
||||
//
|
||||
// bitsPerOutputSample is the number of bits for each output sample (up to 32)
|
||||
// bitsPerInputSample is the number of bits used in each input sample (up to 32)
|
||||
func ResampleUint32(data []uint32, bitsPerInputSample int, bitsPerOutputSample int) []uint32 {
|
||||
samples := []uint32{}
|
||||
var samples []uint32
|
||||
|
||||
bitsLeftPerSample := bitsPerOutputSample
|
||||
var sample uint32
|
||||
|
@ -60,7 +60,7 @@ func StringToUTF16(s string) string {
|
||||
|
||||
// PDFDocEncodingToRunes decodes PDFDocEncoded byte slice `b` to unicode runes.
|
||||
func PDFDocEncodingToRunes(b []byte) []rune {
|
||||
runes := []rune{}
|
||||
var runes []rune
|
||||
for _, bval := range b {
|
||||
rune, has := pdfDocEncoding[bval]
|
||||
if !has {
|
||||
|
@ -86,7 +86,7 @@ func resolveReferences(obj core.PdfObject, objmap map[int64]core.PdfObject) erro
|
||||
func CompareDictionariesDeep(d1, d2 *core.PdfObjectDictionary) bool {
|
||||
if len(d1.Keys()) != len(d2.Keys()) {
|
||||
common.Log.Debug("Dict entries mismatch (%d != %d)", len(d1.Keys()), len(d2.Keys()))
|
||||
common.Log.Debug("Was '%s' vs '%s'", d1.DefaultWriteString(), d2.DefaultWriteString())
|
||||
common.Log.Debug("Was '%s' vs '%s'", d1.WriteString(), d2.WriteString())
|
||||
return false
|
||||
}
|
||||
|
||||
@ -140,8 +140,8 @@ func CompareDictionariesDeep(d1, d2 *core.PdfObjectDictionary) bool {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
if v1.DefaultWriteString() != v2.DefaultWriteString() {
|
||||
common.Log.Debug("Mismatch '%s' != '%s'", v1.DefaultWriteString(), v2.DefaultWriteString())
|
||||
if v1.WriteString() != v2.WriteString() {
|
||||
common.Log.Debug("Mismatch '%s' != '%s'", v1.WriteString(), v2.WriteString())
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ func (cmap CMapIdentityH) CharacterCodesToCID(raw []byte) ([]CID, error) {
|
||||
return nil, core.ErrRangeError
|
||||
}
|
||||
|
||||
cids := []CID{}
|
||||
var cids []CID
|
||||
for i := 0; i < len(raw); i += 2 {
|
||||
b1 := CID(raw[i])
|
||||
b2 := CID(raw[i+1])
|
||||
|
@ -21,13 +21,13 @@ import (
|
||||
const MissingCodeRune = '\ufffd' // <20>
|
||||
|
||||
// GlyphToRune returns the rune corresponding to glyph `glyph` if there is one.
|
||||
// XXX: TODO: Can we return a string here? e.g. When we are extracting text, we want to get "ffi"
|
||||
// TODO: Can we return a string here? e.g. When we are extracting text, we want to get "ffi"
|
||||
// rather than 'ffi'. We only need a glyph ➞ rune map when we need to convert back to
|
||||
// glyphs.
|
||||
// We are currently applying RuneToString to the output of functions that call
|
||||
// GlyphToRune. While this gives the same result, it makes the calling code complex and
|
||||
// fragile.
|
||||
// XXX: TODO: Can we combine all the tables glyphAliases, glyphlistGlyphToRuneMap,
|
||||
// TODO: Can we combine all the tables glyphAliases, glyphlistGlyphToRuneMap,
|
||||
// texGlyphlistGlyphToStringMap, additionalGlyphlistGlyphToRuneMap and ".notdef"?
|
||||
func GlyphToRune(glyph GlyphName) (rune, bool) {
|
||||
// We treat glyph "eight.lf" the same as glyph "eight".
|
||||
|