Initial checkin of Pika from heckimp

This commit is contained in:
2023-09-25 15:35:21 -07:00
commit 891e999216
6761 changed files with 5240685 additions and 0 deletions

View File

@ -0,0 +1,579 @@
/* tiff loading for PIKA
* -Peter Mattis
*
* The TIFF loading code has been completely revamped by Nick Lamb
* njl195@zepler.org.uk -- 18 May 1998
* And it now gains support for tiles (and doubtless a zillion bugs)
* njl195@zepler.org.uk -- 12 June 1999
* LZW patent fuss continues :(
* njl195@zepler.org.uk -- 20 April 2000
* The code for this filter is based on "tifftopnm" and "pnmtotiff",
* 2 programs that are a part of the netpbm package.
* khk@khk.net -- 13 May 2000
* Added support for ICCPROFILE tiff tag. If this tag is present in a
* TIFF file, then a parasite is created and vice versa.
* peter@kirchgessner.net -- 29 Oct 2002
* Progress bar only when run interactive
* Added support for layer offsets - pablo.dangelo@web.de -- 7 Jan 2004
* Honor EXTRASAMPLES tag while loading images with alphachannel
* pablo.dangelo@web.de -- 16 Jan 2004
*/
#include "config.h"
#include <errno.h>
#include <string.h>
#include <tiffio.h>
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "file-tiff-io.h"
static gboolean tiff_file_size_error = FALSE;
typedef struct
{
GFile *file;
GObject *stream;
GInputStream *input;
GOutputStream *output;
gboolean can_seek;
gchar *buffer;
gsize allocated;
gsize used;
gsize position;
} TiffIO;
static TIFFExtendProc parent_extender;
static void tiff_io_warning (const gchar *module,
const gchar *fmt,
va_list ap) G_GNUC_PRINTF (2, 0);
static void tiff_io_error (const gchar *module,
const gchar *fmt,
va_list ap) G_GNUC_PRINTF (2, 0);
static tsize_t tiff_io_read (thandle_t handle,
tdata_t buffer,
tsize_t size);
static tsize_t tiff_io_write (thandle_t handle,
tdata_t buffer,
tsize_t size);
static toff_t tiff_io_seek (thandle_t handle,
toff_t offset,
gint whence);
static gint tiff_io_close (thandle_t handle);
static toff_t tiff_io_get_file_size (thandle_t handle);
static void register_geotags (TIFF *tif);
static void
register_geotags (TIFF *tif)
{
static gboolean geotifftags_registered = FALSE;
if (geotifftags_registered)
return;
geotifftags_registered = TRUE;
TIFFMergeFieldInfo (tif, geotifftags_fieldinfo, (sizeof (geotifftags_fieldinfo) / sizeof (geotifftags_fieldinfo[0])));
if (parent_extender)
(*parent_extender) (tif);
}
static TiffIO tiff_io = { 0, };
TIFF *
tiff_open (GFile *file,
const gchar *mode,
GError **error)
{
TIFFSetWarningHandler ((TIFFErrorHandler) tiff_io_warning);
TIFFSetErrorHandler ((TIFFErrorHandler) tiff_io_error);
parent_extender = TIFFSetTagExtender (register_geotags);
tiff_io.file = file;
if (! strcmp (mode, "r"))
{
tiff_io.input = G_INPUT_STREAM (g_file_read (file, NULL, error));
if (! tiff_io.input)
return NULL;
tiff_io.stream = G_OBJECT (tiff_io.input);
}
else if(! strcmp (mode, "w") || ! strcmp (mode, "w8"))
{
tiff_io.output = G_OUTPUT_STREAM (g_file_replace (file,
NULL, FALSE,
G_FILE_CREATE_NONE,
NULL, error));
if (! tiff_io.output)
return NULL;
tiff_io.stream = G_OBJECT (tiff_io.output);
}
else if(! strcmp (mode, "a"))
{
GIOStream *iostream = G_IO_STREAM (g_file_open_readwrite (file, NULL,
error));
if (! iostream)
return NULL;
tiff_io.input = g_io_stream_get_input_stream (iostream);
tiff_io.output = g_io_stream_get_output_stream (iostream);
tiff_io.stream = G_OBJECT (iostream);
}
else
{
g_assert_not_reached ();
}
#if 0
#warning FIXME !can_seek code is broken
tiff_io.can_seek = g_seekable_can_seek (G_SEEKABLE (tiff_io.stream));
#endif
tiff_io.can_seek = TRUE;
return TIFFClientOpen ("file-tiff", mode,
(thandle_t) &tiff_io,
tiff_io_read,
tiff_io_write,
tiff_io_seek,
tiff_io_close,
tiff_io_get_file_size,
NULL, NULL);
}
gboolean
tiff_got_file_size_error (void)
{
return tiff_file_size_error;
}
void
tiff_reset_file_size_error (void)
{
tiff_file_size_error = FALSE;
}
static void
tiff_io_warning (const gchar *module,
const gchar *fmt,
va_list ap)
{
gint tag = 0;
/* Between libtiff 3.7.0beta2 and 4.0.0alpha. */
if (! strcmp (fmt, "%s: unknown field with tag %d (0x%x) encountered") ||
/* Before libtiff 3.7.0beta2. */
! strcmp (fmt, "%.1000s: unknown field with tag %d (0x%x) encountered"))
{
va_list ap_test;
G_VA_COPY (ap_test, ap);
va_arg (ap_test, const char *); /* ignore first arg */
tag = va_arg (ap_test, int);
va_end (ap_test);
}
/* for older versions of libtiff? */
else if (! strcmp (fmt, "unknown field with tag %d (0x%x) ignored") ||
/* Since libtiff 4.0.0alpha. */
! strcmp (fmt, "Unknown field with tag %d (0x%x) encountered") ||
/* Since libtiff 4.3.0rc1. */
! strcmp (fmt, "Unknown field with tag %u (0x%x) encountered"))
{
va_list ap_test;
G_VA_COPY (ap_test, ap);
tag = va_arg (ap_test, int);
va_end (ap_test);
}
else if (! strcmp (fmt, "Incorrect value for \"%s\"; tag ignored"))
{
va_list ap_test;
const char *stag;
G_VA_COPY (ap_test, ap);
stag = va_arg (ap_test, const char *);
if (! strcmp (stag, "RichTIFFIPTC"))
{
gchar *msg = g_strdup_vprintf (fmt, ap);
/* This is an error in Adobe products. Just report to stderr. */
g_printerr ("[%s] %s\n", module, msg);
g_free (msg);
return;
}
va_end (ap_test);
}
/* Workaround for: http://bugzilla.gnome.org/show_bug.cgi?id=131975
* Ignore the warnings about unregistered private tags (>= 32768).
*/
if (tag >= 32768)
return;
/* Other unknown fields are only reported to stderr. */
if (tag > 0)
{
gchar *msg = g_strdup_vprintf (fmt, ap);
g_printerr ("%s\n", msg);
g_free (msg);
return;
}
else if (! strcmp (module, "TIFFReadDirectory") &&
! strcmp (fmt,
"Sum of Photometric type-related color channels and ExtraSamples doesn't match SamplesPerPixel."
" Defining non-color channels as ExtraSamples."))
{
/* We will process this issue in our code. Just report to stderr. */
g_printerr ("%s: [%s] %s\n", G_STRFUNC, module, fmt);
return;
}
else if (! strcmp (module, "Fax4Decode") ||
g_str_has_prefix (module, "Fax3Decode"))
{
/* Certain corrupt TIFF Fax images can produce a large amount of
* warnings which can cause PIKA to run out of GDI resources on
* Windows and eventually crash.
* The real problem seems to be that the amount of error console
* messages does not have a limit.
* See e.g. the first page of m1-8110934bb3b18d0e87ccc1ddfc5f0107.tif
* from imagetestsuite. LibTiff does not return -1 from
* ReadScanline, presumably because for fax images it's not
* unreasonable to expect certain lines to fail.
* Let's just only report to stderr in this case. */
gchar *msg = g_strdup_vprintf (fmt, ap);
g_printerr ("LibTiff warning: [%s] %s\n", module, msg);
g_free (msg);
return;
}
g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, ap);
}
static void
tiff_io_error (const gchar *module,
const gchar *fmt,
va_list ap)
{
gchar *msg;
/* Workaround for: http://bugzilla.gnome.org/show_bug.cgi?id=132297
* Ignore the errors related to random access and JPEG compression
*/
if (! strcmp (fmt, "Compression algorithm does not support random access"))
return;
msg = g_strdup_vprintf (fmt, ap);
if (g_strcmp0 (fmt, "Maximum TIFF file size exceeded") == 0)
/* @module in my tests were "TIFFAppendToStrip" but I wonder if
* this same error could not happen with other "modules".
*/
tiff_file_size_error = TRUE;
else
/* Easier for debugging to at least print messages on stderr. */
g_printerr ("LibTiff error: [%s] %s\n", module, msg);
g_log (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, "%s", msg);
g_free (msg);
}
static tsize_t
tiff_io_read (thandle_t handle,
tdata_t buffer,
tsize_t size)
{
TiffIO *io = (TiffIO *) handle;
GError *error = NULL;
gssize read = -1;
if (io->can_seek)
{
gsize bytes_read = 0;
if (! g_input_stream_read_all (io->input,
(void *) buffer, (gsize) size,
&bytes_read,
NULL, &error))
{
g_printerr ("%s", error->message);
g_clear_error (&error);
}
read = bytes_read;
}
else
{
if (io->position + size > io->used)
{
gsize missing;
gsize bytes_read;
missing = io->position + size - io->used;
if (io->used + missing > io->allocated)
{
gchar *new_buffer;
gsize new_size = 1;
gsize needed;
needed = io->used + missing - io->allocated;
while (new_size < io->allocated + needed)
new_size *= 2;
new_buffer = g_try_realloc (io->buffer, new_size);
if (! new_buffer)
return -1;
io->buffer = new_buffer;
io->allocated = new_size;
}
if (! g_input_stream_read_all (io->input,
(void *) (io->buffer + io->used),
missing,
&bytes_read, NULL, &error))
{
g_printerr ("%s", error->message);
g_clear_error (&error);
}
io->used += bytes_read;
}
g_assert (io->position + size <= io->used);
memcpy (buffer, io->buffer + io->position, size);
io->position += size;
read = size;
}
return (tsize_t) read;
}
static tsize_t
tiff_io_write (thandle_t handle,
tdata_t buffer,
tsize_t size)
{
TiffIO *io = (TiffIO *) handle;
GError *error = NULL;
gssize written = -1;
if (io->can_seek)
{
gsize bytes_written = 0;
if (! g_output_stream_write_all (io->output,
(void *) buffer, (gsize) size,
&bytes_written,
NULL, &error))
{
g_printerr ("%s", error->message);
g_clear_error (&error);
}
written = bytes_written;
}
else
{
if (io->position + size > io->allocated)
{
gchar *new_buffer;
gsize new_size;
new_size = io->position + size;
new_buffer = g_try_realloc (io->buffer, new_size);
if (! new_buffer)
return -1;
io->buffer = new_buffer;
io->allocated = new_size;
}
g_assert (io->position + size <= io->allocated);
memcpy (io->buffer + io->position, buffer, size);
io->position += size;
io->used = MAX (io->used, io->position);
written = size;
}
return (tsize_t) written;
}
static GSeekType
lseek_to_seek_type (gint whence)
{
switch (whence)
{
default:
case SEEK_SET:
return G_SEEK_SET;
case SEEK_CUR:
return G_SEEK_CUR;
case SEEK_END:
return G_SEEK_END;
}
}
static toff_t
tiff_io_seek (thandle_t handle,
toff_t offset,
gint whence)
{
TiffIO *io = (TiffIO *) handle;
GError *error = NULL;
gboolean sought = FALSE;
goffset position = -1;
if (io->can_seek)
{
sought = g_seekable_seek (G_SEEKABLE (io->stream),
(goffset) offset, lseek_to_seek_type (whence),
NULL, &error);
if (sought)
{
position = g_seekable_tell (G_SEEKABLE (io->stream));
}
else
{
g_printerr ("%s", error->message);
g_clear_error (&error);
}
}
else
{
switch (whence)
{
default:
case SEEK_SET:
if (offset <= io->used)
position = io->position = offset;
break;
case SEEK_CUR:
if (io->position + offset <= io->used)
position = io->position += offset;
break;
case G_SEEK_END:
if (io->used + offset <= io->used)
position = io->position = io->used + offset;
break;
}
}
return (toff_t) position;
}
static gint
tiff_io_close (thandle_t handle)
{
TiffIO *io = (TiffIO *) handle;
GError *error = NULL;
gboolean closed = FALSE;
if (io->input && ! io->output)
{
closed = g_input_stream_close (io->input, NULL, &error);
}
else
{
if (! io->can_seek && io->buffer && io->allocated)
{
if (! g_output_stream_write_all (io->output,
(void *) io->buffer,
io->allocated,
NULL, NULL, &error))
{
g_printerr ("%s", error->message);
g_clear_error (&error);
}
}
if (io->input)
{
closed = g_io_stream_close (G_IO_STREAM (io->stream), NULL, &error);
}
else
{
closed = g_output_stream_close (io->output, NULL, &error);
}
}
if (! closed)
{
g_printerr ("%s", error->message);
g_clear_error (&error);
}
g_object_unref (io->stream);
io->stream = NULL;
io->input = NULL;
io->output = NULL;
g_free (io->buffer);
io->buffer = NULL;
io->allocated = 0;
io->used = 0;
io->position = 0;
return closed ? 0 : -1;
}
static toff_t
tiff_io_get_file_size (thandle_t handle)
{
TiffIO *io = (TiffIO *) handle;
GError *error = NULL;
GFileInfo *info;
goffset size = 0;
info = g_file_query_info (io->file,
G_FILE_ATTRIBUTE_STANDARD_SIZE,
G_FILE_QUERY_INFO_NONE,
NULL, &error);
if (! info)
{
g_printerr ("%s", error->message);
g_clear_error (&error);
}
else
{
size = g_file_info_get_size (info);
g_object_unref (info);
}
return (toff_t) size;
}

