Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * @(#)TechSmithCodecCore.java 
    * 
    * Copyright (c) 2011 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.avi;
  
  import static java.lang.Math.*;

TechSmithCodec (tscc) encodes a BufferedImage as a byte[] array.

This codec does not encode the color palette of an image. This must be done separately.

Supported input formats:

    Format with BufferedImage.class, any width, any height, depth=8,16 or 24.
Supported output formats:
    Format with byte[].class, same width and height as input format, depth=8,16 or 24.
The codec supports lossless delta- and key-frame encoding of images with 8, 16 or 24 bits per pixel.

Compression of a frame is performed in two steps: In the first, step a frame is compressed line by line from bottom to top. In the second step the resulting data is compressed again using zlib compression.

Apart from the second compression step and the support for 16- and 24-bit data, this encoder is identical to the RunLengthCodec.

Each line of a frame is compressed individually. A line consists of two-byte op-codes optionally followed by data. The end of the line is marked with the EOL op-code.

The following op-codes are supported:

  • 0x00 0x00
    Marks the end of a line.
  • 0x00 0x01
    Marks the end of the bitmap.
  • 0x00 0x02 dx dy
    Marks a delta (skip). dx and dy indicate the horizontal and vertical offset from the current position. dx and dy are unsigned 8-bit values.
  • 0x00 n pixel{n 0x00?}
    Marks a literal run. n gives the number of 8-, 16- or 24-bit pixels that follow. n must be between 3 and 255. If n is odd and 8-bit pixels are used, a pad byte with the value 0x00 must be added.
  • n pixel
    Marks a repetition. n gives the number of times the given pixel is repeated. n must be between 1 and 255.
Example:
 Compressed data         Expanded data

 03 04                   04 04 04
 05 06                   06 06 06 06 06
 00 03 45 56 67 00       45 56 67
 02 78                   78 78
 00 02 05 01             Move 5 right and 1 down
 02 78                   78 78
 00 00                   End of line
 09 1E                   1E 1E 1E 1E 1E 1E 1E 1E 1E
 00 01                   End of RLE bitmap
 
References:
http://wiki.multimedia.cx/index.php?title=TechSmith_Screen_Capture_Codec

Palette colors

In an AVI file, palette changes are stored in chunks with id's with the suffix "pc". "pc" chunks contain an AVIPALCHANGE struct as shown below.

 /* ------------------
  * AVI Palette Change
  * ------------------
  * /
 
 // Values for this enum have been taken from:
 // http://biodi.sdsc.edu/Doc/GARP/garp-1.1/define.h
 enum {
     PC_EXPLICIT = 0x02,
     // Specifies that the low-order word of the logical palette entry 
     // designates a hardware palette index. This flag allows the application to 
     // show the contents of the display device palette.
     PC_NOCOLLAPSE = 0x04,
     // Specifies that the color be placed in an unused entry in the system 
     // palette instead of being matched to an existing color in the system 
     // palette. If there are no unused entries in the system palette, the color 
     // is matched normally. Once this color is in the system palette, colors in
     // other logical palettes can be matched to this color.
     PC_RESERVED = 0x01
     // Specifies that the logical palette entry be used for palette animation. 
     // This flag prevents other windows from matching colors to the palette 
     // entry since the color frequently changes. If an unused system-palette
     // entry is available, the color is placed in that entry. Otherwise, the 
     // color is not available for animation.
 } peFlagsEnum;
 /* 
  * The PALETTEENTRY structure specifies the color and usage of an entry in a
  * logical palette. A logical palette is defined by a LOGPALETTE structure.
  * /
 typedef struct { 
   BYTE peRed; // Specifies a red intensity value for the palette entry.
   BYTE peGreen; // Specifies a green intensity value for the palette entry.
   BYTE peBlue; // Specifies a blue intensity value for the palette entry.
   BYTE enum peFlagsEnum peFlags; // Specifies how the palette entry is to be used.
 } PALETTEENTRY;
 
 typedef struct {
   AVIPALCHANGE avipalchange;
 } AVIPALCHANGE0;
 
 typedef struct {
     PALETTEENTRY  p[256];
 } PALETTEENTRY_ALLENTRIES;
 
 typedef struct {
     BYTE          firstEntry;
         // Specifies the index of the first palette entry to change.
     BYTE          numEntries;
         // Specifies the number of palette entries to change, or zero to change 
         // all 256 palette entries.
     WORD          flags;
         // Reserved.
     PALETTEENTRY  peNew[numEntries];
         // Specifies an array of PALETTEENTRY structures, of size "numEntries".
     PALETTEENTRY_ALLENTRIES  all[numEntries==0];
 } AVIPALCHANGE;
 

Author(s):
Werner Randelshofer
Version:
$Id: TechSmithCodecCore.java 299 2013-01-03 07:40:18Z werner $
 
 public class TechSmithCodecCore extends AbstractVideoCodecCore {
 
     private byte[] temp2;
     private int[] palette;
 
     public TechSmithCodecCore() {
         reset();
     }
 
     public void reset() {
          = null;
     }
 
     public int[] getPalette() {
         if ( == null) {
              = new int[256];
             // initalize palette with grayscale colors
             for (int i = 0; i < .i++) {
                 [i] = (i) | (i << 8) | (i << 16);
             }
         }
         return ;
     }

    
Decodes an AVI palette change chunk. FIXME - This could be moved out into a separate class.
 
     public void decodePalette(byte[] inDatint offint lenthrows IOException {
         getPalette();
         ByteArrayImageInputStream in = new ByteArrayImageInputStream(inDatofflen.);
         int firstEntry = in.readUnsignedByte();
         int numEntries = in.readUnsignedByte();
         if (numEntries == 0) {
             numEntries = 256;
         }
         int flags = in.readUnsignedShort();
         if (firstEntry + numEntries > 256) {
             throw new IOException("Illegal headers in pc chunk. firstEntry=" + firstEntry + ", numEntries=" + numEntries);
         }
         in.setByteOrder(.);
         for (int i = 0; i < numEntriesi++) {
             int rgbf = in.readInt();
             [i + firstEntry] = rgbf >> 8;
         }
     }

    
Decodes to 8-bit palettised. Returns true if a key-frame was decoded.

Parameters:
inDat
off
length
outDat
prevDat The pixels decoded in the previous frame. Since no double buffering is used, this can be the same array than outDat.
width
height
onlyDecodeIfKeyframe
Returns:
True if a key-frame was decoded.
Throws:
java.io.IOException
 
     public boolean decode8(byte[] inDatint offint lengthbyte[] outDatbyte[] prevDatint widthint heightboolean onlyDecodeIfKeyframethrows IOException {
         // Handle delta frame with all identical pixels
         if (length <= 2) {
             return false;
         }
 
                 new InflaterInputStream(new ByteArrayInputStream(inDatofflength)));
 
         int offset = 0;
         int scanlineStride = width;
         int upsideDown = (height - 1) * scanlineStride + offset;
         // Decode each scanline
         int verticalOffset = 0;
         boolean isKeyFrame = true;
         try {
             int y = 0;
             int xy = upsideDown;
             loop:
             while (true) {
                 int opcode = in.readUnsignedByte();
                 if (opcode == 0) {
                     opcode = in.readUnsignedByte();
                     switch (opcode) {
                         case 0x0000: // end of line
                             y++;
                             xy = (height - 1 - y) * scanlineStride + offset;
                             break;
                         case 0x0001: // end of bitmap
                             break loop;
                         case 0x0002: // delta skip
                             isKeyFrame = false;
                             int dx = in.readUnsignedByte();
                             int dy = in.readUnsignedByte();
                             y += dy;
                             int end = xy + dx - dy * scanlineStride;
                             if (prevDat != outDat) {
                                 System.arraycopy(prevDatxyoutDatxyend - xy);
                             }
                             xy = end;
                             break;
                         default// literal run
                             in.readFully(outDatxyopcode);
                             xy += opcode;
                             if ((opcode & 1) == 1) {
                                 int pad = in.readByte() & 0xff;
                                 if (pad != 0) {
                                     throw new IOException("Illegal pad byte, pad=0x" + Integer.toHexString(pad));
                                 }
                             }
                             break;
                     }
                 } else {
                     // repetition
                     byte v = in.readByte();
                     for (int end = xy + opcodexy < endxy++) {
                         outDat[xy] = v;
                     }
                 }
 
             }
         } catch (ArrayIndexOutOfBoundsException t) {
             t.printStackTrace();
         }
         in.close();
         return isKeyFrame;
     }

    
Decodes to 24-bit direct color. Returns true if a key-frame was decoded.

Parameters:
inDat
off
length
outDat
prevDat The pixels decoded in the previous frame. Since no double buffering is used, this can be the same array than outDat.
width
height
onlyDecodeIfKeyframe
Returns:
True if a key-frame was decoded.
Throws:
java.io.IOException
 
     public boolean decode8(byte[] inDatint offint lengthint[] outDatint[] prevDatint widthint heightboolean onlyDecodeIfKeyframethrows IOException {
         // Handle delta frame with all identical pixels
         if (length <= 2) {
             return false;
         }
         if ( == null || . < 255) {
              = new byte[255];
         }
         getPalette();
 
                 new InflaterInputStream(new ByteArrayInputStream(inDatofflength)));
 
         int offset = 0;
         int scanlineStride = width;
         int upsideDown = (height - 1) * scanlineStride + offset;
         // Decode each scanline
         int verticalOffset = 0;
         boolean isKeyFrame = true;
         try {
             int y = 0;
             int xy = upsideDown;
             loop:
             while (true) {
                 int opcode = in.readUnsignedByte();
                 if (opcode == 0) {
                     opcode = in.readUnsignedByte();
                     switch (opcode) {
                         case 0x0000: // end of line
                             y++;
                             xy = (height - 1 - y) * scanlineStride + offset;
                             break;
                         case 0x0001: // end of bitmap
                             break loop;
                         case 0x0002: { // delta skip
                             isKeyFrame = false;
                             int dx = in.readUnsignedByte();
                             int dy = in.readUnsignedByte();
                             y += dy;
                             int end = xy + dx - dy * scanlineStride;
                             if (prevDat != outDat) {
                                 System.arraycopy(prevDatxyoutDatxyend - xy);
                             }
                             xy = end;
                             break;
                         }
                         default: { // literal run
                             in.readFully(, 0, opcode);
                             for (int i = 0; i < opcodei++) {
                                 outDat[xy + i] = [[i] & 0xff];
                             }
                             xy += opcode;
                             if ((opcode & 1) == 1) {
                                 int pad = in.readByte() & 0xff;
                                 if (pad != 0) {
                                     throw new IOException("Illegal pad byte, pad=0x" + Integer.toHexString(pad));
                                 }
                             }
                             break;
                         }
                     }
                 } else {
                     // repetition
                     int v = [in.readUnsignedByte()];
                     for (int end = xy + opcodexy < endxy++) {
                         outDat[xy] = v;
                     }
                 }
 
             }
         } catch (ArrayIndexOutOfBoundsException t) {
             t.printStackTrace();
         }
         in.close();
         return isKeyFrame;
     }

    
Decodes to 24-bit RGB. Returns true if a key-frame was decoded.
 
     public boolean decode24(byte[] inDatint offint lengthint[] outDatint[] prevDatint widthint heightboolean onlyDecodeIfKeyframethrows IOException {
         // Handle delta frame with all identical pixels
         if (length <= 2) {
             return false;
         }
 
                 new InflaterInputStream(new ByteArrayInputStream(inDatofflength)));
 
         int offset = 0;
         int scanlineStride = width;
         int upsideDown = (height - 1) * scanlineStride + offset;
         // Decode each scanline
         int verticalOffset = 0;
         boolean isKeyFrame = true;
         try {
             int y = 0;
             int xy = upsideDown;
             loop:
             while (true) {
                 int opcode = in.readUnsignedByte();
                 if (opcode == 0) {
                     opcode = in.readUnsignedByte();
                     switch (opcode) {
                         case 0x0000: // end of line
                             y++;
                             xy = (height - 1 - y) * scanlineStride + offset;
                             break;
                         case 0x0001: // end of bitmap
                             break loop;
                         case 0x0002: {// delta skip
                             isKeyFrame = false;
                             int dx = in.readUnsignedByte();
                             int dy = in.readUnsignedByte();
                             y += dy;
                             int end = xy + dx - dy * scanlineStride;
                             if (prevDat != outDat) {
                                 System.arraycopy(prevDatxyoutDatxyend - xy);
                             }
                             xy = end;
                             break;
                         }
                         default: {// literal run
                             readInts24LE(inoutDatxyopcode);
                             xy += opcode;
                             break;
                         }
                     }
                 } else {
                     // repetition
                     int v = readInt24LE(in);
                     for (int end = xy + opcodexy < endxy++) {
                         outDat[xy] = v;
                     }
                 }
 
             }
         } catch (ArrayIndexOutOfBoundsException t) {
             t.printStackTrace();
         }
         in.close();
         return isKeyFrame;
     }
    
Decodes from 16-bit to 24-bit RGB. Returns true if a key-frame was decoded.
 
     public boolean decode16(byte[] inDatint offint lengthint[] outDatint[] prevDatint widthint heightboolean onlyDecodeIfKeyframethrows IOException {
         // Handle delta frame with all identical pixels
         if (length <= 2) {
             if (outDat!=prevDat) {
                 System.arraycopy(prevDat,0,outDat,0,width*height);
             }
             return false;
         }
 
                 new InflaterInputStream(new ByteArrayInputStream(inDatofflength)), .);
 
         int offset = 0;
         int scanlineStride = width;
         int upsideDown = (height - 1) * scanlineStride + offset;
         // Decode each scanline
         int verticalOffset = 0;
         boolean isKeyFrame = true;
         try {
             int y = 0;
             int xy = upsideDown;
             loop:
             while (true) {
                 int opcode = in.readUnsignedByte();
                 if (opcode == 0) {
                     opcode = in.readUnsignedByte();
                     switch (opcode) {
                         case 0x0000: // end of line
                             y++;
                             xy = (height - 1 - y) * scanlineStride + offset;
                             break;
                         case 0x0001: // end of bitmap
                             break loop;
                         case 0x0002: {// delta skip
                             isKeyFrame = false;
                             int dx = in.readUnsignedByte();
                             int dy = in.readUnsignedByte();
                             y += dy;
                             int end = xy + dx - dy * scanlineStride;
                             if (prevDat != outDat) {
                                 System.arraycopy(prevDatxyoutDatxyend - xy);
                             }
                             xy = end;
                             break;
                         }
                         default: {// literal run
                             readRGBs555to24(inoutDatxyopcode);
                             xy += opcode;
                             break;
                         }
                     }
                 } else {
                     // repetition
                     int v = readRGB555to24(in);
                     for (int end = xy + opcodexy < endxy++) {
                         outDat[xy] = v;
                     }
                 }
 
             }
         } catch (ArrayIndexOutOfBoundsException t) {
             t.printStackTrace();
         }
         in.close();
         return isKeyFrame;
     }

    
Encodes an 8-bit delta frame with indexed colors.

Parameters:
out The output stream.
data The image data.
prev The image data of the previous frame.
offset The offset to the first pixel in the data array.
width The width of the image in data elements.
scanlineStride The number to add to offset to get to the next scanline.
 
     public void encodeDelta8(OutputStream outbyte[] databyte[] prevint widthint heightint offsetint scanlineStride)
             throws IOException {
 
 
         int ymax = offset + height * scanlineStride;
         int upsideDown = ymax - scanlineStride + offset;
 
         // Encode each scanline
         int verticalOffset = 0;
         for (int y = offsety < ymaxy += scanlineStride) {
             int xy = upsideDown - y;
             int xymax = xy + width;
 
             // determine skip count
             int skipCount = 0;
             for (; xy < xymax; ++xy, ++skipCount) {
                 if (data[xy] != prev[xy]) {
                     break;
                 }
             }
             if (skipCount == width) {
                 // => the entire line can be skipped
                 ++verticalOffset;
                 continue;
             }
 
 
             while (verticalOffset > 0 || skipCount > 0) {
                 .write(0x00); // Escape code
                 .write(0x02); // Skip OP-code
                 .write(min(255, skipCount)); // horizontal offset
                 .write(min(255, verticalOffset)); // vertical offset
                 skipCount -= min(255, skipCount);
                 verticalOffset -= min(255, verticalOffset);
             }
 
             int literalCount = 0;
             int repeatCount = 0;
             for (; xy < xymax; ++xy) {
                 // determine skip count
                 for (skipCount = 0; xy < xymax; ++xy, ++skipCount) {
                     if (data[xy] != prev[xy]) {
                         break;
                     }
                 }
                 xy -= skipCount;
 
                 // determine repeat count
                 byte v = data[xy];
                 for (repeatCount = 0; xy < xymax && repeatCount < 255; ++xy, ++repeatCount) {
                     if (data[xy] != v) {
                         break;
                     }
                 }
                 xy -= repeatCount;
 
                 if (skipCount < 4 && xy + skipCount < xymax && repeatCount < 3) {
                     literalCount++;
                 } else {
                     while (literalCount > 0) {
                         if (literalCount < 3) {
                             .write(1); // Repeat OP-code
                             .write(data[xy - literalCount]);
                             literalCount--;
                         } else {
                             int literalRun = min(254, literalCount);
                             .write(0); // Escape code
                             .write(literalRun); // Literal OP-code
                             .write(dataxy - literalCountliteralRun);
                             if ((literalRun & 1) == 1) {
                                 .write(0); // pad byte
                             }
                             literalCount -= literalRun;
                         }
                     }
                     if (xy + skipCount == xymax) {
                         // => we can skip until the end of the line without
                         //    having to write an op-code
                         xy += skipCount - 1;
                     } else if (skipCount >= repeatCount) {
                         while (skipCount > 0) {
                             .write(0); // Escape code
                             .write(0x0002); // Skip OP-code
                             .write(min(255, skipCount));
                             .write(0);
                             xy += min(255, skipCount);
                             skipCount -= min(255, skipCount);
                         }
                         xy -= 1;
                     } else {
                         .write(repeatCount); // Repeat OP-code
                         .write(v);
                         xy += repeatCount - 1;
                     }
                 }
             }
 
             // flush literal run
             while (literalCount > 0) {
                 if (literalCount < 3) {
                     .write(1); // Repeat OP-code
                     .write(data[xy - literalCount]);
                     literalCount--;
                 } else {
                     int literalRun = min(254, literalCount);
                     .write(0);
                     .write(literalRun); // Literal OP-code
                     .write(dataxy - literalCountliteralRun);
                     if ((literalRun & 1) == 1) {
                         .write(0); // pad byte
                     }
                     literalCount -= literalRun;
                 }
             }
 
             .write(0); // Escape code
             .write(0x00); // End of line OP-code
         }
         .write(0); // Escape code
         .write(0x01);// End of bitmap
 
 
         if (.length() == 2) {
             .toOutputStream(out);
         } else {
             DeflaterOutputStream defl = new DeflaterOutputStream(out);
             .toOutputStream(defl);
             defl.finish();
         }
     }

    
Encodes an 8-bit delta frame with indexed colors to 24-bit.

Parameters:
out The output stream.
data The image data.
prev The image data of the previous frame.
offset The offset to the first pixel in the data array.
width The width of the image in data elements.
scanlineStride The number to add to offset to get to the next scanline.
 
     public void encodeDelta8to24(OutputStream outbyte[] databyte[] prevint widthint heightint offsetint scanlineStride)
             throws IOException {
 
 
         int ymax = offset + height * scanlineStride;
         int upsideDown = ymax - scanlineStride + offset;
 
         // Encode each scanline
         int verticalOffset = 0;
         for (int y = offsety < ymaxy += scanlineStride) {
             int xy = upsideDown - y;
             int xymax = xy + width;
 
             // determine skip count
             int skipCount = 0;
             for (; xy < xymax; ++xy, ++skipCount) {
                 if (data[xy] != prev[xy]) {
                     break;
                 }
             }
             if (skipCount == width) {
                 // => the entire line can be skipped
                 ++verticalOffset;
                 continue;
             }
 
 
             while (verticalOffset > 0 || skipCount > 0) {
                 .write(0x00); // Escape code
                 .write(0x02); // Skip OP-code
                 .write(min(255, skipCount)); // horizontal offset
                 .write(min(255, verticalOffset)); // vertical offset
                 skipCount -= min(255, skipCount);
                 verticalOffset -= min(255, verticalOffset);
             }
 
             int literalCount = 0;
             int repeatCount = 0;
             for (; xy < xymax; ++xy) {
                 // determine skip count
                 for (skipCount = 0; xy < xymax; ++xy, ++skipCount) {
                     if (data[xy] != prev[xy]) {
                         break;
                     }
                 }
                 xy -= skipCount;
 
                 // determine repeat count
                 byte v = data[xy];
                 for (repeatCount = 0; xy < xymax && repeatCount < 255; ++xy, ++repeatCount) {
                     if (data[xy] != v) {
                         break;
                     }
                 }
                 xy -= repeatCount;
 
                 if (skipCount < 4 && xy + skipCount < xymax && repeatCount < 3) {
                     literalCount++;
                 } else {
                     while (literalCount > 0) {
                         if (literalCount < 3) {
                             .write(1); // Repeat OP-code
                             writeInt24LE([data[xy - literalCount]&0xff]);
                             literalCount--;
                         } else {
                             int literalRun = min(254, literalCount);
                             .write(0); // Escape code
                             .write(literalRun); // Literal OP-code
                             for (int i = xy - literalCountend = xy - literalCount + literalRuni < endi++) {
                                 writeInt24LE([data[i]&0xff]);
                             }
                             literalCount -= literalRun;
                         }
                     }
                     if (xy + skipCount == xymax) {
                         // => we can skip until the end of the line without
                         //    having to write an op-code
                         xy += skipCount - 1;
                     } else if (skipCount >= repeatCount) {
                         while (skipCount > 0) {
                             .write(0); // Escape code
                             .write(0x0002); // Skip OP-code
                             .write(min(255, skipCount));
                             .write(0);
                             xy += min(255, skipCount);
                             skipCount -= min(255, skipCount);
                         }
                         xy -= 1;
                     } else {
                         .write(repeatCount); // Repeat OP-code
                         writeInt24LE([v&0xff]);
                         xy += repeatCount - 1;
                     }
                 }
             }
 
             // flush literal run
             while (literalCount > 0) {
                 if (literalCount < 3) {
                     .write(1); // Repeat OP-code
                     writeInt24LE([data[xy - literalCount]]);
                     literalCount--;
                 } else {
                     int literalRun = min(254, literalCount);
                     .write(0);
                     .write(literalRun); // Literal OP-code
                     for (int i = xy - literalCountend = xy - literalCount + literalRuni < endi++) {
                         writeInt24LE([data[i]&0xff]);
                     }
                     /*
                     temp.write(data, xy - literalCount, literalRun);
                     if (literalRun & 1 == 1) {
                     temp.write(0); // pad byte
                     }*/
                     literalCount -= literalRun;
                 }
             }
 
             .write(0); // Escape code
             .write(0x00); // End of line OP-code
         }
         .write(0); // Escape code
         .write(0x01);// End of bitmap
 
 
         if (.length() == 2) {
             .toOutputStream(out);
         } else {
             DeflaterOutputStream defl = new DeflaterOutputStream(out);
             .toOutputStream(defl);
             defl.finish();
         }
     }

    
Encodes a delta frame which is known to have the same content than the previous frame.

Parameters:
out
data
prev
width
height
offset
scanlineStride
Throws:
java.io.IOException
 
     public void encodeSameDelta8(OutputStream outbyte[] databyte[] prevint widthint heightint offsetint scanlineStride)
             throws IOException {
         /*
         temp.clear();temp.setByteOrder(ByteOrder.LITTLE_ENDIAN);
         temp.write(0); // Escape code
         temp.write(0x01);// End of bitmap
         DeflaterOutputStream defl = new DeflaterOutputStream(out);
         temp.toOutputStream(defl);
         defl.finish();
         */
         out.write(0); // Escape code
         out.write(0x01);// End of bitmap
     }

    
Encodes a delta frame which is known to have the same content than the previous frame.

Parameters:
out
data
prev
width
height
offset
scanlineStride
Throws:
java.io.IOException
 
     public void encodeSameDelta24(OutputStream outint[] dataint[] prevint widthint heightint offsetint scanlineStride)
             throws IOException {
         /*
         temp.clear();temp.setByteOrder(ByteOrder.LITTLE_ENDIAN);
 
         temp.write(0); // Escape code
         temp.write(0x01);// End of bitmap
         DeflaterOutputStream defl = new DeflaterOutputStream(out);
         temp.toOutputStream(defl);
         defl.finish();
         */
         out.write(0); // Escape code
         out.write(0x01);// End of bitmap
     }

    
Encodes a delta frame which is known to have the same content than the previous frame.

Parameters:
out
data
prev
width
height
offset
scanlineStride
Throws:
java.io.IOException
 
     public void encodeSameDelta16(OutputStream outshort[] datashort[] prevint widthint heightint offsetint scanlineStride)
             throws IOException {
         /*
         temp.clear();temp.setByteOrder(ByteOrder.LITTLE_ENDIAN);
         temp.write(0); // Escape code
         temp.write(0x01);// End of bitmap
         DeflaterOutputStream defl = new DeflaterOutputStream(out);
         temp.toOutputStream(defl);
         defl.finish();
         */
         out.write(0); // Escape code
         out.write(0x01);// End of bitmap
     }

    
Encodes a 8-bit key frame with indexed colors.

Parameters:
out The output stream.
data The image data.
offset The offset to the first pixel in the data array.
width The width of the image in data elements.
scanlineStride The number to add to offset to get to the next scanline.
 
     public void encodeKey8(OutputStream outbyte[] dataint widthint heightint offsetint scanlineStride)
             throws IOException {
         int ymax = offset + height * scanlineStride;
         int upsideDown = ymax - scanlineStride + offset;
 
         // Encode each scanline separately
         for (int y = offsety < ymaxy += scanlineStride) {
             int xy = upsideDown - y;
             int xymax = xy + width;
 
             int literalCount = 0;
             int repeatCount = 0;
             for (; xy < xymax; ++xy) {
                 // determine repeat count
                 byte v = data[xy];
                 for (repeatCount = 0; xy < xymax && repeatCount < 255; ++xy, ++repeatCount) {
                     if (data[xy] != v) {
                         break;
                     }
                 }
                 xy -= repeatCount;
                 if (repeatCount < 3) {
                     literalCount++;
                     if (literalCount == 254) {
                         .write(0);
                         .write(literalCount); // Literal OP-code
                         .write(dataxy - literalCount + 1, literalCount);
                         literalCount = 0;
                     }
                 } else {
                     if (literalCount > 0) {
                         if (literalCount < 3) {
                             for (; literalCount > 0; --literalCount) {
                                 .write(1); // Repeat OP-code
                                 .write(data[xy - literalCount]);
                             }
                         } else {
                             .write(0);
                             .write(literalCount); // Literal OP-code
                             .write(dataxy - literalCountliteralCount);
                             if ((literalCount & 1) == 1) {
                                 .write(0); // pad byte
                             }
                             literalCount = 0;
                         }
                     }
                     .write(repeatCount); // Repeat OP-code
                     .write(v);
                     xy += repeatCount - 1;
                 }
             }
 
             // flush literal run
             if (literalCount > 0) {
                 if (literalCount < 3) {
                     for (; literalCount > 0; --literalCount) {
                         .write(1); // Repeat OP-code
                         .write(data[xy - literalCount]);
                     }
                 } else {
                     .write(0);
                     .write(literalCount);
                     .write(dataxy - literalCountliteralCount);
                     if ((literalCount & 1) == 1) {
                         .write(0); // pad byte
                     }
                 }
                 literalCount = 0;
             }
 
             .write(0);
             .write(0x0000);// End of line
         }
         .write(0);
         .write(0x0001);// End of bitmap
         //temp.toOutputStream(out);
 
         DeflaterOutputStream defl = new DeflaterOutputStream(out);
         .toOutputStream(defl);
         defl.finish();
     }

    
Encodes a 8-bit key frame with indexed colors to 24-bit.

Parameters:
out The output stream.
data The image data.
offset The offset to the first pixel in the data array.
width The width of the image in data elements.
scanlineStride The number to add to offset to get to the next scanline.
 
     public void encodeKey8to24(OutputStream outbyte[] dataint widthint heightint offsetint scanlineStride)
             throws IOException {
         int ymax = offset + height * scanlineStride;
         int upsideDown = ymax - scanlineStride + offset;
 
         // Encode each scanline separately
         for (int y = offsety < ymaxy += scanlineStride) {
            int xy = upsideDown - y;
            int xymax = xy + width;
            int literalCount = 0;
            int repeatCount = 0;
            for (; xy < xymax; ++xy) {
                // determine repeat count
                byte v = data[xy];
                for (repeatCount = 0; xy < xymax && repeatCount < 255; ++xy, ++repeatCount) {
                    if (data[xy] != v) {
                        break;
                    }
                }
                xy -= repeatCount;
                if (repeatCount < 3) {
                    literalCount++;
                    if (literalCount == 254) {
                        .write(0);
                        .write(literalCount); // Literal OP-code
                        for (int i = xy - literalCount + 1, end = xy + 1; i < endi++) {
                            writeInt24LE([data[i]&0xff]);
                        }
                        //temp.write(data, xy - literalCount + 1, literalCount);
                        literalCount = 0;
                    }
                } else {
                    if (literalCount > 0) {
                        if (literalCount < 3) {
                            for (; literalCount > 0; --literalCount) {
                                .write(1); // Repeat OP-code
                                writeInt24LE([data[xy - literalCount]&0xff]);
                            }
                        } else {
                            .write(0);
                            .write(literalCount); // Literal OP-code
                            for (int i = xy - literalCountend = xyi < endi++) {
                                writeInt24LE([data[i]&0xff]);
                            }
                            //temp.write(data, xy - literalCount, literalCount);
                            //if ((literalCount & 1) == 1) {
                            //    temp.write(0); // pad byte
                            //}
                            literalCount = 0;
                        }
                    }
                    .write(repeatCount); // Repeat OP-code
                    writeInt24LE([v&0xff]);
                    xy += repeatCount - 1;
                }
            }
            // flush literal run
            if (literalCount > 0) {
                if (literalCount < 3) {
                    for (; literalCount > 0; --literalCount) {
                        .write(1); // Repeat OP-code
                        writeInt24LE([data[xy - literalCount]&0xff]);
                    }
                } else {
                    .write(0);
                    .write(literalCount);
                    for (int i = xy - literalCountend = xyi < endi++) {
                        writeInt24LE([data[i]&0xff]);
                    }
                    //temp.write(data, xy - literalCount, literalCount);
                    //if ((literalCount & 1) == 1) {
                    //    temp.write(0); // pad byte
                    //}
                }
                literalCount = 0;
            }
            .write(0);
            .write(0x0000);// End of line
        }
        .write(0);
        .write(0x0001);// End of bitmap
        //temp.toOutputStream(out);
        DeflaterOutputStream defl = new DeflaterOutputStream(out);
        .toOutputStream(defl);
        defl.finish();
    }

    
