Advertisement
ZNZNCOOP

Graffiti

Feb 12th, 2016
845
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 30.07 KB | None | 0 0
  1. local gpu=require("component").gpu
  2. local graffiti = {}
  3.  
  4. if gpu.maxDepth()==8 then
  5.  graffiti.colors = {
  6.   white    = 0xffffff,
  7.   orange   = 0xff9200,
  8.   magenta  = 0xff00ff,
  9.   lightblue= 0x99dbff,
  10.   yellow   = 0xffff00,
  11.   lime     = 0x00ff00,
  12.   pink     = 0xffb6bf,
  13.   gray     = 0x787878,
  14.   silver   = 0xc3c3c3,
  15.   cyan     = 0x00ffff,
  16.   purple   = 0x990080,
  17.   blue     = 0x0000ff,
  18.   brown    = 0x992440,
  19.   green    = 0x009200,
  20.   red      = 0xff0000,
  21.   black    = 0x000000}
  22. elseif gpu.maxDepth()==4 then
  23.  graffiti.colors = {
  24.   white    = 0xffffff,
  25.   orange   = 0xffcc33,
  26.   magenta  = 0xcc66cc,
  27.   lightblue= 0x336699,
  28.   yellow   = 0xffff33,
  29.   lime     = 0x33cc33,
  30.   pink     = 0xff6699,
  31.   gray     = 0x333333,
  32.   silver   = 0xcccccc,
  33.   cyan     = 0x6699ff,
  34.   purple   = 0x9933cc,
  35.   blue     = 0x333399,
  36.   brown    = 0x663300,
  37.   green    = 0x336600,
  38.   red      = 0xff3333,
  39.   black    = 0x000000}
  40. else
  41.  graffiti.colors  ={
  42.   white    = 0xffffff,
  43.   black    = 0x000000}
  44. end
  45.  
  46. local currentX,currentY = 1,1
  47. local Color = gpu.getForeground()
  48. local maxX,maxY=gpu.getResolution()
  49.  
  50. graffiti.setColor=function(color)
  51.   checkArg(1, color, "number")
  52.   Color=color
  53. end
  54.  
  55. local function getColor(x,y)
  56.   if x<1 or x>maxX then return end
  57.   local n=y % 2
  58.   y=(y+n)/2
  59.   if y<1 or y>maxY then return end
  60.   local c,Fc,Bc = gpu.get(x,y)
  61.   if c~="▄" or n==1 then return Bc end
  62.   return Fc
  63. end
  64.  
  65. graffiti.getColor=function(x,y)
  66.   checkArg(1, x, "number")
  67.   checkArg(2, y, "number")
  68.   return getColor(math.floor(x+0.5),math.floor(y+0.5))
  69. end
  70.  
  71. local function dot(x,y,color)
  72.   if x<1 or x>maxX then return end
  73.   local n=y % 2
  74.   y=(y+n)/2
  75.   if y<1 or y>maxY then return end
  76.   color=color or Color
  77.   local c,Fc,Bc = gpu.get(x,y)
  78.   if c~="▄" then Fc=Bc end
  79.   if n==0 then Fc=color else Bc=color end
  80.   gpu.setForeground(Fc)
  81.   gpu.setBackground(Bc)
  82.   gpu.set(x,y,"▄")
  83. end
  84.  
  85. local function dot_alpha(x,y,r,g,b,a)
  86.   if x<1 or x>maxX then return end
  87.   local n=y % 2
  88.   y=(y+n)/2
  89.   if y<1 or y>maxY then return end
  90.   local c,Fc,Bc = gpu.get(x,y)
  91.   if c~="▄" then Fc=Bc end
  92.   if n==0 then
  93.     local b0=Fc % 256
  94.     Fc=math.floor(Fc/256)
  95.     local r0, g0 = math.floor(Fc/256), Fc % 256
  96.     r0=math.floor(r0+(r-r0)*a/255+0.5)
  97.     g0=math.floor(g0+(g-g0)*a/255+0.5)
  98.     b0=math.floor(b0+(b-b0)*a/255+0.5)
  99.     Fc=(r0*256 + g0)*256 + b0
  100.   else
  101.     local b0=Bc % 256
  102.     Bc=math.floor(Bc/256)
  103.     local r0, g0 = math.floor(Bc/256), Bc % 256
  104.     r0=math.floor(r0+(r-r0)*a/255+0.5)
  105.     g0=math.floor(g0+(g-g0)*a/255+0.5)
  106.     b0=math.floor(b0+(b-b0)*a/255+0.5)
  107.     Bc=(r0*256 + g0)*256 + b0
  108.   end
  109.  
  110.   gpu.setForeground(Fc)
  111.   gpu.setBackground(Bc)
  112.   gpu.set(x,y,"▄")
  113. end
  114.  
  115. graffiti.dot=function(x,y)
  116.   checkArg(1, x, "number")
  117.   checkArg(2, y, "number")
  118.   local Fc, Bc = gpu.getForeground(), gpu.getBackground()
  119.   maxX,maxY=gpu.getResolution()
  120.   x=math.floor(x+0.5)
  121.   y=math.floor(y+0.5)
  122.   dot(x,y)
  123.   currentX,currentY = x,y
  124.   gpu.setForeground(Fc)
  125.   gpu.setBackground(Bc)
  126. end
  127.  
  128. local function move(x,y) -- алгоритм Брезенхема рисования линии
  129.   local dx,dy=math.abs(x-currentX),math.abs(y-currentY)
  130.   local x0,y0=currentX,currentY
  131.   local sx = x0<x and 1 or -1
  132.   local sy = y0<y and 1 or -1
  133.   local err = 0
  134.   if dx>dy then
  135.     while true do
  136.       dot(x0,y0)
  137.       x0=x0+sx
  138.       if x0*sx>=x*sx then return end
  139.       err=err+dy
  140.       if 2*err>=dx then
  141.         y0=y0 + sy
  142.         err=err-dx
  143.       end
  144.     end
  145.   else
  146.     while true do
  147.       dot(x0,y0)
  148.       y0=y0+sy
  149.       if y0*sy>=y*sy then return end
  150.       err=err+dx
  151.       if 2*err>=dy then
  152.         x0=x0 + sx
  153.         err=err-dy
  154.       end
  155.     end
  156.   end
  157. end
  158.  
  159. graffiti.move=function(x,y)
  160.   checkArg(1, x, "number")
  161.   checkArg(2, y, "number")
  162.   x=math.floor(x+0.5)
  163.   y=math.floor(y+0.5)
  164.   local Fc, Bc = gpu.getForeground(), gpu.getBackground()
  165.   maxX,maxY=gpu.getResolution()
  166.   move(x,y)
  167.   currentX,currentY = x,y
  168.   gpu.setForeground(Fc)
  169.   gpu.setBackground(Bc)
  170. end
  171.  
  172. graffiti.line=function(x0,y0,x1,y1)
  173.   checkArg(1, x0, "number")
  174.   checkArg(2, y0, "number")
  175.   checkArg(3, x1, "number")
  176.   checkArg(4, y1, "number")
  177.   local Fc, Bc = gpu.getForeground(), gpu.getBackground()
  178.   maxX,maxY=gpu.getResolution()
  179.   x0=math.floor(x0+0.5)
  180.   y0=math.floor(y0+0.5)
  181.   dot(x0,y0)
  182.   currentX,currentY = x0,y0
  183.   x1=math.floor(x1+0.5)
  184.   y1=math.floor(y1+0.5)
  185.   move(x1,y1)
  186.   currentX,currentY = x1,y1
  187.   gpu.setForeground(Fc)
  188.   gpu.setBackground(Bc)
  189. end
  190.  
  191. graffiti.circle=function(xc,yc,r,fillColor) -- модифицированный алгоритм Брезенхема рисования окружности
  192.   checkArg(1, xc, "number")
  193.   checkArg(2, yc, "number")
  194.   checkArg(3, r, "number")
  195.   checkArg(4, fillColor, "number", "boolean", "nil")
  196.   local Fc, Bc = gpu.getForeground(), gpu.getBackground()
  197.   maxX,maxY=gpu.getResolution()
  198.   if fillColor==true then fillColor=Color end
  199.   xc=math.floor(xc+0.5)
  200.   yc=math.floor(yc+0.5)
  201.   z=math.floor(r+0.5)
  202.   local d=3-2*r
  203.   local x,y=0,r
  204.   while(x <= y) do
  205.     dot(xc+x,yc+y)
  206.     dot(xc+x,yc-y)
  207.     dot(xc-x,yc-y)
  208.     dot(xc-x,yc+y)
  209.     if y>x then
  210.       dot(xc+y,yc+x)
  211.       dot(xc+y,yc-x)
  212.       dot(xc-y,yc-x)
  213.       dot(xc-y,yc+x)
  214.       if fillColor then
  215.         for i=xc-y+1,xc+y-1 do
  216.           dot(i,yc+x, fillColor)
  217.           if x>0 then dot(i,yc-x, fillColor) end
  218.         end
  219.       end
  220.     end
  221.     if d<0 then d=d+4*x+6
  222.     else
  223.       d=d+4*(x-y)+10
  224.       y=y-1
  225.       if fillColor and y>x then
  226.         for i=xc-x,xc+x do
  227.           dot(i,yc+y, fillColor)
  228.           dot(i,yc-y, fillColor)
  229.         end
  230.       end
  231.     end
  232.     x=x+1
  233.   end
  234.   gpu.setForeground(Fc)
  235.   gpu.setBackground(Bc)
  236. end
  237.  
  238. graffiti.fill=function(x,y)
  239.   checkArg(1, x, "number")
  240.   checkArg(2, y, "number")
  241.   local Fc, Bc = gpu.getForeground(), gpu.getBackground()
  242.   maxX,maxY=gpu.getResolution()
  243.   x=math.floor(x+0.5)
  244.   y=math.floor(y+0.5)
  245.   local fillColor=getColor(x,y)
  246.   if fillColor==Color then return end
  247.   local fillArray={{x,y}}
  248.   while fillArray[1] do
  249.     x,y=fillArray[1][1],fillArray[1][2]
  250.     table.remove(fillArray,1)
  251.     if getColor(x,y)==fillColor then
  252.       dot(x,y,Color)
  253.       if getColor(x-1,y)==fillColor then table.insert(fillArray,{x-1,y}) end
  254.       if getColor(x+1,y)==fillColor then table.insert(fillArray,{x+1,y}) end
  255.       if getColor(x,y-1)==fillColor then table.insert(fillArray,{x,y-1}) end
  256.       if getColor(x,y+1)==fillColor then table.insert(fillArray,{x,y+1}) end
  257.     end
  258.   end
  259.   gpu.setForeground(Fc)
  260.   gpu.setBackground(Bc)
  261. end
  262.  
  263. graffiti.polygon=function( ... )
  264.   local Fc, Bc = gpu.getForeground(), gpu.getBackground()
  265.   maxX,maxY=gpu.getResolution()
  266.   local args={...}
  267.   local x={} y={}  
  268.   for i=2,#args,2 do
  269.     checkArg(i-1,args[i-1], "number")
  270.     checkArg(i,  args[i], "number")
  271.     table.insert(x,math.floor(args[i-1]+0.5))
  272.     table.insert(y,math.floor(args[i]+0.5))
  273.   end
  274.   x[0]=x[#x]
  275.   y[0]=y[#y]
  276.  
  277.   local fillColor
  278.   if #args % 2 ==1 then fillColor=args[#args] end
  279.   if fillColor==true then fillColor=Color end
  280.   if fillColor then
  281.     checkArg(#args, fillColor, "number")
  282.     local minY,maxY=math.huge,-math.huge
  283.     for i=1,#x do
  284.       if y[i]<minY then minY=y[i] end
  285.       if y[i]>maxY then maxY=y[i] end
  286.     end
  287.     for yy=minY,maxY do
  288.       local xx={}
  289.       for i=1,#x do
  290.         local c=(y[i]-yy)*(yy-y[i-1])
  291.         if c>0 then
  292.           xx[#xx+1]=math.floor((x[i-1]-x[i])*(yy-y[i])/(y[i-1]-y[i])+x[i]+0.5)
  293.         end
  294.         if c==0 then
  295.           if yy>y[i-1] then xx[#xx+1]=x[i] end
  296.           if yy>y[i] then xx[#xx+1]=x[i-1] end
  297.         end
  298.       end
  299.       table.sort(xx)
  300.       for i=1,#xx,2 do
  301.         for i=xx[i]+1,xx[i+1]-1 do dot(i,yy, fillColor) end
  302.       end
  303.     end
  304.   end
  305.   dot(x[0],y[0])
  306.   currentX,currentY = x[0],y[0]
  307.   for i=1,#x do
  308.     move(x[i],y[i])
  309.     currentX,currentY = x[i],y[i]
  310.   end
  311.   gpu.setForeground(Fc)
  312.   gpu.setBackground(Bc)
  313. end
  314.  
  315.  
  316. ------------------------deflate--------------------------------------------
  317. local band, lshift, rshift                  ----77
  318. band = bit32.band
  319. lshift = bit32.lshift
  320. rshift = bit32.rshift
  321.  
  322. local function make_outstate(outbs)         ----98
  323.     local outstate = {}
  324.     outstate.outbs = outbs
  325.     outstate.window = {}
  326.     outstate.window_pos = 1
  327.     return outstate
  328. end
  329.  
  330. local function output(outstate, byte)       ----106
  331.     -- debug('OUTPUT:', s)
  332.     local window_pos = outstate.window_pos
  333.     outstate.outbs(byte)
  334.     outstate.window[window_pos] = byte
  335.     outstate.window_pos = window_pos % 32768 + 1   
  336. end
  337.  
  338. local function noeof(val, ctx)                     ----114
  339.     return assert(val, 'unexpected end of file with context ' .. tostring(ctx))
  340. end
  341.  
  342. local function memoize(f)                          ----122
  343.     local mt = {}
  344.     local t = setmetatable({}, mt)
  345.     function mt:__index(k)
  346.         local v = f(k)
  347.         t[k] = v
  348.         return v
  349.     end
  350.     return t
  351. end
  352.  
  353. -- small optimization (lookup table for powers of 2)
  354. local pow2 = memoize(function(n) return 2^n end)
  355.  
  356. -- weak metatable marking objects as bitstream type
  357. local is_bitstream = setmetatable({}, {__mode='k'})      ----143
  358.  
  359. local function bytestream_from_string(s)                 ----154
  360.     local i = 1
  361.     local o = {s=s}
  362.     function o:read()
  363.         local by
  364.         if i <= #self.s then
  365.             by = self.s:byte(i)
  366.             i = i + 1
  367.         end
  368.         return by
  369.     end
  370.     return o
  371. end
  372.  
  373. local function bitstream_from_bytestream(bys)            ----186
  374.     local buf_byte = 0
  375.     local buf_nbit = 0
  376.     local o = {}
  377.  
  378.     function o:nbits_left_in_byte()
  379.         return buf_nbit
  380.     end
  381.  
  382.     function o:read(nbits)
  383.         nbits = nbits or 1
  384.         while buf_nbit < nbits do
  385.             local byte = bys:read()
  386.             if not byte then return end -- note: more calls also return nil
  387.             buf_byte = buf_byte + lshift(byte, buf_nbit)
  388.             buf_nbit = buf_nbit + 8
  389.         end
  390.         local bits
  391.         if nbits == 0 then
  392.             bits = 0
  393.         elseif nbits == 32 then
  394.             bits = buf_byte
  395.             buf_byte = 0
  396.         else
  397.             bits = band(buf_byte, rshift(0xffffffff, 32 - nbits))
  398.             buf_byte = rshift(buf_byte, nbits)
  399.         end
  400.        
  401.         if nbits == 16 then
  402.             -- bugfix: swap bytes
  403.             bits = rshift(band(bits, 0xFF00), 8) + lshift(band(bits, 0xFF), 8)
  404.         end
  405.        
  406.         buf_nbit = buf_nbit - nbits
  407.         return bits
  408.     end
  409.    
  410.     is_bitstream[o] = true
  411.  
  412.     return o
  413. end
  414.  
  415. local function get_bitstream(o)                              ----237
  416.     local bs
  417.     if is_bitstream[o] then return o
  418. --  elseif io.type(o) == 'file' then
  419. --      bs = bitstream_from_bytestream(bytestream_from_file(o))
  420.     elseif type(o) == 'string' then
  421.         bs = bitstream_from_bytestream(bytestream_from_string(o))
  422. --  elseif type(o) == 'function' then
  423. --      bs = bitstream_from_bytestream(bytestream_from_function(o))
  424.     else
  425.         runtime_error 'unrecognized type'
  426.     end
  427.     return bs
  428. end
  429.  
  430. local function get_obytestream(o)                              ----254
  431.     local bs
  432.     if io.type(o) == 'file' then
  433.         bs = function(sbyte) o:write(string_char(sbyte)) end
  434.     elseif type(o) == 'function' then
  435.         bs = o
  436.     elseif type(o) == 'table' then
  437.         -- assume __callable table
  438.         bs = o
  439.     else
  440.         runtime_error('unrecognized type: ' .. tostring(o))
  441.     end
  442.     return bs
  443. end
  444.  
  445. local function HuffmanTable(init, is_full)               ----270
  446.     local t = {}
  447.     if is_full then
  448.         for val,nbits in pairs(init) do
  449.             if nbits ~= 0 then
  450.                 t[#t+1] = {val=val, nbits=nbits}
  451.             end
  452.         end
  453.     else
  454.         for i=1,#init-2,2 do
  455.             local firstval, nbits, nextval = init[i], init[i+1], init[i+2]
  456.             if nbits ~= 0 then
  457.                 for val=firstval,nextval-1 do
  458.                     t[#t+1] = {val=val, nbits=nbits}
  459.                 end
  460.             end
  461.         end
  462.     end
  463.     table.sort(t, function(a,b)
  464.         return a.nbits == b.nbits and a.val < b.val or a.nbits < b.nbits
  465.     end)
  466.  
  467.     -- assign codes
  468.     local code = 1  -- leading 1 marker
  469.     local nbits = 0
  470.     for i,s in ipairs(t) do
  471.         if s.nbits ~= nbits then
  472.             code = code * pow2[s.nbits - nbits]
  473.             nbits = s.nbits
  474.         end
  475.         s.code = code
  476.         code = code + 1
  477.     end
  478.  
  479.     local minbits = math.huge
  480.     local look = {}
  481.     for i,s in ipairs(t) do
  482.         minbits = math.min(minbits, s.nbits)
  483.         look[s.code] = s.val
  484.     end
  485.  
  486.     local msb = function(bits, nbits)
  487.         local res = 0
  488.         for i=1,nbits do
  489.             res = lshift(res, 1) + band(bits, 1)
  490.             bits = rshift(bits, 1)
  491.         end
  492.         return res
  493.     end
  494.    
  495.     local tfirstcode = memoize(function(bits)
  496.         return pow2[minbits] + msb(bits, minbits)
  497.     end)
  498.  
  499.     function t:read(bs)
  500.         local code = 1 -- leading 1 marker
  501.         local nbits = 0
  502.         while 1 do
  503.             if nbits == 0 then  -- small optimization (optional)
  504.                 code = tfirstcode[noeof(bs:read(minbits), 1)]
  505.                 nbits = nbits + minbits
  506.             else
  507.                 local b = noeof(bs:read(), 2)
  508.                 nbits = nbits + 1
  509.                 code = lshift(code, 1) + b   -- MSB first
  510.             end
  511.             local val = look[code]
  512.             if val then
  513.                 return val
  514.             end
  515.         end
  516.     end
  517.  
  518.     return t
  519. end
  520.  
  521. local function parse_zlib_header(bs)                          ----358
  522.     local cm = bs:read(4) -- Compression Method
  523.     local cinfo = bs:read(4) -- Compression info
  524.     local fcheck = bs:read(5) -- FLaGs: FCHECK (check bits for CMF and FLG)
  525.     local fdict = bs:read(1) -- FLaGs: FDICT (present dictionary)
  526.     local flevel = bs:read(2) -- FLaGs: FLEVEL (compression level)
  527.     local cmf = cinfo * 16  + cm -- CMF (Compresion Method and flags)
  528.     local flg = fcheck + fdict * 32 + flevel * 64 -- FLaGs
  529.    
  530.     if cm ~= 8 then -- not "deflate"
  531.         error("unrecognized zlib compression method: " + cm)
  532.     end
  533.     if cinfo > 7 then
  534.         error("invalid zlib window size: cinfo=" + cinfo)
  535.     end
  536.     local window_size = 2^(cinfo + 8)
  537.    
  538.     if (cmf*256 + flg) % 31 ~= 0 then
  539.         error("invalid zlib header (bad fcheck sum) - overflow by " .. ((cmf*256 + flg) % 31))
  540.     end
  541.    
  542.     if fdict == 1 then
  543.         error("FIX:TODO - FDICT not currently implemented")
  544.     end
  545.    
  546.     return window_size
  547. end
  548.  
  549. local function parse_huffmantables(bs)                                      ----451
  550.         local hlit = bs:read(5) -- # of literal/length codes - 257
  551.         local hdist = bs:read(5) -- # of distance codes - 1
  552.         local hclen = noeof(bs:read(4), 3) -- # of code length codes - 4
  553.  
  554.         local ncodelen_codes = hclen + 4
  555.         local codelen_init = {}
  556.         local codelen_vals = {
  557.             16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
  558.         for i=1,ncodelen_codes do
  559.             local nbits = bs:read(3)
  560.             local val = codelen_vals[i]
  561.             codelen_init[val] = nbits
  562.         end
  563.         local codelentable = HuffmanTable(codelen_init, true)
  564.  
  565.         local function decode(ncodes)
  566.             local init = {}
  567.             local nbits
  568.             local val = 0
  569.             while val < ncodes do
  570.                 local codelen = codelentable:read(bs)
  571.                 --FIX:check nil?
  572.                 local nrepeat
  573.                 if codelen <= 15 then
  574.                     nrepeat = 1
  575.                     nbits = codelen
  576.                     --debug('w', nbits)
  577.                 elseif codelen == 16 then
  578.                     nrepeat = 3 + noeof(bs:read(2), 4)
  579.                     -- nbits unchanged
  580.                 elseif codelen == 17 then
  581.                     nrepeat = 3 + noeof(bs:read(3), 5)
  582.                     nbits = 0
  583.                 elseif codelen == 18 then
  584.                     nrepeat = 11 + noeof(bs:read(7), 6)
  585.                     nbits = 0
  586.                 else
  587.                     error 'ASSERT'
  588.                 end
  589.                 for i=1,nrepeat do
  590.                     init[val] = nbits
  591.                     val = val + 1
  592.                 end
  593.             end
  594.             local huffmantable = HuffmanTable(init, true)
  595.             return huffmantable
  596.         end
  597.  
  598.         local nlit_codes = hlit + 257
  599.         local ndist_codes = hdist + 1
  600.  
  601.         local littable = decode(nlit_codes)
  602.         local disttable = decode(ndist_codes)
  603.  
  604.         return littable, disttable
  605. end
  606.  
  607. local tdecode_len_base
  608. local tdecode_len_nextrabits
  609. local tdecode_dist_base
  610. local tdecode_dist_nextrabits
  611. local function parse_compressed_item(bs, outstate, littable, disttable)
  612.     local val = littable:read(bs)
  613.     if val < 256 then -- literal
  614.         output(outstate, val)
  615.     elseif val == 256 then -- end of block
  616.         return true
  617.     else
  618.         if not tdecode_len_base then
  619.             local t = {[257]=3}
  620.             local skip = 1
  621.             for i=258,285,4 do
  622.                 for j=i,i+3 do t[j] = t[j-1] + skip end
  623.                 if i ~= 258 then skip = skip * 2 end
  624.             end
  625.             t[285] = 258
  626.             tdecode_len_base = t
  627.         end
  628.         if not tdecode_len_nextrabits then
  629.             local t = {}
  630.             for i=257,285 do
  631.                 local j = math.max(i - 261, 0)
  632.                 t[i] = rshift(j, 2)
  633.             end
  634.             t[285] = 0
  635.             tdecode_len_nextrabits = t
  636.         end
  637.         local len_base = tdecode_len_base[val]
  638.         local nextrabits = tdecode_len_nextrabits[val]
  639.         local extrabits = bs:read(nextrabits)
  640.         local len = len_base + extrabits
  641.  
  642.         if not tdecode_dist_base then
  643.             local t = {[0]=1}
  644.             local skip = 1
  645.             for i=1,29,2 do
  646.                 for j=i,i+1 do t[j] = t[j-1] + skip end
  647.                 if i ~= 1 then skip = skip * 2 end
  648.             end
  649.             tdecode_dist_base = t
  650.         end
  651.         if not tdecode_dist_nextrabits then
  652.             local t = {}
  653.             for i=0,29 do
  654.                 local j = math.max(i - 2, 0)
  655.                 t[i] = rshift(j, 1)
  656.             end
  657.             tdecode_dist_nextrabits = t
  658.         end
  659.         local dist_val = disttable:read(bs)
  660.         local dist_base = tdecode_dist_base[dist_val]
  661.         local dist_nextrabits = tdecode_dist_nextrabits[dist_val]
  662.         local dist_extrabits = bs:read(dist_nextrabits)
  663.         local dist = dist_base + dist_extrabits
  664.  
  665.         for i=1,len do
  666.             local pos = (outstate.window_pos - 1 - dist) % 32768 + 1    -- 32K
  667.             output(outstate, assert(outstate.window[pos], 'invalid distance'))
  668.         end
  669.     end
  670.     return false
  671. end
  672.  
  673. local function parse_block(bs, outstate)                      ----583
  674.     local bfinal = bs:read(1)
  675.     local btype = bs:read(2)
  676.  
  677.     local BTYPE_NO_COMPRESSION = 0
  678.     local BTYPE_FIXED_HUFFMAN = 1
  679.     local BTYPE_DYNAMIC_HUFFMAN = 2
  680.     local BTYPE_RESERVED_ = 3
  681.  
  682.     if DEBUG then
  683.         debug('bfinal=', bfinal)
  684.         debug('btype=', btype)
  685.     end
  686.  
  687.     if btype == BTYPE_NO_COMPRESSION then
  688.         bs:read(bs:nbits_left_in_byte())
  689.         local len = bs:read(16)
  690.         local nlen_ = noeof(bs:read(16), 7)
  691.  
  692.         for i=1,len do
  693.             local by = noeof(bs:read(8), 8)
  694.             output(outstate, by)
  695.         end
  696.     elseif btype == BTYPE_FIXED_HUFFMAN or btype == BTYPE_DYNAMIC_HUFFMAN then
  697.         local littable, disttable
  698.         if btype == BTYPE_DYNAMIC_HUFFMAN then
  699.             littable, disttable = parse_huffmantables(bs)
  700.         else
  701.             littable    = HuffmanTable {0,8, 144,9, 256,7, 280,8, 288,nil}
  702.             disttable = HuffmanTable {0,5, 32,nil}
  703.         end
  704.  
  705.         repeat
  706.             local is_done = parse_compressed_item(
  707.                 bs, outstate, littable, disttable)
  708.         until is_done
  709.     else
  710.         error 'unrecognized compression type'
  711.     end
  712.  
  713.     return bfinal ~= 0
  714. end
  715.  
  716. function inflate(t)                                  ----627
  717.     local bs = get_bitstream(t.input)
  718.     local outbs = get_obytestream(t.output)
  719.     local outstate = make_outstate(outbs)
  720.  
  721.     repeat
  722.         local is_final = parse_block(bs, outstate)
  723.     until is_final
  724. end
  725.  
  726. function inflate_zlib(t)
  727.     local bs = get_bitstream(t.input)
  728.     local outbs = get_obytestream(t.output)
  729.     local window_size_ = parse_zlib_header(bs)
  730.     local data_adler32 = 1
  731.     inflate{input=bs, output=outbs}
  732.     bs:read(bs:nbits_left_in_byte())
  733.    
  734.     local b3 = bs:read(8)
  735.     local b2 = bs:read(8)
  736.     local b1 = bs:read(8)
  737.     local b0 = bs:read(8)
  738.     if bs:read() then
  739.         warn 'trailing garbage ignored'
  740.     end
  741. end
  742.  
  743.  
  744. --
  745. -- libPNGimage by TehSomeLuigi
  746. -- Revision: 1
  747. --
  748. -- A library to load, edit and save PNGs for OpenComputers
  749. --
  750.  
  751. --[[
  752.    
  753.     Feel free to use however you wish.
  754.     This header must however be preserved should this be redistributed, even
  755.     if in a modified form.
  756.    
  757.     This software comes with no warranties whatsoever.
  758.    
  759.     2014 TehSomeLuigi
  760.  
  761. ]]--
  762. local PNGImage = {}                                    ----1
  763. local PNGImagemetatable = {}
  764. PNGImagemetatable.__index = PNGImage
  765.  
  766. local function __unpack_msb_uint32(s)                  ----56
  767.     local a,b,c,d = s:byte(1,#s)
  768.     local num = (((a*256) + b) * 256 + c) * 256 + d
  769.     return num
  770. end
  771.  
  772. -- Read 32-bit unsigned integer (most-significant-byte, MSB, first) from file.
  773. local function __read_msb_uint32(fh)                                               ----110
  774.     return __unpack_msb_uint32(fh:read(4))
  775. end
  776.  
  777. -- Read unsigned byte (integer) from file
  778. local function __read_byte(fh)                       ----115
  779.     return fh:read(1):byte()
  780. end
  781.  
  782. local function getBitWidthPerPixel(ihdr)             ----121
  783.     if ihdr.color_type == 0 then -- Greyscale
  784.         return ihdr.bit_depth
  785.     end
  786.     if ihdr.color_type == 2 then -- Truecolour
  787.         return ihdr.bit_depth * 3
  788.     end
  789.     if ihdr.color_type == 3 then -- Indexed-colour
  790.         return ihdr.bit_depth
  791.     end
  792.     if ihdr.color_type == 4 then -- Greyscale + Alpha
  793.         return ihdr.bit_depth * 2
  794.     end
  795.     if ihdr.color_type == 6 then -- Truecolour + Alpha
  796.         return ihdr.bit_depth * 4
  797.     end
  798. end
  799.  
  800. local function getByteWidthPerScanline(ihdr)         ----139
  801.     return math.ceil((ihdr.width * getBitWidthPerPixel(ihdr)) / 8)
  802. end
  803.  
  804. local outssmt = {}                                     ----143
  805.  
  806. function outssmt:__call(write)
  807.     self.str = self.str .. string.char(write)
  808. end
  809.  
  810. function outssmt.OutStringStream()
  811.     local outss = {str=""}
  812.     setmetatable(outss, outssmt)
  813.     return outss
  814. end
  815.  
  816. local function __parse_IHDR(fh, len)                 ----158
  817.     if len ~= 13 then
  818.         error("PNG IHDR Corrupt - should be 13 bytes long")
  819.     end
  820.    
  821.     local ihdr = {}
  822.    
  823.     ihdr.width = __read_msb_uint32(fh)
  824.     ihdr.height = __read_msb_uint32(fh)
  825.     ihdr.bit_depth = __read_byte(fh)
  826.     ihdr.color_type = __read_byte(fh)
  827.     ihdr.compression_method = __read_byte(fh)
  828.     ihdr.filter_method = __read_byte(fh)
  829.     ihdr.interlace_method = __read_byte(fh)
  830.        
  831.     return ihdr
  832. end
  833.  
  834. local function __parse_IDAT(fh, len, commeth, outss)   ----206
  835.     if commeth ~= 0 then
  836.         error("Only zlib/DEFLATE compression supported")
  837.     end
  838.     local input = fh:read(len)
  839.     local cfg = {input=input, output=outss, disable_crc=true}
  840.     inflate_zlib(cfg)
  841.     return true
  842. end
  843.  
  844. local function getPNGStdByteAtXY(ihdr, oss, x, y)               ----237
  845.     local bpsl = getByteWidthPerScanline(ihdr) -- don't include filterType byte -- we don't store that after it has been read
  846.     if (x <= 0) or (y <= 0) then
  847.         return 0 -- this is what the spec says we should return when the coordinate is out of bounds -- in this part of the code, the coordinates are ONE-BASED like in good Lua
  848.     end
  849.     local offset_by_y = (y - 1) * bpsl
  850.     -- now read it!
  851.     local idx = offset_by_y + x
  852.     return oss.str:sub(idx, idx):byte()
  853. end
  854.  
  855. local function __paeth_predictor(a, b, c) --249
  856.     local p = a + b - c
  857.     local pa = math.abs(p - a)
  858.     local pb = math.abs(p - b)
  859.     local pc = math.abs(p - c)
  860.     if pa <= pb and pa <= pc then
  861.         return a
  862.     elseif pb <= pc then
  863.         return b
  864.     else
  865.         return c
  866.     end
  867. end
  868.  
  869. local function __parse_IDAT_effective_bytes(outss, ihdr)    ----265
  870.     local bpsl = getByteWidthPerScanline(ihdr)
  871.     local bypsl = math.ceil(getBitWidthPerPixel(ihdr) / 8)
  872.    
  873.     if outss.str:len() == 0 then
  874.         error("Empty string: outss")
  875.     end
  876.    
  877.     local bys = bytestream_from_string(outss.str)
  878.    
  879.     if not bys then
  880.         error("Did not get a bytestream from string", bys, outss)
  881.     end
  882.    
  883.     local out2 = outssmt.OutStringStream() -- __callable table with metatable that stores what you give it
  884.    
  885.     local y = 0
  886.    
  887.     -- x the byte being filtered;
  888.     -- a the byte corresponding to x in the pixel immediately before the pixel containing x (or the byte immediately before x, when the bit depth is less than 8);
  889.     -- b the byte corresponding to x in the previous scanline;
  890.     -- c the byte corresponding to b in the pixel immediately before the pixel containing b (or the byte immediately before b, when the bit depth is less than 8).
  891.    
  892.     while true do
  893.         local filterType = bys:read()
  894.         if filterType == nil then
  895.             break
  896.         end
  897.         y = y + 1
  898.         for x = 1, bpsl do
  899.             local a = getPNGStdByteAtXY(ihdr, out2, x - bypsl, y)
  900.             local b = getPNGStdByteAtXY(ihdr, out2, x, y - 1)
  901.             local c = getPNGStdByteAtXY(ihdr, out2, x - bypsl, y - 1)
  902.            
  903.             local outVal = 0
  904.            
  905.             if filterType == 0 then outVal = bys:read()
  906.             elseif filterType == 1 then outVal = bys:read() + a
  907.             elseif filterType == 2 then outVal = bys:read() + b
  908.             elseif filterType == 3 then outVal = bys:read() + math.floor((a + b) / 2)
  909.             elseif filterType == 4 then outVal = bys:read() + __paeth_predictor(a, b, c)
  910.             else
  911.                 error("Unsupported Filter Type: " .. tostring(filterType))
  912.             end
  913.             outVal = outVal % 256
  914.             out2(outVal)
  915.         end
  916.     end
  917.    
  918.     return out2
  919. end
  920.  
  921. -- Warning: Co-ordinates are Zero-based but strings are 1-based
  922. function PNGImage:getByteOffsetForPixel(x, y)      ----498
  923.     return (((y * self.ihdr.width) + x) * 4) + 1
  924. end
  925.  
  926. function PNGImage:getPixel(x, y)
  927.     local off = self:getByteOffsetForPixel(x, y)
  928.     return self.data:byte(off, off + 3)
  929. end
  930. --[[
  931. function PNGImage:setPixel(x, y, col)
  932.     local off = self:getByteOffsetForPixel(x, y)
  933.     self.data = table.concat({self.data:sub(1, off - 1), string.char(col[1], col[2], col[3], col[4]), self.data:sub(off + 4)})
  934. end
  935.  
  936. function PNGImage:lineXAB(ax, y, bx, col)
  937.     for x=ax, bx do
  938.         self:setPixel(x, y, col)
  939.     end
  940. end
  941.  
  942. function PNGImage:lineYAB(x, ay, by, col)
  943.     for y=ay, by do
  944.         self:setPixel(x, y, col)
  945.     end
  946. end
  947.  
  948. function PNGImage:lineRectangleAB(ax, ay, bx, by, col)
  949.     self:lineXAB(ax, ay, bx, col)
  950.     self:lineXAB(ax, by, bx, col)
  951.     self:lineYAB(ax, ay, by, col)
  952.     self:lineYAB(bx, ay, by, col)
  953. end
  954.  
  955. function PNGImage:fillRectangleAB(ax, ay, bx, by, col)
  956.     for x=ax, bx do
  957.         for y=ay, by do
  958.             self:setPixel(x, y, col)
  959.         end
  960.     end
  961. end
  962.  
  963. function PNGImage:saveToFile(fn)
  964.     local fh = io.open(fn, 'wb')
  965.     if not fh then
  966.         error("Could not open for writing: " .. fn)
  967.     end
  968.     self:saveToFileHandle(fh)
  969.     fh:close()
  970. end
  971.  
  972. function PNGImage:generateRawIDATData(outbuf)
  973.     for y = 0, self.ihdr.height - 1 do
  974.         outbuf(0) -- filter type is 0 (Filt(x) = Orig(x))
  975.         for x = 0, self.ihdr.width - 1 do
  976.             local r, g, b, a = self:getPixel(x, y)
  977.             outbuf(r)
  978.             outbuf(g)
  979.             outbuf(b)
  980.             outbuf(a)
  981.         end
  982.     end
  983. end
  984. ]]
  985. function PNGImage:getSize()
  986.     return self.ihdr.width, self.ihdr.height
  987. end
  988.  
  989. local function newFromFile(fh)
  990.     local fh = io.open(fh, 'rb')
  991.     if not fh then
  992.         error("Could not open PNG file")
  993.     end
  994.     local pngi = {}
  995.     setmetatable(pngi, PNGImagemetatable)
  996.     local expecting = "\137\080\078\071\013\010\026\010"
  997.     if fh:read(8) ~= expecting then -- check the 8-byte PNG header exists
  998.         error("Not a PNG file")
  999.     end
  1000.    
  1001.     local ihdr
  1002.    
  1003.     local outss = outssmt.OutStringStream()
  1004.    
  1005.     while true do
  1006.         local len = __read_msb_uint32(fh)
  1007.         local stype = fh:read(4)
  1008.         if stype == 'IHDR' then
  1009.             ihdr, msg = __parse_IHDR(fh, len)
  1010.         elseif stype == 'IDAT' then
  1011.             local res, msg = __parse_IDAT(fh, len, ihdr.compression_method, outss)
  1012.         else
  1013.             fh:read(len) -- dummy read
  1014.         end
  1015.         local crc = __read_msb_uint32(fh)
  1016.         if stype == 'IEND' then
  1017.             break
  1018.         end
  1019.     end
  1020.    
  1021.     fh:close()
  1022.    
  1023.     if ihdr.filter_method ~= 0 then
  1024.         error("Unsupported Filter Method: " .. ihdr.filter_method)
  1025.     end
  1026.    
  1027.     if ihdr.interlace_method ~= 0 then
  1028.         error("Unsupported Interlace Method (Interlacing is currently unsupported): " .. ihdr.interlace_method)
  1029.     end
  1030.    
  1031.     if ihdr.color_type ~= 6 --[[TruecolourAlpha]] and ihdr.color_type ~= 2 --[[Truecolour]] then
  1032.         error("Currently, only Truecolour and Truecolour+Alpha images are supported.")
  1033.     end
  1034.    
  1035.     if ihdr.bit_depth ~= 8 then
  1036.         error("Currently, only images with a bit depth of 8 are supported.")
  1037.     end
  1038.        
  1039.     -- now parse the IDAT chunks
  1040.     local out2 = __parse_IDAT_effective_bytes(outss, ihdr)
  1041.    
  1042.     if ihdr.color_type == 2 --[[Truecolour]] then
  1043.         -- add an alpha layer so it effectively becomes RGBA, not RGB
  1044.         local inp = out2.str
  1045.         out2 = outssmt.OutStringStream()
  1046.        
  1047.         for i=1, ihdr.width*ihdr.height do
  1048.             local b = ((i - 1)*3) + 1
  1049.             out2(inp:byte(b)) -- R
  1050.             out2(inp:byte(b + 1)) -- G
  1051.             out2(inp:byte(b + 2)) -- B
  1052.             out2(255) -- A
  1053.         end
  1054.     end
  1055.    
  1056.     pngi.ihdr = ihdr
  1057.     pngi.data = out2.str
  1058.    
  1059.     return pngi
  1060. end
  1061.  
  1062. ------------------ End of libPNGImage ----------------------------
  1063.  
  1064. function graffiti.load(path)
  1065.   checkArg(1,path, "string")
  1066.   local success, pngImageOrErrorMessage = pcall(newFromFile, path)
  1067.   if not success then
  1068.     io.stderr:write(" * PNGView: PNG Loading Error *\n")
  1069.     io.stderr:write("While attempting to load '" .. path .. "' as PNG, libPNGImage erred:\n")
  1070.     error(pngImageOrErrorMessage)
  1071.   end
  1072.   return pngImageOrErrorMessage
  1073. end
  1074.  
  1075. function graffiti.draw(pic,x,y,SizeX,SizeY)
  1076.   checkArg(1,pic,"string","table")
  1077.   checkArg(2, x, "number")
  1078.   checkArg(3, y, "number")
  1079.   checkArg(4, SizeX, "number","nil")
  1080.   checkArg(5, SizeY, "number","nil")
  1081.   if type(pic)=="string" then pic=graffiti.load(pic) end
  1082.  
  1083.   local function alpha(col,r,g,b,a)
  1084.     if a and a > 0 then
  1085.       local b0=col % 256
  1086.       col=math.floor(col/256)
  1087.       local r0, g0 = math.floor(col/256), col % 256
  1088.       r0=math.floor(r0+(r-r0)*a/255+0.5)
  1089.       g0=math.floor(g0+(g-g0)*a/255+0.5)
  1090.       b0=math.floor(b0+(b-b0)*a/255+0.5)
  1091.       return (r0*256 + g0)*256 + b0
  1092.     end
  1093.     return col
  1094.   end
  1095.  
  1096.   local function interpolation(x,y)
  1097.     local x,xf=math.modf(x)
  1098.     local y,yf=math.modf(y)
  1099.     local r1,g1,b1,a1=pic:getPixel(x,y)
  1100.     local r4,g4,b4,a4=r1,g1,b1,a1
  1101.     local r0,g0,b0,a0=r1,g1,b1,a1
  1102.     if xf>0 then
  1103.       local r2,g2,b2,a2=pic:getPixel(x+1,y)
  1104.       if a2 and a2>0 then
  1105.       r4,g4,b4,a4=r4-r2,g4-g2,b4-b2,a4-a2
  1106.       r0,g0,b0,a0=r0+(r2-r1)*xf,g0+(g2-g1)*xf,b0+(b2-b1)*xf,a0+(a2-a1)*xf
  1107.       end
  1108.     end
  1109.     if yf>0 then
  1110.       local r3,g3,b3,a3=pic:getPixel(x,y+1)
  1111.       if a3 and a3>0 then
  1112.       r4,g4,b4,a4=r4-r3,g4-g3,b4-b3,a4-a3
  1113.       r0,g0,b0,a0=r0+(r3-r1)*yf,g0+(g3-g1)*yf,b0+(b3-b1)*yf,a0+(a3-a1)*yf
  1114.       end
  1115.     end
  1116.     if xf>0 and yf>0 then
  1117.       local r5,g5,b5,a5=pic:getPixel(x+1,y+1)
  1118.       if a5 and a5>0 then
  1119.       r0,g0,b0,a0=r0+(r4+r5)*xf*yf,g0+(g4+g5)*xf*yf,b0+(b4+b5)*xf*yf,a0+(a4+a5)*xf*yf
  1120.       end
  1121.     end
  1122.     return r0,g0,b0,a0
  1123.   end
  1124.    
  1125.   local width, height = pic:getSize()
  1126.   SizeX=SizeX or width
  1127.   SizeY=SizeY or SizeX*height/width
  1128.   SizeX=math.floor(SizeX+0.5)
  1129.   SizeY=math.floor(SizeY+0.5)
  1130.   if SizeX<=1 or SizeY<=1 then return end
  1131.   local Fc, Bc = gpu.getForeground(), gpu.getBackground()
  1132.   maxX,maxY=gpu.getResolution()
  1133.   local ScaleX,ScaleY=(width-1)/(SizeX-1), (height-1)/(SizeY-1)
  1134.   local startX,stopX=math.max(1,2-x),math.min(SizeX,maxX-x+1)
  1135.   for j=y % 2,SizeY,2 do
  1136.     local yy=(y+j)/2
  1137.     if yy>=1 and yy<=maxY then
  1138.       for i=startX,stopX do
  1139.         local xx=x+i-1
  1140.         local c,F,B = gpu.get(xx,yy)
  1141.         if c~="▄" then F=B end
  1142.         gpu.setForeground(alpha(F, interpolation((i-1)*ScaleX, j*ScaleY)))
  1143.         gpu.setBackground(alpha(B, interpolation((i-1)*ScaleX, (j-1)*ScaleY)))
  1144.         gpu.set(xx,yy,"▄")
  1145.       end
  1146.     end
  1147.   end
  1148.   gpu.setForeground(Fc)
  1149.   gpu.setBackground(Bc)
  1150. end
  1151.  
  1152. function graffiti.gradient(...)
  1153.   local pngi = {}
  1154.   setmetatable(pngi, PNGImagemetatable)
  1155.   pngi.ihdr={
  1156.     width = 2,
  1157.     height = 2,
  1158.     bit_depth = 8,
  1159.     color_type = 6,
  1160.     compression_method = 0,
  1161.     filter_method = 0,
  1162.     interlace_method = 0
  1163.   }
  1164.   local out2 = outssmt.OutStringStream()
  1165.   local Args={...}
  1166.   for i=1,4 do
  1167.     local col=Args[i]
  1168.     checkArg(i, col, "number")
  1169.     local b0=col % 256
  1170.     col=math.floor(col/256)
  1171.     out2(math.floor(col/256)) -- R
  1172.     out2(col % 256) -- G
  1173.     out2(b0) -- B
  1174.     out2(255) -- A
  1175.   end
  1176.   pngi.data=out2.str
  1177.   return pngi
  1178. end
  1179.  
  1180. return graffiti
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement