home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Hardware / BetaScan / BetaScanDev / ScanmakerE3 / ScanmakerE3.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-23  |  21.7 KB  |  754 lines

  1. //*********************************************************************
  2. //
  3. //                 ScanmakerE3 Scanner device
  4. //
  5. //                    version 98.12.31
  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 <Scanner.h>
  20. #include <Scanner_protos.h>
  21.  
  22. #include "scsi.h"
  23.  
  24. char DevName[] = "ScanmakerE3.device";
  25. char DevIdString[] = "ScanmakerE3";
  26.  
  27. typedef unsigned char ScanCmd[6];
  28.  
  29. // Scanner specifik defines
  30. #define MAX_BASE_RES      300
  31. #define MAX_EXT_RES       300
  32.  
  33. // scanning modes
  34. #define SCANMODE_HALFTONE   0
  35. #define SCANMODE_BW         1 
  36. #define SCANMODE_GRAY       2
  37. #define SCANMODE_COLOR      3
  38.  
  39.  
  40. #define SCANBUFSIZE     32000
  41.  
  42. #define MAX_BUSY_RETRY      5
  43.  
  44.  
  45. static UBYTE* scanBuffer = NULL;
  46.  
  47. // Stored scanning parameters
  48. //
  49. static double x0 = 0;                    /* Scanning frame in mm               */
  50. static double y0 = 0;
  51. static double x1 = 215.9;
  52. static double y1 = 297.3;
  53. static UBYTE  resolutionCode = 100;      /* Resolution in % of max resolution  */
  54. static WORD   brightness[3] = {0,0,0};   /* Brightness for red, green and blue */
  55. static WORD   contrast = 0;              /* Contrast                           */
  56. static WORD   shadow = 0;                /* shadow adjust 0..1023 (default 0)  */
  57. static WORD   highlight = 255;           /* highlight adjust 0..1023 (def. 0)  */
  58. static WORD   midtone = 128;             /* midtone adjust 0..1023 (def. 512)  */
  59. static WORD   halftonePattern = 0;       /* halftonePattern 0..255 (def. 0)    */
  60. static WORD   exposureTime = 0;          /* Exposure time                      */
  61. static double gamma = 1.0;               /* gamma value                        */
  62. static UWORD  scanMode = SCANMODE_COLOR; /* see defines above                  */
  63.  
  64. // Used to make Software corrections of contrast and brightness
  65. static int brightnessValue;
  66. static int contrastValue;
  67.  
  68. // Actual scanning values
  69. //
  70. static LineFormat lineFormat;
  71. static UWORD      bytesPerLine;
  72.  
  73. // Parameters used during scanning
  74. //
  75. static BOOL scanning;    /* Scanner is scanning                                */
  76. static int  lineWidth;   /* Length of one scan line including color informat.  */
  77. static int  scanLines;   /* Total number of lines to read from scanner         */
  78. static int  numPlanes;   /* 3 for rgb24, otherwise 1                           */
  79. static int  bufferLen;   /* Length of scanBuffer in number of lines            */
  80. static int  linesRead;   /* Lines already read from scanner                    */
  81. static int  linesInBuf;  /* Number of lines read from scanner in scanBuffer    */
  82. static int  currentLine; /* Next line from scanBuf to return to user           */
  83. static int  nextPlane;   /* next plane number to return to readScanLine        */
  84.  
  85. //
  86. // Make color correction table brightness and contrast
  87. //
  88.  
  89. UBYTE corrTab[256];
  90.  
  91. void makeCorrTab(int bright,int contrast)
  92. {
  93.   int    i,b,c;
  94.   UBYTE* tab;
  95.  
  96.   tab = corrTab;
  97.   bright = (bright*255)/100;
  98.   c = 100+contrast;
  99.   for( i = 0 ; i < 256 ; i++ )
  100.   {
  101.     b = ((i+bright)*c-50*contrast)/100;
  102.     *(tab++) = b>255?255:(b<0?0:(UBYTE)b);
  103.   }
  104. }
  105.  
  106. /*------------------------------------------------------------------------*/
  107. static void scannerReady(BYTE *error)
  108. {
  109.   if( *error == 0 )
  110.   {
  111.     ScanCmd TEST_UNIT_READY = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
  112.     int retry = 0;
  113.  
  114.     while( sendCommand(TEST_UNIT_READY, 6, NULL, 0, NULL, 0) )
  115.     {
  116.       retry++;
  117.       if (retry == 5)
  118.       {
  119.         *error = SCAN_ERR_READY;
  120.         return;
  121.       }
  122.       Delay(3*50);
  123.     }
  124.   }
  125. }
  126.  
  127.  
  128. /*------------------------------------------------------------------------*/
  129. static void setScanningFrame(BYTE *error)
  130. {
  131.   if( *error == 0 )
  132.   {
  133.     ScanCmd SCANNING_FRAME = { 0x04, 0x00, 0x00, 0x00, 0x09, 0x00 };
  134.     UBYTE   frame_data[9];
  135.  
  136.     int xf0,yf0,xf1,yf1;
  137.     int dpi;
  138.     
  139.     frame_data[0] = 0x00;
  140.     if( scanMode == SCANMODE_HALFTONE )
  141.       frame_data[0] |= 0x01;
  142.  
  143.     // Unit is pixel
  144.     //
  145.     frame_data[0] |= 0x08;
  146.  
  147.     dpi = MAX_BASE_RES;
  148.     xf0 = (int)((double)(x0*dpi)/25.4);
  149.     yf0 = (int)((double)(y0*dpi)/25.4);
  150.     xf1 = (int)((double)(x1*dpi)/25.4);
  151.     yf1 = (int)((double)(y1*dpi)/25.4);
  152.     
  153.     frame_data[1] = (UBYTE)(xf0 & 0xff);
  154.     frame_data[2] = (UBYTE)((xf0 & 0xff00) >> 8);
  155.     frame_data[3] = (UBYTE)(yf0 & 0xff);
  156.     frame_data[4] = (UBYTE)((yf0 & 0xff00) >> 8);
  157.     frame_data[5] = (UBYTE)(xf1 & 0xff);
  158.     frame_data[6] = (UBYTE)((xf1 & 0xff00) >> 8);
  159.     frame_data[7] = (UBYTE)(yf1 & 0xff);
  160.     frame_data[8] = (UBYTE)((yf1 & 0xff00) >> 8);
  161.  
  162.     *error = sendCommand(SCANNING_FRAME, 6, frame_data, 9, NULL, 0);
  163.   }
  164. }
  165.  
  166.  
  167. /*------------------------------------------------------------------------*/
  168. static void selectMode(BYTE *error)
  169. {
  170.   if( *error == 0 )
  171.   {
  172.     ScanCmd MODE_SELECT = { 0x15, 0x00, 0x00, 0x00, 0x0B, 0x00 };
  173.     UBYTE mode_data[11];
  174.  
  175.     mode_data[0] = 0x81;
  176.     
  177.     // Set resolution
  178.     mode_data[0] |= 0x02;
  179.     mode_data[1] = resolutionCode;
  180.     mode_data[2] = (exposureTime/3)+7;
  181.     mode_data[3] = (contrast+49)/7;
  182.     mode_data[4] = halftonePattern;
  183.     mode_data[5] = 0x01;
  184.     mode_data[6] = shadow;
  185.     mode_data[7] = highlight;
  186.     mode_data[8] = 0x6C;
  187.     mode_data[9] = 0x00;
  188.     mode_data[10] = midtone;
  189.         
  190.     *error = sendCommand(MODE_SELECT, 6, mode_data, 11, NULL, 0);
  191.   }
  192. }
  193.  
  194. /*------------------------------------------------------------------------*/
  195. void mode_sense_1(BYTE *error)
  196. {
  197.  
  198.   if( *error == 0 )
  199.   {
  200.     ScanCmd MODE_SELECT_1 = { 0x16, 0x00, 0x00, 0x00, 0x0a, 0x00 };
  201.     unsigned char mode_data[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  202.  
  203.     mode_data[1] = (UBYTE)(brightness[0]);
  204.  
  205.     *error = sendCommand(MODE_SELECT_1, 6, mode_data, 10, NULL, 0);
  206.   }
  207.   if( *error == 0 )
  208.   {
  209.     ScanCmd MODE_SENSE_1 = { 0x19, 0x00, 0x00, 0x00, 0x1e, 0x00 };
  210.     unsigned char mode_data[30] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  211.                                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  212.                                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  213.  
  214.     mode_data[1] = (UBYTE)(brightness[0]);
  215.     mode_data[2] = (UBYTE)(brightness[1]);
  216.     mode_data[3] = (UBYTE)(brightness[2]);
  217.     *error = sendCommand(MODE_SENSE_1, 6, mode_data, 30, NULL, 0);
  218.   }
  219. }
  220.  
  221. /*------------------------------------------------------------------------*/
  222. /* int lut_download (char filter, char *gtable, int gt_entries)           */
  223. /* Issue the LOOK-UP-TABLE DOWNLOAD command to the scanner to download    */
  224. /* the gamma table pointed to by <gtable>. <filter> determines the color  */
  225. /* to which the table applies (RED, GREEN, BLUE, or CLEAR; values other   */
  226. /* than CLEAR may only be specified for one-pass color scanners). The     */
  227. /* number of entries is determined by <entries> (256, 1024, 4096 or       */
  228. /* 65536). The entry width is automatically assumed to be one byte if the */
  229. /* number of entries is 256 and two bytes otherwise.                      */
  230. /*------------------------------------------------------------------------*/
  231.  
  232. void gammaTable(double g, BYTE *error)
  233. {
  234.   if( *error == 0 )
  235.   {
  236.     UBYTE LUT_DOWNLOAD[10] = {0x55,0x00,0x27,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
  237.     UBYTE gTable[256];
  238.     int i;
  239.  
  240.     LUT_DOWNLOAD[7] = (UBYTE)((256 & 0xff00) >> 8);
  241.     LUT_DOWNLOAD[8] = (UBYTE)(256 & 0xff);
  242.  
  243.     if( (g <= 0.0) || (g == 1.0) )
  244.     {
  245.       for( i = 0 ; i < 256 ; i++ )
  246.         gTable[i] = (UBYTE)i;
  247.     }
  248.     else
  249.     {
  250.       for( i = 0 ; i < 256 ; i++ )
  251.         gTable[i] = (UBYTE)(256.0*pow(((double)i)/256.0,1/g));
  252.     }
  253.  
  254.     *error = sendCommand(LUT_DOWNLOAD,10,gTable,256,NULL,0);
  255.   }
  256. }
  257.  
  258. /*------------------------------------------------------------------------*/
  259. static void accessory(BYTE *error)
  260. {
  261.   if( *error == 0 )
  262.   {
  263.     ScanCmd ACCESSORY = { 0x10, 0x00, 0x00, 0x00, 0x9A, 0x00 };
  264.  
  265.     *error = sendCommand(ACCESSORY, 6, NULL, 0, NULL, 0);
  266.   }
  267. }
  268.  
  269. /*------------------------------------------------------------------------*/
  270. static void startScan(BYTE *error)
  271. {
  272.   if( *error == 0 )
  273.   {
  274.     ScanCmd START_SCAN = { 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00 };
  275.  
  276.     switch( scanMode )
  277.     {
  278.       case SCANMODE_HALFTONE:
  279.       case SCANMODE_BW:
  280.         break;
  281.       case SCANMODE_COLOR:
  282.         START_SCAN[4] |= 0x20;  // 1-pass color
  283.       case SCANMODE_GRAY:
  284.         START_SCAN[4] |= 0x40;  // Multibit
  285.         break;
  286.     }
  287.     // if( extendedRes )
  288.     //     START_SCAN[4] |= 0x80;  // extended resolution
  289.  
  290.     *error = sendCommand(START_SCAN, 6, NULL, 0, NULL, 0);
  291.   }
  292. }
  293.  
  294.  
  295. /*------------------------------------------------------------------------*/
  296. static void stopScan(BYTE *error)
  297. {
  298.   if( *error == 0 )
  299.   {
  300.     ScanCmd STOP_SCAN = { 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00 };
  301.  
  302.     *error = sendCommand(STOP_SCAN, 6, NULL, 0, NULL, 0);
  303.   }
  304. }
  305.  
  306. /*------------------------------------------------------------------------*/
  307. static void readScanStatus(int *busy, int *lineWidth, int *linesRemain,BYTE *error)
  308. {
  309.   if( *error == 0 )
  310.   {
  311.     ScanCmd GET_SCAN_STATUS = { 0x0f, 0x00, 0x00, 0x00, 0x06, 0x00 };
  312.     UBYTE status_reply[6];
  313.     int retry = 0;
  314.  
  315.     do
  316.     {
  317.       if( *error = sendCommand(GET_SCAN_STATUS,6,NULL,0,status_reply,6) )
  318.         return;
  319.  
  320.       *busy        = (int)(status_reply[0] != 0);
  321.       *lineWidth   = (int)(status_reply[1] + 256 * status_reply[2]);
  322.       *linesRemain = (int)(status_reply[3]+256*status_reply[4]+256*256*status_reply[5]);
  323.       if( *busy )
  324.       {
  325.         retry++;
  326.         Delay(3*50);
  327.       }
  328.     }
  329.     while( (*busy) && (retry < MAX_BUSY_RETRY) );
  330.     if( *busy )
  331.       *error = SCAN_ERR_READY;
  332.   }
  333. }
  334.  
  335.  
  336. /*----------------------------------------------------------------------*/
  337. /*                                                                      */
  338. /* Read lines from scanner                                              */
  339. /*                                                                      */
  340. /* The number of lines to read must be specified. For color scanning    */
  341. /* the length of one line is three times line width although the lines  */
  342. /* returned is not in correct sequence (r-g-b).                         */
  343. /*                                                                      */
  344. /*----------------------------------------------------------------------*/
  345.  
  346. static void readScanData(int nlines,UBYTE *buffer,int bsize,BYTE *error)
  347. {
  348.   if( *error == 0 )
  349.   {
  350.     ScanCmd READ_SCANNED_DATA = { 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 };
  351.  
  352.     READ_SCANNED_DATA[2] = (UBYTE)((nlines & 0xff0000) >> 16);
  353.     READ_SCANNED_DATA[3] = (UBYTE)((nlines & 0xff00) >> 8);
  354.     READ_SCANNED_DATA[4] = (UBYTE)(nlines & 0xff);
  355.     *error = sendCommand(READ_SCANNED_DATA,6,NULL,0,buffer,bsize);
  356.   }
  357. }
  358.  
  359. /*----------------------------------------------------------------------*/
  360. /*                                                                      */
  361. /* Test scanner                                                         */
  362. /*                                                                      */
  363. /*----------------------------------------------------------------------*/
  364.  
  365. static void testScanner(BYTE *error)
  366. {
  367.   UBYTE    inquiry[96];    /* buffer for INQUIRY data */
  368.   ScanCmd  INQUIRY = { 0x12, 0x00, 0x00, 0x00, 96, 0x00 };
  369.   
  370.   *error = 0;
  371.  
  372.   if( sendCommand(INQUIRY,6,NULL,0,inquiry,96) || ((inquiry[0] & 0x1f) != 0x06) )
  373.     *error = SCAN_OPNERR_NOT_SCANNER;
  374.   else if( (inquiry[62] != 0x5f) )
  375.     *error = SCAN_OPNERR_UNKNOWN;
  376.   else
  377.     *error = 0;
  378. }
  379.  
  380. /////////////////////////////////////////////////////////////////////////
  381. //
  382. //  Interface part
  383. //
  384. /////////////////////////////////////////////////////////////////////////
  385.  
  386. char* modeStrings[] =
  387. {
  388.   "Halftone",
  389.   "Lineart",
  390.   "Gray",
  391.   "Color",
  392.   NULL
  393. };
  394.  
  395. int modeDepth[] = {1,1,8,24};
  396.         
  397. char* halfToneStrings[] =
  398. {
  399.   "53-dot screen (53 gray levels)",
  400.   "Horiz. screen (65 gray levels)",
  401.   "Vert. screen (65 gray levels)",
  402.   "Mixed page (33 gray levels)",
  403.   "71-dot screen (29 gray levels)",
  404.   "60-dot #1 (26 gray levels)",
  405.   "60-dot #2 (26 gray levels)",
  406.   "Fine detail #1 (17 gray levels)",
  407.   "Fine detail #2 (17 gray levels)",
  408.   "Slant line (17 gray levels)",
  409.   "Posterizing (10 gray levels)",
  410.   "High Contrast (5 gray levels)",
  411.   NULL
  412. };
  413.  
  414. int halfToneActive[] = {TRUE,FALSE,FALSE,FALSE};
  415.  
  416. Range xRange = {DOUBLE_FIX(0.0),DOUBLE_FIX(215.9),DOUBLE_FIX(0.0)};
  417. Range yRange = {DOUBLE_FIX(0.0),DOUBLE_FIX(297.3),DOUBLE_FIX(0.0)};
  418. Range resolutionRange = {3,300,3};
  419. Range brightnessRange = {-100,100,1};
  420. Range contrastRange   = {-42,49,7};
  421. Range exposureRange   = {-18,21,3};
  422. Range gammaRange = {DOUBLE_FIX(0.5),DOUBLE_FIX(4.0),DOUBLE_FIX(0.05)};
  423.  
  424. struct OptionDescriptor scannerOptions[] = 
  425. {
  426.   {ID_SCANMODE,TYPE_STRING,UNIT_NONE,CONSTRAINT_STRING_LIST,modeStrings,modeDepth},
  427.   {ID_TL_X,TYPE_FIXED,UNIT_MM,CONSTRAINT_RANGE,(char**)&xRange,NULL},
  428.   {ID_TL_Y,TYPE_FIXED,UNIT_MM,CONSTRAINT_RANGE,(char**)&yRange,NULL},
  429.   {ID_BR_X,TYPE_FIXED,UNIT_MM,CONSTRAINT_RANGE,(char**)&xRange,NULL},
  430.   {ID_BR_Y,TYPE_FIXED,UNIT_MM,CONSTRAINT_RANGE,(char**)&yRange,NULL},
  431.   {ID_RESOLUTION,TYPE_INT,UNIT_DPI,CONSTRAINT_RANGE,(char**)&resolutionRange,NULL},
  432.   {ID_HALFTONEPATTERN,TYPE_STRING,UNIT_NONE,CONSTRAINT_STRING_LIST,halfToneStrings,halfToneActive},
  433.   {ID_BRIGHTNESS,TYPE_INT,UNIT_PERCENT,CONSTRAINT_RANGE,(char**)&brightnessRange,NULL},
  434.   {ID_CONTRAST,TYPE_INT,UNIT_PERCENT,CONSTRAINT_RANGE,(char**)&contrastRange,NULL},
  435.   {ID_ANALOGGAMMA,TYPE_FIXED,UNIT_NONE,CONSTRAINT_RANGE,(char**)&gammaRange,NULL},
  436.   {ID_EXPOSURETIME,TYPE_INT,UNIT_PERCENT,CONSTRAINT_RANGE,(char**)&exposureRange,NULL}
  437. };
  438.  
  439. void closeScanner(void)
  440. {
  441.   if( scanBuffer )
  442.   {
  443.     free(scanBuffer);
  444.     scanBuffer = NULL;
  445.   }
  446.   closeScannerDevice();
  447. }
  448.  
  449. void openScanner(char* name,int unit,struct ScannerOptions* option,BYTE* status)
  450. {
  451.   scanning = FALSE;
  452.   scanLines = 0;
  453.   linesRead = 0;
  454.   
  455.   if( openScannerDevice(name,unit) )
  456.   {
  457.     testScanner(status);
  458.     if( *status )
  459.     {
  460.       closeScanner();
  461.       return;
  462.     }
  463.     
  464.     if( scanBuffer = (UBYTE*)malloc(SCANBUFSIZE) )
  465.     {
  466.       strcpy(option->so_scannerVendor,"Microtek");
  467.       strcpy(option->so_scannerModel,"Scanmaker E3");
  468.       option->so_driverVersion = 2;
  469.       option->so_driverRevision = 0;
  470.       
  471.       option->so_docWidth = 215.9;
  472.       option->so_docHeight = 297.9;
  473.       
  474.       option->so_flags = 0;
  475.       
  476.       option->so_optionNum = sizeof(scannerOptions)/sizeof(struct OptionDescriptor);
  477.       
  478.       option->so_descriptor = scannerOptions;
  479.       
  480.       *status = SCAN_STATUS_OK;
  481.     }
  482.     else
  483.     {
  484.       closeScanner();
  485.       *status = SCAN_OPNERR_MEMORY; // SCAN_ERR_MEMORY;
  486.     }
  487.   }
  488.   else
  489.     *status = SCAN_OPNERR_DEVICE;   // SCAN_ERR_DEVICEOPEN;
  490. }
  491.  
  492. void controlOption(struct OptionValue* value,BYTE* status)
  493. {
  494.   if( value->sp_optionID != ID_NONE )
  495.   {
  496.     value->sp_flags &= CONTROL_CALLMASK; // Clear return mask
  497.  
  498.     if( value->sp_flags & CONTROL_SET )
  499.     {
  500.       switch( value->sp_optionID )
  501.       {
  502.         case ID_SCANMODE:
  503.           scanMode = value->sp_value;
  504.           break;
  505.         case ID_TL_X:            /* upper left corner of scan area     */
  506.           x0 = FIX_DOUBLE(value->sp_value);
  507.           break;
  508.         case ID_TL_Y:            /* upper left corner of scan area     */
  509.           y0 = FIX_DOUBLE(value->sp_value);
  510.           break;
  511.         case ID_BR_X:            /* bottom right corner of scan area   */
  512.           x1 = FIX_DOUBLE(value->sp_value);
  513.           break;
  514.         case ID_BR_Y:            /* bottom right corner of scan area   */
  515.           y1 = FIX_DOUBLE(value->sp_value);
  516.           break;
  517.         case ID_RESOLUTION:      /* scan resolution (combined x and y) */
  518.           if( (value->sp_value < 3) || (value->sp_value > 300) )
  519.             value->sp_flags |= CONTROL_RANGE;
  520.           else
  521.           {
  522.             resolutionCode = (value->sp_value*100)/MAX_BASE_RES;
  523.             if( value->sp_value != (resolutionCode*MAX_BASE_RES)/100 )
  524.               value->sp_flags |= CONTROL_ROUNDED;
  525.           }
  526.           break;
  527.         case ID_HALFTONEPATTERN:
  528.           halftonePattern = value->sp_value;
  529.           break;
  530.         case ID_BRIGHTNESS:
  531.           if( (value->sp_value < -100) || (value->sp_value > 100) )
  532.             value->sp_flags |= CONTROL_RANGE;
  533.           else
  534.             brightnessValue = value->sp_value;
  535.           break;
  536.         case ID_CONTRAST:
  537.           if( (value->sp_value < -42) || (value->sp_value > 49) )
  538.             value->sp_flags |= CONTROL_RANGE;
  539.           else
  540.             contrastValue = ((value->sp_value+42)/7)*7-42;
  541.             if( value->sp_value != contrastValue )
  542.               value->sp_flags |= CONTROL_ROUNDED;
  543.           break;
  544.         case ID_ANALOGGAMMA:
  545.           gamma = FIX_DOUBLE(value->sp_value);
  546.           break;
  547.         case ID_BLACKLEVEL:  /* some times called shadow           */
  548.           shadow = 0;        //value->sp_value;
  549.           break;
  550.         case ID_WHITELEVEL:  /* some times called highlight        */
  551.           highlight = 255;   //value->sp_value;
  552.           break;
  553.         case ID_THRESHOLD:
  554.           midtone = 128;     //value->sp_value;
  555.           break;
  556.         case ID_EXPOSURETIME:
  557.           if( (value->sp_value < -18) || (value->sp_value > 21) )
  558.             value->sp_flags |= CONTROL_RANGE;
  559.           else
  560.             exposureTime = ((value->sp_value+18)/3)*3-18;
  561.             if( value->sp_value != exposureTime )
  562.               value->sp_flags |= CONTROL_ROUNDED;
  563.           break;
  564.         default:
  565.           value->sp_flags |= CONTROL_INVALID;
  566.           break;
  567.       }
  568.     }
  569.         
  570.     if( value->sp_flags & CONTROL_GET )
  571.     {
  572.       switch( value->sp_optionID )
  573.       {
  574.         case ID_SCANMODE:
  575.           value->sp_value = scanMode;
  576.           break;
  577.         case ID_TL_X:            /* upper left corner of scan area     */
  578.           value->sp_value = DOUBLE_FIX(x0);
  579.           break;
  580.         case ID_TL_Y:            /* upper left corner of scan area     */
  581.           value->sp_value = DOUBLE_FIX(y0);
  582.           break;
  583.         case ID_BR_X:            /* bottom right corner of scan area   */
  584.           value->sp_value = DOUBLE_FIX(x1);
  585.           break;
  586.         case ID_BR_Y:            /* bottom right corner of scan area   */
  587.           value->sp_value = DOUBLE_FIX(y1);
  588.           break;
  589.         case ID_RESOLUTION:      /* scan resolution (combined x and y) */
  590.           value->sp_value = (resolutionCode*MAX_BASE_RES)/100;
  591.           break;
  592.         case ID_HALFTONEPATTERN:
  593.           value->sp_value = halftonePattern;
  594.           break;
  595.         case ID_BRIGHTNESS:
  596.           value->sp_value = brightnessValue;
  597.           break;
  598.         case ID_CONTRAST:
  599.           value->sp_value = contrastValue;
  600.           break;
  601.         case ID_ANALOGGAMMA:
  602.           value->sp_value = DOUBLE_FIX(gamma);
  603.           break;
  604.         case ID_EXPOSURETIME:
  605.           value->sp_value = exposureTime;
  606.           break;
  607.         default:
  608.           value->sp_flags |= CONTROL_INVALID;
  609.           break;
  610.       }
  611.     }
  612.   }
  613.  
  614.   *status = 0;
  615. }
  616.  
  617. void startScanning(struct ScanInformation* inform,BYTE* status)
  618. {
  619.   *status = 0;
  620.   
  621.   scannerReady(status);
  622.   selectMode(status);
  623.   mode_sense_1(status);
  624.   setScanningFrame(status);
  625.   gammaTable(gamma,status);
  626.   accessory(status);
  627.  
  628.   if( *status == 0 )
  629.   {
  630.     UWORD imageWidth;
  631.     UWORD imageHeight;
  632.     UWORD imageDepth;
  633.     int   busy;
  634.       
  635.     makeCorrTab(brightnessValue,contrastValue);
  636.  
  637.     startScan(status);
  638.     readScanStatus(&busy,&lineWidth,&scanLines,status);
  639.  
  640.     if( lineWidth <= 0 )
  641.       *status = SCAN_ERR_MISC;
  642.  
  643.     if( *status == 0 )
  644.     {
  645.       switch( scanMode )
  646.       {
  647.         case SCANMODE_HALFTONE:
  648.         case SCANMODE_BW:
  649.           bytesPerLine = lineWidth;
  650.           imageWidth = lineWidth*8;
  651.           imageHeight = scanLines;
  652.           imageDepth = 1;
  653.           numPlanes = 1;
  654.           lineFormat = FORMAT_BW;
  655.           break;
  656.         case SCANMODE_GRAY:
  657.           bytesPerLine = lineWidth;
  658.           imageWidth = bytesPerLine;
  659.           imageHeight = scanLines;
  660.           imageDepth = 8;
  661.           numPlanes = 1;
  662.           lineFormat = FORMAT_GRAY;
  663.           break;
  664.         case SCANMODE_COLOR:
  665.           bytesPerLine = lineWidth-2;
  666.           imageWidth = bytesPerLine;
  667.           imageHeight = scanLines;
  668.           imageDepth = 24;
  669.           numPlanes = 3;
  670.           lineFormat = FORMAT_RGB_RANDOM;
  671.           break;
  672.  
  673.       }
  674.       bufferLen = SCANBUFSIZE/lineWidth/numPlanes;
  675.       linesRead = 0;
  676.       linesInBuf = 0;
  677.       currentLine = 0;
  678.       nextPlane = 0;
  679.       
  680.       inform->sv_xResolution  = (double)(resolutionCode*MAX_BASE_RES)/100.0;
  681.       inform->sv_yResolution  = (double)(resolutionCode*MAX_BASE_RES)/100.0;
  682.       inform->sv_lineFormat   = lineFormat; 
  683.       inform->sv_imageWidth   = imageWidth;
  684.       inform->sv_imageHeight  = imageHeight;
  685.       inform->sv_imageDepth   = imageDepth;
  686.       inform->sv_bytesPerLine = bytesPerLine;
  687.       inform->sv_Flags        = 0;
  688.      
  689.       scanning = TRUE;
  690.     }
  691.   }
  692.   else
  693.     *status = SCAN_ERR_PARAMETER;
  694. }
  695.  
  696. void stopScanning(void)
  697. {
  698.   BYTE status = 0;
  699.   
  700.   if( scanLines != linesRead )
  701.     stopScan(&status);
  702.   scanning = FALSE;
  703. }
  704.  
  705. void readScanLine(struct ScanLine* line,BYTE* status)
  706. {
  707.   if( !scanning )
  708.     *status = SCAN_ERR_NOTSCANNING;
  709.   else if( (scanLines == linesRead) && (currentLine == linesInBuf) )
  710.     *status = SCAN_STATUS_EOF;
  711.   else
  712.   {
  713.     UBYTE* bptr;
  714.     UBYTE* data;
  715.     int    i;
  716.     
  717.     if( currentLine == linesInBuf )
  718.     {
  719.       if( bufferLen < scanLines-linesRead )
  720.         linesInBuf = bufferLen;
  721.       else
  722.         linesInBuf = scanLines-linesRead;
  723.         
  724.       readScanData(linesInBuf,scanBuffer,linesInBuf*lineWidth*numPlanes,status);
  725.       
  726.       if( *status )
  727.         return;
  728.         
  729.       linesRead += linesInBuf;
  730.       currentLine = 0;
  731.     }
  732.     
  733.     bptr = scanBuffer + (numPlanes*currentLine+nextPlane)*lineWidth;
  734.     
  735.     if( lineFormat == FORMAT_RGB_RANDOM )
  736.     {
  737.       line->sl_color = (bptr[1] == 'R') ? FORMAT_RED : ((bptr[1] == 'G') ? FORMAT_GREEN : FORMAT_BLUE);
  738.       bptr += 2;
  739.     }
  740.     else
  741.       line->sl_color = lineFormat;
  742.  
  743.     for( data = line->sl_data, i = 0 ; i < bytesPerLine ; i++ )
  744.       *(data++) = corrTab[*(bptr++)];
  745.     
  746.     if( ++nextPlane == numPlanes )
  747.     {
  748.       nextPlane = 0;
  749.       currentLine++;
  750.     }
  751.   }
  752. }
  753.  
  754.