• Main Page
  • Related Pages
  • Modules
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/Image.cpp

00001 /*
00002  *   This file is part of the Standard Portable Library (SPL).
00003  *
00004  *   SPL is free software: you can redistribute it and/or modify
00005  *   it under the terms of the GNU General Public License as published by
00006  *   the Free Software Foundation, either version 3 of the License, or
00007  *   (at your option) any later version.
00008  *
00009  *   SPL is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details.
00013  *
00014  *   You should have received a copy of the GNU General Public License
00015  *   along with SPL.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 #include <stdio.h>
00018 #include <stdlib.h>
00019 
00020 #include <spl/types.h>
00021 
00022 #ifdef _WINDOWS
00023 #include <spl/configwin32.h>
00024 #else
00025 #include <spl/autoconf/config.h>
00026 #endif
00027 
00028 #ifdef HAVE_STRING_H
00029 #include <string.h>
00030 #endif
00031 
00032 #include <spl/Image.h>
00033 
00034 static unsigned int u32fread(FILE *);
00035 static unsigned int u16fread(FILE *);
00036 static unsigned int u8fread(FILE *);
00037 
00038 static bool IsBMP(char const *name)
00039 {
00040         int len = (int)strlen(name);
00041         return name[len-1] == 'p' && name[len-2] == 'm' && name[len-3] == 'b' && name[len-4] == '.';
00042 }
00043 
00044 Image *Image::GetImage(const char *name)
00045 {
00046     Image *im = new Image();
00047         if ( ! IsBMP(name) )
00048         {
00049                 delete im;
00050                 return NULL;
00051         }
00052     /* Try to load a BMP file */
00053     unsigned int i, colors, offset, tmp, planes;
00054     FILE *fp;
00055 
00056     fp = fopen(name, "rb");
00057     if(!fp)
00058     {
00059         delete im;
00060         return NULL;
00061     }
00062 
00063     if(u16fread(fp) != 0x4d42)
00064     {
00065         fclose(fp);
00066         delete im;
00067         return NULL;
00068     }
00069 
00070     u32fread(fp); /* size */
00071     u16fread(fp); /* reserved 1 */
00072     u16fread(fp); /* reserved 2 */
00073 
00074     offset = u32fread(fp);
00075 
00076     tmp = u32fread(fp); /* header size */
00077     if(tmp == 40)
00078     {
00079         im->m_w = u32fread(fp);
00080         im->m_h = u32fread(fp);
00081         planes = u16fread(fp);
00082         im->m_bpp = u16fread(fp);
00083 
00084         tmp = u32fread(fp); /* compression */
00085         if(tmp != 0)
00086         {
00087             fclose(fp);
00088             delete im;
00089             return NULL;
00090         }
00091 
00092         u32fread(fp); /* sizeimage */
00093         u32fread(fp); /* xpelspermeter */
00094         u32fread(fp); /* ypelspermeter */
00095         u32fread(fp); /* biclrused */
00096         u32fread(fp); /* biclrimportantn */
00097 
00098         colors = (offset - 54) / 4;
00099         for(i = 0; i < colors && i < 256; i++)
00100         {
00101             im->m_blue[i] = u8fread(fp) * 16;
00102             im->m_green[i] = u8fread(fp) * 16;
00103             im->m_red[i] = u8fread(fp) * 16;
00104             im->m_alpha[i] = 0;
00105             u8fread(fp);
00106         }
00107     }
00108     else if(tmp == 12)
00109     {
00110         im->m_w = u32fread(fp);
00111         im->m_h = u32fread(fp);
00112         planes = u16fread(fp);
00113         im->m_bpp = u16fread(fp);
00114 
00115         colors = (offset - 26) / 3;
00116         for(i = 0; i < colors && i < 256; i++)
00117         {
00118             im->m_blue[i] = u8fread(fp);
00119             im->m_green[i] = u8fread(fp);
00120             im->m_red[i] = u8fread(fp);
00121             im->m_alpha[i] = 0;
00122         }
00123     }
00124     else
00125     {
00126         fclose(fp);
00127         delete im;
00128         return NULL;
00129     }
00130 
00131     /* Fill the rest of the palette */
00132     for(i = colors; i < 256; i++)
00133         im->m_blue[i] = im->m_green[i] = im->m_red[i] = im->m_alpha[i] = 0;
00134 
00135     im->m_depth = (im->m_bpp + 7) / 8;
00136 
00137     /* Sanity check */
00138     if(!im->m_w || im->m_w > 0x10000 || !im->m_h || im->m_h > 0x10000 || planes != 1)
00139     {
00140         fclose(fp);
00141         delete im;
00142         return NULL;
00143     }
00144 
00145     /* Allocate the pixel buffer */
00146     im->m_pixels = (byte *)malloc(im->m_w * im->m_h * im->m_depth);
00147     if(!im->m_pixels)
00148     {
00149         fclose(fp);
00150         delete im;
00151         return NULL;
00152     }
00153 
00154     memset(im->m_pixels, 0, im->m_w * im->m_h * im->m_depth);
00155 
00156     /* Read the bitmap data */
00157     for(i = im->m_h; i--; )
00158     {
00159                 int j;
00160         unsigned int k, bits = 0;
00161 
00162         switch(im->m_bpp)
00163         {
00164             case 1:
00165                 for(j = 0; j < im->m_w; j++)
00166                 {
00167                     k = j % 32;
00168                     if(k == 0)
00169                         bits = u32fread(fp);
00170                     im->m_pixels[im->m_w * i * im->m_depth + j] =
00171                         (bits >> ((k & ~0xf) + 0xf - (k & 0xf))) & 0x1;
00172                 }
00173                 break;
00174             case 4:
00175                 for(j = 0; j < im->m_w; j++)
00176                 {
00177                     k = j % 8;
00178                     if(k == 0)
00179                         bits = u32fread(fp);
00180                     im->m_pixels[im->m_w * i * im->m_depth + j] =
00181                         (bits >> (4 * ((k & ~0x1) + 0x1 - (k & 0x1)))) & 0xf;
00182                 }
00183                 break;
00184             default:
00185                 /* Works for 8bpp, but also for 16, 24 etc. */
00186                 fread(im->m_pixels + im->m_w * i * im->m_depth, im->m_w * im->m_depth, 1, fp);
00187                 /* Pad reads to 4 bytes */
00188                 tmp = (im->m_w * im->m_depth) % 4;
00189                 tmp = (4 - tmp) % 4;
00190                 while(tmp--)
00191                     u8fread(fp);
00192                 break;
00193         }
00194     }
00195 
00196     switch(im->m_depth)
00197     {
00198     case 3:
00199         im->m_rmask = 0xff0000;
00200         im->m_gmask = 0x00ff00;
00201         im->m_bmask = 0x0000ff;
00202         im->m_amask = 0x000000;
00203         break;
00204     case 2: /* XXX: those are the 16 bits values */
00205         im->m_rmask = 0x7c00;
00206         im->m_gmask = 0x03e0;
00207         im->m_bmask = 0x001f;
00208         im->m_amask = 0x0000;
00209         break;
00210     case 1:
00211     default:
00212         im->m_bpp = 8;
00213         im->m_rmask = im->m_gmask = im->m_bmask = im->m_amask = 0;
00214         break;
00215     }
00216     fclose(fp);
00217 
00218     return im;
00219 }
00220 
00221 Image::Image()
00222 : m_pixels(NULL)
00223 {
00224 }
00225 
00226 Image::~Image()
00227 {
00228         if ( NULL != m_pixels )
00229         {
00230                 free(m_pixels);
00231         }
00232 }
00233 
00234 #ifdef DEBUG
00235 void Image::ValidateMem () const
00236 {
00237         ASSERT_PTR(m_pixels);
00238 }
00239 
00240 void Image::CheckMem () const
00241 {
00242         DEBUG_NOTE_MEM(m_pixels);
00243 }
00244 #endif
00245 
00246 
00247 #if !defined(USE_IMLIB2)
00248 static unsigned int u32fread(FILE *fp)
00249 {
00250     unsigned char buffer[4];
00251     fread(buffer, 4, 1, fp);
00252     return ((unsigned int)buffer[3] << 24) | ((unsigned int)buffer[2] << 16)
00253              | ((unsigned int)buffer[1] << 8) | ((unsigned int)buffer[0]);
00254 }
00255 
00256 static unsigned int u16fread(FILE *fp)
00257 {
00258     unsigned char buffer[2];
00259     fread(buffer, 2, 1, fp);
00260     return ((unsigned int)buffer[1] << 8) | ((unsigned int)buffer[0]);
00261 }
00262 
00263 static unsigned int u8fread(FILE *fp)
00264 {
00265     unsigned char buffer;
00266     fread(&buffer, 1, 1, fp);
00267     return (unsigned int)buffer;
00268 }
00269 #endif
00270