7 changed files with 376 additions and 0 deletions
@ -0,0 +1 @@ |
|||
module.exports = require('./lib/canvas'); |
@ -0,0 +1,267 @@ |
|||
|
|||
//
|
|||
// Image.cc
|
|||
//
|
|||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
|||
//
|
|||
|
|||
#include "Canvas.h" |
|||
#include "Image.h" |
|||
|
|||
/*
|
|||
* Initialize Image. |
|||
*/ |
|||
|
|||
void |
|||
Image::Initialize(Handle<Object> target) { |
|||
HandleScope scope; |
|||
Local<FunctionTemplate> t = FunctionTemplate::New(Image::New); |
|||
t->InstanceTemplate()->SetInternalFieldCount(1); |
|||
t->SetClassName(String::NewSymbol("Image")); |
|||
|
|||
Local<ObjectTemplate> proto = t->PrototypeTemplate(); |
|||
NODE_SET_PROTOTYPE_METHOD(t, "inspect", Inspect); |
|||
proto->SetAccessor(String::NewSymbol("src"), GetSrc, SetSrc); |
|||
proto->SetAccessor(String::NewSymbol("complete"), GetComplete); |
|||
proto->SetAccessor(String::NewSymbol("width"), GetWidth); |
|||
proto->SetAccessor(String::NewSymbol("height"), GetHeight); |
|||
proto->SetAccessor(String::NewSymbol("onload"), GetOnload, SetOnload); |
|||
proto->SetAccessor(String::NewSymbol("onerror"), GetOnerror, SetOnerror); |
|||
target->Set(String::NewSymbol("Image"), t->GetFunction()); |
|||
} |
|||
|
|||
/*
|
|||
* Initialize a new Image. |
|||
*/ |
|||
|
|||
Handle<Value> |
|||
Image::New(const Arguments &args) { |
|||
HandleScope scope; |
|||
Image *img = new Image; |
|||
img->Wrap(args.This()); |
|||
return args.This(); |
|||
} |
|||
|
|||
/*
|
|||
* Custom inspect. |
|||
*/ |
|||
|
|||
Handle<Value> |
|||
Image::Inspect(const Arguments &args) { |
|||
HandleScope scope; |
|||
Image *img = ObjectWrap::Unwrap<Image>(args.This()); |
|||
Local<String> str = String::New("[Image"); |
|||
if (img->filename) { |
|||
str = String::Concat(str, String::New(" ")); |
|||
str = String::Concat(str, String::New(img->filename)); |
|||
} |
|||
str = String::Concat(str, String::New("]")); |
|||
return scope.Close(str); |
|||
} |
|||
|
|||
/*
|
|||
* Get complete boolean. |
|||
*/ |
|||
|
|||
Handle<Value> |
|||
Image::GetComplete(Local<String>, const AccessorInfo &info) { |
|||
Image *img = ObjectWrap::Unwrap<Image>(info.This()); |
|||
return Boolean::New(img->complete); |
|||
} |
|||
|
|||
/*
|
|||
* Get width. |
|||
*/ |
|||
|
|||
Handle<Value> |
|||
Image::GetWidth(Local<String>, const AccessorInfo &info) { |
|||
Image *img = ObjectWrap::Unwrap<Image>(info.This()); |
|||
return Number::New(img->width); |
|||
} |
|||
|
|||
/*
|
|||
* Get height. |
|||
*/ |
|||
|
|||
Handle<Value> |
|||
Image::GetHeight(Local<String>, const AccessorInfo &info) { |
|||
Image *img = ObjectWrap::Unwrap<Image>(info.This()); |
|||
return Number::New(img->height); |
|||
} |
|||
|
|||
/*
|
|||
* Get src path. |
|||
*/ |
|||
|
|||
Handle<Value> |
|||
Image::GetSrc(Local<String>, const AccessorInfo &info) { |
|||
Image *img = ObjectWrap::Unwrap<Image>(info.This()); |
|||
return String::New(img->filename); |
|||
} |
|||
|
|||
/*
|
|||
* Set src path. |
|||
*/ |
|||
|
|||
void |
|||
Image::SetSrc(Local<String>, Local<Value> val, const AccessorInfo &info) { |
|||
if (val->IsString()) { |
|||
String::AsciiValue src(val); |
|||
Image *img = ObjectWrap::Unwrap<Image>(info.This()); |
|||
img->filename = *src; |
|||
img->load(); |
|||
} |
|||
} |
|||
|
|||
/*
|
|||
* Get onload callback. |
|||
*/ |
|||
|
|||
Handle<Value> |
|||
Image::GetOnload(Local<String>, const AccessorInfo &info) { |
|||
Image *img = ObjectWrap::Unwrap<Image>(info.This()); |
|||
return img->onload; |
|||
} |
|||
|
|||
/*
|
|||
* Set onload callback. |
|||
*/ |
|||
|
|||
void |
|||
Image::SetOnload(Local<String>, Local<Value> val, const AccessorInfo &info) { |
|||
if (val->IsFunction()) { |
|||
Image *img = ObjectWrap::Unwrap<Image>(info.This()); |
|||
img->onload = Persistent<Function>::New(Handle<Function>::Cast(val)); |
|||
} |
|||
} |
|||
|
|||
/*
|
|||
* Get onerror callback. |
|||
*/ |
|||
|
|||
Handle<Value> |
|||
Image::GetOnerror(Local<String>, const AccessorInfo &info) { |
|||
Image *img = ObjectWrap::Unwrap<Image>(info.This()); |
|||
return img->onerror; |
|||
} |
|||
|
|||
/*
|
|||
* Set onerror callback. |
|||
*/ |
|||
|
|||
void |
|||
Image::SetOnerror(Local<String>, Local<Value> val, const AccessorInfo &info) { |
|||
if (val->IsFunction()) { |
|||
Image *img = ObjectWrap::Unwrap<Image>(info.This()); |
|||
img->onerror = Persistent<Function>::New(Handle<Function>::Cast(val)); |
|||
} |
|||
} |
|||
|
|||
/*
|
|||
* Initialize a new Image. |
|||
*/ |
|||
|
|||
Image::Image() { |
|||
complete = false; |
|||
filename = NULL; |
|||
_surface = NULL; |
|||
} |
|||
|
|||
/*
|
|||
* Destroy image and associated surface. |
|||
*/ |
|||
|
|||
Image::~Image() { |
|||
if (_surface) cairo_surface_destroy(_surface); |
|||
} |
|||
|
|||
/*
|
|||
* Load callback. |
|||
*/ |
|||
|
|||
static int |
|||
EIO_Load(eio_req *req) { |
|||
Image *img = (Image *) req->data; |
|||
req->result = img->loadSurface(); |
|||
return 0; |
|||
} |
|||
|
|||
/*
|
|||
* After load callback. |
|||
*/ |
|||
|
|||
static int |
|||
EIO_AfterLoad(eio_req *req) { |
|||
HandleScope scope; |
|||
Image *img = (Image *) req->data; |
|||
|
|||
if (req->result) { |
|||
img->error(Canvas::Error((cairo_status_t) req->result)); |
|||
} else { |
|||
img->loaded(); |
|||
} |
|||
|
|||
ev_unref(EV_DEFAULT_UC); |
|||
return 0; |
|||
} |
|||
|
|||
/*
|
|||
* Initiate image loading. |
|||
*/ |
|||
|
|||
void |
|||
Image::load() { |
|||
Ref(); |
|||
complete = false; |
|||
eio_custom(EIO_Load, EIO_PRI_DEFAULT, EIO_AfterLoad, this); |
|||
ev_ref(EV_DEFAULT_UC); |
|||
} |
|||
|
|||
/*
|
|||
* Invoke onload (when assigned) and assign dimensions. |
|||
*/ |
|||
|
|||
void |
|||
Image::loaded() { |
|||
HandleScope scope; |
|||
complete = true; |
|||
|
|||
if (!onload.IsEmpty()) { |
|||
TryCatch try_catch; |
|||
onload->Call(Context::GetCurrent()->Global(), 0, NULL); |
|||
onload.Dispose(); |
|||
if (try_catch.HasCaught()) { |
|||
error(try_catch.Exception()); |
|||
} |
|||
} |
|||
|
|||
Unref(); |
|||
} |
|||
|
|||
/*
|
|||
* Invoke onerror (when assigned) with the given err. |
|||
*/ |
|||
|
|||
void |
|||
Image::error(Local<Value> err) { |
|||
HandleScope scope; |
|||
// TODO: handle exception in onerror segfault
|
|||
if (!onerror.IsEmpty()) { |
|||
Local<Value> argv[1] = { err }; |
|||
onerror->Call(Context::GetCurrent()->Global(), 1, argv); |
|||
} |
|||
} |
|||
|
|||
/*
|
|||
* Load cairo surface from the image src. |
|||
* |
|||
* TODO: support more formats |
|||
*/ |
|||
|
|||
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); |
|||
} |
@ -0,0 +1,46 @@ |
|||
|
|||
//
|
|||
// Image.h
|
|||
//
|
|||
// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
|
|||
//
|
|||
|
|||
#ifndef __NODE_IMAGE_H__ |
|||
#define __NODE_IMAGE_H__ |
|||
|
|||
#include "canvas.h" |
|||
|
|||
using namespace v8; |
|||
|
|||
class Image: public node::ObjectWrap { |
|||
public: |
|||
bool complete; |
|||
char *filename; |
|||
int width, height; |
|||
Persistent<Function> onload; |
|||
Persistent<Function> onerror; |
|||
static void Initialize(Handle<Object> target); |
|||
static Handle<Value> New(const Arguments &args); |
|||
static Handle<Value> Inspect(const Arguments &args); |
|||
static Handle<Value> GetSrc(Local<String> prop, const AccessorInfo &info); |
|||
static Handle<Value> GetOnload(Local<String> prop, const AccessorInfo &info); |
|||
static Handle<Value> GetOnerror(Local<String> prop, const AccessorInfo &info); |
|||
static Handle<Value> GetComplete(Local<String> prop, const AccessorInfo &info); |
|||
static Handle<Value> GetWidth(Local<String> prop, const AccessorInfo &info); |
|||
static Handle<Value> GetHeight(Local<String> prop, const AccessorInfo &info); |
|||
static void SetSrc(Local<String> prop, Local<Value> val, const AccessorInfo &info); |
|||
static void SetOnload(Local<String> prop, Local<Value> val, const AccessorInfo &info); |
|||
static void SetOnerror(Local<String> prop, Local<Value> val, const AccessorInfo &info); |
|||
inline cairo_surface_t *surface(){ return _surface; } |
|||
cairo_status_t loadSurface(); |
|||
void error(Local<Value>); |
|||
void loaded(); |
|||
void load(); |
|||
Image(); |
|||
|
|||
private: |
|||
cairo_surface_t *_surface; |
|||
~Image(); |
|||
}; |
|||
|
|||
#endif |
After Width: | Height: | Size: 30 KiB |
@ -0,0 +1,58 @@ |
|||
|
|||
/** |
|||
* Module dependencies. |
|||
*/ |
|||
|
|||
var Canvas = require('canvas') |
|||
, Image = Canvas.Image; |
|||
|
|||
var png = __dirname + '/fixtures/clock.png'; |
|||
|
|||
module.exports = { |
|||
'tset Image': function(assert){ |
|||
assert.ok(Image instanceof Function); |
|||
}, |
|||
|
|||
'test Image#onload': function(assert, beforeExit){ |
|||
var img = new Image |
|||
, n = 0; |
|||
|
|||
assert.strictEqual(false, img.complete); |
|||
img.onload = function(){ |
|||
++n; |
|||
}; |
|||
|
|||
img.src = png; |
|||
assert.equal(img.src, png); |
|||
|
|||
beforeExit(function(){ |
|||
assert.strictEqual(true, img.complete); |
|||
assert.strictEqual(320, img.width); |
|||
assert.strictEqual(320, img.height); |
|||
assert.equal(1, n); |
|||
}); |
|||
}, |
|||
|
|||
'test Image#onerror': function(assert, beforeExit){ |
|||
var img = new Image |
|||
, n = 0; |
|||
|
|||
assert.strictEqual(false, img.complete); |
|||
img.onload = function(){ |
|||
assert.fail('called onload'); |
|||
}; |
|||
|
|||
img.onerror = function(err){ |
|||
++n; |
|||
assert.strictEqual(false, img.complete); |
|||
assert.ok(err instanceof Error, 'did not invoke onerror() with error'); |
|||
}; |
|||
|
|||
img.src = png + 's'; |
|||
assert.equal(img.src, png + 's'); |
|||
|
|||
beforeExit(function(){ |
|||
assert.equal(1, n); |
|||
}); |
|||
} |
|||
}; |
Loading…
Reference in new issue