bmp.c

Go to the documentation of this file.
00001 /* This file contains code for unified image loading from many file formats */
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 #undef LOCAL_DEBUG
00022 #undef DO_CLOCKING
00023 #undef DEBUG_TRANSP_GIF
00024 
00025 #ifdef _WIN32
00026 # include "win32/config.h"
00027 # include <windows.h>
00028 # include "win32/afterbase.h"
00029 #else
00030 # include "config.h"
00031 # include <string.h>
00032 # include "afterbase.h"
00033 #endif
00034 
00035 #include "asimage.h"
00036 #include "imencdec.h"
00037 #include "bmp.h"
00038 
00039 
00040 void 
00041 dib_data_to_scanline( ASScanline *buf, 
00042                       BITMAPINFOHEADER *bmp_info, CARD8 *gamma_table, 
00043                                           CARD8 *data, CARD8 *cmap, int cmap_entry_size) 
00044 {       
00045         int x ; 
00046         switch( bmp_info->biBitCount )
00047         {
00048                 case 1 :
00049                         for( x = 0 ; x < bmp_info->biWidth ; x++ )
00050                         {
00051                                 int entry = (data[x>>3]&(1<<(x&0x07)))?cmap_entry_size:0 ;
00052                                 buf->red[x] = cmap[entry+2];
00053                                 buf->green[x] = cmap[entry+1];
00054                                 buf->blue[x] = cmap[entry];
00055                         }
00056                         break ;
00057                 case 4 :
00058                         for( x = 0 ; x < (int)bmp_info->biWidth ; x++ )
00059                         {
00060                                 int entry = data[x>>1];
00061                                 if(x&0x01)
00062                                         entry = ((entry>>4)&0x0F)*cmap_entry_size ;
00063                                 else
00064                                         entry = (entry&0x0F)*cmap_entry_size ;
00065                                 buf->red[x] = cmap[entry+2];
00066                                 buf->green[x] = cmap[entry+1];
00067                                 buf->blue[x] = cmap[entry];
00068                         }
00069                         break ;
00070                 case 8 :
00071                         for( x = 0 ; x < (int)bmp_info->biWidth ; x++ )
00072                         {
00073                                 int entry = data[x]*cmap_entry_size ;
00074                                 buf->red[x] = cmap[entry+2];
00075                                 buf->green[x] = cmap[entry+1];
00076                                 buf->blue[x] = cmap[entry];
00077                         }
00078                         break ;
00079                 case 16 :
00080                         for( x = 0 ; x < (int)bmp_info->biWidth ; ++x )
00081                         {
00082                                 CARD8 c1 = data[x] ;
00083                                 CARD8 c2 = data[++x];
00084                                 buf->blue[x] =    c1&0x1F;
00085                                 buf->green[x] = ((c1>>5)&0x07)|((c2<<3)&0x18);
00086                                 buf->red[x] =   ((c2>>2)&0x1F);
00087                         }
00088                         break ;
00089                 default:
00090                         raw2scanline( data, buf, gamma_table, buf->width, False, (bmp_info->biBitCount==32));
00091         }
00092 }
00093 
00094 BITMAPINFO *
00095 ASImage2DIB( ASVisual *asv, ASImage *im, 
00096                      int offset_x, int offset_y,
00097                          unsigned int to_width,
00098                          unsigned int to_height,
00099                          void **pBits, int mask )
00100 {
00101         BITMAPINFO *bmp_info = NULL;
00102         CARD8 *bits = NULL, *curr ;
00103         int line_size, pad ; 
00104         ASImageDecoder *imdec ;
00105         int y, max_y = to_height;       
00106         int tiling_step = 0 ;
00107         CARD32 *a = 0;
00108    CARD32 *r = 0;
00109    CARD32 *g = 0;
00110    CARD32 *b = 0;       
00111         START_TIME(started);
00112 
00113 LOCAL_DEBUG_CALLER_OUT( "src = %p, offset_x = %d, offset_y = %d, to_width = %d, to_height = %d", im, offset_x, offset_y, to_width, to_height );
00114         if( im== NULL || (imdec = start_image_decoding(asv, im, mask ? SCL_DO_ALPHA : SCL_DO_ALL, offset_x, offset_y, to_width, 0, NULL)) == NULL )
00115         {
00116                 LOCAL_DEBUG_OUT( "failed to start image decoding%s", "");
00117                 return NULL;
00118         }
00119         
00120         if( to_height > im->height )
00121         {
00122                 tiling_step = im->height ;
00123                 max_y = im->height ;
00124         }
00125         /* create bmp_info struct */
00126         bmp_info = (BITMAPINFO *)safecalloc( 1, sizeof(BITMAPINFO) );
00127         bmp_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
00128         bmp_info->bmiHeader.biWidth = to_width ;
00129         bmp_info->bmiHeader.biHeight = to_height ;
00130         bmp_info->bmiHeader.biPlanes = 1 ;
00131         bmp_info->bmiHeader.biBitCount = mask ? 1 : 24 ;
00132         bmp_info->bmiHeader.biCompression = BI_RGB ;
00133         bmp_info->bmiHeader.biSizeImage = 0 ;
00134         bmp_info->bmiHeader.biClrUsed = 0 ;
00135         bmp_info->bmiHeader.biClrImportant = 0 ;
00136         /* allocate DIB bits : */
00137         line_size = mask ? to_width : ((to_width*3+3)/4)*4;          /* DWORD aligned */
00138         pad = line_size-(to_width*(mask ? 1 : 3)) ;
00139         bits = (CARD8 *)safemalloc(line_size * to_height);
00140         curr = bits + line_size * to_height ;
00141 
00142    if (mask) {
00143            a = imdec->buffer.alpha ;
00144    } else {
00145            r = imdec->buffer.red ;
00146            g = imdec->buffer.green ;
00147            b = imdec->buffer.blue ;
00148    }
00149 
00150         for( y = 0 ; y < max_y ; y++  )
00151         {
00152                 register int x = to_width;
00153                 imdec->decode_image_scanline( imdec );
00154                 /* convert to DIB bits : */
00155                 curr -= pad ;
00156                 while( --x >= 0 ) 
00157                 {
00158                         curr -= (mask ? 1 : 3) ; 
00159          if (mask) {
00160             curr[0] = a[x]==0 ? 0 : 1 ;
00161          } else {
00162                            curr[0] = b[x] ;     
00163                            curr[1] = g[x] ; 
00164                            curr[2] = r[x] ;
00165          }
00166                 }        
00167                 if( tiling_step > 0 ) 
00168                 {
00169                         CARD8 *tile ;
00170                         int offset = tiling_step ; 
00171                         while( y + offset < (int)to_height ) 
00172                         {                
00173                                 tile = curr - offset*line_size ; 
00174                                 memcpy( tile, curr, line_size );
00175                                 offset += tiling_step ;
00176                         }
00177                 }        
00178         }
00179         
00180         stop_image_decoding( &imdec );
00181 
00182         SHOW_TIME("", started);
00183         *pBits = bits ;
00184         return bmp_info;
00185 }
00186 
00187 /* stupid typo !!!!! and now we are stuck with it :( */
00188 #undef ASImage2DBI
00189 BITMAPINFO *
00190 ASImage2DBI( ASVisual *asv, ASImage *im, 
00191                      int offset_x, int offset_y,
00192                          unsigned int to_width,
00193                          unsigned int to_height,
00194                          void **pBits, int mask )
00195 {
00196         return ASImage2DIB(asv, im, offset_x, offset_y, to_width, to_height, pBits, mask );
00197 }
00198 
00199 
00200 
00201 ASImage *
00202 DIB2ASImage(BITMAPINFO *bmp_info, int compression)
00203 {
00204   int width = bmp_info->bmiHeader.biWidth;
00205   int height = bmp_info->bmiHeader.biHeight;
00206   ASImage *im = NULL;
00207   ASScanline buf;
00208   int y;
00209         CARD8 *data ;
00210         CARD8 *cmap = NULL ;
00211         int direction = -1 ;
00212         int cmap_entries = 0, cmap_entry_size = 4, row_size ;
00213 
00214   if (width <= 0 || height == 0 )
00215     return NULL;
00216 
00217         if( height < 0 )
00218     {
00219                   direction = 1 ;
00220       height = -height;
00221     }
00222 
00223         if( bmp_info->bmiHeader.biBitCount < 16 )
00224                 cmap_entries = 0x01<<bmp_info->bmiHeader.biBitCount ;
00225 
00226         if( bmp_info->bmiHeader.biSize != 40 )
00227                 cmap_entry_size = 3;
00228 
00229         if( cmap_entries )
00230     {
00231                   cmap = (CARD8*)&(bmp_info->bmiColors[0]);
00232         data = cmap + cmap_entries*cmap_entry_size;
00233     }
00234   else
00235     data = (CARD8*)&(bmp_info->bmiColors[0]);
00236 
00237         row_size = (width*bmp_info->bmiHeader.biBitCount)>>3 ;
00238         if( row_size == 0 )
00239                 row_size = 1 ;
00240         else
00241                 row_size = (row_size+3)/4 ;            /* everything is aligned by 32 bits */
00242         row_size *= 4 ;                            /* in bytes  */
00243 
00244   im = create_asimage(width, height, compression);
00245 
00246         /* Window BMP files are little endian  - we need to swap Red and Blue */
00247         prepare_scanline( width, 0, &buf, True );
00248 
00249         y =( direction == 1 )?0:height-1 ;
00250         while( y >= 0 && y < (int)height)
00251         {
00252                 dib_data_to_scanline(&buf, &(bmp_info->bmiHeader), NULL, data, cmap, cmap_entry_size);
00253                 asimage_add_line (im, IC_RED,   buf.red  , y);
00254                 asimage_add_line (im, IC_GREEN, buf.green, y);
00255                 asimage_add_line (im, IC_BLUE,  buf.blue , y);
00256                 y += direction ;
00257     data += row_size;
00258         }
00259 
00260   free_scanline( &buf, True );
00261 
00262   return im;
00263 }
00264 
00265 
00266 ASImage      *
00267 bitmap2asimage (unsigned char *xim, int width, int height, unsigned int compression, 
00268                 unsigned char *mask)
00269 {
00270         ASImage      *im = NULL;
00271         int           i, bpl, x;
00272         ASScanline    xim_buf;
00273 
00274     if( xim == NULL )
00275                 return NULL ;
00276 
00277         im = create_asimage( width, height, compression);
00278         prepare_scanline( width, 0, &xim_buf, True );
00279 
00280         if( xim )
00281         {
00282             bpl = (width*32)>>3 ;
00283             if( bpl == 0 )
00284                     bpl = 1 ;
00285             else
00286                     bpl = (bpl+3)/4;
00287             bpl *= 4;
00288                 for (i = 0; i < height; i++) {
00289             if (mask) {
00290                for (x = 0; x < width<<2; x += 4) {
00291                   xim[3 + x] = mask[x] == 0 ? 0 : 255;
00292                }
00293             }
00294                            raw2scanline( xim, &xim_buf, 0, width, False, True);
00295             if (mask) asimage_add_line (im, IC_ALPHA, xim_buf.alpha, i);
00296                    asimage_add_line (im, IC_RED,   xim_buf.red, i);
00297                       asimage_add_line (im, IC_GREEN, xim_buf.green, i);
00298                       asimage_add_line (im, IC_BLUE,  xim_buf.blue, i);
00299                            xim += bpl;
00300             if (mask) mask += bpl;
00301                 }
00302         }
00303         free_scanline(&xim_buf, True);
00304 
00305         return im;
00306 }
00307 

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