Advertisement
theTANCO

bpi.lua

May 14th, 2024 (edited)
469
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 4.04 KB | None | 0 0
  1. --[[ This API is for loading and saving bpi files, which are my solution for
  2. ComputerCraft image files with text, text color, and background color.
  3. "BPI" stands for Better Paint Image.
  4.  
  5. Use 'bpi.load' with a file path to load an image.
  6. The image table is formated as follows:
  7. {
  8.   [y] = { -- Y Coordinate
  9.     [x] = { -- X Coordinate
  10.       text = "c", -- Character
  11.       tCol = "0", -- Text Color
  12.       bCol = "f"  -- Background Color
  13.     }
  14.   }
  15. }
  16. The X and Y coordinates should be positive numbers greater than zero and less
  17. than or equal to 2^128.
  18.  
  19. Use 'bpi.save' with an image table and a file path to save a bpi image.
  20. Each pixel in the save file is formatted as follows:
  21.  
  22. X Length = 4 bits for the length in bytes of the X Coordinate.
  23. Y Length = 4 bits for the legnth in bytes of the Y Coordinate.
  24. X Coordinate = X Length bytes.
  25. Y Coordinate = Y Length bytes.
  26. Text Code = 1 byte for the text character code.
  27. Text Color = 4 bits.
  28. Background Color = 4 bits.
  29.  
  30. Each pixel may be between 5 and 35 total bytes depending on the size of the
  31. coordinates. The pixels are not in any specific order. Empty spaces between
  32. pixels may be treated as transparent pixels.
  33.  
  34. The Class API is required to run this program.
  35. In the ComputerCraft terminal, run the following commands:
  36.   Run 'pastebin get t2TvSiSU /API/Class.lua'
  37.   Run 'pastebin get sSSyDAFm /API/bpi.lua'
  38.  
  39. Check out this post on the ComputerCraft forums to see how this file format can
  40. can be used:
  41. https://forums.computercraft.cc/index.php?topic=536.msg1750
  42. ]]
  43.  
  44. require("/API/Class")
  45.  
  46. bpi = Class(function()
  47. local ro = {}
  48.  
  49. ro.save = function(image, path)
  50.   local bin = {}
  51.   local canSave = true
  52.  
  53.   local addByte = function(n)
  54.     table.insert(bin, #bin+1, n)
  55.   end
  56.  
  57.   local bitShift = function(n)
  58.     local b = {}
  59.     repeat
  60.       table.insert(b, #b+1, bit32.band(n, 0xff))
  61.       n = bit32.rshift(n, 8)
  62.     until n == 0
  63.     canSave = canSave and #b-1 <= 0xf
  64.     -- Can't save if the X or Y coordinate is more than 16 bytes (128 bits)
  65.     return b
  66.   end
  67.  
  68.   for y, a in pairs(image) do
  69.     for x, b in pairs(a) do
  70.       local coords = {bitShift(x-1), bitShift(y-1)}
  71.       addByte((#coords[2]-1) + bit32.lshift(#coords[1]-1, 4))
  72.  
  73.       for i, t in ipairs(coords) do
  74.         for j, v in ipairs(t) do
  75.           addByte(v)
  76.         end
  77.       end
  78.  
  79.       addByte(b.text:byte())
  80.       addByte(tonumber(b.bCol, 16) + bit32.lshift(tonumber(b.tCol, 16), 4))
  81.     end
  82.   end
  83.  
  84.   canSave = canSave and #bin <= fs.getFreeSpace(shell.dir())
  85.   if canSave then
  86.     if path:sub(#path-3) ~= ".bpi" then
  87.       path = path .. ".bpi"
  88.     end
  89.     local f = fs.open(path, "wb")
  90.     if f then
  91.       for i, v in ipairs(bin) do
  92.         f.write(v)
  93.       end
  94.       f.close()
  95.       return 0 -- Save successful
  96.     else return 1 end -- Unknown error
  97.   else return 2 end -- Image is too big/Out of space
  98. end
  99.  
  100. ro.load = function(path)
  101.   if path:sub(#path-3) ~= ".bpi" then
  102.     path = path .. ".bpi"
  103.   end
  104.   if fs.exists(path) then
  105.     local bin = {}
  106.     local image = {}
  107.  
  108.     local f = fs.open(path, "rb")
  109.     repeat
  110.       local line = f.read()
  111.       table.insert(bin, #bin+1, line)
  112.     until line == nil
  113.     f.close()
  114.  
  115.     local removeByte = function()
  116.       local n = bin[1]
  117.       table.remove(bin, 1)
  118.       return n
  119.     end
  120.  
  121.     local bitShift = function(l)
  122.       local n = 0
  123.       for i = 0, l do
  124.         n = n + bit32.lshift(removeByte(), i*8)
  125.       end
  126.       return n
  127.     end
  128.  
  129.     while #bin > 0 do
  130.       local coordLength = removeByte()
  131.       local teleX = bitShift(bit32.rshift(bit32.band(coordLength, 0xf0), 4))+1
  132.       local teleY = bitShift(bit32.band(coordLength, 0x0f))+1
  133.       image[teleY] = image[teleY] or {}
  134.       image[teleY][teleX] = {}
  135.       image[teleY][teleX].text = string.char(removeByte())
  136.       local c = string.format("%02x", removeByte())
  137.       image[teleY][teleX].tCol = c:sub(1, 1)
  138.       image[teleY][teleX].bCol = c:sub(2, 2)
  139.     end
  140.     return image
  141.   else
  142.     error("File not found", 2)
  143.   end
  144. end
  145.  
  146. return {
  147.   protected = true,
  148.   readOnly = ro
  149. }
  150. end)()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement