Something went wrong. Try again.
A modern, network-enabled music player platform built on Rockbox technology. rockboxd.tsiry-sandratraina.com
rust deno navidrome airplay libadwaita zig mpris snapcast mpd rockbox audio subsonic
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216--[[ Lua Image save/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * * 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. * ****************************************************************************/]]-- save(img, path/name)-- bmp saving derived from rockbox - screendump.c-- bitdepth is limited by the device-- eg. device displays greyscale, rgb images are saved greyscaleif not rb.lcd_framebuffer then rb.splash(rb.HZ, "No Support!") return nil end
do local rocklib_image = getmetatable(rb.lcd_framebuffer())
-- internal constants local _NIL = nil -- _NIL placeholder local _points = rocklib_image.points
-- saves img to file: name return function(img, name) local file local bbuffer = {} -- concat buffer for s_bytes local fbuffer = {} -- concat buffer for file writes, reused
local function s_bytesLE(bits, value) -- bits must be multiples of 8 (sizeof byte) local byte local nbytes = bit.rshift(bits, 3) for b = 1, nbytes do if value > 0 then byte = value % 256 value = (value - byte) / 256 else byte = 0 end bbuffer[b] = string.char(byte) end return table.concat(bbuffer, _NIL, 1, nbytes) end
local function s_bytesBE(bits, value) -- bits must be multiples of 8 (sizeof byte) local byte local nbytes = bit.rshift(bits, 3) for b = nbytes, 1, -1 do if value > 0 then byte = value % 256 value = (value - byte) / 256 else byte = 0 end bbuffer[b] = string.char(byte) end return table.concat(bbuffer, _NIL, 1, nbytes) end
local cmp = {["r"] = function(c) return bit.band(bit.rshift(c, 16), 0xFF) end, ["g"] = function(c) return bit.band(bit.rshift(c, 08), 0xFF) end, ["b"] = function(c) return bit.band(c, 0xFF) end}
local function bmp_color(color) return s_bytesLE(8, cmp.b(color)).. s_bytesLE(8, cmp.g(color)).. s_bytesLE(8, cmp.r(color)).. s_bytesLE(8, 0) .. "" end -- c_cmp(color, c.r))
local function bmp_color_mix(c1, c2, num, den) -- mixes c1 and c2 as ratio of numerator / denominator -- used 2x each save results local bc1, gc1, rc1 = cmp.b(c1), cmp.g(c1), cmp.r(c1)
return s_bytesLE(8, cmp.b(c2) - bc1 * num / den + bc1).. s_bytesLE(8, cmp.g(c2) - gc1 * num / den + gc1).. s_bytesLE(8, cmp.r(c2) - rc1 * num / den + rc1).. s_bytesLE(8, 0) .. "" end
local w, h = img:width(), img:height() local depth = tonumber(img:__tostring(6)) -- RLI_INFO_DEPTH = 0x6 local format = tonumber(img:__tostring(7)) -- RLI_INFO_FORMAT = 0x7
local bpp, bypl -- bits per pixel, bytes per line -- bypl, pad rows to a multiple of 4 bytes if depth <= 4 then bpp = 8 -- 256 color image bypl = (w + 3) elseif depth <= 16 then bpp = 16 bypl = (w * 2 + 3) elseif depth <= 24 then bpp = 24 bypl = (w * 3 + 3) else bpp = 32 bypl = (w * 4 + 3) end
local linebytes = bit.band(bypl, bit.bnot(3))
local bytesperpixel = bit.rshift(bpp, 3) local headersz = 54 local imgszpad = h * linebytes
local compression, n_colors = 0, 0 local h_ppm, v_ppm = 0x00000EC4, 0x00000EC4 --Pixels Per Meter ~ 96 dpi
if depth == 16 then compression = 3 -- BITFIELDS n_colors = 3 elseif depth <= 8 then n_colors = bit.lshift(1, depth) end
headersz = headersz + (4 * n_colors)
file = io.open('/' .. name, "w+") -- overwrite, rb ignores the 'b' flag
if not file then rb.splash(rb.HZ, "Error opening /" .. name) return end -- create a bitmap header 'rope' with image details -- concatenated at end local bmpheader = fbuffer
bmpheader[01] = "BM" bmpheader[02] = s_bytesLE(32, headersz + imgszpad) bmpheader[03] = "\0\0\0\0" -- WORD reserved 1 & 2 bmpheader[04] = s_bytesLE(32, headersz) -- BITMAPCOREHEADER size bmpheader[05] = s_bytesLE(32, 40) -- BITMAPINFOHEADER size
bmpheader[06] = s_bytesLE(32, w) bmpheader[07] = s_bytesLE(32, h) bmpheader[08] = "\1\0" -- WORD color planes ALWAYS 1 bmpheader[09] = s_bytesLE(16, bpp) -- bits/pixel bmpheader[10] = s_bytesLE(32, compression) bmpheader[11] = s_bytesLE(32, imgszpad) bmpheader[12] = s_bytesLE(32, h_ppm) -- biXPelsPerMeter bmpheader[13] = s_bytesLE(32, v_ppm) -- biYPelsPerMeter bmpheader[14] = s_bytesLE(32, n_colors) bmpheader[15] = s_bytesLE(32, n_colors)
-- Color Table (#n_colors entries) if depth == 1 then -- assuming positive display bmpheader[#bmpheader + 1] = bmp_color(0xFFFFFF) bmpheader[#bmpheader + 1] = bmp_color(0x0) elseif depth == 2 then bmpheader[#bmpheader + 1] = bmp_color(0xFFFFFF) bmpheader[#bmpheader + 1] = bmp_color_mix(0xFFFFFF, 0, 1, 3) bmpheader[#bmpheader + 1] = bmp_color_mix(0xFFFFFF, 0, 2, 3) bmpheader[#bmpheader + 1] = bmp_color(0x0) elseif depth == 16 then if format == 555 then -- red bitfield mask bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x00007C00) -- green bitfield mask bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x000003E0) -- blue bitfield mask bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x0000001F) else --565 -- red bitfield mask bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x0000F800) -- green bitfield mask bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x000007E0) -- blue bitfield mask bmpheader[#bmpheader + 1] = s_bytesLE(32, 0x0000001F) end end
file:write(table.concat(fbuffer))-- write the header to the file now for i=1, #fbuffer do fbuffer[i] = _NIL end -- reuse table
local imgdata = fbuffer -- pad rows to get even number of pixels local pxleft = (linebytes - (bytesperpixel * w)) / bytesperpixel
local t_data = {} local fs_bytes_E = s_bytesLE -- default save in Little Endian
if format == 3553 then -- RGB565SWAPPED fs_bytes_E = s_bytesBE -- Saves in Big Endian end
-- Bitmap lines start at bottom unless biHeight is negative for point in _points(img, 1, h, w + pxleft, 1, 1, 1, true) do imgdata[#imgdata + 1] = fs_bytes_E(bpp, point or 0)
if #fbuffer >= 31 then -- buffered write, increase # for performance file:write(table.concat(fbuffer)) for i=1, #fbuffer do fbuffer[i] = _NIL end -- reuse table end
end file:write(table.concat(fbuffer)) --write leftovers to file fbuffer = _NIL
file:close() end -- save(img, name)end