Skip to content

Commit 564bbe2

Browse files
committed
v.1.2.4
* bicubic interpolation in pattern
1 parent 80e362b commit 564bbe2

File tree

3 files changed

+293
-45
lines changed

3 files changed

+293
-45
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Class to create **linear, radial, conic and elliptic gradients** and **image patterns** as bitmaps without canvas
44

5-
**version 1.2.3** (13 kB minified)
5+
**version 1.2.4** (16 kB minified)
66

77
**API:**
88

src/Gradient.js

Lines changed: 290 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Gradient
33
* class to create linear/radial/elliptical/conic gradients as bitmaps even without canvas
44
*
5-
* @version 1.2.3
5+
* @version 1.2.4
66
* https://github.com/foo123/Gradient
77
*
88
**/
@@ -89,7 +89,7 @@ function Gradient(grad_color_at)
8989
return bmp;
9090
};
9191
}
92-
Gradient.VERSION = "1.2.3";
92+
Gradient.VERSION = "1.2.4";
9393
Gradient.prototype = {
9494
constructor: Gradient,
9595
transform: null,
@@ -303,69 +303,306 @@ Pattern.prototype = {
303303
Pattern.createPattern = function(imageData, repetition) {
304304
if (imageData && imageData.data && imageData.width && imageData.height && (imageData.data.length === 4*imageData.width*imageData.height))
305305
{
306-
var width = imageData.width, height = imageData.height;
306+
var width = imageData.width,
307+
height = imageData.height,
308+
z = [0, 0, 0, 0],
309+
pt = function(x, y) {
310+
if (0 <= x && 0 <= y && x < width && y < height)
311+
{
312+
var index = (x + width*y) << 2;
313+
return [
314+
imageData.data[index ],
315+
imageData.data[index+1],
316+
imageData.data[index+2],
317+
imageData.data[index+3]
318+
];
319+
}
320+
return z;
321+
}
322+
;
307323
switch (repetition)
308324
{
309325
case 'no-repeat':
310326
return new Pattern(function(x, y, pixel, i) {
311-
x = stdMath.round(x);
312-
y = stdMath.round(y);
313-
if (0 <= x && x < width && 0 <= y && y < height)
327+
//x = stdMath.round(x);
328+
//y = stdMath.round(y);
329+
if (-1 < x && x < width && -1 < y && y < height)
314330
{
315-
var j = (x + y*width) << 2;
316-
pixel[i + 0] = imageData.data[j + 0];
317-
pixel[i + 1] = imageData.data[j + 1];
318-
pixel[i + 2] = imageData.data[j + 2];
319-
pixel[i + 3] = imageData.data[j + 3];
331+
var fx = stdMath.floor(x),
332+
fy = stdMath.floor(y),
333+
deltax = stdMath.abs(x-fx),
334+
deltay = stdMath.abs(y-fy);
335+
x = fx; y = fy;
336+
/*
337+
// bilinear
338+
var p00 = pt(x ,y ), p10 = pt(x+1,y ),
339+
p01 = pt(x ,y+1), p11 = pt(x+1,y+1);
340+
pixel[i + 0] = clamp(stdMath.round(linear(
341+
linear(p00[0], p10[0], deltax),
342+
linear(p10[0], p11[0], deltax),
343+
deltay)), 0, 255);
344+
pixel[i + 1] = clamp(stdMath.round(linear(
345+
linear(p00[1], p10[1], deltax),
346+
linear(p10[1], p11[1], deltax),
347+
deltay)), 0, 255);
348+
pixel[i + 2] = clamp(stdMath.round(linear(
349+
linear(p00[2], p10[2], deltax),
350+
linear(p10[2], p11[2], deltax),
351+
deltay)), 0, 255);
352+
pixel[i + 3] = clamp(stdMath.round(linear(
353+
linear(p00[3], p10[3], deltax),
354+
linear(p10[3], p11[3], deltax),
355+
deltay)), 0, 255);
356+
*/
357+
// bicubic
358+
var p00 = pt(x-1,y-1), p10 = pt(x ,y-1), p20 = pt(x+1,y-1), p30 = pt(x+2,y-1),
359+
p01 = pt(x-1,y ), p11 = pt(x ,y ), p21 = pt(x+1,y ), p31 = pt(x+2,y ),
360+
p02 = pt(x-1,y+1), p12 = pt(x ,y+1), p22 = pt(x+1,y+1), p32 = pt(x+2,y+1),
361+
p03 = pt(x-1,y+2), p13 = pt(x ,y+2), p23 = pt(x+1,y+2), p33 = pt(x+2,y+2);
362+
pixel[i + 0] = clamp(stdMath.round(cubic(
363+
cubic(p00[0], p10[0], p20[0], p30[0], deltax),
364+
cubic(p01[0], p11[0], p21[0], p31[0], deltax),
365+
cubic(p02[0], p12[0], p22[0], p32[0], deltax),
366+
cubic(p03[0], p13[0], p23[0], p33[0], deltax),
367+
deltay)), 0, 255);
368+
pixel[i + 1] = clamp(stdMath.round(cubic(
369+
cubic(p00[1], p10[1], p20[1], p30[1], deltax),
370+
cubic(p01[1], p11[1], p21[1], p31[1], deltax),
371+
cubic(p02[1], p12[1], p22[1], p32[1], deltax),
372+
cubic(p03[1], p13[1], p23[1], p33[1], deltax),
373+
deltay)), 0, 255);
374+
pixel[i + 2] = clamp(stdMath.round(cubic(
375+
cubic(p00[2], p10[2], p20[2], p30[2], deltax),
376+
cubic(p01[2], p11[2], p21[2], p31[2], deltax),
377+
cubic(p02[2], p12[2], p22[2], p32[2], deltax),
378+
cubic(p03[2], p13[2], p23[2], p33[2], deltax),
379+
deltay)), 0, 255);
380+
pixel[i + 3] = clamp(stdMath.round(cubic(
381+
cubic(p00[3], p10[3], p20[3], p30[3], deltax),
382+
cubic(p01[3], p11[3], p21[3], p31[3], deltax),
383+
cubic(p02[3], p12[3], p22[3], p32[3], deltax),
384+
cubic(p03[3], p13[3], p23[3], p33[3], deltax),
385+
deltay)), 0, 255);
386+
}
387+
else
388+
{
389+
pixel[i + 0] = 0;
390+
pixel[i + 1] = 0;
391+
pixel[i + 2] = 0;
392+
pixel[i + 3] = 0;
320393
}
321394
return pixel;
322395
});
323396
case 'repeat-x':
324397
return new Pattern(function(x, y, pixel, i) {
325-
x = stdMath.round(x);
326-
y = stdMath.round(y);
327-
if (0 <= y && y < height)
398+
//x = stdMath.round(x);
399+
//y = stdMath.round(y);
400+
if (-1 < y && y < height)
401+
{
402+
if (x > width) x -= stdMath.floor(x/width)*width;
403+
if (x < 0) x += stdMath.ceil(-x/width)*width;
404+
var fx = stdMath.floor(x),
405+
fy = stdMath.floor(y),
406+
deltax = stdMath.abs(x-fx),
407+
deltay = stdMath.abs(y-fy);
408+
x = fx; y = fy;
409+
/*
410+
// bilinear
411+
var p00 = pt(x ,y ), p10 = pt(x+1,y ),
412+
p01 = pt(x ,y+1), p11 = pt(x+1,y+1);
413+
pixel[i + 0] = clamp(stdMath.round(linear(
414+
linear(p00[0], p10[0], deltax),
415+
linear(p10[0], p11[0], deltax),
416+
deltay)), 0, 255);
417+
pixel[i + 1] = clamp(stdMath.round(linear(
418+
linear(p00[1], p10[1], deltax),
419+
linear(p10[1], p11[1], deltax),
420+
deltay)), 0, 255);
421+
pixel[i + 2] = clamp(stdMath.round(linear(
422+
linear(p00[2], p10[2], deltax),
423+
linear(p10[2], p11[2], deltax),
424+
deltay)), 0, 255);
425+
pixel[i + 3] = clamp(stdMath.round(linear(
426+
linear(p00[3], p10[3], deltax),
427+
linear(p10[3], p11[3], deltax),
428+
deltay)), 0, 255);
429+
*/
430+
// bicubic
431+
var p00 = pt(x-1,y-1), p10 = pt(x ,y-1), p20 = pt(x+1,y-1), p30 = pt(x+2,y-1),
432+
p01 = pt(x-1,y ), p11 = pt(x ,y ), p21 = pt(x+1,y ), p31 = pt(x+2,y ),
433+
p02 = pt(x-1,y+1), p12 = pt(x ,y+1), p22 = pt(x+1,y+1), p32 = pt(x+2,y+1),
434+
p03 = pt(x-1,y+2), p13 = pt(x ,y+2), p23 = pt(x+1,y+2), p33 = pt(x+2,y+2);
435+
pixel[i + 0] = clamp(stdMath.round(cubic(
436+
cubic(p00[0], p10[0], p20[0], p30[0], deltax),
437+
cubic(p01[0], p11[0], p21[0], p31[0], deltax),
438+
cubic(p02[0], p12[0], p22[0], p32[0], deltax),
439+
cubic(p03[0], p13[0], p23[0], p33[0], deltax),
440+
deltay)), 0, 255);
441+
pixel[i + 1] = clamp(stdMath.round(cubic(
442+
cubic(p00[1], p10[1], p20[1], p30[1], deltax),
443+
cubic(p01[1], p11[1], p21[1], p31[1], deltax),
444+
cubic(p02[1], p12[1], p22[1], p32[1], deltax),
445+
cubic(p03[1], p13[1], p23[1], p33[1], deltax),
446+
deltay)), 0, 255);
447+
pixel[i + 2] = clamp(stdMath.round(cubic(
448+
cubic(p00[2], p10[2], p20[2], p30[2], deltax),
449+
cubic(p01[2], p11[2], p21[2], p31[2], deltax),
450+
cubic(p02[2], p12[2], p22[2], p32[2], deltax),
451+
cubic(p03[2], p13[2], p23[2], p33[2], deltax),
452+
deltay)), 0, 255);
453+
pixel[i + 3] = clamp(stdMath.round(cubic(
454+
cubic(p00[3], p10[3], p20[3], p30[3], deltax),
455+
cubic(p01[3], p11[3], p21[3], p31[3], deltax),
456+
cubic(p02[3], p12[3], p22[3], p32[3], deltax),
457+
cubic(p03[3], p13[3], p23[3], p33[3], deltax),
458+
deltay)), 0, 255);
459+
}
460+
else
328461
{
329-
x = x % width;
330-
if (0 > x) x += width;
331-
var j = (x + y*width) << 2;
332-
pixel[i + 0] = imageData.data[j + 0];
333-
pixel[i + 1] = imageData.data[j + 1];
334-
pixel[i + 2] = imageData.data[j + 2];
335-
pixel[i + 3] = imageData.data[j + 3];
462+
pixel[i + 0] = 0;
463+
pixel[i + 1] = 0;
464+
pixel[i + 2] = 0;
465+
pixel[i + 3] = 0;
336466
}
337467
return pixel;
338468
});
339469
case 'repeat-y':
340470
return new Pattern(function(x, y, pixel, i) {
341-
x = stdMath.round(x);
342-
y = stdMath.round(y);
343-
if (0 <= x && x < width)
471+
//x = stdMath.round(x);
472+
//y = stdMath.round(y);
473+
if (-1 < x && x < width)
344474
{
345-
y = y % height;
346-
if (0 > y) y += height;
347-
var j = (x + y*width) << 2;
348-
pixel[i + 0] = imageData.data[j + 0];
349-
pixel[i + 1] = imageData.data[j + 1];
350-
pixel[i + 2] = imageData.data[j + 2];
351-
pixel[i + 3] = imageData.data[j + 3];
475+
if (y > height) y -= stdMath.floor(y/height)*height;
476+
if (y < 0) y += stdMath.ceil(-y/height)*height;
477+
var fx = stdMath.floor(x),
478+
fy = stdMath.floor(y),
479+
deltax = stdMath.abs(x-fx),
480+
deltay = stdMath.abs(y-fy);
481+
x = fx; y = fy;
482+
/*
483+
// bilinear
484+
var p00 = pt(x ,y ), p10 = pt(x+1,y ),
485+
p01 = pt(x ,y+1), p11 = pt(x+1,y+1);
486+
pixel[i + 0] = clamp(stdMath.round(linear(
487+
linear(p00[0], p10[0], deltax),
488+
linear(p10[0], p11[0], deltax),
489+
deltay)), 0, 255);
490+
pixel[i + 1] = clamp(stdMath.round(linear(
491+
linear(p00[1], p10[1], deltax),
492+
linear(p10[1], p11[1], deltax),
493+
deltay)), 0, 255);
494+
pixel[i + 2] = clamp(stdMath.round(linear(
495+
linear(p00[2], p10[2], deltax),
496+
linear(p10[2], p11[2], deltax),
497+
deltay)), 0, 255);
498+
pixel[i + 3] = clamp(stdMath.round(linear(
499+
linear(p00[3], p10[3], deltax),
500+
linear(p10[3], p11[3], deltax),
501+
deltay)), 0, 255);
502+
*/
503+
// bicubic
504+
var p00 = pt(x-1,y-1), p10 = pt(x ,y-1), p20 = pt(x+1,y-1), p30 = pt(x+2,y-1),
505+
p01 = pt(x-1,y ), p11 = pt(x ,y ), p21 = pt(x+1,y ), p31 = pt(x+2,y ),
506+
p02 = pt(x-1,y+1), p12 = pt(x ,y+1), p22 = pt(x+1,y+1), p32 = pt(x+2,y+1),
507+
p03 = pt(x-1,y+2), p13 = pt(x ,y+2), p23 = pt(x+1,y+2), p33 = pt(x+2,y+2);
508+
pixel[i + 0] = clamp(stdMath.round(cubic(
509+
cubic(p00[0], p10[0], p20[0], p30[0], deltax),
510+
cubic(p01[0], p11[0], p21[0], p31[0], deltax),
511+
cubic(p02[0], p12[0], p22[0], p32[0], deltax),
512+
cubic(p03[0], p13[0], p23[0], p33[0], deltax),
513+
deltay)), 0, 255);
514+
pixel[i + 1] = clamp(stdMath.round(cubic(
515+
cubic(p00[1], p10[1], p20[1], p30[1], deltax),
516+
cubic(p01[1], p11[1], p21[1], p31[1], deltax),
517+
cubic(p02[1], p12[1], p22[1], p32[1], deltax),
518+
cubic(p03[1], p13[1], p23[1], p33[1], deltax),
519+
deltay)), 0, 255);
520+
pixel[i + 2] = clamp(stdMath.round(cubic(
521+
cubic(p00[2], p10[2], p20[2], p30[2], deltax),
522+
cubic(p01[2], p11[2], p21[2], p31[2], deltax),
523+
cubic(p02[2], p12[2], p22[2], p32[2], deltax),
524+
cubic(p03[2], p13[2], p23[2], p33[2], deltax),
525+
deltay)), 0, 255);
526+
pixel[i + 3] = clamp(stdMath.round(cubic(
527+
cubic(p00[3], p10[3], p20[3], p30[3], deltax),
528+
cubic(p01[3], p11[3], p21[3], p31[3], deltax),
529+
cubic(p02[3], p12[3], p22[3], p32[3], deltax),
530+
cubic(p03[3], p13[3], p23[3], p33[3], deltax),
531+
deltay)), 0, 255);
532+
}
533+
else
534+
{
535+
pixel[i + 0] = 0;
536+
pixel[i + 1] = 0;
537+
pixel[i + 2] = 0;
538+
pixel[i + 3] = 0;
352539
}
353540
return pixel;
354541
});
355542
case 'repeat':
356543
default:
357544
return new Pattern(function(x, y, pixel, i) {
358-
x = stdMath.round(x);
359-
y = stdMath.round(y);
360-
x = x % width;
361-
if (0 > x) x += width;
362-
y = y % height;
363-
if (0 > y) y += height;
364-
var j = (x + y*width) << 2;
365-
pixel[i + 0] = imageData.data[j + 0];
366-
pixel[i + 1] = imageData.data[j + 1];
367-
pixel[i + 2] = imageData.data[j + 2];
368-
pixel[i + 3] = imageData.data[j + 3];
545+
//x = stdMath.round(x);
546+
//y = stdMath.round(y);
547+
if (x > width) x -= stdMath.floor(x/width)*width;
548+
if (x < 0) x += stdMath.ceil(-x/width)*width;
549+
if (y > height) y -= stdMath.floor(y/height)*height;
550+
if (y < 0) y += stdMath.ceil(-y/height)*height;
551+
var fx = stdMath.floor(x),
552+
fy = stdMath.floor(y),
553+
deltax = stdMath.abs(x-fx),
554+
deltay = stdMath.abs(y-fy);
555+
x = fx; y = fy;
556+
/*
557+
// bilinear
558+
var p00 = pt(x ,y ), p10 = pt(x+1,y ),
559+
p01 = pt(x ,y+1), p11 = pt(x+1,y+1);
560+
pixel[i + 0] = clamp(stdMath.round(linear(
561+
linear(p00[0], p10[0], deltax),
562+
linear(p10[0], p11[0], deltax),
563+
deltay)), 0, 255);
564+
pixel[i + 1] = clamp(stdMath.round(linear(
565+
linear(p00[1], p10[1], deltax),
566+
linear(p10[1], p11[1], deltax),
567+
deltay)), 0, 255);
568+
pixel[i + 2] = clamp(stdMath.round(linear(
569+
linear(p00[2], p10[2], deltax),
570+
linear(p10[2], p11[2], deltax),
571+
deltay)), 0, 255);
572+
pixel[i + 3] = clamp(stdMath.round(linear(
573+
linear(p00[3], p10[3], deltax),
574+
linear(p10[3], p11[3], deltax),
575+
deltay)), 0, 255);
576+
*/
577+
// bicubic
578+
var p00 = pt(x-1,y-1), p10 = pt(x ,y-1), p20 = pt(x+1,y-1), p30 = pt(x+2,y-1),
579+
p01 = pt(x-1,y ), p11 = pt(x ,y ), p21 = pt(x+1,y ), p31 = pt(x+2,y ),
580+
p02 = pt(x-1,y+1), p12 = pt(x ,y+1), p22 = pt(x+1,y+1), p32 = pt(x+2,y+1),
581+
p03 = pt(x-1,y+2), p13 = pt(x ,y+2), p23 = pt(x+1,y+2), p33 = pt(x+2,y+2);
582+
pixel[i + 0] = clamp(stdMath.round(cubic(
583+
cubic(p00[0], p10[0], p20[0], p30[0], deltax),
584+
cubic(p01[0], p11[0], p21[0], p31[0], deltax),
585+
cubic(p02[0], p12[0], p22[0], p32[0], deltax),
586+
cubic(p03[0], p13[0], p23[0], p33[0], deltax),
587+
deltay)), 0, 255);
588+
pixel[i + 1] = clamp(stdMath.round(cubic(
589+
cubic(p00[1], p10[1], p20[1], p30[1], deltax),
590+
cubic(p01[1], p11[1], p21[1], p31[1], deltax),
591+
cubic(p02[1], p12[1], p22[1], p32[1], deltax),
592+
cubic(p03[1], p13[1], p23[1], p33[1], deltax),
593+
deltay)), 0, 255);
594+
pixel[i + 2] = clamp(stdMath.round(cubic(
595+
cubic(p00[2], p10[2], p20[2], p30[2], deltax),
596+
cubic(p01[2], p11[2], p21[2], p31[2], deltax),
597+
cubic(p02[2], p12[2], p22[2], p32[2], deltax),
598+
cubic(p03[2], p13[2], p23[2], p33[2], deltax),
599+
deltay)), 0, 255);
600+
pixel[i + 3] = clamp(stdMath.round(cubic(
601+
cubic(p00[3], p10[3], p20[3], p30[3], deltax),
602+
cubic(p01[3], p11[3], p21[3], p31[3], deltax),
603+
cubic(p02[3], p12[3], p22[3], p32[3], deltax),
604+
cubic(p03[3], p13[3], p23[3], p33[3], deltax),
605+
deltay)), 0, 255);
369606
return pixel;
370607
});
371608
}
@@ -603,6 +840,17 @@ Matrix.skewY = function(s) {
603840
Gradient.Matrix = Matrix;
604841

605842
// utils
843+
function linear(A, B, t)
844+
{
845+
// linear bezier
846+
return A*(1-t) + B*(t);
847+
}
848+
function cubic(A, B, C, D, t)
849+
{
850+
// cubic hermite
851+
var t2 = t*t;
852+
return (-A / 2.0 + (3.0*B) / 2.0 - (3.0*C) / 2.0 + D / 2.0)*t2*t + (A - (5.0*B) / 2.0 + 2.0*C - D / 2.0)*t2 + (-A / 2.0 + C / 2.0)*t + (B);
853+
}
606854
function is_strictly_equal(a, b)
607855
{
608856
return stdMath.abs(a - b) < Number.EPSILON;

0 commit comments

Comments
 (0)