2

I'm trying to find a wa to do a similar effect o that found on persona.co How ever after much googling of various search terms I can not find anything that might help. I can see a lot of posts on transforming an image in 3d space, or stretching an image to fit, not not actually distorting the pixels mathematically as I would need.

enter image description here

I had originally looked into using subdivisions to pull apart the mage, but this only works to stretch the image equally unless I made hundreds of divisions on an axis, and then this wouldn't allow me to possibly mirror vertically the image to get the same effect.

My current plan to to run the image through pixel by pixel and duplicate them vertically in increasing amounts and remove on the inverse though this would no doubt cause issues without interpolating the neighboring pixels.

If anyone can point me in the right direction or has any ideas to help me get started that would be enough.

Chris Morris
  • 943
  • 2
  • 17
  • 41

3 Answers3

2

I think they are using PixiJS:

http://www.pixijs.com

D. Cantatore
  • 187
  • 12
2

Easy to do distorsions is you are not too fussy about what it is you want.

By drawing the image one line at a time and changing where from the image you get the line you can make it stretch anywhere you want. Each line that you draw can also be searched horizontally to add additional FX

The following applies half a dozen sin waves to the image. Drawing the image one line at a time. The math is just random so any FX can be made.

You can also go to webGL that will give you much greater power. See this answer https://stackoverflow.com/a/38966946/3877726

The demo. All the stuff to do the distorto is in the function display. The for loop loops from 0 to 1 and all the wave try to keep the value between 0 and 1. only when I get the line from the image and put it on the canvas do I convert the unit value back to pixel coordinates by simply multiplying.

var image = new Image();
image.src = "https://i.stack.imgur.com/jNAXA.jpg";
var iw,ih;

var easeInOut = function (x, pow) {
    x = x < 0 ? 0 : x > 1 ? 1 : x; // clamp x
 var xx = Math.pow(x,pow);
 return xx / (xx + Math.pow(1 - x, pow));
}
function display(){  // put code in here
    ctx.setTransform(1,0,0,1,0,0); // reset transform
    ctx.globalAlpha = 1;           // reset alpha
    ctx.clearRect(0,0,w,h);
    if(image.complete){
        if(ih === undefined){
            ih = image.height;
            iw = image.width;
        }
        var step = 1/ canvas.height;;
        var istep = ih / canvas.height;
        var rstep = 0;
        var y = 0;
        var yh = 0;
        var cH = canvas.height;
        var cH = canvas.height;
        var curve = Math.sin(globalTime /1020) + 1.2;
        var curve2 = Math.sin(globalTime /2217) + 1.4;
        var curve3 = Math.sin(globalTime /533) * Math.PI;
        var curve4 = (Math.sin(globalTime /731) + 1.1) * Math.PI;
        var wave = 4/(Math.PI * 1);
        var wave1 = curve4/(Math.PI * 1);
        for(var i = 0 ;i < 1; i += step){
            var wob = Math.sin(i * wave);
            var wide =  (Math.sin(i * wave1 * 3+curve3) + 1.0)*100;
            y = easeInOut(easeInOut(wob,curve),curve2);
            yh =easeInOut( easeInOut(wob+step,curve),curve2) - y;
            y *= ih;
            yh *= ih;
            ctx.drawImage(image, wide, y, iw-wide*2, yh, 0, i*cH, canvas.width, step*cH);
        }
 
    }
}




function update(timer){ // Main update loop
    globalTime = timer;
    display();  // call demo code
    requestAnimationFrame(update);
}





const RESIZE_DEBOUNCE_TIME = 100;
var w,h,cw,ch,canvas,ctx,createCanvas,resizeCanvas,setGlobals,globalTime=0,resizeCount = 0; 
createCanvas = function () { 
    var c,cs; cs = (c = document.createElement("canvas")).style; 
    cs.position = "absolute"; 
    cs.top = cs.left = "0px"; 
    cs.zIndex = 1000; 
    document.body.appendChild(c); 
    return c;
    
}
resizeCanvas = function () {
    if (canvas === undefined) { 
        canvas = createCanvas(); 
        
    } 
    canvas.width = window.innerWidth; 
    canvas.height = window.innerHeight; 
    ctx = canvas.getContext("2d"); 
    if (typeof setGlobals === "function") { setGlobals(); }
    if (typeof onResize === "function"){ 
        resizeCount += 1; 
        setTimeout(debounceResize,RESIZE_DEBOUNCE_TIME);
        
    }
}
function debounceResize(){ 
    resizeCount -= 1; 
    if(resizeCount <= 0){ onResize();}
}
setGlobals = function(){ 
    cw = (w = canvas.width) / 2; 
    ch = (h = canvas.height) / 2; 
}

resizeCanvas(); 
window.addEventListener("resize",resizeCanvas); 
requestAnimationFrame(update);
Community
  • 1
  • 1
Blindman67
  • 51,134
  • 11
  • 73
  • 136
1

You can easily vertically stretch an image using canvas's context.scale

// stretches the image 2x vertically
ctx.scale(1,2);

And you can flip the image vertically to do the "bottom" part of your image:

// flips the image vertically
context.scale(1,-1);

Example:

enter image description here

var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;

var img=new Image();
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/face.jpg";
function start(){
    ctx.drawImage(img,0,0);
    ctx.translate(img.width*1.25,0);
    // optionally, shrink the img by half so it fits in a reasonable size
    ctx.scale(0.50,0.50);
    ctx.scale(1,2);
    ctx.drawImage(img,0,0);
    ctx.scale(1,-1);
    ctx.drawImage(img,0,-img.height*2);
}
body{ background-color:white; }
#canvas{border:1px solid red; }
<canvas id="canvas" width=400 height=480></canvas>
markE
  • 102,905
  • 11
  • 164
  • 176