admin管理员组

文章数量:1344174

I am using Signature pad js from szimek for making canvas signature pad. I have used 3 canvas at a time. After some research I got a link from Codepen for using multiple instance. Its working though, but the problem arise when the signature needs to be downloaded. After download the PNG and JPG, the images get fully black. Sharing the codes below.

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 .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=".3.1/jquery.min.js"></script>
<script src=".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>

I am using Signature pad js from szimek for making canvas signature pad. I have used 3 canvas at a time. After some research I got a link from Codepen for using multiple instance. Its working though, but the problem arise when the signature needs to be downloaded. After download the PNG and JPG, the images get fully black. Sharing the codes below.

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./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./ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare./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>

Share Improve this question edited Feb 19, 2020 at 9:25 Matt Ellen 11.6k4 gold badges72 silver badges93 bronze badges asked Feb 19, 2020 at 6:33 KevinKevin 1,3771 gold badge9 silver badges21 bronze badges 3
  • I'm only getting the bug with the JPG option in Firefox – Matt Ellen Commented Feb 19, 2020 at 9:30
  • Is there a reason you're using an old version of signature pad? – Matt Ellen Commented Feb 19, 2020 at 9:39
  • @MattEllen same problem in latest version also.. I am getting the downloaded JPG is to be black. – Kevin Commented Feb 19, 2020 at 10:00
Add a ment  | 

1 Answer 1

Reset to default 10

The problem is that you're not setting the background colour, so the JPG is defaulting to black, which means that the whole image is black, because it can't handle transparency.

It's not a problem for PNG or SVG, which is why these work as expected.

To fix it set the background colour of the signature pad to white (taken from the signature pad example):

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)'
});

To apply the above to your code:

signaturePad1 = new SignaturePad(canvas1, {backgroundColor: 'rgb(255, 255, 255)'});

本文标签: