/// <summary> /// Gets an attribute representing a single border side. /// If a border style/color/width has been specified individually, it will override the grouped definition. /// </summary> /// <returns>If the attribute is misformed, the <see cref="HtmlBorder.IsValid"/> property is set to false.</returns> public SideBorder GetAsSideBorder(String name) { string attrValue = this[name]; SideBorder border = SideBorder.Parse(attrValue); // handle attributes specified individually. Unit width = SideBorder.ParseWidth(this[name + "-width"]); if (width.IsValid) { border.Width = width; } var color = GetAsColor(name + "-color"); if (!color.IsEmpty) { border.Color = color; } var style = ConverterUtility.ConvertToBorderStyle(this[name + "-style"]); if (style != w.BorderValues.Nil) { border.Style = style; } return(border); }
/// <summary> /// Gets an attribute representing a color (named color, hexadecimal or hexadecimal /// without the preceding # character). /// </summary> public System.Drawing.Color GetAsColor(String name) { string attrValue = this[name]; if (attrValue != null) { return(ConverterUtility.ConvertToForeColor(attrValue)); } return(System.Drawing.Color.Empty); }
/// <summary> /// Gets the font attribute and combine with the style, size and family. /// </summary> public HtmlFont GetAsFont(String name) { HtmlFont font = HtmlFont.Parse(this[name]); string attrValue = this[name + "-style"]; if (attrValue != null) { var style = ConverterUtility.ConvertToFontStyle(attrValue); if (style.HasValue) { font.Style = style.Value; } } attrValue = this[name + "-variant"]; if (attrValue != null) { var variant = ConverterUtility.ConvertToFontVariant(attrValue); if (variant.HasValue) { font.Variant = variant.Value; } } attrValue = this[name + "-weight"]; if (attrValue != null) { var weight = ConverterUtility.ConvertToFontWeight(attrValue); if (weight.HasValue) { font.Weight = weight.Value; } } attrValue = this[name + "-family"]; if (attrValue != null) { font.Family = ConverterUtility.ConvertToFontFamily(attrValue); } Unit unit = this.GetAsUnit(name + "-size"); if (unit.IsValid) { font.Size = unit; } return(font); }
public static SideBorder Parse(String str) { if (str == null) { return(SideBorder.Empty); } // The properties of a border that can be set, are (in order): border-width, border-style, and border-color. // It does not matter if one of the values above are missing, e.g. border:solid #ff0000; is allowed. // The main problem for parsing this attribute is that the browsers allow any permutation of the values... meaning more coding :( // http://www.w3schools.com/cssref/pr_border.asp List <String> borderParts = new List <String>(str.Split(HttpUtility.WhiteSpaces, StringSplitOptions.RemoveEmptyEntries)); if (borderParts.Count == 0) { return(SideBorder.Empty); } // Initialize default values Unit borderWidth = Unit.Empty; Color borderColor = Color.Empty; w.BorderValues borderStyle = w.BorderValues.Nil; // Now try to guess the values with their permutation // handle border style for (int i = 0; i < borderParts.Count; i++) { borderStyle = ConverterUtility.ConvertToBorderStyle(borderParts[i]); if (borderStyle != w.BorderValues.Nil) { borderParts.RemoveAt(i); // no need to process this part anymore break; } } for (int i = 0; i < borderParts.Count; i++) { borderWidth = ParseWidth(borderParts[i]); if (borderWidth.IsValid) { borderParts.RemoveAt(i); // no need to process this part anymore break; } } // find width if (borderParts.Count > 0) { borderColor = ConverterUtility.ConvertToForeColor(borderParts[0]); } // returns the instance with default value if needed. // These value are the ones used by the browser, i.e: solid 3px black return(new SideBorder( borderStyle == w.BorderValues.Nil? w.BorderValues.Single : borderStyle, borderColor.IsEmpty? Color.Black : borderColor, borderWidth.IsFixed? borderWidth : new Unit(UnitMetric.Pixel, 4))); }
/// <summary> /// Move inside the current tag related to table (td, thead, tr, ...) and converts some common /// attributes to their OpenXml equivalence. /// </summary> /// <param name="en">The Html enumerator positionned on a <i>table (or related)</i> tag.</param> /// <param name="runStyleAttributes">The collection of attributes where to store new discovered attributes.</param> public void ProcessCommonAttributes(HtmlEnumerator en, IList <OpenXmlElement> runStyleAttributes) { List <OpenXmlElement> containerStyleAttributes = new List <OpenXmlElement>(); var colorValue = en.StyleAttributes.GetAsColor("background-color"); // "background-color" is also handled by RunStyleCollection which duplicate this attribute (bug #13212). Let's ignore it if (!colorValue.IsEmpty && en.CurrentTag.Equals("<td>", StringComparison.InvariantCultureIgnoreCase)) { colorValue = System.Drawing.Color.Empty; } if (colorValue.IsEmpty) { colorValue = en.Attributes.GetAsColor("bgcolor"); } if (!colorValue.IsEmpty) { containerStyleAttributes.Add( new Shading() { Val = ShadingPatternValues.Clear, Color = "auto", Fill = colorValue.ToHexString() }); } var htmlAlign = en.StyleAttributes["vertical-align"]; if (htmlAlign == null) { htmlAlign = en.Attributes["valign"]; } if (htmlAlign != null) { TableVerticalAlignmentValues?valign = ConverterUtility.FormatVAlign(htmlAlign); if (valign.HasValue) { containerStyleAttributes.Add(new TableCellVerticalAlignment() { Val = valign }); } } htmlAlign = en.StyleAttributes["text-align"]; if (htmlAlign == null) { htmlAlign = en.Attributes["align"]; } if (htmlAlign != null) { JustificationValues?halign = ConverterUtility.FormatParagraphAlign(htmlAlign); if (halign.HasValue) { this.BeginTagForParagraph(en.CurrentTag, new KeepNext(), new Justification { Val = halign }); } } // implemented by ddforge String[] classes = en.Attributes.GetAsClass(); if (classes != null) { for (int i = 0; i < classes.Length; i++) { string className = documentStyle.GetStyle(classes[i], StyleValues.Table, ignoreCase: true); if (className != null) // only one Style can be applied in OpenXml and dealing with inheritance is out of scope { containerStyleAttributes.Add(new RunStyle() { Val = className }); break; } } } this.BeginTag(en.CurrentTag, containerStyleAttributes); // Process general run styles documentStyle.Runs.ProcessCommonAttributes(en, runStyleAttributes); }
/// <summary> /// There is a few attributes shared by a large number of tags. This method will check them for a limited /// number of tags (<p>, <pre>, <div>, <span> and <body>). /// </summary> /// <returns>Returns true if the processing of this tag should generate a new paragraph.</returns> public bool ProcessCommonAttributes(HtmlEnumerator en, IList <OpenXmlElement> styleAttributes) { if (en.Attributes.Count == 0) { return(false); } bool newParagraph = false; List <OpenXmlElement> containerStyleAttributes = new List <OpenXmlElement>(); string attrValue = en.Attributes["lang"]; if (attrValue != null && attrValue.Length > 0) { try { var ci = System.Globalization.CultureInfo.GetCultureInfo(attrValue); bool rtl = ci.TextInfo.IsRightToLeft; Languages lang = new Languages() { Val = ci.TwoLetterISOLanguageName }; if (rtl) { lang.Bidi = ci.Name; styleAttributes.Add(new Languages() { Bidi = ci.Name }); // notify table documentStyle.Tables.BeginTag(en.CurrentTag, new TableJustification() { Val = TableRowAlignmentValues.Right }); } containerStyleAttributes.Add(new ParagraphMarkRunProperties(lang)); containerStyleAttributes.Add(new BiDi() { Val = OnOffValue.FromBoolean(rtl) }); } catch (ArgumentException) { // lang not valid, ignore it } } attrValue = en.StyleAttributes["text-align"]; if (attrValue != null && en.CurrentTag != "<font>") { JustificationValues?align = ConverterUtility.FormatParagraphAlign(attrValue); if (align.HasValue) { containerStyleAttributes.Add(new Justification { Val = align }); } } // according to w3c, dir should be used in conjonction with lang. But whatever happens, we'll apply the RTL layout attrValue = en.Attributes["dir"]; if (attrValue != null) { if (attrValue.Equals("rtl", StringComparison.OrdinalIgnoreCase)) { styleAttributes.Add(new RightToLeftText()); containerStyleAttributes.Add(new Justification() { Val = JustificationValues.Right }); } else if (attrValue.Equals("ltr", StringComparison.OrdinalIgnoreCase)) { containerStyleAttributes.Add(new Justification() { Val = JustificationValues.Left }); } } // <span> and <font> are considered as semi-container attribute. When converted to OpenXml, there are Runs but not Paragraphs if (en.CurrentTag == "<p>" || en.CurrentTag == "<div>" || en.CurrentTag == "<pre>") { var border = en.StyleAttributes.GetAsBorder("border"); if (!border.IsEmpty) { ParagraphBorders borders = new ParagraphBorders(); if (border.Top.IsValid) { borders.Append( new TopBorder() { Val = border.Top.Style, Color = border.Top.Color.ToHexString(), Size = (uint)border.Top.Width.ValueInPx * 4, Space = 1U }); } if (border.Left.IsValid) { borders.Append( new LeftBorder() { Val = border.Left.Style, Color = border.Left.Color.ToHexString(), Size = (uint)border.Left.Width.ValueInPx * 4, Space = 1U }); } if (border.Bottom.IsValid) { borders.Append( new BottomBorder() { Val = border.Bottom.Style, Color = border.Bottom.Color.ToHexString(), Size = (uint)border.Bottom.Width.ValueInPx * 4, Space = 1U }); } if (border.Right.IsValid) { borders.Append( new RightBorder() { Val = border.Right.Style, Color = border.Right.Color.ToHexString(), Size = (uint)border.Right.Width.ValueInPx * 4, Space = 1U }); } containerStyleAttributes.Add(borders); newParagraph = true; } } else if (en.CurrentTag == "<span>" || en.CurrentTag == "<font>") { // OpenXml limits the border to 4-side of the same color and style. SideBorder border = en.StyleAttributes.GetAsSideBorder("border"); if (border.IsValid) { styleAttributes.Add(new DocumentFormat.OpenXml.Wordprocessing.Border() { Val = border.Style, Color = border.Color.ToHexString(), Size = (uint)border.Width.ValueInPx * 4, Space = 1U }); } } String[] classes = en.Attributes.GetAsClass(); if (classes != null) { for (int i = 0; i < classes.Length; i++) { string className = documentStyle.GetStyle(classes[i], StyleValues.Paragraph, ignoreCase: true); if (className != null) { containerStyleAttributes.Add(new ParagraphStyleId() { Val = className }); newParagraph = true; break; } } } Margin margin = en.StyleAttributes.GetAsMargin("margin"); Indentation indentation = null; if (!margin.IsEmpty) { if (margin.Top.IsFixed || margin.Bottom.IsFixed) { SpacingBetweenLines spacing = new SpacingBetweenLines(); if (margin.Top.IsFixed) { spacing.Before = margin.Top.ValueInDxa.ToString(CultureInfo.InvariantCulture); } if (margin.Bottom.IsFixed) { spacing.After = margin.Bottom.ValueInDxa.ToString(CultureInfo.InvariantCulture); } containerStyleAttributes.Add(spacing); } if (margin.Left.IsFixed || margin.Right.IsFixed) { indentation = new Indentation(); if (margin.Left.IsFixed) { indentation.Left = margin.Left.ValueInDxa.ToString(CultureInfo.InvariantCulture); } if (margin.Right.IsFixed) { indentation.Right = margin.Right.ValueInDxa.ToString(CultureInfo.InvariantCulture); } containerStyleAttributes.Add(indentation); } } // implemented by giorand (feature #13787) Unit textIndent = en.StyleAttributes.GetAsUnit("text-indent"); if (textIndent.IsValid && (en.CurrentTag == "<p>" || en.CurrentTag == "<div>")) { if (indentation == null) { indentation = new Indentation(); } indentation.FirstLine = textIndent.ValueInDxa.ToString(CultureInfo.InvariantCulture); containerStyleAttributes.Add(indentation); } this.BeginTag(en.CurrentTag, containerStyleAttributes); // Process general run styles documentStyle.Runs.ProcessCommonAttributes(en, styleAttributes); return(newParagraph); }
public static HtmlFont Parse(String str) { if (str == null) { return(HtmlFont.Empty); } // The font shorthand property sets all the font properties in one declaration. // The properties that can be set, are (in order): // "font-style font-variant font-weight font-size/line-height font-family" // The font-size and font-family values are required. // If one of the other values are missing, the default values will be inserted, if any. // http://www.w3schools.com/cssref/pr_font_font.asp // in order to split by white spaces, we remove any white spaces between 2 family names (ex: Verdana, Arial -> Verdana,Arial) str = System.Text.RegularExpressions.Regex.Replace(str, @",\s+?", ","); String[] fontParts = str.Split(HttpUtility.WhiteSpaces, StringSplitOptions.RemoveEmptyEntries); if (fontParts.Length < 2) { return(HtmlFont.Empty); } HtmlFont font = HtmlFont.Empty; if (fontParts.Length == 2) // 2=the minimal set of required parameters { // should be the size and the family (in that order). Others are set to their default values font.size = ReadFontSize(fontParts[0]); if (!font.size.IsValid) { return(HtmlFont.Empty); } font.family = ConverterUtility.ConvertToFontFamily(fontParts[1]); return(font); } int index = 0; FontStyle?style = ConverterUtility.ConvertToFontStyle(fontParts[index]); if (style.HasValue) { font.style = style.Value; index++; } if (index + 2 > fontParts.Length) { return(HtmlFont.Empty); } FontVariant?variant = ConverterUtility.ConvertToFontVariant(fontParts[index]); if (variant.HasValue) { font.variant = variant.Value; index++; } if (index + 2 > fontParts.Length) { return(HtmlFont.Empty); } FontWeight?weight = ConverterUtility.ConvertToFontWeight(fontParts[index]); if (weight.HasValue) { font.weight = weight.Value; index++; } if (fontParts.Length - index < 2) { return(HtmlFont.Empty); } font.size = ReadFontSize(fontParts[fontParts.Length - 2]); if (!font.size.IsValid) { return(HtmlFont.Empty); } font.family = ConverterUtility.ConvertToFontFamily(fontParts[fontParts.Length - 1]); return(font); }
private static Unit ReadFontSize(string str) { Unit size = ConverterUtility.ConvertToFontSize(str); return(size); // % and ratio font-size/line-height are not supported }
public static Unit Parse(String str) { if (str == null) { return(Unit.Empty); } str = str.Trim().ToLower(CultureInfo.InvariantCulture); int length = str.Length; int digitLength = -1; for (int i = 0; i < length; i++) { char ch = str[i]; if ((ch < '0' || ch > '9') && (ch != '-' && ch != '.' && ch != ',')) { break; } digitLength = i; } if (digitLength == -1) { // No digits in the width, we ignore this style return(str == "auto"? Unit.Auto : Unit.Empty); } UnitMetric type; if (digitLength < length - 1) { type = ConverterUtility.ConvertToUnitMetric(str.Substring(digitLength + 1).Trim()); } else { type = UnitMetric.Pixel; } string v = str.Substring(0, digitLength + 1); double value; try { TypeConverter converter = new DoubleConverter(); value = (double)converter.ConvertFromString(null, CultureInfo.InvariantCulture, v); if (value < Int16.MinValue || value > Int16.MaxValue) { return(Unit.Empty); } } catch (FormatException) { return(Unit.Empty); } catch (ArithmeticException) { return(Unit.Empty); } return(new Unit(type, value)); }