MineOS/lib/image.lua
2017-04-22 01:51:36 +03:00

406 lines
13 KiB
Lua
Executable File
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.

-------------------------------------------------- Libraries --------------------------------------------------
local colorlib = require("colorlib")
local unicode = require("unicode")
local gpu = require("component").gpu
-------------------------------------------------- Constants --------------------------------------------------
local image = {}
image.formatModules = {}
-------------------------------------------------- Low-level methods --------------------------------------------------
local function compressionYield(iteration)
if iteration % 603 == 0 then os.sleep(0) end
end
function image.getImageCoordinatesByIndex(index, width)
local integer, fractional = math.modf((index - 2) / (width * 4))
return math.ceil(fractional * width), integer + 1
end
function image.getImageIndexByCoordinates(x, y, width)
return (width * 4) * (y - 1) + x * 4 - 1
end
function image.group(picture, compressColors)
local groupedPicture, x, y, iPlus2, iPlus3, background, foreground = {}, 1, 1
for i = 3, #picture, 4 do
iPlus2, iPlus3 = i + 2, i + 3
if compressColors then
background, foreground = colorlib.convert24BitTo8Bit(picture[i]), colorlib.convert24BitTo8Bit(picture[i + 1])
compressionYield(i)
else
background, foreground = picture[i], picture[i + 1]
end
groupedPicture[picture[iPlus2]] = groupedPicture[picture[iPlus2]] or {}
groupedPicture[picture[iPlus2]][picture[iPlus3]] = groupedPicture[picture[iPlus2]][picture[iPlus3]] or {}
groupedPicture[picture[iPlus2]][picture[iPlus3]][background] = groupedPicture[picture[iPlus2]][picture[iPlus3]][background] or {}
groupedPicture[picture[iPlus2]][picture[iPlus3]][background][foreground] = groupedPicture[picture[iPlus2]][picture[iPlus3]][background][foreground] or {}
groupedPicture[picture[iPlus2]][picture[iPlus3]][background][foreground][y] = groupedPicture[picture[iPlus2]][picture[iPlus3]][background][foreground][y] or {}
table.insert(groupedPicture[picture[iPlus2]][picture[iPlus3]][background][foreground][y], x)
x = x + 1
if x > picture[1] then
x, y = 1, y + 1
end
end
return groupedPicture
end
function image.draw(x, y, picture)
local groupedPicture = image.group(picture)
for alpha in pairs(groupedPicture) do
for symbol in pairs(groupedPicture[alpha]) do
for background in pairs(groupedPicture[alpha][symbol]) do
gpu.setBackground(background)
for foreground in pairs(groupedPicture[alpha][symbol][background]) do
gpu.setForeground(foreground)
for yPos in pairs(groupedPicture[alpha][symbol][background][foreground]) do
for xPos = 1, #groupedPicture[alpha][symbol][background][foreground][yPos] do
if alpha > 0x0 then
local oldBackground = background
local _, _, gpuGetBackground = gpu.get(x, y)
gpu.setBackground(colorlib.alphaBlend(gpuGetBackground, background, alpha / 0xFF))
gpu.set(x + groupedPicture[alpha][symbol][background][foreground][yPos][xPos] - 1, y + yPos - 1, symbol)
gpu.setBackground(oldBackground)
else
gpu.set(x + groupedPicture[alpha][symbol][background][foreground][yPos][xPos] - 1, y + yPos - 1, symbol)
end
end
end
end
end
end
end
end
function image.create(width, height, background, foreground, alpha, symbol, random)
local picture = {width, height}
for i = 1, width * height do
table.insert(picture, random and math.random(0x0, 0xFFFFFF) or (background or 0x0))
table.insert(picture, random and math.random(0x0, 0xFFFFFF) or (foreground or 0x0))
table.insert(picture, alpha or 0x0)
table.insert(picture, random and string.char(math.random(65, 90)) or (symbol or " "))
end
return picture
end
function image.copy(picture)
local newPicture = {}
for i = 1, #picture do
table.insert(newPicture, picture[i])
end
return newPicture
end
function image.optimize(picture)
local iPlus1, iPlus2, iPlus3
for i = 3, #picture, 4 do
iPlus1, iPlus2, iPlus3 = i + 1, i + 2, i + 3
if picture[i] == picture[iPlus1] and (picture[iPlus3] == "" or picture[iPlus3] == "") then
picture[iPlus3] = " "
end
if picture[iPlus3] == " " then
picture[iPlus1] = 0x000000
end
end
return picture
end
-------------------------------------------------- Filesystem related methods --------------------------------------------------
function image.loadFormatModule(path, fileExtension)
local loadSuccess, loadReason = loadfile(path)
if loadSuccess then
local xpcallSuccess, xpcallReason = pcall(loadSuccess, image)
if xpcallSuccess then
image.formatModules[fileExtension] = xpcallReason
else
error("Failed to execute image format module: " .. tostring(xpcallReason))
end
else
error("Failed to load image format module: " .. tostring(loadReason))
end
end
local function getFileExtension(path)
return string.match(path, "^.+(%.[^%/]+)%/?$")
end
local function loadOrSave(methodName, path, picture, encodingMethod)
local fileExtension = getFileExtension(path)
if image.formatModules[fileExtension] then
return image.formatModules[fileExtension][methodName](path, picture, encodingMethod)
else
error("Failed to open file \"" .. tostring(path) .. "\" as image: format module for extension \"" .. tostring(fileExtension) .. "\" is not loaded")
end
end
function image.save(path, picture, encodingMethod)
return loadOrSave("save", path, image.optimize(picture), encodingMethod)
end
function image.load(path)
return loadOrSave("load", path)
end
-------------------------------------------------- Image serialization --------------------------------------------------
function image.toString(picture)
local charArray = {
string.format("%02X", picture[1]),
string.format("%02X", picture[2])
}
for i = 3, #picture, 4 do
table.insert(charArray, string.format("%02X", colorlib.convert24BitTo8Bit(picture[i])))
table.insert(charArray, string.format("%02X", colorlib.convert24BitTo8Bit(picture[i])))
table.insert(charArray, string.format("%02X", picture[i + 2]))
table.insert(charArray, picture[i + 3])
compressionYield(i)
end
return table.concat(charArray)
end
function image.fromString(pictureString)
local picture = {
tonumber("0x" .. unicode.sub(pictureString, 1, 2)),
tonumber("0x" .. unicode.sub(pictureString, 3, 4))
}
for i = 5, unicode.len(pictureString), 7 do
table.insert(picture, colorlib.convert8BitTo24Bit(tonumber("0x" .. unicode.sub(pictureString, i, i + 1))))
table.insert(picture, colorlib.convert8BitTo24Bit(tonumber("0x" .. unicode.sub(pictureString, i + 2, i + 3))))
table.insert(picture, tonumber("0x" .. unicode.sub(pictureString, i + 4, i + 5)))
table.insert(picture, unicode.sub(pictureString, i + 6, i + 6))
end
return picture
end
-------------------------------------------------- Image processing --------------------------------------------------
function image.set(picture, x, y, background, foreground, alpha, symbol)
local index = image.getImageIndexByCoordinates(x, y, picture[1])
picture[index], picture[index + 1], picture[index + 2], picture[index + 3] = background, foreground, alpha, symbol
return picture
end
function image.get(picture, x, y)
local index = image.getImageIndexByCoordinates(x, y, picture[1])
return picture[index], picture[index + 1], picture[index + 2], picture[index + 3]
end
function image.getSize(picture)
return picture[1], picture[2]
end
function image.getWidth(picture)
return picture[1]
end
function image.getHeight(picture)
return picture[2]
end
function image.transform(picture, newWidth, newHeight)
local newPicture, stepWidth, stepHeight, background, foreground, alpha, symbol = {newWidth, newHeight}, picture[1] / newWidth, picture[2] / newHeight
local x, y = 1, 1
for j = 1, newHeight do
for i = 1, newWidth do
background, foreground, alpha, symbol = image.get(picture, math.floor(x), math.floor(y))
table.insert(newPicture, background)
table.insert(newPicture, foreground)
table.insert(newPicture, alpha)
table.insert(newPicture, symbol)
x = x + stepWidth
end
x, y = 1, y + stepHeight
end
return newPicture
end
function image.crop(picture, fromX, fromY, width, height)
if fromX >= 1 and fromY >= 1 and fromX + width - 1 <= picture[1] and fromY + height - 1 <= picture[2] then
local newPicture, background, foreground, alpha, symbol = {width, height}
for y = fromY, fromY + height - 1 do
for x = fromX, fromX + width - 1 do
background, foreground, alpha, symbol = image.get(picture, x, y)
table.insert(newPicture, background)
table.insert(newPicture, foreground)
table.insert(newPicture, alpha)
table.insert(newPicture, symbol)
end
end
return newPicture
else
error("Failed to crop image: target coordinates are out of source range")
end
end
function image.flipHorizontally(picture)
local newPicture, background, foreground, alpha, symbol = {picture[1], picture[2]}
for y = 1, picture[2] do
for x = picture[1], 1, -1 do
background, foreground, alpha, symbol = image.get(picture, x, y)
table.insert(newPicture, background)
table.insert(newPicture, foreground)
table.insert(newPicture, alpha)
table.insert(newPicture, symbol)
end
end
return newPicture
end
function image.flipVertically(picture)
local newPicture, background, foreground, alpha, symbol = {picture[1], picture[2]}
for y = picture[2], 1, -1 do
for x = 1, picture[1] do
background, foreground, alpha, symbol = image.get(picture, x, y)
table.insert(newPicture, background)
table.insert(newPicture, foreground)
table.insert(newPicture, alpha)
table.insert(newPicture, symbol)
end
end
return newPicture
end
function image.expand(picture, fromTop, fromBottom, fromLeft, fromRight, background, foreground, alpha, symbol)
local newPicture = image.create(picture[1] + fromRight + fromLeft, picture[2] + fromTop + fromBottom, background, foreground, alpha, symbol)
for y = 1, picture[2] do
for x = 1, picture[1] do
image.set(newPicture, x + fromLeft, y + fromTop, image.get(picture, x, y))
end
end
return newPicture
end
------------------------------------------------------------------------------------------------------------------------
image.loadFormatModule("/lib/ImageFormatModules/OCIF.lua", ".pic")
------------------------------------------------------------------------------------------------------------------------
-- local function loadImageInOldFormat(path)
-- local picture = require("image").load(path)
-- table.insert(picture, 1, picture.height)
-- table.insert(picture, 1, picture.width)
-- picture.width, picture.height = nil, nil
-- return picture
-- end
-- local fs = require("filesystem")
-- local function recursiveConversion(path, targetPath)
-- for file in fs.list(path) do
-- if fs.isDirectory(path .. file) then
-- if not string.find(path .. file, "ConvertedPics") then
-- recursiveConversion(path .. file, targetPath)
-- end
-- else
-- local fileExtension = getFileExtension(path .. file)
-- if fileExtension == ".pic" then
-- print("Загружаю пикчу в старом формате:", path .. file)
-- local oldPicture = loadImageInOldFormat(path .. file)
-- -- local newPath = string.gsub(path, ".app", "")
-- -- print("Сейвлю пикчу в новом:", targetPath .. newPath .. file)
-- -- fs.makeDirectory(targetPath .. newPath)
-- -- image.save(targetPath .. newPath .. file, oldPicture, 6)
-- -- print("---------------")
-- print("Пересохраняю ее в новом формате")
-- image.save(path .. file, oldPicture, 6)
-- end
-- end
-- end
-- end
-- recursiveConversion("/MineOS/", "/ConvertedPics/")
-- local function clearAndDraw(picture)
-- gpu.setBackground(0x2D2D2D)
-- gpu.setForeground(0xFFFFFF)
-- gpu.fill(1, 1, 160, 50, " ")
-- image.draw(1, 1, picture)
-- end
-- clearAndDraw(image.load("/MineOS/System/OS/Icons/Love.pic"))
-- local w, h = 2, 2
-- local picture = image.create(w, h, 0xFF0000, 0xFFFFFF, 0x0, "Q")
-- local picture = loadImageInOldFormat("/MineOS/System/OS/Icons/Love.pic")
-- print("Saving as old...")
-- require("image").save("/testPicOld.pic", picture, 4)
-- print("Processing image...")
-- local newPicture = image.transform(picture, 100, 50)
-- local newPicture = image.flipVertically(picture)
-- local newPicture = image.crop(picture, 4, 4, 20, 10)
-- local newPicture = image.expand(picture, 1, 1, 1, 1, 0xFFFFFF, 0x000000, 0x0, "#")
-- clearAndDraw(newPicture)
-- print("ToStringing...")
-- local pictureString = image.toString(picture)
-- print(pictureString)
-- print("FromStringing...")
-- local fromStringPicture = image.fromString("0804000000 000000 000000 000000 000000 000000 000000 0000FF 000000 0000FF 0000FF 0000FF 0000FF 0000FF 000000 0000FF 000000 000000 000000 000000 000000 000000 000000 0000FF 000000 0000FF 0000FF 0000FF 0000FF 0000FF 000000 0000FF ")
-- clearAndDraw(fromStringPicture)
-- print("Creating new...")
-- image.save("/testPic.pic", picture, 6)
-- print("Loading new...")
-- local loadedPicture = image.load("/testPic.pic")
-- print("Drawing new...")
-- clearAndDraw(loadedPicture)
------------------------------------------------------------------------------------------------------------------------
return image