
#include <windows.h>
#include <float.h>  // MS VC++ version for //_controlfp(0x9001f, 0xfffff);


#include "WSQ_jniexport64.h"

#include <vcl.h>


HMODULE m_library = 0;

Graphics::TBitmap *pInputBitmap;

__declspec(thread) static unsigned char* output_data_stream_encode = (unsigned char*)NULL;
__declspec(thread) static unsigned char* output_data_stream_decode = (unsigned char*)NULL;





typedef char*(*GenerateWSQLibrarySerialNumber)();
GenerateWSQLibrarySerialNumber pGenerateWSQLibrarySerialNumber = 0;

typedef int (*UnlockWSQLibrary)(const char* authorization_code);
UnlockWSQLibrary pUnlockWSQLibrary = 0;

typedef void (*RegisterWSQ)();
RegisterWSQ pRegisterWSQ = 0;

typedef void (*ShowFileConverter)();
ShowFileConverter pShowFileConverter = 0;

typedef HBITMAP (*CreateBMPFromFile)(const char*);
CreateBMPFromFile pCreateBMPFromFile = 0;

typedef void (*SaveBMPToFile)(HBITMAP, const char*, int);
SaveBMPToFile pSaveBMPToFile = 0;

typedef HBITMAP (*CreateBMPFromWSQByteArray)(unsigned char *input_wsq_byte_array, int size_of_input_wsq_byte_array);
CreateBMPFromWSQByteArray pCreateBMPFromWSQByteArray = 0;

typedef int (*SaveWSQByteArrayToImageFile)(unsigned char *input_wsq_byte_array, int size_of_input_wsq_byte_array, const char *filename, int filetype);
SaveWSQByteArrayToImageFile pSaveWSQByteArrayToImageFile = 0;

typedef void (*WriteWSQ_bitrate)(double);
WriteWSQ_bitrate pWriteWSQ_bitrate = 0;

typedef double (*ReadWSQ_bitrate)();
ReadWSQ_bitrate pReadWSQ_bitrate = 0;

typedef void (*WriteWSQ_ppi)(int);
WriteWSQ_ppi pWriteWSQ_ppi = 0;

typedef int (*ReadWSQ_ppi)();
ReadWSQ_ppi pReadWSQ_ppi = 0;

typedef void (*WriteWSQ_comment)(char*);
WriteWSQ_comment pWriteWSQ_comment = 0;

typedef char* (*ReadWSQ_comment)();
ReadWSQ_comment pReadWSQ_comment = 0;

typedef void (*WriteTIFFcompression)(int);
 WriteTIFFcompression pWriteTIFFcompression = 0;

typedef void (*WriteTIFFpredictor)(int);
WriteTIFFpredictor pWriteTIFFpredictor = 0;

typedef void (*SetShowFilePropertiesDialog)(int);
SetShowFilePropertiesDialog pSetShowFilePropertiesDialog = 0;


typedef int (*WSQ_decode_stream)(unsigned char *input_data_stream, const int
input_stream_length, unsigned char **output_data_stream, int *width, int
*height, int *ppi, unsigned char **comment_text);
WSQ_decode_stream pWSQ_decode_stream = 0;


typedef int (*WSQ_encode_stream)
(unsigned char *input_data_stream, const int width, const int height, const double bitrate,
const int ppi, char *comment_text, unsigned char **output_data_stream, int *output_stream_length);
WSQ_encode_stream pWSQ_encode_stream = 0;


typedef HBITMAP (*ConvertHBITMAPtoGrayScale256)(HBITMAP hBitmap);
ConvertHBITMAPtoGrayScale256 pConvertHBITMAPtoGrayScale256 = 0;

typedef int (*SaveHBITMAPtoFileAsGrayScale256BMP)(HBITMAP hBitmap, const char *filename);
SaveHBITMAPtoFileAsGrayScale256BMP pSaveHBITMAPtoFileAsGrayScale256BMP = 0;

typedef int (*ReadWSQ_implementation_number)();
ReadWSQ_implementation_number pReadWSQ_implementation_number = 0;




