Initial checkin of Pika from heckimp

This commit is contained in:
2023-09-25 15:35:21 -07:00
commit 891e999216
6761 changed files with 5240685 additions and 0 deletions

92
plug-ins/twain/README Normal file
View File

@ -0,0 +1,92 @@
TWAIN Plug-in
Copyright (C) 1999 Craig Setera
Craig Setera <setera@home.com>
03/31/1999
Updated for Mac OS X support
Brion Vibber <brion@pobox.com>
07/22/2004
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 3 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, see <https://www.gnu.org/licenses/>.
Based on (at least) the following plug-ins:
Screenshot
GIF
Randomize
Any suggestions, bug-reports or patches are welcome.
This plug-in interfaces to the TWAIN support library in order
to capture images from TWAIN devices directly into PIKA 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:
Should compile and run on both Win32 and Mac OS X 10.3 (possibly
also on 10.2).
Known problems:
- Multiple image transfers will hang the plug-in. The current
configuration compiles with a maximum of single image transfers.
- On Mac OS X, canceling doesn't always close things out fully.
- Epson TWAIN driver on Mac OS X crashes the plugin when scanning.
Debugging:
There are two different versions of the program included, a standard
version and a version built for debugging. The debugging version is
a special version capable of capturing the TWAIN datasource data to
a file for later processing. This feature can be used to create a data
dump that can be sent to me if for some reason the plug-in fails for
your TWAIN datasource. The function of the plug-in is controlled by
the name of the executable file. The plug-in should be placed in your
plug-ins directory and named as follows:
twain.exe - This is the standard (non-debugging) version. This file will
not behave differently if renamed. This version is intended to be used
unless your TWAIN datasource has some problem.
gtwain.exe - This is the debugging version of the program shipped along.
If this program is used as named, it will behave the same as "twain.exe"
except that the file C:\twain.log will be written. This file is a text
file with very little information available for debugging.
dtwain.exe - Renaming "gtwain.exe" to "dtwain.exe" in your plug-ins directory
will change the behavior of the plug-in. The menu option will be registered
as "TWAIN Acquire (Dump)..." and will cause the TWAIN acquire operation to
be dumped to the file "C:\twaincap.bin". This file contains all of the data
necessary to recreate the capture on another system (such as my machine). The
image will not be displayed, as it might cause the plug-in to crash making
the data useless. Instead, a message will be displayed that the image
information was dumped to a file.
rtwain.exe - Renaming "gtwain.exe" to "rtwain.exe" in your plug-ins directory
will change the behavior of the plug-in. The menu option will be registered
as "TWAIN Acquire (Read)..." and will cause the TWAIN acquire operation to
read a previously dumped (using dtwain.exe) TWAIN acquire from
"C:\twaincap.bin".
If you find that you are unable to capture data from you datasource (the plug-in
crashes or the image is wrong), please capture data using the following steps:
1) Copy gtwain.exe to your plug-ins directory as "dtwain.exe".
2) Run PIKA.
3) Choose Xtns->TWAIN Acquire (Dump)...
4) Choose the datasource settings that are causing problems.
5) Choose a *SMALL* sample image.
6) Zip up "C:\twaincap.bin" and "C:\twain.log" and send them to me.

View File

@ -0,0 +1,35 @@
if not platform_windows
subdir_done()
endif
plugin_name = 'twain'
plugin_sources = [
'tw_func.c',
'tw_util.c',
'tw_win.c',
'twain.c',
]
plugin_sources += windows.compile_resources(
pika_plugins_rc,
args: [
'--define', 'ORIGINALFILENAME_STR="@0@"'.format(plugin_name+'.exe'),
'--define', 'INTERNALNAME_STR="@0@"' .format(plugin_name),
'--define', 'TOP_SRCDIR="@0@"' .format(meson.project_source_root()),
],
include_directories: [
rootInclude, appInclude,
],
)
twain = executable(plugin_name,
plugin_sources,
dependencies: [
libpika_dep,
glib,
gtk3,
],
install: true,
install_dir: pikaplugindir / 'plug-ins' / plugin_name,
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

273
plug-ins/twain/tw_dump.c Normal file
View File

@ -0,0 +1,273 @@
/*
* TWAIN Plug-in
* Copyright (C) 1999 Craig Setera
* Craig Setera <setera@home.com>
* 03/31/1999
*
* Updated for Mac OS X support
* Brion Vibber <brion@pobox.com>
* 07/22/2004
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*
*
* Based on (at least) the following plug-ins:
* Screenshot
* GIF
* Randomize
*
* Any suggestions, bug-reports or patches are welcome.
*
* This plug-in interfaces to the TWAIN support library in order
* to capture images from TWAIN devices directly into PIKA 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:
* Should compile and run on both Win32 and Mac OS X 10.3 (possibly
* also on 10.2).
*
* Known problems:
* - Multiple image transfers will hang the plug-in. The current
* configuration compiles with a maximum of single image transfers.
* - On Mac OS X, canceling doesn't always close things out fully.
* - Epson TWAIN driver on Mac OS X crashes the plugin when scanning.
*/
/*
* 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
* (03/31/99) v0.5 Added support for multi-byte samples and paletted
* images.
* (07/23/04) v0.6 Added Mac OS X support.
*/
#include "config.h"
#include <string.h>
#include <glib/gstdio.h>
#include "libpika/pika.h"
#include "tw_dump.h"
#include "tw_func.h"
#include "tw_util.h"
/* File variables */
static FILE *outputFile = NULL;
extern pTW_SESSION twSession;
/*
* dumpPreTransferCallback
*
* This callback function is called before any images
* are transferred. Set up the one time only stuff.
*/
void
dumpPreTransferCallback(void *clientData)
{
/* Open our output file... Not settable... Always
* write to the root directory. Simplistic, but
* gets the job done.
*/
outputFile = g_fopen(DUMP_FILE, "wb");
}
/*
* dumpBeginTransferCallback
*
* The following function is called at the beginning
* of each image transfer.
*/
int
dumpBeginTransferCallback(pTW_IMAGEINFO imageInfo, void *clientData)
{
logBegin(imageInfo, clientData);
/* Dump the image information */
fwrite((void *) imageInfo, sizeof(TW_IMAGEINFO), 1, outputFile);
/* Keep going */
return TRUE;
}
/*
* dumpDataTransferCallback
*
* The following function is called for each memory
* block that is transferred from the data source.
*/
int
dumpDataTransferCallback(pTW_IMAGEINFO imageInfo,
pTW_IMAGEMEMXFER imageMemXfer,
void *clientData)
{
int flag = 1;
logData(imageInfo, imageMemXfer, clientData);
/* Write a flag that says that this is a data packet */
fwrite((void *) &flag, sizeof(int), 1, outputFile);
/* Dump the memory information */
fwrite((void *) imageMemXfer, sizeof(TW_IMAGEMEMXFER), 1, outputFile);
fwrite((void *) imageMemXfer->Memory.TheMem,
1, imageMemXfer->BytesWritten, outputFile);
/* Keep going */
return TRUE;
}
/*
* dumpEndTransferCallback
*
* 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
dumpEndTransferCallback(int completionState, int pendingCount, void *clientData)
{
int flag = 0;
/* Write a flag that says that this is a data packet */
fwrite((void *) &flag, sizeof(int), 1, outputFile);
/* Write the necessary data */
fwrite(&completionState, sizeof(int), 1, outputFile);
fwrite(&pendingCount, sizeof(int), 1, outputFile);
/* Only ever transfer a single image */
return FALSE;
}
/*
* dumpPostTransferCallback
*
* This callback function will be called
* after all possible images have been
* transferred.
*/
void
dumpPostTransferCallback(int pendingCount, void *clientData)
{
char buffer[128];
/* 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);
/* Close the dump file */
fclose(outputFile);
/* Tell the user */
sprintf(buffer, "Image dumped to file %s\n", DUMP_FILE);
pika_message(buffer);
/* Post a message to close up the application */
twainQuitApplication ();
}
/*
* readDumpedImage
*
* Get a previously dumped image.
*/
void readDumpedImage(pTW_SESSION twSession)
{
int moreData;
int completionState;
int pendingCount;
TW_IMAGEINFO imageInfo;
TW_IMAGEMEMXFER imageMemXfer;
/* Open our output file... Not settable... Always
* write to the root directory. Simplistic, but
* gets the job done.
*/
FILE *inputFile = g_fopen(DUMP_FILE, "rb");
/*
* Inform our application that we are getting ready
* to transfer images.
*/
(*twSession->transferFunctions->preTxfrCb)(NULL);
/* Read the image information */
fread((void *) &imageInfo, sizeof(TW_IMAGEINFO), 1, inputFile);
/* Call the begin transfer callback */
if (!(*twSession->transferFunctions->txfrBeginCb)(&imageInfo, twSession->clientData))
return;
/* Read all of the data packets */
fread((void *) &moreData, sizeof(int), 1, inputFile);
while (moreData) {
/* Read the memory information */
fread((void *) &imageMemXfer, sizeof(TW_IMAGEMEMXFER), 1, inputFile);
imageMemXfer.Memory.TheMem = (TW_MEMREF) g_malloc (imageMemXfer.BytesWritten);
fread((void *) imageMemXfer.Memory.TheMem,
1, imageMemXfer.BytesWritten, inputFile);
/* Call the data transfer callback function */
if (!(*twSession->transferFunctions->txfrDataCb)
(&imageInfo,
&imageMemXfer,
twSession->clientData))
return;
/* Clean up the memory */
g_free (imageMemXfer.Memory.TheMem);
/* Check for continuation */
fread((void *) &moreData, sizeof(int), 1, inputFile);
}
/* Grab the final information */
fread(&completionState, sizeof(int), 1, inputFile);
fread(&pendingCount, sizeof(int), 1, inputFile);
if (twSession->transferFunctions->txfrEndCb)
(*twSession->transferFunctions->txfrEndCb)(completionState, 0,
twSession->clientData);
/* Post a message to close up the application */
twainQuitApplication ();
}

