From f55cdca68160fdf5c5253b92c561a0a68c9f716c Mon Sep 17 00:00:00 2001
From: Vojtech Moravec <vojtech.moravec.st@vsb.cz>
Date: Wed, 2 Dec 2020 14:27:03 +0100
Subject: [PATCH] Write binary encoded huffman tree in compression.

This can't be used fully atm, becuase we haven't updated the QCMP file
header to report ver.2. The Decompressors will now try to read
frequencies values, which will fail!
---
 .../java/cz/it4i/qcmp/compression/ImageCompressor.java    | 1 +
 .../java/cz/it4i/qcmp/compression/SQImageCompressor.java  | 8 +++++---
 .../cz/it4i/qcmp/compression/SQImageDecompressor.java     | 1 +
 .../java/cz/it4i/qcmp/compression/VQImageCompressor.java  | 7 +++----
 .../cz/it4i/qcmp/compression/VQImageDecompressor.java     | 1 +
 5 files changed, 11 insertions(+), 7 deletions(-)

diff --git a/src/main/java/cz/it4i/qcmp/compression/ImageCompressor.java b/src/main/java/cz/it4i/qcmp/compression/ImageCompressor.java
index 3ff365c..7ff58e1 100644
--- a/src/main/java/cz/it4i/qcmp/compression/ImageCompressor.java
+++ b/src/main/java/cz/it4i/qcmp/compression/ImageCompressor.java
@@ -217,6 +217,7 @@ public class ImageCompressor extends CompressorDecompressorBase {
      * @return Valid QCMPFile header for compressed file.
      */
     private QCMPFileHeader createHeader() {
+        // TODO(Moravec): Change header to newer version!
         final QCMPFileHeader header = new QCMPFileHeader();
 
 
diff --git a/src/main/java/cz/it4i/qcmp/compression/SQImageCompressor.java b/src/main/java/cz/it4i/qcmp/compression/SQImageCompressor.java
index aee6464..2a5e8f0 100644
--- a/src/main/java/cz/it4i/qcmp/compression/SQImageCompressor.java
+++ b/src/main/java/cz/it4i/qcmp/compression/SQImageCompressor.java
@@ -7,6 +7,7 @@ import cz.it4i.qcmp.cache.SqQvcFile;
 import cz.it4i.qcmp.compression.exception.ImageCompressionException;
 import cz.it4i.qcmp.huffman.HuffmanEncoder;
 import cz.it4i.qcmp.io.InputData;
+import cz.it4i.qcmp.io.OutBitStream;
 import cz.it4i.qcmp.io.loader.IPlaneLoader;
 import cz.it4i.qcmp.io.loader.PlaneLoaderFactory;
 import cz.it4i.qcmp.quantization.scalar.LloydMaxU16ScalarQuantization;
@@ -59,14 +60,15 @@ public class SQImageCompressor extends CompressorDecompressorBase implements IIm
                                              final DataOutputStream compressStream) throws ImageCompressionException {
         final SQCodebook codebook = quantizer.getCodebook();
         final int[] centroids = codebook.getCentroids();
-        final long[] frequencies = codebook.getSymbolFrequencies();
         try {
             for (final int quantizationValue : centroids) {
                 compressStream.writeShort(quantizationValue);
             }
-            for (final long symbolFrequency : frequencies) {
-                compressStream.writeLong(symbolFrequency);
+
+            try (final OutBitStream outBitStream = new OutBitStream(compressStream, options.getBitsPerCodebookIndex(), 32)) {
+                codebook.getHuffmanTreeRoot().writeToBinaryStream(outBitStream);
             }
+
         } catch (final IOException ioEx) {
             throw new ImageCompressionException("Unable to write codebook to compress stream.", ioEx);
         }
diff --git a/src/main/java/cz/it4i/qcmp/compression/SQImageDecompressor.java b/src/main/java/cz/it4i/qcmp/compression/SQImageDecompressor.java
index e3433a4..a7c3c42 100644
--- a/src/main/java/cz/it4i/qcmp/compression/SQImageDecompressor.java
+++ b/src/main/java/cz/it4i/qcmp/compression/SQImageDecompressor.java
@@ -30,6 +30,7 @@ public class SQImageDecompressor extends CompressorDecompressorBase implements I
             for (int i = 0; i < codebookSize; i++) {
                 quantizationValues[i] = compressedStream.readUnsignedShort();
             }
+            // TODO(Moravec): Read frequencies or binary huffman tree based on file format version!!!
             for (int i = 0; i < codebookSize; i++) {
                 symbolFrequencies[i] = compressedStream.readLong();
             }
diff --git a/src/main/java/cz/it4i/qcmp/compression/VQImageCompressor.java b/src/main/java/cz/it4i/qcmp/compression/VQImageCompressor.java
index 0bdd52f..0c8c112 100644
--- a/src/main/java/cz/it4i/qcmp/compression/VQImageCompressor.java
+++ b/src/main/java/cz/it4i/qcmp/compression/VQImageCompressor.java
@@ -8,6 +8,7 @@ import cz.it4i.qcmp.data.Range;
 import cz.it4i.qcmp.fileformat.QuantizationType;
 import cz.it4i.qcmp.huffman.HuffmanEncoder;
 import cz.it4i.qcmp.io.InputData;
+import cz.it4i.qcmp.io.OutBitStream;
 import cz.it4i.qcmp.io.loader.IPlaneLoader;
 import cz.it4i.qcmp.io.loader.PlaneLoaderFactory;
 import cz.it4i.qcmp.quantization.vector.LBGResult;
@@ -72,7 +73,6 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
      */
     private void writeQuantizerToCompressStream(final VectorQuantizer quantizer,
                                                 final DataOutputStream compressStream) throws ImageCompressionException {
-        // TODO
         final int[][] codebook = quantizer.getCodebookVectors();
         try {
             for (final int[] entry : codebook) {
@@ -80,9 +80,8 @@ public class VQImageCompressor extends CompressorDecompressorBase implements IIm
                     compressStream.writeShort(vecVal);
                 }
             }
-            final long[] frequencies = quantizer.getFrequencies();
-            for (final long symbolFrequency : frequencies) {
-                compressStream.writeLong(symbolFrequency);
+            try (final OutBitStream outBitStream = new OutBitStream(compressStream, options.getBitsPerCodebookIndex(), 32)) {
+                quantizer.getCodebook().getHuffmanTreeRoot().writeToBinaryStream(outBitStream);
             }
         } catch (final IOException ioEx) {
             throw new ImageCompressionException("Unable to write codebook to compress stream.", ioEx);
diff --git a/src/main/java/cz/it4i/qcmp/compression/VQImageDecompressor.java b/src/main/java/cz/it4i/qcmp/compression/VQImageDecompressor.java
index 65af70f..87bc9c7 100644
--- a/src/main/java/cz/it4i/qcmp/compression/VQImageDecompressor.java
+++ b/src/main/java/cz/it4i/qcmp/compression/VQImageDecompressor.java
@@ -56,6 +56,7 @@ public class VQImageDecompressor extends CompressorDecompressorBase implements I
                     codebookVectors[codebookIndex][vecIndex] = compressedStream.readUnsignedShort();
                 }
             }
+            // TODO(Moravec): Read frequencies or binary huffman tree based on file format version!!!
             for (int codebookIndex = 0; codebookIndex < codebookSize; codebookIndex++) {
                 frequencies[codebookIndex] = compressedStream.readLong();
             }
-- 
GitLab