[gimp/alxsa-load-icns] plug-ins: Add support for loading .icns files




commit 6c1efc277184796775c8d097cbd7aa8e6112573c
Author: Alx Sa <cmyk student gmail com>
Date:   Sat Oct 15 14:12:02 2022 +0000

    plug-ins: Add support for loading .icns files
    
    This ports ICNS loading code from Brion Vibber's 2004 plug-in.
    It extends support for ICNS files that contain PNG or JP2 format icons.

 configure.ac                        |   1 +
 plug-ins/Makefile.am                |   1 +
 plug-ins/file-icns/Makefile.am      |  55 ++++
 plug-ins/file-icns/file-icns-data.c | 373 ++++++++++++++++++++++
 plug-ins/file-icns/file-icns-data.h |  39 +++
 plug-ins/file-icns/file-icns-load.c | 621 ++++++++++++++++++++++++++++++++++++
 plug-ins/file-icns/file-icns-load.h |  34 ++
 plug-ins/file-icns/file-icns.c      | 236 ++++++++++++++
 plug-ins/file-icns/file-icns.h      |  58 ++++
 plug-ins/file-icns/meson.build      |  31 ++
 plug-ins/meson.build                |   1 +
 po-plug-ins/POTFILES.in             |   2 +
 12 files changed, 1452 insertions(+)
---
diff --git a/configure.ac b/configure.ac
index 231f6a173d..c803fd00a5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3091,6 +3091,7 @@ plug-ins/file-exr/Makefile
 plug-ins/file-faxg3/Makefile
 plug-ins/file-fits/Makefile
 plug-ins/file-fli/Makefile
+plug-ins/file-icns/Makefile
 plug-ins/file-ico/Makefile
 plug-ins/file-jpeg/Makefile
 plug-ins/file-psd/Makefile
diff --git a/plug-ins/Makefile.am b/plug-ins/Makefile.am
index 6384022430..06d5cabfeb 100644
--- a/plug-ins/Makefile.am
+++ b/plug-ins/Makefile.am
@@ -33,6 +33,7 @@ SUBDIRS = \
        file-faxg3              \
        file-fits               \
        file-fli                \
+       file-icns               \
        file-ico                \
        file-jpeg               \
        file-psd                \
