使用 Open XML 2.0 在 Excel 中获取单元格背景色

本文关键字:获取 单元格 背景色 Excel Open XML 使用 | 更新日期: 2023-09-27 18:35:17

我正在尝试在Excel电子表格中获取单元格的背景色。我正在使用 Open XML 2.0 SDK,例如,我能够打开 *.xlsx 文件并获取单元格值。我获取背景色的代码如下:

   public BackgroundColor GetCellBackColor(Cell theCell, SpreadsheetDocument document)
    {
        BackgroundColor backGroundColor = null;
        WorkbookStylesPart styles = SpreadsheetReader.GetWorkbookStyles(document);
        int cellStyleIndex = (int)theCell.StyleIndex.Value;
        CellFormat cellFormat = (CellFormat)styles.Stylesheet.CellFormats.ChildElements[cellStyleIndex];
        Fill fill = (Fill)styles.Stylesheet.Fills.ChildElements[(int)cellFormat.FillId.Value];
        backGroundColor = fill.PatternFill.BackgroundColor;
        return backGroundColor;
    }

我的问题是,PatternFill.BackgroundColor只返回一个自然数,我认为它是样式的 id。我的问题是,代码行

DocumentFormat.OpenXml.Spreadsheet.Color c = (DocumentFormat.OpenXml.Spreadsheet.Color)styles.Stylesheet.Colors.ChildElements[Int32.Parse(backGroundColor.InnerText)];

返回错误,因为Stylesheet.Colors null...也许是因为我在 excel 中使用了"内置"颜色 - 而不是自定义颜色?!

任何想法如何从"backGroundColor-Value"中"计算"真正的颜色数字?

使用 Open XML 2.0 在 Excel 中获取单元格背景色

Excel 电子表格中单元格的填充模式为由两种颜色组成:背景色和前景色。术语前景色在这里有点误导。它不是字体的颜色,但图案填充的前景色。

例如,如果用纯色填充单元格的背景单元格的关联PatternFill对象的ForegroundColor属性设置为选定的纯色值,其中作为 BackgroundColor 对象设置为系统前景色。的PatternType属性 PatternFill对象设置为 PatternValues.Solid

因此,要获得单元格背景(纯色填充)的颜色值,您必须分析相关PatternFill对象的ForegroundColor属性。你必须确定实例表示的"颜色类型":

  1. 自动颜色和系统相关颜色
  2. 索引颜色。
  3. ARGB 颜色(阿尔法、红色、绿色和蓝色)
  4. 基于主题的颜色。
  5. 应用于颜色的色调值。

有关不同"颜色类型"的更多信息,请参阅以下内容链接。

请注意,ForegroundColorBackgroundColorInnerText属性的含义类取决于颜色类型。例如,在基于主题的颜色的情况下,InnerText属性设置为ColorScheme集合中的索引。

下面的示例打印电子表格文档中所有单元格的所有背景色信息:

