1
2
3
4 __version__ = "$Revision: 1.56 $"
5 __license__ = "GPL"
6 __author__ = """Sebastian Hilbert <Sebastian.Hilbert@gmx.net>, Karsten Hilbert <Karsten.Hilbert@gmx.net>"""
7
8
9
10 import sys, os.path, os, string, time, shutil, codecs, glob, locale, errno, stat, logging
11
12
13
14
15
16
17
18 if __name__ == '__main__':
19 sys.path.insert(0, '../../')
20 from Gnumed.pycommon import gmShellAPI, gmTools, gmI18N
21
22
23 _log = logging.getLogger('gm.scanning')
24 _log.info(__version__)
25
26 _twain_module = None
27 _sane_module = None
28
29 use_XSane = True
30
31
32
43
45
46
47
48 - def __init__(self, calling_window=None):
49 _twain_import_module()
50
51 self.__calling_window = calling_window
52 self.__src_manager = None
53 self.__scanner = None
54 self.__done_transferring_image = False
55
56 self.__register_event_handlers()
57
58
59
60 - def acquire_pages_into_files(self, delay=None, filename=None, tmpdir=None):
61 if filename is None:
62 filename = gmTools.get_unique_filename(prefix='gmScannedObj-', suffix='.bmp', tmp_dir=tmpdir)
63 else:
64 tmp, ext = os.path.splitext(filename)
65 if ext != '.bmp':
66 filename = filename + '.bmp'
67
68 self.__filename = os.path.abspath(os.path.expanduser(filename))
69
70 if not self.__init_scanner():
71 raise OSError(-1, 'cannot init TWAIN scanner device')
72
73 self.__done_transferring_image = False
74 self.__scanner.RequestAcquire(True)
75
76 return [self.__filename]
77
79 return self.__done_transferring_image
80
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 return
99
100
101
103 if self.__scanner is not None:
104 return True
105
106 self.__init_src_manager()
107 if self.__src_manager is None:
108 return False
109
110
111 self.__src_manager.SetCallback(self._twain_event_callback)
112
113
114 self.__scanner = self.__src_manager.OpenSource()
115 if self.__scanner is None:
116 _log.error("user canceled scan source selection dialog")
117 return False
118
119 _log.info("TWAIN data source: %s" % self.__scanner.GetSourceName())
120 _log.debug("TWAIN data source config: %s" % str(self.__scanner.GetIdentity()))
121
122 return True
123
125
126 if self.__src_manager is not None:
127 return
128
129
130
131
132
133
134
135
136
137
138
139
140 self.__src_manager = _twain_module.SourceManager(self.__calling_window.GetHandle())
141
142 _log.info("TWAIN source manager config: %s" % str(self.__src_manager.GetIdentity()))
143
144
145
147 self.__twain_event_handlers = {
148 _twain_module.MSG_XFERREADY: self._twain_handle_transfer_in_memory,
149 _twain_module.MSG_CLOSEDSREQ: self._twain_close_datasource,
150 _twain_module.MSG_CLOSEDSOK: self._twain_save_state,
151 _twain_module.MSG_DEVICEEVENT: self._twain_handle_src_event
152 }
153
155 _log.debug('notification of TWAIN event <%s>' % str(twain_event))
156 self.__twain_event_handlers[twain_event]()
157 self.__scanner = None
158 return
159
161 _log.info("being asked to close data source")
162
164 _log.info("being asked to save application state")
165
167 _log.info("being asked to handle device specific event")
168
170
171
172
173 _log.debug('receiving image from TWAIN source')
174 _log.debug('image info: %s' % self.__scanner.GetImageInfo())
175 _log.debug('image layout: %s' % str(self.__scanner.GetImageLayout()))
176
177
178 (external_data_handle, more_images_pending) = self.__scanner.XferImageNatively()
179 try:
180
181 _twain_module.DIBToBMFile(external_data_handle, self.__filename)
182 finally:
183 _twain_module.GlobalHandleFree(external_data_handle)
184 _log.debug('%s pending images' % more_images_pending)
185
186
187
188
189
190 self.__done_transferring_image = True
191
193
194
195
196
197
198 _log.debug('receiving image from TWAIN source')
199 _log.debug('image info: %s' % self.__scanner.GetImageInfo())
200 _log.debug('image layout: %s' % self.__scanner.GetImageLayout())
201
202 self.__scanner.SetXferFileName(self.__filename)
203
204 more_images_pending = self.__scanner.XferImageByFile()
205 _log.debug('%s pending images' % more_images_pending)
206
207
208 self.__scanner.HideUI()
209
210
211 return
212
213
214
231
233
234
235
236 _src_manager = None
237
239 _sane_import_module()
240
241
242
243
244
245
246
247
248 self.__device = device
249 _log.info('using SANE device [%s]' % self.__device)
250
251 self.__init_scanner()
252
254 self.__scanner = _sane_module.open(self.__device)
255
256 _log.debug('opened SANE device: %s' % str(self.__scanner))
257 _log.debug('SANE device config: %s' % str(self.__scanner.get_parameters()))
258 _log.debug('SANE device opts : %s' % str(self.__scanner.optlist))
259 _log.debug('SANE device opts : %s' % str(self.__scanner.get_options()))
260
261 return True
262
264 self.__scanner.close()
265
266 - def acquire_pages_into_files(self, delay=None, filename=None, tmpdir=None):
267 if filename is None:
268 filename = gmTools.get_unique_filename(prefix='gmScannedObj-', suffix='.bmp', tmp_dir=tmpdir)
269 else:
270 tmp, ext = os.path.splitext(filename)
271 if ext != '.bmp':
272 filename = filename + '.bmp'
273
274 filename = os.path.abspath(os.path.expanduser(filename))
275
276 if delay is not None:
277 time.sleep(delay)
278 _log.debug('some sane backends report device_busy if we advance too fast. delay set to %s sec' % delay)
279
280 _log.debug('Trying to get image from scanner into [%s] !' % filename)
281 self.__scanner.start()
282 img = self.__scanner.snap()
283 img.save(filename)
284
285 return [filename]
286
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
314
315 _filetype = u'.png'
316 _xsanerc = os.path.expanduser(os.path.join('~', '.sane', 'xsane', 'xsane.rc'))
317
318 _xsanerc_gnumed = os.path.expanduser(os.path.join('~', '.gnumed', 'gnumed-xsanerc.conf'))
319 _xsanerc_backup = os.path.expanduser(os.path.join('~', '.gnumed', 'gnumed-xsanerc.conf.bak'))
320
321
323
324
325 try:
326 open(cXSaneScanner._xsanerc, 'r').close()
327 except IOError:
328 msg = (
329 'XSane not properly installed for this user:\n\n'
330 ' [%s] not found\n\n'
331 'Start XSane once before using it with GNUmed.'
332 ) % cXSaneScanner._xsanerc
333 raise ImportError(msg)
334
335
336
337 self.device_settings_file = None
338 self.default_device = None
339
342
343 - def acquire_pages_into_files(self, delay=None, filename=None, tmpdir=None):
344 """Call XSane.
345
346 <filename> name part must have format name-001.ext>
347 """
348 if filename is None:
349 filename = gmTools.get_unique_filename (
350 prefix = 'gmScannedObj-',
351 suffix = cXSaneScanner._filetype,
352 tmp_dir = tmpdir
353 )
354 name, ext = os.path.splitext(filename)
355 filename = '%s-001%s' % (name, cXSaneScanner._filetype)
356
357 filename = os.path.abspath(os.path.expanduser(filename))
358 path, name = os.path.split(filename)
359
360 self.__prepare_xsanerc(tmpdir=path)
361
362 cmd = 'xsane --no-mode-selection --save --force-filename "%s" --xsane-rc "%s" %s %s' % (
363 filename,
364 cXSaneScanner._xsanerc_gnumed,
365 gmTools.coalesce(self.device_settings_file, '', '--device-settings %s'),
366 gmTools.coalesce(self.default_device, '')
367 )
368 normal_exit = gmShellAPI.run_command_in_shell(command = cmd, blocking = True)
369
370 if normal_exit:
371 flist = glob.glob(filename.replace('001', '*'))
372 flist.sort()
373 return flist
374
375 raise OSError(-1, 'error starting XSane as [%s]' % cmd)
376
379
380
381
383
384 try:
385 open(cXSaneScanner._xsanerc_gnumed, 'r+b').close()
386 except IOError:
387 _log.info('creating [%s] from [%s]', cXSaneScanner._xsanerc_gnumed, cXSaneScanner._xsanerc)
388 shutil.copyfile(cXSaneScanner._xsanerc, cXSaneScanner._xsanerc_gnumed)
389
390 shutil.move(cXSaneScanner._xsanerc_gnumed, cXSaneScanner._xsanerc_backup)
391
392
393 enc = gmI18N.get_encoding()
394 fread = codecs.open(cXSaneScanner._xsanerc_backup, mode = "rU", encoding = enc)
395 fwrite = codecs.open(cXSaneScanner._xsanerc_gnumed, mode = "w", encoding = enc)
396
397 val_dict = {
398 u'filetype': cXSaneScanner._filetype,
399 u'tmp-path': tmpdir,
400 u'working-directory': tmpdir,
401 u'skip-existing-numbers': u'1',
402 u'filename-counter-step': u'1',
403 u'filename-counter-len': u'3'
404 }
405
406 for idx, line in enumerate(fread):
407 line = line.replace(u'\n', u'')
408 line = line.replace(u'\r', u'')
409
410 if idx % 2 == 0:
411 key = line.strip(u'"')
412 fwrite.write(u'"%s"\n' % key)
413 else:
414 try:
415 value = val_dict[key]
416 except KeyError:
417 value = line
418 fwrite.write(u'%s\n' % value)
419
420 fwrite.flush()
421 fwrite.close()
422 fread.close()
423
424
425
426 return True
427
428
429
430
431
433 try:
434 _twain_import_module()
435
436
437 return None
438 except ImportError:
439 pass
440
441 if use_XSane:
442
443 return None
444
445 _sane_import_module()
446 return _sane_module.get_devices()
447
448 -def acquire_pages_into_files(device=None, delay=None, filename=None, tmpdir=None, calling_window=None, xsane_device_settings=None):
449 """Connect to a scanner and return the scanned pages as a file list.
450
451 returns:
452 - list of filenames: names of scanned pages, may be []
453 - None: unable to connect to scanner
454 """
455 try:
456 scanner = cTwainScanner(calling_window=calling_window)
457 _log.debug('using TWAIN')
458 except ImportError:
459 if use_XSane:
460 _log.debug('using XSane')
461 scanner = cXSaneScanner()
462 scanner.device_settings_file = xsane_device_settings
463 scanner.default_device = device
464 else:
465 _log.debug('using SANE directly')
466 scanner = cSaneScanner(device=device)
467
468 _log.debug('requested filename: [%s]' % filename)
469 fnames = scanner.acquire_pages_into_files(filename=filename, delay=delay, tmpdir=tmpdir)
470 scanner.close()
471 _log.debug('acquired pages into files: %s' % str(fnames))
472
473 return fnames
474
475
476
477 if __name__ == '__main__':
478
479 if len(sys.argv) > 1 and sys.argv[1] == u'test':
480
481 logging.basicConfig(level=logging.DEBUG)
482
483 print "devices:"
484 print get_devices()
485
486 sys.exit()
487
488 setups = [
489 {'dev': 'test:0', 'file': 'x1-test0-1-0001'},
490 {'dev': 'test:1', 'file': 'x2-test1-1-0001.bmp'},
491 {'dev': 'test:0', 'file': 'x3-test0-2-0001.bmp-ccc'}
492 ]
493
494 idx = 1
495 for setup in setups:
496 print "scanning page #%s from device [%s]" % (idx, setup['dev'])
497 idx += 1
498 fnames = acquire_pages_into_files(device = setup['dev'], filename = setup['file'], delay = (idx*5))
499 if fnames is False:
500 print "error, cannot acquire page"
501 else:
502 print " image files:", fnames
503
504
505