<p><div><div><div><div data-show-faces="false" data-height="21" data-width="100" data-layout="button_count" data-send="true" data-href="https://www.r-bloggers.com/building-the-oomsifyer/"></div></div><div></div></div><div></div></div>
<div>
(This article was first published on <strong><a href="http://rmhogervorst.nl/cleancode/blog/2017/11/28/building-the-oomsifier.html"> Clean Code</a></strong>, and kindly contributed to <a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers)</a> </div>
<p>Today I will show you a quick hack (OK it took me like 4 hours during my travels today yesterday and today),<br>
on how to add a dancing banana to any picture.</p>
<p>Now, you might be thinking… Really, why would you add a dancing banana to<br>
a picture, but I don’t have time for that kind of negativity in my life.</p>
<p><img alt="" src="https://i0.wp.com/rmhogervorst.nl/cleancode/images/r-pkg.gif?w=456" data-recalc-dims="1"></p>
<h2>Why oomsifier?</h2>
<p>Jeroen Ooms is one of those crazy productive people in the R world. The way he<br>
wraps c++ libraries into packages makes you think his middle name is c-plus-plus.</p>
<p>At the Sat-R-day in budapest in 2016 (?) Jeroen demonstrated the magick library.<br>
You can now control images from inside R using dark magic and the bindings to<br>
the magick library. In honor of this work and because I needed a cool name,<br>
I will demonstrate <strong>THE OOMSIFYER</strong>.</p>
<blockquote>
<p>Solving the life long dream of people all around the world … of adding dancing banana gifs to pictures…</p>
</blockquote>
<p>If you are like me, you would have thought this would be really easy, but you would be wrong.</p>
<p>First the function then the explanation and some stuff that took me waaay too long<br>
to find out.</p>
<p>The function</p>
<div>
<div>
<pre><code><span>banana</span><span> </span><span>&lt;-</span><span> </span><span>image_read</span><span>(</span><span>&quot;images/banana.gif&quot;</span><span>)</span><span> </span><span># this assumes you have a project with the folder /images/ inside.</span><span>
</span><span>add_banana</span><span> </span><span>&lt;-</span><span> </span><span>function</span><span>(</span><span>image</span><span>,</span><span> </span><span>offset</span><span> </span><span>=</span><span> </span><span>NULL</span><span>,</span><span> </span><span>debug</span><span> </span><span>=</span><span> </span><span>FALSE</span><span>){</span><span>
</span><span>image_in</span><span> </span><span>&lt;-</span><span> </span><span>magick</span><span>::</span><span>image_read</span><span>(</span><span>image</span><span>)</span><span>
</span><span>banana</span><span> </span><span>&lt;-</span><span> </span><span>image_read</span><span>(</span><span>&quot;images/banana.gif&quot;</span><span>)</span><span> </span><span># 365w 360 h</span><span>
</span><span>image_info</span><span> </span><span>&lt;-</span><span> </span><span>image_info</span><span>(</span><span>image_in</span><span>)</span><span>
</span><span>if</span><span>(</span><span>&quot;gif&quot;</span><span> </span><span>%in%</span><span> </span><span>image_info</span><span>$</span><span>format</span><span> </span><span>){</span><span>stop</span><span>(</span><span>&quot;gifs are to difficult for me now&quot;</span><span>)}</span><span>
</span><span>stopifnot</span><span>(</span><span>nrow</span><span>(</span><span>image_info</span><span>)</span><span>==</span><span>1</span><span>)</span><span>
</span><span># scale banana to correct size:</span><span>
</span><span># take smallest dimension.</span><span>
</span><span>target_height</span><span> </span><span>&lt;-</span><span> </span><span>min</span><span>(</span><span>image_info</span><span>$</span><span>width</span><span>,</span><span> </span><span>image_info</span><span>$</span><span>height</span><span>)</span><span>
</span><span># scale banana to 1/3 of the size</span><span>
</span><span>scaling</span><span> </span><span>&lt;-</span><span> </span><span>(</span><span>target_height</span><span> </span><span>/</span><span>3</span><span>)</span><span>
</span><span>front</span><span> </span><span>&lt;-</span><span> </span><span>image_scale</span><span>(</span><span>banana</span><span>,</span><span> </span><span>scaling</span><span>)</span><span>
</span><span># place in lower right corner</span><span>
</span><span># offset is width and hieight minus dimensions picutre?</span><span>
</span><span>scaled_dims</span><span> </span><span>&lt;-</span><span> </span><span>image_info</span><span>(</span><span>front</span><span>)</span><span>
</span><span>x_c</span><span> </span><span>&lt;-</span><span> </span><span>image_info</span><span>$</span><span>width</span><span> </span><span>-</span><span> </span><span>scaled_dims</span><span>$</span><span>width</span><span>
</span><span>y_c</span><span> </span><span>&lt;-</span><span> </span><span>image_info</span><span>$</span><span>height</span><span> </span><span>-</span><span> </span><span>scaled_dims</span><span>$</span><span>height</span><span>
</span><span>offset_value</span><span> </span><span>&lt;-</span><span> </span><span>ifelse</span><span>(</span><span>is.null</span><span>(</span><span>offset</span><span>),</span><span> </span><span>paste0</span><span>(</span><span>&quot;+&quot;</span><span>,</span><span>x_c</span><span>,</span><span>&quot;+&quot;</span><span>,</span><span>y_c</span><span>),</span><span> </span><span>offset</span><span>)</span><span>
</span><span>if</span><span>(</span><span>debug</span><span>)</span><span> </span><span>print</span><span>(</span><span>offset_value</span><span>)</span><span>
</span><span>frames</span><span> </span><span>&lt;-</span><span> </span><span>lapply</span><span>(</span><span>as.list</span><span>(</span><span>front</span><span>),</span><span> </span><span>function</span><span>(</span><span>x</span><span>)</span><span> </span><span>image_composite</span><span>(</span><span>image_in</span><span>,</span><span> </span><span>x</span><span>,</span><span> </span><span>offset</span><span> </span><span>=</span><span> </span><span>offset_value</span><span>))</span><span>
</span><span>result</span><span> </span><span>&lt;-</span><span> </span><span>image_animate</span><span>(</span><span>image_join</span><span>(</span><span>frames</span><span>),</span><span> </span><span>fps</span><span> </span><span>=</span><span> </span><span>10</span><span>)</span><span>
</span><span>result</span><span>
</span><span>}</span><span>
</span></code></pre>
</div>
</div>
<h2>So what can it do?</h2>
<p>This function takes an image, f.i. a ggplot2 image that you saved to disk, and adds the dancing banana gif to the bottom right corner.</p>
<p><img alt="ggplot with banana example" src="https://i2.wp.com/rmhogervorst.nl/cleancode/images/ggplot.gif?w=456" data-recalc-dims="1"></p>
<p>I had to combine information from the magick <a rel="nofollow" href="https://cran.r-project.org/web/packages/magick/vignettes/intro.html#animation" target="_blank">vignette</a> and an earlier <a rel="nofollow" href="https://ropensci.org/blog/2016/08/23/z-magick-release/" target="_blank">blogpost</a> about magick in R.</p>
<p>Things I learned:</p>
<ul>
<li>the magick package returns image information as a data frame</li>
<li>a gif is a succesion of images (frames)</li>
<li>a normal picture is a single frame</li>
<li>to combine a gif and a single frame you have to have exactly as much frames of your original picture as the number of frames in the gif</li>
<li>for every frame you have to merge the gif and image with each other into a composite image</li>
<li>the offset is the number of pixels from the left of the frame and from the top of the frame. I wanted to put the dancing banana at the bottom right of the picture AND I wanted to scale the banana so that it would take over the entire image so the offset needed to be responsive to both scaling and the input dimensions</li>
<li><a rel="nofollow" href="https://twitter.com/ThePracticalDev" target="_blank">the practical dev</a> has many silly o-reilly like book covers that I find hilarious</li>
</ul>
<p><img alt="spss picture" src="https://i2.wp.com/rmhogervorst.nl/cleancode/images/spss.gif?w=456" data-recalc-dims="1"></p>
<p>In a the following posts I might turn this function into an API, stay tuned!</p>
<p><a rel="nofollow" href="http://rmhogervorst.nl/cleancode/blog/2017/11/28/building-the-oomsifier.html" target="_blank">Building the oomsifyer</a> was originally published by at <a rel="nofollow" href="http://rmhogervorst.nl/cleancode" target="_blank">Clean Code</a> on November 28, 2017.</p>
	<p>
