racket/collects/mrlib/gif.ss
2008-02-23 09:42:03 +00:00

76 lines
2.9 KiB
Scheme

(module gif mzscheme
(require mzlib/class
mzlib/file
mred
net/gifwrite
mzlib/contract
mzlib/kw
mzlib/etc)
(provide write-gif
write-animated-gif)
(define (force-bm bm) (if (procedure? bm) (bm) bm))
(define (split-bytes b len offset)
(if (= offset (bytes-length b))
null
(cons (subbytes b offset (+ offset len))
(split-bytes b len (+ offset len)))))
(define (write-gifs bms delay filename one-at-a-time?)
(let* ([init (force-bm (car bms))]
[w (send init get-width)]
[h (send init get-height)])
(let ([argb-thunks
(map (lambda (bm)
(lambda ()
(let ([bm (force-bm bm)]
[argb (make-bytes (* w h 4) 255)])
(send bm get-argb-pixels 0 0 w h argb)
(let ([mask (send bm get-loaded-mask)])
(when mask
(send mask get-argb-pixels 0 0 w h argb #t)))
argb)))
(cons init (cdr bms)))])
(if one-at-a-time?
;; Quantize individually, and stream the images through
(call-with-output-file*
filename
(lambda (p)
(let* ([gif (gif-start p w h 0 #f)])
(when delay
(gif-add-loop-control gif 0))
(for-each (lambda (argb-thunk)
(let-values ([(pixels colormap transparent)
(quantize (argb-thunk))])
(when (or transparent delay)
(gif-add-control gif 'any #f (or delay 0) transparent))
(gif-add-image gif 0 0 w h #f colormap pixels)))
argb-thunks)
(gif-end gif))))
;; Build images and quantize all at once:
(let-values ([(pixels colormap transparent)
(quantize (apply bytes-append (map (lambda (t) (t)) argb-thunks)))])
(call-with-output-file*
filename
(lambda (p)
(let* ([gif (gif-start p w h 0 colormap)])
(when delay
(gif-add-loop-control gif 0))
(for-each (lambda (pixels)
(when (or transparent delay)
(gif-add-control gif 'any #f (or delay 0) transparent))
(gif-add-image gif 0 0 w h #f #f pixels))
(split-bytes pixels (* w h) 0))
(gif-end gif)))))))))
(define (write-gif bm filename)
(write-gifs (list bm) #f filename #f))
(define/kw (write-animated-gif bms delay filename #:key [one-at-a-time? #f])
(write-gifs bms delay filename one-at-a-time?))
)