Skip to content

Commit 4187510

Browse files
authored
Merge pull request #140 from gunnsth/release/v3.1.1
Release unipdf v3.1.1
2 parents c5c8eab + 55a64a5 commit 4187510

File tree

17 files changed

+276
-179
lines changed

17 files changed

+276
-179
lines changed

README.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ creating and reading, processing PDF files. The library is written and supported
2121
- [Rotate pages](https://github.com/unidoc/unipdf-examples/blob/v3/pages/pdf_rotate.go)
2222
- [Extract text from PDF files](https://github.com/unidoc/unipdf-examples/blob/v3/text/pdf_extract_text.go)
2323
- [Text extraction support with size, position and formatting info](https://github.com/unidoc/unipdf-examples/blob/v3/text/pdf_text_locations.go)
24+
- [PDF to CSV](https://github.com/unidoc/unipdf-examples/blob/v3/text/pdf_to_csv.go) illustrates extracting tabular data from PDF.
2425
- [Extract images](https://github.com/unidoc/unipdf-examples/blob/v3/image/pdf_extract_images.go) with coordinates
2526
- [Images to PDF](https://github.com/unidoc/unipdf-examples/blob/v3/image/pdf_images_to_pdf.go)
2627
- [Add images to pages](https://github.com/unidoc/unipdf-examples/blob/v3/image/pdf_add_image_to_page.go)
@@ -42,12 +43,6 @@ as well as [documented examples](https://unidoc.io/examples) on our website.
4243

4344
Contact us if you need any specific examples.
4445

45-
## News
46-
- unidoc has been renamed to unipdf and is maintained under https://github.com/unidoc/unipdf
47-
- The old repository remains under https://github.com/unidoc/unidoc for backwards compatibility and will be read-only.
48-
All development is under the unipdf repository.
49-
- The initial release of unipdf v3.0.0 is compatible with Go modules from the start.
50-
5146
## Installation
5247
With modules:
5348
~~~
@@ -111,10 +106,18 @@ To use unipdf in your projects, you need to get a license.
111106

112107
Get your license on [https://unidoc.io](https://unidoc.io).
113108

114-
To load your license, simply do:
109+
The easiest way to load your license is through environment variables, for example:
110+
```bash
111+
export UNIPDF_CUSTOMER_NAME=UniDoc
112+
export UNIPDF_LICENSE_PATH=/path/to/licenses/UniDoc.txt
113+
```
114+
115+
Alternatively you can load the license in code, simply do:
115116
```go
116-
unidocLicenseKey := "... your license here ..."
117-
err := license.SetLicenseKey(unidocLicenseKey)
117+
licenseKey := "... your license here ..."
118+
customerName := `name of license holder`
119+
120+
err := license.SetLicenseKey(licenseKey, customerName)
118121
if err != nil {
119122
fmt.Printf("Error loading license: %v\n", err)
120123
os.Exit(1)

annotator/field_appearance.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ func genFieldTextAppearance(wa *model.PdfAnnotationWidget, ftxt *model.PdfFieldT
245245

246246
// If fontname not set need to make a new font or use one defined in the resources.
247247
// e.g. Helv commonly used for Helvetica.
248-
if fontname == nil {
248+
if fontname == nil || dr == nil {
249249
// Font not set, revert to Helvetica with name "Helv".
250250
fontname = core.MakeName("Helv")
251251
helv, err := model.NewStandard14Font("Helvetica")
@@ -565,7 +565,7 @@ func genFieldTextCombAppearance(wa *model.PdfAnnotationWidget, ftxt *model.PdfFi
565565

566566
// If fontname not set need to make a new font or use one defined in the resources.
567567
// e.g. Helv commonly used for Helvetica.
568-
if fontname == nil {
568+
if fontname == nil || dr == nil {
569569
// Font not set, revert to Helvetica with name "Helv".
570570
fontname = core.MakeName("Helv")
571571
helv, err := model.NewStandard14Font("Helvetica")
@@ -940,7 +940,7 @@ func makeComboboxTextXObjForm(width, height float64, text string, style Appearan
940940

941941
// If fontname not set need to make a new font or use one defined in the resources.
942942
// e.g. Helv commonly used for Helvetica.
943-
if fontname == nil {
943+
if fontname == nil || dr == nil {
944944
// Font not set, revert to Helvetica with name "Helv".
945945
fontname = core.MakeName("Helv")
946946
helv, err := model.NewStandard14Font("Helvetica")

common/license/util.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,14 @@ package license
88

99
import (
1010
"fmt"
11+
"io/ioutil"
12+
"os"
1113
"strings"
14+
15+
"github.com/unidoc/unipdf/v3/common"
1216
)
1317

14-
// Defaults to the open source license.
18+
// Defaults to unlicensed.
1519
var licenseKey = MakeUnlicensedKey()
1620

1721
// SetLicenseKey sets and validates the license key.
@@ -35,6 +39,29 @@ func SetLicenseKey(content string, customerName string) error {
3539
return nil
3640
}
3741

42+
const licensePathEnvironmentVar = `UNIPDF_LICENSE_PATH`
43+
const licenseCustomerNameEnvironmentVar = `UNIPDF_CUSTOMER_NAME`
44+
45+
func init() {
46+
lpath := os.Getenv(licensePathEnvironmentVar)
47+
custName := os.Getenv(licenseCustomerNameEnvironmentVar)
48+
49+
if len(lpath) == 0 || len(custName) == 0 {
50+
return
51+
}
52+
53+
data, err := ioutil.ReadFile(lpath)
54+
if err != nil {
55+
common.Log.Debug("Unable to read license file: %v", err)
56+
return
57+
}
58+
err = SetLicenseKey(string(data), custName)
59+
if err != nil {
60+
common.Log.Debug("Unable to load license: %v", err)
61+
return
62+
}
63+
}
64+
3865
func GetLicenseKey() *LicenseKey {
3966
if licenseKey == nil {
4067
return nil

common/version.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ import (
1111
)
1212

1313
const releaseYear = 2019
14-
const releaseMonth = 7
15-
const releaseDay = 18
16-
const releaseHour = 19
14+
const releaseMonth = 8
15+
const releaseDay = 4
16+
const releaseHour = 11
1717
const releaseMin = 40
1818

1919
// Version holds version information, when bumping this make sure to bump the released at stamp also.
20-
const Version = "3.1.0"
20+
const Version = "3.1.1"
2121

2222
var ReleasedAt = time.Date(releaseYear, releaseMonth, releaseDay, releaseHour, releaseMin, 0, 0, time.UTC)

core/primitives.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ func GetNumberAsFloat(obj PdfObject) (float64, error) {
541541

542542
// IsNullObject returns true if `obj` is a PdfObjectNull.
543543
func IsNullObject(obj PdfObject) bool {
544-
_, isNull := obj.(*PdfObjectNull)
544+
_, isNull := TraceToDirectObject(obj).(*PdfObjectNull)
545545
return isNull
546546
}
547547

creator/block.go

Lines changed: 44 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,19 @@ func NewBlockFromPage(page *model.PdfPage) (*Block, error) {
9393
b.width = mbox.Urx - mbox.Llx
9494
b.height = mbox.Ury - mbox.Lly
9595

96+
// Inherit page rotation angle.
97+
if page.Rotate != nil {
98+
b.angle = -float64(*page.Rotate)
99+
}
100+
96101
return b, nil
97102
}
98103

104+
// Angle returns the block rotation angle in degrees.
105+
func (blk *Block) Angle() float64 {
106+
return blk.angle
107+
}
108+
99109
// SetAngle sets the rotation angle in degrees.
100110
func (blk *Block) SetAngle(angleDeg float64) {
101111
blk.angle = angleDeg
@@ -132,47 +142,39 @@ func (blk *Block) duplicate() *Block {
132142
// GeneratePageBlocks draws the block contents on a template Page block.
133143
// Implements the Drawable interface.
134144
func (blk *Block) GeneratePageBlocks(ctx DrawContext) ([]*Block, DrawContext, error) {
135-
var blocks []*Block
145+
cc := contentstream.NewContentCreator()
136146

147+
// Position block.
148+
blkWidth, blkHeight := blk.Width(), blk.Height()
137149
if blk.positioning.isRelative() {
138-
// Draw at current ctx.X, ctx.Y position
139-
dup := blk.duplicate()
140-
cc := contentstream.NewContentCreator()
141-
cc.Translate(ctx.X, ctx.PageHeight-ctx.Y-blk.height)
142-
if blk.angle != 0 {
143-
// Make the rotation about the upper left corner.
144-
// TODO: Account for rotation origin. (Consider).
145-
cc.Translate(0, blk.Height())
146-
cc.RotateDeg(blk.angle)
147-
cc.Translate(0, -blk.Height())
148-
}
149-
contents := append(*cc.Operations(), *dup.contents...)
150-
contents.WrapIfNeeded()
151-
dup.contents = &contents
150+
// Relative. Draw at current ctx.X, ctx.Y position.
151+
cc.Translate(ctx.X, ctx.PageHeight-ctx.Y-blkHeight)
152+
} else {
153+
// Absolute. Draw at blk.xPos, blk.yPos position.
154+
cc.Translate(blk.xPos, ctx.PageHeight-blk.yPos-blkHeight)
155+
}
152156

153-
blocks = append(blocks, dup)
157+
// Rotate block.
158+
rotatedHeight := blkHeight
159+
if blk.angle != 0 {
160+
// Make the rotation about the center of the block.
161+
cc.Translate(blkWidth/2, blkHeight/2)
162+
cc.RotateDeg(blk.angle)
163+
cc.Translate(-blkWidth/2, -blkHeight/2)
154164

155-
ctx.Y += blk.height
156-
} else {
157-
// Absolute. Draw at blk.xPos, blk.yPos position
158-
dup := blk.duplicate()
159-
cc := contentstream.NewContentCreator()
160-
cc.Translate(blk.xPos, ctx.PageHeight-blk.yPos-blk.height)
161-
if blk.angle != 0 {
162-
// Make the rotation about the upper left corner.
163-
// TODO: Consider supporting specification of rotation origin.
164-
cc.Translate(0, blk.Height())
165-
cc.RotateDeg(blk.angle)
166-
cc.Translate(0, -blk.Height())
167-
}
168-
contents := append(*cc.Operations(), *dup.contents...)
169-
contents.WrapIfNeeded()
170-
dup.contents = &contents
165+
_, rotatedHeight = blk.RotatedSize()
166+
}
171167

172-
blocks = append(blocks, dup)
168+
if blk.positioning.isRelative() {
169+
ctx.Y += rotatedHeight
173170
}
174171

175-
return blocks, ctx, nil
172+
dup := blk.duplicate()
173+
contents := append(*cc.Operations(), *dup.contents...)
174+
contents.WrapIfNeeded()
175+
dup.contents = &contents
176+
177+
return []*Block{dup}, ctx, nil
176178
}
177179

178180
// Height returns the Block's height.
@@ -185,6 +187,12 @@ func (blk *Block) Width() float64 {
185187
return blk.width
186188
}
187189

190+
// RotatedSize returns the width and height of the rotated block.
191+
func (blk *Block) RotatedSize() (float64, float64) {
192+
_, _, w, h := rotateRect(blk.width, blk.height, blk.angle)
193+
return w, h
194+
}
195+
188196
// addContents adds contents to a block. Wrap both existing and new contents to ensure
189197
// independence of content operations.
190198
func (blk *Block) addContents(operations *contentstream.ContentStreamOperations) {
@@ -335,8 +343,7 @@ func (blk *Block) Draw(d Drawable) error {
335343
}
336344

337345
for _, newBlock := range blocks {
338-
err := mergeContents(blk.contents, blk.resources, newBlock.contents, newBlock.resources)
339-
if err != nil {
346+
if err := blk.mergeBlocks(newBlock); err != nil {
340347
return err
341348
}
342349
}
@@ -356,8 +363,7 @@ func (blk *Block) DrawWithContext(d Drawable, ctx DrawContext) error {
356363
}
357364

358365
for _, newBlock := range blocks {
359-
err := mergeContents(blk.contents, blk.resources, newBlock.contents, newBlock.resources)
360-
if err != nil {
366+
if err := blk.mergeBlocks(newBlock); err != nil {
361367
return err
362368
}
363369
}

creator/creator.go

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import (
2020
// content onto imported PDF pages, etc.
2121
type Creator struct {
2222
pages []*model.PdfPage
23+
pageBlocks map[*model.PdfPage]*Block
24+
2325
activePage *model.PdfPage
2426

2527
pagesize PageSize
@@ -116,6 +118,7 @@ type margins struct {
116118
func New() *Creator {
117119
c := &Creator{}
118120
c.pages = []*model.PdfPage{}
121+
c.pageBlocks = map[*model.PdfPage]*Block{}
119122
c.SetPageSize(PageSizeLetter)
120123

121124
m := 0.1 * c.pageWidth
@@ -513,6 +516,15 @@ func (c *Creator) finalize() error {
513516
return err
514517
}
515518
}
519+
520+
// Draw blocks to pages.
521+
block, ok := c.pageBlocks[page]
522+
if !ok {
523+
return errors.New("could not find page block")
524+
}
525+
if err := block.drawToPage(page); err != nil {
526+
return err
527+
}
516528
}
517529

518530
c.finalized = true
@@ -559,15 +571,21 @@ func (c *Creator) Draw(d Drawable) error {
559571
return err
560572
}
561573

562-
for idx, blk := range blocks {
574+
for idx, block := range blocks {
563575
if idx > 0 {
564576
c.NewPage()
565577
}
566578

567-
p := c.getActivePage()
568-
err := blk.drawToPage(p)
569-
if err != nil {
570-
return err
579+
page := c.getActivePage()
580+
if pageBlock, ok := c.pageBlocks[page]; ok {
581+
if err := pageBlock.mergeBlocks(block); err != nil {
582+
return err
583+
}
584+
if err := mergeResources(block.resources, pageBlock.resources); err != nil {
585+
return err
586+
}
587+
} else {
588+
c.pageBlocks[page] = block
571589
}
572590
}
573591

0 commit comments

Comments
 (0)