Як і було обіцяно, ось моя каїрська версія. Я написав його за допомогою Lua, використовуючи lfs для перегляду каталогів. Мені подобаються ці маленькі виклики, оскільки вони дозволяють мені досліджувати API, які я хотів копати вже давно ...
lfs і LuaCairo - обидва платформи, тому він повинен працювати на інших системах (протестовано на французькій WinXP Pro SP3).
Коли я ходив по дереву, я створив першу версію імен файлів для малювання. Перевага: відсутність накладних витрат на пам’ять. Незручність: Я повинен вказати розмір зображення заздалегідь, тому списки, швидше за все, будуть відрізані.
Тож я зробив цю версію, спочатку пройшовшись по дереву каталогів, зберігаючи її в таблиці Lua. Потім, знаючи кількість файлів, створюючи полотно, щоб воно вміщувалось (принаймні вертикально), і малювало імена.
Ви можете легко переключатись між візуалізацією PNG та SVG. Проблема з останнім: Каїр генерує його на низькому рівні, малюючи літери замість того, щоб використовувати текстові можливості SVG. Ну, принаймні, це гарантує точну рендінг навіть на системах без шрифту. Але файли більші ... Не дуже проблема, якщо стиснути після цього, мати файл .svgz.
Або не повинно бути надто складно безпосередньо генерувати SVG, я раніше використовував Lua для генерації SVG.
-- LuaFileSystem <http://www.keplerproject.org/luafilesystem/>
require"lfs"
-- LuaCairo <http://www.dynaset.org/dogusanh/>
require"lcairo"
local CAIRO = cairo
local PI = math.pi
local TWO_PI = 2 * PI
--~ local dirToList = arg[1] or "C:/PrgCmdLine/Graphviz"
--~ local dirToList = arg[1] or "C:/PrgCmdLine/Tecgraf"
local dirToList = arg[1] or "C:/PrgCmdLine/tcc"
-- Ensure path ends with /
dirToList = string.gsub(dirToList, "([^/])$", "%1/")
print("Listing: " .. dirToList)
local fileNb = 0
--~ outputType = 'svg'
outputType = 'png'
-- dirToList must have a trailing slash
function ListDirectory(dirToList)
local dirListing = {}
for file in lfs.dir(dirToList) do
if file ~= ".." and file ~= "." then
local fileAttr = lfs.attributes(dirToList .. file)
if fileAttr.mode == "directory" then
dirListing[file] = ListDirectory(dirToList .. file .. '/')
else
dirListing[file] = ""
end
fileNb = fileNb + 1
end
end
return dirListing
end
--dofile[[../Lua/DumpObject.lua]] -- My own dump routine
local dirListing = ListDirectory(dirToList)
--~ print("\n" .. DumpObject(dirListing))
print("Found " .. fileNb .. " files")
--~ os.exit()
-- Constants to change to adjust aspect
local initialOffsetX = 20
local offsetY = 50
local offsetIncrementX = 20
local offsetIncrementY = 12
local iconOffset = 10
local width = 800 -- Still arbitrary
local titleHeight = width/50
local height = offsetIncrementY * (fileNb + 1) + titleHeight
local outfile = "CairoDirTree." .. outputType
local ctxSurface
if outputType == 'svg' then
ctxSurface = cairo.SvgSurface(outfile, width, height)
else
ctxSurface = cairo.ImageSurface(CAIRO.FORMAT_RGB24, width, height)
end
local ctx = cairo.Context(ctxSurface)
-- Display a file name
-- file is the file name to display
-- offsetX is the indentation
function DisplayFile(file, bIsDir, offsetX)
if bIsDir then
ctx:save()
ctx:select_font_face("Sans", CAIRO.FONT_SLANT_NORMAL, CAIRO.FONT_WEIGHT_BOLD)
ctx:set_source_rgb(0.5, 0.0, 0.7)
end
-- Display file name
ctx:move_to(offsetX, offsetY)
ctx:show_text(file)
if bIsDir then
ctx:new_sub_path() -- Position independent of latest move_to
-- Draw arc with absolute coordinates
ctx:arc(offsetX - iconOffset, offsetY - offsetIncrementY/3, offsetIncrementY/3, 0, TWO_PI)
-- Violet disk
ctx:set_source_rgb(0.7, 0.0, 0.7)
ctx:fill()
ctx:restore() -- Restore original settings
end
-- Increment line offset
offsetY = offsetY + offsetIncrementY
end
-- Erase background (white)
ctx:set_source_rgb(1.0, 1.0, 1.0)
ctx:paint()
--~ ctx:set_line_width(0.01)
-- Draw in dark blue
ctx:set_source_rgb(0.0, 0.0, 0.3)
ctx:select_font_face("Sans", CAIRO.FONT_SLANT_NORMAL, CAIRO.FONT_WEIGHT_BOLD)
ctx:set_font_size(titleHeight)
ctx:move_to(5, titleHeight)
-- Display title
ctx:show_text("Directory tree of " .. dirToList)
-- Select font for file names
ctx:select_font_face("Sans", CAIRO.FONT_SLANT_NORMAL, CAIRO.FONT_WEIGHT_NORMAL)
ctx:set_font_size(10)
offsetY = titleHeight * 2
-- Do the job
function DisplayDirectory(dirToList, offsetX)
for k, v in pairs(dirToList) do
--~ print(k, v)
if type(v) == "table" then
-- Sub-directory
DisplayFile(k, true, offsetX)
DisplayDirectory(v, offsetX + offsetIncrementX)
else
DisplayFile(k, false, offsetX)
end
end
end
DisplayDirectory(dirListing, initialOffsetX)
if outputType == 'svg' then
cairo.show_page(ctx)
else
--cairo.surface_write_to_png(ctxSurface, outfile)
ctxSurface:write_to_png(outfile)
end
ctx:destroy()
ctxSurface:destroy()
print("Found " .. fileNb .. " files")
Звичайно, ви можете змінити стилі. Я не малював лінії зв’язку, не бачив цього як потрібно. Я можу додати їх за бажанням пізніше.