Animated GIF Creation Slide Specific Effects Tutorial

Animated GIF Creation Slide Specific Effects Tutorial

Animated GIF Creation Slide Specific Effects Tutorial

With our animated GIF creator, last referenced with Ffmpeg Shelling Peas Tutorial, we wanted to nuance the way the ImageMagick and GD effects could operate …

  • they being only applicable to the entire animated GIF output image … before today’s work which makes it so that …
  • optionally they can be turned on or off for individual animated GIF slides

… thereby allowing more flexibility for the user, we’re hoping.

Feel free to try our changed animated GIF creator PHP tutorial_to_animated_gif.php inhouse animated GIF creator web application which now features the additional “slide blurb additional snippet” …

Please note double click toggles the negation of any GD rotations etcetera for this slide only and will become pale yellow here when in negated status, and that a 4x click on first selection reverses logic to be only 2x click selections from then on for a pale orange slide textbox background.


Previous relevant Ffmpeg Shelling Peas Tutorial is shown below.

Ffmpeg Shelling Peas Tutorial

Ffmpeg Shelling Peas Tutorial

Well, our wish to “shell peas” setting up more ffmpeg media options based on the excellent FFmpeg cheat sheet, thanks, today, had its ups and downs for speed of progress, but, yes, to have a solid “framework” to work within, that you are happy with, barring those tweaks you inevitably discover in projects as they gain complexity, is the best first endeavour you might need to do, to feel more relaxed about the parts of the project requiring that third party expertise, which it is your job to test that you have successfully merged into the project. And so, onto yesterday’s Ffmpeg and Pandoc and ImageMagick and Pdfimages Dropdown Linear Gradient Tutorial, we have included new

<?php

$vssfi='img%03d.png';
$bn='*';
$bntwo='.*';

foreach (glob('newfolder_*') as $idfilename) {
if (file_exists($idfilename) && $vssfi == 'img%03d.png') {
foreach (glob($idfilename . DIRECTORY_SEPARATOR . '*') as $idifilename) {
if ($vssfi == 'img%03d.png' && strpos($idifilename, '.') !== false) {
$bnis=basename($idifilename);
$bn='';
$bntwo='';
for ($ibn=0; $ibn<strlen(explode('.', $bnis)[0]); $ibn++) {
if (substr(substr($bnis, $ibn),0,1) >= '0' && substr(substr($bnis, $ibn),0,1) <= '9') {
if ($bntwo == '') {
if (substr(substr($bnis, $ibn),0,1) == '0') {
$bntwo='%0' . strlen(substr(explode('.', $bnis)[0], $ibn)) . 'd' . '.' . explode('.', $idifilename)[-1 + sizeof(explode('.', $idifilename))];
} else {
$bntwo='%d' . '.' . explode('.', $idifilename)[-1 + sizeof(explode('.', $idifilename))];
}
}
} else if ($bntwo == '') {
$bn.=substr(substr($bnis, $ibn),0,1);
}
}
if ($bntwo == '') {
$bn='*';
$bntwo='.' . explode('.', $idifilename)[-1 + sizeof(explode('.', $idifilename))];
}
$vssfi=$idfilename . substr(DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR,0,1) . $bn . $bntwo;
}
}
}
}

?>
<?php echo ”

var ffstr=' Concat demuxer, Display the frame number on each frame, Trimming, Delay video, Delay audio, Extract a frame per second, Extract the frames from a video, Mute some of the audio, Extract one frame, Create a video slideshow from images,', offstr=null, kffstr=0, affstr=[];

//
// And then ... later ...
//
if (newv == 'Trimming') {


document.getElementById('moreb').innerHTML=firstdivih;

document.getElementById('precmds').innerHTML=' ';
document.getElementById('secondi').innerHTML='';
document.getElementById('minusi').innerHTML=' -ss 00:00:00.000 -i ';
document.getElementById('minusi').title='Start time';

document.getElementById('sswitches').innerHTML='-t 60 -c copy ';
document.getElementById('sswitches').title='Duration';

document.getElementById('mysub').value=newv;
} else if (newv == 'Delay video') {

document.getElementById('moreb').innerHTML=firstdivih;
document.getElementById('precmds').innerHTML=' ';

document.getElementById('betweenis').innerHTML='-itsoffset 1.00';
document.getElementById('betweenis').title='Delay in seconds';

document.getElementById('sswitches').innerHTML='-map 1:v -map 0:a <span id=svac contenteditable=false>-vcodec copy -acodec copy </span>';
document.getElementById('sswitches').title='The 1:v 0:a represents video track else use 0:v 1:a for audio track';

document.getElementById('mysub').value=newv;
} else if (newv == 'Delay audio') {

document.getElementById('moreb').innerHTML=firstdivih;
document.getElementById('precmds').innerHTML=' ';

document.getElementById('betweenis').innerHTML='-itsoffset 1.00';
document.getElementById('betweenis').title='Delay in seconds';

document.getElementById('sswitches').innerHTML='-map 0:v -map 1:a <span id=svac contenteditable=false>-vcodec copy -acodec copy </span>';
document.getElementById('sswitches').title='The 0:v 1:a represents audio track else use 1:v 0:a for video track';

document.getElementById('mysub').value=newv;
} else if (newv == 'Extract a frame per second') {

document.getElementById('moreb').innerHTML=firstdivih.replace(' out.mp4',' ');
document.getElementById('precmds').innerHTML=' ';
document.getElementById('secondi').innerHTML='-filter:v fps=fps=1 -vsync 0';
document.getElementById('secondi').title='The 1 represents 1 per second';
document.getElementById('sswitches').innerHTML=\"<span id=sfolder contenteditable=false>newfolder_" . rand(0,784534) . str_replace("\\","\\\\",$ddn) . "out%d.png\" + '</span>';

document.getElementById('mysub').value=newv;
} else if (newv == 'Extract the frames from a video') {

document.getElementById('moreb').innerHTML=firstdivih.replace(' out.mp4',' ');
document.getElementById('precmds').innerHTML=' ';
document.getElementById('secondi').innerHTML=\"-vf \" + String.fromCharCode(34) + \"select='between(t,1,5)+between(t,11,15)'\" + String.fromCharCode(34) + \" -vsync 0\";
document.getElementById('secondi').title='To extract all frames from between 1 and 5 seconds, and also between 11 and 15 seconds';
document.getElementById('sswitches').innerHTML=\"<span id=sfolder contenteditable=false>newfolder_" . rand(0,784534) . str_replace("\\","\\\\",$ddn) . "out%d.png\" + '</span>';

document.getElementById('mysub').value=newv;
} else if (newv == 'Mute some of the audio') {

document.getElementById('moreb').innerHTML=firstdivih;
document.getElementById('secondi').innerHTML='';
document.getElementById('precmds').innerHTML=' ';

document.getElementById('sswitches').innerHTML=\"-vcodec copy -af \" + String.fromCharCode(34) + \"volume=enable='between(t,80,90)'<span id=svolume contenteditable=false>:volume=0\" + String.fromCharCode(34) + \" </span>\";
document.getElementById('sswitches').title='To replace all audio between 1:20 and 1:30 with silence';

document.getElementById('mysub').value=newv;
} else if (newv == 'Create a video slideshow from images') {

document.getElementById('moreb').innerHTML=firstdivih;

document.getElementById('minusi').innerHTML='-r 1/5 -i ';
document.getElementById('minusi').title='Parameter -r marks the image framerate (inverse time of each image); -vf fps=25 marks the true framerate of the output';

document.getElementById('secondi').innerHTML='';
document.getElementById('precmds').innerHTML=' ';
document.getElementById('scbi').innerHTML='" . $vssfi . "';

document.getElementById('sswitches').innerHTML=' -c:v libx264 -vf fps=25<span id=shat contenteditable=false> -pix_fmt yuv420p </span>';

document.getElementById('mysub').value=newv;
} else if (newv == 'Extract one frame') {

document.getElementById('moreb').innerHTML=firstdivih.replace(' out.mp4',' out.jpg');
document.getElementById('secondi').innerHTML='';
document.getElementById('precmds').innerHTML=' ';

document.getElementById('sswitches').innerHTML='-ss 00:00:10.000<span id=svframes contenteditable=false> -vframes 1 </span>';
document.getElementById('sswitches').title='Extract one frame at 10 second mark';

document.getElementById('mysub').value=newv;
}

“; ?>

ffmpeg media functionality talents for you to try yourself, today, in the changed voiceover.php PHP (we’d want you to download to a local MAMP Apache web server’s Document Root folder and which you can run that PHP there).


Previous relevant Ffmpeg and Pandoc and ImageMagick and Pdfimages Dropdown Linear Gradient Tutorial is shown below.

Ffmpeg and Pandoc and ImageMagick and Pdfimages Dropdown Linear Gradient Tutorial

Ffmpeg and Pandoc and ImageMagick and Pdfimages Dropdown Linear Gradient Tutorial

There were two weakness with the logic in yesterday’s Ffmpeg and Pandoc and ImageMagick and Pdfimages Dropdown Hover Swipe Tutorial, we reckon, those being …

  1. it is hard to “hover swipe” with no linework to show where one option starts and another ends, in Y (or top) co-ordinates … and …
  2. the user has trouble knowing whether their swipe attempt worked

… for which we supply ideas …

  1. linear-gradient background, in the form of a colourful “underlay” div element under (now transparent backgrounded) select (ie. dropdown) element (and associated “overlay” div) … and …
  2. emoji for swipe left ⬅ (&#11013;) and for swipe right ➡ (&#10145;) shown briefly

… featuring relevant code snippets …

  1. <?php echo ”

    function overlay() {
    origval=document.getElementById('schoices').value;
    var rect=document.getElementById('fcommand').getBoundingClientRect();
    document.getElementById('moreb').style.position='absolute';
    document.getElementById('moreb').style.left='' + rect.left + 'px';
    document.getElementById('moreb').style.top='' + rect.top + 'px';
    document.getElementById('moreb').style.width='96%'; //' + rect.width + 'px';
    document.getElementById('moreb').style.height='' + rect.height + 'px';


    document.getElementById('moreb').style.border='1px solid black';
    document.getElementById('moreb').style.paddingLeft='20px';
    document.getElementById('moreb').style.backgroundColor='#f9f9f9';
    document.getElementById('fcommand').style.opacity='0.0';
    document.getElementById('fcommand').style.cursor='pointer';


    document.getElementById('moreb').innerHTML='<span id=precmds></span><span id=verb>ffmpeg" . $ffmpegsuf . "</span> <span id=prescbi></span><span id=minusi> -i </span><span id=scbi><iframe onload=checkif(this,\"inv.mp4\"); scrolling=no frameborder=0 id=cbi data-type=file data-value=inv.mp4 data-accept=\"video/*\" style=\"display:inline-block;height:40px;width:92px;vertical-align:middle;\" src=\"/HTMLCSS/client_browsing.htm?d=69075964842271&left=y\"></iframe></span> <span id=betweenis></span> <span id=secondi>-i <span id=scbix><iframe onload=checkiftwo(this,\"inva.mp4\"); scrolling=no frameborder=0 id=cbix data-type=file data-value=inva.mp4 data-accept=\"video/*\" style=\"display:inline-block;height:40px;width:106px;vertical-align:middle;\" src=\"/HTMLCSS/client_browsing.htm?d=69075964842271&right=y\"></iframe></span></span> <span id=sswitches>-c copy -map 0:v:0 -map 1:a:0 -shortest</span> out.mp4 > <a target=_blank title=ffimpdf.bad onclick=getvb(); style=cursor:pointer;text-decoration:underline; data-href=./ffimpdf.bad>ffimpdf.bad</a>';
    if (firstdivih == '') { firstdivih=document.getElementById('moreb').innerHTML; }
    if (firstbutval == '') { firstbutval=document.getElementById('mysub').value; }
    document.getElementById('schoices').style.display='inline-block';


    rect=document.getElementById('schoices').getBoundingClientRect();


    if (eval('' + rect.height) > 100 || 1 == 1) {


    document.getElementById('schoices').style.backgroundColor='transparent';
    document.getElementById('tf').style.position='absolute'; // using new <div id=tf></div>
    document.getElementById('tf').style.left='' + rect.left + 'px';
    document.getElementById('tf').style.top='' + rect.top + 'px';
    document.getElementById('tf').style.width='' + rect.width + 'px';
    document.getElementById('tf').style.height='' + rect.height + 'px';
    // Thanks to https://stackoverflow.com/questions/49660659/css-gradients-inside-gradients
    document.getElementById('tf').style.background='linear-gradient(0deg, #ffffff 10%, rgba(255,255,0,0.6) 20%, rgba(192,192,192,0.6) 31%, rgba(255,215,0,0.6) 42%, rgba(211,211,211,0.6) 53%, rgba(255,165,0,0.6) 63%, rgba(224,255,255,0.6) 74%, rgba(254,254,254,0.6) 85%, #CC7722 100%), linear-gradient( to right, yellow, pink )'; // #fcfafc #f9f6f8 #f8f1f3
    document.getElementById('tf').style.zIndex='-1';


    document.getElementById('doverlay').style.position='absolute';
    document.getElementById('doverlay').style.left='' + rect.left + 'px';
    document.getElementById('doverlay').style.top='' + rect.top + 'px';
    document.getElementById('doverlay').style.width='' + rect.width + 'px';
    if (eval('' + rect.height) < 30) {
    document.getElementById('doverlay').style.height='' + rect.height + 'px';
    } else {
    document.getElementById('doverlay').style.height='' + eval(eval('' + rect.height) / eval('' + document.getElementById('schoices').size)) + 'px';
    }
    document.getElementById('doverlay').style.zIndex='96';
    document.getElementById('doverlay').style.textAlign='center';
    document.getElementById('doverlay').style.display='block';
    document.getElementById('doverlay').title=document.getElementById('mydefopt').title;
    //document.getElementById('mydefopt').style.fontColor='transparent';
    document.getElementById('mydefopt').innerHTML='';


    document.getElementById('doverlaytwo').style.position='absolute';
    document.getElementById('doverlaytwo').style.left='' + rect.left + 'px';
    //document.getElementById('doverlaytwo').style.top='' + eval(eval('' + rect.height) - eval(2 * eval('' + rect.height) / eval('' + document.getElementById('schoices').size))) + 'px';
    document.getElementById('doverlaytwo').style.top='' + eval(eval('' + rect.height) - eval(0.5 * eval('' + rect.height) / eval('' + document.getElementById('schoices').size))) + 'px';
    //document.getElementById('doverlaytwo').style.bottom='' + rect.bottom + 'px';
    document.getElementById('doverlaytwo').style.width='' + rect.width + 'px';
    if (eval('' + rect.height) < 30) {
    if (1 == 2) { document.getElementById('doverlaytwo').style.height='' + rect.height + 'px'; }
    } else {
    document.getElementById('doverlaytwo').style.height='' + eval(eval('' + rect.height) / eval('' + document.getElementById('schoices').size)) + 'px';
    }
    document.getElementById('doverlaytwo').style.zIndex='96';
    document.getElementById('doverlaytwo').style.textAlign='center';
    document.getElementById('doverlaytwo').style.display='block';
    document.getElementById('mydefopttwo').innerHTML='';

    rect=document.getElementById('mysub').getBoundingClientRect();
    document.getElementById('mysub').style.position='absolute';
    document.getElementById('mysub').style.left='' + rect.left + 'px';
    document.getElementById('mysub').style.top='' + rect.top + 'px';

    setInterval(fhoc, 1000);
    }


    }

    “; ?>
    … using a multiple linear-gradient element style background for the first time we can remember
  2. <?php echo ”

    var swipel='', swipelcp='', swiper='', swipercp='';

    var ra='&#10145;', racp=String.fromCodePoint(10145);
    var la='&#11013;', lacp=String.fromCodePoint(11013);


    function isplace(thiso, e) {
    var kkk=0;
    e = e || window.event;
    e.preventDefault();
    if (e.touches) {
    if (e.touches[0].pageX) {
    pos3 = e.touches[0].pageX;
    pos4 = e.touches[0].pageY;
    } else {
    pos3 = e.touches[0].clientX;
    pos4 = e.touches[0].clientY;
    }
    //console.log('pos3=' + pos3 + ',pos4=' + pos4);
    } else if (e.clientX || e.clientY) {
    pos3 = e.clientX;
    pos4 = e.clientY;
    } else {
    pos3 = e.pageX;
    pos4 = e.pageY;
    }
    if (lasto == e.target) {
    if (Math.abs(pos1 - pos3) >= 70) {
    if (pos3 > pos1) { // swipe right
    swiper=ra;
    swipercp=racp;

    if (e.target == opastr) {
    kkk=eval(1 + eval('' + kpastr));
    if (kkk >= eval('' + apastr.length)) {
    kpastr=eval('' + kpastr);
    } else {
    kpastr=kkk;
    }
    } else if (e.target == opdstr) {
    kkk=eval(1 + eval('' + kpdstr));
    if (kkk >= eval('' + apdstr.length)) {
    kpdstr=eval('' + kpdstr);
    } else {
    kpdstr=kkk;
    }
    } else if (e.target == oimstr) {
    kkk=eval(1 + eval('' + kimstr));
    if (kkk >= eval('' + aimstr.length)) {
    kimstr-=eval('' + kimstr);
    } else {
    kimstr=kkk;
    }
    } else if (e.target == offstr) {
    kkk=eval(1 + eval('' + kffstr));
    if (kkk >= eval('' + affstr.length)) {
    kffstr-=eval('' + kffstr);
    } else {
    kffstr=kkk;
    }
    }
    } else { // swipe left
    swipel=la;
    swipelcp=lacp;

    if (e.target == opastr) {
    kkk=eval(-1 + eval('' + kpastr));
    if (kkk < 0) {
    kpastr=eval(-1 + eval('' + apastr.length));
    } else {
    kpastr=kkk;
    }
    } else if (e.target == opdstr) {
    kkk=eval(-1 + eval('' + kpdstr));
    if (kkk < 0) {
    kpdstr=eval(-1 + eval('' + apdstr.length));
    } else {
    kpdstr=kkk;
    }
    } else if (e.target == oimstr) {
    kkk=eval(-1 + eval('' + kimstr));
    if (kkk < 0) {
    kimstr=eval(-1 + eval('' + aimstr.length));
    } else {
    kimstr=kkk;
    }
    } else if (e.target == offstr) {
    kkk=eval(-1 + eval('' + kffstr));
    if (kkk < 0) {
    kffstr=eval(-1 + eval('' + affstr.length));
    } else {
    kffstr=kkk;
    }
    }
    }
    }
    //alert('swipe distance = ' + Math.abs(pos1 - pos3));
    }
    lasto=e.target;
    }

    function betweeneatatjoes() {
    var origt='', origrest='', kkprefix=swipelcp + '...', kksuffix='...' + swipercp;
    var origkkprefix='', origkksuffix='', origkprefix='', origksuffix='';
    if (kprefix == '' && ksuffix == '') {
    kprefix=swipel + '&#128309;..';
    kkprefix=swipelcp + String.fromCodePoint(128309) + '..';
    ksuffix='...' + swiper;
    //document.getElementById('doverlaytwo').style.marginTop='20px';
    } else if (kprefix == swipel + '&#128309;..') {
    kprefix=swipel + '.&#128309;.';
    kkprefix=swipelcp +'.' + String.fromCodePoint(128309) + '.';
    ksuffix='...' + swiper;
    } else if (kprefix == swipel + '.&#128309;.') {
    kprefix=swipel + '..&#128309;';
    kkprefix=swipelcp + '..' + String.fromCodePoint(128309) + '';
    ksuffix='...' + swiper;
    } else if (kprefix == swipel + '..&#128309;') {
    ksuffix='&#128309;..' + swiper;
    kksuffix=String.fromCodePoint(128309) + '..' + swipercp;
    kprefix=swipel + '...' + swiper;
    } else if (ksuffix == '&#128309;..' + swiper) {
    ksuffix='.&#128308;.' + swiper;
    kksuffix='.' + String.fromCodePoint(128308) + '.' + swipercp;
    kprefix=swipel + '...';
    } else if (ksuffix == '.&#128308;.' + swiper) {
    ksuffix='..&#128308;' + swiper;
    kksuffix='..' + String.fromCodePoint(128308) + '' + swipercp;
    kprefix=swipel + '...';
    } else {
    kprefix=swipel + '&#917536;..';
    kkprefix=swipelcp + '..' + String.fromCodePoint(917536) + '..';
    ksuffix='...' + swiper;
    //document.getElementById('doverlaytwo').style.marginTop='0px';
    }


    origkkprefix=kkprefix;
    origkksuffix=kksuffix;
    origkprefix=kprefix;
    origksuffix=ksuffix;



    if (oimstr) {
    origt=oimstr.getAttribute('data-title');
    if (lasto == oimstr) {
    kkprefix=origkkprefix;
    kksuffix=origkksuffix;
    kprefix=origkprefix;
    ksuffix=origksuffix;
    } else if (swipel + swiper != '') {
    kkprefix=origkkprefix.replace(swipelcp,'');
    kksuffix=origkksuffix.replace(swipercp,'');
    kprefix=origkprefix.replace(swipel,'');
    ksuffix=origksuffix.replace(swiper,'');
    }

    if (kimstr == 0) {
    oimstr.innerHTML=' ' + kprefix + aimstr[kimstr] + ksuffix;
    origrest=(origt.split('' + aimstr[kimstr])[1] + ',' + origt.split('' + aimstr[kimstr])[0]).trim().replace(/\,\,/g,'').replace('undefined','');
    oimstr.title=kkprefix + aimstr[kimstr] + kksuffix + origrest;
    } else {
    oimstr.innerHTML=' ' + kprefix + aimstr[eval(-1 + kimstr)] + ksuffix;
    origrest=(origt.split('' + aimstr[eval(-1 + kimstr)])[1] + ',' + origt.split('' + aimstr[eval(-1 + kimstr)])[0]).trim().replace(/\,\,/g,'').replace('undefined','');
    oimstr.title=kkprefix + aimstr[eval(-1 + kimstr)] + kksuffix + origrest;
    }
    }
    if (opdstr) {
    origt=opdstr.getAttribute('data-title');
    if (lasto == opdstr) {
    kkprefix=origkkprefix;
    kksuffix=origkksuffix;
    kprefix=origkprefix;
    ksuffix=origksuffix;
    } else if (swipel + swiper != '') {
    kkprefix=origkkprefix.replace(swipelcp,'');
    kksuffix=origkksuffix.replace(swipercp,'');
    kprefix=origkprefix.replace(swipel,'');
    ksuffix=origksuffix.replace(swiper,'');
    }

    if (kpdstr == 0) {
    opdstr.innerHTML=' ' + kprefix + apdstr[kpdstr] + ksuffix;
    origrest=(origt.split('' + apdstr[kpdstr])[1] + ',' + origt.split('' + apdstr[kpdstr])[0]).trim().replace(/\,\,/g,'').replace('undefined','');
    opdstr.title=kkprefix + apdstr[kpdstr] + kksuffix + origrest;
    } else {
    opdstr.innerHTML=' ' + kprefix + apdstr[eval(-1 + kpdstr)] + ksuffix;
    origrest=(origt.split('' + apdstr[eval(-1 + kpdstr)])[1] + ',' + origt.split('' + apdstr[eval(-1 + kpdstr)])[0]).trim().replace(/\,\,/g,'').replace('undefined','');
    opdstr.title=kkprefix + apdstr[eval(-1 + kpdstr)] + kksuffix + origrest;
    }
    }
    if (opastr) {
    origt=opastr.getAttribute('data-title');
    if (lasto == opastr) {
    kkprefix=origkkprefix;
    kksuffix=origkksuffix;
    kprefix=origkprefix;
    ksuffix=origksuffix;
    } else if (swipel + swiper != '') {
    kkprefix=origkkprefix.replace(swipelcp,'');
    kksuffix=origkksuffix.replace(swipercp,'');
    kprefix=origkprefix.replace(swipel,'');
    ksuffix=origksuffix.replace(swiper,'');
    }

    if (kpastr == 0) {
    opastr.innerHTML=' ' + kprefix + apastr[kpastr] + ksuffix;
    origrest=(origt.split('' + apastr[kpastr])[1] + ',' + origt.split('' + apastr[kpastr])[0]).trim().replace(/\,\,/g,'').replace('undefined','');
    opastr.title=kkprefix + apastr[kpastr] + kksuffix + origrest;
    } else {
    opastr.innerHTML=' ' + kprefix + apastr[eval(-1 + kpastr)] + ksuffix;
    origrest=(origt.split('' + apastr[eval(-1 + kpastr)])[1] + ',' + origt.split('' + apastr[eval(-1 + kpastr)])[0]).trim().replace(/\,\,/g,'').replace('undefined','');
    opastr.title=kkprefix + apastr[eval(-1 + kpastr)] + kksuffix + origrest;
    }
    }
    if (offstr) {
    origt=offstr.getAttribute('data-title');
    if (lasto == offstr) {
    kkprefix=origkkprefix;
    kksuffix=origkksuffix;
    kprefix=origkprefix;
    ksuffix=origksuffix;
    } else if (swipel + swiper != '') {
    kkprefix=origkkprefix.replace(swipelcp,'');
    kksuffix=origkksuffix.replace(swipercp,'');
    kprefix=origkprefix.replace(swipel,'');
    ksuffix=origksuffix.replace(swiper,'');
    }

    if (kffstr == 0) {
    offstr.innerHTML=' ' + kprefix + affstr[kffstr] + ksuffix;
    origrest=(origt.split('' + affstr[kffstr])[1] + ',' + origt.split('' + affstr[kffstr])[0]).trim().replace(/\,\,/g,'').replace('undefined','');
    offstr.title=kkprefix + affstr[kffstr] + kksuffix + origrest;
    } else {
    offstr.innerHTML=' ' + kprefix + affstr[eval(-1 + kffstr)] + ksuffix;
    origrest=(origt.split('' + affstr[eval(-1 + kffstr)])[1] + ',' + origt.split('' + affstr[eval(-1 + kffstr)])[0]).trim().replace(/\,\,/g,'').replace('undefined','');
    offstr.title=kkprefix + affstr[eval(-1 + kffstr)] + kksuffix + origrest;
    }
    }
    kcnt++;
    swipel='';
    swipelcp='';
    swiper='';
    swipercp='';

    if (kcnt < 7) { setTimeout(betweeneatatjoes, 1000); }
    }

    “; ?>

… in the changed voiceover.php PHP (we’d want you to download to a local MAMP Apache web server’s Document Root folder and which you can run that PHP there).


Previous relevant Ffmpeg and Pandoc and ImageMagick and Pdfimages Dropdown Hover Swipe Tutorial is shown below.

Ffmpeg and Pandoc and ImageMagick and Pdfimages Dropdown Hover Swipe Tutorial

Ffmpeg and Pandoc and ImageMagick and Pdfimages Dropdown Hover Swipe Tutorial

Some users are impatient, we grant you. Maybe some don’t want to wait the whole time of an 8 second “Eat at Joes” rotation. Well, we thought about this, and got an idea to extend yesterday’s Ffmpeg and Pandoc and ImageMagick and Pdfimages Dropdown Onhover Marquee Tutorial‘s non-mobile functionality via …

  • dropdown option (with animation) element onmouseover (hover swipe (maybe) in x,y) … call such as oimstr.onmouseover=function(event) { wasplace(oimstr, event); }; … uses …
    <?php echo ”

    var pos1=0, pos2=0, pos3=0, pos4=0, lasto=null;

    function wasplace(thiso, e) {
    e = e || window.event;
    e.preventDefault();
    if (e.touches) {
    if (e.touches[0].pageX) {
    pos1 = e.touches[0].pageX;
    pos2 = e.touches[0].pageY;
    } else {
    pos1 = e.touches[0].clientX;
    pos2 = e.touches[0].clientY;
    }
    //console.log('pos3=' + pos3 + ',pos4=' + pos4);
    } else if (e.clientX || e.clientY) {
    pos1 = e.clientX;
    pos2 = e.clientY;
    } else {
    pos1 = e.pageX;
    pos2 = e.pageY;
    }
    lasto=e.target;
    }

    “; ?>
    …and onmouseout (hover swipe out x,y) events … if deltax >= 70 … call such as oimstr.onmouseout=function(event) { isplace(oimstr, event); }; … uses …
    <?php echo ”

    function isplace(thiso, e) {
    var kkk=0;
    e = e || window.event;
    e.preventDefault();
    if (e.touches) {
    if (e.touches[0].pageX) {
    pos3 = e.touches[0].pageX;
    pos4 = e.touches[0].pageY;
    } else {
    pos3 = e.touches[0].clientX;
    pos4 = e.touches[0].clientY;
    }
    //console.log('pos3=' + pos3 + ',pos4=' + pos4);
    } else if (e.clientX || e.clientY) {
    pos3 = e.clientX;
    pos4 = e.clientY;
    } else {
    pos3 = e.pageX;
    pos4 = e.pageY;
    }
    if (lasto == e.target) {
    if (Math.abs(pos1 - pos3) >= 70) {
    if (pos3 > pos1) { // swipe right
    if (e.target == opastr) {
    kkk=eval(1 + eval('' + kpastr));
    if (kkk >= eval('' + apastr.length)) {
    kpastr=0;
    } else {
    kpastr=kkk;
    }
    } else if (e.target == opdstr) {
    kkk=eval(1 + eval('' + kpdstr));
    if (kkk >= eval('' + apdstr.length)) {
    kpdstr=0;
    } else {
    kpdstr=kkk;
    }
    } else if (e.target == oimstr) {
    kkk=eval(1 + eval('' + kimstr));
    if (kkk >= eval('' + aimstr.length)) {
    kimstr=0;
    } else {
    kimstr=kkk;
    }
    } else if (e.target == offstr) {
    kkk=eval(1 + eval('' + kffstr));
    if (kkk >= eval('' + affstr.length)) {
    kffstr=0;
    } else {
    kffstr=kkk;
    }
    }
    } else { // swipe left
    if (e.target == opastr) {
    kkk=eval(-1 + eval('' + kpastr));
    if (kkk < 0) {
    kpastr=eval(-1 + eval('' + apastr.length));
    } else {
    kpastr=kkk;
    }
    } else if (e.target == opdstr) {
    kkk=eval(-1 + eval('' + kpdstr));
    if (kkk < 0) {
    kpdstr=eval(-1 + eval('' + apdstr.length));
    } else {
    kpdstr=kkk;
    }
    } else if (e.target == oimstr) {
    kkk=eval(-1 + eval('' + kimstr));
    if (kkk < 0) {
    kimstr=eval(-1 + eval('' + aimstr.length));
    } else {
    kimstr=kkk;
    }
    } else if (e.target == offstr) {
    kkk=eval(-1 + eval('' + kffstr));
    if (kkk < 0) {
    kffstr=eval(-1 + eval('' + affstr.length));
    } else {
    kffstr=kkk;
    }
    }
    }
    }
    //alert('swipe distance = ' + Math.abs(pos1 - pos3));
    }
    lasto=e.target;
    }

    “; ?>
  • class a swipe right (if deltax > 0) else swipe left … resulting in …
  • immediately show next option innerText if swipe right and show previous option innerText if swipe left

… for you to try for yourself

Media and document action items … please note you can hover swipe right or left, accurately, and with panache, regarding animated options to speed up transitions between option values

… in the changed voiceover.php PHP (we’d want you to download to a local MAMP Apache web server’s Document Root folder and which you can run that PHP there).


Previous relevant Ffmpeg and Pandoc and ImageMagick and Pdfimages Dropdown Onhover Marquee Tutorial is shown below.

Ffmpeg and Pandoc and ImageMagick and Pdfimages Dropdown Onhover Marquee Tutorial

Ffmpeg and Pandoc and ImageMagick and Pdfimages Dropdown Onhover Marquee Tutorial

The non-mobile platforms have that useful wooooorrrrllllddd, the “onhover wooooorrrrllllddd” (to be precise) that can be a great partner for Javascript Ajax methodologies. This onhover (actually the “onmouseover”) event is also useful whereby as a user hovers over an HTML element, and that element’s title attribute has a value, then the user can see that value displayed.

And though, with yesterday’s Ffmpeg and Pandoc and ImageMagick and Pdfimages Animated Emoji Tutorial work …

though we’re not going “full marquee Eat at Joes”

… regarding the dropdown option innerText “look”, there is, for non-mobile, this “onhover wooooorrrrllllddd” we can use to try a form of marquee “look” there, as per

<?php echo ”

function betweeneatatjoes() {
var origt='', origrest='', kkprefix='...', kksuffix='...';
if (kprefix == '' && ksuffix == '') {
kprefix='&#128309;..';
kkprefix=String.fromCodePoint(128309) + '..';
ksuffix='...';
//document.getElementById('doverlaytwo').style.marginTop='20px';
} else if (kprefix == '&#128309;..') {
kprefix='.&#128309;.';
kkprefix='.' + String.fromCodePoint(128309) + '.';
ksuffix='...';
} else if (kprefix == '.&#128309;.') {
kprefix='..&#128309;';
kkprefix='..' + String.fromCodePoint(128309) + '';
ksuffix='...';
} else if (kprefix == '..&#128309;') {
ksuffix='&#128309;..';
kksuffix=String.fromCodePoint(128309) + '..';
kprefix='...';
} else if (ksuffix == '&#128309;..') {
ksuffix='.&#128308;.';
kksuffix='.' + String.fromCodePoint(128308) + '.';
kprefix='...';
} else if (ksuffix == '.&#128308;.') {
ksuffix='..&#128308;';
kksuffix='..' + String.fromCodePoint(128308) + '';
kprefix='...';
} else {
kprefix='&#917536;..';
kkprefix='..' + String.fromCodePoint(917536) + '..';
ksuffix='...';
//document.getElementById('doverlaytwo').style.marginTop='0px';
}
if (oimstr) {
origt=oimstr.getAttribute('data-title');
if (kimstr == 0) {
oimstr.innerHTML=' ' + kprefix + aimstr[kimstr] + ksuffix;
origrest=(origt.split('' + aimstr[kimstr])[1] + ',' + origt.split('' + aimstr[kimstr])[0]).trim().replace(/\,\,/g,'').replace('undefined','');
oimstr.title=kkprefix + aimstr[kimstr] + kksuffix + origrest;

} else {
oimstr.innerHTML=' ' + kprefix + aimstr[eval(-1 + kimstr)] + ksuffix;
origrest=(origt.split('' + aimstr[eval(-1 + kimstr)])[1] + ',' + origt.split('' + aimstr[eval(-1 + kimstr)])[0]).trim().replace(/\,\,/g,'').replace('undefined','');
oimstr.title=kkprefix + aimstr[eval(-1 + kimstr)] + kksuffix + origrest;

}
}
if (opdstr) {
origt=opdstr.getAttribute('data-title');
if (kpdstr == 0) {
opdstr.innerHTML=' ' + kprefix + apdstr[kpdstr] + ksuffix;
origrest=(origt.split('' + apdstr[kpdstr])[1] + ',' + origt.split('' + apdstr[kpdstr])[0]).trim().replace(/\,\,/g,'').replace('undefined','');
opdstr.title=kkprefix + apdstr[kpdstr] + kksuffix + origrest;

} else {
opdstr.innerHTML=' ' + kprefix + apdstr[eval(-1 + kpdstr)] + ksuffix;
origrest=(origt.split('' + apdstr[eval(-1 + kpdstr)])[1] + ',' + origt.split('' + apdstr[eval(-1 + kpdstr)])[0]).trim().replace(/\,\,/g,'').replace('undefined','');
opdstr.title=kkprefix + apdstr[eval(-1 + kpdstr)] + kksuffix + origrest;

}
}
if (opastr) {
origt=opastr.getAttribute('data-title');
if (kpastr == 0) {
opastr.innerHTML=' ' + kprefix + apastr[kpastr] + ksuffix;
origrest=(origt.split('' + apastr[kpastr])[1] + ',' + origt.split('' + apastr[kpastr])[0]).trim().replace(/\,\,/g,'').replace('undefined','');
opastr.title=kkprefix + apastr[kpastr] + kksuffix + origrest;

} else {
opastr.innerHTML=' ' + kprefix + apastr[eval(-1 + kpastr)] + ksuffix;
origrest=(origt.split('' + apastr[eval(-1 + kpastr)])[1] + ',' + origt.split('' + apastr[eval(-1 + kpastr)])[0]).trim().replace(/\,\,/g,'').replace('undefined','');
opastr.title=kkprefix + apastr[eval(-1 + kpastr)] + kksuffix + origrest;

}
}
if (offstr) {
origt=offstr.getAttribute('data-title');
if (kffstr == 0) {
offstr.innerHTML=' ' + kprefix + affstr[kffstr] + ksuffix;
origrest=(origt.split('' + affstr[kffstr])[1] + ',' + origt.split('' + affstr[kffstr])[0]).trim().replace(/\,\,/g,'').replace('undefined','');
offstr.title=kkprefix + affstr[kffstr] + kksuffix + origrest;

} else {
offstr.innerHTML=' ' + kprefix + affstr[eval(-1 + kffstr)] + ksuffix;
origrest=(origt.split('' + affstr[eval(-1 + kffstr)])[1] + ',' + origt.split('' + affstr[eval(-1 + kffstr)])[0]).trim().replace(/\,\,/g,'').replace('undefined','');
offstr.title=kkprefix + affstr[eval(-1 + kffstr)] + kksuffix + origrest;

}
}
kcnt++;
if (kcnt < 7) { setTimeout(betweeneatatjoes, 1000); }
}

“; ?>

Proof positive that emojis are text, and can help provide a graphic display interest for a webpage. As well, as a CSS means by which we stop “dropdown Y jitteriness”, we introduce the use of an emoji ⚪ (&#9898; or &#x26aa;) for most option element Clayton innerText parts, always …


<style>
option:not(.nonwhite)::before {
content: '\0026aa';
}


#doverlay {
background-color: #FFE7E9;
}


#doverlaytwo {
background-color: #FFE7E9;
}


body {
background-color: #FFFFEF;
}
</style>

“; ?>

… with one more media functionality

<?php

var mlook=false, kcnt=0, kprefix='', ksuffix='';
var imstr=' Images to PDF, Images to GIF,', oimstr=null, kimstr=0, aimstr=[];
var pdstr=' PDF to Images, PDF to HTML, PDF to XML,', opdstr=null, kpdstr=0, apdstr=[];
var pastr=' Text to HTML, Text to Rich Text, Text to Word,', opastr=null, kpastr=0, apastr=[];
var ffstr=' Concat demuxer, Display the frame number on each frame,', offstr=null, kffstr=0, affstr=[];

?>

… in the changed voiceover.php PHP (we’d want you to download to a local MAMP Apache web server’s Document Root folder and which you can run that PHP there).


Previous relevant Ffmpeg and Pandoc and ImageMagick and Pdfimages Animated Emoji Tutorial is shown below.

Ffmpeg and Pandoc and ImageMagick and Pdfimages Animated Emoji Tutorial

Ffmpeg and Pandoc and ImageMagick and Pdfimages Animated Emoji Tutorial

The “dropdown animations” introduced into yesterday’s Ffmpeg and Pandoc and ImageMagick and Pdfimages Animated Dropdown Tutorial were a tad subtle, it only involving …

  • the wording of option elements within the dropdown … and though we’re not going “full marquee Eat at Joes” we are accentuating “midway”, today, by …
  • adding emoji 🔵 (&#128309;) movement to the animation for interest sake, as well as being informative (in that the user can anticipate when the new innerText text will arrive, as the emoji moves from left to right)

… that we team with more instances of multiple animation settings …

<?php echo ”

var mlook=false, kcnt=0, kprefix='', ksuffix='';
var imstr=' Images to PDF, Images to GIF,', oimstr=null, kimstr=0, aimstr=[];
var pdstr=' PDF to Images, PDF to HTML, PDF to XML,', opdstr=null, kpdstr=0, apdstr=[];
var pastr=' Text to HTML, Text to Rich Text, Text to Word,', opastr=null, kpastr=0, apastr=[];
var ffstr=' Concat demuxer, ', offstr=null, kffstr=0, affstr=[];

“; ?>

… and a new “between the 8 second setInterval wording refreshes” Javascript function

<?php echo ”

function betweeneatatjoes() {
if (kprefix == '' && ksuffix == '') {
kprefix='&#128309;..';
ksuffix='...';
document.getElementById('doverlaytwo').style.marginTop='20px';
} else if (kprefix == '&#128309;..') {
kprefix='.&#128309;.';
ksuffix='...';
} else if (kprefix == '.&#128309;.') {
kprefix='..&#128309;';
ksuffix='...';
} else if (kprefix == '..&#128309;') {
ksuffix='&#128309;..';
kprefix='...';
} else if (ksuffix == '&#128309;..') {
ksuffix='.&#128309;.';
kprefix='...';
} else if (ksuffix == '.&#128309;.') {
ksuffix='..&#128309;';
kprefix='...';
} else {
kprefix='...';
ksuffix='...';
document.getElementById('doverlaytwo').style.marginTop='0px';
}
if (oimstr) {
if (kimstr == 0) {
oimstr.innerHTML=' ' + kprefix + aimstr[kimstr] + ksuffix;
} else {
oimstr.innerHTML=' ' + kprefix + aimstr[eval(-1 + kimstr)] + ksuffix;
}
}
if (opdstr) {
if (kpdstr == 0) {
opdstr.innerHTML=' ' + kprefix + apdstr[kpdstr] + ksuffix;
} else {
opdstr.innerHTML=' ' + kprefix + apdstr[eval(-1 + kpdstr)] + ksuffix;
}
}
if (opastr) {
if (kpastr == 0) {
opastr.innerHTML=' ' + kprefix + apastr[kpastr] + ksuffix;
} else {
opastr.innerHTML=' ' + kprefix + apastr[eval(-1 + kpastr)] + ksuffix;
}
}
if (offstr) {
if (kffstr == 0) {
offstr.innerHTML=' ' + kprefix + affstr[kffstr] + ksuffix;
} else {
offstr.innerHTML=' ' + kprefix + affstr[kffstr] + ksuffix;
}
}
kcnt++;
if (kcnt < 7) { setTimeout(betweeneatatjoes, 1000); }
}



function eatatjoes() {
kcnt=0;
kprefix='';
ksuffix='';
document.getElementById('doverlaytwo').style.marginTop='0px';

if (oimstr) {
if (kimstr >= eval('' + aimstr.length)) {
kimstr=0;
oimstr.innerHTML=' ' + aimstr[kimstr];
} else {
oimstr.innerHTML=' ' + aimstr[kimstr];
kimstr++;
}
}
if (opdstr) {
if (kpdstr >= eval('' + apdstr.length)) {
kpdstr=0;
opdstr.innerHTML=' ' + apdstr[kpdstr];
} else {
opdstr.innerHTML=' ' + apdstr[kpdstr];
kpdstr++;
}
}
if (opastr) {
//alert(apastr.length);
if (kpastr >= eval('' + apastr.length)) {
kpastr=0;
opastr.innerHTML=' ' + apastr[kpastr];
} else {
opastr.innerHTML=' ' + apastr[kpastr];
kpastr++;
}
}
if (offstr) {
if (kffstr >= eval('' + affstr.length)) {
kffstr=0;
offstr.innerHTML=' ' + affstr[kffstr];
} else {
offstr.innerHTML=' ' + affstr[kffstr];
kffstr++;
}
}
setTimeout(betweeneatatjoes, 1000);
}


function andthen(iidea) {
var outidea=iidea;
var fndpos=-1;
var optsare=document.getElementsByTagName('option'), ioptsare=0;
var iimstr=(imstr.indexOf(',') == -1 ? -1 : outidea.indexOf(imstr.split(',')[0].trim() + ','));
mlook=false;
if (iimstr != -1) {
if ((imstr.split(',')[0].trim() + ',') != imstr.trim()) {
if (document.getElementById('oimagemagick')) {
oimstr=document.getElementById('oimagemagick');
mlook=true;
aimstr=imstr.trim().replace(/\,\ \ /g,',').replace(/\,\ /g,',').replace(/\,$/g,'').split(',');
} else {
for (ioptsare=0; ioptsare<optsare.length; ioptsare++) {
if (optsare[ioptsare].value == imstr.split(',')[0].trim()) {
oimstr=optsare[ioptsare];
mlook=true;
aimstr=imstr.trim().replace(/\,\ \ /g,',').replace(/\,\ /g,',').replace(/\,$/g,'').split(',');
}
}
}
outidea=outidea.replace(imstr.split(',')[0].trim(), imstr.split(',')[0].trim() + '' + (imstr.replace(imstr.split(',')[0],'').trim() + ',').replace(',,',',').replace(/\,$/g,''));
}
}
var ipdstr=(pdstr.indexOf(',') == -1 ? -1 : outidea.indexOf(pdstr.split(',')[0].trim() + ','));
if (ipdstr != -1) {
if ((pdstr.split(',')[0].trim() + ',') != pdstr.trim()) {
if (document.getElementById('opdfimages')) {
opdstr=document.getElementById('opdfimages');
mlook=true;
apdstr=pdstr.trim().replace(/\,\ \ /g,',').replace(/\,\ /g,',').replace(/\,$/g,'').split(',');
} else {
for (ioptsare=0; ioptsare<optsare.length; ioptsare++) {
if (optsare[ioptsare].value == pdstr.split(',')[0].trim()) {
opdstr=optsare[ioptsare];
mlook=true;
apdstr=pdstr.trim().replace(/\,\ \ /g,',').replace(/\,\ /g,',').replace(/\,$/g,'').split(',');
}
}
}
outidea=outidea.replace(pdstr.split(',')[0].trim(), pdstr.split(',')[0].trim() + '' + (pdstr.replace(imstr.split(',')[0],'').trim() + ',').replace(',,',',').replace(/\,$/g,''));
}
}
var ipastr=(pastr.indexOf(',') == -1 ? -1 : outidea.indexOf(pastr.split(',')[0].trim() + ','));
if (ipastr != -1) {
if ((pastr.split(',')[0].trim() + ',') != pastr.trim()) {
if (document.getElementById('opandoc')) {
opastr=document.getElementById('opandoc');
mlook=true;
apastr=pastr.trim().replace(/\,\ \ /g,',').replace(/\,\ /g,',').replace(/\,$/g,'').split(',');
} else {
for (ioptsare=0; ioptsare<optsare.length; ioptsare++) {
if (optsare[ioptsare].value == pastr.split(',')[0].trim()) {
opastr=optsare[ioptsare];
mlook=true;
apastr=pastr.trim().replace(/\,\ \ /g,',').replace(/\,\ /g,',').replace(/\,$/g,'').split(',');
}
}
}
outidea=outidea.replace(pastr.split(',')[0].trim(), pastr.split(',')[0].trim() + '' + (pastr.replace(imstr.split(',')[0],'').trim() + ',').replace(',,',',').replace(/\,$/g,''));
}
}
var iffstr=(ffstr.indexOf(',') == -1 ? -1 : outidea.indexOf(ffstr.split(',')[0].trim() + ','));
if (iffstr != -1) {
if ((ffstr.split(',')[0].trim() + ',') != ffstr.trim()) {
if (document.getElementById('offmpeg')) {
offstr=document.getElementById('offmpeg');
mlook=true;
affstr=ffstr.trim().replace(/\,\ \ /g,',').replace(/\,\ /g,',').replace(/\,$/g,'').split(',');
} else {
for (ioptsare=0; ioptsare<optsare.length; ioptsare++) {
if (optsare[ioptsare].value == ffstr.split(',')[0].trim()) {
offstr=optsare[ioptsare];
mlook=true;
affstr=ffstr.trim().replace(/\,\ \ /g,',').replace(/\,\ /g,',').replace(/\,$/g,'').split(',');
}
}
}
outidea=outidea.replace(ffstr.split(',')[0].trim(), ffstr.split(',')[0].trim() + '' + (ffstr.replace(imstr.split(',')[0],'').trim() + ',').replace(',,',',').replace(/\,$/g,''));
}
}
if (mlook) { setInterval(eatatjoes, 8000); }
return outidea;
}

“; ?>

… helped out via the original setInterval Javascript “eatatjoes” function (all kicked off via modified document.body onload logic
document.getElementById(‘mainspan’).title = andthen(document.getElementById(‘schoices’).innerText.replace(/\&nbsp\;/g,’ ‘).replace(/\ \ /g,’, ‘));
), as modified, above.

You can see this in the changed voiceover.php PHP (we’d want you to download to a local MAMP Apache web server’s Document Root folder and which you can run that PHP there).


Previous relevant Ffmpeg and Pandoc and ImageMagick and Pdfimages Animated Dropdown Tutorial is shown below.

Ffmpeg and Pandoc and ImageMagick and Pdfimages Animated Dropdown Tutorial

Ffmpeg and Pandoc and ImageMagick and Pdfimages Animated Dropdown Tutorial

Lemon curry?! Animated dropdown?! What gives? Well, it’s not “shelling peas”, yet!

Yes, there is another “framework” step forward we wanted to implement before the peas. And yes, no surprises there, the “framework” work relates to adding functionality to our main dropdown. We’re adding a layer of functionality we’re going to refer to as “animated dropdown”. It amounts to …

  • dropdown (ie. select element) … for non-mobile …
  • has size attribute equal to the number of option elements it contains
  • logic wise, because our non-nothing option innerTexts have equalled option values (if you Javascript trim() the option innerText, that is), we have the opportunity to start taking more notice of the …
    <?php echo ”

    function process(tv, tvo) {
    var newval='';
    var ourtv=tvo.value;
    if (tv != '') {
    ourtv=tvo.options[tvo.selectedIndex].innerText.trim();
    }

    if (origval == '') { origval=document.getElementById('mydefopt').title; }
    if (tv == '') {
    document.getElementById('mainspan').innerHTML=document.getElementById('mydefopt').title;
    } else {
    document.getElementById('mydefopt').title=ourtv; //tv;
    document.getElementById('mainspan').innerHTML=document.getElementById('mydefopt').title;
    document.getElementById('schoices').value='';
    }
    newval=document.getElementById('mydefopt').title;
    //alert('origval,newval=' + origval + ' ' + newval);
    if (newval != origval) {
    origval=newval;
    wentfrom(origval, newval);
    } else {
    origval=newval;
    }
    }

    “; ?>
    … option innerHTML as above, meaning …
  • we can set up Javascript code facilitating the animated feel of some option innerHTML looks that are taken notice of as selected via …
    Global variables arranged via each “verb” involved … for today’s “proof of concept” we add one extra Pandoc “Text to Rich Text” option, for now, before the flood of peas arrives …
    <?php echo ”

    var mlook=false;
    var imstr=' Images to PDF, ', oimstr=null, kimstr=0, aimstr=[];
    var pdstr=' PDF to Images, ', opdstr=null, kpdstr=0, apdstr=[];
    var pastr=' Text to HTML, Text to Rich Text,', opastr=null, kpastr=0, apastr=[];
    var ffstr=' Concat demuxer, ', offstr=null, kffstr=0, affstr=[];

    “; ?>
    As heading title is determined at document.body onload document.getElementById(‘mainspan’).title=andthen(document.getElementById(‘schoices’).innerText.replace(/\&nbsp\;/g,’ ‘).replace(/\ \ /g,’, ‘));
    <?php echo ”

    function andthen(iidea) {
    var outidea=iidea;
    var fndpos=-1;
    var optsare=document.getElementsByTagName('option'), ioptsare=0;
    var iimstr=(imstr.indexOf(',') == -1 ? -1 : outidea.indexOf(imstr.split(',')[0].trim() + ','));
    mlook=false;
    if (iimstr != -1) {
    if ((imstr.split(',')[0].trim() + ',') != imstr.trim()) {
    if (document.getElementById('oimagemagick')) {
    oimstr=document.getElementById('oimagemagick');
    mlook=true;
    aimstr=imstr.trim().replace(/\,\ \ /g,',').replace(/\,\ /g,',').replace(/\,$/g,'').split(',');
    } else {
    for (ioptsare=0; ioptsare<optsare.length; ioptsare++) {
    if (optsare[ioptsare].value == imstr.split(',')[0].trim()) {
    oimstr=optsare[ioptsare];
    mlook=true;
    aimstr=imstr.trim().replace(/\,\ \ /g,',').replace(/\,\ /g,',').replace(/\,$/g,'').split(',');
    }
    }
    }
    outidea=outidea.replace(imstr.split(',')[0].trim(), imstr.split(',')[0].trim() + '' + (imstr.replace(imstr.split(',')[0],'').trim() + ',').replace(',,',',').replace(/\,$/g,''));
    }
    }
    var ipdstr=(pdstr.indexOf(',') == -1 ? -1 : outidea.indexOf(pdstr.split(',')[0].trim() + ','));
    if (ipdstr != -1) {
    if ((pdstr.split(',')[0].trim() + ',') != pdstr.trim()) {
    if (document.getElementById('opdfimages')) {
    opdstr=document.getElementById('opdfimages');
    mlook=true;
    aipdtr=pdstr.trim().replace(/\,\ \ /g,',').replace(/\,\ /g,',').replace(/\,$/g,'').split(',');
    } else {
    for (ioptsare=0; ioptsare<optsare.length; ioptsare++) {
    if (optsare[ioptsare].value == pdstr.split(',')[0].trim()) {
    opdstr=optsare[ioptsare];
    mlook=true;
    apdstr=pdstr.trim().replace(/\,\ \ /g,',').replace(/\,\ /g,',').replace(/\,$/g,'').split(',');
    }
    }
    }
    outidea=outidea.replace(pdstr.split(',')[0].trim(), pdstr.split(',')[0].trim() + '' + (pdstr.replace(imstr.split(',')[0],'').trim() + ',').replace(',,',',').replace(/\,$/g,''));
    }
    }
    var ipastr=(pastr.indexOf(',') == -1 ? -1 : outidea.indexOf(pastr.split(',')[0].trim() + ','));
    if (ipastr != -1) {
    if ((pastr.split(',')[0].trim() + ',') != pastr.trim()) {
    if (document.getElementById('opandoc')) {
    opastr=document.getElementById('opandoc');
    mlook=true;
    apastr=pastr.trim().replace(/\,\ \ /g,',').replace(/\,\ /g,',').replace(/\,$/g,'').split(',');
    } else {
    for (ioptsare=0; ioptsare<optsare.length; ioptsare++) {
    if (optsare[ioptsare].value == pastr.split(',')[0].trim()) {
    opastr=optsare[ioptsare];
    mlook=true;
    apastr=pastr.trim().replace(/\,\ \ /g,',').replace(/\,\ /g,',').replace(/\,$/g,'').split(',');
    }
    }
    }
    outidea=outidea.replace(pastr.split(',')[0].trim(), pastr.split(',')[0].trim() + '' + (pastr.replace(imstr.split(',')[0],'').trim() + ',').replace(',,',',').replace(/\,$/g,''));
    }
    }
    var iffstr=(ffstr.indexOf(',') == -1 ? -1 : outidea.indexOf(ffstr.split(',')[0].trim() + ','));
    if (iffstr != -1) {
    if ((ffstr.split(',')[0].trim() + ',') != ffstr.trim()) {
    if (document.getElementById('offmpeg')) {
    offstr=document.getElementById('offmpeg');
    mlook=true;
    affstr=ffstr.trim().replace(/\,\ \ /g,',').replace(/\,\ /g,',').replace(/\,$/g,'').split(',');
    } else {
    for (ioptsare=0; ioptsare<optsare.length; ioptsare++) {
    if (optsare[ioptsare].value == ffstr.split(',')[0].trim()) {
    offstr=optsare[ioptsare];
    mlook=true;
    affstr=ffstr.trim().replace(/\,\ \ /g,',').replace(/\,\ /g,',').replace(/\,$/g,'').split(',');
    }
    }
    }
    outidea=outidea.replace(ffstr.split(',')[0].trim(), ffstr.split(',')[0].trim() + '' + (ffstr.replace(imstr.split(',')[0],'').trim() + ',').replace(',,',',').replace(/\,$/g,''));
    }
    }
    if (mlook) { setInterval(eatatjoes, 8000); }
    return outidea;
    }

    “; ?>
    … the appeal of all this being that the dropdown height can be controlled by swapping animation for height extension (and user experience downgrades)
    Animated dropdown setInterval Javascript function (bit like marquee Eat at Joes type of animation (we’ll see if it gets more like it into the future, perhaps?)) …
    <?php echo ”

    function eatatjoes() {
    if (oimstr) {
    if (kimstr >= eval('' + aimstr.length)) {
    kimstr=0;
    oimstr.innerHTML=' ' + aimstr[kimstr];
    } else {
    oimstr.innerHTML=' ' + aimstr[kimstr];
    kimstr++;
    }
    }
    if (opdstr) {
    if (kpdstr >= eval('' + apdstr.length)) {
    kpdstr=0;
    opdstr.innerHTML=' ' + apdstr[kpdstr];
    } else {
    opdstr.innerHTML=' ' + apdstr[kpdstr];
    kpdstr++;
    }
    }
    if (opastr) {
    if (kpastr >= eval('' + apastr.length)) {
    kpastr=0;
    opastr.innerHTML=' ' + apastr[kpastr];
    } else {
    opastr.innerHTML=' ' + apastr[kpastr];
    kpastr++;
    }
    }
    if (offstr) {
    if (kffstr >= eval('' + affstr.length)) {
    kffstr=0;
    offstr.innerHTML=' ' + affstr[kffstr];
    } else {
    offstr.innerHTML=' ' + affstr[kffstr];
    kffstr++;
    }
    }
    }

    “; ?>

… onto yesterday’s Ffmpeg and Pandoc and ImageMagick and Pdfimages Media Tutorial in the changed voiceover.php PHP (we’d want you to download to a local MAMP Apache web server’s Document Root folder and which you can run that PHP there).


Previous relevant Ffmpeg and Pandoc and ImageMagick and Pdfimages Media Tutorial is shown below.

Ffmpeg and Pandoc and ImageMagick and Pdfimages Media Tutorial

Ffmpeg and Pandoc and ImageMagick and Pdfimages Media Tutorial

Onto yesterday’s Ffmpeg and ImageMagick and Pdfimages Media Tutorial

  • ffmpeg … two more media manipulation “verb” stars today …
  • ImageMagick (can help us with new “Images to PDF” option)
  • pdfimages (can help us with new “PDF to Images” option) … “verb” collection, today, we wanted to add …
  • pandoc (can help us with new “Text to HTML” option) …

    If you need to convert files from one markup format into another, pandoc is your swiss-army knife.

… to help improve the “one stop shop” aspects, especially regarding “documents”, to our current Intranet feeling web application in the changed voiceover.php PHP (we’d want you to download to a local MAMP Apache web server’s Document Root folder and which you can run that PHP there).


Previous relevant Ffmpeg and ImageMagick and Pdfimages Media Tutorial is shown below.

Ffmpeg and ImageMagick and Pdfimages Media Tutorial

Ffmpeg and ImageMagick and Pdfimages Media Tutorial

Yesterday’s Ffmpeg Rotate Video Tutorial left you with …

We now present those four in “an expanded out” (at least on non-mobile) dropdown HTML element. Maybe you can guess why?

… and today we are deploying the framework parts and two new media manipulation options regarding PDF that add to our PHP web application’s functionality.

Operating system commands can be thought of to start with …

  • an action item (to be precise a desktop software file specification) … and, what we often think is, like …
  • the command’s “verb” part (as funny as that is to think of a “noun” sounding desktop software file specification being like a “verb”) … verbs being action items in a sentence … down to being essential in any sentence … to the point a “verb” can be the whole sentence

We want to add functionality by adding to our first “verb” …

  • ffmpeg … two more media manipulation “verb” stars today …
  • ImageMagick (can help us with new “Images to PDF” option)
  • pdfimages (can help us with new “PDF to Images” option)

… and to help the “framework” ahead of “shelling peas” we lean on the experience we got from the Animated GIF Creation on Windows MAMP via PDF Tutorial thread of blog postings to deal with …

  • software paths
  • presenting two new “verb” ideas … and us being so fond of dropdowns, we decided to try, for our first time …
    1. start to use three HTML option CSS text-align style choices being left (for ffmpeg), center (for ImageMagick) and right (for pdfimages) … as in …

      … within …

      Add Voiceover Audio to Video via ffmpeg  pdfimages



      <select size=7 onchange=process(this.value,this); style=display:inline-block;font-size:8px; id=schoices><option style=text-align:center; id=mydefopt title='Add Voiceover Audio to Video' value=''>&#10549; Image&#11015;Magick &#10550;</option><option value='Add Voiceover Audio to Video'> Add Voiceover Audio to Video </option><option style='text-align:center;' value='Images to PDF'> Images to PDF</option><option style='text-align:right;' value='PDF to Images'> PDF to Images</option><option value='Burn subtitles'> Burn subtitles</option><option value='Concat demuxer'> Concat demuxer</option><option value='Rotate a video'> Rotate a video</option></select>

      … and then in order to offer the “center” ImageMagick be a link back to the product we introduce some new overlay code
      <?php echo ”

      function overlay() {
      origval=document.getElementById('schoices').value;
      var rect=document.getElementById('fcommand').getBoundingClientRect();
      document.getElementById('moreb').style.position='absolute';
      document.getElementById('moreb').style.left='' + rect.left + 'px';
      document.getElementById('moreb').style.top='' + rect.top + 'px';
      document.getElementById('moreb').style.width='96%'; //' + rect.width + 'px';
      document.getElementById('moreb').style.height='' + rect.height + 'px';
      document.getElementById('moreb').style.border='1px solid black';
      document.getElementById('moreb').style.paddingLeft='20px';
      document.getElementById('moreb').style.backgroundColor='#f9f9f9';
      document.getElementById('fcommand').style.opacity='0.0';
      document.getElementById('fcommand').style.cursor='pointer';
      document.getElementById('moreb').innerHTML='<span id=precmds></span><span id=verb>ffmpeg" . $ffmpegsuf . "</span> <span id=prescbi></span><span id=minusi> -i </span><span id=scbi><iframe onload=checkif(this,\"inv.mp4\"); scrolling=no frameborder=0 id=cbi data-type=file data-value=inv.mp4 data-accept=\"video/*\" style=\"display:inline-block;height:40px;width:92px;vertical-align:middle;\" src=\"/HTMLCSS/client_browsing.htm?d=69075964842271&left=y\"></iframe></span> <span id=betweenis></span> <span id=secondi>-i <span id=scbix><iframe onload=checkiftwo(this,\"inva.mp4\"); scrolling=no frameborder=0 id=cbix data-type=file data-value=inva.mp4 data-accept=\"video/*\" style=\"display:inline-block;height:40px;width:106px;vertical-align:middle;\" src=\"/HTMLCSS/client_browsing.htm?d=69075964842271&right=y\"></iframe></span></span> <span id=sswitches>-c copy -map 0:v:0 -map 1:a:0 -shortest</span> out.mp4 > <a target=_blank title=ffimpdf.bad onclick=getvb(); style=cursor:pointer;text-decoration:underline; data-href=./ffimpdf.bad>ffimpdf.bad</a>';
      if (firstdivih == '') { firstdivih=document.getElementById('moreb').innerHTML; }
      if (firstbutval == '') { firstbutval=document.getElementById('mysub').value; }
      document.getElementById('schoices').style.display='inline-block';


      rect=document.getElementById('schoices').getBoundingClientRect();


      if (eval('' + rect.height) > 100 || 1 == 1) {
      document.getElementById('doverlay').style.position='absolute';
      document.getElementById('doverlay').style.left='' + rect.left + 'px';
      document.getElementById('doverlay').style.top='' + rect.top + 'px';
      document.getElementById('doverlay').style.width='' + rect.width + 'px';
      if (eval('' + rect.height) < 30) {
      document.getElementById('doverlay').style.height='' + rect.height + 'px';
      } else {
      document.getElementById('doverlay').style.height='' + eval(eval('' + rect.height) / eval('' + document.getElementById('schoices').size)) + 'px';
      }
      document.getElementById('doverlay').style.zIndex='96';
      document.getElementById('doverlay').style.textAlign='center';
      document.getElementById('doverlay').style.display='block';
      document.getElementById('doverlay').title=document.getElementById('mydefopt').title;
      //document.getElementById('mydefopt').style.fontColor='transparent';
      document.getElementById('mydefopt').innerHTML='';
      setInterval(fhoc, 1000);
      }



      }


      function fhoc() {
      var rectx=document.getElementById('schoices').getBoundingClientRect();
      document.getElementById('doverlay').style.left='' + rectx.left + 'px';
      document.getElementById('doverlay').title=document.getElementById('mydefopt').title;
      if (document.getElementById('scbi')) {
      if (document.getElementById('scbi').innerHTML.indexOf('<') == -1) {
      if (document.getElementById('scbi').innerHTML.trim().indexOf(' ') != -1) {
      if (document.getElementById('scbi').innerHTML.trim().indexOf(String.fromCharCode(34)) == -1) {
      document.getElementById('scbi').innerHTML=String.fromCharCode(34) + document.getElementById('scbi').innerHTML.trim() + String.fromCharCode(34);
      }
      }
      }
      }
      if (document.getElementById('scbix')) {
      if (document.getElementById('scbix').innerHTML.indexOf('<') == -1) {
      if (document.getElementById('scbix').innerHTML.trim().indexOf(' ') != -1) {
      if (document.getElementById('scbix').innerHTML.trim().indexOf(String.fromCharCode(34)) == -1) {
      document.getElementById('scbix').innerHTML=String.fromCharCode(34) + document.getElementById('scbix').innerHTML.trim() + String.fromCharCode(34);
      }
      }
      }
      }
      }


      “; ?>

  • Javascript to set up the HTML div contenteditable=true look for these two new options …
    <?php echo ”

    if (newv == 'PDF to Images') {
    document.getElementById('moreb').innerHTML=firstdivih.replace(' out.mp4',' " . $minuspng . "');
    document.getElementById('secondi').innerHTML='';
    document.getElementById('sswitches').innerHTML=\"<span id=sfolder contenteditable=false>newfolder_" . rand(0,784534) . str_replace("\\","\\\\",$ddn) . "\" + '</span>ideas';

    document.getElementById('precmds').innerHTML=' ';
    document.getElementById('verb').innerHTML='" . $pdfimages . $pdfimagessuf . "';
    document.getElementById('scbi').innerHTML=document.getElementById('scbi').innerHTML.replace(/inv\.mp4/g,'inv.pdf ');
    document.getElementById('minusi').innerHTML=' -j ';

    document.getElementById('mysub').value=newv;
    } else if (newv == 'Images to PDF') {
    document.getElementById('moreb').innerHTML=firstdivih.replace('out.mp4','out.pdf');

    document.getElementById('precmds').innerHTML=' ';
    document.getElementById('secondi').innerHTML='';
    document.getElementById('verb').innerHTML='" . $magickverb . $magicksuf . "';
    document.getElementById('sswitches').innerHTML='-auto-orient';
    document.getElementById('sswitches').title='To perform a folder of images (only, we suggest) right click or two finger guesture to left and enter the folder name only';
    document.getElementById('scbi').innerHTML=document.getElementById('scbi').innerHTML.replace(/inv\.mp4/g,'inv.jpg ');
    document.getElementById('minusi').innerHTML='';
    document.getElementById('scbi').setAttribute('contenteditable', true);
    document.getElementById('scbi').onblur=function(event) { if (document.getElementById('mydefopt').title == 'Images to PDF') { if (event.target.innerHTML.replace(/\ \;/g,' ').trim() == '') { event.target.innerHTML='folder' + \"" . str_replace("\\","\\\\",$ddn) . "*\"; } if (event.target.innerHTML.toLowerCase().indexOf('.txt') == -1) { if (event.target.innerHTML.indexOf('.') != -1) { document.getElementById('ifs').innerHTML+='<iframe id=voaskfor' + ifile + ' style=display:none; src=\"./voiceover.php?infilegetsize=' + encodeURIComponent(listtxt + ';' + event.target.innerHTML) + '\"></iframe>'; ifile++; if (document.getElementById('moreb').title.indexOf(\"file '\" + event.target.innerHTML.replace(String.fromCharCode(34),'').replace(String.fromCharCode(34),'') + \"'\") == -1) { document.getElementById('moreb').title+=String.fromCharCode(10) + \"file '\" + event.target.innerHTML.replace(String.fromCharCode(34),'').replace(String.fromCharCode(34),'') + \"'\"; } } } event.target.innerHTML=listtxt; if (document.getElementById('minusi')) { document.getElementById('minusi').innerHTML=''; } } };
    document.getElementById('moreb').onblur=function(event) { if (document.getElementById('mydefopt').title == 'Images to PDF') { if (document.getElementById('minusi')) { var thingos=document.getElementById('minusi').innerHTML.replace(/\ \;/g,' ').trim().split('-i '); if (thingos.length > 1) { if (thingos[1].trim() != '' && (thingos[1] + '~').toLowerCase().indexOf('.txt~') == -1) { spanfill(thingos[1]); } } document.getElementById('minusi').innerHTML=''; } if (!document.getElementById('scbi')) { event.target.innerHTML=event.target.innerHTML.replace('<span id=\"between', '<span id=scbi contenteditable=true>' + listtxt + '</span> <span id=\"between'); putbackonblur(); if (event.target.innerHTML.indexOf('> -i </span><span id=\"scbi\"') == -1) { event.target.innerHTML=event.target.innerHTML.replace('</span>' + event.target.innerHTML.split('<span id=\"scbi\"')[0].split('</span>')[-1 + eval(event.target.innerHTML.split('<span id=\"scbi\"')[0].split('</span>').length)],'</span>'); } } } };
    document.getElementById('moreb').oncontextmenu=function(event) { document.getElementById('scbi').innerHTML='folder' + \"" . str_replace("\\","\\\\",$ddn) . "*\"; };


    document.getElementById('mysub').value=newv;
    }

    “; ?>
  • the performing of those two new “verb” ideas …
    <?php

    $pfolder='';
    $ppdf='';

    // ... later ...
    $cmdis=str_replace('+',' ',urldecode($_GET['fcommand']));
    if (PHP_OS =='WINNT' || PHP_OS =='WIN32' || PHP_OS =='Windows') {
    if ($ffmpegpre != '' && strpos($cmdis, 'ffmpeg.') !== false && strpos($cmdis, $ffmpegpre) === false) {
    $cmdis=str_replace('ffmpeg.', $ffmpegpre . 'ffmpeg.', $cmdis);
    }
    if ($magickpre != '' && strpos($cmdis, $magickverb . '.') !== false && strpos($cmdis, $magickpre) === false) {
    $cmdis=str_replace($magickverb . '.', $magickpre . $magickverb . '.', $cmdis);
    }
    if ($pdfimagespre != '' && strpos($cmdis, 'pdfimages.') !== false && strpos($cmdis, $pdfimagespre) === false) {
    $cmdis=str_replace('pdfimages.', $pdfimagespre . 'pdfimages.', $cmdis);
    }
    }

    $precmd=explode('>', $cmdis);
    if (strpos($cmdis, 'pdfimages') !== false && strpos($cmdis, 'newfolder_') !== false) {
    $pfolder='newfolder_' . explode(DIRECTORY_SEPARATOR, explode('newfolder_', $cmdis)[1])[0];
    $beforep=explode($pfolder, $cmdis)[0];
    $afterp=explode($pfolder, $cmdis)[1];
    while (file_exists($pfolder)) {
    $pfolder='newfolder' . '_' . explode('newfolder', $pfolder)[1];
    $cmdis=$beforep . $pfolder . $afterp;
    }
    if (!file_exists($pfolder)) { mkdir($pfolder); }
    }

    // ... later ...
    $outf=$subcmd[1];
    // ... later ...
    if (strpos(strtolower(trim($outf) . '~'), '.pdf~') !== false) {
    $ppdf=trim($outf);
    }

    // ... later ...
    $rs=shell_exec($cmdis);

    // ... later ...
    if ($pfolder != '') {
    $rs.="<br><br>";
    foreach (glob($pfolder . DIRECTORY_SEPARATOR . '*.*') as $ifilename) {
    $rs.='<img title="' . $ifilename . '" src="' . $ifilename . '?rand=' . rand(0,7654532) . '"></img>';
    }
    }
    if ($ppdf != '') {
    $outf='';
    $rs.="<br><br><iframe style='width:98%;height:800px;' src='" . $ppdf . "?rand=" . rand(0,7654532) . "' title='" . $ppdf . "'></iframe>";
    }

    ?>

… in the changed voiceover.php PHP (we’d want you to download to a local MAMP Apache web server’s Document Root folder and which you can run that PHP there).


Previous relevant Ffmpeg Rotate Video Tutorial is shown below.

Ffmpeg Rotate Video Tutorial

Ffmpeg Rotate Video Tutorial

It’s getting closer to “shelling peas”, are today’s “Rotate a video via ffmpeg” changes, but we are not there yet. Yes, most programmers want to be “shelling peas” adding functionality to web applications, once they have set up a framework in which they are happy to work. Yesterday’s Ffmpeg Concat Demuxer Tutorial “defence talk” is getting us closer to that “shelling peas” “homeostasis feel” (with an “Intranet” pike, no doubt?!) as you can see from a Javascript “Rotate a video” code snippet below …

<?php echo ”

if (newv == 'Rotate a video') {
document.getElementById('moreb').innerHTML=firstdivih;

document.getElementById('precmds').innerHTML=' ';
document.getElementById('secondi').innerHTML='';


document.getElementById('sswitches').innerHTML='<span id=notranspose contenteditable=false>-vf \"transpose=</span><span id=transpose contenteditable=true>1</span><span id=nottranspose contenteditable=false>\" </span>';
document.getElementById('sswitches').title='" . str_replace("\n", "' + String.fromCharCode(10) + '",$rotateadvice) . "';
document.getElementById('sswitches').oncontextmenu=function(event) { alert(event.target.title); };

document.getElementById('mysub').value=newv;
}

“; ?>

… effectively straightjacketing the crucial …


-vf "transpose=1"

… ffmpeg switch definition, by the user, to changing that 1 above as per the hover over advice, to help the user, straight from Mux Video and Audio from another Video, thanks, to advise …

<?php

$rotateadvice="Rotate a video

Rotate 90 clockwise:

ffmpeg -i in.mov -vf \"transpose=1\" out.mov
For the transpose parameter you can pass:

0 = 90CounterCLockwise and Vertical Flip (default)
1 = 90Clockwise
2 = 90CounterClockwise
3 = 90Clockwise and Vertical Flip

Use -vf \"transpose=2,transpose=2\" for 180 degrees.";

?>

Yes, the user can still put a bad entry there, but at least the web application has attempted to point them in the right direction, here.

If you examine the changes the changed voiceover.php PHP (we’d want you to download to a local MAMP Apache web server’s Document Root folder and which you can run that PHP there), am sure that you will concur

  • Concat demuxer concatenation of videos ffmpeg functionality, onto the “as of yesterday” …
  • Voiceovers … and …
  • Burn subtitles
  • Rotate a video

… was the simplest functionality component, yet, of the four. We now present those four in “an expanded out” (at least on non-mobile) dropdown HTML element. Maybe you can guess why?


Previous relevant Ffmpeg Concat Demuxer Tutorial is shown below.

Ffmpeg Concat Demuxer Tutorial

Ffmpeg Concat Demuxer Tutorial

Onto yesterday’s Ffmpeg Burn Subtitles Tutorial work we’re still not up to “shelling any peas” adding in …

  • Concat demuxer concatenation of videos ffmpeg functionality, onto the “as of yesterday” …
  • Voiceovers … and …
  • Burn subtitles

… progress.

What’s different this time? Well, ffmpeg works the command, we again thank Mux Video and Audio from another Video for (regarding “the plan”), using an interim file …

Concat demuxer

First, make a text file.

file ‘in1.mp4’
file ‘in2.mp4’
file ‘in3.mp4’
file ‘in4.mp4’

Then, run ffmpeg :

ffmpeg -f concat -i list.txt -c copy out.mp4

… and for File API browsing (with our, once again, tweaked inhouse client_browsing.htm) there will be a delay, deriving the file path in “second call PHP”. We handle this by writing two new Javascript functions …

<?php echo ”

var ifile=0, ibfile=0;

function takeoffone() {
ibfile--;
if (ibfile <= 0) {
document.getElementById('mysub').style.cursor='pointer';
} else {
document.getElementById('mysub').style.cursor='progress';
}
}

function organizefilenamesize(fn, fs) {
document.getElementById('ifs').innerHTML+='<iframe id=voaskfor' + ifile + ' style=display:none; src=\"./voiceover.php?concat=' + encodeURIComponent('list.txt') + '&filename=' + encodeURIComponent(fn) + '&haveasleep=' + eval(3 * eval('' + ifile)) + '&filesize=' + fs + '\"></iframe>';
if (ibfile == 0) {
document.getElementById('mysub').style.cursor='progress';
}
ifile++;
ibfile++;
if (document.getElementById('moreb').title.indexOf(\"file '\" + fn.replace(String.fromCharCode(34),'').replace(String.fromCharCode(34),'') + \"'\") == -1) {
document.getElementById('moreb').title+=String.fromCharCode(10) + \"file '\" + fn.replace(String.fromCharCode(34),'').replace(String.fromCharCode(34),'') + \"'\";
}
}

“; ?>

… available to call from child iframes via parent.takeoneoff(); (from voiceover.php second PHP call) and parent.organizefilenamesize(files[ij].name, files[ij].size); (from client_browsing.htm) respectively, to facilitate a progress cursor on the submit button to remind the user we’d like more time. Along the way, too, we found


ffmpeg -f concat -safe 0 -i list.txt -c copy out.mp4

… thanks to the excellent advice we found at this webpage.

You can see this work in the changed voiceover.php PHP (we’d want you to download to a local MAMP Apache web server’s Document Root folder and which you can run that PHP there).

Did you know?

Just like the use of …

… are the SpongeBob, Patrick, and Squidward of the online woooorrrrllllddd, in an “offence” line of “piecing together an operating system command” thinking, thinking “defence” regarding this we added one (we were pleasantly surprised to discover worked, so as) to have …

  • div contenteditable=true
  • spanizing within that div
  • innerText
  • mask off parts the programmer wants left untouched via span contenteditable=false

… being like the Hall and Oates meets Everything But the Girl (on a yacht, of course) step back into the ’80s!

Take a look at some tweaks


if (newv == 'Burn subtitles') {
document.getElementById('moreb').innerHTML=firstdivih;
//document.getElementById('precmds').innerHTML=document.getElementById('verb').innerHTML + ' ' + document.getElementById('secondi').innerHTML.replace(/inva\.mp4/g,'sub.srt ') + ' sub.ass; ';
document.getElementById('precmds').innerHTML=document.getElementById('verb').innerHTML + ' ' + document.getElementById('secondi').innerHTML.replace(/inva\.mp4/g,'sub.srt ') + ' <span id=subass contenteditable=false>sub.ass;</span> ';
document.getElementById('secondi').innerHTML='';
//document.getElementById('sswitches').innerHTML='-vf ass=sub.ass';
document.getElementById('sswitches').innerHTML='-vf<span id=asssubass contenteditable=false> ass=sub.ass </span>';
document.getElementById('mysub').value=newv;
}

… in a “Burn subtitles” relevant Javascript code snippet.


Previous relevant Ffmpeg Burn Subtitles Tutorial is shown below.

Ffmpeg Burn Subtitles Tutorial

Ffmpeg Burn Subtitles Tutorial

The initial inspiration for this current ffmpeg themed series of blog posting was, and still is, Mux Video and Audio from another Video, thanks. So many great ideas, we found, that today we add onto the …

  • first idea of Voiceovers we’ve established to work with MAMP in macOS and Windows over the previous days, allowing us to now think to add a first suboption idea of …
  • Burn subtitles … as per our link’s …

    Burn subtitles
    Use the libass library (make sure your ffmpeg install has the library in the configuration –enable-libass).

    First convert the subtitles to .ass format:

    ffmpeg -i sub.srt sub.ass
    Then add them using a video filter:

    ffmpeg -i in.mp4 -vf ass=sub.ass out.mp4

… as a useful video piece of functionality we’d say.

To get this going, easily (from a programming perspective) …

  • our textarea element remains as the form conduit to the ffmpeg command via the onsubmit event final analysis of the …
  • underlying div contenteditable=true is “spanned” up a lot more as per …
    <?php echo ”

    document.getElementById('moreb').innerHTML='<span id=precmds></span><span id=verb>ffmpeg" . $ffmpegsuf . "</span> -i <span id=scbi><iframe onload=checkif(this,\"inv.mp4\"); scrolling=no frameborder=0 id=cbi data-type=file data-value=inv.mp4 data-accept=\"video/*\" style=\"display:inline-block;height:40px;width:92px;vertical-align:middle;\" src=\"/HTMLCSS/client_browsing.htm?d=9075964842271&left=y\"></iframe></span> <span id=betweenis></span> <span id=secondi>-i <span id=scbix><iframe onload=checkiftwo(this,\"inva.mp4\"); scrolling=no frameborder=0 id=cbix data-type=file data-value=inva.mp4 data-accept=\"video/*\" style=\"display:inline-block;height:40px;width:106px;vertical-align:middle;\" src=\"/HTMLCSS/client_browsing.htm?d=9075964842271&right=y\"></iframe></span></span> <span id=sswitches>-c copy -map 0:v:0 -map 1:a:0 -shortest</span> out.mp4 > <a target=_blank title=ffm.bad onclick=getvb(); style=cursor:pointer;text-decoration:underline; data-href=./ffm.bad>ffm.bad</a>';

    “; ?>
    … and at the onsubmit event Javascript the innerText attribute usage makes it fairly easy to say
    <?php echo ”

    function mergechanges() {
    if (document.getElementById('scbi').innerHTML.indexOf('<') == -1) {
    if (document.getElementById('precmds').innerHTML != '') {
    document.getElementById('fcommand').value=document.getElementById('moreb').innerText;
    } else {

    document.getElementById('fcommand').value=document.getElementById('fcommand').value.replace(' inv.mp4 ', ' ' + document.getElementById('scbi').innerHTML + ' ');
    }
    //alert('not oops ' + document.getElementById('fcommand').value);
    } //else {
    //alert('oops');
    //}
    if (document.getElementById('scbix').innerHTML.indexOf('<') == -1) {
    //alert('zoops');
    document.getElementById('fcommand').value=document.getElementById('fcommand').value.replace(' inva.mp4 ', ' ' + document.getElementById('scbix').innerHTML + ' ');
    }
    if (document.getElementById('moreb').innerText.indexOf(' -c ') != -1 && document.getElementById('fcommand').value.indexOf(' -c ') != -1) {
    //alert('azoops');
    if (document.getElementById('moreb').innerText.split(' -c ')[1] != document.getElementById('fcommand').value.split(' -c ')[1]) {
    //alert('bzoops');
    document.getElementById('fcommand').value=document.getElementById('fcommand').value.split(' -c ')[0] + ' -c ' + document.getElementById('moreb').innerText.split(' -c ')[1];
    }
    }
    return true;
    }

    “; ?>
    … to slice through that “span” complexity like margarine (or butter that’s been left out on a hot day for approximately 7 hours 17 minutes 23 seconds)

And so, onto yesterday’s Ffmpeg Improved Windows Media Browsing Tutorial feel free to see this in the changed voiceover.php PHP (we’d want you to download to a local MAMP Apache web server’s Document Root folder and which you can run that PHP there).


Previous relevant Ffmpeg Improved Windows Media Browsing Tutorial is shown below.

Ffmpeg Improved Windows Media Browsing Tutorial

Ffmpeg Improved Windows Media Browsing Tutorial

Yesterday’s Ffmpeg Mux Video and Audio Windows Media Browsing Tutorial taught us a lesson, as a side issue, that what we said when we presented Animated GIF Creation on Windows MAMP via PDF Tutorial

No matter how we tried, we could not get a Windows command line command like …


forfiles /P "[PathToFileBestGuess]" /S /M "[FileBaseName]" /C "cmd /c echo @path@fsize" | find "[FileSizeInBytes]"

… to work out a file path when supplied a file base name and a file size and you call as above with starting folders. That works well (for deriverability (if that is a word!)) in the “cmd” window but not when called under the auspices of PHP exec or shell_exec. It could be that you lose a lot of a Windows user environment when asking PHP to do some operating system work.

… was “only partially” the story. We found out that that ” | find ” command piping could cause problems on Windows MAMP using shell_exec or exec to do some operating system functionality. But before your enthusiasm oozes over the edges, Windows “forfiles” is still very hard to get working with PHP shell_exec or exec, even using PHP to perform that ” | find ” filtering of results.

However, on revisiting the issue in the changed voiceover.php PHP (we’d want you to download to a local MAMP Apache web server’s Document Root folder and which you can run that PHP there) there were dual purpose motivations going on, for us, because our changed animated GIF creator PHP tutorial_to_animated_gif.php (that if you download to MAMP would best go to Document Root PHP/animegif folder along with the wonderful GIFEncoder.class.php … thanks) inhouse animated GIF creator web application and the changed PDF parts to animated GIF creation helper php_calls_pdfimages.php (also a standalone proposition) PHP code could be fixed up at the same time, with a new PHP ourshell_exec function interventional code snippet up at the top …

<?php

function ourshell_exec($onea, $twoa = NULL, $threea = NULL) {
$folder='';
$pattern='';
$size='';
$filesa=[];
if (PHP_OS =='WINNT' || PHP_OS =='WIN32' || PHP_OS =='Windows' || (strpos(('~@!' . $onea), '~@!forfiles /P "') !== false && strpos(('~@!' . $onea), '/M "') !== false && strpos(('~@!' . $onea), 'find "') !== false)) {
$folder=explode('"', explode('forfiles /P "', $onea)[1])[0]; // . substr(DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR, 0, 1);
if (7 == 7) {
$folder=explode('"', explode('forfiles /P "', $onea)[1])[0]; // . substr(DIRECTORY_SEPARATOR . DIRECTORY_SEPARATOR, 0, 1);
$pattern=explode('"', explode('/M "', $onea)[1])[0];
$size=explode('"', explode('find "', $onea)[1])[0];
$thiscmd=trim(explode(" | find ", $onea)[0]);
if (strpos($pattern, ' ') === false) { $thiscmd=str_replace('/M "' . $pattern . '"', '/M ' . $pattern, $thiscmd); }
if (strpos($folder, ' ') === false) { $thiscmd=str_replace('/P "' . $folder . '"', '/P ' . $folder, $thiscmd); }
if (strpos($thiscmd, '"cmd /c ') !== false && substr($thiscmd,-1,1) != '"') { $thiscmd.='"'; }
if (strpos($thiscmd, "/P C:\\ ") !== false) {
if (strpos($thiscmd, "/P C:\\ ") !== false) {
if (strpos($pattern, " ") === false) {
$thiscmd="DIR C:\\" . $pattern . " /S /-C";
} else {
$thiscmd="DIR \"C:\\" . $pattern . "\" /S /-C";
}
}
}
//file_put_contents('xxx.xxx',file_get_contents('xxx.xxx'). "\n" . '' . $size . ' ' . $thiscmd);
$nofind=shell_exec($thiscmd . ' 2> nul');

//file_put_contents('xxxx.xxxx',file_get_contents('xxxx.xxxx'). "\n" . '' . $size . ' ' . $nofind);
//exit;
$findings=explode("\n", $nofind);
$bitbefore='';
for ($ifindgs=0; $ifindgs<sizeof($findings); $ifindgs++) {
if (strpos(str_replace("\r","",$findings[$ifindgs]), 'Directory of ') !== false) {
$bitbefore=explode('Directory of ', str_replace("\r","",$findings[$ifindgs]))[1] . "\\";
}
if (strpos((str_replace("\r","",$findings[$ifindgs]) . '~'), $size . '~') !== false) {
return str_replace('~','',str_replace($size . '~', '', (str_replace("\r","",$findings[$ifindgs]) . '~')));
} else if (strpos((str_replace("\r","",$findings[$ifindgs]) . ''), $size . ' ') !== false) {
//file_put_contents('xxxxx.xxxxx',$bitbefore . explode($size . ' ', (str_replace("\r","",$findings[$ifindgs]) . ''))[1]);
return $bitbefore . explode($size . ' ', (str_replace("\r","",$findings[$ifindgs]) . ''))[1];
}
}
if ($folder == "C:\\") { return ''; }
}

// more code
// as per usual
// stays here ...
}
return shell_exec($onea, $twoa, $threea);
}

?>

… where we substitute in Windows DIR C:\ /S /-C thinking in place of forfiles (via shell_exec minus the ” | find ” piping, that is).


Previous relevant Ffmpeg Mux Video and Audio Windows Media Browsing Tutorial is shown below.

Ffmpeg Mux Video and Audio Windows Media Browsing Tutorial

Ffmpeg Mux Video and Audio Windows Media Browsing Tutorial

You know it’s “Intranet feely land”?

You look out the train window (tee hee) and see macOS racing through their usual routine.

Of course you’ll pick the buffet car containing the rice bubbles ahead of the vegemite corn flakes?!

But do we need to reiterate that in “Intranet feely land” you’ve got your macOS typose of work not suiting “arch Windows” methodologies? Take the case of …

At least, with macOS MAMP there is the excellent command line “file” we can use to show information about some potential input files you could use in this, so far, user unfriendly, “first draft” version of the PHP.

… to the beach, would be nice … but we digress. Well, in any case, we asked Google (not via the “arch Window”) does windows have the equivalent of linux file command” and got to the helpful What is the equivalent to the Linux File command for windows? – Super User, thanks, and then ended up at the really useful third party “file.exe” for (non-arch) Windows usage and proceeded with it, working off Ffmpeg Mux Video and Audio Media Browsing Tutorial, to start being able to develop this “reveal” details/summary arrangement in either macOS or Windows MAMP environments, that “ffmpeg” voiceover command, which normally works a lot better than …

I command thee mux, hey you, with audible you, over yonder, by dale and meadow be, yea!

… when it occurred to us we could turn the base filename parts of those “file.exe” reports into links that when clicked mapped those clicked files into place into the “ffmpeg” command being developed above (as alternative input file designator idea to browsing or div contenteditable=true typing ways), in the changed voiceover.php PHP (we’d want you to download to a local MAMP Apache web server’s Document Root folder) and which you can run that PHP there.

And so, we reckon the work day got worth it!


Previous relevant Ffmpeg Mux Video and Audio Media Browsing Tutorial is shown below.

Ffmpeg Mux Video and Audio Media Browsing Tutorial

Ffmpeg Mux Video and Audio Media Browsing Tutorial

Onto yesterday’s Ffmpeg Mux Video and Audio Primer Tutorial

There be a flowerin’ of inner warmth and glo’ towards all our readers, youngins and oldins alike … like!

Yes, we’re involving good ol’ HTML5 File API Object Javascript logic, so our “Intranet” savvy downloaders out there …

Full o’ inner warmth and glo’ towards each other … like!

… can easily browse for their two media input files, and for the first time ever integrating our ever tweaked inhouse client_browsing.htm (also a standalone proposition) (we’d like you to download to MAMP Document Root’s HTMLCSS subfolder) we add “oncontextmenu” event changes to its input type=file browser hosting parent iframe element onload event Javascript function as per

<?php echo ”

var voaf='', voaftwo='';

function checkif(iois, ival) {
if (iois.src.indexOf('?d=') != -1) {
var aconto = (iois.contentWindow || iois.contentDocument);
if (aconto != null) {
if (aconto.document) { aconto = aconto.document; }
if (aconto.getElementById('files')) {
if (voaf == '') {
voaf=iois.src;
iois.setAttribute('data-parentspan', 's' + ival.replace('inv.mp4','cbi').replace('inva.mp4','cbix'));
document.getElementById('myh1').title='s' + ival.replace('inv.mp4','cbi').replace('inva.mp4','cbix');
document.getElementById('myh1').setAttribute('data-url', iois.src);
setInterval(voaff, 1000);
} else if (voaftwo == '') {
voaftwo=iois.src;
iois.setAttribute('data-parentspan', 's' + ival.replace('inv.mp4','cbi').replace('inva.mp4','cbix'));
document.getElementById('myh3').title='s' + ival.replace('inv.mp4','cbi').replace('inva.mp4','cbix');
document.getElementById('myh3').setAttribute('data-url', iois.src);
//alert(iois.id + ' data-parentspan=' + iois.getAttribute('data-parentspan'));
}
//alert(iois.id + ' data-parentspan=' + iois.getAttribute('data-parentspan'));
aconto.getElementsByTagName('h1')[0].style.opacity='0.0';
//alert('here');
aconto.getElementById('files').style.position='absolute';
aconto.getElementById('files').style.left='0px';
aconto.getElementById('files').style.top='0px';
aconto.getElementById('files').style.zIndex='99';
aconto.getElementById('files').style.marginLeft='10px';
aconto.getElementById('files').style.marginTop='8px';
aconto.getElementById('files').style.visibility='visible';
aconto.getElementById('files').style.display='block';
aconto.getElementById('files').style.backgroundColor='#eeeeee';
aconto.getElementById('files').setAttribute('data-hostcont', ival);
aconto.getElementById('files').setAttribute('data-hostspan', 's' + ival.replace('inv.mp4','cbi').replace('inva.mp4','cbix'));
aconto.getElementById('files').oncontextmenu = function(event) { var suf=event.target.getAttribute('data-hostspan'); parent.document.getElementById(suf).innerHTML=\"" . str_replace("\\","\\\\",dirname(__FILE__) . DIRECTORY_SEPARATOR) . "\" + event.target.getAttribute('data-hostcont'); }
if (ival == 'inv.mp4') {
aconto.getElementById('files').accept='video/*';
aconto.getElementById('files').title='Click to browse for video else right click or two finger gesture to make disappear.';
} else {
aconto.getElementById('files').accept='video/*,audio/*';
aconto.getElementById('files').title='Click to browse for video or audio else right click or two finger gesture to make disappear.';
}
//alert('there');
aconto.getElementById('dwstyle').innerHTML+=\"<style> #files::before { content: '\" + ival + \"'; } </style>\";
}
}
}
}

“; ?>

… to allow a user who prefers the overlayed div contenteditable=true alternative (which speaks back to the HTML form textarea conduit when that form’s “onsubmit” event is called) onto yesterday’s exclusively textarea methodology

<?php echo ”

function overlay() {
var rect=document.getElementById('fcommand').getBoundingClientRect();
document.getElementById('moreb').style.position='absolute';
document.getElementById('moreb').style.left='' + rect.left + 'px';
document.getElementById('moreb').style.top='' + rect.top + 'px';
document.getElementById('moreb').style.width='96%'; //' + rect.width + 'px';
document.getElementById('moreb').style.height='' + rect.height + 'px';
document.getElementById('moreb').style.border='1px solid black';
document.getElementById('moreb').style.paddingLeft='20px';
document.getElementById('moreb').style.backgroundColor='#f9f9f9';
document.getElementById('fcommand').style.opacity='0.0';
document.getElementById('moreb').innerHTML='ffmpeg" . $ffmpegsuf . " -i <span id=scbi><iframe onload=checkif(this,\"inv.mp4\"); scrolling=no frameborder=0 id=cbi data-type=file data-value=inv.mp4 data-accept=\"video/*\" style=\"display:inline-block;height:40px;width:92px;vertical-align:middle;\" src=\"/HTMLCSS/client_browsing.htm?d=975964842271&left=y\"></iframe></span> -i <span id=scbix><iframe onload=checkiftwo(this,\"inva.mp4\"); scrolling=no frameborder=0 id=cbix data-type=file data-value=inva.mp4 data-accept=\"video/*\" style=\"display:inline-block;height:40px;width:106px;vertical-align:middle;\" src=\"/HTMLCSS/client_browsing.htm?d=975964842271&right=y\"></iframe></span> -c copy -map 0:v:0 -map 1:a:0 -shortest out.mp4 > voiceover.bad';
}

function mergechanges() {
if (document.getElementById('scbi').innerHTML.indexOf('<') == -1) {
document.getElementById('fcommand').value=document.getElementById('fcommand').value.replace(' inv.mp4 ', ' ' + document.getElementById('scbi').innerHTML + ' ');
//alert('not oops ' + document.getElementById('fcommand').value);
} //else {
//alert('oops');
//}
if (document.getElementById('scbix').innerHTML.indexOf('<') == -1) {
document.getElementById('fcommand').value=document.getElementById('fcommand').value.replace(' inva.mp4 ', ' ' + document.getElementById('scbix').innerHTML + ' ');
}
if (document.getElementById('moreb').innerText.indexOf(' -c ') != -1 && document.getElementById('fcommand').value.indexOf(' -c ') != -1) {
if (document.getElementById('moreb').innerText.split(' -c ')[1] != document.getElementById('fcommand').value.split(' -c ')[1]) {
document.getElementById('fcommand').value=document.getElementById('fcommand').value.split(' -c ')[0] + ' -c ' + document.getElementById('moreb').innerText.split(' -c ')[1];
}
}
return true;
}


“; ?>

… reign supreme collecting their media file specification information in the changed voiceover.php PHP (we’d want you to download to a local MAMP Apache web server’s Document Root folder) and which you can run that PHP there.

The previous work of Animated GIF Creation Install Paths Tutorial‘s thread of blog postings has been a great help with this ffmpeg “Intranet feeling” integration work we use, around here, in conjunction with macOS or Windows operating system MAMP Apache local web server environments.


Previous relevant Ffmpeg Mux Video and Audio Primer Tutorial is shown below.

Ffmpeg Mux Video and Audio Primer Tutorial

Ffmpeg Mux Video and Audio Primer Tutorial

We’ve got another “Intranet feeling” PHP web application “first draft” for you today. The reason we’re opting for “Intranet feeling” (ie. we’re asking you to download the voiceover.php PHP to a local MAMP Apache web server and run the PHP there from its Document Root folder) is that we want to further explore the brilliant …


ffmpeg -i inv.mp4 -i inva.mp4 -c copy -map 0:v:0 -map 1:a:0 -shortest out.mp4

… we got inspired to try via Mux Video and Audio from another Video and FFMPEG mux video and audio (from another video) – mapping issue … thanks and thanks … to add audio to a video stream from two different sources.

At least, with macOS MAMP there is the excellent command line “file” we can use to show information about some potential input files you could use in this, so far, user unfriendly, “first draft” version of the PHP.

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.


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 Animation, eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , | Leave a comment

Image Filter Display Tutorial

Image Filter Display Tutorial

Image Filter Display Tutorial

We’re glad today’s “Image Filter Display Tutorial” blog posting title is shorter than yesterday’s “Animated GIF Duration Calculation Filter Browsing Tutorial” because the main task today was …

  • to take all our “proof of concept” web applications and distil them down to an “Image Filter Display” web application of far greater simplicity … and along that way …
  • we had to play around with one more “proof of concept” idea, that of allowing the user to control the content of the CSS filters dropdown, and our first “out there” thought that contenteditable=true could be applied to all the dropdown’s option elements to achieve this needed to be disproved (as it took two hours to be sure of … to be sure) … in favour of a new dropdown “Change” option solution …

    function callresell() {
    var oselo=document.getElementById('simgag');
    var svalis='';
    var sc=';';
    var changefound=false;
    if (document.getElementById('imgag')) {
    oselo.value=document.getElementById('imgag').title;
    }
    var reselit=prompt('Please change the semicolon separated options list. Optionally hash # separate a CSS filter refresh interval in seconds (currently ' + eval(Math.abs(ingifint) / 1000.000) + ' seconds).', oselo.innerText);
    if (reselit != null) {
    if (reselit.indexOf('#') != -1) {
    if (ingifint < 0) {
    ingifint=Math.round(eval(-1000.0 * eval('' + reselit.split('#')[1].split(';')[0])));
    } else {
    ingifint=Math.round(eval(1000.0 * eval('' + reselit.split('#')[1].split(';')[0])));
    }
    reselit=reselit.replace('#' + reselit.split('#')[1].split(';')[0], '');
    }
    }
    if (reselit == null) {
    return '';
    } else if (reselit != oselo.innerText) {
    var sih=oselo.innerHTML;
    var vsl=reselit.split(';');
    var shi=sih.split('</option>');
    var ssize='' + oselo.size;
    var vssize=0;
    var newih='';
    for (var ihi=0; ihi<vsl.length; ihi++) {
    if (vsl[ihi].trim() != '') {
    if (vsl[ihi].trim() == 'Change') { changefound=true; sc=''; } else { sc=';'; }
    if (eval('' + shi.length) > ihi) {
    if (eval('' + (shi[ihi] + '</option>').split(vsl[ihi].trim() + sc).length) == 3) {
    newih+=shi[ihi] + '</option>';
    vssize++;
    } else {
    svalis=shi[ihi].split(' value="')[1].split('"')[0];
    newih+=shi[ihi].split('>')[0].replace(svalis, vsl[ihi].trim() + sc) + '>' + vsl[ihi].trim() + sc + '</option>';
    vssize++;
    }
    } else if (vsl[ihi].trim().indexOf('filter:') == 0) {
    newih+='<option contenteditable=true value="' + vsl[ihi].trim() + sc + '">' + vsl[ihi].trim() + sc + '</option>';
    vssize++;
    } else {
    newih+='<option contenteditable=true value="' + vsl[ihi].trim() + '">' + vsl[ihi].trim() + '' + '</option>';
    vssize++;
    }
    }
    }
    if (!changefound) {
    newih+='<option contenteditable=true value="Change">Change</option>';
    vssize++;
    }
    oselo.innerHTML=newih;
    if (eval('' + ssize) != eval('' + vssize)) {
    oselo.size='' + eval('' + vssize);
    }
    }
    return '';
    }

    … and …
  • in the image browsing helper we needed to allow for non animated GIF images, as we did for our new image_css_filter_display.html “first draft” “Image Filter Display” web application”

And so, onto yesterday’s Animated GIF Duration Calculation Filter Browsing Tutorial we developed, today, a changed client_browsing.htm helper web application you can try for yourself as a standalone arrangement or have it get called via today’s changed read_exif_off_image_rotate.php PHP image exif reporter web application.


Previous relevant Animated GIF Duration Calculation Filter Browsing Tutorial is shown below.

Animated GIF CSS Filter Browsing Tutorial

Animated GIF Duration Calculation Filter Browsing Tutorial

Can a “proof of concept” arrangement last three blog postings? If there’s more you want to prove, ahead of committing to the final product that might hone in on the specificity of the idea, and another iframe hosted web application joins in on “proof of concept” goings on and will be useful into the future, we’d say it’s possible, yes. But we would say that, wouldn’t we?!

In our defence, it is easier to prove all solutions to all the contentious issues, and then hone in and reduce to make a specific new web application, rather than extending and still needing to prove as you go along, not knowing whether an issue will cause you insurmountable issues in the future.

But they would say that, wouldn’t they?!

And so, continuing on from the recent Animated GIF Duration Calculation Filter Tutorial we considered another mode that a user might use on top of …

  • entering an image (animated GIF) URL into a textbox … that being to …
  • browse for a local system (animated GIF) file (via File API)

… getting us to call on changes to our “via File API” specialist with a changed (with new data URI supporting Javascript) …


var ingif='', ingifstyle='filter: none;', ingifint=0, ingifchosen=false, isag=-1, isagname='';

function prefetch(whatgifmaybe) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
if ((whatgifmaybe.toLowerCase().trim().split('#')[0] + '?').indexOf('.gif?') != -1 || whatgifmaybe.indexOf('data:image/gif') == 0) {
ingif=whatgifmaybe;
document.body.style.cursor='progress';
fetch(whatgifmaybe)
.then(res => res.arrayBuffer())
.then(ab => isGifAnimated(new Uint8Array(ab)))
.then(console.log);
}
}

function clooktv(intv) {
var finds=[];
document.getElementById('imgag').title=intv;
if (ingifchosen) {
finds=document.getElementById('simgag').outerHTML.split('>' + intv + '</option>');
if (eval('' + finds.length) > 1) {
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
}
}
document.body.innerHTML+='<style> #imgag { ' + intv + ' } </style>';
return intv;
}

function changelook() {
var finds=[];
if (ingifint > 0) {
setTimeout(changelook, ingifint);
if (ingifchosen) {
ingifchosen=false;
} else {
finds=document.getElementById('simgag').outerHTML.split('>' + ingifstyle + '</option>');
if (eval('' + finds.length) > 1) {
if (finds[1].indexOf('</select>') == 0) {
ingifstyle='filter: none;';
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
} else {
ingifstyle=finds[1].split('>')[1].split('<')[0];
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
}
document.getElementById('simgag').value=clooktv(ingifstyle);
}
}
}
}

/** @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.
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;
}
}
//alert('' + eval(duration / 100));
if (eval(duration / 100) > 0.11) {
//alert('' + duration);
var damore='', wpthere=false;
if (document.getElementById('aside')) {
if (document.getElementById('aside').outerHTML.toLowerCase().indexOf('<div') == 0) {
damore=' showing <select onchange=\"ingifchosen=true; ingifstyle=clooktv(this.value);\" id=simgag size=13><option value=\"filter: none;\" selected>filter: none;</option><option value=\"filter: blur(5px);\">filter: blur(5px);</option><option value=\"filter: brightness(0.4);\">filter: brightness(0.4);</option><option value=\"filter: contrast(200%);\">filter: contrast(200%);</option><option value=\"filter: drop-shadow(16px 16px 20px blue);\">filter: drop-shadow(16px 16px 20px blue);</option><option value=\"filter: grayscale(50%);\">filter: grayscale(50%);</option><option value=\"filter: hue-rotate(90deg);\">filter: hue-rotate(90deg);</option><option value=\"filter: invert(75%);\">filter: invert(75%);</option><option value=\"filter: opacity(25%);\">filter: opacity(25%);</option><option value=\"filter: saturate(30%);\">filter: saturate(30%);</option><option value=\"filter: sepia(60%);\">filter: sepia(60%);</option><option value=\"filter: contrast(175%) brightness(33%);\">filter: contrast(175%) brightness(33%);</option><option value=\"filter: drop-shadow(3px 3px red) sepia(100%) drop-shadow(-3px -3px blue);\">filter: drop-shadow(3px 3px red) sepia(100%) drop-shadow(-3px -3px blue);</option></select><br><br><img onload=\"if (ingifint == 0) { ingifint=' + eval(duration * 10) + '; setTimeout(changelook, eval(800 + ingifint)); }\" title=\"filter: none;\" src=\"' + ingif + '\" id=imgag></img><br>';
//ingifint=eval(duration * 10);
//setTimeout(changelook, eval(duration * 10));
if (window.parent) {
if (window.self !== window.parent && parent.document.getElementById('aside')) {
wpthere=true;
parent.document.getElementById('aside').innerHTML='Animated GIF ' + isagname + ' duration is ' + eval(duration / 100) + ' seconds ' + damore;
parent.document.getElementById('aside').scrollIntoView();
parent.document.getElementById('image').style.opacity='0.5';
parent.document.getElementById('image').style.width='5%';
parent.document.getElementById('isub').style.opacity='0.5';
} else {
document.getElementById('aside').style.display='block';
document.getElementById('aside').innerHTML='Animated GIF ' + isagname + ' duration is ' + eval(duration / 100) + ' seconds ' + damore;
}
} else {
document.getElementById('aside').style.display='block';
document.getElementById('aside').innerHTML='Animated GIF ' + isagname + ' duration is ' + eval(duration / 100) + ' seconds ' + damore;
}
if (!wpthere) { document.getElementById('aside').scrollIntoView(); }
} else {
document.getElementById('aside').innerHTML=' (<?php echo $image; ?> animated GIF ' + isagname + ' duration is ' + eval(duration / 100) + ' seconds)' + damore;
}
}
//} else {
//alert('duration=' + duration);
}
document.body.style.cursor='pointer';
return duration / 100; // if 0.1 is not an animated GIF
}

client_browsing.htm helper web application you can try for yourself as a standalone arrangement or have it get called via today’s changed read_exif_off_image_rotate.php PHP image exif reporter web application.

Did you know?

A quirk with our new HTML button element within an HTML form had us, initially, before realizing …

  • onmousedown event event.stopPropagation() usage can be used to cancel a following onclick event on non-mobile … and …
  • ontouchdown (yay!!!) event event.stopPropagation() usage can be used to cancel a following onclick event on mobile

… as in …


<button title='Click or touch here, as required, for chance to browse for Animated GIF' ontouchdown='event.stopPropagation(); spagif();' onmousedown='event.stopPropagation(); spagif();'><sup>Animated</sup><sub>GIF</sub></button>

… and could overcome the adverse “onclick” based coding we had prior to the discovery. Thanks to javascript – Does using event.preventDefault() in “mousedown” prevent “click” or “mouseup” event in jquery? – Stack Overflow for the heads up about this.


Previous relevant Animated GIF Duration Calculation Filter Tutorial is shown below.

Animated GIF CSS Filter Tutorial

Animated GIF Duration Calculation Filter Tutorial

Can a “proof of concept” arrangement last two blog postings? If there’s more you want to prove, ahead of committing to the final product that might hone in on the specificity of the idea, we’d say it’s possible, yes. And so, continuing on from the recent Animated GIF Duration Calculation Primer Tutorial we tweak its PHP hosting “proof of concept” parent web application to try out our second point we’re out to prove …

We want to prove that CSS filter works for animated GIFs as well as it appears to work with other image types of elements.

Conservative worry, we grant you, but we did want to make sure this all worked, and happily, it was all fine …


var ingif='', ingifstyle='filter: none;', ingifint=0, ingifchosen=false;

function prefetch(whatgifmaybe) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
if ((whatgifmaybe.toLowerCase().trim().split('#')[0] + '?').indexOf('.gif?') != -1) {
ingif=whatgifmaybe;
document.body.style.cursor='progress';
fetch(whatgifmaybe)
.then(res => res.arrayBuffer())
.then(ab => isGifAnimated(new Uint8Array(ab)))
.then(console.log);
}
}

function clooktv(intv) {
var finds=[];
document.getElementById('imgag').title=intv;
if (ingifchosen) {
finds=document.getElementById('simgag').outerHTML.split('>' + intv + '</option>');
if (eval('' + finds.length) > 1) {
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
}
}
document.body.innerHTML+='<style> #imgag { ' + intv + ' } </style>';
return intv;
}

function changelook() {
var finds=[];
if (ingifint > 0) {
setTimeout(changelook, ingifint);
if (ingifchosen) {
ingifchosen=false;
} else {
finds=document.getElementById('simgag').outerHTML.split('>' + ingifstyle + '</option>');
if (eval('' + finds.length) > 1) {
if (finds[1].indexOf('</select>') == 0) {
ingifstyle='filter: none;';
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
} else {
ingifstyle=finds[1].split('>')[1].split('<')[0];
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
}
document.getElementById('simgag').value=clooktv(ingifstyle);
}
}
}
}

/** @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.
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;
}
}
//alert('' + eval(duration / 100));
if (eval(duration / 100) > 0.11) {
var damore='';
if (document.getElementById('aside')) {
if (document.getElementById('aside').outerHTML.toLowerCase().indexOf('<div') == 0) {
damore=' showing <select onchange=\"ingifchosen=true; ingifstyle=clooktv(this.value);\" id=simgag size=13><option value=\"filter: none;\" selected>filter: none;</option><option value=\"filter: blur(5px);\">filter: blur(5px);</option><option value=\"filter: brightness(0.4);\">filter: brightness(0.4);</option><option value=\"filter: contrast(200%);\">filter: contrast(200%);</option><option value=\"filter: drop-shadow(16px 16px 20px blue);\">filter: drop-shadow(16px 16px 20px blue);</option><option value=\"filter: grayscale(50%);\">filter: grayscale(50%);</option><option value=\"filter: hue-rotate(90deg);\">filter: hue-rotate(90deg);</option><option value=\"filter: invert(75%);\">filter: invert(75%);</option><option value=\"filter: opacity(25%);\">filter: opacity(25%);</option><option value=\"filter: saturate(30%);\">filter: saturate(30%);</option><option value=\"filter: sepia(60%);\">filter: sepia(60%);</option><option value=\"filter: contrast(175%) brightness(33%);\">filter: contrast(175%) brightness(33%);</option><option value=\"filter: drop-shadow(3px 3px red) sepia(100%) drop-shadow(-3px -3px blue);\">filter: drop-shadow(3px 3px red) sepia(100%) drop-shadow(-3px -3px blue);</option></select><br><br><img onload=\"if (ingifint == 0) { ingifint=' + eval(duration * 10) + '; setTimeout(changelook, eval(800 + ingifint)); }\" title=\"filter: none;\" src=\"' + ingif + '\" id=imgag></img><br>';
document.getElementById('aside').innerHTML='<?php echo $image; ?> Animated GIF ' + ingif.split('#')[0].split('?')[0] + ' duration is ' + eval(duration / 100) + ' seconds ' + damore;
//ingifint=eval(duration * 10);
//setTimeout(changelook, eval(duration * 10));
document.getElementById('aside').scrollIntoView();
} else {
document.getElementById('aside').innerHTML=' (<?php echo $image; ?> animated GIF ' + ingif.split('#')[0].split('?')[0] + ' duration is ' + eval(duration / 100) + ' seconds)' + damore;
}
}
}
document.body.style.cursor='pointer';
return duration / 100; // if 0.1 is not an animated GIF
}

And so, especially because GIF images cannot be useful for exif information, it helps us isolate our “proof of concept” feel to today’s changed read_exif_off_image_rotate.php PHP image exif reporter web application which we can supply an argument to such as the Katoomba Street Art Walk inspired one also shown below …


Previous relevant Animated GIF Duration Calculation Primer Tutorial is shown below.

Animated GIF Duration Calculation Primer Tutorial

Animated GIF Duration Calculation Primer Tutorial

We’ve got a new (mini-?)project developing. No, it doesn’t hurt in the “you know what”! But thanks for your concern?!

It’s a project that reminds us about an adage regarding projects, that might seem pretty obvious, but is worth mentioning …

Many projects being 90% perspiration, 10% inspiration, there might be the “not sure we can do” items that should be tackled first.

That truism is all well and good, but not always possible, of course, when you have to set up the difficult environment ahead of testing this unknown. Not so, with the “unknown” of our new project …

We want to know whether we can detect an animated GIF media file playing duration, ideally in client side Javascript, and if not possible there, we would settle for a server side PHP solution.

Happily (via our duration of animated GIF using Javascript Google search), yet again, the online wooooorrrrlllldd has come to our rescue via this excellent webpage‘s Javascript ideas, so many thanks!

We slotted its thinking (and Javascript (via PHP) …


function prefetch(whatgifmaybe) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
if ((whatgifmaybe.toLowerCase().trim().split('#')[0] + '?').indexOf('.gif?') != -1) {
document.body.style.cursor='progress';
fetch(whatgifmaybe)
.then(res => res.arrayBuffer())
.then(ab => isGifAnimated(new Uint8Array(ab)))
.then(console.log);
}
}

/** @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.
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; } } //alert('' + eval(duration / 100)); if (eval(duration / 100) > 0.11) { if (document.getElementById('aside')) { document.getElementById('aside').innerHTML=' (<?php echo $image; ?> animated GIF duration is ' + eval(duration / 100) + ' seconds)'; } } document.body.style.cursor='pointer'; return duration / 100; // if 0.1 is not an animated GIF }

... logic), you might say in a "kludgy" way (but, for us, serving a "proof of concept" purpose), that allows us to proceed on other aims of our project that will become apparent into the near future. No, we are not totally "out of the woods" yet regarding "unknowns" but today's changed read_exif_off_image_rotate.php PHP image exif reporter web application) into the "onblur" logic of an image URL textbox HTML element, that web application talked about when we presented Gimp Guillotine Image File Browse Media Tutorial. You might try it yourself, but not sure "animated GIF and exif" mix, if you get my meaning, but if your image is an animated GIF you should be informed of its duration, in seconds, up the top of the webpage (given permissions and all, that is)?

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 Animation, eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Animated GIF Duration Calculation Filter Browsing Tutorial

Animated GIF CSS Filter Browsing Tutorial

Animated GIF Duration Calculation Filter Browsing Tutorial

Can a “proof of concept” arrangement last three blog postings? If there’s more you want to prove, ahead of committing to the final product that might hone in on the specificity of the idea, and another iframe hosted web application joins in on “proof of concept” goings on and will be useful into the future, we’d say it’s possible, yes. But we would say that, wouldn’t we?!

In our defence, it is easier to prove all solutions to all the contentious issues, and then hone in and reduce to make a specific new web application, rather than extending and still needing to prove as you go along, not knowing whether an issue will cause you insurmountable issues in the future.

But they would say that, wouldn’t they?!

And so, continuing on from the recent Animated GIF Duration Calculation Filter Tutorial we considered another mode that a user might use on top of …

  • entering an image (animated GIF) URL into a textbox … that being to …
  • browse for a local system (animated GIF) file (via File API)

… getting us to call on changes to our “via File API” specialist with a changed (with new data URI supporting Javascript) …


var ingif='', ingifstyle='filter: none;', ingifint=0, ingifchosen=false, isag=-1, isagname='';

function prefetch(whatgifmaybe) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
if ((whatgifmaybe.toLowerCase().trim().split('#')[0] + '?').indexOf('.gif?') != -1 || whatgifmaybe.indexOf('data:image/gif') == 0) {
ingif=whatgifmaybe;
document.body.style.cursor='progress';
fetch(whatgifmaybe)
.then(res => res.arrayBuffer())
.then(ab => isGifAnimated(new Uint8Array(ab)))
.then(console.log);
}
}

function clooktv(intv) {
var finds=[];
document.getElementById('imgag').title=intv;
if (ingifchosen) {
finds=document.getElementById('simgag').outerHTML.split('>' + intv + '</option>');
if (eval('' + finds.length) > 1) {
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
}
}
document.body.innerHTML+='<style> #imgag { ' + intv + ' } </style>';
return intv;
}

function changelook() {
var finds=[];
if (ingifint > 0) {
setTimeout(changelook, ingifint);
if (ingifchosen) {
ingifchosen=false;
} else {
finds=document.getElementById('simgag').outerHTML.split('>' + ingifstyle + '</option>');
if (eval('' + finds.length) > 1) {
if (finds[1].indexOf('</select>') == 0) {
ingifstyle='filter: none;';
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
} else {
ingifstyle=finds[1].split('>')[1].split('<')[0];
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
}
document.getElementById('simgag').value=clooktv(ingifstyle);
}
}
}
}

/** @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.
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;
}
}
//alert('' + eval(duration / 100));
if (eval(duration / 100) > 0.11) {
//alert('' + duration);
var damore='', wpthere=false;
if (document.getElementById('aside')) {
if (document.getElementById('aside').outerHTML.toLowerCase().indexOf('<div') == 0) {
damore=' showing <select onchange=\"ingifchosen=true; ingifstyle=clooktv(this.value);\" id=simgag size=13><option value=\"filter: none;\" selected>filter: none;</option><option value=\"filter: blur(5px);\">filter: blur(5px);</option><option value=\"filter: brightness(0.4);\">filter: brightness(0.4);</option><option value=\"filter: contrast(200%);\">filter: contrast(200%);</option><option value=\"filter: drop-shadow(16px 16px 20px blue);\">filter: drop-shadow(16px 16px 20px blue);</option><option value=\"filter: grayscale(50%);\">filter: grayscale(50%);</option><option value=\"filter: hue-rotate(90deg);\">filter: hue-rotate(90deg);</option><option value=\"filter: invert(75%);\">filter: invert(75%);</option><option value=\"filter: opacity(25%);\">filter: opacity(25%);</option><option value=\"filter: saturate(30%);\">filter: saturate(30%);</option><option value=\"filter: sepia(60%);\">filter: sepia(60%);</option><option value=\"filter: contrast(175%) brightness(33%);\">filter: contrast(175%) brightness(33%);</option><option value=\"filter: drop-shadow(3px 3px red) sepia(100%) drop-shadow(-3px -3px blue);\">filter: drop-shadow(3px 3px red) sepia(100%) drop-shadow(-3px -3px blue);</option></select><br><br><img onload=\"if (ingifint == 0) { ingifint=' + eval(duration * 10) + '; setTimeout(changelook, eval(800 + ingifint)); }\" title=\"filter: none;\" src=\"' + ingif + '\" id=imgag></img><br>';
//ingifint=eval(duration * 10);
//setTimeout(changelook, eval(duration * 10));
if (window.parent) {
if (window.self !== window.parent && parent.document.getElementById('aside')) {
wpthere=true;
parent.document.getElementById('aside').innerHTML='Animated GIF ' + isagname + ' duration is ' + eval(duration / 100) + ' seconds ' + damore;
parent.document.getElementById('aside').scrollIntoView();
parent.document.getElementById('image').style.opacity='0.5';
parent.document.getElementById('image').style.width='5%';
parent.document.getElementById('isub').style.opacity='0.5';
} else {
document.getElementById('aside').style.display='block';
document.getElementById('aside').innerHTML='Animated GIF ' + isagname + ' duration is ' + eval(duration / 100) + ' seconds ' + damore;
}
} else {
document.getElementById('aside').style.display='block';
document.getElementById('aside').innerHTML='Animated GIF ' + isagname + ' duration is ' + eval(duration / 100) + ' seconds ' + damore;
}
if (!wpthere) { document.getElementById('aside').scrollIntoView(); }
} else {
document.getElementById('aside').innerHTML=' (<?php echo $image; ?> animated GIF ' + isagname + ' duration is ' + eval(duration / 100) + ' seconds)' + damore;
}
}
//} else {
//alert('duration=' + duration);
}
document.body.style.cursor='pointer';
return duration / 100; // if 0.1 is not an animated GIF
}

client_browsing.htm helper web application you can try for yourself as a standalone arrangement or have it get called via today’s changed read_exif_off_image_rotate.php PHP image exif reporter web application.

Did you know?

A quirk with our new HTML button element within an HTML form had us, initially, before realizing …

  • onmousedown event event.stopPropagation() usage can be used to cancel a following onclick event on non-mobile … and …
  • ontouchdown (yay!!!) event event.stopPropagation() usage can be used to cancel a following onclick event on mobile

… as in …


<button title='Click or touch here, as required, for chance to browse for Animated GIF' ontouchdown='event.stopPropagation(); spagif();' onmousedown='event.stopPropagation(); spagif();'><sup>Animated</sup><sub>GIF</sub></button>

… and could overcome the adverse “onclick” based coding we had prior to the discovery. Thanks to javascript – Does using event.preventDefault() in “mousedown” prevent “click” or “mouseup” event in jquery? – Stack Overflow for the heads up about this.


Previous relevant Animated GIF Duration Calculation Filter Tutorial is shown below.

Animated GIF CSS Filter Tutorial

Animated GIF Duration Calculation Filter Tutorial

Can a “proof of concept” arrangement last two blog postings? If there’s more you want to prove, ahead of committing to the final product that might hone in on the specificity of the idea, we’d say it’s possible, yes. And so, continuing on from the recent Animated GIF Duration Calculation Primer Tutorial we tweak its PHP hosting “proof of concept” parent web application to try out our second point we’re out to prove …

We want to prove that CSS filter works for animated GIFs as well as it appears to work with other image types of elements.

Conservative worry, we grant you, but we did want to make sure this all worked, and happily, it was all fine …


var ingif='', ingifstyle='filter: none;', ingifint=0, ingifchosen=false;

function prefetch(whatgifmaybe) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
if ((whatgifmaybe.toLowerCase().trim().split('#')[0] + '?').indexOf('.gif?') != -1) {
ingif=whatgifmaybe;
document.body.style.cursor='progress';
fetch(whatgifmaybe)
.then(res => res.arrayBuffer())
.then(ab => isGifAnimated(new Uint8Array(ab)))
.then(console.log);
}
}

function clooktv(intv) {
var finds=[];
document.getElementById('imgag').title=intv;
if (ingifchosen) {
finds=document.getElementById('simgag').outerHTML.split('>' + intv + '</option>');
if (eval('' + finds.length) > 1) {
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
}
}
document.body.innerHTML+='<style> #imgag { ' + intv + ' } </style>';
return intv;
}

function changelook() {
var finds=[];
if (ingifint > 0) {
setTimeout(changelook, ingifint);
if (ingifchosen) {
ingifchosen=false;
} else {
finds=document.getElementById('simgag').outerHTML.split('>' + ingifstyle + '</option>');
if (eval('' + finds.length) > 1) {
if (finds[1].indexOf('</select>') == 0) {
ingifstyle='filter: none;';
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
} else {
ingifstyle=finds[1].split('>')[1].split('<')[0];
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
}
document.getElementById('simgag').value=clooktv(ingifstyle);
}
}
}
}

/** @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.
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;
}
}
//alert('' + eval(duration / 100));
if (eval(duration / 100) > 0.11) {
var damore='';
if (document.getElementById('aside')) {
if (document.getElementById('aside').outerHTML.toLowerCase().indexOf('<div') == 0) {
damore=' showing <select onchange=\"ingifchosen=true; ingifstyle=clooktv(this.value);\" id=simgag size=13><option value=\"filter: none;\" selected>filter: none;</option><option value=\"filter: blur(5px);\">filter: blur(5px);</option><option value=\"filter: brightness(0.4);\">filter: brightness(0.4);</option><option value=\"filter: contrast(200%);\">filter: contrast(200%);</option><option value=\"filter: drop-shadow(16px 16px 20px blue);\">filter: drop-shadow(16px 16px 20px blue);</option><option value=\"filter: grayscale(50%);\">filter: grayscale(50%);</option><option value=\"filter: hue-rotate(90deg);\">filter: hue-rotate(90deg);</option><option value=\"filter: invert(75%);\">filter: invert(75%);</option><option value=\"filter: opacity(25%);\">filter: opacity(25%);</option><option value=\"filter: saturate(30%);\">filter: saturate(30%);</option><option value=\"filter: sepia(60%);\">filter: sepia(60%);</option><option value=\"filter: contrast(175%) brightness(33%);\">filter: contrast(175%) brightness(33%);</option><option value=\"filter: drop-shadow(3px 3px red) sepia(100%) drop-shadow(-3px -3px blue);\">filter: drop-shadow(3px 3px red) sepia(100%) drop-shadow(-3px -3px blue);</option></select><br><br><img onload=\"if (ingifint == 0) { ingifint=' + eval(duration * 10) + '; setTimeout(changelook, eval(800 + ingifint)); }\" title=\"filter: none;\" src=\"' + ingif + '\" id=imgag></img><br>';
document.getElementById('aside').innerHTML='<?php echo $image; ?> Animated GIF ' + ingif.split('#')[0].split('?')[0] + ' duration is ' + eval(duration / 100) + ' seconds ' + damore;
//ingifint=eval(duration * 10);
//setTimeout(changelook, eval(duration * 10));
document.getElementById('aside').scrollIntoView();
} else {
document.getElementById('aside').innerHTML=' (<?php echo $image; ?> animated GIF ' + ingif.split('#')[0].split('?')[0] + ' duration is ' + eval(duration / 100) + ' seconds)' + damore;
}
}
}
document.body.style.cursor='pointer';
return duration / 100; // if 0.1 is not an animated GIF
}

And so, especially because GIF images cannot be useful for exif information, it helps us isolate our “proof of concept” feel to today’s changed read_exif_off_image_rotate.php PHP image exif reporter web application which we can supply an argument to such as the Katoomba Street Art Walk inspired one also shown below …


Previous relevant Animated GIF Duration Calculation Primer Tutorial is shown below.

Animated GIF Duration Calculation Primer Tutorial

Animated GIF Duration Calculation Primer Tutorial

We’ve got a new (mini-?)project developing. No, it doesn’t hurt in the “you know what”! But thanks for your concern?!

It’s a project that reminds us about an adage regarding projects, that might seem pretty obvious, but is worth mentioning …

Many projects being 90% perspiration, 10% inspiration, there might be the “not sure we can do” items that should be tackled first.

That truism is all well and good, but not always possible, of course, when you have to set up the difficult environment ahead of testing this unknown. Not so, with the “unknown” of our new project …

We want to know whether we can detect an animated GIF media file playing duration, ideally in client side Javascript, and if not possible there, we would settle for a server side PHP solution.

Happily (via our duration of animated GIF using Javascript Google search), yet again, the online wooooorrrrlllldd has come to our rescue via this excellent webpage‘s Javascript ideas, so many thanks!

We slotted its thinking (and Javascript (via PHP) …


function prefetch(whatgifmaybe) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
if ((whatgifmaybe.toLowerCase().trim().split('#')[0] + '?').indexOf('.gif?') != -1) {
document.body.style.cursor='progress';
fetch(whatgifmaybe)
.then(res => res.arrayBuffer())
.then(ab => isGifAnimated(new Uint8Array(ab)))
.then(console.log);
}
}

/** @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.
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; } } //alert('' + eval(duration / 100)); if (eval(duration / 100) > 0.11) { if (document.getElementById('aside')) { document.getElementById('aside').innerHTML=' (<?php echo $image; ?> animated GIF duration is ' + eval(duration / 100) + ' seconds)'; } } document.body.style.cursor='pointer'; return duration / 100; // if 0.1 is not an animated GIF }

... logic), you might say in a "kludgy" way (but, for us, serving a "proof of concept" purpose), that allows us to proceed on other aims of our project that will become apparent into the near future. No, we are not totally "out of the woods" yet regarding "unknowns" but today's changed read_exif_off_image_rotate.php PHP image exif reporter web application) into the "onblur" logic of an image URL textbox HTML element, that web application talked about when we presented Gimp Guillotine Image File Browse Media Tutorial. You might try it yourself, but not sure "animated GIF and exif" mix, if you get my meaning, but if your image is an animated GIF you should be informed of its duration, in seconds, up the top of the webpage (given permissions and all, that is)?

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 Animation, eLearning, Event-Driven Programming, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

PicPick Windows Audio and Screenshot Presentations Primer Tutorial

PicPick Windows Audio and Screenshot Presentations Primer Tutorial

PicPick Windows Audio and Screenshot Presentations Primer Tutorial

Thanks to the heads up from the APC magazine, in a recent issue, we were really interested to download and try a Windows desktop application called PicPick which can help with Screen Capture Presentations Without or With Audio. It was that “or With Audio” of huge interest to us, and yes, our …

  • downloading and install … then …
  • simple GIF presentation … then …
  • simple MP4 video presentation (with audio) …

… was all great! The only gripe here being the huge disk size of the (5 seconds worth of recording equating to 25mB) GIF, totally overridden by the excitement of the “audio overlay in MP4 video” (though we’d much prefer Stephen Fry to “yours truly”?!)

Another issue that may surprise is that the Windows PrtScn button (screenshooting functionality) is fed into PicPick (workflows), if you have PicPick installed. It took us about a minute to get used to that, but we thought we should mention that, as it is definitely worthwhile you experiment with the myriad PicPick “presentation helpers” in PicPick’s main menu that you can see in today’s animated GIF presentation of our first look at PicPick.

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

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

Animated GIF Duration Calculation Filter Tutorial

Animated GIF CSS Filter Tutorial

Animated GIF Duration Calculation Filter Tutorial

Can a “proof of concept” arrangement last two blog postings? If there’s more you want to prove, ahead of committing to the final product that might hone in on the specificity of the idea, we’d say it’s possible, yes. And so, continuing on from the recent Animated GIF Duration Calculation Primer Tutorial we tweak its PHP hosting “proof of concept” parent web application to try out our second point we’re out to prove …

We want to prove that CSS filter works for animated GIFs as well as it appears to work with other image types of elements.

Conservative worry, we grant you, but we did want to make sure this all worked, and happily, it was all fine …


var ingif='', ingifstyle='filter: none;', ingifint=0, ingifchosen=false;

function prefetch(whatgifmaybe) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
if ((whatgifmaybe.toLowerCase().trim().split('#')[0] + '?').indexOf('.gif?') != -1) {
ingif=whatgifmaybe;
document.body.style.cursor='progress';
fetch(whatgifmaybe)
.then(res => res.arrayBuffer())
.then(ab => isGifAnimated(new Uint8Array(ab)))
.then(console.log);
}
}

function clooktv(intv) {
var finds=[];
document.getElementById('imgag').title=intv;
if (ingifchosen) {
finds=document.getElementById('simgag').outerHTML.split('>' + intv + '</option>');
if (eval('' + finds.length) > 1) {
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
}
}
document.body.innerHTML+='<style> #imgag { ' + intv + ' } </style>';
return intv;
}

function changelook() {
var finds=[];
if (ingifint > 0) {
setTimeout(changelook, ingifint);
if (ingifchosen) {
ingifchosen=false;
} else {
finds=document.getElementById('simgag').outerHTML.split('>' + ingifstyle + '</option>');
if (eval('' + finds.length) > 1) {
if (finds[1].indexOf('</select>') == 0) {
ingifstyle='filter: none;';
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
} else {
ingifstyle=finds[1].split('>')[1].split('<')[0];
document.getElementById('simgag').innerHTML=document.getElementById('simgag').innerHTML.replace(' selected',' data-selected').replace('>' + ingifstyle + '</option>', ' selected>' + ingifstyle + '</option>');
}
document.getElementById('simgag').value=clooktv(ingifstyle);
}
}
}
}

/** @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.
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;
}
}
//alert('' + eval(duration / 100));
if (eval(duration / 100) > 0.11) {
var damore='';
if (document.getElementById('aside')) {
if (document.getElementById('aside').outerHTML.toLowerCase().indexOf('<div') == 0) {
damore=' showing <select onchange=\"ingifchosen=true; ingifstyle=clooktv(this.value);\" id=simgag size=13><option value=\"filter: none;\" selected>filter: none;</option><option value=\"filter: blur(5px);\">filter: blur(5px);</option><option value=\"filter: brightness(0.4);\">filter: brightness(0.4);</option><option value=\"filter: contrast(200%);\">filter: contrast(200%);</option><option value=\"filter: drop-shadow(16px 16px 20px blue);\">filter: drop-shadow(16px 16px 20px blue);</option><option value=\"filter: grayscale(50%);\">filter: grayscale(50%);</option><option value=\"filter: hue-rotate(90deg);\">filter: hue-rotate(90deg);</option><option value=\"filter: invert(75%);\">filter: invert(75%);</option><option value=\"filter: opacity(25%);\">filter: opacity(25%);</option><option value=\"filter: saturate(30%);\">filter: saturate(30%);</option><option value=\"filter: sepia(60%);\">filter: sepia(60%);</option><option value=\"filter: contrast(175%) brightness(33%);\">filter: contrast(175%) brightness(33%);</option><option value=\"filter: drop-shadow(3px 3px red) sepia(100%) drop-shadow(-3px -3px blue);\">filter: drop-shadow(3px 3px red) sepia(100%) drop-shadow(-3px -3px blue);</option></select><br><br><img onload=\"if (ingifint == 0) { ingifint=' + eval(duration * 10) + '; setTimeout(changelook, eval(800 + ingifint)); }\" title=\"filter: none;\" src=\"' + ingif + '\" id=imgag></img><br>';
document.getElementById('aside').innerHTML='<?php echo $image; ?> Animated GIF ' + ingif.split('#')[0].split('?')[0] + ' duration is ' + eval(duration / 100) + ' seconds ' + damore;
//ingifint=eval(duration * 10);
//setTimeout(changelook, eval(duration * 10));
document.getElementById('aside').scrollIntoView();
} else {
document.getElementById('aside').innerHTML=' (<?php echo $image; ?> animated GIF ' + ingif.split('#')[0].split('?')[0] + ' duration is ' + eval(duration / 100) + ' seconds)' + damore;
}
}
}
document.body.style.cursor='pointer';
return duration / 100; // if 0.1 is not an animated GIF
}

And so, especially because GIF images cannot be useful for exif information, it helps us isolate our “proof of concept” feel to today’s changed read_exif_off_image_rotate.php PHP image exif reporter web application which we can supply an argument to such as the Katoomba Street Art Walk inspired one also shown below …


Previous relevant Animated GIF Duration Calculation Primer Tutorial is shown below.

Animated GIF Duration Calculation Primer Tutorial

Animated GIF Duration Calculation Primer Tutorial

We’ve got a new (mini-?)project developing. No, it doesn’t hurt in the “you know what”! But thanks for your concern?!

It’s a project that reminds us about an adage regarding projects, that might seem pretty obvious, but is worth mentioning …

Many projects being 90% perspiration, 10% inspiration, there might be the “not sure we can do” items that should be tackled first.

That truism is all well and good, but not always possible, of course, when you have to set up the difficult environment ahead of testing this unknown. Not so, with the “unknown” of our new project …

We want to know whether we can detect an animated GIF media file playing duration, ideally in client side Javascript, and if not possible there, we would settle for a server side PHP solution.

Happily (via our duration of animated GIF using Javascript Google search), yet again, the online wooooorrrrlllldd has come to our rescue via this excellent webpage‘s Javascript ideas, so many thanks!

We slotted its thinking (and Javascript (via PHP) …


function prefetch(whatgifmaybe) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
if ((whatgifmaybe.toLowerCase().trim().split('#')[0] + '?').indexOf('.gif?') != -1) {
document.body.style.cursor='progress';
fetch(whatgifmaybe)
.then(res => res.arrayBuffer())
.then(ab => isGifAnimated(new Uint8Array(ab)))
.then(console.log);
}
}

/** @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.
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; } } //alert('' + eval(duration / 100)); if (eval(duration / 100) > 0.11) { if (document.getElementById('aside')) { document.getElementById('aside').innerHTML=' (<?php echo $image; ?> animated GIF duration is ' + eval(duration / 100) + ' seconds)'; } } document.body.style.cursor='pointer'; return duration / 100; // if 0.1 is not an animated GIF }

... logic), you might say in a "kludgy" way (but, for us, serving a "proof of concept" purpose), that allows us to proceed on other aims of our project that will become apparent into the near future. No, we are not totally "out of the woods" yet regarding "unknowns" but today's changed read_exif_off_image_rotate.php PHP image exif reporter web application) into the "onblur" logic of an image URL textbox HTML element, that web application talked about when we presented Gimp Guillotine Image File Browse Media Tutorial. You might try it yourself, but not sure "animated GIF and exif" mix, if you get my meaning, but if your image is an animated GIF you should be informed of its duration, in seconds, up the top of the webpage (given permissions and all, that is)?

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, Tutorials | Tagged , , , , , , , , , , , , , , , | Leave a comment

Saving Power on iPhone Out and About Tutorial

Saving Power on iPhone Out and About Tutorial

Saving Power on iPhone Out and About Tutorial

The other day, out and about using an iPhone, we started out with the battery at 100% but within 5 minutes it had gone to about 85%, if my memory serves me correctly. Ideally, we wanted the iPhone to last another 4 hours, so the projections for that were not good.

Am sure am no Robinson Crusoe getting this scenario happen?! So, what are some steps mere mortals can apply, given you cannot get to a power source (and these days, there are those portable power sources available) to try to prolong the life of the battery on the iPhone in situ? Today’s animated GIF presentation shows some of what we suggest below, and it goes without saying your own research can be great here, and the wooooorrrrrlllldddd knowledge on this matter is huuuuuuuuggggggeee.

First off, we find the most natural approach is to double touch the iPhone’s Home Button to see a horizontally cascading view of applications open, that you can swipe up to close as you think necessary, is a first good starting point.

Next might be, even so, take a more scientific approach and go to …


Settings -> Battery

… and see what applications are using power, and plan further as to what needs changing, perhaps, within that app’s Settings, to help. Also, within the “Settings -> Battery” realm, there is a “Low Power Mode” switch you could turn on, even before you are prompted for it, to …

Low Power Mode temporarily reduces background activity like downloads and mail fetch until you can fully charge your iPhone.

For us though, what seemed to be the most effective idea, as we talked about with Location Services iPad Battery Loss Issue Tutorial, was to turn off all “Location Services” functionality immediately via …


Settings -> Privacy -> Location Services ... turn off switch

… which, in practice, being as we cannot commit this to memory, we got to the steps above via “Settings -> Search … typed in Location Services”.

Also notorious for eating up battery, can be any Weather app you have set to be always monitoring. Perhaps a look, in Settings, at an app itself, inside its subsettings might help here? We turned off a Weather app’s ability to access “Mobile Data” on our iPhone, for example.

Also an option is to dim the display (or … gasp … power it off) via, for us, a bottom left diagonal swipe towards top right, causing the menu with display brightness be adjustable, in order for you to turn it down lower, as another idea (not shown on today’s presentation animated GIF). (And isn’t the torch marvellous to find and bring your pooch back in at 2am in the morning?!)

The upshot? Taking these steps well and truly got us through the 4 hours needed, with lots of battery power yet to be used up. But if it hadn’t worked, what then? There are thoughts that some malware these days can hang around your iPhone goings on, maybe, but that some of these might be neutralized via powering your iPhone off, and then (as required) back on (and if that helped, perhaps you should be looking into Malware Removal apps).

They do say, too, when first getting an iPhone, you can “train” your battery to be more efficient.

Happy “out and about”ness to you!


Previous relevant Saving Power on iPhone Out and About Tutorial is shown below.

Location Services iPad Battery Loss Issue Tutorial

Location Services iPad Battery Loss Issue Tutorial

Do you own an iPad that loses battery power too fast?

We were, and the kind and honest people at iExperts set us right that we had the “Location Services” setting set to on.

As related at this useful link here are good steps to remedy this issue …

  1. First, go to the iPad’s Settings by touching the Setting icon. It looks like gears in motion.
  2. Next, scroll down the left-side menu and tap “Privacy.”
  3. If you want to completely turn off Location Services, tap the button at the top of the screen next to Location Services, as you can see with today’s tutorial picture.
  4. If you just want to turn it off in a single app, scroll down the list until you see the app’s name. You can choose to “Never” allow an app access, to “Always” allow an app access, or to only allow access “While Using the App.”
  5. Share My Location will show your location in text messages sent through iMessage and through the Find My Friends app. If you are only turning off location services for individual apps, you may want to turn this setting off as well.

… and, if you are like us, what you will see is that your iPad battery fully charged will last hours longer than it used to, presumably because it will have periods now where nothing is asked of it, whereas having “Location Services” set to “on” requires some power virtually the whole time.

Well, this fix, using just its first 3 steps, above, might be thought of as a bit crude. What if there is good use made of “Location Services”? Well, a less crude method is outlined at this link … thanks. We used its methodology to arrive at the Weather app component (used by Notification Services) and set it to be “Never” rather than “Always”, the “Always” apps being the ones that badly affect the battery life of the iPad. So we show this less crude approach with the images below.



Trap for young … cough, cough … players, we presume?!

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, iOS, Tutorials | Tagged , , , , , , , , , , , , , , , , | Leave a comment

Animated GIF Duration Calculation Primer Tutorial

Animated GIF Duration Calculation Primer Tutorial

Animated GIF Duration Calculation Primer Tutorial

We’ve got a new (mini-?)project developing. No, it doesn’t hurt in the “you know what”! But thanks for your concern?!

It’s a project that reminds us about an adage regarding projects, that might seem pretty obvious, but is worth mentioning …

Many projects being 90% perspiration, 10% inspiration, there might be the “not sure we can do” items that should be tackled first.

That truism is all well and good, but not always possible, of course, when you have to set up the difficult environment ahead of testing this unknown. Not so, with the “unknown” of our new project …

We want to know whether we can detect an animated GIF media file playing duration, ideally in client side Javascript, and if not possible there, we would settle for a server side PHP solution.

Happily (via our duration of animated GIF using Javascript Google search), yet again, the online wooooorrrrlllldd has come to our rescue via this excellent webpage‘s Javascript ideas, so many thanks!

We slotted its thinking (and Javascript (via PHP) …


function prefetch(whatgifmaybe) { // thanks to https://stackoverflow.com/questions/69564118/how-to-get-duration-of-gif-image-in-javascript#:~:text=Mainly%20use%20parseGIF()%20%2C%20then,duration%20of%20a%20GIF%20image.
if ((whatgifmaybe.toLowerCase().trim().split('#')[0] + '?').indexOf('.gif?') != -1) {
document.body.style.cursor='progress';
fetch(whatgifmaybe)
.then(res => res.arrayBuffer())
.then(ab => isGifAnimated(new Uint8Array(ab)))
.then(console.log);
}
}

/** @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.
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; } } //alert('' + eval(duration / 100)); if (eval(duration / 100) > 0.11) { if (document.getElementById('aside')) { document.getElementById('aside').innerHTML=' (<?php echo $image; ?> animated GIF duration is ' + eval(duration / 100) + ' seconds)'; } } document.body.style.cursor='pointer'; return duration / 100; // if 0.1 is not an animated GIF }

... logic), you might say in a "kludgy" way (but, for us, serving a "proof of concept" purpose), that allows us to proceed on other aims of our project that will become apparent into the near future. No, we are not totally "out of the woods" yet regarding "unknowns" but today's changed read_exif_off_image_rotate.php PHP image exif reporter web application) into the "onblur" logic of an image URL textbox HTML element, that web application talked about when we presented Gimp Guillotine Image File Browse Media Tutorial. You might try it yourself, but not sure "animated GIF and exif" mix, if you get my meaning, but if your image is an animated GIF you should be informed of its duration, in seconds, up the top of the webpage (given permissions and all, that is)?

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

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

WordPress List Style User Interaction Form Tutorial

WordPress List Style User Interaction Form Tutorial

WordPress List Style User Interaction Form Tutorial

It can be hard going on a mini-project where you need to set up data structures for success until you get to today’s progress, on top of yesterday’s WordPress List Style User Emoji Image List Tutorial, where we can finally offer a decent user interface to these data structures. So, yayyyyyyyy!

In Change User Controllable Font, Border, Background Settings‘s HTML form based approach, the user can see “all before them” the data items that make up the full scope of what the functionality offers, in today’s case that being user controllable …


ul.noclass li

… CSS styling options in the WordPress blog you are reading. The ++ we ask you to add to the “listimage” textbox here allows a window.localStorage means by which the web browser you are using will assist you keep that look for the new time you access this WordPress blog with that web browser and device combination. And it may well be, you want to (perhaps be amused) with a particular look (which can bring a smile to your face) but never want to go through the ordeal again … well … consider appending ++ here.

We’ve kept the original approach too, and it works as before, should a user prefer, and they want a simple approach, and we needed to change our WordPress TwentyTen theme’s header.php as below …

<?php echo ”

function eqworrydecodeURIComponent(instw) {
var eqis='=', ampis='';
var outstw=decodeURIComponent(instw);
if (outstw.trim() != '') {
if (outstw.indexOf(eqis) != -1) {
eqis='=';
ampis='&';
} else if (outstw.indexOf(encodeURIComponent(eqis)) != -1) {
if (1 == 1) {
ampis='&';
outstw=decodeURIComponent(outstw);
} else {
eqis=encodeURIComponent(eqis);
ampis=encodeURIComponent('&');
}
}
if (ampis != '') {
document.getElementById('listwimage').value=(outstw.split('listwimage=')[1] ? ('' + decodeURIComponent(outstw.split('listwimage=')[1].split('&')[0])) : "");
document.getElementById('listhimage').value=(outstw.split('listhimage=')[1] ? ('' + decodeURIComponent(outstw.split('listw\himage=')[1].split('&')[0])) : "");
document.getElementById('midpseudoclass').value=(outstw.split('midpseudoclass=')[1] ? ('' + decodeURIComponent(outstw.split('midpseudoclass=')[1].split('&')[0])) : "");
return (outstw.split('listimage=')[1] ? ('' + decodeURIComponent(outstw.split('listimage=')[1].split('&')[0])) : "");
}
}
return outstw;
}


function cookieAVal(cName) {
if (cName == 'forcedemoji') {
if (window.localStorage) {
if (decodeURIComponent(('' + localStorage.getItem('listimage')).replace(/^undefined/g,'').replace(/^null/g,'')) != '') {
return eqworrydecodeURIComponent(localStorage.getItem('listimage'));
}
if (decodeURIComponent(('' + sessionStorage.getItem('listimage')).replace(/^undefined/g,'').replace(/^null/g,'')) != '') {
return eqworrydecodeURIComponent(sessionStorage.getItem('listimage'));
}
}
if (cName == 'forcedemoji' && document.getElementById(cName)) {
return document.getElementById(cName).value;
}
return '';
}

var expireDate = new Date();
expireDate.setDate(expireDate.getDate()-1);
if (window.localStorage && cName == 'forced_emoji') {
if (decodeURIComponent(('' + localStorage.getItem('forced_emoji')).replace(/^undefined/g,'').replace(/^null/g,'')) != '') {
if (decodeURIComponent(('' + localStorage.getItem('forced_emoji')).replace(/^undefined/g,'').replace(/^null/g,'')).indexOf('`') != -1) {
document.cookie = cName + "=; expires=" + expireDate.toGMTString();
return decodeURIComponent(localStorage.getItem('forced_emoji'));
} else {
document.cookie = cName + "=; expires=" + expireDate.toGMTString();
return decodeURIComponent(localStorage.getItem('forced_emoji'));
}
}
}
if (document.cookie != '') {
var tCookie=document.cookie.split("; ");


for (var j=0; j<tCookie.length; j++) {
if (cName == tCookie[j].split("=")[0]) {
return decodeURIComponent(tCookie[j].split("=")[1]);
}
}
}
if (cName == 'forced_emoji' && document.getElementById(cName)) {
return document.getElementById(cName).value;
}

return '';
}

function deleteACookie(goodname) {
if (window.localStorage && goodname == 'forced_emoji') {
if (('' + localStorage.getItem('forced_emoji')).replace(/^undefined/g,'').replace(/^null/g,'') != '') {
localStorage.removeItem('forced_emoji');
}
}

var expireDate = new Date();
expireDate.setDate(expireDate.getDate()-1);
//if (("" + cookieAVal(goodname)).length != 0) {
document.cookie = goodname + "=; expires=" + expireDate.toGMTString();
//}
}

function newlsvsco(tvis, tvo) {
var origtvis=tvis;
if (tvis != '' && tvis.replace(/\-/g,'') == '') {
if (tvis.indexOf('--') != -1) {
if (decodeURIComponent(('' + window.localStorage.getItem('listimage')).replace(/^undefined/g,'').replace(/^null/g,'')) != '') {
window.localStorage.removeItem('listimage');
}
if (decodeURIComponent(('' + window.sessionStorage.getItem('listimage')).replace(/^undefined/g,'').replace(/^null/g,'')) != '') {
window.sessionStorage.removeItem('listimage');
}
if (decodeURIComponent(('' + window.localStorage.getItem('forced_emoji')).replace(/^undefined/g,'').replace(/^null/g,'')) != '') {
window.localStorage.removeItem('forced_emoji');
}
} else {
if (decodeURIComponent(('' + window.sessionStorage.getItem('listimage')).replace(/^undefined/g,'').replace(/^null/g,'')) != '') {
window.sessionStorage.removeItem('listimage');
}
}
document.getElementById('forced_emoji').value='';
document.getElementById('forcedemoji').value='';
return '';
}

if (tvo.id == 'forcedemoji') { // new window.localStorage way
if (tvis.indexOf('`') != -1 || (tvis.trim() == '' && tvis != '')) {
document.getElementById('forced_emoji').value=tvis;
tvo.value='';
document.getElementById('tdnew').style.display='none';
newlsvsco(tvis.replace(String.fromCharCode(32), String.fromCharCode(96)).replace(String.fromCharCode(44), String.fromCharCode(96)), document.getElementById('forced_emoji'));
return '';
}
if (tvis.indexOf('+') != -1) {
if (tvis.slice(-2) == '++') {
tvo.value=tvis.substring(0, eval(-2 + tvis.length)) + ' ';
tvis=tvis.substring(0, eval(-2 + tvis.length)) + ' ';
}
if (tvis.slice(-1) == '+') {
tvo.value=tvis.substring(0, eval(-1 + tvis.length)) + ' ';
tvis=tvis.substring(0, eval(-1 + tvis.length)) + ' ';
}
}
} else {

if (tvis.indexOf('`') != -1 && tvis.indexOf(',') != -1) {
document.getElementById('forcedemoji').value=tvis.replace(String.fromCharCode(96), String.fromCharCode(44)).replace(String.fromCharCode(96), String.fromCharCode(32), document.getElementById('forcedemoji'));
tvo.value='';
document.getElementById('tdoriginal').style.display='none';
newlsvsco(document.getElementById('forcedemoji').value, document.getElementById('forced_emoji'));
return '';
}

if (eval('' + tvis.length) > 0) {
tvis=tvis.replace(/\#/g, '').replace(/\&/g,'').replace(/\x/g, '').replace(/\X/g, '').replace(/\u/g, '').replace(/\U/g, '').replace(/\//g, '').replace(/\|/g, '`').replace(/\;/g, '`').replace(/\,/g, '`').replace('```', '`').replace('``', '`').replace('```', '`').replace(/\`$/g, '').replace(/\`$/g, '');
if (window.localStorage) {
if (document.getElementById('forced_emoji')) {
document.getElementById('forced_emoji').name=document.getElementById('forced_emoji').id;
}
if (tvis.trim() != '') {
window.localStorage.setItem('forced_emoji', encodeURIComponent(tvis.trim()));
if (document.getElementById('forced_emoji') && (tvis != tvis.trim() || origtvis != tvis)) {
document.getElementById('forced_emoji').value=tvis.trim();
}
} else {
window.localStorage.setItem('forced_emoji', encodeURIComponent(tvis));
}
} else {
var xexpireDate = new Date();
xexpireDate.setMonth(xexpireDate.getMonth()+6);
if (tvis.trim() != '') {
document.cookie = 'forced_emoji=' + encodeURIComponent(tvis.trim()) + '; expires=' + xexpireDate.toGMTString();
if (document.getElementById('forced_emoji') && (tvis != tvis.trim() || origtvis != tvis)) {
document.getElementById('forced_emoji').value=tvis.trim();
}
} else {
document.cookie = 'forced_emoji=' + encodeURIComponent(tvis) + '; expires=' + xexpireDate.toGMTString();
}
}
}
if (1 == 2) { change_ff(this, this.value); }
}
}

“; ?>

… to also help make this user interaction improvement happen.


Previous relevant WordPress List Style User Emoji Image List Tutorial is shown below.

WordPress List Style User Emoji Image List Tutorial

WordPress List Style User Emoji Image List Tutorial

When in yesterday’s WordPress List Style User CSS Middle Pseudo Class Tutorial we said …

(though, come to think of it, there may be another layer of thought before that … we’ll see)

Well, we saw, and did want to allow for four more feature extensions …

  1. allow for a comma separated list (that can correspond, optionally, with a comma separated pseudo-class list) … of …
  2. a mix of “list style” images and/or emojis … all …
  3. rememberable and recallable on a web browser tab via window.sessionStorage … or …
  4. rememberable and recallable on a web browser at any time in any tab via window.localStorage

… as required.

Here are some examples of use (where adding one + to end of URL uses window.sessionStorage and two ++ to end of URL uses window.localStorage) …

… using …

<?php echo ”

function locsess(inldef) {
var outldef=inldef;
if (inldef == '') { // listimage
if (decodeURIComponent(('' + window.localStorage.getItem('listimage')).replace(/^undefined/g,'').replace(/^null/g,'')) != '') {
outldef=decodeURIComponent(window.localStorage.getItem('listimage')).replace(/\%2C/g,',');
if (document.URL.indexOf('listimage=') == -1) {
if (document.URL.indexOf('?') == -1) {
location.href=document.URL.split('#')[0] + '?' + outldef.substring(1);
return inldef;
} else {
location.href=document.URL.split('#')[0] + '' + outldef;
return inldef;
}
}
} else if (decodeURIComponent(('' + window.sessionStorage.getItem('listimage')).replace(/^undefined/g,'').replace(/^null/g,'')) != '') {
outldef=decodeURIComponent(window.sessionStorage.getItem('listimage')).replace(/\%2C/g,',');;
if (document.URL.indexOf('listimage=') == -1) {
if (document.URL.indexOf('?') == -1) {
location.href=document.URL.split('#')[0] + '?' + outldef.substring(1);
return inldef;
} else {
location.href=document.URL.split('#')[0] + '' + outldef;
return inldef;
}
}
}
}
return outldef;
}

function list_style_image_check() {
var hbit=(" height: " + (location.search.split('listhimage=')[1] ? ('' + decodeURIComponent(location.search.split('listhimage=')[1].split('&')[0])) : (location.search.split('listwimage=')[1] ? ('' + Math.round(eval(('' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0]))) * 5.0 / 7.0)) : " 25")) + "px; ").replace(' height: 25px; ','');
var wbit=(" width: " + (location.search.split('listwimage=')[1] ? ('' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0])) : ' 35') + "px; ").replace(' width: 35px; ','');
var mlit=(" margin-left: " + (location.search.split('listwimage=')[1] ? ('-' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0])) : ' -35') + "px; ").replace(' margin-left: -35px; ','');
var listimage='', lsbit='&listimage=', mlbit=('' + wbit + hbit.replace('height','font-size') + hbit + mlit).replace(' width:',' display:inline-block; width:');


if ((document.URL.split('#')[0] + '&').indexOf('listimage=--&') != -1 || (document.URL.split('#')[0] + '&').indexOf('listimage=' + encodeURIComponent('--') + '&') != -1) {
if (decodeURIComponent(('' + window.localStorage.getItem('listimage')).replace(/^undefined/g,'').replace(/^null/g,'')) != '') {
window.localStorage.removeItem('listimage');
}
if (decodeURIComponent(('' + window.sessionStorage.getItem('listimage')).replace(/^undefined/g,'').replace(/^null/g,'')) != '') {
window.sessionStorage.removeItem('listimage');
}
} else if ((document.URL.split('#')[0] + '&').indexOf('listimage=-&') != -1 || (document.URL.split('#')[0] + '&').indexOf('listimage=' + encodeURIComponent('-') + '&') != -1) {
if (decodeURIComponent(('' + window.sessionStorage.getItem('listimage')).replace(/^undefined/g,'').replace(/^null/g,'')) != '') {
window.sessionStorage.removeItem('listimage');
}
}
listimage=location.search.split('listimage=')[1] ? decodeURIComponent(location.search.split('listimage=')[1].split('&')[0]).replace(/\+/g,' ') : locsess("");
if (listimage.replace(/\-/g,'') != '' && (listimage + '@#$').indexOf(' @#$') != -1) {
if (decodeURIComponent(('' + window.localStorage.getItem('listimage')).replace(/^undefined/g,'').replace(/^null/g,'')) != '') {
window.localStorage.removeItem('listimage');
}
lsbit+=encodeURIComponent(listimage.trim());
if ((location.search.split('midpseudoclass=')[1] ? ('' + decodeURIComponent(location.search.split('midpseudoclass=')[1].split('&')[0])) : ":") != ":") {
lsbit+='&midpseudoclass=' + encodeURIComponent((location.search.split('midpseudoclass=')[1] ? ('' + decodeURIComponent(location.search.split('midpseudoclass=')[1].split('&')[0])) : ":"));
}
if ((location.search.split('listwimage=')[1] ? ('' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0])) : '') != '') {
lsbit+='&listwimage=' + encodeURIComponent((location.search.split('listwimage=')[1] ? ('' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0])) : ''));
}
if ((location.search.split('listhimage=')[1] ? ('' + decodeURIComponent(location.search.split('listhimage=')[1].split('&')[0])) : '') != '') {
lsbit+='&listhimage=' + encodeURIComponent((location.search.split('listhimage=')[1] ? ('' + decodeURIComponent(location.search.split('listhimage=')[1].split('&')[0])) : ''));
}
window.localStorage.setItem('listimage', lsbit);
} else if (listimage.replace(/\-/g,'') != '' && (listimage + '@#$').indexOf(' @#$') != -1) {
if (decodeURIComponent(('' + window.sessionStorage.getItem('listimage')).replace(/^undefined/g,'').replace(/^null/g,'')) != '') {
window.sessionStorage.removeItem('listimage');
}
lsbit+=encodeURIComponent(listimage.trim());
if ((location.search.split('midpseudoclass=')[1] ? ('' + decodeURIComponent(location.search.split('midpseudoclass=')[1].split('&')[0])) : ":") != ":") {
lsbit+='&midpseudoclass=' + encodeURIComponent((location.search.split('midpseudoclass=')[1] ? ('' + decodeURIComponent(location.search.split('midpseudoclass=')[1].split('&')[0])) : ":"));
}
if ((location.search.split('listwimage=')[1] ? ('' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0])) : '') != '') {
lsbit+='&listwimage=' + encodeURIComponent((location.search.split('listwimage=')[1] ? ('' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0])) : ''));
}
if ((location.search.split('listhimage=')[1] ? ('' + decodeURIComponent(location.search.split('listhimage=')[1].split('&')[0])) : '') != '') {
lsbit+='&listhimage=' + encodeURIComponent((location.search.split('listhimage=')[1] ? ('' + decodeURIComponent(location.search.split('listhimage=')[1].split('&')[0])) : ''));
}
window.sessionStorage.setItem('listimage', lsbit);
}
if (listimage.replace(/\-/g,'') != '') {
var contbit=" content:''; ";
var dbistuff='';
var pclass=(location.search.split('midpseudoclass=')[1] ? ('' + decodeURIComponent(location.search.split('midpseudoclass=')[1].split('&')[0])) : "");
var alistimage=listimage.split(',');
var blistimage=listimage.split('.');
var iblistimage=0, jlistimage=0;
var apclass=pclass.split(',');


if (eval('' + alistimage.length) > 1) {
if (apclass[0].trim() == '') {
if (alistimage[0].toLowerCase().trim().replace(/\./g,'').replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').replace(/a/g,'').replace(/b/g,'').replace(/c/g,'').replace(/d/g,'').replace(/e/g,'').replace(/f/g,'') != '') {
dbistuff+="<style> ul.noclass li:" + apclass[0] + ":before { content: ''; display: inline-block; height: " + (location.search.split('listhimage=')[1] ? ('' + decodeURIComponent(location.search.split('listhimage=')[1].split('&')[0])) : (location.search.split('listwimage=')[1] ? ('' + Math.round(eval(('' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0]))) * 5.0 / 7.0)) : "25")) + "px; width: " + (location.search.split('listwimage=')[1] ? ('' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0])) : "35") + "px; background-image: url('" + alistimage[jlistimage] + "'); background-size: contain; background-repeat: no-repeat; margin-left: -" + (location.search.split('listwimage=')[1] ? (':' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0])) : "35") + "px; } </style>";
} else {
blistimage=alistimage[0].split('.');
// content:'\000031\0020e3';
contbit=" content:''; ";
contbit=" content:'\\" + ('000000' + blistimage[0]).slice(-6) + "'; ";
for (iblistimage=1; iblistimage<blistimage.length; iblistimage++) {
contbit=contbit.replace("';", "\\" + ('000000' + blistimage[iblistimage]).slice(-6) + "';");
}
dbistuff+="<style> ul.noclass li:" + apclass[0] + ":before { " + contbit + mlbit + " } </style>";
}
apclass[0]='nth-child(1)';
}
for (jlistimage=0; jlistimage<alistimage.length; jlistimage++) {
if (apclass.length <= eval(0 + jlistimage)) {
apclass.push(apclass[0].replace('(1)', '(' + eval(1 + jlistimage) + ')'));
}
if (alistimage[jlistimage].toLowerCase().trim().replace(/\./g,'').replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').replace(/a/g,'').replace(/b/g,'').replace(/c/g,'').replace(/d/g,'').replace(/e/g,'').replace(/f/g,'') != '') {
dbistuff+="<style> ul.noclass li:" + apclass[jlistimage] + ":before { content: ''; display: inline-block; height: " + (location.search.split('listhimage=')[1] ? ('' + decodeURIComponent(location.search.split('listhimage=')[1].split('&')[0])) : (location.search.split('listwimage=')[1] ? ('' + Math.round(eval(('' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0]))) * 5.0 / 7.0)) : "25")) + "px; width: " + (location.search.split('listwimage=')[1] ? ('' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0])) : "35") + "px; background-image: url('" + alistimage[jlistimage] + "'); background-size: contain; background-repeat: no-repeat; margin-left: -" + (location.search.split('listwimage=')[1] ? (':' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0])) : "35") + "px; } </style>";
} else {
blistimage=alistimage[jlistimage].split('.');
// content:'\000031\0020e3';
contbit=" content:''; ";
contbit=" content:'\\" + ('000000' + blistimage[0]).slice(-6) + "'; ";
for (iblistimage=1; iblistimage<blistimage.length; iblistimage++) {
contbit=contbit.replace("';", "\\" + ('000000' + blistimage[iblistimage]).slice(-6) + "';");
}
dbistuff+="<style> ul.noclass li:" + apclass[jlistimage] + ":before { " + contbit + mlbit + " } </style>";
}
}
document.body.innerHTML+=dbistuff;

} else if (listimage.toLowerCase().trim().replace(/\./g,'').replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'').replace(/a/g,'').replace(/b/g,'').replace(/c/g,'').replace(/d/g,'').replace(/e/g,'').replace(/f/g,'') != '') {
document.body.innerHTML+="<style> ul.noclass li" + (location.search.split('midpseudoclass=')[1] ? (':' + decodeURIComponent(location.search.split('midpseudoclass=')[1].split('&')[0])) : ":") + ":before { content: ''; display: inline-block; height: " + (location.search.split('listhimage=')[1] ? ('' + decodeURIComponent(location.search.split('listhimage=')[1].split('&')[0])) : (location.search.split('listwimage=')[1] ? ('' + Math.round(eval(('' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0]))) * 5.0 / 7.0)) : "25")) + "px; width: " + (location.search.split('listwimage=')[1] ? ('' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0])) : "35") + "px; background-image: url('" + listimage + "'); background-size: contain; background-repeat: no-repeat; margin-left: -" + (location.search.split('listwimage=')[1] ? (':' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0])) : "35") + "px; } </style>";
} else {
// content:'\000031\0020e3';
contbit=" content:'\\" + ('000000' + blistimage[0]).slice(-6) + "'; ";
for (iblistimage=1; iblistimage<blistimage.length; iblistimage++) {
contbit=contbit.replace("';", "\\" + ('000000' + blistimage[iblistimage]).slice(-6) + "';");
}
document.body.innerHTML+="<style> ul.noclass li" + (location.search.split('midpseudoclass=')[1] ? (':' + decodeURIComponent(location.search.split('midpseudoclass=')[1].split('&')[0])) : ":") + ":before { " + contbit + " } </style>";
}
} else if ((location.search.split('midpseudoclass=')[1] ? (':' + decodeURIComponent(location.search.split('midpseudoclass=')[1].split('&')[0])) : ":") != ":") {
var stylestuff='', sparts=document.head.innerHTML.split('ul.noclass li::before {');
if (eval('' + sparts.length) > 1) {
for (var isparts=1; isparts<sparts.length; isparts++) {
stylestuff+=' ' + sparts[isparts].split('}')[0] + ' ';
}
}
if (stylestuff != '') {
document.body.innerHTML+="<style> ul.noclass li" + (location.search.split('midpseudoclass=')[1] ? (':' + decodeURIComponent(location.search.split('midpseudoclass=')[1].split('&')[0])) : ":") + ":before { " + stylestuff + " } </style>";
}
}
}

“; ?>


Previous relevant WordPress List Style User CSS Middle Pseudo Class Tutorial is shown below.

WordPress List Style User CSS Middle Pseudo Class Tutorial

WordPress List Style User CSS Middle Pseudo Class Tutorial

Sorry, but before moving on from yesterday’s WordPress List Style Image Primer Tutorial “ul li” list style image work, we need to add another hard to remember GET argument arrangement, because between the ::


<style> ul li::before { content: ''; display: inline-block; height: 25px; width: 35px; background-image: url('" + listimage + "'); background-size: contain; background-repeat: no-repeat; margin-left: -35px; } </style>

… colons via …

<?php echo ”

function list_style_image_check() {
var listimage=location.search.split('listimage=')[1] ? decodeURIComponent(location.search.split('listimage=')[1].split('&')[0]) : "";
if (listimage != '') {
document.body.innerHTML+="<style> ul.noclass li" + (location.search.split('midpseudoclass=')[1] ? (':' + decodeURIComponent(location.search.split('midpseudoclass=')[1].split('&')[0])) : ":") + ":before { content: ''; display: inline-block; height: 25px; width: 35px; background-image: url('" + listimage + "'); background-size: contain; background-repeat: no-repeat; margin-left: -35px; } </style>";
}
}

“; ?>

… in the CSS styling, the user can now optionally insert, via “&midpseudoclass=[middle pseudo class eg. first-child]” or “?midpseudoclass=[middle pseudo class eg. first-child]” a CSS “ul li” styling additional consideration. For this URL “appendage” you might consider pseudo-class values such as …

And later, we make all this more accessible for user usage (though, come to think of it, there may be another layer of thought before that … we’ll see).

Stop Press

We decided to allow the image dimensions be arguments (probably just 5 minute ones) via …

  • &listwimage=[pixelValue]&listhimage=[pixelValue]
  • &listwimage=[pixelValue]# and listhimage is 5/7 of this

… via …

<?php echo ”

function list_style_image_check() {
var listimage=location.search.split('listimage=')[1] ? decodeURIComponent(location.search.split('listimage=')[1].split('&')[0]) : "";
if (listimage != '') {
document.body.innerHTML+="<style> ul.noclass li" + (location.search.split('midpseudoclass=')[1] ? (':' + decodeURIComponent(location.search.split('midpseudoclass=')[1].split('&')[0])) : ":") + ":before { content: ''; display: inline-block; height: " + (location.search.split('listhimage=')[1] ? ('' + decodeURIComponent(location.search.split('listhimage=')[1].split('&')[0])) : (location.search.split('listwimage=')[1] ? ('' + Math.round(eval(('' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0]))) * 5.0 / 7.0)) : "25")) + "px; width: " + (location.search.split('listwimage=')[1] ? ('' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0])) : "35") + "px; background-image: url('" + listimage + "'); background-size: contain; background-repeat: no-repeat; margin-left: -" + (location.search.split('listwimage=')[1] ? (':' + decodeURIComponent(location.search.split('listwimage=')[1].split('&')[0])) : "35") + "px; } </style>";
}
}

“; ?>

… so that you can have a “Fifth Fatter Baboon” or “Last Tall Penguin”.


Previous relevant WordPress List Style Image Primer Tutorial is shown below.

WordPress List Style Image Primer Tutorial

WordPress List Style Image Primer Tutorial

Think it might be part of “the human thaing” to “make associations” or “link things”. As such, our “link” to yesterday’s Cut to the Chase of Blog Posting Mobile Events Tutorial is WordPress blog TwentyTen them’s header.php “thinking”, but quite a different topic, in that today’s “first draft” and “terribly user unfriendly” work today revolves around CSS styling and aesthetics, rather than the event logic discussed yesterday.

In the past we’ve allowed the styling of …


ul li

… ie. “ul” element begets “li” element bullet point “looks” be user controllable … in terms of emoji usage. Well, today, we add onto that possibility, the possibility to use an image rather than an emoji, though you could hardly call our “first draft” of this in any way easily “user controllable” (but appending to a WordPress blog URL ?listimage=[someImageURL] …

<?php echo ”

function list_style_image_check() {
var listimage=location.search.split('listimage=')[1] ? decodeURIComponent(location.search.split('listimage=')[1].split('&')[0]) : "";
if (listimage != '') {
document.body.innerHTML+="<style> ul li::before { content: ''; display: inline-block; height: 25px; width: 35px; background-image: url('" + listimage + "'); background-size: contain; background-repeat: no-repeat; margin-left: -35px; } </style>";
}
}

“; ?>

… is the “behind the scenes approach” called at the document.body onload event header.php is privy to). We thank this enormously useful website for great advice here, and in days to come we improve on that “user unfriendliness”.


Previous relevant Cut to the Chase of Blog Posting Mobile Events Tutorial is shown below.

Cut to the Chase of Blog Posting Mobile Events Tutorial

Cut to the Chase of Blog Posting Mobile Events Tutorial

On the way to you reading this blog posting there have been numerous intervention points for us, as overseeing programmers …

  • PHP server layer before any client side intervention …
  • PHP header.php interfaces from server side considerations into Javascript client side considerations ahead of document.body onload event …
  • PHP header.php interfaces into Javascript (with its DOM) client side considerations at document.body onload event …
  • PHP header.php interfaces into Javascript (with its DOM) client side considerations after document.body onload event

… and it is in that last layer we dynamically create the “Cut to the Chase” elements you see reading this blog posting. In this way, to change “after document.body onload event” client side aspects to “Cut to the Chase” is not hard, even to changing the type of event …

<?php echo ”

var oncm=' oncontextmenu=';
var oncmt=' or right click or two finger gesture ';
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
oncm=' ontouchmove=';
oncmt=' or drag over gesture ';
}

“; ?>

… some “Cut to the Chase” element Javascript logic points at.

And so, given yesterday’s “wet lettuce” mobile platform response to the “oncontextmenu” intervention yesterday, we’re changing yesterday’s …

<?php echo ”

tworp.innerHTML = tworp.innerHTML.replace("<li>", "<li title='Cut to The Chase ... ... double click " + oncmt + " for blog posting image involvement'" + oncm + "' findthing=\"" + rptdtitle[ieight] + "\"; setTimeout(rcrplater,1000); nothanks=false; ' ondblclick=' findthing=\"" + rptdtitle[ieight] + "\"; setTimeout(dblrplater,1000); nothanks=false; ' onclick=' findthing=\"" + rptdtitle[ieight] + "\"; setTimeout(rplater,1000); nothanks=false; ' class='" + eight[ieight] + "'>");
// ... and ...
xpspana[ximb].innerHTML+=' <div style="display:inline-block;border:3px solid rgba(255,165,0,0.4); background-color:rgba(255,255,0,0.3); " id=cc' + zspare + '><a target=_blank style="cursor:pointer;display:inline-block;text-decoration:none; font-size:12px;" ondblclick="dblrplatern(' + String.fromCharCode(39) + xspare + String.fromCharCode(39) + ');" ' + oncm + '"rcrplatern(' + String.fromCharCode(39) + xspare + String.fromCharCode(39) + ');" href=//www.rjmprogramming.com.au/slideshow.html?title=' + encodeURIComponent(xspare) + ' " title="Cut to the Chase ... double click ' + oncmt + ' for blog posting image involvement ... to (the gist of) ' + (xspare) + '" id=tcc' + zspare + '>&#9986;</a><a target=_blank style="background: rgba(0,255,0,0.3); background: -webkit-linear-gradient(left top, rgba(0,255,0,0.3), rgba(255,255,0,0.3)); background: -o-linear-gradient(bottom right, rgba(0,255,0,0.3), rgba(255,255,0,0.3)); background: -moz-linear-gradient(bottom right, rgba(0,255,0,0.3), rgba(255,255,0,0.3)); background: linear-gradient(to bottom right, rgba(0,255,0,0.3), rgba(255,255,0,0.3)); cursor:pointer;display:inline-block;text-decoration:none;transform: scale(-1, 1); -o-transform: scale(-1, 1); -moz-transform: scale(-1, 1); -ms-transform: scale(-1, 1); -webkit-transform: scale(-1, 1); font-size:12px;" ondblclick="dblrplatern(' + String.fromCharCode(39) + xspare + String.fromCharCode(39) + ');" ' + oncm + '"rcrplatern(' + String.fromCharCode(39) + xspare + String.fromCharCode(39) + ');" href=//www.rjmprogramming.com.au/slideshow.html?title=' + encodeURIComponent(xspare) + ' " title="Cut to the Chase ... double click ' + oncmt + ' for blog posting image involvement ... to (the gist of) ' + (xspare) + '" id=ttcc' + zspare + '>&#127939;&#127998;&#8205;&#9792;&#65039;&#127939;&#127996;&#8205;&#9794;&#65039;</a><iframe style=display:none; id=icc' + zspare + ' src=></iframe></div>';

“; ?>

… to improve on yesterday’s Cut to the Chase of Blog Posting New Arguments Tutorial‘s offerings up at this WordPress blog’s TwentyTen theme’s header.php PHP code.


Previous relevant Cut to the Chase of Blog Posting New Arguments Tutorial is shown below.

Cut to the Chase of Blog Posting New Arguments Tutorial

Cut to the Chase of Blog Posting New Arguments Tutorial

Yes, yesterday’s Action Item of Blog Posting New Arguments Tutorial‘s work was all about extending what our “Cut to the Chase” functionality is capable of, by adding to any existant …

  • onclick event logic … with …
  • ondblclick event showing of the blog posting tutorial image as well as the action item in a new web browser tab
  • oncontextmenu event (ie. right click or two finger gesture) showing of the blog posting tutorial image as well as the action item in a new web browser window

… and as well as yesterday’s slideshow.html preparatory work, we needed to change our good ol’ WordPress TwentyTen themed header.php (in amongst its Javascript) as below to make this idea a reality …

New Javascript functions …
<?php echo ”

function dblrplatern(ft) {
window.open("//www.rjmprogramming.com.au/slideshow.html?dc=y&title=" + encodeURIComponent(ft), "_blank");
}

function rcrplatern(ft) {
window.open("//www.rjmprogramming.com.au/slideshow.html?rc=y&title=" + encodeURIComponent(ft), "_blank");
}


function dblrplater() {
if (findthing != "") {
window.open("//www.rjmprogramming.com.au/slideshow.html?dc=y&title=" + encodeURIComponent(findthing), "_blank");
findthing="";
}
nothanks=false;
}


function rcrplater() {
if (findthing != "") {
window.open("//www.rjmprogramming.com.au/slideshow.html?rc=y&title=" + encodeURIComponent(findthing), "_blank");
findthing="";
}
nothanks=false;
}

“; ?>
… and changes to any “Cut to the Chase” linking elements … for example …
<?php echo ”

tworp.innerHTML = tworp.innerHTML.replace("<li>", "<li title='Cut to The Chase ... ... double click or right click or two finger gesture for blog posting image involvement' oncontextmenu=' findthing=\"" + rptdtitle[ieight] + "\"; setTimeout(rcrplater,1000); nothanks=false; ' ondblclick=' findthing=\"" + rptdtitle[ieight] + "\"; setTimeout(dblrplater,1000); nothanks=false; ' onclick=' findthing=\"" + rptdtitle[ieight] + "\"; setTimeout(rplater,1000); nothanks=false; ' class='" + eight[ieight] + "'>");
// ... and ...
xpspana[ximb].innerHTML+=' <div style="display:inline-block;border:3px solid rgba(255,165,0,0.4); background-color:rgba(255,255,0,0.3); " id=cc' + zspare + '><a target=_blank style="cursor:pointer;display:inline-block;text-decoration:none; font-size:12px;" ondblclick="dblrplatern(' + String.fromCharCode(39) + xspare + String.fromCharCode(39) + ');" oncontextmenu="rcrplatern(' + String.fromCharCode(39) + xspare + String.fromCharCode(39) + ');" href=//www.rjmprogramming.com.au/slideshow.html?title=' + encodeURIComponent(xspare) + ' " title="Cut to the Chase ... double click or right click or two finger gesture for blog posting image involvement ... to (the gist of) ' + (xspare) + '" id=tcc' + zspare + '>&#9986;</a><a target=_blank style="background: rgba(0,255,0,0.3); background: -webkit-linear-gradient(left top, rgba(0,255,0,0.3), rgba(255,255,0,0.3)); background: -o-linear-gradient(bottom right, rgba(0,255,0,0.3), rgba(255,255,0,0.3)); background: -moz-linear-gradient(bottom right, rgba(0,255,0,0.3), rgba(255,255,0,0.3)); background: linear-gradient(to bottom right, rgba(0,255,0,0.3), rgba(255,255,0,0.3)); cursor:pointer;display:inline-block;text-decoration:none;transform: scale(-1, 1); -o-transform: scale(-1, 1); -moz-transform: scale(-1, 1); -ms-transform: scale(-1, 1); -webkit-transform: scale(-1, 1); font-size:12px;" ondblclick="dblrplatern(' + String.fromCharCode(39) + xspare + String.fromCharCode(39) + ');" oncontextmenu="rcrplatern(' + String.fromCharCode(39) + xspare + String.fromCharCode(39) + ');" href=//www.rjmprogramming.com.au/slideshow.html?title=' + encodeURIComponent(xspare) + ' " title="Cut to the Chase ... double click or right click or two finger gesture for blog posting image involvement ... to (the gist of) ' + (xspare) + '" id=ttcc' + zspare + '>&#127939;&#127998;&#8205;&#9792;&#65039;&#127939;&#127996;&#8205;&#9794;&#65039;</a><iframe style=display:none; id=icc' + zspare + ' src=></iframe></div>';

“; ?>


Previous relevant Action Item of Blog Posting New Arguments Tutorial is shown below.

Action Item of Blog Posting New Arguments Tutorial

Action Item of Blog Posting New Arguments Tutorial

Around here, with our WordPress blog postings, we indulge the concepts of …

  • the blog posting title
  • the blog posting text content
  • the blog posting tutorial image
  • the blog posting action item

… that last one sometimes being the same as the penultimate “tutorial image” concept, but more usually some web application URL or URL to some other place of interest.

And we have an HTML and Javascript web application that treats that “action item” as the centre of attention, rather than the usual “blog posting” focus. It is called slideshow.html and we have changed it today for some purposes we’ll go further into with tomorrow’s blog posting. We’ve added Javascript logic to accept URL ? (GET) arguments …

  • ?dc=
  • ?rc=

… in readiness to add functionality improvements around here.

Perhaps you can see ahead to tomorrow examining the changed slideshow.html “action item” as the centre of attention web application?

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