70
plug-ins/twain/tw_dump.h Normal file
View File

@ -0,0 +1,70 @@
/*
* TWAIN Plug-in
* Copyright (C) 1999 Craig Setera
* Craig Setera <setera@home.com>
* 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 3 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, see <https://www.gnu.org/licenses/>.
*
*
* Based on (at least) the following plug-ins:
* Screenshot
* GIF
* Randomize
*
* Any suggestions, bug-reports or patches are welcome.
*
* This plug-in interfaces to the TWAIN support library in order
* to capture images from TWAIN devices directly into PIKA 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
* is TWAIN support available on Macintosh, I neither have a
* 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.
*/
/*
* 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
* (03/31/99) v0.5 Added support for multi-byte samples and paletted
* images.
*/
#include "tw_platform.h"
#include "tw_func.h"
void dumpPreTransferCallback(void *clientData);
int dumpBeginTransferCallback(pTW_IMAGEINFO imageInfo, void *clientData);
int dumpDataTransferCallback(pTW_IMAGEINFO imageInfo,
pTW_IMAGEMEMXFER imageMemXfer,
void *clientData);
int dumpEndTransferCallback(int completionState, int pendingCount, void *clientData);
void dumpPostTransferCallback(int pendingCount, void *clientData);
void readDumpedImage(pTW_SESSION twSession);

878
plug-ins/twain/tw_func.c Normal file
View File

@ -0,0 +1,878 @@
/*
* TWAIN Plug-in
* Copyright (C) 1999 Craig Setera
* Craig Setera <setera@home.com>
* 03/31/1999
*
* Updated for Mac OS X support
* Brion Vibber <brion@pobox.com>
* 07/22/2004
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*
*
* Based on (at least) the following plug-ins:
* Screenshot
* GIF
* Randomize
*
* Any suggestions, bug-reports or patches are welcome.
*
* This plug-in interfaces to the TWAIN support library in order
* to capture images from TWAIN devices directly into PIKA 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:
* Should compile and run on both Win32 and Mac OS X 10.3 (possibly
* also on 10.2).
*
* Known problems:
* - Multiple image transfers will hang the plug-in. The current
* configuration compiles with a maximum of single image transfers.
* - On Mac OS X, canceling doesn't always close things out fully.
* - Epson TWAIN driver on Mac OS X crashes the plugin when scanning.
*/
/*
* 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
* (03/31/99) v0.5 Added support for multi-byte samples and paletted
* images.
* (07/23/04) v0.6 Added Mac OS X support.
*/
#include "config.h"
#include <glib.h> /* Needed when compiling with gcc */
#include "tw_func.h"
#include "tw_util.h"
#include "tw_local.h"
/*
* Twain error code to string mappings
*/
static int twainErrorCount = 0;
static char *twainErrors[] = {
"No error",
"Failure due to unknown causes",
"Not enough memory to perform operation",
"No Data Source",
"DS is connected to max possible apps",
"DS or DSM reported error, application shouldn't",
"Unknown capability",
"Unrecognized MSG DG DAT combination",
"Data parameter out of range",
"DG DAT MSG out of expected sequence",
"Unknown destination App/Src in DSM_Entry",
"Capability not supported by source",
"Operation not supported by capability",
"Capability has dependency on other capability",
"File System operation is denied (file is protected)",
"Operation failed because file already exists.",
"File not found",
"Operation failed because directory is not empty",
"The feeder is jammed",
"The feeder detected multiple pages",
"Error writing the file (disk full?)",
"The device went offline prior to or during this operation",
NULL
};
/*
* FloatToFix32
*
* Convert a floating point value into a FIX32.
*/
TW_FIX32 FloatToFIX32(float floater)
{
TW_FIX32 Fix32_value;
TW_INT32 value = (TW_INT32) (floater * 65536.0 + 0.5);
Fix32_value.Whole = value >> 16;
Fix32_value.Frac = value & 0x0000ffffL;
return (Fix32_value);
}
/*
* Fix32ToFloat
*
* Convert a FIX32 value into a floating point value.
*/
float FIX32ToFloat(TW_FIX32 fix32)
{
float floater;
floater = (float) fix32.Whole + (float) fix32.Frac / 65536.0;
return floater;
}
/*
* twainError
*
* Return the TWAIN error message associated
* with the specified error code.
*/
char *
twainError(int errorCode)
{
/* Check whether we've counted */
if (twainErrorCount == 0)
while (twainErrors[twainErrorCount++]) {}
/* Check out of bounds */
if (errorCode >= twainErrorCount)
return "Unknown TWAIN Error Code";
else
return twainErrors[errorCode];
}
/*
* currentTwainError
*
* Return the current TWAIN error message.
*/
char *
currentTwainError(pTW_SESSION twSession)
{
TW_STATUS twStatus;
/* Get the current status code from the DSM */
twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
DG_CONTROL, DAT_STATUS, MSG_GET,
(TW_MEMREF) &twStatus);
/* Return the mapped error code */
return twainError(twStatus.ConditionCode);
}
/*
* getImage
*
* This is a "high-level" function that can be called in order
* to take all of the steps necessary to kick off an image-transfer
* from a user-specified TWAIN datasource. The data will be passed
* back to the callback function specified in the session structure.
*/
int
getImage(pTW_SESSION twSession)
{
/* Do some sanity checking first and bail
* if necessary.
*/
if (!twainIsAvailable()) {
LogMessage("TWAIN is not available for image capture\n");
return FALSE;
}
/* One step at a time */
if (!openDSM(twSession)) {
LogMessage("Unable to open data source manager\n");
return FALSE;
}
if (!selectDS(twSession)) {
LogMessage("Data source not selected\n");
return FALSE;
}
if (!openDS(twSession)) {
LogMessage("Unable to open datasource\n");
return FALSE;
}
requestImageAcquire(twSession, TRUE);
return TRUE;
}
/*
* openDSM
*
* Open the data source manager
*/
int
openDSM(pTW_SESSION twSession)
{
/* Make sure that we aren't already open */
if (DSM_IS_OPEN(twSession))
return TRUE;
/* Open the data source manager */
twSession->twRC = callDSM(APP_IDENTITY(twSession), NULL,
DG_CONTROL, DAT_PARENT, MSG_OPENDSM,
(TW_MEMREF) &(twSession->hwnd));
/* Check the return code */
switch (twSession->twRC) {
case TWRC_SUCCESS:
/* We are now at state 3 */
twSession->twainState = 3;
return TRUE;
break;
case TWRC_FAILURE:
default:
LogMessage("OpenDSM failure\n");
break;
}
return FALSE;
}
/*
* selectDS
*
* Select a datasource using the TWAIN user
* interface.
*/
int
selectDS(pTW_SESSION twSession)
{
/* The datasource manager must be open */
if (DSM_IS_CLOSED(twSession)) {
LogMessage("Can't select data source with closed source manager\n");
return FALSE;
}
/* Ask TWAIN to present the source select dialog */
twSession->twRC = callDSM(APP_IDENTITY(twSession), NULL,
DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT,
(TW_MEMREF) DS_IDENTITY(twSession));
/* Check the return to determine what the user decided
* to do.
*/
switch (twSession->twRC) {
case TWRC_SUCCESS:
LogMessage("Data source %s selected\n", DS_IDENTITY(twSession)->ProductName);
return TRUE;
break;
case TWRC_CANCEL:
LogMessage("User cancelled TWAIN source selection\n");
break;
case TWRC_FAILURE:
default:
LogMessage("Error \"%s\" during TWAIN source selection\n",
currentTwainError(twSession));
break;
}
return FALSE;
}
/*
* selectDefaultDS
*
* Select the default datasource.
*/
int
selectDefaultDS(pTW_SESSION twSession)
{
/* The datasource manager must be open */
if (DSM_IS_CLOSED(twSession)) {
LogMessage("Can't select data source with closed source manager\n");
return FALSE;
}
/* Ask TWAIN to present the source select dialog */
twSession->twRC = callDSM(APP_IDENTITY(twSession), NULL,
DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT,
(TW_MEMREF) DS_IDENTITY(twSession));
/* Check the return code */
return (twSession->twRC == TWRC_SUCCESS);
}
/*
* openDS
*
* Open a data source using the TWAIN user interface.
*/
int
openDS(pTW_SESSION twSession)
{
TW_IDENTITY *dsIdentity;
/* The datasource manager must be open */
if (DSM_IS_CLOSED(twSession)) {
LogMessage("openDS: Cannot open data source... manager closed\n");
return FALSE;
}
/* Is the data source already open? */
if (DS_IS_OPEN(twSession)) {
LogMessage("openDS: Data source already open\n");
return TRUE;
}
/* Open the TWAIN datasource */
dsIdentity = DS_IDENTITY(twSession);
twSession->twRC = callDSM(APP_IDENTITY(twSession), NULL,
DG_CONTROL, DAT_IDENTITY, MSG_OPENDS,
(TW_MEMREF) dsIdentity);
/* Check the return to determine what the user decided
* to do.
*/
switch (twSession->twRC) {
case TWRC_SUCCESS:
/* We are now in TWAIN state 4 */
twSession->twainState = 4;
LogMessage("Data source %s opened\n", DS_IDENTITY(twSession)->ProductName);
LogMessage("\tVersion.MajorNum = %d\n", dsIdentity->Version.MajorNum);
LogMessage("\tVersion.MinorNum = %d\n", dsIdentity->Version.MinorNum);
LogMessage("\tVersion.Info = %s\n", dsIdentity->Version.Info);
LogMessage("\tProtocolMajor = %d\n", dsIdentity->ProtocolMajor);
LogMessage("\tProtocolMinor = %d\n", dsIdentity->ProtocolMinor);
LogMessage("\tManufacturer = %s\n", dsIdentity->Manufacturer);
LogMessage("\tProductFamily = %s\n", dsIdentity->ProductFamily);
return TRUE;
break;
default:
LogMessage("Error \"%s\" opening data source\n", currentTwainError(twSession));
break;
}
return FALSE;
}
/*
* setBufferedXfer
*/
static int
setBufferedXfer(pTW_SESSION twSession)
{
TW_CAPABILITY bufXfer;
pTW_ONEVALUE pvalOneValue;
/* Make sure the data source is open first */
if (DS_IS_CLOSED(twSession))
return FALSE;
/* Create the capability information */
bufXfer.Cap = ICAP_XFERMECH;
bufXfer.ConType = TWON_ONEVALUE;
bufXfer.hContainer = twainAllocHandle(sizeof(TW_ONEVALUE));
pvalOneValue = (pTW_ONEVALUE) twainLockHandle(bufXfer.hContainer);
pvalOneValue->ItemType = TWTY_UINT16;
pvalOneValue->Item = TWSX_MEMORY;
twainUnlockHandle(bufXfer.hContainer);
/* Make the call to the source manager */
twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
DG_CONTROL, DAT_CAPABILITY, MSG_SET,
(TW_MEMREF) &bufXfer);
/* Free the container */
twainFreeHandle(bufXfer.hContainer);
/* Let the caller know what happened */
return (twSession->twRC==TWRC_SUCCESS);
}
/*
* requestImageAcquire
*
* Request that the acquire user interface
* be displayed. This may or may not cause
* an image to actually be transferred.
*/
int
requestImageAcquire(pTW_SESSION twSession, gboolean showUI)
{
/* Make sure in the correct state */
if (DS_IS_CLOSED(twSession)) {
LogMessage("Can't acquire image with closed datasource\n");
return FALSE;
}
twainSetupCallback(twSession);
/* Set the transfer mode */
if (setBufferedXfer(twSession)) {
TW_USERINTERFACE ui;
/* Set the UI information */
ui.ShowUI = TRUE;
ui.ModalUI = TRUE;
/* In Windows, the callbacks are sent to the window message handler */
ui.hParent = twSession->hwnd;
/* Make the call to the source manager */
twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
DG_CONTROL, DAT_USERINTERFACE, MSG_ENABLEDS,
(TW_MEMREF) &ui);
if (twSession->twRC == TWRC_SUCCESS) {
/* We are now at a new twain state */
twSession->twainState = 5;
return TRUE;
} else {
LogMessage("Error during data source enable\n");
return FALSE;
}
} else {
LogMessage("Unable to set buffered transfer mode: %s\n",
currentTwainError(twSession));
return FALSE;
}
}
/*
* disableDS
*
* Disable the datasource associated with twSession.
*/
int
disableDS(pTW_SESSION twSession)
{
TW_USERINTERFACE ui;
/* Verify the datasource is enabled */
if (DS_IS_DISABLED(twSession)) {
LogMessage("disableDS: Data source not enabled\n");
return TRUE;
}
/* Set the UI information */
ui.ShowUI = TRUE;
ui.ModalUI = TRUE;
ui.hParent = twSession->hwnd;
/* Make the call to the source manager */
twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
DG_CONTROL, DAT_USERINTERFACE, MSG_DISABLEDS,
(TW_MEMREF) &ui);
if (twSession->twRC == TWRC_SUCCESS) {
/* We are now at a new twain state */
twSession->twainState = 4;
return TRUE;
} else {
LogMessage("Error during data source disable\n");
return FALSE;
}
}
/*
* closeDS
*
* Close the datasource associated with the
* specified session.
*/
int
closeDS(pTW_SESSION twSession)
{
/* Can't close a closed data source */
if (DS_IS_CLOSED(twSession)) {
LogMessage("closeDS: Data source already closed\n");
return TRUE;
}
/* Open the TWAIN datasource */
twSession->twRC = callDSM(APP_IDENTITY(twSession), NULL,
DG_CONTROL, DAT_IDENTITY, MSG_CLOSEDS,
(TW_MEMREF) DS_IDENTITY(twSession));
/* Check the return to determine what the user decided
* to do.
*/
switch (twSession->twRC) {
case TWRC_SUCCESS:
/* We are now in TWAIN state 3 */
twSession->twainState = 3;
LogMessage("Data source %s closed\n", DS_IDENTITY(twSession)->ProductName);
return TRUE;
break;
default:
LogMessage("Error \"%s\" closing data source\n", currentTwainError(twSession));
break;
}
return FALSE;
}
/*
* closeDSM
*
* Close the data source manager
*/
int
closeDSM(pTW_SESSION twSession)
{
if (DSM_IS_CLOSED(twSession)) {
LogMessage("closeDSM: Source Manager not open\n");
return FALSE;
} else {
if (DS_IS_OPEN(twSession)) {
LogMessage("closeDSM: Can't close source manager with open source\n");
return FALSE;
} else {
twSession->twRC = callDSM(APP_IDENTITY(twSession), NULL,
DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM,
(TW_MEMREF)&(twSession->hwnd));
if (twSession->twRC != TWRC_SUCCESS) {
LogMessage("CloseDSM failure -- %s\n", currentTwainError(twSession));
}
else {
/* We are now in state 2 */
twSession->twainState = 2;
}
}
}
/* Let the caller know what happened */
return (twSession->twRC==TWRC_SUCCESS);
}
/*
* beginImageTransfer
*
* Begin an image transfer.
*/
static int
beginImageTransfer(pTW_SESSION twSession, pTW_IMAGEINFO imageInfo)
{
/* Clear our structures */
memset(imageInfo, 0, sizeof(TW_IMAGEINFO));
/* Query the image information */
twSession->twRC = callDSM(
APP_IDENTITY(twSession), DS_IDENTITY(twSession),
DG_IMAGE, DAT_IMAGEINFO, MSG_GET,
(TW_MEMREF) imageInfo);
/* Check the return code */
if (twSession->twRC != TWRC_SUCCESS) {
LogMessage("Get Image Info failure - %s\n", currentTwainError(twSession));
return FALSE;
}
/* Call the begin transfer callback if registered */
if (twSession->transferFunctions->txfrBeginCb)
if (!(*twSession->transferFunctions->txfrBeginCb)(imageInfo, twSession->clientData))
return FALSE;
/* We should continue */
return TRUE;
}
/*
* transferImage
*
* The Source indicated it is ready to transfer data. It is
* waiting for the application to inquire about the image details,
* initiate the actual transfer, and, hence, transition the session
* from State 6 to 7. Return the reason for exiting the transfer.
*/
static void
transferImage(pTW_SESSION twSession, pTW_IMAGEINFO imageInfo)
{
TW_SETUPMEMXFER setupMemXfer;
TW_IMAGEMEMXFER imageMemXfer;
char *buffer;
/* Clear our structures */
memset(&setupMemXfer, 0, sizeof(TW_SETUPMEMXFER));
memset(&imageMemXfer, 0, sizeof(TW_IMAGEMEMXFER));
/* Find out how the source would like to transfer... */
twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
DG_CONTROL, DAT_SETUPMEMXFER, MSG_GET,
(TW_MEMREF) &setupMemXfer);
/* Allocate the buffer for the transfer */
buffer = g_new (char, setupMemXfer.Preferred);
imageMemXfer.Memory.Flags = TWMF_APPOWNS | TWMF_POINTER;
imageMemXfer.Memory.Length = setupMemXfer.Preferred;
imageMemXfer.Memory.TheMem = (TW_MEMREF) buffer;
/* Get the data */
do {
/* Setup for the memory transfer */
imageMemXfer.Compression = TWON_DONTCARE16;
imageMemXfer.BytesPerRow = TWON_DONTCARE32;
imageMemXfer.Columns = TWON_DONTCARE32;
imageMemXfer.Rows = TWON_DONTCARE32;
imageMemXfer.XOffset = TWON_DONTCARE32;
imageMemXfer.YOffset = TWON_DONTCARE32;
imageMemXfer.BytesWritten = TWON_DONTCARE32;
/* Get the next block of memory */
twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
DG_IMAGE, DAT_IMAGEMEMXFER, MSG_GET,
(TW_MEMREF) &imageMemXfer);
if ((twSession->twRC == TWRC_SUCCESS) ||
(twSession->twRC == TWRC_XFERDONE)) {
/* Call the callback function */
if (!(*twSession->transferFunctions->txfrDataCb) (
imageInfo,
&imageMemXfer,
twSession->clientData)) {
/* Callback function requested to cancel */
twSession->twRC = TWRC_CANCEL;
break;
}
}
} while (twSession->twRC == TWRC_SUCCESS);
/* Free the memory buffer */
g_free (imageMemXfer.Memory.TheMem);
}
/*
* endPendingTransfer
*
* Cancel the currently pending transfer.
* Return the count of pending transfers.
*/
static int
endPendingTransfer(pTW_SESSION twSession)
{
TW_PENDINGXFERS pendingXfers;
twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
DG_CONTROL, DAT_PENDINGXFERS, MSG_ENDXFER,
(TW_MEMREF) &pendingXfers);
if (!pendingXfers.Count)
twSession->twainState = 5;
return pendingXfers.Count;
}
/*
* cancelPendingTransfers
*
* Cancel all pending image transfers.
*/
void
cancelPendingTransfers(pTW_SESSION twSession)
{
TW_PENDINGXFERS pendingXfers;
twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
DG_CONTROL, DAT_PENDINGXFERS, MSG_RESET,
(TW_MEMREF) &pendingXfers);
}
/*
* endImageTransfer
*
* Finish transferring an image. Return the count
* of pending images.
*/
static int
endImageTransfer(pTW_SESSION twSession, int *pendingCount)
{
gboolean continueTransfers = FALSE;
int exitCode = twSession->twRC;
/* Have now exited the transfer for some reason... Figure out
* why and what to do about it
*/
switch (twSession->twRC) {
case TWRC_XFERDONE:
case TWRC_CANCEL:
LogMessage("Xfer done received\n");
*pendingCount = endPendingTransfer(twSession);
break;
case TWRC_FAILURE:
LogMessage("Failure received\n");
*pendingCount = endPendingTransfer(twSession);
break;
default:
*pendingCount = 0;
break;
}
/* Call the end transfer callback */
if (twSession->transferFunctions->txfrEndCb)
continueTransfers =
(*twSession->transferFunctions->txfrEndCb)(exitCode,
*pendingCount,
twSession->clientData);
return (*pendingCount && continueTransfers);
}
/*
* transferImages
*
* Transfer all of the images that are available from the
* datasource.
*/
static void
transferImages(pTW_SESSION twSession)
{
TW_IMAGEINFO imageInfo;
int pendingCount;
/* Check the image transfer callback function
* before even attempting to do the transfer
*/
if (!twSession->transferFunctions || !twSession->transferFunctions->txfrDataCb) {
LogMessage("Attempting image transfer without callback function\n");
return;
}
/*
* Inform our application that we are getting ready
* to transfer images.
*/
if (twSession->transferFunctions->preTxfrCb)
(*twSession->transferFunctions->preTxfrCb)(twSession->clientData);
/* Loop through the available images */
do {
/* Move to the new state */
twSession->twainState = 6;
/* Begin the image transfer */
if (!beginImageTransfer(twSession, &imageInfo))
continue;
/* Call the image transfer function */
transferImage(twSession, &imageInfo);
} while (endImageTransfer(twSession, &pendingCount));
/*
* Inform our application that we are done
* transferring images.
*/
if (twSession->transferFunctions->postTxfrCb)
(*twSession->transferFunctions->postTxfrCb)(pendingCount,
twSession->clientData);
}
void
processTwainMessage(TW_UINT16 message, pTW_SESSION twSession)
{
switch (message) {
case MSG_XFERREADY:
LogMessage("Source says that data is ready\n");
transferImages(twSession);
break;
case MSG_CLOSEDSREQ:
/* Disable the datasource, Close the Data source
* and close the data source manager
*/
LogMessage("CloseDSReq\n");
disableDS(twSession);
closeDS(twSession);
closeDSM(twSession);
break;
/* No message from the Source to the App break;
* possible new message
*/
case MSG_NULL:
default:
break;
}
}
/**********************************************************************
* Session related functions
**********************************************************************/
/*
* newSession
*
* Create a new TWAIN session.
*/
pTW_SESSION
newSession(pTW_IDENTITY appIdentity) {
/* Create the structure */
pTW_SESSION session = g_new (TW_SESSION, 1);
/* Set the structure fields */
session->hwnd = 0;
session->twRC = TWRC_SUCCESS;
session->appIdentity = appIdentity;
session->dsIdentity = g_new (TW_IDENTITY, 1);
session->dsIdentity->Id = 0;
session->dsIdentity->ProductName[0] = '\0';
session->transferFunctions = NULL;
if (twainIsAvailable())
session->twainState = 2;
else
session->twainState = 0;
return session;
}
/*
* registerWindowHandle
*
* Register the window handle to be used for this
* session.
*/
void
registerWindowHandle(pTW_SESSION session, TW_HANDLE hwnd)
{
session->hwnd = hwnd;
}
/*
* registerTransferCallback
*
* Register the callback to use when transferring
* image data.
*/
void
registerTransferCallbacks(pTW_SESSION session,
pTXFR_CB_FUNCS txfrFuncs,
void *clientData)
{
session->transferFunctions = txfrFuncs;
session->clientData = clientData;
}
/*
* setClientData
*
* Set the client data associated with the specified
* TWAIN session.
*/
void
setClientData(pTW_SESSION session, void *clientData)
{
session->clientData = clientData;
}

243
plug-ins/twain/tw_func.h Normal file
View File

@ -0,0 +1,243 @@
/*
* TWAIN Plug-in
* Copyright (C) 1999 Craig Setera
* Craig Setera <setera@home.com>
* 03/31/1999
*
* Updated for Mac OS X support
* Brion Vibber <brion@pobox.com>
* 07/22/2004
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*
*
* Based on (at least) the following plug-ins:
* Screenshot
* GIF
* Randomize
*
* Any suggestions, bug-reports or patches are welcome.
*
* This plug-in interfaces to the TWAIN support library in order
* to capture images from TWAIN devices directly into PIKA 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:
* Should compile and run on both Win32 and Mac OS X 10.3 (possibly
* also on 10.2).
*
* Known problems:
* - Multiple image transfers will hang the plug-in. The current
* configuration compiles with a maximum of single image transfers.
* - On Mac OS X, canceling doesn't always close things out fully.
* - Epson TWAIN driver on Mac OS X crashes the plugin when scanning.
*/
/*
* 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
* (03/31/99) v0.5 Added support for multi-byte samples and paletted
* images.
* (07/23/04) v0.6 Added Mac OS X support.
*/
#ifndef _TW_FUNC_H
#define _TW_FUNC_H
#include "tw_platform.h"
/*
* Pre-image transfer function type
*
* Sent to the caller before any of the
* images are transferred to the application.
*/
typedef void (* TW_PRE_TXFR_CB)(void *);
/*
* Image transfer begin function type
*
* Sent to the caller when an image transfer
* is about to begin. The caller may return
* FALSE if the transfer should not continue.
* Otherwise, the function should return a
* TRUE value.
*/
typedef int (* TW_TXFR_BEGIN_CB)(pTW_IMAGEINFO, void *);
/*
* Image transfer callback function type
*
* Expected to return true if the image transfer
* should continue. False if the transfer should
* be cancelled.
*/
typedef int (* TW_TXFR_DATA_CB)(pTW_IMAGEINFO, pTW_IMAGEMEMXFER, void *);
/*
* Image transfer end function type
*
* Sent to the caller when an image transfer
* is completed. 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.
*/
typedef int (* TW_TXFR_END_CB)(int, int, void *);
/*
* Post-image transfer callback
*
* This callback function is called after all
* of the possible images have been transferred
* from the datasource.
*/
typedef void (* TW_POST_TXFR_CB)(int, void *);
/*
* The following structure defines the
* three callback functions that are called
* while an image is being transferred.
* The types of these functions are defined
* above. Any function that is NULL will just
* not be called.
*/
typedef struct _TXFR_CB_FUNCS {
/* Pre-transfer function */
TW_PRE_TXFR_CB preTxfrCb;
/* Begin function */
TW_TXFR_BEGIN_CB txfrBeginCb;
/* Data transfer */
TW_TXFR_DATA_CB txfrDataCb;
/* End function */
TW_TXFR_END_CB txfrEndCb;
/* Post-transfer function */
TW_POST_TXFR_CB postTxfrCb;
} TXFR_CB_FUNCS, *pTXFR_CB_FUNCS;
/*
* Data representing a TWAIN
* application to data source
* session.
*/
typedef struct _TWAIN_SESSION {
/* The window handle related to the TWAIN application on Win32 */
TW_HANDLE hwnd;
/* The current TWAIN return code */
TW_UINT16 twRC;
/* The application's TWAIN identity */
pTW_IDENTITY appIdentity;
/* The datasource's TWAIN identity */
pTW_IDENTITY dsIdentity;
/* The image data transfer functions */
pTXFR_CB_FUNCS transferFunctions;
/* Client data that is associated with the image
* transfer callback
*/
void *clientData;
/*
* The following variable tracks the current state
* as related to the TWAIN engine. The states are:
*
* 1) Pre-session: The DSM has not been loaded
* 2) Source Manager Loaded (not opened)
* 3) Source Manager Opened
* 4) Source Open
* 5) Source Enabled
* 6) Transfer ready
* 7) Transferring
*/
int twainState;
} TW_SESSION, *pTW_SESSION;
/* Session structure access
* macros
*/
/* #define pAPP_IDENTITY(tw_session) (&(tw_session->appIdentity)) */
#define APP_IDENTITY(tw_session) (tw_session->appIdentity)
/* #define pDS_IDENTITY(tw_session) (&(tw_session->dsIdentity)) */
#define DS_IDENTITY(tw_session) (tw_session->dsIdentity)
/* State macros... Each expects
* a Twain Session pointer
*/
#define TWAIN_LOADED(tw_session) (tw_session->twainState >= 2)
#define TWAIN_UNLOADED(tw_session) (tw_session->twainState < 2)
#define DSM_IS_OPEN(tw_session) (tw_session->twainState >= 3)
#define DSM_IS_CLOSED(tw_session) (tw_session->twainState < 3)
#define DS_IS_OPEN(tw_session) (tw_session->twainState >= 4)
#define DS_IS_CLOSED(tw_session) (tw_session->twainState < 4)
#define DS_IS_ENABLED(tw_session) (tw_session->twainState >= 5)
#define DS_IS_DISABLED(tw_session) (tw_session->twainState < 5)
/* Function declarations */
char *twainError(int);
char *currentTwainError(pTW_SESSION);
int getImage(pTW_SESSION);
int loadTwainLibrary(pTW_SESSION);
int unloadTwainLibrary(pTW_SESSION twSession);
int openDSM(pTW_SESSION);
int selectDS(pTW_SESSION);
int selectDefaultDS(pTW_SESSION);
int openDS(pTW_SESSION);
int requestImageAcquire(pTW_SESSION, gboolean);
int disableDS(pTW_SESSION);
int closeDS(pTW_SESSION);
int closeDSM(pTW_SESSION);
void cancelPendingTransfers(pTW_SESSION);
int scanImage (void);
TW_FIX32 FloatToFIX32(float);
float FIX32ToFloat(TW_FIX32);
void processTwainMessage(TW_UINT16 message, pTW_SESSION twSession);
pTW_SESSION newSession(pTW_IDENTITY);
void registerWindowHandle(pTW_SESSION, TW_HANDLE);
void registerTransferCallbacks(pTW_SESSION, pTXFR_CB_FUNCS, void *);
void setClientData(pTW_SESSION session, void *clientData);
pTW_SESSION initializeTwain(void);
#ifdef G_OS_WIN32
void LogLastWinError(void);
BOOL InitApplication(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow, pTW_SESSION twSession);
#endif
#endif /* _TW_FUNC_H */

48
plug-ins/twain/tw_local.h Normal file
View File

@ -0,0 +1,48 @@
/*
* TWAIN Plug-in
* Copyright (C) 1999 Craig Setera
* Craig Setera <setera@home.com>
* 03/31/1999
*
* Updated for Mac OS X support
* Brion Vibber <brion@pobox.com>
* 07/22/2004
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*/
#ifndef _TW_LOCAL_H
#define _TW_LOCAL_H
#include "tw_func.h"
/* Functions which the platform-independent code will call */
TW_UINT16 callDSM(pTW_IDENTITY, pTW_IDENTITY,
TW_UINT32, TW_UINT16,
TW_UINT16, TW_MEMREF);
int twainIsAvailable(void);
void twainQuitApplication (void);
gboolean twainSetupCallback (pTW_SESSION twSession);
TW_HANDLE twainAllocHandle(size_t size);
TW_MEMREF twainLockHandle (TW_HANDLE handle);
void twainUnlockHandle (TW_HANDLE handle);
void twainFreeHandle (TW_HANDLE handle);
int twainMain (void);
int scanImage (void);
#endif

View File

@ -0,0 +1,35 @@
/*
* TWAIN Plug-in
* Copyright (C) 1999 Craig Setera
* Craig Setera <setera@home.com>
* 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 3 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, see <https://www.gnu.org/licenses/>.
*/
#ifndef _TW_PLATFORM_H
#define _TW_PLATFORM_H
#include <windows.h>
#include "twain.h"
/* The DLL to be loaded for TWAIN support */
#define TWAIN_DLL_NAME_W L"TWAIN_32.DLL"
#define TWAIN_DLL_NAME "TWAIN_32.DLL"
#define DEBUG_LOGFILE "c:\\twain.log"
#define DUMP_FILE "C:\\TWAINCAP.BIN"
#define DUMP_NAME "DTWAIN.EXE"
#define READDUMP_NAME "RTWAIN.EXE"
#endif

170
plug-ins/twain/tw_util.c Normal file
View File

@ -0,0 +1,170 @@
/*
* TWAIN Plug-in
* Copyright (C) 1999 Craig Setera
* Craig Setera <setera@home.com>
* 03/31/1999
*
* Updated for Mac OS X support
* Brion Vibber <brion@pobox.com>
* 07/22/2004
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*
*
* Based on (at least) the following plug-ins:
* Screenshot
* GIF
* Randomize
*
* Any suggestions, bug-reports or patches are welcome.
*
* This plug-in interfaces to the TWAIN support library in order
* to capture images from TWAIN devices directly into PIKA 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:
* Should compile and run on both Win32 and Mac OS X 10.3 (possibly
* also on 10.2).
*
* Known problems:
* - Multiple image transfers will hang the plug-in. The current
* configuration compiles with a maximum of single image transfers.
* - On Mac OS X, canceling doesn't always close things out fully.
* - Epson TWAIN driver on Mac OS X crashes the plugin when scanning.
*/
/*
* 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
* (03/31/99) v0.5 Added support for multi-byte samples and paletted
* images.
* (07/23/04) v0.6 Added Mac OS X support.
*/
#include "config.h"
#include <glib.h> /* Needed when compiling with gcc */
#include <glib/gstdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "tw_util.h"
#ifdef _DEBUG
#include "tw_func.h"
FILE *logFile = NULL;
#endif
#ifdef _DEBUG
/*
* LogMessage
*/
void
LogMessage(char *format, ...)
{
va_list args;
time_t time_of_day;
char *ctime_string;
/* Open the log file as necessary */
if (!logFile)
logFile = g_fopen(DEBUG_LOGFILE, "w");
time_of_day = time(NULL);
ctime_string = ctime(&time_of_day);
ctime_string[19] = '\0';
fprintf(logFile, "[%s] ", (ctime_string + 11));
va_start(args, format);
vfprintf(logFile, format, args);
fflush(logFile);
va_end(args);
}
void
logBegin(pTW_IMAGEINFO imageInfo, void *clientData)
{
int i;
char buffer[256];
LogMessage("\n");
LogMessage("*************************************\n");
LogMessage("\n");
LogMessage("Image transfer begin:\n");
/* LogMessage("\tClient data: %s\n", (char *) clientData); */
/* Log the image information */
LogMessage("Image information:\n");
LogMessage("\tXResolution: %f\n", FIX32ToFloat(imageInfo->XResolution));
LogMessage("\tYResolution: %f\n", FIX32ToFloat(imageInfo->YResolution));
LogMessage("\tImageWidth: %d\n", imageInfo->ImageWidth);
LogMessage("\tImageLength: %d\n", imageInfo->ImageLength);
LogMessage("\tSamplesPerPixel: %d\n", imageInfo->SamplesPerPixel);
sprintf(buffer, "\tBitsPerSample: {");
for (i = 0; i < 8; i++) {
if (imageInfo->BitsPerSample[i])
strcat(buffer, "1");
else
strcat(buffer, "0");
if (i != 7)
strcat(buffer, ",");
}
LogMessage("%s}\n", buffer);
LogMessage("\tBitsPerPixel: %d\n", imageInfo->BitsPerPixel);
LogMessage("\tPlanar: %s\n", (imageInfo->Planar ? "TRUE" : "FALSE"));
LogMessage("\tPixelType: %d\n", imageInfo->PixelType);
/* Compression */
}
void
logData(pTW_IMAGEINFO imageInfo,
pTW_IMAGEMEMXFER imageMemXfer,
void *clientData)
{
LogMessage("Image transfer callback called:\n");
LogMessage("\tClient data: %s\n", (char *) clientData);
LogMessage("Memory block transferred:\n");
LogMessage("\tBytesPerRow = %d\n", imageMemXfer->BytesPerRow);
LogMessage("\tColumns = %d\n", imageMemXfer->Columns);
LogMessage("\tRows = %d\n", imageMemXfer->Rows);
LogMessage("\tXOffset = %d\n", imageMemXfer->XOffset);
LogMessage("\tYOffset = %d\n", imageMemXfer->YOffset);
LogMessage("\tBytesWritten = %d\n", imageMemXfer->BytesWritten);
}
#else
/*
* LogMessage
*/
void
LogMessage(char *format, ...)
{
}
#endif /* DEBUG */

73
plug-ins/twain/tw_util.h Normal file
View File

@ -0,0 +1,73 @@
/*
* TWAIN Plug-in
* Copyright (C) 1999 Craig Setera
* Craig Setera <setera@home.com>
* 03/31/1999
*
* Updated for Mac OS X support
* Brion Vibber <brion@pobox.com>
* 07/22/2004
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*
*
* Based on (at least) the following plug-ins:
* Screenshot
* GIF
* Randomize
*
* Any suggestions, bug-reports or patches are welcome.
*
* This plug-in interfaces to the TWAIN support library in order
* to capture images from TWAIN devices directly into PIKA 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:
* Should compile and run on both Win32 and Mac OS X 10.3 (possibly
* also on 10.2).
*
* Known problems:
* - Multiple image transfers will hang the plug-in. The current
* configuration compiles with a maximum of single image transfers.
* - On Mac OS X, canceling doesn't always close things out fully.
* - Epson TWAIN driver on Mac OS X crashes the plugin when scanning.
*/
/*
* 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
* (03/31/99) v0.5 Added support for multi-byte samples and paletted
* images.
* (07/23/04) v0.6 Added Mac OS X support.
*/
#ifndef __TW_UTIL_H
#define __TW_UTIL_H
#include "tw_platform.h"
void LogMessage(char *, ...);
#ifdef _DEBUG
void logBegin(pTW_IMAGEINFO, void *);
void logData(pTW_IMAGEINFO, pTW_IMAGEMEMXFER, void *);
#endif
#endif /* __TW_UTIL_H */

394
plug-ins/twain/tw_win.c Normal file
View File

@ -0,0 +1,394 @@
/*
* TWAIN Plug-in
* Copyright (C) 1999 Craig Setera
* Craig Setera <setera@home.com>
* 03/31/1999
*
* Updated for Mac OS X support
* Brion Vibber <brion@pobox.com>
* 07/22/2004
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*/
/*
* Windows platform-specific code
*/
#include "config.h"
#include <libpika/pika.h>
#include "tw_platform.h"
#include "tw_func.h"
#include "tw_util.h"
#include "tw_local.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int twainMessageLoop(pTW_SESSION);
int TwainProcessMessage(LPMSG lpMsg, pTW_SESSION twSession);
extern pTW_SESSION initializeTwain ();
#ifdef _DEBUG
extern void setRunMode(char *argv[]);
#endif
#define APP_NAME "TWAIN"
#define SHOW_WINDOW 0
#define WM_TRANSFER_IMAGE (WM_USER + 100)
/* main bits */
static HWND hwnd = NULL;
static HINSTANCE hInst = NULL;
/* Storage for the DLL handle */
static HINSTANCE hDLL = NULL;
/* Storage for the entry point into the DSM */
static DSMENTRYPROC dsmEntryPoint = NULL;
/*
* callDSM
*
* Call the specified function on the data source manager.
*/
TW_UINT16
callDSM(pTW_IDENTITY pOrigin,
pTW_IDENTITY pDest,
TW_UINT32 DG,
TW_UINT16 DAT,
TW_UINT16 MSG,
TW_MEMREF pData)
{
/* Call the function */
return (*dsmEntryPoint) (pOrigin, pDest, DG, DAT, MSG, pData);
}
/*
* twainIsAvailable
*
* Return boolean indicating whether TWAIN is available
*/
int
twainIsAvailable(void)
{
/* Already loaded? */
if (dsmEntryPoint) {
return TRUE;
}
/* Attempt to load the library */
hDLL = LoadLibraryW (TWAIN_DLL_NAME_W);
if (hDLL == NULL)
return FALSE;
/* Look up the entry point for use */
dsmEntryPoint = (DSMENTRYPROC) GetProcAddress(hDLL, "DSM_Entry");
if (dsmEntryPoint == NULL)
return FALSE;
return TRUE;
}
TW_HANDLE
twainAllocHandle (size_t size)
{
return GlobalAlloc(GHND, size);
}
TW_MEMREF
twainLockHandle (TW_HANDLE handle)
{
return GlobalLock (handle);
}
void
twainUnlockHandle (TW_HANDLE handle)
{
GlobalUnlock (handle);
}
void
twainFreeHandle (TW_HANDLE handle)
{
GlobalFree (handle);
}
gboolean
twainSetupCallback (pTW_SESSION twSession)
{
/* Callbacks go through the window messaging system */
return TRUE;
}
/*
* unloadTwainLibrary
*
* Unload the TWAIN dynamic link library
*/
int
unloadTwainLibrary(pTW_SESSION twSession)
{
/* Explicitly free the SM library */
if (hDLL) {
FreeLibrary(hDLL);
hDLL=NULL;
}
/* the data source id will no longer be valid after
* twain is killed. If the id is left around the
* data source can not be found or opened
*/
DS_IDENTITY(twSession)->Id = 0;
/* We are now back at state 1 */
twSession->twainState = 1;
LogMessage("Source Manager successfully closed\n");
return TRUE;
}
/*
* TwainProcessMessage
*
* Returns TRUE if the application should process message as usual.
* Returns FALSE if the application should skip processing of this message
*/
int
TwainProcessMessage(LPMSG lpMsg, pTW_SESSION twSession)
{
TW_EVENT twEvent;
twSession->twRC = TWRC_NOTDSEVENT;
/* Only ask Source Manager to process event if there is a Source connected. */
if (DSM_IS_OPEN(twSession) && DS_IS_OPEN(twSession)) {
/*
* A Source provides a modeless dialog box as its user interface.
* The following call relays Windows messages down to the Source's
* UI that were intended for its dialog box. It also retrieves TWAIN
* messages sent from the Source to our Application.
*/
twEvent.pEvent = (TW_MEMREF) lpMsg;
twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
DG_CONTROL, DAT_EVENT, MSG_PROCESSEVENT,
(TW_MEMREF) &twEvent);
/* Check the return code */
if (twSession->twRC == TWRC_NOTDSEVENT) {
return FALSE;
}
/* Process the message as necessary */
processTwainMessage(twEvent.TWMessage, twSession);
}
/* tell the caller what happened */
return (twSession->twRC == TWRC_DSEVENT);
}
/*
* twainMessageLoop
*
* Process Win32 window messages and provide special handling
* of TWAIN specific messages. This loop will not exit until
* the application exits.
*/
int
twainMessageLoop(pTW_SESSION twSession)
{
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
if (DS_IS_CLOSED(twSession) || !TwainProcessMessage(&msg, twSession)) {
TranslateMessage((LPMSG)&msg);
DispatchMessage(&msg);
}
}
return msg.wParam;
}
/*
* LogLastWinError
*
* Log the last Windows error as returned by
* GetLastError.
*/
void
LogLastWinError(void)
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
(LPTSTR) &lpMsgBuf,
0,
NULL
);
LogMessage("%s\n", lpMsgBuf);
/* Free the buffer. */
LocalFree( lpMsgBuf );
}
void twainQuitApplication (void)
{
PostQuitMessage (0);
}
/******************************************************************
* Win32 setup...
******************************************************************/
/*
* InitApplication
*
* Initialize window data and register the window class
*/
BOOL
InitApplication(HINSTANCE hInstance)
{
WNDCLASS wc;
BOOL retValue;
/*
* 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;
/* Register the window class and stash success/failure code. */
retValue = RegisterClass(&wc);
/* Log error */
if (!retValue)
LogLastWinError();
return retValue;
}
/*
* InitInstance
*
* Create the main window for the application. Used to
* interface with the TWAIN datasource.
*/
BOOL
InitInstance(HINSTANCE hInstance, int nCmdShow, pTW_SESSION twSession)
{
/* Create our window */
hwnd = CreateWindow(APP_NAME, APP_NAME, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
NULL, NULL, hInstance, NULL);
if (!hwnd) {
return (FALSE);
}
/* Register our window handle with the TWAIN
* support.
*/
registerWindowHandle(twSession, hwnd);
/* Schedule the image transfer by posting a message */
PostMessage(hwnd, WM_TRANSFER_IMAGE, 0, 0);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
return TRUE;
}
/*
* 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
twainMain (void)
{
/* Initialize the twain information */
pTW_SESSION twSession = initializeTwain();
/* Since we are not using our own WinMain anymore where we
could get hInst we get it here using GetModuleHandleW. */
if (!hInst)
hInst = GetModuleHandleW(NULL);
/* Perform instance initialization */
if (!InitApplication(hInst))
return (FALSE);
/* Perform application initialization */
if (!InitInstance(hInst, SHOW_WINDOW, twSession))
return (FALSE);
/*
* Call the main message processing loop...
* This call will not return until the application
* exits.
*/
return twainMessageLoop(twSession);
}
/*
* WndProc
*
* Process window message for the main window.
*/
LRESULT CALLBACK
WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_TRANSFER_IMAGE:
/* Get an image */
scanImage ();
break;
case WM_DESTROY:
LogMessage("Exiting application\n");
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return 0;
}

977
plug-ins/twain/twain.c Normal file
View File

