Automated Tethering of iPhone to iPad Tutorial

Automated Tethering of iPhone to iPad Tutorial

Automated Tethering of iPhone to iPad Tutorial

Thinking on yesterday’s Automated Tethering of iPhone to Mac Tutorial, the next day …

Was in the car doing a bit of work on the iPad (iOS (8th generation) Version 16.3.1), unconnected at the time, the other day, when we didn’t got get a surprise. Lo and behold, a To infinity and beyond, we looked, but no notification style dialog box came up.

But we went looking in …


Settings -> Wi-Fi -> Auto Join Hotspot

… and discovered the setting was set to “Ask to Join” while we think a better setting to get the ball rolling, here, would be “Automatic” (rather than “Never”). And so it came to pass.

And though we had to adjust Personal Hotspot settings on the iPhone to allow others to connect (automatically, now), Wi-Fi connections on the iPad became automated, and we did get connected to the big wide online connected wooooorrrrrllllldddd on the iPad via the iPhone’s Personal Hotspot this way! Yayyyyyy!


Previous relevant Automated Tethering of iPhone to Mac Tutorial is shown below.

Automated Tethering of iPhone to Mac Tutorial

Automated Tethering of iPhone to Mac Tutorial

Was in the car doing a bit of work on the MacBook Air (macOS Sonoma Version 14.5), unconnected at the time, the other day, when we got a surprise. Lo and behold, a notification style dialog box came up …

Personal Hotspot Available
Do you want to join “Robert’s iPhone”?

… presumably because we had our iPhone in the car (and had invoked its Personal Hotspot functionality in the past, as you can read about with Troubleshooting Retethering Windows 10 to iPhone Tutorial) and then, on hovering over it (it took me a day to tweak to) came up with …

Personal Hotspot Available
Do you want to join “Robert’s iPhone”?     

… that on clicking the Join button had us connected to the big wide online connected wooooorrrrrllllldddd without needing to do anything on the iPhone! Great integration!

We looked up with Google’s Image search via …


Personal Hotspot Available

… in “full FOMO horror”, getting us to read this webpage, thanks, to see that some people even expect more?! Impressive enough, and stop there, we’d say.


Previous relevant Troubleshooting Retethering Windows 10 to iPhone Tutorial is shown below.

Troubleshooting Retethering Windows 10 to iPhone Tutorial

Troubleshooting Retethering Windows 10 to iPhone Tutorial

You might say today’s “Troubleshooting Retethering Windows 10 to iPhone Tutorial” is missing a “Tethering Windows 10 to iPhone Primer Tutorial” on top of the Tethering MacBook Pro to iPhone Primer Tutorial involving the macOS wooooooorrrrrrllllllddd, but sometimes we can intimate the positives during an explanation of the negatives (… and after all that’s what it’s all about).

And yes, things go wrong in I.T.? Who’d believe it? And so, today, we had just such a disconnect re-rehearsing a way to have a Windows 10 laptop be connected to the Internet away from a WiFi router scenario offsite, but taking along the “lassooable” iPhone 6 (you guessed it … as had been done successfully in the past). Well, another whole consideration is “why would the iPhone 6 Personal Hotspot (turned on) not appear in the Windows 10 WiFi connection list” but today’s troubleshooting theme goes past that onto the practicalities of Forgetting the whY and adding the MCAand concentrating on the “how” of “how to fix this”, which via good ol’ Google


windows 10 will not connect to iphone 6 personal hotspot

… leading us to today’s star turn link (thanks) …

1 Press Windows Key + I shortcut to quickly open the Settings app.
2 When Settings app opens, navigate to Network & Internet section
3 From the menu on the left select Wi-Fi. Now click on Manage known networks.
4 List of memorized Wi-Fi networks will appear. Select your Wi-Fi network and click the Forget button.
5 Then connect to your hotspot network again.

… curiously precursored by a presumption we do not believe to have been true surmising that the hotspot password had changed. No worries, though, because the advice helped, that being to first …

  1. Forget the network (on Windows 10 laptop)
  2. Retry the reopened Personal Hotspot network (on iPhone 6)
  3. Back at same place you “Forgot”, suddenly “remember” via Properties set “Connect Automatically When in Range” on (on Windows 10 laptop) … perhaps needing the iPhone 6 Personal Hotspot password

… that last step above an “addendum” to the great advice quoted above, and summarized via today’s animated GIF presentation.

Voila! Connection for Windows 10 in a scenario where there is no WiFi router but an iPhone 6 Personal Hotspot is available. We have to say, though, two things …

  • the iPhone needs Mobile Data to be on, and to get a signal to its ISP here … and that …
  • this is likely to cost you more in cold hard cash than your home WiFi arrangements would, in all probability, for the time it takes to get the work done, in this Personal Hotspot way (and for people called “Personal Hotspot”My way)

We hope you never have this issue, and thank the contributors to troubleshooting advice, who have, and by sharing online, thereby getting answers out of people we’d like to thank, too … Dzięki.


Previous relevant Tethering MacBook Pro to iPhone Primer Tutorial is shown below.

Tethering MacBook Pro to iPhone Primer Tutorial

Tethering MacBook Pro to iPhone Primer Tutorial

Today we talk about a networking topic, regarding the idea if you are out and about, out of reach of WiFi connections, with your laptop, notebook or MacBook Pro, but you have available to you a device such as an Android or iPhone or iPad or tablet with inbuilt SIM card network connector, that networks via a mobile network (eg. here in Australia a 4G (soon to go to 5G) network) you (and we) can, perhaps …

  • “tether” your laptop, notebook or MacBook Pro (Robert’s MacBook Pro) … to that …
  • Android or iPhone (Robert’s iPhone) or iPad or tablet with inbuilt SIM card network connector accessing its mobile network (such as, here in Australia, 4G (soon to become 5G))

No, our MacBook Pro is not Mister Ed, but we do form a “stable” connection … chortle, chortle.

The clue to all this is, for us, in the iPhone’s …


Settings -> Personal Hotspot -> switch on

… and there you will see three modes of “hotspotting” …

  1. WiFi
  2. Bluetooth … enable on both and “Pair” on both
  3. USB … we use in Xcode running and testing mobile applications on iPhone (or iPad)

… the first of which is great with that scenario we talked about at the top of the article.

  1. be on iPhone and touch Settings icon
  2. touch Personal Hotspot
  3. touch to be On
  4. over at MacBook Pro and click Settings icon
  5. click WiFi
  6. pick Robert’s iPhone (or equivalent) in the list and it will have that “tethering” icon (two linked ellipses)
  7. voila! … you can surf the net, read your emails and do any of those other “online” activities … but be aware that this arrangement usually costs more in service charges

You can take a look at our PDF slideshow presentation of some of these concepts.

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

Automated Tethering of iPhone to Mac Tutorial

Automated Tethering of iPhone to Mac Tutorial

Automated Tethering of iPhone to Mac Tutorial

Was in the car doing a bit of work on the MacBook Air (macOS Sonoma Version 14.5), unconnected at the time, the other day, when we got a surprise. Lo and behold, a notification style dialog box came up …

Personal Hotspot Available
Do you want to join “Robert’s iPhone”?

… presumably because we had our iPhone in the car (and had invoked its Personal Hotspot functionality in the past, as you can read about with Troubleshooting Retethering Windows 10 to iPhone Tutorial) and then, on hovering over it (it took me a day to tweak to) came up with …

Personal Hotspot Available
Do you want to join “Robert’s iPhone”?     

… that on clicking the Join button had us connected to the big wide online connected wooooorrrrrllllldddd without needing to do anything on the iPhone! Great integration!

We looked up with Google’s Image search via …


Personal Hotspot Available

… in “full FOMO horror”, getting us to read this webpage, thanks, to see that some people even expect more?! Impressive enough, and stop there, we’d say.


Previous relevant Troubleshooting Retethering Windows 10 to iPhone Tutorial is shown below.

Troubleshooting Retethering Windows 10 to iPhone Tutorial

Troubleshooting Retethering Windows 10 to iPhone Tutorial

You might say today’s “Troubleshooting Retethering Windows 10 to iPhone Tutorial” is missing a “Tethering Windows 10 to iPhone Primer Tutorial” on top of the Tethering MacBook Pro to iPhone Primer Tutorial involving the macOS wooooooorrrrrrllllllddd, but sometimes we can intimate the positives during an explanation of the negatives (… and after all that’s what it’s all about).

And yes, things go wrong in I.T.? Who’d believe it? And so, today, we had just such a disconnect re-rehearsing a way to have a Windows 10 laptop be connected to the Internet away from a WiFi router scenario offsite, but taking along the “lassooable” iPhone 6 (you guessed it … as had been done successfully in the past). Well, another whole consideration is “why would the iPhone 6 Personal Hotspot (turned on) not appear in the Windows 10 WiFi connection list” but today’s troubleshooting theme goes past that onto the practicalities of Forgetting the whY and adding the MCAand concentrating on the “how” of “how to fix this”, which via good ol’ Google


windows 10 will not connect to iphone 6 personal hotspot

… leading us to today’s star turn link (thanks) …

1 Press Windows Key + I shortcut to quickly open the Settings app.
2 When Settings app opens, navigate to Network & Internet section
3 From the menu on the left select Wi-Fi. Now click on Manage known networks.
4 List of memorized Wi-Fi networks will appear. Select your Wi-Fi network and click the Forget button.
5 Then connect to your hotspot network again.

… curiously precursored by a presumption we do not believe to have been true surmising that the hotspot password had changed. No worries, though, because the advice helped, that being to first …

  1. Forget the network (on Windows 10 laptop)
  2. Retry the reopened Personal Hotspot network (on iPhone 6)
  3. Back at same place you “Forgot”, suddenly “remember” via Properties set “Connect Automatically When in Range” on (on Windows 10 laptop) … perhaps needing the iPhone 6 Personal Hotspot password

… that last step above an “addendum” to the great advice quoted above, and summarized via today’s animated GIF presentation.

Voila! Connection for Windows 10 in a scenario where there is no WiFi router but an iPhone 6 Personal Hotspot is available. We have to say, though, two things …

  • the iPhone needs Mobile Data to be on, and to get a signal to its ISP here … and that …
  • this is likely to cost you more in cold hard cash than your home WiFi arrangements would, in all probability, for the time it takes to get the work done, in this Personal Hotspot way (and for people called “Personal Hotspot”My way)

We hope you never have this issue, and thank the contributors to troubleshooting advice, who have, and by sharing online, thereby getting answers out of people we’d like to thank, too … Dzięki.


Previous relevant Tethering MacBook Pro to iPhone Primer Tutorial is shown below.

Tethering MacBook Pro to iPhone Primer Tutorial

Tethering MacBook Pro to iPhone Primer Tutorial

Today we talk about a networking topic, regarding the idea if you are out and about, out of reach of WiFi connections, with your laptop, notebook or MacBook Pro, but you have available to you a device such as an Android or iPhone or iPad or tablet with inbuilt SIM card network connector, that networks via a mobile network (eg. here in Australia a 4G (soon to go to 5G) network) you (and we) can, perhaps …

  • “tether” your laptop, notebook or MacBook Pro (Robert’s MacBook Pro) … to that …
  • Android or iPhone (Robert’s iPhone) or iPad or tablet with inbuilt SIM card network connector accessing its mobile network (such as, here in Australia, 4G (soon to become 5G))

No, our MacBook Pro is not Mister Ed, but we do form a “stable” connection … chortle, chortle.

The clue to all this is, for us, in the iPhone’s …


Settings -> Personal Hotspot -> switch on

… and there you will see three modes of “hotspotting” …

  1. WiFi
  2. Bluetooth … enable on both and “Pair” on both
  3. USB … we use in Xcode running and testing mobile applications on iPhone (or iPad)

… the first of which is great with that scenario we talked about at the top of the article.

  1. be on iPhone and touch Settings icon
  2. touch Personal Hotspot
  3. touch to be On
  4. over at MacBook Pro and click Settings icon
  5. click WiFi
  6. pick Robert’s iPhone (or equivalent) in the list and it will have that “tethering” icon (two linked ellipses)
  7. voila! … you can surf the net, read your emails and do any of those other “online” activities … but be aware that this arrangement usually costs more in service charges

You can take a look at our PDF slideshow presentation of some of these concepts.

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, iOS, Networking, Operating System, Software, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Pandoc Install and Public Face Sharing and Security Tutorial

Pandoc Install and Public Face Sharing and Security Tutorial

Pandoc Install and Public Face Sharing and Security Tutorial

It’s interesting thinking on today’s work, further to yesterday’s Pandoc Install and Public Face Tutorial, teaming …

  • sharing … and …
  • security

… ideas and concepts do not feel like likely “conceptfellows”. But these two ideas share the same repository, if you will … our turning to …

/tmp/

… Linux output file placement, as a safe place to not only …

  • not be seen or accessible to the public … but also …
  • a place where if clobbering takes place it is of little consequence (as it is not available to any Javascript)

… you can see us implementing with the changed macos_textutil_convert.php working in the old way and now in the new way now with safer “midair feeling” outputs.


Previous relevant Pandoc Install and Public Face Tutorial is shown below.

Pandoc Install and Public Face Tutorial

Pandoc Install and Public Face Tutorial

As with the recent Ffmpeg Install and Public Face Tutorial there’s an opportunity with our new web server to install Document Conversion command line software known as …


pandoc

… we install on AlmaLinux9 via …


dnf install pandoc

… and which we can interface to via our “public facing” inhouse PHP …

As you can imagine there is an extra security concern here, and working through being a stage two set of changes, before we display the output document file directly, and concern ourselves with similar security issues uploads worry us with, but, for now, see where we are at so far.


Previous relevant Ffmpeg Install and Public Face Tutorial is shown below.

Ffmpeg Install and Public Face Tutorial

Ffmpeg Install and Public Face Tutorial

Our recent web server VPS migration can not only be …

  • a migration of functionality (eg. this WordPress blog) … as well as …
  • an opportunity to open up new vistas of serverside functionality

… such as today’s ffmpeg install, which is only feasible because of the …

  • additional diskspace … chance on new web server allows for …
  • chance to install ffmpeg …

    dnf config-manager --set-enabled powertools
    dnf install --nogpgcheck https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-$(rpm -E %rhel).noarch.rpm -y
    dnf install --nogpgcheck https://mirrors.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-$(rpm -E %rhel).noarch.rpm -y
    dnf install ffmpeg

    … thanks to this great link, along with ImageMagick …

… on this new “public face” (even more public when DNS is applied later).

Codewise this involved …

… further to recent work touching these ideas with Animated GIF Creator Overlayed Images Top Left Tutorial.

See some of this public install of ffmpeg here.


Previous relevant Animated GIF Creator Overlayed Images Top Left Tutorial is shown below.

Animated GIF Creator Overlayed Images Top Left Tutorial

Animated GIF Creator Overlayed Images Top Left Tutorial

To add to the recent Animated GIF Creator Overlayed Images Tutorial‘s user interaction logic, we add a way to control those two “overlay” CSS properties …

  • left
  • top

… but more in the sense that we allow CSS …

  • margin-eft
  • margin-top

… come into the picture, after a dalliance with CSS calc thoughts.

This allows for offsetted images be part of the “overlay mix” that you can retry this at our changed tutorial_to_animated_gif.php inhouse public domain Animated GIF Creator.


Previous relevant Animated GIF Creator Overlayed Images Tutorial is shown below.

Animated GIF Creator Overlayed Images Tutorial

Animated GIF Creator Overlayed Images Tutorial

We wanted to add an “Overlayed Images” functionality component to the “Animated GIF Creator” of Animated GIF Creator Video Intranet Tutorial, today.

The work involves both of the HTML design “big concepts” we are keen on at this blog …

  • overlay … via CSS control of
    1. position:absolute;top:0px;left:0px;
    2. opacity:1.0;
    3. z-index:1;
  • reveal … lately, mostly, via HTML use of …
    1. details
    2. summary

… the latter being the “container” for our interactive input be able to control overlay items 2 and 3, which affect the “overlayed images” output display via the clicking of a new “Overlay Images” button. That button …


<input disabled onclick="overlaythem();" id="overlayit" type="button" title='Overlay Images' value='Overlay Images'></input>

… starts off as disabled … and works with new HTML div elements …


<div id=overlayedj><h1>&nbsp;</h1><br></div><div id=overlayedi></div>

… until at least two images are defined, at which time the button becomes enabled …


function onfit(ithis) {
if (ithis.value == '' && ('' + ithis.placeholder).indexOf(']') != -1) {
ithis.value=('' + ithis.placeholder).split('[')[1].split(']')[0];
}
ithis.type='number';
}

function overlayds(inm, newop, newzi) {
var outdets='';
var divrect=null;
var poslt=' data-style=\"position:absolute;left:px;top:px;\" ';
var reposit='';
if (!document.getElementById('detsum' + ('' + inm))) {
if (document.getElementById('overlayedi').innerHTML == '') {
document.getElementById('overlayedi').title='Overlayed Images Below ... Click for It in New Window ...';
document.getElementById('overlayedj').innerHTML='<h1>Overlayed Images Below ...</h1><br>';
divrect=document.getElementById('overlayedi').getBoundingClientRect();
poslt=' data-style=\"position:absolute;left:' + ('' + divrect.left).split('.')[0].trim() + 'px;top:' + ('' + eval(200 + eval('' + ('' + divrect.top).split('.')[0]))).trim() + 'px;\" ';
} else {
poslt=' data-style=\"' + document.getElementById('detsum1').getAttribute('data-style') + '\" ';
}
outdets='&nbsp;&nbsp;<details ' + poslt + ' id=\"detsum' + ('' + inm) + '\" style=\" display:inline-block; \" open><summary id=\"sumdet' + ('' + inm) + '\">Overlay</summary><input onchange=overlayds(' + inm + ',this.value,String.fromCharCode(32)); onblur=overlayds(' + inm + ',this.value,String.fromCharCode(32)); type=text onfocus=onfit(this); id=\"opacity' + ('' + inm) + '\" style=\" display:inline-block; \" placeholder=\"Opacity [1.00]\" value=\"\" step=0.01 min=0.00 max=1.00></input><br><input onfocus=onfit(this); onchange=overlayds(' + inm + ',String.fromCharCode(32),this.value); onblur=overlayds(' + inm + ',String.fromCharCode(32),this.value); type=text id=\"zindex' + ('' + inm) + '\" style=\" display:inline-block; \" placeholder=\"Z-Index [1]\" value=\"\" min==999 max=999 step=1></input><br></details>';
reposit=poslt.replace(' data-',' ');
reposit=reposit.replace('\"', '\"opacity:1.0;z-index:1;');
if (document.getElementById('overlayedi').innerHTML == '') {
document.getElementById('overlayedi').innerHTML='<img id=\"imgdet' + ('' + inm) + '\" src=\"' + document.getElementById('slideshow' + ('' + inm).replace(/^1$/g,'')).value + '\" ' + reposit + '></img>';
document.getElementById('overlayedi').style.width=('' + document.getElementById('imgdet' + ('' + inm)).width).replace('px','') + 'px';
document.getElementById('overlayedi').style.height=('' + document.getElementById('imgdet' + ('' + inm)).height).replace('px','') + 'px';
document.getElementById('overlayedi').onclick = function(){ var woo=window.open('','_blank','top=100,left=100,width=' + document.getElementById('overlayedi').style.width.replace('px','') + ',height=' + document.getElementById('overlayedi').style.height.replace('px','')); woo.document.write('<html><head><title>Overlayed Images Below ...</title></head><body>' + document.getElementById('overlayedi').outerHTML.replace(/left\:[\ ]*/g,'left:0.0').replace(/top\:[\ ]*/g,'top:0.0') + '</body></html>'); woo.document.title='Overlayed Images Below ...'; };
} else {
document.getElementById('overlayedi').innerHTML+='<img id=\"imgdet' + ('' + inm) + '\" src=\"' + document.getElementById('slideshow' + ('' + inm).replace(/^1$/g,'')).value + '\" ' + reposit + '></img>';
}
} else {
document.getElementById('detsum' + ('' + inm)).style.display='inline-block';
if (newop != ' ') {
if (newop.trim() == '') {
document.getElementById('imgdet' + inm).style.opacity='1.0';
} else {
document.getElementById('imgdet' + inm).style.opacity='' + newop;
}
}
if (newz != ' ') {
if (newz.trim() == '') {
document.getElementById('imgdet' + inm).style.zIndex='1';
} else {
document.getElementById('imgdet' + inm).style.zIndex='' + newzi;
}
}
}
return outdets;
}

function overlaythem() {
var suffidea=1;
while (document.getElementById('slideshow' + ('' + suffidea).replace(/^1$/g, '')).value != '') {
document.getElementById('ours' + ('' + suffidea)).innerHTML+=overlayds(suffidea,'','');
suffidea++;
}
}

You can try this at our changed tutorial_to_animated_gif.php inhouse public domain Animated GIF Creator.


Previous relevant Animated GIF Creator Video Intranet Tutorial is shown below.

Animated GIF Creator Video Intranet Tutorial

Animated GIF Creator Video Intranet Tutorial

With the recent Animated GIF Creator Video Revisit Tutorial (preceding Animated GIF Creator Video Share Tutorial) we wrote …

… one reason being that we do not want to install the wonderful ffmpeg (command line video creation tool) on the RJM Programming domain, but, in macOS, here with MAMP, we are quite happy to live with the Homebrew (Terminal application’s) install …

… setting up what could be “lost functionality”, but today, we come around to either adding a new …


Convert to Video

… dropdown option should all be ritchy ditch, and if not, often we will add new “Advice” dropdown options to remind the user what they’d need to arrange to get to a “Convert to Video” scenario.

Selecting “Convert to Video” sets up a hydrid “Internet/Intranet” feeling scenario where …

  • the user is using our changed tutorial_to_animated_gif.php inhouse public domain Animated GIF Creator containing this new “Convert to Video” option off the “ImageMagick” dropdown …
  • the user defines some image slide data … eg. browsing to create data-URIs (but careful not to do too many) …
  • the user selects that “Convert to Video” option …
  • a window.open popup calls URL like …
    HTTP://localhost:8888/PHP/animegif/tutorial_to_animated_gif.php?video=1687644
    … in a new window …
  • those data-URIs are converted into /tmp/jmtmp0*.[imageExt] files … ready for …
  • ffmpeg commands like …

    ffmpeg -framerate 0.1 -i /tmp/jmtmp%03d.jpeg -c:v libvpx-vp9 -pix_fmt yuva420p -lossless 1 -c:a copy video.webm; ffmpeg -i video.webm video.mov 2>> video.bad

    … be nested in PHP exec (via MAMP local web server incarnation of the inhouse Animated GIF Creator) as a way to create videos …
  • which can be downloaded within that public domain “parent” inhouse Animated GIF Creator session

Which begs the question …


How do we know when to offer the "Convert to Video" option on that dropdown?

This logic is centred around a few useful ideas (with this cross domain scenario ruling out Ajax and Iframe src= definitions, as useful ways to go) …

  1. open the MAMP local web server “HTTP://localhost:8888/PHP/animegif/tutorial_to_animated_gif.php” URLs in an iframe (with onload event logics) pointed at by a window.open second argument (effectively avoiding any loose useful or not popup windows hanging around) …
  2. the most we can ask at the receiver is that window.opener is defined … and if so, just at that discovery …
  3. an image called “amhere.jpg” is created via PHP GD functionality … and back at the “public domain” parent within the iframe onload logic (where with contentWindow or contentDocument do not expect a document.body or even a document) …
  4. we attempt to “hotlink” that MAMP local web server image … as per …

    var tryit='http://localhost:8888/PHP/animegif/amhere.jpg';

    document.getElementById('ctvopt').value='advice';
    document.getElementById('ctvopt').innerHTML='Advice on Convert to Video';

    if (tryit != '') {
    var im=new Image();

    im.onload = function() {
    document.getElementById('ctvopt').value='video';
    console.log('this.height=' + eval('' + this.height));
    if (eval('' + this.height) >= 20) {
    document.getElementById('ctvopt').innerHTML='Convert to Video';
    } else {
    document.getElementById('ctvopt').innerHTML='Convert to Video (but ffmpeg not installed or in unexpected place)';
    }
    document.getElementById('imsel').title='All except Convert to Video, which needs ffmpeg installed, use ImageMagick';
    };


    im.src=tryit;
    tryit='';
    }


Previous relevant Animated GIF Creator Video Revisit Tutorial is shown below.

Animated GIF Creator Video Revisit Tutorial

Animated GIF Creator Video Revisit Tutorial

We hope you realize that our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator (helped out by a changed emailhtml.php inhouse email creator helper serverside PHP web application) can be accessed …

  1. in that public RJM Programming mode of use above … but even better can be …
  2. download relevant code to macOS MAMP local web server places off /Applications/MAMP/htdocs/ $_SERVER[‘DOCUMENT_ROOT’] places …

    … and check the code for the validity of any ImageMagick paths … and if not all these conditions, simulate the same and cobble it together in the code

… one reason being that we do not want to install the wonderful ffmpeg (command line video creation tool) on the RJM Programming domain, but, in macOS, here with MAMP, we are quite happy to live with the Homebrew (Terminal application’s) install …


brew install ffmpeg

… to open a whole new woooooorrrrlllllddd of video creation opportunities using this MAMP local web URL …


HTTP://localhost:8888/PHP/animegif/tutorial_to_animated_gif.php# Animated GIF Creator on MAMP local web server

And so, onto yesterday’s Animated GIF Creator PDF Last Reveal Tutorial we decided to revisit video creation parts of our inhouse Animated GIF Creator on this MacBook Air. We needed to reinstall ffmpeg, and we show that in today’s animated GIF tutorial picture and also created the “video.mov” video below, in the process …

… we tweaked out of “video/mp4” ffmpeg created videos thinking towards “video/webm” or “video.mov” ffmpeg created videos that suit the “few frames but spaced out video” we wanted to achieve for all practical purposes, that “video/mp4” playing too fast for us to see anything much but the first and last slide …

<?php

$videofr=" -r " . (1000 / $delay) . " ";
$videofr=" -r " . (1000 / $delay) . " -filter:v setpts=" . ($delay / 1000) . "*PTS ";
$videomime="video/mp4";
$videoext=".mp4";

$videofr=" -framerate 0.1 ";
$videoext=".webm";
$videomime="video/webm";
$videomidbit="-c:v libvpx-vp9 -pix_fmt yuva420p -lossless 1 -c:a copy";
//$videocmd=$videopath . "ffmpeg -r " . (1000 / $delay) . " -filter:v setpts=" . ($delay / 1000) . "*PTS " . " -i " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "%03d.jpg " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.mp4 2> " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.bad";
//$svideocmd="ffmpeg -r " . (1000 / $delay) . " -filter:v setpts=" . ($delay / 1000) . "*PTS " . " -i " . "%03d.jpg " . "video.mp4";
$videocmd=$videopath . "ffmpeg " . $videofr . " -i " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "%03d.jpg " . $videomidbit . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video" . $videoext . " 2> " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.bad";
$svideocmd="ffmpeg " . $videofr . " -i " . "%03d.jpg " . $videomidbit . " " . "video" . $videoext;
$videocmd.="; " . $videopath . "ffmpeg -i " . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video" . $videoext . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.mov 2>> " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.bad";
$svideocmd.="; " . "ffmpeg -i " . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video" . $videoext . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.mov 2>> " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.bad";
$videohtml="<video title='" . $svideocmd . "' controls id=ivideo type='" . $videomime . "'><source src='video.mov'></source><source src='video" . $videoext . "'></source></video>";
$videosuffix="";

?>


Previous relevant Animated GIF Creator PDF Last Reveal Tutorial is shown below.

Animated GIF Creator PDF Last Reveal Tutorial

Animated GIF Creator PDF Last Reveal Tutorial

As a web application programmer we like buttons. There are “buttons” and there are buttons. Yes, there is an HTML button element, and it and the input type=button element render as that part of a webpage most recognizable to users the world over. You click or tap this button and something usually happens.

But we also enjoy “Emoji Buttons” for we graphically challenged programmers. Using an emoji text and graphic can make span elements or p elements or lots of other HTML elements that have an innerHTML property, be like a very succinct button like entity, also appreciated around here because it takes up so little webpage “real estate”.

And so onto yesterday’s Animated GIF Creator PDF Order Tutorial we set about, today, “revealing” any enduring animated GIF and/or PDF created during a previous session, using Emoji Buttons as the email/SMS sharing action buttons.

We say “revealing” because, like the way “Emoji Buttons” save webpage “real estate”, so can the use of the HTML5 details/summary element combination. It is in that summary “enduring” header part of that combination we can place some “Emoji Buttons”. You will (once you start creating and sharing animated GIFs and/or PDFs) see from our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator (helped out by a changed emailhtml.php inhouse email creator helper serverside PHP web application) that we place three Emoji Buttons …

  1. 📟 SMS (Animated GIF or PDF) Limited relevance period (ie. no data URIs involved, so rely on an absolute URL whose content might change or start not to exist down the track) … via “a” “sms:” link click/tap
  2. 📧 Email (Animated GIF or PDF) Limited relevance period (ie. no data URIs involved, so rely on an absolute URL whose content might change or start not to exist down the track) … via “a” “mailto:” link click/tap
  3. 📧 Email (Animated GIF or PDF) Enduring relevance (ie. data URIs involved, so do not rely on any absolute URL whose content might change or start not to exist down the track) … via PHP mail function means of sending email with HTML attachment containing the relevant Animated GIF or PDF

Yes, “Emoji Buttons” can have their size controlled but not by the usual CSS width and height properties, but by the CSS font-size property. Here is the new Javascript function that those Emoji Button “onclick” logic points to …

<?php eho ”

function askes(isemail, isoab) {
var esask='', izhr=null, izform=null;
var isoa=document.getElementById(isoab.id.replace('b',''));
if (isemail) {
esask=prompt('Please enter email address to send this to', '');
if (esask != null) {
if (esask.indexOf('@') != -1) {
if (isoa.outerHTML.indexOf('<img') == 0) {
//alert('More Animated GIF to come');
izhr = new XMLHttpRequest();
izform=new FormData();
izform.append('to', esask.trim());
izform.append('inline', '" . dirname(__FILE__) . DIRECTORY_SEPARATOR . server_remote_addr() . ".gif" . "');
izform.append('subj', 'My Latest Animated GIF via RJM Programming ... ');
izform.append('tdhuhta', ('<body><div title=\"" . explode('/animegif',$durlis)[0] . '/animegif/' . server_remote_addr() . "\" style=\"overflow:auto;-webkit-overflow-scrolling:touch;height:100%;\"><img style=\"width:100%;height:900px;\" src=\"" . dirname(__FILE__) . DIRECTORY_SEPARATOR . server_remote_addr() . ".gif" . "\"></img></div></body>'));
izhr.open('post', '//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php', true);
izhr.send(izform);
} else if (isoa.outerHTML.indexOf('<a') != 0) {
//alert('More PDF to come');
izhr = new XMLHttpRequest();
izform=new FormData();
izform.append('to', esask.trim());
izform.append('inline', '" . dirname(__FILE__) . DIRECTORY_SEPARATOR . server_remote_addr() . "_animegif.pdf" . "');
izform.append('subj', 'My Latest PDF via Animated GIF via RJM Programming ... ');
izform.append('tdhuhta', ('<body><div title=\"" . explode('/animegif',$durlis)[0] . '/animegif/' . server_remote_addr() . "_\" style=\"overflow:auto;-webkit-overflow-scrolling:touch;height:100%;\"><object style=\"width:100%;height:900px;\" type=\"application/pdf\" data=\"" . dirname(__FILE__) . DIRECTORY_SEPARATOR . server_remote_addr() . "_animegif.pdf" . "\"></object></div></body>'));
izhr.open('post', '//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php', true);
izhr.send(izform);
} else {
isoa.href='mailto:' + esask.trim() + '?' + isoa.href.split('?')[1];
isoa.click();
}
}
}
} else {
esask=prompt('Please enter SMS number to send this to', '');
if (esask != null) {
if ((esask.trim() != '' && esask.trim().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,'') == '')) {
isoa.href='sms:' + esask.trim() + '&' + isoa.href.split('&')[1];
isoa.click();
}
}
}
}

“; ?>

Cute, huh?!


Previous relevant Animated GIF Creator PDF Order Tutorial is shown below.

Animated GIF Creator PDF Order Tutorial

Animated GIF Creator PDF Order Tutorial

Order becomes an interesting subject to us today regarding the PDF conversions possible in amongst the Animated GIF creating of yesterday’s Animated GIF Creator PDF Share Tutorial.

That is because we may have some advanced users out there that want that possibility of differentiating the data of …

  • animated GIF … containing all features asked for, in totality … from the chance for the user to have any of the PDF conversion option sets below …
  • PDF … one of …
    1. no PDF conversion
    2. full PDF conversion … with the user choices regarding raw image content and title and watermarking and ImageMagick and GD modifiers
    3. light PDF conversion … with the user choices regarding just raw image content (the only option out of these last three available before today’s work)
    4. medium PDF conversion … with the user choices regarding just ImageMagick and GD modifiers

… perhaps as a “before and after” tool regarding presentations, maybe?

No dropdowns used here (enforcing an order), just the user’s order in which they choose to select the “PDF conversion” option from the ImageMagick dropdown (in relation to other selections) determining how and when this PDF conversion occurs in the workflow through to creating the animated GIF with our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator serverside PHP web application. Just remember to select PDF Conversion as early as possible to do that “light PDF conversion” option above and last thing if you are interested in “full PDF conversion” (where you can create PDF documents with the bells and whistles ImageMagick and GD modifiers can offer) and today’s tutorial picture is an example of “medium PDF conversion” (when we ordered our settings by first Grayscale, second PDF conversion and last title and watermarking options). Clicking or tapping the ImageMagick link can get the user to the Javascript popup window where they might define the email or SMS recipient for that PDF conversion data file download.


Previous relevant Animated GIF Creator PDF Share Tutorial is shown below.

Animated GIF Creator PDF Share Tutorial

Animated GIF Creator PDF Share Tutorial

To share yesterday’s Animated GIF Creator PDF Conversion Tutorial PDF data formatted image slides (and then onto an animated GIF) would be a step forward, wouldn’t you say?

What sharing conduits do we code for? We always intended …

  • email … but as the day wore on trying to get the usage to work on mobile and non-mobile we decided to relinquish our wish to not have to create a user specific enduring (until that same browser type and user combination share) PDF document for the user request … mainly to get mobile email downloads to be friendly … and so this opened the door for …
  • SMS … to access that enduring PDF as a URL in the SMS message (that becomes a link for the recipient)

… the email methodology used being that “midair feeling” Ajax/FormData approach in our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator serverside PHP web application …

<?php echo ”

function emailhtmlit() {
var induri=ginduri;
var pemail='" . urldecode($_GET['outpdf']) . urldecode($_POST['outpdf']) . "';
if (pemail != null) {
if (pemail.indexOf('@') != -1 || (pemail.trim() != '' && pemail.trim().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,'') == '')) {
if (induri.trim() == '') {
if (induri == '') {
document.getElementById('pdfproposed').src='./animegif.pdf?rand=' + Math.floor(Math.random() * 19854654);
} else {
ginduri='found';
}
setTimeout(emailhtmlit, 15000);
} else {
ginduri='';
var zhr = new XMLHttpRequest();
var zform=new FormData();
if (pemail.indexOf('@') != -1) { zform.append('to', pemail); }
zform.append('inline', '" . dirname(__FILE__) . DIRECTORY_SEPARATOR . "animegif.pdf" . "');
zform.append('subj', 'My PDF version of Animated GIF via RJM Programming ... ');
zform.append('tdhuhta', ('<body><div title=\"" . explode('/animegif',$durlis)[0] . '/animegif/' . server_remote_addr() . "_\" style=\"overflow:auto;-webkit-overflow-scrolling:touch;height:100%;\"><object style=\"width:100%;height:900px;\" type=\"application/pdf\" data=\"" . dirname(__FILE__) . DIRECTORY_SEPARATOR . 'animegif.pdf' . "\"><embed style=\"width:100%;height:900px;\" type=\"application/pdf\" src=\"" . dirname(__FILE__) . DIRECTORY_SEPARATOR . 'animegif.pdf' . "\"></embed></object></div></body>'));
//zform.append('tdhuhta', ('<body><iframe srcdoc=\"" . dirname(__FILE__) . DIRECTORY_SEPARATOR . 'animegif.pdf' . "\"></iframe></body>'));
zhr.open('post', '//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php', true);
zhr.send(zform);
if (pemail.indexOf('@') == -1) {
var hrefp=document.getElementById('pdfsms').href.split('&body=')[0];
hrefp+=pemail.trim() + '&body=' + document.getElementById('pdfsms').href.split('&body=')[1];
document.getElementById('pdfsms').href=hrefp;
document.getElementById('pdfsms').click();
}
}
}
}
}

“; ?>

… and this called on our PHP email creator helper to better interface in its $_POST arguments reading section in our changed emailhtml.php inhouse email creator helper serverside PHP web application …

<?php

$psacv="";
$okayin=true;
$subd="";
$subptitle='';
$subdata="";
$subfile="";
$getpostfound=false;
<br>
foreach( $_POST as $name=>$val ) {
if ($val != "") {
// blah blah blah //file_put_contents("jnv." . $name, "jnv.inv00 " . strlen($phpcont));
if ($name == "tdhuhta" && $subfile != "" && $subdata != "" && strpos(str_replace("+"," ",urldecode($val)), $subfile) !== false) {
if (strpos(str_replace("+"," ",urldecode($val)), ' srcdoc="') !== false || strpos(str_replace("+"," ",urldecode($val)), ' data="') !== false) {
if (strpos(str_replace("+"," ",urldecode($val)), ' title="') !== false) { //file_put_contents('haaa.aaa',explode('/animegif/', explode('"', explode(' title="', str_replace("+"," ",urldecode($val)))[1])[0])[1]);
if (!file_exists('../PHP/animegif/' . explode('/animegif/', explode('"', explode(' title="', str_replace("+"," ",urldecode($val)))[1])[0])[1] . 'animegif.pdf')) {
if (file_exists('../PHP/animegif/animegif.pdf')) {
copy('../PHP/animegif/animegif.pdf', '../PHP/animegif/' . explode('/animegif/', explode('"', explode(' title="', str_replace("+"," ",urldecode($val)))[1])[0])[1] . 'animegif.pdf');
}
}
$psacv=explode('"', explode(' title="', str_replace("+"," ",urldecode($val)))[1])[0] . 'animegif.pdf';
$subptitle='<a target=_blank href="' . explode('"', explode(' title="', str_replace("+"," ",urldecode($val)))[1])[0] . 'animegif.pdf">Mobile whole PDF</a><br>';
}
$vrest=explode('"', explode(' srcdoc="',str_replace("+"," ",urldecode($val)))[1])[0];
$val=urlencode("<body>" . $subptitle . "<iframe style='width:100%;height:95vh;overflow:auto;-webkit-overflow-scrolling:touch;' srcdoc='<div style=width:92%;height:95vh;overflow:auto;-webkit-overflow-scrolling:touch;><object id=myobj style=width:95%;height:95vh; type=application/pdf data=\"" . $subdata . "\"></object></div>'></iframe></body>");
}
// blah blah blah
if ($name == "inline") {
if (strpos(str_replace("+"," ",urldecode($val)), 'animegif.pdf') !== false && isset($_POST['tdhuhta'])) {
if (file_exists(str_replace("+"," ",urldecode($val)))) {
$subfile=str_replace("+"," ",urldecode($val));
$subdata='data:application/pdf;base64,' . base64_encode(file_get_contents(str_replace("+"," ",urldecode($val))));
$val="";
$name="x";
$okayin=false;
}
}
// blah blah blah
}
}

?>

Creating the PDFs got helped out in “reliability terms” via the introduced animegif.php inhouse Wait Around Longer serverside PHP web application.


Previous relevant Animated GIF Creator PDF Conversion Tutorial is shown below.

Animated GIF Creator PDF Conversion Tutorial

Animated GIF Creator PDF Conversion Tutorial

Up to yesterday’s Animated GIF Creator Slide Specific Application Tutorial the recent progress had us …

  • knowing the good places to intervene between the original slide image data being read in and the animated GIF slide output … and …
  • involvement of ImageMagick … so, today, these two help us down the path to …
  • adding PDF as an output format possibility, in addition to the animated GIF and other ideas floated as output formats

… with our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator serverside PHP web application.

We have more “reliability work” and “email sharing work” to go after today’s start, but it primarily called on ImageMagick command line’s talent for a command like …


convert /tmp/imtmp0*.*[gGmMiI]* /tmp/imtmp000.pdf

… to “concatenate” into the one output PDF file (called “/tmp/imtmp000.pdf”) the slides, arranged by our code into that “/tmp/imtmp0*.*[gGmMiI]*” (file specification) arrangement above. Yes, we meant “convert” above, as “mogrify” (batch work) appears not to be able to perform this task.

We hope you stay the course!


Previous relevant Animated GIF Creator Slide Specific Application Tutorial is shown below.

Animated GIF Creator Slide Specific Application Tutorial

Animated GIF Creator Slide Specific Application Tutorial

It’s all fine and good improving on the ImageMagick and GD and Exif functionality modifications like with yesterday’s Animated GIF Creator Exif Rotation Compensation Tutorial, but in reality, if you are going to start creating animated GIFs to explain a process, you are going to want to apply these “slide modifiers” on a slide by slide basis, rather than enforcing a “whole of animated GIF slide set” paradigm, as for the last few days worth of work.

And so, we decided to do what we often do, “sliding in” more functionality (chortle, chortle). We tend to want to …

  • start with hardcoded text (or element) … somewhere … today it happens to be in an HTML span element that once involved just …

    <span id="smyim"></span>

    … and used to get filled, Javascript DOM wise, when needed via …

    document.getElementById('smyim').innerHTML='ImageMagick switches: '; // and yes, it remains that way even now, but read on ...
  • add intelligence (quite often that being onclick logic(s)) to that hardcoded element via …

    <span id=smyim title=Application onclick=applyto(); style=cursor:pointer;text-decoration:underline;></span>
  • that serves the purpose, as the user clicks/taps it (alerted to that fact, perhaps, because we underline the element and add an appropriate cursor when hovering over it (plus a title)), of calling Javascript …

    function applyto() {
    var huhto=prompt('Apply ImageMagick and/or GD to which slides, in comma separated list, counting starting with 1? Defaults to applying to all slides. Comma delimit. Negatives mean all but. Ranges can be specified. For example ... 2,4-7,9', document.getElementById('appliedto').value);
    if (huhto == null) { huhto=''; }
    if (huhto.trim() == '') {
    document.getElementById('appliedto').value='';
    document.getElementById('smyim').title='Application';
    } else {
    document.getElementById('appliedto').value=huhto.trim();
    document.getElementById('smyim').title=huhto.trim();
    }
    }
  • to glean an (often times out of the normal workflow of the web application) informational piece of data, interactively, from the user, via a Javascript prompt popup

So that’s the clientside of this work … “alerting the user to the existance of the functionality” you might say.

And then there’s “the application” of that nuanced user requirement. And that’s where the “inhouse ‘our’ prefix to wrapper function name paradigms” come in handy. We introduced “blanket” functionality thoughts via this approach, and so to “partially undo” that thinking, we make the “our” prefix conditional, as is available to us with our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator serverside PHP web application (helped out by a changed exif_rotation_check.php inhouse Exif detector PHP helper), as per

<?php

function ourcomplicated($inio, $iappl) {
$ideasl=explode(",", str_replace(' ','',$iappl));
$xour="our";
for ($iqa=0; $iqa<sizeof($ideasl); $iqa++) {
if (trim($ideasl[$iqa]) != '') {
$xour="";
if (('-' . $inio) == trim($ideasl[$iqa])) { return ""; }
$ideasr=explode("-", str_replace(' ','',trim($ideasl[$iqa])));
for ($iqb=0; $iqb<sizeof($ideasr); $iqb++) {
if (('' . $inio) == trim($ideasr[$iqb])) {
return "our";
}
if ($iqb == 1) {
if (trim($ideasr[1]) == "") { $ideasr[1]="99999999"; }
if ($inio >= $ideasr[0] && $inio <= $ideasr[1]) { return "our"; }
}
}
}
}
return $xour;
}


?>

teamed with

<?php

$ours="our";
for ($io=1; $io$ours=ourcomplicated($io, $iappliedto);
// blah blah blah
if (strpos($aphoto[0], ";base64,") !== false) {
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefromstring(base64_decode('" . explode(";base64,",$aphoto[0])[1] . "'));", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachonestring));
} else if (strpos(strtolower($aphoto[0]), "//") !== false) {
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefromstring(@file_get_contents('" . $prefix . $aphoto[0] . "'));", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
} else if (strpos(strtolower($aphoto[0]), ".jp") !== false) {
if (strpos($prefix, "../../") !== false && !file_exists($prefix . $aphoto[0]) && file_exists(str_replace("../../","../",$prefix) . $aphoto[0])) {
$prefix=str_replace("../../","../",$prefix);
}
//file_put_contents('qpqp.qpqp', $eachone . "\n\n" . $atext . "\n\n" . str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefromjpeg('" . $prefix . $aphoto[0] . "');", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
//file_put_contents('qpqpqp.qpqpqp', $gifphp);
} else if (strpos(strtolower($aphoto[0]), ".png") !== false) {
if (strpos($prefix, "../../") !== false && !file_exists($prefix . $aphoto[0]) && file_exists(str_replace("../../","../",$prefix) . $aphoto[0])) {
$prefix=str_replace("../../","../",$prefix);
}
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefrompng('" . $prefix . $aphoto[0] . "');", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
} else if (strpos(strtolower($aphoto[0]), ".gif") !== false) {
if (strpos($prefix, "../../") !== false && !file_exists($prefix . $aphoto[0]) && file_exists(str_replace("../../","../",$prefix) . $aphoto[0])) {
$prefix=str_replace("../../","../",$prefix);
}
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefromgif('" . $prefix . $aphoto[0] . "');", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
} else if (strpos(strtolower($aphoto[0]), ".bmp") !== false) {
if (strpos($prefix, "../../") !== false && !file_exists($prefix . $aphoto[0]) && file_exists(str_replace("../../","../",$prefix) . $aphoto[0])) {
$prefix=str_replace("../../","../",$prefix);
}
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefrombmp('" . $prefix . $aphoto[0] . "');", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
}
// blah blah blah
}

?>

We use these “new abilities” better explaining “the abscence or otherwise of Exif checking”, and the implications of that in the animated GIF creator woooooorrrrrrlllllddd, contrasting the first two slides, showing one with “No Exif checking” (the bad old days) versus “With Exif checking” (the renaissance of liberated thinking in the South South East woooorrrrrlllldddd) in today’s animated GIF presentation.

Get the picture?!


Previous relevant Animated GIF Creator Exif Rotation Compensation Tutorial is shown below.

Animated GIF Creator Exif Rotation Compensation Tutorial

Animated GIF Creator Exif Rotation Compensation Tutorial

The recent couple of days of work like yesterday’s Animated GIF Creator GD Transformations Interfacing Tutorial have given us “rotation functionality” tools to counteract the unusual effects Exif …

Exchangeable image file format (officially Exif, according to JEIDA/JEITA/CIPA specifications) is a standard that specifies the formats for images, sound, and ancillary tags used by digital cameras (including smartphones), scanners and other systems handling image and sound files recorded by digital cameras.

… can have converting mobile device camera created images into animated GIFs via our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator PHP web application.

But with some photos it’s there in the photo’s metadata information letting the future user know what orientation the camera of that mobile device was in as you took the photo. In order to help our animated GIF creator, the first slide image is scoured for Exif metadata and if found, a suitable rotation correction can be applied to the slides there and then. In order to scour for Exif metadata we needed to write a exif_rotation_check.php inhouse Exif detector PHP helper.


Previous relevant Animated GIF Creator GD Transformations Interfacing Tutorial is shown below.

Animated GIF Creator GD Transformations Interfacing Tutorial

Animated GIF Creator GD Transformations Interfacing Tutorial

The PHP GD image library is so much more useful than for the “filters” interfaced to with yesterday’s Animated GIF Creator GD Filter Interfacing Tutorial. Under an “umbrella term” transformations, today we add interfacing to GD functionality …

… into our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator PHP web application. We found it more user friendly to tailor the asking of numerical parameters for these GD calls work via …

<?php

$gfcds='';
$gdfs=[];
if (strpos(($imvgn . $imafn . $imqty . $imgds), '|') !== false) {
$gdfs=explode(';', trim(explode('|', $imvgn . $imafn . $imqty . $imgds)[1]));
for ($itf=0; $itf<sizeof($gdfs); $itf++) {
if (trim($gdfs[$itf]) != '') {
if (trim($gdfs[$itf]) == strtolower(trim($gdfs[$itf]))) {
$gfcds.=chr(10) . " imagefilter(" . "$" . "oimo, IMG_FILTER_" . strtoupper(trim($gdfs[$itf])) . "); " . chr(10);
} else if (trim($gdfs[$itf]) == strtoupper(trim($gdfs[$itf]))) {
$gfcds.=chr(10) . " image" . explode(',',explode(" ",strtolower(trim($gdfs[$itf])))[0])[0] . "(" . "$" . "oimo, IMG_" . str_replace(" ","_",strtoupper(trim( str_replace(explode(' ',$gdfs[$itf])[0] . ' ','',$gdfs[$itf]) ))) . "); " . chr(10);
} else if (strpos(strtoupper(trim($gdfs[$itf])), "SCALE") !== false) {
$gfcds.=chr(10) . " $" . "oimo=image" . explode(',',explode(" ",strtolower(trim($gdfs[$itf])))[0])[0] . "(" . "$" . "oimo" . str_replace(" ","_",(trim( str_replace(explode(',',explode(" ",(trim($gdfs[$itf])))[0])[0],'',$gdfs[$itf]) ))) . "); " . chr(10);
} else if (strpos(strtoupper(trim($gdfs[$itf])), "COPY") === false) {
$gfcds.=chr(10) . " image" . explode(',',explode(" ",strtolower(trim($gdfs[$itf])))[0])[0] . "(" . "$" . "oimo" . str_replace(" ","_",(trim( str_replace(explode(',',explode(" ",(trim($gdfs[$itf])))[0])[0],'',$gdfs[$itf]) ))) . "); " . chr(10);
} else {
$gfcds.=chr(10) . " image" . explode(',',explode(" ",strtolower(trim($gdfs[$itf])))[0])[0] . "(" . "$" . "oimo" . "," . "$" . "oimo" . explode("," . "$" . "oimo", $gdfs[$itf])[1] . "); " . chr(10);
}
}
}
}

?>

… to work with modified PHP writes PHP of the ilk …

<?php echo ”

function ourimagecreatefromstring(\$inidis) {
global \$imvgn, \$imafn, \$imqty, \$imgds, \$gfcds;
if ((\$imvgn . \$imafn . \$imqty . \$imgds) != '' && strpos(\$inidis, ';base64,') !== false) {
\$extis=str_replace('jpeg','jpg',explode('/', explode(';base64,', \$inidis)[0])[1]);
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, base64_encode(explode(';base64,', \$inidis)[1]));
\$fzis=filesize(\$sofarout);
if (trim(explode('|', \$imvgn . \$imafn . \$imqty . \$imgds)[0]) != '') {
exec('" . $immogpath . "mogrify ' . explode('|', \$imvgn . \$imafn . \$imqty . \$imgds)[0] . ' /tmp/imtmp.' . \$extis);
}
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false ||
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
\$oimo=null;
if (strtolower(\$extis) == 'png') {
\$oimo=imagecreatefrompng('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strtolower(\$extis) == 'bmp') {
\$oimo=imagecreatefrombmp('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strtolower(\$extis) == 'gif') {
\$oimo=imagecreatefromgif('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
\$oimo=imagecreatefromjpeg('/tmp/imtmp.' . \$extis); " . $gfcds . "
}
if (\$oimo) { return \$oimo; }
} else if ((\$imvgn . \$imafn . \$imqty . \$imgds) != '') {
\$extis=str_replace('jpeg','jpg','" . $inextis . "');
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
if (strpos(strtolower((\$imvgn . \$imafn . \$imqty . \$imgds)), '-format ') === false) { \$imvgn.=' -format " . str_replace('jpg','jpeg',$inextis) . " '; }
if (trim(explode('|', \$imvgn . \$imafn . \$imqty . \$imgds)[0]) != '') {
exec('" . $immogpath . "mogrify ' . explode('|', \$imvgn . \$imafn . \$imqty . \$imgds)[0] . ' /tmp/imtmp.' . \$extis);
}
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
\$oimo=null;
if (strtolower(\$extis) == 'png') {
\$oimo=imagecreatefrompng('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strtolower(\$extis) == 'bmp') {
\$oimo=imagecreatefrombmp('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strtolower(\$extis) == 'gif') {
\$oimo=imagecreatefromgif('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
\$oimo=imagecreatefromjpeg('/tmp/imtmp.' . \$extis); " . $gfcds . "
}
if (\$oimo) { return \$oimo; }
}
return imagecreatefromstring(\$inidis);
}

“; “?>

… and to get there clientwise, in the Javascript …


function gdadd(oselo) {
var pari=1, thispari='0';
if (oselo.value != '') {
//alert(oselo.value);
var oselovalue=oselo.value.replace(',' + '$' + 'oimo','~' + '$' + 'oimo').split(',')[0];
//alert(oselovalue);
var oseloval=oselo.value;
if (document.getElementById('imgds')) { if (document.getElementById('imgds').value == '') { document.getElementById('imgds').value='|'; } else { document.getElementById('imgds').value+=';'; } }
oseloval=oseloval.replace(',' + '$' + 'oimo','~' + '$' + 'oimo');
oseloval=oseloval.replace(oseloval.split(',')[0], '');
while (oseloval.indexOf(',') != -1) {
//alert(oseloval);
if ((oseloval + ' ').substring(1).split(',')[0].trim() != '') {
if ((' ' + (oseloval + ' ').substring(1).split(',')[0].trim() + ' ').toLowerCase().indexOf(' colour ') != -1) {
thispari=prompt('Enter' + (' ' + (oseloval + ' ').substring(1).split(',')[0].trim() + ' ').toLowerCase().replace(' colour ', ' red,green,blue colour ') + 'parameter for GD ' + oselo.value.split(',')[0] + ' ' + pari + ' of ' + eval(-1 + oselo.value.replace(',' + '$' + 'oimo','').split(',').length) + '?', '0');
if (thispari == null) {
thispari='0';
} else if (thispari.trim() == '') {
thispari='0';
} else if (thispari.indexOf(',') == -1) {
oselovalue+=',' + thispari + '';
} else {
oselovalue+=',imagecolorallocate(' + '$' + 'oimo,' + thispari + ')';
}
} else {
thispari=prompt('Enter ' + (oseloval + ' ').substring(1).split(',')[0].trim() + ' parameter for GD ' + oselo.value.split(',')[0] + ' ' + pari + ' of ' + eval(-1 + oselo.value.replace(',' + '$' + 'oimo','').split(',').length) + '?', '0');
if (thispari == null) {
thispari='0';
} else {
oselovalue+=',' + thispari;
}
}
oseloval=oseloval.replace(',' + (oseloval + ' ').substring(1).split(',')[0].trim(),'').trim();
} else {
thispari=prompt('Enter numerical parameter for GD ' + oselo.value.split(',')[0] + ' ' + pari + ' of ' + eval(-1 + oselo.value.replace(',' + '$' + 'oimo','').split(',').length) + '?', '0');
oseloval=oseloval.replace(',','');
if (thispari == null) {
thispari='0';
} else {
oselovalue+=',' + thispari;
}
}
//oseloval=oseloval.replace(oseloval.split(',')[0] + ',', '');
//oseloval=oseloval.replace(',','');
pari++;
}
if (document.getElementById('gdopt')) {
document.getElementById('gdopt').innerHTML+='  ' + oselovalue.replace('~',',');
}
if (document.getElementById('imgds')) {
document.getElementById('imgds').value+=oselovalue.replace('~',',');
//document.getElementById('imgds').style.display='inline-block';
//document.getElementById('imgds').style.width='300px';
if (document.getElementById('smyim').innerHTML == '') { document.getElementById('smyim').innerHTML='ImageMagick switches: '; }
} else if (document.getElementById('myim')) {
document.getElementById('myim').innerHTML='<span is=smyim>ImageMagick switches: </span><input id=imqty name=imqty type=text style=display:inline-block; value=\"\"></input><input id=imgds name=imgds type=hidden style=display:inline-block; value=\"|' + oselovalue.replace('~',',') + '\"></input>';
document.getElementById('imqty').style.width='300px';
}
oselo.value='';
}
}


Previous relevant Animated GIF Creator GD Filter Interfacing Tutorial is shown below.

Animated GIF Creator GD Filter Interfacing Tutorial

Animated GIF Creator GD Filter Interfacing Tutorial

We are into image modification on the way to creating “compiled” animated GIF images, at the moment. Yesterday’s Animated GIF Creator ImageMagick Interfacing Tutorial got us interfacing (or integrating) …

  • ImageMagick batch processing “mogrify” ideas … and, today, it is the turn of …
  • GD image filters …

… into our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator PHP web application.


Previous relevant Animated GIF Creator ImageMagick Interfacing Tutorial is shown below.

Animated GIF Creator ImageMagick Interfacing Tutorial

Animated GIF Creator ImageMagick Interfacing Tutorial

Yes, you guessed it! On top of yesterday’s ImageMagick Vignette Primer Tutorial, today we want to interface the ImageMagick batch processing “mogrify” ideas into our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator PHP web application.

“Interfacing” (or integrating) into code often has you asking the question …


Where do we intervene to place our logic?

We’ve decided to “wrap” our PHP GD calls …

… into inhouse “our” prefixed function versions as per (PHP writing out PHP) …

<?php echo ”

\$imvgn='" . $imvgn . "'; /" . "/ vignette factor
\$imafn='" . $imafn . "'; /" . "/ affine transformation
\$imqty='" . $imqty . "'; /" . "/ image conversion and/or quality RE jpeg


function ourimagecreatefromstring(\$inidis) {
global \$imvgn, \$imafn, \$imqty;
if ((\$imvgn . \$imafn . \$imqty) != '' && strpos(\$inidis, ';base64,') !== false) {
\$extis=str_replace('jpeg','jpg',explode('/', explode(';base64,', \$inidis)[0])[1]);
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, base64_encode(explode(';base64,', \$inidis)[1]));
\$fzis=filesize(\$sofarout);
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false ||
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
} else if ((\$imvgn . \$imafn . \$imqty) != '') {
\$extis=str_replace('jpeg','jpg','" . $inextis . "');
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
if (strpos(strtolower((\$imvgn . \$imafn . \$imqty)), '-format ') === false) { \$imvgn.=' -format " . str_replace('jpg','jpeg',$inextis) . " '; }
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
}
return imagecreatefromstring(\$inidis);
}

function ourimagecreatefromjpeg(\$inidis) {
global \$imvgn, \$imafn, \$imqty;
if ((\$imvgn . \$imafn . \$imqty) != '') {
\$extis='jpg';
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
}
return imagecreatefromjpeg(\$inidis);
}

function ourimagecreatefrompng(\$inidis) {
global \$imvgn, \$imafn, \$imqty;
if ((\$imvgn . \$imafn . \$imqty) != '') {
\$extis='png';
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
}
return imagecreatefrompng(\$inidis);
}

function ourimagecreatefromgif(\$inidis) {
global \$imvgn, \$imafn, \$imqty;
if ((\$imvgn . \$imafn . \$imqty) != '') {
\$extis='gif';
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
}
return imagecreatefromgif(\$inidis);
}

function ourimagecreatefrombmp(\$inidis) {
global \$imvgn, \$imafn, \$imqty;
if ((\$imvgn . \$imafn . \$imqty) != '') {
\$extis='bmp';
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
}
return imagecreatefrombmp(\$inidis);
}

“; ?>

… and change existant calls into (equivalent inhouse) “our” function calls as above.


Previous relevant ImageMagick Vignette Primer Tutorial is shown below.

ImageMagick Vignette Primer Tutorial

ImageMagick Vignette Primer Tutorial

Continuing on with the ImageMagick batch processing “mogrify” ideas of yesterday’s ImageMagick Batch Image Conversion Affine Transformation Tutorial and the “vignette” image editing ideas of Gimp Vignette Primer Tutorial, as below, today, we took some pet photos with an iPad’s Camera app and shared them off the Photos app via two Mail sharing option emails containing seven attachments each. Using an iPad, the JPEG “jpg” output files were too big for our inhouse Animated GIF Creator PHP web application to handle, and so to perform the …

  • animated GIF presentation, off these downloaded email photo attachments … and along the way …
  • quality adjusted them (yes, “mogrify” does not stuff JPG to JPG conversions, and we used “mogrify” -quality 20% switch here) … and …
  • rotate them 180 degrees (“mogrify” uses switches -affine -1,0,0,-1,0,0 -transform +repage here) … and …
  • vignette 50% (“mogrify” uses switch -vignette 50 here)

… on the way to compiling into an animated GIF image, and we turned to ImageMagick again, using its affine transformation talents, along with its awesome vignetting talents …




… where the last two dropdown options will be similar, the last showing the input image into ImageMagick can be an animated GIF that is truely treated like an animated GIF.

By the way, should you be interested in photo orientation off a mobile device camera, have a read of PHP Exif Image Information Revisit Tutorial.

Nala and Luna and Charlie bid you a fond farewell!


Previous relevant Gimp Vignette Primer Tutorial is shown below.

Gimp Vignette Primer Tutorial

Gimp Vignette Primer Tutorial

The last time we talked about the miraculous, redolent and amazing image editor called Gimp am sure there was someone in a shower … it stands to reason … and one of those showerers, surely, would have been singing The Gimp Song … and if not … why not? … but we digress … anyway we had the Gimp Transparency Primer Tutorial as shown below go into some image transparency issues with Gimp.

In today’s tutorial we make use of a great tutorial (even so far as with direct quotes below) called Add a Vignette to a Photograph with GIMP (thanks) to try a photographic technique called vignetting on one of the photographs we added, recently, into the mix of those of the Custom Header Image mix at this blog … specifically the one of Nala, the dog, on the door ledge. Need to warn you here and now that if there was the time all over again, it would be better achieved that second time around, but this is not the point with learning, but rather getting some starting point with a great “product” like Gimp, and trying it yourself, once you have a method. It boils down to:

  1. Open Gimp graphical editor application
  2. File->Open … pick your image file
  3. Layer->New Layer (we’ll call “Vg”) … pick Foreground Colour
  4. In the Layers dialog, click on your “Vg” layer to select it, and select Soft light from the “Mode” drop-down box
  5. Right click on your “Vg” layer and go to Add Layer Mask. In the dialog that pops up, you want “Initialise Layer Mask to” set to “White (full opacity)”. Click “Add”
  6. Below Opacity bar select Link icon next to Eye icon, which will already be showing
  7. Use the freeform select tool (press F to bring this up) and draw a selection somewhere around the primary point of interest in your photo
  8. Use your bucket tool (Shift+B) and click within the selection to fill it
  9. Deselect your selection with Select->None
  10. Go to Filters->Blur->Gaussian Blur. In the dialog that comes up, you want “Radius” set to a very large amount; a tenth of the longest edge of the photo is not too much
  11. Click on your “Vg” layer to select it (if it isn’t already selected), and then slide the opacity slider towards the right until the effect is subtle enough. Our (ever so subtle) example of Nala, in the tutorial, used an opacity of about 66%
  12. Click Export button in two windows (NB. this overwrites the image file, so if this is not desirable, export to a different image file name and/or type)

Here is an image comparison link.

As with most Gimp ideas, jump in and give it a go, as you’ll find your own ways and means of using this great product … am pretty sure.

Link to Gimp “spiritual home” … here.
Link to Gimp forum … here.


Previous relevant Gimp Transparency Primer Tutorial is shown below.

Gimp Transparency Primer Tutorial

Gimp Transparency Primer Tutorial

Here is a tutorial that adds to a previous Gimp Layers Primer Tutorial as shown below, and gives you more insight into the massive possibilities of using a sophisticated image editor and use layers with various amounts of transparency, especially suited to use with png image files.

Today’s tutorial where we construct a Birthday Card that needs tweaking for the words in front to be seen a bit more clearly, by making the image behind a bit more transparent, changes the transparency of a single image via:

  1. Open Gimp graphical editor application
  2. File->Open Layers … pick your image file
  3. If Layers window not showing, make it show via Windows->Layers – Brushes
  4. Below Opacity bar select Link icon next to Eye icon, which will already be showing
  5. Change Opacity bar setting to a value of Transparency (100% is Opaque, 0% is Transparent) that suits … today we do 70%
  6. File->Export
  7. Click Export button in two windows (NB. this overwrites the image file, so if this is not desirable, export to a different image file name and/or type)

As with most Gimp ideas, jump in and give it a go, as you’ll find your own ways and means of using this great product … am pretty sure.

Link to Gimp “spiritual home” … here.
Link to Gimp forum … here.


Previous relevant Gimp Layers Primer Tutorial is shown below.

Gimp Layers Primer Tutorial

Gimp Layers Primer Tutorial

Here is a tutorial that gives you an insight into the massive possibilities of using a sophisticated image editor and use layers with various amounts of transparency, especially suited to use with png image files.

Transparency (or its obverse, opacity) can be used to have the one image achieve several “ends” (ie. purposes). Although it is a bit of a clumsy example in the tutorial, you can see that the technique can be used for artistic purposes … often called “Photoshopping” (named after the more famous, and also brilliant, rival product, Photoshop).

Lots of those classic “Photoshopping” techniques can be achieved in Gimp, and some other tutorials at this blog touch on that.

Am sure you can imagine what the concept of a layer is with regard to image manipulation. Within Gimp, for beginners not used to this concept, you find yourself underestimating and underplaying what can be achieved with the various layers of a multi-layered image. In simplistic terms each layer has the functionality in Gimp to be treated as a whole new image, and this is the best way to think of it when trying to achieve what you want to achieve with Gimp.

Link to Gimp “spiritual home” … here.
Link to Gimp forum … here.

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.


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

Pandoc Install and Public Face Tutorial

Pandoc Install and Public Face Tutorial

Pandoc Install and Public Face Tutorial

As with the recent Ffmpeg Install and Public Face Tutorial there’s an opportunity with our new web server to install Document Conversion command line software known as …


pandoc

… we install on AlmaLinux9 via …


dnf install pandoc

… and which we can interface to via our “public facing” inhouse PHP …

As you can imagine there is an extra security concern here, and working through being a stage two set of changes, before we display the output document file directly, and concern ourselves with similar security issues uploads worry us with, but, for now, see where we are at so far.


Previous relevant Ffmpeg Install and Public Face Tutorial is shown below.

Ffmpeg Install and Public Face Tutorial

Ffmpeg Install and Public Face Tutorial

Our recent web server VPS migration can not only be …

  • a migration of functionality (eg. this WordPress blog) … as well as …
  • an opportunity to open up new vistas of serverside functionality

… such as today’s ffmpeg install, which is only feasible because of the …

  • additional diskspace … chance on new web server allows for …
  • chance to install ffmpeg …

    dnf config-manager --set-enabled powertools
    dnf install --nogpgcheck https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-$(rpm -E %rhel).noarch.rpm -y
    dnf install --nogpgcheck https://mirrors.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-$(rpm -E %rhel).noarch.rpm -y
    dnf install ffmpeg

    … thanks to this great link, along with ImageMagick …

… on this new “public face” (even more public when DNS is applied later).

Codewise this involved …

… further to recent work touching these ideas with Animated GIF Creator Overlayed Images Top Left Tutorial.

See some of this public install of ffmpeg here.


Previous relevant Animated GIF Creator Overlayed Images Top Left Tutorial is shown below.

Animated GIF Creator Overlayed Images Top Left Tutorial

Animated GIF Creator Overlayed Images Top Left Tutorial

To add to the recent Animated GIF Creator Overlayed Images Tutorial‘s user interaction logic, we add a way to control those two “overlay” CSS properties …

  • left
  • top

… but more in the sense that we allow CSS …

  • margin-eft
  • margin-top

… come into the picture, after a dalliance with CSS calc thoughts.

This allows for offsetted images be part of the “overlay mix” that you can retry this at our changed tutorial_to_animated_gif.php inhouse public domain Animated GIF Creator.


Previous relevant Animated GIF Creator Overlayed Images Tutorial is shown below.

Animated GIF Creator Overlayed Images Tutorial

Animated GIF Creator Overlayed Images Tutorial

We wanted to add an “Overlayed Images” functionality component to the “Animated GIF Creator” of Animated GIF Creator Video Intranet Tutorial, today.

The work involves both of the HTML design “big concepts” we are keen on at this blog …

  • overlay … via CSS control of
    1. position:absolute;top:0px;left:0px;
    2. opacity:1.0;
    3. z-index:1;
  • reveal … lately, mostly, via HTML use of …
    1. details
    2. summary

… the latter being the “container” for our interactive input be able to control overlay items 2 and 3, which affect the “overlayed images” output display via the clicking of a new “Overlay Images” button. That button …


<input disabled onclick="overlaythem();" id="overlayit" type="button" title='Overlay Images' value='Overlay Images'></input>

… starts off as disabled … and works with new HTML div elements …


<div id=overlayedj><h1>&nbsp;</h1><br></div><div id=overlayedi></div>

… until at least two images are defined, at which time the button becomes enabled …


function onfit(ithis) {
if (ithis.value == '' && ('' + ithis.placeholder).indexOf(']') != -1) {
ithis.value=('' + ithis.placeholder).split('[')[1].split(']')[0];
}
ithis.type='number';
}

function overlayds(inm, newop, newzi) {
var outdets='';
var divrect=null;
var poslt=' data-style=\"position:absolute;left:px;top:px;\" ';
var reposit='';
if (!document.getElementById('detsum' + ('' + inm))) {
if (document.getElementById('overlayedi').innerHTML == '') {
document.getElementById('overlayedi').title='Overlayed Images Below ... Click for It in New Window ...';
document.getElementById('overlayedj').innerHTML='<h1>Overlayed Images Below ...</h1><br>';
divrect=document.getElementById('overlayedi').getBoundingClientRect();
poslt=' data-style=\"position:absolute;left:' + ('' + divrect.left).split('.')[0].trim() + 'px;top:' + ('' + eval(200 + eval('' + ('' + divrect.top).split('.')[0]))).trim() + 'px;\" ';
} else {
poslt=' data-style=\"' + document.getElementById('detsum1').getAttribute('data-style') + '\" ';
}
outdets='&nbsp;&nbsp;<details ' + poslt + ' id=\"detsum' + ('' + inm) + '\" style=\" display:inline-block; \" open><summary id=\"sumdet' + ('' + inm) + '\">Overlay</summary><input onchange=overlayds(' + inm + ',this.value,String.fromCharCode(32)); onblur=overlayds(' + inm + ',this.value,String.fromCharCode(32)); type=text onfocus=onfit(this); id=\"opacity' + ('' + inm) + '\" style=\" display:inline-block; \" placeholder=\"Opacity [1.00]\" value=\"\" step=0.01 min=0.00 max=1.00></input><br><input onfocus=onfit(this); onchange=overlayds(' + inm + ',String.fromCharCode(32),this.value); onblur=overlayds(' + inm + ',String.fromCharCode(32),this.value); type=text id=\"zindex' + ('' + inm) + '\" style=\" display:inline-block; \" placeholder=\"Z-Index [1]\" value=\"\" min==999 max=999 step=1></input><br></details>';
reposit=poslt.replace(' data-',' ');
reposit=reposit.replace('\"', '\"opacity:1.0;z-index:1;');
if (document.getElementById('overlayedi').innerHTML == '') {
document.getElementById('overlayedi').innerHTML='<img id=\"imgdet' + ('' + inm) + '\" src=\"' + document.getElementById('slideshow' + ('' + inm).replace(/^1$/g,'')).value + '\" ' + reposit + '></img>';
document.getElementById('overlayedi').style.width=('' + document.getElementById('imgdet' + ('' + inm)).width).replace('px','') + 'px';
document.getElementById('overlayedi').style.height=('' + document.getElementById('imgdet' + ('' + inm)).height).replace('px','') + 'px';
document.getElementById('overlayedi').onclick = function(){ var woo=window.open('','_blank','top=100,left=100,width=' + document.getElementById('overlayedi').style.width.replace('px','') + ',height=' + document.getElementById('overlayedi').style.height.replace('px','')); woo.document.write('<html><head><title>Overlayed Images Below ...</title></head><body>' + document.getElementById('overlayedi').outerHTML.replace(/left\:[\ ]*/g,'left:0.0').replace(/top\:[\ ]*/g,'top:0.0') + '</body></html>'); woo.document.title='Overlayed Images Below ...'; };
} else {
document.getElementById('overlayedi').innerHTML+='<img id=\"imgdet' + ('' + inm) + '\" src=\"' + document.getElementById('slideshow' + ('' + inm).replace(/^1$/g,'')).value + '\" ' + reposit + '></img>';
}
} else {
document.getElementById('detsum' + ('' + inm)).style.display='inline-block';
if (newop != ' ') {
if (newop.trim() == '') {
document.getElementById('imgdet' + inm).style.opacity='1.0';
} else {
document.getElementById('imgdet' + inm).style.opacity='' + newop;
}
}
if (newz != ' ') {
if (newz.trim() == '') {
document.getElementById('imgdet' + inm).style.zIndex='1';
} else {
document.getElementById('imgdet' + inm).style.zIndex='' + newzi;
}
}
}
return outdets;
}

function overlaythem() {
var suffidea=1;
while (document.getElementById('slideshow' + ('' + suffidea).replace(/^1$/g, '')).value != '') {
document.getElementById('ours' + ('' + suffidea)).innerHTML+=overlayds(suffidea,'','');
suffidea++;
}
}

You can try this at our changed tutorial_to_animated_gif.php inhouse public domain Animated GIF Creator.


Previous relevant Animated GIF Creator Video Intranet Tutorial is shown below.

Animated GIF Creator Video Intranet Tutorial

Animated GIF Creator Video Intranet Tutorial

With the recent Animated GIF Creator Video Revisit Tutorial (preceding Animated GIF Creator Video Share Tutorial) we wrote …

… one reason being that we do not want to install the wonderful ffmpeg (command line video creation tool) on the RJM Programming domain, but, in macOS, here with MAMP, we are quite happy to live with the Homebrew (Terminal application’s) install …

… setting up what could be “lost functionality”, but today, we come around to either adding a new …


Convert to Video

… dropdown option should all be ritchy ditch, and if not, often we will add new “Advice” dropdown options to remind the user what they’d need to arrange to get to a “Convert to Video” scenario.

Selecting “Convert to Video” sets up a hydrid “Internet/Intranet” feeling scenario where …

  • the user is using our changed tutorial_to_animated_gif.php inhouse public domain Animated GIF Creator containing this new “Convert to Video” option off the “ImageMagick” dropdown …
  • the user defines some image slide data … eg. browsing to create data-URIs (but careful not to do too many) …
  • the user selects that “Convert to Video” option …
  • a window.open popup calls URL like …
    HTTP://localhost:8888/PHP/animegif/tutorial_to_animated_gif.php?video=1687644
    … in a new window …
  • those data-URIs are converted into /tmp/jmtmp0*.[imageExt] files … ready for …
  • ffmpeg commands like …

    ffmpeg -framerate 0.1 -i /tmp/jmtmp%03d.jpeg -c:v libvpx-vp9 -pix_fmt yuva420p -lossless 1 -c:a copy video.webm; ffmpeg -i video.webm video.mov 2>> video.bad

    … be nested in PHP exec (via MAMP local web server incarnation of the inhouse Animated GIF Creator) as a way to create videos …
  • which can be downloaded within that public domain “parent” inhouse Animated GIF Creator session

Which begs the question …


How do we know when to offer the "Convert to Video" option on that dropdown?

This logic is centred around a few useful ideas (with this cross domain scenario ruling out Ajax and Iframe src= definitions, as useful ways to go) …

  1. open the MAMP local web server “HTTP://localhost:8888/PHP/animegif/tutorial_to_animated_gif.php” URLs in an iframe (with onload event logics) pointed at by a window.open second argument (effectively avoiding any loose useful or not popup windows hanging around) …
  2. the most we can ask at the receiver is that window.opener is defined … and if so, just at that discovery …
  3. an image called “amhere.jpg” is created via PHP GD functionality … and back at the “public domain” parent within the iframe onload logic (where with contentWindow or contentDocument do not expect a document.body or even a document) …
  4. we attempt to “hotlink” that MAMP local web server image … as per …

    var tryit='http://localhost:8888/PHP/animegif/amhere.jpg';

    document.getElementById('ctvopt').value='advice';
    document.getElementById('ctvopt').innerHTML='Advice on Convert to Video';

    if (tryit != '') {
    var im=new Image();

    im.onload = function() {
    document.getElementById('ctvopt').value='video';
    console.log('this.height=' + eval('' + this.height));
    if (eval('' + this.height) >= 20) {
    document.getElementById('ctvopt').innerHTML='Convert to Video';
    } else {
    document.getElementById('ctvopt').innerHTML='Convert to Video (but ffmpeg not installed or in unexpected place)';
    }
    document.getElementById('imsel').title='All except Convert to Video, which needs ffmpeg installed, use ImageMagick';
    };


    im.src=tryit;
    tryit='';
    }


Previous relevant Animated GIF Creator Video Revisit Tutorial is shown below.

Animated GIF Creator Video Revisit Tutorial

Animated GIF Creator Video Revisit Tutorial

We hope you realize that our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator (helped out by a changed emailhtml.php inhouse email creator helper serverside PHP web application) can be accessed …

  1. in that public RJM Programming mode of use above … but even better can be …
  2. download relevant code to macOS MAMP local web server places off /Applications/MAMP/htdocs/ $_SERVER[‘DOCUMENT_ROOT’] places …

    … and check the code for the validity of any ImageMagick paths … and if not all these conditions, simulate the same and cobble it together in the code

… one reason being that we do not want to install the wonderful ffmpeg (command line video creation tool) on the RJM Programming domain, but, in macOS, here with MAMP, we are quite happy to live with the Homebrew (Terminal application’s) install …


brew install ffmpeg

… to open a whole new woooooorrrrlllllddd of video creation opportunities using this MAMP local web URL …


HTTP://localhost:8888/PHP/animegif/tutorial_to_animated_gif.php# Animated GIF Creator on MAMP local web server

And so, onto yesterday’s Animated GIF Creator PDF Last Reveal Tutorial we decided to revisit video creation parts of our inhouse Animated GIF Creator on this MacBook Air. We needed to reinstall ffmpeg, and we show that in today’s animated GIF tutorial picture and also created the “video.mov” video below, in the process …

… we tweaked out of “video/mp4” ffmpeg created videos thinking towards “video/webm” or “video.mov” ffmpeg created videos that suit the “few frames but spaced out video” we wanted to achieve for all practical purposes, that “video/mp4” playing too fast for us to see anything much but the first and last slide …

<?php

$videofr=" -r " . (1000 / $delay) . " ";
$videofr=" -r " . (1000 / $delay) . " -filter:v setpts=" . ($delay / 1000) . "*PTS ";
$videomime="video/mp4";
$videoext=".mp4";

$videofr=" -framerate 0.1 ";
$videoext=".webm";
$videomime="video/webm";
$videomidbit="-c:v libvpx-vp9 -pix_fmt yuva420p -lossless 1 -c:a copy";
//$videocmd=$videopath . "ffmpeg -r " . (1000 / $delay) . " -filter:v setpts=" . ($delay / 1000) . "*PTS " . " -i " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "%03d.jpg " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.mp4 2> " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.bad";
//$svideocmd="ffmpeg -r " . (1000 / $delay) . " -filter:v setpts=" . ($delay / 1000) . "*PTS " . " -i " . "%03d.jpg " . "video.mp4";
$videocmd=$videopath . "ffmpeg " . $videofr . " -i " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "%03d.jpg " . $videomidbit . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video" . $videoext . " 2> " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.bad";
$svideocmd="ffmpeg " . $videofr . " -i " . "%03d.jpg " . $videomidbit . " " . "video" . $videoext;
$videocmd.="; " . $videopath . "ffmpeg -i " . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video" . $videoext . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.mov 2>> " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.bad";
$svideocmd.="; " . "ffmpeg -i " . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video" . $videoext . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.mov 2>> " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.bad";
$videohtml="<video title='" . $svideocmd . "' controls id=ivideo type='" . $videomime . "'><source src='video.mov'></source><source src='video" . $videoext . "'></source></video>";
$videosuffix="";

?>


Previous relevant Animated GIF Creator PDF Last Reveal Tutorial is shown below.

Animated GIF Creator PDF Last Reveal Tutorial

Animated GIF Creator PDF Last Reveal Tutorial

As a web application programmer we like buttons. There are “buttons” and there are buttons. Yes, there is an HTML button element, and it and the input type=button element render as that part of a webpage most recognizable to users the world over. You click or tap this button and something usually happens.

But we also enjoy “Emoji Buttons” for we graphically challenged programmers. Using an emoji text and graphic can make span elements or p elements or lots of other HTML elements that have an innerHTML property, be like a very succinct button like entity, also appreciated around here because it takes up so little webpage “real estate”.

And so onto yesterday’s Animated GIF Creator PDF Order Tutorial we set about, today, “revealing” any enduring animated GIF and/or PDF created during a previous session, using Emoji Buttons as the email/SMS sharing action buttons.

We say “revealing” because, like the way “Emoji Buttons” save webpage “real estate”, so can the use of the HTML5 details/summary element combination. It is in that summary “enduring” header part of that combination we can place some “Emoji Buttons”. You will (once you start creating and sharing animated GIFs and/or PDFs) see from our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator (helped out by a changed emailhtml.php inhouse email creator helper serverside PHP web application) that we place three Emoji Buttons …

  1. 📟 SMS (Animated GIF or PDF) Limited relevance period (ie. no data URIs involved, so rely on an absolute URL whose content might change or start not to exist down the track) … via “a” “sms:” link click/tap
  2. 📧 Email (Animated GIF or PDF) Limited relevance period (ie. no data URIs involved, so rely on an absolute URL whose content might change or start not to exist down the track) … via “a” “mailto:” link click/tap
  3. 📧 Email (Animated GIF or PDF) Enduring relevance (ie. data URIs involved, so do not rely on any absolute URL whose content might change or start not to exist down the track) … via PHP mail function means of sending email with HTML attachment containing the relevant Animated GIF or PDF

Yes, “Emoji Buttons” can have their size controlled but not by the usual CSS width and height properties, but by the CSS font-size property. Here is the new Javascript function that those Emoji Button “onclick” logic points to …

<?php eho ”

function askes(isemail, isoab) {
var esask='', izhr=null, izform=null;
var isoa=document.getElementById(isoab.id.replace('b',''));
if (isemail) {
esask=prompt('Please enter email address to send this to', '');
if (esask != null) {
if (esask.indexOf('@') != -1) {
if (isoa.outerHTML.indexOf('<img') == 0) {
//alert('More Animated GIF to come');
izhr = new XMLHttpRequest();
izform=new FormData();
izform.append('to', esask.trim());
izform.append('inline', '" . dirname(__FILE__) . DIRECTORY_SEPARATOR . server_remote_addr() . ".gif" . "');
izform.append('subj', 'My Latest Animated GIF via RJM Programming ... ');
izform.append('tdhuhta', ('<body><div title=\"" . explode('/animegif',$durlis)[0] . '/animegif/' . server_remote_addr() . "\" style=\"overflow:auto;-webkit-overflow-scrolling:touch;height:100%;\"><img style=\"width:100%;height:900px;\" src=\"" . dirname(__FILE__) . DIRECTORY_SEPARATOR . server_remote_addr() . ".gif" . "\"></img></div></body>'));
izhr.open('post', '//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php', true);
izhr.send(izform);
} else if (isoa.outerHTML.indexOf('<a') != 0) {
//alert('More PDF to come');
izhr = new XMLHttpRequest();
izform=new FormData();
izform.append('to', esask.trim());
izform.append('inline', '" . dirname(__FILE__) . DIRECTORY_SEPARATOR . server_remote_addr() . "_animegif.pdf" . "');
izform.append('subj', 'My Latest PDF via Animated GIF via RJM Programming ... ');
izform.append('tdhuhta', ('<body><div title=\"" . explode('/animegif',$durlis)[0] . '/animegif/' . server_remote_addr() . "_\" style=\"overflow:auto;-webkit-overflow-scrolling:touch;height:100%;\"><object style=\"width:100%;height:900px;\" type=\"application/pdf\" data=\"" . dirname(__FILE__) . DIRECTORY_SEPARATOR . server_remote_addr() . "_animegif.pdf" . "\"></object></div></body>'));
izhr.open('post', '//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php', true);
izhr.send(izform);
} else {
isoa.href='mailto:' + esask.trim() + '?' + isoa.href.split('?')[1];
isoa.click();
}
}
}
} else {
esask=prompt('Please enter SMS number to send this to', '');
if (esask != null) {
if ((esask.trim() != '' && esask.trim().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,'') == '')) {
isoa.href='sms:' + esask.trim() + '&' + isoa.href.split('&')[1];
isoa.click();
}
}
}
}

“; ?>

Cute, huh?!


Previous relevant Animated GIF Creator PDF Order Tutorial is shown below.

Animated GIF Creator PDF Order Tutorial

Animated GIF Creator PDF Order Tutorial

Order becomes an interesting subject to us today regarding the PDF conversions possible in amongst the Animated GIF creating of yesterday’s Animated GIF Creator PDF Share Tutorial.

That is because we may have some advanced users out there that want that possibility of differentiating the data of …

  • animated GIF … containing all features asked for, in totality … from the chance for the user to have any of the PDF conversion option sets below …
  • PDF … one of …
    1. no PDF conversion
    2. full PDF conversion … with the user choices regarding raw image content and title and watermarking and ImageMagick and GD modifiers
    3. light PDF conversion … with the user choices regarding just raw image content (the only option out of these last three available before today’s work)
    4. medium PDF conversion … with the user choices regarding just ImageMagick and GD modifiers

… perhaps as a “before and after” tool regarding presentations, maybe?

No dropdowns used here (enforcing an order), just the user’s order in which they choose to select the “PDF conversion” option from the ImageMagick dropdown (in relation to other selections) determining how and when this PDF conversion occurs in the workflow through to creating the animated GIF with our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator serverside PHP web application. Just remember to select PDF Conversion as early as possible to do that “light PDF conversion” option above and last thing if you are interested in “full PDF conversion” (where you can create PDF documents with the bells and whistles ImageMagick and GD modifiers can offer) and today’s tutorial picture is an example of “medium PDF conversion” (when we ordered our settings by first Grayscale, second PDF conversion and last title and watermarking options). Clicking or tapping the ImageMagick link can get the user to the Javascript popup window where they might define the email or SMS recipient for that PDF conversion data file download.


Previous relevant Animated GIF Creator PDF Share Tutorial is shown below.

Animated GIF Creator PDF Share Tutorial

Animated GIF Creator PDF Share Tutorial

To share yesterday’s Animated GIF Creator PDF Conversion Tutorial PDF data formatted image slides (and then onto an animated GIF) would be a step forward, wouldn’t you say?

What sharing conduits do we code for? We always intended …

  • email … but as the day wore on trying to get the usage to work on mobile and non-mobile we decided to relinquish our wish to not have to create a user specific enduring (until that same browser type and user combination share) PDF document for the user request … mainly to get mobile email downloads to be friendly … and so this opened the door for …
  • SMS … to access that enduring PDF as a URL in the SMS message (that becomes a link for the recipient)

… the email methodology used being that “midair feeling” Ajax/FormData approach in our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator serverside PHP web application …

<?php echo ”

function emailhtmlit() {
var induri=ginduri;
var pemail='" . urldecode($_GET['outpdf']) . urldecode($_POST['outpdf']) . "';
if (pemail != null) {
if (pemail.indexOf('@') != -1 || (pemail.trim() != '' && pemail.trim().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,'') == '')) {
if (induri.trim() == '') {
if (induri == '') {
document.getElementById('pdfproposed').src='./animegif.pdf?rand=' + Math.floor(Math.random() * 19854654);
} else {
ginduri='found';
}
setTimeout(emailhtmlit, 15000);
} else {
ginduri='';
var zhr = new XMLHttpRequest();
var zform=new FormData();
if (pemail.indexOf('@') != -1) { zform.append('to', pemail); }
zform.append('inline', '" . dirname(__FILE__) . DIRECTORY_SEPARATOR . "animegif.pdf" . "');
zform.append('subj', 'My PDF version of Animated GIF via RJM Programming ... ');
zform.append('tdhuhta', ('<body><div title=\"" . explode('/animegif',$durlis)[0] . '/animegif/' . server_remote_addr() . "_\" style=\"overflow:auto;-webkit-overflow-scrolling:touch;height:100%;\"><object style=\"width:100%;height:900px;\" type=\"application/pdf\" data=\"" . dirname(__FILE__) . DIRECTORY_SEPARATOR . 'animegif.pdf' . "\"><embed style=\"width:100%;height:900px;\" type=\"application/pdf\" src=\"" . dirname(__FILE__) . DIRECTORY_SEPARATOR . 'animegif.pdf' . "\"></embed></object></div></body>'));
//zform.append('tdhuhta', ('<body><iframe srcdoc=\"" . dirname(__FILE__) . DIRECTORY_SEPARATOR . 'animegif.pdf' . "\"></iframe></body>'));
zhr.open('post', '//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php', true);
zhr.send(zform);
if (pemail.indexOf('@') == -1) {
var hrefp=document.getElementById('pdfsms').href.split('&body=')[0];
hrefp+=pemail.trim() + '&body=' + document.getElementById('pdfsms').href.split('&body=')[1];
document.getElementById('pdfsms').href=hrefp;
document.getElementById('pdfsms').click();
}
}
}
}
}

“; ?>

… and this called on our PHP email creator helper to better interface in its $_POST arguments reading section in our changed emailhtml.php inhouse email creator helper serverside PHP web application …

<?php

$psacv="";
$okayin=true;
$subd="";
$subptitle='';
$subdata="";
$subfile="";
$getpostfound=false;
<br>
foreach( $_POST as $name=>$val ) {
if ($val != "") {
// blah blah blah //file_put_contents("jnv." . $name, "jnv.inv00 " . strlen($phpcont));
if ($name == "tdhuhta" && $subfile != "" && $subdata != "" && strpos(str_replace("+"," ",urldecode($val)), $subfile) !== false) {
if (strpos(str_replace("+"," ",urldecode($val)), ' srcdoc="') !== false || strpos(str_replace("+"," ",urldecode($val)), ' data="') !== false) {
if (strpos(str_replace("+"," ",urldecode($val)), ' title="') !== false) { //file_put_contents('haaa.aaa',explode('/animegif/', explode('"', explode(' title="', str_replace("+"," ",urldecode($val)))[1])[0])[1]);
if (!file_exists('../PHP/animegif/' . explode('/animegif/', explode('"', explode(' title="', str_replace("+"," ",urldecode($val)))[1])[0])[1] . 'animegif.pdf')) {
if (file_exists('../PHP/animegif/animegif.pdf')) {
copy('../PHP/animegif/animegif.pdf', '../PHP/animegif/' . explode('/animegif/', explode('"', explode(' title="', str_replace("+"," ",urldecode($val)))[1])[0])[1] . 'animegif.pdf');
}
}
$psacv=explode('"', explode(' title="', str_replace("+"," ",urldecode($val)))[1])[0] . 'animegif.pdf';
$subptitle='<a target=_blank href="' . explode('"', explode(' title="', str_replace("+"," ",urldecode($val)))[1])[0] . 'animegif.pdf">Mobile whole PDF</a><br>';
}
$vrest=explode('"', explode(' srcdoc="',str_replace("+"," ",urldecode($val)))[1])[0];
$val=urlencode("<body>" . $subptitle . "<iframe style='width:100%;height:95vh;overflow:auto;-webkit-overflow-scrolling:touch;' srcdoc='<div style=width:92%;height:95vh;overflow:auto;-webkit-overflow-scrolling:touch;><object id=myobj style=width:95%;height:95vh; type=application/pdf data=\"" . $subdata . "\"></object></div>'></iframe></body>");
}
// blah blah blah
if ($name == "inline") {
if (strpos(str_replace("+"," ",urldecode($val)), 'animegif.pdf') !== false && isset($_POST['tdhuhta'])) {
if (file_exists(str_replace("+"," ",urldecode($val)))) {
$subfile=str_replace("+"," ",urldecode($val));
$subdata='data:application/pdf;base64,' . base64_encode(file_get_contents(str_replace("+"," ",urldecode($val))));
$val="";
$name="x";
$okayin=false;
}
}
// blah blah blah
}
}

?>

Creating the PDFs got helped out in “reliability terms” via the introduced animegif.php inhouse Wait Around Longer serverside PHP web application.


Previous relevant Animated GIF Creator PDF Conversion Tutorial is shown below.

Animated GIF Creator PDF Conversion Tutorial

Animated GIF Creator PDF Conversion Tutorial

Up to yesterday’s Animated GIF Creator Slide Specific Application Tutorial the recent progress had us …

  • knowing the good places to intervene between the original slide image data being read in and the animated GIF slide output … and …
  • involvement of ImageMagick … so, today, these two help us down the path to …
  • adding PDF as an output format possibility, in addition to the animated GIF and other ideas floated as output formats

… with our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator serverside PHP web application.

We have more “reliability work” and “email sharing work” to go after today’s start, but it primarily called on ImageMagick command line’s talent for a command like …


convert /tmp/imtmp0*.*[gGmMiI]* /tmp/imtmp000.pdf

… to “concatenate” into the one output PDF file (called “/tmp/imtmp000.pdf”) the slides, arranged by our code into that “/tmp/imtmp0*.*[gGmMiI]*” (file specification) arrangement above. Yes, we meant “convert” above, as “mogrify” (batch work) appears not to be able to perform this task.

We hope you stay the course!


Previous relevant Animated GIF Creator Slide Specific Application Tutorial is shown below.

Animated GIF Creator Slide Specific Application Tutorial

Animated GIF Creator Slide Specific Application Tutorial

It’s all fine and good improving on the ImageMagick and GD and Exif functionality modifications like with yesterday’s Animated GIF Creator Exif Rotation Compensation Tutorial, but in reality, if you are going to start creating animated GIFs to explain a process, you are going to want to apply these “slide modifiers” on a slide by slide basis, rather than enforcing a “whole of animated GIF slide set” paradigm, as for the last few days worth of work.

And so, we decided to do what we often do, “sliding in” more functionality (chortle, chortle). We tend to want to …

  • start with hardcoded text (or element) … somewhere … today it happens to be in an HTML span element that once involved just …

    <span id="smyim"></span>

    … and used to get filled, Javascript DOM wise, when needed via …

    document.getElementById('smyim').innerHTML='ImageMagick switches: '; // and yes, it remains that way even now, but read on ...
  • add intelligence (quite often that being onclick logic(s)) to that hardcoded element via …

    <span id=smyim title=Application onclick=applyto(); style=cursor:pointer;text-decoration:underline;></span>
  • that serves the purpose, as the user clicks/taps it (alerted to that fact, perhaps, because we underline the element and add an appropriate cursor when hovering over it (plus a title)), of calling Javascript …

    function applyto() {
    var huhto=prompt('Apply ImageMagick and/or GD to which slides, in comma separated list, counting starting with 1? Defaults to applying to all slides. Comma delimit. Negatives mean all but. Ranges can be specified. For example ... 2,4-7,9', document.getElementById('appliedto').value);
    if (huhto == null) { huhto=''; }
    if (huhto.trim() == '') {
    document.getElementById('appliedto').value='';
    document.getElementById('smyim').title='Application';
    } else {
    document.getElementById('appliedto').value=huhto.trim();
    document.getElementById('smyim').title=huhto.trim();
    }
    }
  • to glean an (often times out of the normal workflow of the web application) informational piece of data, interactively, from the user, via a Javascript prompt popup

So that’s the clientside of this work … “alerting the user to the existance of the functionality” you might say.

And then there’s “the application” of that nuanced user requirement. And that’s where the “inhouse ‘our’ prefix to wrapper function name paradigms” come in handy. We introduced “blanket” functionality thoughts via this approach, and so to “partially undo” that thinking, we make the “our” prefix conditional, as is available to us with our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator serverside PHP web application (helped out by a changed exif_rotation_check.php inhouse Exif detector PHP helper), as per

<?php

function ourcomplicated($inio, $iappl) {
$ideasl=explode(",", str_replace(' ','',$iappl));
$xour="our";
for ($iqa=0; $iqa<sizeof($ideasl); $iqa++) {
if (trim($ideasl[$iqa]) != '') {
$xour="";
if (('-' . $inio) == trim($ideasl[$iqa])) { return ""; }
$ideasr=explode("-", str_replace(' ','',trim($ideasl[$iqa])));
for ($iqb=0; $iqb<sizeof($ideasr); $iqb++) {
if (('' . $inio) == trim($ideasr[$iqb])) {
return "our";
}
if ($iqb == 1) {
if (trim($ideasr[1]) == "") { $ideasr[1]="99999999"; }
if ($inio >= $ideasr[0] && $inio <= $ideasr[1]) { return "our"; }
}
}
}
}
return $xour;
}


?>

teamed with

<?php

$ours="our";
for ($io=1; $io$ours=ourcomplicated($io, $iappliedto);
// blah blah blah
if (strpos($aphoto[0], ";base64,") !== false) {
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefromstring(base64_decode('" . explode(";base64,",$aphoto[0])[1] . "'));", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachonestring));
} else if (strpos(strtolower($aphoto[0]), "//") !== false) {
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefromstring(@file_get_contents('" . $prefix . $aphoto[0] . "'));", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
} else if (strpos(strtolower($aphoto[0]), ".jp") !== false) {
if (strpos($prefix, "../../") !== false && !file_exists($prefix . $aphoto[0]) && file_exists(str_replace("../../","../",$prefix) . $aphoto[0])) {
$prefix=str_replace("../../","../",$prefix);
}
//file_put_contents('qpqp.qpqp', $eachone . "\n\n" . $atext . "\n\n" . str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefromjpeg('" . $prefix . $aphoto[0] . "');", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
//file_put_contents('qpqpqp.qpqpqp', $gifphp);
} else if (strpos(strtolower($aphoto[0]), ".png") !== false) {
if (strpos($prefix, "../../") !== false && !file_exists($prefix . $aphoto[0]) && file_exists(str_replace("../../","../",$prefix) . $aphoto[0])) {
$prefix=str_replace("../../","../",$prefix);
}
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefrompng('" . $prefix . $aphoto[0] . "');", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
} else if (strpos(strtolower($aphoto[0]), ".gif") !== false) {
if (strpos($prefix, "../../") !== false && !file_exists($prefix . $aphoto[0]) && file_exists(str_replace("../../","../",$prefix) . $aphoto[0])) {
$prefix=str_replace("../../","../",$prefix);
}
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefromgif('" . $prefix . $aphoto[0] . "');", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
} else if (strpos(strtolower($aphoto[0]), ".bmp") !== false) {
if (strpos($prefix, "../../") !== false && !file_exists($prefix . $aphoto[0]) && file_exists(str_replace("../../","../",$prefix) . $aphoto[0])) {
$prefix=str_replace("../../","../",$prefix);
}
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefrombmp('" . $prefix . $aphoto[0] . "');", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
}
// blah blah blah
}

?>

We use these “new abilities” better explaining “the abscence or otherwise of Exif checking”, and the implications of that in the animated GIF creator woooooorrrrrrlllllddd, contrasting the first two slides, showing one with “No Exif checking” (the bad old days) versus “With Exif checking” (the renaissance of liberated thinking in the South South East woooorrrrrlllldddd) in today’s animated GIF presentation.

Get the picture?!


Previous relevant Animated GIF Creator Exif Rotation Compensation Tutorial is shown below.

Animated GIF Creator Exif Rotation Compensation Tutorial

Animated GIF Creator Exif Rotation Compensation Tutorial

The recent couple of days of work like yesterday’s Animated GIF Creator GD Transformations Interfacing Tutorial have given us “rotation functionality” tools to counteract the unusual effects Exif …

Exchangeable image file format (officially Exif, according to JEIDA/JEITA/CIPA specifications) is a standard that specifies the formats for images, sound, and ancillary tags used by digital cameras (including smartphones), scanners and other systems handling image and sound files recorded by digital cameras.

… can have converting mobile device camera created images into animated GIFs via our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator PHP web application.

But with some photos it’s there in the photo’s metadata information letting the future user know what orientation the camera of that mobile device was in as you took the photo. In order to help our animated GIF creator, the first slide image is scoured for Exif metadata and if found, a suitable rotation correction can be applied to the slides there and then. In order to scour for Exif metadata we needed to write a exif_rotation_check.php inhouse Exif detector PHP helper.


Previous relevant Animated GIF Creator GD Transformations Interfacing Tutorial is shown below.

Animated GIF Creator GD Transformations Interfacing Tutorial

Animated GIF Creator GD Transformations Interfacing Tutorial

The PHP GD image library is so much more useful than for the “filters” interfaced to with yesterday’s Animated GIF Creator GD Filter Interfacing Tutorial. Under an “umbrella term” transformations, today we add interfacing to GD functionality …

… into our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator PHP web application. We found it more user friendly to tailor the asking of numerical parameters for these GD calls work via …

<?php

$gfcds='';
$gdfs=[];
if (strpos(($imvgn . $imafn . $imqty . $imgds), '|') !== false) {
$gdfs=explode(';', trim(explode('|', $imvgn . $imafn . $imqty . $imgds)[1]));
for ($itf=0; $itf<sizeof($gdfs); $itf++) {
if (trim($gdfs[$itf]) != '') {
if (trim($gdfs[$itf]) == strtolower(trim($gdfs[$itf]))) {
$gfcds.=chr(10) . " imagefilter(" . "$" . "oimo, IMG_FILTER_" . strtoupper(trim($gdfs[$itf])) . "); " . chr(10);
} else if (trim($gdfs[$itf]) == strtoupper(trim($gdfs[$itf]))) {
$gfcds.=chr(10) . " image" . explode(',',explode(" ",strtolower(trim($gdfs[$itf])))[0])[0] . "(" . "$" . "oimo, IMG_" . str_replace(" ","_",strtoupper(trim( str_replace(explode(' ',$gdfs[$itf])[0] . ' ','',$gdfs[$itf]) ))) . "); " . chr(10);
} else if (strpos(strtoupper(trim($gdfs[$itf])), "SCALE") !== false) {
$gfcds.=chr(10) . " $" . "oimo=image" . explode(',',explode(" ",strtolower(trim($gdfs[$itf])))[0])[0] . "(" . "$" . "oimo" . str_replace(" ","_",(trim( str_replace(explode(',',explode(" ",(trim($gdfs[$itf])))[0])[0],'',$gdfs[$itf]) ))) . "); " . chr(10);
} else if (strpos(strtoupper(trim($gdfs[$itf])), "COPY") === false) {
$gfcds.=chr(10) . " image" . explode(',',explode(" ",strtolower(trim($gdfs[$itf])))[0])[0] . "(" . "$" . "oimo" . str_replace(" ","_",(trim( str_replace(explode(',',explode(" ",(trim($gdfs[$itf])))[0])[0],'',$gdfs[$itf]) ))) . "); " . chr(10);
} else {
$gfcds.=chr(10) . " image" . explode(',',explode(" ",strtolower(trim($gdfs[$itf])))[0])[0] . "(" . "$" . "oimo" . "," . "$" . "oimo" . explode("," . "$" . "oimo", $gdfs[$itf])[1] . "); " . chr(10);
}
}
}
}

?>

… to work with modified PHP writes PHP of the ilk …

<?php echo ”

function ourimagecreatefromstring(\$inidis) {
global \$imvgn, \$imafn, \$imqty, \$imgds, \$gfcds;
if ((\$imvgn . \$imafn . \$imqty . \$imgds) != '' && strpos(\$inidis, ';base64,') !== false) {
\$extis=str_replace('jpeg','jpg',explode('/', explode(';base64,', \$inidis)[0])[1]);
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, base64_encode(explode(';base64,', \$inidis)[1]));
\$fzis=filesize(\$sofarout);
if (trim(explode('|', \$imvgn . \$imafn . \$imqty . \$imgds)[0]) != '') {
exec('" . $immogpath . "mogrify ' . explode('|', \$imvgn . \$imafn . \$imqty . \$imgds)[0] . ' /tmp/imtmp.' . \$extis);
}
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false ||
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
\$oimo=null;
if (strtolower(\$extis) == 'png') {
\$oimo=imagecreatefrompng('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strtolower(\$extis) == 'bmp') {
\$oimo=imagecreatefrombmp('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strtolower(\$extis) == 'gif') {
\$oimo=imagecreatefromgif('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
\$oimo=imagecreatefromjpeg('/tmp/imtmp.' . \$extis); " . $gfcds . "
}
if (\$oimo) { return \$oimo; }
} else if ((\$imvgn . \$imafn . \$imqty . \$imgds) != '') {
\$extis=str_replace('jpeg','jpg','" . $inextis . "');
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
if (strpos(strtolower((\$imvgn . \$imafn . \$imqty . \$imgds)), '-format ') === false) { \$imvgn.=' -format " . str_replace('jpg','jpeg',$inextis) . " '; }
if (trim(explode('|', \$imvgn . \$imafn . \$imqty . \$imgds)[0]) != '') {
exec('" . $immogpath . "mogrify ' . explode('|', \$imvgn . \$imafn . \$imqty . \$imgds)[0] . ' /tmp/imtmp.' . \$extis);
}
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
\$oimo=null;
if (strtolower(\$extis) == 'png') {
\$oimo=imagecreatefrompng('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strtolower(\$extis) == 'bmp') {
\$oimo=imagecreatefrombmp('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strtolower(\$extis) == 'gif') {
\$oimo=imagecreatefromgif('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
\$oimo=imagecreatefromjpeg('/tmp/imtmp.' . \$extis); " . $gfcds . "
}
if (\$oimo) { return \$oimo; }
}
return imagecreatefromstring(\$inidis);
}

“; “?>

… and to get there clientwise, in the Javascript …


function gdadd(oselo) {
var pari=1, thispari='0';
if (oselo.value != '') {
//alert(oselo.value);
var oselovalue=oselo.value.replace(',' + '$' + 'oimo','~' + '$' + 'oimo').split(',')[0];
//alert(oselovalue);
var oseloval=oselo.value;
if (document.getElementById('imgds')) { if (document.getElementById('imgds').value == '') { document.getElementById('imgds').value='|'; } else { document.getElementById('imgds').value+=';'; } }
oseloval=oseloval.replace(',' + '$' + 'oimo','~' + '$' + 'oimo');
oseloval=oseloval.replace(oseloval.split(',')[0], '');
while (oseloval.indexOf(',') != -1) {
//alert(oseloval);
if ((oseloval + ' ').substring(1).split(',')[0].trim() != '') {
if ((' ' + (oseloval + ' ').substring(1).split(',')[0].trim() + ' ').toLowerCase().indexOf(' colour ') != -1) {
thispari=prompt('Enter' + (' ' + (oseloval + ' ').substring(1).split(',')[0].trim() + ' ').toLowerCase().replace(' colour ', ' red,green,blue colour ') + 'parameter for GD ' + oselo.value.split(',')[0] + ' ' + pari + ' of ' + eval(-1 + oselo.value.replace(',' + '$' + 'oimo','').split(',').length) + '?', '0');
if (thispari == null) {
thispari='0';
} else if (thispari.trim() == '') {
thispari='0';
} else if (thispari.indexOf(',') == -1) {
oselovalue+=',' + thispari + '';
} else {
oselovalue+=',imagecolorallocate(' + '$' + 'oimo,' + thispari + ')';
}
} else {
thispari=prompt('Enter ' + (oseloval + ' ').substring(1).split(',')[0].trim() + ' parameter for GD ' + oselo.value.split(',')[0] + ' ' + pari + ' of ' + eval(-1 + oselo.value.replace(',' + '$' + 'oimo','').split(',').length) + '?', '0');
if (thispari == null) {
thispari='0';
} else {
oselovalue+=',' + thispari;
}
}
oseloval=oseloval.replace(',' + (oseloval + ' ').substring(1).split(',')[0].trim(),'').trim();
} else {
thispari=prompt('Enter numerical parameter for GD ' + oselo.value.split(',')[0] + ' ' + pari + ' of ' + eval(-1 + oselo.value.replace(',' + '$' + 'oimo','').split(',').length) + '?', '0');
oseloval=oseloval.replace(',','');
if (thispari == null) {
thispari='0';
} else {
oselovalue+=',' + thispari;
}
}
//oseloval=oseloval.replace(oseloval.split(',')[0] + ',', '');
//oseloval=oseloval.replace(',','');
pari++;
}
if (document.getElementById('gdopt')) {
document.getElementById('gdopt').innerHTML+='  ' + oselovalue.replace('~',',');
}
if (document.getElementById('imgds')) {
document.getElementById('imgds').value+=oselovalue.replace('~',',');
//document.getElementById('imgds').style.display='inline-block';
//document.getElementById('imgds').style.width='300px';
if (document.getElementById('smyim').innerHTML == '') { document.getElementById('smyim').innerHTML='ImageMagick switches: '; }
} else if (document.getElementById('myim')) {
document.getElementById('myim').innerHTML='<span is=smyim>ImageMagick switches: </span><input id=imqty name=imqty type=text style=display:inline-block; value=\"\"></input><input id=imgds name=imgds type=hidden style=display:inline-block; value=\"|' + oselovalue.replace('~',',') + '\"></input>';
document.getElementById('imqty').style.width='300px';
}
oselo.value='';
}
}


Previous relevant Animated GIF Creator GD Filter Interfacing Tutorial is shown below.

Animated GIF Creator GD Filter Interfacing Tutorial

Animated GIF Creator GD Filter Interfacing Tutorial

We are into image modification on the way to creating “compiled” animated GIF images, at the moment. Yesterday’s Animated GIF Creator ImageMagick Interfacing Tutorial got us interfacing (or integrating) …

  • ImageMagick batch processing “mogrify” ideas … and, today, it is the turn of …
  • GD image filters …

… into our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator PHP web application.


Previous relevant Animated GIF Creator ImageMagick Interfacing Tutorial is shown below.

Animated GIF Creator ImageMagick Interfacing Tutorial

Animated GIF Creator ImageMagick Interfacing Tutorial

Yes, you guessed it! On top of yesterday’s ImageMagick Vignette Primer Tutorial, today we want to interface the ImageMagick batch processing “mogrify” ideas into our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator PHP web application.

“Interfacing” (or integrating) into code often has you asking the question …


Where do we intervene to place our logic?

We’ve decided to “wrap” our PHP GD calls …

… into inhouse “our” prefixed function versions as per (PHP writing out PHP) …

<?php echo ”

\$imvgn='" . $imvgn . "'; /" . "/ vignette factor
\$imafn='" . $imafn . "'; /" . "/ affine transformation
\$imqty='" . $imqty . "'; /" . "/ image conversion and/or quality RE jpeg


function ourimagecreatefromstring(\$inidis) {
global \$imvgn, \$imafn, \$imqty;
if ((\$imvgn . \$imafn . \$imqty) != '' && strpos(\$inidis, ';base64,') !== false) {
\$extis=str_replace('jpeg','jpg',explode('/', explode(';base64,', \$inidis)[0])[1]);
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, base64_encode(explode(';base64,', \$inidis)[1]));
\$fzis=filesize(\$sofarout);
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false ||
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
} else if ((\$imvgn . \$imafn . \$imqty) != '') {
\$extis=str_replace('jpeg','jpg','" . $inextis . "');
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
if (strpos(strtolower((\$imvgn . \$imafn . \$imqty)), '-format ') === false) { \$imvgn.=' -format " . str_replace('jpg','jpeg',$inextis) . " '; }
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
}
return imagecreatefromstring(\$inidis);
}

function ourimagecreatefromjpeg(\$inidis) {
global \$imvgn, \$imafn, \$imqty;
if ((\$imvgn . \$imafn . \$imqty) != '') {
\$extis='jpg';
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
}
return imagecreatefromjpeg(\$inidis);
}

function ourimagecreatefrompng(\$inidis) {
global \$imvgn, \$imafn, \$imqty;
if ((\$imvgn . \$imafn . \$imqty) != '') {
\$extis='png';
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
}
return imagecreatefrompng(\$inidis);
}

function ourimagecreatefromgif(\$inidis) {
global \$imvgn, \$imafn, \$imqty;
if ((\$imvgn . \$imafn . \$imqty) != '') {
\$extis='gif';
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
}
return imagecreatefromgif(\$inidis);
}

function ourimagecreatefrombmp(\$inidis) {
global \$imvgn, \$imafn, \$imqty;
if ((\$imvgn . \$imafn . \$imqty) != '') {
\$extis='bmp';
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
}
return imagecreatefrombmp(\$inidis);
}

“; ?>

… and change existant calls into (equivalent inhouse) “our” function calls as above.


Previous relevant ImageMagick Vignette Primer Tutorial is shown below.

ImageMagick Vignette Primer Tutorial

ImageMagick Vignette Primer Tutorial

Continuing on with the ImageMagick batch processing “mogrify” ideas of yesterday’s ImageMagick Batch Image Conversion Affine Transformation Tutorial and the “vignette” image editing ideas of Gimp Vignette Primer Tutorial, as below, today, we took some pet photos with an iPad’s Camera app and shared them off the Photos app via two Mail sharing option emails containing seven attachments each. Using an iPad, the JPEG “jpg” output files were too big for our inhouse Animated GIF Creator PHP web application to handle, and so to perform the …

  • animated GIF presentation, off these downloaded email photo attachments … and along the way …
  • quality adjusted them (yes, “mogrify” does not stuff JPG to JPG conversions, and we used “mogrify” -quality 20% switch here) … and …
  • rotate them 180 degrees (“mogrify” uses switches -affine -1,0,0,-1,0,0 -transform +repage here) … and …
  • vignette 50% (“mogrify” uses switch -vignette 50 here)

… on the way to compiling into an animated GIF image, and we turned to ImageMagick again, using its affine transformation talents, along with its awesome vignetting talents …




… where the last two dropdown options will be similar, the last showing the input image into ImageMagick can be an animated GIF that is truely treated like an animated GIF.

By the way, should you be interested in photo orientation off a mobile device camera, have a read of PHP Exif Image Information Revisit Tutorial.

Nala and Luna and Charlie bid you a fond farewell!


Previous relevant Gimp Vignette Primer Tutorial is shown below.

Gimp Vignette Primer Tutorial

Gimp Vignette Primer Tutorial

The last time we talked about the miraculous, redolent and amazing image editor called Gimp am sure there was someone in a shower … it stands to reason … and one of those showerers, surely, would have been singing The Gimp Song … and if not … why not? … but we digress … anyway we had the Gimp Transparency Primer Tutorial as shown below go into some image transparency issues with Gimp.

In today’s tutorial we make use of a great tutorial (even so far as with direct quotes below) called Add a Vignette to a Photograph with GIMP (thanks) to try a photographic technique called vignetting on one of the photographs we added, recently, into the mix of those of the Custom Header Image mix at this blog … specifically the one of Nala, the dog, on the door ledge. Need to warn you here and now that if there was the time all over again, it would be better achieved that second time around, but this is not the point with learning, but rather getting some starting point with a great “product” like Gimp, and trying it yourself, once you have a method. It boils down to:

  1. Open Gimp graphical editor application
  2. File->Open … pick your image file
  3. Layer->New Layer (we’ll call “Vg”) … pick Foreground Colour
  4. In the Layers dialog, click on your “Vg” layer to select it, and select Soft light from the “Mode” drop-down box
  5. Right click on your “Vg” layer and go to Add Layer Mask. In the dialog that pops up, you want “Initialise Layer Mask to” set to “White (full opacity)”. Click “Add”
  6. Below Opacity bar select Link icon next to Eye icon, which will already be showing
  7. Use the freeform select tool (press F to bring this up) and draw a selection somewhere around the primary point of interest in your photo
  8. Use your bucket tool (Shift+B) and click within the selection to fill it
  9. Deselect your selection with Select->None
  10. Go to Filters->Blur->Gaussian Blur. In the dialog that comes up, you want “Radius” set to a very large amount; a tenth of the longest edge of the photo is not too much
  11. Click on your “Vg” layer to select it (if it isn’t already selected), and then slide the opacity slider towards the right until the effect is subtle enough. Our (ever so subtle) example of Nala, in the tutorial, used an opacity of about 66%
  12. Click Export button in two windows (NB. this overwrites the image file, so if this is not desirable, export to a different image file name and/or type)

Here is an image comparison link.

As with most Gimp ideas, jump in and give it a go, as you’ll find your own ways and means of using this great product … am pretty sure.

Link to Gimp “spiritual home” … here.
Link to Gimp forum … here.


Previous relevant Gimp Transparency Primer Tutorial is shown below.

Gimp Transparency Primer Tutorial

Gimp Transparency Primer Tutorial

Here is a tutorial that adds to a previous Gimp Layers Primer Tutorial as shown below, and gives you more insight into the massive possibilities of using a sophisticated image editor and use layers with various amounts of transparency, especially suited to use with png image files.

Today’s tutorial where we construct a Birthday Card that needs tweaking for the words in front to be seen a bit more clearly, by making the image behind a bit more transparent, changes the transparency of a single image via:

  1. Open Gimp graphical editor application
  2. File->Open Layers … pick your image file
  3. If Layers window not showing, make it show via Windows->Layers – Brushes
  4. Below Opacity bar select Link icon next to Eye icon, which will already be showing
  5. Change Opacity bar setting to a value of Transparency (100% is Opaque, 0% is Transparent) that suits … today we do 70%
  6. File->Export
  7. Click Export button in two windows (NB. this overwrites the image file, so if this is not desirable, export to a different image file name and/or type)

As with most Gimp ideas, jump in and give it a go, as you’ll find your own ways and means of using this great product … am pretty sure.

Link to Gimp “spiritual home” … here.
Link to Gimp forum … here.


Previous relevant Gimp Layers Primer Tutorial is shown below.

Gimp Layers Primer Tutorial

Gimp Layers Primer Tutorial

Here is a tutorial that gives you an insight into the massive possibilities of using a sophisticated image editor and use layers with various amounts of transparency, especially suited to use with png image files.

Transparency (or its obverse, opacity) can be used to have the one image achieve several “ends” (ie. purposes). Although it is a bit of a clumsy example in the tutorial, you can see that the technique can be used for artistic purposes … often called “Photoshopping” (named after the more famous, and also brilliant, rival product, Photoshop).

Lots of those classic “Photoshopping” techniques can be achieved in Gimp, and some other tutorials at this blog touch on that.

Am sure you can imagine what the concept of a layer is with regard to image manipulation. Within Gimp, for beginners not used to this concept, you find yourself underestimating and underplaying what can be achieved with the various layers of a multi-layered image. In simplistic terms each layer has the functionality in Gimp to be treated as a whole new image, and this is the best way to think of it when trying to achieve what you want to achieve with Gimp.

Link to Gimp “spiritual home” … here.
Link to Gimp forum … here.

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.


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

English Word Association Game Revisit Tutorial

English Word Association Game Revisit Tutorial

English Word Association Game Revisit Tutorial

One step forward, and steps back is how we’d describe progress, onto the PHP Word Association web application game of Language Word Association Game Tutorial

  • the step forward being the replacing of obsolete Yahoo YQL Thesaurus sources of information with that of the newly introduced Free Thesaurus source, thanks … making the game not show error messages any more and …
  • the steps back relate to our Word Association game being locked into “English modus operandi” only

We add coding to make this happen, just in case Yahoo YQL is ever resurrected, and for “coding posterity purposes”, by introducing a new PHP variable called $theone as featuring in changed PHP code snippets below …

New variables
<?php

$theone=0;
$rdonly="";

?>
Read from thesaurus data source
<?php

$pageContent = "";
if ((
$theone % 2) == 0) {
$pageContent = @file_get_contents("http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20thesaurus%20where%20key%3D%225r3uguAhHMoAQJIlShGL%22%20and%20word%3D%22".urlencode($selname)."%22%20and%20language%3D%22" . $language . "%22&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=");
}
if (
$theone == 1 && $pageContent != '') { $theone=2; } else if ($pageContent == '') { $theone=1; }
if (
$theone == 1) {
$pageContent = @file_get_contents("ht
tp://www.freethesaurus.com/".urlencode($selname)); //."%22%20and%20language%3D%22" . $language . "%22&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=");
$rdonly=" disabled";
if (strpos($pageContent, '<div class="TCont">') === false) {
header('Location: ./word_association.php');
exit;
}
}


?>
Process thesaurus data
<?php

if ($theone == 1) {
$mylist = explode('<div class="TCont">', $pageContent);
if (sizeof($mylist) > 1) {
$pageContent=explode('</div>', $mylist[1])[0];
//file_put_contents('xzz.xzz', $pageContent);
}
$mylist = explode('</h4>', $pageContent);
if (sizeof($mylist) > 1) {
$pageContent=$mylist[0] . '</h4>' . explode('</ul>', $mylist[1])[0] . '</ul>';
$mylist = explode('</h4>', $pageContent);
}
} else {

$mylist = explode('"synonyms":"', $pageContent);
}

if (sizeof($mylist) > 1 || $persist == "n") {
for ($i=1; $i<sizeof($mylist); $i++) {
if ($theone == 1) {
$myline = explode('</ul>', $mylist[$i]);
$mywords = explode("</li>", $myline[0]);
} else {

$myline = explode('"', $mylist[$i]);
$mywords = explode("|", $myline[0]);
}
for ($ii=0; $ii<sizeof($mywords); $ii++) {
if ($theone == 1) {
$selname = "";
//echo "yes" . $ii . " ... " . explode('>', explode('</a>', $mywords[$ii])[0])[(-1 + sizeof(explode('>', explode('</a>', $mywords[$ii])[0])))];
//exit;
$tra=trim(explode('>', explode('</a>', $mywords[$ii])[0])[(-1 + sizeof(explode('>', explode('</a>', $mywords[$ii])[0])))]);
if ($tra != '') {
$rest = str_replace("</select>", "<option value=\"" . $tra . "\">" . $tra . "</option></select>", $rest);
}
} else {

$preword = explode(" (", $mywords[$ii]);
$proposed = str_replace(" (umgangssprachlich)", "", str_replace(" (antonym)", "", str_replace(" (related term)", "", str_replace(" (similar term)", "", $mywords[$ii]))));
$huhs = explode(" (", $proposed);
if (sizeof($huhs) > 1) $proposed = $huhs[0];
if (substr(($proposed . " "), 0, 1) == "(") {
$huhs = explode(") ", $proposed);
if (sizeof($huhs) > 1) $proposed = str_replace($huhs[0] . ") ", "", $proposed);
}
if (strlen(str_replace(" -> " . $proposed . " -> ", "", " -> " . $myp . " -> ")) == strlen(" -> " . $myp . " -> ") && strlen(str_replace(">" . $proposed . "<", "", ">" . $rest . "<")) == strlen(">" . $rest . "<")) {
if (strpos($mywords[$ii], " (antonym)") !== false) {
$selname = "";
$rest = str_replace("</select>", "<option value=\"" . $proposed . "\">" . $proposed . "</option></select>", $rest);
//echo "<tr><td style='background-color:white;'></td><td style='background-color:white;'><a style='text-decoration:none;' target=_blank title='" . str_replace(" (antonym)", "", $mywords[$ii]) . "' href='" . $dprefix . str_replace(" (antonym)", "", $preword[0]) . "'>" . str_replace(" (antonym)", "", $mywords[$ii]) . "</a></td></tr>";
} else {
$selname = "";
$rest = str_replace("</select>", "<option value=\"" . $proposed . "\">" . $proposed . "</option></select>", $rest);
//echo "<tr><td style='background-color:white;'><a style='text-decoration:none;' target=_blank title='" . str_replace(" (antonym)", "", $mywords[$ii]) . "' href='" . $dprefix . str_replace(" (antonym)", "", $preword[0]) . "'>" . str_replace(" (antonym)", "", $mywords[$ii]) . "</a></td><td style='background-color:white;'></td></tr>";
}
}
}
}
}
}

?>

… and so, we’d recommend you (re-)try the changed word_association.php English Word Association Game.


Previous relevant Language Word Association Game Tutorial is shown below.

Language Word Association Game Tutorial

Language Word Association Game Tutorial

Yesterday we created English Word Association Game Primer Tutorial as shown below, to show a draft English only version of a Word Association game good for ESL purposes.

Today we build on that functionality by allowing Word Associations in French or German or Spanish or Italian (the other languages offered with altervista thesaurus web service database with Yahoo YQL), in addition, as long as the user supplies the first “seed” word for these languages. Everything about the English functionality stays as is … keeping backward compatibility, as you’d see by clicking the picture of the tutorial below, where you play the English (only) Word Association Game, as we had it yesterday.

With yesterday’s yesterday’s Yahoo YQL Web Service JSON Thesaurus Tutorial, using Yahoo Web Services called YQL, as shown below, building on previous ones here at this blog, we effectively signed off on the final (supplementing recent PHP/CSS Sentence Auxiliary Verb Game Tutorial showing CSS #[elementID]:before { content: [prefixContent]; } and #[elementID]:after { content: [suffixContent]; } functionality presented on the day before yesterday) impediment to writing an English Word Association game a teacher of ESL could use for the teaching of vocabulary for an advanced student learning English as their second language (or maybe their first?!). The YQL name is the way it is because it simplified the API aspects of its functionality for the developer to concentrate on SQL, and I’m really supportive of this concept. You don’t have to output in JSON, as other data forms like XML are acceptable. Let’s see what Wikipedia says about YQL below.

Yahoo! Query Language (YQL) is an SQL-like query language created by Yahoo! as part of their Developer Network. YQL is designed to retrieve and manipulate data from APIs through a single Web interface, thus allowing mashups that enable developers to create their own applications.[1]

Initially launched in October 2008 with access to Yahoo APIs,[2] February 2009 saw the addition of open data tables from third parties such as Google Reader, the Guardian, and The New York Times.[3] Some of these APIs still require an API key to access them. On April 29th of 2009, Yahoo introduced the capability to execute the tables of data built through YQL using JavaScript run on the company’s servers for free.[3]

So this tutorial builds on the logic of the thesaurus tutorial of yesterday to use a YQL web service into data emanating from its links to the altervista thesaurus web service database with Yahoo YQL website … thanks. For the altervista thesaurus database usage it is best to request a key for your web service queries. You fill in a word (or two, or three) of interest to search for like-minded words.

And what is a thesaurus? Recap on yesterday, perhaps, by reading what Wikipedia says here but, basically, it can be thought of as a repository of a language’s list of words of a similar meaning to the word of your interest. It is a great tool for people learning a language foreign to them, especially regarding their vocabulary.

With word association, as you might imagine, a thesaurus comes in handy for the words associated with the original word and its chosen followers, but if we want a feature to be, in English execution runs, that we can supply that first English word programmatically, we need functionality like for PHP/Javascript Words Within Words Game Tutorial to get that initial English “seed” word chosen from a dictionary. For the French or German or Spanish or Italian parts of the functionality the user supplies this first “seed” word, and then the thesaurus kicks in in a programmatical way from then on, as for the English functionality.

Here is a link to some downloadable PHP programming source code which you may want to rename to word_association.php (and then there is a PHP live run).

How we got there … word_association.php


Previous relevant English Word Association Game Primer Tutorial is shown below.

English Word Association Game Primer Tutorial

English Word Association Game Primer Tutorial

With yesterday’s Yahoo YQL Web Service JSON Thesaurus Tutorial, using Yahoo Web Services called YQL, as shown below, building on previous ones here at this blog, we effectively signed off on the final (supplementing recent PHP/CSS Sentence Auxiliary Verb Game Tutorial showing CSS #[elementID]:before { content: [prefixContent]; } and #[elementID]:after { content: [suffixContent]; } functionality presented on the day before yesterday) impediment to writing an English Word Association game a teacher of ESL could use for the teaching of vocabulary for an advanced student learning English as their second language (or maybe their first?!). The YQL name is the way it is because it simplified the API aspects of its functionality for the developer to concentrate on SQL, and I’m really supportive of this concept. You don’t have to output in JSON, as other data forms like XML are acceptable. Let’s see what Wikipedia says about YQL below.

Yahoo! Query Language (YQL) is an SQL-like query language created by Yahoo! as part of their Developer Network. YQL is designed to retrieve and manipulate data from APIs through a single Web interface, thus allowing mashups that enable developers to create their own applications.[1]

Initially launched in October 2008 with access to Yahoo APIs,[2] February 2009 saw the addition of open data tables from third parties such as Google Reader, the Guardian, and The New York Times.[3] Some of these APIs still require an API key to access them. On April 29th of 2009, Yahoo introduced the capability to execute the tables of data built through YQL using JavaScript run on the company’s servers for free.[3]

So this tutorial builds on the logic of the thesaurus tutorial of yesterday to use a YQL web service into data emanating from its links to the altervista thesaurus web service database with Yahoo YQL website … thanks. For the altervista thesaurus database usage it is best to request a key for your web service queries. You fill in a word (or two, or three) of interest to search for like-minded words.

And what is a thesaurus? Recap on yesterday, perhaps, by reading what Wikipedia says here but, basically, it can be thought of as a repository of a language’s list of words of a similar meaning to the word of your interest. It is a great tool for people learning a language foreign to them, especially regarding their vocabulary.

With word association, as you might imagine, a thesaurus comes in handy for the words associated with the original word and its chosen followers, but we need functionality like for PHP/Javascript Words Within Words Game Tutorial to get that initial “seed” word chosen from a dictionary.

Here is a link to some downloadable PHP programming source code which you may want to rename to word_association.php (and then there is a PHP live run).

Did you know?

Again we use PHP and we hope this is not frustrating those readers who have no PHP installed? It is easy to install PHP web server language (and Apache web server with MySql database) locally for Windows or Mac and would recommend, respectively, EasyPHP Windows Framework for PHP/MySql Tutorial and MAMP Mac Framework for PHP/MySql Tutorial for (install) advice here.


Previous relevant Yahoo YQL Web Service JSON Thesaurus Tutorial is shown below.

Yahoo YQL Web Service JSON Thesaurus Tutorial

Yahoo YQL Web Service JSON Thesaurus Tutorial

Here is a tutorial that might be re-introducing you to the Yahoo Web Services called YQL, building on previous ones here at this blog. The name is the way it is because it simplified the API aspects of its functionality for the developer to concentrate on SQL, and I’m really supportive of this concept. You don’t have to output in JSON, as other data forms like XML are acceptable. Let’s see what Wikipedia says about YQL below.

Yahoo! Query Language (YQL) is an SQL-like query language created by Yahoo! as part of their Developer Network. YQL is designed to retrieve and manipulate data from APIs through a single Web interface, thus allowing mashups that enable developers to create their own applications.[1]

Initially launched in October 2008 with access to Yahoo APIs,[2] February 2009 saw the addition of open data tables from third parties such as Google Reader, the Guardian, and The New York Times.[3] Some of these APIs still require an API key to access them. On April 29th of 2009, Yahoo introduced the capability to execute the tables of data built through YQL using JavaScript run on the company’s servers for free.[3]

So this tutorial uses a YQL web service into the data emanating from its links to the altervista thesaurus web service database with Yahoo YQL website … thanks. For the altervista thesaurus database usage it is best to request a key for your web service queries. You fill in a word (or two, or three) of interest to search for like-minded words.

And what is a thesaurus? Read what Wikipedia says here but, basically, it can be thought of as a repository of a language’s list of words of a similar meaning to the word of your interest. It is a great tool for people learning a language foreign to them, especially regarding their vocabulary.

The two big PHP functions of use (as distinct from an Ajax approach, requiring no PHP … read on) for this are:

  • file_get_contents
  • json_decode … when there is a data structure of any complexity, this function is highly recommended, but for today’s tutorial we do not use it, and take the opportunity to show you a solution using Ajax that requires no PHP … link to some downloadable Ajax inspired HTML programming source code which you may want to rename to Ajax_yql_thesaurus.html which changes from the HTML supervising PHP approach as per Ajax_yql_thesaurus.html (and then there is an Ajax live run)

Good links for information regarding this tutorial (thanks) are:

Another tool you should have in your armoury for jobs like this is the online JSON validator here. A generic JSON approach to issues could be:

  1. Type the URL you were given into a web browser address bar and have a look at it
  2. Type the URL you were given into http://jsonlint.com/ and have it validated
  3. Understand in your own mind what would be different about 1. to make it suitable
  4. Incorporate findings of 3. into massaging of data between file_get_contents and json_decode

Here is a link to some downloadable HTML programming source code which you may want to rename to yql_thesaurus.html which calls some downloadable PHP programming source code which you may want to rename to yql_thesaurus.php (and then there is a PHP live run).

We thank the following free online dictionaries …

Stay tuned for an interesting blog posting tomorrow which combines the new thesaurus functionality of today’s contribution, along with the functionality “smarts” of yesterday’s PHP/CSS Sentence Auxiliary Verb Game Tutorial.

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

Earth Scanner Longitude Prompt Tutorial

Earth Scanner Longitude Prompt Tutorial

Earth Scanner Longitude Prompt Tutorial

Sometimes in I.T. you plan for something, and there’s an unplanned for “side benefit”. We more often see this the other way around, where your plan causes “side harm”, but we’ll take today’s “side benefit” of …

Slowing things down (as discussed below)

… anyday, regarding the plan to add some …

  • “when” style logic new functionality … onto the …
  • “where” style functionality … so predominant, in our inhouse Earth Scanner web application …

… we last talked about, recently, with Earth Scanner Initial Placename Popup Window Tutorial.

Yes, as we’ve outlined many times, we think the software of I.T. is best suited to the “where” of life, followed by the “when” of life matters, in that order. And for us, where (tee hee) “where” meets “when” is easiest to grasp, for us, with Timezone places, which PHP is very good at, luckily enough.

So we decided to add in “right click” (ie. oncontextmenu event) (sorry and using ontouchend (happening on a click), mobile users) logic, as a new independent layer of functionality for those curious users who happen to “right click” on our Earth Scanner map …

  • initially, perhaps, anywhere, when they are told if they “right click” …
  • a particuar Longitude, then Timezone place current times of relevance to that Longitude’s value will be shown in a Javascript prompt window

Then, in making this happen for the changed and tweaked


var nckname=' ';

function newprompt(inpt, indt) {
inpt=inpt.replace(inpt.split(String.fromCharCode(10))[0], inpt.split(String.fromCharCode(10))[0] + ' ( ie. ' + nckname + ' ) ');
return prompt(inpt, inpt);
}

function ocm(sthis,intenlong,smlt,lglt) {
var mten=-10, startat=1;
var wasvl='';
var alertbit=" var ap=newprompt('" + intenlong + "'.replace(/\~/g,String.fromCharCode(10)),'" + intenlong + "'.replace(/\~/g,String.fromCharCode(10))); ";
var ijk=1, kcnt=0, tzp='', datetime_str='', xkcnt='';
var findsare=yourtzlist.split((',' + intenlong).replace(/^0/g,'00').replace(/0$/g,''));
if (nckname == ' ') {
nckname='';
document.body.oncontextmenu=function(evt){ evt.stopPropagation(); if (nckname == '') { alert('Right click on Longitudes will show Timezone Place current times of relevance'); } };
}
if (intenlong == 0) { findsare=yourtzlist.split(',+0"'); } else if (intenlong < 0) { mten=10; }
var findsaretwo=yourtzlist.split((',' + eval(mten + intenlong)).replace(/^0/g,'00').replace(/0$/g,''));
for (ijk=1; ijk<findsare.length; ijk++) {
if ((intenlong == 0 || (findsare[ijk].substring(0,1) >= '0' && findsare[ijk].substring(0,1) <= '4' && findsare[ijk].substring(1).substring(0,1) < '0')) && findsare[ijk].indexOf('>') != -1 && findsare[ijk].indexOf('<') != -1) {
tzp=findsare[ijk].split('>')[1].split('<')[0];
if (tzp.indexOf('/') != -1) {
console.log(tzp);
datetime_str = new Date().toLocaleString("en-AU", { timeZone: tzp });
console.log(datetime_str);
if (eval('' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[0]) >= eval('' + smlt) && eval('' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[0]) <= eval('' + lglt)) {
wasvl=xkcnt;
xkcnt='~' + tzp + ' ' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[0] + ',' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[1] + ' ' + datetime_str + ' ' + wasvl;
} else {
xkcnt+='~' + tzp + ' ' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[0] + ',' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[1] + ' ' + datetime_str + ' ';
kcnt++;
}
if (eval('' + findsaretwo.length) > ijk) {
startat++;
if (findsaretwo[ijk].substring(0,1) >= '6' && findsaretwo[ijk].substring(0,1) <= '9' && findsaretwo[ijk].substring(1).substring(0,1) < '0' && findsaretwo[ijk].indexOf('>') != -1 && findsaretwo[ijk].indexOf('<') != -1) {
tzp=findsaretwo[ijk].split('>')[1].split('<')[0];
if (tzp.indexOf('/') != -1) {
datetime_str = new Date().toLocaleString("en-AU", { timeZone: tzp });
if (eval('' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[0]) >= eval('' + smlt) && eval('' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[0]) <= eval('' + lglt)) {
wasvl=xkcnt;
xkcnt='~' + tzp + ' ' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[0] + ',' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[1] + ' ' + datetime_str + ' ' + wasvl;
} else {
xkcnt+='~' + tzp + ' ' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[0] + ',' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[1] + ' ' + ' ' + datetime_str + ' ';
}
kcnt++;
}
}
}
}
}
}
for (ijk=startat; ijk<findsaretwo.length; ijk++) {
if (findsaretwo[ijk].substring(0,1) >= '6' && findsaretwo[ijk].substring(0,1) <= '9' && findsaretwo[ijk].substring(1).substring(0,1) < '0' && findsaretwo[ijk].indexOf('>') != -1 && findsaretwo[ijk].indexOf('<') != -1) {
tzp=findsaretwo[ijk].split('>')[1].split('<')[0];
if (tzp.indexOf('/') != -1) {
datetime_str = new Date().toLocaleString("en-AU", { timeZone: tzp });
if (eval('' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[0]) >= eval('' + smlt) && eval('' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[0]) <= eval('' + lglt)) {
wasvl=xkcnt;
xkcnt='~' + tzp + ' ' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[0] + ',' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[1] + ' ' + datetime_str + ' ' + wasvl;
} else {
xkcnt+='~' + tzp + ' ' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[0] + ',' + yourtzlist.split(tzp)[1].split('data-geo="')[1].split(',')[1] + ' ' + ' ' + datetime_str + ' ';
}
kcnt++;
}
}
}
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
return ' class=along ontouchend=" nckname=event.target.innerText; event.stopPropagation(); ' + alertbit.replace(/\'\.replace/g, "" + xkcnt + "'.replace") + ' " ';
}
return ' class=along oncontextmenu=" nckname=event.target.innerText; event.stopPropagation(); ' + alertbit.replace(/\'\.replace/g, "" + xkcnt + "'.replace") + ' " ';
}

earth_scanner.html code for the Earth Scanner web application, we realized it was “slowing the progression” of the Earth Scanner’s relentless push to “move on”, and so could help some users who do not necessarily want to “move on” so quickly, and instead want to see what is showing on the Earth Scanner map at the time they “right clicked”. Well, we’d like to say …

And all because you asked for it.

… but we’d be joshing?!


Previous relevant Earth Scanner Initial Placename Popup Window Tutorial is shown below.

Earth Scanner Initial Placename Popup Window Tutorial

Earth Scanner Initial Placename Popup Window Tutorial

With the Earth Bearing Distance Missing Two Hashtagged Mailto Sharing Tutorial it was the same Earth Scanner web application involved as talked about in Earth Scanner Placements Tutorial where it talked about the URL …


https://www.rjmprogramming.com.au/HTMLCSS/earth_scanner.html?nontz=Alice_Springs%7C133.8807%7C_23.6980%7CAU#Alice_Springs
… or equivalent in this case regarding real mantissa … remember rules?

https://www.rjmprogramming.com.au/HTMLCSS/earth_scanner.html?nontz=Alice_Springs%7C133.8807%7C_23.6980%7CAU#Alice_Springs

On revisiting this posting it occurred to us, that an improvement for our Earth Scanner web application would be to acknowledge this …

  • initial place … especially given it might disappear from the maps presented too soon …
  • if possible, and Wikipedia can help, present a popup window featuring background images regarding that place

… to supplement map information with real life photography, thanks Wikipedia. A new Javascript function …


var startwoo=null;

function placetopretz(iois) {
if (iois.src.indexOf('nickname=') != -1) {
var twaconto = (iois.contentWindow || iois.contentDocument);
if (twaconto != null) {
if (twaconto.document) { twaconto = twaconto.document; }
//var xzs=prompt(twaconto.body.outerHTML,twaconto.body.outerHTML);
//alert(89);
if (twaconto.body.outerHTML.indexOf('.style.background') != -1) {
if (!startwoo) {
startwoo=window.open('','_blank','top=50,left=50,width=800,height=800');
//document.getElementById('botif').style.display='block';


//document.getElementById('botif').style.position='absolute';
//document.getElementById('botif').style.top='0px';
//document.getElementById('botif').style.left='0px';
//document.getElementById('botif').style.opacity='0.5';
//document.getElementById('botif').style.zIndex='2222';
console.log(twaconto.body.outerHTML.split('} }')[0].split('>')[0].trim().replace(/parent\./g,'').replace(/\"\;/g,"'").replace(/\&\;/g,"&").slice(-40));
var conlog=('<html>' + (twaconto.body.outerHTML.split('} }')[0].split('>')[0].trim().replace(/parent\./g,'').replace(/\"\;/g,"'").replace(/\&\;/g,"&").replace(/\"/g,"'").replace(" onload='", ' onload="') + ' } }"><div id=ourcanvas style=display:block;width:800px;height:800px;></div><br><div id=stz></div></body></html>').replace(/\'\>/g,'">').replace(/\<\;/g,'<').replace(/\>\;/g,'>').replace(/yourcanvas/g,'ourcanvas').replace(String.fromCharCode(10),' ').replace(String.fromCharCode(10),' ').replace(String.fromCharCode(10),' ').replace(String.fromCharCode(10),' ').replace(String.fromCharCode(10),' '));
var inonl=conlog.split(' onload="')[1].split('"')[0];
if (1 == 1) {
console.log('<html><head><sc' + 'ript type=text/javascr' + 'ipt> function xyz() { ' + inonl.replace(/\ document.getE/g, ' ' + String.fromCharCode(10) + ' document.getE') + ' } </scr' + 'ipt></head>' + conlog.replace(inonl, ' xyz(); '));
startwoo.document.write('<html><head><scri' + 'pt type=text/javascr' + 'ipt> function xyz() { ' + inonl.replace(/\ document.getE/g, ' ' + String.fromCharCode(10) + ' document.getE').replace(/\,URL\(/g, ",' + 'URL(") + ' } setTimeout(xyz,5000); </scr' + 'ipt></head>' + conlog.replace(inonl, ' xyz(); '));
startwoo.document.title=decodeURIComponent(iois.src.split('nickname=')[1].split('&')[0].split('#')[0]).replace(/\_/g,' ');
//document.getElementById('botif').srcdoc=('<html><head><scri' + 'pt type=text/javascr' + 'ipt> function xyz() { ' + inonl.replace(/\ document.getE/g, ' ' + String.fromCharCode(10) + ' document.getE').replace(/\,URL\(/g, ",' + 'URL(") + ' } </scr' + 'ipt></head>' + conlog.replace(inonl, ' xyz(); '));
} else {
console.log('<html>' + (twaconto.body.outerHTML.split('} }')[0].split('>')[0].trim().replace(/parent\./g,'').replace(/\"\;/g,"'").replace(/\&\;/g,"&").replace(/\"/g,"'").replace(" onload='", ' onload="') + ' } }"><div id=ourcanvas style=display:block;width:800px;height:800px;></div><br><div id=stz></div></body></html>').replace(/\'\>/g,'">').replace(/\<\;/g,'<').replace(/\>\;/g,'>').replace(/yourcanvas/g,'ourcanvas').replace(String.fromCharCode(10),' ').replace(String.fromCharCode(10),' ').replace(String.fromCharCode(10),' ').replace(String.fromCharCode(10),' ').replace(String.fromCharCode(10),' '));
startwoo.document.write('<html>' + (twaconto.body.outerHTML.split('} }')[0].split('>')[0].trim().replace(/parent\./g,'').replace(/\"\;/g,"'").replace(/\&\;/g,"&").replace(/\"/g,"'").replace(" onload='", ' onload="') + ' } }"><div id=ourcanvas style=display:block;width:800px;height:800px;></div><br><div id=stz></div></body></html>').replace(/\'\>/g,'">').replace(/\<\;/g,'<').replace(/\>\;/g,'>').replace(/yourcanvas/g,'ourcanvas').replace(String.fromCharCode(10),' ').replace(String.fromCharCode(10),' ').replace(String.fromCharCode(10),' ').replace(String.fromCharCode(10),' ').replace(String.fromCharCode(10),' '));
startwoo.document.title=decodeURIComponent(iois.src.split('nickname=')[1].split('&')[0].split('#')[0]).replace(/\_/g,' ');
//document.getElementById('botif').srcdoc=('<html>' + (twaconto.body.outerHTML.split('} }')[0].split('>')[0].trim().replace(/parent\./g,'').replace(/\"\;/g,"'").replace(/\&\;/g,"&").replace(/\"/g,"'").replace(" onload='", ' onload="') + ' } }"><div id=ourcanvas style=display:block;width:800px;height:800px;></div><br><div id=stz></div></body></html>').replace(/\'\>/g,'">').replace(/\<\;/g,'<').replace(/\>\;/g,'>').replace(/yourcanvas/g,'ourcanvas').replace(String.fromCharCode(10),' ').replace(String.fromCharCode(10),' ').replace(String.fromCharCode(10),' ').replace(String.fromCharCode(10),' ').replace(String.fromCharCode(10),' '));
}
}
}
}
}
}

… helped us with this tweaking of the changed earth_scanner.html code for the Earth Scanner web application.


Previous relevant Earth Bearing Distance Missing Two Hashtagged Mailto Sharing Tutorial is shown below.

Earth Bearing Distance Missing Two Hashtagged Mailto Sharing Tutorial

Earth Bearing Distance Missing Two Hashtagged Mailto Sharing Tutorial

We’re returning to our Missing Two web application, after …

  • the recent Earth Bearing Distance Missing Two Earth Scanner Integration Tutorial Earth Scanner integration … because, today …
  • it becomes our “guinea pig” web application helping out the …
    1. Ajax … and …
    2. FormData … methodologies we use a lot around here in the past …
    3. calling PHP emailhtml.php … to send …
    4. emails containing (HTML perhaps) inline content or attachments … that being the “old way” being helped out by …
    5. intervention in the codes so that an “a” link “mailto:” with hashtagging scenario can augment this (ie. back it up)

    … approaches we use with lots of our web application sharing functionalities

We found, in a “first draft” look at this there were three parts to the solution.

At the PHP code of emailhtml.php PHP mail based email creator code add this near the end
<?php

if ($mailto != '') {
echo "<ht" . "ml>
<he" . "ad>
<scr" . "ipt type='text/javascript'>
function mto() {
document.getElementById('amto').click();
}
</scr" . "ipt>
</he" . "ad>
<bo" . "dy onload=mto();>
<a target=_top style=display:none; href='" . $mailto . "' id=amto>Email</a>
</bo" . "dy></ht" . "ml>";
}


?>
… helped out by, at the correct place
<?php

$mailto='mailto:' . $to . '?subject=' . str_replace('+','%20',urlencode($subject));
$mailto.='&body=https://www.rjmprogramming.com.au/htmlemail.html?rand=' . ('' . time());
$mailto.='#' . base64_encode(urlencode($hcont)); // base64_encode($hcont);


?>
… in the changed emailhtml.php PHP mail email inhouse interfacer
A totally new HTML/Javascript inhouse simple reader of hashtag data to display webpage data …

<html>
<head>
<title>Display Hashtagged HTML Data - RJM Programming - March, 2024</title>
<script type='text/javascript'>
var lh=(('' + location.hash).replace(/^null/g,'').replace(/^undefined/g,'')).replace(/^\#/g,'');
if (lh != '') {
if (lh.indexOf('JTNDY') == 0) {
lh=decodeURIComponent(window.atob(decodeURIComponent(lh))).replace(/\+/g,' ');
} else if (lh.indexOf(window.btoa('<')) == 0 || lh.indexOf('PGJ') == 0) {
lh=window.atob(lh).replace(/\+/g,' ');
} else {
lh=decodeURIComponent(lh).replace(/\+/g,' ');
}
}
var lhdatas=lh.split('data:');
var prefixer='"';
var bodyis='<body></body>', headis='';

for (var ilh=1; ilh<lhdatas.length; ilh++) {
prefixer=lhdatas[eval(-1 + ilh)].slice(-1).replace('(',')').replace('[',']').replace('{','}');
if (lhdatas[ilh].split(prefixer)[0].indexOf(' ') != -1) {
lh=lh.replace(lhdatas[ilh].split(prefixer)[0], lhdatas[ilh].split(prefixer)[0].replace(/\ /g,'+'));
}
}

if (lh.indexOf('</body>') != -1 && lh.indexOf('<body') != -1) {
bodyis='<body' + lh.split('<body')[1].split('</html>')[0];
} else if (lh.trim() != '' && lh.indexOf('<head') == -1) {
bodyis=lh;
}

if (lh.indexOf('</head>') != -1 && lh.indexOf('<head') != -1) {
headis='<head' + lh.split('<head')[1].split('</head>')[0] + '</head>';
document.write(headis.replace(/https\:\/\//g,'//').replace(/http\:\/\//g,'//') + bodyis.replace(/https\:\/\//g,'//').replace(/http\:\/\//g,'//'));
} else if (bodyis != '<body></body>') {
document.write(bodyis.replace(/https\:\/\//g,'//').replace(/http\:\/\//g,'//'));
}

</script>
</head>
<body>
</body>
</html>

… in htmlemail.html Hashtag Email Data Reader and Display “first draft”
Missing Two web application (as an example of what others will try to achieve, as time goes on) this way

var xzhr=null;

xzhr = new XMLHttpRequest();
var xform=new FormData();
xform.append('inline','');
xform.append('to',em.trim());
if (em.trim() != em) {
xform.append('subj','Missing Two');
//var cbgtd=document.getElementById('tdlook').getBoundingClientRect();
xform.append('body','<body>' + document.body.innerHTML.replace(/\ id\=\"mysel\"/g, ' name="mysel" id="mysel"').replace(/\ size\=\"3\"/g, ' size="4"').replace(/\ data\-href\=/g, ' target=_blank href=').replace('</form>', '<br><br><input style=background-color:lightgreen; type=submit value=Solve></input></form>').replace('DISPLAY:table-row','DISPLAY:none').replace(lastfis,lasttis).replace(lasteis,lastenow).replace(lasteis2,lastenow2).replace(lastsis,lastsnow).replace(lastsis2,lastsnow2).replace('absolute;','absolute;display:none;').replace(flatf,tlatf).replace(flongf,tlongf).replace(flatt,tlatt).replace(flongt,tlongt).replace(fbrg,tbrg).replace(fdist,tdist) + '</body>');
} else {
xform.append('subj','Missing Two');
xform.append('body','<body>' + document.body.innerHTML.replace(/\ id\=\"mysel\"/g, ' name="mysel" id="mysel"').replace(/\ size\=\"3\"/g, ' size="4"').replace(/\ data\-href\=/g, ' target=_blank href=').replace('</form>', '<br><br><input style=background-color:lightgreen; type=submit value=Solve></input></form>').replace('DISPLAY:table-row','DISPLAY:none').replace(lastfis,lasttis).replace(lasteis,lastenow).replace(lasteis2,lastenow2).replace(lastsis,lastsnow).replace(lastsis2,lastsnow2).replace('absolute;','absolute;display:none;').replace(flatf,tlatf).replace(flongf,tlongf).replace(flatt,tlatt).replace(flongt,tlongt).replace(fbrg,tbrg).replace(fdist,tdist) + '</body>');
}
xzhr.onreadystatechange=stateChanged;
xzhr.open('post','//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php',true);
xzhr.send(xform);

… Ajax calling of …

function stateChanged() {
if (xzhr.readyState == 4) {
if (xzhr.status == 200) {
//alert(xzhr.response);
if (xzhr.response.indexOf('</a>') != -1) {
document.getElementById('mtodiv').innerHTML='<a' + xzhr.response.split('<a')[eval(-1 + xzhr.response.split('<a').length)].split('</a>')[0] + '</a>';
var alista=document.getElementsByTagName('a');
alista[eval(-1 + alista.length)].click();
}
}
}
}


… in a changed missing_two.html‘s “Missing Two” web application

The hashtagging email story continues!

Stop Press

A tweaked missing_two.html‘s “Missing Two” web application prioritizes timezone place name geolocations over other placename ideas.


Previous relevant Earth Bearing Distance Missing Two Earth Scanner Integration Tutorial is shown below.

Earth Bearing Distance Missing Two Earth Scanner Integration Tutorial

Earth Bearing Distance Missing Two Earth Scanner Integration Tutorial

Today we’re combining precedents from …

… where we integrate the first into the second. Yes, you can code for a web application, to start with, normally, as a “topmost” one, but when it is asked to be “called upon” as a tool for another web application, lots of surprises can happen. Our surprise in this integration above, a bit different to a lot we do, was …

  • the Earth Scanner performs well in a popup window … but …
  • the Earth Scanner does not perform well in an iframe

… we guess, because of those calculations for the variables screenwidth and screenheight which are so crucial to the scrolling required for that Earth Scanner.

At first we thought we’d just whack into a popup window from the Missing Two host, a URL to the Earth Scanner relevant to the two places in the Missing Two web application. But then we had some time to think about it, and remembered how the work of Earth Scanner Map Image Margin Tutorial introduced …

  • a sliver of margin applied to the map image (big img element) … and we wondered “who owns that sliver?” … so, in case it was the document.body element, as we hoped, we’d try …
  • img element onclick event arrangement amendment

    document.getElementById('myimg').onclick=function(event) { event.stopPropagation(); movesallowed=false; gmovesallowed=false; if (gdefv != '') { askfor=ourprompt(event,'Earth Scanner - RJM Programming - February, 2024 ... ' + String.fromCharCode(10) + 'Thanks to https://github.com/nvkelso/natural-earth-raster/blob/master/50m_rasters/HYP_50M_SR_W/HYP_50M_SR_W.README.html ... ' + String.fromCharCode(10) + 'Currently top left of screen is (Longitude,Latitude) ' + '(' + eval(-180 + xp * 360 / 100) + ',' + eval(90 - yp * 180 / 100) + ') and bottom right is (' + eval(-180 + screenlong + xp * 360 / 100) + ',' + eval(90 - screenlat - yp * 180 / 100) + ') and around the middle is (' + eval(-180 + eval(screenlong / 2) + xp * 360 / 100) + ',' + eval(90 - eval(screenlat / 2) - yp * 180 / 100) + ').' + String.fromCharCode(10) + 'Where do you want middle of screen to be in terms of Longitude,Latitude? Suffix with space to show meridians and/or prefix with space to not show meridians.', gdefv); gdefv=''; } else { askfor=ourprompt(event,'Earth Scanner - RJM Programming - February, 2024 ... ' + String.fromCharCode(10) + 'Thanks to https://github.com/nvkelso/natural-earth-raster/blob/master/50m_rasters/HYP_50M_SR_W/HYP_50M_SR_W.README.html ... ' + String.fromCharCode(10) + 'Currently top left of screen is (Longitude,Latitude) ' + '(' + eval(-180 + xp * 360 / 100) + ',' + eval(90 - yp * 180 / 100) + ') and bottom right is (' + eval(-180 + screenlong + xp * 360 / 100) + ',' + eval(90 - screenlat - yp * 180 / 100) + ') and around the middle is (' + eval(-180 + eval(screenlong / 2) + xp * 360 / 100) + ',' + eval(90 - eval(screenlat / 2) - yp * 180 / 100) + ').' + String.fromCharCode(10) + 'Where do you want middle of screen to be in terms of Longitude,Latitude? Suffix with space to show meridians and/or prefix with space to not show meridians.', ''); } if (('' + askfor).replace('(','').replace(')','').replace('[','').replace(']','').indexOf(',') != -1) {
    ameridian='';
    acircleoflatitude='';
    enforcedlong=false;
    enforcedxp=-999; } movesallowed=true; gmovesallowed=true; };

    … augmented by …
  • positive action around the “equivalent of document.body onload event” for the Earth Scanner …

    var thecss='';
    var earth_scanner_css=location.search.split('css=')[1] ? (decodeURIComponent(location.search.split('css=')[1].split('&')[0]).replace(/\+/g,' ')) : '';
    thecss=earth_scanner_css;
    var atendest='<input type=hidden id=posturl style=display:none; value=""></input><input type=button id=dbutton onclick=checkforstt(); style=display:none;></input>';
    var atend='<br><br><div id=dc><canvas title="" id=ourcanvas width=' + ('' + eval(-15 + (window.orientation == 0 ? window.screen.height: window.screen.width)) + 'px').replace('pxpx','').replace('px','') + ' height=660 style="width:' + ('' + eval(-15 + (window.orientation == 0 ? window.screen.height: window.screen.width)) + 'px').replace('pxpx','px') + ';height:660px;border:1px solid red;background-color:' + bcol + ';' + extrastyle + '"></canvas></div><div id=xdscriptstuff></div><div id=xdstylestuff></div><textarea id=myta style=display:none; value=""></textarea><iframe onload=scranal(this); id=scrmytaif style=display:none; src=></iframe><iframe onload=styanal(this); id=stymytaif style=display:none; src=></iframe><iframe class="spag" scrolling="no" data-onload="iifopen(this);" id="cbi" frameborder="0" style="position:fixed;top:0px;left:150px;width:173px;height:218px;margin-top:-204px;display:none;" src="/HTMLCSS/client_browsing.htm?straighttext=312160562686"></iframe><textarea id=result1 style=display:none;></textarea><textarea id=result2 style=display:none;></textarea>' + exdstylestuff + exdscriptstuff + atendest;
    var parentiframe='';
    var iol='';
    if (window.opener) {
    var pu=window.opener.document.URL;
    if (pu.indexOf('#') == -1 && ('' + window.opener.location.hash).replace(/^null/g,'').replace(/^undefined/g,'') != '') {
    pu+=('#' + ('' + window.opener.location.hash)).replace(/^\#\#/g, '#');
    }
    thecss+='display:block;';
    parentiframe='<br><iframe id=mtif style="width:100%;height:800px;z-index:987;margin:0 0 0 0;margin-left:10px;margin-top:10px;background-color:rgba(0,0,255,0.5);" src="' + pu + '"></iframe><div id=dhiddens style=display:none;><div id=goagain></div><input type=hidden id=ltf value=></input><input type=hidden id=lgf value=></input><input type=hidden id=ltt value=></input><input type=hidden id=lgt value=></input><div id=slong></div><iframe id=niframe src=></iframe></div>';

    iol=' onload="document.body.onclick=function(){ document.getElementById(' + "'myimg'" + ').style.display=document.getElementById(' + "'myimg'" + ').style.display.replace(' + "'block','NONE'" + ').replace(' + "'none','block'" + ').replace(' + "'NONE','none'" + '); if (1 == 2) { document.getElementById(' + "'dstyle'" + ').style.display=document.getElementById(' + "'dstyle'" + ').style.display.replace(' + "'visible','HIDDEN'" + ').replace(' + "'hidden','visible'" + ').replace(' + "'HIDDEN','hidden'" + '); } if (document.getElementById(' + "'myimg'" + ').style.display == ' + "'none'" + ') { window.scrollTo(0,0); document.body.style.backgroundColor=' + "'rgba(255,0,0,0.5)'" + '; } else { window.scrollTo(cspx, cspy); document.body.style.backgroundColor=' + "'rgba(0,0,255,0.5)'" + '; } } " ';
    setInterval(getcsp, 5000);
    }

    document.write("<img" + iol + " src='/HTMLCSS/HYP_50M_SR_W.jpg' id=myimg width=" + eval(zoomf * 10800) + " height=" + eval(zoomf * 5400) + " style='margin:0 0 0 0;margin-left:10px;margin-top:10px;" + thecss + "'></img><div id=dstyle style=visibility:visible;></div><input id=sdtitle type=hidden value='Earth Scanner'></input><input id=sdtext type=hidden value='Earth Scanner - RJM Programming'></input><input id=sdurl type=hidden value='" + document.URL.split('#')[0] + ('' + location.hash).replace(/^null/g,'').replace(/^undefined/g,'') + "'></input><iframe scrolling=no farmeborder=0 style='z-index:3456;position:fixed;top:55px;left:15px;width:30px;height:24px;' onload='storeshare(this);' src='/HTMLCSS/web_share_api_test.html?emojize=128231'></iframe><input type=hidden id=itworked value=''></input><iframe onload=coordit(this); id=wif style=display:none;margin-left:50px; src='//wikipedia.org/wiki/Saint_George,_Antigua_and_Barbuda'></iframe><iframe onload=coordittwo(this); id=wiftwo style=display:none; src=></iframe><input type=hidden id=placegeo title='' value=''></input>" + atend + parentiframe);

    … calling …

    var cspx=0, cspy=0;

    function getcsp() {
    // Thanks to https://stackoverflow.com/questions/31712287/get-scroll-position-in-javascript
    var ourcspx = eval('' + (document.body.scrollX || document.body.scrollLeft || document.getElementsByTagName("html")[0].scrollLeft));
    var ourcspy = eval('' + (document.body.scrollY || document.body.scrollTop || document.getElementsByTagName("html")[0].scrollTop));
    if (ourcspx > 100) {
    cspx=ourcspx;
    cspy=ourcspy;
    }
    //document.title='cspx=' + cspx + ' and cspy=' + cspy + ' ourcspx=' + ourcspx + ' and ourcspy=' + ourcspy;
    }

… surprising us regarding how much could be done at the “child” to make this popup window arrangement be fitting into the integration so that …

  • user calls the “parent” Missing Two web application …
  • user fills in the two places … now a clickable details/summary “reveal” “Earth Scanner …” arrangement, if clicked …
  • opens new Earth Scanner popup window with the calling URL hosted in a popup window iframe element below it … so that …
  • clicking in the left hand “document.body” element’s “sliver” which might involve “user scrolling to”, to find (and yes, that is where the ownership lies, luckily) toggles the Earth Scanner topmost with Missing Two “clone” topmost …
  • with the scrolling remembered (our testing shows … “for the main part”) … or the user can choose to …
  • close the popup window in order to fall back to calling “parent” Missing Two web application window, only (still with the “Earth Scanner …” details/summary “reveal” arrangement showing)

Codewise …


Previous relevant Earth Bearing Distance Missing Two Trip Geolocation Elevation Tutorial is shown below.

Earth Bearing Distance Missing Two Trip Geolocation Elevation Tutorial

Earth Bearing Distance Missing Two Trip Geolocation Elevation Tutorial

Onto yesterday’s Earth Bearing Distance Missing Two Trip Geolocation Tutorial and its Geolocation progress we started the day with a different course of action to how we ended it. The day’s motivation was to automate a Place Name elevation knowledge in order to help with that …

What’s out there in the distance?

… thinking we talked about, first, at Earth Bearing Distance Missing Two Place Name and Horizon Tutorial.

We suspected that we were naive in our thinking because Google searches lead to nothing with our theory, that theory being that we could combine …

… could derive for us a semi reliable elevation value. There’s theory, though, and then there’s empirical application, and we could not get the application of the former match the aims with the latter, but will leave you with our Javascript attempt via …


function elevviaz(inlat) { // thanks to https://www.physicsclassroom.com/class/circles/Lesson-3/The-Value-of-g
var dsq=0.0, ddsql=0.0;
if (eval('' + zalpha) != 0) {
var cone=0.0000000000667430;
var mone=5980000000000000000000000.0;
var rone=get_radius_at_lat(inlat); //6380000.0000;
//for (var ii=1; ii<=24; ii++) {
// mone*=10.0;
//}
dsq=eval('' + mone);
alert('dsq(1 is big const)=' + dsq);
dsq*=eval('' + cone);
alert('dsq(2 times small const vs 398600441800000.0)=' + dsq);
dsq=398600441800000.0;
dsq/=9.8; //eval('' + zalpha);
alert('dsq(3 divide by iphone ' + zalpha + ')=' + dsq);
dsq=Math.pow(dsq, 0.5);
alert('dsq(4 square root)=' + dsq);
rone=dsq; //dsq-=rone;
alert('dsq(5 minus sea level earth radius ' + rone + ')=' + dsq);

dsq=eval('' + mone);
alert('dsq(1 is big const)=' + dsq);
dsq*=eval('' + cone);
alert('dsq(2 times small const vs 398600441800000.0)=' + dsq);
dsq=398600441800000.0;
dsq/=eval('' + zalpha);
alert('dsq(3 divide by iphone ' + zalpha + ')=' + dsq);
dsq=Math.pow(dsq, 0.5);
alert('dsq(4 square root)=' + dsq);
dsq-=rone;
alert('dsq(5 minus sea level earth radius ' + rone + ')=' + dsq);

}
return dsq;
}

After abandoning this approach, sadly, later in the day some sporadically happier news was that we discovered that the Geolocation API can sometimes pass across a decent elevation value, which we applied as below into our code’s thinking in our changed missing_two.html‘s “Missing Two” web application.


var appendz="";
var iinb=0;


function showPosition(position) {
if (userlatitude == 0.0 && userlongitude == 0.0) {
userlatitude=eval('' + position.coords.latitude);
userlongitude=eval('' + position.coords.longitude);
//alert('' + position.coords.heading);
if (('' + position.coords.altitude).replace('null','') != '' && iinb == -1) {
appendz=";" + ('' + position.coords.altitude).replace('null','');
}

if (userlatitude != 0.0 || userlongitude != 0.0) {
//document.getElementById('you').innerHTML='(0,0)';
if (document.getElementById('spfr').innerHTML.indexOf('rom') != -1) {
if (document.getElementById('latf') && document.getElementById('longf')) {
document.getElementById('latf').focus();
document.getElementById('latf').value=userlatitude;
document.getElementById('longf').focus();
document.getElementById('longf').value=userlongitude;
document.getElementById('latf').focus();
userlatitude=0.0;
userlongitude=0.0;
document.getElementById('ssf').innerHTML='Here';
if (appendz != '') {
fplacen='Here (elevation ' + appendz.substring(1) + ' m)';
document.getElementById('ssf').innerHTML=fplacen;
} else {

fplacen='Here';
}
gllentry='' + document.getElementById('latf').value + ',' + document.getElementById('longf').value + ',' + fplacen;
askit();
//document.getElementById('spfr').innerHTML='to';
}
} else {
if (document.getElementById('latt') && document.getElementById('longt')) {
document.getElementById('latt').focus();
document.getElementById('latt').value=userlatitude;
document.getElementById('longt').focus();
document.getElementById('longt').value=userlongitude;
document.getElementById('latt').focus();
userlatitude=0.0;
userlongitude=0.0;
document.getElementById('sst').innerHTML='Here';
if (appendz != '') {
tplacen='Here (elevation ' + appendz.substring(1) + ' m)';
document.getElementById('sst').innerHTML=tplacen;
} else {

tplacen='Here';
}
gllentry='' + document.getElementById('latt').value + ',' + document.getElementById('longt').value + ',' + tplacen;
askit();
}
}
}
}
}

function getLocation(inb) {
iinb=inb.indexOf(';');
if (navigator.geolocation) {
try {
navigator.geolocation.getCurrentPosition(showPosition);
//setTimeout(later, 1000);
if (appendz != "" && iinb != -1) { appendz=""; }
if (inb != inb.trim() && document.getElementById('spfr').innerHTML.indexOf('rom') != -1) { fplacen+=' '; }
if (inb != inb.trim() && document.getElementById('spfr').innerHTML.indexOf('rom') == -1) { tplacen+=' '; }
if (document.getElementById('spfr').innerHTML.indexOf('rom') != -1) {
document.getElementById('ipn').value=fplacen;
} else {
document.getElementById('ipn').value=tplacen;
}
gid = navigator.geolocation.watchPosition(gsuccess, gerror, goptions);
return false;
} catch(err) {
//setTimeout(later, 1000);
}
} else if (userlatitude != 0.0 || userlongitude != 0.0) {
//document.getElementById('you').innerHTML='(0,0)';
if (document.getElementById('spfr').innerHTML.indexOf('rom') != -1) {
if (document.getElementById('latf') && document.getElementById('longf')) {
document.getElementById('latf').focus();
document.getElementById('latf').value=userlatitude;
document.getElementById('longf').focus();
document.getElementById('longf').value=userlongitude;
document.getElementById('latf').focus();
userlatitude=0.0;
userlongitude=0.0;
document.getElementById('ssf').innerHTML='Here';
if (appendz != '') {
fplacen='Here (elevation ' + appendz.substring(1) + ' m)';
document.getElementById('ssf').innerHTML=fplacen;
} else {

fplacen='Here';
}
gllentry='' + document.getElementById('latf').value + ',' + document.getElementById('longf').value + ',' + fplacen;
askit();
//document.getElementById('spfr').innerHTML='to';
return false;
}
} else {
if (document.getElementById('latt') && document.getElementById('longt')) {
document.getElementById('latt').focus();
document.getElementById('latt').value=userlatitude;
document.getElementById('longt').focus();
document.getElementById('longt').value=userlongitude;
document.getElementById('latt').focus();
userlatitude=0.0;
userlongitude=0.0;
document.getElementById('sst').innerHTML='Here';
if (appendz != '') {
tplacen='Here (elevation ' + appendz.substring(1) + ' m)';
document.getElementById('sst').innerHTML=tplacen;
} else {

tplacen='Here';
}
gllentry='' + document.getElementById('latt').value + ',' + document.getElementById('longt').value + ',' + tplacen;
askit();
return false;
}
}
}
return true;
}


Previous relevant Earth Bearing Distance Missing Two Trip Geolocation Tutorial is shown below.

Earth Bearing Distance Missing Two Trip Geolocation Tutorial

Earth Bearing Distance Missing Two Trip Geolocation Tutorial

Okay, it’s the day where gobsmacked readers of Earth Bearing Distance Missing Two Trip Compass Tutorial and (all) users of its “Missing Two” web application can be relieved of their “gobsmackederhood“?! Yes …

  • on top of our Wikipedia way to glean Latitude and Longitude for a Place Name … today (oh, but the shame of it all, the shame, leaving it for so long … oh, the shame of“okay, that’s it … pull yourself together”) we finally get around to …
  • “Here” Place Name based HTML5 Geolocation API (should the user be allowing Location Services (into their frightfully busy lives) for their web browser of use) … yayyyyyyyy!

… is flagged to the user via that top textbox’s “placeholder” blurb being adjusted (for 7 seconds) as a user focuses there via changed HTML


<h1 id=myh1 style='display:block;'>Missing Two (<font size=1>optional</font> <span onclick="this.innerHTML=this.innerHTML.replace('to','From').replace('from','to').replace('From','from'); document.getElementById('ipn').focus(); " id=spfr title='Click me to toggle between from and to' style='cursor:pointer;'>from</span> <input onfocus='hereit(this,"");' title='Optionally semicolon separate an elevation affecting horizon distance used for Place Name/Bearing (where Compass app might show you this elevation value) input scenarios. Note that a Place Name/Distance scenario shows a Locality Distance Ring map. Append space for gyroscope bearing.' onblur='lkwk(this,"");' style='display:inline-block;width:280px;' placeholder='Place Name' id=ipn value='' type=text></input>) in Table Column <span data-onfocus="document.getElementById('semail').innerHTML='';" data-title='Email to (append a space to just show the table cell with the gradient)?' data-contenteditable=true data-onblur=preemail(this.innerHTML); onclick=emailit(''); id=semail title=Email>&#128231;</span> <span data-onfocus="document.getElementById('semail').innerHTML='';" data-title='SMS to?' data-contenteditable=true data-onblur=preemail(this.innerHTML); onclick=toize(''); id=ssms title=SMS>&#128223;</span><div id=dntable style=display:none;>    <table border=1 id=ntable style="background-color:pink;display:inline-block;font-size:10px;"><tr><td>N</td></tr><tr><td>&#11014;</td></tr></table>    <div style='display:inline-block;cursor:pointer;' id=arrowup title='To Portrait Up ... line up, parallel, with compass N to face North the ideal way' onclick='alert(this.title);'>&#11014;</div></div></h1>

… calling on new Javascript …


var oiqplaceholder='';

function oiqit() {
if (oiqplaceholder != '') {
hereit(document.getElementById('ipn'), oiqplaceholder);
oiqplaceholder='';
} else if (document.getElementById('ipn')) {
if (('' + document.getElementById('ipn').placeholder).indexOf('"Here" ') == 0 && ('' + document.getElementById('ipn').placeholder).indexOf(' Longitude. ') != -1) {
document.getElementById('ipn').placeholder=document.getElementById('ipn').placeholder.split(' Longitude. ')[1];
}
}
}

function hereit(oiq, twopis) {
var wasp='';
if (twopis != '') {
if (('' + oiq.placeholder).indexOf('"Here"') == -1) {
wasp=('' + oiq.placeholder);
oiq.placeholder='"Here" uses Geolocation derived Latitude, Longitude. ' + wasp;
setTimeout(oiqit, 7000);
}
document.getElementById('myh1').style.cursor='pointer';
} else if (oiq.value == '' && document.URL.toLowerCase().indexOf('https') == 0) {
if (('' + oiq.placeholder).indexOf('"Here"') == -1) {
wasp=('' + oiq.placeholder);
oiqplaceholder='"Here" uses Geolocation derived Latitude, Longitude. ' + wasp;
document.getElementById('myh1').style.cursor='progess';
setTimeout(oiqit, 500);
}
}
}

… and if the user types in the Here  we are looking for


function lkwk(oiis, twop) {
var doi=true;
if (oiis.value.trim() != '') {
if ((('' + oiis.value).replace(/\"/g,'').replace(/\'/g,'').replace(';',' ') + ' ').toLowerCase().indexOf('here ') == 0) { doi=false; if (1 == 2) { oiis.value=''; } doi=getLocation(); if (1 == 2) { return ''; } }
if (document.getElementById('tdmid')) {
if (document.getElementById('tdmid').innerHTML.toLowerCase().indexOf('<iframe') != -1) {
if (document.getElementById('spfr')) {
if (document.getElementById('spfr').innerHTML.toLowerCase().indexOf('rom') != -1) {
location.href=document.URL.split('#')[0].split('?')[0] + '?ipn=' + encodeURIComponent(oiis.value);
}
}
}
}
if (oiis.value.trim() != oiis.value) { tplacen=tplacen.trim(); } else { tplacen+=String.fromCharCode(32); }
var ois=oiis.value.trim().split(';');
if (doi) { document.getElementById('ifplacegeo').src=document.getElementById('ifplacegeo').src.split('?')[0].split('#')[0] + '?placegeo=' + encodeURIComponent(ois[0]); }
if (eval('' + ois.length) > 1) { elev=eval('' + ois[1]); evel=Math.max(elev, 2.0); }
if (twop == '') { oiis.value=''; }
if (doi) { document.body.style.cursor='progress'; }
}
}

… new Geolocation API Javascript code swings into action …


var userlatitude=0.0, userlongitude=0.0;

function getLocation() {
if (navigator.geolocation) {
try {
navigator.geolocation.getCurrentPosition(showPosition);
//setTimeout(later, 1000);
return false;
} catch(err) {
//setTimeout(later, 1000);
}
} else if (userlatitude != 0.0 || userlongitude != 0.0) {
//document.getElementById('you').innerHTML='(0,0)';
if (document.getElementById('spfr').innerHTML.indexOf('rom') != -1) {
if (document.getElementById('latf') && document.getElementById('longf')) {
document.getElementById('latf').focus();
document.getElementById('latf').value=userlatitude;
document.getElementById('longf').focus();
document.getElementById('longf').value=userlongitude;
document.getElementById('latf').focus();
userlatitude=0.0;
userlongitude=0.0;
document.getElementById('ssf').innerHTML='Here';
gllentry='' + document.getElementById('latf').value + ',' + document.getElementById('longf').value + ',Here';
askit();
//document.getElementById('spfr').innerHTML='to';
fplacen='Here';
return false;
}
} else {
if (document.getElementById('latt') && document.getElementById('longt')) {
document.getElementById('latt').focus();
document.getElementById('latt').value=userlatitude;
document.getElementById('longt').focus();
document.getElementById('longt').value=userlongitude;
document.getElementById('latt').focus();
userlatitude=0.0;
userlongitude=0.0;
document.getElementById('sst').innerHTML='Here';
gllentry='' + document.getElementById('latt').value + ',' + document.getElementById('longt').value + ',Here';
askit();
tplacen='Here';
return false;
}
}
}
return true;
}


function showPosition(position) {
if (userlatitude == 0.0 && userlongitude == 0.0) {
userlatitude=eval('' + position.coords.latitude);
userlongitude=eval('' + position.coords.longitude);
if (userlatitude != 0.0 || userlongitude != 0.0) {
//document.getElementById('you').innerHTML='(0,0)';
if (document.getElementById('spfr').innerHTML.indexOf('rom') != -1) {
if (document.getElementById('latf') && document.getElementById('longf')) {
document.getElementById('latf').focus();
document.getElementById('latf').value=userlatitude;
document.getElementById('longf').focus();
document.getElementById('longf').value=userlongitude;
document.getElementById('latf').focus();
userlatitude=0.0;
userlongitude=0.0;
document.getElementById('ssf').innerHTML='Here';
gllentry='' + document.getElementById('latf').value + ',' + document.getElementById('longf').value + ',Here';
askit();
//document.getElementById('spfr').innerHTML='to';
fplacen='Here';
}
} else {
if (document.getElementById('latt') && document.getElementById('longt')) {
document.getElementById('latt').focus();
document.getElementById('latt').value=userlatitude;
document.getElementById('longt').focus();
document.getElementById('longt').value=userlongitude;
document.getElementById('latt').focus();
userlatitude=0.0;
userlongitude=0.0;
document.getElementById('sst').innerHTML='Here';
gllentry='' + document.getElementById('latt').value + ',' + document.getElementById('longt').value + ',Here';
askit();
tplacen='Here';
}
}
}
}
}

… into our changed missing_two.html‘s “Missing Two” web application.

What a programmer’s relief!


Previous relevant Earth Bearing Distance Missing Two Trip Compass Tutorial is shown below.

Earth Bearing Distance Missing Two Trip Compass Tutorial

Earth Bearing Distance Missing Two Trip Compass Tutorial

The recent Earth Bearing Distance Missing Two Trip North Point Tutorial set up a …

  • mobile device “North point” additional functionality … and today …
  • more compass use helpers to guide user towards facing North … as well as …
  • allow for Degrees Minutes Seconds as alternative angular method of entry harnessing changed HTML … exemplified by …

    Latitude (decimal degrees): <input title='' style='width:90px;display:inline-block;' onchange='this.style.backgroundColor="pink";cwhat[0]=false; cwhat[1]=false; if (!decided) { if (!cwhat[5]) { cwhat[5]=true; } if (!cwhat[4]) { cwhat[4]=true; } decided=true; } top.document.getElementById("ltf").value=this.value; ' onblur='this.style.backgroundColor="pink"; cwhat[0]=false; cwhat[1]=false; if (!decided) { if (!cwhat[5]) { cwhat[5]=true; } if (!cwhat[4]) { cwhat[4]=true; } decided=true; } top.document.getElementById("ltf").value=mdms(this.value,this); ' id=latf name=latf type=number onfocus='ati=0; atic=[]; atis=[];' onkeydown='couldbedms(event);' min=-90.0000000 max=90.0000000 step=0.0000010 value='0.0000000'></input><br>

    … helped out by new Javascript …

    var ati=0, atis=[], atic=[];

    function mdms(tvis, otvis) {
    var altvl=0.0, dvr=1.0, isv=0;
    if (eval('' + atic.length) >= 1) {
    //alert('ov=' + otvis.value + ' and atic[0]=' + atic[0]);
    if (atic[0].indexOf('-') != -1 && otvis.value.indexOf('-') == -1) {
    isv++;
    } else if (atic[0].indexOf('+') != -1 && otvis.value.indexOf('+') == -1) {
    isv++;
    } else if (eval('' + atis.length) >= 2) {
    if (eval('' + atis[1]) > 60) { isv++; }
    }
    }
    if (eval('' + atic.length) > 1) {
    //alert('Here ' + atic.length + ' last is=' + atic[eval(-1 + atic.length)]);
    for (var ijh=0; ijh<atic.length; ijh++) {
    if (atic[ijh].trim() != '') {
    isv++;
    if (atic[0].indexOf('-') != -1) {
    altvl-=eval(eval('' + dvr) * eval(atic[ijh].replace('-','')));
    } else {
    altvl+=eval(eval('' + dvr) * eval(atic[ijh].replace('-','')));
    }
    //alert('Here ' + altvl);
    dvr/=60.0;
    }
    }
    if (isv > 1) {
    tvis='' + altvl;
    otvis.value='' + altvl;
    }
    }
    ati=0;
    atic=[];
    atis=[];
    return tvis;
    }

    function idms(otvis) {
    var altvl=0.0, dvr=1.0, isv=0;
    if (eval('' + atic.length) >= 1) {
    //alert('Ov=' + otvis.value + ' and Atic[0]=' + atic[0]);
    if (atic[0].indexOf('-') != -1 && otvis.value.indexOf('-') == -1) {
    isv++;
    } else if (atic[0].indexOf('+') != -1 && otvis.value.indexOf('+') == -1) {
    isv++;
    } else if (eval('' + atis.length) >= 2) {
    if (eval('' + atis[1]) > 60) { isv++; }
    }
    }
    if (eval('' + atic.length) > 1) {
    //alert('here ' + atic.length + ' last is=' + atic[eval(-1 + atic.length)]);
    for (var ijh=0; ijh<atic.length; ijh++) {
    if (atic[ijh].trim() != '') {
    isv++;
    if (atic[0].indexOf('-') != -1) {
    altvl-=eval(eval('' + dvr) * eval(atic[ijh].replace('-','').replace('+','')));
    } else {
    altvl+=eval(eval('' + dvr) * eval(atic[ijh].replace('-','').replace('+','')));
    }
    //alert('here ' + altvl);
    dvr/=60.0;
    }
    }
    if (isv > 1) {
    otvis.value='' + altvl;
    }
    }
    ati=0;
    atic=[];
    atis=[];
    return otvis;
    }

    function couldbedms(event) {
    var wasc='';
    if (eval('' + event.keyCode) == 69 || eval('' + event.keyCode) == 78 || eval('' + event.keyCode) == 87 || eval('' + event.keyCode) == 83 || eval('' + event.keyCode) == 187 || eval('' + event.keyCode) == 189 || eval('' + event.keyCode) == 190 || (eval('' + event.keyCode) >= 48 && eval('' + event.keyCode) <= 57)) {
    if (ati == 0) { atis=[]; atis.push(0); atic.push(''); } else if (ati < 0) { ati=0; }
    ati++;
    atis[eval(-1 + atis.length)]=ati;
    if (eval('' + event.keyCode) == 87 || eval('' + event.keyCode) == 83) {
    if (atic[0].indexOf('-') == -1) { wasc=atic[0]; atic[0]='-' + wasc; }
    } else if (eval('' + event.keyCode) == 69 || eval('' + event.keyCode) == 78) {
    if (atic[0].indexOf('+') == -1) { wasc=atic[0]; atic[0]='+' + wasc; }
    } else if (eval('' + event.keyCode) != 187) {
    atic[eval(-1 + atic.length)]+=String.fromCharCode(eval(eval('' + event.keyCode) % 144));
    }
    } else {
    ati=-1;
    if (eval('' + event.keyCode) >= 65 && eval('' + event.keyCode) <= 90) {
    atis.push(eval('' + event.keyCode));
    } else {
    atis.push(0);
    }
    atic.push('');
    }
    }

… improving the functionality and ease of use of our changed missing_two.html‘s “Missing Two” web application when using a mobile platform.


Previous relevant Earth Bearing Distance Missing Two Trip North Point Tutorial is shown below.

Earth Bearing Distance Missing Two Trip North Point Tutorial

Earth Bearing Distance Missing Two Trip North Point Tutorial

We build on the recent Earth Bearing Distance Missing Two Trip Tap Orientation Tutorial and help out those “what’s out there in the distance” dreamers of Earth Bearing Distance Missing Two Trip Details Orientation Tutorial by, today adding a “North point” (HTML table element) to …

… on some mobile platforms, such as the iOS iPad we tested, adding compass like new functionality, as per the new HTML …


<h1 id=myh1 style='display:block;'>Missing Two (<font size=1>optional</font> <span onclick="this.innerHTML=this.innerHTML.replace('to','From').replace('from','to').replace('From','from'); document.getElementById('ipn').focus(); " id=spfr title='Click me to toggle between from and to' style='cursor:pointer;'>from</span> <input title='Optionally semicolon separate an elevation affecting horizon distance used for Place Name/Bearing (where Compass app might show you this elevation value) input scenarios. Note that a Place Name/Distance scenario shows a Locality Distance Ring map. Append space for gyroscope bearing.' onblur='lkwk(this);' style='display:inline-block;width:280px;' placeholder='Place Name' id=ipn value='' type=text></input>) in Table Column <span data-onfocus="document.getElementById('semail').innerHTML='';" data-title='Email to (append a space to just show the table cell with the gradient)?' data-contenteditable=true data-onblur=preemail(this.innerHTML); onclick=emailit(''); id=semail title=Email>&#128231;</span> <span data-onfocus="document.getElementById('semail').innerHTML='';" data-title='SMS to?' data-contenteditable=true data-onblur=preemail(this.innerHTML); onclick=toize(''); id=ssms title=SMS>&#128223;</span><div id=dntable style=display:none;>    <table border=1 id=ntable style="background-color:pink;display:inline-block;font-size:10px;"><tr><td>N</td></tr><tr><td>&#11014;</td></tr></table>    &#11014;</div></h1>

… and Javascript …


var wasthisso='' + (screen.msOrientation || screen.mozOrientation || (screen.orientation || {}).type); //"portrait";
var wasangle=eval(180 - eval('' + window.orientation));


if (1 == 1) {
window.addEventListener("orientationchange", function() {
// Announce the new orientation number
wasangle=eval(180 - eval('' + window.orientation));
var thisso='' + screen.msOrientation || screen.mozOrientation || (screen.orientation || {}).type;
if (('' + thisso) == 'undefined') {
var mql=window.matchMedia("(orientation: portrait)");
// If there are matches, we're in portrait
if (mql.matches) {
thisso="Portrait"; // Portrait orientation
} else {
thisso="Landscape"; // Landscape orientation
}
}


if (thisso != wasthisso) {
wasthisso=thisso;
//alert('ori');
}
}, false);
}

if (window.DeviceOrientationEvent) {
if (1 == 2) { alert(1); }
// Listen for orientation changes ... thanks to https://davidwalsh.name/orientation-change
// Listen for the deviceorientation event and handle the raw data
window.addEventListener('deviceorientation', function(eventData) {
// gamma is the left-to-right tilt in degrees, where right is positive
if (1 == 2) { alert(11); }
if (document.getElementById('ipn')) {
//if (('' + document.getElementById('ipn').placeholder).indexOf('Append space and face north for gyroscope bearing.') == -1) {
if (('' + document.getElementById('ipn').placeholder).indexOf(' and ') == -1) {
document.getElementById('ipn').className='ph';
document.getElementById('ipn').placeholder+='. Append space and portrait face north for gyroscope bearing.';
document.getElementById("myviewport").setAttribute("content", "width=device-width, initial-scale=1.5, minimum-scale=0.1, maximum-scale=8, user-scalable=yes");
setTimeout(asafn, 5000);
}
}
//eventData.absolute=true;


var eventDataalpha = eval(360.0 - eval('' + eventData.alpha)); // lalpha)); //
if (eventData.absolute !== true && +eventData.webkitCompassAccuracy > 0 && +eventData.webkitCompassAccuracy < 50) {
eventDataalpha = eval('' + eventData.webkitCompassHeading || 0);
if (document.getElementById('dntable')) { document.getElementById('dntable').style.display='inline-block'; }
}

if (!datstart) { eventDataalpha-=initial_yaw; }


tiltLeftToRight = eval('' + eventData.gamma);

// beta is the front-to-back tilt in degrees, where front is positive
tiltFrontToBack = eval('' + eventData.beta);

// alpha is the compass direction the device is facing in degrees
lastalpha='' + eventData.alpha; // lalpha; //
dorbrg = eval('' + eventDataalpha); //compassHeading(eval('' + eventDataalpha), tiltFrontToBack, tiltLeftToRight);
if (1 == 2) { alert(dorbrg); }
if (document.URL.indexOf('aleJUNKrt=') != -1) {
alert(dorbrg);
}
if (document.URL.indexOf('upJUNKdate=') != -1 || (fplacen != '' && tplacen == '')) {
if (eventData.absolute || 1 == 1) {
//document.getElementById('brg').value='' + eval(eval(540.0 - eval('' + dorbrg)) % 360.0);
//document.getElementById('brg').value='' + eval(eval(720.0 - eval('' + dorbrg)) % 360.0);
//document.getElementById('brg').value='' + dorbrg;
if (eval(dcnt % 10) == 0) {
document.getElementById('brg').value='' + eval(eval(720.0 + eval('' + dorbrg)) % 360.0);
document.getElementById('brg').style.backgroundColor='yellow';
}
dcnt++;
}
}


if (datstart && (fplacen != '' && tplacen == '')) {
datstart=false;
//initial_yaw=eval(360.0 - eval('' + lalpha)); //eventData.alpha));
//alert('0:' + initial_yaw);
if (!eventData.absolute) {
initial_yaw=eval(360.0 - eval('' + eventData.alpha)); // lalpha)); //
}
//alert('' + initial_yaw);
initial_pitch=Math.round(tiltFrontToBack);
initial_roll=Math.round(tiltLeftToRight);
//alert(initial_yaw + ',' + initial_pitch + ',' + initial_roll);
}


if (document.getElementById('ntable')) {
var ts=450;
if (wasangle != 0) {
ts+=wasangle;
}
try { document.getElementById('ntable').style.webkitTransform = ("rotate(" + eval(ts - Math.round(dorbrg)) + "deg)"); } catch(e10) { }
try { document.getElementById('ntable').style.MozTransform = ("rotate(" + eval(ts - Math.round(dorbrg)) + "deg)"); } catch(e1000) { }
try { document.getElementById('ntable').style.msTransform = ("rotate(" + eval(ts - Math.round(dorbrg)) + "deg)"); } catch(e100) { }
try { document.getElementById('ntable').style.OTransform = ("rotate(" + eval(ts - Math.round(dorbrg)) + "deg)"); } catch(e10000) { }
try { document.getElementById('ntable').style.transform = ("rotate(" + eval(ts - Math.round(dorbrg)) + "deg)"); } catch(e1) { }
}



handleOrientationEvent(tiltFrontToBack, tiltLeftToRight, dorbrg, eventData.absolute);

if ((fplacen != '' && tplacen == '') && document.getElementById('ipn')) {
//if (('' + document.getElementById('ipn').placeholder).indexOf('Append space and face north for gyroscope bearing.') != -1) {
if (('' + document.getElementById('ipn').placeholder).indexOf('Append space and ') != -1) {
document.getElementById('ipn').style.backgroundColor='#f0f0f0';
//document.getElementById('ipn').placeholder=document.getElementById('ipn').placeholder.split('Append space and face north for gyroscope bearing.')[0] + ' Now swivel to direction of interest then tap yellow textbox.';
document.getElementById('ipn').placeholder=document.getElementById('ipn').placeholder.split('Append space and ')[0] + ' Now swivel to direction of interest then tap yellow textbox.';
document.getElementById("myviewport").setAttribute("content", "width=device-width, initial-scale=1.2, minimum-scale=0.1, maximum-scale=8, user-scalable=yes");
//window.scrollBy(0,50); //location.href='#brg';
}
}


}, false);
}


Previous relevant Earth Bearing Distance Missing Two Trip Tap Orientation Tutorial is shown below.

Earth Bearing Distance Missing Two Trip Details Tap Tutorial

Earth Bearing Distance Missing Two Trip Tap Orientation Tutorial

That window.DeviceOrientationEvent event work of the recent Earth Bearing Distance Missing Two Trip Details Orientation Tutorial was missing an important point. We learnt about this point by debugging on an iOS (iPhone 7) Google Chrome web browser, as we showed with yesterday’s Google Chrome on iOS Web Browser Debug Tutorial. That tutorial’s finding lead us to the Google search for …


ERROR NotAllowedError Requesting device

… and onto the excellent How to requestPermission for devicemotion and deviceorientation events in iOS 13+

One more thing

One more thing to keep in mind is that requestPermission could only be called on a user gesture (e.g. click). This is reasonable UX too as we would want to tell users why we are asking for such permissions and let them confirm before prompting them so that they see it coming.

Otherwise you would get this error:

Console error: NotAllowedError: Requesting device orientation or motion access requires a user gesture to prompt

… where we needed to shift our oft-used document.body onload event code placement thinking to allow for this thinking, plus the provision of a button for the user to tap, as required, should the “permission” popup window be required to seek permission to, effectively, access that device’s gyroscope measurements via that window.DeviceOrientationEvent and/or window.DeviceMotionEvent event(s).

This is a similar Apple requirement, as it applies to iOS playing audio files, which we have mentioned quite a bit at this blog. One could say …

We should have known.

… and luckily two is too polite to say …

You blockhead!

… to which we are infinitely grateful, and will install for the rest of the day, that …

Two is our favourite number (for the rest of today, that is).

But it’s not only …

… for you to try for yourself, perhaps there on your mobile device with an accessible gyroscope on a compatible web browser such as Google Chrome (or others, now) on iOS.


Previous relevant Earth Bearing Distance Missing Two Trip Details Orientation Tutorial is shown below.

Earth Bearing Distance Missing Two Trip Details Orientation Tutorial

Earth Bearing Distance Missing Two Trip Details Orientation Tutorial

Humans, particularly before the advent of the mobile devices, were probably (as a whole) more skilled regarding navigation via “landmarks” or “sunmarks” or “moonmarks” working out …

In which direction is North?

Well, the irony here, today, is that the better you have been hanging onto these skills you are, the better you can use our new …

  • mobile phone …
  • containing a gyroscope … but …
  • not an accessible compass (or if so, the knowledge of where North is becomes superfluous below)
  • using a compatible web browser such as Google Chrome …
  • a good indication your scenario is compatible being that at some stage you answer “Allow” to a prompt as below …

    … at some point … using …
  • today’s changed missing_two.html‘s live run link modifications … using …
    1. window.DeviceOrientationEvent event … and perhaps you could use …
    2. window.DeviceMotionEvent event

  • software detection to offer that user …

… the chance to mix technology with human navigational instincts to answer that perennial question similarly asked in Earth Bearing Distance Missing Two Place Name and Horizon Tutorial

What’s out there in the distance?

… via …

  1. using a compatible web browser such as Google Chrome … live run
  2. point your mobile phone in portrait to North (or at least arrange to do this just before tapping the Done link in step below)
  3. enter in a Place Name into that top textbox (to which, it’s good, as known, to append semicolon elevation) and add a space, and because you are on a mobile device, tap the Done link
  4. bearing text will start being updated with bearing of your mobile device portrait mode top pointing direction … so …
  5. when you’ve swivelled the mobile device to be pointing (in portrait) to the (What’s out there in the distance?) direction of interest, tap that yellow bearing textbox, then tap the Done link … resulting in …
  6. Google Chart Map Chart showing your Place Name and (the calculated) Horizon Position in that direction of your choosing

… meaning the combination of …

  • your mobile device’s gyroscope’s angle measuring talent (akin to those theodolite talents Land Surveyors are using) … and …
  • your navigational talents knowing where North is

… save you having to know that awkward “bearing” (in degrees) textbox answer to What’s out there in the distance? Perhaps see what we mean viewing today’s animated GIF presentation.

Onto yesterday’s Earth Bearing Distance Missing Two Trip Details Styling Tutorial and since the last time we ventured into the wooooorrrrrlllldddd of “window.DeviceOrientationEvent” logic we’ve gotten great help Javascript coding for the permissions side to the handling of this event, as per …


if ((navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) || document.URL.indexOf('alert=') != -1) && document.URL.toLowerCase().indexOf('https:') != 0) {
location.href=document.URL.replace('http:','https:') + '&random=' + Math.floor(Math.random() * 174765654);
}
if ((navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i) || document.URL.indexOf('update=') != -1) && document.URL.toLowerCase().indexOf('https:') != 0) {
location.href=document.URL.replace('http:','https:') + '&random=' + Math.floor(Math.random() * 174765654);
}

// Thanks to https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await and
// https://gist.github.com/Ajasra/ddd616505013a4309c0dda8a8ba626cb

async function myfunction() {
console.log('Inside of myfunction');
//alert(0);
if (window.DeviceOrientationEvent && typeof(DeviceOrientationEvent.requestPermission) === "function") {
//alert(4);
const permissionState = await DeviceOrientationEvent.requestPermission().then(response => {
if (response === 'granted') {
if (1 == 2) { alert('GrAnted'); }
//window.addEventListener('deviceorientation', OrientationHandler, true);
dorh();
} else if (result.state === 'prompt') {
if (1 == 2) { alert("Need prompt!"); }
} else {
if (1 == 2) { alert("Not Supported!"); }
}
}).catch(console.error);

//if (permissionState === "granted") {
// alert('granted');
//} else {
// alert('denied');
//}
} else if (window.DeviceOrientationEvent) {
//alert(44);
dorh();
}

if (window.DeviceMotionEvent && typeof(DeviceMotionEvent.requestPermission) === "function") {
//alert(24);
const permissionStateM = await DeviceMotionEvent.requestPermission().then(response => {
if (response === 'granted') {
if (1 == 2) { alert('GranTed'); }
window.addEventListener('devicemotion', function(event) {
lalpha='' + event.rotationRate.alpha;
});
//window.addEventListener('deviceorientation', OrientationHandler, true);
} else if (result.state === 'prompt') {
if (1 == 2) { alert("NeeD prompt!"); }
} else {
if (1 == 2) { alert("NoT Supported!"); }
}
}).catch(console.error);

//if (permissionStateM === "granted") {
// alert('Granted');
//} else {
// alert('Denied');
//}
} else if (window.DeviceMotionEvent) {
//alert(244);
window.addEventListener('devicemotion', function(event) {
lalpha='' + event.rotationRate.alpha;
});
}

}

// Here we wait for the myfunction to finish
// and then returns a promise that'll be waited for aswell
// It's useless to wait the myfunction to finish before to return
// we can simply returns a promise that will be resolved later

// Also point that we don't use async keyword on the function because
// we can simply returns the promise returned by myfunction
function start() {
return myfunction();
}

// Call start
(async() => {
console.log('before start');

await start();


console.log('after start');
})();

var degtorad = Math.PI / 180; // Degree-to-Radian conversion ... thanks to https://www.w3.org/TR/orientation-event/#worked-example

function dorh() {
//let laSensor = new LinearAccelerationSensor({frequency: 60});

//laSensor.addEventListener('reading', e => {
// console.log("Linear acceleration along the X-axis " + laSensor.x);
// console.log("Linear acceleration along the Y-axis " + laSensor.y);
// console.log("Linear acceleration along the Z-axis " + laSensor.z);
//});
//laSensor.start();


//window.addEventListener('devicemotion', function(event) {
// alert(event.rotationRate.alpha + ' m/s2');
//});


if (1 == 3) {
window.addEventListener("orientationchange", function() {
// Announce the new orientation number
var thisso='' + screen.msOrientation || screen.mozOrientation || (screen.orientation || {}).type;
if (('' + thisso) == 'undefined') {
var mql=window.matchMedia("(orientation: portrait)");
// If there are matches, we're in portrait
if (mql.matches) {
thisso="Portrait"; // Portrait orientation
} else {
thisso="Landscape"; // Landscape orientation
}
}


if (thisso != wasthisso) {
wasthisso=thisso;
alert('ori');
}
}, false);
}

if (window.DeviceOrientationEvent) {
if (1 == 2) { alert(1); }
// Listen for orientation changes ... thanks to https://davidwalsh.name/orientation-change
// Listen for the deviceorientation event and handle the raw data
window.addEventListener('deviceorientation', function(eventData) {
// gamma is the left-to-right tilt in degrees, where right is positive
if (1 == 2) { alert(11); }
if (document.getElementById('ipn')) {
//if (('' + document.getElementById('ipn').placeholder).indexOf('Append space and face north for gyroscope bearing.') == -1) {
if (('' + document.getElementById('ipn').placeholder).indexOf(' and ') == -1) {
document.getElementById('ipn').className='ph';
document.getElementById('ipn').placeholder+='. Append space and portrait face north for gyroscope bearing.';
document.getElementById("myviewport").setAttribute("content", "width=device-width, initial-scale=1.5, minimum-scale=0.1, maximum-scale=8, user-scalable=yes");
setTimeout(asafn, 5000);
}
}
//eventData.absolute=true;


var eventDataalpha = eval(360.0 - eval('' + eventData.alpha)); // lalpha)); //
if (!datstart) { eventDataalpha-=initial_yaw; }


tiltLeftToRight = eval('' + eventData.gamma);

// beta is the front-to-back tilt in degrees, where front is positive
tiltFrontToBack = eval('' + eventData.beta);

// alpha is the compass direction the device is facing in degrees
lastalpha='' + eventData.alpha; // lalpha; //
dorbrg = eval('' + eventDataalpha); //compassHeading(eval('' + eventDataalpha), tiltFrontToBack, tiltLeftToRight);
if (1 == 2) { alert(dorbrg); }
if (document.URL.indexOf('aleJUNKrt=') != -1) {
alert(dorbrg);
}
if (document.URL.indexOf('upJUNKdate=') != -1 || (fplacen != '' && tplacen == '')) {
if (eventData.absolute || 1 == 1) {
//document.getElementById('brg').value='' + eval(eval(540.0 - eval('' + dorbrg)) % 360.0);
//document.getElementById('brg').value='' + eval(eval(720.0 - eval('' + dorbrg)) % 360.0);
//document.getElementById('brg').value='' + dorbrg;
if (eval(dcnt % 10) == 0) {
document.getElementById('brg').value='' + eval(eval(720.0 + eval('' + dorbrg)) % 360.0);
document.getElementById('brg').style.backgroundColor='yellow';
}
dcnt++;
}
}


if (datstart && (fplacen != '' && tplacen == '')) {
datstart=false;
//initial_yaw=eval(360.0 - eval('' + lalpha)); //eventData.alpha));
//alert('0:' + initial_yaw);
if (!eventData.absolute) {
initial_yaw=eval(360.0 - eval('' + eventData.alpha)); // lalpha)); //
}
//alert('' + initial_yaw);
initial_pitch=Math.round(tiltFrontToBack);
initial_roll=Math.round(tiltLeftToRight);
//alert(initial_yaw + ',' + initial_pitch + ',' + initial_roll);
}


handleOrientationEvent(tiltFrontToBack, tiltLeftToRight, dorbrg, eventData.absolute);

if ((fplacen != '' && tplacen == '') && document.getElementById('ipn')) {
//if (('' + document.getElementById('ipn').placeholder).indexOf('Append space and face north for gyroscope bearing.') != -1) {
if (('' + document.getElementById('ipn').placeholder).indexOf('Append space and ') != -1) {
document.getElementById('ipn').style.backgroundColor='#f0f0f0';
//document.getElementById('ipn').placeholder=document.getElementById('ipn').placeholder.split('Append space and face north for gyroscope bearing.')[0] + ' Now swivel to direction of interest then tap yellow textbox.';
document.getElementById('ipn').placeholder=document.getElementById('ipn').placeholder.split('Append space and ')[0] + ' Now swivel to direction of interest then tap yellow textbox.';
document.getElementById("myviewport").setAttribute("content", "width=device-width, initial-scale=1.2, minimum-scale=0.1, maximum-scale=8, user-scalable=yes");
//window.scrollBy(0,50); //location.href='#brg';
}
}


}, false);
}
}

var handleOrientationEvent = function(tiltFrontToBack, tiltLeftToRight, dorbrg, absis) {
// do something amazing
if (1 == 2) { alert(dorbrg); }
if (document.URL.indexOf('alJUNKert=') != -1) {
alert(dorbrg);
}
if (document.URL.indexOf('upJUNKdate=') != -1 || (fplacen != '' && tplacen == '')) {
if (absis || 1 == 1) {
//document.getElementById('brg').value='' + eval(eval(540.0 - eval('' + dorbrg)) % 360.0);
//document.getElementById('brg').value='' + eval(eval(720.0 - eval('' + dorbrg)) % 360.0);
//document.getElementById('brg').value='' + dorbrg;
if (eval(dcnt % 10) == 0) {
document.getElementById('brg').value='' + eval(eval(720.0 + eval('' + dorbrg)) % 360.0);
document.getElementById('brg').style.backgroundColor='yellow';
}
dcnt++;
}
}
};


function asafn() {
if (document.getElementById('ipn')) {
//if (('' + document.getElementById('ipn').placeholder).indexOf('Append space and face north for gyroscope bearing.') == -1) {
if (('' + document.getElementById('ipn').placeholder).indexOf('Append space and portrait face north for ') != -1) {
document.getElementById('ipn').placeholder=document.getElementById('ipn').placeholder.split('Append space and ')[0] + 'Append space and portrait face north onto ;elevation(m)?';
setTimeout(asafn, 5000);
} else if (('' + document.getElementById('ipn').placeholder).indexOf('Append space and ') != -1) {
document.getElementById('ipn').placeholder=document.getElementById('ipn').placeholder.split('Append space and ')[0] + 'Append space and portrait face north for horizon bearing.';
setTimeout(asafn, 5000);
}
}
}

Today we added a meta viewport, and for the first time that we can recall, we started styling the “placeholder” of that top textbox as per (thanks to https://stackoverflow.com/questions/44679144/how-to-make-input-placeholder-font-size-different-from-input-value-font-size) …


<meta id="myviewport" name="viewport" content="width=device-width, initial-scale=1, minimum-scale=0.1, maximum-scale=8, user-scalable=yes" >
<style>
summary { background-color: #f0f0f0; }

.ph::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
color: red;
opacity: 1; /* Firefox */
font-size: 8px;
}

.ph:-ms-input-placeholder { /* Internet Explorer 10-11 */
color: red;
font-size: 8px;
}

.ph::-ms-input-placeholder { /* Microsoft Edge */
color: red;
font-size: 8px;
}

</style>


Previous relevant Earth Bearing Distance Missing Two Trip Details Styling Tutorial is shown below.

Earth Bearing Distance Missing Two Trip Details Styling Tutorial

Earth Bearing Distance Missing Two Trip Details Styling Tutorial

On top of the recent Earth Bearing Distance Missing Two Trip Details Reveal Tutorial, today we discuss styling strategies a little. When and where do you style your webpage? We think you do it all along, but for us, we like “little spurts” at it too, so we might let a web application project progress in a practical approach not worrying about aesthetics too much until we do a “little spurt” bubble of activity regarding styling. Often times ideas for that can be developed away from the laptop you might write the code on. For example, today’s changed missing_two.html‘s live run link modifications were directed by an email we sent to ourselves …

Jobs

Robert Metcalfe
Sun, Sep 12, 8:16 PM (5 days ago)
to me

Vertical-align: top
I frame too high
To after horizon leaves horizon I frame title
Lat long display online-block
Coloured summary background colour
Th header cells text-align center

Sent from my iPhone

… “mind map” type ideas that may or may not be followed through to fruition, depending on …

  • where possible
  • where feasible
  • where wise

This strategy above is for your small projects, else if much bigger, or involving multiple people to produce, or being written to a specification, or being written for a third party, you’d be much better placed to think about styling issues from the start, in a plan. You might want to use wireframes?

On these small projects we also don’t mind just involving the one HTML (or PHP writing HTML) source file and use a combination of …

  • inline <style> CSS styling goes here </style> within the webpage <head></head> header section … or …
  • in amongst the HTML via “style” attribute … eg. <p id=”myp” style=” CSS styling for p element goes here “> Content for p element goes here </p>

… or Javascript DOM code such as …


document.getElementById('myp').style.fontSize='18px';

… and it is very rare, with these small projects, though very good in organizational terms, to write all your CSS styling in an external CSS (styling file) arrangement such as …


<head>
<link href='./my_styling.css' rel='stylesheet' type='text/css'>
</head>

There are many ways to … well, you know what I mean … a cat! Not only were “no cats harmed in the making of this tutorial” but no cats were even roughed up?!


Previous relevant Earth Bearing Distance Missing Two Trip Details Reveal Tutorial is shown below.

Earth Bearing Distance Missing Two Trip Details Reveal Tutorial

Earth Bearing Distance Missing Two Trip Details Reveal Tutorial

Yes, there’s only so long you can use the wonderful details/summary HTML element combination as with the recent Earth Bearing Distance Missing Two Trip Details Summary Tutorial‘s …

we often use to “reveal”, or not, webpage “real estate”, but today we default to the “open” look

… just using that “open” element mode of use, and not want to make use of its “reveal” talents. How so? Well, a bit like the dropdown element, we find that the details/summary combination allows for the containment of lots of data for a controlled amount of “reveal”. In this day and age of responsiveness to limited screen sizes, that is a big advantage.

Today, then, with our changed missing_two.html‘s live run link, we have …

  1. that first (at first) “open” details/summary nesting a Google Chart Map Chart iframe summarizing the entirety of your Trip … today …
  2. festooned with up arrow emoji (⬆) “button” links which, when clicked, zero in (into a new topmost “only open” details/summary nesting Google Chart Map Chart iframe set of data) on any one “leg” of your trip, displaying its own crow fly distance and Google Maps Directions information link, as well as new …
  3. accommodation (🛌) links ala accommodation in Springwood, New South Wales Google image search style links

… to enhance a Trip Planner’s user experience. Perhaps best to explain a bit codewise is to say “follow the Javascript variable interesting in code below” …


function askit() {
var ourdist=0.0, ourbrg=0.0;
//alert(gllentry);
if (gllentry.indexOf(',') != -1) {
if ((1 == 2 && gllonesuffix == 'f') || document.getElementById('spfr').innerHTML == 'from') {
tpurl=origtpurl;
document.getElementById('latf').focus();
document.getElementById('latf').value=gllentry.split(',')[0];
//var mu="//www.rjmprogramming.com.au/PHP/Map/map.php?title=London&label=['Lat',&value='Lon','Name']&data=,[51.5072,-0.1275,~London~]";
mu=mu.replace('[51.5072,','[' + gllentry.split(',')[0] + ',');
document.getElementById('longf').focus();
document.getElementById('longf').value=gllentry.split(',')[1];
mu=mu.replace(',-0.1275,',',' + gllentry.split(',')[1] + ',');
document.getElementById('latf').focus();
gllonesuffix = 't';
document.getElementById('spfr').innerHTML=document.getElementById('spfr').innerHTML.replace('from','to<input type=hidden name=fplacen value="' + gllentry.split(',')[2].replace(/\;/g,',') + '"></input>');
fplacen=gllentry.split(',')[2].replace(/\;/g,',');
document.getElementById('ssf').innerHTML=' ' + gllentry.split(',')[2].replace(/\;/g,',');
mu=mu.replace('=LonJunkdon','=' + encodeURIComponent(gllentry.split(',')[2].replace(/\;/g,','))).replace(',~London~]',',~' + encodeURIComponent(gllentry.split(',')[2].replace(/\;/g,',')) + '~],[051.5072,-00.1275,~LonDon~]');
tpurl=tpurl.replace("Sydney+NSW,+Australia",encodeURIComponent(gllentry.split(',')[2].replace(/\;/g,',')));
if (document.getElementById('sftif') && document.getElementById('iftif')) {
document.getElementById('iftif').src=document.getElementById('iftif').src.replace('&',encodeURIComponent(' from ' + gllentry.split(',')[2].replace(/\;/g,',')) + '&') + ',[' + gllentry.replace(',' + gllentry.split(',')[1] + ',', ',' + gllentry.split(',')[1] + ',~').replace(/\ /g,'%20') + '~]';
document.getElementById('sftif').innerHTML+=' <a target=_blank title=Accomodation onclick=woit(this); data-href="' + accomurl.replace(/Springwood\,\+New\+South\+Wales/g, encodeURIComponent(gllentry.split(',')[2].replace(/\;/g,',')).replace(/\%20/g,'+')) + '">from &#128716;</a> <a target=_blank title="' + gllentry.split(',')[2].replace(/\;/g,',') + '" href="//en.wikipedia.org/wiki/' + encodeURIComponent(gllentry.split(',')[2].replace(/\;/g,',')) + '">' + gllentry.split(',')[2].replace(/\;/g,',') + '</a>';
document.getElementById('brg').value='0.0000000';
document.getElementById('dist').value='0.000';
document.getElementById('brg').style.backgroundColor='white';
document.getElementById('dist').style.backgroundColor='white';
cwhat=[false,false,true,true,false,false];
ourdist=great_circle_distance(document.getElementById(eles[0]).value,document.getElementById(eles[1]).value,document.getElementById(eles[4]).value,document.getElementById(eles[5]).value);
document.getElementById(eles[3]).value='' + ourdist;

//Let ‘R’ be the radius of Earth,
//‘L’ be the longitude,
//‘θ’ be latitude,
//‘β‘ be Bearing.


//Bearing from point A to B, can be calculated as,

//β = atan2(X,Y),

//where, X and Y are two quantities and can be calculated as:

//X = cos θb * sin ∆L

//Y = cos θa * sin θb – sin θa * cos θb * cos ∆L


ourbrg=eval(eval(360.0 + eval(eval(eval(180.0 / Math.PI) * Math.atan2(
eval(eval('' + Math.cos(eval(Math.PI / 180.0) * eval('' + document.getElementById(eles[4]).value))) *
eval('' + Math.sin(eval(Math.PI / 180.0) * eval(eval('' + document.getElementById(eles[5]).value) - eval('' + document.getElementById(eles[1]).value))))),
eval(eval('' + Math.cos(eval(Math.PI / 180.0) * eval('' + document.getElementById(eles[0]).value))) *
eval('' + Math.sin(eval(Math.PI / 180.0) * eval('' + document.getElementById(eles[4]).value)))) -
eval(eval('' + Math.sin(eval(Math.PI / 180.0) * eval('' + document.getElementById(eles[0]).value))) *
eval('' + Math.cos(eval(Math.PI / 180.0) * eval('' + document.getElementById(eles[4]).value))) *
eval('' + Math.cos(eval(Math.PI / 180.0) * eval(eval('' + document.getElementById(eles[5]).value) - eval('' + document.getElementById(eles[1]).value)))))
)))) % 360.0);


document.getElementById('mysel').value='2';
document.getElementById(eles[2]).value='' + ourbrg;
document.getElementById(eles[2]).style.backgroundColor='lightgreen';
document.getElementById(eles[3]).style.backgroundColor='lightgreen';
}
} else {
var interesting=false, waslatt='', waslongt='', wasfplacen='';
if (gllonesuffix == 'f') {
interesting=true;
waslatt=document.getElementById('latt').value;
waslongt=document.getElementById('longt').value;
if (documentURL == document.URL) {
wasfplacen=location.search.split('tplacen=')[1] ? (' ' + decodeURIComponent(location.search.split('tplacen=')[1].split('&')[0]).replace(/\+/g,' ')) : ''; //document.getElementById('tplacen').value;
} else {
wasfplacen=decodeURIComponent(documentURL.split('tplacen=')[eval(-1 + documentURL.split('tplacen=').length)].split('&')[0]);
}
//alert('interesting');
}

mu=mu.replace('=London','=' + encodeURIComponent(fplacen));
document.getElementById('brg').focus();
document.getElementById('dist').focus();
document.getElementById('latt').focus();
document.getElementById('latt').value=gllentry.split(',')[0];
mu=mu.replace('[051.5072,','[' + gllentry.split(',')[0] + ',');
document.getElementById('longt').focus();
document.getElementById('longt').value=gllentry.split(',')[1];
mu=mu.replace(',-00.1275,',',' + gllentry.split(',')[1] + ',');
document.getElementById('latt').focus();
gllonesuffix = 'f';
if (interesting) {
document.getElementById('spfr').innerHTML=document.getElementById('spfr').innerHTML.replace('to','from<input type=hidden id=tplacen name=tplacen value="' + gllentry.split(',')[2].replace(/\;/g,',') + '"></input>');
} else {
document.getElementById('spfr').innerHTML=document.getElementById('spfr').innerHTML.replace('to','from<input type=hidden id=tplacen name=tplacen value="' + gllentry.split(',')[2].replace(/\;/g,',') + '"></input>');
}
document.getElementById('ifill').value='Map Trip';
document.getElementById('sst').innerHTML=' ' + gllentry.split(',')[2].replace(/\;/g,',');
mu=mu.replace(',~LonDon~]',',~' + encodeURIComponent(gllentry.split(',')[2].replace(/\;/g,',')) + '~]');
tpurl=tpurl.replace("Brisbane+QLD,+Australia",encodeURIComponent(gllentry.split(',')[2].replace(/\;/g,',')));
if (document.getElementById('sftif') && document.getElementById('iftif')) {
if (document.getElementById('addafirst')) { document.getElementById('addafirst').style.display='inline-block'; }
if (document.getElementById('addacc')) { document.getElementById('addacc').style.display='inline-block'; }
document.getElementById('iftif').src=document.getElementById('iftif').src.replace('&',encodeURIComponent(' to ' + gllentry.split(',')[2].replace(/\;/g,',')) + '&') + ',[' + gllentry.replace(',' + gllentry.split(',')[1] + ',', ',' + gllentry.split(',')[1] + ',~').replace(/\ /g,'%20') + '~]';
//if (interesting) {
// alert('interesting ... fplacen=' + fplacen);
//}
if (interesting) {
document.getElementById('sftif').innerHTML+=(' from <a target=_blank title="' + wasfplacen + '" href="//en.wikipedia.org/wiki/' + encodeURIComponent(wasfplacen) + '">' + wasfplacen + '</a> ').substring(0,1) + '<a target=_blank title=Accomodation onclick=woit(this); data-href="' + accomurl.replace(/Springwood\,\+New\+South\+Wales/g, encodeURIComponent(wasfplacen).replace(/\%20/g,'+')) + '">&#128716;</a>' + '<a target=_blank title="Google Maps Directions" href="' + tpurl.replace('https:','') + '">to</a><a title="Map of this trip leg" class="adda" onclick="addto(this);" data-from="' + (wasfplacen ? wasfplacen : fplacen) + '" data-to="' + gllentry.split(',')[2].replace(/\;/g,',') + '" style="display:inline-block;cursor:pointer;" data-latf=' + (waslatt ? waslatt : document.getElementById('latf').value) + ' data-longf=' + (waslongt ? waslongt : document.getElementById('longf').value) + ' data-latt=' + document.getElementById('latt').value + ' data-longt=' + document.getElementById('longt').value + ' data-gcd=' + eval(eval('' + great_circle_distance((waslatt ? waslatt : document.getElementById(eles[0]).value),(waslongt ? waslongt : document.getElementById(eles[1]).value),document.getElementById(eles[4]).value,document.getElementById(eles[5]).value)) / 1000.000) + '>&#11014;<a> <a target=_blank title="' + gllentry.split(',')[2].replace(/\;/g,',') + '" href="//en.wikipedia.org/wiki/' + encodeURIComponent(gllentry.split(',')[2].replace(/\;/g,',')) + '">' + gllentry.split(',')[2].replace(/\;/g,',') + '</a> (' + '<a target=_blank title=Accomodation onclick=woit(this); data-href="' + accomurl.replace(/Springwood\,\+New\+South\+Wales/g, encodeURIComponent(gllentry.split(',')[2].replace(/\;/g,',')).replace(/\%20/g,'+')) + '">&#128716;</a> ' + eval(eval('' + great_circle_distance(document.getElementById(eles[0]).value,document.getElementById(eles[1]).value,document.getElementById(eles[4]).value,document.getElementById(eles[5]).value)) / 1000.000) + ' kilometres)';
//alert('interesting ... fplacen=' + wasfplacen);
} else {

document.getElementById('sftif').innerHTML+=' <a target=_blank title="Google Maps Directions" href="' + tpurl.replace('https:','') + '">to</a><a title="Map of this trip leg" class="adda" onclick="addto(this);" data-from="' + (wasfplacen ? wasfplacen : fplacen) + '" data-to="' + gllentry.split(',')[2].replace(/\;/g,',') + '" style="display:inline-block;cursor:pointer;" data-latf=' + (waslatf ? waslatf : document.getElementById('latf').value) + ' data-longf=' + (waslongf ? waslongf : document.getElementById('longf').value) + ' data-latt=' + document.getElementById('latt').value + ' data-longt=' + document.getElementById('longt').value + ' data-gcd=' + eval(eval('' + great_circle_distance((waslatf ? waslatf : document.getElementById(eles[0]).value),(waslongf ? waslongf : document.getElementById(eles[1]).value),document.getElementById(eles[4]).value,document.getElementById(eles[5]).value)) / 1000.000) + '>&#11014;<a> <a target=_blank title="' + gllentry.split(',')[2].replace(/\;/g,',') + '" href="//en.wikipedia.org/wiki/' + encodeURIComponent(gllentry.split(',')[2].replace(/\;/g,',')) + '">' + gllentry.split(',')[2].replace(/\;/g,',') + '</a> (' + '<a target=_blank title=Accomodation onclick=woit(this); data-href="' + accomurl.replace(/Springwood\,\+New\+South\+Wales/g, encodeURIComponent(gllentry.split(',')[2].replace(/\;/g,',')).replace(/\%20/g,'+')) + '">&#128716;</a> ' + eval(eval('' + great_circle_distance(document.getElementById(eles[0]).value,document.getElementById(eles[1]).value,document.getElementById(eles[4]).value,document.getElementById(eles[5]).value)) / 1000.000) + ' kilometres)';
}
document.getElementById('brg').style.backgroundColor='white';
document.getElementById('dist').style.backgroundColor='white';
documentURL+='&tplacen=' + encodeURIComponent(gllentry.split(',')[2].replace(/\;/g,','));
cwhat=[false,false,true,true,false,false];
ourdist=great_circle_distance(document.getElementById(eles[0]).value,document.getElementById(eles[1]).value,document.getElementById(eles[4]).value,document.getElementById(eles[5]).value);
document.getElementById(eles[3]).value='' + ourdist;

//Let ‘R’ be the radius of Earth,
//‘L’ be the longitude,
//‘θ’ be latitude,
//‘β‘ be Bearing.


//Bearing from point A to B, can be calculated as,

//β = atan2(X,Y),

//where, X and Y are two quantities and can be calculated as:

//X = cos θb * sin ∆L

//Y = cos θa * sin θb – sin θa * cos θb * cos ∆L


ourbrg=eval(eval(360.0 + eval(eval(eval(180.0 / Math.PI) * Math.atan2(
eval(eval('' + Math.cos(eval(Math.PI / 180.0) * eval('' + document.getElementById(eles[4]).value))) *
eval('' + Math.sin(eval(Math.PI / 180.0) * eval(eval('' + document.getElementById(eles[5]).value) - eval('' + document.getElementById(eles[1]).value))))),
eval(eval('' + Math.cos(eval(Math.PI / 180.0) * eval('' + document.getElementById(eles[0]).value))) *
eval('' + Math.sin(eval(Math.PI / 180.0) * eval('' + document.getElementById(eles[4]).value)))) -
eval(eval('' + Math.sin(eval(Math.PI / 180.0) * eval('' + document.getElementById(eles[0]).value))) *
eval('' + Math.cos(eval(Math.PI / 180.0) * eval('' + document.getElementById(eles[4]).value))) *
eval('' + Math.cos(eval(Math.PI / 180.0) * eval(eval('' + document.getElementById(eles[5]).value) - eval('' + document.getElementById(eles[1]).value)))))
)))) % 360.0);


document.getElementById('mysel').value='2';
document.getElementById(eles[2]).value='' + ourbrg;
document.getElementById(eles[2]).style.backgroundColor='lightgreen';
document.getElementById(eles[3]).style.backgroundColor='lightgreen';


if (interesting) {
document.getElementById('spfr').innerHTML='to';
document.getElementById('ipn').focus();
}

}
}
document.getElementById('ipn').placeholder=gllentry.split(',')[2].replace(/\;/g,',');
}
gllentry='';
document.getElementById('placegeo').value='';
}


Previous relevant Earth Bearing Distance Missing Two Trip Details Summary Tutorial is shown below.

Earth Bearing Distance Missing Two Trip Details Summary Tutorial

Earth Bearing Distance Missing Two Trip Details Summary Tutorial

The recent Earth Bearing Distance Missing Two Locality Distance Ring Tutorial coalesced “From” Place name functionality for …

  • defined bearing … deriving horizon place
  • defined distance … deriving ring of positions … and today we consider …
  • Trip functionality thoughts via “To” Place name definitions supplementing the already entered “From” Place name

We say “Trip Details Summary” in our blog posting title today as a hint about how we present a nester of Google Chart Map Chart display data.

The details/summary HTML element combination we often use to “reveal”, or not, webpage “real estate”, but today we default to the “open” look and add Wikipedia links and crowfly distance and Google Maps Directions information into the summary tag, for extra interest with your Trip planning.

The user can access this functionality with our changed missing_two.html‘s live run link …

  1. user enters “From” Place Name via new textbox … eg. “Lawson, New South Wales”
  2. user enters “To” Place Name via new textbox … eg. “Katoomba”
  3. user clicks/taps the “Fill” button
  4. optionally the user can add more places to the Map Chart by adding more “From” and/or “To” Place Name definitions


Previous relevant Earth Bearing Distance Missing Two Locality Distance Ring Tutorial is shown below.

Earth Bearing Distance Missing Two Locality Distance Ring Tutorial

Earth Bearing Distance Missing Two Locality Distance Ring Tutorial

The corollary to yesterday’s Earth Bearing Distance Missing Two Place Name and Horizon Tutorial‘s …

  • locality and bearing derivation of a “place on horizon” position … is, today …
  • locality and distance derivation of a “locality distance ring” set of positions

… again, combining the geodata talents of Wikipedia and a Google Chart Map Chart, we figure.

And so a user accessing this functionality with our changed missing_two.html‘s live run link …

  1. user enters “From” Place Name via new textbox … eg. “Lawson, New South Wales”
  2. user enters “Distance” (eg. “5000.000” metres) and tabs out … we use the “onblur” event …

    var dok=true;

    function dfillablemaybe(brgo) {
    if (!dok) { return ''; }
    var i, ourbrg=0.0, ourdist=0.0, j, dvlat='', dvlong='';
    if (('' + brgo.value).replace(/0/g,'').replace('.','') != '') {
    //alert('356:' + document.getElementById('dist').value);
    if (('' + document.getElementById('dist').value).replace(/0/g,'').replace('.','') == '' || (fplacen != '' && tplacen == '')) {
    //alert(456);
    if (('' + document.getElementById('latt').value).replace(/0/g,'').replace('.','') == '' || (fplacen != '' && tplacen == '')) {
    //alert(556);
    if (('' + document.getElementById('longt').value).replace(/0/g,'').replace('.','') == '' || (fplacen != '' && tplacen == '')) {
    //alert(656);
    if (('' + document.getElementById('ssf').innerHTML) != '') {
    //alert(756);
    if (!viastart) {
    //document.getElementById('brg').focus();
    document.getElementById('brg').value='0.0000001';
    //brgo.focus();
    }
    if (mu.indexOf('[051.5072,') != -1) {
    //alert(856);
    if (!viastart) {
    //alert(1);
    document.getElementById('ifill').click();
    //alert(11);
    }
    mu=mu.replace('[051.5072,','[' + eval('' + document.getElementById('latt').value).toFixed(3) + ',');
    mu=mu.replace(',-00.1275,',',' + eval('' + document.getElementById('longt').value).toFixed(3) + ',');
    if (('' + brgo.value).indexOf('000.000') != -1) {
    //mu=mu.replace(encodeURIComponent('looking out North'), encodeURIComponent(('' + brgo.value).split('000.000')[0] + 'km Ring'));
    mu=mu.replace(',~LonDon~]',',~' + encodeURIComponent(fplacen + ' looking North') + '~]');
    mu=mu.replace('=London','=' + encodeURIComponent(fplacen + (' ' + brgo.value).split('000.000')[0] + 'km Ring'));
    } else {
    mu=mu.replace(',~LonDon~]',',~' + encodeURIComponent(fplacen + ' looking North') + '~]');
    mu=mu.replace('=London','=' + encodeURIComponent(fplacen + ' looking out North'));
    }
    //mu=mu.replace(',~LonDon~]',',~' + encodeURIComponent(fplacen + ' looking North') + '~]');
    //mu=mu.replace('=London','=' + encodeURIComponent(fplacen + ' looking out North'));
    //alert('956:' + mu);
    //document.getElementById('hplacen').innerHTML='<input type=hidden name=fplacen value="' + mu + '"></input>';
    //document.getElementById('tdmid').innerHTML='<iframe src="' + mu + '" style="width:100%;height:700px;"></iframe>';
    if (viastart) {
    for (var dbrg=30; dbrg<=330; dbrg+=30) {
    //document.getElementById('brg').value='' + dbrg + '.0000000';

    if (('' + document.getElementById('mysel').value) == '2') {
    ourbrg=eval(eval(540.0 + 180.0 + eval('' + document.getElementById(eles[2]).value)) % 360.0);
    } else {
    ourbrg=eval('' + document.getElementById(eles[2]).value);
    }
    ourbrg=eval('' + dbrg);
    for (j=eval(3 - eval(('' + document.getElementById('mysel').value))); j>=1; j--) {
    ourdist=eval('' + document.getElementById(eles[3]).value);

    //Let first point latitude be la1,
    ///longitude as lo1,
    //d be distance,
    //R as radius of Earth,
    //Ad be the angular distance i.e d/R and.
    //θ be the bearing,

    //Here is the formula to find the second point, when first point, bearing and distance is known:

    //latitude of second point = la2 = asin(sin la1 * cos Ad + cos la1 * sin Ad * cos θ), and
    //longitude of second point = lo2 = lo1 + atan2(sin θ * sin Ad * cos la1 , cos Ad – sin la1 * sin la2)


    dvlat='' +
    eval(eval(eval(180.0 / Math.PI) * Math.asin(
    Math.sin(eval(Math.PI / 180.0) * eval('' + document.getElementById(eles[0]).value)) *
    Math.cos(eval(eval('' + ourdist) / 6371000.0)) +
    Math.cos(eval(Math.PI / 180.0) * eval('' + document.getElementById(eles[0]).value)) *
    Math.sin(eval(eval('' + ourdist) / 6371000.0)) *
    Math.cos(eval(Math.PI / 180.0) * eval('' + ourbrg)))));

    //Let first point latitude be la1,
    //longitude as lo1,
    //d be distance,
    //R as radius of Earth,
    //Ad be the angular distance i.e d/R and
    //θ be the bearing,
    // longitude of second point = lo2 = lo1 + atan2(sin θ * sin Ad * cos la1 , cos Ad – sin la1 * sin la2)

    dvlong='' + eval(eval(180.0 / Math.PI) * eval(eval(eval(Math.PI / 180.0) * eval('' + document.getElementById(eles[1]).value)) +
    Math.atan2(
    eval(eval('' + Math.sin(eval(Math.PI / 180.0) * eval('' + ourbrg)) *
    eval('' + Math.sin(eval(eval('' + ourdist) / 6371000.0)))) *
    eval('' + Math.cos(eval(Math.PI / 180.0) * eval('' + document.getElementById(eles[0]).value)))),
    eval(eval('' + Math.cos(eval(eval('' + ourdist) / 6371000.0))) -
    eval(eval('' + Math.sin(eval(Math.PI / 180.0) * eval('' + document.getElementById(eles[0]).value)))) *
    eval('' + Math.sin(eval(Math.PI / 180.0) * eval('' + document.getElementById(eles[4]).value)))))));
    mu+=',[' + eval('' + dvlat).toFixed(3) + ',' + eval('' + dvlong).toFixed(3) + ',~' + dbrg + '~]';


    }

    }
    document.getElementById('tdmid').innerHTML='<iframe src="' + mu + '" style="width:100%;height:700px;"></iframe>';
    fplacen='';
    }
    }

    }
    }
    }
    }
    }
    }

    … logic of that occurrence to say it is this scenario and above … so …
  3. set bearing to value “0.0000001” (ie. start the locality distance ring looking North)
  4. we programmatically click the yellow “Fill” button
  5. a Google Chart Map Chart is displayed with both …
    • observer position … and this approximate calculated …
    • locality distance ring set of positions at 30 degree intervals around the ring whose radius is the Distance value (in metres) entered by the user


Previous relevant Earth Bearing Distance Missing Two Place Name and Horizon Tutorial is shown below.

Earth Bearing Distance Missing Two Place Name and Horizon Tutorial

Earth Bearing Distance Missing Two Place Name and Horizon Tutorial

Yesterday’s Earth Bearing Distance Missing Two Place Name Tutorial left off with …

We hope so, and there is another reason for this preparatory work that will be explained tomorrow. Stay tuned!

Well, today’s “tomorrow”. Let me ask first, did you read our Compass iOS App Primer Tutorial? Well, the use of the Compass iOS (and am sure Android would have their own version of) mobile app fits into our scenario whereby …

  • we had occasion to be looking at a long distance view into the distance down a road both …
    1. during the day … and also seeing …
    2. lights at night

    … which set us (being of the “where are we” looking curious set) wondering …

  • where are we looking?
  • whipping out the iPhone’s Compass app gave us all of …
    1. bearing to distant view …
    2. elevation in metres … interesting …
    3. latitude, longitude of where we were (though we think we’ll get help from Wikipedia here, thanks)

    … meaning …

  • we could offer the user of our changed missing_two.html‘s live run link the chance to involve data items 1 and 2 above directly and 3 (via Wikipedia) … to have it that …
    1. user enters “From” Place Name via new textbox (and add the Compass app elevation (in metres) as a semicolon separated data item) … eg. “Lawson, New South Wales;740”
    2. user enters “Bearing” (eg. “185” (off the Compass app)) and tabs out … we use the “onblur” event …

      var dok=true;

      function fillablemaybe(brgo) {
      if (('' + brgo.value).replace(/0/g,'').replace('.','') != '') {
      //alert('356:' + document.getElementById('dist').value);
      if (('' + document.getElementById('dist').value).replace(/0/g,'').replace('.','') == '' || (fplacen != '' && tplacen == '')) {
      //alert(456);
      if (('' + document.getElementById('latt').value).replace(/0/g,'').replace('.','') == '' || (fplacen != '' && tplacen == '')) {
      //alert(556);
      if (('' + document.getElementById('longt').value).replace(/0/g,'').replace('.','') == '' || (fplacen != '' && tplacen == '')) {
      //alert(656);
      if (('' + document.getElementById('ssf').innerHTML) != '') {
      //alert(756);
      if (!viastart) {
      dok=false;
      document.getElementById('dist').focus();
      if (1 == 1) { // assume 2m elevation ... thanks to https://en.wikipedia.org/wiki/Horizon
      document.getElementById('dist').value='' + Math.floor(Math.pow(eval(eval(2.0 * eval('' + elev)) * 6371000.0), 0.5)) + '.000';
      } else {
      document.getElementById('dist').value='5000.000';
      }
      elev=2.0;
      brgo.focus();
      }
      if (mu.indexOf('[051.5072,') != -1) {
      //alert(856);
      if (!viastart) {
      document.getElementById('ifill').click();
      }
      mu=mu.replace('[051.5072,','[' + document.getElementById('latt').value + ',');
      mu=mu.replace(',-00.1275,',',' + document.getElementById('longt').value + ',');
      mu=mu.replace(',~LonDon~]',',~' + encodeURIComponent(fplacen + ' looking out at bearing ' + brgo.value + ' degrees towards horizon') + '~]');
      mu=mu.replace('=London','=' + encodeURIComponent(fplacen + ' looking out at bearing ' + brgo.value + ' degrees towards horizon'));
      //alert('956:' + mu);
      //document.getElementById('hplacen').innerHTML='<input type=hidden name=fplacen value="' + mu + '"></input>';
      document.getElementById('tdmid').innerHTML='<iframe src="' + mu + '" style="width:100%;height:700px;"></iframe>';
      if (viastart) {
      fplacen='';
      }
      }
      }
      }
      }
      }
      }
      }

      … logic of that occurrence to say it is this scenario and above … so compute …
    3. the distance to horizon is computed via square root of two times elevation (in meters) times radius of earth (in meters) … then …
    4. we programmatically click the yellow “Fill” button
    5. a Google Chart Map Chart is displayed with both …
      1. observer position … and this approximate calculated …
      2. horizon position

      … to help you un-nut “where are we looking?… we hope

… which you can see the gist of with today’s animated GIF presentation.

Bit like relaxed orienteering, would you say?!


Previous relevant Earth Bearing Distance Missing Two Place Name Tutorial is shown below.

Earth Bearing Distance Missing Two Place Name Tutorial

Earth Bearing Distance Missing Two Place Name Tutorial

It’s often a good news story in I.T. when you can replace or supplement numbers with names (without being too nosy about it, that is!) And so, extending the functionality of our “Missing Two” web application talked about, last, with Earth Bearing Distance Missing Two Trip Share Tutorial we allow the user to enter in Place Names as an alternative to entering in the Latitude and Longitude co-ordinates of that place’s position on the earth, especially apt for any web application purporting to be helpful regarding “trip” functionality.

Being suckers for “the where of life” web applications out there, we’re tickled pink to be offering this “red zone” special extension to functionality, and all because you asked for it (well, that’s my story, and am sticking with it).

As we went along coding for this change, and implications of this into the future, we realized we needed to allow for two more (GET argument) data items to be catered for, the codelines below responsible for “reading them in” …


var fplacen=location.search.split('fplacen=')[1] ? (' ' + decodeURIComponent(location.search.split('fplacen=')[1].split('&')[0]).replace(/\+/g,' ')) : '';
var tplacen=location.search.split('tplacen=')[1] ? (' ' + decodeURIComponent(location.search.split('tplacen=')[1].split('&')[0]).replace(/\+/g,' ')) : '';

… and allowed for within the (static) HTML’s form element‘s HTML as per …


<h1 id=myh1 style='display:block;'>Missing Two (<font size=1>optional</font> <span id=spfr>from</span> <input onblur='lkwk(this);' style='display:inline-block;' placeholder='Place Name' id=ipn value='' type=text></input>) in a Table Column <span data-onfocus="document.getElementById('semail').innerHTML='';" data-title='Email to (append a space to just show the table cell with the gradient)?' data-contenteditable=true data-onblur=preemail(this.innerHTML); onclick=emailit(''); id=semail title=Email>&#128231;</span> <span data-onfocus="document.getElementById('semail').innerHTML='';" data-title='SMS to?' data-contenteditable=true data-onblur=preemail(this.innerHTML); onclick=toize(''); id=ssms title=SMS>&#128223;</span></h1>

… and …


<tr id=trhead style='display:table-row;'><th style='width:30%;text-align:left;background-color:#f0e0d0;'><a title='Show nearest TimeZone places' id=afrom onclick=mapit(this); style='cursor:pointer;text-decoration:underline;'>From</a><span id=ssf></span>> <div id=dfrom style='display:none;'></div></th><th style='width:30%;text-align:left;background-color:#e0d0f0;'> ... On The Way ...</th><th style='text-align:left;background-color:#d0f0e0;'><a title='Show nearest TimeZone places' id=ato onclick=mapit(this); style='cursor:pointer;text-decoration:underline;'>To</a><span id=sst></span> <div id=dto style='display:none;'></div></th></tr>

… and populated via supportive “onload” event based Javascript DOMWikipedia (thanks) based” logic as per …


if (fplacen != '') {
document.getElementById('ssf').innerHTML=fplacen;
fplacen='';
}
if (tplacen != '') {
document.getElementById('sst').innerHTML=tplacen;
tplacen='';
}

… as the incoming code paradigm, living with the outgoing paradigm’s work based on that “lkwk(this);” Javascript function …


var gllentry='';

function askit() {
//alert(gllentry);
if (gllentry.indexOf(',') != -1) {
if (gllonesuffix == 'f') {
document.getElementById('latf').focus();
document.getElementById('latf').value=gllentry.split(',')[0];
document.getElementById('longf').focus();
document.getElementById('longf').value=gllentry.split(',')[1];
document.getElementById('latf').focus();
gllonesuffix = 't';
document.getElementById('spfr').innerHTML=document.getElementById('spfr').innerHTML.replace('from','to<input type=hidden name=fplacen value="' + gllentry.split(',')[2].replace(/\;/g,',') + '"></input>');
document.getElementById('ssf').innerHTML=' ' + gllentry.split(',')[2].replace(/\;/g,',');
} else {
document.getElementById('brg').focus();
document.getElementById('dist').focus();
document.getElementById('latt').focus();

document.getElementById('latt').value=gllentry.split(',')[0];
document.getElementById('longt').focus();
document.getElementById('longt').value=gllentry.split(',')[1];
document.getElementById('latt').focus();
gllonesuffix = 'f';
document.getElementById('spfr').innerHTML=document.getElementById('spfr').innerHTML.replace('to','from<input type=hidden name=tplacen value="' + gllentry.split(',')[2].replace(/\;/g,',') + '"></input>');
document.getElementById('sst').innerHTML=' ' + gllentry.split(',')[2].replace(/\;/g,',');
}
document.getElementById('ipn').placeholder=gllentry.split(',')[2].replace(/\;/g,',');
}
gllentry='';
document.getElementById('placegeo').value='';
}

function lookforg() {
if (document.getElementById('placegeo').value != '') {
gllentry=document.getElementById('placegeo').value + ',' + decodeURIComponent(document.getElementById('ifplacegeo').src.split('?placegeo=')[1]).replace(/\,/g,';');
askit();
} else {
setTimeout(lookforg,1000);
}
}

function checkit(iois) {
if (iois != null) {
if (iois.src.indexOf('?placegeo=') != -1) {
//alert(1);
var aconto = (iois.contentWindow || iois.contentDocument);
//alert(11);
if (aconto != null) {
//alert(111);
if (aconto.document) { aconto = aconto.document; }
//alert(1111);
if (aconto.body != null) {
//alert(2);
document.body.style.cursor='pointer';
if (document.getElementById('placegeo').value != '') {
//alert(3);
gllentry=document.getElementById('placegeo').value + ',' + decodeURIComponent(iois.src.split('?placegeo=')[1]).replace(/\,/g,';');
askit();
} else {
//alert(8);
setTimeout(lookforg,1000);
}
}
}
}
}
}


function lkwk(oiis) {
if (oiis.value.trim() != '') {
document.getElementById('ifplacegeo').src=document.getElementById('ifplacegeo').src.split('?')[0].split('#')[0] + '?placegeo=' + encodeURIComponent(oiis.value);
oiis.value='';
document.body.style.cursor='progress';
}

}

… supporting the relevant (new static) HTML …


<iframe onload='checkit(this);' style='display:none;' id=ifplacegeo src='../PHP/fgc/index.php'></iframe>
<input type=hidden id=placegeo value=''></input>

Believe it or not, with this web application, it is important what input type=text textboxes are “visited”, and up until today, we had no concerns with that “ordering” issue very much, because we only coded for “real user” interactive input, but today’s place name functionality modifications mean that we feel we need to programmatically force the order somewhat in these place name entry scenarios, but we were not sure whether our non-mobile only (and slightly kludgy feeling) [input type=text element].focus(); interventions would/could work. But they did, happily, at least for non-mobile platforms! This means input type=text element “onblur” events must have been triggered, we figure, which is an interesting finding (well, you had to be there, didn’t you?!)

Perhaps, then, the changed missing_two.html‘s live run link will spark your interest? We hope so, and there is another reason for this preparatory work that will be explained tomorrow. Stay tuned!


Previous relevant Earth Bearing Distance Missing Two Trip Share Tutorial is shown below.

Earth Bearing Distance Missing Two Trip Share Tutorial

Earth Bearing Distance Missing Two Trip Share Tutorial

When Ajax came on the scene, HTML form navigation got that bit daggier. But as time has gone on, we’ve started appreciating those more traditional HTML form navigation methodologies more for a few major reasons …

  1. the FormData in the Ajax/FormData combination of navigational methodologies simulates static HTML form element functionality
  2. we’ve grown to really admire “Inline HTML Email” sharing via PHP mail to the email and back again out to the “www” wooooorrrrrlllllddd via an “Inline HTML Email Form” (as widens the scope of use for today’s web application)
  3. we’ve grown to really admire a static HTML form element’s “onsubmit” event to massage an HTML form element’s content on the way through to accepting the “action” form navigational destination, or reject that
  4. we’ve grown to really admire the concept of multiple submit button elements without or with an associated name attribute to be able to detect which submit button was clicked/touched

… and it seems to me there are now in the web application wooooorrrrrllllddd a plethora of navigational functionality choices for programmers out there. Yayyyyy!

And so, onto Earth Bearing Distance Missing Two Trip Tutorial today we add two sharing conduit …

  • email
  • SMS

… means of functionality which call on …


function preemailit(ine) {
if (ine.indexOf('@') != -1) {
emailit(ine);
} else if (ine != '') {
toize(ine);
}
}

function dummyencodeURIComponent(invl) {
return invl;
}

function emailit(defe) {
//document.getElementById('ih').value=document.getElementById('tdlook').innerHTML.replace(/\<br\>/g,String.fromCharCode(10));
var lastfis='youllneverfindthis';
var lasttis='';
var lasteis='youllneverfindthis';
var lastenow='';
var lastsis='youllneverfindthis';
var lastsnow='';
var lasteis2='youllneverfindthis';
var lastenow2='';
var lastsis2='youllneverfindthis';
var lastsnow2='';
var em='';
var suffbits='?latf=' + encodeURIComponent(document.getElementById('latf').value) + '&longf=' + encodeURIComponent(document.getElementById('longf').value) + '&latt=' + encodeURIComponent(document.getElementById('latt').value) + '&longt=' + encodeURIComponent(document.getElementById('longt').value) + '&brg=' + encodeURIComponent(document.getElementById('brg').value) + '&dist=' + encodeURIComponent(document.getElementById('dist').value);
if (defe.indexOf('@') != -1) {
em=defe
} else {
em=prompt('Email to? (all uppercase uses client email else sends an Inline HTML Email Form)', '');
}
if (em == null) { em=''; }
if (em.indexOf('@') != -1) {
//document.getElementById('from').value=em;
if (document.URL.toLowerCase().indexOf('rjmprogramming.com.au') != -1 && em != em.toUpperCase()) {
var xzhr = new XMLHttpRequest();
var xform=new FormData();
xform.append('inline','');
xform.append('to',em.trim());
var flatf=document.getElementById('latf').outerHTML;
var flongf=document.getElementById('longf').outerHTML;
var flatt=document.getElementById('latt').outerHTML;
var flongt=document.getElementById('longt').outerHTML;
var fbrg=document.getElementById('brg').outerHTML;
var fdist=document.getElementById('dist').outerHTML;
var tlatf='<input type=text name=latf id=latf value="' + document.getElementById('latf').value + '"></input>';
var tlongf='<input type=text name=longf id=longf value="' + document.getElementById('longf').value + '"></input>';
var tlatt='<input type=text name=latt id=latt value="' + document.getElementById('latt').value + '"></input>';
var tlongt='<input type=text name=longt id=longt value="' + document.getElementById('longt').value + '"></input>';
var tbrg='<input type=text name=brg id=brg value="' + document.getElementById('brg').value + '"></input>';
var tdist='<input type=text name=dist id=dist value="' + document.getElementById('dist').value + '"></input>';
//if (from.indexOf('@') != -1) { xform.append('cc',from.trim()); }
console.log('tdfrom');
faux=true;
mapit(document.getElementById('tdfrom'));
console.log(document.getElementById('afrom').href);
console.log('tdto');
faux=true;
mapit(document.getElementById('tdto'));
console.log(document.getElementById('ato').href);
if (document.body.innerHTML.indexOf('<tr id="trfoot"') != -1) {
lastfis='<tr id="trfoot"' + document.body.innerHTML.split('<tr id="trfoot"')[1].split('</tr>')[0] + '</tr>';
if (document.getElementById('asms').href.indexOf('sms:') != -1) {
lasteis='<span ';
lastenow='<a target=_blank href="mailto:?subject=' + dummyencodeURIComponent(encodeURIComponent('Missing%20Two')) + '&body=' + dummyencodeURIComponent(encodeURIComponent(document.getElementById('asms').href.split('&body=')[1])) + '" ';
lasteis2='</span>';
lastenow2='</a>';
lastsis='<span ';
lastsnow='<a target=_blank href="' + document.getElementById('asms').href.split('&')[0] + '&body=' + dummyencodeURIComponent(encodeURIComponent(document.getElementById('asms').href.split('&body=')[1])) + '" ';
lastsis2='</span>';
lastsnow2='</a>';
} else if (document.getElementById('asms').href.indexOf('mailto:') != -1) {
lastsis='<span ';
lastsis=document.getElementById('ssms').outerHTML.split('>')[0] + '>';
lastsnow='<a target=_blank href="sms:&body=' + dummyencodeURIComponent(encodeURIComponent(document.getElementById('asms').href.split('&body=')[1])) + '" ';
lastsnow='<input type=submit title=SMS name=sms id=ssms value="';
lastsis2='</span>';
lastsnow2='</a>';
lastsnow2='"></input>';
lasteis='<span ';
lastenow='<a target=_blank href="mailto:' + em.trim() + '?subject=' + dummyencodeURIComponent(encodeURIComponent('Missing%20Two')) + '&body=' + dummyencodeURIComponent(encodeURIComponent(document.getElementById('asms').href.split('&body=')[1])) + '" ';
lasteis2='</span>';
lastenow2='</a>';
}
}
if (em.trim() != em) {
xform.append('subj','Missing Two');
//var cbgtd=document.getElementById('tdlook').getBoundingClientRect();
xform.append('body','<body>' + document.body.innerHTML.replace(/\ id\=\"mysel\"/g, ' name="mysel" id="mysel"').replace(/\ size\=\"3\"/g, ' size="4"').replace(/\ data\-href\=/g, ' target=_blank href=').replace('</form>', '<br><br><input style=background-color:lightgreen; type=submit value=Solve></input></form>').replace('DISPLAY:table-row','DISPLAY:none').replace(lastfis,lasttis).replace(lasteis,lastenow).replace(lasteis2,lastenow2).replace(lastsis,lastsnow).replace(lastsis2,lastsnow2).replace('absolute;','absolute;display:none;').replace(flatf,tlatf).replace(flongf,tlongf).replace(flatt,tlatt).replace(flongt,tlongt).replace(fbrg,tbrg).replace(fdist,tdist) + '</body>');
} else {
xform.append('subj','Missing Two');
xform.append('body','<body>' + document.body.innerHTML.replace(/\ id\=\"mysel\"/g, ' name="mysel" id="mysel"').replace(/\ size\=\"3\"/g, ' size="4"').replace(/\ data\-href\=/g, ' target=_blank href=').replace('</form>', '<br><br><input style=background-color:lightgreen; type=submit value=Solve></input></form>').replace('DISPLAY:table-row','DISPLAY:none').replace(lastfis,lasttis).replace(lasteis,lastenow).replace(lasteis2,lastenow2).replace(lastsis,lastsnow).replace(lastsis2,lastsnow2).replace('absolute;','absolute;display:none;').replace(flatf,tlatf).replace(flongf,tlongf).replace(flatt,tlatt).replace(flongt,tlongt).replace(fbrg,tbrg).replace(fdist,tdist) + '</body>');
}
xzhr.open('post','//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php',true);
xzhr.send(xform);
} else {
document.getElementById('asms').href='mailto:' + em.trim() + '?subject=' + encodeURIComponent('Missing Two') + '&body=' + encodeURIComponent(document.URL.split('#')[0].split('?')[0] + suffbits); // + '?missingtwo=' + encodeURIComponent(encodeURIComponent(document.getElementById('dfix').innerHTML.replace('background: ','').replace('background:','').replace(');',')').replace(';',''))));
document.getElementById('asms').click();
}
}
}

… in the changed missing_two.html‘s live run link.


Previous relevant Earth Bearing Distance Missing Two Trip Tutorial is shown below.

Earth Bearing Distance Missing Two Trip Tutorial

Earth Bearing Distance Missing Two Trip Tutorial

If we were to nominate an “onions of the 4th dimension” improvement on top of the work of Earth Bearing Distance Missing Two Context Tutorial we’d nominate … anyone, anyone … yes, tenticle 5 of The Kraken … we’d want to allow our “Missing Two Geographical places via Bearing and Distance” web application be turned into a trip planner by allowing for multiple legs, perhaps of a trip, to be “represented” by our new incarnation of the web application. As per usual, with extensions of functionality, here, it is optional, and manifested by … anyone, anyone … yes, tenticle 9 3/4 of The Kraken … turning a hardcoded piece of (webpage) text into an HTML element with action logic behind it … our TAHPOWTIAHEWALBI moment, you could say?!

Seriously though, it is rare that a sizeable trip happens as a one leg with the one bearing and distance component, so we turn our old web application into a …

… type of web application, in order to do that other thing we like to do, and that is to have the one (in this case just HTML/Javascript/CSS) codeset handle both simple and (optional) complex usage functionalities.

How do we differentiate a “top.document” parent from an (HTML) iframe (element) child? We use …

  • address bar URL ? and & argument (?latf=[previousToLatitude]&longf=[previousToLongitude]) usage (and analysis) via … checked for via
  • <body onload=’moremaybe();’>

  • function moremaybe() {
    var latto=location.search.split('latf=')[1] ? decodeURIComponent(location.search.split('latf=')[1].split('&')[0]) : '';
    var longto=location.search.split('longf=')[1] ? decodeURIComponent(location.search.split('longf=')[1].split('&')[0]) : '';
    if (latto != '' && longto != '') {
    nextplease();
    top.document.getElementById('goagain').style.display='block';
    document.getElementById('latf').value=latto;
    document.getElementById('latf').style.backgroundColor="pink";
    cwhat[0]=false;
    cwhat[1]=false;
    if (!decided) {
    if (!cwhat[5]) {
    cwhat[5]=true;
    }
    if (!cwhat[4]) {
    cwhat[4]=true;
    }
    decided=true;
    }
    top.document.getElementById("ltf").value=latto;
    document.getElementById('longf').value=longto;
    document.getElementById('longf').style.backgroundColor="pink";
    cwhat[0]=false;
    cwhat[1]=false;
    if (!decided) {
    if (!cwhat[5]) {
    cwhat[5]=true;
    }
    if (!cwhat[4]) {
    cwhat[4]=true;
    }
    decided=true;
    }
    top.document.getElementById("lgf").value=longto;
    document.getElementById('dtop').style.display='none';
    document.getElementById('trhead').style.display='none';
    document.getElementById('trfoot').style.display='none';
    document.getElementById('myt').border=0;
    var recti=parent.document.getElementById('niframe').getBoundingClientRect();
    parent.document.getElementById('niframe').height=eval(200 + eval(('' + recti.height).replace('px',''))) + 'px';
    if (parent.document.getElementById('niframe') != top.document.getElementById('niframe')) {
    var trecti=top.document.getElementById('niframe').getBoundingClientRect();
    top.document.getElementById('niframe').height=eval(200 + eval(('' + trecti.height).replace('px',''))) + 'px';
    }
    setTimeout(checkfill, 500);
    parent.document.getElementById("slong").innerHTML=":";
    parent.document.getElementById("slong").title="";
    parent.document.getElementById("slong").style.textDecoration="none";
    //top.document.title+=' started ';
    }
    }

… where you can see that “top.document” (top) parent is just that … top.document … and that a parent of an (HTML) iframe (element) trip leg is referred to via … parent.document … and what is being done in the here and now of a simple scenario (just in the (top) parent) or a complex (non (top) parent leg) … document … references come into play. That parent.document.getElementById(“slong”) refers to the dynamically changed method of adding legs, by turning the …

  • hardcoded “:” (text) of the To longitude textbox labelling … into a clickable and onclick event working …

  • document.getElementById('slong').style.cursor='pointer';
    document.getElementById('slong').style.textDecoration='underline';
    document.getElementById('slong').title='Click for another leg of a trip, perhaps?';
    document.getElementById('slong').innerHTML='+';

    … optionally used, and dynamic extension to functionality … our “onions of the 4th dimension” moment … who said we don’t care about your health here?!

… so that top.document.getElementById(‘niframe’) is the representation of that “top.document” parent’s first (HTML) iframe (element) child.

Why ask that previous question? To have the one codebase service all the scenarios, we need (the code) to know “where it is at”, so to speak.

The changed missing_two.html‘s live run link can have you planning your own “where of life” trip itinerary of interest yourself.


Previous relevant Earth Bearing Distance Missing Two Context Tutorial is shown below.

Earth Bearing Distance Missing Two Context Tutorial

Earth Bearing Distance Missing Two Context Tutorial

Mapping and navigational apps wouldn’t be as popular as they are without …

  • satellite based geodata available to our mobile and laptop (and cars etcetera) devices and their software … and …
  • the human urge to want to know where they are

… and so to leave yesterday’s Earth Bearing Distance Missing Two Primer Tutorial “proof of concept” web application the way it was, not showing much context to the latitude and longitude form “asks” would be a missed opportunity.

In this sense, we’ve decided to interface this web application to …

… to give the changed missing_two.html‘s live run link that optional map (or visual) extra context. This is accessible off links applied to the previously hardcoded “From” and “To” table headers. Please feel free to give it a go to see what we mean.


Previous relevant Earth Bearing Distance Missing Two Primer Tutorial is shown below.

Earth Bearing Distance Missing Two Primer Tutorial

Earth Bearing Distance Missing Two Primer Tutorial

Get in a conversation with a Land Surveyor, and drop in your sentence, close to each other, the words “bearing” and “distance” and in all likelihood you’ll get a smile. Is it a curved smile? Maybe, they are interested in the geodesic aspects to these two terms. You see, the rules of Euclidean geometry are all fine and good and used by Land Surveyors for small distances involving local mapping or small area mapping, where the curvature of the Earth is not really a factor. In fact, in the early days of Land Surveying, the plotting of an area might have been done using a table resting on a tripod, which hopefully made that table level (all good terrestrial surveying wants you to be perpendicular to the imaginary plumb bob hanging from your instrument, and hanging down in accordance with gravity’s laws). Geodesic interest for Land Surveyors tries to take into account the curvature of the Earth, which we’ll assume for today, is a sphere, though in reality it takes on a spheroidal shape that is not quite a sphere.

Polar co-ordinate designations are an alternative “view” to placing yourself, as distinct from grid co-ordinates, or geographical latitude and longitude.

We talked about some of what we have written a proof of concept web application for today with the PHP Google Map Chart Bearing Distance Tutorial some time back, and revisited its excellent …

very useful link that talks about the Haversine distance formula, as well

… and rereading this excellent webpage, realized that two sets of formulae there (plus the great circle distance calculations before) could help us piece together a useful navigational web application that, out of …

From Latitude, Longitude Bearing, Distance To Latitude, Longitude

… we could get the user to fill out 2 of 3 columns of information above, and calculate the missing one for them.

How is this useful? Well, sometimes you want to know …

  • We are at X. We are crow flying to Y. In which direction do we set out? How far is it?
  • We are at X. That looks like a nice direction to head, so what compass reading is that? If I go however far, where do I end up?

Second one for those dreamers and adventurers (or perhaps, orienteerers) methinks. Anyway, feel free to try the HTML and Javascript ‘s live run link, or down below …


Previous relevant PHP Google Map Chart Bearing Distance Tutorial is shown below.

PHP Google Map Chart Bearing Distance Tutorial

PHP Google Map Chart Bearing Distance Tutorial

There have been three recent things going on, for us, involving software integration of our interface to the great Google Chart Map Chart

As a worker with a background in Land Surveying, of course, the words “bearing” and “distance” were part of the “bread and butter” of this job. The modern day equipment can, at the observer’s tripod, and given the chainperson’s placement of equipment, deal with both of these “measures” at once, but you can still use the old theodolites and distance measuring chains if you like. You take your measurements and use calculations like those underlying the workings of the web application of HTML and Javascript and CSS Survey Traverse Tutorial which are all fine and dandy if the distances are relatively small, because we can think “planar geometry” as we mostly learn at school. But if the measurements involve long enough distances, you need to take into account that Earth is, basically, round … meanwhile, on the phone ….

You don’t say. You don’t say. You don’t say.

“What’d they say?” …

They didn’t say.

When distances are this large we need to turn towards “geodesic calculations” and today …

Here are some “live runs” …

… and here’s the changed PHP map.php changed in this way.


Previous relevant PHP Wikipedia Australian List Integration Tutorial is shown below.

PHP Wikipedia Australian List Integration Tutorial

PHP Wikipedia Australian List Integration Tutorial

Yesterday’s PHP Wikipedia Australian List Makeover Tutorial got us thinking more about “where of life” functionality integration possibilities.

For us, with many “where of life” web applications, the Google Charts Map Chart is a core part of the functionality, as the receptacle, and more and more often as time goes on, also a launching pad out to other concepts, such as …

  • TimeZone … and …
  • Weather

… two of the concepts hovering about our “Other Side of the World” web application we last talked about with Other Side of the World Google Chart Tutorial, whose supervisory HTML other_side_of_the_world.htm‘s live run, changed in this way to tweak the the linking of …

  • latitude and longitude and (anywhere) placename … to …
  • TimeZone place(s) … and then (with great help from Weather Underground (thanks)) onto …
  • direct or nearby weather predictions

… coming off a new Map Chart Google Chart and its select event menu option

  • Nearest TimeZone=Z (and onto Other Side of the World and Weather)
  • YouTube=Y (looking for placename)

… the latter integrating us with YouTube API for Iframe embedded videos interface HTML/Javascript “parent” web application called karaoke_youtube_api.htm HTML iframe elements in another direction additional to yesterday’s usage. Along the way, we tweak the Google Map=G menu option, adding more map type options and zooming in a little less by default, and with the Nearby Airports=A option making the default be a search for 3 (rather than 4) nearby airports. A lot of this all happens because of the changes to

… which all got changed to allow for an “Animate” feature, allowing for an automated right to left “animation” (via hashtagging) of the Wikipedia based slides near the top of this suite of web application’s webpages. We hope you get to try all this out for yourself.


Previous relevant PHP Wikipedia Australian List Makeover Tutorial is shown below.

PHP Wikipedia Australian List Makeover Tutorial

PHP Wikipedia Australian List Makeover Tutorial

Some time back we linked a Wikipedia “list” webpage to the Google Charts Map Chart functionality with PHP Modularization for Lighthouses in Australia Tutorial.

We’re revisiting, and finding some “peer” web applications, linked by a dropdown, that all …

  • access a relevant Wikipedia “list” webpage for Australian “things” and mentioning latitude and longitude … which link to …
  • Google Charts Map Chart

… for all of …

We were inspired to take on this “makeover” of “where of life” functionalities because earlier on today we discovered a stupendous online resource for Australian geography enthusiasts, the Bonzle Digital Atlas of Australia, with incredibly detailed and flexible search mechanisms, thanks heaps!

We’ve decided to include extra buttons (to those already linking to Google Maps links and to the relevant Wikipedia webpage) for that suite of web applications above for …

Great for research and “surfing the Australian world”! Lose yourself!

What happened Javascript (australian_lighthouses.js changed this way) and PHP wise?


Previous relevant PHP Modularization for Lighthouses in Australia Tutorial is shown below.

PHP Modularization for Lighthouses in Australia Tutorial

PHP Modularization for Lighthouses in Australia Tutorial

Today we want to try two more things …

  1. continuing on with our PHP code (you could call australian_lighthouses.php) for our Australian Lighthouses project
  2. talk about PHP glob and its modularization sensibilities

… so let’s talk about the second one first … it’s south of north … chortle, chortle.

What does PHP’s glob do? It is doing functionality like the “underworkings” of any browse button you would see would do when you have a hard disk (in your life) … unfortunately, this is no longer a given (with mobile technology and the “cloud” challenging this thinking, sometimes). Give glob a file specification and a directory to start with, and it will happily (if you were both “globular” and “modular” you would be, too) provide you with a list of filenames, so that we use it to construct this PHP function for use with our lighthouses web application …


function selcreate($def) {
$ret=$def;
$selstr='<select onchange=" window.location=this.value; "><option value="' . str_replace(" ", "_", strtolower($def)) . '_lighthouses.php">' . $def . '</option>';
$cnt=0;
foreach (glob("*_lighthouses.php") as $filename) {
if (strpos(($filename . "*"), (str_replace(" ", "_", strtolower($def)) . '_lighthouses.php*')) === false) {
$cnt++;
$newidea=str_replace("_", " ", str_replace("_lighthouses.php", "", strtolower($filename)));
$newideas=explode(" ", $newidea);
$ideas=strtoupper(substr($newideas[0],0,1)) . strtolower(substr($newideas[0],1));
for ($ii=1; $ii<sizeof($newideas); $ii++) {
$ideas.=(" " . strtoupper(substr($newideas[$ii],0,1)) . strtolower(substr($newideas[$ii],1)));
}
$selstr.='<option value="' . $filename . '">' . $ideas . '</option>';
}
}
if ($cnt > 0) return $selstr . "</select>";
return $ret;
}

… and hope you can see that glob could be used for PHP code to self-detect sibling variation programs, so that, for instance, if we “plonked” (ie. eg. (s)ftp it) an egypt_lighthouses.php (probably with an egypt_lighthouses.js accompanying Javascript file) into the same directory as our …

… it would automatically be added into the functionality of its siblings without you having to change any code of those siblings … and that egypt_lighthouses.php is free to be a web application with a totally different method of functionality … cute, huh?!

As a matter of fact ireland_lighthouses.php is quite different, and if you examine the code, you will see that the Javascript putElement(s)By via PHP Relative URLs Tutorial is more apt to a discussion of its workings.

You see, there are so many many different ways to “skin a cat” in Information Technology, quite often … not always … but “quite often” … and why be cornered into thinking there is only one way to do things?

The other thing you’ll find is that even though ireland_lighthouses.php differs a lot to its nearest matching sibling (in terms of methodology), new_zealand_lighthouses.php the Javascript corresponding codesets called ireland_lighthouses.js and new_zealand_lighthouses.js are only superficially different … in other words our PHP coalesces concepts into a similar “client” look … a “modularization” of sorts … not everybody’s sort, but a sort none the less … and this begs a question?

Why is “modularization” a good thing? Well, to me, you don’t have to have any “modularization” going on at all, and this is fine by me, but you must deal with issues that allow you to modify many many codesets efficiently and accurately in vastly different ways to be efficient, or be “modular” and be able to, perhaps, even, automate your changes, because of these “modular” patterns you’ve created … many people find “modularization” blissful … and often it suits the work patterns for teams of programmers. Perhaps you want to read about MVC (and its like) as a coding modularization idea for PHP (or many other programming languages, for that matter).


Previous releveant PHP/Javascript Asynchronous Lighthouses in Australia Tutorial is shown below.

PHP/Javascript Asynchronous Lighthouses in Australia Tutorial

PHP/Javascript Asynchronous Lighthouses in Australia Tutorial

Today we want to try two things …

  1. continuing on with our PHP code (you could call australian_lighthouses.php) for our Australian Lighthouses project
  2. talk about Javascript asynchronous script tag option

… so let’s talk about the second one first … it’s south … chortle, chortle.

Why should you be interested in the HTML’s script tag attributes …

  • asynch=”asynch”
  • defer=”defer”

? Well, we want our web pages to load as fast as possible. Yaaaaaa?! So if there was the mechanism to do more than one bit of ((client) Javascript) thinking at a time would you avail yourself of the opportunity … or would you pick what’s behind door 3?

Do you want to hear more on this theory wise? It seems to me, there are web application mission critical parts, and there are embellishments, quite often … “nice to haves” but not “mission critical” … well, if those “nice to haves” could be arranged not to hog all the web application designated CPU that would be good, wouldn’t it?! Yaaaaaaaaaaa?!

So, that, in theory, is y why.

Now back to the project at hand … Australian Lighthouses … don’t you think some geographical sorting options and place name sorting options might be useful? Yaaaaaaaaaaaaaaaaa?! But for us it doesn’t feel mission critical … so we …

  • place the logic in some external Javascript called australian_lighthouses.js
  • we load it from the PHP via
    <script type=”text/javascript” src=”australian_lighthouses.js” async=”async”></script>

    … and this amounts to the only change to today’s PHP code from yesterday as per this link

… and this becomes a way to modularize your thinking regarding a project … please don’t think there are not a myriad of other ways … this is just one idea here.

With regard to how we approached our external Javascript we did not demand anything (much) of our parent PHP and this may not be the fastest way to approach this. What we mean by that is that, perhaps, as a general rule, external Javascript can perform faster with the parent PHP or HTML leaving it with a lot more HTML element id=”[elementId]” to hang its hats on, so to speak … instead, here, we acted innocently with our Javascript and used lots of calls to the Javascript DOM method getElementsByTagName() (which results in an array return value). Perhaps calls to getElementById() via (parent) arranged id=”[elementId]” would be faster?! Today, as with the previous Static HTML Javascript Primer Tutorial we concentrated on the “modular” feel to additional external Javascript code ideas.

So try a live run to see what we mean.


Previous relevant PHP Lighthouses in Australia Primer Tutorial is shown below.

PHP Lighthouses in Australia Primer Tutorial

PHP Lighthouses in Australia Primer Tutorial

Today we examine some of the methodology behind a project idea.

Projects need …

  • an idea … ours came from listening to the radio and hearing about Lighthouses, and how the technologies had changed what they look like and how they function these days … to quote Wikipedia with respect to Australian Lighthouses (thanks) …

    The first lighthouse was Macquarie Lighthouse, which was lit in 1793 as a tripod mounted wood and coal fired beacon. The last manned lighthouse was Maatsuyker Island Lighthouse, off the south coast of Tasmania, which was automated in 1996.

  • a means to access information … much easier these days with the search engines … we went with a Google Search as per list of lighthouse positions … which led to …
  • the information source(s) … we settled, and were not surprised about the source, for Wikipedia’s List of lighthouses and lightvessels in Australia – Wikipedia … then, once happy about the quality of the source information, analyzed …
  • the source data format … initially, at least, via View->Page Source, relative to the webpage … to get ideas for how to parse the data … so that we can determine a …
  • programming language of choice … which is PHP … no surprise here … will need a server-side language … and a method like PHP’s file_get_contents() … from there …
  • PHP coding to parse the data and put it into another format that value adds … otherwise why do it, as the Wikipedia information is fine as is … that is where we determine that we should …
  • include an iframe that uses the Google Chart Map Chart to add that extra overall positional view of Lighthouses … a definite asset to the reader’s understanding of the subject … definitely a “where” web application … and in doing this we notice that …
  • Google Chart Map Chart map.php web application needed to be able to handle much larger input data streams than it could in its previous incarnation of only allowing PHP $_GET[] parameters … so we change it to allow $_POST[] parameters … maybe you noticed this with yesterday’s PHP/Javascript/HTML Google Chart Map Onclick Tutorial as shown below … as this meant that …
  • we need an HTML form that POSTs to the iframe with the Google Chart Map Chart map.php web application allowable because we are on the same domain with this thinking … and using an HTML textarea element to store the huge string of Lighthouse data that will be passed across via urldecode($_POST[‘data’]) at map.php … using PHP’s urldecode() and urlencode() methods and Javascript’s decodeURIComponent() method … as well as utilizing …
  • Google Chart Map Chart map.php web application onclick and tooltip functionality we’ve been working on lately … hence the talk about this below … working out what (component) tools could do with a “makeover” is an extremely important part of any project and can be a useful compartmentalizing of the project

… and so we end up with our live run behind which is the PHP programming source code you could call australian_lighthouses.php for your perusal.


Previous relevant PHP/Javascript/HTML Google Chart Map Onclick Tutorial is shown below.

PHP/Javascript/HTML Google Chart Map Onclick Tutorial

PHP/Javascript/HTML Google Chart Map Onclick Tutorial

They say “the knee bone’s connected to the thigh bone” then they say “the thigh bone’s connected to the … hip bone” then they say “let’s call the whole thing off” … sometimes.

Today we say “the onmouseover event is connected to the onclick event” then we say “the onclick event is connected to the online woooooorld” … “do … the hokey pokey” x3 … “that’s what the onclick event preceeded by the onmouseover event within the environs you are encountering … is all about”.

That news is pretty good actually, because it means mobile users are not missing out on much not having easy access to any onmouseover (ie. hover) functionality … they’ll still reach any onclick logic you present them, in the default case of events where onclick is a valid “touch” event as well.

So the data structure of arrangements to allow for this onclick functionality is intrinsically the same as allowed for yesterday with the PHP/Javascript/HTML Google Chart Map Tooltips Tutorial as shown below, but we just check for some more delimitation issue matters, and our updated prompting window logic gets quite “blurby” as per the Javascript (via PHP) …



echo " datalinesuffix = prompt('Enter decimal Latitude,Longitude ' + thisline + extra + ' (for no more hit Cancel button and append with ' + '\\n\\n' + ',\"A tooltip and clicking link for Google Map of <a target=_blank href=https://www.google.com.au/maps/place/' + encodeURIComponent(dlp2) + '>' + dlp2 + '</a>\" ' + '\\n\\n' + ' or maybe perhaps ' + '\\n\\n' + ',\"A tooltip and clicking link for Google Map based on latitude and longitude of <a target=_blank href=https://maps.google.com.au/maps?' + encodeURIComponent('z=15&t=m&q=loc:') + '{latitude}{longitude}>' + dlp2 + '</a>\"' + '\\n\\n' + ' optionally (as (just) two examples of what is possible with HTML included (activates with onclick bit not onmouseover))', thisdef); " . "\n";
echo ' if (datalinesuffix != null) { if (datalinesuffix.indexOf("{latitude}") != -1) { dlsa=datalinesuffix.split(","); if (dlsa[0].indexOf("-") == -1) { datalinesuffix=datalinesuffix.replace("{latitude}",encodeURIComponent("+" + dlsa[0])); } else { datalinesuffix=datalinesuffix.replace("{latitude}",encodeURIComponent(dlsa[0])); } } if (datalinesuffix.indexOf("{longitude}") != -1) { dlsa=datalinesuffix.split(","); if (dlsa.length > 1) { if (dlsa[1].indexOf("-") == -1) { datalinesuffix=datalinesuffix.replace("{longitude}",encodeURIComponent("+" + dlsa[1])); } else { datalinesuffix=datalinesuffix.replace("{longitude}",encodeURIComponent(dlsa[1])); } } } } ' . "\n";

… as again we are making use of $_GET[] parameters coming into the PHP at the server side.

The bigger picture plan for how this helps something else we are trying will become apparent over time … in the fullness of time … at the appropriate juncture of juxtapositions.

Let’s see some PHP code in live action for this tutorial where you define your map characteristics and data.

Link to Google Chart Tools “spiritual home” … via Google.
Link to Google Chart Tools Map information … via Google.
Link to Google Chart tooltips information … via Google.

Link to some downloadable PHP programming code … rename to map.php which changed from yesterday as per this link.


Previous relevant PHP/Javascript/HTML Google Chart Map Tooltips Tutorial is shown below.

PHP/Javascript/HTML Google Chart Map Tooltips Tutorial

PHP/Javascript/HTML Google Chart Map Tooltips Tutorial

Here is a tutorial that is revisiting Google Graphs API, or Google Chart Tools, and its Map functionality, which we first talked about with PHP/Javascript/HTML Google Chart Map Tutorial as shown below. Please read

Google Chart Tools provide a perfect way to visualize data on your website. From simple line charts to complex hierarchical tree maps, the chart galley provides a large number of well-designed chart types. Populating your data is easy using the provided client- and server-side tools.

Why are we revisiting? Well, we are interested in the interactive side to this wonderful product. We are going to start with a look into “tooltips”. Tooltips are those optional informational features of some webpages that happen when hovering over an HTML element, principally through the filling out of an HTML element’s title global attribute.. Google Charts functionality amounts to the use of Javascript, and, these days, SVG HTML elements, so “tooltips” are very relevant to the “user experience” when using Google Charts. With the Map Chart, the latitude, laongitude set is combined with a title, which can be the default “tooltip” shown, as this is all fine for many usages, but we want to extend it so that that title doesn’t have to be the tooltip.

The integration of this added functionality into the Google Chart Map Chart involves adding an extra “string” column to the data table as per the bold bits of the new Javascript (via PHP) snippet …



if (isset($_GET['value']) && (isset($_GET['tooltip']) || strpos($GETdata, "'") !== false)) {
echo " var data = new google.visualization.DataTable(); /" . "/" . $GETlabel . $GETvalue . " \n";
echo " data.addColumn('number', '" . str_replace("'","",str_replace(",","",str_replace("['","",$GETlabel))) . "'); \n";
echo " data.addColumn('number', " . str_replace(",", "); data.addColumn({'type': 'string', 'role': 'tooltip', 'p': {'html': true}}); data.addColumn('string', ", str_replace("]","",$GETvalue)) . "); \n";
echo " data.addRows([ \n";
echo str_replace("''" . "''", "''", str_replace("~", "'", substr($GETdata,1)));
echo " ]); \n";
} else {

echo ' var data = google.visualization.arrayToDataTable([ ' . "\n";
echo " " . $GETlabel . $GETvalue . " \n";
echo str_replace("''" . "''", "''", str_replace("~", "'", $GETdata));
echo " ]);\n";
}

… making use of $_GET[] parameters coming into the PHP at the server side … you’ll find that Javascript loves to work with PHP as one of those Fred and Ginger relationships of the programming world … you’ll be happier writing Javascript from your PHP too … try it and you’ll see the advantages time and again and again and again … did we leave out one? … and again.

The bigger picture plan for how this helps something else we are trying will hopefully become apparent over time.

Let’s see some PHP code in live action for this tutorial where you define your map characteristics and data.

Link to Google Chart Tools “spiritual home” … via Google.
Link to Google Chart Tools Map information … via Google.
Link to Google Chart tooltips information … via Google.

Link to some downloadable PHP programming code … rename to map.php which changed from the days of Google Charts Emailing Primer Tutorial as per this link.


Previous relevant PHP/Javascript/HTML Google Chart Map Tutorial is shown below.

PHP/Javascript/HTML Google Chart Map Tutorial

PHP/Javascript/HTML Google Chart Map Tutorial

Here is a tutorial that introduces you to Google Graphs API, or Google Chart Tools, and its Map functionality.

Google Chart Tools provide a perfect way to visualize data on your website. From simple line charts to complex hierarchical tree maps, the chart galley provides a large number of well-designed chart types. Populating your data is easy using the provided client- and server-side tools.

Let’s see some PHP code in live action for this tutorial where you define your map characteristics and data.

Link to Google Chart Tools “spiritual home” … via Google.
Link to Google Chart Tools Map information … via Google.

Link to some downloadable PHP programming code … rename to map.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.


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

Ffmpeg Install and Public Face Tutorial

Ffmpeg Install and Public Face Tutorial

Ffmpeg Install and Public Face Tutorial

Our recent web server VPS migration can not only be …

  • a migration of functionality (eg. this WordPress blog) … as well as …
  • an opportunity to open up new vistas of serverside functionality

… such as today’s ffmpeg install, which is only feasible because of the …

  • additional diskspace … chance on new web server allows for …
  • chance to install ffmpeg …

    dnf config-manager --set-enabled powertools
    dnf install --nogpgcheck https://mirrors.rpmfusion.org/free/el/rpmfusion-free-release-$(rpm -E %rhel).noarch.rpm -y
    dnf install --nogpgcheck https://mirrors.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-$(rpm -E %rhel).noarch.rpm -y
    dnf install ffmpeg

    … thanks to this great link, along with ImageMagick …

… on this new “public face” (even more public when DNS is applied later).

Codewise this involved …

… further to recent work touching these ideas with Animated GIF Creator Overlayed Images Top Left Tutorial.

See some of this public install of ffmpeg here.


Previous relevant Animated GIF Creator Overlayed Images Top Left Tutorial is shown below.

Animated GIF Creator Overlayed Images Top Left Tutorial

Animated GIF Creator Overlayed Images Top Left Tutorial

To add to the recent Animated GIF Creator Overlayed Images Tutorial‘s user interaction logic, we add a way to control those two “overlay” CSS properties …

  • left
  • top

… but more in the sense that we allow CSS …

  • margin-eft
  • margin-top

… come into the picture, after a dalliance with CSS calc thoughts.

This allows for offsetted images be part of the “overlay mix” that you can retry this at our changed tutorial_to_animated_gif.php inhouse public domain Animated GIF Creator.


Previous relevant Animated GIF Creator Overlayed Images Tutorial is shown below.

Animated GIF Creator Overlayed Images Tutorial

Animated GIF Creator Overlayed Images Tutorial

We wanted to add an “Overlayed Images” functionality component to the “Animated GIF Creator” of Animated GIF Creator Video Intranet Tutorial, today.

The work involves both of the HTML design “big concepts” we are keen on at this blog …

  • overlay … via CSS control of
    1. position:absolute;top:0px;left:0px;
    2. opacity:1.0;
    3. z-index:1;
  • reveal … lately, mostly, via HTML use of …
    1. details
    2. summary

… the latter being the “container” for our interactive input be able to control overlay items 2 and 3, which affect the “overlayed images” output display via the clicking of a new “Overlay Images” button. That button …


<input disabled onclick="overlaythem();" id="overlayit" type="button" title='Overlay Images' value='Overlay Images'></input>

… starts off as disabled … and works with new HTML div elements …


<div id=overlayedj><h1>&nbsp;</h1><br></div><div id=overlayedi></div>

… until at least two images are defined, at which time the button becomes enabled …


function onfit(ithis) {
if (ithis.value == '' && ('' + ithis.placeholder).indexOf(']') != -1) {
ithis.value=('' + ithis.placeholder).split('[')[1].split(']')[0];
}
ithis.type='number';
}

function overlayds(inm, newop, newzi) {
var outdets='';
var divrect=null;
var poslt=' data-style=\"position:absolute;left:px;top:px;\" ';
var reposit='';
if (!document.getElementById('detsum' + ('' + inm))) {
if (document.getElementById('overlayedi').innerHTML == '') {
document.getElementById('overlayedi').title='Overlayed Images Below ... Click for It in New Window ...';
document.getElementById('overlayedj').innerHTML='<h1>Overlayed Images Below ...</h1><br>';
divrect=document.getElementById('overlayedi').getBoundingClientRect();
poslt=' data-style=\"position:absolute;left:' + ('' + divrect.left).split('.')[0].trim() + 'px;top:' + ('' + eval(200 + eval('' + ('' + divrect.top).split('.')[0]))).trim() + 'px;\" ';
} else {
poslt=' data-style=\"' + document.getElementById('detsum1').getAttribute('data-style') + '\" ';
}
outdets='&nbsp;&nbsp;<details ' + poslt + ' id=\"detsum' + ('' + inm) + '\" style=\" display:inline-block; \" open><summary id=\"sumdet' + ('' + inm) + '\">Overlay</summary><input onchange=overlayds(' + inm + ',this.value,String.fromCharCode(32)); onblur=overlayds(' + inm + ',this.value,String.fromCharCode(32)); type=text onfocus=onfit(this); id=\"opacity' + ('' + inm) + '\" style=\" display:inline-block; \" placeholder=\"Opacity [1.00]\" value=\"\" step=0.01 min=0.00 max=1.00></input><br><input onfocus=onfit(this); onchange=overlayds(' + inm + ',String.fromCharCode(32),this.value); onblur=overlayds(' + inm + ',String.fromCharCode(32),this.value); type=text id=\"zindex' + ('' + inm) + '\" style=\" display:inline-block; \" placeholder=\"Z-Index [1]\" value=\"\" min==999 max=999 step=1></input><br></details>';
reposit=poslt.replace(' data-',' ');
reposit=reposit.replace('\"', '\"opacity:1.0;z-index:1;');
if (document.getElementById('overlayedi').innerHTML == '') {
document.getElementById('overlayedi').innerHTML='<img id=\"imgdet' + ('' + inm) + '\" src=\"' + document.getElementById('slideshow' + ('' + inm).replace(/^1$/g,'')).value + '\" ' + reposit + '></img>';
document.getElementById('overlayedi').style.width=('' + document.getElementById('imgdet' + ('' + inm)).width).replace('px','') + 'px';
document.getElementById('overlayedi').style.height=('' + document.getElementById('imgdet' + ('' + inm)).height).replace('px','') + 'px';
document.getElementById('overlayedi').onclick = function(){ var woo=window.open('','_blank','top=100,left=100,width=' + document.getElementById('overlayedi').style.width.replace('px','') + ',height=' + document.getElementById('overlayedi').style.height.replace('px','')); woo.document.write('<html><head><title>Overlayed Images Below ...</title></head><body>' + document.getElementById('overlayedi').outerHTML.replace(/left\:[\ ]*/g,'left:0.0').replace(/top\:[\ ]*/g,'top:0.0') + '</body></html>'); woo.document.title='Overlayed Images Below ...'; };
} else {
document.getElementById('overlayedi').innerHTML+='<img id=\"imgdet' + ('' + inm) + '\" src=\"' + document.getElementById('slideshow' + ('' + inm).replace(/^1$/g,'')).value + '\" ' + reposit + '></img>';
}
} else {
document.getElementById('detsum' + ('' + inm)).style.display='inline-block';
if (newop != ' ') {
if (newop.trim() == '') {
document.getElementById('imgdet' + inm).style.opacity='1.0';
} else {
document.getElementById('imgdet' + inm).style.opacity='' + newop;
}
}
if (newz != ' ') {
if (newz.trim() == '') {
document.getElementById('imgdet' + inm).style.zIndex='1';
} else {
document.getElementById('imgdet' + inm).style.zIndex='' + newzi;
}
}
}
return outdets;
}

function overlaythem() {
var suffidea=1;
while (document.getElementById('slideshow' + ('' + suffidea).replace(/^1$/g, '')).value != '') {
document.getElementById('ours' + ('' + suffidea)).innerHTML+=overlayds(suffidea,'','');
suffidea++;
}
}

You can try this at our changed tutorial_to_animated_gif.php inhouse public domain Animated GIF Creator.


Previous relevant Animated GIF Creator Video Intranet Tutorial is shown below.

Animated GIF Creator Video Intranet Tutorial

Animated GIF Creator Video Intranet Tutorial

With the recent Animated GIF Creator Video Revisit Tutorial (preceding Animated GIF Creator Video Share Tutorial) we wrote …

… one reason being that we do not want to install the wonderful ffmpeg (command line video creation tool) on the RJM Programming domain, but, in macOS, here with MAMP, we are quite happy to live with the Homebrew (Terminal application’s) install …

… setting up what could be “lost functionality”, but today, we come around to either adding a new …


Convert to Video

… dropdown option should all be ritchy ditch, and if not, often we will add new “Advice” dropdown options to remind the user what they’d need to arrange to get to a “Convert to Video” scenario.

Selecting “Convert to Video” sets up a hydrid “Internet/Intranet” feeling scenario where …

  • the user is using our changed tutorial_to_animated_gif.php inhouse public domain Animated GIF Creator containing this new “Convert to Video” option off the “ImageMagick” dropdown …
  • the user defines some image slide data … eg. browsing to create data-URIs (but careful not to do too many) …
  • the user selects that “Convert to Video” option …
  • a window.open popup calls URL like …
    HTTP://localhost:8888/PHP/animegif/tutorial_to_animated_gif.php?video=1687644
    … in a new window …
  • those data-URIs are converted into /tmp/jmtmp0*.[imageExt] files … ready for …
  • ffmpeg commands like …

    ffmpeg -framerate 0.1 -i /tmp/jmtmp%03d.jpeg -c:v libvpx-vp9 -pix_fmt yuva420p -lossless 1 -c:a copy video.webm; ffmpeg -i video.webm video.mov 2>> video.bad

    … be nested in PHP exec (via MAMP local web server incarnation of the inhouse Animated GIF Creator) as a way to create videos …
  • which can be downloaded within that public domain “parent” inhouse Animated GIF Creator session

Which begs the question …


How do we know when to offer the "Convert to Video" option on that dropdown?

This logic is centred around a few useful ideas (with this cross domain scenario ruling out Ajax and Iframe src= definitions, as useful ways to go) …

  1. open the MAMP local web server “HTTP://localhost:8888/PHP/animegif/tutorial_to_animated_gif.php” URLs in an iframe (with onload event logics) pointed at by a window.open second argument (effectively avoiding any loose useful or not popup windows hanging around) …
  2. the most we can ask at the receiver is that window.opener is defined … and if so, just at that discovery …
  3. an image called “amhere.jpg” is created via PHP GD functionality … and back at the “public domain” parent within the iframe onload logic (where with contentWindow or contentDocument do not expect a document.body or even a document) …
  4. we attempt to “hotlink” that MAMP local web server image … as per …

    var tryit='http://localhost:8888/PHP/animegif/amhere.jpg';

    document.getElementById('ctvopt').value='advice';
    document.getElementById('ctvopt').innerHTML='Advice on Convert to Video';

    if (tryit != '') {
    var im=new Image();

    im.onload = function() {
    document.getElementById('ctvopt').value='video';
    console.log('this.height=' + eval('' + this.height));
    if (eval('' + this.height) >= 20) {
    document.getElementById('ctvopt').innerHTML='Convert to Video';
    } else {
    document.getElementById('ctvopt').innerHTML='Convert to Video (but ffmpeg not installed or in unexpected place)';
    }
    document.getElementById('imsel').title='All except Convert to Video, which needs ffmpeg installed, use ImageMagick';
    };


    im.src=tryit;
    tryit='';
    }


Previous relevant Animated GIF Creator Video Revisit Tutorial is shown below.

Animated GIF Creator Video Revisit Tutorial

Animated GIF Creator Video Revisit Tutorial

We hope you realize that our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator (helped out by a changed emailhtml.php inhouse email creator helper serverside PHP web application) can be accessed …

  1. in that public RJM Programming mode of use above … but even better can be …
  2. download relevant code to macOS MAMP local web server places off /Applications/MAMP/htdocs/ $_SERVER[‘DOCUMENT_ROOT’] places …

    … and check the code for the validity of any ImageMagick paths … and if not all these conditions, simulate the same and cobble it together in the code

… one reason being that we do not want to install the wonderful ffmpeg (command line video creation tool) on the RJM Programming domain, but, in macOS, here with MAMP, we are quite happy to live with the Homebrew (Terminal application’s) install …


brew install ffmpeg

… to open a whole new woooooorrrrlllllddd of video creation opportunities using this MAMP local web URL …


HTTP://localhost:8888/PHP/animegif/tutorial_to_animated_gif.php# Animated GIF Creator on MAMP local web server

And so, onto yesterday’s Animated GIF Creator PDF Last Reveal Tutorial we decided to revisit video creation parts of our inhouse Animated GIF Creator on this MacBook Air. We needed to reinstall ffmpeg, and we show that in today’s animated GIF tutorial picture and also created the “video.mov” video below, in the process …

… we tweaked out of “video/mp4” ffmpeg created videos thinking towards “video/webm” or “video.mov” ffmpeg created videos that suit the “few frames but spaced out video” we wanted to achieve for all practical purposes, that “video/mp4” playing too fast for us to see anything much but the first and last slide …

<?php

$videofr=" -r " . (1000 / $delay) . " ";
$videofr=" -r " . (1000 / $delay) . " -filter:v setpts=" . ($delay / 1000) . "*PTS ";
$videomime="video/mp4";
$videoext=".mp4";

$videofr=" -framerate 0.1 ";
$videoext=".webm";
$videomime="video/webm";
$videomidbit="-c:v libvpx-vp9 -pix_fmt yuva420p -lossless 1 -c:a copy";
//$videocmd=$videopath . "ffmpeg -r " . (1000 / $delay) . " -filter:v setpts=" . ($delay / 1000) . "*PTS " . " -i " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "%03d.jpg " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.mp4 2> " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.bad";
//$svideocmd="ffmpeg -r " . (1000 / $delay) . " -filter:v setpts=" . ($delay / 1000) . "*PTS " . " -i " . "%03d.jpg " . "video.mp4";
$videocmd=$videopath . "ffmpeg " . $videofr . " -i " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "%03d.jpg " . $videomidbit . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video" . $videoext . " 2> " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.bad";
$svideocmd="ffmpeg " . $videofr . " -i " . "%03d.jpg " . $videomidbit . " " . "video" . $videoext;
$videocmd.="; " . $videopath . "ffmpeg -i " . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video" . $videoext . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.mov 2>> " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.bad";
$svideocmd.="; " . "ffmpeg -i " . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video" . $videoext . " " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.mov 2>> " . dirname(__FILE__) . DIRECTORY_SEPARATOR . "video.bad";
$videohtml="<video title='" . $svideocmd . "' controls id=ivideo type='" . $videomime . "'><source src='video.mov'></source><source src='video" . $videoext . "'></source></video>";
$videosuffix="";

?>


Previous relevant Animated GIF Creator PDF Last Reveal Tutorial is shown below.

Animated GIF Creator PDF Last Reveal Tutorial

Animated GIF Creator PDF Last Reveal Tutorial

As a web application programmer we like buttons. There are “buttons” and there are buttons. Yes, there is an HTML button element, and it and the input type=button element render as that part of a webpage most recognizable to users the world over. You click or tap this button and something usually happens.

But we also enjoy “Emoji Buttons” for we graphically challenged programmers. Using an emoji text and graphic can make span elements or p elements or lots of other HTML elements that have an innerHTML property, be like a very succinct button like entity, also appreciated around here because it takes up so little webpage “real estate”.

And so onto yesterday’s Animated GIF Creator PDF Order Tutorial we set about, today, “revealing” any enduring animated GIF and/or PDF created during a previous session, using Emoji Buttons as the email/SMS sharing action buttons.

We say “revealing” because, like the way “Emoji Buttons” save webpage “real estate”, so can the use of the HTML5 details/summary element combination. It is in that summary “enduring” header part of that combination we can place some “Emoji Buttons”. You will (once you start creating and sharing animated GIFs and/or PDFs) see from our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator (helped out by a changed emailhtml.php inhouse email creator helper serverside PHP web application) that we place three Emoji Buttons …

  1. 📟 SMS (Animated GIF or PDF) Limited relevance period (ie. no data URIs involved, so rely on an absolute URL whose content might change or start not to exist down the track) … via “a” “sms:” link click/tap
  2. 📧 Email (Animated GIF or PDF) Limited relevance period (ie. no data URIs involved, so rely on an absolute URL whose content might change or start not to exist down the track) … via “a” “mailto:” link click/tap
  3. 📧 Email (Animated GIF or PDF) Enduring relevance (ie. data URIs involved, so do not rely on any absolute URL whose content might change or start not to exist down the track) … via PHP mail function means of sending email with HTML attachment containing the relevant Animated GIF or PDF

Yes, “Emoji Buttons” can have their size controlled but not by the usual CSS width and height properties, but by the CSS font-size property. Here is the new Javascript function that those Emoji Button “onclick” logic points to …

<?php eho ”

function askes(isemail, isoab) {
var esask='', izhr=null, izform=null;
var isoa=document.getElementById(isoab.id.replace('b',''));
if (isemail) {
esask=prompt('Please enter email address to send this to', '');
if (esask != null) {
if (esask.indexOf('@') != -1) {
if (isoa.outerHTML.indexOf('<img') == 0) {
//alert('More Animated GIF to come');
izhr = new XMLHttpRequest();
izform=new FormData();
izform.append('to', esask.trim());
izform.append('inline', '" . dirname(__FILE__) . DIRECTORY_SEPARATOR . server_remote_addr() . ".gif" . "');
izform.append('subj', 'My Latest Animated GIF via RJM Programming ... ');
izform.append('tdhuhta', ('<body><div title=\"" . explode('/animegif',$durlis)[0] . '/animegif/' . server_remote_addr() . "\" style=\"overflow:auto;-webkit-overflow-scrolling:touch;height:100%;\"><img style=\"width:100%;height:900px;\" src=\"" . dirname(__FILE__) . DIRECTORY_SEPARATOR . server_remote_addr() . ".gif" . "\"></img></div></body>'));
izhr.open('post', '//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php', true);
izhr.send(izform);
} else if (isoa.outerHTML.indexOf('<a') != 0) {
//alert('More PDF to come');
izhr = new XMLHttpRequest();
izform=new FormData();
izform.append('to', esask.trim());
izform.append('inline', '" . dirname(__FILE__) . DIRECTORY_SEPARATOR . server_remote_addr() . "_animegif.pdf" . "');
izform.append('subj', 'My Latest PDF via Animated GIF via RJM Programming ... ');
izform.append('tdhuhta', ('<body><div title=\"" . explode('/animegif',$durlis)[0] . '/animegif/' . server_remote_addr() . "_\" style=\"overflow:auto;-webkit-overflow-scrolling:touch;height:100%;\"><object style=\"width:100%;height:900px;\" type=\"application/pdf\" data=\"" . dirname(__FILE__) . DIRECTORY_SEPARATOR . server_remote_addr() . "_animegif.pdf" . "\"></object></div></body>'));
izhr.open('post', '//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php', true);
izhr.send(izform);
} else {
isoa.href='mailto:' + esask.trim() + '?' + isoa.href.split('?')[1];
isoa.click();
}
}
}
} else {
esask=prompt('Please enter SMS number to send this to', '');
if (esask != null) {
if ((esask.trim() != '' && esask.trim().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,'') == '')) {
isoa.href='sms:' + esask.trim() + '&' + isoa.href.split('&')[1];
isoa.click();
}
}
}
}

“; ?>

Cute, huh?!


Previous relevant Animated GIF Creator PDF Order Tutorial is shown below.

Animated GIF Creator PDF Order Tutorial

Animated GIF Creator PDF Order Tutorial

Order becomes an interesting subject to us today regarding the PDF conversions possible in amongst the Animated GIF creating of yesterday’s Animated GIF Creator PDF Share Tutorial.

That is because we may have some advanced users out there that want that possibility of differentiating the data of …

  • animated GIF … containing all features asked for, in totality … from the chance for the user to have any of the PDF conversion option sets below …
  • PDF … one of …
    1. no PDF conversion
    2. full PDF conversion … with the user choices regarding raw image content and title and watermarking and ImageMagick and GD modifiers
    3. light PDF conversion … with the user choices regarding just raw image content (the only option out of these last three available before today’s work)
    4. medium PDF conversion … with the user choices regarding just ImageMagick and GD modifiers

… perhaps as a “before and after” tool regarding presentations, maybe?

No dropdowns used here (enforcing an order), just the user’s order in which they choose to select the “PDF conversion” option from the ImageMagick dropdown (in relation to other selections) determining how and when this PDF conversion occurs in the workflow through to creating the animated GIF with our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator serverside PHP web application. Just remember to select PDF Conversion as early as possible to do that “light PDF conversion” option above and last thing if you are interested in “full PDF conversion” (where you can create PDF documents with the bells and whistles ImageMagick and GD modifiers can offer) and today’s tutorial picture is an example of “medium PDF conversion” (when we ordered our settings by first Grayscale, second PDF conversion and last title and watermarking options). Clicking or tapping the ImageMagick link can get the user to the Javascript popup window where they might define the email or SMS recipient for that PDF conversion data file download.


Previous relevant Animated GIF Creator PDF Share Tutorial is shown below.

Animated GIF Creator PDF Share Tutorial

Animated GIF Creator PDF Share Tutorial

To share yesterday’s Animated GIF Creator PDF Conversion Tutorial PDF data formatted image slides (and then onto an animated GIF) would be a step forward, wouldn’t you say?

What sharing conduits do we code for? We always intended …

  • email … but as the day wore on trying to get the usage to work on mobile and non-mobile we decided to relinquish our wish to not have to create a user specific enduring (until that same browser type and user combination share) PDF document for the user request … mainly to get mobile email downloads to be friendly … and so this opened the door for …
  • SMS … to access that enduring PDF as a URL in the SMS message (that becomes a link for the recipient)

… the email methodology used being that “midair feeling” Ajax/FormData approach in our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator serverside PHP web application …

<?php echo ”

function emailhtmlit() {
var induri=ginduri;
var pemail='" . urldecode($_GET['outpdf']) . urldecode($_POST['outpdf']) . "';
if (pemail != null) {
if (pemail.indexOf('@') != -1 || (pemail.trim() != '' && pemail.trim().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,'') == '')) {
if (induri.trim() == '') {
if (induri == '') {
document.getElementById('pdfproposed').src='./animegif.pdf?rand=' + Math.floor(Math.random() * 19854654);
} else {
ginduri='found';
}
setTimeout(emailhtmlit, 15000);
} else {
ginduri='';
var zhr = new XMLHttpRequest();
var zform=new FormData();
if (pemail.indexOf('@') != -1) { zform.append('to', pemail); }
zform.append('inline', '" . dirname(__FILE__) . DIRECTORY_SEPARATOR . "animegif.pdf" . "');
zform.append('subj', 'My PDF version of Animated GIF via RJM Programming ... ');
zform.append('tdhuhta', ('<body><div title=\"" . explode('/animegif',$durlis)[0] . '/animegif/' . server_remote_addr() . "_\" style=\"overflow:auto;-webkit-overflow-scrolling:touch;height:100%;\"><object style=\"width:100%;height:900px;\" type=\"application/pdf\" data=\"" . dirname(__FILE__) . DIRECTORY_SEPARATOR . 'animegif.pdf' . "\"><embed style=\"width:100%;height:900px;\" type=\"application/pdf\" src=\"" . dirname(__FILE__) . DIRECTORY_SEPARATOR . 'animegif.pdf' . "\"></embed></object></div></body>'));
//zform.append('tdhuhta', ('<body><iframe srcdoc=\"" . dirname(__FILE__) . DIRECTORY_SEPARATOR . 'animegif.pdf' . "\"></iframe></body>'));
zhr.open('post', '//www.rjmprogramming.com.au/HTMLCSS/emailhtml.php', true);
zhr.send(zform);
if (pemail.indexOf('@') == -1) {
var hrefp=document.getElementById('pdfsms').href.split('&body=')[0];
hrefp+=pemail.trim() + '&body=' + document.getElementById('pdfsms').href.split('&body=')[1];
document.getElementById('pdfsms').href=hrefp;
document.getElementById('pdfsms').click();
}
}
}
}
}

“; ?>

… and this called on our PHP email creator helper to better interface in its $_POST arguments reading section in our changed emailhtml.php inhouse email creator helper serverside PHP web application …

<?php

$psacv="";
$okayin=true;
$subd="";
$subptitle='';
$subdata="";
$subfile="";
$getpostfound=false;
<br>
foreach( $_POST as $name=>$val ) {
if ($val != "") {
// blah blah blah //file_put_contents("jnv." . $name, "jnv.inv00 " . strlen($phpcont));
if ($name == "tdhuhta" && $subfile != "" && $subdata != "" && strpos(str_replace("+"," ",urldecode($val)), $subfile) !== false) {
if (strpos(str_replace("+"," ",urldecode($val)), ' srcdoc="') !== false || strpos(str_replace("+"," ",urldecode($val)), ' data="') !== false) {
if (strpos(str_replace("+"," ",urldecode($val)), ' title="') !== false) { //file_put_contents('haaa.aaa',explode('/animegif/', explode('"', explode(' title="', str_replace("+"," ",urldecode($val)))[1])[0])[1]);
if (!file_exists('../PHP/animegif/' . explode('/animegif/', explode('"', explode(' title="', str_replace("+"," ",urldecode($val)))[1])[0])[1] . 'animegif.pdf')) {
if (file_exists('../PHP/animegif/animegif.pdf')) {
copy('../PHP/animegif/animegif.pdf', '../PHP/animegif/' . explode('/animegif/', explode('"', explode(' title="', str_replace("+"," ",urldecode($val)))[1])[0])[1] . 'animegif.pdf');
}
}
$psacv=explode('"', explode(' title="', str_replace("+"," ",urldecode($val)))[1])[0] . 'animegif.pdf';
$subptitle='<a target=_blank href="' . explode('"', explode(' title="', str_replace("+"," ",urldecode($val)))[1])[0] . 'animegif.pdf">Mobile whole PDF</a><br>';
}
$vrest=explode('"', explode(' srcdoc="',str_replace("+"," ",urldecode($val)))[1])[0];
$val=urlencode("<body>" . $subptitle . "<iframe style='width:100%;height:95vh;overflow:auto;-webkit-overflow-scrolling:touch;' srcdoc='<div style=width:92%;height:95vh;overflow:auto;-webkit-overflow-scrolling:touch;><object id=myobj style=width:95%;height:95vh; type=application/pdf data=\"" . $subdata . "\"></object></div>'></iframe></body>");
}
// blah blah blah
if ($name == "inline") {
if (strpos(str_replace("+"," ",urldecode($val)), 'animegif.pdf') !== false && isset($_POST['tdhuhta'])) {
if (file_exists(str_replace("+"," ",urldecode($val)))) {
$subfile=str_replace("+"," ",urldecode($val));
$subdata='data:application/pdf;base64,' . base64_encode(file_get_contents(str_replace("+"," ",urldecode($val))));
$val="";
$name="x";
$okayin=false;
}
}
// blah blah blah
}
}

?>

Creating the PDFs got helped out in “reliability terms” via the introduced animegif.php inhouse Wait Around Longer serverside PHP web application.


Previous relevant Animated GIF Creator PDF Conversion Tutorial is shown below.

Animated GIF Creator PDF Conversion Tutorial

Animated GIF Creator PDF Conversion Tutorial

Up to yesterday’s Animated GIF Creator Slide Specific Application Tutorial the recent progress had us …

  • knowing the good places to intervene between the original slide image data being read in and the animated GIF slide output … and …
  • involvement of ImageMagick … so, today, these two help us down the path to …
  • adding PDF as an output format possibility, in addition to the animated GIF and other ideas floated as output formats

… with our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator serverside PHP web application.

We have more “reliability work” and “email sharing work” to go after today’s start, but it primarily called on ImageMagick command line’s talent for a command like …


convert /tmp/imtmp0*.*[gGmMiI]* /tmp/imtmp000.pdf

… to “concatenate” into the one output PDF file (called “/tmp/imtmp000.pdf”) the slides, arranged by our code into that “/tmp/imtmp0*.*[gGmMiI]*” (file specification) arrangement above. Yes, we meant “convert” above, as “mogrify” (batch work) appears not to be able to perform this task.

We hope you stay the course!


Previous relevant Animated GIF Creator Slide Specific Application Tutorial is shown below.

Animated GIF Creator Slide Specific Application Tutorial

Animated GIF Creator Slide Specific Application Tutorial

It’s all fine and good improving on the ImageMagick and GD and Exif functionality modifications like with yesterday’s Animated GIF Creator Exif Rotation Compensation Tutorial, but in reality, if you are going to start creating animated GIFs to explain a process, you are going to want to apply these “slide modifiers” on a slide by slide basis, rather than enforcing a “whole of animated GIF slide set” paradigm, as for the last few days worth of work.

And so, we decided to do what we often do, “sliding in” more functionality (chortle, chortle). We tend to want to …

  • start with hardcoded text (or element) … somewhere … today it happens to be in an HTML span element that once involved just …

    <span id="smyim"></span>

    … and used to get filled, Javascript DOM wise, when needed via …

    document.getElementById('smyim').innerHTML='ImageMagick switches: '; // and yes, it remains that way even now, but read on ...
  • add intelligence (quite often that being onclick logic(s)) to that hardcoded element via …

    <span id=smyim title=Application onclick=applyto(); style=cursor:pointer;text-decoration:underline;></span>
  • that serves the purpose, as the user clicks/taps it (alerted to that fact, perhaps, because we underline the element and add an appropriate cursor when hovering over it (plus a title)), of calling Javascript …

    function applyto() {
    var huhto=prompt('Apply ImageMagick and/or GD to which slides, in comma separated list, counting starting with 1? Defaults to applying to all slides. Comma delimit. Negatives mean all but. Ranges can be specified. For example ... 2,4-7,9', document.getElementById('appliedto').value);
    if (huhto == null) { huhto=''; }
    if (huhto.trim() == '') {
    document.getElementById('appliedto').value='';
    document.getElementById('smyim').title='Application';
    } else {
    document.getElementById('appliedto').value=huhto.trim();
    document.getElementById('smyim').title=huhto.trim();
    }
    }
  • to glean an (often times out of the normal workflow of the web application) informational piece of data, interactively, from the user, via a Javascript prompt popup

So that’s the clientside of this work … “alerting the user to the existance of the functionality” you might say.

And then there’s “the application” of that nuanced user requirement. And that’s where the “inhouse ‘our’ prefix to wrapper function name paradigms” come in handy. We introduced “blanket” functionality thoughts via this approach, and so to “partially undo” that thinking, we make the “our” prefix conditional, as is available to us with our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator serverside PHP web application (helped out by a changed exif_rotation_check.php inhouse Exif detector PHP helper), as per

<?php

function ourcomplicated($inio, $iappl) {
$ideasl=explode(",", str_replace(' ','',$iappl));
$xour="our";
for ($iqa=0; $iqa<sizeof($ideasl); $iqa++) {
if (trim($ideasl[$iqa]) != '') {
$xour="";
if (('-' . $inio) == trim($ideasl[$iqa])) { return ""; }
$ideasr=explode("-", str_replace(' ','',trim($ideasl[$iqa])));
for ($iqb=0; $iqb<sizeof($ideasr); $iqb++) {
if (('' . $inio) == trim($ideasr[$iqb])) {
return "our";
}
if ($iqb == 1) {
if (trim($ideasr[1]) == "") { $ideasr[1]="99999999"; }
if ($inio >= $ideasr[0] && $inio <= $ideasr[1]) { return "our"; }
}
}
}
}
return $xour;
}


?>

teamed with

<?php

$ours="our";
for ($io=1; $io$ours=ourcomplicated($io, $iappliedto);
// blah blah blah
if (strpos($aphoto[0], ";base64,") !== false) {
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefromstring(base64_decode('" . explode(";base64,",$aphoto[0])[1] . "'));", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachonestring));
} else if (strpos(strtolower($aphoto[0]), "//") !== false) {
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefromstring(@file_get_contents('" . $prefix . $aphoto[0] . "'));", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
} else if (strpos(strtolower($aphoto[0]), ".jp") !== false) {
if (strpos($prefix, "../../") !== false && !file_exists($prefix . $aphoto[0]) && file_exists(str_replace("../../","../",$prefix) . $aphoto[0])) {
$prefix=str_replace("../../","../",$prefix);
}
//file_put_contents('qpqp.qpqp', $eachone . "\n\n" . $atext . "\n\n" . str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefromjpeg('" . $prefix . $aphoto[0] . "');", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
//file_put_contents('qpqpqp.qpqpqp', $gifphp);
} else if (strpos(strtolower($aphoto[0]), ".png") !== false) {
if (strpos($prefix, "../../") !== false && !file_exists($prefix . $aphoto[0]) && file_exists(str_replace("../../","../",$prefix) . $aphoto[0])) {
$prefix=str_replace("../../","../",$prefix);
}
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefrompng('" . $prefix . $aphoto[0] . "');", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
} else if (strpos(strtolower($aphoto[0]), ".gif") !== false) {
if (strpos($prefix, "../../") !== false && !file_exists($prefix . $aphoto[0]) && file_exists(str_replace("../../","../",$prefix) . $aphoto[0])) {
$prefix=str_replace("../../","../",$prefix);
}
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefromgif('" . $prefix . $aphoto[0] . "');", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
} else if (strpos(strtolower($aphoto[0]), ".bmp") !== false) {
if (strpos($prefix, "../../") !== false && !file_exists($prefix . $aphoto[0]) && file_exists(str_replace("../../","../",$prefix) . $aphoto[0])) {
$prefix=str_replace("../../","../",$prefix);
}
$gifphp.=str_replace("imagecreatefromjpeg('source01.jpg');", "" . $ours . "imagecreatefrombmp('" . $prefix . $aphoto[0] . "');", str_replace("\$text='';", "\$text=\"" . str_replace("+"," ",urldecode($atext)) . "\";", $eachone));
}
// blah blah blah
}

?>

We use these “new abilities” better explaining “the abscence or otherwise of Exif checking”, and the implications of that in the animated GIF creator woooooorrrrrrlllllddd, contrasting the first two slides, showing one with “No Exif checking” (the bad old days) versus “With Exif checking” (the renaissance of liberated thinking in the South South East woooorrrrrlllldddd) in today’s animated GIF presentation.

Get the picture?!


Previous relevant Animated GIF Creator Exif Rotation Compensation Tutorial is shown below.

Animated GIF Creator Exif Rotation Compensation Tutorial

Animated GIF Creator Exif Rotation Compensation Tutorial

The recent couple of days of work like yesterday’s Animated GIF Creator GD Transformations Interfacing Tutorial have given us “rotation functionality” tools to counteract the unusual effects Exif …

Exchangeable image file format (officially Exif, according to JEIDA/JEITA/CIPA specifications) is a standard that specifies the formats for images, sound, and ancillary tags used by digital cameras (including smartphones), scanners and other systems handling image and sound files recorded by digital cameras.

… can have converting mobile device camera created images into animated GIFs via our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator PHP web application.

But with some photos it’s there in the photo’s metadata information letting the future user know what orientation the camera of that mobile device was in as you took the photo. In order to help our animated GIF creator, the first slide image is scoured for Exif metadata and if found, a suitable rotation correction can be applied to the slides there and then. In order to scour for Exif metadata we needed to write a exif_rotation_check.php inhouse Exif detector PHP helper.


Previous relevant Animated GIF Creator GD Transformations Interfacing Tutorial is shown below.

Animated GIF Creator GD Transformations Interfacing Tutorial

Animated GIF Creator GD Transformations Interfacing Tutorial

The PHP GD image library is so much more useful than for the “filters” interfaced to with yesterday’s Animated GIF Creator GD Filter Interfacing Tutorial. Under an “umbrella term” transformations, today we add interfacing to GD functionality …

… into our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator PHP web application. We found it more user friendly to tailor the asking of numerical parameters for these GD calls work via …

<?php

$gfcds='';
$gdfs=[];
if (strpos(($imvgn . $imafn . $imqty . $imgds), '|') !== false) {
$gdfs=explode(';', trim(explode('|', $imvgn . $imafn . $imqty . $imgds)[1]));
for ($itf=0; $itf<sizeof($gdfs); $itf++) {
if (trim($gdfs[$itf]) != '') {
if (trim($gdfs[$itf]) == strtolower(trim($gdfs[$itf]))) {
$gfcds.=chr(10) . " imagefilter(" . "$" . "oimo, IMG_FILTER_" . strtoupper(trim($gdfs[$itf])) . "); " . chr(10);
} else if (trim($gdfs[$itf]) == strtoupper(trim($gdfs[$itf]))) {
$gfcds.=chr(10) . " image" . explode(',',explode(" ",strtolower(trim($gdfs[$itf])))[0])[0] . "(" . "$" . "oimo, IMG_" . str_replace(" ","_",strtoupper(trim( str_replace(explode(' ',$gdfs[$itf])[0] . ' ','',$gdfs[$itf]) ))) . "); " . chr(10);
} else if (strpos(strtoupper(trim($gdfs[$itf])), "SCALE") !== false) {
$gfcds.=chr(10) . " $" . "oimo=image" . explode(',',explode(" ",strtolower(trim($gdfs[$itf])))[0])[0] . "(" . "$" . "oimo" . str_replace(" ","_",(trim( str_replace(explode(',',explode(" ",(trim($gdfs[$itf])))[0])[0],'',$gdfs[$itf]) ))) . "); " . chr(10);
} else if (strpos(strtoupper(trim($gdfs[$itf])), "COPY") === false) {
$gfcds.=chr(10) . " image" . explode(',',explode(" ",strtolower(trim($gdfs[$itf])))[0])[0] . "(" . "$" . "oimo" . str_replace(" ","_",(trim( str_replace(explode(',',explode(" ",(trim($gdfs[$itf])))[0])[0],'',$gdfs[$itf]) ))) . "); " . chr(10);
} else {
$gfcds.=chr(10) . " image" . explode(',',explode(" ",strtolower(trim($gdfs[$itf])))[0])[0] . "(" . "$" . "oimo" . "," . "$" . "oimo" . explode("," . "$" . "oimo", $gdfs[$itf])[1] . "); " . chr(10);
}
}
}
}

?>

… to work with modified PHP writes PHP of the ilk …

<?php echo ”

function ourimagecreatefromstring(\$inidis) {
global \$imvgn, \$imafn, \$imqty, \$imgds, \$gfcds;
if ((\$imvgn . \$imafn . \$imqty . \$imgds) != '' && strpos(\$inidis, ';base64,') !== false) {
\$extis=str_replace('jpeg','jpg',explode('/', explode(';base64,', \$inidis)[0])[1]);
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, base64_encode(explode(';base64,', \$inidis)[1]));
\$fzis=filesize(\$sofarout);
if (trim(explode('|', \$imvgn . \$imafn . \$imqty . \$imgds)[0]) != '') {
exec('" . $immogpath . "mogrify ' . explode('|', \$imvgn . \$imafn . \$imqty . \$imgds)[0] . ' /tmp/imtmp.' . \$extis);
}
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false ||
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
\$oimo=null;
if (strtolower(\$extis) == 'png') {
\$oimo=imagecreatefrompng('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strtolower(\$extis) == 'bmp') {
\$oimo=imagecreatefrombmp('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strtolower(\$extis) == 'gif') {
\$oimo=imagecreatefromgif('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
\$oimo=imagecreatefromjpeg('/tmp/imtmp.' . \$extis); " . $gfcds . "
}
if (\$oimo) { return \$oimo; }
} else if ((\$imvgn . \$imafn . \$imqty . \$imgds) != '') {
\$extis=str_replace('jpeg','jpg','" . $inextis . "');
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
if (strpos(strtolower((\$imvgn . \$imafn . \$imqty . \$imgds)), '-format ') === false) { \$imvgn.=' -format " . str_replace('jpg','jpeg',$inextis) . " '; }
if (trim(explode('|', \$imvgn . \$imafn . \$imqty . \$imgds)[0]) != '') {
exec('" . $immogpath . "mogrify ' . explode('|', \$imvgn . \$imafn . \$imqty . \$imgds)[0] . ' /tmp/imtmp.' . \$extis);
}
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
\$oimo=null;
if (strtolower(\$extis) == 'png') {
\$oimo=imagecreatefrompng('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strtolower(\$extis) == 'bmp') {
\$oimo=imagecreatefrombmp('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strtolower(\$extis) == 'gif') {
\$oimo=imagecreatefromgif('/tmp/imtmp.' . \$extis); " . $gfcds . "
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
\$oimo=imagecreatefromjpeg('/tmp/imtmp.' . \$extis); " . $gfcds . "
}
if (\$oimo) { return \$oimo; }
}
return imagecreatefromstring(\$inidis);
}

“; “?>

… and to get there clientwise, in the Javascript …


function gdadd(oselo) {
var pari=1, thispari='0';
if (oselo.value != '') {
//alert(oselo.value);
var oselovalue=oselo.value.replace(',' + '$' + 'oimo','~' + '$' + 'oimo').split(',')[0];
//alert(oselovalue);
var oseloval=oselo.value;
if (document.getElementById('imgds')) { if (document.getElementById('imgds').value == '') { document.getElementById('imgds').value='|'; } else { document.getElementById('imgds').value+=';'; } }
oseloval=oseloval.replace(',' + '$' + 'oimo','~' + '$' + 'oimo');
oseloval=oseloval.replace(oseloval.split(',')[0], '');
while (oseloval.indexOf(',') != -1) {
//alert(oseloval);
if ((oseloval + ' ').substring(1).split(',')[0].trim() != '') {
if ((' ' + (oseloval + ' ').substring(1).split(',')[0].trim() + ' ').toLowerCase().indexOf(' colour ') != -1) {
thispari=prompt('Enter' + (' ' + (oseloval + ' ').substring(1).split(',')[0].trim() + ' ').toLowerCase().replace(' colour ', ' red,green,blue colour ') + 'parameter for GD ' + oselo.value.split(',')[0] + ' ' + pari + ' of ' + eval(-1 + oselo.value.replace(',' + '$' + 'oimo','').split(',').length) + '?', '0');
if (thispari == null) {
thispari='0';
} else if (thispari.trim() == '') {
thispari='0';
} else if (thispari.indexOf(',') == -1) {
oselovalue+=',' + thispari + '';
} else {
oselovalue+=',imagecolorallocate(' + '$' + 'oimo,' + thispari + ')';
}
} else {
thispari=prompt('Enter ' + (oseloval + ' ').substring(1).split(',')[0].trim() + ' parameter for GD ' + oselo.value.split(',')[0] + ' ' + pari + ' of ' + eval(-1 + oselo.value.replace(',' + '$' + 'oimo','').split(',').length) + '?', '0');
if (thispari == null) {
thispari='0';
} else {
oselovalue+=',' + thispari;
}
}
oseloval=oseloval.replace(',' + (oseloval + ' ').substring(1).split(',')[0].trim(),'').trim();
} else {
thispari=prompt('Enter numerical parameter for GD ' + oselo.value.split(',')[0] + ' ' + pari + ' of ' + eval(-1 + oselo.value.replace(',' + '$' + 'oimo','').split(',').length) + '?', '0');
oseloval=oseloval.replace(',','');
if (thispari == null) {
thispari='0';
} else {
oselovalue+=',' + thispari;
}
}
//oseloval=oseloval.replace(oseloval.split(',')[0] + ',', '');
//oseloval=oseloval.replace(',','');
pari++;
}
if (document.getElementById('gdopt')) {
document.getElementById('gdopt').innerHTML+='  ' + oselovalue.replace('~',',');
}
if (document.getElementById('imgds')) {
document.getElementById('imgds').value+=oselovalue.replace('~',',');
//document.getElementById('imgds').style.display='inline-block';
//document.getElementById('imgds').style.width='300px';
if (document.getElementById('smyim').innerHTML == '') { document.getElementById('smyim').innerHTML='ImageMagick switches: '; }
} else if (document.getElementById('myim')) {
document.getElementById('myim').innerHTML='<span is=smyim>ImageMagick switches: </span><input id=imqty name=imqty type=text style=display:inline-block; value=\"\"></input><input id=imgds name=imgds type=hidden style=display:inline-block; value=\"|' + oselovalue.replace('~',',') + '\"></input>';
document.getElementById('imqty').style.width='300px';
}
oselo.value='';
}
}


Previous relevant Animated GIF Creator GD Filter Interfacing Tutorial is shown below.

Animated GIF Creator GD Filter Interfacing Tutorial

Animated GIF Creator GD Filter Interfacing Tutorial

We are into image modification on the way to creating “compiled” animated GIF images, at the moment. Yesterday’s Animated GIF Creator ImageMagick Interfacing Tutorial got us interfacing (or integrating) …

  • ImageMagick batch processing “mogrify” ideas … and, today, it is the turn of …
  • GD image filters …

… into our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator PHP web application.


Previous relevant Animated GIF Creator ImageMagick Interfacing Tutorial is shown below.

Animated GIF Creator ImageMagick Interfacing Tutorial

Animated GIF Creator ImageMagick Interfacing Tutorial

Yes, you guessed it! On top of yesterday’s ImageMagick Vignette Primer Tutorial, today we want to interface the ImageMagick batch processing “mogrify” ideas into our changed tutorial_to_animated_gif.php inhouse Animated GIF Creator PHP web application.

“Interfacing” (or integrating) into code often has you asking the question …


Where do we intervene to place our logic?

We’ve decided to “wrap” our PHP GD calls …

… into inhouse “our” prefixed function versions as per (PHP writing out PHP) …

<?php echo ”

\$imvgn='" . $imvgn . "'; /" . "/ vignette factor
\$imafn='" . $imafn . "'; /" . "/ affine transformation
\$imqty='" . $imqty . "'; /" . "/ image conversion and/or quality RE jpeg


function ourimagecreatefromstring(\$inidis) {
global \$imvgn, \$imafn, \$imqty;
if ((\$imvgn . \$imafn . \$imqty) != '' && strpos(\$inidis, ';base64,') !== false) {
\$extis=str_replace('jpeg','jpg',explode('/', explode(';base64,', \$inidis)[0])[1]);
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, base64_encode(explode(';base64,', \$inidis)[1]));
\$fzis=filesize(\$sofarout);
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false ||
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
} else if ((\$imvgn . \$imafn . \$imqty) != '') {
\$extis=str_replace('jpeg','jpg','" . $inextis . "');
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
if (strpos(strtolower((\$imvgn . \$imafn . \$imqty)), '-format ') === false) { \$imvgn.=' -format " . str_replace('jpg','jpeg',$inextis) . " '; }
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
}
return imagecreatefromstring(\$inidis);
}

function ourimagecreatefromjpeg(\$inidis) {
global \$imvgn, \$imafn, \$imqty;
if ((\$imvgn . \$imafn . \$imqty) != '') {
\$extis='jpg';
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
}
return imagecreatefromjpeg(\$inidis);
}

function ourimagecreatefrompng(\$inidis) {
global \$imvgn, \$imafn, \$imqty;
if ((\$imvgn . \$imafn . \$imqty) != '') {
\$extis='png';
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
}
return imagecreatefrompng(\$inidis);
}

function ourimagecreatefromgif(\$inidis) {
global \$imvgn, \$imafn, \$imqty;
if ((\$imvgn . \$imafn . \$imqty) != '') {
\$extis='gif';
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
}
return imagecreatefromgif(\$inidis);
}

function ourimagecreatefrombmp(\$inidis) {
global \$imvgn, \$imafn, \$imqty;
if ((\$imvgn . \$imafn . \$imqty) != '') {
\$extis='bmp';
\$inextis=\$extis;
\$sofarout='/tmp/imtmp.' . \$extis;
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
unlink(\$imfilename);
}
file_put_contents(\$sofarout, \$inidis);
\$fzis=filesize(\$sofarout);
exec('" . $immogpath . "mogrify ' . \$imvgn . \$imafn . \$imqty . ' /tmp/imtmp.' . \$extis);
foreach (glob('/tmp/imtmp.*') as \$imfilename) {
if (filesize(\$imfilename) != \$fzis) { // strpos(\$imfilename, '.' . \$extis) === false) {
\$sofarout=\$imfilename;
\$extis=explode('.', \$imfilename)[1];
}
}
if (strtolower(\$extis) == 'png') {
return imagecreatefrompng('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'bmp') {
return imagecreatefrombmp('/tmp/imtmp.' . \$extis);
} else if (strtolower(\$extis) == 'gif') {
return imagecreatefromgif('/tmp/imtmp.' . \$extis);
} else if (strpos(strtolower(\$extis), 'jp') !== false) {
return imagecreatefromjpeg('/tmp/imtmp.' . \$extis);
}
}
return imagecreatefrombmp(\$inidis);
}

“; ?>

… and change existant calls into (equivalent inhouse) “our” function calls as above.


Previous relevant ImageMagick Vignette Primer Tutorial is shown below.

ImageMagick Vignette Primer Tutorial

ImageMagick Vignette Primer Tutorial

Continuing on with the ImageMagick batch processing “mogrify” ideas of yesterday’s ImageMagick Batch Image Conversion Affine Transformation Tutorial and the “vignette” image editing ideas of Gimp Vignette Primer Tutorial, as below, today, we took some pet photos with an iPad’s Camera app and shared them off the Photos app via two Mail sharing option emails containing seven attachments each. Using an iPad, the JPEG “jpg” output files were too big for our inhouse Animated GIF Creator PHP web application to handle, and so to perform the …

  • animated GIF presentation, off these downloaded email photo attachments … and along the way …
  • quality adjusted them (yes, “mogrify” does not stuff JPG to JPG conversions, and we used “mogrify” -quality 20% switch here) … and …
  • rotate them 180 degrees (“mogrify” uses switches -affine -1,0,0,-1,0,0 -transform +repage here) … and …
  • vignette 50% (“mogrify” uses switch -vignette 50 here)

… on the way to compiling into an animated GIF image, and we turned to ImageMagick again, using its affine transformation talents, along with its awesome vignetting talents …




… where the last two dropdown options will be similar, the last showing the input image into ImageMagick can be an animated GIF that is truely treated like an animated GIF.

By the way, should you be interested in photo orientation off a mobile device camera, have a read of PHP Exif Image Information Revisit Tutorial.

Nala and Luna and Charlie bid you a fond farewell!


Previous relevant Gimp Vignette Primer Tutorial is shown below.

Gimp Vignette Primer Tutorial

Gimp Vignette Primer Tutorial

The last time we talked about the miraculous, redolent and amazing image editor called Gimp am sure there was someone in a shower … it stands to reason … and one of those showerers, surely, would have been singing The Gimp Song … and if not … why not? … but we digress … anyway we had the Gimp Transparency Primer Tutorial as shown below go into some image transparency issues with Gimp.

In today’s tutorial we make use of a great tutorial (even so far as with direct quotes below) called Add a Vignette to a Photograph with GIMP (thanks) to try a photographic technique called vignetting on one of the photographs we added, recently, into the mix of those of the Custom Header Image mix at this blog … specifically the one of Nala, the dog, on the door ledge. Need to warn you here and now that if there was the time all over again, it would be better achieved that second time around, but this is not the point with learning, but rather getting some starting point with a great “product” like Gimp, and trying it yourself, once you have a method. It boils down to:

  1. Open Gimp graphical editor application
  2. File->Open … pick your image file
  3. Layer->New Layer (we’ll call “Vg”) … pick Foreground Colour
  4. In the Layers dialog, click on your “Vg” layer to select it, and select Soft light from the “Mode” drop-down box
  5. Right click on your “Vg” layer and go to Add Layer Mask. In the dialog that pops up, you want “Initialise Layer Mask to” set to “White (full opacity)”. Click “Add”
  6. Below Opacity bar select Link icon next to Eye icon, which will already be showing
  7. Use the freeform select tool (press F to bring this up) and draw a selection somewhere around the primary point of interest in your photo
  8. Use your bucket tool (Shift+B) and click within the selection to fill it
  9. Deselect your selection with Select->None
  10. Go to Filters->Blur->Gaussian Blur. In the dialog that comes up, you want “Radius” set to a very large amount; a tenth of the longest edge of the photo is not too much
  11. Click on your “Vg” layer to select it (if it isn’t already selected), and then slide the opacity slider towards the right until the effect is subtle enough. Our (ever so subtle) example of Nala, in the tutorial, used an opacity of about 66%
  12. Click Export button in two windows (NB. this overwrites the image file, so if this is not desirable, export to a different image file name and/or type)

Here is an image comparison link.

As with most Gimp ideas, jump in and give it a go, as you’ll find your own ways and means of using this great product … am pretty sure.

Link to Gimp “spiritual home” … here.
Link to Gimp forum … here.


Previous relevant Gimp Transparency Primer Tutorial is shown below.

Gimp Transparency Primer Tutorial

Gimp Transparency Primer Tutorial

Here is a tutorial that adds to a previous Gimp Layers Primer Tutorial as shown below, and gives you more insight into the massive possibilities of using a sophisticated image editor and use layers with various amounts of transparency, especially suited to use with png image files.

Today’s tutorial where we construct a Birthday Card that needs tweaking for the words in front to be seen a bit more clearly, by making the image behind a bit more transparent, changes the transparency of a single image via:

  1. Open Gimp graphical editor application
  2. File->Open Layers … pick your image file
  3. If Layers window not showing, make it show via Windows->Layers – Brushes
  4. Below Opacity bar select Link icon next to Eye icon, which will already be showing
  5. Change Opacity bar setting to a value of Transparency (100% is Opaque, 0% is Transparent) that suits … today we do 70%
  6. File->Export
  7. Click Export button in two windows (NB. this overwrites the image file, so if this is not desirable, export to a different image file name and/or type)

As with most Gimp ideas, jump in and give it a go, as you’ll find your own ways and means of using this great product … am pretty sure.

Link to Gimp “spiritual home” … here.
Link to Gimp forum … here.


Previous relevant Gimp Layers Primer Tutorial is shown below.

Gimp Layers Primer Tutorial

Gimp Layers Primer Tutorial

Here is a tutorial that gives you an insight into the massive possibilities of using a sophisticated image editor and use layers with various amounts of transparency, especially suited to use with png image files.

Transparency (or its obverse, opacity) can be used to have the one image achieve several “ends” (ie. purposes). Although it is a bit of a clumsy example in the tutorial, you can see that the technique can be used for artistic purposes … often called “Photoshopping” (named after the more famous, and also brilliant, rival product, Photoshop).

Lots of those classic “Photoshopping” techniques can be achieved in Gimp, and some other tutorials at this blog touch on that.

Am sure you can imagine what the concept of a layer is with regard to image manipulation. Within Gimp, for beginners not used to this concept, you find yourself underestimating and underplaying what can be achieved with the various layers of a multi-layered image. In simplistic terms each layer has the functionality in Gimp to be treated as a whole new image, and this is the best way to think of it when trying to achieve what you want to achieve with Gimp.

Link to Gimp “spiritual home” … here.
Link to Gimp forum … here.

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.


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, Installers, Operating System, Software, Tutorials | Tagged , , , , , , , , , , , , , , | Leave a comment

AlmaLinux WordPress Site Health Installs Tutorial

AlmaLinux WordPress Site Health Installs Tutorial

Yesterday’s AlmaLinux Apache/PHP/MySql WordPress Migration Tutorial was about …

  • configuring the major players, software wise, running WordPress 6.6 on AlmaLinux 9.0.4 … and today …
  • via the WordPress admin area’s Tools menu’s Site Health report “One or more recommended modules are missing” section … for our website it discovered missing …
    1. exif
    2. imagick
    3. fileinfo
    4. intl

… and after a bit of lack of success we discovered from the dnf package manager information that the list “verb” could be very useful. That, along with …


php -v

… resulting in 8.1.19 made the choice of module name [moduleName] in …


dnf install [moduleName]

… module install statements a doddle, as you can see.


Previous relevant AlmaLinux Apache/PHP/MySql WordPress Migration Tutorial is shown below.

AlmaLinux Apache/PHP/MySql WordPress Migration Tutorial

AlmaLinux Apache/PHP/MySql WordPress Migration Tutorial

Yes, we’re migrating again (as we were talking about with Apache/PHP/MySql Web Hosting Website Migration ssh Tutorial), though as you read this blog posting, if hot off the press here on 19/7/2024, we’ll not have transferred the DNS over yet, which we’ll outline the reasons for into the future. But, today, we’re excited to outline some steps after …

  • data migration … which our web hoster, Crazy Domains, did a good job regarding … ahead of …
  • seeing HTML and Javascript and CSS working fine straight away … and today’s progress migrating the WordPress Blog (involving serverside PHP and MySql) you are reading now …

… in terms of a migration consisting of (just in terms of major players) …

Description From To
Hosting VPS CentOS 6.4 x86.64 WHM cPanel 11.38.2 (build 23) AlmaLinux 9.4.0 cPanel 11.120
Operating System type Linux 2.6.32-220.13.1.el6.x86_64 Linux 5.14.0-362.18.1.el9_3.x86_64
Web Server type Apache 2.2.29 Apache 2.4.61
Server Language PHP 5.4.38 PHP 8.1.19
Database type MySql 5.1.70 MySql 8.0.38
Blog type WordPress 4.1.1 WordPress 6.6

… that PHP leap very big (and we were near an edge regarding PHP 5.4.38 where a WP-CLI approach as below can still work … some earlier 5’s will not work, we were told along the way), and trepidatious, to our mind, but at least for WordPress, now working, via (just highlights, and we’ll leave out that it is great to have a backup of the MySql WordPress software and database ideally, before starting (because we already had one courtesy of the data migration above)) …

  1. install WP-CLI … via ssh -p 22 [adminUser]@[newIPaddressForRJMProgrammingIntoTheFuture] … profuse thanks to this great advice

    # cd ~[websiteUser]
    # cd public_html/ITblog
    # curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
    # php wp-cli.phar --info
    # chmod +x wp-cli.phar
    # mv wp-cli.phar /usr/local/bin/wp
  2. run the plan ideas past Crazy Domains
  3. just install the WordPress Codex software in wp-admin and wp-includes … via ssh -p 22 [adminUser]@[newIPaddressForRJMProgrammingIntoTheFuture]

    # su - [websiteUser]
    $ cd ~[websiteUser]
    $ cd public_html/ITblog
    $ wp core download --force --skip-content
  4. iron out just the one (yee, ha) plugins and/or theme issues that can occur entering a URL such as https://[newIPaddressForRJMProgrammingIntoTheFuture]/ITblog into a web browser address bar … removing …

    New Google Plus Badge Widget

    … plugin folder and files, because it’s name was apparent in the error message in the video below, and once done WordPress 6.6 starting looking like it’s old self … yee, ha
  5. amend wp-config.php to add in code statement … thanks to this great advice

    define('RELOCATE',true);

    … meaning URLs such as https://[newIPaddressForRJMProgrammingIntoTheFuture]/ITblog just address data and software on [newIPaddressForRJMProgrammingIntoTheFuture] proposed new AlmaLinux9 web server (rather than ducking off to https://www.rjmprogramming.com.au/ITblog/ or https://[oldIPaddressForRJMProgrammingFromTheNearFuturePast]/ITblog/)
  6. on our way to WordPress admin section via https://[newIPaddressForRJMProgrammingIntoTheFuture]/ITblog/wp-admin into the web browser address bar …

    WordPress MySql database was updated (to align with PHP 8.1.19 and MySql 8.0.38 and WordPress 6.6 requirements)
  7. in WordPress admin section General Settings make sure both WordPress Address (URL) and Site Address (URL) get mapped to …

    https://[newIPaddressForRJMProgrammingIntoTheFuture]/ITblog

    … during our migration phase, at least
  8. practice writing …

    Blog posts

    … in WordPress Code editor (showing HTML, as we are most familiar with, but you can edit in a visual mode of use, if you like)

Feel free to see some of what we did here in video below …


Previous relevant Apache/PHP/MySql Web Hosting Website Migration ssh Tutorial is shown below.

Apache/PHP/MySql Web Hosting Website Migration ssh Tutorial

Apache/PHP/MySql Web Hosting Website Migration ssh Tutorial

One of the most amazing aspects to the Crazy Domains performed data migration for the RJM Programming domain on 17/1/2023, thanks, was the way, from our point of view, it was …

Changed No change
IP address Any usernames
Power management Any passwords
DNS mappings ssh access (just with changed IP address slotted in for old one)
sftp access
cPanel access (just with changed IP address slotted in for old one)

… with so little affecting our day to day interactions with the website.

And so, on this topic, adding to the recent Apache/PHP/MySql Web Hosting Website Migration DNS Tutorial we want to hone in on that Any usernames and Any passwords resisting any need to change. How so? Well, it’s to do with how ssh and sftp and RSA keys and Fingerprints work. Let’s ask experts some questions.

How does ssh use rsa keys to help with login?

And we liked What Is an SSH Key? Generation, Authentication, Key Pair Info & More

How does SSH RSA key work?

An SSH key relies upon the use of two related keys, a public key and a private key, that together create a key pair that is used as the secure access credential. The private key is secret, known only to the user, and should be encrypted and stored safely.

That “stored safely” is the key (chortle, chortle) to the cleverness of the system. The key is stored on the same web server disk migrated, and so access to a username’s previous password is maintained that way.

How does ssh use a fingerprint to help with login?

And we liked Check the SSH host fingerprint of a server with the web console

Secure Shell (SSH) uses a fingerprint generated with the unique server host key so that a client can identify the server. Whenever the host fingerprint changes, SSH issues the following warning: The host fingerprint can’t be verified or it has changed. When you configure the SSH server, the host key generates randomly.

And so, we can see that the fingerprint mechanism can help the user authenticate, and have the key refresh itself, in the new web server IP address environment, as you can see in today’s tutorial picture.

Cute, huh?!


Previous relevant Apache/PHP/MySql Web Hosting Website Migration DNS Tutorial is shown below.

Apache/PHP/MySql Web Hosting Website Migration DNS Tutorial

Apache/PHP/MySql Web Hosting Website Migration DNS Tutorial

Regarding Apache/PHP/MySql web hosting, and the recent Apache/PHP/MySql Web Hosting Website Migration Tutorial‘s subject matter regarding a Crazy Domains inspired Data Migration here at RJM Programming on 17/1/2023, we wanted to go over a last set of DNS setting …

The Domain Name System (DNS) is a hierarchical and distributed naming system for computers, services, and other resources in the Internet or other Internet Protocol (IP) networks. It associates various information with domain names assigned to each of the associated entities. Most prominently, it translates readily memorized domain names to the numerical IP addresses needed for locating and identifying computer services and devices with the underlying network protocols.[1] The Domain Name System has been an essential component of the functionality of the Internet since 1985.

… steps that represented that final “tying the knot” of repositioning the RJM Programming domain to a new IP address and allowing cPanel and ssh and sftp website access methods not have to change regarding username and password usage, just IP addresses, perhaps totally “behind the scenes”. Think of it like a “renaming the underbelly” exercise, perhaps!

Until these DNS settings are adjusted in “A records” up at the web hoster by the Webmaster or Web Hoster, and there is, typically, about a five minute wait afterwards, the website cannot be reached via your usual …


https://www.rjmprogramming.com.au

… web browser address bar way to navigate to the Landing Page of the RJM Programming domain.

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, Installers, Operating System, Software, Tutorials | Tagged , , , , , , , , , , | Leave a comment