Как представить 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 удалены).
Изменены элементы управления для включения:
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}"
Убрано все позиционирование из конвертера. Конвертер теперь читается как
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);
}