From a409babc5d259b7aa138eaf29a68365923dce8ea Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk <tj@vision-media.ca> Date: Wed, 17 Nov 2010 13:57:51 -0800 Subject: [PATCH 1/9] Added Image::extension() --- src/Image.cc | 16 ++++++++++++++++ src/Image.h | 8 ++++++++ 2 files changed, 24 insertions(+) diff --git a/src/Image.cc b/src/Image.cc index 7e6315f..2b1a122 100644 --- a/src/Image.cc +++ b/src/Image.cc @@ -9,6 +9,7 @@ #include "Image.h" #include <stdlib.h> #include <string.h> +#include <jpeglib.h> Persistent<FunctionTemplate> Image::constructor; @@ -202,6 +203,7 @@ EIO_AfterLoad(eio_req *req) { void Image::load() { + printf("%d\n", extension(filename)); if (LOADING != state) { // TODO: use node IO // Ref(); @@ -273,4 +275,18 @@ Image::loadSurface() { width = cairo_image_surface_get_width(_surface); height = cairo_image_surface_get_height(_surface); 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; } \ No newline at end of file diff --git a/src/Image.h b/src/Image.h index e1b7c57..5034247 100644 --- a/src/Image.h +++ b/src/Image.h @@ -43,6 +43,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; From 2c5ebd3d8200d40ade9f97c9a9e67fe317739c1f Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk <tj@vision-media.ca> Date: Wed, 17 Nov 2010 14:54:43 -0800 Subject: [PATCH 2/9] Work on jpeg loading --- src/Image.cc | 61 ++++++++++++++++++++++++++++++++++++++++++++++------ wscript | 3 ++- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/src/Image.cc b/src/Image.cc index 2b1a122..8338469 100644 --- a/src/Image.cc +++ b/src/Image.cc @@ -203,7 +203,6 @@ EIO_AfterLoad(eio_req *req) { void Image::load() { - printf("%d\n", extension(filename)); if (LOADING != state) { // TODO: use node IO // Ref(); @@ -271,10 +270,60 @@ Image::error(Local<Value> err) { cairo_status_t Image::loadSurface() { - _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); + switch (extension(filename)) { + case Image::PNG: + _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); + break; + case Image::JPEG: { + // 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; + + 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 + (width * 4)); + for (int x = 0; x < width; ++x) { + uint32_t *pixel = row + x; + uint8_t r = src[x]; + uint8_t g = src[x + 1]; + uint8_t b = src[x + 2]; + *pixel = 255 << 24 + | r << 16 + | g << 8 + | b; + } + } + + _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); + } + break; + } + return CAIRO_STATUS_READ_ERROR; } /* @@ -289,4 +338,4 @@ Image::extension(const char *filename) { if (0 == strcmp(".jpg", filename - 4)) return Image::JPEG; if (0 == strcmp(".png", filename - 4)) return Image::PNG; return Image::UNKNOWN; -} \ No newline at end of file +} 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 From 0b227bd1e6b7c9ddd27961a9077b3c41ef291caf Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk <tj@vision-media.ca> Date: Wed, 17 Nov 2010 15:13:38 -0800 Subject: [PATCH 3/9] Todo --- src/Image.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Image.cc b/src/Image.cc index 8338469..23da356 100644 --- a/src/Image.cc +++ b/src/Image.cc @@ -265,6 +265,7 @@ Image::error(Local<Value> err) { /* * Load cairo surface from the image src. * + * TODO: better format resolution * TODO: support more formats */ From bc39108143ef57b186ef40c83697f5e39d0aedbb Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk <tj@vision-media.ca> Date: Wed, 17 Nov 2010 15:21:06 -0800 Subject: [PATCH 4/9] Misc refactoring --- src/Image.cc | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/Image.cc b/src/Image.cc index 23da356..6e31e7a 100644 --- a/src/Image.cc +++ b/src/Image.cc @@ -300,16 +300,13 @@ Image::loadSurface() { uint32_t *row = (uint32_t *)(data + (width * 4)); for (int x = 0; x < width; ++x) { uint32_t *pixel = row + x; - uint8_t r = src[x]; - uint8_t g = src[x + 1]; - uint8_t b = src[x + 2]; *pixel = 255 << 24 - | r << 16 - | g << 8 - | b; + | src[x + 0] << 16 + | src[x + 1] << 8 + | src[x + 2]; } } - + _surface = cairo_image_surface_create_for_data( data , CAIRO_FORMAT_ARGB32 From c9c6955c91f5ac4b716807123a22e7e44ed70011 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk <tj@vision-media.ca> Date: Thu, 18 Nov 2010 09:17:19 -0800 Subject: [PATCH 5/9] stride --- src/Image.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Image.cc b/src/Image.cc index 6e31e7a..eb6f164 100644 --- a/src/Image.cc +++ b/src/Image.cc @@ -292,12 +292,13 @@ Image::loadSurface() { 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 + (width * 4)); + uint32_t *row = (uint32_t *)(data + stride * y); for (int x = 0; x < width; ++x) { uint32_t *pixel = row + x; *pixel = 255 << 24 From 3c747204fad3686982af6170df1f4942dbf3f25a Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk <tj@vision-media.ca> Date: Thu, 18 Nov 2010 09:27:13 -0800 Subject: [PATCH 6/9] Fixed jpeg loading --- src/Image.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Image.cc b/src/Image.cc index eb6f164..3fe99c0 100644 --- a/src/Image.cc +++ b/src/Image.cc @@ -302,9 +302,9 @@ Image::loadSurface() { for (int x = 0; x < width; ++x) { uint32_t *pixel = row + x; *pixel = 255 << 24 - | src[x + 0] << 16 - | src[x + 1] << 8 - | src[x + 2]; + | src[3 * x + 0] << 16 + | src[3 * x + 1] << 8 + | src[3 * x + 2]; } } @@ -314,7 +314,7 @@ Image::loadSurface() { , width , height , width * 4); - +cairo_surface_write_to_png(_surface, "test2.png"); fclose(stream); jpeg_finish_decompress(&info); jpeg_destroy_decompress(&info); From dfa5d630ab2048d8635cf75822d7da9ac1199bbe Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk <tj@vision-media.ca> Date: Thu, 18 Nov 2010 09:31:06 -0800 Subject: [PATCH 7/9] bx --- src/Image.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Image.cc b/src/Image.cc index 3fe99c0..0c289f6 100644 --- a/src/Image.cc +++ b/src/Image.cc @@ -300,11 +300,12 @@ Image::loadSurface() { 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[3 * x + 0] << 16 - | src[3 * x + 1] << 8 - | src[3 * x + 2]; + | src[bx + 0] << 16 + | src[bx + 1] << 8 + | src[bx + 2]; } } From 8b64b12f56b0a2e9a9f88953d1a9ef47c6d58be1 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk <tj@vision-media.ca> Date: Thu, 18 Nov 2010 09:38:20 -0800 Subject: [PATCH 8/9] Added width x height to Image#inspect() --- lib/image.js | 1 + src/Image.cc | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) 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 0c289f6..df4d392 100644 --- a/src/Image.cc +++ b/src/Image.cc @@ -315,7 +315,7 @@ Image::loadSurface() { , width , height , width * 4); -cairo_surface_write_to_png(_surface, "test2.png"); + fclose(stream); jpeg_finish_decompress(&info); jpeg_destroy_decompress(&info); From 41b08746ebb90dff269a5dd53c2423c675a37569 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk <tj@vision-media.ca> Date: Thu, 18 Nov 2010 10:13:47 -0800 Subject: [PATCH 9/9] Added Image::loadJPEG() and Image::loadPNG() --- src/Image.cc | 115 ++++++++++++++++++++++++++++----------------------- src/Image.h | 2 + 2 files changed, 66 insertions(+), 51 deletions(-) diff --git a/src/Image.cc b/src/Image.cc index df4d392..80a218f 100644 --- a/src/Image.cc +++ b/src/Image.cc @@ -265,67 +265,80 @@ Image::error(Local<Value> err) { /* * Load cairo surface from the image src. * - * TODO: better format resolution + * TODO: better format detection * TODO: support more formats */ cairo_status_t Image::loadSurface() { switch (extension(filename)) { - case Image::PNG: - _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); - break; - case Image::JPEG: { - // 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); - } - break; + 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); +} + +/* + * 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. */ diff --git a/src/Image.h b/src/Image.h index 5034247..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<Value>); void loadSync(); void loaded();