1

the errorI am new to Canvas and I have a task where I have an input box to input a text. then I upload an image.When the image is displayed, it should have the text repeated in the background.

So far I have been able to upload the image and slightly grey scale it, but I do not know how to to use the text to be repeate din the background

It would be great if someone could point me in the direction of what to do next.-Thanks

my code so far:

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<script>
document.addEventListener('DOMContentLoaded', function(){
    var canvas = document.getElementById('canvas');
    var context = canvas.getContext('2d');
    var source = document.getElementById('fileupload');
    source.addEventListener('change',handleImage,false);

    function handleImage(e){
        var reader = new FileReader();
        reader.onload = function(event){
            var img = new Image();
            img.onload = function(){

                context.drawImage(img,0,0);
                grayScale(context, canvas);
            }
            img.src = event.target.result;
        }
        reader.readAsDataURL(e.target.files[0]);
    }

    function grayScale(context, canvas) {
        var imgData = context.getImageData(0, 0, canvas.width, canvas.height);
        var pixels  = imgData.data;
        for (var i = 0, n = pixels.length; i < n; i += 4) {
            pixels[i]+=20;
            var grayscale = (pixels[i*4] + pixels[i*4+1] + pixels[i*4+2]) /3;
            pixels[i*4  ] = grayscale;        // red
            pixels[i*4+1] = grayscale+30;        // green
            pixels[i*4+2] = grayscale;        // blue
           // pixels[i+3] = 0.5;            // is alpha
        }
        //redraw the image in black & white
        context.putImageData(imgData, 0, 0);
    }



})
</script>


        <input type="text" id="textcontent">
        <input type="range" id="slider">


        Background<input type="checkbox" id="background">
        Select file: <input id="fileupload" type="file" multiple>
        <canvas id='canvas' width="800" height ="800"></canvas>

</body>
</html>
javascript novice
  • 777
  • 2
  • 9
  • 28
  • It seems like the text is repeated in the background in your screenshot? Is there a certain color the background needs to be (white for example). Text can be repeated on top of the canvas after the image is created, but the hard part will be decided what the background vs what the image is. But depending on how you define that could not be too big of a problem. – Spencer Wieczorek Aug 26 '15 at 03:18
  • If background color checkbox is checked, the background is black, else the background is white. I want to know how to repeat the text in the background oncethe image is created. – javascript novice Aug 26 '15 at 03:27
  • There's a bunch of these kind of image --> ascii generators around on the web, a number of them have a description of the approach used. I've not read about them for several years now. From memory, there are a couple of approaches that seem most common - each of them require that you can examine a bitmap of any/all characters used for the final image. Some simply determine the ratio of black:white pixels and use this to calculate the 'brightness' of the charcater, while others also take into account _where_ the pixels are found, to provide shape-matching. Consider `-` : `_` , `[`:`]`, `<`:`>` – enhzflep Aug 26 '15 at 03:54
  • See http://stackoverflow.com/questions/394882/how-do-ascii-art-image-conversion-algorithms-work and http://www.codeproject.com/Articles/20435/Using-C-To-Generate-ASCII-Art-From-An-Image – enhzflep Aug 26 '15 at 03:55

1 Answers1

0

I'm not sure it is exactly what you want but from your given code, and what you asked, here is a solution :

You can first draw your text in a new canvas, and use it as a pattern to your main one. Then, thanks to context2d's globalCompositeOperation set to 'destination-in', you can keep only the text pattern over your image.

var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
var source = document.getElementById('fileupload');
source.addEventListener('change', handleImage, false);
var slider = document.getElementById('slider');
slider.onchange = handleImage;
var inputText = document.getElementById('textcontent');
inputText.onchange = handleImage;

function handleImage(e) {
  if (source.files.length < 1) return;
  var reader = new FileReader();
  reader.onload = function(event) {
    var img = new Image();
    img.onload = function() {
      context.fillRect(0, 0, canvas.width, canvas.height);
      context.drawImage(img, 0, 0);
      grayScale(context, canvas);
      textBackground();
    }
    img.src = event.target.result;
  }
  reader.readAsDataURL(source.files[0]);
}

