/**
*
*/
package compression;
import gr.zdimensions.jsquish.Squish;
import gr.zdimensions.jsquish.Squish.CompressionType;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import java.util.zip.DataFormatException;
import ddsutil.ByteBufferedImage;
/**
* Compressor for DXT-Compression
* @author danielsenff
*
*/
public class DXTBufferCompressor {
// byte[] compressedData;
protected byte[] byteData;
protected int[] intData;
protected Dimension dimension;
protected CompressionType compressionType;
/**
* @param data Byte-Array should store ARGB
* @param width
* @param height
* @param compressionType
*/
public DXTBufferCompressor(final byte[] data,
final int width,
final int height,
final Squish.CompressionType compressionType) {
this(data, new Dimension(width, height), compressionType);
}
/**
* @param byteBuffer ByteBuffer should store ARGB
* @param width
* @param height
* @param compressionType
*/
public DXTBufferCompressor(final ByteBuffer byteBuffer,
final int width,
final int height,
final Squish.CompressionType compressionType) {
this(toByteArray(byteBuffer),
new Dimension(width, height),
compressionType);
}
/**
* @param image
* @param compressionType
*/
public DXTBufferCompressor(final BufferedImage image,
final Squish.CompressionType compressionType) {
this(ByteBufferedImage.convertBIintoARGBArray((BufferedImage) image),
new Dimension(image.getWidth(null), image.getHeight(null)),
compressionType );
}
/**
* @param data Byte-Array should store ARGB
* @param dimension
* @param compressionType
*/
public DXTBufferCompressor(final byte[] data,
final Dimension dimension,
final Squish.CompressionType compressionType) {
this.byteData = data;
this.dimension = dimension;
this.compressionType = compressionType;
}
/**
* @param data
* @param dimension
* @param compressionType
*/
public DXTBufferCompressor(final int[] data,
final Dimension dimension,
final Squish.CompressionType compressionType) {
this.intData = data;
this.dimension = dimension;
this.compressionType = compressionType;
}
/**
* @return ByteBuffer
*/
public ByteBuffer getByteBuffer() {
byte[] compressedData;
try {
// the data-Array given to the squishCompressToArray is expected to be
// width * height * 4 -> with RGBA, which means, if we got RGB, we need to add A!
if(byteData.length < dimension.height*dimension.width*4) {
System.out.println("blow up array from RGB to ARGB");
byteData = convertRGBArraytiRGBAArray(byteData, dimension);
}
compressedData = squishCompressToArray(byteData, dimension.width, dimension.height, compressionType);
return ByteBuffer.wrap(compressedData);
} catch (DataFormatException e) {
e.printStackTrace();
}
return null;
}
private byte[] convertRGBArraytiRGBAArray(byte[] data, final Dimension dimension) {
int rgbLength = data.length;
int rgbaLength = dimension.width * dimension.height * 4;
byte[] rgbaBuffer = new byte[rgbaLength];
// populate new array
// we always copy 3 byte chunks, skip one byte, which we set to 255 and take the next 3 byte
int loopN = 0;
for (int i = 0; i < rgbLength; i=i+3) {
int srcPos = i;
int destPos = i+loopN;
System.arraycopy(data, srcPos, rgbaBuffer, destPos, 3);
loopN++;
}
return rgbaBuffer;
}
/**
* Get the Byte-array held by this object.
* @return
*/
public byte[] getArray() {
try {
return squishCompressToArray(byteData, dimension.width, dimension.height, compressionType);
} catch (final DataFormatException e) {
e.printStackTrace();
}
return byteData;
}
/**
* Compresses the RGBA-byte-array into a DXT-compressed {@link ByteBuffer}.
* @param rgba
* @param height
* @param width
* @param compressionType
* @return
*/
// private static ByteBuffer squishCompress(final byte[] rgba,
// final int width,
// final int height,
// final Squish.CompressionType compressionType) {
//
//
// ByteBuffer buffer = ByteBuffer.wrap(squishCompressToArray(rgba, width, height, compressionType));
// return buffer;
// }
/**
* Compresses the RGBA-byte-array into a DXT-compressed byte-array.
* @param rgba Byte-Array needs to be in RGBA-order
* @param height
* @param width
* @param compressionType
* @return
* @throws DataFormatException
*/
private static byte[] squishCompressToArray(final byte[] rgba,
final int width,
final int height,
final Squish.CompressionType compressionType) throws DataFormatException {
// expected array length
int length = width * height * 4;
if (rgba.length != length) throw new DataFormatException("unexpected length:" +
rgba.length + " instead of "+ length);
int storageRequirements = Squish.getStorageRequirements(width, height, compressionType);
return Squish.compressImage(rgba,
width,
height,
new byte[storageRequirements],
compressionType,
Squish.CompressionMethod.CLUSTER_FIT);
}
private static byte[] squishCompressToArray(final int[] rgba,
final int width,
final int height,
final Squish.CompressionType compressionType) throws DataFormatException {
// expected array length
int length = width * height;
if (rgba.length != length) throw new DataFormatException("unexpected length:" +
rgba.length + " instead of "+ length);
int storageRequirements = Squish.getStorageRequirements(width, height, compressionType);
return Squish.compressImage(rgba,
width,
height,
new byte[storageRequirements],
compressionType,
Squish.CompressionMethod.CLUSTER_FIT);
}
/**
* Compresses a {@link ByteBuffer} into a DXT-compressed {@link ByteBuffer}
* @param buffer
* @param width
* @param height
* @param compressionType
* @return
*/
// private static ByteBuffer squishCompress(final ByteBuffer bytebuffer,
// final int width ,final int height, final Squish.CompressionType compressionType) {
//
// //byte[] rgba = toByteArray(bytebuffer);
// return squishCompress(byteBuffer, width, height, compressionType);
// }
private static byte[] toByteArray(final ByteBuffer bytebuffer) {
byte[] rgba = new byte[bytebuffer.capacity()];
bytebuffer.get(rgba);
return rgba;
}
/**
* @return
*/
public int getStorageRequirements() {
return getStorageRequirements(dimension, compressionType);
}
/**
* Return the length of the required {@link ByteBuffer} for the image
* @param width
* @param height
* @param type
* @return
*/
public static int getStorageRequirements(final int width, final int height,
final Squish.CompressionType type) {
return Squish.getStorageRequirements(width, height, type);
}
/**
* Return the length of the required {@link ByteBuffer} for the image
* @param imageDimension
* @param type
* @return
*/
public static int getStorageRequirements(final Dimension imageDimension,
final Squish.CompressionType type) {
return Squish.getStorageRequirements((int)imageDimension.getWidth(), (int)imageDimension.getHeight(), type);
}
}