Fix bugs in previous commit that caused FTBFS in synfig and ETL FTBFS with older...
[synfig.git] / synfig-core / tags / synfig_0_61_07_rc2 / src / modules / mod_bmp / mptr_bmp.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file mptr_bmp.cpp
3 **      \brief bmp Target Module
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **
10 **      This package is free software; you can redistribute it and/or
11 **      modify it under the terms of the GNU General Public License as
12 **      published by the Free Software Foundation; either version 2 of
13 **      the License, or (at your option) any later version.
14 **
15 **      This package is distributed in the hope that it will be useful,
16 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **      General Public License for more details.
19 **      \endlegal
20 **
21 ** === N O T E S ===========================================================
22 **
23 ** ========================================================================= */
24
25 /* === H E A D E R S ======================================================= */
26
27 #define SYNFIG_NO_ANGLE
28
29 #ifdef USING_PCH
30 #       include "pch.h"
31 #else
32 #ifdef HAVE_CONFIG_H
33 #       include <config.h>
34 #endif
35
36 #include "mptr_bmp.h"
37 #include <synfig/general.h>
38 #include <synfig/surface.h>
39
40 #include <algorithm>
41 #include <functional>
42 #endif
43
44 /* === U S I N G =========================================================== */
45
46 using namespace synfig;
47 using namespace std;
48 using namespace etl;
49
50 /* === G L O B A L S ======================================================= */
51
52 SYNFIG_IMPORTER_INIT(bmp_mptr);
53 SYNFIG_IMPORTER_SET_NAME(bmp_mptr,"bmp");
54 SYNFIG_IMPORTER_SET_EXT(bmp_mptr,"bmp");
55 SYNFIG_IMPORTER_SET_VERSION(bmp_mptr,"0.1");
56 SYNFIG_IMPORTER_SET_CVS_ID(bmp_mptr,"$Id$");
57
58 /* === M E T H O D S ======================================================= */
59
60 struct BITMAPFILEHEADER
61 {
62         unsigned char   bfType[2];
63         unsigned long   bfSize;
64         unsigned short  bfReserved1;
65         unsigned short  bfReserved2;
66         unsigned long   bfOffsetBits;
67 };
68
69 struct BITMAPINFOHEADER
70 {
71         unsigned long   biSize;
72         long                    biWidth;
73         long                    biHeight;
74         unsigned short  biPlanes;
75         unsigned short  biBitCount;
76         unsigned long   biCompression;
77         unsigned long   biSizeImage;
78         long                    biXPelsPerMeter;
79         long                    biYPelsPerMeter;
80         unsigned long   biClrUsed;
81         unsigned long   biClrImportant;
82 };
83
84 #ifdef WORDS_BIGENDIAN
85 inline long little_endian(const long &x)
86 {
87         long ret;
88         char *big_e=(char *)&ret;
89         char *lit_e=(char *)&x;
90         big_e[0]=lit_e[3];
91         big_e[1]=lit_e[2];
92         big_e[2]=lit_e[1];
93         big_e[3]=lit_e[0];
94         return ret;
95 }
96 inline short little_endian_short(const short &x)
97 {
98         short ret;
99         char *big_e=(char *)&ret;
100         char *lit_e=(char *)&x;
101         big_e[0]=lit_e[1];
102         big_e[1]=lit_e[0];
103         return ret;
104 }
105 #else
106 #define little_endian(x)        (x)
107 #define little_endian_short(x)  (x)
108 #endif
109
110
111
112
113
114
115 bmp_mptr::bmp_mptr(const char *file)
116 {
117         filename=file;
118 }
119
120 bmp_mptr::~bmp_mptr()
121 {
122 }
123
124 bool
125 bmp_mptr::get_frame(synfig::Surface &surface,Time /*time*/, synfig::ProgressCallback *cb)
126 {
127         FILE *file=fopen(filename.c_str(),"rb");
128         if(!file)
129         {
130                 if(cb)cb->error("bmp_mptr::GetFrame(): "+strprintf(_("Unable to open %s"),filename.c_str()));
131                 else synfig::error("bmp_mptr::GetFrame(): "+strprintf(_("Unable to open %s"),filename.c_str()));
132                 return false;
133         }
134
135         BITMAPFILEHEADER fileheader;
136         BITMAPINFOHEADER infoheader;
137         char b_char=fgetc(file);
138         char m_char=fgetc(file);
139
140         if(b_char!='B' || m_char!='M')
141         {
142                 if(cb)cb->error("bmp_mptr::GetFrame(): "+strprintf(_("%s is not in BMP format"),filename.c_str()));
143                 else synfig::error("bmp_mptr::GetFrame(): "+strprintf(_("%s is not in BMP format"),filename.c_str()));
144                 return false;
145         }
146
147         if(fread(&fileheader.bfSize, 1, sizeof(BITMAPFILEHEADER)-4, file)!=sizeof(BITMAPFILEHEADER)-4)
148         {
149                 String str("bmp_mptr::get_frame(): "+strprintf(_("Failure while reading BITMAPFILEHEADER from %s"),filename.c_str()));
150                 if(cb)cb->error(str);
151                 else synfig::error(str);
152                 return false;
153         }
154
155         if(fread(&infoheader, 1, sizeof(BITMAPINFOHEADER), file)!=sizeof(BITMAPINFOHEADER))
156         {
157                 String str("bmp_mptr::get_frame(): "+strprintf(_("Failure while reading BITMAPINFOHEADER from %s"),filename.c_str()));
158                 if(cb)cb->error(str);
159                 else synfig::error(str);
160                 return false;
161         }
162
163         int offset=little_endian(fileheader.bfOffsetBits);
164
165         if(offset!=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)-2)
166         {
167                 String str("bmp_mptr::get_frame(): "+strprintf(_("Bad BITMAPFILEHEADER in %s. (bfOffsetBits=%d, should be %d)"),filename.c_str(),offset,sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)-2));
168                 if(cb)cb->error(str);
169                 else synfig::error(str);
170                 return false;
171         }
172
173         if(little_endian(infoheader.biSize)!=little_endian(40))
174         {
175                 String str("bmp_mptr::get_frame(): "+strprintf(_("Bad BITMAPINFOHEADER in %s. (biSize=%d, should be 40)"),filename.c_str(),little_endian(infoheader.biSize)));
176                 if(cb)cb->error(str);
177                 else synfig::error(str);
178                 return false;
179         }
180
181         int w,h,bit_count;
182
183         w=little_endian(infoheader.biWidth);
184         h=little_endian(infoheader.biHeight);
185         bit_count=little_endian_short(infoheader.biBitCount);
186
187         synfig::warning("w:%d\n",w);
188         synfig::warning("h:%d\n",h);
189         synfig::warning("bit_count:%d\n",bit_count);
190
191         if(little_endian(infoheader.biCompression))
192         {
193                 if(cb)cb->error("bmp_mptr::GetFrame(): "+string(_("Reading compressed bitmaps is not supported")));
194                 else synfig::error("bmp_mptr::GetFrame(): "+string(_("Reading compressed bitmaps is not supported")));
195                 return false;
196         }
197
198         if(bit_count!=24 && bit_count!=32)
199         {
200                 if(cb)cb->error("bmp_mptr::GetFrame(): "+strprintf(_("Unsupported bit depth (bit_count=%d, should be 24 or 32)"),bit_count));
201                 else synfig::error("bmp_mptr::GetFrame(): "+strprintf(_("Unsupported bit depth (bit_count=%d, should be 24 or 32)"),bit_count));
202                 return false;
203         }
204
205         int x;
206         int y;
207         surface.set_wh(w,h);
208         for(y=0;y<surface.get_h();y++)
209                 for(x=0;x<surface.get_w();x++)
210                 {
211 //                      float b=(float)(unsigned char)fgetc(file)*(1.0/255.0);
212 //                      float g=(float)(unsigned char)fgetc(file)*(1.0/255.0);
213 //                      float r=(float)(unsigned char)fgetc(file)*(1.0/255.0);
214                         float b=gamma().b_U8_to_F32((unsigned char)fgetc(file));
215                         float g=gamma().g_U8_to_F32((unsigned char)fgetc(file));
216                         float r=gamma().r_U8_to_F32((unsigned char)fgetc(file));
217
218                         surface[h-y-1][x]=Color(
219                                 r,
220                                 g,
221                                 b,
222                                 1.0
223                         );
224                         if(bit_count==32)
225                                 fgetc(file);
226                 }
227
228
229         fclose(file);
230         return true;
231 }
232