function grayScale(context, canvas) {

  var imgData = context.getImageData(0, 0, canvas.width, canvas.height);
  var pixels = imgData.data;
  for (var i = 0, n = pixels.length; i < n; i += 4) {
    pixels[i] += 20;
    var grayscale = (pixels[i] + pixels[i + 1] + pixels[i + 2]) / 3;
    pixels[i] = grayscale; // red
    pixels[i + 1] = grayscale + 5; // green
    pixels[i + 2] = grayscale; // blue
    // pixels[i+3] = 0.5;            // is alpha
  }
  //redraw the image in black & white
  context.putImageData(imgData, 0, 0);
}

function textBackground() {
  var txt = inputText.value;
  if (!txt) return;
  var fontSize = +slider.value;

  var c = document.createElement('canvas'),
    ctx = c.getContext('2d');

  var check = document.getElementById('background').checked;
  //set the fontSize so we are able to set our canvas size
  ctx.font = fontSize + "px Arial";
  c.width = ctx.measureText(txt).width + fontSize;
  c.height = fontSize;
  // set it again since the change of width has reset it
  ctx.font = fontSize + "px Arial";
  ctx.fillText(txt, 0, fontSize);
  // draw our text

  var pattern = context.createPattern(c, 'repeat');
  // set our main canvas fillStyle to our newly created pattern
  context.fillStyle = pattern;
  // should we keep only the text or draw the text over the image
  context.globalCompositeOperation = check ? 'destination-in' : 'source-over';
  context.fillRect(0, 0, canvas.width, canvas.height);
  // reset the context
  context.globalCompositeOperation = 'source-over';
  context.fillStyle = "#000";
}
<input type="text" id="textcontent">
<input type="range" id="slider" min=4 max=40 value=6>Background


<input type="checkbox" checked id="background">Select file:
<input id="fileupload" type="file" multiple>
<canvas id='canvas' width="800" height="800"></canvas>

Note : I also fixed your grayscale function, to avoid the maybe not desired moiré effect.

Kaiido
  • 123,334
  • 13
  • 219
  • 285
  • Thanks! this is very close to what I wanted. Just one thing though. When I run this on my system,the text is spaced widely apart horizonatally,but its fine vertically. I am wondering why this is happening. – javascript novice Aug 26 '15 at 15:36
  • My page looks as seen in the image above. Any suggestions? – javascript novice Aug 26 '15 at 15:42
  • Indeed, there seems to be a bug in here. At first sight I would say that it is related to the `ctx.meaureText` method returning undefined, but I think that FF guys would have spot this so it could be (pure speculation, I don't remember how measureText deals this) that you don't have the font on your system. If you want to check by yourself, try to append `c` to the document and check its width. If it seems correct, then the problem comes from createPattern. Anyway, I'll try tomorrow on my Ubuntu. – Kaiido Aug 26 '15 at 16:25
  • I am wondering if it is a browser issue. Seems to be working ok on chrome. Not on firefox. – javascript novice Aug 26 '15 at 16:48
  • Looks like I shouldnt be using this at all. The task is to have a div with the text as multiple span elements and the image should be on it. Such that if I select the text in the image, it can be selected. I have no idea how to go about it. – javascript novice Aug 26 '15 at 19:42
  • I think I need to split the input text, put each letter in a span and attach each span to a pixel (that you get from the image data). – javascript novice Aug 26 '15 at 22:33
  • Found the bug (actually FF on ubuntu is the only one who got it right), fontSize was a string, needed to transform it to a number. Now, for your new requirements, I'm not sure that canvas is the best way to do it : if you really need `` elements, you will have some harsh time to make it clip your image. One solution would be to append all those spans in a div, and set this div's background image to your canvas, or to use svg : check [this link for an example](http://stackoverflow.com/questions/10846504/text-with-image-background-in-svg-or-css). – Kaiido Aug 27 '15 at 01:14
  • Thanks @Kaiido. I will try workign with the new approach over the weekend. – javascript novice Aug 28 '15 at 17:16