Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

api: ImageSpec::scanline_bytes, tile_bytes, image_bytes #4631

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/include/OpenImageIO/imageio.h
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,13 @@ class OIIO_API ImageSpec {
/// overflow where it's not representable in an `imagesize_t`.
imagesize_t scanline_bytes (bool native=false) const noexcept;

/// Returns the number of bytes comprising each scanline, if all channels
/// were of the given type. If `type` is `TypeUnknown`, then it returns
/// the bytes a scanline using each channel's native type. This will
/// return `std::numeric_limits<imagesize_t>::max()` in the event of an
/// overflow where it's not representable in an `imagesize_t`.
imagesize_t scanline_bytes(TypeDesc type) const noexcept;

/// Return the number of pixels comprising a tile (or 0 if it is not a
/// tiled image). This will return
/// `std::numeric_limits<imagesize_t>::max()` in the event of an
Expand All @@ -404,6 +411,13 @@ class OIIO_API ImageSpec {
/// case of per-channel formats).
imagesize_t tile_bytes (bool native=false) const noexcept;

/// Returns the number of bytes comprising each tile, if all channels
/// were of the given type. If `type` is `TypeUnknown`, then it returns
/// the bytes a scanline using each channel's native type. This will
/// return `std::numeric_limits<imagesize_t>::max()` in the event of an
/// overflow where it's not representable in an `imagesize_t`.
imagesize_t tile_bytes(TypeDesc type) const noexcept;

/// Return the number of pixels for an entire image. This will
/// return `std::numeric_limits<imagesize_t>::max()` in the event of
/// an overflow where it's not representable in an `imagesize_t`.
Expand All @@ -420,6 +434,12 @@ class OIIO_API ImageSpec {
/// the case of per-channel formats).
imagesize_t image_bytes (bool native=false) const noexcept;

/// Returns the number of bytes comprising an entire image of these
/// dimensions, if the values were all of type `datatype`. For the
/// special case of `datatype == `TypeUnknown`, compute the size of
/// the image in the "native" data types for all channels.
imagesize_t image_bytes(TypeDesc datatype) const noexcept;

/// Verify that on this platform, a `size_t` is big enough to hold the
/// number of bytes (and pixels) in a scanline, a tile, and the
/// whole image. If this returns false, the image is much too big
Expand Down
33 changes: 33 additions & 0 deletions src/libOpenImageIO/formatspec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,17 @@ ImageSpec::scanline_bytes(bool native) const noexcept



imagesize_t
ImageSpec::scanline_bytes(TypeDesc type) const noexcept
{
return type == TypeUnknown
? scanline_bytes(true)
: clamped_mult64(clamped_mult64(size_t(width), size_t(nchannels)),
type.size());
}



imagesize_t
ImageSpec::tile_pixels() const noexcept
{
Expand All @@ -296,6 +307,17 @@ ImageSpec::tile_bytes(bool native) const noexcept



imagesize_t
ImageSpec::tile_bytes(TypeDesc type) const noexcept
{
return type == TypeUnknown
? tile_bytes(true)
: clamped_mult64(clamped_mult64(tile_pixels(), nchannels),
type.size());
}



imagesize_t
ImageSpec::image_pixels() const noexcept
{
Expand All @@ -317,6 +339,17 @@ ImageSpec::image_bytes(bool native) const noexcept



imagesize_t
ImageSpec::image_bytes(TypeDesc datatype) const noexcept
{
if (datatype == TypeUnknown)
return image_bytes(false); // special case: native size
return clamped_mult64(image_pixels(),
imagesize_t(nchannels) * datatype.size());
}



void
ImageSpec::attribute(string_view name, TypeDesc type, const void* value)
{
Expand Down
27 changes: 25 additions & 2 deletions src/libOpenImageIO/imagespec_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,42 @@ test_imagespec_pixels()
OIIO_CHECK_EQUAL((size_t)(BYTES_IN_FLOAT * CHANNELS), spec.pixel_bytes());
OIIO_CHECK_EQUAL((imagesize_t)(BYTES_IN_FLOAT * CHANNELS * WIDTH),
spec.scanline_bytes());
OIIO_CHECK_EQUAL((imagesize_t)(sizeof(uint16_t) * CHANNELS * WIDTH),
spec.scanline_bytes(TypeUInt16));
OIIO_CHECK_EQUAL(spec.scanline_bytes(true),
spec.scanline_bytes(TypeUnknown));
OIIO_CHECK_EQUAL((imagesize_t)(WIDTH * HEIGHT), spec.image_pixels());

// check that the magnitude is right (not clamped) -- should be about > 2^40
long long expected_bytes = BYTES_IN_FLOAT * CHANNELS * WIDTH * HEIGHT;
uint64_t expected_bytes = BYTES_IN_FLOAT * CHANNELS * WIDTH * HEIGHT;
// log (x) / log (2) = log2 (x)
// log (2^32) / log (2) = log2 (2^32) = 32
// log (2^32) * M_LOG2E = 32
double log2_result = log((double)expected_bytes) * M_LOG2E;
OIIO_CHECK_LT(40, log2_result);
OIIO_CHECK_EQUAL((imagesize_t)expected_bytes, spec.image_bytes());
OIIO_CHECK_EQUAL(expected_bytes, spec.image_bytes());

std::cout << "expected_bytes = " << expected_bytes << ", log "
<< log((double)expected_bytes) << std::endl;

OIIO_CHECK_EQUAL(spec.image_bytes(true), spec.image_bytes(TypeUnknown));
OIIO_CHECK_EQUAL(spec.image_bytes(false), spec.image_bytes(TypeFloat));

// Check tiles -- should be zero
OIIO_CHECK_EQUAL(spec.tile_bytes(), 0);
OIIO_CHECK_EQUAL(spec.tile_bytes(TypeUnknown), 0);
OIIO_CHECK_EQUAL(spec.tile_bytes(TypeUInt16), 0);
// Make apparent tiles and check
spec.tile_width = 7;
spec.tile_height = 5;
spec.tile_depth = 3;
OIIO_CHECK_EQUAL((imagesize_t)(BYTES_IN_FLOAT * spec.nchannels
* spec.tile_pixels()),
spec.tile_bytes());
OIIO_CHECK_EQUAL((imagesize_t)(sizeof(uint16_t) * spec.nchannels
* spec.tile_pixels()),
spec.tile_bytes(TypeUInt16));
OIIO_CHECK_EQUAL(spec.tile_bytes(true), spec.tile_bytes(TypeUnknown));
}


Expand Down
20 changes: 12 additions & 8 deletions src/python/py_imagespec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,6 @@ declare_imagespec(py::module& m)
return spec.channel_bytes(chan, native);
},
"channel"_a, "native"_a = false)
// .def("pixel_bytes",
// [](const ImageSpec &spec){ return spec.pixel_bytes(); })
.def(
"pixel_bytes",
[](const ImageSpec& spec, bool native) {
Expand All @@ -126,30 +124,36 @@ declare_imagespec(py::module& m)
return spec.pixel_bytes(chbegin, chend, native);
},
"chbegin"_a, "chend"_a, "native"_a = false)
// .def("scanline_bytes",
// [](const ImageSpec &spec){ return spec.scanline_bytes(); })
.def(
"scanline_bytes",
[](const ImageSpec& spec, bool native) {
return spec.scanline_bytes(native);
},
"native"_a = false)
// .def("tile_bytes",
// [](const ImageSpec &spec){ return spec.tile_bytes(); })
.def("scanline_bytes",
[](const ImageSpec& spec, TypeDesc type) {
return spec.scanline_bytes(type);
})
.def(
"tile_bytes",
[](const ImageSpec& spec, bool native) {
return spec.tile_bytes(native);
},
"native"_a = false)
// .def("image_bytes",
// [](const ImageSpec &spec){ return spec.image_bytes(); })
.def("tile_bytes", [](const ImageSpec& spec,
TypeDesc type) { return spec.tile_bytes(type); })
.def(
"image_bytes",
[](const ImageSpec& spec, bool native) {
return spec.image_bytes(native);
},
"native"_a = false)
.def(
"image_bytes",
[](const ImageSpec& spec, TypeDesc datatype) {
return spec.image_bytes(datatype);
},
"native"_a = false)
.def("tile_pixels", &ImageSpec::tile_pixels)
.def("image_pixels", &ImageSpec::image_pixels)
.def("size_t_safe", &ImageSpec::size_t_safe)
Expand Down
6 changes: 3 additions & 3 deletions testsuite/python-imagespec/ref/out-python3.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ channel bytes = 4
channel_bytes(1) = 4 native 1
channel_bytes(4) = 4 native 4
pixel bytes = 20 native 8
scanline bytes = 12800 native 5120
tile bytes = 655360 native 262144
image bytes = 6144000 native 2457600
scanline bytes = 12800 native 5120 if uint16 6400
tile bytes = 655360 native 262144 if uint16 327680
image bytes = 6144000 native 2457600 if uint16 3072000
tile pixels = 32768
image_pixels = 307200
size_t_safe = True
Expand Down
6 changes: 3 additions & 3 deletions testsuite/python-imagespec/ref/out.txt
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ channel bytes = 4
channel_bytes(1) = 4 native 1
channel_bytes(4) = 4 native 4
pixel bytes = 20 native 8
scanline bytes = 12800 native 5120
tile bytes = 655360 native 262144
image bytes = 6144000 native 2457600
scanline bytes = 12800 native 5120 if uint16 6400
tile bytes = 655360 native 262144 if uint16 327680
image bytes = 6144000 native 2457600 if uint16 3072000
tile pixels = 32768
image_pixels = 307200
size_t_safe = True
Expand Down
6 changes: 3 additions & 3 deletions testsuite/python-imagespec/src/test_imagespec.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ def print_imagespec (spec, msg="") :
print (" channel_bytes(1) =", s.channel_bytes(1), "native", s.channel_bytes(1,True))
print (" channel_bytes(4) =", s.channel_bytes(4), "native", s.channel_bytes(4,True))
print ("pixel bytes =", s.pixel_bytes(), "native", s.pixel_bytes(True))
print ("scanline bytes =", s.scanline_bytes(), "native", s.scanline_bytes(True))
print ("tile bytes =", s.tile_bytes(), "native", s.tile_bytes(True))
print ("image bytes =", s.image_bytes(), "native", s.image_bytes(True))
print ("scanline bytes =", s.scanline_bytes(), "native", s.scanline_bytes(True), "if uint16", s.scanline_bytes("uint16"))
print ("tile bytes =", s.tile_bytes(), "native", s.tile_bytes(True), "if uint16", s.tile_bytes("uint16"))
print ("image bytes =", s.image_bytes(), "native", s.image_bytes(True), "if uint16", s.image_bytes("uint16"))
print ("tile pixels =", s.tile_pixels())
print ("image_pixels =", s.image_pixels())
print ("size_t_safe =", s.size_t_safe())
Expand Down
Loading