NetNewsWire Web Feed macOS Safari Primer Tutorial

NetNewsWire Web Feed macOS Safari Primer Tutorial

NetNewsWire Web Feed macOS Safari Primer Tutorial

In the same “RSS feed” feel of FeedBurner Web Feed Primer Tutorial, the other day …

  • on this macOS MacBook Air … using …
  • Safari web browser … we had occasion to type into the address bar …
  • https://www.rjmprogramming.com.au/ITblog/tag/document/feed/
  • to which we received the advisory message …

    This is a link to an RSS feed. Would you like to search the App Store for Apps that can display RSS feeds?

    … different to the (less worrying) behaviour on Google Chrome …

So we went looking for a free macOS and Safari RSS feed reader and came up with the great looking NetNewsWire for this purpose, thanks. It looks great!


Previous relevant FeedBurner Web Feed Primer Tutorial is shown below.

FeedBurner Web Feed Primer Tutorial

FeedBurner Web Feed Primer Tutorial

We’ve opened a FeedBurner web feed management provider account for the Robert James Metcalfe Blog, our WordPress 4.1.1 blog at this link. Let’s see what Wikipedia says about FeedBurner, which Google acquired on 3rd June 2007, here and below …

FeedBurner is a web feed management provider launched in 2004.[1] FeedBurner was founded by Dick Costolo, Eric Lunt, Steve Olechowski, and Matt Shobe. Costolo is a University of Michigan graduate, and was CEO of Twitter from 2010 to 2015. FeedBurner provides custom RSS feeds and management tools to bloggers, podcasters, and other web-based content publishers.

Web feed management providers like FeedBurner are pretty important to bloggers because a lot of web traffic to blogs these days does not come from the user finding the blog news via their favourites or out of habit each day, but rather from “feeds” they have subscribed to, that they use the precis headline of to decide whether they want to read further on a topic of interest or disgust or whatever or what…everrrrrr.

It was fairly straightforward as a Google Gmail user to sign up for the Robert James Metcalfe Blog feed to be registered with FeedBurner. More or less just follow your nose with a visit to http://feedburner.com … but what was a bit surprising was the next day’s realization that just because some content looks okay in HTML it would necessarily be totally okay for FeedBurner which requires that content to validate in terms of XML data as well.

Now here is where the FeedBurner “Troubleshootize” tab functionalities called (for the Robert James Metcalfe Blog feed) …

… can come into their own to show you any potential problems.

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


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

Posted in eLearning, Operating System, Software, Tutorials | Tagged , , , , , , , , , , | Leave a comment

Australian Geographical Quiz Scrolling Tutorial

Australian Geographical Quiz Scrolling Tutorial

Australian Geographical Quiz Scrolling Tutorial

We were a little gobsmacked revisiting the 2017 era Australian Geographical Quiz Context Tutorial quiz web application (and thanks to Australian Geographic website here) that looking through the code … arrrgggghhh … the string …

.scroll

… was missing. Why should it be there? Well, on a re-run through of how the Australian Geographical Quiz web application worked, we were asked to click on …

Wilsons Promontory

… which did not send us into a tizzy by itself. Oh no! We never panic?! Even without the apostrophe in Wilsons we handled that … no worries … we realize that could have been because two (or more) guys or gals or both called Wilson were standing together at just the right time and place (or sent there by Karen) when a “promontory” needed naming … no problems. No, what caused our “too fragile” web application diffs was the way we had to scroll down to that esteemed Victorian coastal location in our (temporarily, mind you) less esteemious web application. We got funny places mentioned as our nearest “place of click”, and it was then the “true horror” happened (ie. with our code scouring reveal) … no “false horror” around here … no … it was “true” all right … we’re here to tell you! Any obs! Okay?!

The fix, you ask?!

Glad you asked! Take a look at (where we also catered for mobile platforms better too) …


function icheck(evt) {
if (realclick) {
var x,y;
if (evt.touches) {
if (evt.touches[0].pageX) {
x = (eval(evt.touches[0].pageX + document.body.scrollLeft * 1) * 1);
y = (eval(evt.touches[0].pageY + document.body.scrollTop * 1) * 1);
} else {
x = (eval(evt.touches[0].clientX + document.body.scrollLeft * 1) * 1);
y = (eval(evt.touches[0].clientY + document.body.scrollTop * 1) * 1);
}
} else
if (evt.clientX || evt.clientY) {
x = (eval(evt.clientX + document.body.scrollLeft * 1) * 1);
y = (eval(evt.clientY + document.body.scrollTop * 1) * 1);
} else {
x = (eval(evt.pageX + document.body.scrollLeft * 1) * 1);
y = (eval(evt.pageY + document.body.scrollTop * 1) * 1);
}
var distco=((x - midcoords[placepick][0]) * (x - midcoords[placepick][0])) + ((y - midcoords[placepick][1]) * (y - midcoords[placepick][1]));
var halfpoint='';

var davw=' ... you are very cold ';
if (distco <= verywarm) {
halfpoint='0.5';
davw=" ... you are very warm (and it's possible there is an overlap, so you score the 0.5 choosing this with OK button) ";
} else if (distco <= warm) {
davw=' ... you are warm ';
} else if (distco <= cool) {
davw=' ... you are cool ';
} else if (distco <= cold) {
davw=' ... you are cold ';
}

var nearestplace='';
var nearestdistco=-1;
for (var jwhich=0; jwhich<midcoords.length; jwhich++) {
distco=((midcoords[jwhich][0] - x) * (midcoords[jwhich][0] - x)) + ((midcoords[jwhich][1] - y) * (midcoords[jwhich][1] - y));
if (jwhich == 0) {
nearestplace=places[jwhich].replace(/_/g,' ');
nearestdistco=distco;
} else if (distco < nearestdistco) {
nearestplace=places[jwhich].replace(/_/g,' ');
nearestdistco=distco;
}
}
goes++;
if (nearestplace == placechosen.replace(/_/g,' ')) {
score+=factor;
setTimeout(resetit, 200);
setTimeout(pickone,1000);
} else {
var ans=prompt('You clicked nearest to ' + nearestplace + ' (0 for YouTube search, -0 for Australian Geographic search, +0 Both, 0.0 for Context in Map Legend) but we wanted you to identify ' + placechosen.replace(/_/g,' ') + ' (1 for YouTube search, -1 for Australian Geographic search, +1 Both, 1.1 for Context in Map Legend)' + davw + ' ... try again ... or ... Choose to Cancel', halfpoint);
if (ans == null) {
//alert(92);
setTimeout(pickone,2000);
} else if (ans == '0.0') {
if (lgo != null) lgo.close();
lgo=window.open(pathto + 'legend_via_map.htm?url=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0]) + '&tarea=&submit=Create+Legend+for+HTML+Map+Data&whereami=where-am-i&whatami=what-am-i&secret=secret#' + nearestplace.replace(/ /g,'_'), '_blank');
} else if (ans == '1.1') {
if (lgo != null) lgo.close();
lgo=window.open(pathto + 'legend_via_map.htm?url=' + encodeURIComponent(document.URL.split('?')[0].split('#')[0]) + '&tarea=&submit=Create+Legend+for+HTML+Map+Data&whereami=where-am-i&whatami=what-am-i&secret=secret#' + placechosen.replace(/ /g,'_'), '_blank');
} else if (ans == '-0') {
if (ago != null) ago.close();
ago=window.open('http://www.australiangeographic.com.au/search/search?query=' + nearestplace.replace(/ /g,'%20').replace(/_/g,'%20'),'_blank','top=15,left=15,width=300,height=300');
} else if (ans == '-1') {
if (ago != null) ago.close();
ago=window.open('http://www.australiangeographic.com.au/search/search?query=' + placechosen.replace(/ /g,'%20').replace(/_/g,'%20'),'_blank','top=15,left=15,width=300,height=300');
} else if (ans.replace('+','') == '0') {
if (yto == null) {
if (document.title.indexOf('Country ') != 0) document.title='Country ' + document.title;
document.getElementById('youtube').innerHTML='<a ontouchstart=" realclick=false; setTimeout(resetit,1000); " onclick=" realclick=false; setTimeout(resetit,1000);" title="Back to top" href="#iag">Back to top</a><iframe style=width:900px;height:700px; id=iyto src="' + pathto + 'karaoke_youtube_api.htm?emoji=on&nokaraoke=y&youtubeid=%20%20%20%20%20%20%20' + nearestplace.replace(/ /g,'%20').replace(/_/g,'%20') + '"></iframe>';
yto=document.getElementById('iyto');
} else {
yto.src=pathto + 'karaoke_youtube_api.htm?emoji=on&nokaraoke=y&youtubeid=%20%20%20%20%20%20%20' + nearestplace.replace(/ /g,'%20').replace(/_/g,'%20');
}
if (ans == '+0') {
if (ago != null) ago.close();
ago=window.open('http://www.australiangeographic.com.au/search/search?query=' + nearestplace.replace(/ /g,'%20').replace(/_/g,'%20'),'_blank','top=15,left=15,width=300,height=300');
}
location.href='#iyto';
} else if (ans.replace('+','') == '1') {
if (yto == null) {
if (document.title.indexOf('Country ') != 0) document.title='Country ' + document.title;
document.getElementById('youtube').innerHTML='<a ontouchstart=" realclick=false; setTimeout(resetit,1000); " onclick=" realclick=false; setTimeout(resetit,1000);" title="Back to top" href="#iag">Back to top</a><iframe style=width:900px;height:700px; id=iyto src="' + pathto + 'karaoke_youtube_api.htm?emoji=on&nokaraoke=y&youtubeid=%20%20%20%20%20%20%20' + placechosen.replace(/ /g,'%20').replace(/_/g,'%20') + '"></iframe>';
yto=document.getElementById('iyto');
} else {
yto.src=pathto + 'karaoke_youtube_api.htm?emoji=on&nokaraoke=y&youtubeid=%20%20%20%20%20%20%20' + placechosen.replace(/ /g,'%20').replace(/_/g,'%20');
}
if (ans == '+1') {
if (ago != null) ago.close();
ago=window.open('http://www.australiangeographic.com.au/search/search?query=' + placechosen.replace(/ /g,'%20').replace(/_/g,'%20'),'_blank','top=15,left=15,width=300,height=300');
}
location.href='#iyto';
} else if (ans == '0.5') {
score+=0.5;
setTimeout(pickone,2000);
}
setTimeout(resetit, 200);
}
document.getElementById('score').innerHTML='Score: ' + score + '/' + goes;
}
return '';
}

… in agmap.htm, changed in this way using the Australian Geographical Quiz web application.


Previous relevant Australian Geographical Quiz Context Tutorial is shown below.

Australian Geographical Quiz Context Tutorial

Australian Geographical Quiz Context Tutorial

We are continuing on with our Australian Geographic quiz today, building on our Australian Geographical Quiz Primer Tutorial start yesterday, with some added functionality to assist with “finding out more”. Which is natural for us when we come upon information we have never heard of before. What the “net” has most helped us out with in this respect is its potential as a reference source with …

  • Search Engine websites
  • Encyclopaedic websites such as Wikipedia
  • Research websites
  • Education websites
  • Video repositories

… and today we are going to (allow an) interface to the search functionality of the Australian Geographic website, in addition to the biggest online Video repository, YouTube, and use their great API to embed YouTube videos within HTML iframe elements on your webpage. Perusing YouTube you may have noticed that for many years now at YouTube Share button options, there have been ways to have YouTube help you to “cut” the video embedding HTML code necessary to display a video. That is the basis behind the API, but the API also facilitates …

  • Sequencing videos
  • Stop and start and pause
  • Durations
  • Titles
  • Volume
  • Resizing

… and we’d like to direct you to YouTube API Iframe Synchronicity Resizing Tutorial for further reading here.

Now, as far as “context” goes, coming back to our blog posting title today, sometimes a map can be a bit of an overwhelmingly big thing to take in as the one data source, so we’ve also added as an “interfacing” additional functionality option, the chance for the user to latch onto the work we did with map legends and talked about at Legend for and from HTML Map Element Web Server Tutorial and other related blog postings. Legends turn the map “big” picture into a whole lot of place specific small pictures, with the advantage today, at least with the “Difficult” mode of play, the Australian states are colour coded, so in the legend you can display it will “lob” you onto your specific place of interest, and the background colouring will give you some hints as to where this is in the context of the “bigger picture” map also displayed for you to the left of the map legend.

To understand this more in “context” … chortle, chortle … why not try the Australian Geography quiz yourself at this live run link? Or perhaps peruse the HTML and Javascript code you could call agmap.htm changed in this way for today’s added functionalities? Also changing that little bit for the concept of processing incoming document.URL URLs containing a specially constructed “Australian Geography Quiz” “branded” hashtag (#) appendage as the means to highlight a “lobbed to” legend placename was the HTML code you could call legend_via_map.htm changing in this way to achieve that interfacing logic.


Previous relevant Australian Geographical Quiz Primer Tutorial is shown below.

Australian Geographical Quiz Primer Tutorial

Australian Geographical Quiz Primer Tutorial

We have some similar ideas going on today, with our new web application quiz/game, to those of ESL Vocabulary Getting Warmer Image Tutorial as shown below, as can be summarised by …

  • use of the one underlying background image … coupled with …
  • use of HTML map element on top of that … created via …
  • the brilliant, the stupendous Mobilefish website helper … thanks … to arrive at a …
  • “getting warmer” type of quiz related, today, to Australian Geography

… the underlying map image for which we’ve based on one from the stupendous, the brilliant Australian Geographic magazine and website, so thanks.

A thing different in today’s work, apart from the inherent different look and array manipulations you look and act differently with, over time, with the code, is that we have two images …

  1. original image photographed with an iPad … for an “Easier” gameplay level of difficulty … as well as a …
  2. “confused up”/”messed up” … call it what you will … image version put through a session on Gimp to …
    • Free Select Cut … and …
    • Free Select Gaussian Blur

    … in order to arrive at an image for a “Difficult” gameplay level of difficulty (where there is less on the map image to help the user

… presented to the player of the web application “Australian Geography” game in an HTML select “dropdown” choice.

The other bit extra we’ve done today, because the HTML map element has not been designed to cover the whole rectangle of the image, is to harness the document.body onclick event (fired off via the HTML <body onload=’atstart();’ ontouchstart=’icheck(event);’ onclick=’icheck(event);’>) to check for (web application game) clicks (or touches) that are not …

  • HTML select element based clicks … nor …
  • other HTML map element HTML area element clicks

… and if so, record that click event’s mouse (x,y) co-ordinates and report on this in a similar way to the “HTML map element HTML area element clicks”, except that we have no link to a name for their click (whereas we can glean a name off the HTML area element alt property for those HTML map element HTML area element clicks), and so we inform the user of the “nearest” place they clicked (or touched) near … as per (Javascript DOM code) …


function icheck(evt) {
if (realclick) {
var x,y;
if (evt.clientX || evt.clientY) {
x = evt.clientX;
y = evt.clientY;
} else {
x = evt.pageX;
y = evt.pageY;
}
var distco=((x - midcoords[placepick][0]) * (x - midcoords[placepick][0])) + ((y - midcoords[placepick][1]) * (y - midcoords[placepick][1]));
var halfpoint='';

var davw=' ... you are very cold ';
if (distco <= verywarm) {
halfpoint='0.5';
davw=' ... you are very warm (and its possible there is an overlap, so you score the 0.5 choosing this with OK button) ';
} else if (distco <= warm) {
davw=' ... you are warm ';
} else if (distco <= cool) {
davw=' ... you are cool ';
} else if (distco <= cold) {
davw=' ... you are cold ';
}

var nearestplace='';
var nearestdistco=-1;
for (var jwhich=0; jwhich<midcoords.length; jwhich++) {
distco=((midcoords[jwhich][0] - x) * (midcoords[jwhich][0] - x)) + ((midcoords[jwhich][1] - y) * (midcoords[jwhich][1] - y));
if (jwhich == 0) {
nearestplace=places[jwhich].replace(/_/g,' ');
nearestdistco=distco;
} else if (distco < nearestdistco) {
nearestplace=places[jwhich].replace(/_/g,' ');
nearestdistco=distco;
}
}
goes++;
var ans=prompt('You clicked nearest to ' + nearestplace + ' but we wanted you to identify ' + placechosen.replace(/_/g,' ') + davw + ' ... try again ... or ... Choose to Cancel', halfpoint);
if (ans == null) {
//alert(92);
setTimeout(pickone,2000);
} else if (ans == '0.5') {
score+=0.5;
setTimeout(pickone,2000);
}
setTimeout(resetit, 200);
document.getElementById('score').innerHTML='Score: ' + score + '/' + goes;
}
return '';
}

The Javascript realclick global variable above is set to false by those other HTML select element and/or HTML map element area element click (or touch) events, and then a “setTimeout(resetit,1000);” (for example) would put realclick global variable back to its usual true value.

Why not try the Australian Geography quiz yourself at this live run link? Or peruse the HTML and Javascript code you could call agmap.html perhaps? By the way, this quiz is designed not to ask about the more populous regions or places of Australia, but more your outback or national park or adventure thought places.


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


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

Posted in eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Trust This Computer Issue on iPhone Tutorial

Just Javascript Card Game iPhone Debugging Tutorial

Trust This Computer Issue on iPhone Tutorial

We think we introduced a problem with the way our iPhone charges (or is hard to) recently, and we think we got “out of synch” with using the iPhone as a debugging tool (as we show with Just Javascript Card Game iPhone Debugging Tutorial), connected via an Apple white lead to the USB port of a MacBook Air.

The symptoms of the look of our version of the problem, was that using a particular combination of …

  • Apple white lead
  • MacBook Air USB port

… and us using those two in combination, with a powered up MacBook Air, was charging the iPhone, it would be interrupted constantly in its charging by a “not happening” attempt to bring up a …

Trust this Computer

… alert looking somewhat like …

… alert box regarding the MacBook Air (probably caused by that “out of synch” event during a debugging session). The iPhone constantly buzzes (technically, “vibrates”) every five seconds or so, and even when we got the alert box to show after first remedial steps (suggested by Apple) below …

  1. Go to Settings, then tap General.
  2. Tap Transfer or Reset [Device].
  3. Tap Reset, then tap Reset Location & Privacy.

… we got to a validation 6-8-digit number keyboard screen …

… (after Powering On and Off) that didn’t hang around long enough either (between buzzes) until …

… and we got long enough time to answer that validation 6-8-digit number keyboard screen … phew! Normal behaviour now, hopefully for a good while?!


Previous relevant Just Javascript Card Game iPhone Debugging Tutorial is shown below.

Just Javascript Card Game iPhone Debugging Tutorial

Just Javascript Card Game iPhone Debugging Tutorial

Before yesterday’s Just Javascript Card Game CSS Offerings Tutorial there was the day before yesterday’s Just Javascript Card Game User CSS Tutorial which …

  • introduced an error on mobile devices …
  • not apparent on the MacBook Air we were coding on

… the salutary lesson being that you need to test on platforms you have available to you because our code is sprinkled with plenty of Javascript …


if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
// comes here if most mobile platforms
}

… “if” tests where the “mobile platform” code parts way with the “non-mobile platform” code. This is very likely in the scenario of you creating a game web application involving graphics.

Being the Apple afficianados we are we tend to want to debug the scenario of an iPhone blank screen issue via …

  1. be on MacBook Air Safari web browser …
  2. also be on iPhone Safari web browser at the address https://www.rjmprogramming.com.au/HTMLCSS/cards_usefocus.html?card_memories=2
  3. connect the two with an Apple white lead that is USB at the MacBook Air end and the other end is that same recharging port connection …
  4. back at MacBook Air Safari web browser in the Develop menu you should see the name of the iPhone (eg. “Robert’s iPhone”) appear in the list so go there now …
  5. if the only option is something like “Allow for Development” over at the iPhone you might have a Trust vs Do Not Trust answer to make, and we advise you to be trusting, at which point …
  6. back at MacBook Air Safari web browser in the Develop menu -> [iPhone device name] submenu it should show an option for that https://www.rjmprogramming.com.au/HTMLCSS/cards_usefocus.html?card_memories=2 webpage, and so choose that option …
  7. you may want to refresh the iPhone web address …
  8. back at MacBook Air Safari web browser in the Develop menu -> [iPhone device name] submenu -> [https://www.rjmprogramming.com.au/HTMLCSS/cards_usefocus.html?card_memories=2] subsubmenu be in the Console tab …
  9. we eventually got the error message of use just using the iPhone web application until the line number helped us track down and debug the issue

Also, today, we’ve added to yesterday’s …

  1. accept from then on the presented CSS styling option
  2. reject to restore original CSS styling
  3. wait to be offered the next CSS styling suggestion
  4. enter their own user additional styling CSS
  5. with “accept” and “enter their own” options above spaces at end of user entry signify that window.localStorage should be used to be able to save and recall this CSS for future use

… making use of new Javascript functions in the changed


function checkls() {
if (window.localStorage) {
if (('' + window.localStorage.getItem('cardscsseffect')).replace(/^null$/g,'').replace(/^undefined$/g,'') != '') {
csseffects=('' + decodeURIComponent(window.localStorage.getItem('cardscsseffect')).trim() + ';').replace(';;',';').replace('; ;',';');
document.head.innerHTML+='<style> html { ' + csseffects + ' } </style>';
if (csseffects.replace(/\ /g,'').toLowerCase() == 'filter:none;') {
csseffects='';
window.localStorage.removeItem('cardscsseffect');
return ' are CSS and add spaces to remember.';
} else {
csseffects=' ' + csseffects;
}
return ' ( eg. filter:none; ) override CSS ' + csseffects.trim();
}
}
return ' are CSS and add spaces to remember.';
}

function recallornot(csseffect, iffalsesavetocookie) {
if (!iffalsesavetocookie && window.localStorage) {
if (('' + window.localStorage.getItem('cardscsseffect')).replace(/^null$/g,'').replace(/^undefined$/g,'') != '') {
window.localStorage.removeItem('cardscsseffect');
}
window.localStorage.setItem('cardscsseffect', encodeURIComponent((csseffect.trim() + ';').replace(';;',';')));
}
return csseffect;
}

… code in cards_usefocus.html code behind the “Just Javascript” Memories Card Game or live run with single window (good for mobile) or default live run (for your platform, and if non-mobile it will try child popup windows).



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


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

Posted in eLearning, Hardware, iOS, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Animated GIF Slide Extraction Applied CSS Styling Tutorial

Animated GIF Slide Extraction Applied CSS Styling Tutorial

Animated GIF Slide Extraction Applied CSS Styling Tutorial

We dedicate today’s blog posting to the English phrase (that maybe works in other languages) …

Same, same but different

… as it is about the pros and cons of HTML iframe integration, especially as it applies to CSS styling. Off the top of our heads we see a Pros and Cons table looking like …

Pros and Cons of HTML Iframe Based Web Application Software Integration
Pros Cons
Become tools Difficulty with styling integration especially regarding time of coding differences
Become modularised Focus within iframe can cause problems
Ability to begin again at (0,0) regarding positioning Hashtag navigation within iframe can cause problems
Sharing the coding and execution load
Software organizational advantages
Can glean information off parent and vice versa
New chance for synchronizations
Multitasking
Coding language mixing
Parent child interactions

… and, as you can see, we are mainly fans of what it can bring to the table (mild chuckle, followed by a chortle).

But that first Con can grate, that “Difficulty with styling integration especially regarding time of coding differences”, and today, we thought we’d “apply” to relevant (there was one we found we should not “apply” the thinking to) HTML iframe “child” styling using yesterday’s Animated GIF Slide Extraction CSS Styling Tutorial‘s CSS styling idea in the “parent” (“applied” to these children).

We used a “suck it and see” approach whereby we just, where applicable, appended the CSS <style></style> styling logic of yesterday (plus a bit) to the document.body “body” innerHTML attribute of the iframe called, to see whether it felt more integrated. And we thought it did, perhaps because that styling was one of the more generic feeling ones we can remember (by that we’re meaning that the selectors were often just HTML tag names rather than too much “class” or “id” aspects to those selectors). Also, sometimes it won’t work because adding to the document.body innerHTML can sometimes “muck up” logic (but not today).

And what allows for “deploying” such an idea? Inhouse, we call what we do here “Client Pre-emptive Iframe” ideas, where the relevant iframe element’s “onload” (or on rare occasions, “onerror”) events are used to add logic at a slightly later time to any HTML iframe document.body element’s “onload” logic would be applied. This is a powerful mechanism open to you if you are dealing with same domain parent/child URLs, that is the case for us with this work today.

It’s as easy to do as (showing you one iframe “onload” function example below, and with inline CSS usage, rather than an external CSS file usage (where it would be even easier)) …


var paconto=null;

function pcheckit(iois) {
paconto = (iois.contentWindow || iois.contentDocument);
if (paconto != null) {
if (paconto.document) { paconto = paconto.document; }
if (paconto.body != null) {
setTimeout(function(){
if (document.getElementById('pmyifthree')) {
document.getElementById('pmyifthree').scrolling='no';
}
document.getElementById('myifthree').scrolling='no';
paconto.body.innerHTML+='<st' + 'yle> ' + document.head.innerHTML.split('<st' + 'yle>')[1].split('</st' + 'yle>')[0] + ' </st' + 'yle>';
paconto.getElementsByTagName('select')[0].style.display='none';
paconto.getElementById('image').style.display='none';
paconto.getElementById('isub').style.display='none';
paconto.getElementsByTagName('div')[0].style.opacity='0.0';
paconto.getElementsByTagName('select')[1].style.display='none';
paconto.getElementsByTagName('h1')[0].style.opacity='0.0';
if (1 == 1) { paconto.getElementsByTagName('h4')[0].style.opacity='0.0'; }
if (1 == 1) { paconto.getElementsByTagName('h3')[0].style.opacity='0.0'; }
}, 12000);
}
}
}

… to make this idea come, above. We don’t go overboard with precise integration, that is not our point. Just a …

Same, same but different

… feel in the changed tenth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version, or now, the Animated GIF Slide Extraction via User Interaction web application hashtag speed test version), which you can try below.


Previous relevant Animated GIF Slide Extraction CSS Styling Tutorial is shown below.

Animated GIF Slide Extraction CSS Styling Tutorial

Animated GIF Slide Extraction CSS Styling Tutorial

Another aesthetic plus on top of …

… which we flesh out more of today, further to yesterday’s Animated GIF Slide Extraction Speed Test Tutorial.

What was new to us with today’s work? The linear gradient effect (called text gradient) applied to text was new, thanks, in amongst …

<style>

#agmode { background-color: #98FB98; }
#agmodetwo { background-color: #AFEEEE; }

hr {
border: 5px solid green;
border-radius: 5px;
}

hr.one {
border: 5px solid red;
border-radius: 5px;
}

hr.two {
border: 5px solid orange;
border-radius: 5px;
}

hr.three {
border: 5px solid green;
border-radius: 5px;
}

body {
background: linear-gradient(to right, rgba(173,216,230,0.5) 0%, rgba(255,255,127,0.5) 100%);
}

img {
background: linear-gradient(to right, transparent 0%, transparent 100%);
border-radius: 9px;
}

h3 {
text-shadow: -1px 1px 1px #952dff;
}

input {
text-shadow: -0.4px 0.4px 0.4px #2d952d;
border-radius: 200px;
}

input::placeholder {
text-shadow: -1px 1px 1px #2d95ff;
}

summary {
text-shadow: -1px 1px 1px #ff952d;
}

h1 {
/* font-size: 72px; */
background: -webkit-linear-gradient(rgb(188, 12, 241), rgb(212, 64, 104), rgb(104, 212, 64));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}


iframe {
border-radius: 9px;
}

a {
border-radius: 9px;
}

</style>

… in the changed ninth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version, or now, the Animated GIF Slide Extraction via User Interaction web application hashtag speed test version), which you can try below.


Previous relevant Animated GIF Slide Extraction Speed Test Tutorial is shown below.

Animated GIF Slide Extraction Speed Test Tutorial

Animated GIF Slide Extraction Speed Test Tutorial

Yesterday’s Animated GIF Slide Extraction User Experience Tutorial sparked our interest in that …

  • we wondered whether hashtag components appended to ($_GET) address bar URLs perhaps consisting of ? and & argument parts slowed things down … and after first considering some standalone arrangement …
  • we realized we have quite good conditions with our current Animated GIF Extraction web application project predilections to adapt it

Getting into the coding of this we realized we were touching on another unknown to us. Is a hashtag call such as …


./agtoslides.php?slidenumber=1&random=56476858765876&delay=400&title=%2E%2Fuser_of_ss.gif&numfillin=3#agname=%2E%2Fuser_of_ss.gif

… to PHP going to register the hashtagging? Well, certainly not with PHP functionality but a client facing document.body onload event logic can see it …

<?php

// agtoslides.php
// RJM Programming
// May, 2024
// Animated GIF to a slide via ... ksh agtoslides.ksh [animatedGIFfilename] [slideNumber]
ini_set('max_execution_time', 60000);

$outp='';
$infl='';
$infill='';
$preoutp='';
$postoutp='';

if (file_exists('/tmp/agtoslides')) {
if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh')) {
if (isset($argc) && !isset($_GET['agname']) && !isset($_POST['agname'])) {
$infl=str_replace('+',' ',$argv[1]);
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($argv[1]));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
} else if (!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
}
if ($argc > 2) {
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($argv[2]))) . ' ' . $infill;
} else {
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else {
if (isset($_GET['random']) && !isset($_GET['agname'])) {
echo "<html>
<head>
<scrip" . "t type=text/javascript>
var jjjxhr=null, jjjform=null, astr='', stats=0;

function joneslidedu() {
if (jjjxhr.readyState == 4) {
if (jjjxhr.status == 200) {
parent.window.opener.timingshashpush((new Date()).getTime()); // document.body.innerHTML=jjjxhr.responseText.split(jjjxhr.responseText.substring(1).split('>')[0])[1].split('</body>')[0];
stats=jjjxhr.status;
}
}
}

function ajaxit() {
if (1 == 1) {
parent.setstats(1);
jjjform = new FormData();
jjjxhr = new XMLHttpRequest();
jjjform.append('agname', decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]));
jjjform.append('random', decodeURIComponent('" . $_GET['random'] . "'));
jjjform.append('slidenumber', decodeURIComponent('" . $_GET['slidenumber'] . "'));
jjjxhr.open('post', './agtoslides.php', true);
jjjxhr.onreadystatechange = joneslidedu;
jjjxhr.send(jjjform);
if (parent.window.opener.setstats) {
parent.window.opener.setstats(1);
}
parent.window.opener.document.getElementById('spareagname').value=decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]);
//alert(parent.window.opener.document.getElementById('sparemyform').outerHTML.length);
if (eval('' + parent.window.opener.document.getElementById('sparemyform').outerHTML.length) < 1000) {
parent.window.opener.document.getElementById('sparemyform').method='GET';
} else {
parent.window.opener.document.getElementById('sparemyform').method='POST';
}
parent.window.opener.document.getElementById('sparemyform').action=('' + parent.document.getElementById('sparemyform').action).split('#')[0];
parent.window.opener.document.getElementById('sparemysub').click();
if (1 == 11) {
//parent.getto().document.title='yes';
while (('' + parent.getto().getstats()) != '200') {
if (astr == '' || eval('' + astr.length) > 800) {
astr=' ';
} else {
astr+=' ';
}
}
}
} else {
jjjform = new FormData();
jjjxhr = new XMLHttpRequest();
jjjform.append('agname', decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]));
jjjform.append('random', decodeURIComponent('" . $_GET['random'] . "'));
jjjform.append('slidenumber', decodeURIComponent('" . $_GET['slidenumber'] . "'));
jjjxhr.open('post', './agtoslides.php', true);
jjjxhr.onreadystatechange = joneslidedu;
jjjxhr.send(jjjform);
while (stats != 200) {
if (astr == '' || eval('' + astr.length) > 800) {
astr=' ';
} else {
astr+=' ';
}
}
}
return true;
}

</scr" . "ipt>
</head>
<body onload='return ajaxit();' id=xbody></body></html>
";
exit;
}
if (isset($_GET['agname'])) {
if (isset($_GET['random'])) {
$infill=trim(str_replace('+',' ',urldecode($_GET['random']))) . ' tidyhere';
}
$infl=str_replace(' ','+',urldecode($_GET['agname']));
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($_GET['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
} else if (strpos($infl, $_SERVER['SERVER_NAME']) === false && strpos($infl, 'http') !== false) {
$infl=str_replace(' ','+',urldecode($_GET['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), file_get_contents(str_replace('https:','http:',$infl)) );
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
}
if ((!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) && strpos($infl, 'data:image/') === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
}
if (isset($_GET['slidenumber'])) {
//echo 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber']));
//exit;
//file_put_contents('xget.xxx', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
//echo ' --- ' . $outp;
//exit;
} else {
//file_put_contents('xget.zzz', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else if (isset($_POST['agname'])) {
if (isset($_POST['random'])) {
$infill=trim(str_replace('+',' ',urldecode($_POST['random']))) . ' tidyhere';
}
$infl=str_replace(' ','+',urldecode($_POST['agname']));
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($_POST['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
//if (strlen($infl) != 0) {
//file_put_contents('x.xx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
} else if (strpos($infl, $_SERVER['SERVER_NAME']) === false && strpos($infl, 'http') !== false) {
$infl=str_replace(' ','+',urldecode($_POST['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), file_get_contents(str_replace('https:','http:',$infl)) );
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
//if (strlen($infl) != 0) {
//file_put_contents('x.xxxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
// } else {
//file_put_contents('x.xxxxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
}
if ((!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) && strpos($infl, 'data:image/') === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
//if (strlen($infl) != 0) {
//file_put_contents('x.xxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
}
if (isset($_POST['slidenumber'])) {
//file_put_contents('xpost.xxx', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_POST['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_POST['slidenumber'])) . ' ' . $infill);
} else {
//file_put_contents('xpost.zzz', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else {
$fp = fopen("php://input", "r");
$post = "" . file_get_contents("php://input");
fclose($fp);
if (strpos($post, "agname=") !== false && strpos($post, "random=") !== false && strpos($post, "slidenumber=") !== false) {
$infill=explode('&', explode('random=', $post)[1])[0] . ' tidyhere';
$sn=explode('&', explode('slidenumber=', $post)[1])[0];
$infl=str_replace(' ','+',urldecode(explode('&', explode('agname=', $post)[1])[0]));
if (strpos($infl, 'data:image/') !== false) {
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
}
//file_put_contents('x.xxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . $sn . ' ' . $infill);
}
}
}
}
}
$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;

?>

… we found, to our relief! And though the synchronization is not exact, we simulate “apples for apples” via that Ajax asynchronicity timing for a hashtag call for the “window.open” window, versus the “window.opener” window non-hashtag call of that default animated GIF (like a splash page example) as you enter the web application.

Codewise we have …


Previous relevant Animated GIF Slide Extraction User Experience Tutorial is shown below.

Animated GIF Slide Extraction User Experience Tutorial

Animated GIF Slide Extraction User Experience Tutorial

We often equate the term “user experience” with “niceties”, in that we often find we deal with “user experience” issues well into a project, but you can put more effort into forward design planning so that you deal with it better throughout the project. We found with the Animated GIF Slide Extraction project of yesterday’s Animated GIF Creation Canvas Integration via Slide Extraction Tutorial that issues that had annoyed us for several days past, but which did not stop the web application working, turned into a day where we felt that we were improving the “user experience” by “fixing annoyances” and “adding niceties”, today. As you might imagine, this can be subjective, because just because we think an idea is an improvement does not mean every user out there will think so, and this is where time set aside for real users to try a product (ie. user acceptance testing) ahead of “going live” can be a great idea.

Anyway, there was …

  • an annoyance, on non-mobile, we first introduced when we integrated Animated GIF Creation in with Animated GIF Slide Extraction a couple of days ago … too much cursor:progress; usage … and in fixing we were astonished that cursor:wait; displays the same graphics … anyway, we think it helps when a cursor can help a user get used to identifying wherein the workflow they are situated at any given time …
    <?php echo ”

    function cursorcheck(defisidea) {
    if (window.parent) { if (parent.document.getElementById('cursorchoice')) { if (parent.document.getElementById('cursorchoice').value != '') { return parent.document.getElementById('cursorchoice').value; } } }
    return defisidea;
    }

    “; ?>
    … looking to parent …

    <input data-choice='' type=hidden value='help' id='cursorchoice'></input>
  • we felt better adding <hr> horizontal rule elements above and below the middle HTML iframe we set aside for client browsing functionality … and also …
  • made that iframe less wide enabling us to place to the right of it a hashtag navigational “a” link back up to the top …

    <hr>
    <iframe onload=pcheckit(this); style='display:inline-block;width:80%;height:160px;' id=myifthree src='/PHP/read_exif_off_image_rotate.php#itwo'></iframe> <a id=atotop style='display:inline-block;vertical-align:top;width:15%;text-shadow: -1px 1px 1px #952dff;' onclick="window.scrollTo(0,0);" href='#mydet'>&#11014; Top</a>
    <hr>

    … and …
  • given a background indicative of the goings on with the extracted animated GIF slide …

    function ob(tv) {
    if (tv == '' && intc != '') {
    tv=intc;
    document.getElementById('agname').value=intc;
    document.getElementById('mygimage').src=intc;
    document.getElementById('atotop').style.backgroundImage='linear-gradient(rgba(255,255,255,0.2),rgba(255,255,255,0.2)),URL(' + intc + ')';
    document.getElementById('atotop').style.backgroundSize='contain';
    document.getElementById('atotop').style.backgroundRepeat='no-repeat';

    if (window.parent) {
    if (window.parent != window.self) {
    parent.document.getElementById('myta').setAttribute('data-img', document.getElementById('myta').getAttribute('data-img'));
    parent.document.getElementById('myta').title=document.getElementById('myta').title;
    parent.document.getElementById('agname').value=intc;
    parent.document.getElementById('mygimage').src=intc;
    parent.document.getElementById('atotop').style.backgroundImage='linear-gradient(rgba(255,255,255,0.2),rgba(255,255,255,0.2)),URL(' + intc + ')';
    parent.document.getElementById('atotop').style.backgroundSize='contain';
    parent.document.getElementById('atotop').style.backgroundRepeat='no-repeat';

    parent.document.getElementById('agname').value=intc;
    parent.document.getElementById('mygimage').title='Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...';
    parent.document.getElementById('mysum').innerHTML=appbut('Animated GIF Slide Extraction Display ... RJM Programming - May, 2024 ... Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...');
    parent.document.getElementById('slidenumber').value='' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij));
    parent.unsetit();
    }
    }
    //tv=gifurl;
    ij=0;
    setTimeout(function(){ intc=''; }, 27000);
    }
    if (tv.trim() != '') {
    if (tv.indexOf('data') != 0 && tv.indexOf('//') != -1 && document.URL.indexOf('//') != -1) {
    if (tv.split('//')[1].split('/')[0].toLowerCase().replace(/^www\./g,'') != document.URL.split('//')[1].split('/')[0].toLowerCase().replace(/^www\./g,'')) {
    document.getElementById('myiffour').src='/getex.php?dodu=y&url=' + encodeURIComponent(tv); //window.open('/getex.php?dodu=y&url=' + encodeURIComponent(tv), '_blank');
    } else {
    prefetch(tv);
    }
    } else {
    prefetch(tv);
    }
    }
    }

    … and …
  • should the user click one (of the now two, and colour coded, as below) Animated GIF Creation action buttons now presented in our “reveal” details/summary the scrolling now lands

    function appittwo(iob) {
    if (('' + document.getElementById('agmode').getAttribute('data-mode')) != '') {
    document.getElementById('agmode').setAttribute('data-mode', '');
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    } else {
    document.getElementById('agmode').setAttribute('data-mode', 'rcmysubmit');
    document.getElementById('cursorchoice').setAttribute('data-choice', 'rcmysubmit');
    document.getElementById('cursorchoice').value='copy';
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    if (document.getElementById('followxthrough')) {
    document.getElementById('followxthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    }
    document.getElementById('agmode').style.display='none';
    document.getElementById('agmodetwo').style.display='none';
    document.getElementById('agmodethree').style.display='none';
    setTimeout(function(){ document.getElementById('myifthree').scrollIntoView(); }, 8000); //location.href='#myifthree';
    }
    }

    function appit(iob) {
    if (('' + document.getElementById('agmode').getAttribute('data-mode')) != '') {
    document.getElementById('agmode').setAttribute('data-mode', '');
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    } else {
    document.getElementById('agmode').setAttribute('data-mode', 'mysubmit');
    document.getElementById('cursorchoice').setAttribute('data-choice', 'mysubmit');
    document.getElementById('cursorchoice').value='copy';
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    if (document.getElementById('followxthrough')) {
    document.getElementById('followxthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    }
    document.getElementById('agmode').style.display='none';
    document.getElementById('agmodetwo').style.display='none';
    document.getElementById('agmodethree').style.display='none';
    setTimeout(function(){ document.getElementById('myifthree').scrollIntoView(); }, 8000); //location.href='#myifthree';
    }
    }

    … at the top of that middle iframe which is short enough so it and the Animated GIF Creation iframe are viewable on many platforms, those button presses created personalized animated GIFs there and then (at least on non-mobile), the user there to see that happening … where …
  • the user clicking the buttons up the top or down the bottom regarding Animate GIF Creation work for the two “submit” button modes can see which one was pressed via new border:5px dotted yellow; styling …
    <?php

    $indone="youllneverfindthis";
    $outdone="youllneverfindthis";


    if (isset($_POST['followthrough']) || isset($_GET['followthrough'])) {
    if (isset($_POST['followthrough'])) {
    if (strlen($_POST['followthrough']) > 0) {
    $indone='#' . $_POST['followthrough'] . " { ba";
    $outdone='#' . $_POST['followthrough'] . " { border:5px dotted yellow; ba";

    if ($_POST['followthrough'] == 'overlayit') {
    $smallfillin="\n setTimeout(function(){ overlaythem(); }, 8000); \n document.getElementById('" . $_POST['followthrough'] . "').style.border='4px dotted pink'; \n";
    } else {
    $smallfillin="\n document.getElementById('" . $_POST['followthrough'] . "').style.border='4px dotted pink'; \n setTimeout(function(){ document.getElementById('" . $_POST['followthrough'] . "').click(); }, 5000); \n";
    }
    }
    } else if (isset($_GET['followthrough'])) {
    if (strlen($_GET['followthrough']) > 0) {
    $indone='#' . $_GET['followthrough'] . " { ba";
    $outdone='#' . $_GET['followthrough'] . " { border:5px dotted yellow; ba";

    if ($_GET['followthrough'] == 'overlayit') {
    $smallfillin="\n setTimeout(function(){ overlaythem(); }, 8000); \n document.getElementById('" . $_GET['followthrough'] . "').style.border='4px dotted pink'; \n";
    } else {
    $smallfillin="\n document.getElementById('" . $_GET['followthrough'] . "').style.border='4px dotted pink'; \n setTimeout(function(){ document.getElementById('" . $_GET['followthrough'] . "').click(); }, 5000); \n";
    }
    }
    }
    }

    ?>
    applied

    <?php echo ”

    <style>
    input[type=submit]:active {
    border: 5px dotted yellow;
    }
    a { padding: 5px 5px 5px 5px; margin: 5px 5px 5px 5px; border: 1px solid red; background-color: #f0f0f0; }
    ::placeholder {
    font-size: 9px;
    }
    ::-webkit-input-placeholder { /* Chrome/Opera/Safari */
    font-size: 9px;
    }
    ::-moz-placeholder { /* Firefox 19+ */
    font-size: 9px;
    }
    :-ms-input-placeholder { /* IE 10+ */
    font-size: 9px;
    }
    :-moz-placeholder { /* Firefox 18- */
    font-size: 9px;
    }" . str_replace($indone, $outdone, "
    #mysubmit { background-color: #98FB98; }
    #rcmysubmit { background-color: #AFEEEE; }
    #overlayit { background-color: #FADADD; }
    #imsel { background-color: cyan; }
    #jmsel { background-color: magenta; }
    #watermarkmode { background-color: olive; }
    #selwhs { background-color: teal; }
    #sfilteris { background-color: lightgreen; } ") . "
    </style>

    “; ?>
    to the relevant bottom button

Codewise we have …


Previous relevant Animated GIF Creation Canvas Integration via Slide Extraction Tutorial is shown below.

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Thinking about yesterday’s Animated GIF Creation Data Limits via Slide Extraction Tutorial‘s progress …

What about if the user is happy to use those filled in animated GIF slide textboxes (with delay and title) to create a user created (and downloadable) animated GIF there and then?

Well, we know that user could click their own presented button, but we wanted to flag it up at the parent ahead of time too, in terms of clarity in the changed seventh 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.

So, what’s all this got to do with an HTML canvas element (in case we have readers who take notice of the nuances of blog posting titles, that is)? Well, once you reach the stage with our inhouse Animated GIF Creator web application, where it has created your own animated GIF image, there is an “onclick” subsection of functionality that, in our new scenario, suffered from an error 404 (Bad Request) because the codeline ran as …

<?php echo ”

canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords, '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));

“; ?>

… but got that error because variable useyourwords contains an animated GIF “first slide” data-URI (useful in that a [canvasContext].drawImage() call of it would do what “drawImage” does with animated GIFs anyway (going back to the original point regarding this whole thread of blog postings)) which caused an overshoot of data size limits on conventional ($_GET style) address bar URLs (perhaps involving ? and & arguments (whether they be five minute or ten minute ones)). But regular readers will know, for a happy couple of months now, we recognize we do not always have to call into play serverside PHP and its $_POST mechanisms here, because we can also call on our life changing hashtagging (ie. #) (clientside approach for HTML/Javascript/CSS webpage) ideas now! Yay!!!!! And so, it came to pass, that … yes … there was light on yonder hilland vale … whatever that is … as “we broke bread” … shall we say … let’s … with some new hashtagging code in the changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application

<?php echo ”

if (eval('' + ('' + '/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords).length) <= 800) {
canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords, '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));
} else {
canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords.replace('&','#'), '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));
}


“; ?>

… as above and with the changed user_of_signature_signature.htm User of Signature Signature inhouse canvas graphic data web application “canvas hoster” …


var thewords=(location.search + location.hash).split('thewords=')[1] ? decodeURIComponent((location.search + location.hash).split('thewords=')[1].split('&')[0]) : "";
if (thewords.indexOf('data') == 0) { thewords=thewords.replace(/\ /g,'+'); }

… to bring “canvas integration” into the mix.


Previous relevant Animated GIF Creation Data Limits via Slide Extraction Tutorial is shown below.

Animated GIF Creation Data Limits via Slide Extraction Tutorial

Animated GIF Creation Data Limits via Slide Extraction Tutorial

Even PHP’s $_POST[] approach to HTML form navigation data sharing has it’s limits, and that can be challenged when considering a whole set of data-URI defined animated GIF slide images.

But, behind the scenes, when $_POST[] does not get filled out with regard to the data limits of the Apache/PHP/MySql (in our case) web server involved, there is still php://input

PHP provides a number of miscellaneous I/O streams that allow access to PHP’s own input and output streams, the standard input, output and error file descriptors, in-memory and disk-backed temporary file streams, and filters that can manipulate other file resources as they are read from and written to.

php://stdin, php://stdout and php://stderr ¶
php://stdin, php://stdout and php://stderr allow direct access to the corresponding input or output stream of the PHP process. The stream references a duplicate file descriptor, so if you open php://stdin and later close it, you close only your copy of the descriptor-the actual stream referenced by STDIN is unaffected. It is recommended that you simply use the constants STDIN, STDOUT and STDERR instead of manually opening streams using these wrappers.

php://stdin is read-only, whereas php://stdout and php://stderr are write-only.

… we can turn to (thanks, PHP), that can save the day in a lot of these scenarios.

The thing is, which our parent HTML and Javascript can help with, we want to be flagging the scenario where we should be checking that php://input usage might be coming into play. Well, even for an HTML form method=POST action=[ourRelevantPHP] scenario, the PHP global $_SERVER[‘QUERY_STRING’] is honoured, shall we say (separate to any $_GET[] ideas, is what we are getting at here). So we can, at the client HTML and Javascript parent (and client) end, set a unique $_SERVER[‘QUERY_STRING’] condition to test for in a changed sixth 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, nuancing yesterday’s Animated GIF Creation Interfacing via Slide Extraction Tutorial


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

… and then, up at that “[ourRelevantPHP]” changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application we can test as per

<?php

if (strpos(('' . $_SERVER['QUERY_STRING']), '=numfillin') !== false && !isset($_POST['numfillin']) && !isset($_GET['numfillin'])) {
$fp = fopen("php://input", "r");
$post = "" . file_get_contents("php://input");
fclose($fp);
$prefdelim='?';
$pairings=[];
//file_put_contents('yes.yes', substr($post,0,300));
if (strpos($post, '=') !== false && strpos($post, '?') === false) {
$pairings=explode('=', ('?' . $post));
} else if (strpos($post, '=') !== false) {
$pairings=explode('=', ('' . $post));
}
if (strpos($post, '=') !== false) { // && strpos($post, '?') !== false) {
$post='';
//file_put_contents('yesagain.yes', '' . sizeof($pairings));
for ($ipairings=1; $ipairings<sizeof($pairings); $ipairings++) {
$thisval=explode('&', $pairings[$ipairings])[0];
$thisname=explode($prefdelim, $pairings[-1 + $ipairings])[1];
if (strpos(('~' . $thisval), '~data') !== false) {
$_POST[$thisname]=$thisval;
} else {
$_POST[$thisname]=$thisval;
}
if (strpos($thisname, 'slideshow') !== false) {
//file_put_contents('yes_yet_again.yes', '' . $thisname . ' ' . strlen($thisval));
}
//file_put_contents('yes_again.yes', '' . $thisname . ' ' . strlen($thisval));
$prefdelim='&';
}
$pairings=[];
}
}
$post='';

if (isset($_GET['numfillin'])) { $numfillin=$_GET['numfillin']; }
if (isset($_POST['numfillin'])) { $numfillin=$_POST['numfillin']; }

$nonplus=' ';
$theplus='+';
if ($numfillin >= 2) {
if (isset($_GET['numfillin'])) {
$numfillin=$_GET['numfillin'];
if (isset($_GET['slideshow'])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$preurl=str_replace($nonplus,$theplus,urldecode($_GET['slideshow']));
}
$nonplus=' ';
$theplus='+';
if (isset($_GET['slideshow2'])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow2']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_GET['slideshow2'])) . '"',$twopattern);
} else {
$bigfillin=$twopattern;
}
} else if (isset($_POST['numfillin'])) {
$numfillin=$_POST['numfillin'];
if (isset($_POST['slideshow'])) {
//file_put_contents('yes_slideshow_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$preurl=str_replace($nonplus,$theplus,urldecode($_POST['slideshow']));
}
if (isset($_POST['slideshow2'])) {
//file_put_contents('yes_slideshow2_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow2']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_POST['slideshow2'])) . '"',$twopattern);
} else {
$bigfillin=$twopattern;
}
}
$nonplus=' ';
$theplus='+';
for ($ijh=3; $ijh<=$numfillin; $ijh++) {
$pretwopattern='<div id="fdiv' . $ijh . '">';
if (isset($_GET['slideshow' . $ijh])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow' . $ijh]),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_GET['slideshow' . $ijh])) . '"',str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern))))) . $posttwopattern . '</div>', $bigfillin);
} else if (isset($_POST['slideshow' . $ijh])) {
//file_put_contents('yes_slideshow' . $ijh . '_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow' . $ijh]),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_POST['slideshow' . $ijh])) . '"',str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern))))) . $posttwopattern . '</div>', $bigfillin);
} else {
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern)))) . $posttwopattern . '</div>', $bigfillin);
}
$nonplus=' ';
$theplus='+';
if ($ijh == $numfillin) {
$ijh++;
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern)))) . $posttwopattern . '</div>', $bigfillin);
}
}
}

?>

… to cater for more scenarios, we’re hoping!


Previous relevant Animated GIF Creation Interfacing via Slide Extraction Tutorial is shown below.

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.


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.


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

Posted in eLearning | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Animated GIF Slide Extraction CSS Styling Tutorial

Animated GIF Slide Extraction CSS Styling Tutorial

Animated GIF Slide Extraction CSS Styling Tutorial

Another aesthetic plus on top of …

… which we flesh out more of today, further to yesterday’s Animated GIF Slide Extraction Speed Test Tutorial.

What was new to us with today’s work? The linear gradient effect (called text gradient) applied to text was new, thanks, in amongst …

<style>

#agmode { background-color: #98FB98; }
#agmodetwo { background-color: #AFEEEE; }

hr {
border: 5px solid green;
border-radius: 5px;
}

hr.one {
border: 5px solid red;
border-radius: 5px;
}

hr.two {
border: 5px solid orange;
border-radius: 5px;
}

hr.three {
border: 5px solid green;
border-radius: 5px;
}

body {
background: linear-gradient(to right, rgba(173,216,230,0.5) 0%, rgba(255,255,127,0.5) 100%);
}

img {
background: linear-gradient(to right, transparent 0%, transparent 100%);
border-radius: 9px;
}

h3 {
text-shadow: -1px 1px 1px #952dff;
}

input {
text-shadow: -0.4px 0.4px 0.4px #2d952d;
border-radius: 200px;
}

input::placeholder {
text-shadow: -1px 1px 1px #2d95ff;
}

summary {
text-shadow: -1px 1px 1px #ff952d;
}

h1 {
/* font-size: 72px; */
background: -webkit-linear-gradient(rgb(188, 12, 241), rgb(212, 64, 104), rgb(104, 212, 64));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}


iframe {
border-radius: 9px;
}

a {
border-radius: 9px;
}

</style>

… in the changed ninth draft extract_ag_slide_huh_of.html Animated GIF Slide Extraction web application (or Animated GIF Slide Extraction via User Interaction web application version, or now, the Animated GIF Slide Extraction via User Interaction web application hashtag speed test version), which you can try below.


Previous relevant Animated GIF Slide Extraction Speed Test Tutorial is shown below.

Animated GIF Slide Extraction Speed Test Tutorial

Animated GIF Slide Extraction Speed Test Tutorial

Yesterday’s Animated GIF Slide Extraction User Experience Tutorial sparked our interest in that …

  • we wondered whether hashtag components appended to ($_GET) address bar URLs perhaps consisting of ? and & argument parts slowed things down … and after first considering some standalone arrangement …
  • we realized we have quite good conditions with our current Animated GIF Extraction web application project predilections to adapt it

Getting into the coding of this we realized we were touching on another unknown to us. Is a hashtag call such as …


./agtoslides.php?slidenumber=1&random=56476858765876&delay=400&title=%2E%2Fuser_of_ss.gif&numfillin=3#agname=%2E%2Fuser_of_ss.gif

… to PHP going to register the hashtagging? Well, certainly not with PHP functionality but a client facing document.body onload event logic can see it …

<?php

// agtoslides.php
// RJM Programming
// May, 2024
// Animated GIF to a slide via ... ksh agtoslides.ksh [animatedGIFfilename] [slideNumber]
ini_set('max_execution_time', 60000);

$outp='';
$infl='';
$infill='';
$preoutp='';
$postoutp='';

if (file_exists('/tmp/agtoslides')) {
if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh')) {
if (isset($argc) && !isset($_GET['agname']) && !isset($_POST['agname'])) {
$infl=str_replace('+',' ',$argv[1]);
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($argv[1]));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
} else if (!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
}
if ($argc > 2) {
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($argv[2]))) . ' ' . $infill;
} else {
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else {
if (isset($_GET['random']) && !isset($_GET['agname'])) {
echo "<html>
<head>
<scrip" . "t type=text/javascript>
var jjjxhr=null, jjjform=null, astr='', stats=0;

function joneslidedu() {
if (jjjxhr.readyState == 4) {
if (jjjxhr.status == 200) {
parent.window.opener.timingshashpush((new Date()).getTime()); // document.body.innerHTML=jjjxhr.responseText.split(jjjxhr.responseText.substring(1).split('>')[0])[1].split('</body>')[0];
stats=jjjxhr.status;
}
}
}

function ajaxit() {
if (1 == 1) {
parent.setstats(1);
jjjform = new FormData();
jjjxhr = new XMLHttpRequest();
jjjform.append('agname', decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]));
jjjform.append('random', decodeURIComponent('" . $_GET['random'] . "'));
jjjform.append('slidenumber', decodeURIComponent('" . $_GET['slidenumber'] . "'));
jjjxhr.open('post', './agtoslides.php', true);
jjjxhr.onreadystatechange = joneslidedu;
jjjxhr.send(jjjform);
if (parent.window.opener.setstats) {
parent.window.opener.setstats(1);
}
parent.window.opener.document.getElementById('spareagname').value=decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]);
//alert(parent.window.opener.document.getElementById('sparemyform').outerHTML.length);
if (eval('' + parent.window.opener.document.getElementById('sparemyform').outerHTML.length) < 1000) {
parent.window.opener.document.getElementById('sparemyform').method='GET';
} else {
parent.window.opener.document.getElementById('sparemyform').method='POST';
}
parent.window.opener.document.getElementById('sparemyform').action=('' + parent.document.getElementById('sparemyform').action).split('#')[0];
parent.window.opener.document.getElementById('sparemysub').click();
if (1 == 11) {
//parent.getto().document.title='yes';
while (('' + parent.getto().getstats()) != '200') {
if (astr == '' || eval('' + astr.length) > 800) {
astr=' ';
} else {
astr+=' ';
}
}
}
} else {
jjjform = new FormData();
jjjxhr = new XMLHttpRequest();
jjjform.append('agname', decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]));
jjjform.append('random', decodeURIComponent('" . $_GET['random'] . "'));
jjjform.append('slidenumber', decodeURIComponent('" . $_GET['slidenumber'] . "'));
jjjxhr.open('post', './agtoslides.php', true);
jjjxhr.onreadystatechange = joneslidedu;
jjjxhr.send(jjjform);
while (stats != 200) {
if (astr == '' || eval('' + astr.length) > 800) {
astr=' ';
} else {
astr+=' ';
}
}
}
return true;
}

</scr" . "ipt>
</head>
<body onload='return ajaxit();' id=xbody></body></html>
";
exit;
}
if (isset($_GET['agname'])) {
if (isset($_GET['random'])) {
$infill=trim(str_replace('+',' ',urldecode($_GET['random']))) . ' tidyhere';
}
$infl=str_replace(' ','+',urldecode($_GET['agname']));
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($_GET['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
} else if (strpos($infl, $_SERVER['SERVER_NAME']) === false && strpos($infl, 'http') !== false) {
$infl=str_replace(' ','+',urldecode($_GET['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), file_get_contents(str_replace('https:','http:',$infl)) );
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
}
if ((!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) && strpos($infl, 'data:image/') === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
}
if (isset($_GET['slidenumber'])) {
//echo 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber']));
//exit;
//file_put_contents('xget.xxx', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
//echo ' --- ' . $outp;
//exit;
} else {
//file_put_contents('xget.zzz', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else if (isset($_POST['agname'])) {
if (isset($_POST['random'])) {
$infill=trim(str_replace('+',' ',urldecode($_POST['random']))) . ' tidyhere';
}
$infl=str_replace(' ','+',urldecode($_POST['agname']));
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($_POST['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
//if (strlen($infl) != 0) {
//file_put_contents('x.xx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
} else if (strpos($infl, $_SERVER['SERVER_NAME']) === false && strpos($infl, 'http') !== false) {
$infl=str_replace(' ','+',urldecode($_POST['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), file_get_contents(str_replace('https:','http:',$infl)) );
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
//if (strlen($infl) != 0) {
//file_put_contents('x.xxxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
// } else {
//file_put_contents('x.xxxxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
}
if ((!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) && strpos($infl, 'data:image/') === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
//if (strlen($infl) != 0) {
//file_put_contents('x.xxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
}
if (isset($_POST['slidenumber'])) {
//file_put_contents('xpost.xxx', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_POST['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_POST['slidenumber'])) . ' ' . $infill);
} else {
//file_put_contents('xpost.zzz', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else {
$fp = fopen("php://input", "r");
$post = "" . file_get_contents("php://input");
fclose($fp);
if (strpos($post, "agname=") !== false && strpos($post, "random=") !== false && strpos($post, "slidenumber=") !== false) {
$infill=explode('&', explode('random=', $post)[1])[0] . ' tidyhere';
$sn=explode('&', explode('slidenumber=', $post)[1])[0];
$infl=str_replace(' ','+',urldecode(explode('&', explode('agname=', $post)[1])[0]));
if (strpos($infl, 'data:image/') !== false) {
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
}
//file_put_contents('x.xxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . $sn . ' ' . $infill);
}
}
}
}
}
$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;

?>

… we found, to our relief! And though the synchronization is not exact, we simulate “apples for apples” via that Ajax asynchronicity timing for a hashtag call for the “window.open” window, versus the “window.opener” window non-hashtag call of that default animated GIF (like a splash page example) as you enter the web application.

Codewise we have …


Previous relevant Animated GIF Slide Extraction User Experience Tutorial is shown below.

Animated GIF Slide Extraction User Experience Tutorial

Animated GIF Slide Extraction User Experience Tutorial

We often equate the term “user experience” with “niceties”, in that we often find we deal with “user experience” issues well into a project, but you can put more effort into forward design planning so that you deal with it better throughout the project. We found with the Animated GIF Slide Extraction project of yesterday’s Animated GIF Creation Canvas Integration via Slide Extraction Tutorial that issues that had annoyed us for several days past, but which did not stop the web application working, turned into a day where we felt that we were improving the “user experience” by “fixing annoyances” and “adding niceties”, today. As you might imagine, this can be subjective, because just because we think an idea is an improvement does not mean every user out there will think so, and this is where time set aside for real users to try a product (ie. user acceptance testing) ahead of “going live” can be a great idea.

Anyway, there was …

  • an annoyance, on non-mobile, we first introduced when we integrated Animated GIF Creation in with Animated GIF Slide Extraction a couple of days ago … too much cursor:progress; usage … and in fixing we were astonished that cursor:wait; displays the same graphics … anyway, we think it helps when a cursor can help a user get used to identifying wherein the workflow they are situated at any given time …
    <?php echo ”

    function cursorcheck(defisidea) {
    if (window.parent) { if (parent.document.getElementById('cursorchoice')) { if (parent.document.getElementById('cursorchoice').value != '') { return parent.document.getElementById('cursorchoice').value; } } }
    return defisidea;
    }

    “; ?>
    … looking to parent …

    <input data-choice='' type=hidden value='help' id='cursorchoice'></input>
  • we felt better adding <hr> horizontal rule elements above and below the middle HTML iframe we set aside for client browsing functionality … and also …
  • made that iframe less wide enabling us to place to the right of it a hashtag navigational “a” link back up to the top …

    <hr>
    <iframe onload=pcheckit(this); style='display:inline-block;width:80%;height:160px;' id=myifthree src='/PHP/read_exif_off_image_rotate.php#itwo'></iframe> <a id=atotop style='display:inline-block;vertical-align:top;width:15%;text-shadow: -1px 1px 1px #952dff;' onclick="window.scrollTo(0,0);" href='#mydet'>&#11014; Top</a>
    <hr>

    … and …
  • given a background indicative of the goings on with the extracted animated GIF slide …

    function ob(tv) {
    if (tv == '' && intc != '') {
    tv=intc;
    document.getElementById('agname').value=intc;
    document.getElementById('mygimage').src=intc;
    document.getElementById('atotop').style.backgroundImage='linear-gradient(rgba(255,255,255,0.2),rgba(255,255,255,0.2)),URL(' + intc + ')';
    document.getElementById('atotop').style.backgroundSize='contain';
    document.getElementById('atotop').style.backgroundRepeat='no-repeat';

    if (window.parent) {
    if (window.parent != window.self) {
    parent.document.getElementById('myta').setAttribute('data-img', document.getElementById('myta').getAttribute('data-img'));
    parent.document.getElementById('myta').title=document.getElementById('myta').title;
    parent.document.getElementById('agname').value=intc;
    parent.document.getElementById('mygimage').src=intc;
    parent.document.getElementById('atotop').style.backgroundImage='linear-gradient(rgba(255,255,255,0.2),rgba(255,255,255,0.2)),URL(' + intc + ')';
    parent.document.getElementById('atotop').style.backgroundSize='contain';
    parent.document.getElementById('atotop').style.backgroundRepeat='no-repeat';

    parent.document.getElementById('agname').value=intc;
    parent.document.getElementById('mygimage').title='Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...';
    parent.document.getElementById('mysum').innerHTML=appbut('Animated GIF Slide Extraction Display ... RJM Programming - May, 2024 ... Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...');
    parent.document.getElementById('slidenumber').value='' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij));
    parent.unsetit();
    }
    }
    //tv=gifurl;
    ij=0;
    setTimeout(function(){ intc=''; }, 27000);
    }
    if (tv.trim() != '') {
    if (tv.indexOf('data') != 0 && tv.indexOf('//') != -1 && document.URL.indexOf('//') != -1) {
    if (tv.split('//')[1].split('/')[0].toLowerCase().replace(/^www\./g,'') != document.URL.split('//')[1].split('/')[0].toLowerCase().replace(/^www\./g,'')) {
    document.getElementById('myiffour').src='/getex.php?dodu=y&url=' + encodeURIComponent(tv); //window.open('/getex.php?dodu=y&url=' + encodeURIComponent(tv), '_blank');
    } else {
    prefetch(tv);
    }
    } else {
    prefetch(tv);
    }
    }
    }

    … and …
  • should the user click one (of the now two, and colour coded, as below) Animated GIF Creation action buttons now presented in our “reveal” details/summary the scrolling now lands

    function appittwo(iob) {
    if (('' + document.getElementById('agmode').getAttribute('data-mode')) != '') {
    document.getElementById('agmode').setAttribute('data-mode', '');
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    } else {
    document.getElementById('agmode').setAttribute('data-mode', 'rcmysubmit');
    document.getElementById('cursorchoice').setAttribute('data-choice', 'rcmysubmit');
    document.getElementById('cursorchoice').value='copy';
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    if (document.getElementById('followxthrough')) {
    document.getElementById('followxthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    }
    document.getElementById('agmode').style.display='none';
    document.getElementById('agmodetwo').style.display='none';
    document.getElementById('agmodethree').style.display='none';
    setTimeout(function(){ document.getElementById('myifthree').scrollIntoView(); }, 8000); //location.href='#myifthree';
    }
    }

    function appit(iob) {
    if (('' + document.getElementById('agmode').getAttribute('data-mode')) != '') {
    document.getElementById('agmode').setAttribute('data-mode', '');
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    } else {
    document.getElementById('agmode').setAttribute('data-mode', 'mysubmit');
    document.getElementById('cursorchoice').setAttribute('data-choice', 'mysubmit');
    document.getElementById('cursorchoice').value='copy';
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    if (document.getElementById('followxthrough')) {
    document.getElementById('followxthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    }
    document.getElementById('agmode').style.display='none';
    document.getElementById('agmodetwo').style.display='none';
    document.getElementById('agmodethree').style.display='none';
    setTimeout(function(){ document.getElementById('myifthree').scrollIntoView(); }, 8000); //location.href='#myifthree';
    }
    }

    … at the top of that middle iframe which is short enough so it and the Animated GIF Creation iframe are viewable on many platforms, those button presses created personalized animated GIFs there and then (at least on non-mobile), the user there to see that happening … where …
  • the user clicking the buttons up the top or down the bottom regarding Animate GIF Creation work for the two “submit” button modes can see which one was pressed via new border:5px dotted yellow; styling …
    <?php

    $indone="youllneverfindthis";
    $outdone="youllneverfindthis";


    if (isset($_POST['followthrough']) || isset($_GET['followthrough'])) {
    if (isset($_POST['followthrough'])) {
    if (strlen($_POST['followthrough']) > 0) {
    $indone='#' . $_POST['followthrough'] . " { ba";
    $outdone='#' . $_POST['followthrough'] . " { border:5px dotted yellow; ba";

    if ($_POST['followthrough'] == 'overlayit') {
    $smallfillin="\n setTimeout(function(){ overlaythem(); }, 8000); \n document.getElementById('" . $_POST['followthrough'] . "').style.border='4px dotted pink'; \n";
    } else {
    $smallfillin="\n document.getElementById('" . $_POST['followthrough'] . "').style.border='4px dotted pink'; \n setTimeout(function(){ document.getElementById('" . $_POST['followthrough'] . "').click(); }, 5000); \n";
    }
    }
    } else if (isset($_GET['followthrough'])) {
    if (strlen($_GET['followthrough']) > 0) {
    $indone='#' . $_GET['followthrough'] . " { ba";
    $outdone='#' . $_GET['followthrough'] . " { border:5px dotted yellow; ba";

    if ($_GET['followthrough'] == 'overlayit') {
    $smallfillin="\n setTimeout(function(){ overlaythem(); }, 8000); \n document.getElementById('" . $_GET['followthrough'] . "').style.border='4px dotted pink'; \n";
    } else {
    $smallfillin="\n document.getElementById('" . $_GET['followthrough'] . "').style.border='4px dotted pink'; \n setTimeout(function(){ document.getElementById('" . $_GET['followthrough'] . "').click(); }, 5000); \n";
    }
    }
    }
    }

    ?>
    applied

    <?php echo ”

    <style>
    input[type=submit]:active {
    border: 5px dotted yellow;
    }
    a { padding: 5px 5px 5px 5px; margin: 5px 5px 5px 5px; border: 1px solid red; background-color: #f0f0f0; }
    ::placeholder {
    font-size: 9px;
    }
    ::-webkit-input-placeholder { /* Chrome/Opera/Safari */
    font-size: 9px;
    }
    ::-moz-placeholder { /* Firefox 19+ */
    font-size: 9px;
    }
    :-ms-input-placeholder { /* IE 10+ */
    font-size: 9px;
    }
    :-moz-placeholder { /* Firefox 18- */
    font-size: 9px;
    }" . str_replace($indone, $outdone, "
    #mysubmit { background-color: #98FB98; }
    #rcmysubmit { background-color: #AFEEEE; }
    #overlayit { background-color: #FADADD; }
    #imsel { background-color: cyan; }
    #jmsel { background-color: magenta; }
    #watermarkmode { background-color: olive; }
    #selwhs { background-color: teal; }
    #sfilteris { background-color: lightgreen; } ") . "
    </style>

    “; ?>
    to the relevant bottom button

Codewise we have …


Previous relevant Animated GIF Creation Canvas Integration via Slide Extraction Tutorial is shown below.

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Thinking about yesterday’s Animated GIF Creation Data Limits via Slide Extraction Tutorial‘s progress …

What about if the user is happy to use those filled in animated GIF slide textboxes (with delay and title) to create a user created (and downloadable) animated GIF there and then?

Well, we know that user could click their own presented button, but we wanted to flag it up at the parent ahead of time too, in terms of clarity in the changed seventh 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.

So, what’s all this got to do with an HTML canvas element (in case we have readers who take notice of the nuances of blog posting titles, that is)? Well, once you reach the stage with our inhouse Animated GIF Creator web application, where it has created your own animated GIF image, there is an “onclick” subsection of functionality that, in our new scenario, suffered from an error 404 (Bad Request) because the codeline ran as …

<?php echo ”

canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords, '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));

“; ?>

… but got that error because variable useyourwords contains an animated GIF “first slide” data-URI (useful in that a [canvasContext].drawImage() call of it would do what “drawImage” does with animated GIFs anyway (going back to the original point regarding this whole thread of blog postings)) which caused an overshoot of data size limits on conventional ($_GET style) address bar URLs (perhaps involving ? and & arguments (whether they be five minute or ten minute ones)). But regular readers will know, for a happy couple of months now, we recognize we do not always have to call into play serverside PHP and its $_POST mechanisms here, because we can also call on our life changing hashtagging (ie. #) (clientside approach for HTML/Javascript/CSS webpage) ideas now! Yay!!!!! And so, it came to pass, that … yes … there was light on yonder hilland vale … whatever that is … as “we broke bread” … shall we say … let’s … with some new hashtagging code in the changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application

<?php echo ”

if (eval('' + ('' + '/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords).length) <= 800) {
canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords, '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));
} else {
canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords.replace('&','#'), '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));
}


“; ?>

… as above and with the changed user_of_signature_signature.htm User of Signature Signature inhouse canvas graphic data web application “canvas hoster” …


var thewords=(location.search + location.hash).split('thewords=')[1] ? decodeURIComponent((location.search + location.hash).split('thewords=')[1].split('&')[0]) : "";
if (thewords.indexOf('data') == 0) { thewords=thewords.replace(/\ /g,'+'); }

… to bring “canvas integration” into the mix.


Previous relevant Animated GIF Creation Data Limits via Slide Extraction Tutorial is shown below.

Animated GIF Creation Data Limits via Slide Extraction Tutorial

Animated GIF Creation Data Limits via Slide Extraction Tutorial

Even PHP’s $_POST[] approach to HTML form navigation data sharing has it’s limits, and that can be challenged when considering a whole set of data-URI defined animated GIF slide images.

But, behind the scenes, when $_POST[] does not get filled out with regard to the data limits of the Apache/PHP/MySql (in our case) web server involved, there is still php://input

PHP provides a number of miscellaneous I/O streams that allow access to PHP’s own input and output streams, the standard input, output and error file descriptors, in-memory and disk-backed temporary file streams, and filters that can manipulate other file resources as they are read from and written to.

php://stdin, php://stdout and php://stderr ¶
php://stdin, php://stdout and php://stderr allow direct access to the corresponding input or output stream of the PHP process. The stream references a duplicate file descriptor, so if you open php://stdin and later close it, you close only your copy of the descriptor-the actual stream referenced by STDIN is unaffected. It is recommended that you simply use the constants STDIN, STDOUT and STDERR instead of manually opening streams using these wrappers.

php://stdin is read-only, whereas php://stdout and php://stderr are write-only.

… we can turn to (thanks, PHP), that can save the day in a lot of these scenarios.

The thing is, which our parent HTML and Javascript can help with, we want to be flagging the scenario where we should be checking that php://input usage might be coming into play. Well, even for an HTML form method=POST action=[ourRelevantPHP] scenario, the PHP global $_SERVER[‘QUERY_STRING’] is honoured, shall we say (separate to any $_GET[] ideas, is what we are getting at here). So we can, at the client HTML and Javascript parent (and client) end, set a unique $_SERVER[‘QUERY_STRING’] condition to test for in a changed sixth 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, nuancing yesterday’s Animated GIF Creation Interfacing via Slide Extraction Tutorial


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

… and then, up at that “[ourRelevantPHP]” changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application we can test as per

<?php

if (strpos(('' . $_SERVER['QUERY_STRING']), '=numfillin') !== false && !isset($_POST['numfillin']) && !isset($_GET['numfillin'])) {
$fp = fopen("php://input", "r");
$post = "" . file_get_contents("php://input");
fclose($fp);
$prefdelim='?';
$pairings=[];
//file_put_contents('yes.yes', substr($post,0,300));
if (strpos($post, '=') !== false && strpos($post, '?') === false) {
$pairings=explode('=', ('?' . $post));
} else if (strpos($post, '=') !== false) {
$pairings=explode('=', ('' . $post));
}
if (strpos($post, '=') !== false) { // && strpos($post, '?') !== false) {
$post='';
//file_put_contents('yesagain.yes', '' . sizeof($pairings));
for ($ipairings=1; $ipairings<sizeof($pairings); $ipairings++) {
$thisval=explode('&', $pairings[$ipairings])[0];
$thisname=explode($prefdelim, $pairings[-1 + $ipairings])[1];
if (strpos(('~' . $thisval), '~data') !== false) {
$_POST[$thisname]=$thisval;
} else {
$_POST[$thisname]=$thisval;
}
if (strpos($thisname, 'slideshow') !== false) {
//file_put_contents('yes_yet_again.yes', '' . $thisname . ' ' . strlen($thisval));
}
//file_put_contents('yes_again.yes', '' . $thisname . ' ' . strlen($thisval));
$prefdelim='&';
}
$pairings=[];
}
}
$post='';

if (isset($_GET['numfillin'])) { $numfillin=$_GET['numfillin']; }
if (isset($_POST['numfillin'])) { $numfillin=$_POST['numfillin']; }

$nonplus=' ';
$theplus='+';
if ($numfillin >= 2) {
if (isset($_GET['numfillin'])) {
$numfillin=$_GET['numfillin'];
if (isset($_GET['slideshow'])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$preurl=str_replace($nonplus,$theplus,urldecode($_GET['slideshow']));
}
$nonplus=' ';
$theplus='+';
if (isset($_GET['slideshow2'])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow2']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_GET['slideshow2'])) . '"',$twopattern);
} else {
$bigfillin=$twopattern;
}
} else if (isset($_POST['numfillin'])) {
$numfillin=$_POST['numfillin'];
if (isset($_POST['slideshow'])) {
//file_put_contents('yes_slideshow_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$preurl=str_replace($nonplus,$theplus,urldecode($_POST['slideshow']));
}
if (isset($_POST['slideshow2'])) {
//file_put_contents('yes_slideshow2_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow2']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_POST['slideshow2'])) . '"',$twopattern);
} else {
$bigfillin=$twopattern;
}
}
$nonplus=' ';
$theplus='+';
for ($ijh=3; $ijh<=$numfillin; $ijh++) {
$pretwopattern='<div id="fdiv' . $ijh . '">';
if (isset($_GET['slideshow' . $ijh])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow' . $ijh]),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_GET['slideshow' . $ijh])) . '"',str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern))))) . $posttwopattern . '</div>', $bigfillin);
} else if (isset($_POST['slideshow' . $ijh])) {
//file_put_contents('yes_slideshow' . $ijh . '_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow' . $ijh]),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_POST['slideshow' . $ijh])) . '"',str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern))))) . $posttwopattern . '</div>', $bigfillin);
} else {
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern)))) . $posttwopattern . '</div>', $bigfillin);
}
$nonplus=' ';
$theplus='+';
if ($ijh == $numfillin) {
$ijh++;
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern)))) . $posttwopattern . '</div>', $bigfillin);
}
}
}

?>

… to cater for more scenarios, we’re hoping!


Previous relevant Animated GIF Creation Interfacing via Slide Extraction Tutorial is shown below.

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.


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.

Posted in Ajax, eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Animated GIF Slide Extraction Speed Test Tutorial

Animated GIF Slide Extraction Speed Test Tutorial

Animated GIF Slide Extraction Speed Test Tutorial

Yesterday’s Animated GIF Slide Extraction User Experience Tutorial sparked our interest in that …

  • we wondered whether hashtag components appended to ($_GET) address bar URLs perhaps consisting of ? and & argument parts slowed things down … and after first considering some standalone arrangement …
  • we realized we have quite good conditions with our current Animated GIF Extraction web application project predilections to adapt it

Getting into the coding of this we realized we were touching on another unknown to us. Is a hashtag call such as …


./agtoslides.php?slidenumber=1&random=56476858765876&delay=400&title=%2E%2Fuser_of_ss.gif&numfillin=3#agname=%2E%2Fuser_of_ss.gif

… to PHP going to register the hashtagging? Well, certainly not with PHP functionality but a client facing document.body onload event logic can see it …

<?php

// agtoslides.php
// RJM Programming
// May, 2024
// Animated GIF to a slide via ... ksh agtoslides.ksh [animatedGIFfilename] [slideNumber]
ini_set('max_execution_time', 60000);

$outp='';
$infl='';
$infill='';
$preoutp='';
$postoutp='';

if (file_exists('/tmp/agtoslides')) {
if (file_exists(rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh')) {
if (isset($argc) && !isset($_GET['agname']) && !isset($_POST['agname'])) {
$infl=str_replace('+',' ',$argv[1]);
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($argv[1]));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
} else if (!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
}
if ($argc > 2) {
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($argv[2]))) . ' ' . $infill;
} else {
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else {
if (isset($_GET['random']) && !isset($_GET['agname'])) {
echo "<html>
<head>
<scrip" . "t type=text/javascript>
var jjjxhr=null, jjjform=null, astr='', stats=0;

function joneslidedu() {
if (jjjxhr.readyState == 4) {
if (jjjxhr.status == 200) {
parent.window.opener.timingshashpush((new Date()).getTime()); // document.body.innerHTML=jjjxhr.responseText.split(jjjxhr.responseText.substring(1).split('>')[0])[1].split('</body>')[0];
stats=jjjxhr.status;
}
}
}

function ajaxit() {
if (1 == 1) {
parent.setstats(1);
jjjform = new FormData();
jjjxhr = new XMLHttpRequest();
jjjform.append('agname', decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]));
jjjform.append('random', decodeURIComponent('" . $_GET['random'] . "'));
jjjform.append('slidenumber', decodeURIComponent('" . $_GET['slidenumber'] . "'));
jjjxhr.open('post', './agtoslides.php', true);
jjjxhr.onreadystatechange = joneslidedu;
jjjxhr.send(jjjform);
if (parent.window.opener.setstats) {
parent.window.opener.setstats(1);
}
parent.window.opener.document.getElementById('spareagname').value=decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]);
//alert(parent.window.opener.document.getElementById('sparemyform').outerHTML.length);
if (eval('' + parent.window.opener.document.getElementById('sparemyform').outerHTML.length) < 1000) {
parent.window.opener.document.getElementById('sparemyform').method='GET';
} else {
parent.window.opener.document.getElementById('sparemyform').method='POST';
}
parent.window.opener.document.getElementById('sparemyform').action=('' + parent.document.getElementById('sparemyform').action).split('#')[0];
parent.window.opener.document.getElementById('sparemysub').click();
if (1 == 11) {
//parent.getto().document.title='yes';
while (('' + parent.getto().getstats()) != '200') {
if (astr == '' || eval('' + astr.length) > 800) {
astr=' ';
} else {
astr+=' ';
}
}
}
} else {
jjjform = new FormData();
jjjxhr = new XMLHttpRequest();
jjjform.append('agname', decodeURIComponent(('' + location.hash).split('agname=')[1].split('&')[0].split('#')[0]));
jjjform.append('random', decodeURIComponent('" . $_GET['random'] . "'));
jjjform.append('slidenumber', decodeURIComponent('" . $_GET['slidenumber'] . "'));
jjjxhr.open('post', './agtoslides.php', true);
jjjxhr.onreadystatechange = joneslidedu;
jjjxhr.send(jjjform);
while (stats != 200) {
if (astr == '' || eval('' + astr.length) > 800) {
astr=' ';
} else {
astr+=' ';
}
}
}
return true;
}

</scr" . "ipt>
</head>
<body onload='return ajaxit();' id=xbody></body></html>
";
exit;
}
if (isset($_GET['agname'])) {
if (isset($_GET['random'])) {
$infill=trim(str_replace('+',' ',urldecode($_GET['random']))) . ' tidyhere';
}
$infl=str_replace(' ','+',urldecode($_GET['agname']));
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($_GET['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
} else if (strpos($infl, $_SERVER['SERVER_NAME']) === false && strpos($infl, 'http') !== false) {
$infl=str_replace(' ','+',urldecode($_GET['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), file_get_contents(str_replace('https:','http:',$infl)) );
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
}
if ((!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) && strpos($infl, 'data:image/') === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
}
if (isset($_GET['slidenumber'])) {
//echo 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber']));
//exit;
//file_put_contents('xget.xxx', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_GET['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
//echo ' --- ' . $outp;
//exit;
} else {
//file_put_contents('xget.zzz', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else if (isset($_POST['agname'])) {
if (isset($_POST['random'])) {
$infill=trim(str_replace('+',' ',urldecode($_POST['random']))) . ' tidyhere';
}
$infl=str_replace(' ','+',urldecode($_POST['agname']));
if (strpos($infl, 'data:image/') !== false) {
$infl=str_replace(' ','+',urldecode($_POST['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
//if (strlen($infl) != 0) {
//file_put_contents('x.xx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
} else if (strpos($infl, $_SERVER['SERVER_NAME']) === false && strpos($infl, 'http') !== false) {
$infl=str_replace(' ','+',urldecode($_POST['agname']));
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), file_get_contents(str_replace('https:','http:',$infl)) );
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
//if (strlen($infl) != 0) {
//file_put_contents('x.xxxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
// } else {
//file_put_contents('x.xxxxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
}
if ((!file_exists($infl) || strpos($infl, DIRECTORY_SEPARATOR) === false) && strpos($infl, 'data:image/') === false) {
$infl=rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $infl;
//if (strlen($infl) != 0) {
//file_put_contents('x.xxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
//}
}
if (isset($_POST['slidenumber'])) {
//file_put_contents('xpost.xxx', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_POST['slidenumber'])) . ' ' . $infill . ' 2> ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.err');
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . str_replace('+',' ',urldecode($_POST['slidenumber'])) . ' ' . $infill);
} else {
//file_put_contents('xpost.zzz', 'ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' 1' . ' ' . $infill);
}
} else {
$fp = fopen("php://input", "r");
$post = "" . file_get_contents("php://input");
fclose($fp);
if (strpos($post, "agname=") !== false && strpos($post, "random=") !== false && strpos($post, "slidenumber=") !== false) {
$infill=explode('&', explode('random=', $post)[1])[0] . ' tidyhere';
$sn=explode('&', explode('slidenumber=', $post)[1])[0];
$infl=str_replace(' ','+',urldecode(explode('&', explode('agname=', $post)[1])[0]));
if (strpos($infl, 'data:image/') !== false) {
file_put_contents('/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]), base64_decode(explode(';base64,', $infl )[1] ));
$infl='/tmp/agtoslides/xx' . explode(' ',$infill)[0] . '_xx.' . str_replace('jpeg','jpg',explode(';',explode('/', $infl )[1])[0]);
}
//file_put_contents('x.xxx', $infl . ' ' . shell_exec('ls -l /tmp/agtoslides/*.*'));
$outp=shell_exec('ksh ' . rtrim(dirname(__FILE__), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . 'agtoslides.ksh ' . $infl . ' ' . $sn . ' ' . $infill);
}
}
}
}
}
$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;

?>

… we found, to our relief! And though the synchronization is not exact, we simulate “apples for apples” via that Ajax asynchronicity timing for a hashtag call for the “window.open” window, versus the “window.opener” window non-hashtag call of that default animated GIF (like a splash page example) as you enter the web application.

Codewise we have …


Previous relevant Animated GIF Slide Extraction User Experience Tutorial is shown below.

Animated GIF Slide Extraction User Experience Tutorial

Animated GIF Slide Extraction User Experience Tutorial

We often equate the term “user experience” with “niceties”, in that we often find we deal with “user experience” issues well into a project, but you can put more effort into forward design planning so that you deal with it better throughout the project. We found with the Animated GIF Slide Extraction project of yesterday’s Animated GIF Creation Canvas Integration via Slide Extraction Tutorial that issues that had annoyed us for several days past, but which did not stop the web application working, turned into a day where we felt that we were improving the “user experience” by “fixing annoyances” and “adding niceties”, today. As you might imagine, this can be subjective, because just because we think an idea is an improvement does not mean every user out there will think so, and this is where time set aside for real users to try a product (ie. user acceptance testing) ahead of “going live” can be a great idea.

Anyway, there was …

  • an annoyance, on non-mobile, we first introduced when we integrated Animated GIF Creation in with Animated GIF Slide Extraction a couple of days ago … too much cursor:progress; usage … and in fixing we were astonished that cursor:wait; displays the same graphics … anyway, we think it helps when a cursor can help a user get used to identifying wherein the workflow they are situated at any given time …
    <?php echo ”

    function cursorcheck(defisidea) {
    if (window.parent) { if (parent.document.getElementById('cursorchoice')) { if (parent.document.getElementById('cursorchoice').value != '') { return parent.document.getElementById('cursorchoice').value; } } }
    return defisidea;
    }

    “; ?>
    … looking to parent …

    <input data-choice='' type=hidden value='help' id='cursorchoice'></input>
  • we felt better adding <hr> horizontal rule elements above and below the middle HTML iframe we set aside for client browsing functionality … and also …
  • made that iframe less wide enabling us to place to the right of it a hashtag navigational “a” link back up to the top …

    <hr>
    <iframe onload=pcheckit(this); style='display:inline-block;width:80%;height:160px;' id=myifthree src='/PHP/read_exif_off_image_rotate.php#itwo'></iframe> <a id=atotop style='display:inline-block;vertical-align:top;width:15%;text-shadow: -1px 1px 1px #952dff;' onclick="window.scrollTo(0,0);" href='#mydet'>&#11014; Top</a>
    <hr>

    … and …
  • given a background indicative of the goings on with the extracted animated GIF slide …

    function ob(tv) {
    if (tv == '' && intc != '') {
    tv=intc;
    document.getElementById('agname').value=intc;
    document.getElementById('mygimage').src=intc;
    document.getElementById('atotop').style.backgroundImage='linear-gradient(rgba(255,255,255,0.2),rgba(255,255,255,0.2)),URL(' + intc + ')';
    document.getElementById('atotop').style.backgroundSize='contain';
    document.getElementById('atotop').style.backgroundRepeat='no-repeat';

    if (window.parent) {
    if (window.parent != window.self) {
    parent.document.getElementById('myta').setAttribute('data-img', document.getElementById('myta').getAttribute('data-img'));
    parent.document.getElementById('myta').title=document.getElementById('myta').title;
    parent.document.getElementById('agname').value=intc;
    parent.document.getElementById('mygimage').src=intc;
    parent.document.getElementById('atotop').style.backgroundImage='linear-gradient(rgba(255,255,255,0.2),rgba(255,255,255,0.2)),URL(' + intc + ')';
    parent.document.getElementById('atotop').style.backgroundSize='contain';
    parent.document.getElementById('atotop').style.backgroundRepeat='no-repeat';

    parent.document.getElementById('agname').value=intc;
    parent.document.getElementById('mygimage').title='Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...';
    parent.document.getElementById('mysum').innerHTML=appbut('Animated GIF Slide Extraction Display ... RJM Programming - May, 2024 ... Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...');
    parent.document.getElementById('slidenumber').value='' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij));
    parent.unsetit();
    }
    }
    //tv=gifurl;
    ij=0;
    setTimeout(function(){ intc=''; }, 27000);
    }
    if (tv.trim() != '') {
    if (tv.indexOf('data') != 0 && tv.indexOf('//') != -1 && document.URL.indexOf('//') != -1) {
    if (tv.split('//')[1].split('/')[0].toLowerCase().replace(/^www\./g,'') != document.URL.split('//')[1].split('/')[0].toLowerCase().replace(/^www\./g,'')) {
    document.getElementById('myiffour').src='/getex.php?dodu=y&url=' + encodeURIComponent(tv); //window.open('/getex.php?dodu=y&url=' + encodeURIComponent(tv), '_blank');
    } else {
    prefetch(tv);
    }
    } else {
    prefetch(tv);
    }
    }
    }

    … and …
  • should the user click one (of the now two, and colour coded, as below) Animated GIF Creation action buttons now presented in our “reveal” details/summary the scrolling now lands

    function appittwo(iob) {
    if (('' + document.getElementById('agmode').getAttribute('data-mode')) != '') {
    document.getElementById('agmode').setAttribute('data-mode', '');
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    } else {
    document.getElementById('agmode').setAttribute('data-mode', 'rcmysubmit');
    document.getElementById('cursorchoice').setAttribute('data-choice', 'rcmysubmit');
    document.getElementById('cursorchoice').value='copy';
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    if (document.getElementById('followxthrough')) {
    document.getElementById('followxthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    }
    document.getElementById('agmode').style.display='none';
    document.getElementById('agmodetwo').style.display='none';
    document.getElementById('agmodethree').style.display='none';
    setTimeout(function(){ document.getElementById('myifthree').scrollIntoView(); }, 8000); //location.href='#myifthree';
    }
    }

    function appit(iob) {
    if (('' + document.getElementById('agmode').getAttribute('data-mode')) != '') {
    document.getElementById('agmode').setAttribute('data-mode', '');
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    } else {
    document.getElementById('agmode').setAttribute('data-mode', 'mysubmit');
    document.getElementById('cursorchoice').setAttribute('data-choice', 'mysubmit');
    document.getElementById('cursorchoice').value='copy';
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    if (document.getElementById('followxthrough')) {
    document.getElementById('followxthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    }
    document.getElementById('agmode').style.display='none';
    document.getElementById('agmodetwo').style.display='none';
    document.getElementById('agmodethree').style.display='none';
    setTimeout(function(){ document.getElementById('myifthree').scrollIntoView(); }, 8000); //location.href='#myifthree';
    }
    }

    … at the top of that middle iframe which is short enough so it and the Animated GIF Creation iframe are viewable on many platforms, those button presses created personalized animated GIFs there and then (at least on non-mobile), the user there to see that happening … where …
  • the user clicking the buttons up the top or down the bottom regarding Animate GIF Creation work for the two “submit” button modes can see which one was pressed via new border:5px dotted yellow; styling …
    <?php

    $indone="youllneverfindthis";
    $outdone="youllneverfindthis";


    if (isset($_POST['followthrough']) || isset($_GET['followthrough'])) {
    if (isset($_POST['followthrough'])) {
    if (strlen($_POST['followthrough']) > 0) {
    $indone='#' . $_POST['followthrough'] . " { ba";
    $outdone='#' . $_POST['followthrough'] . " { border:5px dotted yellow; ba";

    if ($_POST['followthrough'] == 'overlayit') {
    $smallfillin="\n setTimeout(function(){ overlaythem(); }, 8000); \n document.getElementById('" . $_POST['followthrough'] . "').style.border='4px dotted pink'; \n";
    } else {
    $smallfillin="\n document.getElementById('" . $_POST['followthrough'] . "').style.border='4px dotted pink'; \n setTimeout(function(){ document.getElementById('" . $_POST['followthrough'] . "').click(); }, 5000); \n";
    }
    }
    } else if (isset($_GET['followthrough'])) {
    if (strlen($_GET['followthrough']) > 0) {
    $indone='#' . $_GET['followthrough'] . " { ba";
    $outdone='#' . $_GET['followthrough'] . " { border:5px dotted yellow; ba";

    if ($_GET['followthrough'] == 'overlayit') {
    $smallfillin="\n setTimeout(function(){ overlaythem(); }, 8000); \n document.getElementById('" . $_GET['followthrough'] . "').style.border='4px dotted pink'; \n";
    } else {
    $smallfillin="\n document.getElementById('" . $_GET['followthrough'] . "').style.border='4px dotted pink'; \n setTimeout(function(){ document.getElementById('" . $_GET['followthrough'] . "').click(); }, 5000); \n";
    }
    }
    }
    }

    ?>
    applied

    <?php echo ”

    <style>
    input[type=submit]:active {
    border: 5px dotted yellow;
    }
    a { padding: 5px 5px 5px 5px; margin: 5px 5px 5px 5px; border: 1px solid red; background-color: #f0f0f0; }
    ::placeholder {
    font-size: 9px;
    }
    ::-webkit-input-placeholder { /* Chrome/Opera/Safari */
    font-size: 9px;
    }
    ::-moz-placeholder { /* Firefox 19+ */
    font-size: 9px;
    }
    :-ms-input-placeholder { /* IE 10+ */
    font-size: 9px;
    }
    :-moz-placeholder { /* Firefox 18- */
    font-size: 9px;
    }" . str_replace($indone, $outdone, "
    #mysubmit { background-color: #98FB98; }
    #rcmysubmit { background-color: #AFEEEE; }
    #overlayit { background-color: #FADADD; }
    #imsel { background-color: cyan; }
    #jmsel { background-color: magenta; }
    #watermarkmode { background-color: olive; }
    #selwhs { background-color: teal; }
    #sfilteris { background-color: lightgreen; } ") . "
    </style>

    “; ?>
    to the relevant bottom button

Codewise we have …


Previous relevant Animated GIF Creation Canvas Integration via Slide Extraction Tutorial is shown below.

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Thinking about yesterday’s Animated GIF Creation Data Limits via Slide Extraction Tutorial‘s progress …

What about if the user is happy to use those filled in animated GIF slide textboxes (with delay and title) to create a user created (and downloadable) animated GIF there and then?

Well, we know that user could click their own presented button, but we wanted to flag it up at the parent ahead of time too, in terms of clarity in the changed seventh 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.

So, what’s all this got to do with an HTML canvas element (in case we have readers who take notice of the nuances of blog posting titles, that is)? Well, once you reach the stage with our inhouse Animated GIF Creator web application, where it has created your own animated GIF image, there is an “onclick” subsection of functionality that, in our new scenario, suffered from an error 404 (Bad Request) because the codeline ran as …

<?php echo ”

canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords, '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));

“; ?>

… but got that error because variable useyourwords contains an animated GIF “first slide” data-URI (useful in that a [canvasContext].drawImage() call of it would do what “drawImage” does with animated GIFs anyway (going back to the original point regarding this whole thread of blog postings)) which caused an overshoot of data size limits on conventional ($_GET style) address bar URLs (perhaps involving ? and & arguments (whether they be five minute or ten minute ones)). But regular readers will know, for a happy couple of months now, we recognize we do not always have to call into play serverside PHP and its $_POST mechanisms here, because we can also call on our life changing hashtagging (ie. #) (clientside approach for HTML/Javascript/CSS webpage) ideas now! Yay!!!!! And so, it came to pass, that … yes … there was light on yonder hilland vale … whatever that is … as “we broke bread” … shall we say … let’s … with some new hashtagging code in the changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application

<?php echo ”

if (eval('' + ('' + '/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords).length) <= 800) {
canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords, '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));
} else {
canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords.replace('&','#'), '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));
}


“; ?>

… as above and with the changed user_of_signature_signature.htm User of Signature Signature inhouse canvas graphic data web application “canvas hoster” …


var thewords=(location.search + location.hash).split('thewords=')[1] ? decodeURIComponent((location.search + location.hash).split('thewords=')[1].split('&')[0]) : "";
if (thewords.indexOf('data') == 0) { thewords=thewords.replace(/\ /g,'+'); }

… to bring “canvas integration” into the mix.


Previous relevant Animated GIF Creation Data Limits via Slide Extraction Tutorial is shown below.

Animated GIF Creation Data Limits via Slide Extraction Tutorial

Animated GIF Creation Data Limits via Slide Extraction Tutorial

Even PHP’s $_POST[] approach to HTML form navigation data sharing has it’s limits, and that can be challenged when considering a whole set of data-URI defined animated GIF slide images.

But, behind the scenes, when $_POST[] does not get filled out with regard to the data limits of the Apache/PHP/MySql (in our case) web server involved, there is still php://input

PHP provides a number of miscellaneous I/O streams that allow access to PHP’s own input and output streams, the standard input, output and error file descriptors, in-memory and disk-backed temporary file streams, and filters that can manipulate other file resources as they are read from and written to.

php://stdin, php://stdout and php://stderr ¶
php://stdin, php://stdout and php://stderr allow direct access to the corresponding input or output stream of the PHP process. The stream references a duplicate file descriptor, so if you open php://stdin and later close it, you close only your copy of the descriptor-the actual stream referenced by STDIN is unaffected. It is recommended that you simply use the constants STDIN, STDOUT and STDERR instead of manually opening streams using these wrappers.

php://stdin is read-only, whereas php://stdout and php://stderr are write-only.

… we can turn to (thanks, PHP), that can save the day in a lot of these scenarios.

The thing is, which our parent HTML and Javascript can help with, we want to be flagging the scenario where we should be checking that php://input usage might be coming into play. Well, even for an HTML form method=POST action=[ourRelevantPHP] scenario, the PHP global $_SERVER[‘QUERY_STRING’] is honoured, shall we say (separate to any $_GET[] ideas, is what we are getting at here). So we can, at the client HTML and Javascript parent (and client) end, set a unique $_SERVER[‘QUERY_STRING’] condition to test for in a changed sixth 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, nuancing yesterday’s Animated GIF Creation Interfacing via Slide Extraction Tutorial


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

… and then, up at that “[ourRelevantPHP]” changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application we can test as per

<?php

if (strpos(('' . $_SERVER['QUERY_STRING']), '=numfillin') !== false && !isset($_POST['numfillin']) && !isset($_GET['numfillin'])) {
$fp = fopen("php://input", "r");
$post = "" . file_get_contents("php://input");
fclose($fp);
$prefdelim='?';
$pairings=[];
//file_put_contents('yes.yes', substr($post,0,300));
if (strpos($post, '=') !== false && strpos($post, '?') === false) {
$pairings=explode('=', ('?' . $post));
} else if (strpos($post, '=') !== false) {
$pairings=explode('=', ('' . $post));
}
if (strpos($post, '=') !== false) { // && strpos($post, '?') !== false) {
$post='';
//file_put_contents('yesagain.yes', '' . sizeof($pairings));
for ($ipairings=1; $ipairings<sizeof($pairings); $ipairings++) {
$thisval=explode('&', $pairings[$ipairings])[0];
$thisname=explode($prefdelim, $pairings[-1 + $ipairings])[1];
if (strpos(('~' . $thisval), '~data') !== false) {
$_POST[$thisname]=$thisval;
} else {
$_POST[$thisname]=$thisval;
}
if (strpos($thisname, 'slideshow') !== false) {
//file_put_contents('yes_yet_again.yes', '' . $thisname . ' ' . strlen($thisval));
}
//file_put_contents('yes_again.yes', '' . $thisname . ' ' . strlen($thisval));
$prefdelim='&';
}
$pairings=[];
}
}
$post='';

if (isset($_GET['numfillin'])) { $numfillin=$_GET['numfillin']; }
if (isset($_POST['numfillin'])) { $numfillin=$_POST['numfillin']; }

$nonplus=' ';
$theplus='+';
if ($numfillin >= 2) {
if (isset($_GET['numfillin'])) {
$numfillin=$_GET['numfillin'];
if (isset($_GET['slideshow'])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$preurl=str_replace($nonplus,$theplus,urldecode($_GET['slideshow']));
}
$nonplus=' ';
$theplus='+';
if (isset($_GET['slideshow2'])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow2']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_GET['slideshow2'])) . '"',$twopattern);
} else {
$bigfillin=$twopattern;
}
} else if (isset($_POST['numfillin'])) {
$numfillin=$_POST['numfillin'];
if (isset($_POST['slideshow'])) {
//file_put_contents('yes_slideshow_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$preurl=str_replace($nonplus,$theplus,urldecode($_POST['slideshow']));
}
if (isset($_POST['slideshow2'])) {
//file_put_contents('yes_slideshow2_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow2']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_POST['slideshow2'])) . '"',$twopattern);
} else {
$bigfillin=$twopattern;
}
}
$nonplus=' ';
$theplus='+';
for ($ijh=3; $ijh<=$numfillin; $ijh++) {
$pretwopattern='<div id="fdiv' . $ijh . '">';
if (isset($_GET['slideshow' . $ijh])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow' . $ijh]),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_GET['slideshow' . $ijh])) . '"',str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern))))) . $posttwopattern . '</div>', $bigfillin);
} else if (isset($_POST['slideshow' . $ijh])) {
//file_put_contents('yes_slideshow' . $ijh . '_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow' . $ijh]),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_POST['slideshow' . $ijh])) . '"',str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern))))) . $posttwopattern . '</div>', $bigfillin);
} else {
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern)))) . $posttwopattern . '</div>', $bigfillin);
}
$nonplus=' ';
$theplus='+';
if ($ijh == $numfillin) {
$ijh++;
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern)))) . $posttwopattern . '</div>', $bigfillin);
}
}
}

?>

… to cater for more scenarios, we’re hoping!


Previous relevant Animated GIF Creation Interfacing via Slide Extraction Tutorial is shown below.

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.


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.

Posted in Ajax, eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Animated GIF Slide Extraction User Experience Tutorial

Animated GIF Slide Extraction User Experience Tutorial

Animated GIF Slide Extraction User Experience Tutorial

We often equate the term “user experience” with “niceties”, in that we often find we deal with “user experience” issues well into a project, but you can put more effort into forward design planning so that you deal with it better throughout the project. We found with the Animated GIF Slide Extraction project of yesterday’s Animated GIF Creation Canvas Integration via Slide Extraction Tutorial that issues that had annoyed us for several days past, but which did not stop the web application working, turned into a day where we felt that we were improving the “user experience” by “fixing annoyances” and “adding niceties”, today. As you might imagine, this can be subjective, because just because we think an idea is an improvement does not mean every user out there will think so, and this is where time set aside for real users to try a product (ie. user acceptance testing) ahead of “going live” can be a great idea.

Anyway, there was …

  • an annoyance, on non-mobile, we first introduced when we integrated Animated GIF Creation in with Animated GIF Slide Extraction a couple of days ago … too much cursor:progress; usage … and in fixing we were astonished that cursor:wait; displays the same graphics … anyway, we think it helps when a cursor can help a user get used to identifying wherein the workflow they are situated at any given time …
    <?php echo ”

    function cursorcheck(defisidea) {
    if (window.parent) { if (parent.document.getElementById('cursorchoice')) { if (parent.document.getElementById('cursorchoice').value != '') { return parent.document.getElementById('cursorchoice').value; } } }
    return defisidea;
    }

    “; ?>
    … looking to parent …

    <input data-choice='' type=hidden value='help' id='cursorchoice'></input>
  • we felt better adding <hr> horizontal rule elements above and below the middle HTML iframe we set aside for client browsing functionality … and also …
  • made that iframe less wide enabling us to place to the right of it a hashtag navigational “a” link back up to the top …

    <hr>
    <iframe onload=pcheckit(this); style='display:inline-block;width:80%;height:160px;' id=myifthree src='/PHP/read_exif_off_image_rotate.php#itwo'></iframe> <a id=atotop style='display:inline-block;vertical-align:top;width:15%;text-shadow: -1px 1px 1px #952dff;' onclick="window.scrollTo(0,0);" href='#mydet'>&#11014; Top</a>
    <hr>

    … and …
  • given a background indicative of the goings on with the extracted animated GIF slide …

    function ob(tv) {
    if (tv == '' && intc != '') {
    tv=intc;
    document.getElementById('agname').value=intc;
    document.getElementById('mygimage').src=intc;
    document.getElementById('atotop').style.backgroundImage='linear-gradient(rgba(255,255,255,0.2),rgba(255,255,255,0.2)),URL(' + intc + ')';
    document.getElementById('atotop').style.backgroundSize='contain';
    document.getElementById('atotop').style.backgroundRepeat='no-repeat';

    if (window.parent) {
    if (window.parent != window.self) {
    parent.document.getElementById('myta').setAttribute('data-img', document.getElementById('myta').getAttribute('data-img'));
    parent.document.getElementById('myta').title=document.getElementById('myta').title;
    parent.document.getElementById('agname').value=intc;
    parent.document.getElementById('mygimage').src=intc;
    parent.document.getElementById('atotop').style.backgroundImage='linear-gradient(rgba(255,255,255,0.2),rgba(255,255,255,0.2)),URL(' + intc + ')';
    parent.document.getElementById('atotop').style.backgroundSize='contain';
    parent.document.getElementById('atotop').style.backgroundRepeat='no-repeat';

    parent.document.getElementById('agname').value=intc;
    parent.document.getElementById('mygimage').title='Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...';
    parent.document.getElementById('mysum').innerHTML=appbut('Animated GIF Slide Extraction Display ... RJM Programming - May, 2024 ... Finding slide ' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij)) + ' of ' + ij + ' ... please wait ...');
    parent.document.getElementById('slidenumber').value='' + eval(1 + eval(eval(-1 + eval('' + gifloc.replace('%',''))) % ij));
    parent.unsetit();
    }
    }
    //tv=gifurl;
    ij=0;
    setTimeout(function(){ intc=''; }, 27000);
    }
    if (tv.trim() != '') {
    if (tv.indexOf('data') != 0 && tv.indexOf('//') != -1 && document.URL.indexOf('//') != -1) {
    if (tv.split('//')[1].split('/')[0].toLowerCase().replace(/^www\./g,'') != document.URL.split('//')[1].split('/')[0].toLowerCase().replace(/^www\./g,'')) {
    document.getElementById('myiffour').src='/getex.php?dodu=y&url=' + encodeURIComponent(tv); //window.open('/getex.php?dodu=y&url=' + encodeURIComponent(tv), '_blank');
    } else {
    prefetch(tv);
    }
    } else {
    prefetch(tv);
    }
    }
    }

    … and …
  • should the user click one (of the now two, and colour coded, as below) Animated GIF Creation action buttons now presented in our “reveal” details/summary the scrolling now lands

    function appittwo(iob) {
    if (('' + document.getElementById('agmode').getAttribute('data-mode')) != '') {
    document.getElementById('agmode').setAttribute('data-mode', '');
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    } else {
    document.getElementById('agmode').setAttribute('data-mode', 'rcmysubmit');
    document.getElementById('cursorchoice').setAttribute('data-choice', 'rcmysubmit');
    document.getElementById('cursorchoice').value='copy';
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    if (document.getElementById('followxthrough')) {
    document.getElementById('followxthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    }
    document.getElementById('agmode').style.display='none';
    document.getElementById('agmodetwo').style.display='none';
    document.getElementById('agmodethree').style.display='none';
    setTimeout(function(){ document.getElementById('myifthree').scrollIntoView(); }, 8000); //location.href='#myifthree';
    }
    }

    function appit(iob) {
    if (('' + document.getElementById('agmode').getAttribute('data-mode')) != '') {
    document.getElementById('agmode').setAttribute('data-mode', '');
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    } else {
    document.getElementById('agmode').setAttribute('data-mode', 'mysubmit');
    document.getElementById('cursorchoice').setAttribute('data-choice', 'mysubmit');
    document.getElementById('cursorchoice').value='copy';
    document.getElementById('followthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    if (document.getElementById('followxthrough')) {
    document.getElementById('followxthrough').value=('' + document.getElementById('agmode').getAttribute('data-mode'));
    }
    document.getElementById('agmode').style.display='none';
    document.getElementById('agmodetwo').style.display='none';
    document.getElementById('agmodethree').style.display='none';
    setTimeout(function(){ document.getElementById('myifthree').scrollIntoView(); }, 8000); //location.href='#myifthree';
    }
    }

    … at the top of that middle iframe which is short enough so it and the Animated GIF Creation iframe are viewable on many platforms, those button presses created personalized animated GIFs there and then (at least on non-mobile), the user there to see that happening … where …
  • the user clicking the buttons up the top or down the bottom regarding Animate GIF Creation work for the two “submit” button modes can see which one was pressed via new border:5px dotted yellow; styling …
    <?php

    $indone="youllneverfindthis";
    $outdone="youllneverfindthis";


    if (isset($_POST['followthrough']) || isset($_GET['followthrough'])) {
    if (isset($_POST['followthrough'])) {
    if (strlen($_POST['followthrough']) > 0) {
    $indone='#' . $_POST['followthrough'] . " { ba";
    $outdone='#' . $_POST['followthrough'] . " { border:5px dotted yellow; ba";

    if ($_POST['followthrough'] == 'overlayit') {
    $smallfillin="\n setTimeout(function(){ overlaythem(); }, 8000); \n document.getElementById('" . $_POST['followthrough'] . "').style.border='4px dotted pink'; \n";
    } else {
    $smallfillin="\n document.getElementById('" . $_POST['followthrough'] . "').style.border='4px dotted pink'; \n setTimeout(function(){ document.getElementById('" . $_POST['followthrough'] . "').click(); }, 5000); \n";
    }
    }
    } else if (isset($_GET['followthrough'])) {
    if (strlen($_GET['followthrough']) > 0) {
    $indone='#' . $_GET['followthrough'] . " { ba";
    $outdone='#' . $_GET['followthrough'] . " { border:5px dotted yellow; ba";

    if ($_GET['followthrough'] == 'overlayit') {
    $smallfillin="\n setTimeout(function(){ overlaythem(); }, 8000); \n document.getElementById('" . $_GET['followthrough'] . "').style.border='4px dotted pink'; \n";
    } else {
    $smallfillin="\n document.getElementById('" . $_GET['followthrough'] . "').style.border='4px dotted pink'; \n setTimeout(function(){ document.getElementById('" . $_GET['followthrough'] . "').click(); }, 5000); \n";
    }
    }
    }
    }

    ?>
    applied

    <?php echo ”

    <style>
    input[type=submit]:active {
    border: 5px dotted yellow;
    }
    a { padding: 5px 5px 5px 5px; margin: 5px 5px 5px 5px; border: 1px solid red; background-color: #f0f0f0; }
    ::placeholder {
    font-size: 9px;
    }
    ::-webkit-input-placeholder { /* Chrome/Opera/Safari */
    font-size: 9px;
    }
    ::-moz-placeholder { /* Firefox 19+ */
    font-size: 9px;
    }
    :-ms-input-placeholder { /* IE 10+ */
    font-size: 9px;
    }
    :-moz-placeholder { /* Firefox 18- */
    font-size: 9px;
    }" . str_replace($indone, $outdone, "
    #mysubmit { background-color: #98FB98; }
    #rcmysubmit { background-color: #AFEEEE; }
    #overlayit { background-color: #FADADD; }
    #imsel { background-color: cyan; }
    #jmsel { background-color: magenta; }
    #watermarkmode { background-color: olive; }
    #selwhs { background-color: teal; }
    #sfilteris { background-color: lightgreen; } ") . "
    </style>

    “; ?>
    to the relevant bottom button

Codewise we have …


Previous relevant Animated GIF Creation Canvas Integration via Slide Extraction Tutorial is shown below.

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Thinking about yesterday’s Animated GIF Creation Data Limits via Slide Extraction Tutorial‘s progress …

What about if the user is happy to use those filled in animated GIF slide textboxes (with delay and title) to create a user created (and downloadable) animated GIF there and then?

Well, we know that user could click their own presented button, but we wanted to flag it up at the parent ahead of time too, in terms of clarity in the changed seventh 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.

So, what’s all this got to do with an HTML canvas element (in case we have readers who take notice of the nuances of blog posting titles, that is)? Well, once you reach the stage with our inhouse Animated GIF Creator web application, where it has created your own animated GIF image, there is an “onclick” subsection of functionality that, in our new scenario, suffered from an error 404 (Bad Request) because the codeline ran as …

<?php echo ”

canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords, '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));

“; ?>

… but got that error because variable useyourwords contains an animated GIF “first slide” data-URI (useful in that a [canvasContext].drawImage() call of it would do what “drawImage” does with animated GIFs anyway (going back to the original point regarding this whole thread of blog postings)) which caused an overshoot of data size limits on conventional ($_GET style) address bar URLs (perhaps involving ? and & arguments (whether they be five minute or ten minute ones)). But regular readers will know, for a happy couple of months now, we recognize we do not always have to call into play serverside PHP and its $_POST mechanisms here, because we can also call on our life changing hashtagging (ie. #) (clientside approach for HTML/Javascript/CSS webpage) ideas now! Yay!!!!! And so, it came to pass, that … yes … there was light on yonder hilland vale … whatever that is … as “we broke bread” … shall we say … let’s … with some new hashtagging code in the changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application

<?php echo ”

if (eval('' + ('' + '/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords).length) <= 800) {
canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords, '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));
} else {
canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords.replace('&','#'), '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));
}


“; ?>

… as above and with the changed user_of_signature_signature.htm User of Signature Signature inhouse canvas graphic data web application “canvas hoster” …


var thewords=(location.search + location.hash).split('thewords=')[1] ? decodeURIComponent((location.search + location.hash).split('thewords=')[1].split('&')[0]) : "";
if (thewords.indexOf('data') == 0) { thewords=thewords.replace(/\ /g,'+'); }

… to bring “canvas integration” into the mix.


Previous relevant Animated GIF Creation Data Limits via Slide Extraction Tutorial is shown below.

Animated GIF Creation Data Limits via Slide Extraction Tutorial

Animated GIF Creation Data Limits via Slide Extraction Tutorial

Even PHP’s $_POST[] approach to HTML form navigation data sharing has it’s limits, and that can be challenged when considering a whole set of data-URI defined animated GIF slide images.

But, behind the scenes, when $_POST[] does not get filled out with regard to the data limits of the Apache/PHP/MySql (in our case) web server involved, there is still php://input

PHP provides a number of miscellaneous I/O streams that allow access to PHP’s own input and output streams, the standard input, output and error file descriptors, in-memory and disk-backed temporary file streams, and filters that can manipulate other file resources as they are read from and written to.

php://stdin, php://stdout and php://stderr ¶
php://stdin, php://stdout and php://stderr allow direct access to the corresponding input or output stream of the PHP process. The stream references a duplicate file descriptor, so if you open php://stdin and later close it, you close only your copy of the descriptor-the actual stream referenced by STDIN is unaffected. It is recommended that you simply use the constants STDIN, STDOUT and STDERR instead of manually opening streams using these wrappers.

php://stdin is read-only, whereas php://stdout and php://stderr are write-only.

… we can turn to (thanks, PHP), that can save the day in a lot of these scenarios.

The thing is, which our parent HTML and Javascript can help with, we want to be flagging the scenario where we should be checking that php://input usage might be coming into play. Well, even for an HTML form method=POST action=[ourRelevantPHP] scenario, the PHP global $_SERVER[‘QUERY_STRING’] is honoured, shall we say (separate to any $_GET[] ideas, is what we are getting at here). So we can, at the client HTML and Javascript parent (and client) end, set a unique $_SERVER[‘QUERY_STRING’] condition to test for in a changed sixth 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, nuancing yesterday’s Animated GIF Creation Interfacing via Slide Extraction Tutorial


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

… and then, up at that “[ourRelevantPHP]” changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application we can test as per

<?php

if (strpos(('' . $_SERVER['QUERY_STRING']), '=numfillin') !== false && !isset($_POST['numfillin']) && !isset($_GET['numfillin'])) {
$fp = fopen("php://input", "r");
$post = "" . file_get_contents("php://input");
fclose($fp);
$prefdelim='?';
$pairings=[];
//file_put_contents('yes.yes', substr($post,0,300));
if (strpos($post, '=') !== false && strpos($post, '?') === false) {
$pairings=explode('=', ('?' . $post));
} else if (strpos($post, '=') !== false) {
$pairings=explode('=', ('' . $post));
}
if (strpos($post, '=') !== false) { // && strpos($post, '?') !== false) {
$post='';
//file_put_contents('yesagain.yes', '' . sizeof($pairings));
for ($ipairings=1; $ipairings<sizeof($pairings); $ipairings++) {
$thisval=explode('&', $pairings[$ipairings])[0];
$thisname=explode($prefdelim, $pairings[-1 + $ipairings])[1];
if (strpos(('~' . $thisval), '~data') !== false) {
$_POST[$thisname]=$thisval;
} else {
$_POST[$thisname]=$thisval;
}
if (strpos($thisname, 'slideshow') !== false) {
//file_put_contents('yes_yet_again.yes', '' . $thisname . ' ' . strlen($thisval));
}
//file_put_contents('yes_again.yes', '' . $thisname . ' ' . strlen($thisval));
$prefdelim='&';
}
$pairings=[];
}
}
$post='';

if (isset($_GET['numfillin'])) { $numfillin=$_GET['numfillin']; }
if (isset($_POST['numfillin'])) { $numfillin=$_POST['numfillin']; }

$nonplus=' ';
$theplus='+';
if ($numfillin >= 2) {
if (isset($_GET['numfillin'])) {
$numfillin=$_GET['numfillin'];
if (isset($_GET['slideshow'])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$preurl=str_replace($nonplus,$theplus,urldecode($_GET['slideshow']));
}
$nonplus=' ';
$theplus='+';
if (isset($_GET['slideshow2'])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow2']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_GET['slideshow2'])) . '"',$twopattern);
} else {
$bigfillin=$twopattern;
}
} else if (isset($_POST['numfillin'])) {
$numfillin=$_POST['numfillin'];
if (isset($_POST['slideshow'])) {
//file_put_contents('yes_slideshow_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$preurl=str_replace($nonplus,$theplus,urldecode($_POST['slideshow']));
}
if (isset($_POST['slideshow2'])) {
//file_put_contents('yes_slideshow2_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow2']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_POST['slideshow2'])) . '"',$twopattern);
} else {
$bigfillin=$twopattern;
}
}
$nonplus=' ';
$theplus='+';
for ($ijh=3; $ijh<=$numfillin; $ijh++) {
$pretwopattern='<div id="fdiv' . $ijh . '">';
if (isset($_GET['slideshow' . $ijh])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow' . $ijh]),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_GET['slideshow' . $ijh])) . '"',str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern))))) . $posttwopattern . '</div>', $bigfillin);
} else if (isset($_POST['slideshow' . $ijh])) {
//file_put_contents('yes_slideshow' . $ijh . '_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow' . $ijh]),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_POST['slideshow' . $ijh])) . '"',str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern))))) . $posttwopattern . '</div>', $bigfillin);
} else {
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern)))) . $posttwopattern . '</div>', $bigfillin);
}
$nonplus=' ';
$theplus='+';
if ($ijh == $numfillin) {
$ijh++;
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern)))) . $posttwopattern . '</div>', $bigfillin);
}
}
}

