Improve speed of canvas painting
While trying to replicate Coding Train's [Mandelbrot set sketch](https://www.youtube.com/watch?v=6z7GQewK-Ks), I found that canvas painting is very slow.

Here's my code to create a canvas and draw a picture of the Mandelbrot set on it (requires `alexandria` for the utility function):

```lisp
(defun make-mandelbrot-image (width height min-val max-val max-iters bound)
  (let ((canvas (make-canvas width height)))
    (dotimes (x width)
      (dotimes (y height)
        (let ((c (complex (remap x 0 width min-val max-val)
                          (remap y 0 height min-val max-val)))
              (z 0)
              (n 0))
          (loop while (and (< n max-iters) (< (abs z) bound))
                do (setf z (+ (* z z) c))
                do (incf n))
          (canvas-paint canvas
                        (gray-255 (remap n 0 max-iters 0 255))
                        x
                        y))))
    (canvas-lock canvas)
    canvas))

(defun remap (x la ha lb hb)
  "Takes x from the interval [la, ha] and remaps it to the
interval [lb, hb]. If x is outside the expected interval, then
it gets clamped."
  (setf x (alexandria:clamp x la ha))
  (+ lb (* (- hb lb) (/ (- x la) (- ha la)))))
```

Running `(time (make-mandelbrot-image 100 100 -1 +1 10 16))`, this takes over 9 seconds on my machine, even for this relatively small canvas size.

Extracting the logic to compute the value at each coordinate, it takes only 0.015 seconds. This indicates that the slowness comes from painting the canvas or generating the resulting image.

```lisp
(time
   (let ((width 100) (height 100) (max-val 1) (min-val 1) (max-iters 10) (bound 16))
     (dotimes (x width)
       (dotimes (y height)
         (let ((c (complex (remap x 0 width min-val max-val)
                           (remap y 0 height min-val max-val)))
               (z 0)
               (n 0))
           (loop while (and (< n max-iters) (< (abs z) bound))
                 do (setf z (+ (* z z) c))
                 do (incf n)))))))
```

Finally, commenting out the `(canvas-lock canvas)` line in the original code, which (as far as I understand) is responsible for generating an image, it takes just as much time as before (9+ seconds). This leads me to believe that `(canvas-paint)` is the bottleneck. I am happy to dig into this and work on optimising it. Ideally, I think that pixel poking should be just as fast as in p5.js or Processing.