1 // MaCoPiX = Mascot Construnctive Pilot for X
2 // (ActX / Gtk+ Evolution)
3 //
4 //
5 // bmpwrite.c
6 // Read and write bmp image files
7 // originated from gimp-1.3 *** see below copyright ***
8 //
9 // Copyright 2002-2007 K.Chimari
10 // http://rosegray.sakura.ne.jp/
11 //
12 //
13 // This program is free software; you can redistribute it and/or modify
14 // it under the terms of the GNU General Public License as published by
15 // the Free Software Foundation; either version 2 of the License, or
16 // (at your option) any later version.
17 //
18 // This program is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 // GNU General Public License for more details.
22 //
23 // You should have received a copy of the GNU General Public License
24 // along with this program; if not, write to the Free Software
25 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 //
27
28
29 /* bmpwrite.c Writes Bitmap files. Even RLE encoded ones. */
30 /* (Windows (TM) doesn't read all of those, but who */
31 /* cares? ;-) */
32 /* I changed a few things over the time, so perhaps */
33 /* it dos now, but now there's no Windows left on */
34 /* my computer... */
35
36 /* Alexander.Schulz@stud.uni-karlsruhe.de */
37
38 /*
39 * The GIMP -- an image manipulation program
40 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
41 *
42 * This program is free software; you can redistribute it and/or modify
43 * it under the terms of the GNU General Public License as published by
44 * the Free Software Foundation; either version 2 of the License, or
45 * (at your option) any later version.
46 *
47 * This program is distributed in the hope that it will be useful,
48 * but WITHOUT ANY WARRANTY; without even the implied warranty of
49 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50 * GNU General Public License for more details.
51 *
52 * You should have received a copy of the GNU General Public License
53 * along with this program; if not, write to the Free Software
54 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
55 * ----------------------------------------------------------------------------
56 */
57 #include "main.h"
58 #include <stdio.h>
59
60 #include <gtk/gtk.h>
61 #include <gdk-pixbuf/gdk-pixbuf.h>
62
63 #include "bmp.h"
64
65 int
WriteBMP(const gchar * filename,GdkPixbuf * pbuf)66 WriteBMP (const gchar *filename,
67 GdkPixbuf *pbuf)
68 {
69 FILE *outfile;
70 gint Red[MAXCOLORS];
71 gint Green[MAXCOLORS];
72 gint Blue[MAXCOLORS];
73 gint rows, cols, Spcols, channels, MapSize, SpZeile;
74 glong BitsPerPixel;
75 gint colors;
76 guchar puffer[50];
77 gint encoded;
78 guchar *pixels;
79
80 /* first: can we save this image? */
81 pixels = (guchar *) gdk_pixbuf_get_pixels (pbuf) ;
82 colors = 0;
83 BitsPerPixel = 24;
84 MapSize = 0;
85 channels = 4;
86
87 /* Perhaps someone wants RLE encoded Bitmaps */
88 encoded = 0;
89
90 /* Let's take some file */
91 outfile = fopen (filename, "wb");
92 if (!outfile) {
93 g_message ("Can't open %s", filename);
94 return 0;
95 }
96
97 /* fetch the image */
98
99 /* Now, we need some further information ... */
100 cols = gdk_pixbuf_get_width (pbuf);
101 rows = gdk_pixbuf_get_height(pbuf);
102
103
104 /* ... that we write to our headers. */
105 Spcols = cols;
106
107 if ((((Spcols * BitsPerPixel) / 8) % 4) == 0) {
108 SpZeile = ((Spcols * BitsPerPixel) / 8);
109 } else {
110 SpZeile = ((gint) (((Spcols * BitsPerPixel) / 8) / 4) + 1) * 4;
111 }
112 Bitmap_File_Head.bfSize = 0x36 + MapSize + (rows * SpZeile);
113 Bitmap_File_Head.zzHotX = 0;
114 Bitmap_File_Head.zzHotY = 0;
115 Bitmap_File_Head.bfOffs = 0x36 + MapSize;
116 Bitmap_File_Head.biSize = 40;
117
118 Bitmap_Head.biWidth = cols;
119 Bitmap_Head.biHeight = rows;
120 Bitmap_Head.biPlanes = 1;
121 Bitmap_Head.biBitCnt = BitsPerPixel;
122
123 Bitmap_Head.biCompr = 0;
124 Bitmap_Head.biSizeIm = SpZeile * rows;
125
126 Bitmap_Head.biClrUsed = 0;
127 Bitmap_Head.biClrImp = Bitmap_Head.biClrUsed;
128
129 /* And now write the header and the colormap (if any) to disk */
130
131 Write (outfile, "BM", 2);
132
133 FromL (Bitmap_File_Head.bfSize, &puffer[0x00]);
134 FromS (Bitmap_File_Head.zzHotX, &puffer[0x04]);
135 FromS (Bitmap_File_Head.zzHotY, &puffer[0x06]);
136 FromL (Bitmap_File_Head.bfOffs, &puffer[0x08]);
137 FromL (Bitmap_File_Head.biSize, &puffer[0x0C]);
138
139 Write (outfile, puffer, 16);
140
141 FromL (Bitmap_Head.biWidth, &puffer[0x00]);
142 FromL (Bitmap_Head.biHeight, &puffer[0x04]);
143 FromS (Bitmap_Head.biPlanes, &puffer[0x08]);
144 FromS (Bitmap_Head.biBitCnt, &puffer[0x0A]);
145 FromL (Bitmap_Head.biCompr, &puffer[0x0C]);
146 FromL (Bitmap_Head.biSizeIm, &puffer[0x10]);
147 FromL (Bitmap_Head.biXPels, &puffer[0x14]);
148 FromL (Bitmap_Head.biYPels, &puffer[0x18]);
149 FromL (Bitmap_Head.biClrUsed, &puffer[0x1C]);
150 FromL (Bitmap_Head.biClrImp, &puffer[0x20]);
151
152 Write (outfile, puffer, 36);
153 WriteColorMap (outfile, Red, Green, Blue, MapSize);
154
155 /* After that is done, we write the image ... */
156
157 WriteImage (outfile,
158 pixels, cols, rows,
159 encoded, channels, BitsPerPixel, SpZeile, MapSize);
160
161 /* ... and exit normally */
162 fclose (outfile);
163
164 return 1;
165 }
166
167 void
WriteColorMap(FILE * f,gint red[MAXCOLORS],gint green[MAXCOLORS],gint blue[MAXCOLORS],gint size)168 WriteColorMap (FILE *f,
169 gint red[MAXCOLORS],
170 gint green[MAXCOLORS],
171 gint blue[MAXCOLORS],
172 gint size)
173 {
174 gchar trgb[4];
175 gint i;
176
177 size /= 4;
178 trgb[3] = 0;
179 for (i = 0; i < size; i++)
180 {
181 trgb[0] = (guchar) blue[i];
182 trgb[1] = (guchar) green[i];
183 trgb[2] = (guchar) red[i];
184 Write (f, trgb, 4);
185 }
186 }
187
188 void
WriteImage(FILE * f,guchar * src,gint width,gint height,gint encoded,gint channels,gint bpp,gint spzeile,gint MapSize)189 WriteImage (FILE *f,
190 guchar *src,
191 gint width,
192 gint height,
193 gint encoded,
194 gint channels,
195 gint bpp,
196 gint spzeile,
197 gint MapSize)
198 {
199 guchar buf[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0};
200 guchar puffer[8];
201 guchar *temp, v;
202 guchar *Zeile, *ketten;
203 gint xpos, ypos, i, j, rowstride, laenge, thiswidth;
204 gint breite, n, k;
205
206 xpos = 0;
207 rowstride = width * channels;
208
209 /* We'll begin with the 24 bit Bitmaps, they are easy :-) */
210
211 if (bpp == 24)
212 {
213 for (ypos = height - 1; ypos >= 0; ypos--) /* for each row */
214 {
215 for (i = 0; i < width; i++) /* for each pixel */
216 {
217 temp = src + (ypos * rowstride) + (xpos * channels);
218 buf[2] = (guchar) *temp;
219 temp++;
220 buf[1] = (guchar) *temp;
221 temp++;
222 buf[0] = (guchar) *temp;
223 xpos++;
224 Write (f, buf, 3);
225 }
226 Write (f, &buf[3], spzeile - (width * 3));
227 #if 0
228 cur_progress++;
229 if ((interactive_bmp) &&
230 ((cur_progress % 5) == 0))
231 gimp_progress_update ((gdouble) cur_progress /
232 (gdouble) max_progress);
233 #endif
234 xpos = 0;
235 }
236 }
237 else
238 {
239 switch (encoded) /* now it gets more difficult */
240 { /* uncompressed 1,4 and 8 bit */
241 case 0:
242 {
243 thiswidth = (width / (8 / bpp));
244 if (width % (8 / bpp))
245 thiswidth++;
246
247 for (ypos = height - 1; ypos >= 0; ypos--) /* for each row */
248 {
249 for (xpos = 0; xpos < width;) /* for each _byte_ */
250 {
251 v = 0;
252 for (i = 1;
253 (i <= (8 / bpp)) && (xpos < width);
254 i++, xpos++) /* for each pixel */
255 {
256 temp = src + (ypos * rowstride) + (xpos * channels);
257 v=v | ((guchar) *temp << (8 - (i * bpp)));
258 }
259 Write (f, &v, 1);
260 }
261 Write (f, &buf[3], spzeile - thiswidth);
262 xpos = 0;
263 #if 0
264 cur_progress++;
265 if ((interactive_bmp) &&
266 ((cur_progress % 5) == 0))
267 gimp_progress_update ((gdouble) cur_progress /
268 (gdouble) max_progress);
269 #endif
270 }
271 break;
272 }
273 default:
274 { /* Save RLE encoded file, quite difficult */
275 laenge = 0;
276 buf[12] = 0;
277 buf[13] = 1;
278 buf[14] = 0;
279 buf[15] = 0;
280 Zeile = (guchar *) g_malloc (width / (8 / bpp) + 10);
281 ketten = (guchar *) g_malloc (width / (8 / bpp) + 10);
282 for (ypos = height - 1; ypos >= 0; ypos--)
283 { /* each row separately */
284 /*printf("Line: %i\n",ypos); */
285 j = 0;
286 /* first copy the pixels to a buffer,
287 * making one byte from two 4bit pixels
288 */
289 for (xpos = 0; xpos < width;)
290 {
291 v = 0;
292 for (i = 1;
293 (i <= (8 / bpp)) && (xpos < width);
294 i++, xpos++)
295 { /* for each pixel */
296 temp = src + (ypos * rowstride) + (xpos * channels);
297 v = v | ((guchar) * temp << (8 - (i * bpp)));
298 }
299 Zeile[j++] = v;
300 }
301 breite = width / (8 / bpp);
302 if (width % (8 / bpp))
303 breite++;
304 /* then check for strings of equal bytes */
305 for (i = 0; i < breite;)
306 {
307 j = 0;
308 while ((i + j < breite) &&
309 (j < (255 / (8 / bpp))) &&
310 (Zeile[i + j] == Zeile[i]))
311 j++;
312
313 ketten[i] = j;
314 /*printf("%i:",ketten[i]); */
315 i += j;
316 }
317 /*printf("\n"); */
318
319 /* then write the strings and the other pixels to the file */
320 for (i = 0; i < breite;)
321 {
322 if (ketten[i] < 3)
323 /* strings of different pixels ... */
324 {
325 j = 0;
326 while ((i + j < breite) &&
327 (j < (255 / (8 / bpp))) &&
328 (ketten[i + j] < 3))
329 j += ketten[i + j];
330
331 /* this can only happen if j jumps over
332 * the end with a 2 in ketten[i+j]
333 */
334 if (j > (255 / (8 / bpp)))
335 j -= 2;
336 /* 00 01 and 00 02 are reserved */
337 if (j > 2)
338 {
339 Write (f, &buf[12], 1);
340 n = j * (8 / bpp);
341 if (n + i * (8 / bpp) > width)
342 n--;
343 Write (f, &n, 1);
344 laenge += 2;
345 Write (f, &Zeile[i], j);
346 /*printf("0.%i.",n); */
347 /*for (k=j;k;k--) printf("#"); */
348 laenge += j;
349 if ((j) % 2)
350 {
351 Write (f, &buf[12], 1);
352 laenge++;
353 /*printf("0"); */
354 }
355 /*printf("|"); */
356 }
357 else
358 {
359 for (k = i; k < i + j; k++)
360 {
361 n = (8 / bpp);
362 if (n + i * (8 / bpp) > width)
363 n--;
364 Write (f, &n, 1);
365 Write (f, &Zeile[k], 1);
366 /*printf("%i.#|",n); */
367 laenge += 2;
368 }
369 }
370 i += j;
371 }
372 else
373 /* strings of equal pixels */
374 {
375 n = ketten[i] * (8 / bpp);
376 if (n + i * (8 / bpp) > width)
377 n--;
378 Write (f, &n, 1);
379 Write (f, &Zeile[i], 1);
380 /*printf("%i.#|",n); */
381 i += ketten[i];
382 laenge += 2;
383 }
384 }
385 /*printf("\n"); */
386 Write (f, &buf[14], 2); /* End of row */
387 laenge += 2;
388 #if 0
389 cur_progress++;
390 if ((interactive_bmp) &&
391 ((cur_progress % 5) == 0))
392 gimp_progress_update ((gdouble) cur_progress /
393 (gdouble) max_progress);
394 #endif
395 }
396 fseek (f, -2, SEEK_CUR); /* Overwrite last End of row ... */
397 Write (f, &buf[12], 2); /* ... with End of file */
398
399 fseek (f, 0x22, SEEK_SET); /* Write length of image */
400 FromL (laenge, puffer);
401 Write (f, puffer, 4);
402 fseek (f, 0x02, SEEK_SET); /* Write length of file */
403 laenge += (0x36 + MapSize);
404 FromL (laenge, puffer);
405 Write (f, puffer, 4);
406 g_free (ketten);
407 g_free (Zeile);
408 break;
409 }
410 }
411 }
412 #if 0
413 if (interactive_bmp)
414 gimp_progress_update (1);
415 #endif
416 }
417
418 /* ********************************************************** bmpwrite.c *** */
419