Example #1
0
        // 将一个<p>元素内容切割为Line数组
        int CutLines(Graphics g,
            RectParam rect_def,
            XmlNode nodeP,
            out List<Line> lines,
            out string strError)
        {
            strError = "";
            lines = new List<Line>();

            float fLineHeight = 0;
            string strFontString = "";

            string strText = nodeP.InnerText;

            if (String.IsNullOrEmpty(strText) == true)
            {
                // TODO 只有一行的高度
                using (Font font = new Font("Times New Roman", 16.0F))
                {
                    // TODO: 需要测试一下空字符串是否可以用于MesasureString()
                    SizeF size = g.MeasureString(strText, font);
                    fLineHeight = size.Height;
                    strFontString = GetFontString(font);
                }
                Line current_line = new Line();
                current_line.Height = fLineHeight;
                current_line.FontDef = strFontString;
                lines.Add(current_line);

                return 0;
            }

            CharacterRange[] ranges = new CharacterRange[strText.Length];
            for (int i = 0; i < strText.Length; i++)
            {
                ranges[i] = new CharacterRange(i, 1);
            }

            StringFormat format = new StringFormat();
            format.FormatFlags = StringFormatFlags.NoClip;
            format.SetMeasurableCharacterRanges(ranges);


            Region[] regions = new Region[strText.Length];

            using (Font font = new Font("Times New Roman", 16.0F))
            {

                SizeF size = g.MeasureString(strText, font);
                fLineHeight = size.Height;
                RectangleF layout = new RectangleF(0, 0, size.Width, size.Height);
                regions = g.MeasureCharacterRanges(
                    strText,
                    font,
                    layout,
                    format);
                strFontString = GetFontString(font);
            }

            // 切割为若干行
            {
                Line current_line = new Line();
                current_line.Height = fLineHeight;
                current_line.FontDef = strFontString;
                lines.Add(current_line);
                float x = 0;
                for (int i = 0; i < regions.Length; i++)
                {
                    Region region = regions[i];
                    RectangleF rect = region.GetBounds(g);
                    if (x > rect_def.Width)
                    {
                        // 另起一行
                        current_line = new Line();
                        current_line.Height = fLineHeight;
                        current_line.FontDef = strFontString;
                        lines.Add(current_line);
                        Box box = new Box();
                        box.Text = strText.Substring(i, 1);
                        box.Width = rect.Width;
                        box.Height = rect.Height;
                        current_line.Boxes.Add(box);
                        x = 0;
                    }
                    else
                    {
                        Box box = new Box();
                        box.Text = strText.Substring(i, 1);
                        box.Width = rect.Width;
                        box.Height = rect.Height;
                        current_line.Boxes.Add(box);
                    }

                    x += rect.Width;
                }
            }

            return 0;
        }
Example #2
0
 public RectParam(RectParam rect_ref)
 {
     this.X = rect_ref.X;
     this.Y = rect_ref.Y;
     this.Width = rect_ref.Width;
     this.WidthString = rect_ref.WidthString;
     this.Padding = new Padding(rect_ref.Padding.Left,
         rect_ref.Padding.Top,
         rect_ref.Padding.Right,
         rect_ref.Padding.Bottom);
     this.Height = rect_ref.Height;
 }
