zequan

Untitled

Jun 18th, 2014
170
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.79 KB | None | 0 0
  1. --[[
  2. OC Efficient image file format
  3. this is a space efficient and fast rendering algorithm for non text images
  4. it tries to reduce images to a small number of fills instead of setting each pixel individually
  5. header:
  6. string "OCI"
  7. version: byte
  8. meta: zero terminated string
  9. width: byte
  10.  
  11. repeat:
  12. color: byte
  13. width: byte
  14. height: byte
  15. ]]--
  16.  
  17. local component=require("component")
  18. local s=require("serialization")
  19.  
  20. local oci={}
  21. local version=0
  22.  
  23. --[[
  24. encodes an image to another format
  25. modes:
  26. oci:
  27. default output
  28. xy24:
  29. default input
  30. data[x][y]=24 bit color
  31. yx24:
  32. data[y][x]=24 bit color
  33. xy8:
  34. data[x][y]=8 bit color
  35. yx8:
  36. data[y][x]=8 bit color
  37. <number> or str:
  38. image is encoded as a string with 8 bit colors and width is <number>
  39. returns output,width,height
  40. ]]
  41.  
  42. local function round(num)
  43. return math.floor(num+0.5)
  44. end
  45.  
  46. local function c24to8(num)
  47. return round(bit32.rshift(num,16)*7/255)*32+round((bit32.rshift(num,8)%256)*7/255)*4+round((num%256)*3/255)
  48. end
  49.  
  50. local function c8to24(c)
  51. return round(math.floor(c/32)*255/7)*65536+round((math.floor(c/4)%8)*255/7)*256+round((c%4)*255/3)
  52. end
  53.  
  54. local function encode(data,mode,omode,meta)
  55. mode=mode or "xy24"
  56. omode=omode or "oci"
  57. local inp={}
  58. local wd
  59. local hi
  60. if mode=="oci" then
  61. if data:sub(1,3)~="OCI" then
  62. error("invalid OCI data")
  63. end
  64. data=data:sub(4)
  65. local version=data:byte(1,1)
  66. local meta,width,data=data:match("^.(.-)%z(.)(.+)")
  67. width=width:byte()
  68. wd=width
  69. hi=0
  70. local x=1
  71. local y=1
  72. for l1=1,#data,3 do
  73. local c=c8to24(data:byte(l1))
  74. local w=data:byte(l1+1)
  75. local h=data:byte(l1+2)
  76. hi=math.max(hi,(h+y)-1)
  77. -- fill space
  78. for cy=y,(h+y)-1 do
  79. inp[cy]=inp[cy] or {}
  80. for cx=x,(w+x)-1 do
  81. inp[cy][cx]=c
  82. end
  83. end
  84. -- find next pixel
  85. if x+w>width then
  86. x=1
  87. y=h+y
  88. else
  89. x=x+w
  90. end
  91. end
  92. elseif mode=="xy24" then
  93. wd=#data
  94. hi=#(data[1] or {})
  95. for x=1,#data do
  96. local c=data[x]
  97. hi=#c
  98. for y=1,#c do
  99. inp[y]=inp[y] or {}
  100. inp[y][x]=data[x][y]
  101. end
  102. end
  103. elseif mode=="yx24" then
  104. wd=#(data[1] or {})
  105. hi=#data
  106. inp=data
  107. elseif mode=="xy8" then
  108. wd=#data
  109. hi=#(data[1] or {})
  110. for x=1,#data do
  111. local c=data[x]
  112. for y=1,#c do
  113. inp[y]=inp[y] or {}
  114. inp[y][x]=c8to24(c[y])
  115. end
  116. end
  117. elseif mode=="yx8" then
  118. wd=#(data[1] or {})
  119. hi=#data
  120. for y=1,#data do
  121. inp[y]={}
  122. local c=data[y]
  123. for x=1,#c do
  124. inp[y][x]=c8to24(c[x])
  125. end
  126. end
  127. elseif tonumber(mode) then
  128. local w=tonumber(mode)
  129. if #data%w~=0 then
  130. error("invalid data")
  131. end
  132. for l1=1,#data do
  133. local x=((l1-1)%w)+1
  134. local y=math.floor(l1/w)+1
  135. inp[y]=inp[y] or {}
  136. inp[y][x]=c8to24(data:byte(l1,l1))
  137. end
  138. else
  139. error("no such mode: "..tostring(mode))
  140. end
  141. local out
  142. if omode=="oci" then
  143. -- this can be slow on large images
  144. local ot={}
  145. local ud=setmetatable({},{__index=function(s,n)
  146. local o={}
  147. s[n]=o
  148. return o
  149. end})
  150. -- generate
  151. for y=1,hi do
  152. ot[y]={}
  153. local c=inp[y]
  154. for x=1,wd do
  155. local cc=c[x]
  156. if not ud[y][x] then
  157. local mx=y+x
  158. local ct={y,x}
  159. local pmn=wd
  160. for cy=y,hi do
  161. if inp[cy][x]~=cc then
  162. break
  163. end
  164. local m=x
  165. for cx=x,pmn do
  166. if inp[cy][cx]~=cc then
  167. break
  168. end
  169. m=cx
  170. end
  171. pmn=math.min(pmn,m)
  172. if m+cy>mx then
  173. ct={cy,m}
  174. end
  175. end
  176. for sy=y,ct[1] do
  177. for sx=x,ct[2] do
  178. ud[sy][sx]=true
  179. end
  180. end
  181. ot[y][x]=ct
  182. end
  183. end
  184. end
  185. out="OCI"..string.char(version).."\0"..string.char(wd)
  186. for y=1,hi do
  187. local c=ot[y]
  188. for x=1,wd do
  189. local cc=c[x]
  190. if cc then
  191. out=out..string.char(c24to8(inp[y][x]))..string.char((cc[2]-x)+1)..string.char((cc[1]-y)+1)
  192. end
  193. end
  194. end
  195. elseif omode=="xy24" then
  196. out={}
  197. for x=1,wd do
  198. out[x]={}
  199. for y=1,hi do
  200. out[x][y]=inp[y][x]
  201. end
  202. end
  203. elseif omode=="yx24" then
  204. out=inp
  205. elseif omode=="xy8" then
  206. out={}
  207. for x=1,wd do
  208. out[x]={}
  209. for y=1,hi do
  210. out[x][y]=c24to8(inp[y][x])
  211. end
  212. end
  213. elseif omode=="yx8" then
  214. out={}
  215. for y=1,hi do
  216. out[y]={}
  217. for x=1,wd do
  218. out[y][x]=c24to8(inp[y][x])
  219. end
  220. end
  221. elseif omode=="str" then
  222. out=""
  223. for y=1,hi do
  224. for x=1,wd do
  225. out=out..string.char(c24to8(inp[y][x]))
  226. end
  227. end
  228. end
  229. return out,wd,hi
  230. end
  231.  
  232. --[[
  233. renders an oci image
  234. x and y are start of image, defaults to 1
  235. ]]
  236.  
  237. local function render(data,x,y)
  238. if data:sub(1,3)~="OCI" then
  239. error("invalid OCI")
  240. end
  241. data=data:sub(4)
  242. local gpu=component.gpu
  243. x=x or 1
  244. y=y or 1
  245. local version=data:byte(1,1)
  246. local odata=data
  247. local meta,width,data=data:match("^.(.-)%z(.)(.+)$")
  248. width=width:byte()
  249. local cx=1
  250. local cy=1
  251. if #data%3~=0 then
  252. error("invalid OCI "..#data..","..(#data%3))
  253. end
  254. local f=setmetatable({},{__index=function(s,n)
  255. local o={}
  256. s[n]=o
  257. return o
  258. end})
  259. for l1=1,#data,3 do
  260. local w=data:byte(l1+1)
  261. local h=data:byte(l1+2)
  262. -- fill space
  263. gpu.setBackground(c8to24(data:byte(l1)))
  264. gpu.fill(x+cx-1,y+cy-1,w,h," ")
  265. for sy=cy,cy+h-1 do
  266. for sx=cx,cx+w-1 do
  267. f[sy][sx]=true
  268. end
  269. end
  270. -- find next pixel
  271. while f[cy][cx] do
  272. cx=cx+1
  273. cy=cy+math.floor(cx/(width+1))
  274. cx=((cx-1)%width)+1
  275. end
  276. end
  277. end
  278.  
  279. return {
  280. encode=encode,
  281. render=render,
  282. }
Advertisement
Add Comment
Please, Sign In to add comment