View File

@ -0,0 +1,51 @@
/* tiff loading for PIKA
* -Peter Mattis
*
* The TIFF loading code has been completely revamped by Nick Lamb
* njl195@zepler.org.uk -- 18 May 1998
* And it now gains support for tiles (and doubtless a zillion bugs)
* njl195@zepler.org.uk -- 12 June 1999
* LZW patent fuss continues :(
* njl195@zepler.org.uk -- 20 April 2000
* The code for this filter is based on "tifftopnm" and "pnmtotiff",
* 2 programs that are a part of the netpbm package.
* khk@khk.net -- 13 May 2000
* Added support for ICCPROFILE tiff tag. If this tag is present in a
* TIFF file, then a parasite is created and vice versa.
* peter@kirchgessner.net -- 29 Oct 2002
* Progress bar only when run interactive
* Added support for layer offsets - pablo.dangelo@web.de -- 7 Jan 2004
* Honor EXTRASAMPLES tag while loading images with alphachannel
* pablo.dangelo@web.de -- 16 Jan 2004
*/
#ifndef __FILE_TIFF_IO_H__
#define __FILE_TIFF_IO_H__
/* Adding support for GeoTIFF Tags */
#define GEOTIFF_MODELPIXELSCALE 33550
#define GEOTIFF_MODELTIEPOINT 33922
#define GEOTIFF_MODELTRANSFORMATION 34264
#define GEOTIFF_KEYDIRECTORY 34735
#define GEOTIFF_DOUBLEPARAMS 34736
#define GEOTIFF_ASCIIPARAMS 34737
static const TIFFFieldInfo geotifftags_fieldinfo[] = {
{ GEOTIFF_MODELPIXELSCALE, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, "GeoModelPixelScale" },
{ GEOTIFF_MODELTIEPOINT, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, "GeoTiePoints" },
{ GEOTIFF_MODELTRANSFORMATION, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, "GeoModelTransformation" },
{ GEOTIFF_KEYDIRECTORY, -1, -1, TIFF_SHORT, FIELD_CUSTOM, TRUE, TRUE, "GeoKeyDirectory" },
{ GEOTIFF_DOUBLEPARAMS, -1, -1, TIFF_DOUBLE, FIELD_CUSTOM, TRUE, TRUE, "GeoDoubleParams" },
{ GEOTIFF_ASCIIPARAMS, -1, -1, TIFF_ASCII, FIELD_CUSTOM, TRUE, FALSE, "GeoAsciiParams" }
};
TIFF * tiff_open (GFile *file,
const gchar *mode,
GError **error);
gboolean tiff_got_file_size_error (void);
void tiff_reset_file_size_error (void);
#endif /* __FILE_TIFF_IO_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,58 @@
/* tiff loading for PIKA
* -Peter Mattis
*
* The TIFF loading code has been completely revamped by Nick Lamb
* njl195@zepler.org.uk -- 18 May 1998
* And it now gains support for tiles (and doubtless a zillion bugs)
* njl195@zepler.org.uk -- 12 June 1999
* LZW patent fuss continues :(
* njl195@zepler.org.uk -- 20 April 2000
* The code for this filter is based on "tifftopnm" and "pnmtotiff",
* 2 programs that are a part of the netpbm package.
* khk@khk.net -- 13 May 2000
* Added support for ICCPROFILE tiff tag. If this tag is present in a
* TIFF file, then a parasite is created and vice versa.
* peter@kirchgessner.net -- 29 Oct 2002
* Progress bar only when run interactive
* Added support for layer offsets - pablo.dangelo@web.de -- 7 Jan 2004
* Honor EXTRASAMPLES tag while loading images with alphachannel
* pablo.dangelo@web.de -- 16 Jan 2004
*/
#ifndef __FILE_TIFF_LOAD_H__
#define __FILE_TIFF_LOAD_H__
#define LOAD_PROC "file-tiff-load"
typedef enum
{
TIFF_REDUCEDFILE = -2,
TIFF_MISC_THUMBNAIL = -1
} TIFF_THUMBNAIL_TYPE;
typedef struct
{
TIFF *tif;
gint o_pages;
gint n_pages;
gint *pages;
gint *filtered_pages; /* thumbnail is marked as < 0 */
gint n_filtered_pages;
gint n_reducedimage_pages;
GtkWidget *selector;
PikaPageSelectorTarget target;
gboolean keep_empty_space;
gboolean show_reduced;
} TiffSelectedPages;
PikaPDBStatusType load_image (GFile *file,
PikaRunMode run_mode,
PikaImage **image,
gboolean *resolution_loaded,
gboolean *profile_loaded,
gboolean *ps_metadata_loaded,
GError **error);
#endif /* __FILE_TIFF_LOAD_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
/* tiff saving for PIKA
* -Peter Mattis
*
* The TIFF loading code has been completely revamped by Nick Lamb
* njl195@zepler.org.uk -- 18 May 1998
* And it now gains support for tiles (and doubtless a zillion bugs)
* njl195@zepler.org.uk -- 12 June 1999
* LZW patent fuss continues :(
* njl195@zepler.org.uk -- 20 April 2000
* The code for this filter is based on "tifftopnm" and "pnmtotiff",
* 2 programs that are a part of the netpbm package.
* khk@khk.net -- 13 May 2000
* Added support for ICCPROFILE tiff tag. If this tag is present in a
* TIFF file, then a parasite is created and vice versa.
* peter@kirchgessner.net -- 29 Oct 2002
* Progress bar only when run interactive
* Added support for layer offsets - pablo.dangelo@web.de -- 7 Jan 2004
* Honor EXTRASAMPLES tag while loading images with alphachannel
* pablo.dangelo@web.de -- 16 Jan 2004
*/
#ifndef __FILE_TIFF_SAVE_H__
#define __FILE_TIFF_SAVE_H__
gboolean save_image (GFile *file,
PikaImage *image,
PikaImage *orig_image,
GObject *config,
PikaMetadata *metadata,
GError **error);
gboolean save_dialog (PikaImage *image,
PikaProcedure *procedure,
GObject *config,
gboolean has_alpha,
gboolean is_monochrome,
gboolean is_indexed,
gboolean is_multi_layer,
gboolean classic_tiff_failed);
#endif /* __FILE_TIFF_SAVE_H__ */

View File

@ -0,0 +1,570 @@
/* tiff loading for PIKA
* -Peter Mattis
*
* The TIFF loading code has been completely revamped by Nick Lamb
* njl195@zepler.org.uk -- 18 May 1998
* And it now gains support for tiles (and doubtless a zillion bugs)
* njl195@zepler.org.uk -- 12 June 1999
* LZW patent fuss continues :(
* njl195@zepler.org.uk -- 20 April 2000
* The code for this filter is based on "tifftopnm" and "pnmtotiff",
* 2 programs that are a part of the netpbm package.
* khk@khk.net -- 13 May 2000
* Added support for ICCPROFILE tiff tag. If this tag is present in a
* TIFF file, then a parasite is created and vice versa.
* peter@kirchgessner.net -- 29 Oct 2002
* Progress bar only when run interactive
* Added support for layer offsets - pablo.dangelo@web.de -- 7 Jan 2004
* Honor EXTRASAMPLES tag while loading images with alphachannel
* pablo.dangelo@web.de -- 16 Jan 2004
*/
/*
* 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.
*/
#include "config.h"
#include <tiffio.h>
#include <libpika/pika.h>
#include <libpika/pikaui.h>
#include "file-tiff.h"
#include "file-tiff-io.h"
#include "file-tiff-load.h"
#include "file-tiff-save.h"
#include "libpika/stdplugins-intl.h"
#define SAVE_PROC "file-tiff-save"
#define PLUG_IN_BINARY "file-tiff"
typedef struct _Tiff Tiff;
typedef struct _TiffClass TiffClass;
struct _Tiff
{
PikaPlugIn parent_instance;
};
struct _TiffClass
{
PikaPlugInClass parent_class;
};
#define TIFF_TYPE (tiff_get_type ())
#define TIFF (obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TIFF_TYPE, Tiff))
GType tiff_get_type (void) G_GNUC_CONST;
static GList * tiff_query_procedures (PikaPlugIn *plug_in);
static PikaProcedure * tiff_create_procedure (PikaPlugIn *plug_in,
const gchar *name);
static PikaValueArray * tiff_load (PikaProcedure *procedure,
PikaRunMode run_mode,
GFile *file,
const PikaValueArray *args,
gpointer run_data);
static PikaValueArray * tiff_save (PikaProcedure *procedure,
PikaRunMode run_mode,
PikaImage *image,
gint n_drawables,
PikaDrawable **drawables,
GFile *file,
const PikaValueArray *args,
gpointer run_data);
static PikaPDBStatusType tiff_save_rec (PikaProcedure *procedure,
PikaRunMode run_mode,
PikaImage *orig_image,
gint n_orig_drawables,
PikaDrawable **orig_drawables,
GFile *file,
PikaProcedureConfig *config,
PikaMetadata *metadata,
gboolean retried,
GError **error);
static gboolean image_is_monochrome (PikaImage *image);
static gboolean image_is_multi_layer (PikaImage *image);
G_DEFINE_TYPE (Tiff, tiff, PIKA_TYPE_PLUG_IN)
PIKA_MAIN (TIFF_TYPE)
DEFINE_STD_SET_I18N
static void
tiff_class_init (TiffClass *klass)
{
PikaPlugInClass *plug_in_class = PIKA_PLUG_IN_CLASS (klass);
plug_in_class->query_procedures = tiff_query_procedures;
plug_in_class->create_procedure = tiff_create_procedure;
plug_in_class->set_i18n = STD_SET_I18N;
}
static void
tiff_init (Tiff *tiff)
{
}
static GList *
tiff_query_procedures (PikaPlugIn *plug_in)
{
GList *list = NULL;
list = g_list_append (list, g_strdup (LOAD_PROC));
list = g_list_append (list, g_strdup (SAVE_PROC));
return list;
}
static PikaProcedure *
tiff_create_procedure (PikaPlugIn *plug_in,
const gchar *name)
{
PikaProcedure *procedure = NULL;
if (! strcmp (name, LOAD_PROC))
{
procedure = pika_load_procedure_new (plug_in, name,
PIKA_PDB_PROC_TYPE_PLUGIN,
tiff_load, NULL, NULL);
pika_procedure_set_menu_label (procedure, _("TIFF or BigTIFF image"));
pika_procedure_set_documentation (procedure,
"Loads files of the TIFF and BigTIFF file formats",
"Loads files of the Tag Image File Format (TIFF) and "
"its 64-bit offsets variant (BigTIFF)",
name);
pika_procedure_set_attribution (procedure,
"Spencer Kimball, Peter Mattis & Nick Lamb",
"Nick Lamb <njl195@zepler.org.uk>",
"1995-1996,1998-2003");
pika_file_procedure_set_handles_remote (PIKA_FILE_PROCEDURE (procedure),
TRUE);
pika_file_procedure_set_mime_types (PIKA_FILE_PROCEDURE (procedure),
"image/tiff");
pika_file_procedure_set_extensions (PIKA_FILE_PROCEDURE (procedure),
"tif,tiff");
pika_file_procedure_set_magics (PIKA_FILE_PROCEDURE (procedure),
"0,string,II*\\0,0,string,MM\\0*");
}
else if (! strcmp (name, SAVE_PROC))
{
procedure = pika_save_procedure_new (plug_in, name,
PIKA_PDB_PROC_TYPE_PLUGIN,
tiff_save, NULL, NULL);
pika_procedure_set_image_types (procedure, "*");
pika_procedure_set_menu_label (procedure, _("TIFF or BigTIFF image"));
pika_procedure_set_documentation (procedure,
"Exports files in the TIFF or BigTIFF file formats",
"Exports files in the Tag Image File Format (TIFF) or "
"its 64-bit offsets variant (BigTIFF) able to support "
"much bigger file sizes",
name);
pika_procedure_set_attribution (procedure,
"Spencer Kimball & Peter Mattis",
"Spencer Kimball & Peter Mattis",
"1995-1996,2000-2003");
pika_file_procedure_set_handles_remote (PIKA_FILE_PROCEDURE (procedure),
TRUE);
pika_file_procedure_set_format_name (PIKA_FILE_PROCEDURE (procedure),
_("TIFF"));
pika_file_procedure_set_mime_types (PIKA_FILE_PROCEDURE (procedure),
"image/tiff");
pika_file_procedure_set_extensions (PIKA_FILE_PROCEDURE (procedure),
"tif,tiff");
PIKA_PROC_ARG_BOOLEAN (procedure, "bigtiff",
_("Export in _BigTIFF variant file format"),
_("The BigTIFF variant file format uses 64-bit offsets, "
"hence supporting over 4GiB files and bigger"),
FALSE,
G_PARAM_READWRITE);
PIKA_PROC_ARG_INT (procedure, "compression",
_("Co_mpression"),
_("Compression type: { NONE (0), LZW (1), PACKBITS (2), "
"DEFLATE (3), JPEG (4), CCITT G3 Fax (5), "
"CCITT G4 Fax (6) }"),
0, 6, 0,
G_PARAM_READWRITE);
PIKA_PROC_ARG_BOOLEAN (procedure, "save-transparent-pixels",
_("Save color _values from transparent pixels"),
_("Keep the color data masked by an alpha channel "
"intact (do not store premultiplied components)"),
TRUE,
G_PARAM_READWRITE);
PIKA_PROC_ARG_BOOLEAN (procedure, "cmyk",
_("Export as CMY_K"),
_("Create a CMYK TIFF image using the soft-proofing color profile"),
FALSE,
G_PARAM_READWRITE);
PIKA_PROC_AUX_ARG_BOOLEAN (procedure, "save-layers",
_("Save La_yers"),
_("Save Layers"),
TRUE,
G_PARAM_READWRITE);
PIKA_PROC_AUX_ARG_BOOLEAN (procedure, "crop-layers",
_("Crop L_ayers"),
_("Crop Layers"),
TRUE,
G_PARAM_READWRITE);
PIKA_PROC_AUX_ARG_BOOLEAN (procedure, "save-geotiff",
_("Save _GeoTIFF data"),
_("Save GeoTIFF data"),
TRUE,
G_PARAM_READWRITE);
pika_save_procedure_set_support_exif (PIKA_SAVE_PROCEDURE (procedure), TRUE);
pika_save_procedure_set_support_iptc (PIKA_SAVE_PROCEDURE (procedure), TRUE);
pika_save_procedure_set_support_xmp (PIKA_SAVE_PROCEDURE (procedure), TRUE);
#ifdef TIFFTAG_ICCPROFILE
pika_save_procedure_set_support_profile (PIKA_SAVE_PROCEDURE (procedure), TRUE);
#endif
pika_save_procedure_set_support_thumbnail (PIKA_SAVE_PROCEDURE (procedure), TRUE);
pika_save_procedure_set_support_comment (PIKA_SAVE_PROCEDURE (procedure), TRUE);
}
return procedure;
}
static PikaValueArray *
tiff_load (PikaProcedure *procedure,
PikaRunMode run_mode,
GFile *file,
const PikaValueArray *args,
gpointer run_data)
{
PikaValueArray *return_vals;
PikaPDBStatusType status;
PikaImage *image = NULL;
gboolean resolution_loaded = FALSE;
gboolean profile_loaded = FALSE;
gboolean ps_metadata_loaded = FALSE;
PikaMetadata *metadata;
GError *error = NULL;
gegl_init (NULL, NULL);
if (run_mode == PIKA_RUN_INTERACTIVE)
pika_ui_init (PLUG_IN_BINARY);
status = load_image (file, run_mode, &image,
&resolution_loaded,
&profile_loaded,
&ps_metadata_loaded,
&error);
if (!image)
return pika_procedure_new_return_values (procedure, status, error);
metadata = pika_image_metadata_load_prepare (image,
"image/tiff",
file, NULL);
if (metadata)
{
PikaMetadataLoadFlags flags = PIKA_METADATA_LOAD_ALL;
if (resolution_loaded)
flags &= ~PIKA_METADATA_LOAD_RESOLUTION;
if (profile_loaded)
flags &= ~PIKA_METADATA_LOAD_COLORSPACE;
pika_image_metadata_load_finish (image, "image/tiff",
metadata, flags);
g_object_unref (metadata);
}
return_vals = pika_procedure_new_return_values (procedure,
PIKA_PDB_SUCCESS,
NULL);
PIKA_VALUES_SET_IMAGE (return_vals, 1, image);
return return_vals;
}
static PikaValueArray *
tiff_save (PikaProcedure *procedure,
PikaRunMode run_mode,
PikaImage *image,
gint n_drawables,
PikaDrawable **drawables,
GFile *file,
const PikaValueArray *args,
gpointer run_data)
{
PikaProcedureConfig *config;
PikaMetadata *metadata;
GError *error = NULL;
PikaPDBStatusType status = PIKA_PDB_SUCCESS;
gegl_init (NULL, NULL);
config = pika_procedure_create_config (procedure);
metadata = pika_procedure_config_begin_export (config, image, run_mode,
args, "image/tiff");
switch (run_mode)
{
case PIKA_RUN_INTERACTIVE:
case PIKA_RUN_WITH_LAST_VALS:
pika_ui_init (PLUG_IN_BINARY);
break;
default:
break;
}
status = tiff_save_rec (procedure, run_mode, image,
n_drawables, drawables,
file, config, metadata, FALSE, &error);
pika_procedure_config_end_export (config, image, file, status);
g_object_unref (config);
return pika_procedure_new_return_values (procedure, status, error);
}
static PikaPDBStatusType
tiff_save_rec (PikaProcedure *procedure,
PikaRunMode run_mode,
PikaImage *orig_image,
gint n_orig_drawables,
PikaDrawable **orig_drawables,
GFile *file,
PikaProcedureConfig *config,
PikaMetadata *metadata,
gboolean retried,
GError **error)
{
PikaImage *image = orig_image;
PikaDrawable **drawables = orig_drawables;
gint n_drawables = n_orig_drawables;
PikaPDBStatusType status = PIKA_PDB_SUCCESS;
PikaExportReturn export = PIKA_EXPORT_CANCEL;
gboolean bigtiff = FALSE;
if (run_mode == PIKA_RUN_INTERACTIVE)
{
if (! save_dialog (orig_image, procedure, G_OBJECT (config),
n_drawables == 1 ? pika_drawable_has_alpha (drawables[0]) : TRUE,
image_is_monochrome (orig_image),
pika_image_get_base_type (orig_image) == PIKA_INDEXED,
image_is_multi_layer (orig_image),
retried))
{
return PIKA_PDB_CANCEL;
}
}
switch (run_mode)
{
case PIKA_RUN_INTERACTIVE:
case PIKA_RUN_WITH_LAST_VALS:
{
PikaExportCapabilities capabilities;
PikaCompression compression;
gboolean save_layers;
gboolean crop_layers;
g_object_get (config,
"bigtiff", &bigtiff,
"compression", &compression,
"save-layers", &save_layers,
"crop-layers", &crop_layers,
NULL);
if (compression == PIKA_COMPRESSION_CCITTFAX3 ||
compression == PIKA_COMPRESSION_CCITTFAX4)
{
/* G3/G4 are fax compressions. They only support
* monochrome images without alpha support.
*/
capabilities = PIKA_EXPORT_CAN_HANDLE_INDEXED;
}
else
{
capabilities = (PIKA_EXPORT_CAN_HANDLE_RGB |
PIKA_EXPORT_CAN_HANDLE_GRAY |
PIKA_EXPORT_CAN_HANDLE_INDEXED |
PIKA_EXPORT_CAN_HANDLE_ALPHA);
}
if (save_layers && image_is_multi_layer (orig_image))
{
capabilities |= PIKA_EXPORT_CAN_HANDLE_LAYERS;
if (crop_layers)
capabilities |= PIKA_EXPORT_NEEDS_CROP;
}
export = pika_export_image (&image, &n_drawables, &drawables, "TIFF",
capabilities);
if (export == PIKA_EXPORT_CANCEL)
return PIKA_PDB_CANCEL;
}
break;
default:
break;
}
#if 0
/* FIXME */
if (n_drawables != 1 && tsvals.save_layers)
{
g_set_error (&error, G_FILE_ERROR, 0,
_("\"Save layers\" option not set while trying to export multiple layers."));
status = PIKA_PDB_CALLING_ERROR;
}
#endif
if (status == PIKA_PDB_SUCCESS)
{
if (! save_image (file, image, orig_image, G_OBJECT (config),
metadata, error))
status = PIKA_PDB_EXECUTION_ERROR;
}
if (export == PIKA_EXPORT_EXPORT)
{
pika_image_delete (image);
g_free (drawables);
}
if (status == PIKA_PDB_EXECUTION_ERROR &&
run_mode == PIKA_RUN_INTERACTIVE &&
! retried && ! bigtiff && tiff_got_file_size_error ())
{
/* Retrying but just once, when the save failed because we exceeded
* TIFF max size, to propose BigTIFF instead. */
tiff_reset_file_size_error ();
g_clear_error (error);
return tiff_save_rec (procedure, run_mode,
orig_image, n_orig_drawables, orig_drawables,
file, config, metadata, TRUE, error);
}
return status;
}
static gboolean
image_is_monochrome (PikaImage *image)
{
guchar *colors;
gint num_colors;
gboolean monochrome = FALSE;
g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE);
colors = pika_image_get_colormap (image, NULL, &num_colors);
if (colors)
{
if (num_colors == 2 || num_colors == 1)
{
const guchar bw_map[] = { 0, 0, 0, 255, 255, 255 };
const guchar wb_map[] = { 255, 255, 255, 0, 0, 0 };
if (memcmp (colors, bw_map, 3 * num_colors) == 0 ||
memcmp (colors, wb_map, 3 * num_colors) == 0)
{
monochrome = TRUE;
}
}
g_free (colors);
}
return monochrome;
}
static gboolean
image_is_multi_layer (PikaImage *image)
{
gint32 n_layers;
g_free (pika_image_get_layers (image, &n_layers));
return (n_layers > 1);
}
gint
pika_compression_to_tiff_compression (PikaCompression compression)
{
switch (compression)
{
case PIKA_COMPRESSION_NONE: return COMPRESSION_NONE;
case PIKA_COMPRESSION_LZW: return COMPRESSION_LZW;
case PIKA_COMPRESSION_PACKBITS: return COMPRESSION_PACKBITS;
case PIKA_COMPRESSION_ADOBE_DEFLATE: return COMPRESSION_ADOBE_DEFLATE;
case PIKA_COMPRESSION_JPEG: return COMPRESSION_JPEG;
case PIKA_COMPRESSION_CCITTFAX3: return COMPRESSION_CCITTFAX3;
case PIKA_COMPRESSION_CCITTFAX4: return COMPRESSION_CCITTFAX4;
}
return COMPRESSION_NONE;
}
PikaCompression
tiff_compression_to_pika_compression (gint compression)
{
switch (compression)
{
case COMPRESSION_NONE: return PIKA_COMPRESSION_NONE;
case COMPRESSION_LZW: return PIKA_COMPRESSION_LZW;
case COMPRESSION_PACKBITS: return PIKA_COMPRESSION_PACKBITS;
case COMPRESSION_DEFLATE: return PIKA_COMPRESSION_ADOBE_DEFLATE;
case COMPRESSION_ADOBE_DEFLATE: return PIKA_COMPRESSION_ADOBE_DEFLATE;
case COMPRESSION_OJPEG: return PIKA_COMPRESSION_JPEG;
case COMPRESSION_JPEG: return PIKA_COMPRESSION_JPEG;
case COMPRESSION_CCITTFAX3: return PIKA_COMPRESSION_CCITTFAX3;
case COMPRESSION_CCITTFAX4: return PIKA_COMPRESSION_CCITTFAX4;
}
return PIKA_COMPRESSION_NONE;
}

