IMG_lbm.c
author Sylvain Becker <sylvain.becker@gmail.com>
Thu, 20 Jun 2019 10:20:04 +0200
changeset 672 6dd3b4df8ec1
parent 648 b9f71b5a12ba
permissions -rw-r--r--
Android: fix compilation libpng-1.6.37 (missing arm/palette_neon_intrinsics.c)

undefined reference to `png_riffle_palette_neon'
undefined reference to `png_do_expand_palette_rgba8_neon'
undefined reference to `png_do_expand_palette_rgb8_neon'
     1 /*
     2   SDL_image:  An example image loading library for use with SDL
     3   Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 
    22 /* This is a ILBM image file loading framework
    23    Load IFF pictures, PBM & ILBM packing methods, with or without stencil
    24    Written by Daniel Morais ( Daniel AT Morais DOT com ) in September 2001.
    25    24 bits ILBM files support added by Marc Le Douarain (http://www.multimania.com/mavati)
    26    in December 2002.
    27    EHB and HAM (specific Amiga graphic chip modes) support added by Marc Le Douarain
    28    (http://www.multimania.com/mavati) in December 2003.
    29    Stencil and colorkey fixes by David Raulo (david.raulo AT free DOT fr) in February 2004.
    30    Buffer overflow fix in RLE decompression by David Raulo in January 2008.
    31 */
    32 
    33 #include "SDL_endian.h"
    34 #include "SDL_image.h"
    35 
    36 #ifdef LOAD_LBM
    37 
    38 
    39 #define MAXCOLORS 256
    40 
    41 /* Structure for an IFF picture ( BMHD = Bitmap Header ) */
    42 
    43 typedef struct
    44 {
    45     Uint16 w, h;        /* width & height of the bitmap in pixels */
    46     Sint16 x, y;        /* screen coordinates of the bitmap */
    47     Uint8 planes;       /* number of planes of the bitmap */
    48     Uint8 mask;         /* mask type ( 0 => no mask ) */
    49     Uint8 tcomp;        /* compression type */
    50     Uint8 pad1;         /* dummy value, for padding */
    51     Uint16 tcolor;      /* transparent color */
    52     Uint8 xAspect,      /* pixel aspect ratio */
    53           yAspect;
    54     Sint16  Lpage;      /* width of the screen in pixels */
    55     Sint16  Hpage;      /* height of the screen in pixels */
    56 } BMHD;
    57 
    58 int IMG_isLBM( SDL_RWops *src )
    59 {
    60     Sint64 start;
    61     int   is_LBM;
    62     Uint8 magic[4+4+4];
    63 
    64     if ( !src )
    65         return 0;
    66     start = SDL_RWtell(src);
    67     is_LBM = 0;
    68     if ( SDL_RWread( src, magic, sizeof(magic), 1 ) )
    69     {
    70         if ( !SDL_memcmp( magic, "FORM", 4 ) &&
    71             ( !SDL_memcmp( magic + 8, "PBM ", 4 ) ||
    72               !SDL_memcmp( magic + 8, "ILBM", 4 ) ) )
    73         {
    74             is_LBM = 1;
    75         }
    76     }
    77     SDL_RWseek(src, start, RW_SEEK_SET);
    78     return( is_LBM );
    79 }
    80 
    81 SDL_Surface *IMG_LoadLBM_RW( SDL_RWops *src )
    82 {
    83     Sint64 start;
    84     SDL_Surface *Image;
    85     Uint8       id[4], pbm, colormap[MAXCOLORS*3], *MiniBuf, *ptr, count, color, msk;
    86     Uint32      size, bytesloaded, nbcolors;
    87     Uint32      i, j, bytesperline, nbplanes, stencil, plane, h;
    88     Uint32      remainingbytes;
    89     Uint32      width;
    90     BMHD          bmhd;
    91     char        *error;
    92     Uint8       flagHAM,flagEHB;
    93 
    94     Image   = NULL;
    95     error   = NULL;
    96     MiniBuf = NULL;
    97 
    98     if ( !src ) {
    99         /* The error message has been set in SDL_RWFromFile */
   100         return NULL;
   101     }
   102     start = SDL_RWtell(src);
   103 
   104     if ( !SDL_RWread( src, id, 4, 1 ) )
   105     {
   106         error="error reading IFF chunk";
   107         goto done;
   108     }
   109 
   110     /* Should be the size of the file minus 4+4 ( 'FORM'+size ) */
   111     if ( !SDL_RWread( src, &size, 4, 1 ) )
   112     {
   113         error="error reading IFF chunk size";
   114         goto done;
   115     }
   116 
   117     /* As size is not used here, no need to swap it */
   118 
   119     if ( SDL_memcmp( id, "FORM", 4 ) != 0 )
   120     {
   121         error="not a IFF file";
   122         goto done;
   123     }
   124 
   125     if ( !SDL_RWread( src, id, 4, 1 ) )
   126     {
   127         error="error reading IFF chunk";
   128         goto done;
   129     }
   130 
   131     pbm = 0;
   132 
   133     /* File format : PBM=Packed Bitmap, ILBM=Interleaved Bitmap */
   134     if ( !SDL_memcmp( id, "PBM ", 4 ) ) pbm = 1;
   135     else if ( SDL_memcmp( id, "ILBM", 4 ) )
   136     {
   137         error="not a IFF picture";
   138         goto done;
   139     }
   140 
   141     nbcolors = 0;
   142 
   143     SDL_memset( &bmhd, 0, sizeof( BMHD ) );
   144     flagHAM = 0;
   145     flagEHB = 0;
   146 
   147     while ( SDL_memcmp( id, "BODY", 4 ) != 0 )
   148     {
   149         if ( !SDL_RWread( src, id, 4, 1 ) )
   150         {
   151             error="error reading IFF chunk";
   152             goto done;
   153         }
   154 
   155         if ( !SDL_RWread( src, &size, 4, 1 ) )
   156         {
   157             error="error reading IFF chunk size";
   158             goto done;
   159         }
   160 
   161         bytesloaded = 0;
   162 
   163         size = SDL_SwapBE32( size );
   164 
   165         if ( !SDL_memcmp( id, "BMHD", 4 ) ) /* Bitmap header */
   166         {
   167             if ( !SDL_RWread( src, &bmhd, sizeof( BMHD ), 1 ) )
   168             {
   169                 error="error reading BMHD chunk";
   170                 goto done;
   171             }
   172 
   173             bytesloaded = sizeof( BMHD );
   174 
   175             bmhd.w      = SDL_SwapBE16( bmhd.w );
   176             bmhd.h      = SDL_SwapBE16( bmhd.h );
   177             bmhd.x      = SDL_SwapBE16( bmhd.x );
   178             bmhd.y      = SDL_SwapBE16( bmhd.y );
   179             bmhd.tcolor = SDL_SwapBE16( bmhd.tcolor );
   180             bmhd.Lpage  = SDL_SwapBE16( bmhd.Lpage );
   181             bmhd.Hpage  = SDL_SwapBE16( bmhd.Hpage );
   182         }
   183 
   184         if ( !SDL_memcmp( id, "CMAP", 4 ) ) /* palette ( Color Map ) */
   185         {
   186             if (size > sizeof (colormap)) {
   187                 error="colormap size is too large";
   188                 goto done;
   189             }
   190 
   191             if ( !SDL_RWread( src, &colormap, size, 1 ) )
   192             {
   193                 error="error reading CMAP chunk";
   194                 goto done;
   195             }
   196 
   197             bytesloaded = size;
   198             nbcolors = size / 3;
   199         }
   200 
   201         if ( !SDL_memcmp( id, "CAMG", 4 ) ) /* Amiga ViewMode  */
   202         {
   203             Uint32 viewmodes;
   204             if ( !SDL_RWread( src, &viewmodes, sizeof(viewmodes), 1 ) )
   205             {
   206                 error="error reading CAMG chunk";
   207                 goto done;
   208             }
   209 
   210             bytesloaded = size;
   211             viewmodes = SDL_SwapBE32( viewmodes );
   212             if ( viewmodes & 0x0800 )
   213                 flagHAM = 1;
   214             if ( viewmodes & 0x0080 )
   215                 flagEHB = 1;
   216         }
   217 
   218         if ( SDL_memcmp( id, "BODY", 4 ) )
   219         {
   220             if ( size & 1 ) ++size;     /* padding ! */
   221             size -= bytesloaded;
   222             /* skip the remaining bytes of this chunk */
   223             if ( size ) SDL_RWseek( src, size, RW_SEEK_CUR );
   224         }
   225     }
   226 
   227     /* compute some usefull values, based on the bitmap header */
   228 
   229     width = ( bmhd.w + 15 ) & 0xFFFFFFF0;  /* Width in pixels modulo 16 */
   230 
   231     bytesperline = ( ( bmhd.w + 15 ) / 16 ) * 2;
   232 
   233     nbplanes = bmhd.planes;
   234 
   235     if ( pbm )                         /* File format : 'Packed Bitmap' */
   236     {
   237         bytesperline *= 8;
   238         nbplanes = 1;
   239     }
   240 
   241     stencil = (bmhd.mask & 1);   /* There is a mask ( 'stencil' ) */
   242 
   243     /* Allocate memory for a temporary buffer ( used for
   244            decompression/deinterleaving ) */
   245 
   246     MiniBuf = (Uint8 *)SDL_malloc( bytesperline * (nbplanes + stencil) );
   247     if ( MiniBuf == NULL )
   248     {
   249         error="not enough memory for temporary buffer";
   250         goto done;
   251     }
   252 
   253     if ( ( Image = SDL_CreateRGBSurface( SDL_SWSURFACE, width, bmhd.h, (nbplanes==24 || flagHAM==1)?24:8, 0, 0, 0, 0 ) ) == NULL )
   254        goto done;
   255 
   256     if ( bmhd.mask & 2 )               /* There is a transparent color */
   257         SDL_SetColorKey( Image, SDL_TRUE, bmhd.tcolor );
   258 
   259     /* Update palette informations */
   260 
   261     /* There is no palette in 24 bits ILBM file */
   262     if ( nbcolors>0 && flagHAM==0 )
   263     {
   264         /* FIXME: Should this include the stencil? See comment below */
   265         int nbrcolorsfinal = 1 << (nbplanes + stencil);
   266         ptr = &colormap[0];
   267 
   268         for ( i=0; i<nbcolors; i++ )
   269         {
   270             Image->format->palette->colors[i].r = *ptr++;
   271             Image->format->palette->colors[i].g = *ptr++;
   272             Image->format->palette->colors[i].b = *ptr++;
   273         }
   274 
   275         /* Amiga EHB mode (Extra-Half-Bright) */
   276         /* 6 bitplanes mode with a 32 colors palette */
   277         /* The 32 last colors are the same but divided by 2 */
   278         /* Some Amiga pictures save 64 colors with 32 last wrong colors, */
   279         /* they shouldn't !, and here we overwrite these 32 bad colors. */
   280         if ( (nbcolors==32 || flagEHB ) && (1<<nbplanes)==64 )
   281         {
   282             nbcolors = 64;
   283             ptr = &colormap[0];
   284             for ( i=32; i<64; i++ )
   285             {
   286                 Image->format->palette->colors[i].r = (*ptr++)/2;
   287                 Image->format->palette->colors[i].g = (*ptr++)/2;
   288                 Image->format->palette->colors[i].b = (*ptr++)/2;
   289             }
   290         }
   291 
   292         /* If nbcolors < 2^nbplanes, repeat the colormap */
   293         /* This happens when pictures have a stencil mask */
   294         if ( nbrcolorsfinal > (1<<nbplanes) ) {
   295             nbrcolorsfinal = (1<<nbplanes);
   296         }
   297         for ( i=nbcolors; i < (Uint32)nbrcolorsfinal; i++ )
   298         {
   299             Image->format->palette->colors[i].r = Image->format->palette->colors[i%nbcolors].r;
   300             Image->format->palette->colors[i].g = Image->format->palette->colors[i%nbcolors].g;
   301             Image->format->palette->colors[i].b = Image->format->palette->colors[i%nbcolors].b;
   302         }
   303         if ( !pbm )
   304             Image->format->palette->ncolors = nbrcolorsfinal;
   305     }
   306 
   307     /* Get the bitmap */
   308 
   309     for ( h=0; h < bmhd.h; h++ )
   310     {
   311         /* uncompress the datas of each planes */
   312 
   313         for ( plane=0; plane < (nbplanes+stencil); plane++ )
   314         {
   315             ptr = MiniBuf + ( plane * bytesperline );
   316 
   317             remainingbytes = bytesperline;
   318 
   319             if ( bmhd.tcomp == 1 )      /* Datas are compressed */
   320             {
   321                 do
   322                 {
   323                     if ( !SDL_RWread( src, &count, 1, 1 ) )
   324                     {
   325                         error="error reading BODY chunk";
   326                         goto done;
   327                     }
   328 
   329                     if ( count & 0x80 )
   330                     {
   331                         count ^= 0xFF;
   332                         count += 2; /* now it */
   333 
   334                         if ( ( count > remainingbytes ) || !SDL_RWread( src, &color, 1, 1 ) )
   335                         {
   336                             error="error reading BODY chunk";
   337                             goto done;
   338                         }
   339                         SDL_memset( ptr, color, count );
   340                     }
   341                     else
   342                     {
   343                         ++count;
   344 
   345                         if ( ( count > remainingbytes ) || !SDL_RWread( src, ptr, count, 1 ) )
   346                         {
   347                            error="error reading BODY chunk";
   348                             goto done;
   349                         }
   350                     }
   351 
   352                     ptr += count;
   353                     remainingbytes -= count;
   354 
   355                 } while ( remainingbytes > 0 );
   356             }
   357             else
   358             {
   359                 if ( !SDL_RWread( src, ptr, bytesperline, 1 ) )
   360                 {
   361                     error="error reading BODY chunk";
   362                     goto done;
   363                 }
   364             }
   365         }
   366 
   367         /* One line has been read, store it ! */
   368 
   369         ptr = (Uint8 *)Image->pixels;
   370         if ( nbplanes==24 || flagHAM==1 )
   371             ptr += h * width * 3;
   372         else
   373             ptr += h * width;
   374 
   375         if ( pbm )                 /* File format : 'Packed Bitmap' */
   376         {
   377            SDL_memcpy( ptr, MiniBuf, width );
   378         }
   379         else        /* We have to un-interlace the bits ! */
   380         {
   381             if ( nbplanes!=24 && flagHAM==0 )
   382             {
   383                 size = ( width + 7 ) / 8;
   384 
   385                 for ( i=0; i < size; i++ )
   386                 {
   387                     SDL_memset( ptr, 0, 8 );
   388 
   389                     for ( plane=0; plane < (nbplanes + stencil); plane++ )
   390                     {
   391                         color = *( MiniBuf + i + ( plane * bytesperline ) );
   392                         msk = 0x80;
   393 
   394                         for ( j=0; j<8; j++ )
   395                         {
   396                             if ( ( plane + j ) <= 7 ) ptr[j] |= (Uint8)( color & msk ) >> ( 7 - plane - j );
   397                             else                        ptr[j] |= (Uint8)( color & msk ) << ( plane + j - 7 );
   398 
   399                             msk >>= 1;
   400                         }
   401                     }
   402                     ptr += 8;
   403                 }
   404             }
   405             else
   406             {
   407                 Uint32 finalcolor = 0;
   408                 size = ( width + 7 ) / 8;
   409                 /* 24 bitplanes ILBM : R0...R7,G0...G7,B0...B7 */
   410                 /* or HAM (6 bitplanes) or HAM8 (8 bitplanes) modes */
   411                 for ( i=0; i<width; i=i+8 )
   412                 {
   413                     Uint8 maskBit = 0x80;
   414                     for ( j=0; j<8; j++ )
   415                     {
   416                         Uint32 pixelcolor = 0;
   417                         Uint32 maskColor = 1;
   418                         Uint8 dataBody;
   419                         for ( plane=0; plane < nbplanes; plane++ )
   420                         {
   421                             dataBody = MiniBuf[ plane*size+i/8 ];
   422                             if ( dataBody&maskBit )
   423                                 pixelcolor = pixelcolor | maskColor;
   424                             maskColor = maskColor<<1;
   425                         }
   426                         /* HAM : 12 bits RGB image (4 bits per color component) */
   427                         /* HAM8 : 18 bits RGB image (6 bits per color component) */
   428                         if ( flagHAM )
   429                         {
   430                             switch( pixelcolor>>(nbplanes-2) )
   431                             {
   432                                 case 0: /* take direct color from palette */
   433                                     finalcolor = colormap[ pixelcolor*3 ] + (colormap[ pixelcolor*3+1 ]<<8) + (colormap[ pixelcolor*3+2 ]<<16);
   434                                     break;
   435                                 case 1: /* modify only blue component */
   436                                     finalcolor = finalcolor&0x00FFFF;
   437                                     finalcolor = finalcolor | (pixelcolor<<(16+(10-nbplanes)));
   438                                     break;
   439                                 case 2: /* modify only red component */
   440                                     finalcolor = finalcolor&0xFFFF00;
   441                                     finalcolor = finalcolor | pixelcolor<<(10-nbplanes);
   442                                     break;
   443                                 case 3: /* modify only green component */
   444                                     finalcolor = finalcolor&0xFF00FF;
   445                                     finalcolor = finalcolor | (pixelcolor<<(8+(10-nbplanes)));
   446                                     break;
   447                             }
   448                         }
   449                         else
   450                         {
   451                             finalcolor = pixelcolor;
   452                         }
   453 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   454                             *ptr++ = (Uint8)(finalcolor>>16);
   455                             *ptr++ = (Uint8)(finalcolor>>8);
   456                             *ptr++ = (Uint8)(finalcolor);
   457 #else
   458                             *ptr++ = (Uint8)(finalcolor);
   459                             *ptr++ = (Uint8)(finalcolor>>8);
   460                             *ptr++ = (Uint8)(finalcolor>>16);
   461 #endif
   462                         maskBit = maskBit>>1;
   463                     }
   464                 }
   465             }
   466         }
   467     }
   468 
   469 done:
   470 
   471     if ( MiniBuf ) SDL_free( MiniBuf );
   472 
   473     if ( error )
   474     {
   475         SDL_RWseek(src, start, RW_SEEK_SET);
   476         if ( Image ) {
   477             SDL_FreeSurface( Image );
   478             Image = NULL;
   479         }
   480         IMG_SetError( "%s", error );
   481     }
   482 
   483     return( Image );
   484 }
   485 
   486 #else /* LOAD_LBM */
   487 
   488 /* See if an image is contained in a data source */
   489 int IMG_isLBM(SDL_RWops *src)
   490 {
   491     return(0);
   492 }
   493 
   494 /* Load an IFF type image from an SDL datasource */
   495 SDL_Surface *IMG_LoadLBM_RW(SDL_RWops *src)
   496 {
   497     return(NULL);
   498 }
   499 
   500 #endif /* LOAD_LBM */