如何在图像中呈现带有 RenderTargetBitmap 的 FormattedText?

Posted

技术标签:

【中文标题】如何在图像中呈现带有 RenderTargetBitmap 的 FormattedText?【英文标题】:How to present FormattedText with RenderTargetBitmap in an Image? 【发布时间】:2014-10-26 17:45:58 【问题描述】:

我在 Google 上找不到答案。

我有很多字符串要显示在画布上。每个字符串都将使用从 ItemsControl 调用的字符串转换器中的 FormattedText() 方法创建。

代码的问题在于,它需要在 RenderTargetBitmap() 中使用非常大的宽度和高度来显示不同位置的所有字符串,即使每个字符串的实际宽度大约为 700,实际高度为 40。(似乎 RenderTargetBitmap() 需要足够大,不仅可以容纳字符串,还可以容纳该字符串在绘图上下文中的位置)。

您如何创建一个仅包含单个格式化文本字符串的图像,该图像具有正确的实际高度和宽度,只有格式化文本,然后将该图像正确定位在“左上角”点?

从 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 样式 TargetType="x:Type FrameworkElement Setter Property="Canvas.Top" Value="Binding topleft.Y" Setter 属性="Canvas.Left" 值="绑定 topleft.X" Setter 属性="高度" 值="绑定 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;
        
    
    

【问题讨论】:

随着您在这里提出的每一个问题,您似乎越来越纠结于越来越陌生的解决方案。从绑定转换器返回 Image 控件纯属无稽之谈。也许是时候解释一下你的最终目标了。您的应用程序期望做什么?肯定有更简单的方法可以到达那里。拥有 ItemsControl 肯定是正确的,但是您还应该创建一个适当的 DataTemplate(为其 ItemTemplate 属性)来可视化您的字符串。 @Clemens 你可能是正确的。大约 6 年前,我编写了原始代码来执行手写识别和文本编辑。我最近的努力是尝试将旧代码拆开,更好地理解它,并尽可能接近 MVVM 模式。当前的问题来自于采用较旧的格式化文本,将其显示在项目控件中,但需要每行的最终图像尽可能精确到字符串尺寸。然后将针对生成的图像进行命中测试。然后将笔画 + 命中的结果提供给我的编辑器以修改字符串。 @Clemens 如果有更清洁的方法,我肯定愿意接受建议。 老实说,我不明白你在做什么。什么是“旧格式文本”?命中测试有什么用?什么是“击球+击球”?如果你想实现一个真正的 WPF 解决方案,你应该首先从你的所有细节中退一步,并给出目的或你的应用程序的一般描述。它有什么作用?应该如何工作? 那么为什么不创建一个包含 TextBlock 和覆盖 InkCanvas 的 UserControl,两者都包含在 Grid 中,并在 ItemsControl 的 ItemTemplate 中使用它。因此,每个字符串项都有一个 InkCanvas,并且可以摆脱任何命中测试和所有其他复杂的东西。 【参考方案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 class 将其转换为只需几行代码的图像:

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

【讨论】:

以上是关于如何在图像中呈现带有 RenderTargetBitmap 的 FormattedText?的主要内容,如果未能解决你的问题,请参考以下文章

将自定义类插入到由 tinyMCE 通过 jQuery 呈现的 WYSIWIG 输出中(在 Wordpress 中处理带有标题的图像)

在 React Native iOS 中的图像顶部呈现具有透明背景的文本框

带有 OpenGL 和 Kinect v2 的 QT5:错误的图像呈现

在视图而不是模板中生成带有 Django 静态 url 的图像标签

如何在从带有翠鸟的URL加载图像后调整UIImageView的大小

如何解析带有附件和内联图像的 EML 文件并转换为 HTML