Welcome Guest! You need to login or register to make posts.

Notification

Icon
Error

Options
Go to last post Go to first unread
vmrocha  
#1 Posted : Tuesday, August 30, 2016 11:46:01 AM(UTC)
vmrocha

Rank: Member

Groups: Member
Joined: 1/10/2016(UTC)
Posts: 15

Thanks: 7 times
I'm trying to write program using GraphicsMill that will generate a PDF with a specific size. What is the best way to draw an ArtText that will fill the maximum area available as possible without having to stretch it? I'm trying to guess what is the best font size doing an exhaustive search for the font size starting on 1. That's not efficient at all and can take a lot of time depending on the target size. Do you have something to recommend?

Code:

Imports Aurigma.GraphicsMill
Imports Aurigma.GraphicsMill.AdvancedDrawing
Imports Aurigma.GraphicsMill.AdvancedDrawing.Art
Imports Aurigma.GraphicsMill.AdvancedDrawing.Effects
Imports Aurigma.GraphicsMill.Codecs
Imports DPointF = System.Drawing.PointF
Imports DRectangleF = System.Drawing.RectangleF

   (...)

    Private Shared Sub UpdateFontSize(options As WarpedTextOptions, graphics As Graphics, targetRect As DRectangleF)

        Dim unionBlackbox As New DRectangleF
        Dim targetRectPixels As New DRectangleF(
                    UnitConverter.ConvertUnitsToPixels(options.DPI, targetRect.X, Unit.Point),
                    UnitConverter.ConvertUnitsToPixels(options.DPI, targetRect.Y, Unit.Point),
                    UnitConverter.ConvertUnitsToPixels(options.DPI, targetRect.Width, Unit.Point),
                    UnitConverter.ConvertUnitsToPixels(options.DPI, targetRect.Height, Unit.Point))

        options.TextFontSize = 1

        Do
            options.TextFontSize = options.TextFontSize + 1

            Dim artText = GetArtText(options, graphics)
            Dim textBlackBox = artText.GetBlackBox()

            Dim shadowBlackbox As New DRectangleF(textBlackBox.Location, textBlackBox.Size)
            shadowBlackbox.Inflate(options.Shadow.SizePixels, options.Shadow.SizePixels)
            shadowBlackbox.Offset(options.Shadow.OffsetXPixels, options.Shadow.OffsetYPixels)

            unionBlackbox = DRectangleF.Union(textBlackBox, shadowBlackbox)

        Loop While unionBlackbox.Width < targetRectPixels.Width AndAlso unionBlackbox.Height < targetRectPixels.Height

        options.TextFontSize = options.TextFontSize - 1

    End Sub

   (...)
vmrocha  
#2 Posted : Tuesday, August 30, 2016 12:34:22 PM(UTC)
vmrocha

Rank: Member

Groups: Member
Joined: 1/10/2016(UTC)
Posts: 15

Thanks: 7 times
As suggested by a friend of mine, I refactored the code to use binary search, that increased the performance from seconds to milliseconds.

Does anyone see any problem on using the max value as the targetRect height.

Code:

Imports Aurigma.GraphicsMill
Imports Aurigma.GraphicsMill.AdvancedDrawing
Imports Aurigma.GraphicsMill.AdvancedDrawing.Art
Imports Aurigma.GraphicsMill.AdvancedDrawing.Effects
Imports Aurigma.GraphicsMill.Codecs
Imports DPointF = System.Drawing.PointF
Imports DRectangleF = System.Drawing.RectangleF

   (...)

    Private Shared Sub UpdateFontSize(
        options As WarpedTextOptions, graphics As Graphics, targetRect As DRectangleF)

        Dim unionBlackbox As New DRectangleF
        Dim targetRectPixels As New DRectangleF(
                    UnitConverter.ConvertUnitsToPixels(options.DPI, targetRect.X, Unit.Point),
                    UnitConverter.ConvertUnitsToPixels(options.DPI, targetRect.Y, Unit.Point),
                    UnitConverter.ConvertUnitsToPixels(options.DPI, targetRect.Width, Unit.Point),
                    UnitConverter.ConvertUnitsToPixels(options.DPI, targetRect.Height, Unit.Point))

        Dim min = MIN_FONT_SIZE
        Dim max = targetRect.Height

        options.TextFontSize = min

        While min < max

            Dim mid As Integer = CInt((min + max) / 2)
            options.TextFontSize = mid

            Dim artText = GetArtText(options, graphics)
            Dim textBlackBox = artText.GetBlackBox()

            Dim shadowBlackbox As New DRectangleF(textBlackBox.Location, textBlackBox.Size)
            shadowBlackbox.Inflate(options.Shadow.SizePixels, options.Shadow.SizePixels)
            shadowBlackbox.Offset(options.Shadow.OffsetXPixels, options.Shadow.OffsetYPixels)

            unionBlackbox = DRectangleF.Union(textBlackBox, shadowBlackbox)
            If (unionBlackbox.Width < targetRectPixels.Width AndAlso
                unionBlackbox.Height < targetRectPixels.Height) Then
                min = mid + 1
            Else
                max = mid - 1
            End If

        End While

    End Sub

   (...)

Edited by user Tuesday, August 30, 2016 4:11:31 PM(UTC)  | Reason: typo

Fedor  
#3 Posted : Wednesday, August 31, 2016 3:29:20 AM(UTC)
Fedor

Rank: Advanced Member

Groups: Member, Administration, Moderator
Joined: 7/28/2003(UTC)
Posts: 1,556

Thanks: 5 times
Was thanked: 62 time(s) in 61 post(s)
Hi,

Here is my code review.

Code:
	Private Shared Sub UpdateFontSize(
		options As WarpedTextOptions, graphics As Graphics, targetRect As DRectangleF)

		Dim unionBlackbox As New DRectangleF
		Dim targetRectPixels As New DRectangleF(
					UnitConverter.ConvertUnitsToPixels(options.DPI, targetRect.X, Unit.Point),
					UnitConverter.ConvertUnitsToPixels(options.DPI, targetRect.Y, Unit.Point),
					UnitConverter.ConvertUnitsToPixels(options.DPI, targetRect.Width, Unit.Point),
					UnitConverter.ConvertUnitsToPixels(options.DPI, targetRect.Height, Unit.Point))

		'Dim min = MIN_FONT_SIZE
		' 1. The maximum size of inscribed figure is a diagonal of a rectangle
		' 2. Use a font size of the float (Single) type. Otherwise you can get an inaccurate result
		Dim max As Single = System.Math.Sqrt(targetRect.Height * targetRect.Height + targetRect.Width * targetRect.Width)
		'Dim max = targetRect.Height
		Dim max As Single = targetRect.Height

		'options.TextFontSize = min

		' 3. Limit an iteration count to prevent hanging
		Const MAX_ITERATIONS As Integer = 20
		Dim i = 0

		'While min < max
		' 4. Use a condition based on precison
		Const PRECISION As Single = 0.05F

		While (max - min) / max > PRECISION AndAlso i < MAX_ITERATIONS

			' Dim mid As Integer = CInt((min + max) / 2)
			' See p. 2
			Dim mid As Single = CSng((min + max) / 2.0F)

			options.TextFontSize = mid

			Dim artText = GetArtText(options, graphics)
			Dim textBlackBox = artText.GetBlackBox()

			Dim shadowBlackbox As New DRectangleF(textBlackBox.Location, textBlackBox.Size)
			shadowBlackbox.Inflate(options.Shadow.SizePixels, options.Shadow.SizePixels)
			shadowBlackbox.Offset(options.Shadow.OffsetXPixels, options.Shadow.OffsetYPixels)

			unionBlackbox = DRectangleF.Union(textBlackBox, shadowBlackbox)

			' 5. There is no need to increment/decrement the mid value:
			If (unionBlackbox.Width < targetRectPixels.Width AndAlso
				unionBlackbox.Height < targetRectPixels.Height) Then
				'min = mid + 1
				min = mid
			Else
				'max = mid - 1
				max = mid
			End If

			i = i + 1
		End While

	End Sub


Please be advised that the code is untested.

Edited by user Wednesday, August 31, 2016 3:30:18 AM(UTC)  | Reason: Not specified

Best regards,
Fedor Skvortsov
thanks 1 user thanked Fedor for this useful post.
vmrocha on 8/31/2016(UTC)
vmrocha  
#4 Posted : Wednesday, August 31, 2016 8:22:27 AM(UTC)
vmrocha

Rank: Member

Groups: Member
Joined: 1/10/2016(UTC)
Posts: 15

Thanks: 7 times
Hi Fedor, why the max font size should be the max size of the inscribed figure (diagonal)?
Fedor  
#5 Posted : Tuesday, December 20, 2016 9:48:09 PM(UTC)
Fedor

Rank: Advanced Member

Groups: Member, Administration, Moderator
Joined: 7/28/2003(UTC)
Posts: 1,556

Thanks: 5 times
Was thanked: 62 time(s) in 61 post(s)
Please see the attached image:

font-size.png
Best regards,
Fedor Skvortsov
Users browsing this topic
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.