在将签名笔下的画布签名下载为JPG、PNG格式时,画布会变成完全黑色。

4

我正在使用 Signature pad js ,这是来自szimek 的用于制作画布签名板的库。我同时使用了3个画布。经过一些研究,我从Codepen中获得了一个链接,用于使用多个实例。虽然它能正常工作,但问题在于需要下载签名后,PNG和JPG图片会变成完全黑色。下面是相关代码。

var wrapper1 = document.getElementById("signature-pad-1"),
    canvas1 = wrapper1.querySelector("canvas"),
    signaturePad1;

var wrapper2 = document.getElementById("signature-pad-2"),
    canvas2 = wrapper2.querySelector("canvas"),
    signaturePad2;

function resizeCanvas(canvas) {
    var ratio =  window.devicePixelRatio || 1;
    canvas.width = canvas.offsetWidth * ratio;
    canvas.height = canvas.offsetHeight * ratio;
    canvas.getContext("2d").scale(ratio, ratio);
}

function clear1() { signaturePad1.clear(); }
function clear2() { signaturePad2.clear(); }

function save() {
    if (signaturePad1.isEmpty() || signaturePad2.isEmpty())
        alert("Error: Please sign both pads!");
    else
        alert("Success!");
}


resizeCanvas(canvas1);
signaturePad1 = new SignaturePad(canvas1);

resizeCanvas(canvas2);
signaturePad2 = new SignaturePad(canvas2);

$("#clear1").click(clear1);
$("#clear2").click(clear2);
$("#save").click(save);


var savePNGButton1 = wrapper1.querySelector("[data-action=save-png]");
var saveJPGButton1 = wrapper1.querySelector("[data-action=save-jpg]");
var saveSVGButton1 = wrapper1.querySelector("[data-action=save-svg]");

var savePNGButton2 = wrapper2.querySelector("[data-action=save-png]");
var saveJPGButton2 = wrapper2.querySelector("[data-action=save-jpg]");
var saveSVGButton2 = wrapper2.querySelector("[data-action=save-svg]");


// One could simply use Canvas#toBlob method instead, but it's just to show
// that it can be done using result of SignaturePad#toDataURL.
function dataURLToBlob(dataURL) {
  // Code taken from https://github.com/ebidel/filer.js
  var parts = dataURL.split(';base64,');
  var contentType = parts[0].split(":")[1];
  var raw = window.atob(parts[1]);
  var rawLength = raw.length;
  var uInt8Array = new Uint8Array(rawLength);

  for (var i = 0; i < rawLength; ++i) {
    uInt8Array[i] = raw.charCodeAt(i);
  }

  return new Blob([uInt8Array], { type: contentType });
}

function download(dataURL, filename) {
  if (navigator.userAgent.indexOf("Safari") > -1 && navigator.userAgent.indexOf("Chrome") === -1) {
    window.open(dataURL);
  } else {
    var blob = dataURLToBlob(dataURL);
    var url = window.URL.createObjectURL(blob);

    var a = document.createElement("a");
    a.style = "display: none";
    a.href = url;
    a.download = filename;

    document.body.appendChild(a);
    a.click();

    window.URL.revokeObjectURL(url);
  }
}

savePNGButton1.addEventListener("click", function (event) {
  if (signaturePad1.isEmpty()) {
    alert("Please provide a signature first.");
  } else {
    var dataURL = signaturePad1.toDataURL();
    download(dataURL, "signature.png");
  }
});

saveJPGButton1.addEventListener("click", function (event) {
  if (signaturePad1.isEmpty()) {
    alert("Please provide a signature first.");
  } else {
    var dataURL = signaturePad1.toDataURL("image/jpeg");
    download(dataURL, "signature.jpg");
  }
});

saveSVGButton1.addEventListener("click", function (event) {
  if (signaturePad1.isEmpty()) {
    alert("Please provide a signature first.");
  } else {
    var dataURL = signaturePad1.toDataURL('image/svg+xml');
    download(dataURL, "signature.svg");
  }
});

savePNGButton2.addEventListener("click", function (event) {
  if (signaturePad2.isEmpty()) {
    alert("Please provide a signature first.");
  } else {
    var dataURL = signaturePad2.toDataURL();
    download(dataURL, "signature.png");
  }
});

saveJPGButton2.addEventListener("click", function (event) {
  if (signaturePad2.isEmpty()) {
    alert("Please provide a signature first.");
  } else {
    var dataURL = signaturePad2.toDataURL("image/jpeg");
    download(dataURL, "signature.jpg");
  }
});

saveSVGButton2.addEventListener("click", function (event) {
  if (signaturePad2.isEmpty()) {
    alert("Please provide a signature first.");
  } else {
    var dataURL = signaturePad2.toDataURL('image/svg+xml');
    download(dataURL, "signature.svg");
  }
});
 body {
  font-family: Helvetica, Sans-Serif;

  -moz-user-select: none;
  -webkit-user-select: none;
  -ms-user-select: none;
}

.m-signature-pad {
  position: relative;
  font-size: 10px;
  width: 400px;
  height: 400px;
  border: 1px solid #e8e8e8;
  background-color: #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.27), 0 0 40px rgba(0, 0, 0, 0.08) inset;
  border-radius: 4px;
}

