Advertisement
FluttyProger

PlayOCIFM.lua

Jan 22nd, 2017
172
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 11.17 KB | None | 0 0
  1. local buffer = require("doubleBuffering")
  2. local bit32 = require("bit32")
  3.  
  4. local args={...}
  5.  
  6. local constants = {
  7.     OCIFSignature = "OCIF",
  8.     OCIF2Elements = {
  9.         alphaStart = "A",
  10.         symbolStart = "S",
  11.         backgroundStart = "B",
  12.         foregroundStart = "F",
  13.     },
  14.     elementCount = 4,
  15.     byteSize = 8,
  16.     nullChar = 0,
  17.     rawImageLoadStep = 19,
  18.     compressedFileFormat = ".pic",
  19.     pngFileFormat = ".png",
  20. }
  21.  
  22. local palette = {
  23.   0x000000, 0x000040, 0x000080, 0x0000BF, 0x0000FF, 0x002400, 0x002440, 0x002480, 0x0024BF, 0x0024FF, 0x004900, 0x004940, 0x004980, 0x0049BF, 0x0049FF, 0x006D00,
  24.   0x006D40, 0x006D80, 0x006DBF, 0x006DFF, 0x009200, 0x009240, 0x009280, 0x0092BF, 0x0092FF, 0x00B600, 0x00B640, 0x00B680, 0x00B6BF, 0x00B6FF, 0x00DB00, 0x00DB40,
  25.   0x00DB80, 0x00DBBF, 0x00DBFF, 0x00FF00, 0x00FF40, 0x00FF80, 0x00FFBF, 0x00FFFF, 0x0F0F0F, 0x1E1E1E, 0x2D2D2D, 0x330000, 0x330040, 0x330080, 0x3300BF, 0x3300FF,
  26.   0x332400, 0x332440, 0x332480, 0x3324BF, 0x3324FF, 0x334900, 0x334940, 0x334980, 0x3349BF, 0x3349FF, 0x336D00, 0x336D40, 0x336D80, 0x336DBF, 0x336DFF, 0x339200,
  27.   0x339240, 0x339280, 0x3392BF, 0x3392FF, 0x33B600, 0x33B640, 0x33B680, 0x33B6BF, 0x33B6FF, 0x33DB00, 0x33DB40, 0x33DB80, 0x33DBBF, 0x33DBFF, 0x33FF00, 0x33FF40,
  28.   0x33FF80, 0x33FFBF, 0x33FFFF, 0x3C3C3C, 0x4B4B4B, 0x5A5A5A, 0x660000, 0x660040, 0x660080, 0x6600BF, 0x6600FF, 0x662400, 0x662440, 0x662480, 0x6624BF, 0x6624FF,
  29.   0x664900, 0x664940, 0x664980, 0x6649BF, 0x6649FF, 0x666D00, 0x666D40, 0x666D80, 0x666DBF, 0x666DFF, 0x669200, 0x669240, 0x669280, 0x6692BF, 0x6692FF, 0x66B600,
  30.   0x66B640, 0x66B680, 0x66B6BF, 0x66B6FF, 0x66DB00, 0x66DB40, 0x66DB80, 0x66DBBF, 0x66DBFF, 0x66FF00, 0x66FF40, 0x66FF80, 0x66FFBF, 0x66FFFF, 0x696969, 0x787878,
  31.   0x878787, 0x969696, 0x990000, 0x990040, 0x990080, 0x9900BF, 0x9900FF, 0x992400, 0x992440, 0x992480, 0x9924BF, 0x9924FF, 0x994900, 0x994940, 0x994980, 0x9949BF,
  32.   0x9949FF, 0x996D00, 0x996D40, 0x996D80, 0x996DBF, 0x996DFF, 0x999200, 0x999240, 0x999280, 0x9992BF, 0x9992FF, 0x99B600, 0x99B640, 0x99B680, 0x99B6BF, 0x99B6FF,
  33.   0x99DB00, 0x99DB40, 0x99DB80, 0x99DBBF, 0x99DBFF, 0x99FF00, 0x99FF40, 0x99FF80, 0x99FFBF, 0x99FFFF, 0xA5A5A5, 0xB4B4B4, 0xC3C3C3, 0xCC0000, 0xCC0040, 0xCC0080,
  34.   0xCC00BF, 0xCC00FF, 0xCC2400, 0xCC2440, 0xCC2480, 0xCC24BF, 0xCC24FF, 0xCC4900, 0xCC4940, 0xCC4980, 0xCC49BF, 0xCC49FF, 0xCC6D00, 0xCC6D40, 0xCC6D80, 0xCC6DBF,
  35.   0xCC6DFF, 0xCC9200, 0xCC9240, 0xCC9280, 0xCC92BF, 0xCC92FF, 0xCCB600, 0xCCB640, 0xCCB680, 0xCCB6BF, 0xCCB6FF, 0xCCDB00, 0xCCDB40, 0xCCDB80, 0xCCDBBF, 0xCCDBFF,
  36.   0xCCFF00, 0xCCFF40, 0xCCFF80, 0xCCFFBF, 0xCCFFFF, 0xD2D2D2, 0xE1E1E1, 0xF0F0F0, 0xFF0000, 0xFF0040, 0xFF0080, 0xFF00BF, 0xFF00FF, 0xFF2400, 0xFF2440, 0xFF2480,
  37.   0xFF24BF, 0xFF24FF, 0xFF4900, 0xFF4940, 0xFF4980, 0xFF49BF, 0xFF49FF, 0xFF6D00, 0xFF6D40, 0xFF6D80, 0xFF6DBF, 0xFF6DFF, 0xFF9200, 0xFF9240, 0xFF9280, 0xFF92BF,
  38.   0xFF92FF, 0xFFB600, 0xFFB640, 0xFFB680, 0xFFB6BF, 0xFFB6FF, 0xFFDB00, 0xFFDB40, 0xFFDB80, 0xFFDBBF, 0xFFDBFF, 0xFFFF00, 0xFFFF40, 0xFFFF80, 0xFFFFBF, 0xFFFFFF,
  39. }
  40.  
  41. function HEXtoRGB(color)
  42.   return bit32.rshift(color, 16), bit32.band(bit32.rshift(color, 8), 0xFF), bit32.band(color, 0xFF)
  43. end
  44.  
  45. function RGBtoHEX(rr, gg, bb)
  46.   return bit32.lshift(rr, 16) + bit32.lshift(gg, 8) + bb
  47. end
  48.  
  49. local function mergeBytesToNumber(...)
  50.     local bytes = {...}
  51.     local finalNumber = bytes[1]
  52.     for i = 2, #bytes do
  53.         finalNumber = bit32.bor(bit32.lshift(finalNumber, 8), bytes[i])
  54.     end
  55.     return finalNumber
  56. end
  57.  
  58. -- Сконвертировать все переданные байты в строку
  59. local function convertBytesToString(...)
  60.     local bytes = {...}
  61.     for i = 1, #bytes do
  62.         bytes[i] = string.char(bytes[i])
  63.     end
  64.     return table.concat(bytes)
  65. end
  66.  
  67. --Выделить бит-терминатор в первом байте UTF-8 символа: 1100 0010 --> 0010 0000
  68. local function selectTerminateBit_l()
  69.     local prevByte = nil
  70.     local prevTerminateBit = nil
  71.  
  72.     return function( byte )
  73.         local x, terminateBit = nil
  74.         if ( prevByte == byte ) then
  75.             return prevTerminateBit
  76.         end
  77.  
  78.         x = bit32.band( bit32.bnot(byte), 0x000000FF )
  79.         x = bit32.bor( x, bit32.rshift(x, 1) )
  80.         x = bit32.bor( x, bit32.rshift(x, 2) )
  81.         x = bit32.bor( x, bit32.rshift(x, 4) )
  82.         x = bit32.bor( x, bit32.rshift(x, 8) )
  83.         x = bit32.bor( x, bit32.rshift(x, 16) )
  84.  
  85.         terminateBit = x - bit32.rshift(x, 1)
  86.  
  87.         prevByte = byte
  88.         prevTerminateBit = terminateBit
  89.  
  90.         return terminateBit
  91.     end
  92. end
  93. local selectTerminateBit = selectTerminateBit_l()
  94.  
  95. --Прочитать n байтов из файла, возвращает прочитанные байты как число, если не удалось прочитать, то возвращает 0
  96. local function readBytes(file, count)
  97.   local readedBytes = file:read(count)
  98.   return mergeBytesToNumber(string.byte(readedBytes, 1, count))
  99. end
  100.  
  101. --Подготавливает цвета и символ для записи в файл сжатого формата
  102. local function encodePixel(background, foreground, alpha, char)
  103.     --Расхерачиваем жирные цвета в компактные цвета
  104.     local ascii_background1, ascii_background2, ascii_background3 = HEXtoRGB(background)
  105.     local ascii_foreground1, ascii_foreground2, ascii_foreground3 = HEXtoRGB(foreground)
  106.     --Расхерачиваем жирный код юникод-символа в несколько миленьких ascii-кодов
  107.     local ascii_char1, ascii_char2, ascii_char3, ascii_char4, ascii_char5, ascii_char6 = string.byte( char, 1, 6 )
  108.     ascii_char1 = ascii_char1 or constants.nullChar
  109.     --Возвращаем все расхераченное
  110.     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
  111. end
  112.  
  113. --Декодирование UTF-8 символа
  114. local function decodeChar(file)
  115.     local first_byte = readBytes(file, 1)
  116.     local charcode_array = {first_byte}
  117.     local len = 1
  118.  
  119.     local middle = selectTerminateBit(first_byte)
  120.     if ( middle == 32 ) then
  121.         len = 2
  122.     elseif ( middle == 16 ) then
  123.         len = 3
  124.     elseif ( middle == 8 ) then
  125.         len = 4
  126.     elseif ( middle == 4 ) then
  127.         len = 5
  128.     elseif ( middle == 2 ) then
  129.         len = 6
  130.     end
  131.  
  132.     for i = 1, len-1 do
  133.         table.insert( charcode_array, readBytes(file, 1) )
  134.     end
  135.  
  136.     return string.char( table.unpack( charcode_array ) )
  137. end
  138.  
  139. local function convert8BitTo24Bit(hex8)
  140.   return palette[hex8 + 1]
  141. end
  142.  
  143. local function convertCoordsToIndex(x, y, width)
  144.     return (width * (y - 1) + x) * constants.elementCount - constants.elementCount + 1
  145. end
  146.  
  147. local function optimize(picture)
  148.     local i1, i2, i3 = 0, 0, 0
  149.     for i = 1, #picture, constants.elementCount do
  150.         --Уменьшаем нагрузку на ЦОПЕ
  151.         i1, i2, i3 = i + 1, i + 2, i + 3
  152.         --Если цвет фона равен цвету текста, и используется псевдографические полупиксели
  153.         if picture[i] == picture[i1] and (picture[i3] == "▄" or picture[i3] == "▀") then
  154.             picture[i3] = " "
  155.         end
  156.         --Если символ равен пролбелу, т.е. цвет текста не учитывается
  157.         if picture[i3] == " " then     
  158.             picture[i1] = 0x000000
  159.         end
  160.     end
  161.  
  162.     return picture
  163. end
  164.  
  165. local function loadOCIF2(file, decompressColors, useOCIF4)
  166.     local picture = {}
  167.  
  168.     --Читаем размер изображения
  169.     local readedWidth = string.byte(file:read(1))
  170.     local readedHeight = string.byte(file:read(1))
  171.     local readednum = string.byte(file:read(1))
  172.     picture.width = readedWidth
  173.     picture.height = readedHeight
  174.     picture.num = readednum
  175.  
  176.     local header, alpha, symbol, foreground, background, y, alphaSize, symbolSize, foregroundSize, backgroundSize, ySize = ""
  177.     while true do
  178.         header = file:read(1)
  179.         if not header or header == "C" then break end
  180.         -- print("----------------------")
  181.         -- print("Заголовок: " .. header)
  182.         if header == "A" then
  183.             local countOfBytesForArraySize = string.byte(file:read(1))
  184.             alphaSize = string.byte(file:read(countOfBytesForArraySize))
  185.             alpha = string.byte(file:read(1))
  186.             -- print("Количество байт под размер массива символов: " .. countOfBytesForArraySize)
  187.             -- print("Размер массива символов: " .. alphaSize)
  188.             -- print("Альфа: " .. alpha)
  189.  
  190.         elseif header == "S" then
  191.             if decompressColors then
  192.                 symbolSize = string.byte(file:read(1))
  193.             else
  194.                 symbolSize = mergeBytesToNumber(string.byte(file:read(3), 1, 3))
  195.             end
  196.             symbol = decodeChar(file)
  197.             -- print("Размер массива цвета текста: " .. symbolSize)
  198.             -- print("Символ: \"" .. symbol .. "\"")
  199.  
  200.         elseif header == "F" then
  201.             if decompressColors then
  202.                 foregroundSize = string.byte(file:read(1))
  203.                 foreground = convert8BitTo24Bit(string.byte(file:read(1)))
  204.             else
  205.                 foregroundSize = mergeBytesToNumber(string.byte(file:read(3), 1, 3))
  206.                 foreground = mergeBytesToNumber(string.byte(file:read(3), 1, 3))
  207.             end
  208.             -- print("Размер массива цвета фона: " .. foregroundSize)
  209.             -- print("Цвет текста: " .. foreground)
  210.  
  211.         elseif header == "B" then
  212.             backgroundSize = mergeBytesToNumber(string.byte(file:read(2), 1, 2))
  213.             if decompressColors then
  214.                 background = convert8BitTo24Bit(string.byte(file:read(1)))
  215.             else
  216.                 background = mergeBytesToNumber(string.byte(file:read(3), 1, 3))
  217.             end
  218.             -- print("Размер массива координат: " .. backgroundSize)
  219.             -- print("Цвет фона: " .. background)
  220.  
  221.             --Поддержка загрузки формата OCIF3
  222.             if not useOCIF4 then
  223.                 --Читаем координаты
  224.                 for i = 1, backgroundSize, 2 do
  225.                     local x = string.byte(file:read(1))
  226.                     local y = string.byte(file:read(1))
  227.                     local index = convertCoordsToIndex(x, y, readedWidth)
  228.                     -- print("Координата: " .. x .. "x" .. y .. ", индекс: "..index)
  229.  
  230.                     picture[index] = background
  231.                     picture[index + 1] = foreground
  232.                     picture[index + 2] = alpha
  233.                     picture[index + 3] = symbol
  234.                 end
  235.             end
  236.  
  237.         --Новый формат OCIF4
  238.         elseif header == "Y" and useOCIF4 then
  239.             ySize = string.byte(file:read(1))
  240.             y = string.byte(file:read(1))
  241.             -- print("Размер массива Y: " .. ySize)
  242.             -- print("Текущий Y: " .. y)
  243.  
  244.             for i = 1, ySize do
  245.                 local x = string.byte(file:read(1))
  246.                 local index = convertCoordsToIndex(x, y, readedWidth)
  247.                 -- print("Координата: " .. x .. "x" .. y .. ", индекс: "..index)
  248.  
  249.                 picture[index] = background
  250.                 picture[index + 1] = foreground
  251.                 picture[index + 2] = alpha
  252.                 picture[index + 3] = symbol
  253.             end    
  254.         else
  255.             error("Error while reading OCIFM format: unknown Header type (" .. header .. ")")
  256.         end
  257.     end
  258.     return picture
  259. end
  260.  
  261. local file = io.open(args[1],"rb")
  262.  
  263. if file:read(5) ~= "OCIFM" then
  264.     error("ЭТОТ ФОРМАТ НЕ ПОДДЕРЖИВАЕТСЯ!!!")
  265. end
  266.  
  267. buffer.start()
  268.  
  269. while true do
  270.     local chto=file:read(1)
  271.     if chto == "O" then
  272.         local imgdata=optimize(loadOCIF2(file, true, true))
  273.         buffer.image(1, 1, imgdata)
  274.         buffer.draw()
  275.         os.sleep(0)
  276.     elseif not chto then
  277.         break
  278.     end
  279. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement