Comparing version 0.0.3 to 0.0.4
@@ -228,8 +228,9 @@ /** | ||
var dst = that._data.data; | ||
var srcPos = 0; | ||
var dstPos = 0; | ||
for (var i = 0; i < n; i++) { | ||
var pos = i*4; | ||
dst[pos] = 255 - src[pos]; | ||
dst[pos+1] = 255 - src[pos+1]; | ||
dst[pos+2] = 255 - src[pos+2]; | ||
dst[pos+3] = src[pos+3]; | ||
dst[dstPos++] = 255 - src[srcPos++]; | ||
dst[dstPos++] = 255 - src[srcPos++]; | ||
dst[dstPos++] = 255 - src[srcPos++]; | ||
dst[dstPos++] = src[srcPos++]; | ||
} | ||
@@ -295,3 +296,61 @@ return that; | ||
return that; | ||
}, | ||
crop: function(options) { | ||
var t = options.top; | ||
var l = options.left; | ||
var w = options.width; | ||
var h = options.height; | ||
var that = new Bitmap({width: w, height: h}); | ||
var src = this._data.data; | ||
var dst = that._data.data; | ||
var w4 = 2 * 4; | ||
for (var i = 0; i < h; i++) { | ||
var srcPos = ((i+t)*w + l) * 4; | ||
var dstPos = i * 4; | ||
for (var j = 0; j < w4; j++) { | ||
dst[dstPos++] = src[srcPos++]; | ||
} | ||
} | ||
return that; | ||
}, | ||
blur: function(options) { | ||
// todo: expand to own file with different blur algorithms | ||
var that = new Bitmap({width: this.width, height: this.height}); | ||
var w = this.width; | ||
var h = this.height; | ||
var W = w-1; | ||
var H = h-1; | ||
var V = w*4; // used for i offsets | ||
var src = this._data.data; | ||
var dst = that._data.data; | ||
for (var i = 0; i < h; i++) { | ||
for (var j = 0; j < w; j++) { | ||
for (var k = 0; k < 4; k++) { | ||
var pos = (i*w + j) * 4 + k; | ||
var t = src[pos -(i>0?V:0) - (j>0?4:0)] * 1 + // 1/16 | ||
src[pos -(i>0?V:0) ] * 2 + // 2/16 | ||
src[pos -(i>0?V:0) + (j<W?4:0)] * 1 + // 1/16 | ||
src[pos - (j>0?4:0)] * 2 + // 2/16 | ||
src[pos ] * 4 + // 4/16 | ||
src[pos + (j<W?4:0)] * 2 + // 2/16 | ||
src[pos +(i<H?V:0) - (j>0?4:0)] * 1 + // 1/16 | ||
src[pos +(i<H?V:0) ] * 2 + // 2/16 | ||
src[pos +(i<H?V:0) + (j<W?4:0)] * 1; // 1/16 | ||
dst[pos] = Math.round(t/16); | ||
} | ||
} | ||
} | ||
return that; | ||
} | ||
} |
@@ -28,4 +28,14 @@ /** | ||
module.exports = { | ||
_writeFile: function(width, height, data, filename) { | ||
// for debugging | ||
var Bitmap = require("./bitmap"); | ||
var bmp = new Bitmap({ | ||
width: width, height: height, | ||
data: data | ||
}); | ||
bmp.writeFile(filename); | ||
}, | ||
_pad: function(dst, options) { | ||
@@ -208,4 +218,5 @@ var top = options.bounds.top; | ||
}, | ||
bicubicInterpolation: function(src, dst, options) { | ||
_interpolate2D: function(src, dst, options, interpolate) { | ||
this._pad(dst, options); | ||
@@ -234,24 +245,22 @@ | ||
// when dst smaller than src/2, interpolate first to a multiple between 0.5 and 1.0 src, then sum squares | ||
var wM = Math.floor(wSrc / wDst); | ||
var wDst2 = wDst * wM; | ||
var hM = Math.floor(hSrc / hDst); | ||
var hDst2 = hDst * hM; | ||
//console.log("wM="+wM + ", wDst2="+wDst2 + ", hM="+hM + ", hDst2="+hDst2); | ||
var bufSrc = src._data.data; | ||
var bufDst = dst._data.data; | ||
var interpolateCubic = function(x0, x1, x2, x3, t) { | ||
var a0 = x3 - x2 - x0 + x1; | ||
var a1 = x0 - x1 - a0; | ||
var a2 = x2 - x0; | ||
var a3 = x1; | ||
return Math.max(0,Math.min(255,(a0 * (t * t * t)) + (a1 * (t * t)) + (a2 * t) + (a3))); | ||
} | ||
// =========================================================== | ||
// Pass 1 - interpolate scanlines | ||
// buf1 has width of dst and height of src | ||
var buf1 = new Buffer(wDst * hSrc * 4); | ||
// Pass 1 - interpolate rows | ||
// buf1 has width of dst2 and height of src | ||
var buf1 = new Buffer(wDst2 * hSrc * 4); | ||
for (var i = 0; i < hSrc; i++) { | ||
for (var j = 0; j < wDst; j++) { | ||
for (var j = 0; j < wDst2; j++) { | ||
// i in src coords, j in dst coords | ||
// calculate x in src crop coords | ||
var x = j * wSrc / wDst; | ||
var x = j * wSrc / wDst2; | ||
var xPos = Math.floor(x); | ||
@@ -261,45 +270,136 @@ var t = x - xPos; | ||
var buf1Pos = (i * wDst + j) * 4; | ||
var buf1Pos = (i * wDst2 + j) * 4; | ||
for (var k = 0; k < 4; k++) { | ||
var kPos = srcPos + k; | ||
var x0 = (xPos + lSrc > 0) ? bufSrc[kPos - 4] : bufSrc[kPos]; | ||
var x0 = (xPos + lSrc > 0) ? bufSrc[kPos - 4] : 2*bufSrc[kPos]-bufSrc[kPos+4]; | ||
var x1 = bufSrc[kPos]; | ||
var x2 = bufSrc[kPos + 4]; | ||
var x3 = (xPos + lSrc < srcWidth - 1) ? bufSrc[kPos + 8] : bufSrc[kPos + 4]; | ||
buf1[buf1Pos+k] = interpolateCubic(x0,x1,x2,x3,t); | ||
var x3 = (xPos + lSrc < srcWidth - 1) ? bufSrc[kPos + 8] : 2*bufSrc[kPos + 4]-bufSrc[kPos]; | ||
buf1[buf1Pos+k] = interpolate(x0,x1,x2,x3,t); | ||
} | ||
} | ||
} | ||
//var Bitmap = require("./bitmap"); | ||
//var tmp = new Bitmap({ | ||
// width: wDst, height: hSrc, | ||
// data: buf1 | ||
//}); | ||
//tmp.writeFile("out/tmp.jpg"); | ||
//this._writeFile(wDst2, hSrc, buf1, "out/bc/buf1.jpg"); | ||
// =========================================================== | ||
// Pass 2 - interpolate columns | ||
for (var i = 0; i < hDst; i++) { | ||
for (var j = 0; j < wDst; j++) { | ||
// i&j in dst coords | ||
// buf2 has width and height of dst2 | ||
var buf2 = new Buffer(wDst2 * hDst2 * 4); | ||
for (var i = 0; i < hDst2; i++) { | ||
for (var j = 0; j < wDst2; j++) { | ||
// i&j in dst2 coords | ||
// calculate y in buf1 coords | ||
var y = i * hSrc / hDst; | ||
var y = i * hSrc / hDst2; | ||
var yPos = Math.floor(y); | ||
var t = y - yPos; | ||
var buf1Pos = (yPos * wDst + j) * 4; | ||
var dstPos = ((i+tDst) * dstWidth + j + lDst) * 4; | ||
var buf1Pos = (yPos * wDst2 + j) * 4; | ||
var buf2Pos = (i * wDst2 + j) * 4; | ||
for (var k = 0; k < 4; k++) { | ||
var kPos = buf1Pos + k; | ||
var y0 = (yPos > 0) ? buf1[kPos - wDst*4] : buf1[kPos]; | ||
var y0 = (yPos > 0) ? buf1[kPos - wDst2*4] : 2*buf1[kPos]-buf1[kPos + wDst2*4]; | ||
var y1 = buf1[kPos]; | ||
var y2 = buf1[kPos + wDst*4]; | ||
var y3 = (yPos < hSrc) ? buf1[kPos + wDst*8] : buf1[kPos + wDst*4]; | ||
var y2 = buf1[kPos + wDst2*4]; | ||
var y3 = (yPos < hSrc) ? buf1[kPos + wDst2*8] : 2*buf1[kPos + wDst2*4]-buf1[kPos]; | ||
bufDst[dstPos + k] = interpolateCubic(y0,y1,y2,y3,t); | ||
buf2[buf2Pos + k] = interpolate(y0,y1,y2,y3,t); | ||
} | ||
} | ||
} | ||
//this._writeFile(wDst2, hDst2, buf2, "out/bc/buf2.jpg"); | ||
// =========================================================== | ||
// Pass 3 - scale to dst | ||
var m = wM * hM; | ||
if (m > 1) { | ||
for (var i = 0; i < hDst; i++) { | ||
for (var j = 0; j < wDst; j++) { | ||
// i&j in dst bounded coords | ||
var r = 0; | ||
var g = 0; | ||
var b = 0; | ||
var a = 0; | ||
for (var y = 0; y < hM; y++) { | ||
var yPos = i * hM + y; | ||
for (var x = 0; x < wM; x++) { | ||
var xPos = j * wM + x; | ||
var xyPos = (yPos * wDst2 + xPos) * 4; | ||
r += buf2[xyPos]; | ||
g += buf2[xyPos+1]; | ||
b += buf2[xyPos+2]; | ||
a += buf2[xyPos+3]; | ||
} | ||
} | ||
var pos = ((i+tDst)*dstWidth + j + lDst) * 4; | ||
bufDst[pos] = Math.round(r / m); | ||
bufDst[pos+1] = Math.round(g / m); | ||
bufDst[pos+2] = Math.round(b / m); | ||
bufDst[pos+3] = Math.round(a / m); | ||
} | ||
} | ||
} else { | ||
// 1 to 1 copy | ||
for (var i = 0; i < hDst; i++) { | ||
for (var j = 0; j < wDst; j++) { | ||
var buf2Pos = (i*wDst + j) * 4; | ||
var dstPos = ((i+tDst)*dstWidth + j + lDst) * 4; | ||
bufDst[dstPos++] = buf2[buf2Pos++]; | ||
bufDst[dstPos++] = buf2[buf2Pos++]; | ||
bufDst[dstPos++] = buf2[buf2Pos++]; | ||
bufDst[dstPos++] = buf2[buf2Pos++]; | ||
} | ||
} | ||
} | ||
}, | ||
bicubicInterpolation: function(src, dst, options) { | ||
var interpolateCubic = function(x0, x1, x2, x3, t) { | ||
var a0 = x3 - x2 - x0 + x1; | ||
var a1 = x0 - x1 - a0; | ||
var a2 = x2 - x0; | ||
var a3 = x1; | ||
return Math.max(0,Math.min(255,(a0 * (t * t * t)) + (a1 * (t * t)) + (a2 * t) + (a3))); | ||
} | ||
return this._interpolate2D(src, dst, options, interpolateCubic); | ||
}, | ||
hermiteInterpolation: function(src, dst, options) { | ||
var interpolateHermite = function(x0, x1, x2, x3, t) | ||
{ | ||
var c0 = x1; | ||
var c1 = 0.5 * (x2 - x0); | ||
var c2 = x0 - (2.5 * x1) + (2 * x2) - (0.5 * x3); | ||
var c3 = (0.5 * (x3 - x0)) + (1.5 * (x1 - x2)); | ||
return Math.max(0,Math.min(255,Math.round((((((c3 * t) + c2) * t) + c1) * t) + c0))); | ||
} | ||
return this._interpolate2D(src, dst, options, interpolateHermite); | ||
}, | ||
bezierInterpolation: function(src, dst, options) { | ||
// between 2 points y(n), y(n+1), use next points out, y(n-1), y(n+2) | ||
// to predict control points (a & b) to be placed at n+0.5 | ||
// ya(n) = y(n) + (y(n+1)-y(n-1))/4 | ||
// yb(n) = y(n+1) - (y(n+2)-y(n))/4 | ||
// then use std bezier to interpolate [n,n+1) | ||
// y(n+t) = y(n)*(1-t)^3 + 3 * ya(n)*(1-t)^2*t + 3 * yb(n)*(1-t)*t^2 + y(n+1)*t^3 | ||
// note the 3* factor for the two control points | ||
// for edge cases, can choose: | ||
// y(-1) = y(0) - 2*(y(1)-y(0)) | ||
// y(w) = y(w-1) + 2*(y(w-1)-y(w-2)) | ||
// but can go with y(-1) = y(0) and y(w) = y(w-1) | ||
var interpolateBezier = function(x0, x1, x2, x3, t) { | ||
// x1, x2 are the knots, use x0 and x3 to calculate control points | ||
var cp1 = x1 + (x2-x0)/4; | ||
var cp2 = x2 - (x3-x1)/4; | ||
var nt = 1-t; | ||
var c0 = x1 * nt * nt * nt; | ||
var c1 = 3 * cp1 * nt * nt * t; | ||
var c2 = 3 * cp2 * nt * t * t; | ||
var c3 = x2 * t * t * t; | ||
return Math.max(0,Math.min(255,Math.round(c0 + c1 + c2 + c3))); | ||
} | ||
return this._interpolate2D(src, dst, options, interpolateBezier); | ||
} | ||
} |
{ | ||
"name": "imagejs", | ||
"version": "0.0.3", | ||
"version": "0.0.4", | ||
"description": "Image Processor", | ||
@@ -5,0 +5,0 @@ "private": false, |
@@ -7,3 +7,4 @@ # ImageJS | ||
This is an early release supporting only jpeg files and only the simplest resize algorithm but there will be more to come. | ||
This is an early release supporting only jpeg and png files and only the simplest resize algorithms | ||
but there will be more to come. | ||
@@ -18,17 +19,12 @@ # Installation | ||
<li> | ||
<a href="#image-resize">Enhanced Resize</a> | ||
<a href="#resize">Enhanced Resize</a> | ||
<ul> | ||
<li>New Resize Algorithm: Bicubic Interpolation</li> | ||
<li>New Resize Algorithm: Bezier Interpolation</li> | ||
<li>2 Pass algorithm to compensate for undersampling</li> | ||
</ul> | ||
</li> | ||
<li><a href="blur">Blur Images</a></li> | ||
<li><a href="crop">Crop Images</a></li> | ||
</ul> | ||
# Coming Soon | ||
<ul> | ||
<li>Bicubic Interpolation</li> | ||
<li>Crop</li> | ||
<li>Pad</li> | ||
</ul> | ||
# Contents | ||
@@ -45,2 +41,6 @@ | ||
<li><a href="set-pixel">Set Pixel</a></li> | ||
<li><a href="negative">Negative</a></li> | ||
<li><a href="blur">Blur</a></li> | ||
<li><a href="crop">Crop</a></li> | ||
<li><a href="resize">Resize</a></li> | ||
</ul> | ||
@@ -85,2 +85,3 @@ </li> | ||
### Set Pixel | ||
```javascript | ||
@@ -90,8 +91,24 @@ // Set a pixel | ||
bitmap.setPixel(x,y, a,r,g,b); | ||
``` | ||
### Negative | ||
```javascript | ||
// Create a new bitmap that is a negative of the original | ||
var negative = bitmap.negative(); | ||
``` | ||
// Create a new bitmap resized from an original | ||
### Blur | ||
```javascript | ||
// blur with simple gaussian filter | ||
var blurred = bitmap.blur(); | ||
``` | ||
### Crop | ||
```javascript | ||
// create a new bitmap from a portion of another | ||
var cropped = bitmap.crop({top: 50, left: 30, width: 100, height: 100}); | ||
``` | ||
### Resize | ||
```javascript | ||
// resize to 64x64 icon sized bitmap using nearest neighbor algorithm & stretch to fit | ||
@@ -125,2 +142,3 @@ var thumbnail = bitmap.resize({ | ||
* bicubicInterpolation | ||
* bezierInterpolation | ||
@@ -172,1 +190,2 @@ ## Reading Images | ||
| 0.0.3 | <ul><li><a href="#image-resize">Enhanced Resize</a><ul><li>New Resize Algorithm: Bicubic Interpolation</li></ul></li></ul> | | ||
| 0.0.4 | <ul><li><a href="#resizing-bitmaps">Enhanced Resize</a><ul><li>New Resize Algorithm: Bezier Interpolation</li><li>2 Pass algorithm to compensate for undersampling</li></ul></li><li><a href="blur">Blur Images</a></li><li><a href="crop">Crop Images</a></li></ul> | |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
38478
729
185