0

我的程序是 MS paint 和 Pickpick 的一种复制版本。并且功能之一是栅格化所选对象,例如文本块或形状。

关于可选对象,为了调整大小和与装饰器一起移动,它有 1 个 ContentControl,包括 1 个文本块 + 1 个形状。

ContentControl (able to resize, rotate, move)
└─> Textblock (bold, italic, V-align, H-align, word wrap...)
└─> Shape (can be a triangle, rectangle etc...)

像这样

转换为使用绘图上下文绘制形状而不是在 Canvas 上渲染并不难。

var SH = CC.GetShape();
var TB = CC.GetTextBlock();
var visual = new DrawingVisual();

Geometry geo = null;
System.Windows.Media.Pen pen = null;
System.Windows.Media.Brush brush = null;
if (SH != null)
{
    geo = SH.RenderedGeometry;  // shape to geo
    if (geo == null)
        return;
    pen = new System.Windows.Media.Pen(SH.Stroke, SH.StrokeThickness);
    brush = SH.Fill;
}

using (var dc = visual.RenderOpen())
{
    // Draw the background first
    dc.DrawImage(first, new Rect(0, 0, first.Width, first.Height));
    dc.PushTransform(new TranslateTransform(left, top));
    // Draw the shape
    if (SH != null && geo != null)
        dc.DrawGeometry(brush, pen, geo);
}

但是,在使用绘图上下文绘制 Textblock 时,我参考了下面的链接来计算 Textblock 与 DrawingContext.DrawText 垂直对齐
的位置, 但问题是当 Textblock 有多行或换行时。
我的程序截图 在此处输入图像描述

 if (TB.Text.Equals(string.Empty) == false)
 {
      var typeface = new Typeface(CC.txtSetting.fontFamily,
      CC.txtSetting.fontStyle,
      CC.txtSetting.fontWeight,
      FontStretches.Normal);

      var formattedText = new FormattedText(TB.Text
                 , CultureInfo.CurrentCulture
                 , FlowDirection.LeftToRight
                 , typeface
                 , CC.txtSetting.fontSize
                 , new SolidColorBrush(CC.txtSetting.fontColor));

      double centerX = CC.ActualWidth / 2;
      double centerY = CC.ActualHeight / 2;

      double txtPositionX = 0.0f;
      double txtPositionY = 0.0f;
      if (TB.TextAlignment == TextAlignment.Left)
      {
          txtPositionX = 1.0f;
      }
      else if (TB.TextAlignment == TextAlignment.Center)
      {
          txtPositionX = centerX - formattedText.WidthIncludingTrailingWhitespace / 2;
      }
      else if (TB.TextAlignment == TextAlignment.Right)
      {
          txtPositionX = CC.Width - 
formattedText.WidthIncludingTrailingWhitespace - 1.0f;
      }

      if (TB.VerticalAlignment == VerticalAlignment.Top)
      {
          txtPositionY = 1.0f;
      }
      else if (TB.VerticalAlignment == VerticalAlignment.Center)
      {
          txtPositionY = centerY - formattedText.Height / 2;
      }
      else if (TB.VerticalAlignment == VerticalAlignment.Bottom)
      {
          txtPositionY = CC.Height - formattedText.Height - 1.0f;
      }

      var ptLocation = new System.Windows.Point(txtPositionX, txtPositionY);
                dc.DrawText(formattedText, ptLocation);
  }

此外,文本块由 ContentControl 包装,因此根据用户更改文本块的属性,它会有很大的不同。我想似乎不可能转换每个变量。所以,我正在考虑其他的绘画方式。

  1. 使用 GDI+ 进行绘制,而不是使用绘图上下文进行绘制。(仍不确定)
  2. 在用户编辑文本时使用绘图上下文。(所以在光栅化之前它会是一样的,反之亦然)
  3. 有什么方法可以直接将文本块转换/捕获为图像或几何图形?(如果可能的话,这将是最好的方法。)例如,要获得应用了着色器效果的图像源,我确实喜欢这样做。所以..可能有办法。 如何获得效果应用源的对象

也可以从http://ngwin.com/picpick 参考这个程序
picpick 截图 在此处输入图像描述

有更好的想法吗?先感谢您。

4

1 回答 1

0

我做到了!
我可以使用RenderTargetBimap. 因为ContentControlVisual元素的一部分。
CustomControl是从 继承的控制权ContentControl

    public static BitmapSource ControlToBitmap(CustomControl control)
    {
        int W = (int)control.ActualWidth;
        int H = (int)control.ActualHeight;
        RenderTargetBitmap renderBitmap = new RenderTargetBitmap(
         W, H,
         96d, 96d, PixelFormats.Pbgra32);

        // needed otherwise the image output is black
        control.Measure(new System.Windows.Size(W, H));
        control.Arrange(new Rect(new System.Windows.Size(W, H)));

        renderBitmap.Render(control);

        var BS = RenderTargetBitmapToBitmap(renderBitmap);
        return BS;
    }

要修复的错误行为
此外,我必须处理角度。因为我无法直接捕获角度控制。但我的想法是

  1. 先备份角度值。
  2. 并将控件恢复为不旋转( RotateTransform = 0.0)
  3. 将非旋转控件捕获到位图。
  4. 然后再次旋转捕获的位图。
  5. 将两个位图合并为一个。

    public static void OverlayControl(ImageSource first, CustomControl CC)
    {
        if (CC == null)
            return;
    
        var visual = new DrawingVisual();
    
        double left = Canvas.GetLeft(CC);
        double top = Canvas.GetTop(CC);
    
        // Get control's angle.
        double rotationInDegrees = 0.0f;
        RotateTransform rotation = CC.RenderTransform as RotateTransform;
        if (rotation != null) // Make sure the transform is actually a RotateTransform
        {
            rotationInDegrees = rotation.Angle; // back up this to temp var.
            rotation.Angle = 0.0f; // Set this to 0.0 to capture properly.
        }
    
        var second = ControlToBitmap(CC);
    
    
        using (var dc = visual.RenderOpen())
        {
            // Draw the background image frist.
            dc.DrawImage(first, new Rect(0, 0, first.Width, first.Height));
    
            // Push angle if the control has rotated.
            if (rotationInDegrees != 0.0f)
                dc.PushTransform(new RotateTransform(rotationInDegrees, left + (CC.Width / 2), top + (CC.Height / 2)));
    
            // transfrom as much as control moved from the origin.
            dc.PushTransform(new TranslateTransform(left, top));
            // Draw the second image. (captured image from the control)
            dc.DrawImage(second, new Rect(0, 0, second.Width, second.Height));
    
            // pop transforms
            dc.Pop();
        }
    
        var rtb = new RenderTargetBitmap((int)first.Width, (int)first.Height,
                                    96, 96, PixelFormats.Default);
        rtb.Render(visual);
        // Set as a one combined image.
        MainWindow.VM.RenderedImage = rtb;
    }
    

现在,一切似乎都很好。 在此处输入图像描述

于 2018-02-16T09:09:58.650 回答