Indigo Image (.igi) format

A forum for exporter development discussion.
User avatar
OnoSendai
Developer
Posts: 6241
Joined: Sat May 20, 2006 6:16 pm
Location: Wellington, NZ
Contact:

Indigo Image (.igi) format

Post by OnoSendai » Tue Feb 13, 2007 10:07 pm

All comments and suggestions welcome:

Obviously this is a very simple format, just the way I like it :)

Also the image sizes are gigantic, but I don't really care.

Note that the Indigo Tone Mapper program expects the colour space to be XYZ.

Do whatever you want with this format, the spec is 'public domain'.
Look forward to seeing some cool stuff :)

Code: Select all

/*=====================================================================
IndigoImageHeader
-----------------
This should be stored on disk as a tightly packed structure (no padding between elements)
in little endian byte order.
Image data starts at byte 5032. (This should also be the size of the header on disk)

All integers and unsigned integers are 32 bit
=====================================================================*/
class IndigoImageHeader
{
public:
	IndigoImageHeader(){}
	~IndigoImageHeader(){}

	static const int MAGIC_NUMBER = 66613373;
	int magic_number; // Should be 66613373
	static const int LATEST_FORMAT_VERSION = 4;
	int format_version;

	double num_samples; // Total num samples taken over entire image
	unsigned int width; // Width of supersampled (large) image
	unsigned int height; // Height of supersampled (large) image
	unsigned int supersample_factor; // >= 1
	int zipped; // Boolean

	int image_data_size; // Size of image data in bytes
	// Should be equal to width*height*12*num_layers, if data is uncompressed.

	unsigned int colour_space; // 0 = XYZ

	// New in format version 2: total render time spent on image, in seconds.
	double render_time;

	// New in format version 3: number of light layers in file.
	unsigned int num_layers;

	// New in format version 4: Layer names
	unsigned int layer_name_format; // 0 = ASCII
	unsigned int num_named_layers; // This should be <= num_layers
	struct LayerName
	{
		unsigned int layer_name_len;
		static const int MAX_LAYER_NAME_BYTES = 64;
		char name_data[MAX_LAYER_NAME_BYTES];
	}; // 68 bytes

	static const int MAX_NUM_LAYER_NAMES = 16;
	LayerName layer_names[MAX_NUM_LAYER_NAMES]; // 68B * 16 = 1088B

	unsigned int last_rng_seed;

	// 16 * 4 = 64 bytes + 1088 bytes = 1152 bytes

	unsigned char padding[3880]; // Padding in case I want more stuff in the header in future.  Starts at byte 1152.

	// Image data follows:
	// For each layer,
	// top row, then next-to-top row, etc...
	// left to right across the row.
	// 3 32 bit floats per pixel.
};

Old specification (version 2)

Code: Select all

class IndigoImageHeader
{
public:
	IndigoImageHeader();

	~IndigoImageHeader();

	// All integers and unsigned integers are 32 bit
	// Byte order should be little endian (Intel byte order)

	int magic_number; // Should be 66613373
	int format_version; // Latest version is 2

	double num_samples; // Total num samples taken over entire image
	unsigned int width; // Width of supersampled (large) image
	unsigned int height; // Height of supersampled (large) image
	unsigned int supersample_factor; // >= 1
	int zipped; // Boolean

	int image_data_size; // Size of image data in bytes
	// Should be equal to width*height*12, if data is uncompressed.

	unsigned int colour_space; // 0 = XYZ

	// New in format version 2: total render time spent on image, in seconds.
	double render_time;

	unsigned char padding[4992]; // Padding in case I want more stuff in the header in future.

	// Image data follows:
	// top row, then next-to-top row, etc...
	// left to right across the row.
	// 3 32 bit floats per pixel.
};






Old v1 spec:

Code: Select all

class IndigoImageHeader
{
public:
	/*=====================================================================
	IndigoImageHeader
	-----------------
	
	=====================================================================*/
	IndigoImageHeader();

	~IndigoImageHeader();

	//all integers and unsigned integers are 32 bit

	int magic_number;//should be 66613373
	int format_version;//1

	double num_samples;//total num samples taken over entire image
	unsigned int width;//width of supersampled (large) image
	unsigned int height;//height of supersampled (large) image
	unsigned int supersample_factor;// >= 1
	int zipped;//boolean

	int image_data_size;//size of image data in bytes
	//should be equal to width*height*12, if data is uncompressed.

	unsigned int colour_space;//0 = XYZ

	unsigned char padding[5000];//padding in case i want more stuff in the header in future

	//image data follows:
	//top row, then next-to-top row, etc...
	//left to right across the row.
	//3 32 bit floats per pixel.
};

Last edited by OnoSendai on Thu Feb 19, 2009 3:19 pm, edited 3 times in total.

User avatar
VictorJapi
Posts: 58
Joined: Sun Jan 21, 2007 1:27 am
Location: Zamora - Algeciras || España

Post by VictorJapi » Tue Feb 13, 2007 11:52 pm

Why not a pre/post scale and burn vars? so the image could be saved without any transformation applied and do it at load time with the defaults saved.
winmain(){
japi victorJapi;
victorJapi::Signature();
}

User avatar
eman7613
Posts: 597
Joined: Sat Sep 16, 2006 2:52 pm

Post by eman7613 » Wed Feb 14, 2007 1:36 pm

it occurs to me... is there a conversion method to get the igi to a png, jpg, or bmp?
Yes i know, my spelling sucks

User avatar
manitwo
Posts: 1029
Joined: Wed Jul 05, 2006 4:50 am
Location: Tirol - Austria

Post by manitwo » Wed Feb 14, 2007 1:40 pm

you can use the new tonemapper to export to jpg or png :wink:

ryjo
Posts: 68
Joined: Tue Jul 04, 2006 6:16 am
Location: Pluton

Post by ryjo » Thu Feb 15, 2007 9:51 pm

Thanks,

Could youd add the endianess of the ints/floats etc, and the specific order the color values are stored (R,G,B or B,G,R). :)

ryjo

User avatar
OnoSendai
Developer
Posts: 6241
Joined: Sat May 20, 2006 6:16 pm
Location: Wellington, NZ
Contact:

Post by OnoSendai » Thu Feb 15, 2007 10:04 pm

little endian (Intel byte order).

The pixels aren't RGB, but XYZ, a more general 3-d colour space.

Deus
Posts: 336
Joined: Sun Feb 04, 2007 3:47 am

Post by Deus » Thu Feb 15, 2007 10:23 pm

Little endian is gay.

User avatar
OnoSendai
Developer
Posts: 6241
Joined: Sat May 20, 2006 6:16 pm
Location: Wellington, NZ
Contact:

Post by OnoSendai » Thu Feb 15, 2007 10:32 pm

Deus wrote:Little endian is gay.
lol :)

User avatar
VictorJapi
Posts: 58
Joined: Sun Jan 21, 2007 1:27 am
Location: Zamora - Algeciras || España

Post by VictorJapi » Thu Feb 15, 2007 10:33 pm

Deus wrote:Little endian is gay.
THIS IS THE WAAAARRRR!!! DEATH TO BIG ENDIAAAAAAN!!!!
winmain(){
japi victorJapi;
victorJapi::Signature();
}

ryjo
Posts: 68
Joined: Tue Jul 04, 2006 6:16 am
Location: Pluton

Post by ryjo » Fri Feb 16, 2007 2:34 am

Hi,

I wrote an implementation of this format so igi files can be read from Java.

Code: Select all

/*
 * Public Domain.
 * 
 * Note that this piece of software may be unfinished or buggy, or both.
 * 
 */
package igi;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.channels.FileChannel;

/**
 * Support for reading igi (indigo image) files.
 * <p>
 * Example usage:
 * <pre>
 * IGI igi = new IGI(filename);
 * int w = igi.getWidth();
 * int h = igi.getHeight();
 * float[] x = new float[w * h];
 * float[] y = new float[w * h];
 * float[] z = new float[w * h];
 * igi.readData(x, y, z);
 * </pre>
 * 
 * @version igi ver 1
 */
public class IGI {
	private static final int IGI_VERSION = 1;
	private static final int HEADER_SIZE = 40;
	private static final int HEADER_EXTRA_SIZE = 5000;
	private static final int DATA_BLOCK_START = HEADER_SIZE + HEADER_EXTRA_SIZE;
	
	private final File file;
	private final int dataSize;
	private final int width;
	private final int height;
	private final int sampleFactor;
	private final double samples;
	
	/**
	 * Create an IGI instance and read the header data.
	 * 
	 * @param path
	 *            The path to the file.
	 * @throws IOException
	 *             If the file is not accessable, or is not in the correct
	 *             format.
	 */
	public IGI(String path) throws IOException {
		this(new File(path));
	}

	/**
	 * Create an IGI instance and read the header data.
	 * 
	 * @param file
	 *            The file to read.
	 * @throws IOException
	 *             If the file is not accessable, or is not in the correct
	 *             format.
	 */
	public IGI(File f) throws IOException {
		this.file = f.getCanonicalFile();

		ByteBuffer buffer = ByteBuffer.allocate(HEADER_SIZE);
		buffer.order(ByteOrder.LITTLE_ENDIAN);
		RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
		FileChannel fileChannel = randomAccessFile.getChannel();

		try {
			fileChannel.read(buffer);
			buffer.flip();
			
			int magic = buffer.getInt();
			int version = buffer.getInt();
			double samples = buffer.getDouble();
			int width = buffer.getInt();
			int height = buffer.getInt();
			int sampleFactor = buffer.getInt();
			int compression = buffer.getInt();
			int dataSize = buffer.getInt();
			int colorSpace = buffer.getInt();
	
			if (magic != 66613373)
				throw new IOException("wrong magic: " + magic);
			
			if (version != IGI_VERSION)
				throw new IOException("unsupported version: " + version);
			
			if (compression != 0)
				throw new IOException("unsupported compression: " + compression);
	
			if (colorSpace != 0)
				throw new IOException("unsupported color space: " + colorSpace);
			
			if (dataSize < 0)
				throw new IOException("illegal data block size: " + dataSize);
			
			// Only support 31 bit "unsigned" ints
			if (width <= 0 || height <= 0 || sampleFactor <= 0)
				throw new IOException(
						"unsupported dimension: width=" + width + 
						" height=" + height + 
						" sampleFactor=" + sampleFactor);
			
			this.samples = samples;
			this.dataSize = dataSize;
			this.width = width;
			this.height = height;
			this.sampleFactor = sampleFactor;
		} finally {
			try {
				fileChannel.close();
			} catch (IOException e) {
			}
		}
	}
	
	/**
	 * Read the data block and store as X, Y and Z channels.
	 * @param x The X data values.
	 * @param y The Y data values.
	 * @param z The Z data values.
	 * @throws IOException If there is an io problem or the data block is incomplete.
	 */
	public void readData(float[] x, float[] y, float[] z) throws IOException {
		RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
		FileChannel fileChannel = randomAccessFile.getChannel();

		try {
			readData(fileChannel, x, y, z);
		} finally {
			try {
				fileChannel.close();
			} catch (IOException e) {
			}
		}
	}

	private void readData(FileChannel fileChannel, float[] x, float[] y, float[] z) throws IOException {
		ByteBuffer dataBuffer = ByteBuffer.allocate(dataSize);
		dataBuffer.order(ByteOrder.LITTLE_ENDIAN);
		int n = fileChannel.read(dataBuffer, DATA_BLOCK_START);
		if (n != dataSize)
			throw new IOException("incomplete data block: expected " + dataSize + " got " + n);

		dataBuffer.flip();
		FloatBuffer xyzFloats = dataBuffer.asFloatBuffer();

		try {
			for (int i=0; xyzFloats.hasRemaining(); i++) {
				x[i] = xyzFloats.get();
				y[i] = xyzFloats.get();
				z[i] = xyzFloats.get();
			}
		} catch (RuntimeException e) {
			throw new IOException("buffer error: " + e);
		}
	}

	/**
	 * Return the "Super Sample Factor" from the igi file header.
	 * @return The "Super Sample Factor" from the igi file header.
	 */
	public int getSampleFactor() {
		return sampleFactor;
	}

	/**
	 * Return the igi image height.
	 * @return The image height.
	 */
	public int getHeight() {
		return height;
	}

	/**
	 * Return the igi image width.
	 * @return The image width.
	 */
	public int getWidth() {
		return width;
	}

	/**
	 * Return the size of the image data block.
	 * @return The size of the image data block.
	 */
	public int getDataSize() {
		return dataSize;
	}
	
	/**
	 * Return the samples field of the igi header.
	 * @return The samples field of the igi header.
	 */
	public double getSamples() {
		return samples;
	}

	/**
	 * Retrieve the file for this igi image.
	 * @return The file object.
	 */
	public File getFile() {
		return file;
	}
}

User avatar
OnoSendai
Developer
Posts: 6241
Joined: Sat May 20, 2006 6:16 pm
Location: Wellington, NZ
Contact:

Post by OnoSendai » Fri Feb 16, 2007 2:37 am

nice! looks kinda like my C++ code :)

ryjo
Posts: 68
Joined: Tue Jul 04, 2006 6:16 am
Location: Pluton

Post by ryjo » Fri Feb 16, 2007 2:56 am

OnoSendai wrote:nice! looks kinda like my C++ code :)
Yes, Java and C++ are fairly similar, except in Java you write all code for a class in the same file. And all memory management is very different. And speed, when you run it :) (though I think its pretty fast nowadays)

Deus
Posts: 336
Joined: Sun Feb 04, 2007 3:47 am

Post by Deus » Fri Feb 16, 2007 3:45 am

"However, when Java is promoted as the sole programming language, its flaws and limitations become serious."
Bjarne Stroustrup

I like java. But when I need to solve a problem that could benefit from java compared to C/C++ I would pick python in 80% of the cases.

User avatar
matsta
Posts: 730
Joined: Mon Jan 29, 2007 7:50 am
Location: 127.0.0.1

Post by matsta » Fri Feb 23, 2007 8:10 am

rofl noob question coming up XD.

wat must i do with the code to be able to save as igi?

lol told u

ryjo
Posts: 68
Joined: Tue Jul 04, 2006 6:16 am
Location: Pluton

Post by ryjo » Fri Feb 23, 2007 8:58 am

matsta wrote:rofl noob question coming up XD.

wat must i do with the code to be able to save as igi?

lol told u
infile.txt -> set "save_igi" to "true"

That should work.

Post Reply
25 posts

Who is online

Users browsing this forum: No registered users and 4 guests