<div>
<div>To <strong>leave a comment</strong> for the author, please follow the link and comment on their blog: <strong><a href="http://rmhogervorst.nl/cleancode/blog/2017/11/28/building-the-oomsifier.html"> Clean Code</a></strong>.</div>
<hr>
<a rel="nofollow" href="https://www.r-bloggers.com/">R-bloggers.com</a> offers <strong><a rel="nofollow" href="https://feedburner.google.com/fb/a/mailverify?uri=RBloggers">daily e-mail updates</a></strong> about <a rel="nofollow" href="https://www.r-project.org/" title="The R Project for Statistical Computing">R</a> news and <a rel="nofollow" href="https://www.r-bloggers.com/search/tutorial" title="R tutorials">tutorials</a> on topics such as: <a rel="nofollow" href="https://www.r-bloggers.com/search/data%20science" title="Data science">Data science</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Big%20Data" title="Big Data">Big Data, <a rel="nofollow" href="https://www.r-users.com/" title="R jobs">R jobs</a>, visualization (<a rel="nofollow" href="https://www.r-bloggers.com/search/ggplot2" title="ggplot and ggplot2 tutorials">ggplot2</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/boxplot" title="Boxplots using lattice and ggplot2 tutorials">Boxplots</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/map" title="Maps and gis">maps</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/animation" title="Animation in R">animation</a>), programming (<a rel="nofollow" href="https://www.r-bloggers.com/search/RStudio" title="RStudio IDE for R">RStudio</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/sweave" title="Sweave and literate programming">Sweave</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/LaTeX" title="LaTeX in R">LaTeX</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/SQL" title="SQL and databases">SQL</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/eclipse" title="Eclipse IDE for R">Eclipse</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/git" title="git and github, Version Control System">git</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/hadoop" title="Large data in R using Hadoop">hadoop</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/Web+Scraping" title="Web Scraping of google, facebook, yahoo, twitter and more using R">Web Scraping</a>) statistics (<a rel="nofollow" href="https://www.r-bloggers.com/search/regression" title="Regressions and ANOVA analysis tutorials">regression</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/PCA" title="principal component analysis tutorial">PCA</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/time+series" title="Time series">time series</a>, <a rel="nofollow" href="https://www.r-bloggers.com/search/trading" title="finance trading">trading</a>) and more...
<img width="1" alt="" src="http://feeds.feedburner.com/~r/RBloggers/~4/jw6VSVvBSpI" height="1"></a></div>