Yet another custom Google Picasa API gallery 1

As thousands of other people, I store my photos on the Picasa Web Albums from Google. Why did I choose Google in the first place? Well, the Picasa Web Albums had this easy way to upload pictures via Picasa application, and the first versions of the albums were just complex enough to sort pictures and organize them into sub-albums, yet still simple enough to be easy to operate with. Besides, it was one of the few album providers with a lot of free space as long as you had your Gmail account (and who doesn’t have one of those…).

After a couple of years of usage, I sadly found some things that buggered me. The inability to create a nested structure (you can only have ona layer of organization), and the somewhat outdated look & feel made me look again for alternatives, but when you have so many pictures at one provider already, it’s hard to move. The final nail in the coffin, however, was the merger of Picasa Web Albums and Google+. The galleries in G+, while certainly aesthetically appealing, were (at least in the first version of G+) incredibly bandwidth-hungry, and even required some insane hardware to play really smoothly. Besides, since I don’t use G+ much, I didn’t like the merger as my album was now directly tied to my G+ profile.

That’s when I decided I’ll implement my own gallery on my own server. Luckily, Google did (as many other things) the whole Picasa thing properly – the API to Picasa Web Albums is quite powerful and lets you customize the display of your galleries, while still retaining the ease of uploading images via Picasa, and preserving your old albums.

I will not walk you through the whole process of making the custom gallery, but instead, show you how I implemented it, and how I have tailored it to my needs. One thing I’d like to point out that I didn’t implement, as I don’t have a need for it, but is certainly doable – you can implement a multi-layer organization of your albums with the help of captions. Google lets you caption each image, and if you organize this caption into a nested structure, let’s say “subalbum1|subalbum2|subalbum3||caption”, you can create an “artificial” nested structure of your own!

Ookay, enough with the chatting. Let’s get to the code! Google Picasa Web Albums Data API offers libraries for many popular web languages. As I only needed a relatively simple gallery, I picked PHP as the language.

First, let’s check the contents of my conf.php file.

conf.php


<?php
// ======================================
// CONFIGURATION FILE FOR PICASA GALLERY
// ======================================

// The Picasa service username
$userId = '<your_google_id>';

// Maximum thumbnail size (can be 32, 48, 64, 72, 144, 160). Cropped (c) or uncropped (u).
$thumbSize = '160c';

// Maximum image size can be 94, 110, 128, 200, 220, 288, 320, 400, 512, 576, 640,
// 720, 800, 912, 1024, 1152, 1280, 1440, 1600. These images are available as only uncropped(u) sizes.

$imgSize = '1280u';

// An array containing the albums that should not be shown (even though they are public!)
$hideAlbums = array('Scrapbook Photos', 'Warhammer army sale', 'Profile Photos');

As you can see from the config file, it’s pretty straightforward – first 3 options are needed to connect to Google Picasa Albums API, and to initialize parameters. The last option is my own; I have certain albums (I’m looking at you, Scrapbook Photos & Profile Photos) that I don’t want to display under my gallery, as they’re default Google-created un-erasable albums that serve only G+.

index.php


<?php
// Include the config file
include "./conf.php";

// Load the albums
$file = file_get_contents('https://picasaweb.google.com/data/feed/api/user/' . $userId . '?kind=album&access=public&thumbsize=' . $thumbSize);
$xml = new SimpleXMLElement($file);
$xml->registerXPathNamespace('gphoto', 'http://schemas.google.com/photos/2007');
$xml->registerXPathNamespace('media', 'http://search.yahoo.com/mrss/');
?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>zluftan.si ← Gallery</title>
<link rel="stylesheet" type="text/css" href="./style.css" />
<link rel="icon" type="image/ico" href="./favicon.ico">
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:400,200">
<script src="jquery-1.10.2.min.js"></script>
<script src="http://cdn.jquerytools.org/1.2.7/full/jquery.tools.min.js"></script>
</head>
<body>

 <!-- HEADER -->
 <?php echo file_get_contents('./header.html'); ?>

 <!-- BREADCRUMBS -->
 <div id="breadcrumbs">
 <ul>
 <li class="home"><i></i><a href="./index.php">&#160;</a></li>
 <li><i></i><span>Gallery</span></li>
 </ul>
 </div>

