在 HTML5/JavaScript 中将图像包裹在圆柱形对象周围 [英] Wrap an image around a cylindrical object in HTML5 / JavaScript

查看:36
本文介绍了在 HTML5/JavaScript 中将图像包裹在圆柱形对象周围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将图像包裹在一个圆柱形物体上,比如 web 应用程序中的杯子,就像这样

I want to wrap an image around a cylindrical object like mugs in a web app, like so

这可能是包含用户上传图像的转换图像的基本图像(例如杯子的 jpeg 图像).

This will likely be a base image (e.g. a jpeg image of a mug) containing a transformed image of a user uploaded image.

照相馆.但是,这当然不适用于 Web、移动或服务器环境.

There seems to be a lot of resources on this in PhotoShop. However, this is of course not appropriate for web, mobile or server environments.

我也知道这是可能的,因为许多网站已经做得非常好.例如,Vista 打印(见图片),Asda 照片(并通过在 Google 上搜索个性化杯子在互联网上加载更多内容),使用的似乎只是 HTML5.

I also know this is possible, as a number of sites already do this extremely well. For example, Vista Print (see image), Asda Photos (and loads more on the internet by just searching personalised mugs on Google), using what seems to be just HTML5.

然而,奇怪的是我似乎找不到任何关于 Web 应用程序的答案.StackOverflow 中有很多关于此的问题都没有得到解答,例如:将图像包裹在圆柱体周围使用 html 5 画布和 javascript 将图像包裹在圆柱形杯子上如何使用 html5 画布在杯子上叠加图像 还有更多!

However, bizarley I cannot seem to find any answers for a Web App. There's a lot of questions on this in StackOverflow that are all unanswered like: Wrap an image around a cylinder, wrap image around a cylindrical cup using html 5 canvas and javascript, How overlay image over a cup using html5 canvas and many many more!

因此,请有人最终提供这个问题的答案.

Therefore can someone please finally provide an answer to this question.

推荐答案

带 Canvas 2D 的简单圆柱体包裹

使用 sin 和 cos 创建曲线图的非常简单的示例.图像被切成约 1 像素宽的条带,然后渲染为半个压扁的圆圈.由于透视是与距离相关的线性效果,我还通过在 y 方向上根据 sin(angle) 放大来添加少量透视(其中,左侧的角度 = 0 Math.PI/2 位于前中心).

Simple cylinder wrap with Canvas 2D

Very simple example using sin and cos to create the curved map. The images is cut into strips approx 1 pixel wide then rendered as half a squashed circle. As perspective is a linear effect related to distance I also add a small amount of perspective by scaling up in the y direction depending on sin(angle) (where angle = 0 on the left Math.PI / 2 at the forward center).

这两个演示动画只是为了表明它不是一个缓慢的过程,但与 webGL 相比,它是蜗牛.如果你使用这种方法,不要让它实时,否则你会消耗移动设备的电池.实时 3D 应该用 webGL 来完成

These two demos are animated just to show that it is not a slow process, but compared to webGL it is a snail. If you use such a method, don't make it realtime or you will chew up the batteries of mobile devices. Realtime 3D should be done with webGL

var createImage=function(w,h){var i=document.createElement("canvas");i.width=w;i.height=h;i.ctx=i.getContext("2d");return i;}

var canvas = createImage(400,400);
var ctx = canvas.ctx;
document.body.appendChild(canvas)
ctx.clearRect(0,0,500,500)
var image = createImage(400,200);
image.ctx.font = "60px arial";
image.ctx.textAlign = "center";
image.ctx.fillStyle = "#7F5";
image.ctx.fillRect(0,0,image.width,image.height)
image.ctx.fillStyle = "white";
image.ctx.fillText("Wrap around",200,60)
image.ctx.fillText("Some images",200,140)


function draw(ang,tilt, perspective){
    var step = 1/(Math.max(image.width,400));
    for(var i = 0; i < 1; i += step){
        var a = i * Math.PI;
        var a1 = (i+ step*2) * Math.PI ;
        var ix = i * image.width*1.2;
        var iw = step * image.width*1.2;
        a += ang * Math.PI * 2;
        a1 += ang * Math.PI * 2;
        a = Math.PI -a;
        a1 = Math.PI -a1;
        var x = canvas.width * 0.5;
        var y = canvas.height * 0.1;
        
        var x1 = x + Math.cos(a1) * 110;
        var y1 = y + Math.sin(a) * tilt;
        x += Math.cos(a) * 110;
        y += Math.sin(a) * tilt;
        var s = Math.sin(a);
        var s1 = Math.sin(a1);
        if(s > 0 || s1 > 0){
            ctx.drawImage(image,ix,0,iw,image.height,x1,y- s * perspective*0.5,x-x1,200 + s * perspective)
        }
        
        
    }
}
var w = canvas.width;
var h = canvas.height;




// main update function
function update(timer){
    ctx.setTransform(1,0,0,1,0,0); // reset transform
    ctx.globalAlpha = 1;           // reset alpha
    ctx.fillStyle = "black"
    ctx.fillRect(0,0,w,h);
    draw(timer / 2000, 40,30)
    requestAnimationFrame(update);
}
requestAnimationFrame(update);

