local function load(path) local image = { w = 0, h = 0, scale = 1.0, palette = {}, lines = {} } local fp, err = io.open(path, "rb") if not fp then return nil, err end local magic = fp:read(4) if magic ~= "CCPI" then return nil, "Invalid header: expected CCPI got " .. magic end image.w, image.h = string.byte(fp:read(1)), string.byte(fp:read(1)) image.scale = 0.5 + string.byte(fp:read(1)) * 5 / 255 for i = 1, 16 do image.palette[i] = bit.blshift(string.byte(fp:read(1)), 16) image.palette[i] = bit.bor(image.palette[i], bit.blshift(string.byte(fp:read(1)), 8)) image.palette[i] = bit.bor(image.palette[i], string.byte(fp:read(1))) end for y = 1, image.h do local line = { s = "", bg = "", fg = "" } for x = 1, image.w do line.s = line.s .. fp:read(1) local char = fp:read(1) if char == nil then return nil, string.format("Failed to read color data for x=%d y=%d", x, y) end local color = string.byte(char) line.bg = line.bg .. string.format("%x", bit.band(0xF, color)) line.fg = line.fg .. string.format("%x", bit.band(0xF, bit.brshift(color, 4))) end table.insert(image.lines, line) end fp:close() return image end local function draw(img, ox, oy, monitor) -- todo: add expect() local t = monitor or term.current() ox = ox or 1 oy = oy or 1 for i = 1, 16 do t.setPaletteColor(bit.blshift(1, i - 1), img.palette[i]) end t.setTextScale(img.scale) for y = 1, img.h do t.setCursorPos(ox, oy + y - 1) t.blit(img.lines[y].s, img.lines[y].fg, img.lines[y].bg) end end return { load = load, draw = draw }