Fixed multiple image scaling and rasterization issues.

This commit is contained in:
Leon Styhre 2021-10-23 15:45:44 +02:00
parent 39acfdfe00
commit 6cee6d2732
5 changed files with 21 additions and 28 deletions

View file

@ -63,11 +63,8 @@ void ImageComponent::resize()
else {
// SVG rasterization is determined by height and rasterization is done in terms of pixels.
// If rounding is off enough in the rasterization step (for images with extreme aspect
// ratios), it can cause cutoff when the aspect ratio breaks.
// So we always make sure the resultant height is an integer to make sure cutoff doesn't
// happen, and scale width from that (you'll see this scattered throughout the function).
// It's important to use floorf rather than round for this, as we never want to round up
// since that can lead to the cutoff just described.
// ratios), it can cause cutoff when the aspect ratio breaks. So we always make sure to
// round accordingly to avoid such issues.
if (mTargetIsMax) {
mSize = textureSize;
@ -77,13 +74,11 @@ void ImageComponent::resize()
// This will be mTargetSize.x. We can't exceed it, nor be lower than it.
mSize.x *= resizeScale.x;
// We need to make sure we're not creating an image larger than max size.
mSize.y = std::min(floorf(mSize.y * resizeScale.x), mTargetSize.y);
mSize.y = floorf(std::min(mSize.y * resizeScale.x, mTargetSize.y));
}
else {
// This will be mTargetSize.y(). We can't exceed it.
mSize.y = floorf(mSize.y * resizeScale.y);
// For SVG rasterization, always calculate width from rounded height (see comment
// above). We need to make sure we're not creating an image larger than max size.
mSize.y *= resizeScale.y;
mSize.x = std::min((mSize.y / textureSize.y) * textureSize.x, mTargetSize.x);
}
}
@ -106,9 +101,7 @@ void ImageComponent::resize()
float cropPercent = (mSize.x - mTargetSize.x) / (mSize.x * 2.0f);
crop(cropPercent, 0.0f, cropPercent, 0.0f);
}
// For SVG rasterization, always calculate width from rounded height (see comment
// above). We need to make sure we're not creating an image smaller than min size.
mSize.y = std::max(floorf(mSize.y), mTargetSize.y);
mSize.y = std::max(mSize.y, mTargetSize.y);
mSize.x = std::max((mSize.y / textureSize.y) * textureSize.x, mTargetSize.x);
}
else {
@ -117,23 +110,24 @@ void ImageComponent::resize()
mSize = mTargetSize == glm::vec2{} ? textureSize : mTargetSize;
// If only one component is set, we resize in a way that maintains aspect ratio.
// For SVG rasterization, we always calculate width from rounded height (see
// comment above).
if (!mTargetSize.x && mTargetSize.y) {
mSize.y = floorf(mTargetSize.y);
mSize.y = mTargetSize.y;
mSize.x = (mSize.y / textureSize.y) * textureSize.x;
}
else if (mTargetSize.x && !mTargetSize.y) {
mSize.y = floorf((mTargetSize.x / textureSize.x) * textureSize.y);
mSize.y = (mTargetSize.x / textureSize.x) * textureSize.y;
mSize.x = (mSize.y / textureSize.y) * textureSize.x;
}
}
}
// Make sure sub-pixel values are not rounded to zero.
if (mSize.x < 1.0f)
mSize.x = ceilf(mSize.x);
if (mSize.y < 1.0f)
mSize.y = ceilf(mSize.y);
mTexture->rasterizeAt(static_cast<size_t>(mSize.x), static_cast<size_t>(mSize.y));
mTexture->rasterizeAt(mSize.x, mSize.y);
onSizeChanged();
}

View file

@ -73,8 +73,8 @@ bool TextureData::initSVGFromMemory(const std::string& fileData)
mSourceHeight = svgImage->height;
}
mWidth = static_cast<size_t>(floorf(floorf(mSourceWidth) * mScaleDuringLoad));
mHeight = static_cast<size_t>(floorf(floorf(mSourceHeight) * mScaleDuringLoad));
mWidth = static_cast<int>(std::round(mSourceWidth * mScaleDuringLoad));
mHeight = static_cast<int>(std::round(mSourceHeight * mScaleDuringLoad));
if (mWidth == 0) {
// Auto scale width to keep aspect ratio.
@ -92,9 +92,8 @@ bool TextureData::initSVGFromMemory(const std::string& fileData)
NSVGrasterizer* rast = nsvgCreateRasterizer();
nsvgRasterize(rast, svgImage, 0, 0, mHeight / svgImage->height, tempVector.data(),
static_cast<int>(mWidth), static_cast<int>(mHeight),
static_cast<int>(mWidth) * 4);
nsvgRasterize(rast, svgImage, 0, 0, mHeight / svgImage->height, tempVector.data(), mWidth,
mHeight, mWidth * 4);
// This is important in order to avoid memory leaks.
nsvgDeleteRasterizer(rast);

View file

@ -72,8 +72,8 @@ private:
std::string mPath;
unsigned int mTextureID;
std::vector<unsigned char> mDataRGBA;
size_t mWidth;
size_t mHeight;
int mWidth;
int mHeight;
float mSourceWidth;
float mSourceHeight;
float mScaleDuringLoad;

View file

@ -194,7 +194,7 @@ std::shared_ptr<TextureResource> TextureResource::get(const std::string& path,
return tex;
}
void TextureResource::rasterizeAt(size_t width, size_t height)
void TextureResource::rasterizeAt(float width, float height)
{
if (mTextureData != nullptr) {
glm::vec2 textureSize = mTextureData.get()->getSize();

View file

@ -44,7 +44,7 @@ public:
// 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
// using get(), by using the scaleDuringLoad parameter (which also works for raster graphics).
void rasterizeAt(size_t width, size_t height);
void rasterizeAt(float width, float height);
glm::vec2 getSourceImageSize() const { return mSourceSize; }
virtual ~TextureResource();