为了进一步扩展它,您可以添加叠加层来进行照明.我找不到白色杯子的公共领域图像,因此我使用相同的函数将照明(一些简单的渐变)渲染到图像上.然后对于最终输出,我将叠加层渲染为背景图像,然后是文本,然后再次使用阴影图像进行两次传递,首先使用乘法"变暗,然后使用变亮"进行柔和的高光

To extend it a little further you can add overlays to do lighting. I could not find a public domain image of a white cup so I used the same function to render the lighting (A few simple gradients) onto and image. Then for the final output I render the overlay as a backing image, then the text, then two passes again with the shading image, first darken with "multiply", then a soft highlight with "lighten"

var createImage=function(w,h){var i=document.createElement("canvas");i.width=w;i.height=h;i.ctx=i.getContext("2d");return i;}

var canvas = createImage(400,400);
var ctx = canvas.ctx;
document.body.appendChild(canvas)
ctx.clearRect(0,0,500,500)
var image = createImage(400,200);
image.ctx.font = "60px arial";
image.ctx.textAlign = "center";
image.ctx.fillStyle = "#999";
image.ctx.fillRect(0,10,image.width,image.height-20)
image.ctx.fillStyle = "white";
image.ctx.fillText("Wrap around",200,60)
image.ctx.fillText("Some images",200,140)

//---------------------------------------------------------------------
// create shading map
var shading = createImage(400,200);
// left to right shading
var g1 = shading.ctx.createLinearGradient(0,0,400,0);
g1.addColorStop(0,"rgba(245,245,245,1)");
g1.addColorStop(0.05,"rgba(255,255,255,1)");
g1.addColorStop(0.5,"rgba(230,230,230,1)");
g1.addColorStop(0.95,"rgba(255,255,255,1)");
g1.addColorStop(1,"rgba(245,245,245,1)");
shading.ctx.fillStyle = g1;
shading.ctx.fillRect(0,0,400,200);

// bottom to top shading
var g = shading.ctx.createLinearGradient(0,0,0,200);
g.addColorStop(1,"rgba(200,200,200,1)");
g.addColorStop(0.95,"rgba(200,200,200,0.4)");
g.addColorStop(0,"rgba(255,255,255,0.0)");
shading.ctx.globalCompositeOperation = "multiply";
shading.ctx.fillStyle = g;
shading.ctx.fillRect(0,0,400,200);


var g = shading.ctx.createRadialGradient(0,-100,100,0,-100,200);
g.addColorStop(0,"rgba(200,200,200,1)");
g.addColorStop(0.95,"rgba(255,255,255,1)");
g.addColorStop(1,"rgba(255,255,255,0)");
shading.ctx.fillStyle = g;
shading.ctx.globalCompositeOperation = "screen";
shading.ctx.setTransform(1.4,0,0,1,200,0);
shading.ctx.beginPath();
shading.ctx.arc(0,-100,200,0,Math.PI * 2);
shading.ctx.globalAlpha = 0.5;
shading.ctx.fill();
shading.ctx.setTransform(1,0,0,1,0,0);
shading.ctx.fillStyle = g1;
shading.ctx.fillRect(0,0,400,200);

var overlay = createImage(400,400);
draw(shading,overlay.ctx,0, 40,30,110,200,1);

function draw(image,ctx,ang,tilt, perspective, width, height,stretch){
    var step = 1/(Math.max(image.width,400));
    for(var i = 0; i < 1; i += step){
        var a = i * Math.PI;
        var a1 = (i+ step*2) * Math.PI ;
        var ix = i * image.width*stretch;
        var iw = step * image.width*stretch;
        a += ang * Math.PI * 2;
        a1 += ang * Math.PI * 2;
        a = Math.PI -a;
        a1 = Math.PI -a1;
        var x = canvas.width * 0.5;
        var y = canvas.height * 0.1;
        
        var x1 = x + Math.cos(a1) * width;
        var y1 = y + Math.sin(a) * tilt;
        x += Math.cos(a) * width;
        y += Math.sin(a) * tilt;
        var s = Math.sin(a);
        var s1 = Math.sin(a1);
        if(s > 0 || s1 > 0){
            ctx.drawImage(image,ix,0,iw,image.height,x1,y- s * perspective*0.5,(x-x1-1),height + s * perspective)
        }
        
        
    }
}
var w = canvas.width;
var h = canvas.height;

// main update function
function update1(timer){
    ctx.setTransform(1,0,0,1,0,0); // reset transform
    ctx.globalAlpha = 1;           // reset alpha
    ctx.fillStyle = "black"
    ctx.fillRect(0,0,w,h);
    ctx.drawImage(overlay,0,0);
    draw(image,ctx,timer / 4000, 40,30,110,200,1)
    ctx.globalCompositeOperation = "multiply";
    ctx.drawImage(overlay,0,0);
    ctx.globalAlpha = 0.2
    ctx.globalCompositeOperation = "lighten";
    ctx.drawImage(overlay,0,0);
    ctx.globalCompositeOperation = "source-over";
    requestAnimationFrame(update1);
}

 requestAnimationFrame(update1);

这篇关于在 HTML5/JavaScript 中将图像包裹在圆柱形对象周围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