
org.monte.media.anim.ANIMKeyFrame Maven / Gradle / Ivy
/*
* @(#)ANIMKeyFrame.java 1.1 2010-06-27
*
* Copyright (c) 1999-2010 Werner Randelshofer, Goldau, Switzerland.
* All rights reserved.
*
* You may not use, copy or modify this file, except in compliance with the
* license agreement you entered into with Werner Randelshofer.
* For details see accompanying license terms.
*/
package org.monte.media.anim;
import org.monte.media.image.BitmapImage;
import org.monte.media.iff.IFFParser;
import org.monte.media.ParseException;
/**
* @author Werner Randelshofer, Hausmatt 10, CH-6405 Goldau, Switzerland
* @version 2010-06-27 Support for "vertical" compression added.
*
1.0 1999-10-19
*/
public class ANIMKeyFrame
extends ANIMFrame {
private int compression;
protected final static int VDAT_ID = IFFParser.stringToID("VDAT");
public ANIMKeyFrame() {
}
@Override
public void setData(byte[] data) {
this.data = data;
}
/** For possible values see {@link ANIMMovieTrack}. */
public void setCompression(int compression) {
this.compression = compression;
}
@Override
public void decode(BitmapImage bitmap, ANIMMovieTrack track) {
switch (compression) {
case ANIMMovieTrack.CMP_BYTE_RUN_1:
unpackByteRun1(data, bitmap.getBitmap());
break;
case ANIMMovieTrack.CMP_VERTICAL:
unpackVertical(data, bitmap);
break;
case ANIMMovieTrack.CMP_NONE:
default:
System.arraycopy(data, 0, bitmap.getBitmap(), 0, data.length);
break;
}
}
/**
* ByteRun1 run decoder.
*
* The run encoding scheme by byteRun1 is best described by pseudo
* code for the decoder Unpacker (called UnPackBits in
* the Macintosh toolbox.
*
* UnPacker:
* LOOP until produced the desired number of bytes
* Read the next source byte into n
* SELECT n FROM
* [0..127] => copy the next n+1 bytes literally
* [-1..-127] => replicate the next byte -n+1 times
* -128 => no operation
* ENDCASE;
* ENDLOOP;
*
*
*/
public static int unpackByteRun1(byte[] in, byte[] out) {
int iOut = 0; // output array index
int iIn = 0; // input array index
int n = 0; // The unpack command
byte copyByte;
try {
while (iOut < out.length) {
n = in[iIn++];
if (n >= 0) { // [0..127] => copy the next n+1 bytes literally
n = n + 1;
System.arraycopy(in, iIn, out, iOut, n);
iOut += n;
iIn += n;
} else {
if (n != -128) {//[-1..-127] => replicate the next byte -n+1 times
copyByte = in[iIn++];
for (; n < 1; n++) {
out[iOut++] = copyByte;
}
}
}
}
} catch (IndexOutOfBoundsException e) {
System.out.println("ANIMKeyFrame.unpackByteRun1(): " + e);
System.out.println(" Plane-Index: " + iOut + " Plane size:" + out.length);
System.out.println(" Buffer-Index: " + iIn + " Buffer size:" + in.length);
System.out.println(" Command: " + n);
}
return iOut;
}
/**
* Vertical run decoder.
*
* Each plane is stored in a separate VDAT chunk.
*
* A VDAT chunk consists of an id, a length, and a body.
*
* struct {
* uint16 id; // The 4 ASCII characters "VDAT"
* uint16 length,
* byte[length] body
* }
*
* The body consists of a command list and a data list.
*
* struct {
* uint16 cnt; // Command count + 2
* uint8[cnt - 2] cmd; // The commands
* uint16[] data; // Data words
* }
*
* Pseudo code for the unpacker:
*
* UnPacker:
* Read cnt;
* LOOP cnt - 2 TIMES
* Read the next command byte into cmd
* SELECT cmd FROM
* 0 =>
* Read the next data word into n
* Copy the next n data words literally
* 1 =>
* Read the next data word into n
* Replicate the next data word n times
* [2..127] =>
* Replicate the next data word cmd times
* [-1..-128] =>
* Copy the next -cmd data words literally
* ENDCASE;
* IF end of data reached THEN EXIT END;
* ENDLOOP;
*
*
*/
public void unpackVertical(byte[] in, BitmapImage bm)
{
byte[] out = bm.getBitmap();
int iIn = 0; // input index
int endOfData = 0;
int bmhdWidth = bm.getWidth();
int bmhdHeight = bm.getHeight();
int bmhdNbPlanes = bm.getDepth();
byte buf[] = new byte[bmhdWidth * bmhdHeight / 8]; // temporary bitplane buffer
int scanlineStride = bm.getScanlineStride();
int columnCount = (bmhdWidth / 8) * bmhdHeight;
int columnStride = bmhdHeight * 2;
try {
for (int p = 0; p < bmhdNbPlanes; p++) {
// Each plane is stored in a separate VDAT chunk.
// ----------------------------------------------
int iBuf = 0;
iIn = endOfData;
// read the "VDAT" chunk id and length
int id = (in[iIn++] & 0xff) << 24 | (in[iIn++] & 0xff) << 16 | (in[iIn++] & 0xff) << 8 | (in[iIn++] & 0xff);
if (id != VDAT_ID) {
throw new ParseException("Illegal VDAT chunk ID:" + IFFParser.idToString(id) + " at " + (iIn - 4));
}
long length = (in[iIn++] & 0xffL) << 24 | (in[iIn++] & 0xffL) << 16 | (in[iIn++] & 0xffL) << 8 | (in[iIn++] & 0xffL);
if (iIn + length > in.length) {
throw new ParseException("Illegal VDAT chunk length:" + length + " at " + (iIn - 4));
}
endOfData += length + 8;
// The body consists of a command list and a data list.
// ----------------------------------------------------
// read the command count, compute the offset to the data list
int cnt = (in[iIn++] & 0xff) << 8 | (in[iIn++] & 0xff);
int iCmd = iIn;
iIn = iIn + cnt - 2;
try {
// Process the commands until all commands read or end of data reached
for (int i = cnt - 2; i > 0 && iIn < endOfData; i--) {
int cmd = in[iCmd++];
if (cmd == 0) {
// 0 => Read the next data word into n
// Copy the next n data words literally
int n = (in[iIn++] & 0xff) << 8 | (in[iIn++] & 0xff);
for (n *= 2; n > 0; n--) {
buf[iBuf++] = in[iIn++];
}
} else if (cmd == 1) {
// 1 => Read the next data word into n
// Replicate the next data word n times
int n = (in[iIn++] & 0xff) << 8 | (in[iIn++] & 0xff);
byte dhigh = in[iIn++]; // high byte
byte dlow = in[iIn++]; // low byte
for (; n > 0; n--) {
buf[iBuf++] = dhigh;
buf[iBuf++] = dlow;
}
} else if (cmd >= 2) {
// [2..127] => Replicate the next data word cmd times
byte dhigh = in[iIn++]; // high byte
byte dlow = in[iIn++]; // low byte
for (int n = cmd; n > 0; n--) {
buf[iBuf++] = dhigh;
buf[iBuf++] = dlow;
}
} else {
// [-1..-128] => Copy the next -cmd data words literally
for (int n = cmd * -2; n > 0; n--) {
buf[iBuf++] = in[iIn++];
}
}
}
} catch (IndexOutOfBoundsException e) {
System.err.println("IndexOutOfBounds in bitplane " + p);
e.printStackTrace();
}
// Copy buffer into bitmap
int bitplaneOffset = bm.getBitplaneStride() * p;
for (int xBuf = 0, xOut = 0; xBuf < columnCount; xBuf += columnStride, xOut += 2) {
for (int yBuf = 0, yOut = bitplaneOffset; yBuf < columnStride; yBuf += 2, yOut += scanlineStride) {
out[xOut + yOut] = buf[xBuf + yBuf];
out[xOut + 1 + yOut] = buf[xBuf + 1 + yBuf];
}
}
}
} catch (ParseException e) {
e.printStackTrace();
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
// System.out.println("ILBMDecoder.unpackVertical(): " + e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy