--- winicon/icodialog.c	2006-10-05 20:37:03.000000000 +0300
+++ winicon-vista/icodialog.c	2006-10-03 09:31:18.000000000 +0300
@@ -35,6 +35,8 @@
 
 static void   ico_bpp_changed (GtkWidget *combo,
                                GObject   *hbox);
+static void   ico_toggle_compress (GtkWidget *checkbox,
+                                   GObject   *hbox);
 
 
 
@@ -126,6 +128,7 @@ ico_create_icon_hbox (GtkWidget   *icon_
   GtkWidget *vbox;
   GtkWidget *alignment;
   GtkWidget *combo;
+  GtkWidget *checkbox;
 
   hbox = gtk_hbox_new (FALSE, 6);
 
@@ -172,6 +175,14 @@ ico_create_icon_hbox (GtkWidget   *icon_
   gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
   gtk_widget_show (combo);
 
+  checkbox = gtk_check_button_new_with_mnemonic ("Compressed (PNG)");
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (checkbox),
+                                info->compress[layer_num]);
+  g_signal_connect (checkbox, "toggled",
+                    G_CALLBACK (ico_toggle_compress), hbox);
+  gtk_box_pack_start (GTK_BOX (vbox), checkbox, FALSE, FALSE, 0);
+  gtk_widget_show (checkbox);
+
   return hbox;
 }
 
@@ -438,3 +449,21 @@ ico_bpp_changed (GtkWidget *combo,
   ico_dialog_update_icon_preview (dialog, layer, bpp);
 }
 
+static void
+ico_toggle_compress (GtkWidget *checkbox,
+                     GObject   *hbox)
+{
+  GtkWidget   *dialog;
+  gint         layer_num;
+  IcoSaveInfo *info;
+
+  dialog = gtk_widget_get_toplevel (checkbox);
+
+  info = g_object_get_data (G_OBJECT (dialog), "save_info");
+  g_assert (info);
+  layer_num = GPOINTER_TO_INT (g_object_get_data (hbox, "icon_layer_num"));
+
+  /* Update vector entry for later when we're actually saving */
+  info->compress[layer_num] =
+    gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbox));
+}
--- winicon/icoload.c	2006-10-05 20:36:03.000000000 +0300
+++ winicon-vista/icoload.c	2006-10-05 19:31:44.000000000 +0300
@@ -28,6 +28,7 @@
 
 #include <libgimp/gimp.h>
 #include <libgimp/gimpui.h>
+#include <png.h>
 
 /* #define ICO_DBG */
 