Example #3
0
        // 将一个字符串切割为Line数组
        // parameters:
        //      strTextParam    ==null 表示触发<p>前面的初始化换行
        //                      == "\r\n" 执行<br/>动作
        int BuildLines(Graphics g,
            RectParam rect_def,
            string strTextParam,
            Font font,
            Color color,
            ParagraphFormat p_format,
            ref List<PrintLine> lines,
            out string strError)
        {
            strError = "";
            int nRet = 0;

            float fLineHeight = 0;
            string strFontString = GetFontString(font);
            string strFontColor = GetColorString(color);

            // 表示建立一个空的<p>元素显示位置
            if (strTextParam == null)
            {
                SizeF size = g.MeasureString("1", font);
                fLineHeight = size.Height;

                float emheight = font.FontFamily.GetEmHeight(FontStyle.Regular);
                float ascent = font.FontFamily.GetCellAscent(FontStyle.Regular);

                PrintLine current_line = null;

                current_line = new PrintLine();
                current_line.HorzAlign = GetHorzAlign(p_format.Align);
                current_line.Height = fLineHeight;
                current_line.Width = rect_def.Width - rect_def.Padding.Horizontal;
                current_line.FontDef = strFontString;
                current_line.ColorDef = strFontColor;
                current_line.BaseRatio = ascent / emheight;
                lines.Add(current_line);
                current_line.Indent = p_format.Indent;

                return 0;
            }

            // 回车换行
            if (strTextParam == "\r\n")
            {
                SizeF size = g.MeasureString("1", font);
                fLineHeight = size.Height;

                float emheight = font.FontFamily.GetEmHeight(FontStyle.Regular);
                float ascent = font.FontFamily.GetCellAscent(FontStyle.Regular);

                PrintLine current_line = null;

                // 另起一行
                current_line = new PrintLine();
                current_line.HorzAlign = GetHorzAlign(p_format.Align);
                current_line.Height = fLineHeight;
                current_line.Width = rect_def.Width - rect_def.Padding.Horizontal;
                current_line.FontDef = strFontString;
                current_line.ColorDef = strFontColor;
                current_line.BaseRatio = ascent / emheight;
                lines.Add(current_line);
                current_line.Indent = p_format.Indent;

                return 0;
            }


            for (int j=0; ;j++ )
            {
                if (String.IsNullOrEmpty(strTextParam) == true)
                    break;

                float emheight = font.FontFamily.GetEmHeight(FontStyle.Regular);
                float ascent = font.FontFamily.GetCellAscent(FontStyle.Regular);

                int nLen = Math.Min(30, strTextParam.Length);
                string strText = strTextParam.Substring(0, nLen);
                strTextParam = strTextParam.Remove(0, nLen);

                CharacterRange[] ranges = new CharacterRange[strText.Length];
                for (int i = 0; i < strText.Length; i++)
                {
                    ranges[i] = new CharacterRange(i, 1);
                }

                StringFormat format = new StringFormat();
                format.FormatFlags = StringFormatFlags.NoClip ;
                format.SetMeasurableCharacterRanges(ranges);


                Region[] regions = new Region[strText.Length];

                {
                    SizeF size = g.MeasureString(strText, font);
                    fLineHeight = size.Height;
                    RectangleF layout = new RectangleF(0, 0, size.Width, size.Height);
                    regions = g.MeasureCharacterRanges(
                        strText,
                        font,
                        layout,
                        format);
                }

                // 切割为若干行
                {
                    float x = 0;
                    PrintLine current_line = null;
                    if (lines.Count == 0)
                    {
                        current_line = new PrintLine();
                        current_line.HorzAlign = GetHorzAlign(p_format.Align);
                        current_line.Height = fLineHeight;
                        current_line.Width = rect_def.Width - rect_def.Padding.Horizontal;
                        current_line.FontDef = strFontString;
                        current_line.ColorDef = strFontColor;
                        current_line.BaseRatio = ascent / emheight;
                        lines.Add(current_line);
                        x = p_format.Indent;
                        current_line.Indent = p_format.Indent;

                    }
                    else
                    {
                        current_line = lines[lines.Count - 1];
                        x = GetLineWidth(current_line) + current_line.Indent;
                    }

                    for (int i = 0; i < regions.Length; i++)
                    {
                        string strCurrentChar = strText.Substring(i, 1);

                        Region region = regions[i];
                        RectangleF rect = region.GetBounds(g);
                        if (x + rect.Width > rect_def.Width - rect_def.Padding.Horizontal)
                        {
                            if (p_format.LineBreak == "word")
                            {
                                // return:
                                //      -1   无需特殊处理
                                //      其他  需要切断的位置
                                nRet = DetectLineBreak(strCurrentChar,
                                    current_line);
                            }
                            else
                                nRet = -1;

                            if (nRet != -1)
                            {
                                PrintLine prev_line = current_line;

                                // 另起一行
                                current_line = new PrintLine();
                                current_line.HorzAlign = GetHorzAlign(p_format.Align);
                                current_line.Width = rect_def.Width - rect_def.Padding.Horizontal;
                                current_line.BaseRatio = prev_line.BaseRatio;
                                lines.Add(current_line);
                                x = 0;

                                int nStart = nRet;

                                // 准备字体、颜色字符串
                                string strTempFontString = prev_line.FontDef;
                                string strTempColorString = prev_line.ColorDef;
                                for (int k = 0; k <= nStart; k++)
                                {
                                    Box box = prev_line.Boxes[k];
                                    if (string.IsNullOrEmpty(box.FontDef) == false)
                                        strTempFontString = box.FontDef;
                                    if (string.IsNullOrEmpty(box.ColorDef) == false)
                                        strTempColorString = box.ColorDef;
                                }

                                current_line.FontDef = strTempFontString;
                                current_line.ColorDef = strTempColorString;

                                // 切断,同时获得行高度
                                float fTempLineHeight = 0;
                                int nCount = prev_line.Boxes.Count;
                                for (int k = nStart; k < nCount; k++)
                                {
                                    Box box = prev_line.Boxes[nStart];
                                    current_line.Boxes.Add(box);
                                    prev_line.Boxes.RemoveAt(nStart);
                                    if (fTempLineHeight < box.Height)
                                        fTempLineHeight = box.Height;
                                }

                                current_line.Height = fTempLineHeight;
                            }
                            else
                            {
                                // 另起一行
                                current_line = new PrintLine();
                                current_line.HorzAlign = GetHorzAlign(p_format.Align);
                                current_line.Height = fLineHeight;
                                current_line.Width = rect_def.Width - rect_def.Padding.Horizontal;
                                current_line.FontDef = strFontString;
                                current_line.ColorDef = strFontColor;
                                current_line.BaseRatio = ascent / emheight;
                                lines.Add(current_line);
                                x = 0;

                            }
                        }
                        else
                        {
                        }


                        if (current_line.Boxes.Count == 0
                            && lines.Count > 1
                            && strCurrentChar == " ")
                        {
                            // 忽略第二行以后最左端的空格
                        }
                        else
                        {
                            Box box = new Box();
                            box.Text = strCurrentChar;
                            box.Width = rect.Width;
                            box.Height = rect.Height;
                            box.Base = fLineHeight * ascent / emheight;
                            if (i == 0 && j == 0)
                            {
                                box.FontDef = strFontString;
                                box.ColorDef = strFontColor;
                            }
                            if (current_line.Height < fLineHeight)
                            {
                                current_line.Height = fLineHeight;
                            }
                            current_line.Boxes.Add(box);

                            x += rect.Width;
                        }

                    }
                }
            }

            return 0;
        }
