1
# -*- coding: utf-8 -*-
3
# (c) Copyright 2003-2015 HP Development Company, L.P.
5
# This program is free software; you can redistribute it and/or modify
6
# it under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 2 of the License, or
8
# (at your option) any later version.
10
# This program is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
15
# You should have received a copy of the GNU General Public License
16
# along with this program; if not, write to the Free Software
17
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
40
MFPDTF_RASTER_BITMAP = 0
41
MFPDTF_RASTER_GRAYMAP = 1
46
MFPDTF_RASTER_YCC411 = 6
47
MFPDTF_RASTER_JPEG = 7
70
# Raster data record types
79
IMAGE_VARIANT_HEADER_SIZE = 10
80
DIAL_STRINGS_VARIANT_HEADER_SIZE = 6
81
FAX_IMAGE_VARIANT_HEADER_SIZE = 74
85
RASTER_RECORD_SIZE = 4
87
DIAL_STRING_RECORD_SIZE = 51
90
PAGE_FLAG_NEW_PAGE = 0x01
91
PAGE_FLAG_END_PAGE = 0x02
92
PAGE_FLAG_NEW_DOC = 0x04
93
PAGE_FLAG_END_DOC = 0x08
94
PAGE_FLAG_END_STREAM = 0x10
96
# Fax data variant header data source
100
SRC_HOST_THEN_SCANNER = 6
101
SRC_SCANNER_THEN_HOST = 7
103
# Fax data variant header TTI header control
105
TTI_PREPENDED_TO_IMAGE = 1
106
TTI_OVERLAYED_ON_IMAGE = 2
112
def parseFixedHeader(buffer):
114
block_len, header_len, data_type, page_flags = struct.unpack(fmt, buffer[:8])
115
page_flags = page_flags & 0x1f
116
return block_len, header_len, data_type, page_flags
118
def parseImageVariantHeader(buffer, data_type):
119
if data_type == DT_SCANNED_IMAGES:
121
major_ver, minor_ver, src_pages, copies_per_page, zoom, jpeg_q_factor = struct.unpack(fmt, buffer[:10])
122
return major_ver, minor_ver, src_pages, copies_per_page, zoom, jpeg_q_factor
123
elif data_type == DT_FAX_IMAGES:
126
def parseRecord(buffer):
127
record_type = struct.unpack("<B", buffer[0])[0]
129
if record_type == RT_START_PAGE:
130
fmt = "<BBHHHIIIHHIII"
131
id, encoding, page_num, black_ppr, black_bpp, black_rpp, black_hort_dpi, black_vert_dpi, cmy_ppr, cmy_bpp, cmy_rpp, cmy_hort_dpi, cmy_vert_dpi = \
132
struct.unpack(fmt, buffer[:SOP_RECORD_SIZE])
133
assert id == record_type
134
return id, (encoding, page_num, black_ppr, black_bpp, black_rpp, black_hort_dpi, black_vert_dpi, cmy_ppr, cmy_bpp, cmy_rpp, cmy_hort_dpi, cmy_vert_dpi)
136
elif record_type == RT_RASTER:
138
id, unused, data_size = struct.unpack(fmt, buffer[:RASTER_RECORD_SIZE])
139
assert id == record_type
140
return id, (unused, data_size)
142
elif record_type == RT_END_PAGE:
144
id, unused1, unused2, unused3, black_rows, cmy_rows = struct.unpack(fmt, buffer[:EOP_RECORD_SIZE])
145
assert id == record_type
146
return id, (unused1, unused2, unused3, black_rows, cmy_rows)
148
log.error("Error: Invalid record type: %d" % record_type)
149
raise Error(ERROR_INTERNAL)
153
def readChannelToStream(device, channel_id, stream, single_read=True, callback=None):
154
STATE_END, STATE_FIXED_HEADER, STATE_VARIANT_HEADER, STATE_RECORD = list(range(4))
155
state, total_bytes, block_remaining, header_remaining, data_remaining = 1, 0, 0, 0, 0
157
while state != STATE_END:
158
log.debug("**** State %d ****" % state)
159
if state == STATE_FIXED_HEADER:
165
if data_remaining == 0:
166
fields, data = device.readChannel(channel_id)
167
data_remaining = len(data)
168
if callback is not None:
171
block_len, header_len, data_type, page_flags = parseFixedHeader(data)
172
block_remaining, header_remaining = block_len-FIXED_HEADER_SIZE, header_len-FIXED_HEADER_SIZE
173
log.debug("Fixed header: (datalen=%d(0x%x),blocklen=%d(0x%x),headerlen=%d(0x%x),datatype=0x%x,pageflags=0x%x)" %
174
(len(data), len(data), block_len, block_len, header_len, header_len, data_type, page_flags))
175
data_remaining -= FIXED_HEADER_SIZE
176
data = data[FIXED_HEADER_SIZE:]
178
log.debug("Data: data=%d,block=%d,header=%d" % (data_remaining, block_remaining, header_remaining))
180
if page_flags & PAGE_FLAG_END_STREAM:
184
if header_remaining > 0:
185
state = STATE_VARIANT_HEADER
188
elif state == STATE_VARIANT_HEADER:
189
if data_type == DT_SCANNED_IMAGES:
190
major_ver, minor_ver, src_pages, copies_per_page, zoom, jpeg_q_factor = parseImageVariantHeader(data, data_type)
191
log.debug("Variant header: (major/minor=%d/%d,src_pages=%d,copies_per_page=%d,zoom=%d,jpeg_q_factor=%d" %
192
(major_ver, minor_ver, src_pages, copies_per_page, zoom, jpeg_q_factor))
193
data = data[IMAGE_VARIANT_HEADER_SIZE:]
194
block_remaining -= IMAGE_VARIANT_HEADER_SIZE
195
header_remaining -= IMAGE_VARIANT_HEADER_SIZE
196
data_remaining -= IMAGE_VARIANT_HEADER_SIZE
198
elif data_type == DT_FAX_IMAGES:
199
log.error("Unsupported data type")
202
log.error("Unsupported data type")
204
log.debug("Data: data=%d,block=%d,header=%d" % (data_remaining, block_remaining, header_remaining))
206
if header_remaining > 0:
207
log.error("Header size error.")
212
if block_remaining == 0:
213
state = STATE_FIXED_HEADER
216
elif state == STATE_RECORD:
217
record_type, record = parseRecord(data)
219
if record_type == RT_START_PAGE:
220
encoding, page_num, black_ppr, black_bpp, black_rpp, black_hort_dpi, black_vert_dpi, \
221
cmy_ppr, cmy_bpp, cmy_rpp, cmy_hort_dpi, cmy_vert_dpi = record
222
log.debug("Start page record: (encoding=0x%x, page=%d)" % (encoding, page_num))
223
data = data[SOP_RECORD_SIZE:]
224
block_remaining -= SOP_RECORD_SIZE
225
data_remaining -= SOP_RECORD_SIZE
226
if block_remaining != 0:
227
log.error("Block size error.")
234
state = STATE_FIXED_HEADER
235
log.debug("Data: data=%d,block=%d,header=%d" % (data_remaining, block_remaining, header_remaining))
238
elif record_type == RT_RASTER:
239
unused, data_size = record
240
log.debug("Raster record: (data size=%d(0x%x))" % (data_size, data_size))
241
data = data[RASTER_RECORD_SIZE:]
242
block_remaining -= RASTER_RECORD_SIZE
243
data_remaining -= RASTER_RECORD_SIZE
244
log.debug("Data: data=%d,block=%d,header=%d" % (data_remaining, block_remaining, header_remaining))
246
if block_remaining > 0 and data_remaining > 0:
247
log.debug("Writing remainder of data...")
249
log.debug("Data len=%d(0x%x)" % (data_len,data_len))
250
stream.write(data[:block_remaining])
251
block_remaining -= data_len
252
data_remaining -= data_len
254
if data_remaining != 0:
255
log.error("Data size error")
259
while block_remaining > 0:
264
log.debug("Reading more data from device...")
265
fields, data = device.readChannel(channel_id)
267
if callback is not None:
271
log.debug("Data len=%d(0x%x)" % (data_len,data_len))
272
stream.write(data[:block_remaining])
273
total_bytes += data_len
274
block_remaining -= data_len
276
if block_remaining != 0:
277
log.error("Block size error.")
281
state = STATE_FIXED_HEADER
284
elif record_type == RT_END_PAGE:
285
unused1, unused2, unused3, black_rows, cmy_rows = record
286
log.debug("End page record: (black_rows=%d,cmy_rows=%d)" % (black_rows, cmy_rows))
287
data = data[EOP_RECORD_SIZE:]
288
block_remaining -= EOP_RECORD_SIZE
289
data_remaining -= EOP_RECORD_SIZE
290
if block_remaining != 0:
291
log.error("Block size error.")
292
log.debug("Data: data=%d,block=%d,header=%d" % (data_remaining, block_remaining, header_remaining))
294
if page_flags & PAGE_FLAG_END_DOC or \
295
page_flags & PAGE_FLAG_END_STREAM:
298
state = STATE_FIXED_HEADER
301
log.debug("Read %d bytes" % total_bytes)
306
def buildMFPDTFBlock(data_type, page_flags=0, send_variant=False, data=None):
308
# [Variant header - dial, fax, or scan]
311
block = io.StringIO()
312
block.write(struct.pack("<I", 0)) # Block len (4bytes)
313
header_len = FIXED_HEADER_SIZE
316
if data_type == DT_DIAL_STRINGS:
317
header_len += DIAL_STRINGS_VARIANT_HEADER_SIZE
319
elif data_type == DT_FAX_IMAGES:
320
header_len += FAX_IMAGE_VARIANT_HEADER_SIZE
322
block.write(struct.pack("<H", header_len)) # Header len (2 bytes)
323
block.write(struct.pack("<B", data_type)) # Data type (1 byte)
324
block.write(struct.pack("<B", page_flags)) # Page flags (1 byte)
327
if data_type == DT_DIAL_STRINGS:
328
block.write(struct.pack("<BB", MAJOR_VER, MINOR_VER))
329
block.write(struct.pack("<H", 1)) # num strings
330
block.write(struct.pack("<H", 51)) # ?
332
elif data_type == DT_FAX_IMAGES:
333
block.write(struct.pack("<BB", MAJOR_VER, MINOR_VER))
334
block.write(struct.pack("<B", SRC_HOST)) # Data source (1 byte)
335
block.write(struct.pack("<H", 1)) # Num pages (2 bytes)
336
block.write(struct.pack("<B", TTI_NONE)) # TTI control
337
block.write(struct.pack("<I", 0)) # time (4 bytes)
338
block.write("\x00"*20) # T30_CSI (20 bytes)
339
block.write("\x20"*20) # T30_SUB (20 bytes)
340
block.write("\x20"*20) # T30_PWD (20 bytes)
341
block.write("<I", 0) # xaction ID (4 bytes)
343
if data_type == DT_DIAL_STRINGS:
345
dial_string = data['dial-string']
346
block.write(dial_string)
347
block.write('\x00'*(51-len(dial_string)))
349
elif data_type == DT_FAX_IMAGES:
353
# fixed header (8 bytes):
355
# +----------------------------+
357
# | block len (32 bits) |
358
# | length of entire |
360
# +----------------------------+
362
# | header length (16 bits) |
363
# | length of fixed and |
364
# | variant header (if any) |
365
# | ==8 if no variant (fixed |
367
# | >8 if variant header |
369
# +----------------------------+
371
# | data type (8 bits) | 3=DIAL_STRINGS
372
# | data type of data record(s)| 12=TTI BITMAP
374
# +----------------------------+
376
# | page flags (8 bits) |
378
# +----------------------------+
380
# followed by variant header and/or
383
# image header variant (10 bytes)
385
# +----------------------------+
387
# | major ver (8 bits) |
389
# +----------------------------+
391
# | minor ver (8 bits) |
393
# +----------------------------+
395
# | source pages (16 bits) |
397
# +----------------------------+
399
# | copies/page (16 bits) |
401
# +----------------------------+
403
# | zoom factor (16 bits) |
405
# +----------------------------+
407
# | jpeg Q factor (16 bits) |
409
# +----------------------------+
411
# dial strings variant header (6 bytes)
413
# +----------------------------+
415
# | major ver (8 bits) |
417
# +----------------------------+
419
# | minor ver (8 bits) |
421
# +----------------------------+
423
# | num strings (16 bits) |
425
# +----------------------------+
427
# | dial string len (16 bits) |
429
# +----------------------------+
431
# dial string data part
432
# +----------------------------+
434
# | dial string (51 bytes) |
436
# +----------------------------+
438
# start page (SOP) record (36 bytes)
440
# +----------------------------+
442
# | id = 0 (8 bits) |
444
# +----------------------------+
446
# | encoding (8 bits) |
448
# +----------------------------+
450
# | page num (16 bits) |
452
# +----------------------------+
454
# | black data desc (16 bytes) |
456
# +----------------------------+
458
# | cmy data desc (16 bytes) |
460
# +----------------------------+
463
# raster data record (4 bytes + data)
465
# +----------------------------+
467
# | id = 1 (8 bits) |
469
# +----------------------------+
471
# | unused (8 bits) |
473
# +----------------------------+
475
# | data bytes (n) (16 bits) |
477
# +----------------------------+
481
# +----------------------------+
484
# end page (EOP) record (12 bytes)
486
# +----------------------------+
488
# | id = 2 (8 bits) |
490
# +----------------------------+
492
# | unused (24 bits) |
494
# +----------------------------+
496
# | rows of black (32 bits) |
498
# +----------------------------+
500
# | rows of cmy (32 bits) |
502
# +----------------------------+