{"id":63730,"date":"2024-05-27T03:01:51","date_gmt":"2024-05-26T17:01:51","guid":{"rendered":"http:\/\/www.rjmprogramming.com.au\/ITblog\/?p=63730"},"modified":"2024-05-27T16:36:41","modified_gmt":"2024-05-27T06:36:41","slug":"animated-gif-slide-extraction-primer-tutorial","status":"publish","type":"post","link":"https:\/\/www.rjmprogramming.com.au\/ITblog\/animated-gif-slide-extraction-primer-tutorial\/","title":{"rendered":"Animated GIF Slide Extraction Primer Tutorial"},"content":{"rendered":"<div style=\"width: 230px\" class=\"wp-caption alignnone\"><a target=_blank href=\"https:\/\/www.rjmprogramming.com.au\/Mac\/extract_ag_slide_huh_of.html?noask=y\"><img decoding=\"async\" style=\"border: 15px solid pink;\" alt=\"Animated GIF Slide Extraction Primer Tutorial\" src=\"http:\/\/www.rjmprogramming.com.au\/Mac\/extract_ag_slide_huh_of.jpg\" title=\"Animated GIF Slide Extraction Primer Tutorial\"  style=\"float:left;\" \/><\/a><p class=\"wp-caption-text\">Animated GIF Slide Extraction Primer Tutorial<\/p><\/div>\n<p>Would you believe &#8230;<\/p>\n<ul>\n<li>the extraction of an HTML video element still is not too hard using that HTML video element object as the first parameter to a [canvasContext].<a target=_blank title='HTML canvas element drawImage() method information from w3schools' href='http:\/\/www.w3schools.com\/tags\/canvas_drawimage.asp'>drawImage<\/a> method call (as you might recall reading the recent <a target=_blank href='https:\/\/www.rjmprogramming.com.au\/ITblog\/canvas-drawimage-first-parameter-primer-tutorial\/' title='Canvas DrawImage First Parameter Primer Tutorial'>Canvas DrawImage First Parameter Primer Tutorial<\/a>) &#8230; whereas &#8230;<\/li>\n<li>the extraction of an HTML animated GIF image (ie. img) element still is a lot harder, regarding only the clientside Javascript side of web applications because using that animated GIF img object as that first  parameter to a [canvasContext].drawImage method call results only in the first still (or slide) of that animated GIF<\/li>\n<\/ul>\n<p>?  And so, to proceed with our &#8220;Animated GIF Slide Extraction&#8221; web application where a user can ask for the still (or slide) to be honed in on, needed us to design it so that a &#8230;<\/p>\n<ul>\n<li>an HTML and Javascript parent (clientside) <a target=_blank href=\"https:\/\/www.rjmprogramming.com.au\/Mac\/extract_ag_slide_huh_of.html_GETME\">extract_ag_slide_huh_of.html<\/a> <a target=_blank href=\"https:\/\/www.rjmprogramming.com.au\/Mac\/extract_ag_slide_huh_of.html?noask=y\">Animated GIF Slide Extraction web application<\/a> (or <a target=_blank href=\"https:\/\/www.rjmprogramming.com.au\/Mac\/extract_ag_slide_huh_of.html\">Animated GIF Slide Extraction via User Interaction web application<\/a> version) calls &#8230;<\/li>\n<li>serverside PHP <a target=_blank href=\"https:\/\/www.rjmprogramming.com.au\/Mac\/agtoslides.php_GETME\">agtoslides.php<\/a> iframe hosted child web application &#8230; calling, via <a target=_blank title='PHP shell_exec() method information' href='http:\/\/php.net\/manual\/en\/function.shell-exec.php'>shell_exec<\/a>, a &#8230;<\/li>\n<li><a target=_blank title='Korn Shell' href='https:\/\/en.wikipedia.org\/wiki\/KornShell'>Korn Shell<\/a> <a target=_blank href=\"https:\/\/www.rjmprogramming.com.au\/Mac\/agtoslides.ksh_GETME\">agtoslides.ksh<\/a> script &#8230; facilitating call of &#8230;<\/li>\n<li><a target=_blank title='ImageMagick command line' href='http:\/\/www.imagemagick.org\/script\/command-line-tools.php'>ImageMagick<\/a> <a target=_blank title='ImageMagick animated GIF slide extraction information' href='https:\/\/www.imagemagick.org\/discourse-server\/viewtopic.php?t=22597'>convert command<\/a> based &#8230;<br \/>\n<code><br \/>\nconvert -coalesce [animatedGIFimageFileName] [outputPNGoutputFilespec]<br \/>\n<\/code>\n<\/li>\n<\/ul>\n<p> &#8230; looking arrangement could fulfil our requirements, so far, where the user can supply &#8230;<\/p>\n<ol>\n<li>[animatedGIFimageFileName] &#8230; and &#8230;<\/li>\n<li>slide number to extract (which can be entered as a percentage, being as our &#8220;HTML and Javascript parent (clientside) web application&#8221; logics are capable of determining an animated GIF&#8217;s &#8230;<\/p>\n<ul>\n<li><font color=purple>number of slides<\/font> (PHP extracts) &#8230; and, albeit not needed so far, with this project &#8230;<\/li>\n<li><font color=magenta>duration<\/font> of an animated GIF &#8220;run through&#8221;<\/li>\n<\/ul>\n<p>)<\/li>\n<\/ol>\n<p> &#8230; in &#8230;<\/p>\n<p><code><br \/>\n<font color=purple>var ij=0;<\/font><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  if (origgifloc == '') { origgifloc=gifloc; }<br \/>\n  pbefore='';<br \/>\n  \/\/ij=0;<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      <font color=magenta>const delay = (uint8[i + 5] &lt;&lt; 8) | (uint8[i + 4] & 0xFF);<br \/>\n      duration += delay &lt; 2 ? 10 : delay;<\/font><br \/>\n    <br \/> <br \/>\n  if (doit || gifloc.indexOf('%') != -1 || 1 == 1) {<br \/>\n    <font color=purple>ij++;<\/font><br \/>\n    doit=true;<br \/>\n    gifloc=origgifloc;<br \/>\n    pbefore='' + ('gifloc=' + gifloc + ' and duration=' + eval(duration \/ 100) + ' and ij=' + ij + ' ');<br \/>\n    if (origgifloc.indexOf('%') != -1) { gifloc='' + Math.round(eval(eval(gifloc.replace('%','')) * eval('' + ij) \/ 100.0)); }<br \/>\n    \/\/document.title='' + pbefore + ' ... ' + gifloc;<br \/>\n  }<br \/>\n    }<br \/>\n  }<br \/>\n  if (eval(<font color=magenta>duration \/ 100<\/font>) &lt;= 0.11) {<br \/>\n  return 0;<br \/>\n  }<br \/>\n  \/\/if (gifloc.indexOf('%') != -1) {<br \/>\n  \/\/  alert('' + eval(duration \/ 100) + ' vs ' + delay);<br \/>\n  \/\/  gifloc=gifloc.replace('%','');<br \/>\n  \/\/}<br \/>\n  if (1 == 5 && canextract &gt; 0) {<br \/>\n    alert('' + eval(duration \/ 100));<br \/>\n  } else {<br \/>\n<br \/>\n  var newimg=new Image();<br \/>\n  newimg.onload = function(){<br \/>\n    ih=newimg.height;<br \/>\n    iw=newimg.width;<br \/>\n    document.getElementById('dimg').style.width='' + eval(1 * newimg.width) + 'px';<br \/>\n    document.getElementById('dimg').style.height='' + eval(1 * newimg.height) + 'px';<br \/>\n    document.getElementById('dimg').style.background='linear-gradient(rgba(255,255,255,0.9),rgba(255,255,255,0.9)),url(' + gifurl + ')';<br \/>\n    \/\/document.getElementById('dimg').style.backgroundPosition='' + iw + 'px ' + ih + 'px';<br \/>\n    document.getElementById('dimg').style.backgroundPosition='0px 0px';<br \/>\n    document.getElementById('dimg').style.backgroundSize='' + newimg.width + 'px ' + newimg.height + 'px';<br \/>\n    document.getElementById('dimg').style.backgroundRepeat='no-repeat';<br \/>\n    document.getElementById('dimg').src='#';<br \/>\n    document.getElementById('dimg').src=gifurl;<br \/>\n    document.getElementById('mygimage').style.opacity='0.1';<br \/>\n  };<br \/>\n  <br \/>\n  newimg.src=gifurl;<br \/>\n  goi=document.getElementById('mygimage');<br \/>\n  goisrc=gifurl;<br \/>\n  document.getElementById('mygimage').src=gifurl;<br \/>\n  \/\/newimg.src=gifurl;<br \/>\n  setTimeout(function(){<br \/>\n      jjform = new FormData();<br \/>\n      jjxhr = new XMLHttpRequest();<br \/>\n      document.getElementById('agname').value=gifurl;<br \/>\n      document.getElementById('mygimage').title='Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...';<br \/>\n      document.getElementById('slidenumber').value='' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij));<br \/>\n      jjform.append('agname', gifurl);<br \/>\n      jjform.append('slidenumber', '' + eval(1 + eval(      eval(-1 + eval('' + gifloc.replace('%','')))     % ij)));<br \/>\n      jjxhr.onreadystatechange = oneslidedu;<br \/>\n      \/\/jjxhr.responseType = \"Document\";<br \/>\n      jjxhr.open('post', '.\/agtoslides.php', true);<br \/>\n      if (1 == 1) {<br \/>\n      if (eval('' + document.getElementById('agname').value.length) &lt; 400) {<br \/>\n      \/\/document.getElementById('dimg').style.opacity='0.1';<br \/>\n      document.body.style.cursor='progress';<br \/>\n      document.getElementById('myif').src='.\/agtoslides.php?agname=' + encodeURIComponent(document.getElementById('agname').value) + '&slidenumber=' + encodeURIComponent(document.getElementById('slidenumber').value);<br \/>\n      } else {<br \/>\n      \/\/document.getElementById('dimg').style.opacity='0.1';<br \/>\n      document.body.style.cursor='progress';<br \/>\n      document.getElementById('mysub').click();<br \/>\n      }<br \/>\n      } else {<br \/>\n      jjxhr.send(jjform);<br \/>\n      }<br \/>\n  }, 5000);<br \/>\n  }<br \/>\n  return <font color=magenta>duration \/ 100<\/font>; \/\/ if 0.1 is not an animated GIF<br \/>\n}<br \/>\n<\/code><\/p>\n<p> &#8230; and to try this out you can turn the iframe below into a user interaction one via a <a onclick=\"document.getElementById('ifea').src=document.getElementById('ifea').src.split('?')[0] + '?rand=' + Math.floor(Math.random() * 19878675);\" href=\"#ifea\">click below<\/a> &#8230;<\/p>\n<p><iframe id=ifea style=\"width:95%;height:1200px;\" src=\"https:\/\/www.rjmprogramming.com.au\/Mac\/extract_ag_slide_huh_of.html?noask=yes\"><\/iframe><\/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='#d63730' onclick='var dv=document.getElementById(\"d63730\"); dv.innerHTML = \"&lt;iframe width=670 height=600 src=\" + \"https:\/\/www.rjmprogramming.com.au\/ITblog\/tag\/animated-gif\" + \"&gt;&lt;\/iframe&gt;\"; dv.style.display = \"block\";'>this<\/a> too.<\/p>\n<div id='d63730' style='display: none; border-left: 2px solid green; border-top: 2px solid green;'><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Would you believe &#8230; the extraction of an HTML video element still is not too hard using that HTML video element object as the first parameter to a [canvasContext].drawImage method call (as you might recall reading the recent Canvas DrawImage &hellip; <a href=\"https:\/\/www.rjmprogramming.com.au\/ITblog\/animated-gif-slide-extraction-primer-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":[4,12,14,29,37],"tags":[83,84,184,234,2650,2518,2618,4329,576,590,4442,1658,3163,652,677,849,1886,932,2042,997,1761,1105,1895,1138,3942,1149,4251,1319,3214],"class_list":["post-63730","post","type-post","status-publish","format-standard","hentry","category-animation","category-elearning","category-event-driven-programming","category-operating-system","category-tutorials","tag-animated-gif","tag-animation-2","tag-canvas","tag-command-line","tag-convert","tag-drawimage","tag-extract","tag-extraction","tag-html","tag-image","tag-image-file","tag-imagemagick","tag-interaction","tag-javascript","tag-korn-shell","tag-object","tag-parameter","tag-php","tag-png","tag-programming","tag-prompt","tag-script","tag-sequence","tag-shell","tag-shell_exec","tag-slide","tag-still","tag-tutorial","tag-user-interaction"],"_links":{"self":[{"href":"https:\/\/www.rjmprogramming.com.au\/ITblog\/wp-json\/wp\/v2\/posts\/63730"}],"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=63730"}],"version-history":[{"count":15,"href":"https:\/\/www.rjmprogramming.com.au\/ITblog\/wp-json\/wp\/v2\/posts\/63730\/revisions"}],"predecessor-version":[{"id":63745,"href":"https:\/\/www.rjmprogramming.com.au\/ITblog\/wp-json\/wp\/v2\/posts\/63730\/revisions\/63745"}],"wp:attachment":[{"href":"https:\/\/www.rjmprogramming.com.au\/ITblog\/wp-json\/wp\/v2\/media?parent=63730"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.rjmprogramming.com.au\/ITblog\/wp-json\/wp\/v2\/categories?post=63730"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.rjmprogramming.com.au\/ITblog\/wp-json\/wp\/v2\/tags?post=63730"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}