Skip to content

Instantly share code, notes, and snippets.

@andrey-helldar
Last active December 18, 2018 11:52
Show Gist options
  • Save andrey-helldar/96ec1f44ba0ea8b60d0e5cc4954bf8ab to your computer and use it in GitHub Desktop.
Save andrey-helldar/96ec1f44ba0ea8b60d0e5cc4954bf8ab to your computer and use it in GitHub Desktop.
Resize images with javascript
function resize(path, canvas, width) {
var HERMITE = new Hermite_class();
var ctx = canvas.getContext('2d');
var img_w;
var img_h;
var current_size = false;
var img = new Image();
img.crossOrigin = 'Anonymous'; //cors support
img.onload = function () {
draw_image();
var coeff = img.height / img.width;
var height = width * coeff;
//resize
resize(width, height);
};
img.src = path;
function draw_image() {
img_w = img.width;
img_h = img.height;
//prepare canvas
canvas.width = img_w;
canvas.height = img_h;
ctx.clearRect(0, 0, img_w, img_h);
//draw image
ctx.drawImage(img, 0, 0);
}
function resize(width, height, slider) {
if (slider === true && current_size == width + 'x' + height) {
//stop event from firing twice - firefix bug
return false;
}
current_size = width + 'x' + height;
//prepare canvas
canvas.width = img_w;
canvas.height = img_h;
ctx.drawImage(img, 0, 0); //draw image
//resize
HERMITE.resample_single(canvas, width, height, true);
}
// ----------- LIBRARY BELOW ------------------------
/**
* Hermite resize - fast image resize/resample using Hermite filter.
* Author: ViliusL
* demo: http://viliusle.github.io/miniPaint/
*/
function Hermite_class() {
var cores;
var workers_archive = [];
var workerBlobURL;
/**
* contructor
*/
this.init = function () {
cores = navigator.hardwareConcurrency || 4;
}();
/**
* Returns CPU cores count
*
* @returns {int}
*/
this.getCores = function () {
return cores;
};
/**
* Hermite resize. Detect cpu count and use best option for user.
*
* @param {HtmlElement} canvas
* @param {int} width
* @param {int} height
* @param {boolean} resize_canvas if true, canvas will be resized. Optional.
* @param {boolean} on_finish finish handler. Optional.
*/
this.resample_auto = function (canvas, width, height, resize_canvas, on_finish) {
var cores = this.getCores();
if (!!window.Worker && cores > 1) {
//workers supported and we have at least 2 cpu cores - using multithreading
this.resample(canvas, width, height, resize_canvas, on_finish);
} else {
//1 cpu version
this.resample_single(canvas, width, height, true);
on_finish();
}
};
/**
* Hermite resize. Resize actual image.
*
* @param {string} image_id
* @param {int} width
* @param {int} height optional.
* @param {int} percentages optional.
* @param {string} multi_core optional.
*/
this.resize_image = function (image_id, width, height, percentages, multi_core) {
var img = document.getElementById(image_id);
//create temp canvas
var temp_canvas = document.createElement('canvas');
temp_canvas.width = img.width;
temp_canvas.height = img.height;
var temp_ctx = temp_canvas.getContext('2d');
//draw image
temp_ctx.drawImage(img, 0, 0);
//prepare size
if (width == undefined && height == undefined && percentages != undefined) {
width = img.width / 100 * percentages;
height = img.height / 100 * percentages;
}
if (height == undefined) {
var ratio = img.width / width;
height = img.height / ratio;
}
width = Math.round(width);
height = Math.round(height);
var on_finish = function () {
var dataURL = temp_canvas.toDataURL();
img.width = width;
img.height = height;
img.src = dataURL;
delete dataURL;
delete temp_canvas;
};
//resize
if (multi_core == undefined || multi_core == true) {
this.resample(temp_canvas, width, height, true, on_finish);
} else {
this.resample_single(temp_canvas, width, height, true);
on_finish();
}
};
/**
* Hermite resize, multicore version - fast image resize/resample using Hermite filter.
*
* @param {HtmlElement} canvas
* @param {int} width
* @param {int} height
* @param {boolean} resize_canvas if true, canvas will be resized. Optional.
* @param {boolean} on_finish finish handler. Optional.
*/
this.resample = function (canvas, width, height, resize_canvas, on_finish) {
var width_source = canvas.width;
var height_source = canvas.height;
width = Math.round(width);
height = Math.round(height);
var ratio_h_half = Math.ceil(height_source / height / 2);
//stop old workers
if (workers_archive.length > 0) {
for (var c = 0; c < cores; c++) {
if (workers_archive[c] != undefined) {
workers_archive[c].terminate();
delete workers_archive[c];
}
}
}
workers_archive = new Array(cores);
var ctx = canvas.getContext('2d');
//prepare source and target data for workers
var source = new Array(cores);
var target = new Array(cores);
for (var c = 0; c < cores; c++) {
//source
var offset_y = Math.ceil(height_source / cores) * c;
var block_height = Math.ceil(height_source / cores) + ratio_h_half * cores;
if (offset_y + block_height > height_source) {
block_height = height_source - offset_y;
}
if (block_height < 1) {
//size too small, nothing left for this core
continue;
}
source[c] = ctx.getImageData(0, offset_y, width_source, block_height);
//target
offset_y = Math.ceil(height / cores) * c;
block_height = Math.ceil(height / cores);
if (offset_y + block_height > height) {
block_height = height - offset_y;
}
if (block_height < 1) {
//size too small, nothing left for this core
continue;
}
target[c] = true;
}
//clear and resize canvas
if (resize_canvas === true) {
canvas.width = width;
canvas.height = height;
} else {
ctx.clearRect(0, 0, width_source, height_source);
}
//start
var workers_in_use = 0;
for (var c = 0; c < cores; c++) {
if (target[c] == undefined) {
//no job for this worker
continue;
}
workers_in_use++;
var my_worker = new Worker(workerBlobURL);
workers_archive[c] = my_worker;
my_worker.onmessage = function (event) {
workers_in_use--;
var core = event.data.core;
delete workers_archive[core];
//draw
target[core] = ctx.createImageData(width, Math.ceil(height / cores));
target[core].data.set(event.data.target);
var y = Math.ceil(height / cores) * core;
ctx.putImageData(target[core], 0, y);
if (workers_in_use <= 0) {
//finish
on_finish();
}
};
var objData = {
width_source: width_source,
height_source: height_source,
width: width,
height: height,
core: c,
cores: cores,
source: source[c].data.buffer
};
my_worker.postMessage(objData, [objData.source]);
}
};
// Build a worker from an anonymous function body - purpose is to avoid separate file
workerBlobURL = URL.createObjectURL(new Blob(['(',
function () {
//begin worker
onmessage = function (event) {
var core = event.data.core;
var cores = event.data.cores;
var width_source = event.data.width_source;
var height_source = event.data.height_source;
var width = event.data.width;
var height = event.data.height;
var ratio_w = width_source / width;
var ratio_h = height_source / height;
var ratio_w_half = Math.ceil(ratio_w / 2);
var ratio_h_half = Math.ceil(ratio_h / 2);
var source = new Uint8ClampedArray(event.data.source);
var source_h = source.length / width_source / 4;
var target_size = width * Math.ceil(height / cores) * 4;
var target_memory = new ArrayBuffer(target_size);
var target = new Uint8ClampedArray(target_memory, 0, target_size);
//j position in original source = j + d_h - d_h_source;
var d_h_source = Math.ceil(height_source / cores) * core;
var d_h = Math.ceil(height / cores) * core;
//calculate
for (var j = 0; j < Math.ceil(height / cores); j++) {
for (var i = 0; i < width; i++) {
var x2 = (i + j * width) * 4;
var weight = 0;
var weights = 0;
var weights_alpha = 0;
var gx_r = 0;
var gx_g = 0;
var gx_b = 0;
var gx_a = 0;
var center_y = (d_h + j + 0.5) * ratio_h - d_h_source;
var yy_start = Math.floor(j * ratio_h);
var yy_stop = Math.ceil((d_h + j + 1) * ratio_h - d_h_source);
var xx_start = Math.floor(i * ratio_w);
var xx_stop = Math.ceil((i + 1) * ratio_w);
for (var yy = yy_start; yy < yy_stop; yy++) {
if (yy >= source_h || yy < 0) {
//extra border check
continue;
}
var dy = Math.abs(center_y - (yy + 0.5)) / ratio_h_half;
var center_x = (i + 0.5) * ratio_w;
var w0 = dy * dy; //pre-calc part of w
for (var xx = xx_start; xx < xx_stop; xx++) {
var dx = Math.abs(center_x - (xx + 0.5)) / ratio_w_half;
var w = Math.sqrt(w0 + dx * dx);
if (w >= 1) {
//pixel too far
continue;
}
//hermite filter
weight = 2 * w * w * w - 3 * w * w + 1;
//calc source pixel location
var pos_x = 4 * (xx + yy * width_source);
//alpha
gx_a += weight * source[pos_x + 3];
weights_alpha += weight;
//colors
if (source[pos_x + 3] < 255)
weight = weight * source[pos_x + 3] / 250;
gx_r += weight * source[pos_x];
gx_g += weight * source[pos_x + 1];
gx_b += weight * source[pos_x + 2];
weights += weight;
}
}
target[x2] = gx_r / weights;
target[x2 + 1] = gx_g / weights;
target[x2 + 2] = gx_b / weights;
target[x2 + 3] = gx_a / weights_alpha;
}
}
//return
var objData = {
core: core,
target: target
};
postMessage(objData, [target.buffer]);
};
//end worker
}.toString(),
')()'], {type: 'application/javascript'}));
/**
* Hermite resize - fast image resize/resample using Hermite filter. 1 cpu version!
*
* @param {HtmlElement} canvas
* @param {int} width
* @param {int} height
* @param {boolean} resize_canvas if true, canvas will be resized. Optional.
*/
this.resample_single = function (canvas, width, height, resize_canvas) {
var width_source = canvas.width;
var height_source = canvas.height;
width = Math.round(width);
height = Math.round(height);
var ratio_w = width_source / width;
var ratio_h = height_source / height;
var ratio_w_half = Math.ceil(ratio_w / 2);
var ratio_h_half = Math.ceil(ratio_h / 2);
var ctx = canvas.getContext('2d');
var img = ctx.getImageData(0, 0, width_source, height_source);
var img2 = ctx.createImageData(width, height);
var data = img.data;
var data2 = img2.data;
for (var j = 0; j < height; j++) {
for (var i = 0; i < width; i++) {
var x2 = (i + j * width) * 4;
var weight = 0;
var weights = 0;
var weights_alpha = 0;
var gx_r = 0;
var gx_g = 0;
var gx_b = 0;
var gx_a = 0;
var center_y = (j + 0.5) * ratio_h;
var yy_start = Math.floor(j * ratio_h);
var yy_stop = Math.ceil((j + 1) * ratio_h);
for (var yy = yy_start; yy < yy_stop; yy++) {
var dy = Math.abs(center_y - (yy + 0.5)) / ratio_h_half;
var center_x = (i + 0.5) * ratio_w;
var w0 = dy * dy; //pre-calc part of w
var xx_start = Math.floor(i * ratio_w);
var xx_stop = Math.ceil((i + 1) * ratio_w);
for (var xx = xx_start; xx < xx_stop; xx++) {
var dx = Math.abs(center_x - (xx + 0.5)) / ratio_w_half;
var w = Math.sqrt(w0 + dx * dx);
if (w >= 1) {
//pixel too far
continue;
}
//hermite filter
weight = 2 * w * w * w - 3 * w * w + 1;
var pos_x = 4 * (xx + yy * width_source);
//alpha
gx_a += weight * data[pos_x + 3];
weights_alpha += weight;
//colors
if (data[pos_x + 3] < 255)
weight = weight * data[pos_x + 3] / 250;
gx_r += weight * data[pos_x];
gx_g += weight * data[pos_x + 1];
gx_b += weight * data[pos_x + 2];
weights += weight;
}
}
data2[x2] = gx_r / weights;
data2[x2 + 1] = gx_g / weights;
data2[x2 + 2] = gx_b / weights;
data2[x2 + 3] = gx_a / weights_alpha;
}
}
//clear and resize canvas
if (resize_canvas === true) {
canvas.width = width;
canvas.height = height;
} else {
ctx.clearRect(0, 0, width_source, height_source);
}
//draw
ctx.putImageData(img2, 0, 0);
};
}
}
/*
* Hermite resize - fast image resize/resample using Hermite filter.
* https://github.com/viliusle/Hermite-resize
*/
function Hermite_class() {
var cores;
var workers_archive = [];
var workerBlobURL;
/**
* contructor
*/
this.init = function () {
cores = navigator.hardwareConcurrency || 4;
}();
/**
* Returns CPU cores count
*
* @returns {int}
*/
this.getCores = function () {
return cores;
};
/**
* Hermite resize. Detect cpu count and use best option for user.
*
* @param {HtmlElement} canvas
* @param {int} width
* @param {int} height
* @param {boolean} resize_canvas if true, canvas will be resized. Optional.
* @param {boolean} on_finish finish handler. Optional.
*/
this.resample_auto = function (canvas, width, height, resize_canvas, on_finish) {
var cores = this.getCores();
if (!!window.Worker && cores > 1) {
//workers supported and we have at least 2 cpu cores - using multithreading
this.resample(canvas, width, height, resize_canvas, on_finish);
}
else {
//1 cpu version
this.resample_single(canvas, width, height, true);
if (on_finish != undefined) {
on_finish();
}
}
};
/**
* Hermite resize. Resize actual image.
*
* @param {string} image_id
* @param {int} width
* @param {int} height optional.
* @param {int} percentages optional.
* @param {string} multi_core optional.
*/
this.resize_image = function (image_id, width, height, percentages, multi_core) {
var img = document.getElementById(image_id);
//create temp canvas
var temp_canvas = document.createElement("canvas");
temp_canvas.width = img.width;
temp_canvas.height = img.height;
var temp_ctx = temp_canvas.getContext("2d");
//draw image
temp_ctx.drawImage(img, 0, 0);
//prepare size
if (width == undefined && height == undefined && percentages != undefined) {
width = img.width / 100 * percentages;
height = img.height / 100 * percentages;
}
if (height == undefined) {
var ratio = img.width / width;
height = img.height / ratio;
}
width = Math.round(width);
height = Math.round(height);
var on_finish = function () {
var dataURL = temp_canvas.toDataURL();
img.width = width;
img.height = height;
img.src = dataURL;
dataURL = null;
temp_canvas = null;
};
//resize
if (multi_core == undefined || multi_core == true) {
this.resample(temp_canvas, width, height, true, on_finish);
}
else {
this.resample_single(temp_canvas, width, height, true);
on_finish();
}
};
/**
* Hermite resize, multicore version - fast image resize/resample using Hermite filter.
*
* @param {HtmlElement} canvas
* @param {int} width
* @param {int} height
* @param {boolean} resize_canvas if true, canvas will be resized. Optional.
* @param {boolean} on_finish finish handler. Optional.
*/
this.resample = function (canvas, width, height, resize_canvas, on_finish) {
var width_source = canvas.width;
var height_source = canvas.height;
width = Math.round(width);
height = Math.round(height);
var ratio_h = height_source / height;
//stop old workers
if (workers_archive.length > 0) {
for (var c = 0; c < cores; c++) {
if (workers_archive[c] != undefined) {
workers_archive[c].terminate();
delete workers_archive[c];
}
}
}
workers_archive = new Array(cores);
var ctx = canvas.getContext("2d");
//prepare source and target data for workers
var data_part = [];
var block_height = Math.ceil(height_source / cores / 2) * 2;
var end_y = -1;
for (var c = 0; c < cores; c++) {
//source
var offset_y = end_y + 1;
if (offset_y >= height_source) {
//size too small, nothing left for this core
continue;
}
end_y = offset_y + block_height - 1;
end_y = Math.min(end_y, height_source - 1);
var current_block_height = block_height;
current_block_height = Math.min(block_height, height_source - offset_y);
//console.log('source split: ', '#'+c, offset_y, end_y, 'height: '+current_block_height);
data_part[c] = {};
data_part[c].source = ctx.getImageData(0, offset_y, width_source, block_height);
data_part[c].target = true;
data_part[c].start_y = Math.ceil(offset_y / ratio_h);
data_part[c].height = current_block_height;
}
//clear and resize canvas
if (resize_canvas === true) {
canvas.width = width;
canvas.height = height;
}
else {
ctx.clearRect(0, 0, width_source, height_source);
}
//start
var workers_in_use = 0;
for (var c = 0; c < cores; c++) {
if (data_part[c] == undefined) {
//no job for this worker
continue;
}
workers_in_use++;
var my_worker = new Worker(workerBlobURL);
workers_archive[c] = my_worker;
my_worker.onmessage = function (event) {
workers_in_use--;
var core = event.data.core;
workers_archive[core].terminate();
delete workers_archive[core];
//draw
var height_part = Math.ceil(data_part[core].height / ratio_h);
data_part[core].target = ctx.createImageData(width, height_part);
data_part[core].target.data.set(event.data.target);
ctx.putImageData(data_part[core].target, 0, data_part[core].start_y);
if (workers_in_use <= 0) {
//finish
if (on_finish != undefined) {
on_finish();
}
}
};
var objData = {
width_source: width_source,
height_source: data_part[c].height,
width: width,
height: Math.ceil(data_part[c].height / ratio_h),
core: c,
source: data_part[c].source.data.buffer,
};
my_worker.postMessage(objData, [objData.source]);
}
};
// Build a worker from an anonymous function body - purpose is to avoid separate file
workerBlobURL = window.URL.createObjectURL(new Blob(['(',
function () {
//begin worker
onmessage = function (event) {
var core = event.data.core;
var width_source = event.data.width_source;
var height_source = event.data.height_source;
var width = event.data.width;
var height = event.data.height;
var ratio_w = width_source / width;
var ratio_h = height_source / height;
var ratio_w_half = Math.ceil(ratio_w / 2);
var ratio_h_half = Math.ceil(ratio_h / 2);
var source = new Uint8ClampedArray(event.data.source);
var source_h = source.length / width_source / 4;
var target_size = width * height * 4;
var target_memory = new ArrayBuffer(target_size);
var target = new Uint8ClampedArray(target_memory, 0, target_size);
//calculate
for (var j = 0; j < height; j++) {
for (var i = 0; i < width; i++) {
var x2 = (i + j * width) * 4;
var weight = 0;
var weights = 0;
var weights_alpha = 0;
var gx_r = 0;
var gx_g = 0;
var gx_b = 0;
var gx_a = 0;
var center_y = j * ratio_h;
var xx_start = Math.floor(i * ratio_w);
var xx_stop = Math.ceil((i + 1) * ratio_w);
var yy_start = Math.floor(j * ratio_h);
var yy_stop = Math.ceil((j + 1) * ratio_h);
xx_stop = Math.min(xx_stop, width_source);
yy_stop = Math.min(yy_stop, height_source);
for (var yy = yy_start; yy < yy_stop; yy++) {
var dy = Math.abs(center_y - yy) / ratio_h_half;
var center_x = i * ratio_w;
var w0 = dy * dy; //pre-calc part of w
for (var xx = xx_start; xx < xx_stop; xx++) {
var dx = Math.abs(center_x - xx) / ratio_w_half;
var w = Math.sqrt(w0 + dx * dx);
if (w >= 1) {
//pixel too far
continue;
}
//hermite filter
weight = 2 * w * w * w - 3 * w * w + 1;
//calc source pixel location
var pos_x = 4 * (xx + yy * width_source);
//alpha
gx_a += weight * source[pos_x + 3];
weights_alpha += weight;
//colors
if (source[pos_x + 3] < 255)
weight = weight * source[pos_x + 3] / 250;
gx_r += weight * source[pos_x];
gx_g += weight * source[pos_x + 1];
gx_b += weight * source[pos_x + 2];
weights += weight;
}
}
target[x2] = gx_r / weights;
target[x2 + 1] = gx_g / weights;
target[x2 + 2] = gx_b / weights;
target[x2 + 3] = gx_a / weights_alpha;
}
}
//return
var objData = {
core: core,
target: target,
};
postMessage(objData, [target.buffer]);
};
//end worker
}.toString(),
')()'], {type: 'application/javascript'}));
/**
* Hermite resize - fast image resize/resample using Hermite filter. 1 cpu version!
*
* @param {HtmlElement} canvas
* @param {int} width
* @param {int} height
* @param {boolean} resize_canvas if true, canvas will be resized. Optional.
*/
this.resample_single = function (canvas, width, height, resize_canvas) {
var width_source = canvas.width;
var height_source = canvas.height;
width = Math.round(width);
height = Math.round(height);
var ratio_w = width_source / width;
var ratio_h = height_source / height;
var ratio_w_half = Math.ceil(ratio_w / 2);
var ratio_h_half = Math.ceil(ratio_h / 2);
var ctx = canvas.getContext("2d");
var img = ctx.getImageData(0, 0, width_source, height_source);
var img2 = ctx.createImageData(width, height);
var data = img.data;
var data2 = img2.data;
for (var j = 0; j < height; j++) {
for (var i = 0; i < width; i++) {
var x2 = (i + j * width) * 4;
var weight = 0;
var weights = 0;
var weights_alpha = 0;
var gx_r = 0;
var gx_g = 0;
var gx_b = 0;
var gx_a = 0;
var center_y = j * ratio_h;
var xx_start = Math.floor(i * ratio_w);
var xx_stop = Math.ceil((i + 1) * ratio_w);
var yy_start = Math.floor(j * ratio_h);
var yy_stop = Math.ceil((j + 1) * ratio_h);
xx_stop = Math.min(xx_stop, width_source);
yy_stop = Math.min(yy_stop, height_source);
for (var yy = yy_start; yy < yy_stop; yy++) {
var dy = Math.abs(center_y - yy) / ratio_h_half;
var center_x = i * ratio_w;
var w0 = dy * dy; //pre-calc part of w
for (var xx = xx_start; xx < xx_stop; xx++) {
var dx = Math.abs(center_x - xx) / ratio_w_half;
var w = Math.sqrt(w0 + dx * dx);
if (w >= 1) {
//pixel too far
continue;
}
//hermite filter
weight = 2 * w * w * w - 3 * w * w + 1;
var pos_x = 4 * (xx + yy * width_source);
//alpha
gx_a += weight * data[pos_x + 3];
weights_alpha += weight;
//colors
if (data[pos_x + 3] < 255)
weight = weight * data[pos_x + 3] / 250;
gx_r += weight * data[pos_x];
gx_g += weight * data[pos_x + 1];
gx_b += weight * data[pos_x + 2];
weights += weight;
}
}
data2[x2] = gx_r / weights;
data2[x2 + 1] = gx_g / weights;
data2[x2 + 2] = gx_b / weights;
data2[x2 + 3] = gx_a / weights_alpha;
}
}
//clear and resize canvas
if (resize_canvas === true) {
canvas.width = width;
canvas.height = height;
}
else {
ctx.clearRect(0, 0, width_source, height_source);
}
//draw
ctx.putImageData(img2, 0, 0);
};
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.images .image {
border: 1px solid red;
display: inline-flex;
align-items: center;
justify-content: center;
margin: 5px;
position: relative;
overflow: hidden;
}
.images .image span {
display: block;
position: absolute;
top: 10px;
left: 10px;
background-color: #1D1D1D;
color: #FFFFFF;
padding: 3px 5px;
}
.images .image canvas {
image-rendering: pixelated;
height: auto;
}
#s124x74 {width: 124px; height: 74px;}
#s180x108 {width: 180px; height: 108px;}
#s256x114 {width: 256px; height: 114px;}
#s320x160 {width: 320px; height: 160px;}
#s715x210 {width: 715px; height: 210px;}
#s800x400 {width: 800px; height: 400px;}
#s1000x310 {width: 1000px; height: 310px;}
#s1024x400 {width: 1024px; height: 400px;}
#s1920x1080 {width: 1920px; height: 1080px;}
</style>
</head>
<body>
<div class="images">
<div class="image" id="s124x74"><span>124x74</span>
<canvas></canvas>
</div>
<div class="image" id="s180x108"><span>180x108</span>
<canvas></canvas>
</div>
<div class="image" id="s256x114"><span>256x114</span>
<canvas></canvas>
</div>
<div class="image" id="s320x160"><span>320x160</span>
<canvas></canvas>
</div>
<div class="image" id="s715x210"><span>715x210</span>
<canvas></canvas>
</div>
<div class="image" id="s800x400"><span>800x400</span>
<canvas></canvas>
</div>
<div class="image" id="s1000x310"><span>1000x310</span>
<canvas></canvas>
</div>
<div class="image" id="s1024x400"><span>1024x400</span>
<canvas></canvas>
</div>
<div class="image" id="s1920x1080"><span>1920x1080</span>
<canvas></canvas>
</div>
</div>
<script src="hermite.js"></script>
<script src="app.js"></script>
<script>
let _sizes = [
[1024, 400],
[1000, 310],
[800, 400],
[715, 210],
[320, 160],
[256, 114],
[180, 108],
[124, 74]
];
_sizes.forEach((size) => {
let _path = 'https://i.imgur.com/1OyMrXd.jpg';
let _id = 's' + size.join('x');
let _width = size[0];
let _element = document.getElementById(_id);
let _canvas = _element.children[1];
resize(_path, _canvas, _width);
});
</script>
</body>
</html>
@andrey-helldar
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment