The basic API consists of four functions.
Use only the basic API if replacing the rand()/srand() functions of the random number generation library.
There are four additional APIs, all for structured dithering.
In the C++ class library:
  1. Setting parameters of the Gaussian filter to control blue noise generation
  2. Changing the number of gradations (default is 256) to control structured dithering
  3. Dithering using error diffusion method
  4. Structured dithering using white noise
Many APIs not supported by this library exist.
This library supports only the essential elements of the C++ class library but is open-source, allowing the addition of APIs as needed.

Two of the basic APIs correspond to the standard C/C++ library functions rand()/srand(int seed), implemented as bluenoise()/sblunenoise(int seed).
Another is blunenoiseex(), which returns blue noise in a range wider than 0 to RAND_MAX. By default, it generates blue noise in the range of 0 to 65535, offering higher precision than blunenoise.

When using blunenoiseex() extensively, additional APIs can be used to enlarge the size of the blue noise matrix.
It can generate blue noise in the range of 0 to 0x07ffffff.
If additional APIs are called, the blue noise matrix will use files in the specified folder.
If additional APIs are not called, a pre-initialized 256×256 matrix will be used.

  1. sblunenoise(int seed) corresponding to srand(int seed)
  2. Changes the blue noise generation sequence.
    If additional APIs are called, the first call to bluenoise()/bluenoiseex()/sbluenoise() will require time and memory to read the table from a file.
    If additional APIs are not called, there is no overhead on the first call.
  3. blunenoise() corresponding to rand()
  4. Generates blue noise in the range of 0 to RAND_MAX.
    Using bluenoise does not require calling the additional API setblunenoisematrix.
  5. blunenoiseex() for high-precision blue noise generation
  6. Generates blue noise in the range of 0 to size * size.
    Even without additional APIs, it generates higher precision blue noise than bluenoise().
    Using additional APIs allows generating a blue noise sequence in the range of 0 to 0x0fffffff.
  7. Additional APIs
  8. Specialized APIs that most users will never use. When using blunenoiseex(), a larger blue noise matrix improves quality.
    When using blunenoise(), even with this API, the generated blue noise is a coarse sequence in the range of 0 to RAND_MAX (0x7fff).

    To use the blue noise matrix table, specify the folder for saving the matrix table and the matrix size as arguments.
    At the same time, a matrix table of one of the following sizes will be used: 512×512, 1024×1024, 2048×2048, 4096×4096, 8192×8192, or 16384×16384.
    In normal usage, this API call is unnecessary. For purposes like "requiring high-precision blue noise," a 1024×1024 blue noise is usually sufficient. For special purposes (e.g., structured dithering on A0-sized printers or initializing a large matrix with blue noise sequences), matrices of 2048×2048 or larger are used. However, file size and memory for loading the matrix increase significantly.
    If the specified matrix table does not exist in the designated folder, a new table will be created.
    The file sizes of the tables are as follows. The memory required for loading is approximately equal to the file size.
    If using the original 256×256 size table, set the folder name to NULL or "".
    Matrix SizeValue Range Generated by bluenoiseex()File SizeValue Range Generated by bluenoise()
    256×2560–0x0000ffff (0–65,535)Embedded data, no file0–0x00007fff (0–32,767)
    512×5120–0x0003ffff (0–262,143)1 MB0–0x00007fff (0–32,767)
    1024×10240–0x000fffff (0–1,048,575)
    Sufficient as a substitute for random sequences
    4 MB0–0x00007fff (0–32,767)
    2048×20480–0x003fffff (0–4,194,303)16 MB0–0x00007fff (0–32,767)
    4096×40960–0x00ffffff (0–16,777,215)
    24-bit color image range
    64 MB0–0x00007fff (0–32,767)
    8192×81920–0x03ffffff (0–67,108,863)
    Used for wide-format printers (e.g., national archive projects)
    256 MB0–0x00007fff (0–32,767)
    16384×163840–0x0fffffff (0–268,435,455)
    No known use cases (possible splitting for CYMK matrices)
    1024 MB (1 GB)0–0x00007fff (0–32,767)

Loading and Releasing the DLL

The definition of each API is as follows in "bluenoisecallback.h":
///////////////////////////////
// Set the seed for the blue noise sequence
//  int			seed;		seed value
// Return Value
//  Negative....Error (INITIALIZE_ERROR...Initialization error (failed to create class instance: insufficient memory))
typedef int (__stdcall* SBLUENOISE)(int seed);
extern SBLUENOISE sbluenoise;
/////////////////////////
// Retrieve the blue noise sequence (0–RAND_MAX)
// RAND_MAX is 0x7fff (32767), so it is coarse
// Return Value
//  Negative....Error (INITIALIZE_ERROR...Initialization error (failed to create class instance: insufficient memory))
//  Blue noise sequence
typedef int (__stdcall* BLUENOISE)();
extern BLUENOISE bluenoise;
/////////////////////////
// Retrieve a high-precision blue noise sequence (0–size*size)
// Even without using files, sizes (256*256) provide 0–65535, which is detailed
//   256*  256       0–0x0000ffff (0–65535-1)      Without using files
//   512*  512       0–0x0003ffff (0–262143-1)       1 MB
//  1024* 1024       0–0x000fffff (0–1048575-1)       4 MB
//  2048* 2048       0–0x003fffff (0–4194304-1)      16 MB
//  4096* 4096       0–0x00ffffff (0–16777216-1)     64 MB
//  8192* 8192       0–0x03ffffff (0–67108864-1)    256 MB
// 16384*16384       0–0x0fffffff (0–268435456-1)   1024 MB (1 GB)
// Return Value
//  Negative....Error (INITIALIZE_ERROR...Initialization error (failed to create class instance: insufficient memory))
//  Blue noise sequence
typedef int (__stdcall* BLUENOISEEX)();
extern BLUENOISEEX bluenoiseex;
/////////////////////////
// Set the folder for saving/loading the blue noise matrix and set the matrix size
// This is not set for generating normal blue noise in the range of 0–RAND_MAX
// It is set for retrieving high-precision blue noise with bluenoiseex()
// Input
//    const char* pfolder; Folder name where the matrix file exists/is generated
//                        If pointing to NULL or "", the built-in 256×256 matrix is used
//    int         size;   Matrix size (512/1024/2048/4096/8192/16384)
//                        If 1024, a 1024×1024 blue noise matrix is generated. File size is 4 MB
// Return Value
//  Negative....Error (INITIALIZE_ERROR...Initialization error (failed to create class instance: insufficient memory))
//  Negative....Error (FILE_OPEN_ERROR...Unable to save or read the file)
//                (MEMORY_SHORTAGE...Insufficient memory)
// Reads the file named sizexsizeraw.dat in the specified folder
//                   If size is 1024, the file name is 1024x1024raw.dat
//                   If the file does not exist, it is created
//                   Larger sizes generate higher-quality blue noise
typedef int (__stdcall* SETBLUENOISEMATRIX)(const char* pfolder,int size);
extern SETBLUENOISEMATRIX setbluenoisematrix;
The loading and releasing of the DLL are as follows:
#include "bluenoisecallback.h"
HINSTANCE bn_dllinstance;       // DLL instance
// DLL Entry Points
SBLUENOISE sbluenoise;
BLUENOISE bluenoise;
BLUENOISEEX bluenoiseex;
SETBLUENOISEMATRIX setbluenoisematrix;
ORDEREDDITHER2 ordereddither2;
ORDEREDDITHER4 ordereddither4;
ORDEREDDITHERLINE2 orderedditherline2;
ORDEREDDITHERLINE4 orderedditherline4;

{
    // ....
    // Load
    // gmodulepath contains the path of the executable file.
    // Assume "bluenoisedll.dll" is in the executable path
	char	filename[FILENAME_MAX];
	sprintf(filename,"%sbluenoisedll.dll",gmodulepath);
	bn_dllinstance = LoadLibrary(filename);
	if(bn_dllinstance == NULL) {
		char	buffer[512];
		sprintf(buffer,"Failed to load DLL file bluenoisedll.dll");
		AfxMessageBox(buffer,MB_OK | MB_ICONEXCLAMATION);
		return(2);
	}
	sbluenoise = (SBLUENOISE)GetProcAddress(bn_dllinstance,"sbluenoise");
	bluenoise = (BLUENOISE)GetProcAddress(bn_dllinstance,"bluenoise");
	bluenoiseex = (BLUENOISEEX)GetProcAddress(bn_dllinstance,"bluenoiseex");
	setbluenoisematrix = (SETBLUENOISEMATRIX)GetProcAddress(bn_dllinstance,"setbluenoisematrix");
	if(sbluenoise == NULL || bluenoise == NULL || bluenoiseex == NULL || setbluenoisematrix == NULL) {
		char	buffer[512];
		sprintf(buffer,"Version mismatch for DLL file bluenoisedll.dll(or bluenoiseutf8dll)");
		AfxMessageBox(buffer,MB_OK | MB_ICONEXCLAMATION);
		FreeLibrary(bn_dllinstance);
		return(2);       
	}
	ordereddither2 = (ORDEREDDITHER2)GetProcAddress(bn_dllinstance,"ordereddither2");
	ordereddither4 = (ORDEREDDITHER2)GetProcAddress(bn_dllinstance,"ordereddither4");
	orderedditherline2 = (ORDEREDDITHERLINE2)GetProcAddress(bn_dllinstance,"orderedditherline2");
	orderedditherline4 = (ORDEREDDITHERLINE4)GetProcAddress(bn_dllinstance,"orderedditherline4");
	if(ordereddither2 == NULL || ordereddither4 == NULL || orderedditherline2 == NULL || orderedditherline4 == NULL) {
		char	buffer[512];
		sprintf(buffer,"Version mismatch for DLL file bluenoisedll.dll(or bluenoiseutf8dll)");
		AfxMessageBox(buffer,MB_OK | MB_ICONEXCLAMATION);
		FreeLibrary(bn_dllinstance);
		return(2);       
	}
    // ....
    // Release
    FreeLibrary(bn_dllinstance);
}

API Corresponding to rand()/srand(int seed)

The call to bluenoise(), which corresponds to rand(), is as follows.
Similarly, to call blunnoiseex(), which corresponds to rand(), simply replace "bluenoise" with "bluenoiseex" in the following code.
// Set 1000 bluenoise sequences in m_editresult and display them in an edit box or similar
void CDlgBluenoise::OnBnClickedMakebluenoise100()
{
	m_editresult = "";
	char	buffer[1024];
	for(int i = 0 ; i < 1000 ; i++) {
		if(i % 10 == 0) {
			sprintf(buffer,"(%03d)",i / 10);
			m_editresult += buffer;
		}
		if(i % 10 == 9) {
			sprintf(buffer,"%10d\r\n",bluenoise());
		}
		else {
			sprintf(buffer,"%10d, ",bluenoise());
		}
		m_editresult += buffer;
	}
	UpdateData(FALSE);
}
The call to setbluenoisematrix() for creating a new matrix (usually larger than the initial size of 256×256) is as follows.
To use a matrix created with setbluenoisematrix(), call bluenoiseex() instead of bluenoise().
// In the sample program below, the folder is "g:/tmp/", but normally a different folder is specified.
// m_editsize contains a value in the range of 512 to 16384 void CDlgBluenoise::OnBnClickedSetsize() { UpdateData(TRUE); if(m_editsize == 256) { setbluenoisematrix("",m_editsize); } else { setbluenoisematrix("g:\\tmp\\",m_editsize); } UpdateData(FALSE); }

Utility Functions

Perform structured dithering using blue noise.
The input image has 256 gradations, and the number of planes is up to 8 (0–7).
The output image has either 2 or 4 gradations.

The class library supports structured dithering using white noise and dithering using error diffusion methods, but these are not supported by the dynamic link library.
To use these features, use the class library or customize the source code of this library.
Customization is straightforward.

// 1...ordered dither utility
// do ordered dither (for grayscale image only)
// for multiplane image (e.g., RGB, CMYK), use class library or add API to this library.
// input
//	int			width;			image width (pixel)
//	int			height;			image height (pixel)
//	int			scanlinesize1;	scanline size (byte count) of one line image
//	unsigned char*	pdata1;			256 level image
//	int			scanlinesize2;	scanline size (byte count) of 2 or 4 level image
// output
//	unsigned char*	pdata2;			2 or 4 level image (one pixel is one byte)
//                                2 levels have values (0, 255)
//                                4 levels have values (0, 85, 170, 255)
// return value
//	Negative value...error (INITIALIZE_ERROR...Initialization error (failed to create class instance: memory shortage)
//	                 error (FILE_OPEN_ERROR...Failed to save or load blue noise matrix data)
//	                 error (MEMORY_SHORTAGE...Memory shortage))
// This library reads "sizexsizeraw.dat" in the folder specified by setbluenoisematrix().
//                   If "size" is 1024, the file name is "1024x1024raw.dat".
//                   If "sizexsizeraw.dat" does not exist, setbluenoisematrix() API generates the file automatically.
//                   Larger "size" values result in higher dithering quality.
typedef int (__stdcall* ORDEREDDITHER2)(int width, int height, int scanlinesize1, unsigned char* pdata1, int scanlinesize2, unsigned char* pdata2);
extern ORDEREDDITHER2 ordereddither2;

typedef int (__stdcall* ORDEREDDITHER4)(int width, int height, int scanlinesize1, unsigned char* pdata1, int scanlinesize2, unsigned char* pdata2);
extern ORDEREDDITHER4 ordereddither4;

// ordered dither utility
//     line-by-line process
// INPUT
//   int            y;               line number (0, ..., height - 1)
typedef int (__stdcall* ORDEREDDITHERLINE2)(int width, int y, unsigned char* pdata1, unsigned char* pdata2);
extern ORDEREDDITHERLINE2 orderedditherline2;

typedef int (__stdcall* ORDEREDDITHERLINE4)(int width, int y, unsigned char* pdata1, unsigned char* pdata2);
#extern ORDEREDDITHERLINE4 orderedditherline4;
// 1...Structured Dithering Utility
//  Performs structured dithering for grayscale images
//  Structured dithering for multiplane images (e.g., RGB, CMYK) is supported in the C++ class library.
//  For multiplane images, use the class library or extend this library’s API.
// INPUT
//	int			width;			Image width (pixel)
//	int			height;			Image height (pixel)
//	int			scanlinesize1;	Scanline size of pdata1 (bytes per line of image)
//	unsigned char*	pdata1;			256-level image (1 pixel per byte)
//	int			scanlinesize2;	Scanline size of pdata2 (bytes per line of image)
// OUTPUT
//	unsigned char*	pdata2;			2 or 4-level image (1 pixel per byte)
//                                2 levels: (0/255)
//                                4 levels: (0/85/170/255)
// RETURN VALUE
//	Negative value...error (INITIALIZE_ERROR...Initialization error (failed to create class instance: memory shortage))
//                   error (FILE_OPEN_ERROR...Failed to save or load blue noise data)
//                   error (MEMORY_SHORTAGE...Memory shortage))
// This library saves/loads files with the name "sizexsizeraw.dat" in the folder specified by setbluenoisematrix().
//                   For example, if "size" is 1024, the file name is "1024x1024raw.dat".
//                   If the file does not exist, setbluenoisematrix() automatically creates blue noise and saves it with the name "sizexsizeraw.dat".
//                   Larger "size" values result in higher dithering quality.
typedef int (__stdcall* ORDEREDDITHER2)(int width, int height, int scanlinesize1, unsigned char* pdata1, int scanlinesize2, unsigned char* pdata2);
extern ORDEREDDITHER2 ordereddither2;

typedef int (__stdcall* ORDEREDDITHER4)(int width, int height, int scanlinesize1, unsigned char* pdata1, int scanlinesize2, unsigned char* pdata2);
extern ORDEREDDITHER4 ordereddither4;

// Structured Dithering
//     Line-by-line dithering (e.g., for printer drivers processing one line at a time)
// INPUT
//   int            y;               Line number (0 to height - 1)
typedef int (__stdcall* ORDEREDDITHERLINE2)(int width, int y, unsigned char* pdata1, unsigned char* pdata2);
extern ORDEREDDITHERLINE2 orderedditherline2;

typedef int (__stdcall* ORDEREDDITHERLINE4)(int width, int y, unsigned char* pdata1, unsigned char* pdata2);
#extern ORDEREDDITHERLINE4 orderedditherline4;

Sample Program
int				width = mppimage[0]->mgetrawwidth();                    // Width of the original 256-level grayscale image (pixels)
int				height = mppimage[0]->mgetrawheight();                  // Height of the original 256-level grayscale image (pixels)
int				scanlinesize = mppimage[0]->mgetrawscanlinesize();      // Scanline size of the original 256-level grayscale image (bytes)
unsigned char*	pdata1 = mppimage[0]->mgetrawdata();                    // Original 256-level grayscale image (scanlinesize * height bytes)
unsigned char*	pdata2 = (unsigned char*)malloc(scanlinesize * height); // 2/4-level dithered grayscale image (scanlinesize * height bytes)
                                                                        // For 2 levels, luminance values are 0/255
                                                                        // For 4 levels, luminance values are 0/85/170/255
if(pdata2 != NULL) {
	ordereddither2(0, width, height, scanlinesize, pdata1, scanlinesize, pdata2);
	free(pdata2);
}
Line Processing Sample Program
int				width = mppimage[0]->mgetrawwidth();                    // Width of the original 256-level grayscale image (pixels)
int				height = mppimage[0]->mgetrawheight();                  // Height of the original 256-level grayscale image (pixels)
int				scanlinesize = mppimage[0]->mgetrawscanlinesize();      // Scanline size of the original 256-level grayscale image (bytes)
unsigned char*	pdata1 = mppimage[0]->mgetrawdata();                    // Original 256-level grayscale image (scanlinesize * height bytes)
unsigned char*	pdata2 = (unsigned char*)malloc(scanlinesize * height); // 2/4-level dithered grayscale image (scanlinesize * height bytes)
                                                                        // For 2 levels, luminance values are 0/255
                                                                        // For 4 levels, luminance values are 0/85/170/255
if(pdata2 != NULL) {
    for(int i = 0 ; i < height ; i++) {
	    unsigned char* ps1 = pdata1 + i * scanlinesize;
	    unsigned char* ps2 = pdata2 + i * scanlinesize;
	    orderedditherline4(0, width, i, ps1, ps2);
    }
	free(pdata2);
}