【问题标题】:Wrap images on papercup(background image)将图像包裹在纸杯上(背景图像)
【发布时间】:2015-02-01 05:08:26
【问题描述】:

我想在示例纸杯上包装图像和文本。 当图像上传到画布上时,我想将它包裹在位置始终固定的纸杯的背景图像上。 我将 Fabric JS 用于 html5 画布工具。 这是我的代码,但它只显示 1 个像素的图像,当我单击图像进行拖放时,它消失了。

HTML:

<div id="container">
    <input type="file" id="imageLoader" name="imageLoader" />
    Remove:<input type="button" value="remove" id="imageRemove" name="imageRemove" onClick="handleRemove()"/>
    <canvas id="canvas" width="500" height="400" style="width:1000px;height:500px;margin-left:5%;" ></canvas>


</div>

JS:

var offsetY=[0,1,2,3,4,5,6,5,4,3,2,1,0];

var canvas = new fabric.Canvas('canvas', {
    backgroundColor: 'rgb(240,240,240)'
});



var imageLoader = document.getElementById('imageLoader');
imageLoader.addEventListener('change', handleImage, false);

function handleImage(e) {
  var reader = new FileReader();
  reader.onload = function (event) {
    var image = new Image();
    image.onload = function () {
        var width = image.width,
            height = image.height;
        var context = $("canvas")[0].getContext("2d");
        for(var x=0;x<offsetY.length;x++){
            context.drawImage(image,
                x,0,1,image.height,
                x,offsetY[x],1,image.height);           
        }

    };
    image.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
}

function handleRemove() {
canvas.clear().renderAll();
}

我是html5画布的新手,请帮忙。

http://jsfiddle.net/kNEaX/217/

【问题讨论】:

  • 这里有几个初始错误:您正在使用 CSS 设置画布大小(直接使用宽度和高度,并且仅),您使用 1 像素的目标宽度绘制图像(这解释了为什么图像宽度为 1 像素),并且直接使用画布不会更新织物的内部结构(您应该改用织物方法),这就是为什么当您与织物交互时画布会变为空白。
  • 你能帮我写drawImage的代码吗?我想实现这样的东西-stackoverflow.com/questions/26403646/…

标签: javascript html5-canvas fabricjs


【解决方案1】:

您可以像这样绘制用户图像:

关于这个纸杯:

结果如下:

使用此示例代码:

修改此示例以满足您的需要。祝你的项目好运!

var faceCanvas = document.getElementById('face');
var faceCtx = faceCanvas.getContext('2d');

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


$myslider = $('#myslider');
$myslider.val(50);

var PI = Math.PI;
var cupTop = 78;
var cupBottom = 295;
var dxx = 19;
var dyy = 34;
var l = {
  x0: 41,
  y0: cupTop,
  x1: 74,
  y1: cupBottom
};
var r = {
  x0: 249,
  y0: cupTop,
  x1: 218,
  y1: cupBottom
};
var t = {
  x0: l.x0,
  y0: l.y0,
  x1: l.x0 + dxx,
  y1: r.y0 + dyy,
  x2: r.x0 - dxx,
  y2: r.y0 + dyy,
  x3: r.x0,
  y3: r.y0
};
var b = {
  x0: l.x1,
  y0: l.y1,
  x1: l.x1 + dxx,
  y1: r.y1 + dyy,
  x2: r.x1 - dxx,
  y2: r.y1 + dyy,
  x3: r.x1,
  y3: r.y1
};
var topOffset = 40;

var imgCount = 2;
var cup = new Image();
cup.crossOrigin = 'anonymous';
cup.onload = start;
var pic = new Image();
pic.crossOrigin = 'anonymous';
pic.onload = start;
cup.src = 'https://image.ibb.co/iKJvyc/VENFv.png';
pic.src = 'https://image.ibb.co/dJHG4H/Pu7aY.jpg';

function start() {
  if (--imgCount > 0) {
    return;
  }

  cw = canvas.width = faceCanvas.width = cup.width;
  ch = canvas.height = faceCanvas.height = cup.height;

  draw();

  face();

  $myslider.change(function() {
    var value = parseInt($(this).val()) / 100;
    topOffset = (l.y1 - l.y0 - pic.height) * value;
    draw();
    face();
  });

}


function face() {

  //
  var lm = (l.y1 - l.y0) / (l.x1 - l.x0);
  var lb = l.y1 - (lm * l.x1);
  //
  var rm = (r.y1 - r.y0) / (r.x1 - r.x0);
  var rb = r.y1 - (rm * r.x1);

  faceCtx.clearRect(0, 0, faceCanvas.width, faceCanvas.height);

  for (var y = 0; y < pic.height; y++) {

    var yy = cupTop + topOffset + y;
    var leftX = (yy - lb) / lm;
    var rightX = (yy - rb) / rm;
    var width = rightX - leftX;

    faceCtx.drawImage(
      pic,
      0, y, pic.width, 1,
      leftX, yy, width, 1
    );

  }

  var yy = cupTop + topOffset;
  var p0 = {
    x: (yy - lb) / lm,
    y: cupTop + topOffset
  };
  var p3 = {
    x: (yy - rb) / rm,
    y: cupTop + topOffset
  };
  var p1 = {
    x: p0.x + dxx,
    y: p0.y + dyy
  };
  var p2 = {
    x: p3.x - dxx,
    y: p3.y + dyy
  };
  var points = calcPointsOnBezier(p0, p1, p2, p3);

  for (var x in points) {
    var y = points[x];
    ctx.drawImage(faceCanvas, x, 0, 1, ch, x, y - yy, 1, ch);
  }

}

function calcPointsOnBezier(p0, p1, p2, p3) {

  var points = {};
  for (var x = parseInt(p0.x); x < parseInt(p3.x + 1); x++) {
    points[x] = p0.y;
  }

  for (var i = 0; i < 1000; i++) {
    var t = i / 1000;
    var pt = getCubicBezierXYatT(p0, p1, p2, p3, t);
    points[parseInt(pt.x)] = parseInt(pt.y);
  }

  return (points);
}

function draw() {
  ctx.strokeStyle = 'gold';
  ctx.clearRect(0, 0, cw, ch);
  ctx.drawImage(cup, 0, 0);
  // diagnostic();
}

function diagnostic() {
  ctx.beginPath();
  ctx.moveTo(l.x0, l.y0);
  ctx.lineTo(l.x1, l.y1);
  ctx.moveTo(r.x0, r.y0);
  ctx.lineTo(r.x1, r.y1);
  ctx.lineWidth = 3;
  ctx.stroke();

  ctx.beginPath();
  ctx.moveTo(t.x0, t.y0);
  ctx.bezierCurveTo(t.x1, t.y1, t.x2, t.y2, t.x3, t.y3);
  ctx.stroke();

  ctx.beginPath();
  ctx.moveTo(b.x0, b.y0);
  ctx.bezierCurveTo(b.x1, b.y1, b.x2, b.y2, b.x3, b.y3);
  ctx.stroke();
}

function getCubicBezierXYatT(startPt, controlPt1, controlPt2, endPt, T) {
  var x = CubicN(T, startPt.x, controlPt1.x, controlPt2.x, endPt.x);
  var y = CubicN(T, startPt.y, controlPt1.y, controlPt2.y, endPt.y);
  return ({
    x: x,
    y: y
  });
}

// cubic helper formula at T distance
function CubicN(T, a, b, c, d) {
  var t2 = T * T;
  var t3 = t2 * T;
  return a + (-a * 3 + T * (3 * a - a * T)) * T +
    (3 * b + T * (-6 * b + b * 3 * T)) * T +
    (c * 3 - c * 3 * T) * t2 +
    d * t3;
}
body {
  background-color: ivory;
}

canvas {
  border: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
Vertical Position:<input id=myslider type=range min=0 max=100 value=50><br>
<canvas id="canvas" width=300 height=300></canvas>
<canvas id="face" width=300 height=300 hidden></canvas>

附加说明:上面的示例在 Html Canvas 元素上创建了效果

这样做是因为该效果需要在原生 Canvas 元素中提供的 context.drawImage 方法。

使用原生画布创建效果后,您可以轻松地使用原生画布作为图像源来创建 FabricJS Image 对象(fabric.Image 接受 html 画布作为图像源):

// get a reference to the html canvas with the
// "image around mug" effect
var canvas=document.getElementById("canvas");

// create a fabric.Image using that html canvas
// as an image source
var c=new fabric.Canvas('c');
var myFabricImage=new fabric.Image(canvas, {
  left: 50,
  top: 50,
});
c.add(myFabricImage);

【讨论】:

  • 谢谢马克E。这将有很大帮助。但是是否可以使用织物方法代替?此方法中不允许拖放、调整大小和旋转。
  • 使用 html 画布创建效果后,您可以使用该 html 画布作为图像源创建一个 fabric.Image。我在答案中添加了示例代码来做到这一点。干杯!
  • 太棒了。我想这会做:)
  • @markE 我能问一下为什么你使用drawImage函数来剪辑图像而不是仅仅设置宽度和高度?我正在尝试为一个非常相似的项目实现这一点,但它使我的图像越过物体(在这种情况下是杯子)看起来真的是串起来的。提前感谢您的回复。
  • 这个静态图不错,但是怎么做3d旋转动画。
猜你喜欢
  • 1970-01-01
  • 2016-09-09
  • 1970-01-01
  • 1970-01-01
  • 2013-08-01
  • 2011-02-13
  • 1970-01-01
  • 2017-03-10
  • 1970-01-01
相关资源
最近更新 更多