;;; -*- Mode: LISP; Syntax: Zetalisp; Package: DVI; Base: 10; -*- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; This file contains the methods for translation of DVI commands ;; to ImPress format. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; The following methods are defined. ;; ;; :set-char ;; :set-rule ;; :put-char ;; :put-rule ;; :nop ;; :bop ;; :eop ;; :push - handled by document :push-stack method ;; :pop - handled by document :pop-stack method ;; :right ;; :w ;; :x ;; :down ;; :y ;; :z ;; :set-fnt ;; :xxx ;; :start-output ;; :end-output ;; :do-pages ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defflavor imagen-dvi-document ((extra-pixel-h-offset 0) (extra-pixel-v-offset 0)) (document) :settable-instance-variables) ;;FOR THE IMAGEN PRINTER (defmethod (imagen-dvi-document :initialize) () (send self :set-printer-name "IMAGEN") (send self :set-printer-resolution 300) (send self :set-printer-max-fonts 64) (send self :set-fontmap (make-array 64 :fill-pointer 0)) (send self :set-buffer (make-array (* 5 (file-length file-buffer)) :type art-8b :fill-pointer 0 :area *temp-buffer*)) (send self :set-fontnums (make-array 64 :fill-pointer 0)) (maphash #'(lambda (ignore table) (fill (fd-char-status table) 0)) *font-definitions*)) (defmethod (imagen-dvi-document :normal-ending) () ()) (defmethod (imagen-dvi-document :abnormal-ending) () ()) ;; ImPress commands used. (defconstant bgly 199) (defconstant mplus 131) (defconstant mminus 132) (defconstant mmove 133) (defconstant brule 193) (defconstant page 213) (defconstant endpage 219) (defconstant sp 128) (defconstant set-sp 210) (defconstant set-abs-v 137) (defconstant set-abs-h 135) (defconstant set-family 207) (defconstant create-path 230) (defconstant set-pen 232) (defconstant draw-path 234) (defconst set-magnification 236) (defconst bitmap 235) (defconst opaque 3) (defconst eof 255) (defconst impress-set-push-mask 214) (defconst impress-push 211) (defconst impress-pop 212) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmethod (imagen-dvi-document :start-output)() (format t "~& Processing pages.... ") ) (defvar *im-debug* nil) (defmethod (imagen-dvi-document :end-output)() ;download needed fonts (format t "~& Writing output ... ") (with-open-stream (outstream (open-8b-output outfile)) (setq outfile (send outstream :truename)) ;for each needed font (dotimes (fntnum (fill-pointer fontnums)) (let* ((key (aref fontmap fntnum)) (fontdef (send *font-definitions* :get-hash key)) (fontdims (fd-font-directory fontdef)) (rasters (fd-raster-info fontdef)) (char-status (fd-char-status fontdef))) ;for each needed char (dotimes (charcode chars-per-font) (cond ((not (zerop (aref char-status charcode))) (let ((chardims (aref fontdims charcode))) (write-byte outstream bgly) (write-2-bytes outstream (logior (lsh fntnum 7) charcode)) (write-2-bytes outstream (char-pxl-width chardims)) ;; units to avoid roundoff errors. (write-2-bytes outstream (char-width chardims)) (write-2-bytes outstream (char-x-offset chardims)) (write-2-bytes outstream (char-height chardims)) (write-2-bytes outstream (char-y-offset chardims))) (let ((raster (aref rasters charcode))) (dotimes (i (array-length raster)) (write-byte outstream (aref raster i))))))))) ;output textual commands from buffer (send outstream :string-out buffer) )) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; This is the main loop that processes the pages ;; once the preamble and postamble have been ;; processed. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmethod (imagen-dvi-document :do-pages)() (move-back file-buffer (1- total-pages)) (let ((current-page 1) (bop-params nil)) (loop for command = (bget-byte file-buffer) do (if ( command bop)(bad-dvi "bop command missing")) (setq bop-params nil) (dotimes (i 11) ; collect the c0 to c9 params and prev page ptr (setq bop-params (cons (bsigned-quad file-buffer) bop-params))) (setq bop-params (nreverse bop-params)) ; put them in right order (format t "[~D" current-page) (cond ((or (not *do-page-p*) (funcall *do-page-p* current-page (car bop-params))) (send self :bop bop-params) ;;do the page (loop for cmnd = (bget-byte file-buffer) do ; (if ( cmnd pre)(bad-dvi "invalid DVI command between bop and eop")) (cond (*im-debug* (let ((message (get-message-name cmnd)) (args (get-parameters cmnd file-buffer))) (format t "~%~A ~S " message args) (cond ((eq message :push-stack) (format t "~D ~D ~D ~D ~D" h v w x y z)) ((memq message '(:set-char :put-char)) (tyo args))) (send self message args) (cond ((eq message :pop-stack) (format t "~D ~D ~D ~D ~D" h v w x y z))))) ('else (send self (get-message-name cmnd) (get-parameters cmnd file-buffer)))) (if (= cmnd eop)(return (values))))) ('else (format t " (~D)skipping" (car bop-params)) (loop for cmnd = (bget-byte file-buffer) do (get-parameters cmnd file-buffer) (if (= cmnd eop) (return (values)))))) (incf current-page) ;; set pointer to the next bop and loop back (if ( current-page total-pages) (loop for byte = (bget-byte file-buffer) until (= byte bop) do (cond (( byte nop) ; i.e., font def, skip the params (incf (fill-pointer file-buffer) (+ (1+ (- byte fntdef1)) 12)) (let ((bytes (+ (bget-byte file-buffer) (bget-byte file-buffer)))) (incf (fill-pointer file-buffer) bytes)))) finally (decf (fill-pointer file-buffer))) (return (format t "]"))) (format t "] ") ))) (defmacro correct() `(let ((diff (- pixel-h (pixel-round h)))) (cond ((< diff 0) (dotimes (i (minus diff)) (write-buffer buffer mplus))) ((> diff 0) (dotimes (i diff) (write-buffer buffer mminus)))) (setq pixel-h (pixel-round h)))) (defmethod (imagen-dvi-document :set-char)(charcode) ;;params - the char code of the char to be set ; (if (> char-code chars-per-font)(bad-dvi "Undefined font member")) (write-buffer buffer charcode) ;;set the char (let* ((fntdef (send *font-definitions* :get-hash current-font)) (char-dims (aref (fd-font-directory fntdef)charcode))) ;;set char status to used. (aset 1 (fd-char-status fntdef) charcode) ;;advance internal h and correct for cumulative errors. (incf h (char-dvi-width char-dims)) (incf pixel-h (char-pxl-width char-dims)) (correct))) (defmethod (imagen-dvi-document :set-rule)(params) ;;(car params) - height of rectangle ;;(cdr params) - width of rectangle (let ((ht (car params)) (wd (cdr params))) (cond ((and (> ht 0)(> wd 0)) (correct) ;;draw the rule on the imagen (write-buffer buffer brule) (write2-buffer buffer (rule-pixels wd)) (write2-buffer buffer (rule-pixels ht)) (write2-buffer buffer (- 1 (pixel-round ht))) ;offset ;;advance the internal h (incf h wd) ;;advance the pen on the imagen (write-buffer buffer mmove) (write2-buffer buffer (- (rule-pixels h) pixel-h)) (setq pixel-h (rule-pixels h)))))) (defmethod (imagen-dvi-document :put-char)(charcode) ;;params - the char code of the char to be written ; (if (> charcode chars-per-font)(bad-dvi "Undefined font member")) (write-buffer buffer charcode) ;;write the char (let* ((fntdef (send *font-definitions* :get-hash current-font)) (char-dims (aref (fd-font-directory fntdef)charcode))) (write-buffer buffer mmove) (write2-buffer buffer (minus (char-width char-dims)))) (aset 1 (fd-char-status (send *font-definitions* :get-hash current-font)) charcode) ) (defmethod (imagen-dvi-document :put-rule )(params) ;;(car params) - height of rectangle ;;(cdr params) - width of rectangle (let ((ht (car params)) (wd (cdr params))) (cond ((and (> ht 0)(> wd 0)) (correct) ;;draw the rule on the imagen (write-buffer buffer brule) (write2-buffer buffer (rule-pixels wd)) (write2-buffer buffer (rule-pixels ht)) (write2-buffer buffer (- 1 (pixel-round ht))))))) (defvar *extra-pixel-h-offset* nil) (defvar *extra-pixel-v-offset* nil) (defun set-picture-page (h-inches v-inches &optional (left-page-offset 0)) (list (setq *EXTRA-PIXEL-V-OFFSET* (round (* v-inches 300))) (setq *EXTRA-PIXEL-H-OFFSET* (cond ((zerop left-page-offset) (round (* h-inches 300))) ('else #'(lambda (pnum) (cond ((oddp pnum) (round (* h-inches 300))) ('else (round (* (- h-inches left-page-offset) 300)))))))))) (defmethod (imagen-dvi-document :bop) (list) (format t "(~D)" (car list)) (setq extra-pixel-h-offset (cond ((not *extra-pixel-h-offset*) 0) ((numberp *extra-pixel-h-offset*) *extra-pixel-h-offset*) ('else (funcall *extra-pixel-h-offset* (car list))))) (setq extra-pixel-v-offset (cond ((not *extra-pixel-v-offset*) 0) ((numberp *extra-pixel-v-offset*) *extra-pixel-v-offset*) ('else (funcall *extra-pixel-v-offset* (car list))))) (setq h (dvi-round (+ xpage-offset extra-pixel-h-offset)) v (dvi-round (+ ypage-offset extra-pixel-v-offset)) w 0 x 0 y 0 z 0 pixel-h (+ xpage-offset extra-pixel-h-offset) pixel-v (+ ypage-offset extra-pixel-v-offset)) (send self :empty-stack) (setq current-font "Undefined") (write-buffer buffer page) (write-buffer buffer set-abs-h) (write2-buffer buffer pixel-h) (write-buffer buffer set-abs-v) (write2-buffer buffer pixel-v) ) (defmethod (imagen-dvi-document :eop)(ignore) ;send the page for printing (write-buffer buffer endpage) ; (if ( 0 (fill-pointer hstack)) ; (print "Warning - Stack not empty at EOP")) ) (defmethod (imagen-dvi-document :after :pop-stack)(ignore) (write-buffer buffer set-abs-h) (write2-buffer buffer pixel-h) (write-buffer buffer set-abs-v) (write2-buffer buffer pixel-v)) (defmethod (imagen-dvi-document :right)(delta-h) ;params - amount in dvi units to move h in the right direction (incf h delta-h) (let ((diff (pixel-round h))) (write-buffer buffer mmove) (write2-buffer buffer (- diff pixel-h)) (setq pixel-h diff))) (defmethod (imagen-dvi-document :w)(new-w) ;params - = nil if current value of w is to be used ; = gives new value of w if not nil (if (numberp new-w)(setq w new-w)) (incf h w) (let ((diff (pixel-round h))) (write-buffer buffer mmove) (write2-buffer buffer (- diff pixel-h)) (setq pixel-h diff))) (defmethod (imagen-dvi-document :x)(new-x) ;params - = nil if current value of w is to be used ; = gives new value of w if not nil ; this makes use of the set space feature of ImPress, ; which presumably is faster than explicitly setting ; the x position. (cond ((numberp new-x) (setq x new-x) (write-buffer buffer set-sp) (write2-buffer buffer (pixel-round x)))) (write-buffer buffer sp) (incf h x) (incf pixel-h (pixel-round x)) (correct) ) (defmethod (imagen-dvi-document :down)(delta-v) ;params - amount to move pen down in dvi units (incf v delta-v) (setq pixel-v (pixel-round v)) (write-buffer buffer set-abs-v) (write2-buffer buffer pixel-v)) (defmethod (imagen-dvi-document :y)(new-y) (if (numberp new-y)(setq y new-y)) (incf v y) (setq pixel-v (pixel-round v)) (write-buffer buffer set-abs-v) (write2-buffer buffer pixel-v)) (defmethod (imagen-dvi-document :z)(new-z) (if (numberp new-z)(setq z new-z)) (incf v z) (setq pixel-v (pixel-round v)) (write-buffer buffer set-abs-v) (write2-buffer buffer pixel-v)) (defmethod (imagen-dvi-document :set-fnt)(texfntnum) ;params - number of font to set to (TeX number) (let ((fntnum (get-fntnum texfntnum fontnums))) (setq current-font (aref fontmap fntnum)) (if (null current-font)(bad-dvi "Undefined font")) (write-buffer buffer set-family) (write-buffer buffer fntnum))) (defvar *ignore-specials* nil) (defmethod (imagen-dvi-document :xxx) (bytes) (let ((string (make-string bytes)) (offset (fill-pointer file-buffer))) (incf (fill-pointer file-buffer) bytes) (copy-array-portion file-buffer offset (fill-pointer file-buffer) string 0 bytes) (let ((command (parse-xxx-string string))) (cond (*ignore-specials*) ((and (consp command) (symbolp (car command)) (get (intern (string-upcase (car command)) "") 'imagen-dvi-xxx)) (funcall (get (intern (string-upcase (car command)) "") 'imagen-dvi-xxx) self command)) ('else (bad-dvi "unknown \special command: ~A" (car command))))))) (defun (:impress-bitmap imagen-dvi-xxx) (document command) (let ((buffer (send document :buffer))) (format t "~&Reading impress bitmap from ~S ~{~S ~S~^, ~}~%" (cadr command) (cddr command)) (cond ((not (probe-file (cadr command))) (format t "File does not exist. Continuing...~%")) ('else (write-buffer buffer impress-set-push-mask) (write-buffer buffer 255) (write-buffer buffer 255) (write-buffer buffer impress-push) (with-open-stream (stream (open-8b-input (cadr command))) (let ((defaults)) (when (setq defaults (probe-defaults stream (cadr command))) (format t "~&Getting defaults from ~A~%" defaults) (setq defaults (car (forms-from-file defaults)))) (let ((hsize (send stream :tyi)) (vsize (send stream :tyi))) (read-32-le stream) (read-32-le stream) (write-buffer buffer set-magnification) (write-buffer buffer (get (cdr command) :magnification (getf defaults :magnification 0))) (write-buffer buffer set-abs-h) (write2-buffer buffer (round (evaluate-offset (get (cdr command) :h-offset (getf defaults :h-offset 0)) document))) (write-buffer buffer set-abs-v) (write2-buffer buffer (round (evaluate-offset (get (cdr command) :v-offset (getf defaults :v-offset 0)) document))) (write-buffer buffer bitmap) (write-buffer buffer opaque) (write-buffer buffer hsize) (write-buffer buffer vsize) (let ((s-stream)) (setq s-stream #'(lambda (op &optional arg1 &rest args) (si:selectq-with-which-operations op (:tyo (write-buffer buffer arg1)) (:string-out (do ((j (or (car args) 0) (1+ j)) (end (or (cadr args) (length arg1))) (to buffer)) ((= j end)) (write-buffer to (aref arg1 j)))) (#+(OR LMI SYMBOLICS) t #+TI OTHERWISE (stream-default-handler s-stream op arg1 args))))) (stream-copy-until-eof stream s-stream)) (write-buffer buffer impress-pop)))))))) (defun evaluate-offset (x document) ;; return an offset in imagen-sized pixels, i.e. 300 per inch. ;; common input is (+ :pixel-v 150), for 1/2 inch under the last text. (etypecase x (number x) (symbol (* (quotient 300.0 (send document :printer-resolution)) (ecase x (:pixel-h (send document :pixel-h)) (:pixel-v (send document :pixel-v)) (:ypage-offset (send document :ypage-offset)) (:xpage-offset (send document :xpage-offset)) (:extra-pixel-h-offset (or (send document ':send-if-handles :extra-pixel-h-offset) 0)) (:extra-pixel-v-offset (or (send document ':send-if-handles :extra-pixel-v-offset) 0))))) (cons (apply (car x) (mapcar #'(lambda (a) (evaluate-offset a document)) (cdr x)))))) ;;; the following code is for converting bitmaps as arrays into ;;; impress BITMAP data bytes. (defvar *imagen-data-bytes* nil) (defvar *imagen-data-size* nil) (defvar *bitrev-byte-table* nil) (defvar *32^32-chunk* nil) (defvar *128-byte-chunk* nil) (defun setup-imagen-data-bytes (array x y dx dy) (when (null *bitrev-byte-table*) (setq *bitrev-byte-table* (make-array 256)) (dotimes (j 256) (setf (aref *bitrev-byte-table* j) (do ((value 0 (dpb (ldb (byte 1 k) j) (byte 1 (- 7 k)) value)) (k 0 (1+ k))) ((= k 8) value))))) (when (or (null *32^32-chunk*) (null *128-byte-chunk*)) (setq *32^32-chunk* (make-array '(32 32) :type 'art-1b)) (setq *128-byte-chunk* (make-array 128 :type 'art-8b :displaced-to *32^32-chunk*))) (multiple-value-bind (easy-y remainder-y) (floor dy 32) (multiple-value-bind (easy-x remainder-x) (floor dx 32) (let ((hsize (+ easy-x (if (zerop remainder-x) 0 1))) (vsize (+ easy-y (if (zerop remainder-y) 0 1)))) (setq *imagen-data-size* (list hsize vsize dx dy)) (do ((ymap 0 (1+ ymap)) (data-bytes *imagen-data-bytes*) (inc 0) (bitrev *bitrev-byte-table*) (32^32-chunk *32^32-chunk*) (128-byte-chunk *128-byte-chunk*)) ((= ymap vsize)) (do ((xmap 0 (1+ xmap))) ((= xmap hsize)) (let ((xbase (ash xmap 5)) (ybase (ash ymap 5))) (let ((x-want (min (- dx xbase) 32)) (y-want (min (- dy ybase) 32))) (when (or (= x-want remainder-x) (= y-want remainder-y)) (fill 128-byte-chunk 0)) (bitblt tv:alu-seta x-want y-want array (+ xbase x) (+ ybase y) 32^32-chunk 0 0))) (copy-array-portion-translated 128-byte-chunk 0 128 data-bytes inc (incf inc 128) bitrev))))))) (defun copy-array-portion-translated (from-array from-start from-end to-array to-start to-end translation-table) ;; a canditate for microcompilation. (copy-array-portion from-array from-start from-end to-array to-start to-end) ;; A typical screen array takes 4.2 seconds to process. ;; 1.0 seconds with the following code commented out, ;; and 0.33 seconds with this entire function a no-op. (do ((j to-start (1+ j))) ((= j to-end)) ;; by having only one real array reference here ;; we win in the array cache. (setf (aref to-array j) ;; 3.4 seconds without the %p-contents-offset. (%p-contents-offset translation-table (1+ (aref to-array j)))))) ;;; the following code is enabled via (setq si:*default-bit-array-pinter* :bitmap) ;;; in the LMI system. It is a way to create the bitmap files to be used ;;; by the \special{impress-bitmap ...} command. ;;; this will save a file with the minimal information ;;; about the bitmap. <128*HSIZE*VSIZE bytes of data> ;;; #+(OR LMI TI) (progn 'compile (defvar *bitmap-pathname-defaults* nil) (add-initialization "bitmap pathname defaults" '(progn (setq *bitmap-pathname-defaults* (fs:make-pathname-defaults)) (fs:merge-and-set-pathname-defaults "FOO.IBITS" *bitmap-pathname-defaults*)) '(:now warm)) (defun open-printer-bitmap-file (printer) (let (pathname) (cond ((atom printer) (setq pathname (prompt-and-read `(:pathname :defaults ,*bitmap-pathname-defaults*) "~&Filename for bitmap, default /"~A/"> " (fs:merge-pathname-defaults "" *bitmap-pathname-defaults*))) (format *query-io* "~&Writing to /"~A/"~%" pathname)) ('else (setq pathname (fs:parse-pathname (cadr printer))))) (fs:merge-and-set-pathname-defaults pathname *bitmap-pathname-defaults*) (cond ((eq :lispm (send pathname :system-type)) (open pathname :direction :output)) ('else (open pathname :direction :output :raw t))))) (defun (:impress-bitmap-file si:print-bit-array) (PRINTER ARRAY LEFT TOP RIGHT BOTTOM &rest ignore) (when (null *imagen-data-bytes*) (setq *imagen-data-bytes* (make-array (// (* 1024 1024) 8) :type 'art-string))) (setup-imagen-data-bytes array left top (- right left) (- bottom top)) (with-open-stream (stream (open-printer-bitmap-file printer)) (send stream :tyo (nth 0 *imagen-data-size*)) (send stream :tyo (nth 1 *imagen-data-size*)) (write-32-le (nth 2 *imagen-data-size*) stream) (write-32-le (nth 3 *imagen-data-size*) stream) (send stream :string-out *imagen-data-bytes* 0 (* 128 (nth 0 *imagen-data-size*) (nth 1 *imagen-data-size*))) (setq *imagen-data-size* nil))) ) (defun (:saved-paint-image imagen-dvi-xxx) (document command) (let (FILE DEFAULTS ARRAY WIDTH HEIGHT MAGNIFICATION H-OFFSET V-OFFSET HSIZE VSIZE BUFFER array-h-offset array-v-offset array-width array-height) (setq buffer (send document :buffer)) (format t "~&Loading paint file ~S" (cadr command)) (multiple-value-setq (array file) (load-paint-array (cadr command))) (when (setq defaults (probe-file (send file :new-pathname :type "DEFAULTS" :VERSION :NEWEST))) (format t "~&Getting defaults from ~A" defaults) (SETQ DEFAULTS (CAR (FORMS-FROM-FILE DEFAULTS)))) (SETQ WIDTH (PIXEL-ARRAY-WIDTH ARRAY)) (SETQ HEIGHT (PIXEL-ARRAY-HEIGHT ARRAY)) (setq magnification (get (cdr command) :magnification (getf defaults :magnification 0))) (setq h-offset (evaluate-offset (get (cdr command) :h-offset (getf defaults :h-offset 0)) document)) (setq v-offset (evaluate-offset (get (cdr command) :v-offset (getf defaults :v-offset 0)) document)) (when (null *imagen-data-bytes*) (setq *imagen-data-bytes* (make-array (// (* 1024 1024) 8) :type 'art-string))) (format t " processing ...") (setq array-h-offset (eval (getf defaults :array-h-offset 0))) (setq array-v-offset (eval (getf defaults :array-v-offset 0))) (setq array-width (eval (getf defaults :array-width (- width array-h-offset)))) (setq array-height (eval (getf defaults :array-height (- height array-v-offset)))) (setup-imagen-data-bytes array array-h-offset array-v-offset (min array-width (- width array-h-offset)) (min array-height (- height array-v-offset))) (setq hsize (nth 0 *imagen-data-size*)) (setq vsize (nth 1 *imagen-data-size*)) (write-buffer buffer impress-set-push-mask) (write-buffer buffer 255) (write-buffer buffer 255) (write-buffer buffer impress-push) (write-buffer buffer set-magnification) (write-buffer buffer magnification) (write-buffer buffer set-abs-h) (write2-buffer buffer (round h-offset)) (write-buffer buffer set-abs-v) (write2-buffer buffer (round v-offset)) (write-buffer buffer bitmap) (write-buffer buffer opaque) (write-buffer buffer hsize) (write-buffer buffer vsize) (do ((data *imagen-data-bytes*) (j 0 (1+ j)) (n (* 128 hsize vsize))) ((= j n)) (write-buffer buffer (aref data j))) (write-buffer buffer impress-pop)))