Всъщност има няколко проблема с вашия код:
- Вие не затваряте файловия поток на изображението, което сте отворили, което означава, че никога няма да можете да запазите модифицираното изображение със същото име на файл. Всъщност никоя програма няма да може да презапише файла, докато вашата програма не бъде затворена.
- Не проверявате дали редакцията е възможна; отворите изображение, което е по-малко от 51 пиксела във всяко измерение и операцията за запазване ще се срине.
- Вие предлагате само да запазите като jpeg... формат, в който промяната на единичен пиксел неизбежно ще бъде зацапана от компресията.
- Вие не всъщност записвате като jpeg. Запазването по подразбиране без посочване на тип ще направи изображението да завърши като png формат. Просто ще има грешно файлово разширение.
- Както ilyas varol посочи, вие запазвате немодифицирания
File
вместо редактирания image
.
Основните правила, които трябва да запомните, когато отваряте изображения, са следните:
За да заобиколите проблема с незатворения поток, можете вместо това да заредите изображението по следния начин:
private void Import_Click(object sender, EventArgs e)
{
OpenFileDialog f = new OpenFileDialog();
f.Filter = "Image files (*.jpg, *.png)|*.jpg;*.png";
if (f.ShowDialog() != DialogResult.OK)
return;
using (Bitmap img = new Bitmap(f.FileName))
{
// if a file was already opened, dispose the old one.
// Start by setting the shown image to null so it
// will never try to show the disposed object.
pictureBox1.Image = null;
if (File != null)
{
try { File.Dispose(); }
catch { /* ignore */ }
}
// Clone loaded image into new object
File = new Bitmap(img);
}
pictureBox1.Image = File;
}
Конструкторът new Bitmap(image)
е един от малкото безопасни начини за създаване на клонинг на обект на изображение, който е напълно изключен от оригиналния зареден източник . Има страничен ефект от преобразуване на изображението в 32-битов цвят, ако преди това е било в различен цветен формат.
Тук обаче има друг проблем. Във функцията за експортиране вие отново правите нов Bitmap
, който не изхвърляте. Защо правите този клонинг? Има ли проблем с директното използване на File
? Ако няма, трябва просто да го редактирате директно и промяната на пиксела ще бъде показана и в потребителския интерфейс. Ако искате да приложите промяната само към запазената картина, отново използвайте блок using
за новия обект, така че ресурсите на изображението в паметта да се почистват автоматично след това.
Освен това трябва наистина да извършите операцията само след като потребителят действително е потвърдил името на файла. Вашият код го изпълнява, дори ако натиснат Отказ, защото се изпълнява, преди дори да покажете диалоговия прозорец.
private void Export_Click(object sender, EventArgs e)
{
SaveFileDialog f = new SaveFileDialog();
f.Filter = "Png Image (.png)|*.png";
if (f.ShowDialog() != DialogResult.OK)
return;
// OPTION 1: Edit "File" directly:
// Don't edit without doing the necessary checks.
if (File.Width > 50 && File.Height > 50)
File.SetPixel(50, 50, Color.Black);
File.Save(f.FileName, ImageFormat.Png);
// OPTION 2: Edit clone without affecting "File":
using (Bitmap image = new Bitmap(File))
{
// Don't edit without doing the necessary checks.
if (image.Width > 50 && image.Height > 50)
image.SetPixel(50, 50, Color.Black);
image.Save(f.FileName, ImageFormat.Png);
}
}
01.07.2021