robustify tiff alpha channel support a tiny bit

This commit is contained in:
David Rose 2005-01-04 03:07:05 +00:00
parent 6956d642d2
commit 470ad797ae
2 changed files with 109 additions and 23 deletions

View File

@ -384,11 +384,48 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
} }
if (_is_valid) { if (_is_valid) {
if (spp >= 1 && spp <= 4) { unsigned short num_extra_samples;
_num_channels = spp; unsigned short *extra_samples = NULL;
if (!TIFFGetField(tif, TIFFTAG_EXTRASAMPLES, &num_extra_samples,
&extra_samples)) {
num_extra_samples = 0;
}
_num_channels = spp - num_extra_samples;
unassoc_alpha_sample = 0;
assoc_alpha_sample = 0;
if (_num_channels == 1 || _num_channels == 3) {
// Look for an alpha channel in one of the extra samples, if
// any.
bool got_alpha = false;
for (unsigned short s = 0; s < num_extra_samples && !got_alpha; s++) {
if (extra_samples[s] == EXTRASAMPLE_UNASSALPHA) {
unassoc_alpha_sample = s + _num_channels;
_num_channels++;
got_alpha = true;
} else if (extra_samples[s] == EXTRASAMPLE_ASSOCALPHA) {
assoc_alpha_sample = s + _num_channels;
_num_channels++;
got_alpha = true;
}
}
// Unfortunately, Photoshop seems to write
// EXTRASAMPLE_UNSPECIFIED into the EXTRASAMPLES field for its
// alpha channels. If we have exactly one extra channel and
// it's an UNSPECIFIED channel, assume it's meant to be alpha.
if (!got_alpha && num_extra_samples == 1 &&
extra_samples[0] == EXTRASAMPLE_UNSPECIFIED) {
unassoc_alpha_sample = _num_channels;
_num_channels++;
}
} else { } else {
pnmimage_tiff_cat.error() pnmimage_tiff_cat.error()
<< "Cannot handle " << spp << "-channel image.\n"; << "Cannot handle " << spp << "-color image (with "
<< num_extra_samples << " extra channels).\n";
_is_valid = false; _is_valid = false;
} }
} }
@ -404,7 +441,7 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
} }
_maxval = ( 1 << bps ) - 1; _maxval = ( 1 << bps ) - 1;
if ( _maxval == 1 && spp == 1 ) { if ( _maxval == 1 && _num_channels == 1 ) {
if (pnmimage_tiff_cat.is_debug()) { if (pnmimage_tiff_cat.is_debug()) {
pnmimage_tiff_cat.debug(false) pnmimage_tiff_cat.debug(false)
<< "monochrome\n"; << "monochrome\n";
@ -561,7 +598,8 @@ read_row(xel *row_data, xelval *alpha_data) {
unsigned char *buf = (unsigned char*) alloca((size_t)TIFFScanlineSize(tif)); unsigned char *buf = (unsigned char*) alloca((size_t)TIFFScanlineSize(tif));
int col; int col;
unsigned char sample; xelval gray, sample;
xelval r, g, b;
if ( TIFFReadScanline( tif, buf, current_row, 0 ) < 0 ) { if ( TIFFReadScanline( tif, buf, current_row, 0 ) < 0 ) {
pnmimage_tiff_cat.error() pnmimage_tiff_cat.error()
@ -570,6 +608,7 @@ read_row(xel *row_data, xelval *alpha_data) {
} }
unsigned char *inP = buf; unsigned char *inP = buf;
unsigned s;
int bitsleft = 8; int bitsleft = 8;
switch ( photomet ) { switch ( photomet ) {
@ -577,11 +616,21 @@ read_row(xel *row_data, xelval *alpha_data) {
for ( col = 0; col < _x_size; ++col ) for ( col = 0; col < _x_size; ++col )
{ {
NEXTSAMPLE; NEXTSAMPLE;
PPM_PUTB(row_data[col], sample); gray = sample;
if ( spp == 2 ) {
NEXTSAMPLE; // Alpha channel for (s = 1; s < spp; s++) {
alpha_data[col] = sample; NEXTSAMPLE;
if (s == unassoc_alpha_sample) {
alpha_data[col] = sample;
} else if (s == assoc_alpha_sample) {
alpha_data[col] = sample;
if (sample != 0) {
gray = (xelval)((float)gray * _maxval / (float)sample);
}
}
} }
PPM_PUTB(row_data[col], gray);
} }
break; break;
@ -589,12 +638,23 @@ read_row(xel *row_data, xelval *alpha_data) {
for ( col = 0; col < _x_size; ++col ) for ( col = 0; col < _x_size; ++col )
{ {
NEXTSAMPLE; NEXTSAMPLE;
sample = _maxval - sample; gray = _maxval - sample;
PPM_PUTB(row_data[col], sample); for (s = 1; s < spp; s++) {
if ( spp == 2 ) { NEXTSAMPLE;
NEXTSAMPLE; // Alpha channel sample = _maxval - sample;
alpha_data[col] = sample;
if (s == unassoc_alpha_sample) {
alpha_data[col] = sample;
} else if (s == assoc_alpha_sample) {
alpha_data[col] = sample;
if (sample != 0) {
gray = (xelval)((float)gray * _maxval / (float)sample);
}
}
} }
PPM_PUTB(row_data[col], gray);
} }
break; break;
@ -603,28 +663,53 @@ read_row(xel *row_data, xelval *alpha_data) {
{ {
NEXTSAMPLE; NEXTSAMPLE;
row_data[col] = colormap[sample]; row_data[col] = colormap[sample];
if ( spp == 2 ) {
NEXTSAMPLE; // Alpha channel for (s = 1; s < spp; s++) {
alpha_data[col] = sample; NEXTSAMPLE;
if (s == unassoc_alpha_sample) {
alpha_data[col] = sample;
} else if (s == assoc_alpha_sample) {
alpha_data[col] = sample;
if (sample != 0) {
r = PPM_GETR(row_data[col]);
g = PPM_GETG(row_data[col]);
b = PPM_GETB(row_data[col]);
r = (xelval)((float)r * _maxval / (float)sample);
g = (xelval)((float)g * _maxval / (float)sample);
b = (xelval)((float)b * _maxval / (float)sample);
PPM_ASSIGN(row_data[col], r, g, b);
}
}
} }
} }
break; break;
case PHOTOMETRIC_RGB: case PHOTOMETRIC_RGB:
for ( col = 0; col < _x_size; ++col ) { for ( col = 0; col < _x_size; ++col ) {
xelval r, g, b;
NEXTSAMPLE; NEXTSAMPLE;
r = sample; r = sample;
NEXTSAMPLE; NEXTSAMPLE;
g = sample; g = sample;
NEXTSAMPLE; NEXTSAMPLE;
b = sample; b = sample;
PPM_ASSIGN(row_data[col], r, g, b);
if ( spp == 4 ) { for (s = 3; s < spp; s++) {
NEXTSAMPLE; // Alpha channel NEXTSAMPLE;
alpha_data[col] = sample; if (s == unassoc_alpha_sample) {
alpha_data[col] = sample;
} else if (s == assoc_alpha_sample) {
alpha_data[col] = sample;
if (sample != 0) {
r = (xelval)((float)r * _maxval / (float)sample);
g = (xelval)((float)g * _maxval / (float)sample);
b = (xelval)((float)b * _maxval / (float)sample);
}
}
} }
PPM_ASSIGN(row_data[col], r, g, b);
} }
break; break;

View File

@ -65,6 +65,7 @@ public:
private: private:
unsigned short photomet; unsigned short photomet;
unsigned short bps, spp; unsigned short bps, spp;
unsigned short unassoc_alpha_sample, assoc_alpha_sample;
xel colormap[TIFF_COLORMAP_MAXCOLORS]; xel colormap[TIFF_COLORMAP_MAXCOLORS];
int current_row; int current_row;