]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-ico.c
Include "config.h" instead of <config.h> Command used: find -name
[~andy/gtk] / gdk-pixbuf / io-ico.c
1 /* -*- mode: C; c-file-style: "linux" -*- */
2 /* GdkPixbuf library - Windows Icon/Cursor image loader
3  *
4  * Copyright (C) 1999 The Free Software Foundation
5  *
6  * Authors: Arjan van de Ven <arjan@fenrus.demon.nl>
7  *          Federico Mena-Quintero <federico@gimp.org>
8  *
9  * Based on io-bmp.c
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2 of the License, or (at your option) any later version.
15  *
16  * This library 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  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the
23  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24  * Boston, MA 02111-1307, USA.
25  */
26
27 #undef DUMPBIH
28 /*
29
30 Icons are just like BMP's, except for the header.
31  
32 Known bugs:
33         * bi-tonal files aren't tested 
34
35 */
36
37 #include "config.h"
38 #include <stdio.h>
39 #include <stdlib.h>
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #include <string.h>
44 #include "gdk-pixbuf-private.h"
45 #include "gdk-pixbuf-io.h"
46 #include <errno.h>
47
48 \f
49
50 /* 
51
52 These structures are actually dummies. These are according to
53 the "Windows API reference guide volume II" as written by 
54 Borland International, but GCC fiddles with the alignment of
55 the internal members.
56
57 */
58
59 struct BitmapFileHeader {
60         gushort bfType;
61         guint bfSize;
62         guint reserverd;
63         guint bfOffbits;
64 };
65
66 struct BitmapInfoHeader {
67         guint biSize;
68         guint biWidth;
69         guint biHeight;
70         gushort biPlanes;
71         gushort biBitCount;
72         guint biCompression;
73         guint biSizeImage;
74         guint biXPelsPerMeter;
75         guint biYPelsPerMeter;
76         guint biClrUsed;
77         guint biClrImportant;
78 };
79
80 #ifdef DUMPBIH
81 /* 
82
83 DumpBIH printf's the values in a BitmapInfoHeader to the screen, for 
84 debugging purposes.
85
86 */
87 static void DumpBIH(unsigned char *BIH)
88 {                               
89         printf("biSize      = %i \n",
90                (int)(BIH[3] << 24) + (BIH[2] << 16) + (BIH[1] << 8) + (BIH[0]));
91         printf("biWidth     = %i \n",
92                (int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]));
93         printf("biHeight    = %i \n",
94                (int)(BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) +
95                (BIH[8]));
96         printf("biPlanes    = %i \n", (int)(BIH[13] << 8) + (BIH[12]));
97         printf("biBitCount  = %i \n", (int)(BIH[15] << 8) + (BIH[14]));
98         printf("biCompress  = %i \n",
99                (int)(BIH[19] << 24) + (BIH[18] << 16) + (BIH[17] << 8) +
100                (BIH[16]));
101         printf("biSizeImage = %i \n",
102                (int)(BIH[23] << 24) + (BIH[22] << 16) + (BIH[21] << 8) +
103                (BIH[20]));
104         printf("biXPels     = %i \n",
105                (int)(BIH[27] << 24) + (BIH[26] << 16) + (BIH[25] << 8) +
106                (BIH[24]));
107         printf("biYPels     = %i \n",
108                (int)(BIH[31] << 24) + (BIH[30] << 16) + (BIH[29] << 8) +
109                (BIH[28]));
110         printf("biClrUsed   = %i \n",
111                (int)(BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) +
112                (BIH[32]));
113         printf("biClrImprtnt= %i \n",
114                (int)(BIH[39] << 24) + (BIH[38] << 16) + (BIH[37] << 8) +
115                (BIH[36]));
116 }
117 #endif
118
119 /* Progressive loading */
120 struct headerpair {
121         gint width;
122         gint height;
123         guint depth;
124         guint Negative;         /* Negative = 1 -> top down BMP,  
125                                    Negative = 0 -> bottom up BMP */
126 };
127
128 struct ico_progressive_state {
129         GdkPixbufModuleSizeFunc size_func;
130         GdkPixbufModulePreparedFunc prepared_func;
131         GdkPixbufModuleUpdatedFunc updated_func;
132         gpointer user_data;
133
134         gint HeaderSize;        /* The size of the header-part (incl colormap) */
135         guchar *HeaderBuf;      /* The buffer for the header (incl colormap) */
136         gint BytesInHeaderBuf;  /* The size of the allocated HeaderBuf */
137         gint HeaderDone;        /* The nr of bytes actually in HeaderBuf */
138
139         gint LineWidth;         /* The width of a line in bytes */
140         guchar *LineBuf;        /* Buffer for 1 line */
141         gint LineDone;          /* # of bytes in LineBuf */
142         gint Lines;             /* # of finished lines */
143
144         gint Type;              /*  
145                                    32 = RGBA
146                                    24 = RGB
147                                    16 = 555 RGB
148                                    8 = 8 bit colormapped
149                                    4 = 4 bpp colormapped
150                                    1  = 1 bit bitonal 
151                                  */
152         gboolean cursor;
153         gint x_hot;
154         gint y_hot;
155
156         struct headerpair Header;       /* Decoded (BE->CPU) header */
157         
158         gint                    DIBoffset;
159         gint                    ImageScore;
160
161
162         GdkPixbuf *pixbuf;      /* Our "target" */
163 };
164
165 static gpointer
166 gdk_pixbuf__ico_image_begin_load(GdkPixbufModuleSizeFunc size_func,
167                                  GdkPixbufModulePreparedFunc prepared_func,
168                                  GdkPixbufModuleUpdatedFunc updated_func,
169                                  gpointer user_data,
170                                  GError **error);
171 static gboolean gdk_pixbuf__ico_image_stop_load(gpointer data, GError **error);
172 static gboolean gdk_pixbuf__ico_image_load_increment(gpointer data,
173                                                      const guchar * buf, guint size,
174                                                      GError **error);
175
176 static void 
177 context_free (struct ico_progressive_state *context)
178 {
179         g_free (context->LineBuf);
180         context->LineBuf = NULL;
181         g_free (context->HeaderBuf);
182
183         if (context->pixbuf)
184                 g_object_unref (context->pixbuf);
185
186         g_free (context);
187 }
188
189 static void DecodeHeader(guchar *Data, gint Bytes,
190                          struct ico_progressive_state *State,
191                          GError **error)
192 {
193 /* For ICO's we have to be very clever. There are multiple images possible
194    in an .ICO. As a simple heuristic, we select the image which occupies the 
195    largest number of bytes.
196  */   
197  
198         gint IconCount = 0; /* The number of icon-versions in the file */
199         guchar *BIH; /* The DIB for the used icon */
200         guchar *Ptr;
201         gint I;
202         guint16 imgtype; /* 1 = icon, 2 = cursor */
203  
204         /* Step 1: The ICO header */
205
206         /* First word should be 0 according to specs */
207         if (((Data[1] << 8) + Data[0]) != 0) {
208                 g_set_error_literal (error,
209                                      GDK_PIXBUF_ERROR,
210                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
211                                      _("Invalid header in icon"));
212                 return;
213
214         }
215
216         imgtype = (Data[3] << 8) + Data[2];
217
218         State->cursor = (imgtype == 2) ? TRUE : FALSE;
219
220         /* If it is not a cursor make sure it is actually an icon */
221         if (!State->cursor && imgtype != 1) {
222                 g_set_error_literal (error,
223                                      GDK_PIXBUF_ERROR,
224                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
225                                      _("Invalid header in icon"));
226                 return;
227         }
228
229
230         IconCount = (Data[5] << 8) + (Data[4]);
231         
232         State->HeaderSize = 6 + IconCount*16;
233
234         if (State->HeaderSize>State->BytesInHeaderBuf) {
235                 guchar *tmp=g_try_realloc(State->HeaderBuf,State->HeaderSize);
236                 if (!tmp) {
237                         g_set_error_literal (error,
238                                              GDK_PIXBUF_ERROR,
239                                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
240                                              _("Not enough memory to load icon"));
241                         return;
242                 }
243                 State->HeaderBuf = tmp;
244                 State->BytesInHeaderBuf = State->HeaderSize;
245         }
246         if (Bytes < State->HeaderSize)
247                 return;
248         
249         /* We now have all the "short-specs" of the versions 
250            So we iterate through them and select the best one */
251            
252         State->ImageScore = 0;
253         State->DIBoffset  = 0;
254         Ptr = Data + 6;
255         for (I=0;I<IconCount;I++) {
256                 int ThisScore;
257                 
258                 ThisScore = (Ptr[11] << 24) + (Ptr[10] << 16) + (Ptr[9] << 8) + (Ptr[8]);
259
260                 if (ThisScore>=State->ImageScore) {
261                         State->ImageScore = ThisScore;
262                         State->x_hot = (Ptr[5] << 8) + Ptr[4];
263                         State->y_hot = (Ptr[7] << 8) + Ptr[6];
264                         State->DIBoffset = (Ptr[15]<<24)+(Ptr[14]<<16)+
265                                            (Ptr[13]<<8) + (Ptr[12]);
266                                                                  
267                 }
268                 
269                 
270                 Ptr += 16;      
271         } 
272
273         if (State->DIBoffset < 0) {
274                 g_set_error_literal (error,
275                                      GDK_PIXBUF_ERROR,
276                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
277                                      _("Invalid header in icon"));
278                 return;
279         }
280
281         /* We now have a winner, pointed to in State->DIBoffset,
282            so we know how many bytes are in the "header" part. */
283               
284         State->HeaderSize = State->DIBoffset + 40; /* 40 = sizeof(InfoHeader) */
285
286         if (State->HeaderSize < 0) {
287                 g_set_error_literal (error,
288                                      GDK_PIXBUF_ERROR,
289                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
290                                      _("Invalid header in icon"));
291                 return;
292         }
293
294         if (State->HeaderSize>State->BytesInHeaderBuf) {
295                 guchar *tmp=g_try_realloc(State->HeaderBuf,State->HeaderSize);
296                 if (!tmp) {
297                         g_set_error_literal (error,
298                                              GDK_PIXBUF_ERROR,
299                                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
300                                              _("Not enough memory to load icon"));
301                         return;
302                 }
303                 State->HeaderBuf = tmp;
304                 State->BytesInHeaderBuf = State->HeaderSize;
305         }
306         if (Bytes<State->HeaderSize) 
307                 return;   
308         
309         BIH = Data+State->DIBoffset;
310
311 #ifdef DUMPBIH
312         DumpBIH(BIH);
313 #endif  
314         /* Add the palette to the headersize */
315                 
316         State->Header.width =
317             (int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]);
318         if (State->Header.width == 0) {
319                 g_set_error_literal (error,
320                                      GDK_PIXBUF_ERROR,
321                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
322                                      _("Icon has zero width"));
323                 return;
324         }
325         State->Header.height =
326             (int)((BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) + (BIH[8]))/2;
327             /* /2 because the BIH height includes the transparency mask */
328         if (State->Header.height == 0) {
329                 g_set_error_literal (error,
330                                      GDK_PIXBUF_ERROR,
331                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
332                                      _("Icon has zero height"));
333                 return;
334         }
335         State->Header.depth = (BIH[15] << 8) + (BIH[14]);
336
337         State->Type = State->Header.depth;      
338         if (State->Lines>=State->Header.height)
339                 State->Type = 1; /* The transparency mask is 1 bpp */
340         
341         /* Determine the  palette size. If the header indicates 0, it
342            is actually the maximum for the bpp. You have to love the
343            guys who made the spec. */
344         I = (int)(BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) + (BIH[32]);
345         I = I*4;
346         if ((I==0)&&(State->Type==1))
347                 I = 2*4;
348         if ((I==0)&&(State->Type==4))
349                 I = 16*4;
350         if ((I==0)&&(State->Type==8))
351                 I = 256*4;
352         
353         State->HeaderSize+=I;
354         
355         if (State->HeaderSize < 0) {
356                 g_set_error_literal (error,
357                                      GDK_PIXBUF_ERROR,
358                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
359                                      _("Invalid header in icon"));
360                 return;
361         }
362
363         if (State->HeaderSize>State->BytesInHeaderBuf) {
364                 guchar *tmp=g_try_realloc(State->HeaderBuf,State->HeaderSize);
365                 if (!tmp) {
366                         g_set_error_literal (error,
367                                              GDK_PIXBUF_ERROR,
368                                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
369                                              _("Not enough memory to load icon"));
370                         return;
371                 }
372                 State->HeaderBuf = tmp;
373                 State->BytesInHeaderBuf = State->HeaderSize;
374         }
375         if (Bytes < State->HeaderSize)
376                 return;
377
378         if ((BIH[16] != 0) || (BIH[17] != 0) || (BIH[18] != 0)
379             || (BIH[19] != 0)) {
380                 /* FIXME: is this the correct message? */
381                 g_set_error_literal (error,
382                                      GDK_PIXBUF_ERROR,
383                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
384                                      _("Compressed icons are not supported"));
385                 return;
386         }
387
388         /* Negative heights mean top-down pixel-order */
389         if (State->Header.height < 0) {
390                 State->Header.height = -State->Header.height;
391                 State->Header.Negative = 1;
392         }
393         if (State->Header.width < 0) {
394                 State->Header.width = -State->Header.width;
395         }
396         g_assert (State->Header.width > 0);
397         g_assert (State->Header.height > 0);
398
399         if (State->Type == 32)
400                 State->LineWidth = State->Header.width * 4;
401         else if (State->Type == 24)
402                 State->LineWidth = State->Header.width * 3;
403         else if (State->Type == 16)
404                 State->LineWidth = State->Header.width * 2;
405         else if (State->Type == 8)
406                 State->LineWidth = State->Header.width * 1;
407         else if (State->Type == 4)
408                 State->LineWidth = (State->Header.width+1)/2;
409         else if (State->Type == 1) {
410                 State->LineWidth = State->Header.width / 8;
411                 if ((State->Header.width & 7) != 0)
412                         State->LineWidth++;
413         } else {
414           g_set_error_literal (error,
415                                GDK_PIXBUF_ERROR,
416                                GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
417                                _("Unsupported icon type"));
418           return;
419         }
420
421         /* Pad to a 32 bit boundary */
422         if (((State->LineWidth % 4) > 0))
423                 State->LineWidth = (State->LineWidth / 4) * 4 + 4;
424
425
426         if (State->LineBuf == NULL) {
427                 State->LineBuf = g_try_malloc(State->LineWidth);
428                 if (!State->LineBuf) {
429                         g_set_error_literal (error,
430                                              GDK_PIXBUF_ERROR,
431                                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
432                                              _("Not enough memory to load icon"));
433                         return;
434                 }
435         }
436
437         g_assert(State->LineBuf != NULL);
438
439
440         if (State->pixbuf == NULL) {
441 #if 1
442                 if (State->size_func) {
443                         gint width = State->Header.width;
444                         gint height = State->Header.height;
445
446                         (*State->size_func) (&width, &height, State->user_data);
447                         if (width == 0 || height == 0) {
448                                 State->LineWidth = 0;
449                                 return;
450                         }
451                 }
452 #endif
453
454                 State->pixbuf =
455                     gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
456                                    State->Header.width,
457                                    State->Header.height);
458                 if (!State->pixbuf) {
459                         g_set_error_literal (error,
460                                              GDK_PIXBUF_ERROR,
461                                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
462                                              _("Not enough memory to load icon"));
463                         return;
464                 }
465                 if (State->cursor) {
466                         gchar hot[10];
467                         g_snprintf (hot, 10, "%d", State->x_hot);
468                         gdk_pixbuf_set_option (State->pixbuf, "x_hot", hot);
469                         g_snprintf (hot, 10, "%d", State->y_hot);
470                         gdk_pixbuf_set_option (State->pixbuf, "y_hot", hot);
471                 }
472
473                 if (State->prepared_func != NULL)
474                         /* Notify the client that we are ready to go */
475                         (*State->prepared_func) (State->pixbuf,
476                                                  NULL,
477                                                  State->user_data);
478
479         }
480
481 }
482
483 /* 
484  * func - called when we have pixmap created (but no image data)
485  * user_data - passed as arg 1 to func
486  * return context (opaque to user)
487  */
488
489 static gpointer
490 gdk_pixbuf__ico_image_begin_load(GdkPixbufModuleSizeFunc size_func,
491                                  GdkPixbufModulePreparedFunc prepared_func,
492                                  GdkPixbufModuleUpdatedFunc updated_func,
493                                  gpointer user_data,
494                                  GError **error)
495 {
496         struct ico_progressive_state *context;
497
498         context = g_new0(struct ico_progressive_state, 1);
499         context->size_func = size_func;
500         context->prepared_func = prepared_func;
501         context->updated_func = updated_func;
502         context->user_data = user_data;
503
504         context->HeaderSize = 54;
505         context->HeaderBuf = g_try_malloc(14 + 40 + 4*256 + 512);
506         if (!context->HeaderBuf) {
507                 g_free (context);
508                 g_set_error_literal (error,
509                                      GDK_PIXBUF_ERROR,
510                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
511                                      _("Not enough memory to load ICO file"));
512                 return NULL;
513         }
514         /* 4*256 for the colormap */
515         context->BytesInHeaderBuf = 14 + 40 + 4*256 + 512 ;
516         context->HeaderDone = 0;
517
518         context->LineWidth = 0;
519         context->LineBuf = NULL;
520         context->LineDone = 0;
521         context->Lines = 0;
522
523         context->Type = 0;
524
525         memset(&context->Header, 0, sizeof(struct headerpair));
526
527
528         context->pixbuf = NULL;
529
530
531         return (gpointer) context;
532 }
533
534 /*
535  * context - returned from image_begin_load
536  *
537  * free context, unref gdk_pixbuf
538  */
539 static gboolean 
540 gdk_pixbuf__ico_image_stop_load(gpointer data,
541                                 GError **error)
542 {
543         struct ico_progressive_state *context =
544             (struct ico_progressive_state *) data;
545
546         /* FIXME this thing needs to report errors if
547          * we have unused image data
548          */
549
550         g_return_val_if_fail(context != NULL, TRUE);
551
552         context_free (context);
553         return TRUE;
554 }
555
556 static void
557 OneLine32 (struct ico_progressive_state *context)
558 {
559         gint X;
560         guchar *Pixels;
561
562         X = 0;
563         if (context->Header.Negative == 0)
564                 Pixels = (context->pixbuf->pixels +
565                           context->pixbuf->rowstride *
566                           (context->Header.height - context->Lines - 1));
567         else
568                 Pixels = (context->pixbuf->pixels +
569                           context->pixbuf->rowstride *
570                           context->Lines);
571         while (X < context->Header.width) {
572                 Pixels[X * 4 + 0] = context->LineBuf[X * 4 + 2];
573                 Pixels[X * 4 + 1] = context->LineBuf[X * 4 + 1];
574                 Pixels[X * 4 + 2] = context->LineBuf[X * 4 + 0];
575                 Pixels[X * 4 + 3] = context->LineBuf[X * 4 + 3];
576                 X++;
577         }
578 }
579
580 static void OneLine24(struct ico_progressive_state *context)
581 {
582         gint X;
583         guchar *Pixels;
584
585         X = 0;
586         if (context->Header.Negative == 0)
587                 Pixels = (context->pixbuf->pixels +
588                           context->pixbuf->rowstride *
589                           (context->Header.height - context->Lines - 1));
590         else
591                 Pixels = (context->pixbuf->pixels +
592                           context->pixbuf->rowstride *
593                           context->Lines);
594         while (X < context->Header.width) {
595                 Pixels[X * 4 + 0] = context->LineBuf[X * 3 + 2];
596                 Pixels[X * 4 + 1] = context->LineBuf[X * 3 + 1];
597                 Pixels[X * 4 + 2] = context->LineBuf[X * 3 + 0];
598                 X++;
599         }
600
601 }
602
603 static void
604 OneLine16 (struct ico_progressive_state *context)
605 {
606         int i;
607         guchar *pixels;
608         guchar *src;
609
610         if (context->Header.Negative == 0)
611                 pixels = (context->pixbuf->pixels +
612                           context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
613         else
614                 pixels = (context->pixbuf->pixels +
615                           context->pixbuf->rowstride * context->Lines);
616
617         src = context->LineBuf;
618
619         for (i = 0; i < context->Header.width; i++) {
620                 int v, r, g, b;
621
622                 v = (int) src[0] | ((int) src[1] << 8);
623                 src += 2;
624
625                 /* Extract 5-bit RGB values */
626
627                 r = (v >> 10) & 0x1f;
628                 g = (v >> 5) & 0x1f;
629                 b = v & 0x1f;
630
631                 /* Fill the rightmost bits to form 8-bit values */
632
633                 *pixels++ = (r << 3) | (r >> 2);
634                 *pixels++ = (g << 3) | (g >> 2);
635                 *pixels++ = (b << 3) | (b >> 2);
636                 pixels++; /* skip alpha channel */
637         }
638 }
639
640
641 static void OneLine8(struct ico_progressive_state *context)
642 {
643         gint X;
644         guchar *Pixels;
645
646         X = 0;
647         if (context->Header.Negative == 0)
648                 Pixels = (context->pixbuf->pixels +
649                           context->pixbuf->rowstride *
650                           (context->Header.height - context->Lines - 1));
651         else
652                 Pixels = (context->pixbuf->pixels +
653                           context->pixbuf->rowstride *
654                           context->Lines);
655         while (X < context->Header.width) {
656                 /* The joys of having a BGR byteorder */
657                 Pixels[X * 4 + 0] =
658                     context->HeaderBuf[4 * context->LineBuf[X] + 42+context->DIBoffset];
659                 Pixels[X * 4 + 1] =
660                     context->HeaderBuf[4 * context->LineBuf[X] + 41+context->DIBoffset];
661                 Pixels[X * 4 + 2] =
662                     context->HeaderBuf[4 * context->LineBuf[X] + 40+context->DIBoffset];
663                 X++;
664         }
665 }
666 static void OneLine4(struct ico_progressive_state *context)
667 {
668         gint X;
669         guchar *Pixels;
670
671         X = 0;
672         if (context->Header.Negative == 0)
673                 Pixels = (context->pixbuf->pixels +
674                           context->pixbuf->rowstride *
675                           (context->Header.height - context->Lines - 1));
676         else
677                 Pixels = (context->pixbuf->pixels +
678                           context->pixbuf->rowstride *
679                           context->Lines);
680         
681         while (X < context->Header.width) {
682                 guchar Pix;
683                 
684                 Pix = context->LineBuf[X/2];
685
686                 Pixels[X * 4 + 0] =
687                     context->HeaderBuf[4 * (Pix>>4) + 42+context->DIBoffset];
688                 Pixels[X * 4 + 1] =
689                     context->HeaderBuf[4 * (Pix>>4) + 41+context->DIBoffset];
690                 Pixels[X * 4 + 2] =
691                     context->HeaderBuf[4 * (Pix>>4) + 40+context->DIBoffset];
692                 X++;
693                 if (X<context->Header.width) { 
694                         /* Handle the other 4 bit pixel only when there is one */
695                         Pixels[X * 4 + 0] =
696                             context->HeaderBuf[4 * (Pix&15) + 42+context->DIBoffset];
697                         Pixels[X * 4 + 1] =
698                             context->HeaderBuf[4 * (Pix&15) + 41+context->DIBoffset];
699                         Pixels[X * 4 + 2] =
700                             context->HeaderBuf[4 * (Pix&15) + 40+context->DIBoffset];
701                         X++;
702                 }
703         }
704         
705 }
706
707 static void OneLine1(struct ico_progressive_state *context)
708 {
709         gint X;
710         guchar *Pixels;
711
712         X = 0;
713         if (context->Header.Negative == 0)
714                 Pixels = (context->pixbuf->pixels +
715                           context->pixbuf->rowstride *
716                           (context->Header.height - context->Lines - 1));
717         else
718                 Pixels = (context->pixbuf->pixels +
719                           context->pixbuf->rowstride *
720                           context->Lines);
721         while (X < context->Header.width) {
722                 int Bit;
723
724                 Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7));
725                 Bit = Bit & 1;
726                 /* The joys of having a BGR byteorder */
727                 Pixels[X * 4 + 0] = Bit*255;
728                 Pixels[X * 4 + 1] = Bit*255;
729                 Pixels[X * 4 + 2] = Bit*255;
730                 X++;
731         }
732 }
733
734 static void OneLineTransp(struct ico_progressive_state *context)
735 {
736         gint X;
737         guchar *Pixels;
738
739         /* Ignore the XOR mask for XP style 32-bpp icons with alpha */ 
740         if (context->Header.depth == 32)
741                 return;
742
743         X = 0;
744         if (context->Header.Negative == 0)
745                 Pixels = (context->pixbuf->pixels +
746                           context->pixbuf->rowstride *
747                           (2*context->Header.height - context->Lines - 1));
748         else
749                 Pixels = (context->pixbuf->pixels +
750                           context->pixbuf->rowstride *
751                           (context->Lines-context->Header.height));
752         while (X < context->Header.width) {
753                 int Bit;
754
755                 Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7));
756                 Bit = Bit & 1;
757                 /* The joys of having a BGR byteorder */
758                 Pixels[X * 4 + 3] = 255-Bit*255;
759 #if 0
760                 if (Bit){
761                   Pixels[X*4+0] = 255;
762                   Pixels[X*4+1] = 255;
763                 } else {
764                   Pixels[X*4+0] = 0;
765                   Pixels[X*4+1] = 0;
766                 }
767 #endif          
768                 X++;
769         }
770 }
771
772
773 static void OneLine(struct ico_progressive_state *context)
774 {
775         context->LineDone = 0;
776         
777         if (context->Lines >= context->Header.height*2) {
778                 return;
779         }
780                 
781         if (context->Lines <context->Header.height) {           
782                 if (context->Type == 32)
783                         OneLine32 (context);
784                 else if (context->Type == 24)
785                         OneLine24(context);
786                 else if (context->Type == 16)
787                         OneLine16 (context);
788                 else if (context->Type == 8)
789                         OneLine8(context);
790                 else if (context->Type == 4)
791                         OneLine4(context);
792                 else if (context->Type == 1)
793                         OneLine1(context);
794                 else 
795                         g_assert_not_reached ();
796         } else
797                 OneLineTransp(context);
798         
799         context->Lines++;
800         if (context->Lines>=context->Header.height) {
801                 context->Type = 1;
802                 context->LineWidth = context->Header.width / 8;
803                 if ((context->Header.width & 7) != 0)
804                         context->LineWidth++;
805                 /* Pad to a 32 bit boundary */
806                 if (((context->LineWidth % 4) > 0))
807                         context->LineWidth = (context->LineWidth / 4) * 4 + 4;
808                         
809         }
810           
811
812         if (context->updated_func != NULL) {
813                 (*context->updated_func) (context->pixbuf,
814                                           0,
815                                           context->Lines % context->Header.height,
816                                           context->Header.width,
817                                           1,
818                                           context->user_data);
819
820         }
821 }
822
823 /*
824  * context - from image_begin_load
825  * buf - new image data
826  * size - length of new image data
827  *
828  * append image data onto inrecrementally built output image
829  */
830 static gboolean
831 gdk_pixbuf__ico_image_load_increment(gpointer data,
832                                      const guchar * buf,
833                                      guint size,
834                                      GError **error)
835 {
836         struct ico_progressive_state *context =
837             (struct ico_progressive_state *) data;
838
839         gint BytesToCopy;
840
841         while (size > 0) {
842                 g_assert(context->LineDone >= 0);
843                 if (context->HeaderDone < context->HeaderSize) {        /* We still 
844                                                                            have headerbytes to do */
845                         BytesToCopy =
846                             context->HeaderSize - context->HeaderDone;
847                         if (BytesToCopy > size)
848                                 BytesToCopy = size;
849
850                         memmove(context->HeaderBuf + context->HeaderDone,
851                                buf, BytesToCopy);
852
853                         size -= BytesToCopy;
854                         buf += BytesToCopy;
855                         context->HeaderDone += BytesToCopy;
856                 } 
857                 else {
858                         BytesToCopy =
859                             context->LineWidth - context->LineDone;
860                         if (BytesToCopy > size)
861                                 BytesToCopy = size;
862
863                         if (BytesToCopy > 0) {
864                                 memmove(context->LineBuf +
865                                        context->LineDone, buf,
866                                        BytesToCopy);
867
868                                 size -= BytesToCopy;
869                                 buf += BytesToCopy;
870                                 context->LineDone += BytesToCopy;
871                         }
872                         if ((context->LineDone >= context->LineWidth) &&
873                             (context->LineWidth > 0))
874                                 OneLine(context);
875
876
877                 }
878
879                 if (context->HeaderDone >= 6 && context->pixbuf == NULL) {
880                         GError *decode_err = NULL;
881                         DecodeHeader(context->HeaderBuf,
882                                      context->HeaderDone, context, &decode_err);
883                         if (context->LineBuf != NULL && context->LineWidth == 0)
884                                 return TRUE;
885
886                         if (decode_err) {
887                                 g_propagate_error (error, decode_err);
888                                 return FALSE;
889                         }
890                 }
891         }
892
893         return TRUE;
894 }
895
896 /* saving ICOs */ 
897
898 static gint
899 write8 (FILE     *f,
900         guint8   *data,
901         gint      count)
902 {
903   gint bytes;
904   gint written;
905
906   written = 0;
907   while (count > 0)
908     {
909       bytes = fwrite ((char*) data, sizeof (char), count, f);
910       if (bytes <= 0)
911         break;
912       count -= bytes;
913       data += bytes;
914       written += bytes;
915     }
916
917   return written;
918 }
919
920 static gint
921 write16 (FILE     *f,
922          guint16  *data,
923          gint      count)
924 {
925   gint i;
926
927   for (i = 0; i < count; i++)
928           data[i] = GUINT16_TO_LE (data[i]);
929
930   return write8 (f, (guint8*) data, count * 2);
931 }
932
933 static gint
934 write32 (FILE     *f,
935          guint32  *data,
936          gint      count)
937 {
938   gint i;
939
940   for (i = 0; i < count; i++)
941           data[i] = GUINT32_TO_LE (data[i]);
942   
943   return write8 (f, (guint8*) data, count * 4);
944 }
945
946 typedef struct _IconEntry IconEntry;
947 struct _IconEntry {
948         gint width;
949         gint height;
950         gint depth;
951         gint hot_x;
952         gint hot_y;
953
954         guint8 n_colors;
955         guint32 *colors;
956         guint xor_rowstride;
957         guint8 *xor;
958         guint and_rowstride;
959         guint8 *and;
960 };
961
962 static gboolean
963 fill_entry (IconEntry *icon, 
964             GdkPixbuf *pixbuf, 
965             gint       hot_x, 
966             gint       hot_y, 
967             GError   **error) 
968  {
969         guchar *p, *pixels, *and, *xor;
970         gint n_channels, v, x, y;
971
972         if (icon->width > 255 || icon->height > 255) {
973                 g_set_error_literal (error,
974                                      GDK_PIXBUF_ERROR,
975                                      GDK_PIXBUF_ERROR_BAD_OPTION,
976                                      _("Image too large to be saved as ICO"));
977                 return FALSE;
978         } 
979         
980         if (hot_x > -1 && hot_y > -1) {
981                 icon->hot_x = hot_x;
982                 icon->hot_y = hot_y;
983                 if (icon->hot_x >= icon->width || icon->hot_y >= icon->height) {
984                         g_set_error_literal (error,
985                                              GDK_PIXBUF_ERROR,
986                                              GDK_PIXBUF_ERROR_BAD_OPTION,
987                                              _("Cursor hotspot outside image"));
988                         return FALSE;
989                 }
990         }
991         else {
992                 icon->hot_x = -1;
993                 icon->hot_y = -1;
994         }
995         
996         switch (icon->depth) {
997         case 32:
998                 icon->xor_rowstride = icon->width * 4;
999                 break;
1000         case 24:
1001                 icon->xor_rowstride = icon->width * 3;
1002                 break;
1003         case 16:
1004                 icon->xor_rowstride = icon->width * 2;
1005                 break;
1006         default:
1007                 g_set_error (error,
1008                              GDK_PIXBUF_ERROR,
1009                              GDK_PIXBUF_ERROR_BAD_OPTION,
1010                              _("Unsupported depth for ICO file: %d"), icon->depth);
1011                 return FALSE;
1012         }
1013
1014         if ((icon->xor_rowstride % 4) != 0)             
1015                 icon->xor_rowstride = 4 * ((icon->xor_rowstride / 4) + 1);
1016         icon->xor = g_new0 (guchar, icon->xor_rowstride * icon->height);
1017
1018         icon->and_rowstride = icon->width / 8;
1019         if ((icon->and_rowstride % 4) != 0)             
1020                 icon->and_rowstride = 4 * ((icon->and_rowstride / 4) + 1);
1021         icon->and = g_new0 (guchar, icon->and_rowstride * icon->height);
1022
1023         pixels = gdk_pixbuf_get_pixels (pixbuf);
1024         n_channels = gdk_pixbuf_get_n_channels (pixbuf);
1025         for (y = 0; y < icon->height; y++) {
1026                 p = pixels + gdk_pixbuf_get_rowstride (pixbuf) * (icon->height - 1 - y);
1027                 and = icon->and + icon->and_rowstride * y;
1028                 xor = icon->xor + icon->xor_rowstride * y;
1029                 for (x = 0; x < icon->width; x++) {
1030                         switch (icon->depth) {
1031                         case 32:
1032                                 xor[0] = p[2];
1033                                 xor[1] = p[1];
1034                                 xor[2] = p[0];
1035                                 xor[3] = 0xff;
1036                                 if (n_channels == 4) {
1037                                         xor[3] = p[3];
1038                                         if (p[3] < 0x80)
1039                                                 *and |= 1 << (7 - x % 8);
1040                                 }
1041                                 xor += 4;
1042                                 break;
1043                         case 24:
1044                                 xor[0] = p[2];
1045                                 xor[1] = p[1];
1046                                 xor[2] = p[0];
1047                                 if (n_channels == 4 && p[3] < 0x80)
1048                                         *and |= 1 << (7 - x % 8);
1049                                 xor += 3;
1050                                 break;
1051                         case 16:
1052                                 v = ((p[0] >> 3) << 10) | ((p[1] >> 3) << 5) | (p[2] >> 3);
1053                                 xor[0] = v & 0xff;
1054                                 xor[1] = v >> 8;
1055                                 if (n_channels == 4 && p[3] < 0x80)
1056                                         *and |= 1 << (7 - x % 8);
1057                                 xor += 2;
1058                                 break;
1059                         }
1060                         
1061                         p += n_channels;
1062                         if (x % 8 == 7) 
1063                                 and++;
1064                 }
1065         }
1066
1067         return TRUE;
1068 }
1069
1070 static void
1071 free_entry (IconEntry *icon)
1072 {
1073         g_free (icon->colors);
1074         g_free (icon->and);
1075         g_free (icon->xor);
1076         g_free (icon);
1077 }
1078
1079 static void
1080 write_icon (FILE *f, GSList *entries)
1081 {
1082         IconEntry *icon;
1083         GSList *entry;
1084         guint8 bytes[4];
1085         guint16 words[4];
1086         guint32 dwords[6];
1087         gint type;
1088         gint n_entries;
1089         gint offset;
1090         gint size;
1091
1092         if (((IconEntry *)entries->data)->hot_x > -1)
1093                 type = 2;
1094         else 
1095                 type = 1;
1096         n_entries = g_slist_length (entries);
1097
1098         /* header */
1099         words[0] = 0;
1100         words[1] = type;
1101         words[2] = n_entries;
1102         write16 (f, words, 3);
1103         
1104         offset = 6 + 16 * n_entries;
1105
1106         for (entry = entries; entry; entry = entry->next) {
1107                 icon = (IconEntry *)entry->data;
1108                 size = 40 + icon->height * (icon->and_rowstride + icon->xor_rowstride);
1109                 
1110                 /* directory entry */
1111                 bytes[0] = icon->width;
1112                 bytes[1] = icon->height;
1113                 bytes[2] = icon->n_colors;
1114                 bytes[3] = 0;
1115                 write8 (f, bytes, 4);
1116                 if (type == 1) {
1117                         words[0] = 1;
1118                         words[1] = icon->depth;
1119                 }
1120                 else {
1121                         words[0] = icon->hot_x;
1122                         words[1] = icon->hot_y;
1123                 }
1124                 write16 (f, words, 2);
1125                 dwords[0] = size;
1126                 dwords[1] = offset;
1127                 write32 (f, dwords, 2);
1128
1129                 offset += size;
1130         }
1131
1132         for (entry = entries; entry; entry = entry->next) {
1133                 icon = (IconEntry *)entry->data;
1134
1135                 /* bitmap header */
1136                 dwords[0] = 40;
1137                 dwords[1] = icon->width;
1138                 dwords[2] = icon->height * 2;
1139                 write32 (f, dwords, 3);
1140                 words[0] = 1;
1141                 words[1] = icon->depth;
1142                 write16 (f, words, 2);
1143                 dwords[0] = 0;
1144                 dwords[1] = 0;
1145                 dwords[2] = 0;
1146                 dwords[3] = 0;
1147                 dwords[4] = 0;
1148                 dwords[5] = 0;
1149                 write32 (f, dwords, 6);
1150
1151                 /* image data */
1152                 write8 (f, icon->xor, icon->xor_rowstride * icon->height);
1153                 write8 (f, icon->and, icon->and_rowstride * icon->height);
1154         }
1155 }
1156
1157 static gboolean
1158 gdk_pixbuf__ico_image_save (FILE          *f, 
1159                             GdkPixbuf     *pixbuf, 
1160                             gchar        **keys,
1161                             gchar        **values,
1162                             GError       **error)
1163 {
1164         gint hot_x, hot_y;
1165         IconEntry *icon;
1166         GSList *entries = NULL;
1167
1168         /* support only single-image ICOs for now */
1169         icon = g_new0 (IconEntry, 1);
1170         icon->width = gdk_pixbuf_get_width (pixbuf);
1171         icon->height = gdk_pixbuf_get_height (pixbuf);
1172         icon->depth = gdk_pixbuf_get_has_alpha (pixbuf) ? 32 : 24;
1173         hot_x = -1;
1174         hot_y = -1;
1175         
1176         /* parse options */
1177         if (keys && *keys) {
1178                 gchar **kiter;
1179                 gchar **viter;
1180                 
1181                 for (kiter = keys, viter = values; *kiter && *viter; kiter++, viter++) {
1182                         char *endptr;
1183                         if (strcmp (*kiter, "depth") == 0) {
1184                                 sscanf (*viter, "%d", &icon->depth);
1185                         }
1186                         else if (strcmp (*kiter, "x_hot") == 0) {
1187                                 hot_x = strtol (*viter, &endptr, 10);
1188                         }
1189                         else if (strcmp (*kiter, "y_hot") == 0) {
1190                                 hot_y = strtol (*viter, &endptr, 10);
1191                         }
1192
1193                 }
1194         }
1195
1196         if (!fill_entry (icon, pixbuf, hot_x, hot_y, error)) {
1197                 free_entry (icon);
1198                 return FALSE;
1199         }
1200
1201         entries = g_slist_append (entries, icon); 
1202         write_icon (f, entries);
1203
1204         g_slist_foreach (entries, (GFunc)free_entry, NULL);
1205         g_slist_free (entries);
1206
1207         return TRUE;
1208 }
1209
1210 #ifndef INCLUDE_ico
1211 #define MODULE_ENTRY(function) G_MODULE_EXPORT void function
1212 #else
1213 #define MODULE_ENTRY(function) void _gdk_pixbuf__ico_ ## function
1214 #endif
1215
1216 MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
1217 {
1218         module->begin_load = gdk_pixbuf__ico_image_begin_load;
1219         module->stop_load = gdk_pixbuf__ico_image_stop_load;
1220         module->load_increment = gdk_pixbuf__ico_image_load_increment;
1221         module->save = gdk_pixbuf__ico_image_save;
1222 }
1223
1224 MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
1225 {
1226         static GdkPixbufModulePattern signature[] = {
1227                 { "  \x1   ", "zz znz", 100 }, 
1228                 { "  \x2   ", "zz znz", 100 },
1229                 { NULL, NULL, 0 }
1230         };
1231         static gchar * mime_types[] = {
1232                 "image/x-icon",
1233                 "image/x-ico",
1234                 "image/x-win-bitmap",
1235                 NULL
1236         };
1237         static gchar * extensions[] = {
1238                 "ico",
1239                 "cur",
1240                 NULL
1241         };
1242
1243         info->name = "ico";
1244         info->signature = signature;
1245         info->description = N_("The ICO image format");
1246         info->mime_types = mime_types;
1247         info->extensions = extensions;
1248         info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE;
1249         info->license = "LGPL";
1250 }
1251
1252
1253
1254