Advertisement
Pirnogion

OC/image

Aug 26th, 2015
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 9.42 KB | None | 0 0
  1. --[[
  2. Автор: Pirnogion
  3. Основная идея формата .ocif(Open Computers image format):
  4.     -Запись:
  5.         1. Берется информация об 1 пикселе изображени( цвет фона, цвет символа, символ )
  6.         2. Цвета перекодируется из 24 битной(требует 3 байта) паитры в 8 битную(требует 1 байт)
  7.         3. Символ перекодируется в его число в кодировке utf8 и разбивается на отдельные байты
  8.         4. Все полученные числа перекодируются в ASCII-симолы и записываются в файл
  9.  
  10.     -Чтение:
  11.         1. Цвета считываются из файла и кодируются в HEX-записи с преобразованием в 24 битную палитру
  12.         2. Сичтывается один байт идущий после байтов цветов
  13.         3. По считанному байту определяется количество байт, которыми закодирован utf8 символ
  14.         4. Считанные байты символа перекодиркются в utf8 символ
  15.         5. Информация о цветах и символе заносится в массив
  16.  
  17.     -Примечания:
  18.         Для идентификации файла придумана его подпись(сигнатура) размером в 7бит нагло спизженная с реального формата .PNG.
  19.         Чисто для создания атмосферы и, естественно, для пафоса.
  20.  
  21.     -Вид массива:
  22.         image_array = { {[1] = <foreground>, [2] = <background>, [3] = <alpha>, [4] = <char>}, ... }
  23.  
  24.     -Планы:
  25.         1. Запилить анимации...........................................( )
  26. --]]
  27.  
  28. --CONSTANTS--
  29. local IMAGE_FG = 3
  30. local IMAGE_BG = 2
  31. local IMAGE_AL = 1
  32. local IMAGE_CH = 0
  33.  
  34. local ELEMENT_COUNT = 4
  35.  
  36. local IMAGE_WIDTH  = 1
  37. local IMAGE_HEIGHT = 2
  38. local IMAGE        = 3
  39.  
  40. local BYTE      = 8
  41. local NULL_CHAR = 0
  42.  
  43. local FILE_OPEN_ERROR = "Can't open file"
  44.  
  45. --.ocif подпись
  46. --.ocif signature
  47. local ocif_signature1 = 0x896F6369
  48. local ocif_signature2 = 0x00661A0A --7 bytes: 89 6F 63 69 66 1A 0A
  49. local ocif_signature_expand = { string.char(0x89), string.char(0x6F), string.char(0x63), string.char(0x69), string.char(0x66), string.char(0x1A), string.char(0x0A) }
  50.  
  51. local imageAPI = {}
  52.  
  53. --Выделить бит-терминатор в первом байте utf8 символа: 1100 0010 --> 0010 0000
  54. --Select terminate bit in the first byte utf8 char: 1100 0010 --> 0010 0000
  55. local function selectTerminateBit_l()
  56.     local prevByte = nil
  57.     local prevTerminateBit = nil
  58.  
  59.     return function( byte )
  60.         local x, terminateBit = nil
  61.         if ( prevByte == byte ) then
  62.             return prevTerminateBit
  63.         end
  64.  
  65.         x = bit32.band( bit32.bnot(byte), 0x000000FF )
  66.         x = bit32.bor( x, bit32.rshift(x, 1) )
  67.         x = bit32.bor( x, bit32.rshift(x, 2) )
  68.         x = bit32.bor( x, bit32.rshift(x, 4) )
  69.         x = bit32.bor( x, bit32.rshift(x, 8) )
  70.         x = bit32.bor( x, bit32.rshift(x, 16) )
  71.  
  72.         terminateBit = x - bit32.rshift(x, 1)
  73.  
  74.         --save state
  75.         prevByte = byte
  76.         prevTerminateBit = terminateBit
  77.  
  78.         return terminateBit
  79.     end
  80. end
  81. local selectTerminateBit = selectTerminateBit_l()
  82.  
  83. --Прочитать n байтов из файла, возвращает прочитанные байты как число, если не удалось прочитать, то возвращает 0
  84. --Read n byte from file and returns readed bytes as number. If read failed, then returns 0
  85. local function readBytes(file, bytes)
  86.   local readedByte = 0
  87.   local readedNumber = 0
  88.   for i = bytes, 1, -1 do
  89.     readedByte = string.byte( file:read(1) or NULL_CHAR )
  90.     readedNumber = readedNumber + bit32.lshift(readedByte, i*8-8)
  91.   end
  92.  
  93.   return readedNumber
  94. end
  95.  
  96. --Преобразует цвет в hex записи в rgb запись
  97. --Convert HEX color to RGB color
  98. function HEXtoRGB(color)
  99.   local rr = bit32.rshift( color, 16 )
  100.   local gg = bit32.rshift( bit32.band(color, 0x00ff00), 8 )
  101.   local bb = bit32.band(color, 0x0000ff)
  102.  
  103.   return rr, gg, bb
  104. end
  105.  
  106. function RGBtoHEX(rr, gg, bb)
  107.   return bit32.lshift(rr, 16) + bit32.lshift(gg, 8) + bb
  108. end
  109.  
  110. --Альфа-смешение
  111. --Alpha blending
  112. local function alpha_blend(back_color, front_color, alpha_channel)
  113.     local INVERTED_ALPHA_CHANNEL = 255-alpha_channel
  114.  
  115.     local back_color_rr, back_color_gg, back_color_bb    = HEXtoRGB(back_color)
  116.     local front_color_rr, front_color_gg, front_color_bb = HEXtoRGB(front_color)
  117.  
  118.     local blended_rr = front_color_rr * INVERTED_ALPHA_CHANNEL / 255 + back_color_rr * alpha_channel / 255
  119.     local blended_gg = front_color_gg * INVERTED_ALPHA_CHANNEL / 255 + back_color_gg * alpha_channel / 255
  120.     local blended_bb = front_color_bb * INVERTED_ALPHA_CHANNEL / 255 + back_color_bb * alpha_channel / 255
  121.  
  122.     return RGBtoHEX( blended_rr, blended_gg, blended_bb )
  123. end
  124.  
  125. --Конвертация 24 битной палитры в 8 битную
  126. --Convert 24bit palette to 8bit
  127. local function HEX_color24to8( hexcolor24 )
  128.     local rr, gg, bb = HEXtoRGB( hexcolor24 )
  129.  
  130.     return bit32.lshift( bit32.rshift(rr, 5), 5 ) + bit32.lshift( bit32.rshift(gg, 5), 2 ) + bit32.rshift(bb, 6)
  131. end
  132.  
  133. --Конвертация 8 битной палитры в 24 битную
  134. --Convert 8bit palette to 24bit
  135. local function HEX_color8to24( hexcolor8 )
  136.     local rr = bit32.lshift( bit32.rshift( hexcolor8, 5 ), 5 )
  137.     local gg = bit32.lshift( bit32.rshift( bit32.band( hexcolor8, 28 ), 2 ), 5 )
  138.     local bb = bit32.lshift( bit32.band( hexcolor8, 3 ), 6 )
  139.  
  140.     return RGBtoHEX( rr, gg, bb )
  141. end
  142.  
  143. --Подготавливает цвета и символ для записи в файл
  144. --Preparation colors and char from write to file
  145. local function encodePixel(hexcolor_fg, hexcolor_bg, alpha, char)
  146.     --split hex-colors
  147.     local new_fg = HEX_color24to8( hexcolor_fg )
  148.     local new_bg = HEX_color24to8( hexcolor_bg )
  149.     local ascii_char1, ascii_char2, ascii_char3, ascii_char4, ascii_char5, ascii_char6 = string.byte( char, 1, 6 )
  150.  
  151.     ascii_char1 = ascii_char1 or NULL_CHAR
  152.  
  153.     return new_fg, new_bg, alpha, ascii_char1, ascii_char2, ascii_char3, ascii_char4, ascii_char5, ascii_char6
  154. end
  155.  
  156. --Декодирование utf8 символа
  157. --Decode utf8 char
  158. local function decodeChar(file)
  159.     local first_byte = readBytes(file, 1)
  160.     local charcode_array = {first_byte}
  161.     local len = 1
  162.  
  163.     local middle = selectTerminateBit(first_byte)
  164.     if ( middle == 32 ) then
  165.         len = 2
  166.     elseif ( middle == 16 ) then
  167.         len = 3
  168.     elseif ( middle == 8 ) then
  169.         len = 4
  170.     elseif ( middle == 4 ) then
  171.         len = 5
  172.     elseif ( middle == 2 ) then
  173.         len = 6
  174.     end
  175.  
  176.     for i = 1, len-1 do
  177.         table.insert( charcode_array, readBytes(file, 1) )
  178.     end
  179.  
  180.     return string.char( table.unpack( charcode_array ) )
  181. end
  182.  
  183. --Запись в файл по массиву изображения
  184. --Write image array to file
  185. function imageAPI.write(path, image)
  186.     local file = assert( io.open(path, "w"), FILE_OPEN_ERROR )
  187.  
  188.     file:write( table.unpack(ocif_signature_expand) )
  189.     file:write( string.char( image[IMAGE_WIDTH]  ) )
  190.     file:write( string.char( image[IMAGE_HEIGHT] ) )
  191.  
  192.     for element = ELEMENT_COUNT, image[IMAGE_HEIGHT] * image[IMAGE_WIDTH] * ELEMENT_COUNT, ELEMENT_COUNT do
  193.         local encodedPixel =
  194.         {
  195.             encodePixel
  196.             (
  197.                 image[IMAGE][element-IMAGE_FG],
  198.                 image[IMAGE][element-IMAGE_BG],
  199.                 image[IMAGE][element-IMAGE_AL],
  200.                 image[IMAGE][element-IMAGE_CH]
  201.             )
  202.         }
  203.         for i = 1, #encodedPixel do
  204.             file:write( string.char( encodedPixel[i] ) )
  205.         end
  206.     end
  207.  
  208.     file:close()
  209. end
  210.  
  211. --Чтение из файла, возвращет массив изображения
  212. --Read from file, return image array
  213. function imageAPI.read(path)
  214.     local image = {}
  215.     local file = assert( io.open(path, "rb"), FILE_OPEN_ERROR )
  216.  
  217.     local signature1, signature2 = readBytes(file, 4), readBytes(file, 3)
  218.     if ( signature1 ~= ocif_signature1 or signature2 ~= ocif_signature2 ) then
  219.         file:close()
  220.         return nil
  221.     end
  222.  
  223.     image[IMAGE_WIDTH]  = readBytes(file, 1)
  224.     image[IMAGE_HEIGHT] = readBytes(file, 1)
  225.  
  226.     image[IMAGE] = {}
  227.  
  228.     for element = ELEMENT_COUNT, image[IMAGE_HEIGHT] * image[IMAGE_WIDTH] * ELEMENT_COUNT, ELEMENT_COUNT do
  229.         image[IMAGE][element-IMAGE_FG] = HEX_color8to24( readBytes(file, 1) )
  230.         image[IMAGE][element-IMAGE_BG] = HEX_color8to24( readBytes(file, 1) )
  231.         image[IMAGE][element-IMAGE_AL] = readBytes(file, 1)
  232.         image[IMAGE][element-IMAGE_CH] = decodeChar( file )
  233.     end
  234.  
  235.     file:close()
  236.  
  237.     return image
  238. end
  239.  
  240. --Отрисовка изображения
  241. --Draw image
  242. function imageAPI.draw(image, sx, sy, gpu)
  243.     local x, y = 0, 0
  244.     local prevBG, prevFG = nil, nil
  245.     local currentBG, currentFG = nil, nil
  246.     for element = ELEMENT_COUNT, image[IMAGE_HEIGHT] * image[IMAGE_WIDTH] * ELEMENT_COUNT, ELEMENT_COUNT do
  247.         x = (x % image[IMAGE_WIDTH]) + 1
  248.         y = (x == 1) and y+1 or y
  249.  
  250.         local _, _, back_color = gpu.get(sx+x-1, sy+y-1)
  251.  
  252.         currentFG = image[IMAGE][element-IMAGE_FG]
  253.         currentBG = alpha_blend( back_color, image[IMAGE][element-IMAGE_BG], image[IMAGE][element-IMAGE_AL] )
  254.  
  255.         if ( currentFG ~= prevFG ) then
  256.             prevFG = currentFG
  257.             gpu.setForeground(currentFG)
  258.         end
  259.         if ( currentBG ~= prevBG ) then
  260.             prevBG = currentBG
  261.             gpu.setBackground(currentBG)
  262.         end
  263.  
  264.         gpu.set(sx+x-1, sy+y-1, image[IMAGE][element-IMAGE_CH])
  265.     end
  266. end
  267.  
  268. return imageAPI
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement