我需要在图像的底部添加半英寸的空白区域,并在左下角和右下角(在新添加的空白区域内)绘制一个字符串。一切似乎工作正常,但字体有时看起来太小或太大。
我想我需要以某种方式将抽绳字体缩放到图像的大小?我已经筋疲力尽,试图解决这个问题......请帮助!!
见下面的代码----
Imports System.IO
Imports System.Drawing.Graphics
Imports System.Drawing
Imports System.Drawing.Bitmap
Imports System.Drawing.Imaging
Public Class Form1
Dim ofilepath As String = "C:\temp\20141022\TEST0000001.tif"
Dim nfilepath As String = "C:\temp\20141022\new.tif"
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim newbm As New Bitmap(AddBorderAndStamp(Bitmap.FromFile(ofilepath), Color.White, 50, Path.GetFileNameWithoutExtension(ofilepath), "CONFIDENTIAL"))
newbm.Save(nfilepath, Imaging.ImageFormat.Tiff)
Me.Close()
End Sub
Public Function AddBorderAndStamp(ByVal bm As Bitmap, ByVal borderColor As System.Drawing.Color, ByVal borderWidthInPixels As Integer, ByVal bates As String, ByVal designation As String) As Bitmap
Dim voffset As Integer = 75
Dim hoffset As Integer = 15
Dim newBitmap As New Bitmap(bm.Width, bm.Height + (borderWidthInPixels * 2))
Dim mfont As Font = New Font("Arial", 32, FontStyle.Bold)
For x As Integer = 0 To newBitmap.Width - 1
For y As Integer = newBitmap.Height - 1 To (newBitmap.Height - 1) - borderWidthInPixels Step -1
newBitmap.SetPixel(x, y, borderColor)
Next
Next
Dim gr As System.Drawing.Graphics = Graphics.FromImage(newBitmap)
gr.Clear(Color.White)
gr.DrawImage(bm, 0, 0, bm.Width, bm.Height)
Dim textSize As SizeF = gr.MeasureString(bates, mfont)
gr.DrawString(bates, mfont, Brushes.Black, bm.Width - textSize.Width - hoffset, newBitmap.Height - voffset)
gr.DrawString(designation, mfont, Brushes.Black, hoffset, newBitmap.Height - voffset)
gr.Dispose()
Return newBitmap
End Function
End Class
答案 0 :(得分:0)
如果您想知道此行bates
字符串的大小(宽度):
Dim textSize As SizeF = gr.MeasureString(bates, mfont)
在将位图绘制到位图上之前,您必须计算要在font size
上执行的缩放,以确保文本缩小(如果太长)或拉伸(如果太窄)虽然没有过度拉伸高度 - 意味着要在图像上绘制。
然后, 只有当您拥有有效的字体 时,才能像使用以下行一样绘制文字
gr.DrawString(bates, mfont, Brushes.Black, bm.Width - textSize.Width - hoffset, newBitmap.Height - voffset)
gr.DrawString(designation, mfont, Brushes.Black, hoffset, newBitmap.Height - voffset)
要了解要使用的字体大小,请查看this SO Question Page 我知道它是C#,但这基本上是你在绘制贝茨和指定文字之前必须做的事情。区别在于两点:
String
缩放在一个剪辑矩形(bates和指定)而不是一个。designation
和右侧bates
之间的(默认)分隔。但这两点可以很容易地解决。这也意味着您的问题可能重复(StackOverflow不推荐同一问题的多个变体,因为SO 的目的 直接将您带到一个问题和答案的页面 - 如果已经回答 - 但是不要用相同主题的数十个副本充斥您的身份)
但恕我直言,两个字符串(名称和贝茨)足以将此视为一个新问题,因为其他主题未涵盖的代码处理。
saeed的功能转换为vb.Net
Private Function FindFont( _
ByRef rg As Graphics, _
ByVal testString as String, _
ByVal clipRoom As Size, _
ByVal preferedFont As Font) As Font
' You should perform some scale functions...
Dim realSize As SizeF = rg.MeasureString(testString, PreferedFont)
Dim heightScaleRatio As Double = clipRoom.Height / realSize.Height
Dim widthScaleRatio As Double = clipRoom.Width / realSize.Width
Dim scaleRatio As Double
Dim newFontSize As Single ' I'm used to declare everything on top.
If heightScaleRatio < widthScaleRatio Then
scaleRatio = heightScaleRatio
Else
scaleRatio = widthScaleRatio
End If
newFontSize = CSng(preferedFont.Size * ScaleRatio)
Return New Font(preferedFont.FontFamily, newFontSize, preferedFont.Style)
End Function
为了提供代码,Credits首先使用saeed,但如果saeed使用了我不知道的其他人的代码,原作者的信用将取代saeed&#39>。 < / p>
该功能的必要参数是:
rg As Graphics
。您已经拥有它,即rg
功能中的AddBorderAndStamp
。testString As String
。你也拥有它,它只是testString = designation + bates
clipRoom As Size
。你还没有那个变量。您必须在AddBorderAndStamp
函数中声明它,并使用一些逻辑来定义其.Width
和.Height
值。preferedFont As Font
。你也已经有了,mfont As Font = New Font("Arial", 32, FontStyle.Bold)
要添加到AddBorderAndStamp
功能的声明是:
Dim clipRoom As Size ' Declare it.
Dim stampSeparation As Integer = 80 ' why 80 ? dunno ! it's an arbitrary value..
stampSeparation是一个任意变量,表示宽度IN 指定和贝茨之间的PIXEL。基本上,它看起来像这样:
'< - - - - - - - total Bitmap width - - - - - - - >
'| |designation|_____________|bates| |
'| | | | | ^ Right Image boder
'| | | | ^ Right margin
'| | | ^ Left plot of your bates String
'| | <-------------> Length or Width of stampSeparation
'| ^ Left plot of your designation String
'^ Left image border
您的可用空间来写文字是
的总和但是因为你想要通过stampSeparation分隔指定和bates beeing, stampSeparation必须从可用的剪辑宽度中减去。所以:
clipRoom.Width = newBitmap.Width - (hOffset * 2) - stampSeparation
' newBitmap.Width - 30 - 80
' newBitmap.Width - 110
' CAREFULL !!! clipRoom.Width MUST be positive !!!
' Check your bm is wide enough, say at least 200 pixels Width...
您在底部的房间是一个不同的故事:您的AddBorderAndStamp
函数有一个borderWidthInPixels
(作为整数)参数,用于定义您在顶部/底部平均值添加的房间。然后使用voffset
(作为整数)变量将图章向上移动..这意味着您在图像底部的高度可用空间来绘制文本:
clipRoom.Height = vOffset ' ?
' 75 ?
' (CAREFULL !!! clipRoom.Height MUST be positive !!!)
如果我是你,我会根据clipRoom.Height
的一小部分动态定义AddBorderAndStamp
,并在之后动态计算vOffset
使用designation
知道bates
和MeasureString
高度的最终高度......但那将是一种过度杀伤......
' perhaps one simple logic like the following would suffice
' clipRoom.Height = CInt(vOffset * 4 / 5)
现在您有clipRoom
以及调用FindFont(...)
功能所需的所有其他内容。
Public Function AddBorderAndStamp(...) As Bitmap
' Dim vOffset ' ...
' Dim hOffset ' ...
' ...
' add the following declarations :
Dim clipRoom As Size
Dim stampSeparation As Integer = 80 ' or 60 as you like but small enough
' ...
' ... your function block code goes here until the following line :
gr.DrawImage(bm, 0, 0, bm.Width, bm.Height)
' Calculate the available clip room...
clipRoom.Width = newBitmap.Width - (hOffset * 2) - stampSeparation
clipRoom.Height = vOffset
' ^^ remember : the logic to handle valid Width and Height is up to you
' I know how to handle that, but you should aswell, or try at least.
' Now, update the size of your font...
mFont = FindFont(rg, designation + bates, clipRoom, mFont)
' then continue with the rest of the code...
Dim textSize As SizeF = gr.MeasureString(bates, mfont)
gr.DrawString(bates, mfont, Brushes.Black, bm.Width - textSize.Width - hoffset, newBitmap.Height - voffset)
gr.DrawString(designation, mfont, Brushes.Black, hoffset, newBitmap.Height - voffset)
gr.Dispose()
Return newBitmap
End Function
顺便说一下:
您好。您应该在帖子中添加
[vb.Net]
标记,然后移除[image]
或[bitmap]
,因为这些是同义词。
如果没有格式化,很难发现代码拼写错误。但是,由于你是StackOverflow(SO)的新手,我不想向你投票或标记你,但我坚持:更新你问题的标签。
备注1:
您写道:
For x As Integer = 0 To newBitmap.Width - 1
For y As Integer = newBitmap.Height - 1 To (newBitmap.Height - 1) - borderWidthInPixels Step -1
newBitmap.SetPixel(x, y, borderColor)
Next
Next
Dim gr As System.Drawing.Graphics = Graphics.FromImage(newBitmap)
gr.Clear(Color.White)
您从底部逐个像素地更改newBitmap
的颜色。我没关系,但有更好的方法来实现这一点。
但是,你要声明一个Graphics来处理newBitmap上的绘图,然后你调用gr.Clear(Color.White)
???
是不是 完全 用白色绘制你的newBitmap,从而破坏了上面的SetPixel循环的目的?
我不明白。也许你希望这个功能浪费时间,所以只需使用
System.Threading.Thread.Sleep(X) ' where X is an Integer variable in miliseconds
否则,我建议你摆脱SetPixel及其包围For循环,然后使用你的gr Graphics填充一个Rectangle:
' ...
Dim gr As System.Drawing.Graphics = Graphics.FromImage(newBitmap)
gr.Clear(Color.White)
gr.FillRectangle( _
New SolidBrush(borderColor), _
0, newBitmap.Height - borderWidthInPixels, _
newBitmap.Width, borderWidthInPixels)
gr.DrawImage(bm, 0, 0, bm.Width, bm.Height)
' ...
备注2:
' you've set newBitmap to have
' bm.Heigth expanded by two times the value of borderWidthInPixels
Dim newBitmap As New Bitmap(bm.Width, bm.Height + (borderWidthInPixels * 2))
' ...
' Then you plot bm at the very top of newBitmap
gr.DrawImage(bm, 0, 0, bm.Width, bm.Height)
' that means you have a blank space at the bottom
' that height twice the value of borderWidthInPixels
' ...
' But you plot bates and designation
' at a fixed vOffset from the bottom of newBitmap
gr.DrawString(bates, , , , newBitmap.Height - voffset)
gr.DrawString(designation, , , , newBitmap.Height - voffset)
borderWidthInPixels
和voffset
之间的关系对我来说仍然不清楚,这可能会误导上述clipRoom.Height
的表述。
但是,我认为我已经给出了足够的材料来帮助你,即使上面的clipRoom.Height公式错误,也很容易修复它。
你还必须明白我默认使用 saeed 方法,但是通过阅读我链接的帖子,你会发现其他方法,迭代方法,我不会这样做很多因为它们是迭代 CPU重而不总是更精确。你甚至可以找到关于TextToBitmap的提示;尝试更适合你,但它也更复杂..对于你正在做的事情,我认为一个或两个像素取代输出不是问题。
对于垂直展示位置,您说&#34; ..但有时候字体看起来太小或太大了。&#34; 这不够准确全面了解这个问题。您应该发布&#34;太小&#34; 案例和&#34;太大&#34; 案例的两个图像样本。由于您没有更改代码中的字体大小,我认为太小问题是指定和bates之间的空间太大,太大重叠文本。没有一个参考可能的垂直布局问题,所以我的答案并没有详细阐述。这就是为什么我不在这里引入多线逻辑,这将代表另一个问题(如果没有可用的话)