Здесь есть проблема, которую нужно исправить:
→ fadeTimer.Interval = 10;
:
(возможно) вы используете неправильный таймер: System.Timers. Таймер Истек повышен в потоке ThreadPool. Если вы не установили SynchronizingObject для объекта Control, который затем используется для маршалинга вызовов обработчика, ссылка на Control в обработчике вызовет проблему (исключения нарушения между потоками). В этом контексте вы можете использовать System. Windows .Forms.Timer вместо этого: его событие Tick
вызывается в потоке пользовательского интерфейса.
Кроме того, интервал таймера слишком мал. Стандартное (официальное) разрешение System.Windows.Forms.Timer
составляет 55ms
(выше, чем System.Timers.Timer
). Вы заканчиваете перекрывающимися событиями.
→ GetPixel()
/ SetPixel()
:
не может использоваться для этой задачи. Эти методы слишком медленны при последовательном вызове для установки нескольких пикселей. Они используются для изменения небольшого набора пикселей (или только одного), а не для изменения пикселей всего изображения.
Bitmap.LockBits () - это общий инструмент, используемый для установки цвета байты растровых изображений.
→ pictureOut.Image = changeOpacity((Bitmap)pictureOut.Image.Clone(), oChange);
:
Вы используете свойство Image элемента управления для предоставления растрового изображения источника, затем вы устанавливаете то же свойство, которое предоставляло источник, используя тот же источник, модифицированный.
Это никогда не даст вам полностью блеклое изображение, и вы ищете проблемы.
Существует простой инструмент, который можно легко выполнить для sh этой задачи: класс ColorMatrix . Этот класс обрабатывает стандартную матрицу 5x5, предоставляя некоторые упрощенные инструменты, позволяющие устанавливать значения компонентов Matrix.
Компонент Matrix 5x5 со значением [3, 3]
(Matrix3x3
) представляет значение Alpha: все компоненты RGB
.
Класс ColorMatrix
применяется к растровому изображению с помощью метода SetColorMatrix () класса ImageAttributes
, который затем передается в перегрузка Graphics.DrawImage () , которая принимает объект ImageAttributes
в качестве аргумента.
Поскольку эта процедура Fade может быть полезна в других ситуациях, я думаю, что это хорошая идея - создать метод расширения: он добавляет новый метод SetOpacity()
к класс Bitmap.
Он также может одновременно изменять гамму, если этого требует эффект затухания.
Осталось загрузить две битовые карты, создать таймер, установить разумный Interval
(100ms
здесь) и нарисовать битовую карту на поверхности двух элементов управления PictureBox (три здесь , чтобы проверить простой эффект смешивания).
Значение увеличения / уменьшения непрозрачности установлено на .025f
, поэтому непрозрачность меняется 1/4
максимального диапазона 0.0f-1.0f
каждую секунду. Для настройки по мере необходимости.
![Bitmap Fade ColorMatrix](https://i.stack.imgur.com/TsS2C.gif)
Не очень хорошо с 256 цветами
► Добавить класс расширения в проект.
► Настройте форму с 3-мя элементами управления PictureBox и назначьте каждому из них 3 описателя событий, которые вы здесь найдете.
► Не назначайте растровое изображение для PictureBoxes во время разработки. Растровые изображения загружаются во время выполнения, как показано в примере кода.
► Добавьте кнопку для запуска таймера.
► после завершения процедуры fading
вы немедленно перезапускаете таймер, поскольку он перематывает сам (затухание начинается заново, применяя обратный эффект к каждому растровому изображению и смешанным растровым изображениям).
![Bitmap Fade and blend ColorMatrix](https://i.stack.imgur.com/bLgtb.gif)
Держите инструменты диагностики открытыми: вы увидите, что не тратите ни одного МБ памяти, даже если вы повторите операцию несколько раз раз.
using System.Drawing;
using System.IO;
using System.Windows.Forms;
public partial class FormBitmaFadeTest : Form
{
Bitmap sourceBmp1 = null;
Bitmap sourceBmp2 = null;
Bitmap fadeBmp1 = null;
Bitmap fadeBmp2 = null;
float opacity1 = 0.0f;
float opacity2 = 1.0f;
float increment = .025f;
Timer timer = null;
public FormBitmaFadeTest()
{
InitializeComponent();
if (components == null) components = new System.ComponentModel.Container();
components.Add(timer);
string image1Path = [Source Image 1 Path];
string image2Path = [Source Image 2 Path];
sourceBmp1 = (Bitmap)Image.FromStream(new MemoryStream(File.ReadAllBytes(image1Path)));
sourceBmp2 = (Bitmap)Image.FromStream(new MemoryStream(File.ReadAllBytes(image2Path)));
fadeBmp1 = sourceBmp1.Clone() as Bitmap;
fadeBmp2 = sourceBmp2.Clone() as Bitmap;
timer = new Timer() { Interval = 100 };
timer.Tick += this.TimerTick;
}
private void TimerTick(object sender, EventArgs e)
{
opacity1 += increment;
opacity2 -= increment;
if ((opacity1 >= 1.0f || opacity1 <= .0f) || (opacity2 >= 1.0f || opacity2 <= .0f)) {
increment *= -1;
timer.Stop();
}
fadeBmp1?.Dispose();
fadeBmp2?.Dispose();
fadeBmp1 = sourceBmp1.SetOpacity(opacity1);
fadeBmp2 = sourceBmp2.SetOpacity(opacity2);
pictureBox1.Invalidate();
pictureBox2.Invalidate();
pictureBox3.Invalidate();
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
if (fadeBmp1 == null) return;
var units = GraphicsUnit.Pixel;
e.Graphics.DrawImage(fadeBmp1, new RectangleF(PointF.Empty, pictureBox1.ClientSize), fadeBmp1.GetBounds(ref units), units);
}
private void pictureBox2_Paint(object sender, PaintEventArgs e)
{
if (fadeBmp2 == null) return;
var units = GraphicsUnit.Pixel;
e.Graphics.DrawImage(fadeBmp2, new RectangleF(PointF.Empty, pictureBox2.ClientSize), fadeBmp2.GetBounds(ref units), units);
}
private void pictureBox3_Paint(object sender, PaintEventArgs e)
{
if (fadeBmp1 == null || fadeBmp2 == null) return;
var units = GraphicsUnit.Pixel;
e.Graphics.DrawImage(fadeBmp2, new RectangleF(PointF.Empty, pictureBox3.ClientSize), fadeBmp2.GetBounds(ref units), units);
e.Graphics.DrawImage(fadeBmp1, new RectangleF(PointF.Empty, pictureBox3.ClientSize), fadeBmp1.GetBounds(ref units), units);
}
}
Метод расширения:
Методы расширения (C# Руководство по программированию)
using System.Drawing;
using System.Drawing.Imaging;
public static class BitmapExtensions
{
static float[][] fadeMatrix = {
new float[] {1, 0, 0, 0, 0},
new float[] {0, 1, 0, 0, 0},
new float[] {0, 0, 1, 0, 0},
new float[] {0, 0, 0, 1, 0},
new float[] {0, 0, 0, 0, 1}
};
public static Bitmap SetOpacity(this Bitmap bitmap, float Opacity, float Gamma = 1.0f)
{
var mx = new ColorMatrix(fadeMatrix);
mx.Matrix33 = Opacity;
var bmp = new Bitmap(bitmap.Width, bitmap.Height);
using (var g = Graphics.FromImage(bmp))
using (var attributes = new ImageAttributes()) {
attributes.SetGamma(Gamma, ColorAdjustType.Bitmap);
attributes.SetColorMatrix(mx, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
g.Clear(Color.Transparent);
g.DrawImage(bitmap, new Rectangle(0, 0, bmp.Width, bmp.Height),
0, 0, bitmap.Width, bitmap.Height, GraphicsUnit.Pixel, attributes);
return bmp;
}
}
}