9 Replies Latest reply on May 26, 2017 12:01 PM by Robert Wiley

    Calculate Width of Scalable Font

    Craig Anderson

      I am using font 0 (zero) and cannot figure out how I can pre-determine whether a given font size and phrase will be too long for the badges that I am printing.

       

      A good example can be seen here:

       

      http://labelary.com/viewer.html?density=8&width=4&height=3&units=inches&index=0&zpl=%5EXA%0A%5EXA%0A%5ECF0%2C0%2C0%0A%5E…

       

      Both words are 13 characters long and both have the same font size for height and width - but the "MASSACHUSETTS" line is too long.

       

      Is there a way to calculate, ahead of time (meaning before I send the ZPL code to the printer) the total width of Zebra Font 0 with given text and font size?

        • Re: Calculate Width of Scalable Font
          Craig Anderson

          I can't imagine I'm the only person who needs to do this?

            • Re: Calculate Width of Scalable Font
              Robin West

              Hi Craig,

              You are not, but we don't really have a good answer for you.  Fonts are much more complicated than most people realize.  Determining the printed width of a string using a scaleable font essentially requires using a font engine to actually create the bitmap and size it.  I can see if we can get you more info on font 0 specifically, but you will essentially have to calculate the width character by character.  It would be easier to use a monospace scaleable font like "Courier New".  Unfortunately we only have monospcace bitmap fonts, which are not fully scalable by default on the printer. 

              We do have a few essentially for free.  Let me know if you want one.  You can also convert several of the free Google fonts for use in our printers.

                • Re: Calculate Width of Scalable Font
                  Craig Anderson

                  Thanks for getting back to me Robyn. The Internet basically has nothing on anything like this, so you're my last hope.

                   

                  If you could get me more information on font 0 specifically, that would be great yes.

                   

                  A prior developer that worked for a client of mine 15+ years ago, developed a solution that I'd like to run by you. I believe that it works similar to what you outlined - by calculating the width character by character. What I'm unsure of, however, is whether the base widths that he used are accurate (or where they even came from). A few quick example base widths:

                  • !: 2602
                  • #: 4228
                  • 0: 4228
                  • 1: 4228
                  • 2: 4228
                  • 3: 4228
                  • A: 4879
                  • G: 5204
                  • ~: 8782
                  • <: 87872

                   

                  Does this look familiar to you at all?

                   

                  For each character in the text to be printed, it takes the base width and divides it by 8782 (what appears to be the maximum character width) and then multiplies that by the desired font size. It then adds up all calculated character widths and sees if it will fit in the maximum width of the available printing area. If it doesn't fit, it starts the whole process over again, decrementing the desired font width by one.

                   

                  It's not perfect, as I've found several scenarios where the calculation result is less than the maximum width - but the printed result ends up too long (and overlaps). If I use 770 for my maximum width instead of the actual 800 - it seems to work fine. But the whole solution feels held together with glue, and I don't love that I have no idea where those character widths came from.

                   

                  Any insight on this solution, or another direction that I might go in, that you can provide would be greatly appreciated.

                    • Re: Calculate Width of Scalable Font
                      Robin West

                      Hi Craig,

                      Sorry, I don't recognize the reference for those numbers.

                      I'll see what I can find, but until then, here are some articles you might find interesting:

                      Calculate Character Widths

                      Variable-width Fonts

                      Most of our printers print at 8 dots per mm.  ZPL takes font sizes in dots, not points.

                        • Re: Calculate Width of Scalable Font
                          Craig Anderson

                          Were you able to find anything?

                          • Re: Calculate Width of Scalable Font
                            Craig Anderson

                            Checking in again, any luck?

                              • Re: Calculate Width of Scalable Font
                                Robert Wiley

                                I created a set of subroutines in VB.NET that calculates the length of a string for font 0. I printed all the characters out at 72 points and physically measured the distance each one occupies. These values are converted to printer dots for a 300 DPI printer and saved into a hash table similar to what you've described. The ASCII character code for each character is the key for the hash table.

                                 

                                The first VB.NET subroutine loads the hash table.

                                 

                                The second subroutine returns the length of a string in dots at a 72-point font size on a 300 DPI printer

                                 

                                The third subroutine returns a font size that is less than or equal to a given font size that will fit into a given area. It requires an array of text such as what would be placed into a field block (^FB)

                                 

                                Hope this helps in some way. I have looked for a better solution but haven't had any luck at all. The data in the hash table isn't perfect but it's worked out very well for my needs.

                                 

                                My VB.NET code follow:

                                 

                                Public gintHash(125) As Integer

                                 

                                Sub LoadHash()

                                        gintHash(32) = 305

                                        gintHash(33) = 287

                                        gintHash(34) = 471

                                        gintHash(35) = 471

                                        gintHash(36) = 471

                                        gintHash(37) = 890

                                        gintHash(38) = 598

                                        gintHash(39) = 287

                                        gintHash(40) = 293

                                        gintHash(41) = 293

                                        gintHash(42) = 471

                                        gintHash(43) = 847

                                        gintHash(44) = 325

                                        gintHash(45) = 1500

                                        gintHash(46) = 293

                                        gintHash(47) = 293

                                        gintHash(48) = 480

                                        gintHash(49) = 480

                                        gintHash(50) = 480

                                        gintHash(51) = 480

                                        gintHash(52) = 480

                                        gintHash(53) = 480

                                        gintHash(54) = 480

                                        gintHash(55) = 480

                                        gintHash(56) = 480

                                        gintHash(57) = 480

                                        gintHash(58) = 293

                                        gintHash(59) = 293

                                        gintHash(60) = 986

                                        gintHash(61) = 890

                                        gintHash(62) = 986

                                        gintHash(63) = 432

                                        gintHash(64) = 890

                                        gintHash(65) = 547

                                        gintHash(66) = 547

                                        gintHash(67) = 527

                                        gintHash(68) = 585

                                        gintHash(69) = 489

                                        gintHash(70) = 515

                                        gintHash(71) = 585

                                        gintHash(72) = 598

                                        gintHash(73) = 267

                                        gintHash(74) = 432

                                        gintHash(75) = 547

                                        gintHash(76) = 471

                                        gintHash(77) = 742

                                        gintHash(78) = 598

                                        gintHash(79) = 560

                                        gintHash(80) = 547

                                        gintHash(81) = 560

                                        gintHash(82) = 585

                                        gintHash(83) = 522

                                        gintHash(84) = 489

                                        gintHash(85) = 598

                                        gintHash(86) = 522

                                        gintHash(87) = 795

                                        gintHash(88) = 547

                                        gintHash(89) = 547

                                        gintHash(90) = 489

                                        gintHash(92) = 293

                                        gintHash(97) = 452

                                        gintHash(98) = 489

                                        gintHash(99) = 432

                                        gintHash(100) = 489

                                        gintHash(101) = 470

                                        gintHash(102) = 274

                                        gintHash(103) = 489

                                        gintHash(104) = 489

                                        gintHash(105) = 254

                                        gintHash(106) = 254

                                        gintHash(107) = 432

                                        gintHash(108) = 254

                                        gintHash(109) = 742

                                        gintHash(110) = 489

                                        gintHash(111) = 471

                                        gintHash(112) = 489

                                        gintHash(113) = 489

                                        gintHash(114) = 325

                                        gintHash(115) = 420

                                        gintHash(116) = 267

                                        gintHash(117) = 489

                                        gintHash(118) = 432

                                        gintHash(119) = 657

                                        gintHash(120) = 432

                                        gintHash(121) = 432

                                        gintHash(122) = 381

                                        gintHash(123) = 489

                                        gintHash(124) = 489

                                        gintHash(125) = 489

                                End Sub

                                 

                                Function intStringLen(strText As String) As Integer

                                        Dim intI As Integer

                                        Dim intLength As Integer = 0

                                        Dim intChrCode As Integer

                                        Dim intTotalLength As Integer

                                        ' function returns the total length of the string in printer dots for a font of 72 points (300 dots)

                                        Try

                                            If strText = "" Then Return 0

                                            intTotalLength = Len(strText)

                                            For intI = 1 To intTotalLength

                                                intChrCode = Asc(Mid(strText, intI, 1))

                                                Select Case intChrCode

                                                    Case 32 To 125

                                                        intLength += gintHash(intChrCode)

                                                    Case Else

                                                        intLength += 833

                                                End Select

                                            Next 'intI

                                            Return intLength

                                        Catch ex As Exception

                                            'Catch errors here

                                        End Try

                                        Return intLength

                                End Function

                                 

                                Function strFontWidth(strTextArray() As String, intPrintArea As Integer, StrCurrentFontWidth As String) As String

                                        Dim intBase As Integer

                                        Dim intLength As Integer

                                        Dim intMaxLength As Integer = 0

                                        Dim intCurrentFontWidth As Integer

                                        Dim intJ As Integer

                                        Dim intMinBound As Integer

                                        Dim intMaxBound As Integer

                                        ' Function returns the largest font width that will fit in a given print area that is no larger than the current font width

                                        Try

                                            intBase = intPrintArea  * 1000    'print area in printer dots * thousandths of an inch

                                            intCurrentFontWidth = Val(StrCurrentFontWidth)

                                            intMinBound = LBound(strTextArray)

                                            intMaxBound = UBound(strTextArray)

                                            For intJ = intMinBound To intMaxBound

                                                intLength = intStringLen(strTextArray(intJ))

                                                If intLength > intMaxLength Then

                                                    intMaxLength = intLength

                                                End If

                                            Next

                                            intLength = intBase \ intMaxLength

                                            If intLength > intCurrentFontWidth Then intLength = intCurrentFontWidth

                                            Return Trim(Str(intLength))

                                        Catch ex As Exception

                                            'Catch errors here

                                        End Try

                                        Return Trim(Str(intLength))

                                End Function

                                  • Re: Calculate Width of Scalable Font
                                    Craig Anderson

                                    First, thanks for replying here. It's nice, if nothing else, to know that I'm not the only person who struggles with this problem.

                                     

                                    You said that you printed all the characters at 72 points and physically measured them - sorry if this is a dumb question, but what did you use for measurement?

                                      • Re: Calculate Width of Scalable Font
                                        Robert Wiley

                                        I measured them with a small steel ruler. At 72 points (300 printer dots) the characters were large enough to measure fairly close. Granted my process wasn't perfectly accurate and I have not accounted for the variable kerning between various characters but it seems to be within about +-5%. I use these routines to fit text on a lot of labels and to place a registered trademark symbol at the end of different lines of text. In areas where maximum font size is critical I usually drop the font size by a dot or decrease the print area by 5%.