extern int setDefaultScannerOption(SANE_Handle *devHandle, const SANE_Option_Descriptor *sod, int option ) { if ( sod->cap & SANE_CAP_AUTOMATIC ) { int paramSetRet; int status = control_option (devHandle, sod, option, SANE_ACTION_SET_AUTO, NULL, ¶mSetRet); if(status == SANE_STATUS_GOOD) { handleSaneErrors("Cannot set automatically", status, paramSetRet); //updateScanProgress(uuid, SCAN_ERRO_FROM_SCANNER, status); return 1; } } return 0; }
char *internalDoScanningOperation(char *uuid, char *lang) { int request_resolution = 0; int docid; int current_page = 0; int total_requested_pages; double totbytes = 0; SANE_Status status; SANE_Handle *openDeviceHandle; SANE_Byte *raw_image; SANE_Parameters pars; char *docid_s; char *total_requested_pages_s; char *devName; char *outFilename; char *raw_image_format; char *header; o_log(DEBUGM, "doScanningOperation: sane initialized uuid(%s)",(char *)uuid); updateScanProgress(uuid, SCAN_WAITING_ON_SCANNER, 0); // Open the device devName = getScanParam(uuid, SCAN_PARAM_DEVNAME); o_log(DEBUGM, "sane_open of \"%s\"",devName); status = sane_open ((SANE_String_Const) devName, (SANE_Handle)&openDeviceHandle); if(status != SANE_STATUS_GOOD) { handleSaneErrors("Cannot open device ", devName, status, 0); updateScanProgress(uuid, SCAN_ERRO_FROM_SCANNER, status); free(devName); return 0; } free(devName); /* ========================================================== */ if ( ! setOptions( (char *)uuid, openDeviceHandle, &request_resolution ) ) return 0; o_log(DEBUGM, "sane_start: setOptions returned request_resolution %d\n",request_resolution); int timeout = 5; while( 0 < timeout ) { status = sane_start (openDeviceHandle); if(status == SANE_STATUS_GOOD) { break; } else { if(status == SANE_STATUS_DEVICE_BUSY ) { // BUSY signal could be the scanner just having a // bit of lag - specially network connected devices timeout--; if ( timeout == 0 ) { handleSaneErrors("Cannot start scanning", "even after trying several time", status, 0); updateScanProgress(uuid, SCAN_ERRO_FROM_SCANNER, status); return 0; } else { o_log(WARNING, "Device reports not ready to 'start', waiting 500ms. Will try another %d times", timeout); usleep(500 * 1000); // 500ms or 0.5sec } } else { handleSaneErrors("Cannot start scanning", "", status, 0); updateScanProgress(uuid, SCAN_ERRO_FROM_SCANNER, status); return 0; } } } // Get scanning params (from the scanner) if( request_resolution == 0 ) { o_log(DEBUGM, "Resolution did not get set in scanner setup."); updateScanProgress(uuid, SCAN_INTERNAL_ERROR, 10004); return 0; } o_log(DEBUGM, "Get scanning params"); status = sane_get_parameters (openDeviceHandle, &pars); o_log(INFORMATION, "Scanner Parm : stat=%s form=%d,lf=%d,bpl=%d,pixpl=%d,lin=%d,dep=%d", sane_strstatus (status), pars.format, pars.last_frame, pars.bytes_per_line, pars.pixels_per_line, pars.lines, pars.depth); switch (pars.format) { case SANE_FRAME_GRAY: o_log(DEBUGM, "Expecting Gray data (1 channel only)."); raw_image_format = o_strdup( "P5" ); break; case SANE_FRAME_RGB: o_log(DEBUGM, "Expecting RGB data (3 channels)."); raw_image_format = o_strdup( "P6" ); break; default: o_log(DEBUGM, "backend returns three frames speratly. We do not currently support this."); updateScanProgress(uuid, SCAN_INTERNAL_ERROR, 10003); return 0; break; } header = o_printf ("%s\n# SANE data follows\n%d %d\n%d\n", raw_image_format, pars.pixels_per_line, pars.lines, (pars.depth <= 8) ? 255 : 65535); free( raw_image_format ); // Save Record // docid_s = getScanParam(uuid, SCAN_PARAM_DOCID); total_requested_pages_s = getScanParam(uuid, SCAN_PARAM_REQUESTED_PAGES); total_requested_pages = atoi(total_requested_pages_s); free(total_requested_pages_s); if( docid_s == NULL ) { o_log(DEBUGM, "Saving record"); updateScanProgress(uuid, SCAN_DB_WORKING, 0); docid_s = addNewScannedDoc(pars.lines, pars.pixels_per_line, request_resolution, total_requested_pages); setScanParam(uuid, SCAN_PARAM_DOCID, docid_s); setScanParam(uuid, SCAN_PARAM_ON_PAGE, "1"); current_page = 1; } else { char *current_page_s = getScanParam(uuid, SCAN_PARAM_ON_PAGE); current_page = atoi(current_page_s); free(current_page_s); current_page++; current_page_s = itoa(current_page, 10); setScanParam(uuid, SCAN_PARAM_ON_PAGE, current_page_s); free(current_page_s); } docid = atoi(docid_s); free(docid_s); totbytes = (double)((pars.bytes_per_line * pars.lines)); /* ========================================================== */ raw_image = collectData( (char *)uuid, openDeviceHandle, totbytes, pars.bytes_per_line, header ); o_log(INFORMATION, "Scanning done."); o_log(DEBUGM, "sane_cancel"); sane_cancel(openDeviceHandle); o_log(DEBUGM, "sane_close"); sane_close(openDeviceHandle); // Convert Raw into JPEG // updateScanProgress(uuid, SCAN_CONVERTING_FORMAT, 0); PIX *pix; if ( ( pix = pixReadMem( raw_image, (pars.bytes_per_line*pars.lines)+strlen(header) ) ) == NULL) { o_log(ERROR, "Could not load the image data into a PIX"); } updateScanProgress(uuid, SCAN_CONVERTING_FORMAT, 55); o_log(INFORMATION, "Convertion process: Loaded (depth: %d)", pixGetDepth(pix)); free(raw_image); free(header); outFilename = o_printf("%s/scans/%d_%d.jpg", BASE_DIR, docid, current_page); pixWrite(outFilename, pix, IFF_JFIF_JPEG); free(outFilename); updateScanProgress(uuid, SCAN_CONVERTING_FORMAT, 100); o_log(INFORMATION, "Conversion process: Complete"); // Do OCR - on this page // - OCR libs just wants the raw data and not the image header ocrImage( uuid, docid, current_page, request_resolution, pix, lang ); #ifdef CAN_PHASH // Calulate the pHash, so we can compare images later if( current_page == 1 ) { updateScanProgress(uuid, SCAN_CALULATING_PHASH, 0); unsigned long long hash = getImagePhash_px( pix ); savePhash( docid, hash ); } #endif /* CAN_PHASH */ pixDestroy( &pix ); // cleaup && What should we do next // o_log(DEBUGM, "mostly done."); if(current_page >= total_requested_pages) updateScanProgress(uuid, SCAN_FINISHED, docid); else updateScanProgress(uuid, SCAN_WAITING_ON_NEW_PAGE, ++current_page); o_log(DEBUGM, "Page scan done."); return o_strdup("OK"); }
int setOptions( char *uuid, SANE_Handle *openDeviceHandle, int *request_resolution ) { int option = 0; SANE_Status status; SANE_Fixed v_f; SANE_Int v_i; SANE_Bool v_b; char *v_c; //const char *modes[] = { SANE_VALUE_SCAN_MODE_COLOR, SANE_VALUE_SCAN_MODE_GRAY, "Grayscale", NULL }; const char *modes_colour[] = { SANE_VALUE_SCAN_MODE_COLOR, "Color", SANE_VALUE_SCAN_MODE_GRAY, "Grayscale", NULL }; const char *modes_gray[] = { SANE_VALUE_SCAN_MODE_GRAY, "Grayscale", NULL }; const char *speeds[] = { "Auto", "Normal", "Fast", NULL }; const char *compression[] = { "None", NULL }; const char *sources[] = { "Auto", SANE_I18N ("Auto"), "Flatbed", SANE_I18N ("Flatbed"), "FlatBed", "Normal", SANE_I18N ("Normal"), NULL }; int testScanner = 0; char *devName = getScanParam(uuid, SCAN_PARAM_DEVNAME); if ( strstr(devName, "test") != 0 ) { testScanner = 1; } free(devName); for (option = 0; option < 9999; option++) { const SANE_Option_Descriptor *sod = sane_get_option_descriptor (openDeviceHandle, option); // No more options if (sod == NULL) break; // Just a placeholder if (sod->type == SANE_TYPE_GROUP || sod->name == NULL || option == 0) continue; log_option( option, sod ); // Validation if ( (sod->cap & SANE_CAP_SOFT_SELECT) && (sod->cap & SANE_CAP_HARD_SELECT) ) { o_log(DEBUGM, "The backend said that '%s' is both hardward and software settable! Err", sod->name); updateScanProgress(uuid, SCAN_ERRO_FROM_SCANNER, 0); return 0; } // we MUST set this value if ( (sod->cap & SANE_CAP_SOFT_DETECT) && ((sod->cap & SANE_CAP_INACTIVE) == 0) ) { // A hardware setting if ( sod->cap & SANE_CAP_HARD_SELECT ) { o_log(DEBUGM, "We've got no way of telling the user to set the hardward %s! Err", sod->name); } // a software setting else { int paramSetRet = 0; // Set scanning Source if ( strcmp(sod->name, SANE_NAME_SCAN_SOURCE) == 0 ) { if ( !setDefaultScannerOption(openDeviceHandle, sod, option, ¶mSetRet) ) { int i, j; int foundMatch = 0; for (i = 0; sources[i] != NULL; i++) { for (j = 0; sod->constraint.string_list[j]; j++) { if (strcmp (sources[i], sod->constraint.string_list[j]) == 0) break; } if (sod->constraint.string_list[j] != NULL) { v_c = o_strdup(sources[i]); status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, (void *)v_c, ¶mSetRet); free(v_c); foundMatch = 1; break; } } if( foundMatch == 0 ) { o_log(DEBUGM, "Non of the available options are appropriate."); } } } // Set scanning mode else if ( strcmp(sod->name, SANE_NAME_SCAN_MODE ) == 0 ) { const char **modes; char *requested_mode = getScanParam(uuid, SCAN_PARAM_FORMAT ); if( 0 == strcmp( "colour", requested_mode ) ) { modes = modes_colour; } else { modes = modes_gray; } free( requested_mode ); int i, j; int foundMatch = 0; for (i = 0; modes[i] != NULL; i++) { for (j = 0; sod->constraint.string_list[j]; j++) { if (strcmp (modes[i], sod->constraint.string_list[j]) == 0) break; } if (sod->constraint.string_list[j] != NULL) { v_c = o_strdup(modes[i]); status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, (void *)v_c, ¶mSetRet); free(v_c); foundMatch = 1; break; } } if( foundMatch == 0 ) { o_log(DEBUGM, "Non of the available options are appropriate."); } } else if ( strcmp(sod->name, "batch-scan" ) == 0 ) { v_b = SANE_FALSE; status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, ¶mSetRet); } else if ( strcmp(sod->name, "compression") == 0 ) { int i, j; int foundMatch = 0; for (i = 0; compression[i] != NULL; i++) { for (j = 0; sod->constraint.string_list[j]; j++) { o_log(DEBUGM, "n list: %s", sod->constraint.string_list[j]); if (strcmp (compression[i], sod->constraint.string_list[j]) == 0) break; } if (sod->constraint.string_list[j] != NULL) { o_log(DEBUGM, "Attempting to set compresstion to: %s", compression[i]); v_c = o_strdup(compression[i]); status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, (void *)v_c, ¶mSetRet); free(v_c); foundMatch = 1; break; } } if( foundMatch == 0 ) { o_log(DEBUGM, "Non of the available options are appropriate."); } } // Set scanning depth else if ( strcmp(sod->name, SANE_NAME_BIT_DEPTH) == 0 ) { if ( !setDefaultScannerOption(openDeviceHandle, sod, option, ¶mSetRet) ) { if( sod->type == SANE_TYPE_STRING ) { v_c = o_strdup("8"); status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, (void *)v_c, ¶mSetRet); free(v_c); } if (sod->type == SANE_TYPE_FIXED) { v_f = SANE_FIX( 8 ); status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_f, ¶mSetRet); } else { v_i = 8; status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_i, ¶mSetRet); } } } // Set Preview mode else if ( strcmp(sod->name, SANE_NAME_PREVIEW) == 0 ) { if ( !setDefaultScannerOption(openDeviceHandle, sod, option, ¶mSetRet) ) { v_b = SANE_FALSE; status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, ¶mSetRet); } } // Set scanning resolution else if ( strcmp(sod->name, SANE_NAME_SCAN_RESOLUTION) == 0 ) { char *request_resolution_s; request_resolution_s = getScanParam(uuid, SCAN_PARAM_REQUESTED_RESOLUTION); *request_resolution = atoi(request_resolution_s); free(request_resolution_s); if (sod->type == SANE_TYPE_FIXED) { v_f = SANE_FIX( *request_resolution ); status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_f, ¶mSetRet); } else if (sod->type == SANE_TYPE_INT) { int sane_resolution = *request_resolution; status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &sane_resolution, ¶mSetRet); } else { int sane_resolution = *request_resolution; if( sod->constraint.range->quant != 0 ) sane_resolution = sane_resolution * sod->constraint.range->quant; status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &sane_resolution, ¶mSetRet); } } else if ( strcmp(sod->name, SANE_NAME_SCAN_TL_Y) == 0 ) { v_f = sod->constraint.range->min; status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_f, ¶mSetRet); } else if ( strcmp(sod->name, SANE_NAME_SCAN_TL_X) == 0 ) { v_f = sod->constraint.range->min; status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_f, ¶mSetRet); } else if ( strcmp(sod->name, SANE_NAME_SCAN_BR_Y) == 0 ) { int pagelength; char *length_s; v_f = sod->constraint.range->max; length_s = getScanParam(uuid, SCAN_PARAM_LENGTH); pagelength = atoi(length_s); if(pagelength && pagelength >= 20 && pagelength < 100) v_f = SANE_FIX( ( SANE_UNFIX(v_f) * (double)pagelength) / 100); free(length_s); status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_f, ¶mSetRet); } else if ( strcmp(sod->name, SANE_NAME_SCAN_BR_X) == 0 ) { v_f = sod->constraint.range->max; status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_f, ¶mSetRet); } else if ( strcmp(sod->name, SANE_NAME_BRIGHTNESS) == 0 ) { v_f = 0; status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_f, ¶mSetRet); } else if ( strcmp(sod->name, SANE_NAME_CONTRAST) == 0 ) { v_f = 0; status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_f, ¶mSetRet); } else if ( strcmp(sod->name, SANE_NAME_SCAN_SPEED) == 0) { if ( !setDefaultScannerOption(openDeviceHandle, sod, option, ¶mSetRet) ) { int i, j; int foundMatch = 0; for (i = 0; speeds[i] != NULL; i++) { for (j = 0; sod->constraint.string_list[j]; j++) { if (strcmp (speeds[i], sod->constraint.string_list[j]) == 0) break; } if (sod->constraint.string_list[j] != NULL) { v_c = o_strdup(speeds[i]); status = control_option (openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, (void *)v_c, ¶mSetRet); free(v_c); foundMatch = 1; break; } } if( foundMatch == 0 ) { o_log(DEBUGM, "Non of the available options are appropriate."); } } } else if ( strcmp(sod->name, "custom-gamma") == 0 ) { v_b = SANE_FALSE; status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, ¶mSetRet); } // For the test 'virtual scanner' else if (testScanner == 1) { if ( strcmp(sod->name, "hand-scanner" ) == 0 ) { v_b = SANE_FALSE; status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, ¶mSetRet); } else if ( strcmp(sod->name, "three-pass") == 0 ){ v_b = SANE_FALSE; status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, ¶mSetRet); } else if ( strcmp(sod->name, "three-pass-order") == 0 ) { status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, "RGB", ¶mSetRet); } else if ( strcmp(sod->name, "test-raw_imageture") == 0 ) { status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, "Color pattern", ¶mSetRet); } else if ( strcmp(sod->name, "read-delay") == 0 ) { v_b = SANE_TRUE; status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, ¶mSetRet); } else if ( strcmp(sod->name, "fuzzy-parameters") == 0 ) { v_b = SANE_TRUE; status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, ¶mSetRet); } else if ( strcmp(sod->name, "read-delay-duration") == 0 ) { v_i = 1000; status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_i, ¶mSetRet); } else if ( strcmp(sod->name, "read-limit") == 0 ) { v_b = SANE_TRUE; status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, ¶mSetRet); } else if ( strcmp(sod->name, "read-limit-size") == 0 ) { v_i = sod->constraint.range->max; status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_i, ¶mSetRet); } else if ( strcmp(sod->name, "read-return-value") == 0 ) { status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, "Default", ¶mSetRet); } else if ( strcmp(sod->name, "ppl-loss") == 0 ) { v_i = 0; status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_i, ¶mSetRet); } else if ( strcmp(sod->name, "invert-endianess") == 0 ) { v_b = SANE_FALSE; status = control_option(openDeviceHandle, sod, option, SANE_ACTION_SET_VALUE, &v_b, ¶mSetRet); } } // not a 'well known' option else { // try setting automatically if ( !setDefaultScannerOption(openDeviceHandle, sod, option, ¶mSetRet) ) o_log(DEBUGM, "Could not set authmatically", sod->name); } if( status != SANE_STATUS_GOOD ) { handleSaneErrors("Cannot set no to", sod->name, status, paramSetRet); updateScanProgress(uuid, SCAN_ERRO_FROM_SCANNER, status); return 0; } if ( paramSetRet & SANE_INFO_RELOAD_OPTIONS ) { //start from the beginning again. option = 0; } } // setable option } else { o_log(DEBUGM, "The option does not need to be set."); } } // options loop return 1; }