首页 > 解决方案 > 转换后的WPF像素化黑白图像

问题描述

我有一个带有Image Control. 我绘制线条和文本,在图像上显示基于文本的不同颜色的文本字段type

对于这个例子,所有颜色都是白色的。

然后我将按下一个按钮,将图像转换为 ,将其BlackWhite显示到图像控件,然后生成一个光栅文件。

我遇到的问题是,当我将其转换为黑白时,线条和文本周围的阴影越来越大Pixelated

有没有办法摆脱阴影或阻止它们被像素化?

我什至可以同时绘制一个额外隐藏的黑白图像,并从该图像而不是用户看到的图像生成光栅。

示例图像 放大的最终图像

最小可行示例

xml

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="400" Width="500">
    <Grid>
        <Image x:Name="originalImage" HorizontalAlignment="Left" Height="100" Margin="30,100,0,0" VerticalAlignment="Top" Width="183" />
        <Image x:Name="convertedImage" HorizontalAlignment="Left" Height="100" Margin="250,100,0,0" VerticalAlignment="Top" Width="183" />
    </Grid>
</Window>

xml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DrawingVisual visual = new DrawingVisual();
            using (DrawingContext dc = visual.RenderOpen())
            {
                int fs = 28;
                string textContain = "Testing 123";
                Point p = new Point(0, 0);
                dc.DrawRectangle(Brushes.Black, null, new Rect(0, 0, originalImage.Width, originalImage.Height));
                dc.DrawText(new FormattedText(textContain, System.Globalization.CultureInfo.InvariantCulture, FlowDirection.LeftToRight,
                            new Typeface("Arial"), fs, Brushes.White, VisualTreeHelper.GetDpi(visual).PixelsPerDip), p);
            }
            RenderTargetBitmap target = 
                new RenderTargetBitmap((int)originalImage.Width, (int)originalImage.Height, 96, 96, PixelFormats.Default);
            target.Render(visual);
            FormatConvertedBitmap grayBitmapSource1 =
            new FormatConvertedBitmap(target as BitmapSource, PixelFormats.Bgr24, null, 0);

            var grayBitmapSource = new FormatConvertedBitmap();
            grayBitmapSource.BeginInit();
            grayBitmapSource.Source = grayBitmapSource1.Source as BitmapSource;
            grayBitmapSource.DestinationFormat = PixelFormats.BlackWhite;
            grayBitmapSource.EndInit();
            originalImage.Source = target;
            convertedImage.Source = grayBitmapSource;
        }
    }
}

在此处输入图像描述

标签: c#wpfimage

解决方案


我想我正在做某事。我拍摄了图像,将其制作为 gray8 图像,然后将该图像写入一个数组,其中每个字节都是一个像素。然后使用该数组生成另一个数组,其中每个字节为 8 个像素,然后生成最终图片。此图用于比较: 图像1

这是一个例子:

xml

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="400" Width="500">
    <Grid>
        <Image x:Name="originalImage" HorizontalAlignment="Left" Height="100" Margin="30,100,0,0" VerticalAlignment="Top" Width="200" />
        <Image x:Name="convertedImage" HorizontalAlignment="Left" Height="100" Margin="250,39,0,0" VerticalAlignment="Top" Width="200" />
        <Image x:Name="CustomConvertedImage" HorizontalAlignment="Left" Height="100" Margin="250,156,0,0" VerticalAlignment="Top" Width="200" />
    </Grid>
</Window>

xml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DrawingVisual visual = new DrawingVisual();
            using (DrawingContext dc = visual.RenderOpen())
            {
                int fs = 28;
                string textContain = "Testing 123";
                Point p = new Point(10, 10);
                dc.DrawRectangle(Brushes.Black, null, new Rect(0, 0, originalImage.Width, originalImage.Height));
                dc.DrawText(new FormattedText(textContain, System.Globalization.CultureInfo.InvariantCulture, FlowDirection.LeftToRight,
                            new Typeface("Arial"), fs, Brushes.White, VisualTreeHelper.GetDpi(visual).PixelsPerDip), p);
                dc.DrawLine(new Pen(Brushes.White, 3), new Point(5, 5), new Point(originalImage.Width - 5, 5));
                dc.DrawLine(new Pen(Brushes.White, 3), new Point(5, originalImage.Height - 5), new Point(originalImage.Width - 5, originalImage.Height - 5));
                dc.DrawLine(new Pen(Brushes.White, 3), new Point(5, 5), new Point(5, originalImage.Height));
                dc.DrawLine(new Pen(Brushes.White, 3), new Point(originalImage.Width - 5, 0), new Point(originalImage.Width - 5, originalImage.Height - 5));
            }
            RenderTargetBitmap target =
                new RenderTargetBitmap((int)originalImage.Width, (int)originalImage.Height, 96, 96, PixelFormats.Default);
            target.Render(visual);
            FormatConvertedBitmap grayBitmapSource1 =
            new FormatConvertedBitmap(target as BitmapSource, PixelFormats.Bgr24, null, 0);

            var grayBitmapSource = new FormatConvertedBitmap();
            grayBitmapSource.BeginInit();
            grayBitmapSource.Source = grayBitmapSource1.Source as BitmapSource;
            grayBitmapSource.DestinationFormat = PixelFormats.BlackWhite;
            grayBitmapSource.EndInit();
            originalImage.Source = target;
            convertedImage.Source = grayBitmapSource;
            CustomConvertedImage.Source = ConvertToBlackAndWhiteAliased(originalImage, 80).Item1;
        }

        private Tuple<System.Windows.Media.Imaging.BitmapSource, byte[]> ConvertToBlackAndWhiteAliased(Image _sourceImage, int _grayFilter = 80)
        {
            FormatConvertedBitmap grayed8Image = new FormatConvertedBitmap(_sourceImage.Source as BitmapSource, PixelFormats.Gray8, null, 0);
            double bytePerPixel_Test = grayed8Image.Format.BitsPerPixel / 8.0;
            int width_Test = grayed8Image.PixelWidth;
            int height_Test = grayed8Image.PixelHeight;
            int stride_Test = (int)(width_Test * bytePerPixel_Test);
            byte[] resultLine_Test = new byte[height_Test * stride_Test];
            grayed8Image.CopyPixels(resultLine_Test, stride_Test, 0);

            double bytePerPixel = 1 / 8.0;
            int width = grayed8Image.PixelWidth;
            int height = grayed8Image.PixelHeight;
            int stride = (int)(width * bytePerPixel);
            byte[] resultLine = new byte[height * stride];

            byte tempByter;
            for (int enum8bpp = 0; enum8bpp < resultLine_Test.Length; enum8bpp += 8)
            {
                tempByter = 0;

                for (int tempByterEnumer = 0; tempByterEnumer < 8; tempByterEnumer++)
                {
                    tempByter |= (byte)(((resultLine_Test[enum8bpp + tempByterEnumer] > _grayFilter) ? 1 : 0) << 7 - tempByterEnumer);
                }

                resultLine[enum8bpp / 8] = tempByter;
            }
            WriteableBitmap bitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.BlackWhite, null);
            bitmap.WritePixels(new Int32Rect(0, 0, width, height), resultLine, (int)(width * (bitmap.Format.BitsPerPixel / 8.0)), 0);
            return new Tuple<System.Windows.Media.Imaging.BitmapSource, byte[]>(bitmap, resultLine);
        }
    }
}

您可以从函数(使用 .item1)或直接从数组(item2)获取图像。_grayFilter 表示您希望转换器的敏感程度(0 到 255,表示 gray8 像素格式中的 256 种灰度)。我遇到的问题并且由于某种原因(由于锁定,大脑可能就像一个土豆泥)我无法解决它,是原始图像宽度需要可被 8 整除,否则会引发异常。我的意思是我明白为什么,你需要 8 个字节的原始图像在第二个数组上创建一个字节,但我找不到添加空值的方法。明天可能会解决,但请随时提供帮助:)


推荐阅读