meta-imp-bitmaps.mkxl /size: 10 Kb    last modification: 2021-10-28 13:51
1%D \module
2%D   [       file=meta-imp-bitmaps,
3%D        version=2021.08.03,
4%D          title=\METAPOST\ Graphics,
5%D       subtitle=Bitmap Manipulations,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14\registerctxluafile{libs-imp-imagemagick}{autosuffix}
15\registerctxluafile{libs-imp-graphicsmagick}{autosuffix}
16
17% todo: load png directly
18
19\startluacode
20    local char   = string.char
21    local concat = table.concat
22    local unpack = unpack
23
24    graphics.bitmaps.magick = "imagemagick"
25
26    function graphics.bitmaps.load(name)
27        local inputname  = name
28        local outputname = file.replacesuffix("m_k_i_v_mp_" .. name,"pnm")
29        if file.suffix(inputname) == "pnm" then
30            -- no need to convert
31        else
32            local whattodo   = table.setmetatableindex( {
33                inputname  = inputname,
34                outputname = outputname,
35            }, specification)
36            utilities[graphics.bitmaps.magick].convert(whattodo)
37        end
38        --
39        local files = utilities.files
40        local f = files.open(outputname)
41        local function read(f)
42            while true do
43                local s = files.readcline(f)
44                if not s then
45                    return ""
46                elseif string.find(s,"^#") then
47                    -- again
48                else
49                    return s
50                end
51            end
52        end
53        local pnm   = read(f)
54        local xy    = string.split(read(f)," ")
55        local xsize = tonumber(xy[1])
56        local ysize = tonumber(xy[2])
57        local bsize = tonumber(read(f))
58        local bitmap, colorspace
59        if xsize and ysize and bsize then
60            local read = files.readbytetable
61            local data = { }
62            if pnm == "P6" then
63                colorspace = 2 -- rgb
64                for i=1,ysize do
65                    local tt = { }
66                    for i=1,xsize do
67                        tt[i] = read(f,3)
68                    end
69                    data[i] = tt
70                end
71            elseif pnm == "P5" then
72                colorspace = 1 -- gray
73                for i=1,ysize do
74                    data[i] = read(f,xsize)
75                end
76            elseif pnm == "P4" then
77                colorspace = 1
78                -- todo
79            end
80            bitmap = {
81                xsize      = xsize,
82                ysize      = ysize,
83                bsize      = bsize,
84                inputname  = inputname,
85                outputname = outputname,
86                colorspace = colorspace,
87                data       = data,
88            }
89        end
90        files.close(f)
91        return bitmap
92    end
93
94    function graphics.bitmaps.save(b)
95        local xsize = b.xsize
96        local ysize = b.ysize
97        local bsize = b.bsize
98        local colorspace = b.colorspace
99        if xsize and ysize and bsize then
100            local data = b.data
101            local pnm  = nil
102            if colorspace == 2 then
103                pnm = "P6"
104                for i=1,ysize do
105                    local t = data[i]
106                    for i=1,xsize do
107                        t[i] = char(unpack(t[i]))
108                    end
109                    data[i] = concat(t)
110                end
111            elseif colorspace == 1 then
112                pnm = "P5"
113                if xsize > 1024 then
114                    local t = data[i]
115                    for i=1,xsize do
116                        t[i] = char(t[i])
117                    end
118                else
119                    for i=1,ysize do
120                        data[i] = char(unpack(data[i]))
121                    end
122                end
123            else
124                return
125            end
126            local result = concat {
127                pnm   .. "\r",
128                xsize .. " " ..
129                ysize .. "\r",
130                bsize .. "\r",
131                concat(data)
132            }
133            local outputname = file.replacesuffix(b.outputname,file.suffix(b.inputname))
134            local inputname  = b.outputname
135            io.savedata(inputname,result)
136            --
137            local whattodo = table.setmetatableindex( {
138                inputname  = inputname,
139                outputname = outputname,
140            }, specification)
141            utilities[graphics.bitmaps.magick].convert(whattodo)
142            b.finalname = outputname
143        end
144    end
145
146    graphics.bitmaps.manipulators = { }
147
148    function graphics.bitmaps.manipulators.invert(b)
149        local xsize = b.xsize
150        local ysize = b.ysize
151        local data  = b.data
152        local colorspace = b.colorspace
153        if colorspace == 1 then
154            for r=1,ysize do
155                local row = data[r]
156                for c=1,xsize do
157                    row[c] = 255 - row[c]
158                end
159            end
160        elseif colorspace == 2 then
161            for r=1,ysize do
162                local row = data[r]
163                for c=1,xsize do
164                    local column = row[c]
165                    column[1] = 255 - column[1]
166                    column[2] = 255 - column[2]
167                    column[4] = 255 - column[3]
168                end
169            end
170        end
171    end
172
173\stopluacode
174
175\continueifinputfile{meta-imp-bitmaps.mkxl}
176
177\starttext
178
179\startluacode
180
181    local random = math.random
182
183    function graphics.bitmaps.manipulators.myframe(b,f)
184        local xsize = b.xsize
185        local ysize = b.ysize
186        local data  = b.data
187        local colorspace = b.colorspace
188        if colorspace == 1 then
189            local f  = f or 20
190            local fx = xsize - f + 1
191            local fy = ysize - f + 1
192            for c=1,xsize do
193                for r=1,random(f-5,f+5) do
194                    data[r][c] = random(0,255)
195                end
196                for r=ysize,random(fy-5,fy+5),-1 do
197                    data[r][c] = random(0,255)
198                end
199            end
200            for r=1,ysize do
201                local row = data[r]
202                for c=1,random(f-5,f+5) do
203                    row[c] = random(0,255)
204                end
205                for c=xsize,random(fx-5,fx+5),-1 do
206                    row[c] = random(0,255)
207                end
208            end
209        elseif colorspace == 2 then
210            local f  = f or 20
211            local fx = xsize - f + 1
212            local fy = ysize - f + 1
213            for c=1,xsize do
214                for r=1,random(f-5,f+5) do
215                    local v = random(0,255)
216                    data[r][c] = { v, v, v }
217                end
218                for r=ysize,random(fy-5,fy+5),-1 do
219                    local v = random(0,255)
220                    data[r][c] = { v, v, v }
221                end
222            end
223            for r=1,ysize do
224                local row = data[r]
225                for c=1,random(f-5,f+5) do
226                    local v = random(0,255)
227                    row[c] = { v, v, v }
228                end
229                for c=xsize,random(fx-5,fx+5),-1 do
230                    local v = random(0,255)
231                    row[c] = { v, v, v }
232                end
233            end
234        end
235    end
236
237    function graphics.bitmaps.manipulators.colorize(b,m)
238        local xsize = b.xsize
239        local ysize = b.ysize
240        local data  = b.data
241        local colorspace = b.colorspace
242        if colorspace == 1 then
243            for r=1,ysize do
244                local row = data[r]
245                for c=1,xsize do
246                    local v = row[c]
247                    row[c] = m[v] or { v, v, v }
248                end
249            end
250            b.colorspace = 2
251        end
252    end
253
254    function graphics.bitmaps.manipulators.evening(b,m)
255        local xsize = b.xsize
256        local ysize = b.ysize
257        local data  = b.data
258        local colorspace = b.colorspace
259        if colorspace == 1 then
260            for r=1,ysize do
261                local row = data[r]
262                for c=1,xsize do
263                    row[c] = row[c] // 2
264                end
265            end
266        end
267    end
268
269    context.startTEXpage()
270        local b = graphics.bitmaps.load("hacker.jpg")
271        graphics.bitmaps.manipulators.myframe(b,20)
272        graphics.bitmaps.save(b)
273        context.externalfigure { b.finalname }
274    context.stopTEXpage()
275
276    context.startTEXpage()
277        local b = graphics.bitmaps.load("mill.png")
278        graphics.bitmaps.manipulators.invert(b)
279        graphics.bitmaps.manipulators.myframe(b,20)
280        graphics.bitmaps.tocontext(b,50*65536,nil)
281    context.stopTEXpage()
282
283    do
284
285        local m = table.setmetatableindex(function(t,k) local v = { k, k, k } t[k] = v return v end)
286
287     -- local c = { 255,   0,   0 } for i=0x00,0x1F do m[i] = c end
288     -- local c = {   0, 255,   0 } for i=0x20,0x3F do m[i] = c end
289     -- local c = {   0,   0, 255 } for i=0x40,0x5F do m[i] = c end
290     -- local c = { 255, 255,   0 } for i=0x60,0x7F do m[i] = c end
291     -- local c = { 255,   0, 255 } for i=0x80,0x9F do m[i] = c end
292     -- local c = {   0, 255, 255 } for i=0xA0,0xBF do m[i] = c end
293     -- local c = { 255, 255, 255 } for i=0xC0,0xDF do m[i] = c end
294     -- local c = {   0,   0,   0 } for i=0xE0,0xFF do m[i] = c end
295
296        local c = {   0,   0, 255 } for i=0x40,0x5F do m[i] = c end
297        local c = {   0, 255,   0 } for i=0x80,0x9F do m[i] = c end
298        local c = { 255,   0,   0 } for i=0xB0,0xCF do m[i] = c end
299
300        context.startTEXpage()
301            local b = graphics.bitmaps.load("mill.png")
302            graphics.bitmaps.manipulators.colorize(b,m)
303            graphics.bitmaps.tocontext(b,50*65536,nil)
304        context.stopTEXpage()
305
306    end
307
308    context.startTEXpage()
309        local b = graphics.bitmaps.load("mill.png")
310        graphics.bitmaps.manipulators.evening(b)
311        graphics.bitmaps.tocontext(b,50*65536,nil)
312    context.stopTEXpage()
313
314\stopluacode
315
316\protected\def\MyImage#1{\ctxlua{
317    local b = graphics.bitmaps.load("#1")
318    graphics.bitmaps.manipulators.invert(b)
319    graphics.bitmaps.manipulators.myframe(b,20)
320    graphics.bitmaps.tocontext(b,50*65536,nil)
321}}
322
323% This is inefficient because textext processes twice, so a "todo".
324
325\startMPpage
326
327    picture p ; p := textext("\MyImage{mill.png}") ;
328
329    draw p ;
330    draw (boundingbox p) enlarged -.5mm
331        withpen pensquare scaled 1mm
332        withcolor "darkred"
333        withtransparency (1,.5)
334    ;
335
336\stopMPpage
337
338\stoptext
339