Animated GIF Creation Interfacing via Slide Extraction Tutorial

Animated GIF Creation Interfacing via Slide Extraction Tutorial

Animated GIF Creation Interfacing via Slide Extraction Tutorial

The work of today combines …

… to add the chance for a user to use what ImageMagick produces as an Animated GIF slide and fill this out into the textboxes of the Animated GIF Creator “child” iframe hosted incarnation “quietly” filled out probably “below the fold”, but scrollable toable.

There are data limits to what the Animated GIF Creator can handle, but perhaps it can help a user create their own Animated GIFs, for their own purposes, via other sources.

Sources for courses

… we’d say. But we would say that, wouldn’t we?!

To make this happen, amongst the …

  1. PHP … and …
  2. Korn Shell

… helper components (to get to ImageMagick) we swap the “tidying up of interim files” role Korn Shell used to do, quite successfully (and still does for any interim “whole Animated GIF” files created), passing the responsibilities to the PHP to do (via passing over to the Korn Shell a new extra argument, to tell it this is the new arrangement). And at the changed third draft agtoslides.php PHP (working with the changed third draft agtoslides.ksh), before the “outputting command line” is executed, a whole lot of “child asks stuff of the parent” “programming talk and action” happens (and works, because our Client Pre-emptive Iframe Onload Event logic looks for that iframe document’s document.body.innerHTML as the representation of the extracted slide (of the animated GIF) of interest) …

<?php

$preoutp='';
$postoutp='';

$inn=0;
$ij=0;
$otherstuff="";
if (isset($_GET['delay'])) {
$otherstuff.='delay=' . str_replace('+',' ',urldecode($_GET['delay'])) . '&';
}
if (isset($_POST['delay'])) {
$otherstuff.='delay=' . str_replace('+',' ',urldecode($_POST['delay'])) . '&';
}
if (isset($_GET['title'])) {
$otherstuff.='title=' . str_replace('+',' ',urldecode($_GET['title'])) . '&';
}
if (isset($_POST['title'])) {
$otherstuff.='title=' . str_replace('+',' ',urldecode($_POST['title'])) . '&';
}
if (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
while (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
$ij++;
$inn++;
}
}
$inn=0;
while (file_exists('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')) {
if ($postoutp == '') {
$postoutp='</body></html>';
$preoutp="<html><body onload=\" parent.agslideshow('slideshow','data:image/" . explode('#',str_replace('jpg','jpeg',strtolower(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[-1 + sizeof(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png'))])))[0] . ';base64,' . base64_encode(file_get_contents(explode('#','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[0])) . "'); ";
}
if ($postoutp != '') {
if ($inn > 0) {
$preoutp.=" parent.agslideshow('slideshow" . ('' . (1 + $inn)) . "','data:image/" . explode('#',str_replace('jpg','jpeg',strtolower(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[-1 + sizeof(explode('.','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png'))])))[0] . ';base64,' . base64_encode(file_get_contents(explode('#','/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png')[0])) . "'); ";
}
}
unlink('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_' . substr(('00000' . $inn),-5) . '.png');
$inn++;
}
if ($postoutp != '') { $preoutp.=" parent.preagslideshow('/PHP/animegif/tutorial_to_animated_gif.php?" . $otherstuff . "numfillin=" . ('' . $ij) . "'); \">"; }
//file_put_contents('x.x', $preoutp . $outp . $postoutp);
echo $preoutp . $outp . $postoutp;
exit;

?>

… to have the new parent Javascript functions …


function preagslideshow(theurl) {
if (theurl.indexOf('delay=') != -1) {
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=hidden name=delay value="' + decodeURIComponent(theurl.split('delay=')[1].split('&')[0]) + '"></input>';
} else {
jjform.append('delay', decodeURIComponent(theurl.split('delay=')[1].split('&')[0]));
}
}
if (theurl.indexOf('title=') != -1) {
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=hidden name=title value="' + decodeURIComponent(theurl.split('title=')[1].split('&')[0]) + '"></input>';
} else {
jjform.append('title', decodeURIComponent(theurl.split('title=')[1].split('&')[0]));
}
}
if (theurl.indexOf('numfillin=') != -1) {
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=hidden name=numfillin value="' + decodeURIComponent(theurl.split('numfillin=')[1].split('&')[0]) + '"></input>';
} else {
jjform.append('numfillin', decodeURIComponent(theurl.split('numfillin=')[1].split('&')[0]));
}
}
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=submit style=display:none; id=mysubag value=Submit></input>';
//alert(document.getElementById('agf').outerHTML);
document.getElementById('mysubag').click();
} else {
jjxhr.onreadystatechange = twoslidedu;
//jjxhr.responseType = "Document";
jjxhr.open('post', theurl.split('?')[0], true);
//document.getElementById('ifconto').src=theurl;
}
}

function agslideshow(thename, thevalue) {
if (1 == 1) {
if (thename == 'slideshow') {
if (9 == 9) {
//alert(thevalue);
document.getElementById('agf').innerHTML='<input type=hidden name=slideshow value="' + thevalue + '"></input>';
} else {
jjform = new FormData();
jjxhr = new XMLHttpRequest();
jjform.append('slideshow', thevalue);
}
} else {
if (9 == 9) {
document.getElementById('agf').innerHTML+='<input type=hidden name=' + thename + ' value="' + thevalue + '"></input>';
} else {
jjform.append(thename, thevalue);
}
}
} else {
agconto.getElementById(thename).value=thevalue;
}
}

… working with the new static HTML …


<form id=agf style=display:none; method=POST data-target=ifconto action='/PHP/animegif/tutorial_to_animated_gif.php'>
</form>

… be able to assist with this new Animated GIF Creator interfacing to happen for the user, should they be interested, in a changed fifth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), which you can try below.


Previous relevant Animated GIF Slide Extraction Reveal Tutorial is shown below.

Animated GIF Slide Extraction Reveal Tutorial

Animated GIF Slide Extraction Reveal Tutorial

Around here, we’re not ashamed to simplify 90% of web design issues into two categories …

  1. an “overlay” issue … or …
  2. a “reveal” issue

… and today’s improvements, pitted against the progress up until yesterday’s Animated GIF Slide Extraction Absolute URL Tutorial, pitted these two “colossuses” (at least in our mind) against each other as concept ideas towards today’s work’s solution. Which wins? We opted for a “reveal” solution, where the initial position is “reveal”.

We could have “overlayed” but we went for the KISS (“keep it simple simpleton”) principle, where, what you see at the top of a webpage takes prominence for the user. The thing is, though, in this alternate input section, we are not fussed that it stays around, hence the details/summary “reveal” way a user can make it disappear at any given point in time.

Here’s the thing, though, a details/summary “reveal” pairing has that “summary” innerHTML content part that can remain, no matter what, as a status informer mechanism we’re hoping helps out the “formerly obtuse” web application ways of our Animated GIF Extraction web application, in a changed fourth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), which you can try below.


Previous relevant Animated GIF Slide Extraction Absolute URL Tutorial is shown below.

Animated GIF Slide Extraction Absolute URL Tutorial

Animated GIF Slide Extraction Absolute URL Tutorial

The other user entry the user might do using the Animated GIF Slide Extraction web application of yesterday’s Animated GIF Slide Extraction Browsing Tutorial onto …

  • relative animated GIF URL (within the address bar domain of use or an absolute URL serving similar purposes) … and yesterday’s …
  • browsed for local animated GIF file of interest … is today’s …
  • absolute URL pointing to a domain not the same as the address bar domain of use

As you might guess this last option for the user may not work for a domain with very high security, but being as hotlinking images makes the Internet woooorrrrllllddd go around perhaps the user can try this underlying curl based logic out, to see with a changed third draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version), try below.

You may have noticed in our first draft we were not concerned with two incarnations of the web application being executed at once. Back then, one might interfere with the next if interrupted during the serverside ImageMagick phase of creating the png slides off the input animated GIF. Recently, we have started using …


uniquifier

… based logic (but in non-SQL realms) for that ImageMagick work. By and large the internal use only interim file naming in this ImageMagick phase is 99.9999999% sure to be unique to your session, and so not interfering, or accidentally picking up, other sessional data. You might want to look out for a textbox named “random”, in the code, regarding how we make that happen …


user@Users-Air htdocs % fgrep -n "'random'" extract_ag_slide_huh_of.html
157: jjform.append('random', document.getElementById('random').value);
165: document.getElementById('myif').src='./agtoslides.php?agname=' + encodeURIComponent(document.getElementById('agname').value) + '&slidenumber=' + encodeURIComponent(document.getElementById('slidenumber').value) + '&random=' + encodeURIComponent(document.getElementById('random').value);
167: //window.open('//www.rjmprogramming.com.au/Mac/extract_ag_slide_huh_of.html?slide=' + encodeURIComponent(document.getElementById('slidenumber').value) + '&random=' + encodeURIComponent(document.getElementById('random').value) + '#url=' + encodeURIComponent(document.getElementById('agname').value), '_blank', 'top=10,left=10,width=600,height=600');
173: document.getElementById('random').value='' + Math.floor(Math.random() * 198786753);
293: document.getElementById('random').value='' + Math.floor(Math.random() * 198786753);
376:<body onload="document.getElementById('random').value='' + Math.floor(Math.random() * 19878675); setTimeout(askaway,8000); ob(gifurl);">
user@Users-Air htdocs %


Previous relevant Animated GIF Slide Extraction Browsing Tutorial is shown below.

Animated GIF Slide Extraction Browsing Tutorial

Animated GIF Slide Extraction Browsing Tutorial

As of the recent Animated GIF Slide Extraction Primer Tutorial‘s progress with an Extraction of a User Nominated Animated GIF Slide web application’s …

  • input animated GIF URL modus operandi … today we add …
  • local operating system file browsing method of user animated GIF entry

… approach to our web application’s functionality abilities in a changed second draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version) helped out, especially via PHP’s acceptance of HTML form method=POST data, by …

… or via arrangements below.


Previous relevant Animated GIF Slide Extraction Primer Tutorial is shown below.

Animated GIF Slide Extraction Primer Tutorial

Animated GIF Slide Extraction Primer Tutorial

Would you believe …

  • 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 First Parameter Primer Tutorial) … whereas …
  • 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

? And so, to proceed with our “Animated GIF Slide Extraction” 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 …

… looking arrangement could fulfil our requirements, so far, where the user can supply …

  1. [animatedGIFimageFileName] … and …
  2. slide number to extract (which can be entered as a percentage, being as our “HTML and Javascript parent (clientside) web application” logics are capable of determining an animated GIF’s …

    • number of slides (PHP extracts) … and, albeit not needed so far, with this project …
    • duration of an animated GIF “run through”

    )

… in …


var ij=0;

/** @param {Uint8Array} uint8 */
function 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.
if (origgifloc == '') { origgifloc=gifloc; }
pbefore='';
//ij=0;
let duration = 0;
for (let i = 0, len = uint8.length; i < len; i++) {
if (uint8[i] == 0x21
&& uint8[i + 1] == 0xF9
&& uint8[i + 2] == 0x04
&& uint8[i + 7] == 0x00)
{
const delay = (uint8[i + 5] << 8) | (uint8[i + 4] & 0xFF);
duration += delay < 2 ? 10 : delay;



if (doit || gifloc.indexOf('%') != -1 || 1 == 1) {
ij++;
doit=true;
gifloc=origgifloc;
pbefore='' + ('gifloc=' + gifloc + ' and duration=' + eval(duration / 100) + ' and ij=' + ij + ' ');
if (origgifloc.indexOf('%') != -1) { gifloc='' + Math.round(eval(eval(gifloc.replace('%','')) * eval('' + ij) / 100.0)); }
//document.title='' + pbefore + ' ... ' + gifloc;
}
}
}
if (eval(duration / 100) <= 0.11) {
return 0;
}
//if (gifloc.indexOf('%') != -1) {
// alert('' + eval(duration / 100) + ' vs ' + delay);
// gifloc=gifloc.replace('%','');
//}
if (1 == 5 && canextract > 0) {
alert('' + eval(duration / 100));
} else {

var newimg=new Image();
newimg.onload = function(){
ih=newimg.height;
iw=newimg.width;
document.getElementById('dimg').style.width='' + eval(1 * newimg.width) + 'px';
document.getElementById('dimg').style.height='' + eval(1 * newimg.height) + 'px';
document.getElementById('dimg').style.background='linear-gradient(rgba(255,255,255,0.9),rgba(255,255,255,0.9)),url(' + gifurl + ')';
//document.getElementById('dimg').style.backgroundPosition='' + iw + 'px ' + ih + 'px';
document.getElementById('dimg').style.backgroundPosition='0px 0px';
document.getElementById('dimg').style.backgroundSize='' + newimg.width + 'px ' + newimg.height + 'px';
document.getElementById('dimg').style.backgroundRepeat='no-repeat';
document.getElementById('dimg').src='#';
document.getElementById('dimg').src=gifurl;
document.getElementById('mygimage').style.opacity='0.1';
};

newimg.src=gifurl;
goi=document.getElementById('mygimage');
goisrc=gifurl;
document.getElementById('mygimage').src=gifurl;
//newimg.src=gifurl;
setTimeout(function(){
jjform = new FormData();
jjxhr = new XMLHttpRequest();
document.getElementById('agname').value=gifurl;
document.getElementById('mygimage').title='Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...';
document.getElementById('slidenumber').value='' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij));
jjform.append('agname', gifurl);
jjform.append('slidenumber', '' + eval(1 + eval( eval(-1 + eval('' + gifloc.replace('%',''))) % ij)));
jjxhr.onreadystatechange = oneslidedu;
//jjxhr.responseType = "Document";
jjxhr.open('post', './agtoslides.php', true);
if (1 == 1) {
if (eval('' + document.getElementById('agname').value.length) < 400) {
//document.getElementById('dimg').style.opacity='0.1';
document.body.style.cursor='progress';
document.getElementById('myif').src='./agtoslides.php?agname=' + encodeURIComponent(document.getElementById('agname').value) + '&slidenumber=' + encodeURIComponent(document.getElementById('slidenumber').value);
} else {
//document.getElementById('dimg').style.opacity='0.1';
document.body.style.cursor='progress';
document.getElementById('mysub').click();
}
} else {
jjxhr.send(jjform);
}
}, 5000);
}
return duration / 100; // if 0.1 is not an animated GIF
}

… and to try this out you can turn the iframe below into a user interaction one via a click below

If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.


If this was interesting you may be interested in this too.

This entry was posted in eLearning, Event-Driven Programming, Tutorials and tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *