2012-02-23

Full Justified Texts with GdiPlus-X

 According to Wikipedia, "In typesettingjustification (can also be referred to as 'full justification') is the typographic alignment setting of text or images within a column or "measure" to align along both the left and right margin. Text set this way is said to be "justified".

 

In justified text, the spaces between words, and, to a lesser extent, between glyphs or letters (kerning), are stretched or sometimes compressed in order to make the text align with both the left and right margins. When using justification, it is customary to treat the last line of a paragraph separately by left or right aligning it, depending on the language direction. Lines in which the spaces have been stretched beyond their normal width are called loose lines, while those whose spaces have been compressed are called tight lines."

To create Full-Justified texts, the main point is to know exactly the measures of each word, and to be able to draw each word exactly in a certain position. Unfortunately, VFP does not bring thiese possibilities natively. Yes, I know we have TXTWIDTH and FONTMETRIC(6), but they are not that accurate. A good but not beautiful solution was to use some monospace fonts, like Courier New or Lucida Console, that every character has the same measures.

So, if we wanted to use any fonts, one of the few options was to use the RTF Active-X control, or to use an OLE Word object in a VFP form.

With the GdiPlus-X library, from now on you can also draw Full Justified texts in a very easy way too.

GDI+ originally allows to draw texts in three String Format Alignments: Left, Center and Right. In these last years, I've noticed that it's a very common request from VFP developers the ability to draw texts in FullJustified mode.



To draw Full-Justified strings we need to have the accurate measurements of each of the words in a paragraph, and draw each word individually in a calculated position. Well, no need to say that GDI+ provides the needed tools for the task. So, we added a new method to the Graphics class of the GdiPlus-X library, DRAWSTRINGJUSTIFIED.

Maybe you find that the natural choice would be to add a new StringFormat Alignment fot FullJustifying purposes, and let the method "DrawString" deal with the text and the received parameters and draw. But we believe that the original library, GdiPlus.dll will receive some updates in the future, and MS can possibly include a specific "StringFormat.Alignment" for our case. So, we found the best solution would be to create a new method, with a different name. The usage is very similar to the original "DrawString":

 

MethodDrawStringJustified(tcString, toFont as xfcFont, toBrush as xfcBrush, toRectangle as xfcRectangle)

PARAMETERS

tcStringCharacter, String to Draw
toFontObject, Font that defines the text format of the string.
toBrushObject, Brush that determines the color and texture of the drawn text.
toRectangleObject, Rectangle structure that specifies the location of the drawn text.

 

HOW IT WORKS

Basically, DrawStringJustified receives the 4 parameters above, very similar to DrawString. But intead of drawing the whole text in one time, this function needs to make some calculations in order to know where exactly each word from the string will be drawn. It starts by populating an array of words and the calculated measures of each word, using GdipMeasureString. Then, calculates how many words will fit on each line. Next step is to calculate the resulting space between the words of the related line. After collecting all information needed, we draw each word at a time, at the calculated position.

For maximum performance, we used direct API calls to gdiplus.dll for the main process, measuring and drawing each string. I did some tests, and the difference is huge, about 5 times faster.

VERY IMPORTANT - READ THIS !

All samples below require that you have the latest PLANNED RELEASE, 0.08A. It's a little bit hidden at codeplex, so I'm putting below the link for direct downloading:

http://www.codeplex.com/VFPX/Release/ProjectReleases.aspx?ReleaseId=1711

TIME TO PLAY

1 - Draw Full-Justified strings in image files

The PRG below shows how to draw a text in 4 ways, left, centered, right and full justified, just like the picture above, and saves he image to a file.

** Program: FullJustCode.prg
** Sample program that draws text in 4 modes:
** 1 - Left Aligned
** 2 - Centered
** 3 - Right Aligned
** 4 - Full Justified

* The code performs the following actions:
* Creates a String
* Draws text in 4 modes and shows the results
* Locate and load GdiPlus-X
DO LOCFILE("System.App")
LOCAL lcText AS CHARACTER
TEXT TO m.lcText NOSHOW
GDIPlusX is a set of VFP 9.0 class libraries that wrap the 603 GDI+ Flat API functions of GDIPlus.dll.
The library currently consist of 83 VFP classes and 1,146 methods. The project is still under development so not all classes have been completed and several of the classes/methods are still being tested.
ENDTEXT

WITH _SCREEN.SYSTEM.Drawing

    * Create Image
    LOCAL loBMP AS xfcBitmap
    m.loBMP = .BITMAP.New(400, 600)

    * Create a Graphics object to be able to draw on image
    LOCAL loGfx AS xfcGraphics
    m.loGfx = .Graphics.FromImage(m.loBMP)

    * Fill Image with White Background color
    m.loGfx.CLEAR(.COLOR.White)

    * Create a DarkBlue Brush
    LOCAL loTextBrush AS xfcSolidBrush
    m.loTextBrush = .SolidBrush.New(.COLOR.DarkBlue)

    * Create Font Object
    LOCAL loFont AS xfcFont
    m.loFont = .FONT.New("Tahoma", 11, .FontStyle.Regular)

    * Create a StringFormat object
    LOCAL loStringFormat AS xfcStringFormat
    m.loStringFormat = .StringFormat.New()

    LOCAL lnHeight, lnWidth
    m.lnWidth  = 400
    m.lnHeight = 150

    * Draw Left Aligned Text
    m.loStringFormat.ALIGNMENT = .StringAlignment.NEAR
    m.loGfx.DrawString(m.lcText, m.loFont, m.loTextBrush, ;
          .Rectangle.New(0, 0, m.lnWidth, m.lnHeight), ;
          m.loStringFormat)

    * Draw Centered Text
    m.loStringFormat.ALIGNMENT = .StringAlignment.CENTER
    m.loGfx.DrawString(m.lcText, m.loFont, m.loTextBrush, ;
          .Rectangle.New(0, m.lnHeight + 1, m.lnWidth, m.lnHeight), ;
          m.loStringFormat)

    * Draw Right Aligned Text
    m.loStringFormat.ALIGNMENT = .StringAlignment.Far
    m.loGfx.DrawString(m.lcText, m.loFont, m.loTextBrush, ;
          .Rectangle.New(0, m.lnHeight * 2 + 1, m.lnWidth, m.lnHeight), ;
          m.loStringFormat)

    * Draw Full Justified
    m.loGfx.DrawStringJustified(m.lcText, m.loFont, m.loTextBrush, ;
          .Rectangle.New(0, m.lnHeight * 3 + 1, m.lnWidth, m.lnHeight))

    * Draw a Red Border
    m.loGfx.DrawRectangle(.PEN.New(.COLOR.Red, 1), 0, 0, 399, 599)

    * Save Image to Disk
    m.loBMP.SAVE("c:\TestAlignment.png", .Imaging.ImageFormat.Png)

    * Show Generated Text
    RUN /N explorer.EXE c:\TestAlignment.Png

ENDWITH
RETURN

2 - Draw Full-Justified strings in Forms

The easiest way to draw a Full-Justified string in a form is using the ImageCanvas object. Below is the code that you need to add to the "BeforeDraw" method if the ImgCanvas. In my previous post, Direct Draw with the Image Canvas from GdiPlus-X you'll get a tutorial showing how to work with it, and some tips.

Note that I chose to reduce the code of the GDI+ drawing part, to show that with only two lines of code you can draw your Full-Justified string with the image canvas.


LOCAL lcText AS CHARACTER
TEXT TO m.lcText NOSHOW
GDIPlusX is a set of VFP 9.0 class libraries that wrap the 603 GDI+ Flat API functions of GDIPlus.dll.
The library currently consist of 83 VFP classes and 1,146 methods. The project is still under development so not all classes have been completed and several of the classes/methods are still being tested. The Readme.htm file, included with the download, shows the current coding status of each class. As of August 31, 2006, the overall status of the library is about 97% coded and 60% tested.
ENDTEXT

WITH _SCREEN.SYSTEM.Drawing
    * Fill Image with Background color
    THIS.oGfx.CLEAR(.COLOR.White)

    * Draw the Full-Justified text
    THIS.oGfx.DrawStringJustified(m.lcText, .FONT.New("Tahoma", 12), ;
          .Brushes.Black, THIS.Rectangle)
ENDWITH


In the samples folder of the GdiPlus-X libary you'll find the form "FULLJUSTIFIED.SCX". Don't miss to run it, and play, changing the fonts, sizes, style, alignment type. But, in my opinion the most interesting feature of that sample is that you can resize the form, and the whole image will be redrawn in a flash ! Doing that you'll see how fast this routine works.



 

3 - Draw Full-Justified strings in reports.

This has become very easy too, after the creation of a specific report listener... but I prefer to leave this for my next post.


 

Maybe you have interest in the DRAWSTRINGJUSTIFIED method. To see the code, open the class xfcGraphics from the file Drawing.vcx. Look for the method "DrawStringJustified".

No comments:

Post a Comment