diff --git a/include/utils/Image.h b/include/utils/Image.h index b500a2bb..61562b1d 100644 --- a/include/utils/Image.h +++ b/include/utils/Image.h @@ -1,51 +1,24 @@ #pragma once -// STL includes -#include -#include -#include -#include -#include -#include +#include -// https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types#ssize-t -#if defined(_MSC_VER) -#include -typedef SSIZE_T ssize_t; -#endif +#include template class Image { public: - typedef Pixel_T pixel_type; - /// - /// Default constructor for an image - /// Image() : - _width(1), - _height(1), - _pixels(new Pixel_T[2]), - _endOfPixels(_pixels + 1) + Image(1, 1, Pixel_T()) { - memset(_pixels, 0, 2*sizeof(Pixel_T)); } - /// - /// Constructor for an image with specified width and height - /// - /// @param width The width of the image - /// @param height The height of the image - /// Image(const unsigned width, const unsigned height) : - _width(width), - _height(height), - _pixels(new Pixel_T[width * height + 1]), - _endOfPixels(_pixels + width * height) + Image(width, height, Pixel_T()) + { - memset(_pixels, 0, (_width*_height+1)*sizeof(Pixel_T)); } /// @@ -56,52 +29,37 @@ public: /// @param background The color of the image /// Image(const unsigned width, const unsigned height, const Pixel_T background) : - _width(width), - _height(height), - _pixels(new Pixel_T[width * height + 1]), - _endOfPixels(_pixels + width * height) + _d_ptr(new ImageData(width, height, background)) { - std::fill(_pixels, _endOfPixels, background); } /// /// Copy constructor for an image + /// @param other The image which will be copied /// - Image(const Image & other) : - _width(other._width), - _height(other._height), - _pixels(new Pixel_T[other._width * other._height + 1]), - _endOfPixels(_pixels + other._width * other._height) + Image(const Image & other) { - memcpy(_pixels, other._pixels, (long) other._width * other._height * sizeof(Pixel_T)); + _d_ptr = other._d_ptr; } - // Define assignment operator in terms of the copy constructor - // More to read: https://stackoverflow.com/questions/255612/dynamically-allocating-an-array-of-objects?answertab=active#tab-top Image& operator=(Image rhs) { - rhs.swap(*this); + // Define assignment operator in terms of the copy constructor + // More to read: https://stackoverflow.com/questions/255612/dynamically-allocating-an-array-of-objects?answertab=active#tab-top + _d_ptr = rhs._d_ptr; return *this; } - void swap(Image& s) noexcept + void swap(Image& s) { - using std::swap; - swap(this->_width, s._width); - swap(this->_height, s._height); - swap(this->_pixels, s._pixels); - swap(this->_endOfPixels, s._endOfPixels); + std::swap(this->_d_ptr, s._d_ptr); } - // C++11 Image(Image&& src) noexcept - : _width(0) - , _height(0) - , _pixels(NULL) - , _endOfPixels(NULL) { - src.swap(*this); + std::swap(this->_d_ptr, src._d_ptr); } + Image& operator=(Image&& src) noexcept { src.swap(*this); @@ -113,7 +71,6 @@ public: /// ~Image() { - delete[] _pixels; } /// @@ -123,7 +80,7 @@ public: /// inline unsigned width() const { - return _width; + return _d_ptr->width(); } /// @@ -133,22 +90,17 @@ public: /// inline unsigned height() const { - return _height; + return _d_ptr->height(); } uint8_t red(const unsigned pixel) const { - return (_pixels + pixel)->red; + return _d_ptr->red(pixel); } uint8_t green(const unsigned pixel) const { - return (_pixels + pixel)->green; - } - - uint8_t blue(const unsigned pixel) const - { - return (_pixels + pixel)->blue; + return _d_ptr->green(pixel); } /// @@ -159,9 +111,9 @@ public: /// /// @return const reference to specified pixel /// - const Pixel_T& operator()(const unsigned x, const unsigned y) const + uint8_t blue(const unsigned pixel) const { - return _pixels[toIndex(x,y)]; + return _d_ptr->blue(pixel); } /// @@ -169,12 +121,17 @@ public: /// /// @param x The x index /// @param y The y index + const Pixel_T& operator()(const unsigned x, const unsigned y) const + { + return _d_ptr->operator()(x, y); + } + /// /// @return reference to specified pixel /// Pixel_T& operator()(const unsigned x, const unsigned y) { - return _pixels[toIndex(x,y)]; + return _d_ptr->operator()(x, y); } /// Resize the image @@ -182,28 +139,7 @@ public: /// @param height The height of the image void resize(const unsigned width, const unsigned height) { - if ((width*height) > unsigned((_endOfPixels-_pixels))) - { - delete[] _pixels; - _pixels = new Pixel_T[width*height + 1]; - _endOfPixels = _pixels + width*height; - } - - _width = width; - _height = height; - } - - /// - /// Copies another image into this image. The images should have exactly the same size. - /// - /// @param other The image to copy into this - /// - void copy(const Image& other) - { - assert(other._width == _width); - assert(other._height == _height); - - memcpy(_pixels, other._pixels, _width * _height * sizeof(Pixel_T)); + _d_ptr->resize(width, height); } /// @@ -212,7 +148,7 @@ public: /// Pixel_T* memptr() { - return _pixels; + return _d_ptr->memptr(); } /// @@ -221,10 +157,9 @@ public: /// const Pixel_T* memptr() const { - return _pixels; + return _d_ptr->memptr(); } - /// /// Convert image of any color order to a RGB image. /// @@ -232,38 +167,31 @@ public: /// void toRgb(Image& image) { - image.resize(_width, _height); - const unsigned imageSize = _width * _height; - - for (unsigned idx=0; idxtoRgb(*(image.imageData())); } /// - /// get size of buffer - // + /// Get size of buffer + /// ssize_t size() const { - return (ssize_t) _width * _height * sizeof(Pixel_T); + return _d_ptr->size(); } + /// /// Clear the image - // + /// void clear() { - _width = 1; - _height = 1; - delete[] _pixels; - _pixels = new Pixel_T[2]; - _endOfPixels = _pixels + 1; - memset(_pixels, 0, (unsigned long) _width * _height * sizeof(Pixel_T)); + _d_ptr->clear(); + } + + QSharedDataPointer> imageData() const + { + return _d_ptr; } private: - /// /// Translate x and y coordinate to index of the underlying vector /// @@ -274,18 +202,10 @@ private: /// inline unsigned toIndex(const unsigned x, const unsigned y) const { - return y*_width + x; + return _d_ptr->toIndex(x, y); } private: - /// The width of the image - unsigned _width; - /// The height of the image - unsigned _height; - - /// The pixels of the image - Pixel_T* _pixels; - - /// Pointer to the last(extra) pixel - Pixel_T* _endOfPixels; + QSharedDataPointer> _d_ptr; }; + diff --git a/include/utils/ImageData.h b/include/utils/ImageData.h new file mode 100644 index 00000000..aad49876 --- /dev/null +++ b/include/utils/ImageData.h @@ -0,0 +1,180 @@ +#pragma once + +// STL includes +#include +#include +#include +#include +#include +#include +#include + +// QT includes +#include + +// https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types#ssize-t +#if defined(_MSC_VER) +#include +typedef SSIZE_T ssize_t; +#endif + +template +class ImageData : public QSharedData +{ +public: + typedef Pixel_T pixel_type; + + ImageData(const unsigned width, const unsigned height, const Pixel_T background) : + _width(width), + _height(height), + _pixels(new Pixel_T[width * height + 1]) + { + std::fill(_pixels, _pixels + width * height, background); + } + + ImageData(const ImageData & other) : + QSharedData(other), + _width(other._width), + _height(other._height), + _pixels(new Pixel_T[other._width * other._height + 1]) + { + memcpy(_pixels, other._pixels, (long) other._width * other._height * sizeof(Pixel_T)); + } + + ImageData& operator=(ImageData rhs) + { + rhs.swap(*this); + return *this; + } + + void swap(ImageData& s) noexcept + { + using std::swap; + swap(this->_width, s._width); + swap(this->_height, s._height); + swap(this->_pixels, s._pixels); + } + + ImageData(ImageData&& src) noexcept + : _width(0) + , _height(0) + , _pixels(NULL) + { + src.swap(*this); + } + + ImageData& operator=(ImageData&& src) noexcept + { + src.swap(*this); + return *this; + } + + ~ImageData() + { + delete[] _pixels; + } + + inline unsigned width() const + { + return _width; + } + + inline unsigned height() const + { + return _height; + } + + uint8_t red(const unsigned pixel) const + { + return (_pixels + pixel)->red; + } + + uint8_t green(const unsigned pixel) const + { + return (_pixels + pixel)->green; + } + + uint8_t blue(const unsigned pixel) const + { + return (_pixels + pixel)->blue; + } + + const Pixel_T& operator()(const unsigned x, const unsigned y) const + { + return _pixels[toIndex(x,y)]; + } + + Pixel_T& operator()(const unsigned x, const unsigned y) + { + return _pixels[toIndex(x,y)]; + } + + void resize(const unsigned width, const unsigned height) + { + if (width == _width && height == _height) + return; + + if ((width * height) > unsigned((_width * _height))) + { + delete[] _pixels; + _pixels = new Pixel_T[width*height + 1]; + } + + _width = width; + _height = height; + } + + Pixel_T* memptr() + { + return _pixels; + } + + const Pixel_T* memptr() const + { + return _pixels; + } + + void toRgb(ImageData& image) + { + image.resize(_width, _height); + const unsigned imageSize = _width * _height; + + for (unsigned idx = 0; idx < imageSize; idx++) + { + const Pixel_T & color = _pixels[idx]; + image.memptr()[idx] = ColorRgb{color.red, color.green, color.blue}; + } + } + + ssize_t size() const + { + return (ssize_t) _width * _height * sizeof(Pixel_T); + } + + void clear() + { + if (_width != 1 || _height != 1) + { + _width = 1; + _height = 1; + delete[] _pixels; + _pixels = new Pixel_T[2]; + } + + memset(_pixels, 0, (unsigned long) _width * _height * sizeof(Pixel_T)); + } + +private: + inline unsigned toIndex(const unsigned x, const unsigned y) const + { + return y * _width + x; + } + +private: + /// The width of the image + unsigned _width; + /// The height of the image + unsigned _height; + /// The pixels of the image + Pixel_T* _pixels; +}; diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index 19af041c..39a4b7bf 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -39,6 +39,7 @@ // Boblight #include + Hyperion::Hyperion(const quint8& instance) : QObject() , _instIndex(instance) diff --git a/libsrc/utils/ImageResampler.cpp b/libsrc/utils/ImageResampler.cpp index fcc1eab6..ed4208f0 100644 --- a/libsrc/utils/ImageResampler.cpp +++ b/libsrc/utils/ImageResampler.cpp @@ -60,8 +60,7 @@ void ImageResampler::processImage(const uint8_t * data, int width, int height, i // calculate the output size int outputWidth = (width - _cropLeft - cropRight - (_horizontalDecimation >> 1) + _horizontalDecimation - 1) / _horizontalDecimation; int outputHeight = (height - _cropTop - cropBottom - (_verticalDecimation >> 1) + _verticalDecimation - 1) / _verticalDecimation; - if ((outputImage.height() != unsigned(outputHeight)) && (outputImage.width() != unsigned(outputWidth))) - outputImage.resize(outputWidth, outputHeight); + outputImage.resize(outputWidth, outputHeight); for (int yDest = 0, ySource = _cropTop + (_verticalDecimation >> 1); yDest < outputHeight; ySource += _verticalDecimation, ++yDest) { @@ -71,7 +70,7 @@ void ImageResampler::processImage(const uint8_t * data, int width, int height, i switch (pixelFormat) { - case PixelFormat::UYVY: + case PixelFormat::UYVY: { int index = lineLength * ySource + (xSource << 1); uint8_t y = data[index+1]; @@ -123,7 +122,7 @@ void ImageResampler::processImage(const uint8_t * data, int width, int height, i break; #ifdef HAVE_JPEG_DECODER case PixelFormat::MJPEG: - break; + break; #endif case PixelFormat::NO_CHANGE: Error(Logger::getInstance("ImageResampler"), "Invalid pixel format given");