www.webdeveloper.com
Results 1 to 8 of 8

Thread: [RESOLVED] Can't get canvas.setTransform to work :(

  1. #1
    Join Date
    Jul 2010
    Posts
    22

    resolved [RESOLVED] Can't get canvas.setTransform to work :(

    Hello all. I'm still playing around with HTML5 + JS, and while i have made a certain progress, i still don't get a lot about it.

    I resorted to ripping off other people's work, and found this awesome canvas example: http://www.html5.jp/blog/contents/HT...rm-jquery.html.
    It works great if i leave it at this:
    Code:
    ctx.save();
    ctx.clearRect(-w*2, -h*2, w*4, h*4);
    ctx.setTransform(p.m11, p.m12, p.m21, p.m22, p.dx, p.dy);
    ctx.drawImage(img, 0, 0);
    ctx.restore();
    But as soon as i leave out the drawImage part and substitute it with putImageData i previously created (remember, i have a dynamically generated thing, it's only on canvas, not in an Image object that i could use for drawImage), it stops scaling! I'm back to the big, 100% scaled image.

    PLEASE help me out with this, these canvas and their logic are driving me nuts!!!!

    P.S. Also, why do we save the state before making any changes, then restore the state after the changes, and somehow still see the changes made??? Shouldn't the restore() method revert to the state before any changes were made??

    I'm eagerly awaiting for anyone to shed some light on this

  2. #2
    Join Date
    Jan 2003
    Location
    Texas
    Posts
    10,413
    Hi,

    I don't claim to be an expert on Canvas, but I think we can figure it out. ;-)

    Regarding
    putImageData, it would be easier for me to understand what the problem is if you had a link so I could see how you're using it. It's a little hard to answer that otherwise.

    Your question about save state / restore state has to do with the behavior of Canvas. When you transform the canvas without clearing it and redrawing it, the canvas remains the same and new changes are placed on top of it. In other words, if you took out the save/clear/restore lines, and made the code look like the following, you would see duplicate copies of the image on top of one another:


    Code:
    	//ctx.save();
    	//ctx.clearRect(-w*2, -h*2, w*4, h*4);
    	ctx.setTransform(p.m11, p.m12, p.m21, p.m22, p.dx, p.dy);
    	ctx.drawImage(img, 0, 0);
    	//ctx.restore();
    In that case, changing the parameters of the setTransform method would duplicate the canvas view in addition to modifying it.

    The way to work around this is, of course, to save the canvas context in its current state (which is why we start with the
    save() method), clear what is currently visible on the canvas (clearRect()), perform our transformation operation, and then when we're done, restore the canvas state (restore()). The save/restore methods don't actually clear/restore the output of the canvas itself (that's what drawImage does); however, they do provide state-change information (the "context" as it were), which is important for a program that will be interacting with the canvas (particularly for optimizing redraws and the creation of new paths after they have been filled or stroked). Essentially, the transformations performed on the canvas are cumulative, and therefore each call saves and restores the canvas state. Does that help any?

  3. #3
    Join Date
    Jul 2010
    Posts
    22
    Jona,

    thank you so much for explaining canvas to me! my biggest mistake was that i thought that the save() and restore() methods saved/restored the pixel data of canvas. now i understand that, apparently, they save/restore the, er, attributes of canvas, such as the transform arguments.

    however, now it seems clearer to me that the resize trick may be impossible to implement at all.
    i have put together a small example: http://gda.0fees.net/tests/test01.php
    function resize1() works just great, but it redraws the image from a static source. this is not what i need
    function resize2() calls putImageData(), and apparently this method disregards the transformed state of canvas...

    P. S. sorry i'm so slow. i received the notification about your answer immediately, but things have been keeping me really busy lately...

  4. #4
    Join Date
    Jul 2010
    Posts
    22
    Update:
    i have found a workaround that uses the drawImage function. it's kinda dodgy though.
    Code:
    var tempImage = new Image;
    /* draw something on the canvas here */
    tempImage.src = $("tc").toDataURL("image/png");
    $("tc").getContext("2d").clearRect(0, 0, 604, 339);
    $("tc").getContext("2d").drawImage(tempImage, 0, 0, 302, 170)
    This does scale the image inside the canvas to 50%, but it's not exactly lightning fast. in fact, it appears to be several times slower than using putImageData() (which doesn't work, however).
    I only wonder whether i will have any speed boost if i say screw it and implement bicubic interpolation of the imageData array

  5. #5
    Join Date
    Jan 2003
    Location
    Texas
    Posts
    10,413
    Hi,

    Why not simply draw the image to the canvas at 50% of the canvas dimensions? No need for a transform operation at all, and probably faster, too.


    Code:
    var ctx = $('tc').getContext('2d');
    
     ctx.save();
     ctx.clearRect(0, 0, 604, 339);
     ctx.drawImage($('ti'), 0, 0, 604 / 2, 339 / 2);
     ctx.restore();

  6. #6
    Join Date
    Jul 2010
    Posts
    22
    Then it will always draw the original image, as contained in the file.

    Sorry that my example page doesn't reflect it, but instead of drawing a PNG file there actually should be drawing some graphs and stuff rendered in real time. I can't fetch it from a file, it's content created on the fly.
    And also i apologize that i can't post what exactly i'm working with and need to show this by way of example pages - my work is slightly confidential as of now

  7. #7
    Join Date
    Jan 2003
    Location
    Texas
    Posts
    10,413
    The image being drawn to the canvas is pixel data, so you're going to want to operate on that before drawing it to the canvas, rather than drawing it to the canvas and then performing your operations.

    In the following example code, you can reference
    imgD.data to modify the pixel data directly.

    Code:
    var ctx = $('tc').getContext('2d');
    
     ctx.save();
     ctx.clearRect(0, 0, 604, 339);
    
     ctx.drawImage($('ti'), 0, 0, 604, 339);
    
     var imgD = ctx.getImageData(0, 0, 604, 339);
    
     ctx.putImageData(imgD, 0, 0);
    
     ctx.restore();
    Here's a very simplified example that increases the exposure (contrast) of the image.

    Code:
    var ctx = $('tc').getContext('2d');
    
     ctx.save();
     ctx.clearRect(0, 0, 604, 339);
    
     ctx.drawImage($('ti'), 0, 0, 604, 339);
    
     var imgD = ctx.getImageData(0, 0, 604, 339);
    
     // this loop should be extracted to a separate function
     for (var x = 0; x < imgD.data.length; x++){
      imgD.data[x] = imgD.data[x] << 2;
     }
    
     ctx.putImageData(imgD, 0, 0);
    
     ctx.restore();

  8. #8
    Join Date
    Jul 2010
    Posts
    22
    Yeah, i guess i will work in this direction, even though it will reduce the flexibility of my script.

    And Jona, big thanks for helping me out! - before you explained things to me, i hadn't understood canvas at all, and now i do!

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center



Recent Articles