You can of course, but the ImageIO API is terrible. This may get you started:
/** If alpha is true, returns an RGBA buffer, else returns an RGB buffer. */
static public BufferedImage pixmapToImage (Pixmap pixmap, boolean alpha, @Null BufferedImage reuse) {
DirectColorModel colorModel;
if (alpha)
colorModel = rgbaColorModel;
else
colorModel = rgbColorModel;
if (reuse != null) {
if (reuse.getWidth() == pixmap.getWidth() && reuse.getHeight() == pixmap.getHeight()
&& reuse.getColorModel() == colorModel && reuse.getRaster().getDataBuffer() instanceof BufferRGBA rgba) {
rgba.setPixmap(pixmap);
return reuse;
}
reuse.flush();
}
DataBuffer buffer = alpha ? new BufferRGBA(pixmap) : new BufferRGB(pixmap);
SampleModel sampleModel = colorModel.createCompatibleSampleModel(pixmap.getWidth(), pixmap.getHeight());
var raster = new WritableRaster(sampleModel, buffer, new Point()) {};
return new BufferedImage(colorModel, raster, false, null);
}
static private final DirectColorModel rgbaColorModel = new DirectColorModel(32, //
0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
static private final DirectColorModel rgbColorModel = new DirectColorModel(24, //
0x00ff0000, 0x0000ff00, 0x000000ff);
static public class BufferRGBA extends DataBuffer {
protected ByteBuffer pixels;
int width, height;
public BufferRGBA (Pixmap pixmap) {
super(DataBuffer.TYPE_INT, pixmap.getWidth() * pixmap.getHeight());
setPixmap(pixmap);
}
public void setPixmap (Pixmap pixmap) {
if (getSize() != pixmap.getWidth() * pixmap.getHeight()) throw error();
width = pixmap.getWidth();
height = pixmap.getHeight();
pixels = pixmap.getPixels();
}
public void setElem (int bank, int index, int value) {
pixels.putInt(index, value);
}
public int getElem (int bank, int index) {
return pixels.getInt(index << 2);
}
public void toInts (int[] ints) {
IntBuffer buffer = pixels.order(ByteOrder.BIG_ENDIAN).asIntBuffer();
if (ints.length != buffer.remaining()) throw error();
buffer.get(ints);
}
}
static public class BufferRGB extends BufferRGBA {
public BufferRGB (Pixmap pixmap) {
super(pixmap);
}
public int getElem (int bank, int index) {
return pixels.getInt(index << 2) >> 8; // rgba -> rgb
}
public void toInts (int[] ints) {
int bytesPerLine = width * 4;
var line = new byte[bytesPerLine];
for (int i = 0, n = width * height; i < n;) {
pixels.get(line, 0, bytesPerLine);
for (int x = 0; x < bytesPerLine; x += 4) {
int r = line[x] & 0xFF;
int g = line[x + 1] & 0xFF;
int b = line[x + 2] & 0xFF;
ints[i++] = (r << 16) | (g << 8) | b;
}
}
pixels.position(0);
}
}
I think I got all the app classes. The rest are imported from ImageIO and libgdx.
The GIF format is simple, if very old. However, making a GIF can be complex because of temporal quantization: reducing to 256 colors over multiple frames, without the colors flickering across frames. I suggest using gifski if high quality is important. There is a Java wrapper that we created or you can run it from the CLI. Gifski makes high quality GIFs, but they are large. If you want smaller GIFs, you will have poor quality. With the Java wrapper you don't need ImageIO garbage.