Ffmpeg Video Overall Effects Tutorial

Ffmpeg Video Overall Effects Tutorial

Ffmpeg Video Overall Effects Tutorial

Today’s work (all on our macOS MAMP local Apache/PHP/MySQL web server environment) is only “toe dipping” in a “great big sea of possibilities” regarding the great ffmpeg‘s “filtering style abilities” further to yesterday’s Ffmpeg Video Subliminal Message Tutorial, but …

  • as you try out things you discover others …
  • can be a foot in the door researching this type of work yourself …

… we’re hoping. And it’s not as if ffmpeg was on it’s own here with the second concept below …

  1. fade in and fade out video effect … inspired by Top 20 best commands for FFmpeg to try …

    ffmpeg -i brush__turkey.m4v -vf "fade=in:0:5,fade=out:73:5" brushturkey_fadein_fadeout.m4v
  2. colour balancing improvements regarding an underexposed video

… as the …

  • Gimp image editor’s abilities (matching a lot of what you read Photoshop can help with too) with Curves helped out … along with …
  • Python expertly designed to link Gimp and ffmpeg “whole of video” manipulations

… enacting …

  1. selection of a video still image, ideally not containing the Brush Turkey …
  2. open image in Gimp
  3. “Aoife”‘esque Colours -> Curves…
  4. opens Adjust Colour Curves subwindow (initially a straight line)
  5. but dragging it to become a curve in a way that brightens the underexposed image to improve … we then …
  6. click + button to Save presets to a name …
  7. controlled by left pointing infilled triangle icon click that Manages Presets … and we ended up with …
  8. bush_-_turkey.presets


  9. and then we discovered this Converts GIMP colour curve to something the FFmpeg can read in the curve filter excellent project, the extraction of the Python there allowing us to go …

    python3 ../gimp_curves_ffmpeg.py

    … to output brush.out

  10. which formed most of the final curves — ffmpeg examples inspired ffmpeg command …

    ffmpeg -y -i brush__turkey.m4v -filter_complex "
    [0:v]
    curves=
    master='0.0/0 0.01171875/0.033751864777061671 0.0234375/0.067435644319434537 0.03515625/0.10098325339242978 0.046875/0.1343266067613586 0.05859375/0.16739761919153215 0.0703125/0.20012820544826168 0.08203125/0.23245028029685835 0.09375/0.26429575850263332 0.10546875/0.29559655483089792 0.1171875/0.32628458404696314 0.12890625/0.35629176091614018 0.140625/0.38555000020374036 0.15234375/0.41399121667507488 0.1640625/0.44154732509545486 0.17578125/0.46815024023019147 0.1875/0.49373187684459596 0.19921875/0.51822414970397945 0.2109375/0.54155897357365324 0.22265625/0.56366826321892849 0.234375/0.58448393340511628 0.24609375/0.6039378988975278 0.2578125/0.62196207446147445 0.26953125/0.63848837486226717 0.28125/0.65344871486521738 0.29296875/0.66677500923563593 0.3046875/0.67964838149075235 0.31640625/0.6910493179152648 0.328125/0.70214399210941336 0.33984375/0.71293769240972005 0.3515625/0.72343570715270744 0.36328125/0.73364332467489723 0.375/0.74356583331281156 0.38671875/0.75320852140297312 0.3984375/0.76257667728190348 0.41015625/0.77167558928612512 0.421875/0.78051054575216006 0.43359375/0.78908683501653032 0.4453125/0.7974097454157586 0.45703125/0.80548456528636625 0.46875/0.81331658296487608 0.48046875/0.82091108678780988 0.4921875/0.82827336509169003 0.50390625/0.83540870621303842 0.515625/0.84232239848837742 0.52734375/0.84901973025422939 0.5390625/0.85550598984711601 0.55078125/0.86178646560355965 0.5625/0.86786644586008233 0.57421875/0.87375121895320629 0.5859375/0.87944607321945378 0.59765625/0.88495629699534695 0.609375/0.89028717861740791 0.62109375/0.89544400642215893 0.6328125/0.90043206874612158 0.64453125/0.90525665392581867 0.65625/0.9099230502977721 0.66796875/0.91443654619850423 0.6796875/0.91880242996453687 0.69140625/0.92302598993239249 0.703125/0.92711251443859277 0.71484375/0.93106729181966053 0.7265625/0.93489561041211733 0.73828125/0.93860275855248565 0.75/0.94219402457728751 0.76171875/0.94567469682304517 0.7734375/0.94905006362628086 0.78515625/0.95232541332351639 0.796875/0.95550603425127423 0.80859375/0.9585972147460764 0.8203125/0.96160424314444504 0.83203125/0.96453240778290228 0.84375/0.96738699699797048 0.85546875/0.97017329912617156 0.8671875/0.97289660250402765 0.87890625/0.97556219546806111 0.890625/0.97817536635479407 0.90234375/0.98074140350074845 0.9140625/0.98326559524244661 0.92578125/0.98575322991641046 0.9375/0.98820959585916268 0.94921875/0.99063998140722487 0.9609375/0.99304967489711937 0.97265625/0.99544396466536833 0.984375/0.9978281390484941 0.99609375/1":red="0.0/0 0.01171875/0.011764705882352943 0.0234375/0.023529411764705879 0.03515625/0.035294117647058816 0.046875/0.047058823529411764 0.05859375/0.058823529411764712 0.0703125/0.07058823529411766 0.08203125/0.082352941176470587 0.09375/0.094117647058823528 0.10546875/0.10588235294117647 0.1171875/0.11764705882352938 0.12890625/0.12941176470588237 0.140625/0.14117647058823532 0.15234375/0.15294117647058825 0.1640625/0.1647058823529412 0.17578125/0.17647058823529413 0.1875/0.18823529411764706 0.19921875/0.20000000000000007 0.2109375/0.21176470588235291 0.22265625/0.22352941176470589 0.234375/0.23529411764705882 0.24609375/0.24705882352941175 0.2578125/0.25882352941176473 0.26953125/0.27058823529411768 0.28125/0.28235294117647064 0.29296875/0.29411764705882348 0.3046875/0.30588235294117649 0.31640625/0.31764705882352934 0.328125/0.3294117647058824 0.33984375/0.3411764705882353 0.3515625/0.35294117647058826 0.36328125/0.3647058823529411 0.375/0.37647058823529411 0.38671875/0.38823529411764712 0.3984375/0.39999999999999997 0.41015625/0.41176470588235292 0.421875/0.42352941176470582 0.43359375/0.43529411764705883 0.4453125/0.44705882352941184 0.45703125/0.45882352941176474 0.46875/0.47058823529411764 0.48046875/0.48235294117647054 0.4921875/0.49411764705882355 0.50390625/0.50588235294117645 0.515625/0.51764705882352946 0.52734375/0.52941176470588236 0.5390625/0.54117647058823526 0.55078125/0.55294117647058827 0.5625/0.56470588235294117 0.57421875/0.57647058823529407 0.5859375/0.58823529411764708 0.59765625/0.59999999999999998 0.609375/0.61176470588235299 0.62109375/0.62352941176470589 0.6328125/0.63529411764705879 0.64453125/0.6470588235294118 0.65625/0.65882352941176481 0.66796875/0.6705882352941176 0.6796875/0.68235294117647061 0.69140625/0.69411764705882351 0.703125/0.70588235294117663 0.71484375/0.71764705882352942 0.7265625/0.7294117647058822 0.73828125/0.74117647058823533 0.75/0.75294117647058822 0.76171875/0.76470588235294112 0.7734375/0.77647058823529425 0.78515625/0.78823529411764703 0.796875/0.80000000000000004 0.80859375/0.81176470588235294 0.8203125/0.82352941176470584 0.83203125/0.83529411764705874 0.84375/0.84705882352941175 0.85546875/0.85882352941176465 0.8671875/0.87058823529411766 0.87890625/0.88235294117647056 0.890625/0.89411764705882357 0.90234375/0.90588235294117636 0.9140625/0.91764705882352937 0.92578125/0.92941176470588238 0.9375/0.94117647058823528 0.94921875/0.95294117647058818 0.9609375/0.96470588235294119 0.97265625/0.97647058823529409 0.984375/0.98823529411764721 0.99609375/1":green="0.0/0 0.01171875/0.011764705882352943 0.0234375/0.023529411764705879 0.03515625/0.035294117647058816 0.046875/0.047058823529411764 0.05859375/0.058823529411764712 0.0703125/0.07058823529411766 0.08203125/0.082352941176470587 0.09375/0.094117647058823528 0.10546875/0.10588235294117647 0.1171875/0.11764705882352938 0.12890625/0.12941176470588237 0.140625/0.14117647058823532 0.15234375/0.15294117647058825 0.1640625/0.1647058823529412 0.17578125/0.17647058823529413 0.1875/0.18823529411764706 0.19921875/0.20000000000000007 0.2109375/0.21176470588235291 0.22265625/0.22352941176470589 0.234375/0.23529411764705882 0.24609375/0.24705882352941175 0.2578125/0.25882352941176473 0.26953125/0.27058823529411768 0.28125/0.28235294117647064 0.29296875/0.29411764705882348 0.3046875/0.30588235294117649 0.31640625/0.31764705882352934 0.328125/0.3294117647058824 0.33984375/0.3411764705882353 0.3515625/0.35294117647058826 0.36328125/0.3647058823529411 0.375/0.37647058823529411 0.38671875/0.38823529411764712 0.3984375/0.39999999999999997 0.41015625/0.41176470588235292 0.421875/0.42352941176470582 0.43359375/0.43529411764705883 0.4453125/0.44705882352941184 0.45703125/0.45882352941176474 0.46875/0.47058823529411764 0.48046875/0.48235294117647054 0.4921875/0.49411764705882355 0.50390625/0.50588235294117645 0.515625/0.51764705882352946 0.52734375/0.52941176470588236 0.5390625/0.54117647058823526 0.55078125/0.55294117647058827 0.5625/0.56470588235294117 0.57421875/0.57647058823529407 0.5859375/0.58823529411764708 0.59765625/0.59999999999999998 0.609375/0.61176470588235299 0.62109375/0.62352941176470589 0.6328125/0.63529411764705879 0.64453125/0.6470588235294118 0.65625/0.65882352941176481 0.66796875/0.6705882352941176 0.6796875/0.68235294117647061 0.69140625/0.69411764705882351 0.703125/0.70588235294117663 0.71484375/0.71764705882352942 0.7265625/0.7294117647058822 0.73828125/0.74117647058823533 0.75/0.75294117647058822 0.76171875/0.76470588235294112 0.7734375/0.77647058823529425 0.78515625/0.78823529411764703 0.796875/0.80000000000000004 0.80859375/0.81176470588235294 0.8203125/0.82352941176470584 0.83203125/0.83529411764705874 0.84375/0.84705882352941175 0.85546875/0.85882352941176465 0.8671875/0.87058823529411766 0.87890625/0.88235294117647056 0.890625/0.89411764705882357 0.90234375/0.90588235294117636 0.9140625/0.91764705882352937 0.92578125/0.92941176470588238 0.9375/0.94117647058823528 0.94921875/0.95294117647058818 0.9609375/0.96470588235294119 0.97265625/0.97647058823529409 0.984375/0.98823529411764721 0.99609375/1":blue="0.0/0 0.01171875/0.011764705882352943 0.0234375/0.023529411764705879 0.03515625/0.035294117647058816 0.046875/0.047058823529411764 0.05859375/0.058823529411764712 0.0703125/0.07058823529411766 0.08203125/0.082352941176470587 0.09375/0.094117647058823528 0.10546875/0.10588235294117647 0.1171875/0.11764705882352938 0.12890625/0.12941176470588237 0.140625/0.14117647058823532 0.15234375/0.15294117647058825 0.1640625/0.1647058823529412 0.17578125/0.17647058823529413 0.1875/0.18823529411764706 0.19921875/0.20000000000000007 0.2109375/0.21176470588235291 0.22265625/0.22352941176470589 0.234375/0.23529411764705882 0.24609375/0.24705882352941175 0.2578125/0.25882352941176473 0.26953125/0.27058823529411768 0.28125/0.28235294117647064 0.29296875/0.29411764705882348 0.3046875/0.30588235294117649 0.31640625/0.31764705882352934 0.328125/0.3294117647058824 0.33984375/0.3411764705882353 0.3515625/0.35294117647058826 0.36328125/0.3647058823529411 0.375/0.37647058823529411 0.38671875/0.38823529411764712 0.3984375/0.39999999999999997 0.41015625/0.41176470588235292 0.421875/0.42352941176470582 0.43359375/0.43529411764705883 0.4453125/0.44705882352941184 0.45703125/0.45882352941176474 0.46875/0.47058823529411764 0.48046875/0.48235294117647054 0.4921875/0.49411764705882355 0.50390625/0.50588235294117645 0.515625/0.51764705882352946 0.52734375/0.52941176470588236 0.5390625/0.54117647058823526 0.55078125/0.55294117647058827 0.5625/0.56470588235294117 0.57421875/0.57647058823529407 0.5859375/0.58823529411764708 0.59765625/0.59999999999999998 0.609375/0.61176470588235299 0.62109375/0.62352941176470589 0.6328125/0.63529411764705879 0.64453125/0.6470588235294118 0.65625/0.65882352941176481 0.66796875/0.6705882352941176 0.6796875/0.68235294117647061 0.69140625/0.69411764705882351 0.703125/0.70588235294117663 0.71484375/0.71764705882352942 0.7265625/0.7294117647058822 0.73828125/0.74117647058823533 0.75/0.75294117647058822 0.76171875/0.76470588235294112 0.7734375/0.77647058823529425 0.78515625/0.78823529411764703 0.796875/0.80000000000000004 0.80859375/0.81176470588235294 0.8203125/0.82352941176470584 0.83203125/0.83529411764705874 0.84375/0.84705882352941175 0.85546875/0.85882352941176465 0.8671875/0.87058823529411766 0.87890625/0.88235294117647056 0.890625/0.89411764705882357 0.90234375/0.90588235294117636 0.9140625/0.91764705882352937 0.92578125/0.92941176470588238 0.9375/0.94117647058823528 0.94921875/0.95294117647058818 0.9609375/0.96470588235294119 0.97265625/0.97647058823529409 0.984375/0.98823529411764721 0.99609375/1'
    [v]" -map '[v]' -an brushturkey_better_colour.m4v

