c# - 转换后的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;
}
}
}
解决方案
我想我正在做某事。我拍摄了图像,将其制作为 gray8 图像,然后将该图像写入一个数组,其中每个字节都是一个像素。然后使用该数组生成另一个数组,其中每个字节为 8 个像素,然后生成最终图片。此图用于比较:
这是一个例子:
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 个字节的原始图像在第二个数组上创建一个字节,但我找不到添加空值的方法。明天可能会解决,但请随时提供帮助:)
推荐阅读
- powershell - 如何从 Get-ADComputer 的描述字段中删除逗号后的文本?
- graphql - 使用 graphql 提供图像
- oop - 如何存储系统创建的待办事项?
- .net - .net 中的正则表达式以 2 个特定字符开头,以数字结尾,并以一定长度
- lucene - 为 FuzzyQuery 获取重写的术语列表
- authorization - Sonos audioclip api 减少了身份验证参数的长度
- laravel - 我们如何在 laravel eloquent/querybuilder 中转换 sql
- python - 什么是 Python 映射?
- compiler-construction - YACC时表达式&&表达式错误!无法先读取第一个表达式
- php - 什么是 mcrypt_get_block 替代方案以及如何使用它