2018-8-10-WPF-修改图片颜色
| title | author | date | CreateTime | categories |
|---|---|---|---|---|
|
WPF 修改图片颜色
|
lindexi
|
2018-08-10 19:16:53 +0800
|
2018-07-03 15:47:55 +0800
|
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();
}
去掉蓝色的图片
现在的程序看起来还不能使用,尝试添加几个依赖属性,用来修改图片的颜色
可以点击这里下载程序
首先在 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;
}
}
参见:
2018-8-10-WPF-修改图片颜色的更多相关文章
- WPF 修改图片颜色
原文:WPF 修改图片颜色 本文告诉大家如何修改图片的颜色,如去掉图片的蓝色 在 WPF 可以使用很多图片处理的方法,本文告诉大家的是一个图片处理,可以把处理的图片保存在文件. 在阅读本文,我假设大家 ...
- xml代码修改图片颜色
<?xml version="1.0" encoding="utf-8"?> <bitmap xmlns:android="http ...
- Android动态修改图片颜色的实现方式分析
版权声明:本文为博主原创文章,未经博主允许不得转载. 1.修改色相.饱和度.亮度 参看:http://blog.csdn.NET/sjf0115/article/details/7267063 2.使 ...
- c# 快速修改图片颜色
public static void ChangeColour(this Bitmap bmp, byte inColourR, byte inColourG, byte inColourB, byt ...
- word中批量修改图片大小的两个方法
前言: 对于把ppt的内容拷贝到word中: 对ppt的一页进行复制,然后粘贴到word中 如果要的是ppt运行过程中的内容,在qq运行的情况下,按Ctrl+Alt+A截屏,按勾,然后可以直接粘贴到w ...
- Android 使用ColorMatrix改变图片颜色
原文链接:http://blog.csdn.net/janice0529/article/details/49207939 ColorMatrix的颜色矩阵介绍 颜色矩阵M是一个5*4的矩阵,在And ...
- 利用Photoshop修改图片以达到投稿要求
摘自:http://www.dxy.cn/bbs/thread/8602152#8602152 利用Photoshop修改图片以达到投稿要求 软件版本为Photoshop CS V8.0.1(中文版) ...
- tabbarItem字体及图片颜色设置
tabbarItem设置图片后运行往往与我们原始图片颜色有出入,这是因为在默认情况下,未选中状态图片和字体颜色为灰色,选中状态下图片和字体颜色为蓝色. UIImage 在呈现(render)时会选 ...
- Gradify - 提取图片颜色,创建响应式的 CSS渐变
被请求的HTTP对象之间的延迟会有一个时间段,这个期间网页看起来不完整.Gradify 可以分析出图像中4个最常见的颜色,创建一个梯度(或纯色)作为图片占位符.Gradify 可以在在任何图像发现最突 ...
随机推荐
- iOS将image转90,180,270度的方法
http://blog.sina.com.cn/s/blog_6602ffbc0101ckx3.html 这里要分享的是将image旋转,而不是将imageView旋转,原理就是使用quartz2D来 ...
- qbao
# -*- coding: utf-8 -*- import Image, cStringIO, webbrowser, re, time, math import urllib, urllib2, ...
- bzoj4152 The Captain
Description 给定平面上的n个点,定义(x1,y1)到(x2,y2)的费用为min(|x1-x2|,|y1-y2|),求从1号点走到n号点的最小费用. Input 第一行包含一个正整数n(2 ...
- C# 从零开始写 SharpDx 应用 画三角
原文:C# 从零开始写 SharpDx 应用 画三角 版权声明:博客已迁移到 https://blog.lindexi.com 欢迎访问.如果当前博客图片看不到,请到 https://blog.lin ...
- WPF疑难杂症之二(全屏幕窗口)
原文:WPF疑难杂症之二(全屏幕窗口) 近日的学习中遇到一个非常奇怪的问题:用XAML文件创建了一个全屏幕窗口,然后,在窗口中建立了一个非常简单的动画.一切都在我的掌控之中,实现非常的顺利. WPF中 ...
- 2019-11-19-git-修改commit日期为之前的日期
title author date CreateTime categories git 修改commit日期为之前的日期 lindexi 2019-11-19 08:53:16 +0800 2018- ...
- 2019-8-31-C#-将-Begin-和-End-异步方法转-task-异步
title author date CreateTime categories C# 将 Begin 和 End 异步方法转 task 异步 lindexi 2019-08-31 16:55:58 + ...
- 利用scrapy爬取文件后并基于管道化的持久化存储
我们在pycharm上爬取 首先我们可以在本文件打开命令框或在Terminal下创建 scrapy startproject xiaohuaPro ------------创建文件 scrapy ...
- oracle使用表的别名(Alias)
当在SQL语句中连接多个表时, 请使用表的别名并把别名前缀于每个Column上.这样一来,就可以减少解析的时间并减少那些由Column歧义引起的语法错误. (Column歧义指的是由于SQL中不同 ...
- vue 组件评论 的同时进行刷新
注意:1.最重要理解这里的父组件的刷新功能,通过v-on事件绑定委托给子组件执行,因为子组件的提交按钮和父组件的刷新评论的功能是分开的. 2.没有数据时直接点击提交按钮时会出bug,并且关闭后重新加载 ...