MineOS/Applications/Photoshop/Photoshop.lua

1411 lines
55 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.

------------------------------------------------ Информешйн, епта --------------------------------------------------------------
local photoshopVersion = "Photoshop v6.6"
local copyright = [[
Photoshop v6.6 для OpenComputers
Автор: ECS
Контактый адрес: https://vk.com/id7799889
Соавтор: Pornogion
Контактый адрес: https://vk.com/id88323331
Что нового в версии 6.6:
- Программа адаптирована под работу с нумерически индексированным форматом изображения
- Добавлена поддержка кодирования формата OCIF6
Что нового в версии 6.5:
- Палитра заменена на более быструю и стильную, работающую на тройном буфере
- Добавлена возможность загрузки изображения из строки, созданной методом сохранения StringImage
Что нового в версии 6.4:
- Добавлена возможность выбора цвета сетки прозрачности во вкладке "Вид"
Что нового в версии 6.3:
- Добавлена поддержка языковых пакетов
Что нового в версии 6.2:
- Добавлен суб-инструмент "Полигон"
- Улучшен инструмент "Выделение", теперь можно выделять области с шириной или высотой, равными 1
Что нового в версии 6.1:
- Добавлен суб-инструмент "Эллипс"
Что нового в версии 6.0:
- Добавлен иструмент "Фигура", включающий в себя линию, прямоугольник и рамку
- Добавлен фильтр размытия по Гауссу
- Переработана концепция работы с выделениями
Что нового в версии 5.1:
- Цветовая гамма программы изменена на более детальную
- Добавлена информационная мини-панель к инструменту "выделение"
- Добавлена информация о размере изображения, отображаемая под самим изображением
- Ускорен алгоритм рисования кистью и ластиком
Что нового в версии 5.0:
- Добавлен инструмент "выделение" и несколько функций для работы с ним
- Добавлено меню "Горячие клавиши", подсказывающее, как можно удобнее работать с программой
Что нового в версии 4.0:
- Программа переведена на библиотеку тройного буфера, скорость работы увеличена в десятки раз
- Добавлены функции обрезки, расширения, поворота и отражения картинки
- Добавлены функции тона/насыщенности, цветового баланса и наложения фотофильтра
]]
copyright = nil
------------------------------------------------ Библиотеки --------------------------------------------------------------
local ecs = require("ECSAPI")
local MineOSCore = require("MineOSCore")
local GUI = require("GUI")
local fs = require("filesystem")
local unicode = require("unicode")
local image = require("image")
local component = require("component")
local keyboard = require("keyboard")
local buffer = require("doubleBuffering")
local color = require("color")
local palette = require("palette")
local event = require("event")
------------------------------------------------ Переменные --------------------------------------------------------------
--Инициализируем библиотеку двойного буфера
buffer.start()
--Массив локалиации
local localization = MineOSCore.getCurrentApplicationLocalization()
--Массив инфы о выделении
local selection
--Получаем аргументы программы
local args = {...}
--Массив главного изображения
local masterPixels = {
0,
0,
}
--Базовая цветовая схема программы
local colors = {
leftToolbar = 0x3c3c3c,
leftToolbarButton = 0x2d2d2d,
leftToolbarButtonText = 0xeeeeee,
topToolbar = 0x4b4b4b,
drawingArea = 0x1e1e1e,
console = 0x2d2d2d,
consoleText = 0x999999,
transparencyWhite = 0xffffff,
transparencyGray = 0xcccccc,
transparencyVariable = 0xffffff,
oldBackground = 0x0,
oldForeground = 0x0,
topMenu = 0xeeeeee,
topMenuText = 0x262626,
}
--Различные константы и размеры тулбаров и кликабельных зон
local sizes = {
widthOfLeftBar = 6,
}
sizes.xStartOfDrawingArea = sizes.widthOfLeftBar + 1
sizes.xEndOfDrawingArea = buffer.screen.width
sizes.yStartOfDrawingArea = 2
sizes.yEndOfDrawingArea = buffer.screen.height - 1
sizes.widthOfDrawingArea = sizes.xEndOfDrawingArea - sizes.xStartOfDrawingArea + 1
sizes.heightOfDrawingArea = sizes.yEndOfDrawingArea - sizes.yStartOfDrawingArea + 1
sizes.heightOfLeftBar = buffer.screen.height - 1
sizes.sizeOfPixelData = 4
--Для изображения
local function reCalculateImageSizes(x, y)
sizes.xStartOfImage = x or 9
sizes.yStartOfImage = y or 6
sizes.xEndOfImage = sizes.xStartOfImage + image.getWidth(masterPixels) - 1
sizes.yEndOfImage = sizes.yStartOfImage + image.getHeight(masterPixels) - 1
end
reCalculateImageSizes()
--Инструменты
local instruments = {
"M",
"B",
"E",
"F",
"T",
"S",
}
sizes.heightOfInstrument = 3
sizes.yStartOfInstruments = 2
local currentInstrument = 2
local currentBackground = 0x000000
local currentForeground = 0xFFFFFF
local currentAlpha = 0x00
local currentSymbol = " "
local currentBrushSize = 1
local savePath
local currentShape
local currentPolygonCountOfEdges
local showTransparencyGrid = true
------------------------------------------------ Функции отрисовки --------------------------------------------------------------
--Объекты для тача
local obj = {}
local function newObj(class, name, ...)
obj[class] = obj[class] or {}
obj[class][name] = {...}
end
--Функция-сваппер переменных, пока что юзается только в выделении
--А, не, наебал!
--Вон, ниже тоже юзается! Ха, удобненько
local function swap(a, b)
return b, a
end
--Адекватное округление, ибо в луашке нет такого, ХАХ
local function round(num)
if num >= 0 then
return math.floor(num + 0.5)
else
return math.ceil(num - 0.5)
end
end
--Отрисовка "прозрачной зоны", этакая сеточка чередующаяся
local function drawTransparentZone(x, y)
if showTransparencyGrid then
y = y - 1
local stro4ka1 = ""
local stro4ka2 = ""
if image.getWidth(masterPixels) % 2 == 0 then
stro4ka1 = string.rep("", math.floor(image.getWidth(masterPixels) / 2))
stro4ka2 = stro4ka1
else
stro4ka1 = string.rep("", math.floor(image.getWidth(masterPixels) / 2))
stro4ka2 = stro4ka1 .. ""
end
for i = 1, image.getHeight(masterPixels) do
if i % 2 == 0 then
buffer.square(x, y + i, image.getWidth(masterPixels), 1, colors.transparencyWhite, colors.transparencyGray, " ")
buffer.text(x + 1, y + i, colors.transparencyGray, stro4ka1)
else
buffer.square(x, y + i, image.getWidth(masterPixels), 1, colors.transparencyWhite, colors.transparencyGray)
buffer.text(x, y + i, colors.transparencyGray, stro4ka2)
end
end
else
buffer.square(x, y, image.getWidth(masterPixels), image.getHeight(masterPixels), colors.transparencyWhite, 0x000000, " ")
end
end
--Банальная заливка фона
local function drawBackground()
buffer.square(sizes.xStartOfDrawingArea, sizes.yStartOfDrawingArea, sizes.widthOfDrawingArea, sizes.heightOfDrawingArea + 1, colors.drawingArea, 0xFFFFFF, " ")
end
--Отрисовка цветов
local function drawColors()
local xPos, yPos = 2, buffer.screen.height - 4
buffer.square(xPos, yPos, 3, 2, currentBackground, 0xFFFFFF, " ")
buffer.square(xPos + 3, yPos + 1, 1, 2, currentForeground, 0xFFFFFF, " ")
buffer.square(xPos + 1, yPos + 2, 2, 1, currentForeground, 0xFFFFFF, " ")
buffer.text(xPos + 1, yPos + 3, 0xaaaaaa, "←→")
newObj("Colors", 1, xPos, yPos, xPos + 2, yPos + 1)
newObj("Colors", 2, xPos + 3, yPos + 1, xPos + 3, yPos + 2)
newObj("Colors", 3, xPos + 1, yPos + 2, xPos + 3, yPos + 2)
newObj("Colors", 4, xPos + 1, yPos + 3, xPos + 2, yPos + 3)
end
--Отрисовка панели инструментов слева
local function drawLeftBar()
--Рисуем подложечку
buffer.square(1, 5, sizes.widthOfLeftBar, sizes.heightOfLeftBar, colors.leftToolbar, 0xFFFFFF, " ")
--Рисуем инструменты
local yPos = sizes.yStartOfInstruments
for i = 1, #instruments do
if currentInstrument == i then
buffer.square(1, yPos, sizes.widthOfLeftBar, sizes.heightOfInstrument, colors.leftToolbarButton, 0xFFFFFF, " ")
else
buffer.square(1, yPos, sizes.widthOfLeftBar, sizes.heightOfInstrument, colors.leftToolbar, 0xFFFFFF, " ")
end
buffer.text(3, yPos + 1, colors.leftToolbarButtonText, instruments[i])
newObj("Instruments", i, 1, yPos, sizes.widthOfLeftBar, yPos + sizes.heightOfInstrument - 1)
yPos = yPos + sizes.heightOfInstrument
end
--И цвета
drawColors()
end
--Отрисовка верхнего меню
local function drawTopMenu()
obj.menu = GUI.menu(1, 1, buffer.screen.width, colors.topMenu, colors.topMenuText, 0x3366CC, 0xFFFFFF, 0)
obj.menu:addItem("PS", ecs.colors.blue)
obj.menu:addItem(localization.file)
obj.menu:addItem(localization.image)
obj.menu:addItem(localization.view)
obj.menu:addItem(localization.hotkeys)
obj.menu:addItem(localization.about)
obj.menu:draw()
end
--Функция, создающая пустой массив изображения на основе указанных ранее длины и ширины
local function createEmptyMasterPixels()
--Создаем пустой мастерпиксельс
for j = 1, image.getHeight(masterPixels) * image.getWidth(masterPixels) do
table.insert(masterPixels, 0x010101)
table.insert(masterPixels, 0x010101)
table.insert(masterPixels, 0xFF)
table.insert(masterPixels, " ")
end
end
--Мини-консолька для отладки, сообщающая снизу, че происходит ваще
local function console(text)
buffer.square(sizes.xStartOfDrawingArea, buffer.screen.height, sizes.widthOfDrawingArea, 1, colors.console, colors.consoleText, " ")
local _, total, used = ecs.getInfoAboutRAM()
local RAMText = used .. "/" .. total .. " KB RAM"
buffer.text(sizes.xEndOfDrawingArea - unicode.len(RAMText), buffer.screen.height, colors.consoleText, RAMText)
buffer.text(sizes.xStartOfDrawingArea + 1, buffer.screen.height, colors.consoleText, text)
end
--Функция, берущая указанный пиксель из массива изображения и рисующая его в буфере корректно,
--т.е. с учетом прозрачности и т.п.
local function drawPixel(x, y, xPixel, yPixel, iterator)
--Получаем тукущие данные о пикселе
local background, foreground, alpha, symbol = masterPixels[iterator], masterPixels[iterator + 1], masterPixels[iterator + 2], masterPixels[iterator + 3]
--Если пиксель не прозрачный
if alpha == 0x00 then
buffer.set(x, y, background, foreground, symbol)
--Если пиксель прозрачнее непрозрачного
elseif alpha > 0x00 then
local blendColor
if xPixel % 2 == 0 then
if yPixel % 2 == 0 then
blendColor = colors.transparencyGray
else
blendColor = colors.transparencyWhite
end
else
if yPixel % 2 == 0 then
blendColor = colors.transparencyWhite
else
blendColor = colors.transparencyGray
end
end
buffer.set(x, y, color.blend(blendColor, background, alpha / 0xFF), foreground, symbol)
end
background, foreground, alpha, symbol = nil, nil, nil, nil
end
--Пиздюлинка, показывающая размер текста и тыпы
local function drawTooltip(x, y, ...)
local texts = {...}
--Рассчитываем ширину пиздюлинки
local maxWidth = 0; for i = 1, #texts do maxWidth = math.max(maxWidth, unicode.len(texts[i])) end
--Рисуем пиздюлинку
buffer.square(x, y, maxWidth + 2, #texts, 0x000000, 0xFFFFFF, " ", 69); x = x + 1
for i = 1, #texts do buffer.text(x, y, 0xFFFFFF, texts[i]); y = y + 1 end
end
--Функция для отрисовки выделения соотв. инструментом
local function drawSelection()
local color = 0x000000
local xStart, yStart = sizes.xStartOfImage + selection.x - 1, sizes.yStartOfImage + selection.y - 1
local xEnd, yEnd = xStart + selection.width - 1, yStart + selection.height - 1
local currentBackground
local function nextColor()
if color == 0x000000 then color = 0xFFFFFF else color = 0x000000 end
end
--"━"
--"┃"
local function drawSelectionSquare(x1, y1, x2, y2, xStep, yStep, symbol)
for y = y1, y2, yStep do
for x = x1, x2, xStep do
local background = buffer.get(x, y)
buffer.set(x, y, background, color, symbol)
nextColor()
end
end
end
local function drawCornerPoint(x, y, symbol)
local background = buffer.get(x, y)
buffer.set(x, y, background, color, symbol)
nextColor()
end
if selection.width > 1 and selection.height > 1 then
drawCornerPoint(xStart, yStart, "")
drawSelectionSquare(xStart + 1, yStart, xEnd - 1, yStart, 1, 1, "")
drawCornerPoint(xEnd, yStart, "")
drawSelectionSquare(xEnd, yStart + 1, xEnd, yEnd - 1, 1, 1, "")
drawCornerPoint(xEnd, yEnd, "")
drawSelectionSquare(xEnd - 1, yEnd, xStart + 1, yEnd, -1, 1, "")
drawCornerPoint(xStart, yEnd, "")
drawSelectionSquare(xStart, yEnd - 1, xStart, yStart + 1, 1, -1, "")
else
if selection.width == 1 then
drawSelectionSquare(xStart, yStart, xStart, yEnd, 1, 1, "")
elseif selection.height == 1 then
drawSelectionSquare(xStart, yStart, xEnd, yStart, 1, 1, "")
end
end
drawTooltip(xEnd + 2, yEnd - 1, localization.w .. ": " .. selection.width .. " px", localization.h .. ": " .. selection.height .. " px")
-- drawTooltip(xEnd + 2, yEnd - 1, "Ш: " .. selection.width .. " px", "В: " .. selection.height .. " px", "S: " .. xStart .. "x" .. yStart, "E: " .. xEnd .. "x" .. yEnd)
end
local function line(x0, y0, x1, y1, background, applyToMasterPixels)
local steep = false;
if math.abs(x0 - x1) < math.abs(y0 - y1 ) then
x0, y0 = swap(x0, y0)
x1, y1 = swap(x1, y1)
steep = true;
end
if (x0 > x1) then
x0, x1 = swap(x0, x1)
y0, y1 = swap(y0, y1)
end
local dx = x1 - x0;
local dy = y1 - y0;
local derror2 = math.abs(dy) * 2
local error2 = 0;
local y = y0;
for x = x0, x1, 1 do
if steep then
if applyToMasterPixels then
image.set(masterPixels, y, x, background, 0x000000, 0x00, " ")
else
buffer.set(y, x, background, 0x000000, " ")
end
else
if applyToMasterPixels then
image.set(masterPixels, x, y, background, 0x000000, 0x00, " ")
else
buffer.set(x, y, background, 0x000000, " ")
end
end
error2 = error2 + derror2;
if error2 > dx then
y = y + (y1 > y0 and 1 or -1);
error2 = error2 - dx * 2;
end
end
end
local function drawShapeCornerPoints(xStart, yStart, xEnd, yEnd)
buffer.set(xStart, yStart, 0x99FF80, 0x000000, " ")
buffer.set(xEnd, yEnd, 0x99FF80, 0x000000, " ")
end
local function drawLineShape()
local xStart, yStart = sizes.xStartOfImage + selection.xStart - 1, sizes.yStartOfImage + selection.yStart - 1
local xEnd, yEnd = sizes.xStartOfImage + selection.xEnd - 1, sizes.yStartOfImage + selection.yEnd - 1
line(xStart, yStart, xEnd, yEnd, currentBackground)
drawShapeCornerPoints(xStart, yStart, xEnd, yEnd)
drawTooltip(xEnd + 2, yEnd - 3, localization.w .. ": " .. selection.width .. " px", localization.h .. ": " .. selection.height .. " px", " ", localization.accept)
end
--Функция для обводки выделенной зоны
local function stroke(x, y, width, height, color, applyToMasterPixels)
if applyToMasterPixels then
local iterator
for i = x, x + width - 1 do
iterator = image.getImageIndexByCoordinates(i, y, image.getWidth(masterPixels))
masterPixels[iterator] = color; masterPixels[iterator + 1] = 0x0; masterPixels[iterator + 2] = 0x0; masterPixels[iterator + 3] = " "
iterator = image.getImageIndexByCoordinates(i, y + height - 1, image.getWidth(masterPixels))
masterPixels[iterator] = color; masterPixels[iterator + 1] = 0x0; masterPixels[iterator + 2] = 0x0; masterPixels[iterator + 3] = " "
end
for i = y, y + height - 1 do
iterator = image.getImageIndexByCoordinates(x, i, image.getWidth(masterPixels))
masterPixels[iterator] = color; masterPixels[iterator + 1] = 0x0; masterPixels[iterator + 2] = 0x0; masterPixels[iterator + 3] = " "
iterator = image.getImageIndexByCoordinates(x + width - 1, i, image.getWidth(masterPixels))
masterPixels[iterator] = color; masterPixels[iterator + 1] = 0x0; masterPixels[iterator + 2] = 0x0; masterPixels[iterator + 3] = " "
end
else
buffer.square(x, y, width, 1, color, 0x000000, " ")
buffer.square(x, y + height - 1, width, 1, color, 0x000000, " ")
buffer.square(x, y, 1, height, color, 0x000000, " ")
buffer.square(x + width - 1, y, 1, height, color, 0x000000, " ")
end
end
local function ellipse(xStart, yStart, width, height, color, applyToMasterPixels)
--helper function, draws pixel and mirrors it
local function setpixel4(centerX, centerY, deltaX, deltaY, color)
if applyToMasterPixels then
image.set(masterPixels, centerX + deltaX, centerY + deltaY, color, 0x000000, 0x00, " ")
image.set(masterPixels, centerX - deltaX, centerY + deltaY, color, 0x000000, 0x00, " ")
image.set(masterPixels, centerX + deltaX, centerY - deltaY, color, 0x000000, 0x00, " ")
image.set(masterPixels, centerX - deltaX, centerY - deltaY, color, 0x000000, 0x00, " ")
else
buffer.set(centerX + deltaX, centerY + deltaY, color, 0x000000, " ")
buffer.set(centerX - deltaX, centerY + deltaY, color, 0x000000, " ")
buffer.set(centerX + deltaX, centerY - deltaY, color, 0x000000, " ")
buffer.set(centerX - deltaX, centerY - deltaY, color, 0x000000, " ")
end
end
--red ellipse, 2*10px border
local centerX = math.floor(xStart + width / 2)
local centerY = math.floor(yStart + height / 2)
local radiusX = math.floor(width / 2)
local radiusY = math.floor(height / 2)
local radiusX2 = radiusX ^ 2
local radiusY2 = radiusY ^ 2
--upper and lower halves
local quarter = math.floor(radiusX2 / math.sqrt(radiusX2 + radiusY2))
for x = 0, quarter do
local y = radiusY * math.sqrt(1 - x^2 / radiusX2)
setpixel4(centerX, centerY, x, math.floor(y), color);
end
--right and left halves
quarter = math.floor(radiusY2 / math.sqrt(radiusX2 + radiusY2));
for y = 0, quarter do
x = radiusX * math.sqrt(1 - y^2 / radiusY2);
setpixel4(centerX, centerY, math.floor(x), y, color);
end
end
local function polygon(xCenter, yCenter, xStart, yStart, countOfEdges, color)
local degreeStep = 360 / countOfEdges
local deltaX, deltaY = xStart - xCenter, yStart - yCenter
local radius = math.sqrt(deltaX ^ 2 + deltaY ^ 2)
local halfRadius = radius / 2
local startDegree = math.deg(math.asin(deltaX / radius))
local function calculatePosition(degree)
local radDegree = math.rad(degree)
local deltaX2 = math.sin(radDegree) * radius
local deltaY2 = math.cos(radDegree) * radius
return round(xCenter + deltaX2), round(yCenter + (deltaY >= 0 and deltaY2 or -deltaY2))
end
local xOld, yOld, xNew, yNew = calculatePosition(startDegree)
for degree = (startDegree + degreeStep - 1), (startDegree + 360), degreeStep do
xNew, yNew = calculatePosition(degree)
buffer.line(xOld, yOld, xNew, yNew, color, 0x000000, " ")
xOld, yOld = xNew, yNew
end
end
local function drawPolygonShape()
local xStart, yStart = sizes.xStartOfImage + selection.xStart - 1, sizes.yStartOfImage + selection.yStart - 1
local xEnd, yEnd = sizes.xStartOfImage + selection.xEnd - 1, sizes.yStartOfImage + selection.yEnd - 1
local radius = math.floor(math.sqrt(selection.width ^ 2 + (selection.height*2) ^ 2))
polygon(xStart, yStart, xEnd, yEnd, currentPolygonCountOfEdges, currentBackground)
drawShapeCornerPoints(xStart, yStart, xEnd, yEnd)
drawTooltip(xEnd + 2, yEnd - 3, localization.radius .. ": " .. radius .. " px", localization.edges .. ": " .. currentPolygonCountOfEdges, " ", localization.accept)
end
local function drawSquareShape(type)
local xStart, yStart = sizes.xStartOfImage + selection.x - 1, sizes.yStartOfImage + selection.y - 1
local xEnd, yEnd = xStart + selection.width - 1, yStart + selection.height - 1
if type == "filledSquare" then
buffer.square(xStart, yStart, selection.width, selection.height, currentBackground, 0x000000, " ")
elseif type == "frame" then
stroke(xStart, yStart, selection.width, selection.height, currentBackground, false)
elseif type == "ellipse" then
ellipse(xStart, yStart, selection.width, selection.height, currentBackground, false)
end
drawShapeCornerPoints(xStart, yStart, xEnd, yEnd)
drawTooltip(xEnd + 2, yEnd - 3, localization.w .. ": " .. selection.width .. " px", localization.h .. ": " .. selection.height .. " px", " ", localization.accept)
end
local function drawMultiPointInstrument()
if selection and selection.finished == true then
if instruments[currentInstrument] == "M" then
drawSelection()
elseif instruments[currentInstrument] == "S" then
if currentShape == localization.line then
drawLineShape()
elseif currentShape == localization.ellipse then
drawSquareShape("ellipse")
elseif currentShape == localization.rectangle then
drawSquareShape("filledSquare")
elseif currentShape == localization.border then
drawSquareShape("frame")
elseif currentShape == localization.polygon then
drawPolygonShape()
end
end
end
end
--Отрисовка изображения
local function drawImage()
--Стартовые нужности
local xPixel, yPixel = 1, 1
local xPos, yPos = sizes.xStartOfImage, sizes.yStartOfImage
--Устанавливаем ограничение прорисовки, чтобы картинка не съебывала за дозволенную зону
buffer.setDrawLimit(sizes.xStartOfDrawingArea, sizes.yStartOfDrawingArea, sizes.widthOfDrawingArea, sizes.heightOfDrawingArea)
--Рисуем прозрачную зону
drawTransparentZone(xPos, yPos)
--Перебираем массив мастерпиксельса
for i = 3, #masterPixels, 4 do
--Рисуем пиксель, если у него прозрачность не абсолютная, ЛИБО имеется какой-то символ
--Т.е. даже если прозрачность и охуела, но символ есть, то рисуем его
if masterPixels[i + 2] ~= 0xFF or masterPixels[i + 3] ~= " " then
drawPixel(xPos, yPos, xPixel, yPixel, i)
end
--Всякие расчеты координат
xPixel = xPixel + 1
xPos = xPos + 1
if xPixel > image.getWidth(masterPixels) then xPixel = 1; xPos = sizes.xStartOfImage; yPixel = yPixel + 1; yPos = yPos + 1 end
end
if image.getWidth(masterPixels) > 0 and image.getHeight(masterPixels) > 0 then
local text = localization.size .. ": " .. image.getWidth(masterPixels) .. "x" .. image.getHeight(masterPixels) .. " px"
xPos = math.floor(sizes.xStartOfImage + image.getWidth(masterPixels) / 2 - unicode.len(text) / 2)
buffer.text(xPos, sizes.yEndOfImage + 1, 0xFFFFFF, text)
end
--Рисуем мультиинструмент
drawMultiPointInstrument()
--Убираем ограничение отрисовки
buffer.resetDrawLimit()
end
--Просто для удобства
local function drawBackgroundAndImage()
drawBackground()
drawImage()
end
--Функция, рисующая ВСЕ, абсолютли, епта
local function drawAll()
drawBackground()
drawLeftBar()
drawTopMenu()
drawBackgroundAndImage()
buffer.draw()
end
------------------------------------------------ Вспомогательные функции для работы с изображением и прочим --------------------------------------------------------------
--Смена инструмента на указанный номер
local function changeInstrumentTo(ID)
currentInstrument = ID
selection = nil
drawAll()
end
--Перемещалка картинки в указанном направлении, поддерживающая все инструменты
local function move(direction)
if instruments[currentInstrument] == "M" and selection and selection.finished == true then
if direction == "up" then
selection.y = selection.y - 1
if selection.y < 1 then selection.y = 1 end
elseif direction == "down" then
selection.y = selection.y + 1
if selection.y + selection.height - 1 > image.getHeight(masterPixels) then selection.y = selection.y - 1 end
elseif direction == "left" then
selection.x = selection.x - 1
if selection.x < 1 then selection.x = 1 end
elseif direction == "right" then
selection.x = selection.x + 1
if selection.x + selection.width - 1 > image.getWidth(masterPixels) then selection.x = selection.x - 1 end
end
else
local howMuchUpDown = 2
local howMuchLeftRight = 4
if direction == "up" then
reCalculateImageSizes(sizes.xStartOfImage, sizes.yStartOfImage - howMuchUpDown)
elseif direction == "down" then
reCalculateImageSizes(sizes.xStartOfImage, sizes.yStartOfImage + howMuchUpDown)
elseif direction == "left" then
reCalculateImageSizes(sizes.xStartOfImage - howMuchLeftRight, sizes.yStartOfImage)
elseif direction == "right" then
reCalculateImageSizes(sizes.xStartOfImage + howMuchLeftRight, sizes.yStartOfImage)
end
end
drawBackgroundAndImage()
buffer.draw()
end
--Просто более удобная установка пикселя, а то все эти плюсы, минусы, бррр
local function setPixel(iterator, background, foreground, alpha, symbol)
masterPixels[iterator] = background
masterPixels[iterator + 1] = foreground
masterPixels[iterator + 2] = alpha
masterPixels[iterator + 3] = symbol
end
--Функция, меняющая цвета местами
local function swapColors()
currentBackground, currentForeground = swap(currentBackground, currentForeground)
drawColors()
console("Цвета поменяны местами")
end
--Ух, сука! Функция для работы инструмента текста
--Лютая дичь, спиздил со старого фш, но, вроде, пашет нормас
--Правда, чет есть предчувствие, что костыльная и багованная она, ну да похуй
local function inputText(x, y, limit)
local oldPixels = ecs.rememberOldPixels(x,y-1,x+limit-1,y+1)
local text = ""
local inputPos = 1
local function drawThisShit()
for i = 1, inputPos do
ecs.invertedText(x + i - 1, y + 1, "")
ecs.adaptiveText(x + i - 1, y - 1, " ", currentBackground)
end
ecs.invertedText(x + inputPos - 1, y + 1, "")--"▲","▼"
ecs.invertedText(x + inputPos - 1, y - 1, "")
ecs.adaptiveText(x, y, ecs.stringLimit("start", text, limit, false), currentBackground)
end
drawThisShit()
while true do
local e = {event.pull()}
if e[1] == "key_down" then
if e[4] == 14 then
if unicode.len(text) >= 1 then
text = unicode.sub(text, 1, -2)
if unicode.len(text) < (limit - 1) then
inputPos = inputPos - 1
end
ecs.drawOldPixels(oldPixels)
drawThisShit()
end
elseif e[4] == 28 then
break
elseif e[4] == 200 then
text = text .. ""
if unicode.len(text) < limit then
inputPos = inputPos + 1
end
drawThisShit()
elseif e[4] == 208 then
text = text .. ""
if unicode.len(text) < limit then
inputPos = inputPos + 1
end
drawThisShit()
else
local symbol = ecs.convertCodeToSymbol(e[3])
if symbol ~= nil then
text = text .. symbol
if unicode.len(text) < limit then
inputPos = inputPos + 1
end
drawThisShit()
end
end
elseif e[1] == "clipboard" then
if e[3] then
text = text .. e[3]
if unicode.len(text) < limit then
inputPos = inputPos + unicode.len(e[3])
end
drawThisShit()
end
end
end
ecs.drawOldPixels(oldPixels)
if text == "" then text = " " end
return text
end
--Функция-применятор текста к массиву изображения
local function saveTextToPixels(x, y, text)
local sText = unicode.len(text)
local iterator
x = x - 1
for i = 1, sText do
if x + i > image.getWidth(masterPixels) then break end
iterator = image.getImageIndexByCoordinates(x + i, y, image.getWidth(masterPixels))
setPixel(iterator, masterPixels[iterator], currentBackground, masterPixels[iterator + 2], unicode.sub(text, i, i))
end
end
--Функция-центратор картинки по центру моника
local function tryToFitImageOnCenterOfScreen()
reCalculateImageSizes()
local x, y = sizes.xStartOfImage, sizes.yStartOfImage
if image.getWidth(masterPixels) < sizes.widthOfDrawingArea then
x = math.floor(sizes.xStartOfDrawingArea + sizes.widthOfDrawingArea / 2 - image.getWidth(masterPixels) / 2) - 1
end
if image.getHeight(masterPixels) < sizes.heightOfDrawingArea then
y = math.floor(sizes.yStartOfDrawingArea + sizes.heightOfDrawingArea / 2 - image.getHeight(masterPixels) / 2)
end
reCalculateImageSizes(x, y)
end
--Функция, спрашивающая юзверя, какого размера пикчу он хочет создать - ну, и создает ее
local function new()
selection = nil
local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, {"EmptyLine"}, {"CenterText", 0x262626, localization.newDocument}, {"EmptyLine"}, {"Input", 0x262626, 0x880000, localization.width}, {"Input", 0x262626, 0x880000, localization.height}, {"EmptyLine"}, {"Button", {0x999999, 0xffffff, "OK"}})
data[1] = tonumber(data[1]) or 51
data[2] = tonumber(data[2]) or 19
masterPixels = {}
masterPixels[1], masterPixels[2] = data[1], data[2]
createEmptyMasterPixels()
tryToFitImageOnCenterOfScreen()
drawAll()
end
--Обычная рекурсивная заливка, алгоритм спизжен с вики
--Есть инфа, что выжирает стек, но Луа, вроде, не особо ругается, так что заебок все
local function fill(x, y, startColor, fillColor)
local function doFill(xStart, yStart)
local iterator = image.getImageIndexByCoordinates(xStart, yStart, image.getWidth(masterPixels))
--Завершаем функцию, если цвет в массиве не такой, какой мы заливаем
if masterPixels[iterator] ~= startColor or masterPixels[iterator] == fillColor then return end
--Заливаем в память
masterPixels[iterator] = fillColor
masterPixels[iterator + 2] = currentAlpha
doFill(xStart + 1, yStart)
doFill(xStart - 1, yStart)
doFill(xStart, yStart + 1)
doFill(xStart, yStart - 1)
iterator = nil
end
doFill(x, y)
end
--Кисть, КИИИИСТЬ
local function brush(x, y, background, foreground, alpha, symbol)
--Смещение влево и вправо относительно указанного центра кисти
--КОРОЧ, НЕ ТУПИ
--Чтобы кисточка была по центру мыши, ну
local position = math.floor(currentBrushSize / 2)
x, y = x - position, y - position
--Хуевинка для рисования
local newIterator
--Перебираем кисть по ширине и высоте
for cyka = 1, currentBrushSize do
for pidor = 1, currentBrushSize do
--Если этот кусочек входит в границы рисовабельной зоны, то
if x >= 1 and x <= image.getWidth(masterPixels) and y >= 1 and y <= image.getHeight(masterPixels) then
--Считаем итератор для кусочка кисти
newIterator = image.getImageIndexByCoordinates(x, y, image.getWidth(masterPixels))
--Если прозрачности кисти ВАЩЕ НЕТ, то просто рисуем как обычненько все
if alpha == 0x00 then
setPixel(newIterator, background, foreground, alpha, symbol)
--Если прозрачности кисти есть какая-то, но она не абсолютная
elseif alpha < 0xFF and alpha > 0x00 then
--Если пиксель в массиве ни хуя не прозрачный, то оставляем его таким же, разве что цвет меняем на сблендированный
if masterPixels[newIterator + 2] == 0x00 then
local gettedBackground = color.blend(masterPixels[newIterator], background, alpha / 0xFF)
setPixel(newIterator, gettedBackground, foreground, 0x00, symbol)
--А если прозрачный, то смешиваем прозрачности
--Пиздануться вообще, сук
else
--Если его прозрачность максимальная
if masterPixels[newIterator + 2] == 0xFF then
setPixel(newIterator, background, foreground, alpha, symbol)
--Если не максимальная
else
local newAlpha = masterPixels[newIterator + 2] - (0xFF - alpha)
if newAlpha < 0x00 then newAlpha = 0x00 end
setPixel(newIterator, background, foreground, newAlpha, symbol)
end
end
--Если указанная прозрачность максимальна, т.е. равна 0xFF
else
setPixel(newIterator, 0x000000, 0x000000, 0xFF, " ")
end
--Рисуем пиксель из мастерпиксельса
drawPixel(x + sizes.xStartOfImage - 1, y + sizes.yStartOfImage - 1, x, y, newIterator)
end
x = x + 1
end
x = x - currentBrushSize
y = y + 1
end
end
--Функция-обрезчик картинки
local function crop()
if selection then
masterPixels = image.crop(masterPixels, selection.x, selection.y, selection.width, selection.height)
selection = nil
tryToFitImageOnCenterOfScreen()
drawAll()
end
end
--Функция-расширитель картинки
local function expand()
local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true,
{"EmptyLine"},
{"CenterText", 0x262626, localization.expand},
{"EmptyLine"},
{"Input", 0x262626, 0x880000, localization.countOfPixels},
{"Selector", 0x262626, 0x880000, localization.fromBottom, localization.fromTop, localization.fromLeft, localization.fromRight},
{"EmptyLine"},
{"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}}
)
if data[3] == "OK" then
local countOfPixels = tonumber(data[1])
if countOfPixels then
masterPixels = image.expand(masterPixels,
data[2] == localization.fromTop and countOfPixels or 0,
data[2] == localization.fromBottom and countOfPixels or 0,
data[2] == localization.fromLeft and countOfPixels or 0,
data[2] == localization.fromRight and countOfPixels or 0,
0x010101, 0x010101, 0xFF, " "
)
reCalculateImageSizes(sizes.xStartOfImage, sizes.yStartOfImage)
drawAll()
end
end
end
--Функция-загрузчик картинки из файла
local function loadImageFromFile(path)
if fs.exists(path) then
selection = nil
masterPixels = image.load(path)
savePath = path
tryToFitImageOnCenterOfScreen()
else
ecs.error("Файл \"" .. path .. "\" не существует")
end
end
--Функция-заполнитель выделенной зоны какими-либо данными
local function fillSelection(background, foreground, alpha, symbol)
for j = selection.y, selection.y + selection.height - 1 do
for i = selection.x, selection.x + selection.width - 1 do
local iterator = image.getImageIndexByCoordinates(i, j, image.getWidth(masterPixels))
masterPixels[iterator] = background
masterPixels[iterator + 1] = foreground
masterPixels[iterator + 2] = alpha
masterPixels[iterator + 3] = symbol
end
end
drawAll()
end
local function applyShapeToMasterPixels()
if currentShape == localization.line then
line(selection.xStart, selection.yStart, selection.xEnd, selection.yEnd, currentBackground, true)
elseif currentShape == localization.rectangle then
fillSelection(currentBackground, 0x00000, 0x00, " ")
elseif currentShape == localization.border then
stroke(selection.x, selection.y, selection.width, selection.height, currentBackground, true)
elseif currentShape == localization.ellipse then
ellipse(selection.x, selection.y, selection.width, selection.height, currentBackground, true)
end
selection = nil
drawBackgroundAndImage()
buffer.draw()
end
------------------------------------------------ Старт программы --------------------------------------------------------------
--Рисуем весь интерфейс чисто для красоты
drawAll()
--Открываем файлы по аргументам программы
if args[1] == "o" or args[1] == "open" or args[1] == "-o" or args[1] == "load" then
loadImageFromFile(args[2])
else
new()
end
--Отрисовываем интерфейс снова, поскольку у нас либо создался новый документ, либо открылся имеющийся файл
drawAll()
--Анализируем ивенты
while true do
local e = {event.pull()}
if e[1] == "touch" or e[1] == "drag" or e[1] == "drop" then
--Левый клик
if e[5] == 0 then
--Если кликнули на рисовабельную зонку
if ecs.clickedAtArea(e[3], e[4], sizes.xStartOfImage, sizes.yStartOfImage, sizes.xEndOfImage, sizes.yEndOfImage) then
--Получаем координаты в изображении и итератор
local x, y = e[3] - sizes.xStartOfImage + 1, e[4] - sizes.yStartOfImage + 1
local iterator = image.getImageIndexByCoordinates(x, y, image.getWidth(masterPixels))
--Все для инструментов мультиточечного рисования
if instruments[currentInstrument] == "M" or instruments[currentInstrument] == "S" then
if e[1] == "touch" then
selection = {}
selection.xStart, selection.yStart = x, y
elseif e[1] == "drag" and selection then
local x1, y1 = selection.xStart, selection.yStart
local x2, y2 = x, y
if x1 > x2 then
x1, x2 = swap(x1, x2)
end
if y1 > y2 then
y1, y2 = swap(y1, y2)
end
selection.x, selection.y = x1, y1
selection.x2, selection.y2 = x2, y2
selection.xEnd, selection.yEnd = x, y
selection.width = selection.x2 - selection.x + 1
selection.height = selection.y2 - selection.y + 1
selection.finished = true
end
--Если выделение полностью завершено, то отдаем контроль отрисовочным функциям
-- if instruments[currentInstrument] == "M" then
drawBackgroundAndImage()
buffer.draw()
-- end
--Кисть
elseif instruments[currentInstrument] == "B" then
--Если нажата клавиша альт
if keyboard.isKeyDown(56) then
local _, gettedForeground, gettedBackground = component.gpu.get(e[3], e[4])
currentBackground = gettedBackground
currentForeground = gettedForeground
drawColors()
buffer.draw()
--Если обычная кисть, просто кисть, вообще всем кистям кисть
else
brush(x, y, currentBackground, currentForeground, currentAlpha, currentSymbol)
--Пишем что-то в консоли
console("Кисть: клик на точку "..e[3].."x"..e[4]..", координаты в изображении: "..x.."x"..y..", индекс массива изображения: "..iterator)
buffer.draw()
end
--Ластик
elseif instruments[currentInstrument] == "E" then
brush(x, y, currentBackground, currentForeground, 0xFF, currentSymbol)
console("Ластик: клик на точку "..e[3].."x"..e[4]..", координаты в изображении: "..x.."x"..y..", индекс массива изображения: "..iterator)
buffer.draw()
--Текст
elseif instruments[currentInstrument] == "T" then
local limit = image.getWidth(masterPixels) - x + 1
local text = inputText(e[3], e[4], limit)
saveTextToPixels(x, y, text)
drawImage()
buffer.draw()
--Заливка
elseif instruments[currentInstrument] == "F" then
fill(x, y, masterPixels[iterator], currentBackground)
drawImage()
buffer.draw()
end
iterator, x, y = nil, nil, nil
end
--Цвета
for key in pairs(obj["Colors"]) do
if ecs.clickedAtArea(e[3], e[4], obj["Colors"][key][1], obj["Colors"][key][2], obj["Colors"][key][3], obj["Colors"][key][4]) then
if key == 1 then
currentBackground = palette.show("auto", "auto", currentBackground) or currentBackground
drawAll()
elseif key == 2 or key == 3 then
currentForeground = palette.show("auto", "auto", currentForeground) or currentForeground
drawAll()
elseif key == 4 then
buffer.text(obj["Colors"][key][1], obj["Colors"][key][2], 0xFF0000, "←→")
os.sleep(0.2)
swapColors()
buffer.draw()
end
break
end
end
--Инструменты
for key in pairs(obj["Instruments"]) do
if ecs.clickedAtArea(e[3], e[4], obj["Instruments"][key][1], obj["Instruments"][key][2], obj["Instruments"][key][3], obj["Instruments"][key][4]) then
selection = nil
currentInstrument = key
drawLeftBar(); buffer.draw()
if instruments[currentInstrument] == "S" then
local action = GUI.contextMenu(obj["Instruments"][key][3] + 1, obj["Instruments"][key][2], {localization.line}, {localization.ellipse}, {localization.rectangle}, {localization.polygon}, {localization.border}):show()
currentShape = action or localization.line
if currentShape == localization.polygon then
local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true,
{"EmptyLine"},
{"CenterText", 0x262626, localization.edges},
{"EmptyLine"},
{"Selector", 0x262626, 0x880000, "3", "4", "5", "6", "7", "8", "9", "10"},
{"EmptyLine"},
{"Button", {0xaaaaaa, 0xffffff, "OK"}}
)
currentPolygonCountOfEdges = tonumber(data[1])
end
drawAll()
end
break
end
end
--Верхний меню-бар
local object = obj.menu:getClickedObject(e[3], e[4])
if object then
object:press()
buffer.draw()
local action
if object.text == localization.file then
action = GUI.contextMenu(object.x, object.y + 1, {localization.new, false, "^N"}, {localization.open, false, "^O"}, {localization.createFromString}, "-", {localization.save, (savePath == nil), "^S"}, {localization.saveAs}, "-", {localization.exit}):show()
elseif object.text == localization.image then
action = GUI.contextMenu(object.x, object.y + 1,
-- {localization.crop},
{localization.expand},
-- "-",
-- {localization.rotateBy90},
-- {localization.rotateBy180},
"-",
{localization.flipHorizontal},
{localization.flipVertical}
):show()
elseif object.text == localization.view then
action = GUI.contextMenu(object.x, object.y + 1, {localization.transparencyPad}):show()
elseif object.text == localization.about then
ecs.universalWindow("auto", "auto", 36, 0xeeeeee, true, {"EmptyLine"}, {"CenterText", 0x880000, photoshopVersion}, {"EmptyLine"}, {"CenterText", 0x262626, localization.developers}, {"CenterText", 0x555555, "Тимофеев Игорь"}, {"CenterText", 0x656565, "vk.com/id7799889"}, {"CenterText", 0x656565, "Трифонов Глеб"}, {"CenterText", 0x656565, "vk.com/id88323331"}, {"EmptyLine"}, {"CenterText", 0x262626, localization.testers}, {"CenterText", 0x656565, "Шестаков Тимофей"}, {"CenterText", 0x656565, "vk.com/id113499693"}, {"CenterText", 0x656565, "Вечтомов Роман"}, {"CenterText", 0x656565, "vk.com/id83715030"}, {"CenterText", 0x656565, "Омелаенко Максим"}, {"CenterText", 0x656565, "vk.com/paladincvm"}, {"EmptyLine"},{"Button", {0xbbbbbb, 0xffffff, "OK"}})
elseif object.text == localization.hotkeys then
ecs.universalWindow( "auto", "auto", 42, 0xeeeeee, true,
table.unpack(localization.hotkeysLines)
)
end
if action == localization.exit then
ecs.prepareToExit()
return
elseif action == localization.hueSaturation then
local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true,
{"EmptyLine"},
{"CenterText", 0x262626, localization.hueSaturation},
{"EmptyLine"},
{"Slider", 0x262626, 0x880000, 0, 100, 50, localization.hue .. ": ", ""},
{"Slider", 0x262626, ecs.colors.red, 0, 100, 50, localization.saturation .. ": ", ""},
{"Slider", 0x262626, 0x000000, 0, 100, 50, localization.brightness .. ": ", ""},
{"EmptyLine"},
{"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}}
)
if data[4] == "OK" then
masterPixels = image.hueSaturationBrightness(masterPixels, data[1] - 50, data[2] - 50, data[3] - 50)
drawAll()
end
elseif action == localization.gaussianBlur then
local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true,
{"EmptyLine"},
{"CenterText", 0x262626, localization.gaussianBlur},
{"EmptyLine"},
{"Slider", 0x262626, 0x880000, 1, 5, 2, localization.radius .. ": ", ""},
{"Slider", 0x262626, 0x880000, 1, 255, 0x88, localization.force .. ": ", ""},
{"EmptyLine"},
{"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}}
)
if data[3] == "OK" then
masterPixels = image.gaussianBlur(masterPixels, tonumber(data[1]), tonumber(data[2]))
drawAll()
end
elseif action == localization.colorBalance then
local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true,
{"EmptyLine"},
{"CenterText", 0x262626, localization.colorBalance},
{"EmptyLine"},
{"Slider", 0x262626, 0x880000, 0, 100, 50, "R: ", ""},
{"Slider", 0x262626, ecs.colors.green, 0, 100, 50, "G: ", ""},
{"Slider", 0x262626, ecs.colors.blue, 0, 100, 50, "B: ", ""},
{"EmptyLine"},
{"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}}
)
if data[4] == "OK" then
masterPixels = image.colorBalance(masterPixels, data[1] - 50, data[2] - 50, data[3] - 50)
drawAll()
end
elseif action == localization.photoFilter then
local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true,
{"EmptyLine"},
{"CenterText", 0x262626, localization.photoFilter},
{"EmptyLine"},
{"Color", localization.filterColor, 0x333333},
{"Slider", 0x262626, 0x880000, 0, 255, 100, localization.transparency .. ": ", ""},
{"EmptyLine"},
{"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}}
)
if data[3] == "OK" then
masterPixels = image.photoFilter(masterPixels, data[1], data[2])
drawAll()
end
elseif action == localization.crop then
crop()
elseif action == localization.expand then
expand()
elseif action == localization.flipVertical then
masterPixels = image.flipVertically(masterPixels)
drawAll()
elseif action == localization.flipHorizontal then
masterPixels = image.flipHorizontally(masterPixels)
drawAll()
elseif action == localization.invertColors then
masterPixels = image.invert(masterPixels)
drawAll()
elseif action == localization.blackWhite then
masterPixels = image.blackAndWhite(masterPixels)
drawAll()
elseif action == localization.rotateBy90 then
masterPixels = image.rotate(masterPixels, 90)
drawAll()
elseif action == localization.rotateBy180 then
masterPixels = image.rotate(masterPixels, 180)
drawAll()
elseif action == localization.new then
new()
drawAll()
elseif action == localization.saveAs then
local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true,
{"EmptyLine"},
{"CenterText", 0x262626, localization.saveAs},
{"EmptyLine"},
{"Input", 0x262626, 0x880000, localization.path},
{"Selector", 0x262626, 0x880000, "OCIF6", "OCIF1", "StringImage"},
{"EmptyLine"},
{"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}}
)
if data[3] == "OK" then
data[1] = data[1] or "Untitled.pic"
local path = string.gsub(data[1], "%.pic$", "") .. ".pic"
if data[2] == "StringImage" then
local file = io.open(path, "w")
file:write(image.toString(masterPixels))
file:close()
else
savePath = path
image.save(path, masterPixels, data[2] == "OCIF6" and 6 or 1)
end
end
elseif action == localization.save then
image.save(savePath, masterPixels)
elseif action == localization.open then
local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true, {"EmptyLine"}, {"CenterText", 0x262626, localization.open}, {"EmptyLine"}, {"Input", 0x262626, 0x880000, localization.path}, {"EmptyLine"}, {"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}})
if data[2] == "OK" then
local fileFormat = ecs.getFileFormat(data[1])
if not data[1] then
ecs.error("Некорректное имя файла!")
elseif not fs.exists(data[1]) then
ecs.error("Файл\""..data[1].."\" не существует!")
elseif fileFormat ~= ".pic" and fileFormat ~= ".rawpic" and fileFormat ~= ".png" then
ecs.error("Формат файла \""..fileFormat.."\" не поддерживается!")
else
loadImageFromFile(data[1])
drawAll()
end
end
elseif action == localization.createFromString then
local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true,
{"EmptyLine"},
{"CenterText", 0x262626, localization.createFromString},
{"EmptyLine"},
{"Input", 0x262626, 0x880000, localization.string},
{"EmptyLine"},
{"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}}
)
if data[2] == "OK" then
local success, picture = pcall(image.fromString, data[1])
if success then
masterPixels, selection, savePath = picture, nil, nil
tryToFitImageOnCenterOfScreen()
drawAll()
else
error("Failed to create image from string")
end
end
elseif action == localization.transparencyPad then
local data = ecs.universalWindow("auto", "auto", 30, ecs.windowColors.background, true,
{"EmptyLine"},
{"CenterText", 0x262626, localization.transparencyPad},
{"EmptyLine"},
{"Color", localization.transparencyColor .. " 1", colors.transparencyWhite},
{"Color", localization.transparencyColor .. " 2", colors.transparencyGray},
{"EmptyLine"},
{"Switch", 0xF2B233, 0xffffff, 0x262626, localization.transparencyGrid, showTransparencyGrid},
{"EmptyLine"},
{"Button", {0xaaaaaa, 0xffffff, "OK"}, {0x888888, 0xffffff, localization.cancel}}
)
if data[4] == "OK" then
colors.transparencyWhite, colors.transparencyGray, showTransparencyGrid = data[1], data[2], data[3]
drawAll()
end
end
drawTopMenu()
buffer.draw()
end
else
--Если кликнули на рисовабельную зонку
if ecs.clickedAtArea(e[3], e[4], sizes.xStartOfImage, sizes.yStartOfImage, sizes.xEndOfImage, sizes.yEndOfImage) then
if instruments[currentInstrument] == "M" and selection then
local action = GUI.contextMenu(e[3], e[4],
{localization.deselect},
{localization.crop},
"-",
{localization.fill},
{localization.border},
"-",
{localization.clear}
):show()
if action == localization.deselect then
selection = nil
drawAll()
elseif action == localization.crop then
crop()
elseif action == localization.clear then
fillSelection(0x0, 0x0, 0xFF, " ")
elseif action == localization.fill then
fillSelection(currentBackground, 0x0, 0x0, " ")
elseif action == localization.border then
stroke(selection.x, selection.y, selection.width, selection.height, currentBackground, true)
drawAll()
end
else
local x, y, width, height = e[3], e[4], 30, 12
--А это чтоб за края экрана не лезло
if y + height >= buffer.screen.height then y = buffer.screen.height - height end
if x + width + 1 >= buffer.screen.width then x = buffer.screen.width - width - 1 end
currentBrushSize, currentAlpha = table.unpack(ecs.universalWindow(x, y, width, 0xeeeeee, true, {"EmptyLine"}, {"CenterText", 0x880000, localization.brushParameters}, {"Slider", 0x262626, 0x880000, 1, 10, currentBrushSize, localization.size .. ": ", " px"}, {"Slider", 0x262626, 0x880000, 0, 255, currentAlpha, localization.transparency .. ": ", ""}, {"EmptyLine"}, {"Button", {0xbbbbbb, 0xffffff, "OK"}}))
buffer.draw()
end
end
end
elseif e[1] == "key_down" then
--Стрелки
if e[4] == 200 then
move("up")
elseif e[4] == 208 then
move("down")
elseif e[4] == 203 then
move("left")
elseif e[4] == 205 then
move("right")
-- --Пробел
-- elseif e[4] == 57 then
-- drawAll()
--ENTER
elseif e[4] == 28 then
if instruments[currentInstrument] == "S" and selection and selection.finished then
applyShapeToMasterPixels()
end
--BACKSPACE
elseif e[4] == 14 then
if selection and selection.finished then
fillSelection(0x000000, 0x000000, 0x00, " ")
drawAll()
end
--X
elseif e[4] == 45 then
swapColors()
buffer.draw()
--B
elseif e[4] == 48 then
changeInstrumentTo(2)
--E
elseif e[4] == 18 then
changeInstrumentTo(3)
--G
elseif e[4] == 34 then
changeInstrumentTo(4)
--T
elseif e[4] == 20 then
changeInstrumentTo(5)
--M
elseif e[4] == 50 then
changeInstrumentTo(1)
--D
elseif e[4] == 32 then
if keyboard.isControlDown() then
selection = nil
drawAll()
else
currentBackground = 0x000000
currentForeground = 0xFFFFFF
currentAlpha = 0x00
drawColors()
buffer.draw()
end
end
elseif e[1] == "scroll" then
if e[5] == 1 then
move("up")
else
move("down")
end
end
end
------------------------------------------------ Выход из программы --------------------------------------------------------------