// return: // -1 无需特殊处理 // 其他 需要切断的位置 static int DetectLineBreak(string strCurrentChar, PrintLine line) { // 如果是西文分隔符号 if (SepChars.IndexOf(strCurrentChar) != -1) return -1; // 如果是中文字符 if (StringUtil.IsHanzi(strCurrentChar[0]) == true) return -1; for (int i = line.Boxes.Count - 1; i >= 0; i--) { Box box = line.Boxes[i]; if (SepChars.IndexOf(box.Text) != -1) { if (i == line.Boxes.Count - 1) return -1; return i + 1; } if (StringUtil.IsHanzi(box.Text[0]) == true) { if (i == line.Boxes.Count - 1) return -1; return i + 1; } } return -1; // 如果整个line都是无法切割,就干脆放弃按词折行 }
// 获得一个行的最右端位置 static float GetLineWidth(PrintLine line) { float x = 0; for (int i = 0; i < line.Boxes.Count; i++) { Box box = line.Boxes[i]; x += box.LeftBlank + box.Width; } return x; }
// 将一个字符串切割为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; }