home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / twain / twain.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-24  |  31.1 KB  |  1,136 lines

  1. /*  
  2.  * TWAIN Plug-in
  3.  * Copyright (C) 1999 Craig Setera
  4.  * Craig Setera <setera@home.com>
  5.  * 03/31/1999
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 2 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program; if not, write to the Free Software
  19.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20.  *
  21.  *
  22.  * Based on (at least) the following plug-ins:
  23.  * Screenshot
  24.  * GIF
  25.  * Randomize
  26.  *
  27.  * Any suggestions, bug-reports or patches are welcome.
  28.  * 
  29.  * This plug-in interfaces to the TWAIN support library in order
  30.  * to capture images from TWAIN devices directly into GIMP images.
  31.  * The plug-in is capable of acquiring the following type of
  32.  * images:
  33.  * - B/W (1 bit images translated to grayscale B/W)
  34.  * - Grayscale up to 16 bits per pixel
  35.  * - RGB up to 16 bits per sample (24, 30, 36, etc.)
  36.  * - Paletted images (both Gray and RGB)
  37.  *
  38.  * Prerequisites:
  39.  *  This plug-in will not compile on anything other than a Win32
  40.  *  platform.  Although the TWAIN documentation implies that there
  41.  *  is TWAIN support available on Macintosh, I neither have a 
  42.  *  Macintosh nor the interest in porting this.  If anyone else
  43.  *  has an interest, consult www.twain.org for more information on
  44.  *  interfacing to TWAIN.
  45.  *
  46.  * Known problems:
  47.  * - Multiple image transfers will hang the plug-in.  The current
  48.  *   configuration compiles with a maximum of single image transfers.
  49.  */
  50.  
  51. /* 
  52.  * Revision history
  53.  *  (02/07/99)  v0.1   First working version (internal)
  54.  *  (02/09/99)  v0.2   First release to anyone other than myself
  55.  *  (02/15/99)  v0.3   Added image dump and read support for debugging
  56.  *  (03/31/99)  v0.5   Added support for multi-byte samples and paletted 
  57.  *                     images.
  58.  */
  59. #include "config.h"
  60.  
  61. #include <glib.h>        /* Needed when compiling with gcc */
  62.  
  63. #include <stdio.h>
  64. #include <stdlib.h>
  65. #include <string.h>
  66. #include <ctype.h>
  67. #include <windows.h>
  68.  
  69. #include <gtk/gtk.h>
  70.  
  71. #include "libgimp/gimp.h"
  72. #include "libgimp/stdplugins-intl.h"
  73.  
  74. #include "tw_func.h"
  75. #include "tw_util.h"
  76.  
  77. #ifdef _DEBUG
  78. #include "tw_dump.h"
  79. #endif /* _DEBUG */
  80.  
  81. /*
  82.  * Plug-in Definitions
  83.  */
  84. #define PLUG_IN_NAME        "twain-acquire"
  85. #define PLUG_IN_DESCRIPTION "Capture an image from a TWAIN datasource"
  86. #define PLUG_IN_HELP        "This plug-in will capture an image from a TWAIN datasource"
  87. #define PLUG_IN_AUTHOR      "Craig Setera (setera@home.com)"
  88. #define PLUG_IN_COPYRIGHT   "Craig Setera"
  89. #define PLUG_IN_VERSION     "v0.5 (03/31/1999)"
  90.  
  91. #ifdef _DEBUG
  92. #define PLUG_IN_D_NAME        "twain-acquire-dump"
  93. #define PLUG_IN_D_MENU_PATH   "<Toolbox>/File/Acquire/TWAIN (Dump)..."
  94.  
  95. #define PLUG_IN_R_NAME        "twain-acquire-read"
  96. #define PLUG_IN_R_MENU_PATH   "<Toolbox>/File/Acquire/TWAIN (Read)..."
  97. #endif /* _DEBUG */
  98.  
  99. /*
  100.  * Application definitions
  101.  */
  102. #define APP_NAME "TWAIN"
  103. #define MAX_IMAGES 1
  104. #define SHOW_WINDOW 0
  105. #define WM_TRANSFER_IMAGE (WM_USER + 100)
  106.  
  107. /*
  108.  * Definition of the run states 
  109.  */
  110. #define RUN_STANDARD 0
  111. #define RUN_DUMP 1
  112. #define RUN_READDUMP 2
  113.  
  114. /* Global variables */
  115. pTW_SESSION twSession = NULL;
  116.  
  117. static HWND        hwnd = NULL;
  118. static HINSTANCE   hInst = NULL;
  119. static char        *destBuf = NULL;
  120. static int         twain_run_mode = RUN_STANDARD;
  121.  
  122. /* Forward declarations */
  123. void preTransferCallback(void *);
  124. int  beginTransferCallback(pTW_IMAGEINFO, void *);
  125. int  dataTransferCallback(pTW_IMAGEINFO, pTW_IMAGEMEMXFER, void *);
  126. int  endTransferCallback(int, int, void *);
  127. void postTransferCallback(int, void *);
  128.  
  129. static void init(void);
  130. static void quit(void);
  131. static void query(void);
  132. static void run(char *, int, GimpParam *, int *, GimpParam **);
  133.  
  134. /* This plug-in's functions */
  135. GimpPlugInInfo PLUG_IN_INFO =
  136. {
  137.   NULL,    /* init_proc */
  138.   NULL,    /* quit_proc */
  139.   query,   /* query_proc */
  140.   run,     /* run_proc */
  141. };
  142.     
  143. extern void set_gimp_PLUG_IN_INFO_PTR(GimpPlugInInfo *);
  144.  
  145. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  146.  
  147. /* Data structure holding data between runs */
  148. /* Currently unused... Eventually may be used
  149.  * to track dialog data.
  150.  */
  151. typedef struct {
  152.   gchar  sourceName[34];
  153.   gfloat xResolution;
  154.   gfloat yResolution;
  155.   gint   xOffset;
  156.   gint   yOffset;
  157.   gint   width;
  158.   gint   height;
  159.   gint   imageType;
  160. } TwainValues;
  161.  
  162. /* Default Twain values */
  163. static TwainValues twainvals = 
  164.   "",
  165.   100.0, 100.0,
  166.   0, 0,
  167.   0, 0,
  168.   TWPT_RGB
  169. };
  170.  
  171. /* The standard callback functions */
  172. TXFR_CB_FUNCS standardCbFuncs = {
  173.   preTransferCallback,
  174.   beginTransferCallback,
  175.   dataTransferCallback,
  176.   endTransferCallback,
  177.   postTransferCallback };
  178.  
  179. /******************************************************************
  180.  * Dump handling
  181.  ******************************************************************/
  182.  
  183. #ifdef _DEBUG
  184. /* The dumper callback functions */
  185. TXFR_CB_FUNCS dumperCbFuncs = {
  186.   dumpPreTransferCallback,
  187.   dumpBeginTransferCallback,
  188.   dumpDataTransferCallback,
  189.   dumpEndTransferCallback,
  190.   dumpPostTransferCallback };
  191.  
  192. static void
  193. setRunMode(char *argv[])
  194. {
  195.   char *exeName = strrchr(argv[0], '\\') + 1;
  196.  
  197.   LogMessage("Executable name: %s\n", exeName);
  198.  
  199.   if (!_stricmp(exeName, "DTWAIN.EXE"))
  200.     twain_run_mode = RUN_DUMP;
  201.  
  202.   if (!_stricmp(exeName, "RTWAIN.EXE"))
  203.     twain_run_mode = RUN_READDUMP;
  204. }
  205. #endif /* _DEBUG */
  206.     
  207. /******************************************************************
  208.  * Win32 entry point and setup...
  209.  ******************************************************************/
  210.     
  211. /*
  212.  * WinMain
  213.  *
  214.  * The standard gimp entry point won't quite cut it for
  215.  * this plug-in.  This plug-in requires creation of a
  216.  * standard Win32 window (hidden) in order to receive
  217.  * and process window messages on behalf of the TWAIN
  218.  * datasource.
  219.  */
  220. int APIENTRY 
  221. WinMain(HINSTANCE hInstance,
  222.     HINSTANCE hPrevInstance,
  223.     LPSTR     lpCmdLine,
  224.     int       nCmdShow)
  225. {
  226.         
  227.   /* 
  228.    * Normally, we would do all of the Windows-ish set up of
  229.    * the window classes and stuff here in WinMain.  But,
  230.    * the only time we really need the window and message
  231.    * queues is during the plug-in run.  So, all of that will
  232.    * be done during run().  This avoids all of the Windows
  233.    * setup stuff for the query().  Stash the instance handle now
  234.    * so it is available from the run() procedure.
  235.    */
  236.   hInst = hInstance;
  237.  
  238. #ifdef _DEBUG
  239.   /* When in debug version, we allow different run modes...
  240.    * make sure that it is correctly set.
  241.    */
  242.   setRunMode(__argv);
  243. #endif /* _DEBUG */
  244.  
  245.   /*
  246.    * Now, call gimp_main... This is what the MAIN() macro
  247.    * would usually do.
  248.    */
  249.   set_gimp_PLUG_IN_INFO_PTR(&PLUG_IN_INFO);
  250.   return gimp_main(__argc, __argv);
  251. }
  252.     
  253. /*
  254.  * initTwainAppIdentity
  255.  *
  256.  * Initialize and return our application's identity for
  257.  * the TWAIN runtime.
  258.  */
  259. static pTW_IDENTITY
  260. getAppIdentity(void)
  261. {
  262.   pTW_IDENTITY appIdentity = g_new (TW_IDENTITY, 1);
  263.         
  264.   /* Set up the application identity */
  265.   appIdentity->Id = 0;
  266.   appIdentity->Version.MajorNum = 0;
  267.   appIdentity->Version.MinorNum = 1;
  268.   appIdentity->Version.Language = TWLG_USA;
  269.   appIdentity->Version.Country = TWCY_USA;
  270.   strcpy(appIdentity->Version.Info, "GIMP TWAIN 0.5");
  271.   appIdentity->ProtocolMajor = TWON_PROTOCOLMAJOR;
  272.   appIdentity->ProtocolMinor = TWON_PROTOCOLMINOR;
  273.   appIdentity->SupportedGroups = DG_IMAGE;
  274.   strcpy(appIdentity->Manufacturer, "Craig Setera");
  275.   strcpy(appIdentity->ProductFamily, "GIMP");
  276.   strcpy(appIdentity->ProductName, "GIMP for Win32");
  277.         
  278.   return appIdentity;
  279. }
  280.     
  281. /*
  282.  * initializeTwain
  283.  *
  284.  * Do the necessary TWAIN initialization.  This sets up
  285.  * our TWAIN session information.  The session stuff is
  286.  * something built by me on top of the standard TWAIN
  287.  * datasource manager calls.
  288.  */
  289. void
  290. initializeTwain(void)
  291. {
  292.   pTW_IDENTITY appIdentity;
  293.         
  294.   /* Get our application's identity */
  295.   appIdentity = getAppIdentity();
  296.         
  297.   /* Create a new session object */
  298.   twSession = newSession(appIdentity);
  299.         
  300.   /* Register our image transfer callback functions */
  301. #ifdef _DEBUG
  302.   if (twain_run_mode == RUN_DUMP)
  303.     registerTransferCallbacks(twSession, &dumperCbFuncs, NULL);
  304.   else
  305. #endif /* _DEBUG */
  306.     registerTransferCallbacks(twSession, &standardCbFuncs, NULL);
  307. }
  308.     
  309. /*
  310.  * InitApplication
  311.  *
  312.  * Initialize window data and register the window class
  313.  */
  314. BOOL 
  315. InitApplication(HINSTANCE hInstance)
  316. {
  317.   WNDCLASS wc;
  318.   BOOL retValue;
  319.         
  320.   /*
  321.    * Fill in window class structure with parameters to describe
  322.    * the main window.
  323.    */
  324.   wc.style = CS_HREDRAW | CS_VREDRAW;
  325.   wc.lpfnWndProc = (WNDPROC) WndProc;
  326.   wc.cbClsExtra = 0;
  327.   wc.cbWndExtra = 0;
  328.   wc.hInstance = hInstance;
  329.   wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  330.   wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  331.   wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  332.   wc.lpszClassName = APP_NAME;
  333.   wc.lpszMenuName = NULL;
  334.         
  335.   /* Register the window class and stash success/failure code. */
  336.   retValue = RegisterClass(&wc);
  337.         
  338.   /* Log error */
  339.   if (!retValue)
  340.     LogLastWinError();
  341.         
  342.   return retValue;
  343. }
  344.     
  345. /*
  346.  * InitInstance
  347.  * 
  348.  * Create the main window for the application.  Used to
  349.  * interface with the TWAIN datasource.
  350.  */
  351. BOOL 
  352. InitInstance(HINSTANCE hInstance, int nCmdShow)
  353. {
  354.   /* Create our window */
  355.   hwnd = CreateWindow(APP_NAME, APP_NAME, WS_OVERLAPPEDWINDOW,
  356.               CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
  357.               NULL, NULL, hInstance, NULL);
  358.         
  359.   if (!hwnd) {
  360.     return (FALSE);
  361.   }
  362.         
  363.   ShowWindow(hwnd, nCmdShow);
  364.   UpdateWindow(hwnd);
  365.         
  366.   return TRUE;
  367. }
  368.     
  369. /*
  370.  * twainWinMain
  371.  *
  372.  * This is the function that represents the code that
  373.  * would normally reside in WinMain (see above).  This
  374.  * function will get called during run() in order to set
  375.  * up the windowing environment necessary for TWAIN to
  376.  * operate.
  377.  */
  378. int
  379. twainWinMain(void) 
  380. {
  381.         
  382.   /* Initialize the twain information */
  383.   initializeTwain();
  384.         
  385.   /* Perform instance initialization */
  386.   if (!InitApplication(hInst))
  387.     return (FALSE);
  388.         
  389.   /* Perform application initialization */
  390.   if (!InitInstance(hInst, SHOW_WINDOW))
  391.     return (FALSE);
  392.         
  393.   /* 
  394.    * Call the main message processing loop...
  395.    * This call will not return until the application
  396.    * exits.
  397.    */
  398.   return twainMessageLoop(twSession);
  399. }
  400.     
  401. /*
  402.  * WndProc
  403.  *
  404.  * Process window message for the main window.
  405.  */
  406. LRESULT CALLBACK 
  407. WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  408. {
  409.   switch (message) {
  410.             
  411.   case WM_CREATE:
  412.     /* Register our window handle with the TWAIN
  413.      * support.
  414.      */
  415.     registerWindowHandle(twSession, hWnd);
  416.             
  417.     /* Schedule the image transfer by posting a message */
  418.     PostMessage(hWnd, WM_TRANSFER_IMAGE, 0, 0);
  419.     break;
  420.             
  421.   case WM_TRANSFER_IMAGE:
  422.     /* Get an image */
  423. #ifdef _DEBUG
  424.     if (twain_run_mode == RUN_READDUMP)
  425.       readDumpedImage(twSession);
  426.     else
  427. #endif /* _DEBUG */
  428.       getImage(twSession);
  429.     break;
  430.             
  431.   case WM_DESTROY:
  432.     LogMessage("Exiting application\n");
  433.     PostQuitMessage(0);
  434.     break;
  435.             
  436.   default:
  437.     return (DefWindowProc(hWnd, message, wParam, lParam));
  438.   }
  439.   return 0;
  440. }
  441.     
  442. /******************************************************************
  443.  * GIMP Plug-in entry points
  444.  ******************************************************************/
  445.     
  446. /*
  447.  * Plug-in Parameter definitions
  448.  */
  449. #define NUMBER_IN_ARGS 1
  450. #define IN_ARGS { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" }
  451. #define NUMBER_OUT_ARGS 2
  452. #define OUT_ARGS \
  453.     { GIMP_PDB_INT32, "image_count", "Number of acquired images" }, \
  454.     { GIMP_PDB_INT32ARRAY, "image_ids", "Array of acquired image identifiers" }
  455.  
  456.     
  457. /*
  458.  * query
  459.  *
  460.  * The plug-in is being queried.  Install our procedure for
  461.  * acquiring.
  462.  */
  463. static void 
  464. query(void)
  465. {
  466.   static GimpParamDef args[] = { IN_ARGS };
  467.   static GimpParamDef return_vals[] = { OUT_ARGS };
  468.  
  469.   INIT_I18N ();
  470.  
  471. #ifdef _DEBUG
  472.   if (twain_run_mode == RUN_DUMP)
  473.     /* the installation of the plugin */
  474.     gimp_install_procedure(PLUG_IN_D_NAME,
  475.                PLUG_IN_DESCRIPTION,
  476.                PLUG_IN_HELP,
  477.                PLUG_IN_AUTHOR,
  478.                PLUG_IN_COPYRIGHT,
  479.                PLUG_IN_VERSION,
  480.                PLUG_IN_D_MENU_PATH,
  481.                NULL,
  482.                GIMP_EXTENSION,        
  483.                NUMBER_IN_ARGS,
  484.                NUMBER_OUT_ARGS,
  485.                args,
  486.                return_vals);
  487.  
  488.   else if (twain_run_mode == RUN_READDUMP)
  489.     /* the installation of the plugin */
  490.     gimp_install_procedure(PLUG_IN_R_NAME,
  491.                PLUG_IN_DESCRIPTION,
  492.                PLUG_IN_HELP,
  493.                PLUG_IN_AUTHOR,
  494.                PLUG_IN_COPYRIGHT,
  495.                PLUG_IN_VERSION,
  496.                PLUG_IN_R_MENU_PATH,
  497.                NULL,
  498.                GIMP_EXTENSION,        
  499.                NUMBER_IN_ARGS,
  500.                NUMBER_OUT_ARGS,
  501.                args,
  502.                return_vals);
  503.   else
  504. #endif /* _DEBUG */
  505.     /* the installation of the plugin */
  506.     gimp_install_procedure(PLUG_IN_NAME,
  507.                PLUG_IN_DESCRIPTION,
  508.                PLUG_IN_HELP,
  509.                PLUG_IN_AUTHOR,
  510.                PLUG_IN_COPYRIGHT,
  511.                PLUG_IN_VERSION,
  512.                N_("<Toolbox>/File/Acquire/TWAIN..."),
  513.                NULL,
  514.                GIMP_EXTENSION,        
  515.                NUMBER_IN_ARGS,
  516.                NUMBER_OUT_ARGS,
  517.                args,
  518.                return_vals);
  519. }
  520.     
  521.     
  522. /* Return values storage */
  523. static GimpParam values[3];
  524.  
  525. /*
  526.  * run
  527.  *
  528.  * The plug-in is being requested to run.
  529.  * Capture an image from a TWAIN datasource
  530.  */
  531. static void 
  532. run(gchar *name,        /* name of plugin */
  533.     gint nparams,        /* number of in-paramters */
  534.     GimpParam *param,        /* in-parameters */
  535.     gint *nreturn_vals,            /* number of out-parameters */
  536.     GimpParam **return_vals)    /* out-parameters */
  537. {
  538.   GimpRunModeType run_mode;
  539.  
  540.   /* Initialize the return values
  541.    * Always return at least the status to the caller. 
  542.    */
  543.   values[0].type = GIMP_PDB_STATUS;
  544.   values[0].data.d_status = GIMP_PDB_SUCCESS;
  545.   *nreturn_vals = 1;
  546.   *return_vals = values;
  547.  
  548.   /* Before we get any further, verify that we have
  549.    * TWAIN and that there is actually a datasource
  550.    * to be used in doing the acquire.
  551.    */
  552.   if (!twainIsAvailable()) {
  553.     values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  554.     return;
  555.   }
  556.  
  557.   /* Get the runmode from the in-parameters */
  558.   run_mode = param[0].data.d_int32;
  559.         
  560.   /* Set up the rest of the return parameters */
  561.   values[1].type = GIMP_PDB_INT32;
  562.   values[1].data.d_int32 = 0;
  563.   values[2].type = GIMP_PDB_INT32ARRAY;
  564.   values[2].data.d_int32array = g_new (gint32, MAX_IMAGES);
  565.         
  566.   /* How are we running today? */
  567.   switch (run_mode) {
  568.   case GIMP_RUN_INTERACTIVE:
  569.     /* Retrieve values from the last run...
  570.      * Currently ignored
  571.      */
  572.     gimp_get_data(PLUG_IN_NAME, &twainvals);
  573.     break;
  574.             
  575.   case GIMP_RUN_NONINTERACTIVE:
  576.     /* Currently, we don't do non-interactive calls.
  577.      * Bail if someone tries to call us non-interactively
  578.      */
  579.     values[0].data.d_status = GIMP_PDB_CALLING_ERROR;
  580.     return;
  581.             
  582.   case GIMP_RUN_WITH_LAST_VALS:
  583.     /* Retrieve values from the last run...
  584.      * Currently ignored
  585.      */
  586.     gimp_get_data(PLUG_IN_NAME, &twainvals);
  587.     break;
  588.             
  589.   default:
  590.     break;
  591.   } /* switch */
  592.         
  593.   /* Have we succeeded so far? */
  594.   if (values[0].data.d_status == GIMP_PDB_SUCCESS)
  595.     twainWinMain();
  596.         
  597.   /* Check to make sure we got at least one valid
  598.    * image.
  599.    */
  600.   if (values[1].data.d_int32 > 0) {
  601.     /* An image was captured from the TWAIN
  602.      * datasource.  Do final Interactive
  603.      * steps.
  604.      */
  605.     if (run_mode == GIMP_RUN_INTERACTIVE) {
  606.       /* Store variable states for next run */
  607.       gimp_set_data(PLUG_IN_NAME, &twainvals, sizeof (TwainValues));
  608.     }
  609.             
  610.     /* Set return values */
  611.     *nreturn_vals = 3;
  612.   } else {
  613.     values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
  614.   }
  615. }
  616.     
  617. /***********************************************************************
  618.  * Image transfer callback functions
  619.  ***********************************************************************/
  620.     
  621. /* Data used to carry data between each of
  622.  * the callback function calls.
  623.  */
  624. typedef struct {
  625.   gint32 image_id;
  626.   gint32 layer_id;
  627.   GimpPixelRgn pixel_rgn;
  628.   GimpDrawable *drawable;
  629.   pTW_PALETTE8 paletteData;
  630.   int totalPixels;
  631.   int completedPixels;
  632. } ClientDataStruct, *pClientDataStruct;
  633.  
  634. /*
  635.  * preTransferCallback
  636.  *
  637.  * This callback function is called before any images
  638.  * are transferred.  Set up the one time only stuff.
  639.  */
  640. void
  641. preTransferCallback(void *clientData)
  642. {
  643.   /* Initialize our progress dialog */
  644.   gimp_progress_init(_("Transferring TWAIN data"));
  645. }
  646.  
  647. /*
  648.  * beginTransferCallback
  649.  *
  650.  * The following function is called at the beginning
  651.  * of each image transfer.
  652.  */
  653. int
  654. beginTransferCallback(pTW_IMAGEINFO imageInfo, void *clientData)
  655. {
  656.   int done = 0;
  657.   int imageType, layerType;
  658.  
  659.   pClientDataStruct theClientData = g_new (ClientDataStruct, 1);
  660.  
  661. #ifdef _DEBUG        
  662.   logBegin(imageInfo, clientData);
  663. #endif
  664.         
  665.   /* Decide on the image type */
  666.   switch (imageInfo->PixelType) {
  667.   case TWPT_BW:
  668.   case TWPT_GRAY:
  669.     /* Set up the image and layer types */
  670.     imageType = GIMP_GRAY;
  671.     layerType = GIMP_GRAY_IMAGE;
  672.     break;
  673.             
  674.   case TWPT_RGB:
  675.     /* Set up the image and layer types */
  676.     imageType = GIMP_RGB;
  677.     layerType = GIMP_RGB_IMAGE;
  678.     break;
  679.  
  680.   case TWPT_PALETTE:
  681.     /* Get the palette data */
  682.     theClientData->paletteData = g_new (TW_PALETTE8, 1);
  683.     twSession->twRC = callDSM(APP_IDENTITY(twSession), DS_IDENTITY(twSession),
  684.                   DG_IMAGE, DAT_PALETTE8, MSG_GET,
  685.                   (TW_MEMREF) theClientData->paletteData);
  686.     if (twSession->twRC != TWRC_SUCCESS)
  687.       return FALSE;
  688.  
  689.     switch (theClientData->paletteData->PaletteType) {
  690.     case TWPA_RGB:
  691.       /* Set up the image and layer types */
  692.       imageType = GIMP_RGB;
  693.       layerType = GIMP_RGB_IMAGE;
  694.       break;
  695.  
  696.     case TWPA_GRAY:
  697.       /* Set up the image and layer types */
  698.       imageType = GIMP_GRAY;
  699.       layerType = GIMP_GRAY_IMAGE;
  700.       break;
  701.  
  702.     default:
  703.       return FALSE;
  704.     }
  705.     break;
  706.  
  707.   default:
  708.     /* We don't know how to deal with anything other than
  709.      * the types listed above.  Bail for any other image
  710.      * type.
  711.      */
  712.     return FALSE;
  713.   }
  714.         
  715.   /* Create the GIMP image */
  716.   theClientData->image_id = gimp_image_new(imageInfo->ImageWidth, 
  717.                        imageInfo->ImageLength, imageType);
  718.             
  719.   /* Create a layer */
  720.   theClientData->layer_id = gimp_layer_new(theClientData->image_id,
  721.                        _("Background"),
  722.                        imageInfo->ImageWidth, 
  723.                        imageInfo->ImageLength,
  724.                        layerType, 100, GIMP_NORMAL_MODE);
  725.         
  726.   /* Add the layer to the image */
  727.   gimp_image_add_layer(theClientData->image_id, 
  728.                theClientData->layer_id, 0);
  729.         
  730.   /* Update the progress dialog */
  731.   theClientData->totalPixels = imageInfo->ImageWidth * imageInfo->ImageLength;
  732.   theClientData->completedPixels = 0;
  733.   gimp_progress_update((double) 0);
  734.         
  735.   /* Get our drawable */
  736.   theClientData->drawable = gimp_drawable_get(theClientData->layer_id);
  737.         
  738.   /* Initialize a pixel region for writing to the image */
  739.   gimp_pixel_rgn_init(&(theClientData->pixel_rgn), theClientData->drawable, 
  740.               0, 0, imageInfo->ImageWidth, imageInfo->ImageLength,
  741.               TRUE, FALSE);
  742.         
  743.   /* Store our client data for the data transfer callbacks */
  744.   if (clientData)
  745.     g_free (clientData);
  746.   setClientData(twSession, (void *) theClientData);
  747.         
  748.   /* Make sure to return TRUE to continue the image
  749.    * transfer
  750.    */
  751.   return TRUE;
  752. }
  753.     
  754. /*
  755.  * bitTransferCallback
  756.  *
  757.  * The following function is called for each memory
  758.  * block that is transferred from the data source if
  759.  * the image type is Black/White.
  760.  *
  761.  * Black and white data is unpacked from bit data
  762.  * into byte data and written into a gray scale GIMP
  763.  * image.
  764.  */
  765. static char bitMasks[] = { 128, 64, 32, 16, 8, 4, 2, 1 };
  766. static int 
  767. bitTransferCallback(pTW_IMAGEINFO imageInfo,
  768.             pTW_IMAGEMEMXFER imageMemXfer,
  769.             void *clientData)
  770. {
  771.   int row, col, offset;
  772.   char *srcBuf;
  773.   int rows = imageMemXfer->Rows;
  774.   int cols = imageMemXfer->Columns;
  775.   pClientDataStruct theClientData = (pClientDataStruct) clientData;
  776.         
  777.   /* Allocate a buffer as necessary */
  778.   if (!destBuf)
  779.     destBuf = g_new (char, rows * cols);
  780.         
  781.   /* Unpack the image data from bits into bytes */
  782.   srcBuf = (char *) imageMemXfer->Memory.TheMem;
  783.   offset = 0;
  784.   for (row = 0; row < rows; row++) {
  785.     for (col = 0; col < cols; col++) {
  786.       char byte = srcBuf[(row * imageMemXfer->BytesPerRow) + (col / 8)];
  787.       destBuf[offset++] = ((byte & bitMasks[col % 8]) != 0) ? 255 : 0;
  788.     }
  789.   }
  790.         
  791.   /* Update the complete chunk */
  792.   gimp_pixel_rgn_set_rect(&(theClientData->pixel_rgn), 
  793.               (guchar *) destBuf,
  794.               imageMemXfer->XOffset, imageMemXfer->YOffset,
  795.               cols, rows);
  796.         
  797.   /* Update the user on our progress */
  798.   theClientData->completedPixels += (cols * rows);
  799.   gimp_progress_update((double) theClientData->completedPixels / 
  800.                (double) theClientData->totalPixels);
  801.         
  802.   return TRUE;
  803. }
  804.     
  805. /*
  806.  * oneBytePerSampleTransferCallback
  807.  *
  808.  * The following function is called for each memory
  809.  * block that is transferred from the data source if
  810.  * the image type is Grayscale or RGB.  This transfer
  811.  * mode is quicker than the modes that require translation
  812.  * from a greater number of bits per sample down to the
  813.  * 8 bits per sample understood by The GIMP.
  814.  */
  815. static int 
  816. oneBytePerSampleTransferCallback(pTW_IMAGEINFO imageInfo,
  817.              pTW_IMAGEMEMXFER imageMemXfer,
  818.              void *clientData)
  819. {
  820.   int row;
  821.   char *srcBuf;
  822.   int bytesPerPixel = imageInfo->BitsPerPixel / 8;
  823.   int rows = imageMemXfer->Rows;
  824.   int cols = imageMemXfer->Columns;
  825.   pClientDataStruct theClientData = (pClientDataStruct) clientData;
  826.         
  827.   /* Allocate a buffer as necessary */
  828.   if (!destBuf)
  829.     destBuf = g_new (char, rows * cols * bytesPerPixel);
  830.         
  831.   /* The bytes coming from the source may not be padded in
  832.    * a way that The GIMP is terribly happy with.  It is
  833.    * possible to transfer row by row, but that is particularly
  834.    * expensive in terms of performance.  It is much cheaper
  835.    * to rearrange the data and transfer it in one large chunk.
  836.    * The next chunk of code rearranges the incoming data into
  837.    * a non-padded chunk for The GIMP.
  838.    */
  839.   srcBuf = (char *) imageMemXfer->Memory.TheMem;
  840.   for (row = 0; row < rows; row++) {
  841.     /* Copy the current row */
  842.     memcpy((destBuf + (row * bytesPerPixel * cols)),
  843.        (srcBuf + (row * imageMemXfer->BytesPerRow)),
  844.        (bytesPerPixel * cols));
  845.   }
  846.         
  847.   /* Update the complete chunk */
  848.   gimp_pixel_rgn_set_rect(&(theClientData->pixel_rgn), 
  849.               (guchar *) destBuf,
  850.               imageMemXfer->XOffset, imageMemXfer->YOffset,
  851.               cols, rows);
  852.         
  853.   /* Update the user on our progress */
  854.   theClientData->completedPixels += (cols * rows);
  855.   gimp_progress_update((double) theClientData->completedPixels / 
  856.                (double) theClientData->totalPixels);
  857.         
  858.   return TRUE;
  859. }
  860.     
  861. /*
  862.  * twoBytesPerSampleTransferCallback
  863.  *
  864.  * The following function is called for each memory
  865.  * block that is transferred from the data source if
  866.  * the image type is Grayscale or RGB.
  867.  */ 
  868. static int 
  869. twoBytesPerSampleTransferCallback(pTW_IMAGEINFO imageInfo,
  870.              pTW_IMAGEMEMXFER imageMemXfer,
  871.              void *clientData)
  872. {
  873.   static float ratio = 0.00390625;
  874.   int row, col, sample;
  875.   char *srcBuf, *destByte;
  876.   int rows = imageMemXfer->Rows;
  877.   int cols = imageMemXfer->Columns;
  878.   int bitsPerSample = imageInfo->BitsPerPixel / imageInfo->SamplesPerPixel;
  879.   int bytesPerSample = bitsPerSample / 8;
  880.  
  881.   TW_UINT16 *samplePtr;
  882.  
  883.   pClientDataStruct theClientData = (pClientDataStruct) clientData;
  884.         
  885.   /* Allocate a buffer as necessary */
  886.   if (!destBuf)
  887.     destBuf = g_new (char, rows * cols * imageInfo->SamplesPerPixel);
  888.         
  889.   /* The bytes coming from the source may not be padded in
  890.    * a way that The GIMP is terribly happy with.  It is
  891.    * possible to transfer row by row, but that is particularly
  892.    * expensive in terms of performance.  It is much cheaper
  893.    * to rearrange the data and transfer it in one large chunk.
  894.    * The next chunk of code rearranges the incoming data into
  895.    * a non-padded chunk for The GIMP.  This function must also
  896.    * reduce from multiple bytes per sample down to single byte
  897.    * per sample.
  898.    */
  899.   /* Work through the rows */
  900.   for (row = 0; row < rows; row++) {
  901.     /* The start of this source row */
  902.     samplePtr = (TW_UINT16 *) 
  903.       ((char *) imageMemXfer->Memory.TheMem + (row * imageMemXfer->BytesPerRow));
  904.  
  905.     /* The start of this dest row */
  906.     destByte = destBuf + (row * imageInfo->SamplesPerPixel * cols);
  907.  
  908.     /* Work through the columns */
  909.     for (col = 0; col < cols; col++) {
  910.       /* Finally, work through each of the samples */
  911.       for (sample = 0; sample < imageInfo->SamplesPerPixel; sample++) {
  912.                 /* Get the value */
  913.     TW_UINT16 value = *samplePtr;
  914.  
  915.                 /* Move the sample pointer */
  916.     samplePtr++;
  917.  
  918.                 /* Place in the destination */
  919.     *destByte = (char) ((float) value * (float) ratio);
  920.     destByte++;
  921.       }
  922.     }
  923.   }
  924.         
  925.   /* Send the complete chunk */
  926.   gimp_pixel_rgn_set_rect(&(theClientData->pixel_rgn), 
  927.               (guchar *) destBuf,
  928.               imageMemXfer->XOffset, imageMemXfer->YOffset,
  929.               cols, rows);
  930.         
  931.   /* Update the user on our progress */
  932.   theClientData->completedPixels += (cols * rows);
  933.   gimp_progress_update((double) theClientData->completedPixels / 
  934.                (double) theClientData->totalPixels);
  935.         
  936.   return TRUE;
  937. }
  938.     
  939. /*
  940.  * palettedTransferCallback
  941.  *
  942.  * The following function is called for each memory
  943.  * block that is transferred from the data source if
  944.  * the image type is paletted.  This does not create
  945.  * an indexed image type in The GIMP because for some
  946.  * reason it does not allow creation of a specific
  947.  * palette.  This function will create an RGB or Gray
  948.  * image and use the palette to set the details of
  949.  * the pixels.
  950.  */ 
  951. static int 
  952. palettedTransferCallback(pTW_IMAGEINFO imageInfo,
  953.              pTW_IMAGEMEMXFER imageMemXfer,
  954.              void *clientData)
  955. {
  956.   int channelsPerEntry;
  957.   int row, col;
  958.   int rows = imageMemXfer->Rows;
  959.   int cols = imageMemXfer->Columns;
  960.   char *destPtr = NULL, *srcPtr = NULL;
  961.  
  962.   /* Get the client data */
  963.   pClientDataStruct theClientData = (pClientDataStruct) clientData;
  964.         
  965.   /* Look up the palette entry size */
  966.   channelsPerEntry = 
  967.     (theClientData->paletteData->PaletteType == TWPA_RGB) ? 3 : 1;
  968.  
  969.   /* Allocate a buffer as necessary */
  970.   if (!destBuf)
  971.     destBuf = g_new (char, rows * cols * channelsPerEntry);
  972.  
  973.   /* Work through the rows */
  974.   destPtr = destBuf;
  975.   for (row = 0; row < rows; row++) {
  976.     srcPtr = (char *) ((char *) imageMemXfer->Memory.TheMem + 
  977.                (row * imageMemXfer->BytesPerRow));
  978.  
  979.     /* Work through the columns */
  980.     for (col = 0; col < cols; col++) {
  981.       /* Get the palette index */
  982.       int index = (unsigned char) *srcPtr;
  983.       srcPtr++;
  984.  
  985.       switch (theClientData->paletteData->PaletteType) {
  986.       case TWPA_GRAY:
  987.     *destPtr = theClientData->paletteData->Colors[index].Channel1;
  988.     destPtr++;
  989.     break;
  990.  
  991.       case TWPA_RGB:
  992.     *destPtr = theClientData->paletteData->Colors[index].Channel1;
  993.     destPtr++;
  994.     *destPtr = theClientData->paletteData->Colors[index].Channel2;
  995.     destPtr++;
  996.     *destPtr = theClientData->paletteData->Colors[index].Channel3;
  997.     destPtr++;
  998.       }
  999.     }
  1000.   }
  1001.         
  1002.   /* Send the complete chunk */
  1003.   gimp_pixel_rgn_set_rect(&(theClientData->pixel_rgn), 
  1004.               (guchar *) destBuf,
  1005.               imageMemXfer->XOffset, imageMemXfer->YOffset,
  1006.               cols, rows);
  1007.         
  1008.   /* Update the user on our progress */
  1009.   theClientData->completedPixels += (cols * rows);
  1010.   gimp_progress_update((double) theClientData->completedPixels / 
  1011.                (double) theClientData->totalPixels);
  1012.         
  1013.   return TRUE;
  1014. }
  1015.     
  1016. /*
  1017.  * dataTransferCallback
  1018.  *
  1019.  * The following function is called for each memory
  1020.  * block that is transferred from the data source.
  1021.  */
  1022. int 
  1023. dataTransferCallback(pTW_IMAGEINFO imageInfo,
  1024.              pTW_IMAGEMEMXFER imageMemXfer,
  1025.              void *clientData)
  1026. {
  1027. #ifdef _DEBUG
  1028.   logData(imageInfo, imageMemXfer, clientData);
  1029. #endif
  1030.         
  1031.   /* Choose the appropriate transfer handler */
  1032.   switch (imageInfo->PixelType) {
  1033.   case TWPT_PALETTE:
  1034.     return palettedTransferCallback(imageInfo, imageMemXfer, clientData);
  1035.  
  1036.   case TWPT_BW:
  1037.     return bitTransferCallback(imageInfo, imageMemXfer, clientData);
  1038.             
  1039.   case TWPT_GRAY:
  1040.   case TWPT_RGB:
  1041.     switch (imageInfo->BitsPerPixel / imageInfo->SamplesPerPixel) {
  1042.     case 8:
  1043.       return oneBytePerSampleTransferCallback(imageInfo, imageMemXfer, clientData);
  1044.                 
  1045.     case 16:
  1046.       return twoBytesPerSampleTransferCallback(imageInfo, imageMemXfer, clientData);
  1047.  
  1048.     default:
  1049.       return FALSE;
  1050.     }
  1051.             
  1052.   default:
  1053.     return FALSE;
  1054.   }
  1055. }
  1056.     
  1057. /*
  1058.  * endTransferCallback
  1059.  *
  1060.  * The following function is called at the end of the
  1061.  * image transfer.  The caller will be handed
  1062.  * the image transfer completion state.  The
  1063.  * following values (defined in twain.h) are
  1064.  * possible:
  1065.  *
  1066.  * TWRC_XFERDONE
  1067.  *  The transfer completed successfully
  1068.  * TWRC_CANCEL
  1069.  *  The transfer was completed by the user
  1070.  * TWRC_FAILURE
  1071.  *  The transfer failed.
  1072.  */
  1073. int
  1074. endTransferCallback(int completionState, int pendingCount, void *clientData)
  1075. {
  1076.   pClientDataStruct theClientData = (pClientDataStruct) clientData;
  1077.         
  1078.   LogMessage("endTransferCallback: CompState = %d, pending = %d\n",
  1079.          completionState, pendingCount);
  1080.  
  1081.   /* Clean up and detach from the drawable */
  1082.   if (destBuf) {
  1083.     g_free (destBuf);
  1084.     destBuf = NULL;
  1085.   }
  1086.   gimp_drawable_flush(theClientData->drawable);
  1087.   gimp_drawable_detach(theClientData->drawable);
  1088.  
  1089.   /* Make sure to check our return code */
  1090.   if (completionState == TWRC_XFERDONE) {
  1091.     /* We have a completed image transfer */
  1092.     values[2].type = GIMP_PDB_INT32ARRAY;    
  1093.     values[2].data.d_int32array[values[1].data.d_int32++] =
  1094.       theClientData->image_id;
  1095.                 
  1096.     /* Display the image */
  1097.     LogMessage("Displaying image %d\n", theClientData->image_id);
  1098.     gimp_display_new (theClientData->image_id);
  1099.   } else {
  1100.     /* The transfer did not complete successfully */
  1101.     LogMessage("Deleting image\n");
  1102.     gimp_image_delete(theClientData->image_id);
  1103.   }
  1104.         
  1105.   /* Shut down if we have received all of the possible images */
  1106.   return (values[1].data.d_int32 < MAX_IMAGES);
  1107. }
  1108.  
  1109. /*
  1110.  * postTransferCallback
  1111.  *
  1112.  * This callback function will be called
  1113.  * after all possible images have been
  1114.  * transferred.
  1115.  */
  1116. void
  1117. postTransferCallback(int pendingCount, void *clientData)
  1118. {
  1119.   /* Shut things down. */
  1120.   if (pendingCount != 0)
  1121.     cancelPendingTransfers(twSession);
  1122.  
  1123.   /* This will close the datasource and datasource
  1124.    * manager.  Then the message queue will be shut
  1125.    * down and the run() procedure will finally be
  1126.    * able to finish.
  1127.    */
  1128.   disableDS(twSession);
  1129.   closeDS(twSession);
  1130.   closeDSM(twSession);
  1131.         
  1132.   /* Post a message to close up the application */
  1133.   PostQuitMessage(0);
  1134. }
  1135.