Skip to content

Commit

Permalink
add 32-bit float TIF output support to ojph_expand
Browse files Browse the repository at this point in the history
  • Loading branch information
michaeldsmith committed Jan 7, 2025
1 parent 7657919 commit aa7a38c
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 22 deletions.
11 changes: 8 additions & 3 deletions src/apps/common/ojph_img_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -650,8 +650,11 @@ namespace ojph {
buffer = NULL;
width = height = num_components = 0;
bytes_per_sample = 0;
bit_depth_of_data[0] = bit_depth_of_data[1] = 0;
bit_depth_of_data[2] = bit_depth_of_data[3] = 0;
for (int c = 0; c < 3; c++)
{
bit_depth_of_data[c] = 0;
is_signed[c] = false;
}
buffer_size = 0;
cur_line = samples_per_line = 0;
bytes_per_line = 0;
Expand All @@ -667,7 +670,7 @@ namespace ojph {

void open(char* filename);
void configure(ui32 width, ui32 height, ui32 num_components,
ui32 *bit_depth);
ui32 *bit_depth, bool* is_signed, bool* has_nlt_type3);
virtual ui32 write(const line_buf* line, ui32 comp_num);
virtual void close() {
if (tiff_handle) {
Expand All @@ -685,6 +688,8 @@ namespace ojph {
const char* fname;
ui32 width, height, num_components;
ui32 bit_depth_of_data[4];
bool is_signed[4];
bool has_nlt_type3[4];
ui32 bytes_per_sample;
ui8* buffer;
size_t buffer_size;
Expand Down
22 changes: 20 additions & 2 deletions src/apps/ojph_expand/ojph_expand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ int main(int argc, char *argv[]) {
{
codestream.set_planar(false);
ojph::param_siz siz = codestream.access_siz();
ojph::param_nlt nlt = codestream.access_nlt();

bool all_same = true;
ojph::point p = siz.get_downsampling(0);
Expand All @@ -338,12 +339,29 @@ int main(int argc, char *argv[]) {
"To save an image to tif(f), all the components must have the "
"same downsampling ratio\n");
ojph::ui32 bit_depths[4] = { 0, 0, 0, 0 };
for (ojph::ui32 c = 0; c < siz.get_num_components(); c++)
bool is_signeds[4] = { false, false, false, false };
bool has_nlt_type3[4] = { false, false, false, false };
for (ojph::ui32 c = 0; c < (siz.get_num_components() > 4 ? 4 : siz.get_num_components()); c++)
{
bit_depths[c] = siz.get_bit_depth(c);
is_signeds[c] = siz.is_signed(c);
bool nlt_is_signed;
ojph::ui8 nlt_bit_depth;
has_nlt_type3[c] = nlt.get_type3_transformation(c, nlt_bit_depth, nlt_is_signed);

if (true == has_nlt_type3[c] && (nlt_bit_depth != siz.get_bit_depth(c) || nlt_is_signed != siz.is_signed(c)))
{
OJPH_ERROR(0x02000005,
"There is discrepancy in component %d configuration between "
"SIZ marker segment, which specifies bit_depth = %d and "
"signedness = %s, and NLT marker segment, which specifies "
"bit_depth = %d and signedness = %s.\n", c,
siz.get_bit_depth(c), siz.is_signed(c) ? "True" : "False",
nlt_bit_depth, nlt_is_signed ? "True" : "False");
}
}
tif.configure(siz.get_recon_width(0), siz.get_recon_height(0),
siz.get_num_components(), bit_depths);
siz.get_num_components(), bit_depths, is_signeds, has_nlt_type3);
tif.open(output_filename);
base = &tif;
}
Expand Down
84 changes: 67 additions & 17 deletions src/apps/others/ojph_img_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1091,12 +1091,17 @@ namespace ojph {
{
// Error on known incompatilbe output formats
ui32 max_bitdepth = 0;
bool any_component_has_nlt_type3 = false;
for (ui32 c = 0; c < num_components; c++)
{
if (bit_depth_of_data[c] > max_bitdepth)
max_bitdepth = bit_depth_of_data[c];

if (has_nlt_type3[c] == true)
any_component_has_nlt_type3 = true;
}
if (max_bitdepth > 16)

if (max_bitdepth > 16 && max_bitdepth != 32 && any_component_has_nlt_type3 == false )
{
OJPH_WARN(0x030000B1, "TIFF output is currently limited to files "
"with max_bitdepth = 16, the source codestream has max_bitdepth=%d"
Expand All @@ -1116,6 +1121,10 @@ namespace ojph {

buffer_size = width * (size_t)num_components * (size_t)bytes_per_sample;
buffer = (ui8*)malloc(buffer_size);
if(NULL == buffer)
{
OJPH_ERROR(0x030000B4, "unable to allocate %ul bytes for buffer[]", buffer_size);
}
fname = filename;
cur_line = 0;

Expand Down Expand Up @@ -1160,38 +1169,49 @@ namespace ojph {

TIFFSetField(tiff_handle, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField(tiff_handle, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
//TIFFSetField(tiff_handle, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT);
if (32 == max_bitdepth)
{
TIFFSetField(tiff_handle, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP);
}
TIFFSetField(tiff_handle, TIFFTAG_ROWSPERSTRIP, height);

}

////////////////////////////////////////////////////////////////////////////
void tif_out::configure(ui32 width, ui32 height, ui32 num_components,
ui32 *bit_depth)
ui32 *bit_depth, bool *is_signed, bool *has_nlt_type3)
{
assert(tiff_handle == NULL); //configure before opening

this->width = width;
this->height = height;
this->num_components = num_components;
ui32 max_bitdepth = 0;
bool any_component_has_nlt_type3 = false;
for (ui32 c = 0; c < num_components; c++)
{
this->bit_depth_of_data[c] = bit_depth[c];
if (bit_depth[c] > max_bitdepth)
max_bitdepth = bit_depth[c];

this->is_signed[c] = is_signed[c];
this->has_nlt_type3[c] = has_nlt_type3[c];
if (has_nlt_type3[c] == true)
any_component_has_nlt_type3 = true;
}

bytes_per_sample = (max_bitdepth + 7) / 8; // round up
if (bytes_per_sample > 2)
{
// TIFF output is currently limited to files with max_bitdepth = 16,
// the decoded data will be truncated to 16 bits
if (max_bitdepth <= 8)
bytes_per_sample = 1;
else if (max_bitdepth <= 16)
bytes_per_sample = 2;
}
else
bytes_per_sample = 4;

if(any_component_has_nlt_type3)
bytes_per_sample = 4;

samples_per_line = num_components * width;
bytes_per_line = bytes_per_sample * (size_t)samples_per_line;

}

////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -1295,16 +1315,46 @@ namespace ojph {
// 16 bit MSB
*dp = (ui16)((val >> bits_to_shift) & bit_mask);
}
}

}
}
// write scanline when the last component is reached
if (comp_num == num_components-1)
else if (bytes_per_sample == 4)
{

// float32 was compressed
if (has_nlt_type3[comp_num] == true)
{
int result = TIFFWriteScanline(tiff_handle, buffer, cur_line++);
if (result != 1)
OJPH_ERROR(0x030000C1, "error writing to file %s", fname);
if (bit_depth_of_data[comp_num] == 32)
{
const float* sp = line->f32;
float* dp = (float*)buffer + comp_num;
for (ui32 i = width; i > 0; --i, dp += num_components)
{
float val = *sp++;
*dp = val;
}
}
else
{
OJPH_ERROR(0x030000C1,
"bytes_per_sample = 4 has_nlt_type3[%d] = true and bit_depth_of_data[%d]=%d is not yet supported",
comp_num, comp_num, bit_depth_of_data[comp_num]);
}
}
else
{
OJPH_ERROR(0x030000C2,
"bytes_per_sample = 4 has_nlt_type3[%d] = false is not yet supported",
comp_num);
}
}

// write scanline when the last component is reached
if (comp_num == num_components-1)
{
int result = TIFFWriteScanline(tiff_handle, buffer, cur_line++);
if (result != 1)
OJPH_ERROR(0x030000C3, "error writing to file %s", fname);
}
return 0;
}
#endif /* OJPH_ENABLE_TIFF_SUPPORT */
Expand Down

0 comments on commit aa7a38c

Please sign in to comment.