Quite a few changes are required to get this working as expected:
Don't use Image.Fromfile()
: if you have to for some reason, always use the overload (string, bool
) that allows to preserve the embedded color management information. Since you can avoid it, adopt the method shown here, using File.ReadAllBytes()
and a MemoryStream
(or a FileStream
in a using
block).
Graphics.SetClip() doesn't allow anti-aliasing. This also applies to Regions (without further adjustments, at least). Here, I'm using a TextureBrush, a special brush build from a Bitmap (your resized Bitmap), which is then used to fill the ellipse that crops the resized image.
Disposing of the disposable objects you create is quite important, especially when you deal with graphics objects. Of course you need to dispose of all the disposable objects you create (objects that provide a Dispose()
method). This includes the OpenFileDialog
object.
Don't use paths in this form: @"....Image.png"
: this path won't exist (or it will not be inaccessible, or simply wrong) when you move your executable somewhere else.
Always use Path.Combine() (as shown here) to build a full path.
The example here saves the Image inside a CroppedImages
subfolder in the executable path.
This topic is quite broad, though (e.g., you may not be allowed to store data in the executable path, so you may need to use a dedicated path in the User AppData
folder or in the ProgramData
directory).
All calculations need to be revisited, take a look t what I posted here.
private void Recorte_Click(object sender, EventArgs e)
{
using (var ofd = new OpenFileDialog()) {
ofd.Filter = "Image Files (*.jpg; *.jpeg; *.gif; *.bmp; *.png)|*.jpg; *.jpeg; *.gif; *.bmp; *.png";
ofd.RestoreDirectory = true;
if (ofd.ShowDialog() != DialogResult.OK) return;
Image croppedImage = null;
using (var sourceImage = Image.FromStream(new MemoryStream(File.ReadAllBytes(ofd.FileName))))
using (var resizedImage = ResizeImage(sourceImage, new Size(100, 300), false)) {
croppedImage = CropToCircle(resizedImage, Color.Transparent, Color.Turquoise);
pictureBox1.Image?.Dispose();
pictureBox1.Image = croppedImage;
string destinationPath = Path.Combine(Application.StartupPath, @"CroppedImagesCortada.png");
croppedImage.Save(destinationPath, ImageFormat.Png);
}
}
}
The CropToCircle
method is rewritten and I've added an overload that alllows to specify a Pen Color.
The Pen will then be used to draw a border around the cropped elliptical region.
public static Image CropToCircle(Image srcImage, Color backColor)
{
return CropToCircle(srcImage, backColor, Color.Transparent);
}
public static Image CropToCircle(Image srcImage, Color backColor, Color borderColor)
{
var rect = new Rectangle(0, 0, srcImage.Width, srcImage.Height);
var cropped = new Bitmap(srcImage.Width, srcImage.Height, PixelFormat.Format32bppArgb);
using (var tBrush = new TextureBrush(srcImage))
using (var pen = new Pen(borderColor, 2))
using (var g = Graphics.FromImage(cropped)) {
g.SmoothingMode = SmoothingMode.AntiAlias;
if (backColor != Color.Transparent) g.Clear(backColor);
g.FillEllipse(tBrush, rect);
if (borderColor != Color.Transparent) {
rect.Inflate(-1, -1);
g.DrawEllipse(pen, rect);
}
return cropped;
}
}
The ResizeImage
method is simplified.
- The scale ratio, when used, takes the maximum value of new Size specified and resizes the Image to fit this Size boundaries.
- The Graphics PixelOffsetMode is set to
PixelOffsetMode.Half
. The notes here explain why.
public static Image ResizeImage(Image image, Size newSize, bool preserveAspectRatio = true)
{
float scale = Math.Max(newSize.Width, newSize.Height) / (float)Math.Max(image.Width, image.Height);
Size imageSize = preserveAspectRatio
? Size.Round(new SizeF(image.Width * scale, image.Height * scale))
: newSize;
var resizedImage = new Bitmap(imageSize.Width, imageSize.Height);
using (var g = Graphics.FromImage(resizedImage)) {
g.PixelOffsetMode = PixelOffsetMode.Half;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.DrawImage(image, 0, 0, imageSize.Width, imageSize.Height);
}
return resizedImage;
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…