protected internal virtual TextString convertToCharacters(string text, Graphics2D g, FontFactory fontFactory, ColorFactory colorFactory)
        {
            TextString        characters = new TextString();
            FontRenderContext frc        = g.getFontRenderContext();
            double            lastx      = 0;

            for (int i = 0; i < text.Length; i++)
            {
                Font          font   = fontFactory.getFont(i);
                char          c      = text[i];
                FontMetrics   fm     = g.getFontMetrics(font);
                Rectangle2D   bounds = font.getStringBounds(Convert.ToString(c), frc);
                TextCharacter tc     = new TextCharacter();
                tc.Character = c;
                tc.Font      = font;
                tc.Width     = fm.charWidth(c);
                tc.Height    = fm.getAscent() + fm.getDescent();
                tc.Ascent    = fm.getAscent();
                tc.Descent   = fm.getDescent();
                tc.X         = lastx;
                tc.Y         = 0;
                tc.Font      = font;
                tc.Color     = colorFactory.getColor(i);
                lastx       += bounds.getWidth();
                characters.addCharacter(tc);
            }
            return(characters);
        }
        public void draw(string text, BufferedImage canvas, FontFactory fontFactory, ColorFactory colorFactory)
        {
            Graphics2D g  = (Graphics2D)canvas.getGraphics();
            TextString ts = convertToCharacters(text, g, fontFactory, colorFactory);

            arrangeCharacters(canvas.getWidth(), canvas.getHeight(), ts);
            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            foreach (TextCharacter tc in ts.Characters)
            {
                g.setColor(tc.Color);
                g.drawString(tc.iterator(), (float)tc.X, (float)tc.Y);
            }
        }
        protected internal override void arrangeCharacters(int width, int height, TextString ts)
        {
            double widthRemaining = (width - ts.Width - leftMargin - rightMargin) / ts.Characters.Count;
            double vmiddle        = height / 2;
            double x = leftMargin + widthRemaining / 2;
            Random r = new Random();

            height -= topMargin + bottomMargin;
            foreach (TextCharacter tc in ts.Characters)
            {
                double heightRemaining = height - tc.Height;
                double y = vmiddle + 0.35 * tc.Ascent + (1 - 2 * r.NextDouble()) * heightRemaining;
                tc.X = x;
                tc.Y = y;
                x   += tc.Width + widthRemaining;
            }
        }
 protected internal abstract void arrangeCharacters(int width, int height, TextString ts);