root/trunk/thirdparty/cl-pdf/font.lisp

Revision 2636, 7.2 kB (checked in by hans, 10 months ago)

add cl-pdf for pixel->pdf converter

Line 
1 ;;; cl-pdf copyright 2002-2005 Marc Battyani see license.txt for the details
2 ;;; You can reach me at marc.battyani@fractalconcept.com or marc@battyani.net
3 ;;; The homepage of cl-pdf is here: http://www.fractalconcept.com/asp/html/cl-pdf.html
4
5 (in-package #:pdf)
6
7 (defvar *font* nil
8   "The current font in text mode")
9
10 (defvar *font-size* nil
11   "The current font in text mode")
12
13 (defvar *font-cache* (make-hash-table :test #'equal))
14
15 (defgeneric font-descriptor (font-metrics &key embed errorp))
16
17 (defclass font ()
18  ((name :accessor name :initform "helvetica" :initarg :name)
19   (encoding :accessor encoding :initform *standard-encoding*)
20   (hyphen-code :accessor hyphen-code :initform 0)
21   (hyphen-char :accessor hyphen-char :initform nil)
22   (font-metrics :accessor font-metrics)
23   (kernings :accessor kernings :initform (make-hash-table))
24   (characters :accessor characters :initform (make-array 256 :initial-element nil))
25   (pdf-widths :accessor pdf-widths :initform (make-array 256 :initial-element 0))))
26
27 (defmethod print-object ((self font) stream)
28   (print-unreadable-object (self stream :identity t :type t)
29     (format stream "~a" (name self))))
30
31 (defmethod initialize-instance :after ((font font) &key encoding &allow-other-keys)
32   (let ((font-metrics (gethash (name font) *font-metrics*)))
33     (unless font-metrics (error "Font ~s not found" (name font)))
34     (setf (font-metrics font) font-metrics)
35     (unless encoding
36       (setf (gethash (list (name font) nil) *font-cache*) font))
37     (setf (encoding font)
38           (if encoding
39               (get-encoding encoding)
40               (extract-font-metrics-encoding font-metrics)))
41     (if (eql (keyword-name (encoding font)) :unicode-encoding)
42         (setf (pdf-widths font) (pdf-widths font-metrics)
43               (characters font) (encoding-vector font-metrics)
44               (hyphen-code font) (if (gethash "hyphen" (characters font-metrics))
45                                      (code (gethash "hyphen" (characters font-metrics)))
46                                      0)
47               (hyphen-char font) (code-char (hyphen-code font)))
48         (loop with font-characters = (characters font-metrics)
49            with pdf-widths = (pdf-widths font)
50            with void-char = (gethash "VoidCharacter" font-characters)
51            and characters = (characters font)
52            and hyphen-code = nil
53            for i from 0 to 255
54            for char-name across (char-names (encoding font))
55            for char = (or (gethash char-name font-characters)
56                           (aref (encoding-vector font-metrics) i)
57                           void-char)
58            do (setf (aref characters i) char
59                     (aref pdf-widths i) (round (* 1000 (width char))))
60              (when (and (not hyphen-code) (string= char-name "hyphen"))
61                (setf hyphen-code i
62                      (hyphen-code font) i
63                      (hyphen-char font) (code-char i)))))
64     (compute-kern-pairs font)
65     (setf (gethash (list (name font) (encoding font)) *font-cache*) font)))
66
67 (defun compute-kern-pairs (font)
68   (let ((char-to-code (make-hash-table))
69         (characters (characters font))
70         (kernings (kernings font)))
71     (loop for c across characters
72           for code from 0
73           when c do (setf (gethash c char-to-code) code))
74     (maphash #'(lambda (k v)
75                  (let ((code1 (gethash (car k) char-to-code))
76                        (code2 (gethash (cdr k) char-to-code)))
77                    (when (and code1 code2)
78                      (setf (gethash (+ (* code1 65536) code2) kernings) (car v)))))
79              (kernings (font-metrics font)))))
80
81
82 (defgeneric get-char-metrics (char-or-code font encoding)
83  ;;; This generic allows to customize treating charset by the lisp implementation
84   ;; and is intended to replace get-char.
85   ;; Args: char-or-code  Lisp character or its char-code
86  (:method (char-or-code font encoding)
87    (declare (ignore encoding))
88   (aref (characters font)
89         (if (characterp char-or-code) (char-code char-or-code) char-or-code))))
90
91 (defmethod get-char-metrics (char font (encoding single-byte-encoding))
92   (aref (characters font)
93         (if #+lispworks (lw:base-char-p char)
94             #+(or allegro sbcl) (standard-char-p char)
95             #-(or lispworks allegro sbcl) t
96             (char-code char)
97             (char-external-code char (charset encoding)))))
98
99 (defmethod get-char-metrics ((code integer) font (encoding single-byte-encoding))
100   (let ((char (code-char code)))
101   (aref (characters font)
102         (if #+lispworks (lw:base-char-p char)
103               #+(or allegro sbcl) (standard-char-p char)
104               #-(or lispworks allegro sbcl) t
105             code
106               (char-external-code char (charset encoding))))))
107
108 #+unused
109 (defun get-char (code font)
110   (aref (characters font) code))
111
112 #+unused
113 (defmacro force-char-code (char-or-code)
114   (let ((char (gensym "char")))
115     `(let ((,char ,char-or-code))
116       (if (characterp ,char) (char-code ,char) ,char))))
117  
118 (defun get-char-width (char-or-code font &optional font-size)
119   (let ((char-metrics (get-char-metrics char-or-code font (encoding font))))
120     (if font-size (* (width char-metrics) font-size) (width char-metrics))))
121
122 (defun get-char-size (char-or-code font &optional font-size)
123   (let* ((char-metrics (get-char-metrics char-or-code font (encoding font)))
124          (width (width char-metrics))
125          (bbox (bbox char-metrics))
126          (ascender (aref bbox 3))
127          (descender (aref bbox 1)))
128     (if font-size
129         (values (* width font-size)(* ascender font-size)(* descender font-size))
130         (values width ascender descender))))
131
132 (defun get-char-italic-correction (char-or-code font &optional font-size)
133   (let* ((char-metrics (get-char-metrics char-or-code font (encoding font)))
134          (left (left-italic-correction char-metrics))
135          (right (right-italic-correction char-metrics)))
136     (if font-size
137         (values (* left font-size)(* right font-size))
138         (values left right))))
139
140 (defun get-font-italic-correction (font &optional font-size)
141   (let* ((italic-sin (italic-sin (font-metrics font)))
142          (left (* italic-sin (ascender (font-metrics font))))
143          (right (* italic-sin (descender (font-metrics font)))))
144     (if font-size
145         (values (* left font-size)(* right font-size))
146         (values left right))))
147
148 (defun get-kerning (char1 char2 font &optional font-size)
149   (let* ((encoding (encoding font))
150          (char-metrics1 (get-char-metrics char1 font encoding))
151          (char-metrics2 (get-char-metrics char2 font encoding))
152          (kerning (gethash (+ (ash (code char-metrics1) 16) (code char-metrics2))
153                            (kernings font)
154                            0)))
155     (if font-size (* font-size kerning) kerning)))
156
157 (defun get-font (&optional (name "helvetica") (encoding *default-encoding*))
158   (setf name (string-downcase name))
159   (let ((font-metrics (gethash name *font-metrics*)))
160     (when (typep font-metrics 'ttu-font-metrics)
161       (setf encoding *unicode-encoding*)))
162   (let ((font (gethash (list name (get-encoding encoding)) *font-cache*)))
163     (if font
164         font
165         (make-instance 'font :name name :encoding encoding))))
166
167 (defun clear-font-cache ()
168   (clrhash *font-cache*))
169
170 (defvar %fonts-loaded% nil)
171
172 (defun load-fonts (&optional force)
173   (when (or (not %fonts-loaded%) force)
174     (dolist (font-dir *afm-files-directories*)
175       (map nil 'read-afm-file (directory (merge-pathnames font-dir "*.afm"))))
176     (clear-font-cache)
177     (setf %fonts-loaded% t)))
178
179 (eval-when (:load-toplevel :execute)
180   (load-fonts))
Note: See TracBrowser for help on using the browser.