imagecore/image/image.h (253 lines of code) (raw):

/* * MIT License * * Copyright (c) 2017 Twitter * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #pragma once #include "imagecore/imagecore.h" #include "imagecore/image/kernel.h" namespace imagecore { // translates from number of channels to primitive type template<uint32_t channels> class toPrimType { public: typedef uint8_t asType; }; template<> class toPrimType<1> { public: typedef uint8_t asType; }; template<> class toPrimType<2> { public: typedef uint16_t asType; }; template<> class toPrimType<4> { public: typedef uint32_t asType; }; // components, with scalar and simd specializations template<uint32_t Channels> struct ComponentBase { typedef toPrimType<Channels> primType; uint8_t mChannels[Channels]; }; template<uint32_t Channels> struct ComponentScalar : public ComponentBase<Channels> { }; template<uint32_t Channels> struct ComponentSIMD : public ComponentBase<Channels> { }; enum EResizeQuality { kResizeQuality_Bilinear = 0, kResizeQuality_Low, kResizeQuality_Medium, kResizeQuality_High, kResizeQuality_HighSharp, kResizeQuality_MAX }; enum ECropGravity { kGravityHeuristic = 0, // top for portraits, else center kGravityCenter, kGravityLeft, kGravityTop, kGravityRight, kGravityBottom }; enum EImageColorModel { kColorModel_RGBA, kColorModel_RGBX, kColorModel_Grayscale, kColorModel_YUV_420 }; enum EImageOrientation { kImageOrientation_Up = 1, kImageOrientation_Down = 3, kImageOrientation_Left = 6, kImageOrientation_Right = 8 }; enum EResolutionUnit { kNone = 1, kInches = 2, kCm = 3 }; enum EAltitudeRef { kAboveSeaLevel = 0, kBelowSeaLevel = 1 }; enum EEdgeMask { kEdge_None = 0x00, kEdge_Left = 0x01, kEdge_Top = 0x02, kEdge_Right = 0x04, kEdge_Bottom = 0x08, kEdge_All = kEdge_Left | kEdge_Top | kEdge_Right | kEdge_Bottom }; // A bounding box class class ImageRegion { public: ImageRegion(unsigned int width, unsigned int height, unsigned int left, unsigned int top) { m_Left = left; m_Top = top; m_Width = width; m_Height = height; } // these return NULL if there is an error static ImageRegion* fromString(const char* input); static ImageRegion* fromGravity( unsigned int width, unsigned int height, unsigned int targetWidth, unsigned int targetHeight, ECropGravity gravity); // accessors unsigned int left() const { return m_Left; } unsigned int right() const { return m_Left + m_Width; } unsigned int top() const { return m_Top; } unsigned int bottom() const { return m_Top + m_Height; } unsigned int width() const { return m_Width; } unsigned int height() const { return m_Height; } // mutators void left(unsigned int value) { m_Left = value; } void top(unsigned int value) { m_Top = value; } void width(unsigned int value) { m_Width = value; } void height(unsigned int value) { m_Height = value; } protected: unsigned int m_Left; unsigned int m_Top; unsigned int m_Width; unsigned int m_Height; }; class ImageGrayscale; class ImageRGBA; class ImageYUV; class ImageInterleaved; class Image { public: static Image* create(EImageColorModel colorSpace, unsigned int width, unsigned int height); static Image* create(EImageColorModel colorSpace, unsigned int width, unsigned int height, unsigned int padding, unsigned int alignment); virtual ~Image() {} virtual void setDimensions(unsigned int width, unsigned int height) = 0; virtual void setDimensions(unsigned int width, unsigned int height, unsigned int padding, unsigned int alignment) = 0; virtual void setPadding(unsigned int padding) = 0; virtual bool resize(Image* dest, EResizeQuality quality) = 0; virtual void reduceHalf(Image* dest) = 0; virtual bool crop(const ImageRegion& boundingBox) = 0; virtual void rotate(Image* dest, EImageOrientation direction) = 0; virtual void fillPadding() = 0; virtual void clear(uint8_t r, uint8_t g, uint8_t b, uint8_t a); virtual void clearRect(unsigned int x, unsigned int y, unsigned int w, unsigned int h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) = 0; virtual void copy(Image* dest); virtual void copyRect(Image* dest, unsigned int sourceX, unsigned int sourceY, unsigned int destX, unsigned int destY, unsigned int width, unsigned int height) = 0; virtual Image* move() = 0; virtual unsigned int getWidth() const = 0; virtual unsigned int getHeight() const = 0; virtual unsigned int getPadding() = 0; virtual EImageColorModel getColorModel() const = 0; virtual class ImageRGBA* asRGBA() = 0; virtual class ImageGrayscale* asGrayscale() = 0; virtual class ImageYUV* asYUV() = 0; virtual class ImageYUVSemiplanar* asYUVSemiplanar() = 0; virtual class ImageInterleaved* asInterleaved() = 0; static bool colorModelIsRGBA(EImageColorModel colorModel) { return colorModel == kColorModel_RGBA || colorModel == kColorModel_RGBX; } static bool colorModelIsGrayscale(EImageColorModel colorModel) { return colorModel == kColorModel_Grayscale; } static bool colorModelIsInterleaved(EImageColorModel colorModel) { return colorModelIsRGBA(colorModel) || colorModelIsGrayscale(colorModel); } static bool colorModelIsYUV(EImageColorModel colorModel) { return colorModel == kColorModel_YUV_420; } static unsigned int getDownsampleFilterKernelSize(EResizeQuality quality); static EFilterType getDownsampleFilterKernelType(EResizeQuality quality); static unsigned int getUpsampleFilterKernelSize(EResizeQuality quality); static EFilterType getUpsampleFilterKernelType(EResizeQuality quality); static bool validateSize(unsigned int width, unsigned int height); }; template <uint32_t Channels> class ImagePlane { typedef toPrimType<Channels> primType; public: static ImagePlane* create(uint8_t* buffer, unsigned int capacity); static ImagePlane* create(unsigned int width, unsigned int height); static ImagePlane* create(unsigned int width, unsigned int height, unsigned int padding, unsigned int alignment); ~ImagePlane(); const uint8_t* getBytes(); uint8_t* lockRect(unsigned int width, unsigned int height, unsigned int& pitch); uint8_t* lockRect(unsigned int x, unsigned int y, unsigned int width, unsigned int height, unsigned int& pitch); void unlockRect(); void setDimensions(unsigned int width, unsigned int height); void setDimensions(unsigned int width, unsigned int height, unsigned int padding, unsigned int alignment); void setPadding(unsigned int padding); void setOffset(unsigned int offsetX, unsigned int offsetY); bool resize(ImagePlane* dest, EResizeQuality quality); void reduceHalf(ImagePlane* dest); bool downsampleFilter(ImagePlane* dest, const FilterKernelAdaptive* filterKernelX, const FilterKernelAdaptive* filterKernelY, bool unpadded); bool crop(const ImageRegion& boundingBox); void rotate(ImagePlane* dest, EImageOrientation direction); void transpose(ImagePlane* dest); void fillPadding(EEdgeMask edgeMask = kEdge_All); void clear(typename primType::asType component); void clearRect(unsigned int x, unsigned int y, unsigned int w, unsigned int h, typename primType::asType component); void copyRect(ImagePlane* dest, unsigned int sourceX, unsigned int sourceY, unsigned int destX, unsigned int destY, unsigned int width, unsigned int height); void copy(ImagePlane* dest); unsigned int getWidth() { return m_Width; } unsigned int getHeight() { return m_Height; } unsigned int getPitch() { return m_Pitch; } unsigned int getPadding() { return m_Padding; } unsigned int getCapacity() { return m_Capacity; } unsigned int getAlignment() { return m_Alignment; } unsigned int getImageSize(); private: ImagePlane(uint8_t* buffer, unsigned int capacity, bool ownsBuffer); bool checkCapacity(unsigned int width, unsigned int height); bool downsampleFilterSeperable(ImagePlane* dest, const FilterKernelAdaptive* filterKernelX, const FilterKernelAdaptive* filterKernelY, bool unpadded); bool downsampleFilter4x4(ImagePlane* dest, const FilterKernelAdaptive* filterKernelX, const FilterKernelAdaptive* filterKernelY); bool downsampleFilter2x2(ImagePlane* dest, const FilterKernelAdaptive* filterKernelX, const FilterKernelAdaptive* filterKernelY); bool upsampleFilter4x4(ImagePlane* dest, const FilterKernelFixed* filterKernelX, const FilterKernelFixed* filterKernelY); static unsigned int paddingOffset(unsigned int pitch, unsigned int pad_amount); static unsigned int paddedPitch(unsigned int width, unsigned int pad_amount, unsigned int alignment); static unsigned int totalImageSize(unsigned int width, unsigned int height, unsigned int padAmount, unsigned int alignment); uint8_t* m_Buffer; unsigned int m_Capacity; unsigned int m_Width; unsigned int m_Height; unsigned int m_Pitch; unsigned int m_Padding; unsigned int m_OffsetX; unsigned int m_OffsetY; unsigned int m_Alignment; unsigned int m_PadRegionDirty; bool m_OwnsBuffer; }; extern template class ImagePlane<1>; extern template class ImagePlane<2>; extern template class ImagePlane<4>; typedef ImagePlane<1> ImagePlaneGrayscale; typedef ImagePlane<1> ImagePlane8; typedef ImagePlane<2> ImagePlane16; typedef ImagePlane<4> ImagePlaneRGBA; }