SANE_Status soapht_read(SANE_Handle handle, SANE_Byte *data, SANE_Int maxLength, SANE_Int *length) { struct soap_session *ps = (struct soap_session *)handle; int ret, stat=SANE_STATUS_IO_ERROR; DBG8("sane_hpaio_read() handle=%p data=%p maxLength=%d\n", (void *)handle, data, maxLength); if(ps->user_cancel) { DBG8("soapht_read() EVENT_SCAN_CANCEL****uri=%s\n", ps->uri); SendScanEvent(ps->uri, EVENT_SCAN_CANCEL); return SANE_STATUS_CANCELLED; } ret = get_ip_data(ps, data, maxLength, length); if(ret & (IP_INPUT_ERROR | IP_FATAL_ERROR)) { BUG("ipConvert error=%x\n", ret); goto bugout; } if (ret & IP_DONE) { stat = SANE_STATUS_EOF; SendScanEvent(ps->uri, EVENT_END_SCAN_JOB); } else stat = SANE_STATUS_GOOD; bugout: if (stat != SANE_STATUS_GOOD) { if (ps->ip_handle) { /* Note always call ipClose when SANE_STATUS_EOF, do not depend on sane_cancel because sane_cancel is only called at the end of a batch job. */ ipClose(ps->ip_handle); ps->ip_handle = 0; } ps->bb_end_page(ps, 0); } DBG8("-sane_hpaio_read() output=%p bytes_read=%d maxLength=%d status=%d\n", data, *length, maxLength, stat); return stat; } /* soapht_read */
const SANE_Option_Descriptor *soapht_get_option_descriptor(SANE_Handle handle, SANE_Int option) { struct soap_session *ps = (struct soap_session *)handle; DBG8("sane_hpaio_get_option_descriptor(option=%s)\n", ps->option[option].name); if (option < 0 || option >= SOAP_OPTION_MAX) return NULL; return &ps->option[option]; } /* soapht_get_option_descriptor */
SANE_Status soapht_get_parameters(SANE_Handle handle, SANE_Parameters *params) { struct soap_session *ps = (struct soap_session *)handle; set_extents(ps); /* Get scan parameters for sane client. */ ps->bb_get_parameters(ps, params, ps->ip_handle ? SPO_STARTED : SPO_BEST_GUESS); DBG8("sane_hpaio_get_parameters(): format=%d, last_frame=%d, lines=%d, depth=%d, pixels_per_line=%d, bytes_per_line=%d\n", params->format, params->last_frame, params->lines, params->depth, params->pixels_per_line, params->bytes_per_line); return SANE_STATUS_GOOD; } /* soapht_get_parameters */
void ledm_cancel(SANE_Handle handle) { struct ledm_session *ps = (struct ledm_session *)handle; DBG8("sane_hpaio_cancel()\n"); ps -> user_cancel = 1; /* Sane_cancel is always called at the end of the scan job. Note that on a multiple page scan job sane_cancel is called only once */ if (ps->ip_handle) { ipClose(ps->ip_handle); ps->ip_handle = 0; } bb_end_scan(ps, 0); } /* ledm_cancel */
void soapht_cancel(SANE_Handle handle) { struct soap_session *ps = (struct soap_session *)handle; DBG8("sane_hpaio_cancel()\n"); /* * Sane_cancel is always called at the end of the scan job. Note that on a multiple page scan job * sane_cancel is called only once. */ ps -> user_cancel = 1; if (ps->ip_handle) { ipClose(ps->ip_handle); ps->ip_handle = 0; } ps->bb_end_scan(ps, 0); } /* soapht_cancel */
void soapht_close(SANE_Handle handle) { struct soap_session *ps = (struct soap_session *)handle; DBG8("sane_hpaio_close()\n"); if (ps == NULL || ps != session) { BUG("invalid sane_close\n"); return; } ps->bb_close(ps); bb_unload(ps); if (ps->dd > 0) hpmud_close_device(ps->dd); free(ps); session = NULL; } /* saneht_close */
SANE_Status soapht_start(SANE_Handle handle) { struct soap_session *ps = (struct soap_session *)handle; SANE_Parameters pp; IP_IMAGE_TRAITS traits; IP_XFORM_SPEC xforms[IP_MAX_XFORMS], *pXform=xforms; int stat, ret; DBG8("sane_hpaio_start()\n"); ps -> user_cancel = 0; ps -> cnt = 0; ps -> index = 0; if (set_extents(ps)) { BUG("invalid extents: tlx=%d brx=%d tly=%d bry=%d minwidth=%d minheight%d maxwidth=%d maxheight=%d\n", ps->currentTlx, ps->currentTly, ps->currentBrx, ps->currentBry, ps->min_width, ps->min_height, ps->tlxRange.max, ps->tlyRange.max); stat = SANE_STATUS_INVAL; goto bugout; } /* If input is ADF and ADF is empty, return SANE_STATUS_NO_DOCS. */ if (ps->currentInputSource==IS_ADF || ps->currentInputSource==IS_ADF_DUPLEX) { ret = ps->bb_is_paper_in_adf(ps); /* 0 = no paper in adf, 1 = paper in adf, -1 = error */ if (ret == 0) { stat = SANE_STATUS_NO_DOCS; /* done scanning */ SendScanEvent (ps->uri, EVENT_SCAN_ADF_NO_DOCS); goto bugout; } else if (ret < 0) { stat = SANE_STATUS_IO_ERROR; goto bugout; } } /* Start scan and get actual image traits. */ if (ps->bb_start_scan(ps)) { stat = SANE_STATUS_IO_ERROR; goto bugout; } SendScanEvent(ps->uri, EVENT_START_SCAN_JOB); memset(xforms, 0, sizeof(xforms)); /* Setup image-processing pipeline for xform. */ if (ps->currentScanMode == CE_RGB24 || ps->currentScanMode == CE_GRAY8) { switch(ps->currentCompression) { case SF_JFIF: pXform->aXformInfo[IP_JPG_DECODE_FROM_DENALI].dword = 0; /* 0=no */ ADD_XFORM(X_JPG_DECODE); pXform->aXformInfo[IP_CNV_COLOR_SPACE_WHICH_CNV].dword = IP_CNV_YCC_TO_SRGB; pXform->aXformInfo[IP_CNV_COLOR_SPACE_GAMMA].dword = 0x00010000; ADD_XFORM(X_CNV_COLOR_SPACE); break; case SF_HPRAW: default: break; } } else { /* Must be BLACK_AND_WHITE1 (Lineart). */ switch(ps->currentCompression) { case SF_JFIF: pXform->aXformInfo[IP_JPG_DECODE_FROM_DENALI].dword = 0; /* 0=no */ ADD_XFORM(X_JPG_DECODE); pXform->aXformInfo[IP_GRAY_2_BI_THRESHOLD].dword = 127; ADD_XFORM(X_GRAY_2_BI); break; case SF_HPRAW: pXform->aXformInfo[IP_GRAY_2_BI_THRESHOLD].dword = 127; ADD_XFORM(X_GRAY_2_BI); default: break; } } /* Setup x/y cropping for xform. (Actually we let cm1017 do it's own cropping) */ pXform->aXformInfo[IP_CROP_LEFT].dword = 0; pXform->aXformInfo[IP_CROP_RIGHT].dword = 0; pXform->aXformInfo[IP_CROP_TOP].dword = 0; pXform->aXformInfo[IP_CROP_MAXOUTROWS].dword = 0; ADD_XFORM(X_CROP); /* Setup x/y padding for xform. (Actually we let cm1017 do it's own padding) */ pXform->aXformInfo[IP_PAD_LEFT].dword = 0; /* # of pixels to add to left side */ pXform->aXformInfo[IP_PAD_RIGHT].dword = 0; /* # of pixels to add to right side */ pXform->aXformInfo[IP_PAD_TOP].dword = 0; /* # of rows to add to top */ pXform->aXformInfo[IP_PAD_BOTTOM].dword = 0; /* # of rows to add to bottom */ pXform->aXformInfo[IP_PAD_VALUE].dword = ps->currentScanMode == CE_BLACK_AND_WHITE1 ? 0 : -1; /* lineart white = 0, rgb white = -1 */ pXform->aXformInfo[IP_PAD_MIN_HEIGHT].dword = 0; ADD_XFORM(X_PAD); /* Open image processor. */ if ((ret = ipOpen(pXform-xforms, xforms, 0, &ps->ip_handle)) != IP_DONE) { BUG("unable open image processor: err=%d\n", ret); stat = SANE_STATUS_INVAL; goto bugout; } /* Get scan parameters for image processor. */ if (ps->currentCompression == SF_HPRAW) ps->bb_get_parameters(ps, &pp, SPO_STARTED_JR); /* hpraw, use actual parameters */ else ps->bb_get_parameters(ps, &pp, SPO_BEST_GUESS); /* jpeg, use best guess */ traits.iPixelsPerRow = pp.pixels_per_line; switch(ps->currentScanMode) { case CE_BLACK_AND_WHITE1: /* lineart (let IP create Mono from Gray8) */ case CE_GRAY8: traits.iBitsPerPixel = 8; /* grayscale */ break; case CE_RGB24: default: traits.iBitsPerPixel = 24; /* color */ break; } traits.lHorizDPI = ps->currentResolution << 16; traits.lVertDPI = ps->currentResolution << 16; traits.lNumRows = pp.lines; traits.iNumPages = 1; traits.iPageNum = 1; traits.iComponentsPerPixel = ((traits.iBitsPerPixel % 3) ? 1 : 3); ipSetDefaultInputTraits(ps->ip_handle, &traits); /* If jpeg get output image attributes from the image processor. */ if (ps->currentCompression == SF_JFIF) { /* Enable parsed header flag. */ ipResultMask(ps->ip_handle, IP_PARSED_HEADER); /* Wait for image processor to process header so we know the exact size of the image for sane_get_params. */ while (1) { ret = get_ip_data(ps, NULL, 0, NULL); if (ret & (IP_INPUT_ERROR | IP_FATAL_ERROR | IP_DONE)) { BUG("ipConvert error=%x\n", ret); stat = SANE_STATUS_IO_ERROR; goto bugout; } if (ret & IP_PARSED_HEADER) { ipGetImageTraits(ps->ip_handle, NULL, &ps->image_traits); /* get valid image traits */ ipResultMask(ps->ip_handle, 0); /* disable parsed header flag */ break; } } } else ipGetImageTraits(ps->ip_handle, NULL, &ps->image_traits); /* get valid image traits */ stat = SANE_STATUS_GOOD; bugout: if (stat != SANE_STATUS_GOOD) { if (ps->ip_handle) { ipClose(ps->ip_handle); ps->ip_handle = 0; } ps->bb_end_scan(ps, stat == SANE_STATUS_IO_ERROR ? 1: 0); } return stat; } /* soapht_start */
SANE_Status soapht_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *value, SANE_Int *set_result) { struct soap_session *ps = (struct soap_session *)handle; SANE_Int *int_value = value, mset_result=0; int i, stat=SANE_STATUS_INVAL; char sz[64]; switch(option) { case SOAP_OPTION_COUNT: if (action == SANE_ACTION_GET_VALUE) { *int_value = SOAP_OPTION_MAX; stat = SANE_STATUS_GOOD; } break; case SOAP_OPTION_SCAN_MODE: if (action == SANE_ACTION_GET_VALUE) { for (i=0; ps->scanModeList[i]; i++) { if (ps->currentScanMode == ps->scanModeMap[i]) { strcpy(value, ps->scanModeList[i]); stat = SANE_STATUS_GOOD; break; } } } else if (action == SANE_ACTION_SET_VALUE) { for (i=0; ps->scanModeList[i]; i++) { if (strcasecmp(ps->scanModeList[i], value) == 0) { ps->currentScanMode = ps->scanModeMap[i]; set_scan_mode_side_effects(ps, ps->currentScanMode); mset_result |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; stat = SANE_STATUS_GOOD; break; } } } else { /* Set default. */ ps->currentScanMode = ps->scanModeMap[0]; set_scan_mode_side_effects(ps, ps->currentScanMode); stat = SANE_STATUS_GOOD; } break; case SOAP_OPTION_INPUT_SOURCE: if (action == SANE_ACTION_GET_VALUE) { for (i=0; ps->inputSourceList[i]; i++) { if (ps->currentInputSource == ps->inputSourceMap[i]) { strcpy(value, ps->inputSourceList[i]); stat = SANE_STATUS_GOOD; break; } } } else if (action == SANE_ACTION_SET_VALUE) { for (i=0; ps->inputSourceList[i]; i++) { if (strcasecmp(ps->inputSourceList[i], value) == 0) { ps->currentInputSource = ps->inputSourceMap[i]; set_input_source_side_effects(ps, ps->currentInputSource); if(ps->currentInputSource == IS_ADF || ps->currentInputSource == IS_ADF_DUPLEX) { i = ps->adf_resolutionList[0] + 1; while(i--) ps->resolutionList[i] = ps->adf_resolutionList[i]; } else //if(ps->currentInputSource == IS_PLATEN) { i = ps->platen_resolutionList[0] + 1; while(i--) ps->resolutionList[i] = ps->platen_resolutionList[i]; } mset_result |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; stat = SANE_STATUS_GOOD; break; } } } else { /* Set default. */ ps->currentInputSource = ps->inputSourceMap[0]; set_input_source_side_effects(ps, ps->currentInputSource); mset_result |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; stat = SANE_STATUS_GOOD; } break; case SOAP_OPTION_SCAN_RESOLUTION: if (action == SANE_ACTION_GET_VALUE) { *int_value = ps->currentResolution; stat = SANE_STATUS_GOOD; } else if (action == SANE_ACTION_SET_VALUE) { for (i=1; i <= ps->resolutionList[0]; i++) { if (ps->resolutionList[i] == *int_value) { ps->currentResolution = *int_value; mset_result |= SANE_INFO_RELOAD_PARAMS; stat = SANE_STATUS_GOOD; break; } } if (stat != SANE_STATUS_GOOD) { ps->currentResolution = ps->resolutionList[1]; stat = SANE_STATUS_GOOD; } } else { /* Set default. */ ps->currentResolution = 75; stat = SANE_STATUS_GOOD; } break; case SOAP_OPTION_CONTRAST: if (action == SANE_ACTION_GET_VALUE) { *int_value = ps->currentContrast; stat = SANE_STATUS_GOOD; } else if (action == SANE_ACTION_SET_VALUE) { if (*int_value >= SOAP_CONTRAST_MIN && *int_value <= SOAP_CONTRAST_MAX) { ps->currentContrast = *int_value; } else { ps->currentContrast = SOAP_CONTRAST_DEFAULT; } mset_result |= SANE_INFO_RELOAD_PARAMS; stat = SANE_STATUS_GOOD; } else { /* Set default. */ ps->currentContrast = SOAP_CONTRAST_DEFAULT; stat = SANE_STATUS_GOOD; } break; case SOAP_OPTION_BRIGHTNESS: if (action == SANE_ACTION_GET_VALUE) { *int_value = ps->currentBrightness; stat = SANE_STATUS_GOOD; } else if (action == SANE_ACTION_SET_VALUE) { if (*int_value >= SOAP_BRIGHTNESS_MIN && *int_value <= SOAP_BRIGHTNESS_MAX) { ps->currentBrightness = *int_value; } else { ps->currentBrightness = SOAP_BRIGHTNESS_DEFAULT; } stat = SANE_STATUS_GOOD; } else { /* Set default. */ ps->currentBrightness = SOAP_BRIGHTNESS_DEFAULT; stat = SANE_STATUS_GOOD; } break; case SOAP_OPTION_COMPRESSION: if (action == SANE_ACTION_GET_VALUE) { for (i=0; ps->compressionList[i]; i++) { if (ps->currentCompression == ps->compressionMap[i]) { strcpy(value, ps->compressionList[i]); stat = SANE_STATUS_GOOD; break; } } } else if (action == SANE_ACTION_SET_VALUE) { for (i=0; ps->compressionList[i]; i++) { if (strcasecmp(ps->compressionList[i], value) == 0) { ps->currentCompression = ps->compressionMap[i]; stat = SANE_STATUS_GOOD; break; } } } else { /* Set default. */ ps->currentCompression = SF_JFIF; stat = SANE_STATUS_GOOD; } break; case SOAP_OPTION_JPEG_QUALITY: if (action == SANE_ACTION_GET_VALUE) { *int_value = ps->currentJpegQuality; stat = SANE_STATUS_GOOD; } else if (action == SANE_ACTION_SET_VALUE) { if (*int_value >= MIN_JPEG_COMPRESSION_FACTOR && *int_value <= MAX_JPEG_COMPRESSION_FACTOR) { ps->currentJpegQuality = *int_value; stat = SANE_STATUS_GOOD; break; } } else { /* Set default. */ ps->currentJpegQuality = SAFER_JPEG_COMPRESSION_FACTOR; stat = SANE_STATUS_GOOD; } break; case SOAP_OPTION_TL_X: if (action == SANE_ACTION_GET_VALUE) { *int_value = ps->currentTlx; stat = SANE_STATUS_GOOD; } else if (action == SANE_ACTION_SET_VALUE) { if (*int_value >= ps->tlxRange.min && *int_value <= ps->tlxRange.max) { ps->currentTlx = *int_value; mset_result |= SANE_INFO_RELOAD_PARAMS; stat = SANE_STATUS_GOOD; break; } } else { /* Set default. */ ps->currentTlx = ps->tlxRange.min; stat = SANE_STATUS_GOOD; } break; case SOAP_OPTION_TL_Y: if (action == SANE_ACTION_GET_VALUE) { *int_value = ps->currentTly; stat = SANE_STATUS_GOOD; } else if (action == SANE_ACTION_SET_VALUE) { if (*int_value >= ps->tlyRange.min && *int_value <= ps->tlyRange.max) { ps->currentTly = *int_value; mset_result |= SANE_INFO_RELOAD_PARAMS; stat = SANE_STATUS_GOOD; break; } } else { /* Set default. */ ps->currentTly = ps->tlyRange.min; stat = SANE_STATUS_GOOD; } break; case SOAP_OPTION_BR_X: if (action == SANE_ACTION_GET_VALUE) { *int_value = ps->currentBrx; stat = SANE_STATUS_GOOD; } else if (action == SANE_ACTION_SET_VALUE) { if (*int_value >= ps->brxRange.min && *int_value <= ps->brxRange.max) { ps->currentBrx = *int_value; mset_result |= SANE_INFO_RELOAD_PARAMS; stat = SANE_STATUS_GOOD; break; } } else { /* Set default. */ ps->currentBrx = ps->brxRange.max; stat = SANE_STATUS_GOOD; } break; case SOAP_OPTION_BR_Y: if (action == SANE_ACTION_GET_VALUE) { *int_value = ps->currentBry; stat = SANE_STATUS_GOOD; } else if (action == SANE_ACTION_SET_VALUE) { if (*int_value >= ps->bryRange.min && *int_value <= ps->bryRange.max) { ps->currentBry = *int_value; mset_result |= SANE_INFO_RELOAD_PARAMS; stat = SANE_STATUS_GOOD; break; } } else { /* Set default. */ ps->currentBry = ps->bryRange.max; stat = SANE_STATUS_GOOD; } break; default: break; } if (set_result) *set_result = mset_result; if (stat != SANE_STATUS_GOOD) { BUG("control_option failed: option=%s action=%s\n", ps->option[option].name, action==SANE_ACTION_GET_VALUE ? "get" : action==SANE_ACTION_SET_VALUE ? "set" : "auto"); } DBG8("sane_hpaio_control_option (option=%s action=%s value=%s)\n", ps->option[option].name, action==SANE_ACTION_GET_VALUE ? "get" : action==SANE_ACTION_SET_VALUE ? "set" : "auto", value ? ps->option[option].type == SANE_TYPE_STRING ? (char *)value : psnprintf(sz, sizeof(sz), "%d", *(int *)value) : "na"); return stat; } /* soapht_control_option */
SANE_Status soapht_open(SANE_String_Const device, SANE_Handle *handle) { struct hpmud_model_attributes ma; int i, stat = SANE_STATUS_IO_ERROR; DBG8("sane_hpaio_open(%s)\n", device); if (session) { BUG("session in use\n"); return SANE_STATUS_DEVICE_BUSY; } if ((session = create_session()) == NULL) return SANE_STATUS_NO_MEM; /* Set session to specified device. */ snprintf(session->uri, sizeof(session->uri)-1, "hp:%s", device); /* prepend "hp:" */ /* Get actual model attributes from models.dat. */ hpmud_query_model(session->uri, &ma); session->scan_type = ma.scantype; if (hpmud_open_device(session->uri, ma.mfp_mode, &session->dd) != HPMUD_R_OK) { BUG("unable to open device %s\n", session->uri); goto bugout; free(session); session = NULL; return SANE_STATUS_IO_ERROR; } if (bb_load(session, SCAN_PLUGIN_SOAPHT)) { stat = SANE_STATUS_IO_ERROR; goto bugout; } /* Init sane option descriptors. */ init_options(session); if (session->bb_open(session)) { stat = SANE_STATUS_IO_ERROR; goto bugout; } /* Set supported Scan Modes as determined by bb_open. */ soapht_control_option(session, SOAP_OPTION_SCAN_MODE, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */ /* Set scan input sources as determined by bb_open. */ soapht_control_option(session, SOAP_OPTION_INPUT_SOURCE, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */ /* Set supported resolutions. */ soapht_control_option(session, SOAP_OPTION_SCAN_RESOLUTION, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */ /* Set supported brightness. */ soapht_control_option(session, SOAP_OPTION_BRIGHTNESS, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */ /* Set supported contrast. */ soapht_control_option(session, SOAP_OPTION_CONTRAST, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */ /* Set supported compression. (Note, cm1017 may say it supports MMR, but it doesn't) */ soapht_control_option(session, SOAP_OPTION_COMPRESSION, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */ /* Determine supported jpeg quality factor as determined by bb_open. */ soapht_control_option(session, SOAP_OPTION_JPEG_QUALITY, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */ /* Set x,y extents. See bb_open */ soapht_control_option(session, SOAP_OPTION_TL_X, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */ soapht_control_option(session, SOAP_OPTION_TL_Y, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */ soapht_control_option(session, SOAP_OPTION_BR_X, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */ soapht_control_option(session, SOAP_OPTION_BR_Y, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */ *handle = (SANE_Handle *)session; stat = SANE_STATUS_GOOD; bugout: if (stat != SANE_STATUS_GOOD) { if (session) { bb_unload(session); if (session->dd > 0) hpmud_close_device(session->dd); free(session); session = NULL; } } return stat; } /* saneht_open */