From 1e7ced2c6656ee749989114c4d17bf8133ddbcee Mon Sep 17 00:00:00 2001
From: Aloshi <allofquist@yahoo.com>
Date: Fri, 23 May 2014 16:51:56 -0500
Subject: [PATCH] Two fixes with SVG rasterizing: 1. Original width/height were
 being returned as integers, even though they can be floats (see
 SVGResource::getImageSize()).  Function also renamed to be more descriptive
 (renamed to getSourceImageSize()). 2. Now we always round height and scale
 width from the rounded height when doing scaling, since SVG rasterization
 scale is determined from height. This seems to fix some 1px cutoff I was
 seeing, but I'm not sure if it still works for images with extreme aspect
 ratios that are taller rather than wider.

---
 src/components/ImageComponent.cpp | 25 +++++++++++++++++++------
 src/resources/SVGResource.cpp     | 10 +++++++---
 src/resources/SVGResource.h       |  2 +-
 3 files changed, 27 insertions(+), 10 deletions(-)

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<SVGResource*>(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<SVGResource*>(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;