From 893a23b05184851f30111f791b1137cafc91e066 Mon Sep 17 00:00:00 2001 From: xingluo Date: Sun, 4 May 2025 21:38:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E9=99=A4=20bimg-play.lua?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bimg-play.lua | 313 -------------------------------------------------- 1 file changed, 313 deletions(-) delete mode 100644 bimg-play.lua diff --git a/bimg-play.lua b/bimg-play.lua deleted file mode 100644 index a8f4e2f..0000000 --- a/bimg-play.lua +++ /dev/null @@ -1,313 +0,0 @@ --- bimg_player.lua --- BIMG Player (Shell Version) --- Usage: bimg_player [options] - --- Initialize settings -local running = false -local currentAnimation = nil -local httpEnabled = http and http.get - --- Show help message -local function showHelp() - print("BIMG Player - Usage:") - print("bimg_player [options]") - print() - print("Options:") - print(" --loop Loop animation") - print(" --url Load from URL") - print(" --monitor Play on specific monitor (top/bottom/left/right/front/back)") - print(" --scale Set display scale (0.5-3)") - print(" --fps Set frame rate (1-60)") - print(" --help Show this help") - print() - print("Examples:") - print("bimg_player animation.bimg --loop") - print("bimg_player http://example.com/image.bimg --url --monitor top") -end - --- Draw single frame -local function drawFrame(frame, termObj) - for y, row in ipairs(frame) do - termObj.setCursorPos(1, y) - termObj.blit(table.unpack(row)) - end - if frame.palette then - for i = 0, #frame.palette do - local c = frame.palette[i] - if type(c) == "table" then - termObj.setPaletteColor(2^i, table.unpack(c)) - else - termObj.setPaletteColor(2^i, c) - end - end - end -end - --- Load image file -local function loadImageFile(path) - local file, err = fs.open(shell.resolve(path), "rb") - if not file then error("Cannot open file: " .. err) end - local data = file.readAll() - file.close() - local success, img = pcall(textutils.unserialize, data) - if not success then error("Invalid BIMG file: " .. img) end - return img -end - --- Load image from URL -local function loadImageURL(url) - if not httpEnabled then - error("HTTP API not available, cannot load from URL") - end - - print("Downloading from URL: "..url) - local response = http.get(url) - if not response then - error("Download failed: " .. url) - end - - local data = response.readAll() - response.close() - local success, img = pcall(textutils.unserialize, data) - if not success then error("Invalid BIMG data: " .. img) end - return img -end - --- Monitor calibration -local function calibrateMonitors(width, height) - term.clear() - term.setCursorPos(1, 1) - print("Multi-Monitor Calibration Mode") - print("Please right-click each monitor in order") - print("From top-left to bottom-right, left to right first") - - local monitors = {} - local names = {} - - for y = 1, height do - monitors[y] = {} - for x = 1, width do - local _, oy = term.getCursorPos() - - -- Draw calibration UI - for ly = 1, height do - term.setCursorPos(3, oy + ly - 1) - term.clearLine() - for lx = 1, width do - term.blit('\x8F ', (lx == x and ly == y) and '00' or '77', 'ff') - end - end - - term.setCursorPos(3, oy + height) - term.write(string.format("Position (%d, %d)", x, y)) - term.setCursorPos(1, oy) - - -- Wait for monitor click - repeat - local _, name = os.pullEvent('monitor_touch') - monitors[y][x] = name - until not names[name] - - names[monitors[y][x]] = true - sleep(0.25) - end - end - - settings.set('bimg_player.multimonitor', monitors) - settings.save() - print("Calibration complete. Settings saved.") - - return monitors -end - --- Stop playback -local function stopPlayback() - if currentAnimation then - currentAnimation.running = false - os.queueEvent("bimg_stop") - end - running = false -end - --- Clean up terminal -local function cleanupTerminal(termObj) - termObj.setBackgroundColor(colors.black) - termObj.setTextColor(colors.white) - termObj.clear() - termObj.setCursorPos(1, 1) - for i = 0, 15 do - termObj.setPaletteColor(2^i, term.nativePaletteColor(2^i)) - end -end - --- Main playback function -local function playAnimation(img, options) - options = options or {} - local termObj = options.terminal or term - local loop = options.loop or false - local fps = options.fps or (img.secondsPerFrame and (1/img.secondsPerFrame)) or 20 - local frameDelay = 1/fps - - -- Set running state - running = true - currentAnimation = { - running = true, - loop = loop - } - - -- Playback function - local function playFrames() - repeat - if img.multiMonitor then - local width, height = img.multiMonitor.width, img.multiMonitor.height - local monitors = settings.get('bimg_player.multimonitor') - - -- Calibrate if needed - if not monitors or #monitors < height or #monitors[1] < width then - monitors = calibrateMonitors(width, height) - end - - -- Multi-monitor playback - for i = 1, #img, width * height do - if not currentAnimation.running then break end - - for y = 1, height do - for x = 1, width do - local frameIndex = i + (y-1) * width + x-1 - if frameIndex <= #img then - local monitor = peripheral.wrap(monitors[y][x]) - if monitor then - drawFrame(img[frameIndex], monitor) - end - end - end - end - - sleep(frameDelay) - end - else - -- Single monitor playback - termObj.clear() - for _, frame in ipairs(img) do - if not currentAnimation.running then break end - drawFrame(frame, termObj) - sleep(frameDelay) - end - end - until not loop or not currentAnimation.running - end - - -- Start playback - parallel.waitForAny( - function() - local ok, err = pcall(playFrames) - if not ok then printError("Playback error: "..err) end - cleanupTerminal(termObj) - running = false - end, - function() - while currentAnimation.running do - os.pullEvent("bimg_stop") - currentAnimation.running = false - end - end - ) -end - --- Parse command line arguments -local function parseArguments(args) - local options = {} - local path = nil - - local i = 1 - while i <= #args do - local arg = args[i] - if arg == "--loop" then - options.loop = true - elseif arg == "--url" then - options.isURL = true - elseif arg == "--monitor" then - i = i + 1 - options.terminal = peripheral.wrap(args[i]) - if not options.terminal then - error("Invalid monitor side: " .. (args[i] or "nil")) - end - elseif arg == "--scale" then - i = i + 1 - local scale = tonumber(args[i]) - if scale and scale >= 0.5 and scale <= 3 then - options.scale = scale - else - error("Invalid scale value (should be 0.5-3)") - end - elseif arg == "--fps" then - i = i + 1 - local fps = tonumber(args[i]) - if fps and fps >= 1 and fps <= 60 then - options.fps = fps - else - error("Invalid FPS value (should be 1-60)") - end - elseif arg == "--help" then - showHelp() - return nil - elseif not path and not arg:find("^-") then - path = arg - else - error("Unknown option: " .. arg) - end - i = i + 1 - end - - if not path then - showHelp() - return nil - end - - return path, options -end - --- Main program entry -local function main(...) - local args = {...} - - -- Show help if no arguments - if #args == 0 then - showHelp() - return - end - - -- Parse arguments - local ok, path, options = pcall(parseArguments, args) - if not ok then - printError(path) -- Here path contains the error message - showHelp() - return - end - - if not path then return end -- User requested help - - -- Load image - local img - if options.isURL then - img = loadImageURL(path) - else - img = loadImageFile(path) - end - - -- Apply display scale - if options.scale and img.multiMonitor then - img.multiMonitor.scale = options.scale - end - - -- Start playback - playAnimation(img, options) - - -- Wait for keypress if not looping - if not options.loop then - stopPlayback() - end -end - --- Start program -main(...) \ No newline at end of file