rockbox/apps/plugins/lua/include_lua/image.lua
William Wilgus f85df30e3e lua add rlimg.lua example script split large includes to separate files
Change-Id: I67cac5bc4ce5525ab30abf9443f6cc1a33190512
2019-08-04 16:57:02 +02:00

205 lines
7.3 KiB
Lua

--[[ Lua Image functions
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2017 William Wilgus
*
* This program 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 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
]]
--[[ Exposed Functions
_img.search
_img.rotate
_img.resize
_img.tile
_img.new
_img.load
-- Exposed Constants
_img.RLI_INFO_ALL
_img.RLI_INFO_TYPE
_img.RLI_INFO_WIDTH
_img.RLI_INFO_HEIGHT
_img.RLI_INFO_ELEMS
_img.RLI_INFO_BYTES
_img.RLI_INFO_DEPTH
_img.RLI_INFO_FORMAT
_img.RLI_INFO_ADDRESS
]]
--[[Other rbimage Functions:
--------------------------------------------------------------------------------
img:_len() or #img -- returns number of pixels in image
img:__tostring([item]) or tostring(img) -- returns data about the image item = 0
is the same as tostring(img) otherwise
item = 1 is the first item in list
item = 7 is the 7th item
item = 8 is the data address in hex
-- See Constants _img.RLI_INFO_....
img:_data(element) -- returns/sets raw pixel data
NOTE!! this data is defined by the target and targets with
different color depth, bit packing, etc will not be
compatible with the same image's data on another target
]]
--------------------------------------------------------------------------------
if not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end
local _img = {} do
local rocklib_image = getmetatable(rb.lcd_framebuffer())
setmetatable(_img, rocklib_image)
-- internal constants
local _NIL = nil -- _NIL placeholder
local _math = require("math_ex") -- math functions needed
local LCD_W, LCD_H = rb.LCD_WIDTH, rb.LCD_HEIGHT
local _copy = rocklib_image.copy
local _get = rocklib_image.get
local _marshal = rocklib_image.marshal
local _points = rocklib_image.points
-- returns new image -of- img sized to fit w/h tiling to fit if needed
_img.tile = function(img, w, h)
local hs , ws = img:height(), img:width()
local t_img = rb.new_image(w, h)
for x = 1, w, ws do _copy(t_img, img, x, 1, 1, 1) end
for y = hs, h, hs do _copy(t_img, t_img, 1, y, 1, 1, w, hs) end
return t_img
end
-- resizes src to size of dst
_img.resize = function(dst, src)
-- simple nearest neighbor resize derived from rockbox - pluginlib_bmp.c
-- pretty rough results highly recommend building one more suited..
local dw, dh = dst:width(), dst:height()
local xstep = (bit.lshift(src:width(), 8) / (dw)) + 1
local ystep = (bit.lshift(src:height(), 8) / (dh))
local xpos, ypos = 0, 0
local src_x, src_y
-- walk the dest get src pixel
local function rsz_trans(val, x, y)
if x == 1 then
src_y = bit.rshift(ypos,8) + 1
xpos = xstep - bit.rshift(xstep,4) + 1
ypos = ypos + ystep;
end
src_x = bit.rshift(xpos,8) + 1
xpos = xpos + xstep
return (_get(src, src_x, src_y, true) or 0)
end
--/* (dst*, [x1, y1, x2, y2, dx, dy, clip, function]) */
_marshal(dst, 1, 1, dw, dh, _NIL, _NIL, false, rsz_trans)
end
-- returns new image -of- img rotated in whole degrees 0 - 360
_img.rotate = function(img, degrees)
-- we do this backwards as if dest was the unrotated object
degrees = 360 - degrees
local c, s = _math.d_cos(degrees), _math.d_sin(degrees)
-- get the center of the source image
local s_xctr, s_yctr = img:width() / 2, img:height() / 2
-- get the the new center of the dest image at rotation angle
local d_xctr = ((math.abs(s_xctr * c) + math.abs(s_yctr * s))/ 10000) + 1
local d_yctr = ((math.abs(s_xctr * s) + math.abs(s_yctr * c))/ 10000) + 1
-- calculate size of rect new image will occupy
local dw, dh = d_xctr * 2 - 1, d_yctr * 2 - 1
local r_img = rb.new_image(dw, dh)
-- r_img:clear() -- doesn't need cleared as we walk every pixel
--[[rotation works on origin of 0,0 we need to offset to the center of the
image and then place the upper left back at the origin (0, 0)]]
--[[0,0|-----| ^< |-------| v> 0,0|-------|
| | | 0,0 | | |
|_____| |_______| |_______| ]]
-- walk the dest get translated src pixel, oversamples src to fill gaps
local function rot_trans(val, x, y)
-- move center x/y to the origin
local xtran = x - d_xctr;
local ytran = y - d_yctr;
-- rotate about the center of the image by x degrees
local yrot = ((xtran * s) + (ytran * c)) / 10000 + s_yctr
local xrot = ((xtran * c) - (ytran * s)) / 10000 + s_xctr
-- upper left of src image back to origin, copy src pixel
return _get(img, xrot, yrot, true) or 0
end
_marshal(r_img, 1, 1, dw, dh, _NIL, _NIL, false, rot_trans)
return r_img
end
--searches an image for target color
_img.search = function(img, x1, y1, x2, y2, targetclr, variation, stepx, stepy)
if variation > 128 then variation = 128 end
if variation < -128 then variation = -128 end
local targeth = targetclr + variation
local targetl = targetclr - variation
if targeth < targetl then
local swap = targeth
targeth = targetl
targetl = swap
end
for point, x, y in _points(img, x1, y1, x2, y2, stepx, stepy) do
if point >= targetl and point <= targeth then
return point, x, y
end
end
return nil, nil, nil
end
--[[ we won't be extending these into RLI_IMAGE]]
-- creates a new rbimage size w x h
_img.new = function(w, h)
return rb.new_image(w, h)
end
-- returns new image -of- file: name (_NIL if error)
_img.load = function(name)
return rb.read_bmp_file("/" .. name)
end
-- expose tostring constants to outside through _img table
_img.RLI_INFO_ALL = 0x0
_img.RLI_INFO_TYPE = 0x1
_img.RLI_INFO_WIDTH = 0x2
_img.RLI_INFO_HEIGHT = 0x3
_img.RLI_INFO_ELEMS = 0x4
_img.RLI_INFO_BYTES = 0x5
_img.RLI_INFO_DEPTH = 0x6
_img.RLI_INFO_FORMAT = 0x7
_img.RLI_INFO_ADDRESS = 0x8
end -- _img functions
return _img