WPF 修改圖片顏色
本文告訴大家如何修改圖片的顏色,如去掉圖片的藍色
在 WPF 可以使用很多圖片處理的方法,本文告訴大家的是一個圖片處理,可以把處理的圖片保存在文件。
在閱讀本文,我假設大家是熟悉 WPF 的,至少了解 C# ,也知道圖片的格式。
在 WPF 可以使用 ARBG 數組表示圖片,本文修改圖片顏色的方法就是使用 ARBG 數組的方法修改,修改裏面的元素的值。
如我需要去掉圖片的藍色,就可以通過修改 ARBG 數組的元素,設置所有藍色為 0 ,去掉藍色。
讀取圖片
首先找到一張好看的圖片,放在解決方案
讀取解決方案的圖片
var stream = Application.GetResourceStream(new Uri("pack://application:,,,/1.jpg")).Stream;
如果找不到圖片,就是沒有設置圖片生成是 Resource
解析文件
創建 WriteableBitmap 需要使用 ImageSource 所以需要先解析
// 其他忽略代碼
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit ();
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
使用 BitmapImage 解析文件
創建圖片
在讀取圖片之後就可以創建圖片
var writeableBitmap = new WriteableBitmap(bitmapImage);
轉換圖片格式
如果讀取到的圖片不是 BGRA 的格式,就需要轉換圖片格式
var formatConvertedBitmap = new FormatConvertedBitmap();
formatConvertedBitmap.BeginInit();
formatConvertedBitmap.Source = bitmapImage;
formatConvertedBitmap.DestinationFormat = PixelFormats.Bgra32;
formatConvertedBitmap.EndInit();
使用這個代碼可以把格式轉為PixelFormats.Bgra32
,需要重新創建圖片
var stream = Application.GetResourceStream(new Uri("pack://application:,,,/1.jpg")).Stream;
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
var formatConvertedBitmap = new FormatConvertedBitmap();
formatConvertedBitmap.BeginInit();
formatConvertedBitmap.Source = bitmapImage;
formatConvertedBitmap.DestinationFormat = PixelFormats.Bgra32;
formatConvertedBitmap.EndInit();
var writeableBitmap = new WriteableBitmap(formatConvertedBitmap);
嘗試顯示圖片,可以看到圖片還是很好看
讀取數組
在圖片可以看到圖片是使用 BGRA 的格式數組,所以只需要讀取圖片數組就可以修改圖片
讀取圖片需要使用不安全代碼,需要右擊項目屬性,點擊生成,允許不安全代碼。
在修改圖片之前需要使用 Lock 函數,讀取圖片的數組長度可以使用這個代碼
var length = writeableBitmap.PixelWidth * writeableBitmap.PixelHeight *
writeableBitmap.Format.BitsPerPixel / 8;
這裏知道使用的是 BGRA 也就是一個像素使用 4 個 byte ,一個圖片的像素就是writeableBitmap.PixelWidth * writeableBitmap.PixelHeight
。這裏 writeableBitmap.Format.BitsPerPixel
就是拿到一個像素的 bit 數。
轉換數組
var backBuffer = (byte*) writeableBitmap.BackBuffer;
讀取顏色就是從數組拿到值
for (int i = 0; i + 4 < length; i = i + 4)
{
var blue = backBuffer[i];
var green = backBuffer[i + 1];
var red = backBuffer[i + 2];
var alpha = backBuffer[i + 3];
}
修改顏色就是修改對應的值然後設置數組,如設置藍色是 0 去掉藍色
for (int i = 0; i + 4 < length; i = i + 4)
{
var blue = backBuffer[i];
var green = backBuffer[i + 1];
var red = backBuffer[i + 2];
var alpha = backBuffer[i + 3];
blue = 0;
backBuffer[i] = blue;
backBuffer[i + 1] = green;
backBuffer[i + 2] = red;
backBuffer[i + 3] = alpha;
}
設置之後需要設置圖片顯示
writeableBitmap.AddDirtyRect(new Int32Rect(0, 0, writeableBitmap.PixelWidth, writeableBitmap.PixelHeight));
writeableBitmap.Unlock();
所以去掉圖片的藍色可以使用 RemoveBlue 函數,設置藍色為 0 的方法就是讀取藍色然後修改數組
private unsafe void RemoveBlue(WriteableBitmap writeableBitmap)
{
writeableBitmap.Lock();
var length = writeableBitmap.PixelWidth * writeableBitmap.PixelHeight *
writeableBitmap.Format.BitsPerPixel / 8;
var backBuffer = (byte*) writeableBitmap.BackBuffer;
for (int i = 0; i + 4 < length; i = i + 4)
{
var blue = backBuffer[i];
var green = backBuffer[i + 1];
var red = backBuffer[i + 2];
var alpha = backBuffer[i + 3];
blue = 0;
backBuffer[i] = blue;
backBuffer[i + 1] = green;
backBuffer[i + 2] = red;
backBuffer[i + 3] = alpha;
}
writeableBitmap.AddDirtyRect(new Int32Rect(0, 0, writeableBitmap.PixelWidth, writeableBitmap.PixelHeight));
writeableBitmap.Unlock();
}
去掉藍色的圖片
代碼:WPF 修改圖片顏色 1.2-CSDN下載
現在的程序看起來還不能使用,嘗試添加幾個依賴屬性,用來修改圖片的顏色
可以點擊這裏下載程序
WPF 修改圖片
首先在 xaml 添加幾個控件
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="485*" />
<ColumnDefinition Width="308*" />
</Grid.ColumnDefinitions>
<Image x:Name="Image" />
<Grid Grid.Column="1">
<Grid VerticalAlignment="Center">
<FrameworkElement.Resources>
<Style TargetType="Slider">
<Setter Property="Width" Value="100" />
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Margin" Value="10,10,10,10" />
<Setter Property="Minimum" Value="-255" />
<Setter Property="Maximum" Value="255" />
</Style>
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="10,10,10,10" />
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
<local:DoubleConvert x:Key="DoubleConvert" />
</FrameworkElement.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock>藍色</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0">綠色</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="0">紅色</TextBlock>
<TextBlock Grid.Row="3" Grid.Column="0">透明度</TextBlock>
<!-- 藍色 -->
<Slider Grid.Row="0" Grid.Column="1" Value="{Binding Path=Blue,Mode=TwoWay}" />
<!-- 綠色 -->
<Slider Grid.Row="1" Grid.Column="1" Value="{Binding Path=Green,Mode=TwoWay}" />
<!-- 紅色 -->
<Slider Grid.Row="2" Grid.Column="1" Value="{Binding Path=Red,Mode=TwoWay}" />
<!-- 透明度 -->
<Slider Grid.Row="3" Grid.Column="1" Value="{Binding Path=Alpha,Mode=TwoWay}" />
<!-- 藍色 -->
<TextBlock Grid.Row="0" Grid.Column="2"
Text="{Binding Path=Blue,Mode=OneWay,Converter={StaticResource DoubleConvert}}" />
<!-- 綠色 -->
<TextBlock Grid.Row="1" Grid.Column="2"
Text="{Binding Path=Green,Mode=OneWay,Converter={StaticResource DoubleConvert}}" />
<!-- 紅色 -->
<TextBlock Grid.Row="2" Grid.Column="2"
Text="{Binding Path=Red,Mode=OneWay,Converter={StaticResource DoubleConvert}}" />
<!-- 透明度 -->
<TextBlock Grid.Row="3" Grid.Column="2"
Text="{Binding Path=Alpha,Mode=OneWay,Converter={StaticResource DoubleConvert}}" />
</Grid>
<Grid VerticalAlignment="Bottom">
<Button Margin="10,10,10,10" Content="替換圖片" Click="Button_OnClick" />
</Grid>
</Grid>
</Grid>
註意在頁面設置數據
DataContext="{Binding RelativeSource={RelativeSource Self}}"
然後打開 cs 添加代碼
private WriteableBitmap _writeableBitmap;
public MainWindow()
{
InitializeComponent();
Image.Margin = new Thickness(10, 10, 10, 10);
var stream = Application.GetResourceStream(new Uri("pack://application:,,,/1.jpg")).Stream;
ChangeImage(stream);
DataContext = this;
}
public static readonly DependencyProperty BlueProperty = DependencyProperty.Register(
"Blue", typeof(double), typeof(MainWindow),
new PropertyMetadata(default(double), (s, e) => ((MainWindow) s).ChangeArray()));
public double Blue
{
get { return (double) GetValue(BlueProperty); }
set { SetValue(BlueProperty, value); }
}
public static readonly DependencyProperty GreenProperty = DependencyProperty.Register(
"Green", typeof(double), typeof(MainWindow),
new PropertyMetadata(default(double), (s, e) => ((MainWindow) s).ChangeArray()));
public double Green
{
get { return (double) GetValue(GreenProperty); }
set { SetValue(GreenProperty, value); }
}
public static readonly DependencyProperty RedProperty = DependencyProperty.Register(
"Red", typeof(double), typeof(MainWindow),
new PropertyMetadata(default(double), (s, e) => ((MainWindow) s).ChangeArray()));
public double Red
{
get { return (double) GetValue(RedProperty); }
set { SetValue(RedProperty, value); }
}
public static readonly DependencyProperty AlphaProperty = DependencyProperty.Register(
"Alpha", typeof(double), typeof(MainWindow),
new PropertyMetadata(default(double), (s, e) => ((MainWindow) s).ChangeArray()));
public double Alpha
{
get { return (double) GetValue(AlphaProperty); }
set { SetValue(AlphaProperty, value); }
}
private void ChangeImage(Stream stream)
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = stream;
bitmapImage.EndInit();
var formatConvertedBitmap = new FormatConvertedBitmap();
formatConvertedBitmap.BeginInit();
formatConvertedBitmap.Source = bitmapImage;
formatConvertedBitmap.DestinationFormat = PixelFormats.Bgra32;
formatConvertedBitmap.EndInit();
_writeableBitmap = new WriteableBitmap(formatConvertedBitmap);
ChangeArray();
}
private unsafe void ChangeArray()
{
var writeableBitmap = _writeableBitmap;
if (writeableBitmap == null)
{
return;
}
writeableBitmap.Lock();
var length = writeableBitmap.PixelWidth * writeableBitmap.PixelHeight *
writeableBitmap.Format.BitsPerPixel / 8;
var backBuffer = (byte*) writeableBitmap.BackBuffer;
var byteList = new byte[length];
for (int i = 0; i + 4 < length; i = i + 4)
{
var blue = backBuffer[i];
var green = backBuffer[i + 1];
var red = backBuffer[i + 2];
var alpha = backBuffer[i + 3];
blue += (byte) Blue;
green += (byte) Green;
red += (byte) Red;
alpha += (byte) Alpha;
byteList[i] = blue;
byteList[i + 1] = green;
byteList[i + 2] = red;
byteList[i + 3] = alpha;
}
writeableBitmap.Unlock();
writeableBitmap = new WriteableBitmap(writeableBitmap.PixelWidth, writeableBitmap.PixelHeight, 96, 96,
writeableBitmap.Format, writeableBitmap.Palette);
writeableBitmap.Lock();
writeableBitmap.WritePixels(new Int32Rect(0, 0, writeableBitmap.PixelWidth, writeableBitmap.PixelHeight),
byteList, writeableBitmap.BackBufferStride, 0);
writeableBitmap.AddDirtyRect(new Int32Rect(0, 0, writeableBitmap.PixelWidth, writeableBitmap.PixelHeight));
writeableBitmap.Unlock();
Image.Source = writeableBitmap;
}
private void Button_OnClick(object sender, RoutedEventArgs e)
{
var openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "jpg(*.jpg)|*.jpg";
if (openFileDialog.ShowDialog() == true)
{
var stream = openFileDialog.OpenFile();
ChangeImage(stream);
}
}
public class DoubleConvert : IValueConverter
{
/// <inheritdoc />
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double n)
{
return n.ToString("0.00");
}
return DependencyProperty.UnsetValue;
}
/// <inheritdoc />
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
代碼:WPF 修改圖片顏色 2.5-CSDN下載
參見:
How to: Convert a BitmapSource to a Different PixelFormat
本文會經常更新,請閱讀原文: https://lindexi.gitee.io/lindexi/post/WPF-%E4%BF%AE%E6%94%B9%E5%9B%BE%E7%89%87%E9%A2%9C%E8%89%B2.html ,以避免陳舊錯誤知識的誤導,同時有更好的閱讀體驗。
本作品采用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名林德熙(包含鏈接: https://lindexi.gitee.io ),不得用於商業目的,基於本文修改後的作品務必以相同的許可發布。如有任何疑問,請 與我聯系 。
WPF 修改圖片顏色