jpeg sizes or binary shuffle (lisp)

2006-06-30 11:14:50

I was going to use jpeg.lisp to get jpeg dimensions for cl-picarc but defconstant and sbcl would not play nice. Plus it was a little heavy handed for what I needed, so I rolled by own:


;; I only need the dimisions of a jpeg so I am going
;; to roll my own dimension extractor
;; based in part on
;; http://dev.w3.org/cvsweb/Amaya/libjpeg/rdjpgcom.c?rev=1.2

(defun jpeg-next-marker (in)
  (labels ((1-byte (s c)
                   (if (= c #xff) 
                       (1-byte s (read-byte s))
                       c)))
    (1-byte in (read-byte in))))

(defun jpeg-skip-variable (in)
  (let ((len (2-bytes in)))
    (if (< len 2) (error "Bad jpeg marker length")
        (dotimes (i (- len 1)) 
          (read-byte in)))))
    

(defun jpeg-first-marker (in)
  (let ((c1 (read-byte in))
        (c2 (read-byte in)))
    (if (not (and (= c1 #xff) (= c2 #xd8)))
        (error "Not a JPEG file"))
    c2))

;;msb first
(defun 2-bytes (in)
  (let ((b1 (read-byte in))
        (b2 (read-byte in)))
    (dpb b1 (byte 8 8) (dpb b2 (byte 8 0) #x0))))

(defun jpeg-process-image-size (in)
  (2-bytes in)
  (read-byte in)
  (let ((height (2-bytes in))
        (width  (2-bytes in)))
    (values width height)))
                  
(defun jpeg-image-size (file-name)
  (with-open-file (s file-name :element-type '(unsigned-byte 8))
    (if (not (= (jpeg-first-marker s) #xd8))
        (values 0 0)
        (progn
          (loop
           (let ((marker (jpeg-next-marker s)))
             (cond ((or (= marker #xC0)
                        (= marker #xC1)
                        (= marker #xC2)
                        (= marker #xC3)
                        (= marker #xC5)
                        (= marker #xC6)
                        (= marker #xC7)
                        (= marker #xC9)
                        (= marker #xCA)
                        (= marker #xCB)
                        (= marker #xCD)
                        (= marker #xCE)
                        (= marker #xCF)) 
                    (return (jpeg-process-image-size s)))
                   ((or (= marker #xda)
                        (= marker #xd9)) (return (values 0 0)))
                   (t (jpeg-skip-variable s)))))))))

This is the first time I have had to work with binary files using lisp. It is kind of nice. I am using cl-png to get the png image sizes and I do not plan to support gifs.