Skip to content

Commit

Permalink
Multiple changes to PNG handling
Browse files Browse the repository at this point in the history
- Do not attempt to support writing bitwise images, even if the number of pixels in the width direction is a factor of 8.
- Fix intensity scaling of bitwise images such that values of 0 and 255 are used in the output uint8 image.
 Add test data and tests for verifying operation of PNG export.
  • Loading branch information
Lestropie committed Oct 4, 2023
1 parent 76d7007 commit 386db1f
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 20 deletions.
11 changes: 9 additions & 2 deletions core/file/png.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ namespace MR
bit_depth (0),
filename (filename),
data_type (H.datatype()),
multiplier (1.0),
outfile (NULL)
{
if (Path::exists (filename) && !App::overwrite_files)
Expand Down Expand Up @@ -231,17 +232,23 @@ namespace MR
png_destroy_write_struct (&png_ptr, &info_ptr);
throw Exception ("Undefined data type in image \"" + H.name() + "\" for PNG writer");
case DataType::Bit:
bit_depth = 1;
assert (false);
break;
case DataType::UInt8:
bit_depth = 8;
break;
case DataType::Float32:
bit_depth = 8;
multiplier = std::numeric_limits<uint8_t>::max(); break;
break;
case DataType::UInt16:
case DataType::UInt32:
case DataType::UInt64:
bit_depth = 16;
break;
case DataType::Float64:
bit_depth = 16;
multiplier = std::numeric_limits<uint16_t>::max(); break;
break;
}
// Detect cases where one axis has a size of 1, and hence represents the image plane
Expand Down Expand Up @@ -327,7 +334,7 @@ namespace MR
};


if (bit_depth == 1 || data_type == DataType::UInt8 || data_type == DataType::UInt16BE) {
if (data_type == DataType::UInt8 || data_type == DataType::UInt16BE) {
finish (data);
} else {
uint8_t scratch[row_bytes * height];
Expand Down
13 changes: 3 additions & 10 deletions core/file/png.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ namespace MR
int color_type, bit_depth;
std::string filename;
DataType data_type;
default_type multiplier;
FILE* outfile;

static void error_handler (png_struct_def*, const char*);
Expand All @@ -100,16 +101,8 @@ namespace MR
std::function<default_type(const void*,size_t,default_type,default_type)> fetch_func;
std::function<void(default_type,void*,size_t,default_type,default_type)> store_func;
__set_fetch_store_functions<default_type> (fetch_func, store_func, data_type);
default_type multiplier = 1.0;
switch (data_type() & DataType::Type) {
case DataType::Float32: multiplier = std::numeric_limits<uint8_t>::max(); break;
case DataType::Float64: multiplier = std::numeric_limits<uint16_t>::max(); break;
}
for (size_t i = 0; i != num_elements; ++i) {
Raw::store_BE<T> (std::min (default_type(std::numeric_limits<T>::max()), std::max (0.0, std::round(multiplier * fetch_func (in_ptr, 0, 0.0, 1.0)))), out_ptr);
in_ptr += data_type.bytes();
out_ptr += sizeof(T);
}
for (size_t i = 0; i != num_elements; ++i)
Raw::store_BE<T> (std::min (default_type(std::numeric_limits<T>::max()), std::max (0.0, std::round(multiplier * fetch_func (in_ptr, i, 0.0, 1.0)))), out_ptr, i);
};


Expand Down
14 changes: 8 additions & 6 deletions core/formats/png.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ namespace MR
// - 4 volumes (save as RGBA)
// This needs to be compatible with NameParser used in Header::create():
// "num_axes" subtracts from H.ndim() however many instances of [] there are
size_t width_axis = 0, axis_to_zero = 3;
// size_t width_axis = 0;
size_t axis_to_zero = 3;
if (H.ndim() - num_axes > 1)
throw Exception ("Cannot nominate more than one axis using square-bracket notation for PNG format");
switch (num_axes) {
Expand All @@ -170,7 +171,7 @@ namespace MR
axis_to_zero = 1;
} else if (H.size(0) == 1) {
axis_to_zero = 0;
width_axis = 1;
//width_axis = 1;
} else {
// If image is 3D, and all three axes have size greater than one, and we
// haven't used the square-bracket notation, we can't export genuine 3D data
Expand All @@ -192,8 +193,8 @@ namespace MR
}
if (axis < 0)
throw Exception ("Cannot export 4D image to PNG format if all three spatial axes have size greater than 1 and square-bracket notation is not used");
if (!axis_to_zero)
width_axis = 1;
// if (!axis_to_zero)
// width_axis = 1;
break;
default:
throw Exception ("Cannot generate PNG file(s) from image with more than 4 axes");
Expand Down Expand Up @@ -223,9 +224,10 @@ namespace MR

H.transform().setIdentity();

if (H.datatype() == DataType::Bit && H.size (width_axis) % 8) {
WARN ("Cannot write bitwise PNG image with width not a factor of 8; will instead write with 8-bit depth");
if (H.datatype() == DataType::Bit) {
WARN ("Cannot write bitwise PNG images; will instead write with 8-bit depth");
H.datatype() = DataType::UInt8;
H.intensity_scale() = 1.0 / 255.0;
}

return true;
Expand Down
7 changes: 6 additions & 1 deletion testing/binaries/tests/mrconvert
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,9 @@ mrconvert mrcat/voxel[].mih - | testing_diff_header -keyval - mrcat/all_axis0.mi
mrconvert mrcat/all_axis3.mif tmp-[].mif -force && testing_diff_header -keyval tmp-0.mif mrcat/voxel1.mih && testing_diff_header -keyval tmp-1.mif mrcat/voxel2.mih && testing_diff_header -keyval tmp-2.mif mrcat/voxel3.mih && testing_diff_header -keyval tmp-3.mif mrcat/voxel4.mih && testing_diff_header -keyval tmp-4.mif mrcat/voxel5.mih && testing_diff_header -keyval tmp-5.mif mrcat/voxel6.mih
mrconvert dwi.mif tmp-[]-[].mif -force && testing_diff_image dwi.mif tmp-[]-[].mif
mrconvert dwi.mif -coord 3 1:2:end -axes 0:2,-1,3 - | testing_diff_image - mrconvert/dwi_select_axes.mif

mrinfo template.mif.gz -transform > tmp.txt && mrconvert template.mif.gz tmp[].png -force && mrconvert tmp[].png -vox 2.5 - | mrtransform - -replace tmp.txt - | mrcalc - 255 -div - | testing_diff_image - $(mrcalc template.mif.gz 1.0 -min -) -abs 0.002
rm -f tmpaxial*.png && mrconvert template.mif.gz -coord 2 9,19,29,39,49 tmpaxial[].png && testing_diff_image tmpaxial[].png mrconvert/axial[].png
rm -f tmpcoronal*.png && mrconvert template.mif.gz -coord 1 17,32,47,62,77 -axes 0,2,1 tmpcoronal[].png && testing_diff_image tmpcoronal[].png mrconvert/coronal[].png
rm -f tmpsagittal*.png && mrconvert template.mif.gz -coord 0 27,47,67 -axes 1,2,0 tmpsagittal[].png && testing_diff_image tmpsagittal[].png mrconvert/sagittal[].png
rm -f tmpmask*.png && mrconvert mask.mif tmpmask[].png && testing_diff_image tmpmask[].png mrconvert/mask[].png
rm -f tmptissues*.png && mrconvert dwi2fod/msmt/tissues.mif tmptissues[].png && testing_diff_image tmptissues[].png mrconvert/tissues[].png

0 comments on commit 386db1f

Please sign in to comment.