MineOS/lib/image.lua
2015-08-29 23:03:14 +03:00

378 lines
11 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

local fs = require("filesystem")
local unicode = require("unicode")
local gpu = require("component").gpu
local image = {}
local transparentSymbol = "#"
--------------------Все, что касается сжатого формата изображений (у нас он назван "JPG")----------------------------------------------------------------------------------
-- OC image format .ocif by Pirnogion
-- Спасибо, Пир
-- Охуенный форматик
local ocif_signature1 = 0x896F6369
local ocif_signature2 = 0x00661A0A --7 bytes: 89 6F 63 69 66 1A 0A
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) }
local BYTE = 8
local NULL_CHAR = 0
local imageAPI = {}
local function readBytes(file, bytes)
local readedByte = 0
local readedNumber = 0
for i = bytes, 1, -1 do
readedByte = string.byte( file:read(1) or NULL_CHAR )
readedNumber = readedNumber + bit32.lshift(readedByte, i*8-8)
end
return readedNumber
end
local function HEXtoRGB(color)
local rr = bit32.rshift( color, 16 )
local gg = bit32.rshift( bit32.band(color, 0x00ff00), 8 )
local bb = bit32.band(color, 0x0000ff)
return rr, gg, bb
end
local function encodePixel(hexcolor_fg, hexcolor_bg, char)
local rr_fg, gg_fg, bb_fg = HEXtoRGB( hexcolor_fg )
local rr_bg, gg_bg, bb_bg = HEXtoRGB( hexcolor_bg )
local ascii_char1, ascii_char2 = string.byte( char, 1, 2 )
ascii_char1 = ascii_char1 or NULL_CHAR
ascii_char2 = ascii_char2 or NULL_CHAR
return rr_fg, gg_fg, bb_fg, rr_bg, gg_bg, bb_bg, ascii_char1, ascii_char2
end
local function decodeChar(char1, char2)
if ( char1 ~= 0 and char2 ~= 0 ) then
return string.char( char1, char2 )
elseif ( char1 ~= 0) then
return string.char( char1 )
elseif ( char2 ~= 0 ) then
return string.char( char2 )
end
end
--Конвертируем массив классического "сырого" формата в сжатый и оптимизированный
function image.convertImagetoGroupedImage(PNGMassiv)
local newPNGMassiv = { ["backgrounds"] = {} }
--Перебираем весь массив стандартного PNG-вида по высоте
for j = 1, #PNGMassiv do
for i = 1, #PNGMassiv[j] do
local back = PNGMassiv[j][i][1]
local fore = PNGMassiv[j][i][2]
local symbol = PNGMassiv[j][i][3]
newPNGMassiv["backgrounds"][back] = newPNGMassiv["backgrounds"][back] or {}
newPNGMassiv["backgrounds"][back][fore] = newPNGMassiv["backgrounds"][back][fore] or {}
table.insert(newPNGMassiv["backgrounds"][back][fore], {i, j, symbol} )
back, fore, symbol = nil, nil, nil
end
end
return newPNGMassiv
end
--Чтение сжатого формата
local function loadJPG(path)
local image = {}
local file = io.open(path, "rb")
local signature1, signature2 = readBytes(file, 4), readBytes(file, 3)
if ( signature1 ~= ocif_signature1 or signature2 ~= ocif_signature2 ) then
file:close()
return nil
end
image.width = readBytes(file, 1)
image.height = readBytes(file, 1)
image.depth = readBytes(file, 1)
for y = 1, image.height, 1 do
table.insert( image, {} )
for x = 1, image.width, 1 do
table.insert( image[y], {} )
image[y][x][2] = readBytes(file, 3)
image[y][x][1] = readBytes(file, 3)
image[y][x][3] = decodeChar(readBytes(file, 1), readBytes(file, 1))
end
end
file:close()
return image
end
--Рисование сжатого формата
function image.drawJPG(x, y, image)
x = x - 1
y = y - 1
local image2 = convertImagetoGroupedImage(image)
--Перебираем массив с фонами
for back, backValue in pairs(image2["backgrounds"]) do
gpu.setBackground(back)
for fore, foreValue in pairs(image2["backgrounds"][back]) do
gpu.setForeground(fore)
for pixel = 1, #image2["backgrounds"][back][fore] do
if image2["backgrounds"][back][fore][pixel][3] ~= transparentSymbol then
gpu.set(x + image2["backgrounds"][back][fore][pixel][1], y + image2["backgrounds"][back][fore][pixel][2], image2["backgrounds"][back][fore][pixel][3])
end
end
end
end
end
--Сохранение JPG в файл из существующего массива
function image.saveJPG(path, image)
-- Удаляем файл, если есть
-- И делаем папку к нему
fs.remove(path)
fs.makeDirectory(fs.path(path))
local file = io.open(path, "w")
--print("width = ", image.width)
file:write( table.unpack(ocif_signature_expand) )
file:write( string.char( image.width ) )
file:write( string.char( image.height ) )
file:write( string.char( image.depth ) )
for y = 1, image.height, 1 do
for x = 1, image.width, 1 do
local encodedPixel = { encodePixel( image[y][x][2], image[y][x][1], image[y][x][3] ) }
for i = 1, #encodedPixel do
file:write( string.char( encodedPixel[i] ) )
end
end
end
file:close()
end
---------------------------Все, что касается несжатого формата (у нас он назван "PNG")-------------------------------------------------------
-- Перевод HEX-цвета из файла (из 00ff00 делает 0x00ff00)
local function HEXtoSTRING(color,withNull)
local stro4ka = string.format("%x",color)
local sStro4ka = unicode.len(stro4ka)
if sStro4ka < 6 then
stro4ka = string.rep("0", 6 - sStro4ka) .. stro4ka
end
if withNull then return "0x"..stro4ka else return stro4ka end
end
--Загрузка ПНГ
local function loadPNG(path)
local file = io.open(path, "r")
local newPNGMassiv = { ["backgrounds"] = {} }
local pixelCounter, lineCounter = 1, 1
for line in file:lines() do
local dlinaStroki = unicode.len(line)
pixelCounter = 1
for i = 1, dlinaStroki, 16 do
local back = tonumber("0x"..unicode.sub(line, i, i + 5))
local fore = tonumber("0x"..unicode.sub(line, i + 7, i + 12))
local symbol = unicode.sub(line, i + 14, i + 14)
newPNGMassiv["backgrounds"][back] = newPNGMassiv["backgrounds"][back] or {}
newPNGMassiv["backgrounds"][back][fore] = newPNGMassiv["backgrounds"][back][fore] or {}
table.insert(newPNGMassiv["backgrounds"][back][fore], {pixelCounter, lineCounter, symbol} )
pixelCounter = pixelCounter + 1
back, fore, symbol = nil, nil, nil
end
lineCounter = lineCounter + 1
end
file:close()
pixelCounter, lineCounter = nil, nil
return newPNGMassiv
end
-- Сохранение существующего массива ПНГ в файл
function image.savePNG(path, MasterPixels)
-- Удаляем файл, если есть
-- И делаем папку к нему
fs.remove(path)
fs.makeDirectory(fs.path(path))
local f = io.open(path, "w")
for j=1, #MasterPixels do
for i=1,#MasterPixels[j] do
f:write(HEXtoSTRING(MasterPixels[j][i][1])," ",HEXtoSTRING(MasterPixels[j][i][2])," ",MasterPixels[j][i][3]," ")
end
f:write("\n")
end
f:close()
end
--Отрисовка ПНГ
function image.drawPNG(x, y, massivSudaPihay)
--Уменьшаем значения кординат на 1, т.к. циклы начинаются с единицы
x = x - 1
y = y - 1
--Конвертируем "сырой" формат PNG в оптимизированный и сгруппированный по цветам
--local massivSudaPihay = convertImagetoGroupedImage(massivSudaPihay2)
--Более не требуется, встроил конвертер в загрузчик файлов, по сути
--конвертации теперь вообще нет.
--Перебираем массив с фонами
for back, backValue in pairs(massivSudaPihay["backgrounds"]) do
gpu.setBackground(back)
for fore, foreValue in pairs(massivSudaPihay["backgrounds"][back]) do
gpu.setForeground(fore)
for pixel = 1, #massivSudaPihay["backgrounds"][back][fore] do
if massivSudaPihay["backgrounds"][back][fore][pixel][3] ~= transparentSymbol then
gpu.set(x + massivSudaPihay["backgrounds"][back][fore][pixel][1], y + massivSudaPihay["backgrounds"][back][fore][pixel][2], massivSudaPihay["backgrounds"][back][fore][pixel][3])
end
end
end
end
end
---------------------Глобальные функции данного API, с ними мы и работаем---------------------------------------------------------
--Конвертер из PNG в JPG
function image.PNGtoJPG(PNGMassiv)
local JPGMassiv = {}
local width, height = 0, 0
--Сохраняем пиксели
for j = 1, #PNGMassiv do
JPGMassiv[j] = {}
width = 0
for i = 1, #PNGMassiv[j] do
JPGMassiv[j][i] = { table.unpack(PNGMassiv[j][i]) }
width = width + 1
end
height = height + 1
end
JPGMassiv["width"] = width
JPGMassiv["height"] = height
JPGMassiv["depth"] = 8
return JPGMassiv
end
--Конвертер из JPG в PNG
function image.JPGtoPNG(JPGMassiv)
local PNGMassiv = {}
local width, height = 0, 0
--Сохраняем пиксели
for j = 1, #JPGMassiv do
PNGMassiv[j] = {}
width = 0
for i = 1, #JPGMassiv[j] do
PNGMassiv[j][i] = { table.unpack(JPGMassiv[j][i]) }
width = width + 1
end
height = height + 1
end
return PNGMassiv
end
-- Просканировать файловую систему на наличие .PNG
-- И сохранить рядом с ними аналогичную копию в формате .JPG
-- Осторожно, функция для дебага и знающих людей
-- С кривыми ручками сюда не лезь
function image.convertAllPNGtoJPG(path)
local list = ecs.getFileList(path)
for key, file in pairs(list) do
if fs.isDirectory(path.."/"..file) then
image.convertAllPNGtoJPG(path.."/"..file)
else
if ecs.getFileFormat(file) == ".png" or ecs.getFileFormat(file) == ".PNG" then
print("Найден .PNG в директории \""..path.."/"..file.."\"")
print("Загружаю этот файл...")
PNGFile = loadPNG(path.."/"..file)
print("Загрузка завершена!")
print("Конвертация в JPG начата...")
JPGFile = image.PNGtoJPG(PNGFile)
print("Ковертация завершена!")
print("Сохраняю .JPG в той же папке...")
image.saveJPG(path.."/"..ecs.hideFileFormat(file)..".jpg", JPGFile)
print("Сохранение завершено!")
print(" ")
end
end
end
end
--Загрузка любого изображения из доступных типов
function image.load(path)
local kartinka = {}
local fileFormat = ecs.getFileFormat(path)
if string.lower(fileFormat) == ".jpg" then
kartinka["format"] = ".jpg"
kartinka["image"] = loadJPG(path)
elseif string.lower(fileFormat) == ".png" then
kartinka["format"] = ".png"
kartinka["image"] = loadPNG(path)
else
ecs.error("Wrong file format! (not .png or .jpg)")
end
return kartinka
end
--Отрисовка этого изображения
function image.draw(x, y, kartinka)
if kartinka.format == ".jpg" then
image.drawJPG(x, y, kartinka["image"])
elseif kartinka.format == ".png" then
image.drawPNG(x, y, kartinka["image"])
end
end
---------------------------------------------------------------------------------------------------------------------
-- ecs.prepareToExit()
-- local cyka1 = image.load("System/OS/Icons/Love.png")
-- local cyka2 = image.load("Pastebin.app/Resources/Icon.png")
-- image.draw(2, 2, cyka1)
-- image.draw(40, 2, cyka2)
return image