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 = {
|
||||
createWorker : function (worker, workerId) {
|
||||
if (!workers[workerId]) {
|
||||
var typedArray = [(worker+"").replace(/function \(\)\s?\{/,"").replace(/\}[^}]*$/, "")];
|
||||
var blob = new Blob(typedArray, {type: "application/javascript"}); // pass a useful mime type here
|
||||
workers[workerId] = window.URL.createObjectURL(blob);
|
||||
workers[workerId] = ns.WorkerUtils.createWorkerURL(worker);
|
||||
}
|
||||
|
||||
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",
|
||||
|
||||
// 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
|
||||
"js/app.js",
|
||||
|
Loading…
Reference in New Issue
Block a user