1997-11-25 06:05:25 +08:00
|
|
|
/* tiff loading and saving for the GIMP
|
|
|
|
* -Peter Mattis
|
1998-05-18 08:54:11 +08:00
|
|
|
* The TIFF loading code has been completely revamped by Nick Lamb
|
|
|
|
* njl195@zepler.org.uk -- 18 May 1998
|
1999-09-18 06:28:25 +08:00
|
|
|
* And it now gains support for tiles (and doubtless a zillion bugs)
|
|
|
|
* njl195@zepler.org.uk -- 12 June 1999
|
2000-04-20 12:38:31 +08:00
|
|
|
* LZW patent fuss continues :(
|
|
|
|
* njl195@zepler.org.uk -- 20 April 2000
|
1997-11-25 06:05:25 +08: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 09:07:13 +08:00
|
|
|
* 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.
|
1997-11-25 06:05:25 +08: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.
|
|
|
|
*/
|
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
#include "config.h"
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <tiffio.h>
|
2000-01-09 04:00:10 +08:00
|
|
|
|
|
|
|
#include <libgimp/gimp.h>
|
|
|
|
#include <libgimp/gimpui.h>
|
2000-01-26 01:46:56 +08:00
|
|
|
|
2000-01-09 14:02:20 +08:00
|
|
|
#include "libgimp/stdplugins-intl.h"
|
1998-10-12 06:50:03 +08:00
|
|
|
|
2000-05-02 04:22:55 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
gint compression;
|
|
|
|
gint fillorder;
|
|
|
|
} TiffSaveVals;
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
gint run;
|
|
|
|
} TiffSaveInterface;
|
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
gint32 ID;
|
2000-08-22 09:26:57 +08:00
|
|
|
GimpDrawable *drawable;
|
|
|
|
GimpPixelRgn pixel_rgn;
|
2000-01-26 01:46:56 +08:00
|
|
|
guchar *pixels;
|
|
|
|
guchar *pixel;
|
1998-11-09 10:05:24 +08:00
|
|
|
} channel_data;
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
/* Declare some local functions.
|
|
|
|
*/
|
2000-01-26 01:46:56 +08:00
|
|
|
static void query (void);
|
|
|
|
static void run (gchar *name,
|
|
|
|
gint nparams,
|
2000-08-22 09:26:57 +08:00
|
|
|
GimpParam *param,
|
2000-01-26 01:46:56 +08:00
|
|
|
gint *nreturn_vals,
|
2000-08-22 09:26:57 +08:00
|
|
|
GimpParam **return_vals);
|
2000-01-26 01:46:56 +08:00
|
|
|
|
|
|
|
static gint32 load_image (gchar *filename);
|
|
|
|
|
|
|
|
static void load_rgba (TIFF *tif,
|
|
|
|
channel_data *channel);
|
|
|
|
static void load_lines (TIFF *tif,
|
|
|
|
channel_data *channel,
|
|
|
|
gushort bps,
|
|
|
|
gushort photomet,
|
|
|
|
gint alpha,
|
|
|
|
gint extra);
|
|
|
|
static void load_tiles (TIFF *tif,
|
|
|
|
channel_data *channel,
|
|
|
|
gushort bps,
|
|
|
|
gushort photomet,
|
|
|
|
gint alpha,
|
|
|
|
gint extra);
|
|
|
|
|
|
|
|
static void read_separate (guchar *source,
|
|
|
|
channel_data *channel,
|
|
|
|
gushort bps,
|
|
|
|
gushort photomet,
|
|
|
|
gint startcol,
|
|
|
|
gint startrow,
|
|
|
|
gint rows,
|
|
|
|
gint cols,
|
|
|
|
gint alpha,
|
|
|
|
gint extra,
|
|
|
|
gint sample);
|
|
|
|
static void read_16bit (guchar *source,
|
|
|
|
channel_data *channel,
|
|
|
|
gushort photomet,
|
|
|
|
gint startcol,
|
|
|
|
gint startrow,
|
|
|
|
gint rows,
|
|
|
|
gint cols,
|
|
|
|
gint alpha,
|
2000-10-26 07:49:30 +08:00
|
|
|
gint extra,
|
|
|
|
gint align);
|
2000-01-26 01:46:56 +08:00
|
|
|
static void read_8bit (guchar *source,
|
|
|
|
channel_data *channel,
|
|
|
|
gushort photomet,
|
|
|
|
gint startcol,
|
|
|
|
gint startrow,
|
|
|
|
gint rows,
|
|
|
|
gint cols,
|
|
|
|
gint alpha,
|
2000-10-26 07:49:30 +08:00
|
|
|
gint extra,
|
|
|
|
gint align);
|
2000-01-26 01:46:56 +08:00
|
|
|
static void read_default (guchar *source,
|
|
|
|
channel_data *channel,
|
|
|
|
gushort bps,
|
|
|
|
gushort photomet,
|
|
|
|
gint startcol,
|
|
|
|
gint startrow,
|
|
|
|
gint rows,
|
|
|
|
gint cols,
|
|
|
|
gint alpha,
|
2000-10-26 07:49:30 +08:00
|
|
|
gint extra,
|
|
|
|
gint align);
|
2000-01-26 01:46:56 +08:00
|
|
|
|
|
|
|
static gint save_image (gchar *filename,
|
|
|
|
gint32 image,
|
|
|
|
gint32 drawable,
|
|
|
|
gint32 orig_image);
|
|
|
|
|
|
|
|
static gint save_dialog (void);
|
|
|
|
|
|
|
|
static void save_ok_callback (GtkWidget *widget,
|
|
|
|
gpointer data);
|
|
|
|
static void comment_entry_callback (GtkWidget *widget,
|
|
|
|
gpointer data);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-10-12 06:50:03 +08:00
|
|
|
#define DEFAULT_COMMENT "Created with The GIMP"
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-08-22 09:26:57 +08:00
|
|
|
GimpPlugInInfo PLUG_IN_INFO =
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-01-26 01:46:56 +08:00
|
|
|
NULL, /* init_proc */
|
|
|
|
NULL, /* quit_proc */
|
|
|
|
query, /* query_proc */
|
|
|
|
run, /* run_proc */
|
1997-11-25 06:05:25 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static TiffSaveVals tsvals =
|
|
|
|
{
|
2000-04-20 12:38:31 +08:00
|
|
|
COMPRESSION_NONE, /* compression */
|
1997-11-25 06:05:25 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static TiffSaveInterface tsint =
|
|
|
|
{
|
2000-01-26 01:46:56 +08:00
|
|
|
FALSE /* run */
|
1997-11-25 06:05:25 +08:00
|
|
|
};
|
|
|
|
|
1998-11-09 10:05:24 +08:00
|
|
|
static char *image_comment= NULL;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
MAIN ()
|
|
|
|
|
|
|
|
static void
|
2000-01-26 01:46:56 +08:00
|
|
|
query (void)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
static GimpParamDef load_args[] =
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
{ GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
|
|
|
|
{ GIMP_PDB_STRING, "filename", "The name of the file to load" },
|
|
|
|
{ GIMP_PDB_STRING, "raw_filename", "The name of the file to load" }
|
1997-11-25 06:05:25 +08:00
|
|
|
};
|
2000-08-22 09:26:57 +08:00
|
|
|
static GimpParamDef load_return_vals[] =
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
{ GIMP_PDB_IMAGE, "image", "Output image" }
|
1997-11-25 06:05:25 +08:00
|
|
|
};
|
2000-01-26 01:46:56 +08:00
|
|
|
static gint nload_args = sizeof (load_args) / sizeof (load_args[0]);
|
|
|
|
static gint nload_return_vals = (sizeof (load_return_vals) /
|
|
|
|
sizeof (load_return_vals[0]));
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-08-22 09:26:57 +08:00
|
|
|
static GimpParamDef save_args[] =
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
{ GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
|
|
|
|
{ GIMP_PDB_IMAGE, "image", "Input image" },
|
|
|
|
{ GIMP_PDB_DRAWABLE, "drawable", "Drawable to save" },
|
|
|
|
{ GIMP_PDB_STRING, "filename", "The name of the file to save the image in" },
|
|
|
|
{ GIMP_PDB_STRING, "raw_filename", "The name of the file to save the image in" },
|
|
|
|
{ GIMP_PDB_INT32, "compression", "Compression type: { NONE (0), LZW (1), PACKBITS (2), DEFLATE (3), JPEG (4)" }
|
1997-11-25 06:05:25 +08:00
|
|
|
};
|
2000-01-26 01:46:56 +08:00
|
|
|
static gint nsave_args = sizeof (save_args) / sizeof (save_args[0]);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
gimp_install_procedure ("file_tiff_load",
|
2000-01-31 10:32:30 +08:00
|
|
|
"loads files of the tiff file format",
|
1997-11-25 06:05:25 +08:00
|
|
|
"FIXME: write help for tiff_load",
|
1998-05-18 08:54:11 +08:00
|
|
|
"Spencer Kimball, Peter Mattis & Nick Lamb",
|
1998-05-31 14:49:20 +08:00
|
|
|
"Nick Lamb <njl195@zepler.org.uk>",
|
2000-04-20 12:38:31 +08:00
|
|
|
"1995-1996,1998-2000",
|
1997-11-25 06:05:25 +08:00
|
|
|
"<Load>/Tiff",
|
|
|
|
NULL,
|
2000-08-22 09:26:57 +08:00
|
|
|
GIMP_PLUGIN,
|
1997-11-25 06:05:25 +08:00
|
|
|
nload_args, nload_return_vals,
|
|
|
|
load_args, load_return_vals);
|
|
|
|
|
|
|
|
gimp_install_procedure ("file_tiff_save",
|
2000-01-31 10:32:30 +08:00
|
|
|
"saves files in the tiff file format",
|
2000-10-20 11:38:15 +08:00
|
|
|
"Saves files in the Tagged Image File Format. "
|
|
|
|
"The value for the saved comment is taken "
|
|
|
|
"from the 'gimp-comment' parasite.",
|
1997-11-25 06:05:25 +08:00
|
|
|
"Spencer Kimball & Peter Mattis",
|
|
|
|
"Spencer Kimball & Peter Mattis",
|
2000-04-20 12:38:31 +08:00
|
|
|
"1995-1996,2000",
|
1997-11-25 06:05:25 +08:00
|
|
|
"<Save>/Tiff",
|
1998-05-18 08:54:11 +08:00
|
|
|
"RGB*, GRAY*, INDEXED",
|
2000-08-22 09:26:57 +08:00
|
|
|
GIMP_PLUGIN,
|
1997-11-25 06:05:25 +08:00
|
|
|
nsave_args, 0,
|
|
|
|
save_args, NULL);
|
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
gimp_register_magic_load_handler ("file_tiff_load",
|
|
|
|
"tif,tiff",
|
|
|
|
"",
|
|
|
|
"0,string,II*\\0,0,string,MM\\0*");
|
|
|
|
gimp_register_save_handler ("file_tiff_save",
|
|
|
|
"tif,tiff",
|
|
|
|
"");
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2000-01-26 01:46:56 +08:00
|
|
|
run (gchar *name,
|
|
|
|
gint nparams,
|
2000-08-22 09:26:57 +08:00
|
|
|
GimpParam *param,
|
2000-01-26 01:46:56 +08:00
|
|
|
gint *nreturn_vals,
|
2000-08-22 09:26:57 +08:00
|
|
|
GimpParam **return_vals)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
static GimpParam values[2];
|
|
|
|
GimpRunModeType run_mode;
|
|
|
|
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
|
1998-11-09 10:05:24 +08:00
|
|
|
#ifdef GIMP_HAVE_PARASITES
|
2000-05-27 06:28:40 +08:00
|
|
|
GimpParasite *parasite;
|
1998-11-09 10:05:24 +08:00
|
|
|
#endif /* GIMP_HAVE_PARASITES */
|
2000-01-26 01:46:56 +08:00
|
|
|
gint32 image;
|
|
|
|
gint32 drawable;
|
|
|
|
gint32 orig_image;
|
2000-08-24 22:17:34 +08:00
|
|
|
GimpExportReturnType export = GIMP_EXPORT_CANCEL;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
run_mode = param[0].data.d_int32;
|
|
|
|
|
|
|
|
*nreturn_vals = 1;
|
2000-01-26 01:46:56 +08:00
|
|
|
*return_vals = values;
|
2000-08-22 09:26:57 +08:00
|
|
|
values[0].type = GIMP_PDB_STATUS;
|
|
|
|
values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
if (strcmp (name, "file_tiff_load") == 0)
|
|
|
|
{
|
2000-01-09 14:02:20 +08:00
|
|
|
INIT_I18N();
|
1998-05-18 08:54:11 +08:00
|
|
|
image = load_image (param[1].data.d_string);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-05-18 08:54:11 +08:00
|
|
|
if (image != -1)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
*nreturn_vals = 2;
|
2000-08-22 09:26:57 +08:00
|
|
|
values[1].type = GIMP_PDB_IMAGE;
|
1998-05-18 08:54:11 +08:00
|
|
|
values[1].data.d_image = image;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
status = GIMP_PDB_EXECUTION_ERROR;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (strcmp (name, "file_tiff_save") == 0)
|
|
|
|
{
|
1999-10-04 02:54:54 +08:00
|
|
|
image = orig_image = param[1].data.d_int32;
|
1999-10-25 08:59:18 +08:00
|
|
|
drawable = param[2].data.d_int32;
|
1998-11-09 10:05:24 +08:00
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
/* Do this right this time, if POSSIBLE query for parasites, otherwise
|
|
|
|
or if there isn't one, choose the DEFAULT_COMMENT */
|
1998-11-09 10:05:24 +08:00
|
|
|
|
1999-10-04 02:54:54 +08:00
|
|
|
/* eventually export the image */
|
|
|
|
switch (run_mode)
|
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_RUN_INTERACTIVE:
|
|
|
|
case GIMP_RUN_WITH_LAST_VALS:
|
2000-01-26 01:46:56 +08:00
|
|
|
INIT_I18N_UI();
|
2000-05-02 04:22:55 +08:00
|
|
|
gimp_ui_init ("tiff", FALSE);
|
1999-10-04 02:54:54 +08:00
|
|
|
export = gimp_export_image (&image, &drawable, "TIFF",
|
2000-08-24 22:17:34 +08:00
|
|
|
(GIMP_EXPORT_CAN_HANDLE_RGB |
|
|
|
|
GIMP_EXPORT_CAN_HANDLE_GRAY |
|
|
|
|
GIMP_EXPORT_CAN_HANDLE_INDEXED |
|
|
|
|
GIMP_EXPORT_CAN_HANDLE_ALPHA ));
|
|
|
|
if (export == GIMP_EXPORT_CANCEL)
|
1999-10-04 07:48:33 +08:00
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
values[0].data.d_status = GIMP_PDB_CANCEL;
|
1999-10-04 07:48:33 +08:00
|
|
|
return;
|
|
|
|
}
|
1999-10-04 02:54:54 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
1998-11-09 10:05:24 +08:00
|
|
|
#ifdef GIMP_HAVE_PARASITES
|
1999-10-17 08:07:55 +08:00
|
|
|
parasite = gimp_image_parasite_find (orig_image, "gimp-comment");
|
1998-11-13 12:00:54 +08:00
|
|
|
if (parasite)
|
1999-10-04 02:54:54 +08:00
|
|
|
image_comment = g_strdup (parasite->data);
|
2000-05-27 06:28:40 +08:00
|
|
|
gimp_parasite_free (parasite);
|
1998-11-09 10:05:24 +08:00
|
|
|
#endif /* GIMP_HAVE_PARASITES */
|
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
if (!image_comment)
|
|
|
|
image_comment = g_strdup (DEFAULT_COMMENT);
|
1998-10-12 06:50:03 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
switch (run_mode)
|
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_RUN_INTERACTIVE:
|
1997-11-25 06:05:25 +08:00
|
|
|
/* Possibly retrieve data */
|
|
|
|
gimp_get_data ("file_tiff_save", &tsvals);
|
2000-01-26 01:46:56 +08:00
|
|
|
|
1998-11-09 10:05:24 +08:00
|
|
|
#ifdef GIMP_HAVE_PARASITES
|
1999-10-17 08:07:55 +08:00
|
|
|
parasite = gimp_image_parasite_find (orig_image, "tiff-save-options");
|
1998-11-13 12:00:54 +08:00
|
|
|
if (parasite)
|
1999-10-04 02:54:54 +08:00
|
|
|
{
|
2000-01-26 01:46:56 +08:00
|
|
|
tsvals.compression =
|
|
|
|
((TiffSaveVals *) parasite->data)->compression;
|
1999-10-04 02:54:54 +08:00
|
|
|
}
|
2000-05-27 06:28:40 +08:00
|
|
|
gimp_parasite_free (parasite);
|
1998-11-09 10:05:24 +08:00
|
|
|
#endif /* GIMP_HAVE_PARASITES */
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* First acquire information with a dialog */
|
|
|
|
if (! save_dialog ())
|
2000-08-22 09:26:57 +08:00
|
|
|
status = GIMP_PDB_CANCEL;
|
2000-01-26 01:46:56 +08:00
|
|
|
break;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_RUN_NONINTERACTIVE:
|
2000-01-26 01:46:56 +08:00
|
|
|
INIT_I18N();
|
1997-11-25 06:05:25 +08:00
|
|
|
/* Make sure all the arguments are there! */
|
1999-09-21 02:00:06 +08:00
|
|
|
if (nparams != 6)
|
2000-01-26 01:46:56 +08:00
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
status = GIMP_PDB_CALLING_ERROR;
|
2000-01-26 01:46:56 +08:00
|
|
|
}
|
|
|
|
else
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
switch (param[5].data.d_int32)
|
|
|
|
{
|
|
|
|
case 0: tsvals.compression = COMPRESSION_NONE; break;
|
|
|
|
case 1: tsvals.compression = COMPRESSION_LZW; break;
|
|
|
|
case 2: tsvals.compression = COMPRESSION_PACKBITS; break;
|
2000-04-20 12:38:31 +08:00
|
|
|
case 3: tsvals.compression = COMPRESSION_DEFLATE; break;
|
|
|
|
case 4: tsvals.compression = COMPRESSION_JPEG; break;
|
2000-08-22 09:26:57 +08:00
|
|
|
default: status = GIMP_PDB_CALLING_ERROR; break;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
}
|
2000-04-02 18:27:23 +08:00
|
|
|
break;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_RUN_WITH_LAST_VALS:
|
1997-11-25 06:05:25 +08:00
|
|
|
/* Possibly retrieve data */
|
|
|
|
gimp_get_data ("file_tiff_save", &tsvals);
|
2000-01-26 01:46:56 +08:00
|
|
|
|
1998-11-09 10:05:24 +08:00
|
|
|
#ifdef GIMP_HAVE_PARASITES
|
1999-10-17 08:07:55 +08:00
|
|
|
parasite = gimp_image_parasite_find (orig_image, "tiff-save-options");
|
1998-11-13 12:00:54 +08:00
|
|
|
if (parasite)
|
1999-10-04 02:54:54 +08:00
|
|
|
{
|
2000-01-26 01:46:56 +08:00
|
|
|
tsvals.compression =
|
|
|
|
((TiffSaveVals *) parasite->data)->compression;
|
1999-10-04 02:54:54 +08:00
|
|
|
}
|
2000-05-27 06:28:40 +08:00
|
|
|
gimp_parasite_free (parasite);
|
1998-11-09 10:05:24 +08:00
|
|
|
#endif /* GIMP_HAVE_PARASITES */
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2000-08-22 09:26:57 +08:00
|
|
|
if (status == GIMP_PDB_SUCCESS)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
2000-01-26 01:46:56 +08:00
|
|
|
if (save_image (param[3].data.d_string, image, drawable, orig_image))
|
|
|
|
{
|
|
|
|
/* Store mvals data */
|
|
|
|
gimp_set_data ("file_tiff_save", &tsvals, sizeof (TiffSaveVals));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
status = GIMP_PDB_EXECUTION_ERROR;
|
2000-01-26 01:46:56 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
1999-10-04 02:54:54 +08:00
|
|
|
|
2000-08-24 22:17:34 +08:00
|
|
|
if (export == GIMP_EXPORT_EXPORT)
|
1999-10-04 02:54:54 +08:00
|
|
|
gimp_image_delete (image);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
2000-01-26 01:46:56 +08:00
|
|
|
else
|
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
status = GIMP_PDB_CALLING_ERROR;
|
2000-01-26 01:46:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
values[0].data.d_status = status;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
libgimp/gimp.def libgimp/gimpui.def libgimp/makefile.{cygwin,msc}
2000-02-15 Tor Lillqvist <tml@iki.fi>
* libgimp/gimp.def
* libgimp/gimpui.def
* libgimp/makefile.{cygwin,msc}
* app/makefile.{cygwin,msc}
* plug-ins/makefile.{cygwin,msc}: Updates.
* app/datafiles.c (is_script): New Win32-only function, which
tests if a file's extension matches one of the extensions in the
PATHEXT environment variable (which the cmd.exe command
interpreter also uses). This is to avoid starting applications
associated with any random data file the user might have dropped
in the plug-ins folder, while still supporting plug-ins written in
scripting languages.
* app/gimpparasite.c (gimp_parasiterc_save): (Win32:) Cannot
rename to an existing file.
* plug-ins/Lighting/lighting_image.c
* plug-ins/Lighting/lighting_share.c
* plug-ins/MapObject/mapobject_preview.c
* plug-ins/MapObject/mapobject_shade.c: Use G_PI.
* plug-ins/common/gz.c: #ifdef G_OS_WIN32 was used before its
potential definition via glib.h.
* plug-ins/common/jpeg.c: Also recognize Exif files, which are
typically produced by digital cameras. The usually have a .jpg
file name extension, and would thus already match this plug-in,
but add the magic string just in case. They are loaded just fine
by libjpeg even if they don't have the JFIF signature.
* plug-ins/common/tiff.c: Set TIFF warning and error handler, so
we get to pass libtiff's messages through the normal channels.
2000-02-15 06:44:06 +08:00
|
|
|
static void
|
|
|
|
tiff_warning(const char* module, const char* fmt, va_list ap)
|
|
|
|
{
|
|
|
|
g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, ap);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
tiff_error(const char* module, const char* fmt, va_list ap)
|
|
|
|
{
|
|
|
|
g_logv (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, fmt, ap);
|
|
|
|
}
|
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
static gint32
|
|
|
|
load_image (gchar *filename)
|
1999-10-04 02:54:54 +08:00
|
|
|
{
|
2000-05-02 04:22:55 +08:00
|
|
|
TIFF *tif;
|
|
|
|
gushort bps, spp, photomet;
|
|
|
|
gint cols, rows, alpha;
|
2000-08-22 09:26:57 +08:00
|
|
|
gint image, image_type = GIMP_RGB;
|
|
|
|
gint layer, layer_type = GIMP_RGB_IMAGE;
|
2000-05-02 04:22:55 +08:00
|
|
|
gushort extra, *extra_types;
|
1999-09-18 06:28:25 +08:00
|
|
|
channel_data *channel= NULL;
|
1998-05-18 08:54:11 +08:00
|
|
|
|
2000-05-02 04:22:55 +08:00
|
|
|
gushort *redmap, *greenmap, *bluemap;
|
|
|
|
guchar colors[3]= {0, 0, 0};
|
|
|
|
guchar cmap[768];
|
1998-05-18 08:54:11 +08:00
|
|
|
|
2000-05-02 04:22:55 +08:00
|
|
|
gint i, j, worst_case = 0;
|
|
|
|
gchar *name;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-10-08 16:15:21 +08:00
|
|
|
TiffSaveVals save_vals;
|
1998-11-09 10:05:24 +08:00
|
|
|
#ifdef GIMP_HAVE_PARASITES
|
2000-05-27 06:28:40 +08:00
|
|
|
GimpParasite *parasite;
|
1998-11-09 10:05:24 +08:00
|
|
|
#endif /* GIMP_HAVE_PARASITES */
|
1998-10-08 16:15:21 +08:00
|
|
|
guint16 tmp;
|
2000-06-18 09:07:13 +08:00
|
|
|
#ifdef TIFFTAG_ICCPROFILE
|
|
|
|
uint32 profile_size;
|
|
|
|
guchar *icc_profile;
|
|
|
|
#endif
|
libgimp/gimp.def libgimp/gimpui.def libgimp/makefile.{cygwin,msc}
2000-02-15 Tor Lillqvist <tml@iki.fi>
* libgimp/gimp.def
* libgimp/gimpui.def
* libgimp/makefile.{cygwin,msc}
* app/makefile.{cygwin,msc}
* plug-ins/makefile.{cygwin,msc}: Updates.
* app/datafiles.c (is_script): New Win32-only function, which
tests if a file's extension matches one of the extensions in the
PATHEXT environment variable (which the cmd.exe command
interpreter also uses). This is to avoid starting applications
associated with any random data file the user might have dropped
in the plug-ins folder, while still supporting plug-ins written in
scripting languages.
* app/gimpparasite.c (gimp_parasiterc_save): (Win32:) Cannot
rename to an existing file.
* plug-ins/Lighting/lighting_image.c
* plug-ins/Lighting/lighting_share.c
* plug-ins/MapObject/mapobject_preview.c
* plug-ins/MapObject/mapobject_shade.c: Use G_PI.
* plug-ins/common/gz.c: #ifdef G_OS_WIN32 was used before its
potential definition via glib.h.
* plug-ins/common/jpeg.c: Also recognize Exif files, which are
typically produced by digital cameras. The usually have a .jpg
file name extension, and would thus already match this plug-in,
but add the magic string just in case. They are loaded just fine
by libjpeg even if they don't have the JFIF signature.
* plug-ins/common/tiff.c: Set TIFF warning and error handler, so
we get to pass libtiff's messages through the normal channels.
2000-02-15 06:44:06 +08:00
|
|
|
|
|
|
|
TIFFSetWarningHandler (tiff_warning);
|
|
|
|
TIFFSetErrorHandler (tiff_error);
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
tif = TIFFOpen (filename, "r");
|
1998-05-18 08:54:11 +08:00
|
|
|
if (!tif) {
|
1999-10-04 02:54:54 +08:00
|
|
|
g_message ("TIFF Can't open %s\n", filename);
|
1998-05-18 08:54:11 +08:00
|
|
|
gimp_quit ();
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-01-09 14:02:20 +08:00
|
|
|
name = g_strdup_printf( _("Loading %s:"), filename);
|
1997-11-25 06:05:25 +08:00
|
|
|
gimp_progress_init (name);
|
1998-05-18 08:54:11 +08:00
|
|
|
g_free (name);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
TIFFGetFieldDefaulted (tif, TIFFTAG_BITSPERSAMPLE, &bps);
|
1998-05-18 08:54:11 +08:00
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
if (bps > 8 && bps != 16) {
|
|
|
|
worst_case = 1; /* Wrong sample width => RGBA */
|
1998-05-18 08:54:11 +08:00
|
|
|
}
|
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
TIFFGetFieldDefaulted (tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
|
|
|
|
|
1998-05-18 08:54:11 +08:00
|
|
|
if (!TIFFGetField (tif, TIFFTAG_EXTRASAMPLES, &extra, &extra_types))
|
|
|
|
extra = 0;
|
|
|
|
|
|
|
|
if (!TIFFGetField (tif, TIFFTAG_IMAGEWIDTH, &cols)) {
|
1999-10-04 02:54:54 +08:00
|
|
|
g_message ("TIFF Can't get image width\n");
|
1998-05-18 08:54:11 +08:00
|
|
|
gimp_quit ();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!TIFFGetField (tif, TIFFTAG_IMAGELENGTH, &rows)) {
|
1999-10-04 02:54:54 +08:00
|
|
|
g_message ("TIFF Can't get image length\n");
|
1998-05-18 08:54:11 +08:00
|
|
|
gimp_quit ();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!TIFFGetField (tif, TIFFTAG_PHOTOMETRIC, &photomet)) {
|
1999-09-18 06:28:25 +08:00
|
|
|
g_message("TIFF Can't get photometric\nAssuming min-is-black\n");
|
1998-10-05 18:05:29 +08: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). */
|
|
|
|
photomet = PHOTOMETRIC_MINISBLACK;
|
1998-05-18 08:54:11 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
/* test if the extrasample represents an associated alpha channel... */
|
1998-05-18 08:54:11 +08:00
|
|
|
if (extra > 0 && (extra_types[0] == EXTRASAMPLE_ASSOCALPHA)) {
|
1997-11-25 06:05:25 +08:00
|
|
|
alpha = 1;
|
1998-11-09 10:05:24 +08:00
|
|
|
--extra;
|
1998-05-18 08:54:11 +08:00
|
|
|
} else {
|
1997-11-25 06:05:25 +08:00
|
|
|
alpha = 0;
|
1998-05-18 08:54:11 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-11-09 10:05:24 +08:00
|
|
|
if (photomet == PHOTOMETRIC_RGB && spp > 3 + extra) {
|
1998-05-31 14:49:20 +08:00
|
|
|
alpha= 1;
|
1998-11-09 10:05:24 +08:00
|
|
|
extra= spp - 4;
|
|
|
|
} else if (photomet != PHOTOMETRIC_RGB && spp > 1 + extra) {
|
1998-05-31 14:49:20 +08:00
|
|
|
alpha= 1;
|
1998-11-09 10:05:24 +08:00
|
|
|
extra= spp - 2;
|
1998-05-18 08:54:11 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-05-18 08:54:11 +08:00
|
|
|
switch (photomet) {
|
|
|
|
case PHOTOMETRIC_MINISBLACK:
|
|
|
|
case PHOTOMETRIC_MINISWHITE:
|
2000-08-22 09:26:57 +08:00
|
|
|
image_type = GIMP_GRAY;
|
|
|
|
layer_type = (alpha) ? GIMP_GRAYA_IMAGE : GIMP_GRAY_IMAGE;
|
1998-05-18 08:54:11 +08:00
|
|
|
break;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-05-18 08:54:11 +08:00
|
|
|
case PHOTOMETRIC_RGB:
|
2000-08-22 09:26:57 +08:00
|
|
|
image_type = GIMP_RGB;
|
|
|
|
layer_type = (alpha) ? GIMP_RGBA_IMAGE : GIMP_RGB_IMAGE;
|
1998-05-18 08:54:11 +08:00
|
|
|
break;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-05-18 08:54:11 +08:00
|
|
|
case PHOTOMETRIC_PALETTE:
|
2000-08-22 09:26:57 +08:00
|
|
|
image_type = GIMP_INDEXED;
|
|
|
|
layer_type = (alpha) ? GIMP_INDEXEDA_IMAGE : GIMP_INDEXED_IMAGE;
|
1998-05-18 08:54:11 +08:00
|
|
|
break;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-05-18 08:54:11 +08:00
|
|
|
default:
|
1999-09-18 06:28:25 +08:00
|
|
|
worst_case = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (worst_case) {
|
2000-08-22 09:26:57 +08:00
|
|
|
image_type = GIMP_RGB;
|
|
|
|
layer_type = GIMP_RGBA_IMAGE;
|
1998-05-18 08:54:11 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-05-18 08:54:11 +08:00
|
|
|
if ((image = gimp_image_new (cols, rows, image_type)) == -1) {
|
1998-05-31 14:49:20 +08:00
|
|
|
g_message("TIFF Can't create a new image\n");
|
1998-05-18 08:54:11 +08:00
|
|
|
gimp_quit ();
|
|
|
|
}
|
|
|
|
gimp_image_set_filename (image, filename);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-06-18 09:07:13 +08:00
|
|
|
/* attach a parasite containing an ICC profile - if found in the TIFF file */
|
|
|
|
|
|
|
|
#ifdef TIFFTAG_ICCPROFILE
|
|
|
|
/* If TIFFTAG_ICCPROFILE is defined we are dealing with a libtiff version
|
|
|
|
* that can handle ICC profiles. Otherwise just ignore this section. */
|
|
|
|
if (TIFFGetField (tif, TIFFTAG_ICCPROFILE, &profile_size, &icc_profile)) {
|
|
|
|
#ifdef GIMP_HAVE_PARASITES
|
2000-08-22 09:26:57 +08:00
|
|
|
parasite = gimp_parasite_new("icc-profile", 0,
|
2000-06-18 09:07:13 +08:00
|
|
|
profile_size, icc_profile);
|
|
|
|
gimp_image_parasite_attach(image, parasite);
|
2000-08-22 09:26:57 +08:00
|
|
|
gimp_parasite_free(parasite);
|
2000-06-18 09:07:13 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-04-20 12:38:31 +08:00
|
|
|
/* attach a parasite containing the compression */
|
1998-10-08 16:15:21 +08:00
|
|
|
if (!TIFFGetField (tif, TIFFTAG_COMPRESSION, &tmp))
|
|
|
|
save_vals.compression = COMPRESSION_NONE;
|
|
|
|
else
|
|
|
|
save_vals.compression = tmp;
|
1998-11-09 10:05:24 +08:00
|
|
|
#ifdef GIMP_HAVE_PARASITES
|
2000-05-27 06:28:40 +08:00
|
|
|
parasite = gimp_parasite_new ("tiff-save-options", 0,
|
|
|
|
sizeof (save_vals), &save_vals);
|
|
|
|
gimp_image_parasite_attach (image, parasite);
|
|
|
|
gimp_parasite_free (parasite);
|
1998-11-09 10:05:24 +08:00
|
|
|
#endif /* GIMP_HAVE_PARASITES */
|
1998-10-08 16:15:21 +08:00
|
|
|
|
1998-10-05 18:05:29 +08:00
|
|
|
|
1998-10-12 06:50:03 +08:00
|
|
|
/* Attach a parasite containing the image description. Pretend to
|
1998-10-14 10:54:02 +08:00
|
|
|
* be a gimp comment so other plugins will use this description as
|
1998-10-12 06:50:03 +08:00
|
|
|
* an image comment where appropriate. */
|
1998-11-09 10:05:24 +08:00
|
|
|
#ifdef GIMP_HAVE_PARASITES
|
1998-10-12 06:50:03 +08:00
|
|
|
{
|
|
|
|
char *img_desc;
|
|
|
|
|
|
|
|
if (TIFFGetField (tif, TIFFTAG_IMAGEDESCRIPTION, &img_desc))
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
|
|
|
|
len = strlen(img_desc) + 1;
|
|
|
|
len = MIN(len, 241);
|
|
|
|
img_desc[len-1] = '\000';
|
|
|
|
|
2000-05-27 06:28:40 +08:00
|
|
|
parasite = gimp_parasite_new ("gimp-comment",
|
|
|
|
GIMP_PARASITE_PERSISTENT,
|
|
|
|
len, img_desc);
|
1999-10-17 08:07:55 +08:00
|
|
|
gimp_image_parasite_attach (image, parasite);
|
2000-05-27 06:28:40 +08:00
|
|
|
gimp_parasite_free (parasite);
|
1998-10-12 06:50:03 +08:00
|
|
|
}
|
|
|
|
}
|
1998-11-09 10:05:24 +08:00
|
|
|
#endif /* GIMP_HAVE_PARASITES */
|
1998-10-12 06:50:03 +08:00
|
|
|
|
1998-10-05 18:05:29 +08:00
|
|
|
/* any resolution info in the file? */
|
1998-11-09 10:05:24 +08:00
|
|
|
#ifdef GIMP_HAVE_RESOLUTION_INFO
|
1998-10-05 18:05:29 +08:00
|
|
|
{
|
2000-02-08 04:35:13 +08:00
|
|
|
gfloat xres = 72.0, yres = 72.0;
|
|
|
|
gushort read_unit;
|
|
|
|
GimpUnit unit = GIMP_UNIT_PIXEL; /* invalid unit */
|
1998-10-05 18:05:29 +08:00
|
|
|
|
|
|
|
if (TIFFGetField (tif, TIFFTAG_XRESOLUTION, &xres)) {
|
|
|
|
if (TIFFGetField (tif, TIFFTAG_YRESOLUTION, &yres)) {
|
|
|
|
|
1999-10-04 02:54:54 +08:00
|
|
|
if (TIFFGetFieldDefaulted (tif, TIFFTAG_RESOLUTIONUNIT, &read_unit))
|
|
|
|
{
|
|
|
|
switch (read_unit)
|
|
|
|
{
|
|
|
|
case RESUNIT_NONE:
|
|
|
|
/* ImageMagick writes files with this silly resunit */
|
2000-01-08 18:55:05 +08:00
|
|
|
g_message ("TIFF warning: resolution units meaningless\n");
|
1999-10-04 02:54:54 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RESUNIT_INCH:
|
2000-02-08 04:35:13 +08:00
|
|
|
unit = GIMP_UNIT_INCH;
|
1999-10-04 02:54:54 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case RESUNIT_CENTIMETER:
|
|
|
|
xres *= 2.54;
|
|
|
|
yres *= 2.54;
|
2000-02-08 04:35:13 +08:00
|
|
|
unit = GIMP_UNIT_MM; /* as this is our default metric unit */
|
1999-10-04 02:54:54 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
g_message ("TIFF file error: unknown resolution unit type %d, "
|
|
|
|
"assuming dpi\n", read_unit);
|
2000-01-26 01:46:56 +08:00
|
|
|
break;
|
1999-10-04 02:54:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ /* no res unit tag */
|
|
|
|
/* old AppleScan software produces these */
|
|
|
|
g_message ("TIFF warning: resolution specified without\n"
|
|
|
|
"any units tag, assuming dpi\n");
|
1998-10-05 18:05:29 +08:00
|
|
|
}
|
2000-01-26 01:46:56 +08:00
|
|
|
}
|
1999-10-04 02:54:54 +08:00
|
|
|
else
|
|
|
|
{ /* xres but no yres */
|
|
|
|
g_message("TIFF warning: no y resolution info, assuming same as x\n");
|
|
|
|
yres = xres;
|
1998-10-05 18:05:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* now set the new image's resolution info */
|
2000-01-08 18:55:05 +08: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 */
|
2000-01-08 20:42:53 +08:00
|
|
|
if (read_unit != RESUNIT_NONE)
|
2000-01-08 18:55:05 +08:00
|
|
|
{
|
|
|
|
gimp_image_set_resolution (image, xres, yres);
|
2000-02-08 04:35:13 +08:00
|
|
|
if (unit != GIMP_UNIT_PIXEL)
|
2000-01-08 18:55:05 +08:00
|
|
|
gimp_image_set_unit (image, unit);
|
|
|
|
}
|
1998-10-05 18:05:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* no x res tag => we assume we have no resolution info, so we
|
|
|
|
* don't care. Older versions of this plugin used to write files
|
|
|
|
* with no resolution tags at all. */
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
}
|
1998-11-09 10:05:24 +08:00
|
|
|
#endif /* GIMP_HAVE_RESOLUTION_INFO */
|
1998-10-05 18:05:29 +08:00
|
|
|
|
|
|
|
|
1998-05-18 08:54:11 +08:00
|
|
|
/* Install colormap for INDEXED images only */
|
2000-08-22 09:26:57 +08:00
|
|
|
if (image_type == GIMP_INDEXED)
|
1999-10-04 02:54:54 +08:00
|
|
|
{
|
|
|
|
if (!TIFFGetField (tif, TIFFTAG_COLORMAP, &redmap, &greenmap, &bluemap))
|
|
|
|
{
|
|
|
|
g_message ("TIFF Can't get colormaps\n");
|
|
|
|
gimp_quit ();
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-10-04 02:54:54 +08:00
|
|
|
for (i = 0, j = 0; i < (1 << bps); i++)
|
|
|
|
{
|
|
|
|
cmap[j++] = redmap[i] >> 8;
|
|
|
|
cmap[j++] = greenmap[i] >> 8;
|
|
|
|
cmap[j++] = bluemap[i] >> 8;
|
|
|
|
}
|
|
|
|
gimp_image_set_cmap (image, cmap, (1 << bps));
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
/* Allocate channel_data for all channels, even the background layer */
|
|
|
|
channel = g_new (channel_data, extra + 1);
|
2000-01-09 14:02:20 +08:00
|
|
|
layer = gimp_layer_new (image, _("Background"), cols, rows, layer_type,
|
2000-08-22 09:26:57 +08:00
|
|
|
100, GIMP_NORMAL_MODE);
|
1999-09-18 06:28:25 +08:00
|
|
|
channel[0].ID= layer;
|
1998-05-18 08:54:11 +08:00
|
|
|
gimp_image_add_layer (image, layer, 0);
|
1999-09-18 06:28:25 +08:00
|
|
|
channel[0].drawable= gimp_drawable_get(layer);
|
1998-11-09 10:05:24 +08:00
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
if (extra > 0 && !worst_case) {
|
1998-11-09 10:05:24 +08:00
|
|
|
/* Add alpha channels as appropriate */
|
1999-09-18 06:28:25 +08:00
|
|
|
for (i= 1; i <= extra; ++i) {
|
2000-01-09 14:02:20 +08:00
|
|
|
channel[i].ID= gimp_channel_new(image, _("TIFF Channel"), cols, rows,
|
1998-11-09 10:05:24 +08:00
|
|
|
100.0, colors);
|
|
|
|
gimp_image_add_channel(image, channel[i].ID, 0);
|
|
|
|
channel[i].drawable= gimp_drawable_get (channel[i].ID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
if (worst_case) {
|
|
|
|
g_message("TIFF Fell back to RGBA, image may be inverted\n");
|
|
|
|
load_rgba (tif, channel);
|
|
|
|
} else if (TIFFIsTiled(tif)) {
|
|
|
|
load_tiles (tif, channel, bps, photomet, alpha, extra);
|
|
|
|
} else { /* Load scanlines in tile_height chunks */
|
|
|
|
load_lines (tif, channel, bps, photomet, alpha, extra);
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
|
|
|
|
2000-01-22 09:48:17 +08:00
|
|
|
for (i= 0; !worst_case && i < extra; ++i) {
|
1998-11-09 10:05:24 +08:00
|
|
|
gimp_drawable_flush (channel[i].drawable);
|
|
|
|
gimp_drawable_detach (channel[i].drawable);
|
|
|
|
}
|
|
|
|
|
|
|
|
return image;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
1999-09-18 06:28:25 +08:00
|
|
|
load_rgba (TIFF *tif, channel_data *channel)
|
1998-11-09 10:05:24 +08:00
|
|
|
{
|
1999-09-18 06:28:25 +08:00
|
|
|
uint32 imageWidth, imageLength;
|
1999-09-18 09:22:29 +08:00
|
|
|
gulong *buffer;
|
1999-09-18 06:28:25 +08:00
|
|
|
|
|
|
|
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imageWidth);
|
|
|
|
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imageLength);
|
|
|
|
gimp_pixel_rgn_init (&(channel[0].pixel_rgn), channel[0].drawable,
|
|
|
|
0, 0, imageWidth, imageLength, TRUE, FALSE);
|
1999-09-18 09:22:29 +08:00
|
|
|
buffer = g_new(gulong, imageWidth * imageLength);
|
1999-09-18 06:28:25 +08:00
|
|
|
channel[0].pixels = (guchar*) buffer;
|
|
|
|
if (buffer == NULL) {
|
|
|
|
g_message("TIFF Unable to allocate temporary buffer\n");
|
|
|
|
}
|
|
|
|
if (!TIFFReadRGBAImage(tif, imageWidth, imageLength, buffer, 0))
|
|
|
|
g_message("TIFF Unsupported layout, no RGBA loader\n");
|
1998-11-09 10:05:24 +08:00
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
gimp_pixel_rgn_set_rect(&(channel[0].pixel_rgn), channel[0].pixels,
|
|
|
|
0, 0, imageWidth, imageLength);
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
static void
|
|
|
|
load_tiles (TIFF *tif, channel_data *channel,
|
|
|
|
unsigned short bps, unsigned short photomet,
|
|
|
|
int alpha, int extra)
|
|
|
|
{
|
|
|
|
uint16 planar= PLANARCONFIG_CONTIG;
|
|
|
|
uint32 imageWidth, imageLength;
|
|
|
|
uint32 tileWidth, tileLength;
|
|
|
|
uint32 x, y, rows, cols;
|
|
|
|
guchar *buffer;
|
|
|
|
double progress= 0.0, one_row;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planar);
|
|
|
|
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imageWidth);
|
|
|
|
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imageLength);
|
|
|
|
TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tileWidth);
|
|
|
|
TIFFGetField(tif, TIFFTAG_TILELENGTH, &tileLength);
|
|
|
|
one_row = (double) tileLength / (double) imageLength;
|
|
|
|
buffer = g_malloc(TIFFTileSize(tif));
|
|
|
|
|
|
|
|
for (i= 0; i <= extra; ++i) {
|
|
|
|
channel[i].pixels= g_new(guchar, tileWidth * tileLength *
|
|
|
|
channel[i].drawable->bpp);
|
|
|
|
}
|
1998-11-09 10:05:24 +08:00
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
for (y = 0; y < imageLength; y += tileLength) {
|
|
|
|
for (x = 0; x < imageWidth; x += tileWidth) {
|
|
|
|
gimp_progress_update (progress + one_row *
|
|
|
|
( (double) x / (double) imageWidth));
|
|
|
|
TIFFReadTile(tif, buffer, x, y, 0, 0);
|
|
|
|
cols= MIN(imageWidth - x, tileWidth);
|
|
|
|
rows= MIN(imageLength - y, tileLength);
|
|
|
|
if (bps == 16) {
|
2000-10-26 07:49:30 +08:00
|
|
|
read_16bit(buffer, channel, photomet, y, x, rows, cols, alpha,
|
|
|
|
extra, tileWidth - cols);
|
1999-09-18 06:28:25 +08:00
|
|
|
} else if (bps == 8) {
|
2000-10-26 07:49:30 +08:00
|
|
|
read_8bit(buffer, channel, photomet, y, x, rows, cols, alpha,
|
|
|
|
extra, tileWidth - cols);
|
1999-09-18 06:28:25 +08:00
|
|
|
} else {
|
2000-10-26 07:49:30 +08:00
|
|
|
read_default(buffer, channel, bps, photomet, y, x, rows, cols,
|
|
|
|
alpha, extra, tileWidth - cols);
|
1999-09-18 06:28:25 +08:00
|
|
|
}
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
1999-09-18 06:28:25 +08:00
|
|
|
progress+= one_row;
|
|
|
|
}
|
|
|
|
for (i= 0; i <= extra; ++i) {
|
|
|
|
g_free(channel[i].pixels);
|
|
|
|
}
|
|
|
|
g_free(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
load_lines (TIFF *tif, channel_data *channel,
|
1999-10-04 02:54:54 +08:00
|
|
|
unsigned short bps, unsigned short photomet,
|
|
|
|
int alpha, int extra)
|
1999-09-18 06:28:25 +08:00
|
|
|
{
|
|
|
|
uint16 planar= PLANARCONFIG_CONTIG;
|
|
|
|
uint32 imageLength, lineSize, cols, rows;
|
|
|
|
guchar *buffer;
|
|
|
|
int i, y, tile_height = gimp_tile_height ();
|
|
|
|
|
|
|
|
TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &planar);
|
|
|
|
TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imageLength);
|
|
|
|
TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &cols);
|
|
|
|
lineSize= TIFFScanlineSize(tif);
|
|
|
|
|
|
|
|
for (i= 0; i <= extra; ++i) {
|
|
|
|
channel[i].pixels= g_new(guchar, tile_height * cols
|
|
|
|
* channel[i].drawable->bpp);
|
|
|
|
}
|
1998-11-09 10:05:24 +08:00
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
buffer = g_malloc(lineSize * tile_height);
|
|
|
|
if (planar == PLANARCONFIG_CONTIG) {
|
|
|
|
for (y = 0; y < imageLength; y+= tile_height ) {
|
|
|
|
gimp_progress_update ( (double) y / (double) imageLength);
|
|
|
|
rows = MIN(tile_height, imageLength - y);
|
|
|
|
for (i = 0; i < rows; ++i)
|
|
|
|
TIFFReadScanline(tif, buffer + i * lineSize, y + i, 0);
|
|
|
|
if (bps == 16) {
|
2000-10-26 07:49:30 +08:00
|
|
|
read_16bit(buffer, channel, photomet, y, 0, rows, cols,
|
|
|
|
alpha, extra, 0);
|
1999-09-18 06:28:25 +08:00
|
|
|
} else if (bps == 8) {
|
2000-10-26 07:49:30 +08:00
|
|
|
read_8bit(buffer, channel, photomet, y, 0, rows, cols,
|
|
|
|
alpha, extra, 0);
|
1999-09-18 06:28:25 +08:00
|
|
|
} else {
|
2000-10-26 07:49:30 +08:00
|
|
|
read_default(buffer, channel, bps, photomet, y, 0, rows, cols,
|
|
|
|
alpha, extra, 0);
|
1999-09-18 06:28:25 +08:00
|
|
|
}
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
1999-09-18 06:28:25 +08:00
|
|
|
} else { /* PLANARCONFIG_SEPARATE -- Just say "No" */
|
|
|
|
uint16 s, samples;
|
|
|
|
TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &samples);
|
|
|
|
for (s = 0; s < samples; ++s) {
|
|
|
|
for (y = 0; y < imageLength; y+= tile_height ) {
|
|
|
|
gimp_progress_update ( (double) y / (double) imageLength);
|
|
|
|
rows = MIN(tile_height, imageLength - y);
|
|
|
|
for (i = 0; i < rows; ++i)
|
|
|
|
TIFFReadScanline(tif, buffer + i * lineSize, y + i, s);
|
|
|
|
read_separate (buffer, channel, bps, photomet,
|
|
|
|
y, 0, rows, cols, alpha, extra, s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i= 0; i <= extra; ++i) {
|
|
|
|
g_free(channel[i].pixels);
|
|
|
|
}
|
|
|
|
g_free(buffer);
|
|
|
|
}
|
1998-11-09 10:05:24 +08:00
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
static void
|
2000-05-02 04:22:55 +08:00
|
|
|
read_16bit (guchar *source,
|
|
|
|
channel_data *channel,
|
|
|
|
gushort photomet,
|
|
|
|
gint startrow,
|
|
|
|
gint startcol,
|
|
|
|
gint rows,
|
|
|
|
gint cols,
|
|
|
|
gint alpha,
|
2000-10-26 07:49:30 +08:00
|
|
|
gint extra,
|
|
|
|
gint align)
|
1999-09-18 06:28:25 +08:00
|
|
|
{
|
|
|
|
guchar *dest;
|
2000-05-02 04:22:55 +08:00
|
|
|
gint gray_val, red_val, green_val, blue_val, alpha_val;
|
|
|
|
gint col, row, i;
|
1999-09-18 06:28:25 +08:00
|
|
|
|
|
|
|
for (i= 0; i <= extra; ++i) {
|
|
|
|
gimp_pixel_rgn_init (&(channel[i].pixel_rgn), channel[i].drawable,
|
|
|
|
startcol, startrow, cols, rows, TRUE, FALSE);
|
|
|
|
}
|
|
|
|
|
2000-11-20 07:54:46 +08:00
|
|
|
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
|
|
|
source++; /* offset source once, to look at the high byte */
|
|
|
|
#endif
|
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
for (row = 0; row < rows; ++row) {
|
|
|
|
dest= channel[0].pixels + row * cols * channel[0].drawable->bpp;
|
|
|
|
|
|
|
|
for (i= 1; i <= extra; ++i) {
|
|
|
|
channel[i].pixel= channel[i].pixels + row * cols;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-11-09 10:05:24 +08:00
|
|
|
for (col = 0; col < cols; col++) {
|
|
|
|
switch (photomet) {
|
|
|
|
case PHOTOMETRIC_MINISBLACK:
|
|
|
|
if (alpha) {
|
1999-09-18 06:28:25 +08:00
|
|
|
gray_val= *source; source+= 2;
|
|
|
|
alpha_val= *source; source+= 2;
|
1998-11-09 10:05:24 +08:00
|
|
|
if (alpha_val)
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = gray_val * 255 / alpha_val;
|
1998-11-09 10:05:24 +08:00
|
|
|
else
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = 0;
|
|
|
|
*dest++ = alpha_val;
|
1998-11-09 10:05:24 +08:00
|
|
|
} else {
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = *source; source+= 2;
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
|
|
|
break;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-11-09 10:05:24 +08:00
|
|
|
case PHOTOMETRIC_MINISWHITE:
|
|
|
|
if (alpha) {
|
1999-09-18 06:28:25 +08:00
|
|
|
gray_val= *source; source+= 2;
|
|
|
|
alpha_val= *source; source+= 2;
|
1998-11-09 10:05:24 +08:00
|
|
|
if (alpha_val)
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = ((255 - gray_val) * 255) / alpha_val;
|
1998-11-09 10:05:24 +08:00
|
|
|
else
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = 0;
|
|
|
|
*dest++ = alpha_val;
|
1998-11-09 10:05:24 +08:00
|
|
|
} else {
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = ~(*source); source+= 2;
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PHOTOMETRIC_PALETTE:
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++= *source; source+= 2;
|
|
|
|
if (alpha) *dest++= *source; source+= 2;
|
1998-11-09 10:05:24 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PHOTOMETRIC_RGB:
|
|
|
|
if (alpha) {
|
1999-09-18 06:28:25 +08:00
|
|
|
red_val= *source; source+= 2;
|
|
|
|
green_val= *source; source+= 2;
|
|
|
|
blue_val= *source; source+= 2;
|
|
|
|
alpha_val= *source; source+= 2;
|
1998-11-09 10:05:24 +08:00
|
|
|
if (alpha_val) {
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = (red_val * 255) / alpha_val;
|
|
|
|
*dest++ = (green_val * 255) / alpha_val;
|
|
|
|
*dest++ = (blue_val * 255) / alpha_val;
|
1998-11-09 10:05:24 +08:00
|
|
|
} else {
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = 0;
|
|
|
|
*dest++ = 0;
|
|
|
|
*dest++ = 0;
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = alpha_val;
|
1998-11-09 10:05:24 +08:00
|
|
|
} else {
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = *source; source+= 2;
|
|
|
|
*dest++ = *source; source+= 2;
|
|
|
|
*dest++ = *source; source+= 2;
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* This case was handled earlier */
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
1999-09-18 06:28:25 +08:00
|
|
|
for (i= 1; i <= extra; ++i) {
|
|
|
|
*channel[i].pixel++ = *source; source+= 2;
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
|
|
|
}
|
2000-10-26 07:49:30 +08:00
|
|
|
if (align) {
|
|
|
|
switch (photomet) {
|
|
|
|
case PHOTOMETRIC_MINISBLACK:
|
|
|
|
case PHOTOMETRIC_MINISWHITE:
|
|
|
|
case PHOTOMETRIC_PALETTE:
|
|
|
|
source+= align * (1 + alpha + extra) * 2;
|
|
|
|
break;
|
|
|
|
case PHOTOMETRIC_RGB:
|
|
|
|
source+= align * (3 + alpha + extra) * 2;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
1999-09-18 06:28:25 +08:00
|
|
|
}
|
|
|
|
for (i= 0; i <= extra; ++i) {
|
|
|
|
gimp_pixel_rgn_set_rect(&(channel[i].pixel_rgn), channel[i].pixels,
|
|
|
|
startcol, startrow, cols, rows);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2000-05-02 04:22:55 +08:00
|
|
|
read_8bit (guchar *source,
|
|
|
|
channel_data *channel,
|
|
|
|
gushort photomet,
|
|
|
|
gint startrow,
|
|
|
|
gint startcol,
|
|
|
|
gint rows,
|
|
|
|
gint cols,
|
|
|
|
gint alpha,
|
2000-10-26 07:49:30 +08:00
|
|
|
gint extra,
|
|
|
|
gint align)
|
1999-09-18 06:28:25 +08:00
|
|
|
{
|
|
|
|
guchar *dest;
|
2000-05-02 04:22:55 +08:00
|
|
|
gint gray_val, red_val, green_val, blue_val, alpha_val;
|
|
|
|
gint col, row, i;
|
1999-09-18 06:28:25 +08:00
|
|
|
|
|
|
|
for (i= 0; i <= extra; ++i) {
|
|
|
|
gimp_pixel_rgn_init (&(channel[i].pixel_rgn), channel[i].drawable,
|
|
|
|
startcol, startrow, cols, rows, TRUE, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (row = 0; row < rows; ++row) {
|
|
|
|
dest= channel[0].pixels + row * cols * channel[0].drawable->bpp;
|
|
|
|
|
|
|
|
for (i= 1; i <= extra; ++i) {
|
|
|
|
channel[i].pixel= channel[i].pixels + row * cols;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (col = 0; col < cols; col++) {
|
|
|
|
switch (photomet) {
|
|
|
|
case PHOTOMETRIC_MINISBLACK:
|
|
|
|
if (alpha) {
|
|
|
|
gray_val= *source++;
|
|
|
|
alpha_val= *source++;
|
|
|
|
if (alpha_val)
|
|
|
|
*dest++ = gray_val * 255 / alpha_val;
|
|
|
|
else
|
|
|
|
*dest++ = 0;
|
|
|
|
*dest++ = alpha_val;
|
|
|
|
} else {
|
|
|
|
*dest++ = *source++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PHOTOMETRIC_MINISWHITE:
|
|
|
|
if (alpha) {
|
|
|
|
gray_val= *source++;
|
|
|
|
alpha_val= *source++;
|
|
|
|
if (alpha_val)
|
|
|
|
*dest++ = ((255 - gray_val) * 255) / alpha_val;
|
|
|
|
else
|
|
|
|
*dest++ = 0;
|
|
|
|
*dest++ = alpha_val;
|
|
|
|
} else {
|
|
|
|
*dest++ = ~(*source++);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PHOTOMETRIC_PALETTE:
|
|
|
|
*dest++= *source++;
|
|
|
|
if (alpha) *dest++= *source++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PHOTOMETRIC_RGB:
|
|
|
|
if (alpha) {
|
|
|
|
red_val= *source++;
|
|
|
|
green_val= *source++;
|
|
|
|
blue_val= *source++;
|
|
|
|
alpha_val= *source++;
|
|
|
|
if (alpha_val) {
|
|
|
|
*dest++ = (red_val * 255) / alpha_val;
|
|
|
|
*dest++ = (green_val * 255) / alpha_val;
|
|
|
|
*dest++ = (blue_val * 255) / alpha_val;
|
|
|
|
} else {
|
|
|
|
*dest++ = 0;
|
|
|
|
*dest++ = 0;
|
|
|
|
*dest++ = 0;
|
|
|
|
}
|
|
|
|
*dest++ = alpha_val;
|
|
|
|
} else {
|
|
|
|
*dest++ = *source++;
|
|
|
|
*dest++ = *source++;
|
|
|
|
*dest++ = *source++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* This case was handled earlier */
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
|
|
|
for (i= 1; i <= extra; ++i) {
|
|
|
|
*channel[i].pixel++ = *source++;
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
|
|
|
}
|
2000-10-26 07:49:30 +08:00
|
|
|
if (align) {
|
|
|
|
switch (photomet) {
|
|
|
|
case PHOTOMETRIC_MINISBLACK:
|
|
|
|
case PHOTOMETRIC_MINISWHITE:
|
|
|
|
case PHOTOMETRIC_PALETTE:
|
|
|
|
source+= align * (1 + alpha + extra);
|
|
|
|
break;
|
|
|
|
case PHOTOMETRIC_RGB:
|
|
|
|
source+= align * (3 + alpha + extra);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
1998-05-18 08:54:11 +08:00
|
|
|
}
|
1999-09-18 06:28:25 +08:00
|
|
|
for (i= 0; i <= extra; ++i) {
|
|
|
|
gimp_pixel_rgn_set_rect(&(channel[i].pixel_rgn), channel[i].pixels,
|
|
|
|
startcol, startrow, cols, rows);
|
|
|
|
}
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-05-18 08:54:11 +08:00
|
|
|
/* Step through all <= 8-bit samples in an image */
|
|
|
|
|
|
|
|
#define NEXTSAMPLE(var) \
|
1997-11-25 06:05:25 +08:00
|
|
|
{ \
|
1998-05-18 08:54:11 +08:00
|
|
|
if (bitsleft == 0) \
|
1997-11-25 06:05:25 +08:00
|
|
|
{ \
|
1999-09-18 06:28:25 +08:00
|
|
|
source++; \
|
1997-11-25 06:05:25 +08:00
|
|
|
bitsleft = 8; \
|
|
|
|
} \
|
|
|
|
bitsleft -= bps; \
|
1999-09-18 06:28:25 +08:00
|
|
|
var = ( *source >> bitsleft ) & maxval; \
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
1998-11-09 10:05:24 +08:00
|
|
|
static void
|
2000-05-02 04:22:55 +08:00
|
|
|
read_default (guchar *source,
|
|
|
|
channel_data *channel,
|
|
|
|
gushort bps,
|
|
|
|
gushort photomet,
|
|
|
|
gint startrow,
|
|
|
|
gint startcol,
|
|
|
|
gint rows,
|
|
|
|
gint cols,
|
|
|
|
gint alpha,
|
2000-10-26 07:49:30 +08:00
|
|
|
gint extra,
|
|
|
|
gint align)
|
1998-11-09 10:05:24 +08:00
|
|
|
{
|
1999-09-18 06:28:25 +08:00
|
|
|
guchar *dest;
|
2000-05-02 04:22:55 +08:00
|
|
|
gint gray_val, red_val, green_val, blue_val, alpha_val;
|
|
|
|
gint col, row, i;
|
|
|
|
gint bitsleft = 8, maxval = (1 << bps) - 1;
|
1998-11-09 10:05:24 +08:00
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
for (i= 0; i <= extra; ++i) {
|
|
|
|
gimp_pixel_rgn_init (&(channel[i].pixel_rgn), channel[i].drawable,
|
|
|
|
startcol, startrow, cols, rows, TRUE, FALSE);
|
|
|
|
}
|
1998-05-18 08:54:11 +08:00
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
for (row = 0; row < rows; ++row) {
|
|
|
|
dest= channel[0].pixels + row * cols * channel[0].drawable->bpp;
|
1998-05-18 08:54:11 +08:00
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
for (i= 1; i <= extra; ++i) {
|
|
|
|
channel[i].pixel= channel[i].pixels + row * cols;
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
1998-05-18 08:54:11 +08:00
|
|
|
|
1998-11-09 10:05:24 +08:00
|
|
|
for (col = 0; col < cols; col++) {
|
1998-05-18 08:54:11 +08:00
|
|
|
switch (photomet) {
|
|
|
|
case PHOTOMETRIC_MINISBLACK:
|
1998-11-09 10:05:24 +08:00
|
|
|
NEXTSAMPLE(gray_val);
|
|
|
|
if (alpha) {
|
|
|
|
NEXTSAMPLE(alpha_val);
|
|
|
|
if (alpha_val)
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = (gray_val * 65025) / (alpha_val * maxval);
|
1998-11-09 10:05:24 +08:00
|
|
|
else
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = 0;
|
|
|
|
*dest++ = alpha_val;
|
1998-11-09 10:05:24 +08:00
|
|
|
} else {
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = (gray_val * 255) / maxval;
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
|
|
|
break;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-05-18 08:54:11 +08:00
|
|
|
case PHOTOMETRIC_MINISWHITE:
|
1998-11-09 10:05:24 +08:00
|
|
|
NEXTSAMPLE(gray_val);
|
|
|
|
if (alpha) {
|
|
|
|
NEXTSAMPLE(alpha_val);
|
|
|
|
if (alpha_val)
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = ((maxval - gray_val) * 65025) / (alpha_val * maxval);
|
1998-11-09 10:05:24 +08:00
|
|
|
else
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = 0;
|
|
|
|
*dest++ = alpha_val;
|
1998-11-09 10:05:24 +08:00
|
|
|
} else {
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = ((maxval - gray_val) * 255) / maxval;
|
1998-05-18 08:54:11 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PHOTOMETRIC_PALETTE:
|
1999-09-18 06:28:25 +08:00
|
|
|
NEXTSAMPLE(*dest++);
|
1998-11-09 10:05:24 +08:00
|
|
|
if (alpha) {
|
1999-09-18 06:28:25 +08:00
|
|
|
NEXTSAMPLE(*dest++);
|
1998-05-18 08:54:11 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PHOTOMETRIC_RGB:
|
1998-11-09 10:05:24 +08:00
|
|
|
NEXTSAMPLE(red_val)
|
|
|
|
NEXTSAMPLE(green_val)
|
|
|
|
NEXTSAMPLE(blue_val)
|
|
|
|
if (alpha) {
|
|
|
|
NEXTSAMPLE(alpha_val)
|
|
|
|
if (alpha_val) {
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = (red_val * 255) / alpha_val;
|
|
|
|
*dest++ = (green_val * 255) / alpha_val;
|
|
|
|
*dest++ = (blue_val * 255) / alpha_val;
|
1998-11-09 10:05:24 +08:00
|
|
|
} else {
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = 0;
|
|
|
|
*dest++ = 0;
|
|
|
|
*dest++ = 0;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = alpha_val;
|
1998-11-09 10:05:24 +08:00
|
|
|
} else {
|
1999-09-18 06:28:25 +08:00
|
|
|
*dest++ = red_val;
|
|
|
|
*dest++ = green_val;
|
|
|
|
*dest++ = blue_val;
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
1998-05-18 08:54:11 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* This case was handled earlier */
|
|
|
|
g_assert_not_reached();
|
|
|
|
}
|
1999-09-18 06:28:25 +08:00
|
|
|
for (i= 1; i <= extra; ++i) {
|
1998-11-09 10:05:24 +08:00
|
|
|
NEXTSAMPLE(alpha_val);
|
|
|
|
*channel[i].pixel++ = alpha_val;
|
|
|
|
}
|
1998-05-18 08:54:11 +08:00
|
|
|
}
|
2000-10-26 07:49:30 +08:00
|
|
|
if (align) {
|
|
|
|
switch (photomet) {
|
|
|
|
case PHOTOMETRIC_MINISBLACK:
|
|
|
|
case PHOTOMETRIC_MINISWHITE:
|
|
|
|
case PHOTOMETRIC_PALETTE:
|
|
|
|
for (i= 0; i < align * (1 + alpha + extra); ++i) {
|
|
|
|
NEXTSAMPLE(alpha_val);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PHOTOMETRIC_RGB:
|
|
|
|
for (i= 0; i < align * (3 + alpha + extra); ++i) {
|
|
|
|
NEXTSAMPLE(alpha_val);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
1999-09-18 06:28:25 +08:00
|
|
|
bitsleft= 0;
|
|
|
|
}
|
|
|
|
for (i= 0; i <= extra; ++i) {
|
|
|
|
gimp_pixel_rgn_set_rect(&(channel[i].pixel_rgn), channel[i].pixels,
|
|
|
|
startcol, startrow, cols, rows);
|
1998-05-18 08:54:11 +08:00
|
|
|
}
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-11-09 10:05:24 +08:00
|
|
|
static void
|
2000-05-02 04:22:55 +08:00
|
|
|
read_separate (guchar *source,
|
|
|
|
channel_data *channel,
|
|
|
|
gushort bps,
|
|
|
|
gushort photomet,
|
|
|
|
gint startrow,
|
|
|
|
gint startcol,
|
|
|
|
gint rows,
|
|
|
|
gint cols,
|
|
|
|
gint alpha,
|
|
|
|
gint extra,
|
|
|
|
gint sample)
|
1998-11-09 10:05:24 +08:00
|
|
|
{
|
1999-09-18 06:28:25 +08:00
|
|
|
guchar *dest;
|
2000-05-02 04:22:55 +08:00
|
|
|
gint col, row, c;
|
|
|
|
gint bitsleft = 8, maxval = (1 << bps) - 1;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
if (bps > 8) {
|
|
|
|
g_message("TIFF Unsupported layout\n");
|
1998-11-09 10:05:24 +08:00
|
|
|
gimp_quit();
|
|
|
|
}
|
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
if (sample < channel[0].drawable->bpp) {
|
|
|
|
c = 0;
|
|
|
|
} else {
|
|
|
|
c = (sample - channel[0].drawable->bpp) + 4;
|
|
|
|
photomet = PHOTOMETRIC_MINISBLACK;
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
gimp_pixel_rgn_init (&(channel[c].pixel_rgn), channel[c].drawable,
|
|
|
|
startcol, startrow, cols, rows, TRUE, FALSE);
|
1998-11-09 10:05:24 +08:00
|
|
|
|
1999-09-18 06:28:25 +08:00
|
|
|
gimp_pixel_rgn_get_rect(&(channel[c].pixel_rgn), channel[c].pixels,
|
|
|
|
startcol, startrow, cols, rows);
|
|
|
|
for (row = 0; row < rows; ++row) {
|
|
|
|
dest = channel[c].pixels + row * cols * channel[c].drawable->bpp;
|
|
|
|
if (c == 0) {
|
|
|
|
for (col = 0; col < cols; ++col) {
|
|
|
|
NEXTSAMPLE(dest[col * channel[0].drawable->bpp + sample]);
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
1999-09-18 06:28:25 +08:00
|
|
|
} else {
|
|
|
|
for (col = 0; col < cols; ++col)
|
|
|
|
NEXTSAMPLE(dest[col]);
|
1998-11-09 10:05:24 +08:00
|
|
|
}
|
|
|
|
}
|
1999-09-18 06:28:25 +08:00
|
|
|
gimp_pixel_rgn_set_rect(&(channel[c].pixel_rgn), channel[c].pixels,
|
|
|
|
startcol, startrow, cols, rows);
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
** pnmtotiff.c - converts a portable anymap to a Tagged Image File
|
|
|
|
**
|
|
|
|
** Derived by Jef Poskanzer from ras2tif.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.
|
|
|
|
*/
|
|
|
|
|
2000-05-02 04:22:55 +08:00
|
|
|
static gint
|
|
|
|
save_image (gchar *filename,
|
|
|
|
gint32 image,
|
|
|
|
gint32 layer,
|
|
|
|
gint32 orig_image) /* the export function might have created a duplicate */
|
1999-10-04 02:54:54 +08:00
|
|
|
{
|
2000-05-02 04:22:55 +08:00
|
|
|
TIFF *tif;
|
|
|
|
gushort red[256];
|
|
|
|
gushort grn[256];
|
|
|
|
gushort blu[256];
|
|
|
|
gint cols, col, rows, row, i;
|
|
|
|
glong rowsperstrip;
|
|
|
|
gushort compression;
|
|
|
|
gushort extra_samples[1];
|
|
|
|
gint alpha;
|
|
|
|
gshort predictor;
|
|
|
|
gshort photometric;
|
|
|
|
gshort samplesperpixel;
|
|
|
|
gshort bitspersample;
|
|
|
|
gint bytesperrow;
|
|
|
|
guchar *t, *src, *data;
|
|
|
|
guchar *cmap;
|
|
|
|
gint colors;
|
|
|
|
gint success;
|
2000-08-22 09:26:57 +08:00
|
|
|
GimpDrawable *drawable;
|
|
|
|
GimpImageType drawable_type;
|
|
|
|
GimpPixelRgn pixel_rgn;
|
2000-05-02 04:22:55 +08:00
|
|
|
gint tile_height;
|
|
|
|
gint y, yend;
|
|
|
|
gchar *name;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
compression = tsvals.compression;
|
2000-05-12 14:53:15 +08:00
|
|
|
|
|
|
|
/* Disabled because this isn't in older releases of libtiff, and it
|
|
|
|
wasn't helping much anyway */
|
|
|
|
#if 0
|
2000-04-20 12:38:31 +08:00
|
|
|
if (TIFFFindCODEC((uint16) compression) == NULL)
|
|
|
|
compression = COMPRESSION_NONE; /* CODEC not available */
|
2000-05-12 14:53:15 +08:00
|
|
|
#endif
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
predictor = 0;
|
2000-04-20 12:38:31 +08:00
|
|
|
tile_height = gimp_tile_height ();
|
|
|
|
rowsperstrip = tile_height;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
libgimp/gimp.def libgimp/gimpui.def libgimp/makefile.{cygwin,msc}
2000-02-15 Tor Lillqvist <tml@iki.fi>
* libgimp/gimp.def
* libgimp/gimpui.def
* libgimp/makefile.{cygwin,msc}
* app/makefile.{cygwin,msc}
* plug-ins/makefile.{cygwin,msc}: Updates.
* app/datafiles.c (is_script): New Win32-only function, which
tests if a file's extension matches one of the extensions in the
PATHEXT environment variable (which the cmd.exe command
interpreter also uses). This is to avoid starting applications
associated with any random data file the user might have dropped
in the plug-ins folder, while still supporting plug-ins written in
scripting languages.
* app/gimpparasite.c (gimp_parasiterc_save): (Win32:) Cannot
rename to an existing file.
* plug-ins/Lighting/lighting_image.c
* plug-ins/Lighting/lighting_share.c
* plug-ins/MapObject/mapobject_preview.c
* plug-ins/MapObject/mapobject_shade.c: Use G_PI.
* plug-ins/common/gz.c: #ifdef G_OS_WIN32 was used before its
potential definition via glib.h.
* plug-ins/common/jpeg.c: Also recognize Exif files, which are
typically produced by digital cameras. The usually have a .jpg
file name extension, and would thus already match this plug-in,
but add the magic string just in case. They are loaded just fine
by libjpeg even if they don't have the JFIF signature.
* plug-ins/common/tiff.c: Set TIFF warning and error handler, so
we get to pass libtiff's messages through the normal channels.
2000-02-15 06:44:06 +08:00
|
|
|
TIFFSetWarningHandler (tiff_warning);
|
|
|
|
TIFFSetErrorHandler (tiff_error);
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
tif = TIFFOpen (filename, "w");
|
1999-10-04 02:54:54 +08:00
|
|
|
if (!tif)
|
|
|
|
{
|
|
|
|
g_print ("Can't write image to\n%s", filename);
|
|
|
|
return 0;
|
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-01-09 14:02:20 +08:00
|
|
|
name = g_strdup_printf( _("Saving %s:"), filename);
|
1997-11-25 06:05:25 +08:00
|
|
|
gimp_progress_init (name);
|
2000-05-02 04:22:55 +08:00
|
|
|
g_free (name);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
1998-05-18 08:54:11 +08:00
|
|
|
drawable = gimp_drawable_get (layer);
|
|
|
|
drawable_type = gimp_drawable_type (layer);
|
2000-05-02 04:22:55 +08:00
|
|
|
gimp_pixel_rgn_init (&pixel_rgn, drawable,
|
|
|
|
0, 0, drawable->width, drawable->height, FALSE, FALSE);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
cols = drawable->width;
|
|
|
|
rows = drawable->height;
|
|
|
|
|
|
|
|
switch (drawable_type)
|
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_RGB_IMAGE:
|
1999-01-12 10:13:18 +08:00
|
|
|
predictor = 2;
|
1997-11-25 06:05:25 +08:00
|
|
|
samplesperpixel = 3;
|
|
|
|
bitspersample = 8;
|
|
|
|
photometric = PHOTOMETRIC_RGB;
|
|
|
|
bytesperrow = cols * 3;
|
|
|
|
alpha = 0;
|
|
|
|
break;
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_GRAY_IMAGE:
|
1997-11-25 06:05:25 +08:00
|
|
|
samplesperpixel = 1;
|
|
|
|
bitspersample = 8;
|
|
|
|
photometric = PHOTOMETRIC_MINISBLACK;
|
|
|
|
bytesperrow = cols;
|
|
|
|
alpha = 0;
|
|
|
|
break;
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_RGBA_IMAGE:
|
1999-01-12 10:13:18 +08:00
|
|
|
predictor = 2;
|
1997-11-25 06:05:25 +08:00
|
|
|
samplesperpixel = 4;
|
|
|
|
bitspersample = 8;
|
|
|
|
photometric = PHOTOMETRIC_RGB;
|
|
|
|
bytesperrow = cols * 4;
|
|
|
|
alpha = 1;
|
|
|
|
break;
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_GRAYA_IMAGE:
|
1997-11-25 06:05:25 +08:00
|
|
|
samplesperpixel = 2;
|
|
|
|
bitspersample = 8;
|
|
|
|
photometric = PHOTOMETRIC_MINISBLACK;
|
|
|
|
bytesperrow = cols * 2;
|
|
|
|
alpha = 1;
|
|
|
|
break;
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_INDEXED_IMAGE:
|
1997-11-25 06:05:25 +08:00
|
|
|
samplesperpixel = 1;
|
|
|
|
bitspersample = 8;
|
|
|
|
photometric = PHOTOMETRIC_PALETTE;
|
|
|
|
bytesperrow = cols;
|
|
|
|
alpha = 0;
|
|
|
|
|
1998-05-18 08:54:11 +08:00
|
|
|
cmap = gimp_image_get_cmap (image, &colors);
|
1997-11-25 06:05:25 +08:00
|
|
|
|
|
|
|
for (i = 0; i < colors; i++)
|
|
|
|
{
|
1998-04-27 07:28:04 +08:00
|
|
|
red[i] = *cmap++ * 65535 / 255;
|
|
|
|
grn[i] = *cmap++ * 65535 / 255;
|
|
|
|
blu[i] = *cmap++ * 65535 / 255;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
break;
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_INDEXEDA_IMAGE:
|
1997-11-25 06:05:25 +08:00
|
|
|
return 0;
|
1998-10-08 16:15:21 +08:00
|
|
|
default:
|
1999-09-18 06:28:25 +08:00
|
|
|
return 0;
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set TIFF parameters. */
|
2000-01-30 13:01:58 +08:00
|
|
|
TIFFSetField (tif, TIFFTAG_SUBFILETYPE, 0);
|
1997-11-25 06:05:25 +08:00
|
|
|
TIFFSetField (tif, TIFFTAG_IMAGEWIDTH, cols);
|
|
|
|
TIFFSetField (tif, TIFFTAG_IMAGELENGTH, rows);
|
|
|
|
TIFFSetField (tif, TIFFTAG_BITSPERSAMPLE, bitspersample);
|
|
|
|
TIFFSetField (tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
|
|
|
|
TIFFSetField (tif, TIFFTAG_COMPRESSION, compression);
|
2000-04-20 12:38:31 +08:00
|
|
|
if ((compression == COMPRESSION_LZW || compression == COMPRESSION_DEFLATE)
|
|
|
|
&& (predictor != 0)) {
|
1997-11-25 06:05:25 +08:00
|
|
|
TIFFSetField (tif, TIFFTAG_PREDICTOR, predictor);
|
2000-04-20 12:38:31 +08:00
|
|
|
}
|
|
|
|
if (alpha) {
|
1997-11-25 06:05:25 +08:00
|
|
|
extra_samples [0] = EXTRASAMPLE_ASSOCALPHA;
|
|
|
|
TIFFSetField (tif, TIFFTAG_EXTRASAMPLES, 1, extra_samples);
|
2000-04-20 12:38:31 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
TIFFSetField (tif, TIFFTAG_PHOTOMETRIC, photometric);
|
|
|
|
TIFFSetField (tif, TIFFTAG_DOCUMENTNAME, filename);
|
|
|
|
TIFFSetField (tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
|
|
|
|
TIFFSetField (tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip);
|
|
|
|
/* TIFFSetField( tif, TIFFTAG_STRIPBYTECOUNTS, rows / rowsperstrip ); */
|
|
|
|
TIFFSetField (tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
|
|
|
|
1998-11-09 10:05:24 +08:00
|
|
|
#ifdef GIMP_HAVE_RESOLUTION_INFO
|
1998-10-05 18:05:29 +08:00
|
|
|
/* resolution fields */
|
|
|
|
{
|
2000-02-08 04:35:13 +08:00
|
|
|
gdouble xresolution;
|
|
|
|
gdouble yresolution;
|
|
|
|
gushort save_unit = RESUNIT_INCH;
|
|
|
|
GimpUnit unit;
|
|
|
|
gfloat factor;
|
1999-05-23 01:56:35 +08:00
|
|
|
|
1999-10-04 02:54:54 +08:00
|
|
|
gimp_image_get_resolution (orig_image, &xresolution, &yresolution);
|
|
|
|
unit = gimp_image_get_unit (orig_image);
|
1999-05-23 01:56:35 +08:00
|
|
|
factor = gimp_unit_get_factor (unit);
|
|
|
|
|
|
|
|
/* if we have a metric unit, save the resolution as centimeters
|
|
|
|
*/
|
2000-02-08 04:35:13 +08:00
|
|
|
if ((ABS (factor - 0.0254) < 1e-5) || /* m */
|
|
|
|
(ABS (factor - 0.254) < 1e-5) || /* dm */
|
|
|
|
(ABS (factor - 2.54) < 1e-5) || /* cm */
|
|
|
|
(ABS (factor - 25.4) < 1e-5)) /* mm */
|
1999-05-23 01:56:35 +08:00
|
|
|
{
|
|
|
|
save_unit = RESUNIT_CENTIMETER;
|
|
|
|
xresolution /= 2.54;
|
|
|
|
yresolution /= 2.54;
|
|
|
|
}
|
1998-11-15 07:28:47 +08:00
|
|
|
|
1999-05-23 01:56:35 +08:00
|
|
|
if (xresolution > 1e-5 && yresolution > 1e-5)
|
1998-10-05 18:05:29 +08:00
|
|
|
{
|
1999-05-23 01:56:35 +08:00
|
|
|
TIFFSetField (tif, TIFFTAG_XRESOLUTION, xresolution);
|
|
|
|
TIFFSetField (tif, TIFFTAG_YRESOLUTION, yresolution);
|
|
|
|
TIFFSetField (tif, TIFFTAG_RESOLUTIONUNIT, save_unit);
|
1998-10-05 18:05:29 +08:00
|
|
|
}
|
|
|
|
}
|
1998-11-13 12:00:54 +08:00
|
|
|
#endif /* GIMP_HAVE_RESOLUTION_INFO */
|
1998-10-05 18:05:29 +08:00
|
|
|
|
1998-10-12 06:50:03 +08:00
|
|
|
/* do we have a comment? If so, create a new parasite to hold it,
|
|
|
|
* and attach it to the image. The attach function automatically
|
|
|
|
* detaches a previous incarnation of the parasite. */
|
1998-11-09 10:05:24 +08:00
|
|
|
#ifdef GIMP_HAVE_PARASITES
|
1998-10-12 06:50:03 +08:00
|
|
|
if (image_comment && *image_comment != '\000')
|
1999-10-04 02:54:54 +08:00
|
|
|
{
|
2000-05-27 06:28:40 +08:00
|
|
|
GimpParasite *parasite;
|
1999-10-04 02:54:54 +08:00
|
|
|
|
|
|
|
TIFFSetField (tif, TIFFTAG_IMAGEDESCRIPTION, image_comment);
|
2000-05-27 06:28:40 +08:00
|
|
|
parasite = gimp_parasite_new ("gimp-comment",
|
|
|
|
GIMP_PARASITE_PERSISTENT,
|
|
|
|
strlen (image_comment) + 1, image_comment);
|
1999-10-17 08:07:55 +08:00
|
|
|
gimp_image_parasite_attach (orig_image, parasite);
|
2000-05-27 06:28:40 +08:00
|
|
|
gimp_parasite_free (parasite);
|
1999-10-04 02:54:54 +08:00
|
|
|
}
|
1998-11-09 10:05:24 +08:00
|
|
|
#endif /* GIMP_HAVE_PARASITES */
|
1998-10-12 06:50:03 +08:00
|
|
|
|
2000-06-18 09:07:13 +08:00
|
|
|
/* do we have an ICC profile? If so, write it to the TIFF file */
|
|
|
|
#ifdef GIMP_HAVE_PARASITES
|
|
|
|
#ifdef TIFFTAG_ICCPROFILE
|
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
GimpParasite *parasite;
|
2000-06-18 09:07:13 +08:00
|
|
|
uint32 profile_size;
|
|
|
|
guchar *icc_profile;
|
|
|
|
|
|
|
|
parasite = gimp_image_parasite_find (orig_image, "icc-profile");
|
|
|
|
if (parasite)
|
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
profile_size = gimp_parasite_data_size(parasite);
|
|
|
|
icc_profile = gimp_parasite_data(parasite);
|
2000-06-18 09:07:13 +08:00
|
|
|
|
|
|
|
TIFFSetField(tif, TIFFTAG_ICCPROFILE, profile_size, icc_profile);
|
2000-08-22 09:26:57 +08:00
|
|
|
gimp_parasite_free(parasite);
|
2000-06-18 09:07:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2000-08-22 09:26:57 +08:00
|
|
|
if (drawable_type == GIMP_INDEXED_IMAGE)
|
1997-11-25 06:05:25 +08:00
|
|
|
TIFFSetField (tif, TIFFTAG_COLORMAP, red, grn, blu);
|
|
|
|
|
|
|
|
/* array to rearrange data */
|
|
|
|
src = g_new (guchar, bytesperrow * tile_height);
|
|
|
|
data = g_new (guchar, bytesperrow);
|
|
|
|
|
|
|
|
/* Now write the TIFF data. */
|
|
|
|
for (y = 0; y < rows; y = yend)
|
|
|
|
{
|
|
|
|
yend = y + tile_height;
|
|
|
|
yend = MIN (yend, rows);
|
|
|
|
|
|
|
|
gimp_pixel_rgn_get_rect (&pixel_rgn, src, 0, y, cols, yend - y);
|
|
|
|
|
|
|
|
for (row = y; row < yend; row++)
|
|
|
|
{
|
|
|
|
t = src + bytesperrow * (row - y);
|
|
|
|
|
|
|
|
switch (drawable_type)
|
|
|
|
{
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_INDEXED_IMAGE:
|
1997-11-25 06:05:25 +08:00
|
|
|
success = (TIFFWriteScanline (tif, t, row, 0) >= 0);
|
|
|
|
break;
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_GRAY_IMAGE:
|
1997-11-25 06:05:25 +08:00
|
|
|
success = (TIFFWriteScanline (tif, t, row, 0) >= 0);
|
|
|
|
break;
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_GRAYA_IMAGE:
|
1997-11-25 06:05:25 +08:00
|
|
|
for (col = 0; col < cols*samplesperpixel; col+=samplesperpixel)
|
|
|
|
{
|
|
|
|
/* pre-multiply gray by alpha */
|
|
|
|
data[col + 0] = (t[col + 0] * t[col + 1]) / 255;
|
|
|
|
data[col + 1] = t[col + 1]; /* alpha channel */
|
|
|
|
}
|
|
|
|
success = (TIFFWriteScanline (tif, data, row, 0) >= 0);
|
|
|
|
break;
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_RGB_IMAGE:
|
1997-11-25 06:05:25 +08:00
|
|
|
success = (TIFFWriteScanline (tif, t, row, 0) >= 0);
|
|
|
|
break;
|
2000-08-22 09:26:57 +08:00
|
|
|
case GIMP_RGBA_IMAGE:
|
1997-11-25 06:05:25 +08:00
|
|
|
for (col = 0; col < cols*samplesperpixel; col+=samplesperpixel)
|
|
|
|
{
|
|
|
|
/* pre-multiply rgb by alpha */
|
|
|
|
data[col+0] = t[col + 0] * t[col + 3] / 255;
|
|
|
|
data[col+1] = t[col + 1] * t[col + 3] / 255;
|
|
|
|
data[col+2] = t[col + 2] * t[col + 3] / 255;
|
|
|
|
data[col+3] = t[col + 3]; /* alpha channel */
|
|
|
|
}
|
|
|
|
success = (TIFFWriteScanline (tif, data, row, 0) >= 0);
|
|
|
|
break;
|
|
|
|
default:
|
1998-10-12 06:50:03 +08:00
|
|
|
success = FALSE;
|
1997-11-25 06:05:25 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
1998-05-31 14:49:20 +08:00
|
|
|
if (!success) {
|
2000-05-02 04:22:55 +08:00
|
|
|
g_message ("TIFF Failed a scanline write on row %d", row);
|
|
|
|
return 0;
|
1998-05-31 14:49:20 +08:00
|
|
|
}
|
1997-11-25 06:05:25 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
gimp_progress_update ((double) row / (double) rows);
|
|
|
|
}
|
|
|
|
|
|
|
|
TIFFFlushData (tif);
|
|
|
|
TIFFClose (tif);
|
|
|
|
|
|
|
|
gimp_drawable_detach (drawable);
|
|
|
|
g_free (data);
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gint
|
2000-01-09 04:00:10 +08:00
|
|
|
save_dialog (void)
|
1997-11-25 06:05:25 +08:00
|
|
|
{
|
|
|
|
GtkWidget *dlg;
|
2000-01-26 01:46:56 +08:00
|
|
|
GtkWidget *vbox;
|
1997-11-25 06:05:25 +08:00
|
|
|
GtkWidget *frame;
|
1998-10-12 06:50:03 +08:00
|
|
|
GtkWidget *hbox;
|
|
|
|
GtkWidget *label;
|
|
|
|
GtkWidget *entry;
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-01-09 14:02:20 +08:00
|
|
|
dlg = gimp_dialog_new ( _("Save as TIFF"), "tiff",
|
2000-05-23 01:10:28 +08:00
|
|
|
gimp_standard_help_func, "filters/tiff.html",
|
2000-01-09 04:00:10 +08:00
|
|
|
GTK_WIN_POS_MOUSE,
|
|
|
|
FALSE, TRUE, FALSE,
|
|
|
|
|
2000-01-09 14:02:20 +08:00
|
|
|
_("OK"), save_ok_callback,
|
2000-01-09 04:00:10 +08:00
|
|
|
NULL, NULL, NULL, TRUE, FALSE,
|
2000-01-09 14:02:20 +08:00
|
|
|
_("Cancel"), gtk_widget_destroy,
|
2000-01-09 04:00:10 +08:00
|
|
|
NULL, 1, NULL, FALSE, TRUE,
|
|
|
|
|
|
|
|
NULL);
|
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
|
2000-01-09 04:00:10 +08:00
|
|
|
GTK_SIGNAL_FUNC (gtk_main_quit),
|
1997-11-25 06:05:25 +08:00
|
|
|
NULL);
|
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
vbox = gtk_vbox_new (FALSE, 4);
|
|
|
|
gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
|
|
|
|
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), vbox, FALSE, TRUE, 0);
|
1998-10-12 06:50:03 +08:00
|
|
|
|
1997-11-25 06:05:25 +08:00
|
|
|
/* compression */
|
2000-01-26 01:46:56 +08:00
|
|
|
frame =
|
|
|
|
gimp_radio_group_new2 (TRUE, _("Compression"),
|
|
|
|
gimp_radio_button_update,
|
|
|
|
&tsvals.compression, (gpointer) tsvals.compression,
|
1997-11-25 06:05:25 +08:00
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
_("None"), (gpointer) COMPRESSION_NONE, NULL,
|
|
|
|
_("LZW"), (gpointer) COMPRESSION_LZW, NULL,
|
|
|
|
_("Pack Bits"), (gpointer) COMPRESSION_PACKBITS, NULL,
|
2000-04-20 12:38:31 +08:00
|
|
|
_("Deflate"), (gpointer) COMPRESSION_DEFLATE, NULL,
|
|
|
|
_("JPEG"), (gpointer) COMPRESSION_JPEG, NULL,
|
1998-10-12 06:50:03 +08:00
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
NULL);
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
|
|
|
|
gtk_widget_show (frame);
|
1998-10-12 06:50:03 +08:00
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
/* comment entry */
|
2000-01-09 04:00:10 +08:00
|
|
|
hbox = gtk_hbox_new (FALSE, 4);
|
2000-01-26 01:46:56 +08:00
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
|
2000-01-09 04:00:10 +08:00
|
|
|
gtk_widget_show (hbox);
|
|
|
|
|
2000-01-09 14:02:20 +08:00
|
|
|
label = gtk_label_new ( _("Comment:"));
|
2000-01-09 04:00:10 +08:00
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
1998-10-12 06:50:03 +08:00
|
|
|
gtk_widget_show (label);
|
2000-01-09 04:00:10 +08:00
|
|
|
|
1998-10-12 06:50:03 +08:00
|
|
|
entry = gtk_entry_new ();
|
|
|
|
gtk_widget_show (entry);
|
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
|
|
|
|
gtk_entry_set_text (GTK_ENTRY (entry), image_comment);
|
|
|
|
gtk_signal_connect (GTK_OBJECT (entry), "changed",
|
2000-01-26 01:46:56 +08:00
|
|
|
GTK_SIGNAL_FUNC (comment_entry_callback),
|
1998-10-12 06:50:03 +08:00
|
|
|
NULL);
|
|
|
|
|
|
|
|
gtk_widget_show (frame);
|
|
|
|
|
2000-01-26 01:46:56 +08:00
|
|
|
gtk_widget_show (vbox);
|
1997-11-25 06:05:25 +08:00
|
|
|
gtk_widget_show (dlg);
|
|
|
|
|
|
|
|
gtk_main ();
|
|
|
|
gdk_flush ();
|
|
|
|
|
|
|
|
return tsint.run;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
save_ok_callback (GtkWidget *widget,
|
|
|
|
gpointer data)
|
|
|
|
{
|
|
|
|
tsint.run = TRUE;
|
|
|
|
gtk_widget_destroy (GTK_WIDGET (data));
|
|
|
|
}
|
|
|
|
|
1998-10-12 06:50:03 +08:00
|
|
|
static void
|
|
|
|
comment_entry_callback (GtkWidget *widget,
|
|
|
|
gpointer data)
|
|
|
|
{
|
2000-01-26 01:46:56 +08:00
|
|
|
gint len;
|
|
|
|
gchar *text;
|
1998-10-12 06:50:03 +08:00
|
|
|
|
|
|
|
text = gtk_entry_get_text (GTK_ENTRY (widget));
|
2000-01-26 01:46:56 +08:00
|
|
|
len = strlen (text);
|
1998-10-12 06:50:03 +08:00
|
|
|
|
|
|
|
/* Temporary kludge for overlength strings - just return */
|
|
|
|
if (len > 240)
|
|
|
|
{
|
|
|
|
g_message ("TIFF save: Your comment string is too long.\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-10-04 02:54:54 +08:00
|
|
|
g_free (image_comment);
|
|
|
|
image_comment = g_strdup (text);
|
1998-10-12 06:50:03 +08:00
|
|
|
|
|
|
|
/* g_print ("COMMENT: %s\n", image_comment); */
|
|
|
|
}
|