Encodes a 16-bit delta frame.

Parameters:
out The output stream.
data The image data.
prev The image data of the previous frame.
offset The offset to the first pixel in the data array.
width The width of the image in data elements.
scanlineStride The number to add to offset to get to the next scanline.
    public void encodeDelta16(OutputStream outshort[] datashort[] prevint widthint heightint offsetint scanlineStride)
            throws IOException {
        int ymax = offset + height * scanlineStride;
        int upsideDown = ymax - scanlineStride + offset;
        // Encode each scanline
        int verticalOffset = 0;
        for (int y = offsety < ymaxy += scanlineStride) {
            int xy = upsideDown - y;
            int xymax = xy + width;
            // determine skip count
            int skipCount = 0;
            for (; xy < xymax; ++xy, ++skipCount) {
                if (data[xy] != prev[xy]) {
                    break;
                }
            }
            if (skipCount == width) {
                // => the entire line can be skipped
                ++verticalOffset;
                continue;
            }
            while (verticalOffset > 0 || skipCount > 0) {
                .write(0x00); // Escape code
                .write(0x02); // Skip OP-code
                .write(min(255, skipCount)); // horizontal offset
                .write(min(255, verticalOffset)); // vertical offset
                skipCount -= min(255, skipCount);
                verticalOffset -= min(255, verticalOffset);
            }
            int literalCount = 0;
            int repeatCount = 0;
            for (; xy < xymax; ++xy) {
                // determine skip count
                for (skipCount = 0; xy < xymax; ++xy, ++skipCount) {
                    if (data[xy] != prev[xy]) {
                        break;
                    }
                }
                xy -= skipCount;
                // determine repeat count
                short v = data[xy];
                for (repeatCount = 0; xy < xymax && repeatCount < 255; ++xy, ++repeatCount) {
                    if (data[xy] != v) {
                        break;
                    }
                }
                xy -= repeatCount;
                if (skipCount < 4 && xy + skipCount < xymax && repeatCount < 3) {
                    literalCount++;
                } else {
                    while (literalCount > 0) {
                        if (literalCount < 3) {
                            .write(1); // Repeat OP-code
                            .writeShort(data[xy - literalCount]);
                            literalCount--;
                        } else {
                            int literalRun = min(254, literalCount);
                            .write(0); // Escape code
                            .write(literalRun); // Literal OP-code
                            .writeShorts(dataxy - literalCountliteralRun);
                            literalCount -= literalRun;
                        }
                    }
                    if (xy + skipCount == xymax) {
                        // => we can skip until the end of the line without
                        //    having to write an op-code
                        xy += skipCount - 1;
                    } else if (skipCount >= repeatCount) {
                        while (skipCount > 0) {
                            .write(0); // Escape code
                            .write(0x02); // Skip OP-code
                            .write(min(255, skipCount)); // horizontal skip
                            .write(0); // vertical skip
                            xy += min(255, skipCount);
                            skipCount -= min(255, skipCount);
                        }
                        xy -= 1;
                    } else {
                        .write(repeatCount); // Repeat OP-code
                        .writeShort(v);
                        xy += repeatCount - 1;
                    }
                }
            }
            // flush literal run
            while (literalCount > 0) {
                if (literalCount < 3) {
                    .write(1); // Repeat OP-code
                    .writeShort(data[xy - literalCount]);
                    literalCount--;
                } else {
                    int literalRun = min(254, literalCount);
                    .write(0); // Escape code
                    .write(literalRun); // Literal OP-code
                    .writeShorts(dataxy - literalCountliteralRun);
                    literalCount -= literalRun;
                }
            }
            .write(0); // Escape code
            .write(0x00); // End of line OP-code
        }
        .write(0); // Escape code
        .write(0x01);// End of bitmap OP-code
        if (.length() == 2) {
            .toOutputStream(out);
        } else {
            DeflaterOutputStream defl = new DeflaterOutputStream(out);
            .toOutputStream(defl);
            defl.finish();
        }
    }

    
