private static PdfStyle GetStyleFromStyleAttribute(XmlAttribute attrStyle, PdfStyle currentStyle) { Dictionary<string, string> dictStyleParts = new Dictionary<string, string>(); foreach (string style in attrStyle.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) { string[] styleParts = style.Split(':'); dictStyleParts.Add(styleParts[0].Trim(), styleParts[1].Trim()); } PdfStyle newStyle = new PdfStyle(); if (dictStyleParts.ContainsKey("font-family")) newStyle.Font.Name = dictStyleParts["font-family"]; else if (dictStyleParts.ContainsKey("FONT-FAMILY")) newStyle.Font.Name = dictStyleParts["FONT-FAMILY"]; else newStyle.Font.Name = currentStyle.Font.Name; if (dictStyleParts.ContainsKey("font-size")) newStyle.Font.Size = ConvertFontSize(dictStyleParts["font-size"]); else if (dictStyleParts.ContainsKey("FONT-SIZE")) newStyle.Font.Size = ConvertFontSize(dictStyleParts["FONT-SIZE"]); else newStyle.Font.Size = currentStyle.Font.Size; if (dictStyleParts.ContainsKey("font-weight")) newStyle.Font.Bold = ConvertFontBold(dictStyleParts["font-weight"]); else if (dictStyleParts.ContainsKey("FONT-WEIGHT")) newStyle.Font.Bold = ConvertFontBold(dictStyleParts["FONT-WEIGHT"]); else newStyle.Font.Bold = currentStyle.Font.Bold; if (dictStyleParts.ContainsKey("font-style")) newStyle.Font.Italic = ConvertFontItalic(dictStyleParts["font-style"]); else if (dictStyleParts.ContainsKey("FONT-STYLE")) newStyle.Font.Italic = ConvertFontItalic(dictStyleParts["FONT-STYLE"]); else newStyle.Font.Italic = currentStyle.Font.Italic; if (dictStyleParts.ContainsKey("text-decoration")) { newStyle.Font.Underline = ConvertFontUnderline(dictStyleParts["text-decoration"]); newStyle.Font.Strikeout = ConvertFontStrikethrough(dictStyleParts["text-decoration"]); } else if (dictStyleParts.ContainsKey("TEXT-DECORATION")) { newStyle.Font.Underline = ConvertFontUnderline(dictStyleParts["TEXT-DECORATION"]); newStyle.Font.Strikeout = ConvertFontStrikethrough(dictStyleParts["TEXT-DECORATION"]); } else { newStyle.Font.Underline = currentStyle.Font.Underline; newStyle.Font.Strikeout = currentStyle.Font.Strikeout; } return newStyle; }
private static void WriteNumberFragment(XmlWriter writer, KeyValuePair<string, string> paragraphAlignment, ChildNumberingSchemeType numberingSchemeType, int number, PdfStyle numberingStyle) { if (paragraphAlignment.Key == "horizontalalignment") if (paragraphAlignment.Value != "left") throw new Exception(string.Format("A numbered paragraph cannot be {0}-aligned.", paragraphAlignment.Value)); writer.WriteStartElement("numberfragment"); writer.WriteAttributeString("type", "fragment"); numberingStyle.Font.Bold = true; writer.WriteAttributeString("font", TallPDFFontName(numberingStyle.Font)); writer.WriteAttributeString("fontsize", numberingStyle.Font.Size.ToString()); writer.WriteString(ChildNumberingSchemeHelper.ParagraphNumber(numberingSchemeType, number)); writer.WriteEndElement(); //numberfragment }
private static PdfStyle DetermineNumberingStyle(XmlNode node, PdfStyle currentStyle) { //search through "node" until the first node of XmlNodeType.Text is reached. Return the style of that node. foreach (XmlNode childNode in node.ChildNodes) { if (childNode.NodeType == XmlNodeType.Text) { return currentStyle; } if (childNode.NodeType == XmlNodeType.Element) { switch (childNode.Name) { case "font": Style fontNodeStyle = GetStyleFromFontElement(childNode, currentStyle); currentStyle.Font.Name = fontNodeStyle.Font.Name; currentStyle.Font.Size = fontNodeStyle.Font.Size; break; case "span": case "div": XmlAttribute attrStyle = childNode.Attributes["style"]; if (attrStyle != null) { Style divNodeStyle = GetStyleFromStyleAttribute(attrStyle, currentStyle); currentStyle.Font.Name = divNodeStyle.Font.Name; currentStyle.Font.Size = divNodeStyle.Font.Size; } break; } } DetermineNumberingStyle(childNode, currentStyle); } //if it gets to here, we didn't find a text node, so return the default style return DefaultStyle(); }
private static void ProcessClauseContent(XmlWriter writer, XmlNodeList nodeList, PdfLayoutSettings pdfLayoutSettings, Stack<PdfStyle> styleStack) { foreach (XmlNode node in nodeList) { switch (node.NodeType) { #region NodeType == Element case XmlNodeType.Element: { switch (node.Name) { #region case font case "font": { styleStack.Push(GetStyleFromFontElement(node, styleStack.Peek())); ProcessClauseContent(writer, node.ChildNodes, pdfLayoutSettings, styleStack); styleStack.Pop(); break; } #endregion #region case b/strong case "strong": case "b": { PdfStyle newStyle = new PdfStyle(); newStyle.CopyFrom(styleStack.Peek()); newStyle.Font.Bold = true; styleStack.Push(newStyle); ProcessClauseContent(writer, node.ChildNodes, pdfLayoutSettings, styleStack); styleStack.Pop(); break; } #endregion #region case pws case Term._ELEMENT_PRESERVE_WHITE_SPACE: { PdfStyle newStyle = new PdfStyle(); newStyle.CopyFrom(styleStack.Peek()); newStyle.PreserveWhiteSpace = true; styleStack.Push(newStyle); ProcessClauseContent(writer, node.ChildNodes, pdfLayoutSettings, styleStack); styleStack.Pop(); break; } #endregion #region case sup case "sup": { PdfStyle newStyle = new PdfStyle(); newStyle.CopyFrom(styleStack.Peek()); newStyle.FontTransform = FontTransform.Superscript; styleStack.Push(newStyle); ProcessClauseContent(writer, node.ChildNodes, pdfLayoutSettings, styleStack); styleStack.Pop(); break; } #endregion #region case sub case "sub": { PdfStyle newStyle = new PdfStyle(); newStyle.CopyFrom(styleStack.Peek()); newStyle.FontTransform = FontTransform.Subscript; styleStack.Push(newStyle); ProcessClauseContent(writer, node.ChildNodes, pdfLayoutSettings, styleStack); styleStack.Pop(); break; } #endregion #region case i/em case "i": case "em": { PdfStyle newStyle = new PdfStyle(); newStyle.CopyFrom(styleStack.Peek()); newStyle.Font.Italic = true; styleStack.Push(newStyle); ProcessClauseContent(writer, node.ChildNodes, pdfLayoutSettings, styleStack); styleStack.Pop(); break; } #endregion #region case u, a //treat <a></a> just like <u></u> when rendering a PDF case "a": case "u": { PdfStyle newStyle = new PdfStyle(); newStyle.CopyFrom(styleStack.Peek()); newStyle.Font.Underline = true; styleStack.Push(newStyle); ProcessClauseContent(writer, node.ChildNodes, pdfLayoutSettings, styleStack); styleStack.Pop(); break; } #endregion #region case strike case "strike": { PdfStyle newStyle = new PdfStyle(); newStyle.CopyFrom(styleStack.Peek()); newStyle.Font.Strikeout = true; styleStack.Push(newStyle); ProcessClauseContent(writer, node.ChildNodes, pdfLayoutSettings, styleStack); styleStack.Pop(); break; } #endregion #region case span case "span": { XmlAttribute attrSpanStyle = node.Attributes["style"]; if (attrSpanStyle != null) styleStack.Push(GetStyleFromStyleAttribute(attrSpanStyle, styleStack.Peek())); ProcessClauseContent(writer, node.ChildNodes, pdfLayoutSettings, styleStack); if (attrSpanStyle != null) styleStack.Pop(); break; } #endregion #region case div case "div": { XmlAttribute attrDivStyle = node.Attributes["style"]; if (attrDivStyle != null) styleStack.Push(GetStyleFromStyleAttribute(attrDivStyle, styleStack.Peek())); ProcessClauseContent(writer, node.ChildNodes, pdfLayoutSettings, styleStack); if (attrDivStyle != null) styleStack.Pop(); WriteLineBreak(writer, true); break; } #endregion #region case br case "br": { WriteLineBreak(writer, pdfLayoutSettings.OpenParagraphCounter <= 0); break; } #endregion #region case p case "p": { if (ContainsImage(node)) { ProcessImage(writer, pdfLayoutSettings, node); } else { if (pdfLayoutSettings.OpenParagraphCounter > 0) { writer.WriteEndElement(); //close current paragraph before starting a new one pdfLayoutSettings.OpenParagraphCounter--; } if (node.ChildNodes.Count > 0) { writer.WriteStartElement("paragraph"); pdfLayoutSettings.InTextParagraph = true; pdfLayoutSettings.OpenParagraphCounter++; pdfLayoutSettings.ParagraphAlignment = GetParagraphAlignment(node); writer.WriteAttributeString("spacingbefore", (pdfLayoutSettings.SuppressSpacingBefore ? "0" : PARAGRAPH_SPACING.ToString())); if (!string.IsNullOrEmpty(pdfLayoutSettings.ParagraphAlignment.Key)) writer.WriteAttributeString(pdfLayoutSettings.ParagraphAlignment.Key, pdfLayoutSettings.ParagraphAlignment.Value); if (pdfLayoutSettings.IsFirstParagraph && !pdfLayoutSettings.CompletedFirstTextNode) { WriteParagraphAttributes(writer, pdfLayoutSettings.FirstParagraphAttributes); if (pdfLayoutSettings.PageBreakBefore) { writer.WriteAttributeString("startonnewpage", "true"); pdfLayoutSettings.PageBreakBefore = false; } if (pdfLayoutSettings.NumberingSchemeType != ChildNumberingSchemeType.None) { PdfStyle numberingStyle = DetermineNumberingStyle(node, DefaultStyle()); WriteNumberFragment(writer, pdfLayoutSettings.ParagraphAlignment, pdfLayoutSettings.NumberingSchemeType, pdfLayoutSettings.NumberingIndex, numberingStyle); } } else { WriteParagraphAttributes(writer, pdfLayoutSettings.OtherParagraphAttributes); } ProcessClauseContent(writer, node.ChildNodes, pdfLayoutSettings, styleStack); pdfLayoutSettings.IsFirstParagraph = false; } // if (node.ChildNodes.Count > 0) if (pdfLayoutSettings.OpenParagraphCounter > 0) { writer.WriteEndElement(); //paragraph pdfLayoutSettings.OpenParagraphCounter--; } } break; } #endregion #region case hr case "hr": { if (pdfLayoutSettings.OpenParagraphCounter > 0) { writer.WriteEndElement(); //close current paragraph before starting a new one pdfLayoutSettings.OpenParagraphCounter--; } XmlAttribute attrHrWidth = node.Attributes["size"]; int lineWidth = 1; if (attrHrWidth != null) if (!int.TryParse(attrHrWidth.Value, out lineWidth)) throw new ArgumentException(string.Format("Invalid width parameter on hr tag: '{0}'.", attrHrWidth.Value)); writer.WriteStartElement("paragraph"); pdfLayoutSettings.InTextParagraph = false; writer.WriteAttributeString("type", "drawing"); writer.WriteAttributeString("spacingbefore", "3"); writer.WriteAttributeString("spacingafter", "3"); writer.WriteAttributeString("width", "540"); writer.WriteAttributeString("height", lineWidth.ToString()); writer.WriteStartElement("shape"); writer.WriteAttributeString("type", "lineshape"); writer.WriteAttributeString("x", "0"); writer.WriteAttributeString("y", "0"); writer.WriteAttributeString("x1", "540"); writer.WriteAttributeString("y1", "0"); writer.WriteStartElement("pen"); writer.WriteAttributeString("color", "black"); writer.WriteAttributeString("width", lineWidth.ToString()); writer.WriteEndElement(); // pen writer.WriteEndElement(); // shape writer.WriteEndElement(); // paragraph break; } #endregion #region case table case "table": { if (pdfLayoutSettings.OpenParagraphCounter > 0) { writer.WriteEndElement(); //close current paragraph before starting a new one pdfLayoutSettings.OpenParagraphCounter--; } writer.WriteStartElement("paragraph"); writer.WriteAttributeString("type", "table"); writer.WriteAttributeString("spacingbefore", (pdfLayoutSettings.CompletedFirstTextNode ? "0" : PARAGRAPH_SPACING.ToString())); pdfLayoutSettings.InTextParagraph = false; WriteTableAttributes(writer, node.Attributes, pdfLayoutSettings); ProcessClauseContent(writer, node.ChildNodes, pdfLayoutSettings, styleStack); pdfLayoutSettings.TableCellSpacing = 0; pdfLayoutSettings.TableCellPadding = 0; writer.WriteEndElement(); // paragraph pdfLayoutSettings.IsFirstParagraph = false; break; } #endregion #region case tr case "tr": { writer.WriteStartElement("row"); ProcessClauseContent(writer, node.ChildNodes, pdfLayoutSettings, styleStack); writer.WriteEndElement(); // row break; } #endregion #region case td/th case "td": case "th": { //save off current pdfLayoutSettings to re-use after the table cell PdfLayoutSettings savedPdfLayoutSettings = new PdfLayoutSettings(); pdfLayoutSettings.CopyTo(ref savedPdfLayoutSettings); if (!string.IsNullOrEmpty(pdfLayoutSettings.TableCellAlignment)) { pdfLayoutSettings.FirstParagraphAttributes["horizontalalignment"] = pdfLayoutSettings.TableCellAlignment; pdfLayoutSettings.OtherParagraphAttributes["horizontalalignment"] = pdfLayoutSettings.TableCellAlignment; } //Set selected paragrpah layout attributes pdfLayoutSettings.SuppressSpacingBefore = true; pdfLayoutSettings.FirstParagraphAttributes = ParagraphAttributes(false, false, 0, false, false, false); pdfLayoutSettings.OtherParagraphAttributes = ParagraphAttributes(false, false, 0, false, false, false); pdfLayoutSettings.FirstParagraphAttributes = pdfLayoutSettings.OtherParagraphAttributes; writer.WriteStartElement("cell"); WriteCellAttributes(writer, node.Attributes, pdfLayoutSettings); if (node.ChildNodes.Count > 0) { writer.WriteStartElement("paragraph"); pdfLayoutSettings.InTextParagraph = true; pdfLayoutSettings.OpenParagraphCounter++; pdfLayoutSettings.ParagraphAlignment = GetParagraphAlignment(node); writer.WriteAttributeString("spacingbefore", (pdfLayoutSettings.SuppressSpacingBefore ? "0" : PARAGRAPH_SPACING.ToString())); if (!string.IsNullOrEmpty(pdfLayoutSettings.ParagraphAlignment.Key)) writer.WriteAttributeString(pdfLayoutSettings.ParagraphAlignment.Key, pdfLayoutSettings.ParagraphAlignment.Value); if (pdfLayoutSettings.IsFirstParagraph && !pdfLayoutSettings.CompletedFirstTextNode) { WriteParagraphAttributes(writer, pdfLayoutSettings.FirstParagraphAttributes); if (pdfLayoutSettings.PageBreakBefore) { writer.WriteAttributeString("startonnewpage", "true"); pdfLayoutSettings.PageBreakBefore = false; } } else { WriteParagraphAttributes(writer, pdfLayoutSettings.OtherParagraphAttributes); } ProcessClauseContent(writer, node.ChildNodes, pdfLayoutSettings, styleStack); pdfLayoutSettings.IsFirstParagraph = false; } // if (node.ChildNodes.Count > 0) if (pdfLayoutSettings.OpenParagraphCounter > 0) { writer.WriteEndElement(); //paragraph pdfLayoutSettings.OpenParagraphCounter--; } writer.WriteEndElement(); // cell //reset paragrpah layout attributes back to the saved values savedPdfLayoutSettings.CopyTo(ref pdfLayoutSettings); break; } #endregion #region unused table elements case "tbody": case "thead": case "tfoot": { ProcessClauseContent(writer, node.ChildNodes, pdfLayoutSettings, styleStack); break; } #endregion #region case "img" case "img": { PdfStyle currentStyle = styleStack.Peek(); writer.WriteStartElement("fragment"); writer.WriteAttributeString("font", TallPDFFontName(currentStyle.Font)); writer.WriteAttributeString("fontsize", currentStyle.Font.Size.ToString()); if (pdfLayoutSettings.SuppressSpaceBetweenFragments) if (!char.IsWhiteSpace(node.OuterXml[0])) writer.WriteAttributeString("suppressspacebefore", "true"); if (currentStyle.Font.Underline) writer.WriteAttributeString("underline", "true"); if (currentStyle.Font.Strikeout) writer.WriteAttributeString("strikeout", "true"); if (currentStyle.FontTransform == FontTransform.Subscript) writer.WriteAttributeString("subscript", "true"); else if (currentStyle.FontTransform == FontTransform.Superscript) writer.WriteAttributeString("superscript", "true"); writer.WriteString(Utility.XMLHelper.GetText(node)); writer.WriteEndElement(); //fragment break; } #endregion #region "itatImage" case XMLNames._A_ITATImageElement: { //do nothing. This is processed within the <p> tag, using the ProcessImage() method break; } #endregion #region default (throw exception) default: throw new Exception("XHTML Element not processed: " + node.OuterXml); #endregion } break; } #endregion #region NodeType == Text case XmlNodeType.Text: { bool createdNewParagraph = false; if (pdfLayoutSettings.OpenParagraphCounter <= 0) { createdNewParagraph = true; writer.WriteStartElement("paragraph"); //start new paragraph pdfLayoutSettings.InTextParagraph = true; pdfLayoutSettings.OpenParagraphCounter++; writer.WriteAttributeString("spacingbefore", "0"); if (!string.IsNullOrEmpty(pdfLayoutSettings.ParagraphAlignment.Key)) writer.WriteAttributeString(pdfLayoutSettings.ParagraphAlignment.Key, pdfLayoutSettings.ParagraphAlignment.Value); if (pdfLayoutSettings.IsFirstParagraph) { WriteParagraphAttributes(writer, pdfLayoutSettings.FirstParagraphAttributes); if (pdfLayoutSettings.PageBreakBefore) { writer.WriteAttributeString("startonnewpage", "true"); pdfLayoutSettings.PageBreakBefore = false; } } else WriteParagraphAttributes(writer, pdfLayoutSettings.OtherParagraphAttributes); } PdfStyle currentStyle = styleStack.Peek(); writer.WriteStartElement("fragment"); writer.WriteAttributeString("font", TallPDFFontName(currentStyle.Font)); if (currentStyle.PreserveWhiteSpace) writer.WriteAttributeString("preservewhitespace", "true"); //RLR,DG v1.5 - added to preserve formatting in text terms (e.g., line breaks) writer.WriteAttributeString("fontsize", currentStyle.Font.Size.ToString()); if (pdfLayoutSettings.SuppressSpaceBetweenFragments) if (!char.IsWhiteSpace(node.Value[0])) writer.WriteAttributeString("suppressspacebefore", "true"); if (currentStyle.Font.Underline) writer.WriteAttributeString("underline", "true"); if (currentStyle.Font.Strikeout) writer.WriteAttributeString("strikeout", "true"); if (currentStyle.FontTransform == FontTransform.Subscript) writer.WriteAttributeString("subscript", "true"); else if (currentStyle.FontTransform == FontTransform.Superscript) writer.WriteAttributeString("superscript", "true"); writer.WriteString(node.Value); writer.WriteEndElement(); //fragment //if THIS node does NOT end with a space, then suppress the extra space before the NEXT fragment pdfLayoutSettings.SuppressSpaceBetweenFragments = (!node.Value.EndsWith(" ")); pdfLayoutSettings.CompletedFirstTextNode = true; if (createdNewParagraph) { writer.WriteEndElement(); //paragraph pdfLayoutSettings.OpenParagraphCounter--; } break; } #endregion #region NodeType == Whitespace case XmlNodeType.Whitespace: { bool createdParagraph = false; if (pdfLayoutSettings.OpenParagraphCounter <= 0) { writer.WriteStartElement("paragraph"); createdParagraph = true; pdfLayoutSettings.OpenParagraphCounter++; writer.WriteAttributeString("type", "textparagraph"); writer.WriteAttributeString("spacingbefore", (pdfLayoutSettings.SuppressSpacingBefore ? "0" : PARAGRAPH_SPACING.ToString())); } PdfStyle currentStyle = styleStack.Peek(); writer.WriteStartElement("fragment"); writer.WriteAttributeString("font", TallPDFFontName(currentStyle.Font)); writer.WriteAttributeString("fontsize", currentStyle.Font.Size.ToString()); if (pdfLayoutSettings.SuppressSpaceBetweenFragments) writer.WriteAttributeString("suppressspacebefore", "true"); if (currentStyle.Font.Underline) writer.WriteAttributeString("underline", "true"); if (currentStyle.Font.Strikeout) writer.WriteAttributeString("strikeout", "true"); writer.WriteString(node.Value); writer.WriteEndElement(); //fragment if (createdParagraph) { writer.WriteEndElement(); // paragraph pdfLayoutSettings.OpenParagraphCounter--; } //DO NOT suppress the space before the NEXT fragment pdfLayoutSettings.SuppressSpaceBetweenFragments = false; break; } #endregion #region unused NodeTypes (throw exception) case XmlNodeType.SignificantWhitespace: case XmlNodeType.Attribute: case XmlNodeType.CDATA: case XmlNodeType.Comment: case XmlNodeType.Document: case XmlNodeType.DocumentFragment: case XmlNodeType.DocumentType: case XmlNodeType.EndElement: case XmlNodeType.EndEntity: case XmlNodeType.Entity: case XmlNodeType.EntityReference: case XmlNodeType.None: case XmlNodeType.Notation: case XmlNodeType.ProcessingInstruction: case XmlNodeType.XmlDeclaration: default: throw new Exception(string.Format("XHTML Node not processed: NodeType={0}, OuterXml= ", node.NodeType.ToString(), node.OuterXml)); #endregion } } }
private static PdfStyle GetStyleFromFontElement(XmlNode node, PdfStyle currentStyle) { //parse <font> tag and return a corresponding Font obejct XmlAttribute attrFace = node.Attributes["face"]; XmlAttribute attrSize = node.Attributes["size"]; PdfStyle rtn = new PdfStyle(); if (attrFace == null) rtn.Font.Name = currentStyle.Font.Name; else rtn.Font.Name = attrFace.Value; if (attrSize == null) rtn.Font.Size = currentStyle.Font.Size; else rtn.Font.Size = ConvertFontSize(attrSize.Value); return rtn; }
private static PdfStyle DefaultStyle() { PdfStyle rtn = new PdfStyle(); rtn.Font.Name = "timesroman"; rtn.Font.Size = new FontUnit(12); return rtn; }