Title: Scale images and save them in C#
Occasionally when I'm writing a book or article, I need to scale images and then save them. MS Paint does this easily, but it loses any transparency information when it saves images. This program lets you scale images and then save them without losing the transparency information.
I don't know why Paint doesn't do this. It's pretty easy. Most of this program's code deals with the user interface.
If you enter a width, height, or percentage size, the program calculates and displays the other values to preserve the image's aspect ratio. It then scales the image accordingly and you can save the result.
The program uses the following variables declared at the class level.
// The loaded image.
private Bitmap LoadedImage = null;
// True if we should ignore change events.
private bool IgnoreChanges = false;
The variable LoadedImage stores the originally loaded image. Variable IgnoreChanges let's it prevent event cascades when you change one of the values in the text boxes.
For example, the following code executes when you change the width value.
private void txtWidth_TextChanged(object sender, EventArgs e)
{
if (IgnoreChanges) return;
double width;
if (double.TryParse(txtWidth.Text, out width))
{
SetScale(width / LoadedImage.Width, false, true, true);
}
}
If IgnoreChanges is true, the event handler exits. Otherwise it tries to parse the width value. If the value is a valid double, the code calculates the desired scale needed to scale images and passes it into the SetScale method. The final parameters tell SetScale to update the image's height and percentage values but not the width (because the user is currently editing the width).
private void SetScale(double scale,
bool show_width, bool show_height, bool show_percent)
{
int width = (int)(LoadedImage.Width * scale);
int height = (int)(LoadedImage.Height * scale);
if ((width < 1) || (height < 1)) return;
Bitmap scaled_image = new Bitmap(width, height);
using (Graphics gr = Graphics.FromImage(scaled_image))
{
gr.InterpolationMode =
InterpolationMode.HighQualityBilinear;
Rectangle source = new Rectangle(
0, 0, LoadedImage.Width, LoadedImage.Height);
Point[] dest =
{
new Point(0, 0),
new Point(width, 0),
new Point(0, height),
};
gr.DrawImage(LoadedImage, dest, source,
GraphicsUnit.Pixel);
}
picBackground.Image = scaled_image;
IgnoreChanges = true;
if (show_width) txtWidth.Text = width.ToString("0");
if (show_height) txtHeight.Text = height.ToString("0");
if (show_percent)
{
int percent = (int)(scale * 100);
txtPercent.Text = percent.ToString("0");
}
IgnoreChanges = false;
}
The code calculates the image's scaled dimensions. If either the width or height is less than 1, the method returns. That prevents it from trying to make a bitmap with width or height less than 0, which would make the program crash.
The program then creates a bitmap with the scaled dimensions and copies the original image onto it at its scaled size. It uses the HighQualityBilinear InterpolationMode value because that seems to produce the best result, at least in the examples I tried. You could try other InterpolationMode values when you scale images.
The method then sets IgnoreChanges to true and updates the program's text boxes. The TextChanged event handlers all check IgnoreChanges to see if they should call SetScale. If the program didn't do this, you would get the following chain of events:
- Typing in a text box triggers the TextChanged event handler
- The event handler calls SetScale
- SetScale updates the text boxes
- The change to the text boxes triggers the TextChanged event handler
- The sequence repeats until your system runs out of memory and the program crashes
That's all the code the program uses to scale images. The rest of the program mostly deals with loading images and saving images. Download the example to see the details.
Download the example to experiment with it and to see additional details.
|