Successfully Use PHP & ImageMagick

Today I’m sharing some example code to do the following all in one PHP script:

  • search Bing for an image given a keyword,
  • store the image locally,
  • add a dark overlay to that image,
  • add a curved title, and
  • add text on top of that image below the title that adjusts to the available space.

First, we’re going to create 2 parameters to be passed in “k” will represent the keyword that we’re searching for in a Bing image search and we want Bing to find a photo that is at least 300x300 pixels and has any “Creative Commons” license.  The second parameter will be “text” which will contain the text that we want to overlay on top of the image.  You can also pass in the title of the image if you choose but we’re going to use the current date for this example. We’re going to use cURL for retrieving the image result set and the image itself and ImageMagick for manipulating changes on our image.  The Bing search parameters that I have defined below are not necessary if you’re only interested in finding any image without filtering the results.  The searchUrl variable should at least contain “https://www.bing.com/images/search?q=<QUERY HERE>“.  To narrow down the Bing query results, simply use the “Filter” option and capture the URL for your script.

Below is the script for reference and we’ll walk through it afterwards.

<?php

$keyword = $_GET[“k”];
$theText = isset($_GET[“text”]) ? str_replace(“%20″,” “,$_GET[“text”]) : “Some very\n long text that needs to be placed on the image somewhere \nindeed what should \nI do now I have \nno idea lorem ipsum lorem ipsum what \nwhat what now now now how how how \nwhy why why when when when”;
$urlKey = str_replace(” “,”+”,$keyword);
$searchUrl = “http://www.bing.com/images/search?pq=”.$urlKey.”&q=”.$urlKey.”&qft=+filterui:imagesize-custom_300_300+filterui:licenseType-Any+filterui:photo-photo&FORM=IRFLTR”;

$output = getUrl($searchUrl);
preg_match_all(‘!<a class=”thumb” target=”_blank” href=”(.*?)”!’, $output,$url_matches);
//$url_matches[1] is an array of images matching search criteria

downloadImage($url_matches[1][0]);

function getUrl($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
function downloadImage($url){
global $theText;
preg_match_all(“!.*?/!”,$url,$slashMatch);
preg_match(“!”.end($slashMatch[0]).”(.*?.*)!”,$url, $imageNameArray);
$imageName = str_replace(“+”,”-“,$imageNameArray[1]);
$imageNameNoExtension = substr($imageName, 0, strrpos($imageName, ‘.’));
$fp = fopen($imageName, “w+”);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_AUTOREFERER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_USERAGENT, ‘Mozilla/5.0’);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,0);
curl_setopt($ch, CURLOPT_TIMEOUT, 400); //timeout in seconds
$imageData = curl_exec($ch);
curl_close($ch);
fwrite($fp, $imageData);
fclose($fp);

$dateText = date(‘F j, Y’);
$theTitle = $dateText;
$textColor = “white”;
$convertCmd = ‘/usr/local/bin/convert’;

$imCmd = $convertCmd.’ ‘.$imageName.’ -resize 500x500 -size 500x500 -frame 500x500 xc:black +swap -gravity center -write mpr:image -composite ‘.$imageName;
echo $imCmd.”<br>”;
exec($imCmd);

//add a dark transparent overlay
$imCmd = $convertCmd.’ ‘.$imageName.’ ‘;
$imCmd .= ” \( -clone 0 -fill ‘#000000A0’ -alpha set -draw ‘color 0,0 reset’ \) -compose atop -composite “.$imageNameNoExtension.”.png”;
echo $imCmd.”<br>”;
exec($imCmd);

//resize it to 500x500
//add the title
$imCmd = $convertCmd.’ ‘.$imageNameNoExtension.’.png -thumbnail 500x500 -write mpr:image +delete ‘;
$imCmd .= ‘-pointsize 30 -fill ‘.$textColor.’ -background none label:”‘.$theTitle.'” -virtual-pixel transparent -distort arc 60 -write mpr:arc +delete ‘;
$imCmd .= ‘mpr:image mpr:arc -gravity north -composite ‘.$imageNameNoExtension.’.png’;
echo $imCmd.”<br>”;
exec($imCmd);

//add the text
$imCmd = $convertCmd.’ ‘.$imageNameNoExtension.’.png -background none ‘;//-annotate +10+60
$imCmd .= ” -fill ‘”.$textColor.”‘ “;
$imCmd .= “-size 480x350 -font ComicSans caption:'”.$theText.”‘ “;
$imCmd .= “-gravity NorthWest -geometry +10+60 -composite “.$imageNameNoExtension.’.png’;
echo $imCmd.”<br>”;
exec($imCmd);

echo “<img src='”.$imageNameNoExtension.”.png’>”;
}

