Như đã hứa, đây là phiên bản Cairo của tôi. Tôi viết kịch bản nó bằng Lua, sử dụng lfs để xem các thư mục. Tôi thích những thử thách nhỏ này, vì chúng cho phép tôi khám phá các API mà tôi muốn đào từ lâu ...
lfs và LuaCairo đều là nền tảng đa nền tảng, vì vậy nó sẽ hoạt động trên các hệ thống khác (được thử nghiệm trên WinXP Pro SP3 của Pháp).
Tôi đã tạo tên tệp bản vẽ phiên bản đầu tiên khi tôi đi bộ trên cây. Ưu điểm: không cần bộ nhớ. Không thuận tiện: Tôi phải chỉ định kích thước hình ảnh trước, vì vậy danh sách có thể bị cắt bỏ.
Vì vậy, tôi đã tạo phiên bản này, đầu tiên đi bộ cây thư mục, lưu trữ nó trong một bảng Lua. Sau đó, biết số lượng tệp, tạo canvas cho phù hợp (ít nhất là theo chiều dọc) và vẽ tên.
Bạn có thể dễ dàng chuyển đổi giữa kết xuất PNG và SVG. Vấn đề với cái sau: Cairo tạo nó ở mức thấp, vẽ các chữ cái thay vì sử dụng khả năng văn bản của SVG. Ít nhất, nó đảm bảo kết xuất chính xác ngay cả trên các hệ thống không có phông chữ. Nhưng các tệp lớn hơn ... Không thực sự là vấn đề nếu bạn nén nó sau đó, để có tệp .svgz.
Hoặc không quá khó để tạo SVG trực tiếp, trước đây tôi đã sử dụng Lua để tạo 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")
Tất nhiên, bạn có thể thay đổi phong cách. Tôi đã không vẽ các đường kết nối, tôi thấy nó không cần thiết. Tôi có thể thêm chúng vào tùy ý sau.