Dynamic Image Merging w/Text from RSS Feed via PHP



A good coder is a lazy coder, and I revel in my laziness. Most of my websites feature image slideshows on the front with content that constantly needs to be updated, so I was looking for ways to automate the process. I decided to write a script that would import the content from an RSS feed, but I was still left with the image issue. Then it hit me; why not pull images directly from the feed an dynamically resize them? So I created this proof of concept using the Yahoo! Top News Stories RSS feed – the script imports the feed > selects a random item from the group > parses the description to get the thumbnail image > parses the URL to determine the full size image > imports the full size image via cURL > applies some filters to make it look newspaper-y > resizes it > applies it to a newspaper background > adds the title and description from the item to the image > outputs the image to the browser, on the fly. You can view the image above to see this; either refresh the page to grab new content or click the image to open in a new window and then refresh the image a few times. Code below.

<?php
//check out more shit at http://www.halnesbitt.com

ini_set('memory_limit', '100M');

$ch = curl_init(); 
$timeout = 20; 
curl_setopt ($ch, CURLOPT_URL, 'http://news.yahoo.com/rss/'); 
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1); 
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout); 
$xml = curl_exec($ch); 
curl_close($ch); 

$rss = simplexml_load_string($xml);

$total = count($rss->channel->item);
$random = rand(0, $total);

$count = 0;
foreach($rss->channel->item as $item) {
	if($count == $random) {

		$title =  $item->title;
 		$title = preg_replace('/[^(\x20-\x7F)]*/','', $title); //clean the bullshit ascii
		$title = substr($title,0,70); //keep the title from spilling over
		$desc =  strip_tags($item->description);
		$desc = preg_replace('/[^(\x20-\x7F)]*/','', $desc); //clean the bullshit ascii
		$link = $item->link;
		$pubDate = $item->pubDate;
		$pubDateFormatted = date('l F d, Y', strtotime($item->pubDate));

		//extract the image from the description
		preg_match('@@Uims', $item->description, $matches); 
		$src = $matches[1];
		$fullsize = substr($src,strrpos($src, "http://"));
		if($fullsize == "") {
			$noimage = "Y";
		}

		//set defaults if the item is empty
		if($title == "") {
			$title = "Dynamic News Image";
			$desc = "This script parses an RSS feed and grabs the item and outputs it as an image. It uses detection to find the fullsize image from the thumbnail and will display a random item from the current set on each 

load. You are seeing this message because the random item selected happened to be a blank node.";
			$link = "http://www.halnesbitt.com";
			$pubDate = date("D, d M Y H:i:s T");
			$pubDateFormatted = date('l F d, Y', strtotime($pubDate));
		}

	}
	$count++;
	
}
 
if($noimage != "Y") {
	//run another curl to get the image
	$ch = curl_init(); 
	$timeout = 20; 
	curl_setopt ($ch, CURLOPT_URL, $fullsize); 
	curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1); 
	curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout); 
	$remoteImage = curl_exec($ch); 
	curl_close($ch);
	$photo = imagecreatefromstring($remoteImage);

	$old_width = imagesx($photo);
	$old_height = imagesy($photo);

	$layout_width = 845;
	$layout_height = 560;


	$original_aspect = $old_width / $old_height;
	$layout_aspect = $layout_width / $layout_height;

	if($original_aspect >= $layout_aspect) {   
	// If image is wider than thumbnail (in aspect ratio sense)   
		$new_height = $layout_height;   
		$new_width = $old_width / ($old_height / $layout_height);
	} else {   
	// If the thumbnail is wider than the image   
		$new_width = $layout_width;   
		$new_height = $old_height / ($old_width / $layout_width);
	}

	$src_x = ($new_width - $layout_width) / 2;
	$src_y = ($new_height - $layout_height) / 2;

	//create the background
	$bg_img = imagecreatefromjpeg("../images/newspaper.jpg");

	//crop the new photo
	$tmp_img = imagecreatetruecolor($layout_width, $layout_height);
	imagecopyresampled($tmp_img, $photo, 0, 0, $src_x, $src_y, $new_width, $new_height, $old_width, $old_height);
	$photo = $tmp_img;

	//run it through some filters to make it look more newspaper-esque
 	imagefilter($photo, IMG_FILTER_COLORIZE, 84, 80, 66); //84, 80, 66
	imagefilter($photo, IMG_FILTER_BRIGHTNESS, -50);
	imagefilter($photo, IMG_FILTER_CONTRAST, 10);
	imagefilter($photo, IMG_FILTER_GAUSSIAN_BLUR);


	//place the new photo on top of the background
	imagecopy($bg_img, $photo, 32, -90, 0, 0, $layout_width, $layout_height);

	//assign photo data
	$photo = $bg_img; 


} else {
	$photo = imagecreatefromjpeg("../images/newspaper.jpg");
}