diff --git a/plug-ins/file-icns/Makefile.am b/plug-ins/file-icns/Makefile.am
new file mode 100644
index 0000000000..5ece7f8f86
--- /dev/null
+++ b/plug-ins/file-icns/Makefile.am
@@ -0,0 +1,55 @@
+## Process this file with automake to produce Makefile.in
+
+libgimpui = $(top_builddir)/libgimp/libgimpui-$(GIMP_API_VERSION).la
+libgimpconfig = $(top_builddir)/libgimpconfig/libgimpconfig-$(GIMP_API_VERSION).la
+libgimpwidgets = $(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la
+libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la
+libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
+libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la
+libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
+
+if OS_WIN32
+mwindows = -mwindows
+endif
+
+if HAVE_WINDRES
+include $(top_srcdir)/build/windows/gimprc-plug-ins.rule
+file_icns_RC = file-icns.rc.o
+endif
+
+AM_LDFLAGS = $(mwindows)
+
+libexecdir = $(gimpplugindir)/plug-ins/file-icns
+
+libexec_PROGRAMS = file-icns
+
+file_icns_CFLAGS = $(PNG_CFLAGS)
+
+file_icns_SOURCES = \
+       file-icns-data.c        \
+       file-icns-data.h        \
+       file-icns-load.c        \
+       file-icns-load.h        \
+       file-icns.c     \
+       file-icns.h
+
+AM_CPPFLAGS = \
+       -I$(top_srcdir) \
+       $(GTK_CFLAGS)   \
+       $(GEGL_CFLAGS) \
+       -I$(includedir)
+
+LDADD = \
+       $(libgimpui)            \
+       $(libgimpwidgets)       \
+       $(libgimpconfig)        \
+       $(libgimp)              \
+       $(libgimpcolor)         \
+       $(libgimpmath)          \
+       $(libgimpbase)          \
+       $(GTK_LIBS)             \
+       $(GEGL_LIBS)            \
+       $(PNG_LIBS)             \
+       $(RT_LIBS)              \
+       $(INTLLIBS)             \
+       $(file_icns_RC)
diff --git a/plug-ins/file-icns/file-icns-data.c b/plug-ins/file-icns/file-icns-data.c
new file mode 100644
index 0000000000..febb56ed4b
--- /dev/null
+++ b/plug-ins/file-icns/file-icns-data.c
@@ -0,0 +1,373 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
+ *
+ * file-icns-data.c
+ * Copyright (C) 2004 Brion Vibber <brion pobox com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include "file-icns-data.h"
+
+/* Ported from Brion Vibber's icnsdata.c code, under the GPL license, version 3
+ * or any later version of the license */
+IconType iconTypes[] =
+{
+  /* 1-bit, no mask? */
+  {"SICN",  16,  16,  1, 0, FALSE},
+  {"ICON",  32,  32,  1, 0, FALSE},
+
+  /* 1-bit image and hitmask */
+  {"icm#",  12,  12,  1, "icm#", FALSE},
+  {"ics#",  16,  16,  1, "ics#", FALSE},
+  {"ICN#",  32,  32,  1, "ICN#", FALSE},
+  {"ich#",  48,  48,  1, "ich#", FALSE},
+
+  /* 4-bit. Use mask from binary. */
+  {"icm4",  12,  12,  4, "icm#", FALSE},
+  {"ics4",  16,  16,  4, "ics#", FALSE},
+  {"icl4",  32,  32,  4, "ICN#", FALSE},
+  {"ich4",  48,  48,  4, "ich#", FALSE},
+
+  /* 8-bit. Use mask from binary. */
+  {"icm8",  12,  12,  8, "icm#", FALSE},
+  {"ics8",  16,  16,  8, "ics#", FALSE},
+  {"icl8",  32,  32,  8, "ICN#", FALSE},
+  {"ich8",  48,  48,  8, "ich#", FALSE},
+
+  /* 32-bit color icons; separate 8-bit alpha */
+  {"is32",  16,  16, 32, "s8mk", FALSE},
+  {"il32",  32,  32, 32, "l8mk", FALSE},
+  {"ih32",  48,  48, 32, "h8mk", FALSE},
+  {"it32", 128, 128, 32, "t8mk", FALSE},
+
+  /* Post-MacOS 10.0 ICNS formats */
+  /* PNG, JPEG 2000, or 24-bit RGB */
+  {"icp4",   16,   16, 32, "N/A", TRUE},
+  {"icp5",   32,   32, 32, "N/A", TRUE},
+
+  /* PNG or JPEG 2000 */
+  {"icp6",   48,   48, 0, "N/A", TRUE},
+  {"ic07",  128,  128, 0, "N/A", TRUE},
+  {"ic08",  256,  256, 0, "N/A", TRUE},
+  {"ic09",  512,  512, 0, "N/A", TRUE},
+  {"sb24",   24,   24, 0, "N/A", TRUE},
+
+  /* PNG or JPEG 2000 (Retina) */
+  {"ic10", 1024, 1024, 0, "N/A", TRUE},
+  {"ic11",   32,   32, 0, "N/A", TRUE},
+  {"ic12",   64,   64, 0, "N/A", TRUE},
+  {"ic13",  256,  256, 0, "N/A", TRUE},
+  {"ic14",  512,  512, 0, "N/A", TRUE},
+  {"icsB",   36,   36, 0, "N/A", TRUE},
+  {"SB24",   48,   48, 0, "N/A", TRUE},
+
+  /* ARGB, PNG, or JPEG 2000 */
+  {"ic04",   16,   16, 0, "N/A", TRUE},
+  {"icsb",   18,   18, 0, "N/A", TRUE},
+
+  {0, 0, 0, 0, 0}
+};
+
+IconType maskTypes[] =
+{
+  /* 8-bit masks */
+  {"s8mk",  16,  16,  8, 0},
+  {"l8mk",  32,  32,  8, 0},
+  {"h8mk",  48,  48,  8, 0},
+  {"t8mk", 128, 128,  8, 0},
+
+  {0, 0, 0, 0, 0}
+};
+
+guchar icns_colormap_4[] =
+{
+    0xFF, 0xFF, 0xFF,
+    0xFC, 0xF3, 0x05,
+    0xFF, 0x64, 0x02,
+    0xDD, 0x08, 0x06,
+    0xF2, 0x08, 0x84,
+    0x46, 0x00, 0xA5,
+    0x00, 0x00, 0xD4,
+    0x02, 0xAB, 0xEA,
+    0x1F, 0xB7, 0x14,
+    0x00, 0x64, 0x11,
+    0x56, 0x2C, 0x05,
+    0x90, 0x71, 0x3A,
+    0xC0, 0xC0, 0xC0,
+    0x80, 0x80, 0x80,
+    0x40, 0x40, 0x40,
+    0x00, 0x00, 0x00
+};
+
+guchar icns_colormap_8[] =
+{
+    0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xCC,
+    0xFF, 0xFF, 0x99,
+    0xFF, 0xFF, 0x66,
+    0xFF, 0xFF, 0x33,
+    0xFF, 0xFF, 0x00,
+    0xFF, 0xCC, 0xFF,
+    0xFF, 0xCC, 0xCC,
+    0xFF, 0xCC, 0x99,
+    0xFF, 0xCC, 0x66,
+    0xFF, 0xCC, 0x33,
+    0xFF, 0xCC, 0x00,
+    0xFF, 0x99, 0xFF,
+    0xFF, 0x99, 0xCC,
+    0xFF, 0x99, 0x99,
+    0xFF, 0x99, 0x66,
+    0xFF, 0x99, 0x33,
+    0xFF, 0x99, 0x00,
+    0xFF, 0x66, 0xFF,
+    0xFF, 0x66, 0xCC,
+    0xFF, 0x66, 0x99,
+    0xFF, 0x66, 0x66,
+    0xFF, 0x66, 0x33,
+    0xFF, 0x66, 0x00,
+    0xFF, 0x33, 0xFF,
+    0xFF, 0x33, 0xCC,
+    0xFF, 0x33, 0x99,
+    0xFF, 0x33, 0x66,
+    0xFF, 0x33, 0x33,
+    0xFF, 0x33, 0x00,
+    0xFF, 0x00, 0xFF,
+    0xFF, 0x00, 0xCC,
+    0xFF, 0x00, 0x99,
+    0xFF, 0x00, 0x66,
+    0xFF, 0x00, 0x33,
+    0xFF, 0x00, 0x00,
+    0xCC, 0xFF, 0xFF,
+    0xCC, 0xFF, 0xCC,
+    0xCC, 0xFF, 0x99,
+    0xCC, 0xFF, 0x66,
+    0xCC, 0xFF, 0x33,
+    0xCC, 0xFF, 0x00,
+    0xCC, 0xCC, 0xFF,
+    0xCC, 0xCC, 0xCC,
+    0xCC, 0xCC, 0x99,
+    0xCC, 0xCC, 0x66,
+    0xCC, 0xCC, 0x33,
+    0xCC, 0xCC, 0x00,
+    0xCC, 0x99, 0xFF,
+    0xCC, 0x99, 0xCC,
+    0xCC, 0x99, 0x99,
+    0xCC, 0x99, 0x66,
+    0xCC, 0x99, 0x33,
+    0xCC, 0x99, 0x00,
+    0xCC, 0x66, 0xFF,
+    0xCC, 0x66, 0xCC,
+    0xCC, 0x66, 0x99,
+    0xCC, 0x66, 0x66,
+    0xCC, 0x66, 0x33,
+    0xCC, 0x66, 0x00,
+    0xCC, 0x33, 0xFF,
+    0xCC, 0x33, 0xCC,
+    0xCC, 0x33, 0x99,
+    0xCC, 0x33, 0x66,
+    0xCC, 0x33, 0x33,
+    0xCC, 0x33, 0x00,
+    0xCC, 0x00, 0xFF,
+    0xCC, 0x00, 0xCC,
+    0xCC, 0x00, 0x99,
+    0xCC, 0x00, 0x66,
+    0xCC, 0x00, 0x33,
+    0xCC, 0x00, 0x00,
+    0x99, 0xFF, 0xFF,
+    0x99, 0xFF, 0xCC,
+    0x99, 0xFF, 0x99,
+    0x99, 0xFF, 0x66,
+    0x99, 0xFF, 0x33,
+    0x99, 0xFF, 0x00,
+    0x99, 0xCC, 0xFF,
+    0x99, 0xCC, 0xCC,
+    0x99, 0xCC, 0x99,
+    0x99, 0xCC, 0x66,
+    0x99, 0xCC, 0x33,
+    0x99, 0xCC, 0x00,
+    0x99, 0x99, 0xFF,
+    0x99, 0x99, 0xCC,
+    0x99, 0x99, 0x99,
+    0x99, 0x99, 0x66,
+    0x99, 0x99, 0x33,
+    0x99, 0x99, 0x00,
+    0x99, 0x66, 0xFF,
+    0x99, 0x66, 0xCC,
+    0x99, 0x66, 0x99,
+    0x99, 0x66, 0x66,
+    0x99, 0x66, 0x33,
+    0x99, 0x66, 0x00,
+    0x99, 0x33, 0xFF,
+    0x99, 0x33, 0xCC,
+    0x99, 0x33, 0x99,
+    0x99, 0x33, 0x66,
+    0x99, 0x33, 0x33,
+    0x99, 0x33, 0x00,
+    0x99, 0x00, 0xFF,
+    0x99, 0x00, 0xCC,
+    0x99, 0x00, 0x99,
+    0x99, 0x00, 0x66,
+    0x99, 0x00, 0x33,
+    0x99, 0x00, 0x00,
+    0x66, 0xFF, 0xFF,
+    0x66, 0xFF, 0xCC,
+    0x66, 0xFF, 0x99,
+    0x66, 0xFF, 0x66,
+    0x66, 0xFF, 0x33,
+    0x66, 0xFF, 0x00,
+    0x66, 0xCC, 0xFF,
+    0x66, 0xCC, 0xCC,
+    0x66, 0xCC, 0x99,
+    0x66, 0xCC, 0x66,
+    0x66, 0xCC, 0x33,
+    0x66, 0xCC, 0x00,
+    0x66, 0x99, 0xFF,
+    0x66, 0x99, 0xCC,
+    0x66, 0x99, 0x99,
+    0x66, 0x99, 0x66,
+    0x66, 0x99, 0x33,
+    0x66, 0x99, 0x00,
+    0x66, 0x66, 0xFF,
+    0x66, 0x66, 0xCC,
+    0x66, 0x66, 0x99,
+    0x66, 0x66, 0x66,
+    0x66, 0x66, 0x33,
+    0x66, 0x66, 0x00,
+    0x66, 0x33, 0xFF,
+    0x66, 0x33, 0xCC,
+    0x66, 0x33, 0x99,
+    0x66, 0x33, 0x66,
+    0x66, 0x33, 0x33,
+    0x66, 0x33, 0x00,
+    0x66, 0x00, 0xFF,
+    0x66, 0x00, 0xCC,
+    0x66, 0x00, 0x99,
+    0x66, 0x00, 0x66,
+    0x66, 0x00, 0x33,
+    0x66, 0x00, 0x00,
+    0x33, 0xFF, 0xFF,
+    0x33, 0xFF, 0xCC,
+    0x33, 0xFF, 0x99,
+    0x33, 0xFF, 0x66,
+    0x33, 0xFF, 0x33,
+    0x33, 0xFF, 0x00,
+    0x33, 0xCC, 0xFF,
+    0x33, 0xCC, 0xCC,
+    0x33, 0xCC, 0x99,
+    0x33, 0xCC, 0x66,
+    0x33, 0xCC, 0x33,
+    0x33, 0xCC, 0x00,
+    0x33, 0x99, 0xFF,
+    0x33, 0x99, 0xCC,
+    0x33, 0x99, 0x99,
+    0x33, 0x99, 0x66,
+    0x33, 0x99, 0x33,
+    0x33, 0x99, 0x00,
+    0x33, 0x66, 0xFF,
+    0x33, 0x66, 0xCC,
+    0x33, 0x66, 0x99,
+    0x33, 0x66, 0x66,
+    0x33, 0x66, 0x33,
+    0x33, 0x66, 0x00,
+    0x33, 0x33, 0xFF,
+    0x33, 0x33, 0xCC,
+    0x33, 0x33, 0x99,
+    0x33, 0x33, 0x66,
+    0x33, 0x33, 0x33,
+    0x33, 0x33, 0x00,
+    0x33, 0x00, 0xFF,
+    0x33, 0x00, 0xCC,
+    0x33, 0x00, 0x99,
+    0x33, 0x00, 0x66,
+    0x33, 0x00, 0x33,
+    0x33, 0x00, 0x00,
+    0x00, 0xFF, 0xFF,
+    0x00, 0xFF, 0xCC,
+    0x00, 0xFF, 0x99,
+    0x00, 0xFF, 0x66,
+    0x00, 0xFF, 0x33,
+    0x00, 0xFF, 0x00,
+    0x00, 0xCC, 0xFF,
+    0x00, 0xCC, 0xCC,
+    0x00, 0xCC, 0x99,
+    0x00, 0xCC, 0x66,
+    0x00, 0xCC, 0x33,
+    0x00, 0xCC, 0x00,
+    0x00, 0x99, 0xFF,
+    0x00, 0x99, 0xCC,
+    0x00, 0x99, 0x99,
+    0x00, 0x99, 0x66,
+    0x00, 0x99, 0x33,
+    0x00, 0x99, 0x00,
+    0x00, 0x66, 0xFF,
+    0x00, 0x66, 0xCC,
+    0x00, 0x66, 0x99,
+    0x00, 0x66, 0x66,
+    0x00, 0x66, 0x33,
+    0x00, 0x66, 0x00,
+    0x00, 0x33, 0xFF,
+    0x00, 0x33, 0xCC,
+    0x00, 0x33, 0x99,
+    0x00, 0x33, 0x66,
+    0x00, 0x33, 0x33,
+    0x00, 0x33, 0x00,
+    0x00, 0x00, 0xFF,
+    0x00, 0x00, 0xCC,
+    0x00, 0x00, 0x99,
+    0x00, 0x00, 0x66,
+    0x00, 0x00, 0x33,
+    0xEE, 0x00, 0x00,
+    0xDD, 0x00, 0x00,
+    0xBB, 0x00, 0x00,
+    0xAA, 0x00, 0x00,
+    0x88, 0x00, 0x00,
+    0x77, 0x00, 0x00,
+    0x55, 0x00, 0x00,
+    0x44, 0x00, 0x00,
+    0x22, 0x00, 0x00,
+    0x11, 0x00, 0x00,
+    0x00, 0xEE, 0x00,
+    0x00, 0xDD, 0x00,
+    0x00, 0xBB, 0x00,
+    0x00, 0xAA, 0x00,
+    0x00, 0x88, 0x00,
+    0x00, 0x77, 0x00,
+    0x00, 0x55, 0x00,
+    0x00, 0x44, 0x00,
+    0x00, 0x22, 0x00,
+    0x00, 0x11, 0x00,
+    0x00, 0x00, 0xEE,
+    0x00, 0x00, 0xDD,
+    0x00, 0x00, 0xBB,
+    0x00, 0x00, 0xAA,
+    0x00, 0x00, 0x88,
+    0x00, 0x00, 0x77,
+    0x00, 0x00, 0x55,
+    0x00, 0x00, 0x44,
+    0x00, 0x00, 0x22,
+    0x00, 0x00, 0x11,
+    0xEE, 0xEE, 0xEE,
+    0xDD, 0xDD, 0xDD,
+    0xBB, 0xBB, 0xBB,
+    0xAA, 0xAA, 0xAA,
+    0x88, 0x88, 0x88,
+    0x77, 0x77, 0x77,
+    0x55, 0x55, 0x55,
+    0x44, 0x44, 0x44,
+    0x22, 0x22, 0x22,
+    0x11, 0x11, 0x11,
+    0x00, 0x00, 0x00
+};
diff --git a/plug-ins/file-icns/file-icns-data.h b/plug-ins/file-icns/file-icns-data.h
new file mode 100644
index 0000000000..705bed33f1
--- /dev/null
+++ b/plug-ins/file-icns/file-icns-data.h
@@ -0,0 +1,39 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
+ *
+ * file-icns-data.h
+ * Copyright (C) 2004 Brion Vibber <brion pobox com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef _ICNS_DATA_H
+#define _ICNS_DATA_H
+
+typedef struct _IconType
+{
+  gchar    *type;
+  guint     width;
+  guint     height;
+  guint     bits;
+  gchar    *mask;
+  gboolean  isModern; /* OSX icns files */
+} IconType;
+
+extern IconType iconTypes[];
+extern IconType maskTypes[];
+extern guchar   icns_colormap_4[];
+extern guchar   icns_colormap_8[];
+
+#endif
diff --git a/plug-ins/file-icns/file-icns-load.c b/plug-ins/file-icns/file-icns-load.c
new file mode 100644
index 0000000000..82e34541e7
--- /dev/null
+++ b/plug-ins/file-icns/file-icns-load.c
@@ -0,0 +1,621 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
+ *
+ * file-icns-load.c
+ * Copyright (C) 2004 Brion Vibber <brion pobox com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include <glib/gstdio.h>
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include <png.h>
+
+/* #define ICNS_DBG */
+
+#include "file-icns.h"
+#include "file-icns-data.h"
+#include "file-icns-load.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+IcnsResource * resource_load     (FILE         *file);
+
+IcnsResource * resource_find     (IcnsResource *list,
+                                  gchar        *type,
+                                  gint          max);
+
+gboolean       resource_get_next (IcnsResource *icns,
+                                  IcnsResource *res);
+
+void           icns_slurp        (guchar       *dest,
+                                  IconType     *icontype,
+                                  IcnsResource *icns,
+                                  IcnsResource *mask);
+
+gboolean       icns_decompress   (guchar       *dest,
+                                  IconType     *icontype,
+                                  IcnsResource *image,
+                                  IcnsResource *mask);
+
+void           icns_attach_image (GimpImage    *image,
+                                  IconType     *icontype,
+                                  IcnsResource *icns,
+                                  IcnsResource *mask,
+                                  gboolean      isOSX);
+
+GimpImage *    icns_load         (IcnsResource *icns,
+                                  GFile        *file);
+
+/* Ported from Brion Vibber's icnsload.c code, under the GPL license, version 3
+ * or any later version of the license */
+IcnsResource *
+resource_load (FILE *file)
+{
+  IcnsResource *res = NULL;
+
+  if (file)
+    {
+      IcnsResourceHeader header;
+
+      if (1 == fread (&header, sizeof (IcnsResourceHeader), 1, file))
+        {
+          gchar   type[5];
+          guint32 size;
+
+          strncpy (type, header.type, 4);
+          type[4] = '\0';
+          size = GUINT32_FROM_BE (header.size);
+
+          if (! strncmp (header.type, "icns", 4) && size > sizeof (IcnsResourceHeader))
+            {
+              res = (IcnsResource *) g_new (guchar, sizeof (IcnsResource) + size);
+              strncpy (res->type, header.type, 4);
+              res->type[4] = '\0';
+              res->size = size;
+              res->cursor = sizeof (IcnsResourceHeader);
+              res->data = (guchar *) res + sizeof (IcnsResource);
+              fseek (file, 0, SEEK_SET);
+
+              if (size != fread (res->data, 1, res->size, file))
+                {
+                  g_message ("** expected %d bytes\n", size);
+                  g_free (res);
+                  res = NULL;
+                }
+            }
+        }
+      else
+        {
+          g_message (("** couldn't read icns header.\n"));
+        }
+      fclose (file);
+    }
+  else
+    {
+      g_message (("** couldn't open file.\n"));
+    }
+  return res;
+}
+
+IcnsResource *
+resource_find (IcnsResource *list,
+               gchar        *type,
+               gint          max)
+{
+       for (gint i = 0; i < max; i++)
+         {
+           if (! strncmp (list[i].type, type, 4))
+             return &list[i];
+         }
+       return NULL;
+}
+
+gboolean
+resource_get_next (IcnsResource *icns,
+                   IcnsResource *res)
+{
+  IcnsResourceHeader *header;
+
+  if (icns->size - icns->cursor < sizeof (IcnsResourceHeader))
+    return FALSE;
+
+  header = (IcnsResourceHeader *) &(icns->data[icns->cursor]);
+  strncpy (res->type, header->type, 4);
+  res->size   = GUINT32_FROM_BE (header->size);
+  res->cursor = sizeof (IcnsResourceHeader);
+  res->data   = &(icns->data[icns->cursor]);
+
+  icns->cursor += res->size;
+  if (icns->cursor > icns->size)
+    {
+      gchar typestring[5];
+      fourcc_get_string (icns->type, typestring);
+      g_message ("icns resource_get_next: resource too big! type '%s', size %u\n",
+                 typestring, icns->size);
+
+      return FALSE;
+    }
+  return TRUE;
+}
+
+GimpImage *
+icns_load (IcnsResource *icns,
+           GFile        *file)
+{
+  IcnsResource *resources;
+  guint         nResources;
+  gfloat        current_resources = 0;
+  GimpImage    *image;
+
+  resources = g_new (IcnsResource, 256);
+
+  /* Largest .icns icon is 1024 x 1024 */
+  image = gimp_image_new (1024, 1024, GIMP_RGB);
+  gimp_image_set_file (image, file);
+
+  nResources = 0;
+  while (resource_get_next (icns, &resources[nResources++])) {}
+
+  for (gint i = 0; iconTypes[i].type; i++)
+    {
+      IcnsResource *icns;
+      IcnsResource *mask = NULL;
+
+      if ((icns = resource_find (resources, iconTypes[i].type, nResources)))
+        {
+          if (! iconTypes[i].isModern)
+            mask = resource_find (resources, iconTypes[i].mask, nResources);
+
+          icns_attach_image (image, &iconTypes[i], icns, mask, iconTypes[i].isModern);
+
+          gimp_progress_update (current_resources++ / nResources);
+        }
+    }
+
+  gimp_image_resize_to_layers (image);
+  g_free (resources);
+  return image;
+}
+
+void
+icns_slurp (guchar       *dest,
+            IconType     *icontype,
+            IcnsResource *icns,
+            IcnsResource *mask)
+{
+  guint  out;
+  guint  max;
+  guchar bucket = 0;
+  guchar bit;
+  guint  index;
+
+  max = icontype->width * icontype->height;
+  icns->cursor = sizeof (IcnsResourceHeader);
+
+  switch (icontype->bits)
+    {
+      case 1:
+        for (out = 0; out < max; out++)
+          {
+            if (out % 8 == 0)
+              bucket = icns->data[icns->cursor++];
+
+            bit = (bucket & 0x80) ? 0 : 255;
+            bucket = bucket << 1;
+            dest[out * 4]     = bit;
+            dest[out * 4 + 1] = bit;
+            dest[out * 4 + 2] = bit;
+          }
+        break;
+      case 4:
+        for (out = 0; out < max; out++)
+          {
+            if (out % 2 == 0)
+              bucket = icns->data[icns->cursor++];
+
+            index = 3 * (bucket & 0xf0) >> 4;
+            bucket = bucket << 4;
+            dest[out * 4]     = icns_colormap_4[index];
+            dest[out * 4 + 1] = icns_colormap_4[index + 1];
+            dest[out * 4 + 2] = icns_colormap_4[index + 2];
+          }
+        break;
+      case 8:
+        for (out = 0; out < max; out++)
+          {
+            index = 3 * icns->data[icns->cursor++];
+            dest[out * 4]     = icns_colormap_8[index];
+            dest[out * 4 + 1] = icns_colormap_8[index + 1];
+            dest[out * 4 + 2] = icns_colormap_8[index + 2];
+            dest[out * 4 + 3] = 255;
+          }
+        break;
+      case 32:
+        for (out = 0; out < max; out++)
+          {
+            dest[out * 4]     = icns->data[icns->cursor++];
+            dest[out * 4 + 1] = icns->data[icns->cursor++];
+            dest[out * 4 + 2] = icns->data[icns->cursor++];
+            /* Throw away alpha, use the mask */
+            icns->cursor++;
+            if (mask)
+              dest[out * 4 + 3] = icns->data[mask->cursor++];
+            else
+              dest[out * 4 + 3] = 255;
+          }
+        break;
+      }
+
+    /* Now for the mask */
+    if (mask && icontype->bits != 32)
+      {
+        mask->cursor = sizeof (IcnsResourceHeader) + icontype->width * icontype->height / 8;
+        for (out = 0; out < max; out++)
+          {
+            if (out % 8 == 0)
+              bucket = mask->data[mask->cursor++];
+
+            bit = (bucket & 0x80) ? 255 : 0;
+            bucket = bucket << 1;
+            dest[out * 4 + 3] = bit;
+          }
+      }
+}
+
+gboolean
+icns_decompress (guchar       *dest,
+                 IconType     *icontype,
+                 IcnsResource *image,
+                 IcnsResource *mask)
+{
+  guint  max;
+  guint  channel;
+  guint  out;
+  guchar run;
+  guchar val;
+  gint   n_channels = 3;
+
+  max = icontype->width * icontype->height;
+  memset (dest, 255, max * 4);
+
+  /* For some reason there seem to be 4 null bytes at the start of an it32. */
+  if (! strncmp (icontype->type, "it32", 4))
+    image->cursor += 4;
+
+  for (channel = 0; channel < n_channels; channel++)
+    {
+      out = 0;
+      while (out < max)
+        {
+          run = image->data[image->cursor++];
+
+          if (run & 0x80)
+            {
+              /* Compressed */
+              if (image->cursor >= image->size)
+                {
+                  g_message ("Corrupt icon: compressed run overflows input size.");
+                  return FALSE;
+                }
+
+              val = image->data[image->cursor++];
+
+              for (run -= 125; run > 0; run--)
+                {
+                  if (out >= max)
+                    {
+                      g_message ("Corrupt icon? compressed run overflows output size.");
+                      return FALSE;
+                    }
+                  dest[out++ * 4 + channel] = val;
+                }
+            }
+          else
+            {
+              /* Uncompressed */
+              for (run += 1; run > 0; run--)
+                {
+                  if (image->cursor >= image->size)
+                    {
+                      g_message ("Corrupt icon: uncompressed run overflows input size.");
+                      return FALSE;
+                    }
+                  if (out >= max)
+                    {
+                      g_message ("Corrupt icon: uncompressed run overflows output size.");
+                      return FALSE;
+                    }
+                  dest[out++ * 4 + channel] = image->data[image->cursor++];
+                }
+            }
+        }
+    }
+
+    if (mask)
+      {
+        gchar typestring[5];
+        fourcc_get_string (mask->type, typestring);
+
+        for (out = 0; out < max; out++)
+          dest[out * 4 + 3] = mask->data[mask->cursor++];
+      }
+    return TRUE;
+}
+
+void
+icns_attach_image (GimpImage    *image,
+                   IconType     *icontype,
+                   IcnsResource *icns,
+                   IcnsResource *mask,
+                   gboolean      isOSX)
+{
+  gchar           layer_name[5];
+  guchar         *dest;
+  GimpLayer      *layer;
+  GeglBuffer     *buffer;
+  guint           row;
+  guint           expected_size;
+  gboolean        layer_loaded = FALSE;
+
+  strncpy (layer_name, icontype->type, 4);
+  layer_name[4] = '\0';
+
+  row = 4 * icontype->width;
+  dest = g_malloc (row * icontype->height);
+
+  expected_size =
+    (icontype->width * icontype->height * icontype->bits) / 8;
+
+  if (icns == mask)
+    expected_size *= 2;
+
+  expected_size += sizeof (IcnsResourceHeader);
+
+  if (isOSX)
+    {
+      gchar           image_type[5];
+      GimpImage      *temp_image;
+      GFile          *temp_file      = NULL;
+      FILE           *fp;
+      GimpValueArray *return_vals    = NULL;
+      GimpLayer     **layers;
+      GimpLayer      *new_layer;
+      gint            n_layers;
+      gchar          *temp_file_type = NULL;
+      gchar          *procedure_name = NULL;
+
+      temp_image = gimp_image_new (icontype->width, icontype->height,
+                                   gimp_image_get_base_type (image));
+
+      strncpy (image_type, (gchar *) icns->data + 8, 4);
+      image_type[4] = '\0';
+
+      /* PNG */
+      if (! strncmp (image_type, "\x89\x50\x4E\x47", 4))
+        {
+          temp_file_type = "png";
+          procedure_name = "file-png-load";
+        }
+      /* JPEG 2000 */
+      else if (! strncmp (image_type, "\x0CjP", 3))
+        {
+          temp_file_type = "jp2";
+          procedure_name = "file-jp2-load";
+        }
+
+      if (temp_file_type && procedure_name)
+        {
+          temp_file = gimp_temp_file (temp_file_type);
+          fp = g_fopen (g_file_peek_path (temp_file), "wb");
+
+          if (! fp)
+            {
+              g_message (_("Error trying to open temporary %s file '%s' "
+                         "for icns loading: %s"),
+                         temp_file_type,
+                         gimp_file_get_utf8_name (temp_file),
+                         g_strerror (errno));
+              return;
+            }
+
+          fwrite (icns->data + 8, sizeof (guchar), icns->size - 8, fp);
+          fclose (fp);
+
+          return_vals =
+            gimp_pdb_run_procedure (gimp_get_pdb (),
+                                    procedure_name,
+                                    GIMP_TYPE_RUN_MODE, GIMP_RUN_NONINTERACTIVE,
+                                    G_TYPE_FILE,        temp_file,
+                                    G_TYPE_NONE);
+        }
+
+      if (temp_image && return_vals)
+        {
+          temp_image = g_value_get_object (gimp_value_array_index (return_vals, 1));
+
+          layers = gimp_image_get_layers (temp_image, &n_layers);
+          new_layer = gimp_layer_new_from_drawable (GIMP_DRAWABLE (layers[0]), image);
+          gimp_item_set_name (GIMP_ITEM (new_layer), layer_name);
+          gimp_image_insert_layer (image, new_layer, NULL, 0);
+
+          layer_loaded = TRUE;
+
+          g_file_delete (temp_file, NULL, NULL);
+          g_object_unref (temp_file);
+          gimp_value_array_unref (return_vals);
+          g_free (layers);
+        }
+    }
+  else
+    {
+      if (icontype->bits != 32 || expected_size == icns->size)
+        icns_slurp (dest, icontype, icns, mask);
+      else
+        icns_decompress (dest, icontype, icns, mask);
+    }
+
+  if (! layer_loaded)
+    {
+      layer = gimp_layer_new (image, layer_name, icontype->width, icontype->height,
+                              GIMP_RGBA_IMAGE, 100,
+                              gimp_image_get_default_new_layer_mode (image));
+
+      buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
+
+      gegl_buffer_set (buffer,
+                       GEGL_RECTANGLE (0, 0, icontype->width, icontype->height),
+                       0, NULL,
+                       dest, GEGL_AUTO_ROWSTRIDE);
+
+      gimp_image_insert_layer (image, layer, NULL, 0);
+
+      g_object_unref (buffer);
+    }
+
+  g_free (dest);
+}
+
+GimpImage *
+icns_load_image (GFile        *file,
+                 gint32       *file_offset,
+                 GError      **error)
+{
+  FILE          *fp;
+  IcnsResource  *icns;
+  GimpImage     *image;
+
+  gegl_init (NULL, NULL);
+
+  gimp_progress_init_printf (_("Opening '%s'"),
+                             gimp_file_get_utf8_name (file));
+
+  fp = g_fopen (g_file_peek_path (file), "rb");
+
+  if (! fp)
+    {
+      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
+                   _("Could not open '%s' for reading: %s"),
+                   gimp_file_get_utf8_name (file), g_strerror (errno));
+      return NULL;
+    }
+
+  icns = resource_load (fp);
+
+  fclose (fp);
+
+  if (! icns)
+    {
+      g_message ("Invalid or corrupt icns resource file.");
+      return NULL;
+    }
+
+  image = icns_load (icns, file);
+
+  g_free (icns);
+
+  gimp_progress_update (1.0);
+
+  return image;
+}
+
+GimpImage *
+icns_load_thumbnail_image (GFile   *file,
+                           gint    *width,
+                           gint    *height,
+                           gint32   file_offset,
+                           GError **error)
+{
+  gint          w          = 0;
+  FILE         *fp;
+  GimpImage    *image      = NULL;
+  IcnsResource *icns;
+  IcnsResource *resources;
+  IcnsResource *mask       = NULL;
+  guint         i;
+  gint          match      = -1;
+  guint         nResources = 0;
+
+  gegl_init (NULL, NULL);
+
+  gimp_progress_init_printf (_("Opening thumbnail for '%s'"),
+                             gimp_file_get_utf8_name (file));
+
+  fp = g_fopen (g_file_peek_path (file), "rb");
+
+  if (! fp)
+    {
+      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
+                   _("Could not open '%s' for reading: %s"),
+                   gimp_file_get_utf8_name (file), g_strerror (errno));
+      return NULL;
+    }
+
+  icns = resource_load (fp);
+  fclose (fp);
+
+  if (! icns)
+  {
+    g_message ("Invalid or corrupt icns resource file.");
+    return NULL;
+  }
+
+  image = gimp_image_new (1024, 1024, GIMP_RGB);
+
+  resources = g_new (IcnsResource, 256);
+  while (resource_get_next (icns, &resources[nResources++])) {}
+
+  for (i = 0; iconTypes[i].type; i++)
+    {
+      if ((icns = resource_find (resources, iconTypes[i].type, nResources)))
+        {
+          if (iconTypes[i].width > w)
+            {
+              w = iconTypes[i].width;
+              match = i;
+            }
+        }
+    }
+
+  if (match > -1)
+    {
+      icns = resource_find (resources, iconTypes[match].type, nResources);
+
+      if (! iconTypes[match].isModern)
+        mask = resource_find (resources, iconTypes[match].mask, nResources);
+
+      icns_attach_image (image, &iconTypes[match], icns, mask, iconTypes[match].isModern);
+
+      gimp_image_resize_to_layers (image);
+    }
+  else
+    {
+      g_message ("Invalid or corrupt icns resource file.");
+      return NULL;
+    }
+
+  g_free (resources);
+
+  gimp_progress_update (1.0);
+
+  return image;
+}
diff --git a/plug-ins/file-icns/file-icns-load.h b/plug-ins/file-icns/file-icns-load.h
new file mode 100644
index 0000000000..355fffd9ae
--- /dev/null
+++ b/plug-ins/file-icns/file-icns-load.h
@@ -0,0 +1,34 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
+ *
+ * file-icns-load.h
+ * Copyright (C) 2004 Brion Vibber <brion pobox com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ICNS_LOAD_H__
+#define __ICNS_LOAD_H__
+
+GimpImage * icns_load_image           (GFile         *file,
+                                       gint32        *file_offset,
+                                       GError       **error);
+
+GimpImage * icns_load_thumbnail_image (GFile         *file,
+                                       gint          *width,
+                                       gint          *height,
+                                       gint32         file_offset,
+                                       GError       **error);
+
+#endif
diff --git a/plug-ins/file-icns/file-icns.c b/plug-ins/file-icns/file-icns.c
new file mode 100644
index 0000000000..78f9bcf78a
--- /dev/null
+++ b/plug-ins/file-icns/file-icns.c
@@ -0,0 +1,236 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
+ *
+ * file-icns.c
+ * Copyright (C) 2004 Brion Vibber <brion pobox com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib/gstdio.h>
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+/* #define ICNS_DBG */
+
+#include "file-icns.h"
+#include "file-icns-load.h"
+//#include "ico-save.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+#define LOAD_PROC           "file-icns-load"
+#define LOAD_THUMB_PROC     "file-icns-load-thumb"
+
+
+typedef struct _Icns      Icns;
+typedef struct _IcnsClass IcnsClass;
+
+struct _Icns
+{
+  GimpPlugIn      parent_instance;
+};
+
+struct _IcnsClass
+{
+  GimpPlugInClass parent_class;
+};
+
+
+#define ICNS_TYPE  (icns_get_type ())
+#define ICNS (obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ICNS_TYPE, Icns))
+
+GType                   icns_get_type         (void) G_GNUC_CONST;
+
+static GList          * icns_query_procedures (GimpPlugIn           *plug_in);
+static GimpProcedure  * icns_create_procedure (GimpPlugIn           *plug_in,
+                                               const gchar          *name);
+
+static GimpValueArray * icns_load             (GimpProcedure        *procedure,
+                                               GimpRunMode           run_mode,
+                                               GFile                *file,
+                                               const GimpValueArray *args,
+                                               gpointer              run_data);
+static GimpValueArray * icns_load_thumb       (GimpProcedure        *procedure,
+                                               GFile                *file,
+                                               gint                  size,
+                                               const GimpValueArray *args,
+                                               gpointer              run_data);
+
+
+G_DEFINE_TYPE (Icns, icns, GIMP_TYPE_PLUG_IN)
+
+GIMP_MAIN (ICNS_TYPE)
+DEFINE_STD_SET_I18N
+
+static void
+icns_class_init (IcnsClass *klass)
+{
+  GimpPlugInClass *plug_in_class  = GIMP_PLUG_IN_CLASS (klass);
+
+  plug_in_class->query_procedures = icns_query_procedures;
+  plug_in_class->create_procedure = icns_create_procedure;
+  plug_in_class->set_i18n         = STD_SET_I18N;
+}
+
+static void
+icns_init (Icns *icns)
+{
+}
+
+static GList *
+icns_query_procedures (GimpPlugIn *plug_in)
+{
+  GList *list = NULL;
+
+  list = g_list_append (list, g_strdup (LOAD_THUMB_PROC));
+  list = g_list_append (list, g_strdup (LOAD_PROC));
+
+  return list;
+}
+
+static GimpProcedure *
+icns_create_procedure (GimpPlugIn  *plug_in,
+                       const gchar *name)
+{
+  GimpProcedure *procedure = NULL;
+
+  if (! strcmp (name, LOAD_PROC))
+    {
+      procedure = gimp_load_procedure_new (plug_in, name,
+                                           GIMP_PDB_PROC_TYPE_PLUGIN,
+                                           icns_load, NULL, NULL);
+
+      gimp_procedure_set_menu_label (procedure, N_("Icns"));
+
+      gimp_procedure_set_documentation (procedure,
+                                        "Loads files in Apple Icon Image format",
+                                        "Loads Apple Icon Image files.",
+                                        name);
+      gimp_procedure_set_attribution (procedure,
+                                      "Brion Vibber <brion pobox com>",
+                                      "Brion Vibber <brion pobox com>",
+                                      "2004");
+
+      gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
+                                          "image/x-icns");
+      gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
+                                          "icns");
+      gimp_file_procedure_set_magics (GIMP_FILE_PROCEDURE (procedure),
+                                      "0,string,\x69\x63\x6E\x73");
+
+      gimp_load_procedure_set_thumbnail_loader (GIMP_LOAD_PROCEDURE (procedure),
+                                                LOAD_THUMB_PROC);
+    }
+  else if (! strcmp (name, LOAD_THUMB_PROC))
+    {
+      procedure = gimp_thumbnail_procedure_new (plug_in, name,
+                                                GIMP_PDB_PROC_TYPE_PLUGIN,
+                                                icns_load_thumb, NULL, NULL);
+
+      gimp_procedure_set_documentation (procedure,
+                                        "Loads a preview from an Apple Icon Image file",
+                                        "",
+                                        name);
+      gimp_procedure_set_attribution (procedure,
+                                      "Brion Vibber <brion pobox com>",
+                                      "Brion Vibber <brion pobox com>",
+                                      "2004");
+    }
+
+  return procedure;
+}
+
+static GimpValueArray *
+icns_load (GimpProcedure        *procedure,
+           GimpRunMode           run_mode,
+           GFile                *file,
+           const GimpValueArray *args,
+           gpointer              run_data)
+{
+  GimpValueArray *return_vals;
+  GimpImage      *image;
+  GError         *error       = NULL;
+
+  gegl_init (NULL, NULL);
+
+  image = icns_load_image (file, NULL, &error);
+
+  if (! image)
+    return gimp_procedure_new_return_values (procedure,
+                                             GIMP_PDB_EXECUTION_ERROR,
+                                             error);
+
+  return_vals = gimp_procedure_new_return_values (procedure,
+                                                  GIMP_PDB_SUCCESS,
+                                                  NULL);
+
+  GIMP_VALUES_SET_IMAGE (return_vals, 1, image);
+
+  return return_vals;
+}
+
+static GimpValueArray *
+icns_load_thumb (GimpProcedure        *procedure,
+                 GFile                *file,
+                 gint                  size,
+                 const GimpValueArray *args,
+                 gpointer              run_data)
+{
+  GimpValueArray *return_vals;
+  gint            width;
+  gint            height;
+  GimpImage      *image;
+  GError         *error = NULL;
+
+  gegl_init (NULL, NULL);
+
+  width  = size;
+  height = size;
+
+  image = icns_load_thumbnail_image (file,
+                                     &width, &height, 0, &error);
+
+  if (! image)
+    return gimp_procedure_new_return_values (procedure,
+                                             GIMP_PDB_EXECUTION_ERROR,
+                                             error);
+
+  return_vals = gimp_procedure_new_return_values (procedure,
+                                                  GIMP_PDB_SUCCESS,
+                                                  NULL);
+
+  GIMP_VALUES_SET_IMAGE (return_vals, 1, image);
+  GIMP_VALUES_SET_INT   (return_vals, 2, width);
+  GIMP_VALUES_SET_INT   (return_vals, 3, height);
+
+  gimp_value_array_truncate (return_vals, 4);
+
+  return return_vals;
+}
+
+/* Buffer should point to *at least 5 byte buffer*! */
+void
+fourcc_get_string (gchar *fourcc,
+                   gchar *buf)
+{
+  buf = fourcc;
+  buf[4] = 0;
+}
diff --git a/plug-ins/file-icns/file-icns.h b/plug-ins/file-icns/file-icns.h
new file mode 100644
index 0000000000..872b73aa95
--- /dev/null
+++ b/plug-ins/file-icns/file-icns.h
@@ -0,0 +1,58 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
+ *
+ * file-icns.h
+ * Copyright (C) 2004 Brion Vibber <brion pobox com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ICNS_H__
+#define __ICNS_H__
+
+
+#ifdef ICNS_DBG
+#define D(x) \
+{ \
+  printf("ICNS plugin: "); \
+  printf x; \
+}
+#else
+#define D(x)
+#endif
+
+#define PLUG_IN_BINARY      "file-icns"
+#define PLUG_IN_ROLE        "gimp-file-icns"
+
+
+typedef struct _IcnsResourceHeader
+{
+  /* Big-endian! */
+  gchar    type[4];
+  guint32  size;
+} IcnsResourceHeader;
+
+typedef struct _IcnsResource
+{
+  gchar    type[5];
+  guint32  size;
+  guint32  cursor;
+  guchar  *data;
+} IcnsResource;
+
+void
+fourcc_get_string (gchar *fourcc,
+                   gchar *buf);
+
+#endif /* __ICNS_H__ */
diff --git a/plug-ins/file-icns/meson.build b/plug-ins/file-icns/meson.build
new file mode 100644
index 0000000000..a66b342021
--- /dev/null
+++ b/plug-ins/file-icns/meson.build
@@ -0,0 +1,31 @@
+plugin_name = 'file-icns'
+
+plugin_sources = [
+  'file-icns-data.c',
+  'file-icns-load.c',
+  'file-icns.c',
+]
+
+if platform_windows
+  plugin_sources += windows.compile_resources(
+    gimp_plugins_rc,
+    args: [
+      '--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
+      '--define', 'INTERNALNAME_STR="@0@"'    .format(plugin_name),
+      '--define', 'TOP_SRCDIR="@0@"'          .format(meson.source_root()),
+    ],
+    include_directories: [
+      rootInclude, appInclude,
+    ],
+  )
+endif
+
+executable(plugin_name,
+  plugin_sources,
+  dependencies: [
+    libgimpui_dep,
+    libpng,
+  ],
+  install: true,
+  install_dir: gimpplugindir / 'plug-ins' / plugin_name,
+)
diff --git a/plug-ins/meson.build b/plug-ins/meson.build
index 11c0553541..22556d618f 100644
--- a/plug-ins/meson.build
+++ b/plug-ins/meson.build
@@ -5,6 +5,7 @@ subdir('file-exr')
 subdir('file-faxg3')
 subdir('file-fits')
 subdir('file-fli')
+subdir('file-icns')
 subdir('file-ico')
 subdir('file-jpeg')
 subdir('file-psd')
diff --git a/po-plug-ins/POTFILES.in b/po-plug-ins/POTFILES.in
index eff90c9f92..4494e8a05c 100644
--- a/po-plug-ins/POTFILES.in
+++ b/po-plug-ins/POTFILES.in
@@ -96,6 +96,8 @@ plug-ins/file-faxg3/faxg3.c
 plug-ins/file-fits/fits.c
 plug-ins/file-fli/fli.c
 plug-ins/file-fli/fli-gimp.c
+plug-ins/file-icns/file-icns-load.c
+plug-ins/file-icns/file-icns.c
 plug-ins/file-ico/ico-dialog.c
 plug-ins/file-ico/ico-load.c
 plug-ins/file-ico/ico-save.c


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]