Advertisement
astral17

OCPaintScriptOCIF

Nov 14th, 2016
165
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 45.58 KB | None | 0 0
  1. ---------------------------------------- OpenComputers Image Format (OCIF) -----------------------------------------------------------
  2.  
  3. --[[
  4.  
  5.   Автор: Pornogion
  6.     VK: https://vk.com/id88323331
  7.   Соавтор: IT
  8.     VK: https://vk.com/id7799889
  9.  
  10.  
  11. ]]
  12. local serialization = {}
  13.  
  14. -- Important: pretty formatting will allow presenting non-serializable values
  15. -- but may generate output that cannot be unserialized back.
  16. function serialization.serialize(value, pretty)
  17.   local kw =  {["and"]=true, ["break"]=true, ["do"]=true, ["else"]=true,
  18.                ["elseif"]=true, ["end"]=true, ["false"]=true, ["for"]=true,
  19.                ["function"]=true, ["goto"]=true, ["if"]=true, ["in"]=true,
  20.                ["local"]=true, ["nil"]=true, ["not"]=true, ["or"]=true,
  21.                ["repeat"]=true, ["return"]=true, ["then"]=true, ["true"]=true,
  22.                ["until"]=true, ["while"]=true}
  23.   local id = "^[%a_][%w_]*$"
  24.   local ts = {}
  25.   local function s(v, l)
  26.     local t = type(v)
  27.     if t == "nil" then
  28.       return "nil"
  29.     elseif t == "boolean" then
  30.       return v and "true" or "false"
  31.     elseif t == "number" then
  32.       if v ~= v then
  33.         return "0/0"
  34.       elseif v == math.huge then
  35.         return "math.huge"
  36.       elseif v == -math.huge then
  37.         return "-math.huge"
  38.       else
  39.         return tostring(v)
  40.       end
  41.     elseif t == "string" then
  42.       return string.format("%q", v):gsub("\\\n","\\n")
  43.     elseif t == "table" and pretty and getmetatable(v) and getmetatable(v).__tostring then
  44.       return tostring(v)
  45.     elseif t == "table" then
  46.       if ts[v] then
  47.         if pretty then
  48.           return "recursion"
  49.         else
  50.           error("tables with cycles are not supported")
  51.         end
  52.       end
  53.       ts[v] = true
  54.       local i, r = 1, nil
  55.       local f
  56.       if pretty then
  57.         local ks, sks, oks = {}, {}, {}
  58.         for k in pairs(v) do
  59.           if type(k) == "number" then
  60.             table.insert(ks, k)
  61.           elseif type(k) == "string" then
  62.             table.insert(sks, k)
  63.           else
  64.             table.insert(oks, k)
  65.           end
  66.         end
  67.         table.sort(ks)
  68.         table.sort(sks)
  69.         for _, k in ipairs(sks) do
  70.           table.insert(ks, k)
  71.         end
  72.         for _, k in ipairs(oks) do
  73.           table.insert(ks, k)
  74.         end
  75.         local n = 0
  76.         f = table.pack(function()
  77.           n = n + 1
  78.           local k = ks[n]
  79.           if k ~= nil then
  80.             return k, v[k]
  81.           else
  82.             return nil
  83.           end
  84.         end)
  85.       else
  86.         f = table.pack(pairs(v))
  87.       end
  88.       for k, v in table.unpack(f) do
  89.         if r then
  90.           r = r .. "," .. (pretty and ("\n" .. string.rep(" ", l)) or "")
  91.         else
  92.           r = "{"
  93.         end
  94.         local tk = type(k)
  95.         if tk == "number" and k == i then
  96.           i = i + 1
  97.           r = r .. s(v, l + 1)
  98.         else
  99.           if tk == "string" and not kw[k] and string.match(k, id) then
  100.             r = r .. k
  101.           else
  102.             r = r .. "[" .. s(k, l + 1) .. "]"
  103.           end
  104.           r = r .. "=" .. s(v, l + 1)
  105.         end
  106.       end
  107.       ts[v] = nil -- allow writing same table more than once
  108.       return (r or "{") .. "}"
  109.     else
  110.       if pretty then
  111.         return tostring(t)
  112.       else
  113.         error("unsupported type: " .. t)
  114.       end
  115.     end
  116.   end
  117.   local result = s(value, 1)
  118.   local limit = type(pretty) == "number" and pretty or 10
  119.   if pretty then
  120.     local truncate = 0
  121.     while limit > 0 and truncate do
  122.       truncate = string.find(result, "\n", truncate + 1, true)
  123.       limit = limit - 1
  124.     end
  125.     if truncate then
  126.       return result:sub(1, truncate) .. "..."
  127.     end
  128.   end
  129.   return result
  130. end
  131.  
  132. function serialization.unserialize(data)
  133.   checkArg(1, data, "string")
  134.   local result, reason = load("return " .. data, "=data", _, {math={huge=math.huge}})
  135.   if not result then
  136.     return nil, reason
  137.   end
  138.   local ok, output = pcall(result)
  139.   if not ok then
  140.     return nil, output
  141.   end
  142.   return output
  143. end
  144.  
  145. local colorlib = {}
  146. local serialization = require("serialization")
  147.  
  148. local function isNan(x)
  149.   return x~=x
  150. end
  151.  
  152. --RGB model
  153. function colorlib.HEXtoRGB(color)
  154.   color = math.floor(color)
  155.  
  156.   local rr = bit32.rshift( color, 16 )
  157.   local gg = bit32.rshift( bit32.band(color, 0x00ff00), 8 )
  158.   local bb = bit32.band(color, 0x0000ff)
  159.  
  160.   return rr, gg, bb
  161. end
  162.  
  163. function colorlib.RGBtoHEX(rr, gg, bb)
  164.   return bit32.lshift(rr, 16) + bit32.lshift(gg, 8) + bb
  165. end
  166.  
  167. --HSB model
  168. function colorlib.RGBtoHSB(rr, gg, bb)
  169.   local max = math.max(rr, math.max(gg, bb))
  170.   local min = math.min(rr, math.min(gg, bb))
  171.   local delta = max - min
  172.  
  173.   local h = 0
  174.   if ( max == rr and gg >= bb) then h = 60*(gg-bb)/delta end
  175.   if ( max == rr and gg <= bb ) then h = 60*(gg-bb)/delta + 360 end
  176.   if ( max == gg ) then h = 60*(bb-rr)/delta + 120 end
  177.   if ( max == bb ) then h = 60*(rr-gg)/delta + 240 end
  178.  
  179.   local s = 0
  180.   if ( max ~= 0 ) then s = 1-(min/max) end
  181.  
  182.   local b = max*100/255
  183.  
  184.   if isNan(h) then h = 0 end
  185.  
  186.   return h, s*100, b
  187. end
  188.  
  189. function colorlib.HSBtoRGB(h, s, v)
  190.   if h > 359 then h = 0 end
  191.   local rr, gg, bb = 0, 0, 0
  192.   local const = 255
  193.  
  194.   s = s/100
  195.   v = v/100
  196.  
  197.   local i = math.floor(h/60)
  198.   local f = h/60 - i
  199.  
  200.   local p = v*(1-s)
  201.   local q = v*(1-s*f)
  202.   local t = v*(1-(1-f)*s)
  203.  
  204.   if ( i == 0 ) then rr, gg, bb = v, t, p end
  205.   if ( i == 1 ) then rr, gg, bb = q, v, p end
  206.   if ( i == 2 ) then rr, gg, bb = p, v, t end
  207.   if ( i == 3 ) then rr, gg, bb = p, q, v end
  208.   if ( i == 4 ) then rr, gg, bb = t, p, v end
  209.   if ( i == 5 ) then rr, gg, bb = v, p, q end
  210.  
  211.   return math.floor(rr * const), math.floor(gg * const), math.floor(bb * const)
  212. end
  213.  
  214. function colorlib.HEXtoHSB(color)
  215.   local rr, gg, bb = colorlib.HEXtoRGB(color)
  216.   local h, s, b = colorlib.RGBtoHSB( rr, gg, bb )
  217.  
  218.   return h, s, b
  219. end
  220.  
  221. function colorlib.HSBtoHEX(h, s, b)
  222.   local rr, gg, bb = colorlib.HSBtoRGB(h, s, b)
  223.   local color = colorlib.RGBtoHEX(rr, gg, bb)
  224.  
  225.   return color
  226. end
  227.  
  228. --Смешивание двух цветов на основе альфа-канала второго
  229. function colorlib.alphaBlend(firstColor, secondColor, alphaChannel)
  230.   local invertedAlphaChannelDividedBy255 = (255 - alphaChannel) / 255
  231.   alphaChannel = alphaChannel / 255
  232.  
  233.   local firstColorRed, firstColorGreen, firstColorBlue = colorlib.HEXtoRGB(firstColor)
  234.   local secondColorRed, secondColorGreen, secondColorBlue = colorlib.HEXtoRGB(secondColor)
  235.  
  236.   return colorlib.RGBtoHEX(
  237.     secondColorRed * invertedAlphaChannelDividedBy255 + firstColorRed * alphaChannel,
  238.     secondColorGreen * invertedAlphaChannelDividedBy255 + firstColorGreen * alphaChannel,
  239.     secondColorBlue * invertedAlphaChannelDividedBy255 + firstColorBlue * alphaChannel
  240.   )
  241. end
  242.  
  243. --Получение среднего цвета между перечисленными. К примеру, между черным и белым выдаст серый.
  244. function colorlib.getAverageColor(...)
  245.   local colors = {...}
  246.   local averageRed, averageGreen, averageBlue = 0, 0, 0
  247.   for i = 1, #colors do
  248.     local r, g, b = colorlib.HEXtoRGB(colors[i])
  249.     averageRed, averageGreen, averageBlue = averageRed + r, averageGreen + g, averageBlue + b
  250.   end
  251.   return colorlib.RGBtoHEX(math.floor(averageRed / #colors), math.floor(averageGreen / #colors), math.floor(averageBlue / #colors))
  252. end
  253.  
  254. -----------------------------------------------------------------------------------------------------------------------
  255.  
  256. local palette = {
  257.   0x000000, 0x000040, 0x000080, 0x0000BF, 0x0000FF, 0x002400, 0x002440, 0x002480, 0x0024BF, 0x0024FF, 0x004900, 0x004940, 0x004980, 0x0049BF, 0x0049FF, 0x006D00,
  258.   0x006D40, 0x006D80, 0x006DBF, 0x006DFF, 0x009200, 0x009240, 0x009280, 0x0092BF, 0x0092FF, 0x00B600, 0x00B640, 0x00B680, 0x00B6BF, 0x00B6FF, 0x00DB00, 0x00DB40,
  259.   0x00DB80, 0x00DBBF, 0x00DBFF, 0x00FF00, 0x00FF40, 0x00FF80, 0x00FFBF, 0x00FFFF, 0x0F0F0F, 0x1E1E1E, 0x2D2D2D, 0x330000, 0x330040, 0x330080, 0x3300BF, 0x3300FF,
  260.   0x332400, 0x332440, 0x332480, 0x3324BF, 0x3324FF, 0x334900, 0x334940, 0x334980, 0x3349BF, 0x3349FF, 0x336D00, 0x336D40, 0x336D80, 0x336DBF, 0x336DFF, 0x339200,
  261.   0x339240, 0x339280, 0x3392BF, 0x3392FF, 0x33B600, 0x33B640, 0x33B680, 0x33B6BF, 0x33B6FF, 0x33DB00, 0x33DB40, 0x33DB80, 0x33DBBF, 0x33DBFF, 0x33FF00, 0x33FF40,
  262.   0x33FF80, 0x33FFBF, 0x33FFFF, 0x3C3C3C, 0x4B4B4B, 0x5A5A5A, 0x660000, 0x660040, 0x660080, 0x6600BF, 0x6600FF, 0x662400, 0x662440, 0x662480, 0x6624BF, 0x6624FF,
  263.   0x664900, 0x664940, 0x664980, 0x6649BF, 0x6649FF, 0x666D00, 0x666D40, 0x666D80, 0x666DBF, 0x666DFF, 0x669200, 0x669240, 0x669280, 0x6692BF, 0x6692FF, 0x66B600,
  264.   0x66B640, 0x66B680, 0x66B6BF, 0x66B6FF, 0x66DB00, 0x66DB40, 0x66DB80, 0x66DBBF, 0x66DBFF, 0x66FF00, 0x66FF40, 0x66FF80, 0x66FFBF, 0x66FFFF, 0x696969, 0x787878,
  265.   0x878787, 0x969696, 0x990000, 0x990040, 0x990080, 0x9900BF, 0x9900FF, 0x992400, 0x992440, 0x992480, 0x9924BF, 0x9924FF, 0x994900, 0x994940, 0x994980, 0x9949BF,
  266.   0x9949FF, 0x996D00, 0x996D40, 0x996D80, 0x996DBF, 0x996DFF, 0x999200, 0x999240, 0x999280, 0x9992BF, 0x9992FF, 0x99B600, 0x99B640, 0x99B680, 0x99B6BF, 0x99B6FF,
  267.   0x99DB00, 0x99DB40, 0x99DB80, 0x99DBBF, 0x99DBFF, 0x99FF00, 0x99FF40, 0x99FF80, 0x99FFBF, 0x99FFFF, 0xA5A5A5, 0xB4B4B4, 0xC3C3C3, 0xCC0000, 0xCC0040, 0xCC0080,
  268.   0xCC00BF, 0xCC00FF, 0xCC2400, 0xCC2440, 0xCC2480, 0xCC24BF, 0xCC24FF, 0xCC4900, 0xCC4940, 0xCC4980, 0xCC49BF, 0xCC49FF, 0xCC6D00, 0xCC6D40, 0xCC6D80, 0xCC6DBF,
  269.   0xCC6DFF, 0xCC9200, 0xCC9240, 0xCC9280, 0xCC92BF, 0xCC92FF, 0xCCB600, 0xCCB640, 0xCCB680, 0xCCB6BF, 0xCCB6FF, 0xCCDB00, 0xCCDB40, 0xCCDB80, 0xCCDBBF, 0xCCDBFF,
  270.   0xCCFF00, 0xCCFF40, 0xCCFF80, 0xCCFFBF, 0xCCFFFF, 0xD2D2D2, 0xE1E1E1, 0xF0F0F0, 0xFF0000, 0xFF0040, 0xFF0080, 0xFF00BF, 0xFF00FF, 0xFF2400, 0xFF2440, 0xFF2480,
  271.   0xFF24BF, 0xFF24FF, 0xFF4900, 0xFF4940, 0xFF4980, 0xFF49BF, 0xFF49FF, 0xFF6D00, 0xFF6D40, 0xFF6D80, 0xFF6DBF, 0xFF6DFF, 0xFF9200, 0xFF9240, 0xFF9280, 0xFF92BF,
  272.   0xFF92FF, 0xFFB600, 0xFFB640, 0xFFB680, 0xFFB6BF, 0xFFB6FF, 0xFFDB00, 0xFFDB40, 0xFFDB80, 0xFFDBBF, 0xFFDBFF, 0xFFFF00, 0xFFFF40, 0xFFFF80, 0xFFFFBF, 0xFFFFFF,
  273. }
  274.  
  275. function colorlib.convert24BitTo8Bit(hex24)
  276.   local encodedIndex = nil
  277.   local colorMatchFactor = nil
  278.   local colorMatchFactor_min = math.huge
  279.  
  280.   local red24, green24, blue24 = colorlib.HEXtoRGB(hex24)
  281.  
  282.   for colorIndex, colorPalette in ipairs(palette) do
  283.     local redPalette, greenPalette, bluePalette = colorlib.HEXtoRGB(colorPalette)
  284.  
  285.     colorMatchFactor = (redPalette-red24)^2 + (greenPalette-green24)^2 + (bluePalette-blue24)^2
  286.  
  287.     if (colorMatchFactor < colorMatchFactor_min) then
  288.       encodedIndex = colorIndex
  289.       colorMatchFactor_min = colorMatchFactor
  290.     end
  291.   end
  292.    
  293.   return encodedIndex - 1
  294.   -- return searchClosestColor(1, #palette, hex24)
  295. end
  296.  
  297. function colorlib.convert8BitTo24Bit(hex8)
  298.   return palette[hex8 + 1]
  299. end
  300.  
  301. function colorlib.debugColorCompression(color)
  302.   local compressedColor = colorlib.convert24BitTo8Bit(color)
  303.   local decompressedColor = colorlib.convert8BitTo24Bit(compressedColor)
  304.   print("Исходный цвет: " .. string.format("0x%06X", color))
  305.   print("Сжатый цвет: " .. string.format("0x%02X", compressedColor))
  306.   print("Расжатый цвет: " .. string.format("0x%06X", decompressedColor))
  307. end
  308.  
  309.  
  310. -----------------------------------------------------------------------------------------------------------------------
  311.  
  312. --------------------------------------- Подгрузка библиотек --------------------------------------------------------------
  313.  
  314. -- Адаптивная загрузка необходимых библиотек и компонентов
  315. local libraries = {
  316. --  bit32 = "bit32",
  317. }
  318.  
  319. --for library in pairs(libraries) do if not _G[library] then _G[library] = require(libraries[library]) end end; libraries = nil
  320. local unicode=require("unicode")
  321.  
  322.  
  323. local image = {}
  324.  
  325. -------------------------------------------- Переменные -------------------------------------------------------------------
  326.  
  327. --Константы программы
  328. local constants = {
  329.   OCIFSignature = "OCIF",
  330.   OCIF2Elements = {
  331.     alphaStart = "A",
  332.     symbolStart = "S",
  333.     backgroundStart = "B",
  334.     foregroundStart = "F",
  335.   },
  336.   elementCount = 4,
  337.   byteSize = 8,
  338.   nullChar = 0,
  339.   rawImageLoadStep = 19,
  340.   compressedFileFormat = ".pic",
  341.   pngFileFormat = ".png",
  342. }
  343.  
  344. ---------------------------------------- Локальные функции -------------------------------------------------------------------
  345.  
  346. --Формула конвертации индекса массива изображения в абсолютные координаты пикселя изображения
  347. local function convertIndexToCoords(index, width)
  348.   --Приводим индекс к корректному виду (1 = 1, 4 = 2, 7 = 3, 10 = 4, 13 = 5, ...)
  349.   index = (index + constants.elementCount - 1) / constants.elementCount
  350.   --Получаем остаток от деления индекса на ширину изображения
  351.   local ostatok = index % width
  352.   --Если остаток равен 0, то х равен ширине изображения, а если нет, то х равен остатку
  353.   local x = (ostatok == 0) and width or ostatok
  354.   --А теперь как два пальца получаем координату по Y
  355.   local y = math.ceil(index / width)
  356.   --Очищаем остаток из оперативки
  357.   ostatok = nil
  358.   --Возвращаем координаты
  359.   return x, y
  360. end
  361.  
  362. --Формула конвертации абсолютных координат пикселя изображения в индекс для массива изображения
  363. local function convertCoordsToIndex(x, y, width)
  364.   return (width * (y - 1) + x) * constants.elementCount - constants.elementCount + 1
  365. end
  366.  
  367. --Костыльное получение размера массива, ибо автор луа не позволяет
  368. --подсчитывать ненумерические индексы через #massiv
  369. --мда, мда
  370. --...
  371. --мда
  372. local function getArraySize(array)
  373.   local size = 0
  374.   for key in pairs(array) do
  375.     size = size + 1
  376.   end
  377.   return size
  378. end
  379.  
  380. --Получить количество байт, которое можно извлечь из указанного числа
  381. local function getCountOfBytes(number)
  382.   if number == 0 or number == 1 then return 1 end
  383.   return math.ceil(math.log(number, 256))
  384. end
  385.  
  386. --Распидорасить число на составляющие байты
  387. local function extractBytesFromNumber(number, countOfBytesToExtract)
  388.   local bytes = {}
  389.   local byteCutter = 0xff
  390.   for i = 1, countOfBytesToExtract do
  391.     table.insert(bytes, 1, bit32.rshift(bit32.band(number, byteCutter), (i-1)*8))
  392.     byteCutter = bit32.lshift(byteCutter, 8)
  393.   end
  394.   return table.unpack(bytes)
  395. end
  396.  
  397. --Склеить байты и создать из них число
  398. local function mergeBytesToNumber(...)
  399.   local bytes = {...}
  400.   local finalNumber = bytes[1]
  401.   for i = 2, #bytes do
  402.     finalNumber = bit32.bor(bit32.lshift(finalNumber, 8), bytes[i])
  403.   end
  404.   return finalNumber
  405. end
  406.  
  407. -- Сконвертировать все переданные байты в строку
  408. local function convertBytesToString(...)
  409.   local bytes = {...}
  410.   for i = 1, #bytes do
  411.     bytes[i] = string.char(bytes[i])
  412.   end
  413.   return table.concat(bytes)
  414. end
  415.  
  416. --Выделить бит-терминатор в первом байте UTF-8 символа: 1100 0010 --> 0010 0000
  417. local function selectTerminateBit_l()
  418.   local prevByte = nil
  419.   local prevTerminateBit = nil
  420.  
  421.   return function( byte )
  422.     local x, terminateBit = nil
  423.     if ( prevByte == byte ) then
  424.       return prevTerminateBit
  425.     end
  426.  
  427.     x = bit32.band( bit32.bnot(byte), 0x000000FF )
  428.     x = bit32.bor( x, bit32.rshift(x, 1) )
  429.     x = bit32.bor( x, bit32.rshift(x, 2) )
  430.     x = bit32.bor( x, bit32.rshift(x, 4) )
  431.     x = bit32.bor( x, bit32.rshift(x, 8) )
  432.     x = bit32.bor( x, bit32.rshift(x, 16) )
  433.  
  434.     terminateBit = x - bit32.rshift(x, 1)
  435.  
  436.     prevByte = byte
  437.     prevTerminateBit = terminateBit
  438.  
  439.     return terminateBit
  440.   end
  441. end
  442. local selectTerminateBit = selectTerminateBit_l()
  443.  
  444. --Прочитать n байтов из файла, возвращает прочитанные байты как число, если не удалось прочитать, то возвращает 0
  445. local function readBytes(file, count)
  446.   local readedBytes = file:read(count)
  447.   return mergeBytesToNumber(string.byte(readedBytes, 1, count))
  448. end
  449.  
  450. --Подготавливает цвета и символ для записи в файл сжатого формата
  451. local function encodePixel(background, foreground, alpha, char)
  452.   --Расхерачиваем жирные цвета в компактные цвета
  453.   local ascii_background1, ascii_background2, ascii_background3 = colorlib.HEXtoRGB(background)
  454.   local ascii_foreground1, ascii_foreground2, ascii_foreground3 = colorlib.HEXtoRGB(foreground)
  455.   --Расхерачиваем жирный код юникод-символа в несколько миленьких ascii-кодов
  456.   local ascii_char1, ascii_char2, ascii_char3, ascii_char4, ascii_char5, ascii_char6 = string.byte( char, 1, 6 )
  457.   ascii_char1 = ascii_char1 or constants.nullChar
  458.   --Возвращаем все расхераченное
  459.   return ascii_background1, ascii_background2, ascii_background3, ascii_foreground1, ascii_foreground2, ascii_foreground3, alpha, ascii_char1, ascii_char2, ascii_char3, ascii_char4, ascii_char5, ascii_char6
  460. end
  461.  
  462. --Декодирование UTF-8 символа
  463. local function decodeChar(file)
  464.   local first_byte = readBytes(file, 1)
  465.   local charcode_array = {first_byte}
  466.   local len = 1
  467.  
  468.   local middle = selectTerminateBit(first_byte)
  469.   if ( middle == 32 ) then
  470.     len = 2
  471.   elseif ( middle == 16 ) then
  472.     len = 3
  473.   elseif ( middle == 8 ) then
  474.     len = 4
  475.   elseif ( middle == 4 ) then
  476.     len = 5
  477.   elseif ( middle == 2 ) then
  478.     len = 6
  479.   end
  480.  
  481.   for i = 1, len-1 do
  482.     table.insert( charcode_array, readBytes(file, 1) )
  483.   end
  484.  
  485.   return string.char( table.unpack( charcode_array ) )
  486. end
  487.  
  488. --Правильное конвертирование HEX-переменной в строковую
  489. local function HEXtoSTRING(color, bitCount, withNull)
  490.   local stro4ka = string.format("%X",color)
  491.   local sStro4ka = unicode.len(stro4ka)
  492.  
  493.   if sStro4ka < bitCount then
  494.     stro4ka = string.rep("0", bitCount - sStro4ka) .. stro4ka
  495.   end
  496.  
  497.   sStro4ka = nil
  498.  
  499.   if withNull then return "0x"..stro4ka else return stro4ka end
  500. end
  501.  
  502. --Получение формата файла
  503. local function getFileFormat(path)
  504.   local name = fs.name(path)
  505.   local starting, ending = string.find(name, "(.)%.[%d%w]*$")
  506.   if starting == nil then
  507.     return nil
  508.   else
  509.     return unicode.sub(name, starting + 1, -1)
  510.   end
  511.   name, starting, ending = nil, nil, nil
  512. end
  513.  
  514. --Прочесть сигнатуру файла и сравнить ее с константой
  515. local function readSignature(file)
  516.   local readedSignature = file:read(4)
  517.   if readedSignature ~= constants.OCIFSignature then
  518.     file:close()
  519.     error("Can't load file: wrong OCIF format signature (\""..readedSignature .. "\" ~= \"" ..constants.OCIFSignature .. "\")")
  520.   end
  521. end
  522.  
  523. --Записать сигнатуру в файл
  524. local function writeSignature(file)
  525.   file:write(constants.OCIFSignature)
  526. end
  527.  
  528. --Сжать все цвета в изображении в 8-битную палитру
  529. local function convertImageColorsTo8Bit(picture)
  530.   for i = 1, #picture, 4 do
  531.     picture[i] = colorlib.convert24BitTo8Bit(picture[i])
  532.     picture[i + 1] = colorlib.convert24BitTo8Bit(picture[i + 1])
  533.     if i % 505 == 0 then os.sleep(0) end
  534.   end
  535.   return picture
  536. end
  537.  
  538. --Расжать все цвета в изображении в 24-битную палитру
  539. local function convertImageColorsTo24Bit(picture)
  540.   for i = 1, #picture, 4 do
  541.     picture[i] = colorlib.convert8BitTo24Bit(picture[i])
  542.     picture[i + 1] = colorlib.convert8BitTo24Bit(picture[i + 1])
  543.     if i % 505 == 0 then os.sleep(0) end
  544.   end
  545.   return picture
  546. end
  547.  
  548. ------------------------------ Все, что касается формата OCIF1 ------------------------------------------------------------
  549.  
  550. -- Запись в файл сжатого OCIF-формата изображения
  551. local function saveOCIF1(file, picture)
  552.   local encodedPixel
  553.   file:write( string.char( picture.width  ) )
  554.   file:write( string.char( picture.height ) )
  555.  
  556.   for i = 1, picture.width * picture.height * constants.elementCount, constants.elementCount do
  557.     encodedPixel =
  558.     {
  559.       encodePixel(picture[i], picture[i + 1], picture[i + 2], picture[i + 3])
  560.     }
  561.     for j = 1, #encodedPixel do
  562.       file:write( string.char( encodedPixel[j] ) )
  563.     end
  564.   end
  565.  
  566.   file:close()
  567. end
  568.  
  569. --Чтение из файла сжатого OCIF-формата изображения, возвращает массив типа 2 (подробнее о типах см. конец файла)
  570. local function loadOCIF1(file)
  571.   local picture = {}
  572.  
  573.   --Читаем ширину и высоту файла
  574.   picture.width = readBytes(file, 1)
  575.   picture.height = readBytes(file, 1)
  576.  
  577.   for i = 1, picture.width * picture.height do
  578.     --Читаем бекграунд
  579.     table.insert(picture, readBytes(file, 3))
  580.     --Читаем форграунд
  581.     table.insert(picture, readBytes(file, 3))
  582.     --Читаем альфу
  583.     table.insert(picture, readBytes(file, 1))
  584.     --Читаем символ
  585.     table.insert(picture, decodeChar( file ))
  586.   end
  587.  
  588.   file:close()
  589.  
  590.   return picture
  591. end
  592.  
  593. ------------------------------------------ Все, что касается формата OCIF2 ------------------------------------------------
  594.  
  595. local function saveOCIF2(file, picture, compressColors)
  596.   --Записываем ширину изображения
  597.   file:write(string.char(picture.width))
  598.   file:write(string.char(picture.height))
  599.  
  600.   --Группируем картинку
  601.   local grouppedPucture = image.convertToGroupedImage(picture)
  602.  
  603.   --Перебираем все альфы
  604.   for alpha in pairs(grouppedPucture) do
  605.     --Получаем размер массива, содержащего символы
  606.     local arraySize = getArraySize(grouppedPucture[alpha])
  607.     local countOfBytesForArraySize = getCountOfBytes(arraySize)
  608.     --Записываем в файл символ АльфаСтарта, размер массива альфы и само значение альфы
  609.     file:write(
  610.       constants.OCIF2Elements.alphaStart,
  611.       string.char(countOfBytesForArraySize),
  612.       convertBytesToString(extractBytesFromNumber(arraySize, countOfBytesForArraySize)),
  613.       string.char(alpha)
  614.     )
  615.    
  616.     for symbol in pairs(grouppedPucture[alpha]) do
  617.       --Записываем заголовок
  618.       file:write(constants.OCIF2Elements.symbolStart)
  619.       --Записываем количество всех цветов текста и символ
  620.       if compressColors then
  621.         file:write(
  622.           string.char(getArraySize(grouppedPucture[alpha][symbol])),
  623.           convertBytesToString(string.byte(symbol, 1, 6))
  624.         )
  625.       else
  626.         file:write(
  627.           convertBytesToString(extractBytesFromNumber(getArraySize(grouppedPucture[alpha][symbol]), 3)),
  628.           convertBytesToString(string.byte(symbol, 1, 6))
  629.         )
  630.       end
  631.    
  632.       for foreground in pairs(grouppedPucture[alpha][symbol]) do
  633.         --Записываем заголовок
  634.         file:write(constants.OCIF2Elements.foregroundStart)
  635.         --Записываем количество цветов фона и цвет текста
  636.         if compressColors then
  637.           file:write(
  638.             string.char(getArraySize(grouppedPucture[alpha][symbol][foreground])),
  639.             string.char(foreground)
  640.           )
  641.         else
  642.           file:write(
  643.             convertBytesToString(extractBytesFromNumber(getArraySize(grouppedPucture[alpha][symbol][foreground]), 3)),
  644.             convertBytesToString(extractBytesFromNumber(foreground, 3))
  645.           )
  646.         end
  647.    
  648.         for background in pairs(grouppedPucture[alpha][symbol][foreground]) do
  649.           --Записываем заголовок и размер массива координат
  650.           file:write(
  651.               constants.OCIF2Elements.backgroundStart,
  652.               convertBytesToString(extractBytesFromNumber(getArraySize(grouppedPucture[alpha][symbol][foreground][background]), 2))
  653.           )
  654.           --Записываем цвет фона
  655.           if compressColors then
  656.             file:write(string.char(background))
  657.           else
  658.             file:write(convertBytesToString(extractBytesFromNumber(background, 3)))
  659.           end
  660.      
  661.           --Перебираем координаты
  662.           for y in pairs(grouppedPucture[alpha][symbol][foreground][background]) do
  663.             --Записываем заголовок координат, размер массива y и само значение y
  664.             file:write(
  665.               "Y",
  666.               string.char(getArraySize(grouppedPucture[alpha][symbol][foreground][background][y])),
  667.               string.char(y)
  668.             )
  669.             --Записываем ИКСЫЫЫ
  670.             --Ы
  671.             for i = 1, #grouppedPucture[alpha][symbol][foreground][background][y] do
  672.               file:write(string.char(grouppedPucture[alpha][symbol][foreground][background][y][i]))
  673.             end
  674.           end
  675.         end
  676.       end
  677.     end
  678.   end
  679.  
  680.   file:close()
  681. end
  682.  
  683. local function loadOCIF2(file, decompressColors, useOCIF4)
  684.   local picture = {}
  685.  
  686.   --Читаем размер изображения
  687.   local readedWidth = string.byte(file:read(1))
  688.   local readedHeight = string.byte(file:read(1))
  689.   picture.width = readedWidth
  690.   picture.height = readedHeight
  691.  
  692.   local header, alpha, symbol, foreground, background, y, alphaSize, symbolSize, foregroundSize, backgroundSize, ySize = ""
  693.   while true do
  694.     header = file:read(1)
  695.     if not header then break end
  696.     -- print("----------------------")
  697.     -- print("Заголовок: " .. header)
  698.  
  699.     if header == "A" then
  700.       local countOfBytesForArraySize = string.byte(file:read(1))
  701.       alphaSize = string.byte(file:read(countOfBytesForArraySize))
  702.       alpha = string.byte(file:read(1))
  703.       -- print("Количество байт под размер массива символов: " .. countOfBytesForArraySize)
  704.       -- print("Размер массива символов: " .. alphaSize)
  705.       -- print("Альфа: " .. alpha)
  706.  
  707.     elseif header == "S" then
  708.       if decompressColors then
  709.         symbolSize = string.byte(file:read(1))
  710.       else
  711.         symbolSize = mergeBytesToNumber(string.byte(file:read(3), 1, 3))
  712.       end
  713.       symbol = decodeChar(file)
  714.       -- print("Размер массива цвета текста: " .. symbolSize)
  715.       -- print("Символ: \"" .. symbol .. "\"")
  716.  
  717.     elseif header == "F" then
  718.       if decompressColors then
  719.         foregroundSize = string.byte(file:read(1))
  720.         foreground = colorlib.convert8BitTo24Bit(string.byte(file:read(1)))
  721.       else
  722.         foregroundSize = mergeBytesToNumber(string.byte(file:read(3), 1, 3))
  723.         foreground = mergeBytesToNumber(string.byte(file:read(3), 1, 3))
  724.       end
  725.       -- print("Размер массива цвета фона: " .. foregroundSize)
  726.       -- print("Цвет текста: " .. foreground)
  727.  
  728.     elseif header == "B" then
  729.       backgroundSize = mergeBytesToNumber(string.byte(file:read(2), 1, 2))
  730.       if decompressColors then
  731.         background = colorlib.convert8BitTo24Bit(string.byte(file:read(1)))
  732.       else
  733.         background = mergeBytesToNumber(string.byte(file:read(3), 1, 3))
  734.       end
  735.       -- print("Размер массива координат: " .. backgroundSize)
  736.       -- print("Цвет фона: " .. background)
  737.  
  738.       --Поддержка загрузки формата OCIF3
  739.       if not useOCIF4 then
  740.         --Читаем координаты
  741.         for i = 1, backgroundSize, 2 do
  742.           local x = string.byte(file:read(1))
  743.           local y = string.byte(file:read(1))
  744.           local index = convertCoordsToIndex(x, y, readedWidth)
  745.           -- print("Координата: " .. x .. "x" .. y .. ", индекс: "..index)
  746.  
  747.           picture[index] = background
  748.           picture[index + 1] = foreground
  749.           picture[index + 2] = alpha
  750.           picture[index + 3] = symbol
  751.         end
  752.       end
  753.  
  754.     --Новый формат OCIF4
  755.     elseif header == "Y" and useOCIF4 then
  756.       ySize = string.byte(file:read(1))
  757.       y = string.byte(file:read(1))
  758.       -- print("Размер массива Y: " .. ySize)
  759.       -- print("Текущий Y: " .. y)
  760.  
  761.       for i = 1, ySize do
  762.         local x = string.byte(file:read(1))
  763.         local index = convertCoordsToIndex(x, y, readedWidth)
  764.         -- print("Координата: " .. x .. "x" .. y .. ", индекс: "..index)
  765.  
  766.         picture[index] = background
  767.         picture[index + 1] = foreground
  768.         picture[index + 2] = alpha
  769.         picture[index + 3] = symbol
  770.       end  
  771.     else
  772.       error("Error while reading OCIF format: unknown Header type (" .. header .. ")")
  773.     end
  774.  
  775.   end
  776.  
  777.   file:close()
  778.  
  779.   return picture
  780. end
  781.  
  782. ------------------------------ Все, что касается формата RAW ------------------------------------------------------------
  783.  
  784. --Сохранение в файл сырого формата изображения типа 2 (подробнее о типах см. конец файла)
  785. local function saveRaw(file, picture)
  786.  
  787.   file:write("\n")
  788.  
  789.   local xPos, yPos = 1, 1
  790.   for i = 1, picture.width * picture.height * constants.elementCount, constants.elementCount do
  791.     file:write( HEXtoSTRING(picture[i], 6), " ", HEXtoSTRING(picture[i + 1], 6), " ", HEXtoSTRING(picture[i + 2], 2), " ", picture[i + 3], " ")
  792.  
  793.     xPos = xPos + 1
  794.     if xPos > picture.width then
  795.       xPos = 1
  796.       yPos = yPos + 1
  797.       file:write("\n")
  798.     end
  799.   end
  800.  
  801.   file:close()
  802. end
  803.  
  804. --Загрузка из файла сырого формата изображения типа 2 (подробнее о типах см. конец файла)
  805. local function loadRaw(file)
  806.   --Читаем один байт "прост так"
  807.   file:read(1)
  808.  
  809.   local picture = {}
  810.   local background, foreground, alpha, symbol, sLine
  811.   local lineCounter = 0
  812.  
  813.   for line in file:lines() do
  814.     sLine = unicode.len(line)
  815.     for i = 1, sLine, constants.rawImageLoadStep do
  816.       background = "0x" .. unicode.sub(line, i, i + 5)
  817.       foreground = "0x" .. unicode.sub(line, i + 7, i + 12)
  818.       alpha = "0x" .. unicode.sub(line, i + 14, i + 15)
  819.       symbol = unicode.sub(line, i + 17, i + 17)
  820.  
  821.       table.insert(picture, tonumber(background))
  822.       table.insert(picture, tonumber(foreground))
  823.       table.insert(picture, tonumber(alpha))
  824.       table.insert(picture, symbol)
  825.     end
  826.     lineCounter = lineCounter + 1
  827.   end
  828.  
  829.   picture.width = sLine / constants.rawImageLoadStep
  830.   picture.height = lineCounter
  831.  
  832.   file:close()
  833.   return picture
  834. end
  835.  
  836. ----------------------------------- Вспомогательные функции программы ------------------------------------------------------------
  837.  
  838. --Оптимизировать и сгруппировать по цветам картинку типа 2 (подробнее о типах см. конец файла)
  839. function image.convertToGroupedImage(picture)
  840.   --Создаем массив оптимизированной картинки
  841.   local optimizedPicture = {}
  842.   --Задаем константы
  843.   local xPos, yPos, background, foreground, alpha, symbol = 1, 1, nil, nil, nil, nil
  844.   --Перебираем все элементы массива
  845.   for i = 1, picture.width * picture.height * constants.elementCount, constants.elementCount do
  846.     --Получаем символ из неоптимизированного массива
  847.     background, foreground, alpha, symbol = picture[i], picture[i + 1], picture[i + 2], picture[i + 3]
  848.     --Группируем картинку по цветам
  849.     optimizedPicture[alpha] = optimizedPicture[alpha] or {}
  850.     optimizedPicture[alpha][symbol] = optimizedPicture[alpha][symbol] or {}
  851.     optimizedPicture[alpha][symbol][foreground] = optimizedPicture[alpha][symbol][foreground] or {}
  852.     optimizedPicture[alpha][symbol][foreground][background] = optimizedPicture[alpha][symbol][foreground][background] or {}
  853.     optimizedPicture[alpha][symbol][foreground][background][yPos] = optimizedPicture[alpha][symbol][foreground][background][yPos] or {}
  854.  
  855.     table.insert(optimizedPicture[alpha][symbol][foreground][background][yPos], xPos)
  856.     --Если xPos достигает width изображения, то сбросить на 1, иначе xPos++
  857.     xPos = (xPos == picture.width) and 1 or xPos + 1
  858.     --Если xPos равняется 1, то yPos++, а если нет, то похуй
  859.     yPos = (xPos == 1) and yPos + 1 or yPos
  860.   end
  861.   --Возвращаем оптимизированный массив
  862.   return optimizedPicture
  863. end
  864.  
  865. -- Функция оптимизации цвета текста и символов у картинки, уменьшает число GPU-операций при отрисовке из буфера
  866. -- Вызывается только при сохранении файла, так что на быстродействии не сказывается,
  867. -- а в целом штука очень и очень полезная. Фиксит криворукость художников.
  868. function image.optimize(picture)
  869.   local i1, i2, i3 = 0, 0, 0
  870.   for i = 1, #picture, constants.elementCount do
  871.     --Уменьшаем нагрузку на ЦОПЕ
  872.     i1, i2, i3 = i + 1, i + 2, i + 3
  873.     --Если цвет фона равен цвету текста, и используется псевдографические полупиксели
  874.     if picture[i] == picture[i1] and (picture[i3] == "▄" or picture[i3] == "▀") then
  875.       picture[i3] = " "
  876.     end
  877.     --Если символ равен пролбелу, т.е. цвет текста не учитывается
  878.     if picture[i3] == " " then    
  879.       picture[i1] = 0x000000
  880.     end
  881.   end
  882.  
  883.   return picture
  884. end
  885.  
  886. --Получить пиксель из изображения по указанным координатам
  887. function image.get(picture, x, y)
  888.   if x >= 1 and y >= 1 and x <= picture.width and y <= picture.height then
  889.     local index = convertCoordsToIndex(x, y, picture.width)
  890.     return picture[index], picture[index + 1], picture[index + 2], picture[index + 3]
  891.   else
  892.     return nil
  893.   end
  894. end
  895.  
  896. --Установить пиксель в изображении по указанным координатам
  897. function image.set(picture, x, y, background, foreground, alpha, symbol, debug)
  898.   if x >= 1 and y >= 1 and x <= picture.width and y <= picture.height then
  899.     local index = convertCoordsToIndex(x, y, picture.width)
  900.     picture[index] = background or 0xFF00FF
  901.     picture[index + 1] = foreground or 0xFF00FF
  902.     picture[index + 2] = alpha or 0x00
  903.     picture[index + 3] = symbol or " "
  904.     return picture
  905.   else
  906.     error("Can't set pixel because it's located out of image coordinates: x = " .. x .. ", y = " .. y)
  907.   end
  908. end
  909.  
  910. ------------------------------------------ Методы трансформирования изображения ------------------------------------------------
  911.  
  912. --Вставка ряда пикселей
  913. function image.insertRow(picture, y, rowArray)
  914.   local index = convertCoordsToIndex(1, y, picture.width)
  915.   for i = 1, #rowArray, 4 do
  916.     table.insert(picture, index, rowArray[i + 3])
  917.     table.insert(picture, index, rowArray[i + 2])
  918.     table.insert(picture, index, rowArray[i + 1])
  919.     table.insert(picture, index, rowArray[i])
  920.     index = index + 4
  921.   end
  922.   picture.height = picture.height + 1
  923.   return picture
  924. end
  925.  
  926. function image.insertColumn(picture, x, columnArray)
  927.   local index = convertCoordsToIndex(x, 1, picture.width)
  928.   for i = 1, #columnArray, 4 do
  929.     table.insert(picture, index, columnArray[i + 3])
  930.     table.insert(picture, index, columnArray[i + 2])
  931.     table.insert(picture, index, columnArray[i + 1])
  932.     table.insert(picture, index, columnArray[i])
  933.     index = index + picture.width * 4 + 4
  934.   end
  935.   picture.width = picture.width + 1
  936.   return picture
  937. end
  938.  
  939. --Удаление ряда пикселей
  940. function image.removeRow(picture, y)
  941.   local index = convertCoordsToIndex(1, y, picture.width)
  942.   for i = 1, picture.width * 4 do table.remove(picture, index) end
  943.   picture.height = picture.height - 1
  944.   return picture
  945. end
  946.  
  947. --Удаление колонки пикселей
  948. function image.removeColumn(picture, x)
  949.   local index = convertCoordsToIndex(x, 1, picture.width)
  950.   for i = 1, picture.height do
  951.     for j = 1, 4 do table.remove(picture, index) end
  952.     index = index + (picture.width) * 4 - 4
  953.   end
  954.   picture.width = picture.width - 1
  955.   return picture
  956. end
  957.  
  958. --Получение ряда пикселей
  959. function image.getRow(picture, y)
  960.   local row, background, foreground, alpha, symbol = {width = picture.width, height = 1}
  961.   for x = 1, picture.width do
  962.     background, foreground, alpha, symbol = image.get(picture, x, y)
  963.     table.insert(row, background)
  964.     table.insert(row, foreground)
  965.     table.insert(row, alpha)
  966.     table.insert(row, symbol)
  967.   end
  968.   return row
  969. end
  970.  
  971. --Получение колонки пикселей
  972. function image.getColumn(picture, x)
  973.   local column, background, foreground, alpha, symbol = {width = 1, height = picture.height}
  974.   for y = 1, picture.height do
  975.     background, foreground, alpha, symbol = image.get(picture, x, y)
  976.     table.insert(column, background)
  977.     table.insert(column, foreground)
  978.     table.insert(column, alpha)
  979.     table.insert(column, symbol)
  980.   end
  981.   return column
  982. end
  983.  
  984. ----------------------------------------- Строковая обработка изображений -------------------------------------------------------------------
  985.  
  986. --Преобразовать изображение в строковую интерпретацию, которая может быть вставлена в код
  987. --Удобно, если не хочется возиться с файловой системой
  988. function image.toString(picture)
  989.   local stringedPicture = {}
  990.   picture = convertImageColorsTo8Bit(picture)
  991.   table.insert(stringedPicture, string.format("%02X", picture.width))
  992.   table.insert(stringedPicture, string.format("%02X", picture.height))
  993.   for i = 1, #picture, 4 do
  994.     table.insert(stringedPicture, string.format("%02X", picture[i]))
  995.     table.insert(stringedPicture, string.format("%02X", picture[i + 1]))
  996.     table.insert(stringedPicture, string.format("%02X", picture[i + 2]))
  997.     table.insert(stringedPicture, picture[i + 3])
  998.   end
  999.   picture = convertImageColorsTo24Bit(picture)
  1000.   return table.concat(stringedPicture)
  1001. end
  1002.  
  1003. --Получить изображение из строковой интерпретации, созданной ранее
  1004. function image.fromString(stringedPicture)
  1005.   local picture = {}
  1006.   local subIndex = 1
  1007.   picture.width = tonumber("0x" .. unicode.sub(stringedPicture, subIndex, subIndex + 1)); subIndex = subIndex + 2
  1008.   picture.height = tonumber("0x" .. unicode.sub(stringedPicture, subIndex, subIndex + 1)); subIndex = subIndex + 2
  1009.  
  1010.   for pixel = 1, picture.width * picture.height do
  1011.     table.insert(picture, tonumber("0x" .. unicode.sub(stringedPicture, subIndex, subIndex + 1))); subIndex = subIndex + 2
  1012.     table.insert(picture, tonumber("0x" .. unicode.sub(stringedPicture, subIndex, subIndex + 1))); subIndex = subIndex + 2
  1013.     table.insert(picture, tonumber("0x" .. unicode.sub(stringedPicture, subIndex, subIndex + 1))); subIndex = subIndex + 2
  1014.     table.insert(picture, unicode.sub(stringedPicture, subIndex, subIndex)); subIndex = subIndex + 1
  1015.   end
  1016.   picture = convertImageColorsTo24Bit(picture)
  1017.   return picture
  1018. end
  1019.  
  1020. ----------------------------------------- Основные функции программы -------------------------------------------------------------------
  1021.  
  1022. --Сохранить изображение любого поддерживаемого формата
  1023. function image.save(path, picture, encodingMethod)
  1024.   result=""
  1025.   encodingMethod = encodingMethod or 4
  1026.   --Создать папку под файл, если ее нет
  1027.   --fs.makeDirectory(fs.path(path))
  1028.   --Получаем формат указанного файла
  1029.   --local fileFormat = getFileFormat(path)
  1030.   local fileFormat = ".pic"
  1031.   --Проверяем соответствие формата файла
  1032.   if fileFormat == constants.compressedFileFormat then
  1033.     --Оптимизируем картинку
  1034.     picture = image.optimize(picture)
  1035.     --Открываем файл
  1036. --    local file = io.open(path, "w") костыльное переопределение команд file:write и file:read
  1037.     file={}
  1038.     function file.write(self,...)
  1039.       local mas={...}
  1040.       for i=1,#mas do
  1041.         result=result..mas[i]
  1042.       end
  1043.     end
  1044.     function file.close()
  1045.     end--]]
  1046.     --Записываем сигнатуру
  1047.     writeSignature(file)
  1048.     --Разбираемся с кодировкой
  1049.     if encodingMethod == 0 or string.lower(encodingMethod) == "raw" then
  1050.       file:write(string.char(encodingMethod))
  1051.       saveRaw(file, picture)
  1052.     elseif encodingMethod == 1 or string.lower(encodingMethod) == "ocif1" then
  1053.       file:write(string.char(encodingMethod))
  1054.       saveOCIF1(file, picture)
  1055.     elseif encodingMethod == 2 or string.lower(encodingMethod) == "ocif2" then
  1056.       file:write(string.char(encodingMethod))
  1057.       saveOCIF2(file, picture)
  1058.     elseif encodingMethod == 3 or string.lower(encodingMethod) == "ocif3" then
  1059.       error("Saving in encoding method 3 is deprecated and no longer supported. Use method 4 instead of it.")
  1060.     elseif encodingMethod == 4 or string.lower(encodingMethod) == "ocif4" then
  1061.       file:write(string.char(encodingMethod))
  1062.       picture = convertImageColorsTo8Bit(picture)
  1063.       saveOCIF2(file, picture, true)
  1064.       picture = convertImageColorsTo24Bit(picture)
  1065.     elseif encodingMethod == 6 then
  1066.       file:close()
  1067.       file = io.open(path, "w")
  1068.       file:write(image.toString(picture))
  1069.       file:close()
  1070.     else
  1071.       file:close()
  1072.       error("Unsupported encoding method.\n")
  1073.     end
  1074.   else
  1075.     file:close()
  1076.     error("Unsupported file format.\n")
  1077.   end
  1078.   return result
  1079. end
  1080.  
  1081. --Загрузить изображение любого поддерживаемого формата
  1082. function image.load(str)
  1083.   --Кинуть ошибку, если такого файла не существует
  1084. --  if not fs.exists(path) then error("File \""..path.."\" does not exists.\n") end
  1085.   --Получаем формат указанного файла
  1086.   local fileFormat = getFileFormat(path)
  1087.   --Проверяем соответствие формата файла
  1088.   if fileFormat == constants.compressedFileFormat then
  1089.     --local file = io.open(path, "rb")
  1090.     file={pos=1}
  1091.     function file.read(self,count)
  1092.       count=count or 1
  1093.       local op=file.pos
  1094.       file.pos=file.pos+count-1
  1095.       return string.sub(str,op,file.pos)
  1096.     end
  1097.     function file.close()
  1098.     end--]]
  1099.     --Читаем сигнатуру файла
  1100.     readSignature(file)
  1101.     --Читаем метод обработки изображения
  1102.     local encodingMethod = string.byte(file:read(1))
  1103.     --Читаем файлы в зависимости от метода
  1104.     --print("Загружаю файл типа " .. encodingMethod)
  1105.     if encodingMethod == 0 then
  1106.       return image.optimize(loadRaw(file))
  1107.     elseif encodingMethod == 1 then
  1108.       return image.optimize(loadOCIF1(file))
  1109.     elseif encodingMethod == 2 then
  1110.       return image.optimize(loadOCIF2(file))
  1111.     elseif encodingMethod == 3 then
  1112.       return image.optimize(loadOCIF2(file, true))
  1113.     elseif encodingMethod == 4 then
  1114.       return image.optimize(loadOCIF2(file, true, true))
  1115.     else
  1116.       file:close()
  1117.       error("Unsupported encoding method: " .. encodingMethod .. "\n")
  1118.     end
  1119.   --Поддержка ПНГ-формата
  1120.   elseif fileFormat == constants.pngFileFormat then
  1121.     return image.loadPng(path)
  1122.   else
  1123.     error("Unsupported file format: " .. fileFormat .. "\n")
  1124.   end
  1125. end
  1126.  
  1127. function load(str)
  1128.   return image.load(str)
  1129. end
  1130.  
  1131. function save(tbl)
  1132.   local picture = {}
  1133.   local foreground, background, symbol
  1134.   picture.width, picture.height = tbl.width, tbl.height
  1135.  
  1136.   for j = 1, picture.height do
  1137.     for i = 1, picture.width do
  1138.       --symbol, foreground, background = component.gpu.get(i, j)
  1139.       table.insert(picture, tbl[(j-1)*picture.width+i].background)
  1140.       table.insert(picture, tbl[(j-1)*picture.width+i].foreground)
  1141.       table.insert(picture, 0x00)
  1142.       table.insert(picture, tbl[(j-1)*picture.width+i].letter)
  1143.     end
  1144.   end
  1145.  
  1146.   return image.save("/disk/disk/trnd2.pic", picture)
  1147. --  return image.toString(picture)
  1148. end
  1149.  
  1150. --tbl={width=3,height=2,
  1151. --{background=0xff0000,foreground=0x000000,letter=" "},{background=0xff0000,foreground=0x000000,letter=" "},{background=0xff0000,foreground=0x000000,letter=" "},
  1152. --{background=0xff0000,foreground=0x000000,letter=" "},{background=0xff0000,foreground=0x000000,letter=")"},{background=0xff0000,foreground=0x000000,letter=" "},
  1153. --}
  1154. --f=io.open("trnd.pic","w")
  1155. --f:write(save(tbl))
  1156. --_G.tmpRND=save(tbl)
  1157. --f:close()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement