From 80f58af6970bc8ed7079de2d6c1f6d66bb139332 Mon Sep 17 00:00:00 2001 From: ubq323 Date: Thu, 4 Aug 2022 22:23:48 +0100 Subject: load_pnm --- img/load_pnm.lua | 127 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 107 insertions(+), 20 deletions(-) (limited to 'img/load_pnm.lua') diff --git a/img/load_pnm.lua b/img/load_pnm.lua index 60cac8a..1cd228c 100644 --- a/img/load_pnm.lua +++ b/img/load_pnm.lua @@ -1,34 +1,121 @@ -local perr = require("util").perr +-- only going to support binary ones +-- because the textual ones are annoying -local function load_p1(fname) +-- types: +-- P1 ascii pbm +-- P2 ascii pgm +-- P3 ascii ppm +-- P4 binary pbm +-- P5 binary pgm +-- P6 binary ppm - local file,err = fs.open(fname,"r") - perr(err,"fs.open") - local imgf = file.readAll() - --print(img) - assert(imgf:sub(1,2) == "P1","only P1 images are supported at the moment") - local width,height, cur = imgf:match("%s*(%d+)%s*(%d+)%s*()",3) - assert(width,"couldn't find image header") - local img=setmetatable({},{__index=function(t,k) +-- function nextpixel(imgf,cur,depth) -> pixel, ncur +-- where pixel is {r,g,b}, with r,g,b in [0,1] + +local function np_p1(imgf,cur,depth) + local val,ncur = imgf:match("[01]%s*()",cur) + val = tonumber(val) + assert(val,"bad image format at "..cur) + local p = (1-v) -- 1 is black (0), 0 is white (1) + local pixel = {p,p,p} + return pixel,ncur +end +local function np_p2(imgf,cur,depth) + local val,ncur = imgf:match("(%d+)%s+()",cur) + val = tonumber(val) + assert(val,"bad image format at "..cur) + assert(0<=val and val<=depth, "image value out of range at "..cur) + local p = val/depth + local pixel = {p,p,p} + return pixel,ncur +end +local function np_p3(imgf,cur,depth) + local tr,tg,tb,ncur = imgf:match("(%d+)%s+(%d+)%s+(%d+)%s+()",cur) + local vr,vg,vb = tonumber(tr),tonumber(tg),tonumber(tb) + assert(vr,"bad image format at "..cur) + for _,v in ipairs{vr,vg,vb} do + assert(0<=v and v<=depth,"image value out of range at "..cur) + end + local pr,pg,pb = vr/depth,vg/depth,vb/depth + local pixel = {pr,pg,pb} + return pixel,ncur +end +-- i will figure this one out later +local function np_p4() error("p4 isn't supported yet") end +local function np_p5(imgf,cur,depth) + local val = imgf:byte(cur) + assert(val<=depth,"image value out of range at "..cur) + local p = val/depth + local pixel = {p,p,p} + return pixel,cur+1 +end +local function np_p6(imgf,cur,depth) + local vr,vg,vb = img:byte(cur,cur+3) + for _,v in ipairs{vr,vg,vb} do + assert(0<=v and v<=depth, "image value out of range at "..cur) + end + local pr,pg,pb = vr/depth,vg/depth,vb/depth + local pixel = {pr,pg,pb} + return pixel,cur+3 +end + +local nextpixel_fns = { + [1]=np_p1, + [2]=np_p2, + [3]=np_p3, + [4]=np_p4, + [5]=np_p5, + [6]=np_p6, +} + + +local function parse(imgf) + assert(imgf:sub(1,1) == "P","invalid header") + local typech = tonumber(imgf:sub(2,2)) + assert(typech and 1<=typech and typech<=6,"invalid header type") + + local has_depth = not(typech == 1 or typech == 4) + + local width,height,cur = imgf:match("%s*(%d+)%s*(%d+)%s*()",3) + assert(width,"couldn't find image dimensions") + + -- by 'depth' i mean 'maximum value' + local depth = 1 + if has_depth then + local ndepth,ncur = imgf:match("(%d+)%s*()") + assert(ndepth,"couldn't find image depth (max pixel value), in a format that needs it") + depth=ndepth + cur=ncur + end + assert(depth<=255,"depth too high (shouldn't be above 255)") + + -- img[y][x]; 1,1 is top left + local img = setmetatable({},{__index=function(t,k) if type(k) ~= "number" then return nil end local r = {} rawset(t,k,r) return r end}) - -- img[y][x]. 1,1 is top left - for row=1,height do - for col =1,width do - local val,ncur = imgf:match("(%d+)%s*()",cur) - cur = ncur - img[row][col] = tonumber(val) + local x,y=1,1 + local nextpixel = nextpixel_fns[typech] + + while cur <= #imgf do + local npixel,ncur = nextpixel(imgf,cur,depth) + img[y][x] = npixel + cur = ncur + if y > width then + y = 1 + x = x + 1 + end + if x > height then + break end end - - img.width=width - img.height=height + + img.width = width + img.height = height return img end -return load_p1 -- cgit v1.2.3