file-pnm: Add support for saving PFM (portable floatmap) files in color and gray

This commit is contained in:
Mukund Sivaraman 2015-01-20 20:14:07 +05:30
parent b6095b6fa5
commit 51e4491fbf
1 changed files with 225 additions and 104 deletions

View File

@ -44,6 +44,7 @@
#define PBM_SAVE_PROC "file-pbm-save"
#define PGM_SAVE_PROC "file-pgm-save"
#define PPM_SAVE_PROC "file-ppm-save"
#define PFM_SAVE_PROC "file-pfm-save"
#define PLUG_IN_BINARY "file-pnm"
#define PLUG_IN_ROLE "gimp-file-pnm"
@ -112,9 +113,6 @@ typedef struct
* by the spec anyways so this shouldn't
* be an issue. */
#define SAVE_COMMENT_STRING "# CREATOR: GIMP PNM Filter Version 1.1\n"
/* Declare some local functions.
*/
static void query (void);
@ -129,6 +127,7 @@ static gint save_image (GFile *file,
gint32 image_ID,
gint32 drawable_ID,
gboolean pbm,
gboolean float_format,
GError **error);
static gboolean save_dialog (void);
@ -247,6 +246,15 @@ query (void)
{ GIMP_PDB_INT32, "raw", "TRUE for raw output, FALSE for ascii output" }
};
static const GimpParamDef pfm_save_args[] =
{
{ GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
{ 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_install_procedure (LOAD_PROC,
"Loads files in the PNM file format",
"This plug-in loads files in the various Netpbm portable file formats.",
@ -317,20 +325,35 @@ query (void)
G_N_ELEMENTS (save_args), 0,
save_args, NULL);
gimp_install_procedure (PFM_SAVE_PROC,
"Saves files in the PFM file format",
"PFM saving handles all images without transparency.",
"Mukund Sivaraman",
"Mukund Sivaraman",
"2015",
N_("PFM image"),
"RGB, GRAY, INDEXED",
GIMP_PLUGIN,
G_N_ELEMENTS (pfm_save_args), 0,
pfm_save_args, NULL);
gimp_register_file_handler_mime (PNM_SAVE_PROC, "image/x-portable-anymap");
gimp_register_file_handler_mime (PBM_SAVE_PROC, "image/x-portable-bitmap");
gimp_register_file_handler_mime (PGM_SAVE_PROC, "image/x-portable-graymap");
gimp_register_file_handler_mime (PPM_SAVE_PROC, "image/x-portable-pixmap");
gimp_register_file_handler_mime (PPM_SAVE_PROC, "image/x-portable-floatmap");
gimp_register_file_handler_uri (PNM_SAVE_PROC);
gimp_register_file_handler_uri (PBM_SAVE_PROC);
gimp_register_file_handler_uri (PGM_SAVE_PROC);
gimp_register_file_handler_uri (PPM_SAVE_PROC);
gimp_register_file_handler_uri (PFM_SAVE_PROC);
gimp_register_save_handler (PNM_SAVE_PROC, "pnm", "");
gimp_register_save_handler (PBM_SAVE_PROC, "pbm", "");
gimp_register_save_handler (PGM_SAVE_PROC, "pgm", "");
gimp_register_save_handler (PPM_SAVE_PROC, "ppm", "");
gimp_register_save_handler (PFM_SAVE_PROC, "pfm", "");
}
static void
@ -342,12 +365,13 @@ run (const gchar *name,
{
static GimpParam values[2];
GimpRunMode run_mode;
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
gint32 image_ID;
gint32 drawable_ID;
GimpExportReturn export = GIMP_EXPORT_CANCEL;
GError *error = NULL;
gboolean pbm = FALSE; /* flag for PBM output */
GimpExportReturn export = GIMP_EXPORT_CANCEL;
GError *error = NULL;
gboolean pbm = FALSE; /* flag for PBM output */
gboolean float_format = FALSE; /* flag for PFM output */
INIT_I18N ();
gegl_init (NULL, NULL);
@ -378,7 +402,8 @@ run (const gchar *name,
else if (strcmp (name, PNM_SAVE_PROC) == 0 ||
strcmp (name, PBM_SAVE_PROC) == 0 ||
strcmp (name, PGM_SAVE_PROC) == 0 ||
strcmp (name, PPM_SAVE_PROC) == 0)
strcmp (name, PPM_SAVE_PROC) == 0 ||
strcmp (name, PFM_SAVE_PROC) == 0)
{
image_ID = param[1].data.d_int32;
drawable_ID = param[2].data.d_int32;
@ -408,12 +433,19 @@ run (const gchar *name,
export = gimp_export_image (&image_ID, &drawable_ID, "PGM",
GIMP_EXPORT_CAN_HANDLE_GRAY);
}
else
else if (strcmp (name, PPM_SAVE_PROC) == 0)
{
export = gimp_export_image (&image_ID, &drawable_ID, "PPM",
GIMP_EXPORT_CAN_HANDLE_RGB |
GIMP_EXPORT_CAN_HANDLE_INDEXED);
}
else
{
export = gimp_export_image (&image_ID, &drawable_ID, "PFM",
GIMP_EXPORT_CAN_HANDLE_RGB |
GIMP_EXPORT_CAN_HANDLE_GRAY);
float_format = TRUE;
}
if (export == GIMP_EXPORT_CANCEL)
{
@ -426,47 +458,69 @@ run (const gchar *name,
break;
}
switch (run_mode)
if (strcmp (name, PFM_SAVE_PROC) != 0)
{
case GIMP_RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data (name, &psvals);
/* First acquire information with a dialog */
if (! save_dialog ())
status = GIMP_PDB_CANCEL;
break;
case GIMP_RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 6)
switch (run_mode)
{
status = GIMP_PDB_CALLING_ERROR;
case GIMP_RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data (name, &psvals);
/* First acquire information with a dialog */
if (! save_dialog ())
status = GIMP_PDB_CANCEL;
break;
case GIMP_RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 6)
{
status = GIMP_PDB_CALLING_ERROR;
}
else
{
psvals.raw = (param[5].data.d_int32) ? TRUE : FALSE;
pbm = (strcmp (name, PBM_SAVE_PROC) == 0);
}
break;
case GIMP_RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data (name, &psvals);
break;
default:
break;
}
else
}
else
{
switch (run_mode)
{
psvals.raw = (param[5].data.d_int32) ? TRUE : FALSE;
pbm = (strcmp (name, PBM_SAVE_PROC) == 0);
case GIMP_RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 5)
{
status = GIMP_PDB_CALLING_ERROR;
}
break;
default:
break;
}
break;
case GIMP_RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data (name, &psvals);
break;
default:
break;
}
if (status == GIMP_PDB_SUCCESS)
{
if (save_image (g_file_new_for_uri (param[3].data.d_string),
image_ID, drawable_ID, pbm,
image_ID, drawable_ID, pbm, float_format,
&error))
{
/* Store psvals data */
gimp_set_data (name, &psvals, sizeof (PNMSaveVals));
if (strcmp (name, PFM_SAVE_PROC) != 0)
{
/* Store psvals data */
gimp_set_data (name, &psvals, sizeof (PNMSaveVals));
}
}
else
{
@ -1044,6 +1098,17 @@ pnmsaverow_raw (PNMRowInfo *ri,
return output_write (ri->output, data, ri->xres * ri->np, error);
}
/* Writes out RGB and grayscale float rows */
static gboolean
pnmsaverow_float (PNMRowInfo *ri,
const float *data,
GError **error)
{
return output_write (ri->output, data,
ri->xres * ri->np * sizeof (float),
error);
}
/* Writes out indexed raw rows */
static gboolean
pnmsaverow_raw_indexed (PNMRowInfo *ri,
@ -1110,10 +1175,12 @@ save_image (GFile *file,
gint32 image_ID,
gint32 drawable_ID,
gboolean pbm,
gboolean float_format,
GError **error)
{
GOutputStream *output;
GeglBuffer *buffer;
gboolean status = FALSE;
GOutputStream *output = NULL;
GeglBuffer *buffer = NULL;
const Babl *format;
const gchar *header_string = NULL;
GimpImageType drawable_type;
@ -1122,20 +1189,18 @@ save_image (GFile *file,
guchar red[256];
guchar grn[256];
guchar blu[256];
guchar *data;
guchar *d;
gchar *rowbuf;
gchar buf[BUFLEN];
gint np = 0;
gint xres, yres;
gint ypos, yend;
gint rowbufsize = 0;
gchar *comment = NULL;
/* Make sure we're not saving an image with an alpha channel */
if (gimp_drawable_has_alpha (drawable_ID))
{
g_message (_("Cannot save images with alpha channel."));
return FALSE;
goto out;
}
gimp_progress_init_printf (_("Saving '%s'"),
@ -1146,7 +1211,7 @@ save_image (GFile *file,
NULL, FALSE, G_FILE_CREATE_NONE,
NULL, error));
if (! output)
return FALSE;
goto out;
buffer = gimp_drawable_get_buffer (drawable_ID);
@ -1156,7 +1221,7 @@ save_image (GFile *file,
drawable_type = gimp_drawable_type (drawable_ID);
/* write out magic number */
if (!psvals.raw)
if (!float_format && !psvals.raw)
{
if (pbm)
{
@ -1196,11 +1261,11 @@ save_image (GFile *file,
default:
g_warning ("PNM: Unknown drawable_type\n");
return FALSE;
goto out;
}
}
}
else
else if (!float_format)
{
if (pbm)
{
@ -1240,17 +1305,34 @@ save_image (GFile *file,
default:
g_warning ("PNM: Unknown drawable_type\n");
return FALSE;
goto out;
}
}
}
else
{
switch (drawable_type)
{
case GIMP_GRAY_IMAGE:
header_string = "Pf\n";
format = babl_format ("Y float");
np = 1;
break;
case GIMP_RGB_IMAGE:
header_string = "PF\n";
format = babl_format ("RGB float");
np = 3;
break;
default:
g_warning ("PFM: Unknown drawable_type\n");
goto out;
}
}
if (! output_write (output, header_string, strlen (header_string), error))
{
g_object_unref (output);
g_object_unref (buffer);
return FALSE;
}
goto out;
rowinfo.zero_is_black = FALSE;
@ -1307,81 +1389,120 @@ save_image (GFile *file,
}
/* write out comment string */
if (! output_write (output, SAVE_COMMENT_STRING, strlen (SAVE_COMMENT_STRING),
error))
{
g_object_unref (output);
g_object_unref (buffer);
return FALSE;
}
comment = g_strdup_printf("# Created by GIMP version %s PNM plug-in\n",
GIMP_VERSION);
if (! output_write (output, comment, strlen (comment), error))
goto out;
/* write out resolution and maxval */
if (pbm)
g_snprintf (buf, sizeof (buf), "%d %d\n", xres, yres);
else
else if (!float_format)
g_snprintf (buf, sizeof (buf), "%d %d\n255\n", xres, yres);
else
g_snprintf (buf, sizeof (buf), "%d %d\n%f\n", xres, yres,
G_BYTE_ORDER == G_BIG_ENDIAN ? 1.0f : -1.0f);
if (! output_write (output, buf, strlen (buf), error))
goto out;
if (!float_format)
{
g_object_unref (output);
g_object_unref (buffer);
return FALSE;
}
guchar *data;
guchar *d;
gchar *rowbuf = NULL;
/* allocate a buffer for retrieving information from the pixel region */
data = g_new (guchar,
gimp_tile_height () * xres *
babl_format_get_bytes_per_pixel (format));
/* allocate a buffer for retrieving information from the pixel region */
data = g_new (guchar,
gimp_tile_height () * xres *
babl_format_get_bytes_per_pixel (format));
rowbuf = g_new (gchar, rowbufsize + 1);
rowbuf = g_new (gchar, rowbufsize + 1);
rowinfo.output = output;
rowinfo.rowbuf = rowbuf;
rowinfo.xres = xres;
rowinfo.np = np;
rowinfo.output = output;
rowinfo.rowbuf = rowbuf;
rowinfo.xres = xres;
rowinfo.np = np;
d = NULL; /* only to please the compiler */
d = NULL; /* only to please the compiler */
/* Write the body out */
for (ypos = 0; ypos < yres; ypos++)
{
if ((ypos % gimp_tile_height ()) == 0)
/* Write the body out */
for (ypos = 0; ypos < yres; ypos++)
{
yend = ypos + gimp_tile_height ();
yend = MIN (yend, yres);
if ((ypos % gimp_tile_height ()) == 0)
{
yend = ypos + gimp_tile_height ();
yend = MIN (yend, yres);
gegl_buffer_get (buffer,
GEGL_RECTANGLE (0, ypos, xres, yend - ypos), 1.0,
format, data,
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
d = data;
}
if (! saverow (&rowinfo, d, error))
{
g_free (rowbuf);
g_free (data);
goto out;
}
d += xres * (np ? np : 1);
if (ypos % 32 == 0)
gimp_progress_update ((double) ypos / (double) yres);
}
g_free (rowbuf);
g_free (data);
}
else
{
/* allocate a buffer for retrieving information from the pixel
region */
gfloat *data = g_new (gfloat, xres * np);
rowinfo.output = output;
rowinfo.rowbuf = NULL;
rowinfo.xres = xres;
rowinfo.np = np;
/* Write the body out in reverse row order */
for (ypos = yres - 1; ypos >= 0; ypos--)
{
gegl_buffer_get (buffer,
GEGL_RECTANGLE (0, ypos, xres, yend - ypos), 1.0,
GEGL_RECTANGLE (0, ypos, xres, 1), 1.0,
format, data,
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
d = data;
if (! pnmsaverow_float (&rowinfo, data, error))
{
g_free (data);
goto out;
}
if (ypos % 32 == 0)
gimp_progress_update ((double) (yres - ypos) / (double) yres);
}
if (! saverow (&rowinfo, d, error))
{
g_free (rowbuf);
g_free (data);
g_object_unref (output);
g_object_unref (buffer);
return FALSE;
}
d += xres * (np ? np : 1);
if (ypos % 32 == 0)
gimp_progress_update ((double) ypos / (double) yres);
g_free (data);
}
g_free (rowbuf);
g_free (data);
g_object_unref (buffer);
g_object_unref (output);
gimp_progress_update (1.0);
status = TRUE;
return TRUE;
out:
if (comment)
g_free (comment);
if (buffer)
g_object_unref (buffer);
if (output)
g_object_unref (output);
return status;
}
static gboolean