0

I am trying to extract base64 HTML image data after clicking a button which loads the base64 data from the server.

When testing locally, I have to click twice initially to get the expected results. And every subsequent click works as expected.

How can I shape this code so that it triggers on only one click?

<html>
<button id="t-load" type="button" data-board="g" data-tid="0" style="font-size: 11px; padding: 0px; width: 90px; box-sizing: border-box; margin: 0px 6px 0px 0px; vertical-align: middle; height: 18px;">Get Captcha</button>

<div id="t-fg" style="width: 100%; height: 100%; position: absolute; background-repeat: no-repeat; background-position: left top; background-image: url(&quot;data:image/png;base64,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&quot;);"></div>
</html>


<script>
// turn string to image
function b64toImageData(datas) {
    return new Promise(async function (resolve, reject) {

        // We create an image to receive the Data URI
        var img = document.createElement('img');

        // When the event "onload" is triggered we can resize the image.
        img.onload = function () {
        // We create a canvas and get its context.
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');

        // We set the dimensions at the wanted size.
        canvas.width = img.width;
        canvas.height = img.height;

        // We resize the image with the canvas method drawImage();
        ctx.drawImage(this, 0, 0, img.width, img.height);
        // get image data
        var imageDatas = ctx.getImageData(0, 0, img.width, img.height);

        // This is the return of the Promise
        resolve(imageDatas);
        };
        // add data to img
        img.src = datas;
    })
    }

// event listener;
document.addEventListener("click", function () {
  document.getElementById("t-load").onclick = async function () {
        // get img
        var fg = document.getElementById("t-fg").style.backgroundImage.slice(5, -2);
        console.log(fg)
        // get img data
        var base_img = await b64toImageData(fg);
        // log results
        console.log(base_img.data);
  }

});
</script>

John Stud
  • 1,506
  • 23
  • 46
  • Because you bind event only on first click. Remove outer `document.addEventListener("click")` – Justinas Jan 13 '23 at 21:36
  • This leads to the following error if I strip that out; `TypeError: Cannot set properties of null (setting 'onclick')` – John Stud Jan 13 '23 at 21:39
  • 1
    @JohnStud It works fine: https://jsfiddle.net/skg5ow69/ – Unmitigated Jan 13 '23 at 21:40
  • Interesting; I am trying to run this in Requestly/Chrome and it is yielding that error! – John Stud Jan 13 '23 at 21:42
  • 2
    @JohnStud Depending on where you placed your script, you may need to replace `document.addEventListener("click"` with `document.addEventListener("DOMContentLoaded"` – Unmitigated Jan 13 '23 at 21:43
  • @Unmitigated appreciate the help; that resolves the error but when using this on the live website I want to work on, it emits no results in my console; any thoughts? – John Stud Jan 13 '23 at 21:47
  • 1
    @JohnStud Where exactly did you place your script? If you place it right before the closing body tag, then it should work fine. – Unmitigated Jan 13 '23 at 21:48
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/251129/discussion-between-john-stud-and-unmitigated). – John Stud Jan 13 '23 at 21:48
  • @JohnStud As to why you get `Cannot set properties of null`, see [Why does jQuery or a DOM method such as getElementById not find the element?](https://stackoverflow.com/questions/14028959/why-does-jquery-or-a-dom-method-such-as-getelementbyid-not-find-the-element) – Darryl Noakes Jan 13 '23 at 21:58

1 Answers1

1

Instead of the event handlers that you are using, you can delegate the click handler to the body and use still async.

function b64toImageData(datas) {
  return new Promise(async function(resolve, reject) {

    // We create an image to receive the Data URI
    var img = document.createElement('img');

    // When the event "onload" is triggered we can resize the image.
    img.onload = function() {
      // We create a canvas and get its context.
      var canvas = document.createElement('canvas');
      var ctx = canvas.getContext('2d');

      // We set the dimensions at the wanted size.
      canvas.width = img.width;
      canvas.height = img.height;

      // We resize the image with the canvas method drawImage();
      ctx.drawImage(this, 0, 0, img.width, img.height);
      // get image data
      var imageDatas = ctx.getImageData(0, 0, img.width, img.height);

      // This is the return of the Promise
      resolve(imageDatas);
    };
    // add data to img
    img.src = datas;
  })
}

document.body.addEventListener("click", async(e) => {
  let el = e.target;
  if (el.id == "t-load") {
    var fg = document.getElementById("t-fg").style.backgroundImage.slice(5, -2);
    console.log(fg)
    console.log("WAITING!! don't click again!")
    var base_img = await b64toImageData(fg);
    console.log(base_img.data);
  }
});
<button id="t-load" type="button" data-board="g" data-tid="0" style="font-size: 11px; padding: 0px; width: 90px; box-sizing: border-box; margin: 0px 6px 0px 0px; vertical-align: middle; height: 18px;">Get Captcha</button>

<div id="t-fg" style="width: 100%; height: 100%; position: absolute; background-repeat: no-repeat; background-position: left top; background-image: url(&quot;data:image/png;base64,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&quot;);"></div>
imvain2
  • 15,480
  • 1
  • 16
  • 21
  • Thanks this is super helpful and a nice improvement it seems. I am trying to then run this code on https://boards.4channel.org/ck/ to grab captcha; any idea why console.log(fg) still remains empty in it's output? – John Stud Jan 13 '23 at 22:38