3

When i add large images onto my page with kineticjs i am getting some poor quality when i am setting them to quite small sizes. The result is often jagged/rough. If however i add the same image and set the dimensions just with img src I get a much better quality and smoothly scaled down version.

Is there anything i can add to combat this? jsfiddle, screenshot and code all below

JSFIDDLE: http://jsfiddle.net/vTLkn/6/

example

// Define Stage
var stage = new Kinetic.Stage({
    container: "canvas",
    width: 300,
    height: 200
});

//Define Layer for Images
var layer = new Kinetic.Layer();
stage.add(layer);   

// Draw Image Function
function drawImage(image,w,h,x,y) { 
    // Define Function's Image Properties
    var theImage = new Kinetic.Image({
        image: image,
        x: x,
        y: y,
        width: w,
        height: h
    });
    
    // Add Function's Image to Layer
    layer.add(theImage);
    layer.draw();
}
    
// Define Image 1 and Draw on Load
var image1 = new Image();
image1.onload = function() {
    drawImage( this, 250, 188, 0, 0);
};
image1.src = "http://i.imgbox.com/vMfjLbnw.jpg";
Glorfindel
  • 21,988
  • 13
  • 81
  • 109
odd_duck
  • 3,941
  • 7
  • 43
  • 85
  • Canvas (typically) uses bilinear interpolation (low-pass filter in this case) instead of bicubic as images uses. I'm not sure how to do it with kinectjs but the principle (down stepping) is explained here: http://stackoverflow.com/questions/17861447/html5-canvas-drawimage-how-to-apply-antialiasing Short version is that you need to downsize the image twice (or more), first half the target size then from half to final size. –  Apr 14 '14 at 11:38
  • related http://stackoverflow.com/questions/17861447/html5-canvas-drawimage-how-to-apply-antialiasing?lq=1 – Tomás Apr 14 '14 at 12:16
  • Thanks for the link. I am unsure how i can do the same procedure with kineticjs though as it's a different way of drawing the image? – odd_duck Apr 14 '14 at 12:18

1 Answers1

2

Well, based on the comment from @Cryptoburner. I implemented a custom shape in Kinetic and used the sceneFunc to use the drawImage function as implemented in the related link.

var theImage = new Kinetic.Shape({
    sceneFunc: function(context) {
        /// step 1
        var oc = document.createElement('canvas'),
            octx = oc.getContext('2d');
        oc.width = image.width * 0.5;
        oc.height = image.height * 0.5;
        octx.drawImage(image, 0,0, oc.width,oc.height);

        /// step 2
        octx.drawImage(oc,0,0,oc.width * 0.5,oc.height * 0.5);



        context.drawImage(oc,0,0,oc.width * 0.5, oc.height * 0.5,
                         0,0,w,h);
    }
});

enter image description here

So here is the fiddle: http://jsfiddle.net/vTLkn/8/

Now it's still not as good as the Img version, but it is and improvement. Since your image is 1000 pixels wider, it would probably be a good idea to do another iteration of downsizing (in the custom sceneFunc.

PS. Updated the Kinetic version to 5.0.1, otherwise it didn't work.

Sjiep
  • 688
  • 5
  • 14
  • i've just implemented this into my full code and although it works, i also have a `setImage` function that updates the image if the user wishes to select another: function changeImage(source){ var newImage = new Image(); var img = global.stage1.get('#Image1')[0]; newImage.onload = function() { img.setImage(newImage); }; newImage.src = source; but i get Uncaught TypeError: undefined is not a function - is it as it is now a shape not an image? – odd_duck Apr 15 '14 at 13:42
  • Mmm, it now indeed is a shape and not an image, so setImage is non-existent. You could either extend the existing Kinetic.Image object (see http://stackoverflow.com/questions/14892827/how-to-extend-kineticjs-shape) or you can create your own setImage function. I adapted the fiddle (http://jsfiddle.net/vTLkn/9/) such that it has an image property which can be accessed by getAttr('image') and setAttr('image', value), your changeImage function could use the setAttr to change the image source – Sjiep Apr 15 '14 at 15:18
  • Massive thnak you once again Sjiep but i cannot get the actual setAttr (on change) to respond. I now have: http://jsfiddle.net/vTLkn/12/ but nothing happens on the click – odd_duck Apr 15 '14 at 18:48
  • that was after i did `drawImage('http://i.imgbox.com/F0xZeMLG.jpg', 213, 236, 0, 0);` instead but that was giving me a console error of: `Uncaught TypeError: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': No function was found that matched the signature provided. ` – odd_duck Apr 15 '14 at 18:53
  • You had forgotten the onload construction. This works: http://jsfiddle.net/vTLkn/13/. The onload looks a bit strange/messy in my opinion, but I have very little experience with it. I'm pretty sure the code could be written more nicely, but the fiddle works :P – Sjiep Apr 15 '14 at 18:58
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/50719/discussion-between-sjiep-and-odd-duck) – Sjiep Apr 15 '14 at 19:00