xcf.c

Go to the documentation of this file.
00001 /* This file contains code for unified image loading from XCF file  */
00002 /********************************************************************/
00003 /* Copyright (c) 2001 Sasha Vasko <sasha at aftercode.net>           */
00004 /********************************************************************/
00005 /*
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 
00021 #ifdef _WIN32
00022 #include "win32/config.h"
00023 #else
00024 #include "config.h"
00025 #endif
00026 
00027 /*#define LOCAL_DEBUG*/
00028 /*#define DO_CLOCKING*/
00029 
00030 #ifdef HAVE_STDLIB_H
00031 #include <stdlib.h>
00032 #endif
00033 #include <string.h>
00034 #if TIME_WITH_SYS_TIME
00035 # include <sys/time.h>
00036 # include <time.h>
00037 #else
00038 # if HAVE_SYS_TIME_H
00039 #  include <sys/time.h>
00040 # else
00041 #  include <time.h>
00042 # endif
00043 #endif
00044 
00045 #ifdef _WIN32
00046 # include "win32/afterbase.h"
00047 #else
00048 # include "afterbase.h"
00049 #endif
00050 #include "asimage.h"
00051 #include "xcf.h"
00052 
00053 static XcfProperty *read_xcf_props( FILE *fp );
00054 static XcfListElem *read_xcf_list_offsets( FILE *fp, size_t elem_size );
00055 static void             read_xcf_layers( XcfImage *xcf_im, FILE *fp, XcfLayer *head );
00056 static void                     read_xcf_channels( XcfImage *xcf_im, FILE *fp, XcfChannel *head );
00057 static XcfHierarchy*read_xcf_hierarchy( XcfImage *xcf_im, FILE *fp, CARD8 opacity, ARGB32 colormask );
00058 static void             read_xcf_levels( XcfImage *xcf_im, FILE *fp, XcfLevel *head );
00059 static void             read_xcf_tiles( XcfImage *xcf_im, FILE *fp, XcfTile *head );
00060 static void             read_xcf_tiles_rle( XcfImage *xcf_im, FILE *fp, XcfTile *head );
00061 
00062 static size_t
00063 xcf_read8 (FILE *fp, CARD8 *data, int count)
00064 {
00065         size_t total = count;
00066 
00067         while (count > 0)
00068     {
00069                 int bytes = fread ((char*) data, sizeof (char), count, fp);
00070         if( bytes <= 0 )
00071                         break;
00072         count -= bytes;
00073         data += bytes;
00074     }
00075         return total;
00076 }
00077 
00078 static size_t
00079 xcf_read32 (FILE *fp, CARD32 *data, int count)
00080 {
00081         size_t total = count;
00082         if( count > 0 )
00083         {
00084                 CARD8 *raw = (CARD8*)data ;
00085                 total = xcf_read8( fp, raw, count<<2 )>>2;
00086                 count = 0 ;
00087 #ifndef WORDS_BIGENDIAN
00088                 while( count < (int)total )
00089                 {
00090                         data[count] = (raw[0]<<24)|(raw[1]<<16)|(raw[2]<<8)|raw[3];
00091                         ++count ;
00092                         raw += 4 ;
00093                 }
00094 #endif
00095         }
00096         return total;
00097 }
00098 
00099 static void
00100 xcf_skip_string (FILE *fp)
00101 {
00102         CARD32 size = 0;
00103         if( xcf_read32 (fp, &size, 1)< 1 )
00104                 return;
00105         if( size > 0 )
00106         {
00107                 fseek(fp, size, SEEK_CUR );
00108         }
00109 }
00110 void print_xcf_layers( char* prompt, XcfLayer *head );
00111 
00112 XcfImage *
00113 read_xcf_image( FILE *fp )
00114 {
00115         XcfImage *xcf_im = NULL ;
00116         XcfProperty *prop ;
00117 
00118         if( fp )
00119         {
00120                 int i ;
00121                 char sig[XCF_SIGNATURE_FULL_LEN+1] ;
00122                 if( xcf_read8( fp, (unsigned char*)&(sig[0]),XCF_SIGNATURE_FULL_LEN ) >= XCF_SIGNATURE_FULL_LEN )
00123                 {
00124                         if( mystrncasecmp( sig, XCF_SIGNATURE, XCF_SIGNATURE_LEN) == 0 )
00125                         {
00126                                 xcf_im = safecalloc( 1, sizeof(XcfImage));
00127                                 if( mystrncasecmp( &(sig[XCF_SIGNATURE_LEN+1]), "file", 4 ) == 0 )
00128                                         xcf_im->version = 0 ;
00129                                 else
00130                                         xcf_im->version = atoi(&(sig[XCF_SIGNATURE_LEN+1]));
00131                                 if( xcf_read32( fp, &(xcf_im->width), 3 ) < 3 )
00132                                 {
00133                                         free( xcf_im );
00134                                         xcf_im = NULL ;
00135                                 }
00136                         }
00137                 }
00138                 if( xcf_im == NULL )
00139                 {
00140                         show_error( "invalid .xcf file format - not enough data to read" );
00141                         return NULL ;
00142                 }
00143 
00144                 xcf_im->properties = read_xcf_props( fp );
00145                 for( prop = xcf_im->properties ; prop != NULL ; prop = prop->next )
00146                 {
00147                         if( prop->id == XCF_PROP_COLORMAP )
00148                         {
00149                                 register int i ;
00150                                 CARD32 n = *((CARD32*)(prop->data)) ;
00151                                 n = as_ntohl(n);
00152                                 xcf_im->num_cols = n ;
00153                                 xcf_im->colormap = safemalloc( MAX(n*3,(CARD32)XCF_COLORMAP_SIZE));
00154                                 if( xcf_im->version == 0 )
00155                                 {
00156                                         for( i = 0 ; i < (int)n ; i++ )
00157                                         {
00158                                                 xcf_im->colormap[i*3] = i ;
00159                                                 xcf_im->colormap[i*3+1] = i ;
00160                                                 xcf_im->colormap[i*3+2] = i ;
00161                                         }
00162                                 }else
00163                                         memcpy( xcf_im->colormap, prop->data+4, MIN(prop->len-4,n));
00164                         }else if( prop->id == XCF_PROP_COMPRESSION )
00165                                 xcf_im->compression = *(prop->data);
00166                 }
00167                 xcf_im->layers =        (XcfLayer*)  read_xcf_list_offsets( fp, sizeof(XcfLayer)  );
00168                 xcf_im->channels =      (XcfChannel*)read_xcf_list_offsets( fp, sizeof(XcfChannel));
00169                 for( i = 0 ; i < XCF_TILE_HEIGHT ; i++ )
00170                         prepare_scanline(xcf_im->width,0,&(xcf_im->scanline_buf[i]), False );
00171 
00172                 if( xcf_im->layers )
00173                         read_xcf_layers( xcf_im, fp, xcf_im->layers );
00174                 if( xcf_im->channels )
00175                         read_xcf_channels( xcf_im, fp, xcf_im->channels );
00176         }
00177         return xcf_im;
00178 }
00179 
00180 /*******************************************************************************/
00181 /* printing functions :                                                                                                    */
00182 void
00183 print_xcf_properties( char* prompt, XcfProperty *prop )
00184 {
00185         register int i = 0 ;
00186         while( prop )
00187         {
00188                 fprintf( stderr, "%s.properties[%d] = %p\n", prompt, i, prop );
00189                 fprintf( stderr, "%s.properties[%d].id = %ld\n", prompt, i, (long)prop->id );
00190                 fprintf( stderr, "%s.properties[%d].size = %ld\n", prompt, i, (long)prop->len );
00191                 if( prop->len > 0 )
00192                 {
00193                         register unsigned int k ;
00194                         fprintf( stderr, "%s.properties[%d].data = ", prompt, i );
00195                         for( k = 0 ; k < prop->len ; k++ )
00196                                 fprintf( stderr, "%2.2X ", prop->data[k] );
00197                         fprintf( stderr, "\n" );
00198                 }
00199                 prop = prop->next ;
00200                 ++i ;
00201         }
00202 }
00203 
00204 void
00205 print_xcf_hierarchy( char* prompt, XcfHierarchy *h )
00206 {
00207         if( h )
00208         {
00209                 XcfLevel *level = h->levels ;
00210                 int i = 0 ;
00211 
00212                 fprintf( stderr, "%s.hierarchy.width = %ld\n", prompt, (long)h->width );
00213                 fprintf( stderr, "%s.hierarchy.height = %ld\n", prompt,(long) h->height );
00214                 fprintf( stderr, "%s.hierarchy.bpp = %ld\n", prompt, (long)h->bpp );
00215                 while( level )
00216                 {
00217                         XcfTile *tile = level->tiles ;
00218                         int k = 0 ;
00219                         fprintf( stderr, "%s.hierarchy.level[%d].offset = %ld\n", prompt, i, (long)level->offset );
00220                         fprintf( stderr, "%s.hierarchy.level[%d].width = %ld\n", prompt, i, (long)level->width );
00221                         fprintf( stderr, "%s.hierarchy.level[%d].height = %ld\n", prompt, i, (long)level->height );
00222                         while ( tile )
00223                         {
00224                                 fprintf( stderr, "%s.hierarchy.level[%d].tile[%d].offset = %ld\n", prompt, i, k, (long)tile->offset );
00225                                 fprintf( stderr, "%s.hierarchy.level[%d].tile[%d].estimated_size = %ld\n", prompt, i, k, (long)tile->estimated_size );
00226                                 tile = tile->next ;
00227                                 ++k ;
00228                         }
00229                         level = level->next ;
00230                         ++i ;
00231                 }
00232         }
00233 }
00234 
00235 void
00236 print_xcf_channels( char* prompt, XcfChannel *head, Bool mask )
00237 {
00238         register int i = 0 ;
00239         char p[256] ;
00240         while( head )
00241         {
00242                 if( mask )
00243                         sprintf( p, "%s.mask", prompt );
00244                 else
00245                         sprintf( p, "%s.channel[%d]", prompt, i );
00246 
00247                 if( head->offset > 0 )
00248                         fprintf( stderr, "%s.offset = %ld\n", p, (long)head->offset );
00249                 fprintf( stderr, "%s.width = %ld\n" , p,(long) head->width );
00250                 fprintf( stderr, "%s.height = %ld\n", p, (long)head->height );
00251                 print_xcf_properties( p, head->properties );
00252                 fprintf( stderr, "%s.opacity = %ld\n", p, (long)head->opacity );
00253                 fprintf( stderr, "%s.visible = %d\n" , p, head->visible );
00254                 fprintf( stderr, "%s.color = #%lX\n" , p, (long)head->color );
00255                 fprintf( stderr, "%s.hierarchy_offset = %ld\n", p, (long)head->hierarchy_offset );
00256                 print_xcf_hierarchy( p, head->hierarchy );
00257 
00258                 head = head->next ;
00259                 ++i ;
00260         }
00261 }
00262 
00263 void
00264 print_xcf_layers( char* prompt, XcfLayer *head )
00265 {
00266         register int i = 0 ;
00267         char p[256] ;
00268         while( head )
00269         {
00270                 fprintf( stderr, "%s.layer[%d] = %p\n", prompt, i, head );
00271                 fprintf( stderr, "%s.layer[%d].offset = %ld\n", prompt, i, (long)head->offset );
00272                 fprintf( stderr, "%s.layer[%d].width = %ld\n", prompt, i, (long)head->width );
00273                 fprintf( stderr, "%s.layer[%d].height = %ld\n", prompt, i, (long)head->height );
00274                 fprintf( stderr, "%s.layer[%d].type = %ld\n", prompt, i, (long)head->type );
00275                 sprintf( p, "%s.layer[%d]", prompt, i );
00276                 print_xcf_properties( p, head->properties );
00277                 fprintf( stderr, "%s.layer[%d].opacity = %ld\n", prompt, i, (long)head->opacity );
00278                 fprintf( stderr, "%s.layer[%d].visible = %d\n", prompt, i, head->visible );
00279                 fprintf( stderr, "%s.layer[%d].preserve_transparency = %d\n", prompt, i,  head->preserve_transparency );
00280                 fprintf( stderr, "%s.layer[%d].mode = %ld\n"    , prompt, i, (long)head->mode                              );
00281                 fprintf( stderr, "%s.layer[%d].offset_x = %ld\n", prompt, i, (long)head->offset_x                          );
00282                 fprintf( stderr, "%s.layer[%d].offset_y = %ld\n", prompt, i, (long)head->offset_y                          );
00283 
00284                 fprintf( stderr, "%s.layer[%d].hierarchy_offset = %ld\n", prompt, i, (long)head->hierarchy_offset );
00285                 print_xcf_hierarchy( p, head->hierarchy );
00286                 fprintf( stderr, "%s.layer[%d].mask_offset = %ld\n", prompt, i, (long)head->mask_offset );
00287                 print_xcf_channels( p, head->mask, True );
00288 
00289                 head = head->next ;
00290                 ++i ;
00291         }
00292 }
00293 
00294 void
00295 print_xcf_image( XcfImage *xcf_im )
00296 {
00297         if( xcf_im )
00298         {
00299                 fprintf( stderr, "XcfImage.version = %d\n", xcf_im->version );
00300                 fprintf( stderr, "XcfImage.width = %ld\nXcfImage.height = %ld\nXcfImage.type = %ld\n",
00301                                                   (long)xcf_im->width, (long)xcf_im->height, (long)xcf_im->type );
00302                 fprintf( stderr, "XcfImage.num_cols = %ld\n", (long)xcf_im->num_cols );
00303                 fprintf( stderr, "XcfImage.compression = %d\n", xcf_im->compression );
00304                 print_xcf_properties( "XcfImage", xcf_im->properties );
00305                 print_xcf_layers( "XcfImage", xcf_im->layers );
00306                 print_xcf_channels( "XcfImage", xcf_im->channels, False );
00307         }
00308 }
00309 
00310 /*******************************************************************************/
00311 /* deallocation functions :                                                                                                */
00312 
00313 void
00314 free_xcf_properties( XcfProperty *head )
00315 {
00316         while( head )
00317         {
00318                 XcfProperty *next = head->next ;
00319                 if( head->len > 0  && head->data && head->data != (CARD8*)&(head->buffer[0]))
00320                         free( head->data );
00321                 free( head );
00322                 head = next ;
00323         }
00324 }
00325 
00326 void
00327 free_xcf_hierarchy( XcfHierarchy *hierarchy )
00328 {
00329         if( hierarchy )
00330         {
00331                 register XcfLevel *level = hierarchy->levels;
00332                 while( level )
00333                 {
00334                         XcfLevel *next = level->next ;
00335                         while( level->tiles )
00336                         {
00337                                 XcfTile *next = level->tiles->next ;
00338                                 if( level->tiles->data )
00339                                         free( level->tiles->data );
00340                                 free( level->tiles );
00341                                 level->tiles = next ;
00342                         }
00343                         free( level );
00344                         level = next ;
00345                 }
00346                 if( hierarchy->image )
00347             destroy_asimage( &hierarchy->image );
00348                 free( hierarchy );
00349         }
00350 }
00351 
00352 void
00353 free_xcf_channels( XcfChannel *head )
00354 {
00355         while( head )
00356         {
00357                 XcfChannel *next = head->next ;
00358                 if( head->properties )
00359                         free_xcf_properties( head->properties );
00360                 if( head->hierarchy )
00361                         free_xcf_hierarchy( head->hierarchy );
00362                 free( head );
00363                 head = next ;
00364         }
00365 }
00366 
00367 void
00368 free_xcf_layers( XcfLayer *head )
00369 {
00370         while( head )
00371         {
00372                 XcfLayer *next = head->next ;
00373                 if( head->properties )
00374                         free_xcf_properties( head->properties );
00375                 if( head->hierarchy )
00376                         free_xcf_hierarchy( head->hierarchy );
00377                 free_xcf_channels( head->mask );
00378                 free( head );
00379                 head = next ;
00380         }
00381 }
00382 
00383 void
00384 free_xcf_image( XcfImage *xcf_im )
00385 {
00386         if( xcf_im )
00387         {
00388                 int i ;
00389 
00390                 if( xcf_im->properties )
00391                         free_xcf_properties( xcf_im->properties );
00392                 if( xcf_im->colormap )
00393                         free( xcf_im->colormap );
00394                 if( xcf_im->layers )
00395                         free_xcf_layers( xcf_im->layers );
00396                 if( xcf_im->channels )
00397                         free_xcf_channels( xcf_im->channels );
00398 
00399                 for( i = 0 ; i < XCF_TILE_HEIGHT ; i++ )
00400                         free_scanline( &(xcf_im->scanline_buf[i]), True );
00401         }
00402 }
00403 
00404 
00405 /*******************************************************************************/
00406 /* detail loading functions :                                                                                              */
00407 
00408 static XcfProperty *
00409 read_xcf_props( FILE *fp )
00410 {
00411         XcfProperty *head = NULL;
00412         XcfProperty **tail = &head;
00413         CARD32 prop_vals[2] ;
00414 
00415         do
00416         {
00417                 if( xcf_read32( fp, &(prop_vals[0]), 2 ) < 2 )
00418                         break;
00419                 if( prop_vals[0] != 0 )
00420                 {
00421                         *tail = safecalloc( 1, sizeof(XcfProperty));
00422                         (*tail)->id  = prop_vals[0] ;
00423                         (*tail)->len = prop_vals[1] ;
00424                         if( (*tail)->len > 0 )
00425                         {
00426                                 if( (*tail)->len <= 8 )
00427                                         (*tail)->data = (CARD8*)&((*tail)->buffer[0]) ;
00428                                 else
00429                                         (*tail)->data = safemalloc( (*tail)->len );
00430                                 xcf_read8( fp, (*tail)->data, (*tail)->len );
00431                         }
00432                         tail = &((*tail)->next);
00433                 }
00434         }while( prop_vals[0] != 0 );
00435         return head;
00436 }
00437 
00438 static XcfListElem *
00439 read_xcf_list_offsets( FILE *fp, size_t elem_size )
00440 {
00441         XcfListElem *head = NULL ;
00442         XcfListElem **tail = &head ;
00443         CARD32 offset ;
00444 
00445         do
00446         {
00447                 if( xcf_read32( fp, &offset, 1 ) < 1 )
00448                         break;
00449                 if( offset != 0 )
00450                 {
00451                         *tail = safecalloc( 1, elem_size);
00452                         (*tail)->any.offset  = offset ;
00453                         tail = (XcfListElem**)&((*tail)->any.next);
00454                 }
00455         }while( offset != 0 );
00456         return head;
00457 }
00458 
00459 static void
00460 read_xcf_layers( XcfImage *xcf_im, FILE *fp, XcfLayer *head )
00461 {
00462         XcfProperty *prop ;
00463         while( head )
00464         {
00465                 fseek( fp, head->offset, SEEK_SET );
00466                 if( xcf_read32( fp, &(head->width), 3 ) < 3 )
00467                 {
00468                         head->width = 0 ;
00469                         head->height = 0 ;
00470                         head->type = 0 ;
00471                         continue;                          /* not enough data */
00472                 }
00473                 xcf_skip_string(fp);
00474                 head->properties = read_xcf_props( fp );
00475                 for( prop = head->properties ; prop != NULL ; prop = prop->next )
00476                 {
00477                         CARD32 *pd = (CARD32*)(prop->data) ;
00478                         if( prop->id ==  XCF_PROP_FLOATING_SELECTION )
00479                         {
00480                                 xcf_im->floating_selection = head;
00481                         }else if( prop->id ==  XCF_PROP_OPACITY && pd)
00482                         {
00483                                 head->opacity = as_ntohl(*pd);
00484                         }else if( prop->id ==  XCF_PROP_VISIBLE && pd)
00485                         {
00486                                 head->visible = ( *pd !=0);
00487                         }else if( prop->id ==  XCF_PROP_PRESERVE_TRANSPARENCY && pd)
00488                         {
00489                                 head->preserve_transparency = (*pd!=0);
00490                         }else if( prop->id == XCF_PROP_MODE && pd)
00491                         {
00492                                 head->mode = as_ntohl(*pd);
00493                         }else if( prop->id == XCF_PROP_OFFSETS && pd)
00494                         {
00495                                 head->offset_x = as_ntohl(pd[0]);
00496                                 head->offset_y = as_ntohl(pd[1]);
00497                         }
00498                 }
00499 
00500                 if( xcf_im->floating_selection != head && head->visible )
00501                 { /* we absolutely do not want to load floating selection or invisible layers :*/
00502                         if( xcf_read32( fp, &(head->hierarchy_offset), 2 ) < 2 )
00503                         {
00504                                 head->hierarchy_offset = 0 ;
00505                                 head->mask_offset = 0 ;
00506                         }
00507                         if( head->hierarchy_offset > 0 )
00508                         {
00509                                 fseek( fp, head->hierarchy_offset, SEEK_SET );
00510                                 head->hierarchy = read_xcf_hierarchy( xcf_im, fp, (CARD8)head->opacity, 0xFFFFFFFF );
00511                         }
00512                         if( head->mask_offset > 0 )
00513                         {
00514                                 head->mask = safecalloc( 1, sizeof(XcfChannel) );
00515                                 head->mask->offset = head->mask_offset;
00516                                 read_xcf_channels( xcf_im, fp, head->mask );
00517                         }
00518                 }
00519 
00520                 head = head->next ;
00521         }
00522 }
00523 
00524 static void
00525 read_xcf_channels( XcfImage *xcf_im, FILE *fp, XcfChannel *head )
00526 {
00527         XcfProperty *prop ;
00528         while( head )
00529         {
00530                 fseek( fp, head->offset, SEEK_SET );
00531                 if( xcf_read32( fp, &(head->width), 2 ) < 2 )
00532                 {
00533                         head->width = 0 ;
00534                         head->height = 0 ;
00535                         continue;                          /* not enough data */
00536                 }
00537                 xcf_skip_string(fp);
00538                 head->properties = read_xcf_props( fp );
00539                 for( prop = head->properties ; prop != NULL ; prop = prop->next )
00540                 {
00541                         CARD32 *pd = (CARD32*)(prop->data) ;
00542                         if( prop->id ==  XCF_PROP_OPACITY )
00543                         {
00544                                 head->opacity = as_ntohl(*pd);
00545                         }else if( prop->id ==  XCF_PROP_VISIBLE )
00546                         {
00547                                 head->visible = ( *pd !=0);
00548                         }else if( prop->id ==  XCF_PROP_COLOR )
00549                         {
00550                                 head->color = MAKE_ARGB32(0xFF,prop->data[0],prop->data[1],prop->data[2]);
00551                         }
00552                 }
00553 
00554                 if( head->visible )
00555                 {       /* onli visible channels we need : */
00556                         if( xcf_read32( fp, &(head->hierarchy_offset), 1 ) < 1 )
00557                                 head->hierarchy_offset = 0 ;
00558 
00559                         if( head->hierarchy_offset > 0 )
00560                         {
00561                                 fseek( fp, head->hierarchy_offset, SEEK_SET );
00562                                 head->hierarchy = read_xcf_hierarchy( xcf_im, fp, (CARD8)head->opacity, head->color );
00563                         }
00564                 }
00565                 head = head->next ;
00566         }
00567 }
00568 
00569 typedef void (*decode_xcf_tile_func)( FILE *fp, XcfTile *tile, int bpp,
00570                                                                           ASScanline *buf, CARD8* tile_buf, int offset_x, int offset_y, int width, int height);
00571 
00572 
00573 void decode_xcf_tile( FILE *fp, XcfTile *tile, int bpp,
00574                                          ASScanline *buf, CARD8* tile_buf, int offset_x, int offset_y, int width, int height);
00575 void decode_xcf_tile_rle( FILE *fp, XcfTile *tile, int bpp,
00576                                          ASScanline *buf, CARD8* tile_buf, int offset_x, int offset_y, int width, int height);
00577 Bool fix_xcf_image_line( ASScanline *buf, int bpp, unsigned int width, CARD8 *cmap,
00578                                                  CARD8 opacity, ARGB32 color );
00579 
00580 
00581 static XcfHierarchy*
00582 read_xcf_hierarchy( XcfImage *xcf_im, FILE *fp, CARD8 opacity, ARGB32 colormask )
00583 {
00584         XcfHierarchy *h = NULL ;
00585         CARD32 h_props[3] ;
00586 
00587         if( xcf_read32( fp, &(h_props[0]), 3 ) < 3 )
00588                 return NULL;
00589         h = safecalloc(1, sizeof(XcfHierarchy));
00590 
00591         h->width  = h_props[0] ;
00592         h->height = h_props[1] ;
00593         h->bpp    = h_props[2] ;
00594 
00595         h->levels = (XcfLevel*)read_xcf_list_offsets( fp, sizeof(XcfLevel));
00596         if( h->levels )
00597         {
00598                 read_xcf_levels( xcf_im, fp, h->levels );
00599 
00600                 /* now we want to try and merge all the tiles into single ASImage */
00601                 if( h->levels->width == h->width && h->levels->height == h->height )
00602                 { /* only first level is interesting for us : */
00603                   /* do not know why, but GIMP (at least up to v1.3) has been writing only
00604                    * one level, and faking the rest - future extensibility ? */
00605                         int height_left = h->height ;
00606                         ASScanline      *buf = &(xcf_im->scanline_buf[0]) ;
00607                         XcfTile                 *tile = h->levels->tiles ;
00608                         decode_xcf_tile_func decode_func = decode_xcf_tile ;
00609                         CARD8                   *tile_buf = &(xcf_im->tile_buf[0]);
00610                         int i;
00611 
00612                         if( xcf_im->compression == XCF_COMPRESS_RLE )
00613                                 decode_func = decode_xcf_tile_rle ;
00614                         else if( xcf_im->compression != XCF_COMPRESS_NONE )
00615                         {
00616                                 show_error( "XCF image contains information compressed with usupported method." );
00617                                 return h;
00618                         }
00619 
00620                         if (XCF_TILE_WIDTH < h->width)
00621                                 tile_buf = safemalloc (h->width*XCF_TILE_HEIGHT*6);
00622                                 
00623                         if (xcf_im->width < h->width)
00624                                 for( i = 0 ; i < XCF_TILE_HEIGHT ; i++ )
00625                                 {
00626                                         free_scanline (&(xcf_im->scanline_buf[i]), True); 
00627                                         prepare_scanline (h->width,0,&(xcf_im->scanline_buf[i]), False );
00628                                 }
00629 
00630                         h->image = create_asimage(  h->width, h->height, 0/* no compression */ );
00631                         while( height_left > 0 && tile )
00632                         {
00633                                 int width_left = h->width ;
00634                                 int max_i, y ;
00635                                 /* first - lets collect our data : */
00636                                 while( width_left > 0 && tile )
00637                                 {
00638                                         fseek( fp, tile->offset, SEEK_SET );
00639                                         decode_func(fp, tile, h->bpp, buf, tile_buf,
00640                                                             h->width-width_left, h->height-height_left,  /* really don't need this one */
00641                                                                 MIN(width_left,XCF_TILE_WIDTH), MIN(height_left,XCF_TILE_HEIGHT));
00642 
00643                                         width_left -= XCF_TILE_WIDTH ;
00644                                         tile = tile->next ;
00645                                 }
00646 
00647                                 /* now lets encode it into ASImage : */
00648                                 max_i = MIN(height_left,XCF_TILE_HEIGHT);
00649                                 y = h->height - height_left ;
00650                                 for( i = 0 ; i < max_i ; i++ )
00651                                 {
00652                                         Bool do_alpha = fix_xcf_image_line( &(buf[i]), h->bpp, h->width, xcf_im->colormap, opacity, colormask );
00653                                         if( h->bpp > 1 || xcf_im->colormap != NULL )
00654                                         {
00655                                                 asimage_add_line (h->image, IC_RED,   buf[i].red  , y+i);
00656                                                 asimage_add_line (h->image, IC_GREEN, buf[i].green, y+i);
00657                                                 asimage_add_line (h->image, IC_BLUE,  buf[i].blue , y+i);
00658                                         }
00659                                         if( do_alpha ) /* we don't want to store alpha component - if its all FF */
00660                                                 asimage_add_line (h->image, IC_ALPHA, buf[i].alpha, y+i);
00661                                 }
00662                                 /* continue on to the next row : */
00663                                 height_left -= XCF_TILE_HEIGHT ;
00664                         }
00665                         if (tile_buf != &(xcf_im->tile_buf[0]))
00666                                 free (tile_buf);
00667                 }
00668         }
00669         return h;
00670 }
00671 
00672 static void
00673 read_xcf_levels( XcfImage *xcf_im, FILE *fp, XcfLevel *head )
00674 {
00675         while( head )
00676         {
00677                 fseek( fp, head->offset, SEEK_SET );
00678                 if( xcf_read32( fp, &(head->width), 2 ) < 2 )
00679                 {
00680                         head->width = 0 ;
00681                         head->height = 0 ;
00682                         continue;                          /* not enough data */
00683                 }
00684 
00685                 head->tiles = (XcfTile*)read_xcf_list_offsets( fp, sizeof(XcfTile));
00686                 if( head->tiles )
00687                 {
00688                         if( xcf_im->compression == XCF_COMPRESS_NONE )
00689                                 read_xcf_tiles( xcf_im, fp, head->tiles );
00690                         else if( xcf_im->compression == XCF_COMPRESS_RLE )
00691                                 read_xcf_tiles_rle( xcf_im, fp, head->tiles );
00692                 }
00693                 head = head->next ;
00694         }
00695 }
00696 
00697 static void
00698 read_xcf_tiles( XcfImage *xcf_im, FILE *fp, XcfTile *head )
00699 {
00700         while( head )
00701         {
00702                 head->estimated_size = XCF_TILE_WIDTH*XCF_TILE_HEIGHT*4 ;
00703                 head = head->next ;
00704         }
00705 }
00706 
00707 
00708 static void
00709 read_xcf_tiles_rle( XcfImage *xcf_im, FILE *fp, XcfTile *head )
00710 {
00711         while( head )
00712         {
00713                 if( head->next )
00714                         head->estimated_size = head->next->offset - head->offset ;
00715                 else
00716                         head->estimated_size = (XCF_TILE_WIDTH*XCF_TILE_HEIGHT)*6 ;
00717                 head = head->next ;
00718         }
00719 }
00720 
00721 /* now the fun part of actually decoding ARGB values : */
00722 
00723 static inline void
00724 store_colors( CARD8 *data, ASScanline *curr_buf, int bpp, int comp, int offset_x, int width )
00725 {
00726         register int i ;
00727         CARD32   *out = NULL;
00728         if( comp+1 < bpp || bpp == 3 )
00729         {
00730                 switch( comp )
00731                 {
00732                         case 0 : out = &(curr_buf->red[offset_x]); break ;
00733                         case 1 : out = &(curr_buf->green[offset_x]); break ;
00734                         case 2 : out = &(curr_buf->blue[offset_x]); break ;
00735                 }
00736         }else
00737                 out = &(curr_buf->alpha[offset_x]);
00738 
00739         if( out ) 
00740                 for( i = 0 ; i < width ; i++ )
00741                         out[i] = data[i] ;
00742 }
00743 
00744 void
00745 decode_xcf_tile( FILE *fp, XcfTile *tile, int bpp,
00746                                  ASScanline *buf, CARD8* tile_buf, int offset_x, int offset_y, int width, int height)
00747 {
00748         int bytes_in, available = width*height ;
00749         int y = 0;
00750         int comp = 0 ;
00751 
00752         bytes_in = xcf_read8( fp, tile_buf, available*6 );
00753         while( comp < bpp && bytes_in >= 2 )
00754         {
00755                 while ( y < height )
00756                 {
00757                         store_colors( tile_buf, &(buf[y]), bpp, comp, offset_x, MIN(width,bytes_in));
00758                         tile_buf += width ;
00759                         bytes_in -= width ;
00760                         ++y ;
00761                 }
00762                 ++comp;
00763                 y = 0 ;
00764         }
00765 }
00766 
00767 
00768 void
00769 decode_xcf_tile_rle( FILE *fp, XcfTile *tile, int bpp,
00770                                          ASScanline *buf, CARD8* tile_buf, int offset_x, int offset_y, int width, int height)
00771 {
00772         int bytes_in, available = width*height ;
00773         int x = 0, y = 0;
00774         CARD8   tmp[XCF_TILE_WIDTH] ;
00775         int comp = 0 ;
00776 
00777         bytes_in = xcf_read8( fp, tile_buf, available*6 );
00778         while( comp < bpp && bytes_in >= 2 )
00779         {
00780                 while ( y < height )
00781                 {
00782                         int len = *tile_buf ;
00783                         register int i ;
00784                         ++tile_buf;
00785                         --bytes_in;
00786                         if( len >= 128 )
00787                         {                                                                          /* direct data  */
00788                                 if( len == 128 )
00789                                 {
00790                                         len = (((int)tile_buf[0])<<8)+tile_buf[1] ;
00791                                         tile_buf += 2 ; bytes_in -= 2 ;
00792                                 }else
00793                                         len = 255 - (len-1);
00794                                 if( len > bytes_in )
00795                                         break;
00796                                 for( i = 0 ; i < len ; ++i )
00797                                 {
00798                                         tmp[x] = tile_buf[i] ;
00799                                         if( ++x >= width )
00800                                         {
00801                                                 store_colors( &(tmp[0]), &(buf[y]), bpp, comp, offset_x, width );
00802                                                 x = 0 ;
00803                                                 ++y ;
00804                                                 if( y >= height )
00805                                                         i = len ;
00806                                         }
00807                                 }
00808                                 tile_buf += len ;
00809                                 bytes_in -= len ;
00810                         }else
00811                         {                                      /* repeating data */
00812                                 CARD8 v ;
00813                                 ++len ;
00814                                 if( len == 128 )
00815                                 {
00816                                         len = (((int)tile_buf[0])<<8)+tile_buf[1] ;
00817                                         tile_buf += 2 ; bytes_in -= 2 ;
00818                                 }
00819                                 if( len >= bytes_in )
00820                                         len = bytes_in-1 ;
00821                                 v = tile_buf[0] ;
00822                                 for( i = 0 ; i < len ; ++i)
00823                                 {
00824                                         tmp[x] = v ;
00825                                         if( ++x >= width )
00826                                         {
00827                                                 store_colors( &(tmp[0]), &(buf[y]), bpp, comp, offset_x, width );
00828                                                 x = 0 ;
00829                                                 ++y ;
00830                                                 if( y >= height )
00831                                                         i = len ;
00832                                         }
00833                                 }
00834                                 ++tile_buf;
00835                                 --bytes_in;
00836                         }
00837                 }
00838                 ++comp;
00839                 x = 0 ;
00840                 y = 0 ;
00841         }
00842 }
00843 
00844 Bool
00845 fix_xcf_image_line( ASScanline *buf, int bpp, unsigned int width, CARD8 *cmap,
00846                                         CARD8 opacity, ARGB32 color )
00847 {
00848         register unsigned int i ;
00849         Bool do_alpha = False ;
00850         if( bpp == 1 )
00851         {
00852                 if( cmap )
00853                 {
00854                         for( i = 0 ; i < width ; i++ )
00855                         {
00856                                 int cmap_idx = ((int)(buf->alpha[i]))*3 ;
00857                                 buf->red[i]   = cmap[cmap_idx];
00858                                 buf->blue[i]  = cmap[cmap_idx+1];
00859                                 buf->green[i] = cmap[cmap_idx+2];
00860                                 buf->alpha[i] = opacity;
00861                         }
00862                 }if ( (color&0x00FFFFFF) == 0x00FFFFFF )
00863                         for( i = 0 ; i < width ; i++ )
00864                         {
00865                                 buf->red[i]   = buf->alpha[i];
00866                                 buf->blue[i]  = buf->alpha[i];
00867                                 buf->green[i] = buf->alpha[i];
00868                                 buf->alpha[i] = opacity;
00869                         }
00870                 else
00871                         for( i = 0 ; i < width ; i++ )
00872                                 buf->alpha[i] = ((int)(buf->alpha[i])*opacity)>>8;
00873         }if( bpp == 2 )
00874         {
00875                 for( i = 0 ; i < width ; i++ )
00876                 {
00877                         if( cmap )
00878                         {
00879                                 int cmap_idx = ((int)(buf->red[i]))*3 ;
00880                                 buf->red[i]   = cmap[cmap_idx];
00881                                 buf->blue[i]  = cmap[cmap_idx+1];
00882                                 buf->green[i] = cmap[cmap_idx+2];
00883                         }else
00884                                 buf->blue[i] = buf->green[i] = buf->red[i] ;
00885 
00886                         buf->alpha[i] = ((int)(buf->alpha[i])*opacity)>>8;
00887                         if( (buf->alpha[i]&0x00FF) != 0x00FF )
00888                                 do_alpha = True ;
00889                 }
00890         }else
00891         {
00892                 for( i = 0 ; i < width ; i++ )
00893                 {
00894                         buf->alpha[i] = ((int)(buf->alpha[i])*opacity)>>8;
00895                         if( (buf->alpha[i]&0x00FF) != 0x00FF )
00896                                 do_alpha = True ;
00897                 }
00898         }
00899         return do_alpha;
00900 }

Generated on Tue Jul 5 14:13:33 2011 for ROOT_528-00b_version by  doxygen 1.5.1