Example #4
0
        // parameters:
        //      state  ParagraphFirst 是否为首次处理一个<p>
        int Process(
            Graphics g,
            RectParam rect_def,
            XmlNode node,
            Hashtable macro_table,
            RectGroup rect_group,
            ref List<PrintLine> lines,
            out string strError)
        {
            strError = "";
            int nRet = 0;

            if (node.NodeType == XmlNodeType.Element
                && node.Name == "br")
            {
                SetLastLine(lines);

                Color color;
                Font font = GetNodeFont(node, out color);

                ParagraphFormat format = GetNodeParagraphFormat(node);

                try
                {
                    nRet = BuildLines(g,
            rect_def,
            "\r\n",
            font,
            color,
            format,
            ref lines,
            out strError);
                    if (nRet == -1)
                        return -1;
                }
                finally
                {
                    font.Dispose();
                }

                return 0;
            }

            int nStartLines = lines.Count;
            int nLinesLimit = -1;
            ParagraphGroup p_group = null;

            // <p>的开头,触发一下换行
            if (node.NodeType == XmlNodeType.Element
                && node.Name == "p")
            {
                SetLastLine(lines);

                Color color;
                Font font = GetNodeFont(node, out color);

                ParagraphFormat format = GetNodeParagraphFormat(node);
                nLinesLimit = (int)format.MaxLines;

                p_group = new ParagraphGroup();
                p_group.Format = format;
                rect_group.Paragraphs.Add(p_group);

                try
                {

                    nRet = BuildLines(g,
            rect_def,
            null,
            font,
            color,
            format,
            ref lines,
            out strError);
                    if (nRet == -1)
                        return -1;


                }
                finally
                {
                    font.Dispose();
                }
            }

            for (int i = 0; i < node.ChildNodes.Count; i++)
            {
                XmlNode child = node.ChildNodes[i];

                if (child.NodeType == XmlNodeType.Text)
                {
                    string strText = child.Value;
                    strText = strText.Replace("\n", "\r");
                    strText = strText.Replace("\r", "");

                    if (macro_table != null)
                    {
                        strText = StringUtil.MacroString(macro_table,
        strText);
                    }

                    Color color;
                    Font font = GetNodeFont(node, out color);

                    ParagraphFormat format = GetNodeParagraphFormat(node);

                    try
                    {
                        nRet = BuildLines(g,
                rect_def,
                strText,
                font,
                color,
                format,
                ref lines,
                out strError);
                        if (nRet == -1)
                            return -1;
                    }
                    finally
                    {
                        font.Dispose();
                    }
                }

                if (child.NodeType == XmlNodeType.Element)
                {
                    int x_delta = 0;
                    int y_delta = 0;
                    RectParam current_rect_def = rect_def;
                    if (child.Name == "p")
                    {
                        // 2012/4/23
                        // 让<p>的padding属性起作用
                        ParagraphFormat format = GetNodeParagraphFormat(child);
                        current_rect_def = new RectParam(rect_def);
                        current_rect_def.Padding = AddPadding(current_rect_def.Padding, format.Padding);
                        x_delta = format.Padding.Left;
                        y_delta = format.Padding.Top;
                    }

                    int nStartLine = 0;
                    if (lines != null)
                        nStartLine = lines.Count;

                    nRet = Process(
                        g,
                        current_rect_def,
                        child,
                        macro_table,
                        rect_group,
                        ref lines,
                        out strError);
                    if (nRet == -1)
                        return -1;

                    // 对新增的行进行平移
                    if (x_delta != 0 || y_delta != 0)
                    {
                        for (int j = nStartLine; j < lines.Count; j++)
                        {
                            PrintLine line = lines[j];

                            // 
                            line.X += x_delta;
                            line.Y += y_delta;
                        }
                    }
                }
            }

            // 删除多余的行
            if (nLinesLimit != -1)
            {
                // TODO 如果发生切断,是不是最后要加... ?
                while (lines.Count > nStartLines + nLinesLimit)
                {
                    lines.RemoveAt(lines.Count - 1);
                }
            }

            if (p_group != null)
            {
                for (int i = nStartLines; i < lines.Count; i++)
                {
                    p_group.Lines.Add(lines[i]);
                }
            }

            return 0;
        }
