meltingice / CamanJS

Javascript HTML5 (Ca)nvas (Man)ipulation
http://camanjs.com
BSD 3-Clause "New" or "Revised" License
3.55k stars 404 forks source link

Modifying a pre-existing canvas #16

Closed earthiverse closed 12 years ago

earthiverse commented 12 years ago
//1 of 2
Caman('../images/banner.png', '#separate', function () {
    this.colorize(25, 180, 200, 40);
    this.render();
});
//2 of 2
Caman('#separate', function() {
    this.invert();
    this.render();
});
//1 of 1
Caman('../images/banner.png', '#all', function () {
    this.colorize(25, 180, 200, 40);
    this.invert();
    this.render();
});

see: http://earthiverse.ath.cx/tests/camanjs.html

The separate one won't complete the 2nd part Caman('#separate', function() {... when I am expecting it to.

Under 'Loading onto a Canvas without an Image' on http://camanjs.com/docs, I think I followed the right procedure for this.

I would like to modify a pre-existing canvas on a different page, so this would be useful to me.

ghost commented 12 years ago

I'm having the same issue - i'm loading an image in to a canvas element and then trying to modify it as you are, but i cant seem to get it working (works fine when i try with an <img> element):

Caman("#myCanvas", function () {
   this.saturation(20);
   this.render(function() {
      //completed callback
  });
});
meltingice commented 12 years ago

I'm not 100% sure, but I think you guys are actually having two separate issues here.

earthiverse: you're running into a race condition. Invoking Caman() on the same element without waiting for first render to finish is what's causing you issues. You may need to do something like this:

function invokeSeparate() {
    Caman('#separate', function() {
        this.invert();
        this.render();
    });
}

Caman('../images/banner.png', '#separate', function () {
    this.colorize(25, 180, 200, 40);
    this.render(function () {
        invokeSeparate();
    });
});

Avoiding this race condition is something I've been wanting to explore and build into the library, but until then, you'll need to watch out for it yourself.

rizzledizzle: I'll do some tests to see if I can replicate your problem and get back to you.

ghost commented 12 years ago

thanks meltingice. just to carify, i am just loading in an image like this:

var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");

// load image from data url
var imageObj = new Image();
imageObj.onload = function(){
    context.drawImage(this, 0, 0);
    //alert('image loaded');
};   

imageObj.src = "images/pic1.jpg";

Caman("#myCanvas", function () {
this.saturation(20);
this.render(function() {
  //completed callback
});
});
meltingice commented 12 years ago

Ah, looks like you have a race condition as well :)

What's happening is you're loading the image into the canvas, which is an asynchronous process (hence the onload callback), and invoking Caman at the same time without waiting. Remember that Caman() is a function, so it will be invoked immediately in this context.

The simple fix would be to invoke Caman from inside of the imageObj.onload callback after you call drawImage(). This way you avoid the race condition of loading the image into the canvas while simultaneously trying to render filters on the canvas.

var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");

// load image from data url
var imageObj = new Image();
imageObj.onload = function(){
    context.drawImage(this, 0, 0);

    Caman("#myCanvas", function () {
        this.saturation(20);
        this.render(function() {
            //completed callback
        });
    });
};   

imageObj.src = "images/pic1.jpg";
ghost commented 12 years ago

thanks for the feedback. i did have the call to caman inside a jquery click event, and i was waiting until the image loaded into the canvas before clicking. However i will have another play and see if i can get it working :)

ghost commented 12 years ago

had another play, and i didn't have any luck.

in fact, i think the caman function is not running properly when i pass in a canvas id. I put an alert within the Caman function e.g.

Caman("#mycanvasid", function () {
        alert('yo');
                    //caman effects go here

Nothing happens. however, if i swap out my canvas id for the id of an image in the body

Caman("#myImageId", function () {
        alert('yo');
                    //caman effects go here

everything works fine, the effects are applied to the image and the alert is triggered. any ideas on what i might be missing?

biTshifT commented 12 years ago

Pass it the element itself and it works (well it certainly does for me). From a quick glance at the source, I suspect that you can pass it either the canvas element, or the id as: 'mycanvasid' (i.e. without the #).

StackViewer.canvas = document.getElementById('mycanvasid');

...

Caman(StackViewer.canvas, function () {
  this.brightness(StackViewer.windowLevel)
    .contrast(StackViewer.windowWidth)
    .render();
});
meltingice commented 12 years ago

Correct, this has been fixed in recent versions.