"zaail" Posts

Send us your Tiff files!

Back in April of 2010 we introduced ZaaIL, which was an Alchemy port of the open source C DevIL image library. ZaaIL was released to our labs as simply an experimental project to serve a specific purpose and to also allow for us to learn the ins and outs of Adobe’s Alchemy project.

Since our release of ZaaIL, there have been loads of questions and clients who have contacted us regarding deeper support of three formats: TIFF, JP2000 and DICOM.

We’re happy to announce that ZaaLabs has addressed the first of those three image formats, the TIFF format.

ZaaTiff (AS3 and JavaScript)

We currently have a build of what we’re calling our ZaaTiff library. Below you can see screenshot of us parsing a TIFF file and displaying it in Flash in the browser. We have also built a very rudimentary document viewer using minimal comps.

We also have built out an ExternalInterface JavaScript bridge.

And finally, we have also built out an experimental JavaScript version of the TIFF Parser which renders to an HTML5 Canvas.

We need your help!

The TIFF file specification is expansive, and finding test images of all the different formats is quite difficult. In an effort to make ZaaTiff all-encompassing, we need more test images of varying types.

What we’re looking for:

  • 1 Bit Per Pixel / Group 3 1D / CCITT modified Huffman RLE
  • 1 Bit Per Pixel / Group 3 2D / CCITT Group 3 fax encoding
  • 1 Bit Per Pixel / Group 4 2D / CCITT Group 4 fax encoding
  • 8 Bits Per Pixel / JPEG Compression
  • 8 Bits Per Pixel / LZW Compression
  • 24 Bits Per Pixel / LZW Compression
  • 24 Bits Per Pixel / JPEG Compression
  • Pretty much any TIFF file…

If you have TIFF files sitting around, email them to info [at] zaalabs [dot] com, with the subject of “ZaaTiff Test Image”.

Any questions, comments, etc… feel free to comment below.

Thanks!

Compiling ZaaIL with Alchemy – Part 3

So now you’ve compiled DevIL! Congratulations! However, you may notice there’s still no .swc or .swf for you to use. We still have one more step to complete.

Currently we have all the libraries compiled with Alchemy, but we haven’t defined the interface that we’ll expose to Flash yet. There are two methods to do this:

1) Write C code directly that defines this relationship.
2) Write GlueGen (gg) to define this relationship, and then use another one of Alchemy’s tools to turn this glue code into the corresponding C and AS code.

For ZaaIL, we used option 2, creating a GlueGen interface.

I created a file named devil.gg and put this file in the DevIL library directory. If you decide to create it elsewhere the path to il.h will need to be adjusted accordingly. The documentation on GlueGen syntax and features is pretty sparse (Quick heads up… there is a similar tool for Java), so some of this may not be the best way, but I found that it worked.

The documentation we do have is available here.

At the top of this file you define a code block that will be passed straight through to the C file.

// some C code with some includes -- top level blocks get emitted as-is to the C glue
{
    #include
    #include "include/IL/il.h"
}

We then import ByteArray and define functions that you want to make available to Flash. The first function, ilInit, is about as simple as it gets. Flash is going to be able to call ilInit which will call the C ilInit, no arguments are involved and no return type to worry about.

The next function ilLoadImage has parameters and a return type we need to handle. I’m not sure about the naming of the incoming parameters to these functions, so I just named them the same as the expected values on the C side. Then with the return type we are saying that C will return ILboolean, but on the AS side we want a uint (this is called marshalling).

// import the ByteArray class -- gets emitted into AS glue
import flash.utils.ByteArray;
 
public function ilInit():void;
 
public function ilLoadImage(path:String):(ILboolean)uint;
 
public function ilGetError():(ILenum)uint;
 
public function ilGetInteger(Mode:uint):(unsigned)uint;
 
public function ilOriginFunc(Mode:uint):(ILboolean)uint;
 
public function ilEnable(Mode:uint):(ILboolean)uint;

Lastly, we can implement functions of our own that we can call from AS. Below I define a function named ilGetPixels, which wraps the C function ilCopyPixels. This function has a body and actually does some work to ensure that we create a byte array that is in the format Actionscript wants (which is ARGB as opposed to RGBA which DevIL provides).

public function ilGetPixels(offset_x:int, offset_y:int, offset_z:int, width:int, height:int, depth:int, data:ByteArray):void
{
 
	int bytes_read;
	int full_width;
	int full_height;
	int full_depth;
	int bpp;
	int bpc;
	int i;
	char r, g, b, a;
	unsigned int byte;
	ILubyte * bytes;
 
	// Get the values from the library
	bpp = ilGetInteger(IL_IMAGE_BPP);
	bpc = ilGetInteger(IL_IMAGE_BPC);
	full_width = ilGetInteger(IL_IMAGE_WIDTH);
	full_height = ilGetInteger(IL_IMAGE_HEIGHT);
	full_depth = ilGetInteger(IL_IMAGE_DEPTH);
 
	// Check the given values
	if (offset_x + width > full_width)
		width = (full_width - offset_x);
	if (offset_y + height > full_height)
		height = (full_height - offset_y);
	if (offset_z + depth > full_depth)
		depth = (full_depth - offset_z);
 
	// Now get the information from the library
	bytes_read = width * height * depth * 4 * bpc;
	bytes = (ILubyte*)malloc(bytes_read);
	ilCopyPixels(offset_x, offset_y, offset_z, width, height, depth, IL_RGBA, IL_UNSIGNED_BYTE, bytes);
 
	// Switch RGBA to ARGB
	for (i=0; i < bytes_read; i+=4)
	{
		r = bytes[i];
		g = bytes[i+1];
		b = bytes[i+2];
		a = bytes[i+3];
 
		bytes[i] = a;
		bytes[i+1] = r;
		bytes[i+2] = g;
		bytes[i+3] = b;
	}
 
	// Copy the pixels into the bytes array
	AS3_SetS(data, "position", NULL);
	AS3_ByteArray_writeBytes(data, bytes, bytes_read);
 
	// Free up the memory
	free(bytes);
 
}

So the file in its entirety looks like this

// some C code with some includes -- top level blocks get emitted as-is to the C glue
{
	#include
	#include "include/IL/il.h"
}
 
// "int" AS3 <=> C "int"
// "uint" AS3 <=> C "unsigned"
// "Number" AS3 <=> C "double"
// "Boolean" AS3 <=> C "int"
// "String" AS3 <=> C malloc-ed "const char *" (returning one will free it!)
// else AS3 <=> C "AS3_Val"
 
// import the ByteArray class -- gets emitted into AS glue
import flash.utils.ByteArray;
 
public function ilInit():void;
 
public function ilLoadImage/ilLoadImage(path:String):(ILboolean)uint;
 
public function ilGetError():(ILenum)uint;
 
public function ilGetInteger(Mode:uint):(unsigned)uint;
 
public function ilOriginFunc(Mode:uint):(ILboolean)uint;
 
public function ilEnable(Mode:uint):(ILboolean)uint;
 
public function ilGetPixels(offset_x:int, offset_y:int, offset_z:int, width:int, height:int, depth:int, data:ByteArray):void
{
 
	int bytes_read;
	int full_width;
	int full_height;
	int full_depth;
	int bpp;
	int bpc;
	int i;
	char r, g, b, a;
	unsigned int byte;
	ILubyte * bytes;
 
	// Get the values from the library
	bpp = ilGetInteger(IL_IMAGE_BPP);
	bpc = ilGetInteger(IL_IMAGE_BPC);
	full_width = ilGetInteger(IL_IMAGE_WIDTH);
	full_height = ilGetInteger(IL_IMAGE_HEIGHT);
	full_depth = ilGetInteger(IL_IMAGE_DEPTH);
 
	// Check the given values
	if (offset_x + width > full_width)
		width = (full_width - offset_x);
	if (offset_y + height > full_height)
		height = (full_height - offset_y);
	if (offset_z + depth > full_depth)
		depth = (full_depth - offset_z);
 
	// Now get the information from the library
	bytes_read = width * height * depth * 4 * bpc;
	bytes = (ILubyte*)malloc(bytes_read);
	ilCopyPixels(offset_x, offset_y, offset_z, width, height, depth, IL_RGBA, IL_UNSIGNED_BYTE, bytes);
 
	// Switch RGBA to ARGB
	for (i=0; i < bytes_read; i+=4)
	{
		r = bytes[i];
		g = bytes[i+1];
		b = bytes[i+2];
		a = bytes[i+3];
 
		bytes[i] = a;
		bytes[i+1] = r;
		bytes[i+2] = g;
		bytes[i+3] = b;
	}
 
	// Copy the pixels into the bytes array
	AS3_SetS(data, "position", NULL);
	AS3_ByteArray_writeBytes(data, bytes, bytes_read);
 
	// Free up the memory
	free(bytes);
 
}

Now that we have our GlueGen file created, we’re ready to convert the GlueGen into C and AS. This can be accomplished by running

GlueGen devil.gg -cpackage cmodule.devil -package Zaa.IL -class ZaaIL

This will create glue.c and glue.as. With these files we can create our swc! We now need to turn Alchemy on again, if you’ve turned it off, by running alc-on. We can then use gcc to compile our glue.c file. When we do run this command, we once again need to tell gcc where to find the libraries that its linking against, since they’re static libraries. My command looked like this:

alc-on
sudo gcc glue.c -O3 -Llib/.libs -lIL -L../jpeg-8a -ljpeg -L../libpng-1.2.43 -lpng -L../zlib -lz -L../libmng-1.0.10 -lmng -swc -o zaail.swc

If you look in this directory, you should now see zaail.swc! There it is in all its glory! You now have a fully functional swc, copy it into the lib directory of your project and you’re off!

Now we need to discuss how exactly you can use your shiny new swc. There is some boiler plate code you need to get working with your object.

import cmodule.zaail.CLibInit;
private var loader:CLibInit = new CLibInit();
private var lib:Object = loader.init();

And that’s about it for the boiler plate. Import what you need and setup a couple of objects. Then you’re ready to call functions on your object. Here is the setup code for ZaaIL:

lib.ilInit();
lib.ilOriginFunc(ZaaILInterface.IL_ORIGIN_UPPER_LEFT);
lib.ilEnable(ZaaILInterface.IL_ORIGIN_SET);

You’ll notice that these are functions that we had exposed through the GlueGen. More about how you can interact with these libraries can be found here. Since this is actually running a virtual machine within the Flash Player some interactions with the C code have to be done differently. For instance to allow the virtual machine to access a file, you have to call supplyFile, give it the path and the ByteArray for the contents of the file.

Let us know if you have questions in the comments below.

Compiling ZaaIL with Alchemy – Part 2

This is Part 2 of our 3 part series on compiling ZaaIL from DevIL using the Adobe Alchemy toolset (you can find Part 1 here). Since Alchemy is at best alpha software… most of what I’m going to explain are fixes issues I ran into as I was working with Alchemy.

Issue 1: ALCHEMY_HOME not being found properly

The first issue has to do with the environment variable $ALCHEMY_HOME. You can check what your $ALCHEMY_HOME environment variable is set to by going to Terminal and typing:

echo $ALCHEMY_HOME

If you followed the steps correctly from Part 1 of this series, you should see something print out, mine says “/projects/zaalabs/alchemy-darwin-v0.5a”.

Unfortunately, one of the perl scripts (hacks.pl) in the ALCHEMY_HOME/achacks directory isn’t able to reference the $ALCHEMY_HOME environment variable correctly. Open up hacks.pl, and go to line 56. The way I fixed this, which is admittedly not the best way, is to hard-code my path into the file.

Issue 2: asc.jar is not found

Another issue in the hacks.pl file, found on line 57, is the path to asc.jar. ALCHEMY_HOME/asm-asc/lib does not exist, however there is an asc.jar in ALCHEMY_HOME/bin. Adjust the path accordingly and you’ll be rid of yet another compiler error.

hacks.pl Changes

Issue 3: Syntax error: expecting identifier before leftbrace

The next issue is within the GCC perl script (ALCHEMY_HOME/achacks/gcc). Open it up with your favorite text editor (I use vim… I know, old school), and find line 274. This regular expression is actually a little too restrictive and will throw errors regarding other generated Alchemy files. The line that needs to be changed looks like this:

if($o =~ /([^.]*)/)

and needs to be changed to look like this:

if($o =~ /([^/.]+)(..*)*$/)

This solution was found in the forums for Adobe Alchemy, posted by James Quirk. The error manifested itself as:

[Compiler] Error #1084: Syntax error: expecting identifier before leftbrace.
12679.achacks.as, Ln 1, Col 18:
package cmodule. {
.................^

GCC Perl Regex Change

Issue 4: error: ‘operator new’ takes type ‘size_t’ (‘long unsigned int’) as first parameter

If you are on a Mac, there is a good chance that you will see this error during compilation:

error: ‘operator new’ takes type ‘size_t’ (‘long unsigned int’) as first parameter

To fix this… we need to make a change when g++ gets called, it needs to have the -DOSX flag with it. This involves modifying the makefiles after the ./configure script generates them.

To do this, you need to open up the makefile and find the line where either CPPFLAGS or CXXFLAGS is being set. If CXXFLAGS is present, you should add the command here. If it isn’t present, you should add it to CPPFLAGS. Different makefiles use different variable names, but either way you’re looking for the variable that holds the flags to be passed to g++. In most of my makefiles the line looked like this:

CXXFLAGS = -O3

and I changed it to:

CXXFLAGS = -O3 -DOSX

Issue 5: My $PATH environment variable is empty

It should also be noted that sometimes I would find things in my terminal would start acting funny after running alc-off or alc-on. I found that when I did an echo $PATH, my path would be empty. The remedy was to close the terminal and reopen it, to restore things to a sane state.

Getting started!

Now we’re ready to start really compiling something! Lets start with zlib. This will unpack into the directory zlib-1.2.4, however libpng will expect it to be in the zlib. So instead of changing where libpng looks, lets just move zlib-1.2.4 to zlib. Now change directory into zlib, and run alc-on. Then we can run the configure script

mv zlib-1.2.4 zlib
cd zlib
alc-on
./configure

Output should be similar to the screen shot below.

ZLib Configuration Output

Now we’re ready to make/compile the code.

[Note] Using sudo here is important, otherwise you may get permission denied errors during some of the compilation steps.

sudo make

ZLib Make Output

This output looks fine, so zlib is ready to go. Next we install zlib. “sudo make install”. After the install completes, you can go ahead and run alc-off to return your system path to normal.

sudo make install
alc off

ZLib Make Install

[Note about compiling libpng] I ran into problems when compiling libpng with a configure script, so I downloaded the version that doesn’t use configure scripts and used it instead. Doing it this way allows you to skip the configure script, and just run a makefile directly. To do this you have to use the -f option for make and specify the path to the file. For libpng without the configuration script it has a folder named scripts that has a bunch of premade makefiles. The one we want is makefile.gcc which has been configured for a generic unix system.

Issue 6: Unable to open file: $ALCHEMY_HOME/avm2-libc/lib/asmachine.abc

As you are compiling these other libraries you may notice an error go past that reads:

[Compiler] Error #1063: Unable to open file: /projects/zaalabs/alchemy-darwin-v0.5a/avm2-libc/lib/asmachine.abc

This error occurs in some cases when your code tries to build/use a shared library. As far as I can tell… this file is not in the released version of Alchemy, and therefore shared libraries are broken. I haven’t found a fix for this error, and so for now I just work around it by using static libraries.

These steps should work for most of the dependencies. Remember that some of DevIL’s dependencies have dependencies of their own. Therefore the order in which you compile your libraries is important. ZLib must be compiled before LibPNG will compile, and all of DevILs dependencies must be compiled before we can compile DevIL.

Compiling DevIL

Once we’ve tackled the feat of configuring and compiling all of DevIL’s dependencies, we’re ready to compile DevIL. This time the compilation steps will be a bit different… since DevIL depends on all of these other libraries. Normally you would still follow the same procedure and things would turn out great, if you were compiling without Alchemy that is. However, Alchemy currently has some problems with shared libraries as mentioned above, so we’ll have to use static libraries.

This means when running gcc you need to append some special parameters, but we don’t want to manually compile the library, instead we want to use the makefile that is generated by the configure script. So we again need to modify the makefile.

After configuring DevIL using:

./configure

Open up the Makefile and find the line where IL_LIBSs is defined and modify it so that it reads:

IL_LIBS = -ltiff -lpng12 -llcms -ljpeg -L../jpeg-8a -L../tiff3.9.2 -L../libpng-1.2.43 -L../lcms-1.19

The -L arguments is added to tell gcc where to look for the dependencies when compiling the code.

DevIL Static Makefile Changes

Modify the makefile in the DevIL root folder, as well as the makefile in the lib directory of DevIL. After those modifications, you’re ready to compile DevIL with “sudo make” [make sure you run alc-on before you make this file as well].

At this point you should have a fully compiled DevIL with all of its necessary libraries linked in. Woot!

In the next post we’ll build our GlueGen file and compile into a usable swc. As always if you run into any problems or just want to leave a comment feel free to pipe up below.

ZaaIL in the Wild – Random Fractals Image Zoomer

It’s really cool when you get to see one of your projects being used by other developers. Taras Novak of Random Fractals has released his next version of Image Zoomer (v. 0.2), which is a really cool Flex 4 application that allows the user to move bitmap data around, zoom in on it, etc… simple, but effective.

Check it out here: Flex 4 Image Zoomer