2016-12-31 09:34:15 +00:00
|
|
|
package com.bytezone.diskbrowser.applefile;
|
|
|
|
|
2017-01-26 04:19:23 +00:00
|
|
|
import java.awt.Color;
|
2016-12-31 09:34:15 +00:00
|
|
|
import java.io.ByteArrayInputStream;
|
|
|
|
import java.io.IOException;
|
2017-01-14 01:40:58 +00:00
|
|
|
import java.util.List;
|
2016-12-31 09:34:15 +00:00
|
|
|
|
|
|
|
import javax.imageio.ImageIO;
|
|
|
|
|
|
|
|
import com.bytezone.diskbrowser.prodos.ProdosConstants;
|
2017-01-26 04:19:23 +00:00
|
|
|
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
2016-12-31 09:34:15 +00:00
|
|
|
|
|
|
|
public abstract class HiResImage extends AbstractFile
|
|
|
|
{
|
2018-07-25 05:48:14 +00:00
|
|
|
// File Type Aux Name
|
|
|
|
// $06 BIN isGif() - OriginalHiResImage
|
|
|
|
// $06 BIN isPng() - OriginalHiResImage
|
|
|
|
// $06 BIN .BMP isBmp() - OriginalHiResImage
|
|
|
|
// $06 BIN .AUX - DoubleHiResImage
|
|
|
|
// $06 BIN .PAC - DoubleHiResImage
|
|
|
|
// $06 BIN .A2FC - DoubleHiResImage
|
|
|
|
// $06 BIN $2000 eof $4000 - DoubleHiResImage
|
|
|
|
// $06 BIN $1FFF eof $1FF8/$1FFF/$2000/$4000 - OriginalHiResImage
|
|
|
|
// $06 BIN $2000 eof $1FF8/$1FFF/$2000/$4000 - OriginalHiResImage
|
|
|
|
// $06 BIN $4000 eof $1FF8/$1FFF/$2000/$4000 - OriginalHiResImage
|
|
|
|
// $06 BIN .3200 - ???
|
|
|
|
// $06 BIN .3201 - ???
|
|
|
|
|
|
|
|
// $08 PICT <$4000 Apple II Graphics File - ???
|
|
|
|
// $08 PICT $4000 Packed Hi-Res file - ???
|
|
|
|
// $08 PICT $4001 Packed Double Hi-Res file - ???
|
|
|
|
|
|
|
|
// $C0 PNT $0000 Paintworks Packed Super Hi-Res - SHRPictureFile2 *
|
|
|
|
// * $C0 PNT $0001 Packed IIGS Super Hi-Res Image (xx) - SHRPictureFile2
|
|
|
|
// * $C0 PNT $0002 IIGS Super Hi-Res Picture File (APF) - SHRPictureFile
|
|
|
|
// $C0 PNT $0003 Packed IIGS QuickDraw II PICT File - SHRPictureFile2 *
|
2018-07-28 12:00:02 +00:00
|
|
|
// $C0 PNT $0004 Packed Super Hi-Res 3200 (Brooks) (yy) .3201? - SHRPictureFile2 *
|
|
|
|
// $C0 PNT $8001 GTv background picture
|
|
|
|
// $C0 PNT $8005 DreamGraphix document
|
|
|
|
// $C0 PNT $8006 GIF
|
2018-07-25 05:48:14 +00:00
|
|
|
|
|
|
|
// * $C1 PIC $0000 IIGS Super Hi-Res Image (xx) - SHRPictureFile2
|
|
|
|
// $C1 PIC $0001 IIGS QuickDraw II PICT File - SHRPictureFile2 *
|
2018-07-28 12:00:02 +00:00
|
|
|
// * $C1 PIC $0002 Super Hi-Res 3200 (Brooks) (yy) .3200? - SHRPictureFile2
|
|
|
|
// $C1 PIC $8001 Allison raw image
|
|
|
|
// $C1 PIC $8002 Thunderscan
|
|
|
|
// $C1 PIC $8003 DreamGraphix
|
|
|
|
|
|
|
|
// $C2 ANI Paintworks animation
|
|
|
|
// $C3 PAL Paintworks palette
|
2018-07-25 05:48:14 +00:00
|
|
|
|
2018-07-31 07:02:19 +00:00
|
|
|
static PaletteFactory paletteFactory = new PaletteFactory ();
|
2017-01-12 22:11:05 +00:00
|
|
|
|
2018-07-31 07:02:19 +00:00
|
|
|
static final byte[] pngHeader =
|
2016-12-31 09:34:15 +00:00
|
|
|
{ (byte) 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
|
|
|
|
|
2018-07-31 07:02:19 +00:00
|
|
|
static boolean colourQuirks;
|
|
|
|
static boolean monochrome;
|
2016-12-31 09:34:15 +00:00
|
|
|
|
2018-07-31 07:02:19 +00:00
|
|
|
int fileType;
|
|
|
|
int auxType;
|
|
|
|
int eof;
|
2017-01-25 11:02:50 +00:00
|
|
|
|
2018-07-31 07:02:19 +00:00
|
|
|
byte[] unpackedBuffer;
|
|
|
|
int paletteIndex;
|
|
|
|
String failureReason = "";
|
2016-12-31 09:34:15 +00:00
|
|
|
|
|
|
|
public HiResImage (String name, byte[] buffer)
|
|
|
|
{
|
|
|
|
super (name, buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
public HiResImage (String name, byte[] buffer, int loadAddress)
|
|
|
|
{
|
|
|
|
this (name, buffer, loadAddress, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
public HiResImage (String name, byte[] buffer, int loadAddress, boolean scrunched)
|
|
|
|
{
|
|
|
|
super (name, buffer);
|
|
|
|
|
|
|
|
this.loadAddress = loadAddress; // for the disassembly listing
|
|
|
|
|
|
|
|
if (scrunched)
|
|
|
|
this.buffer = unscrunch (buffer);
|
|
|
|
}
|
|
|
|
|
2017-01-25 11:02:50 +00:00
|
|
|
public HiResImage (String name, byte[] buffer, int fileType, int auxType, int eof)
|
2016-12-31 09:34:15 +00:00
|
|
|
{
|
|
|
|
super (name, buffer);
|
|
|
|
|
|
|
|
this.fileType = fileType;
|
|
|
|
this.auxType = auxType;
|
2017-01-25 11:02:50 +00:00
|
|
|
this.eof = eof;
|
2016-12-31 09:34:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
protected void createImage ()
|
|
|
|
{
|
2017-01-25 05:26:37 +00:00
|
|
|
if (isGif (buffer) || isPng (buffer) || isBmp (buffer))
|
2016-12-31 09:34:15 +00:00
|
|
|
makeImage ();
|
|
|
|
else if (monochrome)
|
|
|
|
createMonochromeImage ();
|
|
|
|
else
|
|
|
|
createColourImage ();
|
|
|
|
}
|
|
|
|
|
2018-07-30 08:44:29 +00:00
|
|
|
abstract void createMonochromeImage ();
|
2016-12-31 09:34:15 +00:00
|
|
|
|
2018-07-30 08:44:29 +00:00
|
|
|
abstract void createColourImage ();
|
2016-12-31 09:34:15 +00:00
|
|
|
|
2017-01-14 20:58:07 +00:00
|
|
|
public void checkPalette ()
|
|
|
|
{
|
|
|
|
if (!monochrome && paletteIndex != paletteFactory.getCurrentPaletteIndex ())
|
|
|
|
createImage ();
|
|
|
|
}
|
|
|
|
|
2017-01-14 11:11:07 +00:00
|
|
|
public void setPalette ()
|
2017-01-11 21:26:28 +00:00
|
|
|
{
|
|
|
|
if (!monochrome)
|
|
|
|
createImage ();
|
|
|
|
}
|
|
|
|
|
2016-12-31 09:34:15 +00:00
|
|
|
public void setColourQuirks (boolean value)
|
|
|
|
{
|
|
|
|
if (colourQuirks == value)
|
|
|
|
return;
|
|
|
|
|
|
|
|
colourQuirks = value;
|
|
|
|
|
|
|
|
if (!monochrome)
|
|
|
|
createImage ();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setMonochrome (boolean value)
|
|
|
|
{
|
|
|
|
if (monochrome == value)
|
|
|
|
return;
|
|
|
|
|
|
|
|
monochrome = value;
|
|
|
|
createImage ();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void setDefaultColourQuirks (boolean value)
|
|
|
|
{
|
|
|
|
colourQuirks = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void setDefaultMonochrome (boolean value)
|
|
|
|
{
|
|
|
|
monochrome = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*-
|
|
|
|
Mode Page 1 Page 2
|
|
|
|
280 x 192 Black & White 0 4
|
|
|
|
280 x 192 Limited Color 1 5
|
|
|
|
560 x 192 Black & White 2 6
|
|
|
|
140 x 192 Full Color 3 7
|
|
|
|
*/
|
|
|
|
|
|
|
|
// SHR see - http://noboot.com/charlie/cb2e_p3.htm
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String getText ()
|
|
|
|
{
|
|
|
|
String auxText = "";
|
|
|
|
StringBuilder text = new StringBuilder ("Image File : " + name);
|
2017-01-26 04:19:23 +00:00
|
|
|
text.append (String.format ("%nFile type : $%02X %s", fileType,
|
|
|
|
ProdosConstants.fileTypes[fileType]));
|
2016-12-31 09:34:15 +00:00
|
|
|
|
|
|
|
switch (fileType)
|
|
|
|
{
|
2017-01-26 04:19:23 +00:00
|
|
|
case ProdosConstants.FILE_TYPE_PICT: // 0x08
|
2016-12-31 09:34:15 +00:00
|
|
|
if (auxType < 0x4000)
|
|
|
|
{
|
2017-01-26 04:19:23 +00:00
|
|
|
auxText = "Apple II Graphics File";
|
2016-12-31 09:34:15 +00:00
|
|
|
byte mode = buffer[0x78]; // 0-7
|
2017-01-26 04:19:23 +00:00
|
|
|
System.out.println ("Prodos PICT, mode=" + mode); // see mode table above
|
2016-12-31 09:34:15 +00:00
|
|
|
}
|
|
|
|
else if (auxType == 0x4000)
|
|
|
|
auxText = "Packed Hi-Res File";
|
|
|
|
else if (auxType == 0x4001)
|
|
|
|
auxText = "Packed Double Hi-Res File";
|
2017-01-27 07:11:00 +00:00
|
|
|
else
|
|
|
|
auxText = "Unknown aux: " + auxType;
|
2016-12-31 09:34:15 +00:00
|
|
|
break;
|
|
|
|
|
2017-01-26 04:19:23 +00:00
|
|
|
case ProdosConstants.FILE_TYPE_PNT: // 0xC0
|
2018-07-30 08:44:29 +00:00
|
|
|
switch (auxType)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
auxText = "Paintworks Packed SHR Image";
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
auxText = "Packed Super Hi-Res Image";
|
|
|
|
break;
|
|
|
|
case 2:
|
2018-07-31 07:02:19 +00:00
|
|
|
auxText = "Super Hi-Res Image (Apple Preferred Format)";
|
2018-07-30 08:44:29 +00:00
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
auxText = "Packed QuickDraw II PICT File";
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
auxText = "Packed Super Hi-Res 3200 color image";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
auxText = "Unknown aux: " + auxType;
|
|
|
|
}
|
2016-12-31 09:34:15 +00:00
|
|
|
break;
|
|
|
|
|
2017-01-26 04:19:23 +00:00
|
|
|
case ProdosConstants.FILE_TYPE_PIC: // 0xC1
|
2018-07-30 08:44:29 +00:00
|
|
|
switch (auxType)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
auxText = "Super Hi-res Screen Image";
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
auxText = "QuickDraw PICT File";
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
auxText = "Super Hi-Res 3200 color image";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
auxText = "Unknown aux: " + auxType;
|
|
|
|
}
|
2016-12-31 09:34:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!auxText.isEmpty ())
|
|
|
|
text.append (String.format ("%nAux type : $%04X %s", auxType, auxText));
|
|
|
|
|
|
|
|
text.append (String.format ("%nFile size : %,d", buffer.length));
|
2017-01-25 11:02:50 +00:00
|
|
|
text.append (String.format ("%nEOF : %,d", eof));
|
2016-12-31 09:34:15 +00:00
|
|
|
if (unpackedBuffer != null)
|
|
|
|
{
|
|
|
|
text.append (String.format ("%nUnpacked : %,d%n%n", unpackedBuffer.length));
|
2017-01-25 01:38:00 +00:00
|
|
|
// text.append (HexFormatter.format (unpackedBuffer));
|
2016-12-31 09:34:15 +00:00
|
|
|
}
|
2018-07-31 07:02:19 +00:00
|
|
|
if (!failureReason.isEmpty ())
|
|
|
|
text.append (String.format ("%nFailure : %s", failureReason));
|
2016-12-31 09:34:15 +00:00
|
|
|
|
|
|
|
return text.toString ();
|
|
|
|
}
|
|
|
|
|
2017-01-25 04:40:15 +00:00
|
|
|
/*
|
|
|
|
* Unpack the Apple PackBytes format.
|
|
|
|
*
|
|
|
|
* Format is:
|
|
|
|
* <flag><data> ...
|
|
|
|
*
|
|
|
|
* Flag values (first 6 bits of flag byte):
|
|
|
|
* 00xxxxxx: (0-63) 1 to 64 bytes follow, all different
|
|
|
|
* 01xxxxxx: (0-63) 1 to 64 repeats of next byte
|
|
|
|
* 10xxxxxx: (0-63) 1 to 64 repeats of next 4 bytes
|
|
|
|
* 11xxxxxx: (0-63) 1 to 64 repeats of next byte taken as 4 bytes
|
|
|
|
* (as in 10xxxxxx case)
|
|
|
|
*/
|
|
|
|
|
2016-12-31 09:34:15 +00:00
|
|
|
// Super Hi-res IIGS
|
|
|
|
protected byte[] unpackBytes (byte[] buffer)
|
2018-07-28 12:00:02 +00:00
|
|
|
{
|
|
|
|
for (int i = 1; i <= 4; i++)
|
|
|
|
try
|
|
|
|
{
|
|
|
|
byte[] newBuf = new byte[32768 * i]; // keep guessing
|
|
|
|
unpack (buffer, newBuf);
|
|
|
|
return newBuf;
|
|
|
|
}
|
|
|
|
catch (ArrayIndexOutOfBoundsException e)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2018-07-31 07:02:19 +00:00
|
|
|
System.out.println ("unpackBytes()");
|
|
|
|
failureReason = "buffer too small";
|
2018-07-28 12:00:02 +00:00
|
|
|
return new byte[0];
|
|
|
|
}
|
|
|
|
|
2018-07-30 08:44:29 +00:00
|
|
|
// this should call unpackLine()
|
2018-07-28 12:00:02 +00:00
|
|
|
private void unpack (byte[] buffer, byte[] newBuf) throws ArrayIndexOutOfBoundsException
|
2016-12-31 09:34:15 +00:00
|
|
|
{
|
|
|
|
// routine found here - http://kpreid.livejournal.com/4319.html
|
|
|
|
|
|
|
|
byte[] fourBuf = new byte[4];
|
|
|
|
|
|
|
|
int ptr = 0, newPtr = 0;
|
|
|
|
while (ptr < buffer.length)
|
|
|
|
{
|
2017-01-24 08:59:40 +00:00
|
|
|
int type = (buffer[ptr] & 0xC0) >> 6; // 0-3
|
|
|
|
int count = (buffer[ptr++] & 0x3F) + 1; // 1-64
|
2016-12-31 09:34:15 +00:00
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
2018-07-25 05:48:14 +00:00
|
|
|
case 0: // copy next 1-64 bytes as is
|
2016-12-31 09:34:15 +00:00
|
|
|
while (count-- != 0)
|
|
|
|
newBuf[newPtr++] = buffer[ptr++];
|
|
|
|
break;
|
|
|
|
|
2018-07-25 05:48:14 +00:00
|
|
|
case 1: // repeat next byte 3/5/6/7 times
|
2016-12-31 09:34:15 +00:00
|
|
|
byte b = buffer[ptr++];
|
|
|
|
while (count-- != 0)
|
|
|
|
newBuf[newPtr++] = b;
|
|
|
|
break;
|
|
|
|
|
2018-07-25 05:48:14 +00:00
|
|
|
case 2: // repeat next 4 bytes (count) times
|
2016-12-31 09:34:15 +00:00
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
fourBuf[i] = buffer[ptr++];
|
|
|
|
while (count-- != 0)
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
newBuf[newPtr++] = fourBuf[i];
|
|
|
|
break;
|
|
|
|
|
2018-07-25 05:48:14 +00:00
|
|
|
case 3: // repeat next byte (4*count) times
|
2016-12-31 09:34:15 +00:00
|
|
|
b = buffer[ptr++];
|
|
|
|
count *= 4;
|
|
|
|
while (count-- != 0)
|
|
|
|
newBuf[newPtr++] = b;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-31 07:02:19 +00:00
|
|
|
// Super Hi-res IIGS (MAIN in $C0/02)
|
|
|
|
int unpackLine (byte[] buffer, byte[] newBuf, int newPtr)
|
2017-01-26 04:19:23 +00:00
|
|
|
{
|
|
|
|
byte[] fourBuf = new byte[4];
|
|
|
|
|
|
|
|
int ptr = 0;
|
|
|
|
while (ptr < buffer.length)
|
|
|
|
{
|
|
|
|
int type = (buffer[ptr] & 0xC0) >> 6; // 0-3
|
|
|
|
int count = (buffer[ptr++] & 0x3F) + 1; // 1-64
|
|
|
|
|
|
|
|
if (ptr >= buffer.length)
|
|
|
|
break;
|
|
|
|
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
while (count-- != 0)
|
2018-07-31 07:02:19 +00:00
|
|
|
if (newPtr < newBuf.length && ptr < buffer.length)
|
2017-01-26 04:19:23 +00:00
|
|
|
newBuf[newPtr++] = buffer[ptr++];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
byte b = buffer[ptr++];
|
|
|
|
while (count-- != 0)
|
2018-07-31 07:02:19 +00:00
|
|
|
if (newPtr < newBuf.length)
|
2017-01-26 04:19:23 +00:00
|
|
|
newBuf[newPtr++] = b;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
|
if (ptr < buffer.length)
|
|
|
|
fourBuf[i] = buffer[ptr++];
|
|
|
|
while (count-- != 0)
|
|
|
|
for (int i = 0; i < 4; i++)
|
2018-07-31 07:02:19 +00:00
|
|
|
if (newPtr < newBuf.length)
|
2017-01-26 04:19:23 +00:00
|
|
|
newBuf[newPtr++] = fourBuf[i];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
b = buffer[ptr++];
|
|
|
|
count *= 4;
|
|
|
|
while (count-- != 0)
|
2018-07-31 07:02:19 +00:00
|
|
|
if (newPtr < newBuf.length)
|
2017-01-26 04:19:23 +00:00
|
|
|
newBuf[newPtr++] = b;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return newPtr;
|
|
|
|
}
|
|
|
|
|
2016-12-31 09:34:15 +00:00
|
|
|
// Beagle Bros routine to expand a hi-res screen
|
|
|
|
private byte[] unscrunch (byte[] src)
|
|
|
|
{
|
|
|
|
byte[] dst = new byte[0x2000];
|
|
|
|
int p1 = 0;
|
|
|
|
int p2 = 0;
|
|
|
|
|
|
|
|
while (p1 < dst.length)
|
|
|
|
{
|
|
|
|
byte b = src[p2++];
|
|
|
|
if ((b == (byte) 0x80) || (b == (byte) 0xFF))
|
|
|
|
{
|
|
|
|
b &= 0x7F;
|
|
|
|
int rpt = src[p2++];
|
|
|
|
for (int i = 0; i < rpt; i++)
|
|
|
|
dst[p1++] = b;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
dst[p1++] = b;
|
|
|
|
}
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void makeImage ()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
image = ImageIO.read (new ByteArrayInputStream (buffer));
|
|
|
|
}
|
|
|
|
catch (IOException e)
|
|
|
|
{
|
|
|
|
e.printStackTrace ();
|
|
|
|
}
|
2017-01-25 05:26:37 +00:00
|
|
|
catch (IndexOutOfBoundsException e) // some BMP files cause this
|
|
|
|
{
|
|
|
|
System.out.println ("Error in makeImage()");
|
|
|
|
System.out.println (e.getMessage ());
|
|
|
|
}
|
2016-12-31 09:34:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean isGif (byte[] buffer)
|
|
|
|
{
|
|
|
|
if (buffer.length < 6)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
String text = new String (buffer, 0, 6);
|
|
|
|
return text.equals ("GIF89a") || text.equals ("GIF87a");
|
|
|
|
}
|
|
|
|
|
|
|
|
public static boolean isPng (byte[] buffer)
|
|
|
|
{
|
|
|
|
if (buffer.length < pngHeader.length)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (int i = 0; i < pngHeader.length; i++)
|
|
|
|
if (pngHeader[i] != buffer[i])
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2017-01-12 22:11:05 +00:00
|
|
|
|
2017-02-01 21:15:30 +00:00
|
|
|
// http://www.daubnet.com/en/file-format-bmp
|
2017-01-25 05:26:37 +00:00
|
|
|
public static boolean isBmp (byte[] buffer)
|
|
|
|
{
|
2017-02-01 21:15:30 +00:00
|
|
|
if (buffer.length < 26)
|
2017-01-25 05:26:37 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
String text = new String (buffer, 0, 2);
|
2017-02-01 21:15:30 +00:00
|
|
|
int size = HexFormatter.unsignedLong (buffer, 2);
|
|
|
|
|
|
|
|
if (false)
|
|
|
|
{
|
|
|
|
int empty = HexFormatter.unsignedLong (buffer, 6);
|
|
|
|
int offset = HexFormatter.unsignedLong (buffer, 10);
|
|
|
|
int header = HexFormatter.unsignedLong (buffer, 14);
|
|
|
|
int width = HexFormatter.unsignedLong (buffer, 18);
|
|
|
|
int height = HexFormatter.unsignedLong (buffer, 22);
|
|
|
|
|
|
|
|
System.out.println (buffer.length);
|
|
|
|
System.out.println (size);
|
|
|
|
System.out.println (empty);
|
|
|
|
System.out.println (offset);
|
|
|
|
System.out.println (header);
|
|
|
|
System.out.println (width);
|
|
|
|
System.out.println (height);
|
|
|
|
}
|
|
|
|
|
|
|
|
return text.equals ("BM") && size <= buffer.length;
|
2017-01-25 05:26:37 +00:00
|
|
|
}
|
|
|
|
|
2017-01-14 01:40:58 +00:00
|
|
|
public static PaletteFactory getPaletteFactory ()
|
2017-01-12 22:11:05 +00:00
|
|
|
{
|
2017-01-14 01:40:58 +00:00
|
|
|
return paletteFactory;
|
2017-01-12 22:11:05 +00:00
|
|
|
}
|
|
|
|
|
2017-01-14 01:40:58 +00:00
|
|
|
public static List<Palette> getPalettes ()
|
2017-01-12 22:11:05 +00:00
|
|
|
{
|
2017-01-14 01:40:58 +00:00
|
|
|
return paletteFactory.getPalettes ();
|
2017-01-12 22:11:05 +00:00
|
|
|
}
|
2017-01-26 04:19:23 +00:00
|
|
|
|
|
|
|
class ColorTable
|
|
|
|
{
|
|
|
|
int id;
|
|
|
|
ColorEntry[] entries = new ColorEntry[16];
|
|
|
|
|
|
|
|
public ColorTable ()
|
|
|
|
{
|
|
|
|
// default empty table
|
|
|
|
id = -1;
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
|
|
entries[i] = new ColorEntry ();
|
|
|
|
}
|
|
|
|
|
|
|
|
public ColorTable (int id, byte[] data, int offset)
|
|
|
|
{
|
|
|
|
this.id = id;
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
|
|
{
|
2018-07-31 07:02:19 +00:00
|
|
|
// if (offset >= data.length)
|
|
|
|
// {
|
|
|
|
// System.out.println ("oops");
|
|
|
|
// return;
|
|
|
|
// }
|
2017-01-26 04:19:23 +00:00
|
|
|
entries[i] = new ColorEntry (data, offset);
|
|
|
|
offset += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
String toLine ()
|
|
|
|
{
|
|
|
|
|
|
|
|
StringBuilder text = new StringBuilder ();
|
|
|
|
|
2017-02-01 21:15:30 +00:00
|
|
|
text.append (String.format ("%02X", id));
|
2017-01-26 04:19:23 +00:00
|
|
|
for (int i = 0; i < 16; i++)
|
|
|
|
text.append (String.format (" %04X", entries[i].value));
|
|
|
|
|
|
|
|
return text.toString ();
|
|
|
|
}
|
|
|
|
|
|
|
|
void reverse ()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
|
|
{
|
|
|
|
ColorEntry temp = entries[i];
|
|
|
|
entries[i] = entries[15 - i];
|
|
|
|
entries[15 - i] = temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString ()
|
|
|
|
{
|
|
|
|
StringBuilder text = new StringBuilder ();
|
|
|
|
|
|
|
|
text.append (String.format ("%2d ColorTable%n", id));
|
|
|
|
for (int i = 0; i < 8; i++)
|
|
|
|
text.append (String.format (" %2d: %04X", i, entries[i].value));
|
|
|
|
text.append ("\n");
|
|
|
|
for (int i = 8; i < 16; i++)
|
|
|
|
text.append (String.format (" %2d: %04X", i, entries[i].value));
|
|
|
|
|
|
|
|
return text.toString ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class ColorEntry
|
|
|
|
{
|
|
|
|
int value; // 0RGB
|
|
|
|
Color color;
|
|
|
|
|
|
|
|
public ColorEntry ()
|
|
|
|
{
|
|
|
|
// default empty entry
|
|
|
|
value = 0;
|
|
|
|
color = new Color (0, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
public ColorEntry (byte[] data, int offset)
|
|
|
|
{
|
|
|
|
value = HexFormatter.unsignedShort (data, offset);
|
|
|
|
|
|
|
|
int red = ((value >> 8) & 0x0f) * 17;
|
|
|
|
int green = ((value >> 4) & 0x0f) * 17;
|
|
|
|
int blue = (value & 0x0f) * 17;
|
2017-01-27 07:11:00 +00:00
|
|
|
|
2017-01-26 04:19:23 +00:00
|
|
|
color = new Color (red, green, blue);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString ()
|
|
|
|
{
|
|
|
|
return String.format ("ColorEntry: %04X", value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class DirEntry
|
|
|
|
{
|
|
|
|
int numBytes;
|
|
|
|
int mode;
|
|
|
|
|
|
|
|
public DirEntry (byte[] data, int offset)
|
|
|
|
{
|
|
|
|
numBytes = HexFormatter.unsignedShort (data, offset);
|
|
|
|
mode = HexFormatter.unsignedShort (data, offset + 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString ()
|
|
|
|
{
|
|
|
|
return String.format ("Bytes: %5d, mode: %02X", numBytes, mode);
|
|
|
|
}
|
|
|
|
}
|
2015-06-01 09:35:51 +00:00
|
|
|
}
|