Let’s say you have images that you wish to load into your application. However, instead of having the user downscale or downsize those images first, your application could do it for them.
Below is a piece of code I wrote in C# that will do just that by brute forcing. Admittedly, it’s not the best solution. An AI probably could do it better but in many cases, the following works pretty well.
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
namespace ImageTuner
{
class Program
{
static void Main(string[] args)
{
string originalImageFile = "<image image file>.jpg";
string scaledImageFile = "<downsized image file>.jpg";
bool imageMatchCriterion = false;
bool imageStillTooBig = false;
float resolutionScaleFactor = 0.95f;
long jpegQualityLevel = 100L;
using (var originalImage = new Bitmap(originalImageFile))
{
while (!imageMatchCriterion)
{
Console.WriteLine("Image doesn't match size criterion. Resizing.");
int scaledHeight = (int)(originalImage.Height * resolutionScaleFactor);
int scaledWidth = (int)(originalImage.Width * resolutionScaleFactor);
using (var toCompress = new Bitmap(originalImage, new Size(height: scaledHeight, width: scaledWidth)))
{
var jpgEncoder = GetEncoder(ImageFormat.Jpeg);
var myEncoder = Encoder.Quality;
var myEncoderParameters = new EncoderParameters(1);
var myEncoderParameter = new EncoderParameter(myEncoder, jpegQualityLevel);
myEncoderParameters.Param[0] = myEncoderParameter;
using (var tempStream = new MemoryStream())
{
//Save the image byte to memory first.
toCompress.Save(tempStream, jpgEncoder, myEncoderParameters);
byte[] imageSize = tempStream.ToArray();
//Check the image size in memory. If it's too big, continue to loop.
if (imageSize.Length <= 512000)
{
imageMatchCriterion = true;
using (var saveStream = new FileStream(scaledImageFile, FileMode.Create))
{
toCompress.Save(saveStream, jpgEncoder, myEncoderParameters);
}
}
else
{
if (resolutionScaleFactor > 0.60f)
{
//Reduce the resolution of the image by 10 percent each time.
resolutionScaleFactor -= 0.10f;
}
else
{
//When the resolution scaling already reach 60%, time to look at reducing the quality level by 5 each time.
if (jpegQualityLevel > 50)
{
jpegQualityLevel -= 5L;
}
else
{
//Cannot drop the image quality below 50 percent. Once that happen, the image is almost unusable.
imageStillTooBig = true;
break;
}
}
}
}
}
}
}
if (imageStillTooBig)
{
Console.WriteLine("Image resizing failed.");
}
else
{
Console.WriteLine("Image resizing completed.");
}
}
private static ImageCodecInfo GetEncoder(ImageFormat format)
{
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();
foreach (ImageCodecInfo codec in codecs)
{
if (codec.FormatID == format.Guid)
{
return codec;
}
}
return null;
}
}
}