PDA

View Full Version : Image packer project



paul_nicholls
23-10-2007, 12:03 AM
Hi guys :-)
I am currently writing an image packer utility that uses freeimage for loading/saving graphic files.

see screenshots of current version

http://www.postimage.org/aVoLeO9.jpg (http://www.postimage.org/image.php?v=aVoLeO9)
http://www.postimage.org/aVoLDKA.jpg (http://www.postimage.org/image.php?v=aVoLDKA)

I have incorporated in my code an updated version of the TPartition class that Nitrogen wrote for his Font Studio (http://www.nitrogen.za.org/projectinfo.asp?id=12) (Thanks Nitrogen!!).

I thought I'd share the updated TPartition unit here.

I have replaced the corner constants with an enumerated type for specifying how to pack the rectangles, added a new option for packing rectangles as horizontal strips, made the Insert method return true or false and the rect as a var parameter, altered variable names, and altered the code formatting (easier to read in my opinion, no offense intended to Nitrogen).

When my image packer is done, I will share it as well :)

Again, lots of thanks to Nitrogen for sharing the original partition code :-)

You can download the unit from here

http://fpc4gp2x.eonclash.com/downloads/Partitions.pas

I tried pasting it here but using the code and pascal both screwed up the formatting and some of the code :(

This is how I use the unit:


Type
{................................................. .............................}
TRectangle = Class
Rect : TRect;
Name : AnsiString;
FileName : AnsiString;
Width,Height : Integer;
Index : Integer;
WasInserted : Boolean;
End;
{................................................. .............................}

{................................................. .............................}
<SNIP>
{................................................. .............................}

{................................................. .............................}
Function CompareRectanglesByArea(a,b: Pointer): Integer;
Begin
Result := -1 * ((TRectangle(a).Width * TRectangle(a).Height) - (TRectangle(b).Width * TRectangle(b).Height));
End;
{................................................. .............................}

{................................................. .............................}
Function CompareRectanglesByIndex(a,b: Pointer): Integer;
Begin
Result := TRectangle(a).Index - TRectangle(b).Index;
End;
{................................................. .............................}

{................................................. .............................}
Procedure TForm_MainForm.PackRectangles(x,y,x2,y2: Integer; PackingMode: TPackingMode);
Var
Rectangle : TRectangle;
i : Integer;
Partition : TPartition;
r : TRect;
Begin
If FRectangles.Count <= 0 Then Exit;
Partition := TPartition.Create(x,y,x2,y2,PackingMode);

If PackingMode <> ePackingMode_HorizontalStrips Then
FRectangles.Sort(@CompareRectanglesByArea);
For i := 0 To FRectangles.Count - 1 Do
Begin
Rectangle := TRectangle(FRectangles.Items[i]);
Rectangle.WasInserted := False;
If Partition.Insert(Rectangle.Width,Rectangle.Height, r) Then
Begin
Rectangle.WasInserted := True;
Rectangle.Rect := r;
End;
End;

If PackingMode <> ePackingMode_HorizontalStrips Then
FRectangles.Sort(@CompareRectanglesByIndex);
Partition.Free;
For i := 0 To FRectangles.Count - 1 Do
Begin
Rectangle := TRectangle(FRectangles.Items[i]);
If Rectangle.WasInserted Then
StringGrid_ImagesToPack.Cells[1,i + 1] := ''
Else
StringGrid_ImagesToPack.Cells[1,i + 1] := 'X';
End;
End;
{................................................. .............................}

{................................................. .............................}


FRectangles is a TList holding a number of the TRectangle classes that I want to pack.

TRectangle.Rect is the rectangle where it was inserted, and TRectangle.WasInserted can be checked for to see if the rectangle was actually inserted.

TRectangle.Index allows me to sort the list by area and then back to the original order.

TRectangle.Width and TRectangle.Height is the width and height of this rectangle to be inserted.

After packing the rectangles I am going through the list and updating a stringgrid showing if the rectangle was inserted or not, but you can do whatever you want with this information of course.

I call the PackRectangles like so:
PackRectangles(0,0,FPackedImage.GetWidth,FPackedIm age.GetHeight,PackingMode);

the first 4 parameters are the rectangle (top,left, bottom,right) where I want to attempt to pack the rectangles into; in this case the whole of the specified image dimensions, and the PackingMode is just one of the TPackingMode enums from the TPartition unit.

cheers,
Paul.

arthurprs
23-10-2007, 12:52 AM
i don't understand what is a image packer, the ideia is put some images in a big one?

paul_nicholls
23-10-2007, 01:01 AM
Hi arthurprs,
yes an image packer is designed to pack multiple smaller images of any size into a larger image (usually with power of 2 dimensions).

This is usually done for a number of reasons:

a) save texture swapping
b) allow non-power of 2 dimensioned images to be used when you may be limited to only power of 2 sized textures.

This site gives examples and one reason (packing lightmaps using similar algorithm)
(http://www.blackpawn.com/texts/lightmaps/default.html)

I hope this helps :-)
cheers,
Paul

arthurprs
23-10-2007, 01:35 AM
Hi arthurprs,
yes an image packer is designed to pack multiple smaller images of any size into a larger image (usually with power of 2 dimensions).

This is usually done for a number of reasons:

a) save texture swapping
b) allow non-power of 2 dimensioned images to be used when you may be limited to only power of 2 sized textures.

This site gives examples and one reason (packing lightmaps using similar algorithm)
(http://www.blackpawn.com/texts/lightmaps/default.html)

I hope this helps :-)
cheers,
Paul

thx, talking about that, i need to implement pattern drawing on my framework, i will code something now ;P

Luuk van Venrooij
23-10-2007, 06:10 AM
Looks nice. Can you save the images to dds with mipmaps and compression?

paul_nicholls
24-10-2007, 01:33 AM
Looks nice. Can you save the images to dds with mipmaps and compression?

Not unless I get a 3rd party DDS writer, or create one myself.

Currently, the image formats supported are the ones freeimage support:

cheers,
Paul

arthurprs
24-10-2007, 01:38 AM
Looks nice. Can you save the images to dds with mipmaps and compression?

Not unless I get a 3rd party DDS writer, or create one myself.

Currently, the image formats supported are the ones freeimage support:

cheers,
Paul

http://imaginglib.sourceforge.net/index.php?page=about

don't know if it support everything you want in dds, but supporting saving dds

i use it in almost every project :) very powerfull library!

Luuk van Venrooij
24-10-2007, 04:29 AM
I also use it in my projects :)

paul_nicholls
29-10-2007, 04:29 AM
Hi guys :-)
I have uploaded a minimally working version of the Image Packer (http://fpc4gp2x.eonclash.com/downloads/Image Packer.7z) which includes the exe + source (Delphi 5 tested) + freeimage.dll.

You can add images and pack them in one of two ways (best fit partitioning (sorted from largest to smallest) or as horizontal strips in the order they are specified.

When images are imported, the program tries to guess what type they are; a single image, or an array of smaller images. This can be specified for each file at import time (or changed later by clicking on the Type column field for that image).

After packing the images you can alter the names of each packed image rectangle.

If any of the images couldn't be packed, their status will be a red cross instead of a green tick (images to pack grid)

The final total packed image size can be altered if needed using preset width and height values or using custom width and height.

You can export the packed image as BMP, PNG, or other image type (right click on packed image).
You can export the packed image rectangles data as INI or XML files (right click on the packed images grid.

A packed image file type will be created later on but for now this will do.

I know it is a work-in-progress, so feedback is important :-)

cheers,
Paul

arthurprs
29-10-2007, 04:25 PM
working nice here :)

my sugestion are,

default rect names = "(sourceimagename-extension)-#number"

and guidelines like these blank lines
http://img135.imageshack.us/img135/9541/imageinfovm1.png

paul_nicholls
29-10-2007, 09:23 PM
working nice here :)

my sugestion are,

default rect names = "(sourceimagename-extension)-#number"

and guidelines like these blank lines
http://img135.imageshack.us/img135/9541/imageinfovm1.png

Thanks :-)

So you think I should make names like this example?

Explosion-png#0
Explosion-png#1
Explosion-png#2
etc.

Ok, that could be a good idea as a starting point.

I will look into adding an option to have a gap around the images when packing them...it will need some thought when packing images that are arrays of images.

cheers,
Paul

arthurprs
30-10-2007, 01:19 AM
working nice here :)

my sugestion are,

default rect names = "(sourceimagename-extension)-#number"

and guidelines like these blank lines
http://img135.imageshack.us/img135/9541/imageinfovm1.png

Thanks :-)

So you think I should make names like this example?

Explosion-png#0
Explosion-png#1
Explosion-png#2
etc.

Ok, that could be a good idea as a starting point.

I will look into adding an option to have a gap around the images when packing them...it will need some thought when packing images that are arrays of images.

cheers,
Paul
from a sprite pic named explosion.png and fog.png
-explosion#0
-explosion#1
-explosion#2
-explosion#3
-fog#0
-fog#1

and another thing, when loading image arrays an option to determine width and heigh of titles, sometimes it can be very usefull


sorry if im abusing on the suggestions :?

paul_nicholls
30-10-2007, 02:03 AM
from a sprite pic named explosion.png and fog.png
-explosion#0
-explosion#1
-explosion#2
-explosion#3
-fog#0
-fog#1

and another thing, when loading image arrays an option to determine width and heigh of titles, sometimes it can be very usefull

It now uses the filename without path and extension as the default image name for the rectangles as you have suggested (not uploaded yet).

I am not sure what you mean by the option to determine the width and height of tiles...it already does this when you add images, and when you click on the type column field for an image you can alter this if you wish.

cheers,
Paul

arthurprs
30-10-2007, 05:51 PM
from a sprite pic named explosion.png and fog.png
-explosion#0
-explosion#1
-explosion#2
-explosion#3
-fog#0
-fog#1

and another thing, when loading image arrays an option to determine width and heigh of titles, sometimes it can be very usefull

It now uses the filename without path and extension as the default image name for the rectangles as you have suggested (not uploaded yet).

I am not sure what you mean by the option to determine the width and height of tiles...it already does this when you add images, and when you click on the type column field for an image you can alter this if you wish.

cheers,
Paul
Yes but if you have a 200x200 image with 80x80 titles, the columns and rows option will not work correctly

paul_nicholls
30-10-2007, 09:58 PM
Ah, ok...I see what you are getting at now :-)
cheers,
Paul