blob: 289fb14c7c974e5d09363b80df90a3f268b9a390 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
;;; Chickadee Game Toolkit
;;; Copyright © 2023 David Thompson <dthompson2@worcester.edu>
;;;
;;; Chickadee is free software: you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published
;;; by the Free Software Foundation, either version 3 of the License,
;;; or (at your option) any later version.
;;;
;;; Chickadee is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program. If not, see
;;; <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
;; Data type for representing images on disk.
;;
;;; Code:
(define-module (chickadee image)
#:use-module (chickadee graphics color)
#:use-module (chickadee image jpeg)
#:use-module (chickadee image png)
#:use-module (chickadee pixbuf)
#:use-module (chickadee utils)
#:use-module (ice-9 exceptions)
#:use-module (ice-9 match)
#:use-module (rnrs bytevectors)
#:use-module (srfi srfi-9)
#:use-module (srfi srfi-9 gnu)
#:export (make-image
image?
image-file-name
temp-image-file-name
read-image
write-image))
(define &image-error
(make-exception-type '&image-error &error '()))
(define make-image-error (record-constructor &image-error))
(define (image-error message irritants)
(raise-exception
(make-exception
(make-image-error)
(make-exception-with-message message)
(make-exception-with-irritants irritants))))
;; An image is pixel data that is stored on disk in one of a variety
;; of formats.
(define-record-type <image>
(%make-image file-name)
image?
(file-name image-file-name))
(define (make-image file-name)
(%make-image (absolute-file-name file-name)))
(define (print-image image port)
;; Rendering in a format that Geiser understands so that images can
;; be viewed inline at the REPL.
(format port "#<Image: ~a>" (image-file-name image)))
(set-record-type-printer! <image> print-image)
(define (image-format image)
(match (file-extension (image-file-name image))
((or "jpg" "jpeg") 'jpeg)
("png" 'png)
(_ 'unknown)))
(define* (read-image image)
"Read data from IMAGE and return a pixbuf."
(define-values (pixels width height)
(case (image-format image)
((jpeg)
(load-jpeg (image-file-name image)))
((png)
(load-png (image-file-name image)))
(else
(image-error "unsupported image format: ~a" (image-format image)))))
(bytevector->pixbuf pixels width height #:format 'rgba #:bit-depth 8))
;; Not guaranteed to be a file that doesn't exist, but good enough.
(define (temp-image-file-name format)
(string-append (tmpdir) "/"
(symbol->string
(gensym "chickadee-"))
"."
(symbol->string format)))
(define* (write-image pixbuf
#:optional (file-name (temp-image-file-name 'png))
#:key (format 'png))
"Write PIXBUF to FILE-NAME and return an image object. FORMAT may be
either 'png' or 'jpeg'."
(unless (and (eq? (pixbuf-format pixbuf) 'rgba)
(= (pixbuf-bit-depth pixbuf) 8))
(image-error "can only write RGBA pixbufs with 8 bit depth: ~a" pixbuf))
(case format
((png)
(save-png (pixbuf-pixels pixbuf)
(pixbuf-width pixbuf)
(pixbuf-height pixbuf)
file-name))
(else
(image-error "unsupport image format: ~a" format)))
(make-image file-name))
|