Skip to content
Snippets Groups Projects
Commit 4888aa07 authored by Vojtech Moravec's avatar Vojtech Moravec
Browse files

Single plane sq compress/decompress.

parent ee3559d9
No related branches found
No related tags found
No related merge requests found
...@@ -50,11 +50,13 @@ public class DataCompressor { ...@@ -50,11 +50,13 @@ public class DataCompressor {
} }
case Decompress: { case Decompress: {
ImageDecompressor decompressor = new ImageDecompressor(parsedCliOptions); ImageDecompressor decompressor = new ImageDecompressor(parsedCliOptions);
if (decompressor.decompress()) { try {
} else { decompressor.decompress();
} catch (Exception e) {
System.err.println("Errors occurred during decompression."); System.err.println("Errors occurred during decompression.");
} System.err.println(e.getMessage());
return; e.printStackTrace();
} return;
} }
case PrintHelp: { case PrintHelp: {
formatter.printHelp("ijava -jar DataCompressor.jar", options); formatter.printHelp("ijava -jar DataCompressor.jar", options);
...@@ -71,8 +73,7 @@ public class DataCompressor { ...@@ -71,8 +73,7 @@ public class DataCompressor {
} }
return; return;
} }
} } return;
return;
} }
@NotNull @NotNull
......
...@@ -40,9 +40,28 @@ public class ParsedCliOptions { ...@@ -40,9 +40,28 @@ public class ParsedCliOptions {
private String getDefaultOutputFilePath(final String inputPath) { private String getDefaultOutputFilePath(final String inputPath) {
final File inputFile = new File(inputPath); final File inputFile = new File(inputPath);
final File outputFile = new File(Paths.get("").toAbsolutePath().toString(), final File outputFile = new File(Paths.get("").toAbsolutePath().toString(), inputFile.getName());
inputFile.getName() + CompressorDecompressorBase.EXTENSTION);
return (outputFile.getAbsolutePath()); String defaultValue = outputFile.getAbsolutePath();
switch (method) {
case Compress:
defaultValue += CompressorDecompressorBase.EXTENSTION;
break;
case Decompress: {
if (defaultValue.endsWith(CompressorDecompressorBase.EXTENSTION)) {
defaultValue = defaultValue.substring(0,
defaultValue.length() - CompressorDecompressorBase.EXTENSTION.length());
}
}
case PrintHelp:
break;
case InspectFile:
defaultValue += ".txt";
break;
}
return defaultValue;
} }
private void parseCLI(final CommandLine cmd) { private void parseCLI(final CommandLine cmd) {
......
...@@ -48,7 +48,6 @@ public class ImageCompressor extends CompressorDecompressorBase { ...@@ -48,7 +48,6 @@ public class ImageCompressor extends CompressorDecompressorBase {
dataOutputStream.flush(); dataOutputStream.flush();
dataOutputStream.close(); dataOutputStream.close();
fos.flush(); fos.flush();
fos.close(); fos.close();
} }
......
...@@ -2,32 +2,28 @@ package compression; ...@@ -2,32 +2,28 @@ package compression;
import cli.ParsedCliOptions; import cli.ParsedCliOptions;
import compression.fileformat.QCMPFileHeader; import compression.fileformat.QCMPFileHeader;
import compression.io.InBitStream;
import compression.utilities.TypeConverter;
import java.io.*; import java.io.*;
public class ImageDecompressor extends CompressorDecompressorBase { public class ImageDecompressor extends CompressorDecompressorBase {
private FileInputStream fileInputStream = null;
private DataInputStream dataInputStream = null;
public ImageDecompressor(ParsedCliOptions options) { public ImageDecompressor(ParsedCliOptions options) {
super(options); super(options);
} }
public boolean decompress() {
return true;
}
private void openCompressStreams() throws FileNotFoundException { // private void openCompressStreams() throws FileNotFoundException {
fileInputStream = new FileInputStream(options.getInputFile()); // fileInputStream = new FileInputStream(options.getInputFile());
dataInputStream = new DataInputStream(fileInputStream); // dataInputStream = new DataInputStream(fileInputStream);
} // }
private void closeInputStreams() throws IOException { // private void closeInputStreams() throws IOException {
fileInputStream.close(); // fileInputStream.close();
dataInputStream.close(); // dataInputStream.close();
} // }
private long getExpectedDataSizeForScalarQuantization(final QCMPFileHeader header) { private long getExpectedDataSizeForScalarQuantization(final QCMPFileHeader header) {
final int codebookSize = (int) Math.pow(2, header.getBitsPerPixel()); final int codebookSize = (int) Math.pow(2, header.getBitsPerPixel());
...@@ -36,7 +32,7 @@ public class ImageDecompressor extends CompressorDecompressorBase { ...@@ -36,7 +32,7 @@ public class ImageDecompressor extends CompressorDecompressorBase {
codebookDataSize *= (header.isCodebookPerPlane() ? header.getImageSizeZ() : 1); codebookDataSize *= (header.isCodebookPerPlane() ? header.getImageSizeZ() : 1);
final long pixelCount = header.getImageSizeX() * header.getImageSizeY() * header.getImageSizeZ(); final long pixelCount = header.getImageSizeX() * header.getImageSizeY() * header.getImageSizeZ();
final long pixelDataSize = (pixelCount * header.getBitsPerPixel()) / 8; final long pixelDataSize = (int) Math.ceil((pixelCount * header.getBitsPerPixel()) / 8.0);
return (codebookDataSize + pixelDataSize); return (codebookDataSize + pixelDataSize);
} }
...@@ -57,21 +53,6 @@ public class ImageDecompressor extends CompressorDecompressorBase { ...@@ -57,21 +53,6 @@ public class ImageDecompressor extends CompressorDecompressorBase {
return -1; return -1;
} }
private boolean isValidQCMPFile() throws IOException {
openCompressStreams();
final QCMPFileHeader header = readQCMPFileHeader(dataInputStream);
closeInputStreams();
if (header == null) {
return false;
} else {
final long fileSize = new File(options.getInputFile()).length();
final long dataSize = fileSize - QCMPFileHeader.QCMP_HEADER_SIZE;
final long expectedDataSize = getExpectedDataSize(header);
return (dataSize == expectedDataSize);
}
}
private QCMPFileHeader readQCMPFileHeader(DataInputStream inputStream) throws IOException { private QCMPFileHeader readQCMPFileHeader(DataInputStream inputStream) throws IOException {
QCMPFileHeader header = new QCMPFileHeader(); QCMPFileHeader header = new QCMPFileHeader();
if (!header.readHeader(inputStream)) { if (!header.readHeader(inputStream)) {
...@@ -84,9 +65,15 @@ public class ImageDecompressor extends CompressorDecompressorBase { ...@@ -84,9 +65,15 @@ public class ImageDecompressor extends CompressorDecompressorBase {
public String inspectCompressedFile() throws IOException { public String inspectCompressedFile() throws IOException {
StringBuilder logBuilder = new StringBuilder(); StringBuilder logBuilder = new StringBuilder();
boolean validFile = true; boolean validFile = true;
openCompressStreams();
var fileInputStream = new FileInputStream(options.getInputFile());
var dataInputStream = new DataInputStream(fileInputStream);
final QCMPFileHeader header = readQCMPFileHeader(dataInputStream); final QCMPFileHeader header = readQCMPFileHeader(dataInputStream);
closeInputStreams();
fileInputStream.close();
dataInputStream.close();
if (header == null) { if (header == null) {
logBuilder.append("Input file is not valid QCMPFile\n"); logBuilder.append("Input file is not valid QCMPFile\n");
...@@ -139,4 +126,96 @@ public class ImageDecompressor extends CompressorDecompressorBase { ...@@ -139,4 +126,96 @@ public class ImageDecompressor extends CompressorDecompressorBase {
logBuilder.append("\n=== Input file is ").append(validFile ? "VALID" : "INVALID").append(" ===\n"); logBuilder.append("\n=== Input file is ").append(validFile ? "VALID" : "INVALID").append(" ===\n");
return logBuilder.toString(); return logBuilder.toString();
} }
public void decompress() throws Exception {
var fileInputStream = new FileInputStream(options.getInputFile());
var dataInputStream = new DataInputStream(fileInputStream);
final QCMPFileHeader header = readQCMPFileHeader(dataInputStream);
if (header == null) {
throw new Exception("Failed to read QCMPFile header");
}
if (!header.validateHeader()) {
throw new Exception("QCMPFile header is invalid");
}
final long fileSize = new File(options.getInputFile()).length();
final long dataSize = fileSize - QCMPFileHeader.QCMP_HEADER_SIZE;
final long expectedDataSize = getExpectedDataSize(header);
if (dataSize != expectedDataSize) {
throw new Exception("Invalid file size.");
}
FileOutputStream fos = new FileOutputStream(options.getOutputFile(), false);
DataOutputStream decompressStream = new DataOutputStream(fos);
switch (header.getQuantizationType()) {
case Scalar:
decompressUsingScalarQuantization(dataInputStream, decompressStream, header);
break;
case Vector1D:
case Vector2D:
// TODO!
break;
case Vector3D:
case Invalid:
throw new Exception("Invalid quantization type;");
}
fileInputStream.close();
dataInputStream.close();
decompressStream.flush();
decompressStream.close();
fos.flush();
fos.close();
}
private int[] readQuantizationValues(DataInputStream compressedStream, final int n) throws IOException {
int[] quantizationValues = new int[n];
for (int i = 0; i < n; i++) {
quantizationValues[i] = compressedStream.readUnsignedShort();
}
return quantizationValues;
}
private void decompressUsingScalarQuantization(DataInputStream compressedStream,
DataOutputStream decompressStream,
final QCMPFileHeader header) throws Exception {
final int codebookSize = (int) Math.pow(2, header.getBitsPerPixel());
final int planeCountForDecompression = header.getImageSizeZ();
final int planePixelCount = header.getImageSizeX() * header.getImageSizeY();
final int planeIndicesDataSize = (int) Math.ceil((planePixelCount * header.getBitsPerPixel()) / 8.0);
int[] quantizationValues = null;
if (!header.isCodebookPerPlane()) {
// There is only one codebook.
quantizationValues = readQuantizationValues(compressedStream, codebookSize);
}
for (int planeIndex = 0; planeIndex < planeCountForDecompression; planeIndex++) {
if (header.isCodebookPerPlane()) {
quantizationValues = readQuantizationValues(compressedStream, codebookSize);
}
assert (quantizationValues != null);
InBitStream inBitStream = new InBitStream(compressedStream, header.getBitsPerPixel(), planeIndicesDataSize);
inBitStream.readToBuffer();
inBitStream.setAllowReadFromUnderlyingStream(false);
final int[] indices = inBitStream.readNValues(planePixelCount);
short[] decompressedValues = new short[planePixelCount];
for (int i = 0; i < planePixelCount; i++) {
decompressedValues[i] = TypeConverter.intToShort(quantizationValues[indices[i]]);
}
final byte[] decompressedPlaneData = TypeConverter.shortArrayToByteArray(decompressedValues, false);
decompressStream.write(decompressedPlaneData);
}
}
} }
\ No newline at end of file
...@@ -15,6 +15,8 @@ public class InBitStream { ...@@ -15,6 +15,8 @@ public class InBitStream {
private final int bitsPerValue; private final int bitsPerValue;
private boolean allowReadFromUnderlyingStream = true;
public InBitStream(InputStream inputStream, final int bitsPerValue, final int bufferSize) { public InBitStream(InputStream inputStream, final int bitsPerValue, final int bufferSize) {
this.inputStream = inputStream; this.inputStream = inputStream;
this.bitsPerValue = bitsPerValue; this.bitsPerValue = bitsPerValue;
...@@ -27,11 +29,19 @@ public class InBitStream { ...@@ -27,11 +29,19 @@ public class InBitStream {
bitBufferSize = 0; bitBufferSize = 0;
} }
public void readToBuffer() throws IOException {
bytesAvailable = inputStream.read(buffer, 0, buffer.length);
bufferPosition = 0;
}
private void readByteToBitBuffer() throws IOException { private void readByteToBitBuffer() throws IOException {
if (!(bufferPosition < bytesAvailable)) { if (!(bufferPosition < bytesAvailable)) {
bytesAvailable = inputStream.read(buffer, 0, buffer.length); if (!allowReadFromUnderlyingStream) {
bufferPosition = 0; throw new IOException("Can not read from underlying stream.");
}
readToBuffer();
} }
if (bufferPosition < bytesAvailable) { if (bufferPosition < bytesAvailable) {
...@@ -51,10 +61,6 @@ public class InBitStream { ...@@ -51,10 +61,6 @@ public class InBitStream {
return (bit > 0 ? 1 : 0); return (bit > 0 ? 1 : 0);
} }
// boolean canRead() {
// birb
// }
public int readValue() throws IOException { public int readValue() throws IOException {
int result = 0; int result = 0;
int bit; int bit;
...@@ -75,5 +81,13 @@ public class InBitStream { ...@@ -75,5 +81,13 @@ public class InBitStream {
return values; return values;
} }
/**/ public boolean canReadFromUnderlyingStream() {
return allowReadFromUnderlyingStream;
}
public void setAllowReadFromUnderlyingStream(final boolean allowReadFromUnderlyingStream) {
this.allowReadFromUnderlyingStream = allowReadFromUnderlyingStream;
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment