Documentation ¶
Overview ¶
Package postscript implements a rudimentary PostScript interpreter.
The package does not implement any drawing operations. It does implement enough of the PostScript language to be able to read most Type 1 fonts.
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var ( ErrExecutionLimitExceeded = &postScriptError{eInterrupt, "execution limit exceeded"} ErrNoPostScript = errors.New("not a PostScript file") )
View Source
var CIDInit = Dict{ "begincmap": builtin(func(intp *Interpreter) error { intp.cmap = &CMapInfo{} return nil }), "endcmap": builtin(func(intp *Interpreter) error { if len(intp.DictStack) < 1 || intp.cmap == nil { return intp.e(eStackunderflow, "endcmap: cmap dictionary not found") } sort.Slice(intp.cmap.CodeSpaceRanges, func(i, j int) bool { if len(intp.cmap.CodeSpaceRanges[i].Low) != len(intp.cmap.CodeSpaceRanges[j].Low) { return len(intp.cmap.CodeSpaceRanges[i].Low) < len(intp.cmap.CodeSpaceRanges[j].Low) } return bytes.Compare(intp.cmap.CodeSpaceRanges[i].Low, intp.cmap.CodeSpaceRanges[j].Low) < 0 }) sort.Slice(intp.cmap.Chars, func(i, j int) bool { return bytes.Compare(intp.cmap.Chars[i].Src, intp.cmap.Chars[j].Src) < 0 }) sort.Slice(intp.cmap.Ranges, func(i, j int) bool { return bytes.Compare(intp.cmap.Ranges[i].Low, intp.cmap.Ranges[j].Low) < 0 }) dict := intp.DictStack[len(intp.DictStack)-1] dict["CodeMap"] = intp.cmap intp.cmap = nil return nil }), "usecmap": builtin(func(intp *Interpreter) error { if intp.cmap == nil { return intp.e(eUndefined, "usecmap: not in cmap block") } if len(intp.Stack) < 1 { return intp.e(eStackunderflow, "usecmap: not enough arguments") } name, ok := intp.Stack[len(intp.Stack)-1].(Name) if !ok { return intp.e(eTypecheck, "usecmap: expected name, got %T", intp.Stack[len(intp.Stack)-1]) } intp.Stack = intp.Stack[:len(intp.Stack)-1] intp.cmap.UseCMap = string(name) return nil }), "begincodespacerange": builtin(func(intp *Interpreter) error { if intp.cmap == nil { return intp.e(eUndefined, "begincodespacerange: not in cmap block") } if len(intp.Stack) < 1 { return intp.e(eStackunderflow, "begincodespacerange: not enough arguments") } n, ok := intp.Stack[len(intp.Stack)-1].(Integer) if !ok { return intp.e(eTypecheck, "begincodespacerange: expected integer, got %T", intp.Stack[len(intp.Stack)-1]) } else if n < 0 || n > 100 { return intp.e(eRangecheck, "begincodespacerange: invalid length %d", n) } intp.Stack = intp.Stack[:len(intp.Stack)-1] intp.cmap.tmpCodeSpaceRanges = make([]CodeSpaceRange, n) return nil }), "endcodespacerange": builtin(func(intp *Interpreter) error { if intp.cmap == nil { return intp.e(eUndefined, "endcodespacerange: not in cmap block") } base := len(intp.Stack) - 2*len(intp.cmap.tmpCodeSpaceRanges) if base < 0 { return intp.e(eStackunderflow, "endcodespacerange: not enough arguments") } for i := range intp.cmap.tmpCodeSpaceRanges { lo, ok := intp.Stack[base+2*i].(String) if !ok { return intp.e(eTypecheck, "endcodespacerange: expected string, got %T", intp.Stack[base+2*i]) } hi, ok := intp.Stack[base+2*i+1].(String) if !ok { return intp.e(eTypecheck, "endcodespacerange: expected string, got %T", intp.Stack[base+2*i+1]) } if len(lo) != len(hi) { return intp.e(eRangecheck, "endcodespacerange: expected strings of equal length, got %d and %d", len(lo), len(hi)) } intp.cmap.tmpCodeSpaceRanges[i] = CodeSpaceRange{lo, hi} } intp.Stack = intp.Stack[:base] intp.cmap.CodeSpaceRanges = append(intp.cmap.CodeSpaceRanges, intp.cmap.tmpCodeSpaceRanges...) intp.cmap.tmpCodeSpaceRanges = nil return nil }), "begincidchar": builtin(func(intp *Interpreter) error { if intp.cmap == nil { return intp.e(eUndefined, "begincidchar: not in cmap block") } if len(intp.Stack) < 1 { return intp.e(eStackunderflow, "begincidchar: not enough arguments") } n, ok := intp.Stack[len(intp.Stack)-1].(Integer) if !ok { return intp.e(eTypecheck, "begincidchar: expected integer, got %T", intp.Stack[len(intp.Stack)-1]) } else if n < 0 || n > 100 { return intp.e(eRangecheck, "begincidchar: invalid length %d", n) } intp.Stack = intp.Stack[:len(intp.Stack)-1] intp.cmap.tmpChars = make([]CharMap, n) return nil }), "endcidchar": builtin(func(intp *Interpreter) error { if intp.cmap == nil { return intp.e(eUndefined, "endcidchar: not in cmap block") } base := len(intp.Stack) - 2*len(intp.cmap.tmpChars) if base < 0 { return intp.e(eStackunderflow, "endcidchar: not enough arguments") } for i := range intp.cmap.tmpChars { code, ok := intp.Stack[base+2*i].(String) if !ok { return intp.e(eTypecheck, "endcidchar: expected string, got %T", intp.Stack[base+2*i]) } val := intp.Stack[base+2*i+1] if _, ok := val.(Integer); !ok { return intp.e(eTypecheck, "endcidchar: expected integer, got %T", val) } intp.cmap.tmpChars[i] = CharMap{code, val} } intp.Stack = intp.Stack[:base] intp.cmap.Chars = append(intp.cmap.Chars, intp.cmap.tmpChars...) intp.cmap.tmpChars = nil return nil }), "begincidrange": builtin(func(intp *Interpreter) error { if intp.cmap == nil { return intp.e(eUndefined, "begincidrange: not in cmap block") } if len(intp.Stack) < 1 { return intp.e(eStackunderflow, "begincidrange: not enough arguments") } n, ok := intp.Stack[len(intp.Stack)-1].(Integer) if !ok { return intp.e(eTypecheck, "begincidrange: expected integer, got %T", intp.Stack[len(intp.Stack)-1]) } else if n < 0 || n > 100 { return intp.e(eRangecheck, "begincidrange: invalid length %d", n) } intp.Stack = intp.Stack[:len(intp.Stack)-1] intp.cmap.tmpRanges = make([]RangeMap, n) return nil }), "endcidrange": builtin(func(intp *Interpreter) error { if intp.cmap == nil { return intp.e(eUndefined, "endcidrange: not in cmap block") } base := len(intp.Stack) - 3*len(intp.cmap.tmpRanges) if base < 0 { return intp.e(eStackunderflow, "endcidrange: not enough arguments") } for i := range intp.cmap.tmpRanges { lo, ok := intp.Stack[base+3*i].(String) if !ok { return intp.e(eTypecheck, "endcidrange: expected string, got %T", intp.Stack[base+3*i]) } hi, ok := intp.Stack[base+3*i+1].(String) if !ok { return intp.e(eTypecheck, "endcidrange: expected string, got %T", intp.Stack[base+3*i+1]) } if len(lo) != len(hi) || bytes.Compare(lo, hi) > 0 { return intp.e(eRangecheck, "endcidrange: invalid range <%x> <%x>", lo, hi) } val := intp.Stack[base+3*i+2] if _, ok := val.(Integer); !ok { return intp.e(eTypecheck, "endcidrange: expected integer, got %T", val) } intp.cmap.tmpRanges[i].Low = lo intp.cmap.tmpRanges[i].High = hi intp.cmap.tmpRanges[i].Dst = val } intp.Stack = intp.Stack[:base] intp.cmap.Ranges = append(intp.cmap.Ranges, intp.cmap.tmpRanges...) intp.cmap.tmpRanges = nil return nil }), "beginbfchar": builtin(func(intp *Interpreter) error { if intp.cmap == nil { return intp.e(eUndefined, "beginbfchar: not in cmap block") } if len(intp.Stack) < 1 { return intp.e(eStackunderflow, "beginbfchar: not enough arguments") } n, ok := intp.Stack[len(intp.Stack)-1].(Integer) if !ok { return intp.e(eTypecheck, "beginbfchar: expected integer, got %T", intp.Stack[len(intp.Stack)-1]) } else if n < 0 || n > 100 { return intp.e(eRangecheck, "beginbfchar: invalid length %d", n) } intp.Stack = intp.Stack[:len(intp.Stack)-1] intp.cmap.tmpChars = make([]CharMap, n) return nil }), "endbfchar": builtin(func(intp *Interpreter) error { if intp.cmap == nil { return intp.e(eUndefined, "endbfchar: not in cmap block") } base := len(intp.Stack) - 2*len(intp.cmap.tmpChars) if base < 0 { return intp.e(eStackunderflow, "endbfchar: not enough arguments") } for i := range intp.cmap.tmpChars { code, ok := intp.Stack[base+2*i].(String) if !ok { return intp.e(eTypecheck, "endbfchar: expected string, got %T", intp.Stack[base+2*i]) } val := intp.Stack[base+2*i+1] if !isStringOrName(val) { return intp.e(eTypecheck, "endbfchar: expected string or name, got %T", val) } intp.cmap.tmpChars[i] = CharMap{code, val} } intp.Stack = intp.Stack[:base] intp.cmap.Chars = append(intp.cmap.Chars, intp.cmap.tmpChars...) intp.cmap.tmpChars = nil return nil }), "beginbfrange": builtin(func(intp *Interpreter) error { if intp.cmap == nil { return intp.e(eUndefined, "beginbfrange: not in cmap block") } if len(intp.Stack) < 1 { return intp.e(eStackunderflow, "beginbfrange: not enough arguments") } n, ok := intp.Stack[len(intp.Stack)-1].(Integer) if !ok { return intp.e(eTypecheck, "beginbfrange: expected integer, got %T", intp.Stack[len(intp.Stack)-1]) } else if n < 0 || n > 100 { return intp.e(eRangecheck, "beginbfrange: invalid length %d", n) } intp.Stack = intp.Stack[:len(intp.Stack)-1] intp.cmap.tmpRanges = make([]RangeMap, n) return nil }), "endbfrange": builtin(func(intp *Interpreter) error { if intp.cmap == nil { return intp.e(eUndefined, "endbfrange: not in cmap block") } base := len(intp.Stack) - 3*len(intp.cmap.tmpRanges) if base < 0 { return intp.e(eStackunderflow, "endbfrange: not enough arguments") } for i := range intp.cmap.tmpRanges { lo, ok := intp.Stack[base+3*i].(String) if !ok { return intp.e(eTypecheck, "endbfrange: expected string, got %T", intp.Stack[base+3*i]) } hi, ok := intp.Stack[base+3*i+1].(String) if !ok { return intp.e(eTypecheck, "endbfrange: expected string, got %T", intp.Stack[base+3*i+1]) } if len(lo) != len(hi) || bytes.Compare(lo, hi) > 0 { return intp.e(eRangecheck, "endbfrange: invalid range <%x> <%x>", lo, hi) } val := intp.Stack[base+3*i+2] if !isStringOrArray(val) { return intp.e(eTypecheck, "endbfrange: expected string or array of names, got %T", val) } intp.cmap.tmpRanges[i].Low = lo intp.cmap.tmpRanges[i].High = hi intp.cmap.tmpRanges[i].Dst = val } intp.Stack = intp.Stack[:base] intp.cmap.Ranges = append(intp.cmap.Ranges, intp.cmap.tmpRanges...) intp.cmap.tmpRanges = nil return nil }), "beginnotdefchar": builtin(func(intp *Interpreter) error { if intp.cmap == nil { return intp.e(eUndefined, "beginnotdefchar: not in cmap block") } if len(intp.Stack) < 1 { return intp.e(eStackunderflow, "beginnotdefchar: not enough arguments") } n, ok := intp.Stack[len(intp.Stack)-1].(Integer) if !ok { return intp.e(eTypecheck, "beginnotdefchar: expected integer, got %T", intp.Stack[len(intp.Stack)-1]) } else if n < 0 || n > 100 { return intp.e(eRangecheck, "beginnotdefchar: invalid length %d", n) } intp.Stack = intp.Stack[:len(intp.Stack)-1] intp.cmap.tmpChars = make([]CharMap, n) return nil }), "endnotdefchar": builtin(func(intp *Interpreter) error { if intp.cmap == nil { return intp.e(eUndefined, "endnotdefchar: not in cmap block") } base := len(intp.Stack) - 2*len(intp.cmap.tmpChars) if base < 0 { return intp.e(eStackunderflow, "endnotdefchar: not enough arguments") } for i := range intp.cmap.tmpChars { code, ok := intp.Stack[base+2*i].(String) if !ok { return intp.e(eTypecheck, "endnotdefchar: expected string, got %T", intp.Stack[base+2*i]) } val := intp.Stack[base+2*i+1] if _, ok := val.(Integer); !ok { return intp.e(eTypecheck, "endnotdefchar: expected integer, got %T", val) } intp.cmap.tmpChars[i] = CharMap{code, val} } intp.Stack = intp.Stack[:base] intp.cmap.tmpChars = nil return nil }), "beginnotdefrange": builtin(func(intp *Interpreter) error { if intp.cmap == nil { return intp.e(eUndefined, "beginnotdefrange: not in cmap block") } if len(intp.Stack) < 1 { return intp.e(eStackunderflow, "beginnotdefrange: not enough arguments") } n, ok := intp.Stack[len(intp.Stack)-1].(Integer) if !ok { return intp.e(eTypecheck, "beginnotdefrange: expected integer, got %T", intp.Stack[len(intp.Stack)-1]) } else if n < 0 || n > 100 { return intp.e(eRangecheck, "beginnotdefrange: invalid length %d", n) } intp.Stack = intp.Stack[:len(intp.Stack)-1] intp.cmap.tmpRanges = make([]RangeMap, n) return nil }), "endnotdefrange": builtin(func(intp *Interpreter) error { if intp.cmap == nil { return intp.e(eUndefined, "endnotdefrange: not in cmap block") } base := len(intp.Stack) - 3*len(intp.cmap.tmpRanges) if base < 0 { return intp.e(eStackunderflow, "endnotdefrange: not enough arguments") } for i := range intp.cmap.tmpRanges { lo, ok := intp.Stack[base+3*i].(String) if !ok { return intp.e(eTypecheck, "endnotdefrange: expected string, got %T", intp.Stack[base+3*i]) } hi, ok := intp.Stack[base+3*i+1].(String) if !ok { return intp.e(eTypecheck, "endnotdefrange: expected string, got %T", intp.Stack[base+3*i+1]) } if len(lo) != len(hi) || bytes.Compare(lo, hi) > 0 { return intp.e(eRangecheck, "endnotdefrange: invalid range <%x> <%x>", lo, hi) } val := intp.Stack[base+3*i+2] if _, ok := val.(Integer); !ok { return intp.e(eTypecheck, "endnotdefrange: expected integer, got %T", val) } intp.cmap.tmpRanges[i].Low = lo intp.cmap.tmpRanges[i].High = hi intp.cmap.tmpRanges[i].Dst = val } intp.Stack = intp.Stack[:base] intp.cmap.tmpRanges = nil return nil }), }
Functions ¶
This section is empty.
Types ¶
type CMapInfo ¶ added in v0.3.5
type CMapInfo struct { CodeSpaceRanges []CodeSpaceRange Chars []CharMap Ranges []RangeMap UseCMap string // contains filtered or unexported fields }
type CodeSpaceRange ¶ added in v0.3.5
type CodeSpaceRange struct {
Low, High []byte
}
type Interpreter ¶
type Interpreter struct { // CheckStart can be set to true to make the interpreter check that the // first two input bytes are "%!"; otherwise, ErrNoPostScript is returned. // This flag must be set before the first call to Execute. CheckStart bool // MaxOps can be set to a positive value to limit the number of executed // operations. If this limit is exceeded, ErrExecutionLimitExceeded is // returned. MaxOps int // Stack is the PostScript operand stack. Stack []Object // DictStack is the PostScript dictionary stack. DictStack []Dict // NumOps is the number of executed operations so far. NumOps int // SystemDict is the PostScript system dictionary. SystemDict Dict // InternalDict is the PostScript internal dictionary. InternalDict Dict // UserDict is the PostScript user dictionary. UserDict Dict // ErrorDict is the PostScript error dictionary. ErrorDict Dict // Resources is a Dict of Dicts, which contains the resources // for each category. Resources Dict // FontDirectory is the PostScript font directory. // The `definefont` PostScript operator adds fonts to this dictionary. FontDirectory Dict CMapDirectory Dict // DSC contains all DSC comments found in the input so far. // These are comments of the form "%%key: value" or "%%key". DSC []Comment // contains filtered or unexported fields }
Interpreter represents one instance of the PostScript interpreter.
func NewInterpreter ¶
func NewInterpreter() *Interpreter
NewInterpreter creates a new instance of the PostScript interpreter.
func (*Interpreter) Execute ¶
func (intp *Interpreter) Execute(r io.Reader) error
Execute executes the PostScript code in the given reader.
func (*Interpreter) ExecuteString ¶
func (intp *Interpreter) ExecuteString(code string) error
ExecuteString executes the PostScript code in the given string.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package afm provides a parser for Adobe Font Metrics (AFM) files.
|
Package afm provides a parser for Adobe Font Metrics (AFM) files. |
examples
|
|
Package funit contains types for representing font design units.
|
Package funit contains types for representing font design units. |
Package pfb implements the PFB (Printer Font Binary) format.
|
Package pfb implements the PFB (Printer Font Binary) format. |
Package type1 implements reading and writing of PostScript Type 1 fonts.
|
Package type1 implements reading and writing of PostScript Type 1 fonts. |
Click to show internal directories.
Click to hide internal directories.