?>

… to cater for more scenarios, we’re hoping!


Previous relevant Animated GIF Creation Interfacing via Slide Extraction Tutorial is shown below.

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.


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.

Posted in eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Animated GIF Creation Canvas Integration via Slide Extraction Tutorial

Thinking about yesterday’s Animated GIF Creation Data Limits via Slide Extraction Tutorial‘s progress …

What about if the user is happy to use those filled in animated GIF slide textboxes (with delay and title) to create a user created (and downloadable) animated GIF there and then?

Well, we know that user could click their own presented button, but we wanted to flag it up at the parent ahead of time too, in terms of clarity in the changed seventh 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.

So, what’s all this got to do with an HTML canvas element (in case we have readers who take notice of the nuances of blog posting titles, that is)? Well, once you reach the stage with our inhouse Animated GIF Creator web application, where it has created your own animated GIF image, there is an “onclick” subsection of functionality that, in our new scenario, suffered from an error 404 (Bad Request) because the codeline ran as …

<?php echo ”

canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords, '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));

“; ?>

… but got that error because variable useyourwords contains an animated GIF “first slide” data-URI (useful in that a [canvasContext].drawImage() call of it would do what “drawImage” does with animated GIFs anyway (going back to the original point regarding this whole thread of blog postings)) which caused an overshoot of data size limits on conventional ($_GET style) address bar URLs (perhaps involving ? and & arguments (whether they be five minute or ten minute ones)). But regular readers will know, for a happy couple of months now, we recognize we do not always have to call into play serverside PHP and its $_POST mechanisms here, because we can also call on our life changing hashtagging (ie. #) (clientside approach for HTML/Javascript/CSS webpage) ideas now! Yay!!!!! And so, it came to pass, that … yes … there was light on yonder hilland vale … whatever that is … as “we broke bread” … shall we say … let’s … with some new hashtagging code in the changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application

<?php echo ”

if (eval('' + ('' + '/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords).length) <= 800) {
canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords, '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));
} else {
canvwo.push(window.open('/HTMLCSS/user_of_signature_signature.htm?slide=' + tid.replace(/^slideshow1$/g,'slideshow') + useyourwords.replace('&','#'), '_blank', 'top=' + eval(screen.height - hw) + ',left=' + eval(screen.width - hw) + ',width=' + hw + ',height=' + hw));
}


“; ?>

… as above and with the changed user_of_signature_signature.htm User of Signature Signature inhouse canvas graphic data web application “canvas hoster” …


var thewords=(location.search + location.hash).split('thewords=')[1] ? decodeURIComponent((location.search + location.hash).split('thewords=')[1].split('&')[0]) : "";
if (thewords.indexOf('data') == 0) { thewords=thewords.replace(/\ /g,'+'); }

… to bring “canvas integration” into the mix.


Previous relevant Animated GIF Creation Data Limits via Slide Extraction Tutorial is shown below.

Animated GIF Creation Data Limits via Slide Extraction Tutorial

Animated GIF Creation Data Limits via Slide Extraction Tutorial

Even PHP’s $_POST[] approach to HTML form navigation data sharing has it’s limits, and that can be challenged when considering a whole set of data-URI defined animated GIF slide images.

But, behind the scenes, when $_POST[] does not get filled out with regard to the data limits of the Apache/PHP/MySql (in our case) web server involved, there is still php://input

PHP provides a number of miscellaneous I/O streams that allow access to PHP’s own input and output streams, the standard input, output and error file descriptors, in-memory and disk-backed temporary file streams, and filters that can manipulate other file resources as they are read from and written to.

php://stdin, php://stdout and php://stderr ¶
php://stdin, php://stdout and php://stderr allow direct access to the corresponding input or output stream of the PHP process. The stream references a duplicate file descriptor, so if you open php://stdin and later close it, you close only your copy of the descriptor-the actual stream referenced by STDIN is unaffected. It is recommended that you simply use the constants STDIN, STDOUT and STDERR instead of manually opening streams using these wrappers.

php://stdin is read-only, whereas php://stdout and php://stderr are write-only.

… we can turn to (thanks, PHP), that can save the day in a lot of these scenarios.

The thing is, which our parent HTML and Javascript can help with, we want to be flagging the scenario where we should be checking that php://input usage might be coming into play. Well, even for an HTML form method=POST action=[ourRelevantPHP] scenario, the PHP global $_SERVER[‘QUERY_STRING’] is honoured, shall we say (separate to any $_GET[] ideas, is what we are getting at here). So we can, at the client HTML and Javascript parent (and client) end, set a unique $_SERVER[‘QUERY_STRING’] condition to test for in a changed sixth 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, nuancing yesterday’s Animated GIF Creation Interfacing via Slide Extraction Tutorial


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

… and then, up at that “[ourRelevantPHP]” changed PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application we can test as per

<?php

if (strpos(('' . $_SERVER['QUERY_STRING']), '=numfillin') !== false && !isset($_POST['numfillin']) && !isset($_GET['numfillin'])) {
$fp = fopen("php://input", "r");
$post = "" . file_get_contents("php://input");
fclose($fp);
$prefdelim='?';
$pairings=[];
//file_put_contents('yes.yes', substr($post,0,300));
if (strpos($post, '=') !== false && strpos($post, '?') === false) {
$pairings=explode('=', ('?' . $post));
} else if (strpos($post, '=') !== false) {
$pairings=explode('=', ('' . $post));
}
if (strpos($post, '=') !== false) { // && strpos($post, '?') !== false) {
$post='';
//file_put_contents('yesagain.yes', '' . sizeof($pairings));
for ($ipairings=1; $ipairings<sizeof($pairings); $ipairings++) {
$thisval=explode('&', $pairings[$ipairings])[0];
$thisname=explode($prefdelim, $pairings[-1 + $ipairings])[1];
if (strpos(('~' . $thisval), '~data') !== false) {
$_POST[$thisname]=$thisval;
} else {
$_POST[$thisname]=$thisval;
}
if (strpos($thisname, 'slideshow') !== false) {
//file_put_contents('yes_yet_again.yes', '' . $thisname . ' ' . strlen($thisval));
}
//file_put_contents('yes_again.yes', '' . $thisname . ' ' . strlen($thisval));
$prefdelim='&';
}
$pairings=[];
}
}
$post='';

if (isset($_GET['numfillin'])) { $numfillin=$_GET['numfillin']; }
if (isset($_POST['numfillin'])) { $numfillin=$_POST['numfillin']; }

$nonplus=' ';
$theplus='+';
if ($numfillin >= 2) {
if (isset($_GET['numfillin'])) {
$numfillin=$_GET['numfillin'];
if (isset($_GET['slideshow'])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$preurl=str_replace($nonplus,$theplus,urldecode($_GET['slideshow']));
}
$nonplus=' ';
$theplus='+';
if (isset($_GET['slideshow2'])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow2']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_GET['slideshow2'])) . '"',$twopattern);
} else {
$bigfillin=$twopattern;
}
} else if (isset($_POST['numfillin'])) {
$numfillin=$_POST['numfillin'];
if (isset($_POST['slideshow'])) {
//file_put_contents('yes_slideshow_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$preurl=str_replace($nonplus,$theplus,urldecode($_POST['slideshow']));
}
if (isset($_POST['slideshow2'])) {
//file_put_contents('yes_slideshow2_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow2']),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_POST['slideshow2'])) . '"',$twopattern);
} else {
$bigfillin=$twopattern;
}
}
$nonplus=' ';
$theplus='+';
for ($ijh=3; $ijh<=$numfillin; $ijh++) {
$pretwopattern='<div id="fdiv' . $ijh . '">';
if (isset($_GET['slideshow' . $ijh])) {
if (str_replace('+',' ',substr(urldecode($_GET['slideshow' . $ijh]),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_GET['slideshow' . $ijh])) . '"',str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern))))) . $posttwopattern . '</div>', $bigfillin);
} else if (isset($_POST['slideshow' . $ijh])) {
//file_put_contents('yes_slideshow' . $ijh . '_again.yes', '' . $numfillin);
if (str_replace('+',' ',substr(urldecode($_POST['slideshow' . $ijh]),0,1)) == ' ') { $theplus=' '; $nonplus='+'; }
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace(' value=""',' value="' . str_replace($nonplus,$theplus,urldecode($_POST['slideshow' . $ijh])) . '"',str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern))))) . $posttwopattern . '</div>', $bigfillin);
} else {
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern)))) . $posttwopattern . '</div>', $bigfillin);
}
$nonplus=' ';
$theplus='+';
if ($ijh == $numfillin) {
$ijh++;
$bigfillin=str_replace('<div id="fdiv' . (-1 + $ijh) . '"></div>', '<div id="fdiv' . (-1 + $ijh). '">' . $pretwopattern . str_replace('slideshow2"', 'slideshow' . $ijh . '"', str_replace('<div id="fdiv2"', '<div id="fdiv' . $ijh . '"', str_replace('>2<', '>' . $ijh . '<', str_replace('ours2', 'ours' . $ijh, $twopattern)))) . $posttwopattern . '</div>', $bigfillin);
}
}
}

?>

… to cater for more scenarios, we’re hoping!


Previous relevant Animated GIF Creation Interfacing via Slide Extraction Tutorial is shown below.

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.


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


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

Posted in eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment