Why do I get null characters at the end of my files when encoding and decoding?

I’m making a web app that encodes an input file into a canvas element based on the char codes of each character in the input file.

For instance ABC, being 0x41, 0x42 and 0x43 would make the color code #414243, and so on for the entire file.

A canvas element is then updated with the color codes to create a downloadable image.

To decode, there is a function that goes through each part of the uploaded image file, gets the color code and converts it back into characters based on the color values.

The issue is, I’m getting NUL characters at the end of the decoded file, and I’m at my wits end about how to handle these.

Here’s the full JS code

function getFile (inp, encode=true){
  //no return
  let file = inp.files[0];
  let fr = new FileReader();

  if (encode){
    fr.readAsText(file);
    fr.onload = function(){
      let hexCodes = colorCode (fr.result, file['name']);
      let imgMain = document.getElementById ("main-canvas");
      imgMain.width = hexCodes.length;
      imgMain.height = 100;
      let ctx = imgMain.getContext("2d");
      for (let i=0;i<hexCodes.length;++i){
        ctx.fillStyle = hexCodes[i];
        ctx.fillRect (i,0,i+1,100);
      }
    };
  }else{
    fr.readAsDataURL(file);
    fr.onload = function(){
      var imgTmp = new Image();
      imgTmp.src = fr.result;
      imgTmp.onload = function(){
        let tmpDecode = colorDecode(imgTmp);
        let link = document.getElementById("download-link");
        link.download = tmpDecode[0];
        let tmpBlob = new Blob ([tmpDecode[1]],{type: 'text/plain'});
        link.href = window.URL.createObjectURL(tmpBlob);
      }
    }
  }
  
  fr.onerror = function(){
    console.log (fr.error);
  };
}

function rbg(r,g,b){
  //returns an HTML color code
  let rR = "0"+r.toString(16);
  let rG = "0"+g.toString(16);
  let rB = "0"+b.toString(16);
  rR = rR.substr(rR.length - 2);
  rG = rG.substr(rG.length - 2);
  rB = rB.substr(rB.length - 2);
  return "#" + rR + rG + rB;
}

function colorCode(strInp, strName){
  //returns an array of color codes;
  let colors    = [[],[],[]];
  let colorsHex = [];
  while(strName.length<256)
    strName += String.fromCharCode (0);
  let wholeStr = strName + strInp;
  for(let i=0;i<wholeStr.length;++i){
    colors[i%3].push(wholeStr[i].charCodeAt(0));
  }
  if (colors[0].length>colors[1].length)
    colors[1].push(0);
  if (colors[1].length>colors[2].length)
    colors[2].push(0);
  for (let i=0;i<colors[0].length;++i){
    colorsHex.push(rbg(colors[0][i],colors[1][i],colors[2][i]));
  }
  return colorsHex;
}

function colorDecode(imgInp){
  //returns text value of file
  let imgMain = document.createElement ("canvas");
  let ctx = imgMain.getContext("2d");
  imgMain.width = imgInp.width;
  if (imgMain.width < 256)
    return "Image is not of correct length!";
  imgMain.height = imgInp.height;
  ctx.drawImage (imgInp, 0, 0);
  let retVal = "";
  let name = "";
  for (let i=0;i<86;++i){
    let p = ctx.getImageData(i,10,1,1).data;
    if (p[0] === 0)
      break;
    name += String.fromCharCode (p[0]);
    if (i!==86){
      if (p[1] === 0)
        break;
      name += String.fromCharCode (p[1]);
      if (p[2] === 0)
        break;
      name += String.fromCharCode (p[2]);
    }
  }
  name += String.fromCharCode(0); //ensures it's null terminated
  for (let i=85;i<imgMain.width;++i){
    let p = ctx.getImageData(i,10,1,1).data;
    if (i!==85)
      retVal += String.fromCharCode(p[0]);
    retVal += String.fromCharCode(p[1]);
    retVal += String.fromCharCode(p[2]);
  }
  while(retVal[-1]===String.fromCharCode(0) ||
        retVal[-1]===String.fromCharCode(32))
    retVal = retVal.substr(0,retVal.length-1);
  return [name.substring(0,name.length-1), retVal];
}

And here’s the HTML just in case it’s relevant

<doctype html>
<html>
  <head>
    <title>Color Coder</title>
    <script src="colorCoder.js"></script>
  </head>
  <body>
    <label for="inp">Select a file to convert</label>
    <input type="file" id="inp" onchange="getFile(this)">
    <br>
    <canvas id="main-canvas" height=100></canvas>
    <br>
    <label for="inpDecode">Select an image to decode</label>
    <input type="file" id="inpDecode" onchange="getFile(this, false)">
    <br>
    <a id="download-link" download href="javascript:alert('Nothing to download!');">Download</a>
  </body>
</html>

I know I’m adding char values 0 at the end of the strings, but shouldn’t

while(retVal[-1]===String.fromCharCode(0) ||
        retVal[-1]===String.fromCharCode(32))
    retVal = retVal.substr(0,retVal.length-1);

take care of removing those NUL characters?

I’ve tried changing readAsText to readAsBinaryString, still get similar (the same?) issues.

I’m downloading the images as .PNG, and while I don’t know, it doesn’t look like it’s losing resolution at any point.