FormatCondition to change cell color no longer working in several use cases

We recently had a defect appear in our product, and we have chased it down to something having changed in aspose-cells for java 21.12. 21.11 works as before, then the change happened in 21.12 and the change persists in every release we’ve tried after that up to 24.2.

In the release notes:

I suspect one of these two may be the culprit (based solely on the title as I know no details of each):

CELLSJAVA-43469
“Possible regression: Performance degradation of FormatConditionCollection.addArea()”

CELLSJAVA-44000
“Cells style is incorrect in HTML when using icon set and other conditional formatting at the same time”

What we found is that having several FormatConditions on a cell, to set the color of a cell based on a text value, no longer sets the correct color of every cell. We were able to figure out a workaround that involves creating one FormatConditionCollection per FormatCondition that we want to set, then doing a addArea() for each of those FormatConditionCollections. This creates unnecessary collections, since the whole point of a collection should be to store more than one element, not just a single element. But, I confirmed adding more elements then doing a addArea() of the entire collection breaks the colors from 21.12 onward.

Here is our standalone test file that demonstrates a case that works, plus several that don’t. Simply put the approriate jar in the classpath, comment out the case you want to try, run it, then open up the output file.

MainCells.java.zip (2.2 KB)

Here’s a code snippet of broken1() so others can see what this is about:

    public static void broken1(Worksheet worksheet) {
        CellArea area = CellArea.createCellArea(2, 1, 4, 1);
        ConditionalFormattingCollection cfs = worksheet.getConditionalFormattings();

        // Create one collection; should be able to hold 3 FormatConditions, right?
        int index = cfs.add();
        FormatConditionCollection fcs = cfs.get(index);

        // Create 3 FormatConditions, one per column value that we have
        int i1 = fcs.addCondition(FormatConditionType.CELL_VALUE, OperatorType.EQUAL, "first", null);
        int i2 = fcs.addCondition(FormatConditionType.CELL_VALUE, OperatorType.EQUAL, "second", null);
        int i3 = fcs.addCondition(FormatConditionType.CELL_VALUE, OperatorType.EQUAL, "third", null);
        FormatCondition fc1 = fcs.get(i1);
        FormatCondition fc2 = fcs.get(i2);
        FormatCondition fc3 = fcs.get(i3);

        // Get each condition's style
        Style ss1 = fc1.getStyle();
        Style ss2 = fc2.getStyle();
        Style ss3 = fc3.getStyle();

        // Create the colors
        // NOTE: replace these RGB values with built-in colors and it somehow works
        Color color1 =  hex2Color("FF0000");
//        Color color1 = Color.getRed();
        Color color2 =  hex2Color("FFFF66");
//        Color color2 = Color.getYellow();
        Color color3 =  hex2Color("9BDFFF");
//        Color color3 = Color.getBlue();

        // Set those colors as the background of each style when that condition triggers
        ss1.setBackgroundColor(color1);
        ss2.setBackgroundColor(color2);
        ss3.setBackgroundColor(color3);
        fc1.setStyle(ss1);
        fc2.setStyle(ss2);
        fc3.setStyle(ss3);

        // Set this whole collection on the area all at once. I would expect this to be able to apply all the conditions in this collection
        // to the area.
        fcs.addArea(area);
    }

Here’s an explanation of the various scenarios in that file:

works(): We got this one to work by creating one collection per condition. And, each condition has to be fully processed to the point of calling addArea() before moving on to the next condition.

broken1(): This attempts to use one collection for all 3 of the conditions, followed by a single addArea() at the end. This used to work. What’s extra strange here is if I create the Color instances using convenience methods like Color.getRed() instead of the RGB values, it gets the colors correct! We have to use RGB values though; convenience methods for colors would reduce functionality of our product.

broken2(): This is same as broken1() but rearranged so that each condition is fully processed before moving on to the next condition.

broken3(): This is a variation of works() in that we’re still making one collection per condition. All that changed is that work on each condition is interspersed so that we’re not completing all the work for one condition all in one block of code. But, this line of code will fail with an index out of bounds:

int i1 = fcs1.addCondition(FormatConditionType.CELL_VALUE, OperatorType.EQUAL, “first”, null);

It does not seem logical to me that there should be an index out of bounds, since the API calls that created the collection then the condition are using the index returned by the Aspose API, not some incorrect number we made up.

Here is what the colors look like when it works:

image.jpg (190.1 KB)

And when it doesn’t work:

image.jpg (180.1 KB)

Any help here much appreciated! And, we’d really like if it could go back to working as it did in 21.11. Thanks!

@chuckw,

I have reviewed your scenario and the sample code segment from your resource files. For the XLS file format (Microsoft Excel (97-2003)), there is a limitation regarding the color palette, which allows only 56 colors to be applied to cells, fonts, gridlines, graphic objects, fills, and lines in a chart. When you want to apply custom colors as background fills, you need to add those custom colors to the palette. It’s important to note that this limitation only applies to the XLS (Excel 97 - 2003) file format, and there is no such limitation for XLSX (2007 - 2019/2022) or other advanced MS Excel file formats.

For your case to workaround it, you can simply add your custom colors to the palette so that when you save the file in XLS format, the color is properly applied to the cells. For example, in the case of broken1 and broken2 functions, please try adding the following lines of code, and it will work as expected. (I have also tested this):

workbook.changePalette(color1,55);
workbook.changePalette(color2,54);
workbook.changePalette(color3,53);

Hope, this helps a bit.

Interesting, so that may explain why I get different results when using RGB colors versus the convenience methods.

But, why does my example code have scenarios where the colors work versus not, based on whether I put more than one condition in a collection? I am not creating more colors in one example versus the other example. And, why did it work in Aspose 21.11 and not in 21.12? I think there is more going on here than just a color pallette.

For my example that works, should I still be adding to the color palette as you show here even though it didn’t have a color issue? How do I know what integer value to give it? We use picklists that pull from several dozen possible colors, so there’s quite a few.

After pondering this some more, it would seem your implementation (at least from 21.12 onward) has a characteristic about it where it can handle working with exactly one custom color at a time that hasn’t been added to the palette. If I try to use more than one color at once, by using a collection with more than one condition in it (and thus more than one color), then do addArea(), that’s where the colors stomp on each other. And, if I interlace my code so that it is working with more than one color at a time prior to the addArea() call, it has that same effect of colors stomping on each other. So, somehow being careful to only work with one color at a time somehow tip toes around the implementation detail to make this possible?

Any further confirmation on this would be appreciated, since I want to make sure our defect fix is as robust as possible. It is working now with no changePalette() call as long as I only touch one color at a time before each addArea() call. Although, I don’t know how robust that is.

If I do need to call changePalette() to make it more robust, I did some experiments and see I can print out all 56 colors in the palette currently there (which it defaulted to these 56 colors; we didn’t create any of them). Outside of this specific feature of ours I’m dealing with now, we only use the colors black and white (via calls to Color.getBlack and Color.getWhite). So, if a bunch of changePalette() calls really are needed, I would imagine I could fill up 54 of the 56 color slots as long as I don’t overwrite black or white. Right? Our color picker has 45 choices, so it looks like they’d all fit if a customer managed to actually use all 45 of them.

@chuckw
By using sample code for testing, we are able to reproduce the issue. Unable to apply formatting when adding multiple formatting conditions.

We have opened the following new ticket(s) in our internal issue tracking system and will deliver their fixes according to the terms mentioned in Free Support Policies.

Issue ID(s): CELLSJAVA-45883

You can obtain Paid Support Services if you need support on a priority basis, along with the direct access to our Paid Support management team.

@chuckw,

Your findings and provided details are logical and make sense, and they should be investigated in detail. Since we have already logged a ticket with the ID “CELLSJAVA-45883” for your issue, please spare us a little time to evaluate your issue in detail, and hopefully we can figure it out soon.

We apologize for any inconvenience caused!

1 Like

Thank you very much, I’ll go with our current workaround and will wait to see how this new ticket progresses!

@chuckw,

Sure, and hopefully we will resolve the issue soon. Once we have an update on it, we will let you know.

@chuckw
We have fixed CELLSJAVA-45883. The fix will be included in the next release (Aspose.Cells v24.3) scheduled for release this week or next week in March. You will be notified when the next version is published.

1 Like

That is impressively fast, thanks!

@chuckw
You are welcome. If you have any questions, please feel free to contact us.

The issues you have found earlier (filed as CELLSJAVA-45883) have been fixed in Aspose.Cells for Java 24.3.