Friday, 26 October 2012

Quartz Composer Image Composition

I have used Quartz Composer to display messages from for example Twitter.  The raw data I am displaying includes the author's profile image, author's name, message content and the destination of any URL within that message.  I feed that data from a Mac OSX application written in Objective-C as a number of arrays.  This post explains how to take these constituent parts and arrange them within a single image that can then be easily manipulated.

The root level is shown in the next screenshot where the main action is within the Render In Image patch.  The inputs to this are the arrays of data sent in from the OSX app.  The output of the Render In Image patch goes straight to a Billboard.

Inside the Render In Image patch I use javascript to calculate the positions of the elements of the final message image.  A number of Image With String patches to convert text to an image which also provide Display Width and Display Height of the image to the javascript patch.  The positions of all elements are sent to the Billboard patches that display them.

The BlockWidth and BlockHeight define the size of the area within which the elements are composited and this is generated by scaling from the Rendering Destination Dimensions patch.  In the screenshot below the value of Scaler is 0.95

The final bit of detail is the code within the javascript block that uses the dimensions of the individual elements to place them within the final image block regardless of the size of those elements.  For example the author's profile picture (AuthorImage) is always butted up against the top left corner and the Author Name is butted up against that.

function (__number AuthorNameX, __number AuthorNameY, __number AuthorImageX, __number AuthorImageY, __number ContentX, __number ContentY, __number PubDateX, __number PubDateY, __number ContentURLX, __number ContentURLY) main (__number BlockWidth, __number BlockHeight, __number AuthorNameWidth, __number AuthorNameHeight, __number AuthorImageWidth, __number AuthorImageHeight, __number ContentWidth, __number ContentHeight, __number PubDateWidth, __number PubDateHeight, __number ContentURLWidth, __number ContentURLHeight)
var result = new Object();
var offset = 0.01;

// Inputs: BlockWidth, BlockHeight,
// AuthorNameWidth, AuthorNameHeight, 
// AuthorImageWidth, AuthorImageHeight,  
// ContentWidth,  ContentHeight,  
// PubDateWidth,  PubDateHeight
// ContentURLWidth, ContentURLHeight

// Outputs: AuthorNameX, AuthorNameY,
// AuthorImageX, AuthorImageY,
// ContentX, ContentY,
// PubDateX, PubDateY
// ContentURLX, ContentURLY

result.AuthorImageX = -(BlockWidth - AuthorImageWidth)/2;
result.AuthorImageY = (BlockHeight - AuthorImageHeight)/2;

result.AuthorNameX = AuthorImageWidth/2 + offset;
result.AuthorNameY = (BlockHeight - AuthorNameHeight)/2;

result.ContentX = 0;
result.ContentY = BlockHeight/2 - AuthorImageHeight - ContentHeight/2 - offset;

result.PubDateX = 0;
result.PubDateY = (BlockHeight - PubDateHeight)/2;

result.ContentURLX = 0;
result.ContentURLY = result.ContentY - ContentURLHeight/2 - ContentHeight/2;

return result;

Here is an example of the output of the Render In Image patch - sorry for the garish colours they are quickly and randomly selected to make the different areas stand out during development:

This image can be translated/scaled/rotated etc, very easily without having to worry about how they all stick together.

If enough people show interest in the post I might produce a tutorial video showing how to build this in excruciating detail.