Clean up Image class.

This commit is contained in:
jmsgrogan 2023-01-11 14:31:29 +00:00
parent 4bb87de0e6
commit 0d3674faac
30 changed files with 330 additions and 135 deletions

View file

@ -2,8 +2,9 @@
void CyclicRedundancyChecker::createTable()
{
mTable = std::vector<unsigned long>(TABLE_SIZE, 0);
unsigned long c{0};
for (int n = 0; n < 256; n++)
for (int n = 0; n < TABLE_SIZE; n++)
{
c = (unsigned long) n;
for (int k = 0; k < 8; k++)

View file

@ -2,6 +2,8 @@
#include "AbstractChecksumCalculator.h"
#include <vector>
class CyclicRedundancyChecker : public AbstractChecksumCalculator
{
public:
@ -16,5 +18,7 @@ private:
bool mTableComputed{false};
uint32_t mLastValue{0xffffffffL};
unsigned long mTable[256];
static const std::size_t TABLE_SIZE{ 256 };
std::vector<unsigned long> mTable;
};

View file

@ -55,8 +55,7 @@ std::string GlyphRunOutlines::toPostScriptPath()
return path;
}
FontGlyph::FontGlyph(unsigned width, unsigned height, int bearingX, int bearingY,
int advanceX, std::unique_ptr<Image<unsigned char> > image)
FontGlyph::FontGlyph(unsigned width, unsigned height, int bearingX, int bearingY, int advanceX, std::unique_ptr<Image> image)
: mImage(std::move(image)),
mWidth(width),
mHeight(height),
@ -67,7 +66,7 @@ FontGlyph::FontGlyph(unsigned width, unsigned height, int bearingX, int bearingY
}
Image<unsigned char>* FontGlyph::getImage() const
Image* FontGlyph::getImage() const
{
return mImage.get();
}

View file

@ -38,12 +38,10 @@ private:
class FontGlyph
{
public:
FontGlyph(unsigned width, unsigned height, int bearingX, int bearingY,
int advanceX, std::unique_ptr<Image<unsigned char> > image);
FontGlyph(unsigned width, unsigned height, int bearingX, int bearingY, int advanceX, std::unique_ptr<Image> image);
Image<unsigned char>* getImage() const;
Image* getImage() const;
unsigned getWidth() const;
unsigned getHeight() const;
@ -57,5 +55,5 @@ private:
int mBearingX{0};
int mBearingY{0};
int mAdvanceX{0};
std::unique_ptr<Image<unsigned char> > mImage;
std::unique_ptr<Image> mImage;
};

View file

@ -40,12 +40,11 @@ Scene* DrawingSurface::getScene()
return mScene.get();
}
Image<unsigned char>* DrawingSurface::getImage()
Image* DrawingSurface::getImage()
{
if (!mBackingImage)
{
mBackingImage = std::make_unique<Image<unsigned char> >(mWidth, mHeight);
mBackingImage->initialize();
mBackingImage = std::make_unique<Image>(mWidth, mHeight);
}
return mBackingImage.get();
}

View file

@ -3,8 +3,6 @@
#include <memory>
class Scene;
template<typename T>
class Image;
class DrawingSurface
@ -21,7 +19,7 @@ public:
unsigned getHeight() const;
Image<unsigned char>* getImage();
Image* getImage();
Scene* getScene();
@ -29,5 +27,5 @@ protected:
unsigned mWidth = 0;
unsigned mHeight = 0;
std::unique_ptr<Scene> mScene;
std::unique_ptr<Image<unsigned char> > mBackingImage;
std::unique_ptr<Image> mBackingImage;
};

View file

@ -94,6 +94,9 @@ void DirectXInterface::initialize()
void DirectXInterface::initializeD2dStandalone()
{
D2D1_FACTORY_OPTIONS d2dFactoryOptions = {};
D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, __uuidof(ID2D1Factory3), &d2dFactoryOptions, &mD2dFactory);
}

View file

@ -1,29 +1,51 @@
set(MODULE_NAME image)
set(platform_LIB_INCLUDES)
list(APPEND image_HEADERS
Image.h
ImageData.h
PlatformImage.h
PlatformImageWriter.h
png/PngWriter.h
png/PngReader.h
)
list(APPEND image_LIB_INCLUDES
Image.cpp
ImageBitStream.cpp
PlatformImage.cpp
png/PngWriter.cpp
png/PngReader.cpp
png/PngHeader.cpp
png/PngInfo.cpp
ImageBitStream.cpp
)
if(WIN32)
list(APPEND platform_LIB_INCLUDES
win32/Win32WicImage.h
win32/Win32WicImage.cpp
win32/Win32WicImageWriter.h
win32/Win32WicImageWriter.cpp
win32/Win32WicInterface.h
win32/Win32WicInterface.cpp
)
endif()
list(APPEND image_LIBS core compression)
list(APPEND image_DEFINES "")
add_library(image SHARED ${image_LIB_INCLUDES} ${platform_LIB_INCLUDES} ${image_HEADERS})
add_library(image SHARED ${image_LIB_INCLUDES} ${image_HEADERS})
#target_compile_definitions(image PRIVATE ${image_DEFINES})
target_include_directories(image PUBLIC
target_include_directories(${MODULE_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/png)
set_target_properties( image PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
${CMAKE_CURRENT_SOURCE_DIR}/png
${CMAKE_CURRENT_SOURCE_DIR}/win32
)
set_target_properties( ${MODULE_NAME} PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON )
target_link_libraries( image PUBLIC ${image_LIBS})
target_link_libraries( ${MODULE_NAME} PUBLIC ${image_LIBS})
set_property(TARGET image PROPERTY FOLDER src)
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER src)

View file

@ -2,121 +2,111 @@
#include "Color.h"
template<typename T>
Image<T>::Image(unsigned width, unsigned height)
: mWidth(width),
mHeight(height)
Image::Image(unsigned width, unsigned height, ImageData::Type dataType)
: mWidth(width),
mHeight(height),
mDataType(mDataType)
{
}
template<typename T>
Image<T>::~Image()
Image::~Image()
{
}
template<typename T>
void Image<T>::initialize()
std::unique_ptr<Image> Image::Create(unsigned width, unsigned height, ImageData::Type dataType)
{
mData = std::vector<T>(getBytesPerRow()*mHeight, 10);
return std::make_unique<Image>(width, height, dataType);
}
template<typename T>
void Image<T>::setDataItem(std::size_t index, T item)
void Image::initialize()
{
if(index >= mData.size())
if (mDataType == ImageData::Type::UCHAR || mDataType == ImageData::Type::UNKNOWN)
{
return;
auto data = std::unique_ptr<ImageDataT<unsigned char> >();
data->initialize(getBytesPerRow() * mHeight, 0);
mData = std::move(data);
}
else
{
auto data = std::unique_ptr<ImageDataT<uint8_t> >();
data->initialize(getBytesPerRow() * mHeight, 0);
mData = std::move(data);
}
mData[index] = item;
}
template<typename T>
void Image<T>::setPixelValue(unsigned idx, unsigned jdx, const Color& color)
void Image::setPixelValue(unsigned idx, unsigned jdx, const Color& color)
{
if (mData.empty())
if (!mData)
{
initialize();
}
mData[jdx*getBytesPerRow() + idx*3] = static_cast<T>(color.getR());
mData[jdx*getBytesPerRow() + idx*3 + 1] = static_cast<T>(color.getG());
mData[jdx*getBytesPerRow() + idx*3 + 2] = static_cast<T>(color.getB());
const auto offset = jdx * getBytesPerRow() + idx * 3;
mData->setDataItem(offset, color.getR());
mData->setDataItem(offset + 1, color.getG());
mData->setDataItem(offset + 2, color.getB());
}
template<typename T>
std::unique_ptr<Image<T> > Image<T>::Create(unsigned width, unsigned height)
{
return std::make_unique<Image<T> >(width, height);
}
template<typename T>
unsigned Image<T>::getBytesPerRow() const
unsigned Image::getBytesPerRow() const
{
const auto bitsPerEntry = mBitDepth <= 8 ? 1 : 2;
return mWidth * mNumChannels *bitsPerEntry;
return mWidth * mNumChannels * bitsPerEntry;
}
template<typename T>
unsigned Image<T>::getWidth() const
unsigned Image::getWidth() const
{
return mWidth;
}
template<typename T>
unsigned Image<T>::getHeight() const
unsigned Image::getHeight() const
{
return mHeight;
}
template<typename T>
unsigned Image<T>::getBitDepth() const
unsigned Image::getBitDepth() const
{
return mBitDepth;
}
template<typename T>
T Image<T>::getByte(unsigned idx, unsigned jdx) const
PlatformImage* Image::getPlatformImage() const
{
return mData[jdx*getBytesPerRow() + idx];
return mPlatformImage.get();
}
template<typename T>
unsigned Image<T>::getNumChannels() const
ImageData* Image::getData()
{
return mData.get();
}
unsigned char Image::getAsUnsignedChar(unsigned idx, unsigned jdx) const
{
return mData->getAsUnsignedChar(jdx * getBytesPerRow() + idx);
}
unsigned Image::getNumChannels() const
{
return mNumChannels;
}
template<typename T>
void Image<T>::setData(const std::vector<T>& data)
{
mData = data;
}
template<typename T>
void Image<T>::setWidth(unsigned width)
void Image::setWidth(unsigned width)
{
mWidth = width;
}
template<typename T>
void Image<T>::setHeight(unsigned height)
void Image::setHeight(unsigned height)
{
mHeight = height;
}
template<typename T>
void Image<T>::setBitDepth(unsigned bitDepth)
void Image::setBitDepth(unsigned bitDepth)
{
mBitDepth = bitDepth;
}
template<typename T>
void Image<T>::setNumChannels(unsigned numChannels)
void Image::setNumChannels(unsigned numChannels)
{
mNumChannels = numChannels;
}
template class Image<unsigned char>;
//template class Image<uint8_t>;

View file

@ -1,17 +1,19 @@
#pragma once
#include "PlatformImage.h"
#include "ImageData.h"
#include <memory>
#include <vector>
class Color;
template<typename T>
class Image
{
public:
Image(unsigned width, unsigned height);
Image(unsigned width, unsigned height, ImageData::Type dataType = ImageData::Type::UCHAR);
~Image();
static std::unique_ptr<Image<T> > Create(unsigned width, unsigned height);
static std::unique_ptr<Image> Create(unsigned width, unsigned height, ImageData::Type dataType = ImageData::Type::UCHAR);
unsigned getBytesPerRow() const;
unsigned getWidth() const;
@ -19,40 +21,25 @@ public:
unsigned getBitDepth() const;
unsigned getNumChannels() const;
ImageData* getData();
unsigned char getAsUnsignedChar(unsigned idx, unsigned jdx) const;
PlatformImage* getPlatformImage() const;
void setPixelValue(unsigned idx, unsigned jdx, const Color& color);
T getByte(unsigned idx, unsigned jdx) const;
void setData(const std::vector<T>& data);
void setDataItem(std::size_t index, T);
void setWidth(unsigned width);
void setHeight(unsigned height);
void setBitDepth(unsigned bitDepth);
void setNumChannels(unsigned numChannels);
void initialize();
const T* getDataPtr() const
{
return mData.data();
}
const std::vector<T>& getDataRef() const
{
return mData;
}
std::vector<T> getData() const
{
return mData;
}
private:
void initialize();
unsigned mWidth{1};
unsigned mHeight{1};
unsigned mBitDepth{8};
unsigned mNumChannels{4};
std::vector<T> mData;
ImageData::Type mDataType;
std::unique_ptr<ImageData> mData;
std::unique_ptr<PlatformImage> mPlatformImage;
};

View file

@ -1,6 +1,6 @@
#include "ImageBitStream.h"
ImageBitStream::ImageBitStream(Image<unsigned char>* image)
ImageBitStream::ImageBitStream(Image* image)
: BitStream(),
mImage(image)
{
@ -9,7 +9,7 @@ ImageBitStream::ImageBitStream(Image<unsigned char>* image)
bool ImageBitStream::isFinished() const
{
return mByteOffset == mImage->getDataRef().size();
return mByteOffset == mImage->getData()->getLength();
}
std::vector<unsigned char> ImageBitStream::peekNextNBytes(unsigned n) const
@ -25,7 +25,7 @@ std::optional<unsigned char> ImageBitStream::readNextByte()
{
return std::nullopt;
}
const auto val = mImage->getDataRef()[mByteOffset];
const auto val = mImage->getData()->getAsUnsignedChar(mByteOffset);
return val;
}
@ -37,6 +37,6 @@ void ImageBitStream::writeByte(unsigned char data, bool checkOverflow )
{
return;
}
mImage->setDataItem(mByteOffset, data);
mImage->getData()->setDataItem(mByteOffset, data);
}

View file

@ -7,7 +7,7 @@
class ImageBitStream : public BitStream
{
public:
ImageBitStream(Image<unsigned char>* image);
ImageBitStream(Image* image);
bool isFinished() const override;
@ -28,5 +28,5 @@ public:
}
private:
Image<unsigned char>* mImage{nullptr};
Image* mImage{nullptr};
};

110
src/image/ImageData.h Normal file
View file

@ -0,0 +1,110 @@
#pragma once
#include <vector>
#include <type_traits>
class ImageData
{
public:
enum class Type
{
UCHAR,
UINT8,
UNKNOWN
};
virtual Type getType() const = 0;
virtual void setDataItem(std::size_t index, unsigned char item) = 0;
virtual unsigned char getAsUnsignedChar(std::size_t index) const = 0;
virtual std::size_t getLength() const = 0;
};
template<typename T>
class ImageDataT : public ImageData
{
public:
virtual Type getType() const override
{
if (std::is_same<T, unsigned char>::value)
{
return Type::UCHAR;
}
else if (std::is_same<T, uint8_t>::value)
{
return Type::UINT8;
}
else
{
return Type::UNKNOWN;
}
}
template<typename T>
const T* getDataPtr() const
{
return mData.data();
}
template<typename T>
const std::vector<T>& getData() const
{
return mData;
}
template<typename T>
void setData(const std::vector<T>& data)
{
mData = data;
}
void setDataItem(std::size_t index, unsigned char item) override
{
if (index < mData.size())
{
mData[index] = static_cast<T>(item);
}
}
template<typename T>
void setDataItem(std::size_t index, T item)
{
if (index < mData.size())
{
mData[index] = item;
}
}
template<typename T>
void initialize(std::size_t size, T value)
{
mData.resize(size);
for (std::size_t idx = 0; idx < size; idx++)
{
mData[idx] = value;
}
}
unsigned char getAsUnsignedChar(std::size_t index) const override
{
if (index < mData.size())
{
return static_cast<unsigned char>(mData[index]);
}
else
{
return 0;
}
}
std::size_t getLength() const override
{
return mData.size();
}
private:
std::vector<T> mData;
};

View file

@ -0,0 +1,13 @@
#pragma once
template<typename T>
class Image;
template<typename T>
class PlatformImage
{
public:
PlatformImage(Image<T>* image);
private:
Image<T>* mImage{ nullptr };
};

15
src/image/PlatformImage.h Normal file
View file

@ -0,0 +1,15 @@
#pragma once
class Image;
class PlatformImage
{
public:
PlatformImage(Image* image)
: mImage(image)
{
}
private:
Image* mImage{ nullptr };
};

View file

@ -0,0 +1,6 @@
#pragma once
class PlatformImageWriter
{
};

View file

@ -162,9 +162,9 @@ bool PngReader::readIDATChunk(unsigned length)
}
}
std::unique_ptr<Image<unsigned char> > PngReader::read()
std::unique_ptr<Image> PngReader::read()
{
auto image = std::make_unique<Image<unsigned char> >(5, 5);
auto image = std::make_unique<Image>(5, 5);
mFile = std::make_unique<File>(mPath);
mFile->open(File::AccessMode::Read);
@ -188,7 +188,6 @@ std::unique_ptr<Image<unsigned char> > PngReader::read()
image->setHeight(mHeader.getHeight());
image->setBitDepth(mHeader.getBitDepth());
image->setNumChannels(mHeader.getPngInfo().getNumChannels());
image->initialize();
auto image_bit_stream = std::make_unique<ImageBitStream>(image.get());
PngFilter filter(mOutputStream.get(), image_bit_stream.get());

View file

@ -20,7 +20,7 @@ public:
~PngReader();
void setPath(const Path& path);
std::unique_ptr<Image<unsigned char> > read();
std::unique_ptr<Image> read();
private:
bool readChunk();
@ -34,7 +34,7 @@ private:
PngHeader mHeader;
std::unique_ptr<Image<unsigned char> > mWorkingImage;
std::unique_ptr<Image> mWorkingImage;
std::unique_ptr<File> mFile;
Path mPath;

View file

@ -157,7 +157,7 @@ void PngWriter::writeDataChunks(const BufferBitStream& buffer)
}
}
void PngWriter::write(Image<unsigned char>* image)
void PngWriter::write(Image* image)
{
if (!mPath.empty())
{
@ -222,7 +222,7 @@ void PngWriter::write(Image<unsigned char>* image)
}
}
void PngWriter::write(const std::unique_ptr<Image<unsigned char> >& image)
void PngWriter::write(const std::unique_ptr<Image>& image)
{
write(image.get());
}

View file

@ -3,6 +3,7 @@
#include "PngHeader.h"
#include "Image.h"
#include "DeflateElements.h"
#include "PlatformImageWriter.h"
#include <memory>
#include <string>
@ -28,8 +29,8 @@ public:
void setPngInfo(const PngInfo& info);
void write(const std::unique_ptr<Image<unsigned char> >& image);
void write(Image<unsigned char>* image);
void write(const std::unique_ptr<Image>& image);
void write(Image* image);
private:
void writeSignature();
@ -42,7 +43,7 @@ private:
//void writeIDatChunk();
Path mPath;
Image<unsigned char>* mWorkingImage{nullptr};
Image* mWorkingImage{nullptr};
std::unique_ptr<BitStream> mInStream;
std::unique_ptr<BitStream> mOutStream;
std::unique_ptr<File> mWorkingFile;
@ -52,6 +53,8 @@ private:
PngHeader mPngHeader;
Deflate::CompressionMethod mCompressionMethod{Deflate::CompressionMethod::DYNAMIC_HUFFMAN};
std::unique_ptr<PlatformImageWriter> mPlatformWriter;
};
using PngWriterPtr = std::unique_ptr<PngWriter>;

