diff options
Diffstat (limited to 'gdk-pixbuf/io-ico.c')
-rw-r--r-- | gdk-pixbuf/io-ico.c | 1254 |
1 files changed, 0 insertions, 1254 deletions
diff --git a/gdk-pixbuf/io-ico.c b/gdk-pixbuf/io-ico.c deleted file mode 100644 index e7fedb9295..0000000000 --- a/gdk-pixbuf/io-ico.c +++ /dev/null @@ -1,1254 +0,0 @@ -/* -*- mode: C; c-file-style: "linux" -*- */ -/* GdkPixbuf library - Windows Icon/Cursor image loader - * - * Copyright (C) 1999 The Free Software Foundation - * - * Authors: Arjan van de Ven <arjan@fenrus.demon.nl> - * Federico Mena-Quintero <federico@gimp.org> - * - * Based on io-bmp.c - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#undef DUMPBIH -/* - -Icons are just like BMP's, except for the header. - -Known bugs: - * bi-tonal files aren't tested - -*/ - -#include "config.h" -#include <stdio.h> -#include <stdlib.h> -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif -#include <string.h> -#include "gdk-pixbuf-private.h" -#include "gdk-pixbuf-io.h" -#include <errno.h> - - - -/* - -These structures are actually dummies. These are according to -the "Windows API reference guide volume II" as written by -Borland International, but GCC fiddles with the alignment of -the internal members. - -*/ - -struct BitmapFileHeader { - gushort bfType; - guint bfSize; - guint reserverd; - guint bfOffbits; -}; - -struct BitmapInfoHeader { - guint biSize; - guint biWidth; - guint biHeight; - gushort biPlanes; - gushort biBitCount; - guint biCompression; - guint biSizeImage; - guint biXPelsPerMeter; - guint biYPelsPerMeter; - guint biClrUsed; - guint biClrImportant; -}; - -#ifdef DUMPBIH -/* - -DumpBIH printf's the values in a BitmapInfoHeader to the screen, for -debugging purposes. - -*/ -static void DumpBIH(unsigned char *BIH) -{ - printf("biSize = %i \n", - (int)(BIH[3] << 24) + (BIH[2] << 16) + (BIH[1] << 8) + (BIH[0])); - printf("biWidth = %i \n", - (int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4])); - printf("biHeight = %i \n", - (int)(BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) + - (BIH[8])); - printf("biPlanes = %i \n", (int)(BIH[13] << 8) + (BIH[12])); - printf("biBitCount = %i \n", (int)(BIH[15] << 8) + (BIH[14])); - printf("biCompress = %i \n", - (int)(BIH[19] << 24) + (BIH[18] << 16) + (BIH[17] << 8) + - (BIH[16])); - printf("biSizeImage = %i \n", - (int)(BIH[23] << 24) + (BIH[22] << 16) + (BIH[21] << 8) + - (BIH[20])); - printf("biXPels = %i \n", - (int)(BIH[27] << 24) + (BIH[26] << 16) + (BIH[25] << 8) + - (BIH[24])); - printf("biYPels = %i \n", - (int)(BIH[31] << 24) + (BIH[30] << 16) + (BIH[29] << 8) + - (BIH[28])); - printf("biClrUsed = %i \n", - (int)(BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) + - (BIH[32])); - printf("biClrImprtnt= %i \n", - (int)(BIH[39] << 24) + (BIH[38] << 16) + (BIH[37] << 8) + - (BIH[36])); -} -#endif - -/* Progressive loading */ -struct headerpair { - gint width; - gint height; - guint depth; - guint Negative; /* Negative = 1 -> top down BMP, - Negative = 0 -> bottom up BMP */ -}; - -struct ico_progressive_state { - GdkPixbufModuleSizeFunc size_func; - GdkPixbufModulePreparedFunc prepared_func; - GdkPixbufModuleUpdatedFunc updated_func; - gpointer user_data; - - gint HeaderSize; /* The size of the header-part (incl colormap) */ - guchar *HeaderBuf; /* The buffer for the header (incl colormap) */ - gint BytesInHeaderBuf; /* The size of the allocated HeaderBuf */ - gint HeaderDone; /* The nr of bytes actually in HeaderBuf */ - - gint LineWidth; /* The width of a line in bytes */ - guchar *LineBuf; /* Buffer for 1 line */ - gint LineDone; /* # of bytes in LineBuf */ - gint Lines; /* # of finished lines */ - - gint Type; /* - 32 = RGBA - 24 = RGB - 16 = 555 RGB - 8 = 8 bit colormapped - 4 = 4 bpp colormapped - 1 = 1 bit bitonal - */ - gboolean cursor; - gint x_hot; - gint y_hot; - - struct headerpair Header; /* Decoded (BE->CPU) header */ - - gint DIBoffset; - gint ImageScore; - - - GdkPixbuf *pixbuf; /* Our "target" */ -}; - -static gpointer -gdk_pixbuf__ico_image_begin_load(GdkPixbufModuleSizeFunc size_func, - GdkPixbufModulePreparedFunc prepared_func, - GdkPixbufModuleUpdatedFunc updated_func, - gpointer user_data, - GError **error); -static gboolean gdk_pixbuf__ico_image_stop_load(gpointer data, GError **error); -static gboolean gdk_pixbuf__ico_image_load_increment(gpointer data, - const guchar * buf, guint size, - GError **error); - -static void -context_free (struct ico_progressive_state *context) -{ - g_free (context->LineBuf); - context->LineBuf = NULL; - g_free (context->HeaderBuf); - - if (context->pixbuf) - g_object_unref (context->pixbuf); - - g_free (context); -} - -static void DecodeHeader(guchar *Data, gint Bytes, - struct ico_progressive_state *State, - GError **error) -{ -/* For ICO's we have to be very clever. There are multiple images possible - in an .ICO. As a simple heuristic, we select the image which occupies the - largest number of bytes. - */ - - gint IconCount = 0; /* The number of icon-versions in the file */ - guchar *BIH; /* The DIB for the used icon */ - guchar *Ptr; - gint I; - guint16 imgtype; /* 1 = icon, 2 = cursor */ - - /* Step 1: The ICO header */ - - /* First word should be 0 according to specs */ - if (((Data[1] << 8) + Data[0]) != 0) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - _("Invalid header in icon")); - return; - - } - - imgtype = (Data[3] << 8) + Data[2]; - - State->cursor = (imgtype == 2) ? TRUE : FALSE; - - /* If it is not a cursor make sure it is actually an icon */ - if (!State->cursor && imgtype != 1) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - _("Invalid header in icon")); - return; - } - - - IconCount = (Data[5] << 8) + (Data[4]); - - State->HeaderSize = 6 + IconCount*16; - - if (State->HeaderSize>State->BytesInHeaderBuf) { - guchar *tmp=g_try_realloc(State->HeaderBuf,State->HeaderSize); - if (!tmp) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, - _("Not enough memory to load icon")); - return; - } - State->HeaderBuf = tmp; - State->BytesInHeaderBuf = State->HeaderSize; - } - if (Bytes < State->HeaderSize) - return; - - /* We now have all the "short-specs" of the versions - So we iterate through them and select the best one */ - - State->ImageScore = 0; - State->DIBoffset = 0; - Ptr = Data + 6; - for (I=0;I<IconCount;I++) { - int ThisScore; - - ThisScore = (Ptr[11] << 24) + (Ptr[10] << 16) + (Ptr[9] << 8) + (Ptr[8]); - - if (ThisScore>=State->ImageScore) { - State->ImageScore = ThisScore; - State->x_hot = (Ptr[5] << 8) + Ptr[4]; - State->y_hot = (Ptr[7] << 8) + Ptr[6]; - State->DIBoffset = (Ptr[15]<<24)+(Ptr[14]<<16)+ - (Ptr[13]<<8) + (Ptr[12]); - - } - - - Ptr += 16; - } - - if (State->DIBoffset < 0) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - _("Invalid header in icon")); - return; - } - - /* We now have a winner, pointed to in State->DIBoffset, - so we know how many bytes are in the "header" part. */ - - State->HeaderSize = State->DIBoffset + 40; /* 40 = sizeof(InfoHeader) */ - - if (State->HeaderSize < 0) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - _("Invalid header in icon")); - return; - } - - if (State->HeaderSize>State->BytesInHeaderBuf) { - guchar *tmp=g_try_realloc(State->HeaderBuf,State->HeaderSize); - if (!tmp) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, - _("Not enough memory to load icon")); - return; - } - State->HeaderBuf = tmp; - State->BytesInHeaderBuf = State->HeaderSize; - } - if (Bytes<State->HeaderSize) - return; - - BIH = Data+State->DIBoffset; - -#ifdef DUMPBIH - DumpBIH(BIH); -#endif - /* Add the palette to the headersize */ - - State->Header.width = - (int)(BIH[7] << 24) + (BIH[6] << 16) + (BIH[5] << 8) + (BIH[4]); - if (State->Header.width == 0) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - _("Icon has zero width")); - return; - } - State->Header.height = - (int)((BIH[11] << 24) + (BIH[10] << 16) + (BIH[9] << 8) + (BIH[8]))/2; - /* /2 because the BIH height includes the transparency mask */ - if (State->Header.height == 0) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - _("Icon has zero height")); - return; - } - State->Header.depth = (BIH[15] << 8) + (BIH[14]); - - State->Type = State->Header.depth; - if (State->Lines>=State->Header.height) - State->Type = 1; /* The transparency mask is 1 bpp */ - - /* Determine the palette size. If the header indicates 0, it - is actually the maximum for the bpp. You have to love the - guys who made the spec. */ - I = (int)(BIH[35] << 24) + (BIH[34] << 16) + (BIH[33] << 8) + (BIH[32]); - I = I*4; - if ((I==0)&&(State->Type==1)) - I = 2*4; - if ((I==0)&&(State->Type==4)) - I = 16*4; - if ((I==0)&&(State->Type==8)) - I = 256*4; - - State->HeaderSize+=I; - - if (State->HeaderSize < 0) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - _("Invalid header in icon")); - return; - } - - if (State->HeaderSize>State->BytesInHeaderBuf) { - guchar *tmp=g_try_realloc(State->HeaderBuf,State->HeaderSize); - if (!tmp) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, - _("Not enough memory to load icon")); - return; - } - State->HeaderBuf = tmp; - State->BytesInHeaderBuf = State->HeaderSize; - } - if (Bytes < State->HeaderSize) - return; - - if ((BIH[16] != 0) || (BIH[17] != 0) || (BIH[18] != 0) - || (BIH[19] != 0)) { - /* FIXME: is this the correct message? */ - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - _("Compressed icons are not supported")); - return; - } - - /* Negative heights mean top-down pixel-order */ - if (State->Header.height < 0) { - State->Header.height = -State->Header.height; - State->Header.Negative = 1; - } - if (State->Header.width < 0) { - State->Header.width = -State->Header.width; - } - g_assert (State->Header.width > 0); - g_assert (State->Header.height > 0); - - if (State->Type == 32) - State->LineWidth = State->Header.width * 4; - else if (State->Type == 24) - State->LineWidth = State->Header.width * 3; - else if (State->Type == 16) - State->LineWidth = State->Header.width * 2; - else if (State->Type == 8) - State->LineWidth = State->Header.width * 1; - else if (State->Type == 4) - State->LineWidth = (State->Header.width+1)/2; - else if (State->Type == 1) { - State->LineWidth = State->Header.width / 8; - if ((State->Header.width & 7) != 0) - State->LineWidth++; - } else { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_CORRUPT_IMAGE, - _("Unsupported icon type")); - return; - } - - /* Pad to a 32 bit boundary */ - if (((State->LineWidth % 4) > 0)) - State->LineWidth = (State->LineWidth / 4) * 4 + 4; - - - if (State->LineBuf == NULL) { - State->LineBuf = g_try_malloc(State->LineWidth); - if (!State->LineBuf) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, - _("Not enough memory to load icon")); - return; - } - } - - g_assert(State->LineBuf != NULL); - - - if (State->pixbuf == NULL) { -#if 1 - if (State->size_func) { - gint width = State->Header.width; - gint height = State->Header.height; - - (*State->size_func) (&width, &height, State->user_data); - if (width == 0 || height == 0) { - State->LineWidth = 0; - return; - } - } -#endif - - State->pixbuf = - gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, - State->Header.width, - State->Header.height); - if (!State->pixbuf) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, - _("Not enough memory to load icon")); - return; - } - if (State->cursor) { - gchar hot[10]; - g_snprintf (hot, 10, "%d", State->x_hot); - gdk_pixbuf_set_option (State->pixbuf, "x_hot", hot); - g_snprintf (hot, 10, "%d", State->y_hot); - gdk_pixbuf_set_option (State->pixbuf, "y_hot", hot); - } - - if (State->prepared_func != NULL) - /* Notify the client that we are ready to go */ - (*State->prepared_func) (State->pixbuf, - NULL, - State->user_data); - - } - -} - -/* - * func - called when we have pixmap created (but no image data) - * user_data - passed as arg 1 to func - * return context (opaque to user) - */ - -static gpointer -gdk_pixbuf__ico_image_begin_load(GdkPixbufModuleSizeFunc size_func, - GdkPixbufModulePreparedFunc prepared_func, - GdkPixbufModuleUpdatedFunc updated_func, - gpointer user_data, - GError **error) -{ - struct ico_progressive_state *context; - - context = g_new0(struct ico_progressive_state, 1); - context->size_func = size_func; - context->prepared_func = prepared_func; - context->updated_func = updated_func; - context->user_data = user_data; - - context->HeaderSize = 54; - context->HeaderBuf = g_try_malloc(14 + 40 + 4*256 + 512); - if (!context->HeaderBuf) { - g_free (context); - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY, - _("Not enough memory to load ICO file")); - return NULL; - } - /* 4*256 for the colormap */ - context->BytesInHeaderBuf = 14 + 40 + 4*256 + 512 ; - context->HeaderDone = 0; - - context->LineWidth = 0; - context->LineBuf = NULL; - context->LineDone = 0; - context->Lines = 0; - - context->Type = 0; - - memset(&context->Header, 0, sizeof(struct headerpair)); - - - context->pixbuf = NULL; - - - return (gpointer) context; -} - -/* - * context - returned from image_begin_load - * - * free context, unref gdk_pixbuf - */ -static gboolean -gdk_pixbuf__ico_image_stop_load(gpointer data, - GError **error) -{ - struct ico_progressive_state *context = - (struct ico_progressive_state *) data; - - /* FIXME this thing needs to report errors if - * we have unused image data - */ - - g_return_val_if_fail(context != NULL, TRUE); - - context_free (context); - return TRUE; -} - -static void -OneLine32 (struct ico_progressive_state *context) -{ - gint X; - guchar *Pixels; - - X = 0; - if (context->Header.Negative == 0) - Pixels = (context->pixbuf->pixels + - context->pixbuf->rowstride * - (context->Header.height - context->Lines - 1)); - else - Pixels = (context->pixbuf->pixels + - context->pixbuf->rowstride * - context->Lines); - while (X < context->Header.width) { - Pixels[X * 4 + 0] = context->LineBuf[X * 4 + 2]; - Pixels[X * 4 + 1] = context->LineBuf[X * 4 + 1]; - Pixels[X * 4 + 2] = context->LineBuf[X * 4 + 0]; - Pixels[X * 4 + 3] = context->LineBuf[X * 4 + 3]; - X++; - } -} - -static void OneLine24(struct ico_progressive_state *context) -{ - gint X; - guchar *Pixels; - - X = 0; - if (context->Header.Negative == 0) - Pixels = (context->pixbuf->pixels + - context->pixbuf->rowstride * - (context->Header.height - context->Lines - 1)); - else - Pixels = (context->pixbuf->pixels + - context->pixbuf->rowstride * - context->Lines); - while (X < context->Header.width) { - Pixels[X * 4 + 0] = context->LineBuf[X * 3 + 2]; - Pixels[X * 4 + 1] = context->LineBuf[X * 3 + 1]; - Pixels[X * 4 + 2] = context->LineBuf[X * 3 + 0]; - X++; - } - -} - -static void -OneLine16 (struct ico_progressive_state *context) -{ - int i; - guchar *pixels; - guchar *src; - - if (context->Header.Negative == 0) - pixels = (context->pixbuf->pixels + - context->pixbuf->rowstride * (context->Header.height - context->Lines - 1)); - else - pixels = (context->pixbuf->pixels + - context->pixbuf->rowstride * context->Lines); - - src = context->LineBuf; - - for (i = 0; i < context->Header.width; i++) { - int v, r, g, b; - - v = (int) src[0] | ((int) src[1] << 8); - src += 2; - - /* Extract 5-bit RGB values */ - - r = (v >> 10) & 0x1f; - g = (v >> 5) & 0x1f; - b = v & 0x1f; - - /* Fill the rightmost bits to form 8-bit values */ - - *pixels++ = (r << 3) | (r >> 2); - *pixels++ = (g << 3) | (g >> 2); - *pixels++ = (b << 3) | (b >> 2); - pixels++; /* skip alpha channel */ - } -} - - -static void OneLine8(struct ico_progressive_state *context) -{ - gint X; - guchar *Pixels; - - X = 0; - if (context->Header.Negative == 0) - Pixels = (context->pixbuf->pixels + - context->pixbuf->rowstride * - (context->Header.height - context->Lines - 1)); - else - Pixels = (context->pixbuf->pixels + - context->pixbuf->rowstride * - context->Lines); - while (X < context->Header.width) { - /* The joys of having a BGR byteorder */ - Pixels[X * 4 + 0] = - context->HeaderBuf[4 * context->LineBuf[X] + 42+context->DIBoffset]; - Pixels[X * 4 + 1] = - context->HeaderBuf[4 * context->LineBuf[X] + 41+context->DIBoffset]; - Pixels[X * 4 + 2] = - context->HeaderBuf[4 * context->LineBuf[X] + 40+context->DIBoffset]; - X++; - } -} -static void OneLine4(struct ico_progressive_state *context) -{ - gint X; - guchar *Pixels; - - X = 0; - if (context->Header.Negative == 0) - Pixels = (context->pixbuf->pixels + - context->pixbuf->rowstride * - (context->Header.height - context->Lines - 1)); - else - Pixels = (context->pixbuf->pixels + - context->pixbuf->rowstride * - context->Lines); - - while (X < context->Header.width) { - guchar Pix; - - Pix = context->LineBuf[X/2]; - - Pixels[X * 4 + 0] = - context->HeaderBuf[4 * (Pix>>4) + 42+context->DIBoffset]; - Pixels[X * 4 + 1] = - context->HeaderBuf[4 * (Pix>>4) + 41+context->DIBoffset]; - Pixels[X * 4 + 2] = - context->HeaderBuf[4 * (Pix>>4) + 40+context->DIBoffset]; - X++; - if (X<context->Header.width) { - /* Handle the other 4 bit pixel only when there is one */ - Pixels[X * 4 + 0] = - context->HeaderBuf[4 * (Pix&15) + 42+context->DIBoffset]; - Pixels[X * 4 + 1] = - context->HeaderBuf[4 * (Pix&15) + 41+context->DIBoffset]; - Pixels[X * 4 + 2] = - context->HeaderBuf[4 * (Pix&15) + 40+context->DIBoffset]; - X++; - } - } - -} - -static void OneLine1(struct ico_progressive_state *context) -{ - gint X; - guchar *Pixels; - - X = 0; - if (context->Header.Negative == 0) - Pixels = (context->pixbuf->pixels + - context->pixbuf->rowstride * - (context->Header.height - context->Lines - 1)); - else - Pixels = (context->pixbuf->pixels + - context->pixbuf->rowstride * - context->Lines); - while (X < context->Header.width) { - int Bit; - - Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7)); - Bit = Bit & 1; - /* The joys of having a BGR byteorder */ - Pixels[X * 4 + 0] = Bit*255; - Pixels[X * 4 + 1] = Bit*255; - Pixels[X * 4 + 2] = Bit*255; - X++; - } -} - -static void OneLineTransp(struct ico_progressive_state *context) -{ - gint X; - guchar *Pixels; - - /* Ignore the XOR mask for XP style 32-bpp icons with alpha */ - if (context->Header.depth == 32) - return; - - X = 0; - if (context->Header.Negative == 0) - Pixels = (context->pixbuf->pixels + - context->pixbuf->rowstride * - (2*context->Header.height - context->Lines - 1)); - else - Pixels = (context->pixbuf->pixels + - context->pixbuf->rowstride * - (context->Lines-context->Header.height)); - while (X < context->Header.width) { - int Bit; - - Bit = (context->LineBuf[X / 8]) >> (7 - (X & 7)); - Bit = Bit & 1; - /* The joys of having a BGR byteorder */ - Pixels[X * 4 + 3] = 255-Bit*255; -#if 0 - if (Bit){ - Pixels[X*4+0] = 255; - Pixels[X*4+1] = 255; - } else { - Pixels[X*4+0] = 0; - Pixels[X*4+1] = 0; - } -#endif - X++; - } -} - - -static void OneLine(struct ico_progressive_state *context) -{ - context->LineDone = 0; - - if (context->Lines >= context->Header.height*2) { - return; - } - - if (context->Lines <context->Header.height) { - if (context->Type == 32) - OneLine32 (context); - else if (context->Type == 24) - OneLine24(context); - else if (context->Type == 16) - OneLine16 (context); - else if (context->Type == 8) - OneLine8(context); - else if (context->Type == 4) - OneLine4(context); - else if (context->Type == 1) - OneLine1(context); - else - g_assert_not_reached (); - } else - OneLineTransp(context); - - context->Lines++; - if (context->Lines>=context->Header.height) { - context->Type = 1; - context->LineWidth = context->Header.width / 8; - if ((context->Header.width & 7) != 0) - context->LineWidth++; - /* Pad to a 32 bit boundary */ - if (((context->LineWidth % 4) > 0)) - context->LineWidth = (context->LineWidth / 4) * 4 + 4; - - } - - - if (context->updated_func != NULL) { - (*context->updated_func) (context->pixbuf, - 0, - context->Lines % context->Header.height, - context->Header.width, - 1, - context->user_data); - - } -} - -/* - * context - from image_begin_load - * buf - new image data - * size - length of new image data - * - * append image data onto inrecrementally built output image - */ -static gboolean -gdk_pixbuf__ico_image_load_increment(gpointer data, - const guchar * buf, - guint size, - GError **error) -{ - struct ico_progressive_state *context = - (struct ico_progressive_state *) data; - - gint BytesToCopy; - - while (size > 0) { - g_assert(context->LineDone >= 0); - if (context->HeaderDone < context->HeaderSize) { /* We still - have headerbytes to do */ - BytesToCopy = - context->HeaderSize - context->HeaderDone; - if (BytesToCopy > size) - BytesToCopy = size; - - memmove(context->HeaderBuf + context->HeaderDone, - buf, BytesToCopy); - - size -= BytesToCopy; - buf += BytesToCopy; - context->HeaderDone += BytesToCopy; - } - else { - BytesToCopy = - context->LineWidth - context->LineDone; - if (BytesToCopy > size) - BytesToCopy = size; - - if (BytesToCopy > 0) { - memmove(context->LineBuf + - context->LineDone, buf, - BytesToCopy); - - size -= BytesToCopy; - buf += BytesToCopy; - context->LineDone += BytesToCopy; - } - if ((context->LineDone >= context->LineWidth) && - (context->LineWidth > 0)) - OneLine(context); - - - } - - if (context->HeaderDone >= 6 && context->pixbuf == NULL) { - GError *decode_err = NULL; - DecodeHeader(context->HeaderBuf, - context->HeaderDone, context, &decode_err); - if (context->LineBuf != NULL && context->LineWidth == 0) - return TRUE; - - if (decode_err) { - g_propagate_error (error, decode_err); - return FALSE; - } - } - } - - return TRUE; -} - -/* saving ICOs */ - -static gint -write8 (FILE *f, - guint8 *data, - gint count) -{ - gint bytes; - gint written; - - written = 0; - while (count > 0) - { - bytes = fwrite ((char*) data, sizeof (char), count, f); - if (bytes <= 0) - break; - count -= bytes; - data += bytes; - written += bytes; - } - - return written; -} - -static gint -write16 (FILE *f, - guint16 *data, - gint count) -{ - gint i; - - for (i = 0; i < count; i++) - data[i] = GUINT16_TO_LE (data[i]); - - return write8 (f, (guint8*) data, count * 2); -} - -static gint -write32 (FILE *f, - guint32 *data, - gint count) -{ - gint i; - - for (i = 0; i < count; i++) - data[i] = GUINT32_TO_LE (data[i]); - - return write8 (f, (guint8*) data, count * 4); -} - -typedef struct _IconEntry IconEntry; -struct _IconEntry { - gint width; - gint height; - gint depth; - gint hot_x; - gint hot_y; - - guint8 n_colors; - guint32 *colors; - guint xor_rowstride; - guint8 *xor; - guint and_rowstride; - guint8 *and; -}; - -static gboolean -fill_entry (IconEntry *icon, - GdkPixbuf *pixbuf, - gint hot_x, - gint hot_y, - GError **error) - { - guchar *p, *pixels, *and, *xor; - gint n_channels, v, x, y; - - if (icon->width > 255 || icon->height > 255) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_BAD_OPTION, - _("Image too large to be saved as ICO")); - return FALSE; - } - - if (hot_x > -1 && hot_y > -1) { - icon->hot_x = hot_x; - icon->hot_y = hot_y; - if (icon->hot_x >= icon->width || icon->hot_y >= icon->height) { - g_set_error_literal (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_BAD_OPTION, - _("Cursor hotspot outside image")); - return FALSE; - } - } - else { - icon->hot_x = -1; - icon->hot_y = -1; - } - - switch (icon->depth) { - case 32: - icon->xor_rowstride = icon->width * 4; - break; - case 24: - icon->xor_rowstride = icon->width * 3; - break; - case 16: - icon->xor_rowstride = icon->width * 2; - break; - default: - g_set_error (error, - GDK_PIXBUF_ERROR, - GDK_PIXBUF_ERROR_BAD_OPTION, - _("Unsupported depth for ICO file: %d"), icon->depth); - return FALSE; - } - - if ((icon->xor_rowstride % 4) != 0) - icon->xor_rowstride = 4 * ((icon->xor_rowstride / 4) + 1); - icon->xor = g_new0 (guchar, icon->xor_rowstride * icon->height); - - icon->and_rowstride = (icon->width + 7) / 8; - if ((icon->and_rowstride % 4) != 0) - icon->and_rowstride = 4 * ((icon->and_rowstride / 4) + 1); - icon->and = g_new0 (guchar, icon->and_rowstride * icon->height); - - pixels = gdk_pixbuf_get_pixels (pixbuf); - n_channels = gdk_pixbuf_get_n_channels (pixbuf); - for (y = 0; y < icon->height; y++) { - p = pixels + gdk_pixbuf_get_rowstride (pixbuf) * (icon->height - 1 - y); - and = icon->and + icon->and_rowstride * y; - xor = icon->xor + icon->xor_rowstride * y; - for (x = 0; x < icon->width; x++) { - switch (icon->depth) { - case 32: - xor[0] = p[2]; - xor[1] = p[1]; - xor[2] = p[0]; - xor[3] = 0xff; - if (n_channels == 4) { - xor[3] = p[3]; - if (p[3] < 0x80) - *and |= 1 << (7 - x % 8); - } - xor += 4; - break; - case 24: - xor[0] = p[2]; - xor[1] = p[1]; - xor[2] = p[0]; - if (n_channels == 4 && p[3] < 0x80) - *and |= 1 << (7 - x % 8); - xor += 3; - break; - case 16: - v = ((p[0] >> 3) << 10) | ((p[1] >> 3) << 5) | (p[2] >> 3); - xor[0] = v & 0xff; - xor[1] = v >> 8; - if (n_channels == 4 && p[3] < 0x80) - *and |= 1 << (7 - x % 8); - xor += 2; - break; - } - - p += n_channels; - if (x % 8 == 7) - and++; - } - } - - return TRUE; -} - -static void -free_entry (IconEntry *icon) -{ - g_free (icon->colors); - g_free (icon->and); - g_free (icon->xor); - g_free (icon); -} - -static void -write_icon (FILE *f, GSList *entries) -{ - IconEntry *icon; - GSList *entry; - guint8 bytes[4]; - guint16 words[4]; - guint32 dwords[6]; - gint type; - gint n_entries; - gint offset; - gint size; - - if (((IconEntry *)entries->data)->hot_x > -1) - type = 2; - else - type = 1; - n_entries = g_slist_length (entries); - - /* header */ - words[0] = 0; - words[1] = type; - words[2] = n_entries; - write16 (f, words, 3); - - offset = 6 + 16 * n_entries; - - for (entry = entries; entry; entry = entry->next) { - icon = (IconEntry *)entry->data; - size = 40 + icon->height * (icon->and_rowstride + icon->xor_rowstride); - - /* directory entry */ - bytes[0] = icon->width; - bytes[1] = icon->height; - bytes[2] = icon->n_colors; - bytes[3] = 0; - write8 (f, bytes, 4); - if (type == 1) { - words[0] = 1; - words[1] = icon->depth; - } - else { - words[0] = icon->hot_x; - words[1] = icon->hot_y; - } - write16 (f, words, 2); - dwords[0] = size; - dwords[1] = offset; - write32 (f, dwords, 2); - - offset += size; - } - - for (entry = entries; entry; entry = entry->next) { - icon = (IconEntry *)entry->data; - - /* bitmap header */ - dwords[0] = 40; - dwords[1] = icon->width; - dwords[2] = icon->height * 2; - write32 (f, dwords, 3); - words[0] = 1; - words[1] = icon->depth; - write16 (f, words, 2); - dwords[0] = 0; - dwords[1] = 0; - dwords[2] = 0; - dwords[3] = 0; - dwords[4] = 0; - dwords[5] = 0; - write32 (f, dwords, 6); - - /* image data */ - write8 (f, icon->xor, icon->xor_rowstride * icon->height); - write8 (f, icon->and, icon->and_rowstride * icon->height); - } -} - -static gboolean -gdk_pixbuf__ico_image_save (FILE *f, - GdkPixbuf *pixbuf, - gchar **keys, - gchar **values, - GError **error) -{ - gint hot_x, hot_y; - IconEntry *icon; - GSList *entries = NULL; - - /* support only single-image ICOs for now */ - icon = g_new0 (IconEntry, 1); - icon->width = gdk_pixbuf_get_width (pixbuf); - icon->height = gdk_pixbuf_get_height (pixbuf); - icon->depth = gdk_pixbuf_get_has_alpha (pixbuf) ? 32 : 24; - hot_x = -1; - hot_y = -1; - - /* parse options */ - if (keys && *keys) { - gchar **kiter; - gchar **viter; - - for (kiter = keys, viter = values; *kiter && *viter; kiter++, viter++) { - char *endptr; - if (strcmp (*kiter, "depth") == 0) { - sscanf (*viter, "%d", &icon->depth); - } - else if (strcmp (*kiter, "x_hot") == 0) { - hot_x = strtol (*viter, &endptr, 10); - } - else if (strcmp (*kiter, "y_hot") == 0) { - hot_y = strtol (*viter, &endptr, 10); - } - - } - } - - if (!fill_entry (icon, pixbuf, hot_x, hot_y, error)) { - free_entry (icon); - return FALSE; - } - - entries = g_slist_append (entries, icon); - write_icon (f, entries); - - g_slist_foreach (entries, (GFunc)free_entry, NULL); - g_slist_free (entries); - - return TRUE; -} - -#ifndef INCLUDE_ico -#define MODULE_ENTRY(function) G_MODULE_EXPORT void function -#else -#define MODULE_ENTRY(function) void _gdk_pixbuf__ico_ ## function -#endif - -MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module) -{ - module->begin_load = gdk_pixbuf__ico_image_begin_load; - module->stop_load = gdk_pixbuf__ico_image_stop_load; - module->load_increment = gdk_pixbuf__ico_image_load_increment; - module->save = gdk_pixbuf__ico_image_save; -} - -MODULE_ENTRY (fill_info) (GdkPixbufFormat *info) -{ - static GdkPixbufModulePattern signature[] = { - { " \x1 ", "zz znz", 100 }, - { " \x2 ", "zz znz", 100 }, - { NULL, NULL, 0 } - }; - static gchar * mime_types[] = { - "image/x-icon", - "image/x-ico", - "image/x-win-bitmap", - NULL - }; - static gchar * extensions[] = { - "ico", - "cur", - NULL - }; - - info->name = "ico"; - info->signature = signature; - info->description = N_("The ICO image format"); - info->mime_types = mime_types; - info->extensions = extensions; - info->flags = GDK_PIXBUF_FORMAT_WRITABLE | GDK_PIXBUF_FORMAT_THREADSAFE; - info->license = "LGPL"; -} - - - - |