Browsers & Color Management II – the Code

This post follows on the Browsers & Color Management I – Sending Color Patches in through the Web Browser with more details on the code used to drive images through the browser window. As one might have expected, three components were needed: html, css, and some sort of JavaScript. For the latter, I picked jQuery library (jquery-1.7.min.js) which is well suited for this task.

About the code:

jQuery code used in this project is essentially a slideshow script that works on the client side. That explains why we do not need any active connection to the Internet. It will run in our browser providing that JavaScript is enabled. Since it turns images into a slideshow, it can be used for many other purposes, e.g., to display photos on our personal web site. jQuery is free, open source software, dual-licensed under the MIT License or the GNU General Public License, Version 2 and it is included in the “js” folder inside the zip file.

If you have not done so before, download it here: v 1.01 | Complete set of files. Fixed a minor error in the index increment and displaying full set of images. – [downloaded 1036 times]

The code below is just a sample of the whole script with associated files, shown only to outline the structure and logic of the script.

manual_patches.js [part 1]

The script starts with declaration of several variables. These are mostly arrays that are used to store different sets of images. Function “mainimage()” (line 9) is the heart of the script. It takes index “nr” and displays the next image in “array0”. Interestingly, there are three calls to the white patch, all in order to provide a stage at which a measuring device can read the white point. During the “onclick” event at the “Next” button, the first white patch will hide (line 5, [part 3], id=”white”). Next, mainimage() function will fire up by fading out another instance of the white patch (class=”img1″) and the index will advance to “0”. This happens at line 10 with the “complete” callback function that is fired once the fadeOut event is complete. Only then, the next image in array fades in (second image). Index gets incremented by the event function (lines 4, 17 in the [part 3]) and its value will be displayed in the Patch field which is <p> element of the html document with id attribute of “count” (<p id=”count”> </p>).

// Declare global variables
var index = -1; // accounting for the three white patches
var array0 = [];
var array1 = [];
var array1a = [];
var spaces = ["untagged", "srgb", "argb", "prophoto"];

