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