-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added cairoxml2cairo.lua and an output filter for Scrupp. The vector …
…graphic is displayed in a window, if the generated file is opened with Scrupp.
- Loading branch information
Showing
2 changed files
with
345 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
#!/usr/bin/env lua | ||
|
||
--[[ | ||
Copyright (c) 2010 Andreas Krinke | ||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. | ||
--]] | ||
|
||
local formats = "c lua-oocairo scrupp" | ||
|
||
-- default export filter | ||
local format = "scrupp" | ||
local infile, outfile | ||
|
||
-- collect command line arguments | ||
if #arg == 2 then | ||
infile = arg[1] | ||
outfile = arg[2] | ||
elseif #arg == 4 and arg[1] == "-f" and string.find(formats, arg[2]) then | ||
format = arg[2] | ||
infile = arg[3] | ||
outfile = arg[4] | ||
else | ||
print([[ | ||
Usage: lua cairoxml2cairo.lua [-f format] xml-file source-file | ||
Available formats: ]] .. formats) | ||
os.exit() | ||
end | ||
|
||
-- try to load the source code format definitions | ||
local success, replacements = pcall(require, "formats." .. format) | ||
|
||
if not success then | ||
print(string.format([[ | ||
Error loading format %s. | ||
Is %s.lua missing in directory 'formats'?]], format, format)) | ||
os.exit() | ||
end | ||
|
||
-- list of tags, that start a pattern definition | ||
local pattern_tags = { | ||
solid = true, | ||
linear = true, | ||
radial = true | ||
} | ||
|
||
-- stores the current state of cairo | ||
local state = {} | ||
|
||
----------------------------------------------------------------------------- | ||
-- Function Definitions | ||
----------------------------------------------------------------------------- | ||
|
||
----------------------------------------------------------------------------- | ||
-- Simple XML Parser | ||
-- source: http://lua-users.org/wiki/LuaXml | ||
local function parseargs(s) | ||
local arg = {} | ||
string.gsub(s, "(%w+)=([\"'])(.-)%2", function (w, _, a) | ||
arg[w] = a | ||
end) | ||
return arg | ||
end | ||
|
||
local function collect(s) | ||
local stack = {} | ||
local top = {} | ||
table.insert(stack, top) | ||
local ni,c,label,xarg, empty | ||
local i, j = 1, 1 | ||
while true do | ||
ni,j,c,label,xarg, empty = string.find(s, "<(%/?)([%w%-:]+)(.-)(%/?)>", i) | ||
if not ni then break end | ||
local text = string.sub(s, i, ni-1) | ||
if not string.find(text, "^%s*$") then | ||
table.insert(top, text) | ||
end | ||
if empty == "/" then -- empty element tag | ||
table.insert(top, {label=label, xarg=parseargs(xarg), empty=1}) | ||
elseif c == "" then -- start tag | ||
top = {label=label, xarg=parseargs(xarg)} | ||
table.insert(stack, top) -- new level | ||
else -- end tag | ||
local toclose = table.remove(stack) -- remove top | ||
top = stack[#stack] | ||
if #stack < 1 then | ||
error("nothing to close with "..label) | ||
end | ||
if toclose.label ~= label then | ||
error("trying to close "..toclose.label.." with "..label) | ||
end | ||
table.insert(top, toclose) | ||
end | ||
i = j+1 | ||
end | ||
local text = string.sub(s, i) | ||
if not string.find(text, "^%s*$") then | ||
table.insert(stack[#stack], text) | ||
end | ||
if #stack > 1 then | ||
error("unclosed "..stack[stack.n].label) | ||
end | ||
return stack[1] | ||
end | ||
-- End Simple XML Parser | ||
----------------------------------------------------------------------------- | ||
|
||
--- Outputs the source code corresponding to the current tag. | ||
-- For each start and end tag, different source code can be defined. | ||
-- @param fh Output filehandle. | ||
-- @param kind Either "pre" (start tag was parsed) | ||
-- or "post" (stop tag was parsed). | ||
-- @param t Table containing information about the current tag. | ||
local function output(fh, kind, t) | ||
local label = t.label | ||
if label == "svg" then | ||
error("svg tag detected\nPlease provide a cairo xml file, not an svg file.") | ||
end | ||
|
||
if kind == "post" then | ||
if label == "surface" then | ||
state.last_environment = "surface" | ||
elseif pattern_tags[label] then | ||
state.last_environment = "pattern" | ||
end | ||
end | ||
|
||
local rep = replacements[label] | ||
if not rep then | ||
error("not supported tag: " .. label) | ||
end | ||
|
||
local s | ||
if kind == "pre" then | ||
if type(rep) == "table" then | ||
rep = rep.pre | ||
end | ||
else | ||
if type(rep) == "table" then | ||
rep = rep.post | ||
else | ||
rep = nil | ||
end | ||
end | ||
|
||
if type(rep) == "string" then | ||
s = rep | ||
elseif type(rep) == "function" then | ||
s = rep(state, t[1]) | ||
end | ||
if s then | ||
s = string.gsub(s, "$value", t[1]) | ||
s = string.gsub(s, "$(%w+)", t.xarg) | ||
fh:write(s, "\n") | ||
end | ||
end | ||
|
||
--- Processes the table generated by the XML parser. | ||
-- @param fh Output filehandle. | ||
-- @param t Table generated by collect(). | ||
-- @see collect. | ||
local function process(fh, t) | ||
for _,child in ipairs(t) do | ||
if type(child) == "table" then | ||
output(fh, "pre", child) | ||
process(fh, child) | ||
output(fh, "post", child) | ||
end | ||
end | ||
end | ||
|
||
----------------------------------------------------------------------------- | ||
-- Main | ||
----------------------------------------------------------------------------- | ||
|
||
-- open the input and output file | ||
local fh_in = assert(io.open(infile)) | ||
local fh_out = assert(io.open(outfile, "w")) | ||
|
||
-- read and parse the whole xml file | ||
local t = collect(fh_in:read("*a")) | ||
|
||
-- process the resulting table | ||
process(fh_out, t) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
--[[ | ||
Copyright (c) 2010 Andreas Krinke | ||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. | ||
--]] | ||
|
||
local string = string | ||
local format = string.format | ||
local gmatch = string.gmatch | ||
local gsub = string.gsub | ||
local lower = string.lower | ||
local match = string.match | ||
|
||
local concat = table.concat | ||
local tonumber = tonumber | ||
local unpack = unpack | ||
|
||
return { | ||
image = { | ||
pre = [[ | ||
local Cairo = require "oocairo" | ||
local surface = Cairo.image_surface_create("argb32", $width, $height) | ||
local cr = Cairo.context_create(surface) | ||
local temp_surface | ||
local pattern | ||
local matrix | ||
]], | ||
|
||
post = [[ | ||
-- use scrupp to display the surface | ||
scrupp.init("Cairo: simple-example", $width, $height, 32, false) | ||
local image = scrupp.addImageFromCairo(surface) | ||
main = { | ||
render = function(dt) | ||
image:render(0,0) | ||
end, | ||
keypressed = function(key) | ||
if key == "ESCAPE" then | ||
scrupp.exit() | ||
end | ||
end | ||
}]] | ||
}, | ||
|
||
surface = { | ||
pre = [[ | ||
do | ||
temp_surface = Cairo.image_surface_create("argb32", $width, $height) | ||
local cr = Cairo.context_create(temp_surface)]], | ||
}, | ||
|
||
fill = {post = "cr:fill_preserve()\n----------------------"}, | ||
stroke = {post = "cr:stroke_preserve()\n----------------------"}, | ||
mask = {}, | ||
|
||
operator = function(state, value) return format('cr:set_operator("%s")', lower(value)) end, | ||
tolerance = "cr:set_tolerance($value)", | ||
antialias = function(state, value) return format('cr:set_antialias("%s")', lower(match(value, "_(.*)"))) end, | ||
["fill-rule"] = function(state, value) return format('cr:set_fill_rule("%s")', lower(value)) end, | ||
["line-width"] = "cr:set_line_width($value)", | ||
["miter-limit"] = "cr:set_miter_limit($value)", | ||
["line-cap"] = function(state, value) return format('cr:set_line_cap("%s")', lower(match(value, "_([^_]-)$"))) end, | ||
["line-join"] = function(state, value) return format('cr:set_line_join("%s")', lower(match(value, "_([^_]-)$"))) end, | ||
|
||
linear = "pattern = Cairo.pattern_create_linear($x1, $y1, $x2, $y2)", | ||
radial = "pattern = Cairo.pattern_create_radial($x1, $y1, $r1, $x2, $y2, $r2)", | ||
solid = function(state, value) return format("pattern = Cairo.pattern_create_rgba(%s)", gsub(value, " ", ",")) end, | ||
["color-stop"] = function(state, value) return format("pattern:add_color_stop_rgba(%s)", gsub(value, " ", ",")) end, | ||
extend = function(state, value) return format('pattern:set_extend("%s")', lower(match(value, "_(.*)"))) end, | ||
filter = function(state, value) return format('pattern:set_filter("%s")', lower(match(value, "_(.*)"))) end, | ||
|
||
["source-pattern"] = { | ||
post = function(state, value) | ||
if state.last_environment == "surface" then | ||
return "end\ncr:set_source(temp_surface, 0, 0)" | ||
else | ||
return "cr:set_source(pattern)" | ||
end | ||
end | ||
}, | ||
|
||
["mask-pattern"] = { | ||
post = function(state, value) | ||
if state.last_environment == "surface" then | ||
return "cr:mask(temp_surface, 0, 0)" | ||
else | ||
return "cr:mask(pattern)" | ||
end | ||
end | ||
}, | ||
|
||
path = function(state, value) | ||
local s = {"cr:new_path()"} | ||
local stack = {} | ||
for x in gmatch(value, "%S+") do | ||
local n = tonumber(x) | ||
if n then | ||
stack[#stack+1] = x | ||
else | ||
if x == "m" then | ||
s[#s+1] = format("cr:move_to(%s, %s)", unpack(stack)) | ||
elseif x == "l" then | ||
s[#s+1] = format("cr:line_to(%s, %s)", unpack(stack)) | ||
elseif x == "c" then | ||
s[#s+1] = format("cr:curve_to(%s, %s, %s, %s, %s, %s)", unpack(stack)) | ||
elseif x == "h" then | ||
s[#s+1] = "cr:close_path()" | ||
end | ||
stack = {} | ||
end | ||
end | ||
return concat(s, "\n") | ||
end, | ||
|
||
matrix = function(state, value) | ||
local s = format("matrix = {%s}\n", gsub(value, " ", ",")) | ||
if state.last_environment == "surface" then | ||
return s .. "matrix[5], matrix[6] = 0,0\ncr:set_matrix(matrix)" | ||
else | ||
return s .. "pattern:set_matrix(matrix)" | ||
end | ||
end | ||
} |