Skip to content

Commit cf5e5c4

Browse files
committed
Merge pull request #569 from targos/expose-imagedata
expose ImageData constructor
2 parents 2fc1316 + 2884267 commit cf5e5c4

File tree

3 files changed

+94
-15
lines changed

3 files changed

+94
-15
lines changed

lib/canvas.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ exports.Context2d = Context2d;
6262
exports.PNGStream = PNGStream;
6363
exports.JPEGStream = JPEGStream;
6464
exports.Image = Image;
65+
exports.ImageData = canvas.ImageData;
6566

6667
if (FontFace) {
6768
function Font(name, path, idx) {

src/ImageData.cc

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,46 +44,66 @@ NAN_METHOD(ImageData::New) {
4444

4545
int width;
4646
int height;
47+
int length;
4748

4849
if (info[0]->IsUint32() && info[1]->IsUint32()) {
4950
width = info[0]->Uint32Value();
51+
if (width == 0) {
52+
Nan::ThrowRangeError("The source width is zero.");
53+
return;
54+
}
5055
height = info[1]->Uint32Value();
51-
int size = width * height;
56+
if (height == 0) {
57+
Nan::ThrowRangeError("The source height is zero.");
58+
return;
59+
}
60+
length = width * height * 4;
5261

5362
#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION <= 10
54-
Local<Int32> sizeHandle = Nan::New(size);
63+
Local<Int32> sizeHandle = Nan::New(length);
5564
Local<Value> caargv[] = { sizeHandle };
5665
clampedArray = global->Get(Nan::New("Uint8ClampedArray").ToLocalChecked()).As<Function>()->NewInstance(1, caargv);
5766
#else
58-
clampedArray = Uint8ClampedArray::New(ArrayBuffer::New(Isolate::GetCurrent(), size), 0, size);
67+
clampedArray = Uint8ClampedArray::New(ArrayBuffer::New(Isolate::GetCurrent(), length), 0, length);
5968
#endif
6069

6170
#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION <= 10
6271
} else if (info[0]->ToObject()->GetIndexedPropertiesExternalArrayDataType() == kExternalPixelArray && info[1]->IsUint32()) {
6372
clampedArray = info[0]->ToObject();
73+
length = clampedArray->GetIndexedPropertiesExternalArrayDataLength();
6474
#else
6575
} else if (info[0]->IsUint8ClampedArray() && info[1]->IsUint32()) {
6676
clampedArray = info[0].As<Uint8ClampedArray>();
77+
length = clampedArray->Length();
6778
#endif
79+
if (length == 0) {
80+
Nan::ThrowRangeError("The input data has a zero byte length.");
81+
return;
82+
}
83+
if (length % 4 != 0) {
84+
Nan::ThrowRangeError("The input data byte length is not a multiple of 4.");
85+
return;
86+
}
6887
width = info[1]->Uint32Value();
69-
if (info[2]->IsUint32()) {
70-
height = info[2]->Uint32Value();
71-
} else {
72-
#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION <= 10
73-
height = clampedArray->GetIndexedPropertiesExternalArrayDataLength() / width;
74-
#else
75-
height = clampedArray->Length() / width;
76-
#endif
88+
int size = length / 4;
89+
if (width == 0) {
90+
Nan::ThrowRangeError("The source width is zero.");
91+
return;
92+
}
93+
if (size % width != 0) {
94+
Nan::ThrowRangeError("The input data byte length is not a multiple of (4 * width).");
95+
return;
96+
}
97+
height = size / width;
98+
if (info[2]->IsUint32() && info[2]->Uint32Value() != height) {
99+
Nan::ThrowRangeError("The input data byte length is not equal to (4 * width * height).");
100+
return;
77101
}
78102
} else {
79103
Nan::ThrowTypeError("Expected (Uint8ClampedArray, width[, height]) or (width, height)");
80104
return;
81105
}
82106

83-
// No behavior defined in spec. This is what WebKit does:
84-
if (width < 1) width = 1;
85-
if (height < 1) height = 1;
86-
87107
#if NODE_MAJOR_VERSION < 3
88108
void *dataPtr = clampedArray->GetIndexedPropertiesExternalArrayData();
89109
#else

test/imageData.test.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
'use strict';
2+
3+
var Canvas = require('../')
4+
, ImageData = Canvas.ImageData
5+
, assert = require('assert');
6+
7+
describe('ImageData', function () {
8+
it('should throw with invalid numeric arguments', function () {
9+
assert.throws(function () {
10+
new ImageData(0, 0);
11+
}, /width is zero/);
12+
assert.throws(function () {
13+
new ImageData(1, 0);
14+
}, /height is zero/);
15+
assert.throws(function () {
16+
new ImageData(0);
17+
}, TypeError);
18+
});
19+
20+
it('should construct with width and height', function () {
21+
var imagedata = new ImageData(2, 3);
22+
assert.strictEqual(imagedata.width, 2);
23+
assert.strictEqual(imagedata.height, 3);
24+
assert(imagedata.data instanceof Uint8ClampedArray);
25+
assert.strictEqual(imagedata.data.length, 24);
26+
});
27+
28+
it('should throw with invalid typed array', function () {
29+
assert.throws(function () {
30+
new ImageData(new Uint8ClampedArray(0), 0);
31+
}, /input data has a zero byte length/);
32+
assert.throws(function () {
33+
new ImageData(new Uint8ClampedArray(3), 0);
34+
}, /input data byte length is not a multiple of 4/);
35+
assert.throws(function () {
36+
new ImageData(new Uint8ClampedArray(16), 3);
37+
}, RangeError);
38+
assert.throws(function () {
39+
new ImageData(new Uint8ClampedArray(12), 3, 5);
40+
}, RangeError);
41+
});
42+
43+
it('should construct with typed array', function () {
44+
var data = new Uint8ClampedArray(2 * 3 * 4);
45+
var imagedata = new ImageData(data, 2);
46+
assert.strictEqual(imagedata.width, 2);
47+
assert.strictEqual(imagedata.height, 3);
48+
assert(imagedata.data instanceof Uint8ClampedArray);
49+
assert.strictEqual(imagedata.data.length, 24);
50+
51+
data = new Uint8ClampedArray(3 * 4 * 4);
52+
imagedata = new ImageData(data, 3, 4);
53+
assert.strictEqual(imagedata.width, 3);
54+
assert.strictEqual(imagedata.height, 4);
55+
assert(imagedata.data instanceof Uint8ClampedArray);
56+
assert.strictEqual(imagedata.data.length, 48);
57+
});
58+
});

0 commit comments

Comments
 (0)