Bug 778990 - PNM file plugin doesn't preserve 16-bit image precision

Save PNM in 16-bit format with max value of 65536 if the
image precision is not U8.
This commit is contained in:
Daniel P. Berrange
2017-02-20 23:12:05 +00:00
committed by Michael Natterer
parent c87543aaac
commit ad9ccc4b58

View File

@ -60,7 +60,7 @@ typedef void (* PNMLoaderFunc) (PNMScanner *scanner,
PNMInfo *info, PNMInfo *info,
GeglBuffer *buffer); GeglBuffer *buffer);
typedef gboolean (* PNMSaverowFunc) (PNMRowInfo *info, typedef gboolean (* PNMSaverowFunc) (PNMRowInfo *info,
const guchar *data, guchar *data,
GError **error); GError **error);
struct _PNMScanner struct _PNMScanner
@ -95,6 +95,7 @@ struct _PNMRowInfo
gchar *rowbuf; /* Buffer for writing out rows */ gchar *rowbuf; /* Buffer for writing out rows */
gint xres; /* X resolution */ gint xres; /* X resolution */
gint np; /* Number of planes */ gint np; /* Number of planes */
gint bpc; /* Bytes per color */
guchar *red; /* Colormap red */ guchar *red; /* Colormap red */
guchar *grn; /* Colormap green */ guchar *grn; /* Colormap green */
guchar *blu; /* Colormap blue */ guchar *blu; /* Colormap blue */
@ -146,22 +147,22 @@ static void pnm_load_rawpfm (PNMScanner *scan,
GeglBuffer *buffer); GeglBuffer *buffer);
static gboolean pnmsaverow_ascii (PNMRowInfo *ri, static gboolean pnmsaverow_ascii (PNMRowInfo *ri,
const guchar *data, guchar *data,
GError **error); GError **error);
static gboolean pnmsaverow_raw (PNMRowInfo *ri, static gboolean pnmsaverow_raw (PNMRowInfo *ri,
const guchar *data, guchar *data,
GError **error); GError **error);
static gboolean pnmsaverow_raw_pbm (PNMRowInfo *ri, static gboolean pnmsaverow_raw_pbm (PNMRowInfo *ri,
const guchar *data, guchar *data,
GError **error); GError **error);
static gboolean pnmsaverow_ascii_pbm (PNMRowInfo *ri, static gboolean pnmsaverow_ascii_pbm (PNMRowInfo *ri,
const guchar *data, guchar *data,
GError **error); GError **error);
static gboolean pnmsaverow_ascii_indexed (PNMRowInfo *ri, static gboolean pnmsaverow_ascii_indexed (PNMRowInfo *ri,
const guchar *data, guchar *data,
GError **error); GError **error);
static gboolean pnmsaverow_raw_indexed (PNMRowInfo *ri, static gboolean pnmsaverow_raw_indexed (PNMRowInfo *ri,
const guchar *data, guchar *data,
GError **error); GError **error);
static void pnmscanner_destroy (PNMScanner *s); static void pnmscanner_destroy (PNMScanner *s);
@ -1046,7 +1047,7 @@ output_write (GOutputStream *output,
/* Writes out mono raw rows */ /* Writes out mono raw rows */
static gboolean static gboolean
pnmsaverow_raw_pbm (PNMRowInfo *ri, pnmsaverow_raw_pbm (PNMRowInfo *ri,
const guchar *data, guchar *data,
GError **error) GError **error)
{ {
gint b, p = 0; gint b, p = 0;
@ -1077,7 +1078,7 @@ pnmsaverow_raw_pbm (PNMRowInfo *ri,
/* Writes out mono ascii rows */ /* Writes out mono ascii rows */
static gboolean static gboolean
pnmsaverow_ascii_pbm (PNMRowInfo *ri, pnmsaverow_ascii_pbm (PNMRowInfo *ri,
const guchar *data, guchar *data,
GError **error) GError **error)
{ {
static gint line_len = 0; /* ascii pbm lines must be <= 70 chars long */ static gint line_len = 0; /* ascii pbm lines must be <= 70 chars long */
@ -1112,10 +1113,20 @@ pnmsaverow_ascii_pbm (PNMRowInfo *ri,
/* Writes out RGB and grayscale raw rows */ /* Writes out RGB and grayscale raw rows */
static gboolean static gboolean
pnmsaverow_raw (PNMRowInfo *ri, pnmsaverow_raw (PNMRowInfo *ri,
const guchar *data, guchar *data,
GError **error) GError **error)
{ {
return output_write (ri->output, data, ri->xres * ri->np, error); gint i;
if (ri->bpc == 2)
{
gushort *d = (gushort *)data;
for (i = 0; i < ri->xres * ri->np; i++)
{
*d = g_htons(*d);
d++;
}
}
return output_write (ri->output, data, ri->xres * ri->np * ri->bpc, error);
} }
/* Writes out RGB and grayscale float rows */ /* Writes out RGB and grayscale float rows */
@ -1132,7 +1143,7 @@ pnmsaverow_float (PNMRowInfo *ri,
/* Writes out indexed raw rows */ /* Writes out indexed raw rows */
static gboolean static gboolean
pnmsaverow_raw_indexed (PNMRowInfo *ri, pnmsaverow_raw_indexed (PNMRowInfo *ri,
const guchar *data, guchar *data,
GError **error) GError **error)
{ {
gint i; gint i;
@ -1151,26 +1162,34 @@ pnmsaverow_raw_indexed (PNMRowInfo *ri,
/* Writes out RGB and grayscale ascii rows */ /* Writes out RGB and grayscale ascii rows */
static gboolean static gboolean
pnmsaverow_ascii (PNMRowInfo *ri, pnmsaverow_ascii (PNMRowInfo *ri,
const guchar *data, guchar *data,
GError **error) GError **error)
{ {
gint i; gint i;
gchar *rbcur = ri->rowbuf; gchar *rbcur = ri->rowbuf;
gushort *sdata = (gushort *)data;
for (i = 0; i < ri->xres * ri->np; i++) for (i = 0; i < ri->xres * ri->np; i++)
{
if (ri->bpc == 2)
{
sprintf ((gchar *) rbcur,"%d\n", 0xffff & *(sdata++));
}
else
{ {
sprintf ((gchar *) rbcur,"%d\n", 0xff & *(data++)); sprintf ((gchar *) rbcur,"%d\n", 0xff & *(data++));
}
rbcur += strlen (rbcur); rbcur += strlen (rbcur);
} }
return output_write (ri->output, ri->rowbuf, strlen ((gchar *) ri->rowbuf), return output_write (ri->output, ri->rowbuf, rbcur - ri->rowbuf,
error); error);
} }
/* Writes out RGB and grayscale ascii rows */ /* Writes out RGB and grayscale ascii rows */
static gboolean static gboolean
pnmsaverow_ascii_indexed (PNMRowInfo *ri, pnmsaverow_ascii_indexed (PNMRowInfo *ri,
const guchar *data, guchar *data,
GError **error) GError **error)
{ {
gint i; gint i;
@ -1240,6 +1259,17 @@ save_image (GFile *file,
drawable_type = gimp_drawable_type (drawable_ID); drawable_type = gimp_drawable_type (drawable_ID);
switch (gimp_image_get_precision (image_ID))
{
case GIMP_PRECISION_U8_LINEAR:
case GIMP_PRECISION_U8_GAMMA:
rowinfo.bpc = 1;
break;
default:
rowinfo.bpc = 2;
break;
}
/* write out magic number */ /* write out magic number */
if (!float_format && !psvals.raw) if (!float_format && !psvals.raw)
{ {
@ -1257,17 +1287,33 @@ save_image (GFile *file,
{ {
case GIMP_GRAY_IMAGE: case GIMP_GRAY_IMAGE:
header_string = "P2\n"; header_string = "P2\n";
if (rowinfo.bpc == 1)
{
format = babl_format ("Y' u8"); format = babl_format ("Y' u8");
np = 1;
rowbufsize = xres * 4; rowbufsize = xres * 4;
}
else
{
format = babl_format ("Y' u16");
rowbufsize = xres * 6;
}
np = 1;
saverow = pnmsaverow_ascii; saverow = pnmsaverow_ascii;
break; break;
case GIMP_RGB_IMAGE: case GIMP_RGB_IMAGE:
header_string = "P3\n"; header_string = "P3\n";
if (rowinfo.bpc == 1)
{
format = babl_format ("R'G'B' u8"); format = babl_format ("R'G'B' u8");
np = 3;
rowbufsize = xres * 12; rowbufsize = xres * 12;
}
else
{
format = babl_format ("R'G'B' u16");
rowbufsize = xres * 18;
}
np = 3;
saverow = pnmsaverow_ascii; saverow = pnmsaverow_ascii;
break; break;
@ -1301,17 +1347,33 @@ save_image (GFile *file,
{ {
case GIMP_GRAY_IMAGE: case GIMP_GRAY_IMAGE:
header_string = "P5\n"; header_string = "P5\n";
if (rowinfo.bpc == 1)
{
format = babl_format ("Y' u8"); format = babl_format ("Y' u8");
np = 1;
rowbufsize = xres; rowbufsize = xres;
}
else
{
format = babl_format ("Y' u16");
rowbufsize = xres * 2;
}
np = 1;
saverow = pnmsaverow_raw; saverow = pnmsaverow_raw;
break; break;
case GIMP_RGB_IMAGE: case GIMP_RGB_IMAGE:
header_string = "P6\n"; header_string = "P6\n";
if (rowinfo.bpc == 1)
{
format = babl_format ("R'G'B' u8"); format = babl_format ("R'G'B' u8");
np = 3;
rowbufsize = xres * 3; rowbufsize = xres * 3;
}
else
{
format = babl_format ("R'G'B' u16");
rowbufsize = xres * 6;
}
np = 3;
saverow = pnmsaverow_raw; saverow = pnmsaverow_raw;
break; break;
@ -1422,7 +1484,8 @@ save_image (GFile *file,
if (pbm) if (pbm)
g_snprintf (buf, sizeof (buf), "%d %d\n", xres, yres); g_snprintf (buf, sizeof (buf), "%d %d\n", xres, yres);
else if (!float_format) else if (!float_format)
g_snprintf (buf, sizeof (buf), "%d %d\n255\n", xres, yres); g_snprintf (buf, sizeof (buf), "%d %d\n%d\n", xres, yres,
rowinfo.bpc == 1 ? 255 : 65535);
else else
g_snprintf (buf, sizeof (buf), "%d %d\n%f\n", xres, yres, g_snprintf (buf, sizeof (buf), "%d %d\n%f\n", xres, yres,
G_BYTE_ORDER == G_BIG_ENDIAN ? 1.0f : -1.0f); G_BYTE_ORDER == G_BIG_ENDIAN ? 1.0f : -1.0f);
@ -1473,7 +1536,7 @@ save_image (GFile *file,
goto out; goto out;
} }
d += xres * (np ? np : 1); d += xres * (np ? np : 1) * rowinfo.bpc;
if (ypos % 32 == 0) if (ypos % 32 == 0)
gimp_progress_update ((double) ypos / (double) yres); gimp_progress_update ((double) ypos / (double) yres);