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.

CImageLoaderXCF (Gimp XCF image loader)

Postby randomMesh » Thu Jun 14, 2012 2:20 am

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:
cpp 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
"In fact, nearly every sequence of punctuation is used for something in Perl. So, if you get writer’s block, just let the cat walk across the keyboard, and debug the result."

Katastrophe - A free, open source flocking boids simulation
User avatar
randomMesh
 
Posts: 1138
Joined: Fri Dec 29, 2006 12:04 am

Re: CImageLoaderXCF (Gimp XCF image loader)

Postby zerochen » Thu Jun 21, 2012 10:21 pm

hey

nice work.
if you change this lines below it also works under windows:)
cpp 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)
 
zerochen
 
Posts: 195
Joined: Wed Jan 07, 2009 1:17 am
Location: Germany

Re: CImageLoaderXCF (Gimp XCF image loader)

Postby hendu » Fri Jun 22, 2012 8:49 am

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)
hendu
 
Posts: 1557
Joined: Sat Dec 18, 2010 12:53 pm

Re: CImageLoaderXCF (Gimp XCF image loader)

Postby zerochen » Fri Jun 22, 2012 1:14 pm

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

cpp 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
zerochen
 
Posts: 195
Joined: Wed Jan 07, 2009 1:17 am
Location: Germany

Re: CImageLoaderXCF (Gimp XCF image loader)

Postby randomMesh » Fri Jun 22, 2012 1:46 pm

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.
"In fact, nearly every sequence of punctuation is used for something in Perl. So, if you get writer’s block, just let the cat walk across the keyboard, and debug the result."

Katastrophe - A free, open source flocking boids simulation
User avatar
randomMesh
 
Posts: 1138
Joined: Fri Dec 29, 2006 12:04 am


Return to Code Snippets

Who is online

Users browsing this forum: No registered users and 1 guest