diff --git a/lib/image.js b/lib/image.js index be0658b..231d6be 100644 --- a/lib/image.js +++ b/lib/image.js @@ -21,6 +21,7 @@ var Canvas = require('../build/default/canvas') Image.prototype.inspect = function(){ return '[Image' + + (this.complete ? ':' + this.width + 'x' + this.height : '') + (this.src ? ' ' + this.src : '') + (this.complete ? ' complete' : '') + ']'; diff --git a/src/Image.cc b/src/Image.cc index 7e6315f..80a218f 100644 --- a/src/Image.cc +++ b/src/Image.cc @@ -9,6 +9,7 @@ #include "Image.h" #include #include +#include Persistent Image::constructor; @@ -264,13 +265,90 @@ Image::error(Local err) { /* * Load cairo surface from the image src. * + * TODO: better format detection * TODO: support more formats */ cairo_status_t Image::loadSurface() { + switch (extension(filename)) { + case Image::PNG: return loadPNG(); + case Image::JPEG: return loadJPEG(); + } + return CAIRO_STATUS_READ_ERROR; +} + +/* + * Load PNG. + */ + +cairo_status_t +Image::loadPNG() { _surface = cairo_image_surface_create_from_png(filename); width = cairo_image_surface_get_width(_surface); height = cairo_image_surface_get_height(_surface); return cairo_surface_status(_surface); -} \ No newline at end of file +} + +/* + * Load JPEG, convert RGB to ARGB. + */ + +cairo_status_t +Image::loadJPEG() { + // TODO: error handling + // TODO: move to node IO + FILE *stream = fopen(filename, "r"); + struct jpeg_decompress_struct info; + struct jpeg_error_mgr err; + info.err = jpeg_std_error(&err); + jpeg_create_decompress(&info); + jpeg_stdio_src(&info, stream); + jpeg_read_header(&info, 1); + jpeg_start_decompress(&info); + width = info.output_width; + height = info.output_height; + + int stride = width * 4; + uint8_t *data = (uint8_t *) malloc(width * height * 4); + uint8_t *src = (uint8_t *) malloc(width * 3); + + for (int y = 0; y < height; ++y) { + jpeg_read_scanlines(&info, &src, 1); + uint32_t *row = (uint32_t *)(data + stride * y); + for (int x = 0; x < width; ++x) { + int bx = 3 * x; + uint32_t *pixel = row + x; + *pixel = 255 << 24 + | src[bx + 0] << 16 + | src[bx + 1] << 8 + | src[bx + 2]; + } + } + + _surface = cairo_image_surface_create_for_data( + data + , CAIRO_FORMAT_ARGB32 + , width + , height + , width * 4); + + fclose(stream); + jpeg_finish_decompress(&info); + jpeg_destroy_decompress(&info); + return cairo_surface_status(_surface); +} + +/* + * Return UNKNOWN, JPEG, or PNG based on the filename. + */ + +Image::type +Image::extension(const char *filename) { + size_t len = strlen(filename); + filename += len; + if (0 == strcmp(".jpeg", filename - 5)) return Image::JPEG; + if (0 == strcmp(".jpg", filename - 4)) return Image::JPEG; + if (0 == strcmp(".png", filename - 4)) return Image::PNG; + return Image::UNKNOWN; +} diff --git a/src/Image.h b/src/Image.h index e1b7c57..06035aa 100644 --- a/src/Image.h +++ b/src/Image.h @@ -32,6 +32,8 @@ class Image: public node::ObjectWrap { inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); } inline int stride(){ return cairo_image_surface_get_stride(_surface); } cairo_status_t loadSurface(); + cairo_status_t loadPNG(); + cairo_status_t loadJPEG(); void error(Local); void loadSync(); void loaded(); @@ -43,6 +45,14 @@ class Image: public node::ObjectWrap { , LOADING , COMPLETE } state; + + typedef enum { + UNKNOWN + , JPEG + , PNG + } type; + + static type extension(const char *filename); private: cairo_surface_t *_surface; diff --git a/wscript b/wscript index 1469995..96b614a 100644 --- a/wscript +++ b/wscript @@ -11,6 +11,7 @@ def configure(conf): conf.check_tool('compiler_cxx') conf.check_tool('node_addon') conf.env.append_value('CPPFLAGS', '-DNDEBUG') + conf.check(lib='jpeg', uselib_store='JPEG') conf.check_cfg(package='cairo', mandatory=1, args='--cflags --libs') flags = ['-O3', '-Wall'] conf.env.append_value('CCFLAGS', flags) @@ -20,4 +21,4 @@ def build(bld): obj = bld.new_task_gen('cxx', 'shlib', 'node_addon') obj.target = 'canvas' obj.source = bld.glob('src/*.cc') - obj.uselib = ['CAIRO'] \ No newline at end of file + obj.uselib = ['CAIRO', 'JPEG'] \ No newline at end of file