mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
WIP : Use workers to compute hash and current colors
This commit is contained in:
parent
40cced7be0
commit
9e6e39e3d8
@ -6,12 +6,17 @@
|
|||||||
ns.WorkerUtils = {
|
ns.WorkerUtils = {
|
||||||
createWorker : function (worker, workerId) {
|
createWorker : function (worker, workerId) {
|
||||||
if (!workers[workerId]) {
|
if (!workers[workerId]) {
|
||||||
var typedArray = [(worker+"").replace(/function \(\)\s?\{/,"").replace(/\}[^}]*$/, "")];
|
workers[workerId] = ns.WorkerUtils.createWorkerURL(worker);
|
||||||
var blob = new Blob(typedArray, {type: "application/javascript"}); // pass a useful mime type here
|
|
||||||
workers[workerId] = window.URL.createObjectURL(blob);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Worker(workers[workerId]);
|
return new Worker(workers[workerId]);
|
||||||
|
},
|
||||||
|
|
||||||
|
createWorkerURL : function (worker) {
|
||||||
|
// remove "function () {" at the start of the worker string and the last "}" before the end
|
||||||
|
var typedArray = [(worker+"").replace(/function\s*\(\)\s*\{/,"").replace(/\}[^}]*$/, "")];
|
||||||
|
var blob = new Blob(typedArray, {type: "application/javascript"});
|
||||||
|
return window.URL.createObjectURL(blob);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
@ -1,5 +0,0 @@
|
|||||||
(function () {
|
|
||||||
var ns = $.namespace('pskl.worker');
|
|
||||||
|
|
||||||
ns.HashBuilder = function () {};
|
|
||||||
})();
|
|
@ -1,177 +0,0 @@
|
|||||||
(function () {
|
|
||||||
var ns = $.namespace('pskl.worker');
|
|
||||||
|
|
||||||
var imageProcessorWorker = function () {
|
|
||||||
var currentStep, currentProgress, currentTotal;
|
|
||||||
|
|
||||||
var initStepCounter_ = function (total) {
|
|
||||||
currentStep = 0;
|
|
||||||
currentProgress = 0;
|
|
||||||
currentTotal = total;
|
|
||||||
};
|
|
||||||
|
|
||||||
var postStep_ = function () {
|
|
||||||
currentStep = currentStep + 1;
|
|
||||||
var progress = ((currentStep / currentTotal) *100).toFixed(1);
|
|
||||||
if (progress != currentProgress) {
|
|
||||||
currentProgress = progress;
|
|
||||||
this.postMessage({
|
|
||||||
type : 'STEP',
|
|
||||||
progress : currentProgress,
|
|
||||||
currentStep : currentStep,
|
|
||||||
total : currentTotal
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var rgbToHex = function (r, g, b) {
|
|
||||||
return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
|
|
||||||
};
|
|
||||||
|
|
||||||
var componentToHex = function (c) {
|
|
||||||
var hex = c.toString(16);
|
|
||||||
return hex.length == 1 ? "0" + hex : hex;
|
|
||||||
};
|
|
||||||
|
|
||||||
var imageDataToGrid = function (imageData, width, height, transparent) {
|
|
||||||
// Draw the zoomed-up pixels to a different canvas context
|
|
||||||
var grid = [];
|
|
||||||
for (var x = 0 ; x < width ; x++){
|
|
||||||
grid[x] = [];
|
|
||||||
postStep_();
|
|
||||||
for (var y = 0 ; y < height ; y++){
|
|
||||||
// Find the starting index in the one-dimensional image data
|
|
||||||
var i = (y * width + x)*4;
|
|
||||||
var r = imageData[i ];
|
|
||||||
var g = imageData[i+1];
|
|
||||||
var b = imageData[i+2];
|
|
||||||
var a = imageData[i+3];
|
|
||||||
if (a < 125) {
|
|
||||||
grid[x][y] = transparent;
|
|
||||||
} else {
|
|
||||||
grid[x][y] = rgbToHex(r,g,b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return grid;
|
|
||||||
};
|
|
||||||
|
|
||||||
var getColorsMapFromImageData = function (imageData, width, height) {
|
|
||||||
var grid = imageDataToGrid(imageData, width, height, 'transparent');
|
|
||||||
|
|
||||||
var colorsMap = {};
|
|
||||||
for (var i = 0 ; i < grid.length ; i++) {
|
|
||||||
postStep_();
|
|
||||||
for (var j = 0 ; j < grid[i].length ; j++) {
|
|
||||||
var color = grid[i][j];
|
|
||||||
if (color != 'transparent') {
|
|
||||||
colorsMap[color] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return colorsMap;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.onmessage = function(event) {
|
|
||||||
try {
|
|
||||||
var data = event.data;
|
|
||||||
|
|
||||||
initStepCounter_(data.width * 2);
|
|
||||||
|
|
||||||
var colorsMap = getColorsMapFromImageData(data.imageData, data.width, data.height);
|
|
||||||
|
|
||||||
this.postMessage({
|
|
||||||
type : 'SUCCESS',
|
|
||||||
colorsMap : colorsMap
|
|
||||||
});
|
|
||||||
} catch(e) {
|
|
||||||
this.postMessage({
|
|
||||||
type : 'ERROR',
|
|
||||||
message : e.message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
ns.ImageProcessor = function (image, onSuccess, onStep, onError) {
|
|
||||||
this.image = image;
|
|
||||||
|
|
||||||
this.onStep = onStep;
|
|
||||||
this.onSuccess = onSuccess;
|
|
||||||
this.onError = onError;
|
|
||||||
|
|
||||||
// var worker = pskl.utils.WorkerUtils.addPartialWorker(imageProcessorWorker, 'step-counter');
|
|
||||||
this.worker = pskl.utils.WorkerUtils.createWorker(imageProcessorWorker, 'image-colors-processor');
|
|
||||||
this.worker.onmessage = this.onWorkerMessage.bind(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
ns.ImageProcessor.prototype.process = function () {
|
|
||||||
var canvas = pskl.utils.CanvasUtils.createFromImage(this.image);
|
|
||||||
var imageData = pskl.utils.CanvasUtils.getImageDataFromCanvas(canvas);
|
|
||||||
this.worker.postMessage({
|
|
||||||
imageData : imageData,
|
|
||||||
width : this.image.width,
|
|
||||||
height : this.image.height
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
ns.ImageProcessor.prototype.createNamespace = function (name) {
|
|
||||||
var createNamespace = (function () {
|
|
||||||
var parts = name.split('.');
|
|
||||||
if (parts.length > 0) {
|
|
||||||
var node = this;
|
|
||||||
for (var i = 0 ; i < parts.length ; i++) {
|
|
||||||
if (!node[parts[i]]) {
|
|
||||||
node[parts[i]] = {};
|
|
||||||
}
|
|
||||||
node = node[parts[i]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
var script = createNamespace + "";
|
|
||||||
script = script.replace(/function \(\) \{/,"").replace(/\}[^}]*$/, "");
|
|
||||||
script = "var name = '" + name + "';" + script;
|
|
||||||
|
|
||||||
this.runScript(script);
|
|
||||||
};
|
|
||||||
|
|
||||||
ns.ImageProcessor.prototype.onWorkerMessage = function (event) {
|
|
||||||
if (event.data.type === 'STEP') {
|
|
||||||
this.onStep(event);
|
|
||||||
} else if (event.data.type === 'SUCCESS') {
|
|
||||||
this.onSuccess(event);
|
|
||||||
this.worker.terminate();
|
|
||||||
} else if (event.data.type === 'ERROR') {
|
|
||||||
this.onError(event);
|
|
||||||
this.worker.terminate();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ns.ImageProcessor.prototype.importAll__ = function (classToImport, classpath) {
|
|
||||||
this.createNamespace(classpath);
|
|
||||||
for (var key in classToImport) {
|
|
||||||
if (classToImport.hasOwnProperty(key)) {
|
|
||||||
this.addMethod(classToImport[key], classpath + '.' + key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ns.ImageProcessor.prototype.addMethod__ = function (method, name) {
|
|
||||||
this.runScript(name + "=" + method);
|
|
||||||
};
|
|
||||||
|
|
||||||
ns.ImageProcessor.prototype.runScript__ = function (script) {
|
|
||||||
this.worker.postMessage({
|
|
||||||
type : 'RUN_SCRIPT',
|
|
||||||
script : this.getScriptAsUrl(script)
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
ns.ImageProcessor.prototype.getScriptAsUrl__ = function (script) {
|
|
||||||
var blob = new Blob([script], {type: "application/javascript"}); // pass a useful mime type here
|
|
||||||
return window.URL.createObjectURL(blob);
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
32
src/js/worker/hash/Hash.js
Normal file
32
src/js/worker/hash/Hash.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
(function () {
|
||||||
|
var ns = $.namespace('pskl.worker.hash');
|
||||||
|
|
||||||
|
ns.Hash = function (str, onSuccess, onStep, onError) {
|
||||||
|
this.str = str;
|
||||||
|
|
||||||
|
this.onStep = onStep;
|
||||||
|
this.onSuccess = onSuccess;
|
||||||
|
this.onError = onError;
|
||||||
|
|
||||||
|
this.worker = pskl.utils.WorkerUtils.createWorker(ns.HashWorker, 'hash-builder');
|
||||||
|
this.worker.onmessage = this.onWorkerMessage.bind(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.Hash.prototype.process = function () {
|
||||||
|
this.worker.postMessage({
|
||||||
|
str : this.str
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.Hash.prototype.onWorkerMessage = function (event) {
|
||||||
|
if (event.data.type === 'STEP') {
|
||||||
|
this.onStep(event);
|
||||||
|
} else if (event.data.type === 'SUCCESS') {
|
||||||
|
this.onSuccess(event);
|
||||||
|
this.worker.terminate();
|
||||||
|
} else if (event.data.type === 'ERROR') {
|
||||||
|
this.onError(event);
|
||||||
|
this.worker.terminate();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
34
src/js/worker/hash/HashWorker.js
Normal file
34
src/js/worker/hash/HashWorker.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
(function () {
|
||||||
|
var ns = $.namespace('pskl.worker');
|
||||||
|
|
||||||
|
ns.HashBuilder = function () {
|
||||||
|
var hashCode = function(str) {
|
||||||
|
var hash = 0;
|
||||||
|
if (str.length !== 0) {
|
||||||
|
for (var i = 0, l = str.length; i < l; i++) {
|
||||||
|
var chr = str.charCodeAt(i);
|
||||||
|
hash = ((hash << 5) - hash) + chr;
|
||||||
|
hash |= 0; // Convert to 32bit integer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onmessage = function(event) {
|
||||||
|
try {
|
||||||
|
var data = event.data;
|
||||||
|
var str = data.str;
|
||||||
|
var hash = hashCode(str);
|
||||||
|
this.postMessage({
|
||||||
|
type : 'SUCCESS',
|
||||||
|
hash : hash
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
this.postMessage({
|
||||||
|
type : 'ERROR',
|
||||||
|
message : e.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
39
src/js/worker/imageprocessor/ImageProcessor.js
Normal file
39
src/js/worker/imageprocessor/ImageProcessor.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
(function () {
|
||||||
|
var ns = $.namespace('pskl.worker.imageprocessor');
|
||||||
|
|
||||||
|
ns.ImageProcessor = function (image, onSuccess, onStep, onError) {
|
||||||
|
this.image = image;
|
||||||
|
|
||||||
|
this.onStep = onStep;
|
||||||
|
this.onSuccess = onSuccess;
|
||||||
|
this.onError = onError;
|
||||||
|
|
||||||
|
this.worker = pskl.utils.WorkerUtils.createWorker(ns.ImageProcessorWorker, 'image-colors-processor');
|
||||||
|
this.worker.onmessage = this.onWorkerMessage.bind(this);
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.ImageProcessor.prototype.process = function () {
|
||||||
|
var canvas = pskl.utils.CanvasUtils.createFromImage(this.image);
|
||||||
|
var imageData = pskl.utils.CanvasUtils.getImageDataFromCanvas(canvas);
|
||||||
|
this.worker.postMessage({
|
||||||
|
imageData : imageData,
|
||||||
|
width : this.image.width,
|
||||||
|
height : this.image.height
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.ImageProcessor.prototype.onWorkerMessage = function (event) {
|
||||||
|
if (event.data.type === 'STEP') {
|
||||||
|
this.onStep(event);
|
||||||
|
} else if (event.data.type === 'SUCCESS') {
|
||||||
|
this.onSuccess(event);
|
||||||
|
this.worker.terminate();
|
||||||
|
} else if (event.data.type === 'ERROR') {
|
||||||
|
this.onError(event);
|
||||||
|
this.worker.terminate();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
|
98
src/js/worker/imageprocessor/ImageProcessorWorker.js
Normal file
98
src/js/worker/imageprocessor/ImageProcessorWorker.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
(function () {
|
||||||
|
var ns = $.namespace('pskl.worker.imageprocessor');
|
||||||
|
|
||||||
|
ns.ImageProcessorWorker = function () {
|
||||||
|
var currentStep, currentProgress, currentTotal;
|
||||||
|
|
||||||
|
var initStepCounter_ = function (total) {
|
||||||
|
currentStep = 0;
|
||||||
|
currentProgress = 0;
|
||||||
|
currentTotal = total;
|
||||||
|
};
|
||||||
|
|
||||||
|
var postStep_ = function () {
|
||||||
|
currentStep = currentStep + 1;
|
||||||
|
var progress = ((currentStep / currentTotal) *100).toFixed(1);
|
||||||
|
if (progress != currentProgress) {
|
||||||
|
currentProgress = progress;
|
||||||
|
this.postMessage({
|
||||||
|
type : 'STEP',
|
||||||
|
progress : currentProgress,
|
||||||
|
currentStep : currentStep,
|
||||||
|
total : currentTotal
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var rgbToHex = function (r, g, b) {
|
||||||
|
return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
|
||||||
|
};
|
||||||
|
|
||||||
|
var componentToHex = function (c) {
|
||||||
|
var hex = c.toString(16);
|
||||||
|
return hex.length == 1 ? "0" + hex : hex;
|
||||||
|
};
|
||||||
|
|
||||||
|
var imageDataToGrid = function (imageData, width, height, transparent) {
|
||||||
|
// Draw the zoomed-up pixels to a different canvas context
|
||||||
|
var grid = [];
|
||||||
|
for (var x = 0 ; x < width ; x++){
|
||||||
|
grid[x] = [];
|
||||||
|
postStep_();
|
||||||
|
for (var y = 0 ; y < height ; y++){
|
||||||
|
// Find the starting index in the one-dimensional image data
|
||||||
|
var i = (y * width + x)*4;
|
||||||
|
var r = imageData[i ];
|
||||||
|
var g = imageData[i+1];
|
||||||
|
var b = imageData[i+2];
|
||||||
|
var a = imageData[i+3];
|
||||||
|
if (a < 125) {
|
||||||
|
grid[x][y] = transparent;
|
||||||
|
} else {
|
||||||
|
grid[x][y] = rgbToHex(r,g,b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return grid;
|
||||||
|
};
|
||||||
|
|
||||||
|
var getColorsMapFromImageData = function (imageData, width, height) {
|
||||||
|
var grid = imageDataToGrid(imageData, width, height, 'transparent');
|
||||||
|
|
||||||
|
var colorsMap = {};
|
||||||
|
for (var i = 0 ; i < grid.length ; i++) {
|
||||||
|
postStep_();
|
||||||
|
for (var j = 0 ; j < grid[i].length ; j++) {
|
||||||
|
var color = grid[i][j];
|
||||||
|
if (color != 'transparent') {
|
||||||
|
colorsMap[color] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return colorsMap;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onmessage = function(event) {
|
||||||
|
try {
|
||||||
|
var data = event.data;
|
||||||
|
|
||||||
|
initStepCounter_(data.width * 2);
|
||||||
|
|
||||||
|
var colorsMap = getColorsMapFromImageData(data.imageData, data.width, data.height);
|
||||||
|
|
||||||
|
this.postMessage({
|
||||||
|
type : 'SUCCESS',
|
||||||
|
colorsMap : colorsMap
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
this.postMessage({
|
||||||
|
type : 'ERROR',
|
||||||
|
message : e.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -185,7 +185,10 @@
|
|||||||
"js/devtools/init.js",
|
"js/devtools/init.js",
|
||||||
|
|
||||||
// Workers
|
// Workers
|
||||||
"js/worker/ImageProcessor.js",
|
"js/worker/hash/HashWorker.js",
|
||||||
|
"js/worker/hash/Hash.js",
|
||||||
|
"js/worker/imageprocessor/ImageProcessorWorker.js",
|
||||||
|
"js/worker/imageprocessor/ImageProcessor.js",
|
||||||
|
|
||||||
// Application controller and initialization
|
// Application controller and initialization
|
||||||
"js/app.js",
|
"js/app.js",
|
||||||
|
Loading…
Reference in New Issue
Block a user