【问题标题】:How to grab the relative positions of a signiture in canvas on top of text如何在文本顶部的画布中获取签名的相对位置
【发布时间】:2015-03-23 03:37:09
【问题描述】:

我有一个存储在 MS SQL VARMAX 字段中的合同文本。当加载到画布中时,我需要让用户在不同的地方签名。然后需要将签名保存为 svg 格式。但是如何获取每个签名的相对位置呢?所以当我加载文本时,我可以在正确的位置显示签名。

谢谢,

多伦

【问题讨论】:

  • 添加一些代码并告诉我们您尝试了什么。
  • 签名本身是如何界定的?如果您可以将签名与一些周围的空白隔离,那么您可以使用 context.getImageData 来分析这些像素并隔离签名本身。然而,将这些光栅像素转换为 svg 路径要复杂得多。
  • 我正在使用 ImageMagick 将文本转换为图像。然后将签名与文本图像组合成一张图像并将其存储在高清中。那是一年半前的事了。现在使用 HTML5 画布,我意识到它可以在动态中以不同的方式完成,同时从数据库中获取文本和签名的图像定义,然后动态将它们组合成一个文件。我将签名作为 base 64 存储在数据库中。但我可以将其更改为 SVG 格式。我需要一些启动代码才能让我继续前进……谢谢。
  • 感谢下面的代码,这是一个很好的开始。 我没有提到除了签名之外,合同上的某些地方可能有 2 个首字母缩写(并非所有时间) .在 2 个地方说 Joe Doe 作为 jd(手写)。你会怎么处理?
  • 我已经添加到关于如何在画布上捕获多个签名和/或首字母的答案。干杯!

标签: javascript sql-server html canvas svg


【解决方案1】:

当该人最初签署合同时,您可能会在合同文本上直接放置一个单独的画布。签名者将鼠标/笔在画布上移动以创建他们的签名。签名将是画布上唯一的不透明像素。

您可以使用getImageData 获取画布的像素数据。然后你可以循环遍历每个像素并保存最左边、最上面、最右边和最下面的不透明像素位置。这为您提供了您想要的签名边界框。

这里是如何在画布上获取签名的边界框。

function findBoundary(){
    var data=ctx.getImageData(0,0,cw,ch).data;
    var top=1000000;
    var left=1000000;
    var right=-10;
    var bottom=-10;
    for(var y=0;y<ch;y++){
    for(var x=0;x<cw;x++){
        var n=(y*cw+x)*4+3;
        if(data[n]>200){
            if(x<left){left=x;}
            if(x>right){right=x;}
            if(y<top){top=y;}
            if(y>bottom){bottom=y;}
        }
    }}
    return({x:left,y:top,width:right-left+1,height:bottom-top+1});
}

示例代码和演示:

注意:这个简单的演示并不意味着是一个签名捕获应用程序——我假设您已经拥有一个完整的签名应用程序。它只是在您拖动鼠标时绘制一个笔划,并在您释放鼠标时向您显示笔划的边界框。

var $results=$('#results');

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

ctx.lineCap = "round";
ctx.lineWidth=2;

var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var scrollX=$canvas.scrollLeft();
var scrollY=$canvas.scrollTop();

var isDown=false;
var startX;
var startY;

$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUpOut(e);});
$("#canvas").mouseout(function(e){handleMouseUpOut(e);});


function findBoundary(){
  var data=ctx.getImageData(0,0,cw,ch).data;
  var top=1000000;
  var left=1000000;
  var right=-10;
  var bottom=-10;
  for(var y=0;y<ch;y++){
    for(var x=0;x<cw;x++){
      var n=(y*cw+x)*4+3;
      if(data[n]>200){
        if(x<left){left=x;}
        if(x>right){right=x;}
        if(y<top){top=y;}
        if(y>bottom){bottom=y;}
      }
    }}
  return({x:left,y:top,width:right-left+1,height:bottom-top+1});
}



function handleMouseDown(e){
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  startX=parseInt(e.clientX-offsetX);
  startY=parseInt(e.clientY-offsetY);

  // Put your mousedown stuff here
  ctx.clearRect(0,0,cw,ch);
  ctx.lineWidth=3;
  ctx.strokeStyle='black';
  isDown=true;
}

function handleMouseUpOut(e){
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  isDown=false;

  var pos=findBoundary();
  ctx.strokeStyle='red';
  ctx.lineWidth=1;
  ctx.globalAlpha=0.50;
  ctx.strokeRect(pos.x,pos.y,pos.width,pos.height);
  ctx.globalAlpha=1.00;

  $results.text(
    'Signature boundary x/y: '
    +parseInt(pos.x)+'/'
    +parseInt(pos.y)+', width/height: '
    +parseInt(pos.width)+'/'
    +parseInt(pos.height)
  );
}

function handleMouseOut(e){
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  // Put your mouseOut stuff here
  isDown=false;
}

function handleMouseMove(e){
  if(!isDown){return;}
  // tell the browser we're handling this event
  e.preventDefault();
  e.stopPropagation();

  mouseX=parseInt(e.clientX-offsetX);
  mouseY=parseInt(e.clientY-offsetY);

  // Put your mousemove stuff here
  ctx.beginPath();
  ctx.moveTo(startX,startY);
  ctx.lineTo(mouseX,mouseY);
  ctx.stroke();
  startX=mouseX;
  startY=mouseY;

}
body{ background-color: white; }
#canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4 id='results'>Sign by dragging</h4>
<canvas id="canvas" width=300 height=300></canvas>

[基于附加问题的补充]

除了签名之外,某些地方可能还有 2 个首字母 合同……你会怎么处理?

这涉及通过建立边界框进行集合识别。

  1. 找到包含最顶部不透明像素的行,

  2. 逐行向下移动,直到您有足够的行且没有不透明像素(== 直到您确定签名垂直完整)。

  3. 找到包含最左边不透明像素的列,

  4. 逐列向右移动,直到您有足够的行且没有不透明像素(== 直到您确定签名水平完整)。

  5. 签名的边界框是#1-4中确定的左/右和上/下像素。

  6. 擦除边界框中的像素。

此时您已成功捕获第一个签名(或首字母)。

重复步骤 #1-6,直到找不到像素(== 直到没有更多的签名或首字母)。

祝你的项目好运!

【讨论】:

    猜你喜欢
    • 2015-07-01
    • 2019-09-03
    • 2019-08-28
    • 1970-01-01
    • 2020-12-26
    • 2010-11-23
    • 1970-01-01
    • 1970-01-01
    • 2018-02-01
    相关资源
    最近更新 更多