Some simple IM stuff Thread last updated on 2005-12-20 10:15:22

Posted by member 12025 on 2005-12-20 10:14:03

It took quite awhile to get some of the syntax down, mainly because the docs are for *n*x shells. Then it's taken awhile to get alpha channel work done right, because the docs for that sucked, but have now been made much better.

For the package, apppath should be the IM folder, using escapes, and temppath must exist, whatever it is set to (else IM will error out). Also, all directories used for final paths must exist. I aught to fix it (piping from md can get a check done)...

The work is done in a serial fashion. I was going to be more elaborate, but it was starting to take more work than it was worth.

im.begin( destination file) --set file
im.stuff (whatever) --do stuff, usually with an input file, returning an output file
im.complete () --house cleaning

So far, gradients and rotations (non-90º) take the longest to perform.

The package:
--[[
Each function that creates an image returns the image's file path. Some
functions will take this path to do operations.
]]

require "args"

module "im"

local type = type;

local len = string.len;
local find = string.find;
local sub = string.sub;
local format = string.format;

local getn = table.getn;
local ins = table.insert;
local rem = table.remove;
local ipairs = ipairs;


set = function (s) lslua.exec ("!commandshowtext "..s) end;
run = function (s)
if debug == true then
set ("cmd.exe /K "..quote (s))
os.execute ("cmd.exe /K "..quote (s))
else
os.execute ("cmd.exe /C "..quote (s)) --this is the trick to automating it...
end
end;

apppath = evar.miscdir.."im\\";
temppath = evar.miscdir.."im\\temp\\";
haltcode = { "halt!" }; --useless?
gradientsize = "500";
debug = false; --not recommended unless there's a problem

files = {};
style = ""; --current file

--[[ BASICS ]]
--[[ these use my own log module
info = function (title,caption) log["info"] (title,caption) end;
warn = function (title,caption) log["warn"] (title,caption) end;
error = function (title,caption) log["error"] (title,caption) end;
]]
info = function (title,caption) end;
warn = function (title,caption) end;
error = function (title,caption) end;

convert = function (s) return quote (apppath.."convert.exe").." "..s end;
identify = function (s) return quote (apppath.."identify.exe").." "..s end;

getsize = function (s)
local id = apppath.."identify.exe"
local info = temppath.."info.txt"

run (identify (quote (s)).." > "..quote (info))

local file = io.open (info,"r")
local line = args.strsplit (file:read ()," ")
file:close ()
for i,v in ipairs(line) do
if v == "PNG" then
line = line[i+1]
break
end
end
local slice = find (line,"x")
return { width = sub (line,1,slice-1), height = sub (line,slice+1)}
end

--[[ FILE MANAGEMENT]]

begin = function (path)
_M.style = path
clearfiles ()
end;

complete = function (path) --path not really used
delfile (_M.style) --if it currently exists
os.rename (files[getn(files)], style) --last temp file
clearfiles()
_M.style = ""
end;

newfile = function ()
local count = getn (_M.files)+1
local name = temppath..count..".png"

ins (_M.files,name)
info ("newfile",name)

return _M.files [getn(_M.files)]
end;
clearfiles = function () --optional return
os.execute ("del.exe /Q "..quote (temppath.."*.*"))
return "temp files cleared."
end;
delfile = function (s)
os.execute ("del.exe /Q "..quote (s))
end;


--[[ DATA VERIFICATION OR CONVERSION ]]

function round (n,shift)
shift = 10^shift
return math.floor ((n*shift)+0.5)/shift
end

