javascriptjqueryhtml

Image input to canvas and color picker


I have found 2 scripts, one for loading image from file input into canvas and the other is a color picker from image in canvas, but I can't find a way to fuse them into one script.

My goal is to have script that takes file from input, puts it into canvas and than targets at x=10,y=10 coordinates on image and calculates rgb and hex codes of it without submitting form.

html

<label>Image File:</label><br/>
<input type="file" id="uploadImage" name="uploadImage"/>
<canvas id="cvs" ></canvas>
<div id="hex">HEX: <input type="text"></input></div>
<div id="rgb">RGB: <input type="text"></input></div>

File to canvas without submit code

  var imageLoader = document.getElementById('uploadFile');
        imageLoader.addEventListener('change', handleImage, false);
        var canvas = document.getElementById('cvs');
        var ctx = canvas.getContext('2d');


        function handleImage(e) {
            var reader = new FileReader();
            reader.onload = function (event) {
                var img = new Image();
                img.onload = function () {
                    canvas.width = img.width;
                    canvas.height = img.height;
                    ctx.drawImage(img, 0, 0);
                }
                img.src = event.target.result;
            }
            reader.readAsDataURL(e.target.files[0]);
        }

I want to do something like this together with working script from above.

function rgbToHex(R,G,B) {return toHex(R)+toHex(G)+toHex(B)}
        function toHex(n) {
          n = parseInt(n,10);
          if (isNaN(n)) return "00";
          n = Math.max(0,Math.min(n,255));
          return "0123456789ABCDEF".charAt((n-n%16)/16)  + "0123456789ABCDEF".charAt(n%16);
        }
        $('#cvs').click(function(event){
          // getting image data and RGB values
          var img_data = ctx.getImageData(10, 10, 1, 1).data;
          var R = img_data[0];
          var G = img_data[1];
          var B = img_data[2];  
          var rgb = R + ',' + G + ',' + B;
          // convert RGB to HEX
          var hex = rgbToHex(R,G,B);
          // making the color the value of the input
          $('#rgb input').val(rgb);
          $('#hex input').val('#' + hex);
        });

Solution

  • Instead of $('#cvs').click(function(event){ create a function that takes as arguments the two x and y coordinates. Then, to retrieve the RGBA value use CanvasRenderingContext2D: getImageData() method:

    const getColor = (x, y) => {
      const [r, g, b, a] = ctx.getImageData(x, y, 1, 1).data;
      console.log(r, g, b, a);
    };
    

    const el = (sel, par = document) => par.querySelector(sel);
    
    const elUpload = el("#uploadImage");
    const elCanvas = el("#canvas");
    const ctx = elCanvas.getContext("2d", { willReadFrequently: true });
    
    const handleImage = (ev) => {
      Object.assign(new FileReader(), {
        onload(evt) {
          Object.assign(new Image(), {
            src: evt.target.result,
            onload() {
              ctx.canvas.width = this.naturalWidth;
              ctx.canvas.height = this.naturalHeight;
              ctx.drawImage(this, 0, 0);
              getColor(10, 10);  //  <<< GET IMMEDIATELY AT x10 y10
            }
          });
        }
      }).readAsDataURL(ev.target.files[0]);
    };
    
    const rgbToHex = (r, g, b, a = 255) => {
      const hex = ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
      const alpha = Math.round(a).toString(16).padStart(2, "0");
      return `#${hex}${alpha}`;
    };
    
    const getColor = (x, y) => {
      const [r, g, b, a] = ctx.getImageData(x, y, 1, 1).data;
      const rgb = `rgb(${r} ${g} ${b} / ${a/255})`;
      const hex = rgbToHex(r, g, b, a);
      el("#pos").value = `X:${x} Y:${y}`;
      el("#rgb").value = rgb;
      el("#hex").value = hex;
      el("#preview").style.setProperty("--bg", rgb);
    };
    
    elUpload.addEventListener("change", handleImage);
    elCanvas.addEventListener("click", ({x, y}) => {
      const xOrg = (x - elCanvas.offsetLeft) / elCanvas.offsetWidth * elCanvas.width;
      const yOrg = (y - elCanvas.offsetTop) / elCanvas.offsetHeight * elCanvas.height;
      getColor(xOrg, yOrg);  // <<< GET ON CLICK
    });
    #canvas {
      display: block;
      width: auto;
      height: 150px;
      cursor: crosshair;
    }
    
    #preview {
      width: 50px;
      height: 50px;
      border: 1px solid #000;
    
      &::after {
        content: "";
        display: block;
        width: 100%;
        height: 100%;
        background-color: var(--bg, #0000);
      }
    }
    
    #preview, 
    #canvas {
      background: 50% / 12px 12px repeating-conic-gradient(#ddd 0% 25%, #fff 0% 50%);
    }
    Read image pixel color at coordinates: X=10 Y=10:<br>
    <label>Image: <input type="file" id="uploadImage"></label>
    <canvas id="canvas"></canvas>
    Click on the image to read the color
    <div>Coordinate: <input id="pos" type="text"></div>
    <div>HEXa: <input id="hex" type="text"></div>
    <div>RGBa: <input id="rgb" type="text"></div>
    Color preview: <div id="preview"></div>