Using Epplus to read spreadsheet and determine all the cell's style, including conditionally format - conditional-formatting

I am using Epplus (C#.net) to read the values and the styling of cells(background and font color) in a spreadsheet, that is protected and locked.
Style.Fill.BackgroundColor.Rgb; Style.Fill.BackgroundColor.Theme and Style.Font.Color.Rgb; Style.Font.Color
work correctly in most of the cells. I am running into a problem with cells that are using the conditional format 'Format only unique or duplicate values'. Background and Font colors are being returned from Epplus as null.
Here is the code to get the background/font color from a particular cell
private ExcelStyleLoad GetStyleInfo(ExcelRange currentCell)
{
ExcelStyleLoad retval = new ExcelStyleLoad();
//background
retval.BackgroundColor = currentCell.Style.Fill.BackgroundColor.Rgb;
retval.BackgroundTheme = currentCell.Style.Fill.BackgroundColor.Theme;
//font
retval.FontColor = currentCell.Style.Font.Color.Rgb;
retval.FontTheme = currentCell.Style.Font.Color.Theme;
//other
retval.isBold = currentCell.Style.Font.Bold;
retval.isUnderline = currentCell.Style.Font.UnderLine;
retval.isItalics = currentCell.Style.Font.Italic;
retval.FullAddress = currentCell.FullAddress;
return retval;
}
I have also tried to use currentCell.ConditionalFormatting.AddDuplicateValues() to determine the background/font color and have had no success.
Any suggestions how I can get the background/font color of the cells that are using the ConditionalFormatting?

In my understanding, cells with conditional formatting do not (necessarily) have a backgroundcolor, they just have the conditional formatting rule. The background colour is infered from the value and the rule when the sheet is being displayed.
This meets your observation.
So you will have to look for conditional formatting in the cells and calculate the colour values yourself when reading the formatting. That's little hope in your case where the sheet is protected and locked.
Anyway, you should be able to determine unique / duplicate cells even in protected and locked sheets. Good luck!

Related

get cell fill color using openpyxl

I would like to get the background fill value for a particular cell in a sheet using openpyxl. I thought that the selected answer from this post openpyxl : Is there a way to search an Excel spreadsheet for cells with specific fill color? would help me, but it isn't working properly.
Here is my current code:
wb1 = Workbook()
ws1 = wb1.create_sheet('new sheet', 0)
ws1.cell(1,1).value = 0.5 # cell A1
rule = ColorScaleRule(start_type='num', start_value=0, start_color='FFFFFF',
end_type='num', end_value=1, end_color='FF007F')
ws1.add(range_string='A1', cfRule=rule)
print('rgb_fg: ', ws1.cell(1,1).fill.fgColor.rgb)
print('rgb_bg: ', ws1.cell(1,1).fill.bgColor.rgb)
output:
rgb_fg: 00000000
rgb_bg: 00000000
Since I assigned 0.5 as the value of cell "A1" in ws1, then I would have no reason to think that the rgb of this cell would be 00000000 (black). It should be a light salmon red color, which is what I get if the sheet is saved and I view it.
Note I printed fgColor and bgColor just to cover all my bases (or the ones I can think of)
Perhaps something funky happens when a ColorScaleRule is applied to a cell so its fill value can't be read in the way I expect?
Conditional formatting is not handled the same way as static colors. Background colors from those conditional rules are dynamic and therefore left to only be applied by spreadsheet software, not the library itself. Therefore, you will not be able to determine this value with openpyxl.
The good news is that if you were to save the spreadsheet, you would see that your code is correct and the cell does appear pink.

How to iterate over an Excel file and ID colored cell values

I have an excel workbook that has cells of a column colored with specific colors to keep or exclude certain users that will then be used to filter another excel workbook.
I want to loop through this column and identify cells with red background and add a functional column stating 0 and identify cells with yellow background and add 1 to this same functional column so as to work as the filter for the other workbook.
I'm hoping to use OpenPyXL to complete this task.
column_pi = ws["A"]
for cell in column_pi:
f cell.fill.fgColor == "00FF0000": # Red Hex
# add column stating 0 as value
Have also tried this but no luck, returning nothing
red_fill = PatternFill(fill_type=None, start_color='00FF0000', end_color='00FF0000')
yellow_fill = PatternFill(fill_type=None, start_color='00FFFF00', end_color='00FFFF00')
for cell in column_pi:
if cell.fill == yellow_fill:
print(cell)
Works with no hex codes provided for no_fill
no_fill = PatternFill(fill_type=None)
for cell in column_pi:
if cell.fill == no_fill:
print(cell)
Any thoughts on the best way to iterate over the values and check the fill/background color are of a specific color and then add a functional column like this?
fill is a set of more complicated variables, so looking for it to be exactly equal only to red_fill or yellow_fill here isn't going to work. The complication is mostly due to being able to set a colour either as a static rgba value, or as one that will automatically update when the theme is changed. Styles in openpyxl, with parameters like PatternFill, are easy ways to set multiple of these values at once.
If you look up cell.fill for a particular cell, it returns something like:
<openpyxl.styles.fills.PatternFill object>
Parameters:
patternType='solid', fgColor=<openpyxl.styles.colors.Color object>
Parameters:
rgb='FFD9D9D9', indexed=None, auto=None, theme=None, tint=0.0, type='rgb', bgColor=<openpyxl.styles.colors.Color object>
Parameters:
rgb='00000000', indexed=None, auto=None, theme=None, tint=0.0, type='rgb'
You can specify these values directly as part of cell.fill.fill_type (synonym for cell.fill.patternType), cell.fill.fgColor, and cell.fill.bgColor. Plus sub-attributes like cell.fill.fgColor.rgb.
You could also make it quicker by picking knowncell.fill.fgColor of a cell you know to have red_fill, if one exists. That way, you could check any of fill_type, fgColor and/or bgColor match. Try:
red_fill = knowncell.fill
for cell in column_pi:
if cell.fill.fgColor == red_fill.fgColor and cell.fill.fill_type == red_fill.fill_type:
print(cell)
However, you can't match knowncell.fill directly with cell.fill, I think because a new openpyxl style object is created each time you define a new one.

Check if MigraDoc font of a row is bold or not

I have a MigraDoc Table with multiple rows . I am trying to find if a particular row is bold or not
if(table.Rows[0].Font.bold ==font.bold)
{
Do Something
}
Idea is to change the colour of that row to a specific one.
There are many ways to set font attributes with MigraDoc. What do you want to happen if some columns are bold and some are not? Or if some columns contain both bold and regular text?
The clean approach would be determining the color of the row when you add contents to it. Each MigraDoc document element has a Tag member of type object that you can use for your own purposes.
When filling the row you can set the color directly. Or you can use the Tag member to mark the row as "important" and set the colors for important rows at a later stage.
Untested code that may work - and since there are several ways to make text bold, this will work only if the code that fills the rows also sets the Bold property to true:
if (table.Rows[0].Format.Font.Bold == true)
{
Do Something
}
The above will not work if a row is "bold", but the boldness comes from a Style or is set via paragraph properties.
IMHO using the Tag member is a cleaner way.

Conditional Format Based on color code

I need to conditional format background color of Columns O:Y based on the color code AF:AK, is there a conditional format formula, or VBA code I can use.
Please ignore current format on columns O:X
You can't set the background colour to match the numbers directly in those cells with conditional formatting, though it is possible using VBA.
However, it is easier to check the value of the cells using the standard Conditional formatting rules and set the colours manually. This means you can have any colour matched to any number. Of course, you can choose the correct colour to fill if this is important to the solution.
I have set this up on a sheet below. I put the conditional formatting formula in the first cell (removing the $ symbol the system puts in for you) and copy across and down.

In Apache POI HSSF, Cell Type Still Shows Up as "General" Excel, Even Though it's Number-Formatted

I am using Apache POI HSSF to generate an Excel spreadsheet from my Java Web app.
I need a cell formatted as "Number" with 2 decimal points. (My values in Java are BigDecimals, but I can convert them to doubles, no problem.) I am using this code:
CellStyle numericStyle = wb.createCellStyle();
numericStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("#,##0.00"));
// output in this new style...
row.createCell(cellnum).setCellValue(((BigDecimal)value).doubleValue());
row.getCell(cellnum).setCellStyle(numericStyle);
The issue is that, even though this works, Excel still shows my cells as General. They need to be shown as Number. As a result, for example, 0 is shown as 0, but it should be 0.00, which would happen if the format was correct (Number).
I see that it gets generated as General because I can right-click on a cell and then choose "Format Cells" to see what it is right now. It needs to be set to "Number" by Apache POI HSSF.
Reviewing the Apache POI API it looks like you should be able to specify the cell's type.
...
Cell cell = row.createCell(...);
cell.setCellType(Cell.CELL_TYPE_NUMERIC);
...
I'm assuming you haven't yet found an answer for your question.
One way to display numbers with two decimals is to set a cell style. This allows you to customize the number of decimal places and the decimal separator, among other things.
protected CellStyle getCellStyle(HSSFWorkbook workbook) {
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setDataFormat(
workbook.getCreationHelper().createDataFormat().getFormat("#,##0.00"));
return cellStyle;
}
Later on, when you fill your workbook, you apply this cellStyle to the desired cells:
CellStyle cellStyle = getCellStyle();
//...
// create your cell
cell.setCellStyle(cellStyle);
// set the value
It won't show as numeric type in Excel. It shows as Custom type. But visually it should be the same, or at least close enough.