1 /*
2 Copyright (c) 2015 Timur Gafarov
3
4 Boost Software License - Version 1.0 - August 17th, 2003
5
6 Permission is hereby granted, free of charge, to any person or organization
7 obtaining a copy of the software and accompanying documentation covered by
8 this license (the "Software") to use, reproduce, display, distribute,
9 execute, and transmit the Software, and to prepare derivative works of the
10 Software, and to permit third-parties to whom the Software is furnished to
11 do so, all subject to the following:
12
13 The copyright notices in the Software and this entire statement, including
14 the above license grant, this restriction and the following disclaimer,
15 must be included in all copies of the Software, in whole or in part, and
16 all derivative works of the Software, unless such copies or derivative
17 works are solely in the form of machine-executable object code generated by
18 a source language processor.
19
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 DEALINGS IN THE SOFTWARE.
27 */
28
29 // dimage is actually stripped out part of dlib - just to support reading PNG and JPEG
30 module dimage.huffman;
31
32 import dimage.memory;
33 import dimage.bitio;
34
35 //import dlib.core.memory;
36 //import dlib.core.bitio;
37
38 struct HuffmanTreeNode
39 {
40 HuffmanTreeNode* parent;
41 HuffmanTreeNode* left;
42 HuffmanTreeNode* right;
43 ubyte ch;
44 uint freq;
45 bool blank = true;
46
47 this(
48 HuffmanTreeNode* leftNode,
49 HuffmanTreeNode* rightNode,
50 ubyte symbol,
51 uint frequency,
52 bool isBlank)
53 {
54 parent = null;
55 left = leftNode;
56 right = rightNode;
57
58 if (left !is null)
59 left.parent = &this;
60 if (right !is null)
61 right.parent = &this;
62
63 ch = symbol;
64 freq = frequency;
65 blank = isBlank;
66 }
67
68 bool isLeaf()
69 {
70 return (left is null && right is null);
71 }
72
73 void free()
74 {
75 if (left !is null)
76 {
77 left.free();
78 Delete(left);
79 }
80
81 if (right !is null)
82 {
83 right.free();
84 Delete(right);
85 }
86 }
87
88 /*
89 // TODO: implement this without GC
90
91 void getCodes(ref string[ubyte] table, string code = "")
92 {
93 if (isLeaf())
94 {
95 table[ch] = code;
96 }
97 else
98 {
99 if (left !is null)
100 left.getCodes(table, code ~ '0');
101 if (right !is null)
102 right.getCodes(table, code ~ '1');
103 }
104 }
105
106 void print(string indent = "")
107 {
108 writefln("%s<%s>%x", indent, freq, ch);
109 indent ~= " ";
110 if (left !is null)
111 left.print(indent);
112 if (right !is null)
113 right.print(indent);
114 }
115 */
116 }
117
118 /*
119 // TODO: implement this without GC
120
121 HuffmanTreeNode* buildHuffmanTree(ubyte[] data)
122 {
123 // Count frequencies
124 uint[ubyte] freqs;
125 foreach(s; data)
126 {
127 if (s in freqs)
128 freqs[s] += 1;
129 else
130 freqs[s] = 1;
131 }
132
133 // Sort in descending order
134 ubyte[] symbols = freqs.keys;
135 sort!((a, b) => freqs[a] > freqs[b])(symbols);
136
137 // Create node list
138 auto nodeList = new HuffmanTreeNode*[symbols.length];
139 foreach(i, s; symbols)
140 nodeList[i] = new HuffmanTreeNode(null, null, s, freqs[s], false);
141
142 // Build tree
143 while (nodeList.length > 1)
144 {
145 // Pop two nodes with minimal frequencies
146 auto n1 = nodeList[$-1];
147 auto n2 = nodeList[$-2];
148 nodeList.popBack;
149 nodeList.popBack;
150
151 // Insert a new parent node
152 uint fsum = n1.freq + n2.freq;
153 auto parent = new HuffmanTreeNode(n1, n2, 0, fsum, false);
154 nodeList ~= parent;
155 sort!((a, b) => a.freq > b.freq)(nodeList);
156 }
157
158 auto root = nodeList[0];
159
160 return root;
161 }
162
163 void packHuffmanTree(HuffmanTreeNode* node, BitWriter* bw)
164 {
165 if (node.isLeaf)
166 {
167 bw.writeBit(true);
168 bw.writeByte(node.ch);
169 }
170 else
171 {
172 bw.writeBit(false);
173 packHuffmanTree(node.left, bw);
174 packHuffmanTree(node.right, bw);
175 }
176 }
177
178 HuffmanTreeNode* unpackHuffmanTree(BitReader* br)
179 {
180 if (!br.end)
181 {
182 bool bit = br.readBit();
183 if (bit)
184 {
185 byte ch = br.readByte();
186 return new HuffmanTreeNode(null, null, ch, 0, false);
187 }
188 else
189 {
190 HuffmanTreeNode* left = unpackHuffmanTree(br);
191 HuffmanTreeNode* right = unpackHuffmanTree(br);
192 return new HuffmanTreeNode(left, right, 0, 0, false);
193 }
194 }
195 else return null;
196 }
197
198 ubyte[] encodeHuffman(ubyte[] data, out HuffmanTreeNode* tree)
199 {
200 // Build Huffman tree
201 tree = buildHuffmanTree(data);
202
203 // Generate binary codes
204 string[ubyte] huffTable;
205 tree.getCodes(huffTable);
206
207 // Encode data
208 string bitStr;
209 foreach(s; data)
210 bitStr ~= huffTable[s];
211
212 // Pack bits to byte array
213 uint octetsLen = 0;
214 ubyte lastBits = 0;
215 if (bitStr.length == 8)
216 {
217 octetsLen = 1;
218 }
219 else if (bitStr.length > 8)
220 {
221 octetsLen = cast(uint)bitStr.length / 8;
222 lastBits = cast(ubyte)(bitStr.length % 8);
223 if (lastBits != 0)
224 octetsLen++;
225 }
226 else
227 {
228 octetsLen = 1;
229 lastBits = cast(ubyte)(bitStr.length);
230 }
231
232 octetsLen++;
233 auto octets = new ubyte[octetsLen];
234 octets[0] = lastBits;
235
236 uint bitPos = 0;
237 uint bytePos = 1;
238
239 foreach(bit; bitStr)
240 {
241 bool state;
242 if (bit == '0')
243 state = false;
244 else
245 state = true;
246
247 octets[bytePos] = setBit(octets[bytePos], bitPos, state);
248 bitPos++;
249
250 if (bitPos == 8)
251 {
252 bitPos = 0;
253 bytePos++;
254 }
255 }
256
257 return octets;
258 }
259
260 ubyte[] decodeHuffman(ubyte[] data, HuffmanTreeNode* tree)
261 {
262 // Generate binary codes
263 string[ubyte] huffTable;
264 tree.getCodes(huffTable);
265
266 //Unpack bits from array
267 ubyte[] result;
268 bool appendNext = true;
269 string code = "";
270 ubyte lastBits = data[0];
271 foreach(i, b; data[1..$])
272 {
273 uint len;
274 if ((lastBits != 0) && (i == data.length-1))
275 len = lastBits;
276 else
277 len = 8;
278
279 foreach(bp; 0..len)
280 {
281 char bitChr = getBit(b, bp)? '1':'0';
282 if (appendNext)
283 {
284 code ~= bitChr;
285 foreach(key, val; huffTable)
286 {
287 if (code == val)
288 {
289 result ~= key;
290 appendNext = false;
291 break;
292 }
293 }
294 }
295 else
296 {
297 code = "";
298 code ~= bitChr;
299 appendNext = true;
300 }
301 }
302 }
303
304 return result;
305 }
306
307 */
308
309