tohex = function (c) -- ideally, this will merge with the color module (mine or tnl's), but that's in the future!
local t,r = type (c),""
if t == "string" then
r = c
elseif t == "table" then
if c.r ~= nil and c.g ~= nil and c.b ~= nil then
r = format ("%.2x%.2x%.2x",c.r,c.g,c.b)
elseif c.red ~= nil and c.green ~= nil and c.blue ~= nil then
r = format ("%.2x%.2x%.2x",c.red,c.green,c.blue)
elseif getn (c) == 3 then
r = format ("%.2x%.2x%.2x",c[1],c[2],c[3])
end
end
return r
end;

quote = function (s) return "\""..s.."\"" end;

--[[ IMAGE OPERATIONS ]]
-- returns of torun for optional logging and IM syntax debugging (handy with docs being for *n*x shells)

solidcanvas = function (color,width,height)
local path = newfile ()
local torun = convert ("-size "..width.."x"..height.." xc:#"..tohex (color).." \""..path.."\"")
run (torun)
return path, torun
end;

gradient = function (colorfrom, colorto, rotate, width, height)
if rotate == nil then rotate = 0 end

local path = newfile ()
s = "-size "..gradientsize.."x"..gradientsize.." gradient:#"..tohex (colorfrom).."-#"..tohex (colorto)
rotate = tonumber (rotate)
if rotate == 45 or rotate == -45 or
rotate == 315 or rotate == -315 or
rotate == 135 or rotate == -135 or
rotate == 225 or rotate == -225 then
local dim = math.floor (gradientsize*(2^0.5))
s = "-size "..dim.."x"..dim.." gradient:#"..tohex (colorfrom).."-#"..tohex (colorto)
s = s.." -rotate "..rotate.." -gravity center -crop "..(gradientsize-1).."x"..(gradientsize-1).."+0+0 +repage"
elseif rotate == 0 or
rotate == 90 or rotate == -90 or
rotate == 180 or rotate == -180 or
rotate == 270 or rotate == -270 then
s = "-size "..gradientsize.."x"..gradientsize.." gradient:#"..tohex (colorfrom).."-#"..tohex (colorto).." -rotate "..rotate
end

if width ~= nil and height ~= nil then
s = s.." -resize "..width.."x"..height.."!"
end

local torun = convert (s.." "..quote (path))
run (torun)
return path, torun
end;

-- 1.5 and 0.75 == BlackBox raised bevel
bevel = function (sourcepath, light,dark)
if light == nil then light = 1 end
if dark == nil then dark = 1 end

info ("bevel","checking dimensions")
dim = getsize (sourcepath)

info ("bevel","adjusting left and right")
local left,right = newfile (), newfile ()
s = quote (sourcepath).." -crop 1x"..dim.height.."+0+0 -fx u*"..light.." "..quote (left)
run (convert (s))
s = quote (sourcepath).." -crop 1x"..dim.height.."+"..(dim.width-1).."+0 -fx u*"..dark.." "..quote (right)
run (convert (s))
s = quote (sourcepath).." "..quote (left).." -geometry +0+0 -composite "..quote (right).." -geometry +"..(dim.width-1).."+0 -composite "..quote (sourcepath)
run (convert (s))

info ("bevel","adjusting top and bottom")
local top,bottom = newfile (), newfile ()
s = quote (sourcepath).." -crop "..dim.width.."x1+0+0 -fx u*"..light.." "..quote (top)
run (convert (s))
s = quote (sourcepath).." -crop "..dim.width.."x1+0+"..(dim.height-1).." -fx u*"..dark.." "..quote (bottom)
run (convert (s))
s = quote (sourcepath).." "..quote (top).." -geometry +0+0 -composite "..quote (bottom).." -geometry +0+"..(dim.height-1).." -composite "..quote (sourcepath)
run (convert (s))

return sourcepath
end;

insert = function (sourcepath,destpath,x,y)
local torun = convert (quote (sourcepath).." "..quote (sourcepath).." -geometry +"..x.."+"..y.." -composite "..quote (sourcepath))
run (torun)
return sourcepath, torun
end;

border = function (sourcepath,size,color)
local dim, destpath = getsize (sourcepath), newfile ()
local torun = convert ("-size "..(dim.width+(2*size)).."x"..(dim.height+(2*size)).." xc:#"..tohex (color).." "..quote (sourcepath).." -geometry +"..size.."+"..size.." -composite "..quote (destpath))
run (torun)

return destpath, torun
end;

--image edge should be roughly 4*sigma, by experiment, but sometimes 5*sigma...I don't know why. Right now I'm making it big and using (5*sigma-1)
shadow = function (w,h,sigma,color)
if not color then color = "000000" end
local destpath = newfile ()
local torun = convert ("-size "..w+(4*sigma).."x"..h+(4*sigma).." xc:none -channel RGBA -fill #"..tohex (color).." -draw \"rectangle "..(2*sigma)..","..(2*sigma).." "..w+(2*sigma)..","..h+(2*sigma).."\" -blur 0x"..sigma.." "..quote (destpath))
run (torun)

return destpath, torun
end;


Two and a half examples, which use MiscDir:
require "evar"
require "im"

--2px black border, gray->red gradient going NW->SE (mimic BB style)
im.begin (evar.miscdir.."a.png") --returns are all path names
a = im.gradient ("a00000","555555",135,200,50)
b = im.bevel (a, 1.5,0.75)
c = im.border (b, 2, "000000")
im.complete ()

-- same as above, but more of a functional approach
im.begin (evar.miscdir.."b.png")
im.complete (im.border (im.bevel (im.gradient ("a00000","555555",135,200,50), 1.5,0.75), 2, "000000"))

--4px blur with alpha to make a shadow; requires alphamap support, and image edge should be around 8px
im.begin (evar.miscdir.."c.png")
d = im.shadow (100,100,2,"#c00000")
im.complete ()