@@ -140,13 +141,46 @@ gboolean
 ico_read_size (FILE        *fp,
                IcoLoadInfo *info)
 {
+  png_structp png_ptr;
+  png_infop   info_ptr;
+  png_uint_32 w, h;
+  gint32      bpp;
+  gint32      color_type;
   guint32     magic;
 
   if ( fseek (fp, info->offset, SEEK_SET) < 0 )
     return FALSE;
 
   ico_read_int32 (fp, &magic, 1);
-  if (magic == 40)
+  if (magic == ICO_PNG_MAGIC)
+    {
+      png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL,
+                                        NULL);
+      if ( !png_ptr )
+        return FALSE;
+      info_ptr = png_create_info_struct (png_ptr);
+      if ( !info_ptr )
+        {
+          png_destroy_read_struct (&png_ptr, NULL, NULL);
+          return FALSE;
+        }
+      if (setjmp (png_jmpbuf (png_ptr)))
+        {
+          png_destroy_read_struct (&png_ptr, NULL, NULL);
+          return FALSE;
+        }
+      png_init_io (png_ptr, fp);
+      png_set_sig_bytes (png_ptr, 4);
+      png_read_info (png_ptr, info_ptr);
+      png_get_IHDR (png_ptr, info_ptr, &w, &h, &bpp, &color_type,
+                    NULL, NULL, NULL);
+      png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
+      info->width = w;
+      info->height = h;
+      D(("ico_read_size: PNG: %ix%i\n", info->width, info->height));
+      return TRUE;
+    }
+  else if (magic == 40)
     {
       if (ico_read_int32 (fp, &info->width, 1)
           && ico_read_int32 (fp, &info->height, 1))
@@ -204,6 +238,96 @@ ico_read_info (FILE *fp,
   return info;
 }
 
+static gboolean
+ico_read_png (FILE    *fp,
+              guint32  header,
+              guchar  *buffer,
+              gint     maxsize,
+              gint    *width,
+              gint    *height)
+{
+  png_structp   png_ptr;
+  png_infop     info;
+  png_uint_32   w;
+  png_uint_32   h;
+  gint32        bit_depth;
+  gint32        color_type;
+  guint32     **rows;
+  gint          i;
+
+  png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+  if ( !png_ptr )
+    return FALSE;
+  info = png_create_info_struct (png_ptr);
+  if ( !info )
+    {
+      png_destroy_read_struct (&png_ptr, NULL, NULL);
+      return FALSE;
+    }
+
+  if (setjmp (png_jmpbuf (png_ptr)))
+    {
+      png_destroy_read_struct (&png_ptr, &info, NULL);
+      return FALSE;
+    }
+
+  png_init_io (png_ptr, fp);
+  png_set_sig_bytes (png_ptr, 4);
+  png_read_info (png_ptr, info);
+  png_get_IHDR (png_ptr, info, &w, &h, &bit_depth, &color_type,
+                NULL, NULL, NULL);
+  if (w*h*4 > maxsize)
+    {
+      png_destroy_read_struct (&png_ptr, &info, NULL);
+      return FALSE;
+    }
+  D(("ico_read_png: %ix%i, %i bits, %i type\n", (gint)w, (gint)h,
+     bit_depth, color_type));
+  switch (color_type)
+    {
+    case PNG_COLOR_TYPE_GRAY:
+      png_set_gray_1_2_4_to_8 (png_ptr);
+      if ( bit_depth == 16 )
+        png_set_strip_16 (png_ptr);
+      png_set_gray_to_rgb (png_ptr);
+      png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
+      break;
+    case PNG_COLOR_TYPE_GRAY_ALPHA:
+      png_set_gray_1_2_4_to_8 (png_ptr);
+      if ( bit_depth == 16 )
+        png_set_strip_16 (png_ptr);
+      png_set_gray_to_rgb (png_ptr);
+      break;
+    case PNG_COLOR_TYPE_PALETTE:
+      png_set_palette_to_rgb (png_ptr);
+      if (png_get_valid (png_ptr, info, PNG_INFO_tRNS))
+        png_set_tRNS_to_alpha (png_ptr);
+      else
+        png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
+      break;
+    case PNG_COLOR_TYPE_RGB:
+      if (bit_depth == 16)
+        png_set_strip_16 (png_ptr);
+      png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_AFTER);
+      break;
+    case PNG_COLOR_TYPE_RGB_ALPHA:
+      if (bit_depth == 16)
+        png_set_strip_16 (png_ptr);
+      break;
+    }
+
+  *width = w;
+  *height = h;
+  rows = g_new (guint32*, h);
+  rows[0] = (guint32*) buffer;
+  for (i = 1; i < h; i++)
+    rows[i] = rows[i-1] + w;
+  png_read_image (png_ptr, (png_bytepp) rows);
+  png_destroy_read_struct (&png_ptr, &info, NULL);
+  g_free (rows);
+  return TRUE;
+}
+
 gint
 ico_get_bit_from_data (const guint8 *data,
                        gint          line_width,
@@ -461,7 +585,12 @@ ico_load_layer (FILE        *fp,
        || !ico_read_int32 (fp, &first_bytes, 1) )
     return -1;
 
-  if (first_bytes == 40)
+  if (first_bytes == ICO_PNG_MAGIC)
+    {
+      if (!ico_read_png (fp, first_bytes, buffer, maxsize, &width, &height))
+        return -1;
+    }
+  else if (first_bytes == 40)
     {
       if (!ico_read_icon (fp, first_bytes, buffer, maxsize, &width, &height))
         return -1;
--- winicon/icosave.c	2006-10-05 19:23:53.000000000 +0300
+++ winicon-vista/icosave.c	2006-10-03 09:52:28.000000000 +0300
@@ -29,6 +29,8 @@
 #include <libgimp/gimp.h>
 #include <libgimp/gimpui.h>
 
+#include <png.h>
+
 /* #define ICO_DBG */
 
 #include "main.h"
@@ -164,6 +166,7 @@ ico_save_init (gint32 image_ID, IcoSaveI
   info->layers = layers;
   info->depths = g_new (gint, info->num_icons);
   info->default_depths = g_new (gint, info->num_icons);
+  info->compress = g_new (gboolean, info->num_icons);
 
   /* Limit the color depths to values that don't cause any color loss --
      the user should pick these anyway, so we can save her some time.
@@ -201,6 +204,17 @@ ico_save_init (gint32 image_ID, IcoSaveI
           /* Otherwise, or if real alpha levels are used, stick with 32bpp */
           info->default_depths [i] = 32;
         }
+
+      // vista icons
+      if (gimp_drawable_width (layers[i]) > 255
+          || gimp_drawable_height (layers[i]) > 255 )
+        {
+          info->compress[i] = TRUE;
+        }
+      else
+        {
+          info->compress[i] = FALSE;
+        }
     }
 
   /* set with default values */
@@ -672,6 +686,81 @@ ico_image_get_reduced_buf (guint32   lay
 }
 
 static gboolean
+ico_write_png (FILE   *fp,
+               gint32  layer,
+               gint32  depth)
+{
+  png_structp png_ptr;
+  png_infop   info_ptr;
+  png_byte  **row_pointers;
+  gint        i, rowstride;
+  gint        width, height;
+  gint        num_colors_used;
+  guchar     *palette;
+  guchar     *buffer;
+
+  row_pointers = NULL;
+  palette = NULL;
+  buffer = NULL;
+
+  width = gimp_drawable_width (layer);
+  height = gimp_drawable_height (layer);
+
+  png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+  if ( !png_ptr )
+    return FALSE;
+
+  info_ptr = png_create_info_struct (png_ptr);
+  if ( !info_ptr )
+    {
+      png_destroy_write_struct (&png_ptr, NULL);
+      return FALSE;
+    }
+
+  if (setjmp (png_jmpbuf (png_ptr)))
+    {
+      png_destroy_write_struct (&png_ptr, &info_ptr);
+      if ( row_pointers )
+        g_free (row_pointers);
+      if (palette)
+        g_free (palette);
+      if (buffer)
+        g_free (buffer);
+      return FALSE;
+    }
+
+  ico_image_get_reduced_buf (layer, depth, &num_colors_used,
+                             &palette, &buffer);
+
+  png_init_io (png_ptr, fp);
+  png_set_IHDR (png_ptr, info_ptr, width, height,
+                8,
+                PNG_COLOR_TYPE_RGBA,
+                PNG_INTERLACE_NONE,
+                PNG_COMPRESSION_TYPE_DEFAULT,
+                PNG_FILTER_TYPE_DEFAULT);
+  png_write_info (png_ptr, info_ptr);
+
+  rowstride = ico_rowstride (width, 32);
+  row_pointers = g_new (png_byte*, height);
+  for (i = 0; i < height; i++)
+    {
+      row_pointers[i] = buffer + rowstride * i;
+    }
+  png_write_image (png_ptr, row_pointers);
+
+  row_pointers = NULL;
+
+  png_write_end (png_ptr, info_ptr);
+  png_destroy_write_struct (&png_ptr, &info_ptr);
+
+  g_free (row_pointers);
+  g_free (palette);
+  g_free (buffer);
+  return TRUE;
+}
+
+static gboolean
 ico_write_icon (FILE   *fp,
                 gint32  layer,
                 gint32  depth)
@@ -891,6 +980,7 @@ ico_save_info_free (IcoSaveInfo  *info)
 {
   g_free (info->depths);
   g_free (info->default_depths);
+  g_free (info->compress);
   g_free (info->layers);
   memset (info, 0, sizeof (IcoSaveInfo));
 }
@@ -974,7 +1064,10 @@ ico_save_image (const gchar *filename,
       entries[i].planes = 1;
       entries[i].bpp = info.depths[i];
       entries[i].offset = ftell (fp);
-      saved = ico_write_icon (fp, info.layers[i], info.depths[i]);
+      if (info.compress[i])
+        saved = ico_write_png (fp, info.layers[i], info.depths[i]);
+      else
+        saved = ico_write_icon (fp, info.layers[i], info.depths[i]);
       if (!saved)
         {
           ico_save_info_free (&info);
--- winicon/main.h	2006-10-05 19:17:06.000000000 +0300
+++ winicon-vista/main.h	2006-10-02 20:55:34.000000000 +0300
@@ -33,6 +33,7 @@
 #define D(x)
 #endif
 
+#define ICO_PNG_MAGIC       0x474e5089
 #define ICO_ALPHA_THRESHOLD 127
 #define ICO_MAXBUF          4096
 
@@ -85,6 +86,7 @@ typedef struct _IcoSaveInfo
 {
     gint        *depths;
     gint        *default_depths;
+    gboolean    *compress;
     gint        *layers;
     gint         num_icons;
 } IcoSaveInfo;
--- winicon/Makefile.am	2006-10-05 19:02:08.000000000 +0300
+++ winicon-vista/Makefile.am	2006-10-03 10:29:53.000000000 +0300
@@ -18,6 +18,8 @@ libexecdir = $(gimpplugindir)/plug-ins
 
 libexec_PROGRAMS = winicon
 
+winicon_CFLAGS = $(PNG_CFLAGS)
+
 winicon_SOURCES = \
 	icodialog.c	\
 	icodialog.h	\
@@ -41,6 +43,7 @@ LDADD = \
 	$(libgimpcolor)		\
 	$(libgimpmath)		\
 	$(libgimpbase)		\
+	$(LIBPNG)		\
 	$(GTK_LIBS)		\
 	$(RT_LIBS)		\
 	$(INTLLIBS)
