zoukankan      html  css  js  c++  java
  • 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();
            }
    

    去掉蓝色的图片

    代码: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

  • 相关阅读:
    hdu 5224 Tom and paper 水题
    2015 UESTC 搜索专题N题 韩爷的梦 hash
    2015 UESTC 搜索专题M题 Palindromic String 马拉车算法
    2015 UESTC 搜索专题K题 秋实大哥の恋爱物语 kmp
    2015 UESTC 搜索专题J题 全都是秋实大哥 kmp
    2015 UESTC 搜索专题F题 Eight Puzzle 爆搜
    2015 UESTC 搜索专题E题 吴队长征婚 爆搜
    2015 UESTC 搜索专题D题 基爷的中位数 二分
    2015 UESTC 搜索专题C题 基爷与加法等式 爆搜DFS
    2015 UESTC 搜索专题B题 邱老师降临小行星 记忆化搜索
  • 原文地址:https://www.cnblogs.com/lindexi/p/12086618.html
Copyright © 2011-2022 走看看