Browse Source

TgaImageConverter: properly handle pixel storage alignment.

pull/107/head
Vladimír Vondruš 11 years ago
parent
commit
6ea868d723
  1. 49
      src/MagnumPlugins/TgaImageConverter/Test/TgaImageConverterTest.cpp
  2. 9
      src/MagnumPlugins/TgaImageConverter/TgaImageConverter.cpp

49
src/MagnumPlugins/TgaImageConverter/Test/TgaImageConverterTest.cpp

@ -27,6 +27,7 @@
#include <tuple> #include <tuple>
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
#include <Corrade/TestSuite/Tester.h> #include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/Container.h>
#include <Corrade/Utility/Directory.h> #include <Corrade/Utility/Directory.h>
#include "Magnum/Image.h" #include "Magnum/Image.h"
@ -46,24 +47,39 @@ class TgaImageConverterTest: public TestSuite::Tester {
void wrongFormat(); void wrongFormat();
void wrongType(); void wrongType();
void data(); void rgb();
void rgba();
}; };
namespace { namespace {
constexpr char originalData[] = { /* Padded to four byte alignment (the resulting file is *not* padded) */
constexpr char OriginalDataRGB[] = {
1, 2, 3, 2, 3, 4, 0, 0,
3, 4, 5, 4, 5, 6, 0, 0,
5, 6, 7, 6, 7, 8, 0, 0
};
constexpr char ConvertedDataRGB[] = {
1, 2, 3, 2, 3, 4, 1, 2, 3, 2, 3, 4,
3, 4, 5, 4, 5, 6, 3, 4, 5, 4, 5, 6,
5, 6, 7, 6, 7, 8 5, 6, 7, 6, 7, 8
}; };
const ImageView2D original(PixelFormat::RGB, PixelType::UnsignedByte, {2, 3}, originalData); const ImageView2D OriginalRGB{PixelFormat::RGB, PixelType::UnsignedByte, {2, 3}, OriginalDataRGB};
constexpr char OriginalDataRGBA[] = {
1, 2, 3, 4, 2, 3, 4, 5,
3, 4, 5, 6, 4, 5, 6, 7,
5, 6, 7, 8, 6, 7, 8, 9
};
const ImageView2D OriginalRGBA{PixelFormat::RGBA, PixelType::UnsignedByte, {2, 3}, OriginalDataRGBA};
} }
TgaImageConverterTest::TgaImageConverterTest() { TgaImageConverterTest::TgaImageConverterTest() {
addTests({&TgaImageConverterTest::wrongFormat, addTests({&TgaImageConverterTest::wrongFormat,
&TgaImageConverterTest::wrongType, &TgaImageConverterTest::wrongType,
&TgaImageConverterTest::data}); &TgaImageConverterTest::rgb,
&TgaImageConverterTest::rgba});
} }
void TgaImageConverterTest::wrongFormat() { void TgaImageConverterTest::wrongFormat() {
@ -88,19 +104,36 @@ void TgaImageConverterTest::wrongType() {
CORRADE_COMPARE(out.str(), "Trade::TgaImageConverter::exportToData(): unsupported color type PixelType::Float\n"); CORRADE_COMPARE(out.str(), "Trade::TgaImageConverter::exportToData(): unsupported color type PixelType::Float\n");
} }
void TgaImageConverterTest::data() { void TgaImageConverterTest::rgb() {
const auto data = TgaImageConverter().exportToData(original); const auto data = TgaImageConverter().exportToData(OriginalRGB);
TgaImporter importer; TgaImporter importer;
CORRADE_VERIFY(importer.openData(data)); CORRADE_VERIFY(importer.openData(data));
std::optional<Trade::ImageData2D> converted = importer.image2D(0); std::optional<Trade::ImageData2D> converted = importer.image2D(0);
CORRADE_VERIFY(converted); CORRADE_VERIFY(converted);
CORRADE_COMPARE(converted->storage().alignment(), 1);
CORRADE_COMPARE(converted->size(), Vector2i(2, 3)); CORRADE_COMPARE(converted->size(), Vector2i(2, 3));
CORRADE_COMPARE(converted->format(), PixelFormat::RGB); CORRADE_COMPARE(converted->format(), PixelFormat::RGB);
CORRADE_COMPARE(converted->type(), PixelType::UnsignedByte); CORRADE_COMPARE(converted->type(), PixelType::UnsignedByte);
CORRADE_COMPARE((std::string{converted->data(), 2*3*3}), CORRADE_COMPARE_AS(converted->data(), Containers::ArrayView<const char>{ConvertedDataRGB},
(std::string{original.data(), 2*3*3})); TestSuite::Compare::Container);
}
void TgaImageConverterTest::rgba() {
const auto data = TgaImageConverter().exportToData(OriginalRGBA);
TgaImporter importer;
CORRADE_VERIFY(importer.openData(data));
std::optional<Trade::ImageData2D> converted = importer.image2D(0);
CORRADE_VERIFY(converted);
CORRADE_COMPARE(converted->storage().alignment(), 4);
CORRADE_COMPARE(converted->size(), Vector2i(2, 3));
CORRADE_COMPARE(converted->format(), PixelFormat::RGBA);
CORRADE_COMPARE(converted->type(), PixelType::UnsignedByte);
CORRADE_COMPARE_AS(converted->data(), Containers::ArrayView<const char>{OriginalDataRGBA},
TestSuite::Compare::Container);
} }
}}} }}}

9
src/MagnumPlugins/TgaImageConverter/TgaImageConverter.cpp

@ -90,8 +90,13 @@ Containers::Array<char> TgaImageConverter::doExportToData(const ImageView2D& ima
header->width = UnsignedShort(Utility::Endianness::littleEndian(image.size().x())); header->width = UnsignedShort(Utility::Endianness::littleEndian(image.size().x()));
header->height = UnsignedShort(Utility::Endianness::littleEndian(image.size().y())); header->height = UnsignedShort(Utility::Endianness::littleEndian(image.size().y()));
/* Fill data */ /* Fill data or copy them row by row if we need to drop the padding */
std::copy(image.data().data(), image.data()+pixelSize*image.size().product(), data.begin()+sizeof(TgaHeader)); const std::size_t rowSize = image.size().x()*pixelSize;
const std::size_t rowStride = std::get<1>(image.dataProperties()).x();
if(rowStride != rowSize) {
for(std::int_fast32_t y = 0; y != image.size().y(); ++y)
std::copy_n(image.data() + y*rowStride, rowSize, data.begin() + sizeof(TgaHeader) + y*rowSize);
} else std::copy(image.data().data(), image.data()+pixelSize*image.size().product(), data.begin() + sizeof(TgaHeader));
if(image.format() == PixelFormat::RGB) { if(image.format() == PixelFormat::RGB) {
auto pixels = reinterpret_cast<Math::Vector3<UnsignedByte>*>(data.begin()+sizeof(TgaHeader)); auto pixels = reinterpret_cast<Math::Vector3<UnsignedByte>*>(data.begin()+sizeof(TgaHeader));

Loading…
Cancel
Save