Added a function to ImageComponent to crop fully transparent areas around an image.

This commit is contained in:
Leon Styhre 2021-06-12 21:08:35 +02:00
parent 64b112a1b6
commit aeb74055d0
5 changed files with 71 additions and 2 deletions

View file

@ -9,6 +9,7 @@
#include "components/ImageComponent.h"
#include "resources/TextureResource.h"
#include "utils/CImgUtil.h"
#include "Log.h"
#include "Settings.h"
#include "ThemeData.h"
@ -264,6 +265,55 @@ void ImageComponent::uncrop()
crop(0, 0, 0, 0);
}
void ImageComponent::cropTransparentPadding(float maxSizeX, float maxSizeY)
{
if (mSize == 0)
return;
std::vector<unsigned char> imageRGBA = mTexture.get()->getRawRGBAData();
if (imageRGBA.size() == 0)
return;
Vector2i imageSize = mTexture.get()->getSize();
cimg_library::CImg<unsigned char> imageCImg(imageSize.x(), imageSize.y(), 1, 4, 0);
int paddingCoords[4] = {};
// We need to convert our RGBA data to the CImg internal format as CImg does not interleave
// the pixels (as in RGBARGBARGBA).
Utils::CImg::convertRGBAToCImg(imageRGBA, imageCImg);
// This will give us the coordinates for the fully transparent areas.
Utils::CImg::getTransparentPaddingCoords(imageCImg, paddingCoords);
Vector2f originalSize = mSize;
float cropLeft = static_cast<float>(paddingCoords[0]) / static_cast<float>(imageSize.x());
float cropTop = static_cast<float>(paddingCoords[1]) / static_cast<float>(imageSize.y());
float cropRight = static_cast<float>(paddingCoords[2]) / static_cast<float>(imageSize.x());
float cropBottom = static_cast<float>(paddingCoords[3]) / static_cast<float>(imageSize.y());
crop(cropLeft, cropTop, cropRight, cropBottom);
// Cropping the image obviously leads to a reduction in size, so we need to determine
// how much to scale up after cropping to keep within the max size restrictions that
// were passed as arguments.
mSize.x() -= mSize.x() * (cropLeft + cropRight);
mSize.y() -= mSize.y() * (cropTop + cropBottom);
float scaleFactor = originalSize.y() / mSize.y();
if (scaleFactor * mSize.x() > maxSizeX)
scaleFactor = maxSizeX / mSize.x();
if (scaleFactor * mSize.y() > maxSizeY)
scaleFactor = maxSizeY / mSize.y();
setResize(mSize.x() * scaleFactor, mSize.y() * scaleFactor);
updateVertices();
}
void ImageComponent::setFlipX(bool flip)
{
mFlipX = flip;
@ -314,8 +364,8 @@ void ImageComponent::updateVertices()
// We go through this mess to make sure everything is properly rounded.
// If we just round vertices at the end, edge cases occur near sizes of 0.5.
const Vector2f topLeft = { mSize * mTopLeftCrop };
const Vector2f bottomRight = { mSize * mBottomRightCrop };
const Vector2f topLeft = { 0, 0 };
const Vector2f bottomRight = mSize;
const float px = mTexture->isTiled() ? mSize.x() / getTextureSize().x() : 1.0f;
const float py = mTexture->isTiled() ? mSize.y() / getTextureSize().y() : 1.0f;

View file

@ -61,6 +61,10 @@ public:
void crop(float left, float top, float right, float bot);
void uncrop();
// This crops any entirely transparent areas around the actual image.
// The arguments restrict how much the end result is allowed to be scaled.
void cropTransparentPadding(float maxSizeX, float maxSizeY);
// Multiply all pixels in the image by this color when rendering.
void setColorShift(unsigned int color) override;
void setColorShiftEnd(unsigned int color);

View file

@ -57,6 +57,7 @@ public:
// Define a factor for scaling the file when loading it (1.0f = no scaling).
void setScaleDuringLoad(float scale) { mScaleDuringLoad = scale; }
std::vector<unsigned char> getRawRGBAData() { return mDataRGBA; }
bool tiled() { return mTile; }
private:

View file

@ -105,6 +105,16 @@ void TextureResource::manualUnload(std::string path, bool tile)
}
}
std::vector<unsigned char> TextureResource::getRawRGBAData()
{
std::shared_ptr<TextureData> data = sTextureDataManager.get(this);
if (data)
return data.get()->getRawRGBAData();
else
return std::vector<unsigned char>(0);
}
const Vector2i TextureResource::getSize() const
{
return mSize;

View file

@ -17,6 +17,7 @@
#include <cmath>
#include <set>
#include <string>
#include <vector>
class TextureData;
@ -35,6 +36,9 @@ public:
virtual void initFromMemory(const char* data, size_t length);
static void manualUnload(std::string path, bool tile);
// Returns the raw pixel values.
std::vector<unsigned char> getRawRGBAData();
// For SVG graphics this function effectively rescales the image to the defined size.
// It does unload and re-rasterize the texture though which may cause flickering in some
// situations. An alternative is to set a scaling factor directly when loading the texture