|
Packit Service |
2781ba |
/* This file is an image processing operation for GEGL
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* GEGL is free software; you can redistribute it and/or
|
|
Packit Service |
2781ba |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit Service |
2781ba |
* License as published by the Free Software Foundation; either
|
|
Packit Service |
2781ba |
* version 3 of the License, or (at your option) any later version.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* GEGL is distributed in the hope that it will be useful,
|
|
Packit Service |
2781ba |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
2781ba |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
2781ba |
* Lesser General Public License for more details.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
2781ba |
* License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit Service |
2781ba |
*
|
|
Packit Service |
2781ba |
* Copyright 2009 Henrik Akesson <h.m.akesson (a) gmail.com>
|
|
Packit Service |
2781ba |
*/
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include "config.h"
|
|
Packit Service |
2781ba |
#include <glib/gi18n-lib.h>
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#ifdef GEGL_CHANT_PROPERTIES
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_chant_file_path (path, _("File"), "", _("Path of file to load."))
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#else
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#define GEGL_CHANT_TYPE_SOURCE
|
|
Packit Service |
2781ba |
#define GEGL_CHANT_C_FILE "ppm-load.c"
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#define MAX_CHARS_IN_ROW 500
|
|
Packit Service |
2781ba |
#define CHANNEL_COUNT 3
|
|
Packit Service |
2781ba |
#define ASCII_P 80
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#include "gegl-chant.h"
|
|
Packit Service |
2781ba |
#include <stdio.h>
|
|
Packit Service |
2781ba |
#include <stdlib.h>
|
|
Packit Service |
3704c4 |
#include <errno.h>
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
typedef enum {
|
|
Packit Service |
2781ba |
PIXMAP_ASCII = 51,
|
|
Packit Service |
2781ba |
PIXMAP_RAW = 54,
|
|
Packit Service |
2781ba |
} map_type;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
typedef struct {
|
|
Packit Service |
2781ba |
map_type type;
|
|
Packit Service |
3704c4 |
glong width;
|
|
Packit Service |
3704c4 |
glong height;
|
|
Packit Service |
2781ba |
gsize numsamples; /* width * height * channels */
|
|
Packit Service |
2781ba |
gsize bpc; /* bytes per channel */
|
|
Packit Service |
2781ba |
guchar *data;
|
|
Packit Service |
2781ba |
} pnm_struct;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gboolean
|
|
Packit Service |
2781ba |
ppm_load_read_header(FILE *fp,
|
|
Packit Service |
2781ba |
pnm_struct *img)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
/* PPM Headers Variable Declaration */
|
|
Packit Service |
2781ba |
gchar *ptr;
|
|
Packit Service |
2781ba |
//gchar *retval;
|
|
Packit Service |
2781ba |
gchar header[MAX_CHARS_IN_ROW];
|
|
Packit Service |
2781ba |
gint maxval;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
3704c4 |
/* Check the PPM file Type P3 or P6 */
|
|
Packit Service |
2781ba |
fgets (header,MAX_CHARS_IN_ROW,fp);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (header[0] != ASCII_P ||
|
|
Packit Service |
2781ba |
(header[1] != PIXMAP_ASCII &&
|
|
Packit Service |
2781ba |
header[1] != PIXMAP_RAW))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_warning ("Image is not a portable pixmap");
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
img->type = header[1];
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Check the Comments */
|
|
Packit Service |
2781ba |
fgets (header,MAX_CHARS_IN_ROW,fp);
|
|
Packit Service |
2781ba |
while(header[0] == '#')
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
fgets (header,MAX_CHARS_IN_ROW,fp);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Get Width and Height */
|
|
Packit Service |
3704c4 |
errno = 0;
|
|
Packit Service |
3704c4 |
img->width = strtol (header,&ptr,10);
|
|
Packit Service |
3704c4 |
if (errno)
|
|
Packit Service |
3704c4 |
{
|
|
Packit Service |
3704c4 |
g_warning ("Error reading width: %s", strerror(errno));
|
|
Packit Service |
3704c4 |
return FALSE;
|
|
Packit Service |
3704c4 |
}
|
|
Packit Service |
3704c4 |
else if (img->width < 0)
|
|
Packit Service |
3704c4 |
{
|
|
Packit Service |
3704c4 |
g_warning ("Error: width is negative");
|
|
Packit Service |
3704c4 |
return FALSE;
|
|
Packit Service |
3704c4 |
}
|
|
Packit Service |
3704c4 |
|
|
Packit Service |
3704c4 |
img->height = strtol (ptr,&ptr,10);
|
|
Packit Service |
3704c4 |
if (errno)
|
|
Packit Service |
3704c4 |
{
|
|
Packit Service |
3704c4 |
g_warning ("Error reading height: %s", strerror(errno));
|
|
Packit Service |
3704c4 |
return FALSE;
|
|
Packit Service |
3704c4 |
}
|
|
Packit Service |
3704c4 |
else if (img->width < 0)
|
|
Packit Service |
3704c4 |
{
|
|
Packit Service |
3704c4 |
g_warning ("Error: height is negative");
|
|
Packit Service |
3704c4 |
return FALSE;
|
|
Packit Service |
3704c4 |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
fgets (header,MAX_CHARS_IN_ROW,fp);
|
|
Packit Service |
3704c4 |
maxval = strtol (header,&ptr,10);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if ((maxval != 255) && (maxval != 65535))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_warning ("Image is not an 8-bit or 16-bit portable pixmap");
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
switch (maxval)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
case 255:
|
|
Packit Service |
2781ba |
img->bpc = sizeof (guchar);
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
case 65535:
|
|
Packit Service |
2781ba |
img->bpc = sizeof (gushort);
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
default:
|
|
Packit Service |
2781ba |
g_warning ("%s: Programmer stupidity error", G_STRLOC);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
3704c4 |
/* Later on, img->numsamples is multiplied with img->bpc to allocate
|
|
Packit Service |
3704c4 |
* memory. Ensure it doesn't overflow. */
|
|
Packit Service |
3704c4 |
if (!img->width || !img->height ||
|
|
Packit Service |
3704c4 |
G_MAXSIZE / img->width / img->height / CHANNEL_COUNT < img->bpc)
|
|
Packit Service |
3704c4 |
{
|
|
Packit Service |
3704c4 |
g_warning ("Illegal width/height: %ld/%ld", img->width, img->height);
|
|
Packit Service |
3704c4 |
return FALSE;
|
|
Packit Service |
3704c4 |
}
|
|
Packit Service |
3704c4 |
img->numsamples = img->width * img->height * CHANNEL_COUNT;
|
|
Packit Service |
3704c4 |
|
|
Packit Service |
2781ba |
return TRUE;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
ppm_load_read_image(FILE *fp,
|
|
Packit Service |
2781ba |
pnm_struct *img)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
guint i;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (img->type == PIXMAP_RAW)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
fread (img->data, img->bpc, img->numsamples, fp);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Fix endianness if necessary */
|
|
Packit Service |
2781ba |
if (img->bpc > 1)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gushort *ptr = (gushort *) img->data;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (i=0; i < img->numsamples; i++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
*ptr = GUINT16_FROM_BE (*ptr);
|
|
Packit Service |
2781ba |
ptr++;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
/* Plain PPM format */
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (img->bpc == sizeof (guchar))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
guchar *ptr = img->data;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (i = 0; i < img->numsamples; i++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
guint sample;
|
|
Packit Service |
2781ba |
fscanf (fp, " %u", &sample);
|
|
Packit Service |
2781ba |
*ptr++ = sample;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else if (img->bpc == sizeof (gushort))
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
gushort *ptr = (gushort *) img->data;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
for (i = 0; i < img->numsamples; i++)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
guint sample;
|
|
Packit Service |
2781ba |
fscanf (fp, " %u", &sample);
|
|
Packit Service |
2781ba |
*ptr++ = sample;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
else
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
g_warning ("%s: Programmer stupidity error", G_STRLOC);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static GeglRectangle
|
|
Packit Service |
2781ba |
get_bounding_box (GeglOperation *operation)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
|
|
Packit Service |
2781ba |
GeglRectangle result = {0,0,0,0};
|
|
Packit Service |
2781ba |
pnm_struct img;
|
|
Packit Service |
2781ba |
FILE *fp;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
fp = (!strcmp (o->path, "-") ? stdin : fopen (o->path,"rb") );
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (!fp)
|
|
Packit Service |
2781ba |
return result;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (!ppm_load_read_header (fp, &img))
|
|
Packit Service |
2781ba |
goto out;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
switch (img.bpc)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
case 1:
|
|
Packit Service |
2781ba |
gegl_operation_set_format (operation, "output",
|
|
Packit Service |
2781ba |
babl_format ("R'G'B' u8"));
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
case 2:
|
|
Packit Service |
2781ba |
gegl_operation_set_format (operation, "output",
|
|
Packit Service |
2781ba |
babl_format ("R'G'B' u16"));
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
default:
|
|
Packit Service |
2781ba |
g_warning ("%s: Programmer stupidity error", G_STRLOC);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
result.width = img.width;
|
|
Packit Service |
2781ba |
result.height = img.height;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
out:
|
|
Packit Service |
2781ba |
if (stdin != fp)
|
|
Packit Service |
2781ba |
fclose (fp);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return result;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static gboolean
|
|
Packit Service |
2781ba |
process (GeglOperation *operation,
|
|
Packit Service |
2781ba |
GeglBuffer *output,
|
|
Packit Service |
2781ba |
const GeglRectangle *result,
|
|
Packit Service |
2781ba |
gint level)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
|
|
Packit Service |
2781ba |
FILE *fp;
|
|
Packit Service |
2781ba |
pnm_struct img;
|
|
Packit Service |
2781ba |
GeglRectangle rect = {0,0,0,0};
|
|
Packit Service |
2781ba |
gboolean ret = FALSE;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
fp = (!strcmp (o->path, "-") ? stdin : fopen (o->path,"rb"));
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (!fp)
|
|
Packit Service |
2781ba |
return FALSE;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
if (!ppm_load_read_header (fp, &img))
|
|
Packit Service |
2781ba |
goto out;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
/* Allocating Array Size */
|
|
Packit Service |
3704c4 |
|
|
Packit Service |
3704c4 |
/* Should use g_try_malloc(), but this causes crashes elsewhere because the
|
|
Packit Service |
3704c4 |
* error signalled by returning FALSE isn't properly acted upon. Therefore
|
|
Packit Service |
3704c4 |
* g_malloc() is used here which aborts if the requested memory size can't be
|
|
Packit Service |
3704c4 |
* allocated causing a controlled crash. */
|
|
Packit Service |
2781ba |
img.data = (guchar*) g_malloc (img.numsamples * img.bpc);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
3704c4 |
/* No-op without g_try_malloc(), see above. */
|
|
Packit Service |
3704c4 |
if (! img.data)
|
|
Packit Service |
3704c4 |
{
|
|
Packit Service |
3704c4 |
g_warning ("Couldn't allocate %" G_GSIZE_FORMAT " bytes, giving up.", ((gsize)img.numsamples * img.bpc));
|
|
Packit Service |
3704c4 |
goto out;
|
|
Packit Service |
3704c4 |
}
|
|
Packit Service |
3704c4 |
|
|
Packit Service |
3704c4 |
rect.height = img.height;
|
|
Packit Service |
3704c4 |
rect.width = img.width;
|
|
Packit Service |
3704c4 |
|
|
Packit Service |
2781ba |
switch (img.bpc)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
case 1:
|
|
Packit Service |
2781ba |
gegl_buffer_get (output, &rect, 1.0, babl_format ("R'G'B' u8"), img.data,
|
|
Packit Service |
2781ba |
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
case 2:
|
|
Packit Service |
2781ba |
gegl_buffer_get (output, &rect, 1.0, babl_format ("R'G'B' u16"), img.data,
|
|
Packit Service |
2781ba |
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
default:
|
|
Packit Service |
2781ba |
g_warning ("%s: Programmer stupidity error", G_STRLOC);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
ppm_load_read_image (fp, &img;;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
switch (img.bpc)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
case 1:
|
|
Packit Service |
2781ba |
gegl_buffer_set (output, &rect, 0, babl_format ("R'G'B' u8"), img.data,
|
|
Packit Service |
2781ba |
GEGL_AUTO_ROWSTRIDE);
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
case 2:
|
|
Packit Service |
2781ba |
gegl_buffer_set (output, &rect, 0, babl_format ("R'G'B' u16"), img.data,
|
|
Packit Service |
2781ba |
GEGL_AUTO_ROWSTRIDE);
|
|
Packit Service |
2781ba |
break;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
default:
|
|
Packit Service |
2781ba |
g_warning ("%s: Programmer stupidity error", G_STRLOC);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
g_free (img.data);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
ret = TRUE;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
out:
|
|
Packit Service |
2781ba |
if (stdin != fp)
|
|
Packit Service |
2781ba |
fclose (fp);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
return ret;
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static GeglRectangle
|
|
Packit Service |
2781ba |
get_cached_region (GeglOperation *operation,
|
|
Packit Service |
2781ba |
const GeglRectangle *roi)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
return get_bounding_box (operation);
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
static void
|
|
Packit Service |
2781ba |
gegl_chant_class_init (GeglChantClass *klass)
|
|
Packit Service |
2781ba |
{
|
|
Packit Service |
2781ba |
GeglOperationClass *operation_class;
|
|
Packit Service |
2781ba |
GeglOperationSourceClass *source_class;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
operation_class = GEGL_OPERATION_CLASS (klass);
|
|
Packit Service |
2781ba |
source_class = GEGL_OPERATION_SOURCE_CLASS (klass);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
source_class->process = process;
|
|
Packit Service |
2781ba |
operation_class->get_bounding_box = get_bounding_box;
|
|
Packit Service |
2781ba |
operation_class->get_cached_region = get_cached_region;
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_operation_class_set_keys (operation_class,
|
|
Packit Service |
2781ba |
"name" , "gegl:ppm-load",
|
|
Packit Service |
2781ba |
"categories" , "hidden",
|
|
Packit Service |
2781ba |
"description" , _("PPM image loader."),
|
|
Packit Service |
2781ba |
NULL);
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
gegl_extension_handler_register (".ppm", "gegl:ppm-load");
|
|
Packit Service |
2781ba |
}
|
|
Packit Service |
2781ba |
|
|
Packit Service |
2781ba |
#endif
|