Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local unicode = require("unicode")
- local fs = require("filesystem")
- local charpattern = utf8 and utf8.charpattern or "[\0-\x7F\xC2-\xF4][\x80-\xBF]*"
- local function readstr(f)
- local count, reason = f:read(1)
- if not count then return nil, reason or "unexpected EOF" end
- count = string.unpack(">B", count)
- local data, reason = f:read(count)
- if not data or #data ~= count then return nil, reason or "unexpected EOF" end
- return data
- end
- local function readchr(f)
- local c1, reason = f:read(1)
- if not c1 then return nil, reason or "unexpected EOF" end
- local ctr, c = -1, math.max(c1:byte(), 128)
- repeat
- ctr = ctr + 1
- c = (c - 128) * 2
- until c < 128
- local crest, reason = f:read(ctr)
- if not crest or #crest ~= ctr then return nil, reason or "unexpected EOF" end
- return c1 .. crest
- end
- local fontBase = {}
- fontBase.__index = fontBase
- local function loadOCBF(path)
- local font = setmetatable({sizes = {}}, fontBase)
- local f, reason = io.open(path, "rb")
- if not f then return nil, reason end
- if f:read(4) ~= "ocbf" then return nil, "bad signature" end
- font.family, reason = readstr(f)
- if not font.family then return nil, reason end
- font.style, reason = readstr(f)
- if not font.style then return nil, reason end
- while true do
- local char = readchr(f)
- if not char then break end
- local sizewidth, reason = f:read(2)
- if not sizewidth or #sizewidth ~= 2 then
- return nil, reason or "unexpected EOF"
- end
- local size, width = string.unpack(">BB", sizewidth)
- local len = math.ceil(size * width / 8)
- local data = f:read(len)
- if not data or #data ~= len then return nil, reason or "unexpected EOF" end
- if not font.sizes[size] then font.sizes[size] = {} end
- font.sizes[size][char] = {}
- font.sizes[size][char] = {width = width, data = data}
- end
- f:close()
- return font
- end
- function fontBase:drawChar(set, size, char, x, y)
- checkArg(1, set, "function")
- checkArg(2, size, "number")
- checkArg(3, char, "string")
- checkArg(4, x, "number")
- checkArg(5, y, "number")
- if not self.sizes[size] then
- error("no " .. tostring(size) .. " size in ocbf font", 2)
- end
- local char = self.sizes[size][char]
- local i = 0
- for by = 0, size - 1 do
- for bx = 0, char.width - 1 do
- local bytei = math.floor((by * char.width + bx) / 8)
- local biti = 7 - (by * char.width + bx) % 8
- local byte = string.byte(char.data:sub(bytei + 1, bytei + 1))
- if byte >> biti & 1 == 1 then
- set(bx + x, by + y, 1)
- else
- set(bx + x, by + y, 0)
- end
- i = i + 1
- end
- end
- end
- function fontBase:draw(set, size, str, x, y)
- checkArg(1, set, "function")
- checkArg(2, size, "number")
- checkArg(3, str, "string")
- checkArg(4, x, "number")
- checkArg(5, y, "number")
- if not self.sizes[size] then
- error("no " .. tostring(size) .. " size in ocbf font", 2)
- end
- local ix = x
- for i = 1, unicode.len(str) do
- local char = unicode.sub(str, i, i)
- if char == "\n" then
- x = ix
- y = y + size
- else
- self:drawChar(set, size, char, x, y)
- x = x + self.sizes[size][char].width
- end
- end
- end
- function fontBase:width(size, str)
- checkArg(1, size, "number")
- checkArg(2, str, "string")
- local width = 0
- for i = 1, unicode.len(str) do
- local char = unicode.sub(str, i, i)
- width = width + self.sizes[size][char].width
- end
- return width
- end
- function fontBase:__tostring()
- local out = "font: " .. self.family .. " " .. self.style .. " ["
- local i = 1
- for size in pairs(self.sizes) do
- out = out .. (i == 1 and "" or ", ") .. tostring(size)
- i = i + 1
- end
- return out .. "]"
- end
- local ocbf = {}
- ocbf.path = "/usr/share/fonts:/home/.fonts:."
- function ocbf.load(family, style)
- checkArg(1, family, "string")
- checkArg(2, style, "string", "nil")
- local path
- if family:sub(-5, -1) == "ocbf" then
- path = family
- else
- path = ocbf.search(family, style)
- end
- if not path then return nil end
- return loadOCBF(path)
- end
- function ocbf.search(family, style)
- checkArg(1, family, "string")
- checkArg(2, style, "string")
- for path in ocbf.path:gmatch("[^:]+") do
- path = fs.concat(path, family, style .. ".ocbf")
- if fs.exists(path) then
- return path
- end
- end
- end
- return ocbf
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement