1 # -*- coding: utf-8 -*-
3 # (c) Copyright 2003-2007 Hewlett-Packard 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 = 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 = cStringIO.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 # +----------------------------+