Created
December 31, 2020 04:22
-
-
Save wtsnjp/20f222d6a272319e30288b6bad789d3b to your computer and use it in GitHub Desktop.
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
#!/usr/bin/env texlua | |
-- | |
-- This is file 'wtspingif.lua'. | |
-- | |
-- Copyright 2020 Takuto ASAKURA (wtsnjp) | |
-- GitHub: https://github.com/wtsnjp | |
-- Twitter: @wtsnjp | |
-- | |
-- This package is distributed under the MIT License. | |
-- | |
-- program information | |
prog_name = 'wtspingif' | |
version = '0.1' | |
release_date = '2020-12-31' | |
author = 'Takuto ASAKURA (wtsnjp)' | |
-- option flags (default) | |
option_density = 72 | |
option_delay = 1 | |
verbosity_level = 0 | |
-- exit codes | |
exit_ok = 0 | |
exit_error = 1 | |
exit_usage = 2 | |
---------------------------------------- | |
-- library | |
local lfs = require 'lfs' | |
local pdfe = require 'pdfe' | |
-- global functions | |
function log(label, msg, ...) | |
io.stderr:write(prog_name .. ' ' .. label .. ': ' .. msg:format(...) .. '\n') | |
end | |
function err_print(err_type, msg, ...) | |
if (verbosity_level > 0) or (err_type == 'error') | |
or (verbosity_level > -1 and err_type == 'warning') then | |
log(err_type, msg, ...) | |
end | |
end | |
function dbg_print(dbg_type, msg, ...) | |
if debug[dbg_type] then | |
log('debug-' .. dbg_type, msg, ...) | |
end | |
end | |
---------------------------------------- | |
do | |
local function execute(cmd) | |
err_print('info', 'Running command: ' .. cmd) | |
local status = os.execute(cmd) | |
if status > 0 then | |
llmk.util.err_print('error', | |
'Fail running %s (exit code: %d)', cmd, status) | |
os.exit(exit_error) | |
end | |
end | |
function convert(pdf_file) | |
local basename = pdf_file:sub(1, -5) | |
local function png_name(i) | |
return string.format('__wtsg%s_%03d.png', basename, i) | |
end | |
-- estimate number of frames | |
local doc = pdfe.open(pdf_file) | |
local nof_frames = pdfe.getnofpages(doc) | |
pdfe.close(doc) | |
-- generating filenames | |
local png_files = {} | |
for i = 0, nof_frames - 1 do | |
table.insert(png_files, png_name(i)) | |
end | |
local png_args = table.concat(png_files, ' ') | |
-- convert PDF -> PNG images | |
for i = 0, nof_frames - 1 do | |
execute(string.format( | |
'magick %s[%d] -background white -alpha remove -density %d %s', | |
pdf_file, i, option_density, png_name(i))) | |
end | |
-- convert PNG images -> animated GIF | |
execute(string.format( | |
'magick -delay %d %s %s.gif', option_delay, png_args, basename)) | |
-- remove PNG images | |
for _, fn in pairs(png_files) do | |
os.remove(fn) | |
end | |
end | |
end | |
---------------------------------------- | |
do | |
-- help texts | |
local usage_text = [[ | |
Usage: wtspingif [OPTION]... PDF_FILE | |
]] | |
local version_text = [[ | |
%s %s | |
]] | |
-- show uasage / help | |
local function show_usage(out) | |
out:write(usage_text) | |
end | |
-- execution functions | |
local function read_options() | |
if #arg == 0 then | |
show_usage(io.stderr) | |
os.exit(exit_usage) | |
end | |
local curr_arg | |
local action = false | |
-- modified Alternative Get Opt | |
-- cf. http://lua-users.org/wiki/AlternativeGetOpt | |
local function getopt(arg, options) | |
local tmp | |
local tab = {} | |
local saved_arg = { table.unpack(arg) } | |
for k, v in ipairs(saved_arg) do | |
if string.sub(v, 1, 2) == "--" then | |
table.remove(arg, 1) | |
local x = string.find(v, "=", 1, true) | |
if x then | |
table.insert(tab, { string.sub(v, 3, x-1), string.sub(v, x+1) }) | |
else | |
table.insert(tab, { string.sub(v, 3), true }) | |
end | |
elseif string.sub(v, 1, 1) == "-" then | |
table.remove(arg, 1) | |
local y = 2 | |
local l = string.len(v) | |
local jopt | |
while (y <= l) do | |
jopt = string.sub(v, y, y) | |
if string.find(options, jopt, 1, true) then | |
if y < l then | |
tmp = string.sub(v, y+1) | |
y = l | |
else | |
table.remove(arg, 1) | |
tmp = saved_arg[k + 1] | |
end | |
if string.match(tmp, '^%-') then | |
table.insert(tab, { jopt, false }) | |
else | |
table.insert(tab, { jopt, tmp }) | |
end | |
else | |
table.insert(tab, { jopt, true }) | |
end | |
y = y + 1 | |
end | |
end | |
end | |
return tab | |
end | |
opts = getopt(arg, 'db') | |
for _, tp in ipairs(opts) do | |
k, v = tp[1], tp[2] | |
if #k == 1 then | |
curr_arg = '-' .. k | |
else | |
curr_arg = '--' .. k | |
end | |
-- action | |
if (curr_arg == '-h') or (curr_arg == '--help') then | |
action = 'help' | |
elseif (curr_arg == '-V') or (curr_arg == '--version') then | |
action = 'version' | |
elseif (curr_arg == '-v') or (curr_arg == '--verbose') then | |
verbosity_level = 1 | |
elseif (curr_arg == '-d') or (curr_arg == '--density') then | |
option_density = tonumber(v) | |
elseif (curr_arg == '-b') or (curr_arg == '--boost') then | |
option_delay = tonumber(v) | |
else | |
err_print('error', 'unknown option: ' .. curr_arg) | |
err_print('error', error_msg) | |
os.exit(exit_error) | |
end | |
end | |
return action | |
end | |
local function do_action() | |
if action == 'help' then | |
show_usage(io.stdout) | |
elseif action == 'version' then | |
io.stdout:write(version_text:format( | |
prog_name, version, release_date, author)) | |
end | |
end | |
function main() | |
action = read_options() | |
if action then | |
do_action() | |
os.exit(exit_ok) | |
end | |
convert(arg[1]) | |
os.exit(exit_ok) | |
end | |
end | |
---------------------------------------- | |
main() | |
-- EOF |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example: process the following with llmk: