blob: 015891e868ce52659564bacd06515fe840ba3f02 (
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
|
;;; Chickadee Game Toolkit
;;; Copyright © 2023 David Thompson <dthompson2@worcester.edu>
;;;
;;; Licensed under the Apache License, Version 2.0 (the "License");
;;; you may not use this file except in compliance with the License.
;;; You may obtain a copy of the License at
;;;
;;; http://www.apache.org/licenses/LICENSE-2.0
;;;
;;; Unless required by applicable law or agreed to in writing, software
;;; distributed under the License is distributed on an "AS IS" BASIS,
;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;;; See the License for the specific language governing permissions and
;;; limitations under the License.
;;; Commentary:
;;
;; Data type for representing images on disk.
;;
;;; Code:
(define-module (chickadee image)
#:use-module (chickadee graphics color)
#:use-module (chickadee graphics pixbuf)
#:use-module (chickadee image jpeg)
#:use-module (chickadee image png)
#: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))
|