bmp.c

Go to the documentation of this file.
00001 
00007 #include <stdio.h>
00008 #include "ctl/ctldef.h"
00009 #include "bmp.h"
00010 
00011 #ifndef CTL_UNIT
00012 
00020 void BMI_OPC( OPC* opc, const BITMAPINFO* bmi, void* bits )
00021 {
00022     OPC* out = (opc);
00023     const BITMAPINFO* bmin = (bmi);
00024     out->origin = (uint8*)BMI_Origin(bmin,bits);
00025     out->pitch = BMI_LineOffset(bmin);
00026     out->clip.left = out->clip.top = 0;
00027     out->clip.right = BMI_Wide(bmin);
00028     out->clip.bottom = BMI_High(bmin);
00029 }
00030 
00031 /*
00032  * Get 'distance' between c1 and c2 in RGB color space
00033  */
00034 static unsigned ddRGBQUAD( const RGBQUAD* c1, const RGBQUAD* c2 )
00035 {
00036     int diffr = c1->rgbRed - c2->rgbRed;
00037     int diffg = c1->rgbGreen - c2->rgbGreen;
00038     int diffb = c1->rgbBlue - c2->rgbBlue;
00039     return (diffr*diffr)+(diffg*diffg)+(diffb*diffb);
00040 }
00041 
00045 int RGBQUAD_Nearest( const RGBQUAD* clut, size_t count, const RGBQUAD* color )
00046 {
00047     const RGBQUAD* best = clut;
00048     unsigned bestDistance = ddRGBQUAD( best, color );
00049     unsigned score;
00050     pointer_foreach_const(RGBQUAD,clut+1,count-1, curr )
00051     {
00052         score = ddRGBQUAD( curr, color );
00053         if( score < bestDistance )
00054         {
00055             best = curr;
00056             bestDistance = score;
00057             if( !score )
00058                 break;
00059         }
00060     }
00061     return best ? best - clut : 0;
00062 }
00063 
00064 /* Get lsb of a mask */
00065 static int lsb( uint32 val )
00066 {
00067     int bit = 0;
00068     while( val && !(val&1) )
00069     {
00070         val>>=1;
00071         bit++;
00072     }
00073     return bit;
00074 }
00075 
00076 /* Get count of bits in a mask */
00077 static int nbits( uint32 val )
00078 {
00079     int bit = 0;
00080     while( val && !(val&1) )
00081         val>>=1;
00082     while( val&1 )
00083     {
00084         val>>=1;
00085         bit++;
00086     }
00087     return bit;
00088 }
00089 
00090 
00100 bool BMI_ReadRow( RGBQUAD* pixel, const BITMAPINFO* bmi, const void* bits, int row )
00101 {
00102     /* Don't choke on bad row */
00103     assert(bmi);
00104     assert(bits);
00105     if( row < 0 || row >= BMI_High(bmi) || (bmi->bmiHeader.biCompression != BI_RGB && bmi->bmiHeader.biCompression != BI_BITFIELDS && bmi->bmiHeader.biCompression != BI_RLE4 && bmi->bmiHeader.biCompression != BI_RLE8) )
00106     {
00107         memset( pixel, 0, sizeof(RGBQUAD)*BMI_Wide(bmi) );
00108         return false;
00109     }
00110     switch( bmi->bmiHeader.biBitCount )
00111     {
00112     case 1:
00113         {
00114             const RGBQUAD* colors = BMI_ColorData(bmi);
00115             const uint8* pixels = (const uint8*)BMI_LinePtr(bmi,bits,row);
00116             int wordlen = BMI_Wide(bmi);
00117             while( wordlen )
00118             {
00119                 uint8 bit = 0x80;
00120                 while( bit && wordlen )
00121                 {
00122                     *pixel++ = colors[0 != (*pixels & bit)];
00123                     wordlen--;
00124                     bit >>= 1;
00125                 }
00126                 pixels++;
00127             }
00128         }
00129         return true;
00130 
00131     case 4:
00132         {
00133             const RGBQUAD* colors = BMI_ColorData(bmi);
00134             const uint8* pixels = (const uint8*)BMI_LinePtr(bmi,bits,row);
00135             int wordlen = BMI_Wide(bmi);
00136             int curr;
00137             for( curr = 0; curr < wordlen; ++curr )
00138             {
00139                 if( curr&1 )
00140                 {
00141                     *pixel++ = colors[*pixels&0xf];
00142                     pixels++;
00143                 }
00144                 else
00145                 {
00146                     *pixel++ = colors[(*pixels>>4)&0xf];
00147                 }
00148             }
00149         }
00150         return true;
00151 
00152     case 8:
00153         {
00154             const RGBQUAD* colors = BMI_ColorData(bmi);
00155             const uint8* pixels = (const uint8*)BMI_LinePtr(bmi,bits,row);
00156             int wordlen = BMI_Wide(bmi);
00157             while( wordlen-- )
00158                 *pixel++ = colors[*pixels++];
00159         }
00160         return true;
00161 
00162     case 16:
00163         if( bmi->bmiHeader.biCompression == BI_BITFIELDS )
00164         {
00165             const uint32* masks = (const uint32*)BMI_ColorData(bmi);
00166             uint16 mRed = (uint16)masks[0];
00167             uint16 mGreen = (uint16)masks[1];
00168             uint16 mBlue = (uint16)masks[2];
00169             int bRed = lsb(mRed);
00170             int bGreen = lsb(mGreen);
00171             int bBlue = lsb(mBlue);
00172             int nRed = nbits( mRed );
00173             int nGreen = nbits( mGreen );
00174             int nBlue = nbits( mBlue );
00175             const uint16* pixels = (const uint16*)BMI_LinePtr(bmi,bits,row);
00176             int wordlen = BMI_Wide(bmi);
00177             while( wordlen-- )
00178             {
00179                 pixel->rgbBlue = (uint8)(((mBlue & *pixels) >> bBlue) << (8-nBlue));
00180                 pixel->rgbGreen = (uint8)(((mGreen & *pixels) >> bGreen) << (8-nGreen));
00181                 pixel->rgbRed = (uint8)(((mRed & *pixels) >> bRed) << (8-nRed));
00182                 pixel->rgbReserved = 0;
00183                 pixel++;
00184                 pixels++;
00185             }
00186         }
00187         else
00188         {
00189             const uint16* pixels = (const uint16*)BMI_LinePtr(bmi,bits,row);
00190             int wordlen = BMI_Wide(bmi);
00191             while( wordlen-- )
00192             {
00193                 pixel->rgbBlue = (uint8)((*pixels & 0x1f) << 3);
00194                 pixel->rgbGreen = (uint8)(((*pixels >> 5) & 0x1f) << 3);
00195                 pixel->rgbRed = (uint8)(((*pixels >> 10) & 0x1f) << 3);
00196                 pixel->rgbReserved = 0;
00197                 pixels++;
00198                 pixel++;
00199             }
00200         }
00201         return true;
00202 
00203     case 24:
00204         {
00205             const uint8* pixels = (const uint8*)BMI_LinePtr(bmi,bits,row);
00206             int wordlen = BMI_Wide(bmi);
00207             while( wordlen-- )
00208             {
00209                 pixel->rgbBlue = *pixels++;
00210                 pixel->rgbGreen = *pixels++;
00211                 pixel->rgbRed = *pixels++;
00212                 pixel->rgbReserved = 0;
00213                 pixel++;
00214             }
00215         }
00216         return true;
00217 
00218     case 32:
00219         if( bmi->bmiHeader.biCompression == BI_BITFIELDS )
00220         {
00221             const uint32* masks = (const uint32*)BMI_ColorData(bmi);
00222             uint32 mRed = (uint32)masks[0];
00223             uint32 mGreen = (uint32)masks[1];
00224             uint32 mBlue = (uint32)masks[2];
00225             int bRed = lsb(mRed);
00226             int bGreen = lsb(mGreen);
00227             int bBlue = lsb(mBlue);
00228             int nRed = nbits( mRed );
00229             int nGreen = nbits( mGreen );
00230             int nBlue = nbits( mBlue );
00231             const uint32* pixels = (const uint32*)BMI_LinePtr(bmi,bits,row);
00232             int wordlen = BMI_Wide(bmi);
00233             while( wordlen-- )
00234             {
00235                 pixel->rgbBlue = (uint8)(((mBlue & *pixels) >> bBlue) << (8-nBlue));
00236                 pixel->rgbGreen = (uint8)(((mGreen & *pixels) >> bGreen) << (8-nGreen));
00237                 pixel->rgbRed = (uint8)(((mRed & *pixels) >> bRed) << (8-nRed));
00238                 pixel->rgbReserved = 0;
00239                 pixels++;
00240                 pixel++;
00241             }
00242         }
00243         else
00244         {
00245             const uint8* pixels = (const uint8*)BMI_LinePtr(bmi,bits,row);
00246             int wordlen = BMI_Wide(bmi);
00247             while( wordlen-- )
00248             {
00249                 pixel->rgbBlue = *pixels++;
00250                 pixel->rgbGreen = *pixels++;
00251                 pixel->rgbRed = *pixels++;
00252                 pixel->rgbReserved = 0;
00253                 pixel++;
00254                 pixels++;
00255             }
00256         }
00257         return true;
00258 
00259     default:
00260         break;
00261     }
00262     return false;
00263 }
00264 
00265 
00275 bool BMI_WriteRow( const BITMAPINFO* bmi, void* bits, const RGBQUAD* pixel, int row )
00276 {
00277     /* Don't choke on bad row */
00278     assert(bmi);
00279     assert(bits);
00280     if( row < 0 || row >= BMI_High(bmi) || (bmi->bmiHeader.biCompression != BI_RGB && bmi->bmiHeader.biCompression != BI_BITFIELDS) )
00281     {
00282         return false;
00283     }
00284     switch( bmi->bmiHeader.biBitCount )
00285     {
00286     case 1:
00287         {
00288             /* 1 bit color indexes */
00289             const RGBQUAD* colors = BMI_ColorData(bmi);
00290             uint8* pixels = (uint8*)BMI_LinePtr(bmi,bits,row);
00291             int wordlen = BMI_Wide(bmi);
00292             while( wordlen )
00293             {
00294                 uint8 bit = 0x80;
00295                 *pixels = 0;
00296                 while( bit && wordlen )
00297                 {
00298                     if( RGBQUAD_Nearest( colors, 2, pixel++ ) )
00299                         *pixels |= bit;
00300                     bit>>=1;
00301                     wordlen--;
00302                 }
00303                 pixels++;
00304             }
00305         }
00306         return true;
00307 
00308     case 4:
00309         {
00310             const RGBQUAD* colors = BMI_ColorData(bmi);
00311             uint8* pixels = (uint8*)BMI_LinePtr(bmi,bits,row);
00312             int wordlen = BMI_Wide(bmi);
00313             int curr;
00314             for( curr = 0; curr < wordlen; ++curr )
00315             {
00316                 unsigned index = (unsigned)RGBQUAD_Nearest( colors, 16, pixel++ );
00317                 if( wordlen & 1 )
00318                     *pixels++ = (uint8)index;
00319                 else
00320                     *pixels |= (uint8)(index<<4);
00321             }
00322         }
00323         return true;
00324 
00325     case 8:
00326         {
00327             /* 8 bit color indexes */
00328             const RGBQUAD* colors = BMI_ColorData(bmi);
00329             uint8* pixels = (uint8*)BMI_LinePtr(bmi,bits,row);
00330             int wordlen = BMI_Wide(bmi);
00331             while( wordlen-- )
00332                 *pixels++ = (uint8)RGBQUAD_Nearest( colors, 256, pixel++ );
00333         }
00334         return true;
00335 
00336     case 16:
00337         if( bmi->bmiHeader.biCompression == BI_BITFIELDS )
00338         {
00339             /* 16 bit masks */
00340             const uint32* masks = (const uint32*)BMI_ColorData(bmi);
00341             uint16 mRed = (uint16)masks[0];
00342             uint16 mGreen = (uint16)masks[1];
00343             uint16 mBlue = (uint16)masks[2];
00344             int bRed = lsb(mRed);
00345             int bGreen = lsb(mGreen);
00346             int bBlue = lsb(mBlue);
00347             int nRed = nbits( mRed );
00348             int nGreen = nbits( mGreen );
00349             int nBlue = nbits( mBlue );
00350             uint16* pixels = (uint16*)BMI_LinePtr(bmi,bits,row);
00351             int wordlen = BMI_Wide(bmi);
00352             while( wordlen-- )
00353             {
00354                 *pixels = 0;
00355                 *pixels |= (((uint16)pixel->rgbBlue & ((1<<nBlue)-1)) >> (8-nBlue)) << bBlue;
00356                 *pixels |= (((uint16)pixel->rgbGreen & ((1<<nGreen)-1)) >> (8-nGreen)) << bGreen;
00357                 *pixels |= (((uint16)pixel->rgbRed & ((1<<nRed)-1)) >> (8-nRed)) << bRed;
00358                 pixel++;
00359                 pixels++;
00360             }
00361         }
00362         else
00363         {
00364             /* lsb 5 bits of blue, green, red, msb=0 */
00365             uint16* pixels = (uint16*)BMI_LinePtr(bmi,bits,row);
00366             int wordlen = BMI_Wide(bmi);
00367             while( wordlen-- )
00368             {
00369                 *pixels = 0;
00370                 *pixels |= ((uint16)pixel->rgbBlue & 0xf8) >> 3;
00371                 *pixels |= ((uint16)pixel->rgbGreen & 0xf8) << 2;
00372                 *pixels |= ((uint16)pixel->rgbRed & 0xf8) << 7;
00373                 pixels++;
00374                 pixel++;
00375             }
00376         }
00377         return true;
00378 
00379     case 24:
00380         {
00381             /* 24 bits of blue,green,red */
00382             uint8* pixels = (uint8*)BMI_LinePtr(bmi,bits,row);
00383             int wordlen = BMI_Wide(bmi);
00384             while( wordlen-- )
00385             {
00386                 *pixels++ = pixel->rgbBlue;
00387                 *pixels++ = pixel->rgbGreen;
00388                 *pixels++ = pixel->rgbRed;
00389                 pixel++;
00390             }
00391         }
00392         return true;
00393 
00394     case 32:
00395         if( bmi->bmiHeader.biCompression == BI_BITFIELDS )
00396         {
00397             /* 32 bit masks */
00398             const uint32* masks = (const uint32*)BMI_ColorData(bmi);
00399             uint32 mRed = (uint32)masks[0];
00400             uint32 mGreen = (uint32)masks[1];
00401             uint32 mBlue = (uint32)masks[2];
00402             int bRed = lsb(mRed);
00403             int bGreen = lsb(mGreen);
00404             int bBlue = lsb(mBlue);
00405             int nRed = nbits( mRed );
00406             int nGreen = nbits( mGreen );
00407             int nBlue = nbits( mBlue );
00408             uint32* pixels = (uint32*)BMI_LinePtr(bmi,bits,row);
00409             int wordlen = BMI_Wide(bmi);
00410             while( wordlen-- )
00411             {
00412                 *pixels = 0;
00413                 *pixels |= (((uint32)pixel->rgbBlue & ((1<<nBlue)-1)) >> (8-nBlue)) << bBlue;
00414                 *pixels |= (((uint32)pixel->rgbGreen & ((1<<nGreen)-1)) >> (8-nGreen)) << bGreen;
00415                 *pixels |= (((uint32)pixel->rgbRed & ((1<<nRed)-1)) >> (8-nRed)) << bRed;
00416                 pixel++;
00417                 pixels++;
00418             }
00419         }
00420         else
00421         {
00422             /* Default is 8 bits each of blue, green, red */
00423             uint8* pixels = (uint8*)BMI_LinePtr(bmi,bits,row);
00424             int wordlen = BMI_Wide(bmi);
00425             while( wordlen-- )
00426             {
00427                 *pixels++ = pixel->rgbBlue;
00428                 *pixels++ = pixel->rgbGreen;
00429                 *pixels++ = pixel->rgbRed;
00430                 *pixels++ = 0;
00431                 pixel++;
00432             }
00433         }
00434         return true;
00435 
00436     default:
00437         break;
00438     }
00439     return false;
00440 }
00441 
00442 
00443 /*
00444 static int qsColors( const RGBQUAD* c1, const RGBQUAD* c2 )
00445 {
00446     float h1,s1,v1, h2,s2,v2;
00447     RGB256toHSV( c1->rgbRed, c1->rgbGreen, c1->rgbBlue, &h1, &s1, &v1 );
00448     RGB256toHSV( c2->rgbRed, c2->rgbGreen, c2->rgbBlue, &h2, &s2, &v2 );
00449     return (int)(((h1/120.0f) + (v1*2.0f) + s1) - ((h2/220.0f) + (v2*2.0f) + s2));
00450 }
00451 */
00452 
00462 size_t BMI_MakeClut( RGBQUAD* dstlut, size_t cClut, const BITMAPINFO* bmi, const void* bits )
00463 {
00464     BMIClut clutz;
00465     BMI_Clut_Begin( &clutz );
00466     {
00467         BMI_foreach( bmi, bits, pixel )
00468             BMI_Clut_AddColor( &clutz, pixel );
00469     }
00470     return BMI_Clut_Make( &clutz, dstlut, cClut );
00471 }
00472 
00477 void BMI_Clut_Begin( BMIClut* clut )
00478 {
00479     memset( clut->cluts, 0, sizeof(clut->cluts) );
00480 }
00486 void BMI_Clut_AddColor( BMIClut* clut, const RGBQUAD* rgb )
00487 {
00488     #define CLI(RGBQUAD) ( (((RGBQUAD).rgbBlue&0xf8)>>3) | (((RGBQUAD).rgbGreen&0xf8)<<2) | (((RGBQUAD).rgbRed&0xf8)<<7) )
00489     int index = CLI(*rgb);
00490     struct BMIClutEntry* curr = clut->cluts + index;
00491     curr->rgb = *rgb;
00492     if( curr->count < type_max(uint32) )
00493         curr->count++;
00494 }
00495 static int qsclutz( const struct BMIClutEntry* c1, const struct BMIClutEntry* c2 ) { return c2->count-c1->count; }
00496 static int qspretty( const struct BMIClutEntry* c1, const struct BMIClutEntry* c2 )
00497 {
00498     int diff1,diff2,diff;
00499     /* Empty values last */
00500     if( !c1->count || !c2->count )
00501         return c2->count-c1->count;
00502     /* Group greyscales */
00503     diff1 = c1->rgb.rgbRed == c1->rgb.rgbGreen && c1->rgb.rgbRed == c1->rgb.rgbBlue;
00504     diff2 = c2->rgb.rgbRed == c2->rgb.rgbGreen && c2->rgb.rgbRed == c2->rgb.rgbBlue;
00505     diff = diff2-diff1;
00506     if( diff )
00507         return diff;
00508     /* Group primary colors */
00509     diff1 = !c1->rgb.rgbRed || !c1->rgb.rgbGreen || !c1->rgb.rgbBlue;
00510     diff2 = !c2->rgb.rgbRed || !c2->rgb.rgbGreen || !c2->rgb.rgbBlue;
00511     diff = diff2-diff1;
00512     if( diff )
00513         return diff;
00514     /* Diff by B,G.rgbRed */
00515     diff = c1->rgb.rgbBlue - c2->rgb.rgbBlue;
00516     if( diff )
00517         return diff;
00518     diff = c1->rgb.rgbGreen - c2->rgb.rgbGreen;
00519     if( diff )
00520         return diff;
00521     diff = c1->rgb.rgbRed - c2->rgb.rgbRed;
00522     return diff;
00523 }
00524 
00525 
00532 size_t BMI_Clut_Make( BMIClut* clut, RGBQUAD* dstlut, size_t cClut )
00533 {
00534     array_qsort( struct BMIClutEntry, clut->cluts, countof(clut->cluts), qsclutz );
00535     array_qsort( struct BMIClutEntry, clut->cluts, cClut, qspretty );
00536     {
00537         const struct BMIClutEntry* curr = clut->cluts;
00538         size_t remain = cClut;
00539         while( remain )
00540         {
00541             remain--;
00542             if( curr->count )
00543                 *dstlut++ = (curr++)->rgb;
00544             else
00545                 break;
00546         }
00547         cClut -= remain;
00548         return cClut;
00549     }
00550 }
00551 
00552 
00560 void BMI_Translate( const BITMAPINFO* dst, void* bdst, const BITMAPINFO* src, const void* bsrc )
00561 {
00562     RGBQUAD* colors = (RGBQUAD*)malloc( sizeof(RGBQUAD) * max(BMI_Wide(dst),BMI_Wide(src)) );
00563     int rowCurr = min( BMI_High(dst), BMI_High(src) );
00564     while( rowCurr-- )
00565     {
00566         BMI_ReadRow( colors, src, bsrc, rowCurr );
00567         BMI_WriteRow( dst, bdst, colors, rowCurr );
00568     }
00569     free(colors);
00570 }
00571 
00572 
00579 void* BMI_Unpack( const BITMAPINFO* bmi, const void* bits )
00580 {
00581     switch( bmi->bmiHeader.biCompression )
00582     {
00583     default:
00584     case BI_BITFIELDS:
00585     case BI_RGB:
00586         return NULL;
00587 
00588     case BI_RLE4:
00589     case BI_RLE8:
00590         {
00591             size_t current = BMI_BitmapSize(bmi);
00592             size_t lineSize = BMI_LineSize(bmi);
00593             size_t needs = lineSize * BMI_High(bmi);
00594             void* ret = malloc(needs);
00595             const uint8* pSrc = (const uint8*)bits;
00596             const uint8* pEnd = pSrc + current;
00597             uint8* pDstEdge = (uint8*)ret;
00598             uint8* pDst = pDstEdge;
00599             const uint8* pdEnd = pDst + needs;
00600             while( pSrc < pEnd )
00601             {
00602                 int count = *pSrc++;
00603                 if( count )
00604                 {
00605                     uint8 fill = *pSrc++;
00606                     count = min(count,(int)(pdEnd-pDst));
00607                     if( bmi->bmiHeader.biCompression == BI_RLE8 )
00608                     {
00609                         memset( pDst, fill, count );
00610                         pDst += count;
00611                     }
00612                     else
00613                     {
00614                         count>>=1;
00615                         memset( pDst, fill, count );
00616                         pDst += count;
00617                     }
00618                 }
00619                 else /* Escape */
00620                 {
00621                     count = *pSrc++;    /* Get code */
00622                     if( count == 0 )
00623                     {
00624                         pDst = pDstEdge += lineSize;
00625                     }
00626                     else if( count == 1 )
00627                         break;
00628                     else if( count == 2 )
00629                     {
00630                         int x = *pSrc++;
00631                         int y = *pSrc++;
00632                         pDstEdge += (lineSize*y);
00633                         pDst = pDstEdge + x;
00634                     }
00635                     else
00636                     {
00637                         count = min(count,(int)(pdEnd-pDst));
00638                         count = min(count,(int)(pEnd-pSrc));
00639                         if( bmi->bmiHeader.biCompression == BI_RLE4 )
00640                         {
00641                             memcpy( pDst, pSrc, count>>1 );
00642                             pDst += count>>1;
00643                             pSrc += count;
00644                         }
00645                         else
00646                         {
00647                             memcpy( pDst, pSrc, count );
00648                             pDst += count;
00649                             pSrc += count;
00650                         }
00651                         /* Read mysterious excess byte */
00652                         if( bmi->bmiHeader.biCompression == BI_RLE8 )
00653                         {
00654                             if( count & 1 )
00655                                 pSrc++;
00656                         }
00657                         else
00658                         {
00659                             if( (count & 3) == 1 || (count & 3) == 2 )
00660                                 pSrc++;
00661                         }
00662                     }
00663                 }
00664             }
00665             return ret;
00666         }
00667         break;
00668     }
00669 }
00670 
00677 bool BMI_Save( const char* path, const BITMAPINFO* bmi, const void* bits )
00678 {
00679     /*
00680      * TODO: Replace with target independent code
00681      */
00682     /* Save BMI/bits as a BITMAP */
00683     FILE *fp = fopen( path, "wb" );
00684     assert( bmi );
00685     assert( bits );
00686     assert( bmi->bmiHeader.biWidth > 0 );
00687     assert( bmi->bmiHeader.biHeight );
00688     if( fp )
00689     {
00690         BITMAPFILEHEADER bmf;
00691         bmf.bfType = *((uint16 *)"BM");
00692         bmf.bfSize = sizeof(bmf) + BMI_BMI_Size(bmi) + BMI_BitmapSize(bmi);
00693         bmf.bfReserved1 = 0;
00694         bmf.bfReserved2 = 0;
00695         bmf.bfOffBits = sizeof(bmf) + BMI_BMI_Size(bmi);
00696         if( 1 != fwrite( &bmf, sizeof(bmf), 1, fp ) )
00697         {
00698             fclose( fp );
00699             return false;
00700         }
00701         {
00702             /* Tell it form is 'rightside up' */
00703             BITMAPINFO *bmiScratch = BMI_Alloc();
00704             memcpy( bmiScratch, bmi, BMI_BMI_Size(bmi) );
00705             bmiScratch->bmiHeader.biHeight = abs(bmiScratch->bmiHeader.biHeight);
00706             if( 1 != fwrite( bmiScratch, BMI_BMI_Size(bmiScratch), 1, fp ) )
00707             {
00708                 fclose( fp );
00709                 return false;
00710             }
00711             BMI_Free(bmiScratch);
00712         }
00713         {
00714             /* Always write image upside-down */
00715             int line = BMI_High(bmi);
00716             while( line-- )
00717             {
00718                 if( 1 != fwrite( BMI_LinePtr(bmi,bits,line), BMI_LineSize(bmi), 1, fp ) )
00719                     break;
00720             }
00721         }
00722         fclose( fp );
00723         return true;
00724     }
00725     return false;
00726 }
00727 
00728 #include "ctl/mmap.h"
00735 bool BMI_Load( const char* path, BITMAPINFO** bmi, void** bits )
00736 {
00737     /*
00738      * TODO: Replace with target independent code
00739      */
00740     ctl_mmap image;
00741     ctl_mmap_open( &image, path );
00742     if( ctl_mmap_ready(&image) )
00743     {
00744         const BITMAPINFO* bmiIn;
00745         const void* bitsIn;
00746         BMI_ParseData( ctl_mmap_ptr(&image), bmiIn, bitsIn );
00747         *bmi = BMI_BMI_Copy(bmiIn);
00748         *bits = BMI_Unpack( bmiIn, bitsIn );
00749         return true;
00750     }
00751     return false;
00752 }
00753 
00754 #else
00755 #endif /* CTL_UNIT */
00756 

Generated on Fri Jan 2 15:28:34 2009 for Squat by  doxygen 1.5.6