#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <libtexpdf/libtexpdf.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#if !defined LUA_VERSION_NUM || LUA_VERSION_NUM==501
#define lua_rawlen lua_strlen
#endif
pdf_doc *p = NULL;
double height = 0.0;
double precision = 65536.0;
char* producer = "SILE";
#define ASSERT_PDF_OPENED(p) \
if (!p) { \
luaL_error(L, "PDF object not initialized!"); \
return 0; \
}
int pdf_init (lua_State *L) {
pdf_rect mediabox;
const char* fn = luaL_checkstring(L, 1);
double w = luaL_checknumber(L, 2);
height = luaL_checknumber(L, 3);
producer = luaL_checkstring(L, 4);
p = texpdf_open_document(fn, 0, w, height, 0,0,0);
texpdf_init_device(p, 1/precision, 2, 0);
mediabox.llx = 0.0;
mediabox.lly = 0.0;
mediabox.urx = w;
mediabox.ury = height;
texpdf_files_init();
texpdf_init_fontmaps();
texpdf_tt_aux_set_always_embed();
texpdf_doc_set_mediabox(p, 0, &mediabox);
texpdf_add_dict(p->info,
texpdf_new_name("Producer"),
texpdf_new_string(producer, strlen(producer)));
return 0;
}
int pdf_endpage(lua_State *L) {
ASSERT_PDF_OPENED(p);
texpdf_doc_end_page(p);
return 0;
};
int pdf_beginpage(lua_State *L) {
ASSERT_PDF_OPENED(p);
texpdf_doc_begin_page(p, 1,0,height);
return 0;
}
int pdf_changepagesize(lua_State *L) {
pdf_rect mediabox;
double pageno = luaL_checknumber(L, 1);
mediabox.llx = luaL_checknumber(L, 2);
mediabox.lly = luaL_checknumber(L, 3);
mediabox.urx = luaL_checknumber(L, 4);
mediabox.ury = luaL_checknumber(L, 5);
ASSERT_PDF_OPENED(p);
texpdf_doc_set_mediabox(p, pageno, &mediabox);
return 0;
}
int pdf_finish(lua_State *L) {
ASSERT_PDF_OPENED(p);
texpdf_files_close();
texpdf_close_device ();
texpdf_close_document(p);
texpdf_close_fontmaps();
return 0;
}
int pdf_loadfont(lua_State *L) {
const char * filename;
int index = 0;
double ptsize;
int layout_dir = 0;
int extend = 65536;
int slant = 0;
int embolden = 0;
int font_id;
if (!lua_istable(L, 1)) return 0;
lua_pushstring(L, "tempfilename");
lua_gettable(L, -2);
if (lua_isstring(L, -1)) { filename = lua_tostring(L, -1); }
else { luaL_error(L, "No font filename supplied to loadfont"); }
lua_pop(L,1);
lua_pushstring(L, "index");
lua_gettable(L, -2);
if (lua_isnumber(L, -1)) { index = lua_tointeger(L, -1); }
lua_pop(L,1);
index &= 0xFFFFu;
lua_pushstring(L, "pointsize");
lua_gettable(L, -2);
if (lua_isnumber(L, -1)) { ptsize = lua_tonumber(L, -1); }
else { luaL_error(L, "No pointsize supplied to loadfont"); }
lua_pop(L,1);
lua_pushstring(L, "extend");
lua_gettable(L, -2);
if (lua_isnumber(L, -1)) { extend = lua_tointeger(L, -1); }
lua_pop(L,1);
lua_pushstring(L, "embolden");
lua_gettable(L, -2);
if (lua_isnumber(L, -1)) { embolden = lua_tointeger(L, -1); }
lua_pop(L,1);
lua_pushstring(L, "slant");
lua_gettable(L, -2);
if (lua_isnumber(L, -1)) { slant = lua_tointeger(L, -1); }
lua_pop(L,1);
lua_pushstring(L, "layout_dir");
lua_gettable(L, -2);
if (lua_isnumber(L, -1)) { layout_dir = lua_tointeger(L, -1); }
lua_pop(L,1);
font_id = texpdf_dev_load_native_font(filename, index, precision * ptsize, layout_dir, extend, slant, embolden);
lua_pushinteger(L, font_id);
return 1;
}
int pdf_setdirmode(lua_State *L) {
int layout_dir = luaL_checkinteger(L,1);
texpdf_dev_set_dirmode(layout_dir);
return 0;
}
int pdf_setstring(lua_State *L) {
double x = luaL_checknumber(L, 1);
double y = luaL_checknumber(L, 2);
const char* s = luaL_checkstring(L, 3);
int chrlen = luaL_checkinteger(L, 4);
int font_id = luaL_checkinteger(L, 5);
double w = luaL_checknumber(L,6);
ASSERT_PDF_OPENED(p);
texpdf_dev_set_string(p, precision * x, precision * (-height+y), s, chrlen, w * precision, font_id, -1);
return 0;
}
int pdf_setrule(lua_State *L) {
double x = luaL_checknumber(L, 1);
double y = luaL_checknumber(L, 2);
double w = luaL_checknumber(L, 3);
double h = luaL_checknumber(L, 4);
ASSERT_PDF_OPENED(p);
texpdf_dev_set_rule(p, precision * x, precision * (-height+y), precision * w, precision * h);
return 0;
}
int pdf_colorpush_rgb(lua_State *L) {
double r = luaL_checknumber(L, 1);
double g = luaL_checknumber(L, 2);
double b = luaL_checknumber(L, 3);
pdf_color color;
ASSERT_PDF_OPENED(p);
texpdf_color_rgbcolor(&color, r, g, b);
texpdf_color_push(p, &color, &color);
return 0;
}
int pdf_colorpush_cmyk(lua_State *L) {
double c = luaL_checknumber(L, 1);
double m = luaL_checknumber(L, 2);
double y = luaL_checknumber(L, 3);
double k = luaL_checknumber(L, 4);
ASSERT_PDF_OPENED(p);
pdf_color color;
texpdf_color_cmykcolor(&color, c, m, y, k);
texpdf_color_push(p, &color, &color);
return 0;
}
int pdf_colorpush_gray(lua_State *L) {
double l = luaL_checknumber(L, 1);
pdf_color color;
ASSERT_PDF_OPENED(p);
texpdf_color_graycolor(&color, l);
texpdf_color_push(p, &color, &color);
return 0;
}
int pdf_setcolor_rgb(lua_State *L) {
double r = luaL_checknumber(L, 1);
double g = luaL_checknumber(L, 2);
double b = luaL_checknumber(L, 3);
pdf_color color;
ASSERT_PDF_OPENED(p);
texpdf_color_rgbcolor(&color, r, g, b);
texpdf_color_set(p, &color, &color);
return 0;
}
int pdf_setcolor_cmyk(lua_State *L) {
double c = luaL_checknumber(L, 1);
double m = luaL_checknumber(L, 2);
double y = luaL_checknumber(L, 3);
double k = luaL_checknumber(L, 4);
pdf_color color;
ASSERT_PDF_OPENED(p);
texpdf_color_cmykcolor(&color, c, m, y, k);
texpdf_color_set(p, &color, &color);
return 0;
}
int pdf_setcolor_gray(lua_State *L) {
double l = luaL_checknumber(L, 1);
pdf_color color;
ASSERT_PDF_OPENED(p);
texpdf_color_graycolor(&color, l);
texpdf_color_set(p, &color, &color);
return 0;
}
int pdf_colorpop(lua_State *L) {
ASSERT_PDF_OPENED(p);
texpdf_color_pop(p);
return 0;
}
int pdf_destination(lua_State *L) {
pdf_obj* array = texpdf_new_array();
const char* name = luaL_checkstring(L, 1);
double x = luaL_checknumber(L, 2);
double y = luaL_checknumber(L, 3);
ASSERT_PDF_OPENED(p);
texpdf_add_array(array, texpdf_doc_this_page_ref(p));
texpdf_add_array(array, texpdf_new_name("XYZ"));
texpdf_add_array(array, texpdf_new_number(x));
texpdf_add_array(array, texpdf_new_number(y));
texpdf_add_array(array, texpdf_new_null());
texpdf_doc_add_names(p, "Dests",
name,
strlen(name),
array);
return 0;
}
int pdf_bookmark(lua_State *L) {
const char* dictionary = luaL_checkstring(L, 1);
int level = luaL_checknumber(L, 2);
pdf_obj* dict = texpdf_parse_pdf_dict(&dictionary, dictionary + strlen(dictionary), NULL);
int current_depth;
if (!dict) {
luaL_error(L, "Unparsable bookmark dictionary");
return 0;
}
ASSERT_PDF_OPENED(p);
current_depth = texpdf_doc_bookmarks_depth(p);
if (current_depth > level) {
while (current_depth-- > level)
texpdf_doc_bookmarks_up(p);
} else if (current_depth < level) {
while (current_depth++ < level)
texpdf_doc_bookmarks_down(p);
}
texpdf_doc_bookmarks_add(p, dict, 0);
return 0;
}
int pdf_begin_annotation(lua_State *L) {
return 0;
}
int pdf_end_annotation(lua_State *L) {
const char* dictionary = luaL_checkstring(L, 1);
pdf_rect rect;
pdf_obj* dict;
rect.llx = luaL_checknumber(L, 2);
rect.lly = luaL_checknumber(L, 3);
rect.urx = luaL_checknumber(L, 4);
rect.ury = luaL_checknumber(L, 5);
dict = texpdf_parse_pdf_dict(&dictionary, dictionary + strlen(dictionary), NULL);
if (!dict) {
luaL_error(L, "Unparsable annotation dictionary");
return 0;
}
ASSERT_PDF_OPENED(p);
texpdf_doc_add_annot(p, texpdf_doc_current_page_number(p), &rect, dict, 1);
texpdf_release_obj(dict);
return 0;
}
int pdf_metadata(lua_State *L) {
const char* key = luaL_checkstring(L, 1);
const char* value = luaL_checkstring(L, 2);
int len = lua_rawlen(L, 2);
ASSERT(p);
ASSERT(key);
ASSERT(value);
texpdf_add_dict(p->info,
texpdf_new_name(key),
texpdf_new_string(value, len));
return 0;
}
int pdf_drawimage(lua_State *L) {
const char* filename = luaL_checkstring(L, 1);
transform_info ti;
double x = luaL_checknumber(L, 2);
double y = luaL_checknumber(L, 3);
double w = luaL_checknumber(L, 4);
double h = luaL_checknumber(L, 5);
long page_no = (long)luaL_checkinteger(L, 6);
int form_id = texpdf_ximage_findresource(p, filename, page_no, NULL);
texpdf_transform_info_clear(&ti);
ti.width = w;
ti.height = h;
ti.flags |= (INFO_HAS_WIDTH|INFO_HAS_HEIGHT);
ASSERT_PDF_OPENED(p);
texpdf_dev_put_image(p, form_id, &ti, x, -h-y, 0);
return 0;
}
extern int get_image_bbox(FILE* f, long page_no, double* llx, double* lly, double* urx, double* ury, double* xresol, double* yresol);
int pdf_imagebbox(lua_State *L) {
const char* filename = luaL_checkstring(L, 1);
long page_no = (long)luaL_checkinteger(L, 2);
double llx = 0;
double lly = 0;
double urx = 0;
double ury = 0;
double xresol = 0;
double yresol = 0;
FILE* f = MFOPEN(filename, FOPEN_RBIN_MODE);
if (!f) {
return luaL_error(L, "Image file not found %s", filename);
}
if ( get_image_bbox(f, page_no, &llx, &lly, &urx, &ury, &xresol, &yresol) < 0 ) {
MFCLOSE(f);
return luaL_error(L, "Invalid image file %s", filename);
}
MFCLOSE(f);
lua_pushnumber(L, llx);
lua_pushnumber(L, lly);
lua_pushnumber(L, urx);
lua_pushnumber(L, ury);
if (xresol == 0) {
lua_pushnil(L);
} else {
lua_pushnumber(L, xresol);
}
if (yresol == 0) {
lua_pushnil(L);
} else {
lua_pushnumber(L, yresol);
}
return 6;
}
int pdf_transform(lua_State *L) {
pdf_tmatrix matrix;
double a = luaL_checknumber(L, 1);
double b = luaL_checknumber(L, 2);
double c = luaL_checknumber(L, 3);
double d = luaL_checknumber(L, 4);
double e = luaL_checknumber(L, 5);
double f = luaL_checknumber(L, 6);
ASSERT_PDF_OPENED(p);
texpdf_graphics_mode(p);
pdf_setmatrix(&matrix, a,b,c,d,e,f);
texpdf_dev_concat(p, &matrix);
return 0;
}
int pdf_gsave(lua_State *L) {
ASSERT_PDF_OPENED(p);
texpdf_graphics_mode(p);
texpdf_dev_gsave(p);
return 0;
}
int pdf_grestore(lua_State *L) {
ASSERT_PDF_OPENED(p);
texpdf_graphics_mode(p);
texpdf_dev_grestore(p);
return 0;
}
int pdf_add_content(lua_State *L) {
const char* input = luaL_checkstring(L, 1);
int input_l = lua_rawlen(L, 1);
ASSERT_PDF_OPENED(p);
texpdf_graphics_mode(p);
texpdf_doc_add_page_content(p, " ", 1);
texpdf_doc_add_page_content(p, input, input_l);
texpdf_doc_add_page_content(p, " ", 1);
return 0;
}
int pdf_parse(lua_State *L) {
const char* input = luaL_checkstring(L, 1);
int input_l = lua_rawlen(L, 1);
pdf_obj* o = texpdf_parse_pdf_object(&input, input+input_l, NULL);
if (o) {
lua_pushlightuserdata(L,o);
return 1;
} else {
return 0;
}
}
int pdf_add_dict(lua_State *L) {
pdf_obj* dict = lua_touserdata(L, 1);
pdf_obj* key = lua_touserdata(L, 2);
pdf_obj* value = lua_touserdata(L, 3);
texpdf_add_dict(dict, key, value);
return 0;
}
int pdf_reference(lua_State *L) {
pdf_obj* o1 = lua_touserdata(L, 1);
pdf_obj* o2 = texpdf_ref_obj(o1);
lua_pushlightuserdata(L, o2);
return 1;
}
int pdf_release(lua_State *L) {
pdf_obj* o1 = lua_touserdata(L, 1);
texpdf_release_obj(o1);
return 0;
}
int pdf_get_dictionary(lua_State *L) {
const char* dict = luaL_checkstring(L, 1);
pdf_obj *o = texpdf_doc_get_dictionary(p, dict);
if (o) {
lua_pushlightuserdata(L,o);
return 1;
} else {
return 0;
}
}
int pdf_lookup_dictionary(lua_State *L) {
pdf_obj* dict = lua_touserdata(L, 1);
const char* key = luaL_checkstring(L, 2);
pdf_obj *o = texpdf_lookup_dict(dict, key);
if (o) {
lua_pushlightuserdata(L,o);
return 1;
} else {
return 0;
}
}
int pdf_push_array(lua_State *L) {
pdf_obj* array = lua_touserdata(L, 1);
if (!PDF_OBJ_ARRAYTYPE(array)) {
return luaL_error(L, "push_array called on non-array");
}
pdf_obj* val = lua_touserdata(L, 2);
texpdf_add_array(array, val);
return 0;
}
int pdf_get_array(lua_State *L) {
pdf_obj* array = lua_touserdata(L, 1);
if (!PDF_OBJ_ARRAYTYPE(array)) {
return luaL_error(L, "push_array called on non-array");
}
long idx = lua_tonumber(L, 2);
pdf_obj *o = texpdf_get_array(array,idx);
if (o) {
lua_pushlightuserdata(L,o);
return 1;
} else {
return 0;
}
}
int pdf_array_length(lua_State *L) {
pdf_obj* array = lua_touserdata(L, 1);
if (!PDF_OBJ_ARRAYTYPE(array)) {
return luaL_error(L, "push_array called on non-array");
}
lua_pushinteger(L, texpdf_array_length(array));
return 1;
}
int pdf_new_string(lua_State *L) {
const char* s = luaL_checkstring(L, 1);
int l = lua_rawlen(L, 1);
lua_pushlightuserdata(L, texpdf_new_string(s, l));
return 1;
}
int pdf_version(lua_State *L) {
lua_pushstring(L, texpdf_library_version());
return 1;
}
#if !defined LUA_VERSION_NUM
#define luaL_Reg luaL_reg
#endif
#if !defined LUA_VERSION_NUM || LUA_VERSION_NUM==501
void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
luaL_checkstack(L, nup+1, "too many upvalues");
for (; l->name != NULL; l++) {
int i;
lua_pushstring(L, l->name);
for (i = 0; i < nup; i++)
lua_pushvalue(L, -(nup+1));
lua_pushcclosure(L, l->func, nup);
lua_settable(L, -(nup + 3));
}
lua_pop(L, nup);
}
#endif
static const struct luaL_Reg lib_table [] = {
{"init", pdf_init},
{"beginpage", pdf_beginpage},
{"change_page_size", pdf_changepagesize},
{"endpage", pdf_endpage},
{"finish", pdf_finish},
{"loadfont", pdf_loadfont},
{"setdirmode", pdf_setdirmode},
{"setstring", pdf_setstring},
{"setrule", pdf_setrule},
{"setcolor_rgb", pdf_setcolor_rgb},
{"setcolor_cmyk", pdf_setcolor_cmyk},
{"setcolor_gray", pdf_setcolor_gray},
{"drawimage", pdf_drawimage},
{"imagebbox", pdf_imagebbox},
{"colorpop", pdf_colorpop},
{"colorpush_rgb", pdf_colorpush_rgb},
{"colorpush_cmyk", pdf_colorpush_cmyk},
{"colorpush_gray", pdf_colorpush_gray},
{"setmatrix", pdf_transform},
{"gsave", pdf_gsave},
{"grestore", pdf_grestore},
{"destination", pdf_destination},
{"bookmark", pdf_bookmark},
{"begin_annotation", pdf_begin_annotation},
{"end_annotation", pdf_end_annotation},
{"metadata", pdf_metadata},
{"version", pdf_version},
{"add_content", pdf_add_content},
{"get_dictionary", pdf_get_dictionary},
{"parse", pdf_parse},
{"add_dict", pdf_add_dict},
{"lookup_dictionary", pdf_lookup_dictionary},
{"reference", pdf_reference},
{"release", pdf_release},
{"push_array", pdf_push_array},
{"get_array", pdf_get_array},
{"array_length", pdf_array_length},
{"string", pdf_new_string},
{NULL, NULL}
};
int luaopen_justenoughlibtexpdf (lua_State *L) {
lua_newtable(L);
luaL_setfuncs(L, lib_table, 0);
return 1;
}