// Create some colors
$white = imagecolorallocate($photo, 255, 255, 255);
$black = imagecolorallocate($photo, 0, 0, 0);
$grey = imagecolorallocate($photo, 58, 55, 49);
$blue = imagecolorallocate($photo, 3, 113, 164);


// Replace path by your own font path
$fontR = '../css/fonts/times.ttf';
$fontB = '../css/fonts/timesbd.ttf';
$fontI = '../css/fonts/timesi.ttf';
$fontBI = '../css/fonts/timesbi.ttf';


// Add the title
imagettftext($photo, 20, 0, 32, 535, $grey, $fontB, $title);

// Add the date
imagettftext($photo, 12, 0, 32, 563, $grey, $fontBI, $pubDateFormatted);

//now add the description - need to break them up
$lines = explode('|', wordwrap($desc, 130, '|'));
$y = 590;
foreach ($lines as $line) {
	imagettftext($photo, 11, 0, 32, $y, $grey, $fontR, $line);
	$y += 23;
}

//add the link
imagettftext($photo, 11, 0, 32, $y, $blue, $fontI, $link);

//resize the image into a thumbnail if parameters are passed
if(isset($_GET['w']) || isset($_GET['h'])) {

	//resize the image if it is a thumbnail
	$thumb_width = $_GET['w'];
	$thumb_height = $_GET['h'];
	$old_width = imagesx($photo);
	$old_height = imagesy($photo);

	//if only one value is given, then scale the other proportionately
	if($thumb_width == "") {
		$scale = $thumb_height/$old_height;
		$thumb_width = round($old_width * $scale);
	}

	if($thumb_height == "") {
		$scale = $thumb_width/$old_width;
		$thumb_height = round($old_height * $scale);
	}

	//defaults and maxs/mins
	if($thumb_width > 1500 || $thumb_width < 15) {
		$thumb_width = 950;
	}

	if($thumb_height > 1500 || $thumb_height < 15) {
		$thumb_height = 726;
	}


	$original_aspect = $old_width / $old_height;
	$thumb_aspect = $thumb_width / $thumb_height;

	if($original_aspect >= $thumb_aspect) {   
	// If image is wider than thumbnail (in aspect ratio sense)   
		$new_height = $thumb_height;   
		$new_width = $old_width / ($old_height / $thumb_height);
	} else {   
	// If the thumbnail is wider than the image   
		$new_width = $thumb_width;   
		$new_height = $old_height / ($old_width / $thumb_width);
	}

	$src_x = ($new_width - $thumb_width) / 2;
	$src_y = ($new_height - $thumb_height) / 2;

	$tmp_img = imagecreatetruecolor($thumb_width, $thumb_height);
	imagecopyresampled($tmp_img, $photo, 0, 0, $src_x, $src_y, $new_width, $new_height, $old_width, $old_height);
	$photo = $tmp_img;
}
 

// Set the headers
header('Content-Type: image/jpeg');
header("Content-Disposition: inline; filename=news-image-by-hal-nesbitt-" . $random . ".jpg");
session_cache_limiter('nocache');
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
header("Cache-Control: no-store, no-cache, must-revalidate");
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");

// output the image and clean up
imagejpeg($photo);
if($photo) {
	imagedestroy($photo);
}
if($bg_img) {
	imagedestroy($bg_img);
}
if($tmp_img) {
	imagedestroy($tmp_img);
}

?>

Published by

Hal

Aside from being a champion yo-yoer, I am the full-time computer geek at the American Society of Nephrology. I recently completed my MBA from George Washington University which I am hoping will enable me to finally afford my own bad habits. I also do freelance design, specializing in Flash, PHP, and ASP/ASP.NET.

Leave a Reply

Your email address will not be published. Required fields are marked *