Source code © 1994-2024 Guillaume Dargaud.
Free use, distribution and modification.
Can be integrated in commercial programs, but the source/fp/lib/dll provided here must not be sold independently.
Last updated on 2022/02/15
"Life would be so much easier if we only had the source code."
Here are some snippets of C code that I hacked for specific purposes. I believe them to be useful and since it was developed while I was paid by the (Italian/French/US) government, you might consider it like your tax money at work. All this code is ANSI C and should work on any 32 bit compiler. I have tested them on LabWindows/CVI on Windows and Linux.
Since 2019, most of the code is available on my gitlab page.
LabWindows/CVI has some great libraries for math/signal stuff. The problem is that most of it works on arrays. What if you have on the fly data and want temporary results ? Here's a standard statistics module I wrote that enables you to keep feeding data to it while getting results. Note that you can compile it for FLOAT or DOUBLE precision. Two structures and two sets of functions: for single and double variables.
CStat S; StatReset(&S); StatAdd(&S, 10); StatAdd(&S, 0); StatAdd(&S, 50); A=StatAvr(&S); // will return 20 // S.N =3 // S.Min=0 // S.Max=50
When you have a graph with a series of plots, it makes sense to display the plots in a range of colors, like a rainbow. Problem is, the rainbow is not very visible (all the colors have the same luminance), and how do you scale between two colors anyway ? Use my ColorScaleHSL function. This module also gives you conversion functions between RGB colors and HSL color definitions and macros to get darker colors.
See the examples below for different scales of RGB and HSL between 2 colors, or here for examples with 3 colors. If you don't want to bother with the source but want to do some color stuff, check out my color palette generator freeware.
COLORREF Color; for (RG=0; RG<NbRG; RG++) { if (Int[RG]<Min) Min=Int[RG]; if (Int[RG]>Max) Max=Int[RG]; } if (Max==Min) MaxInt++; // Avoid divide by 0 for (RG=0; RG<NbRG; RG++) { Color=ColorScaleHSL(VAL_WHITE, VAL_BLACK, (Int[RG]-Min)/(Max-Min)); ... SetCtrlAttribute (PnlFax, Cnvs , ATTR_PEN_COLOR, Color); CanvasDrawLine (PnlFax, Cnvs, P1, P2); }
The images on the left show examples of scalings between various colors (black, white, primaries [RGB] and secondaries [CMY]) using linear RGB and linear HSL. Pass the mouse over the following lines (requires JavaScript):
RGB | HSL | |
---|---|---|
Linear | 1 | 2 |
8 steps | 3 | 4 |
The strftime function from the ANSI C library is nice, but it lacks a lot of things before being really useful in a scientific environment. My StrfTime()
function adds many formatting codes, like the number of minutes since the start of the year and things like that. And it stays compatible with the standard C strftime()
function.
In addition to the two StrfTime source files for the library, there's also a documentation file, a LabWindows/CVI function panel and also 5 utility programs and scripts to compile independently:
StrfTime.exe
to format a time string from the command line)Note 1: this code uses both two and four digits years, and is Y2K compliant within 1970 ~ 2026.
Note 2: 'Julian day' refers here to a day of the year expressed as a number from 1 to 366, not to the true Julian calendar established by Julius Cesar and now superseded by the Gregorian calendar (our calendar). Julian days DDD are equivalent to Month/Days MMDD, but you need to know if the year is a leap year to provide a conversion. Source code included for all programs.
Example of Use in Unix: running through a sequence of dates (I also provide a script that does exactly that, with plenty of extras):
#! /bin/ksh Start=950101 # Start date YYMMDD - included Stop=$(FormatTime.exe NOW "%y%m%d") # End date YYMMDD - excluded YYMMDD=$Start while [ $YYMMDD != $Stop ] do FormatTime.exe $YYMMDD "%d %B %Y" # Skip to next day YYMMDD=$(TimeJump.exe $YYMMDD +1) done
When writing scientific programs, one of the first problem you run into is: how do you want to control the program parameters (input values, default directories...). Asking the user each time is not a good idea because you cannot run the program in a batch and most of the options are probably always the same; hard coding the values inside the program is fine until you need to change them (get the same compiler, same compiling options...); saving in the registry is non portable, complex and allows for only one set of data.
No the usual solution is to put the values inside a file. But then you need a parser to read it properly. Here's one. Note that this is for reading only, you cannot modify the parameter values inside the file. Also this code works but is not optimized for speed.
char DirSfcBin[MAX_PATHNAME_LEN]; int MaxLat, DoLegend, ColorZero, ColorNan, ColorCurve; float MaxScale; ParseParamString("Param.txt", DirSfcBin); ParseParamInt("Param.txt", MaxLat); ParseParamFloat("Param.txt", MaxScale); ParseParamBool("Param.txt", DoLegend); ParseParamHex("Param.txt", ColorZero); ParseParamHex("Param.txt", ColorNan); ParseParamHex("Param.txt", ColorCurve);Will parse the following Param.txt file:
; This is the parameter file ; Comments are preceded by ; # or ! ; You can use blank lines too ; Parameters can be in any order in the file, in case of duplicates, only the first one is read. DirSfcBin="/raid/data/SfcRain/" ; Use double quotes around strings NAN=-9999. ; float, ignored value MaxLat = 40 ; integer ColorZero= 0xC0C0C0 ; hex value ColorNan = FFFFFF ; optional 0x ColorCuve= 0x101040 ; Syntax error MaxScale=10. ; leading/trailing spaces are ignored DoLegend=Y ; Bool can be T, F, Y, N, True, False, Yes, No, 0, 1...
You want to lighten up a bitmap or turn it to a negative image ? That's a simple graphic filter (here the function Filter1x1()
).
You want to sharpen up a bitmap or enhance the edges or emboss it ? That can be done with a 3x3 graphic filter (here the function Filter3x3()
).
You want to change a color bitmap to greyscale or switch the colors ? That can be done with an interchannel graphic filter (here the function Filter1C()
).
This sample source code does all of that (plus 5x5 filters) and works in the same way than the user defined filters of applications like PhotoShop or Paint Shop Pro.
Some sample filters are included, but if you want to define your own, here's how for a 3x3 filter: define a 3x3 matrix with the coefficients of the surrounding pixels, a divider and a bias. For instance {{1,0,0},{0,5,0},{0,0,1}} will apply to a pixel the sum of the upper left pixel, the lower right pixel and 5 times the central pixel. Then it is divided by div and we add a bias. The result is truncated to fit between 0 (black) and 255 (white). This applies separately to the different channels Red, Green and Blue. There is no way to combine the channels with a normal 1x1, 3x3 or 5x5 filter, but you can do it with an interchannel filter. It works on greyscale images, 24 bits RGB or 32 bits images with alpha channel (the filter is applied to the alpha channel, which may not be a desired result).
Two source files and some specific LabWindows/CVI code to do a custom filter popup (one UIR file CustomFilter.uir, and one C file FilterPopup.c with their respective headers). I did not bother creating a function panel for LabWindows/CVI. Example of use:
Png_ReadBitmapFromFile(NULL, &Bits, &RowBytes, &PixDepth, &Width, &Height, SourcePathName); // Reads a PNG file Filter3x3(Bits, RowBytes, PixDepth, Width, Height, FilterSharpen); // Apply sharpen filter Jpg_SaveBitmapToFile(Bits, RowBytes, PixDepth, Width, Height, DestPathName, Compression)); // Saves to a JPEG file
There are many ways to log error messages out of a program, but I couldn't find one that matched my requirements, so I wrote a simple logging facility. The requirements:
// print all messages to stderr, no time stamp SimpleLog_Setup(NULL, NULL, 0, 1, 0, " "); // Avoid repeating the last message SimpleLog_Setup("Msg.log", "%H:%M ", 1, 0, 0, ", "); // Among the last 10 different messages, avoid repeating them at most 20 times SimpleLog_Setup("Msg.log", "%Y%m%d-%H%M%S ", 10, 20, 0, "\t"); // Among the last 100 different messages, avoid repeating them but print them at least once per minute SimpleLog_Setup(NULL, "%Y%m%d-%H%M%S ", 100, 0, 60, " "); // Display everything except debug messages SimpleLog_FilterLevel(SL_NOTICE); SLOG(SWRN, "Fubar has a value of %d", fubar); // This won't be printed with the above filter level SLOG(SDBG, "Expected value was %d", tarfu); // Optional before quitting the program, to get pending messages SimpleLog_Flush();
Note: I have 2 executables that do more advanced binary to ascii conversions. This is just a simple C function. Requirement:
2 source files: Bin2ascii.h, Bin2ascii.c. Example of use:
printf("Buffer: %s\n", Bin2ascii(Str, sizeof(Str), 0, 1, 0, 0))
There's sometimes a need to give a user the possibility to input formulas inside a program without recompiling the whole thing, but it's not possible to do this simply in C (there's no magical 'eval' function). So this is a simple postfix evaluator that can use double and booleans present in the program with various formulas. The requirements:
double A=2, B=3, C=4; tPE_Variable VarList[10]; tPE_Val Val; char *Formula="AA BB / sin CC + sqrt"; int NV=0; VarList[NV].Name="AA"; VarList[NV].pVal=&A; VarList[NV++].Type=VAL_DOUBLE; VarList[NV].Name="BB"; VarList[NV].pVal=&B; VarList[NV++].Type=VAL_DOUBLE; VarList[NV].Name="CC"; VarList[NV].pVal=&C; VarList[NV++].Type=VAL_DOUBLE; Val=PostfixEval_Compute(Formula, VarList, NV, NULL, NULL) switch (Val.Type) { case VAL_ERROR: printf("\n%s gave error %s", Formula, PostfixEval_ErrMsg(Val.Err, NULL)); break; case VAL_BOOL: printf("\n%s is %s", Formula, Val.B?"TRUE":"FALSE"); break; case VAL_DOUBLE:printf("\n%s = %f", Formula, Val.D); break; default: printf("\nError, invalid result type %d", Val.Type); break; }