[gimp/bug-601821] Bug 601821 - Retrieve multiple images from TWAIN data source
- From: Michael Schumacher <schumaml src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/bug-601821] Bug 601821 - Retrieve multiple images from TWAIN data source
- Date: Tue, 14 Jun 2016 19:14:14 +0000 (UTC)
commit 7266c173c8be94c3cc716f1b9dbe3c8bee540a67
Author: Jens M. Plonka <jens plonka gmx de>
Date: Tue Jun 14 21:06:52 2016 +0200
Bug 601821 - Retrieve multiple images from TWAIN data source
(primarily multiple pages from a scanner document feeder)
plug-ins/twain/tw_func.c | 217 ++++++++++++++++++++++-----------------------
plug-ins/twain/tw_func.h | 19 ++--
plug-ins/twain/tw_local.h | 9 +--
plug-ins/twain/twain.c | 81 ++++++++---------
4 files changed, 158 insertions(+), 168 deletions(-)
---
diff --git a/plug-ins/twain/tw_func.c b/plug-ins/twain/tw_func.c
index f677f40..b31c3cd 100644
--- a/plug-ins/twain/tw_func.c
+++ b/plug-ins/twain/tw_func.c
@@ -142,13 +142,20 @@ twainError (int errorCode)
char *
currentTwainError (pTW_SESSION twSession)
{
- TW_STATUS twStatus;
+ pTW_STATUS twStatus;
+ char * error;
+
+ twStatus = g_new (TW_STATUS, 1);
/* Get the current status code from the DSM */
twSession->twRC = DSM_GET_STATUS(twSession, twStatus);
/* Return the mapped error code */
- return twainError (twStatus.ConditionCode);
+ error = twainError (twStatus->ConditionCode);
+
+ g_free (twStatus);
+
+ return error;
}
/*
@@ -187,6 +194,8 @@ getImage (pTW_SESSION twSession)
return FALSE;
}
+ set_ds_capabilities (twSession);
+
requestImageAcquire (twSession, TRUE);
return TRUE;
@@ -342,10 +351,26 @@ openDS (pTW_SESSION twSession)
}
/*
- * setBufferedXfer
+ * set_ds_capabilities
+ *
+ * Sets the required capabilities of the data source.
*/
-static int
-setBufferedXfer (pTW_SESSION twSession)
+void
+set_ds_capabilities (pTW_SESSION twSession)
+{
+ if (!DS_IS_OPEN(twSession))
+ {
+ log_message ("Open data source before setting capabilities!\n", currentTwainError(twSession));
+ }
+ else
+ {
+ set_ds_capability (twSession, ICAP_XFERMECH, TWTY_UINT16, TWSX_MEMORY);
+ set_ds_capability (twSession, CAP_XFERCOUNT, TWTY_INT16, TWBP_AUTO);
+ }
+}
+
+void
+set_ds_capability (pTW_SESSION twSession, TW_UINT16 cap, TW_UINT16 type, TW_UINT32 value)
{
TW_CAPABILITY bufXfer;
pTW_ONEVALUE pvalOneValue;
@@ -353,25 +378,25 @@ setBufferedXfer (pTW_SESSION twSession)
/* Make sure the data source is open first */
if (DS_IS_CLOSED(twSession))
{
- return FALSE;
+ return;
}
/* Create the capability information */
- bufXfer.Cap = ICAP_XFERMECH;
+ bufXfer.Cap = cap;
bufXfer.ConType = TWON_ONEVALUE;
bufXfer.hContainer = twainAllocHandle (sizeof(TW_ONEVALUE));
if (bufXfer.hContainer == NULL)
{
g_message ("Error allocating memory for XFer mechanism.\n");
- return FALSE;
+ return;
}
pvalOneValue = (pTW_ONEVALUE) twainLockHandle (bufXfer.hContainer);
- pvalOneValue->ItemType = TWTY_UINT16;
- pvalOneValue->Item = TWSX_MEMORY;
+ pvalOneValue->ItemType = type;
+ pvalOneValue->Item = value;
twainUnlockHandle (bufXfer.hContainer);
/* Make the call to the source manager */
- twSession->twRC = DSM_XFER_SET(twSession, bufXfer);
+ twSession->twRC = DSM_CAPABILITY_SET(twSession, bufXfer);
if (twSession->twRC == TWRC_FAILURE)
{
g_message ("Could not set capability: %s\n", currentTwainError(twSession));
@@ -380,9 +405,6 @@ setBufferedXfer (pTW_SESSION twSession)
/* Free the container */
twainUnlockHandle (bufXfer.hContainer);
twainFreeHandle (bufXfer.hContainer);
-
- /* Let the caller know what happened */
- return (twSession->twRC==TWRC_SUCCESS);
}
/*
@@ -402,29 +424,25 @@ requestImageAcquire (pTW_SESSION twSession, gboolean showUI)
return FALSE;
}
- /* Set the transfer mode */
- if (setBufferedXfer (twSession))
- {
- /* 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;
+ /* 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 = DSM_ENABLE_DS(twSession, ui);
+ /* Make the call to the source manager */
+ twSession->twRC = DSM_ENABLE_DS(twSession, ui);
- switch (twSession->twRC)
- {
- case TWRC_SUCCESS:
- /* We are now at a new twain state */
- twSession->twainState = 5;
- return TRUE;
+ switch (twSession->twRC)
+ {
+ case TWRC_SUCCESS:
+ /* We are now at a new twain state */
+ twSession->twainState = 5;
+ return TRUE;
- case TWRC_FAILURE:
- g_message ("Error enabeling data source: %s\n", currentTwainError(twSession));
- break;
- }
+ case TWRC_FAILURE:
+ g_message ("Error enabeling data source: %s\n", currentTwainError(twSession));
+ break;
}
return FALSE;
}
@@ -531,7 +549,7 @@ closeDSM (pTW_SESSION twSession)
* Begin an image transfer.
*/
static int
-beginImageTransfer (pTW_SESSION twSession, pTW_IMAGEINFO imageInfo)
+beginImageTransfer (pTW_SESSION twSession, pTW_IMAGEINFO imageInfo, gboolean first)
{
/* Clear our structures */
memset (imageInfo, 0, sizeof (TW_IMAGEINFO));
@@ -569,23 +587,16 @@ beginImageTransfer (pTW_SESSION twSession, pTW_IMAGEINFO imageInfo)
* from State 6 to 7. Return the reason for exiting the transfer.
*/
static void
-transferImage (pTW_SESSION twSession, pTW_IMAGEINFO imageInfo)
+transferImage (pTW_SESSION twSession, pTW_IMAGEINFO imageInfo, TW_UINT32 bufferSize)
{
- 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 = DSM_XFER_START(twSession, setupMemXfer);
-
/* Allocate the buffer for the transfer */
- buffer = g_new (char, setupMemXfer.Preferred);
+ memset (&imageMemXfer, 0, sizeof (TW_IMAGEMEMXFER));
+ buffer = g_new (char, bufferSize);
imageMemXfer.Memory.Flags = TWMF_APPOWNS | TWMF_POINTER;
- imageMemXfer.Memory.Length = setupMemXfer.Preferred;
+ imageMemXfer.Memory.Length = bufferSize;
imageMemXfer.Memory.TheMem = (TW_MEMREF) buffer;
/* Get the data */
@@ -621,13 +632,13 @@ transferImage (pTW_SESSION twSession, pTW_IMAGEINFO imageInfo)
}
/*
- * endPendingTransfer
+ * endImageTransfer
*
- * Cancel the currently pending transfer.
- * Return the count of pending transfers.
+ * Finish transferring an image. Return the count
+ * of pending images.
*/
-static int
-endPendingTransfer (pTW_SESSION twSession)
+static void
+endImageTransfer (pTW_SESSION twSession)
{
TW_PENDINGXFERS pendingXfers;
@@ -638,54 +649,8 @@ endPendingTransfer (pTW_SESSION twSession)
twSession->twainState = 5;
}
- return pendingXfers.Count;
-}
-
-/*
- * cancelPendingTransfers
- *
- * Cancel all pending image transfers.
- */
-void
-cancelPendingTransfers (pTW_SESSION twSession)
-{
- TW_PENDINGXFERS pendingXfers;
-
- twSession->twRC = DSM_XFER_RESET(twSession, pendingXfers);
-}
-
-/*
- * endImageTransfer
- *
- * Finish transferring an image. Return the count
- * of pending images.
- */
-static int
-endImageTransfer (pTW_SESSION twSession, int *pendingCount)
-{
- gboolean continueTransfers;
- 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:
- *pendingCount = endPendingTransfer (twSession);
- break;
-
- case TWRC_FAILURE:
- g_message ("Failure received: %s\n", currentTwainError(twSession));
- *pendingCount = endPendingTransfer (twSession);
- break;
- }
-
/* Call the end transfer callback */
- CB_XFER_END(twSession, continueTransfers, exitCode, pendingCount);
-
- return (*pendingCount && continueTransfers);
+ CB_XFER_END(twSession);
}
/*
@@ -697,8 +662,11 @@ endImageTransfer (pTW_SESSION twSession, int *pendingCount)
static void
transferImages (pTW_SESSION twSession)
{
- TW_IMAGEINFO imageInfo;
- int pendingCount;
+ TW_IMAGEINFO imageInfo;
+ TW_PENDINGXFERS pendingXfers;
+ gboolean first;
+ TW_UINT32 bufferSize;
+ TW_SETUPMEMXFER setupMemXfer;
/* Check the image transfer callback function
* before even attempting to do the transfer
@@ -718,28 +686,57 @@ transferImages (pTW_SESSION twSession)
CB_XFER_PRE(twSession);
}
+ first = TRUE;
+
+ /* Clear our structures */
+ memset (&setupMemXfer, 0, sizeof (TW_SETUPMEMXFER));
+
+ /* Find out how the source would like to transfer... */
+ twSession->twRC = DSM_XFER_START(twSession, setupMemXfer);
+ switch (twSession->twRC)
+ {
+ case TWRC_SUCCESS:
+ bufferSize = setupMemXfer.Preferred;
+ break;
+
+ case TWRC_FAILURE:
+ log_message ("Failure setting transfer buffer: %s\n", currentTwainError(twSession));
+ break;
+
+ default:
+ break;
+ }
+
/* Loop through the available images */
- do
+ while (beginImageTransfer (twSession, &imageInfo, first))
{
+ first = FALSE;
/* 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);
+ transferImage (twSession, &imageInfo, bufferSize);
+
+ endImageTransfer (twSession);
+ }
+
+ /* Reset any open transfers */
+ DSM_XFER_RESET(twSession, pendingXfers);
- } while (endImageTransfer (twSession, &pendingCount));
+ /* 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);
/*
* Inform our application that we are done
* transferring images.
*/
- CB_XFER_POST(twSession, pendingCount);
+ CB_XFER_POST(twSession);
}
void
diff --git a/plug-ins/twain/tw_func.h b/plug-ins/twain/tw_func.h
index 54ad04f..091b58a 100644
--- a/plug-ins/twain/tw_func.h
+++ b/plug-ins/twain/tw_func.h
@@ -110,7 +110,7 @@ typedef int (* TW_TXFR_DATA_CB)(pTW_IMAGEINFO, pTW_IMAGEMEMXFER, void *);
* TWRC_FAILURE
* The transfer failed.
*/
-typedef int (* TW_TXFR_END_CB)(int, int, void *);
+typedef void (* TW_TXFR_END_CB)(int, void *);
/*
* Post-image transfer callback
@@ -119,7 +119,7 @@ typedef int (* TW_TXFR_END_CB)(int, int, void *);
* of the possible images have been transferred
* from the datasource.
*/
-typedef void (* TW_POST_TXFR_CB)(int, void *);
+typedef void (* TW_POST_TXFR_CB)(void *);
/*
* The following structure defines the
@@ -211,11 +211,11 @@ typedef struct _TWAIN_SESSION {
#define CB_XFER_DATA(s, i, m) (*s->transferFunctions->txfrDataCb) \
(i, &m, s->clientData)
-#define CB_XFER_END(s, c, e, p) if (s->transferFunctions->txfrEndCb) \
- c = (*s->transferFunctions->txfrEndCb) (e, *p, s->clientData)
+#define CB_XFER_END(s) if (s->transferFunctions->txfrEndCb) \
+ (*s->transferFunctions->txfrEndCb) (s->twRC, s->clientData)
-#define CB_XFER_POST(s, p) if (s->transferFunctions->postTxfrCb) \
- (*s->transferFunctions->postTxfrCb) (p, s->clientData)
+#define CB_XFER_POST(s) if (s->transferFunctions->postTxfrCb) \
+ (*s->transferFunctions->postTxfrCb) (s->clientData)
/* Session structure access
* macros
@@ -236,7 +236,7 @@ typedef struct _TWAIN_SESSION {
#define DS_IS_DISABLED(s) ((s == NULL) ? TRUE : s->twainState < 5)
#define DSM_GET_STATUS(ses, sta) callDSM(ses->appIdentity, ses->dsIdentity, \
- DG_CONTROL, DAT_STATUS, MSG_GET, (TW_MEMREF) &sta)
+ DG_CONTROL, DAT_STATUS, MSG_GET, (TW_MEMREF) sta)
#define DSM_OPEN(ses) callDSM(ses->appIdentity, NULL,\
DG_CONTROL, DAT_PARENT, MSG_OPENDSM, (TW_MEMREF) &(ses->hwnd))
@@ -274,7 +274,7 @@ typedef struct _TWAIN_SESSION {
#define DSM_GET_IMAGE(ses, i) callDSM(ses->appIdentity, ses->dsIdentity,\
DG_IMAGE, DAT_IMAGEINFO, MSG_GET, (TW_MEMREF) i)
-#define DSM_XFER_SET(ses, x) callDSM(ses->appIdentity, ses->dsIdentity,\
+#define DSM_CAPABILITY_SET(ses, x) callDSM(ses->appIdentity, ses->dsIdentity,\
DG_CONTROL, DAT_CAPABILITY, MSG_SET, (TW_MEMREF) &x)
#define DSM_XFER_START(ses, x) callDSM(ses->appIdentity, ses->dsIdentity,\
@@ -313,5 +313,6 @@ void processTwainMessage (TW_UINT16 message, pTW_SESSION twSession);
pTW_SESSION newSession (pTW_IDENTITY twSession);
pTW_DATA_SOURCE get_available_ds (pTW_SESSION twSession);
int adjust_selected_data_source (pTW_SESSION twSession);
-
+void set_ds_capabilities (pTW_SESSION twSession);
+void set_ds_capability (pTW_SESSION twSession, TW_UINT16 cap, TW_UINT16 type, TW_UINT32 value);
#endif /* _TW_FUNC_H */
diff --git a/plug-ins/twain/tw_local.h b/plug-ins/twain/tw_local.h
index 3289a9e..0815a90 100644
--- a/plug-ins/twain/tw_local.h
+++ b/plug-ins/twain/tw_local.h
@@ -51,11 +51,6 @@
{ GIMP_PDB_INT32, "image-count", "Number of acquired images" }, \
{ GIMP_PDB_INT32ARRAY, "image-ids", "Array of acquired image identifiers" }
-/*
- * Application definitions
- */
-#define MAX_IMAGES 1
-
/* Functions which the platform-independent code will call */
TW_UINT16 callDSM (
pTW_IDENTITY pOrigin,
@@ -81,8 +76,8 @@ pTW_SESSION initializeTwain (void);
void preTransferCallback (void *);
int beginTransferCallback (pTW_IMAGEINFO, void *);
int dataTransferCallback (pTW_IMAGEINFO, pTW_IMAGEMEMXFER, void *);
-int endTransferCallback (int, int, void *);
-void postTransferCallback (int, void *);
+void endTransferCallback (int, void *);
+void postTransferCallback (void *);
void register_menu (pTW_IDENTITY dsIdentity);
void register_scanner_menus (void);
diff --git a/plug-ins/twain/twain.c b/plug-ins/twain/twain.c
index bd98c4c..3c24e70 100644
--- a/plug-ins/twain/twain.c
+++ b/plug-ins/twain/twain.c
@@ -8,7 +8,8 @@
* Brion Vibber <brion pobox com>
* 07/22/2004
*
- * Added for Win x64 support, changed data source selection.
+ * Added for Win x64 support, changed data source selection, fixed
+ * scanning more than one image.
* Jens M. Plonka <jens plonka gmx de>
* 11/25/2011
*
@@ -61,7 +62,8 @@
* (03/31/99) v0.5 Added support for multi-byte samples and paletted
* images.
* (07/23/04) v0.6 Added Mac OS X support.
- * (11/25/11) v0.7 Added Win x64 support, changed data source selection.
+ * (11/25/11) v0.7 Added Win x64 support, changed data source selection,
+ * fixed scanning more than one image.
*/
#include "config.h"
@@ -94,6 +96,10 @@ static const GimpParamDef args[] = { IN_ARGS };
static const GimpParamDef return_vals[] = { OUT_ARGS };
static char *destBuf = NULL;
+
+/* The list of images to be transferred */
+GList *images = NULL;
+
static char bitMasks[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
/* Return values storage */
@@ -309,14 +315,17 @@ run (const gchar *name,
gint *nreturn_vals,
GimpParam **return_vals)
{
- GimpRunMode run_mode = param[0].data.d_int32;
+ GList *list;
+ gint32 count = 0;
+ gint32 i;
+ GimpRunMode run_mode = param[0].data.d_int32;
/* Initialize the return values
* Always return at least the status to the caller.
*/
values[0].type = GIMP_PDB_STATUS;
values[0].data.d_status = GIMP_PDB_SUCCESS;
- *nreturn_vals = 1;
+ *nreturn_vals = 3;
*return_vals = values;
INIT_I18N ();
@@ -335,7 +344,7 @@ run (const gchar *name,
values[1].type = GIMP_PDB_INT32;
values[1].data.d_int32 = 0;
values[2].type = GIMP_PDB_INT32ARRAY;
- values[2].data.d_int32array = g_new (gint32, MAX_IMAGES);
+ values[2].data.d_int32array = NULL; /* Will be assigned after acquiring images */
/* How are we running today? */
switch (run_mode)
@@ -353,15 +362,31 @@ run (const gchar *name,
/* Have we succeeded so far? */
if (values[0].data.d_status == GIMP_PDB_SUCCESS)
{
- twainMain (name);
+ if (twainMain (name))
+ {
+ count = g_list_length (images);
+ }
}
+ /* Retrun the number of images */
+ values[1].data.d_int32 = count;
+
/* Check to make sure we got at least one valid
* image.
*/
- if (values[1].data.d_int32 > 0) {
- /* Set return values */
- *nreturn_vals = 3;
+ if (count == 0)
+ {
+ values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
+ }
+ else
+ {
+ /* Return the list of image IDs */
+ values[2].data.d_int32array = g_new (gint32, count);
+ for (list = images, i = 0; list; list = g_list_next (list), i++)
+ {
+ values[2].data.d_int32array[i] = GPOINTER_TO_INT (list->data);
+ }
+ g_list_free (images);
}
}
@@ -478,12 +503,6 @@ beginTransferCallback (pTW_IMAGEINFO imageInfo, void *clientData)
gimp_pixel_rgn_init (&(theClientData->pixel_rgn), theClientData->drawable,
0, 0, width, length, TRUE, FALSE);
- /* Store our client data for the data transfer callbacks */
- if (clientData)
- {
- g_free (clientData);
- }
-
twSession->clientData = (void *) theClientData;
/* Make sure to return TRUE to continue the image
@@ -826,8 +845,8 @@ dataTransferCallback (
* TWRC_FAILURE
* The transfer failed.
*/
-int
-endTransferCallback (int completionState, int pendingCount, void *clientData)
+void
+endTransferCallback (int twRC, void *clientData)
{
pClientDataStruct theClientData = (pClientDataStruct) clientData;
@@ -841,13 +860,9 @@ endTransferCallback (int completionState, int pendingCount, void *clientData)
gimp_drawable_detach (theClientData->drawable);
/* Make sure to check our return code */
- if (completionState == TWRC_XFERDONE)
+ if ((twRC == TWRC_XFERDONE) || (twRC == TWRC_SUCCESS))
{
- /* We have a completed image transfer */
- values[2].type = GIMP_PDB_INT32ARRAY;
- values[2].data.d_int32array[values[1].data.d_int32++] =
- theClientData->image_id;
-
+ images = g_list_prepend (images, GINT_TO_POINTER (theClientData->image_id));
/* Display the image */
gimp_display_new (theClientData->image_id);
}
@@ -856,9 +871,6 @@ endTransferCallback (int completionState, int pendingCount, void *clientData)
/* The transfer did not complete successfully */
gimp_image_delete (theClientData->image_id);
}
-
- /* Shut down if we have received all of the possible images */
- return (values[1].data.d_int32 < MAX_IMAGES);
}
/*
@@ -869,23 +881,8 @@ endTransferCallback (int completionState, int pendingCount, void *clientData)
* transferred.
*/
void
-postTransferCallback (int pendingCount, void *clientData)
+postTransferCallback (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 ();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]