Added my "Copyright (c) 2007" notices, for files I edited in 2007.
[synfig.git] / synfig-core / trunk / src / modules / mod_bmp / trgt_bmp.cpp
1 /* === S Y N F I G ========================================================= */
2 /*!     \file trgt_bmp.cpp
3 **      \brief Bitmap Target
4 **
5 **      $Id$
6 **
7 **      \legal
8 **      Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
9 **      Copyright (c) 2007 Chris Moore
10 **
11 **      This package is free software; you can redistribute it and/or
12 **      modify it under the terms of the GNU General Public License as
13 **      published by the Free Software Foundation; either version 2 of
14 **      the License, or (at your option) any later version.
15 **
16 **      This package is distributed in the hope that it will be useful,
17 **      but WITHOUT ANY WARRANTY; without even the implied warranty of
18 **      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 **      General Public License for more details.
20 **      \endlegal
21 */
22 /* ========================================================================= */
23
24 /* === H E A D E R S ======================================================= */
25
26 #define SYNFIG_NO_ANGLE
27
28 #ifdef USING_PCH
29 #       include "pch.h"
30 #else
31 #ifdef HAVE_CONFIG_H
32 #       include <config.h>
33 #endif
34
35 #include "trgt_bmp.h"
36 #include <synfig/general.h>
37
38 #include <cstdio>
39 #include <algorithm>
40 #include <functional>
41 #endif
42
43 /* === U S I N G =========================================================== */
44
45 using namespace synfig;
46 using namespace std;
47 using namespace etl;
48
49 /* === I N F O ============================================================= */
50
51 SYNFIG_TARGET_INIT(bmp);
52 SYNFIG_TARGET_SET_NAME(bmp,"bmp");
53 SYNFIG_TARGET_SET_EXT(bmp,"bmp");
54 SYNFIG_TARGET_SET_VERSION(bmp,"0.1");
55 SYNFIG_TARGET_SET_CVS_ID(bmp,"$Id$");
56
57 /* === C L A S S E S & S T R U C T S ======================================= */
58
59 struct BITMAPFILEHEADER
60 {
61         unsigned char   bfType[2];
62         unsigned long   bfSize;
63         unsigned short  bfReserved1;
64         unsigned short  bfReserved2;
65         unsigned long   bfOffsetBits;
66 };
67
68 struct BITMAPINFOHEADER
69 {
70         unsigned long   biSize;
71         long                    biWidth;
72         long                    biHeight;
73         unsigned short  biPlanes;
74         unsigned short  biBitCount;
75         unsigned long   biCompression;
76         unsigned long   biSizeImage;
77         long                    biXPelsPerMeter;
78         long                    biYPelsPerMeter;
79         unsigned long   biClrUsed;
80         unsigned long   biClrImportant;
81 };
82
83 /* === M E T H O D S ======================================================= */
84
85 #ifdef WORDS_BIGENDIAN
86 inline long little_endian(const long &x)
87 {
88         long ret;
89         char *big_e=(char *)&ret;
90         char *lit_e=(char *)&x;
91         big_e[0]=lit_e[3];
92         big_e[1]=lit_e[2];
93         big_e[2]=lit_e[1];
94         big_e[3]=lit_e[0];
95         return ret;
96 }
97 inline short little_endian_short(const short &x)
98 {
99         short ret;
100         char *big_e=(char *)&ret;
101         char *lit_e=(char *)&x;
102         big_e[0]=lit_e[1];
103         big_e[1]=lit_e[0];
104         return ret;
105 }
106 #else
107 #define little_endian(x)        (x)
108 #define little_endian_short(x)  (x)
109 #endif
110
111 bmp::bmp(const char *Filename)
112 {
113         file=NULL;
114         filename=Filename;
115         multi_image=false;
116         buffer=0;
117         color_buffer=0;
118         set_remove_alpha();
119
120 }
121
122 bmp::~bmp()
123 {
124         if(file)
125                 fclose(file);
126         file=NULL;
127         delete [] buffer;
128         delete [] color_buffer;
129 }
130
131 bool
132 bmp::set_rend_desc(RendDesc *given_desc)
133 {
134         pf=PF_BGR;
135
136     // Flip the image upside down,
137         // because bitmaps are upside down.
138     given_desc->set_flags(0);
139         Point tl=given_desc->get_tl();
140         Point br=given_desc->get_br();
141         Point::value_type tmp;
142         tmp=tl[1];
143         tl[1]=br[1];
144         br[1]=tmp;
145         given_desc->set_tl(tl);
146         given_desc->set_br(br);
147
148         desc=*given_desc;
149         if(desc.get_frame_end()-desc.get_frame_start()>0)
150         {
151                 multi_image=true;
152                 imagecount=desc.get_frame_start();
153         }
154         else
155                 multi_image=false;
156
157     return true;
158 }
159
160 void
161 bmp::end_frame()
162 {
163         if(file)
164                 fclose(file);
165         delete [] color_buffer;
166         color_buffer=0;
167         file=NULL;
168         imagecount++;
169 }
170
171 bool
172 bmp::start_frame(synfig::ProgressCallback *callback)
173 {
174         int w=desc.get_w(),h=desc.get_h();
175
176         rowspan=4*((w*(channels(pf)*8)+31)/32);
177         if(multi_image)
178         {
179                 String newfilename(filename_sans_extension(filename) +
180                                                    etl::strprintf(".%04d",imagecount) +
181                                                    filename_extension(filename));
182                 file=fopen(newfilename.c_str(),POPEN_BINARY_WRITE_TYPE);
183                 if(callback)callback->task(newfilename+_(" (animated)"));
184         }
185         else
186         {
187                 file=fopen(filename.c_str(),POPEN_BINARY_WRITE_TYPE);
188                 if(callback)callback->task(filename);
189         }
190
191         if(!file)
192         {
193                 if(callback)callback->error(_("Unable to open file"));
194                 else synfig::error(_("Unable to open file"));
195                 return false;
196         }
197
198         BITMAPFILEHEADER fileheader;
199         BITMAPINFOHEADER infoheader;
200
201         fileheader.bfType[0]='B';
202         fileheader.bfType[1]='M';
203         fileheader.bfSize=little_endian(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+rowspan*h);
204         fileheader.bfReserved1=0;
205         fileheader.bfReserved2=0;
206         fileheader.bfOffsetBits=little_endian(sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)-2);
207
208         infoheader.biSize=little_endian(40);
209         infoheader.biWidth=little_endian(w);
210         infoheader.biHeight=little_endian(h);
211         infoheader.biPlanes=little_endian_short((short)1);
212         infoheader.biBitCount=little_endian_short((short)(channels(pf)*8));
213         infoheader.biCompression=little_endian(0);
214         infoheader.biSizeImage=little_endian(0);
215         infoheader.biXPelsPerMeter=little_endian((int)rend_desc().get_x_res());
216         infoheader.biYPelsPerMeter=little_endian((int)rend_desc().get_y_res()); // pels per meter...?
217         infoheader.biClrUsed=little_endian(0);
218         infoheader.biClrImportant=little_endian(0);
219
220         fprintf(file,"BM");
221
222         if(!fwrite(&fileheader.bfSize,sizeof(BITMAPFILEHEADER)-4,1,file))
223         {
224                 if(callback)callback->error(_("Unable to write file header to file"));
225                 else synfig::error(_("Unable to write file header to file"));
226                 return false;
227         }
228
229         if(!fwrite(&infoheader,sizeof(BITMAPINFOHEADER),1,file))
230         {
231                 if(callback)callback->error(_("Unable to write info header"));
232                 else synfig::error(_("Unable to write info header"));
233                 return false;
234         }
235
236         delete [] buffer;
237         buffer=new unsigned char[rowspan];
238
239         delete [] color_buffer;
240         color_buffer=new Color[desc.get_w()];
241
242         return true;
243 }
244
245 Color *
246 bmp::start_scanline(int /*scanline*/)
247 {
248         return color_buffer;
249 }
250
251 bool
252 bmp::end_scanline()
253 {
254         if(!file)
255                 return false;
256
257         convert_color_format(buffer, color_buffer, desc.get_w(), pf, gamma());
258
259         if(!fwrite(buffer,1,rowspan,file))
260                 return false;
261
262         return true;
263 }