//----------------------------------------------------------------------------------------------------------
JNIEXPORT jstring JNICALL Java_wsq_1sun_1java_WSQ_1library_GenerateWSQLibrarySerialNumber(JNIEnv *env, jclass)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return jstring();
	}

	if (!pGenerateWSQLibrarySerialNumber) {
		pGenerateWSQLibrarySerialNumber = (GenerateWSQLibrarySerialNumber)::GetProcAddress(m_library, "GenerateWSQLibrarySerialNumber");
	}
	if (!pGenerateWSQLibrarySerialNumber) {
		MessageBoxW(0, L"Unable to get pGenerateWSQLibrarySerialNumber function address", L"Error", 0);
		return jstring();
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	const char* serial_number_char = pGenerateWSQLibrarySerialNumber();
	jstring serial_number = env->NewStringUTF(serial_number_char);
	//_controlfp(0x9001f, 0xfffff);
	Set8087CW(0x133f);  // Disable all fpu exceptions.
	return serial_number;
}
//----------------------------------------------------------------------------------------------------------


JNIEXPORT jint JNICALL Java_wsq_1sun_1java_WSQ_1library_UnlockWSQLibrary(JNIEnv * env, jclass,  jstring authorization_code)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return 0;
	}

	if (!pUnlockWSQLibrary) {
		pUnlockWSQLibrary = (UnlockWSQLibrary)::GetProcAddress(m_library, "UnlockWSQLibrary");
	}
	if (!pUnlockWSQLibrary) {
		MessageBoxW(0, L"Unable to get pUnlockWSQLibrary function address", L"Error", 0);
		return 0;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	const char* authorization_code_char = env->GetStringUTFChars(authorization_code, 0);


	//_controlfp(0x9001f, 0xfffff);
	Set8087CW(0x133f);  // Disable all fpu exceptions.

	return (jint)pUnlockWSQLibrary(authorization_code_char);

}
//----------------------------------------------------------------------------------------------------------


JNIEXPORT void JNICALL Java_wsq_1sun_1java_WSQ_1library_RegisterWSQ(JNIEnv *, jclass)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return;
	}

	if (!pRegisterWSQ) {
		pRegisterWSQ = (RegisterWSQ)::GetProcAddress(m_library, "RegisterWSQ");
	}
	if (!pRegisterWSQ) {
		MessageBoxW(0, L"Unable to get pRegisterWSQ function address", L"Error", 0);
		return;
	}


	Set8087CW(0x133f);  // Disable all fpu exceptions.
	pRegisterWSQ();
	Set8087CW(0x133f);  // Disable all fpu exceptions.
	//_controlfp(0x9001f, 0xfffff);

}
//----------------------------------------------------------------------------------------------------------

JNIEXPORT void JNICALL Java_wsq_1sun_1java_WSQ_1library_ShowFileConverter(JNIEnv *, jclass)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return;
	}

	if (!pShowFileConverter) {
		pShowFileConverter = (ShowFileConverter)::GetProcAddress(m_library, "ShowFileConverter");
	}
	if (!pShowFileConverter) {
		MessageBoxW(0, L"Unable to get pShowFileConverter function address", L"Error", 0);
		return;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.
	pShowFileConverter();
	//_controlfp(0x9001f, 0xfffff);
	Set8087CW(0x133f);  // Disable all fpu exceptions.

}
//----------------------------------------------------------------------------------------------------------

JNIEXPORT jintArray JNICALL Java_wsq_1sun_1java_WSQ_1library_CreateBMPFromFile(JNIEnv* env, jclass, jintArray imageDimension, jstring fileName)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return 0;
	}

	if (!pCreateBMPFromFile) {
		pCreateBMPFromFile = (CreateBMPFromFile)::GetProcAddress(m_library, "CreateBMPFromFile");
	}
	if (!pCreateBMPFromFile) {
		MessageBoxW(0, L"Unable to get pCreateBMPFromFile function address", L"Error", 0);
		return 0;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	const char* file = env->GetStringUTFChars(fileName, 0);
	HBITMAP hBitmap = pCreateBMPFromFile(file);
	if (!hBitmap) {
		MessageBoxW(0, L"Unable to get HBITMAP", L"Error", 0);
		return 0;
	}

	BITMAP bm;
	GetObject(hBitmap, sizeof(bm), &bm);

	int width = bm.bmWidth;
	int height = bm.bmHeight;

	jboolean isDimensionCopy = JNI_FALSE;

	jint* dimension = (jint *)env->GetPrimitiveArrayCritical(imageDimension, &isDimensionCopy);
	dimension[0] = width;
	dimension[1] = height;
	env->ReleasePrimitiveArrayCritical(imageDimension, dimension, JNI_ABORT);


	BITMAPINFO info;
	info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	info.bmiHeader.biWidth = width;
	info.bmiHeader.biHeight = -height;
	info.bmiHeader.biPlanes = 1;
	info.bmiHeader.biBitCount = 32;
	info.bmiHeader.biCompression = BI_RGB;
	info.bmiHeader.biSizeImage = 0;
	info.bmiHeader.biClrUsed = 0;

	jboolean isCopy = JNI_FALSE;

	HDC hdc = CreateCompatibleDC(0);
	jintArray pixels = env->NewIntArray(width * height);
	jint *pixel = (jint *)env->GetPrimitiveArrayCritical(pixels, &isCopy);

	GetDIBits(hdc, hBitmap, 0, height, pixel, &info, DIB_RGB_COLORS);

	env->ReleasePrimitiveArrayCritical(pixels, pixel, JNI_ABORT);

	//_controlfp(0x9001f, 0xfffff);
	Set8087CW(0x133f);  // Disable all fpu exceptions.

	return pixels;
}
//----------------------------------------------------------------------------------------------------------


JNIEXPORT void JNICALL Java_wsq_1sun_1java_WSQ_1library_SaveBMPToFile(JNIEnv* env, jclass, jintArray pixels, jint width, jint height, jstring fileName, jint type)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return;
	}

	if (!pSaveBMPToFile) {
		pSaveBMPToFile = (SaveBMPToFile)::GetProcAddress(m_library, "SaveBMPToFile");
	}
	if (!pSaveBMPToFile) {
		MessageBoxW(0, L"Unable to get pSaveBMPToFile function address", L"Error", 0);
		return;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	jboolean isCopy = JNI_FALSE;
	jint* pixel = (jint *)env->GetPrimitiveArrayCritical(pixels, &isCopy);


//	HBITMAP hBitmap = ::CreateBitmap(width, height, 1, 32, pixel); // works on all Windows versions, EXCEPT Windows2003

//static HBITMAP hBitmap = (HBITMAP) NULL;
HBITMAP hBitmap;
RGBTRIPLE* Picture_Line;


if(pInputBitmap != NULL)
{delete pInputBitmap; pInputBitmap = NULL;}

pInputBitmap = new Graphics::TBitmap;
pInputBitmap->Width = width;
pInputBitmap->Height = height;
pInputBitmap->PixelFormat = pf24bit;

int pixel_number;

  for(int y = 0; y < pInputBitmap->Height; y++)
  {
	Picture_Line = (RGBTRIPLE*)pInputBitmap->ScanLine[y];

	for(int x = 0; x < pInputBitmap->Width; x++)
    {
    pixel_number = pInputBitmap->Width*y+x;

			  Picture_Line->rgbtBlue = (unsigned char)((int)pixel[pixel_number] & 0x000Ff);
			  Picture_Line->rgbtGreen = (unsigned char)((((int)pixel[pixel_number])>>8) & 0x000Ff);
			  Picture_Line->rgbtRed = (unsigned char)((((int)pixel[pixel_number])>>16) & 0x000Ff);

      Picture_Line++;
	 }
  }

hBitmap = pInputBitmap->Handle;



	env->ReleasePrimitiveArrayCritical(pixels, pixel, JNI_ABORT);
	if (!hBitmap) {
		MessageBoxW(0, L"Unable to create HBITMAP", L"Error", 0);
		return;
	}

	const char* file = env->GetStringUTFChars(fileName, 0);
	pSaveBMPToFile(hBitmap, file, type);
	//_controlfp(0x9001f, 0xfffff);
	Set8087CW(0x133f);  // Disable all fpu exceptions.


}
//----------------------------------------------------------------------------------------------------------


JNIEXPORT jintArray JNICALL Java_wsq_1sun_1java_WSQ_1library_CreateBMPFromWSQByteArray(JNIEnv *env, jclass, jintArray imageDimension, jbyteArray input)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return 0;
	}

	if (!pCreateBMPFromWSQByteArray) {
		pCreateBMPFromWSQByteArray = (CreateBMPFromWSQByteArray)::GetProcAddress(m_library, "CreateBMPFromWSQByteArray");
	}
	if (!pCreateBMPFromWSQByteArray) {
		MessageBoxW(0, L"Unable to get pCreateBMPFromWSQByteArray function address", L"Error", 0);
		return 0;
	}


	Set8087CW(0x133f);  // Disable all fpu exceptions.

	jsize input_stream_length = env->GetArrayLength(input);

	jboolean isCopy = JNI_FALSE;
	jbyte * input_data_stream = env->GetByteArrayElements(input, &isCopy);


	HBITMAP hBitmap = pCreateBMPFromWSQByteArray((unsigned char*)input_data_stream, (int)input_stream_length);

	if (!hBitmap) {
		MessageBoxW(0, L"Unable to get HBITMAP", L"Error", 0);
		return 0;
	}

	BITMAP bm;
	GetObject(hBitmap, sizeof(bm), &bm);

	int width = bm.bmWidth;
	int height = bm.bmHeight;

	jboolean isDimensionCopy = JNI_FALSE;

	jint* dimension = (jint *)env->GetPrimitiveArrayCritical(imageDimension, &isDimensionCopy);
	dimension[0] = width;
	dimension[1] = height;
	env->ReleasePrimitiveArrayCritical(imageDimension, dimension, JNI_ABORT);


	BITMAPINFO info;
	info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	info.bmiHeader.biWidth = width;
	info.bmiHeader.biHeight = -height;
	info.bmiHeader.biPlanes = 1;
	info.bmiHeader.biBitCount = 32;
	info.bmiHeader.biCompression = BI_RGB;
	info.bmiHeader.biSizeImage = 0;
	info.bmiHeader.biClrUsed = 0;

//	jboolean isCopy = JNI_FALSE;

	HDC hdc = CreateCompatibleDC(0);
	jintArray pixels = env->NewIntArray(width * height);
	jint *pixel = (jint *)env->GetPrimitiveArrayCritical(pixels, &isCopy);

	GetDIBits(hdc, hBitmap, 0, height, pixel, &info, DIB_RGB_COLORS);

	env->ReleasePrimitiveArrayCritical(pixels, pixel, JNI_ABORT);

	//_controlfp(0x9001f, 0xfffff);
	Set8087CW(0x133f);  // Disable all fpu exceptions.
	return pixels;
}
//----------------------------------------------------------------------------------------------------------


JNIEXPORT jint JNICALL Java_wsq_1sun_1java_WSQ_1library_SaveWSQByteArrayToImageFile
(JNIEnv *env, jclass, jbyteArray input, jstring filename, jint filetype)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return 0;
	}

	if (!pSaveWSQByteArrayToImageFile) {
		pSaveWSQByteArrayToImageFile = (SaveWSQByteArrayToImageFile)::GetProcAddress(m_library, "SaveWSQByteArrayToImageFile");
	}
	if (!pSaveWSQByteArrayToImageFile) {
		MessageBoxW(0, L"Unable to get pSaveWSQByteArrayToImageFile function address", L"Error", 0);
		return 0;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	jsize input_stream_length = env->GetArrayLength(input);

	jboolean isCopy = JNI_FALSE;
	jbyte * input_data_stream = env->GetByteArrayElements(input, &isCopy);

	const char* jfilename = env->GetStringUTFChars(filename, 0);


	int ret = pSaveWSQByteArrayToImageFile((unsigned char*)input_data_stream, (int)input_stream_length, jfilename, filetype);
	//_controlfp(0x9001f, 0xfffff);
	Set8087CW(0x133f);  // Disable all fpu exceptions.
	return ret;

}
//----------------------------------------------------------------------------------------------------------

JNIEXPORT void JNICALL Java_wsq_1sun_1java_WSQ_1library_WriteWSQ_1bitrate(JNIEnv *, jclass, jdouble bitrate)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return;
	}

	if (!pWriteWSQ_bitrate) {
		pWriteWSQ_bitrate = (WriteWSQ_bitrate)::GetProcAddress(m_library, "WriteWSQ_bitrate");
	}
	if (!pWriteWSQ_bitrate) {
		MessageBoxW(0, L"Unable to get pWriteWSQ_bitrate function address", L"Error", 0);
		return;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	pWriteWSQ_bitrate(bitrate);
	//_controlfp(0x9001f, 0xfffff);
	Set8087CW(0x133f);  // Disable all fpu exceptions.

}
//----------------------------------------------------------------------------------------------------------

