[ptx] nona, gimp-2, TIFF_mask multilater tiff files
Pablo d'Angelo
pablo at mathematik.uni-ulm.de
Wed Jan 7 20:13:08 GMT 2004
On Wed, 07 Jan 2004, Pablo d'Angelo wrote:
> I'd rather like to see the masked content in a viewer that doesn't care
> about alpha than crippling the image while saving it!
>
> gimp also writes premultiplied files.. urgh. Should we try to submit a
> patch? (sorry, I won't have time to do this).
Hmm, I thought, while waiting for my pizza, I could add the alpha and layer
stuff... Well it took a bit longer, but here it is.
Now it should be able to read the files properly, but I haven't compiled the
full gimp, so it is untested. I attached the diff to gimp 2 pre1.
Hopefully somebody can try it out and report if it works.
Beware, the plugin can't save multiple layers.. save to .xcf instead of tif.
ciao
Pablo
--
http://wurm.wohnheim.uni-ulm.de/~redman/
Please use PGP
-------------- next part --------------
--- tiff_old.c 2003-12-26 15:59:00.000000000 +0100
+++ tiff.c 2004-01-07 21:12:33.000000000 +0100
@@ -14,6 +14,10 @@
* TIFF file, then a parasite is created and vice versa.
* peter at kirchgessner.net -- 29 Oct 2002
* Progress bar only when run interactive
+ * Added support for non-premultiplied alpha channels, and layer
+ * offsets
+ * pablo.dangelo at web.de -- 7 Jan 2003
+ *
*/
/*
@@ -80,12 +84,14 @@
gushort bps,
gushort photomet,
gboolean alpha,
+ gboolean alpha_premult,
gint extra);
static void load_tiles (TIFF *tif,
channel_data *channel,
gushort bps,
gushort photomet,
gboolean alpha,
+ gboolean alpha_premult,
gint extra);
static void read_separate (guchar *source,
@@ -97,6 +103,7 @@
gint rows,
gint cols,
gboolean alpha,
+ gboolean alpha_premult,
gint extra,
gint sample);
static void read_16bit (guchar *source,
@@ -107,6 +114,7 @@
gint rows,
gint cols,
gboolean alpha,
+ gboolean alpha_premult,
gint extra,
gint align);
static void read_8bit (guchar *source,
@@ -117,6 +125,7 @@
gint rows,
gint cols,
gboolean alpha,
+ gboolean alpha_premult,
gint extra,
gint align);
static void read_default (guchar *source,
@@ -128,6 +137,7 @@
gint rows,
gint cols,
gboolean alpha,
+ gboolean alpha_premult,
gint extra,
gint align);
@@ -399,8 +409,13 @@
guint16 orientation;
gint cols, rows;
gboolean alpha;
+ gboolean alpha_premult = FALSE;
gint image = 0, image_type = GIMP_RGB;
gint layer, layer_type = GIMP_RGB_IMAGE;
+ gfloat layer_offset_x = 0.0;
+ gfloat layer_offset_y = 0.0;
+ gint max_row = 0;
+ gint max_col = 0;
gushort extra, *extra_types;
channel_data *channel = NULL;
@@ -485,6 +500,23 @@
if (extra > 0 && (extra_types[0] == EXTRASAMPLE_ASSOCALPHA))
{
alpha = TRUE;
+ alpha_premult = TRUE;
+ --extra;
+ }
+ else if (extra > 0 && (extra_types[0] == EXTRASAMPLE_UNASSALPHA))
+ {
+ alpha = TRUE;
+ alpha_premult = FALSE;
+ --extra;
+ }
+ else if (extra > 0 && (extra_types[0] == EXTRASAMPLE_UNSPECIFIED))
+ {
+ /* assuming unassociated alpha if unspecified */
+ g_message ("alpha channel type not defined for file %s. "
+ "Assuming alpha is not premultiplied",
+ filename);
+ alpha = TRUE;
+ alpha_premult = FALSE;
--extra;
}
else
@@ -658,8 +690,18 @@
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. */
+
+ /* handle layer offset */
+ if (!TIFFGetField (tif, TIFFTAG_XPOSITION, &layer_offset_x))
+ layer_offset_x = (gfloat)0.0;
+ if (!TIFFGetField (tif, TIFFTAG_YPOSITION, &layer_offset_y))
+ layer_offset_y = (gfloat)0.0;
+
+ layer_offset_x = layer_offset_x * xres;
+ layer_offset_y = layer_offset_y * yres;
}
+
/* Install colormap for INDEXED images only */
if (image_type == GIMP_INDEXED)
{
@@ -682,14 +724,26 @@
/* Allocate channel_data for all channels, even the background layer */
channel = g_new0 (channel_data, extra + 1);
- if (ilayer == 0)
- name = g_strdup (_("Background"));
+ /* try and use layer name from tiff file */
+ name = 0;
+ if (TIFFGetField (tif, TIFFTAG_PAGENAME, &name))
+ {
+ layer = gimp_layer_new (image, name,
+ cols, rows, layer_type, 100, GIMP_NORMAL_MODE);
+ name = 0;
+ }
else
- name = g_strdup_printf (_("Page %d"), ilayer);
+ {
+ if (ilayer == 0)
+ name = g_strdup (_("Background"));
+ else
+ name = g_strdup_printf (_("Page %d"), ilayer);
+
+ layer = gimp_layer_new (image, name,
+ cols, rows, layer_type, 100, GIMP_NORMAL_MODE);
+ g_free (name);
+ }
- layer = gimp_layer_new (image, name,
- cols, rows, layer_type, 100, GIMP_NORMAL_MODE);
- g_free (name);
channel[0].ID = layer;
channel[0].drawable = gimp_drawable_get (layer);
@@ -719,11 +773,11 @@
}
else if (TIFFIsTiled(tif))
{
- load_tiles (tif, channel, bps, photomet, alpha, extra);
+ load_tiles (tif, channel, bps, photomet, alpha, alpha_premult, extra);
}
else
{ /* Load scanlines in tile_height chunks */
- load_lines (tif, channel, bps, photomet, alpha, extra);
+ load_lines (tif, channel, bps, photomet, alpha, alpha_premult, extra);
}
if (TIFFGetField (tif, TIFFTAG_ORIENTATION, &orientation))
@@ -772,6 +826,24 @@
g_free (channel);
channel = NULL;
+ if ( max_col < ((int)(layer_offset_x + 0.5) + cols))
+ {
+ max_col = ((int)(layer_offset_x + 0.5) + cols);
+ }
+
+ if ( max_row < ((int)(layer_offset_y + 0.5) + rows))
+ {
+ max_row = ((int)(layer_offset_y + 0.5) + rows);
+ }
+
+ /* position the layer */
+ if ( layer_offset_x > 0 || layer_offset_y > 0 ) {
+ gimp_layer_set_offsets( layer,
+ (int)(layer_offset_x+0.5),
+ (int)(layer_offset_y+0.5));
+ }
+
+
if (ilayer > 0 && !alpha)
gimp_layer_add_alpha (layer);
@@ -780,6 +852,9 @@
}
while (TIFFReadDirectory (tif));
+ // resize image, to show all layers
+ gimp_image_resize ( image, max_col, max_row, 0, 0);
+
gimp_image_undo_enable (image);
return image;
@@ -821,6 +896,7 @@
gushort bps,
gushort photomet,
gboolean alpha,
+ gboolean alpha_premult,
gint extra)
{
uint16 planar= PLANARCONFIG_CONTIG;
@@ -862,17 +938,17 @@
if (bps == 16)
{
read_16bit (buffer, channel, photomet, y, x, rows, cols, alpha,
- extra, tileWidth - cols);
+ alpha_premult, extra, tileWidth - cols);
}
else if (bps == 8)
{
read_8bit (buffer, channel, photomet, y, x, rows, cols, alpha,
- extra, tileWidth - cols);
+ alpha_premult, extra, tileWidth - cols);
}
else
{
read_default (buffer, channel, bps, photomet, y, x, rows, cols,
- alpha, extra, tileWidth - cols);
+ alpha, alpha_premult, extra, tileWidth - cols);
}
}
progress+= one_row;
@@ -890,6 +966,7 @@
gushort bps,
gushort photomet,
gboolean alpha,
+ gboolean alpha_premult,
gint extra)
{
uint16 planar= PLANARCONFIG_CONTIG;
@@ -926,17 +1003,17 @@
if (bps == 16)
{
read_16bit (buffer, channel, photomet, y, 0, rows, cols,
- alpha, extra, 0);
+ alpha, alpha_premult, extra, 0);
}
else if (bps == 8)
{
read_8bit (buffer, channel, photomet, y, 0, rows, cols,
- alpha, extra, 0);
+ alpha, alpha_premult, extra, 0);
}
else
{
read_default (buffer, channel, bps, photomet, y, 0, rows, cols,
- alpha, extra, 0);
+ alpha, alpha_premult, extra, 0);
}
}
}
@@ -957,7 +1034,7 @@
TIFFReadScanline(tif, buffer + i * lineSize, y + i, s);
read_separate (buffer, channel, bps, photomet,
- y, 0, rows, cols, alpha, extra, s);
+ y, 0, rows, cols, alpha, alpha_premult, extra, s);
}
}
}
@@ -977,6 +1054,7 @@
gint rows,
gint cols,
gboolean alpha,
+ gboolean alpha_premult,
gint extra,
gint align)
{
@@ -1008,16 +1086,24 @@
case PHOTOMETRIC_MINISBLACK:
if (alpha)
{
- gray_val = *source; source += 2;
- alpha_val = *source; source += 2;
- gray_val = MIN (gray_val, alpha_val);
+ if (alpha_premult)
+ {
+ gray_val = *source; source += 2;
+ alpha_val = *source; source += 2;
+ gray_val = MIN (gray_val, alpha_val);
+
+ if (alpha_val)
+ *dest++ = gray_val * 255 / alpha_val;
+ else
+ *dest++ = 0;
- if (alpha_val)
- *dest++ = gray_val * 255 / alpha_val;
+ *dest++ = alpha_val;
+ }
else
- *dest++ = 0;
-
- *dest++ = alpha_val;
+ {
+ *dest++ = *source; source += 2;
+ *dest++ = *source; source += 2;
+ }
}
else
{
@@ -1028,16 +1114,21 @@
case PHOTOMETRIC_MINISWHITE:
if (alpha)
{
- gray_val = *source; source += 2;
- alpha_val = *source; source += 2;
- gray_val = MIN (gray_val, alpha_val);
-
- if (alpha_val)
- *dest++ = ((alpha_val - gray_val) * 255) / alpha_val;
- else
- *dest++ = 0;
+ if (alpha_premult) {
+ gray_val = *source; source += 2;
+ alpha_val = *source; source += 2;
+ gray_val = MIN (gray_val, alpha_val);
+
+ if (alpha_val)
+ *dest++ = ((alpha_val - gray_val) * 255) / alpha_val;
+ else
+ *dest++ = 0;
- *dest++ = alpha_val;
+ *dest++ = alpha_val;
+ } else {
+ *dest++ = *source; source += 2;
+ *dest++ = *source; source += 2;
+ }
}
else
{
@@ -1053,26 +1144,36 @@
case PHOTOMETRIC_RGB:
if (alpha)
{
- red_val = *source; source += 2;
- green_val = *source; source += 2;
- blue_val = *source; source += 2;
- alpha_val = *source; source += 2;
- red_val = MIN (red_val, alpha_val);
- green_val = MIN (green_val, alpha_val);
- blue_val = MIN (blue_val, alpha_val);
- if (alpha_val)
+ if (alpha_premult)
{
- *dest++ = (red_val * 255) / alpha_val;
- *dest++ = (green_val * 255) / alpha_val;
- *dest++ = (blue_val * 255) / alpha_val;
+ red_val = *source; source += 2;
+ green_val = *source; source += 2;
+ blue_val = *source; source += 2;
+ alpha_val = *source; source += 2;
+ red_val = MIN (red_val, alpha_val);
+ green_val = MIN (green_val, alpha_val);
+ blue_val = MIN (blue_val, alpha_val);
+ 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++ = 0;
- *dest++ = 0;
- *dest++ = 0;
+ *dest++ = *source; source += 2;
+ *dest++ = *source; source += 2;
+ *dest++ = *source; source += 2;
+ *dest++ = *source; source += 2;
}
- *dest++ = alpha_val;
}
else
{
@@ -1123,6 +1224,7 @@
gint rows,
gint cols,
gboolean alpha,
+ gboolean alpha_premult,
gint extra,
gint align)
{
@@ -1150,14 +1252,19 @@
case PHOTOMETRIC_MINISBLACK:
if (alpha)
{
- gray_val= *source++;
- alpha_val= *source++;
- gray_val= MIN(gray_val, alpha_val);
- if (alpha_val)
- *dest++ = gray_val * 255 / alpha_val;
- else
- *dest++ = 0;
- *dest++ = alpha_val;
+ if (alpha_premult) {
+ gray_val= *source++;
+ alpha_val= *source++;
+ gray_val= MIN(gray_val, alpha_val);
+ if (alpha_val)
+ *dest++ = gray_val * 255 / alpha_val;
+ else
+ *dest++ = 0;
+ *dest++ = alpha_val;
+ } else {
+ *dest++ = *source; source++;
+ *dest++ = *source; source++;
+ }
}
else
{
@@ -1168,15 +1275,23 @@
case PHOTOMETRIC_MINISWHITE:
if (alpha)
{
- gray_val = *source++;
- alpha_val = *source++;
- gray_val = MIN (gray_val, alpha_val);
-
- if (alpha_val)
- *dest++ = ((alpha_val - gray_val) * 255) / alpha_val;
+ if (alpha_premult)
+ {
+ gray_val = *source++;
+ alpha_val = *source++;
+ gray_val = MIN (gray_val, alpha_val);
+
+ if (alpha_val)
+ *dest++ = ((alpha_val - gray_val) * 255) / alpha_val;
+ else
+ *dest++ = 0;
+ *dest++ = alpha_val;
+ }
else
- *dest++ = 0;
- *dest++ = alpha_val;
+ {
+ *dest++ = *source; source++;
+ *dest++ = *source; source++;
+ }
}
else
{
@@ -1193,27 +1308,37 @@
case PHOTOMETRIC_RGB:
if (alpha)
{
- red_val = *source++;
- green_val = *source++;
- blue_val = *source++;
- alpha_val = *source++;
- red_val = MIN (red_val, alpha_val);
- blue_val = MIN (blue_val, alpha_val);
- green_val = MIN (green_val, alpha_val);
-
- if (alpha_val)
+ if (alpha_premult)
{
- *dest++ = (red_val * 255) / alpha_val;
- *dest++ = (green_val * 255) / alpha_val;
- *dest++ = (blue_val * 255) / alpha_val;
+ red_val = *source++;
+ green_val = *source++;
+ blue_val = *source++;
+ alpha_val = *source++;
+ red_val = MIN (red_val, alpha_val);
+ blue_val = MIN (blue_val, alpha_val);
+ green_val = MIN (green_val, alpha_val);
+
+ 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++ = 0;
- *dest++ = 0;
- *dest++ = 0;
- }
- *dest++ = alpha_val;
+ {
+ *dest++ = *source; source++;
+ *dest++ = *source; source++;
+ *dest++ = *source; source++;
+ *dest++ = *source; source++;
+ }
}
else
{
@@ -1276,6 +1401,7 @@
gint rows,
gint cols,
gboolean alpha,
+ gboolean alpha_premult,
gint extra,
gint align)
{
@@ -1306,14 +1432,22 @@
if (alpha)
{
NEXTSAMPLE (alpha_val);
- gray_val= MIN (gray_val, alpha_val);
+ if (alpha_premult)
+ {
+ gray_val= MIN (gray_val, alpha_val);
- if (alpha_val)
- *dest++ = (gray_val * 65025) / (alpha_val * maxval);
- else
- *dest++ = 0;
+ if (alpha_val)
+ *dest++ = (gray_val * 65025) / (alpha_val * maxval);
+ else
+ *dest++ = 0;
- *dest++ = alpha_val;
+ *dest++ = alpha_val;
+ }
+ else
+ {
+ *dest++ = (gray_val * 255) / maxval;
+ *dest++ = alpha_val;
+ }
}
else
{
@@ -1326,14 +1460,19 @@
if (alpha)
{
NEXTSAMPLE (alpha_val);
- gray_val= MIN (gray_val, alpha_val);
+ if (alpha_premult) {
+ gray_val= MIN (gray_val, alpha_val);
- if (alpha_val)
- *dest++ = ((maxval - gray_val) * 65025) / (alpha_val * maxval);
- else
- *dest++ = 0;
+ if (alpha_val)
+ *dest++ = ((maxval - gray_val) * 65025) / (alpha_val * maxval);
+ else
+ *dest++ = 0;
- *dest++ = alpha_val;
+ *dest++ = alpha_val;
+ } else {
+ *dest++ = ((maxval - gray_val) * 255) / maxval;
+ *dest++ = alpha_val;
+ }
}
else
{
@@ -1354,24 +1493,31 @@
if (alpha)
{
NEXTSAMPLE (alpha_val);
- red_val = MIN (red_val, alpha_val);
- blue_val = MIN (blue_val, alpha_val);
- green_val = MIN (green_val, alpha_val);
+ if (alpha_premult) {
+ red_val = MIN (red_val, alpha_val);
+ blue_val = MIN (blue_val, alpha_val);
+ green_val = MIN (green_val, alpha_val);
- 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;
- }
+ 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;
+ *dest++ = alpha_val;
+ } else {
+ *dest++ = red_val;
+ *dest++ = green_val;
+ *dest++ = blue_val;
+ *dest++ = alpha_val;
+ }
}
else
{
@@ -1428,6 +1574,7 @@
gint rows,
gint cols,
gboolean alpha,
+ gboolean alpha_premult,
gint extra,
gint sample)
{
@@ -1628,7 +1775,7 @@
}
if (alpha)
{
- extra_samples [0] = EXTRASAMPLE_ASSOCALPHA;
+ extra_samples [0] = EXTRASAMPLE_UNASSALPHA;
TIFFSetField (tif, TIFFTAG_EXTRASAMPLES, 1, extra_samples);
}
TIFFSetField (tif, TIFFTAG_PHOTOMETRIC, photometric);
@@ -1755,8 +1902,8 @@
case GIMP_GRAYA_IMAGE:
for (col = 0; col < cols*samplesperpixel; col+=samplesperpixel)
{
- /* pre-multiply gray by alpha */
- data[col + 0] = (t[col + 0] * t[col + 1]) / 255;
+ /* do not premultiply */
+ data[col + 0] = t[col + 0];
data[col + 1] = t[col + 1]; /* alpha channel */
}
success = (TIFFWriteScanline (tif, data, row, 0) >= 0);
@@ -1767,10 +1914,10 @@
case GIMP_RGBA_IMAGE:
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;
+ /* do not pre-multiply */
+ data[col+0] = t[col + 0];
+ data[col+1] = t[col + 1];
+ data[col+2] = t[col + 2];
data[col+3] = t[col + 3]; /* alpha channel */
}
success = (TIFFWriteScanline (tif, data, row, 0) >= 0);
More information about the ptX
mailing list