From e3eebd34b75dad7038d97f35f9f7320810b7e092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 28 May 2019 14:39:53 +0200 Subject: [PATCH] Add templated Image{,View,Data}::pixels(). It's potentially dangerous because the user is responsible for choosing a correct type, on the other hand forcing them to do it verbosely through arrayCast() is both too annoying and too hard to explain. --- doc/snippets/Magnum.cpp | 3 +-- src/Magnum/Image.h | 36 +++++++++++++++++++------ src/Magnum/ImageView.h | 14 ++++++++++ src/Magnum/Test/ImageTest.cpp | 12 ++++----- src/Magnum/Test/ImageViewTest.cpp | 14 +++++----- src/Magnum/Trade/ImageData.h | 19 +++++++++++++ src/Magnum/Trade/Test/ImageDataTest.cpp | 8 +++--- 7 files changed, 79 insertions(+), 27 deletions(-) diff --git a/doc/snippets/Magnum.cpp b/doc/snippets/Magnum.cpp index b8d87ccf4..3a1647f26 100644 --- a/doc/snippets/Magnum.cpp +++ b/doc/snippets/Magnum.cpp @@ -68,8 +68,7 @@ std::nullptr_t data{}; /* [Image-pixels] */ Image2D image{PixelFormat::RGB8Unorm, {128, 128}, data}; -Containers::StridedArrayView2D pixels = - Containers::arrayCast<2, Color3ub>(image.pixels()); +Containers::StridedArrayView2D pixels = image.pixels(); for(auto row: pixels.slice({48, 48}, {80, 80})) { for(Color3ub& pixel: row) pixel *= 1.1f; } diff --git a/src/Magnum/Image.h b/src/Magnum/Image.h index 3e44af0a0..c5324a80c 100644 --- a/src/Magnum/Image.h +++ b/src/Magnum/Image.h @@ -79,14 +79,15 @@ do by hand even with the help of @ref dataProperties(). The @ref pixels() accessor returns a multi-dimensional @ref Corrade::Containers::StridedArrayView describing layout of the data and providing easy access to particular rows, pixels and pixel channels. The -returned view always has one dimension more than the actual image, with the -last dimension being bytes in a particular pixels. The second-to-last dimension -is always pixels in a row, the one before (if the image is at least 2D) is rows -in an image, and for 3D images the very first dimension describes image slices. -Desired usage is casting to a concrete type based on @ref format() first using -@ref Corrade::Containers::arrayCast() (which also flattens the last dimension) -and then operating on the concretely typed array. The following example -brightens the center 32x32 area of an image: +non-templated version returns a view that has one dimension more than the +actual image, with the last dimension being bytes in a particular pixels. The +second-to-last dimension is always pixels in a row, the one before (if the +image is at least 2D) is rows in an image, and for 3D images the very first +dimension describes image slices. Desired usage is casting to a concrete type +based on @ref format() first, either using the templated @ref pixels() or +using @ref Corrade::Containers::arrayCast() and then operating on the +concretely typed array. The following example brightens the center 32x32 area +of an image: @snippet Magnum.cpp Image-pixels @@ -382,6 +383,25 @@ template class Image { Containers::StridedArrayView pixels(); Containers::StridedArrayView pixels() const; /**< @overload */ + /** + * @brief View on pixel data with a concrete pixel type + * + * Compared to non-templated @ref pixels() in addition casts the pixel + * data to a specified type. The user is responsible for choosing + * correct type for given @ref format() --- checking it on the library + * side is not possible for the general case. + */ + template Containers::StridedArrayView pixels() { + /* Deliberately not adding a StridedArrayView include, it should + work without since this is a templated function */ + return Containers::arrayCast(pixels()); + } + + /** @overload */ + template Containers::StridedArrayView pixels() const { + return Containers::arrayCast(pixels()); + } + /** * @brief Release data storage * diff --git a/src/Magnum/ImageView.h b/src/Magnum/ImageView.h index bac1ea9a8..1e76af1bc 100644 --- a/src/Magnum/ImageView.h +++ b/src/Magnum/ImageView.h @@ -394,6 +394,20 @@ template class ImageView { */ Containers::StridedArrayView pixels() const; + /** + * @brief View on pixel data with a concrete pixel type + * + * Compared to non-templated @ref pixels() in addition casts the pixel + * data to a specified type. The user is responsible for choosing + * correct type for given @ref format() --- checking it on the library + * side is not possible for the general case. + */ + template Containers::StridedArrayView pixels() const { + /* Deliberately not adding a StridedArrayView include, it should + work without since this is a templated function */ + return Containers::arrayCast(pixels()); + } + private: PixelStorage _storage; PixelFormat _format; diff --git a/src/Magnum/Test/ImageTest.cpp b/src/Magnum/Test/ImageTest.cpp index a767fb444..9eff1d428 100644 --- a/src/Magnum/Test/ImageTest.cpp +++ b/src/Magnum/Test/ImageTest.cpp @@ -682,14 +682,14 @@ void ImageTest::pixels1D() { const Image1D& cimage = image; { - Containers::StridedArrayView1D pixels = Containers::arrayCast<1, Color3ub>(image.pixels()); + Containers::StridedArrayView1D pixels = image.pixels(); CORRADE_COMPARE(pixels.size(), 2); CORRADE_COMPARE(pixels.stride(), 3); CORRADE_COMPARE(pixels.data(), image.data() + 3*3); CORRADE_COMPARE(pixels[0], (Color3ub{3, 4, 5})); CORRADE_COMPARE(pixels[1], (Color3ub{6, 7, 8})); } { - Containers::StridedArrayView1D pixels = Containers::arrayCast<1, const Color3ub>(cimage.pixels()); + Containers::StridedArrayView1D pixels = cimage.pixels(); CORRADE_COMPARE(pixels.size(), 2); CORRADE_COMPARE(pixels.stride(), 3); CORRADE_COMPARE(pixels.data(), cimage.data() + 3*3); @@ -716,14 +716,14 @@ void ImageTest::pixels2D() { const Image2D& cimage = image; { - Containers::StridedArrayView2D pixels = Containers::arrayCast<2, Color3ub>(image.pixels()); + Containers::StridedArrayView2D pixels = image.pixels(); CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView2D::Size{4, 2})); CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView2D::Stride{20, 3})); CORRADE_COMPARE(pixels.data(), image.data() + 2*20 + 3*3); CORRADE_COMPARE(pixels[3][0], (Color3ub{4, 5, 6})); CORRADE_COMPARE(pixels[3][1], (Color3ub{7, 8, 9})); } { - Containers::StridedArrayView2D pixels = Containers::arrayCast<2, const Color3ub>(cimage.pixels()); + Containers::StridedArrayView2D pixels = cimage.pixels(); CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView2D::Size{4, 2})); CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView2D::Stride{20, 3})); CORRADE_COMPARE(pixels.data(), cimage.data() + 2*20 + 3*3); @@ -776,14 +776,14 @@ void ImageTest::pixels3D() { const Image3D& cimage = image; { - Containers::StridedArrayView3D pixels = Containers::arrayCast<3, Color3ub>(image.pixels()); + Containers::StridedArrayView3D pixels = image.pixels(); CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView3D::Size{3, 4, 2})); CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView3D::Stride{140, 20, 3})); CORRADE_COMPARE(pixels.data(), image.data() + 140 + 2*20 + 3*3); CORRADE_COMPARE(pixels[1][3][0], (Color3ub{9, 8, 7})); CORRADE_COMPARE(pixels[1][3][1], (Color3ub{6, 5, 4})); } { - Containers::StridedArrayView3D pixels = Containers::arrayCast<3, const Color3ub>(cimage.pixels()); + Containers::StridedArrayView3D pixels = cimage.pixels(); CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView3D::Size{3, 4, 2})); CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView3D::Stride{140, 20, 3})); CORRADE_COMPARE(pixels.data(), cimage.data() + 140 + 2*20 + 3*3); diff --git a/src/Magnum/Test/ImageViewTest.cpp b/src/Magnum/Test/ImageViewTest.cpp index caed82b9c..62d83a4fa 100644 --- a/src/Magnum/Test/ImageViewTest.cpp +++ b/src/Magnum/Test/ImageViewTest.cpp @@ -601,7 +601,7 @@ void ImageViewTest::pixels1D() { /* Full test is in ImageTest, this is just a sanity check */ - Containers::StridedArrayView1D pixels = Containers::arrayCast<1, const Color3ub>(image.pixels()); + Containers::StridedArrayView1D pixels = image.pixels(); CORRADE_COMPARE(pixels.size(), 2); CORRADE_COMPARE(pixels.stride(), 3); CORRADE_COMPARE(pixels.data(), image.data() + 3*3); @@ -618,9 +618,9 @@ void ImageViewTest::pixels2D() { /* Full test is in ImageTest, this is just a sanity check */ - Containers::StridedArrayView2D pixels = Containers::arrayCast<2, const Color3ub>(image.pixels()); - CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView2D::Size{4, 2})); - CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView2D::Stride{20, 3})); + Containers::StridedArrayView2D pixels = image.pixels(); + CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView2D::Size{4, 2})); + CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView2D::Stride{20, 3})); CORRADE_COMPARE(pixels.data(), image.data() + 2*20 + 3*3); } @@ -636,9 +636,9 @@ void ImageViewTest::pixels3D() { /* Full test is in ImageTest, this is just a sanity check */ - Containers::StridedArrayView3D pixels = Containers::arrayCast<3, const Color3ub>(image.pixels()); - CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView3D::Size{3, 4, 2})); - CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView3D::Stride{140, 20, 3})); + Containers::StridedArrayView3D pixels = image.pixels(); + CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView3D::Size{3, 4, 2})); + CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView3D::Stride{140, 20, 3})); CORRADE_COMPARE(pixels.data(), image.data() + 140 + 2*20 + 3*3); } diff --git a/src/Magnum/Trade/ImageData.h b/src/Magnum/Trade/ImageData.h index fdb5dbbbb..3452d84bd 100644 --- a/src/Magnum/Trade/ImageData.h +++ b/src/Magnum/Trade/ImageData.h @@ -361,6 +361,25 @@ template class ImageData { Containers::StridedArrayView pixels(); Containers::StridedArrayView pixels() const; /**< @overload */ + /** + * @brief View on pixel data with a concrete pixel type + * + * Compared to non-templated @ref pixels() in addition casts the pixel + * data to a specified type. The user is responsible for choosing + * correct type for given @ref format() --- checking it on the library + * side is not possible for the general case. + */ + template Containers::StridedArrayView pixels() { + /* Deliberately not adding a StridedArrayView include, it should + work without since this is a templated function */ + return Containers::arrayCast(pixels()); + } + + /** @overload */ + template Containers::StridedArrayView pixels() const { + return Containers::arrayCast(pixels()); + } + /** * @brief Release data storage * diff --git a/src/Magnum/Trade/Test/ImageDataTest.cpp b/src/Magnum/Trade/Test/ImageDataTest.cpp index 6a5aae9be..77c4a454e 100644 --- a/src/Magnum/Trade/Test/ImageDataTest.cpp +++ b/src/Magnum/Trade/Test/ImageDataTest.cpp @@ -603,7 +603,7 @@ void ImageDataTest::pixels1D() { /* Full test is in ImageTest, this is just a sanity check */ { - Containers::StridedArrayView1D pixels = Containers::arrayCast<1, Color3ub>(image.pixels()); + Containers::StridedArrayView1D pixels = image.pixels(); CORRADE_COMPARE(pixels.size(), 2); CORRADE_COMPARE(pixels.stride(), 3); CORRADE_COMPARE(pixels.data(), image.data() + 3*3); @@ -628,7 +628,7 @@ void ImageDataTest::pixels2D() { /* Full test is in ImageTest, this is just a sanity check */ { - Containers::StridedArrayView2D pixels = Containers::arrayCast<2, Color3ub>(image.pixels()); + Containers::StridedArrayView2D pixels = image.pixels(); CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView2D::Size{4, 2})); CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView2D::Stride{20, 3})); CORRADE_COMPARE(pixels.data(), image.data() + 2*20 + 3*3); @@ -654,12 +654,12 @@ void ImageDataTest::pixels3D() { /* Full test is in ImageTest, this is just a sanity check */ { - Containers::StridedArrayView3D pixels = Containers::arrayCast<3, Color3ub>(image.pixels()); + Containers::StridedArrayView3D pixels = image.pixels(); CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView3D::Size{3, 4, 2})); CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView3D::Stride{140, 20, 3})); CORRADE_COMPARE(pixels.data(), image.data() + 140 + 2*20 + 3*3); } { - Containers::StridedArrayView3D pixels = Containers::arrayCast<3, const Color3ub>(cimage.pixels()); + Containers::StridedArrayView3D pixels = cimage.pixels(); CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView3D::Size{3, 4, 2})); CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView3D::Stride{140, 20, 3})); CORRADE_COMPARE(pixels.data(), cimage.data() + 140 + 2*20 + 3*3);