.m-signature-pad:before, .m-signature-pad:after {
 position: absolute;
    z-index: -1;
    content: "";
 width: 40%;
 height: 10px;
 left: 20px;
 bottom: 10px;
 background: transparent;
 -webkit-transform: skew(-3deg) rotate(-3deg);
 -moz-transform: skew(-3deg) rotate(-3deg);
 -ms-transform: skew(-3deg) rotate(-3deg);
 -o-transform: skew(-3deg) rotate(-3deg);
 transform: skew(-3deg) rotate(-3deg);
 box-shadow: 0 8px 12px rgba(0, 0, 0, 0.4);
}

.m-signature-pad:after {
 left: auto;
 right: 20px;
 -webkit-transform: skew(3deg) rotate(3deg);
 -moz-transform: skew(3deg) rotate(3deg);
 -ms-transform: skew(3deg) rotate(3deg);
 -o-transform: skew(3deg) rotate(3deg);
 transform: skew(3deg) rotate(3deg);
}

.m-signature-pad--body {
  position: absolute;
  left: 20px;
  right: 20px;
  top: 20px;
  bottom: 20px;
  border: 1px solid #f4f4f4;
}

.m-signature-pad--body canvas {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    border-radius: 4px;
    box-shadow: 0 0 5px rgba(0, 0, 0, 0.02) inset;
 background-color: #fff;
  }
  
  .btn-grp{display:block; width:100%;}
  .signature-pad--footer{position:absolute; bottom:0; left:0; right:0;}

@media screen and (max-width: 1024px) {
  .m-signature-pad {
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 50%;
    height: auto;
    min-width: 100px;
    min-height: 100px;
    margin: 5%;
  }
  #github {
    display: none;
  }
}

@media screen and (min-device-width: 768px) and (max-device-width: 1024px) {
  .m-signature-pad {
    margin: 10%;
  }
}

@media screen and (max-height: 320px) {
  .m-signature-pad--body {
    left: 0;
    right: 0;
    top: 0;
    bottom: 32px;
  }
  .m-signature-pad--footer {
    left: 20px;
    right: 20px;
    bottom: 4px;
    height: 28px;
  }
  .m-signature-pad--footer
    .description {
      font-size: 1em;
      margin-top: 1em;
    }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/signature_pad/1.3.2/signature_pad.min.js"></script>

<div id="signature-pad-1" class="m-signature-pad">
  <div class="m-signature-pad--body">
    <canvas></canvas>
  </div>
  <div class="signature-pad--footer">
      <div class="signature-pad--actions">
        <div>
          <button type="button" class="button clear" data-action="clear">Clear</button>
          <button type="button" class="button" data-action="change-color">Change color</button>
          <button type="button" class="button" data-action="undo">Undo</button>

        </div>
        <div>
          <button type="button" class="button save" data-action="save-png">Save as PNG</button>
          <button type="button" class="button save" data-action="save-jpg">Save as JPG</button>
          <button type="button" class="button save" data-action="save-svg">Save as SVG</button>
        </div>
      </div>
    </div>
</div>

<button id="clear1" onclick="clear(1);">Clear</button>


<div id="signature-pad-2" class="m-signature-pad">
  <div class="m-signature-pad--body">
    <canvas></canvas>
  </div>
  <div class="signature-pad--footer">
      <div class="signature-pad--actions">
        <div>
          <button type="button" class="button clear" data-action="clear">Clear</button>
          <button type="button" class="button" data-action="change-color">Change color</button>
          <button type="button" class="button" data-action="undo">Undo</button>

        </div>
        <div>
          <button type="button" class="button save" data-action="save-png">Save as PNG</button>
          <button type="button" class="button save" data-action="save-jpg">Save as JPG</button>
          <button type="button" class="button save" data-action="save-svg">Save as SVG</button>
        </div>
      </div>
    </div>
</div>
<button id="clear2" onclick="clear(2);">Clear</button>
<br />
<button id="save">Save</button>


我只在Firefox的JPG选项中遇到了这个错误。 - Matt Ellen
你使用旧版本的签名板有任何理由吗? - Matt Ellen
@MattEllen 最新版本也有同样的问题...我下载的JPG是黑色的。 - Kevin
1个回答

7

问题在于您未设置背景颜色,因此JPG默认为黑色,这意味着整个图像都是黑色的,因为它无法处理透明度

对于PNG或SVG来说这不是问题,这就是为什么这些文件按照预期工作的原因。

要解决这个问题,请将签名板的背景颜色设置为白色(从签名板示例中获取):

var signaturePad = new SignaturePad(canvas, {
  // It's Necessary to use an opaque color when saving image as JPEG;
  // this option can be omitted if only saving as PNG or SVG
  backgroundColor: 'rgb(255, 255, 255)'
});

将以上内容应用到您的代码中:
signaturePad1 = new SignaturePad(canvas1, {backgroundColor: 'rgb(255, 255, 255)'});

我该如何将 backgroundColor 添加到包装器 var wrapper1 = document.getElementById("signature-pad-1"), canvas1 = wrapper1.querySelector("canvas"), signaturePad1; 中? - Kevin
1
@Kevin在你调整画板大小的下面,做出构建签名板的操作。 - Matt Ellen
请您帮我编辑一下我的fiddle代码?我不确定在哪里加入它。 - Kevin
如果我将bgColor添加到画布中,它会如何在PNG版本中反映出来? - Kevin
@Kevin,在你的代码中,当你写signaturePad1 = new SignaturePad(canvas1);时,以及第二个签名板时,这就是你需要进行更改的地方。 更改背景颜色只会给PNG和SVG添加背景颜色。如果你坚持使用白色,你不会注意到任何区别。 - Matt Ellen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接