2007-06-06 08:44:52 +00:00
|
|
|
/* tiff loading for GIMP
|
1997-11-24 22:05:25 +00:00
|
|
|
* -Peter Mattis
|
2003-12-02 22:32:42 +00:00
|
|
|
*
|
1998-05-18 00:54:11 +00:00
|
|
|
* The TIFF loading code has been completely revamped by Nick Lamb
|
|
|
|
* njl195@zepler.org.uk -- 18 May 1998
|
1999-09-17 22:28:25 +00:00
|
|
|
* And it now gains support for tiles (and doubtless a zillion bugs)
|
|
|
|
* njl195@zepler.org.uk -- 12 June 1999
|
2000-04-20 04:38:31 +00:00
|
|
|
* LZW patent fuss continues :(
|
|
|
|
* njl195@zepler.org.uk -- 20 April 2000
|
1997-11-24 22:05:25 +00:00
|
|
|
* The code for this filter is based on "tifftopnm" and "pnmtotiff",
|
|
|
|
* 2 programs that are a part of the netpbm package.
|
2000-06-18 01:07:13 +00:00
|
|
|
* khk@khk.net -- 13 May 2000
|
2003-07-15 12:35:39 +00:00
|
|
|
* Added support for ICCPROFILE tiff tag. If this tag is present in a
|
2000-06-18 01:07:13 +00:00
|
|
|
* TIFF file, then a parasite is created and vice versa.
|
2002-12-13 14:57:16 +00:00
|
|
|
* peter@kirchgessner.net -- 29 Oct 2002
|
|
|
|
* Progress bar only when run interactive
|
2004-01-09 19:48:07 +00:00
|
|
|
* Added support for layer offsets - pablo.dangelo@web.de -- 7 Jan 2004
|
2004-01-16 21:28:31 +00:00
|
|
|
* Honor EXTRASAMPLES tag while loading images with alphachannel
|
|
|
|
* pablo.dangelo@web.de -- 16 Jan 2004
|
1997-11-24 22:05:25 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2006-09-12 20:45:51 +00:00
|
|
|
* tifftopnm.c - converts a Tagged Image File to a portable anymap
|
|
|
|
*
|
|
|
|
* Derived by Jef Poskanzer from tif2ras.c, which is:
|
|
|
|
*
|
|
|
|
* Copyright (c) 1990 by Sun Microsystems, Inc.
|
|
|
|
*
|
|
|
|
* Author: Patrick J. Naughton
|
|
|
|
* naughton@wind.sun.com
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software and its
|
|
|
|
* documentation for any purpose and without fee is hereby granted,
|
|
|
|
* provided that the above copyright notice appear in all copies and that
|
|
|
|
* both that copyright notice and this permission notice appear in
|
|
|
|
* supporting documentation.
|
|
|
|
*
|
|
|
|
* This file is provided AS IS with no warranties of any kind. The author
|
|
|
|
* shall have no liability with respect to the infringement of copyrights,
|
|
|
|
* trade secrets or any patents by this file or any part thereof. In no
|
|
|
|
* event will the author be liable for any lost revenue or profits or
|
|
|
|
* other special, indirect and consequential damages.
|
|
|
|
*/
|
1997-11-24 22:05:25 +00:00
|
|
|
|
2000-01-25 17:46:56 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2003-06-13 14:37:00 +00:00
|
|
|
#include <errno.h>
|
1997-11-24 22:05:25 +00:00
|
|
|
#include <string.h>
|
2003-06-13 14:37:00 +00:00
|
|
|
|
2022-12-19 16:29:41 +00:00
|
|
|
#include <gio/gio.h>
|
|
|
|
#include <glib/gstdio.h>
|
|
|
|
|
1997-11-24 22:05:25 +00:00
|
|
|
#include <tiffio.h>
|
2000-01-08 20:00:10 +00:00
|
|
|
|
|
|
|
#include <libgimp/gimp.h>
|
|
|
|
#include <libgimp/gimpui.h>
|
2000-01-25 17:46:56 +00:00
|
|
|
|
2020-05-18 00:13:21 +02:00
|
|
|
#include "file-tiff.h"
|
2019-06-17 17:11:11 +02:00
|
|
|
#include "file-tiff-io.h"
|
2015-12-03 01:02:43 +01:00
|
|
|
#include "file-tiff-load.h"
|
|
|
|
|
2000-01-09 06:02:20 +00:00
|
|
|
#include "libgimp/stdplugins-intl.h"
|
1998-10-11 22:50:03 +00:00
|
|
|
|
2000-05-01 20:22:55 +00:00
|
|
|
|
2015-12-03 01:02:43 +01:00
|
|
|
#define PLUG_IN_ROLE "gimp-file-tiff-load"
|
2005-08-15 22:42:34 +00:00
|
|
|
|
|
|
|
|
2000-01-25 17:46:56 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
2019-08-17 10:52:05 +02:00
|
|
|
GimpDrawable *drawable;
|
|
|
|
GeglBuffer *buffer;
|
|
|
|
const Babl *format;
|
|
|
|
guchar *pixels;
|
|
|
|
guchar *pixel;
|
2014-09-13 21:59:30 +02:00
|
|
|
} ChannelData;
|
1998-11-09 02:05:24 +00:00
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
GIMP_TIFF_LOAD_ASSOCALPHA,
|
|
|
|
GIMP_TIFF_LOAD_UNASSALPHA,
|
|
|
|
GIMP_TIFF_LOAD_CHANNEL
|
|
|
|
} DefaultExtra;
|
2014-09-13 21:59:30 +02:00
|
|
|
|
2021-03-04 12:40:14 -05:00
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
GIMP_TIFF_DEFAULT,
|
|
|
|
GIMP_TIFF_INDEXED,
|
|
|
|
GIMP_TIFF_GRAY,
|
|
|
|
GIMP_TIFF_GRAY_MINISWHITE,
|
|
|
|
} TiffColorMode;
|
|
|
|
|
2015-12-03 01:02:43 +01:00
|
|
|
/* Declare some local functions */
|
|
|
|
|
2024-05-31 04:34:51 +00:00
|
|
|
static GimpColorProfile * load_profile (TIFF *tif);
|
|
|
|
|
|
|
|
static void load_rgba (TIFF *tif,
|
|
|
|
ChannelData *channel);
|
|
|
|
static void load_contiguous (TIFF *tif,
|
|
|
|
ChannelData *channel,
|
|
|
|
const Babl *type,
|
|
|
|
gushort bps,
|
|
|
|
gushort spp,
|
|
|
|
TiffColorMode tiff_mode,
|
|
|
|
gboolean is_signed,
|
|
|
|
gint extra);
|
|
|
|
static void load_separate (TIFF *tif,
|
|
|
|
ChannelData *channel,
|
|
|
|
const Babl *type,
|
|
|
|
gushort bps,
|
|
|
|
gushort spp,
|
|
|
|
TiffColorMode tiff_mode,
|
|
|
|
gboolean is_signed,
|
|
|
|
gint extra);
|
|
|
|
|
2024-08-06 22:56:57 +00:00
|
|
|
static void load_sketchbook_layers (TIFF *tif,
|
|
|
|
GimpImage *image);
|
|
|
|
|
2024-05-31 04:34:51 +00:00
|
|
|
static gboolean is_non_conformant_tiff (gushort photomet,
|
|
|
|
gushort spp);
|
|
|
|
static gushort get_extra_channels_count (gushort photomet,
|
|
|
|
gushort spp,
|
|
|
|
gboolean alpha);
|
|
|
|
|
|
|
|
static void fill_bit2byte (TiffColorMode tiff_mode);
|
|
|
|
static void fill_2bit2byte (TiffColorMode tiff_mode);
|
|
|
|
static void fill_4bit2byte (TiffColorMode tiff_mode);
|
|
|
|
static void convert_bit2byte (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
gint width,
|
|
|
|
gint height);
|
|
|
|
static void convert_2bit2byte (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
gint width,
|
|
|
|
gint height);
|
|
|
|
static void convert_4bit2byte (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
gint width,
|
|
|
|
gint height);
|
|
|
|
|
|
|
|
static void convert_miniswhite (guchar *buffer,
|
|
|
|
gint width,
|
|
|
|
gint height);
|
|
|
|
static void convert_int2uint (guchar *buffer,
|
|
|
|
gint bps,
|
|
|
|
gint spp,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
gint stride);
|
|
|
|
|
|
|
|
static gboolean load_dialog (GimpProcedure *procedure,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
TiffSelectedPages *pages,
|
|
|
|
const gchar *extra_message,
|
|
|
|
DefaultExtra *default_extra);
|
|
|
|
|
|
|
|
static void tiff_dialog_show_reduced (GtkWidget *toggle,
|
|
|
|
gpointer data);
|
2022-06-13 11:05:12 +00:00
|
|
|
|
|
|
|
|
1997-11-24 22:05:25 +00:00
|
|
|
|
2022-06-07 18:41:00 -04:00
|
|
|
/* Grayscale conversion mappings */
|
|
|
|
static const guchar _1_to_8_bitmap [2] =
|
|
|
|
{
|
|
|
|
0, 255
|
|
|
|
};
|
|
|
|
|
|
|
|
static const guchar _1_to_8_bitmap_rev [2] =
|
|
|
|
{
|
|
|
|
255, 0
|
|
|
|
};
|
|
|
|
|
|
|
|
static const guchar _2_to_8_bitmap [4] =
|
|
|
|
{
|
|
|
|
0, 85, 170, 255
|
|
|
|
};
|
|
|
|
|
|
|
|
static const guchar _2_to_8_bitmap_rev [4] =
|
|
|
|
{
|
|
|
|
255, 170, 85, 0
|
|
|
|
};
|
|
|
|
|
|
|
|
static const guchar _4_to_8_bitmap [16] =
|
|
|
|
{
|
|
|
|
0, 17, 34, 51, 68, 85, 102, 119,
|
|
|
|
136, 153, 170, 187, 204, 221, 238, 255
|
|
|
|
};
|
|
|
|
|
|
|
|
static const guchar _4_to_8_bitmap_rev [16] =
|
|
|
|
{
|
|
|
|
255, 238, 221, 204, 187, 170, 153, 136,
|
|
|
|
119, 102, 85, 68, 51, 34, 17, 0
|
|
|
|
};
|
|
|
|
|
|
|
|
static guchar bit2byte[256 * 8];
|
|
|
|
static guchar _2bit2byte[256 * 4];
|
|
|
|
static guchar _4bit2byte[256 * 2];
|
|
|
|
|
|
|
|
|
2007-05-17 19:51:25 +00:00
|
|
|
/* returns a pointer into the TIFF */
|
|
|
|
static const gchar *
|
|
|
|
tiff_get_page_name (TIFF *tif)
|
|
|
|
{
|
|
|
|
static gchar *name;
|
|
|
|
|
|
|
|
if (TIFFGetField (tif, TIFFTAG_PAGENAME, &name) &&
|
|
|
|
g_utf8_validate (name, -1, NULL))
|
|
|
|
{
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-01-14 12:37:59 -05:00
|
|
|
/* is_non_conformant_tiff assumes TIFFTAG_EXTRASAMPLES was not set */
|
|
|
|
static gboolean
|
|
|
|
is_non_conformant_tiff (gushort photomet, gushort spp)
|
|
|
|
{
|
|
|
|
switch (photomet)
|
|
|
|
{
|
|
|
|
case PHOTOMETRIC_RGB:
|
|
|
|
case PHOTOMETRIC_YCBCR:
|
|
|
|
case PHOTOMETRIC_CIELAB:
|
|
|
|
case PHOTOMETRIC_ICCLAB:
|
|
|
|
case PHOTOMETRIC_ITULAB:
|
|
|
|
case PHOTOMETRIC_LOGLUV:
|
|
|
|
return (spp > 3 || (spp == 2 && photomet != PHOTOMETRIC_RGB));
|
|
|
|
break;
|
|
|
|
case PHOTOMETRIC_SEPARATED:
|
|
|
|
return (spp > 4);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return (spp > 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get_extra_channels_count returns number of channels excluding
|
|
|
|
* alpha and color channels
|
|
|
|
*/
|
|
|
|
static gushort
|
|
|
|
get_extra_channels_count (gushort photomet, gushort spp, gboolean alpha)
|
|
|
|
{
|
|
|
|
switch (photomet)
|
|
|
|
{
|
|
|
|
case PHOTOMETRIC_RGB:
|
|
|
|
case PHOTOMETRIC_YCBCR:
|
|
|
|
case PHOTOMETRIC_CIELAB:
|
|
|
|
case PHOTOMETRIC_ICCLAB:
|
|
|
|
case PHOTOMETRIC_ITULAB:
|
|
|
|
case PHOTOMETRIC_LOGLUV:
|
|
|
|
if (spp >= 3)
|
|
|
|
return spp - 3 - (alpha? 1 : 0);
|
|
|
|
else
|
|
|
|
return spp - 1 - (alpha? 1 : 0);
|
|
|
|
break;
|
|
|
|
case PHOTOMETRIC_SEPARATED:
|
|
|
|
return spp - 4 - (alpha? 1 : 0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return spp - 1 - (alpha? 1 : 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
GimpPDBStatusType
|
2024-05-31 04:34:51 +00:00
|
|
|
load_image (GimpProcedure *procedure,
|
|
|
|
GFile *file,
|
2023-10-26 21:26:21 +02:00
|
|
|
GimpRunMode run_mode,
|
|
|
|
GimpImage **image,
|
|
|
|
gboolean *resolution_loaded,
|
|
|
|
gboolean *profile_loaded,
|
|
|
|
gboolean *ps_metadata_loaded,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
GError **error)
|
2007-04-24 18:36:35 +00:00
|
|
|
{
|
2019-06-17 17:11:11 +02:00
|
|
|
TIFF *tif;
|
|
|
|
TiffSelectedPages pages;
|
|
|
|
|
2020-05-18 00:13:21 +02:00
|
|
|
GList *images_list = NULL;
|
|
|
|
DefaultExtra default_extra = GIMP_TIFF_LOAD_UNASSALPHA;
|
|
|
|
gint first_image_type = GIMP_RGB;
|
|
|
|
gint min_row = G_MAXINT;
|
|
|
|
gint min_col = G_MAXINT;
|
|
|
|
gint max_row = 0;
|
|
|
|
gint max_col = 0;
|
|
|
|
gboolean save_transp_pixels = FALSE;
|
2020-12-16 17:56:18 -05:00
|
|
|
GimpColorProfile *first_profile = NULL;
|
2021-08-27 15:15:12 -04:00
|
|
|
const gchar *extra_message = NULL;
|
2019-06-17 17:11:11 +02:00
|
|
|
gint li;
|
2022-06-13 11:05:12 +00:00
|
|
|
gint selectable_pages;
|
2022-12-19 16:29:41 +00:00
|
|
|
gchar *photoshop_data;
|
|
|
|
gint32 photoshop_len;
|
|
|
|
gboolean is_cmyk = FALSE;
|
2024-08-06 22:56:57 +00:00
|
|
|
gchar *sketchbook_info;
|
|
|
|
gint sketchbook_len;
|
|
|
|
gboolean sketchbook_layers = FALSE;
|
2019-06-17 17:11:11 +02:00
|
|
|
|
2019-08-17 10:52:05 +02:00
|
|
|
*image = NULL;
|
2019-06-17 17:11:11 +02:00
|
|
|
gimp_progress_init_printf (_("Opening '%s'"),
|
|
|
|
gimp_file_get_utf8_name (file));
|
2007-05-15 07:12:15 +00:00
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
tif = tiff_open (file, "r", error);
|
|
|
|
if (! tif)
|
2021-03-02 16:08:55 -05:00
|
|
|
{
|
|
|
|
if (! (error && *error))
|
|
|
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
|
|
_("Not a TIFF image or image is corrupt."));
|
|
|
|
|
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
|
|
|
}
|
2007-04-24 18:36:35 +00:00
|
|
|
|
2023-10-26 21:26:21 +02:00
|
|
|
g_object_get (config, "target", &pages.target, NULL);
|
|
|
|
g_object_get (config, "keep-empty-space", &pages.keep_empty_space, NULL);
|
2007-04-24 18:36:35 +00:00
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
pages.n_pages = pages.o_pages = TIFFNumberOfDirectories (tif);
|
|
|
|
if (pages.n_pages == 0)
|
2007-04-24 18:36:35 +00:00
|
|
|
{
|
2020-11-16 15:05:15 +01:00
|
|
|
/* See #5837.
|
|
|
|
* It seems we might be able to rescue some data even though the
|
|
|
|
* TIFF is possibly syntactically wrong.
|
|
|
|
*/
|
2020-11-16 16:10:25 +01:00
|
|
|
|
|
|
|
/* libtiff says max number of directory is 65535. */
|
|
|
|
for (li = 0; li < 65536; li++)
|
|
|
|
{
|
|
|
|
if (TIFFSetDirectory (tif, li) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pages.n_pages = li;
|
|
|
|
if (pages.n_pages == 0)
|
|
|
|
{
|
|
|
|
TIFFClose (tif);
|
|
|
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
|
|
_("TIFF '%s' does not contain any directories"),
|
|
|
|
gimp_file_get_utf8_name (file));
|
|
|
|
|
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
TIFFSetDirectory (tif, 0);
|
|
|
|
g_message (ngettext ("TIFF '%s' directory count by header failed "
|
|
|
|
"though there seems to be %d page."
|
|
|
|
" Attempting to load the file with this assumption.",
|
|
|
|
"TIFF '%s' directory count by header failed "
|
|
|
|
"though there seem to be %d pages."
|
|
|
|
" Attempting to load the file with this assumption.",
|
|
|
|
pages.n_pages),
|
|
|
|
gimp_file_get_utf8_name (file), pages.n_pages);
|
2007-04-24 18:36:35 +00:00
|
|
|
}
|
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
pages.pages = NULL;
|
2021-08-27 15:15:12 -04:00
|
|
|
pages.n_filtered_pages = pages.n_pages;
|
2022-06-13 11:05:12 +00:00
|
|
|
pages.n_reducedimage_pages = pages.n_pages;
|
2021-08-27 15:15:12 -04:00
|
|
|
|
|
|
|
pages.filtered_pages = g_new0 (gint, pages.n_pages);
|
|
|
|
for (li = 0; li < pages.n_pages; li++)
|
|
|
|
pages.filtered_pages[li] = li;
|
2007-04-24 18:36:35 +00:00
|
|
|
|
2022-08-22 12:39:29 -04:00
|
|
|
if (pages.n_pages == 1 || run_mode != GIMP_RUN_INTERACTIVE)
|
2021-08-27 15:15:12 -04:00
|
|
|
{
|
|
|
|
pages.pages = g_new0 (gint, pages.n_pages);
|
2022-08-22 12:39:29 -04:00
|
|
|
for (li = 0; li < pages.n_pages; li++)
|
|
|
|
pages.pages[li] = li;
|
2021-08-27 15:15:12 -04:00
|
|
|
pages.target = GIMP_PAGE_SELECTOR_TARGET_LAYERS;
|
2019-06-17 17:11:11 +02:00
|
|
|
}
|
2021-08-27 15:15:12 -04:00
|
|
|
|
|
|
|
/* Check all pages if any has an unspecified or unset channel. */
|
|
|
|
for (li = 0; li < pages.n_pages; li++)
|
2019-06-17 17:11:11 +02:00
|
|
|
{
|
2021-08-27 15:15:12 -04:00
|
|
|
gushort spp;
|
|
|
|
gushort photomet;
|
|
|
|
gushort extra;
|
|
|
|
gushort *extra_types;
|
|
|
|
gushort file_type = 0;
|
|
|
|
gboolean first_page_old_jpeg = FALSE;
|
2015-12-03 01:02:43 +01:00
|
|
|
|
2021-08-27 15:15:12 -04:00
|
|
|
if (TIFFSetDirectory (tif, li) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
TIFFGetFieldDefaulted (tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
|
|
|
|
if (! TIFFGetField (tif, TIFFTAG_PHOTOMETRIC, &photomet))
|
2019-06-17 17:11:11 +02:00
|
|
|
{
|
2021-08-27 15:15:12 -04:00
|
|
|
guint16 compression;
|
|
|
|
|
|
|
|
if (TIFFGetField (tif, TIFFTAG_COMPRESSION, &compression) &&
|
|
|
|
(compression == COMPRESSION_CCITTFAX3 ||
|
|
|
|
compression == COMPRESSION_CCITTFAX4 ||
|
|
|
|
compression == COMPRESSION_CCITTRLE ||
|
|
|
|
compression == COMPRESSION_CCITTRLEW))
|
|
|
|
{
|
|
|
|
photomet = PHOTOMETRIC_MINISWHITE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* old AppleScan software misses out the photometric tag
|
|
|
|
* (and incidentally assumes min-is-white, but xv
|
|
|
|
* assumes min-is-black, so we follow xv's lead. It's
|
|
|
|
* not much hardship to invert the image later).
|
|
|
|
*/
|
|
|
|
photomet = PHOTOMETRIC_MINISBLACK;
|
|
|
|
}
|
2019-06-17 17:11:11 +02:00
|
|
|
}
|
2021-08-27 15:15:12 -04:00
|
|
|
if (! TIFFGetField (tif, TIFFTAG_EXTRASAMPLES, &extra, &extra_types))
|
|
|
|
extra = 0;
|
2019-04-16 10:04:16 +02:00
|
|
|
|
2021-08-27 15:15:12 -04:00
|
|
|
/* Try to detect if a TIFF page is a thumbnail.
|
|
|
|
* Easy case: if subfiletype is set to FILETYPE_REDUCEDIMAGE.
|
|
|
|
* If no subfiletype is defined we try to detect it ourselves.
|
|
|
|
* We will consider it a thumbnail if:
|
|
|
|
* - It's the second page
|
|
|
|
* - PhotometricInterpretation is YCbCr
|
|
|
|
* - Compression is old style jpeg
|
|
|
|
* - First page uses a different compression or PhotometricInterpretation
|
|
|
|
*
|
|
|
|
* We could also add a check for the presence of TIFFTAG_EXIFIFD since
|
|
|
|
* this should usually be a thumbnail part of EXIF metadata. Since that
|
|
|
|
* probably won't make a difference, I will leave that out for now.
|
|
|
|
*/
|
|
|
|
if (li == 0)
|
2015-12-03 01:02:43 +01:00
|
|
|
{
|
2021-08-27 15:15:12 -04:00
|
|
|
guint16 compression;
|
2019-06-17 17:11:11 +02:00
|
|
|
|
2021-08-27 15:15:12 -04:00
|
|
|
if (TIFFGetField (tif, TIFFTAG_COMPRESSION, &compression) &&
|
|
|
|
compression == COMPRESSION_OJPEG &&
|
|
|
|
photomet == PHOTOMETRIC_YCBCR)
|
|
|
|
first_page_old_jpeg = TRUE;
|
|
|
|
}
|
2020-11-16 16:10:25 +01:00
|
|
|
|
2021-08-27 15:15:12 -04:00
|
|
|
if (TIFFGetField (tif, TIFFTAG_SUBFILETYPE, &file_type))
|
|
|
|
{
|
|
|
|
if (file_type == FILETYPE_REDUCEDIMAGE)
|
|
|
|
{
|
|
|
|
/* file_type is a mask but we will only filter out pages
|
|
|
|
* that only have FILETYPE_REDUCEDIMAGE set */
|
2022-06-13 11:05:12 +00:00
|
|
|
pages.filtered_pages[li] = TIFF_REDUCEDFILE;
|
2021-08-27 15:15:12 -04:00
|
|
|
pages.n_filtered_pages--;
|
|
|
|
g_debug ("Page %d is a FILETYPE_REDUCEDIMAGE thumbnail.\n", li);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (li == 1 && photomet == PHOTOMETRIC_YCBCR &&
|
|
|
|
! first_page_old_jpeg)
|
2019-06-17 17:11:11 +02:00
|
|
|
{
|
|
|
|
guint16 compression;
|
2015-12-03 01:02:43 +01:00
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
if (TIFFGetField (tif, TIFFTAG_COMPRESSION, &compression) &&
|
2021-08-27 15:15:12 -04:00
|
|
|
compression == COMPRESSION_OJPEG)
|
2019-06-17 17:11:11 +02:00
|
|
|
{
|
2022-06-13 11:05:12 +00:00
|
|
|
pages.filtered_pages[li] = TIFF_MISC_THUMBNAIL;
|
2021-08-27 15:15:12 -04:00
|
|
|
pages.n_filtered_pages--;
|
2022-06-13 11:05:12 +00:00
|
|
|
/* This is used to conditionally show reduced images
|
|
|
|
* if they're not a thumbnail
|
|
|
|
*/
|
|
|
|
pages.n_reducedimage_pages--;
|
2021-08-27 15:15:12 -04:00
|
|
|
g_debug ("Page %d is most likely a thumbnail.\n", li);
|
2019-06-17 17:11:11 +02:00
|
|
|
}
|
|
|
|
}
|
2021-08-27 15:15:12 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: current code always assumes that the alpha channel
|
|
|
|
* will be the first extra channel, though the TIFF spec does
|
|
|
|
* not mandate such assumption. A future improvement should be
|
|
|
|
* to actually loop through the extra channels and save the
|
|
|
|
* alpha channel index.
|
|
|
|
* Of course, this is an edge case, as most image would likely
|
|
|
|
* have only a single extra channel anyway. But still we could
|
|
|
|
* be more accurate.
|
|
|
|
*/
|
|
|
|
if (extra > 0 && (extra_types[0] == EXTRASAMPLE_UNSPECIFIED))
|
|
|
|
{
|
|
|
|
extra_message = _("Extra channels with unspecified data.");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (extra == 0 && is_non_conformant_tiff (photomet, spp))
|
|
|
|
{
|
|
|
|
/* ExtraSamples field not set, yet we have more channels than
|
|
|
|
* the PhotometricInterpretation field suggests.
|
|
|
|
* This should not happen as the spec clearly says "This field
|
|
|
|
* must be present if there are extra samples". So the files
|
|
|
|
* can be considered non-conformant.
|
|
|
|
* Let's ask what to do with the channel.
|
2019-06-17 17:11:11 +02:00
|
|
|
*/
|
2021-08-27 15:15:12 -04:00
|
|
|
extra_message = _("Non-conformant TIFF: extra channels without 'ExtraSamples' field.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
TIFFSetDirectory (tif, 0);
|
|
|
|
|
2024-08-06 22:56:57 +00:00
|
|
|
/* Check if there exist layers saved from Alias/AutoDesk Sketchbook */
|
2025-05-28 12:38:47 +00:00
|
|
|
#ifdef TIFFTAG_ALIAS_LAYER_METADATA
|
2024-08-06 22:56:57 +00:00
|
|
|
sketchbook_layers = TIFFGetField (tif, TIFFTAG_ALIAS_LAYER_METADATA,
|
|
|
|
&sketchbook_info, &sketchbook_len);
|
2025-05-28 12:38:47 +00:00
|
|
|
#endif
|
2024-08-06 22:56:57 +00:00
|
|
|
|
2022-06-13 11:05:12 +00:00
|
|
|
pages.show_reduced = FALSE;
|
|
|
|
if (pages.n_reducedimage_pages - pages.n_filtered_pages > 1)
|
|
|
|
pages.show_reduced = TRUE;
|
|
|
|
|
|
|
|
pages.tif = tif;
|
|
|
|
|
2024-05-31 04:34:51 +00:00
|
|
|
if (run_mode == GIMP_RUN_INTERACTIVE &&
|
2021-08-27 15:15:12 -04:00
|
|
|
(pages.n_pages > 1 || extra_message) &&
|
2024-05-31 04:34:51 +00:00
|
|
|
! load_dialog (procedure, config, &pages, extra_message,
|
|
|
|
&default_extra))
|
2021-08-27 15:15:12 -04:00
|
|
|
{
|
|
|
|
TIFFClose (tif);
|
|
|
|
g_clear_pointer (&pages.pages, g_free);
|
|
|
|
|
|
|
|
return GIMP_PDB_CANCEL;
|
|
|
|
}
|
2022-06-13 11:05:12 +00:00
|
|
|
|
|
|
|
selectable_pages = pages.n_filtered_pages;
|
|
|
|
if (pages.show_reduced)
|
|
|
|
selectable_pages = pages.n_reducedimage_pages;
|
|
|
|
|
2021-08-27 15:15:12 -04:00
|
|
|
/* Adjust pages to take filtered out pages into account. */
|
2022-06-13 11:05:12 +00:00
|
|
|
if (pages.o_pages > selectable_pages)
|
2021-08-27 15:15:12 -04:00
|
|
|
{
|
|
|
|
gint fi;
|
|
|
|
gint sel_index = 0;
|
|
|
|
gint sel_add = 0;
|
|
|
|
|
|
|
|
for (fi = 0; fi < pages.o_pages && sel_index < pages.n_pages; fi++)
|
|
|
|
{
|
2022-06-13 11:05:12 +00:00
|
|
|
if ((pages.show_reduced && pages.filtered_pages[fi] == TIFF_MISC_THUMBNAIL) ||
|
|
|
|
(! pages.show_reduced && pages.filtered_pages[fi] <= TIFF_MISC_THUMBNAIL))
|
2019-06-17 17:11:11 +02:00
|
|
|
{
|
2021-08-27 15:15:12 -04:00
|
|
|
sel_add++;
|
2019-06-17 17:11:11 +02:00
|
|
|
}
|
2021-08-27 15:15:12 -04:00
|
|
|
if (pages.pages[sel_index] + sel_add == fi)
|
2019-06-17 17:11:11 +02:00
|
|
|
{
|
2021-08-27 15:15:12 -04:00
|
|
|
pages.pages[sel_index] = fi;
|
|
|
|
sel_index++;
|
2019-06-17 17:11:11 +02:00
|
|
|
}
|
2015-12-03 01:02:43 +01:00
|
|
|
}
|
2019-06-17 17:11:11 +02:00
|
|
|
}
|
2001-01-25 01:20:05 +00:00
|
|
|
|
2023-10-26 21:26:21 +02:00
|
|
|
g_object_set (config, "target", pages.target, NULL);
|
|
|
|
g_object_set (config, "keep-empty-space", pages.keep_empty_space, NULL);
|
2007-04-24 18:36:35 +00:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
/* We will loop through the all pages in case of multipage TIFF
|
|
|
|
* and load every page as a separate layer.
|
|
|
|
*/
|
2019-06-17 17:11:11 +02:00
|
|
|
for (li = 0; li < pages.n_pages; li++)
|
2003-12-02 22:32:42 +00:00
|
|
|
{
|
2015-11-23 22:29:06 +01:00
|
|
|
gint ilayer;
|
|
|
|
gushort bps;
|
|
|
|
gushort spp;
|
|
|
|
gushort photomet;
|
|
|
|
gshort sampleformat;
|
|
|
|
GimpColorProfile *profile;
|
|
|
|
gboolean profile_linear = FALSE;
|
|
|
|
GimpPrecision image_precision;
|
|
|
|
const Babl *type;
|
|
|
|
const Babl *base_format = NULL;
|
2022-04-18 11:00:10 +00:00
|
|
|
const Babl *space = NULL;
|
2015-11-23 22:29:06 +01:00
|
|
|
guint16 orientation;
|
|
|
|
gint cols;
|
|
|
|
gint rows;
|
|
|
|
gboolean alpha;
|
|
|
|
gint image_type = GIMP_RGB;
|
2019-08-17 10:52:05 +02:00
|
|
|
GimpLayer *layer;
|
2015-11-23 22:29:06 +01:00
|
|
|
gint layer_type = GIMP_RGB_IMAGE;
|
|
|
|
float layer_offset_x = 0.0;
|
|
|
|
float layer_offset_y = 0.0;
|
|
|
|
gint layer_offset_x_pixel = 0;
|
|
|
|
gint layer_offset_y_pixel = 0;
|
|
|
|
gushort extra;
|
|
|
|
gushort *extra_types;
|
|
|
|
ChannelData *channel = NULL;
|
2021-10-16 16:37:33 +03:00
|
|
|
uint16_t planar = PLANARCONFIG_CONTIG;
|
2021-03-04 12:40:14 -05:00
|
|
|
TiffColorMode tiff_mode;
|
2020-06-24 15:16:50 +03:00
|
|
|
gboolean is_signed;
|
2015-11-23 22:29:06 +01:00
|
|
|
gint i;
|
|
|
|
gboolean worst_case = FALSE;
|
2020-05-18 00:13:21 +02:00
|
|
|
gint gimp_compression = GIMP_COMPRESSION_NONE;
|
2015-11-23 22:29:06 +01:00
|
|
|
const gchar *name;
|
2012-05-15 02:31:23 +02:00
|
|
|
|
2020-10-24 13:44:39 -04:00
|
|
|
if (TIFFSetDirectory (tif, pages.pages[li]) == 0)
|
|
|
|
{
|
|
|
|
g_message (_("Couldn't read page %d of %d. Image might be corrupt.\n"),
|
|
|
|
li+1, pages.n_pages);
|
|
|
|
continue;
|
|
|
|
}
|
2019-06-17 17:11:11 +02:00
|
|
|
ilayer = pages.pages[li];
|
2007-04-24 18:36:35 +00:00
|
|
|
|
2007-04-25 14:10:20 +00:00
|
|
|
gimp_progress_update (0.0);
|
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
TIFFGetFieldDefaulted (tif, TIFFTAG_BITSPERSAMPLE, &bps);
|
1998-05-18 00:54:11 +00:00
|
|
|
|
2014-09-12 18:50:44 +04:00
|
|
|
TIFFGetFieldDefaulted (tif, TIFFTAG_SAMPLEFORMAT, &sampleformat);
|
|
|
|
|
2015-11-23 22:29:06 +01:00
|
|
|
profile = load_profile (tif);
|
2020-12-16 17:56:18 -05:00
|
|
|
if (! profile && first_profile)
|
|
|
|
{
|
|
|
|
profile = first_profile;
|
|
|
|
g_object_ref (profile);
|
|
|
|
}
|
|
|
|
|
2015-11-23 22:29:06 +01:00
|
|
|
if (profile)
|
2019-06-20 18:08:59 +02:00
|
|
|
{
|
2020-12-16 17:56:18 -05:00
|
|
|
profile_linear = gimp_color_profile_is_linear (profile);
|
|
|
|
|
|
|
|
if (! first_profile)
|
|
|
|
{
|
|
|
|
first_profile = profile;
|
|
|
|
g_object_ref (first_profile);
|
|
|
|
|
|
|
|
if (profile_linear && li > 0 && pages.target != GIMP_PAGE_SELECTOR_TARGET_IMAGES)
|
|
|
|
g_message (_("This image has a linear color profile but "
|
|
|
|
"it was not set on the first layer. "
|
|
|
|
"The layers below layer # %d will be "
|
|
|
|
"interpreted as non linear."), li+1);
|
|
|
|
}
|
|
|
|
else if (pages.target != GIMP_PAGE_SELECTOR_TARGET_IMAGES &&
|
|
|
|
! gimp_color_profile_is_equal (first_profile, profile))
|
|
|
|
{
|
|
|
|
g_message (_("This image has multiple color profiles. "
|
|
|
|
"We will use the first one. If this leads "
|
|
|
|
"to incorrect results you should consider "
|
|
|
|
"loading each layer as a separate image."));
|
|
|
|
}
|
|
|
|
|
2019-06-20 18:08:59 +02:00
|
|
|
if (! *image)
|
|
|
|
*profile_loaded = TRUE;
|
|
|
|
}
|
2015-11-23 22:29:06 +01:00
|
|
|
|
2021-03-02 15:23:09 -05:00
|
|
|
if (bps > 64)
|
|
|
|
{
|
|
|
|
g_message (_("Suspicious bit depth: %d for page %d. Image may be corrupt."),
|
|
|
|
bps, li+1);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-09-12 18:50:44 +04:00
|
|
|
if (bps > 8 && bps != 8 && bps != 16 && bps != 32 && bps != 64)
|
2003-12-02 22:32:42 +00:00
|
|
|
worst_case = TRUE; /* Wrong sample width => RGBA */
|
1998-05-18 00:54:11 +00:00
|
|
|
|
2014-09-12 18:50:44 +04:00
|
|
|
switch (bps)
|
|
|
|
{
|
2015-09-13 00:12:42 +02:00
|
|
|
case 1:
|
2020-12-10 18:46:35 -05:00
|
|
|
case 2:
|
|
|
|
case 4:
|
2014-09-12 18:50:44 +04:00
|
|
|
case 8:
|
2015-11-23 22:29:06 +01:00
|
|
|
if (profile_linear)
|
|
|
|
image_precision = GIMP_PRECISION_U8_LINEAR;
|
|
|
|
else
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 14:23:01 +02:00
|
|
|
image_precision = GIMP_PRECISION_U8_NON_LINEAR;
|
2015-11-23 22:29:06 +01:00
|
|
|
|
|
|
|
type = babl_type ("u8");
|
2014-09-12 18:50:44 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 16:
|
|
|
|
if (sampleformat == SAMPLEFORMAT_IEEEFP)
|
|
|
|
{
|
2015-11-23 22:29:06 +01:00
|
|
|
if (profile_linear)
|
|
|
|
image_precision = GIMP_PRECISION_HALF_LINEAR;
|
|
|
|
else
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 14:23:01 +02:00
|
|
|
image_precision = GIMP_PRECISION_HALF_NON_LINEAR;
|
2015-11-23 22:29:06 +01:00
|
|
|
|
|
|
|
type = babl_type ("half");
|
2014-09-12 18:50:44 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-11-23 22:29:06 +01:00
|
|
|
if (profile_linear)
|
|
|
|
image_precision = GIMP_PRECISION_U16_LINEAR;
|
|
|
|
else
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 14:23:01 +02:00
|
|
|
image_precision = GIMP_PRECISION_U16_NON_LINEAR;
|
2015-11-23 22:29:06 +01:00
|
|
|
|
|
|
|
type = babl_type ("u16");
|
2014-09-12 18:50:44 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 32:
|
|
|
|
if (sampleformat == SAMPLEFORMAT_IEEEFP)
|
|
|
|
{
|
2015-11-23 22:29:06 +01:00
|
|
|
if (profile_linear)
|
|
|
|
image_precision = GIMP_PRECISION_FLOAT_LINEAR;
|
|
|
|
else
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 14:23:01 +02:00
|
|
|
image_precision = GIMP_PRECISION_FLOAT_NON_LINEAR;
|
2015-11-23 22:29:06 +01:00
|
|
|
|
|
|
|
type = babl_type ("float");
|
2014-09-12 18:50:44 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-11-23 22:29:06 +01:00
|
|
|
if (profile_linear)
|
|
|
|
image_precision = GIMP_PRECISION_U32_LINEAR;
|
|
|
|
else
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 14:23:01 +02:00
|
|
|
image_precision = GIMP_PRECISION_U32_NON_LINEAR;
|
2015-11-23 22:29:06 +01:00
|
|
|
|
|
|
|
type = babl_type ("u32");
|
2014-09-12 18:50:44 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 64:
|
2015-11-23 22:29:06 +01:00
|
|
|
if (profile_linear)
|
|
|
|
image_precision = GIMP_PRECISION_DOUBLE_LINEAR;
|
|
|
|
else
|
Initial space invasion commit in GIMP
All babl formats now have a space equivalent to a color profile,
determining the format's primaries and TRCs. This commit makes GIMP
aware of this.
libgimp:
- enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA
as deprecated aliases, add PERCEPTUAL values so we now have LINEAR,
NON_LINEAR and PERCPTUAL for each encoding, matching the babl
encoding variants RGB, R'G'B' and R~G~B~.
- gimp_color_transform_can_gegl_copy() now returns TRUE if both
profiles can return a babl space, increasing the amount of fast babl
color conversions significantly.
- TODO: no solution yet for getting libgimp drawable proxy buffers in
the right format with space.
plug-ins:
- follow the GimpPrecision change.
- TODO: everything else unchanged and partly broken or sub-optimal,
like setting a new image's color profile too late.
app:
- add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as
replacement for all "linear" booleans.
- change gimp-babl functions to take babl spaces and GimpTRCType
parameters and support all sorts of new perceptual ~ formats.
- a lot of places changed in the early days of goat invasion didn't
take advantage of gimp-babl utility functions and constructed
formats manually. They all needed revisiting and many now use much
simpler code calling gimp-babl API.
- change gimp_babl_format_get_color_profile() to really extract a
newly allocated color profile from the format, and add
gimp_babl_get_builtin_color_profile() which does the same as
gimp_babl_format_get_color_profile() did before. Visited all callers
to decide whether they are looking for the format's actual profile,
or for one of the builtin profiles, simplifying code that only needs
builtin profiles.
- drawables have a new get_space_api(), get_linear() is now get_trc().
- images now have a "layer space" and an API to get it,
gimp_image_get_layer_format() returns formats in that space.
- an image's layer space is created from the image's color profile,
change gimpimage-color-profile to deal with that correctly
- change many babl_format() calls to babl_format_with_space() and take
the space from passed formats or drawables
- add function gimp_layer_fix_format_space() which replaces the
layer's buffer with one that has the image's layer format, but
doesn't change pixel values
- use gimp_layer_fix_format_space() to make sure layers loaded from
XCF and created by plug-ins have the right space when added to the
image, because it's impossible to always assign the right space upon
layer creation
- "assign color profile" and "discard color profile" now require use
of gimp_layer_fix_format_space() too because the profile is now
embedded in all formats via the space. Add
gimp_image_assign_color_profile() which does all that and call it
instead of a simple gimp_image_set_color_profile(), also from the
PDB set-color-profile functions, which are essentially "assign" and
"discard" calls.
- generally, make sure a new image's color profile is set before
adding layers to it, gimp_image_set_color_profile() is more than
before considered know-what-you-are-doing API.
- take special precaution in all places that call
gimp_drawable_convert_type(), we now must pass a new_profile from
all callers that convert layers within the same image (such as
image_convert_type, image_convert_precision), because the layer's
new space can't be determined from the image's layer format during
the call.
- change all "linear" properties to "trc", in all config objects like
for levels and curves, in the histogram, in the widgets. This results
in some GUI that now has three choices instead of two.
TODO: we might want to reduce that back to two later.
- keep "linear" boolean properties around as compat if needed for file
pasring, but always convert the parsed parsed boolean to
GimpTRCType.
- TODO: the image's "enable color management" switch is currently
broken, will fix that in another commit.
2018-07-21 14:23:01 +02:00
|
|
|
image_precision = GIMP_PRECISION_DOUBLE_NON_LINEAR;
|
2015-11-23 22:29:06 +01:00
|
|
|
|
|
|
|
type = babl_type ("double");
|
2014-09-12 18:50:44 +04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2021-03-04 12:42:59 -05:00
|
|
|
g_message (_("Unsupported bit depth: %d for page %d."),
|
|
|
|
bps, li+1);
|
|
|
|
continue;
|
2014-09-12 18:50:44 +04:00
|
|
|
}
|
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
g_printerr ("bps: %d\n", bps);
|
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
TIFFGetFieldDefaulted (tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
|
1999-09-17 22:28:25 +00:00
|
|
|
|
2014-09-13 21:59:30 +02:00
|
|
|
if (! TIFFGetField (tif, TIFFTAG_EXTRASAMPLES, &extra, &extra_types))
|
2003-12-02 22:32:42 +00:00
|
|
|
extra = 0;
|
1998-05-18 00:54:11 +00:00
|
|
|
|
2014-09-13 21:59:30 +02:00
|
|
|
if (! TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &cols))
|
2003-12-02 22:32:42 +00:00
|
|
|
{
|
2019-06-17 17:11:11 +02:00
|
|
|
TIFFClose (tif);
|
2021-03-02 16:08:55 -05:00
|
|
|
g_message (_("Could not get image width from '%s'"),
|
2016-04-19 17:18:17 +01:00
|
|
|
gimp_file_get_utf8_name (file));
|
2019-06-17 17:11:11 +02:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2003-12-02 22:32:42 +00:00
|
|
|
}
|
1998-05-18 00:54:11 +00:00
|
|
|
|
2014-09-13 21:59:30 +02:00
|
|
|
if (! TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &rows))
|
2003-12-02 22:32:42 +00:00
|
|
|
{
|
2019-06-17 17:11:11 +02:00
|
|
|
TIFFClose (tif);
|
2021-03-02 16:08:55 -05:00
|
|
|
g_message (_("Could not get image length from '%s'"),
|
2016-04-19 17:18:17 +01:00
|
|
|
gimp_file_get_utf8_name (file));
|
2019-06-17 17:11:11 +02:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2003-12-02 22:32:42 +00:00
|
|
|
}
|
1998-05-18 00:54:11 +00:00
|
|
|
|
2021-03-02 15:23:09 -05:00
|
|
|
if (cols > GIMP_MAX_IMAGE_SIZE || cols <= 0 ||
|
|
|
|
rows > GIMP_MAX_IMAGE_SIZE || rows <= 0)
|
|
|
|
{
|
2021-03-02 16:08:55 -05:00
|
|
|
g_message (_("Invalid image dimensions (%u x %u) for page %d. "
|
|
|
|
"Image may be corrupt."),
|
2021-03-02 15:23:09 -05:00
|
|
|
(guint32) cols, (guint32) rows, li+1);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_printerr ("Image dimensions: %u x %u.\n",
|
|
|
|
(guint32) cols, (guint32) rows);
|
|
|
|
}
|
|
|
|
|
2014-09-13 21:59:30 +02:00
|
|
|
if (! TIFFGetField (tif, TIFFTAG_PHOTOMETRIC, &photomet))
|
2003-12-02 22:32:42 +00:00
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
guint16 compression;
|
2014-09-13 21:59:30 +02:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
if (TIFFGetField (tif, TIFFTAG_COMPRESSION, &compression) &&
|
|
|
|
(compression == COMPRESSION_CCITTFAX3 ||
|
|
|
|
compression == COMPRESSION_CCITTFAX4 ||
|
|
|
|
compression == COMPRESSION_CCITTRLE ||
|
|
|
|
compression == COMPRESSION_CCITTRLEW))
|
2004-01-27 19:19:54 +00:00
|
|
|
{
|
2021-03-02 16:08:55 -05:00
|
|
|
g_message (_("Could not get photometric from '%s'. "
|
|
|
|
"Image is CCITT compressed, assuming min-is-white"),
|
2016-04-19 17:18:17 +01:00
|
|
|
gimp_file_get_utf8_name (file));
|
2004-01-27 19:19:54 +00:00
|
|
|
photomet = PHOTOMETRIC_MINISWHITE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-03-02 16:08:55 -05:00
|
|
|
g_message (_("Could not get photometric from '%s'. "
|
|
|
|
"Assuming min-is-black"),
|
2016-04-19 17:18:17 +01:00
|
|
|
gimp_file_get_utf8_name (file));
|
2015-09-13 20:12:02 +02:00
|
|
|
|
|
|
|
/* old AppleScan software misses out the photometric tag
|
|
|
|
* (and incidentally assumes min-is-white, but xv
|
|
|
|
* assumes min-is-black, so we follow xv's lead. It's
|
|
|
|
* not much hardship to invert the image later).
|
|
|
|
*/
|
2004-01-27 19:19:54 +00:00
|
|
|
photomet = PHOTOMETRIC_MINISBLACK;
|
|
|
|
}
|
2003-12-02 22:32:42 +00:00
|
|
|
}
|
1997-11-24 22:05:25 +00:00
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
/* test if the extrasample represents an associated alpha channel... */
|
|
|
|
if (extra > 0 && (extra_types[0] == EXTRASAMPLE_ASSOCALPHA))
|
|
|
|
{
|
|
|
|
alpha = TRUE;
|
2020-05-18 00:13:21 +02:00
|
|
|
save_transp_pixels = FALSE;
|
2015-09-13 20:12:02 +02:00
|
|
|
extra--;
|
2004-01-16 21:28:31 +00:00
|
|
|
}
|
|
|
|
else if (extra > 0 && (extra_types[0] == EXTRASAMPLE_UNASSALPHA))
|
|
|
|
{
|
|
|
|
alpha = TRUE;
|
2020-05-18 00:13:21 +02:00
|
|
|
save_transp_pixels = TRUE;
|
2015-09-13 20:12:02 +02:00
|
|
|
extra--;
|
2004-01-16 21:28:31 +00:00
|
|
|
}
|
|
|
|
else if (extra > 0 && (extra_types[0] == EXTRASAMPLE_UNSPECIFIED))
|
|
|
|
{
|
2019-06-17 17:11:11 +02:00
|
|
|
if (run_mode != GIMP_RUN_INTERACTIVE)
|
|
|
|
/* In non-interactive mode, we assume unassociated alpha if unspecified.
|
|
|
|
* We don't output messages in interactive mode as the user
|
|
|
|
* has already the ability to choose through a dialog. */
|
2021-03-02 16:08:55 -05:00
|
|
|
g_message (_("Alpha channel type not defined for %s. "
|
|
|
|
"Assuming alpha is not premultiplied"),
|
2019-06-17 17:11:11 +02:00
|
|
|
gimp_file_get_utf8_name (file));
|
|
|
|
|
|
|
|
switch (default_extra)
|
|
|
|
{
|
|
|
|
case GIMP_TIFF_LOAD_ASSOCALPHA:
|
|
|
|
alpha = TRUE;
|
2020-05-18 00:13:21 +02:00
|
|
|
save_transp_pixels = FALSE;
|
2019-06-17 17:11:11 +02:00
|
|
|
break;
|
|
|
|
case GIMP_TIFF_LOAD_UNASSALPHA:
|
|
|
|
alpha = TRUE;
|
2020-05-18 00:13:21 +02:00
|
|
|
save_transp_pixels = TRUE;
|
2019-06-17 17:11:11 +02:00
|
|
|
break;
|
|
|
|
default: /* GIMP_TIFF_LOAD_CHANNEL */
|
|
|
|
alpha = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
2015-09-13 20:12:02 +02:00
|
|
|
extra--;
|
2003-12-02 22:32:42 +00:00
|
|
|
}
|
2019-06-11 15:33:15 +02:00
|
|
|
else /* extra == 0 */
|
2003-12-02 22:32:42 +00:00
|
|
|
{
|
2021-01-14 12:37:59 -05:00
|
|
|
if (is_non_conformant_tiff (photomet, spp))
|
2019-06-11 15:33:15 +02:00
|
|
|
{
|
2019-06-17 17:11:11 +02:00
|
|
|
if (run_mode != GIMP_RUN_INTERACTIVE)
|
2021-03-02 16:08:55 -05:00
|
|
|
g_message (_("Image '%s' does not conform to the TIFF specification: "
|
2019-06-17 17:11:11 +02:00
|
|
|
"ExtraSamples field is not set while extra channels are present. "
|
2021-03-02 16:08:55 -05:00
|
|
|
"Assuming the first extra channel is non-premultiplied alpha."),
|
2019-06-17 17:11:11 +02:00
|
|
|
gimp_file_get_utf8_name (file));
|
|
|
|
|
|
|
|
switch (default_extra)
|
|
|
|
{
|
|
|
|
case GIMP_TIFF_LOAD_ASSOCALPHA:
|
|
|
|
alpha = TRUE;
|
2020-05-18 00:13:21 +02:00
|
|
|
save_transp_pixels = FALSE;
|
2019-06-17 17:11:11 +02:00
|
|
|
break;
|
|
|
|
case GIMP_TIFF_LOAD_UNASSALPHA:
|
|
|
|
alpha = TRUE;
|
2020-05-18 00:13:21 +02:00
|
|
|
save_transp_pixels = TRUE;
|
2019-06-17 17:11:11 +02:00
|
|
|
break;
|
|
|
|
default: /* GIMP_TIFF_LOAD_CHANNEL */
|
|
|
|
alpha = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
2019-06-11 15:33:15 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
alpha = FALSE;
|
|
|
|
}
|
2003-12-02 22:32:42 +00:00
|
|
|
}
|
1997-11-24 22:05:25 +00:00
|
|
|
|
2021-01-14 12:37:59 -05:00
|
|
|
extra = get_extra_channels_count (photomet, spp, alpha);
|
1997-11-24 22:05:25 +00:00
|
|
|
|
2021-03-04 12:40:14 -05:00
|
|
|
tiff_mode = GIMP_TIFF_DEFAULT;
|
2020-06-24 15:16:50 +03:00
|
|
|
is_signed = sampleformat == SAMPLEFORMAT_INT;
|
2005-01-01 19:13:38 +00:00
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
switch (photomet)
|
|
|
|
{
|
2022-06-07 19:11:54 -04:00
|
|
|
case PHOTOMETRIC_PALETTE:
|
2003-12-02 22:32:42 +00:00
|
|
|
case PHOTOMETRIC_MINISBLACK:
|
|
|
|
case PHOTOMETRIC_MINISWHITE:
|
2022-06-08 14:34:03 -04:00
|
|
|
/* Even for bps >= we may need to use tiff_mode, so always set it.
|
|
|
|
* Currently we use it to detect the need to convert 8 bps miniswhite. */
|
|
|
|
if (photomet == PHOTOMETRIC_PALETTE)
|
|
|
|
tiff_mode = GIMP_TIFF_INDEXED;
|
|
|
|
else if (photomet == PHOTOMETRIC_MINISBLACK)
|
|
|
|
tiff_mode = GIMP_TIFF_GRAY;
|
|
|
|
else if (photomet == PHOTOMETRIC_MINISWHITE)
|
|
|
|
tiff_mode = GIMP_TIFF_GRAY_MINISWHITE;
|
|
|
|
|
2022-06-07 19:11:54 -04:00
|
|
|
if (bps < 8)
|
|
|
|
{
|
|
|
|
/* FIXME: It should be a user choice whether this should be
|
|
|
|
* interpreted as indexed or grayscale. For now we will
|
|
|
|
* use indexed (see issue #6766). */
|
|
|
|
image_type = GIMP_INDEXED;
|
|
|
|
layer_type = alpha ? GIMP_INDEXEDA_IMAGE : GIMP_INDEXED_IMAGE;
|
|
|
|
|
|
|
|
if ((bps == 1 || bps == 2 || bps == 4) && ! alpha && spp == 1)
|
|
|
|
{
|
|
|
|
if (bps == 1)
|
|
|
|
fill_bit2byte (tiff_mode);
|
|
|
|
else if (bps == 2)
|
|
|
|
fill_2bit2byte (tiff_mode);
|
|
|
|
else if (bps == 4)
|
|
|
|
fill_4bit2byte (tiff_mode);
|
|
|
|
}
|
|
|
|
}
|
2021-03-04 12:40:14 -05:00
|
|
|
else
|
2005-01-01 19:13:38 +00:00
|
|
|
{
|
2022-06-07 19:11:54 -04:00
|
|
|
if (photomet == PHOTOMETRIC_PALETTE)
|
|
|
|
{
|
|
|
|
image_type = GIMP_INDEXED;
|
|
|
|
layer_type = alpha ? GIMP_INDEXEDA_IMAGE : GIMP_INDEXED_IMAGE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
image_type = GIMP_GRAY;
|
|
|
|
layer_type = alpha ? GIMP_GRAYA_IMAGE : GIMP_GRAY_IMAGE;
|
|
|
|
}
|
2005-01-01 19:13:38 +00:00
|
|
|
}
|
2013-05-25 09:44:56 -04:00
|
|
|
|
2022-06-07 19:11:54 -04:00
|
|
|
if (photomet == PHOTOMETRIC_PALETTE)
|
|
|
|
{
|
|
|
|
/* Do nothing here, handled later.
|
|
|
|
* Didn't want more indenting in the next part. */
|
|
|
|
}
|
|
|
|
else if (alpha)
|
2021-03-04 12:40:14 -05:00
|
|
|
{
|
|
|
|
if (save_transp_pixels)
|
2013-05-25 09:44:56 -04:00
|
|
|
{
|
2021-03-04 12:40:14 -05:00
|
|
|
if (profile_linear)
|
2013-05-25 09:44:56 -04:00
|
|
|
{
|
2021-03-04 12:40:14 -05:00
|
|
|
base_format = babl_format_new (babl_model ("YA"),
|
2021-03-04 15:23:29 -05:00
|
|
|
type,
|
|
|
|
babl_component ("Y"),
|
|
|
|
babl_component ("A"),
|
|
|
|
NULL);
|
2015-11-23 22:29:06 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-03-04 12:40:14 -05:00
|
|
|
base_format = babl_format_new (babl_model ("Y'A"),
|
2021-03-04 15:23:29 -05:00
|
|
|
type,
|
|
|
|
babl_component ("Y'"),
|
|
|
|
babl_component ("A"),
|
|
|
|
NULL);
|
2015-11-23 22:29:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (profile_linear)
|
|
|
|
{
|
2021-03-04 12:40:14 -05:00
|
|
|
base_format = babl_format_new (babl_model ("YaA"),
|
2021-03-04 15:23:29 -05:00
|
|
|
type,
|
|
|
|
babl_component ("Ya"),
|
|
|
|
babl_component ("A"),
|
|
|
|
NULL);
|
2013-05-25 09:44:56 -04:00
|
|
|
}
|
2014-09-12 18:50:44 +04:00
|
|
|
else
|
2013-05-25 09:44:56 -04:00
|
|
|
{
|
2021-03-04 12:40:14 -05:00
|
|
|
base_format = babl_format_new (babl_model ("Y'aA"),
|
2021-03-04 15:23:29 -05:00
|
|
|
type,
|
|
|
|
babl_component ("Y'a"),
|
|
|
|
babl_component ("A"),
|
|
|
|
NULL);
|
2013-05-25 09:44:56 -04:00
|
|
|
}
|
|
|
|
}
|
2005-01-01 19:13:38 +00:00
|
|
|
}
|
2021-03-04 12:40:14 -05:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (profile_linear)
|
|
|
|
{
|
|
|
|
base_format = babl_format_new (babl_model ("Y"),
|
2021-03-04 15:23:29 -05:00
|
|
|
type,
|
|
|
|
babl_component ("Y"),
|
|
|
|
NULL);
|
2021-03-04 12:40:14 -05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
base_format = babl_format_new (babl_model ("Y'"),
|
2021-03-04 15:23:29 -05:00
|
|
|
type,
|
|
|
|
babl_component ("Y'"),
|
|
|
|
NULL);
|
2021-03-04 12:40:14 -05:00
|
|
|
}
|
|
|
|
}
|
2003-12-02 22:32:42 +00:00
|
|
|
break;
|
1997-11-24 22:05:25 +00:00
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
case PHOTOMETRIC_RGB:
|
|
|
|
image_type = GIMP_RGB;
|
2015-09-13 20:12:02 +02:00
|
|
|
layer_type = alpha ? GIMP_RGBA_IMAGE : GIMP_RGB_IMAGE;
|
2013-05-25 09:44:56 -04:00
|
|
|
|
|
|
|
if (alpha)
|
|
|
|
{
|
2020-05-18 00:13:21 +02:00
|
|
|
if (save_transp_pixels)
|
2013-05-25 09:44:56 -04:00
|
|
|
{
|
2015-11-23 22:29:06 +01:00
|
|
|
if (profile_linear)
|
|
|
|
{
|
|
|
|
base_format = babl_format_new (babl_model ("RGBA"),
|
|
|
|
type,
|
|
|
|
babl_component ("R"),
|
|
|
|
babl_component ("G"),
|
|
|
|
babl_component ("B"),
|
|
|
|
babl_component ("A"),
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
base_format = babl_format_new (babl_model ("R'G'B'A"),
|
|
|
|
type,
|
|
|
|
babl_component ("R'"),
|
|
|
|
babl_component ("G'"),
|
|
|
|
babl_component ("B'"),
|
|
|
|
babl_component ("A"),
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (profile_linear)
|
|
|
|
{
|
|
|
|
base_format = babl_format_new (babl_model ("RaGaBaA"),
|
|
|
|
type,
|
|
|
|
babl_component ("Ra"),
|
|
|
|
babl_component ("Ga"),
|
|
|
|
babl_component ("Ba"),
|
|
|
|
babl_component ("A"),
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
base_format = babl_format_new (babl_model ("R'aG'aB'aA"),
|
|
|
|
type,
|
|
|
|
babl_component ("R'a"),
|
|
|
|
babl_component ("G'a"),
|
|
|
|
babl_component ("B'a"),
|
|
|
|
babl_component ("A"),
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (profile_linear)
|
|
|
|
{
|
|
|
|
base_format = babl_format_new (babl_model ("RGB"),
|
2014-09-12 18:50:44 +04:00
|
|
|
type,
|
2015-11-23 22:29:06 +01:00
|
|
|
babl_component ("R"),
|
|
|
|
babl_component ("G"),
|
|
|
|
babl_component ("B"),
|
2014-09-12 18:50:44 +04:00
|
|
|
NULL);
|
2013-05-25 09:44:56 -04:00
|
|
|
}
|
2014-09-12 18:50:44 +04:00
|
|
|
else
|
2013-05-25 09:44:56 -04:00
|
|
|
{
|
2015-11-23 22:29:06 +01:00
|
|
|
base_format = babl_format_new (babl_model ("R'G'B'"),
|
2014-09-12 18:50:44 +04:00
|
|
|
type,
|
2015-11-23 22:29:06 +01:00
|
|
|
babl_component ("R'"),
|
|
|
|
babl_component ("G'"),
|
|
|
|
babl_component ("B'"),
|
2014-09-12 18:50:44 +04:00
|
|
|
NULL);
|
2013-05-25 09:44:56 -04:00
|
|
|
}
|
|
|
|
}
|
2003-12-02 22:32:42 +00:00
|
|
|
break;
|
1997-11-24 22:05:25 +00:00
|
|
|
|
2022-04-18 11:00:10 +00:00
|
|
|
case PHOTOMETRIC_SEPARATED:
|
|
|
|
layer_type = alpha ? GIMP_RGBA_IMAGE : GIMP_RGB_IMAGE;
|
|
|
|
/* It's possible that a CMYK image might not have an
|
|
|
|
* attached profile, so we'll check for it and set up
|
|
|
|
* space accordingly
|
|
|
|
*/
|
2022-12-19 16:29:41 +00:00
|
|
|
is_cmyk = TRUE;
|
2022-04-18 11:00:10 +00:00
|
|
|
if (profile && gimp_color_profile_is_cmyk (profile))
|
|
|
|
{
|
|
|
|
space = gimp_color_profile_get_space (profile,
|
|
|
|
GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
|
|
|
|
error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
space = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (alpha)
|
|
|
|
base_format = babl_format_new (babl_model ("CMYKA"),
|
|
|
|
type,
|
|
|
|
babl_component ("Cyan"),
|
|
|
|
babl_component ("Magenta"),
|
|
|
|
babl_component ("Yellow"),
|
|
|
|
babl_component ("Key"),
|
|
|
|
babl_component ("A"),
|
|
|
|
NULL);
|
|
|
|
else
|
|
|
|
base_format = babl_format_new (babl_model ("CMYK"),
|
|
|
|
type,
|
|
|
|
babl_component ("Cyan"),
|
|
|
|
babl_component ("Magenta"),
|
|
|
|
babl_component ("Yellow"),
|
|
|
|
babl_component ("Key"),
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
base_format =
|
|
|
|
babl_format_with_space (babl_format_get_encoding (base_format),
|
|
|
|
space);
|
|
|
|
break;
|
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
default:
|
2012-06-07 00:06:06 +02:00
|
|
|
g_printerr ("photomet: %d (%d)\n", photomet, PHOTOMETRIC_PALETTE);
|
2003-12-02 22:32:42 +00:00
|
|
|
worst_case = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
1999-09-17 22:28:25 +00:00
|
|
|
|
2012-12-04 13:37:57 +05:30
|
|
|
/* attach a parasite containing the compression */
|
2015-09-13 20:12:02 +02:00
|
|
|
{
|
|
|
|
guint16 compression = COMPRESSION_NONE;
|
2012-12-04 13:37:57 +05:30
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
if (TIFFGetField (tif, TIFFTAG_COMPRESSION, &compression))
|
|
|
|
{
|
|
|
|
switch (compression)
|
|
|
|
{
|
|
|
|
case COMPRESSION_NONE:
|
|
|
|
case COMPRESSION_LZW:
|
|
|
|
case COMPRESSION_PACKBITS:
|
|
|
|
case COMPRESSION_DEFLATE:
|
|
|
|
case COMPRESSION_ADOBE_DEFLATE:
|
|
|
|
case COMPRESSION_JPEG:
|
|
|
|
case COMPRESSION_CCITTFAX3:
|
|
|
|
case COMPRESSION_CCITTFAX4:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case COMPRESSION_OJPEG:
|
|
|
|
worst_case = TRUE;
|
|
|
|
compression = COMPRESSION_JPEG;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2021-03-02 16:08:55 -05:00
|
|
|
g_message (_("Invalid or unknown compression %u. "
|
|
|
|
"Setting compression to none."),
|
|
|
|
compression);
|
2015-09-13 20:12:02 +02:00
|
|
|
compression = COMPRESSION_NONE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2012-12-04 13:37:57 +05:30
|
|
|
|
2020-05-18 00:13:21 +02:00
|
|
|
gimp_compression = tiff_compression_to_gimp_compression (compression);
|
2015-09-13 20:12:02 +02:00
|
|
|
}
|
2012-12-04 13:37:57 +05:30
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
if (worst_case)
|
|
|
|
{
|
2014-09-12 18:50:44 +04:00
|
|
|
image_type = GIMP_RGB;
|
|
|
|
layer_type = GIMP_RGBA_IMAGE;
|
2015-11-23 22:29:06 +01:00
|
|
|
|
|
|
|
if (profile_linear)
|
|
|
|
{
|
|
|
|
base_format = babl_format_new (babl_model ("RaGaBaA"),
|
|
|
|
type,
|
|
|
|
babl_component ("Ra"),
|
|
|
|
babl_component ("Ga"),
|
|
|
|
babl_component ("Ba"),
|
|
|
|
babl_component ("A"),
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
base_format = babl_format_new (babl_model ("R'aG'aB'aA"),
|
|
|
|
type,
|
|
|
|
babl_component ("R'a"),
|
|
|
|
babl_component ("G'a"),
|
|
|
|
babl_component ("B'a"),
|
|
|
|
babl_component ("A"),
|
|
|
|
NULL);
|
|
|
|
}
|
2003-12-02 22:32:42 +00:00
|
|
|
}
|
2003-07-15 12:35:39 +00:00
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
if (pages.target == GIMP_PAGE_SELECTOR_TARGET_LAYERS)
|
2007-06-13 09:57:43 +00:00
|
|
|
{
|
|
|
|
if (li == 0)
|
2015-09-13 20:12:02 +02:00
|
|
|
{
|
|
|
|
first_image_type = image_type;
|
|
|
|
}
|
2007-06-13 11:43:08 +00:00
|
|
|
else if (image_type != first_image_type)
|
2015-09-13 20:12:02 +02:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
2007-06-13 09:57:43 +00:00
|
|
|
}
|
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
if ((pages.target == GIMP_PAGE_SELECTOR_TARGET_IMAGES) || (! *image))
|
2003-12-02 22:32:42 +00:00
|
|
|
{
|
2019-06-17 17:11:11 +02:00
|
|
|
*image = gimp_image_new_with_precision (cols, rows, image_type,
|
|
|
|
image_precision);
|
2013-06-23 16:51:24 +02:00
|
|
|
|
2019-08-17 10:52:05 +02:00
|
|
|
if (! *image)
|
2003-12-02 22:32:42 +00:00
|
|
|
{
|
2019-06-17 17:11:11 +02:00
|
|
|
TIFFClose (tif);
|
2021-03-02 16:08:55 -05:00
|
|
|
g_message (_("Could not create a new image: %s"),
|
2019-08-16 22:55:16 +02:00
|
|
|
gimp_pdb_get_last_error (gimp_get_pdb ()));
|
2019-06-17 17:11:11 +02:00
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
2003-12-02 22:32:42 +00:00
|
|
|
}
|
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
gimp_image_undo_disable (*image);
|
2007-04-24 18:36:35 +00:00
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
if (pages.target == GIMP_PAGE_SELECTOR_TARGET_IMAGES)
|
2023-02-13 22:33:35 +01:00
|
|
|
images_list = g_list_prepend (images_list, *image);
|
2003-12-02 22:32:42 +00:00
|
|
|
}
|
1997-11-24 22:05:25 +00:00
|
|
|
|
2022-07-14 03:29:12 +00:00
|
|
|
/* attach CMYK profile to GimpImage if applicable */
|
|
|
|
if (profile && gimp_color_profile_is_cmyk (profile))
|
|
|
|
{
|
|
|
|
gimp_image_set_simulation_profile (*image, profile);
|
|
|
|
g_clear_object (&profile);
|
|
|
|
}
|
|
|
|
|
2022-04-18 11:00:10 +00:00
|
|
|
/* attach non-CMYK color profile */
|
2015-11-23 22:29:06 +01:00
|
|
|
if (profile)
|
|
|
|
{
|
2020-12-16 17:56:18 -05:00
|
|
|
if (pages.target == GIMP_PAGE_SELECTOR_TARGET_IMAGES || profile == first_profile)
|
|
|
|
gimp_image_set_color_profile (*image, profile);
|
|
|
|
|
2015-11-23 22:29:06 +01:00
|
|
|
g_object_unref (profile);
|
|
|
|
}
|
1998-10-11 22:50:03 +00:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
/* attach parasites */
|
2003-07-15 12:35:39 +00:00
|
|
|
{
|
2020-05-18 00:13:21 +02:00
|
|
|
GString *string;
|
|
|
|
GimpConfigWriter *writer;
|
|
|
|
GimpParasite *parasite;
|
|
|
|
const gchar *img_desc;
|
|
|
|
|
|
|
|
/* construct the save parasite manually instead of simply
|
|
|
|
* creating and saving a save config object, because we want
|
|
|
|
* it to contain only some properties
|
|
|
|
*/
|
|
|
|
|
|
|
|
string = g_string_new (NULL);
|
|
|
|
writer = gimp_config_writer_new_from_string (string);
|
|
|
|
|
|
|
|
gimp_config_writer_open (writer, "compression");
|
|
|
|
gimp_config_writer_printf (writer, "%d", gimp_compression);
|
|
|
|
gimp_config_writer_close (writer);
|
2015-09-13 20:12:02 +02:00
|
|
|
|
2020-05-18 00:13:21 +02:00
|
|
|
gimp_config_writer_finish (writer, NULL, NULL);
|
|
|
|
|
|
|
|
parasite = gimp_parasite_new ("GimpProcedureConfig-file-tiff-save-last",
|
|
|
|
GIMP_PARASITE_PERSISTENT,
|
|
|
|
string->len + 1, string->str);
|
2019-06-17 17:11:11 +02:00
|
|
|
gimp_image_attach_parasite (*image, parasite);
|
2015-09-13 20:12:02 +02:00
|
|
|
gimp_parasite_free (parasite);
|
|
|
|
|
2020-05-18 00:13:21 +02:00
|
|
|
g_string_free (string, TRUE);
|
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
/* Attach a parasite containing the image description.
|
|
|
|
* Pretend to be a gimp comment so other plugins will use this
|
|
|
|
* description as an image comment where appropriate.
|
|
|
|
*/
|
2003-12-02 22:32:42 +00:00
|
|
|
if (TIFFGetField (tif, TIFFTAG_IMAGEDESCRIPTION, &img_desc) &&
|
|
|
|
g_utf8_validate (img_desc, -1, NULL))
|
|
|
|
{
|
|
|
|
parasite = gimp_parasite_new ("gimp-comment",
|
|
|
|
GIMP_PARASITE_PERSISTENT,
|
|
|
|
strlen (img_desc) + 1, img_desc);
|
2019-06-17 17:11:11 +02:00
|
|
|
gimp_image_attach_parasite (*image, parasite);
|
2020-10-29 08:01:26 +05:30
|
|
|
gimp_parasite_free (parasite);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Attach GeoTIFF Tags as Parasite, If available */
|
|
|
|
{
|
|
|
|
GimpParasite *parasite = NULL;
|
|
|
|
void *geotag_data = NULL;
|
2021-10-16 16:37:33 +03:00
|
|
|
uint32_t count = 0;
|
2020-10-29 08:01:26 +05:30
|
|
|
|
|
|
|
if (TIFFGetField (tif, GEOTIFF_MODELPIXELSCALE, &count, &geotag_data))
|
|
|
|
{
|
|
|
|
parasite = gimp_parasite_new ("Gimp_GeoTIFF_ModelPixelScale",
|
|
|
|
GIMP_PARASITE_PERSISTENT,
|
|
|
|
(TIFFDataWidth (TIFF_DOUBLE) * count),
|
|
|
|
geotag_data);
|
|
|
|
gimp_image_attach_parasite (*image, parasite);
|
|
|
|
gimp_parasite_free (parasite);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TIFFGetField (tif, GEOTIFF_MODELTIEPOINT, &count, &geotag_data))
|
|
|
|
{
|
|
|
|
parasite = gimp_parasite_new ("Gimp_GeoTIFF_ModelTiePoint",
|
|
|
|
GIMP_PARASITE_PERSISTENT,
|
|
|
|
(TIFFDataWidth (TIFF_DOUBLE) * count),
|
|
|
|
geotag_data);
|
|
|
|
gimp_image_attach_parasite (*image, parasite);
|
|
|
|
gimp_parasite_free (parasite);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TIFFGetField (tif, GEOTIFF_MODELTRANSFORMATION, &count, &geotag_data))
|
|
|
|
{
|
|
|
|
parasite = gimp_parasite_new ("Gimp_GeoTIFF_ModelTransformation",
|
|
|
|
GIMP_PARASITE_PERSISTENT,
|
|
|
|
(TIFFDataWidth (TIFF_DOUBLE) * count),
|
|
|
|
geotag_data);
|
|
|
|
gimp_image_attach_parasite (*image, parasite);
|
|
|
|
gimp_parasite_free (parasite);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TIFFGetField (tif, GEOTIFF_KEYDIRECTORY, &count, &geotag_data) )
|
|
|
|
{
|
|
|
|
parasite = gimp_parasite_new ("Gimp_GeoTIFF_KeyDirectory",
|
|
|
|
GIMP_PARASITE_PERSISTENT,
|
|
|
|
(TIFFDataWidth (TIFF_SHORT) * count),
|
|
|
|
geotag_data);
|
|
|
|
gimp_image_attach_parasite (*image, parasite);
|
|
|
|
gimp_parasite_free (parasite);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TIFFGetField (tif, GEOTIFF_DOUBLEPARAMS, &count, &geotag_data))
|
|
|
|
{
|
|
|
|
parasite = gimp_parasite_new ("Gimp_GeoTIFF_DoubleParams",
|
|
|
|
GIMP_PARASITE_PERSISTENT,
|
|
|
|
(TIFFDataWidth (TIFF_DOUBLE) * count),
|
|
|
|
geotag_data);
|
|
|
|
gimp_image_attach_parasite (*image, parasite);
|
|
|
|
gimp_parasite_free (parasite);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TIFFGetField (tif, GEOTIFF_ASCIIPARAMS, &count, &geotag_data))
|
|
|
|
{
|
|
|
|
parasite = gimp_parasite_new ("Gimp_GeoTIFF_Asciiparams",
|
|
|
|
GIMP_PARASITE_PERSISTENT,
|
|
|
|
(TIFFDataWidth (TIFF_ASCII) * count),
|
|
|
|
geotag_data);
|
|
|
|
gimp_image_attach_parasite (*image, parasite);
|
2003-12-02 22:32:42 +00:00
|
|
|
gimp_parasite_free (parasite);
|
|
|
|
}
|
|
|
|
}
|
1998-10-05 10:05:29 +00:00
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
/* any resolution info in the file? */
|
2003-07-15 12:35:39 +00:00
|
|
|
{
|
2024-11-26 02:56:54 +00:00
|
|
|
gfloat xres = 72.0;
|
|
|
|
gfloat yres = 72.0;
|
2024-08-20 12:50:49 +00:00
|
|
|
gushort read_unit = RESUNIT_NONE;
|
|
|
|
GimpUnit *unit = gimp_unit_pixel (); /* invalid unit */
|
2003-07-15 12:35:39 +00:00
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
if (TIFFGetField (tif, TIFFTAG_XRESOLUTION, &xres))
|
|
|
|
{
|
|
|
|
if (TIFFGetField (tif, TIFFTAG_YRESOLUTION, &yres))
|
2003-07-15 12:35:39 +00:00
|
|
|
{
|
2003-12-02 22:32:42 +00:00
|
|
|
if (TIFFGetFieldDefaulted (tif, TIFFTAG_RESOLUTIONUNIT,
|
|
|
|
&read_unit))
|
2003-07-15 12:35:39 +00:00
|
|
|
{
|
2003-12-02 22:32:42 +00:00
|
|
|
switch (read_unit)
|
|
|
|
{
|
|
|
|
case RESUNIT_NONE:
|
|
|
|
/* ImageMagick writes files with this silly resunit */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RESUNIT_INCH:
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-25 20:55:21 +02:00
|
|
|
unit = gimp_unit_inch ();
|
2003-12-02 22:32:42 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RESUNIT_CENTIMETER:
|
|
|
|
xres *= 2.54;
|
|
|
|
yres *= 2.54;
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-25 20:55:21 +02:00
|
|
|
unit = gimp_unit_mm (); /* this is our default metric unit */
|
2003-12-02 22:32:42 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2021-03-02 16:08:55 -05:00
|
|
|
g_message (_("Unknown resolution "
|
|
|
|
"unit type %d, assuming dpi"), read_unit);
|
2003-12-02 22:32:42 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2015-09-13 20:12:02 +02:00
|
|
|
{
|
|
|
|
/* no res unit tag */
|
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
/* old AppleScan software produces these */
|
2021-03-02 16:08:55 -05:00
|
|
|
g_message (_("Warning: resolution specified without "
|
|
|
|
"unit type, assuming dpi"));
|
2003-07-15 12:35:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2015-09-13 20:12:02 +02:00
|
|
|
{
|
|
|
|
/* xres but no yres */
|
|
|
|
|
2021-03-02 16:08:55 -05:00
|
|
|
g_message (_("Warning: no y resolution info, assuming same as x"));
|
2003-12-02 22:32:42 +00:00
|
|
|
yres = xres;
|
2003-07-15 12:35:39 +00:00
|
|
|
}
|
1998-10-05 10:05:29 +00:00
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
/* now set the new image's resolution info */
|
2000-01-08 10:55:05 +00:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
/* If it is invalid, instead of forcing 72dpi, do not set
|
|
|
|
* the resolution at all. Gimp will then use the default
|
|
|
|
* set by the user
|
|
|
|
*/
|
2024-11-26 02:56:54 +00:00
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
if (read_unit != RESUNIT_NONE)
|
|
|
|
{
|
2022-08-22 22:21:33 -04:00
|
|
|
if (! isfinite (xres) ||
|
|
|
|
xres < GIMP_MIN_RESOLUTION || xres > GIMP_MAX_RESOLUTION ||
|
|
|
|
! isfinite (yres) ||
|
|
|
|
yres < GIMP_MIN_RESOLUTION || yres > GIMP_MAX_RESOLUTION)
|
|
|
|
{
|
2024-11-26 02:56:54 +00:00
|
|
|
gdouble default_xres = 0.0;
|
|
|
|
gdouble default_yres = 0.0;
|
|
|
|
|
2022-08-22 22:21:33 -04:00
|
|
|
g_message (_("Invalid image resolution info, using default"));
|
|
|
|
/* We need valid xres and yres for computing
|
|
|
|
* layer_offset_x_pixel and layer_offset_y_pixel.
|
|
|
|
*/
|
2024-11-26 02:56:54 +00:00
|
|
|
gimp_image_get_resolution (*image,
|
|
|
|
&default_xres, &default_yres);
|
|
|
|
xres = (gfloat) default_xres;
|
|
|
|
yres = (gfloat) default_yres;
|
2022-08-22 22:21:33 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_image_set_resolution (*image, xres, yres);
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-25 20:55:21 +02:00
|
|
|
if (unit != gimp_unit_pixel ())
|
2022-08-22 22:21:33 -04:00
|
|
|
gimp_image_set_unit (*image, unit);
|
2013-10-27 18:40:09 +01:00
|
|
|
|
2022-08-22 22:21:33 -04:00
|
|
|
*resolution_loaded = TRUE;
|
|
|
|
}
|
2003-12-02 22:32:42 +00:00
|
|
|
}
|
2003-07-15 12:35:39 +00:00
|
|
|
}
|
2003-12-02 22:32:42 +00:00
|
|
|
|
|
|
|
/* no x res tag => we assume we have no resolution info, so we
|
2015-09-13 20:12:02 +02:00
|
|
|
* don't care. Older versions of this plugin used to write
|
|
|
|
* files with no resolution tags at all.
|
|
|
|
*/
|
2003-12-02 22:32:42 +00:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
/* TODO: haven't caught the case where yres tag is present,
|
|
|
|
* but not xres. This is left as an exercise for the reader -
|
|
|
|
* they should feel free to shoot the author of the broken
|
|
|
|
* program that produced the damaged TIFF file in the first
|
|
|
|
* place.
|
|
|
|
*/
|
2004-01-09 19:48:07 +00:00
|
|
|
|
|
|
|
/* handle layer offset */
|
2008-03-13 13:03:32 +00:00
|
|
|
if (! TIFFGetField (tif, TIFFTAG_XPOSITION, &layer_offset_x))
|
2004-01-09 19:48:07 +00:00
|
|
|
layer_offset_x = 0.0;
|
2008-03-13 13:03:32 +00:00
|
|
|
|
|
|
|
if (! TIFFGetField (tif, TIFFTAG_YPOSITION, &layer_offset_y))
|
2004-01-09 19:48:07 +00:00
|
|
|
layer_offset_y = 0.0;
|
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
/* round floating point position to integer position required
|
|
|
|
* by GIMP
|
|
|
|
*/
|
2014-09-13 21:59:30 +02:00
|
|
|
layer_offset_x_pixel = ROUND (layer_offset_x * xres);
|
|
|
|
layer_offset_y_pixel = ROUND (layer_offset_y * yres);
|
2003-07-15 12:35:39 +00:00
|
|
|
}
|
1998-10-05 10:05:29 +00:00
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
/* Install colormap for INDEXED images only */
|
|
|
|
if (image_type == GIMP_INDEXED)
|
|
|
|
{
|
2021-03-04 12:40:14 -05:00
|
|
|
guchar cmap[768];
|
|
|
|
|
2022-06-07 19:11:54 -04:00
|
|
|
if (photomet == PHOTOMETRIC_PALETTE)
|
2003-12-02 22:32:42 +00:00
|
|
|
{
|
2022-06-07 19:11:54 -04:00
|
|
|
gushort *redmap;
|
|
|
|
gushort *greenmap;
|
|
|
|
gushort *bluemap;
|
|
|
|
gint i, j;
|
|
|
|
|
|
|
|
if (! TIFFGetField (tif, TIFFTAG_COLORMAP,
|
|
|
|
&redmap, &greenmap, &bluemap))
|
|
|
|
{
|
|
|
|
TIFFClose (tif);
|
|
|
|
g_message (_("Could not get colormaps from '%s'"),
|
|
|
|
gimp_file_get_utf8_name (file));
|
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0, j = 0; i < (1 << bps); i++)
|
|
|
|
{
|
|
|
|
cmap[j++] = redmap[i] >> 8;
|
|
|
|
cmap[j++] = greenmap[i] >> 8;
|
|
|
|
cmap[j++] = bluemap[i] >> 8;
|
|
|
|
}
|
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
}
|
2022-06-07 19:11:54 -04:00
|
|
|
else if (photomet == PHOTOMETRIC_MINISBLACK)
|
|
|
|
{
|
|
|
|
gint i, j;
|
2005-01-01 19:13:38 +00:00
|
|
|
|
2022-06-07 19:11:54 -04:00
|
|
|
if (bps == 1)
|
|
|
|
{
|
|
|
|
for (i = 0, j = 0; i < (1 << bps); i++)
|
|
|
|
{
|
|
|
|
cmap[j++] = _1_to_8_bitmap[i];
|
|
|
|
cmap[j++] = _1_to_8_bitmap[i];
|
|
|
|
cmap[j++] = _1_to_8_bitmap[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (bps == 2)
|
|
|
|
{
|
|
|
|
for (i = 0, j = 0; i < (1 << bps); i++)
|
|
|
|
{
|
|
|
|
cmap[j++] = _2_to_8_bitmap[i];
|
|
|
|
cmap[j++] = _2_to_8_bitmap[i];
|
|
|
|
cmap[j++] = _2_to_8_bitmap[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (bps == 4)
|
|
|
|
{
|
|
|
|
for (i = 0, j = 0; i < (1 << bps); i++)
|
|
|
|
{
|
|
|
|
cmap[j++] = _4_to_8_bitmap[i];
|
|
|
|
cmap[j++] = _4_to_8_bitmap[i];
|
|
|
|
cmap[j++] = _4_to_8_bitmap[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (photomet == PHOTOMETRIC_MINISWHITE)
|
2021-03-04 12:40:14 -05:00
|
|
|
{
|
2022-06-07 19:11:54 -04:00
|
|
|
gint i, j;
|
|
|
|
|
|
|
|
if (bps == 1)
|
|
|
|
{
|
|
|
|
for (i = 0, j = 0; i < (1 << bps); i++)
|
|
|
|
{
|
|
|
|
cmap[j++] = _1_to_8_bitmap_rev[i];
|
|
|
|
cmap[j++] = _1_to_8_bitmap_rev[i];
|
|
|
|
cmap[j++] = _1_to_8_bitmap_rev[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (bps == 2)
|
|
|
|
{
|
|
|
|
for (i = 0, j = 0; i < (1 << bps); i++)
|
|
|
|
{
|
|
|
|
cmap[j++] = _2_to_8_bitmap_rev[i];
|
|
|
|
cmap[j++] = _2_to_8_bitmap_rev[i];
|
|
|
|
cmap[j++] = _2_to_8_bitmap_rev[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (bps == 4)
|
|
|
|
{
|
|
|
|
for (i = 0, j = 0; i < (1 << bps); i++)
|
|
|
|
{
|
|
|
|
cmap[j++] = _4_to_8_bitmap_rev[i];
|
|
|
|
cmap[j++] = _4_to_8_bitmap_rev[i];
|
|
|
|
cmap[j++] = _4_to_8_bitmap_rev[i];
|
|
|
|
}
|
|
|
|
}
|
2003-12-02 22:32:42 +00:00
|
|
|
}
|
2005-01-01 19:13:38 +00:00
|
|
|
|
2024-09-23 15:17:04 +02:00
|
|
|
gimp_palette_set_colormap (gimp_image_get_palette (*image),
|
|
|
|
babl_format ("R'G'B' u8"),
|
|
|
|
cmap, (1 << bps) * 3);
|
2003-12-02 22:32:42 +00:00
|
|
|
}
|
1998-10-05 10:05:29 +00:00
|
|
|
|
2022-08-22 19:05:22 -04:00
|
|
|
if (extra > 99)
|
|
|
|
{
|
|
|
|
/* Validate number of channels to the same maximum as we use for
|
|
|
|
* Photoshop. A higher number most likely means a corrupt image
|
|
|
|
* and can cause GIMP to become unresponsive and/or stuck.
|
|
|
|
* See m2-d0f86ab189cbe900ec389ca6d7464713.tif from imagetestsuite
|
|
|
|
*/
|
|
|
|
g_message (_("Suspicious number of extra channels: %d. Possibly corrupt image."), extra);
|
|
|
|
extra = 99;
|
|
|
|
}
|
|
|
|
|
2024-08-06 22:56:57 +00:00
|
|
|
/* Stop here if we have Alias/AutoDesk Sketchbook layers, as this
|
|
|
|
* would just be the composite image */
|
|
|
|
if (sketchbook_layers)
|
|
|
|
break;
|
|
|
|
|
2014-09-13 21:59:30 +02:00
|
|
|
/* Allocate ChannelData for all channels, even the background layer */
|
|
|
|
channel = g_new0 (ChannelData, extra + 1);
|
1997-11-24 22:05:25 +00:00
|
|
|
|
2004-02-08 00:40:46 +00:00
|
|
|
/* try and use layer name from tiff file */
|
2007-05-17 19:51:25 +00:00
|
|
|
name = tiff_get_page_name (tif);
|
2005-01-01 19:13:38 +00:00
|
|
|
|
2005-07-17 20:35:32 +00:00
|
|
|
if (name)
|
2004-02-08 00:40:46 +00:00
|
|
|
{
|
2019-06-17 17:11:11 +02:00
|
|
|
layer = gimp_layer_new (*image, name,
|
2005-01-01 19:13:38 +00:00
|
|
|
cols, rows,
|
2017-01-08 23:00:19 +01:00
|
|
|
layer_type,
|
2017-08-21 20:04:25 +02:00
|
|
|
100,
|
2019-06-17 17:11:11 +02:00
|
|
|
gimp_image_get_default_new_layer_mode (*image));
|
2004-02-08 00:40:46 +00:00
|
|
|
}
|
2003-12-02 22:32:42 +00:00
|
|
|
else
|
2004-02-08 00:40:46 +00:00
|
|
|
{
|
2007-05-17 19:51:25 +00:00
|
|
|
gchar *name;
|
|
|
|
|
2004-02-08 00:40:46 +00:00
|
|
|
if (ilayer == 0)
|
|
|
|
name = g_strdup (_("Background"));
|
|
|
|
else
|
|
|
|
name = g_strdup_printf (_("Page %d"), ilayer);
|
1997-11-24 22:05:25 +00:00
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
layer = gimp_layer_new (*image, name,
|
2005-01-01 19:13:38 +00:00
|
|
|
cols, rows,
|
2017-01-08 23:00:19 +01:00
|
|
|
layer_type,
|
2017-08-21 20:04:25 +02:00
|
|
|
100,
|
2019-06-17 17:11:11 +02:00
|
|
|
gimp_image_get_default_new_layer_mode (*image));
|
2004-02-08 00:40:46 +00:00
|
|
|
g_free (name);
|
|
|
|
}
|
1998-11-09 02:05:24 +00:00
|
|
|
|
2015-09-13 00:12:42 +02:00
|
|
|
if (! base_format && image_type == GIMP_INDEXED)
|
|
|
|
{
|
|
|
|
/* can't create the palette format here, need to get it from
|
|
|
|
* an existing layer
|
|
|
|
*/
|
2019-08-17 10:52:05 +02:00
|
|
|
base_format = gimp_drawable_get_format (GIMP_DRAWABLE (layer));
|
2015-09-13 00:12:42 +02:00
|
|
|
}
|
2022-04-18 11:00:10 +00:00
|
|
|
else if (! space)
|
2019-06-11 21:51:16 +02:00
|
|
|
{
|
|
|
|
base_format =
|
|
|
|
babl_format_with_space (babl_format_get_encoding (base_format),
|
2019-08-17 10:52:05 +02:00
|
|
|
gimp_drawable_get_format (GIMP_DRAWABLE (layer)));
|
2019-06-11 21:51:16 +02:00
|
|
|
}
|
2015-09-13 00:12:42 +02:00
|
|
|
|
2019-08-17 10:52:05 +02:00
|
|
|
channel[0].drawable = GIMP_DRAWABLE (layer);
|
|
|
|
channel[0].buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
|
|
|
|
channel[0].format = base_format;
|
2003-12-02 22:32:42 +00:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
if (extra > 0 && ! worst_case)
|
2003-07-15 12:35:39 +00:00
|
|
|
{
|
2015-09-13 16:21:35 +02:00
|
|
|
/* Add extra channels as appropriate */
|
2015-09-13 20:12:02 +02:00
|
|
|
for (i = 1; i <= extra; i++)
|
2003-12-02 22:32:42 +00:00
|
|
|
{
|
2023-11-20 00:20:03 +01:00
|
|
|
GeglColor *color = gegl_color_new ("black");
|
2015-09-13 20:12:02 +02:00
|
|
|
|
2019-08-17 10:52:05 +02:00
|
|
|
channel[i].drawable = GIMP_DRAWABLE (gimp_channel_new (*image, _("TIFF Channel"),
|
2023-11-20 00:20:03 +01:00
|
|
|
cols, rows, 100.0, color));
|
|
|
|
g_object_unref (color);
|
2019-08-17 10:52:05 +02:00
|
|
|
gimp_image_insert_channel (*image, GIMP_CHANNEL (channel[i].drawable), NULL, 0);
|
|
|
|
channel[i].buffer = gimp_drawable_get_buffer (channel[i].drawable);
|
2019-06-18 18:16:25 +02:00
|
|
|
|
|
|
|
/* Unlike color channels, we don't care about the source
|
|
|
|
* TRC for extra channels. We just want to import them
|
|
|
|
* as-is without any value conversion. Since extra
|
|
|
|
* channels are always linear in GIMP, we consider TIFF
|
|
|
|
* extra channels with unspecified data to be linear too.
|
|
|
|
* Only exception are 8-bit non-linear images whose
|
|
|
|
* channel are Y' for legacy/compatibility reasons.
|
|
|
|
*/
|
|
|
|
if (image_precision == GIMP_PRECISION_U8_NON_LINEAR)
|
|
|
|
channel[i].format = babl_format_new (babl_model ("Y'"),
|
|
|
|
type,
|
|
|
|
babl_component ("Y'"),
|
|
|
|
NULL);
|
|
|
|
else
|
|
|
|
channel[i].format = babl_format_new (babl_model ("Y"),
|
|
|
|
type,
|
|
|
|
babl_component ("Y"),
|
|
|
|
NULL);
|
2003-12-02 22:32:42 +00:00
|
|
|
}
|
2003-07-15 12:35:39 +00:00
|
|
|
}
|
1998-11-09 02:05:24 +00:00
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
TIFFGetField (tif, TIFFTAG_PLANARCONFIG, &planar);
|
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
if (worst_case)
|
|
|
|
{
|
2012-05-19 02:51:50 +02:00
|
|
|
load_rgba (tif, channel);
|
2003-12-02 22:32:42 +00:00
|
|
|
}
|
2012-06-07 00:06:06 +02:00
|
|
|
else if (planar == PLANARCONFIG_CONTIG)
|
|
|
|
{
|
2020-06-24 15:16:50 +03:00
|
|
|
load_contiguous (tif, channel, type, bps, spp,
|
2021-03-04 12:40:14 -05:00
|
|
|
tiff_mode, is_signed, extra);
|
2012-06-07 00:06:06 +02:00
|
|
|
}
|
2003-12-02 22:32:42 +00:00
|
|
|
else
|
2012-05-19 15:31:44 +02:00
|
|
|
{
|
2020-06-24 15:16:50 +03:00
|
|
|
load_separate (tif, channel, type, bps, spp,
|
2021-03-04 12:40:14 -05:00
|
|
|
tiff_mode, is_signed, extra);
|
2003-12-02 22:32:42 +00:00
|
|
|
}
|
1998-11-09 02:05:24 +00:00
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
if (TIFFGetField (tif, TIFFTAG_ORIENTATION, &orientation))
|
2003-07-15 12:35:39 +00:00
|
|
|
{
|
2014-09-13 21:59:30 +02:00
|
|
|
gboolean flip_horizontal = FALSE;
|
|
|
|
gboolean flip_vertical = FALSE;
|
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
switch (orientation)
|
|
|
|
{
|
|
|
|
case ORIENTATION_TOPLEFT:
|
|
|
|
break;
|
2014-09-13 21:59:30 +02:00
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
case ORIENTATION_TOPRIGHT:
|
|
|
|
flip_horizontal = TRUE;
|
|
|
|
break;
|
2014-09-13 21:59:30 +02:00
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
case ORIENTATION_BOTRIGHT:
|
|
|
|
flip_horizontal = TRUE;
|
|
|
|
flip_vertical = TRUE;
|
|
|
|
break;
|
2014-09-13 21:59:30 +02:00
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
case ORIENTATION_BOTLEFT:
|
2014-09-13 21:59:30 +02:00
|
|
|
flip_vertical = TRUE;
|
2003-12-02 22:32:42 +00:00
|
|
|
break;
|
2014-09-13 21:59:30 +02:00
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
default:
|
|
|
|
g_warning ("Orientation %d not handled yet!", orientation);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flip_horizontal)
|
2019-08-17 10:52:05 +02:00
|
|
|
gimp_item_transform_flip_simple (GIMP_ITEM (layer),
|
2010-10-06 19:53:14 +02:00
|
|
|
GIMP_ORIENTATION_HORIZONTAL,
|
2015-09-13 20:12:02 +02:00
|
|
|
TRUE /* auto_center */,
|
|
|
|
-1.0 /* axis */);
|
2003-12-02 22:32:42 +00:00
|
|
|
|
|
|
|
if (flip_vertical)
|
2019-08-17 10:52:05 +02:00
|
|
|
gimp_item_transform_flip_simple (GIMP_ITEM (layer),
|
2010-10-06 19:53:14 +02:00
|
|
|
GIMP_ORIENTATION_VERTICAL,
|
2015-09-13 20:12:02 +02:00
|
|
|
TRUE /* auto_center */,
|
|
|
|
-1.0 /* axis */);
|
2003-07-15 12:35:39 +00:00
|
|
|
}
|
2003-01-10 13:59:41 +00:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
for (i = 0; i <= extra; i++)
|
2003-12-02 22:32:42 +00:00
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
if (channel[i].buffer)
|
|
|
|
g_object_unref (channel[i].buffer);
|
2003-12-02 22:32:42 +00:00
|
|
|
}
|
2003-01-10 20:14:30 +00:00
|
|
|
|
2003-12-02 22:32:42 +00:00
|
|
|
g_free (channel);
|
|
|
|
channel = NULL;
|
2003-01-10 13:59:41 +00:00
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
if (pages.target != GIMP_PAGE_SELECTOR_TARGET_IMAGES)
|
2004-01-09 19:48:07 +00:00
|
|
|
{
|
2019-04-16 10:04:16 +02:00
|
|
|
/* compute bounding box of all layers read so far */
|
|
|
|
if (min_col > layer_offset_x_pixel)
|
|
|
|
min_col = layer_offset_x_pixel;
|
|
|
|
if (min_row > layer_offset_y_pixel)
|
|
|
|
min_row = layer_offset_y_pixel;
|
|
|
|
|
|
|
|
if (max_col < layer_offset_x_pixel + cols)
|
|
|
|
max_col = layer_offset_x_pixel + cols;
|
|
|
|
if (max_row < layer_offset_y_pixel + rows)
|
|
|
|
max_row = layer_offset_y_pixel + rows;
|
|
|
|
|
|
|
|
/* position the layer */
|
|
|
|
if (layer_offset_x_pixel > 0 ||
|
|
|
|
layer_offset_y_pixel > 0)
|
|
|
|
{
|
|
|
|
gimp_layer_set_offsets (layer,
|
|
|
|
layer_offset_x_pixel,
|
|
|
|
layer_offset_y_pixel);
|
|
|
|
}
|
2004-01-09 19:48:07 +00:00
|
|
|
}
|
|
|
|
|
2019-08-17 10:52:05 +02:00
|
|
|
gimp_image_insert_layer (*image, layer, NULL, -1);
|
2007-04-24 18:36:35 +00:00
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
if (pages.target == GIMP_PAGE_SELECTOR_TARGET_IMAGES)
|
2007-04-24 18:36:35 +00:00
|
|
|
{
|
2019-06-17 17:11:11 +02:00
|
|
|
gimp_image_undo_enable (*image);
|
|
|
|
gimp_image_clean_all (*image);
|
2007-04-24 18:36:35 +00:00
|
|
|
}
|
2007-04-25 14:10:20 +00:00
|
|
|
|
|
|
|
gimp_progress_update (1.0);
|
2003-07-15 12:35:39 +00:00
|
|
|
}
|
2024-08-06 22:56:57 +00:00
|
|
|
|
|
|
|
/* If this TIF was created in Alias/AutoDesk Sketchbook, it may have layers. */
|
|
|
|
if (sketchbook_layers)
|
|
|
|
load_sketchbook_layers (tif, *image);
|
|
|
|
|
2020-12-16 17:56:18 -05:00
|
|
|
g_clear_object (&first_profile);
|
2003-12-02 22:32:42 +00:00
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
if (pages.target == GIMP_PAGE_SELECTOR_TARGET_IMAGES)
|
2007-04-24 18:36:35 +00:00
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
GList *list = images_list;
|
2007-04-24 18:36:35 +00:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
if (list)
|
2007-04-24 18:36:35 +00:00
|
|
|
{
|
2019-08-17 10:52:05 +02:00
|
|
|
*image = list->data;
|
2015-09-13 20:12:02 +02:00
|
|
|
|
|
|
|
list = g_list_next (list);
|
2007-04-24 18:36:35 +00:00
|
|
|
}
|
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
for (; list; list = g_list_next (list))
|
2007-04-24 18:36:35 +00:00
|
|
|
{
|
2019-08-17 10:52:05 +02:00
|
|
|
gimp_display_new (list->data);
|
2007-04-24 18:36:35 +00:00
|
|
|
}
|
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
g_list_free (images_list);
|
2007-04-24 18:36:35 +00:00
|
|
|
}
|
2019-04-16 10:04:16 +02:00
|
|
|
else
|
|
|
|
{
|
2020-11-16 16:10:25 +01:00
|
|
|
if (! (*image))
|
|
|
|
{
|
|
|
|
TIFFClose (tif);
|
|
|
|
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
|
|
|
_("No data could be read from TIFF '%s'. The file is probably corrupted."),
|
|
|
|
gimp_file_get_utf8_name (file));
|
|
|
|
|
|
|
|
return GIMP_PDB_EXECUTION_ERROR;
|
|
|
|
}
|
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
if (pages.keep_empty_space)
|
2019-04-16 10:04:16 +02:00
|
|
|
{
|
|
|
|
/* unfortunately we have no idea about empty space
|
|
|
|
at the bottom/right of layers */
|
|
|
|
min_col = 0;
|
|
|
|
min_row = 0;
|
|
|
|
}
|
2019-06-20 18:08:59 +02:00
|
|
|
|
2019-04-16 10:04:16 +02:00
|
|
|
/* resize image to bounding box of all layers */
|
2024-08-06 22:56:57 +00:00
|
|
|
if (! sketchbook_layers)
|
|
|
|
gimp_image_resize (*image,
|
|
|
|
max_col - min_col, max_row - min_row,
|
|
|
|
-min_col, -min_row);
|
2019-04-16 10:04:16 +02:00
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
gimp_image_undo_enable (*image);
|
2019-04-16 10:04:16 +02:00
|
|
|
}
|
2007-04-24 18:36:35 +00:00
|
|
|
|
2022-12-19 16:29:41 +00:00
|
|
|
/* Load Photoshop layer metadata */
|
|
|
|
if (TIFFGetField (tif, TIFFTAG_PHOTOSHOP, &photoshop_len, &photoshop_data))
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
GFile *temp_file = NULL;
|
libgimp, plug-ins: move gimp_pdb_run_procedure*() to gimp_procedure_run*().
The gimp_procedure_run() already existed, though it was with an ordered
GimpValueArray array of arguments. Its usage feels redundant to the series of
gimp_pdb_run_procedure*() functions (which is confusing), but
gimp_procedure_run() was actually a bit more generic, because it does not
necessarily calls GimpProcedure-s through the PDB! For instance, it can runs a
local GimpProcedure, such as the case of one procedure which would want to call
another procedure in the same plug-in, but without having to go through PDB. Of
course, for local code, you may as well run relevant functions directly, yet it
makes sense that if one of the redundant-looking function is removed, it should
be the more specific one. Also gimp_procedure_run() feels a lot simpler and
logical, API wise.
A main difference in usage is that now, plug-in developers have to first
explicitly look up the GimpPdbProcedure with gimp_pdb_lookup_procedure() when
they wish to call PDB procedures on the wire. This was done anyway in the
gimp_pdb_run_procedure*() code, now it's explicit (rather than calling by name
directly).
Concretely:
* gimp_pdb_run_procedure(), gimp_pdb_run_procedure_config() and
gimp_pdb_run_procedure_valist() are removed.
* gimp_procedure_run() API is modified to use a variable args list instead of a
GimpValueArray.
* gimp_procedure_run_config() and gimp_procedure_run_valist() are added.
* gimp_procedure_run_config() in particular will be the one used in bindings
which don't have variable args support through a (rename-to
gimp_procedure_run) annotation.
2023-10-18 17:11:20 +02:00
|
|
|
GimpProcedure *procedure;
|
2022-12-19 16:29:41 +00:00
|
|
|
GimpValueArray *return_vals = NULL;
|
|
|
|
|
|
|
|
temp_file = gimp_temp_file ("tmp");
|
|
|
|
fp = g_fopen (g_file_peek_path (temp_file), "wb");
|
|
|
|
|
|
|
|
if (! fp)
|
|
|
|
{
|
|
|
|
g_message (_("Error trying to open temporary %s file '%s' "
|
|
|
|
"for tiff metadata loading: %s"),
|
|
|
|
"tmp", gimp_file_get_utf8_name (temp_file),
|
|
|
|
g_strerror (errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
fwrite (photoshop_data, sizeof (guchar), photoshop_len, fp);
|
|
|
|
fclose (fp);
|
|
|
|
|
libgimp, plug-ins: move gimp_pdb_run_procedure*() to gimp_procedure_run*().
The gimp_procedure_run() already existed, though it was with an ordered
GimpValueArray array of arguments. Its usage feels redundant to the series of
gimp_pdb_run_procedure*() functions (which is confusing), but
gimp_procedure_run() was actually a bit more generic, because it does not
necessarily calls GimpProcedure-s through the PDB! For instance, it can runs a
local GimpProcedure, such as the case of one procedure which would want to call
another procedure in the same plug-in, but without having to go through PDB. Of
course, for local code, you may as well run relevant functions directly, yet it
makes sense that if one of the redundant-looking function is removed, it should
be the more specific one. Also gimp_procedure_run() feels a lot simpler and
logical, API wise.
A main difference in usage is that now, plug-in developers have to first
explicitly look up the GimpPdbProcedure with gimp_pdb_lookup_procedure() when
they wish to call PDB procedures on the wire. This was done anyway in the
gimp_pdb_run_procedure*() code, now it's explicit (rather than calling by name
directly).
Concretely:
* gimp_pdb_run_procedure(), gimp_pdb_run_procedure_config() and
gimp_pdb_run_procedure_valist() are removed.
* gimp_procedure_run() API is modified to use a variable args list instead of a
GimpValueArray.
* gimp_procedure_run_config() and gimp_procedure_run_valist() are added.
* gimp_procedure_run_config() in particular will be the one used in bindings
which don't have variable args support through a (rename-to
gimp_procedure_run) annotation.
2023-10-18 17:11:20 +02:00
|
|
|
procedure = gimp_pdb_lookup_procedure (gimp_get_pdb (),
|
|
|
|
"file-psd-load-metadata");
|
|
|
|
return_vals = gimp_procedure_run (procedure,
|
|
|
|
"run-mode", GIMP_RUN_NONINTERACTIVE,
|
|
|
|
"file", temp_file,
|
|
|
|
"size", photoshop_len,
|
|
|
|
"image", *image,
|
|
|
|
"metadata-type", FALSE,
|
|
|
|
NULL);
|
2022-12-19 16:29:41 +00:00
|
|
|
|
|
|
|
g_file_delete (temp_file, NULL, NULL);
|
|
|
|
g_object_unref (temp_file);
|
|
|
|
gimp_value_array_unref (return_vals);
|
|
|
|
|
|
|
|
*ps_metadata_loaded = TRUE;
|
|
|
|
}
|
|
|
|
|
2025-05-28 12:38:47 +00:00
|
|
|
#ifdef TIFFTAG_IMAGESOURCEDATA
|
2022-12-19 16:29:41 +00:00
|
|
|
if (TIFFGetField (tif, TIFFTAG_IMAGESOURCEDATA, &photoshop_len, &photoshop_data))
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
GFile *temp_file = NULL;
|
libgimp, plug-ins: move gimp_pdb_run_procedure*() to gimp_procedure_run*().
The gimp_procedure_run() already existed, though it was with an ordered
GimpValueArray array of arguments. Its usage feels redundant to the series of
gimp_pdb_run_procedure*() functions (which is confusing), but
gimp_procedure_run() was actually a bit more generic, because it does not
necessarily calls GimpProcedure-s through the PDB! For instance, it can runs a
local GimpProcedure, such as the case of one procedure which would want to call
another procedure in the same plug-in, but without having to go through PDB. Of
course, for local code, you may as well run relevant functions directly, yet it
makes sense that if one of the redundant-looking function is removed, it should
be the more specific one. Also gimp_procedure_run() feels a lot simpler and
logical, API wise.
A main difference in usage is that now, plug-in developers have to first
explicitly look up the GimpPdbProcedure with gimp_pdb_lookup_procedure() when
they wish to call PDB procedures on the wire. This was done anyway in the
gimp_pdb_run_procedure*() code, now it's explicit (rather than calling by name
directly).
Concretely:
* gimp_pdb_run_procedure(), gimp_pdb_run_procedure_config() and
gimp_pdb_run_procedure_valist() are removed.
* gimp_procedure_run() API is modified to use a variable args list instead of a
GimpValueArray.
* gimp_procedure_run_config() and gimp_procedure_run_valist() are added.
* gimp_procedure_run_config() in particular will be the one used in bindings
which don't have variable args support through a (rename-to
gimp_procedure_run) annotation.
2023-10-18 17:11:20 +02:00
|
|
|
GimpProcedure *procedure;
|
2022-12-19 16:29:41 +00:00
|
|
|
GimpValueArray *return_vals = NULL;
|
|
|
|
|
|
|
|
/* Photoshop metadata starts with 'Adobe Photoshop Document Data Block'
|
|
|
|
* so we need to skip past that for the data. */
|
|
|
|
photoshop_data += 36;
|
|
|
|
photoshop_len -= 36;
|
|
|
|
|
|
|
|
temp_file = gimp_temp_file ("tmp");
|
|
|
|
fp = g_fopen (g_file_peek_path (temp_file), "wb");
|
|
|
|
|
|
|
|
if (! fp)
|
|
|
|
{
|
|
|
|
g_message (_("Error trying to open temporary %s file '%s' "
|
|
|
|
"for tiff metadata loading: %s"),
|
|
|
|
"tmp", gimp_file_get_utf8_name (temp_file),
|
|
|
|
g_strerror (errno));
|
|
|
|
}
|
|
|
|
|
|
|
|
fwrite (photoshop_data, sizeof (guchar), photoshop_len, fp);
|
|
|
|
fclose (fp);
|
|
|
|
|
libgimp, plug-ins: move gimp_pdb_run_procedure*() to gimp_procedure_run*().
The gimp_procedure_run() already existed, though it was with an ordered
GimpValueArray array of arguments. Its usage feels redundant to the series of
gimp_pdb_run_procedure*() functions (which is confusing), but
gimp_procedure_run() was actually a bit more generic, because it does not
necessarily calls GimpProcedure-s through the PDB! For instance, it can runs a
local GimpProcedure, such as the case of one procedure which would want to call
another procedure in the same plug-in, but without having to go through PDB. Of
course, for local code, you may as well run relevant functions directly, yet it
makes sense that if one of the redundant-looking function is removed, it should
be the more specific one. Also gimp_procedure_run() feels a lot simpler and
logical, API wise.
A main difference in usage is that now, plug-in developers have to first
explicitly look up the GimpPdbProcedure with gimp_pdb_lookup_procedure() when
they wish to call PDB procedures on the wire. This was done anyway in the
gimp_pdb_run_procedure*() code, now it's explicit (rather than calling by name
directly).
Concretely:
* gimp_pdb_run_procedure(), gimp_pdb_run_procedure_config() and
gimp_pdb_run_procedure_valist() are removed.
* gimp_procedure_run() API is modified to use a variable args list instead of a
GimpValueArray.
* gimp_procedure_run_config() and gimp_procedure_run_valist() are added.
* gimp_procedure_run_config() in particular will be the one used in bindings
which don't have variable args support through a (rename-to
gimp_procedure_run) annotation.
2023-10-18 17:11:20 +02:00
|
|
|
procedure = gimp_pdb_lookup_procedure (gimp_get_pdb (),
|
|
|
|
"file-psd-load-metadata");
|
2024-04-08 17:56:37 -04:00
|
|
|
/* We would like to use run_mode below. That way we could show a dialog
|
|
|
|
* when unsupported Photoshop data is detected in interactive mode.
|
|
|
|
* However, in interactive mode saved config values take precedence over
|
|
|
|
* these values set below, so that won't work. */
|
libgimp, plug-ins: move gimp_pdb_run_procedure*() to gimp_procedure_run*().
The gimp_procedure_run() already existed, though it was with an ordered
GimpValueArray array of arguments. Its usage feels redundant to the series of
gimp_pdb_run_procedure*() functions (which is confusing), but
gimp_procedure_run() was actually a bit more generic, because it does not
necessarily calls GimpProcedure-s through the PDB! For instance, it can runs a
local GimpProcedure, such as the case of one procedure which would want to call
another procedure in the same plug-in, but without having to go through PDB. Of
course, for local code, you may as well run relevant functions directly, yet it
makes sense that if one of the redundant-looking function is removed, it should
be the more specific one. Also gimp_procedure_run() feels a lot simpler and
logical, API wise.
A main difference in usage is that now, plug-in developers have to first
explicitly look up the GimpPdbProcedure with gimp_pdb_lookup_procedure() when
they wish to call PDB procedures on the wire. This was done anyway in the
gimp_pdb_run_procedure*() code, now it's explicit (rather than calling by name
directly).
Concretely:
* gimp_pdb_run_procedure(), gimp_pdb_run_procedure_config() and
gimp_pdb_run_procedure_valist() are removed.
* gimp_procedure_run() API is modified to use a variable args list instead of a
GimpValueArray.
* gimp_procedure_run_config() and gimp_procedure_run_valist() are added.
* gimp_procedure_run_config() in particular will be the one used in bindings
which don't have variable args support through a (rename-to
gimp_procedure_run) annotation.
2023-10-18 17:11:20 +02:00
|
|
|
return_vals = gimp_procedure_run (procedure,
|
2024-04-08 17:56:37 -04:00
|
|
|
"run-mode", GIMP_RUN_NONINTERACTIVE,
|
libgimp, plug-ins: move gimp_pdb_run_procedure*() to gimp_procedure_run*().
The gimp_procedure_run() already existed, though it was with an ordered
GimpValueArray array of arguments. Its usage feels redundant to the series of
gimp_pdb_run_procedure*() functions (which is confusing), but
gimp_procedure_run() was actually a bit more generic, because it does not
necessarily calls GimpProcedure-s through the PDB! For instance, it can runs a
local GimpProcedure, such as the case of one procedure which would want to call
another procedure in the same plug-in, but without having to go through PDB. Of
course, for local code, you may as well run relevant functions directly, yet it
makes sense that if one of the redundant-looking function is removed, it should
be the more specific one. Also gimp_procedure_run() feels a lot simpler and
logical, API wise.
A main difference in usage is that now, plug-in developers have to first
explicitly look up the GimpPdbProcedure with gimp_pdb_lookup_procedure() when
they wish to call PDB procedures on the wire. This was done anyway in the
gimp_pdb_run_procedure*() code, now it's explicit (rather than calling by name
directly).
Concretely:
* gimp_pdb_run_procedure(), gimp_pdb_run_procedure_config() and
gimp_pdb_run_procedure_valist() are removed.
* gimp_procedure_run() API is modified to use a variable args list instead of a
GimpValueArray.
* gimp_procedure_run_config() and gimp_procedure_run_valist() are added.
* gimp_procedure_run_config() in particular will be the one used in bindings
which don't have variable args support through a (rename-to
gimp_procedure_run) annotation.
2023-10-18 17:11:20 +02:00
|
|
|
"file", temp_file,
|
|
|
|
"size", photoshop_len,
|
|
|
|
"image", *image,
|
|
|
|
"metadata-type", TRUE,
|
|
|
|
"cmyk", is_cmyk,
|
|
|
|
NULL);
|
2022-12-19 16:29:41 +00:00
|
|
|
|
|
|
|
g_file_delete (temp_file, NULL, NULL);
|
|
|
|
g_object_unref (temp_file);
|
|
|
|
gimp_value_array_unref (return_vals);
|
|
|
|
|
|
|
|
*ps_metadata_loaded = TRUE;
|
|
|
|
}
|
2025-05-28 12:38:47 +00:00
|
|
|
#endif
|
2022-12-19 16:29:41 +00:00
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
g_free (pages.pages);
|
|
|
|
TIFFClose (tif);
|
|
|
|
|
|
|
|
return GIMP_PDB_SUCCESS;
|
1998-11-09 02:05:24 +00:00
|
|
|
}
|
|
|
|
|
2015-11-23 22:29:06 +01:00
|
|
|
static GimpColorProfile *
|
|
|
|
load_profile (TIFF *tif)
|
|
|
|
{
|
|
|
|
GimpColorProfile *profile = NULL;
|
|
|
|
|
|
|
|
#ifdef TIFFTAG_ICCPROFILE
|
|
|
|
/* If TIFFTAG_ICCPROFILE is defined we are dealing with a
|
|
|
|
* libtiff version that can handle ICC profiles. Otherwise just
|
|
|
|
* return a NULL profile.
|
|
|
|
*/
|
2021-10-16 16:37:33 +03:00
|
|
|
uint32_t profile_size;
|
|
|
|
guchar *icc_profile;
|
2015-11-23 22:29:06 +01:00
|
|
|
|
|
|
|
/* set the ICC profile - if found in the TIFF */
|
|
|
|
if (TIFFGetField (tif, TIFFTAG_ICCPROFILE, &profile_size, &icc_profile))
|
|
|
|
{
|
|
|
|
profile = gimp_color_profile_new_from_icc_profile (icc_profile,
|
|
|
|
profile_size,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return profile;
|
|
|
|
}
|
|
|
|
|
1998-11-09 02:05:24 +00:00
|
|
|
static void
|
2014-09-13 21:59:30 +02:00
|
|
|
load_rgba (TIFF *tif,
|
|
|
|
ChannelData *channel)
|
1998-11-09 02:05:24 +00:00
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
guint32 image_width;
|
|
|
|
guint32 image_height;
|
|
|
|
guint32 row;
|
|
|
|
guint32 *buffer;
|
1999-09-17 22:28:25 +00:00
|
|
|
|
2012-05-19 02:51:50 +02:00
|
|
|
g_printerr ("%s\n", __func__);
|
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &image_width);
|
|
|
|
TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &image_height);
|
2003-07-15 12:35:39 +00:00
|
|
|
|
2021-10-16 16:37:33 +03:00
|
|
|
buffer = g_new (uint32_t, image_width * image_height);
|
2003-01-11 01:31:22 +00:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
if (! TIFFReadRGBAImage (tif, image_width, image_height, buffer, 0))
|
2021-03-02 15:23:09 -05:00
|
|
|
{
|
2021-03-02 16:08:55 -05:00
|
|
|
g_message (_("%s: Unsupported image format, no RGBA loader available"),
|
2021-03-02 15:23:09 -05:00
|
|
|
G_STRFUNC);
|
|
|
|
g_free (buffer);
|
|
|
|
return;
|
|
|
|
}
|
1998-11-09 02:05:24 +00:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
for (row = 0; row < image_height; row++)
|
2003-07-15 12:35:39 +00:00
|
|
|
{
|
2004-07-14 10:57:13 +00:00
|
|
|
#if G_BYTE_ORDER != G_LITTLE_ENDIAN
|
|
|
|
/* Make sure our channels are in the right order */
|
2015-09-13 20:12:02 +02:00
|
|
|
guint32 row_start = row * image_width;
|
2015-09-13 20:20:35 +02:00
|
|
|
guint32 row_end = row_start + image_width;
|
2015-09-13 20:12:02 +02:00
|
|
|
guint32 i;
|
2004-07-14 10:57:13 +00:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
for (i = row_start; i < row_end; i++)
|
2024-08-15 09:50:48 +02:00
|
|
|
buffer[i] = GUINT32_FROM_LE (buffer[i]);
|
2004-07-14 10:57:13 +00:00
|
|
|
#endif
|
2007-09-28 10:10:28 +00:00
|
|
|
|
2012-05-19 02:51:50 +02:00
|
|
|
gegl_buffer_set (channel[0].buffer,
|
2015-09-13 20:12:02 +02:00
|
|
|
GEGL_RECTANGLE (0, image_height - row - 1,
|
2015-09-13 20:20:35 +02:00
|
|
|
image_width, 1),
|
2012-05-19 02:51:50 +02:00
|
|
|
0, channel[0].format,
|
2015-09-13 20:12:02 +02:00
|
|
|
((guchar *) buffer) + row * image_width * 4,
|
2012-05-19 02:51:50 +02:00
|
|
|
GEGL_AUTO_ROWSTRIDE);
|
2003-06-13 14:37:00 +00:00
|
|
|
|
2007-05-09 16:14:18 +00:00
|
|
|
if ((row % 32) == 0)
|
2015-09-13 20:12:02 +02:00
|
|
|
gimp_progress_update ((gdouble) row / (gdouble) image_height);
|
2003-07-15 12:35:39 +00:00
|
|
|
}
|
2012-05-19 15:31:44 +02:00
|
|
|
|
|
|
|
g_free (buffer);
|
1999-09-17 22:28:25 +00:00
|
|
|
}
|
1997-11-24 22:05:25 +00:00
|
|
|
|
1999-09-17 22:28:25 +00:00
|
|
|
static void
|
2021-03-04 12:40:14 -05:00
|
|
|
load_contiguous (TIFF *tif,
|
|
|
|
ChannelData *channel,
|
|
|
|
const Babl *type,
|
|
|
|
gushort bps,
|
|
|
|
gushort spp,
|
|
|
|
TiffColorMode tiff_mode,
|
|
|
|
gboolean is_signed,
|
|
|
|
gint extra)
|
1999-09-17 22:28:25 +00:00
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
guint32 image_width;
|
|
|
|
guint32 image_height;
|
|
|
|
guint32 tile_width;
|
|
|
|
guint32 tile_height;
|
|
|
|
gint bytes_per_pixel;
|
|
|
|
const Babl *src_format;
|
|
|
|
guchar *buffer;
|
|
|
|
guchar *bw_buffer = NULL;
|
|
|
|
gdouble progress = 0.0;
|
|
|
|
gdouble one_row;
|
|
|
|
guint32 y;
|
|
|
|
gint i;
|
2021-03-04 12:40:14 -05:00
|
|
|
gboolean needs_upscale = FALSE;
|
1998-11-09 02:05:24 +00:00
|
|
|
|
2012-05-15 02:31:23 +02:00
|
|
|
g_printerr ("%s\n", __func__);
|
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &image_width);
|
|
|
|
TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &image_height);
|
2012-05-19 15:31:44 +02:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
tile_width = image_width;
|
2012-05-19 15:31:44 +02:00
|
|
|
|
|
|
|
if (TIFFIsTiled (tif))
|
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
TIFFGetField (tif, TIFFTAG_TILEWIDTH, &tile_width);
|
|
|
|
TIFFGetField (tif, TIFFTAG_TILELENGTH, &tile_height);
|
|
|
|
|
2012-05-19 15:31:44 +02:00
|
|
|
buffer = g_malloc (TIFFTileSize (tif));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
tile_width = image_width;
|
|
|
|
tile_height = 1;
|
|
|
|
|
2012-05-19 15:31:44 +02:00
|
|
|
buffer = g_malloc (TIFFScanlineSize (tif));
|
|
|
|
}
|
2003-07-15 12:35:39 +00:00
|
|
|
|
2021-03-04 12:40:14 -05:00
|
|
|
if (tiff_mode != GIMP_TIFF_DEFAULT && bps < 8)
|
|
|
|
{
|
|
|
|
needs_upscale = TRUE;
|
|
|
|
bw_buffer = g_malloc (tile_width * tile_height);
|
|
|
|
}
|
2015-09-13 00:12:42 +02:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
one_row = (gdouble) tile_height / (gdouble) image_height;
|
2003-07-15 12:35:39 +00:00
|
|
|
|
2014-09-12 18:50:44 +04:00
|
|
|
src_format = babl_format_n (type, spp);
|
2012-05-15 02:31:23 +02:00
|
|
|
|
|
|
|
/* consistency check */
|
|
|
|
bytes_per_pixel = 0;
|
|
|
|
for (i = 0; i <= extra; i++)
|
|
|
|
bytes_per_pixel += babl_format_get_bytes_per_pixel (channel[i].format);
|
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
g_printerr ("bytes_per_pixel: %d, format: %d\n",
|
|
|
|
bytes_per_pixel,
|
2012-05-15 02:31:23 +02:00
|
|
|
babl_format_get_bytes_per_pixel (src_format));
|
2003-07-15 12:35:39 +00:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
for (y = 0; y < image_height; y += tile_height)
|
2003-07-15 12:35:39 +00:00
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
guint32 x;
|
|
|
|
|
|
|
|
for (x = 0; x < image_width; x += tile_width)
|
2003-07-15 12:35:39 +00:00
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
GeglBuffer *src_buf;
|
|
|
|
guint32 rows;
|
|
|
|
guint32 cols;
|
|
|
|
gint offset;
|
2012-05-15 02:31:23 +02:00
|
|
|
|
2003-07-15 12:35:39 +00:00
|
|
|
gimp_progress_update (progress + one_row *
|
2015-09-13 20:12:02 +02:00
|
|
|
((gdouble) x / (gdouble) image_width));
|
2003-07-15 12:35:39 +00:00
|
|
|
|
2012-05-19 15:31:44 +02:00
|
|
|
if (TIFFIsTiled (tif))
|
2021-03-02 15:23:09 -05:00
|
|
|
{
|
|
|
|
if (TIFFReadTile (tif, buffer, x, y, 0, 0) == -1)
|
|
|
|
{
|
|
|
|
g_message (_("Reading tile failed. Image may be corrupt at line %d."), y);
|
|
|
|
g_free (buffer);
|
|
|
|
g_free (bw_buffer);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2020-10-24 13:44:39 -04:00
|
|
|
else if (TIFFReadScanline (tif, buffer, y, 0) == -1)
|
|
|
|
{
|
|
|
|
/* Error reading scanline, stop loading */
|
2020-10-24 18:31:31 -04:00
|
|
|
g_message (_("Reading scanline failed. Image may be corrupt at line %d."), y);
|
2020-10-24 13:44:39 -04:00
|
|
|
g_free (buffer);
|
|
|
|
g_free (bw_buffer);
|
|
|
|
return;
|
|
|
|
}
|
2003-07-15 12:35:39 +00:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
cols = MIN (image_width - x, tile_width);
|
|
|
|
rows = MIN (image_height - y, tile_height);
|
2003-07-15 12:35:39 +00:00
|
|
|
|
2021-03-04 12:40:14 -05:00
|
|
|
if (needs_upscale)
|
2020-06-24 15:16:50 +03:00
|
|
|
{
|
2020-12-10 18:46:35 -05:00
|
|
|
if (bps == 1)
|
|
|
|
convert_bit2byte (buffer, bw_buffer, cols, rows);
|
|
|
|
else if (bps == 2)
|
|
|
|
convert_2bit2byte (buffer, bw_buffer, cols, rows);
|
|
|
|
else if (bps == 4)
|
|
|
|
convert_4bit2byte (buffer, bw_buffer, cols, rows);
|
2020-06-24 15:16:50 +03:00
|
|
|
}
|
|
|
|
else if (is_signed)
|
|
|
|
{
|
|
|
|
convert_int2uint (buffer, bps, spp, cols, rows,
|
|
|
|
tile_width * bytes_per_pixel);
|
|
|
|
}
|
2015-09-13 00:12:42 +02:00
|
|
|
|
2021-03-04 12:40:14 -05:00
|
|
|
if (tiff_mode == GIMP_TIFF_GRAY_MINISWHITE && bps == 8)
|
|
|
|
{
|
|
|
|
convert_miniswhite (buffer, cols, rows);
|
|
|
|
}
|
|
|
|
|
|
|
|
src_buf = gegl_buffer_linear_new_from_data (needs_upscale ? bw_buffer : buffer,
|
2012-06-07 00:06:06 +02:00
|
|
|
src_format,
|
|
|
|
GEGL_RECTANGLE (0, 0, cols, rows),
|
2015-09-13 20:12:02 +02:00
|
|
|
tile_width * bytes_per_pixel,
|
2012-06-07 00:06:06 +02:00
|
|
|
NULL, NULL);
|
2013-01-13 22:27:22 +01:00
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
offset = 0;
|
2013-01-13 22:27:22 +01:00
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
for (i = 0; i <= extra; i++)
|
2003-07-15 12:35:39 +00:00
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
GeglBufferIterator *iter;
|
|
|
|
gint src_bpp;
|
|
|
|
gint dest_bpp;
|
2013-01-13 22:27:22 +01:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
src_bpp = babl_format_get_bytes_per_pixel (src_format);
|
2012-06-07 00:06:06 +02:00
|
|
|
dest_bpp = babl_format_get_bytes_per_pixel (channel[i].format);
|
2013-01-13 22:27:22 +01:00
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
iter = gegl_buffer_iterator_new (src_buf,
|
|
|
|
GEGL_RECTANGLE (0, 0, cols, rows),
|
|
|
|
0, NULL,
|
2014-07-02 02:00:35 +02:00
|
|
|
GEGL_ACCESS_READ,
|
2018-09-11 02:03:09 +02:00
|
|
|
GEGL_ABYSS_NONE, 2);
|
2012-06-07 00:06:06 +02:00
|
|
|
gegl_buffer_iterator_add (iter, channel[i].buffer,
|
|
|
|
GEGL_RECTANGLE (x, y, cols, rows),
|
2012-08-29 19:04:13 +02:00
|
|
|
0, channel[i].format,
|
2014-07-02 02:00:35 +02:00
|
|
|
GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE);
|
2013-01-13 22:27:22 +01:00
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
while (gegl_buffer_iterator_next (iter))
|
2012-05-15 02:31:23 +02:00
|
|
|
{
|
2018-09-11 02:03:09 +02:00
|
|
|
guchar *s = iter->items[0].data;
|
|
|
|
guchar *d = iter->items[1].data;
|
2014-09-13 21:59:30 +02:00
|
|
|
gint length = iter->length;
|
2013-01-13 22:27:22 +01:00
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
s += offset;
|
|
|
|
|
|
|
|
while (length--)
|
|
|
|
{
|
|
|
|
memcpy (d, s, dest_bpp);
|
|
|
|
d += dest_bpp;
|
|
|
|
s += src_bpp;
|
|
|
|
}
|
|
|
|
}
|
2013-01-13 22:27:22 +01:00
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
offset += dest_bpp;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_object_unref (src_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
progress += one_row;
|
|
|
|
}
|
2015-09-13 00:12:42 +02:00
|
|
|
|
|
|
|
g_free (buffer);
|
|
|
|
g_free (bw_buffer);
|
2012-06-07 00:06:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2021-03-04 12:40:14 -05:00
|
|
|
load_separate (TIFF *tif,
|
|
|
|
ChannelData *channel,
|
|
|
|
const Babl *type,
|
|
|
|
gushort bps,
|
|
|
|
gushort spp,
|
|
|
|
TiffColorMode tiff_mode,
|
|
|
|
gboolean is_signed,
|
|
|
|
gint extra)
|
2012-06-07 00:06:06 +02:00
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
guint32 image_width;
|
|
|
|
guint32 image_height;
|
|
|
|
guint32 tile_width;
|
|
|
|
guint32 tile_height;
|
|
|
|
gint bytes_per_pixel;
|
|
|
|
const Babl *src_format;
|
|
|
|
guchar *buffer;
|
|
|
|
guchar *bw_buffer = NULL;
|
|
|
|
gdouble progress = 0.0;
|
|
|
|
gdouble one_row;
|
|
|
|
gint i, compindex;
|
2021-03-04 12:40:14 -05:00
|
|
|
gboolean needs_upscale = FALSE;
|
2012-06-07 00:06:06 +02:00
|
|
|
|
|
|
|
g_printerr ("%s\n", __func__);
|
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &image_width);
|
|
|
|
TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &image_height);
|
2012-06-07 00:06:06 +02:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
tile_width = image_width;
|
2012-06-07 00:06:06 +02:00
|
|
|
|
|
|
|
if (TIFFIsTiled (tif))
|
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
TIFFGetField (tif, TIFFTAG_TILEWIDTH, &tile_width);
|
|
|
|
TIFFGetField (tif, TIFFTAG_TILELENGTH, &tile_height);
|
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
buffer = g_malloc (TIFFTileSize (tif));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
tile_width = image_width;
|
|
|
|
tile_height = 1;
|
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
buffer = g_malloc (TIFFScanlineSize (tif));
|
|
|
|
}
|
|
|
|
|
2021-03-04 12:40:14 -05:00
|
|
|
if (tiff_mode != GIMP_TIFF_DEFAULT && bps < 8)
|
|
|
|
{
|
|
|
|
needs_upscale = TRUE;
|
|
|
|
bw_buffer = g_malloc (tile_width * tile_height);
|
|
|
|
}
|
2015-09-13 00:12:42 +02:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
one_row = (gdouble) tile_height / (gdouble) image_height;
|
2012-06-07 00:06:06 +02:00
|
|
|
|
2014-09-12 18:50:44 +04:00
|
|
|
src_format = babl_format_n (type, 1);
|
2012-06-07 00:06:06 +02:00
|
|
|
|
|
|
|
/* consistency check */
|
|
|
|
bytes_per_pixel = 0;
|
|
|
|
for (i = 0; i <= extra; i++)
|
|
|
|
bytes_per_pixel += babl_format_get_bytes_per_pixel (channel[i].format);
|
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
g_printerr ("bytes_per_pixel: %d, format: %d\n",
|
|
|
|
bytes_per_pixel,
|
2012-06-07 00:06:06 +02:00
|
|
|
babl_format_get_bytes_per_pixel (src_format));
|
|
|
|
|
2012-06-07 02:51:33 +02:00
|
|
|
compindex = 0;
|
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
for (i = 0; i <= extra; i++)
|
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
gint n_comps;
|
|
|
|
gint src_bpp;
|
|
|
|
gint dest_bpp;
|
|
|
|
gint offset;
|
|
|
|
gint j;
|
2012-06-07 00:06:06 +02:00
|
|
|
|
2014-09-13 21:59:30 +02:00
|
|
|
n_comps = babl_format_get_n_components (channel[i].format);
|
|
|
|
src_bpp = babl_format_get_bytes_per_pixel (src_format);
|
2012-06-07 00:06:06 +02:00
|
|
|
dest_bpp = babl_format_get_bytes_per_pixel (channel[i].format);
|
|
|
|
|
|
|
|
offset = 0;
|
2013-01-13 22:27:22 +01:00
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
for (j = 0; j < n_comps; j++)
|
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
guint32 y;
|
2014-09-13 21:59:30 +02:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
for (y = 0; y < image_height; y += tile_height)
|
2012-06-07 00:06:06 +02:00
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
guint32 x;
|
|
|
|
|
|
|
|
for (x = 0; x < image_width; x += tile_width)
|
2012-06-07 00:06:06 +02:00
|
|
|
{
|
2015-09-13 20:12:02 +02:00
|
|
|
GeglBuffer *src_buf;
|
|
|
|
GeglBufferIterator *iter;
|
|
|
|
guint32 rows;
|
|
|
|
guint32 cols;
|
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
gimp_progress_update (progress + one_row *
|
2015-09-13 20:12:02 +02:00
|
|
|
((gdouble) x / (gdouble) image_width));
|
2013-01-13 22:27:22 +01:00
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
if (TIFFIsTiled (tif))
|
2021-03-02 15:23:09 -05:00
|
|
|
{
|
|
|
|
if (TIFFReadTile (tif, buffer, x, y, 0, compindex) == -1)
|
|
|
|
{
|
|
|
|
g_message (_("Reading tile failed. Image may be corrupt at line %d."), y);
|
|
|
|
g_free (buffer);
|
|
|
|
g_free (bw_buffer);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2020-10-24 13:44:39 -04:00
|
|
|
else if (TIFFReadScanline (tif, buffer, y, compindex) == -1)
|
|
|
|
{
|
|
|
|
/* Error reading scanline, stop loading */
|
2020-10-24 18:31:31 -04:00
|
|
|
g_message (_("Reading scanline failed. Image may be corrupt at line %d."), y);
|
2020-10-24 13:44:39 -04:00
|
|
|
g_free (buffer);
|
|
|
|
g_free (bw_buffer);
|
|
|
|
return;
|
|
|
|
}
|
2013-01-13 22:27:22 +01:00
|
|
|
|
2015-09-13 20:12:02 +02:00
|
|
|
cols = MIN (image_width - x, tile_width);
|
|
|
|
rows = MIN (image_height - y, tile_height);
|
2013-01-13 22:27:22 +01:00
|
|
|
|
2021-03-04 12:40:14 -05:00
|
|
|
if (needs_upscale)
|
2020-06-24 15:16:50 +03:00
|
|
|
{
|
2020-12-10 18:46:35 -05:00
|
|
|
if (bps == 1)
|
|
|
|
convert_bit2byte (buffer, bw_buffer, cols, rows);
|
|
|
|
else if (bps == 2)
|
|
|
|
convert_2bit2byte (buffer, bw_buffer, cols, rows);
|
|
|
|
else if (bps == 4)
|
|
|
|
convert_4bit2byte (buffer, bw_buffer, cols, rows);
|
2020-06-24 15:16:50 +03:00
|
|
|
}
|
|
|
|
else if (is_signed)
|
|
|
|
{
|
2020-06-24 15:50:24 +03:00
|
|
|
convert_int2uint (buffer, bps, 1, cols, rows,
|
2020-06-24 15:16:50 +03:00
|
|
|
tile_width * bytes_per_pixel);
|
|
|
|
}
|
2015-09-13 00:12:42 +02:00
|
|
|
|
2021-03-04 12:40:14 -05:00
|
|
|
if (tiff_mode == GIMP_TIFF_GRAY_MINISWHITE && bps == 8)
|
|
|
|
{
|
|
|
|
convert_miniswhite (buffer, cols, rows);
|
|
|
|
}
|
|
|
|
|
|
|
|
src_buf = gegl_buffer_linear_new_from_data (needs_upscale ? bw_buffer : buffer,
|
2012-06-07 00:06:06 +02:00
|
|
|
src_format,
|
|
|
|
GEGL_RECTANGLE (0, 0, cols, rows),
|
|
|
|
GEGL_AUTO_ROWSTRIDE,
|
|
|
|
NULL, NULL);
|
2013-01-13 22:27:22 +01:00
|
|
|
|
2012-05-19 15:31:44 +02:00
|
|
|
iter = gegl_buffer_iterator_new (src_buf,
|
|
|
|
GEGL_RECTANGLE (0, 0, cols, rows),
|
|
|
|
0, NULL,
|
2014-07-02 02:00:35 +02:00
|
|
|
GEGL_ACCESS_READ,
|
2018-09-11 02:03:09 +02:00
|
|
|
GEGL_ABYSS_NONE, 2);
|
2012-05-19 15:31:44 +02:00
|
|
|
gegl_buffer_iterator_add (iter, channel[i].buffer,
|
|
|
|
GEGL_RECTANGLE (x, y, cols, rows),
|
2012-08-29 19:04:13 +02:00
|
|
|
0, channel[i].format,
|
2014-07-02 02:00:35 +02:00
|
|
|
GEGL_ACCESS_READWRITE,
|
2012-06-07 00:06:06 +02:00
|
|
|
GEGL_ABYSS_NONE);
|
2013-01-13 22:27:22 +01:00
|
|
|
|
2012-05-19 15:31:44 +02:00
|
|
|
while (gegl_buffer_iterator_next (iter))
|
2012-05-15 02:31:23 +02:00
|
|
|
{
|
2018-09-11 02:03:09 +02:00
|
|
|
guchar *s = iter->items[0].data;
|
|
|
|
guchar *d = iter->items[1].data;
|
2014-09-13 21:59:30 +02:00
|
|
|
gint length = iter->length;
|
2013-01-13 22:27:22 +01:00
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
d += offset;
|
2013-01-13 22:27:22 +01:00
|
|
|
|
2012-05-19 15:31:44 +02:00
|
|
|
while (length--)
|
|
|
|
{
|
2012-06-07 00:06:06 +02:00
|
|
|
memcpy (d, s, src_bpp);
|
2012-05-19 15:31:44 +02:00
|
|
|
d += dest_bpp;
|
|
|
|
s += src_bpp;
|
|
|
|
}
|
2012-05-15 02:31:23 +02:00
|
|
|
}
|
2013-01-13 22:27:22 +01:00
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
g_object_unref (src_buf);
|
2012-05-15 02:31:23 +02:00
|
|
|
}
|
2003-07-15 12:35:39 +00:00
|
|
|
}
|
2012-05-15 02:31:23 +02:00
|
|
|
|
2012-06-07 00:06:06 +02:00
|
|
|
offset += src_bpp;
|
2015-09-13 20:12:02 +02:00
|
|
|
compindex++;
|
2003-07-15 12:35:39 +00:00
|
|
|
}
|
|
|
|
|
2012-05-19 15:31:44 +02:00
|
|
|
progress += one_row;
|
2003-07-15 12:35:39 +00:00
|
|
|
}
|
2013-01-12 22:52:42 -05:00
|
|
|
|
|
|
|
g_free (buffer);
|
2015-09-13 00:12:42 +02:00
|
|
|
g_free (bw_buffer);
|
1999-09-17 22:28:25 +00:00
|
|
|
}
|
1998-11-09 02:05:24 +00:00
|
|
|
|
2024-08-06 22:56:57 +00:00
|
|
|
/* Loads layers stored by the Alias/AutoDesk Sketchbook program */
|
|
|
|
static void
|
|
|
|
load_sketchbook_layers (TIFF *tif,
|
|
|
|
GimpImage *image)
|
|
|
|
{
|
2025-05-28 12:38:47 +00:00
|
|
|
gchar *alias_layer_info = NULL;
|
2024-08-06 22:56:57 +00:00
|
|
|
gint alias_data_len;
|
|
|
|
guint32 image_height = gimp_image_get_height (image);
|
|
|
|
guint32 image_width = gimp_image_get_width (image);
|
|
|
|
GeglColor *fill_color;
|
|
|
|
GeglColor *foreground_color;
|
|
|
|
GimpLayer *background_layer;
|
|
|
|
GimpLayerMode default_mode;
|
|
|
|
const Babl *format = NULL;
|
|
|
|
gchar **image_settings;
|
|
|
|
gchar *hex_color;
|
|
|
|
gint layer_count = 0;
|
|
|
|
gint sub_len;
|
|
|
|
void *ptr;
|
|
|
|
gchar *endptr = NULL;
|
|
|
|
|
|
|
|
default_mode = gimp_image_get_default_new_layer_mode (image);
|
|
|
|
|
|
|
|
TIFFSetDirectory (tif, 0);
|
|
|
|
|
2025-05-28 12:38:47 +00:00
|
|
|
#ifdef TIFFTAG_ALIAS_LAYER_METADATA
|
2024-08-06 22:56:57 +00:00
|
|
|
TIFFGetField (tif, TIFFTAG_ALIAS_LAYER_METADATA, &alias_data_len,
|
|
|
|
&alias_layer_info);
|
2025-05-28 12:38:47 +00:00
|
|
|
#endif
|
|
|
|
if (! alias_layer_info || ! g_utf8_validate (alias_layer_info, -1, NULL))
|
2024-08-06 22:56:57 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* Create background layer. Fill it with the hex color from
|
|
|
|
* the image-level ALIAS_LAYER_METADATA tag. The hex color
|
|
|
|
* is in AGBR format so we need to reverse it */
|
|
|
|
image_settings = g_strsplit (alias_layer_info, ", ", 15);
|
|
|
|
|
|
|
|
if (image_settings[0] != NULL)
|
|
|
|
layer_count = g_ascii_strtoll (image_settings[0], &endptr, 10);
|
|
|
|
|
|
|
|
if (image_settings[2] != NULL && strlen (image_settings[2]) >= 8)
|
|
|
|
hex_color =
|
|
|
|
g_strdup_printf ("#%s%s%s%s", g_utf8_substring (image_settings[2], 6, 8),
|
|
|
|
g_utf8_substring (image_settings[2], 4, 6),
|
|
|
|
g_utf8_substring (image_settings[2], 2, 4),
|
|
|
|
g_utf8_substring (image_settings[2], 0, 2));
|
|
|
|
else
|
|
|
|
hex_color = g_strdup ("transparent");
|
|
|
|
|
|
|
|
fill_color = gegl_color_new (hex_color);
|
|
|
|
g_free (hex_color);
|
|
|
|
|
|
|
|
foreground_color = gegl_color_duplicate (gimp_context_get_foreground ());
|
|
|
|
gimp_context_set_foreground (fill_color);
|
|
|
|
|
|
|
|
background_layer = gimp_layer_new (image, _("Background"),
|
|
|
|
image_width, image_height,
|
|
|
|
GIMP_RGBA_IMAGE, 100, default_mode);
|
|
|
|
|
|
|
|
gimp_image_insert_layer (image, background_layer, NULL, -1);
|
|
|
|
gimp_drawable_fill (GIMP_DRAWABLE (background_layer), GIMP_FILL_FOREGROUND);
|
|
|
|
|
|
|
|
g_object_unref (fill_color);
|
|
|
|
gimp_context_set_foreground (foreground_color);
|
|
|
|
g_object_unref (foreground_color);
|
|
|
|
|
|
|
|
/* The layers are stored in BGRA format */
|
|
|
|
format = babl_format_new (babl_model ("R~G~B~A"),
|
|
|
|
babl_type ("u8"),
|
|
|
|
babl_component ("B~"),
|
|
|
|
babl_component ("G~"),
|
|
|
|
babl_component ("R~"),
|
|
|
|
babl_component ("A"),
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
/* Layers are stored in SubIFDs of the first directory */
|
|
|
|
if (TIFFGetField (tif, TIFFTAG_SUBIFD, &sub_len, &ptr))
|
|
|
|
{
|
|
|
|
toff_t offsets[sub_len];
|
|
|
|
gint count = 0;
|
|
|
|
|
|
|
|
memcpy (offsets, ptr, sub_len * sizeof (offsets[0]));
|
|
|
|
|
|
|
|
for (gint i = 0; i < sub_len; i++)
|
|
|
|
{
|
|
|
|
gchar *alias_sublayer_info = NULL;
|
|
|
|
gint32 alias_sublayer_len = 0;
|
|
|
|
|
|
|
|
if (! TIFFSetSubDirectory (tif, offsets[i]))
|
|
|
|
break;
|
|
|
|
|
2025-05-28 12:38:47 +00:00
|
|
|
#ifdef TIFFTAG_ALIAS_LAYER_METADATA
|
2024-08-06 22:56:57 +00:00
|
|
|
if (TIFFGetField (tif, TIFFTAG_ALIAS_LAYER_METADATA, &alias_sublayer_len, &alias_sublayer_info) &&
|
|
|
|
g_utf8_validate (alias_sublayer_info, -1, NULL))
|
|
|
|
{
|
2025-03-26 23:22:21 +00:00
|
|
|
gchar **layer_settings;
|
|
|
|
GimpLayer *layer;
|
|
|
|
GeglBuffer *buffer;
|
|
|
|
const gchar *layer_name;
|
|
|
|
guint32 layer_width = 0;
|
|
|
|
guint32 layer_height = 0;
|
|
|
|
gfloat x_pos = 0;
|
|
|
|
gfloat y_pos = 0;
|
|
|
|
gfloat opacity = 100;
|
|
|
|
gboolean visible = TRUE;
|
|
|
|
gboolean locked = FALSE;
|
|
|
|
guint32 *pixels;
|
|
|
|
guint32 row;
|
2024-08-06 22:56:57 +00:00
|
|
|
|
|
|
|
layer_settings = g_strsplit (alias_sublayer_info, ", ", 10);
|
|
|
|
|
|
|
|
if (layer_settings[0] != NULL)
|
|
|
|
{
|
|
|
|
opacity = (gfloat) g_ascii_strtod (layer_settings[0], &endptr);
|
|
|
|
opacity *= 100.0f;
|
|
|
|
}
|
|
|
|
if (layer_settings[2] != NULL)
|
|
|
|
visible = g_ascii_strtoll (layer_settings[2], &endptr, 10);
|
|
|
|
|
|
|
|
if (layer_settings[3] != NULL)
|
|
|
|
locked = g_ascii_strtoll (layer_settings[3], &endptr, 10);
|
|
|
|
|
|
|
|
/* Additional tags in SubIFD */
|
|
|
|
layer_name = tiff_get_page_name (tif);
|
|
|
|
|
|
|
|
TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &layer_width);
|
2024-08-23 01:56:38 +00:00
|
|
|
TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &layer_height);
|
2024-08-06 22:56:57 +00:00
|
|
|
|
|
|
|
if (! TIFFGetField (tif, TIFFTAG_XPOSITION, &x_pos))
|
|
|
|
x_pos = 0.0f;
|
|
|
|
|
|
|
|
if (! TIFFGetField (tif, TIFFTAG_YPOSITION, &y_pos))
|
|
|
|
y_pos = 0.0f;
|
|
|
|
|
|
|
|
layer = gimp_layer_new (image, layer_name, layer_width,
|
|
|
|
layer_height, GIMP_RGBA_IMAGE, opacity,
|
|
|
|
default_mode);
|
|
|
|
|
|
|
|
gimp_image_insert_layer (image, layer, NULL, -1);
|
|
|
|
|
|
|
|
/* Loading pixel data */
|
|
|
|
pixels = g_new (uint32_t, layer_width * layer_height);
|
2024-08-23 01:56:38 +00:00
|
|
|
if (! TIFFReadRGBAImage (tif, layer_width, layer_height, pixels, 0))
|
2024-08-06 22:56:57 +00:00
|
|
|
{
|
|
|
|
g_free (pixels);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
|
|
|
|
|
|
|
|
for (row = 0; row < layer_height; row++)
|
|
|
|
{
|
|
|
|
#if G_BYTE_ORDER != G_LITTLE_ENDIAN
|
|
|
|
guint32 row_start = row * layer_width;
|
|
|
|
guint32 row_end = row_start + layer_width;
|
|
|
|
guint32 i;
|
|
|
|
|
|
|
|
/* Make sure our channels are in the right order */
|
|
|
|
for (i = row_start; i < row_end; i++)
|
2024-08-15 09:50:48 +02:00
|
|
|
pixels[i] = GUINT32_FROM_LE (pixels[i]);
|
2024-08-06 22:56:57 +00:00
|
|
|
#endif
|
|
|
|
gegl_buffer_set (buffer,
|
|
|
|
GEGL_RECTANGLE (0, layer_height - row - 1,
|
|
|
|
layer_width, 1),
|
|
|
|
0, format,
|
|
|
|
((guchar *) pixels) + row * layer_width * 4,
|
|
|
|
GEGL_AUTO_ROWSTRIDE);
|
|
|
|
}
|
|
|
|
g_object_unref (buffer);
|
|
|
|
g_free (pixels);
|
|
|
|
|
|
|
|
x_pos += (layer_width - gimp_drawable_get_width (GIMP_DRAWABLE (layer)));
|
|
|
|
y_pos = image_height - gimp_drawable_get_height (GIMP_DRAWABLE (layer)) - y_pos;
|
|
|
|
|
|
|
|
gimp_layer_set_offsets (layer, ROUND (x_pos), ROUND (y_pos));
|
|
|
|
|
|
|
|
gimp_item_set_visible (GIMP_ITEM (layer), visible);
|
|
|
|
/* Set locks after copying pixel data over */
|
|
|
|
gimp_item_set_lock_content (GIMP_ITEM (layer), locked);
|
|
|
|
gimp_layer_set_lock_alpha (layer, locked);
|
|
|
|
|
|
|
|
count++;
|
|
|
|
gimp_progress_update ((gdouble) count / (gdouble) layer_count);
|
|
|
|
}
|
2025-05-28 12:38:47 +00:00
|
|
|
#endif
|
2024-08-06 22:56:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-01-01 19:13:38 +00:00
|
|
|
static void
|
2021-03-04 12:40:14 -05:00
|
|
|
fill_bit2byte (TiffColorMode tiff_mode)
|
2005-01-01 19:13:38 +00:00
|
|
|
{
|
|
|
|
static gboolean filled = FALSE;
|
|
|
|
|
|
|
|
guchar *dest;
|
|
|
|
gint i, j;
|
|
|
|
|
|
|
|
if (filled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
dest = bit2byte;
|
|
|
|
|
2021-03-04 12:40:14 -05:00
|
|
|
if (tiff_mode == GIMP_TIFF_INDEXED)
|
|
|
|
{
|
|
|
|
for (j = 0; j < 256; j++)
|
|
|
|
for (i = 7; i >= 0; i--)
|
|
|
|
{
|
|
|
|
*(dest++) = ((j & (1 << i)) != 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tiff_mode != GIMP_TIFF_DEFAULT)
|
|
|
|
{
|
|
|
|
guchar *_to_8_bitmap = NULL;
|
|
|
|
|
|
|
|
if (tiff_mode == GIMP_TIFF_GRAY)
|
|
|
|
_to_8_bitmap = (guchar *) &_1_to_8_bitmap;
|
|
|
|
else if (tiff_mode == GIMP_TIFF_GRAY_MINISWHITE)
|
|
|
|
_to_8_bitmap = (guchar *) &_1_to_8_bitmap_rev;
|
|
|
|
|
|
|
|
for (j = 0; j < 256; j++)
|
|
|
|
for (i = 7; i >= 0; i--)
|
|
|
|
{
|
|
|
|
gint idx;
|
|
|
|
|
|
|
|
idx = ((j & (1 << i)) != 0);
|
|
|
|
*(dest++) = _to_8_bitmap[idx];
|
|
|
|
}
|
|
|
|
}
|
2005-01-01 19:13:38 +00:00
|
|
|
|
|
|
|
filled = TRUE;
|
|
|
|
}
|
2015-09-13 00:12:42 +02:00
|
|
|
|
2020-12-10 18:46:35 -05:00
|
|
|
static void
|
2021-03-04 12:40:14 -05:00
|
|
|
fill_2bit2byte (TiffColorMode tiff_mode)
|
2020-12-10 18:46:35 -05:00
|
|
|
{
|
|
|
|
static gboolean filled2 = FALSE;
|
|
|
|
|
|
|
|
guchar *dest;
|
|
|
|
gint i, j;
|
|
|
|
|
|
|
|
if (filled2)
|
|
|
|
return;
|
|
|
|
|
|
|
|
dest = _2bit2byte;
|
|
|
|
|
2021-03-04 12:40:14 -05:00
|
|
|
if (tiff_mode == GIMP_TIFF_INDEXED)
|
2020-12-10 18:46:35 -05:00
|
|
|
{
|
2021-03-04 12:40:14 -05:00
|
|
|
for (j = 0; j < 256; j++)
|
|
|
|
{
|
|
|
|
for (i = 3; i >= 0; i--)
|
|
|
|
{
|
|
|
|
*(dest++) = ((j & (3 << (2*i))) >> (2*i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tiff_mode != GIMP_TIFF_DEFAULT)
|
|
|
|
{
|
|
|
|
guchar *_to_8_bitmap = NULL;
|
|
|
|
|
|
|
|
if (tiff_mode == GIMP_TIFF_GRAY)
|
|
|
|
_to_8_bitmap = (guchar *) &_2_to_8_bitmap;
|
|
|
|
else if (tiff_mode == GIMP_TIFF_GRAY_MINISWHITE)
|
|
|
|
_to_8_bitmap = (guchar *) &_2_to_8_bitmap_rev;
|
|
|
|
|
|
|
|
for (j = 0; j < 256; j++)
|
|
|
|
{
|
|
|
|
for (i = 3; i >= 0; i--)
|
|
|
|
{
|
|
|
|
gint idx;
|
|
|
|
|
|
|
|
idx = ((j & (3 << (2*i))) >> (2*i));
|
|
|
|
*(dest++) = _to_8_bitmap[idx];
|
|
|
|
}
|
|
|
|
}
|
2020-12-10 18:46:35 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
filled2 = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-03-04 12:40:14 -05:00
|
|
|
fill_4bit2byte (TiffColorMode tiff_mode)
|
2020-12-10 18:46:35 -05:00
|
|
|
{
|
|
|
|
static gboolean filled4 = FALSE;
|
|
|
|
|
|
|
|
guchar *dest;
|
|
|
|
gint i, j;
|
|
|
|
|
|
|
|
if (filled4)
|
|
|
|
return;
|
|
|
|
|
|
|
|
dest = _4bit2byte;
|
|
|
|
|
2021-03-04 12:40:14 -05:00
|
|
|
if (tiff_mode == GIMP_TIFF_INDEXED)
|
2020-12-10 18:46:35 -05:00
|
|
|
{
|
2021-03-04 12:40:14 -05:00
|
|
|
for (j = 0; j < 256; j++)
|
|
|
|
{
|
|
|
|
for (i = 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
*(dest++) = ((j & (15 << (4*i))) >> (4*i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tiff_mode != GIMP_TIFF_DEFAULT)
|
|
|
|
{
|
|
|
|
guchar *_to_8_bitmap = NULL;
|
|
|
|
|
|
|
|
if (tiff_mode == GIMP_TIFF_GRAY)
|
|
|
|
_to_8_bitmap = (guchar *) &_4_to_8_bitmap;
|
|
|
|
else if (tiff_mode == GIMP_TIFF_GRAY_MINISWHITE)
|
|
|
|
_to_8_bitmap = (guchar *) &_4_to_8_bitmap_rev;
|
|
|
|
|
|
|
|
for (j = 0; j < 256; j++)
|
|
|
|
{
|
|
|
|
for (i = 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
gint idx;
|
|
|
|
|
|
|
|
idx = ((j & (15 << (4*i))) >> (4*i));
|
|
|
|
*(dest++) = _to_8_bitmap[idx];
|
|
|
|
}
|
|
|
|
}
|
2020-12-10 18:46:35 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
filled4 = TRUE;
|
|
|
|
}
|
|
|
|
|
2015-09-13 00:12:42 +02:00
|
|
|
static void
|
|
|
|
convert_bit2byte (const guchar *src,
|
|
|
|
guchar *dest,
|
2015-09-13 20:12:02 +02:00
|
|
|
gint width,
|
|
|
|
gint height)
|
2015-09-13 00:12:42 +02:00
|
|
|
{
|
2022-06-08 13:22:46 -04:00
|
|
|
gint64 x = width * height;
|
2015-09-13 00:12:42 +02:00
|
|
|
|
2022-06-08 13:22:46 -04:00
|
|
|
while (x >= 8)
|
2015-09-13 00:12:42 +02:00
|
|
|
{
|
2022-06-08 13:22:46 -04:00
|
|
|
memcpy (dest, bit2byte + *src * 8, 8);
|
|
|
|
dest += 8;
|
|
|
|
x -= 8;
|
|
|
|
src++;
|
|
|
|
}
|
2015-09-13 00:12:42 +02:00
|
|
|
|
2022-06-08 13:22:46 -04:00
|
|
|
if (x > 0)
|
|
|
|
{
|
|
|
|
memcpy (dest, bit2byte + *src * 8, x);
|
|
|
|
dest += x;
|
|
|
|
src++;
|
2015-09-13 00:12:42 +02:00
|
|
|
}
|
|
|
|
}
|
2019-06-17 17:11:11 +02:00
|
|
|
|
2020-12-10 18:46:35 -05:00
|
|
|
static void
|
|
|
|
convert_2bit2byte (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
gint width,
|
|
|
|
gint height)
|
|
|
|
{
|
2022-06-08 13:22:46 -04:00
|
|
|
gint64 x = width * height;
|
2020-12-10 18:46:35 -05:00
|
|
|
|
2022-06-08 13:22:46 -04:00
|
|
|
while (x >= 4)
|
2020-12-10 18:46:35 -05:00
|
|
|
{
|
2022-06-08 13:22:46 -04:00
|
|
|
memcpy (dest, _2bit2byte + *src * 4, 4);
|
|
|
|
dest += 4;
|
|
|
|
x -= 4;
|
|
|
|
src++;
|
|
|
|
}
|
2020-12-10 18:46:35 -05:00
|
|
|
|
2022-06-08 13:22:46 -04:00
|
|
|
if (x > 0)
|
|
|
|
{
|
|
|
|
memcpy (dest, _2bit2byte + *src * 4, x);
|
|
|
|
dest += x;
|
|
|
|
src++;
|
2020-12-10 18:46:35 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
convert_4bit2byte (const guchar *src,
|
|
|
|
guchar *dest,
|
|
|
|
gint width,
|
|
|
|
gint height)
|
|
|
|
{
|
2022-06-08 13:22:46 -04:00
|
|
|
gint64 x = width * height;
|
2020-12-10 18:46:35 -05:00
|
|
|
|
2022-06-08 13:22:46 -04:00
|
|
|
while (x >= 2)
|
2020-12-10 18:46:35 -05:00
|
|
|
{
|
2022-06-08 13:22:46 -04:00
|
|
|
memcpy (dest, _4bit2byte + *src * 2, 2);
|
|
|
|
dest += 2;
|
|
|
|
x -= 2;
|
|
|
|
src++;
|
|
|
|
}
|
2020-12-10 18:46:35 -05:00
|
|
|
|
2022-06-08 13:22:46 -04:00
|
|
|
if (x > 0)
|
|
|
|
{
|
|
|
|
memcpy (dest, _4bit2byte + *src * 2, x);
|
|
|
|
dest += x;
|
|
|
|
src++;
|
2020-12-10 18:46:35 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-04 12:40:14 -05:00
|
|
|
static void
|
|
|
|
convert_miniswhite (guchar *buffer,
|
|
|
|
gint width,
|
|
|
|
gint height)
|
|
|
|
{
|
|
|
|
gint y;
|
|
|
|
guchar *buf = buffer;
|
|
|
|
|
|
|
|
for (y = 0; y < height; y++)
|
|
|
|
{
|
|
|
|
gint x;
|
|
|
|
|
|
|
|
for (x = 0; x < width; x++)
|
|
|
|
{
|
|
|
|
*buf = ~*buf;
|
|
|
|
buf++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-24 15:16:50 +03:00
|
|
|
static void
|
|
|
|
convert_int2uint (guchar *buffer,
|
|
|
|
gint bps,
|
|
|
|
gint spp,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
gint stride)
|
|
|
|
{
|
|
|
|
gint bytes_per_pixel = bps / 8;
|
|
|
|
gint y;
|
|
|
|
|
|
|
|
for (y = 0; y < height; y++)
|
|
|
|
{
|
|
|
|
guchar *d = buffer + stride * y;
|
|
|
|
gint x;
|
|
|
|
|
|
|
|
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
|
|
|
d += bytes_per_pixel - 1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (x = 0; x < width * spp; x++)
|
|
|
|
{
|
|
|
|
*d ^= 0x80;
|
|
|
|
|
|
|
|
d += bytes_per_pixel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
static gboolean
|
2024-05-31 04:34:51 +00:00
|
|
|
load_dialog (GimpProcedure *procedure,
|
|
|
|
GimpProcedureConfig *config,
|
|
|
|
TiffSelectedPages *pages,
|
|
|
|
const gchar *extra_message,
|
|
|
|
DefaultExtra *default_extra)
|
2019-06-17 17:11:11 +02:00
|
|
|
{
|
|
|
|
GtkWidget *dialog;
|
|
|
|
GtkWidget *vbox;
|
2024-05-31 04:34:51 +00:00
|
|
|
GtkWidget *toggle = NULL;
|
|
|
|
GtkWidget *extra_radio = NULL;
|
2019-06-17 17:11:11 +02:00
|
|
|
gboolean run;
|
|
|
|
|
2022-06-13 11:05:12 +00:00
|
|
|
pages->selector = NULL;
|
|
|
|
|
2024-05-31 04:34:51 +00:00
|
|
|
dialog = gimp_procedure_dialog_new (procedure,
|
|
|
|
GIMP_PROCEDURE_CONFIG (config),
|
|
|
|
_("Import from TIFF"));
|
2019-06-17 17:11:11 +02:00
|
|
|
|
2024-05-31 04:34:51 +00:00
|
|
|
vbox = gimp_procedure_dialog_fill_box (GIMP_PROCEDURE_DIALOG (dialog), "tiff-vbox",
|
|
|
|
"keep-empty-space", NULL);
|
2019-06-17 17:11:11 +02:00
|
|
|
|
2024-05-31 04:34:51 +00:00
|
|
|
gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"tiff-vbox", NULL);
|
2019-06-17 17:11:11 +02:00
|
|
|
|
2024-05-31 04:34:51 +00:00
|
|
|
toggle = gtk_check_button_new_with_mnemonic (_("_Show reduced images"));
|
|
|
|
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
|
2022-06-13 11:05:12 +00:00
|
|
|
pages->show_reduced);
|
2024-05-31 04:34:51 +00:00
|
|
|
gtk_widget_set_margin_bottom (toggle, 6);
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), toggle, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_set_visible (toggle, TRUE);
|
2022-06-13 11:05:12 +00:00
|
|
|
|
2024-05-31 04:34:51 +00:00
|
|
|
g_signal_connect (toggle, "toggled",
|
2022-06-13 11:05:12 +00:00
|
|
|
G_CALLBACK (tiff_dialog_show_reduced),
|
|
|
|
pages);
|
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
if (pages->n_pages > 1)
|
|
|
|
{
|
|
|
|
/* Page Selector */
|
2022-06-13 11:05:12 +00:00
|
|
|
pages->selector = gimp_page_selector_new ();
|
|
|
|
gtk_widget_set_size_request (pages->selector, 300, 200);
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), pages->selector, TRUE, TRUE, 0);
|
2024-05-31 04:34:51 +00:00
|
|
|
gtk_widget_set_visible (pages->selector, TRUE);
|
2019-06-17 17:11:11 +02:00
|
|
|
|
2022-06-13 11:05:12 +00:00
|
|
|
gimp_page_selector_set_n_pages (GIMP_PAGE_SELECTOR (pages->selector),
|
2021-08-27 15:15:12 -04:00
|
|
|
pages->n_filtered_pages);
|
2022-06-13 11:05:12 +00:00
|
|
|
gimp_page_selector_set_target (GIMP_PAGE_SELECTOR (pages->selector),
|
|
|
|
pages->target);
|
2019-06-17 17:11:11 +02:00
|
|
|
|
2022-06-13 11:05:12 +00:00
|
|
|
/* Load a set number of pages, based on whether "Show Reduced Images"
|
|
|
|
* is checked
|
|
|
|
*/
|
2024-05-31 04:34:51 +00:00
|
|
|
tiff_dialog_show_reduced (toggle, pages);
|
2019-06-17 17:11:11 +02:00
|
|
|
|
2022-06-13 11:05:12 +00:00
|
|
|
g_signal_connect_swapped (pages->selector, "activate",
|
2019-06-17 17:11:11 +02:00
|
|
|
G_CALLBACK (gtk_window_activate_default),
|
|
|
|
dialog);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (extra_message)
|
|
|
|
{
|
|
|
|
GtkWidget *warning;
|
|
|
|
|
|
|
|
warning = g_object_new (GIMP_TYPE_HINT_BOX,
|
|
|
|
"icon-name", GIMP_ICON_DIALOG_WARNING,
|
|
|
|
"hint", extra_message,
|
|
|
|
NULL);
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), warning, TRUE, TRUE, 0);
|
2024-05-31 04:34:51 +00:00
|
|
|
gtk_widget_set_visible (warning, TRUE);
|
2019-06-17 17:11:11 +02:00
|
|
|
|
|
|
|
extra_radio = gimp_int_radio_group_new (TRUE, _("Process extra channel as:"),
|
|
|
|
(GCallback) gimp_radio_button_update,
|
2020-01-15 13:51:55 +01:00
|
|
|
default_extra, NULL, GIMP_TIFF_LOAD_UNASSALPHA,
|
Missing mnemonics on several file dialogs
This path corrects missing mnemonics on several save/open/export dialogs.
save: file
open: file, dds, fits, tiff
export: bmp, dds, fli, gbr, gih, mng, pat, pnm, pdf, raw, sunras, sgi, webp
2019-09-09 18:06:29 +00:00
|
|
|
_("_Non-premultiplied alpha"), GIMP_TIFF_LOAD_UNASSALPHA, NULL,
|
|
|
|
_("Pre_multiplied alpha"), GIMP_TIFF_LOAD_ASSOCALPHA, NULL,
|
|
|
|
_("Channe_l"), GIMP_TIFF_LOAD_CHANNEL, NULL,
|
2019-06-17 17:11:11 +02:00
|
|
|
NULL);
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), extra_radio, TRUE, TRUE, 0);
|
2024-05-31 04:34:51 +00:00
|
|
|
gtk_widget_set_visible (extra_radio, TRUE);
|
2019-06-17 17:11:11 +02:00
|
|
|
}
|
|
|
|
|
2024-05-31 04:34:51 +00:00
|
|
|
toggle = gimp_procedure_dialog_get_widget (GIMP_PROCEDURE_DIALOG (dialog),
|
|
|
|
"keep-empty-space", G_TYPE_NONE);
|
|
|
|
gtk_widget_set_margin_top (toggle, 6);
|
|
|
|
gtk_widget_set_margin_bottom (toggle, 6);
|
|
|
|
gtk_box_reorder_child (GTK_BOX (vbox), toggle, -1);
|
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
/* Setup done; display the dialog */
|
2024-05-31 04:34:51 +00:00
|
|
|
gtk_widget_set_visible (dialog, TRUE);
|
2019-06-17 17:11:11 +02:00
|
|
|
|
|
|
|
/* run the dialog */
|
2024-05-31 04:34:51 +00:00
|
|
|
run = gimp_procedure_dialog_run (GIMP_PROCEDURE_DIALOG (dialog));
|
2019-06-17 17:11:11 +02:00
|
|
|
|
|
|
|
if (run)
|
|
|
|
{
|
|
|
|
if (pages->n_pages > 1)
|
|
|
|
{
|
2024-05-31 04:34:51 +00:00
|
|
|
g_object_get (config,
|
|
|
|
"keep-empty-space", &pages->keep_empty_space,
|
|
|
|
NULL);
|
|
|
|
|
2019-06-17 17:11:11 +02:00
|
|
|
pages->target =
|
2022-06-13 11:05:12 +00:00
|
|
|
gimp_page_selector_get_target (GIMP_PAGE_SELECTOR (pages->selector));
|
2019-06-17 17:11:11 +02:00
|
|
|
|
|
|
|
pages->pages =
|
2022-06-13 11:05:12 +00:00
|
|
|
gimp_page_selector_get_selected_pages (GIMP_PAGE_SELECTOR (pages->selector),
|
2019-06-17 17:11:11 +02:00
|
|
|
&pages->n_pages);
|
|
|
|
|
|
|
|
/* select all if none selected */
|
|
|
|
if (pages->n_pages == 0)
|
|
|
|
{
|
2022-06-13 11:05:12 +00:00
|
|
|
gimp_page_selector_select_all (GIMP_PAGE_SELECTOR (pages->selector));
|
2019-06-17 17:11:11 +02:00
|
|
|
|
|
|
|
pages->pages =
|
2022-06-13 11:05:12 +00:00
|
|
|
gimp_page_selector_get_selected_pages (GIMP_PAGE_SELECTOR (pages->selector),
|
2019-06-17 17:11:11 +02:00
|
|
|
&pages->n_pages);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return run;
|
|
|
|
}
|
2022-06-13 11:05:12 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
tiff_dialog_show_reduced (GtkWidget *toggle,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
gint selectable_pages;
|
|
|
|
gint i, j;
|
|
|
|
|
|
|
|
TiffSelectedPages *pages = (TiffSelectedPages *) data;
|
|
|
|
pages->show_reduced = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (toggle));
|
|
|
|
|
|
|
|
/* Clear current pages from selection */
|
|
|
|
gimp_page_selector_set_n_pages (GIMP_PAGE_SELECTOR (pages->selector), 0);
|
|
|
|
/* Jump back to start of the TIFF file */
|
|
|
|
TIFFSetDirectory (pages->tif, 0);
|
|
|
|
|
|
|
|
selectable_pages = pages->n_filtered_pages;
|
|
|
|
if (pages->show_reduced)
|
|
|
|
selectable_pages = pages->n_reducedimage_pages;
|
|
|
|
|
|
|
|
gimp_page_selector_set_n_pages (GIMP_PAGE_SELECTOR (pages->selector),
|
|
|
|
selectable_pages);
|
|
|
|
|
|
|
|
for (i = 0, j = 0; i < pages->n_pages && j < selectable_pages; i++)
|
|
|
|
{
|
|
|
|
if ((pages->show_reduced && pages->filtered_pages[i] != TIFF_MISC_THUMBNAIL) ||
|
|
|
|
(! pages->show_reduced && pages->filtered_pages[i] > TIFF_MISC_THUMBNAIL))
|
|
|
|
{
|
|
|
|
const gchar *name = tiff_get_page_name (pages->tif);
|
|
|
|
|
|
|
|
if (name)
|
|
|
|
gimp_page_selector_set_page_label (GIMP_PAGE_SELECTOR (pages->selector),
|
|
|
|
j, name);
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
|
|
|
|
TIFFReadDirectory (pages->tif);
|
|
|
|
}
|
2023-05-20 18:40:41 +02:00
|
|
|
}
|