Browse Source

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.
pull/344/head
Vladimír Vondruš 7 years ago
parent
commit
e3eebd34b7
  1. 3
      doc/snippets/Magnum.cpp
  2. 36
      src/Magnum/Image.h
  3. 14
      src/Magnum/ImageView.h
  4. 12
      src/Magnum/Test/ImageTest.cpp
  5. 14
      src/Magnum/Test/ImageViewTest.cpp
  6. 19
      src/Magnum/Trade/ImageData.h
  7. 8
      src/Magnum/Trade/Test/ImageDataTest.cpp

3
doc/snippets/Magnum.cpp

@ -68,8 +68,7 @@ std::nullptr_t data{};
/* [Image-pixels] */
Image2D image{PixelFormat::RGB8Unorm, {128, 128}, data};
Containers::StridedArrayView2D<Color3ub> pixels =
Containers::arrayCast<2, Color3ub>(image.pixels());
Containers::StridedArrayView2D<Color3ub> pixels = image.pixels<Color3ub>();
for(auto row: pixels.slice({48, 48}, {80, 80})) {
for(Color3ub& pixel: row) pixel *= 1.1f;
}

36
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<T>() 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<UnsignedInt dimensions> class Image {
Containers::StridedArrayView<dimensions + 1, char> pixels();
Containers::StridedArrayView<dimensions + 1, const char> 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<class T> Containers::StridedArrayView<dimensions, T> pixels() {
/* Deliberately not adding a StridedArrayView include, it should
work without since this is a templated function */
return Containers::arrayCast<dimensions, T>(pixels());
}
/** @overload */
template<class T> Containers::StridedArrayView<dimensions, const T> pixels() const {
return Containers::arrayCast<dimensions, const T>(pixels());
}
/**
* @brief Release data storage
*

14
src/Magnum/ImageView.h

@ -394,6 +394,20 @@ template<UnsignedInt dimensions> class ImageView {
*/
Containers::StridedArrayView<dimensions + 1, const char> 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<class T> Containers::StridedArrayView<dimensions, const T> pixels() const {
/* Deliberately not adding a StridedArrayView include, it should
work without since this is a templated function */
return Containers::arrayCast<dimensions, const T>(pixels());
}
private:
PixelStorage _storage;
PixelFormat _format;

12
src/Magnum/Test/ImageTest.cpp

@ -682,14 +682,14 @@ void ImageTest::pixels1D() {
const Image1D& cimage = image;
{
Containers::StridedArrayView1D<Color3ub> pixels = Containers::arrayCast<1, Color3ub>(image.pixels());
Containers::StridedArrayView1D<Color3ub> pixels = image.pixels<Color3ub>();
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<const Color3ub> pixels = Containers::arrayCast<1, const Color3ub>(cimage.pixels());
Containers::StridedArrayView1D<const Color3ub> pixels = cimage.pixels<Color3ub>();
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<Color3ub> pixels = Containers::arrayCast<2, Color3ub>(image.pixels());
Containers::StridedArrayView2D<Color3ub> pixels = image.pixels<Color3ub>();
CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView2D<Color3ub>::Size{4, 2}));
CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView2D<Color3ub>::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<const Color3ub> pixels = Containers::arrayCast<2, const Color3ub>(cimage.pixels());
Containers::StridedArrayView2D<const Color3ub> pixels = cimage.pixels<Color3ub>();
CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView2D<const Color3ub>::Size{4, 2}));
CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView2D<const Color3ub>::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<Color3ub> pixels = Containers::arrayCast<3, Color3ub>(image.pixels());
Containers::StridedArrayView3D<Color3ub> pixels = image.pixels<Color3ub>();
CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView3D<Color3ub>::Size{3, 4, 2}));
CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView3D<Color3ub>::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<const Color3ub> pixels = Containers::arrayCast<3, const Color3ub>(cimage.pixels());
Containers::StridedArrayView3D<const Color3ub> pixels = cimage.pixels<Color3ub>();
CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView3D<const Color3ub>::Size{3, 4, 2}));
CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView3D<const Color3ub>::Stride{140, 20, 3}));
CORRADE_COMPARE(pixels.data(), cimage.data() + 140 + 2*20 + 3*3);

14
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<const Color3ub> pixels = Containers::arrayCast<1, const Color3ub>(image.pixels());
Containers::StridedArrayView1D<const Color3ub> pixels = image.pixels<Color3ub>();
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<const Color3ub> pixels = Containers::arrayCast<2, const Color3ub>(image.pixels());
CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView2D<const Color3ub>::Size{4, 2}));
CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView2D<const Color3ub>::Stride{20, 3}));
Containers::StridedArrayView2D<const Color3ub> pixels = image.pixels<Color3ub>();
CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView2D<Color3ub>::Size{4, 2}));
CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView2D<Color3ub>::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<const Color3ub> pixels = Containers::arrayCast<3, const Color3ub>(image.pixels());
CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView3D<const Color3ub>::Size{3, 4, 2}));
CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView3D<const Color3ub>::Stride{140, 20, 3}));
Containers::StridedArrayView3D<const Color3ub> pixels = image.pixels<Color3ub>();
CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView3D<Color3ub>::Size{3, 4, 2}));
CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView3D<Color3ub>::Stride{140, 20, 3}));
CORRADE_COMPARE(pixels.data(), image.data() + 140 + 2*20 + 3*3);
}

19
src/Magnum/Trade/ImageData.h

@ -361,6 +361,25 @@ template<UnsignedInt dimensions> class ImageData {
Containers::StridedArrayView<dimensions + 1, char> pixels();
Containers::StridedArrayView<dimensions + 1, const char> 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<class T> Containers::StridedArrayView<dimensions, T> pixels() {
/* Deliberately not adding a StridedArrayView include, it should
work without since this is a templated function */
return Containers::arrayCast<dimensions, T>(pixels());
}
/** @overload */
template<class T> Containers::StridedArrayView<dimensions, const T> pixels() const {
return Containers::arrayCast<dimensions, const T>(pixels());
}
/**
* @brief Release data storage
*

8
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<Color3ub> pixels = Containers::arrayCast<1, Color3ub>(image.pixels());
Containers::StridedArrayView1D<Color3ub> pixels = image.pixels<Color3ub>();
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<Color3ub> pixels = Containers::arrayCast<2, Color3ub>(image.pixels());
Containers::StridedArrayView2D<Color3ub> pixels = image.pixels<Color3ub>();
CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView2D<Color3ub>::Size{4, 2}));
CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView2D<Color3ub>::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<Color3ub> pixels = Containers::arrayCast<3, Color3ub>(image.pixels());
Containers::StridedArrayView3D<Color3ub> pixels = image.pixels<Color3ub>();
CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView3D<Color3ub>::Size{3, 4, 2}));
CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView3D<Color3ub>::Stride{140, 20, 3}));
CORRADE_COMPARE(pixels.data(), image.data() + 140 + 2*20 + 3*3);
} {
Containers::StridedArrayView3D<const Color3ub> pixels = Containers::arrayCast<3, const Color3ub>(cimage.pixels());
Containers::StridedArrayView3D<const Color3ub> pixels = cimage.pixels<Color3ub>();
CORRADE_COMPARE(pixels.size(), (Containers::StridedArrayView3D<const Color3ub>::Size{3, 4, 2}));
CORRADE_COMPARE(pixels.stride(), (Containers::StridedArrayView3D<const Color3ub>::Stride{140, 20, 3}));
CORRADE_COMPARE(pixels.data(), cimage.data() + 140 + 2*20 + 3*3);

Loading…
Cancel
Save