if (palette2 == null)
throw new ImageWriteException(
"Gif: can't write images with more than 256 colors");
int palette_size = palette2.length() + (hasAlpha ? 1 : 0);
BinaryOutputStream bos = new BinaryOutputStream(os, BYTE_ORDER_LSB);
{
// write Header
os.write(0x47); // G magic numbers
os.write(0x49); // I
os.write(0x46); // F
os.write(0x38); // 8 version magic numbers
os.write(0x39); // 9
os.write(0x61); // a
// Logical Screen Descriptor.
bos.write2Bytes(width);
bos.write2Bytes(height);
int colorTableScaleLessOne = (palette_size > 128) ? 7
: (palette_size > 64) ? 6 : (palette_size > 32) ? 5
: (palette_size > 16) ? 4 : (palette_size > 8) ? 3
: (palette_size > 4) ? 2
: (palette_size > 2) ? 1 : 0;
int colorTableSizeInFormat = 1 << (colorTableScaleLessOne + 1);
{
byte colorResolution = (byte) colorTableScaleLessOne; // TODO:
boolean globalColorTableFlag = false;
boolean sortFlag = false;
int globalColorTableFlagMask = 1 << 7;
int sortFlagMask = 8;
int sizeOfGlobalColorTable = 0;
int packedFields = ((globalColorTableFlag ? globalColorTableFlagMask
: 0)
| (sortFlag ? sortFlagMask : 0)
| ((7 & colorResolution) << 4) | (7 & sizeOfGlobalColorTable));
bos.write(packedFields); // one byte
}
{
byte BackgroundColorIndex = 0;
bos.write(BackgroundColorIndex);
}
{
byte PixelAspectRatio = 0;
bos.write(PixelAspectRatio);
}
{ // write Global Color Table.
}
{ // ALWAYS write GraphicControlExtension
bos.write(EXTENSION_CODE);
bos.write((byte) 0xf9);
// bos.write(0xff & (kGraphicControlExtension >> 8));
// bos.write(0xff & (kGraphicControlExtension >> 0));
bos.write((byte) 4); // block size;
int packedFields = hasAlpha ? 1 : 0; // transparency flag
bos.write((byte) packedFields);
bos.write((byte) 0); // Delay Time
bos.write((byte) 0); // Delay Time
bos.write((byte) (hasAlpha ? palette2.length() : 0)); // Transparent
// Color
// Index
bos.write((byte) 0); // terminator
}
if (null != xmpXml)
{
bos.write(EXTENSION_CODE);
bos.write(APPLICATION_EXTENSION_LABEL);
bos.write(XMP_APPLICATION_ID_AND_AUTH_CODE.length); // 0x0B
bos.write(XMP_APPLICATION_ID_AND_AUTH_CODE);
byte xmpXmlBytes[] = xmpXml.getBytes("utf-8");
bos.write(xmpXmlBytes);
// write "magic trailer"
for (int magic = 0; magic <= 0xff; magic++)
bos.write(0xff - magic);
bos.write((byte) 0); // terminator
}
{ // Image Descriptor.
bos.write(IMAGE_SEPARATOR);
bos.write2Bytes(0); // Image Left Position
bos.write2Bytes(0); // Image Top Position
bos.write2Bytes(width); // Image Width
bos.write2Bytes(height); // Image Height
{
boolean LocalColorTableFlag = true;
// boolean LocalColorTableFlag = false;
boolean InterlaceFlag = false;
boolean SortFlag = false;
int SizeOfLocalColorTable = colorTableScaleLessOne;
// int SizeOfLocalColorTable = 0;
int PackedFields = ((LocalColorTableFlag ? LOCAL_COLOR_TABLE_FLAG_MASK
: 0)
| (InterlaceFlag ? INTERLACE_FLAG_MASK : 0)
| (SortFlag ? SORT_FLAG_MASK : 0) | (7 & SizeOfLocalColorTable));
bos.write(PackedFields); // one byte
}
}
{ // write Local Color Table.
for (int i = 0; i < colorTableSizeInFormat; i++)
{
if (i < palette2.length())
{
int rgb = palette2.getEntry(i);
int red = 0xff & (rgb >> 16);
int green = 0xff & (rgb >> 8);
int blue = 0xff & (rgb >> 0);
bos.write(red);
bos.write(green);
bos.write(blue);
} else
{
bos.write(0);
bos.write(0);
bos.write(0);
}
}
}
{ // get Image Data.
int image_data_total = 0;
int LZWMinimumCodeSize = colorTableScaleLessOne + 1;
// LZWMinimumCodeSize = Math.max(8, LZWMinimumCodeSize);
if (LZWMinimumCodeSize < 2)
LZWMinimumCodeSize = 2;
// TODO:
// make
// better
// choice
// here.
bos.write(LZWMinimumCodeSize);
MyLZWCompressor compressor = new MyLZWCompressor(
LZWMinimumCodeSize, BYTE_ORDER_LSB, false); // GIF
// Mode);
byte imagedata[] = new byte[width * height];
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int argb = src.getRGB(x, y);
int rgb = 0xffffff & argb;
int index;
if (hasAlpha)
{
int alpha = 0xff & (argb >> 24);
final int alphaThreshold = 255;
if (alpha < alphaThreshold)
index = palette2.length(); // is transparent
else
index = palette2.getPaletteIndex(rgb);
} else
{
index = palette2.getPaletteIndex(rgb);
}
imagedata[y * width + x] = (byte) index;
}
}
byte compressed[] = compressor.compress(imagedata);
writeAsSubBlocks(bos, compressed);
image_data_total += compressed.length;
}
// palette2.dump();
bos.write(TERMINATOR_BYTE);
}
bos.close();
os.close();
}