public static PatternFill GetCellPatternFill(Cell theCell, SpreadsheetDocument document)
{ 
  WorkbookStylesPart styles = SpreadsheetReader.GetWorkbookStyles(document);
  int cellStyleIndex;
  if (theCell.StyleIndex == null) // I think (from testing) if the StyleIndex is null
  {                               // then this means use cell style index 0.
    cellStyleIndex = 0;           // However I did not found it in the open xml 
  }                               // specification.
  else
  {
    cellStyleIndex = (int)theCell.StyleIndex.Value;
  }      
  CellFormat cellFormat = (CellFormat)styles.Stylesheet.CellFormats.ChildElements[cellStyleIndex];
  Fill fill = (Fill)styles.Stylesheet.Fills.ChildElements[(int)cellFormat.FillId.Value];
  return fill.PatternFill;  
}
private static void PrintColorType(SpreadsheetDocument sd, DocumentFormat.OpenXml.Spreadsheet.ColorType ct)
{
  if (ct.Auto != null)
  {
    Console.Out.WriteLine("System auto color");
  }
  if (ct.Rgb != null)
  {
    Console.Out.WriteLine("RGB value -> {0}", ct.Rgb.Value);
  }
  if (ct.Indexed != null)
  {
    Console.Out.WriteLine("Indexed color -> {0}", ct.Indexed.Value);
    //IndexedColors ic = (IndexedColors)styles.Stylesheet.Colors.IndexedColors.ChildElements[(int)bgc.Indexed.Value];         
  }
  if (ct.Theme != null)
  {
    Console.Out.WriteLine("Theme -> {0}", ct.Theme.Value);
    Color2Type c2t = (Color2Type)sd.WorkbookPart.ThemePart.Theme.ThemeElements.ColorScheme.ChildElements[(int)ct.Theme.Value];
    Console.Out.WriteLine("RGB color model hex -> {0}", c2t.RgbColorModelHex.Val);
  }
  if (ct.Tint != null)
  {
    Console.Out.WriteLine("Tint value -> {0}", ct.Tint.Value);
  }
}
static void ReadAllBackgroundColors()
{
  using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Open("c:''temp''bgcolor.xlsx", false))
  {
    WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart;
    foreach(WorksheetPart worksheetPart in workbookPart.WorksheetParts)
    {
      SheetData sheetData = worksheetPart.Worksheet.Elements<SheetData>().First();
      foreach (Row r in sheetData.Elements<Row>())
      {
        foreach (Cell c in r.Elements<Cell>())
        {            
          Console.Out.WriteLine("----------------");
          PatternFill pf = GetCellPatternFill(c, spreadsheetDocument);        
          Console.Out.WriteLine("Pattern fill type -> {0}", pf.PatternType.Value);
          if (pf.PatternType == PatternValues.None)
          {
            Console.Out.WriteLine("No fill color specified");
            continue;
          }
          Console.Out.WriteLine("Summary foreground color:");
          PrintColorType(spreadsheetDocument, pf.ForegroundColor);
          Console.Out.WriteLine("Summary background color:");
          PrintColorType(spreadsheetDocument, pf.BackgroundColor);                          
        }
      }     
    }
  }
}
static void Main(string[] args)
{ 
  ReadAllBackgroundColors();
}

好吧,我有一个类似的用例,我需要测试哪种 RGB 颜色作为背景颜色应用于单元格。只需从函数追加到代码,

backGroundColor = fill.PatternFill.BackgroundColor.Rgb.Value;
return backgroundColor;

这将返回单元格背景中使用的 Rgb 颜色值。

汉斯的回答很棒!我想添加它,因为我必须解析某些列的渐变填充。这是我的解决方案:

我只是想获取 rgb 字符串,如果您的要求不同,则必须相应地更改返回类型。

public static IEnumerable<string> GetCellFillColors(string sheetName,
     string addressName, WorkbookPart wbPart)
    {
        WorkbookStylesPart styles = wbPart.WorkbookStylesPart;
        Sheet theSheet = wbPart.Workbook.Descendants<Sheet>().
          Where(s => s.Name == sheetName).FirstOrDefault();
        // Throw an exception if there is no sheet.
        if (theSheet == null)
        {
            throw new ArgumentException("sheetName");
        }
        // Retrieve a reference to the worksheet part.
        WorksheetPart wsPart =
            (WorksheetPart)(wbPart.GetPartById(theSheet.Id));
        // Use its Worksheet property to get a reference to the cell 
        // whose address matches the address you supplied.
        Cell theCell = wsPart.Worksheet.Descendants<Cell>().
          Where(c => c.CellReference == addressName).FirstOrDefault();
        int cellStyleIndex;
        if (theCell.StyleIndex == null) // I think (from testing) if the StyleIndex is null
        {                               // then this means use cell style index 0.
            cellStyleIndex = 0;           // However I did not found it in the open xml 
        }                               // specification.
        else
        {
            cellStyleIndex = (int)theCell.StyleIndex.Value;
        }
        CellFormat cellFormat = (CellFormat)styles.Stylesheet.CellFormats.ChildElements[cellStyleIndex];
        DocumentFormat.OpenXml.Spreadsheet.Fill fill = (DocumentFormat.OpenXml.Spreadsheet.Fill)styles.Stylesheet.Fills.ChildElements[(int)cellFormat.FillId.Value];
        if (fill.PatternFill != null)
        {
            return fill.PatternFill?.BackgroundColor?.Rgb?.ToString() != null ?
            new List<string>()
            {
                fill.PatternFill?.BackgroundColor?.Rgb?.ToString()
            } : new List<string>();
        }
        if (fill.GradientFill != null)
        {
            var colors = fill.GradientFill.ChildElements.Select(e => (DocumentFormat.OpenXml.Spreadsheet.GradientStop)e);
            return colors?.Select(c => c?.Color.Rgb?.ToString());
        }
        return null;
    }