@ -0,0 +1,977 @@
/*
* TWAIN Plug-in
* Copyright (C) 1999 Craig Setera
* Craig Setera <setera@home.com>
* 03/31/1999
*
* Updated for Mac OS X support
* Brion Vibber <brion@pobox.com>
* 07/22/2004
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*
*
* Based on (at least) the following plug-ins:
* Screenshot
* GIF
* Randomize
*
* Any suggestions, bug-reports or patches are welcome.
*
* This plug-in interfaces to the TWAIN support library in order
* to capture images from TWAIN devices directly into PIKA 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:
* Should compile and run on both Win32 and Mac OS X 10.3 (possibly
* also on 10.2).
*
* Known problems:
* - Multiple image transfers will hang the plug-in. The current
* configuration compiles with a maximum of single image transfers.
* - On Mac OS X, canceling doesn't always close things out fully.
* - Epson TWAIN driver on Mac OS X crashes the plugin when scanning.
*/
/*
* 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
* (03/31/99) v0.5 Added support for multi-byte samples and paletted
* images.
* (07/23/04) v0.6 Added Mac OS X support.
*/
#include "config.h"
#include <glib.h> /* Needed when compiling with gcc */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tw_platform.h"
#include "tw_local.h"
#include "libpika/pika.h"
#include "libpika/stdplugins-intl.h"
#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"
#define PLUG_IN_DESCRIPTION _("Capture an image from a TWAIN datasource")
#define PLUG_IN_HELP N_("This plug-in will capture an image from a TWAIN datasource")
#define PLUG_IN_AUTHOR "Craig Setera (setera@home.com)"
#define PLUG_IN_COPYRIGHT "Copyright 2004 by Craig Setera"
#define PLUG_IN_VERSION "v0.6 (07/22/2004)"
#ifdef _DEBUG
#define PLUG_IN_D_NAME "twain-acquire-dump"
#define PLUG_IN_R_NAME "twain-acquire-read"
#endif /* _DEBUG */
/*
* Application definitions
*/
#define MAX_IMAGES 1
/*
* Definition of the run states
*/
#define RUN_STANDARD 0
#define RUN_DUMP 1
#define RUN_READDUMP 2
/* Global variables */
pTW_SESSION twSession = NULL;
#ifdef _DEBUG
static int twain_run_mode = RUN_STANDARD;
#endif
/* Forward declarations */
void preTransferCallback (void *clientData);
int beginTransferCallback (pTW_IMAGEINFO imageInfo,
void *clientData);
int dataTransferCallback (pTW_IMAGEINFO imageInfo,
pTW_IMAGEMEMXFER imageMemXfer,
void *clientData);
int endTransferCallback (int completionState,
int pendingCount,
void *clientData);
void postTransferCallback (int pendingCount,
void *clientData);
typedef struct _Twain Twain;
typedef struct _TwainClass TwainClass;
struct _Twain
{
PikaPlugIn parent_instance;
};
struct _TwainClass
{
PikaPlugInClass parent_class;
};
#define TWAIN_TYPE (twain_get_type ())
#define TWAIN (obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TWAIN_TYPE, Twain))
GType twain_get_type (void) G_GNUC_CONST;
static GList * twain_query_procedures (PikaPlugIn *plug_in);
static PikaProcedure * twain_create_procedure (PikaPlugIn *plug_in,
const gchar *name);
static PikaValueArray * twain_run (PikaProcedure *procedure,
PikaRunMode run_mode,
PikaImage *image,
gint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *args,
gpointer run_data);
G_DEFINE_TYPE (Twain, twain, PIKA_TYPE_PLUG_IN)
PIKA_MAIN (TWAIN_TYPE)
DEFINE_STD_SET_I18N
static void
twain_class_init (TwainClass *klass)
{
PikaPlugInClass *plug_in_class = PIKA_PLUG_IN_CLASS (klass);
plug_in_class->query_procedures = twain_query_procedures;
plug_in_class->create_procedure = twain_create_procedure;
plug_in_class->set_i18n = STD_SET_I18N;
}
static void
twain_init (Twain *twain)
{
}
static GList *
twain_query_procedures (PikaPlugIn *plug_in)
{
return g_list_append (NULL, g_strdup (PLUG_IN_NAME));
}
static PikaProcedure *
twain_create_procedure (PikaPlugIn *plug_in,
const gchar *name)
{
PikaProcedure *procedure = NULL;
if (! strcmp (name, PLUG_IN_NAME))
{
procedure = pika_image_procedure_new (plug_in, name,
PIKA_PDB_PROC_TYPE_PLUGIN,
twain_run, NULL, NULL);
pika_procedure_set_image_types (procedure, "*");
pika_procedure_set_sensitivity_mask (procedure,
PIKA_PROCEDURE_SENSITIVE_DRAWABLE |
PIKA_PROCEDURE_SENSITIVE_DRAWABLES |
PIKA_PROCEDURE_SENSITIVE_NO_DRAWABLES |
PIKA_PROCEDURE_SENSITIVE_NO_IMAGE);
pika_procedure_set_menu_label (procedure, _("_Scanner/Camera..."));
pika_procedure_add_menu_path (procedure, "<Image>/File/Create");
pika_procedure_set_documentation (procedure,
PLUG_IN_DESCRIPTION,
PLUG_IN_HELP,
name);
pika_procedure_set_attribution (procedure,
PLUG_IN_AUTHOR,
PLUG_IN_COPYRIGHT,
PLUG_IN_VERSION);
PIKA_PROC_VAL_INT (procedure, "image-count",
"Number of acquired images",
"Number of acquired images",
0, G_MAXINT, 0,
G_PARAM_READWRITE);
PIKA_PROC_VAL_OBJECT_ARRAY (procedure, "images",
"Array of acquired images",
"Array of acquired images",
PIKA_TYPE_IMAGE,
G_PARAM_READWRITE);
}
return procedure;
}
/* 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 */
static TwainValues twainvals =
{
"",
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
};
void
setRunMode (char *argv[])
{
char *exeName = strrchr (argv[0], '\\') + 1;
LogMessage ("Executable name: %s\n", exeName);
if (!_stricmp (exeName, DUMP_NAME))
twain_run_mode = RUN_DUMP;
if (!_stricmp (exeName, READDUMP_NAME))
twain_run_mode = RUN_READDUMP;
}
#endif /* _DEBUG */
int
scanImage (void)
{
#ifdef _DEBUG
if (twain_run_mode == RUN_READDUMP)
{
readDumpedImage (twSession);
return 0;
}
else
#endif /* _DEBUG */
return getImage (twSession);
}
/*
* initTwainAppIdentity
*
* Initialize and return our application's identity for
* the TWAIN runtime.
*/
static pTW_IDENTITY
getAppIdentity (void)
{
pTW_IDENTITY appIdentity = g_new (TW_IDENTITY, 1);
/* 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;
strcpy(appIdentity->Version.Info, "PIKA TWAIN 0.6");
appIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
appIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
appIdentity->SupportedGroups = DG_IMAGE;
strcpy(appIdentity->Manufacturer, "Craig Setera");
strcpy(appIdentity->ProductFamily, "PIKA");
strcpy(appIdentity->ProductName, "PIKA");
return appIdentity;
}
/*
* 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.
*/
pTW_SESSION
initializeTwain (void)
{
pTW_IDENTITY appIdentity;
/* Get our application's identity */
appIdentity = getAppIdentity ();
/* Create a new session object */
twSession = newSession (appIdentity);
/* 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);
return twSession;
}
/******************************************************************
* PIKA Plug-in entry points
******************************************************************/
/* Return values storage */
static GList *image_list = NULL;
static gint image_count = 0;
/*
* run
*
* The plug-in is being requested to run.
* Capture an image from a TWAIN datasource
*/
static PikaValueArray *
twain_run (PikaProcedure *procedure,
PikaRunMode run_mode,
PikaImage *image,
gint n_drawables,
PikaDrawable **drawables,
const PikaValueArray *args,
gpointer run_data)
{
/* Initialize the return values
* Always return at least the status to the caller.
*/
PikaPDBStatusType status = PIKA_PDB_SUCCESS;
PikaValueArray *return_vals = NULL;
PikaImage **images;
GList *list;
gint num_images;
gint i;
gegl_init (NULL, NULL);
/* 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 ())
{
return pika_procedure_new_return_values (procedure, PIKA_PDB_EXECUTION_ERROR,
NULL);
}
/* How are we running today? */
switch (run_mode)
{
case PIKA_RUN_INTERACTIVE:
/* Retrieve values from the last run...
* Currently ignored
*/
pika_get_data (PLUG_IN_NAME, &twainvals);
break;
case PIKA_RUN_NONINTERACTIVE:
/* Currently, we don't do non-interactive calls.
* Bail if someone tries to call us non-interactively
*/
return pika_procedure_new_return_values (procedure, PIKA_PDB_CALLING_ERROR,
NULL);
case PIKA_RUN_WITH_LAST_VALS:
/* Retrieve values from the last run...
* Currently ignored
*/
pika_get_data (PLUG_IN_NAME, &twainvals);
break;
default:
break;
}
/* Have we succeeded so far? */
if (status == PIKA_PDB_SUCCESS)
twainMain ();
/* Check to make sure we got at least one valid
* image.
*/
if (image_count > 0)
{
/* An image was captured from the TWAIN
* datasource. Do final Interactive
* steps.
*/
if (run_mode == PIKA_RUN_INTERACTIVE)
{
/* Store variable states for next run */
pika_set_data (PLUG_IN_NAME, &twainvals, sizeof (TwainValues));
}
num_images = g_list_length (image_list);
images = g_new (PikaImage *, num_images);
for (list = image_list, i = 0;
list;
list = g_list_next (list), i++)
{
images[i] = g_object_ref (list->data);
}
g_list_free (image_list);
/* Set return values */
return_vals = pika_procedure_new_return_values (procedure, status,
NULL);
PIKA_VALUES_SET_INT (return_vals, 1, num_images);
PIKA_VALUES_TAKE_OBJECT_ARRAY (return_vals, 2, PIKA_TYPE_IMAGE, images, num_images);
return return_vals;
}
else
{
return pika_procedure_new_return_values (procedure, PIKA_PDB_EXECUTION_ERROR,
NULL);
}
}
/***********************************************************************
* Image transfer callback functions
***********************************************************************/
/* Data used to carry data between each of
* the callback function calls.
*/
typedef struct
{
PikaImage *image;
PikaLayer *layer;
GeglBuffer *buffer;
const Babl *format;
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 */
pika_progress_init (_("Transferring data from scanner/camera"));
}
/*
* beginTransferCallback
*
* The following function is called at the beginning
* of each image transfer.
*/
int
beginTransferCallback (pTW_IMAGEINFO imageInfo,
void *clientData)
{
pClientDataStruct theClientData = g_new (ClientDataStruct, 1);
const Babl *format;
PikaImageBaseType imageType;
PikaImageType layerType;
PikaPrecision precision;
gint bpc = imageInfo->BitsPerPixel /
imageInfo->SamplesPerPixel;
#ifdef _DEBUG
logBegin (imageInfo, clientData);
#endif
/* Decide on the image type */
switch (imageInfo->PixelType)
{
case TWPT_BW:
/* Set up the image and layer types */
imageType = PIKA_GRAY;
layerType = PIKA_GRAY_IMAGE;
precision = PIKA_PRECISION_U8_NON_LINEAR;
format = babl_format ("Y' u8");
break;
case TWPT_GRAY:
/* Set up the image and layer types */
imageType = PIKA_GRAY;
layerType = PIKA_GRAY_IMAGE;
switch (bpc)
{
case 8:
precision = PIKA_PRECISION_U8_NON_LINEAR;
format = babl_format ("Y' u8");
break;
case 16:
precision = PIKA_PRECISION_U16_NON_LINEAR;
format = babl_format ("Y' u16");
break;
default:
return FALSE;
}
break;
case TWPT_RGB:
/* Set up the image and layer types */
imageType = PIKA_RGB;
layerType = PIKA_RGB_IMAGE;
switch (bpc)
{
case 8:
precision = PIKA_PRECISION_U8_NON_LINEAR;
format = babl_format ("R'G'B' u8");
break;
case 16:
precision = PIKA_PRECISION_U16_NON_LINEAR;
format = babl_format ("R'G'B' u16");
break;
default:
return FALSE;
}
break;
case TWPT_PALETTE:
/* Get the palette data */
theClientData->paletteData = g_new (TW_PALETTE8, 1);
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 */
imageType = PIKA_RGB;
layerType = PIKA_RGB_IMAGE;
precision = PIKA_PRECISION_U8_NON_LINEAR;
format = babl_format ("R'G'B' u8");
break;
case TWPA_GRAY:
/* Set up the image and layer types */
imageType = PIKA_GRAY;
layerType = PIKA_GRAY_IMAGE;
precision = PIKA_PRECISION_U8_NON_LINEAR;
format = babl_format ("Y' u8");
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;
}
/* Create the PIKA image */
theClientData->image = pika_image_new_with_precision (imageInfo->ImageWidth,
imageInfo->ImageLength,
imageType,
precision);
/* Set the actual resolution */
pika_image_set_resolution (theClientData->image,
FIX32ToFloat (imageInfo->XResolution),
FIX32ToFloat (imageInfo->YResolution));
pika_image_set_unit (theClientData->image, PIKA_UNIT_INCH);
/* Create a layer */
theClientData->layer = pika_layer_new (theClientData->image,
_("Background"),
imageInfo->ImageWidth,
imageInfo->ImageLength,
layerType, 100,
PIKA_LAYER_MODE_NORMAL);
/* Add the layer to the image */
pika_image_insert_layer (theClientData->image,
theClientData->layer, NULL, 0);
/* Update the progress dialog */
theClientData->totalPixels = imageInfo->ImageWidth * imageInfo->ImageLength;
theClientData->completedPixels = 0;
pika_progress_update (0.0);
theClientData->buffer = pika_drawable_get_buffer (PIKA_DRAWABLE (theClientData->layer));
theClientData->format = format;
/* Store our client data for the data transfer callbacks */
if (clientData)
g_free (clientData);
setClientData (twSession, (void *) theClientData);
/* Make sure to return TRUE to continue the image
* transfer
*/
return TRUE;
}
/*
* 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 PIKA
* image.
*/
static char bitMasks[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
static int
bitTransferCallback (pTW_IMAGEINFO imageInfo,
pTW_IMAGEMEMXFER imageMemXfer,
void *clientData)
{
int row, col, offset;
char *srcBuf;
char *destBuf;
int rows = imageMemXfer->Rows;
int cols = imageMemXfer->Columns;
pClientDataStruct theClientData = (pClientDataStruct) clientData;
/* Allocate a buffer as necessary */
destBuf = gegl_scratch_new (char, rows * cols);
/* 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;
}
}
/* Update the complete chunk */
gegl_buffer_set (theClientData->buffer,
GEGL_RECTANGLE (imageMemXfer->XOffset, imageMemXfer->YOffset,
cols, rows), 0,
theClientData->format, destBuf,
GEGL_AUTO_ROWSTRIDE);
/* Free the buffer */
gegl_scratch_free (destBuf);
/* Update the user on our progress */
theClientData->completedPixels += (cols * rows);
pika_progress_update ((double) theClientData->completedPixels /
(double) theClientData->totalPixels);
return TRUE;
}
/*
* directTransferCallback
*
* The following function is called for each memory
* block that is transferred from the data source if
* the image type is Grayscale or RGB.
*/
static int
directTransferCallback (pTW_IMAGEINFO imageInfo,
pTW_IMAGEMEMXFER imageMemXfer,
void *clientData)
{
int rows = imageMemXfer->Rows;
int cols = imageMemXfer->Columns;
pClientDataStruct theClientData = (pClientDataStruct) clientData;
/* Update the complete chunk */
gegl_buffer_set (theClientData->buffer,
GEGL_RECTANGLE (imageMemXfer->XOffset, imageMemXfer->YOffset,
cols, rows), 0,
theClientData->format, imageMemXfer->Memory.TheMem,
imageMemXfer->BytesPerRow);
/* Update the user on our progress */
theClientData->completedPixels += (cols * rows);
pika_progress_update ((double) theClientData->completedPixels /
(double) theClientData->totalPixels);
return TRUE;
}
/*
* 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 PIKA 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.
*/
static int
palettedTransferCallback (pTW_IMAGEINFO imageInfo,
pTW_IMAGEMEMXFER imageMemXfer,
void *clientData)
{
int channelsPerEntry;
int row, col;
int rows = imageMemXfer->Rows;
int cols = imageMemXfer->Columns;
char *destBuf;
char *destPtr = NULL;
char *srcPtr = NULL;
/* Get the client data */
pClientDataStruct theClientData = (pClientDataStruct) clientData;
/* Look up the palette entry size */
channelsPerEntry =
(theClientData->paletteData->PaletteType == TWPA_RGB) ? 3 : 1;
/* Allocate a buffer as necessary */
destBuf = gegl_scratch_new (char, rows * cols * channelsPerEntry);
/* Work through the rows */
destPtr = destBuf;
for (row = 0; row < rows; row++)
{
srcPtr = (char *) ((char *) imageMemXfer->Memory.TheMem +
(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++;
}
}
}
/* Send the complete chunk */
gegl_buffer_set (theClientData->buffer,
GEGL_RECTANGLE (imageMemXfer->XOffset, imageMemXfer->YOffset,
cols, rows), 0,
theClientData->format, destBuf,
GEGL_AUTO_ROWSTRIDE);
/* Free the buffer */
gegl_scratch_free (destBuf);
/* Update the user on our progress */
theClientData->completedPixels += (cols * rows);
pika_progress_update ((double) theClientData->completedPixels /
(double) theClientData->totalPixels);
return TRUE;
}
/*
* dataTransferCallback
*
* The following function is called for each memory
* block that is transferred from the data source.
*/
int
dataTransferCallback (pTW_IMAGEINFO imageInfo,
pTW_IMAGEMEMXFER imageMemXfer,
void *clientData)
{
#ifdef _DEBUG
logData (imageInfo, imageMemXfer, clientData);
#endif
/* Choose the appropriate transfer handler */
switch (imageInfo->PixelType)
{
case TWPT_PALETTE:
return palettedTransferCallback (imageInfo, imageMemXfer, clientData);
case TWPT_BW:
return bitTransferCallback (imageInfo, imageMemXfer, clientData);
case TWPT_GRAY:
case TWPT_RGB:
return directTransferCallback (imageInfo, imageMemXfer, clientData);
default:
return FALSE;
}
}
/*
* 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;
LogMessage ("endTransferCallback: CompState = %d, pending = %d\n",
completionState, pendingCount);
/* Clean up and detach from the drawable */
g_object_unref (theClientData->buffer);
/* Make sure to check our return code */
if (completionState == TWRC_XFERDONE)
{
/* We have a completed image transfer */
image_list = g_list_append (image_list, theClientData->image);
image_count++;
/* Display the image */
LogMessage ("Displaying image %d\n",
pika_image_get_id (theClientData->image));
pika_display_new (theClientData->image);
}
else
{
/* The transfer did not complete successfully */
LogMessage ("Deleting image\n");
pika_image_delete (theClientData->image);
}
/* Shut down if we have received all of the possible images */
return (image_count < 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);
/* Post a message to close up the application */
twainQuitApplication ();
}

1819
plug-ins/twain/twain.h Normal file

File diff suppressed because it is too large Load Diff