<!-- ALBUMS HOLDER -->
 <div class="albums">
 <?php
 foreach ($xml->entry as $feed) {
     // Skip the explicitly hidden albums
     if (in_array($feed->title, $hideAlbums)) {
         continue;
 }

 $group = $feed->xpath('./media:group/media:thumbnail');
 $a = $group[0]->attributes(); // We need thumbnail path
 $id = $feed->xpath('./gphoto:id'); // And album id for our thumbnail

 $summary = $feed->summary != '' ? $feed->summary : 'This album does not have any description.';
 if (strlen($summary) > 228) {
     $summary = substr($summary, 0, 228) . '...';
 }
 $title = $feed->title;
 if (strlen($title) > 47) {
     $title = substr($title, 0, 47) . '...';
 }

 echo '<div class="album">';
 echo '<a href="./album.php?id=' . $id[0] . '">'
 echo '<img src="' . $a[0] . '" alt="' . $feed->title . '" title="' . $feed->title . '" ref="' . $id[0] . '" /></a>';
 echo '<div>';
 echo '<a href="./album.php?id=' . $id[0] . '"><h2>' . $title . '</h2></a>';
 echo '<p>' . $summary . '</p>';
 echo '</div>';
 echo '</div>';
 }
 ?>
 </div>

 <!-- FOOTER -->
 <?php echo str_replace('$YEAR', date("Y"), file_get_contents('./footer.html')); ?>

</body>
</html>

My albums are structured in the default Picasa 2-layer hierarchy; I decided I’ll have a main page, containing all my albums, and when clicking individual album, you’ll be redirected to a page dedicated and showing all the images from the selected album. Retrieving your album information is as simple as calling the php function file_get_contents(PICASA_URL) with correct parameters, and you can retrieve everything, from information about all albums, individual images from single album, etc.

You then simply parse the retrieved file (which is in XML format) and pull specific information you need from it. In my instance, I select the thumbnail image location, description name, and unique album id for each of the albums, and display them on the page. I then construct the links for each individual album by simply calling my “album display” .php page, while giving the unique album id as a GET parameter.

My individual album page is a bit unique. I have a lot of short, daily trips, and I didn’t want to create an individual album for each daily excursion, so I merged all the “daily” excursions into albums called “Summer 2012″, “Winter 2012″, etc. Inside those albums, however, I still want to retain structure of individual events. When using Picasa, I decided to prepend a header to all the captions from a single excursion, so inside those “general” albums, I have captions structured like this: <dd>.<mm>.<yyyy> – <trip_title>: <actual image caption>. Of course, this only holds true for albums called “Winter 2012″ etc. To retain this “legacy” structure, there’s a lot of ugly mess in my .php code, but I hope it gives you an idea how you can implement a nested gallery structure for your albums I mentioned above. Let’s check album.php.

<?php
// Include the config file
include "./conf.php";

// Retrieve the album id from the parameters
$albumId = $_GET["id"];
if (empty($albumId)) {
	die;
}

// Load the contents of the specified album
$file = file_get_contents('https://picasaweb.google.com/data/feed/api/user/' . $userId . '/albumid/' . $albumId . '?kind=photo&access=public&thumbsize=' . $thumbSize .'&imgmax=' . $imgSize);
$xml = new SimpleXMLElement($file);
$xml->registerXPathNamespace('media', 'http://search.yahoo.com/mrss/');

// Check if special image description handling is required
$useSubAlbums = false;
if ($xml->title == 'Earlier stuff' ||
    preg_match('/^Summer (19|20)\\d{2}$/', trim($xml->title)) == 1 ||
    preg_match('/^Winter (19|20)\\d{2}\/(19|20)\\d{2}$/', trim($xml->title)) == 1) {
	$useSubAlbums = true;
}

// If we have sub albums, find all of them and save them into an ordered array, they should already be ordered (in Picasa)!
if ($useSubAlbums == true) {
	$subAlbums = array();
	foreach ($xml->entry as $feed) {
		$description = $feed->xpath('./media:group/media:description'); // Retrieve image description

		if (str_word_count($description[0]) <= 0) {
			continue;
		}

		// This works whether the image has the "sub-description" or not =)
		$res = explode(':', $description[0]);
		$title = $res[0];

		if (array_key_exists($title, $subAlbums) == true) {
			$subAlbums[$title][] = $feed;
		} else {
			$tmp = array($feed);
			$subAlbums[$title] = $tmp;
		}
	}
} else {
	$subAlbums = array("tmp" => $xml->entry);
}
?>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title><?php echo $xml->title; ?></title>
<link rel="stylesheet" type="text/css" href="./style.css" />
<link rel="icon" type="image/ico" href="./favicon.ico">
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Yanone+Kaffeesatz:400,200">
<link rel="stylesheet" href="lightbox/css/lightbox.css" />
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="http://cdn.jquerytools.org/1.2.7/full/jquery.tools.min.js"></script>
<script src="lightbox/js/jquery-1.10.2.min.js"></script>
<script src="lightbox/js/lightbox-2.6.min.js"></script>
</head>
<body>
	<!-- HEADER -->
	<?php echo file_get_contents('./header.html'); ?>

	<!-- BREADCRUMBS -->
	<div id="breadcrumbs">
		<ul>
			<li class="home"><i></i><a href="./index.php">&#160;</a></li>
			<li><i></i><a href="./index.php">Gallery</a></li>
			<li><i></i><span><?php echo $xml->title; ?></span></li>
		</ul>
	</div>

	<!-- IMAGES -->
	<?php
	if ($useSubAlbums == true) {
		echo '<div class="subalbums_container">';
	}

	foreach ($subAlbums as $albumTitle => $images) {
		if ($useSubAlbums == true) {
			$res = explode(' - ', $albumTitle);
			$trimmedAlbumTitle = $res[1];
			echo '<div class="subalbum">';
			echo '<h2>' . $trimmedAlbumTitle . '</h2>';
		}

		// Show pictures
		echo '<div class="images' . ($useSubAlbums == true ? '2' : '') . '">';
		foreach ($images as $feed) {
			$group = $feed->xpath('./media:group/media:thumbnail'); // Let's find thumbnail tag
			$a = $group[0]->attributes(); // Now we need to get attributes of thumbnail tag, so we can extract the thumb link

			// Descriptions are tough nut
			$caption = 'Detail';
			$description = $feed->xpath('./media:group/media:description'); // Retrieve image description
			if (str_word_count($description[0]) > 0) {
				if ($useSubAlbums == true) {
					if (strpos($description[0], ':')) {
						$res = explode(': ', $description[0]);
						$caption = $res[1];
					}
				} else {
					$caption = $description[0];
				}
			}

			$b = $feed->content->attributes(); // Now we convert "content" attributes into array

			echo '<div class="image">';
                        echo '<a href="' . $b['src'] . '" title="' . $caption . '" data-lightbox="' . $albumTitle . '">';
                        echo '<img src="' . $a['url'] . '" alt="' . $feed->title . '" width="' . $a['width'] . '" height="' . $a['height'] . '"/>';
                        echo '</a></div>';
		}
		echo '</div>';

		if ($useSubAlbums == true) {
			echo '</div>';
		}
	}

	if ($useSubAlbums == true) {
		echo '</div>';
	}
	?>

	<!-- FOOTER -->
	<?php echo str_replace('$YEAR', date("Y"), file_get_contents('./footer.html')); ?>

</body>
</html>

As you can see, I have special handling when it comes to sub-album structure. Nonetheless, the image info of the album is really easy to retrieve! I decided to use Lightbox for display of full-size images, and in case of sub-albums, I give each of the sub-album images its own data-lightbox attribute, so you have images corresponding to the same sub-album grouped together as a Lightbox album.

And that’s it! Header & footer are just .html files for displaying header/footer. For some shameless self promotion, visit the gallery (mind you, I’m still waiting for the designer to make it a bit nicer).

One comment on “Yet another custom Google Picasa API gallery

  1. Reply mohit verma Sep 19, 2014 8:43 AM

    when i have used your code i m getting this error ‘String could not be parsed as XML’ please send me reply asap.

    thanks in advance

Leave a Reply