Source code © 1994-2010 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 2010/02/02
"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 IRIX on an SGI.
Note: the zip files contain the source code, a lib file for Windows and an FP (function panel) for LabWindows/CVI version 5.5 (the .fp are not backward compatible with previous versions of CVI. Sorry. You can still try to use them by liking directly to the .lib).
First things first, 2 headers that everybody should have, the iso646.h for meaningful connectors (and is better than & or was it && ? No ?) and some version of my def.h useful definitions file.
You can right click on a frame and select [Open frame in new window] to get a full size listing; or SelectAll/Copy/Paste the frame into your favorite editor...
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.
2 source files: Statistics.h, statistics.c and a function panel in Statistics.zip. Example of use:
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.
Two source files: ColorScale.h, ColorScale.c and a function panel in ColorScale.zip. Example of use:
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.
Two source files for the library (StrfTime.h, StrfTime.c), a documentation file and a function panel in StrfTime.zip. Also 5 utility programs and scripts to compile independantly:
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 echo `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.
Two source files: ParseParam.h, ParseParam.c. I did not bother to create a function panel for LabWindows/CVI. Example of use:
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...
Computers think using blocks of 8 bits (one byte). When using more, they order the elementary bytes either Least Significant First (LSF, Little Endian) or Most Significant First (MSF, big endian). This causes big trouble when trading binary files between machines.
To determine what your machine is, you can do (in the C programming language):
long L=1; void *Ptr=&L; char B=*(char*)Ptr;
If you get 1 as a result in B, your machine is little endian, if you get 0 it's big endian. The PC is little endian, the SGI machines and Macs are big endian.
Here's a routine and a couple macros to do the byte swapping. Note that normally values more than one byte should be aligned on a byte boundary. It means that a long (4 bytes) can be at address 0x1230, 0x1234, 0x1238... but usually should not be at 0x1231. It depends a lot on compiler options, optimization...
Two source file: SwapEndian.h and SwapEndian.c. Example of use:
#include "SwapEndian.h"
...
double D;
FILE *file=fopen("File.bin", "rb");
fread(&D, sizeof(D), 1, file);
SWAP_DOUBLE(D);
printf("Value: %d", D);
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: GraphicFilter.h and GraphicFilter.c with 4 functions in them. Also 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. Download them all (18Kb). 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:
2 source files: SimpleLog.h, SimpleLog.c. Example of use:
// 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);
SimpleLog_Write(SL_WARNING, __func__, "fubar has a value of %d", fubar);
// This won't be printed with the above filter level
SimpleLog_Write(SL_DEBUG, __func__, "expected value was %d", tarfu);
// Optional before quitting the program
SimpleLog_Flush();
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:
2 source files: PostfixEval.h, PostfixEval.c. Example of use (also see the testcases at the end of the c file):
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)
switch (Val.Type) {
case VAL_ERROR: printf("\n%s gave error %s", Formula, PostfixEval_ErrMsg(Val.Err)); 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; \
}
Counters: Page:194429, Section:2772259, Site:21987778.
Forward to the next Hack page. Back to my contact page, my computer page or my home page.