]> vgcfreebox.myrthtech.pt Git - ue-ccd-compressaodeimagensbinarias.git/blob - lz78/lz_78.py
second version delivered to teacher
[ue-ccd-compressaodeimagensbinarias.git] / lz78 / lz_78.py
1 import sys
2 import struct
3
4 ########################################################################################
5 # python lz_78.py <d/c> <caminho_para_o_ficheiro_original>
6 #
7 # c: comprimir
8 # d: descomprimir
9 #
10 # Os ficheiros gerados ficarão na mesma pasta que o script
11 ########################################################################################
12
13 def lz78_compression(image):
14 dictionary = {
15 0: ""
16 }
17
18 output = []
19
20 symbol = ""
21
22 for i in image:
23 if (symbol + i) in dictionary.values():
24 symbol += i
25 else:
26 if symbol == "":
27 output.append([0, i])
28 dictionary[len(dictionary)] = i
29 else:
30 output.append([list(dictionary.keys())[list(dictionary.values()).index(symbol)], i])
31 dictionary[len(dictionary)] = symbol + i
32 symbol = ""
33
34 if symbol != "":
35 idx = list(dictionary.keys())[list(dictionary.values()).index(symbol)]
36 output.append([idx, ""])
37
38 return output, dictionary
39
40 def lz78_decompression(compressed_image):
41 dictionary = {
42 0: ""
43 }
44
45 output = ""
46
47 for i in compressed_image:
48 output += dictionary.get(i[0]) + i[1]
49 dictionary[len(dictionary)] = dictionary.get(i[0]) + i[1]
50
51 return output
52
53 def clean_image_data(image_data):
54
55 clean_text = ""
56
57 for line in image_data:
58 line = line.strip()
59 line = line.replace(" ", "")
60 if not line or line.startswith('#'):
61 continue
62 clean_text += line
63
64 return clean_text
65
66 def chunkstring(string, length):
67 return [string[i : length+i] for i in range(0, len(string), length)]
68
69 #Comprimir
70 if sys.argv[1] == "c":
71
72 with open(sys.argv[2], "r") as image:
73 lines = image.readlines()
74 image_size = lines[1]
75
76 if lines[0].strip() != 'P1':
77 raise ValueError("This is not a pbm file")
78
79 clean_text = clean_image_data(lines[2:]) #Limpa os espaços em branco para comprimir melhor
80
81 output, dic = lz78_compression(clean_text)
82
83 print(f"Output: {output}\n")
84 print(f"Dictionary: {dic}")
85
86 #Compressão em texto (human-readable)
87 with open(sys.argv[2] + "_compressed", "w") as save_file:
88 save_file.write(f"{output} \n{image_size}")
89
90 #Compressão em binário (compressão "a sério")
91 with open(sys.argv[2] + ".bin", "wb") as save_file:
92 largura = int(image_size.split()[0])
93 altura = int(image_size.split()[1])
94 save_file.write(struct.pack('II', largura, altura))
95
96 for indice, simbolo in output:
97 simbolo_byte = ord(simbolo) if simbolo != "" else 0
98 save_file.write(struct.pack('HB', indice, simbolo_byte))
99 #Descomprimir
100 elif sys.argv[1] == "d":
101
102 #Descomprimir do ficheiro de texto
103 with open(sys.argv[2] + "_compressed", "r") as image:
104 lines = image.readlines()
105
106 compressed_image = eval(lines[0])
107 image_size = lines[1]
108 length = int(lines[1].split(" ")[0])
109
110 output = lz78_decompression(compressed_image)
111
112 chuncked_output = chunkstring(output, length)
113
114 with open(sys.argv[2] + "_decompressed", "w") as save_file:
115 save_file.write(f"P1\n{image_size}")
116 for line in chuncked_output:
117 save_file.write(f"{line}\n")
118
119 #Descomprimir do binário
120 with open(sys.argv[2] + ".bin", "rb") as image:
121 header = image.read(8)
122 largura, altura = struct.unpack('II', header)
123
124 compressed_image_bin = []
125 while True:
126 chunk = image.read(3)
127 if not chunk:
128 break
129 indice, simbolo_byte = struct.unpack('HB', chunk)
130 simbolo = chr(simbolo_byte) if simbolo_byte != 0 else ""
131 compressed_image_bin.append([indice, simbolo])
132
133 output = lz78_decompression(compressed_image_bin)
134
135 chuncked_output = chunkstring(output, largura)
136
137 with open(sys.argv[2]+ "_bin_decompressed", "w") as save_file:
138 save_file.write(f"P1\n{largura} {altura}\n")
139 for line in chuncked_output:
140 save_file.write(f"{line}\n")