Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

DynamicGifStack is now async

  • Loading branch information...
commit 726cf388e03f3881be17fdfe2755b72a5ea7c44d 1 parent c962843
@pkrumins pkrumins authored
View
8 src/common.h
@@ -32,5 +32,13 @@ bool str_eq(const char *s1, const char *s2);
typedef enum { BUF_RGB, BUF_BGR, BUF_RGBA, BUF_BGRA } buffer_type;
+struct encode_request {
+ v8::Persistent<v8::Function> callback;
+ void *gif_obj;
+ char *gif;
+ int gif_len;
+ char *error;
+};
+
#endif
View
223 src/dynamic_gif_stack.cpp
@@ -6,7 +6,7 @@ using namespace v8;
using namespace node;
std::pair<Point, Point>
-DynamicGifStack::OptimalDimension()
+DynamicGifStack::optimal_dimension()
{
Point top(-1, -1), bottom(-1, -1);
for (GifUpdates::iterator it = gif_stack.begin(); it != gif_stack.end(); ++it) {
@@ -25,6 +25,51 @@ DynamicGifStack::OptimalDimension()
}
void
+DynamicGifStack::construct_gif_data(unsigned char *data, Point &top)
+{
+ switch (buf_type) {
+ case BUF_RGB:
+ case BUF_RGBA:
+ for (GifUpdates::iterator it = gif_stack.begin(); it != gif_stack.end(); ++it) {
+ GifUpdate *gif = *it;
+ int start = (gif->y - top.y)*width*3 + (gif->x - top.x)*3;
+ unsigned char *gifdatap = gif->data;
+ for (int i = 0; i < gif->h; i++) {
+ unsigned char *datap = &data[start + i*width*3];
+ for (int j = 0; j < gif->w; j++) {
+ *datap++ = *gifdatap++;
+ *datap++ = *gifdatap++;
+ *datap++ = *gifdatap++;
+ if (buf_type == BUF_RGBA) gifdatap++;
+ }
+ }
+ }
+ break;
+
+ case BUF_BGR:
+ case BUF_BGRA:
+ for (GifUpdates::iterator it = gif_stack.begin(); it != gif_stack.end(); ++it) {
+ GifUpdate *gif = *it;
+ int start = (gif->y - top.y)*width*3 + (gif->x - top.x)*3;
+ unsigned char *gifdatap = gif->data;
+ for (int i = 0; i < gif->h; i++) {
+ unsigned char *datap = &data[start + i*width*3];
+ for (int j = 0; j < gif->w; j++) {
+ *datap++ = *(gifdatap + 2);
+ *datap++ = *(gifdatap + 1);
+ *datap++ = *gifdatap;
+ gifdatap += (buf_type == BUF_BGRA) ? 4 : 3;
+ }
+ }
+ }
+ break;
+
+ default:
+ throw "Unexpected buf_type in DynamicGifStack::GifEncode";
+ }
+}
+
+void
DynamicGifStack::Initialize(Handle<Object> target)
{
HandleScope scope;
@@ -32,7 +77,8 @@ DynamicGifStack::Initialize(Handle<Object> target)
Local<FunctionTemplate> t = FunctionTemplate::New(New);
t->InstanceTemplate()->SetInternalFieldCount(1);
NODE_SET_PROTOTYPE_METHOD(t, "push", Push);
- NODE_SET_PROTOTYPE_METHOD(t, "encode", GifEncode);
+ NODE_SET_PROTOTYPE_METHOD(t, "encode", GifEncodeAsync);
+ NODE_SET_PROTOTYPE_METHOD(t, "encodeSync", GifEncodeSync);
NODE_SET_PROTOTYPE_METHOD(t, "dimensions", Dimensions);
target->Set(String::NewSymbol("DynamicGifStack"), t->GetFunction());
}
@@ -61,11 +107,11 @@ DynamicGifStack::Push(Buffer *buf, int x, int y, int w, int h)
}
Handle<Value>
-DynamicGifStack::GifEncode()
+DynamicGifStack::GifEncodeSync()
{
HandleScope scope;
- std::pair<Point, Point> optimal = OptimalDimension();
+ std::pair<Point, Point> optimal = optimal_dimension();
Point top = optimal.first, bot = optimal.second;
offset = top;
@@ -82,46 +128,7 @@ DynamicGifStack::GifEncode()
*datap++ = transparency_color.b;
}
- switch (buf_type) {
- case BUF_RGB:
- case BUF_RGBA:
- for (GifUpdates::iterator it = gif_stack.begin(); it != gif_stack.end(); ++it) {
- GifUpdate *gif = *it;
- int start = (gif->y - top.y)*width*3 + (gif->x - top.x)*3;
- unsigned char *gifdatap = gif->data;
- for (int i = 0; i < gif->h; i++) {
- unsigned char *datap = &data[start + i*width*3];
- for (int j = 0; j < gif->w; j++) {
- *datap++ = *gifdatap++;
- *datap++ = *gifdatap++;
- *datap++ = *gifdatap++;
- if (buf_type == BUF_RGBA) gifdatap++;
- }
- }
- }
- break;
-
- case BUF_BGR:
- case BUF_BGRA:
- for (GifUpdates::iterator it = gif_stack.begin(); it != gif_stack.end(); ++it) {
- GifUpdate *gif = *it;
- int start = (gif->y - top.y)*width*3 + (gif->x - top.x)*3;
- unsigned char *gifdatap = gif->data;
- for (int i = 0; i < gif->h; i++) {
- unsigned char *datap = &data[start + i*width*3];
- for (int j = 0; j < gif->w; j++) {
- *datap++ = *(gifdatap + 2);
- *datap++ = *(gifdatap + 1);
- *datap++ = *gifdatap;
- gifdatap += (buf_type == BUF_BGRA) ? 4 : 3;
- }
- }
- }
- break;
-
- default:
- throw "Unexpected buf_type in DynamicGifStack::GifEncode";
- }
+ construct_gif_data(data, top);
try {
GifEncoder gif_encoder(data, width, height, BUF_RGB);
@@ -230,11 +237,135 @@ DynamicGifStack::Dimensions(const Arguments &args)
}
Handle<Value>
-DynamicGifStack::GifEncode(const Arguments &args)
+DynamicGifStack::GifEncodeSync(const Arguments &args)
{
HandleScope scope;
DynamicGifStack *gif_stack = ObjectWrap::Unwrap<DynamicGifStack>(args.This());
- return scope.Close(gif_stack->GifEncode());
+ return scope.Close(gif_stack->GifEncodeSync());
+}
+
+int
+DynamicGifStack::EIO_GifEncode(eio_req *req)
+{
+ encode_request *enc_req = (encode_request *)req->data;
+ DynamicGifStack *gif = (DynamicGifStack *)enc_req->gif_obj;
+
+ std::pair<Point, Point> optimal = gif->optimal_dimension();
+ Point top = optimal.first, bot = optimal.second;
+
+ gif->offset = top;
+ gif->width = bot.x - top.x;
+ gif->height = bot.y - top.y;
+
+ unsigned char *data = (unsigned char*)malloc(sizeof(*data)*gif->width*gif->height*3);
+ if (!data) {
+ enc_req->error = strdup("malloc failed in DynamicGifStack::EIO_GifEncode.");
+ return 0;
+ }
+
+ unsigned char *datap = data;
+ for (int i = 0; i < gif->width*gif->height; i++) {
+ *datap++ = gif->transparency_color.r;
+ *datap++ = gif->transparency_color.g;
+ *datap++ = gif->transparency_color.b;
+ }
+
+ gif->construct_gif_data(data, top);
+
+ buffer_type pbt = (gif->buf_type == BUF_BGR || gif->buf_type == BUF_BGRA) ?
+ BUF_BGRA : BUF_RGBA;
+
+ try {
+ GifEncoder gif_encoder(data, gif->width, gif->height, BUF_RGB);
+ gif_encoder.set_transparency_color(gif->transparency_color);
+ gif_encoder.encode();
+ free(data);
+ enc_req->gif_len = gif_encoder.get_gif_len();
+ enc_req->gif = (char *)malloc(sizeof(*enc_req->gif)*enc_req->gif_len);
+ if (!enc_req->gif) {
+ enc_req->error = strdup("malloc in DynamicGifStack::EIO_GifEncode failed.");
+ return 0;
+ }
+ else {
+ memcpy(enc_req->gif, gif_encoder.get_gif(), enc_req->gif_len);
+ }
+ }
+ catch (const char *err) {
+ enc_req->error = strdup(err);
+ }
+
+ return 0;
+}
+
+int
+DynamicGifStack::EIO_GifEncodeAfter(eio_req *req)
+{
+ HandleScope scope;
+
+ ev_unref(EV_DEFAULT_UC);
+ encode_request *enc_req = (encode_request *)req->data;
+ DynamicGifStack *gif = (DynamicGifStack *)enc_req->gif_obj;
+
+ Handle<Value> argv[3];
+
+ if (enc_req->error) {
+ argv[0] = Undefined();
+ argv[1] = Undefined();
+ argv[2] = ErrorException(enc_req->error);
+ }
+ else {
+ argv[0] = Local<Value>::New(Encode(enc_req->gif, enc_req->gif_len, BINARY));
+ argv[1] = gif->Dimensions();
+ argv[2] = Undefined();
+ }
+
+ TryCatch try_catch; // don't quite see the necessity of this
+
+ enc_req->callback->Call(Context::GetCurrent()->Global(), 3, argv);
+
+ if (try_catch.HasCaught())
+ FatalException(try_catch);
+
+ enc_req->callback.Dispose();
+ free(enc_req->gif);
+ free(enc_req->error);
+
+ gif->Unref();
+ free(enc_req);
+
+ return 0;
+}
+
+Handle<Value>
+DynamicGifStack::GifEncodeAsync(const Arguments &args)
+{
+ HandleScope scope;
+
+ if (args.Length() != 1)
+ return VException("One argument required - callback function.");
+
+ if (!args[0]->IsFunction())
+ return VException("First argument must be a function.");
+
+ Local<Function> callback = Local<Function>::Cast(args[0]);
+ DynamicGifStack *gif = ObjectWrap::Unwrap<DynamicGifStack>(args.This());
+
+ encode_request *enc_req = (encode_request *)malloc(sizeof(*enc_req));
+ if (!enc_req)
+ return VException("malloc in DynamicGifStack::GifEncodeAsync failed.");
+
+ enc_req->callback = Persistent<Function>::New(callback);
+ enc_req->gif_obj = gif;
+ enc_req->gif = NULL;
+ enc_req->gif_len = 0;
+ enc_req->error = NULL;
+
+ eio_custom(EIO_GifEncode, EIO_PRI_DEFAULT, EIO_GifEncodeAfter, enc_req);
+
+ ev_ref(EV_DEFAULT_UC);
+ gif->Ref();
+
+ return Undefined();
}
View
11 src/dynamic_gif_stack.h
@@ -37,7 +37,11 @@ class DynamicGifStack : public node::ObjectWrap {
buffer_type buf_type;
Color transparency_color;
- std::pair<Point, Point> OptimalDimension();
+ std::pair<Point, Point> optimal_dimension();
+
+ static int EIO_GifEncode(eio_req *req);
+ static int EIO_GifEncodeAfter(eio_req *req);
+ void construct_gif_data(unsigned char *data, Point &top);
public:
static void Initialize(v8::Handle<v8::Object> target);
@@ -46,12 +50,13 @@ class DynamicGifStack : public node::ObjectWrap {
v8::Handle<v8::Value> Push(node::Buffer *buf, int x, int y, int w, int h);
v8::Handle<v8::Value> Dimensions();
- v8::Handle<v8::Value> GifEncode();
+ v8::Handle<v8::Value> GifEncodeSync();
static v8::Handle<v8::Value> New(const v8::Arguments &args);
static v8::Handle<v8::Value> Push(const v8::Arguments &args);
static v8::Handle<v8::Value> Dimensions(const v8::Arguments &args);
- static v8::Handle<v8::Value> GifEncode(const v8::Arguments &args);
+ static v8::Handle<v8::Value> GifEncodeSync(const v8::Arguments &args);
+ static v8::Handle<v8::Value> GifEncodeAsync(const v8::Arguments &args);
};
#endif
View
8 src/gif.cpp
@@ -135,14 +135,6 @@ Gif::SetTransparencyColor(const Arguments &args)
return Undefined();
}
-struct encode_request {
- v8::Persistent<v8::Function> callback;
- void *gif_obj;
- char *gif;
- int gif_len;
- char *error;
-};
-
int
Gif::EIO_GifEncode(eio_req *req)
{
View
31 tests/dynamic-gif-stack-async.js
@@ -0,0 +1,31 @@
+var GifLib = require('gif');
+var fs = require('fs');
+var sys = require('sys');
+var Buffer = require('buffer').Buffer;
+
+var gifStack = new GifLib.DynamicGifStack('rgba');
+//gifStack.setTransparencyColor(0x00, 0x00, 0x00);
+
+function rectDim(fileName) {
+ var m = fileName.match(/^\d+-rgba-(\d+)-(\d+)-(\d+)-(\d+).dat$/);
+ var dim = [m[1], m[2], m[3], m[4]].map(function (n) {
+ return parseInt(n, 10);
+ });
+ return { x: dim[0], y: dim[1], w: dim[2], h: dim[3] }
+}
+
+var files = fs.readdirSync('./push-data');
+
+files.forEach(function(file) {
+ var dim = rectDim(file);
+ var rgba = fs.readFileSync('./push-data/' + file);
+ gifStack.push(rgba, dim.x, dim.y, dim.w, dim.h);
+});
+
+gifStack.encode(function (data, dims) {
+ fs.writeFileSync('dynamic-async.gif', data, 'binary');
+
+ sys.log("GIF located at (" + dims.x + "," + dims.y + ") with width " +
+ dims.width + " and height " + dims.height);
+});
+
View
2  tests/dynamic-gif-stack.js
@@ -22,7 +22,7 @@ files.forEach(function(file) {
gifStack.push(rgba, dim.x, dim.y, dim.w, dim.h);
});
-fs.writeFileSync('dynamic.gif', gifStack.encode(), 'binary');
+fs.writeFileSync('dynamic.gif', gifStack.encodeSync(), 'binary');
var dims = gifStack.dimensions();
Please sign in to comment.
Something went wrong with that request. Please try again.