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