patternjavascriptMinor
Image manipulation using HTML5 Canvas
Viewed 0 times
imagehtml5manipulationusingcanvas
Problem
I have recently started researching some computer vision, and in the process of discovering some interesting things I have been compiling some functions that allow me to manipulate images at a low level. I am not interested in replacing any of these functions with already existing, built-in functionality of canvas (but if there are some it is always interesting to learn about them), I am trying to get a bit more low-level here.
I usually do front-ends of feature sites, so I have only cursory experience with the creation of large libraries, and I am wondering whether the style of code and way of implementing it is acceptable and what could - and what should - be improved. I have tested these functions and they do what I intended, so to me it is not about how they function precisely (I am not a mathematician, and I'm sure mathematicians can figure out better and more clever ways to reach these results). By all means, tell me about better ways, but I am trying to see if this would work as a library. I am not afraid to change functions to use core canvas constructs, but my reason for building this was to learn to manipulate pixel based graphics myself, without someone who has written native code for me.
If you run the snippet you will see some use case examples (in order of code they are: normal, blur (radius of 2), grayscale, desaturate (50%) and colour channel (red) - although they may appear in different order depending on which one loads faster). I had to base64 encode an image as I couldn't find a way around cross-origin restrictions otherwise, but of course it works with local loading of images.
The end result would be that you could use this to load an image and apply some effects, and then insert it into the DOM with the following syntax:
Usage
```
var myImage = new ImageManipulation({
image: 'http::domain.tld/image.ext',
callback: function(Image){
// Manipulate the image on load and append to DOM
Image.Blur(2).Desaturate(55).DOM(doc
I usually do front-ends of feature sites, so I have only cursory experience with the creation of large libraries, and I am wondering whether the style of code and way of implementing it is acceptable and what could - and what should - be improved. I have tested these functions and they do what I intended, so to me it is not about how they function precisely (I am not a mathematician, and I'm sure mathematicians can figure out better and more clever ways to reach these results). By all means, tell me about better ways, but I am trying to see if this would work as a library. I am not afraid to change functions to use core canvas constructs, but my reason for building this was to learn to manipulate pixel based graphics myself, without someone who has written native code for me.
If you run the snippet you will see some use case examples (in order of code they are: normal, blur (radius of 2), grayscale, desaturate (50%) and colour channel (red) - although they may appear in different order depending on which one loads faster). I had to base64 encode an image as I couldn't find a way around cross-origin restrictions otherwise, but of course it works with local loading of images.
The end result would be that you could use this to load an image and apply some effects, and then insert it into the DOM with the following syntax:
Usage
```
var myImage = new ImageManipulation({
image: 'http::domain.tld/image.ext',
callback: function(Image){
// Manipulate the image on load and append to DOM
Image.Blur(2).Desaturate(55).DOM(doc
Solution
Miscellaneous Points:
-
Instead of using just
-
The following can be converted to a one-liner:
into something like:
into:
Additionally, there is a
-
You don't need to define
into:
or, another fun way is to use an object, like so:
the same applies to the following:
-
For the work you've put into it, consider giving it a sleek name, instead of
Use the following format instead:
Your structure:
You're currently indenting all your declarations with a large amount of space. Stop it. By following my last point, you can avoid that kind of behaviour all together, but really, it's horrible.
And sometimes you mess it up.
I would consider taking a look at Caman.JS, a image manipulation library with similar features to the one you've made.
- As you're writing a library, it's best to match as many edge cases as you can, and to check if
documenteven exists.
if (!document) throw new Error("the document could not be found");-
Instead of using just
throw use throw new Error() instead, as that allows for a stack trace to find exactly where the problem stems.-
The following can be converted to a one-liner:
if(!this.src)
throw('Initialisation failed: no image in options.');- Single line comments should be written with
//instead of/ ... /:
/* Canvas for input. */- The following block should be removed, instead of a large block like that, you should just have a quick paragraph or even sentence about what the function is:
/***********************************************************/
/********************** Core Functions *********************/
/***********************************************************/into something like:
/* This part of the library houses the core functions,
* ... more stuff here ...
*/- The following can be converted to a ternary statement, and it's also missing space:
if(addLine id+1){
return false;
} else {
return add;
}into:
return (addLine id + 1) ? false : add;- You need to add spaces between your operators, like in the snippet below:
angle = angle%360;Additionally, there is a
%= operator, so it can become this:angle %= 360- In the following code block, there's two points to make:
getPixelAtAxisFromPixel: function(id, angle){
var add, angle, addLine, Self;
Self = this.Self || {width: 0};- You're redefining
angle(literally pointless)
-
You don't need to define
Self with the others, define it on the second line.- You should be using a
switchhere, instead of anifblock, which would be incorrectly formatted anyway (you should've usedelse-ifs aschannelcould only take one of those forms:
if(channel == 'r') channel = 0;
if(channel == 'g') channel = 1;
if(channel == 'b') channel = 2;
if(channel == 'a') channel = 3;into:
switch(channel){
case 'r': channel = 0; break;
case 'g': channel = 1; break;
case 'b': channel = 2; break;
case 'a': channel = 3; break;
}or, another fun way is to use an object, like so:
var channelSwap = {r: 0, g: 1, b: 2, a: 3};
channel = channelSwap[channel];forHumans uses different values for human perception.this is confusing, but not nearly as much as the following:
forHumans = forHumans
? [.3,.4,.3]
: [(1/3),(1/3),(1/3)];- As all three statements end the block, the last
elsecase is superfluous:
if(!this.ready){
if(callee){
this.Throw(callee + " called before ready. Use callback to ensure readiness.");
}
return false;
} else {
return this;
}the same applies to the following:
if(element){
element.appendChild(this.output);
return true;
} else {
return this.output;
}-
For the work you've put into it, consider giving it a sleek name, instead of
ImageManipulation- Instead of using your current format of:
ImageManipulation.prototype = {
init: function(){},
...
Support: function(){}
}Use the following format instead:
ImageManipulation.prototype.init = function(){};
...
ImageManipulation.prototype.Support = function(){};Your structure:
You're currently indenting all your declarations with a large amount of space. Stop it. By following my last point, you can avoid that kind of behaviour all together, but really, it's horrible.
And sometimes you mess it up.
var alpha = channel == 3 ? this.source.data[i+3] : 0;
this.resource.data[i] = channel == 0 ? this.source.data[i] : alpha;
this.resource.data[i+1] = channel == 1 ? this.source.data[i+1] : alpha;
this.resource.data[i+2] = channel == 2 ? this.source.data[i+2] : alpha;
this.resource.data[i+3] = 255;I would consider taking a look at Caman.JS, a image manipulation library with similar features to the one you've made.
Code Snippets
if (!document) throw new Error("the document could not be found");if(!this.src)
throw('Initialisation failed: no image in options.');/* Canvas for input. *//***********************************************************/
/********************** Core Functions *********************/
/***********************************************************//* This part of the library houses the core functions,
* ... more stuff here ...
*/Context
StackExchange Code Review Q#97013, answer score: 4
Revisions (0)
No revisions yet.