]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-ico.c
Correct computation of image height. (OneLine): Correct update
[~andy/gtk] / gdk-pixbuf / io-ico.c
1 /* GdkPixbuf library - Windows Icon/Cursor image loader
2  *
3  * Copyright (C) 1999 The Free Software Foundation
4  *
5  * Authors: Arjan van de Ven <arjan@fenrus.demon.nl>
6  *          Federico Mena-Quintero <federico@gimp.org>
7  *
8  * Based on io-bmp.c
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library 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  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the
22  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */
25
26 #undef DUMPBIH
27 /*
28
29 Icons are just like BMP's, except for the header.
30  
31 Known bugs:
32         * bi-tonal files aren't tested 
33
34 */
35
36 #include <config.h>
37 #include <stdio.h>
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 #include <string.h>
42 #include "gdk-pixbuf-private.h"
43 #include "gdk-pixbuf-io.h"
44 #include <errno.h>
45
46 \f
47
48 /* 
49
50 These structures are actually dummies. These are according to
51 the "Windows API reference guide volume II" as written by 
52 Borland International, but GCC fiddles with the alignment of
53 the internal members.
54
55 */
56
57 struct BitmapFileHeader {
58         gushort bfType;
59         guint bfSize;
60         guint reserverd;
61         guint bfOffbits;
62 };
63
64 struct BitmapInfoHeader {
65         guint biSize;
66         guint biWidth;
67         guint biHeight;
68         gushort biPlanes;
69         gushort biBitCount;
70         guint biCompression;
71         guint biSizeImage;
72         guint biXPelsPerMeter;
73         guint biYPelsPerMeter;
74         guint biClrUsed;
75         guint biClrImportant;
76 };
77
78 #ifdef DUMPBIH
79 /* 
80
81 DumpBIH printf's the values in a BitmapInfoHeader to the screen, for 
82 debugging purposes.
83
84 */
85 static void DumpBIH(unsigned char *BIH)
86 {                               
87         printf("biSize      = %i \n",
88                (int)(BIH[3] << 24) + (BIH[2] << 16) + (BIH[1] << 8) + (BIH[0]));
89         printf("biWidth     = %i \n",
90                (int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]));
91         printf("biHeight    = %i \n",
92                (int)(BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) +
93                (BIH[8]));
94         printf("biPlanes    = %i \n", (int)(BIH[13] << 8) + (BIH[12]));
95         printf("biBitCount  = %i \n", (int)(BIH[15] << 8) + (BIH[14]));
96         printf("biCompress  = %i \n",
97                (int)(BIH[19] << 24) + (BIH[18] << 16) + (BIH[17] << 8) +
98                (BIH[16]));
99         printf("biSizeImage = %i \n",
100                (int)(BIH[23] << 24) + (BIH[22] << 16) + (BIH[21] << 8) +
101                (BIH[20]));
102         printf("biXPels     = %i \n",
103                (int)(BIH[27] << 24) + (BIH[26] << 16) + (BIH[25] << 8) +
104                (BIH[24]));
105         printf("biYPels     = %i \n",
106                (int)(BIH[31] << 24) + (BIH[30] << 16) + (BIH[29] << 8) +
107                (BIH[28]));
108         printf("biClrUsed   = %i \n",
109                (int)(BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) +
110                (BIH[32]));
111         printf("biClrImprtnt= %i \n",
112                (int)(BIH[39] << 24) + (BIH[38] << 16) + (BIH[37] << 8) +
113                (BIH[36]));
114 }
115 #endif
116
117 /* Progressive loading */
118 struct headerpair {
119         gint width;
120         gint height;
121         guint depth;
122         guint Negative;         /* Negative = 1 -> top down BMP,  
123                                    Negative = 0 -> bottom up BMP */
124 };
125
126 struct ico_progressive_state {
127         ModulePreparedNotifyFunc prepared_func;
128         ModuleUpdatedNotifyFunc updated_func;
129         gpointer user_data;
130
131         gint HeaderSize;        /* The size of the header-part (incl colormap) */
132         guchar *HeaderBuf;      /* The buffer for the header (incl colormap) */
133         gint BytesInHeaderBuf;  /* The size of the allocated HeaderBuf */
134         gint HeaderDone;        /* The nr of bytes actually in HeaderBuf */
135
136         gint LineWidth;         /* The width of a line in bytes */
137         guchar *LineBuf;        /* Buffer for 1 line */
138         gint LineDone;          /* # of bytes in LineBuf */
139         gint Lines;             /* # of finished lines */
140
141         gint Type;              /*  
142                                    32 = RGBA
143                                    24 = RGB
144                                    16 = 555 RGB
145                                    8 = 8 bit colormapped
146                                    4 = 4 bpp colormapped
147                                    1  = 1 bit bitonal 
148                                  */
149
150
151         struct headerpair Header;       /* Decoded (BE->CPU) header */
152         
153         gint                    DIBoffset;
154         gint                    ImageScore;
155
156
157         GdkPixbuf *pixbuf;      /* Our "target" */
158 };
159
160 static gpointer
161 gdk_pixbuf__ico_image_begin_load(ModuleSizeFunc size_func,
162                                  ModulePreparedNotifyFunc prepared_func,
163                                  ModuleUpdatedNotifyFunc updated_func,
164                                  gpointer user_data,
165                                  GError **error);
166 static gboolean gdk_pixbuf__ico_image_stop_load(gpointer data, GError **error);
167 static gboolean gdk_pixbuf__ico_image_load_increment(gpointer data,
168                                                      const guchar * buf, guint size,
169                                                      GError **error);
170
171 static void 
172 context_free (struct ico_progressive_state *context)
173 {
174         if (context->LineBuf != NULL)
175                 g_free (context->LineBuf);
176         context->LineBuf = NULL;
177         if (context->HeaderBuf != NULL)
178                 g_free (context->HeaderBuf);
179
180         if (context->pixbuf)
181                 g_object_unref (context->pixbuf);
182
183         g_free (context);
184 }
185                                 
186 /* Shared library entry point --> Can go when generic_image_load
187    enters gdk-pixbuf-io */
188 static GdkPixbuf *
189 gdk_pixbuf__ico_image_load(FILE * f, GError **error)
190 {
191         guchar membuf [4096];
192         size_t length;
193         struct ico_progressive_state *State;
194
195         GdkPixbuf *pb;
196
197         State = gdk_pixbuf__ico_image_begin_load(NULL, NULL, NULL, NULL, error);
198
199         if (State == NULL)
200                 return NULL;
201         
202         while (!feof(f)) {
203                 length = fread(membuf, 1, 4096, f);
204                 if (ferror (f)) {
205                         g_set_error (error,
206                                      G_FILE_ERROR,
207                                      g_file_error_from_errno (errno),
208                                      _("Failure reading ICO: %s"), g_strerror (errno));
209                         context_free (State);
210                         return NULL;
211                 }
212                 if (length > 0)
213                         if (!gdk_pixbuf__ico_image_load_increment(State, membuf, length,
214                                                                   error)) {
215                                 context_free (State);
216                                 return NULL;
217                         }
218         }
219         if (State->pixbuf != NULL)
220                 g_object_ref (State->pixbuf);
221         else {
222                 g_set_error (error,
223                              GDK_PIXBUF_ERROR,
224                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
225                              _("ICO file was missing some data (perhaps it was truncated somehow?)"));
226                 context_free (State);
227                 return NULL;
228         }
229
230         pb = State->pixbuf;
231
232         gdk_pixbuf__ico_image_stop_load(State, NULL);
233         return pb;
234 }
235
236 static void DecodeHeader(guchar *Data, gint Bytes,
237                          struct ico_progressive_state *State,
238                          GError **error)
239 {
240 /* For ICO's we have to be very clever. There are multiple images possible
241    in an .ICO. For now, we select (in order of priority):
242      1) The one with the highest number of colors
243      2) The largest one
244  */   
245  
246         gint IconCount = 0; /* The number of icon-versions in the file */
247         guchar *BIH; /* The DIB for the used icon */
248         guchar *Ptr;
249         gint I;
250  
251         /* Step 1: The ICO header */
252  
253         IconCount = (Data[5] << 8) + (Data[4]);
254         
255         State->HeaderSize = 6 + IconCount*16;
256
257         if (State->HeaderSize>State->BytesInHeaderBuf) {
258                 State->HeaderBuf=g_try_realloc(State->HeaderBuf,State->HeaderSize);
259                 if (!State->HeaderBuf) {
260                         g_set_error (error,
261                                      GDK_PIXBUF_ERROR,
262                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
263                                      _("Not enough memory to load icon"));
264                         return;
265                 }
266                 State->BytesInHeaderBuf = State->HeaderSize;
267         }
268         if (Bytes < State->HeaderSize)
269                 return;
270         
271         /* We now have all the "short-specs" of the versions 
272            So we iterate through them and select the best one */
273            
274         State->ImageScore = 0;
275         State->DIBoffset  = 0;
276         Ptr = Data + 6;
277         for (I=0;I<IconCount;I++) {
278                 int ThisWidth, ThisHeight,ThisColors;
279                 int ThisScore;
280                 
281                 ThisWidth = Ptr[0];
282                 ThisHeight = Ptr[1];
283                 ThisColors = (Ptr[2]);
284                 if (ThisColors==0) 
285                         ThisColors=256; /* Yes, this is in the spec, ugh */
286                 
287                 ThisScore = ThisColors*1024+ThisWidth*ThisHeight; 
288
289                 if (ThisScore>State->ImageScore) {
290                         State->ImageScore = ThisScore;
291                         State->DIBoffset = (Ptr[15]<<24)+(Ptr[14]<<16)+
292                                            (Ptr[13]<<8) + (Ptr[12]);
293                                                                  
294                 }
295                 
296                 
297                 Ptr += 16;      
298         } 
299
300         if (State->DIBoffset < 0) {
301                 g_set_error (error,
302                              GDK_PIXBUF_ERROR,
303                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
304                              _("Invalid header in icon"));
305                 return;
306         }
307
308         /* We now have a winner, pointed to in State->DIBoffset,
309            so we know how many bytes are in the "header" part. */
310               
311         State->HeaderSize = State->DIBoffset + 40; /* 40 = sizeof(InfoHeader) */
312         
313         if (State->HeaderSize>State->BytesInHeaderBuf) {
314                 State->HeaderBuf=g_try_realloc(State->HeaderBuf,State->HeaderSize);
315                 if (!State->HeaderBuf) {
316                         g_set_error (error,
317                                      GDK_PIXBUF_ERROR,
318                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
319                                      _("Not enough memory to load icon"));
320                         return;
321                 }
322                 State->BytesInHeaderBuf = State->HeaderSize;
323         }
324         if (Bytes<State->HeaderSize) 
325                 return;   
326         
327         BIH = Data+State->DIBoffset;
328
329 #ifdef DUMPBIH
330         DumpBIH(BIH);
331 #endif  
332         
333         /* Add the palette to the headersize */
334                 
335         State->Header.width =
336             (int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]);
337         if (State->Header.width == 0) {
338                 g_set_error (error,
339                              GDK_PIXBUF_ERROR,
340                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
341                              _("Icon has zero width"));
342                 return;
343         }
344         State->Header.height =
345             (int)((BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) + (BIH[8]))/2;
346             /* /2 because the BIH height includes the transparency mask */
347         if (State->Header.height == 0) {
348                 g_set_error (error,
349                              GDK_PIXBUF_ERROR,
350                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
351                              _("Icon has zero height"));
352                 return;
353         }
354         State->Header.depth = (BIH[15] << 8) + (BIH[14]);;
355
356         State->Type = State->Header.depth;      
357         if (State->Lines>=State->Header.height)
358                 State->Type = 1; /* The transparency mask is 1 bpp */
359         
360         
361         
362         /* Determine the  palette size. If the header indicates 0, it
363            is actually the maximum for the bpp. You have to love the
364            guys who made the spec. */
365         I = (int)(BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) + (BIH[32]);
366         I = I*4;
367         if ((I==0)&&(State->Type==1))
368                 I = 2*4;
369         if ((I==0)&&(State->Type==4))
370                 I = 16*4;
371         if ((I==0)&&(State->Type==8))
372                 I = 256*4;
373         
374         State->HeaderSize+=I;
375         
376         if (State->HeaderSize>State->BytesInHeaderBuf) {
377                 State->HeaderBuf=g_try_realloc(State->HeaderBuf,State->HeaderSize);
378                 if (!State->HeaderBuf) {
379                         g_set_error (error,
380                                      GDK_PIXBUF_ERROR,
381                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
382                                      _("Not enough memory to load icon"));
383                         return;
384                 }
385                 State->BytesInHeaderBuf = State->HeaderSize;
386         }
387         if (Bytes < State->HeaderSize)
388                 return;
389
390         if ((BIH[16] != 0) || (BIH[17] != 0) || (BIH[18] != 0)
391             || (BIH[19] != 0)) {
392                 /* FIXME: is this the correct message? */
393                 g_set_error (error,
394                              GDK_PIXBUF_ERROR,
395                              GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
396                              _("Compressed icons are not supported"));
397                 return;
398         }
399
400         /* Negative heights mean top-down pixel-order */
401         if (State->Header.height < 0) {
402                 State->Header.height = -State->Header.height;
403                 State->Header.Negative = 1;
404         }
405         if (State->Header.width < 0) {
406                 State->Header.width = -State->Header.width;
407         }
408         g_assert (State->Header.width > 0);
409         g_assert (State->Header.height > 0);
410
411         if (State->Type == 32)
412                 State->LineWidth = State->Header.width * 4;
413         else if (State->Type == 24)
414                 State->LineWidth = State->Header.width * 3;
415         else if (State->Type == 16)
416                 State->LineWidth = State->Header.height * 2;
417         else if (State->Type == 8)
418                 State->LineWidth = State->Header.width * 1;
419         else if (State->Type == 4)
420                 State->LineWidth = (State->Header.width+1)/2;
421         else if (State->Type == 1) {
422                 State->LineWidth = State->Header.width / 8;
423                 if ((State->Header.width & 7) != 0)
424                         State->LineWidth++;
425         } else {
426           g_set_error (error,
427                        GDK_PIXBUF_ERROR,
428                        GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
429                        _("Unsupported icon type"));
430           return;
431         }
432
433         /* Pad to a 32 bit boundary */
434         if (((State->LineWidth % 4) > 0))
435                 State->LineWidth = (State->LineWidth / 4) * 4 + 4;
436
437
438         if (State->LineBuf == NULL) {
439                 State->LineBuf = g_try_malloc(State->LineWidth);
440                 if (!State->LineBuf) {
441                         g_set_error (error,
442                                      GDK_PIXBUF_ERROR,
443                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
444                                      _("Not enough memory to load icon"));
445                         return;
446                 }
447         }
448
449         g_assert(State->LineBuf != NULL);
450
451
452         if (State->pixbuf == NULL) {
453                 State->pixbuf =
454                     gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8,
455                                    State->Header.width,
456                                    State->Header.height);
457                 if (!State->pixbuf) {
458                         g_set_error (error,
459                                      GDK_PIXBUF_ERROR,
460                                      GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
461                                      _("Not enough memory to load icon"));
462                         return;
463                 }
464
465                 if (State->prepared_func != NULL)
466                         /* Notify the client that we are ready to go */
467                         (*State->prepared_func) (State->pixbuf,
468                                                  NULL,
469                                                  State->user_data);
470
471         }
472
473 }
474
475 /* 
476  * func - called when we have pixmap created (but no image data)
477  * user_data - passed as arg 1 to func
478  * return context (opaque to user)
479  */
480
481 static gpointer
482 gdk_pixbuf__ico_image_begin_load(ModuleSizeFunc size_func,
483                                  ModulePreparedNotifyFunc prepared_func,
484                                  ModuleUpdatedNotifyFunc updated_func,
485                                  gpointer user_data,
486                                  GError **error)
487 {
488         struct ico_progressive_state *context;
489
490         context = g_new0(struct ico_progressive_state, 1);
491         context->prepared_func = prepared_func;
492         context->updated_func = updated_func;
493         context->user_data = user_data;
494
495         context->HeaderSize = 54;
496         context->HeaderBuf = g_try_malloc(14 + 40 + 4*256 + 512);
497         if (!context->HeaderBuf) {
498                 g_set_error (error,
499                              GDK_PIXBUF_ERROR,
500                              GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
501                              _("Not enough memory to load ICO file"));
502                 return NULL;
503         }
504         /* 4*256 for the colormap */
505         context->BytesInHeaderBuf = 14 + 40 + 4*256 + 512 ;
506         context->HeaderDone = 0;
507
508         context->LineWidth = 0;
509         context->LineBuf = NULL;
510         context->LineDone = 0;
511         context->Lines = 0;
512
513         context->Type = 0;
514
515         memset(&context->Header, 0, sizeof(struct headerpair));
516
517
518         context->pixbuf = NULL;
519
520
521         return (gpointer) context;
522 }
523
524 /*
525  * context - returned from image_begin_load
526  *
527  * free context, unref gdk_pixbuf
528  */
529 gboolean gdk_pixbuf__ico_image_stop_load(gpointer data,
530                                          GError **error)
531 {
532         struct ico_progressive_state *context =
533             (struct ico_progressive_state *) data;
534
535         /* FIXME this thing needs to report errors if
536          * we have unused image data
537          */
538
539         g_return_val_if_fail(context != NULL, TRUE);
540         
541         context_free (context);
542         return TRUE;
543 }
544
545 static void
546 OneLine32 (struct ico_progressive_state *context)
547 {
548         gint X;
549         guchar *Pixels;
550
551         X = 0;
552         if (context->Header.Negative == 0)
553                 Pixels = (context->pixbuf->pixels +
554                           context->pixbuf->rowstride *
555                           (context->Header.height - context->Lines - 1));
556         else
557                 Pixels = (context->pixbuf->pixels +
558                           context->pixbuf->rowstride *
559                           context->Lines);
560         while (X < context->Header.width) {
561                 Pixels[X * 4 + 0] = context->LineBuf[X * 4 + 2];
562                 Pixels[X * 4 + 1] = context->LineBuf[X * 4 + 1];
563                 Pixels[X * 4 + 2] = context->LineBuf[X * 4 + 0];
564                 Pixels[X * 4 + 3] = context->LineBuf[X * 4 + 3];
565                 X++;
566         }
567 }
568
569 static void OneLine24(struct ico_progressive_state *context)
570 {
571         gint X;
572         guchar *Pixels;
573
574         X = 0;
575         if (context->Header.Negative == 0)
576                 Pixels = (context->pixbuf->pixels +
577                           context->pixbuf->rowstride *
578                           (context->Header.height - context->Lines - 1));
579         else
580                 Pixels = (context->pixbuf->pixels +
581                           context->pixbuf->rowstride *
582                           context->Lines);
583         while (X < context->Header.width) {
584                 Pixels[X * 4 + 0] = context->LineBuf[X * 3 + 2];
585                 Pixels[X * 4 + 1] = context->LineBuf[X * 3 + 1];
586                 Pixels[X * 4 + 2] = context->LineBuf[X * 3 + 0];
587                 X++;
588         }
589
590 }
591
592 static void
593 OneLine16 (struct ico_progressive_state *context)
594 {
595         int i;
596         guchar *pixels;
597         guchar *src;
598
599         if (context->Header.Negative == 0)
600                 pixels = (context->pixbuf->pixels +
601                           context->pixbuf->rowstride * (context->Header.height - context->Lines - 1));
602         else
603                 pixels = (context->pixbuf->pixels +
604                           context->pixbuf->rowstride * context->Lines);
605
606         src = context->LineBuf;
607
608         for (i = 0; i < context->Header.width; i++) {
609                 int v, r, g, b;
610
611                 v = (int) src[0] | ((int) src[1] << 8);
612                 src += 2;
613
614                 /* Extract 5-bit RGB values */
615
616                 r = (v >> 10) & 0x1f;
617                 g = (v >> 5) & 0x1f;
618                 b = v & 0x1f;
619
620                 /* Fill the rightmost bits to form 8-bit values */
621
622                 *pixels++ = (r << 3) | (r >> 2);
623                 *pixels++ = (g << 3) | (g >> 2);
624                 *pixels++ = (b << 3) | (b >> 2);
625                 pixels++; /* skip alpha channel */
626         }
627 }
628
629
630 static void OneLine8(struct ico_progressive_state *context)
631 {
632         gint X;
633         guchar *Pixels;
634
635         X = 0;
636         if (context->Header.Negative == 0)
637                 Pixels = (context->pixbuf->pixels +
638                           context->pixbuf->rowstride *
639                           (context->Header.height - context->Lines - 1));
640         else
641                 Pixels = (context->pixbuf->pixels +
642                           context->pixbuf->rowstride *
643                           context->Lines);
644         while (X < context->Header.width) {
645                 /* The joys of having a BGR byteorder */
646                 Pixels[X * 4 + 0] =
647                     context->HeaderBuf[4 * context->LineBuf[X] + 42+context->DIBoffset];
648                 Pixels[X * 4 + 1] =
649                     context->HeaderBuf[4 * context->LineBuf[X] + 41+context->DIBoffset];
650                 Pixels[X * 4 + 2] =
651                     context->HeaderBuf[4 * context->LineBuf[X] + 40+context->DIBoffset];
652                 X++;
653         }
654 }
655 static void OneLine4(struct ico_progressive_state *context)
656 {
657         gint X;
658         guchar *Pixels;
659
660         X = 0;
661         if (context->Header.Negative == 0)
662                 Pixels = (context->pixbuf->pixels +
663                           context->pixbuf->rowstride *
664                           (context->Header.height - context->Lines - 1));
665         else
666                 Pixels = (context->pixbuf->pixels +
667                           context->pixbuf->rowstride *
668                           context->Lines);
669         
670         while (X < context->Header.width) {
671                 guchar Pix;
672                 
673                 Pix = context->LineBuf[X/2];
674
675                 Pixels[X * 4 + 0] =
676                     context->HeaderBuf[4 * (Pix>>4) + 42+context->DIBoffset];
677                 Pixels[X * 4 + 1] =
678                     context->HeaderBuf[4 * (Pix>>4) + 41+context->DIBoffset];
679                 Pixels[X * 4 + 2] =
680                     context->HeaderBuf[4 * (Pix>>4) + 40+context->DIBoffset];
681                 X++;
682                 if (X<context->Header.width) { 
683                         /* Handle the other 4 bit pixel only when there is one */
684                         Pixels[X * 4 + 0] =
685                             context->HeaderBuf[4 * (Pix&15) + 42+context->DIBoffset];
686                         Pixels[X * 4 + 1] =
687                             context->HeaderBuf[4 * (Pix&15) + 41+context->DIBoffset];
688                         Pixels[X * 4 + 2] =
689                             context->HeaderBuf[4 * (Pix&15) + 40+context->DIBoffset];
690                         X++;
691                 }
692         }
693         
694 }
695
696 static void OneLine1(struct ico_progressive_state *context)
697 {
698         gint X;
699         guchar *Pixels;
700
701         X = 0;
702         if (context->Header.Negative == 0)
703                 Pixels = (context->pixbuf->pixels +
704                           context->pixbuf->rowstride *
705                           (context->Header.height - context->Lines - 1));
706         else
707                 Pixels = (context->pixbuf->pixels +
708                           context->pixbuf->rowstride *
709                           context->Lines);
710         while (X < context->Header.width) {
711                 int Bit;
712
713                 Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7));
714                 Bit = Bit & 1;
715                 /* The joys of having a BGR byteorder */
716                 Pixels[X * 4 + 0] = Bit*255;
717                 Pixels[X * 4 + 1] = Bit*255;
718                 Pixels[X * 4 + 2] = Bit*255;
719                 X++;
720         }
721 }
722
723 static void OneLineTransp(struct ico_progressive_state *context)
724 {
725         gint X;
726         guchar *Pixels;
727
728         X = 0;
729         if (context->Header.Negative == 0)
730                 Pixels = (context->pixbuf->pixels +
731                           context->pixbuf->rowstride *
732                           (2*context->Header.height - context->Lines - 1));
733         else
734                 Pixels = (context->pixbuf->pixels +
735                           context->pixbuf->rowstride *
736                           (context->Lines-context->Header.height));
737         while (X < context->Header.width) {
738                 int Bit;
739
740                 Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7));
741                 Bit = Bit & 1;
742                 /* The joys of having a BGR byteorder */
743                 Pixels[X * 4 + 3] = 255-Bit*255;
744 #if 0           
745                 if (Bit){
746                   Pixels[X*4+0] = 255;
747                   Pixels[X*4+1] = 255;
748                 } else {
749                   Pixels[X*4+0] = 0;
750                   Pixels[X*4+1] = 0;
751                 }
752 #endif          
753                 X++;
754         }
755 }
756
757
758 static void OneLine(struct ico_progressive_state *context)
759 {
760         context->LineDone = 0;
761         
762         if (context->Lines >= context->Header.height*2) {
763                 return;
764         }
765                 
766         if (context->Lines <context->Header.height) {           
767                 if (context->Type == 32)
768                         OneLine32 (context);
769                 else if (context->Type == 24)
770                         OneLine24(context);
771                 else if (context->Type == 16)
772                         OneLine16 (context);
773                 else if (context->Type == 8)
774                         OneLine8(context);
775                 else if (context->Type == 4)
776                         OneLine4(context);
777                 else if (context->Type == 1)
778                         OneLine1(context);
779                 else 
780                         g_assert_not_reached ();
781         } else
782                 OneLineTransp(context);
783         
784         context->Lines++;
785         if (context->Lines>=context->Header.height) {
786                 context->Type = 1;
787                 context->LineWidth = context->Header.width / 8;
788                 if ((context->Header.width & 7) != 0)
789                         context->LineWidth++;
790                 /* Pad to a 32 bit boundary */
791                 if (((context->LineWidth % 4) > 0))
792                         context->LineWidth = (context->LineWidth / 4) * 4 + 4;
793                         
794         }
795           
796
797         if (context->updated_func != NULL) {
798                 (*context->updated_func) (context->pixbuf,
799                                           0,
800                                           context->Lines % context->Header.height,
801                                           context->Header.width,
802                                           1,
803                                           context->user_data);
804
805         }
806 }
807
808 /*
809  * context - from image_begin_load
810  * buf - new image data
811  * size - length of new image data
812  *
813  * append image data onto inrecrementally built output image
814  */
815 static gboolean
816 gdk_pixbuf__ico_image_load_increment(gpointer data,
817                                      const guchar * buf,
818                                      guint size,
819                                      GError **error)
820 {
821         struct ico_progressive_state *context =
822             (struct ico_progressive_state *) data;
823
824         gint BytesToCopy;
825
826         while (size > 0) {
827                 g_assert(context->LineDone >= 0);
828                 if (context->HeaderDone < context->HeaderSize) {        /* We still 
829                                                                            have headerbytes to do */
830                         BytesToCopy =
831                             context->HeaderSize - context->HeaderDone;
832                         if (BytesToCopy > size)
833                                 BytesToCopy = size;
834
835                         memmove(context->HeaderBuf + context->HeaderDone,
836                                buf, BytesToCopy);
837
838                         size -= BytesToCopy;
839                         buf += BytesToCopy;
840                         context->HeaderDone += BytesToCopy;
841                 } 
842                 else {
843                         BytesToCopy =
844                             context->LineWidth - context->LineDone;
845                         if (BytesToCopy > size)
846                                 BytesToCopy = size;
847
848                         if (BytesToCopy > 0) {
849                                 memmove(context->LineBuf +
850                                        context->LineDone, buf,
851                                        BytesToCopy);
852
853                                 size -= BytesToCopy;
854                                 buf += BytesToCopy;
855                                 context->LineDone += BytesToCopy;
856                         }
857                         if ((context->LineDone >= context->LineWidth) &&
858                             (context->LineWidth > 0))
859                                 OneLine(context);
860
861
862                 }
863
864                 if (context->HeaderDone >= 6) {
865                         GError *decode_err = NULL;
866                         DecodeHeader(context->HeaderBuf,
867                                      context->HeaderDone, context, &decode_err);
868                         if (decode_err) {
869                                 g_propagate_error (error, decode_err);
870                                 return FALSE;
871                         }
872                 }
873         }
874
875         return TRUE;
876 }
877
878 void
879 gdk_pixbuf__ico_fill_vtable (GdkPixbufModule *module)
880 {
881   module->load = gdk_pixbuf__ico_image_load;
882   module->begin_load = gdk_pixbuf__ico_image_begin_load;
883   module->stop_load = gdk_pixbuf__ico_image_stop_load;
884   module->load_increment = gdk_pixbuf__ico_image_load_increment;
885 }