2003-11-15 21:53:33 +08:00
|
|
|
/*
|
1999-08-27 07:49:39 +08:00
|
|
|
* TWAIN Plug-in
|
|
|
|
* Copyright (C) 1999 Craig Setera
|
2000-05-12 03:27:26 +08:00
|
|
|
* Craig Setera <setera@home.com>
|
1999-08-27 07:49:39 +08:00
|
|
|
* 03/31/1999
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Based on (at least) the following plug-ins:
|
|
|
|
* Screenshot
|
|
|
|
* GIF
|
|
|
|
* Randomize
|
|
|
|
*
|
|
|
|
* Any suggestions, bug-reports or patches are welcome.
|
2003-11-15 21:53:33 +08:00
|
|
|
*
|
1999-08-27 07:49:39 +08:00
|
|
|
* This plug-in interfaces to the TWAIN support library in order
|
|
|
|
* to capture images from TWAIN devices directly into GIMP images.
|
|
|
|
* The plug-in is capable of acquiring the following type of
|
|
|
|
* images:
|
|
|
|
* - B/W (1 bit images translated to grayscale B/W)
|
|
|
|
* - Grayscale up to 16 bits per pixel
|
|
|
|
* - RGB up to 16 bits per sample (24, 30, 36, etc.)
|
|
|
|
* - Paletted images (both Gray and RGB)
|
|
|
|
*
|
|
|
|
* Prerequisites:
|
|
|
|
* This plug-in will not compile on anything other than a Win32
|
|
|
|
* platform. Although the TWAIN documentation implies that there
|
2003-11-15 21:53:33 +08:00
|
|
|
* is TWAIN support available on Macintosh, I neither have a
|
1999-08-27 07:49:39 +08:00
|
|
|
* Macintosh nor the interest in porting this. If anyone else
|
|
|
|
* has an interest, consult www.twain.org for more information on
|
|
|
|
* interfacing to TWAIN.
|
|
|
|
*
|
|
|
|
* Known problems:
|
|
|
|
* - Multiple image transfers will hang the plug-in. The current
|
|
|
|
* configuration compiles with a maximum of single image transfers.
|
|
|
|
*/
|
|
|
|
|
2003-11-15 21:53:33 +08:00
|
|
|
/*
|
1999-08-27 07:49:39 +08:00
|
|
|
* Revision history
|
|
|
|
* (02/07/99) v0.1 First working version (internal)
|
|
|
|
* (02/09/99) v0.2 First release to anyone other than myself
|
|
|
|
* (02/15/99) v0.3 Added image dump and read support for debugging
|
2003-11-15 21:53:33 +08:00
|
|
|
* (03/31/99) v0.5 Added support for multi-byte samples and paletted
|
1999-08-27 07:49:39 +08:00
|
|
|
* images.
|
|
|
|
*/
|
2000-01-19 04:52:16 +08:00
|
|
|
#include "config.h"
|
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
#include <glib.h> /* Needed when compiling with gcc */
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <windows.h>
|
2000-01-19 04:52:16 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
#include "libgimp/gimp.h"
|
2000-01-19 04:52:16 +08:00
|
|
|
#include "libgimp/stdplugins-intl.h"
|
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
#include "tw_func.h"
|
|
|
|
#include "tw_util.h"
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
#include "tw_dump.h"
|
|
|
|
#endif /* _DEBUG */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Plug-in Definitions
|
|
|
|
*/
|
|
|
|
#define PLUG_IN_NAME "twain-acquire"
|
2000-01-31 10:32:30 +08:00
|
|
|
#define PLUG_IN_DESCRIPTION "Capture an image from a TWAIN datasource"
|
|
|
|
#define PLUG_IN_HELP "This plug-in will capture an image from a TWAIN datasource"
|
2000-05-12 03:27:26 +08:00
|
|
|
#define PLUG_IN_AUTHOR "Craig Setera (setera@home.com)"
|
1999-08-27 07:49:39 +08:00
|
|
|
#define PLUG_IN_COPYRIGHT "Craig Setera"
|
|
|
|
#define PLUG_IN_VERSION "v0.5 (03/31/1999)"
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
#define PLUG_IN_D_NAME "twain-acquire-dump"
|
|
|
|
#define PLUG_IN_D_MENU_PATH "<Toolbox>/File/Acquire/TWAIN (Dump)..."
|
|
|
|
|
|
|
|
#define PLUG_IN_R_NAME "twain-acquire-read"
|
|
|
|
#define PLUG_IN_R_MENU_PATH "<Toolbox>/File/Acquire/TWAIN (Read)..."
|
|
|
|
#endif /* _DEBUG */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Application definitions
|
|
|
|
*/
|
|
|
|
#define APP_NAME "TWAIN"
|
|
|
|
#define MAX_IMAGES 1
|
|
|
|
#define SHOW_WINDOW 0
|
|
|
|
#define WM_TRANSFER_IMAGE (WM_USER + 100)
|
|
|
|
|
|
|
|
/*
|
2003-11-15 21:53:33 +08:00
|
|
|
* Definition of the run states
|
1999-08-27 07:49:39 +08:00
|
|
|
*/
|
|
|
|
#define RUN_STANDARD 0
|
|
|
|
#define RUN_DUMP 1
|
|
|
|
#define RUN_READDUMP 2
|
|
|
|
|
|
|
|
/* Global variables */
|
|
|
|
pTW_SESSION twSession = NULL;
|
|
|
|
|
|
|
|
static HWND hwnd = NULL;
|
|
|
|
static HINSTANCE hInst = NULL;
|
|
|
|
static char *destBuf = NULL;
|
|
|
|
static int twain_run_mode = RUN_STANDARD;
|
|
|
|
|
|
|
|
/* Forward declarations */
|
|
|
|
void preTransferCallback(void *);
|
|
|
|
int beginTransferCallback(pTW_IMAGEINFO, void *);
|
|
|
|
int dataTransferCallback(pTW_IMAGEINFO, pTW_IMAGEMEMXFER, void *);
|
|
|
|
int endTransferCallback(int, int, void *);
|
|
|
|
void postTransferCallback(int, void *);
|
|
|
|
|
2003-07-02 08:15:09 +08:00
|
|
|
static void init (void);
|
|
|
|
static void quit (void);
|
|
|
|
static void query (void);
|
|
|
|
static void run (const gchar *name,
|
|
|
|
gint nparams,
|
|
|
|
const GimpParam *param,
|
|
|
|
gint *nreturn_vals,
|
|
|
|
GimpParam **return_vals);
|
1999-08-27 07:49:39 +08:00
|
|
|
|
|
|
|
/* This plug-in's functions */
|
2000-08-24 07:11:07 +08:00
|
|
|
GimpPlugInInfo PLUG_IN_INFO =
|
1999-08-27 07:49:39 +08:00
|
|
|
{
|
|
|
|
NULL, /* init_proc */
|
|
|
|
NULL, /* quit_proc */
|
|
|
|
query, /* query_proc */
|
|
|
|
run, /* run_proc */
|
|
|
|
};
|
2003-11-15 21:53:33 +08:00
|
|
|
|
2000-08-24 07:11:07 +08:00
|
|
|
extern void set_gimp_PLUG_IN_INFO_PTR(GimpPlugInInfo *);
|
1999-08-27 07:49:39 +08:00
|
|
|
|
|
|
|
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
|
|
|
|
|
|
|
/* Data structure holding data between runs */
|
|
|
|
/* Currently unused... Eventually may be used
|
|
|
|
* to track dialog data.
|
|
|
|
*/
|
|
|
|
typedef struct {
|
|
|
|
gchar sourceName[34];
|
|
|
|
gfloat xResolution;
|
|
|
|
gfloat yResolution;
|
|
|
|
gint xOffset;
|
|
|
|
gint yOffset;
|
|
|
|
gint width;
|
|
|
|
gint height;
|
|
|
|
gint imageType;
|
|
|
|
} TwainValues;
|
|
|
|
|
|
|
|
/* Default Twain values */
|
2003-11-15 21:53:33 +08:00
|
|
|
static TwainValues twainvals =
|
|
|
|
{
|
1999-08-27 07:49:39 +08:00
|
|
|
"",
|
|
|
|
100.0, 100.0,
|
|
|
|
0, 0,
|
|
|
|
0, 0,
|
|
|
|
TWPT_RGB
|
|
|
|
};
|
|
|
|
|
|
|
|
/* The standard callback functions */
|
|
|
|
TXFR_CB_FUNCS standardCbFuncs = {
|
|
|
|
preTransferCallback,
|
|
|
|
beginTransferCallback,
|
|
|
|
dataTransferCallback,
|
|
|
|
endTransferCallback,
|
|
|
|
postTransferCallback };
|
|
|
|
|
|
|
|
/******************************************************************
|
|
|
|
* Dump handling
|
|
|
|
******************************************************************/
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
/* The dumper callback functions */
|
|
|
|
TXFR_CB_FUNCS dumperCbFuncs = {
|
|
|
|
dumpPreTransferCallback,
|
|
|
|
dumpBeginTransferCallback,
|
|
|
|
dumpDataTransferCallback,
|
|
|
|
dumpEndTransferCallback,
|
|
|
|
dumpPostTransferCallback };
|
|
|
|
|
|
|
|
static void
|
|
|
|
setRunMode(char *argv[])
|
|
|
|
{
|
|
|
|
char *exeName = strrchr(argv[0], '\\') + 1;
|
|
|
|
|
|
|
|
LogMessage("Executable name: %s\n", exeName);
|
|
|
|
|
|
|
|
if (!_stricmp(exeName, "DTWAIN.EXE"))
|
|
|
|
twain_run_mode = RUN_DUMP;
|
|
|
|
|
|
|
|
if (!_stricmp(exeName, "RTWAIN.EXE"))
|
|
|
|
twain_run_mode = RUN_READDUMP;
|
|
|
|
}
|
|
|
|
#endif /* _DEBUG */
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/******************************************************************
|
|
|
|
* Win32 entry point and setup...
|
|
|
|
******************************************************************/
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/*
|
|
|
|
* WinMain
|
|
|
|
*
|
|
|
|
* The standard gimp entry point won't quite cut it for
|
|
|
|
* this plug-in. This plug-in requires creation of a
|
|
|
|
* standard Win32 window (hidden) in order to receive
|
|
|
|
* and process window messages on behalf of the TWAIN
|
|
|
|
* datasource.
|
|
|
|
*/
|
2003-11-15 21:53:33 +08:00
|
|
|
int APIENTRY
|
1999-08-27 07:49:39 +08:00
|
|
|
WinMain(HINSTANCE hInstance,
|
|
|
|
HINSTANCE hPrevInstance,
|
|
|
|
LPSTR lpCmdLine,
|
|
|
|
int nCmdShow)
|
|
|
|
{
|
2003-11-15 21:53:33 +08:00
|
|
|
|
|
|
|
/*
|
1999-08-27 07:49:39 +08:00
|
|
|
* Normally, we would do all of the Windows-ish set up of
|
|
|
|
* the window classes and stuff here in WinMain. But,
|
|
|
|
* the only time we really need the window and message
|
|
|
|
* queues is during the plug-in run. So, all of that will
|
|
|
|
* be done during run(). This avoids all of the Windows
|
|
|
|
* setup stuff for the query(). Stash the instance handle now
|
|
|
|
* so it is available from the run() procedure.
|
|
|
|
*/
|
|
|
|
hInst = hInstance;
|
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
/* When in debug version, we allow different run modes...
|
|
|
|
* make sure that it is correctly set.
|
|
|
|
*/
|
|
|
|
setRunMode(__argv);
|
|
|
|
#endif /* _DEBUG */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now, call gimp_main... This is what the MAIN() macro
|
|
|
|
* would usually do.
|
|
|
|
*/
|
2003-05-25 01:00:03 +08:00
|
|
|
return gimp_main(&PLUG_IN_INFO, __argc, __argv);
|
1999-08-27 07:49:39 +08:00
|
|
|
}
|
2001-05-26 06:04:21 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* main
|
|
|
|
*
|
|
|
|
* allow to build as console app as well
|
|
|
|
*/
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
|
|
|
/* When in debug version, we allow different run modes...
|
|
|
|
* make sure that it is correctly set.
|
|
|
|
*/
|
|
|
|
setRunMode(__argv);
|
|
|
|
#endif /* _DEBUG */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now, call gimp_main... This is what the MAIN() macro
|
|
|
|
* would usually do.
|
|
|
|
*/
|
2003-05-25 01:00:03 +08:00
|
|
|
return gimp_main(&PLUG_IN_INFO, __argc, __argv);
|
2001-05-26 06:04:21 +08:00
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/*
|
|
|
|
* initTwainAppIdentity
|
|
|
|
*
|
|
|
|
* Initialize and return our application's identity for
|
|
|
|
* the TWAIN runtime.
|
|
|
|
*/
|
|
|
|
static pTW_IDENTITY
|
|
|
|
getAppIdentity(void)
|
|
|
|
{
|
2000-03-11 22:30:36 +08:00
|
|
|
pTW_IDENTITY appIdentity = g_new (TW_IDENTITY, 1);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Set up the application identity */
|
|
|
|
appIdentity->Id = 0;
|
|
|
|
appIdentity->Version.MajorNum = 0;
|
|
|
|
appIdentity->Version.MinorNum = 1;
|
|
|
|
appIdentity->Version.Language = TWLG_USA;
|
|
|
|
appIdentity->Version.Country = TWCY_USA;
|
2000-01-19 04:52:16 +08:00
|
|
|
strcpy(appIdentity->Version.Info, "GIMP TWAIN 0.5");
|
1999-08-27 07:49:39 +08:00
|
|
|
appIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
|
|
|
|
appIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
|
|
|
|
appIdentity->SupportedGroups = DG_IMAGE;
|
|
|
|
strcpy(appIdentity->Manufacturer, "Craig Setera");
|
|
|
|
strcpy(appIdentity->ProductFamily, "GIMP");
|
2000-01-19 04:52:16 +08:00
|
|
|
strcpy(appIdentity->ProductName, "GIMP for Win32");
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
return appIdentity;
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/*
|
|
|
|
* initializeTwain
|
|
|
|
*
|
|
|
|
* Do the necessary TWAIN initialization. This sets up
|
|
|
|
* our TWAIN session information. The session stuff is
|
|
|
|
* something built by me on top of the standard TWAIN
|
|
|
|
* datasource manager calls.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
initializeTwain(void)
|
|
|
|
{
|
|
|
|
pTW_IDENTITY appIdentity;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Get our application's identity */
|
|
|
|
appIdentity = getAppIdentity();
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Create a new session object */
|
|
|
|
twSession = newSession(appIdentity);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Register our image transfer callback functions */
|
|
|
|
#ifdef _DEBUG
|
|
|
|
if (twain_run_mode == RUN_DUMP)
|
|
|
|
registerTransferCallbacks(twSession, &dumperCbFuncs, NULL);
|
|
|
|
else
|
|
|
|
#endif /* _DEBUG */
|
|
|
|
registerTransferCallbacks(twSession, &standardCbFuncs, NULL);
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/*
|
|
|
|
* InitApplication
|
|
|
|
*
|
|
|
|
* Initialize window data and register the window class
|
|
|
|
*/
|
2003-11-15 21:53:33 +08:00
|
|
|
BOOL
|
1999-08-27 07:49:39 +08:00
|
|
|
InitApplication(HINSTANCE hInstance)
|
|
|
|
{
|
|
|
|
WNDCLASS wc;
|
|
|
|
BOOL retValue;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/*
|
|
|
|
* Fill in window class structure with parameters to describe
|
|
|
|
* the main window.
|
|
|
|
*/
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
|
|
wc.lpfnWndProc = (WNDPROC) WndProc;
|
|
|
|
wc.cbClsExtra = 0;
|
|
|
|
wc.cbWndExtra = 0;
|
|
|
|
wc.hInstance = hInstance;
|
|
|
|
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
|
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
|
|
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
|
|
|
|
wc.lpszClassName = APP_NAME;
|
|
|
|
wc.lpszMenuName = NULL;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Register the window class and stash success/failure code. */
|
|
|
|
retValue = RegisterClass(&wc);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Log error */
|
|
|
|
if (!retValue)
|
|
|
|
LogLastWinError();
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
return retValue;
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/*
|
|
|
|
* InitInstance
|
2003-11-15 21:53:33 +08:00
|
|
|
*
|
1999-08-27 07:49:39 +08:00
|
|
|
* Create the main window for the application. Used to
|
|
|
|
* interface with the TWAIN datasource.
|
|
|
|
*/
|
2003-11-15 21:53:33 +08:00
|
|
|
BOOL
|
1999-08-27 07:49:39 +08:00
|
|
|
InitInstance(HINSTANCE hInstance, int nCmdShow)
|
|
|
|
{
|
|
|
|
/* Create our window */
|
|
|
|
hwnd = CreateWindow(APP_NAME, APP_NAME, WS_OVERLAPPEDWINDOW,
|
|
|
|
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
|
|
|
|
NULL, NULL, hInstance, NULL);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
if (!hwnd) {
|
|
|
|
return (FALSE);
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
ShowWindow(hwnd, nCmdShow);
|
|
|
|
UpdateWindow(hwnd);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/*
|
|
|
|
* twainWinMain
|
|
|
|
*
|
|
|
|
* This is the function that represents the code that
|
|
|
|
* would normally reside in WinMain (see above). This
|
|
|
|
* function will get called during run() in order to set
|
|
|
|
* up the windowing environment necessary for TWAIN to
|
|
|
|
* operate.
|
|
|
|
*/
|
|
|
|
int
|
2003-11-15 21:53:33 +08:00
|
|
|
twainWinMain(void)
|
1999-08-27 07:49:39 +08:00
|
|
|
{
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Initialize the twain information */
|
|
|
|
initializeTwain();
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Perform instance initialization */
|
|
|
|
if (!InitApplication(hInst))
|
|
|
|
return (FALSE);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Perform application initialization */
|
|
|
|
if (!InitInstance(hInst, SHOW_WINDOW))
|
|
|
|
return (FALSE);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
|
|
|
/*
|
1999-08-27 07:49:39 +08:00
|
|
|
* Call the main message processing loop...
|
|
|
|
* This call will not return until the application
|
|
|
|
* exits.
|
|
|
|
*/
|
|
|
|
return twainMessageLoop(twSession);
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/*
|
|
|
|
* WndProc
|
|
|
|
*
|
|
|
|
* Process window message for the main window.
|
|
|
|
*/
|
2003-11-15 21:53:33 +08:00
|
|
|
LRESULT CALLBACK
|
1999-08-27 07:49:39 +08:00
|
|
|
WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
switch (message) {
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
case WM_CREATE:
|
|
|
|
/* Register our window handle with the TWAIN
|
|
|
|
* support.
|
|
|
|
*/
|
|
|
|
registerWindowHandle(twSession, hWnd);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Schedule the image transfer by posting a message */
|
|
|
|
PostMessage(hWnd, WM_TRANSFER_IMAGE, 0, 0);
|
|
|
|
break;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
case WM_TRANSFER_IMAGE:
|
|
|
|
/* Get an image */
|
|
|
|
#ifdef _DEBUG
|
|
|
|
if (twain_run_mode == RUN_READDUMP)
|
|
|
|
readDumpedImage(twSession);
|
|
|
|
else
|
|
|
|
#endif /* _DEBUG */
|
|
|
|
getImage(twSession);
|
|
|
|
break;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
case WM_DESTROY:
|
|
|
|
LogMessage("Exiting application\n");
|
|
|
|
PostQuitMessage(0);
|
|
|
|
break;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
default:
|
|
|
|
return (DefWindowProc(hWnd, message, wParam, lParam));
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/******************************************************************
|
|
|
|
* GIMP Plug-in entry points
|
|
|
|
******************************************************************/
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/*
|
|
|
|
* Plug-in Parameter definitions
|
|
|
|
*/
|
|
|
|
#define NUMBER_IN_ARGS 1
|
2000-08-24 07:11:07 +08:00
|
|
|
#define IN_ARGS { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" }
|
1999-08-27 07:49:39 +08:00
|
|
|
#define NUMBER_OUT_ARGS 2
|
|
|
|
#define OUT_ARGS \
|
2000-08-24 07:11:07 +08:00
|
|
|
{ GIMP_PDB_INT32, "image_count", "Number of acquired images" }, \
|
|
|
|
{ GIMP_PDB_INT32ARRAY, "image_ids", "Array of acquired image identifiers" }
|
1999-08-27 07:49:39 +08:00
|
|
|
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/*
|
|
|
|
* query
|
|
|
|
*
|
|
|
|
* The plug-in is being queried. Install our procedure for
|
|
|
|
* acquiring.
|
|
|
|
*/
|
2003-11-15 21:53:33 +08:00
|
|
|
static void
|
2003-03-26 00:38:19 +08:00
|
|
|
query (void)
|
1999-08-27 07:49:39 +08:00
|
|
|
{
|
2000-08-24 07:11:07 +08:00
|
|
|
static GimpParamDef args[] = { IN_ARGS };
|
|
|
|
static GimpParamDef return_vals[] = { OUT_ARGS };
|
1999-08-27 07:49:39 +08:00
|
|
|
|
|
|
|
#ifdef _DEBUG
|
|
|
|
if (twain_run_mode == RUN_DUMP)
|
|
|
|
/* the installation of the plugin */
|
|
|
|
gimp_install_procedure(PLUG_IN_D_NAME,
|
|
|
|
PLUG_IN_DESCRIPTION,
|
|
|
|
PLUG_IN_HELP,
|
|
|
|
PLUG_IN_AUTHOR,
|
|
|
|
PLUG_IN_COPYRIGHT,
|
|
|
|
PLUG_IN_VERSION,
|
|
|
|
PLUG_IN_D_MENU_PATH,
|
|
|
|
NULL,
|
Changed the semantics of GIMP_EXTENSION and (to some extent) of
2003-06-19 Michael Natterer <mitch@gimp.org>
Changed the semantics of GIMP_EXTENSION and (to some extent)
of GIMP_PLUGIN:
The old meaning of EXTENSION was "I live in the toolbox" and
PLUGIN meant "I take RUN-MODE,IMAGE,DRAWABLE args (but only if I
am invoked interactively)". This is completely useless, since
living in the toolbox means having "<Toolbox>" in the menu_path
and taking RUN-MODE,IMAGE,DRAWABLE means just that, regardless of
what type of procedure we are.
The new meaning of GIMP_PLUGIN is just "I am an ordinary procedure,
I am invoked, do my job and finish", while GIMP_EXTENSION means
"I will install temporary procedures and I will keep running to
keep them available".
(A GIMP_EXTENSION *must* call gimp_extension_ack() now to tell the
core that it's ready to run, or the core will block waiting for
the message !!!).
* configure.in: bumped version number to 1.3.16.
* libgimpbase/gimpprotocol.h: increased protocol version number so
old extensions will refuse to load.
* app/gui/plug-in-commands.c (plug_in_run_cmd_callback): don't
blindly pass RUN-MODE,IMAGE,DRAWABLE to GIMP_PLUGIN procedures but
look at their parameters and pass them either RUN-MODE, or
RUN-MODE,IMAGE, or RUN-MODE,IMAGE,DRAWABLE.
* app/pdb/procedural_db.c: cleaned up, better error reporting,
replaced an impossible error message by g_return_if_fail()
* app/plug-in/plug-in-message.c (plug_in_handle_proc_install):
better error messages.
* app/plug-in/plug-in-params.c: allocate parameter arrays using
g_new0() so we don't have to worry about uninitialized stuff
later.
* app/plug-in/plug-in-run.c (plug_in_run): wait for
gimp_extension_ack() installation confirmation for ALL extensions,
not just for automatically started ones.
* app/plug-in/plug-ins.c: cleanup.
* libgimp/gimp.[ch]: cleaned up and API-documented massively. Made
all magic values given in the GPConfig message static and added
accessor functions for them. Added gimp_tile_width()/height().
Added new function gimp_extension_enable() which turns on
asynchronous processing of temp_proc run requests without having
to enter an endless gimp_extension_process() loop. Moved all
private functions to the end of the file. Added tons of
g_return_if_fail() all over the place. Call gimp_run_procedure2()
from gimp_run_procedure() instead of duplicating the
code. Indentation, spacing, stuff...
* libgimp/gimptile.[ch]: removed gimp_tile_width()/height().
* libgimp/gimpdrawable.c
* libgimp/gimppixelrgn.c
* libgimp/gimptile.c: use the gimp_tile_width()/height() accessor
functions.
* libgimp/gimp.def: added gimp_extension_enable.
* libgimp/gimpmenu.c: removed evil code which connected to
_readchannel manually and use gimp_extension_enable() for watching
temp_procs.
* plug-ins/helpbrowser/helpbrowser.c: removed the same evil code
here and call gimp_extension_enable(). Call gimp_extension_ack()
to let the core know that the temp_proc is installed.
* plug-ins/script-fu/script-fu.c: made all procedures except the
permanently running "extension_script_fu" ordinary GIMP_PLUGIN
procedures.
* plug-ins/common/curve_bend.c
* plug-ins/common/plugindetails.c
* plug-ins/common/screenshot.c
* plug-ins/common/uniteditor.c
* plug-ins/common/winclipboard.c
* plug-ins/dbbrowser/dbbrowser.c
* plug-ins/gfli/gfli.c
* plug-ins/twain/twain.c
* plug-ins/webbrowser/webbrowser.c
* plug-ins/winsnap/winsnap.c: made them all ordinary GIMP_PLUGIN
procedures and renamed them from "extension_*" to "plug_in_*".
Random cleanups.
* app/widgets/gimphelp.c
* plug-ins/maze/maze_face.c: call "plug_in_web_browser" now.
2003-06-20 01:12:00 +08:00
|
|
|
GIMP_PLUGIN,
|
1999-08-27 07:49:39 +08:00
|
|
|
NUMBER_IN_ARGS,
|
|
|
|
NUMBER_OUT_ARGS,
|
|
|
|
args,
|
|
|
|
return_vals);
|
|
|
|
|
|
|
|
else if (twain_run_mode == RUN_READDUMP)
|
|
|
|
/* the installation of the plugin */
|
|
|
|
gimp_install_procedure(PLUG_IN_R_NAME,
|
|
|
|
PLUG_IN_DESCRIPTION,
|
|
|
|
PLUG_IN_HELP,
|
|
|
|
PLUG_IN_AUTHOR,
|
|
|
|
PLUG_IN_COPYRIGHT,
|
|
|
|
PLUG_IN_VERSION,
|
|
|
|
PLUG_IN_R_MENU_PATH,
|
|
|
|
NULL,
|
Changed the semantics of GIMP_EXTENSION and (to some extent) of
2003-06-19 Michael Natterer <mitch@gimp.org>
Changed the semantics of GIMP_EXTENSION and (to some extent)
of GIMP_PLUGIN:
The old meaning of EXTENSION was "I live in the toolbox" and
PLUGIN meant "I take RUN-MODE,IMAGE,DRAWABLE args (but only if I
am invoked interactively)". This is completely useless, since
living in the toolbox means having "<Toolbox>" in the menu_path
and taking RUN-MODE,IMAGE,DRAWABLE means just that, regardless of
what type of procedure we are.
The new meaning of GIMP_PLUGIN is just "I am an ordinary procedure,
I am invoked, do my job and finish", while GIMP_EXTENSION means
"I will install temporary procedures and I will keep running to
keep them available".
(A GIMP_EXTENSION *must* call gimp_extension_ack() now to tell the
core that it's ready to run, or the core will block waiting for
the message !!!).
* configure.in: bumped version number to 1.3.16.
* libgimpbase/gimpprotocol.h: increased protocol version number so
old extensions will refuse to load.
* app/gui/plug-in-commands.c (plug_in_run_cmd_callback): don't
blindly pass RUN-MODE,IMAGE,DRAWABLE to GIMP_PLUGIN procedures but
look at their parameters and pass them either RUN-MODE, or
RUN-MODE,IMAGE, or RUN-MODE,IMAGE,DRAWABLE.
* app/pdb/procedural_db.c: cleaned up, better error reporting,
replaced an impossible error message by g_return_if_fail()
* app/plug-in/plug-in-message.c (plug_in_handle_proc_install):
better error messages.
* app/plug-in/plug-in-params.c: allocate parameter arrays using
g_new0() so we don't have to worry about uninitialized stuff
later.
* app/plug-in/plug-in-run.c (plug_in_run): wait for
gimp_extension_ack() installation confirmation for ALL extensions,
not just for automatically started ones.
* app/plug-in/plug-ins.c: cleanup.
* libgimp/gimp.[ch]: cleaned up and API-documented massively. Made
all magic values given in the GPConfig message static and added
accessor functions for them. Added gimp_tile_width()/height().
Added new function gimp_extension_enable() which turns on
asynchronous processing of temp_proc run requests without having
to enter an endless gimp_extension_process() loop. Moved all
private functions to the end of the file. Added tons of
g_return_if_fail() all over the place. Call gimp_run_procedure2()
from gimp_run_procedure() instead of duplicating the
code. Indentation, spacing, stuff...
* libgimp/gimptile.[ch]: removed gimp_tile_width()/height().
* libgimp/gimpdrawable.c
* libgimp/gimppixelrgn.c
* libgimp/gimptile.c: use the gimp_tile_width()/height() accessor
functions.
* libgimp/gimp.def: added gimp_extension_enable.
* libgimp/gimpmenu.c: removed evil code which connected to
_readchannel manually and use gimp_extension_enable() for watching
temp_procs.
* plug-ins/helpbrowser/helpbrowser.c: removed the same evil code
here and call gimp_extension_enable(). Call gimp_extension_ack()
to let the core know that the temp_proc is installed.
* plug-ins/script-fu/script-fu.c: made all procedures except the
permanently running "extension_script_fu" ordinary GIMP_PLUGIN
procedures.
* plug-ins/common/curve_bend.c
* plug-ins/common/plugindetails.c
* plug-ins/common/screenshot.c
* plug-ins/common/uniteditor.c
* plug-ins/common/winclipboard.c
* plug-ins/dbbrowser/dbbrowser.c
* plug-ins/gfli/gfli.c
* plug-ins/twain/twain.c
* plug-ins/webbrowser/webbrowser.c
* plug-ins/winsnap/winsnap.c: made them all ordinary GIMP_PLUGIN
procedures and renamed them from "extension_*" to "plug_in_*".
Random cleanups.
* app/widgets/gimphelp.c
* plug-ins/maze/maze_face.c: call "plug_in_web_browser" now.
2003-06-20 01:12:00 +08:00
|
|
|
GIMP_PLUGIN,
|
1999-08-27 07:49:39 +08:00
|
|
|
NUMBER_IN_ARGS,
|
|
|
|
NUMBER_OUT_ARGS,
|
|
|
|
args,
|
|
|
|
return_vals);
|
|
|
|
else
|
|
|
|
#endif /* _DEBUG */
|
|
|
|
/* the installation of the plugin */
|
|
|
|
gimp_install_procedure(PLUG_IN_NAME,
|
|
|
|
PLUG_IN_DESCRIPTION,
|
|
|
|
PLUG_IN_HELP,
|
|
|
|
PLUG_IN_AUTHOR,
|
|
|
|
PLUG_IN_COPYRIGHT,
|
|
|
|
PLUG_IN_VERSION,
|
2003-11-15 21:53:33 +08:00
|
|
|
N_("<Toolbox>/File/Acquire/_TWAIN..."),
|
1999-08-27 07:49:39 +08:00
|
|
|
NULL,
|
Changed the semantics of GIMP_EXTENSION and (to some extent) of
2003-06-19 Michael Natterer <mitch@gimp.org>
Changed the semantics of GIMP_EXTENSION and (to some extent)
of GIMP_PLUGIN:
The old meaning of EXTENSION was "I live in the toolbox" and
PLUGIN meant "I take RUN-MODE,IMAGE,DRAWABLE args (but only if I
am invoked interactively)". This is completely useless, since
living in the toolbox means having "<Toolbox>" in the menu_path
and taking RUN-MODE,IMAGE,DRAWABLE means just that, regardless of
what type of procedure we are.
The new meaning of GIMP_PLUGIN is just "I am an ordinary procedure,
I am invoked, do my job and finish", while GIMP_EXTENSION means
"I will install temporary procedures and I will keep running to
keep them available".
(A GIMP_EXTENSION *must* call gimp_extension_ack() now to tell the
core that it's ready to run, or the core will block waiting for
the message !!!).
* configure.in: bumped version number to 1.3.16.
* libgimpbase/gimpprotocol.h: increased protocol version number so
old extensions will refuse to load.
* app/gui/plug-in-commands.c (plug_in_run_cmd_callback): don't
blindly pass RUN-MODE,IMAGE,DRAWABLE to GIMP_PLUGIN procedures but
look at their parameters and pass them either RUN-MODE, or
RUN-MODE,IMAGE, or RUN-MODE,IMAGE,DRAWABLE.
* app/pdb/procedural_db.c: cleaned up, better error reporting,
replaced an impossible error message by g_return_if_fail()
* app/plug-in/plug-in-message.c (plug_in_handle_proc_install):
better error messages.
* app/plug-in/plug-in-params.c: allocate parameter arrays using
g_new0() so we don't have to worry about uninitialized stuff
later.
* app/plug-in/plug-in-run.c (plug_in_run): wait for
gimp_extension_ack() installation confirmation for ALL extensions,
not just for automatically started ones.
* app/plug-in/plug-ins.c: cleanup.
* libgimp/gimp.[ch]: cleaned up and API-documented massively. Made
all magic values given in the GPConfig message static and added
accessor functions for them. Added gimp_tile_width()/height().
Added new function gimp_extension_enable() which turns on
asynchronous processing of temp_proc run requests without having
to enter an endless gimp_extension_process() loop. Moved all
private functions to the end of the file. Added tons of
g_return_if_fail() all over the place. Call gimp_run_procedure2()
from gimp_run_procedure() instead of duplicating the
code. Indentation, spacing, stuff...
* libgimp/gimptile.[ch]: removed gimp_tile_width()/height().
* libgimp/gimpdrawable.c
* libgimp/gimppixelrgn.c
* libgimp/gimptile.c: use the gimp_tile_width()/height() accessor
functions.
* libgimp/gimp.def: added gimp_extension_enable.
* libgimp/gimpmenu.c: removed evil code which connected to
_readchannel manually and use gimp_extension_enable() for watching
temp_procs.
* plug-ins/helpbrowser/helpbrowser.c: removed the same evil code
here and call gimp_extension_enable(). Call gimp_extension_ack()
to let the core know that the temp_proc is installed.
* plug-ins/script-fu/script-fu.c: made all procedures except the
permanently running "extension_script_fu" ordinary GIMP_PLUGIN
procedures.
* plug-ins/common/curve_bend.c
* plug-ins/common/plugindetails.c
* plug-ins/common/screenshot.c
* plug-ins/common/uniteditor.c
* plug-ins/common/winclipboard.c
* plug-ins/dbbrowser/dbbrowser.c
* plug-ins/gfli/gfli.c
* plug-ins/twain/twain.c
* plug-ins/webbrowser/webbrowser.c
* plug-ins/winsnap/winsnap.c: made them all ordinary GIMP_PLUGIN
procedures and renamed them from "extension_*" to "plug_in_*".
Random cleanups.
* app/widgets/gimphelp.c
* plug-ins/maze/maze_face.c: call "plug_in_web_browser" now.
2003-06-20 01:12:00 +08:00
|
|
|
GIMP_PLUGIN,
|
1999-08-27 07:49:39 +08:00
|
|
|
NUMBER_IN_ARGS,
|
|
|
|
NUMBER_OUT_ARGS,
|
|
|
|
args,
|
|
|
|
return_vals);
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Return values storage */
|
2000-08-24 07:11:07 +08:00
|
|
|
static GimpParam values[3];
|
1999-08-27 07:49:39 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* run
|
|
|
|
*
|
|
|
|
* The plug-in is being requested to run.
|
|
|
|
* Capture an image from a TWAIN datasource
|
|
|
|
*/
|
2003-11-15 21:53:33 +08:00
|
|
|
static void
|
2003-07-02 08:15:09 +08:00
|
|
|
run (const gchar *name,
|
|
|
|
gint nparams,
|
|
|
|
const GimpParam *param,
|
|
|
|
gint *nreturn_vals,
|
|
|
|
GimpParam **return_vals)
|
1999-08-27 07:49:39 +08:00
|
|
|
{
|
2001-12-19 08:13:16 +08:00
|
|
|
GimpRunMode run_mode;
|
1999-08-27 07:49:39 +08:00
|
|
|
|
|
|
|
/* Initialize the return values
|
2003-11-15 21:53:33 +08:00
|
|
|
* Always return at least the status to the caller.
|
1999-08-27 07:49:39 +08:00
|
|
|
*/
|
2000-08-24 07:11:07 +08:00
|
|
|
values[0].type = GIMP_PDB_STATUS;
|
|
|
|
values[0].data.d_status = GIMP_PDB_SUCCESS;
|
1999-08-27 07:49:39 +08:00
|
|
|
*nreturn_vals = 1;
|
|
|
|
*return_vals = values;
|
|
|
|
|
2003-03-26 00:38:19 +08:00
|
|
|
INIT_I18N ();
|
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Before we get any further, verify that we have
|
|
|
|
* TWAIN and that there is actually a datasource
|
|
|
|
* to be used in doing the acquire.
|
|
|
|
*/
|
|
|
|
if (!twainIsAvailable()) {
|
2000-08-24 07:11:07 +08:00
|
|
|
values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
|
1999-08-27 07:49:39 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the runmode from the in-parameters */
|
|
|
|
run_mode = param[0].data.d_int32;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Set up the rest of the return parameters */
|
2000-08-24 07:11:07 +08:00
|
|
|
values[1].type = GIMP_PDB_INT32;
|
1999-08-27 07:49:39 +08:00
|
|
|
values[1].data.d_int32 = 0;
|
2000-08-24 07:11:07 +08:00
|
|
|
values[2].type = GIMP_PDB_INT32ARRAY;
|
2000-03-11 22:30:36 +08:00
|
|
|
values[2].data.d_int32array = g_new (gint32, MAX_IMAGES);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* How are we running today? */
|
|
|
|
switch (run_mode) {
|
2000-08-24 07:11:07 +08:00
|
|
|
case GIMP_RUN_INTERACTIVE:
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Retrieve values from the last run...
|
|
|
|
* Currently ignored
|
|
|
|
*/
|
|
|
|
gimp_get_data(PLUG_IN_NAME, &twainvals);
|
|
|
|
break;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
2000-08-24 07:11:07 +08:00
|
|
|
case GIMP_RUN_NONINTERACTIVE:
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Currently, we don't do non-interactive calls.
|
|
|
|
* Bail if someone tries to call us non-interactively
|
|
|
|
*/
|
2000-08-24 07:11:07 +08:00
|
|
|
values[0].data.d_status = GIMP_PDB_CALLING_ERROR;
|
1999-08-27 07:49:39 +08:00
|
|
|
return;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
2000-08-24 07:11:07 +08:00
|
|
|
case GIMP_RUN_WITH_LAST_VALS:
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Retrieve values from the last run...
|
|
|
|
* Currently ignored
|
|
|
|
*/
|
|
|
|
gimp_get_data(PLUG_IN_NAME, &twainvals);
|
|
|
|
break;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
} /* switch */
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Have we succeeded so far? */
|
2000-08-24 07:11:07 +08:00
|
|
|
if (values[0].data.d_status == GIMP_PDB_SUCCESS)
|
1999-08-27 07:49:39 +08:00
|
|
|
twainWinMain();
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Check to make sure we got at least one valid
|
|
|
|
* image.
|
|
|
|
*/
|
|
|
|
if (values[1].data.d_int32 > 0) {
|
|
|
|
/* An image was captured from the TWAIN
|
|
|
|
* datasource. Do final Interactive
|
|
|
|
* steps.
|
|
|
|
*/
|
2000-08-24 07:11:07 +08:00
|
|
|
if (run_mode == GIMP_RUN_INTERACTIVE) {
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Store variable states for next run */
|
|
|
|
gimp_set_data(PLUG_IN_NAME, &twainvals, sizeof (TwainValues));
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Set return values */
|
|
|
|
*nreturn_vals = 3;
|
|
|
|
} else {
|
2000-08-24 07:11:07 +08:00
|
|
|
values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
|
1999-08-27 07:49:39 +08:00
|
|
|
}
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/***********************************************************************
|
|
|
|
* Image transfer callback functions
|
|
|
|
***********************************************************************/
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Data used to carry data between each of
|
|
|
|
* the callback function calls.
|
|
|
|
*/
|
|
|
|
typedef struct {
|
|
|
|
gint32 image_id;
|
|
|
|
gint32 layer_id;
|
2000-08-24 07:11:07 +08:00
|
|
|
GimpPixelRgn pixel_rgn;
|
|
|
|
GimpDrawable *drawable;
|
1999-08-27 07:49:39 +08:00
|
|
|
pTW_PALETTE8 paletteData;
|
|
|
|
int totalPixels;
|
|
|
|
int completedPixels;
|
|
|
|
} ClientDataStruct, *pClientDataStruct;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* preTransferCallback
|
|
|
|
*
|
|
|
|
* This callback function is called before any images
|
|
|
|
* are transferred. Set up the one time only stuff.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
preTransferCallback(void *clientData)
|
|
|
|
{
|
|
|
|
/* Initialize our progress dialog */
|
2003-11-15 21:53:33 +08:00
|
|
|
gimp_progress_init(_("Transferring TWAIN data..."));
|
1999-08-27 07:49:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* beginTransferCallback
|
|
|
|
*
|
|
|
|
* The following function is called at the beginning
|
|
|
|
* of each image transfer.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
beginTransferCallback(pTW_IMAGEINFO imageInfo, void *clientData)
|
|
|
|
{
|
|
|
|
int done = 0;
|
|
|
|
int imageType, layerType;
|
|
|
|
|
2000-03-11 22:30:36 +08:00
|
|
|
pClientDataStruct theClientData = g_new (ClientDataStruct, 1);
|
1999-08-27 07:49:39 +08:00
|
|
|
|
2003-11-15 21:53:33 +08:00
|
|
|
#ifdef _DEBUG
|
1999-08-27 07:49:39 +08:00
|
|
|
logBegin(imageInfo, clientData);
|
|
|
|
#endif
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Decide on the image type */
|
|
|
|
switch (imageInfo->PixelType) {
|
|
|
|
case TWPT_BW:
|
|
|
|
case TWPT_GRAY:
|
|
|
|
/* Set up the image and layer types */
|
2000-08-24 07:11:07 +08:00
|
|
|
imageType = GIMP_GRAY;
|
|
|
|
layerType = GIMP_GRAY_IMAGE;
|
1999-08-27 07:49:39 +08:00
|
|
|
break;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
case TWPT_RGB:
|
|
|
|
/* Set up the image and layer types */
|
2000-08-24 07:11:07 +08:00
|
|
|
imageType = GIMP_RGB;
|
|
|
|
layerType = GIMP_RGB_IMAGE;
|
1999-08-27 07:49:39 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TWPT_PALETTE:
|
|
|
|
/* Get the palette data */
|
2000-03-11 22:30:36 +08:00
|
|
|
theClientData->paletteData = g_new (TW_PALETTE8, 1);
|
1999-08-27 07:49:39 +08:00
|
|
|
twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
|
|
|
|
DG_IMAGE, DAT_PALETTE8, MSG_GET,
|
|
|
|
(TW_MEMREF) theClientData->paletteData);
|
|
|
|
if (twSession->twRC != TWRC_SUCCESS)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
switch (theClientData->paletteData->PaletteType) {
|
|
|
|
case TWPA_RGB:
|
|
|
|
/* Set up the image and layer types */
|
2000-08-24 07:11:07 +08:00
|
|
|
imageType = GIMP_RGB;
|
|
|
|
layerType = GIMP_RGB_IMAGE;
|
1999-08-27 07:49:39 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
case TWPA_GRAY:
|
|
|
|
/* Set up the image and layer types */
|
2000-08-24 07:11:07 +08:00
|
|
|
imageType = GIMP_GRAY;
|
|
|
|
layerType = GIMP_GRAY_IMAGE;
|
1999-08-27 07:49:39 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
/* We don't know how to deal with anything other than
|
|
|
|
* the types listed above. Bail for any other image
|
|
|
|
* type.
|
|
|
|
*/
|
|
|
|
return FALSE;
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Create the GIMP image */
|
2003-11-15 21:53:33 +08:00
|
|
|
theClientData->image_id = gimp_image_new(imageInfo->ImageWidth,
|
1999-08-27 07:49:39 +08:00
|
|
|
imageInfo->ImageLength, imageType);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Create a layer */
|
|
|
|
theClientData->layer_id = gimp_layer_new(theClientData->image_id,
|
2000-01-19 04:52:16 +08:00
|
|
|
_("Background"),
|
2003-11-15 21:53:33 +08:00
|
|
|
imageInfo->ImageWidth,
|
1999-08-27 07:49:39 +08:00
|
|
|
imageInfo->ImageLength,
|
2000-08-24 07:11:07 +08:00
|
|
|
layerType, 100, GIMP_NORMAL_MODE);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Add the layer to the image */
|
2003-11-15 21:53:33 +08:00
|
|
|
gimp_image_add_layer(theClientData->image_id,
|
1999-08-27 07:49:39 +08:00
|
|
|
theClientData->layer_id, 0);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Update the progress dialog */
|
|
|
|
theClientData->totalPixels = imageInfo->ImageWidth * imageInfo->ImageLength;
|
|
|
|
theClientData->completedPixels = 0;
|
|
|
|
gimp_progress_update((double) 0);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Get our drawable */
|
|
|
|
theClientData->drawable = gimp_drawable_get(theClientData->layer_id);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Initialize a pixel region for writing to the image */
|
2003-11-15 21:53:33 +08:00
|
|
|
gimp_pixel_rgn_init(&(theClientData->pixel_rgn), theClientData->drawable,
|
1999-08-27 07:49:39 +08:00
|
|
|
0, 0, imageInfo->ImageWidth, imageInfo->ImageLength,
|
|
|
|
TRUE, FALSE);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Store our client data for the data transfer callbacks */
|
|
|
|
if (clientData)
|
2000-03-11 22:30:36 +08:00
|
|
|
g_free (clientData);
|
1999-08-27 07:49:39 +08:00
|
|
|
setClientData(twSession, (void *) theClientData);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Make sure to return TRUE to continue the image
|
|
|
|
* transfer
|
|
|
|
*/
|
|
|
|
return TRUE;
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/*
|
|
|
|
* bitTransferCallback
|
|
|
|
*
|
|
|
|
* The following function is called for each memory
|
|
|
|
* block that is transferred from the data source if
|
|
|
|
* the image type is Black/White.
|
|
|
|
*
|
|
|
|
* Black and white data is unpacked from bit data
|
|
|
|
* into byte data and written into a gray scale GIMP
|
|
|
|
* image.
|
|
|
|
*/
|
|
|
|
static char bitMasks[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
|
2003-11-15 21:53:33 +08:00
|
|
|
static int
|
1999-08-27 07:49:39 +08:00
|
|
|
bitTransferCallback(pTW_IMAGEINFO imageInfo,
|
|
|
|
pTW_IMAGEMEMXFER imageMemXfer,
|
|
|
|
void *clientData)
|
|
|
|
{
|
|
|
|
int row, col, offset;
|
|
|
|
char *srcBuf;
|
|
|
|
int rows = imageMemXfer->Rows;
|
|
|
|
int cols = imageMemXfer->Columns;
|
|
|
|
pClientDataStruct theClientData = (pClientDataStruct) clientData;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Allocate a buffer as necessary */
|
|
|
|
if (!destBuf)
|
2000-03-11 22:30:36 +08:00
|
|
|
destBuf = g_new (char, rows * cols);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Unpack the image data from bits into bytes */
|
|
|
|
srcBuf = (char *) imageMemXfer->Memory.TheMem;
|
|
|
|
offset = 0;
|
|
|
|
for (row = 0; row < rows; row++) {
|
|
|
|
for (col = 0; col < cols; col++) {
|
|
|
|
char byte = srcBuf[(row * imageMemXfer->BytesPerRow) + (col / 8)];
|
|
|
|
destBuf[offset++] = ((byte & bitMasks[col % 8]) != 0) ? 255 : 0;
|
|
|
|
}
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Update the complete chunk */
|
2003-11-15 21:53:33 +08:00
|
|
|
gimp_pixel_rgn_set_rect(&(theClientData->pixel_rgn),
|
1999-08-27 07:49:39 +08:00
|
|
|
(guchar *) destBuf,
|
|
|
|
imageMemXfer->XOffset, imageMemXfer->YOffset,
|
|
|
|
cols, rows);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Update the user on our progress */
|
|
|
|
theClientData->completedPixels += (cols * rows);
|
2003-11-15 21:53:33 +08:00
|
|
|
gimp_progress_update((double) theClientData->completedPixels /
|
1999-08-27 07:49:39 +08:00
|
|
|
(double) theClientData->totalPixels);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/*
|
|
|
|
* oneBytePerSampleTransferCallback
|
|
|
|
*
|
|
|
|
* The following function is called for each memory
|
|
|
|
* block that is transferred from the data source if
|
|
|
|
* the image type is Grayscale or RGB. This transfer
|
|
|
|
* mode is quicker than the modes that require translation
|
|
|
|
* from a greater number of bits per sample down to the
|
|
|
|
* 8 bits per sample understood by The GIMP.
|
|
|
|
*/
|
2003-11-15 21:53:33 +08:00
|
|
|
static int
|
1999-08-27 07:49:39 +08:00
|
|
|
oneBytePerSampleTransferCallback(pTW_IMAGEINFO imageInfo,
|
|
|
|
pTW_IMAGEMEMXFER imageMemXfer,
|
|
|
|
void *clientData)
|
|
|
|
{
|
|
|
|
int row;
|
|
|
|
char *srcBuf;
|
|
|
|
int bytesPerPixel = imageInfo->BitsPerPixel / 8;
|
|
|
|
int rows = imageMemXfer->Rows;
|
|
|
|
int cols = imageMemXfer->Columns;
|
|
|
|
pClientDataStruct theClientData = (pClientDataStruct) clientData;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Allocate a buffer as necessary */
|
|
|
|
if (!destBuf)
|
2000-03-11 22:30:36 +08:00
|
|
|
destBuf = g_new (char, rows * cols * bytesPerPixel);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* The bytes coming from the source may not be padded in
|
|
|
|
* a way that The GIMP is terribly happy with. It is
|
|
|
|
* possible to transfer row by row, but that is particularly
|
|
|
|
* expensive in terms of performance. It is much cheaper
|
|
|
|
* to rearrange the data and transfer it in one large chunk.
|
|
|
|
* The next chunk of code rearranges the incoming data into
|
|
|
|
* a non-padded chunk for The GIMP.
|
|
|
|
*/
|
|
|
|
srcBuf = (char *) imageMemXfer->Memory.TheMem;
|
|
|
|
for (row = 0; row < rows; row++) {
|
|
|
|
/* Copy the current row */
|
|
|
|
memcpy((destBuf + (row * bytesPerPixel * cols)),
|
|
|
|
(srcBuf + (row * imageMemXfer->BytesPerRow)),
|
|
|
|
(bytesPerPixel * cols));
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Update the complete chunk */
|
2003-11-15 21:53:33 +08:00
|
|
|
gimp_pixel_rgn_set_rect(&(theClientData->pixel_rgn),
|
1999-08-27 07:49:39 +08:00
|
|
|
(guchar *) destBuf,
|
|
|
|
imageMemXfer->XOffset, imageMemXfer->YOffset,
|
|
|
|
cols, rows);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Update the user on our progress */
|
|
|
|
theClientData->completedPixels += (cols * rows);
|
2003-11-15 21:53:33 +08:00
|
|
|
gimp_progress_update((double) theClientData->completedPixels /
|
1999-08-27 07:49:39 +08:00
|
|
|
(double) theClientData->totalPixels);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/*
|
|
|
|
* twoBytesPerSampleTransferCallback
|
|
|
|
*
|
|
|
|
* The following function is called for each memory
|
|
|
|
* block that is transferred from the data source if
|
|
|
|
* the image type is Grayscale or RGB.
|
2003-11-15 21:53:33 +08:00
|
|
|
*/
|
|
|
|
static int
|
1999-08-27 07:49:39 +08:00
|
|
|
twoBytesPerSampleTransferCallback(pTW_IMAGEINFO imageInfo,
|
|
|
|
pTW_IMAGEMEMXFER imageMemXfer,
|
|
|
|
void *clientData)
|
|
|
|
{
|
|
|
|
static float ratio = 0.00390625;
|
|
|
|
int row, col, sample;
|
|
|
|
char *srcBuf, *destByte;
|
|
|
|
int rows = imageMemXfer->Rows;
|
|
|
|
int cols = imageMemXfer->Columns;
|
|
|
|
int bitsPerSample = imageInfo->BitsPerPixel / imageInfo->SamplesPerPixel;
|
|
|
|
int bytesPerSample = bitsPerSample / 8;
|
|
|
|
|
|
|
|
TW_UINT16 *samplePtr;
|
|
|
|
|
|
|
|
pClientDataStruct theClientData = (pClientDataStruct) clientData;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Allocate a buffer as necessary */
|
|
|
|
if (!destBuf)
|
2000-03-11 22:30:36 +08:00
|
|
|
destBuf = g_new (char, rows * cols * imageInfo->SamplesPerPixel);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* The bytes coming from the source may not be padded in
|
|
|
|
* a way that The GIMP is terribly happy with. It is
|
|
|
|
* possible to transfer row by row, but that is particularly
|
|
|
|
* expensive in terms of performance. It is much cheaper
|
|
|
|
* to rearrange the data and transfer it in one large chunk.
|
|
|
|
* The next chunk of code rearranges the incoming data into
|
|
|
|
* a non-padded chunk for The GIMP. This function must also
|
|
|
|
* reduce from multiple bytes per sample down to single byte
|
|
|
|
* per sample.
|
|
|
|
*/
|
|
|
|
/* Work through the rows */
|
|
|
|
for (row = 0; row < rows; row++) {
|
|
|
|
/* The start of this source row */
|
2003-11-15 21:53:33 +08:00
|
|
|
samplePtr = (TW_UINT16 *)
|
1999-08-27 07:49:39 +08:00
|
|
|
((char *) imageMemXfer->Memory.TheMem + (row * imageMemXfer->BytesPerRow));
|
|
|
|
|
|
|
|
/* The start of this dest row */
|
|
|
|
destByte = destBuf + (row * imageInfo->SamplesPerPixel * cols);
|
|
|
|
|
|
|
|
/* Work through the columns */
|
|
|
|
for (col = 0; col < cols; col++) {
|
|
|
|
/* Finally, work through each of the samples */
|
|
|
|
for (sample = 0; sample < imageInfo->SamplesPerPixel; sample++) {
|
|
|
|
/* Get the value */
|
|
|
|
TW_UINT16 value = *samplePtr;
|
|
|
|
|
|
|
|
/* Move the sample pointer */
|
|
|
|
samplePtr++;
|
|
|
|
|
|
|
|
/* Place in the destination */
|
|
|
|
*destByte = (char) ((float) value * (float) ratio);
|
|
|
|
destByte++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Send the complete chunk */
|
2003-11-15 21:53:33 +08:00
|
|
|
gimp_pixel_rgn_set_rect(&(theClientData->pixel_rgn),
|
1999-08-27 07:49:39 +08:00
|
|
|
(guchar *) destBuf,
|
|
|
|
imageMemXfer->XOffset, imageMemXfer->YOffset,
|
|
|
|
cols, rows);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Update the user on our progress */
|
|
|
|
theClientData->completedPixels += (cols * rows);
|
2003-11-15 21:53:33 +08:00
|
|
|
gimp_progress_update((double) theClientData->completedPixels /
|
1999-08-27 07:49:39 +08:00
|
|
|
(double) theClientData->totalPixels);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/*
|
|
|
|
* palettedTransferCallback
|
|
|
|
*
|
|
|
|
* The following function is called for each memory
|
|
|
|
* block that is transferred from the data source if
|
|
|
|
* the image type is paletted. This does not create
|
|
|
|
* an indexed image type in The GIMP because for some
|
|
|
|
* reason it does not allow creation of a specific
|
|
|
|
* palette. This function will create an RGB or Gray
|
|
|
|
* image and use the palette to set the details of
|
|
|
|
* the pixels.
|
2003-11-15 21:53:33 +08:00
|
|
|
*/
|
|
|
|
static int
|
1999-08-27 07:49:39 +08:00
|
|
|
palettedTransferCallback(pTW_IMAGEINFO imageInfo,
|
|
|
|
pTW_IMAGEMEMXFER imageMemXfer,
|
|
|
|
void *clientData)
|
|
|
|
{
|
|
|
|
int channelsPerEntry;
|
|
|
|
int row, col;
|
|
|
|
int rows = imageMemXfer->Rows;
|
|
|
|
int cols = imageMemXfer->Columns;
|
|
|
|
char *destPtr = NULL, *srcPtr = NULL;
|
|
|
|
|
|
|
|
/* Get the client data */
|
|
|
|
pClientDataStruct theClientData = (pClientDataStruct) clientData;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Look up the palette entry size */
|
2003-11-15 21:53:33 +08:00
|
|
|
channelsPerEntry =
|
1999-08-27 07:49:39 +08:00
|
|
|
(theClientData->paletteData->PaletteType == TWPA_RGB) ? 3 : 1;
|
|
|
|
|
|
|
|
/* Allocate a buffer as necessary */
|
|
|
|
if (!destBuf)
|
2000-03-11 22:30:36 +08:00
|
|
|
destBuf = g_new (char, rows * cols * channelsPerEntry);
|
1999-08-27 07:49:39 +08:00
|
|
|
|
|
|
|
/* Work through the rows */
|
|
|
|
destPtr = destBuf;
|
|
|
|
for (row = 0; row < rows; row++) {
|
2003-11-15 21:53:33 +08:00
|
|
|
srcPtr = (char *) ((char *) imageMemXfer->Memory.TheMem +
|
1999-08-27 07:49:39 +08:00
|
|
|
(row * imageMemXfer->BytesPerRow));
|
|
|
|
|
|
|
|
/* Work through the columns */
|
|
|
|
for (col = 0; col < cols; col++) {
|
|
|
|
/* Get the palette index */
|
|
|
|
int index = (unsigned char) *srcPtr;
|
|
|
|
srcPtr++;
|
|
|
|
|
|
|
|
switch (theClientData->paletteData->PaletteType) {
|
|
|
|
case TWPA_GRAY:
|
|
|
|
*destPtr = theClientData->paletteData->Colors[index].Channel1;
|
|
|
|
destPtr++;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TWPA_RGB:
|
|
|
|
*destPtr = theClientData->paletteData->Colors[index].Channel1;
|
|
|
|
destPtr++;
|
|
|
|
*destPtr = theClientData->paletteData->Colors[index].Channel2;
|
|
|
|
destPtr++;
|
|
|
|
*destPtr = theClientData->paletteData->Colors[index].Channel3;
|
|
|
|
destPtr++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Send the complete chunk */
|
2003-11-15 21:53:33 +08:00
|
|
|
gimp_pixel_rgn_set_rect(&(theClientData->pixel_rgn),
|
1999-08-27 07:49:39 +08:00
|
|
|
(guchar *) destBuf,
|
|
|
|
imageMemXfer->XOffset, imageMemXfer->YOffset,
|
|
|
|
cols, rows);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Update the user on our progress */
|
|
|
|
theClientData->completedPixels += (cols * rows);
|
2003-11-15 21:53:33 +08:00
|
|
|
gimp_progress_update((double) theClientData->completedPixels /
|
1999-08-27 07:49:39 +08:00
|
|
|
(double) theClientData->totalPixels);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/*
|
|
|
|
* dataTransferCallback
|
|
|
|
*
|
|
|
|
* The following function is called for each memory
|
|
|
|
* block that is transferred from the data source.
|
|
|
|
*/
|
2003-11-15 21:53:33 +08:00
|
|
|
int
|
1999-08-27 07:49:39 +08:00
|
|
|
dataTransferCallback(pTW_IMAGEINFO imageInfo,
|
|
|
|
pTW_IMAGEMEMXFER imageMemXfer,
|
|
|
|
void *clientData)
|
|
|
|
{
|
|
|
|
#ifdef _DEBUG
|
|
|
|
logData(imageInfo, imageMemXfer, clientData);
|
|
|
|
#endif
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Choose the appropriate transfer handler */
|
|
|
|
switch (imageInfo->PixelType) {
|
|
|
|
case TWPT_PALETTE:
|
|
|
|
return palettedTransferCallback(imageInfo, imageMemXfer, clientData);
|
|
|
|
|
|
|
|
case TWPT_BW:
|
|
|
|
return bitTransferCallback(imageInfo, imageMemXfer, clientData);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
case TWPT_GRAY:
|
|
|
|
case TWPT_RGB:
|
|
|
|
switch (imageInfo->BitsPerPixel / imageInfo->SamplesPerPixel) {
|
|
|
|
case 8:
|
|
|
|
return oneBytePerSampleTransferCallback(imageInfo, imageMemXfer, clientData);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
case 16:
|
|
|
|
return twoBytesPerSampleTransferCallback(imageInfo, imageMemXfer, clientData);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/*
|
|
|
|
* endTransferCallback
|
|
|
|
*
|
|
|
|
* The following function is called at the end of the
|
|
|
|
* image transfer. The caller will be handed
|
|
|
|
* the image transfer completion state. The
|
|
|
|
* following values (defined in twain.h) are
|
|
|
|
* possible:
|
|
|
|
*
|
|
|
|
* TWRC_XFERDONE
|
|
|
|
* The transfer completed successfully
|
|
|
|
* TWRC_CANCEL
|
|
|
|
* The transfer was completed by the user
|
|
|
|
* TWRC_FAILURE
|
|
|
|
* The transfer failed.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
endTransferCallback(int completionState, int pendingCount, void *clientData)
|
|
|
|
{
|
|
|
|
pClientDataStruct theClientData = (pClientDataStruct) clientData;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
LogMessage("endTransferCallback: CompState = %d, pending = %d\n",
|
|
|
|
completionState, pendingCount);
|
|
|
|
|
|
|
|
/* Clean up and detach from the drawable */
|
|
|
|
if (destBuf) {
|
2000-03-11 22:30:36 +08:00
|
|
|
g_free (destBuf);
|
1999-08-27 07:49:39 +08:00
|
|
|
destBuf = NULL;
|
|
|
|
}
|
|
|
|
gimp_drawable_flush(theClientData->drawable);
|
|
|
|
gimp_drawable_detach(theClientData->drawable);
|
|
|
|
|
|
|
|
/* Make sure to check our return code */
|
|
|
|
if (completionState == TWRC_XFERDONE) {
|
|
|
|
/* We have a completed image transfer */
|
2003-11-15 21:53:33 +08:00
|
|
|
values[2].type = GIMP_PDB_INT32ARRAY;
|
1999-08-27 07:49:39 +08:00
|
|
|
values[2].data.d_int32array[values[1].data.d_int32++] =
|
|
|
|
theClientData->image_id;
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Display the image */
|
|
|
|
LogMessage("Displaying image %d\n", theClientData->image_id);
|
2000-01-15 05:38:47 +08:00
|
|
|
gimp_display_new (theClientData->image_id);
|
1999-08-27 07:49:39 +08:00
|
|
|
} else {
|
|
|
|
/* The transfer did not complete successfully */
|
|
|
|
LogMessage("Deleting image\n");
|
|
|
|
gimp_image_delete(theClientData->image_id);
|
|
|
|
}
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Shut down if we have received all of the possible images */
|
|
|
|
return (values[1].data.d_int32 < MAX_IMAGES);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* postTransferCallback
|
|
|
|
*
|
|
|
|
* This callback function will be called
|
|
|
|
* after all possible images have been
|
|
|
|
* transferred.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
postTransferCallback(int pendingCount, void *clientData)
|
|
|
|
{
|
|
|
|
/* Shut things down. */
|
|
|
|
if (pendingCount != 0)
|
|
|
|
cancelPendingTransfers(twSession);
|
|
|
|
|
|
|
|
/* This will close the datasource and datasource
|
|
|
|
* manager. Then the message queue will be shut
|
|
|
|
* down and the run() procedure will finally be
|
|
|
|
* able to finish.
|
|
|
|
*/
|
|
|
|
disableDS(twSession);
|
|
|
|
closeDS(twSession);
|
|
|
|
closeDSM(twSession);
|
2003-11-15 21:53:33 +08:00
|
|
|
|
1999-08-27 07:49:39 +08:00
|
|
|
/* Post a message to close up the application */
|
|
|
|
PostQuitMessage(0);
|
|
|
|
}
|