2nd edition of 1

I was really pleased when my good friend chris asked me to help him with his edition of 1 project. I guess it was exciting working on an arts project. I also liked his project because randomness is an interesting concept, particularly when it comes to computers. Put very simply: computers have trouble picking stuff at random.

Chris’s project was to pick a random image from the internet and present it on screen. It sounds fairly simple, and even slightly boring at first, but it creates a rather magical effect (and slightly addictive after a short while). The combination and sequence of images is interesting. The randomness of selection applies to many layers. How do you pick a random number using a deterministic process (like a computer)? How can you select an image at random if the search engine indexed it based on predefined criteria? What about the selection of the search engine you use? Or any other part of the process. I suppose those questions are only a part of what made this project interesting (for me anyway).

Chris initially used the ghettodriveby website, which does just that – picks a random image. So in that respsect, there wasn’t a great deal of technology or artistic innovation. Chris did however use two monitors and stretched the images on screen, to create a really cool effect – contrasting two random images. Also when displayed full screen, without any context or text, the impact is quite different, and even more so in a gallery space (I have to admit I have never seen edition of 1 in a gallery, not yet anyway).

For the impatient – here’s the temporary end result. Wait for the image to change.

So my first task was to mimic or copy ghettodriveby. The second one was to create a 2nd version for the Deptford X festival. On the 2nd version, images will be searched at random from a limited set of key words – having to do with Deptford.

Why not re-use ghettodriveby? There were a couple of reasons to re-invent the wheel here:

  1. ghettodriveby isn’t very clear about the rights to use it, especially the way chris modified it
  2. Chris had no control over ghettodriveby. If it goes down or changes, edition of 1 won’t work
  3. When using a custom keyword search, ghettodriveby seemed to always return the same image – this was a real problem for Deptford X
  4. because it’s fun to DIY

So the first task (which ended up being put aside for the deptford edition) was reasonably easy. Google provides a search API which allows you to search for images. Whilst there’s no option to search for a random image, we could easily use a random word to search for. Picking up a random word was the next challenge. I then figured out the best way to get a long list of words is wiktionary. You can download their whole database in xml format, and then extract the terms. I created a little python proof-of-concept and it seems to work well. I didn’t include the random word selection into it, but that’s quite easy.

# img_search.py

import urllib2
import cjson
import sys

# usage: img_search.py [search term]
url = ('http://ajax.googleapis.com/ajax/services/search/images?v=1.0&q=%s&start=1' % sys.argv[1]) 

request = urllib2.Request(url, None, {'Referer': 'http://www.your-domain.com'})
response = urllib2.urlopen(request)
results = cjson.decode(response.read())

for i in results['responseData']['results']:
    print i['url']

The problem I faced when narrowing down the search into only a few words (like ‘deptford’) was that the google api seems to limit the maximum results to 60. I have no idea why, but if the start parameter was set to anything higher than 60, google api choked. No results. Bummer. The show was meant to run for 10 days, changing the image every 10 seconds. 60 images per search term isn’t going to cut it.

One workaround was to mix the term with another word, perhaps at random. maybe do a combination of ‘deptford’ and ‘book’, ‘cat’, ‘morning’ or ‘baguette’ (especially ‘baguette’). It wasn’t elegant though, and not random enough.

So we then searched for alternatives. Yahoo BOSS turned out to provide a very similar api, and after going through the motions of getting the API key (which yahoo requires), it looked like yahoo didn’t limit the results. Well, it kinda did, but much higher than 60. I did some experiments and somewhere above 1,000, yahoo seems to always return the same image. 1,000 is manageable though.

Despite having very little experience with php, and not liking it as much as I like python, it seemed like a better choice. You can run php on almost any server. So I then had to work out how to turn my python code into php. This is the end result (more or less). This php only returns a random URL based on a set of keywords, each with its own maximum count (some search expressions might not even return 1,000 results).

<?php

function getLink() {
$search_arr = array(
1 => array("term"=>"deptford", "max"=>1000),
2 => array("term"=>"lewisham", "max"=>1000),
3 => array("term"=>"river+ravensbourne", "max"=>1000),
4 => array("term"=>"deptford+market", "max"=>1000)
);

// picking a random term, and then picking a random position for the url
$term_id = rand(1,count($search_arr));
$term = $search_arr[$term_id]["term"];
$pos = rand(1,$search_arr[$term_id]["max"]);

$url = "http://boss.yahooapis.com/ysearch/images/v1/" . $term . "?appid=<YOUR_APP_ID>&format=json&count=1&start=" . $pos;

// sendRequest
// note how referer is set manually
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_REFERER, "");
$body = curl_exec($ch);
curl_close($ch);

// now, process the JSON string
$json = json_decode($body);
return $json;
}
$json = getLink();

// in case we don't get any results - we simply try again
while (is_null($json->ysearchresponse->resultset_images)) {
	$json = getLink();
}

// Using foreach - but we only get one URL
foreach ($json->ysearchresponse->resultset_images as $val)
{
    echo $val->url;
}
?>

The last part took me probably the longest to work out. Primarily because (very much like php), I have no clue when it comes to javascript and all that XMLHTTPRequest stuff. The code below kinda works, but probably not in IE, and it’s probably pretty lame too. What it simply does is pull a new url for an image from the php script above every 10 seconds. It’s supposed to detect an invalid image and then reload another, but I’m not entirely sure it works actually.

<html>
<head>
<script language="JavaScript">

// I'm using two images, so if there's an error on one, I can quickly swap it with another. I'm not even sure it works
var img1=null;
var img2=null;
 
// this is the function that gets called on error
 function ImgErr() {
        document.myimage.src = img1;
        img1 = img2;
        return true;
}

// this function gets called every 10 seconds and loads a new image
 function RefreshImage()
 {
    var xhr=null;
   if (img1 != null)
       document.myimage.src = img1;
   img1 = img2;
   try
   {
     xhr = new XMLHttpRequest(); 
   } catch(e)
   { 
     try { xhr = new ActiveXObject("Msxml2.XMLHTTP"); } 
     catch (e2)
    { 
       try { xhr = new ActiveXObject("Microsoft.XMLHTTP"); } 
       catch (e) {}
    }
  }

  xhr.onreadystatechange = function()
   { 
     document.myimage.alt="Loading...";                
     if(xhr.readyState == 4)
     {
        if(xhr.status == 200)
        { 
             if (img1 != null)
                 document.myimage.src=img1;
	     img2 = xhr.responseText; 
        } 
     } 
 }; 

 xhr.open("GET", "editionof1-img.php", true);                
 xhr.send(null); 
}

window.setInterval('RefreshImage()', 10000);
</script>
</head>
<body>
<img src="http://editionof1.org/Editionof1.org/image-1_files/droppedImage_1.jpg" name="myimage" width="1497" height="1342" onerror="ImgErr()">
<script>
RefreshImage();
</script>
</body>
</html>

UPDATE: My friend Tal suggested I use jquery, instead of all this XMLHTTPRequest mess, and indeed it makes life so much easier. Here’s the updated version of the html

<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
<script language="JavaScript">

// I'm using two images, so if there's an error on one, I can quickly swap it with another. I'm not even sure it works
var img1=null;
var img2=null;
 
// this function gets called every 10 seconds and loads a new image
 function RefreshImage()
 {
	// this 1-line below saves all the hassle with XMLHTTPRequests, callback functions etc
	$.get("editionof1-img.php", function(data){
		if (img1) document.myimage.src = img1;
		img1 = img2;
		img2 = data;
	});
 }

window.setInterval('RefreshImage()', 10000);
$(function(){
	// Refreshing twice at the beginning to load two images into img1,img2
	RefreshImage();
	RefreshImage();
});

</script>
</head>
<body>
<img src="http://editionof1.org/Editionof1.org/image-1_files/droppedImage_1.jpg" name="myimage" width="1497" height="1342" onerror="RefreshImage()">
</body>
</html>

Leave a Reply

css.php