如何从 canvas 和文本区域创建图像

How to create an image from a canvas and a textarea

我有一个 canvas,还有一个位于 canvas 之上的文本区域:

<canvas id="ideaBox" width="400" height="400"></canvas>
<textarea id="ideaTextArea" rows="15"></textarea>

我想将盒子的内容(包括文本区域)捕获到图像中。这可能吗?

我尝试使用:

var MIME_TYPE = "image/png";
var imgURL = canvas.toDataURL(MIME_TYPE);

但它省略了文本,因为文本在文本区域中,而不是在 canvas.

我也试过使用 html2canvas (http://html2canvas.hertzen.com/),但是你只能将一个元素传递到脚本中,所以我不能同时传递 canvas 和文本区域.

有人对此有想法或经验吗?

以下是如何将标题附加到现有 canvas 的底部:

创建 canvas 的副本,并将文本区域文本附加到副本。

  1. 假设文本必须在原始宽度内换行,从文本区域计算换行文本的高度canvas(参见下面的示例代码)。
  2. 新建 in-memory canvas.
  3. 将新的 canvas 调整为原始 canvas 宽度,但调整为原始 canvas 高度加上换行文本的高度。

    newCanvas.width=originalCanvas.width;
    newCanvas.height=originalCanvas.height+wrappedTextHeight;
    
  4. DrawImage原来的canvas内容改为新的canvas.
  5. 在新canvas.
  6. 底部绘制换行文字
  7. 使用 .toDataURL 从新 canvas 创建新图像。

示例代码和演示:

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

var text='Now is the time for all good men to come to the aid of their country.'
var fontsize=14;
var fontface='verdana';

// testing: draw something on the canvas
ctx.fillStyle='gold';
ctx.fillRect(0,0,cw,ch);
ctx.beginPath();
ctx.moveTo(50,50);
ctx.lineTo(75,270);
ctx.lineTo(100,50);
ctx.lineTo(125,270);
ctx.lineTo(150,50);
ctx.quadraticCurveTo(250,160,150,270);
ctx.lineWidth=15;
ctx.strokeStyle='purple';
ctx.lineCap='round';
ctx.lineJoin='round';
ctx.stroke();

// append a caption at the bottom of the canvas
applyCaption(canvas,text,fontsize,fontface);


function applyCaption(origCanvas,text,fontsize,fontface){
  // calc the height of the wrapped text
  var height=wrapText(0,0,text,fontsize,fontface,canvas.width-20);
  // Create a new canvas
  // Resize the new canvas same as original canvas
  //   but taller by the text height
  var c=document.createElement('canvas');
  var cctx=c.getContext('2d');
  c.width=origCanvas.width;
  c.height=origCanvas.height+height;
  // draw the original canvas contents to the new canvas
  cctx.drawImage(origCanvas,0,0);
  // draw the wrapped text at the bottom of the new canvas
  cctx.fillStyle='white';
  cctx.fillRect(0,c.height-height,c.width,height);
  cctx.fillStyle='black';
  wrapText(10,c.height-height,text,fontsize,fontface,canvas.width-20,cctx);
  // create an image from the new canvas
  var img=new Image();
  img.onload=function(){
    document.body.appendChild(img);
  }
  img.src=c.toDataURL();
}

function wrapText(x,y,text,fontsize,fontface,maxwidth,context){
  if(!context){
    // we're just calculating the wrapped text height
    // so create a throw-away context to work with
    var context=document.createElement('canvas').getContext('2d');
  }
  var startingY=y;
  var words = text.split(' ');
  var line = '';
  var space='';
  var lineHeight = fontsize*1.286;
  context.font = fontsize + "px " + fontface;
  context.textAlign='left';
  context.textBaseline='top'
  for (var n=0; n<words.length; n++) {
    var testLine = line + space + words[n];
    space=' ';
    if (context.measureText(testLine).width > maxwidth) {
      context.fillText(line,x,y);
      line = words[n] + ' ';
      y += lineHeight;
      space='';
    } else {
      line = testLine;
    }
  }
  context.fillText(line, x,y);
  return(y+lineHeight-startingY);
}
body{ background-color: ivory; }
#canvas{border:1px solid red; }
img{border:1px solid lightgray; }
<h4>Original canvas & New canvas with appended caption</h4>
<canvas id="canvas" width=250 height=300></canvas>