zpb-ttf-0.7/ 0040775 0000764 0000764 00000000000 10524643132 011414 5 ustar xach xach zpb-ttf-0.7/zpb-ttf.asd 0100664 0000764 0000764 00000006760 10411055337 013500 0 ustar xach xach ;; zpb-ttf.asd,v 1.5 2006/03/24 20:47:27 xach Exp (defpackage #:zpb-ttf-system (:use #:cl #:asdf)) (in-package #:zpb-ttf-system) (defsystem #:zpb-ttf :version "0.5" :components ((:file "package") (:file "util" :depends-on ("package")) (:file "conditions" :depends-on ("package")) (:file "bounding-box" :depends-on ("package")) (:file "font-loader" :depends-on ("package" "util" "bounding-box")) (:file "maxp" :depends-on ("package" "util" "font-loader")) (:file "head" :depends-on ("package" "util" "conditions" "font-loader")) (:file "kern" :depends-on ("package" "util" "conditions" "font-loader")) (:file "loca" :depends-on ("package" "util" "font-loader")) (:file "name" :depends-on ("package" "util" "conditions" "font-loader")) (:file "cmap" :depends-on ("package" "util" "name" "font-loader")) (:file "post" :depends-on ("package" "util" "conditions" "font-loader")) (:file "hhea" :depends-on ("package" "util" "font-loader")) (:file "hmtx" :depends-on ("package" "util" "font-loader" "hhea")) (:file "glyf" :depends-on ("package" "util" "loca" "font-loader")) (:file "glyph" :depends-on ("package" "util" "font-loader" "bounding-box" "glyf" "kern" "loca")) (:file "font-loader-interface" :depends-on ("package" "util" "conditions" "font-loader" "maxp" "head" "kern" "loca" "name" "cmap" "post" "hhea" "hmtx")))) zpb-ttf-0.7/maxp.lisp 0100664 0000764 0000764 00000003563 10375725047 013270 0 ustar xach xach ;;; Copyright (c) 2006 Zachary Beane, All Rights Reserved ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; ;;; * Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; ;;; * Redistributions in binary form must reproduce the above ;;; copyright notice, this list of conditions and the following ;;; disclaimer in the documentation and/or other materials ;;; provided with the distribution. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;;; ;;; Loading data from the "maxp" table. ;;; ;;; http://www.microsoft.com/OpenType/OTSpec/maxp.htm ;;; http://developer.apple.com/fonts/TTRefMan/RM06/Chap6maxp.html ;;; ;;; maxp.lisp,v 1.3 2006/02/18 23:13:43 xach Exp (in-package #:zpb-ttf) (defmethod load-maxp-info ((font-loader font-loader)) (seek-to-table "maxp" font-loader) (with-slots (input-stream glyph-count) font-loader (let ((version (read-uint32 input-stream))) (check-version "\"maxp\" table" version #x00010000) (setf glyph-count (read-uint16 input-stream))))) zpb-ttf-0.7/hmtx.lisp 0100664 0000764 0000764 00000004310 10375725047 013272 0 ustar xach xach ;;; Copyright (c) 2006 Zachary Beane, All Rights Reserved ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; ;;; * Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; ;;; * Redistributions in binary form must reproduce the above ;;; copyright notice, this list of conditions and the following ;;; disclaimer in the documentation and/or other materials ;;; provided with the distribution. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;;; ;;; Loading data from the "hmtx" table. ;;; ;;; http://www.microsoft.com/OpenType/OTSpec/hmtx.htm ;;; http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hmtx.html ;;; ;;; hmtx.lisp,v 1.3 2006/02/18 23:13:43 xach Exp (in-package #:zpb-ttf) (defmethod load-hmtx-info ((font-loader font-loader)) (let* ((horizontal-metrics-count (horizontal-metrics-count font-loader)) (advance-widths (make-array horizontal-metrics-count)) (left-side-bearings (make-array horizontal-metrics-count))) (seek-to-table "hmtx" font-loader) (with-slots (input-stream) font-loader (dotimes (i horizontal-metrics-count) (setf (svref advance-widths i) (read-uint16 input-stream)) (setf (svref left-side-bearings i) (read-int16 input-stream)))) (setf (advance-widths font-loader) advance-widths (left-side-bearings font-loader) left-side-bearings))) zpb-ttf-0.7/cmap.lisp 0100664 0000764 0000764 00000021502 10410617744 013226 0 ustar xach xach ;;; Copyright (c) 2006 Zachary Beane, All Rights Reserved ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; ;;; * Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; ;;; * Redistributions in binary form must reproduce the above ;;; copyright notice, this list of conditions and the following ;;; disclaimer in the documentation and/or other materials ;;; provided with the distribution. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;;; ;;; Loading data from the "cmap" table. ;;; ;;; http://www.microsoft.com/OpenType/OTSpec/cmap.htm ;;; http://developer.apple.com/fonts/TTRefMan/RM06/Chap6cmap.html ;;; ;;; cmap.lisp,v 1.15 2006/03/23 22:23:32 xach Exp (in-package #:zpb-ttf) (deftype cmap-value-table () `(array (unsigned-byte 16) (*))) ;;; FIXME: "unicode-cmap" is actually a format 4 character map that ;;; happens to currently be loaded from a Unicode-compatible ;;; subtable. However, other character maps (like Microsoft's Symbol ;;; encoding) also use format 4 and could be loaded with these ;;; "unicode" objects and functions. (defclass unicode-cmap () ((segment-count :initarg :segment-count :reader segment-count) (end-codes :initarg :end-codes :reader end-codes) (start-codes :initarg :start-codes :reader start-codes) (id-deltas :initarg :id-deltas :reader id-deltas) (id-range-offsets :initarg :id-range-offsets :reader id-range-offsets) (glyph-indexes :initarg :glyph-indexes :accessor glyph-indexes))) (defun load-unicode-cmap (stream) "Load a Unicode character map of type 4 from STREAM starting at the current offset." (let ((format (read-uint16 stream))) (when (/= format 4) (error 'unsupported-format :location "\"cmap\" subtable" :actual-value format :expected-values (list 4)))) (let ((table-start (- (file-position stream) 2)) (subtable-length (read-uint16 stream)) (language-code (read-uint16 stream)) (segment-count (/ (read-uint16 stream) 2)) (search-range (read-uint16 stream)) (entry-selector (read-uint16 stream)) (range-shift (read-uint16 stream))) (declare (ignore language-code search-range entry-selector range-shift)) (flet ((make-and-load-array (&optional (size segment-count)) (loop with array = (make-array size :element-type '(unsigned-byte 16) :initial-element 0) for i below size do (setf (aref array i) (read-uint16 stream)) finally (return array))) (make-signed (i) (if (logbitp 15 i) (1- (- (logandc2 #xFFFF i))) i))) (let ((end-codes (make-and-load-array)) (pad (read-uint16 stream)) (start-codes (make-and-load-array)) (id-deltas (make-and-load-array)) (id-range-offsets (make-and-load-array)) (glyph-index-array-size (/ (- subtable-length (- (file-position stream) table-start)) 2))) (declare (ignore pad)) (make-instance 'unicode-cmap :segment-count segment-count :end-codes end-codes :start-codes start-codes ;; these are really signed, so sign them :id-deltas (map 'vector #'make-signed id-deltas) :id-range-offsets id-range-offsets :glyph-indexes (make-and-load-array glyph-index-array-size)))))) (defmethod invert-character-map (font-loader) "Return a vector mapping font indexes to code points." (with-slots (start-codes end-codes) (character-map font-loader) (declare (type cmap-value-table start-codes end-codes)) (let ((points (make-array (glyph-count font-loader) :initial-element -1))) (dotimes (i (1- (length end-codes)) points) (loop for j from (aref start-codes i) to (aref end-codes i) for font-index = (code-point-font-index j font-loader) when (minusp (svref points font-index)) do (setf (svref points font-index) j)))))) (defgeneric code-point-font-index (code-point font-loader) (:documentation "Return the index of the Unicode CODE-POINT in FONT-LOADER, if present, otherwise NIL.") (:method (code-point font-loader) (let ((cmap (character-map font-loader))) (with-slots (end-codes start-codes id-deltas id-range-offsets glyph-indexes) cmap (declare (type cmap-value-table end-codes start-codes id-deltas id-range-offsets glyph-indexes)) (dotimes (i (segment-count cmap) 1) (when (<= code-point (aref end-codes i)) (return (let ((start-code (aref start-codes i)) (id-range-offset (aref id-range-offsets i)) (id-delta (aref id-deltas i))) (cond ((< code-point start-code) 0) ((zerop id-range-offset) (logand #xFFFF (+ code-point id-delta))) (t (let* ((glyph-index-offset (- (+ i (ash id-range-offset -1) (- code-point start-code)) (segment-count cmap))) (glyph-index (aref (glyph-indexes cmap) glyph-index-offset))) (logand #xFFFF (+ glyph-index id-delta))))))))))))) (defgeneric font-index-code-point (glyph-index font-loader) (:documentation "Return the code-point for a given glyph index.") (:method (glyph-index font-loader) (let ((point (aref (inverse-character-map font-loader) glyph-index))) (if (plusp point) point 0)))) (defmethod load-cmap-info ((font-loader font-loader)) (seek-to-table "cmap" font-loader) (with-slots (input-stream) font-loader (let ((start-pos (file-position input-stream)) (version-number (read-uint16 input-stream)) (subtable-count (read-uint16 input-stream)) (foundp nil)) (declare (ignore version-number)) (loop repeat subtable-count for platform-id = (read-uint16 input-stream) for platform-specific-id = (read-uint16 input-stream) for offset = (+ start-pos (read-uint32 input-stream)) when (and (= platform-id +microsoft-platform-id+) (= platform-specific-id +microsoft-unicode-bmp-encoding-id+)) do (file-position input-stream offset) (setf (character-map font-loader) (load-unicode-cmap input-stream)) (setf (inverse-character-map font-loader) (invert-character-map font-loader) foundp t) (return)) (unless foundp (error "Could not find supported character map in font file"))))) (defun available-character-maps (loader) (seek-to-table "cmap" loader) (let ((stream (input-stream loader))) (let ((start-pos (file-position stream)) (version-number (read-uint16 stream)) (subtable-count (read-uint16 stream))) (declare (ignore start-pos)) (assert (zerop version-number)) (dotimes (i subtable-count) (let ((platform-id (read-uint16 stream)) (encoding-id (read-uint16 stream)) (offset (read-uint32 stream))) (declare (ignore offset)) (format t "~D (~A) - ~D (~A)~%" platform-id (platform-id-name platform-id) encoding-id (encoding-id-name platform-id encoding-id))))))) zpb-ttf-0.7/post.lisp 0100664 0000764 0000764 00000017177 10524641750 013310 0 ustar xach xach ;;; Copyright (c) 2006 Zachary Beane, All Rights Reserved ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; ;;; * Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; ;;; * Redistributions in binary form must reproduce the above ;;; copyright notice, this list of conditions and the following ;;; disclaimer in the documentation and/or other materials ;;; provided with the distribution. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;;; ;;; "post" table functions ;;; ;;; http://www.microsoft.com/OpenType/OTSpec/post.htm ;;; http://developer.apple.com/fonts/TTRefMan/RM06/Chap6post.html ;;; ;;; post.lisp,v 1.7 2006/11/09 15:06:16 xach Exp (in-package #:zpb-ttf) (defvar *standard-mac-glyph-names* #(".notdef" ".null" "nonmarkingreturn" "space" "exclam" "quotedbl" "numbersign" "dollar" "percent" "ampersand" "quotesingle" "parenleft" "parenright" "asterisk" "plus" "comma" "hyphen" "period" "slash" "zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine" "colon" "semicolon" "less" "equal" "greater" "question" "at" "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "bracketleft" "backslash" "bracketright" "asciicircum" "underscore" "grave" "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z" "braceleft" "bar" "braceright" "asciitilde" "Adieresis" "Aring" "Ccedilla" "Eacute" "Ntilde" "Odieresis" "Udieresis" "aacute" "agrave" "acircumflex" "adieresis" "atilde" "aring" "ccedilla" "eacute" "egrave" "ecircumflex" "edieresis" "iacute" "igrave" "icircumflex" "idieresis" "ntilde" "oacute" "ograve" "ocircumflex" "odieresis" "otilde" "uacute" "ugrave" "ucircumflex" "udieresis" "dagger" "degree" "cent" "sterling" "section" "bullet" "paragraph" "germandbls" "registered" "copyright" "trademark" "acute" "dieresis" "notequal" "AE" "Oslash" "infinity" "plusminus" "lessequal" "greaterequal" "yen" "mu" "partialdiff" "summation" "product" "pi" "integral" "ordfeminine" "ordmasculine" "Omega" "ae" "oslash" "questiondown" "exclamdown" "logicalnot" "radical" "florin" "approxequal" "Delta" "guillemotleft" "guillemotright" "ellipsis" "nonbreakingspace" "Agrave" "Atilde" "Otilde" "OE" "oe" "endash" "emdash" "quotedblleft" "quotedblright" "quoteleft" "quoteright" "divide" "lozenge" "ydieresis" "Ydieresis" "fraction" "currency" "guilsinglleft" "guilsinglright" "fi" "fl" "daggerdbl" "periodcentered" "quotesinglbase" "quotedblbase" "perthousand" "Acircumflex" "Ecircumflex" "Aacute" "Edieresis" "Egrave" "Iacute" "Icircumflex" "Idieresis" "Igrave" "Oacute" "Ocircumflex" "apple" "Ograve" "Uacute" "Ucircumflex" "Ugrave" "dotlessi" "circumflex" "tilde" "macron" "breve" "dotaccent" "ring" "cedilla" "hungarumlaut" "ogonek" "caron" "Lslash" "lslash" "Scaron" "scaron" "Zcaron" "zcaron" "brokenbar" "Eth" "eth" "Yacute" "yacute" "Thorn" "thorn" "minus" "multiply" "onesuperior" "twosuperior" "threesuperior" "onehalf" "onequarter" "threequarters" "franc" "Gbreve" "gbreve" "Idotaccent" "Scedilla" "scedilla" "Cacute" "cacute" "Ccaron" "ccaron" "dcroat")) (defun load-post-format-2 (names stream) (let* ((glyph-count (read-uint16 stream)) (new-count glyph-count)) (when (/= glyph-count (length names)) (warn "Glyph count in \"post\" table (~D) ~ does not match glyph count in \"maxp\" table (~D). ~ This font may be broken." glyph-count (length names)) (setf glyph-count (length names) new-count (length names))) ;; This is done in a couple passes. First, initialize the names ;; tables with indexes into either the standard table or the ;; pstring table. Next, read the pstring table into a vector. ;; Finally, replace the indexes with names. (dotimes (i glyph-count) (let ((name-index (read-uint16 stream))) (when (< name-index 258) (decf new-count)) (setf (aref names i) name-index))) (let ((pstrings (make-array new-count))) (dotimes (i new-count) (setf (aref pstrings i) (read-pstring stream))) (loop for i below glyph-count for j across names do (cond ((< j 258) (setf (aref names i) (aref *standard-mac-glyph-names* j))) (t (setf (aref names i) (aref pstrings (- j 258))))))))) (defun load-post-format-3 (names stream) (declare (ignore stream)) (fill names nil)) (defmethod load-post-info ((font-loader font-loader)) (let ((names (make-array (glyph-count font-loader) :initial-element 0)) (stream (input-stream font-loader))) (seek-to-table "post" font-loader) (let ((format (read-uint32 stream))) (when (/= format #x00020000 #x00030000) (error 'unsupported-format :location "\"post\" table" :expected-values (list #x00020000 #x00030000) :actual-value format)) (setf (italic-angle font-loader) (read-fixed stream) (underline-position font-loader) (read-fword stream) (underline-thickness font-loader) (read-fword stream) (fixed-pitch-p font-loader) (plusp (read-uint32 stream)) (postscript-glyph-names font-loader) names) ;; skip minMemType* fields (advance-file-position stream 16) (case format (#x00020000 (load-post-format-2 names stream)) (#x00030000 (load-post-format-3 names stream)))))) (defun postscript-uni-name-p (name) (let ((end (or (position #\. name) (length name)))) (and (= end 7) (= (mismatch "uni" name) 3) (loop for i from 3 below end always (digit-char-p (char name i) 16))))) (defun postscript-name-code-point (name) "Returns, if available, the interpretation of the PostScript name NAME as a Unicode code point specifier. Ref: http://partners.adobe.com/public/developer/opentype/index_glyph.html" (when (postscript-uni-name-p name) (parse-integer name :start 3 :end 7 :radix 16))) zpb-ttf-0.7/name.lisp 0100664 0000764 0000764 00000035402 10375725047 013240 0 ustar xach xach ;;; Copyright (c) 2006 Zachary Beane, All Rights Reserved ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; ;;; * Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; ;;; * Redistributions in binary form must reproduce the above ;;; copyright notice, this list of conditions and the following ;;; disclaimer in the documentation and/or other materials ;;; provided with the distribution. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;;; ;;; Loading data from the TrueType "name" table. ;;; ;;; http://www.microsoft.com/OpenType/OTSpec/name.htm ;;; http://developer.apple.com/fonts/TTRefMan/RM06/Chap6name.html ;;; ;;; name.lisp,v 1.8 2006/02/18 23:13:43 xach Exp (in-package #:zpb-ttf) (defvar *name-identifiers* #(:copyright-notice :font-family :font-subfamily :unique-subfamily :full-name :name-table-version :postscript-name :trademark-notice :manufacturer-name :designer :description :vendor-url :designer-url :license-description :licence-info-url :reserved :preferred-family :preferred-subfamily :compatible-full :sample-text)) (defvar *platform-identifiers* #(:unicode :macintosh :iso :microsoft :custom)) (defvar *unicode-encoding-ids* #(:unicode-1.0 :unicode-1.1 :iso-10646\:1993 :unicode>=2.0-bmp-only :unicode>=2.0-full-repertoire)) (defvar *microsoft-encoding-ids* #(:symbol :unicode :shiftjis :prc :big5 :wansung :johab :reserved :reserved :reserved :ucs-4)) (defvar *macintosh-encoding-ids* #(:roman :japanese :chinese-traditional :korean :arabic :hebrew :greek :russian :RSymbol :devanagari :gurmukhi :gujarati :oriya :bengali :tamil :telugu :kennada :malayam :sinhalese :burmese :khmer :thai :laotian :georgian :armenian :chinese-simplified :tibetan :mongolian :geez :slavic :vietnamese :sindhi :uninterpreted)) (defparameter *encoding-tables* (vector *unicode-encoding-ids* *macintosh-encoding-ids* nil *microsoft-encoding-ids* nil)) (defun encoding-id-name (platform-id encoding-id) (aref (aref *encoding-tables* platform-id) encoding-id)) (defun platform-id-name (platform-id) (aref *platform-identifiers* platform-id)) (defparameter *macroman-translation-table* #(#x00 #x00 #x01 #x01 #x02 #x02 #x03 #x03 #x04 #x04 #x05 #x05 #x06 #x06 #x07 #x07 #x08 #x08 #x09 #x09 #x0A #x0A #x0B #x0B #x0C #x0C #x0D #x0D #x0E #x0E #x0F #x0F #x10 #x10 #x11 #x11 #x12 #x12 #x13 #x13 #x14 #x14 #x15 #x15 #x16 #x16 #x17 #x17 #x18 #x18 #x19 #x19 #x1A #x1A #x1B #x1B #x1C #x1C #x1D #x1D #x1E #x1E #x1F #x1F #x20 #x20 #x21 #x21 #x22 #x22 #x23 #x23 #x24 #x24 #x25 #x25 #x26 #x26 #x27 #x27 #x28 #x28 #x29 #x29 #x2A #x2A #x2B #x2B #x2C #x2C #x2D #x2D #x2E #x2E #x2F #x2F #x30 #x30 #x31 #x31 #x32 #x32 #x33 #x33 #x34 #x34 #x35 #x35 #x36 #x36 #x37 #x37 #x38 #x38 #x39 #x39 #x3A #x3A #x3B #x3B #x3C #x3C #x3D #x3D #x3E #x3E #x3F #x3F #x40 #x40 #x41 #x41 #x42 #x42 #x43 #x43 #x44 #x44 #x45 #x45 #x46 #x46 #x47 #x47 #x48 #x48 #x49 #x49 #x4A #x4A #x4B #x4B #x4C #x4C #x4D #x4D #x4E #x4E #x4F #x4F #x50 #x50 #x51 #x51 #x52 #x52 #x53 #x53 #x54 #x54 #x55 #x55 #x56 #x56 #x57 #x57 #x58 #x58 #x59 #x59 #x5A #x5A #x5B #x5B #x5C #x5C #x5D #x5D #x5E #x5E #x5F #x5F #x60 #x60 #x61 #x61 #x62 #x62 #x63 #x63 #x64 #x64 #x65 #x65 #x66 #x66 #x67 #x67 #x68 #x68 #x69 #x69 #x6A #x6A #x6B #x6B #x6C #x6C #x6D #x6D #x6E #x6E #x6F #x6F #x70 #x70 #x71 #x71 #x72 #x72 #x73 #x73 #x74 #x74 #x75 #x75 #x76 #x76 #x77 #x77 #x78 #x78 #x79 #x79 #x7A #x7A #x7B #x7B #x7C #x7C #x7D #x7D #x7E #x7E #x7F #x7F #x80 #x00C4 #x81 #x00C5 #x82 #x00C7 #x83 #x00C9 #x84 #x00D1 #x85 #x00D6 #x86 #x00DC #x87 #x00E1 #x88 #x00E0 #x89 #x00E2 #x8A #x00E4 #x8B #x00E3 #x8C #x00E5 #x8D #x00E7 #x8E #x00E9 #x8F #x00E8 #x90 #x00EA #x91 #x00EB #x92 #x00ED #x93 #x00EC #x94 #x00EE #x95 #x00EF #x96 #x00F1 #x97 #x00F3 #x98 #x00F2 #x99 #x00F4 #x9A #x00F6 #x9B #x00F5 #x9C #x00FA #x9D #x00F9 #x9E #x00FB #x9F #x00FC #xA0 #x2020 #xA1 #x00B0 #xA2 #x00A2 #xA3 #x00A3 #xA4 #x00A7 #xA5 #x2022 #xA6 #x00B6 #xA7 #x00DF #xA8 #x00AE #xA9 #x00A9 #xAA #x2122 #xAB #x00B4 #xAC #x00A8 #xAD #x2260 #xAE #x00C6 #xAF #x00D8 #xB0 #x221E #xB1 #x00B1 #xB2 #x2264 #xB3 #x2265 #xB4 #x00A5 #xB5 #x00B5 #xB6 #x2202 #xB7 #x2211 #xB8 #x220F #xB9 #x03C0 #xBA #x222B #xBB #x00AA #xBC #x00BA #xBD #x03A9 #xBE #x00E6 #xBF #x00F8 #xC0 #x00BF #xC1 #x00A1 #xC2 #x00AC #xC3 #x221A #xC4 #x0192 #xC5 #x2248 #xC6 #x2206 #xC7 #x00AB #xC8 #x00BB #xC9 #x2026 #xCA #x00A0 #xCB #x00C0 #xCC #x00C3 #xCD #x00D5 #xCE #x0152 #xCF #x0153 #xD0 #x2103 #xD1 #x2014 #xD2 #x201C #xD3 #x201D #xD4 #x2018 #xD5 #x2019 #xD6 #x00F7 #xD7 #x25CA #xD8 #x00FF #xD9 #x0178 #xDA #x2044 #xDB #x20AC #xDC #x2039 #xDD #x203A #xDE #xFB01 #xDF #xFB02 #xE0 #x2021 #xE1 #x00B7 #xE2 #x201A #xE3 #x201E #xE4 #x2030 #xE5 #x00C2 #xE6 #x00CA #xE7 #x00C1 #xE8 #x00CB #xE9 #x00C8 #xEA #x00CD #xEB #x00CE #xEC #x00CF #xED #x00CC #xEE #x00D3 #xEF #x00D4 #xF0 #xF8FF #xF1 #x00D2 #xF2 #x00DA #xF3 #x00DB #xF4 #x00D9 #xF5 #x0131 #xF6 #x02C6 #xF7 #x02DC #xF8 #x00AF #xF9 #x02D8 #xFA #x02D9 #xFB #x02DA #xFC #x00B8 #xFD #x02DD #xFE #x02DB #xFF #x02C7)) (defconstant +unicode-platform-id+ 0) (defconstant +macintosh-platform-id+ 1) (defconstant +iso-platform-id+ 2) (defconstant +microsoft-platform-id+ 3) (defconstant +custom-platform-id+ 4) (defconstant +unicode-2.0-encoding-id+ 3) (defconstant +microsoft-unicode-bmp-encoding-id+ 1) (defconstant +microsoft-symbol-encoding-id+ 0) (defconstant +macintosh-roman-encoding-id+ 1) ;; Full list of microsoft language IDs is here: ;; http://www.microsoft.com/globaldev/reference/lcid-all.mspx (defconstant +microsoft-us-english-language-id+ #x0409) (defconstant +macintosh-english-language-id+ 1) (defconstant +unicode-language-id+ 0) (defclass name-entry () ((font-loader :initarg :font-loader :accessor font-loader) (platform-id :initarg :platform-id :accessor platform-id) (encoding-id :initarg :encoding-id :accessor encoding-id) (language-id :initarg :language-id :accessor language-id) (name-id :initarg :name-id :accessor name-id) (offset :initarg :offset :accessor offset :documentation "The octet offset within the TrueType file stream of the entry's data. *Not* the same as the offset in the NameRecord structure, which is relative to the start of the string data for the table.") (entry-length :initarg :entry-length :accessor entry-length) (value :reader %value :writer (setf value)) (octets :reader %octets :writer (setf octets)))) (defmethod print-object ((name-entry name-entry) stream) (print-unreadable-object (name-entry stream :type t) (format stream "~A (~A/~A/~D)" (aref *name-identifiers* (name-id name-entry)) (platform-id-name (platform-id name-entry)) (encoding-id-name (platform-id name-entry) (encoding-id name-entry)) (language-id name-entry)))) (defun unicode-octets-to-string (octets) (let ((string (make-string (/ (length octets) 2)))) (flet ((ref16 (i) (+ (ash (aref octets i) 16) (aref octets (1+ i))))) (loop for i from 0 below (length octets) by 2 for j from 0 do (setf (char string j) (code-char (ref16 i)))) string))) (defun macintosh-octets-to-string (octets) (flet ((macroman->unicode (point) (code-char (aref *macroman-translation-table* (1+ (ash point 1)))))) (let ((string (make-string (length octets)))) (dotimes (i (length octets) string) (setf (schar string i) (macroman->unicode (aref octets i))))))) (defgeneric initialize-name-entry (name-entry) (:method (name-entry) (let ((stream (input-stream (font-loader name-entry))) (octets (make-array (entry-length name-entry) :element-type '(unsigned-byte 8))) (value nil) (platform-id (platform-id name-entry))) (file-position stream (offset name-entry)) (read-sequence octets stream) (cond ((or (= platform-id +unicode-platform-id+) (= platform-id +microsoft-platform-id+)) (setf value (unicode-octets-to-string octets))) ((= platform-id +macintosh-platform-id+) (setf value (macintosh-octets-to-string octets))) (t (error 'unsupported-value :location "\"name\" table platform ID" :actual-value platform-id :expected-values (list +unicode-platform-id+ +microsoft-platform-id+ +macintosh-platform-id+)))) (setf (value name-entry) value (octets name-entry) octets)))) (defgeneric value (name-entry) (:method (name-entry) (unless (slot-boundp name-entry 'value) (initialize-name-entry name-entry)) (%value name-entry))) (defgeneric octets (name-entry) (:method (name-entry) (unless (slot-boundp name-entry 'octets) (initialize-name-entry name-entry)) (%octets name-entry))) (defun load-name-info (loader) (seek-to-table "name" loader) (let* ((stream (input-stream loader)) (table-offset (file-position stream)) (format (read-uint16 stream))) (unless (= format 0) (error 'unsupported-format :location "\"name\" table" :actual-value format :expected-values (list 0))) (let* ((count (read-uint16 stream)) (values-offset (read-uint16 stream)) (entries (make-array count))) (setf (name-entries loader) entries) (dotimes (i count) (let ((platform-id (read-uint16 stream)) (encoding-id (read-uint16 stream)) (language-id (read-uint16 stream)) (name-id (read-uint16 stream)) (length (read-uint16 stream)) (offset (read-uint16 stream))) (setf (aref entries i) (make-instance 'name-entry :font-loader loader :platform-id platform-id :encoding-id encoding-id :language-id language-id :name-id name-id :entry-length length :offset (+ table-offset values-offset offset)))))))) ;;; ;;; Fetching info out of the name-entry vector ;;; (defun name-identifier-id (symbol) (let ((id (position symbol *name-identifiers*))) (if id id (error "Unknown NAME identifier: ~S" symbol)))) (defmethod find-name-entry (platform-id encoding-id language-id name-id (font-loader font-loader)) ;; FIXME: this vector is sorted by platform ID, encoding ID, ;; language ID, and name ID, in that order. Could bisect if it ;; mattered. (loop for name-entry across (name-entries font-loader) when (and (or (null platform-id) (= (platform-id name-entry) platform-id)) (or (null encoding-id) (= (encoding-id name-entry) encoding-id)) (or (null language-id) (= (language-id name-entry) language-id)) (or (null name-id) (= (name-id name-entry) name-id))) return name-entry)) (defmethod name-entry-value (name-designator (font-loader font-loader)) (let* ((name-id (etypecase name-designator (keyword (name-identifier-id name-designator)) (integer name-designator))) (entry (or (find-name-entry +unicode-platform-id+ +unicode-2.0-encoding-id+ +unicode-language-id+ name-id font-loader) (find-name-entry +microsoft-platform-id+ nil +microsoft-us-english-language-id+ name-id font-loader) (find-name-entry +macintosh-platform-id+ +macintosh-roman-encoding-id+ +macintosh-english-language-id+ name-id font-loader)))) (when entry (value entry)))) (defmethod postscript-name ((font-loader font-loader)) (name-entry-value :postscript-name font-loader)) (defmethod family-name ((font-loader font-loader)) (name-entry-value :font-family font-loader)) (defmethod subfamily-name ((font-loader font-loader)) (name-entry-value :font-subfamily font-loader)) (defmethod full-name ((font-loader font-loader)) (name-entry-value :full-name font-loader)) zpb-ttf-0.7/font-loader.lisp 0100664 0000764 0000764 00000011603 10410617564 014521 0 ustar xach xach ;;; Copyright (c) 2006 Zachary Beane, All Rights Reserved ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; ;;; * Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; ;;; * Redistributions in binary form must reproduce the above ;;; copyright notice, this list of conditions and the following ;;; disclaimer in the documentation and/or other materials ;;; provided with the distribution. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;;; ;;; The font-loader object, which is the primary interface for ;;; getting glyph and metrics info. ;;; ;;; font-loader.lisp,v 1.26 2006/03/23 22:21:40 xach Exp (in-package #:zpb-ttf) (defclass font-loader () ((tables :initform (make-hash-table) :reader tables) (input-stream :initarg :input-stream :accessor input-stream :documentation "The stream from which things are loaded.") (table-count :initarg :table-count :reader table-count) ;; from the 'head' table (units/em :accessor units/em) (bounding-box :accessor bounding-box) (loca-offset-format :accessor loca-offset-format) ;; from the 'loca' table (glyph-locations :accessor glyph-locations) ;; from the 'cmap' table (character-map :accessor character-map) (inverse-character-map :accessor inverse-character-map) ;; from the 'maxp' table (glyph-count :accessor glyph-count) ;; from the 'hhea' table (ascender :accessor ascender) (descender :accessor descender) (line-gap :accessor line-gap) ;; from the 'hmtx' table (advance-widths :accessor advance-widths) (left-side-bearings :accessor left-side-bearings) ;; from the 'kern' table (kerning-table :initform (make-hash-table) :accessor kerning-table) ;; from the 'name' table (name-entries :initform nil :accessor name-entries) ;; from the 'post' table (italic-angle :accessor italic-angle :initform 0) (fixed-pitch-p :accessor fixed-pitch-p :initform nil) (underline-position :accessor underline-position :initform 0) (underline-thickness :accessor underline-thickness :initform 0) (postscript-glyph-names :accessor postscript-glyph-names) ;; misc (glyph-cache :accessor glyph-cache))) (defclass table-info () ((name :initarg :name :reader name) (offset :initarg :offset :reader offset) (size :initarg :size :reader size))) (defmethod print-object ((object table-info) stream) (print-unreadable-object (object stream :type t) (format stream "\"~A\"" (name object)))) ;;; tag integers to strings and back (defun number->tag (number) "Convert the 32-bit NUMBER to a string of four characters based on the CODE-CHAR of each octet in the number." (let ((tag (make-string 4))) (loop for i below 4 for offset from 24 downto 0 by 8 do (setf (schar tag i) (code-char (ldb (byte 8 offset) number)))) tag)) (defun tag->number (tag) "Convert the four-character string TAG to a 32-bit number based on the CHAR-CODE of each character." (declare (simple-string tag)) (loop for char across tag for offset from 24 downto 0 by 8 summing (ash (char-code char) offset))) ;;; Getting table info out of the loader (defmethod table-info ((tag string) (font-loader font-loader)) (gethash (tag->number tag) (tables font-loader))) (defmethod table-exists-p (tag font-loader) (nth-value 1 (table-info tag font-loader))) (defmethod table-position ((tag string) (font-loader font-loader)) "Return the byte position in the font-loader's stream for the table named by TAG." (let ((table-info (table-info tag font-loader))) (if table-info (offset table-info) (error "No such table -- ~A" tag)))) (defmethod table-size ((tag string) (font-loader font-loader)) (let ((table-info (table-info tag font-loader))) (if table-info (size table-info) (error "No such table -- ~A" tag)))) (defmethod seek-to-table ((tag string) (font-loader font-loader)) "Move FONT-LOADER's input stream to the start of the table named by TAG." (file-position (input-stream font-loader) (table-position tag font-loader))) zpb-ttf-0.7/hhea.lisp 0100664 0000764 0000764 00000004372 10375725047 013227 0 ustar xach xach ;;; Copyright (c) 2006 Zachary Beane, All Rights Reserved ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; ;;; * Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; ;;; * Redistributions in binary form must reproduce the above ;;; copyright notice, this list of conditions and the following ;;; disclaimer in the documentation and/or other materials ;;; provided with the distribution. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;;; ;;; Loading data from the "hhea" table. ;;; ;;; http://www.microsoft.com/OpenType/OTSpec/hhea.htm ;;; http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html ;;; ;;; hhea.lisp,v 1.4 2006/02/18 23:13:43 xach Exp (in-package #:zpb-ttf) (defmethod load-hhea-info ((font-loader font-loader)) (seek-to-table "hhea" font-loader) (with-slots (input-stream ascender descender line-gap) font-loader (let ((version (read-fixed input-stream))) (check-version "\"hhea\" table" version #x00010000)) (setf ascender (read-fword input-stream) descender (read-fword input-stream) line-gap (read-fword input-stream)))) (defmethod horizontal-metrics-count ((font-loader font-loader)) (seek-to-table "hhea" font-loader) (with-slots (input-stream) font-loader ;; Skip to the end, since all we care about is the last item (advance-file-position input-stream 34) (read-uint16 input-stream))) zpb-ttf-0.7/loca.lisp 0100664 0000764 0000764 00000004465 10375725047 013243 0 ustar xach xach ;;; Copyright (c) 2006 Zachary Beane, All Rights Reserved ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; ;;; * Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; ;;; * Redistributions in binary form must reproduce the above ;;; copyright notice, this list of conditions and the following ;;; disclaimer in the documentation and/or other materials ;;; provided with the distribution. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;;; ;;; Loading data from the "loca" table. ;;; ;;; http://www.microsoft.com/OpenType/OTSpec/loca.htm ;;; http://developer.apple.com/fonts/TTRefMan/RM06/Chap6loca.html ;;; ;;; loca.lisp,v 1.3 2006/02/18 23:13:43 xach Exp (in-package #:zpb-ttf) (defmethod load-loca-info ((font-loader font-loader)) (seek-to-table "loca" font-loader) (with-slots (input-stream glyph-locations glyph-count loca-offset-format) font-loader (setf glyph-locations (make-array (1+ glyph-count))) (dotimes (i (1+ glyph-count)) (setf (svref glyph-locations i) (if (eql loca-offset-format :short) (* (read-uint16 input-stream) 2) (read-uint32 input-stream)))))) (defmethod glyph-location (index (font-loader font-loader)) (aref (glyph-locations font-loader) index)) (defmethod glyph-length (index (font-loader font-loader)) (with-slots (glyph-locations) font-loader (- (aref glyph-locations (1+ index)) (aref glyph-locations index)))) zpb-ttf-0.7/head.lisp 0100664 0000764 0000764 00000006000 10375725047 013211 0 ustar xach xach ;;; Copyright (c) 2006 Zachary Beane, All Rights Reserved ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; ;;; * Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; ;;; * Redistributions in binary form must reproduce the above ;;; copyright notice, this list of conditions and the following ;;; disclaimer in the documentation and/or other materials ;;; provided with the distribution. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;;; ;;; Loading data from the "head" table. ;;; ;;; http://www.microsoft.com/OpenType/OTSpec/head.htm ;;; http://developer.apple.com/fonts/TTRefMan/RM06/Chap6head.html ;;; ;;; head.lisp,v 1.5 2006/02/18 23:13:43 xach Exp (in-package #:zpb-ttf) (defmethod load-head-info ((font-loader font-loader)) (seek-to-table "head" font-loader) (with-slots (input-stream units/em bounding-box loca-offset-format) font-loader (flet ((skip-bytes (count) (file-position input-stream (+ count (file-position input-stream))))) (let ((version (read-uint32 input-stream))) (check-version "\"head\" table" version #x00010000)) ;; skip fontRevsion and checkSumAdjustment (both uint32) (skip-bytes 8) ;; check the magicNumber (let ((magic-number (read-uint32 input-stream))) (when (/= magic-number #x5F0F3CF5) (error 'bad-magic :location "\"head\" table" :expected-values (list #x5F0F3CF5) :actual-value magic-number))) ;; skip flags (skip-bytes 2) (setf units/em (read-uint16 input-stream)) ;; skip created and modified dates (skip-bytes 16) (setf bounding-box (vector (read-int16 input-stream) (read-int16 input-stream) (read-int16 input-stream) (read-int16 input-stream))) ;; skip macStyle, lowestRecPPEM, fontDirectionHint (skip-bytes 6) ;; set the loca-offset-format (if (zerop (read-int16 input-stream)) (setf loca-offset-format :short) (setf loca-offset-format :long))))) zpb-ttf-0.7/kern.lisp 0100664 0000764 0000764 00000010221 10412245155 013234 0 ustar xach xach ;;; Copyright (c) 2006 Zachary Beane, All Rights Reserved ;;; ;;; Redistribution and use in source and binary forms, with or without ;;; modification, are permitted provided that the following conditions ;;; are met: ;;; ;;; * Redistributions of source code must retain the above copyright ;;; notice, this list of conditions and the following disclaimer. ;;; ;;; * Redistributions in binary form must reproduce the above ;;; copyright notice, this list of conditions and the following ;;; disclaimer in the documentation and/or other materials ;;; provided with the distribution. ;;; ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ;;; ;;; "kern" table functions ;;; ;;; http://www.microsoft.com/OpenType/OTSpec/kern.htm ;;; http://developer.apple.com/fonts/TTRefMan/RM06/Chap6kern.html ;;; ;;; kern.lisp,v 1.8 2006/03/28 14:38:37 xach Exp (in-package #:zpb-ttf) (defun load-kerning-format-1 (table stream) "Return a hash table keyed on a UINT32 key that represents the glyph index in the left and right halves with a value of the kerning distance between the pair." (let ((pair-count (read-uint16 stream)) (search-range (read-uint16 stream)) (entry-selector (read-uint16 stream)) (range-shift (read-uint16 stream))) (declare (ignore search-range entry-selector range-shift)) (dotimes (i pair-count) (setf (gethash (read-uint32 stream) table) (read-int16 stream))))) (defmethod load-kerning-subtable ((font-loader font-loader) format) (when (/= 1 format) (error 'unsupported-format :description "kerning subtable" :size 1 :expected-values (list 1) :actual-value format)) (load-kerning-format-1 (kerning-table font-loader) (input-stream font-loader))) (defmethod load-kern-info ((font-loader font-loader)) (when (table-exists-p "kern" font-loader) (seek-to-table "kern" font-loader) (let* ((stream (input-stream font-loader)) (maybe-version (read-uint16 stream)) (maybe-table-count (read-uint16 stream)) (version 0) (table-count 0)) ;; These shenanegins are because Apple documents one style of ;; kern table and Microsoft documents another. This code ;; implements Microsoft's version. ;; See: ;; http://developer.apple.com/fonts/TTRefMan/RM06/Chap6kern.html ;; http://www.microsoft.com/OpenType/OTSpec/kern.htm (if (zerop version) (setf version maybe-version table-count maybe-table-count) (setf version (logand (ash maybe-version 16) maybe-table-count) table-count (read-uint32 stream))) (check-version "\"kern\" table" version 0) (dotimes (i table-count) (let ((version (read-uint16 stream)) (length (read-uint16 stream)) (coverage-flags (read-uint8 stream)) (format (read-uint8 stream))) (declare (ignore version length coverage-flags)) (load-kerning-subtable font-loader format)))))) (defmethod all-kerning-pairs ((font-loader font-loader)) (let ((pairs nil)) (maphash (lambda (k v) (let* ((left-index (ldb (byte 16 16) k)) (right-index (ldb (byte 16 0) k)) (left (index-glyph left-index font-loader)) (right (index-glyph right-index font-loader))) (push (list left right v) pairs))) (kerning-table font-loader)) pairs)) zpb-ttf-0.7/zpb-ttf.html 0100664 0000764 0000764 00000051347 10524642217 013702 0 ustar xach xach
Abstract
TrueType fonts have a publicly documented file format. ZPB-TTF is a TrueType file parser that provides an interface for reading typographic metrics, glyph outlines, and other information from the file. It is available under a BSD-like license. The current version is 0.7, released on November 9, 2006.
TrueType is a registered trademark of Apple Computer, Inc.
Download shortcut: http://www.xach.com/lisp/zpb-ttf.tgz
ZPB-TTF has the following limitations:
Font files are loaded by creating font loaders. A font loader has information that applies to the font as a whole, such as its overall bounding box and other typographic metrics, the number of glyphs it contains, and a character map that can be used to convert a character set index into a glyph index meaningful to the font loader.
A font loader can also be used to create and find glyphs. A glyph object has information about an individual glyph such as typographic metrics and its outline.
Glyph outlines are made up of arrays of control points. An array of control points is called a contour. Contours define the shape of the glyph. For example, in most fonts, the glyph for the character #\I has one contour defining its outline. The glyph for the character #\O has two contours: one for the outer edge, and one for the inner edge.
This documentation is not meant to be a substitute for the TrueType
file format documentation. For file format details, see the
specifications from either Apple
or Microsoft.
Glyph Example
This image is a rendering of the Greek small letter lambda (U+03BB) from the Times New Roman TrueType font. It was drawn into a PDF with CL-PDF and rendered with Adobe Acrobat Reader.
The dark gray grid lines represent the axes of the glyph coordinate system. Light grid lines are drawn at intervals of 256 em-square units.
Black squares represent the control points returned from CONTOUR. Solid black squares are points on the outline (ON-CURVE-P returns true), and hollow black squares are not on the outline. Solid red squares represent implicit control points on the glyph outline; they are not in the original contour, but they would be returned in a new contour created with EXPLICIT-CONTOUR-POINTS.
The alternating blue and green portions of the glyph outline
represent the separate segments whose start, control, and end points
were bound with DO-CONTOUR-SEGMENTS.
The ZPB-TTF Dictionary
[Function]
open-font-loader font-file-designator => font-loader
Creates and returns a font-loader object from font-file-designator, which should be either a pathname, pathname namestring, or a font-loader object.
[Function]
close-font-loader font-loader =>
Closes any open resources held by font-loader.
[Macro]
with-font-loader (font-loader font-loader-designator) &body body =>
Performs body with font-loader bound to a font-loader object created as if with (open-font-loader font-loader-designator). Automatically closes the font-loader when finished.
[Function]
glyph-count font-loader => number
Returns the number of glyphs available in font-loader.
[Function]
name-entry-value name-designator font-loader => string
Returns an entry from the TrueType "name" table, which contains human-readable values for copyright info, trademark notices, creator names, and the like.name-designator may be either an integer ID from the table of NameIDs in the TrueType "name" table specification, or a keyword designating such an ID. Valid keywords and their IDs are:
Keyword ID :COPYRIGHT-NOTICE 0 :FONT-FAMILY 1 :FONT-SUBFAMILY 2 :UNIQUE-SUBFAMILY 3 :FULL-NAME 4 :NAME-TABLE-VERSION 5 :POSTSCRIPT-NAME 6 :TRADEMARK-NOTICE 7 :MANUFACTURER-NAME 8 :DESIGNER 9 :DESCRIPTION 10 :VENDOR-URL 11 :DESIGNER-URL 12 :LICENSE-DESCRIPTION 13 :LICENCE-INFO-URL 14 :RESERVED 15 :PREFERRED-FAMILY 16 :PREFERRED-SUBFAMILY 17 :COMPATIBLE-FULL 18 :SAMPLE-TEXT 19 If the font does not provide any "name" table entry for the given name-designator, returns NIL.
[Function]
find-name-entry platform-id language-id name-id font-loader => name-entry
This is the low-level interface used by NAME-ENTRY-VALUE. platform-id, language-id, and name-id should be integer ID values from the TrueType "name" table specification. If the combination of IDs is found in the name table, a name-entry object is returned, otherwise NIL is returned.
[Function]
value name-entry => string
Returns the string value of a name-entry object.
[Function]
italic-angle font-loader => number
Returns the typographic italic angle of font-loader.
[Function]
underline-thickness font-loader => number
Returns the typographic underline thickness of font-loader.
[Function]
underline-position font-loader => number
Returns the typographic underline position of font-loader.
[Function]
fixed-pitch-p font-loader => boolean
Returns true if font-loader is fixed pitch (all glyphs have the same width).
[Function]
units/em font-loader => number
Return the number of units in the typographic em-square of font-loader.
[Function]
ascender font-loader => number
Returns the typographic ascender value of font-loader.
[Function]
descender font-loader => number
Returns the typographic descender value of font-loader.
[Function]
line-gap font-loader => number
Returns the typographic line gap of font-loader.
[Generic function]
postscript-name object => string
Returns the Postscript name of object, which may be a glyph or a font-loader.
[Function]
full-name font-loader => string
Returns the full name of font-loader.
[Function]
family-name font-loader => string
Returns the family name of font-loader.
[Function]
subfamily-name font-loader => string
Returns the subfamily name of font-loader.
[Function]
all-kerning-pairs font-loader => list
Returns a list of all the kerning pairs available in font-loader. Each element of the list is itself a list, with three elements: a left glyph, a right glyph, and a numeric kerning offset.
[Function]
glyph-exists-p character-designator font-loader => boolean
Returns true if font-loader has glyph data for character-designator.
[Function]
index-glyph index font-loader => glyph
Returns the glyph at index in font-loader.
[Function]
find-glyph character-designator font-loader => glyph
Returns the glyph for character-designator in font-loader. If character-designator is an integer, it is treated as a Unicode code-point and the corresponding glyph is fetched from the font. If character-designator is a character, its char-code is used as a Unicode code-point for lookup.
Note: If the char-codes of characters the Lisp implementation do not correspond to Unicode (or a subset), this may not return the expected glyph.If font-loader does not contain any glyphs for character-designator, the "missing glyph" glyph is returned. To test for the existence of a glyph without returning the "missing glyph" glyph, use GLYPH-EXISTS-P.
[Generic function]
bounding-box object => #(xmin ymin xmax ymax)
Returns the bounding box of object, which may be a glyph or a font-loader.
[Generic functions]
xmin object => value
ymin object => value
xmax object => value
ymax object => value
Returns the horizontal and vertical extreme values for object, which may be a glyph or font-loader. If object is a four-element vector, each function is an accessor to the appropriate entry in the vector.
[Function]
x control-point => number
y control-point => number
Returns the respective coordinate of control-point.
[Function]
on-curve-p control-point => boolean
Returns true if control-point is on the contour outline.
[Function]
contour-count glyph => number
Returns the number of contours of glyph. Some glyphs, such as the glyph for the Space character, may have zero contours.
[Function]
contour glyph index => vector
Returns the indexth contour from the contours of glyph. A contour is represented as a vector of control point objects. Each control point may be on (touching) or off (not touching) the the contour outline.TrueType files may store contours that have implicit control points. When two consecutive control points are off the contour outline, there is an implied control point at the midpoint between them on the contour curve.
[Function]
contours glyph => vector
Returns all contours of glyph as a vector.
[Macro]
do-contours (contour glyph &optional
result) &body body => result
Performs body for each contour in glyph, with the contour bound to contour. Returns result (evaluated) at the end of processing.
[Function]
explicit-contour-points contour => vector
Returns a vector of points that is the same as contour with the implicit contour points inserted.
[Macro]
do-contour-segments (start control end) contour &body body =>
For convenience, a TrueType contour may be thought of as being made up of connected segments. Each segment is either a straight line from one point on the outline to another, or a curved line that starts with a point on the outline, is controlled by a point off the outline, and ends with a point on the outline.DO-CONTOUR-SEGMENTS performs body for each segment of contour, with the start, control, and end variables (not evaluated) bound to the start, control, and end points of the segment. If the segment is a straight line, control is bound to NIL.
Contours of a glyph in a TrueType file may contain implied control points; two consecutive points off the outline may be treated as if there is there is an point on the outline at the midpoint between them. DO-CONTOUR-SEGMENTS synthesizes and binds any implicit points as needed when going through the contour segments. (See the Glyph Example for a visual explanation.)
Segments are not a TrueType glyph concept. The term is used for convenience by ZPB-TTF.
[Macro]
do-contour-segments* (control end) contour &body body =>
DO-CONTOUR-SEGMENTS* is like DO-CONTOUR-SEGMENTS, except it does not bind a start variable.
[Function]
code-point glyph => number
Returns the Unicode code point of a character glyph represents. Note: Since font glyphs may represent more than one character, this value may not be exactly what you expect. Note: Since glyphs in a font do not necessarily correspond to a code point, or to a single code point, this may not always return a meaningful value.
[Function]
font-index glyph => number
Returns the integer index of glyph in its font loader.
[Function]
advance-width glyph => number
Returns the typographic advance width of glyph.
[Function]
left-side-bearing glyph => number
Returns the typographic left side bearing of glyph.
[Function]
right-side-bearing glyph => number
Returns the typographic right side bearing of glyph.
[Function]
kerning-offset left-glyph right-glyph
font-loader => number
Returns the typographic kerning adjustment needed for the advance width when left-glyph and right-glyph appear next to each other.
[Function]
string-bounding-box string font-loader =>
#(xmin ymin xmax ymax)
Returns the bounding box for string in the natural unit size of font-loader.
Please send bug reports, patches, questions, and any other feedback to Zachary Beane.