Digital Decomposition of 10 Ruston Close Installation - Source Code John Wild 2011 john.wild@network.rca.ac.uk The installation consisted of 3 elements. A programe, writen using Processing, that displays and processes a photograph stored on a webserver. A PHP program that allows Processing to upload and overwrite the photograph on the server. A MaxSona sonic range finder connected to an Arduino that registered the presence of a viewer in the Gallery and sends a message via the serial port. Bellow is the Source Code for all 3 programes required to make the installation work: - 1) house_installation_Final.pde - applet writen in processing. displays and processes the image. 2) Upload.php - php file stored on the webserver. 3) MaxSona_House.pde - arduino source code to sense the presence of a viewer. ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// // house_installation_Final.pde Source Code..... // Downloads an image from a webserver and displays it fullscreen. // If Arduino sensors a viewer - Delete a pixel, recompress as jpg, send back to webserver. ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// // The program uses the, Post To Web Library v0.6, created by seltar [http://libraries.seltar.org/postToWeb/] //and the FullScreen Library [http://www.superduper.org/processing/fullscreen_api/] //Plus the Serial library to read data from the Arduino. import fullscreen.*; import processing.serial.*; import processing.pdf.*; import org.seltar.Bytes2Web.*; FullScreen fs; PDFToWeb pdf; PImage img; Serial myPort; // Create object from Serial class int val; // Data received from the serial port String Iurl = "http://www.***.***/***/saved/image/House.jpg"; int sec=59999; void setup() { size(720,576); background(0, 0, 0); pdf = new PDFToWeb(this); String portName = Serial.list()[3]; myPort = new Serial(this, portName, 9600); frameRate(5); fs = new FullScreen(this); fs.enter(); // enter fullscreen mode } void draw() { img = loadImage(Iurl);// Load the image from the web server into the program. image(img, 0, 0); // Displays the image while (sec < 60000){ if ( myPort.available() > 0) // If serial data is available { val = myPort.read(); // read it and store it in val if (val == 1) //If the Arduino detects someone { color white = color(255,255,255); // Selects a random pixle int rand_width = int (random(width)); int rand_height = int (random(height)); color c = img.get(rand_width, rand_height); // check pixel is not already white. if (c == white) { int i=0; while (i < 1) { rand_width = int (random(width)); rand_height = int (random(height)); c = img.get(rand_width, rand_height); if (c != white) { i=2; } } } img.set(rand_width, rand_height, white); // Destroys random pixel image(img, 0, 0); // Displays the image pdf.addPage(); save_to_web(); sec=60000; } } sec++; } sec=0; } void save_to_web() // Sends the image back to the webserver and over rights the original { String url = "http://www.***.***/***/Upload.php"; ImageToWeb img = new ImageToWeb(this); img.save("jpg",true); // Recomposed the image in jpeg file format. This will cause the image quality to deteriate. img.post("image",url,"House",true,img.getBytes(g)); println("sending Image"); } ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// // Upload.php Source Code..... // To make house_instalation_Final.pde work you will also have to have the file Upload.php on your server. More info about this code at:- http://libraries.seltar.org/postToWeb/ ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// \n"; $debugData .= "Other info given by browser (size, type): {$_FILES[$fieldName]['size']}, {$_FILES[$fieldName]['type']}
\n"; $fileSize = filesize($tempLocation); $debugData .= "Real file size: $fileSize
\n"; // Strangely enough, if IE is given a path leading to nowhere, it just sends a 0 byte file! if ($fileSize == 0) // Might test a minimum size (smallest header size for graphics...) { return array('', 'File is empty!'); } if ($fileSize > MAX_FILE_SIZE) { return array('', 'File too big!'); } // Get original file name $file = $_FILES[$fieldName]['name']; $debugData .= "Original file name: $file
\n"; // No HTML escape! :( // Strip out the path (given by IE, perhaps other browsers -- Firefox and Opera just give the name) // Most samples I saw use basename() but I found out that it fails to strip a Windows path on a Unix server // I could have used a str_replace, but I like REs... // (I gobble anything up to the last sequence of characters not having slash or anti-slash in it) // Note: ensure magic quotes are disabled or neutralized $file = preg_replace('!.*?([^\\/]+)$!', '$1', $file); $debugData .= "Filter 1: $file
\n"; // Filter out all characters that are not alphanumerical, dot and dash // as they can be troublesome in some OSes. // A sequence of such chars is replaced by a unique underscore. $file = preg_replace('/[^a-zA-Z0-9.-]+/', '_', $file); $debugData .= "Filter 2: $file
\n"; // Split name and extension: gobble everything up to the last dot (file name), then dot and remainder (extension) // Note that .htaccess has no extension and is a pure filename if (preg_match('/^(.+)\.([^.]+)$/', $file, $m) == 0) { // No match => No dot or nothing before the dot $extension = ''; } else { $file = $m[1]; $extension = $m[2]; } $debugData .= "Split: $file $extension
\n"; // Ensure name isn't too long: just truncate it $file = substr($file, 0, MAX_FILE_NAME_LENGTH); $debugData .= "Truncated: $file
\n"; // If extension not allowed (could be a CGI file...), discard it if ($extension != '' && !in_array($extension, $allowedExtensions)) { return array('', 'File format not allowed.'); } // Add trailing slash to dest dir, supposed in Unix format // (if not slash at end, replace last char by itself followed by a slash) $destinationDir = preg_replace('!([^/])$!', '$1/', $destinationDir); if(!file_exists($destinationDir)){ if(!mkdir_recursive($destinationDir, 0777)){ return array('', 'Cannot create project folder.' . " (dest.: $destinationDir)"); } chmod($destinationDir, 0777); } // Create a time stamp used as prefix to make the file name unique. // Might have a conflict if you have millions of users, ie. a probability of having two users // uploading a file in the same second, supposing they go in the same dir. // If so, you are able to improve this code! ;-) // One might want to pass a prefix (or suffix) parameter to this function, eg. to tag the file name // with the name of the author. Just do it! //$prefix = date('Ymd-His-'); //$prefix = ''; $destinationFile = $file . ($extension != '' ? '.' . $extension : ''); $debugData .= "Destination file: $destinationFile
\n"; $destinationPath = $destinationDir . $destinationFile; $debugData .= "Destination path: $destinationPath
\n"; // Move uploaded file from temporary folder to destination // Overwrite a file of same name there, if any (unless, perhaps server is on Windows, might just fail to move). // if (!file_exists($destinationFile)) // { if (!move_uploaded_file($tempLocation, $destinationPath)) { return array('', 'Failed to move upload file.' . " (dest.: $destinationPath)"); } chmod($destinationDir.$destinationFile, 0777); return array($destinationFile, $destinationPath); // } } else { return array('', 'Field not found'); } } function mkdir_recursive($pathname, $mode) { is_dir(dirname($pathname)) || mkdir_recursive(dirname($pathname), $mode); return is_dir($pathname) || @mkdir($pathname, $mode); } $debugData = ''; // Get the title foreach($_FILES as $title=>$file){ break; } unset($file); // just to be sure $destDir .= $title.'/'; /* $maxFiles = 1000; // Max number of files accepted in the dest dir // First, check if we don't have too much files. Not a bad test: since we fix the max size of files, the max total size of the files // is under control. $files = @scandir($destDir); if(is_array($files)){ $files = array_slice($files, 2); // Shift out . and .. while (count($files) > $maxFiles) { $file = array_shift($files); echo $file . " to remove\n"; unlink($destDir . '/' . $file); } } */ $result = HandleUploadedFile($title, './'.$destDir, array('jpg', 'jpeg')); /* if ($debugData != '') { echo "

Debug data:
$debugData

\n"; } */ echo "

uploader

\n"; if ($result[0] == '') { echo "

Error: {$result[1]}

\n"; } else { $page="result.php"; $imageURL = 'http://' . $_SERVER['SERVER_NAME'] . $rootDir . $destDir . $result[0]; // echo $imageURL; } ?> ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// // Arduino Source Code..... // MaxSona_House.pde // Reads a MaxSona range finder. If a person is 410cm or less 1byte is send on the serial bus. ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// // Wire LV MaxSonar-EZ0 // GRD -> GRD // +5 -> 5v // pw -> Arduino pin 7 //Digital pin 7 for reading in the pulse width from the MaxSonar device. //This variable is a constant because the pin will not change throughout execution of this code. const int pwPin = 7; //variables needed to store values long pulse, inches, cm; void setup() { //This opens up a serial connection to shoot the results back to the PC console Serial.begin(9600); Serial.print("started"); } void loop() { pinMode(pwPin, INPUT); //Used to read in the pulse that is being sent by the MaxSonar device. //Pulse Width representation with a scale factor of 147 uS per Inch. pulse = pulseIn(pwPin, HIGH); //147uS per inch inches = pulse/147; //change inches to centimetres cm = inches * 2.54; if (cm < 410){ Serial.print(1, BYTE); // send 1 to Processing delay(2000); } else { // If the switch is not ON, Serial.print(0, BYTE); } }