mirror of
https://github.com/unidoc/unipdf.git
synced 2025-04-24 13:48:49 +08:00
Add low level PageLabels support (#325)
* Add reader method for retriving the PageLabels entry from the catalog * Add writer method for setting the PageLabels entry in the catalog. * Add creator method for adding page labels for the output file * Add creator page labels test case * Minor page labels test case correction
This commit is contained in:
parent
a69d788171
commit
cb0166e96b
@ -13,6 +13,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/unidoc/unipdf/v3/common"
|
||||
"github.com/unidoc/unipdf/v3/core"
|
||||
"github.com/unidoc/unipdf/v3/model"
|
||||
)
|
||||
|
||||
@ -62,6 +63,10 @@ type Creator struct {
|
||||
// Forms.
|
||||
acroForm *model.PdfAcroForm
|
||||
|
||||
// Page labels.
|
||||
pageLabels core.PdfObject
|
||||
|
||||
// Optimizer.
|
||||
optimizer model.Optimizer
|
||||
|
||||
// Default fonts used by all components instantiated through the creator.
|
||||
@ -82,6 +87,14 @@ func (c *Creator) SetOutlineTree(outlineTree *model.PdfOutlineTreeNode) {
|
||||
c.externalOutline = outlineTree
|
||||
}
|
||||
|
||||
// SetPageLabels adds the specified page labels to the PDF file generated
|
||||
// by the creator. See section 12.4.2 "Page Labels" (p. 382 PDF32000_2008).
|
||||
// NOTE: for existing PDF files, the page label ranges object can be obtained
|
||||
// using the model.PDFReader's GetPageLabels method.
|
||||
func (c *Creator) SetPageLabels(pageLabels core.PdfObject) {
|
||||
c.pageLabels = pageLabels
|
||||
}
|
||||
|
||||
// FrontpageFunctionArgs holds the input arguments to a front page drawing function.
|
||||
// It is designed as a struct, so additional parameters can be added in the future with backwards
|
||||
// compatibility.
|
||||
@ -647,6 +660,14 @@ func (c *Creator) Write(ws io.Writer) error {
|
||||
pdfWriter.AddOutlineTree(&c.outline.ToPdfOutline().PdfOutlineTreeNode)
|
||||
}
|
||||
|
||||
// Page labels.
|
||||
if c.pageLabels != nil {
|
||||
if err := pdfWriter.SetPageLabels(c.pageLabels); err != nil {
|
||||
common.Log.Debug("ERROR: Could not set page labels: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Pdf Writer access hook. Can be used to encrypt, etc. via the PdfWriter instance.
|
||||
if c.pdfWriterAccessFunc != nil {
|
||||
err := c.pdfWriterAccessFunc(&pdfWriter)
|
||||
|
@ -2980,6 +2980,60 @@ func TestCreatorStable(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPageLabels(t *testing.T) {
|
||||
// Read input file.
|
||||
f, err := os.Open(testPdfTemplatesFile1)
|
||||
require.NoError(t, err)
|
||||
defer f.Close()
|
||||
|
||||
reader, err := model.NewPdfReader(f)
|
||||
require.NoError(t, err)
|
||||
numPages, err := reader.GetNumPages()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Add input file pages to a new creator instance.
|
||||
c := New()
|
||||
nums := core.MakeArray()
|
||||
for i := 0; i < numPages; i++ {
|
||||
page, err := reader.GetPage(i + 1)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = c.AddPage(page)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Generate a page range for each page.
|
||||
// If page index is even, show page label using Roman uppercase numerals.
|
||||
// Otherwise, show page label using decimal Arabic numerals.
|
||||
labelStyle := "R"
|
||||
if i%2 != 0 {
|
||||
labelStyle = "D"
|
||||
}
|
||||
pageRange := core.MakeDict()
|
||||
pageRange.Set(*core.MakeName("S"), core.MakeName(labelStyle))
|
||||
nums.Append(core.MakeInteger(int64(i)))
|
||||
nums.Append(pageRange)
|
||||
}
|
||||
|
||||
// Create page labels dictionary and add it to the creator.
|
||||
genPageLabels := core.MakeDict()
|
||||
genPageLabels.Set(*core.MakeName("Nums"), nums)
|
||||
c.SetPageLabels(genPageLabels)
|
||||
|
||||
// Write output file to buffer.
|
||||
outBuf := bytes.NewBuffer(nil)
|
||||
err = c.Write(outBuf)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Read output file.
|
||||
reader, err = model.NewPdfReader(bytes.NewReader(outBuf.Bytes()))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Retrieve page labels and compare them to the generated page labels.
|
||||
pageLabels, err := reader.GetPageLabels()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, core.EqualObjects(genPageLabels, pageLabels), true)
|
||||
}
|
||||
|
||||
var errRenderNotSupported = errors.New("rendering pdf is not supported on this system")
|
||||
|
||||
// renderPDFToPNGs uses ghostscript (gs) to render specified PDF file into a set of PNG images (one per page).
|
||||
|
@ -765,6 +765,25 @@ func (r *PdfReader) GetNamedDestinations() (core.PdfObject, error) {
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
// GetPageLabels returns the PageLabels entry in the PDF catalog.
|
||||
// See section 12.4.2 "Page Labels" (p. 382 PDF32000_2008).
|
||||
func (r *PdfReader) GetPageLabels() (core.PdfObject, error) {
|
||||
obj := core.ResolveReference(r.catalog.Get("PageLabels"))
|
||||
if obj == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Resolve references.
|
||||
if !r.isLazy {
|
||||
err := r.traverseObjectData(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
// Inspect inspects the object types, subtypes and content in the PDF file returning a map of
|
||||
// object type to number of instances of each.
|
||||
func (r *PdfReader) Inspect() (map[string]int, error) {
|
||||
|
@ -426,6 +426,18 @@ func (w *PdfWriter) SetNamedDestinations(names core.PdfObject) error {
|
||||
return w.addObjects(names)
|
||||
}
|
||||
|
||||
// SetPageLabels sets the PageLabels entry in the PDF catalog.
|
||||
// See section 12.4.2 "Page Labels" (p. 382 PDF32000_2008).
|
||||
func (w *PdfWriter) SetPageLabels(pageLabels core.PdfObject) error {
|
||||
if pageLabels == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
common.Log.Trace("Setting catalog PageLabels...")
|
||||
w.catalog.Set("PageLabels", pageLabels)
|
||||
return w.addObjects(pageLabels)
|
||||
}
|
||||
|
||||
// SetOptimizer sets the optimizer to optimize PDF before writing.
|
||||
func (w *PdfWriter) SetOptimizer(optimizer Optimizer) {
|
||||
w.optimizer = optimizer
|
||||
|
Loading…
x
Reference in New Issue
Block a user