/
image-lift.ss
144 lines (112 loc) · 4.68 KB
/
image-lift.ss
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#lang scheme/base
(require scheme/class
scheme/gui/base
scheme/list
scheme/port
mrlib/cache-image-snip
scheme/contract
"utils.ss"
"resource.ss"
"collects/moby/runtime/stx.ss")
(define-struct named-bitmap (name bitmap))
;; Image lifting
(provide/contract [struct named-bitmap [(name string?)
(bitmap (is-a?/c bitmap%))]]
[named-bitmap->resource (named-bitmap? . -> . (is-a?/c resource<%>))]
[named-bitmap-save (named-bitmap? path-string? . -> . any)]
[lift-images! ((is-a?/c text%)
. -> . (listof named-bitmap?))]
[lift-images/stx (stx? . -> . (values stx? (listof named-bitmap?)))]
[lift-images/stxs ((listof stx?) . -> . (values (listof stx?) (listof named-bitmap?)))])
(define named-bitmap-resource%
(class* object% (resource<%>)
(init-field named-bitmap)
(super-new)
(define/public (save! a-path)
(named-bitmap-save named-bitmap a-path))
(define/public (get-name)
(named-bitmap-name named-bitmap))
(define/public (get-bytes)
(with-temporary-directory
(lambda (a-dir)
(save! a-dir)
(call-with-input-file (build-path a-dir (get-name))
(lambda (ip)
(port->bytes ip))))))))
;; Turns a named bitmap into a resource.
(define (named-bitmap->resource a-named-bitmap)
(new named-bitmap-resource% [named-bitmap a-named-bitmap]))
;; lift-images!: text -> (listof named-bitmap)
;; Lifts up the image snips in the text.
;; The snips in the text will be replaced with the expression (open-image-url <path>)
;; where path refers to the file name of the named bitmap.
;; Mutates the text, and produces a list of bitmap objects that should be saved.
(define (lift-images! a-text)
(let loop ([a-snip (send a-text find-first-snip)])
(cond
[(not a-snip)
empty]
[(image-snip? a-snip)
(let* ([file-name (make-image-name)]
[bitmap (send a-snip get-bitmap)]
[replacement-snip (make-object string-snip%
(format "(open-image-url ~s)"
file-name))])
(send a-text set-position
(send a-text get-snip-position a-snip)
(+ (send a-text get-snip-position a-snip)
(send a-snip get-count)))
(send a-text insert replacement-snip)
(cons (make-named-bitmap file-name bitmap)
(loop (send replacement-snip next))))]
[else
(loop (send a-snip next))])))
;; lift-images/stx: stx -> (values stx (listof named-bitmap))
;; Lift out the image snips in an stx.
(define (lift-images/stx a-stx)
(cond
[(stx:list? a-stx)
(let-values ([(lifted-elts named-bitmaps)
(lift-images/stxs (stx-e a-stx))])
(values (datum->stx #f lifted-elts (stx-loc a-stx))
named-bitmaps))]
[(stx:atom? a-stx)
(cond [(image-snip? (stx-e a-stx))
(let* ([filename (make-image-name)]
[bitmap (send (stx-e a-stx) get-bitmap)]
[replacement-stx (datum->stx #f `(open-image-url ,filename)
(stx-loc a-stx))])
(values replacement-stx (list (make-named-bitmap filename bitmap))))]
[else
(values a-stx empty)])]))
;; lift-images/stxs: (listof stx) -> (values (listof stx) (listof named-bitmap))
(define (lift-images/stxs stxs)
(cond
[(empty? stxs)
(values empty empty)]
[else
(let-values ([(lifted-stx named-bitmaps)
(lift-images/stx (first stxs))]
[(rest-lifted-stxs rest-named-bitmaps)
(lift-images/stxs (rest stxs))])
(values (cons lifted-stx rest-lifted-stxs)
(append named-bitmaps rest-named-bitmaps)))]))
;; named-bitmap-save: named-bitmap path-string -> void
;; Saves the named bitmap under the given directory.
(define (named-bitmap-save a-named-bitmap a-dir)
(let ([a-path
(build-path a-dir (named-bitmap-name a-named-bitmap))])
(send (named-bitmap-bitmap a-named-bitmap) save-file (path->string a-path)
'png)))
;; make-image-name: -> string
;; Makes a new image name.
(define make-image-name
(let ([i 0])
(lambda ()
(begin0 (string-append "image-" (number->string i) ".png")
(set! i (add1 i))))))
;; image-snip?: snip -> boolean
;; Returns true if this looks like an image snip.
(define (image-snip? a-snip)
(or (is-a? a-snip image-snip%)
(is-a? a-snip cache-image-snip%)))