diff --git a/src/components/ImageComponent.cpp b/src/components/ImageComponent.cpp index 5f33cd718..9da04aab7 100644 --- a/src/components/ImageComponent.cpp +++ b/src/components/ImageComponent.cpp @@ -37,12 +37,20 @@ void ImageComponent::resize() if(!mTexture) return; - const Eigen::Vector2f textureSize((float)getTextureSize().x(), (float)getTextureSize().y()); + SVGResource* svg = dynamic_cast(mTexture.get()); + + const Eigen::Vector2f textureSize = svg ? svg->getSourceImageSize() : Eigen::Vector2f((float)mTexture->getSize().x(), (float)mTexture->getSize().y()); if(mTexture->isTiled()) { mSize = mTargetSize; }else{ + // SVG rasterization is determined by height (see SVGResource.cpp), 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) + // this is probably not the best way, so if you're familiar with this problem and have a better solution, please make a pull request! + if(mTargetIsMax) { mSize = textureSize; @@ -58,27 +66,32 @@ void ImageComponent::resize() mSize[1] *= resizeScale.y(); } + // for SVG rasterization, always calculate width from rounded height (see comment above) + mSize[1] = round(mSize[1]); + mSize[0] = (mSize[1] / textureSize.y()) * textureSize.x(); + }else{ // if both components are set, we just stretch // if no components are set, we don't resize at all mSize = mTargetSize.isZero() ? 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[0] = (mTargetSize.y() / textureSize.y()) * textureSize.x(); - mSize[1] = mTargetSize.y(); + mSize[1] = round(mTargetSize.y()); + mSize[0] = (mSize.y() / textureSize.y()) * textureSize.x(); }else if(mTargetSize.x() && !mTargetSize.y()) { - mSize[0] = mTargetSize.x(); - mSize[1] = (mTargetSize.x() / textureSize.x()) * textureSize.y(); + mSize[1] = round((mTargetSize.x() / textureSize.x()) * textureSize.y()); + mSize[0] = (mSize.y() / textureSize.y()) * textureSize.x(); } } } - SVGResource* svg = dynamic_cast(mTexture.get()); if(svg) { + // mSize.y() should already be rounded svg->rasterizeAt((int)round(mSize.x()), (int)round(mSize.y())); } diff --git a/src/resources/SVGResource.cpp b/src/resources/SVGResource.cpp index 6dc773a47..1051303f4 100644 --- a/src/resources/SVGResource.cpp +++ b/src/resources/SVGResource.cpp @@ -69,6 +69,10 @@ void SVGResource::rasterizeAt(size_t width, size_t height) mLastHeight = height; } + LOG(LogInfo) << "Rasterizing \"" << mPath << "\"..."; + LOG(LogInfo) << " Original width: " << mSVGImage->width << ", original height: " << mSVGImage->height; + LOG(LogInfo) << " width: " << width << ", height: " << height << ", scale: " << height / mSVGImage->height; + unsigned char* imagePx = (unsigned char*)malloc(width * height * 4); NSVGrasterizer* rast = nsvgCreateRasterizer(); @@ -92,12 +96,12 @@ void SVGResource::rasterizeAt(size_t width, size_t height) free(imagePx); } -Eigen::Vector2i SVGResource::getImageSize() const +Eigen::Vector2f SVGResource::getSourceImageSize() const { if(mSVGImage) - return Eigen::Vector2i((int)round(mSVGImage->width), (int)round(mSVGImage->height)); + return Eigen::Vector2f(mSVGImage->width, mSVGImage->height); - return Eigen::Vector2i::Zero(); + return Eigen::Vector2f::Zero(); } void SVGResource::deinitSVG() diff --git a/src/resources/SVGResource.h b/src/resources/SVGResource.h index c28b29396..c68ae4879 100644 --- a/src/resources/SVGResource.h +++ b/src/resources/SVGResource.h @@ -14,7 +14,7 @@ public: virtual void initFromMemory(const char* image, size_t length) override; void rasterizeAt(size_t width, size_t height); - Eigen::Vector2i getImageSize() const; + Eigen::Vector2f getSourceImageSize() const; protected: friend TextureResource;