mirror of
https://github.com/unidoc/unipdf.git
synced 2025-05-05 19:30:30 +08:00
attempting to simplify render branch
This commit is contained in:
parent
79aa75acf8
commit
7f5475badb
@ -22,27 +22,23 @@ import (
|
|||||||
// - Type1
|
// - Type1
|
||||||
// - TrueType
|
// - TrueType
|
||||||
// etc.
|
// etc.
|
||||||
// It also holds the elements common to all fonts in fontSkeleton.
|
|
||||||
// XXX: The idea behind fontSkeleton is to avoid replicating the commmon font field parsing code
|
|
||||||
// in all fonts. Is there a better way of doing this?
|
|
||||||
type PdfFont struct {
|
type PdfFont struct {
|
||||||
fontSkeleton // The fields common to all fonts
|
context fonts.Font // The underlying font: Type0, Type1, Truetype, etc..
|
||||||
context fonts.Font // The underlying font: Type0, Type1, Truetype, etc..
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a string that describes `font`.
|
// String returns a string that describes `font`.
|
||||||
func (font PdfFont) String() string {
|
func (font PdfFont) String() string {
|
||||||
return fmt.Sprintf("%T %s", font.context, font.fontSkeleton.String())
|
return fmt.Sprintf("FONT{%T %s}", font.context, font.baseFields().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// BaseFont returns the font's "BaseFont" field.
|
// BaseFont returns the font's "BaseFont" field.
|
||||||
func (font PdfFont) BaseFont() string {
|
func (font PdfFont) BaseFont() string {
|
||||||
return font.basefont
|
return font.baseFields().basefont
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subtype returns the font's "Subtype" field.
|
// Subtype returns the font's "Subtype" field.
|
||||||
func (font PdfFont) Subtype() string {
|
func (font PdfFont) Subtype() string {
|
||||||
subtype := font.subtype
|
subtype := font.baseFields().subtype
|
||||||
if t, ok := font.context.(*pdfFontType0); ok {
|
if t, ok := font.context.(*pdfFontType0); ok {
|
||||||
subtype = fmt.Sprintf("%s:%s", subtype, t.DescendantFont.Subtype())
|
subtype = fmt.Sprintf("%s:%s", subtype, t.DescendantFont.Subtype())
|
||||||
}
|
}
|
||||||
@ -51,26 +47,20 @@ func (font PdfFont) Subtype() string {
|
|||||||
|
|
||||||
// ToUnicode returns the name of the font's "ToUnicode" field if there is one, or "" if there isn't.
|
// ToUnicode returns the name of the font's "ToUnicode" field if there is one, or "" if there isn't.
|
||||||
func (font PdfFont) ToUnicode() string {
|
func (font PdfFont) ToUnicode() string {
|
||||||
if font.toUnicodeCmap == nil {
|
if font.baseFields().toUnicodeCmap == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return font.toUnicodeCmap.Name()
|
return font.baseFields().toUnicodeCmap.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStandard14Font returns the standard 14 font named `basefont` as a *PdfFont, or an error if it
|
// NewStandard14Font returns the standard 14 font named `basefont` as a *PdfFont, or an error if it
|
||||||
// `basefont` is not one the standard 14 font names.
|
// `basefont` is not one the standard 14 font names.
|
||||||
func NewStandard14Font(basefont string) (*PdfFont, error) {
|
func NewStandard14Font(basefont string) (*PdfFont, error) {
|
||||||
std, ok := fonts.Standard14Fonts[basefont]
|
std, ok := standard14Fonts[basefont]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrFontNotSupported
|
return nil, ErrFontNotSupported
|
||||||
}
|
}
|
||||||
return &PdfFont{
|
return &PdfFont{context: &std}, nil
|
||||||
fontSkeleton: fontSkeleton{
|
|
||||||
subtype: "Type1",
|
|
||||||
basefont: basefont,
|
|
||||||
},
|
|
||||||
context: std,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPdfFontFromPdfObject loads a PdfFont from the dictionary `fontObj`. If there is a problem an
|
// NewPdfFontFromPdfObject loads a PdfFont from the dictionary `fontObj`. If there is a problem an
|
||||||
@ -84,43 +74,43 @@ func NewPdfFontFromPdfObject(fontObj core.PdfObject) (*PdfFont, error) {
|
|||||||
// The allowType0 flag indicates whether loading Type0 font should be supported. This is used to
|
// The allowType0 flag indicates whether loading Type0 font should be supported. This is used to
|
||||||
// avoid cyclical loading.
|
// avoid cyclical loading.
|
||||||
func newPdfFontFromPdfObject(fontObj core.PdfObject, allowType0 bool) (*PdfFont, error) {
|
func newPdfFontFromPdfObject(fontObj core.PdfObject, allowType0 bool) (*PdfFont, error) {
|
||||||
skeleton, err := newFontSkeletonFromPdfObject(fontObj)
|
d, base, err := newFontBaseFieldsFromPdfObject(fontObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
font := &PdfFont{fontSkeleton: *skeleton}
|
|
||||||
|
|
||||||
switch skeleton.subtype {
|
font := &PdfFont{}
|
||||||
|
switch base.subtype {
|
||||||
case "Type0":
|
case "Type0":
|
||||||
if !allowType0 {
|
if !allowType0 {
|
||||||
common.Log.Debug("ERROR: Loading type0 not allowed. font=%s", font)
|
common.Log.Debug("ERROR: Loading type0 not allowed. font=%s", font)
|
||||||
return nil, errors.New("Cyclical type0 loading")
|
return nil, errors.New("Cyclical type0 loading")
|
||||||
}
|
}
|
||||||
type0font, err := newPdfFontType0FromPdfObject(skeleton)
|
type0font, err := newPdfFontType0FromPdfObject(d, base)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("ERROR: While loading Type0 font. font=%s err=%v", font, err)
|
common.Log.Debug("ERROR: While loading Type0 font. font=%s err=%v", base, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
font.context = type0font
|
font.context = type0font
|
||||||
case "Type1", "Type3", "MMType1", "TrueType": // !@#$
|
case "Type1", "Type3", "MMType1", "TrueType": // !@#$
|
||||||
var simplefont *pdfFontSimple
|
var simplefont *pdfFontSimple
|
||||||
if std, ok := fonts.Standard14Fonts[font.basefont]; ok && font.subtype == "Type1" {
|
if std, ok := standard14Fonts[base.basefont]; ok && base.subtype == "Type1" {
|
||||||
font.context = std
|
font.context = &std
|
||||||
stdObj := core.TraceToDirectObject(std.ToPdfObject())
|
stdObj := core.TraceToDirectObject(std.ToPdfObject())
|
||||||
stdSkeleton, err := newFontSkeletonFromPdfObject(stdObj)
|
d, stdBase, err := newFontBaseFieldsFromPdfObject(stdObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("ERROR: Bad Standard14\n\tfont=%s\n\tstd=%+v", font, std)
|
common.Log.Debug("ERROR: Bad Standard14\n\tfont=%s\n\tstd=%+v", base, std)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
simplefont, err = newSimpleFontFromPdfObject(stdSkeleton, true)
|
simplefont, err = newSimpleFontFromPdfObject(d, stdBase, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("ERROR: Bad Standard14\n\tfont=%s\n\tstd=%+v", font, std)
|
common.Log.Debug("ERROR: Bad Standard14\n\tfont=%s\n\tstd=%+v", base, std)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
simplefont, err = newSimpleFontFromPdfObject(skeleton, false)
|
simplefont, err = newSimpleFontFromPdfObject(d, base, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("ERROR: While loading simple font: font=%s err=%v", font, err)
|
common.Log.Debug("ERROR: While loading simple font: font=%s err=%v", base, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -130,22 +120,22 @@ func newPdfFontFromPdfObject(fontObj core.PdfObject, allowType0 bool) (*PdfFont,
|
|||||||
}
|
}
|
||||||
font.context = simplefont
|
font.context = simplefont
|
||||||
case "CIDFontType0":
|
case "CIDFontType0":
|
||||||
cidfont, err := newPdfCIDFontType0FromPdfObject(skeleton)
|
cidfont, err := newPdfCIDFontType0FromPdfObject(d, base)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("ERROR: While loading cid font type0 font: %v", err)
|
common.Log.Debug("ERROR: While loading cid font type0 font: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
font.context = cidfont
|
font.context = cidfont
|
||||||
case "CIDFontType2":
|
case "CIDFontType2":
|
||||||
cidfont, err := newPdfCIDFontType2FromPdfObject(skeleton)
|
cidfont, err := newPdfCIDFontType2FromPdfObject(d, base)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("ERROR: While loading cid font type2 font. font=%s err=%v", font, err)
|
common.Log.Debug("ERROR: While loading cid font type2 font. font=%s err=%v", base, err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
font.context = cidfont
|
font.context = cidfont
|
||||||
default:
|
default:
|
||||||
common.Log.Debug("ERROR: Unsupported font type: font=%s", font)
|
common.Log.Debug("ERROR: Unsupported font type: font=%s", base)
|
||||||
return nil, fmt.Errorf("Unsupported font type: font=%s", font)
|
return nil, fmt.Errorf("Unsupported font type: font=%s", base)
|
||||||
}
|
}
|
||||||
|
|
||||||
return font, nil
|
return font, nil
|
||||||
@ -165,7 +155,7 @@ func (font PdfFont) CharcodeBytesToUnicode(data []byte) (string, int, int) {
|
|||||||
common.Log.Debug("showText: data=[% 02x]=%#q", data, data)
|
common.Log.Debug("showText: data=[% 02x]=%#q", data, data)
|
||||||
|
|
||||||
charcodes := make([]uint16, 0, len(data)+len(data)%2)
|
charcodes := make([]uint16, 0, len(data)+len(data)%2)
|
||||||
if font.isCIDFont() {
|
if font.baseFields().isCIDFont() {
|
||||||
if len(data) == 1 {
|
if len(data) == 1 {
|
||||||
data = []byte{0, data[0]}
|
data = []byte{0, data[0]}
|
||||||
}
|
}
|
||||||
@ -186,8 +176,8 @@ func (font PdfFont) CharcodeBytesToUnicode(data []byte) (string, int, int) {
|
|||||||
charstrings := make([]string, 0, len(charcodes))
|
charstrings := make([]string, 0, len(charcodes))
|
||||||
numMisses := 0
|
numMisses := 0
|
||||||
for _, code := range charcodes {
|
for _, code := range charcodes {
|
||||||
if font.toUnicodeCmap != nil {
|
if font.baseFields().toUnicodeCmap != nil {
|
||||||
r, ok := font.toUnicodeCmap.CharcodeToUnicode2(cmap.CharCode(code))
|
r, ok := font.baseFields().toUnicodeCmap.CharcodeToUnicode2(cmap.CharCode(code))
|
||||||
if ok {
|
if ok {
|
||||||
charstrings = append(charstrings, r)
|
charstrings = append(charstrings, r)
|
||||||
continue
|
continue
|
||||||
@ -203,7 +193,7 @@ func (font PdfFont) CharcodeBytesToUnicode(data []byte) (string, int, int) {
|
|||||||
|
|
||||||
common.Log.Debug("ERROR: No rune. code=0x%04x data=[% 02x]=%#q charcodes=[% 04x] CID=%t\n"+
|
common.Log.Debug("ERROR: No rune. code=0x%04x data=[% 02x]=%#q charcodes=[% 04x] CID=%t\n"+
|
||||||
"\tfont=%s\n\tencoding=%s",
|
"\tfont=%s\n\tencoding=%s",
|
||||||
code, data, data, charcodes, font.isCIDFont(), font, encoder)
|
code, data, data, charcodes, font.baseFields().isCIDFont(), font, encoder)
|
||||||
numMisses++
|
numMisses++
|
||||||
charstrings = append(charstrings, cmap.MissingCodeString)
|
charstrings = append(charstrings, cmap.MissingCodeString)
|
||||||
}
|
}
|
||||||
@ -277,40 +267,36 @@ func (font PdfFont) actualFont() fonts.Font {
|
|||||||
return t
|
return t
|
||||||
case fonts.FontCourier:
|
case fonts.FontCourier:
|
||||||
return t
|
return t
|
||||||
case fonts.FontCourierBold:
|
|
||||||
return t
|
|
||||||
case fonts.FontCourierBoldOblique:
|
|
||||||
return t
|
|
||||||
case fonts.FontCourierOblique:
|
|
||||||
return t
|
|
||||||
case fonts.FontHelvetica:
|
|
||||||
return t
|
|
||||||
case fonts.FontHelveticaBold:
|
|
||||||
return t
|
|
||||||
case fonts.FontHelveticaBoldOblique:
|
|
||||||
return t
|
|
||||||
case fonts.FontHelveticaOblique:
|
|
||||||
return t
|
|
||||||
case fonts.FontTimesRoman:
|
|
||||||
return t
|
|
||||||
case fonts.FontTimesBold:
|
|
||||||
return t
|
|
||||||
case fonts.FontTimesBoldItalic:
|
|
||||||
return t
|
|
||||||
case fonts.FontTimesItalic:
|
|
||||||
return t
|
|
||||||
case fonts.FontSymbol:
|
|
||||||
return t
|
|
||||||
case fonts.FontZapfDingbats:
|
|
||||||
return t
|
|
||||||
default:
|
default:
|
||||||
common.Log.Debug("ERROR: actualFont. Unknown font type %t. font=%s", t, font)
|
common.Log.Debug("ERROR: actualFont. Unknown font type %t. font=%s", t, font)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fontSkeleton represents the fields that are common to all PDF fonts.
|
// baseFields returns the fields of `font`.context that are common to all PDF fonts.
|
||||||
type fontSkeleton struct {
|
func (font PdfFont) baseFields() *fontCommon {
|
||||||
|
if font.context == nil {
|
||||||
|
common.Log.Debug("ERROR: baseFields. context is nil.")
|
||||||
|
panic("RRRR")
|
||||||
|
}
|
||||||
|
switch t := font.context.(type) {
|
||||||
|
case *pdfFontSimple:
|
||||||
|
return t.baseFields()
|
||||||
|
case *pdfFontType0:
|
||||||
|
return t.baseFields()
|
||||||
|
case *pdfCIDFontType0:
|
||||||
|
return t.baseFields()
|
||||||
|
case *pdfCIDFontType2:
|
||||||
|
return t.baseFields()
|
||||||
|
default:
|
||||||
|
//common.Log.Error("ERROR: base. Unknown font type %t. font=%s", t, font.String())
|
||||||
|
panic(fmt.Errorf("ERROR: base. Unknown font type %t. ", t))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fontCommon represents the fields that are common to all PDF fonts.
|
||||||
|
type fontCommon struct {
|
||||||
// All fonts have these fields
|
// All fonts have these fields
|
||||||
basefont string // The font's "BaseFont" field.
|
basefont string // The font's "BaseFont" field.
|
||||||
subtype string // The font's "Subtype" field.
|
subtype string // The font's "Subtype" field.
|
||||||
@ -322,68 +308,65 @@ type fontSkeleton struct {
|
|||||||
toUnicodeCmap *cmap.CMap // Computed from "ToUnicode"
|
toUnicodeCmap *cmap.CMap // Computed from "ToUnicode"
|
||||||
fontDescriptor *PdfFontDescriptor // Computed from "FontDescriptor"
|
fontDescriptor *PdfFontDescriptor // Computed from "FontDescriptor"
|
||||||
|
|
||||||
// This is an internal implementation detail. It is passed to specific font types so they can parse it.
|
|
||||||
dict *core.PdfObjectDictionary
|
|
||||||
|
|
||||||
// objectNumber helps us find the font in the PDF being processed. This helps with debugging
|
// objectNumber helps us find the font in the PDF being processed. This helps with debugging
|
||||||
objectNumber int64
|
objectNumber int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// toFont returns a core.PdfObjectDictionary for `skel`.
|
// asPdfObjectDictionary returns `base` as a core.PdfObjectDictionary.
|
||||||
// It is for use in font ToPdfObject functions.
|
// It is for use in font ToPdfObject functions.
|
||||||
// NOTE: The returned dict's "Subtype" field is set to `subtype` if `skel` doesn't have a subtype.
|
// NOTE: The returned dict's "Subtype" field is set to `subtype` if `base` doesn't have a subtype.
|
||||||
func (skel fontSkeleton) toDict(subtype string) *core.PdfObjectDictionary {
|
func (base fontCommon) asPdfObjectDictionary(subtype string) *core.PdfObjectDictionary {
|
||||||
|
|
||||||
if subtype != "" && skel.subtype != "" && subtype != skel.subtype {
|
if subtype != "" && base.subtype != "" && subtype != base.subtype {
|
||||||
common.Log.Debug("ERROR: toDict. Overriding subtype to %#q %s", subtype, skel)
|
common.Log.Debug("ERROR: asPdfObjectDictionary. Overriding subtype to %#q %s", subtype, base)
|
||||||
} else if subtype == "" && skel.subtype == "" {
|
} else if subtype == "" && base.subtype == "" {
|
||||||
common.Log.Debug("ERROR: toDict no subtype. font=%s", skel)
|
common.Log.Debug("ERROR: asPdfObjectDictionary no subtype. font=%s", base)
|
||||||
} else if skel.subtype == "" {
|
} else if base.subtype == "" {
|
||||||
skel.subtype = subtype
|
base.subtype = subtype
|
||||||
}
|
}
|
||||||
|
|
||||||
d := core.MakeDict()
|
d := core.MakeDict()
|
||||||
d.Set("Type", core.MakeName("Font"))
|
d.Set("Type", core.MakeName("Font"))
|
||||||
d.Set("BaseFont", core.MakeName(skel.basefont))
|
d.Set("BaseFont", core.MakeName(base.basefont))
|
||||||
d.Set("Subtype", core.MakeName(skel.subtype))
|
d.Set("Subtype", core.MakeName(base.subtype))
|
||||||
|
|
||||||
if skel.fontDescriptor != nil {
|
if base.fontDescriptor != nil {
|
||||||
d.Set("FontDescriptor", skel.fontDescriptor.ToPdfObject())
|
d.Set("FontDescriptor", base.fontDescriptor.ToPdfObject())
|
||||||
}
|
}
|
||||||
if skel.toUnicode != nil {
|
if base.toUnicode != nil {
|
||||||
d.Set("ToUnicode", skel.toUnicode)
|
d.Set("ToUnicode", base.toUnicode)
|
||||||
}
|
}
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a string that describes `skel`.
|
// String returns a string that describes `base`.
|
||||||
func (skel fontSkeleton) String() string {
|
func (base fontCommon) String() string {
|
||||||
descriptor := ""
|
descriptor := ""
|
||||||
if skel.fontDescriptor != nil {
|
if base.fontDescriptor != nil {
|
||||||
descriptor = skel.fontDescriptor.String()
|
descriptor = base.fontDescriptor.String()
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("FONT{%#q %#q obj=%d %s}", skel.subtype, skel.basefont, skel.objectNumber, descriptor)
|
return fmt.Sprintf("FONT{%#q %#q obj=%d %s}", base.subtype, base.basefont, base.objectNumber, descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// isCIDFont returns true if `skel` is a CID font.
|
// isCIDFont returns true if `base` is a CID font.
|
||||||
func (skel fontSkeleton) isCIDFont() bool {
|
func (base fontCommon) isCIDFont() bool {
|
||||||
if skel.subtype == "" {
|
if base.subtype == "" {
|
||||||
common.Log.Debug("ERROR: isCIDFont. context is nil. font=%s", skel)
|
common.Log.Debug("ERROR: isCIDFont. context is nil. font=%s", base)
|
||||||
}
|
}
|
||||||
isCID := false
|
isCID := false
|
||||||
switch skel.subtype {
|
switch base.subtype {
|
||||||
case "Type0", "CIDFontType0", "CIDFontType2":
|
case "Type0", "CIDFontType0", "CIDFontType2":
|
||||||
isCID = true
|
isCID = true
|
||||||
}
|
}
|
||||||
common.Log.Trace("isCIDFont: isCID=%t font=%s", isCID, skel)
|
common.Log.Trace("isCIDFont: isCID=%t font=%s", isCID, base)
|
||||||
return isCID
|
return isCID
|
||||||
}
|
}
|
||||||
|
|
||||||
// newFontSkeletonFromPdfObject loads a fontSkeleton from a dictionary. If there is a problem an
|
// newFontBaseFieldsFromPdfObject returns `fontObj` as a dictionary the common fields from that
|
||||||
// error is returned.
|
// dictionary in the fontCommon return. If there is a problem an error is returned.
|
||||||
// The fontSkeleton is the group of fields common to all PDF fonts.
|
// The fontCommon is the group of fields common to all PDF fonts.
|
||||||
func newFontSkeletonFromPdfObject(fontObj core.PdfObject) (*fontSkeleton, error) {
|
func newFontBaseFieldsFromPdfObject(fontObj core.PdfObject) (*core.PdfObjectDictionary, *fontCommon, error) {
|
||||||
font := &fontSkeleton{}
|
font := &fontCommon{}
|
||||||
|
|
||||||
if obj, ok := fontObj.(*core.PdfIndirectObject); ok {
|
if obj, ok := fontObj.(*core.PdfIndirectObject); ok {
|
||||||
font.objectNumber = obj.ObjectNumber
|
font.objectNumber = obj.ObjectNumber
|
||||||
@ -394,36 +377,35 @@ func newFontSkeletonFromPdfObject(fontObj core.PdfObject) (*fontSkeleton, error)
|
|||||||
d, ok := dictObj.(*core.PdfObjectDictionary)
|
d, ok := dictObj.(*core.PdfObjectDictionary)
|
||||||
if !ok {
|
if !ok {
|
||||||
common.Log.Debug("ERROR: Font not given by a dictionary (%T)", fontObj)
|
common.Log.Debug("ERROR: Font not given by a dictionary (%T)", fontObj)
|
||||||
return nil, ErrFontNotSupported
|
return nil, nil, ErrFontNotSupported
|
||||||
}
|
}
|
||||||
font.dict = d
|
|
||||||
|
|
||||||
objtype, err := core.GetName(core.TraceToDirectObject(d.Get("Type")))
|
objtype, err := core.GetName(core.TraceToDirectObject(d.Get("Type")))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("ERROR: Font Incompatibility. Type (Required) missing")
|
common.Log.Debug("ERROR: Font Incompatibility. Type (Required) missing")
|
||||||
return nil, ErrRequiredAttributeMissing
|
return nil, nil, ErrRequiredAttributeMissing
|
||||||
}
|
}
|
||||||
if objtype != "Font" {
|
if objtype != "Font" {
|
||||||
common.Log.Debug("ERROR: Font Incompatibility. Type=%q. Should be %q.", objtype, "Font")
|
common.Log.Debug("ERROR: Font Incompatibility. Type=%q. Should be %q.", objtype, "Font")
|
||||||
return nil, core.ErrTypeError
|
return nil, nil, core.ErrTypeError
|
||||||
}
|
}
|
||||||
|
|
||||||
subtype, err := core.GetName(core.TraceToDirectObject(d.Get("Subtype")))
|
subtype, err := core.GetName(core.TraceToDirectObject(d.Get("Subtype")))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("ERROR: Font Incompatibility. Subtype (Required) missing")
|
common.Log.Debug("ERROR: Font Incompatibility. Subtype (Required) missing")
|
||||||
return nil, ErrRequiredAttributeMissing
|
return nil, nil, ErrRequiredAttributeMissing
|
||||||
}
|
}
|
||||||
font.subtype = subtype
|
font.subtype = subtype
|
||||||
|
|
||||||
if subtype == "Type3" {
|
if subtype == "Type3" {
|
||||||
common.Log.Debug("ERROR: Type 3 font not supprted. d=%s", d)
|
common.Log.Debug("ERROR: Type 3 font not supprted. d=%s", d)
|
||||||
return nil, ErrFontNotSupported
|
return nil, nil, ErrFontNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
basefont, err := core.GetName(core.TraceToDirectObject(d.Get("BaseFont")))
|
basefont, err := core.GetName(core.TraceToDirectObject(d.Get("BaseFont")))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("ERROR: Font Incompatibility. BaseFont (Required) missing")
|
common.Log.Debug("ERROR: Font Incompatibility. BaseFont (Required) missing")
|
||||||
return nil, ErrRequiredAttributeMissing
|
return nil, nil, ErrRequiredAttributeMissing
|
||||||
}
|
}
|
||||||
font.basefont = basefont
|
font.basefont = basefont
|
||||||
|
|
||||||
@ -432,7 +414,7 @@ func newFontSkeletonFromPdfObject(fontObj core.PdfObject) (*fontSkeleton, error)
|
|||||||
fontDescriptor, err := newPdfFontDescriptorFromPdfObject(obj)
|
fontDescriptor, err := newPdfFontDescriptorFromPdfObject(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("ERROR: Bad font descriptor. err=%v", err)
|
common.Log.Debug("ERROR: Bad font descriptor. err=%v", err)
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
font.fontDescriptor = fontDescriptor
|
font.fontDescriptor = fontDescriptor
|
||||||
}
|
}
|
||||||
@ -441,12 +423,12 @@ func newFontSkeletonFromPdfObject(fontObj core.PdfObject) (*fontSkeleton, error)
|
|||||||
if font.toUnicode != nil {
|
if font.toUnicode != nil {
|
||||||
codemap, err := toUnicodeToCmap(font.toUnicode, font.isCIDFont())
|
codemap, err := toUnicodeToCmap(font.toUnicode, font.isCIDFont())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
font.toUnicodeCmap = codemap
|
font.toUnicodeCmap = codemap
|
||||||
}
|
}
|
||||||
|
|
||||||
return font, nil
|
return d, font, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// toUnicodeToCmap returns a CMap of `toUnicode` if it exists
|
// toUnicodeToCmap returns a CMap of `toUnicode` if it exists
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
|
|
||||||
"github.com/unidoc/unidoc/common"
|
"github.com/unidoc/unidoc/common"
|
||||||
"github.com/unidoc/unidoc/pdf/core"
|
"github.com/unidoc/unidoc/pdf/core"
|
||||||
|
"github.com/unidoc/unidoc/pdf/internal/cmap"
|
||||||
"github.com/unidoc/unidoc/pdf/model/fonts"
|
"github.com/unidoc/unidoc/pdf/model/fonts"
|
||||||
"github.com/unidoc/unidoc/pdf/model/textencoding"
|
"github.com/unidoc/unidoc/pdf/model/textencoding"
|
||||||
)
|
)
|
||||||
@ -87,13 +88,51 @@ import (
|
|||||||
// associated CIDFont is called its descendant.
|
// associated CIDFont is called its descendant.
|
||||||
type pdfFontType0 struct {
|
type pdfFontType0 struct {
|
||||||
container *core.PdfIndirectObject
|
container *core.PdfIndirectObject
|
||||||
*fontSkeleton
|
|
||||||
|
// These fields are common to all PDF fonts.
|
||||||
|
|
||||||
|
basefont string // The font's "BaseFont" field.
|
||||||
|
subtype string // The font's "Subtype" field.
|
||||||
|
|
||||||
|
// These are optional fields in the PDF font
|
||||||
|
toUnicode core.PdfObject // The stream containing toUnicodeCmap. We keep it around for ToPdfObject.
|
||||||
|
|
||||||
|
// These objects are computed from optional fields in the PDF font
|
||||||
|
toUnicodeCmap *cmap.CMap // Computed from "ToUnicode"
|
||||||
|
fontDescriptor *PdfFontDescriptor // Computed from "FontDescriptor"
|
||||||
|
|
||||||
|
// objectNumber helps us find the font in the PDF being processed. This helps with debugging
|
||||||
|
objectNumber int64
|
||||||
|
|
||||||
|
// These fields are specific to Type 0 fonts.
|
||||||
|
|
||||||
encoder textencoding.TextEncoder
|
encoder textencoding.TextEncoder
|
||||||
Encoding core.PdfObject
|
Encoding core.PdfObject
|
||||||
DescendantFont *PdfFont // Can be either CIDFontType0 or CIDFontType2 font.
|
DescendantFont *PdfFont // Can be either CIDFontType0 or CIDFontType2 font.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pdfFontType0FromSkeleton returns a pdfFontType0 with its common fields initalized.
|
||||||
|
func pdfFontType0FromSkeleton(base *fontCommon) *pdfFontType0 {
|
||||||
|
return &pdfFontType0{
|
||||||
|
basefont: base.basefont,
|
||||||
|
subtype: base.subtype,
|
||||||
|
toUnicode: base.toUnicode,
|
||||||
|
fontDescriptor: base.fontDescriptor,
|
||||||
|
objectNumber: base.objectNumber,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// baseFields returns the fields of `font` that are common to all PDF fonts.
|
||||||
|
func (font *pdfFontType0) baseFields() *fontCommon {
|
||||||
|
return &fontCommon{
|
||||||
|
basefont: font.basefont,
|
||||||
|
subtype: font.subtype,
|
||||||
|
toUnicode: font.toUnicode,
|
||||||
|
fontDescriptor: font.fontDescriptor,
|
||||||
|
objectNumber: font.objectNumber,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetGlyphCharMetrics returns the character metrics for the specified glyph. A bool flag is
|
// GetGlyphCharMetrics returns the character metrics for the specified glyph. A bool flag is
|
||||||
// returned to indicate whether or not the entry was found in the glyph to charcode mapping.
|
// returned to indicate whether or not the entry was found in the glyph to charcode mapping.
|
||||||
func (font pdfFontType0) GetGlyphCharMetrics(glyph string) (fonts.CharMetrics, bool) {
|
func (font pdfFontType0) GetGlyphCharMetrics(glyph string) (fonts.CharMetrics, bool) {
|
||||||
@ -119,7 +158,8 @@ func (font *pdfFontType0) ToPdfObject() core.PdfObject {
|
|||||||
if font.container == nil {
|
if font.container == nil {
|
||||||
font.container = &core.PdfIndirectObject{}
|
font.container = &core.PdfIndirectObject{}
|
||||||
}
|
}
|
||||||
d := font.toDict("Type0")
|
d := font.baseFields().asPdfObjectDictionary("Type0")
|
||||||
|
|
||||||
font.container.PdfObject = d
|
font.container.PdfObject = d
|
||||||
|
|
||||||
if font.encoder != nil {
|
if font.encoder != nil {
|
||||||
@ -133,16 +173,14 @@ func (font *pdfFontType0) ToPdfObject() core.PdfObject {
|
|||||||
return font.container
|
return font.container
|
||||||
}
|
}
|
||||||
|
|
||||||
// newPdfFontType0FromPdfObject makes a pdfFontType0 based on the input `d` in skeleton.
|
// newPdfFontType0FromPdfObject makes a pdfFontType0 based on the input `d` in base.
|
||||||
// If a problem is encountered, an error is returned.
|
// If a problem is encountered, an error is returned.
|
||||||
func newPdfFontType0FromPdfObject(skeleton *fontSkeleton) (*pdfFontType0, error) {
|
func newPdfFontType0FromPdfObject(d *core.PdfObjectDictionary, base *fontCommon) (*pdfFontType0, error) {
|
||||||
|
|
||||||
d := skeleton.dict
|
|
||||||
|
|
||||||
// DescendantFonts.
|
// DescendantFonts.
|
||||||
arr, err := core.GetArray(core.TraceToDirectObject(d.Get("DescendantFonts")))
|
arr, err := core.GetArray(core.TraceToDirectObject(d.Get("DescendantFonts")))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("ERROR: Invalid DescendantFonts - not an array %s", skeleton)
|
common.Log.Debug("ERROR: Invalid DescendantFonts - not an array %s", base)
|
||||||
return nil, core.ErrRangeError
|
return nil, core.ErrRangeError
|
||||||
}
|
}
|
||||||
if len(arr) != 1 {
|
if len(arr) != 1 {
|
||||||
@ -151,14 +189,12 @@ func newPdfFontType0FromPdfObject(skeleton *fontSkeleton) (*pdfFontType0, error)
|
|||||||
}
|
}
|
||||||
df, err := newPdfFontFromPdfObject(arr[0], false)
|
df, err := newPdfFontFromPdfObject(arr[0], false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("ERROR: Failed loading descendant font: err=%v %s", err, skeleton)
|
common.Log.Debug("ERROR: Failed loading descendant font: err=%v %s", err, base)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
font := &pdfFontType0{
|
font := pdfFontType0FromSkeleton(base)
|
||||||
fontSkeleton: skeleton,
|
font.DescendantFont = df
|
||||||
DescendantFont: df,
|
|
||||||
}
|
|
||||||
|
|
||||||
encoderName, err := core.GetName(core.TraceToDirectObject(d.Get("Encoding")))
|
encoderName, err := core.GetName(core.TraceToDirectObject(d.Get("Encoding")))
|
||||||
// XXX: FIXME This is not valid if encoder is not Identity-H !@#$
|
// XXX: FIXME This is not valid if encoder is not Identity-H !@#$
|
||||||
@ -172,14 +208,51 @@ func newPdfFontType0FromPdfObject(skeleton *fontSkeleton) (*pdfFontType0, error)
|
|||||||
// XXX: This is a stub.
|
// XXX: This is a stub.
|
||||||
type pdfCIDFontType0 struct {
|
type pdfCIDFontType0 struct {
|
||||||
container *core.PdfIndirectObject
|
container *core.PdfIndirectObject
|
||||||
skeleton *fontSkeleton // Elements common to all font types.
|
|
||||||
|
// These fields are common to all PDF fonts.
|
||||||
|
|
||||||
|
basefont string // The font's "BaseFont" field.
|
||||||
|
subtype string // The font's "Subtype" field.
|
||||||
|
|
||||||
|
// These are optional fields in the PDF font
|
||||||
|
toUnicode core.PdfObject // The stream containing toUnicodeCmap. We keep it around for ToPdfObject.
|
||||||
|
|
||||||
|
// These objects are computed from optional fields in the PDF font
|
||||||
|
toUnicodeCmap *cmap.CMap // Computed from "ToUnicode"
|
||||||
|
fontDescriptor *PdfFontDescriptor // Computed from "FontDescriptor"
|
||||||
|
|
||||||
|
// objectNumber helps us find the font in the PDF being processed. This helps with debugging
|
||||||
|
objectNumber int64
|
||||||
|
|
||||||
|
// These fields are specific to Type 0 fonts.
|
||||||
|
|
||||||
encoder textencoding.TextEncoder
|
encoder textencoding.TextEncoder
|
||||||
|
|
||||||
// Table 117 – Entries in a CIDFont dictionary (page 269)
|
// Table 117 – Entries in a CIDFont dictionary (page 269)
|
||||||
CIDSystemInfo core.PdfObject // (Required) Dictionary that defines the character collection of the CIDFont. See Table 116.
|
CIDSystemInfo core.PdfObject // (Required) Dictionary that defines the character collection of the CIDFont. See Table 116.
|
||||||
FontDescriptor core.PdfObject // (Required) Describes the CIDFont’s default metrics other than its glyph widths
|
FontDescriptor core.PdfObject // (Required) Describes the CIDFont’s default metrics other than its glyph widths
|
||||||
|
}
|
||||||
|
|
||||||
|
// pdfCIDFontType0FromSkeleton returns a pdfCIDFontType0 with its common fields initalized.
|
||||||
|
func pdfCIDFontType0FromSkeleton(base *fontCommon) *pdfCIDFontType0 {
|
||||||
|
return &pdfCIDFontType0{
|
||||||
|
basefont: base.basefont,
|
||||||
|
subtype: base.subtype,
|
||||||
|
toUnicode: base.toUnicode,
|
||||||
|
fontDescriptor: base.fontDescriptor,
|
||||||
|
objectNumber: base.objectNumber,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// baseFields returns the fields of `font` that are common to all PDF fonts.
|
||||||
|
func (font *pdfCIDFontType0) baseFields() *fontCommon {
|
||||||
|
return &fontCommon{
|
||||||
|
basefont: font.basefont,
|
||||||
|
subtype: font.subtype,
|
||||||
|
toUnicode: font.toUnicode,
|
||||||
|
fontDescriptor: font.fontDescriptor,
|
||||||
|
objectNumber: font.objectNumber,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encoder returns the font's text encoder.
|
// Encoder returns the font's text encoder.
|
||||||
@ -208,19 +281,18 @@ func (font *pdfCIDFontType0) ToPdfObject() core.PdfObject {
|
|||||||
// newPdfCIDFontType0FromPdfObject creates a pdfCIDFontType0 object from a dictionary (either direct
|
// newPdfCIDFontType0FromPdfObject creates a pdfCIDFontType0 object from a dictionary (either direct
|
||||||
// or via indirect object). If a problem occurs with loading an error is returned.
|
// or via indirect object). If a problem occurs with loading an error is returned.
|
||||||
// XXX: This is a stub.
|
// XXX: This is a stub.
|
||||||
func newPdfCIDFontType0FromPdfObject(skeleton *fontSkeleton) (*pdfCIDFontType0, error) {
|
func newPdfCIDFontType0FromPdfObject(d *core.PdfObjectDictionary, base *fontCommon) (*pdfCIDFontType0, error) {
|
||||||
if skeleton.subtype != "CIDFontType0" {
|
if base.subtype != "CIDFontType0" {
|
||||||
common.Log.Debug("ERROR: Font SubType != CIDFontType0. font=%s", skeleton)
|
common.Log.Debug("ERROR: Font SubType != CIDFontType0. font=%s", base)
|
||||||
return nil, core.ErrRangeError
|
return nil, core.ErrRangeError
|
||||||
}
|
}
|
||||||
|
|
||||||
font := &pdfCIDFontType0{skeleton: skeleton}
|
font := pdfCIDFontType0FromSkeleton(base)
|
||||||
d := skeleton.dict
|
|
||||||
|
|
||||||
// CIDSystemInfo.
|
// CIDSystemInfo.
|
||||||
obj := core.TraceToDirectObject(d.Get("CIDSystemInfo"))
|
obj := core.TraceToDirectObject(d.Get("CIDSystemInfo"))
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
common.Log.Debug("ERROR: CIDSystemInfo (Required) missing. font=%s", skeleton)
|
common.Log.Debug("ERROR: CIDSystemInfo (Required) missing. font=%s", base)
|
||||||
return nil, ErrRequiredAttributeMissing
|
return nil, ErrRequiredAttributeMissing
|
||||||
}
|
}
|
||||||
font.CIDSystemInfo = obj
|
font.CIDSystemInfo = obj
|
||||||
@ -230,10 +302,26 @@ func newPdfCIDFontType0FromPdfObject(skeleton *fontSkeleton) (*pdfCIDFontType0,
|
|||||||
|
|
||||||
// pdfCIDFontType2 represents a CIDFont Type2 font dictionary.
|
// pdfCIDFontType2 represents a CIDFont Type2 font dictionary.
|
||||||
type pdfCIDFontType2 struct {
|
type pdfCIDFontType2 struct {
|
||||||
container *core.PdfIndirectObject
|
container *core.PdfIndirectObject
|
||||||
*fontSkeleton // Elements common to all font types
|
|
||||||
|
|
||||||
encoder textencoding.TextEncoder // !@#$ In skeleton?
|
// These fields are common to all PDF fonts.
|
||||||
|
|
||||||
|
basefont string // The font's "BaseFont" field.
|
||||||
|
subtype string // The font's "Subtype" field.
|
||||||
|
|
||||||
|
// These are optional fields in the PDF font
|
||||||
|
toUnicode core.PdfObject // The stream containing toUnicodeCmap. We keep it around for ToPdfObject.
|
||||||
|
|
||||||
|
// These objects are computed from optional fields in the PDF font
|
||||||
|
toUnicodeCmap *cmap.CMap // Computed from "ToUnicode"
|
||||||
|
fontDescriptor *PdfFontDescriptor // Computed from "FontDescriptor"
|
||||||
|
|
||||||
|
// objectNumber helps us find the font in the PDF being processed. This helps with debugging
|
||||||
|
objectNumber int64
|
||||||
|
|
||||||
|
// These fields are specific to Type 0 fonts.
|
||||||
|
|
||||||
|
encoder textencoding.TextEncoder // !@#$ In base?
|
||||||
ttfParser *fonts.TtfType
|
ttfParser *fonts.TtfType
|
||||||
|
|
||||||
CIDSystemInfo core.PdfObject
|
CIDSystemInfo core.PdfObject
|
||||||
@ -250,6 +338,28 @@ type pdfCIDFontType2 struct {
|
|||||||
gidToWidthMap map[uint16]int
|
gidToWidthMap map[uint16]int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pdfCIDFontType2FromSkeleton returns a pdfCIDFontType2 with its common fields initalized.
|
||||||
|
func pdfCIDFontType2FromSkeleton(base *fontCommon) *pdfCIDFontType2 {
|
||||||
|
return &pdfCIDFontType2{
|
||||||
|
basefont: base.basefont,
|
||||||
|
subtype: base.subtype,
|
||||||
|
toUnicode: base.toUnicode,
|
||||||
|
fontDescriptor: base.fontDescriptor,
|
||||||
|
objectNumber: base.objectNumber,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// baseFields returns the fields of `font` that are common to all PDF fonts.
|
||||||
|
func (font *pdfCIDFontType2) baseFields() *fontCommon {
|
||||||
|
return &fontCommon{
|
||||||
|
basefont: font.basefont,
|
||||||
|
subtype: font.subtype,
|
||||||
|
toUnicode: font.toUnicode,
|
||||||
|
fontDescriptor: font.fontDescriptor,
|
||||||
|
objectNumber: font.objectNumber,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Encoder returns the font's text encoder.
|
// Encoder returns the font's text encoder.
|
||||||
func (font pdfCIDFontType2) Encoder() textencoding.TextEncoder {
|
func (font pdfCIDFontType2) Encoder() textencoding.TextEncoder {
|
||||||
return font.encoder
|
return font.encoder
|
||||||
@ -289,7 +399,7 @@ func (font *pdfCIDFontType2) ToPdfObject() core.PdfObject {
|
|||||||
if font.container == nil {
|
if font.container == nil {
|
||||||
font.container = &core.PdfIndirectObject{}
|
font.container = &core.PdfIndirectObject{}
|
||||||
}
|
}
|
||||||
d := font.toDict("CIDFontType2")
|
d := font.baseFields().asPdfObjectDictionary("CIDFontType2")
|
||||||
font.container.PdfObject = d
|
font.container.PdfObject = d
|
||||||
|
|
||||||
if font.CIDSystemInfo != nil {
|
if font.CIDSystemInfo != nil {
|
||||||
@ -316,19 +426,18 @@ func (font *pdfCIDFontType2) ToPdfObject() core.PdfObject {
|
|||||||
|
|
||||||
// newPdfCIDFontType2FromPdfObject creates a pdfCIDFontType2 object from a dictionary (either direct
|
// newPdfCIDFontType2FromPdfObject creates a pdfCIDFontType2 object from a dictionary (either direct
|
||||||
// or via indirect object). If a problem occurs with loading, an error is returned.
|
// or via indirect object). If a problem occurs with loading, an error is returned.
|
||||||
func newPdfCIDFontType2FromPdfObject(skeleton *fontSkeleton) (*pdfCIDFontType2, error) {
|
func newPdfCIDFontType2FromPdfObject(d *core.PdfObjectDictionary, base *fontCommon) (*pdfCIDFontType2, error) {
|
||||||
if skeleton.subtype != "CIDFontType2" {
|
if base.subtype != "CIDFontType2" {
|
||||||
common.Log.Debug("ERROR: Font SubType != CIDFontType2. font=%s", skeleton)
|
common.Log.Debug("ERROR: Font SubType != CIDFontType2. font=%s", base)
|
||||||
return nil, core.ErrRangeError
|
return nil, core.ErrRangeError
|
||||||
}
|
}
|
||||||
|
|
||||||
font := &pdfCIDFontType2{fontSkeleton: skeleton}
|
font := pdfCIDFontType2FromSkeleton(base)
|
||||||
d := skeleton.dict
|
|
||||||
|
|
||||||
// CIDSystemInfo.
|
// CIDSystemInfo.
|
||||||
obj := d.Get("CIDSystemInfo")
|
obj := d.Get("CIDSystemInfo")
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
common.Log.Debug("ERROR: CIDSystemInfo (Required) missing. font=%s", skeleton)
|
common.Log.Debug("ERROR: CIDSystemInfo (Required) missing. font=%s", base)
|
||||||
return nil, ErrRequiredAttributeMissing
|
return nil, ErrRequiredAttributeMissing
|
||||||
}
|
}
|
||||||
font.CIDSystemInfo = obj
|
font.CIDSystemInfo = obj
|
||||||
@ -357,8 +466,7 @@ func NewCompositePdfFontFromTTFFile(filePath string) (*PdfFont, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prepare the inner descendant font (CIDFontType2).
|
// Prepare the inner descendant font (CIDFontType2).
|
||||||
skeletonCID := fontSkeleton{subtype: "CIDFontType2"}
|
cidfont := &pdfCIDFontType2{subtype: "CIDFontType2"}
|
||||||
cidfont := &pdfCIDFontType2{fontSkeleton: &skeletonCID}
|
|
||||||
cidfont.ttfParser = &ttf
|
cidfont.ttfParser = &ttf
|
||||||
|
|
||||||
// 2-byte character codes ➞ runes
|
// 2-byte character codes ➞ runes
|
||||||
@ -370,7 +478,7 @@ func NewCompositePdfFontFromTTFFile(filePath string) (*PdfFont, error) {
|
|||||||
return runes[i] < runes[j]
|
return runes[i] < runes[j]
|
||||||
})
|
})
|
||||||
|
|
||||||
skeleton := fontSkeleton{
|
base := fontCommon{
|
||||||
subtype: "Type0",
|
subtype: "Type0",
|
||||||
basefont: ttf.PostScriptName,
|
basefont: ttf.PostScriptName,
|
||||||
}
|
}
|
||||||
@ -476,15 +584,14 @@ func NewCompositePdfFontFromTTFFile(filePath string) (*PdfFont, error) {
|
|||||||
flags |= 1 << 2 // Symbolic.
|
flags |= 1 << 2 // Symbolic.
|
||||||
descriptor.Flags = core.MakeInteger(int64(flags))
|
descriptor.Flags = core.MakeInteger(int64(flags))
|
||||||
|
|
||||||
skeleton.fontDescriptor = descriptor
|
base.fontDescriptor = descriptor
|
||||||
descendantFont := PdfFont{
|
descendantFont := PdfFont{
|
||||||
context: cidfont,
|
context: cidfont,
|
||||||
fontSkeleton: skeletonCID,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make root Type0 font.
|
// Make root Type0 font.
|
||||||
type0 := pdfFontType0{
|
type0 := pdfFontType0{
|
||||||
fontSkeleton: &skeleton,
|
fontDescriptor: descriptor,
|
||||||
DescendantFont: &descendantFont,
|
DescendantFont: &descendantFont,
|
||||||
Encoding: core.MakeName("Identity-H"),
|
Encoding: core.MakeName("Identity-H"),
|
||||||
encoder: textencoding.NewTrueTypeFontEncoder(ttf.Chars),
|
encoder: textencoding.NewTrueTypeFontEncoder(ttf.Chars),
|
||||||
@ -492,8 +599,7 @@ func NewCompositePdfFontFromTTFFile(filePath string) (*PdfFont, error) {
|
|||||||
|
|
||||||
// Build Font.
|
// Build Font.
|
||||||
font := PdfFont{
|
font := PdfFont{
|
||||||
fontSkeleton: skeleton,
|
context: &type0,
|
||||||
context: &type0,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &font, nil
|
return &font, nil
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/unidoc/unidoc/common"
|
"github.com/unidoc/unidoc/common"
|
||||||
"github.com/unidoc/unidoc/pdf/core"
|
"github.com/unidoc/unidoc/pdf/core"
|
||||||
|
"github.com/unidoc/unidoc/pdf/internal/cmap"
|
||||||
"github.com/unidoc/unidoc/pdf/model/fonts"
|
"github.com/unidoc/unidoc/pdf/model/fonts"
|
||||||
"github.com/unidoc/unidoc/pdf/model/textencoding"
|
"github.com/unidoc/unidoc/pdf/model/textencoding"
|
||||||
)
|
)
|
||||||
@ -27,9 +28,23 @@ import (
|
|||||||
// containing font-wide metrics and other attributes of the font.
|
// containing font-wide metrics and other attributes of the font.
|
||||||
// Among those attributes is an optional font filestream containing the font program.
|
// Among those attributes is an optional font filestream containing the font program.
|
||||||
type pdfFontSimple struct {
|
type pdfFontSimple struct {
|
||||||
container *core.PdfIndirectObject
|
container *core.PdfIndirectObject
|
||||||
*fontSkeleton // Elements common to all font types
|
|
||||||
|
|
||||||
|
// These fields are common to all PDF fonts.
|
||||||
|
basefont string // The font's "BaseFont" field.
|
||||||
|
subtype string // The font's "Subtype" field.
|
||||||
|
|
||||||
|
// These are optional fields in the PDF font
|
||||||
|
toUnicode core.PdfObject // The stream containing toUnicodeCmap. We keep it around for ToPdfObject.
|
||||||
|
|
||||||
|
// These objects are computed from optional fields in the PDF font
|
||||||
|
toUnicodeCmap *cmap.CMap // Computed from "ToUnicode"
|
||||||
|
fontDescriptor *PdfFontDescriptor // Computed from "FontDescriptor"
|
||||||
|
|
||||||
|
// objectNumber helps us find the font in the PDF being processed. This helps with debugging
|
||||||
|
objectNumber int64
|
||||||
|
|
||||||
|
// These fields are specific to simple PDF fonts.
|
||||||
firstChar int
|
firstChar int
|
||||||
lastChar int
|
lastChar int
|
||||||
charWidths []float64
|
charWidths []float64
|
||||||
@ -41,6 +56,31 @@ type pdfFontSimple struct {
|
|||||||
LastChar core.PdfObject
|
LastChar core.PdfObject
|
||||||
Widths core.PdfObject
|
Widths core.PdfObject
|
||||||
Encoding core.PdfObject
|
Encoding core.PdfObject
|
||||||
|
|
||||||
|
// Standard 14 fonts metrics
|
||||||
|
fontMetrics map[string]fonts.CharMetrics
|
||||||
|
}
|
||||||
|
|
||||||
|
// pdfCIDFontType0FromSkeleton returns a pdfFontSimple with its common fields initalized.
|
||||||
|
func pdfFontSimpleFromSkeleton(base *fontCommon) *pdfFontSimple {
|
||||||
|
return &pdfFontSimple{
|
||||||
|
basefont: base.basefont,
|
||||||
|
subtype: base.subtype,
|
||||||
|
toUnicode: base.toUnicode,
|
||||||
|
fontDescriptor: base.fontDescriptor,
|
||||||
|
objectNumber: base.objectNumber,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// baseFields returns the fields of `font` that are common to all PDF fonts.
|
||||||
|
func (font *pdfFontSimple) baseFields() *fontCommon {
|
||||||
|
return &fontCommon{
|
||||||
|
basefont: font.basefont,
|
||||||
|
subtype: font.subtype,
|
||||||
|
toUnicode: font.toUnicode,
|
||||||
|
fontDescriptor: font.fontDescriptor,
|
||||||
|
objectNumber: font.objectNumber,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encoder returns the font's text encoder.
|
// Encoder returns the font's text encoder.
|
||||||
@ -56,6 +96,11 @@ func (font *pdfFontSimple) SetEncoder(encoder textencoding.TextEncoder) {
|
|||||||
// GetGlyphCharMetrics returns the character metrics for the specified glyph. A bool flag is
|
// GetGlyphCharMetrics returns the character metrics for the specified glyph. A bool flag is
|
||||||
// returned to indicate whether or not the entry was found in the glyph to charcode mapping.
|
// returned to indicate whether or not the entry was found in the glyph to charcode mapping.
|
||||||
func (font pdfFontSimple) GetGlyphCharMetrics(glyph string) (fonts.CharMetrics, bool) {
|
func (font pdfFontSimple) GetGlyphCharMetrics(glyph string) (fonts.CharMetrics, bool) {
|
||||||
|
if font.fontMetrics != nil {
|
||||||
|
metrics, ok := font.fontMetrics[glyph]
|
||||||
|
return metrics, ok
|
||||||
|
}
|
||||||
|
|
||||||
metrics := fonts.CharMetrics{}
|
metrics := fonts.CharMetrics{}
|
||||||
|
|
||||||
code, found := font.encoder.GlyphToCharcode(glyph)
|
code, found := font.encoder.GlyphToCharcode(glyph)
|
||||||
@ -87,7 +132,7 @@ func (font pdfFontSimple) GetGlyphCharMetrics(glyph string) (fonts.CharMetrics,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newSimpleFontFromPdfObject creates a pdfFontSimple from dictionary `d`. Elements of `d` that
|
// newSimpleFontFromPdfObject creates a pdfFontSimple from dictionary `d`. Elements of `d` that
|
||||||
// are already parsed are contained in `skeleton`.
|
// are already parsed are contained in `base`.
|
||||||
// An error is returned if there is a problem with loading.
|
// An error is returned if there is a problem with loading.
|
||||||
// !@#$ Just return a base 14 font, if obj is a base 14 font
|
// !@#$ Just return a base 14 font, if obj is a base 14 font
|
||||||
//
|
//
|
||||||
@ -96,20 +141,14 @@ func (font pdfFontSimple) GetGlyphCharMetrics(glyph string) (fonts.CharMetrics,
|
|||||||
//
|
//
|
||||||
// !@#$ 9.6.6.4 Encodings for TrueType Fonts (page 265)
|
// !@#$ 9.6.6.4 Encodings for TrueType Fonts (page 265)
|
||||||
// Need to get TrueType font's cmap
|
// Need to get TrueType font's cmap
|
||||||
func newSimpleFontFromPdfObject(skeleton *fontSkeleton, std14 bool) (*pdfFontSimple, error) {
|
func newSimpleFontFromPdfObject(d *core.PdfObjectDictionary, base *fontCommon, std14 bool) (*pdfFontSimple, error) {
|
||||||
font := &pdfFontSimple{fontSkeleton: skeleton}
|
font := pdfFontSimpleFromSkeleton(base)
|
||||||
|
|
||||||
d := skeleton.dict
|
|
||||||
|
|
||||||
// !@#$ Failing on ~/testdata/The-Byzantine-Generals-Problem.pdf
|
// !@#$ Failing on ~/testdata/The-Byzantine-Generals-Problem.pdf
|
||||||
|
// FirstChar is not defined in ~/testdata/shamirturing.pdf
|
||||||
if !std14 {
|
if !std14 {
|
||||||
obj := d.Get("FirstChar")
|
obj := d.Get("FirstChar")
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
// See ~/testdata/shamirturing.pdf
|
|
||||||
// if skeleton.subtype == "TrueType" {
|
|
||||||
// common.Log.Debug("ERROR: FirstChar attribute missing. font=%s d=%s", skeleton, d)
|
|
||||||
// return nil, ErrRequiredAttributeMissing
|
|
||||||
// }
|
|
||||||
obj = core.PdfObject(core.MakeInteger(0))
|
obj = core.PdfObject(core.MakeInteger(0))
|
||||||
}
|
}
|
||||||
font.FirstChar = obj
|
font.FirstChar = obj
|
||||||
@ -123,11 +162,7 @@ func newSimpleFontFromPdfObject(skeleton *fontSkeleton, std14 bool) (*pdfFontSim
|
|||||||
|
|
||||||
obj = d.Get("LastChar")
|
obj = d.Get("LastChar")
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
// if skeleton.subtype == "TrueType" {
|
obj = core.PdfObject(core.MakeInteger(255))
|
||||||
// common.Log.Debug("ERROR: LastChar attribute missing")
|
|
||||||
// return nil, ErrRequiredAttributeMissing
|
|
||||||
// }
|
|
||||||
obj = core.PdfObject(core.MakeInteger(0))
|
|
||||||
}
|
}
|
||||||
font.LastChar = obj
|
font.LastChar = obj
|
||||||
intVal, ok = core.TraceToDirectObject(obj).(*core.PdfObjectInteger)
|
intVal, ok = core.TraceToDirectObject(obj).(*core.PdfObjectInteger)
|
||||||
@ -140,9 +175,6 @@ func newSimpleFontFromPdfObject(skeleton *fontSkeleton, std14 bool) (*pdfFontSim
|
|||||||
font.charWidths = []float64{}
|
font.charWidths = []float64{}
|
||||||
obj = d.Get("Widths")
|
obj = d.Get("Widths")
|
||||||
if obj != nil {
|
if obj != nil {
|
||||||
// common.Log.Debug("ERROR: Widths missing from font")
|
|
||||||
// return nil, ErrRequiredAttributeMissing
|
|
||||||
// }
|
|
||||||
font.Widths = obj
|
font.Widths = obj
|
||||||
|
|
||||||
arr, ok := core.TraceToDirectObject(obj).(*core.PdfObjectArray)
|
arr, ok := core.TraceToDirectObject(obj).(*core.PdfObjectArray)
|
||||||
@ -173,7 +205,6 @@ func newSimpleFontFromPdfObject(skeleton *fontSkeleton, std14 bool) (*pdfFontSim
|
|||||||
// addEncoding adds the encoding to the font.
|
// addEncoding adds the encoding to the font.
|
||||||
// The order of precedence is important
|
// The order of precedence is important
|
||||||
func (font *pdfFontSimple) addEncoding() error {
|
func (font *pdfFontSimple) addEncoding() error {
|
||||||
skeleton := font.fontSkeleton
|
|
||||||
var baseEncoder string
|
var baseEncoder string
|
||||||
var differences map[byte]string
|
var differences map[byte]string
|
||||||
var err error
|
var err error
|
||||||
@ -181,12 +212,12 @@ func (font *pdfFontSimple) addEncoding() error {
|
|||||||
// !@#$ Stop setting default encoding in getFontEncoding XXX
|
// !@#$ Stop setting default encoding in getFontEncoding XXX
|
||||||
baseEncoder, differences, err = getFontEncoding(font.Encoding)
|
baseEncoder, differences, err = getFontEncoding(font.Encoding)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.Log.Debug("ERROR: BaseFont=%q Subtype=%q Encoding=%s (%T) err=%v", skeleton.basefont,
|
common.Log.Debug("ERROR: BaseFont=%q Subtype=%q Encoding=%s (%T) err=%v", font.basefont,
|
||||||
skeleton.subtype, font.Encoding, font.Encoding, err)
|
font.subtype, font.Encoding, font.Encoding, err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
common.Log.Debug("addEncoding: BaseFont=%q Subtype=%q Encoding=%s (%T)", skeleton.basefont,
|
common.Log.Debug("addEncoding: BaseFont=%q Subtype=%q Encoding=%s (%T)", font.basefont,
|
||||||
skeleton.subtype, font.Encoding, font.Encoding)
|
font.subtype, font.Encoding, font.Encoding)
|
||||||
|
|
||||||
encoder, err := textencoding.NewSimpleTextEncoder(baseEncoder, differences)
|
encoder, err := textencoding.NewSimpleTextEncoder(baseEncoder, differences)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -196,9 +227,9 @@ func (font *pdfFontSimple) addEncoding() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if font.Encoder() == nil {
|
if font.Encoder() == nil {
|
||||||
descriptor := skeleton.fontDescriptor
|
descriptor := font.fontDescriptor
|
||||||
if descriptor != nil {
|
if descriptor != nil {
|
||||||
switch skeleton.subtype {
|
switch font.subtype {
|
||||||
case "Type1":
|
case "Type1":
|
||||||
// XXX: !@#$ Is this the right order? Do the /Differences need to be reapplied?
|
// XXX: !@#$ Is this the right order? Do the /Differences need to be reapplied?
|
||||||
if descriptor.fontFile != nil && descriptor.fontFile.encoder != nil {
|
if descriptor.fontFile != nil && descriptor.fontFile.encoder != nil {
|
||||||
@ -212,7 +243,6 @@ func (font *pdfFontSimple) addEncoding() error {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
font.SetEncoder(encoder)
|
font.SetEncoder(encoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -277,7 +307,7 @@ func (font *pdfFontSimple) ToPdfObject() core.PdfObject {
|
|||||||
if font.container == nil {
|
if font.container == nil {
|
||||||
font.container = &core.PdfIndirectObject{}
|
font.container = &core.PdfIndirectObject{}
|
||||||
}
|
}
|
||||||
d := font.toDict("")
|
d := font.baseFields().asPdfObjectDictionary("")
|
||||||
font.container.PdfObject = d
|
font.container.PdfObject = d
|
||||||
|
|
||||||
if font.FirstChar != nil {
|
if font.FirstChar != nil {
|
||||||
@ -291,6 +321,8 @@ func (font *pdfFontSimple) ToPdfObject() core.PdfObject {
|
|||||||
}
|
}
|
||||||
if font.Encoding != nil {
|
if font.Encoding != nil {
|
||||||
d.Set("Encoding", font.Encoding)
|
d.Set("Encoding", font.Encoding)
|
||||||
|
} else if font.encoder != nil {
|
||||||
|
d.Set("Encoding", font.encoder.ToPdfObject())
|
||||||
}
|
}
|
||||||
|
|
||||||
return font.container
|
return font.container
|
||||||
@ -309,8 +341,7 @@ func NewPdfFontFromTTFFile(filePath string) (*PdfFont, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
skeleton := fontSkeleton{subtype: "TrueType"}
|
truefont := &pdfFontSimple{subtype: "TrueType"}
|
||||||
truefont := &pdfFontSimple{fontSkeleton: &skeleton}
|
|
||||||
|
|
||||||
// TODO: Make more generic to allow customization... Need to know which glyphs are to be used,
|
// TODO: Make more generic to allow customization... Need to know which glyphs are to be used,
|
||||||
// then can derive
|
// then can derive
|
||||||
@ -403,12 +434,84 @@ func NewPdfFontFromTTFFile(filePath string) (*PdfFont, error) {
|
|||||||
descriptor.Flags = core.MakeInteger(int64(flags))
|
descriptor.Flags = core.MakeInteger(int64(flags))
|
||||||
|
|
||||||
// Build Font.
|
// Build Font.
|
||||||
skeleton.fontDescriptor = descriptor
|
truefont.fontDescriptor = descriptor
|
||||||
|
|
||||||
font := &PdfFont{
|
font := &PdfFont{
|
||||||
fontSkeleton: skeleton,
|
context: truefont,
|
||||||
context: truefont,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return font, nil
|
return font, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var standard14Fonts = map[string]pdfFontSimple{
|
||||||
|
"Courier": pdfFontSimple{subtype: "Type1",
|
||||||
|
basefont: "Courier",
|
||||||
|
encoder: textencoding.NewWinAnsiTextEncoder(),
|
||||||
|
fontMetrics: fonts.CourierCharMetrics,
|
||||||
|
},
|
||||||
|
"Courier-Bold": pdfFontSimple{subtype: "Type1",
|
||||||
|
basefont: "Courier-Bold",
|
||||||
|
encoder: textencoding.NewWinAnsiTextEncoder(),
|
||||||
|
fontMetrics: fonts.CourierBoldCharMetrics,
|
||||||
|
},
|
||||||
|
"Courier-BoldOblique": pdfFontSimple{subtype: "Type1",
|
||||||
|
basefont: "Courier-BoldOblique",
|
||||||
|
encoder: textencoding.NewWinAnsiTextEncoder(),
|
||||||
|
fontMetrics: fonts.CourierBoldObliqueCharMetrics,
|
||||||
|
},
|
||||||
|
"Courier-Oblique": pdfFontSimple{subtype: "Type1",
|
||||||
|
basefont: "Courier-Oblique",
|
||||||
|
encoder: textencoding.NewWinAnsiTextEncoder(),
|
||||||
|
fontMetrics: fonts.CourierObliqueCharMetrics,
|
||||||
|
},
|
||||||
|
"Helvetica": pdfFontSimple{subtype: "Type1",
|
||||||
|
basefont: "Helvetica",
|
||||||
|
encoder: textencoding.NewWinAnsiTextEncoder(),
|
||||||
|
fontMetrics: fonts.HelveticaCharMetrics,
|
||||||
|
},
|
||||||
|
"Helvetica-Bold": pdfFontSimple{subtype: "Type1",
|
||||||
|
basefont: "Helvetica-Bold",
|
||||||
|
encoder: textencoding.NewWinAnsiTextEncoder(),
|
||||||
|
fontMetrics: fonts.HelveticaBoldCharMetrics,
|
||||||
|
},
|
||||||
|
"Helvetica-BoldOblique": pdfFontSimple{subtype: "Type1",
|
||||||
|
basefont: "Helvetica-BoldOblique",
|
||||||
|
encoder: textencoding.NewWinAnsiTextEncoder(),
|
||||||
|
fontMetrics: fonts.HelveticaBoldObliqueCharMetrics,
|
||||||
|
},
|
||||||
|
"Helvetica-Oblique": pdfFontSimple{subtype: "Type1",
|
||||||
|
basefont: "Helvetica-Oblique",
|
||||||
|
encoder: textencoding.NewWinAnsiTextEncoder(),
|
||||||
|
fontMetrics: fonts.HelveticaObliqueCharMetrics,
|
||||||
|
},
|
||||||
|
"Times-Roman": pdfFontSimple{subtype: "Type1",
|
||||||
|
basefont: "Times-Roman",
|
||||||
|
encoder: textencoding.NewWinAnsiTextEncoder(),
|
||||||
|
fontMetrics: fonts.TimesRomanCharMetrics,
|
||||||
|
},
|
||||||
|
"Times-Bold": pdfFontSimple{subtype: "Type1",
|
||||||
|
basefont: "Times-Bold",
|
||||||
|
encoder: textencoding.NewWinAnsiTextEncoder(),
|
||||||
|
fontMetrics: fonts.TimesBoldCharMetrics,
|
||||||
|
},
|
||||||
|
"Times-BoldItalic": pdfFontSimple{subtype: "Type1",
|
||||||
|
basefont: "Times-BoldItalic",
|
||||||
|
encoder: textencoding.NewWinAnsiTextEncoder(),
|
||||||
|
fontMetrics: fonts.TimesBoldItalicCharMetrics,
|
||||||
|
},
|
||||||
|
"Times-Italic": pdfFontSimple{subtype: "Type1",
|
||||||
|
basefont: "Times-Italic",
|
||||||
|
encoder: textencoding.NewWinAnsiTextEncoder(),
|
||||||
|
fontMetrics: fonts.TimesItalicCharMetrics,
|
||||||
|
},
|
||||||
|
"Symbol": pdfFontSimple{subtype: "Type1",
|
||||||
|
basefont: "Symbol",
|
||||||
|
encoder: textencoding.NewSymbolEncoder(),
|
||||||
|
fontMetrics: fonts.SymbolCharMetrics,
|
||||||
|
},
|
||||||
|
"ZapfDingbats": pdfFontSimple{subtype: "Type1",
|
||||||
|
basefont: "ZapfDingbats",
|
||||||
|
encoder: textencoding.NewZapfDingbatsEncoder(),
|
||||||
|
fontMetrics: fonts.ZapfDingbatsCharMetrics,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user