cmap

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 8, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package cmap reads PDF CMaps: the code-to-CID mappings of composite fonts and the code-to-Unicode mappings of /ToUnicode streams (ISO 32000-2 §9.7.5, §9.10.3).

A CMap answers two questions, and conflating them is a common source of wrong output. First, how many bytes is the next character code — one, two, or a mixture, decided by the codespace ranges. Second, what does that code mean, which is either a CID to look a glyph up by, or the text the glyph stands for. Both mappings share one syntax, so one parser reads both.

The byte-splitting question is the one that matters most in practice. A reader that assumes two-byte codes because Identity-H is common will mis-split every mixed-width CMap, and because the result is still a sequence of plausible codes it produces confident wrong text rather than an error.

CMap syntax is PostScript, but only a fixed skeleton of it is legal here, so this package reads tokens rather than interpreting a language: the operators it recognizes are listed in the switch in parse, and everything else is skipped. The tokenizer is content's, because the token syntax is the same one.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CMap

type CMap struct {
	// Name is the /CMapName, when the CMap declares one.
	Name string
	// contains filtered or unexported fields
}

CMap maps character codes to CIDs, or to text, or both.

Both because a /ToUnicode CMap and a CID CMap are the same object with different contents, and a font may have either or both. Absent entries are reported as absent rather than as zero: CID 0 is the notdef glyph and the empty string is a legitimate mapping, so the caller must be able to tell "no answer" from "this answer".

func Identity

func Identity(name string) (*CMap, bool)

Identity returns the Identity-H or Identity-V CMap, or false for any other name.

These two are predefined rather than embedded in the file: two-byte codes mapping to the same CID. They are handled here rather than by loading a predefined CMap file because they need no file, and because every composite font in this repo's corpus uses Identity-H.

func Parse

func Parse(data []byte) (*CMap, error)

Parse reads a CMap from a stream's decoded bytes.

Unrecognized constructs are skipped rather than rejected. A /ToUnicode stream carrying a stray PostScript procedure is common, and a parser that fails on it throws away every mapping in the file over a construct it did not need to understand.

func TwoByte

func TwoByte(name string) *CMap

TwoByte returns a CMap that reads two-byte codes and maps nothing.

This is the fallback for a composite font naming a predefined CMap this package does not carry. Every predefined CMap in ISO 32000-2 Table 118 except the deprecated ones uses two-byte codes, so splitting the string correctly is still possible even when the CIDs are not; the caller then has code widths right and can fall back to /ToUnicode for meaning. Guessing one-byte codes instead would double the glyph count and garble the text.

func (*CMap) CID

func (c *CMap) CID(code uint32) (uint32, bool)

CID returns the CID a code maps to.

func (*CMap) CodeForText

func (c *CMap) CodeForText(text string) (uint32, bool)

CodeForText returns a code that maps to the given text.

This exists for one question the font package has to ask: which code is the space, so that inter-word gaps can be measured against its width. A composite font gives no other way to find it, since a CID carries no character meaning.

The lowest matching code is returned, so the answer does not depend on map iteration order. Several codes mapping to the same text is normal — a subset font often has more than one space-like glyph — and any of them would have the right width, but a stable answer is what makes the caller's behavior reproducible.

func (*CMap) Codes

func (c *CMap) Codes(s []byte) []Code

Codes splits a PDF string into character codes.

The splitting follows §9.7.6.2: the codespace ranges are matched by byte width, shortest first, and a code whose leading bytes fall in no range is still consumed at the width of the shortest range that its first byte could begin. That last rule is what keeps a malformed string from desynchronizing everything after it — the alternative is to stop, which loses the rest of the text for one bad byte.

A CMap with no codespace ranges reads two-byte codes, because a CMap stream that omits them is malformed and every composite font this applies to uses two-byte codes.

func (*CMap) Entries

func (c *CMap) Entries() (cids, texts int)

Entries reports how many code-to-CID and code-to-text mappings the CMap holds, for callers deciding whether it is worth consulting.

func (*CMap) Text

func (c *CMap) Text(code uint32) (string, bool)

Text returns the characters a code stands for, from a /ToUnicode CMap.

type Code

type Code struct {
	Value uint32
	Bytes int
}

Code is one character code lifted out of a string, with the byte width it was written in.

The width is carried because the caller needs it: a /W array indexes by CID, but positioning and error reporting work in bytes, and a two-byte code that consumed one byte on a malformed stream must not silently shift everything after it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL