CImageLoaderXCF (Gimp XCF image loader)

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

CImageLoaderXCF (Gimp XCF image loader)

Post by randomMesh »

The other day i wanted to use an XCF image with Irrlicht. I realized that this wasn't possible, so i made a CImageLoaderXCF.

Description of the XCF image file format

Features:
- Supports multiple layers
- RGB, Grayscale, and Indexed mode with or without alpha channel

Usage is very simple:

Code: Select all

 
#include "CImageLoaderXCF.h"
#include <irrlicht.h>
 
int main()
{
        //setup as usual
        irr::IrrlichtDevice* device = irr::createDevice(irr::video::EDT_OPENGL);
        irr::scene::ISceneManager* smgr = device->getSceneManager();
        irr::video::IVideoDriver* driver = device->getVideoDriver();
 
        //tell Irrlicht there's a new image loader for xcf images
        irr::video::CImageLoaderXCF* xcf_loader = new irr::video::CImageLoaderXCF(device);
        driver->addExternalImageLoader(xcf_loader);
        xcf_loader->drop();
 
        //path to xcf image
        irr::io::path path("test.xcf");
 
        //irrlicht can now directly load xcf images
        irr::video::ITexture* texture = driver->getTexture(path);
 
        //display it on a cube
        irr::scene::IMeshSceneNode* cube = smgr->addCubeSceneNode(10.0f);
        if (texture)
        {
                cube->setMaterialType(irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL); //xcf images support alpha channels
                cube->setMaterialTexture(0, texture);
                cube->setMaterialFlag(irr::video::EMF_LIGHTING, false);
        }
 
 
        //if you want more control over the image:
        //create an XCFImage object. (must be dropped after usage)
        irr::video::XCFImage* xcf_image = xcf_loader->createImage(path);
 
        //this is the method to get the full image with all the layers
        irr::video::IImage* img = xcf_image->createIrrlichtImageFull();
        img->drop();
 
        //you can access all layers of the image and get an IImage out of them
        irr::u32 numLayers = xcf_image->getNumLayers();
        for (irr::u32 i = 0; i < numLayers; ++i)
        {
                irr::video::XCFImage::Layer* layer = xcf_image->getLayer(i);
 
                irr::video::IImage* img = xcf_image->createIrrlichtImageFromLayer(layer);
 
                irr::scene::IMeshSceneNode* cube = smgr->addCubeSceneNode(10.0f);
                cube->setPosition(irr::core::vector3df(i*10 + 10, 0, 0));
                cube->setMaterialType(irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL);
                cube->setMaterialTexture(0, driver->addTexture(layer->name, img));
                cube->setMaterialFlag(irr::video::EMF_LIGHTING, false);
 
                img->drop();
        }
 
 
 
        irr::scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(0, 40,0.05);
        camera->setPosition(irr::core::vector3df(0,0, -15.0f));
 
        while (device->run())
        {
                driver->beginScene(true, true, irr::video::SColor(255, 128, 128, 128));
                smgr->drawAll();
                driver->endScene();
        }
 
 
        delete xcf_image;
 
        device->drop();
 
        return 0;
}
 
 
I am still working on it, it's not finished and there may be a lot of bugs. Please test it and give feedback if you like :)

Known issues:
- Layers must have same size
- Layer modes other than Normal are not supported
- Flattening process of layers is very slow and unoptimized. If you have a better algorithm, please tell me!
- Ignoring channels and masks for now

Download: xfc_reader.zip (Test image included)

Screenshot:
Image
"Whoops..."
zerochen
Posts: 273
Joined: Wed Jan 07, 2009 1:17 am
Location: Germany

Re: CImageLoaderXCF (Gimp XCF image loader)

Post by zerochen »

hey

nice work.
if you change this lines below it also works under windows:)

Code: Select all

 
Index: XCFImage.cpp
===================================================================
--- XCFImage.cpp        (Revision 34)
+++ XCFImage.cpp        (Arbeitskopie)
@@ -9,7 +9,12 @@
 #include "XCFImage.h"
 #include <IrrlichtDevice.h>
 #include <IReadFile.h>
+
+#ifdef _WIN32
+#include <Winsock2.h>
+#else
 #include <netinet/in.h>
+#endif
 
 namespace irr
 {
@@ -894,7 +899,7 @@
                        u32 is_visible;
                        this->totalBytesRead += this->readInt(&is_visible, 1);
 
-                       layer->isVisible = is_visible;
+                       layer->isVisible = is_visible == 0 ? false : true;
 
                        if (this->verbose)
                        {
@@ -909,7 +914,7 @@
                        u32 linked;
                        this->totalBytesRead += this->readInt(&linked, 1);
 
-                       layer->isLinked = linked;
+                       layer->isLinked = linked == 0 ? false : true;
 
                        if (this->verbose)
                        {
@@ -924,7 +929,7 @@
                        u32 lock_content;
                        this->totalBytesRead += this->readInt(&lock_content, 1);
 
-                       layer->lockContent = lock_content;
+                       layer->lockContent = lock_content == 0 ? false : true;
 
                        if (this->verbose)
                        {
@@ -939,7 +944,7 @@
                        u32 lock_alpha;
                        this->totalBytesRead += this->readInt(&lock_alpha, 1);
 
-                       layer->lockAlpha = lock_alpha;
+                       layer->lockAlpha = lock_alpha == 0 ? false : true;
 
                        if (this->verbose)
                        {
@@ -954,7 +959,7 @@
                        u32 apply_mask;
                        this->totalBytesRead += this->readInt(&apply_mask, 1);
 
-                       layer->applyLayerMask = apply_mask;
+                       layer->applyLayerMask = apply_mask == 0 ? false : true;
 
                        if (this->verbose)
                        {
@@ -969,7 +974,7 @@
                        u32 edit_mask;
                        this->totalBytesRead += this->readInt(&edit_mask, 1);
 
-                       layer->editMask = edit_mask;
+                       layer->editMask = edit_mask == 0 ? false : true;
 
                        if (this->verbose)
                        {
@@ -984,7 +989,7 @@
                        u32 show_mask;
                        this->totalBytesRead += this->readInt(&show_mask, 1);
 
-                       layer->showMask = show_mask;
+                       layer->showMask = show_mask == 0 ? false : true;
 
                        if (this->verbose)
                        {
@@ -1176,7 +1181,7 @@
                        u32 visibility;
                        this->totalBytesRead += this->readInt(&visibility, 1);
 
-                       channel->isVisible = visibility;
+                       channel->isVisible = visibility == 0 ? false : true;
 
                        if (this->verbose)
                                this->device->getLogger()->log("\t\t\tSetting visibility", ELL_INFORMATION);
@@ -1188,7 +1193,7 @@
                        u32 linked;
                        this->totalBytesRead += this->readInt(&linked, 1);
 
-                       channel->isLinked = linked;
+                       channel->isLinked = linked == 0 ? false : true;
 
                        if (this->verbose)
                                this->device->getLogger()->log("\t\t\tChannel is linked", ELL_INFORMATION);
@@ -1200,7 +1205,7 @@
                        u32 locked;
                        this->totalBytesRead += this->readInt(&locked, 1);
 
-                       channel->lockContent = locked;
+                       channel->lockContent = locked == 0 ? false : true;
 
                        if (this->verbose)
                                this->device->getLogger()->log("\t\t\tContent is locked", ELL_INFORMATION);
@@ -1212,7 +1217,7 @@
                        u32 show_masked;
                        this->totalBytesRead += this->readInt(&show_masked, 1);
 
-                       channel->showMasked = show_masked;
+                       channel->showMasked = show_masked == 0 ? false : true;
 
                        if (this->verbose)
                        {
@@ -1397,7 +1402,7 @@
                //if the offset is 0 then we need to read in the maximum possible allowing for negative compression
                if (next_offset == 0)
                {
-                       next_offset = tile_offset + XCF_TILE_WIDTH*XCF_TILE_WIDTH*4*1.5;
+                       next_offset = (u32)(tile_offset + XCF_TILE_WIDTH * XCF_TILE_WIDTH * 4 * 1.5f);
                }
 
                file->seek(tile_offset);
@@ -1406,7 +1411,7 @@
                tileHeight = tileY < numTilesY ? XCF_TILE_HEIGHT : hierarchy_height - (tileY-1)*XCF_TILE_HEIGHT;
                tile_buffer_size = tileWidth*tileHeight*hierarchy_bpp;
 
-               u8 tile_buffer[tile_buffer_size];
+               u8* tile_buffer = new u8[tile_buffer_size];
 
                switch (compression)
                {
@@ -1441,7 +1446,12 @@
                }
 
                if (fail)
+               {
+                       if(tile_buffer)
+                               delete[] tile_buffer;
+
                        return false;
+               }
 
 
                //merge buffers
@@ -1457,6 +1467,8 @@
                        buffer_index += hierarchy_width; //offset between two pixels on the same column but in 2 adiacent lines.
                }
 
+               if(tile_buffer)
+                       delete[] tile_buffer;
 
                ++tileX;
                if (tileX%(numTilesX + 1) == 0)
 
hendu
Posts: 2600
Joined: Sat Dec 18, 2010 12:53 pm

Re: CImageLoaderXCF (Gimp XCF image loader)

Post by hendu »

Why the dynamic tile_buffer? That's just wasting time to allocate it, it's small enough to be statically allocated.

Also, what are net functions doing in an image loader ;) sending your info to the big brother?

(I kid, you're likely using the byte swapping functions. But irr has native ones too)
zerochen
Posts: 273
Joined: Wed Jan 07, 2009 1:17 am
Location: Germany

Re: CImageLoaderXCF (Gimp XCF image loader)

Post by zerochen »

yes i was wondering about the net staff too.
he use the ntohl() function to convert a datatype.

the dynamic alloc is because you cant do something like this

Code: Select all

 
tile_buffer_size = tileWidth*tileHeight*hierarchy_bpp;
 
u8 tile_buffer[tile_buffer_size];
 
tile_buffer_size can be zero and that is not allowed
i wonder why his compiler don't complain about it.
i use win7 and vs2010
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

Re: CImageLoaderXCF (Gimp XCF image loader)

Post by randomMesh »

Thank you for your comments.
if you change this lines below it also works under windows:)
Thank you for the patch! Much appreciated! I must admit that i didn't test it under Windows before release. :oops:
tile_buffer_size can be zero and that is not allowed
GCC v. 4.4.5 under Linux didn't complain unless i enabled the -pedantic switch. And then just issues a warning: "warning: ISO C++ forbids variable length array ‘tile_buffer’", no error.
you're likely using the byte swapping functions. But irr has native ones too
Yes, there's os::Byteswap::byteswap, but it's not exposed by the API. So i decided to use ntohl.
"Whoops..."
Post Reply