mirror of
https://github.com/LDDestroier/CC/
synced 2024-12-16 13:10:29 +00:00
497 lines
14 KiB
Plaintext
497 lines
14 KiB
Plaintext
|
local tchar, bchar = string.char(31), string.char(30)
|
||
|
|
||
|
local deepCopy = function(tbl)
|
||
|
local output = {}
|
||
|
for k,v in pairs(tbl) do
|
||
|
output[k] = v
|
||
|
end
|
||
|
return output
|
||
|
end
|
||
|
|
||
|
local function stringWrite(str,pos,ins,exc)
|
||
|
str, ins = tostring(str), tostring(ins)
|
||
|
local output, fn1, fn2 = str:sub(1,pos-1)..ins..str:sub(pos+#ins)
|
||
|
if exc then
|
||
|
repeat
|
||
|
fn1, fn2 = str:find(exc,fn2 and fn2+1 or 1)
|
||
|
if fn1 then
|
||
|
output = stringWrite(output,fn1,str:sub(fn1,fn2))
|
||
|
end
|
||
|
until not fn1
|
||
|
end
|
||
|
return output
|
||
|
end
|
||
|
|
||
|
local checkValid = function(image)
|
||
|
if type(image) == "table" then
|
||
|
if #image == 3 then
|
||
|
if #image[1] + #image[2] + #image[3] >= 3 then
|
||
|
return (#image[1] == #image[2] and #image[2] == #image[3])
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
return false
|
||
|
end
|
||
|
local bl = {
|
||
|
[' '] = 0,
|
||
|
['0'] = 1,
|
||
|
['1'] = 2,
|
||
|
['2'] = 4,
|
||
|
['3'] = 8,
|
||
|
['4'] = 16,
|
||
|
['5'] = 32,
|
||
|
['6'] = 64,
|
||
|
['7'] = 128,
|
||
|
['8'] = 256,
|
||
|
['9'] = 512,
|
||
|
['a'] = 1024,
|
||
|
['b'] = 2048,
|
||
|
['c'] = 4096,
|
||
|
['d'] = 8192,
|
||
|
['e'] = 16384,
|
||
|
['f'] = 32768,
|
||
|
}
|
||
|
local lb = {}
|
||
|
for k,v in pairs(bl) do
|
||
|
lb[v] = k
|
||
|
end
|
||
|
|
||
|
local ldchart = { --it stands for light/dark chart
|
||
|
["0"] = "0",
|
||
|
["1"] = "4",
|
||
|
["2"] = "6",
|
||
|
["3"] = "0",
|
||
|
["4"] = "0",
|
||
|
["5"] = "0",
|
||
|
["6"] = "0",
|
||
|
["7"] = "8",
|
||
|
["8"] = "0",
|
||
|
["9"] = "3",
|
||
|
["a"] = "2",
|
||
|
["b"] = "9",
|
||
|
["c"] = "1",
|
||
|
["d"] = "5",
|
||
|
["e"] = "2",
|
||
|
["f"] = "7"
|
||
|
}
|
||
|
|
||
|
local getSizeNFP = function(image)
|
||
|
local xsize = 0
|
||
|
if type(image) ~= "table" then return 0,0 end
|
||
|
for y = 1, #image do xsize = math.max(xsize,#image[y]) end
|
||
|
return xsize, #image
|
||
|
end
|
||
|
|
||
|
getSize = function(image)
|
||
|
assert(checkValid(image), "Invalid image.")
|
||
|
local x, y = 0, #image[1]
|
||
|
for y = 1, #image[1] do
|
||
|
x = math.max(x, #image[1][y])
|
||
|
end
|
||
|
return x, y
|
||
|
end
|
||
|
|
||
|
crop = function(image, x1, y1, x2, y2)
|
||
|
assert(checkValid(image), "Invalid image.")
|
||
|
local output = {{},{},{}}
|
||
|
for y = y1, y2 do
|
||
|
output[1][#output[1]+1] = image[1][y]:sub(x1,x2)
|
||
|
output[2][#output[2]+1] = image[2][y]:sub(x1,x2)
|
||
|
output[3][#output[3]+1] = image[3][y]:sub(x1,x2)
|
||
|
end
|
||
|
return output
|
||
|
end
|
||
|
|
||
|
loadImageData = function(image, background) --string image
|
||
|
local output = {{},{},{}} --char, text, back
|
||
|
local y = 1
|
||
|
local text, back = " ", background or " "
|
||
|
local doSkip, c1, c2 = false
|
||
|
local maxX = 0
|
||
|
for i = 1, #image do
|
||
|
if doSkip then
|
||
|
doSkip = false
|
||
|
else
|
||
|
output[1][y] = output[1][y] or ""
|
||
|
output[2][y] = output[2][y] or ""
|
||
|
output[3][y] = output[3][y] or ""
|
||
|
c1, c2 = image:sub(i,i), image:sub(i+1,i+1)
|
||
|
if c1 == tchar then
|
||
|
text = c2
|
||
|
doSkip = true
|
||
|
elseif c1 == bchar then
|
||
|
back = c2
|
||
|
doSkip = true
|
||
|
elseif c1 == "\n" then
|
||
|
maxX = math.max(maxX, #output[1][y] + 1)
|
||
|
y = y + 1
|
||
|
text, back = " ", background or " "
|
||
|
else
|
||
|
output[1][y] = output[1][y]..c1
|
||
|
output[2][y] = output[2][y]..text
|
||
|
output[3][y] = output[3][y]..back
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
for y = 1, #output[1] do
|
||
|
output[1][y] = output[1][y] .. (" "):rep(maxX - #output[1][y])
|
||
|
output[2][y] = output[2][y] .. (" "):rep(maxX - #output[2][y])
|
||
|
output[3][y] = output[3][y] .. (" "):rep(maxX - #output[3][y])
|
||
|
end
|
||
|
return output
|
||
|
end
|
||
|
|
||
|
convertFromNFP = function(image)
|
||
|
local output = {{},{},{}}
|
||
|
local imageX, imageY = getSizeNFP(image)
|
||
|
for y = 1, imageY do
|
||
|
output[1][y] = ""
|
||
|
output[2][y] = ""
|
||
|
output[3][y] = ""
|
||
|
for x = 1, imageX do
|
||
|
output[1][y] = output[1][y]..lb[image[y][x] or " "]
|
||
|
output[2][y] = output[2][y]..lb[image[y][x] or " "]
|
||
|
output[3][y] = output[3][y]..lb[image[y][x] or " "]
|
||
|
end
|
||
|
end
|
||
|
return output
|
||
|
end
|
||
|
|
||
|
loadImage = function(path, background)
|
||
|
local file = fs.open(path,"r")
|
||
|
local output = loadImageData(file.readAll(), background)
|
||
|
file.close()
|
||
|
return output
|
||
|
end
|
||
|
|
||
|
unloadImage = function(image)
|
||
|
assert(checkValid(image), "Invalid image.")
|
||
|
local output = ""
|
||
|
local text, back = " ", " "
|
||
|
local c, t, b
|
||
|
for y = 1, #image[1] do
|
||
|
for x = 1, #image[1][y] do
|
||
|
c, t, b = image[1][y]:sub(x,x), image[2][y]:sub(x,x), image[3][y]:sub(x,x)
|
||
|
if (t ~= text) or (x + y == 2) then output = output..tchar..t end
|
||
|
if (b ~= back) or (x + y == 2) then output = output..bchar..b end
|
||
|
output = output..c
|
||
|
end
|
||
|
if y ~= #image[1] then
|
||
|
output = output.."\n"
|
||
|
text, back = " ", " "
|
||
|
end
|
||
|
end
|
||
|
return output
|
||
|
end
|
||
|
|
||
|
drawImage = function(image, x, y)
|
||
|
assert(checkValid(image), "Invalid image.")
|
||
|
local cx, cy = term.getCursorPos()
|
||
|
for iy = 1, #image[1] do
|
||
|
term.setCursorPos(x,y+(iy-1))
|
||
|
term.blit(image[1][iy], image[2][iy], image[3][iy])
|
||
|
end
|
||
|
term.setCursorPos(cx,cy)
|
||
|
end
|
||
|
|
||
|
drawImageTransparent = function(image, x, y)
|
||
|
assert(checkValid(image), "Invalid image. (" .. textutils.serialize(image) .. ")")
|
||
|
local cx, cy = term.getCursorPos()
|
||
|
local c, t, b
|
||
|
for iy = 1, #image[1] do
|
||
|
for ix = 1, #image[1][iy] do
|
||
|
c, t, b = image[1][iy]:sub(ix,ix), image[2][iy]:sub(ix,ix), image[3][iy]:sub(ix,ix)
|
||
|
if not (b == " " and c == " ") then
|
||
|
term.setCursorPos(x+(ix-1),y+(iy-1))
|
||
|
term.blit(c, t, b)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
term.setCursorPos(cx,cy)
|
||
|
end
|
||
|
|
||
|
drawImageCenter = function(image, x, y)
|
||
|
local scr_x, scr_y = term.getSize()
|
||
|
local imageX, imageY = getSize(image)
|
||
|
return drawImage(image, (x and x or (scr_x/2)) - (imageX/2), (y and y or (scr_y/2)) - (imageY/2))
|
||
|
end
|
||
|
|
||
|
drawImageCenterTransparent = function(image, x, y)
|
||
|
local scr_x, scr_y = term.getSize()
|
||
|
local imageX, imageY = getSize(image)
|
||
|
return drawImageTransparent(image, (x and x or (scr_x/2)) - (imageX/2), (y and y or (scr_y/2)) - (imageY/2))
|
||
|
end
|
||
|
|
||
|
colorSwap = function(image, tbl)
|
||
|
local output = {{},{},{}}
|
||
|
for y = 1, #image[1] do
|
||
|
output[1][y] = image[1][y]
|
||
|
output[2][y] = image[2][y]:gsub(".", tbl)
|
||
|
output[3][y] = image[3][y]:gsub(".", tbl)
|
||
|
end
|
||
|
return output
|
||
|
end
|
||
|
|
||
|
local xflippable = {
|
||
|
["\129"] = "\130",
|
||
|
["\131"] = "\131",
|
||
|
["\132"] = "\136",
|
||
|
["\133"] = "\138",
|
||
|
["\134"] = "\137",
|
||
|
["\135"] = "\139",
|
||
|
["\140"] = "\140",
|
||
|
["\141"] = "\142",
|
||
|
["\143"] = "\143",
|
||
|
}
|
||
|
local xinvertable = {
|
||
|
["\144"] = "\159",
|
||
|
["\145"] = "\157",
|
||
|
["\146"] = "\158",
|
||
|
["\147"] = "\156",
|
||
|
["\148"] = "\151",
|
||
|
["\152"] = "\155"
|
||
|
}
|
||
|
for k,v in pairs(xflippable) do
|
||
|
xflippable[v] = k
|
||
|
end
|
||
|
for k,v in pairs(xinvertable) do
|
||
|
xinvertable[v] = k
|
||
|
end
|
||
|
|
||
|
flipX = function(image)
|
||
|
assert(checkValid(image), "Invalid image.")
|
||
|
local output = {{},{},{}}
|
||
|
for y = 1, #image[1] do
|
||
|
output[1][y] = image[1][y]:reverse():gsub(".", xflippable):gsub(".", xinvertable)
|
||
|
output[2][y] = ""
|
||
|
output[3][y] = ""
|
||
|
for x = 1, #image[1][y] do
|
||
|
if (not xflippable[image[1][y]:sub(x,x)]) or xinvertable[image[1][y]:sub(x,x)] then
|
||
|
output[2][y] = image[3][y]:sub(x,x) .. output[2][y]
|
||
|
output[3][y] = image[2][y]:sub(x,x) .. output[3][y]
|
||
|
else
|
||
|
output[2][y] = image[2][y]:sub(x,x) .. output[2][y]
|
||
|
output[3][y] = image[3][y]:sub(x,x) .. output[3][y]
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
return output
|
||
|
end
|
||
|
|
||
|
flipY = function(image)
|
||
|
assert(checkValid(image), "Invalid image.")
|
||
|
local output = {{},{},{}}
|
||
|
for y = #image[1], 1, -1 do
|
||
|
output[1][#output[1]+1] = image[1][y]
|
||
|
output[2][#output[2]+1] = image[2][y]
|
||
|
output[3][#output[3]+1] = image[3][y]
|
||
|
end
|
||
|
return output
|
||
|
end
|
||
|
|
||
|
grayOut = function(image)
|
||
|
assert(checkValid(image), "Invalid image.")
|
||
|
local output = {{},{},{}}
|
||
|
local chart = {
|
||
|
["0"] = "0",
|
||
|
["1"] = "8",
|
||
|
["2"] = "8",
|
||
|
["3"] = "8",
|
||
|
["4"] = "8",
|
||
|
["5"] = "8",
|
||
|
["6"] = "8",
|
||
|
["7"] = "7",
|
||
|
["8"] = "8",
|
||
|
["9"] = "7",
|
||
|
["a"] = "7",
|
||
|
["b"] = "7",
|
||
|
["c"] = "7",
|
||
|
["d"] = "7",
|
||
|
["e"] = "7",
|
||
|
["f"] = "f"
|
||
|
}
|
||
|
for k,v in pairs(chart) do
|
||
|
for y = 1, #image[1] do
|
||
|
output[1][y] = image[1][y]:gsub(k,v)
|
||
|
output[2][y] = image[2][y]:gsub(k,v)
|
||
|
output[3][y] = image[3][y]:gsub(k,v)
|
||
|
end
|
||
|
end
|
||
|
return output
|
||
|
end
|
||
|
|
||
|
greyOut = grayOut
|
||
|
|
||
|
lighten = function(image)
|
||
|
assert(checkValid(image), "Invalid image.")
|
||
|
local output = {{},{},{}}
|
||
|
for k,v in pairs(ldchart) do
|
||
|
for y = 1, #image[1] do
|
||
|
output[1][y] = image[1][y]:gsub(k,v)
|
||
|
output[2][y] = image[2][y]:gsub(k,v)
|
||
|
output[3][y] = image[3][y]:gsub(k,v)
|
||
|
end
|
||
|
end
|
||
|
return output
|
||
|
end
|
||
|
|
||
|
darken = function(image)
|
||
|
assert(checkValid(image), "Invalid image.")
|
||
|
local output = {{},{},{}}
|
||
|
for k,v in pairs(ldchart) do
|
||
|
for y = 1, #image[1] do
|
||
|
output[1][y] = image[1][y]:gsub(v,k)
|
||
|
output[2][y] = image[2][y]:gsub(v,k)
|
||
|
output[3][y] = image[3][y]:gsub(v,k)
|
||
|
end
|
||
|
end
|
||
|
return output
|
||
|
end
|
||
|
|
||
|
stretchImage = function(_image, sx, sy, noRepeat)
|
||
|
assert(checkValid(_image), "Invalid image.")
|
||
|
local output = {{},{},{}}
|
||
|
local image = deepCopy(_image)
|
||
|
if sx < 0 then image = flipX(image) end
|
||
|
if sy < 0 then image = flipY(image) end
|
||
|
sx, sy = math.abs(sx), math.abs(sy)
|
||
|
local imageX, imageY = getSize(image)
|
||
|
local tx, ty
|
||
|
for y = 1, sy do
|
||
|
for x = 1, sx do
|
||
|
tx = math.ceil((x / sx) * imageX)
|
||
|
ty = math.ceil((y / sy) * imageY)
|
||
|
if not noRepeat then
|
||
|
output[1][y] = (output[1][y] or "")..image[1][ty]:sub(tx,tx)
|
||
|
else
|
||
|
output[1][y] = (output[1][y] or "").." "
|
||
|
end
|
||
|
output[2][y] = (output[2][y] or "")..image[2][ty]:sub(tx,tx)
|
||
|
output[3][y] = (output[3][y] or "")..image[3][ty]:sub(tx,tx)
|
||
|
end
|
||
|
end
|
||
|
if noRepeat then
|
||
|
for y = 1, imageY do
|
||
|
for x = 1, imageX do
|
||
|
if image[1][y]:sub(x,x) ~= " " then
|
||
|
tx = math.ceil(((x / imageX) * sx) - ((0.5 / imageX) * sx))
|
||
|
ty = math.ceil(((y / imageY) * sy) - ((0.5 / imageY) * sx))
|
||
|
output[1][ty] = stringWrite(output[1][ty], tx, image[1][y]:sub(x,x))
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
return output
|
||
|
end
|
||
|
|
||
|
pixelateImage = function(image,amntX, amntY)
|
||
|
assert(checkValid(image), "Invalid image.")
|
||
|
local imageX, imageY = getSize(image)
|
||
|
return stretchImage(stretchImage(image,imageX/math.max(amntX,1), imageY/math.max(amntY,1)), imageX, imageY)
|
||
|
end
|
||
|
|
||
|
merge = function(...)
|
||
|
local images = {...}
|
||
|
local output = {{},{},{}}
|
||
|
local imageX, imageY = 0, 0
|
||
|
for i = 1, #images do
|
||
|
imageY = math.max(imageY, #images[i][1][1]+(images[i][3]-1))
|
||
|
for y = 1, #images[i][1][1] do
|
||
|
imageX = math.max(imageX, #images[i][1][1][y]+(images[i][2]-1))
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--will later add code to adjust X/Y positions if negative values are given
|
||
|
|
||
|
local image, xadj, yadj
|
||
|
local tx, ty
|
||
|
for y = 1, imageY do
|
||
|
output[1][y] = {}
|
||
|
output[2][y] = {}
|
||
|
output[3][y] = {}
|
||
|
for x = 1, imageX do
|
||
|
for i = 1, #images do
|
||
|
image, xadj, yadj = images[i][1], images[i][2], images[i][3]
|
||
|
tx, ty = x-(xadj-1), y-(yadj-1)
|
||
|
output[1][y][x] = output[1][y][x] or " "
|
||
|
output[2][y][x] = output[2][y][x] or " "
|
||
|
output[3][y][x] = output[3][y][x] or " "
|
||
|
if image[1][ty] then
|
||
|
if (image[1][ty]:sub(tx,tx) ~= "") and (tx >= 1) then
|
||
|
output[1][y][x] = (image[1][ty]:sub(tx,tx) == " " and output[1][y][x] or image[1][ty]:sub(tx,tx))
|
||
|
output[2][y][x] = (image[2][ty]:sub(tx,tx) == " " and output[2][y][x] or image[2][ty]:sub(tx,tx))
|
||
|
output[3][y][x] = (image[3][ty]:sub(tx,tx) == " " and output[3][y][x] or image[3][ty]:sub(tx,tx))
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
output[1][y] = table.concat(output[1][y])
|
||
|
output[2][y] = table.concat(output[2][y])
|
||
|
output[3][y] = table.concat(output[3][y])
|
||
|
end
|
||
|
return output
|
||
|
end
|
||
|
|
||
|
rotateImage = function(image, angle)
|
||
|
local output = {{},{},{}}
|
||
|
local realOutput = {{},{},{}}
|
||
|
local tx, ty
|
||
|
local imageX, imageY = getSize(image)
|
||
|
local originX, originY = imageX / 2, imageY / 2
|
||
|
local adjX, adjY = 1, 1
|
||
|
for y = 1, #image[1] do
|
||
|
for x = 1, #image[1][y] do
|
||
|
if not (image[1][y]:sub(x,x) == " " and image[2][y]:sub(x,x) == " " and image[3][y]:sub(x,x) == " ") then
|
||
|
tx = math.floor( (x-originX) * math.cos(angle) - (originY-y) * math.sin(angle) )
|
||
|
ty = math.floor( (x-originX) * math.sin(angle) + (originY-y) * math.cos(angle) )
|
||
|
adjX, adjY = math.min(adjX, tx), math.min(adjY, ty)
|
||
|
output[1][ty] = output[1][ty] or {}
|
||
|
output[2][ty] = output[2][ty] or {}
|
||
|
output[3][ty] = output[3][ty] or {}
|
||
|
output[1][ty][tx] = image[1][y]:sub(x,x)
|
||
|
output[2][ty][tx] = image[2][y]:sub(x,x)
|
||
|
output[3][ty][tx] = image[3][y]:sub(x,x)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
for y = adjY, #output[1] do
|
||
|
realOutput[1][y+1-adjY] = {}
|
||
|
realOutput[2][y+1-adjY] = {}
|
||
|
realOutput[3][y+1-adjY] = {}
|
||
|
for x = adjX, #output[1][y] do
|
||
|
realOutput[1][y+1-adjY][x+1-adjX] = output[1][y][x] or " "
|
||
|
realOutput[2][y+1-adjY][x+1-adjX] = output[2][y][x] or " "
|
||
|
realOutput[3][y+1-adjY][x+1-adjX] = output[3][y][x] or " "
|
||
|
end
|
||
|
end
|
||
|
for y = 1, #realOutput[1] do
|
||
|
realOutput[1][y] = table.concat(realOutput[1][y])
|
||
|
realOutput[2][y] = table.concat(realOutput[2][y])
|
||
|
realOutput[3][y] = table.concat(realOutput[3][y])
|
||
|
end
|
||
|
return realOutput, math.ceil(adjX-1+originX), math.ceil(adjY-1+originY)
|
||
|
end
|
||
|
|
||
|
help = function(input)
|
||
|
local helpOut = {
|
||
|
loadImageData = "Loads an NFT image from a string input.",
|
||
|
loadImage = "Loads an NFT image from a file path.",
|
||
|
convertFromNFP = "Loads a table NFP image into a table NFT image, same as what loadImage outputs.",
|
||
|
drawImage = "Draws an image. Does not support transparency, sadly.",
|
||
|
drawImageTransparent = "Draws an image. Supports transparency, but not as fast as drawImage.",
|
||
|
drawImageCenter = "Draws an image centered around the inputted coordinates. Does not support transparency, sadly.",
|
||
|
drawImageCenterTransparent = "Draws an image centered around the inputted coordinates. Supports transparency, but not as fast as drawImageCenter.",
|
||
|
flipX = "Returns the inputted image, but with the X inverted.",
|
||
|
flipY = "Returns the inputted image, but with the Y inverted.",
|
||
|
grayOut = "Returns the inputted image, but with the colors converted into grayscale as best I could.",
|
||
|
lighten = "Returns the inputted image, but with the colors lightened.",
|
||
|
darken = "Returns the inputted image, but with the colors darkened.",
|
||
|
stretchImage = "Returns the inputted image, but it's been stretched to the inputted size. If the fourth argument is true, it will spread non-space characters evenly in the image.",
|
||
|
pixelateImage = "Returns the inputted image, but pixelated to a variable degree.",
|
||
|
merge = "Merges two or more images together.",
|
||
|
crop = "Crops an image between points (X1,Y1) and (X2,Y2).",
|
||
|
rotateImage = "Rotates an image, and also returns how much the image center's X and Y had been adjusted.",
|
||
|
colorSwap = "Swaps the colors of a given image with another color, according to an inputted table."
|
||
|
}
|
||
|
return helpOut[input] or "No such function."
|
||
|
end
|