Поколение APNG с JavaJAVA

Программисты JAVA общаются здесь
Anonymous
Поколение APNG с Java

Сообщение Anonymous »

Я пытаюсь создать анимированную портативную сетевую графику (APNG), используя Java, но, к сожалению, все мои попытки до сих пор были неудачными. После некоторого поиска я наткнулся на фрагмент кода, который, казалось, предложил решение. Тем не менее, я все еще сталкиваюсь с проблемами и буду признателен за любым руководством или помощи от сообщества. < /P>
Вот код Java, с которым я работаю: < /p>
public static void createAPNGAnimation(ArrayList images, int delayMs, boolean infinite, FileOutputStream output) throws IOException {
// APNG signature (same as PNG)
byte[] pngSignature = new byte[]{(byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
output.write(pngSignature);

// Write IHDR chunk (Image Header)
byte[] ihdr = createIHDRChunk(images.get(0));
output.write(ihdr);

// Write acTL chunk (Animation Control)
byte[] acTL = createACTLChunk(images.size(), infinite ? 0 : 1);
output.write(acTL);

// Write frames
for (int i = 0; i < images.size(); i++) {
BufferedImage image = images.get(i);

// Write fcTL chunk (Frame Control)
byte[] fcTL = createFCTLChunk(i, delayMs, image.getWidth(), image.getHeight());
output.write(fcTL);

// Write IDAT or fdAT chunk (Image Data)
byte[] imageData = createIDATChunk(image);
if (i == 0) {
output.write(imageData); // First frame uses IDAT
} else {
byte[] fdAT = createFDATChunk(i, imageData);
output.write(fdAT); // Subsequent frames use fdAT
}
}

// Write IEND chunk (Image End)
byte[] iend = createIENDChunk();
output.write(iend);

System.out.println("APNG animation created successfully!");
}

private static byte[] createIHDRChunk(BufferedImage image) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(intToBytes(13)); // IHDR data length
baos.write("IHDR".getBytes()); // Chunk type
baos.write(intToBytes(image.getWidth())); // Width
baos.write(intToBytes(image.getHeight())); // Height
baos.write(8); // Bit depth
baos.write(6); // Color type (RGBA)
baos.write(0); // Compression method
baos.write(0); // Filter method
baos.write(0); // Interlace method
byte[] chunkData = baos.toByteArray();
baos.write(intToBytes(crc32(chunkData, 4, chunkData.length - 4))); // CRC
return baos.toByteArray();
}

private static byte[] createACTLChunk(int numFrames, int numPlays) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(intToBytes(8)); // acTL data length
baos.write("acTL".getBytes()); // Chunk type
baos.write(intToBytes(numFrames)); // Number of frames
baos.write(intToBytes(numPlays)); // Number of plays (0 = infinite)
byte[] chunkData = baos.toByteArray();
baos.write(intToBytes(crc32(chunkData, 4, chunkData.length - 4))); // CRC
return baos.toByteArray();
}

private static byte[] createFCTLChunk(int sequenceNumber, int delayMs, int width, int height) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(intToBytes(26)); // fcTL data length
baos.write("fcTL".getBytes()); // Chunk type
baos.write(intToBytes(sequenceNumber)); // Sequence number
baos.write(intToBytes(width)); // Width
baos.write(intToBytes(height)); // Height
baos.write(intToBytes(delayMs)); // Delay numerator
baos.write(intToBytes(1000)); // Delay denominator
baos.write(0); // Dispose op
baos.write(0); // Blend op
byte[] chunkData = baos.toByteArray();
baos.write(intToBytes(crc32(chunkData, 4, chunkData.length - 4))); // CRC
return baos.toByteArray();
}

private static byte[] createIDATChunk(BufferedImage image) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
byte[] pngData = baos.toByteArray();

// Extract IDAT chunk from PNG data
int idatStart = findChunk(pngData, "IDAT");
if (idatStart == -1) {
throw new IOException("IDAT chunk not found in PNG data");
}

// Extract the IDAT chunk (length + type + data + CRC)
int length = ByteBuffer.wrap(pngData, idatStart - 4, 4).order(ByteOrder.BIG_ENDIAN).getInt();
byte[] idatChunk = new byte[length + 12]; // 4 (length) + 4 (type) + length (data) + 4 (CRC)
System.arraycopy(pngData, idatStart - 4, idatChunk, 0, idatChunk.length);

return idatChunk;
}

private static byte[] createFDATChunk(int sequenceNumber, byte[] imageData) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(intToBytes(imageData.length - 8)); // fdAT data length (excluding sequence number)
baos.write("fdAT".getBytes()); // Chunk type
baos.write(intToBytes(sequenceNumber)); // Sequence number
baos.write(imageData, 8, imageData.length - 8); // Image data (excluding length and type)
byte[] chunkData = baos.toByteArray();
baos.write(intToBytes(crc32(chunkData, 4, chunkData.length - 4))); // CRC
return baos.toByteArray();
}

private static byte[] createIENDChunk() throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(intToBytes(0)); // IEND data length
baos.write("IEND".getBytes()); // Chunk type
byte[] chunkData = baos.toByteArray();
baos.write(intToBytes(crc32(chunkData, 4, chunkData.length - 4))); // CRC
return baos.toByteArray();
}

private static byte[] intToBytes(int value) {
return ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(value).array();
}

private static int crc32(byte[] data, int offset, int length) {
CRC32 crc = new CRC32();
crc.update(data, offset, length);
return (int) crc.getValue();
}

private static int findChunk(byte[] pngData, String chunkType) {
byte[] typeBytes = chunkType.getBytes();
for (int i = 8; i < pngData.length - 4; i++) {
if (pngData == typeBytes[0] &&
pngData[i + 1] == typeBytes[1] &&
pngData[i + 2] == typeBytes[2] &&
pngData[i + 3] == typeBytes[3]) {
return i; // Return the start of the chunk type
}
}
return -1; // Chunk not found
}
< /code>
Я использую этот код для генерации анимации APNG, и, хотя процесс, кажется, работает для создания различных кусков (IHDR, ACTL, FCTL, IDAT и т. Д.), Я все еще сталкиваюсь с проблемами с выводом, которые, похоже, не демонстрируют анимацию в качестве ожидаемого. Любой совет о том, как отладить или общие ловушки в создании APNG, были бы очень оценены.

Подробнее здесь: https://stackoverflow.com/questions/794 ... -with-java

Вернуться в «JAVA»