{"id":60206,"date":"2023-07-23T03:01:31","date_gmt":"2023-07-22T17:01:31","guid":{"rendered":"http:\/\/www.rjmprogramming.com.au\/ITblog\/?p=60206"},"modified":"2023-07-22T17:51:08","modified_gmt":"2023-07-22T07:51:08","slug":"animated-gif-duration-calculation-filter-tutorial","status":"publish","type":"post","link":"https:\/\/www.rjmprogramming.com.au\/ITblog\/animated-gif-duration-calculation-filter-tutorial\/","title":{"rendered":"Animated GIF Duration Calculation Filter Tutorial"},"content":{"rendered":"<div style=\"width: 230px\" class=\"wp-caption alignnone\"><a target=_blank href=\"http:\/\/www.rjmprogramming.com.au\/PHP\/read_exif_off_image_rotate.php\"><img decoding=\"async\" style=\"border: 15px solid pink;\" alt=\"Animated GIF CSS Filter Tutorial\" src=\"http:\/\/www.rjmprogramming.com.au\/PHP\/ag_filter.gif\" title=\"Animated GIF Duration Calculation Filter Tutorial\"  style=\"float:left;\"  \/><\/a><p class=\"wp-caption-text\">Animated GIF Duration Calculation Filter Tutorial<\/p><\/div>\n<p>Can a &#8220;proof of concept&#8221; arrangement last two blog postings?  If there&#8217;s more you want to prove, ahead of committing to the final product that might hone in on the specificity of the idea, we&#8217;d say it&#8217;s possible, yes.  And so, continuing on from the recent <a title='Animated GIF Duration Calculation Primer Tutorial' href='#agifdcpt'>Animated GIF Duration Calculation Primer Tutorial<\/a> we tweak its PHP hosting &#8220;proof of concept&#8221; parent web application to try out our second point we&#8217;re out to prove &#8230;<\/p>\n<blockquote><p>\nWe want to prove that CSS <a target=_blank title='CSS filters' href='https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/filter'>filter<\/a> works for animated GIFs as well as it appears to work with other image types of elements.\n<\/p><\/blockquote>\n<p>Conservative worry, we grant you, but we did want to make sure this all worked, and happily, it was all fine &#8230;<\/p>\n<p><code><br \/>\n  var ingif='', ingifstyle='filter: none;', ingifint=0, ingifchosen=false;<br \/>\n<br \/>\nfunction prefetch(whatgifmaybe) { \/\/ thanks to https:\/\/stackoverflow.com\/questions\/69564118\/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.<br \/>\nif ((whatgifmaybe.toLowerCase().trim().split('#')[0] + '?').indexOf('.gif?') != -1) {<br \/>\ningif=whatgifmaybe;<br \/>\ndocument.body.style.cursor='progress';<br \/>\nfetch(whatgifmaybe)<br \/>\n  .then(res =&gt; res.arrayBuffer())<br \/>\n  .then(ab =&gt; isGifAnimated(new Uint8Array(ab)))<br \/>\n  .then(console.log);<br \/>\n}<br \/>\n}<br \/>\n<br \/>\nfunction clooktv(intv) {<br \/>\n  var finds=[];<br \/>\n  document.getElementById('imgag').title=intv;<br \/>\n  if (ingifchosen) {<br \/>\n  finds=document.getElementById('simgag').outerHTML.split('&gt;' + intv + '&lt;\/option&gt;');<br \/>\n  if (eval('' + finds.length) &gt; 1) {<br \/>\n    document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('&gt;' + ingifstyle + '&lt;\/option&gt;', ' selected&gt;' + ingifstyle + '&lt;\/option&gt;');<br \/>\n  }<br \/>\n  }<br \/>\n  document.body.innerHTML+='&lt;style&gt; #imgag { ' + intv + ' } &lt;\/style&gt;';<br \/>\n  return intv;<br \/>\n}<br \/>\n<br \/>\nfunction changelook() {<br \/>\n var finds=[];<br \/>\n if (ingifint &gt; 0) {<br \/>\n  setTimeout(changelook, ingifint);<br \/>\n  if (ingifchosen) {<br \/>\n  ingifchosen=false;<br \/>\n  } else {<br \/>\n  finds=document.getElementById('simgag').outerHTML.split('&gt;' + ingifstyle + '&lt;\/option&gt;');<br \/>\n  if (eval('' + finds.length) &gt; 1) {<br \/>\n    if (finds[1].indexOf('&lt;\/select&gt;') == 0) {<br \/>\n      ingifstyle='filter: none;';<br \/>\n      document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('&gt;' + ingifstyle + '&lt;\/option&gt;', ' selected&gt;' + ingifstyle + '&lt;\/option&gt;');<br \/>\n    } else {<br \/>\n      ingifstyle=finds[1].split('&gt;')[1].split('&lt;')[0];<br \/>\n      document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('&gt;' + ingifstyle + '&lt;\/option&gt;', ' selected&gt;' + ingifstyle + '&lt;\/option&gt;');<br \/>\n    }<br \/>\n    document.getElementById('simgag').value=clooktv(ingifstyle);<br \/>\n  }<br \/>\n  }<br \/>\n }<br \/>\n}<br \/>\n<br \/>\n\/** @param {Uint8Array} uint8 *\/<br \/>\nfunction isGifAnimated (uint8) { \/\/ thanks to https:\/\/stackoverflow.com\/questions\/69564118\/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.<br \/>\n  let duration = 0;<br \/>\n  for (let i = 0, len = uint8.length; i &lt; len; i++) {<br \/>\n    if (uint8[i] == 0x21<br \/>\n      && uint8[i + 1] == 0xF9<br \/>\n      && uint8[i + 2] == 0x04<br \/>\n      && uint8[i + 7] == 0x00)<br \/>\n    {<br \/>\n      const delay = (uint8[i + 5] &lt;&lt; 8) | (uint8[i + 4] & 0xFF);<br \/>\n      duration += delay &lt; 2 ? 10 : delay;<br \/>\n    }<br \/>\n  }<br \/>\n  \/\/alert('' + eval(duration \/ 100));<br \/>\n  if (eval(duration \/ 100) &gt; 0.11) {<br \/>\n    var damore='';<br \/>\n    if (document.getElementById('aside')) {<br \/>\n     if (document.getElementById('aside').outerHTML.toLowerCase().indexOf('&lt;div') == 0) {<br \/>\n     damore=' showing &lt;select onchange=\\\"ingifchosen=true; ingifstyle=clooktv(this.value);\\\" id=simgag size=13&gt;&lt;option value=\\\"filter: none;\\\" selected&gt;filter: none;&lt;\/option&gt;&lt;option value=\\\"filter: blur(5px);\\\"&gt;filter: blur(5px);&lt;\/option&gt;&lt;option value=\\\"filter: brightness(0.4);\\\"&gt;filter: brightness(0.4);&lt;\/option&gt;&lt;option value=\\\"filter: contrast(200%);\\\"&gt;filter: contrast(200%);&lt;\/option&gt;&lt;option value=\\\"filter: drop-shadow(16px 16px 20px blue);\\\"&gt;filter: drop-shadow(16px 16px 20px blue);&lt;\/option&gt;&lt;option value=\\\"filter: grayscale(50%);\\\"&gt;filter: grayscale(50%);&lt;\/option&gt;&lt;option value=\\\"filter: hue-rotate(90deg);\\\"&gt;filter: hue-rotate(90deg);&lt;\/option&gt;&lt;option value=\\\"filter: invert(75%);\\\"&gt;filter: invert(75%);&lt;\/option&gt;&lt;option value=\\\"filter: opacity(25%);\\\"&gt;filter: opacity(25%);&lt;\/option&gt;&lt;option value=\\\"filter: saturate(30%);\\\"&gt;filter: saturate(30%);&lt;\/option&gt;&lt;option value=\\\"filter: sepia(60%);\\\"&gt;filter: sepia(60%);&lt;\/option&gt;&lt;option value=\\\"filter: contrast(175%) brightness(33%);\\\"&gt;filter: contrast(175%) brightness(33%);&lt;\/option&gt;&lt;option value=\\\"filter: drop-shadow(3px 3px red) sepia(100%) drop-shadow(-3px -3px blue);\\\"&gt;filter: drop-shadow(3px 3px red) sepia(100%) drop-shadow(-3px -3px blue);&lt;\/option&gt;&lt;\/select&gt;&lt;br&gt;&lt;br&gt;&lt;img onload=\\\"if (ingifint == 0) {  ingifint=' + eval(duration * 10) + '; setTimeout(changelook, eval(800 + ingifint)); }\\\" title=\\\"filter: none;\\\" src=\\\"' + ingif + '\\\" id=imgag&gt;&lt;\/img&gt;&lt;br&gt;';<br \/>\n     document.getElementById('aside').innerHTML='&lt;?php echo $image; ?&gt; Animated GIF ' + ingif.split('#')[0].split('?')[0] + ' duration is ' + eval(duration \/ 100) + ' seconds ' + damore;<br \/>\n     \/\/ingifint=eval(duration * 10);<br \/>\n     \/\/setTimeout(changelook, eval(duration * 10));<br \/>\n     document.getElementById('aside').scrollIntoView();<br \/>\n     } else {<br \/>\n     document.getElementById('aside').innerHTML='  (&lt;?php echo $image; ?&gt; animated GIF ' + ingif.split('#')[0].split('?')[0] + ' duration is ' + eval(duration \/ 100) + ' seconds)' + damore;<br \/>\n     }<br \/>\n    }<br \/>\n  }<br \/>\n  document.body.style.cursor='pointer';<br \/>\n  return duration \/ 100; \/\/ if 0.1 is not an animated GIF<br \/>\n}<br \/>\n<\/code><\/p>\n<p>And so, especially because GIF images cannot be useful for exif information, it helps us isolate our &#8220;proof of concept&#8221; feel to <a target=_blank href='http:\/\/www.rjmprogramming.com.au\/PHP\/Geographicals\/diff.php?one=http:\/\/www.rjmprogramming.com.au\/PHP\/read_exif_off_image_rotate.php--------GETME'>today&#8217;s changed<\/a> <a target=_blank href='http:\/\/www.rjmprogramming.com.au\/PHP\/read_exif_off_image_rotate.php--------GETME'>read_exif_off_image_rotate.php<\/a> <a target=_blank href='http:\/\/www.rjmprogramming.com.au\/PHP\/read_exif_off_image_rotate.php'>PHP image exif reporter web application<\/a> which we can supply an argument to such as the <a target=_blank title='Katoomba Street Art Walk' href='https:\/\/www.visitnsw.com\/destinations\/blue-mountains\/katoomba-area\/katoomba\/attractions\/street-art-walk'>Katoomba Street Art Walk<\/a> <a target=_blank href='http:\/\/www.rjmprogramming.com.au\/PHP\/read_exif_off_image_rotate.php?image=.\/street_art_katoomba.gif'>inspired one<\/a> also shown below &#8230;<\/p>\n<p><iframe onload=\"setTimeout(function(){ location.href='#content'; }, 7000);\" style='width:100%;height:1500px;' src='http:\/\/www.rjmprogramming.com.au\/PHP\/read_exif_off_image_rotate.php?image=.\/street_art_katoomba.gif'><\/iframe><\/p>\n<p><!--p>You can also see this play out at WordPress 4.1.1's <a target=_blank  href='\/\/www.rjmprogramming.com.au\/ITblog\/animated-gif-css-filter-tutorial\/'>Animated GIF CSS Filter Tutorial<\/a>.<\/p-->\n<hr>\n<p id='agifdcpt'>Previous relevant <a target=_blank title='Animated GIF Duration Calculation Primer Tutorial' href='\/\/www.rjmprogramming.com.au\/ITblog\/animated-gif-duration-calculation-primer-tutorial\/'>Animated GIF Duration Calculation Primer Tutorial<\/a> is shown below.<\/p>\n<div style=\"width: 230px\" class=\"wp-caption alignnone\"><a target=_blank href=\"http:\/\/www.rjmprogramming.com.au\/PHP\/read_exif_off_image_rotate.php\"><img decoding=\"async\" style=\"border: 15px solid pink;\" alt=\"Animated GIF Duration Calculation Primer Tutorial\" src=\"http:\/\/www.rjmprogramming.com.au\/PHP\/oneoftwo_agif_dur.jpg\" title=\"Animated GIF Duration Calculation Primer Tutorial\"  style=\"float:left;\"  \/><\/a><p class=\"wp-caption-text\">Animated GIF Duration Calculation Primer Tutorial<\/p><\/div>\n<p>We&#8217;ve got a new (mini-<sub>?<\/sub>)project developing.  No, it doesn&#8217;t hurt in the &#8220;you know what&#8221;!  But thanks for your concern?!<\/p>\n<p>It&#8217;s a project that reminds us about an adage regarding projects, that might seem pretty obvious, but is worth mentioning &#8230;<\/p>\n<blockquote><p>\nMany projects being 90% perspiration, 10% inspiration, there might be the &#8220;not sure we can do&#8221; items that should be tackled first.\n<\/p><\/blockquote>\n<p>That truism is all well and good, but not always possible, of course, when you have to set up the difficult environment ahead of testing this unknown.  Not so, with the &#8220;unknown&#8221; of our new project &#8230;<\/p>\n<blockquote><p>\nWe want to know whether we can detect an animated GIF media file playing duration, ideally in client side Javascript, and if not possible there, we would settle for a server side PHP solution.\n<\/p><\/blockquote>\n<p>Happily <font size=1>(via our <a target=_blank title='Google search for duration of animated GIF using Javascript' href='https:\/\/www.google.com\/search?q=duration+of+animated+GIF+using+Javascript&#038;rlz=1C5CHFA_enAU973AU973&#038;oq=duration+of+animated+GIF+using+Javascript&#038;gs_lcrp=EgZjaHJvbWUyBggAEEUYOTIHCAEQIRigAdIBCTExODE5ajFqNKgCALACAA&#038;sourceid=chrome&#038;ie=UTF-8'>duration of animated GIF using Javascript<\/a> Google search)<\/font>, <a target=_blank title=? href='https:\/\/www.youtube.com\/watch?v=e9_7GcQeiqw&#038;t=2m37s'>yet again<\/a>, the online wooooorrrrlllldd has come to our rescue via <a target=_blank href='https:\/\/stackoverflow.com\/questions\/69564118\/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.'>this excellent webpage<\/a>&#8216;s Javascript ideas, so many thanks!<\/p>\n<p>We slotted its thinking <font size=1>(and Javascript (via PHP) &#8230;<\/p>\n<p><code><br \/>\nfunction prefetch(whatgifmaybe) { \/\/ thanks to https:\/\/stackoverflow.com\/questions\/69564118\/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.<br \/>\nif ((whatgifmaybe.toLowerCase().trim().split('#')[0] + '?').indexOf('.gif?') != -1) {<br \/>\ndocument.body.style.cursor='progress';<br \/>\nfetch(whatgifmaybe)<br \/>\n  .then(res => res.arrayBuffer())<br \/>\n  .then(ab => isGifAnimated(new Uint8Array(ab)))<br \/>\n  .then(console.log);<br \/>\n}<br \/>\n}<br \/>\n<br \/>\n\/** @param {Uint8Array} uint8 *\/<br \/>\nfunction isGifAnimated (uint8) { \/\/ thanks to https:\/\/stackoverflow.com\/questions\/69564118\/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.<br \/>\n  let duration = 0;<br \/>\n  for (let i = 0, len = uint8.length; i &lt; len; i++) {<br \/>\n    if (uint8[i] == 0x21<br \/>\n      && uint8[i + 1] == 0xF9<br \/>\n      && uint8[i + 2] == 0x04<br \/>\n      && uint8[i + 7] == 0x00)<br \/>\n    {<br \/>\n      const delay = (uint8[i + 5] << 8) | (uint8[i + 4] &#038; 0xFF);\n      duration += delay < 2 ? 10 : delay;\n    }\n  }\n  \/\/alert('' + eval(duration \/ 100));\n  if (eval(duration \/ 100) &gt; 0.11) {\n    if (document.getElementById('aside')) {\n     document.getElementById('aside').innerHTML='  (&lt;?php echo $image; ?&gt; animated GIF duration is ' + eval(duration \/ 100) + ' seconds)';\n    }\n  }\n  document.body.style.cursor='pointer';\n  return duration \/ 100; \/\/ if 0.1 is not an animated GIF\n}\n<\/code><\/p>\n<p> ... logic)<\/font>, you might say in a \"kludgy\" way (but, for us, serving a \"proof of concept\" purpose), that allows us to proceed on other aims of our project that will become apparent into the near future.  No, we are not totally \"out of the woods\" yet regarding \"unknowns\" but <a target=_blank href='http:\/\/www.rjmprogramming.com.au\/PHP\/Geographicals\/diff.php?one=http:\/\/www.rjmprogramming.com.au\/PHP\/read_exif_off_image_rotate.php-------GETME'>today's changed<\/a> <a target=_blank href='http:\/\/www.rjmprogramming.com.au\/PHP\/read_exif_off_image_rotate.php-------GETME'>read_exif_off_image_rotate.php<\/a> <a target=_blank href='http:\/\/www.rjmprogramming.com.au\/PHP\/read_exif_off_image_rotate.php'>PHP image exif reporter web application<\/a>) into the \"onblur\" logic of an image URL textbox HTML element, that web application talked about when we presented <a target=_blank title='Gimp Guillotine Image File Browse Media Tutorial' href='https:\/\/www.rjmprogramming.com.au\/ITblog\/gimp-guillotine-image-file-browse-media-tutorial'>Gimp Guillotine Image File Browse Media Tutorial<\/a>.  You might try it yourself, but not sure \"animated GIF and exif\" mix, if you get my meaning, but if your image is an animated GIF you should be informed of its duration, in seconds, up the top of the webpage <font size=1>(given permissions and all, <a target=_blank title='?' href='https:\/\/www.youtube.com\/watch?v=PtR4cWb4HNg'>that is<\/a>)<\/font>?<\/p>\n<p>If this was interesting you may be interested in <a title='Click here to see topics in which you might be interested' href='#d60185' onclick='var dv=document.getElementById(\"d60185\"); dv.innerHTML = \"&lt;iframe width=670 height=600 src=\" + \"https:\/\/www.rjmprogramming.com.au\/ITblog\/tag\/promise\" + \"&gt;&lt;\/iframe&gt;\"; dv.style.display = \"block\";'>this<\/a> too.<\/p>\n<div id='d60185' style='display: none; border-left: 2px solid green; border-top: 2px solid green;'><\/div>\n<hr>\n<p>If this was interesting you may be interested in <a title='Click here to see topics in which you might be interested' href='#d60206' onclick='var dv=document.getElementById(\"d60206\"); dv.innerHTML = \"&lt;iframe width=670 height=600 src=\" + \"https:\/\/www.rjmprogramming.com.au\/ITblog\/tag\/filter\" + \"&gt;&lt;\/iframe&gt;\"; dv.style.display = \"block\";'>this<\/a> too.<\/p>\n<div id='d60206' style='display: none; border-left: 2px solid green; border-top: 2px solid green;'><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Can a &#8220;proof of concept&#8221; arrangement last two blog postings? If there&#8217;s more you want to prove, ahead of committing to the final product that might hone in on the specificity of the idea, we&#8217;d say it&#8217;s possible, yes. And &hellip; <a href=\"https:\/\/www.rjmprogramming.com.au\/ITblog\/animated-gif-duration-calculation-filter-tutorial\/\">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":[12,37],"tags":[83,212,4402,281,2091,431,576,652,932,997,998,2357,4403,1986,1209,1212],"class_list":["post-60206","post","type-post","status-publish","format-standard","hentry","category-elearning","category-tutorials","tag-animated-gif","tag-client","tag-clientdide","tag-css","tag-duration","tag-filter","tag-html","tag-javascript","tag-php","tag-programming","tag-programming-tutorial","tag-promise","tag-proof","tag-proof-of-concept","tag-style","tag-styling"],"_links":{"self":[{"href":"https:\/\/www.rjmprogramming.com.au\/ITblog\/wp-json\/wp\/v2\/posts\/60206"}],"collection":[{"href":"https:\/\/www.rjmprogramming.com.au\/ITblog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.rjmprogramming.com.au\/ITblog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.rjmprogramming.com.au\/ITblog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.rjmprogramming.com.au\/ITblog\/wp-json\/wp\/v2\/comments?post=60206"}],"version-history":[{"count":13,"href":"https:\/\/www.rjmprogramming.com.au\/ITblog\/wp-json\/wp\/v2\/posts\/60206\/revisions"}],"predecessor-version":[{"id":60219,"href":"https:\/\/www.rjmprogramming.com.au\/ITblog\/wp-json\/wp\/v2\/posts\/60206\/revisions\/60219"}],"wp:attachment":[{"href":"https:\/\/www.rjmprogramming.com.au\/ITblog\/wp-json\/wp\/v2\/media?parent=60206"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.rjmprogramming.com.au\/ITblog\/wp-json\/wp\/v2\/categories?post=60206"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.rjmprogramming.com.au\/ITblog\/wp-json\/wp\/v2\/tags?post=60206"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}