/* limglib.c Copyright 2006-2010 Taco Hoekwater This file is part of LuaTeX. LuaTeX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. LuaTeX is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU General Public License along with LuaTeX; if not, see . */ static const char _svn_version[] = "$Id: limglib.c 4051 2011-01-09 22:41:33Z hhenkel $ " "$URL: http://foundry.supelec.fr/svn/luatex/tags/beta-0.70.1/source/texk/web2c/luatexdir/lua/limglib.c $"; #include #include #include #include "lua51/lua.h" #include "lua51/lauxlib.h" #include "ptexlib.h" #include "lua/luatex-api.h" /**********************************************************************/ #ifdef DEBUG void stackDump(lua_State * L, char *s) { int i, t, top = lua_gettop(L); printf("\n=== stackDump <%s>: ", s); for (i = top; i >= 1; i--) { /* repeat for each level */ t = lua_type(L, i); printf("%d: ", i); switch (t) { case LUA_TSTRING: /* strings */ printf("`%s'", lua_tostring(L, i)); break; case LUA_TBOOLEAN: /* booleans */ printf(lua_toboolean(L, i) ? "true" : "false"); break; case LUA_TNUMBER: /* numbers */ printf("%g", (double) lua_tonumber(L, i)); break; default: /* other values */ printf("%s", lua_typename(L, t)); break; } printf(" "); /* put a separator */ } printf("\n"); } #endif /**********************************************************************/ typedef enum { P__ZERO, P_ATTR, P_BBOX, P_COLORDEPTH, P_COLORSPACE, P_DEPTH, P_FILENAME, P_FILEPATH, P_HEIGHT, P_IMAGETYPE, P_INDEX, P_OBJNUM, P_PAGE, P_PAGEBOX, P_TOTALPAGES, P_ROTATION, P_STREAM, P_TRANSFORM, P_WIDTH, P_XRES, P_XSIZE, P_YRES, P_YSIZE, P__SENTINEL } parm_idx; static const parm_struct img_parms[] = { {NULL, P__ZERO}, /* dummy; lua indices run from 1 */ {"attr", P_ATTR}, {"bbox", P_BBOX}, {"colordepth", P_COLORDEPTH}, {"colorspace", P_COLORSPACE}, {"depth", P_DEPTH}, {"filename", P_FILENAME}, {"filepath", P_FILEPATH}, {"height", P_HEIGHT}, {"imagetype", P_IMAGETYPE}, {"index", P_INDEX}, {"objnum", P_OBJNUM}, {"page", P_PAGE}, {"pagebox", P_PAGEBOX}, {"pages", P_TOTALPAGES}, {"rotation", P_ROTATION}, {"stream", P_STREAM}, {"transform", P_TRANSFORM}, {"width", P_WIDTH}, {"xres", P_XRES}, {"xsize", P_XSIZE}, {"yres", P_YRES}, {"ysize", P_YSIZE}, {NULL, P__SENTINEL} }; #define imgtype_max 6 const char *imgtype_s[] = { "none", "pdf", "png", "jpg", "jp2", "jbig2", "stream", NULL }; #define pagebox_max 5 const char *pdfboxspec_s[] = { "none", "media", "crop", "bleed", "trim", "art", NULL }; /**********************************************************************/ static void image_to_lua(lua_State * L, image * a) { /* key user ... */ int i, j; image_dict *d = img_dict(a); assert(d != NULL); lua_pushvalue(L, -1); /* k k u ... */ lua_gettable(L, LUA_ENVIRONINDEX); /* i? k u ... */ if (!lua_isnumber(L, -1)) /* !i k u ... */ luaL_error(L, "image_to_lua(): %s is not a valid image key", lua_tostring(L, -2)); i = (int) lua_tointeger(L, -1); /* i k u ... */ lua_pop(L, 2); /* u ... */ switch (i) { case P_WIDTH: if (is_wd_running(a)) lua_pushnil(L); else lua_pushinteger(L, img_width(a)); break; case P_HEIGHT: if (is_ht_running(a)) lua_pushnil(L); else lua_pushinteger(L, img_height(a)); break; case P_DEPTH: if (is_dp_running(a)) lua_pushnil(L); else lua_pushinteger(L, img_depth(a)); break; case P_TRANSFORM: lua_pushinteger(L, img_transform(a)); break; /* now follow all image_dict entries */ case P_FILENAME: if (img_filename(d) == NULL || strlen(img_filename(d)) == 0) lua_pushnil(L); else lua_pushstring(L, img_filename(d)); break; case P_FILEPATH: if (img_filepath(d) == NULL || strlen(img_filepath(d)) == 0) lua_pushnil(L); else lua_pushstring(L, img_filepath(d)); break; case P_ATTR: if (img_attr(d) == NULL || strlen(img_attr(d)) == 0) lua_pushnil(L); else lua_pushstring(L, img_attr(d)); break; case P_PAGE: if (img_pagename(d) != NULL && strlen(img_pagename(d)) != 0) lua_pushstring(L, img_pagename(d)); else lua_pushinteger(L, img_pagenum(d)); break; case P_TOTALPAGES: lua_pushinteger(L, img_totalpages(d)); break; case P_XSIZE: /* Modify by /Rotate only for output */ if ((img_rotation(d) & 1) == 0) lua_pushinteger(L, img_xsize(d)); else lua_pushinteger(L, img_ysize(d)); break; case P_YSIZE: /* Modify by /Rotate only for output */ if ((img_rotation(d) & 1) == 0) lua_pushinteger(L, img_ysize(d)); else lua_pushinteger(L, img_xsize(d)); break; case P_XRES: lua_pushinteger(L, img_xres(d)); break; case P_YRES: lua_pushinteger(L, img_yres(d)); break; case P_ROTATION: lua_pushinteger(L, img_rotation(d)); break; case P_COLORSPACE: if (img_colorspace(d) == 0) lua_pushnil(L); else lua_pushinteger(L, img_colorspace(d)); break; case P_COLORDEPTH: if (img_colordepth(d) == 0) lua_pushnil(L); else lua_pushinteger(L, img_colordepth(d)); break; case P_IMAGETYPE: j = img_type(d); if (j >= 0 && j <= imgtype_max) { if (j == IMG_TYPE_NONE) lua_pushnil(L); else lua_pushstring(L, imgtype_s[j]); } else assert(0); break; case P_PAGEBOX: j = img_pagebox(d); if (j >= 0 && j <= pagebox_max) { if (j == PDF_BOX_SPEC_NONE) lua_pushnil(L); else lua_pushstring(L, pdfboxspec_s[j]); } else assert(0); break; case P_BBOX: if (!img_is_bbox(d)) { img_bbox(d)[0] = img_xorig(d); img_bbox(d)[1] = img_yorig(d); img_bbox(d)[2] = img_xorig(d) + img_xsize(d); img_bbox(d)[3] = img_yorig(d) + img_ysize(d); } lua_newtable(L); lua_pushinteger(L, 1); lua_pushinteger(L, img_bbox(d)[0]); lua_settable(L, -3); lua_pushinteger(L, 2); lua_pushinteger(L, img_bbox(d)[1]); lua_settable(L, -3); lua_pushinteger(L, 3); lua_pushinteger(L, img_bbox(d)[2]); lua_settable(L, -3); lua_pushinteger(L, 4); lua_pushinteger(L, img_bbox(d)[3]); lua_settable(L, -3); break; case P_OBJNUM: if (img_objnum(d) == 0) lua_pushnil(L); else lua_pushinteger(L, img_objnum(d)); break; case P_INDEX: if (img_index(d) == 0) lua_pushnil(L); else lua_pushinteger(L, img_index(d)); break; case P_STREAM: if (img_type(d) != IMG_TYPE_PDFSTREAM || img_pdfstream_ptr(d) == NULL || img_pdfstream_stream(d) == NULL || strlen(img_pdfstream_stream(d)) == 0) lua_pushnil(L); else lua_pushstring(L, img_pdfstream_stream(d)); break; default: assert(0); } /* v u ... */ } static void lua_to_image(lua_State * L, image * a) { /* value key table ... */ int i; image_dict *d = img_dict(a); assert(d != NULL); lua_pushvalue(L, -2); /* k v k t ... */ lua_gettable(L, LUA_ENVIRONINDEX); /* i? v k t ... */ if (!lua_isnumber(L, -1)) /* !i v k t ... */ luaL_error(L, "lua_to_image(): %s is not a valid image key", lua_tostring(L, -3)); i = (int) lua_tointeger(L, -1); /* i v k t ... */ lua_pop(L, 1); /* v k t ... */ switch (i) { case P_WIDTH: if (lua_isnil(L, -1)) set_wd_running(a); else if (lua_type(L, -1) == LUA_TNUMBER) img_width(a) = (int) lua_tointeger(L, -1); else if (lua_type(L, -1) == LUA_TSTRING) img_width(a) = dimen_to_number(L, lua_tostring(L, -1)); else luaL_error(L, "image.width needs integer or nil value or dimension string"); break; case P_HEIGHT: if (lua_isnil(L, -1)) set_ht_running(a); else if (lua_type(L, -1) == LUA_TNUMBER) img_height(a) = (int) lua_tointeger(L, -1); else if (lua_type(L, -1) == LUA_TSTRING) img_height(a) = dimen_to_number(L, lua_tostring(L, -1)); else luaL_error(L, "image.height needs integer or nil value or dimension string"); break; case P_DEPTH: if (lua_isnil(L, -1)) set_dp_running(a); else if (lua_type(L, -1) == LUA_TNUMBER) img_depth(a) = (int) lua_tointeger(L, -1); else if (lua_type(L, -1) == LUA_TSTRING) img_depth(a) = dimen_to_number(L, lua_tostring(L, -1)); else luaL_error(L, "image.depth needs integer or nil value or dimension string"); break; case P_TRANSFORM: if (lua_isnumber(L, -1)) img_transform(a) = (int) lua_tointeger(L, -1); else luaL_error(L, "image.transform needs integer value"); break; /* now follow all image_dict entries */ case P_FILENAME: if (img_state(d) >= DICT_FILESCANNED) luaL_error(L, "image.filename is now read-only"); if (img_type(d) == IMG_TYPE_PDFSTREAM) luaL_error(L, "image.filename can't be used with image.stream"); if (lua_isstring(L, -1)) { xfree(img_filename(d)); img_filename(d) = xstrdup(lua_tostring(L, -1)); } else luaL_error(L, "image.filename needs string value"); break; case P_ATTR: if (img_state(d) >= DICT_FILESCANNED) luaL_error(L, "image.attr is now read-only"); if (lua_isstring(L, -1) || lua_isnil(L, -1)) { xfree(img_attr(d)); if (lua_isstring(L, -1)) img_attr(d) = xstrdup(lua_tostring(L, -1)); } else luaL_error(L, "image.attr needs string or nil value"); break; case P_PAGE: if (img_state(d) >= DICT_FILESCANNED) luaL_error(L, "image.page is now read-only"); if (lua_type(L, -1) == LUA_TSTRING) { xfree(img_pagename(d)); img_pagename(d) = xstrdup(lua_tostring(L, -1)); img_pagenum(d) = 0; } else if (lua_type(L, -1) == LUA_TNUMBER) { img_pagenum(d) = (int) lua_tointeger(L, -1); xfree(img_pagename(d)); } else luaL_error(L, "image.page needs integer or string value"); break; case P_COLORSPACE: if (img_state(d) >= DICT_FILESCANNED) luaL_error(L, "image.colorspace is now read-only"); if (lua_isnil(L, -1)) img_colorspace(d) = 0; else if (lua_isnumber(L, -1)) img_colorspace(d) = (int) lua_tointeger(L, -1); else luaL_error(L, "image.colorspace needs integer or nil value"); break; case P_PAGEBOX: if (img_state(d) >= DICT_FILESCANNED) luaL_error(L, "image.pagebox is now read-only"); if (lua_isnil(L, -1)) img_pagebox(d) = PDF_BOX_SPEC_NONE; else if (lua_isstring(L, -1)) img_pagebox(d) = luaL_checkoption(L, -1, "none", pdfboxspec_s); else luaL_error(L, "image.pagebox needs string or nil value"); break; case P_BBOX: if (img_state(d) >= DICT_FILESCANNED) luaL_error(L, "image.bbox is now read-only"); if (!lua_istable(L, -1)) luaL_error(L, "image.bbox needs table value"); if (lua_objlen(L, -1) != 4) luaL_error(L, "image.bbox table must have exactly 4 elements"); for (i = 1; i <= 4; i++) { /* v k t ... */ lua_pushinteger(L, i); /* idx v k t ... */ lua_gettable(L, -2); /* int v k t ... */ if (lua_type(L, -1) == LUA_TNUMBER) img_bbox(d)[i - 1] = (int) lua_tointeger(L, -1); else if (lua_type(L, -1) == LUA_TSTRING) img_bbox(d)[i - 1] = dimen_to_number(L, lua_tostring(L, -1)); else luaL_error(L, "image.bbox table needs integer value or dimension string elements"); lua_pop(L, 1); /* v k t ... */ } img_set_bbox(d); break; case P_STREAM: if (img_filename(d) != NULL) luaL_error(L, "image.stream can't be used with image.filename"); if (img_state(d) >= DICT_FILESCANNED) luaL_error(L, "image.stream is now read-only"); if (img_pdfstream_ptr(d) == NULL) new_img_pdfstream_struct(d); xfree(img_pdfstream_stream(d)); img_pdfstream_stream(d) = xstrdup(lua_tostring(L, -1)); img_type(d) = IMG_TYPE_PDFSTREAM; break; case P_FILEPATH: case P_TOTALPAGES: case P_XSIZE: case P_YSIZE: case P_XRES: case P_YRES: case P_ROTATION: case P_IMAGETYPE: case P_OBJNUM: case P_INDEX: case P_COLORDEPTH: luaL_error(L, "image.%s is a read-only variable", img_parms[i].name); break; default: assert(0); } /* v k t ... */ } /**********************************************************************/ static void copy_image(lua_State * L, lua_Number scale) { image *a, **aa, *b, **bb; if (lua_gettop(L) != 1) luaL_error(L, "img.copy() needs exactly 1 argument"); aa = (image **) luaL_checkudata(L, 1, TYPE_IMG); /* a */ lua_pop(L, 1); /* - */ a = *aa; bb = (image **) lua_newuserdata(L, sizeof(image *)); /* b */ luaL_getmetatable(L, TYPE_IMG); /* m b */ lua_setmetatable(L, -2); /* b */ b = *bb = new_image(); if (!is_wd_running(a)) img_width(b) = do_zround(img_width(a) * scale); if (!is_ht_running(a)) img_height(b) = do_zround(img_height(a) * scale); if (!is_dp_running(a)) img_depth(b) = do_zround(img_depth(a) * scale); img_transform(b) = img_transform(a); img_dict(b) = img_dict(a); if (img_dictref(a) != LUA_NOREF) { lua_rawgeti(L, LUA_GLOBALSINDEX, img_dictref(a)); /* ad b */ img_dictref(b) = luaL_ref(L, LUA_GLOBALSINDEX); /* b */ } else assert(img_state(img_dict(a)) >= DICT_REFERED); } /**********************************************************************/ int l_new_image(lua_State * L) { image *a, **aa; image_dict **add; if (lua_gettop(L) > 1) luaL_error(L, "img.new() needs maximum 1 argument"); if (lua_gettop(L) == 1 && !lua_istable(L, -1)) luaL_error(L, "img.new() needs table as optional argument"); /* (t) */ aa = (image **) lua_newuserdata(L, sizeof(image *)); /* i (t) */ luaL_getmetatable(L, TYPE_IMG); /* m i (t) */ lua_setmetatable(L, -2); /* i (t) */ a = *aa = new_image(); add = (image_dict **) lua_newuserdata(L, sizeof(image_dict *)); /* ad i (t) */ luaL_getmetatable(L, TYPE_IMG_DICT); /* m ad i (t) */ lua_setmetatable(L, -2); /* ad i (t) */ img_dict(a) = *add = new_image_dict(); img_dictref(a) = luaL_ref(L, LUA_GLOBALSINDEX); /* i (t) */ if (lua_gettop(L) == 2) { /* i t, else just i */ lua_insert(L, -2); /* t i */ lua_pushnil(L); /* n t i (1st key for iterator) */ while (lua_next(L, -2) != 0) { /* v k t i */ lua_to_image(L, a); /* v k t i */ lua_pop(L, 1); /* k t i */ } /* t i */ lua_pop(L, 1); /* i */ } /* i */ return 1; /* i */ } static int l_copy_image(lua_State * L) { if (lua_gettop(L) != 1) luaL_error(L, "img.copy() needs exactly 1 argument"); if (lua_istable(L, 1)) (void) l_new_image(L); /* image --- if everything worked well */ else (void) copy_image(L, 1.0); /* image */ return 1; /* image */ } static void read_scale_img(image * a) { image_dict *ad; assert(a != NULL); ad = img_dict(a); assert(ad != NULL); if (img_state(ad) == DICT_NEW) { if (img_type(ad) == IMG_TYPE_PDFSTREAM) check_pdfstream_dict(ad); else { fix_pdf_minorversion(static_pdf); read_img(static_pdf, ad, pdf_minor_version, pdf_inclusion_errorlevel); } } if (is_wd_running(a) || is_ht_running(a) || is_dp_running(a)) img_dimen(a) = scale_img(ad, img_dimen(a), img_transform(a)); } static int l_scan_image(lua_State * L) { image *a, **aa; if (lua_gettop(L) != 1) luaL_error(L, "img.scan() needs exactly 1 argument"); if (lua_istable(L, 1)) (void) l_new_image(L); /* image --- if everything worked well */ aa = (image **) luaL_checkudata(L, 1, TYPE_IMG); /* image */ a = *aa; check_o_mode(static_pdf, "img.scan()", 1 << OMODE_PDF, false); /* flush_str(last_tex_string); *//* ?? */ read_scale_img(a); return 1; /* image */ } static halfword img_to_node(image * a) { image_dict *ad; halfword n; assert(a != NULL); ad = img_dict(a); assert(ad != NULL); assert(img_objnum(ad) != 0); n = new_node(whatsit_node, pdf_refximage_node); pdf_ximage_index(n) = img_index(ad); width(n) = img_width(a); height(n) = img_height(a); depth(n) = img_depth(a); pdf_ximage_transform(n) = img_transform(a); return n; } typedef enum { WR_WRITE, WR_IMMEDIATEWRITE, WR_NODE, WR_VF_IMG } wrtype_e; const char *wrtype_s[] = { "img.write()", "img.immediatewrite()", "img.node()", "write vf image" }; static void setup_image(PDF pdf, image * a, wrtype_e writetype) { image_dict *ad; assert(a != NULL); ad = img_dict(a); check_o_mode(pdf, wrtype_s[writetype], 1 << OMODE_PDF, false); /* flush_str(last_tex_string); *//* ?? */ read_scale_img(a); if (img_objnum(ad) == 0) { /* latest needed just before out_img() */ pdf->ximage_count++; img_objnum(ad) = pdf_create_obj(pdf, obj_type_ximage, pdf->ximage_count); img_index(ad) = pdf->ximage_count; idict_to_array(ad); /* now ad is read-only */ obj_data_ptr(pdf, pdf->obj_ptr) = img_index(ad); } } static void write_image_or_node(lua_State * L, wrtype_e writetype) { image *a, **aa; image_dict *ad; halfword n; if (lua_gettop(L) != 1) luaL_error(L, "%s needs exactly 1 argument", wrtype_s[writetype]); if (lua_istable(L, 1)) (void) l_new_image(L); /* image --- if everything worked well */ aa = (image **) luaL_checkudata(L, 1, TYPE_IMG); /* image */ a = *aa; ad = img_dict(a); setup_image(static_pdf, a, writetype); switch (writetype) { case WR_WRITE: n = img_to_node(a); tail_append(n); break; /* image */ case WR_IMMEDIATEWRITE: pdf_begin_dict(static_pdf, img_objnum(ad), 0); write_img(static_pdf, ad); break; /* image */ case WR_NODE: /* image */ lua_pop(L, 1); /* - */ n = img_to_node(a); lua_nodelib_push_fast(L, n); break; /* node */ default: assert(0); } if (img_state(ad) < DICT_REFERED) img_state(ad) = DICT_REFERED; } static int l_write_image(lua_State * L) { write_image_or_node(L, WR_WRITE); return 1; /* image */ } static int l_immediatewrite_image(lua_State * L) { check_o_mode(static_pdf, "img.immediatewrite()", 1 << OMODE_PDF, true); if (global_shipping_mode != NOT_SHIPPING) luaL_error(L, "pdf.immediatewrite() can not be used with \\latelua"); write_image_or_node(L, WR_IMMEDIATEWRITE); return 1; /* image */ } static int l_image_node(lua_State * L) { write_image_or_node(L, WR_NODE); return 1; /* node */ } static int l_image_keys(lua_State * L) { const parm_struct *p = img_parms + 1; if (lua_gettop(L) != 0) luaL_error(L, "img.keys() goes without argument"); lua_newtable(L); /* t */ for (; p->name != NULL; p++) { lua_pushinteger(L, (int) p->idx); /* k t */ lua_pushstring(L, p->name); /* v k t */ lua_settable(L, -3); /* t */ } return 1; } static int l_image_types(lua_State * L) { int i; const char **p; if (lua_gettop(L) != 0) luaL_error(L, "img.types() goes without argument"); lua_newtable(L); /* t */ for (i = 1, p = (const char **) (imgtype_s + 1); *p != NULL; p++, i++) { lua_pushinteger(L, (int) i); /* k t */ lua_pushstring(L, *p); /* v k t */ lua_settable(L, -3); /* t */ } return 1; } static int l_image_boxes(lua_State * L) { int i; const char **p; if (lua_gettop(L) != 0) luaL_error(L, "img.boxes() goes without argument"); lua_newtable(L); /* t */ for (i = 1, p = (const char **) (pdfboxspec_s + 1); *p != NULL; p++, i++) { lua_pushinteger(L, (int) i); /* k t */ lua_pushstring(L, *p); /* v k t */ lua_settable(L, -3); /* t */ } return 1; } static const struct luaL_Reg imglib[] = { {"new", l_new_image}, {"copy", l_copy_image}, {"scan", l_scan_image}, {"write", l_write_image}, {"immediatewrite", l_immediatewrite_image}, {"node", l_image_node}, {"keys", l_image_keys}, {"types", l_image_types}, {"boxes", l_image_boxes}, {NULL, NULL} /* sentinel */ }; /**********************************************************************/ void vf_out_image(PDF pdf, unsigned i) { image *a, **aa; image_dict *ad; lua_State *L = Luas; /* ... */ lua_rawgeti(L, LUA_GLOBALSINDEX, (int) i); /* image ... */ aa = (image **) luaL_checkudata(L, -1, TYPE_IMG); a = *aa; ad = img_dict(a); assert(ad != NULL); setup_image(pdf, a, WR_VF_IMG); /* image ... */ place_img(pdf, ad, img_dimen(a), img_transform(a)); lua_pop(L, 1); /* ... */ } /**********************************************************************/ /* Metamethods for image */ static int m_img_get(lua_State * L) { image **aa = (image **) luaL_checkudata(L, 1, TYPE_IMG); /* k u */ image_to_lua(L, *aa); /* v u */ return 1; } static int m_img_set(lua_State * L) { image **aa = (image **) luaL_checkudata(L, 1, TYPE_IMG); /* value key user */ lua_to_image(L, *aa); /* v k u */ return 0; } static int m_img_mul(lua_State * L) { image **aa; lua_Number scale; if (lua_isnumber(L, 1)) { /* u? n */ aa = (image **) luaL_checkudata(L, 2, TYPE_IMG); /* u n */ lua_insert(L, -2); /* n a */ } else if (lua_isnumber(L, 2)) { /* n u? */ aa = (image **) luaL_checkudata(L, 1, TYPE_IMG); /* n a */ } /* n a */ scale = lua_tonumber(L, 2); /* n a */ lua_pop(L, 1); /* a */ copy_image(L, scale); /* b */ return 1; } static int m_img_print(lua_State * L) { image **aa; image_dict *d; aa = (image **) luaL_checkudata(L, 1, TYPE_IMG); d = img_dict(*aa); if (img_pagename(d) != NULL && strlen(img_pagename(d)) != 0) lua_pushfstring(L, "", img_filename(d), img_pagename(d)); else lua_pushfstring(L, "", img_filename(d), img_pagenum(d)); return 1; } static int m_img_gc(lua_State * L) { image *a, **aa; image_dict *d; aa = (image **) luaL_checkudata(L, 1, TYPE_IMG); a = *aa; d = img_dict(*aa); #ifdef DEBUG printf("\n===== IMG GC ===== a=%d ad=%d\n", a, img_dict(a)); #endif luaL_unref(L, LUA_GLOBALSINDEX, img_dictref(a)); if (!img_is_refered(d)) xfree(a); return 0; } static const struct luaL_Reg img_m[] = { {"__index", m_img_get}, {"__newindex", m_img_set}, {"__mul", m_img_mul}, {"__tostring", m_img_print}, {"__gc", m_img_gc}, /* finalizer */ {NULL, NULL} /* sentinel */ }; /**********************************************************************/ /* Metamethods for image_dict */ static int m_img_dict_gc(lua_State * L) { image_dict *ad, **add; add = (image_dict **) luaL_checkudata(L, 1, TYPE_IMG_DICT); ad = *add; #ifdef DEBUG printf("\n===== IMG_DICT GC FREE ===== ad=%d\n", ad); #endif if (img_state(ad) < DICT_REFERED) free_image_dict(ad); return 0; } static const struct luaL_Reg img_dict_m[] = { {"__gc", m_img_dict_gc}, /* finalizer */ {NULL, NULL} /* sentinel */ }; /**********************************************************************/ int luaopen_img(lua_State * L) { preset_environment(L, img_parms); luaL_newmetatable(L, TYPE_IMG); luaL_register(L, NULL, img_m); luaL_newmetatable(L, TYPE_IMG_DICT); luaL_register(L, NULL, img_dict_m); luaL_register(L, "img", imglib); return 1; } /**********************************************************************/