1204 lines
30 KiB
Go
1204 lines
30 KiB
Go
/*
|
|
Copyright 2018 The pdfcpu Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package pdfcpu
|
|
|
|
import (
|
|
"path/filepath"
|
|
"time"
|
|
)
|
|
|
|
// Functions needed to create a test.pdf that gets used for validation testing (see process_test.go)
|
|
|
|
func createTextAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
d := Dict(map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Text"),
|
|
"Contents": StringLiteral("Text Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 5),
|
|
"C": NewNumberArray(1, 0, 0),
|
|
"Name": Name("Note"),
|
|
})
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createLinkAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
usageDict := Dict(
|
|
map[string]Object{
|
|
"CreatorInfo": Dict(
|
|
map[string]Object{
|
|
"Creator": StringLiteral("pdfcpu"),
|
|
"Subtype": Name("Technical"),
|
|
},
|
|
),
|
|
"Language": Dict(
|
|
map[string]Object{
|
|
"Lang": StringLiteral("en-us"),
|
|
"Preferred": Name("ON"),
|
|
},
|
|
),
|
|
"Export": Dict(
|
|
map[string]Object{
|
|
"ExportState": Name("ON"),
|
|
},
|
|
),
|
|
"Zoom": Dict(
|
|
map[string]Object{
|
|
"min": Float(0),
|
|
},
|
|
),
|
|
"Print": Dict(
|
|
map[string]Object{
|
|
"Subtype": Name("Watermark"),
|
|
"PrintState": Name("ON"),
|
|
},
|
|
),
|
|
"View": Dict(
|
|
map[string]Object{
|
|
"ViewState": Name("Ind"),
|
|
},
|
|
),
|
|
"User": Dict(
|
|
map[string]Object{
|
|
"Type": Name("ON"),
|
|
"Name": StringLiteral("Horst Rutter"),
|
|
},
|
|
),
|
|
"PageElement": Dict(
|
|
map[string]Object{
|
|
"Subtype": Name("FG"),
|
|
},
|
|
),
|
|
},
|
|
)
|
|
|
|
optionalContentGroupDict := Dict(
|
|
map[string]Object{
|
|
"Type": Name("OCG"),
|
|
"Name": StringLiteral("OCG"),
|
|
"Intent": Name("Design"),
|
|
"Usage": usageDict,
|
|
},
|
|
)
|
|
|
|
uriActionDict := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Action"),
|
|
"S": Name("URI"),
|
|
"URI": StringLiteral("https://golang.org"),
|
|
},
|
|
)
|
|
|
|
indRef, err := xRefTable.IndRefForNewObject(uriActionDict)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Link"),
|
|
"Contents": StringLiteral("Link Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 5),
|
|
"C": NewNumberArray(0, 0, 1),
|
|
"A": *indRef,
|
|
"H": Name("I"),
|
|
"PA": *indRef,
|
|
"OC": optionalContentGroupDict,
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createFreeTextAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("FreeText"),
|
|
"Contents": StringLiteral("FreeText Annotation"),
|
|
"F": Integer(128), // Lock
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0, 1, 0),
|
|
"DA": StringLiteral("DA"),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createLineAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Line"),
|
|
"Contents": StringLiteral("Line Annotation"),
|
|
"F": Integer(128), // Lock
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0, 1, 0),
|
|
"L": annotRect,
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createSquareAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Square"),
|
|
"Contents": StringLiteral("Square Annotation"),
|
|
"F": Integer(128), // Lock
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0, .3, .3),
|
|
"IC": NewNumberArray(0.8, .8, .8),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createCircleAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Circle"),
|
|
"Contents": StringLiteral("Circle Annotation"),
|
|
"F": Integer(128), // Lock
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 10),
|
|
"C": NewNumberArray(0.5, 0, 5, 0),
|
|
"IC": NewNumberArray(0.8, .8, .8),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createPolygonAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
// Construct a polyline using the annot rects both lower corners and the upper right corner.
|
|
v := Array{nil, nil, nil, nil}
|
|
copy(v, annotRect)
|
|
v = append(v, annotRect[2])
|
|
v = append(v, annotRect[1])
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Polygon"),
|
|
"Contents": StringLiteral("Polygon Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0, 1, 0),
|
|
"Vertices": v,
|
|
"IC": NewNumberArray(0.3, 0.5, 0.0),
|
|
"BS": Dict(
|
|
map[string]Object{
|
|
"Type": Name("Border"),
|
|
"W": Float(0.5),
|
|
"S": Name("D"),
|
|
},
|
|
),
|
|
"BE": Dict(
|
|
map[string]Object{
|
|
"S": Name("C"),
|
|
"I": Float(1),
|
|
},
|
|
),
|
|
"IT": Name("PolygonCloud"),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createPolyLineAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
// Construct a polyline using the annot rects both lower corners and the upper right corner.
|
|
v := Array{nil, nil, nil, nil}
|
|
copy(v, annotRect)
|
|
v = append(v, annotRect[2])
|
|
v = append(v, annotRect[1])
|
|
|
|
optionalContentGroupDict := Dict(
|
|
map[string]Object{
|
|
"Type": Name("OCG"),
|
|
"Name": StringLiteral("OCG"),
|
|
"Intent": NewNameArray("Design", "View"),
|
|
},
|
|
)
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("PolyLine"),
|
|
"Contents": StringLiteral("PolyLine Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0, 1, 0),
|
|
"Vertices": v,
|
|
"OC": optionalContentGroupDict,
|
|
"IC": NewNumberArray(0.3, 0.5, 0.0),
|
|
"BS": Dict(
|
|
map[string]Object{
|
|
"Type": Name("Border"),
|
|
"W": Float(0.5),
|
|
"S": Name("D"),
|
|
},
|
|
),
|
|
"IT": Name("PolygonCloud"),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createHighlightAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
// Create a quad points array corresponding to the annot rect.
|
|
ar := annotRect
|
|
|
|
qp := Array{}
|
|
qp = append(qp, ar[0])
|
|
qp = append(qp, ar[1])
|
|
qp = append(qp, ar[2])
|
|
qp = append(qp, ar[1])
|
|
qp = append(qp, ar[2])
|
|
qp = append(qp, ar[3])
|
|
qp = append(qp, ar[0])
|
|
qp = append(qp, ar[3])
|
|
|
|
optionalContentGroupDict := Dict(
|
|
map[string]Object{
|
|
"Type": Name("OCG"),
|
|
"Name": StringLiteral("OCG"),
|
|
},
|
|
)
|
|
|
|
optionalContentMembershipDict := Dict(
|
|
map[string]Object{
|
|
"Type": Name("OCMD"),
|
|
"OCGs": Array{nil, optionalContentGroupDict},
|
|
"P": Name("AllOn"),
|
|
"VE": Array{},
|
|
},
|
|
)
|
|
|
|
_ = optionalContentMembershipDict
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Highlight"),
|
|
"Contents": StringLiteral("Highlight Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(.2, 0, 0),
|
|
"OC": optionalContentMembershipDict,
|
|
"QuadPoints": qp,
|
|
"T": StringLiteral("MyTitle"),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createUnderlineAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
// Create a quad points array corresponding to annot rect.
|
|
ar := annotRect
|
|
|
|
qp := Array{}
|
|
qp = append(qp, ar[0])
|
|
qp = append(qp, ar[1])
|
|
qp = append(qp, ar[2])
|
|
qp = append(qp, ar[1])
|
|
qp = append(qp, ar[2])
|
|
qp = append(qp, ar[3])
|
|
qp = append(qp, ar[0])
|
|
qp = append(qp, ar[3])
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Underline"),
|
|
"Contents": StringLiteral("Underline Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(.5, 0, 0),
|
|
"QuadPoints": qp,
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createSquigglyAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
// Create a quad points array corresponding to annot rect.
|
|
ar := annotRect
|
|
|
|
qp := Array{}
|
|
qp = append(qp, ar[0])
|
|
qp = append(qp, ar[1])
|
|
qp = append(qp, ar[2])
|
|
qp = append(qp, ar[1])
|
|
qp = append(qp, ar[2])
|
|
qp = append(qp, ar[3])
|
|
qp = append(qp, ar[0])
|
|
qp = append(qp, ar[3])
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Squiggly"),
|
|
"Contents": StringLiteral("Squiggly Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(.5, 0, 0),
|
|
"QuadPoints": qp,
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createStrikeOutAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
// Create a quad points array corresponding to annot rect.
|
|
ar := annotRect
|
|
|
|
qp := Array{}
|
|
qp = append(qp, ar[0])
|
|
qp = append(qp, ar[1])
|
|
qp = append(qp, ar[2])
|
|
qp = append(qp, ar[1])
|
|
qp = append(qp, ar[2])
|
|
qp = append(qp, ar[3])
|
|
qp = append(qp, ar[0])
|
|
qp = append(qp, ar[3])
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("StrikeOut"),
|
|
"Contents": StringLiteral("StrikeOut Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(.5, 0, 0),
|
|
"QuadPoints": qp,
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createCaretAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Caret"),
|
|
"Contents": StringLiteral("Caret Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0.5, 0.5, 0),
|
|
"RD": NewNumberArray(0, 0, 0, 0),
|
|
"Sy": Name("None"),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createStampAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Stamp"),
|
|
"Contents": StringLiteral("Stamp Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0.5, 0.5, 0.9),
|
|
"Name": Name("Approved"),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createInkAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
ar := annotRect
|
|
|
|
l := Array{
|
|
Array{ar[0], ar[1], ar[2], ar[1]},
|
|
Array{ar[2], ar[1], ar[2], ar[3]},
|
|
Array{ar[2], ar[3], ar[0], ar[3]},
|
|
Array{ar[0], ar[3], ar[0], ar[1]},
|
|
}
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Ink"),
|
|
"Contents": StringLiteral("Ink Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0.5, 0, 0.3),
|
|
"InkList": l,
|
|
"ExData": Dict(
|
|
map[string]Object{
|
|
"Type": Name("ExData"),
|
|
"Subtype": Name("Markup3D"),
|
|
},
|
|
),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createPopupAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Popup"),
|
|
"Contents": StringLiteral("Ink Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0.5, 0, 0.3),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createFileAttachmentAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
// macOS starts up iTunes for audio file attachments.
|
|
|
|
fileName := testAudioFileWAV
|
|
|
|
ir, err := xRefTable.NewEmbeddedFileStreamDict(fileName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
fn := filepath.Base(fileName)
|
|
fileSpecDict, err := xRefTable.NewFileSpecDict(fn, encodeUTF16String(fn), "attached by pdfcpu", *ir)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ir, err = xRefTable.IndRefForNewObject(fileSpecDict)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
now := StringLiteral(DateString(time.Now()))
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("FileAttachment"),
|
|
"Contents": StringLiteral("FileAttachment Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"M": now,
|
|
"F": Integer(0),
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0.5, 0.0, 0.5),
|
|
"CA": Float(0.95),
|
|
"CreationDate": now,
|
|
"Name": Name("Paperclip"),
|
|
"FS": *ir,
|
|
"NM": StringLiteral("SoundFileAttachmentAnnot"),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createFileSpecDict(xRefTable *XRefTable, fileName string) (Dict, error) {
|
|
ir, err := xRefTable.NewEmbeddedFileStreamDict(fileName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
fn := filepath.Base(fileName)
|
|
return xRefTable.NewFileSpecDict(fn, encodeUTF16String(fn), "attached by pdfcpu", *ir)
|
|
}
|
|
|
|
func createSoundObject(xRefTable *XRefTable) (*IndirectRef, error) {
|
|
fileName := testAudioFileWAV
|
|
fileSpecDict, err := createFileSpecDict(xRefTable, fileName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return xRefTable.NewSoundStreamDict(fileName, 44100, fileSpecDict)
|
|
}
|
|
|
|
func createSoundAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
indRef, err := createSoundObject(xRefTable)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Sound"),
|
|
"Contents": StringLiteral("Sound Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0, 0.5, 0.5),
|
|
"Sound": *indRef,
|
|
"Name": Name("Speaker"),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createMovieDict(xRefTable *XRefTable) (*IndirectRef, error) {
|
|
|
|
// not supported: mp3,mp4,m4a
|
|
|
|
fileSpecDict, err := createFileSpecDict(xRefTable, testAudioFileWAV)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"F": fileSpecDict,
|
|
"Aspect": NewIntegerArray(200, 200),
|
|
"Rotate": Integer(0),
|
|
"Poster": Boolean(true),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createMovieAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
indRef, err := createMovieDict(xRefTable)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
movieActivationDict := Dict(
|
|
map[string]Object{
|
|
"Start": Integer(10),
|
|
"Duration": Integer(60),
|
|
"Rate": Float(1.0),
|
|
"Volume": Float(1.0),
|
|
"ShowControls": Boolean(true),
|
|
"Mode": Name("Once"),
|
|
"Synchronous": Boolean(false),
|
|
},
|
|
)
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Movie"),
|
|
"Contents": StringLiteral("Movie Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 3), // rounded corners don't work
|
|
"C": NewNumberArray(0.3, 0.5, 0.5),
|
|
"Movie": *indRef,
|
|
"T": StringLiteral("Sample Movie"),
|
|
"A": movieActivationDict,
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createMediaRenditionAction(xRefTable *XRefTable, mediaClipDataDict *IndirectRef) Dict {
|
|
|
|
r := createMediaRendition(xRefTable, mediaClipDataDict)
|
|
|
|
return Dict(
|
|
map[string]Object{
|
|
"Type": Name("Action"),
|
|
"S": Name("Rendition"),
|
|
"R": *r, // rendition object
|
|
"OP": Integer(0), // Play
|
|
},
|
|
)
|
|
}
|
|
|
|
func createSelectorRenditionAction(mediaClipDataDict *IndirectRef) Dict {
|
|
|
|
r := createSelectorRendition(mediaClipDataDict)
|
|
|
|
return Dict(
|
|
map[string]Object{
|
|
"Type": Name("Action"),
|
|
"S": Name("Rendition"),
|
|
"R": *r, // rendition object
|
|
"OP": Integer(0), // Play
|
|
},
|
|
)
|
|
}
|
|
|
|
func createScreenAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
ir, err := createMediaClipDataDict(xRefTable)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
mediaRenditionAction := createMediaRenditionAction(xRefTable, ir)
|
|
|
|
selectorRenditionAction := createSelectorRenditionAction(ir)
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Screen"),
|
|
"Contents": StringLiteral("Screen Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 3),
|
|
"C": NewNumberArray(0.2, 0.8, 0.5),
|
|
"A": mediaRenditionAction,
|
|
"AA": Dict(
|
|
map[string]Object{
|
|
"D": selectorRenditionAction,
|
|
},
|
|
),
|
|
},
|
|
)
|
|
|
|
ir, err = xRefTable.IndRefForNewObject(d)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Inject indRef of screen annotation into action dicts.
|
|
mediaRenditionAction.Insert("AN", *ir)
|
|
selectorRenditionAction.Insert("AN", *ir)
|
|
|
|
return ir, nil
|
|
}
|
|
|
|
func createWidgetAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
appearanceCharacteristicsDict := Dict(
|
|
map[string]Object{
|
|
"R": Integer(0),
|
|
"BC": NewNumberArray(0.0, 0.0, 0.0),
|
|
"BG": NewNumberArray(0.5, 0.0, 0.5),
|
|
"RC": StringLiteral("Rollover caption"),
|
|
"IF": Dict(
|
|
map[string]Object{
|
|
"SW": Name("A"),
|
|
"S": Name("A"),
|
|
"FB": Boolean(true),
|
|
},
|
|
),
|
|
},
|
|
)
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Widget"),
|
|
"Contents": StringLiteral("Widget Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 3),
|
|
"C": NewNumberArray(0.5, 0.5, 0.5),
|
|
"MK": appearanceCharacteristicsDict,
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createXObjectForPrinterMark(xRefTable *XRefTable) (*IndirectRef, error) {
|
|
buf := `0 0 m 0 25 l 25 25 l 25 0 l s`
|
|
sd, _ := xRefTable.NewStreamDictForBuf([]byte(buf))
|
|
sd.InsertName("Type", "XObject")
|
|
sd.InsertName("Subtype", "Form")
|
|
sd.InsertInt("FormType", 1)
|
|
sd.Insert("BBox", NewNumberArray(0, 0, 25, 25))
|
|
sd.Insert("Matrix", NewIntegerArray(1, 0, 0, 1, 0, 0))
|
|
|
|
if err := sd.Encode(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return xRefTable.IndRefForNewObject(*sd)
|
|
}
|
|
|
|
func createPrinterMarkAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
ir, err := createXObjectForPrinterMark(xRefTable)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("PrinterMark"),
|
|
"Contents": StringLiteral("PrinterMark Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 3),
|
|
"C": NewNumberArray(0.2, 0.8, 0.5),
|
|
"F": Integer(0),
|
|
"AP": Dict(
|
|
map[string]Object{
|
|
"N": *ir,
|
|
},
|
|
),
|
|
"MN": Name("ColorBar"),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createXObjectForWaterMark(xRefTable *XRefTable) (*IndirectRef, error) {
|
|
fIndRef, err := createFontDict(xRefTable, "Helvetica")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
fResDict := NewDict()
|
|
fResDict.Insert("F1", *fIndRef)
|
|
resourceDict := NewDict()
|
|
resourceDict.Insert("Font", fResDict)
|
|
|
|
buf := `0 0 m 0 200 l 200 200 l 200 0 l s BT /F1 48 Tf 0.7 0.7 -0.7 0.7 30 10 Tm 1 Tr 2 w (Watermark) Tj ET`
|
|
sd, _ := xRefTable.NewStreamDictForBuf([]byte(buf))
|
|
sd.InsertName("Type", "XObject")
|
|
sd.InsertName("Subtype", "Form")
|
|
sd.InsertInt("FormType", 1)
|
|
sd.Insert("BBox", NewNumberArray(0, 0, 200, 200))
|
|
sd.Insert("Matrix", NewIntegerArray(1, 0, 0, 1, 0, 0))
|
|
sd.Insert("Resources", resourceDict)
|
|
|
|
if err = sd.Encode(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return xRefTable.IndRefForNewObject(*sd)
|
|
}
|
|
|
|
func createWaterMarkAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
ir, err := createXObjectForWaterMark(xRefTable)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d1 := Dict(
|
|
map[string]Object{
|
|
"Type": Name("FixedPrint"),
|
|
"Matrix": NewIntegerArray(1, 0, 0, 1, 72, -72),
|
|
"H": Float(0),
|
|
"V": Float(0),
|
|
},
|
|
)
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Watermark"),
|
|
"Contents": StringLiteral("Watermark Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 3),
|
|
"C": NewNumberArray(0.2, 0.8, 0.5),
|
|
"F": Integer(0),
|
|
"AP": Dict(
|
|
map[string]Object{
|
|
"N": *ir,
|
|
},
|
|
),
|
|
"FixedPrint": d1,
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func create3DAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("3D"),
|
|
"Contents": StringLiteral("3D Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 3),
|
|
"C": NewNumberArray(0.2, 0.8, 0.5),
|
|
"F": Integer(0),
|
|
"3DD": NewDict(), // stream or 3D reference dict
|
|
"3DV": Name("F"),
|
|
"3DA": NewDict(), // activation dict
|
|
"3DI": Boolean(true),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createRedactAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
// Create a quad points array corresponding to annot rect.
|
|
qp := Array{}
|
|
qp = append(qp, annotRect[0])
|
|
qp = append(qp, annotRect[1])
|
|
qp = append(qp, annotRect[2])
|
|
qp = append(qp, annotRect[1])
|
|
qp = append(qp, annotRect[2])
|
|
qp = append(qp, annotRect[3])
|
|
qp = append(qp, annotRect[0])
|
|
qp = append(qp, annotRect[3])
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Redact"),
|
|
"Contents": StringLiteral("Redact Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 3),
|
|
"C": NewNumberArray(0.2, 0.8, 0.5),
|
|
"F": Integer(0),
|
|
"QuadPoints": qp,
|
|
"IC": NewNumberArray(0.5, 0.0, 0.9),
|
|
"OverlayText": StringLiteral("An overlay"),
|
|
"Repeat": Boolean(true),
|
|
"DA": StringLiteral("x"),
|
|
"Q": Integer(1),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createRemoteGoToAction(xRefTable *XRefTable) (*IndirectRef, error) {
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Action"),
|
|
"S": Name("GoToR"),
|
|
"F": StringLiteral(".\\/go.pdf"),
|
|
"D": Array{Integer(0), Name("Fit")},
|
|
"NewWindow": Boolean(true),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createLinkAnnotationWithRemoteGoToAction(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
ir, err := createRemoteGoToAction(xRefTable)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Link"),
|
|
"Contents": StringLiteral("Link Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0, 0, 1),
|
|
"A": *ir,
|
|
"H": Name("I"),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createEmbeddedGoToAction(xRefTable *XRefTable) (*IndirectRef, error) {
|
|
|
|
f := filepath.Join(testDir, "go.pdf")
|
|
fileSpecDict, err := createFileSpecDict(xRefTable, f)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Action"),
|
|
"S": Name("GoToE"),
|
|
"F": fileSpecDict,
|
|
"D": Array{Integer(0), Name("Fit")},
|
|
"NewWindow": Boolean(true), // not honored by Acrobat Reader.
|
|
"T": Dict(
|
|
map[string]Object{
|
|
"R": Name("C"),
|
|
"N": StringLiteral(filepath.Base(f)),
|
|
},
|
|
),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createLinkAnnotationWithEmbeddedGoToAction(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
ir, err := createEmbeddedGoToAction(xRefTable)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Link"),
|
|
"Contents": StringLiteral("Link Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0, 0, 1),
|
|
"A": *ir,
|
|
"H": Name("I"),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createLinkAnnotationDictWithLaunchAction(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Link"),
|
|
"Contents": StringLiteral("Link Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0, 0, 1),
|
|
"A": Dict(
|
|
map[string]Object{
|
|
"Type": Name("Action"),
|
|
"S": Name("Launch"),
|
|
"F": StringLiteral("golang.pdf"),
|
|
"Win": Dict(
|
|
map[string]Object{
|
|
"F": StringLiteral("golang.pdf"),
|
|
"O": StringLiteral("O"),
|
|
},
|
|
),
|
|
"NewWindow": Boolean(true),
|
|
},
|
|
),
|
|
"H": Name("I"),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createLinkAnnotationDictWithThreadAction(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Link"),
|
|
"Contents": StringLiteral("Link Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0, 0, 1),
|
|
"A": Dict(
|
|
map[string]Object{
|
|
"Type": Name("Action"),
|
|
"S": Name("Thread"),
|
|
"D": Integer(0), // jump to first article thread
|
|
"B": Integer(0), // jump to first bead
|
|
},
|
|
),
|
|
"H": Name("I"),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createLinkAnnotationDictWithSoundAction(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
ir, err := createSoundObject(xRefTable)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Link"),
|
|
"Contents": StringLiteral("Link Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0, 0, 1),
|
|
"A": Dict(
|
|
map[string]Object{
|
|
"Type": Name("Action"),
|
|
"S": Name("Sound"),
|
|
"Sound": *ir,
|
|
"Synchronous": Boolean(false),
|
|
"Repeat": Boolean(false),
|
|
"Mix": Boolean(false),
|
|
},
|
|
),
|
|
"H": Name("I"),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createLinkAnnotationDictWithMovieAction(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Link"),
|
|
"Contents": StringLiteral("Link Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0, 0, 1),
|
|
"A": Dict(
|
|
map[string]Object{
|
|
"Type": Name("Action"),
|
|
"S": Name("Movie"),
|
|
"T": StringLiteral("Sample Movie"),
|
|
"Operation": Name("Play"),
|
|
},
|
|
),
|
|
"H": Name("I"),
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|
|
|
|
func createLinkAnnotationDictWithHideAction(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
hideActionDict := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Action"),
|
|
"S": Name("Hide"),
|
|
"H": Boolean(true),
|
|
},
|
|
)
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("Link"),
|
|
"Contents": StringLiteral("Link Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 1),
|
|
"C": NewNumberArray(0, 0, 1),
|
|
"A": hideActionDict,
|
|
"H": Name("I"),
|
|
},
|
|
)
|
|
|
|
ir, err := xRefTable.IndRefForNewObject(d)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// We hide the link annotation itself.
|
|
hideActionDict.Insert("T", *ir)
|
|
|
|
return ir, nil
|
|
}
|
|
|
|
func createTrapNetAnnotation(xRefTable *XRefTable, pageIndRef IndirectRef, annotRect Array) (*IndirectRef, error) {
|
|
|
|
ir, err := createFontDict(xRefTable, "Helvetica")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
d := Dict(
|
|
map[string]Object{
|
|
"Type": Name("Annot"),
|
|
"Subtype": Name("TrapNet"),
|
|
"Contents": StringLiteral("TrapNet Annotation"),
|
|
"Rect": annotRect,
|
|
"P": pageIndRef,
|
|
"Border": NewIntegerArray(0, 0, 3),
|
|
"C": NewNumberArray(0.2, 0.8, 0.5),
|
|
"F": Integer(0),
|
|
"LastModified": StringLiteral(DateString(time.Now())),
|
|
"FontFauxing": Array{*ir},
|
|
},
|
|
)
|
|
|
|
return xRefTable.IndRefForNewObject(d)
|
|
}
|