View File

@ -0,0 +1,25 @@
/* tiff for PIKA
* -Peter Mattis
*/
#ifndef __FILE_TIFF_H__
#define __FILE_TIFF_H__
typedef enum
{
PIKA_COMPRESSION_NONE,
PIKA_COMPRESSION_LZW,
PIKA_COMPRESSION_PACKBITS,
PIKA_COMPRESSION_ADOBE_DEFLATE,
PIKA_COMPRESSION_JPEG,
PIKA_COMPRESSION_CCITTFAX3,
PIKA_COMPRESSION_CCITTFAX4
} PikaCompression;
gint pika_compression_to_tiff_compression (PikaCompression compression);
PikaCompression tiff_compression_to_pika_compression (gint compression);
#endif /* __FILE_TIFF_H__ */

View File

@ -0,0 +1,33 @@
plugin_name = 'file-tiff'
plugin_sources = [
'file-tiff-io.c',
'file-tiff-save.c',
'file-tiff.c',
'file-tiff-load.c',
]
if platform_windows
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
'--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
'--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
'--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
],
)
endif
executable(plugin_name,
plugin_sources,
dependencies: [
libpikaui_dep,
gexiv2,
libtiff,
],
install: true,
install_dir: pikaplugindir / 'plug-ins' / plugin_name,
)