Example #5
0
        // 处理一个矩形区域
        int DoRect(
            Graphics g,
            XmlNode nodeContainer,
            RectParam rect_def,
            bool bRemainPage,
            Hashtable macro_table,
            RectGroup rect_group,
            ref List<Page> pages,
            out string strError)
        {
            strError = "";
            int nRet = 0;

            Padding padding = new Padding(0, 0, 0, 0);
            string strPadding = DomUtil.GetAttr(nodeContainer,
                "padding");
            if (String.IsNullOrEmpty(strPadding) == false)
            {
                nRet = GetPadding(strPadding,
                out padding,
                out strError);
                if (nRet == -1)
                {
                    strError = "元素<" + nodeContainer.Name + ">中padding属性值 '" + strPadding + "' 格式错误: " + strError;
                    return -1;
                }
            }

            rect_def.Padding = padding;


            List<PrintLine> lines = new List<PrintLine>();

            // 将一个容器元素下级的全部内容切割为Line数组
            nRet = Process(g,
                rect_def,
                nodeContainer,
                macro_table,
                rect_group,
        ref lines,
        out strError);
            if (nRet == -1)
                return -1;

            SetLastLine(lines);

            // 组装到Page中
            int iPage = 0;
            Page current_page = null;
            if (pages.Count > iPage)
                current_page = pages[iPage];
            else
            {
                current_page = new Page();
                pages.Add(current_page);
            }
            float current_height = 0;
            for (int i = 0; i < lines.Count; i++)
            {
                PrintLine line = lines[i];

                if (current_height + line.Height > rect_def.Height - rect_def.Padding.Vertical
                    && current_page.Lines.Count > 0    // 至少有一个行
                    && bRemainPage == false)
                {
                    // 新增一页
                    current_height = 0;
                    iPage++;
                    if (pages.Count > iPage)
                        current_page = pages[iPage];
                    else
                    {
                        current_page = new Page();
                        pages.Add(current_page);
                    }

                }

                // 
                line.X += rect_def.X + rect_def.Padding.Left;
                line.Y += rect_def.Y + rect_def.Padding.Top + current_height;
                current_page.Lines.Add(line);

                current_height += line.Height;
            }

            return iPage;
        }
Example #6
0
        void ResetLines(List<Page> pages,
            RectParam rect_def,
            List<PrintLine> lines)
        {
            int iPage = pages.Count - 1;
            Page current_page = pages[iPage];

            float current_height = rect_def.Height;
            for (int i = lines.Count - 1; i >= 0; i--)
            {
                PrintLine line = lines[i];

                if (current_height - line.Height < 0)
                {
                    // 倒退一页
                    current_height = rect_def.Height;
                    iPage--;
                    if (iPage >= 0)
                        current_page = pages[iPage];
                    else
                    {
                        break;
                    }

                }

                // 把line从pages中原来位置移走
                foreach (Page page in pages)
                {
                    if (page.Lines.IndexOf(line) != -1)
                    {
                        page.Lines.Remove(line);
                        break;
                    }
                }

                line.X = rect_def.X + rect_def.Padding.Left;
                line.Y = rect_def.Y + current_height - rect_def.Padding.Bottom -line.Height ;
                current_page.Lines.Add(line);

                current_height -= line.Height;
            }

        }
Example #7
0
        // parameters:
        //      height  分页以前的单页允许高度
        //      bIsHeaderFooter 是否保持不增加page
        int DoColumns(
            Graphics g,
            XmlNode nodeDocument,
            float x,
            float y,
            float width,
            float height,
            bool bIsHeaderFooter,
            Hashtable macro_table,
            string strHeaderCondition,
            ref List<Page> pages,
            out string strError)
        {
            strError = "";

            List<RectParam> rects = new List<RectParam>();

            // 列出根下面的<Column>元素
            XmlNodeList nodes = nodeDocument.SelectNodes("column");
            for (int i = 0; i < nodes.Count; i++)
            {
                XmlNode node = nodes[i];



                // 获得矩形参数
                RectParam rect = new RectParam();
                rect.WidthString = DomUtil.GetAttr(node, "width");
                rects.Add(rect);

            }

            // 分配宽度。固定宽度剩下以后的,就是auto的平分
            float rest = width;    // 剩下的宽度
            // 1) 处理数字宽度
            int nAutoCount = 0;
            for (int i = 0; i < rects.Count; i++)
            {
                RectParam rect = rects[i];
                string strWidth = rect.WidthString;
                if (StringUtil.IsPureNumber(strWidth) == true)
                {
                    rect.Width = (float)Convert.ToDouble(strWidth);
                    rest -= rect.Width;
                }
                else
                {
                    if (string.Compare(strWidth, "auto", true) != 0)
                    {
                        strError = "<column>元素的width属性值 '"+strWidth+"' 格式错误";
                        return -1;
                    }
                    rect.Width = -1;
                    nAutoCount++;
                }
            }

            // 2) 处理auto宽度
            if (nAutoCount > 0)
            {
                float nAverWidth = rest / nAutoCount;
                if (nAverWidth < 0)
                    nAverWidth = 0;
                for (int i = 0; i < rects.Count; i++)
                {
                    RectParam rect = rects[i];
                    if (rect.Width == -1)
                        rect.Width = nAverWidth;
                }
            }

            // 3)填充 X Y Height
            float start_x = x;
            for (int i = 0; i < rects.Count; i++)
            {
                RectParam rect = rects[i];
                rect.X = start_x;
                start_x += rect.Width;

                rect.Y = y;
                rect.Height = height;   // 一页内最大高度
            }

            List<RectGroup> rect_groups = new List<RectGroup>();

            for (int i = 0; i < nodes.Count; i++)
            {
                XmlNode node = nodes[i];

                if (bIsHeaderFooter == true)
                {
                    string strStyle = DomUtil.GetAttr(node, "style");
                    if (StringUtil.IsInList("hidewhenonepage", strStyle) == true
    && StringUtil.IsInList("onlyonepage", strHeaderCondition) == true)
                        continue;
                    if (StringUtil.IsInList("hidewhenfirstpage", strStyle) == true
&& StringUtil.IsInList("firstpage", strHeaderCondition) == true)
                        continue;
                    if (StringUtil.IsInList("hidewhentailpage", strStyle) == true
&& StringUtil.IsInList("tailpage", strHeaderCondition) == true)
                        continue;
                }

                // 获得矩形参数
                RectParam rect = rects[i];

                RectGroup rect_group = new RectGroup();
                rect_groups.Add(rect_group);

                int nRet = DoRect(
                    g,
                    node,
                    rect,
                    bIsHeaderFooter,
                    macro_table,
                    rect_group,
                    ref pages,
                    out strError);
                if (nRet == -1)
                    return -1;
            }


            if (bIsHeaderFooter == false)
            {
                // 处理valign=bottom的<p>
                for (int i = 0; i < nodes.Count; i++)
                {
                    XmlNode node = nodes[i];

                    // 获得矩形参数
                    RectParam rect = rects[i];

                    RectGroup rect_group = rect_groups[i];
                    for (int j = rect_group.Paragraphs.Count - 1; j >= 0; j--)
                    {
                        ParagraphGroup p_group = rect_group.Paragraphs[j];
                        if (p_group.Format.VertAlign == "bottom")
                        {
                            ResetLines(pages,
    rect,
    p_group.Lines);

                        }
                        else
                            break;  // 只要中间不连续,就中断
                    }
                }
            }

            return 0;
        }