mattes/epeg

Documentation: add example code for using jna

beethoven2493 opened this issue · 0 comments

com.sun.jna is an excellent library for calling C from java. I've used this with epeg to great success.

For example:

public interface EpegLibrary extends Library {
    Pointer epeg_file_open(String fileName);
    Pointer epeg_memory_open(Memory memory, int len);
    void epeg_size_get(Pointer image, int[] width, int[] height);
    void epeg_decode_size_set(Pointer image, int width, int height);
    void epeg_quality_set(Pointer image, int quality);
    void epeg_memory_output_set(Pointer image, PointerByReference output, LongByReference size);
    int epeg_encode(Pointer image);
    void epeg_close(Pointer image);
}

private final EpegLibrary epeg = Native.loadLibrary("epeg", EpegLibrary.class);

// this is an unfortunate hack, I hope someone can figure out a better version
private static class ExposingFree extends Memory {
	public static void exposedFree(Pointer p) {
		free(Pointer.nativeValue(p));
	}
}

public byte[] thumb(String fileName, int targetBigDim, int targetLittleDim, int qualityOutOf100) {
	Pointer image = epeg.epeg_file_open(fileName);
	return thumb(image, targetBigDim, targetLittleDim, qualityOutOf100);
}

public byte[] thumb(byte[] source, int targetBigDim, int targetLittleDim, int qualityOutOf100) {
	Memory buf = new Memory(source.length);
	buf.write(0, source, 0, source.length);
	Pointer image = epeg.epeg_memory_open(buf, source.length);
	byte[] result = thumb(image, targetBigDim, targetLittleDim, qualityOutOf100);
	// would free memory here, but it apparently just gets GC'd
	return result;
}

private byte[] thumb(Pointer image, int targetBigDim, int targetLittleDim, int qualityOutOf100) {
	if (image == null)
		return null;
	int[] width = new int[1];
	int[] height = new int[1];
	epeg.epeg_size_get(image, width, height);
	while ((width[0] >= targetBigDim * 2 && height[0] >= targetBigDim * 2) || (width[0] >= targetLittleDim * 2 || height[0] >= targetLittleDim * 2)) {
		width[0] /= 2;
		height[0] /= 2;
	}
	epeg.epeg_decode_size_set(image, width[0], height[0]);
	epeg.epeg_quality_set(image, qualityOutOf100);
	PointerByReference m = new PointerByReference();
	LongByReference sizeMem = new LongByReference();
	sizeMem.setValue(0);
	epeg.epeg_memory_output_set(image, m, sizeMem);
	int encodeStatus = epeg.epeg_encode(image);
	try {
        if (encodeStatus != 0) {
            throw new RuntimeException("epeg_encode: Error encoding, error=" + encodeStatus);
        }
        long size = sizeMem.getValue();
        if (size == 0) {
            throw new RuntimeException("epeg: Size was 0");
        }
        if (size > Integer.MAX_VALUE) {
            throw new RuntimeException("epeg: Size was > 2GB");
        }
        Pointer pointer = m.getValue();
        try {
            byte[] bytes = pointer.getByteArray(0, (int)size);
            return bytes;
        } finally {
            ExposingFree.exposedFree(pointer);
        }
    } finally {
        epeg.epeg_close(image);
    }
}