… was crucial to our discoveries today

  1. fade in and fade out video effect …
  2. colour balancing improvements regarding an underexposed video …

Further reading for you here, could involve …


Previous relevant Ffmpeg Video Subliminal Message Tutorial is shown below.

Ffmpeg Video Subliminal Message Tutorial

Ffmpeg Video Subliminal Message Tutorial

Revisiting the brilliant ffmpeg, as discussed at the recent Ffmpeg Install and Public Face Tutorial

  • the other day we were reading the excellent Fastest way to extract frames using ffmpeg? and noted it down for a future discussion … and then today …
  • we were inspired by a Brush Turkey which we videoed via an iPhone’s Camera app’s Video mode of capture option …
  • downloaded to this MacBook Air (via AirDrop … good for Apple sharing when the sizes get big … raw video 1:19s long)

And that’s where we are at here, thinking this would be a good opportunity to try creating a Subliminal Message video. But before we go on and “give the game away” you may want to see the result of our Subliminal Message insertion via ffmpeg theme to our work, in action, below. Unlock or give up to unlock the content below the video quiz below …

What is the secret word?
Raw video … to it’s slides …
ffmpeg -i ../IMG_2784.MOV -r 1/1 %03d.jpg
ffmpeg -i %03d.jpg brush_turkey.m4v
Hard guess?
ffmpeg -r 8 -i %03d.jpg brush-turkey.m4v
Easier guess?
ffmpeg -r 6 -i %03d.jpg brush__turkey.m4v


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 Animation, eLearning, GIMP, Photography, Tutorials | Tagged , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Ffmpeg Video Subliminal Message Tutorial

Ffmpeg Video Subliminal Message Tutorial

Ffmpeg Video Subliminal Message Tutorial

Revisiting the brilliant ffmpeg, as discussed at the recent Ffmpeg Install and Public Face Tutorial

  • the other day we were reading the excellent Fastest way to extract frames using ffmpeg? and noted it down for a future discussion … and then today …
  • we were inspired by a Brush Turkey which we videoed via an iPhone’s Camera app’s Video mode of capture option …
  • downloaded to this MacBook Air (via AirDrop … good for Apple sharing when the sizes get big … raw video 1:19s long)

And that’s where we are at here, thinking this would be a good opportunity to try creating a Subliminal Message video. But before we go on and “give the game away” you may want to see the result of our Subliminal Message insertion via ffmpeg theme to our work, in action, below. Unlock or give up to unlock the content below the video quiz below …

What is the secret word?
Raw video … to it’s slides …
ffmpeg -i ../IMG_2784.MOV -r 1/1 %03d.jpg
ffmpeg -i %03d.jpg brush_turkey.m4v
Hard guess?
ffmpeg -r 8 -i %03d.jpg brush-turkey.m4v
Easier guess?
ffmpeg -r 6 -i %03d.jpg brush__turkey.m4v


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

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