Initial checkin of Pika from heckimp
This commit is contained in:
377
plug-ins/file-icns/file-icns-data.c
Normal file
377
plug-ins/file-icns/file-icns-data.c
Normal file
@ -0,0 +1,377 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* 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
|
||||
};
|
43
plug-ins/file-icns/file-icns-data.h
Normal file
43
plug-ins/file-icns/file-icns-data.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* 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
|
623
plug-ins/file-icns/file-icns-load.c
Normal file
623
plug-ins/file-icns/file-icns-load.c
Normal file
@ -0,0 +1,623 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* 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 <libpika/pika.h>
|
||||
#include <libpika/pikaui.h>
|
||||
|
||||
#include <png.h>
|
||||
|
||||
/* #define ICNS_DBG */
|
||||
|
||||
#include "file-icns.h"
|
||||
#include "file-icns-data.h"
|
||||
#include "file-icns-load.h"
|
||||
|
||||
#include "libpika/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 (PikaImage *image,
|
||||
IconType *icontype,
|
||||
IcnsResource *icns,
|
||||
IcnsResource *mask,
|
||||
gboolean isOSX);
|
||||
|
||||
PikaImage * 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"));
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
PikaImage *
|
||||
icns_load (IcnsResource *icns,
|
||||
GFile *file)
|
||||
{
|
||||
IcnsResource *resources;
|
||||
guint nResources;
|
||||
gfloat current_resources = 0;
|
||||
PikaImage *image;
|
||||
|
||||
resources = g_new (IcnsResource, 256);
|
||||
|
||||
/* Largest .icns icon is 1024 x 1024 */
|
||||
image = pika_image_new (1024, 1024, PIKA_RGB);
|
||||
|
||||
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);
|
||||
|
||||
pika_progress_update (current_resources++ / nResources);
|
||||
}
|
||||
}
|
||||
|
||||
pika_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 (PikaImage *image,
|
||||
IconType *icontype,
|
||||
IcnsResource *icns,
|
||||
IcnsResource *mask,
|
||||
gboolean isOSX)
|
||||
{
|
||||
gchar layer_name[5];
|
||||
guchar *dest;
|
||||
PikaLayer *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];
|
||||
PikaImage *temp_image;
|
||||
GFile *temp_file = NULL;
|
||||
FILE *fp;
|
||||
PikaValueArray *return_vals = NULL;
|
||||
PikaLayer **layers;
|
||||
PikaLayer *new_layer;
|
||||
gint n_layers;
|
||||
gchar *temp_file_type = NULL;
|
||||
gchar *procedure_name = NULL;
|
||||
|
||||
temp_image = pika_image_new (icontype->width, icontype->height,
|
||||
pika_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 = pika_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,
|
||||
pika_file_get_utf8_name (temp_file),
|
||||
g_strerror (errno));
|
||||
return;
|
||||
}
|
||||
|
||||
fwrite (icns->data + 8, sizeof (guchar), icns->size - 8, fp);
|
||||
fclose (fp);
|
||||
|
||||
return_vals =
|
||||
pika_pdb_run_procedure (pika_get_pdb (),
|
||||
procedure_name,
|
||||
PIKA_TYPE_RUN_MODE, PIKA_RUN_NONINTERACTIVE,
|
||||
G_TYPE_FILE, temp_file,
|
||||
G_TYPE_NONE);
|
||||
}
|
||||
|
||||
if (temp_image && return_vals)
|
||||
{
|
||||
temp_image = g_value_get_object (pika_value_array_index (return_vals, 1));
|
||||
|
||||
layers = pika_image_get_layers (temp_image, &n_layers);
|
||||
new_layer = pika_layer_new_from_drawable (PIKA_DRAWABLE (layers[0]), image);
|
||||
pika_item_set_name (PIKA_ITEM (new_layer), layer_name);
|
||||
pika_image_insert_layer (image, new_layer, NULL, 0);
|
||||
|
||||
layer_loaded = TRUE;
|
||||
|
||||
g_file_delete (temp_file, NULL, NULL);
|
||||
g_object_unref (temp_file);
|
||||
pika_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 = pika_layer_new (image, layer_name, icontype->width, icontype->height,
|
||||
PIKA_RGBA_IMAGE, 100,
|
||||
pika_image_get_default_new_layer_mode (image));
|
||||
|
||||
buffer = pika_drawable_get_buffer (PIKA_DRAWABLE (layer));
|
||||
|
||||
gegl_buffer_set (buffer,
|
||||
GEGL_RECTANGLE (0, 0, icontype->width, icontype->height),
|
||||
0, NULL,
|
||||
dest, GEGL_AUTO_ROWSTRIDE);
|
||||
|
||||
pika_image_insert_layer (image, layer, NULL, 0);
|
||||
|
||||
g_object_unref (buffer);
|
||||
}
|
||||
|
||||
g_free (dest);
|
||||
}
|
||||
|
||||
PikaImage *
|
||||
icns_load_image (GFile *file,
|
||||
gint32 *file_offset,
|
||||
GError **error)
|
||||
{
|
||||
FILE *fp;
|
||||
IcnsResource *icns;
|
||||
PikaImage *image;
|
||||
|
||||
gegl_init (NULL, NULL);
|
||||
|
||||
pika_progress_init_printf (_("Opening '%s'"),
|
||||
pika_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"),
|
||||
pika_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);
|
||||
|
||||
pika_progress_update (1.0);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
PikaImage *
|
||||
icns_load_thumbnail_image (GFile *file,
|
||||
gint *width,
|
||||
gint *height,
|
||||
gint32 file_offset,
|
||||
GError **error)
|
||||
{
|
||||
gint w = 0;
|
||||
FILE *fp;
|
||||
PikaImage *image = NULL;
|
||||
IcnsResource *icns;
|
||||
IcnsResource *resources;
|
||||
IcnsResource *mask = NULL;
|
||||
guint i;
|
||||
gint match = -1;
|
||||
guint nResources = 0;
|
||||
|
||||
gegl_init (NULL, NULL);
|
||||
|
||||
pika_progress_init_printf (_("Opening thumbnail for '%s'"),
|
||||
pika_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"),
|
||||
pika_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 = pika_image_new (1024, 1024, PIKA_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);
|
||||
|
||||
pika_image_resize_to_layers (image);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_message ("Invalid or corrupt icns resource file.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_free (resources);
|
||||
|
||||
pika_progress_update (1.0);
|
||||
|
||||
return image;
|
||||
}
|
38
plug-ins/file-icns/file-icns-load.h
Normal file
38
plug-ins/file-icns/file-icns-load.h
Normal file
@ -0,0 +1,38 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* 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__
|
||||
|
||||
PikaImage * icns_load_image (GFile *file,
|
||||
gint32 *file_offset,
|
||||
GError **error);
|
||||
|
||||
PikaImage * icns_load_thumbnail_image (GFile *file,
|
||||
gint *width,
|
||||
gint *height,
|
||||
gint32 file_offset,
|
||||
GError **error);
|
||||
|
||||
#endif
|
620
plug-ins/file-icns/file-icns-save.c
Normal file
620
plug-ins/file-icns/file-icns-save.c
Normal file
@ -0,0 +1,620 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* file-icns-save.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 <libpika/pika.h>
|
||||
#include <libpika/pikaui.h>
|
||||
|
||||
#include "file-icns.h"
|
||||
#include "file-icns-data.h"
|
||||
#include "file-icns-load.h"
|
||||
#include "file-icns-save.h"
|
||||
|
||||
#include "libpika/stdplugins-intl.h"
|
||||
|
||||
GtkWidget * icns_dialog_new (IcnsSaveInfo *info);
|
||||
|
||||
static gboolean icns_save_dialog (IcnsSaveInfo *info,
|
||||
PikaImage *image);
|
||||
|
||||
void icns_dialog_add_icon (GtkWidget *dialog,
|
||||
PikaDrawable *layer,
|
||||
gint layer_num,
|
||||
gint duplicates[]);
|
||||
|
||||
static GtkWidget * icns_preview_new (PikaDrawable *layer);
|
||||
|
||||
static GtkWidget * icns_create_icon_item (GtkWidget *icon_preview,
|
||||
PikaDrawable *layer,
|
||||
gint layer_num,
|
||||
IcnsSaveInfo *info,
|
||||
gint duplicates[]);
|
||||
|
||||
static gint icns_find_type (gint width,
|
||||
gint height);
|
||||
static gboolean icns_check_dimensions (gint width,
|
||||
gint height);
|
||||
static gboolean icns_check_compat (GtkWidget *dialog,
|
||||
IcnsSaveInfo *info);
|
||||
|
||||
PikaPDBStatusType icns_export_image (GFile *file,
|
||||
IcnsSaveInfo *info,
|
||||
PikaImage *image,
|
||||
GError **error);
|
||||
|
||||
static void icns_save_info_free (IcnsSaveInfo *info);
|
||||
|
||||
/* Referenced from plug-ins/file-ico/ico-dialog.c */
|
||||
void
|
||||
icns_dialog_add_icon (GtkWidget *dialog,
|
||||
PikaDrawable *layer,
|
||||
gint layer_num,
|
||||
gint duplicates[])
|
||||
{
|
||||
GtkWidget *flowbox;
|
||||
GtkWidget *vbox_item;
|
||||
GtkWidget *preview;
|
||||
gchar key[ICNS_MAXBUF];
|
||||
IcnsSaveInfo *info;
|
||||
|
||||
flowbox = g_object_get_data (G_OBJECT (dialog), "icons_flowbox");
|
||||
info = g_object_get_data (G_OBJECT (dialog), "save_info");
|
||||
|
||||
preview = icns_preview_new (layer);
|
||||
vbox_item = icns_create_icon_item (preview, layer, layer_num, info,
|
||||
duplicates);
|
||||
gtk_flow_box_insert (GTK_FLOW_BOX (flowbox), vbox_item, -1);
|
||||
gtk_widget_show (vbox_item);
|
||||
|
||||
/* Let's make the vbox_item accessible through the layer ID */
|
||||
g_snprintf (key, sizeof (key), "layer_%i_hbox",
|
||||
pika_item_get_id (PIKA_ITEM (layer)));
|
||||
g_object_set_data (G_OBJECT (dialog), key, vbox_item);
|
||||
|
||||
icns_check_compat (dialog, info);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
icns_preview_new (PikaDrawable *layer)
|
||||
{
|
||||
GtkWidget *image;
|
||||
GdkPixbuf *pixbuf;
|
||||
gint width = pika_drawable_get_width (layer);
|
||||
gint height = pika_drawable_get_height (layer);
|
||||
|
||||
pixbuf = pika_drawable_get_thumbnail (layer,
|
||||
MIN (width, 128), MIN (height, 128),
|
||||
PIKA_PIXBUF_SMALL_CHECKS);
|
||||
image = gtk_image_new_from_pixbuf (pixbuf);
|
||||
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
static gint
|
||||
icns_find_type (gint width,
|
||||
gint height)
|
||||
{
|
||||
gint match = -1;
|
||||
|
||||
for (gint j = 0; iconTypes[j].type; j++)
|
||||
{
|
||||
/* TODO: Currently, this chooses the first "modern" ICNS format for a
|
||||
* ICNS file. This is because newer formats are not supported well in
|
||||
* non-native MacOS programs like Inkscape. It'd be nice to design
|
||||
* a GUI with enough information for users to make their own decisions
|
||||
*/
|
||||
if (iconTypes[j].width == width &&
|
||||
iconTypes[j].height == height &&
|
||||
iconTypes[j].isModern)
|
||||
{
|
||||
match = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
icns_check_dimensions (gint width,
|
||||
gint height)
|
||||
{
|
||||
gboolean isValid = TRUE;
|
||||
|
||||
if (width != height)
|
||||
{
|
||||
/* Only valid non-square size is 16x12 */
|
||||
if (! (width == 16 && height == 12))
|
||||
isValid = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Valid square ICNS sizes */
|
||||
if (width != 16 &&
|
||||
width != 18 &&
|
||||
width != 24 &&
|
||||
width != 32 &&
|
||||
width != 36 &&
|
||||
width != 48 &&
|
||||
width != 64 &&
|
||||
width != 128 &&
|
||||
width != 256 &&
|
||||
width != 512 &&
|
||||
width != 1024)
|
||||
isValid = FALSE;
|
||||
}
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
icns_create_icon_item (GtkWidget *icon_preview,
|
||||
PikaDrawable *layer,
|
||||
gint layer_num,
|
||||
IcnsSaveInfo *info,
|
||||
gint duplicates[])
|
||||
{
|
||||
static GtkSizeGroup *size = NULL;
|
||||
|
||||
GtkWidget *vbox_item;
|
||||
GtkWidget *frame;
|
||||
gchar *frame_header;
|
||||
gint match = -1;
|
||||
gint width = pika_drawable_get_width (layer);
|
||||
gint height = pika_drawable_get_height (layer);
|
||||
|
||||
vbox_item = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
|
||||
|
||||
/* To make life easier for the callbacks, we store the
|
||||
layer's ID and stacking number with vbox_item. */
|
||||
|
||||
g_object_set_data (G_OBJECT (vbox_item),
|
||||
"icon_layer", layer);
|
||||
g_object_set_data (G_OBJECT (vbox_item),
|
||||
"icon_layer_num", GINT_TO_POINTER (layer_num));
|
||||
|
||||
frame_header = g_strdup_printf ("%dx%d", width, height);
|
||||
|
||||
frame = pika_frame_new (frame_header);
|
||||
gtk_box_pack_start (GTK_BOX (vbox_item), frame, FALSE, FALSE, 0);
|
||||
gtk_widget_show (frame);
|
||||
g_free (frame_header);
|
||||
|
||||
g_object_set_data (G_OBJECT (vbox_item), "icon_preview", icon_preview);
|
||||
gtk_container_add (GTK_CONTAINER (frame), icon_preview);
|
||||
gtk_widget_show (icon_preview);
|
||||
|
||||
if (! size)
|
||||
size = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
|
||||
|
||||
gtk_size_group_add_widget (size, icon_preview);
|
||||
|
||||
match = icns_find_type (pika_drawable_get_width (layer),
|
||||
pika_drawable_get_height (layer));
|
||||
|
||||
if (! icns_check_dimensions (width, height) ||
|
||||
(match != -1 && duplicates[match] != 0))
|
||||
{
|
||||
GtkWidget *label;
|
||||
gchar *warning;
|
||||
gchar *markup;
|
||||
|
||||
if (! icns_check_dimensions (width, height))
|
||||
warning = g_strdup_printf (_("Invalid icon size. \n"
|
||||
"It will not be exported"));
|
||||
else
|
||||
warning = g_strdup_printf (_("Duplicate layer size. \n"
|
||||
"It will not be exported"));
|
||||
|
||||
markup = g_strdup_printf ("<i>%s</i>", warning);
|
||||
|
||||
label = gtk_label_new (NULL);
|
||||
gtk_label_set_markup (GTK_LABEL (label), markup);
|
||||
g_free (markup);
|
||||
g_free (warning);
|
||||
|
||||
gtk_box_pack_start (GTK_BOX (vbox_item), label, FALSE, FALSE, 0);
|
||||
gtk_widget_show (label);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (vbox_item),
|
||||
"background");
|
||||
}
|
||||
|
||||
if (match != -1)
|
||||
duplicates[match] = 1;
|
||||
|
||||
return vbox_item;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
icns_check_compat (GtkWidget *dialog,
|
||||
IcnsSaveInfo *info)
|
||||
{
|
||||
GtkWidget *warning;
|
||||
GList *iter;
|
||||
gboolean warn = FALSE;
|
||||
gint i;
|
||||
|
||||
for (iter = info->layers, i = 0; iter; iter = iter->next, i++)
|
||||
{
|
||||
gint width = pika_drawable_get_width (iter->data);
|
||||
gint height = pika_drawable_get_height (iter->data);
|
||||
|
||||
warn = ! icns_check_dimensions (width, height);
|
||||
if (warn)
|
||||
break;
|
||||
}
|
||||
|
||||
if (dialog)
|
||||
{
|
||||
warning = g_object_get_data (G_OBJECT (dialog), "warning");
|
||||
gtk_widget_set_visible (warning, warn);
|
||||
}
|
||||
|
||||
return ! warn;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
icns_dialog_new (IcnsSaveInfo *info)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *main_vbox;
|
||||
GtkWidget *frame;
|
||||
GtkWidget *scrolled_window;
|
||||
GtkWidget *viewport;
|
||||
GtkWidget *flowbox;
|
||||
GtkWidget *warning;
|
||||
|
||||
dialog = pika_export_dialog_new (_("Apple Icon Image"),
|
||||
PLUG_IN_BINARY,
|
||||
"plug-in-icns-save");
|
||||
|
||||
g_object_set_data (G_OBJECT (dialog), "save_info", info);
|
||||
|
||||
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
|
||||
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
|
||||
gtk_box_pack_start (GTK_BOX (pika_export_dialog_get_content_area (dialog)),
|
||||
main_vbox, TRUE, TRUE, 0);
|
||||
gtk_widget_show (main_vbox);
|
||||
|
||||
warning = g_object_new (PIKA_TYPE_HINT_BOX,
|
||||
"icon-name", PIKA_ICON_DIALOG_WARNING,
|
||||
"hint",
|
||||
_("Valid ICNS icons sizes are:\n "
|
||||
"16x12, 16x16, 18x18, 24x24, 32x32, 36x36, 48x48,\n"
|
||||
"64x64, 128x128, 256x256, 512x512, and 1024x1024.\n"
|
||||
"Any other sized layers will be ignored on export."),
|
||||
NULL);
|
||||
gtk_box_pack_end (GTK_BOX (main_vbox), warning, FALSE, FALSE, 12);
|
||||
/* Don't show warning by default */
|
||||
|
||||
frame = pika_frame_new (_("Export Icons"));
|
||||
gtk_box_pack_start (GTK_BOX (main_vbox), frame, TRUE, TRUE, 4);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
|
||||
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||
gtk_container_add (GTK_CONTAINER (frame), scrolled_window);
|
||||
gtk_widget_show (scrolled_window);
|
||||
|
||||
viewport = gtk_viewport_new (NULL, NULL);
|
||||
gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
|
||||
gtk_widget_show (viewport);
|
||||
|
||||
flowbox = gtk_flow_box_new ();
|
||||
gtk_flow_box_set_column_spacing (GTK_FLOW_BOX (flowbox), 6);
|
||||
gtk_flow_box_set_row_spacing (GTK_FLOW_BOX (flowbox), 6);
|
||||
gtk_flow_box_set_selection_mode (GTK_FLOW_BOX (flowbox), GTK_SELECTION_NONE);
|
||||
g_object_set_data (G_OBJECT (dialog), "icons_flowbox", flowbox);
|
||||
gtk_container_add (GTK_CONTAINER (viewport), flowbox);
|
||||
gtk_widget_show (flowbox);
|
||||
|
||||
g_object_set_data (G_OBJECT (dialog), "warning", warning);
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
icns_save_dialog (IcnsSaveInfo *info,
|
||||
PikaImage *image)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GList *iter;
|
||||
gint i;
|
||||
gint j;
|
||||
gint response;
|
||||
gint duplicates[ICNS_TYPE_NUM];
|
||||
gint ordered[12] =
|
||||
{12, 16, 18, 24, 32, 36, 48, 64, 128, 256, 512, 1024};
|
||||
|
||||
pika_ui_init (PLUG_IN_BINARY);
|
||||
|
||||
for (i = 0; i < ICNS_TYPE_NUM; i++)
|
||||
duplicates[i] = 0;
|
||||
|
||||
dialog = icns_dialog_new (info);
|
||||
|
||||
/* Add icons in order, smallest to largest */
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
for (iter = info->layers, j = 0;
|
||||
iter;
|
||||
iter = g_list_next (iter), j++)
|
||||
{
|
||||
/* Put the icons in order in dialog */
|
||||
gint width = pika_drawable_get_width (iter->data);
|
||||
gint height = pika_drawable_get_height (iter->data);
|
||||
|
||||
if (height != ordered[i] || ! icns_check_dimensions (width, height))
|
||||
continue;
|
||||
|
||||
icns_dialog_add_icon (dialog, iter->data, i, duplicates);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add any invalid icons at the end */
|
||||
for (iter = info->layers, i = 0;
|
||||
iter;
|
||||
iter = g_list_next (iter), i++)
|
||||
{
|
||||
if (! icns_check_dimensions (pika_drawable_get_width (iter->data),
|
||||
pika_drawable_get_height (iter->data)))
|
||||
icns_dialog_add_icon (dialog, iter->data, i, duplicates);
|
||||
}
|
||||
|
||||
/* Scale the thing to approximately fit its content, but not too large ... */
|
||||
gtk_window_set_default_size (GTK_WINDOW (dialog),
|
||||
200 + (info->num_icons > 4 ?
|
||||
500 : info->num_icons * 120),
|
||||
200 + (info->num_icons > 4 ?
|
||||
250 : info->num_icons * 60));
|
||||
|
||||
gtk_widget_show (dialog);
|
||||
|
||||
response = pika_dialog_run (PIKA_DIALOG (dialog));
|
||||
|
||||
gtk_widget_destroy (dialog);
|
||||
|
||||
return (response == GTK_RESPONSE_OK);
|
||||
}
|
||||
|
||||
PikaPDBStatusType
|
||||
icns_export_image (GFile *file,
|
||||
IcnsSaveInfo *info,
|
||||
PikaImage *image,
|
||||
GError **error)
|
||||
{
|
||||
FILE *fp;
|
||||
GList *iter;
|
||||
gint i;
|
||||
guint32 file_size = 8;
|
||||
PikaValueArray *return_vals = NULL;
|
||||
gint duplicates[ICNS_TYPE_NUM];
|
||||
|
||||
for (i = 0; i < ICNS_TYPE_NUM; i++)
|
||||
duplicates[i] = 0;
|
||||
|
||||
fp = g_fopen (g_file_peek_path (file), "wb");
|
||||
|
||||
if (! fp)
|
||||
{
|
||||
icns_save_info_free (info);
|
||||
g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (errno),
|
||||
_("Could not open '%s' for writing: %s"),
|
||||
pika_file_get_utf8_name (file), g_strerror (errno));
|
||||
return PIKA_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
|
||||
/* Write Header */
|
||||
fwrite ("icns", sizeof (gchar), 4, fp);
|
||||
fwrite ("\0\0\0\0", sizeof (gchar), 4, fp); /* will be filled in later */
|
||||
|
||||
/* Write Icon Data */
|
||||
for (iter = info->layers, i = 0;
|
||||
iter;
|
||||
iter = g_list_next (iter), i++)
|
||||
{
|
||||
gint match = -1;
|
||||
gint width = pika_drawable_get_width (iter->data);
|
||||
gint height = pika_drawable_get_height (iter->data);
|
||||
|
||||
/* Don't export icons with invalid dimensions */
|
||||
if (! icns_check_dimensions (width, height))
|
||||
continue;
|
||||
|
||||
match = icns_find_type (width, height);
|
||||
|
||||
/* MacOS X format icons */
|
||||
if (match != -1 && duplicates[match] == 0)
|
||||
{
|
||||
PikaDrawable **drawables = NULL;
|
||||
GFile *temp_file = NULL;
|
||||
PikaObjectArray *args;
|
||||
FILE *temp_fp;
|
||||
gint temp_size;
|
||||
gint macos_size;
|
||||
|
||||
temp_file = pika_temp_file ("png");
|
||||
|
||||
drawables = g_new (PikaDrawable *, 1);
|
||||
drawables[0] = iter->data;
|
||||
|
||||
args = pika_object_array_new (PIKA_TYPE_DRAWABLE, (GObject **) drawables, 1, FALSE);
|
||||
|
||||
return_vals =
|
||||
pika_pdb_run_procedure (pika_get_pdb (),
|
||||
"file-png-save",
|
||||
PIKA_TYPE_RUN_MODE, PIKA_RUN_NONINTERACTIVE,
|
||||
PIKA_TYPE_IMAGE, image,
|
||||
G_TYPE_INT, 1,
|
||||
PIKA_TYPE_OBJECT_ARRAY, args,
|
||||
G_TYPE_FILE, temp_file,
|
||||
G_TYPE_BOOLEAN, FALSE,
|
||||
G_TYPE_INT, 9,
|
||||
G_TYPE_BOOLEAN, FALSE,
|
||||
G_TYPE_BOOLEAN, FALSE,
|
||||
G_TYPE_BOOLEAN, FALSE,
|
||||
G_TYPE_BOOLEAN, FALSE,
|
||||
G_TYPE_BOOLEAN, FALSE,
|
||||
G_TYPE_BOOLEAN, FALSE,
|
||||
G_TYPE_NONE);
|
||||
|
||||
pika_object_array_free (args);
|
||||
g_clear_pointer (&drawables, g_free);
|
||||
|
||||
if (PIKA_VALUES_GET_ENUM (return_vals, 0) != PIKA_PDB_SUCCESS)
|
||||
{
|
||||
icns_save_info_free (info);
|
||||
g_set_error (error, 0, 0,
|
||||
"Running procedure 'file-png-save' "
|
||||
"for icns export failed: %s",
|
||||
pika_pdb_get_last_error (pika_get_pdb ()));
|
||||
|
||||
return PIKA_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
|
||||
temp_fp = g_fopen (g_file_peek_path (temp_file), "rb");
|
||||
fseek (temp_fp, 0L, SEEK_END);
|
||||
temp_size = ftell (temp_fp);
|
||||
fseek (temp_fp, 0L, SEEK_SET);
|
||||
|
||||
g_file_delete (temp_file, NULL, NULL);
|
||||
g_object_unref (temp_file);
|
||||
|
||||
fwrite (iconTypes[match].type, sizeof (gchar), 4, fp);
|
||||
macos_size = GUINT32_TO_BE (temp_size + 8);
|
||||
fwrite (&macos_size, sizeof (macos_size), 1, fp);
|
||||
|
||||
if (temp_size > 0)
|
||||
{
|
||||
guchar buf[temp_size];
|
||||
|
||||
fread (buf, 1, sizeof (buf), temp_fp);
|
||||
|
||||
if (fwrite (buf, 1, temp_size, fp) < temp_size)
|
||||
{
|
||||
icns_save_info_free (info);
|
||||
g_set_error (error, G_FILE_ERROR,
|
||||
g_file_error_from_errno (errno),
|
||||
_("Error writing icns: %s"),
|
||||
g_strerror (errno));
|
||||
return PIKA_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
}
|
||||
fclose (temp_fp);
|
||||
|
||||
file_size += temp_size + 8;
|
||||
duplicates[match] = 1;
|
||||
}
|
||||
|
||||
pika_progress_update (i / info->num_icons);
|
||||
}
|
||||
|
||||
/* Update header with full file size */
|
||||
file_size = GUINT32_TO_BE (file_size);
|
||||
fseek (fp, 4L, SEEK_SET);
|
||||
fwrite (&file_size, sizeof (file_size), 1, fp);
|
||||
|
||||
pika_progress_update (1.0);
|
||||
|
||||
icns_save_info_free (info);
|
||||
fclose (fp);
|
||||
return PIKA_PDB_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
icns_save_info_free (IcnsSaveInfo *info)
|
||||
{
|
||||
g_list_free (info->layers);
|
||||
memset (info, 0, sizeof (IcnsSaveInfo));
|
||||
}
|
||||
|
||||
PikaPDBStatusType
|
||||
icns_save_image (GFile *file,
|
||||
PikaImage *image,
|
||||
gint32 run_mode,
|
||||
GError **error)
|
||||
{
|
||||
IcnsSaveInfo info;
|
||||
GList *iter;
|
||||
gboolean isValidLayers = FALSE;
|
||||
gint i;
|
||||
|
||||
info.layers = pika_image_list_layers (image);
|
||||
info.num_icons = g_list_length (info.layers);
|
||||
|
||||
/* Initial check if we have any valid layers to export */
|
||||
for (iter = info.layers, i = 0; iter; iter = iter->next, i++)
|
||||
{
|
||||
gint width = pika_drawable_get_width (iter->data);
|
||||
gint height = pika_drawable_get_height (iter->data);
|
||||
|
||||
if (icns_check_dimensions (width, height))
|
||||
{
|
||||
isValidLayers = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (! isValidLayers)
|
||||
{
|
||||
g_set_error (error, G_FILE_ERROR, 0,
|
||||
_("No valid sized layers. Only valid layer sizes are "
|
||||
"16x12, 16x16, 18x18, 24x24, 32x32, 36x36, 48x48, "
|
||||
"64x64, 128x128, 256x256, 512x512, or 1024x1024."));
|
||||
|
||||
return PIKA_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
|
||||
if (run_mode == PIKA_RUN_INTERACTIVE)
|
||||
{
|
||||
/* Allow user to override default values */
|
||||
if (! icns_save_dialog (&info, image))
|
||||
return PIKA_PDB_CANCEL;
|
||||
}
|
||||
else if (run_mode == PIKA_RUN_NONINTERACTIVE)
|
||||
{
|
||||
if (! icns_check_compat (NULL, &info))
|
||||
{
|
||||
g_set_error (error, G_FILE_ERROR, 0,
|
||||
_("Invalid layer size(s). Only valid layer sizes are "
|
||||
"16x12, 16x16, 18x18, 24x24, 32x32, 36x36, 48x48, "
|
||||
"64x64, 128x128, 256x256, 512x512, or 1024x1024."));
|
||||
|
||||
return PIKA_PDB_EXECUTION_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
pika_progress_init_printf (_("Exporting '%s'"),
|
||||
pika_file_get_utf8_name (file));
|
||||
|
||||
return icns_export_image (file, &info, image, error);
|
||||
}
|
34
plug-ins/file-icns/file-icns-save.h
Normal file
34
plug-ins/file-icns/file-icns-save.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
|
||||
*
|
||||
* file-icns-save.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_SAVE_H__
|
||||
#define __ICNS_SAVE_H__
|
||||
|
||||
|
||||
PikaPDBStatusType icns_save_image (GFile *file,
|
||||
PikaImage *image,
|
||||
gint32 run_mode,
|
||||
GError **error);
|
||||
|
||||
#endif /* __ICNS_SAVE_H__ */
|
295
plug-ins/file-icns/file-icns.c
Normal file
295
plug-ins/file-icns/file-icns.c
Normal file
@ -0,0 +1,295 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* 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 <libpika/pika.h>
|
||||
#include <libpika/pikaui.h>
|
||||
|
||||
/* #define ICNS_DBG */
|
||||
|
||||
#include "file-icns.h"
|
||||
#include "file-icns-load.h"
|
||||
#include "file-icns-save.h"
|
||||
|
||||
#include "libpika/stdplugins-intl.h"
|
||||
|
||||
#define LOAD_PROC "file-icns-load"
|
||||
#define LOAD_THUMB_PROC "file-icns-load-thumb"
|
||||
#define SAVE_PROC "file-icns-save"
|
||||
|
||||
|
||||
typedef struct _Icns Icns;
|
||||
typedef struct _IcnsClass IcnsClass;
|
||||
|
||||
struct _Icns
|
||||
{
|
||||
PikaPlugIn parent_instance;
|
||||
};
|
||||
|
||||
struct _IcnsClass
|
||||
{
|
||||
PikaPlugInClass 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 (PikaPlugIn *plug_in);
|
||||
static PikaProcedure * icns_create_procedure (PikaPlugIn *plug_in,
|
||||
const gchar *name);
|
||||
|
||||
static PikaValueArray * icns_load (PikaProcedure *procedure,
|
||||
PikaRunMode run_mode,
|
||||
GFile *file,
|
||||
const PikaValueArray *args,
|
||||
gpointer run_data);
|
||||
static PikaValueArray * icns_load_thumb (PikaProcedure *procedure,
|
||||
GFile *file,
|
||||
gint size,
|
||||
const PikaValueArray *args,
|
||||
gpointer run_data);
|
||||
static PikaValueArray * icns_save (PikaProcedure *procedure,
|
||||
PikaRunMode run_mode,
|
||||
PikaImage *image,
|
||||
gint n_drawables,
|
||||
PikaDrawable **drawables,
|
||||
GFile *file,
|
||||
const PikaValueArray *args,
|
||||
gpointer run_data);
|
||||
|
||||
|
||||
G_DEFINE_TYPE (Icns, icns, PIKA_TYPE_PLUG_IN)
|
||||
|
||||
PIKA_MAIN (ICNS_TYPE)
|
||||
DEFINE_STD_SET_I18N
|
||||
|
||||
static void
|
||||
icns_class_init (IcnsClass *klass)
|
||||
{
|
||||
PikaPlugInClass *plug_in_class = PIKA_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 (PikaPlugIn *plug_in)
|
||||
{
|
||||
GList *list = NULL;
|
||||
|
||||
list = g_list_append (list, g_strdup (LOAD_THUMB_PROC));
|
||||
list = g_list_append (list, g_strdup (LOAD_PROC));
|
||||
list = g_list_append (list, g_strdup (SAVE_PROC));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static PikaProcedure *
|
||||
icns_create_procedure (PikaPlugIn *plug_in,
|
||||
const gchar *name)
|
||||
{
|
||||
PikaProcedure *procedure = NULL;
|
||||
|
||||
if (! strcmp (name, LOAD_PROC))
|
||||
{
|
||||
procedure = pika_load_procedure_new (plug_in, name,
|
||||
PIKA_PDB_PROC_TYPE_PLUGIN,
|
||||
icns_load, NULL, NULL);
|
||||
|
||||
pika_procedure_set_menu_label (procedure, N_("Icns"));
|
||||
|
||||
pika_procedure_set_documentation (procedure,
|
||||
"Loads files in Apple Icon Image format",
|
||||
"Loads Apple Icon Image files.",
|
||||
name);
|
||||
pika_procedure_set_attribution (procedure,
|
||||
"Brion Vibber <brion@pobox.com>",
|
||||
"Brion Vibber <brion@pobox.com>",
|
||||
"2004");
|
||||
|
||||
pika_file_procedure_set_mime_types (PIKA_FILE_PROCEDURE (procedure),
|
||||
"image/x-icns");
|
||||
pika_file_procedure_set_extensions (PIKA_FILE_PROCEDURE (procedure),
|
||||
"icns");
|
||||
pika_file_procedure_set_magics (PIKA_FILE_PROCEDURE (procedure),
|
||||
"0,string,\x69\x63\x6E\x73");
|
||||
|
||||
pika_load_procedure_set_thumbnail_loader (PIKA_LOAD_PROCEDURE (procedure),
|
||||
LOAD_THUMB_PROC);
|
||||
}
|
||||
else if (! strcmp (name, LOAD_THUMB_PROC))
|
||||
{
|
||||
procedure = pika_thumbnail_procedure_new (plug_in, name,
|
||||
PIKA_PDB_PROC_TYPE_PLUGIN,
|
||||
icns_load_thumb, NULL, NULL);
|
||||
|
||||
pika_procedure_set_documentation (procedure,
|
||||
"Loads a preview from an Apple Icon Image file",
|
||||
"",
|
||||
name);
|
||||
pika_procedure_set_attribution (procedure,
|
||||
"Brion Vibber <brion@pobox.com>",
|
||||
"Brion Vibber <brion@pobox.com>",
|
||||
"2004");
|
||||
}
|
||||
else if (! strcmp (name, SAVE_PROC))
|
||||
{
|
||||
procedure = pika_save_procedure_new (plug_in, name,
|
||||
PIKA_PDB_PROC_TYPE_PLUGIN,
|
||||
icns_save, NULL, NULL);
|
||||
|
||||
pika_procedure_set_image_types (procedure, "*");
|
||||
|
||||
pika_procedure_set_menu_label (procedure, _("Apple Icon Image"));
|
||||
pika_procedure_set_icon_name (procedure, PIKA_ICON_BRUSH);
|
||||
|
||||
pika_procedure_set_documentation (procedure,
|
||||
"Saves files in Apple Icon Image file format",
|
||||
"Saves files in Apple Icon Image file format",
|
||||
name);
|
||||
pika_procedure_set_attribution (procedure,
|
||||
"Brion Vibber <brion@pobox.com>",
|
||||
"Brion Vibber <brion@pobox.com>",
|
||||
"2004");
|
||||
|
||||
pika_file_procedure_set_mime_types (PIKA_FILE_PROCEDURE (procedure),
|
||||
"image/x-icns");
|
||||
pika_file_procedure_set_extensions (PIKA_FILE_PROCEDURE (procedure),
|
||||
"icns");
|
||||
}
|
||||
|
||||
return procedure;
|
||||
}
|
||||
|
||||
static PikaValueArray *
|
||||
icns_load (PikaProcedure *procedure,
|
||||
PikaRunMode run_mode,
|
||||
GFile *file,
|
||||
const PikaValueArray *args,
|
||||
gpointer run_data)
|
||||
{
|
||||
PikaValueArray *return_vals;
|
||||
PikaImage *image;
|
||||
GError *error = NULL;
|
||||
|
||||
gegl_init (NULL, NULL);
|
||||
|
||||
image = icns_load_image (file, NULL, &error);
|
||||
|
||||
if (! image)
|
||||
return pika_procedure_new_return_values (procedure,
|
||||
PIKA_PDB_EXECUTION_ERROR,
|
||||
error);
|
||||
|
||||
return_vals = pika_procedure_new_return_values (procedure,
|
||||
PIKA_PDB_SUCCESS,
|
||||
NULL);
|
||||
|
||||
PIKA_VALUES_SET_IMAGE (return_vals, 1, image);
|
||||
|
||||
return return_vals;
|
||||
}
|
||||
|
||||
static PikaValueArray *
|
||||
icns_load_thumb (PikaProcedure *procedure,
|
||||
GFile *file,
|
||||
gint size,
|
||||
const PikaValueArray *args,
|
||||
gpointer run_data)
|
||||
{
|
||||
PikaValueArray *return_vals;
|
||||
gint width;
|
||||
gint height;
|
||||
PikaImage *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 pika_procedure_new_return_values (procedure,
|
||||
PIKA_PDB_EXECUTION_ERROR,
|
||||
error);
|
||||
|
||||
return_vals = pika_procedure_new_return_values (procedure,
|
||||
PIKA_PDB_SUCCESS,
|
||||
NULL);
|
||||
|
||||
PIKA_VALUES_SET_IMAGE (return_vals, 1, image);
|
||||
PIKA_VALUES_SET_INT (return_vals, 2, width);
|
||||
PIKA_VALUES_SET_INT (return_vals, 3, height);
|
||||
|
||||
pika_value_array_truncate (return_vals, 4);
|
||||
|
||||
return return_vals;
|
||||
}
|
||||
|
||||
static PikaValueArray *
|
||||
icns_save (PikaProcedure *procedure,
|
||||
PikaRunMode run_mode,
|
||||
PikaImage *image,
|
||||
gint n_drawables,
|
||||
PikaDrawable **drawables,
|
||||
GFile *file,
|
||||
const PikaValueArray *args,
|
||||
gpointer run_data)
|
||||
{
|
||||
PikaPDBStatusType status;
|
||||
GError *error = NULL;
|
||||
|
||||
gegl_init (NULL, NULL);
|
||||
|
||||
status = icns_save_image (file, image, run_mode, &error);
|
||||
|
||||
return pika_procedure_new_return_values (procedure, status, error);
|
||||
}
|
||||
|
||||
/* Buffer should point to *at least 5 byte buffer*! */
|
||||
void
|
||||
fourcc_get_string (gchar *fourcc,
|
||||
gchar *buf)
|
||||
{
|
||||
buf = fourcc;
|
||||
buf[4] = 0;
|
||||
}
|
70
plug-ins/file-icns/file-icns.h
Normal file
70
plug-ins/file-icns/file-icns.h
Normal file
@ -0,0 +1,70 @@
|
||||
/* PIKA - Photo and Image Kooker Application
|
||||
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
|
||||
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
|
||||
*
|
||||
* Original copyright, applying to most contents (license remains unchanged):
|
||||
* 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 "pika-file-icns"
|
||||
|
||||
#define ICNS_MAXBUF 4096
|
||||
#define ICNS_TYPE_NUM 34
|
||||
|
||||
typedef struct _IcnsResourceHeader
|
||||
{
|
||||
/* Big-endian! */
|
||||
gchar type[4];
|
||||
guint32 size;
|
||||
} IcnsResourceHeader;
|
||||
|
||||
typedef struct _IcnsResource
|
||||
{
|
||||
gchar type[5];
|
||||
guint32 size;
|
||||
guint32 cursor;
|
||||
guchar *data;
|
||||
} IcnsResource;
|
||||
|
||||
typedef struct _IcnsSaveInfo
|
||||
{
|
||||
GList *layers;
|
||||
gint num_icons;
|
||||
} IcnsSaveInfo;
|
||||
|
||||
void
|
||||
fourcc_get_string (gchar *fourcc,
|
||||
gchar *buf);
|
||||
|
||||
#endif /* __ICNS_H__ */
|
32
plug-ins/file-icns/meson.build
Normal file
32
plug-ins/file-icns/meson.build
Normal file
@ -0,0 +1,32 @@
|
||||
plugin_name = 'file-icns'
|
||||
|
||||
plugin_sources = [
|
||||
'file-icns-data.c',
|
||||
'file-icns-load.c',
|
||||
'file-icns-save.c',
|
||||
'file-icns.c',
|
||||
]
|
||||
|
||||
if platform_windows
|
||||
plugin_sources += windows.compile_resources(
|
||||
pika_plugins_rc,
|
||||
args: [
|
||||
'--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
|
||||
'--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
|
||||
'--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
|
||||
],
|
||||
include_directories: [
|
||||
rootInclude, appInclude,
|
||||
],
|
||||
)
|
||||
endif
|
||||
|
||||
executable(plugin_name,
|
||||
plugin_sources,
|
||||
dependencies: [
|
||||
libpikaui_dep,
|
||||
libpng,
|
||||
],
|
||||
install: true,
|
||||
install_dir: pikaplugindir / 'plug-ins' / plugin_name,
|
||||
)
|
Reference in New Issue
Block a user