toxi.in.process

Tuesday, December 04, 2007

Arduino + Processing London workshop this weekend

Apologies for not posting this any earlier (or any other news for that matter, of which there are plenty): Organized by the lovely folks @ Tinker.it, together with Spencer Roberts I'll be co-teaching an H3:Arduino+Processing workshop this weekend (8th/9th December) and would like to point out there are still places available. You should have some basic/intermediate experience with both tools as we will be looking at more "advanced" (yuck, how I hate this word) topics and will try to each have a little interactive project built over the weekend. The workshop space itself is kindly provided by Moving Brands in Shoreditch.

More info and schedule on the workshop website. Ciao.

Tuesday, September 18, 2007

Up & coming in The Netherlands

As usual, a last minute notification (few hours before leaving) about my participation in this year's TodaysArt festival in The Hague, Netherlands.

<>TAG kindly invited me to give 2 lectures about my Processing works in the context of their Information Aesthetics 2 symposium. First I'll be joining Mr. Casey Reas and Aaron Koblin @ Mediamatic in Amsterdam, this Thursday at 2030h.

The Information Aesthetics symposium will then take place at the Spui Theatre, The Hague on Saturday from 1400-1800h. Marius Watz and Manuel Lima (author of Visual Complexity) will also take part in this so am looking ++forward to see what everyone has been up to recently and of course to the discussion about our varied approaches.

Last but not last, I (under the Moving Brands moniker) will be responsible for the re-staging of an adaptation of the KEF Muon audio visualization - this time unfortunately without the Muon speakers & LED floor - but projected in the amazing space of the Richard Meier designed city hall of The Hague. This will be happening throughout Friday and Saturday.

Tuesday, August 21, 2007

Creating weblinks in PDF with iText

Mr. LennyJPG pinged me this morning asking about creating hyperlinks in PDFs generated with Processing. After some digging through the iText javadocs and reading various tutorials it became obvious that Processing's PGraphicsPDF class had to be modified to give us access to the wrapped PdfContentByte instance so that the hyperlink magic can happen. My modified version of Processing's PDF library can be downloaded from here (jar) and there (source). The .jar has to be placed in the /libraries/pdf/library folder inside the Processing root, but please make sure to keep a backup of the original.

The demo below is briefly showing how to create weblinks (here: to various del.icio.us users) and how to position these on the page. All should be pretty self-explanatory. Finally, here's an example PDF generated with this demo.

/**
* iText/Processing PDF weblink demo
* Builds a number of links on the fly and
* positions them randomly on the page.
*
* CAUTION: This demo requires a modified version of
* Processing's PGraphicsPDF class
*
* @author: info at toxi dot co dot uk
*/
import processing.pdf.*;
import com.lowagie.text.*;
import com.lowagie.text.pdf.*;

void setup() {
pageSize(com.lowagie.text.PageSize.A6,false,JAVA2D);
PGraphicsPDF pdf=(PGraphicsPDF)beginRecord(PDF,"test"+(System.currentTimeMillis()/1000)+".pdf");

// draw something in the background
for(int i=0; i < height; i+=10) {
line(0,0,width,i);
line(width,height,0,i);
}

try {
// build hyperlinks for these del.icio.us users
String[] users=new String[] {
"adm",
"blackbeltjones",
"d3",
"garuda",
"golan",
"hahakid",
"jbleecker",
"lennyjpg",
"reas",
"toxi"
};

for(int i=0; i < users.length; i++) {
// java colours are normalized 0.0 .. 1.0
Color linkCol = new Color(random(1), random(1), random(1));
Chunk c=new Chunk(users[i],FontFactory.getFont(FontFactory.HELVETICA, 14, com.lowagie.text.Font.UNDERLINE, linkCol));
c.setBackground(new Color(0,0,0),5,5,5,5);
c.setAnchor("http://del.icio.us/"+users[i]);
// this is using a hacked version of PGraphicsPDF to get access to the PDF content
PdfContentByte cb=pdf.getContent();
ColumnText ct = new ColumnText(cb);
float x=random(width-100);
float y=random(height-100);
ct.setSimpleColumn(new Phrase(c), x,y, x+100, y+50, 16, Element.ALIGN_CENTER);
ct.go();
}
}
catch(Exception e) {
e.printStackTrace();
}
endRecord();
}

// see link below for more info about this method:
// http://www.toxi.co.uk/blog/2007/07/specifying-pdf-page-size-in-processing.htm
void pageSize(com.lowagie.text.Rectangle r, boolean isLandscape, String renderer) {
if (isLandscape) {
size((int)r.top(),(int)r.right(),renderer);
}
else {
size((int)r.right(),(int)r.top(),renderer);
}
}

Tuesday, July 31, 2007

Using JavaDB and db4o in Processing

Kind of as reply to Tom's mini howto for using SQLite with Processing, but also since I've been dabbling with it myself recently, here's an alternative take on using an embedded database from within Processing (or more generally in Java)...

Mainly due to Java's strong focus on server side development, over the past few years there have been several large scale community efforts to create Java native database engines, which don't rely on underlying C code, are high performant and portable: the essence of the Java way. The other benefit is that such DB engines can be embedded and distributed with your application without requiring any further installation. One such development effort is Apache Derby, a project which started in 1996, swapped owners several times (amongst them IBM) and then became an incubator project at Apache in 2004. Sun also joined the project and has been bundling it as library (under the name JavaDB) as part of the JDK (v6+) since December 2006. So in other words if you have Java6 installed you also should have Derby. But even if you don't (for example Mac users), you can download Derby from here and unzip it to any folder on your hard drive.

The following deals with setting up Processing to work with Derby:
  1. Create a new folder structure /derby/library within Processing's /libraries folder
  2. Copy the file derby.jar from Derby's /lib folder into the newly created folder

Before we can start using the database now we first need to create a new database. Derby comes with its own commandline client "ij" which is located in the /bin directory of the main Derby install dir (If you're going to use this tool more often it would make sense to add this /bin directory to your system path).

Launch ij from the commandline and then create a new database with this command:
ij> connect 'jdbc:derby:/path/to/database;create=true';

Databases are just folders and can be stored anywhere. For example on Windows the path /dev/derby/mydb would refer to C:\dev\derby\mydb...

Next create some a simple table in the new database and add some data:
ij> create table cities (
cityID integer not null primary key,
name varchar(32) not null
);
insert into cities values(1,'london');
insert into cities values(2,'berlin');
insert into cities values(3,'san francisco');

Given that all worked fine so far we can finally move on to a small Processing demo to query our exciting dataset:
import org.apache.derby.*;
import java.sql.*;

String driver = "org.apache.derby.jdbc.EmbeddedDriver";
String connectID = "jdbc:derby:/derby/testdb";
Connection conn;

void setup() {
size(100,100);
try {
query();
}
catch(SQLException e) {
e.printStackTrace();
}
}

void query() throws SQLException {
try{
Class.forName(driver);
}
catch(java.lang.ClassNotFoundException e) {
e.printStackTrace();
}

try {
conn = DriverManager.getConnection(connectID);
Statement st=conn.createStatement();
ResultSet results=st.executeQuery("SELECT * FROM cities");
while (results.next()){
println("City: "+results.getString("name"));
}
results.close();
}
catch (Exception e) {
e.printStackTrace();
}
finally {
// always make sure we close the connection
if (conn!=null) conn.close();
}
}

Now, this is obviously an absolute bare bones demo, however Florian Jennet wrote a little database library last year to hide all these excessive try/catch clauses. Unfortunately he's also hardcoded the database connection string to only work with MySQL and there's no source supplied with the library so one could change it and easily add support for other JDBC drivers... (nudge! :)

Speaking of databases, here's another food for thought. SQLite, MySQL, Apache Derby et al are all based on the relational database model. Java on the other hand is object oriented and as you can see it takes a relative large effort to exchange data between both worlds without any further help. To ease these tasks there're various powerful object relationship mappers available acting as translators between the worlds of objects and that of SQL. Last but not least, native object oriented databases are yet another alternative approach here which is far more aligned with the language. db4o is such an object database and allows you to store and query complex object hierarchies in a most natural (in a Java context) way. For example with db4o you can store and restore the entire state of an application - with just a single line of code. This in turn not just saves you a lot of time and headaches, but also enables building more complex, data intensive applications. If you're interested, the db4o site has a very easy to follow tutorial...

Sunday, July 29, 2007

String based designs

As we delve deeper into the realms of applied generative design and deal with a whole population of possible design outcomes, we often find ourselves preferring certain outcomes more than others and want to narrow down our explorations. So the identity of each such design plays an important role. Identity in this context can be defined by the set of input parameters used, but we also need to ensure the processing of these parameters is deterministic, meaning that even though we often use (pseudo)randomness as part of the algorithm, the outcome should be replicable for each set of parameters.

Most (if not all) pseudo-random generators use the concept of a random seed which subsequently produces a unique (and deterministic) sequence of "random" numbers. In Processing you can use both randomSeed() and noiseSeed() to achieve this. Now while using numbers is all fine, and technically speaking, all digital media is just numbers - there're use cases where it'd be nicer to use e.g. text as seed directly. For example, the 20,000 designs of the Lovebytes fluffies are all based on their generated character name only. There're about 10 other parameters, but these too are chosen based on the random sequence seeded by the name.

One way of turning a string into a number is by using message digests, like the popular MD5 or SHA1 algorithms. A message digest takes any number of bytes as input and calculates a fixed length hash. MD5 results in a number 128 bits long and SHA1 160 bits. This is more data than we can cope with since most common random number generators only accept up to 64 bits as input. In Java/Processing this is equivalent to the long type.

The following function takes a string as input, computes the hash and then returns the first 8 bytes as long integer to be used as random seed. Because it doesn't use the full hash it's possible in theory to end up with the same result for different inputs. However, I've not yet managed to come across a collision with the relative short strings (names, sentences, phrases) used in my work.

import java.security.*;

/**
* Calculates the message digest of the given string and
* returns the first 8 bytes packed into a long
*
* @param msg string to form hash from
* @param digest message digest ID (e.g. "MD5" or "SHA1")
* @return zero if failed, else partial digest as type long
*/
long getLongHash(String msg, String digest) {
long result=0;
try {
MessageDigest md = MessageDigest.getInstance(digest);
md.update(msg.getBytes());
byte[] buffer=md.digest();
for(int i=0,bits=56; i<8; i++) {
long val=(buffer[i]<0 ? 0x100+buffer[i] : buffer[i]);
result|=val<<bits;
bits-=8;
}
}
catch(Exception e) {
e.printStackTrace();
}
return result;
}

And again, use it like that:

long seed=getLongHash("Hello world!","MD5"); // "SHA1" as alternative
noiseSeed(seed);


Btw. The default Java Random generator does not guarantee to produce a deterministic sequence across all platforms. This means as long you're using Processing's default random() or noise() functions you're only guaranteed the same sequence as long as you stay on either Windows or OSX or Linux. Last year Marius wrote a Processing wrapper for the famous Mersenne Twister generator, however this one can only be used as alternative and in isolation. Processing's noise() function is hardcoded to use the default Java generator...