JNIEXPORT jdouble JNICALL Java_wsq_1sun_1java_WSQ_1library_ReadWSQ_1bitrate(JNIEnv* env, jclass)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return 0;
	}

	if (!pReadWSQ_bitrate) {
		pReadWSQ_bitrate = (ReadWSQ_bitrate)::GetProcAddress(m_library, "ReadWSQ_bitrate");
	}
	if (!pReadWSQ_bitrate) {
		MessageBoxW(0, L"Unable to get pReadWSQ_bitrate function address", L"Error", 0);
		return 0;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	double d = pReadWSQ_bitrate();
	jdouble jd = d;
	//_controlfp(0x9001f, 0xfffff);
	Set8087CW(0x133f);  // Disable all fpu exceptions.

	return jd;
}
//----------------------------------------------------------------------------------------------------------

JNIEXPORT void JNICALL Java_wsq_1sun_1java_WSQ_1library_WriteWSQ_1ppi(JNIEnv *, jclass, jint ppi)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return;
	}

	if (!pWriteWSQ_ppi) {
		pWriteWSQ_ppi = (WriteWSQ_ppi)::GetProcAddress(m_library, "WriteWSQ_ppi");
	}
	if (!pWriteWSQ_ppi) {
		MessageBoxW(0, L"Unable to get pWriteWSQ_ppi function address", L"Error", 0);
		return;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.
	pWriteWSQ_ppi(ppi);
	//_controlfp(0x9001f, 0xfffff);
	Set8087CW(0x133f);  // Disable all fpu exceptions.

}
//----------------------------------------------------------------------------------------------------------

JNIEXPORT jint JNICALL Java_wsq_1sun_1java_WSQ_1library_ReadWSQ_1ppi(JNIEnv *, jclass)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return 0;
	}

	if (!pReadWSQ_ppi) {
		pReadWSQ_ppi = (ReadWSQ_ppi)::GetProcAddress(m_library, "ReadWSQ_ppi");
	}
	if (!pReadWSQ_ppi) {
		MessageBoxW(0, L"Unable to get pReadWSQ_ppi function address", L"Error", 0);
		return 0;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	int ppi = pReadWSQ_ppi();
	//_controlfp(0x9001f, 0xfffff);
	Set8087CW(0x133f);  // Disable all fpu exceptions.

	return ppi;
}
//----------------------------------------------------------------------------------------------------------

JNIEXPORT void JNICALL Java_wsq_1sun_1java_WSQ_1library_WriteWSQ_1comment(JNIEnv* env, jclass, jstring comment)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return;
	}

	if (!pWriteWSQ_comment) {
		pWriteWSQ_comment = (WriteWSQ_comment)::GetProcAddress(m_library, "WriteWSQ_comment");
	}
	if (!pWriteWSQ_comment) {
		MessageBoxW(0, L"Unable to get pWriteWSQ_comment function address", L"Error", 0);
		return;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	const char* com = env->GetStringUTFChars(comment, 0);
	char* c = const_cast<char*> (com);
	pWriteWSQ_comment(c);

	Set8087CW(0x133f);  // Disable all fpu exceptions.
	//_controlfp(0x9001f, 0xfffff);

}
//----------------------------------------------------------------------------------------------------------

JNIEXPORT jstring JNICALL Java_wsq_1sun_1java_WSQ_1library_ReadWSQ_1comment(JNIEnv* env, jclass)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return jstring();
	}

	if (!pReadWSQ_comment) {
		pReadWSQ_comment = (ReadWSQ_comment)::GetProcAddress(m_library, "ReadWSQ_comment");
	}
	if (!pReadWSQ_comment) {
		MessageBoxW(0, L"Unable to get pReadWSQ_comment function address", L"Error", 0);
		return jstring();
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	const char* comment = pReadWSQ_comment();
	jstring com = env->NewStringUTF(comment);
	//_controlfp(0x9001f, 0xfffff);

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	return com;
}
//----------------------------------------------------------------------------------------------------------

JNIEXPORT void JNICALL Java_wsq_1sun_1java_WSQ_1library_WriteTIFFcompression(JNIEnv *, jclass, jint compression)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return;
	}

	if (!pWriteTIFFcompression) {
		pWriteTIFFcompression = (WriteTIFFcompression)::GetProcAddress(m_library, "WriteTIFFcompression");
	}
	if (!pWriteTIFFcompression) {
		MessageBoxW(0, L"Unable to get pWriteTIFFcompression function address", L"Error", 0);
		return;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	pWriteTIFFcompression(compression);
	//_controlfp(0x9001f, 0xfffff);

	Set8087CW(0x133f);  // Disable all fpu exceptions.

}
//----------------------------------------------------------------------------------------------------------

JNIEXPORT void JNICALL Java_wsq_1sun_1java_WSQ_1library_WriteTIFFpredictor(JNIEnv *, jclass, jint predicat)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return;
	}

	if (!pWriteTIFFpredictor) {
		pWriteTIFFpredictor = (WriteTIFFpredictor)::GetProcAddress(m_library, "WriteTIFFpredictor");
	}
	if (!pWriteTIFFpredictor) {
		MessageBoxW(0, L"Unable to get pWriteTIFFpredictor function address", L"Error", 0);
		return;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	pWriteTIFFpredictor(predicat);
	//_controlfp(0x9001f, 0xfffff);

	Set8087CW(0x133f);  // Disable all fpu exceptions.

}
//----------------------------------------------------------------------------------------------------------

JNIEXPORT void JNICALL Java_wsq_1sun_1java_WSQ_1library_SetShowFilePropertiesDialog(JNIEnv *, jclass, jint file_properties_dialog)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return;
	}

	if (!pSetShowFilePropertiesDialog) {
		pSetShowFilePropertiesDialog = (SetShowFilePropertiesDialog)::GetProcAddress(m_library, "SetShowFilePropertiesDialog");
	}
	if (!pSetShowFilePropertiesDialog) {
		MessageBoxW(0, L"Unable to get pSetShowFilePropertiesDialog function address", L"Error", 0);
		return;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	pSetShowFilePropertiesDialog(file_properties_dialog);
	//_controlfp(0x9001f, 0xfffff);

	Set8087CW(0x133f);  // Disable all fpu exceptions.

}
//----------------------------------------------------------------------------------------------------------


JNIEXPORT jbyteArray JNICALL Java_wsq_1sun_1java_WSQ_1library_WSQ_1decode_1stream(JNIEnv *env, jclass, jbyteArray input, jintArray imageProperties)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return 0;
	}

	if (!pWSQ_decode_stream) {
		pWSQ_decode_stream = (WSQ_decode_stream)::GetProcAddress(m_library, "WSQ_decode_stream");
	}
	if (!pWSQ_decode_stream) {
		MessageBoxW(0, L"Unable to get pWSQ_decode_stream function address", L"Error", 0);
		return 0;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	jsize input_stream_length = env->GetArrayLength(input);

	jboolean isCopy = JNI_FALSE;
	jbyte * input_data_stream = env->GetByteArrayElements(input, &isCopy);


	static unsigned char* wsq_comment_text = (unsigned char*)NULL;
	int width = 0, height = 0, ppi = 0;


	pWSQ_decode_stream((unsigned char *)input_data_stream, input_stream_length,
		&output_data_stream_decode, &width, &height, &ppi, &wsq_comment_text);

    //char buffer_width[20];
	//char buffer_height[20];
	//itoa(width,buffer_width,10);
	//itoa(height,buffer_height,10);
    //MessageBox(0, (const char*)buffer_width, "width", 0);
    //MessageBox(0, (const char*)buffer_height, "height", 0);


	jbyteArray output = env->NewByteArray(width * height);
	jbyte *poutput = env->GetByteArrayElements(output, 0);
	memcpy(poutput, output_data_stream_decode, width * height);
	env->ReleaseByteArrayElements(output, poutput, 0);

	jint dim[3] = { width, height, ppi };

	env->SetIntArrayRegion(imageProperties, 0, 3, (const jint*)dim);


	//_controlfp(0x9001f, 0xfffff);
	Set8087CW(0x133f);  // Disable all fpu exceptions.

	return output;
}
//----------------------------------------------------------------------------------------------------------


JNIEXPORT jbyteArray JNICALL Java_wsq_1sun_1java_WSQ_1library_WSQ_1encode_1stream
(JNIEnv *env, jclass, jbyteArray input, jint width, jint height, jdouble bitrate, jint ppi, jstring comment_text)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return 0;
	}

	if (!pWSQ_encode_stream) {
		pWSQ_encode_stream = (WSQ_encode_stream)::GetProcAddress(m_library, "WSQ_encode_stream");
	}
	if (!pWSQ_encode_stream) {
		MessageBoxW(0, L"Unable to get pWSQ_encode_stream function address", L"Error", 0);
		return 0;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	jboolean isCopy = JNI_FALSE;
	unsigned char* input_data_stream = (unsigned char*)env->GetByteArrayElements(input, &isCopy);

	static unsigned char* wsq_comment_text2 = (unsigned char*)NULL;
	wsq_comment_text2 = (unsigned char*)env->GetStringUTFChars(comment_text, NULL);

	int output_stream_length;

	pWSQ_encode_stream((unsigned char *)input_data_stream, width, height, bitrate, ppi, (char *)wsq_comment_text2, &output_data_stream_encode, &output_stream_length);

	jbyteArray output = env->NewByteArray(output_stream_length);
	jbyte *poutput = env->GetByteArrayElements(output, 0);
	memcpy(poutput, output_data_stream_encode, output_stream_length);
	env->ReleaseByteArrayElements(output, poutput, 0);

	//if(wsq_comment_text2 != NULL)
	//{ free(wsq_comment_text2); wsq_comment_text2 = (unsigned char*)NULL; }

	//_controlfp(0x9001f, 0xfffff);
	Set8087CW(0x133f);  // Disable all fpu exceptions.

	return output;
}
//----------------------------------------------------------------------------------------------------------





JNIEXPORT jintArray JNICALL Java_wsq_1sun_1java_WSQ_1library_ConvertHBITMAPtoGrayScale256(JNIEnv *env, jclass, jintArray imageDimension, jintArray pixels, jint width, jint height)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return 0;
	}

	if (!pConvertHBITMAPtoGrayScale256) {
		pConvertHBITMAPtoGrayScale256 = (ConvertHBITMAPtoGrayScale256)::GetProcAddress(m_library, "ConvertHBITMAPtoGrayScale256");
	}
	if (!pConvertHBITMAPtoGrayScale256) {
		MessageBoxW(0, L"Unable to get pConvertHBITMAPtoGrayScale256 function address", L"Error", 0);
		return 0;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.


	jboolean isCopy = JNI_FALSE;
	jint* pixel = (jint *)env->GetPrimitiveArrayCritical(pixels, &isCopy);

//	HBITMAP hBitmap = ::CreateBitmap(width, height, 1, 32, pixel); // works on all Windows versions, EXCEPT Windows2003

//static HBITMAP hBitmap = (HBITMAP) NULL;
HBITMAP hBitmap;
RGBTRIPLE* Picture_Line;

//Graphics::TBitmap *pInputBitmap;

if(pInputBitmap != NULL)
{delete pInputBitmap; pInputBitmap = NULL;}

pInputBitmap = new Graphics::TBitmap;
pInputBitmap->Width = width;
pInputBitmap->Height = height;
pInputBitmap->PixelFormat = pf24bit;

int pixel_number;

  for(int y = 0; y < pInputBitmap->Height; y++)
  {
	Picture_Line = (RGBTRIPLE*)pInputBitmap->ScanLine[y];

	for(int x = 0; x < pInputBitmap->Width; x++)
    {
    pixel_number = pInputBitmap->Width*y+x;

			  Picture_Line->rgbtBlue = (unsigned char)((int)pixel[pixel_number] & 0x000Ff);
			  Picture_Line->rgbtGreen = (unsigned char)((((int)pixel[pixel_number])>>8) & 0x000Ff);
			  Picture_Line->rgbtRed = (unsigned char)((((int)pixel[pixel_number])>>16) & 0x000Ff);

      Picture_Line++;
     }
  }

  hBitmap = pInputBitmap->Handle;




	env->ReleasePrimitiveArrayCritical(pixels, pixel, JNI_ABORT);
	if (!hBitmap) {
		MessageBoxW(0, L"Unable to create HBITMAP", L"Error", 0);
		return 0;
	}


//-----------------------	
	//static HBITMAP hBitmap_out = (HBITMAP) NULL;
	HBITMAP hBitmap_out;
	hBitmap_out = pConvertHBITMAPtoGrayScale256(hBitmap);
	if (!hBitmap_out) {
		MessageBoxW(0, L"Unable to get HBITMAP", L"Error", 0);
		return 0;
	}

	BITMAP bm_out;
	GetObject(hBitmap_out, sizeof(bm_out), &bm_out);

	int width_out = bm_out.bmWidth;
	int height_out = bm_out.bmHeight;

	jboolean isDimensionCopy = JNI_FALSE;

	jint* dimension_out = (jint *)env->GetPrimitiveArrayCritical(imageDimension, &isDimensionCopy);
	dimension_out[0] = width_out;
	dimension_out[1] = height_out;
	env->ReleasePrimitiveArrayCritical(imageDimension, dimension_out, JNI_ABORT);


	BITMAPINFO info_out;
	info_out.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	info_out.bmiHeader.biWidth = width_out;
	info_out.bmiHeader.biHeight = -height_out;
	info_out.bmiHeader.biPlanes = 1;
	info_out.bmiHeader.biBitCount = 32;
	info_out.bmiHeader.biCompression = BI_RGB;
	info_out.bmiHeader.biSizeImage = 0;
	info_out.bmiHeader.biClrUsed = 0;

	isCopy = JNI_FALSE;

	HDC hdc_out = CreateCompatibleDC(0);
	jintArray pixels_out = env->NewIntArray(width_out * height_out);
	jint *pixel_out = (jint *)env->GetPrimitiveArrayCritical(pixels_out, &isCopy);

	GetDIBits(hdc_out, hBitmap_out, 0, height_out, pixel_out, &info_out, DIB_RGB_COLORS);

	env->ReleasePrimitiveArrayCritical(pixels_out, pixel_out, JNI_ABORT);



	//_controlfp(0x9001f, 0xfffff);
	Set8087CW(0x133f);  // Disable all fpu exceptions.
	return pixels_out;


}
//----------------------------------------------------------------------------------------------------------



