diff options
author | William Wilgus <me.theuser@yahoo.com> | 2018-09-23 18:25:31 +0200 |
---|---|---|
committer | William Wilgus <me.theuser@yahoo.com> | 2018-10-09 01:02:25 +0200 |
commit | c0682e094414d0748456d0b01000727039ff701c (patch) | |
tree | 2cc08bfdfe967bbe18fade1ed835d54a3f91cd23 /apps/plugins/lua/include_lua/image.lua | |
parent | e4b843335bc34810c11ed405d473e6f7c94a153f (diff) | |
download | rockbox-c0682e094414d0748456d0b01000727039ff701c.tar.gz rockbox-c0682e094414d0748456d0b01000727039ff701c.zip |
Clean up rocklib_img
optimize both size and speed
fix invert for color screens
Change-Id: I7edecae32dcb3daf5b3ed984a0e5b3d463269e60
Diffstat (limited to 'apps/plugins/lua/include_lua/image.lua')
-rw-r--r-- | apps/plugins/lua/include_lua/image.lua | 117 |
1 files changed, 51 insertions, 66 deletions
diff --git a/apps/plugins/lua/include_lua/image.lua b/apps/plugins/lua/include_lua/image.lua index c8d7aad9dd..2b2a1ce19f 100644 --- a/apps/plugins/lua/include_lua/image.lua +++ b/apps/plugins/lua/include_lua/image.lua | |||
@@ -65,35 +65,43 @@ if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end | |||
65 | 65 | ||
66 | local _img = {} do | 66 | local _img = {} do |
67 | 67 | ||
68 | local rocklib_image = getmetatable(rb.lcd_framebuffer()) | ||
69 | setmetatable(_img, rocklib_image) | ||
70 | |||
68 | -- internal constants | 71 | -- internal constants |
69 | local _NIL = nil -- _NIL placeholder | 72 | local _NIL = nil -- _NIL placeholder |
70 | local _math = require("math_ex") -- math functions needed | 73 | local _math = require("math_ex") -- math functions needed |
71 | local LCD_W, LCD_H = rb.LCD_WIDTH, rb.LCD_HEIGHT | 74 | local LCD_W, LCD_H = rb.LCD_WIDTH, rb.LCD_HEIGHT |
72 | 75 | ||
76 | local _copy = rocklib_image.copy | ||
77 | local _get = rocklib_image.get | ||
78 | local _marshal = rocklib_image.marshal | ||
79 | local _points = rocklib_image.points | ||
80 | |||
73 | -- returns new image -of- img sized to fit w/h tiling to fit if needed | 81 | -- returns new image -of- img sized to fit w/h tiling to fit if needed |
74 | local function tile(img, w, h) | 82 | _img.tile = function(img, w, h) |
75 | local hs , ws = img:height(), img:width() | 83 | local hs , ws = img:height(), img:width() |
76 | local t_img = rb.new_image(w, h) | 84 | local t_img = rb.new_image(w, h) |
77 | 85 | ||
78 | for x = 1, w, ws do t_img:copy(img, x, 1, 1, 1) end | 86 | for x = 1, w, ws do _copy(t_img, img, x, 1, 1, 1) end |
79 | for y = hs, h, hs do t_img:copy(t_img, 1, y, 1, 1, w, hs) end | 87 | for y = hs, h, hs do _copy(t_img, t_img, 1, y, 1, 1, w, hs) end |
80 | return t_img | 88 | return t_img |
81 | end | 89 | end |
82 | 90 | ||
83 | -- resizes src to size of dst | 91 | -- resizes src to size of dst |
84 | local function resize(dst, src) | 92 | _img.resize = function(dst, src) |
85 | -- simple nearest neighbor resize derived from rockbox - pluginlib_bmp.c | 93 | -- simple nearest neighbor resize derived from rockbox - pluginlib_bmp.c |
86 | -- pretty rough results highly recommend building one more suited.. | 94 | -- pretty rough results highly recommend building one more suited.. |
87 | local dw, dh = dst:width(), dst:height() | 95 | local dw, dh = dst:width(), dst:height() |
88 | 96 | ||
89 | local xstep = (bit.lshift(src:width(),8) / (dw)) + 1 | 97 | local xstep = (bit.lshift(src:width(), 8) / (dw)) + 1 |
90 | local ystep = (bit.lshift(src:height(),8) / (dh)) | 98 | local ystep = (bit.lshift(src:height(), 8) / (dh)) |
91 | 99 | ||
92 | local xpos, ypos = 0, 0 | 100 | local xpos, ypos = 0, 0 |
93 | local src_x, src_y | 101 | local src_x, src_y |
94 | 102 | ||
95 | -- walk the dest get src pixel | 103 | -- walk the dest get src pixel |
96 | function rsz_trans(val, x, y) | 104 | local function rsz_trans(val, x, y) |
97 | if x == 1 then | 105 | if x == 1 then |
98 | src_y = bit.rshift(ypos,8) + 1 | 106 | src_y = bit.rshift(ypos,8) + 1 |
99 | xpos = xstep - bit.rshift(xstep,4) + 1 | 107 | xpos = xstep - bit.rshift(xstep,4) + 1 |
@@ -101,14 +109,14 @@ local _img = {} do | |||
101 | end | 109 | end |
102 | src_x = bit.rshift(xpos,8) + 1 | 110 | src_x = bit.rshift(xpos,8) + 1 |
103 | xpos = xpos + xstep | 111 | xpos = xpos + xstep |
104 | return (src:get(src_x, src_y, true) or 0) | 112 | return (_get(src, src_x, src_y, true) or 0) |
105 | end | 113 | end |
106 | --/* (dst*, [x1, y1, x2, y2, dx, dy, clip, function]) */ | 114 | --/* (dst*, [x1, y1, x2, y2, dx, dy, clip, function]) */ |
107 | dst:marshal(1, 1, dw, dh, _NIL, _NIL, false, rsz_trans) | 115 | _marshal(dst, 1, 1, dw, dh, _NIL, _NIL, false, rsz_trans) |
108 | end | 116 | end |
109 | 117 | ||
110 | -- returns new image -of- img rotated in whole degrees 0 - 360 | 118 | -- returns new image -of- img rotated in whole degrees 0 - 360 |
111 | local function rotate(img, degrees) | 119 | _img.rotate = function(img, degrees) |
112 | -- we do this backwards as if dest was the unrotated object | 120 | -- we do this backwards as if dest was the unrotated object |
113 | degrees = 360 - degrees | 121 | degrees = 360 - degrees |
114 | local c, s = _math.d_cos(degrees), _math.d_sin(degrees) | 122 | local c, s = _math.d_cos(degrees), _math.d_sin(degrees) |
@@ -133,7 +141,7 @@ local _img = {} do | |||
133 | |_____| |_______| |_______| ]] | 141 | |_____| |_______| |_______| ]] |
134 | 142 | ||
135 | -- walk the dest get translated src pixel, oversamples src to fill gaps | 143 | -- walk the dest get translated src pixel, oversamples src to fill gaps |
136 | function rot_trans(val, x, y) | 144 | local function rot_trans(val, x, y) |
137 | -- move center x/y to the origin | 145 | -- move center x/y to the origin |
138 | local xtran = x - d_xctr; | 146 | local xtran = x - d_xctr; |
139 | local ytran = y - d_yctr; | 147 | local ytran = y - d_yctr; |
@@ -142,68 +150,56 @@ local _img = {} do | |||
142 | local yrot = ((xtran * s) + (ytran * c)) / 10000 + s_yctr | 150 | local yrot = ((xtran * s) + (ytran * c)) / 10000 + s_yctr |
143 | local xrot = ((xtran * c) - (ytran * s)) / 10000 + s_xctr | 151 | local xrot = ((xtran * c) - (ytran * s)) / 10000 + s_xctr |
144 | -- upper left of src image back to origin, copy src pixel | 152 | -- upper left of src image back to origin, copy src pixel |
145 | return img:get(xrot, yrot, true) or 0 | 153 | return _get(img, xrot, yrot, true) or 0 |
146 | end | 154 | end |
147 | r_img:marshal(1, 1, dw, dh, _NIL, _NIL, false, rot_trans) | 155 | _marshal(r_img, 1, 1, dw, dh, _NIL, _NIL, false, rot_trans) |
148 | return r_img | 156 | return r_img |
149 | end | 157 | end |
150 | 158 | ||
151 | -- saves img to file: name | 159 | -- saves img to file: name |
152 | local function save(img, name) | 160 | _img.save = function(img, name) |
153 | -- bmp saving derived from rockbox - screendump.c | 161 | -- bmp saving derived from rockbox - screendump.c |
154 | -- bitdepth is limited by the device | 162 | -- bitdepth is limited by the device |
155 | -- eg. device displays greyscale, rgb images are saved greyscale | 163 | -- eg. device displays greyscale, rgb images are saved greyscale |
156 | local file | 164 | local file |
157 | 165 | local bbuffer = {} -- concat buffer for s_bytes | |
158 | local fbuffer = {} -- concat buffer for file writes, reused | 166 | local fbuffer = {} -- concat buffer for file writes, reused |
159 | 167 | ||
160 | local function dump_fbuffer(thresh) | ||
161 | if #fbuffer >= thresh then | ||
162 | file:write(table.concat(fbuffer)) | ||
163 | for i=1, #fbuffer do fbuffer[i] = _NIL end -- reuse table | ||
164 | end | ||
165 | end | ||
166 | |||
167 | local function s_bytesLE(bits, value) | 168 | local function s_bytesLE(bits, value) |
168 | -- bits must be multiples of 8 (sizeof byte) | 169 | -- bits must be multiples of 8 (sizeof byte) |
169 | local byte | 170 | local byte |
170 | local result = "" | 171 | local nbytes = bit.rshift(bits, 3) |
171 | for b = 1, bit.rshift(bits, 3) do | 172 | for b = 1, nbytes do |
172 | if value > 0 then | 173 | if value > 0 then |
173 | byte = value % 256 | 174 | byte = value % 256 |
174 | value = (value - byte) / 256 | 175 | value = (value - byte) / 256 |
175 | result = result .. string.char(byte) | ||
176 | else | 176 | else |
177 | result = result .. string.char(0) | 177 | byte = 0 |
178 | end | 178 | end |
179 | bbuffer[b] = string.char(byte) | ||
179 | end | 180 | end |
180 | return result | 181 | return table.concat(bbuffer, _NIL, 1, nbytes) |
181 | end | 182 | end |
182 | 183 | ||
183 | local function s_bytesBE(bits, value) | 184 | local function s_bytesBE(bits, value) |
184 | -- bits must be multiples of 8 (sizeof byte) | 185 | -- bits must be multiples of 8 (sizeof byte) |
185 | local byte | 186 | local byte |
186 | local result = "" | 187 | local nbytes = bit.rshift(bits, 3) |
187 | for b = 1, bit.rshift(bits, 3) do | 188 | for b = nbytes, 1, -1 do |
188 | if value > 0 then | 189 | if value > 0 then |
189 | byte = value % 256 | 190 | byte = value % 256 |
190 | value = (value - byte) / 256 | 191 | value = (value - byte) / 256 |
191 | result = string.char(byte) .. result | ||
192 | else | 192 | else |
193 | result = string.char(0) .. result | 193 | byte = 0 |
194 | end | 194 | end |
195 | bbuffer[b] = string.char(byte) | ||
195 | end | 196 | end |
196 | return result | 197 | return table.concat(bbuffer, _NIL, 1, nbytes) |
197 | end | ||
198 | |||
199 | local function c_cmp(color, shift) | ||
200 | -- [RR][GG][BB] | ||
201 | return bit.band(bit.rshift(color, shift), 0xFF) | ||
202 | end | 198 | end |
203 | 199 | ||
204 | local cmp = {["r"] = function(c) return c_cmp(c, 16) end, | 200 | local cmp = {["r"] = function(c) return bit.band(bit.rshift(c, 16), 0xFF) end, |
205 | ["g"] = function(c) return c_cmp(c, 08) end, | 201 | ["g"] = function(c) return bit.band(bit.rshift(c, 08), 0xFF) end, |
206 | ["b"] = function(c) return c_cmp(c, 00) end} | 202 | ["b"] = function(c) return bit.band(c, 0xFF) end} |
207 | 203 | ||
208 | local function bmp_color(color) | 204 | local function bmp_color(color) |
209 | return s_bytesLE(8, cmp.b(color)).. | 205 | return s_bytesLE(8, cmp.b(color)).. |
@@ -314,7 +310,8 @@ local _img = {} do | |||
314 | end | 310 | end |
315 | end | 311 | end |
316 | 312 | ||
317 | dump_fbuffer(0) -- write the header to the file now | 313 | file:write(table.concat(fbuffer))-- write the header to the file now |
314 | for i=1, #fbuffer do fbuffer[i] = _NIL end -- reuse table | ||
318 | 315 | ||
319 | local imgdata = fbuffer | 316 | local imgdata = fbuffer |
320 | -- pad rows to a multiple of 4 bytes | 317 | -- pad rows to a multiple of 4 bytes |
@@ -327,18 +324,23 @@ local _img = {} do | |||
327 | end | 324 | end |
328 | 325 | ||
329 | -- Bitmap lines start at bottom unless biHeight is negative | 326 | -- Bitmap lines start at bottom unless biHeight is negative |
330 | for point in img:points(1, h, w + bytesleft, 1) do | 327 | for point in _points(img, 1, h, w + bytesleft, 1) do |
331 | imgdata[#imgdata + 1] = fs_bytes_E(bpp, point or 0) | 328 | imgdata[#imgdata + 1] = fs_bytes_E(bpp, point or 0) |
332 | dump_fbuffer(31) -- buffered write, increase # for performance | ||
333 | end | ||
334 | 329 | ||
335 | dump_fbuffer(0) --write leftovers to file | 330 | if #fbuffer >= 31 then -- buffered write, increase # for performance |
331 | file:write(table.concat(fbuffer)) | ||
332 | for i=1, #fbuffer do fbuffer[i] = _NIL end -- reuse table | ||
333 | end | ||
334 | |||
335 | end | ||
336 | file:write(table.concat(fbuffer)) --write leftovers to file | ||
337 | fbuffer = _NIL | ||
336 | 338 | ||
337 | file:close() | 339 | file:close() |
338 | end -- save(img, name) | 340 | end -- save(img, name) |
339 | 341 | ||
340 | --searches an image for target color | 342 | --searches an image for target color |
341 | local function search(img, x1, y1, x2, y2, targetclr, variation, stepx, stepy) | 343 | _img.search = function(img, x1, y1, x2, y2, targetclr, variation, stepx, stepy) |
342 | 344 | ||
343 | if variation > 128 then variation = 128 end | 345 | if variation > 128 then variation = 128 end |
344 | if variation < -128 then variation = -128 end | 346 | if variation < -128 then variation = -128 end |
@@ -352,7 +354,7 @@ local _img = {} do | |||
352 | targetl = swap | 354 | targetl = swap |
353 | end | 355 | end |
354 | 356 | ||
355 | for point, x, y in img:points(x1, y1, x2, y2, stepx, stepy) do | 357 | for point, x, y in _points(img, x1, y1, x2, y2, stepx, stepy) do |
356 | if point >= targetl and point <= targeth then | 358 | if point >= targetl and point <= targeth then |
357 | return point, x, y | 359 | return point, x, y |
358 | end | 360 | end |
@@ -362,12 +364,12 @@ local _img = {} do | |||
362 | 364 | ||
363 | --[[ we won't be extending these into RLI_IMAGE]] | 365 | --[[ we won't be extending these into RLI_IMAGE]] |
364 | -- creates a new rbimage size w x h | 366 | -- creates a new rbimage size w x h |
365 | local function new(w, h) | 367 | _img.new = function(w, h) |
366 | return rb.new_image(w, h) | 368 | return rb.new_image(w, h) |
367 | end | 369 | end |
368 | 370 | ||
369 | -- returns new image -of- file: name (_NIL if error) | 371 | -- returns new image -of- file: name (_NIL if error) |
370 | local function load(name) | 372 | _img.load = function(name) |
371 | return rb.read_bmp_file("/" .. name) | 373 | return rb.read_bmp_file("/" .. name) |
372 | end | 374 | end |
373 | 375 | ||
@@ -381,23 +383,6 @@ local _img = {} do | |||
381 | _img.RLI_INFO_DEPTH = 0x6 | 383 | _img.RLI_INFO_DEPTH = 0x6 |
382 | _img.RLI_INFO_FORMAT = 0x7 | 384 | _img.RLI_INFO_FORMAT = 0x7 |
383 | _img.RLI_INFO_ADDRESS = 0x8 | 385 | _img.RLI_INFO_ADDRESS = 0x8 |
384 | |||
385 | -- expose functions to the outside through _img table | ||
386 | _img.save = save | ||
387 | _img.search = search | ||
388 | _img.rotate = rotate | ||
389 | _img.resize = resize | ||
390 | _img.tile = tile | ||
391 | |||
392 | -- adds the above _img functions into the metatable for RLI_IMAGE | ||
393 | local ex = getmetatable(rb.lcd_framebuffer()) | ||
394 | for k, v in pairs(_img) do | ||
395 | if ex[k] == _NIL then ex[k] = v end | ||
396 | end | ||
397 | -- not exposed through RLI_IMAGE | ||
398 | _img.new = new | ||
399 | _img.load = load | ||
400 | |||
401 | end -- _img functions | 386 | end -- _img functions |
402 | 387 | ||
403 | return _img | 388 | return _img |