Skip to content

Commit

Permalink
Merge pull request #41 from rharkes/master
Browse files Browse the repository at this point in the history
Add LZ4 compression/decompression
  • Loading branch information
melissalinkert authored Nov 26, 2024
2 parents c95aee4 + 375e645 commit d08e608
Show file tree
Hide file tree
Showing 2 changed files with 197 additions and 0 deletions.
116 changes: 116 additions & 0 deletions src/main/java/ome/codecs/LZ4Codec.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/*
* #%L
* Image encoding and decoding routines.
* %%
* Copyright (C) 2005 - 2022 Open Microscopy Environment:
* - Board of Regents of the University of Wisconsin-Madison
* - Glencoe Software, Inc.
* - University of Dundee
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/

package ome.codecs;

import loci.common.RandomAccessInputStream;
import java.io.IOException;
import java.util.Arrays;

import io.airlift.compress.MalformedInputException;
import io.airlift.compress.lz4.Lz4Decompressor;
import io.airlift.compress.lz4.Lz4Compressor;


/**
* This class implements LZ4 decompression.
*
* @author Rolf Harkes r.harkes at nki.nl
*/
public class LZ4Codec extends BaseCodec {

/* @see BaseCodec#compress(byte[], CodecOptions) */
@Override
public byte[] compress(byte[] data, CodecOptions options)
throws CodecException
{
if (data == null || data.length == 0)
throw new IllegalArgumentException("No data to compress");
Lz4Compressor compressor = new Lz4Compressor();
byte[] output = new byte[compressor.maxCompressedLength(data.length)];
int len = compressor.compress(data,0, data.length, output, 0, output.length);
return Arrays.copyOfRange(output, 0, len);
}

/* @see BaseCodec#decompress(RandomAccessInputStream, CodecOptions) */
@Override
public byte[] decompress(RandomAccessInputStream in, CodecOptions options)
throws CodecException, IOException
{
long byteCount = in.length() - in.getFilePointer();
if (byteCount > Integer.MAX_VALUE || byteCount < 0) {
throw new CodecException("Integer overflow detected when calculating file byteCount.");
}
byte[] data = new byte[(int) byteCount];
in.readFully(data);
return decompress(data, options);
}

/* @see BaseCodec#decompress(byte[]) */
@Override
public byte[] decompress(byte[] data)
throws CodecException
{
return decompress(data, 0, data.length, data.length*255);
}

/* @see BaseCodec#decompress(byte[], CodecOptions) */
@Override
public byte[] decompress(byte[] data, CodecOptions options)
throws CodecException
{
return decompress(data, 0, data.length, options.maxBytes);
}

/**
* Decompresses a block of data of specified length from an initial offset.
*
* @param data The data to be decompressed.
* @param inputOffset The position of the input data at which to begin decompression.
* @param length The length of input data to be decompressed.
* @return The decompressed data.
* @throws CodecException If data is not valid.
*/
public byte[] decompress(byte[] data, int inputOffset, int length, int outputLength)
throws CodecException
{
Lz4Decompressor decompressor = new Lz4Decompressor();
byte[] output = new byte[outputLength];
try {
decompressor.decompress(data, inputOffset, length, output, 0, outputLength);
}
catch(MalformedInputException e) {
throw new CodecException(e);
}
return output;
}
}
81 changes: 81 additions & 0 deletions src/test/java/ome/codecs/LZ4CodecTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* #%L
* Image encoding and decoding routines.
* %%
* Copyright (C) 2005 - 2017 Open Microscopy Environment:
* - Board of Regents of the University of Wisconsin-Madison
* - Glencoe Software, Inc.
* - University of Dundee
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* #L%
*/

package ome.codecs;

import org.testng.annotations.Test;

import static org.testng.AssertJUnit.assertEquals;

public class LZ4CodecTest {

LZ4Codec codec = new LZ4Codec();

@Test
public void testCompressShortUniqueSequence() throws Exception {
byte[] expected = {-96,1,2,3,4,5,6,7,8,9,10};
byte[] in = {1,2,3,4,5,6,7,8,9,10};
CodecOptions options = new CodecOptions();
byte[] comp = codec.compress(in, options);
assertEquals(expected, comp);
}

@Test
public void testDecompressShortUniqueSequence() throws Exception {
byte[] in = {-96,1,2,3,4,5,6,7,8,9,10};
byte[] expected = {1,2,3,4,5,6,7,8,9,10};
CodecOptions options = new CodecOptions();
options.maxBytes=expected.length;
byte[] comp = codec.decompress(in, options);
assertEquals(expected, comp);
}

@Test
public void testCompressLongSeq() throws Exception {
byte[] expected = {21,0,1,0,21,1,1,0,21,2,1,0,21,3,1,0,21,4,1,0,21,5,1,0,21,6,1,0,21,7,1,0,21,8,1,0,21,9,1,0,21,10,1,0,21,11,1,0,21,12,1,0,21,13,1,0,21,14,1,0,21,15,1,0,21,16,1,0,21,17,1,0,21,18,1,0,21,19,1,0,21,20,1,0,21,21,1,0,21,22,1,0,21,23,1,0,21,24,1,0,21,25,1,0,21,26,1,0,21,27,1,0,21,28,1,0,21,29,1,0,21,30,1,0,21,31,1,0,21,32,1,0,21,33,1,0,21,34,1,0,21,35,1,0,21,36,1,0,21,37,1,0,21,38,1,0,21,39,1,0,21,40,1,0,21,41,1,0,21,42,1,0,21,43,1,0,21,44,1,0,21,45,1,0,21,46,1,0,21,47,1,0,21,48,1,0,21,49,1,0,21,50,1,0,21,51,1,0,21,52,1,0,21,53,1,0,21,54,1,0,21,55,1,0,21,56,1,0,21,57,1,0,21,58,1,0,21,59,1,0,21,60,1,0,21,61,1,0,21,62,1,0,21,63,1,0,21,64,1,0,21,65,1,0,21,66,1,0,21,67,1,0,21,68,1,0,21,69,1,0,21,70,1,0,21,71,1,0,21,72,1,0,21,73,1,0,21,74,1,0,21,75,1,0,21,76,1,0,21,77,1,0,21,78,1,0,21,79,1,0,21,80,1,0,21,81,1,0,21,82,1,0,21,83,1,0,21,84,1,0,21,85,1,0,21,86,1,0,21,87,1,0,21,88,1,0,21,89,1,0,21,90,1,0,21,91,1,0,21,92,1,0,21,93,1,0,21,94,1,0,21,95,1,0,21,96,1,0,21,97,1,0,21,98,1,0,-96,99,99,99,99,99,99,99,99,99,99};
byte[] in = {0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,30,30,31,31,31,31,31,31,31,31,31,31,32,32,32,32,32,32,32,32,32,32,33,33,33,33,33,33,33,33,33,33,34,34,34,34,34,34,34,34,34,34,35,35,35,35,35,35,35,35,35,35,36,36,36,36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,38,38,38,38,38,38,38,38,38,38,39,39,39,39,39,39,39,39,39,39,40,40,40,40,40,40,40,40,40,40,41,41,41,41,41,41,41,41,41,41,42,42,42,42,42,42,42,42,42,42,43,43,43,43,43,43,43,43,43,43,44,44,44,44,44,44,44,44,44,44,45,45,45,45,45,45,45,45,45,45,46,46,46,46,46,46,46,46,46,46,47,47,47,47,47,47,47,47,47,47,48,48,48,48,48,48,48,48,48,48,49,49,49,49,49,49,49,49,49,49,50,50,50,50,50,50,50,50,50,50,51,51,51,51,51,51,51,51,51,51,52,52,52,52,52,52,52,52,52,52,53,53,53,53,53,53,53,53,53,53,54,54,54,54,54,54,54,54,54,54,55,55,55,55,55,55,55,55,55,55,56,56,56,56,56,56,56,56,56,56,57,57,57,57,57,57,57,57,57,57,58,58,58,58,58,58,58,58,58,58,59,59,59,59,59,59,59,59,59,59,60,60,60,60,60,60,60,60,60,60,61,61,61,61,61,61,61,61,61,61,62,62,62,62,62,62,62,62,62,62,63,63,63,63,63,63,63,63,63,63,64,64,64,64,64,64,64,64,64,64,65,65,65,65,65,65,65,65,65,65,66,66,66,66,66,66,66,66,66,66,67,67,67,67,67,67,67,67,67,67,68,68,68,68,68,68,68,68,68,68,69,69,69,69,69,69,69,69,69,69,70,70,70,70,70,70,70,70,70,70,71,71,71,71,71,71,71,71,71,71,72,72,72,72,72,72,72,72,72,72,73,73,73,73,73,73,73,73,73,73,74,74,74,74,74,74,74,74,74,74,75,75,75,75,75,75,75,75,75,75,76,76,76,76,76,76,76,76,76,76,77,77,77,77,77,77,77,77,77,77,78,78,78,78,78,78,78,78,78,78,79,79,79,79,79,79,79,79,79,79,80,80,80,80,80,80,80,80,80,80,81,81,81,81,81,81,81,81,81,81,82,82,82,82,82,82,82,82,82,82,83,83,83,83,83,83,83,83,83,83,84,84,84,84,84,84,84,84,84,84,85,85,85,85,85,85,85,85,85,85,86,86,86,86,86,86,86,86,86,86,87,87,87,87,87,87,87,87,87,87,88,88,88,88,88,88,88,88,88,88,89,89,89,89,89,89,89,89,89,89,90,90,90,90,90,90,90,90,90,90,91,91,91,91,91,91,91,91,91,91,92,92,92,92,92,92,92,92,92,92,93,93,93,93,93,93,93,93,93,93,94,94,94,94,94,94,94,94,94,94,95,95,95,95,95,95,95,95,95,95,96,96,96,96,96,96,96,96,96,96,97,97,97,97,97,97,97,97,97,97,98,98,98,98,98,98,98,98,98,98,99,99,99,99,99,99,99,99,99,99};
CodecOptions options = new CodecOptions();
byte[] comp = codec.compress(in, options);
assertEquals(expected, comp);
}

@Test
public void testDecompressLongSeq() throws Exception {
byte[] in = {21,0,1,0,21,1,1,0,21,2,1,0,21,3,1,0,21,4,1,0,21,5,1,0,21,6,1,0,21,7,1,0,21,8,1,0,21,9,1,0,21,10,1,0,21,11,1,0,21,12,1,0,21,13,1,0,21,14,1,0,21,15,1,0,21,16,1,0,21,17,1,0,21,18,1,0,21,19,1,0,21,20,1,0,21,21,1,0,21,22,1,0,21,23,1,0,21,24,1,0,21,25,1,0,21,26,1,0,21,27,1,0,21,28,1,0,21,29,1,0,21,30,1,0,21,31,1,0,21,32,1,0,21,33,1,0,21,34,1,0,21,35,1,0,21,36,1,0,21,37,1,0,21,38,1,0,21,39,1,0,21,40,1,0,21,41,1,0,21,42,1,0,21,43,1,0,21,44,1,0,21,45,1,0,21,46,1,0,21,47,1,0,21,48,1,0,21,49,1,0,21,50,1,0,21,51,1,0,21,52,1,0,21,53,1,0,21,54,1,0,21,55,1,0,21,56,1,0,21,57,1,0,21,58,1,0,21,59,1,0,21,60,1,0,21,61,1,0,21,62,1,0,21,63,1,0,21,64,1,0,21,65,1,0,21,66,1,0,21,67,1,0,21,68,1,0,21,69,1,0,21,70,1,0,21,71,1,0,21,72,1,0,21,73,1,0,21,74,1,0,21,75,1,0,21,76,1,0,21,77,1,0,21,78,1,0,21,79,1,0,21,80,1,0,21,81,1,0,21,82,1,0,21,83,1,0,21,84,1,0,21,85,1,0,21,86,1,0,21,87,1,0,21,88,1,0,21,89,1,0,21,90,1,0,21,91,1,0,21,92,1,0,21,93,1,0,21,94,1,0,21,95,1,0,21,96,1,0,21,97,1,0,21,98,1,0,-96,99,99,99,99,99,99,99,99,99,99};
byte[] expected = {0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,30,30,31,31,31,31,31,31,31,31,31,31,32,32,32,32,32,32,32,32,32,32,33,33,33,33,33,33,33,33,33,33,34,34,34,34,34,34,34,34,34,34,35,35,35,35,35,35,35,35,35,35,36,36,36,36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,38,38,38,38,38,38,38,38,38,38,39,39,39,39,39,39,39,39,39,39,40,40,40,40,40,40,40,40,40,40,41,41,41,41,41,41,41,41,41,41,42,42,42,42,42,42,42,42,42,42,43,43,43,43,43,43,43,43,43,43,44,44,44,44,44,44,44,44,44,44,45,45,45,45,45,45,45,45,45,45,46,46,46,46,46,46,46,46,46,46,47,47,47,47,47,47,47,47,47,47,48,48,48,48,48,48,48,48,48,48,49,49,49,49,49,49,49,49,49,49,50,50,50,50,50,50,50,50,50,50,51,51,51,51,51,51,51,51,51,51,52,52,52,52,52,52,52,52,52,52,53,53,53,53,53,53,53,53,53,53,54,54,54,54,54,54,54,54,54,54,55,55,55,55,55,55,55,55,55,55,56,56,56,56,56,56,56,56,56,56,57,57,57,57,57,57,57,57,57,57,58,58,58,58,58,58,58,58,58,58,59,59,59,59,59,59,59,59,59,59,60,60,60,60,60,60,60,60,60,60,61,61,61,61,61,61,61,61,61,61,62,62,62,62,62,62,62,62,62,62,63,63,63,63,63,63,63,63,63,63,64,64,64,64,64,64,64,64,64,64,65,65,65,65,65,65,65,65,65,65,66,66,66,66,66,66,66,66,66,66,67,67,67,67,67,67,67,67,67,67,68,68,68,68,68,68,68,68,68,68,69,69,69,69,69,69,69,69,69,69,70,70,70,70,70,70,70,70,70,70,71,71,71,71,71,71,71,71,71,71,72,72,72,72,72,72,72,72,72,72,73,73,73,73,73,73,73,73,73,73,74,74,74,74,74,74,74,74,74,74,75,75,75,75,75,75,75,75,75,75,76,76,76,76,76,76,76,76,76,76,77,77,77,77,77,77,77,77,77,77,78,78,78,78,78,78,78,78,78,78,79,79,79,79,79,79,79,79,79,79,80,80,80,80,80,80,80,80,80,80,81,81,81,81,81,81,81,81,81,81,82,82,82,82,82,82,82,82,82,82,83,83,83,83,83,83,83,83,83,83,84,84,84,84,84,84,84,84,84,84,85,85,85,85,85,85,85,85,85,85,86,86,86,86,86,86,86,86,86,86,87,87,87,87,87,87,87,87,87,87,88,88,88,88,88,88,88,88,88,88,89,89,89,89,89,89,89,89,89,89,90,90,90,90,90,90,90,90,90,90,91,91,91,91,91,91,91,91,91,91,92,92,92,92,92,92,92,92,92,92,93,93,93,93,93,93,93,93,93,93,94,94,94,94,94,94,94,94,94,94,95,95,95,95,95,95,95,95,95,95,96,96,96,96,96,96,96,96,96,96,97,97,97,97,97,97,97,97,97,97,98,98,98,98,98,98,98,98,98,98,99,99,99,99,99,99,99,99,99,99};
CodecOptions options = new CodecOptions();
options.maxBytes=expected.length;
byte[] comp = codec.decompress(in, options);
assertEquals(expected, comp);
}
}

0 comments on commit d08e608

Please sign in to comment.