static int load_embedded_image(lua_State *L) { am_check_nargs(L, 1); const char *filename = luaL_checkstring(L, 1); am_embedded_file_record *rec = am_get_embedded_file(filename); if (rec == NULL) { return luaL_error(L, "embedded file not found: %s", filename); } int width, height; int components = 4; stbi_set_flip_vertically_on_load(1); stbi_uc *img_data = stbi_load_from_memory((stbi_uc const *)rec->data, rec->len, &width, &height, &components, 4); if (img_data == NULL) { return luaL_error(L, "error loading image %s: %s", filename, stbi_failure_reason()); } am_image_buffer *img = am_new_userdata(L, am_image_buffer); img->width = width; img->height = height; img->format = AM_PIXEL_FORMAT_RGBA8; int sz = width * height * pixel_format_size(img->format); am_buffer *imgbuf = am_new_userdata(L, am_buffer); imgbuf->size = sz; imgbuf->data = img_data; img->buffer = imgbuf; img->buffer_ref = img->ref(L, -1); lua_pop(L, 1); // pop imgbuf return 1; }
static int load_image(lua_State *L) { am_check_nargs(L, 1); char *errmsg; int len; const char *filename = luaL_checkstring(L, 1); void *data = am_read_resource(filename, &len, &errmsg); if (data == NULL) { lua_pushstring(L, errmsg); free(errmsg); return lua_error(L); } int width, height; int components = 4; stbi_set_flip_vertically_on_load(1); stbi_uc *img_data = stbi_load_from_memory((stbi_uc const *)data, len, &width, &height, &components, 4); free(data); if (img_data == NULL) { return luaL_error(L, "error loading image %s: %s", filename, stbi_failure_reason()); } am_image_buffer *img = am_new_userdata(L, am_image_buffer); img->width = width; img->height = height; img->format = AM_PIXEL_FORMAT_RGBA8; int sz = width * height * pixel_format_size(img->format); am_buffer *imgbuf = am_new_userdata(L, am_buffer); imgbuf->size = sz; imgbuf->data = img_data; img->buffer = imgbuf; img->buffer_ref = img->ref(L, -1); lua_pop(L, 1); // pop imgbuf return 1; }
static int paste(lua_State *L) { am_check_nargs(L, 4); am_image_buffer *dst = am_get_userdata(L, am_image_buffer, 1); am_image_buffer *src = am_get_userdata(L, am_image_buffer, 2); int start_x = lua_tointeger(L, 3) - 1; int start_y = lua_tointeger(L, 4) - 1; if (start_x < 0) luaL_argerror(L, 3, "must be a positive integer"); if (start_y < 0) luaL_argerror(L, 4, "must be a positive integer"); if (src->format != dst->format) luaL_error(L, "images must have the same format"); int src_w = src->width; int src_h = src->height; int dst_w = dst->width; int dst_h = dst->height; if (start_x >= dst_w) return 0; if (start_y >= dst_h) return 0; int pitch = am_min(dst_w - start_x, src_w); int end_y = am_min(dst_h - start_y, src_h); uint8_t *src_data = src->buffer->data; uint8_t *dst_data = dst->buffer->data; int psz = pixel_format_size(src->format); int row_size = pitch * psz; int j = start_y; for (int i = 0; i < end_y; i++) { memmove(dst_data + j * dst_w * psz + start_x * psz, src_data + i * src_w * psz, row_size); j++; } dst->buffer->mark_dirty(start_y * dst_w * psz + start_x * psz, (start_y + end_y - 1) * psz + (start_x + pitch) * psz); return 0; }
static VALUE image_create_cairo_surface(VALUE obj) { cairo_surface_t* cairo_surface; cairo_format_t cairo_format; unsigned char* data; VALUE surface; struct image_data* image = get_image_data(obj); data = xmalloc(sizeof(unsigned char)*RSTRING_LEN(image->buffer)); MEMCPY(data, RSTRING_PTR(image->buffer), unsigned char, RSTRING_LEN(image->buffer)); cairo_format = pixel_format_to_cairo_format(image->pixel_format); cairo_surface = cairo_image_surface_create_for_data( data, cairo_format, (int)image->width, (int)image->height, (int)image->stride*pixel_format_size(image->pixel_format)); cairo_surface_set_user_data(cairo_surface, &cairo_data_key, data, image_surface_did_destroyed); surface = CRSURFACE2RVAL_WITH_DESTROY(cairo_surface); return surface; }
static int create_image_buffer(lua_State *L) { int nargs = am_check_nargs(L, 1); am_image_buffer *img = am_new_userdata(L, am_image_buffer); int arg = 1; if (am_get_type(L, arg) == MT_am_buffer) { img->buffer = am_get_userdata(L, am_buffer, arg); img->buffer_ref = img->ref(L, arg); arg++; } if (nargs < arg) { return luaL_error(L, "not enough arguments"); } img->width = luaL_checkinteger(L, arg++); if (img->width <= 0) { return luaL_error(L, "width must be positive"); } if (nargs >= arg) { img->height = luaL_checkinteger(L, arg++); } else { img->height = img->width; } if (img->height <= 0) { return luaL_error(L, "height must be positive"); } img->format = AM_PIXEL_FORMAT_RGBA8; int required_size = img->width * img->height * pixel_format_size(img->format); if (img->buffer == NULL) { // create new buffer img->buffer = am_new_userdata(L, am_buffer, required_size); img->buffer_ref = img->ref(L, -1); lua_pop(L, 1); // pop buffer; } else { // check supplied buffer has correct size. if (required_size != img->buffer->size) { return luaL_error(L, "buffer has wrong size (%d, expecting %d)", img->buffer->size, required_size); } } return 1; }
static int decode_png(lua_State *L) { am_check_nargs(L, 1); am_buffer *buf = am_get_userdata(L, am_buffer, 1); int width, height; int components = 4; stbi_set_flip_vertically_on_load(1); stbi_uc *img_data = stbi_load_from_memory((stbi_uc const *)buf->data, buf->size, &width, &height, &components, 4); if (img_data == NULL) { return luaL_error(L, "error decoding image %s: %s", buf->origin, stbi_failure_reason()); } am_image_buffer *img = am_new_userdata(L, am_image_buffer); img->width = width; img->height = height; img->format = AM_PIXEL_FORMAT_RGBA8; int sz = width * height * pixel_format_size(img->format); am_buffer *imgbuf = am_new_userdata(L, am_buffer); imgbuf->size = sz; imgbuf->data = img_data; img->buffer = imgbuf; img->buffer_ref = img->ref(L, -1); lua_pop(L, 1); // pop imgbuf return 1; }
static void process_arguments_of_image_initialize(int const argc, VALUE* const argv, VALUE* buffer_ptr, rb_image_file_image_pixel_format_t* pixel_format_ptr, long* width_ptr, long* height_ptr, long* stride_ptr ) { VALUE params; VALUE buffer = Qnil; VALUE pixel_format = Qnil; VALUE width = Qnil; VALUE height = Qnil; VALUE stride = Qnil; rb_image_file_image_pixel_format_t pf; long wd, ht, st; long min_len; ID id_pixel_format, id_data, id_width, id_height, id_row_stride; CONST_ID(id_data, "data"); CONST_ID(id_pixel_format, "pixel_format"); CONST_ID(id_width, "width"); CONST_ID(id_height, "height"); CONST_ID(id_row_stride, "row_stride"); rb_scan_args(argc, argv, "01", ¶ms); if (TYPE(params) == T_HASH) { buffer = rb_hash_lookup(params, ID2SYM(id_data)); pixel_format = rb_hash_lookup(params, ID2SYM(id_pixel_format)); width = rb_hash_lookup(params, ID2SYM(id_width)); height = rb_hash_lookup(params, ID2SYM(id_height)); stride = rb_hash_lookup(params, ID2SYM(id_row_stride)); } if (!NIL_P(buffer)) { Check_Type(buffer, T_STRING); buffer = rb_str_dup(buffer); } if (NIL_P(pixel_format)) rb_raise(rb_eArgError, "missing image pixel format"); if (TYPE(pixel_format) == T_STRING) pixel_format = rb_str_intern(pixel_format); pf = check_pixel_format(pixel_format); if (NIL_P(width)) rb_raise(rb_eArgError, "missing image width"); wd = NUM2LONG(width); if (wd <= 0) rb_raise(rb_eArgError, "zero or negative image width"); if (NIL_P(height)) rb_raise(rb_eArgError, "missing image height"); ht = NUM2LONG(height); if (ht <= 0) rb_raise(rb_eArgError, "zero or negative image height"); if (NIL_P(stride)) { #ifdef HAVE_RB_CAIRO_H st = cairo_format_stride_for_width(pixel_format_to_cairo_format(pf), (int)wd) / pixel_format_size(pf); stride = INT2NUM(st); #else stride = width; #endif } st = NUM2LONG(stride); if (st <= 0) rb_raise(rb_eArgError, "zero or negative image row-stride"); else if (st < wd) { rb_warning("the given row-stride is less than the given image width."); st = wd; } min_len = minimum_buffer_size(pf, st, ht); if (NIL_P(buffer)) { buffer = rb_str_new(NULL, min_len); } else if (RSTRING_LEN(buffer) < min_len) { void rb_str_modify_expand(VALUE, long); rb_warning("the size of the given data is too short for the given size of image"); rb_str_modify_expand(buffer, min_len - RSTRING_LEN(buffer)); } *buffer_ptr = buffer; *pixel_format_ptr = pf; *width_ptr = wd; *height_ptr = ht; *stride_ptr = st; }