Skip to content

Commit 4a2f04f

Browse files
committed
Fix #1041
1 parent 9b1ead8 commit 4a2f04f

File tree

9 files changed

+97
-76
lines changed

9 files changed

+97
-76
lines changed

pkg/pdfcpu/annotation.go

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ func Annotation(xRefTable *model.XRefTable, d types.Dict) (model.AnnotationRende
158158
if err != nil {
159159
return nil, err
160160
}
161+
contents = types.RemoveControlChars(contents)
161162
}
162163

163164
var nm string
@@ -243,7 +244,7 @@ func AnnotationsForSelectedPages(ctx *model.Context, selectedPages types.IntSet)
243244
return m
244245
}
245246

246-
func prepareHeader(horSep *[]int, maxLen *AnnotListMaxLengths) string {
247+
func prepareHeader(horSep *[]int, maxLen *AnnotListMaxLengths, customAnnot bool) string {
247248
s := " Obj# "
248249
if maxLen.ObjNr > 4 {
249250
s += strings.Repeat(" ", maxLen.ObjNr-4)
@@ -270,17 +271,27 @@ func prepareHeader(horSep *[]int, maxLen *AnnotListMaxLengths) string {
270271

271272
s += draw.VBar + " Content"
272273
if maxLen.Content > 7 {
273-
s += strings.Repeat(" ", maxLen.Rect-7)
274-
*horSep = append(*horSep, 8+maxLen.Rect-7)
274+
s += strings.Repeat(" ", maxLen.Content-7)
275+
*horSep = append(*horSep, 8+maxLen.Content-7)
275276
} else {
276277
*horSep = append(*horSep, 8)
277278
}
278279

280+
if customAnnot {
281+
s += draw.VBar + " Type"
282+
if maxLen.Type > 4 {
283+
s += strings.Repeat(" ", maxLen.Type-4)
284+
*horSep = append(*horSep, 5+maxLen.Type-4)
285+
} else {
286+
*horSep = append(*horSep, 5)
287+
}
288+
}
289+
279290
return s
280291
}
281292

282293
type AnnotListMaxLengths struct {
283-
ObjNr, ID, Rect, Content int
294+
ObjNr, ID, Rect, Content, Type int
284295
}
285296

286297
// ListAnnotations returns a formatted list of annotations.
@@ -315,6 +326,7 @@ func ListAnnotations(annots map[int]model.PgAnnots) (int, []string, error) {
315326
var maxLen AnnotListMaxLengths
316327
maxLen.ID = 2
317328
maxLen.Content = len("Content")
329+
maxLen.Type = len("Type")
318330

319331
var objNrs []int
320332
for objNr, ann := range annots.Map {
@@ -332,6 +344,9 @@ func ListAnnotations(annots map[int]model.PgAnnots) (int, []string, error) {
332344
if len(ann.ContentString()) > maxLen.Content {
333345
maxLen.Content = len(ann.ContentString())
334346
}
347+
if len(ann.CustomTypeString()) > maxLen.Type {
348+
maxLen.Type = len(ann.CustomTypeString())
349+
}
335350
}
336351
sort.Ints(objNrs)
337352
ss = append(ss, "")
@@ -340,7 +355,7 @@ func ListAnnotations(annots map[int]model.PgAnnots) (int, []string, error) {
340355
horSep := []int{}
341356

342357
// Render header.
343-
ss = append(ss, prepareHeader(&horSep, &maxLen))
358+
ss = append(ss, prepareHeader(&horSep, &maxLen, annType == "Custom"))
344359

345360
// Render separator.
346361
ss = append(ss, draw.HorSepLine(horSep))
@@ -364,8 +379,15 @@ func ListAnnotations(annots map[int]model.PgAnnots) (int, []string, error) {
364379
s = ann.RectString()
365380
fill3 := strings.Repeat(" ", maxLen.Rect-len(s))
366381

367-
ss = append(ss, fmt.Sprintf(" %s%d %s %s%s %s %s%s %s %s",
368-
fill1, objNr, draw.VBar, fill2, ann.ID(), draw.VBar, fill3, ann.RectString(), draw.VBar, ann.ContentString()))
382+
if ann.Type() != model.AnnCustom {
383+
ss = append(ss, fmt.Sprintf(" %s%d %s %s%s %s %s%s %s %s",
384+
fill1, objNr, draw.VBar, fill2, ann.ID(), draw.VBar, fill3, ann.RectString(), draw.VBar, ann.ContentString()))
385+
} else {
386+
s = ann.ContentString()
387+
fill4 := strings.Repeat(" ", maxLen.Content-len(s))
388+
ss = append(ss, fmt.Sprintf(" %s%d %s %s%s %s %s%s %s %s%s%s %s",
389+
fill1, objNr, draw.VBar, fill2, ann.ID(), draw.VBar, fill3, ann.RectString(), draw.VBar, fill4, ann.ContentString(), draw.VBar, ann.CustomTypeString()))
390+
}
369391

370392
j++
371393
}

pkg/pdfcpu/model/annotation.go

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ const (
7171
AnnWatermark
7272
Ann3D
7373
AnnRedact
74+
AnnCustom
7475
)
7576

7677
var AnnotTypes = map[string]AnnotationType{
@@ -100,6 +101,7 @@ var AnnotTypes = map[string]AnnotationType{
100101
"Watermark": AnnWatermark,
101102
"3D": Ann3D,
102103
"Redact": AnnRedact,
104+
"Custom": AnnCustom,
103105
}
104106

105107
// AnnotTypeStrings manages string representations for annotation types.
@@ -130,6 +132,7 @@ var AnnotTypeStrings = map[AnnotationType]string{
130132
AnnWatermark: "Watermark",
131133
Ann3D: "3D",
132134
AnnRedact: "Redact",
135+
AnnCustom: "Custom",
133136
}
134137

135138
// BorderStyle (see table 168)
@@ -235,11 +238,13 @@ type AnnotationRenderer interface {
235238
RectString() string
236239
ID() string
237240
ContentString() string
241+
CustomTypeString() string
238242
}
239243

240244
// Annotation represents a PDF annotation.
241245
type Annotation struct {
242246
SubType AnnotationType // The type of annotation that this dictionary describes.
247+
CustomSubType string // Out of spec annot type.
243248
Rect types.Rectangle // The annotation rectangle, defining the location of the annotation on the page in default user space units.
244249
Contents string // Text that shall be displayed for the annotation.
245250
NM string // (Since V1.4) The annotation name, a text string uniquely identifying it among all the annotations on its page.
@@ -257,6 +262,7 @@ type Annotation struct {
257262
// NewAnnotation returns a new annotation.
258263
func NewAnnotation(
259264
typ AnnotationType,
265+
customTyp string,
260266
rect types.Rectangle,
261267
contents, id string,
262268
modDate string,
@@ -268,6 +274,7 @@ func NewAnnotation(
268274

269275
return Annotation{
270276
SubType: typ,
277+
CustomSubType: customTyp,
271278
Rect: rect,
272279
Contents: contents,
273280
NM: id,
@@ -292,7 +299,15 @@ func NewAnnotationForRawType(
292299
borderRadX float64,
293300
borderRadY float64,
294301
borderWidth float64) Annotation {
295-
return NewAnnotation(AnnotTypes[typ], rect, contents, id, modDate, f, col, borderRadX, borderRadY, borderWidth)
302+
303+
annType, ok := AnnotTypes[typ]
304+
if !ok {
305+
annType = AnnotTypes["Custom"]
306+
} else {
307+
typ = ""
308+
}
309+
310+
return NewAnnotation(annType, typ, rect, contents, id, modDate, f, col, borderRadX, borderRadY, borderWidth)
296311
}
297312

298313
// ID returns the annotation id.
@@ -305,6 +320,11 @@ func (ann Annotation) ContentString() string {
305320
return ann.Contents
306321
}
307322

323+
// ContentString returns a string representation of ann's contents.
324+
func (ann Annotation) CustomTypeString() string {
325+
return ann.CustomSubType
326+
}
327+
308328
// RectString returns ann's positioning rectangle.
309329
func (ann Annotation) RectString() string {
310330
return ann.Rect.ShortString()
@@ -389,7 +409,7 @@ func NewPopupAnnotation(
389409
parentIndRef *types.IndirectRef,
390410
displayOpen bool) PopupAnnotation {
391411

392-
ann := NewAnnotation(AnnPopup, rect, contents, id, modDate, f, col, borderRadX, borderRadY, borderWidth)
412+
ann := NewAnnotation(AnnPopup, "", rect, contents, id, modDate, f, col, borderRadX, borderRadY, borderWidth)
393413

394414
return PopupAnnotation{
395415
Annotation: ann,
@@ -448,7 +468,7 @@ func NewLinkAnnotation(
448468
borderWidth float64,
449469
borderStyle BorderStyle) LinkAnnotation {
450470

451-
ann := NewAnnotation(AnnLink, rect, contents, id, modDate, f, borderCol, 0, 0, 0)
471+
ann := NewAnnotation(AnnLink, "", rect, contents, id, modDate, f, borderCol, 0, 0, 0)
452472

453473
return LinkAnnotation{
454474
Annotation: ann,
@@ -553,7 +573,7 @@ func NewMarkupAnnotation(
553573
ca *float64,
554574
rc, subject string) MarkupAnnotation {
555575

556-
ann := NewAnnotation(subType, rect, contents, id, modDate, f, col, borderRadX, borderRadY, borderWidth)
576+
ann := NewAnnotation(subType, "", rect, contents, id, modDate, f, col, borderRadX, borderRadY, borderWidth)
557577

558578
return MarkupAnnotation{
559579
Annotation: ann,

pkg/pdfcpu/model/xreftable.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,8 @@ type XRefTable struct {
156156
// Statistics
157157
Stats PDFStats
158158

159-
Tagged bool // File is using tags. This is important for ???
160-
AAPLExtensions bool // File is using Apple extensions for annotations and keywords.
159+
Tagged bool // File is using tags. This is important for ???
160+
CustomExtensions bool // File is using custom extensions for annotations and/or keywords.
161161

162162
// Validation
163163
CurPage int // current page during validation

pkg/pdfcpu/types/string.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@ import (
2727
"golang.org/x/text/unicode/norm"
2828
)
2929

30+
func RemoveControlChars(s string) string {
31+
return strings.Map(func(r rune) rune {
32+
switch r {
33+
case '\n', '\r', '\t', '\b', '\f':
34+
return -1
35+
default:
36+
return r
37+
}
38+
}, s)
39+
}
40+
3041
// NewStringSet returns a new StringSet for slice.
3142
func NewStringSet(slice []string) StringSet {
3243
strSet := StringSet{}

pkg/pdfcpu/validate/annotation.go

Lines changed: 6 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -29,42 +29,6 @@ import (
2929

3030
var errInvalidPageAnnotArray = errors.New("pdfcpu: validatePageAnnotations: page annotation array without indirect references.")
3131

32-
func validateAAPLAKExtrasDictEntry(xRefTable *model.XRefTable, d types.Dict, dictName, entryName string, required bool, sinceVersion model.Version) error {
33-
34-
// No documentation for this PDF-Extension - purely speculative implementation.
35-
36-
d1, err := validateDictEntry(xRefTable, d, dictName, entryName, required, sinceVersion, nil)
37-
if err != nil || d1 == nil {
38-
return err
39-
}
40-
41-
// We have identified modifications by Apple.
42-
43-
xRefTable.AAPLExtensions = true
44-
45-
// // Validation deactivated
46-
// dictName = "AAPLAKExtrasDict"
47-
48-
// // AAPL:AKAnnotationObject, string
49-
// _, err = validateStringEntry(xRefTable, d1, dictName, "AAPL:AKAnnotationObject", OPTIONAL, sinceVersion, nil)
50-
// if err != nil {
51-
// return err
52-
// }
53-
54-
// // AAPL:AKPDFAnnotationDictionary, annotationDict
55-
// ad, err := validateDictEntry(xRefTable, d1, dictName, "AAPL:AKPDFAnnotationDictionary", OPTIONAL, sinceVersion, nil)
56-
// if err != nil {
57-
// return err
58-
// }
59-
60-
// _, err = validateAnnotationDict(xRefTable, ad)
61-
// if err != nil {
62-
// return err
63-
// }
64-
65-
return nil
66-
}
67-
6832
func validateBorderEffectDictEntry(xRefTable *model.XRefTable, d types.Dict, dictName, entryName string, required bool, sinceVersion model.Version) error {
6933

7034
// see 12.5.4
@@ -1765,15 +1729,9 @@ func validateAnnotationDictConcrete(xRefTable *model.XRefTable, d types.Dict, di
17651729
}
17661730
}
17671731

1768-
return errors.Errorf("validateAnnotationDictConcrete: unsupported annotation subtype:%s\n", subtype)
1769-
}
1770-
1771-
func validateAnnotationDictSpecial(xRefTable *model.XRefTable, d types.Dict, dictName string) error {
1732+
xRefTable.CustomExtensions = true
17721733

1773-
// AAPL:AKExtras
1774-
// No documentation for this PDF-Extension - this is a speculative implementation.
1775-
1776-
return validateAAPLAKExtrasDictEntry(xRefTable, d, dictName, "AAPL:AKExtras", OPTIONAL, model.V10)
1734+
return nil
17771735
}
17781736

17791737
func validateAnnotationDict(xRefTable *model.XRefTable, d types.Dict) (isTrapNet bool, err error) {
@@ -1790,10 +1748,10 @@ func validateAnnotationDict(xRefTable *model.XRefTable, d types.Dict) (isTrapNet
17901748
return false, err
17911749
}
17921750

1793-
err = validateAnnotationDictSpecial(xRefTable, d, dictName)
1794-
if err != nil {
1795-
return false, err
1796-
}
1751+
// err = validateAnnotationDictSpecial(xRefTable, d, dictName)
1752+
// if err != nil {
1753+
// return false, err
1754+
// }
17971755

17981756
return *subtype == "TrapNet", nil
17991757
}

pkg/pdfcpu/validate/extGState.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1001,7 +1001,7 @@ func validateExtGStateDict(xRefTable *model.XRefTable, o types.Object) error {
10011001
return err
10021002
}
10031003
if o != nil {
1004-
xRefTable.AAPLExtensions = true
1004+
xRefTable.CustomExtensions = true
10051005
}
10061006

10071007
return nil

0 commit comments

Comments
 (0)