This commit is contained in:
Igor Timofeev 2016-01-10 23:36:39 +03:00
parent eda1560577
commit 769fd67380
3 changed files with 419 additions and 259 deletions

View File

@ -959,7 +959,19 @@ function ECSAPI.stringWrap(strings, limit)
end
--Моя любимая функция ошибки C:
function ECSAPI.error(text)
function ECSAPI.error(...)
local args = {...}
local text = ""
if #args > 1 then
for i = 1, #args do
--text = text .. "[" .. i .. "] = " .. tostring(args[i])
if type(args[i]) == "string" then args[i] = "\"" .. args[i] .. "\"" end
text = text .. tostring(args[i])
if i ~= #args then text = text .. ", " end
end
else
text = tostring(args[1])
end
ECSAPI.universalWindow("auto", "auto", math.ceil(gpu.getResolution() * 0.45), ECSAPI.windowColors.background, true, {"EmptyLine"}, {"CenterText", 0x880000, "Ошибка!"}, {"EmptyLine"}, {"WrappedText", 0x262626, text}, {"EmptyLine"}, {"Button", {0x880000, 0xffffff, "OK!"}})
end
@ -1299,7 +1311,7 @@ function ECSAPI.newApplicationFromLuaFile(pathToLuaFile, pathWhereToCreateApplic
--ECSAPI.universalWindow("auto", "auto", 30, ECSAPI.windowColors.background, true, {"EmptyLine"}, {"CenterText", 0x000000, "Приложение создано!"}, {"EmptyLine"}, {"Button", {ecs.colors.green, 0xffffff, "OK"}})
else
ecs.error("Указанный файл иконки не существует.")
ECSAPI.error("Указанный файл иконки не существует.")
return
end
end

View File

@ -6,7 +6,7 @@ local function check(tVal, tMaxVal, tMinVal, tType)
end
local function isNan(x)
return x~=x
return x~=x
end
--RGB model
@ -87,18 +87,30 @@ end
--Смешивание двух цветов на основе альфа-канала второго
function colorlib.alphaBlend(back_color, front_color, alpha_channel)
local INVERTED_ALPHA_CHANNEL = 255 - alpha_channel
local INVERTED_ALPHA_CHANNEL = 255 - alpha_channel
local back_color_rr, back_color_gg, back_color_bb = colorlib.HEXtoRGB(back_color)
local front_color_rr, front_color_gg, front_color_bb = colorlib.HEXtoRGB(front_color)
local back_color_rr, back_color_gg, back_color_bb = colorlib.HEXtoRGB(back_color)
local front_color_rr, front_color_gg, front_color_bb = colorlib.HEXtoRGB(front_color)
local blended_rr = front_color_rr * INVERTED_ALPHA_CHANNEL / 255 + back_color_rr * alpha_channel / 255
local blended_gg = front_color_gg * INVERTED_ALPHA_CHANNEL / 255 + back_color_gg * alpha_channel / 255
local blended_bb = front_color_bb * INVERTED_ALPHA_CHANNEL / 255 + back_color_bb * alpha_channel / 255
local blended_rr = front_color_rr * INVERTED_ALPHA_CHANNEL / 255 + back_color_rr * alpha_channel / 255
local blended_gg = front_color_gg * INVERTED_ALPHA_CHANNEL / 255 + back_color_gg * alpha_channel / 255
local blended_bb = front_color_bb * INVERTED_ALPHA_CHANNEL / 255 + back_color_bb * alpha_channel / 255
INVERTED_ALPHA_CHANNEL, back_color_rr, back_color_gg, back_color_bb, front_color_rr, front_color_gg, front_color_bb = nil, nil, nil, nil, nil, nil, nil
INVERTED_ALPHA_CHANNEL, back_color_rr, back_color_gg, back_color_bb, front_color_rr, front_color_gg, front_color_bb = nil, nil, nil, nil, nil, nil, nil
return colorlib.RGBtoHEX( blended_rr, blended_gg, blended_bb )
return colorlib.RGBtoHEX( blended_rr, blended_gg, blended_bb )
end
function colorlib.convert24BitTo8Bit(hex24)
local red, green, blue = colorlib.HEXtoRGB(hex24)
return (bit32.lshift(math.floor((red / 32)), 5) + bit32.lshift(math.floor((green / 32)), 2) + math.floor((blue / 64)))
end
function colorlib.convert8BitTo24Bit(hex8)
local red = bit32.rshift(hex8, 5) * 32
local green = bit32.rshift(bit32.band(hex8, 28), 2) * 32
local blue = bit32.band(hex8, 3) * 64
return colorlib.RGBtoHEX(red, green, blue)
end
return colorlib

View File

@ -1,25 +1,80 @@
-------------------------------------------- OCIF Image Format -----------------------------------------------------------
---------------------------------------- OpenComputers Image Format (OCIF) -----------------------------------------------------------
local copyright = [[
--[[
Автор: Pirnogion
Автор: Pornogion
VK: https://vk.com/id88323331
Соавтор: IT
VK: https://vk.com/id7799889
Основные функции:
image.load(string путь): table изображение
Загружает существующую картинку в одном из трех поддерживаемых форматов,
по умолчанию .pic, .rawpic или .png, и возвращает ее в качестве массива (таблицы)
image.draw(int x, int y, table изображение)
Рисует на экране загруженную ранее картинку по указанным координатам
image.save(string путь, table изображение)
Сохраняет указанную картинку в указанном в пути формате, крайне рекомендуется
использовать .pic для экономии места на диске.
Функции для работы с изображением:
image.expand(table картинка, string направление, int количество пикселей[, int цвет фона, int цвет текста, int прозрачность, char символ]): table картинка
Расширяет указанную картинку в указанном направлении (fromRight, fromLeft, fromTop, fromBottom),
создавая при этом пустые белые пиксели. Если указаны опциональные аргументы, то вместо пустых
пикселей могут быть вполне конкретные значения.
image.crop(table картинка, string направление, int количество пикселей): table картинка
Обрезает указанную картинку в указанном направлении (fromRight, fromLeft, fromTop, fromBottom),
удаляя лишние пиксели.
image.rotate(table картинка, int угол): table картинка
Поворачивает указанную картинку на указанный угол. Угол может иметь
значение 90, 180 и 270 градусов.
image.flipVertical(table картинка): table картинка
Отражает указанную картинку по вертикали.
image.flipHorizontal(table картинка): table картинка
Отражает указанную картинку по горизонтали.
Функции для работы с цветом:
image.hueSaturationBrightness(table картинка, int тон, int насыщенность, int яркость): table картинка
Корректирует цветовой тон, насыщенность и яркость указанной картинки.
Значения аргументов могут быть отрицательными для уменьшения параметра
и положительными для его увеличения. Если значение, к примеру, насыщенности
менять не требуется, просто указывайте 0.
Для удобства вы можете использовать следующие сокращения:
image.hue(table картинка, int тон): table картинка
image.saturation(table картинка, int насыщенность): table картинка
image.brightness(table картинка, int яркость): table картинка
image.blackAndWhite(table картинка): table картинка
image.colorBalance(table картинка, int красный, int зеленый, int синий): table картинка
Корректирует цветовые каналы изображения указанной картинки. Аргументы цветовых
каналов могут принимать как отрицательные значения для уменьшения интенсивности канала,
так и положительные для увеличения.
image.invert(table картинка): table картинка
Инвертирует цвета в указанной картинке.
]]
--------------------------------------- Подгрузка библиотек --------------------------------------------------------------
local bit = require("bit32")
-- Адаптивная загрузка необходимых библиотек и компонентов
local libraries = {
["component"] = "component",
["unicode"] = "unicode",
["fs"] = "filesystem",
["colorlib"] = "colorlib",
["bit"] = "bit32",
}
local components = {
@ -34,18 +89,13 @@ local image = {}
-------------------------------------------- Переменные -------------------------------------------------------------------
--Cигнатура OCIF-файла
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 constants = {
OCIFSignature = { string.char(0x89), string.char(0x6F), string.char(0x63), string.char(0x69), string.char(0x66), string.char(0x1A), string.char(0x0A) },
elementCount = 4,
byteSize = 8,
nullChar = 0,
rawImageLoadStep = 19,
fileOpenError = "Can't open file",
compressedFileFormat = ".pic",
rawFileFormat = ".rawpic",
pngFileFormat = ".png",
@ -53,6 +103,27 @@ local constants = {
---------------------------------------- Локальные функции -------------------------------------------------------------------
--Формула конвертации индекса массива изображения в абсолютные координаты пикселя изображения
local function convertIndexToCoords(index, width)
--Приводим индекс к корректному виду (1 = 1, 4 = 2, 7 = 3, 10 = 4, 13 = 5, ...)
index = (index + constants.elementCount - 1) / constants.elementCount
--Получаем остаток от деления индекса на ширину изображения
local ostatok = index % width
--Если остаток равен 0, то х равен ширине изображения, а если нет, то х равен остатку
local x = (ostatok == 0) and width or ostatok
--А теперь как два пальца получаем координату по Y
local y = math.ceil(index / width)
--Очищаем остаток из оперативки
ostatok = nil
--Возвращаем координаты
return x, y
end
--Формула конвертации абсолютных координат пикселя изображения в индекс для массива изображения
local function convertCoordsToIndex(x, y, width)
return (width * (y - 1) + x) * constants.elementCount - constants.elementCount + 1
end
--Выделить бит-терминатор в первом байте UTF-8 символа: 1100 0010 --> 0010 0000
local function selectTerminateBit_l()
local prevByte = nil
@ -152,7 +223,7 @@ local function getFileFormat(path)
if starting == nil then
return nil
else
return unicode.sub(name,starting + 1, -1)
return unicode.sub(name, starting + 1, -1)
end
name, starting, ending = nil, nil, nil
end
@ -162,9 +233,9 @@ end
-- Запись в файл сжатого OCIF-формата изображения
function image.saveCompressed(path, picture)
local encodedPixel
local file = assert( io.open(path, "w"), constants.fileOpenError )
local file = assert( io.open(path, "w"), "Can't open file: access denied!" )
file:write( table.unpack( ocif_signature_expand ) )
file:write( table.unpack( constants.OCIFSignature ) )
file:write( string.char( picture.width ) )
file:write( string.char( picture.height ) )
@ -187,10 +258,10 @@ function image.loadCompressed(path)
local file = assert( io.open(path, "rb"), constants.fileOpenError )
--Проверка файла на соответствие сигнатуры
local signature1, signature2 = readBytes(file, 4), readBytes(file, 3)
if ( signature1 ~= ocif_signature1 or signature2 ~= ocif_signature2 ) then
local readedSignature = file:read(7)
if readedSignature ~= table.concat(constants.OCIFSignature) then
file:close()
return nil
error("Wrong OCIF file signature: " .. readedSignature .." != " .. table.concat(constants.OCIFSignatureExpand))
end
--Читаем ширину и высоту файла
@ -314,12 +385,13 @@ function image.convertToGroupedImage(picture)
--Получаем символ из неоптимизированного массива
background, foreground, alpha, symbol = picture[i], picture[i + 1], picture[i + 2], picture[i + 3]
--Группируем картинку по цветам
optimizedPicture[background] = optimizedPicture[background] or {}
optimizedPicture[background][foreground] = optimizedPicture[background][foreground] or {}
table.insert(optimizedPicture[background][foreground], xPos)
table.insert(optimizedPicture[background][foreground], yPos)
table.insert(optimizedPicture[background][foreground], alpha)
table.insert(optimizedPicture[background][foreground], symbol)
optimizedPicture[alpha] = optimizedPicture[alpha] or {}
optimizedPicture[alpha][symbol] = optimizedPicture[alpha][symbol] or {}
optimizedPicture[alpha][symbol][foreground] = optimizedPicture[alpha][symbol][foreground] or {}
optimizedPicture[alpha][symbol][foreground][background] = optimizedPicture[alpha][symbol][foreground][background] or {}
table.insert(optimizedPicture[alpha][symbol][foreground][background], xPos)
table.insert(optimizedPicture[alpha][symbol][foreground][background], yPos)
--Если xPos достигает width изображения, то сбросить на 1, иначе xPos++
xPos = (xPos == picture.width) and 1 or xPos + 1
--Если xPos равняется 1, то yPos++, а если нет, то похуй
@ -330,7 +402,7 @@ function image.convertToGroupedImage(picture)
end
--Нарисовать по указанным координатам картинку указанной ширины и высоты для теста
function image.drawRandomImage(x, y, width, height)
function image.createRandomImage(x, y, width, height)
local picture = {}
local symbolArray = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "А", "Б", "В", "Г", "Д", "Е", "Ж", "З", "И", "Й", "К", "Л", "И", "Н", "О", "П", "Р", "С", "Т", "У", "Ф", "Х", "Ц", "Ч", "Ш", "Щ", "Ъ", "Ы", "Ь", "Э", "Ю", "Я"}
picture.width = width
@ -348,7 +420,26 @@ function image.drawRandomImage(x, y, width, height)
table.insert(picture, symbol)
end
end
image.draw(x, y, picture)
-- image.draw(x, y, picture)
return picture
end
-- Функция оптимизации цвета текста у картинки, уменьшает число GPU-операций при отрисовке
-- Вызывается только при сохранении файла, так что на быстродействии не сказывается,
-- а в целом штука очень и очень полезная. Фиксит криворукость художников.
function image.optimize(picture, showOptimizationProcess)
local currentForeground = 0x000000
local optimizationCounter = 0
for i = 1, #picture, constants.elementCount do
if picture[i + 3] == " " and picture[i + 1] ~= currentForeground then
picture[i + 1] = currentForeground
if showOptimizationProcess then picture[i + 3] = "#" end
optimizationCounter = optimizationCounter + 1
else
currentForeground = picture[i + 1]
end
end
if showOptimizationProcess then ecs.error("Count of optimized pixels: " .. optimizationCounter) end
return picture
end
@ -360,6 +451,8 @@ function image.save(path, picture)
fs.makeDirectory(fs.path(path))
--Получаем формат указанного файла
local fileFormat = getFileFormat(path)
--Оптимизируем картинку
picture = image.optimize(picture)
--Проверяем соответствие формата файла
if fileFormat == constants.compressedFileFormat then
image.saveCompressed(path, picture)
@ -389,77 +482,48 @@ function image.load(path)
end
--Отрисовка изображения типа 3 (подробнее о типах см. конец файла)
function image.draw(x, y, rawPicture)
function image.draw(x, y, picture)
--Конвертируем в групповое изображение
local picture = image.convertToGroupedImage(rawPicture)
picture = image.convertToGroupedImage(picture)
--Все как обычно
x, y = x - 1, y - 1
--Переменные, чтобы в цикле эту парашу не создавать
local currentBackground, xPos, yPos, alpha, symbol
local _, _
--Перебираем все цвета фона
for background in pairs(picture) do
--Заранее ставим корректный цвет фона
gpu.setBackground(background)
--Перебираем все цвета текста
for foreground in pairs(picture[background]) do
--Ставим сразу и корректный цвет текста
gpu.setForeground(foreground)
--Перебираем все пиксели
for i = 1, #picture[background][foreground], 4 do
--Получаем временную репрезентацию
xPos, yPos, alpha, symbol = picture[background][foreground][i], picture[background][foreground][i + 1], picture[background][foreground][i + 2], picture[background][foreground][i + 3]
--Если альфа имеется, но она не совсем прозрачна
if (alpha > 0x00 and alpha < 0xFF) or (alpha == 0xFF and symbol ~= " ")then
_, _, currentBackground = gpu.get(x + xPos, y + yPos)
currentBackground = colorlib.alphaBlend(currentBackground, background, alpha)
gpu.setBackground(currentBackground)
--Рисуем символ на экране
gpu.set(x + xPos, y + yPos, symbol)
--Если альфа отсутствует
elseif alpha == 0x00 then
if currentBackground ~= background then
currentBackground = background
gpu.setBackground(currentBackground)
local xPos, yPos, currentBackground
for alpha in pairs(picture) do
for symbol in pairs(picture[alpha]) do
for foreground in pairs(picture[alpha][symbol]) do
if gpu.getForeground ~= foreground then gpu.setForeground(foreground) end
for background in pairs(picture[alpha][symbol][foreground]) do
if gpu.getBackground ~= background then gpu.setBackground(background) end
currentBackground = background
for i = 1, #picture[alpha][symbol][foreground][background], 2 do
xPos, yPos = x + picture[alpha][symbol][foreground][background][i], y + picture[alpha][symbol][foreground][background][i + 1]
--Если альфа имеется, но она не совсем прозрачна
if (alpha > 0x00 and alpha < 0xFF) or (alpha == 0xFF and symbol ~= " ")then
_, _, currentBackground = gpu.get(xPos, yPos)
currentBackground = colorlib.alphaBlend(currentBackground, background, alpha)
gpu.setBackground(currentBackground)
gpu.set(xPos, yPos, symbol)
elseif alpha == 0x00 then
if currentBackground ~= background then
currentBackground = background
gpu.setBackground(currentBackground)
end
gpu.set(xPos, yPos, symbol)
end
--ecs.wait()
end
--Рисуем символ на экране
gpu.set(x + xPos, y + yPos, symbol)
end
--Выгружаем сгруппированное изображение из памяти
picture[background][foreground][i], picture[background][foreground][i + 1], picture[background][foreground][i + 2], picture[background][foreground][i + 3] = nil, nil, nil, nil
end
end
--Выгружаем данные о текущем цвете текста из памяти
picture[background][foreground] = nil
end
--Выгружаем данные о текущем фоне из памяти
picture[background] = nil
end
end
local function loadOldPng(path)
local massiv = {}
local file = io.open(path, "r")
local lineCounter = 0
local sLine = 0
for line in file:lines() do
sLine = unicode.len(line)
for i = 1, sLine, 16 do
table.insert(massiv, tonumber("0x" .. unicode.sub(line, i, i + 5)))
table.insert(massiv, tonumber("0x" .. unicode.sub(line, i + 7, i + 12)))
table.insert(massiv, 0x00)
table.insert(massiv, tonumber("0x" .. unicode.sub(line, i + 14, i + 14)))
end
lineCounter = lineCounter + 1
end
massiv.width = sLine / 16
massiv.height = lineCounter
return massiv
end
------------------------------------------ Функция снятия скриншота с экрана ------------------------------------------------
--Сделать скриншот экрана и сохранить его по указанному пути
function image.screenshot(path)
@ -480,172 +544,242 @@ function image.screenshot(path)
image.save(path, picture)
end
------------------------------------------ Функции обработки изображения ------------------------------------------------
function image.expand(picture, mode, countOfPixels, background, foreground, alpha, symbol)
background = background or 0xffffff
foreground = foreground or 0x000000
alpha = alpha or 0x00
symbol = symbol or " "
if mode == "fromRight" then
for j = 1, countOfPixels do
for i = 1, picture.height do
local index = convertCoordsToIndex(picture.width + j, i, picture.width + j)
table.insert(picture, index, symbol); table.insert(picture, index, alpha); table.insert(picture, index, foreground); table.insert(picture, index, background)
end
end
picture.width = picture.width + countOfPixels
elseif mode == "fromLeft" then
for j = 1, countOfPixels do
for i = 1, picture.height do
local index = convertCoordsToIndex(1, i, picture.width + j)
table.insert(picture, index, symbol); table.insert(picture, index, alpha); table.insert(picture, index, foreground); table.insert(picture, index, background)
end
end
picture.width = picture.width + countOfPixels
elseif mode == "fromTop" then
for i = 1, (countOfPixels * picture.width) do
table.insert(picture, 1, symbol); table.insert(picture, 1, alpha); table.insert(picture, 1, foreground); table.insert(picture, 1, background)
end
picture.height = picture.height + countOfPixels
elseif mode == "fromBottom" then
for i = 1, (countOfPixels * picture.width) do
table.insert(picture, background); table.insert(picture, foreground); table.insert(picture, alpha); table.insert(picture, symbol)
end
picture.height = picture.height + countOfPixels
else
error("Wrong image expanding mode: only 'fromRight', 'fromLeft', 'fromTop' and 'fromBottom' are supported.")
end
return picture
end
function image.crop(picture, mode, countOfPixels)
if mode == "fromRight" then
for j = 1, countOfPixels do
for i = 1, picture.height do
local index = convertCoordsToIndex(picture.width + 1 - j, i, picture.width - j)
for a = 1, constants.elementCount do table.remove(picture, index) end
end
end
picture.width = picture.width - countOfPixels
elseif mode == "fromLeft" then
for j = 1, countOfPixels do
for i = 1, picture.height do
local index = convertCoordsToIndex(1, i, picture.width - j)
for a = 1, constants.elementCount do table.remove(picture, index) end
end
end
picture.width = picture.width - countOfPixels
elseif mode == "fromTop" then
for i = 1, (countOfPixels * constants.elementCount * picture.width) do table.remove(picture, 1) end
picture.height = picture.height - countOfPixels
elseif mode == "fromBottom" then
for i = 1, (countOfPixels * constants.elementCount * picture.width) do table.remove(picture, #picture) end
picture.height = picture.height - countOfPixels
else
error("Wrong image cropping mode: only 'fromRight', 'fromLeft', 'fromTop' and 'fromBottom' are supported.")
end
return picture
end
function image.flipVertical(picture)
local newPicture = {}; newPicture.width = picture.width; newPicture.height = picture.height
for j = picture.height, 1, -1 do
for i = 1, picture.width do
local index = convertCoordsToIndex(i, j, picture.width)
table.insert(newPicture, picture[index]); table.insert(newPicture, picture[index + 1]); table.insert(newPicture, picture[index + 2]); table.insert(newPicture, picture[index + 3])
picture[index], picture[index + 1], picture[index + 2], picture[index + 3] = nil, nil, nil, nil
end
end
return newPicture
end
function image.flipHorizontal(picture)
local newPicture = {}; newPicture.width = picture.width; newPicture.height = picture.height
for j = 1, picture.height do
for i = picture.width, 1, -1 do
local index = convertCoordsToIndex(i, j, picture.width)
table.insert(newPicture, picture[index]); table.insert(newPicture, picture[index + 1]); table.insert(newPicture, picture[index + 2]); table.insert(newPicture, picture[index + 3])
picture[index], picture[index + 1], picture[index + 2], picture[index + 3] = nil, nil, nil, nil
end
end
return newPicture
end
function image.rotate(picture, angle)
local function rotateBy90(picture)
local newPicture = {}; newPicture.width = picture.height; newPicture.height = picture.width
for i = 1, picture.width do
for j = picture.height, 1, -1 do
local index = convertCoordsToIndex(i, j, picture.width)
table.insert(newPicture, picture[index]); table.insert(newPicture, picture[index + 1]); table.insert(newPicture, picture[index + 2]); table.insert(newPicture, picture[index + 3])
picture[index], picture[index + 1], picture[index + 2], picture[index + 3] = nil, nil, nil, nil
end
end
return newPicture
end
local function rotateBy180(picture)
local newPicture = {}; newPicture.width = picture.width; newPicture.height = picture.height
for j = picture.height, 1, -1 do
for i = picture.width, 1, -1 do
local index = convertCoordsToIndex(i, j, picture.width)
table.insert(newPicture, picture[index]); table.insert(newPicture, picture[index + 1]); table.insert(newPicture, picture[index + 2]); table.insert(newPicture, picture[index + 3])
picture[index], picture[index + 1], picture[index + 2], picture[index + 3] = nil, nil, nil, nil
end
end
return newPicture
end
local function rotateBy270(picture)
local newPicture = {}; newPicture.width = picture.height; newPicture.height = picture.width
for i = picture.width, 1, -1 do
for j = 1, picture.height do
local index = convertCoordsToIndex(i, j, picture.width)
table.insert(newPicture, picture[index]); table.insert(newPicture, picture[index + 1]); table.insert(newPicture, picture[index + 2]); table.insert(newPicture, picture[index + 3])
picture[index], picture[index + 1], picture[index + 2], picture[index + 3] = nil, nil, nil, nil
end
end
return newPicture
end
if angle == 90 then
return rotateBy90(picture)
elseif angle == 180 then
return rotateBy180(picture)
elseif angle == 270 then
return rotateBy270(picture)
else
error("Can't rotate image: angle must be 90, 180 or 270 degrees.")
end
end
------------------------------------------ Функции для работы с цветом -----------------------------------------------
function image.hueSaturationBrigtness(picture, hue, saturation, brightness)
local function calculateBrightnessChanges(color)
local h, s, b = colorlib.HEXtoHSB(color)
b = b + brightness; if b < 0 then b = 0 elseif b > 100 then b = 100 end
s = s + saturation; if s < 0 then s = 0 elseif s > 100 then s = 100 end
h = h + hue; if h < 0 then h = 0 elseif h > 360 then h = 360 end
return colorlib.HSBtoHEX(h, s, b)
end
for i = 1, #picture, 4 do
picture[i] = calculateBrightnessChanges(picture[i])
picture[i + 1] = calculateBrightnessChanges(picture[i + 1])
end
return picture
end
function image.hue(picture, hue)
return image.hueSaturationBrigtness(picture, hue, 0, 0)
end
function image.saturation(picture, saturation)
return image.hueSaturationBrigtness(picture, 0, saturation, 0)
end
function image.brightness(picture, brightness)
return image.hueSaturationBrigtness(picture, 0, 0, brightness)
end
function image.blackAndWhite(picture)
return image.hueSaturationBrigtness(picture, 0, -100, 0)
end
function image.colorBalance(picture, r, g, b)
local function calculateRGBChanges(color)
local rr, gg, bb = colorlib.HEXtoRGB(color)
rr = rr + r; gg = gg + g; bb = bb + b
if rr < 0 then rr = 0 elseif rr > 255 then rr = 255 end
if gg < 0 then gg = 0 elseif gg > 255 then gg = 255 end
if bb < 0 then bb = 0 elseif bb > 255 then bb = 255 end
return colorlib.RGBtoHEX(rr, gg, bb)
end
for i = 1, #picture, 4 do
picture[i] = calculateRGBChanges(picture[i])
picture[i + 1] = calculateRGBChanges(picture[i + 1])
end
return picture
end
function image.invert(picture)
for i = 1, #picture, 4 do
picture[i] = 0xffffff - picture[i]
picture[i + 1] = 0xffffff - picture[i + 1]
end
return picture
end
function image.photoFilter(picture, color, transparency)
if transparency < 0 then transparency = 0 elseif transparency > 255 then transparency = 255 end
for i = 1, #picture, 4 do
picture[i] = colorlib.alphaBlend(picture[i], color, transparency)
picture[i + 1] = colorlib.alphaBlend(picture[i + 1], color, transparency)
end
return picture
end
function image.replaceColor(picture, fromColor, toColor)
for i = 1, #picture, 4 do
if picture[i] == fromColor then picture[i] = toColor end
end
return picture
end
------------------------------------------ Примеры работы с библиотекой ------------------------------------------------
-- ecs.prepareToExit()
-- ecs.error("Создаю и рисую картинку!")
-- local generatedPic = image.drawRandomImage(1, 1, 160, 50)
-- ecs.error("Сохраняю созданную картинку в формате .pic!")
-- ecs.prepareToExit()
-- image.save("1.pic", generatedPic)
-- ecs.error("Сохраняю созданную картинку в формате .rawpic!")
-- ecs.prepareToExit()
-- image.save("1.rawpic", generatedPic)
-- ecs.error("Загружаю сохраненную картинку в формате .pic!")
-- ecs.prepareToExit()
-- local loadedPic = image.load("1.pic")
-- image.draw(1, 1, loadedPic)
-- ecs.error("Загружаю сохраненную картинку в формате .rawpic!")
-- ecs.prepareToExit()
-- local loadedPic = image.load("1.rawpic")
-- image.draw(1, 1, loadedPic)
------------------------------------------ Типы массивов изображений ---------------------------------------------------
-- local cyka = image.load("MineOS/Applications/Nano.app/Resources/Icon.pic")
-- local cyka = image.load("MineOS/System/OS/Icons/Folder.pic")
-- local cyka = image.load("MineOS/System/OS/Icons/Love.pic")
--[[
Тип 1:
Основной формат изображения, линейная запись данных о пикселях,
сжатие двух цветов и альфа-канала в одно число. Минимальный расход
оперативной памяти, однако для изменения цвета требует декомпрессию.
Структура:
local picture = {
width = ширина изображения,
height = высота изображения,
Сжатые цвета и альфа-канал,
Символ,
Сжатые цвета и альфа-канал,
Символ,
...
}
Пример:
local picture = {
width = 2,
height = 2,
0xff00aa,
"Q",
0x88aacc,
"W",
0xff00aa,
"E",
0x88aacc,
"R"
}
Тип 2 конвертируется только в тип 3 и только для отрисовки на экране:
Изображение типа 3 = image.convertToGroupedImage( Сюда кидаем массив изображения типа 2 )
Тип 2 (сгруппированный по цветам формат, ипользуется только для отрисовки изображения):
Структура:
local picture = {
Цвет фона 1 = {
Цвет текста 1 = {
Координата по X,
Координата по Y,
Альфа-канал,
Символ,
Координата по X,
Координата по Y,
Альфа-канал,
Символ,
...
},
Цвет текста 2 = {
Координата по X,
Координата по Y,
Альфа-канал,
Символ,
Координата по X,
Координата по Y,
Альфа-канал,
Символ,
...
},
...
},
Цвет фона 2 = {
Цвет текста 1 = {
Координата по X,
Координата по Y,
Альфа-канал,
Символ,
Координата по X,
Координата по Y,
Альфа-канал,
Символ,
...
},
Цвет текста 2 = {
Координата по X,
Координата по Y,
Альфа-канал,
Символ,
Координата по X,
Координата по Y,
Альфа-канал,
Символ,
...
},
...
},
}
Пример:
local picture = {
0xffffff = {
0xaabbcc = {
1,
1,
0x00,
"Q",
12,
12,
0xaa,
"W"
},
0x88aa44 = {
5,
5,
0xcc,
"E",
12,
12,
0x00,
"R"
}
},
0x444444 = {
0x112233 = {
40,
20,
0x00,
"T",
12,
12,
0xaa,
"Y"
},
0x88aa44 = {
5,
5,
0xcc,
"U",
12,
12,
0x00,
"I"
}
}
}
]]
-- image.draw(2, 2, cyka)
-- cyka = image.hue(cyka, 200)
-- cyka = image.brightness(cyka, -90)
-- cyka = image.saturation(cyka, -30)
-- cyka = image.colorBalance(cyka, 0, 0, 0)
-- cyka = image.invert(cyka)
-- cyka = image.flipVertical(cyka)
-- cyka = image.flipHorizontal(cyka)
-- cyka = image.rotate(cyka, 180)
-- cyka = image.photoFilter(cyka, 0x0000FF, 0xab)
-- image.draw(16, 2, cyka)
------------------------------------------------------------------------------------------------------------------------
@ -659,3 +793,5 @@ return image