View file

@ -0,0 +1 @@
#include "Win32WicImage.h"

View file

@ -0,0 +1,8 @@
#pragma once
#include "PlatformImage.h"
class Win32WicImage : public PlatformImage
{
};

View file

@ -0,0 +1,2 @@
#include "Win32WicImageWriter.h"

View file

@ -0,0 +1,8 @@
#pragma once
#include "PlatformImageWriter.h"
class Win32WicImageWriter
{
};

View file

@ -0,0 +1,13 @@
#include "Win32WicInterface.h"
#include <wincodec.h>
Win32WicInterface::Win32WicInterface()
{
mIsValid = SUCCEEDED(::CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&mImagingFactory)));
}
IWICImagingFactory* Win32WicInterface::getFactory() const
{
return mImagingFactory.Get();
}

View file

@ -0,0 +1,16 @@
#pragma once
#include <wrl.h>
struct IWICImagingFactory;
class Win32WicInterface
{
Win32WicInterface();
IWICImagingFactory* getFactory() const;
private:
bool mIsValid{ false };
Microsoft::WRL::ComPtr<IWICImagingFactory> mImagingFactory;
};

View file

@ -22,7 +22,7 @@ void AbstractVisualNode::update(SceneInfo* sceneInfo)
}
Image<unsigned char>* AbstractVisualNode::getImage() const
Image* AbstractVisualNode::getImage() const
{
return mImage.get();
}

View file

@ -31,7 +31,7 @@ public:
const std::string& getName() const;
Image<unsigned char>* getImage() const;
Image* getImage() const;
bool getIsVisible() const;
@ -48,7 +48,7 @@ public:
protected:
Point mLocation;
std::vector<std::unique_ptr<SceneItem> > mSceneItems;
std::unique_ptr<Image<unsigned char> > mImage;
std::unique_ptr<Image> mImage;
std::vector<AbstractVisualNode*> mChildren;

View file

@ -32,6 +32,6 @@ TEST_CASE(TestDirectXRendering, "graphics")
auto text_node = std::make_unique<TextNode>("Test", DiscretePoint(100, 100));
scene->addNode(text_node.get());
scene->update(nullptr);
scene->update();
gui_app->run();
};

View file

@ -15,7 +15,7 @@ TEST_CASE(TestCompressedPng, "image")
unsigned width = 20;
unsigned height = 20;
unsigned numChannels = 1;
auto image = Image<unsigned char>::Create(width, height);
auto image = Image::Create(width, height);
image->setNumChannels(numChannels);
image->setBitDepth(8);
@ -26,7 +26,7 @@ TEST_CASE(TestCompressedPng, "image")
data[idx] = val;
}
image->setData(data);
dynamic_cast<ImageDataT<unsigned char>*>(image->getData())->setData(data);
PngWriter writer;
writer.setPath(TestUtils::getTestOutputDir() / "test_compressed.png");
@ -48,7 +48,7 @@ TEST_CASE(TestFixedPng, "image")
unsigned width = 10;
unsigned height = 10;
unsigned numChannels = 1;
auto image = Image<unsigned char>::Create(width, height);
auto image = Image::Create(width, height);
image->setNumChannels(numChannels);
image->setBitDepth(8);
@ -60,7 +60,7 @@ TEST_CASE(TestFixedPng, "image")
data[idx] = val;
}
image->setData(data);
dynamic_cast<ImageDataT<unsigned char>*>(image->getData())->setData(data);
PngWriter writer;
writer.setPath(TestUtils::getTestOutputDir() / "test_fixed.png");
@ -78,7 +78,7 @@ TEST_CASE(TestDynamicCompressedPng, "image")
unsigned width = 10;
unsigned height = 10;
unsigned numChannels = 1;
auto image = Image<unsigned char>::Create(width, height);
auto image = Image::Create(width, height);
image->setNumChannels(numChannels);
image->setBitDepth(8);
@ -90,7 +90,7 @@ TEST_CASE(TestDynamicCompressedPng, "image")
data[idx] = val;
}
image->setData(data);
dynamic_cast<ImageDataT<unsigned char>*>(image->getData())->setData(data);
PngWriter writer;
writer.setPath(TestUtils::getTestOutputDir() / "test_dynamic.png");