Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 1 of 1
  1. #1
    New Coder
    Join Date
    Jun 2009
    Posts
    81
    Thanks
    0
    Thanked 8 Times in 8 Posts

    html5 canvas: Store/Read text in image color channels

    A simple object to store text into and read text from one of an images three color channels: Red/Green/Blue (Alpha not used).

    The object named C is meant to be renamed to whatever works for you.

    **images have to be png**

    use:
    load an image into a canvas element:
    C.load(imgpath,cnvs);

    Store text inside an image:
    C.code.store(C,domObjectToHoldIMG,channel);

    Read the text stored in an image:
    C.code.load("imgpath.png",returnFncToCall,channel);

    The code works in IE, FF, Chrome, Safari, Opera.
    IE, FF, and Opera can use the code from the desktop.

    The images need to be in the same folder holding the code, or in a subfolder.
    You will need to make your own arrangements (code) for uploading and downloading image files to a server.

    There are issue with cross-browser data storage and reading, such as IE can not open image data saved by FF, etc.
    As noted, Chrome and Safari can not read files from the desktop (considered as cross-origin data).
    They can only correctly execute the code when it is stored on a web server.

    reading data from a color channel
    Code:
    <!doctype html>
    <html>
    <head>
    <title>Read Code In Image Color Channel</title>
    <link href='http://fonts.googleapis.com/css?family=Orienta' rel='stylesheet' type='text/css'>
    <style>
    body {font-family: 'Orienta', sans-serif;}
    textarea {width:500px;height:350px;}
    ul {list-style:none;padding:14px;}
    .info {border-radius:14px;background:lightblue;float:left;margin-bottom:10px;}
    .input {padding:14px;border-radius:14px 14px 0px 0px;background:lightblue;float:left;margin-right:10px;}
    </style>
    </head>
    <body>
    <script stype="text/js" src="C.js"></script>
    
    <div class='input'>
    	<form name="f1" onsubmit="return false;">
    		<div><input size="60" id="inp1"> (Path)</div>
    		Channel: 
    		<input id="chred" type="radio" name="n1" value="0" checked /><label for="chred">Red </label>
    		<input id="chgreen" type="radio" name="n1" value="1" /><label for="chgreen">Green </label>
    		<input id="chblue" type="radio" name="n1" value="2" /><label for="chblue">Blue </label>
    		<button>Decode</button>
    		<div>Decoded text in <span id='cchanel'>Red</span> chanel:</div>
    	</form>
    	<div><textarea wrap="off"></textarea></div>
    </div>
    
    <div class="info">
    <ul>
    	<li>Enter the path to the image you want to decode.</li>
    	<li>Select the color channel the text is stored in</li>
    	<li>Click the decode button</li>
    </ul>
    </div>
    
    <div class="info" id="saveinfo"></div>
    <div id="d1"></div>
    <canvas></canvas>
    
    <script>
    // --- handle input --- //
    if(window.event){
    	document.getElementById("inp1").attachEvent("onkeydown",function(e){
    		if(e.keyCode==13){
    			C.load(this.value,document.getElementsByTagName("canvas")[0]);
    			return false;
    		}
    	});
    }else{
    	document.getElementById("inp1").addEventListener("keydown",function(e){
    		if(e.keyCode==13){
    			C.load(this.value,document.getElementsByTagName("canvas")[0]);
    			return false;
    		}
    	},false);
    }
    </script>
    
    <script>
    // --- to track color channel selection. 0=red,1=green,3=blue (,4=alpha - not used) --- //
    C.channel=0;
    // --- setup color channel selection (use 3 channels) --- //
    var rd=document.getElementsByTagName("input");
    for(var i=0;i<rd.length;i++){
    	if(rd[i].name=="n1"){
    		rd[i].onclick = setChanelText;
    	}
    }
    function setChanelText(){
    	document.getElementById("cchanel").innerHTML=["Red","Green","Blue"][this.value];
    	C.channel=[0,1,2][this.value];
    }
    
    // --- load image from path --- //
    document.getElementsByTagName("button")[0].onclick=function(){
    	var c = document.getElementsByTagName("canvas")[0];
    	C.code.load(document.getElementById("inp1").value, showEmbededText, C.channel);
    }
    
    // --- display decoded results --- //
    function showEmbededText(txt){
    	document.getElementsByTagName("textarea")[0].value = txt;
    }
    </script>
    
    </body>
    </html>
    save data to a color channel
    Code:
    <!doctype html>
    <html>
    <head>
    <title>Append Image In Code</title>
    
    <link href='http://fonts.googleapis.com/css?family=Orienta' rel='stylesheet' type='text/css'>
    <style>
    body {font-family: 'Orienta', sans-serif;}
    textarea {width:500px;height:350px;}
    ul {list-style:none;padding:14px;}
    #saveinfo {padding:10px;border-radius:0px 0px 14px 14px;background:lightblue;float:left;margin-bottom:10px;}
    .info {position:absolute;top:-10px;left:566px;}
    .input {padding:14px;border-radius:14px 14px 0px 0px;background:lightblue;float:left;margin-right:10px;}
    #d1 {clear:left;}
    </style>
    
    </head>
    <body>
    
    <div class='input'>
    	<div class='form'>
    	<form name="f1" onsubmit="return false;">
    		<div><input size="60" id="inp1" /> (Path)</div>
    		Channel: 
    		<input id="chred" type="radio" name="n1" value="0" checked /><label for="chred">Red </label>
    		<input id="chgreen" type="radio" name="n1" value="1" /><label for="chgreen">Green </label>
    		<input id="chblue" type="radio" name="n1" value="2" /><label for="chblue">Blue </label>
    		<button>Encode</button>
    	</form>
    	</div>
    	<div class="info">
    		<ul>
    			<li>Enter image path</li>
    			<li>Paste or type text into left textarea</li>
    			<li>Click on Encode</li>
    		</ul>
    	</div>
    
    	<div class='input'>
    	<div>Type in or paste the Code to store in the images <span id='cchanel'>Red</span> chanel</div>
    	<textarea wrap="off"></textarea>
    	</div>
    	<div class='input'>
    	<div>Confirmation: Code Stored in Image</div>
    	<textarea wrap="off"></textarea>
    	</div>
    </div>
    <div id="saveinfo"></div>
    <div id="d1"></div>
    <canvas></canvas>
    
    <script stype="text/js" src="C.js"></script>
    
    <script>
    // --- to track color channel selection. 0=red,1=green,3=blue (,4=alpha - not used) --- //
    C.channel=0;
    
    // --- next 3 function decode the image after it loads --- //
    function decoded(txt){
    	document.getElementsByTagName("textarea")[1].value = txt;
    }
    function decode(img){
    	C.code.load(img.src,decoded,C.channel);
    }
    //imageLoadComplete() is automatically called from the C object after a new image is loaded
    function imageLoadComplete(){
    	var im = document.getElementsByTagName("img");
    	decode(im[im.length-1]);
    	if(imageLoadComplete.doonce){
    		document.getElementById("saveinfo").innerHTML="Right-click on image to save it";
    	}
    }
    imageLoadComplete.doonce=true;
    </script>
    
    <script>
    // --- handle input --- //
    if(window.event){
    	document.getElementById("inp1").attachEvent("onkeydown",function(e){
    		if(e.keyCode==13){
    			C.load(this.value,document.getElementsByTagName("canvas")[0]);
    			return false;
    		}
    	});
    }else{
    	document.getElementById("inp1").addEventListener("keydown",function(e){
    		if(e.keyCode==13){
    			C.load(this.value,document.getElementsByTagName("canvas")[0]);
    			return false;
    		}
    	},false);
    }
    </script>
    
    <script>
    // --- fluff. synchronized scrolling --- //
    document.getElementsByTagName("textarea")[0].onscroll = function(){keeptogether(0)}
    document.getElementsByTagName("textarea")[1].onscroll = function(){keeptogether(1)}
    function keeptogether(n){
    	if(n==1)
    		document.getElementsByTagName("textarea")[0].scrollTop=document.getElementsByTagName("textarea")[1].scrollTop
    	else
    		document.getElementsByTagName("textarea")[1].scrollTop=document.getElementsByTagName("textarea")[0].scrollTop
    }
    </script>
    
    <script>
    // --- setup color channel selection (use 3 channels) --- //
    var rd=document.getElementsByTagName("input");
    for(var i=0;i<rd.length;i++){
    	if(rd[i].name=="n1"){
    		rd[i].onclick = setChanelText;
    	}
    }
    function setChanelText(){
    	document.getElementById("cchanel").innerHTML=["Red","Green","Blue"][this.value];
    	C.channel=[0,1,2][this.value];
    }
    
    // --- load image from path --- //
    document.getElementsByTagName("button")[0].onclick=function(){
    	var txt = document.getElementsByTagName("textarea")[0].value;
    	if(txt==""){
    		alert("There is no code to encode");
    		return false;
    	}
    	var d1 = document.getElementById("d1");
    	var c = document.getElementsByTagName("canvas")[0];
    	C.code.store(txt,d1,c, C.channel);
    }
    //You can load a default image is desired
    //C.load("images/someimage.png",document.getElementsByTagName("canvas")[0]);
    </script>
    
    </body>
    </html>
    the C object
    Code:
    var C=(function(){
    	var canvas = null;
    	var loadIMG = function(imgpath,cnvs){
    		var img = new Image();
    		img.src = imgpath;
    		img.onload = function () {
    			cnvs.width = this.width;
    			cnvs.height = this.height;
    			var ctx = cnvs.getContext('2d');
    			ctx.drawImage(img,0,0);
    			delete this;
    		}
    	}
    	var loadCode = function(imgsrc,fnc,ch){
    		var d=new Image;
    		d.onload=function(){
    			var t=this,wid=t.width,hei=t.height;
    			var canvas = document.createElement("canvas");
    			canvas.id = "thecanvas";
    			canvas.width = wid;
    			canvas.height = hei;
    			var ctx = canvas.getContext("2d");
    			ctx.drawImage(t,0,0);
    			var gidata = ctx.getImageData(0, 0, wid, hei);
    			var idata = gidata.data;
    			var c="";
    			for(var i=0;i<idata.length;){
    				var e=idata[i+ch];if(e>0 && e<128){c+=String.fromCharCode(e);}
    				i+=4;
    			}
    			fnc(c);
    			delete canvas;
     			delete this;
    		};
    		d.src=imgsrc;
    	}
    	var makePNG = function(s,domobj,cnvs,ch){
    		s = s.replace(/\r/g,"");
    		var l = s.length;
    		var ctx1 = cnvs.getContext("2d");
    		var cdata1 = ctx1.getImageData(0,0,cnvs.width, cnvs.height);
    		var cdl1 = cdata1.data.length;
    		if(cdl1 < l*4){
    			alert("Image is too small for the code.");
    			return false;
    		}
    		for (var i=0, idx=0; i<cdl1; i+=4, idx++){
    			if(idx<l){
    				cdata1.data[i+ch] = s.charCodeAt(idx);
    			}else{
    				cdata1.data[i+ch] = 0;
    			}
    		}
    		canvas = document.createElement("canvas");
    		canvas.width = cnvs.width;
    		canvas.height = cnvs.height;
    		var ctx = canvas.getContext("2d");
    		ctx.putImageData(cdata1, 0, 0);
    		setTimeout(function(){C._producePNG(domobj)},1000);
    	}
    	var producePNG = function(domobj){
    		var itxt = canvas.toDataURL("image/png");
    		var png = document.createElement("img");
    		png.src = itxt;
    		domobj.appendChild(png);
    		delete canvas;
    		canvas = null;
    
    		try{
    			imageLoadComplete(); //public confirmation of new image loaded in page.
    		}catch(e){}
    	}
    	return{
    		_producePNG:function(domobj){producePNG(domobj)}, // callback method for for C object use only please.
    		code:{
    			load:function(imgsrc,fnc,ch){if(ch==null)ch=0;loadCode(imgsrc,fnc,ch)},
    			store:function(s,domobj,cnvs,ch){if(ch==null)ch=0;makePNG(s,domobj,cnvs,ch)}
    		},
    		load:function(imgpath,cnvs){loadIMG(imgpath,cnvs)}
    	}
    	/*
    		USE:
    		C.load(imgpath,cnvs); // loads image into canvas element
    		C.code.store(C,domObjectToHoldIMG,channel);		// Stores code in image
    		C.code.load("imgpath.png",returnFncToCall,channel);	// Retrieves code from image
    	*/
    })();
    Last edited by rdspoons; 09-18-2012 at 04:41 AM. Reason: added "**images have to be png**"


 

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •