private static void DrawString(PageText pt, Graphics g, RectangleF r, CanvasProperties cp, PageItemManager cpim)
        {
            StyleInfo si = pt.SI;
            string    s  = pt.Text;

            Font         drawFont   = null;
            StringFormat drawFormat = null;
            Brush        drawBrush  = null;

            try
            {
                // STYLE
                System.Drawing.FontStyle fs = 0;
                if (si.FontStyle == FontStyleEnum.Italic)
                {
                    fs |= System.Drawing.FontStyle.Italic;
                }

                switch (si.TextDecoration)
                {
                case TextDecorationEnum.Underline:
                    fs |= System.Drawing.FontStyle.Underline;
                    break;

                case TextDecorationEnum.LineThrough:
                    fs |= System.Drawing.FontStyle.Strikeout;
                    break;

                case TextDecorationEnum.Overline:
                case TextDecorationEnum.None:
                    break;
                }

                // WEIGHT
                switch (si.FontWeight)
                {
                case FontWeightEnum.Bold:
                case FontWeightEnum.Bolder:
                case FontWeightEnum.W500:
                case FontWeightEnum.W600:
                case FontWeightEnum.W700:
                case FontWeightEnum.W800:
                case FontWeightEnum.W900:
                    fs |= System.Drawing.FontStyle.Bold;
                    break;

                default:
                    break;
                }
                try
                {
                    drawFont = new Font(si.GetFontFamily(), si.FontSize, fs);   // si.FontSize already in points
                }
                catch (ArgumentException)
                {
                    drawFont = new Font("Arial", si.FontSize, fs);      // if this fails we'll let the error pass thru
                }
                // ALIGNMENT
                drawFormat = new StringFormat();
                switch (si.TextAlign)
                {
                case TextAlignEnum.Right:
                    drawFormat.Alignment = StringAlignment.Far;
                    break;

                case TextAlignEnum.Center:
                    drawFormat.Alignment = StringAlignment.Center;
                    break;

                case TextAlignEnum.Left:
                default:
                    drawFormat.Alignment = StringAlignment.Near;
                    break;
                }
                if (pt.SI.WritingMode == WritingModeEnum.tb_rl)
                {
                    drawFormat.FormatFlags |= StringFormatFlags.DirectionRightToLeft;
                    drawFormat.FormatFlags |= StringFormatFlags.DirectionVertical;
                }
                switch (si.VerticalAlign)
                {
                case VerticalAlignEnum.Bottom:
                    drawFormat.LineAlignment = StringAlignment.Far;
                    break;

                case VerticalAlignEnum.Middle:
                    drawFormat.LineAlignment = StringAlignment.Center;
                    break;

                case VerticalAlignEnum.Top:
                default:
                    drawFormat.LineAlignment = StringAlignment.Near;
                    break;
                }
                // draw the background
                DrawBackground(g, r, si);

                // adjust drawing rectangle based on padding
                //RectangleF r2 = new RectangleF(r.Left + si.PaddingLeft,
                //                               r.Top + si.PaddingTop,
                //                               r.Width - si.PaddingLeft - si.PaddingRight,
                //                               r.Height - si.PaddingTop - si.PaddingBottom);
                // http://www.fyireporting.com/forum/viewtopic.php?t=892
                //A.S.> convert pt to px if needed(when printing we need px, when draw preview - pt)
                RectangleF r2;
                if (g.PageUnit == GraphicsUnit.Pixel)
                {
                    r2 = new RectangleF(r.Left + (si.PaddingLeft * g.DpiX) / 72,
                                        r.Top + (si.PaddingTop * g.DpiX) / 72,
                                        r.Width - ((si.PaddingLeft + si.PaddingRight) * g.DpiX) / 72,
                                        r.Height - ((si.PaddingTop + si.PaddingBottom) * g.DpiX) / 72);
                }
                else
                {
                    // adjust drawing rectangle based on padding
                    r2 = new RectangleF(r.Left + si.PaddingLeft,
                                        r.Top + si.PaddingTop,
                                        r.Width - si.PaddingLeft - si.PaddingRight,
                                        r.Height - si.PaddingTop - si.PaddingBottom);
                }

                drawBrush = new SolidBrush(si.Color);
                if (si.TextAlign == TextAlignEnum.Justified) //Added from forum: Hugo http://www.fyireporting.com/forum/viewtopic.php?t=552
                {
                    GraphicsExtended.DrawStringJustified(g, pt.Text, drawFont, drawBrush, r2, '-');
                }
                else if (pt.NoClip)     // request not to clip text
                {
                    g.DrawString(pt.Text, drawFont, drawBrush, new PointF(r.Left, r.Top), drawFormat);
                    HighlightString(g, pt, new RectangleF(r.Left, r.Top, float.MaxValue, float.MaxValue),
                                    drawFont, drawFormat, cp);
                }
                else
                {
                    g.DrawString(pt.Text, drawFont, drawBrush, r2, drawFormat);
                    HighlightString(g, pt, r2, drawFont, drawFormat, cp);
                }
                if (cpim.SelectToolEnabled)
                {
                    if (pt.AllowSelect && cpim.SelectedItemList.Contains(pt))
                    {
                        g.FillRectangle(new SolidBrush(Color.FromArgb(50, cp.SelectItemColor)), r2);
                    }
                }
            }
            finally
            {
                if (drawFont != null)
                {
                    drawFont.Dispose();
                }
                if (drawFormat != null)
                {
                    drawFont.Dispose();
                }
                if (drawBrush != null)
                {
                    drawBrush.Dispose();
                }
            }
        }
        /// <summary>
        /// A draw accounting for scrolling and zoom factors.
        /// </summary>
        public static void Draw(Graphics g, Pages pages, float pageGap, Rectangle clipRectangle,
                                ref CanvasProperties cp, ref PageItemManager cpim)
        {
            if (pages == null)
            {   // No pages; means nothing to draw
                g.FillRectangle(Brushes.White, clipRectangle);
                return;
            }

            g.PageUnit = GraphicsUnit.Pixel;
            g.ScaleTransform(cp.Zoom, cp.Zoom);
            cp.Dpi = new PointF(g.DpiX, g.DpiY);

            // Zoom affects how much will show on the screen.  Adjust our perceived clipping rectangle
            //  to account for it.
            RectangleF r;

            r = new RectangleF((clipRectangle.X) / cp.Zoom, (clipRectangle.Y) / cp.Zoom,
                               (clipRectangle.Width) / cp.Zoom, (clipRectangle.Height) / cp.Zoom);

            // Calculate the top of the page
            int fpage = (int)(cp.Scroll.Y / Measurement.PixelsFromPoints(pages.PageHeight + pageGap, cp.Dpi.Y));
            int lpage = (int)((cp.Scroll.Y + r.Height) / Measurement.PixelsFromPoints(pages.PageHeight + pageGap, cp.Dpi.X)) + 1;

            if (fpage >= pages.PageCount)
            {
                return;
            }
            if (lpage >= pages.PageCount)
            {
                lpage = pages.PageCount - 1;
            }

            cp.Left = cp.Offset.X;
            cp.Top  = pageGap;
            // Loop thru the visible pages
            for (int p = fpage; p <= lpage; p++)
            {
                cp.Scroll = new PointF(
                    cp.Scroll.X,
                    (cp.Scroll.Y - Measurement.PixelsFromPoints(p * (pages.PageHeight + pageGap), cp.Dpi.Y))
                    );

                System.Drawing.Rectangle pr =
                    new System.Drawing.Rectangle(
                        (int)(Measurement.PixelsFromPoints(cp.Left, cp.Dpi.X) - cp.Scroll.X),
                        (int)(Measurement.PixelsFromPoints(cp.Top, cp.Dpi.Y) - cp.Scroll.Y),
                        (int)Measurement.PixelsFromPoints(pages.PageWidth, cp.Dpi.X),
                        (int)Measurement.PixelsFromPoints(pages.PageHeight, cp.Dpi.Y));
                g.FillRectangle(Brushes.White, pr);

                ProcessPage(g, pages[p], r, true, cp, ref cpim);

                // Draw the page outline
                using (Pen pn = new Pen(Brushes.Black, 1))
                {
                    int z3 = Math.Min((int)(3f / cp.Zoom), 3);
                    if (z3 <= 0)
                    {
                        z3 = 1;
                    }
                    int z4 = Math.Min((int)(4f / cp.Zoom), 4);
                    if (z4 <= 0)
                    {
                        z4 = 1;
                    }
                    g.DrawRectangle(pn, pr);                                    // outline of page
                    g.FillRectangle(Brushes.Black,
                                    pr.X + pr.Width, pr.Y + z3, z3, pr.Height); // right side of page
                    g.FillRectangle(Brushes.Black,
                                    pr.X + z3, pr.Y + pr.Height, pr.Width, z4); // bottom of page
                }
            }
        }
        private static void DrawImageSized(PageImage pi, Image im, Graphics g, RectangleF r, CanvasProperties cp, PageItemManager cpim)
        {
            float     height, width;            // some work variables
            StyleInfo si = pi.SI;

            // adjust drawing rectangle based on padding
            //RectangleF r2 = new RectangleF(r.Left + PixelsX(si.PaddingLeft),
            //    r.Top + PixelsY(si.PaddingTop),
            //    r.Width - PixelsX(si.PaddingLeft + si.PaddingRight),
            //    r.Height - PixelsY(si.PaddingTop + si.PaddingBottom));
            // http://www.fyireporting.com/forum/viewtopic.php?t=892
            //A.S.> convert pt to px if needed(when printing we need px, when draw preview - pt)
            RectangleF r2;

            if (g.PageUnit == GraphicsUnit.Pixel)
            {
                r2 = new RectangleF(r.Left + (si.PaddingLeft * g.DpiX) / 72,
                                    r.Top + (si.PaddingTop * g.DpiX) / 72,
                                    r.Width - ((si.PaddingLeft + si.PaddingRight) * g.DpiX) / 72,
                                    r.Height - ((si.PaddingTop + si.PaddingBottom) * g.DpiX) / 72);
            }
            else
            {
                // adjust drawing rectangle based on padding
                r2 = new RectangleF(r.Left + si.PaddingLeft,
                                    r.Top + si.PaddingTop,
                                    r.Width - si.PaddingLeft - si.PaddingRight,
                                    r.Height - si.PaddingTop - si.PaddingBottom);
            }

            Rectangle ir;       // int work rectangle

            ir = new Rectangle(Convert.ToInt32(r2.Left), Convert.ToInt32(r2.Top),
                               Convert.ToInt32(r2.Width), Convert.ToInt32(r2.Height));
            switch (pi.Sizing)
            {
            case ImageSizingEnum.AutoSize:
                // Note: GDI+ will stretch an image when you only provide
                //  the left/top coordinates.  This seems pretty stupid since
                //  it results in the image being out of focus even though
                //  you don't want the image resized.
                if (g.DpiX == im.HorizontalResolution &&
                    g.DpiY == im.VerticalResolution)
                {
                    ir = new Rectangle(Convert.ToInt32(r2.Left), Convert.ToInt32(r2.Top),
                                       im.Width, im.Height);
                }
                g.DrawImage(im, ir);

                break;

            case ImageSizingEnum.Clip:
                Region saveRegion = g.Clip;
                Region clipRegion = new Region(g.Clip.GetRegionData());
                clipRegion.Intersect(r2);
                g.Clip = clipRegion;
                if (g.DpiX == im.HorizontalResolution &&
                    g.DpiY == im.VerticalResolution)
                {
                    ir = new Rectangle(Convert.ToInt32(r2.Left), Convert.ToInt32(r2.Top),
                                       im.Width, im.Height);
                }
                g.DrawImage(im, ir);
                g.Clip = saveRegion;
                break;

            case ImageSizingEnum.FitProportional:
                float ratioIm = (float)im.Height / (float)im.Width;
                float ratioR  = r2.Height / r2.Width;
                height = r2.Height;
                width  = r2.Width;
                if (ratioIm > ratioR)
                {       // this means the rectangle width must be corrected
                    width = height * (1 / ratioIm);
                }
                else if (ratioIm < ratioR)
                {       // this means the ractangle height must be corrected
                    height = width * ratioIm;
                }
                r2 = new RectangleF(r2.X, r2.Y, width, height);
                g.DrawImage(im, r2);
                break;

            case ImageSizingEnum.Fit:
            default:
                g.DrawImage(im, r2);
                break;
            }

            if (cpim.SelectToolEnabled && pi.AllowSelect && cpim.SelectedItemList.Contains(pi))
            {
                g.FillRectangle(new SolidBrush(Color.FromArgb(50, cp.SelectItemColor)), ir);
            }

            return;
        }
        /// <summary>
        /// A simple draw of an entire page.  Useful when printing or creating an image.
        /// </summary>
        public static void Draw(Graphics g, int page, Pages pages, Rectangle clipRectangle, bool drawBackground, ref CanvasProperties cp, ref PageItemManager cpim)
        {
            cp.Dpi                    = new PointF(g.DpiX, g.DpiY);      // this can change (e.g. printing graphics context)
            cp.HighlightText          = null;
            cp.HighlightItem          = null;
            cp.HighlightAll           = false;
            cp.HighlightCaseSensitive = false;

            //			g.InterpolationMode = InterpolationMode.HighQualityBilinear;	// try to unfuzz charts
            g.PageUnit = GraphicsUnit.Pixel;
            g.ScaleTransform(1, 1);

            if (!cp.Offset.IsEmpty)    // used when correcting for non-printable area on paper
            {
                g.TranslateTransform(cp.Offset.X, cp.Offset.Y);
            }

            cp.Left   = 0;
            cp.Top    = 0;
            cp.Scroll = new PointF(0, 0);

            RectangleF r = new RectangleF(clipRectangle.X, clipRectangle.Y,
                                          clipRectangle.Width, clipRectangle.Height);

            if (drawBackground)
            {
                g.FillRectangle(
                    Brushes.White,
                    Measurement.PixelsFromPoints(cp.Left, cp.Dpi.X),
                    Measurement.PixelsFromPoints(cp.Top, cp.Dpi.Y),
                    Measurement.PixelsFromPoints(pages.PageWidth, cp.Dpi.X),
                    Measurement.PixelsFromPoints(pages.PageHeight, cp.Dpi.Y));
            }

            ProcessPage(g, pages[page], r, false, cp, ref cpim);
        }
        private static void DrawImage(PageImage pi, Graphics g, RectangleF r, CanvasProperties cp, PageItemManager cpim)
        {
            Stream strm = null;

            System.Drawing.Image im = null;
            try
            {
                strm = new MemoryStream(pi.ImageData);
                im   = Image.FromStream(strm);
                DrawImageSized(pi, im, g, r, cp, cpim);
            }
            finally
            {
                if (strm != null)
                {
                    strm.Close();
                }
                if (im != null)
                {
                    im.Dispose();
                }
            }
        }
 /// <summary>
 /// Pre-Processes the HTML prior to rendering it in a page.
 /// </summary>
 public static void ProcessHtml(PageTextHtml pth, Graphics g, RectangleF clipRect, bool bHitList, CanvasProperties cp, ref PageItemManager cpim)
 {
     pth.Build(g);                               // Builds the subobjects that make up the html
     CanvasPainter.ProcessPage(g, pth, clipRect, bHitList, cp, ref cpim);
 }
        /// <summary>
        /// Renders all the objects in a Page or composite object.
        /// </summary>
        private static void ProcessPage(Graphics g, IEnumerable p, RectangleF clipRect, bool bHitList, CanvasProperties cp, ref PageItemManager cpim)
        {
            foreach (PageItem pi in p)
            {
                if (pi is PageTextHtml)
                {       // PageTextHtml is actually a composite object (just like a page)
                    if (cpim.SelectToolEnabled && bHitList)
                    {
                        RectangleF hr = new RectangleF(
                            Measurement.PixelsFromPoints(pi.X + cp.Left - cp.Scroll.X, cp.Dpi.X),
                            Measurement.PixelsFromPoints(pi.Y + cp.Scroll.X - cp.Scroll.Y, cp.Dpi.Y),
                            Measurement.PixelsFromPoints(pi.W, cp.Dpi.X),
                            Measurement.PixelsFromPoints(pi.H, cp.Dpi.Y));

                        cpim.HitList.Add(new HitListEntry(hr, pi));
                    }
                    ProcessHtml(pi as PageTextHtml, g, clipRect, bHitList, cp, ref cpim);
                    continue;
                }

                if (pi is PageLine)
                {
                    PageLine pl = pi as PageLine;
                    CanvasPainter.DrawLine(
                        pl.SI.BColorLeft,
                        pl.SI.BStyleLeft,
                        pl.SI.BWidthLeft,
                        g,
                        Measurement.PixelsFromPoints(pl.X + cp.Left - cp.Scroll.X, cp.Dpi.X),
                        Measurement.PixelsFromPoints(pl.Y + cp.Top - cp.Scroll.Y, cp.Dpi.Y),
                        Measurement.PixelsFromPoints(pl.X2 + cp.Left - cp.Scroll.X, cp.Dpi.X),
                        Measurement.PixelsFromPoints(pl.Y2 + cp.Top - cp.Scroll.Y, cp.Dpi.Y));
                    continue;
                }


                RectangleF rect = new RectangleF(
                    Measurement.PixelsFromPoints(pi.X + cp.Left - cp.Scroll.X, cp.Dpi.X),
                    Measurement.PixelsFromPoints(pi.Y + cp.Top - cp.Scroll.Y, cp.Dpi.Y),
                    Measurement.PixelsFromPoints(pi.W, cp.Dpi.X),
                    Measurement.PixelsFromPoints(pi.H, cp.Dpi.Y));

                // Maintain the hit list
                if (bHitList)
                {
                    if (cpim.SelectToolEnabled)
                    {   // we need all PageText and PageImage items that have been displayed
                        if (pi is PageText || pi is PageImage)
                        {
                            cpim.HitList.Add(new HitListEntry(rect, pi));
                        }
                    }
                    // Only care about items with links and tips
                    else if (pi.HyperLink != null || pi.BookmarkLink != null || pi.Tooltip != null)
                    {
                        HitListEntry hle;
                        if (pi is PagePolygon)
                        {
                            hle = new HitListEntry(pi as PagePolygon, cp.Left - cp.Scroll.X, cp.Top - cp.Scroll.Y, ((Canvas)cp.Parent));
                        }
                        else
                        {
                            hle = new HitListEntry(rect, pi);
                        }
                        cpim.HitList.Add(hle);
                    }
                }

                if ((pi is PagePolygon) || (pi is PageCurve))
                { // intentionally empty; polygon's rectangles aren't calculated
                }
                else if (!rect.IntersectsWith(clipRect))
                {
                    continue;
                }

                if (pi.SI.BackgroundImage != null)
                {       // put out any background image
                    PageImage i = pi.SI.BackgroundImage;
                    CanvasPainter.DrawImageBackground(i, pi.SI, g, rect);
                }

                if (pi is PageText)
                {
                    PageText pt = pi as PageText;
                    CanvasPainter.DrawString(pt, g, rect, cp, cpim);
                }
                else if (pi is PageImage)
                {
                    PageImage i = pi as PageImage;
                    CanvasPainter.DrawImage(i, g, rect, cp, cpim);
                }
                else if (pi is PageRectangle)
                {
                    CanvasPainter.DrawBackground(g, rect, pi.SI);
                }
                else if (pi is PageEllipse)
                {
                    PageEllipse pe = pi as PageEllipse;
                    CanvasPainter.DrawEllipse(pe, g, rect);
                }
                else if (pi is PagePie)
                {
                    PagePie pp = pi as PagePie;
                    CanvasPainter.DrawPie(pp, g, rect);
                }
                else if (pi is PagePolygon)
                {
                    PagePolygon ppo = pi as PagePolygon;
                    CanvasPainter.FillPolygon(ppo, g, rect, cp);
                }
                else if (pi is PageCurve)
                {
                    PageCurve pc = pi as PageCurve;
                    CanvasPainter.DrawCurve(pc.SI.BColorLeft, pc.SI.BStyleLeft, pc.SI.BWidthLeft,
                                            g, pc.Points, pc.Offset, pc.Tension, cp);
                }


                CanvasPainter.DrawBorder(pi, g, rect);
            }
        }