Browse Source

Improve docs of image classes.

It looked like it was last touched in 2012. Not great. Also, with this I
can finally stop explaining the four-byte-aligned-row defaults to people
and can just point them to docs.
pull/620/head
Vladimír Vondruš 3 years ago
parent
commit
fe0a46abad
  1. 75
      doc/snippets/Magnum.cpp
  2. 65
      doc/snippets/MagnumTrade.cpp
  3. 60
      src/Magnum/Image.h
  4. 57
      src/Magnum/ImageView.h
  5. 82
      src/Magnum/Trade/ImageData.h

75
doc/snippets/Magnum.cpp

@ -113,7 +113,7 @@ std::nullptr_t data = nullptr;
Image2D image{PixelFormat::RGB8Unorm, {128, 128}, data}; Image2D image{PixelFormat::RGB8Unorm, {128, 128}, data};
Containers::StridedArrayView2D<Color3ub> pixels = image.pixels<Color3ub>(); Containers::StridedArrayView2D<Color3ub> pixels = image.pixels<Color3ub>();
for(auto row: pixels.slice({48, 48}, {80, 80})) { for(auto row: pixels.sliceSize({48, 48}, {32, 32})) {
for(Color3ub& pixel: row) pixel *= 1.1f; for(Color3ub& pixel: row) pixel *= 1.1f;
} }
/* [Image-pixels] */ /* [Image-pixels] */
@ -122,10 +122,23 @@ for(auto row: pixels.slice({48, 48}, {80, 80})) {
{ {
char data[3]; char data[3];
/* [ImageView-usage] */ /* [ImageView-usage] */
ImageView2D image{PixelFormat::RGBA8Unorm, {512, 256}, data}; ImageView2D view{PixelFormat::RGBA8Unorm, {512, 256}, data};
/* [ImageView-usage] */ /* [ImageView-usage] */
} }
{
char tightlyPackedData[3];
/* [ImageView-usage-alignment] */
PixelFormat format = DOXYGEN_ELLIPSIS({});
Vector2i size = DOXYGEN_ELLIPSIS({});
std::size_t rowLength = size.x()*pixelFormatSize(format);
ImageView2D view{
PixelStorage{}.setAlignment(rowLength % 4 == 0 ? 4 : 1),
format, size, tightlyPackedData};
/* [ImageView-usage-alignment] */
}
{ {
char evenFrameData[3], oddFrameData[3]; char evenFrameData[3], oddFrameData[3];
/* [ImageView-usage-streaming] */ /* [ImageView-usage-streaming] */
@ -142,10 +155,10 @@ frame.setData(oddFrameData);
{ {
char data[3]; char data[3];
/* [ImageView-usage-storage] */ /* [ImageView-usage-storage] */
ImageView2D image{ ImageView2D view{
PixelStorage{} PixelStorage{}
.setAlignment(1)
.setRowLength(75) .setRowLength(75)
.setAlignment(4)
.setSkip({25, 25, 0}), .setSkip({25, 25, 0}),
PixelFormat::RGBA8Unorm, {25, 25}, data}; PixelFormat::RGBA8Unorm, {25, 25}, data};
/* [ImageView-usage-storage] */ /* [ImageView-usage-storage] */
@ -155,13 +168,13 @@ ImageView2D image{
{ {
char data[3]; char data[3];
/* [ImageView-usage-gl] */ /* [ImageView-usage-gl] */
ImageView2D image{GL::PixelFormat::DepthComponent, ImageView2D view{GL::PixelFormat::DepthComponent,
GL::PixelType::UnsignedInt, {512, 256}, data}; GL::PixelType::UnsignedInt, {512, 256}, data};
/* [ImageView-usage-gl] */ /* [ImageView-usage-gl] */
/* [ImageView-usage-gl-extract] */ /* [ImageView-usage-gl-extract] */
auto format = pixelFormatUnwrap<GLenum>(image.format()); auto format = pixelFormatUnwrap<GLenum>(view.format());
auto type = GLenum(image.formatExtra()); auto type = GLenum(view.formatExtra());
/* [ImageView-usage-gl-extract] */ /* [ImageView-usage-gl-extract] */
static_cast<void>(format); static_cast<void>(format);
static_cast<void>(type); static_cast<void>(type);
@ -180,7 +193,7 @@ ImageView2D view{{}, MTLPixelFormatRGBA8Unorm_sRGB, {}, 4, {256, 256}, data};
{ {
char data[3]; char data[3];
/* [CompressedImageView-usage] */ /* [CompressedImageView-usage] */
CompressedImageView2D image{CompressedPixelFormat::Bc1RGBUnorm, CompressedImageView2D view{CompressedPixelFormat::Bc1RGBUnorm,
{512, 256}, data}; {512, 256}, data};
/* [CompressedImageView-usage] */ /* [CompressedImageView-usage] */
} }
@ -201,7 +214,7 @@ frame.setData(oddFrameData);
{ {
char data[3]; char data[3];
/* [CompressedImageView-usage-storage] */ /* [CompressedImageView-usage-storage] */
CompressedImageView2D image{ CompressedImageView2D view{
CompressedPixelStorage{} CompressedPixelStorage{}
.setRowLength(64) .setRowLength(64)
.setCompressedBlockSize({4, 4, 1}) .setCompressedBlockSize({4, 4, 1})
@ -215,12 +228,12 @@ CompressedImageView2D image{
{ {
char data[3]; char data[3];
/* [CompressedImageView-usage-gl] */ /* [CompressedImageView-usage-gl] */
CompressedImageView2D image{GL::CompressedPixelFormat::SignedRGRgtc2, CompressedImageView2D view{GL::CompressedPixelFormat::SignedRGRgtc2,
{512, 256}, data}; {512, 256}, data};
/* [CompressedImageView-usage-gl] */ /* [CompressedImageView-usage-gl] */
/* [CompressedImageView-usage-gl-extract] */ /* [CompressedImageView-usage-gl-extract] */
auto format = compressedPixelFormatUnwrap<GLenum>(image.format()); auto format = compressedPixelFormatUnwrap<GLenum>(view.format());
/* [CompressedImageView-usage-gl-extract] */ /* [CompressedImageView-usage-gl-extract] */
static_cast<void>(format); static_cast<void>(format);
} }
@ -228,26 +241,50 @@ static_cast<void>(format);
{ {
/* [Image-usage] */ /* [Image-usage] */
Containers::Array<char> data; Vector2i size{512, 256};
Image2D image{PixelFormat::RGBA8Unorm, {512, 256}, std::move(data)}; PixelFormat format = PixelFormat::RGBA8Unorm;
Image2D image{format, size, Containers::Array<char>{ValueInit,
std::size_t(size.product()*pixelFormatSize(format))}};
/* [Image-usage] */ /* [Image-usage] */
} }
{
/* [Image-usage-padding] */
PixelFormat format = PixelFormat::RGB8Unorm;
Vector2i size{173, 232};
std::size_t rowStride = 4*((size.x()*pixelFormatSize(format) + 3)/4);
Image2D image{format, size,
Containers::Array<char>{ValueInit, std::size_t(size.y()*rowStride)}};
/* [Image-usage-padding] */
}
{
/* [Image-usage-alignment] */
Vector2i size{173, 232};
PixelFormat format = PixelFormat::RGB8Unorm;
std::size_t rowLength = size.x()*pixelFormatSize(format);
Image2D image{
PixelStorage{}.setAlignment(rowLength % 4 == 0 ? 4 : 1), format, size,
Containers::Array<char>{ValueInit, std::size_t(size.y()*rowLength)}};
/* [Image-usage-alignment] */
}
#if defined(MAGNUM_TARGET_GL) && !defined(MAGNUM_TARGET_GLES) #if defined(MAGNUM_TARGET_GL) && !defined(MAGNUM_TARGET_GLES)
{ {
/* [Image-usage-query] */ /* [Image-usage-query] */
GL::Texture2D texture; GL::Texture2D texture;
Image2D image = texture.image(0, {GL::PixelFormat::DepthComponent, Image2D image = texture.image(0, Image2D{PixelFormat::Depth32F});
GL::PixelType::UnsignedInt});
/* [Image-usage-query] */ /* [Image-usage-query] */
} }
#endif #endif
{ {
/* [CompressedImage-usage] */ /* [CompressedImage-usage] */
Containers::Array<char> data;
CompressedImage2D image{CompressedPixelFormat::Bc1RGBUnorm, CompressedImage2D image{CompressedPixelFormat::Bc1RGBUnorm,
{512, 256}, std::move(data)}; {512, 256}, Containers::Array<char>{ValueInit, DOXYGEN_ELLIPSIS(0)}};
/* [CompressedImage-usage] */ /* [CompressedImage-usage] */
} }
@ -255,7 +292,7 @@ CompressedImage2D image{CompressedPixelFormat::Bc1RGBUnorm,
{ {
/* [CompressedImage-usage-query] */ /* [CompressedImage-usage-query] */
GL::Texture2D texture; GL::Texture2D texture;
CompressedImage2D image = texture.compressedImage(0, {}); CompressedImage2D image = texture.compressedImage(0, CompressedImage2D{});
/* [CompressedImage-usage-query] */ /* [CompressedImage-usage-query] */
} }
#endif #endif

65
doc/snippets/MagnumTrade.cpp

@ -415,34 +415,67 @@ for(UnsignedInt i = 0; i != data.trackCount(); ++i) {
} }
{ {
/* [ImageData-construction] */ /* [ImageData-populating] */
Containers::Array<char> data; Containers::Array<char> uncompressedData = DOXYGEN_ELLIPSIS({});
Trade::ImageData2D image{PixelFormat::RGB8Unorm, {32, 32}, std::move(data)}; Trade::ImageData2D uncompressed{PixelFormat::RGB8Unorm,
/* [ImageData-construction] */ {32, 32}, std::move(uncompressedData)};
Containers::Array<char> compressedData = DOXYGEN_ELLIPSIS({});
Trade::ImageData2D compressed{CompressedPixelFormat::Bc1RGBUnorm,
{32, 32}, std::move(compressedData)};
/* [ImageData-populating] */
}
{
/* [ImageData-populating-non-owned] */
Color3ub uncompressedData[]{DOXYGEN_ELLIPSIS({})};
Trade::ImageData2D uncompressed{PixelFormat::RGB8Unorm,
{32, 32}, Trade::DataFlag::Mutable, uncompressedData};
Containers::ArrayView<const char> compressedData = DOXYGEN_ELLIPSIS({});
Trade::ImageData2D compressed{CompressedPixelFormat::Bc1RGBUnorm,
{32, 32}, Trade::DataFlags{}, compressedData};
/* [ImageData-populating-non-owned] */
}
{
/* [ImageData-populating-padding] */
PixelFormat format = DOXYGEN_ELLIPSIS({});
Vector2i size = DOXYGEN_ELLIPSIS({});
std::size_t rowStride = 4*((size.x()*pixelFormatSize(format) + 3)/4);
Containers::Array<char> data{ValueInit, std::size_t(size.y()*rowStride)};
DOXYGEN_ELLIPSIS()
Trade::ImageData2D image{format, size, std::move(data)};
/* [ImageData-populating-padding] */
} }
{ {
/* [ImageData-construction-compressed] */ /* [ImageData-populating-alignment] */
Containers::Array<char> data; PixelFormat format = DOXYGEN_ELLIPSIS({});
Trade::ImageData2D image{CompressedPixelFormat::Bc1RGBUnorm, Vector2i size = DOXYGEN_ELLIPSIS({});
{32, 32}, std::move(data)}; std::size_t rowLength = size.x()*pixelFormatSize(format);
/* [ImageData-construction-compressed] */ Containers::Array<char> data{ValueInit, std::size_t(size.y()*rowLength)};
DOXYGEN_ELLIPSIS()
Trade::ImageData2D image{
PixelStorage{}.setAlignment(rowLength % 4 == 0 ? 4 : 1),
format, size, std::move(data)};
/* [ImageData-populating-alignment] */
} }
#ifdef MAGNUM_TARGET_GL #ifdef MAGNUM_TARGET_GL
{ {
/* [ImageData-usage] */ /* [ImageData-usage] */
Containers::Pointer<Trade::AbstractImporter> importer; Trade::ImageData2D image = DOXYGEN_ELLIPSIS(Trade::ImageData2D{PixelFormat{}, {}, nullptr});
Containers::Optional<Trade::ImageData2D> image = importer->image2D(0);
if(!image) Fatal{} << "Oopsie!";
GL::Texture2D texture; GL::Texture2D texture;
DOXYGEN_ELLIPSIS() DOXYGEN_ELLIPSIS()
texture.setStorage(1, GL::textureFormat(image->format()), image->size()); texture.setStorage(1, GL::textureFormat(image.format()), image.size());
if(!image->isCompressed()) if(!image.isCompressed())
texture.setSubImage(0, {}, *image); texture.setSubImage(0, {}, image);
else else
texture.setCompressedSubImage(0, {}, *image); texture.setCompressedSubImage(0, {}, image);
/* [ImageData-usage] */ /* [ImageData-usage] */
} }
#endif #endif

60
src/Magnum/Image.h

@ -62,19 +62,27 @@ functionality targeted on compressed image formats.
@section Image-usage Basic usage @section Image-usage Basic usage
The image takes ownership of a passed @ref Corrade::Containers::Array, together The image takes ownership of a passed @relativeref{Corrade,Containers::Array},
with storing image size and one of the generic @ref PixelFormat values: together with a @ref PixelFormat and size in pixels:
@snippet Magnum.cpp Image-usage @snippet Magnum.cpp Image-usage
On construction, the image internally calculates pixel size corresponding to The constructor internally checks that the passed array is large enough. For
given pixel format using @ref pixelFormatSize(). This value is needed to check performance reasons it by default expects rows aligned to four bytes, which you
that the passed data array is large enough and is also required by most image need to account for if using odd image sizes in combination with one-, two- or
manipulation operations. three-component formats. The recommended way is to pad the row data to satisfy
the alignment:
@snippet Magnum.cpp Image-usage-padding
Alternatively, if padding is not possible or desirable, you can pass a
@ref PixelStorage instance with the alignment overriden to @cpp 1 @ce:
@snippet Magnum.cpp Image-usage-alignment
It's also possible to create just an image placeholder, storing only the image It's also possible to create just an image placeholder, storing only the image
properties without data or size. That is useful for example to specify desired properties without data or size. That is useful for example to specify desired
format of image queries in graphics APIs: format of image queries in graphics APIs such as @ref GL::Texture::image():
@snippet Magnum.cpp Image-usage-query @snippet Magnum.cpp Image-usage-query
@ -82,7 +90,7 @@ As with @ref ImageView, this class supports extra storage parameters and
implementation-specific pixel format specification. See the @ref ImageView implementation-specific pixel format specification. See the @ref ImageView
documentation for more information. documentation for more information.
@section Image-pixel-views Obtaining a view on pixel data @section Image-pixel-access Pixel data access
While the raw image data are available through @ref data(), for correct pixel While the raw image data are available through @ref data(), for correct pixel
addressing it's required to incorporate all @ref storage() parameters such as addressing it's required to incorporate all @ref storage() parameters such as
@ -90,30 +98,29 @@ row alignment, row length, skip offset and such. This is very error-prone to
do by hand even with the help of @ref dataProperties(). do by hand even with the help of @ref dataProperties().
The @ref pixels() accessor returns a multi-dimensional The @ref pixels() accessor returns a multi-dimensional
@ref Corrade::Containers::StridedArrayView describing layout of the data and @relativeref{Corrade,Containers::StridedArrayView} describing layout of the
providing easy access to particular rows, pixels and pixel channels. The data and providing easy access to particular rows, pixels and pixel contents.
non-templated version returns a view that has one dimension more than the The 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 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 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 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 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 based on @ref format() first, either using the templated @ref pixels<T>() or
using @ref Corrade::Containers::arrayCast() and then operating on the using @relativeref{Corrade,Containers::arrayCast()} and then operating on the
concretely typed array. The following example brightens the center 32x32 area concretely typed array. The following example brightens the center 32x32 area
of an image: of an image:
@snippet Magnum.cpp Image-pixels @snippet Magnum.cpp Image-pixels
@attention Note that the correctness of the cast is can't be generally checked @attention Note that the correctness of the cast can't be generally checked
apart from expecting that the last dimension size is equal to the new type apart from comparing that the last dimension size to the type size. It's
size. It's the user responsibility to ensure the type matches given the user responsibility to ensure the type matches given @ref format().
@ref format().
This operation is available also on @ref ImageView and non-compressed
@ref Trade::ImageData. See @ref Corrade::Containers::StridedArrayView docs for
more information about transforming, slicing and converting the view further.
@see @ref Image1D, @ref Image2D, @ref Image3D, @ref CompressedImage This operation is available also on a @ref ImageView, and non-compressed
@ref Trade::ImageData. See @relativeref{Corrade,Containers::StridedArrayView}
docs for more information about transforming, slicing and casting the view
further.
@see @ref Image1D, @ref Image2D, @ref Image3D
*/ */
template<UnsignedInt dimensions> class Image { template<UnsignedInt dimensions> class Image {
public: public:
@ -460,7 +467,7 @@ template<UnsignedInt dimensions> class Image {
* @m_since{2019,10} * @m_since{2019,10}
* *
* Provides direct and easy-to-use access to image pixels. See * Provides direct and easy-to-use access to image pixels. See
* @ref Image-pixel-views for more information. * @ref Image-pixel-access for more information.
*/ */
Containers::StridedArrayView<dimensions + 1, char> pixels(); Containers::StridedArrayView<dimensions + 1, char> pixels();
Containers::StridedArrayView<dimensions + 1, const char> pixels() const; /**< @overload */ Containers::StridedArrayView<dimensions + 1, const char> pixels() const; /**< @overload */
@ -472,7 +479,8 @@ template<UnsignedInt dimensions> class Image {
* Compared to non-templated @ref pixels() in addition casts the pixel * Compared to non-templated @ref pixels() in addition casts the pixel
* data to a specified type. The user is responsible for choosing * data to a specified type. The user is responsible for choosing
* correct type for given @ref format() --- checking it on the library * correct type for given @ref format() --- checking it on the library
* side is not possible for the general case. * side is not possible for the general case. See also
* @ref Image-pixel-access for more information.
*/ */
template<class T> Containers::StridedArrayView<dimensions, T> pixels() { template<class T> Containers::StridedArrayView<dimensions, T> pixels() {
/* Deliberately not adding a StridedArrayView include, it should /* Deliberately not adding a StridedArrayView include, it should
@ -535,9 +543,8 @@ for equivalent functionality targeted on non-compressed image formats.
@section CompressedImage-usage Basic usage @section CompressedImage-usage Basic usage
The image takes ownership of a passed @ref Corrade::Containers::Array, together The image takes ownership of a passed @relativeref{Corrade,Containers::Array},
with storing image size and one of the generic @ref CompressedPixelFormat together with a @ref CompressedPixelFormat and size in pixels:
values:
@snippet Magnum.cpp CompressedImage-usage @snippet Magnum.cpp CompressedImage-usage
@ -550,7 +557,6 @@ format of image queries in graphics APIs:
As with @ref CompressedImageView, this class supports extra storage parameters As with @ref CompressedImageView, this class supports extra storage parameters
and implementation-specific compressed pixel format specification. See its and implementation-specific compressed pixel format specification. See its
documentation for more information. documentation for more information.
@see @ref CompressedImage1D, @ref CompressedImage2D, @ref CompressedImage3D @see @ref CompressedImage1D, @ref CompressedImage2D, @ref CompressedImage3D
*/ */
template<UnsignedInt dimensions> class CompressedImage { template<UnsignedInt dimensions> class CompressedImage {

57
src/Magnum/ImageView.h

@ -66,16 +66,20 @@ functionality targeted on compressed image formats.
@section ImageView-usage Basic usage @section ImageView-usage Basic usage
Usually, the view is created on some pre-existing data array in order to The view is created from a @ref PixelFormat, size in pixels and a data view:
describe its layout, with pixel format being one of the values from the generic
@link PixelFormat @endlink:
@snippet Magnum.cpp ImageView-usage @snippet Magnum.cpp ImageView-usage
On construction, the image view internally calculates pixel size corresponding The constructor internally checks that the passed array is large enough. For
to given pixel format using @ref pixelFormatSize(). This value is needed to performance reasons it by default expects rows aligned to four bytes, which you
check that the passed data array is large enough and is also required by most need to account for if using odd image sizes in combination with one-, two- or
image manipulation operations. three-component formats. While the recommended way is to pad the row data to
satisfy the alignment similarly as shown in @ref Image-usage "Image usage docs",
but with views it's more likely that you have to adapt to a layout of an
existing data array by passing a @ref PixelStorage instance with the alignment
value overriden if needed:
@snippet Magnum.cpp ImageView-usage-alignment
It's also possible to create an empty view and assign the memory later. That is It's also possible to create an empty view and assign the memory later. That is
useful for example in case of multi-buffered video streaming, where each frame useful for example in case of multi-buffered video streaming, where each frame
@ -83,25 +87,27 @@ has the same properties but a different memory location:
@snippet Magnum.cpp ImageView-usage-streaming @snippet Magnum.cpp ImageView-usage-streaming
It's possible to have views on image sub-rectangles, 3D texture slices or The @ref PixelStorage also allows for specifying arbitrary image slices by
images with over-aligned rows by passing a particular @ref PixelStorage as passing appropriate row length, image height and skip parameters. In the
first parameter. In the following snippet, the view is the center 25x25 following snippet, the view is the center 25x25 sub-rectangle of a 75x75 8-bit
sub-rectangle of a 75x75 8-bit RGB image , with rows aligned to four bytes: RGB image (with tightly packed rows again):
@snippet Magnum.cpp ImageView-usage-storage @snippet Magnum.cpp ImageView-usage-storage
Image views provides pixel data access via @ref pixels() in the same way as the
@ref Image class. See @ref Image-pixel-access "its documentation for more information".
@section ImageView-mutable Data mutability @section ImageView-mutable Data mutability
When using types derived from @ref BasicImageView (e.g. @ref ImageView2D), the The @ref ImageView2D type and related one- and three-dimensional variants only
viewed data are immutable. This is the most common use case. In order to be provide immutable access to the referenced data, as that's the most common use
able to mutate the underlying data (for example in order to read into a case. In order to be able to modify the data (for example in order to read into
pre-allocated memory), use @ref BasicMutableImageView a pre-allocated memory), use @ref MutableImageView2D and friends instead.
(e.g. @ref MutableImageView2D) instead. @ref Image and @ref Trade::ImageData @ref Image and @ref Trade::ImageData are convertible to either of these.
are convertible to either of these. Similarly to Similarly to @ref Corrade::Containers::ArrayView etc., a mutable view is also
@ref Corrade::Containers::ArrayView etc., a mutable view is also implicitly implicitly convertible to a const one.
convertible to a const one.
@subsection ImageView-usage-implementation-specific Implementation-specific formats @section ImageView-usage-implementation-specific Implementation-specific formats
For known graphics APIs, there's a set of utility functions converting from For known graphics APIs, there's a set of utility functions converting from
@ref PixelFormat to implementation-specific format identifiers and such @ref PixelFormat to implementation-specific format identifiers and such
@ -138,7 +144,7 @@ image view using Metal-specific format identifier:
@see @ref BasicImageView, @ref ImageView1D, @ref ImageView2D, @ref ImageView3D, @see @ref BasicImageView, @ref ImageView1D, @ref ImageView2D, @ref ImageView3D,
@ref BasicMutableImageView, @ref MutableImageView1D, @ref BasicMutableImageView, @ref MutableImageView1D,
@ref MutableImageView2D, @ref MutableImageView3D, @ref Image-pixel-views @ref MutableImageView2D, @ref MutableImageView3D
*/ */
template<UnsignedInt dimensions, class T> class ImageView { template<UnsignedInt dimensions, class T> class ImageView {
public: public:
@ -486,7 +492,7 @@ template<UnsignedInt dimensions, class T> class ImageView {
* @m_since{2019,10} * @m_since{2019,10}
* *
* Provides direct and easy-to-use access to image pixels. See * Provides direct and easy-to-use access to image pixels. See
* @ref Image-pixel-views for more information. If the view is empty * @ref Image-pixel-access for more information. If the view is empty
* (with @ref data() being @cpp nullptr @ce), returns @cpp nullptr @ce * (with @ref data() being @cpp nullptr @ce), returns @cpp nullptr @ce
* as well. * as well.
*/ */
@ -501,7 +507,7 @@ template<UnsignedInt dimensions, class T> class ImageView {
* correct type for given @ref format() --- checking it on the library * correct type for given @ref format() --- checking it on the library
* side is not possible for the general case. If the view is empty * side is not possible for the general case. If the view is empty
* (with @ref data() being @cpp nullptr @ce), returns @cpp nullptr @ce * (with @ref data() being @cpp nullptr @ce), returns @cpp nullptr @ce
* as well. * as well. See also @ref Image-pixel-access for more information.
*/ */
template<class U> Containers::StridedArrayView<dimensions, typename std::conditional<std::is_const<Type>::value, typename std::add_const<U>::type, U>::type> pixels() const { template<class U> Containers::StridedArrayView<dimensions, typename std::conditional<std::is_const<Type>::value, typename std::add_const<U>::type, U>::type> pixels() const {
if(!_data && !_data.size()) return {}; if(!_data && !_data.size()) return {};
@ -608,9 +614,8 @@ functionality targeted on non-compressed image formats.
@section CompressedImageView-usage Basic usage @section CompressedImageView-usage Basic usage
Usually, the view is created on some pre-existing data array in order to The view is created from a @ref CompressedPixelFormat, size in pixels and a
describe its layout, with pixel format being one of the values from the generic data view:
@link CompressedPixelFormat @endlink:
@snippet Magnum.cpp CompressedImageView-usage @snippet Magnum.cpp CompressedImageView-usage

82
src/Magnum/Trade/ImageData.h

@ -54,6 +54,13 @@ namespace Magnum { namespace Trade {
/** /**
@brief Image data @brief Image data
Provides access to both uncompressed and compressed image data together with
information about data layout, image size and pixel format. Populated instances
of this class are returned from @ref AbstractImporter::image1D(),
@relativeref{AbstractImporter,image2D()},
@relativeref{AbstractImporter,image3D()},
@ref AbstractImageConverter::convert() and other APIs.
Used mainly by @ref AbstractImporter classes to store either compressed or Used mainly by @ref AbstractImporter classes to store either compressed or
non-compressed multi-dimensional image data together with layout and pixel non-compressed multi-dimensional image data together with layout and pixel
format description. format description.
@ -66,29 +73,20 @@ Particular graphics API wrappers provide additional image classes, for example
@section Trade-ImageData-usage Basic usage @section Trade-ImageData-usage Basic usage
The image usually comes out of @ref AbstractImporter::image1D(), Based on whether the @ref ImageData has an uncompressed or compressed pixel
@ref AbstractImporter::image2D() "image2D()" or format, it behaves either like an @ref Image / @ref ImageView or like a
@ref AbstractImporter::image3D() "image3D()" and, based on what format the @ref CompressedImage / @ref CompressedImageView. It can be distinguished using
particular imported data is in, it stores either compressed or uncompressed @ref isCompressed(); uncompressed image properties are then available through
data. @ref storage(), @ref format(), @ref formatExtra() and @ref pixelSize(),
@snippet MagnumTrade.cpp ImageData-construction
@snippet MagnumTrade.cpp ImageData-construction-compressed
As with @ref Image / @ref ImageView, this class supports extra storage
parameters and implementation-specific format specification, if the importer
has a need for that. See the @ref ImageView documentation for more information.
When using the image, its compression status can be distinguished using
@ref isCompressed(). Uncompressed image properties are available through
@ref storage(), @ref format(), @ref formatExtra() and @ref pixelSize();
compressed properties through @ref compressedStorage() and compressed properties through @ref compressedStorage() and
@ref compressedFormat(). Example of uploading the image to @ref compressedFormat(). Example of uploading the image to a
@link GL::Texture @endlink: @link GL::Texture @endlink:
@snippet MagnumTrade.cpp ImageData-usage @snippet MagnumTrade.cpp ImageData-usage
Uncompressed image data instances provide pixel data access via @ref pixels()
in the same way as the @ref Image class. See @ref Image-pixel-access "its documentation for more information".
@section Trade-ImageData-usage-mutable Mutable data access @section Trade-ImageData-usage-mutable Mutable data access
The interfaces implicitly provide @cpp const @ce views on the contained The interfaces implicitly provide @cpp const @ce views on the contained
@ -101,8 +99,44 @@ first. The following snippet flips the R and B channels of the imported image:
@snippet MagnumTrade.cpp ImageData-usage-mutable @snippet MagnumTrade.cpp ImageData-usage-mutable
@see @ref ImageData1D, @ref ImageData2D, @ref ImageData3D, @section Trade-ImageData-populating Populating an instance
@ref Image-pixel-views
An @ref ImageData instance by default takes over the ownership of an
@relativeref{Corrade,Containers::Array} containing the pixel data together
with size and either @ref PixelFormat or @ref CompressedPixelFormat, similarly
to the @ref Image and @ref CompressedImage classes:
@snippet MagnumTrade.cpp ImageData-populating
The constructor internally checks that the passed array is large enough and as
with other image classes, care must be taken in presence of
non-four-byte-aligned rows. This often closely depends on behavior of the code
or library that operates with the image data and the recommended way is to pad
the row data to satisfy the alignment:
@snippet MagnumTrade.cpp ImageData-populating-padding
Alternatively, if padding is not possible or desirable, you can pass a
@ref PixelStorage instance with the alignment overriden to @cpp 1 @ce:
@snippet MagnumTrade.cpp ImageData-populating-alignment
As with @ref Image / @ref ImageView, this class supports extra storage
parameters and implementation-specific format specification, if the importer
has a need for that. See the @ref ImageView documentation for more information.
@subsection Trade-ImageData-populating-non-owned Non-owned instances
In some cases you may want the @ref ImageData instance to only refer to
external data without taking ownership, for example with a memory-mapped file,
global data etc. For that, instead of moving in an
@relativeref{Corrade,Containers::Array}, pass @ref DataFlags describing data
mutability and ownership together with an
@relativeref{Corrade,Containers::ArrayView}:
@snippet MagnumTrade.cpp ImageData-populating-non-owned
@see @ref ImageData1D, @ref ImageData2D, @ref ImageData3D
*/ */
template<UnsignedInt dimensions> class ImageData { template<UnsignedInt dimensions> class ImageData {
public: public:
@ -802,7 +836,7 @@ template<UnsignedInt dimensions> class ImageData {
* the image is not compressed. The last dimension represents the * the image is not compressed. The last dimension represents the
* actual data type (its size is equal to type size) and is guaranteed * actual data type (its size is equal to type size) and is guaranteed
* to be contiguous. Use the templated overload below to get pixels in * to be contiguous. Use the templated overload below to get pixels in
* a concrete type. See @ref Image-pixel-views for more information. * a concrete type. See @ref Image-pixel-access for more information.
* @see @ref isCompressed(), * @see @ref isCompressed(),
* @ref Corrade::Containers::StridedArrayView::isContiguous() * @ref Corrade::Containers::StridedArrayView::isContiguous()
*/ */
@ -813,7 +847,8 @@ template<UnsignedInt dimensions> class ImageData {
* @m_since{2020,06} * @m_since{2020,06}
* *
* Like @ref pixels() const, but returns a non-const view. Expects that * Like @ref pixels() const, but returns a non-const view. Expects that
* the image is mutable. * the image is mutable. See also @ref Image-pixel-access for more
* information.
* @see @ref dataFlags() * @see @ref dataFlags()
*/ */
Containers::StridedArrayView<dimensions + 1, char> mutablePixels(); Containers::StridedArrayView<dimensions + 1, char> mutablePixels();
@ -825,7 +860,8 @@ template<UnsignedInt dimensions> class ImageData {
* Compared to non-templated @ref pixels() in addition casts the pixel * Compared to non-templated @ref pixels() in addition casts the pixel
* data to a specified type. The user is responsible for choosing * data to a specified type. The user is responsible for choosing
* correct type for given @ref format() --- checking it on the library * correct type for given @ref format() --- checking it on the library
* side is not possible for the general case. * side is not possible for the general case. See also
* @ref Image-pixel-access for more information.
*/ */
template<class T> Containers::StridedArrayView<dimensions, const T> pixels() const { template<class T> Containers::StridedArrayView<dimensions, const T> pixels() const {
/* Deliberately not adding a StridedArrayView include, it should /* Deliberately not adding a StridedArrayView include, it should

Loading…
Cancel
Save