Let’s say that I use the keyword “deer” and example text for the query parameter “text”, here’s what it would look like with the script to the left: If you happen to see timeouts, use the following methods to extend the timeout period so the search image has enough time to download: set_time_limit(0); //PHP script timeout curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,0); // wait indefinitely curl_setopt($ch, CURLOPT_TIMEOUT, 400); //timeout in seconds for cURL

There are two methods in the script, getUrl simply goes out to the Bing search URL, pulls back the HTML of the search, and the first step finds all of the thumbnail images on the screen and gives us an array of all thumbnails and the target image URL:

$output = getUrl($searchUrl); preg_match_all(‘!

Next, we’re going to get the first image from the query image result and download it (feel free to change the name of the file here by updating the $imageName variable).

  preg_match_all("!.*?/!",$url,$slashMatch);
preg_match("!".end($slashMatch[0])."(.*?.*)!",$url, $imageNameArray);
$imageName = str_replace("+","-",$imageNameArray[1]);
$imageNameNoExtension = substr($imageName, 0, strrpos($imageName, '.'));
$fp = fopen(dirname(__FILE__).'/'.$imageName, "w");
$ch = curl_init($url);
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_VERBOSE, 1);
  curl_setopt($ch, CURLOPT_AUTOREFERER, false);
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0');
  curl_setopt($ch, CURLOPT_HEADER, 0);
  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,0); 
  curl_setopt($ch, CURLOPT_TIMEOUT, 400); //timeout in seconds
  $imageData = curl_exec($ch);
  curl_close($ch);
  fwrite($fp, $imageData);
  fclose($fp);

The next step will resize the image to 500x500 pixels and keep the aspect ratio of the image while creating a black background color for the area outside of the scaled image (similar to the black bars on 16:9 ratio movies).  Here we’re defining today’s date as the title, we’re setting all of the text color to white, and we’re pointing to the “convert” command.  In order to accurately run the convert utility, use SSH and the command “which convert”.  Update the $convertCmd value with the result of the command.

  $dateText = date(‘F j, Y’); $theTitle = $dateText; $textColor = “white”; $convertCmd = ‘convert’;//’/usr/local/bin/convert’; $imCmd = $convertCmd.’ ‘.dirname(__FILE__).’/’.$imageName.’ -resize 500x500 -size 500x500 -frame 500x500 xc:black +swap -gravity center -write mpr:image -composite ‘.$imageName; exec($imCmd);

We will then add a dark transparency overlay on top of the image and convert the image to a PNG file so that we can retain transparency (even if the image is not a PNG file to begin with).

$imCmd = $convertCmd.’ ‘.$imageName.’ ‘; $imCmd .= ” \( -clone 0 -fill ‘#000000A0’ -alpha set -draw ‘color 0,0 reset’ \) -compose atop -composite “.$imageNameNoExtension.”.png”; exec($imCmd);

Next we’ll take the new PNG image and add the arched title with an arc of 60 degrees and with a font size of 30 pixels at the top of the image.

$imCmd = $convertCmd.’ ‘.$imageNameNoExtension.’.png -thumbnail 500x500 -write mpr:image +delete ‘; $imCmd .= ‘-pointsize 30 -fill ‘.$textColor.’ -background none label:”‘.$theTitle.'” -virtual-pixel transparent -distort arc 60 -write mpr:arc +delete ‘; $imCmd .= ‘mpr:image mpr:arc -gravity north -composite ‘.$imageNameNoExtension.’.png’; exec($imCmd);

Finally, we’ll add the text on top of the new image just below the title and we’ll have it fit the area between the title and the bottom of the image.

$imCmd = $convertCmd.’ ‘.$imageNameNoExtension.’.png -background none ‘;//-annotate +10+60 $imCmd .= ” -fill ‘”.$textColor.”‘ “; $imCmd .= “-size 480x350 -font ComicSans caption:'”.$theText.”‘ “; $imCmd .= “-gravity NorthWest -geometry +10+60 -composite “.$imageNameNoExtension.’.png’; exec($imCmd);

Now that we have a PNG created exactly how we want, all we have to do is display it inside of a HTML img tag:

echo “<img src='”.$imageNameNoExtension.”.png’>”;

Simple enough, right?  With the power of ImageMagick, it’s easy to autonomously achieve the image manipulation that you need.
%d bloggers like this: