Как представить FormattedText с RenderTargetBitmap в изображении?

Я не могу найти ответ в Google.

У меня есть много строк, которые будут представлены на холсте. Каждая строка будет создана с использованием метода FormattedText() в конвертере строк, вызванном из ItemsControl.

Проблема с кодом заключается в том, что ему требуется смехотворно большая ширина и высота в RenderTargetBitmap() для отображения всех строк в разных позициях, даже если каждая строка имеет приблизительную фактическую ширину 700 и фактическую высоту 40. (Кажется, что хотя RenderTargetBitmap() должен быть достаточно большим, чтобы содержать не только строку, но и позицию этой строки в контексте рисования).

Как создать изображение из одной строки форматированного текста с правильной фактической высотой и шириной только отформатированного текста, а затем правильно расположить это изображение в точке "topleft"?

Преобразователь, вызываемый из ItemsControl, определяется как:

 public class InkConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var stringviewmodel = value as StringViewModel;
        if (stringviewmodel != null)
        {
           stringviewmodel.ft = new FormattedText(
           stringviewmodel.text,
           CultureInfo.CurrentCulture,
           FlowDirection.LeftToRight,
           new Typeface(new FontFamily("Segoe Script"), FontStyles.Italic, FontWeights.Normal, FontStretches.Normal),
           stringviewmodel.emSize,
           stringviewmodel.color);

           stringviewmodel.ft.TextAlignment = TextAlignment.Left;
           stringviewmodel.ft.LineHeight =(double)stringviewmodel.lineheight;

            Image myImage = new Image();

            DrawingVisual dw = new DrawingVisual();
            DrawingContext dc = dw.RenderOpen();
            dc.DrawText(stringviewmodel.ft, stringviewmodel.topleft);
            dc.Close();


            int Width = 2000;
            int Height = 2000;
            RenderTargetBitmap bmp = new RenderTargetBitmap(Width, Height, 120, 96, PixelFormats.Pbgra32);  

            bmp.Render(dw);
            myImage.Source = bmp;

            return myImage;
        }
        else
        {
            return null;
        }
    }

    public object  ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

}

Приложение:

Я написал это, что решило проблему, но не отвечает на мой вопрос. (символы gt и lt удалены).

  1. Изменены элементы управления для включения:

    ItemsControl.ItemContainerStyle Style TargetType = "{x: Type FrameworkElement} Setter Property =" Canvas.Top "Value =" {Binding topleft.Y} "Setter Свойство ="Canvas.Left" Value="{Binding topleft.X}" Setter Свойство = "Высота" Значение ="{Binding ft.Height}"

  2. Убрано все позиционирование из конвертера. Конвертер теперь читается как

    public object Convert(object value, Type targetType, object parameter,   
    System.Globalization.CultureInfo culture)
    {
        var stringviewmodel = value as StringViewModel;
        if (stringviewmodel != null)
        {
           stringviewmodel.ft = new FormattedText(
           stringviewmodel.text,
           CultureInfo.CurrentCulture,
           FlowDirection.LeftToRight,
           new Typeface(new FontFamily("Segoe Script"), FontStyles.Italic, FontWeights.Normal, FontStretches.Normal),
           stringviewmodel.emSize,
           stringviewmodel.color);
    
    
            stringviewmodel.ft.TextAlignment = TextAlignment.Left;
            stringviewmodel.ft.LineHeight =(double)stringviewmodel.lineheight;
    
            Image myImage = new Image();
            DrawingVisual dw = new DrawingVisual();
            DrawingContext dc = dw.RenderOpen();
    
            dc.DrawText(stringviewmodel.ft, new Point(0,0));
    
            dc.Close();
    
           double width = stringviewmodel.ft.text.Width - stringviewmodel.text.OverhangLeading -   stringviewmodel.text.OverhangTrailing;
    
            RenderTargetBitmap bmp = new RenderTargetBitmap(
            (int)(width,
            (int)stringviewmodel.ft.Height,
            96d,            
            96d,
            PixelFormats.Pbgra32);  
    
            bmp.Render(dw);
            myImage.Source = bmp;
    
            return myImage;
        }
        else
        {
            return null;
        }
    }
    

1 ответ

Вы живете в прошлом со всем этим WinForms-подобным кодом... это WPF! Во-первых, вам не нужно никаких FormattedText объекты, как вы можете сделать все это в XAML очень легко. Возьмите этот простой пример:

<TextBlock Name="TextBlockToGetImageFrom">
    <Run FontFamily="Arial" FontWeight="Bold" FontSize="40" Foreground="Red" Text="W" />
    <Run FontFamily="Tahoma" Text="indows" FontSize="20" BaselineAlignment="Bottom" />
    <Run FontFamily="Arial" FontWeight="Bold" FontSize="40" Foreground="Red" Text=" P" />
    <Run FontFamily="Tahoma" Text="resentation" FontSize="20" BaselineAlignment="Center" />
    <Run FontFamily="Arial" FontWeight="Bold" FontSize="40" Foreground="Red" Text=" F" />
    <Run FontFamily="Tahoma" Text="ormat" FontSize="20" BaselineAlignment="Top" />
</TextBlock>

введите описание изображения здесь

Это просто показывает некоторую гибкость WPF, и здесь также не показаны другие параметры. Итак, когда у вас есть TextBlock установить по необходимости, вы можете превратить его в изображение с помощью нескольких строк кода, используя RenderTargetBitmap класс:

RenderTargetBitmap renderTargetBitmap = 
    new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(TextBlockToGetImageFrom); 
PngBitmapEncoder pngImage = new PngBitmapEncoder();
pngImage.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
using (Stream fileStream = File.Create(filePath))
{
    pngImage.Save(fileStream);
}
Другие вопросы по тегам