» Sunday, 26 September A.D. 2010

the essence of pixel conversion

In the spirit of noodling around with code, I present pixel conversion in Lisp:

(defmethod pixel-reader ((format rgba) buffer start)
  #'(lambda ()
      (multiple-value-prog1 (values (aref buffer start)
                                    (aref buffer (+ start 1))
                                    (aref buffer (+ start 2))
                                    (aref buffer (+ start 3)))
        (incf start 4))))

(defmethod pixel-writer ((format rgba) buffer start)
  #'(lambda (r g b a)
      (setf (aref buffer start) r
            (aref buffer (+ start 1)) g
            (aref buffer (+ start 2)) b
            (aref buffer (+ start 3)) a)
      (incf start 4)
      (values)))

(defmethod find-converter ((dst-format rgba-float) (src-format rgba-u8))
  #'(lambda (r g b a)
      (values (float r 1.0f0) (float g 1.0f0) (float b 1.0f0) (float a 1.0f0))))

(defun convert-pixels (dst-format src-format dst-buffer dst-start
                       src-buffer src-start n-pixels)
  (loop with converter = (find-converter dst-format src-format)
        with reader = (pixel-reader src-format src-buffer src-start)
        with writer = (pixel-writer dst-format dst-buffer dst-start)
        repeat n-pixels
        do (multiple-value-call writer
             (multiple-value-call converter (funcall reader)))))

I think that's pretty code, though probably not very efficient. But tweaking it with something like:

(defmethod pixel-writer ((format rgba-float) buffer start)
  #'(lambda (rgba-vec)
      (replace buffer rgba-vec :start1 start)
      (incf start 4)
      (values)))

(defmethod find-converter ((dst-format rgba-float) (src-format rgba-u8))
  (let ((rgba-vec (make-array 4 :element-type 'single-float)))
    #'(lambda (r g b a)
        (setf (aref rgba-vec 0) (float r 1.0f0)
              (aref rgba-vec 1) (float g 1.0f0)
              (aref rgba-vec 2) (float b 1.0f0)
              (aref rgba-vec 3) (float a 1.0f0))
        rgba-vec)))

would eliminate a major source of consing (depending on the implementation, of course; maybe single-floats aren't boxed in your implementation). The small minus is having to repeat the rgba-vec trick for every conversion function, but maybe there's a clever way around that.

posted by Nate @ 9:47PM