-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathbatchscan.py
More file actions
executable file
·347 lines (283 loc) · 14.3 KB
/
batchscan.py
File metadata and controls
executable file
·347 lines (283 loc) · 14.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
#!/usr/bin/python3
# Objectives: scan single sided files. convert to pdf.
import os,sys,re,time,datetime,subprocess
import argparse,logging,traceback,tempfile
import scanutils
# SETTINGS
part = 'part'
timeoffset = 5*60 # in seconds
as_script = False
debug = True
scanutils.debug = debug
default_logdir = os.path.join('/tmp', 'brscan')
default_outdir = os.path.join('/tmp', 'brscan')
waitlimit = 300 # a limit for waiting to fix errors
today = datetime.date.today().isoformat()
def parse_arguments():
global default_outdir,default_logdir
# argument list
parser = argparse.ArgumentParser(description='Process arguments for single and double sided scan')
# else take options from command line
parser.add_argument('--outputdir',nargs='?',action='store',default=default_outdir,const=default_outdir,help='output directory for scanned files')
parser.add_argument('--logdir',nargs='?',action='store',default=default_logdir,const=default_logdir,help='output directory for logfile')
parser.add_argument('--prefix',nargs='?',action='store',default='brscan',const='brscan',help='prefix for scanned file name')
parser.add_argument('--timenow',nargs='?',type=int,action='store',const=int(time.time()),default=int(time.time()),help='timestamp added to scanned output file, in secs from epoch')
parser.add_argument('--device-name',nargs='?',action='store',const=None,default=None,help='scanned device name. Example: brother4:net1;dev1')
parser.add_argument('--resolution',nargs='?',action='store',default='300',const='300',help='scanning resolution in dpi')
parser.add_argument('--height',nargs='?',action='store',default='290',const='290',help='scanned page height. default letter paper height in mm')
parser.add_argument('--width',nargs='?',action='store',default='215.88',const='215.88',help='scanned page width. similar to letter paper in mm')
parser.add_argument('--mode',nargs='?',action='store',default=None,const=None)
#parser.add_argument('--mode',action='store',default = 'Black & White')
parser.add_argument('--source',nargs='?',action='store',default=None,const=None)
# by default, its not in double mode.
parser.add_argument('--duplex',nargs='?',action='store',default=None,const='manual')
# requires exactly one argument, but this not set by nargs
# it's not a dry-run by default.
parser.add_argument('--dry-run',action='store_true',default=False)
args,unknown = parser.parse_known_args()
# process options.
if not args.device_name:
if debug:
scanutils.logprint('No device name set. Trying to automatically find default device')
args.device_name = scanutils.get_default_device()
# check logdir and outputdir, and then normalize the paths
if not os.path.exists(args.logdir):
if debug:
scanutils.logprint('Log directory ',args.logdir,' does not exist. Creating.')
os.makedirs(args.logdir)
# normalize name so that its easy to find
args.logdir = os.path.normpath(args.logdir)
if not os.path.exists(args.outputdir):
if debug:
scanutils.logprint('Output directory ',args.outputdir,' does not exist. Creating.')
os.makedirs(args.outputdir)
# normalize name so that its easy to find
args.outputdir = os.path.normpath(args.outputdir)
# if args.duplex is auto, then look for duplex source. If it's empty
# choose something automatically by running `scanimage -A`. If it's set, use it.
if args.duplex == 'auto':
if not args.source:
args.source = scanutils.get_default_duplex_source()
return args
# SCRIPT START
print("\n",today," Starting ", sys.argv[0]," at",time.time())
# see if run as a script. as_script needed to parse arguments correctly.
# I dont think this is needed anymore.
if not re.match(r'/usr/bin/.*python.*',sys.argv[0]):
as_script = True
# read arguments
args = parse_arguments()
# if debug, logprint parsed arguments
if debug:
# the logfile is not set yet
print('parsed arguments:',args)
# Open logfile
logfile_name = args.logdir + '/batchscan.log'
try:
logfile = open(logfile_name,'a')
logfile.write('Opening logfile.')
except:
scanutils.logprint('Error opening or writing to logile', logfile_name)
try:
logfile = tempfile.NamedTemporaryFile(dir='/tmp',delete=False)
scanutils.logprint('Opened temporary logfile',logfile)
except:
scanutils.logprint('You cannot open a temporary file? You are so screwed.')
# set logfile to stdout
logfile = sys.stdout
if debug:
traceback.print_exc(file=sys.stdout)
scanutils.logfile = logfile
if debug:
scanutils.logprint('The logfile is = ',logfile)
# set filename matchstring regular expressions
match_string_time = args.outputdir + '/' + args.prefix+'-([0-9]+)-'+part+r'-[0-9]+\..*'
match_string_part = args.outputdir + '/' + args.prefix+'-[0-9]+-'+part+r'-([0-9]+)\..*'
# list of odd files
odd_files_name = args.outputdir + '/' + '.' + args.prefix + '-odd-filelist'
if debug:
scanutils.logprint('Look for scanned files of the following form (regex): ', match_string_part)
if args.duplex == 'manual':
# then run complex double sided scanning routines.
scanutils.logprint('Running duplex mode = ', args.duplex)
# look for off files list
if os.path.exists(odd_files_name):
odd_files_list = eval(open(odd_files_name).read())
scanutils.logprint('Found odd files list')
if debug:
scanutils.logprint('They are:',odd_files_list)
# can be overridden below if checks are failed.
run_mode = 'run_even'
# look for file
oddfiles = []
for f in odd_files_list:
if os.path.exists(f):
oddfiles.append(f)
else:
# there is trouble; files missing. i won't do anything.
scanutils.logprint('There are files missing in the odd files list. Missing file = ',f)
# write filelist to logfile
scanutils.logprint('Writing list of saved odd files to log.')
scanutils.logprint(odd_files_list)
if len(oddfiles) > 0:
# the total number of files is of course twice the number of odd files
maxpart = 2*len(oddfiles)
else:
run_mode = 'run_odd'
scanutils.logprint('No files exist in odd files list.')
os.remove(odd_files_name)
else:
# if no odd filelist found, run in odd mode
run_mode = 'run_odd'
# run scanner command
outputfile = args.outputdir + '/' + args.prefix + str(args.timenow) + '-part-%03d.pnm'
if run_mode == 'run_odd':
scanutils.logprint('Scanning odd pages')
[out,err,processhandle] = scanutils.run_scancommand(\
args.device_name,\
outputfile,\
width=args.width,\
height=args.height,\
logfile=logfile,\
debug=debug,\
mode=args.mode,\
resolution=args.resolution,\
batch=True,\
batch_start='1',\
batch_increment='2',\
source=args.source,\
dry_run=args.dry_run)
else: # run_mode == 'run_even'
scanutils.logprint('Scanning even pages')
[out,err,processhandle] = scanutils.run_scancommand(\
args.device_name,\
outputfile,\
width=args.width,\
height=args.height,\
logfile=logfile,\
debug=debug,\
mode=args.mode,\
resolution=args.resolution,\
batch=True,\
batch_start=str(maxpart),\
batch_increment='-2',\
dry_run=args.dry_run)
# wait for run_scancommand to return
processhandle.wait()
# run conversion routines only if not dry_run.
if not args.dry_run:
# find list of scanned files.
# this section can be abstracted since it appears in both single sided and duplex mode
try:
dirname = args.outputdir
matchregex = args.prefix + '-' + str(args.timenow) + r'-part-.*\.pnm'
scanned_files = scanutils.filelist(dirname,matchregex)
if debug:
scanutils.logprint('Scanned files: ', scanned_files)
except:
scanutils.logprint("Error finding scanned files; probably no scanned files found. Check permissions and/or pathname.")
if debug:
traceback.print_exc(file=sys.stdout)
# find number of scanned files
# originally, I found the number of scanned files by looking at the maximum file part number. I don't see why I have to do that. In manual duplex scan mode, this also allows you to delete pages from the odd scanned pages list if necessary.
number_scanned = len(scanned_files)
if debug:
scanutils.logprint("number_scanned: " + str(number_scanned))
if number_scanned > 0:
# waiting is builtin to convert_to_pdf, but ideally you should pass the process handle back and you wait in the main script.
err,converted_files = scanutils.convert_to_pdf(scanned_files,wait=0,debug=debug,logfile=logfile)
# delete original scanned files
if not err and len(converted_files) == len(scanned_files):
for f in scanned_files:
os.remove(f)
# make a filelist and output filename for pdftk
if run_mode == 'run_odd':
# compile the odd pages into a single pdf
compiled_pdf_filename = args.outputdir + '/' + args.prefix + '-' + today + '-' + str(int(time.time())) + '-odd.pdf'
filestopdftk = converted_files
# write filelist to outputdir, used in odd/even mechanism.
tempf = open(odd_files_name,'w')
tempf.write(str(converted_files))
tempf.close()
elif run_mode == 'run_even':
# if scanned even parts, and hence max part number is bigger than 1
# even files are automatically numbered in reverse by the scancommand.
# new files have been ensured to be in sorted order.
converted_files.sort() #newfiles should be sorted already
# interleave two lists, nested for loops
if len(oddfiles) == len(converted_files):
allfiles = scanutils.interleave_lists(oddfiles,converted_files)
else:
logprint('Number of even files scanned not equal to odd files scanned. Compiling even files alone.')
allfiles = converted_files
if debug:
scanutils.logprint('filelist: ' , allfiles)
# ensures that the filename for compiled pdf is unique
compiled_pdf_filename = args.outputdir + '/' + args.prefix + '-' + today + '-' + str(int(time.time())) + '.pdf'
filestopdftk = allfiles
# finally delete even files list
try:
os.remove(odd_files_name)
except:
logprint('Error deleting odd files list!!! Must manually delete')
if debug:
traceback.print_exc(file=sys.stdout)
if len(filestopdftk) > 0:
scanutils.run_pdftk(filestopdftk,compiled_pdf_filename,debug=debug,logfile=logfile)
else:
scanutils.logprint('No files to compile')
#close logfile
logfile.close()
else: # if not (double sided and manual double scanning) simply run single sided scanning routine
# in case we have args.duplex and args.duplextype = 'manual'
# make outputfile
scanutils.logprint('Running in single side mode or --duplex="auto"')
# run scan command
outputfile = args.outputdir + '/' + args.prefix + '-' + str(args.timenow) + '-part-%03d.pnm'
[out,err,processhandle] = scanutils.run_scancommand(\
args.device_name,\
outputfile,\
width=args.width,\
height=args.height,\
logfile=logfile,\
debug=debug,\
mode=args.mode,\
resolution=args.resolution,\
batch_start='1',\
batch_increment='1',\
source=args.source,\
dry_run=args.dry_run)
# wait for run_scancommand to return
processhandle.wait()
# run conversion routines only if not dry_run.
if not args.dry_run:
# find list of scanned files.
try:
dirname = args.outputdir
matchregex = args.prefix + '-' + str(args.timenow) + r'-part-.*\.pnm'
scanned_files = scanutils.filelist(dirname,matchregex)
if debug:
scanutils.logprint('Scanned files: ', scanned_files)
except:
scanutils.logprint("Error finding scanned files; probably no scanned files found. Check permissions and/or pathname.")
if debug:
traceback.print_exc(file=sys.stdout)
# find number of scanned files
# originally, I found the number of scanned files by looking at the maximum file part number. I don't see why I have to do that. In manual duplex scan mode, this also allows you to delete pages from the odd scanned pages list if necessary.
number_scanned = len(scanned_files)
if debug:
scanutils.logprint("number_scanned: " + str(number_scanned))
if number_scanned > 0:
# waiting is builtin to convert_to_pdf, but ideally you should pass the process handle back and you wait in the main script.
err,converted_files = scanutils.convert_to_pdf(scanned_files,wait=0,debug=debug,logfile=logfile)
# delete original scanned files
if not err and len(converted_files) == len(scanned_files):
for f in scanned_files:
os.remove(f)
# find newly converted files
#convertedfiles = filelist('ls ' + args.outputdir + '/' + args.prefix + '-' + str(int(args.timenow)) + '-part-*.pdf')
# make a filelist and output filename to pdftk
compiled_pdf_filename = args.outputdir + '/' + args.prefix + '-' + today + '-' + str(int(time.time())) + '.pdf'
scanutils.run_pdftk(converted_files,compiled_pdf_filename,debug=debug,logfile=logfile)
else:
scanutils.logprint('No scanned files found')