JNIEXPORT jint JNICALL Java_wsq_1sun_1java_WSQ_1library_SaveHBITMAPtoFileAsGrayScale256BMP(JNIEnv *env, jclass, jintArray pixels, jint width, jint height, jstring fileName)
{
	if (!m_library) {
		m_library = ::LoadLibraryW(L"WSQ_library64");
	}
	if (!m_library) {
		MessageBoxW(0, L"Unable to load WSQ_library64.dll", L"Error", 0);
		return 0;
	}

	if (!pSaveHBITMAPtoFileAsGrayScale256BMP) {
		pSaveHBITMAPtoFileAsGrayScale256BMP = (SaveHBITMAPtoFileAsGrayScale256BMP)::GetProcAddress(m_library, "SaveHBITMAPtoFileAsGrayScale256BMP");
	}
	if (!pSaveHBITMAPtoFileAsGrayScale256BMP) {
		MessageBoxW(0, L"Unable to get pSaveHBITMAPtoFileAsGrayScale256BMP function address", L"Error", 0);
		return 0;
	}

	Set8087CW(0x133f);  // Disable all fpu exceptions.

	jboolean isCopy = JNI_FALSE;
	jint* pixel = (jint *)env->GetPrimitiveArrayCritical(pixels, &isCopy);



//	HBITMAP hBitmap = ::CreateBitmap(width, height, 1, 32, pixel); // works on all Windows versions, EXCEPT Windows2003

//static HBITMAP hBitmap = (HBITMAP) NULL;
HBITMAP hBitmap;
RGBTRIPLE* Picture_Line;

//Graphics::TBitmap *pInputBitmap;

if(pInputBitmap != NULL)
{delete pInputBitmap; pInputBitmap = NULL;}

pInputBitmap = new Graphics::TBitmap;
pInputBitmap->Width = width;
pInputBitmap->Height = height;
pInputBitmap->PixelFormat = pf24bit;

int pixel_number;

  for(int y = 0; y < pInputBitmap->Height; y++)
  {
	Picture_Line = (RGBTRIPLE*)pInputBitmap->ScanLine[y];

	for(int x = 0; x < pInputBitmap->Width; x++)
    {
    pixel_number = pInputBitmap->Width*y+x;

			  Picture_Line->rgbtBlue = (unsigned char)((int)pixel[pixel_number] & 0x000Ff);
			  Picture_Line->rgbtGreen = (unsigned char)((((int)pixel[pixel_number])>>8) & 0x000Ff);
			  Picture_Line->rgbtRed = (unsigned char)((((int)pixel[pixel_number])>>16) & 0x000Ff);

      Picture_Line++;
     }
  }
  
hBitmap = pInputBitmap->Handle;



	env->ReleasePrimitiveArrayCritical(pixels, pixel, JNI_ABORT);
	if (!hBitmap) {
		MessageBoxW(0, L"Unable to create HBITMAP", L"Error", 0);
		return 0;
	}

	const char* file = env->GetStringUTFChars(fileName, 0);
	int ret = pSaveHBITMAPtoFileAsGrayScale256BMP(hBitmap, file);
	//_controlfp(0x9001f, 0xfffff);
	Set8087CW(0x133f);  // Disable all fpu exceptions.
	return ret;

}
//----------------------------------------------------------------------------------------------------------


