计算旋转文字加上边框的坐标 [英] Calculate coordinates for rotated text plus bounding border

查看:96
本文介绍了计算旋转文字加上边框的坐标的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个表格,该表格将允许用户创建自定义的邮票以放置在PDF上。表单显示的是pdf第一页的图像,我希望用户基本上在屏幕上单击他们想要其图章的位置,并能够预览其外观。不用担心任何PDF内容,我已经解决了。

I have a form that is going to allow a user to create custom "stamps" to place on a PDF. The form displays with a image of the first page of the pdf and I want the user to basically click on the screen where they want their stamp and be able to preview what its going to look like. Don't worry about any of the PDF stuff, I have that handled.

为了使外观更时尚,我有两张图片,普通的一张,一张亮度降低。我显示低亮度图像,并且当用户将鼠标移到上方时,会显示或突出显示原始图像的一部分。然后,我在该区域中显示用户要放入PDF的文本。

To make things snazzy, I have two copies of the image, the normal one and one with reduced brightness. I display the low brightness image and as the user moves the mouse over, a chunk of the original image is revealed or highlighted. I then display in that area the text the user is going to put on the PDF.

我允许用户使用鼠标滚轮滚动并更改他们放置的文本的角度(从-45度到+45度)。

I allow the user to use the mousewheel to scroll and change the angle of the text they are placing (from -45 degrees to +45 degrees).

这是我的问题:我无法计算正确的矩形/坐标。有时一切看起来都很不错,而其他时候(随着字体大小的变化)它们不太适合。

Here is my problem: I can't calculate the proper rectangles/coordinates. Sometimes everything looks great, other times (as font sizes change) they don't quite fit.

如何计算以下各项的x和y坐标:
放置旋转后的文本
,以及在文本的宽度和宽度处填充边框的矩形高度为10px

How do I calculate the x and y coordinates for: placement of the rotated text AND a bounding rectangle padding the text at its width and height with 10px

下面的代码有效,直到我开始提高字体大小,然后一切都变得不倾斜了。

The code below works, until I start to crank up the font size, then everything gets out of skew.

前两个图像以较小的字体显示文本+边界矩形。看起来不错:

First two images show text + bounding rectangle at smaller fonts. It looks good:


下一个该图显示,随着文本大小的增加,像素四处移动并被切掉。在更大的文本中,宽度/高度也相去甚远。

The next image shows that as the text size gets larger, my pixels are moving all around and gets chopped off. In even larger text, the widths/heights end being way off as well.

>

对不起,示例图像没有显示太多细节。我有无法共享的实际数据。

Sorry the example images don't show much detail. I have actual data that I can't share.

        Private Sub PanelMouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) '// handles the mouse move (handler added elsehwere)

        With CType(sender, PictureBox)

            .Image.Dispose() '// get rid of old image

            Dim b As Bitmap = _curGray.Clone '// the low brightness image as the base image

            '// stamp font and text values are initiated from another form
            Using g As Graphics = Graphics.FromImage(b),
                f As New Font(DefaultFont.FontFamily, CSng(_stmpTools.StampTextSize), If(_stmpTools.StampBold, FontStyle.Bold, FontStyle.Regular))

                Const borderWidth As Integer = 10
                Const borderPadding As Integer = 5

                '// measure the string
                Dim szx As SizeF = g.MeasureString(_stmpTools.StampText, f, Integer.MaxValue, StringFormat.GenericDefault)
                Dim strLength As Single = szx.Width
                Dim strHeight As Single = szx.Height

                Dim x As Single = e.X - borderWidth - borderPadding,
                    y As Single = e.Y

                Dim w As Double, h As Double

                If Math.Abs(_angle) > Double.Epsilon Then
                    h = CDbl(strLength) * Math.Sin(CDbl(Math.Abs(_angle)) * Math.PI / 180.0F)
                    w = Math.Sqrt(CDbl(strLength) * CDbl(strLength) - h * h)
                Else
                    '// its zero. so use calculated values
                    h = strHeight
                    w = strLength
                End If

                '// add space for the 10px border plus 5px of padding
                Dim r As New Rectangle(0, 0, w, h)
                r.Inflate(borderWidth + borderPadding, borderWidth + borderPadding)

                h = r.Height
                w = r.Width

                '// keep box from moving off the left
                If x < .Location.X Then
                    x = .Location.X
                End If

                '// keep box from moving off the right
                If x > .Location.X + .Width - w Then
                    x = .Location.X + .Width - w
                End If

                '// I don't know, but these values work for most smaller fonts, but
                '// it has got to be a fluke
                If _angle > 0 Then
                    y = y - h + borderWidth + borderWidth
                Else
                    y = y - borderWidth
                End If

                '// can't go off the top
                If y < .Location.Y Then
                    y = .Location.Y
                End If

                '// can't go off the bottom
                If y > .Location.Y + .Height - h Then
                    y = .Location.Y + .Height - h
                End If

                Dim rect As New Rectangle(x, y, w, h)
                g.DrawImage(_curImg, rect, rect, GraphicsUnit.Pixel)

                Using br As New SolidBrush(_stmpTools.StampTextColor)
                    RotateString(_stmpTools.StampText, _angle, e.X, e.Y, f, g, br)
                End Using

                '//draw bounding rectangle
                Using p As New Pen(Color.Black, borderWidth)
                    g.DrawRectangle(p, rect)
                End Using

            End Using
            '// set the picture box to show the new image
            .Image = b
        End With

    End Sub

    Private Sub RotateString(ByVal Text As String, ByVal angle As Integer, _
                      ByVal x As Integer, ByVal y As Integer, myfont As Font, mydrawing As Graphics, myColor As Brush)
        Dim myMatrix As New Matrix
        myMatrix.RotateAt(angle * -1, New Point(x, y)) 'Rotate drawing 
        mydrawing.Transform = myMatrix
        mydrawing.DrawString(Text, myFont, myColor, x, y) 'Draw the text string 
        myMatrix.RotateAt(angle, New Point(x, y)) 'Rotate back 
        mydrawing.Transform = myMatrix
    End Sub

在绘图方面,我并不是最大的。因此,任何帮助都是很棒的

I'm not the greatest when it comes to drawing. So any help would be great

使用@LarsTech提供的以下解决方案。我将g.FillRectangle替换为:

Using the solution below from @LarsTech. I replaced the g.FillRectangle with:

g.DrawImage(_curImg, r, r, GraphicsUnit.Pixel)

_curImg是原始图像的副本,其亮度已调整。当我从下面更改代码时,我最终得到:

_curImg is a copy of the original image with the brightness tuned up. When I change the code from below I end up with:

注意双线。它们会随印章一起旋转,即使它们充当背景图像,并且也应不旋转

Note the double lines. They rotate with the stamp, even though they are acting as a background image and should be unrotated

根据建议,我将DrawStamp从@LarsTech更改为以下内容:

Per suggestion, I changed the DrawStamp from @LarsTech to the following:

        Private Sub DrawStamp(g As Graphics, text As String,
                  f As Font, center As Point, angle As Integer, backImg As Image)

        Dim s As Size = g.MeasureString(text, f).ToSize
        Dim r As New Rectangle(center.X - (s.Width / 2) - 16,
                                 center.Y - (s.Height / 2) - 16,
                                 s.Width + 32,
                                 s.Height + 32)

        g.DrawImage(backImg, r, r, GraphicsUnit.Pixel)

        Using m As New Matrix
            m.RotateAt(angle, center)
            g.Transform = m

            Using p As New Pen(Color.Black, 6)
                g.DrawRectangle(p, r)
            End Using
            Using sf As New StringFormat
                sf.LineAlignment = StringAlignment.Center
                sf.Alignment = StringAlignment.Center
                g.DrawString(text, f, Brushes.Black, r, sf)
            End Using
            g.ResetTransform()
        End Using
    End Sub

但是,我现在剩下的是

However, I am now left with

请注意,它绘制了背景,然后旋转并绘制了图章。它几乎可以工作。在此示例中,直线显示了预期的行为...但是,我希望用背景填充整个图章。侧面多余的白色将被旋转到邮票的背景中。我很困惑,因为我会怀疑会截取图像的灰色部分,但并不是(如果我将其移到我不幸不能在此处张贴的其他区域上),通知就没有了

Notice it drew the background, then did the rotation and drew the stamp. It ALMOST works. In this example the straight lines show the intended behavior... however i'm looking to fill the entire stamp with the background. That extra white on the sides would have been what was rotated into the stamp's background. I'm confused because the 'grey' portions I would then suspect to be clipping out parts of the image, but they aren't (if i move it over other areas that I unfortunately can't post on here) notice is out of skew except for the fact that the sides of the rectangle paint as such.

另一个希望提供更多信息的编辑

希望这里是对我正在尝试做的更好的解释。我使用第三方PDF查看器,并且需要允许用户将图像添加到PDF。查看器不允许我在其上引发点击事件,因此为了获取用户的鼠标点击,我执行以下操作:

Here is hopefully a better explaination of what I am trying to do. I use a third party PDF viewer and I need to allow the user to add an image to the PDF. The viewer doesn't allow me to raise click events on it, so in order to grab user mouse clicks, I do the following:


  1. 抓取表单的屏幕

  2. 隐藏PDF查看器

  3. 向我的表单添加一个PictureBox控件,替换PDF查看器所在的区域

  4. 通过屏幕抓取,我制作了亮度降低的图像副本

  5. 显示图像的灰度副本并直接在图像上绘制在图片框上使用鼠标悬停事件

  6. 我在图片框上绘制了一个图章,但希望它的背景是原始的(未调整亮度的图像)。但是,由于该区域可能会通过旋转进行变换,因此我无法获取背景图像。如果未提供角度,则源矩形匹配。但是,如果将其旋转,则无法从源图像中获取相同的旋转矩形。

  1. Take a screen grab of form
  2. Hide the PDF Viewer
  3. Add a PictureBox control to my form, replacing the area where the PDF viewer was
  4. With my screen grab, I make a copy of the image with the brightness reduced
  5. Display the gray scale copy of the image and draw directly on the image using mouse over events on the picturebox
  6. I draw a stamp on the picturebox, but want the background of it to be the original (non adjusted brightness image). However, since the area might be transformed using a rotation, I can't grab the background image. If no angle is provided, the source rectangle matches. However if its rotated, I cannot grab the same rotated rectangle off the source image.

按钮单击事件:

  Dim bds As Rectangle = AxDPVActiveX1.Bounds
  Dim pt As Point = AxDPVActiveX1.PointToScreen(bds.Location)

    Using bit As Bitmap = New Bitmap(bds.Width, bds.Height)
        Using g As Graphics = Graphics.FromImage(bit)
            g.CopyFromScreen(New Point(pt.X - AxDPVActiveX1.Location.X, pt.Y - AxDPVActiveX1.Location.Y), Point.Empty, bds.Size)
        End Using

        _angle = 0

        _curImg = bit.Clone
        _curGray = Utils.CopyImageAndAdjustBrightness(bit, -100)

 End Using

   Dim p As New PictureBox

        Utils.SetControlDoubleBuffered(p)

        p.Dock = DockStyle.Fill
        p.BackColor = Color.Transparent
        AxDPVActiveX1.Visible = False
        p.Image = _curImg.Clone

        AddHandler p.MouseClick, AddressOf PanelDownMouse
        AddHandler p.MouseMove, AddressOf PanelMouseMove
        AddHandler p.MouseWheel, Sub(s As Object, ee As MouseEventArgs)
                                     _angle = Math.Max(Math.Min(_angle + (ee.Delta / 30), 45), -45)
                                     PanelMouseMove(s, ee)
                                 End Sub
        AddHandler p.MouseEnter, Sub(s As Object, ee As EventArgs)
                                     CType(s, Control).Focus()
                                 End Sub


        AxDPVActiveX1.Parent.Controls.Add(p)

在该代码之后,我得到了两个图像。 _curgray是具有调整后的亮度的图像,_curImg是我的原始屏幕抓取。

After that code I end up with two images. _curgray is an image with adjusted brightness, and _curImg is my original screen grab.

_curGray:>
_curImg:

_curGray: _curImg:

一个 mouseMove 移动事件已应用于我的新图片框。这是问题前面所有代码的作用所在。

A mouseMove move event is applied to my new picture box. This is where all the code from earlier in the question comes into play.

使用上面的代码,我的mouseMove事件不断创建新图像以显示在图片框中。如果不涉及轮换,我将获得所需的大部分东西。请注意下图中的图章背景如何比所有背景都亮。蓝色方块上的部分稍浅。我正在使用这种方式吸引观众的注意力,这对于我正在做的事情很重要。

Using the code above, my mouseMove event keeps creating a new imageto display in my picture box. If there is no rotation involved, I get pretty much what I'm looking for. Notice in the below image how the background of the stamp is brighter than everything. The portion over the blue square is slightly lighter. I am using this a way to draw the viewers eye to this area... its important for what I'm doing.

但是,当对其应用旋转时,我似乎无法复制从原始图像。看下面的图片,背景没有随之旋转。我需要从原始图像中抓取一个旋转的矩形。

However, when applying a rotation to it, I cannot seem to copy from the original image. Look at the following image, the backgroundisn't rotating with it. I need to grab a rotated rectangle from the ORIGINAL image.

http ://msdn.microsoft.com/zh-cn/library/ms142040(v = vs.110).aspx Graphics.DrawImage()接受

Public Sub DrawImage ( _
    image As Image, _
    destRect As Rectangle, _
    srcRect As Rectangle, _
    srcUnit As GraphicsUnit _
)

从我的源图像(在本例中为_curImg)中复制此源矩形并将其放置到我的新图形上。它不允许我对源矩形应用转换。基本上,我想从源图像中复制一个等效于旋转矩形的区域(基于@larstech的转换)

where I can specify copy this source rectangle from my source image (in this case _curImg) and place onto my new drawing. It does not allow me to apply a transformation to the source rectangle. Basically I want to copy from my source image an area equivalent to the rotated rectangle (based on the transformation from @larstech )

我不知道如何表达这个概念更清晰。如果仍然不可行,我将接受LarsTech回答作为最佳答案并放弃我的想法。

I don't know how to express this concept any clearer. If it still doesn't make sense I will just accept LarsTech answer as the best answer and scrap my idea.

推荐答案

我会尝试将矩形和文本绘制在一起:

I would try drawing the rectangle and the text together:

Private Sub DrawStamp(g As Graphics, text As String,
                      f As Font, center As Point, angle As Integer)
  Using m As New Matrix
    g.SmoothingMode = SmoothingMode.AntiAlias
    g.TextRenderingHint = TextRenderingHint.AntiAlias
    m.RotateAt(angle, center)
    g.Transform = m
    Dim s As Size = g.MeasureString(text, f).ToSize
    Dim r As New Rectangle(center.X - (s.Width / 2) - 16,
                           center.Y - (s.Height / 2) - 16,
                           s.Width + 32,
                           s.Height + 32)
    g.FillRectangle(Brushes.White, r)
    Using p As New Pen(Color.Black, 6)
      g.DrawRectangle(p, r)
    End Using
    Using sf As New StringFormat
      sf.LineAlignment = StringAlignment.Center
      sf.Alignment = StringAlignment.Center
      g.DrawString(text, f, Brushes.Black, r, sf)
    End Using
    g.ResetTransform()
  End Using
End Sub

绘制示例:

Protected Overrides Sub OnPaint(e As PaintEventArgs)
  MyBase.OnPaint(e)
  e.Graphics.Clear(Color.LightGray)
  Using f As New Font("Calibri", 16, FontStyle.Bold)
    DrawStamp(e.Graphics,
              "Reviewed By Doctor Papa",
              f,
              New Point(Me.ClientSize.Width / 2, Me.ClientSize.Height / 2),
              -25)
  End Using
End Sub

结果:

在这里,我将代码更新为剪切旋转的矩形,以便我可以从原稿复制相同的区域应用文字和边框之前的初始图像:

Here I updated the code to "clip" the rotated rectangle so that I can copy that same area from the original image before applying the text and border:

Private Sub DrawStamp(g As Graphics, text As String,
                      f As Font, center As Point, angle As Integer)

  Dim s As Size = g.MeasureString(text, f).ToSize
  Dim r As New Rectangle(center.X - (s.Width / 2) - 16,
                         center.Y - (s.Height / 2) - 16,
                         s.Width + 32,
                         s.Height + 32)

  Using bmp As New Bitmap(_curImg.Width, _curImg.Height)
    Using gx As Graphics = Graphics.FromImage(bmp)
      Using m As New Matrix
        m.RotateAt(angle, center)
        gx.Transform = m
        gx.SetClip(r)
        gx.ResetTransform()
      End Using
      gx.DrawImage(_curImg, Point.Empty)
    End Using
    g.DrawImage(bmp, Point.Empty)
  End Using

  Using m As New Matrix
    g.SmoothingMode = SmoothingMode.AntiAlias
    g.TextRenderingHint = TextRenderingHint.AntiAlias
    m.RotateAt(angle, center)
    g.Transform = m      
    Using p As New Pen(Color.Black, 6)
      g.DrawRectangle(p, r)
    End Using
    Using sf As New StringFormat
      sf.LineAlignment = StringAlignment.Center
      sf.Alignment = StringAlignment.Center
      g.DrawString(text, f, Brushes.Black, r, sf)
    End Using
    g.ResetTransform()
  End Using
End Sub

新结果:

这篇关于计算旋转文字加上边框的坐标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