UIImage retina safe scaling & drawing

By July 24, 2012Blog

When working on our next app, we found us in a situation where we have lots of graphics in some size and need to present it on the screen in several scaled versions.

The issue is, that graphics can be prepared for each of the sizes needed, but then, it will be redundant. Or find a way how to scale it in the code for the next drawing part.

And of course, there is a coding solution (how else? :-)). The trick is to draw the image to the context created for the screen, so it is properly sized, nice feature out of the box in iOS is that it will do the retina fine tuning automatically. We just need to draw it.

 

public static class UIImageHelper
{
	public static UIImage FromFile (string filename, SizeF fitSize)
	{
		var imageFile = UIImage.FromFile (filename);
 
		return imageFile.ImageToFitSize(fitSize);
	}
 
	public static UIImage ImageToFitSize (this UIImage image, SizeF fitSize)
	{
  	    double imageScaleFactor = 1.0;
	    imageScaleFactor = image.CurrentScale;
 
	    double sourceWidth = image.Size.Width * imageScaleFactor;
	    double sourceHeight = image.Size.Height * imageScaleFactor;
	    double targetWidth = fitSize.Width;
	    double targetHeight = fitSize.Height;
 
	    double sourceRatio = sourceWidth / sourceHeight;
	    double targetRatio = targetWidth / targetHeight;
 
	    bool scaleWidth = (sourceRatio <= targetRatio);
	    scaleWidth = !scaleWidth;
 
	    double scalingFactor, scaledWidth, scaledHeight;
 
	    if (scaleWidth) 
	    {
	        scalingFactor = 1.0 / sourceRatio;
	        scaledWidth = targetWidth;
	        scaledHeight = Math.Round (targetWidth * scalingFactor);
	    } 
	else 
	{
	        scalingFactor = sourceRatio;
	        scaledWidth = Math.Round(targetHeight * scalingFactor);
		scaledHeight = targetHeight;
	}
 
		RectangleF destRect = new RectangleF(0, 0, (float)scaledWidth, (float)scaledHeight);
 
		UIGraphics.BeginImageContextWithOptions(destRect.Size, false, 0.0f);
		image.Draw (destRect); 
		UIImage newImage = UIGraphics.GetImageFromCurrentImageContext ();
		UIGraphics.EndImageContext ();
 
		return newImage;
	}
}

 

Happy coding!