home *** CD-ROM | disk | FTP | other *** search
/ MACD 9 / MACD9.iso / Skanery / BetaScan / ScannerDev / ScanMakerE3.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-06  |  18.9 KB  |  721 lines

  1. //*********************************************************************
  2. //
  3. //                 ScanmakerE3 Scanner device
  4. //
  5. //                    version 98.06.01
  6. //
  7. //*********************************************************************
  8.  
  9. #include <stdlib.h>
  10. #include <stdio.h>
  11. #include <signal.h>
  12. #include <string.h>
  13. #include <math.h>
  14.  
  15. #include <exec/types.h>
  16. #include <proto/exec.h>
  17. #include <proto/dos.h>
  18.  
  19. #include "scsi.h"
  20. #include "Scanner.h"
  21. #include "Scanner_protos.h"
  22.  
  23. //
  24. //  NOTE!!!
  25. //
  26. //  The name in the following two lines (here: ScanmakerE3)
  27. //  must be the same as the name of the device.
  28. //
  29. //  Do not change the string names (DevName and DevIdName)
  30. //
  31. char DevName[] = "ScanmakerE3.device";
  32. char DevIdString[] = "ScanmakerE3";
  33.  
  34. typedef unsigned char SCSICmd[6];
  35.  
  36. // Scanner specifik defines
  37. #define MAX_BASE_RES      300
  38. #define MAX_EXT_RES       300
  39.  
  40. // scanning modes
  41. #define SCANMODE_HALFTONE   0
  42. #define SCANMODE_BW         1 
  43. #define SCANMODE_GREY       2
  44. #define SCANMODE_COLOR      3
  45.  
  46.  
  47. #define SCANBUFSIZE     32000
  48.  
  49. #define MAX_BUSY_RETRY      5
  50.  
  51.  
  52. static UBYTE* scanBuffer = NULL;
  53.  
  54. // Stored scanning parameters
  55. //
  56. static double x0;             /* Scanning frame in mm               */
  57. static double y0;
  58. static double x1;
  59. static double y1;
  60. static UBYTE  resolutionCode; /* Resolution in % of max resolution  */
  61. static UBYTE  resolutionFlag; /* Further resolution information     */
  62. static WORD   brightness[3];  /* Brightness for red, green and blue */
  63. static WORD   contrast;       /* Contrast                           */
  64. static WORD   shadow;         /* shadow adjust 0..1023 (default 0)  */
  65. static WORD   highlight;      /* highlight adjust 0..1023 (def. 0)  */
  66. static WORD   midtone;        /* midtone adjust 0..1023 (def. 512)  */
  67. static WORD   halftonePattern;/* halftonePattern 0..255 (def. 0)    */
  68. static WORD   exposureTime;   /* Exposure time                      */
  69. static double gamma;          /* gamma value                        */
  70. static WORD   scanMode;       /* see above                          */
  71. static BOOL   extendedRes;    /* extended resolution                */
  72. static BOOL   parametersSet;  /* parameters are set                 */
  73.  
  74. // Actual scanning values
  75. //
  76. static UWORD imageWidth;
  77. static UWORD imageHeight;
  78. static UWORD bytesPerLine;
  79. static UWORD xResolution;
  80. static UWORD yResolution;
  81.  
  82. // Parameters used during scanning
  83. //
  84. static BOOL scanning;    /* Scanner is scanning                                */
  85. static int  lineWidth;   /* Length of one scan line including color informat.  */
  86. static int  scanLines;   /* Total number of lines to read from scanner         */
  87. static int  numPlanes;   /* 3 for rgb24, otherwise 1                           */
  88. static int  bufferLen;   /* Length of scanBuffer in number of lines            */
  89. static int  linesRead;   /* Lines already read from scanner                    */
  90. static int  linesInBuf;  /* Number of lines read from scanner in scanBuffer    */
  91. static int  currentLine; /* Next line from scanBuf to return to user           */
  92. static int  nextPlane;   /* next plane number to return to readScanLine        */
  93.  
  94. //
  95. // Make color correction table for brightness and contrast
  96. //
  97.  
  98. UBYTE corrTab[256];
  99.  
  100. void makeCorrTab(int bright,int contrast)
  101. {
  102.   int    i,b,c;
  103.   UBYTE* tab;
  104.  
  105.   tab = corrTab;
  106.   bright = (bright*255)/100;
  107.   c = 100+contrast;
  108.   for( i = 0 ; i < 256 ; i++ )
  109.   {
  110.     b = ((i+bright)*c-50*contrast)/100;
  111.     *(tab++) = b>255?255:(b<0?0:(UBYTE)b);
  112.   }
  113. }
  114.  
  115. static BYTE senseError(void)
  116. {
  117.   BYTE error;
  118.   
  119.   switch( scsi_sensebuffer[0] )
  120.   {
  121.     case 0x00:  // ????
  122.       error = SCAN_ERR_READY;
  123.       break;
  124.     case 0x81:  // Comand or data error
  125.     case 0x83:  // Operation error (illegal parameter values)
  126.       error = SCAN_ERR_PARAMETER;
  127.       break;
  128.     case 0x82:  // Hardware error
  129.       error = SCAN_ERR_HARDWARE;
  130.       break;
  131.     default:    // Other communication error
  132.       error = SCAN_ERR_COMMUNICATION;
  133.       break;
  134.   }
  135.   return error;
  136. }
  137.  
  138. /*------------------------------------------------------------------------*/
  139. static void scannerReady(BYTE *error)
  140. {
  141.   if( *error == 0 )
  142.   {
  143.     SCSICmd TEST_UNIT_READY = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  144.     int retry = 0;
  145.  
  146.     while( !writeSCSI(TEST_UNIT_READY, 6, NULL, 0, NULL, 0) )
  147.     {
  148.       retry++;
  149.       if (retry == 5)
  150.       {
  151.         *error = SCAN_ERR_READY;
  152.         return;
  153.       }
  154.       Delay(3*50);
  155.     }
  156.   }
  157. }
  158.  
  159.  
  160. /*------------------------------------------------------------------------*/
  161. static void setScanningFrame(BYTE *error)
  162. {
  163.   if( *error == 0 )
  164.   {
  165.     SCSICmd SCANNING_FRAME = { 0x04, 0x00, 0x00, 0x00, 0x09, 0x00 };
  166.     UBYTE   frame_data[9];
  167.  
  168.     int xf0,yf0,xf1,yf1;
  169.     int dpi;
  170.     
  171.     frame_data[0] = 0x00;
  172.     if( scanMode == SCANMODE_HALFTONE )
  173.       frame_data[0] |= 0x01;
  174.  
  175.     // Unit is pixel
  176.     //
  177.     frame_data[0] |= 0x08;
  178.  
  179.     dpi = MAX_BASE_RES;
  180.     xf0 = (int)((double)(x0*dpi)/25.4);
  181.     yf0 = (int)((double)(y0*dpi)/25.4);
  182.     xf1 = (int)((double)(x1*dpi)/25.4);
  183.     yf1 = (int)((double)(y1*dpi)/25.4);
  184.     
  185.     frame_data[1] = (UBYTE)(xf0 & 0xff);
  186.     frame_data[2] = (UBYTE)((xf0 & 0xff00) >> 8);
  187.     frame_data[3] = (UBYTE)(yf0 & 0xff);
  188.     frame_data[4] = (UBYTE)((yf0 & 0xff00) >> 8);
  189.     frame_data[5] = (UBYTE)(xf1 & 0xff);
  190.     frame_data[6] = (UBYTE)((xf1 & 0xff00) >> 8);
  191.     frame_data[7] = (UBYTE)(yf1 & 0xff);
  192.     frame_data[8] = (UBYTE)((yf1 & 0xff00) >> 8);
  193.  
  194.     if( !writeSCSI(SCANNING_FRAME, 6, frame_data, 9, NULL, 0) )
  195.       *error = senseError();
  196.   }
  197. }
  198.  
  199.  
  200. /*------------------------------------------------------------------------*/
  201. static void selectMode(BYTE *error)
  202. {
  203.   if( *error == 0 )
  204.   {
  205.     SCSICmd MODE_SELECT = { 0x15, 0x00, 0x00, 0x00, 0x0B, 0x00 };
  206.     UBYTE mode_data[11];
  207.  
  208.     mode_data[0] = 0x81;
  209.     
  210.     // Set resolution
  211.     mode_data[0] |= 0x02;
  212.     mode_data[1] = resolutionCode;
  213.     mode_data[2] = (exposureTime/3)+7;
  214.     mode_data[3] = (contrast+49)/7;
  215.     mode_data[4] = halftonePattern;
  216.     mode_data[5] = 0x01;
  217.     mode_data[6] = shadow;
  218.     mode_data[7] = highlight;
  219.     mode_data[8] = 0x6C;
  220.     mode_data[9] = 0x00;
  221.     mode_data[10] = midtone;
  222.         
  223.     if( !writeSCSI(MODE_SELECT, 6, mode_data, 11, NULL, 0) )
  224.       *error = senseError();
  225.   }
  226. }
  227.  
  228. /*------------------------------------------------------------------------*/
  229. void mode_sense_1(BYTE *error)
  230. {
  231.  
  232.   if( *error == 0 )
  233.   {
  234.     SCSICmd MODE_SELECT_1 = { 0x16, 0x00, 0x00, 0x00, 0x0a, 0x00 };
  235.     unsigned char mode_data[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  236.  
  237.     mode_data[1] = (UBYTE)(brightness[0]);
  238.  
  239.     if( !writeSCSI(MODE_SELECT_1, 6, mode_data, 10, NULL, 0) )
  240.       *error = senseError();  
  241.   }
  242.   if( *error == 0 )
  243.   {
  244.     SCSICmd MODE_SENSE_1 = { 0x19, 0x00, 0x00, 0x00, 0x1e, 0x00 };
  245.     unsigned char mode_data[30] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  246.                                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  247.                                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  248.  
  249.     mode_data[1] = (UBYTE)(brightness[0]);
  250.     mode_data[2] = (UBYTE)(brightness[1]);
  251.     mode_data[3] = (UBYTE)(brightness[2]);
  252.     if( !writeSCSI(MODE_SENSE_1, 6, mode_data, 30, NULL, 0) )
  253.       *error = senseError();
  254.   }
  255. }
  256.  
  257. /*------------------------------------------------------------------------*/
  258. /* int lut_download (char filter, char *gtable, int gt_entries)           */
  259. /* Issue the LOOK-UP-TABLE DOWNLOAD command to the scanner to download    */
  260. /* the gamma table pointed to by <gtable>. <filter> determines the color  */
  261. /* to which the table applies (RED, GREEN, BLUE, or CLEAR; values other   */
  262. /* than CLEAR may only be specified for one-pass color scanners). The     */
  263. /* number of entries is determined by <entries> (256, 1024, 4096 or       */
  264. /* 65536). The entry width is automatically assumed to be one byte if the */
  265. /* number of entries is 256 and two bytes otherwise.                      */
  266. /*------------------------------------------------------------------------*/
  267.  
  268. void gammaTable(double g, BYTE *error)
  269. {
  270.   if( *error == 0 )
  271.   {
  272.     UBYTE LUT_DOWNLOAD[10] = {0x55,0x00,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
  273.     UBYTE gTable[256];
  274.     int i;
  275.  
  276.     LUT_DOWNLOAD[7] = (UBYTE)((256 & 0xff00) >> 8);
  277.     LUT_DOWNLOAD[8] = (UBYTE)(256 & 0xff);
  278.  
  279.     if( (g <= 0.0) || (g == 1.0) )
  280.     {
  281.       for( i = 0 ; i < 256 ; i++ )
  282.         gTable[i] = (UBYTE)i;
  283.     }
  284.     else
  285.     {
  286.       for( i = 0 ; i < 256 ; i++ )
  287.         gTable[i] = (UBYTE)(256.0*pow(((double)i)/256.0,1/g));
  288.     }
  289.  
  290.     if( !writeSCSI(LUT_DOWNLOAD,10,gTable,256,NULL,0) )
  291.       *error = senseError();
  292.   }
  293. }
  294.  
  295. /*------------------------------------------------------------------------*/
  296. static void accessory(BYTE *error)
  297. {
  298.   if( *error == 0 )
  299.   {
  300.     SCSICmd ACCESSORY = { 0x10, 0x00, 0x00, 0x00, 0x9A, 0x00 };
  301.  
  302.     if( !writeSCSI(ACCESSORY, 6, NULL, 0, NULL, 0) )
  303.       *error = senseError();
  304.   }
  305. }
  306.  
  307. /*------------------------------------------------------------------------*/
  308. static void startScan(BYTE *error)
  309. {
  310.   if( *error == 0 )
  311.   {
  312.     SCSICmd START_SCAN = { 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00 };
  313.  
  314.     switch( scanMode )
  315.     {
  316.       case SCANMODE_HALFTONE:
  317.       case SCANMODE_BW:
  318.         break;
  319.       case SCANMODE_COLOR:
  320.         START_SCAN[4] |= 0x20;  // 1-pass color
  321.       case SCANMODE_GREY:
  322.         START_SCAN[4] |= 0x40;  // Multibit
  323.         break;
  324.     }
  325.     if( extendedRes )
  326.         START_SCAN[4] |= 0x80;  // extended resolution
  327.  
  328.     if( !writeSCSI(START_SCAN, 6, NULL, 0, NULL, 0) )
  329.       *error = senseError();
  330.   }
  331. }
  332.  
  333.  
  334. /*------------------------------------------------------------------------*/
  335. static void stopScan(BYTE *error)
  336. {
  337.   if( *error == 0 )
  338.   {
  339.     SCSICmd STOP_SCAN = { 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00 };
  340.  
  341.     if( !writeSCSI(STOP_SCAN, 6, NULL, 0, NULL, 0) )
  342.       *error = senseError();
  343.   }
  344. }
  345.  
  346. /*------------------------------------------------------------------------*/
  347. static void readScanStatus(int *busy, int *lineWidth, int *linesRemain,BYTE *error)
  348. {
  349.   if( *error == 0 )
  350.   {
  351.     SCSICmd GET_SCAN_STATUS = { 0x0f, 0x00, 0x00, 0x00, 0x06, 0x00 };
  352.     UBYTE status_reply[6];
  353.     int retry = 0;
  354.  
  355.     do
  356.     {
  357.       if( !writeSCSI(GET_SCAN_STATUS,6,NULL,0,status_reply,6) )
  358.       {
  359.         *error = senseError();
  360.         return;
  361.       }
  362.       *busy        = (int)(status_reply[0] != 0);
  363.       *lineWidth   = (int)(status_reply[1] + 256 * status_reply[2]);
  364.       *linesRemain = (int)(status_reply[3]+256*status_reply[4]+256*256*status_reply[5]);
  365.       if( *busy )
  366.       {
  367.         retry++;
  368.         Delay(3*50);
  369.       }
  370.     }
  371.     while( (*busy) && (retry < MAX_BUSY_RETRY) );
  372.     if( *busy )
  373.       *error = SCAN_ERR_READY;
  374.   }
  375. }
  376.  
  377.  
  378. /*----------------------------------------------------------------------*/
  379. /*                                                                      */
  380. /* Read lines from scanner                                              */
  381. /*                                                                      */
  382. /* The number of lines to read must be specified. For color scanning    */
  383. /* the length of one line is three times line width although the lines  */
  384. /* returned is not in correct sequence (r-g-b).                         */
  385. /*                                                                      */
  386. /*----------------------------------------------------------------------*/
  387.  
  388. static void readScanData(int nlines,UBYTE *buffer,int bsize,BYTE *error)
  389. {
  390.   if( *error == 0 )
  391.   {
  392.     SCSICmd READ_SCANNED_DATA = { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 };
  393.  
  394.     READ_SCANNED_DATA[2] = (UBYTE)((nlines & 0xff0000) >> 16);
  395.     READ_SCANNED_DATA[3] = (UBYTE)((nlines & 0xff00) >> 8);
  396.     READ_SCANNED_DATA[4] = (UBYTE)(nlines & 0xff);
  397.     if( !writeSCSI(READ_SCANNED_DATA,6,NULL,0,buffer,bsize) )
  398.       *error = senseError();
  399.   }
  400. }
  401.  
  402.  
  403. // 
  404. //
  405. void closeScanner(void)
  406. {
  407.   if( scanBuffer )
  408.   {
  409.     free(scanBuffer);
  410.     scanBuffer = NULL;
  411.   }
  412.   closeSCSI();
  413. }
  414.  
  415.  
  416. void openScanner(char* name,int unit,struct ScannerOptions* option,BYTE* status)
  417. {
  418.   scanning = FALSE;
  419.   scanLines = 0;
  420.   linesRead = 0;
  421.   
  422.   if( openSCSI(name,unit) )
  423.   {
  424.     if( scanBuffer = (UBYTE*)malloc(SCANBUFSIZE) )
  425.     {
  426.       strcpy(option->so_vendor,"Microtek");
  427.       strcpy(option->so_model,"Scanmaker E3");
  428.       option->so_version = 4;
  429.       option->so_revision = 4;
  430.         
  431.       option->so_colorMode  = COLORNUM_HALFTONE|COLORNUM_BW|COLORNUM_GREY8|COLORNUM_RGB24;
  432.       option->so_opticResolution = MAX_BASE_RES;
  433.       option->so_opticResStep = MAX_BASE_RES/100;
  434.       option->so_interResolution = MAX_EXT_RES;
  435.       option->so_interResStep = MAX_EXT_RES/100;
  436.   
  437.       option->so_brightnessMin = 0;   //-100;
  438.       option->so_brightnessMax = 100;
  439.       option->so_brightnessStep = 1;
  440.       option->so_brightnessDefault = 0;
  441.   
  442.       option->so_contrastMin = -50; //-42;
  443.       option->so_contrastMax = 50;  //49;
  444.       option->so_contrastStep = 1;  //7;
  445.       option->so_contrastDefault = 0;
  446.   
  447.       // These three do not work well with Phantom 4800
  448.  
  449.       //option->so_shadowMin = 0;
  450.       //option->so_shadowMax = 255;
  451.       //option->so_shadowStep = 1;
  452.       //option->so_shadowDefault = 0;
  453.   
  454.       //option->so_highlightMin = 0;
  455.       //option->so_highlightMax = 255;
  456.       //option->so_highlightStep = 1;
  457.       //option->so_highlightDefault = 255;
  458.   
  459.       //option->so_midtoneMin = 0;
  460.       //option->so_midtoneMax = 255;
  461.       //option->so_midtoneStep = 1;
  462.       //option->so_midtoneDefault = 128;
  463.   
  464.       option->so_exposureTimeMin = -18;
  465.       option->so_exposureTimeMax = 21;
  466.       option->so_exposureTimeStep = 3;
  467.       option->so_exposureTimeDefault = 0;
  468.   
  469.       option->so_velocityMin = 1;
  470.       option->so_velocityMax = 7;
  471.       option->so_velocityStep = 1;
  472.       option->so_velocityDefault = 1;
  473.  
  474.       option->so_halftonePatternMin = 0;
  475.       option->so_halftonePatternMax = 11;
  476.       option->so_halftonePatternStep = 1;
  477.       option->so_halftonePatternDefault = 0;
  478.   
  479.       option->so_maxLookupTableSize = 256;
  480.       option->so_docWidth = 215.9;
  481.       option->so_docLength = 296.9;
  482.       
  483.       *status = 0;
  484.     }
  485.     else
  486.     {
  487.       closeScanner();
  488.       *status = SCAN_ERR_MEMORY;
  489.     }
  490.   }
  491.   else
  492.     *status = SCAN_ERR_DEVICEOPEN;
  493. }
  494.  
  495. void setParameter(struct ScanParameters* param,BYTE* status)
  496. {
  497.   switch( param->sp_ColorNum )
  498.   {
  499.     case COLORNUM_HALFTONE:
  500.       scanMode = SCANMODE_HALFTONE;
  501.       break;
  502.     case COLORNUM_BW:
  503.       scanMode = SCANMODE_BW;
  504.       break;
  505.     case COLORNUM_GREY8:
  506.       scanMode = SCANMODE_GREY;
  507.       break;
  508.     case COLORNUM_RGB24:
  509.       scanMode = SCANMODE_COLOR;
  510.       break;
  511.     default:
  512.       *status = SCAN_ERR_PARAMETER;
  513.       parametersSet = FALSE;
  514.       return;
  515.   }
  516.   
  517.   // Frame in mm
  518.   x0 = param->sp_x0;
  519.   y0 = param->sp_y0;
  520.   x1 = param->sp_x1;
  521.   y1 = param->sp_y1;
  522.   
  523.   // Resolution code and actual resolution
  524.   if( param->sp_xResolution > MAX_BASE_RES )
  525.   {
  526.     resolutionCode = (param->sp_xResolution*100)/MAX_EXT_RES;
  527.     resolutionFlag = 0;
  528.     extendedRes = TRUE;
  529.     xResolution = (resolutionCode*MAX_EXT_RES)/100;
  530.     yResolution = (resolutionCode*MAX_EXT_RES)/100;
  531.   }
  532.   else
  533.   {
  534.     resolutionCode = (param->sp_xResolution*100)/MAX_BASE_RES;
  535.     resolutionFlag = 0;
  536.     extendedRes = FALSE;
  537.     xResolution = (resolutionCode*MAX_BASE_RES)/100;
  538.     yResolution = (resolutionCode*MAX_BASE_RES)/100;
  539.   }
  540.   
  541.   // Brightness, contrast and exposure time
  542.   brightness[0] = 0; //param->sp_brightness[0];
  543.   brightness[1] = 0; //param->sp_brightness[1];
  544.   brightness[2] = 0; //param->sp_brightness[2];
  545.   shadow = 0; //param->sp_shadow;
  546.   highlight = 255; //param->sp_highlight;
  547.   midtone = 128; //param->sp_midtone;
  548.   halftonePattern = param->sp_halftonePattern;
  549.   contrast = 0; //param->sp_contrast;
  550.   exposureTime = param->sp_exposureTime;
  551.   gamma = param->sp_gamma;
  552.   // extendedRes = 0;
  553.  
  554.   *status = 0;
  555.   scannerReady(status);
  556.   selectMode(status);
  557.   mode_sense_1(status);
  558.   setScanningFrame(status);
  559.   gammaTable(gamma,status);
  560.   accessory(status);
  561.  
  562.   //
  563.   // brightness and contrast is simulated by this driver
  564.   //
  565.   makeCorrTab(param->sp_brightness[0],param->sp_contrast);
  566.  
  567.   if( *status )
  568.     parametersSet = FALSE;
  569.   else
  570.     parametersSet = TRUE;
  571. }
  572.  
  573. void startScanning(struct ScanInformation* inform,BYTE* status)
  574. {
  575.   if( parametersSet )
  576.   {
  577.     int busy;
  578.       
  579.     *status = 0;
  580.     startScan(status);
  581.     readScanStatus(&busy,&lineWidth,&scanLines,status);
  582.  
  583.     if( lineWidth <= 0 )
  584.       *status = SCAN_ERR_MISC;
  585.  
  586.     if( *status == 0 )
  587.     {
  588.       switch( scanMode )
  589.       {
  590.         case SCANMODE_HALFTONE:
  591.         case SCANMODE_BW:
  592.           bytesPerLine = lineWidth;
  593.           imageWidth = lineWidth*8;
  594.           imageHeight = scanLines;
  595.           numPlanes = 1;
  596.           break;
  597.         case SCANMODE_GREY:
  598.           if( extendedRes )
  599.             bytesPerLine = lineWidth*2-1;
  600.           else
  601.             bytesPerLine = lineWidth;
  602.           imageWidth = bytesPerLine;
  603.           imageHeight = scanLines;
  604.           numPlanes = 1;
  605.           break;
  606.         case SCANMODE_COLOR:
  607.           if( extendedRes )
  608.             bytesPerLine = (lineWidth-2)*2-1;
  609.           else
  610.             bytesPerLine = lineWidth-2;
  611.           imageWidth = bytesPerLine;
  612.           imageHeight = scanLines;
  613.           numPlanes = 3;
  614.           break;
  615.  
  616.       }
  617.       bufferLen = SCANBUFSIZE/lineWidth/numPlanes;
  618.       linesRead = 0;
  619.       linesInBuf = 0;
  620.       currentLine = 0;
  621.       nextPlane = 0;
  622.       
  623.       inform->sv_imageWidth = imageWidth;
  624.       inform->sv_imageHeight = imageHeight;
  625.       inform->sv_bytesPerLine = bytesPerLine;
  626.       inform->sv_Flags = 0;
  627.       inform->sv_xResolution = xResolution;
  628.       inform->sv_yResolution = yResolution;
  629.       
  630.       scanning = TRUE;
  631.     }
  632.   }
  633.   else
  634.     *status = SCAN_ERR_PARAMETER;
  635. }
  636.  
  637. void stopScanning(void)
  638. {
  639.   BYTE status = 0;
  640.   
  641.   if( scanLines != linesRead )
  642.     stopScan(&status);
  643.   scanning = FALSE;
  644. }
  645.  
  646. void readScanLine(UBYTE* data,ULONG* length,BYTE* status)
  647. {
  648.   if( !scanning )
  649.     *status = SCAN_ERR_NOTSCANNING;
  650.   else if( *length < bytesPerLine+1 )
  651.     *status = SCAN_ERR_MISC;
  652.   else if( (scanLines == linesRead) && (currentLine == linesInBuf) )
  653.     *status = SCAN_STATUS_EOF;
  654.   else
  655.   {
  656.     UBYTE* bptr;
  657.     
  658.     if( currentLine == linesInBuf )
  659.     {
  660.       if( bufferLen < scanLines-linesRead )
  661.         linesInBuf = bufferLen;
  662.       else
  663.         linesInBuf = scanLines-linesRead;
  664.         
  665.       readScanData(linesInBuf,scanBuffer,linesInBuf*lineWidth*numPlanes,status);
  666.       
  667.       if( *status )
  668.       {
  669.         *length = 0;
  670.         return;
  671.       }
  672.         
  673.       linesRead += linesInBuf;
  674.       currentLine = 0;
  675.     }
  676.     
  677.     bptr = scanBuffer + (numPlanes*currentLine+nextPlane)*lineWidth;
  678.     
  679.     if( scanMode == SCANMODE_COLOR )
  680.     {
  681.       *(data++) = (bptr[1] == 'R') ? 0 : ((bptr[1] == 'G') ? 1 : 2);
  682.       bptr += 2;
  683.     }
  684.     else
  685.       *(data++) = 0;
  686.  
  687.     if( !extendedRes )
  688.     {
  689.       int i;
  690.       
  691.       for( i = 0 ; i < bytesPerLine ; i++ )
  692.       {
  693.         *(data++) = corrTab[*(bptr++)];
  694.       }
  695.  
  696.       *length = bytesPerLine+1;
  697.     }
  698.     else
  699.     {
  700.       int i;
  701.       
  702.       *(data++) = corrTab[*bptr];
  703.       for( i = 1 ; i < (bytesPerLine+1)/2 ; i++ )
  704.       {
  705.         *(data++) = (corrTab[*(bptr++)]+corrTab[(*bptr)])/2;
  706.         *(data++) = corrTab[*bptr];
  707.       }
  708.  
  709.       *length = bytesPerLine+1;
  710.     }
  711.     
  712.     if( ++nextPlane == numPlanes )
  713.     {
  714.       nextPlane = 0;
  715.       currentLine++;
  716.     }
  717.   }
  718.   if( *status )
  719.     *length = 0;
  720. }
  721.