~ubuntu-branches/ubuntu/raring/hplip/raring-proposed

« back to all changes in this revision

Viewing changes to .pc/try_libhpmud.so.0.dpatch/scan/sane/soap.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2012-05-26 11:20:39 UTC
  • mfrom: (1.5.6) (31.1.3 precise)
  • Revision ID: package-import@ubuntu.com-20120526112039-bevxczegxnbyr5m7
Tags: 3.12.4-1
* New upstream release
* Switch to source/format 3.0 (quilt) - drop dpatch
* Refreshed debian/patches
* dh_autoreconf debian/autogen.sh & set local-options single-debian-patch
* Update to debian/compat -> 9
* Fix "hardened build flags" patch from Moritz - thanks (Closes: #667828)
* Fix "duplex descriptor uninitialized" patch from Matej (Closes: #583273)
* Fix "please migrate to kde-runtime" patch from Pino (Closes: #666544)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/************************************************************************************\
 
2
 
 
3
  soap.c - HP SANE backend support for soap based multi-function peripherals
 
4
 
 
5
  (c) 2006,2008 Copyright Hewlett-Packard Development Company, LP
 
6
 
 
7
  Permission is hereby granted, free of charge, to any person obtaining a copy 
 
8
  of this software and associated documentation files (the "Software"), to deal 
 
9
  in the Software without restriction, including without limitation the rights 
 
10
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
 
11
  of the Software, and to permit persons to whom the Software is furnished to do 
 
12
  so, subject to the following conditions:
 
13
 
 
14
  The above copyright notice and this permission notice shall be included in all
 
15
  copies or substantial portions of the Software.
 
16
 
 
17
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 
18
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 
 
19
  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 
 
20
  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
 
21
  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
 
22
  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
23
 
 
24
  Note the CLJ CM1017 windows driver supports jpeg, but no hpraw (over the wire).
 
25
  The problem is hpraw does not return bytes_per_line and number_of_lines at the
 
26
  start of the scan job. Even though we perform the same calculation as firmware
 
27
  for hpraw, due to round-off error between different math libraries determining 
 
28
  the correct bytes_per_line is not always possible (especially at 600dpi and 1200dpi). 
 
29
 
 
30
  Also the CM1017 linart mode only works with hpraw (over the wire).
 
31
 
 
32
  Given the hpraw problem stated above this driver will only support jpeg for all scan
 
33
  modes. Linart will use 8-bit gray then convert to mono. Same as windows.
 
34
 
 
35
  Author: David Suffield
 
36
 
 
37
\************************************************************************************/
 
38
 
 
39
#ifndef _GNU_SOURCE
 
40
#define _GNU_SOURCE
 
41
#endif
 
42
 
 
43
#include <stdarg.h>
 
44
#include <syslog.h>
 
45
#include <stdio.h>
 
46
#include <string.h>
 
47
#include <unistd.h>
 
48
#include <fcntl.h>
 
49
#include <math.h>
 
50
#include <dlfcn.h>
 
51
#include "sane.h"
 
52
#include "saneopts.h"
 
53
#include "hpmud.h"
 
54
#include "hpip.h"
 
55
#include "common.h"
 
56
#include "soap.h"
 
57
#include "soapi.h"
 
58
#include "io.h"
 
59
 
 
60
#define DEBUG_DECLARE_ONLY
 
61
#include "sanei_debug.h"
 
62
 
 
63
static struct soap_session *session = NULL;   /* assume one sane_open per process */
 
64
 
 
65
static int bb_load(struct soap_session *ps, const char *so)
 
66
{
 
67
   char home[128];
 
68
   char sz[255]; 
 
69
   int stat=1;
 
70
 
 
71
   /* Load hpmud manually with symbols exported. Otherwise the plugin will not find it. */ 
 
72
   if ((ps->hpmud_handle = dlopen("libhpmud.so", RTLD_LAZY|RTLD_GLOBAL)) == NULL)
 
73
   {
 
74
      BUG("unable to load restricted library: %s\n", dlerror());
 
75
      goto bugout;
 
76
   } 
 
77
 
 
78
   /* Load math library manually with symbols exported (Ubuntu 8.04). Otherwise the plugin will not find it. */ 
 
79
   if ((ps->math_handle = dlopen("libm.so", RTLD_LAZY|RTLD_GLOBAL)) == NULL)
 
80
   {
 
81
      if ((ps->math_handle = dlopen("libm.so.6", RTLD_LAZY|RTLD_GLOBAL)) == NULL)
 
82
      {
 
83
         BUG("unable to load restricted library: %s\n", dlerror());
 
84
         goto bugout;
 
85
      }
 
86
   } 
 
87
 
 
88
   if (hpmud_get_conf("[dirs]", "home", home, sizeof(home)) != HPMUD_R_OK)
 
89
      goto bugout;
 
90
   snprintf(sz, sizeof(sz), "%s/scan/plugins/%s", home, so);
 
91
   if ((ps->bb_handle = dlopen(sz, RTLD_NOW|RTLD_GLOBAL)) == NULL)
 
92
   {
 
93
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
94
      SendScanEvent(ps->uri, EVENT_PLUGIN_FAIL);
 
95
      goto bugout;
 
96
   } 
 
97
   
 
98
   if ((ps->bb_open = dlsym(ps->bb_handle, "bb_open")) == NULL)
 
99
   {
 
100
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
101
      goto bugout;
 
102
   } 
 
103
   if ((ps->bb_close = dlsym(ps->bb_handle, "bb_close")) == NULL)
 
104
   {
 
105
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
106
      goto bugout;
 
107
   } 
 
108
   if ((ps->bb_get_parameters = dlsym(ps->bb_handle, "bb_get_parameters")) == NULL)
 
109
   {
 
110
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
111
      goto bugout;
 
112
   } 
 
113
   if ((ps->bb_is_paper_in_adf = dlsym(ps->bb_handle, "bb_is_paper_in_adf")) == NULL)
 
114
   {
 
115
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
116
      goto bugout;
 
117
   } 
 
118
   if ((ps->bb_start_scan = dlsym(ps->bb_handle, "bb_start_scan")) == NULL)
 
119
   {
 
120
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
121
      goto bugout;
 
122
   } 
 
123
   if ((ps->bb_end_scan = dlsym(ps->bb_handle, "bb_end_scan")) == NULL)
 
124
   {
 
125
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
126
      goto bugout;
 
127
   } 
 
128
   if ((ps->bb_get_image_data = dlsym(ps->bb_handle, "bb_get_image_data")) == NULL)
 
129
   {
 
130
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
131
      goto bugout;
 
132
   } 
 
133
   if ((ps->bb_end_page = dlsym(ps->bb_handle, "bb_end_page")) == NULL)
 
134
   {
 
135
      BUG("unable to load restricted library %s: %s\n", sz, dlerror());
 
136
      goto bugout;
 
137
   } 
 
138
 
 
139
   stat=0;
 
140
 
 
141
bugout:
 
142
   return stat;
 
143
} /* bb_load */
 
144
 
 
145
static int bb_unload(struct soap_session *ps)
 
146
{
 
147
   if (ps->bb_handle)
 
148
   {   
 
149
      dlclose(ps->bb_handle);
 
150
      ps->bb_handle = NULL;
 
151
   }  
 
152
   if (ps->hpmud_handle)
 
153
   {   
 
154
      dlclose(ps->hpmud_handle);
 
155
      ps->hpmud_handle = NULL;
 
156
   }  
 
157
   if (ps->math_handle)
 
158
   {   
 
159
      dlclose(ps->math_handle);
 
160
      ps->math_handle = NULL;
 
161
   }  
 
162
   return 0;
 
163
} /* bb_unload */
 
164
 
 
165
/* Get raw data (ie: uncompressed data) from image processor. */
 
166
static int get_ip_data(struct soap_session *ps, SANE_Byte *data, SANE_Int maxLength, SANE_Int *length)
 
167
{
 
168
   int ip_ret=IP_INPUT_ERROR;
 
169
   unsigned int outputAvail=maxLength, outputUsed=0, outputThisPos;
 
170
   unsigned char *input, *output = data;
 
171
   unsigned int inputAvail, inputUsed=0, inputNextPos;
 
172
 
 
173
   if (!ps->ip_handle)
 
174
   {
 
175
      BUG("invalid ipconvert state\n");
 
176
      goto bugout;
 
177
   }      
 
178
 
 
179
   if (ps->bb_get_image_data(ps, outputAvail))
 
180
      goto bugout;
 
181
 
 
182
   if (ps->cnt > 0)
 
183
   {
 
184
      inputAvail = ps->cnt;
 
185
      input = &ps->buf[ps->index];
 
186
   }
 
187
   else
 
188
   {
 
189
      input = NULL;   /* no more scan data, flush ipconvert pipeline */
 
190
      inputAvail = 0;
 
191
   }
 
192
 
 
193
   /* Transform input data to output. Note, output buffer may consume more bytes than input buffer (ie: jpeg to raster). */
 
194
   ip_ret = ipConvert(ps->ip_handle, inputAvail, input, &inputUsed, &inputNextPos, outputAvail, output, &outputUsed, &outputThisPos);
 
195
 
 
196
   DBG6("cnt=%d index=%d input=%p inputAvail=%d inputUsed=%d inputNextPos=%d output=%p outputAvail=%d outputThisPos=%d\n", ps->cnt, ps->index, input, 
 
197
         inputAvail, inputUsed, inputNextPos, output, outputAvail, outputThisPos);
 
198
 
 
199
   if (input != NULL)
 
200
   {
 
201
      if (inputAvail == inputUsed)
 
202
      {
 
203
         ps->index = ps->cnt = 0;   /* reset buffer */
 
204
      }
 
205
      else
 
206
      {
 
207
         ps->cnt -= inputUsed;    /* save left over buffer for next soap_read */
 
208
         ps->index += inputUsed;
 
209
      }
 
210
   }
 
211
 
 
212
   if (data)
 
213
      *length = outputUsed;
 
214
 
 
215
   /* For sane do not send output data simultaneously with IP_DONE. */
 
216
   if (ip_ret & IP_DONE && outputUsed)
 
217
      ip_ret &= ~IP_DONE;                               
 
218
 
 
219
bugout:
 
220
   return ip_ret;
 
221
} /* get_ip_data */
 
222
 
 
223
static int set_scan_mode_side_effects(struct soap_session *ps, enum COLOR_ENTRY scanMode)
 
224
{
 
225
   int j=0;
 
226
 
 
227
   memset(ps->compressionList, 0, sizeof(ps->compressionList));
 
228
   memset(ps->compressionMap, 0, sizeof(ps->compressionMap));
 
229
 
 
230
   switch (scanMode)
 
231
   {
 
232
      case CE_BLACK_AND_WHITE1:
 
233
      case CE_GRAY8:
 
234
      case CE_RGB24:
 
235
      default:
 
236
         ps->compressionList[j] = STR_COMPRESSION_JPEG; 
 
237
         ps->compressionMap[j++] = SF_JFIF;
 
238
         ps->currentCompression = SF_JFIF;
 
239
         ps->option[SOAP_OPTION_JPEG_QUALITY].cap |= SANE_CAP_SOFT_SELECT;   /* enable jpeg quality */        
 
240
         break;
 
241
   }
 
242
 
 
243
   return 0;
 
244
} /* set_scan_mode_side_effects */
 
245
 
 
246
static struct soap_session *create_session()
 
247
{
 
248
   struct soap_session *ps;
 
249
 
 
250
   if ((ps = malloc(sizeof(struct soap_session))) == NULL)
 
251
   {
 
252
      BUG("malloc failed: %m\n");
 
253
      return NULL;
 
254
   }
 
255
   memset(ps, 0, sizeof(struct soap_session));
 
256
   ps->tag = "SOAP";
 
257
   ps->dd = -1;
 
258
   ps->cd = -1;
 
259
 
 
260
   return ps;
 
261
} /* create_session */
 
262
 
 
263
static int init_options(struct soap_session *ps)
 
264
{
 
265
   ps->option[SOAP_OPTION_COUNT].name = "option-cnt";
 
266
   ps->option[SOAP_OPTION_COUNT].title = SANE_TITLE_NUM_OPTIONS;
 
267
   ps->option[SOAP_OPTION_COUNT].desc = SANE_DESC_NUM_OPTIONS;
 
268
   ps->option[SOAP_OPTION_COUNT].type = SANE_TYPE_INT;
 
269
   ps->option[SOAP_OPTION_COUNT].unit = SANE_UNIT_NONE;
 
270
   ps->option[SOAP_OPTION_COUNT].size = sizeof(SANE_Int);
 
271
   ps->option[SOAP_OPTION_COUNT].cap = SANE_CAP_SOFT_DETECT;
 
272
   ps->option[SOAP_OPTION_COUNT].constraint_type = SANE_CONSTRAINT_NONE;
 
273
 
 
274
   ps->option[SOAP_OPTION_GROUP_SCAN_MODE].name = "mode-group";
 
275
   ps->option[SOAP_OPTION_GROUP_SCAN_MODE].title = SANE_TITLE_SCAN_MODE;
 
276
   ps->option[SOAP_OPTION_GROUP_SCAN_MODE].type = SANE_TYPE_GROUP;
 
277
 
 
278
   ps->option[SOAP_OPTION_SCAN_MODE].name = SANE_NAME_SCAN_MODE;
 
279
   ps->option[SOAP_OPTION_SCAN_MODE].title = SANE_TITLE_SCAN_MODE;
 
280
   ps->option[SOAP_OPTION_SCAN_MODE].desc = SANE_DESC_SCAN_MODE;
 
281
   ps->option[SOAP_OPTION_SCAN_MODE].type = SANE_TYPE_STRING;
 
282
   ps->option[SOAP_OPTION_SCAN_MODE].unit = SANE_UNIT_NONE;
 
283
   ps->option[SOAP_OPTION_SCAN_MODE].size = MAX_STRING_SIZE;
 
284
   ps->option[SOAP_OPTION_SCAN_MODE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 
285
   ps->option[SOAP_OPTION_SCAN_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 
286
   ps->option[SOAP_OPTION_SCAN_MODE].constraint.string_list = ps->scanModeList;
 
287
 
 
288
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION;
 
289
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION;
 
290
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION;
 
291
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].type = SANE_TYPE_INT;
 
292
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].unit = SANE_UNIT_DPI;
 
293
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].size = sizeof(SANE_Int);
 
294
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 
295
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST;
 
296
   ps->option[SOAP_OPTION_SCAN_RESOLUTION].constraint.word_list = ps->resolutionList;
 
297
 
 
298
   ps->option[SOAP_OPTION_GROUP_ADVANCED].name = "advanced-group";
 
299
   ps->option[SOAP_OPTION_GROUP_ADVANCED].title = STR_TITLE_ADVANCED;
 
300
   ps->option[SOAP_OPTION_GROUP_ADVANCED].type = SANE_TYPE_GROUP;
 
301
   ps->option[SOAP_OPTION_GROUP_ADVANCED].cap = SANE_CAP_ADVANCED;
 
302
 
 
303
   ps->option[SOAP_OPTION_CONTRAST].name = SANE_NAME_CONTRAST;
 
304
   ps->option[SOAP_OPTION_CONTRAST].title = SANE_TITLE_CONTRAST;
 
305
   ps->option[SOAP_OPTION_CONTRAST].desc = SANE_DESC_CONTRAST;
 
306
   ps->option[SOAP_OPTION_CONTRAST].type = SANE_TYPE_INT;
 
307
   ps->option[SOAP_OPTION_CONTRAST].unit = SANE_UNIT_NONE;
 
308
   ps->option[SOAP_OPTION_CONTRAST].size = sizeof(SANE_Int);
 
309
   ps->option[SOAP_OPTION_CONTRAST].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
 
310
   ps->option[SOAP_OPTION_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE;
 
311
   ps->option[SOAP_OPTION_CONTRAST].constraint.range = &ps->contrastRange;
 
312
   ps->contrastRange.min = SOAP_CONTRAST_MIN;
 
313
   ps->contrastRange.max = SOAP_CONTRAST_MAX;
 
314
   ps->contrastRange.quant = 0;
 
315
 
 
316
   ps->option[SOAP_OPTION_COMPRESSION].name = STR_NAME_COMPRESSION;
 
317
   ps->option[SOAP_OPTION_COMPRESSION].title = STR_TITLE_COMPRESSION;
 
318
   ps->option[SOAP_OPTION_COMPRESSION].desc = STR_DESC_COMPRESSION;
 
319
   ps->option[SOAP_OPTION_COMPRESSION].type = SANE_TYPE_STRING;
 
320
   ps->option[SOAP_OPTION_COMPRESSION].unit = SANE_UNIT_NONE;
 
321
   ps->option[SOAP_OPTION_COMPRESSION].size = MAX_STRING_SIZE;
 
322
   ps->option[SOAP_OPTION_COMPRESSION].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
 
323
   ps->option[SOAP_OPTION_COMPRESSION].constraint_type = SANE_CONSTRAINT_STRING_LIST;
 
324
   ps->option[SOAP_OPTION_COMPRESSION].constraint.string_list = ps->compressionList;
 
325
 
 
326
   ps->option[SOAP_OPTION_JPEG_QUALITY].name = STR_NAME_JPEG_QUALITY;
 
327
   ps->option[SOAP_OPTION_JPEG_QUALITY].title = STR_TITLE_JPEG_QUALITY;
 
328
   ps->option[SOAP_OPTION_JPEG_QUALITY].desc = STR_DESC_JPEG_QUALITY;
 
329
   ps->option[SOAP_OPTION_JPEG_QUALITY].type = SANE_TYPE_INT;
 
330
   ps->option[SOAP_OPTION_JPEG_QUALITY].unit = SANE_UNIT_NONE;
 
331
   ps->option[SOAP_OPTION_JPEG_QUALITY].size = sizeof(SANE_Int);
 
332
   ps->option[SOAP_OPTION_JPEG_QUALITY].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED;
 
333
   ps->option[SOAP_OPTION_JPEG_QUALITY].constraint_type = SANE_CONSTRAINT_RANGE;
 
334
   ps->option[SOAP_OPTION_JPEG_QUALITY].constraint.range = &ps->jpegQualityRange;
 
335
   ps->jpegQualityRange.min = MIN_JPEG_COMPRESSION_FACTOR;
 
336
   ps->jpegQualityRange.max = MAX_JPEG_COMPRESSION_FACTOR;
 
337
   ps->jpegQualityRange.quant = 0;
 
338
 
 
339
   ps->option[SOAP_OPTION_GROUP_GEOMETRY].name = "geometry-group";
 
340
   ps->option[SOAP_OPTION_GROUP_GEOMETRY].title = STR_TITLE_GEOMETRY;
 
341
   ps->option[SOAP_OPTION_GROUP_GEOMETRY].type = SANE_TYPE_GROUP;
 
342
   ps->option[SOAP_OPTION_GROUP_GEOMETRY].cap = SANE_CAP_ADVANCED;
 
343
 
 
344
   ps->option[SOAP_OPTION_TL_X].name = SANE_NAME_SCAN_TL_X;
 
345
   ps->option[SOAP_OPTION_TL_X].title = SANE_TITLE_SCAN_TL_X;
 
346
   ps->option[SOAP_OPTION_TL_X].desc = SANE_DESC_SCAN_TL_X;
 
347
   ps->option[SOAP_OPTION_TL_X].type = SANE_TYPE_FIXED;
 
348
   ps->option[SOAP_OPTION_TL_X].unit = SANE_UNIT_MM;
 
349
   ps->option[SOAP_OPTION_TL_X].size = sizeof(SANE_Int);
 
350
   ps->option[SOAP_OPTION_TL_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 
351
   ps->option[SOAP_OPTION_TL_X].constraint_type = SANE_CONSTRAINT_RANGE;
 
352
   ps->option[SOAP_OPTION_TL_X].constraint.range = &ps->tlxRange;
 
353
   ps->tlxRange.min = 0;
 
354
   ps->tlxRange.quant = 0;
 
355
 
 
356
   ps->option[SOAP_OPTION_TL_Y].name = SANE_NAME_SCAN_TL_Y;
 
357
   ps->option[SOAP_OPTION_TL_Y].title = SANE_TITLE_SCAN_TL_Y;
 
358
   ps->option[SOAP_OPTION_TL_Y].desc = SANE_DESC_SCAN_TL_Y;
 
359
   ps->option[SOAP_OPTION_TL_Y].type = SANE_TYPE_FIXED;
 
360
   ps->option[SOAP_OPTION_TL_Y].unit = SANE_UNIT_MM;
 
361
   ps->option[SOAP_OPTION_TL_Y].size = sizeof(SANE_Int);
 
362
   ps->option[SOAP_OPTION_TL_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 
363
   ps->option[SOAP_OPTION_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE;
 
364
   ps->option[SOAP_OPTION_TL_Y].constraint.range = &ps->tlyRange;
 
365
   ps->tlyRange.min = 0;
 
366
   ps->tlyRange.quant = 0;
 
367
 
 
368
   ps->option[SOAP_OPTION_BR_X].name = SANE_NAME_SCAN_BR_X;
 
369
   ps->option[SOAP_OPTION_BR_X].title = SANE_TITLE_SCAN_BR_X;
 
370
   ps->option[SOAP_OPTION_BR_X].desc = SANE_DESC_SCAN_BR_X;
 
371
   ps->option[SOAP_OPTION_BR_X].type = SANE_TYPE_FIXED;
 
372
   ps->option[SOAP_OPTION_BR_X].unit = SANE_UNIT_MM;
 
373
   ps->option[SOAP_OPTION_BR_X].size = sizeof(SANE_Int);
 
374
   ps->option[SOAP_OPTION_BR_X].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 
375
   ps->option[SOAP_OPTION_BR_X].constraint_type = SANE_CONSTRAINT_RANGE;
 
376
   ps->option[SOAP_OPTION_BR_X].constraint.range = &ps->brxRange;
 
377
   ps->brxRange.min = 0;
 
378
   ps->brxRange.quant = 0;
 
379
 
 
380
   ps->option[SOAP_OPTION_BR_Y].name = SANE_NAME_SCAN_BR_Y;
 
381
   ps->option[SOAP_OPTION_BR_Y].title = SANE_TITLE_SCAN_BR_Y;
 
382
   ps->option[SOAP_OPTION_BR_Y].desc = SANE_DESC_SCAN_BR_Y;
 
383
   ps->option[SOAP_OPTION_BR_Y].type = SANE_TYPE_FIXED;
 
384
   ps->option[SOAP_OPTION_BR_Y].unit = SANE_UNIT_MM;
 
385
   ps->option[SOAP_OPTION_BR_Y].size = sizeof(SANE_Int);
 
386
   ps->option[SOAP_OPTION_BR_Y].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT;
 
387
   ps->option[SOAP_OPTION_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE;
 
388
   ps->option[SOAP_OPTION_BR_Y].constraint.range = &ps->bryRange;
 
389
   ps->bryRange.min = 0;
 
390
   ps->bryRange.quant = 0;
 
391
 
 
392
   return 0;
 
393
} /* init_options */
 
394
 
 
395
/* Verify current x/y extents and set effective extents. */ 
 
396
static int set_extents(struct soap_session *ps)
 
397
{
 
398
   int stat = 0;
 
399
 
 
400
   if ((ps->currentBrx > ps->currentTlx) && (ps->currentBrx - ps->currentTlx >= ps->min_width) && (ps->currentBrx - ps->currentTlx <= ps->tlxRange.max))
 
401
   {
 
402
     ps->effectiveTlx = ps->currentTlx;
 
403
     ps->effectiveBrx = ps->currentBrx;
 
404
   }
 
405
   else
 
406
   {
 
407
     ps->effectiveTlx = 0;  /* current setting is not valid, zero it */
 
408
     ps->effectiveBrx = 0;
 
409
     stat = 1;
 
410
   }
 
411
   if ((ps->currentBry > ps->currentTly) && (ps->currentBry - ps->currentTly > ps->min_height) && (ps->currentBry - ps->currentTly <= ps->tlyRange.max))
 
412
   {
 
413
     ps->effectiveTly = ps->currentTly;
 
414
     ps->effectiveBry = ps->currentBry;
 
415
   }
 
416
   else
 
417
   {
 
418
     ps->effectiveTly = 0;  /* current setting is not valid, zero it */
 
419
     ps->effectiveBry = 0;
 
420
     stat = 1;
 
421
   }
 
422
   return stat;
 
423
} /* set_extents */
 
424
 
 
425
/*
 
426
 * SANE APIs.
 
427
 */
 
428
 
 
429
SANE_Status soap_open(SANE_String_Const device, SANE_Handle *handle)
 
430
{
 
431
   struct hpmud_model_attributes ma;
 
432
   int stat = SANE_STATUS_IO_ERROR, i;
 
433
 
 
434
   DBG8("sane_hpaio_open(%s)\n", device);
 
435
 
 
436
   if (session)
 
437
   {
 
438
      BUG("session in use\n");
 
439
      return SANE_STATUS_DEVICE_BUSY;
 
440
   }
 
441
 
 
442
   if ((session = create_session()) == NULL)
 
443
      return SANE_STATUS_NO_MEM;
 
444
    
 
445
   /* Set session to specified device. */
 
446
   snprintf(session->uri, sizeof(session->uri)-1, "hp:%s", device);   /* prepend "hp:" */
 
447
 
 
448
   /* Get actual model attributes from models.dat. */
 
449
   hpmud_query_model(session->uri, &ma);
 
450
   session->scan_type = ma.scantype;
 
451
 
 
452
   if (hpmud_open_device(session->uri, ma.mfp_mode, &session->dd) != HPMUD_R_OK)
 
453
   {
 
454
      BUG("unable to open device %s\n", session->uri);
 
455
      goto bugout;
 
456
 
 
457
      free(session);
 
458
      session = NULL;
 
459
      return SANE_STATUS_IO_ERROR;
 
460
   }
 
461
 
 
462
   if (bb_load(session, "bb_soap.so"))
 
463
   {
 
464
      stat = SANE_STATUS_IO_ERROR;
 
465
      goto bugout;
 
466
   }
 
467
 
 
468
   /* Init sane option descriptors. */
 
469
   init_options(session);  
 
470
 
 
471
   if (session->bb_open(session))
 
472
   {
 
473
      stat = SANE_STATUS_IO_ERROR;
 
474
      goto bugout;
 
475
   }
 
476
 
 
477
   /* Set supported Scan Modes as determined by bb_open. */
 
478
   soap_control_option(session, SOAP_OPTION_SCAN_MODE, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
479
 
 
480
   /* Set supported resolutions. */
 
481
   i=1;
 
482
   session->resolutionList[i++] = 75;
 
483
   session->resolutionList[i++] = 100;
 
484
   session->resolutionList[i++] = 150;
 
485
   session->resolutionList[i++] = 200;
 
486
   session->resolutionList[i++] = 300;
 
487
   session->resolutionList[i++] = 600;
 
488
   session->resolutionList[i++] = 1200;
 
489
   session->resolutionList[0] = i-1;    /* length of word_list */
 
490
   soap_control_option(session, SOAP_OPTION_SCAN_RESOLUTION, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
491
 
 
492
   /* Set supported contrast. */
 
493
   soap_control_option(session, SOAP_OPTION_CONTRAST, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
494
 
 
495
   /* Set supported compression. (Note, cm1017 may say it supports MMR, but it doesn't) */
 
496
   soap_control_option(session, SOAP_OPTION_COMPRESSION, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
497
   
 
498
   /* Set jpeg quality factor as determined by bb_open. */
 
499
   soap_control_option(session, SOAP_OPTION_JPEG_QUALITY, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
500
 
 
501
   /* Set x,y extents. See bb_open */
 
502
   soap_control_option(session, SOAP_OPTION_TL_X, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
503
   soap_control_option(session, SOAP_OPTION_TL_Y, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
504
   soap_control_option(session, SOAP_OPTION_BR_X, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
505
   soap_control_option(session, SOAP_OPTION_BR_Y, SANE_ACTION_SET_AUTO, NULL, NULL); /* set default option */
 
506
 
 
507
   *handle = (SANE_Handle *)session;
 
508
 
 
509
   stat = SANE_STATUS_GOOD;
 
510
 
 
511
bugout:
 
512
 
 
513
   if (stat != SANE_STATUS_GOOD)
 
514
   {
 
515
      if (session)
 
516
      {
 
517
         bb_unload(session);
 
518
         if (session->dd > 0)
 
519
            hpmud_close_device(session->dd);
 
520
         free(session);
 
521
         session = NULL;
 
522
      }
 
523
   }
 
524
 
 
525
   return stat;
 
526
} /* sane_open */
 
527
 
 
528
void soap_close(SANE_Handle handle)
 
529
{
 
530
   struct soap_session *ps = (struct soap_session *)handle;
 
531
 
 
532
   DBG8("sane_hpaio_close()\n"); 
 
533
 
 
534
   if (ps == NULL || ps != session)
 
535
   {
 
536
      BUG("invalid sane_close\n");
 
537
      return;
 
538
   }
 
539
 
 
540
   ps->bb_close(ps);
 
541
   bb_unload(ps);
 
542
 
 
543
   if (ps->dd > 0)
 
544
      hpmud_close_device(ps->dd);
 
545
    
 
546
   free(ps);
 
547
   session = NULL;
 
548
} /* soap_close */
 
549
 
 
550
const SANE_Option_Descriptor *soap_get_option_descriptor(SANE_Handle handle, SANE_Int option)
 
551
{
 
552
   struct soap_session *ps = (struct soap_session *)handle;
 
553
 
 
554
   DBG8("sane_hpaio_get_option_descriptor(option=%s)\n", ps->option[option].name);
 
555
 
 
556
   if (option < 0 || option >= SOAP_OPTION_MAX)
 
557
      return NULL;
 
558
 
 
559
   return &ps->option[option];
 
560
} /* soap_get_option_descriptor */
 
561
 
 
562
SANE_Status soap_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *value, SANE_Int *set_result)
 
563
{
 
564
   struct soap_session *ps = (struct soap_session *)handle;
 
565
   SANE_Int *int_value = value, mset_result=0;
 
566
   int i, stat=SANE_STATUS_INVAL;
 
567
   char sz[64];
 
568
 
 
569
   switch(option)
 
570
   {
 
571
      case SOAP_OPTION_COUNT:
 
572
         if (action == SANE_ACTION_GET_VALUE)
 
573
         {
 
574
            *int_value = SOAP_OPTION_MAX;
 
575
            stat = SANE_STATUS_GOOD;
 
576
         }
 
577
         break;
 
578
      case SOAP_OPTION_SCAN_MODE:
 
579
         if (action == SANE_ACTION_GET_VALUE)
 
580
         {
 
581
            for (i=0; ps->scanModeList[i]; i++)
 
582
            {
 
583
               if (ps->currentScanMode == ps->scanModeMap[i])
 
584
               {
 
585
                  strcpy(value, ps->scanModeList[i]);
 
586
                  stat = SANE_STATUS_GOOD;
 
587
                  break;
 
588
               }
 
589
            }
 
590
         }
 
591
         else if (action == SANE_ACTION_SET_VALUE)
 
592
         {
 
593
            for (i=0; ps->scanModeList[i]; i++)
 
594
            {
 
595
               if (strcasecmp(ps->scanModeList[i], value) == 0)
 
596
               {
 
597
                  ps->currentScanMode = ps->scanModeMap[i];
 
598
                  set_scan_mode_side_effects(ps, ps->currentScanMode);
 
599
                  mset_result |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
 
600
                  stat = SANE_STATUS_GOOD;
 
601
                  break;
 
602
               }
 
603
            }
 
604
         }
 
605
         else
 
606
         {  /* Set default. */
 
607
            ps->currentScanMode = CE_RGB24;
 
608
            set_scan_mode_side_effects(ps, ps->currentScanMode);
 
609
            stat = SANE_STATUS_GOOD;
 
610
         }
 
611
         break;
 
612
      case SOAP_OPTION_SCAN_RESOLUTION:
 
613
         if (action == SANE_ACTION_GET_VALUE)
 
614
         {
 
615
            *int_value = ps->currentResolution;
 
616
            stat = SANE_STATUS_GOOD;
 
617
         }
 
618
         else if (action == SANE_ACTION_SET_VALUE)
 
619
         {
 
620
            for (i=1; i <= ps->resolutionList[0]; i++)
 
621
            {
 
622
               if (ps->resolutionList[i] == *int_value)
 
623
               {
 
624
                  ps->currentResolution = *int_value;
 
625
                  mset_result |= SANE_INFO_RELOAD_PARAMS;
 
626
                  stat = SANE_STATUS_GOOD;
 
627
                  break;
 
628
               }
 
629
            }
 
630
         }
 
631
         else
 
632
         {  /* Set default. */
 
633
            ps->currentResolution = 75;
 
634
            stat = SANE_STATUS_GOOD;
 
635
         }
 
636
         break;
 
637
      case SOAP_OPTION_CONTRAST:
 
638
         if (action == SANE_ACTION_GET_VALUE)
 
639
         {
 
640
            *int_value = ps->currentContrast;
 
641
            stat = SANE_STATUS_GOOD;
 
642
         }
 
643
         else if (action == SANE_ACTION_SET_VALUE)
 
644
         {
 
645
            if (*int_value >= SOAP_CONTRAST_MIN && *int_value <= SOAP_CONTRAST_MAX)
 
646
            {
 
647
               ps->currentContrast = *int_value;
 
648
               stat = SANE_STATUS_GOOD;
 
649
               break;
 
650
            }
 
651
         }
 
652
         else
 
653
         {  /* Set default. */
 
654
            ps->currentContrast = SOAP_CONTRAST_DEFAULT;
 
655
            stat = SANE_STATUS_GOOD;
 
656
         }
 
657
         break;
 
658
      case SOAP_OPTION_COMPRESSION:
 
659
         if (action == SANE_ACTION_GET_VALUE)
 
660
         {
 
661
            for (i=0; ps->compressionList[i]; i++)
 
662
            {
 
663
               if (ps->currentCompression == ps->compressionMap[i])
 
664
               {
 
665
                  strcpy(value, ps->compressionList[i]);
 
666
                  stat = SANE_STATUS_GOOD;
 
667
                  break;
 
668
               }
 
669
            }
 
670
         }
 
671
         else if (action == SANE_ACTION_SET_VALUE)
 
672
         {
 
673
            for (i=0; ps->compressionList[i]; i++)
 
674
            {
 
675
               if (strcasecmp(ps->compressionList[i], value) == 0)
 
676
               {
 
677
                  ps->currentCompression = ps->compressionMap[i];
 
678
                  stat = SANE_STATUS_GOOD;
 
679
                  break;
 
680
               }
 
681
            }
 
682
         }
 
683
         else
 
684
         {  /* Set default. */
 
685
            ps->currentCompression = SF_JFIF;
 
686
            stat = SANE_STATUS_GOOD;
 
687
         }
 
688
         break;
 
689
      case SOAP_OPTION_JPEG_QUALITY:
 
690
         if (action == SANE_ACTION_GET_VALUE)
 
691
         {
 
692
            *int_value = ps->currentJpegQuality;
 
693
            stat = SANE_STATUS_GOOD;
 
694
         }
 
695
         else if (action == SANE_ACTION_SET_VALUE)
 
696
         {
 
697
            if (*int_value >= MIN_JPEG_COMPRESSION_FACTOR && *int_value <= MAX_JPEG_COMPRESSION_FACTOR)
 
698
            {
 
699
               ps->currentJpegQuality = *int_value;
 
700
               stat = SANE_STATUS_GOOD;
 
701
               break;
 
702
            }
 
703
         }
 
704
         else
 
705
         {  /* Set default. */
 
706
            ps->currentJpegQuality = SAFER_JPEG_COMPRESSION_FACTOR;
 
707
            stat = SANE_STATUS_GOOD;
 
708
         }
 
709
         break;
 
710
      case SOAP_OPTION_TL_X:
 
711
         if (action == SANE_ACTION_GET_VALUE)
 
712
         {
 
713
            *int_value = ps->currentTlx;
 
714
            stat = SANE_STATUS_GOOD;
 
715
         }
 
716
         else if (action == SANE_ACTION_SET_VALUE)
 
717
         {
 
718
            if (*int_value >= ps->tlxRange.min && *int_value <= ps->tlxRange.max)
 
719
            {
 
720
               ps->currentTlx = *int_value;
 
721
               mset_result |= SANE_INFO_RELOAD_PARAMS;
 
722
               stat = SANE_STATUS_GOOD;
 
723
               break;
 
724
            }
 
725
         }
 
726
         else
 
727
         {  /* Set default. */
 
728
            ps->currentTlx = ps->tlxRange.min;
 
729
            stat = SANE_STATUS_GOOD;
 
730
         }
 
731
         break;
 
732
      case SOAP_OPTION_TL_Y:
 
733
         if (action == SANE_ACTION_GET_VALUE)
 
734
         {
 
735
            *int_value = ps->currentTly;
 
736
            stat = SANE_STATUS_GOOD;
 
737
         }
 
738
         else if (action == SANE_ACTION_SET_VALUE)
 
739
         {
 
740
            if (*int_value >= ps->tlyRange.min && *int_value <= ps->tlyRange.max)
 
741
            {
 
742
               
 
743
               ps->currentTly = *int_value;
 
744
               mset_result |= SANE_INFO_RELOAD_PARAMS;
 
745
               stat = SANE_STATUS_GOOD;
 
746
               break;
 
747
            }
 
748
         }
 
749
         else
 
750
         {  /* Set default. */
 
751
            ps->currentTly = ps->tlyRange.min;
 
752
            stat = SANE_STATUS_GOOD;
 
753
         }
 
754
         break;
 
755
      case SOAP_OPTION_BR_X:
 
756
         if (action == SANE_ACTION_GET_VALUE)
 
757
         {
 
758
            *int_value = ps->currentBrx;
 
759
            stat = SANE_STATUS_GOOD;
 
760
         }
 
761
         else if (action == SANE_ACTION_SET_VALUE)
 
762
         {
 
763
            if (*int_value >= ps->brxRange.min && *int_value <= ps->brxRange.max)
 
764
            {
 
765
               ps->currentBrx = *int_value;
 
766
               mset_result |= SANE_INFO_RELOAD_PARAMS;
 
767
               stat = SANE_STATUS_GOOD;
 
768
               break;
 
769
            }
 
770
         }
 
771
         else
 
772
         {  /* Set default. */
 
773
            ps->currentBrx = ps->brxRange.max;
 
774
            stat = SANE_STATUS_GOOD;
 
775
         }
 
776
         break;
 
777
      case SOAP_OPTION_BR_Y:
 
778
         if (action == SANE_ACTION_GET_VALUE)
 
779
         {
 
780
            *int_value = ps->currentBry;
 
781
            stat = SANE_STATUS_GOOD;
 
782
         }
 
783
         else if (action == SANE_ACTION_SET_VALUE)
 
784
         {
 
785
            if (*int_value >= ps->bryRange.min && *int_value <= ps->bryRange.max)
 
786
            {
 
787
               ps->currentBry = *int_value;
 
788
               mset_result |= SANE_INFO_RELOAD_PARAMS;
 
789
               stat = SANE_STATUS_GOOD;
 
790
               break;
 
791
            }
 
792
         }
 
793
         else
 
794
         {  /* Set default. */
 
795
            ps->currentBry = ps->bryRange.max;
 
796
            stat = SANE_STATUS_GOOD;
 
797
         }
 
798
         break;
 
799
      default:
 
800
         break;
 
801
   }
 
802
 
 
803
   if (set_result)
 
804
      *set_result = mset_result;
 
805
 
 
806
   if (stat != SANE_STATUS_GOOD)
 
807
   {
 
808
      BUG("control_option failed: option=%s action=%s\n", ps->option[option].name, 
 
809
                  action==SANE_ACTION_GET_VALUE ? "get" : action==SANE_ACTION_SET_VALUE ? "set" : "auto");
 
810
   }
 
811
 
 
812
   DBG8("sane_hpaio_control_option (option=%s action=%s value=%s)\n", ps->option[option].name, 
 
813
                        action==SANE_ACTION_GET_VALUE ? "get" : action==SANE_ACTION_SET_VALUE ? "set" : "auto",
 
814
     value ? ps->option[option].type == SANE_TYPE_STRING ? (char *)value : psnprintf(sz, sizeof(sz), "%d", *(int *)value) : "na");
 
815
 
 
816
   return stat;
 
817
} /* soap_control_option */
 
818
 
 
819
SANE_Status soap_get_parameters(SANE_Handle handle, SANE_Parameters *params)
 
820
{
 
821
   struct soap_session *ps = (struct soap_session *)handle;
 
822
 
 
823
   set_extents(ps);
 
824
 
 
825
   /* Get scan parameters for sane client. */
 
826
   ps->bb_get_parameters(ps, params, ps->ip_handle ? SPO_STARTED : SPO_BEST_GUESS);
 
827
 
 
828
   DBG8("sane_hpaio_get_parameters(): format=%d, last_frame=%d, lines=%d, depth=%d, pixels_per_line=%d, bytes_per_line=%d\n",
 
829
                    params->format, params->last_frame, params->lines, params->depth, params->pixels_per_line, params->bytes_per_line);
 
830
 
 
831
   return SANE_STATUS_GOOD;
 
832
} /* soap_get_parameters */
 
833
 
 
834
SANE_Status soap_start(SANE_Handle handle)
 
835
{
 
836
   struct soap_session *ps = (struct soap_session *)handle;
 
837
   SANE_Parameters pp;
 
838
   IP_IMAGE_TRAITS traits;
 
839
   IP_XFORM_SPEC xforms[IP_MAX_XFORMS], *pXform=xforms;
 
840
   int stat, ret;
 
841
 
 
842
   DBG8("sane_hpaio_start()\n");
 
843
   ps->user_cancel = 0;
 
844
   if (set_extents(ps))
 
845
   {
 
846
      BUG("invalid extents: tlx=%d brx=%d tly=%d bry=%d minwidth=%d minheight%d maxwidth=%d maxheight=%d\n",
 
847
         ps->currentTlx, ps->currentTly, ps->currentBrx, ps->currentBry, ps->min_width, ps->min_height, ps->tlxRange.max, ps->tlyRange.max);
 
848
      stat = SANE_STATUS_INVAL;
 
849
      goto bugout;
 
850
   }   
 
851
 
 
852
   /* Start scan. */
 
853
   if (ps->bb_start_scan(ps))
 
854
   {
 
855
      stat = SANE_STATUS_IO_ERROR;
 
856
      goto bugout;
 
857
   }
 
858
   SendScanEvent(ps->uri, EVENT_START_SCAN_JOB);
 
859
   memset(xforms, 0, sizeof(xforms));    
 
860
 
 
861
   /* Setup image-processing pipeline for xform. */
 
862
   if (ps->currentScanMode == CE_RGB24 || ps->currentScanMode == CE_GRAY8)
 
863
   {
 
864
      pXform->aXformInfo[IP_JPG_DECODE_FROM_DENALI].dword = 0;    /* 0=no */
 
865
      ADD_XFORM(X_JPG_DECODE);
 
866
      pXform->aXformInfo[IP_CNV_COLOR_SPACE_WHICH_CNV].dword = IP_CNV_YCC_TO_SRGB;
 
867
      pXform->aXformInfo[IP_CNV_COLOR_SPACE_GAMMA].dword = 0x00010000;
 
868
      ADD_XFORM(X_CNV_COLOR_SPACE);
 
869
   }
 
870
   else
 
871
   {  /* Must be BLACK_AND_WHITE1 (Lineart). */
 
872
      pXform->aXformInfo[IP_JPG_DECODE_FROM_DENALI].dword = 0;    /* 0=no */
 
873
      ADD_XFORM(X_JPG_DECODE);
 
874
      pXform->aXformInfo[IP_GRAY_2_BI_THRESHOLD].dword = 127;
 
875
      ADD_XFORM(X_GRAY_2_BI);
 
876
   }
 
877
 
 
878
   /* Setup x/y cropping for xform. (Actually we let cm1017 do it's own cropping) */
 
879
   pXform->aXformInfo[IP_CROP_LEFT].dword = 0;
 
880
   pXform->aXformInfo[IP_CROP_RIGHT].dword = 0;
 
881
   pXform->aXformInfo[IP_CROP_TOP].dword = 0;
 
882
   pXform->aXformInfo[IP_CROP_MAXOUTROWS].dword = 0;
 
883
   ADD_XFORM(X_CROP);
 
884
 
 
885
   /* Setup x/y padding for xform. (Actually we let cm1017 do it's own padding) */
 
886
   pXform->aXformInfo[IP_PAD_LEFT].dword = 0; /* # of pixels to add to left side */
 
887
   pXform->aXformInfo[IP_PAD_RIGHT].dword = 0; /* # of pixels to add to right side */
 
888
   pXform->aXformInfo[IP_PAD_TOP].dword = 0; /* # of rows to add to top */
 
889
   pXform->aXformInfo[IP_PAD_BOTTOM].dword = 0;  /* # of rows to add to bottom */
 
890
   pXform->aXformInfo[IP_PAD_VALUE].dword = ps->currentScanMode == CE_BLACK_AND_WHITE1 ? 0 : -1;   /* lineart white = 0, rgb white = -1 */ 
 
891
   pXform->aXformInfo[IP_PAD_MIN_HEIGHT].dword = 0;
 
892
   ADD_XFORM(X_PAD);
 
893
 
 
894
   /* Open image processor. */
 
895
   if ((ret = ipOpen(pXform-xforms, xforms, 0, &ps->ip_handle)) != IP_DONE)
 
896
   {
 
897
      BUG("unable open image processor: err=%d\n", ret);
 
898
      stat = SANE_STATUS_INVAL;
 
899
      goto bugout;
 
900
   }
 
901
 
 
902
   /* Set known input image attributes. */
 
903
   ps->bb_get_parameters(ps, &pp, SPO_BEST_GUESS);
 
904
   traits.iPixelsPerRow = pp.pixels_per_line;
 
905
   switch(ps->currentScanMode)
 
906
   {
 
907
      case CE_BLACK_AND_WHITE1:     /* linart uses 8-bit gray */   
 
908
      case CE_GRAY8:
 
909
         traits.iBitsPerPixel = 8;     /* grayscale */
 
910
         break;
 
911
      case CE_RGB24:
 
912
      default:
 
913
         traits.iBitsPerPixel = 24;      /* color */
 
914
         break;
 
915
   }
 
916
   traits.lHorizDPI = ps->currentResolution << 16;
 
917
   traits.lVertDPI = ps->currentResolution << 16;
 
918
   traits.lNumRows =  pp.lines;
 
919
   traits.iNumPages = 1;
 
920
   traits.iPageNum = 1;
 
921
   traits.iComponentsPerPixel = ((traits.iBitsPerPixel % 3) ? 1 : 3);
 
922
   DBG6("set traits iPixelsPerRow=%d iBitsPerPixel=%d lNumRows=%d iComponentsPerPixel=%d\n", traits.iPixelsPerRow, 
 
923
           traits.iBitsPerPixel, (int)traits.lNumRows, traits.iComponentsPerPixel);
 
924
   ipSetDefaultInputTraits(ps->ip_handle, &traits);
 
925
 
 
926
   /* If jpeg get output image attributes from the image processor. */
 
927
   if (ps->currentCompression == SF_JFIF)
 
928
   {
 
929
      /* Enable parsed header flag. */
 
930
      ipResultMask(ps->ip_handle, IP_PARSED_HEADER);
 
931
 
 
932
      /* Wait for image processor to process header so we know the exact size of the image for sane_get_params. */
 
933
      while (1)
 
934
      {
 
935
         ret = get_ip_data(ps, NULL, 0, NULL);
 
936
 
 
937
         if (ret & (IP_INPUT_ERROR | IP_FATAL_ERROR | IP_DONE))
 
938
         {
 
939
            BUG("ipConvert error=%x\n", ret);
 
940
            stat = SANE_STATUS_IO_ERROR;
 
941
            goto bugout;
 
942
         }
 
943
 
 
944
         if (ret & IP_PARSED_HEADER)
 
945
         {
 
946
            ipGetImageTraits(ps->ip_handle, NULL, &ps->image_traits);  /* get valid image traits */
 
947
            ipResultMask(ps->ip_handle, 0);                          /* disable parsed header flag */
 
948
            break;
 
949
         }
 
950
      }
 
951
   }
 
952
   else
 
953
      ipGetImageTraits(ps->ip_handle, NULL, &ps->image_traits);  /* get valid image traits */
 
954
 
 
955
   DBG6("act traits iPixelsPerRow=%d iBitsPerPixel=%d lNumRows=%d iComponentsPerPixel=%d\n", ps->image_traits.iPixelsPerRow, 
 
956
           ps->image_traits.iBitsPerPixel,  (int)ps->image_traits.lNumRows, ps->image_traits.iComponentsPerPixel);
 
957
 
 
958
   stat = SANE_STATUS_GOOD;
 
959
 
 
960
bugout:
 
961
   if (stat != SANE_STATUS_GOOD)
 
962
   {
 
963
      if (ps->ip_handle)
 
964
      {
 
965
         ipClose(ps->ip_handle); 
 
966
         ps->ip_handle = 0;
 
967
      }   
 
968
      ps->bb_end_scan(ps, stat == SANE_STATUS_IO_ERROR ? 1: 0);
 
969
   }
 
970
 
 
971
   return stat;
 
972
} /* soap_start */
 
973
 
 
974
SANE_Status soap_read(SANE_Handle handle, SANE_Byte *data, SANE_Int maxLength, SANE_Int *length)
 
975
{
 
976
   struct soap_session *ps = (struct soap_session *)handle;
 
977
   int ret, stat=SANE_STATUS_IO_ERROR;
 
978
 
 
979
   DBG8("sane_hpaio_read() handle=%p data=%p maxLength=%d\n", (void *)handle, data, maxLength);
 
980
   if(ps->user_cancel)
 
981
   {
 
982
     DBG8("soap_read() EVENT_SCAN_CANCEL****uri=%s\n", ps->uri);
 
983
     SendScanEvent(ps->uri, EVENT_SCAN_CANCEL);
 
984
     return SANE_STATUS_CANCELLED;
 
985
   }
 
986
   
 
987
   ret = get_ip_data(ps, data, maxLength, length);
 
988
 
 
989
   if(ret & (IP_INPUT_ERROR | IP_FATAL_ERROR))
 
990
   {
 
991
      BUG("ipConvert error=%x\n", ret);
 
992
      goto bugout;
 
993
   }
 
994
 
 
995
   if (ret & IP_DONE)
 
996
   {
 
997
      stat = SANE_STATUS_EOF;
 
998
      SendScanEvent (ps->uri, EVENT_END_SCAN_JOB);
 
999
   }
 
1000
   else
 
1001
      stat = SANE_STATUS_GOOD;
 
1002
 
 
1003
bugout:
 
1004
   if (stat != SANE_STATUS_GOOD)
 
1005
   {
 
1006
      if (ps->ip_handle)
 
1007
      {
 
1008
         /* 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. */ 
 
1009
         ipClose(ps->ip_handle);  
 
1010
         ps->ip_handle = 0;
 
1011
      } 
 
1012
      ps->bb_end_page(ps, 0);
 
1013
   }
 
1014
 
 
1015
   DBG8("-sane_hpaio_read() output=%p bytes_read=%d maxLength=%d status=%d\n", data, *length, maxLength, stat);
 
1016
 
 
1017
   return stat;
 
1018
} /* soap_read */
 
1019
 
 
1020
void soap_cancel(SANE_Handle handle)
 
1021
{
 
1022
   struct soap_session *ps = (struct soap_session *)handle;
 
1023
 
 
1024
   DBG8("sane_hpaio_cancel()\n"); 
 
1025
 
 
1026
   /*
 
1027
    * Sane_cancel is always called at the end of the scan job. Note that on a multiple page scan job 
 
1028
    * sane_cancel is called only once.
 
1029
    */
 
1030
   ps->user_cancel = 1;
 
1031
   if (ps->ip_handle)
 
1032
   {
 
1033
      ipClose(ps->ip_handle); 
 
1034
      ps->ip_handle = 0;
 
1035
   }
 
1036
   ps->bb_end_scan(ps, 0);
 
1037
} /* soap_cancel */
 
1038