WPF пиксельное черно-белое изображение после преобразования - PullRequest
0 голосов
/ 06 апреля 2020

Edited. Добавлен минимальный работоспособный пример

У меня есть приложение wpf с Image Control. Я рисую линии и текст, отображаю на изображении текстовые поля разными цветами на основе type текста.

Для этого примера все цвета будут белыми.

Затем я нажму кнопку, преобразую изображение в BlackWhite, отобразлю его в элемент управления изображением, а затем сгенерирую растровый файл.

Проблема, с которой я столкнулся, заключается в том, что когда я конвертирую его в черно-белое изображение, тени вокруг линий и текста получают Pixelated.

Есть ли способ избавиться от теней или предотвратить их пикселизацию?

Я мог бы даже сделать с помощью рисования на дополнительном скрытом изображении BlackAndWhite в то же время время и создание растра из этого изображения, а не того, которое видит пользователь.

ExampleImage zoomedFinalImage

Пример минимальной работоспособности

xaml

<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>

xaml.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;
        }
    }
}

enter image description here

1 Ответ

0 голосов
/ 09 апреля 2020

Я думаю, что я на что-то. Я взял изображение, сделал его серым, записал это изображение в массив, каждый байт которого представляет собой пиксель. Затем, используя этот массив, я генерирую другой массив, где каждый байт составляет 8 пикселей, и из этого я либо генерирую окончательное изображение. Это изображение для сравнения: img1

А вот пример:

xaml

<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>

xaml.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 для 256 оттенков серого в формате grey8 pixel). Проблема, которая у меня есть, и по какой-то причине (мозг, вероятно, похож на mu sh potato из-за блокировки), я не могу ее решить, это то, что исходная ширина изображения должна делиться на 8, иначе она выдает исключение , Я имею в виду, я понимаю, почему вам нужно 8 байтов исходного изображения, чтобы сделать байт во втором массиве, но я не могу найти способ добавить нули. Наверное, разберемся завтра, но не стесняйтесь помочь :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...