{"id":1343,"date":"2011-12-23T08:15:10","date_gmt":"2011-12-23T15:15:10","guid":{"rendered":"http:\/\/www.marcelpatek.com\/blog\/?p=1343"},"modified":"2012-01-02T09:15:39","modified_gmt":"2012-01-02T16:15:39","slug":"cm-code","status":"publish","type":"post","link":"https:\/\/www.marcelpatek.com\/blog\/2011\/12\/23\/cm-code\/","title":{"rendered":"Browsers &#038; Color Management II &#8211; the Code"},"content":{"rendered":"<p>This post follows on the <a href=\"http:\/\/www.marcelpatek.com\/blog\/2011\/11\/27\/cm-patches\/\">Browsers &amp; Color Management I &#8211; Sending Color Patches in through the Web Browser<\/a> 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.<\/p>\n<h2><\/h2>\n<h2><strong>About the code:<\/strong><\/h2>\n<p>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 <a title=\"Free and open source software\" href=\"http:\/\/en.wikipedia.org\/wiki\/Free_and_open_source_software\">free, open source software<\/a>, <a title=\"Dual-licensing\" href=\"http:\/\/en.wikipedia.org\/wiki\/Dual-licensing\">dual-licensed<\/a> under the <a title=\"MIT License\" href=\"http:\/\/en.wikipedia.org\/wiki\/MIT_License\">MIT License<\/a> or the <a title=\"GNU General Public License\" href=\"http:\/\/en.wikipedia.org\/wiki\/GNU_General_Public_License#Version_2\">GNU General Public License, Version 2<\/a> and it is included in the &#8220;js&#8221; folder inside the zip file.<\/p>\n<p>[space]<\/p>\n<p>If you have not done so before, download it here:<\/p>\n<p>[space]<\/p>\n<p>[download id=&#8221;2&#8243; format=&#8221;Marcel1&#8243;]<\/p>\n<p>[space]<\/p>\n<p>[note]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.[\/note]<\/p>\n<p>[space]<\/p>\n<p>[space]<\/p>\n<p><!--more--><\/p>\n<p>[separator]<\/p>\n<p>[space]<\/p>\n<p id=\"part1\" style=\"padding-left: 30px;\"><span style=\"color: #ff00ff;\">manual_patches.js [part 1]<\/span><\/p>\n<p>[space]<\/p>\n<p>The script starts with declaration of several variables. These are mostly arrays that are used to store different sets of images. Function &#8220;mainimage()&#8221; (line 9) is the heart of the script. It takes index &#8220;nr&#8221; and displays the next image in &#8220;array0&#8221;. 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 &#8220;onclick&#8221; event at the &#8220;Next&#8221; button, the first white patch will hide (line 5, [<a href=\"#part3\">part 3<\/a>], id=&#8221;white&#8221;). Next, mainimage() function will fire up by fading out another instance of the white patch (class=&#8221;img1&#8243;) and the index will advance to &#8220;0&#8221;. This happens at line 10 with the &#8220;complete&#8221; 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 [<a href=\"#part3\">part 3<\/a>]) and its value will be displayed in the Patch field which is &lt;p&gt; element of the html document with id attribute of &#8220;count&#8221; (&lt;p id=&#8221;count&#8221;&gt; &lt;\/p&gt;).<\/p>\n<p>[sourcecode language=&#8221;js&#8221;]<br \/>\n\/\/ Declare global variables<br \/>\nvar index = -1; \/\/ accounting for the three white patches<br \/>\nvar array0 = [];<br \/>\nvar array1 = [];<br \/>\nvar array1a = [];<br \/>\nvar spaces = [&quot;untagged&quot;, &quot;srgb&quot;, &quot;argb&quot;, &quot;prophoto&quot;];<\/p>\n<p>\/\/ Main slideshow function<br \/>\nfunction mainimage(nr) {<br \/>\n      \/\/ when run, move from the first image to the next one<br \/>\n     $(&quot;div.mainimg ul li:eq(0) div img&quot;).fadeOut({&quot;duration&quot;:100, complete:function() {<br \/>\n         $(this).attr(&quot;src&quot;,array0[nr]).fadeIn(100); \/\/display image from the array based on the index and src attribute<br \/>\n         nr = index; \/\/this will set the index of the currently selected image<br \/>\n\t$(&#8216;#count p&#8217;).html(&#8216;Patch: &#8216;+ (index+1) + &#8221;); \/\/ display image sequence number<br \/>\n         };<br \/>\n[\/sourcecode]<\/p>\n<p>[space]<br \/>\n[separator]<\/p>\n<p>[space]<\/p>\n<p id=\"part2\" style=\"padding-left: 30px;\"><span style=\"color: #ff00ff;\">manual_patches.js [part 2]<\/span><\/p>\n<p>[space]<\/p>\n<p>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 &#8220;Total images: &#8220;. Script then follows by generating CSS buttons which have the &#8220;<em>onclick<\/em>&#8221; event attached to each of them.<\/p>\n<p>[space]<\/p>\n<p>The key part of the wrapper function is the selection of color spaces (line 20). It involves the standard &#8220;click()&#8221; 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 &#8220;makearray()&#8221; at line 48. At the same time, radio button for the set selection is cleared to have no default state (line 39).<\/p>\n<p>[space]<\/p>\n<p>Now, about the &#8220;makearray()&#8221; function. It looks at the src path of each image in #photos\u00a0 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 &#8220;each&#8221; 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.<\/p>\n<p>[space]<\/p>\n<p>[sourcecode language=&#8221;js&#8221;]<br \/>\n$(function(){<br \/>\n\/\/ Set defaults<br \/>\n \t\t curr_space = spaces[0]; \/\/ untagged images are set as default<br \/>\n\t\t makearray(); \/\/run function defined at line 48<br \/>\n\t\t array0 = array1a.slice(); \/\/ plain copy of array1a<br \/>\n\t\t totalimages = 12;<br \/>\n\t\t $(&#8216;#total p&#8217;).html(&#8216;Total images: &#8216;+ totalimages + &#8221;);<\/p>\n<p>\/\/Prepare radio and CSS buttons<br \/>\n\t$(&quot;#patch-area&quot;).append(&#8216;&lt;a id=&quot;next&quot; onclick=&quot;next();&quot; href=&quot;#&quot;&gt;Next&lt;\/a&gt;&#8217;);<br \/>\n\t$(&quot;#patch-area&quot;).append(&#8216;&lt;a id=&quot;reset&quot; onclick=&quot;reset();&quot; href=&quot;#&quot;&gt;Reset&lt;\/a&gt;&#8217;);<br \/>\n\t$(&quot;#patch-area&quot;).append(&#8216;&lt;a id=&quot;previous&quot; onclick=&quot;previous();&quot; href=&quot;#&quot;&gt;Previous&lt;\/a&gt;&#8217;);<\/p>\n<p>           $(&#8216;input&#8217;).click(function () {<br \/>\n           $(&#8216;input:not(:checked)&#8217;).parent().removeClass(&quot;selected&quot;); \/\/ box selection styling<br \/>\n           $(&#8216;input:checked&#8217;).parent().addClass(&quot;selected&quot;);<br \/>\n              });<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;&gt; select color space<br \/>\n$(&quot;#untagged&quot;).click(function(){<br \/>\n\t\tif ($(this).text() == &quot;Untagged &#8211; No CM&quot;) \t{<br \/>\n\t\t$(this).text(&quot;Untagged &#8211; No CM&quot;);<br \/>\n\t\t$(&#8216;#selection a&#8217;).css(&#8216;background&#8217;,&#8217;#000F7D&#8217;);<br \/>\n\t\t$(&#8216;#untagged&#8217;).css(&#8216;background&#8217;,&#8217;#ac0000&#8242;);<br \/>\n\t\t curr_space = spaces[0];\t\/\/ Set space for this option<br \/>\n\t\t makearray(); \/\/ make the array &#8211; see below<br \/>\n\t\t \t\t\t}<br \/>\n\t\t});<\/p>\n<p>$(&quot;#srgb&quot;).click(function(){<br \/>\n\t\tif ($(this).text() == &quot;sRGB&quot;) {<br \/>\n\t\t$(this).text(&quot;sRGB&quot;);<br \/>\n\t\t$(&#8216;#selection a&#8217;).css(&#8216;background&#8217;,&#8217;#000F7D&#8217;);<br \/>\n\t\t$(&#8216;#srgb&#8217;).css(&#8216;background&#8217;,&#8217;#ac0000&#8242;);<br \/>\n\t\tcurr_space = spaces[1]; \/\/ Set space for this option<br \/>\n\t\tarray0 = []; \/\/ Clear all arrays<br \/>\n\t\tarray1 =[];<br \/>\n\t\tarray1a = [];<br \/>\n\t\t$(&#8216;#source2&#8217;).prop(&#8216;checked&#8217;, false); \/\/ Clear selection of the set (radio buttons)<br \/>\n\t\tmakearray();<br \/>\n\t\t\t\t \t}<br \/>\n\t\t});<\/p>\n<p>\/\/&#8230;&#8230;&#8230;&#8230; similar for other color spaces<br \/>\n\/\/ &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;&gt; end of space selection<br \/>\n\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-&gt; function to prepare arrays based on space<\/p>\n<p>function makearray() \t{<br \/>\n\t$(&#8216;img&#8217;).attr(&#8216;src&#8217;,function(index,attr){ \/\/ Create correct path to images based on the selected color space<br \/>\n        return attr.replace(\/srgb|argb|prophoto|untagged\/,curr_space);<br \/>\n   \t\t     });<\/p>\n<p>\t$(&#8216;#photos img&#8217;).each(function() { \/\/ take all images from #photos in index.html<br \/>\n    \tarray1.push($(this).attr(&#8216;src&#8217;)); \/\/ and push their src attribute into array1<br \/>\n\t\t\t});<\/p>\n<p>\t$(&#8216;#photos img&#8217;).filter(&#8216;.keep&#8217;).each(function() { \/\/ take some images from #photos (gray and primaries)<br \/>\n    \tarray1a.push($(this).attr(&#8216;src&#8217;)); \/\/ and push their src attribute into an array1a<br \/>\n\t\t\t});<\/p>\n<p>\/\/&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;&gt; Select which set of images to run<\/p>\n<p>     $(&quot;input[name=&#8217;set&#8217;]&quot;).live(&#8216;click&#8217;, function(){<br \/>\n \t var radio_value = $(this).val(); \/\/ Get the button value after it is clicked<\/p>\n<p>  \t if(radio_value == &#8216;short&#8217;) {<br \/>\n   \t \tarray0 = array1a.slice(); } \/\/ Just gray and primaries<br \/>\n   \t else \t{<br \/>\n   \t \tarray0 = []; \/\/Empty Array0 and assign it again in the next step<br \/>\n   \t \tarray0 = array1; \/\/ Full set of patches<br \/>\n   \t\t};<\/p>\n<p> \ttotalimages = array0.length; \/\/  Update Array0 size and print it to the screen<br \/>\n \t$(&#8216;#total p&#8217;).html(&#8216;Total images: &#8216;+ totalimages + &#8221;);<br \/>\n\t\t\t\t});<\/p>\n<p>\t\t\t\t\t          }<br \/>\n});<br \/>\n[\/sourcecode]<\/p>\n<p>[space]<br \/>\n[separator]<\/p>\n<p>[space]<\/p>\n<p id=\"part3\" style=\"padding-left: 30px;\"><span style=\"color: #ff00ff;\">manual_patches.js [part 3]<\/span><\/p>\n<p>[space]<\/p>\n<p>The scripts ends with section of &#8220;events&#8221;, specifically with assignment of events to buttons\u00a0 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 &#8220;window.location.reload(true)&#8221; statement.<\/p>\n<p>[space]<\/p>\n<p>[sourcecode language=&#8221;js&#8221;]<br \/>\n\/\/ Events<br \/>\nfunction next() {<br \/>\n        if (index &lt; array0.length) {<br \/>\n            index++;<br \/>\n            $(&#8216;#white&#8217;).hide(); \/\/ Hide the white patch<br \/>\n            $(&#8216;#container ol li&#8217;).hide(); \/\/Hide instruction area<br \/>\n            $(&#8216;#third&#8217;).hide(); \/\/ Hide the instruction header<br \/>\n            mainimage(index); \/\/start the slideshow<br \/>\n           }<br \/>\n        else {<br \/>\n        \twindow.location.reload(true); \/\/ reset to beginning<br \/>\n        \t }<br \/>\n       };<\/p>\n<p>function previous() {<br \/>\n        if (index &lt; array0.length &amp; index &gt; 0) {<br \/>\n            index&#8211;;<br \/>\n            mainimage(index);<br \/>\n           }<br \/>\n        else {<br \/>\n        \twindow.location.reload(true); \/\/ reset to beginning<br \/>\n        \t }<br \/>\n       };<\/p>\n<p>function reset() {<br \/>\n        \twindow.location.reload(true); \/\/ reset to beginning<br \/>\n        \t};<\/p>\n<p>[\/sourcecode]<\/p>\n<p>[separator]<\/p>\n<p>[space]<\/p>\n<p id=\"index\" style=\"padding-left: 30px;\"><span style=\"color: #ff00ff;\">index.html, only part<\/span><\/p>\n<p>[space]<\/p>\n<p>The main part of XHTML mark-up is outlined below. The body tag opens with a typical block level element &lt;div&gt; with <em>id<\/em> attribute of &#8220;container&#8221;. Navigation mark-up follows next wrapped in another &lt;div&gt; tag with<em> id<\/em> &#8220;selection&#8221;. Those are color space buttons, counters, radio buttons and their description. Patch area starts at line 28 with <em>div<\/em> 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 <em>div<\/em> element with class &#8220;mainimg&#8221; (lines 31-35). This is the first image that fades out when the animation starts.<\/p>\n<p>Next is the complete list of available images wrapped in<em> div<\/em> element with <em>id<\/em> &#8220;photos&#8221;. Each image either has class &#8220;keep&#8221; associated with it or has no class at all. In the former case, the &#8220;keep&#8221; class &#8220;marks&#8221; the image for inclusion in the &#8220;shorter&#8221; list of gray ramp and primaries. Sub-directory &#8220;untagged&#8221; is the default part of <em>src<\/em> path. It is this part that gets replaced by the chosen color space variable (on &#8220;click&#8221; event) through the jQuery script. If you wish to provide your own set of images, it is the place where they would be entered.<\/p>\n<p>[space]<\/p>\n<p>[sourcecode language=&#8221;html&#8221;]<br \/>\n&lt;div id=&quot;container&quot;&gt;<br \/>\n   &lt;div id=&quot;selection&quot;&gt;<br \/>\n    &lt;a id=&quot;untagged&quot; href=&quot;#&quot;&gt;Untagged &#8211; No CM&lt;\/a&gt;<br \/>\n    &lt;a id=&quot;srgb&quot; href=&quot;#&quot;&gt;sRGB&lt;\/a&gt;<br \/>\n    &lt;a id=&quot;argb&quot; href=&quot;#&quot;&gt;Adobe98 RGB&lt;\/a&gt;<br \/>\n    &lt;a id=&quot;prophoto&quot; href=&quot;#&quot;&gt;Pro Photo&lt;\/a&gt;<\/p>\n<p>   &lt;div id=&quot;total&quot;&gt;Total Images:&lt;\/div&gt;<br \/>\n   &lt;div id=&quot;count&quot;&gt;Patch: white&lt;\/div&gt;<\/p>\n<p>&lt;ul id=&quot;radio&quot;&gt;<br \/>\n&lt;li&gt;&lt;input id=&quot;source1&quot; type=&quot;radio&quot; name=&quot;set&quot; value=&quot;all&quot; class=&#8217;ctrl&#8217;&gt;&lt;\/input&gt;<br \/>\n&lt;label for=&quot;source1&quot;&gt;All available patches&lt;\/label&gt;<br \/>\n&lt;\/li&gt;<br \/>\n&lt;li&gt;&lt;input id=&quot;source2&quot; type=&quot;radio&quot; name=&quot;set&quot; checked=&quot;checked&quot; value=&quot;short&quot;&gt;&lt;\/input&gt; &lt;!&#8211; Default state is &quot;checked&quot;&#8211;&gt;<br \/>\n&lt;label for=&quot;source2&quot;&gt;Gray ramp and Primaries&lt;\/label&gt;<br \/>\n&lt;\/li&gt;<br \/>\n&lt;\/ul&gt;<br \/>\n&lt;\/div&gt; &lt;!&#8211; close selection &#8211;&gt;<\/p>\n<p>&lt;div id=&quot;first&quot;&gt;&lt;a href=&quot;#&quot;&gt;[2]&lt;span&gt;<br \/>\nChoose and click which set of patches you wish to run.&lt;\/span&gt;&lt;\/a&gt;&lt;\/div&gt;<br \/>\n&lt;div id=&quot;second&quot;&gt;&lt;a href=&quot;#&quot;&gt;[1]&lt;span&gt;<br \/>\nAlways click &quot;Reset&quot; first. Then click the desired tab above to select patches with a specific<br \/>\nembedded color profile.&lt;\/span&gt;&lt;\/a&gt;&lt;\/div&gt;<\/p>\n<p>&lt;h2&gt;RGB patches&lt;\/h2&gt;<br \/>\n&lt;div id=&quot;patch-area&quot;&gt;<br \/>\n   &lt;div id=&quot;white&quot;&gt;&lt;img src=&quot;images\/white.jpg&quot; alt=&quot;white&quot; \/&gt; &lt;!&#8211; show the white patch for instrument calibration &#8211;&gt;&lt;\/div&gt;<\/p>\n<p>&lt;div class=&quot;mainimg&quot;&gt;<br \/>\n&lt;ul&gt;<br \/>\n&lt;li&gt;&lt;div&gt;&lt;img alt=&quot;n-255&quot; src=&quot;images\/untagged\/n-255.jpg&quot; \/&gt;&lt;\/div&gt;&lt;\/li&gt;<br \/>\n&lt;\/ul&gt;<br \/>\n&lt;\/div&gt;<\/p>\n<p>&lt;div id=&quot;photos&quot;&gt;&lt;!&#8211; Customize the patches below. Keep the syntax. &#8211;&gt;<br \/>\n&lt;img src=&quot;images\/untagged\/n-255.jpg&quot; alt=&quot;n-255&quot; \/&gt;<br \/>\n&lt;img src=&quot;images\/untagged\/n-223.jpg&quot; alt=&quot;n-223&quot; \/&gt;<br \/>\n&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;. and so on for the all patches &#8230;&#8230;&#8230;&#8230;..<br \/>\n&lt;img src=&quot;images\/untagged\/b-0.jpg&quot; alt=&quot;b-0&quot; \/&gt;&lt;\/div&gt;<br \/>\n&lt;\/div&gt;&lt;!&#8211; closing patch-area&#8211;&gt;<br \/>\n[\/sourcecode]<\/p>\n<p>[space]<\/p>\n<p>Again, all discussed files including html file and css styling sheet are included in the zipped file through the download.<br \/>\n[space]<\/p>\n<p>[separator]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post follows on the Browsers &amp; Color Management I &#8211; 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 &hellip; <a href=\"https:\/\/www.marcelpatek.com\/blog\/2011\/12\/23\/cm-code\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13,16,8],"tags":[],"class_list":["post-1343","post","type-post","status-publish","format-standard","hentry","category-code-software","category-color-management","category-software"],"_links":{"self":[{"href":"https:\/\/www.marcelpatek.com\/blog\/wp-json\/wp\/v2\/posts\/1343","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.marcelpatek.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.marcelpatek.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.marcelpatek.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.marcelpatek.com\/blog\/wp-json\/wp\/v2\/comments?post=1343"}],"version-history":[{"count":66,"href":"https:\/\/www.marcelpatek.com\/blog\/wp-json\/wp\/v2\/posts\/1343\/revisions"}],"predecessor-version":[{"id":1345,"href":"https:\/\/www.marcelpatek.com\/blog\/wp-json\/wp\/v2\/posts\/1343\/revisions\/1345"}],"wp:attachment":[{"href":"https:\/\/www.marcelpatek.com\/blog\/wp-json\/wp\/v2\/media?parent=1343"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.marcelpatek.com\/blog\/wp-json\/wp\/v2\/categories?post=1343"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.marcelpatek.com\/blog\/wp-json\/wp\/v2\/tags?post=1343"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}