I'm developing a report in Crystal Reports and need to render some math formulas and equations in it. The formulas and equations are stored in a SQL Server database in plain text (using LaTeX markup).
Getting them to render in HTML is not a problem, because I'm using MathJax to do the work at browser level (in either HTML/CSS or MathML).
The real problem is: how can I get these equations rendered in the report? I've searched throught the web and found nothing about it. Doing some more search at the Crystal interface, the only thing I've found is inserting the (obsolete) "Microsoft Equation Editor" as a OLE object in the report, but neither this worked.
So, how render these LaTeX math equations in this Crystal report? Is there some (obscure) component/plugin that does the job? If not, is there a better manner of doing this? Someone already got and resolved a similar use-case?
OBS 1: I must have this report generated in PDF because of already validated standards in use at my job.
OBS 2: The app which will generate this report is a ASP.NET MVC 3 web app, with a SQL Server 2008 database (using NHibernate).
You'll need to create a user-function library (UFL) to do this. Pass the LaTeX representation of the formula to the UFL, generate an image representation of the formula, return the image's URL.
To use the path, insert a 'picture', then reference the UFL's function in the 'graphic location' property:
//Insert | Picture...; graphic location conditional formula
latex({table.latex_field})
I've found a workaround that is at the same time elegant and not relies on extending the Crystal Reports using C.
I've found this small and simple "latex equation renderer": mimeTeX. Using it, I'm able to render latex equations into GIF images (as a CGI application). With that, I created a phantom byte array field in the datatable where the report is getting data.
Here is what I've done:
- Recover the latex equation markup from my real database;
- Query mimeTeX using this markup and mimeTeX returns a gif image;
- Take this image and convert it to png format (Crystal surprisingly do not support GIF files);
- Finally put this PNG image (its bytes) in the phantom field created in the datatable used by the report;
- Now you can use this field in the report! The images for each record (equation) are generated and displayed without problems!
The only drawback I've found until now using this approach is that all the images are streched to the same size of the field placeholder. If the images have sizes that varies much, some will be displayed pixelated and others will become "squashed". But I'm looking forward how to resolve this issue!
--- Edit ---
Solved the "squashed images" problem. I resize the images in code maintaining their aspect ratio and "pasting" them in a fixed size image. Now all the images get the same size and doesn't get squashed!
Here is the code for the resizing:
MemoryStream ResizeImage(Stream OriginalFile, int NewWidth, int MaxHeight, bool OnlyResizeIfWider)
{
int finalWidth = NewWidth;
int finalHeight = MaxHeight;
System.Drawing.Image FullsizeImage = System.Drawing.Image.FromStream(OriginalFile);
// Prevent using images internal thumbnail
FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
FullsizeImage.RotateFlip(System.Drawing.RotateFlipType.Rotate180FlipNone);
if (OnlyResizeIfWider)
{
if (FullsizeImage.Width <= NewWidth)
{
NewWidth = FullsizeImage.Width;
}
}
int NewHeight = FullsizeImage.Height * NewWidth / FullsizeImage.Width;
if (NewHeight > MaxHeight)
{
// Resize with height instead
NewWidth = FullsizeImage.Width * MaxHeight / FullsizeImage.Height;
NewHeight = MaxHeight;
}
System.Drawing.Image NewImage = FullsizeImage.GetThumbnailImage(NewWidth, NewHeight, null, IntPtr.Zero);
// Clear handle to original file so that we can overwrite it if necessary
FullsizeImage.Dispose();
MemoryStream bmpStream = new MemoryStream();
// Put in a new image of A x B pixels to evict distortion
using (var bitmap = new Bitmap(finalWidth, finalHeight))
{
using (var canvas = Graphics.FromImage(bitmap))
{
canvas.InterpolationMode = InterpolationMode.HighQualityBicubic;
canvas.Clear(Color.White);
canvas.DrawImage(NewImage, 0, 0);
canvas.Save();
}
bitmap.Save(bmpStream, ImageFormat.Bmp);
}
return bmpStream;
}