-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcompression_decompression.py
167 lines (109 loc) · 4.68 KB
/
compression_decompression.py
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
import math
import struct
from collections import Counter
# Pliki używane do kompresji i dekompresji
generated_file = "generated.txt"
destination_file = "compressed.txt"
decompression_file = "decompressed.txt"
# Funckja, która tłumuczy zapis dziesiętny na zapis binarny
def translating_to_binary_char(symbol, length):
bin_symbol = bin(symbol)[2::]
extended_symbol = bin_symbol.rjust(length, "0")
return extended_symbol
# Pobieranie zawartości pliku
with open(generated_file, 'r') as file:
text_to_encrypt = file.read()
# Funkcja, zawierająca wszystkie dane użytkownika
def data():
k = len(text_to_encrypt) # Ilość występujących symboli w tekście
x = len(set(text_to_encrypt)) # Ilość unkilanych symboli w tekście
N = math.ceil(math.log2(x)) # Dlugość bitów dla zapisania jednej wartości
R = (8 - (k * N) % 8) % 8 # Bity uzupełniające
return k, x, N, R
# Funkcja sortownia ilości elementów zgdodnie z zapisem binaranym
def sort_binary_frequency_of_symbols():
# Obliczenie ilości unilanych elementów
unique_words_dict = Counter(text_to_encrypt)
# Sprawdzenia czy słownik nie jest pusty
if len(unique_words_dict):
# Pobieranie danych
k, x, N, R = data()
binary_representation = list()
# Tworzenie liczb binarnych dla każdego elemnetu
for i in range(x):
binary_representation.append(translating_to_binary_char(i, N))
binary_list = []
# Przejście po unikalnym wartościom: symbol oraz binarne reprezentowanie ilości wystąpień
for i, (ch, count) in enumerate(unique_words_dict.most_common()):
binary_representation_for_ch = binary_representation[i]
binary_list.append((ch, binary_representation_for_ch))
if R != 0:
binary_list.append(("rest", translating_to_binary_char(x, R)))
# Tworzenie słownika dla wygodnego wykorzystanie danych
binary_dict = dict(binary_list)
return binary_dict
else:
return ""
# Funckja tłumacząca bity 0 oraz 1 na bajty
def pack_array_of_bools():
with open(generated_file, 'r') as generated_text:
# Pobieranie danych
k, x, N, R = data()
bin_array, binary_dict = list(), sort_binary_frequency_of_symbols()
# Przedstawenie charów na bity True lub False
for char in generated_text.read():
if char in binary_dict:
binary_value = binary_dict[char]
for bin_value_to_save in binary_value:
bin_array.append(True if bin_value_to_save == '1' else False)
# Sprawdzenie czy bity uzupełniające nie równe zero:
if R != 0:
for char in binary_dict['rest']:
for bin_value_to_save in char:
bin_array.append(True if bin_value_to_save == '1' else False)
return bin_array
# Funkcja zapisywania kodu do pliku w postaci bajtów
def saving_to_file():
with open(destination_file, 'wb') as destination:
bin_array = pack_array_of_bools()
try:
chunks = [bin_array[i:i + 8] for i in range(0, len(bin_array), 8)]
for chunk in chunks:
packed_bytes = 0
for i, bit in enumerate(chunk):
packed_bytes |= bit << (7 - i)
destination.write(struct.pack('B', packed_bytes))
except TypeError:
print("File is empty!")
# Funckja dekompresji
def decompression():
with open(destination_file, "rb") as destination:
packed_data = destination.read()
# Wczytanie każdej wartości kompresowanego pliku, czyli każdego bajtu
bool_array = list()
for byte in packed_data:
for i in range(7, -1, -1):
# Tłumaczenie każdego bitu na str
bool_array.append(chr(ord('0') + ((byte >> i) & 1)))
bin_dict = sort_binary_frequency_of_symbols()
# Odwrócenie słownika: wartości i kluczów
reversed_bin_dict = {ch: freq for freq, ch in bin_dict.items()}
k, x, N, R = data()
# Odcięcie bitów uzupełniających w przypadku je istnienia
if R != 0:
bool_array = bool_array[:-R]
decompressed_data = list()
# Sprawdzenie każdej N odległości pomiędzy bitami
for i in range(0, len(bool_array), N):
compressed_data = "".join(bool_array[i:i + N])
decompressed_data.append(reversed_bin_dict[compressed_data])
# Zapisanie danych do pliku
with open(decompression_file, 'w') as decompressed_text:
for each_value in decompressed_data:
decompressed_text.write(each_value)
# Głowna funkcja
def main():
saving_to_file()
decompression()
if __name__ == "__main__":
main()