【发布时间】:2014-05-25 23:10:16
【问题描述】:
我有一个表单,允许用户创建自定义“图章”以放置在 PDF 上。表单显示 pdf 第一页的图像,我希望用户基本上点击他们想要印章的屏幕,并能够预览它的外观。不用担心任何 PDF 的东西,我已经处理好了。
为了让事情变得时髦,我有两个图像副本,一个是正常的,一个是亮度降低的。我显示低亮度图像,当用户将鼠标移到上方时,会显示或突出显示原始图像的一大块。然后我在该区域显示用户将要放在 PDF 上的文本。
我允许用户使用鼠标滚轮滚动和更改他们放置的文本的角度(从 -45 度到 +45 度)。
这是我的问题:我无法计算正确的矩形/坐标。有时一切看起来都很棒,有时(随着字体大小的变化)它们不太合适。
如何计算 x 和 y 坐标: 旋转文本的位置 和一个边界矩形,以 10px 的宽度和高度填充文本
下面的代码有效,直到我开始增加字体大小,然后一切都变得不倾斜了。
前两张图片以较小的字体显示文本 + 边框。看起来不错:
下一张图片显示,随着文本大小变大,我的像素四处移动并被切掉。在更大的文本中,宽度/高度也会偏离。
抱歉,示例图片没有显示太多细节。我有无法分享的实际数据。
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
在绘画方面我不是最棒的。所以任何帮助都会很棒
使用@LarsTech 提供的以下解决方案。我将 g.FillRectangle 替换为:
g.DrawImage(_curImg, r, r, GraphicsUnit.Pixel)
_curImg 是调整了亮度的原始图像的副本。当我从下面更改代码时,我最终得到:
注意双线。它们与图章一起旋转,即使它们充当背景图像并且应该不旋转
根据建议,我将 DrawStamp 从 @LarsTech 更改为以下内容:
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
但是,我现在只剩下
注意它绘制了背景,然后进行了旋转并绘制了图章。它几乎可以工作。在这个例子中,直线显示了预期的行为......但是我希望用背景填充整个图章。两侧多余的白色将被旋转到邮票的背景中。我很困惑,因为我会怀疑“灰色”部分会剪掉图像的一部分,但它们不是(如果我将它移到我不幸无法在此处发布的其他区域)通知已超出倾斜,除了矩形的边是这样绘制的。
希望有更多信息的另一个编辑
希望这里能更好地解释我正在尝试做的事情。我使用第三方 PDF 查看器,我需要允许用户将图像添加到 PDF。查看器不允许我在其上引发点击事件,因此为了获取用户鼠标点击,我执行以下操作:
- 获取表单的屏幕截图
- 隐藏 PDF 查看器
- 向我的表单添加一个 PictureBox 控件,替换 PDF 查看器所在的区域
- 通过屏幕抓取,我制作了降低亮度的图像副本
- 显示图像的灰度副本并使用图片框上的鼠标悬停事件直接在图像上绘图
- 我在图片框上画了一个图章,但希望它的背景是原始的(未调整亮度的图像)。但是,由于该区域可能会使用旋转进行转换,因此我无法抓取背景图像。如果未提供角度,则源矩形匹配。但是,如果它旋转,我无法从源图像中抓取相同的旋转矩形。
按钮点击事件:
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 是我的原始屏幕抓取。
_curGray: _curImg:
mouseMove 移动事件应用于我的新图片框。这就是问题前面的所有代码发挥作用的地方。
使用上面的代码,我的 mouseMove 事件不断创建一个新图像以显示在我的图片框中。如果不涉及轮换,我会得到我想要的东西。请注意下图中邮票的背景是如何比一切都亮的。蓝色方块上方的部分稍浅。我正在使用这种方式来吸引观众注意这个区域......这对我正在做的事情很重要。
但是,当对其应用旋转时,我似乎无法从原始图像中复制。看下图,背景没有随它旋转。我需要从原始图像中抓取一个旋转的矩形。
http://msdn.microsoft.com/en-us/library/ms142040(v=vs.110).aspxGraphics.DrawImage() 接受
Public Sub DrawImage ( _
image As Image, _
destRect As Rectangle, _
srcRect As Rectangle, _
srcUnit As GraphicsUnit _
)
我可以指定从我的源图像(在本例中为 _curImg)复制此源矩形并放置到我的新绘图上。它不允许我对源矩形应用转换。基本上我想从我的源图像中复制一个相当于旋转矩形的区域(基于@larstech 的转换)
我不知道如何更清楚地表达这个概念。如果仍然没有意义,我将接受 LarsTech 的答案作为最佳答案并放弃我的想法。
【问题讨论】:
-
您可以变换矩形的点。新矩形(围绕旋转的文本)具有所有 X 的 x=min,所有 Y 的 y=min,width=maxX-minX 和 height=maxY-minY
标签: vb.net winforms .net-4.5 system.drawing