Browse Source

Merge branch 'putImageData'

v1.x
Tj Holowaychuk 14 years ago
parent
commit
4f2a97bf26
  1. 88
      src/CanvasRenderingContext2d.cc
  2. 1
      src/CanvasRenderingContext2d.h
  3. 29
      src/PixelArray.cc
  4. 75
      test/public/tests.js

88
src/CanvasRenderingContext2d.cc

@ -10,6 +10,7 @@
#include <stdlib.h>
#include "Canvas.h"
#include "Image.h"
#include "ImageData.h"
#include "CanvasRenderingContext2d.h"
#include "CanvasGradient.h"
@ -65,6 +66,7 @@ Context2d::Initialize(Handle<Object> target) {
// Prototype
Local<ObjectTemplate> proto = t->PrototypeTemplate();
NODE_SET_PROTOTYPE_METHOD(t, "drawImage", DrawImage);
NODE_SET_PROTOTYPE_METHOD(t, "putImageData", PutImageData);
NODE_SET_PROTOTYPE_METHOD(t, "save", Save);
NODE_SET_PROTOTYPE_METHOD(t, "restore", Restore);
NODE_SET_PROTOTYPE_METHOD(t, "rotate", Rotate);
@ -381,6 +383,92 @@ Context2d::New(const Arguments &args) {
return args.This();
}
/*
* Put image data.
*
* - imageData, dx, dy
* - imageData, dx, dy, sx, sy, dw, dh
*
*/
Handle<Value>
Context2d::PutImageData(const Arguments &args) {
HandleScope scope;
// TODO: validate
Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This());
ImageData *imageData = ObjectWrap::Unwrap<ImageData>(args[0]->ToObject());
PixelArray *arr = imageData->pixelArray();
uint8_t *src = arr->data();
uint8_t *dst = context->canvas()->data();
int srcStride = arr->stride()
, dstStride = context->canvas()->stride();
int sx = 0
, sy = 0
, sw = 0
, sh = 0
, dx = args[1]->NumberValue()
, dy = args[2]->NumberValue()
, rows
, cols;
// TODO: spec boundaries
switch (args.Length()) {
// imageData, dx, dy
case 3:
cols = arr->width();
rows = arr->height();
break;
// imageData, dx, dy, sx, sy, dw, dh
case 7: {
sx = args[3]->NumberValue();
sy = args[4]->NumberValue();
sw = args[5]->NumberValue();
sh = args[6]->NumberValue();
cols = sw;
rows = sh;
dx += sx;
dy += sy;
}
break;
default:
return ThrowException(Exception::Error(String::New("invalid arguments")));
}
uint8_t *srcRows = src + sy * srcStride + sx * 4;
for (int y = 0; y < rows; ++y) {
uint32_t *row = (uint32_t *)(dst + dstStride * (y + dy));
for (int x = 0; x < cols; ++x) {
int bx = x * 4;
uint32_t *pixel = row + x + dx;
// RGBA
uint8_t a = srcRows[bx + 3];
uint8_t r = srcRows[bx + 0];
uint8_t g = srcRows[bx + 1];
uint8_t b = srcRows[bx + 2];
// ARGB
*pixel = a << 24
| r << 16
| g << 8
| b;
}
srcRows += srcStride;
}
cairo_surface_mark_dirty_rectangle(
context->canvas()->surface()
, dx
, dy
, cols
, rows);
return Undefined();
}
/*
* Draw image src image to the destination (context).
*

1
src/CanvasRenderingContext2d.h

@ -48,6 +48,7 @@ class Context2d: public node::ObjectWrap {
static void Initialize(Handle<Object> target);
static Handle<Value> New(const Arguments &args);
static Handle<Value> DrawImage(const Arguments &args);
static Handle<Value> PutImageData(const Arguments &args);
static Handle<Value> Save(const Arguments &args);
static Handle<Value> Restore(const Arguments &args);
static Handle<Value> Rotate(const Arguments &args);

29
src/PixelArray.cc

@ -85,23 +85,36 @@ PixelArray::PixelArray(Canvas *canvas, int sx, int sy, int width, int height):
// Alloc space for our new data
uint8_t *dst = alloc();
uint8_t *src = canvas->data();
int s = stride();
int srcStride = canvas->stride()
, dstStride = stride();
// Normalize data (argb -> rgba)
for (int y = 0; y < height; ++y) {
uint32_t *row = (uint32_t *)(src + s * y);
uint32_t *row = (uint32_t *)(src + srcStride * (y + sy));
for (int x = 0; x < width; ++x) {
int bx = x * 4;
uint32_t *pixel = row + x;
uint32_t *pixel = row + x + sx;
// premultiplied
// ARGB
uint8_t a = *pixel >> 24;
uint8_t r = *pixel >> 16;
uint8_t g = *pixel >> 8;
uint8_t b = *pixel;
// undo premultiplication
dst[bx + 3] = a;
dst[bx + 0] = (*pixel >> 16) * 255 / a;
dst[bx + 1] = (*pixel >> 8) * 255 / a;
dst[bx + 2] = *pixel * 255 / a;
// TODO: abstract
if (a) {
dst[bx + 0] = r * 255 / a;
dst[bx + 1] = g * 255 / a;
dst[bx + 2] = b * 255 / a;
} else {
dst[bx + 0] = r;
dst[bx + 1] = g;
dst[bx + 2] = b;
}
}
dst += s;
dst += dstStride;
}
}

75
test/public/tests.js

@ -1440,4 +1440,79 @@ tests['drawImage(img,sx,sy,sw,sh,x,y,w,h)'] = function(ctx, done){
done();
};
img.src = 'state.png';
};
tests['putImageData()'] = function(ctx){
for (i=0;i<6;i++){
for (j=0;j<6;j++){
ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' +
Math.floor(255-42.5*j) + ',0)';
ctx.fillRect(j*25,i*25,25,25);
}
}
var data = ctx.getImageData(0,0,50,50);
ctx.putImageData(data,10,10);
};
tests['putImageData() 2'] = function(ctx){
for (i=0;i<6;i++){
for (j=0;j<6;j++){
ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' +
Math.floor(255-42.5*j) + ',0)';
ctx.fillRect(j*25,i*25,25,25);
}
}
var data = ctx.getImageData(25,25,50,50);
ctx.putImageData(data,10,10);
};
tests['putImageData() 3'] = function(ctx){
for (i=0;i<6;i++){
for (j=0;j<6;j++){
ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' +
Math.floor(255-42.5*j) + ',0)';
ctx.fillRect(j*25,i*25,25,25);
}
}
var data = ctx.getImageData(10,25,10,50);
ctx.putImageData(data,50,10);
};
tests['putImageData() 4'] = function(ctx){
for (i=0;i<6;i++){
for (j=0;j<6;j++){
ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' +
Math.floor(255-42.5*j) + ',0)';
ctx.fillRect(j*25,i*25,25,25);
}
}
ctx.strokeRect(30,30,30,30);
var data = ctx.getImageData(0,0,50,50);
ctx.putImageData(data,30,30,10,10,30,30);
};
tests['putImageData() 5'] = function(ctx){
for (i=0;i<6;i++){
for (j=0;j<6;j++){
ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' +
Math.floor(255-42.5*j) + ',0)';
ctx.fillRect(j*25,i*25,25,25);
}
}
ctx.strokeRect(60,60,50,30);
var data = ctx.getImageData(0,0,50,50);
ctx.putImageData(data,60,60,0,0,50,30);
};
tests['putImageData() 6'] = function(ctx){
for (i=0;i<6;i++){
for (j=0;j<6;j++){
ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' +
Math.floor(255-42.5*j) + ',0)';
ctx.fillRect(j*25,i*25,25,25);
}
}
ctx.strokeRect(60,60,50,30);
var data = ctx.getImageData(0,0,50,50);
ctx.putImageData(data,60,60,10,0,35,30);
};
Loading…
Cancel
Save