SHOW:
|
|
- or go back to the newest paste.
1 | class BitWriter(): | |
2 | def __init__(self, consumer): | |
3 | self.consumer = consumer | |
4 | self.bit_buffer = 0 | |
5 | self.bit_buffer_len = 0 | |
6 | ||
7 | def write_bits(self, value, bits): | |
8 | # TODO catch invalid parameter | |
9 | self.bit_buffer |= value << self.bit_buffer_len | |
10 | self.bit_buffer_len += bits | |
11 | while self.bit_buffer_len >= 8: | |
12 | self.consumer.write(chr(self.bit_buffer & 0xff)) | |
13 | self.bit_buffer >>= 8 | |
14 | self.bit_buffer_len -= 8 | |
15 | ||
16 | def finish(self): | |
17 | if self.bit_buffer_len > 0: | |
18 | self.consumer.write(chr(self.bit_buffer & 0xff)) | |
19 | ||
20 | def lzw_encode_default(data, code_bits): | |
21 | """ | |
22 | @data: bytes (in py3) or something iterable with ints <= 255 | |
23 | @code_bits: the minimum_lzw_size (size of code in bits at start = code_bits +1) | |
24 | data should contain the frames pixel index data. | |
25 | - | The result is a string (or byte in py3). |
25 | + | The result is a string (or bytes in py3). |
26 | TODO: replace StringIO with BytesIo | |
27 | """ | |
28 | MAX_DICT_SIZE = 4096 | |
29 | buf = StringIO() | |
30 | writer = BitWriter(buf) | |
31 | ||
32 | if code_bits < 2 or code_bits > 8: | |
33 | raise Exception("Invalid code size"); | |
34 | ||
35 | code_size = code_bits +1 | |
36 | clear_code = 1 << code_bits | |
37 | eoi_code = clear_code +1 | |
38 | next_code = eoi_code +1 | |
39 | # We could use lists or arrays or something more memory friendly here i guess ? | |
40 | # Also we don't really need to recreate all the lists. Zeroing all fields should be enough ? | |
41 | - | root = [[None]*256]*(1 << code_size) |
41 | + | root = list() |
42 | for x in xrange(1 << code_size): | |
43 | root.append([None]*256) | |
44 | - | i = 1 |
44 | + | |
45 | - | last_index = data[0] |
45 | + | |
46 | - | while i < len(data) -1: |
46 | + | i = 0 |
47 | while i < len(data): | |
48 | - | while i < len(data) -1 and not root[last_index][data[i]] is None: |
48 | + | # print("now index #%i (%i)" % (i, data[i])) |
49 | - | last_index = root[last_index][data[i]] |
49 | + | last_index = data[i] |
50 | - | i += 1 |
50 | + | o = i + 1 |
51 | # If we are reading the last byte just write it out as it is. | |
52 | if o >= len(data): | |
53 | - | root[last_index][data[i]] = next_code |
53 | + | writer.write_bits(data[i], code_size) |
54 | break | |
55 | - | # Add new dictionary entry |
55 | + | |
56 | # Loop till we find an unknown sequence | |
57 | # print("Do we know %i -> %i ?" % (last_index, data[o])) | |
58 | while (o < len(data) -1 and not root[last_index][ data[o] ] is None): | |
59 | # print("Known %i -> %i" % (last_index, root[last_index][ data[o] ])) | |
60 | - | root.extend( [ [None]*255 ] * ((1 << code_size) - (1 << (code_size-1))) ) |
60 | + | last_index = root[last_index][ data[o] ] |
61 | - | #print("increase code size to", self.codeBits) |
61 | + | o += 1 |
62 | # print("Do we know %i -> %i ?" % (last_index, data[o])) | |
63 | ||
64 | # print("Create chain from %i to %i (%i)" % (last_index, data[o], next_code)) | |
65 | root[last_index][data[o]] = next_code | |
66 | writer.write_bits(last_index, code_size) | |
67 | - | root = [[None]*265]*(1 << code_size) |
67 | + | i = o |
68 | - | pass |
68 | + | |
69 | #// Add new dictionary entry | |
70 | if next_code < MAX_DICT_SIZE: | |
71 | if (next_code & (next_code - 1)) == 0: #// Is a power of 2 | |
72 | code_size += 1 | |
73 | # TODO: clean this up # Should be way nicer to calc.. to tired TODO: | |
74 | for x in xrange((1 << code_size) - (1 << (code_size-1))): | |
75 | root.append([None]*256) | |
76 | # print("increase code size to", self.codeBits) | |
77 | next_code += 1 | |
78 | else: | |
79 | writer.write_bits(clear_code, code_size) | |
80 | code_size = code_bits +1 | |
81 | next_code = eoi_code +1 | |
82 | root = list() | |
83 | for x in xrange(1 << code_size): | |
84 | root.append([None]*256) | |
85 | ||
86 | writer.write_bits(eoi_code, code_size) | |
87 | writer.finish() | |
88 | return buf.getvalue() |