Search code examples
javascriptjqueryhtmlcanvas

HTML 5 Canvas : Uploaded image colour picker


I'm creating an application using html canvas and javascript. You upload and image and colour pick from it however I'm having an issue where I can only colour pick colours from a small section of the uploaded image. I've tried a few things to fix it and I'm a bit stumped. Anyone have any ideas? I used this to help me: http://www.webdesignerdepot.com/2013/03/how-to-create-a-color-picker-with-html5-canvas/

<canvas width="600" height="300" id="canvas_picker"></canvas>
<div id="hex">HEX: <input type="text"></input></div>
<div id="rgb">RGB: <input type="text"></input></div>
var $files = document.getElementById('file_upload').files[0];
var reader = new FileReader();
reader.onload = imageIsLoaded;

function imageIsLoaded(e) {
    // canvas
    var canvas = document.getElementById('canvas_picker');
    var context = canvas.getContext('2d');
    var $img = $('<img>', { src: e.target.result });

    // Draws Image
    $img.load(function() {
        context.drawImage(this,10, 10);
        $("#loader").hide();
    }); 
}

$('#canvas_picker').click(function(event){
    // getting user coordinates
    var x = event.pageX;
    var y = event.pageY;

    // getting image data and RGB values
    var img_data = canvas.getImageData(x,y , 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
    console.log(R);
    console.log(B);
    console.log(G);

    $('#rgb input').val(rgb);
    console.log(rgb);
    $('#hex input').val('#' + hex);
});

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);
}
reader.readAsDataURL($files);

when I click on a pixel outside the small area, it comes back as 0.


Solution

  • jsBin demo

    Fixed some issues like getImageData trying to read canvas instead of it's context, and the image being drawn at XY 10,10 instead of 0,0.
    Additionally you might want to adjust the Canvas size to the uploaded image W/H.

    In order to prevent coordinates miscalculations (cause you're getting the click coordinate respective to the page edges) and to get the exact position of the mouse inside the canvas, you might want to subtract the canvas offset left / top from the resulting coordinate x, y

    var $picked = $("#picked"); // Just to preview picked colors
    var canvas = $('#canvas_picker')[0];
    var context = canvas.getContext('2d');
    
    
    $("#file_upload").change(function (e) {
      var F = this.files[0];
      var reader = new FileReader();
      reader.onload = imageIsLoaded;
      reader.readAsDataURL(F);  
    });
    
    function imageIsLoaded(e) {
      var img = new Image();
      img.onload = function(){
        canvas.width  = this.width;    // If needed? adjust canvas size
        canvas.height = this.height;   // respective to image size
        context.drawImage(this, 0, 0); // Draw image at 0, 0, not at 10, 10
      };
      img.src = e.target.result;
    }
    
    $('#canvas_picker').click(function(event){
      var x = event.pageX - $(this).offset().left; // Fixed coordinates
      var y = event.pageY - $(this).offset().top; // respective to canvas offs.
      var img_data = context.getImageData(x,y , 1, 1).data;
      var R = img_data[0];
      var G = img_data[1];
      var B = img_data[2]; 
      var rgb = R + ',' + G + ',' + B ;
      var hex = rgbToHex(R,G,B);
      $('#rgb input').val( rgb );
      $('#hex input').val('#' + hex);
      $picked.append("<span style='background:#"+hex+"'>#"+hex+"</span>");
    });
    
    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);
    }
    *{margin:0;}
    canvas{background:#ddd;}
    #picked span{
      display:inline-block;
      width:50px;
      height:50px;
      margin:3px;
      text-align:center;
      text-shadow:1px 1px 1px #000;
      font:8px/50px Arial;
      color:#fff;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <canvas width="600" height="300" id="canvas_picker"></canvas><br>
    <input type="file" id="file_upload"><br>
    <div id="hex">HEX: <input type="text"></div>
    <div id="rgb">RGB: <input type="text"></div>
    
    <div id="picked"></div>