// Main slideshow function
function mainimage(nr) {
      // when run, move from the first image to the next one
     $("div.mainimg ul li:eq(0) div img").fadeOut({"duration":100, complete:function() {
         $(this).attr("src",array0[nr]).fadeIn(100); //display image from the array based on the index and src attribute
         nr = index; //this will set the index of the currently selected image
	$('#count p').html('Patch: '+ (index+1) + ''); // display image sequence number

manual_patches.js [part 2]

Next goes a general wrapper function() used for several events and settings. At the beginning, default settings are defined, such as, default color space (untagged), array0 that contains src attribute of all images, default count of images and its screen output for “Total images: “. Script then follows by generating CSS buttons which have the “onclick” event attached to each of them.

The key part of the wrapper function is the selection of color spaces (line 20). It involves the standard “click()” function that sets the color space variable and css styling upon the click event. There are four selection calls that have very similar structure. Once the color space variable is set, the main array0 is generated by calling the function “makearray()” at line 48. At the same time, radio button for the set selection is cleared to have no default state (line 39).

Now, about the “makearray()” function. It looks at the src path of each image in #photos  html tag and alters the hard-coded path by substituting the default path with the current space variable set above upon the click event (e.g., line 35). This is done with help of the callback function (index, attr). In the next step, an array of image src tags is created using the “each” method. Actually, two arrays are created; one with the full set of images (array1) and another one with the limited set of images (array1a). Which array to use depends on the radio button selection (line 66). Conditional statement and two methods of copying arrays are used. Finally, the total image count is updated by reading the array0 length.

// Set defaults
 		 curr_space = spaces[0]; // untagged images are set as default
		 makearray(); //run function defined at line 48
		 array0 = array1a.slice(); // plain copy of array1a
		 totalimages = 12;
		 $('#total p').html('Total images: '+ totalimages + '');

//Prepare radio and CSS buttons
	$("#patch-area").append('<a id="next" onclick="next();" href="#">Next</a>');
	$("#patch-area").append('<a id="reset" onclick="reset();" href="#">Reset</a>');
	$("#patch-area").append('<a id="previous" onclick="previous();" href="#">Previous</a>');

           $('input').click(function () {
           $('input:not(:checked)').parent().removeClass("selected"); // box selection styling

//-----------------------> select color space
		if ($(this).text() == "Untagged - No CM") 	{
		$(this).text("Untagged - No CM");
		$('#selection a').css('background','#000F7D');
		 curr_space = spaces[0];	// Set space for this option
		 makearray(); // make the array - see below

		if ($(this).text() == "sRGB") {
		$('#selection a').css('background','#000F7D');
		curr_space = spaces[1]; // Set space for this option
		array0 = []; // Clear all arrays
		array1 =[];
		array1a = [];
		$('#source2').prop('checked', false); // Clear selection of the set (radio buttons)

//............ similar for other color spaces
// -----------------------------> end of space selection
//-------------------------------> function to prepare arrays based on space

function makearray() 	{
	$('img').attr('src',function(index,attr){ // Create correct path to images based on the selected color space
        return attr.replace(/srgb|argb|prophoto|untagged/,curr_space);

	$('#photos img').each(function() { // take all images from #photos in index.html
    	array1.push($(this).attr('src')); // and push their src attribute into array1

	$('#photos img').filter('.keep').each(function() { // take some images from #photos (gray and primaries)
    	array1a.push($(this).attr('src')); // and push their src attribute into an array1a

//-----------------------------> Select which set of images to run

     $("input[name='set']").live('click', function(){
 	 var radio_value = $(this).val(); // Get the button value after it is clicked

  	 if(radio_value == 'short') {
   	 	array0 = array1a.slice(); } // Just gray and primaries
   	 else 	{
   	 	array0 = []; //Empty Array0 and assign it again in the next step
   	 	array0 = array1; // Full set of patches

 	totalimages = array0.length; //  Update Array0 size and print it to the screen
 	$('#total p').html('Total images: '+ totalimages + '');


manual_patches.js [part 3]

The scripts ends with section of “events”, specifically with assignment of events to buttons  NEXT, PREVIOUS, and RESET. These assignments consist of index increment (decrement), text styling (hide), and trigger of the main slideshow (mainimage(index)) at the line 8. Reset to the original state is executed by the “window.location.reload(true)” statement.

// Events
function next() {
        if (index < array0.length) {
            $('#white').hide(); // Hide the white patch
            $('#container ol li').hide(); //Hide instruction area
            $('#third').hide(); // Hide the instruction header
            mainimage(index); //start the slideshow
        else {
        	window.location.reload(true); // reset to beginning

function previous() {
        if (index < array0.length & index > 0) {
        else {
        	window.location.reload(true); // reset to beginning

function reset() {
        	window.location.reload(true); // reset to beginning

index.html, only part

The main part of XHTML mark-up is outlined below. The body tag opens with a typical block level element <div> with id attribute of “container”. Navigation mark-up follows next wrapped in another <div> tag with id “selection”. Those are color space buttons, counters, radio buttons and their description. Patch area starts at line 28 with div element encapsulating the first white patch (lines 28-29). This patch is not part of the animation and serves the purpose of calibrating the measuring device. Another instance of the white patch is defined in another div element with class “mainimg” (lines 31-35). This is the first image that fades out when the animation starts.

Next is the complete list of available images wrapped in div element with id “photos”. Each image either has class “keep” associated with it or has no class at all. In the former case, the “keep” class “marks” the image for inclusion in the “shorter” list of gray ramp and primaries. Sub-directory “untagged” is the default part of src path. It is this part that gets replaced by the chosen color space variable (on “click” event) through the jQuery script. If you wish to provide your own set of images, it is the place where they would be entered.

<div id="container">
   <div id="selection">
    <a id="untagged" href="#">Untagged - No CM</a>
    <a id="srgb" href="#">sRGB</a>
    <a id="argb" href="#">Adobe98 RGB</a>
    <a id="prophoto" href="#">Pro Photo</a>

   <div id="total">Total Images:</div>
   <div id="count">Patch: white</div>

<ul id="radio">
<li><input id="source1" type="radio" name="set" value="all" class='ctrl'></input>
<label for="source1">All available patches</label>
<li><input id="source2" type="radio" name="set" checked="checked" value="short"></input> <!-- Default state is "checked"-->
<label for="source2">Gray ramp and Primaries</label>
</div> <!-- close selection -->

<div id="first"><a href="#">[2]<span>
Choose and click which set of patches you wish to run.</span></a></div>
<div id="second"><a href="#">[1]<span>
Always click "Reset" first. Then click the desired tab above to select patches with a specific
embedded color profile.</span></a></div>

<h2>RGB patches</h2>
<div id="patch-area">
   <div id="white"><img src="images/white.jpg" alt="white" /> <!-- show the white patch for instrument calibration --></div>

<div class="mainimg">
<li><div><img alt="n-255" src="images/untagged/n-255.jpg" /></div></li>

<div id="photos"><!-- Customize the patches below. Keep the syntax. -->
<img src="images/untagged/n-255.jpg" alt="n-255" />
<img src="images/untagged/n-223.jpg" alt="n-223" />
................... and so on for the all patches ..............
<img src="images/untagged/b-0.jpg" alt="b-0" /></div>
</div><!-- closing patch-area-->

Again, all discussed files including html file and css styling sheet are included in the zipped file through the download.

Book References
  • jQuery: Novice to Ninja
    Earle Castledine and Craig Sharkie

    ISBN: 0980576857
    Publisher: SitePoint
    Published: March 7, 2010

3 Responses — Written on December 23, 2011 — Filed in: Code, Color management, Software

3 Responses

  1. santi on February 5, 2012, 3:46 am Reply


    Do you know if exists a script that tells the browser (chrome, for example) to use “srgb color profile” on images?
    thank you

  2. mpatek on February 5, 2012, 8:17 am Author Reply

    I am not aware of any such script. Browser’s ability to “understand” profiles has to be built into the browser engine. As of today, Firefox can use any display profile (including sRGB. This can be set in Firefox (through about:config command – see instructions in my other blog), but not in Chrome. Chrome 16 is supposedly handling profiles (Mac version only for now).

  3. santi on February 9, 2012, 6:40 am Reply

    thank you for your answer mpatek

Leave a Reply

Your address will not be published.