Encodes a 24-bit key frame.

Parameters:
out The output stream.
data The image data.
offset The offset to the first pixel in the data array.
width The width of the image in data elements.
scanlineStride The number to add to offset to get to the next scanline.
    public void encodeKey24(OutputStream outint[] dataint widthint heightint offsetint scanlineStride)
            throws IOException {
        int ymax = offset + height * scanlineStride;
        int upsideDown = ymax - scanlineStride + offset;
        // Encode each scanline separately
        for (int y = offsety < ymaxy += scanlineStride) {
            int xy = upsideDown - y;
            int xymax = xy + width;
            int literalCount = 0;
            int repeatCount = 0;
            for (; xy < xymax; ++xy) {
                // determine repeat count
                int v = data[xy];
                for (repeatCount = 0; xy < xymax && repeatCount < 255; ++xy, ++repeatCount) {
                    if (data[xy] != v) {
                        break;
                    }
                }
                xy -= repeatCount;
                if (repeatCount < 3) {
                    literalCount++;
                    if (literalCount == 254) {
                        .write(0);
                        .write(literalCount); // Literal OP-code
                        writeInts24LE(dataxy - literalCount + 1, literalCount);
                        literalCount = 0;
                    }
                } else {
                    if (literalCount > 0) {
                        if (literalCount < 3) {
                            for (; literalCount > 0; --literalCount) {
                                .write(1); // Repeat OP-code
                                writeInt24LE(data[xy - literalCount]);
                            }
                        } else {
                            .write(0);
                            .write(literalCount); // Literal OP-code
                            writeInts24LE(dataxy - literalCountliteralCount);
                            ///if (literalCount & 1 == 1) {
                            ///    temp.write(0); // pad byte
                            ///}
                            literalCount = 0;
                        }
                    }
                    .write(repeatCount); // Repeat OP-code
                    writeInt24LE(v);