Dynamic Color for Reports


Userlevel 3
Badge

Good Morning,

i would like to search for a solution for my idea.
As this idea might be interesting for someone else, i thought it would be interesting to share it here.
We are currently in the process of creating new Standard Reports for our Customers that replace the 300+ Reports from Acumatica. To add a bit “color” to them, we often use textboxes or lines with a certain color. We would like to change the color based upon the main color of the logo that gets updated - or upon a user definied field that contains the hex of the color.

Customization:
» Step 1 | User uploads a Image at the Screen CS101500 (Most likely the company logo)
» Step 2 | Code starts to look through the Image and return the most used color.
» x--------| Example: For this Picture it would be “CornflowerBlue”
» Step 3 | Code iterates through a defined set of reports (since they are able to get edited within a text editor, i could see this working quite well) and searches within each report for a Color
» x------- | Example: Code opens Report SO641010 - finds the color “Purple” and replaces it with “Cornflower Blue” and saves the report back to the system. The next Time the logo gets
replaced within CS101500 it would search within Reports for “Purple” and replace that..

Another approach instead of searching for colors would be to give the textboxes and lines all the same Name. For example “Colored”, so that the Code can look for the Name and search within the next lines for the “Color” that he changes.

Any Ideas how we can accomplish this?
I found a Code that already quite flawlessly outputs the color within c# based upon a local file.
Would love to receive some help upon converting the code into a customization project and working on the other steps to make this idea a reality as i think it is a great idea to match reports to our customers without much work by hand.

Sincerly
Jannik Westermann
 

using System.Collections.Generic;
using System.Linq;
using System.Drawing;
using System;

namespace Bild
{
class Program
{
static void Main(string[] args)
{
var image = (Bitmap)Image.FromFile(@"C:\temp\colorimage3.png");
var mostUsedColor = GetMostUsedColor(image);
var color = GetNearestColor(mostUsedColor);
Console.WriteLine(color.Name);
Console.ReadKey();
}

private static Color GetNearestColor(Color inputColor)
{
var inputRed = Convert.ToDouble(inputColor.R);
var inputGreen = Convert.ToDouble(inputColor.G);
var inputBlue = Convert.ToDouble(inputColor.B);
var colors = new List<Color>();
foreach (var knownColor in Enum.GetValues(typeof(KnownColor)))
{
var color = Color.FromKnownColor((KnownColor)knownColor);
if (!color.IsSystemColor)
colors.Add(color);
}
var nearestColor = Color.Empty;
var distance = 500.0;
foreach (var color in colors)
{
// Compute Euclidean distance between the two colors
var testRed = Math.Pow(Convert.ToDouble(color.R) - inputRed, 2.0);
var testGreen = Math.Pow(Convert.ToDouble(color.G) - inputGreen, 2.0);
var testBlue = Math.Pow(Convert.ToDouble(color.B) - inputBlue, 2.0);
var tempDistance = Math.Sqrt(testBlue + testGreen + testRed);
if (tempDistance == 0.0)
return color;
if (tempDistance < distance)
{
distance = tempDistance;
nearestColor = color;
}
}
return nearestColor;
}

public static Color GetMostUsedColor(Bitmap bitMap)
{
var colorIncidence = new Dictionary<int, int>();
for (var x = 0; x < bitMap.Size.Width; x++)
for (var y = 0; y < bitMap.Size.Height; y++)
{
var pixelColor = bitMap.GetPixel(x, y).ToArgb();
if (colorIncidence.Keys.Contains(pixelColor))
colorIncidence[pixelColor]++;
else
colorIncidence.Add(pixelColor, 1);
}
return Color.FromArgb(colorIncidence.OrderByDescending(x => x.Value).ToDictionary(x => x.Key, x => x.Value).First().Key);
}
}
}

 


10 replies

Userlevel 5
Badge +2

I would just change the report styles in:
\ReportsDefault\TemplateForm.rpx
\ReportsDefault\TemplateFormExternal.rpx
\ReportsDefault\TemplateReport.rpx

A customization plugin can update report styles files on server programmatically but that might not pass Acumatica ISV certification:
Site Configuration using Customization - Acumatica Developers Blog

Userlevel 3
Badge

Hey.
We use the German Version of Acumatica called Lexbizz. 
Therefore we are quite free with Customizations etc. 

Changing just some Styles in a TemplateForm should be quite simple, if i dont get it wrong.
But how can i set the path from the report designer file? Since most likely install directories vary between customer to customer, only the under folder like Website / Download etc. stay the same.

XDocument doc = XDocument.Load("test.xml");
foreach (XElement e in doc.Root.Elements("StyleRule"))
{
if (e.Element("Name").Value == "DocColor-N-R")
{
e.Element("Style").Element("Color").Value = "otherColor";
}
else if (e.Element("Name").Value == "DocLineColor")
{
e.Element("Style").Element("BorderColor").Element("Bottom").Value = "66, 134, 123";
}
}
doc.Save("test.xml");

 

Userlevel 5
Badge +2

You mean obtaining path of IIS virtual directory of the web site?

There are a quite a few ways to obtain path, example from link above uses:
PX.Data.Update.PXInstanceHelper.RootFolder

If you want to create new Templates you can put them in ‘\ReportsDefault’ directory. It is the root directory for templates:

 

Userlevel 3
Badge

Exactly!

Is there any Code example that would achieve this?
Maybe i am blind but i couldn’t find one that helps me

Userlevel 5
Badge +2

A code example for what exactly? Previous link I posted was about how to change a file content on the server programmatically: Site Configuration using Customization - Acumatica Developers Blog

Userlevel 3
Badge

Hey, Sorry i might have been a bit lost there as i am a very newbie coder still learning everything from scratch.

I thought there might be a code example for this specific example for replacing certain values inside of the ReportTemplate. I currently can’t imagine how a fully working code for my use case would look like. 

.

XDocument doc = XDocument.Load("test.xml");
foreach (XElement e in doc.Root.Elements("StyleRule"))
{
if (e.Element("Name").Value == "DocColor-N-R")
{
e.Element("Style").Element("Color").Value = "otherColor";
}
else if (e.Element("Name").Value == "DocLineColor")
{
e.Element("Style").Element("BorderColor").Element("Bottom").Value = "66, 134, 123";
}
}
doc.Save("test.xml");

 

 

 

Userlevel 5
Badge +2

The template is XML format:
<?xml version="1.0" encoding="utf-8"?>

You can use .Net framework XMLReader/XMLWriter classes to read and modify the document.

Userlevel 3
Badge

Hey,

thank u very much.
I figured it out, although i still have some problems with throwing an error when the fieldvalue isnt a hex. Somehow it only appears after saving, even tho i used the Event RowUpdated which should occur before i save it to the database, or not?

 

Userlevel 3
Badge

May i ask where the new Report Versions get saved?
Because if we for example insert an update of the StylesTemplate into the System and declare it as new Version, still the old Version is in the \DefaultReports

Userlevel 3
Badge

Hey @Hughes Beausejour 
I finished my Code for the DefaultReports folder.
See: https://pastebin.com/LdBhc2Qu

But i don’t really know, how i would be able to include the following:

 

  1. Check if there is a new Version of the StylesTemplate in the Table UserReport
  1. If yes: Change the file for the tenant² the field got modified on
  1. If no: Change the ReportsDefault file

 

f. E. if i would insert the Value for the userfield in Demo CompanyID2, it should only change the Report that has the CompanyID 2 inside the database table. 

Could someone help me with this? Maybe with an actual code example that would achieve what we need? I am lost.

Reply


About Acumatica ERP system
Acumatica Cloud ERP provides the best business management solution for transforming your company to thrive in the new digital economy. Built on a future-proof platform with open architecture for rapid integrations, scalability, and ease of use, Acumatica delivers unparalleled value to small and midmarket organizations. Connected Business. Delivered.
© 2008 — 2024  Acumatica, Inc. All rights reserved