(ql:quickload :cl-netpbm)

(defun burkes (img thresh &aux
                  (x (array-dimension img 0))
                  (y (array-dimension img 1)))
 (declare (type fixnum x y thresh)
          (optimize (speed 3) (safety 0)))
 (let ((res (make-array (array-dimensions img)
                        :element-type 'bit))
       (cur (make-array (+ 4 x)
                        :element-type 'double-float))
       (nxt (make-array (+ 4 x)
                        :element-type 'double-float)))
   (declare (dynamic-extent cur nxt))
   (loop for i from 0 to (1- y)
         do (progn
              (loop for j from 0 to (1- x)
                    do (let* ((s (+ (aref img j i)
                                    (aref cur (+ j 2))))
                              (pix (if (< s thresh)
                                       0
                                       1))
                              (err (- s (* pix 255))))
                         (setf (aref res j i) pix)
                         (incf (aref cur (+ j 3)) (* err 0.25D0))
                         (incf (aref cur (+ j 4)) (* err 0.125D0))
                         (incf (aref nxt j) (* err 0.0625D0))
                         (incf (aref nxt (+ j 1)) (* err 0.125D0))
                         (incf (aref nxt (+ j 2)) (* err 0.25D0))
                         (incf (aref nxt (+ j 3)) (* err 0.125D0))
                         (setf (aref nxt (+ j 4)) (* err 0.0625D0))))
              (let ((tmp cur))
                (loop for i from 0 to 3
                      do (setf (aref tmp i) 0.0D0))
                (setf cur nxt)
                (setf nxt tmp))))
   res))

(defun serria-lite (img thresh &aux
                  (x (array-dimension img 0))
                  (y (array-dimension img 1)))
 (let ((res (make-array (array-dimensions img)
                        :element-type 'bit))
       (cur (make-array (+ 2 x)
                        :element-type 'double-float))
       (fwd (make-array (+ 2 x)
                        :element-type 'double-float)))
   (loop for i from 0 to (1- y)
         do (progn
              (loop for j from 0 to (1- x)
                    do (let* ((s (+ (aref img j i)
                                    (aref cur (1+ j))))
                              (pix (if (< s thresh)
                                       0
                                       1))
                              (err (- s (* pix 255))))
                         (setf (aref res j i) pix)
                         (incf (aref cur (+ j 2)) (* err 0.5D0))
                         (let ((n (* err 0.25D0)))
                           (incf (aref fwd j) n)
                           (setf (aref fwd (1+ j)) n))))
              (let ((tmp cur))
                (setf (aref tmp (1- x)) 0.0D0
                      (aref tmp 0) 0.0D0)
                (setf cur fwd)
                (setf fwd tmp))))
   res))


(defun atkinson (img thresh
                &aux
                  (x (array-dimension img 0))
                  (y (array-dimension img 1)))
 (declare (type fixnum x y thresh)
          (optimize (speed 3) (safety 0)))
 (let ((res (make-array (array-dimensions img)
                        :element-type 'bit))
       (cur (make-array (+ 3 x)
                        :element-type 'double-float))
       (fwd1 (make-array (+ 3 x)
                         :element-type 'double-float))
       (fwd2 (make-array (+ 3 x)
                         :element-type 'double-float)))
   (declare (dynamic-extent cur fwd1 fwd2))
   (loop for i from 0 to (1- y)
         do (progn
              (loop for j from 0 to (1- x)
                    do (let* ((s (+ (aref img j i)
                                    (aref cur (1+ j))))
                              (pix (if (< s thresh)
                                       0
                                       1))
                              (err (* 0.125D0 (- s (* pix 255)))))
                         (setf (aref res j i) pix)
                         (incf (aref cur (+ j 2)) err)
                         (incf (aref cur (+ j 3)) err)
                         (incf (aref fwd1 j) err)
                         (incf (aref fwd1 (1+ j)) err)
                         (incf (aref fwd1 (+ j 2)) err)
                         (setf (aref fwd2 (1+ j)) err)))
              (let ((tmp cur))
                (setf (aref cur 0) 0.0D0
                      (aref cur (1- x)) 0.0D0
                      (aref cur (- x 2)) 0.0D0)
                (setf cur fwd1)
                (setf fwd1 fwd2)
                (setf fwd2 tmp))))
   res))

(defvar *value* 210)
(defvar *dither-function* #'atkinson)
(defun convert (file)
 (netpbm:write-to-file
  (make-pathname :name (pathname-name file) :type "pbm")
  (funcall *dither-function* (netpbm:read-from-file file) *value*)
  :format :pbm))