mirror of
https://github.com/dmolony/DiskBrowser.git
synced 2024-11-16 19:08:49 +00:00
324 lines
10 KiB
Java
324 lines
10 KiB
Java
package com.bytezone.diskbrowser.applefile;
|
|
|
|
import java.awt.AlphaComposite;
|
|
import java.awt.Color;
|
|
import java.awt.Graphics2D;
|
|
import java.awt.image.BufferedImage;
|
|
import java.awt.image.DataBuffer;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
|
|
import com.bytezone.diskbrowser.utilities.HexFormatter;
|
|
|
|
public class IconFile extends AbstractFile
|
|
{
|
|
private static Palette palette = new Palette ("Virtual II",
|
|
new int[] { 0x000000, // 0 black
|
|
0xDD0033, // 1 magenta
|
|
0x885500, // 2 brown (8)
|
|
0xFF6600, // 3 orange (9)
|
|
0x007722, // 4 dark green
|
|
0x555555, // 5 grey1
|
|
0x11DD00, // 6 light green (C)
|
|
0xFFFF00, // 7 yellow (D)
|
|
0x000099, // 8 dark blue (2)
|
|
0xDD22DD, // 9 purple (3)
|
|
0xAAAAAA, // A grey2
|
|
0xFF9988, // B pink
|
|
0x2222FF, // C med blue (6)
|
|
0x66AAFF, // D light blue (7)
|
|
0x44FF99, // E aqua
|
|
0xFFFFFF // F white
|
|
});
|
|
// private static Palette palette = new Palette ("Icon palette",
|
|
// new int[] { 0x000000, // 0 black
|
|
// 0x2222FF, // C med blue (6)
|
|
// 0xFFFF00, // 7 yellow (D)
|
|
// 0xFFFFFF, // F white
|
|
// 0x000000, // black
|
|
// 0xDD0033, // 1 magenta
|
|
// 0x11DD00, // 6 light green (C)
|
|
// 0xFFFFFF, // F white
|
|
// 0x000000, // 0 black
|
|
// 0x2222FF, // C med blue (6)
|
|
// 0xFFFF00, // 7 yellow (D)
|
|
// 0xFFFFFF, // F white
|
|
// 0x000000, // black
|
|
// 0xDD0033, // 1 magenta
|
|
// 0x11DD00, // 6 light green (C)
|
|
// 0xFFFFFF, // F white
|
|
// });
|
|
|
|
private final int iBlkNext;
|
|
private final int iBlkID;
|
|
private final int iBlkPath;
|
|
private final String iBlkName;
|
|
private final List<Icon> icons = new ArrayList<IconFile.Icon> ();
|
|
|
|
public IconFile (String name, byte[] buffer)
|
|
{
|
|
super (name, buffer);
|
|
|
|
iBlkNext = HexFormatter.unsignedLong (buffer, 0);
|
|
iBlkID = HexFormatter.unsignedShort (buffer, 4);
|
|
iBlkPath = HexFormatter.unsignedLong (buffer, 6);
|
|
iBlkName = HexFormatter.getHexString (buffer, 10, 16);
|
|
|
|
int ptr = 26;
|
|
while (true)
|
|
{
|
|
int dataLen = HexFormatter.unsignedShort (buffer, ptr);
|
|
if (dataLen == 0 || (dataLen + ptr) > buffer.length)
|
|
break;
|
|
icons.add (new Icon (buffer, ptr));
|
|
ptr += dataLen;
|
|
}
|
|
|
|
// calculate maximum width and height for every icon
|
|
int maxHeight = 0;
|
|
int maxWidth = 0;
|
|
for (Icon icon : icons)
|
|
{
|
|
maxHeight = Math.max (maxHeight, icon.largeImage.iconHeight);
|
|
maxWidth = Math.max (maxWidth, icon.largeImage.iconWidth);
|
|
}
|
|
|
|
// System.out.printf ("Icons: %d, Max height: %d, max width: %d%n", icons.size (),
|
|
// maxHeight, maxWidth);
|
|
|
|
int base = 10;
|
|
int x = base;
|
|
int y = base;
|
|
int gap = 5;
|
|
int columns = Math.min (icons.size (), 4);
|
|
int rows = (icons.size () - 1) / columns + 1;
|
|
// System.out.printf ("Rows: %d, cols: %d%n", rows, columns);
|
|
|
|
image = new BufferedImage (columns * maxWidth + 2 * base + (columns - 1) * gap,
|
|
rows * maxHeight + 2 * base + (rows - 1) * gap, BufferedImage.TYPE_INT_RGB);
|
|
|
|
Graphics2D graphics = image.createGraphics ();
|
|
graphics.setBackground (Color.WHITE);
|
|
graphics.clearRect (0, 0, image.getWidth (), image.getHeight ());
|
|
|
|
Graphics2D g2d = image.createGraphics ();
|
|
g2d.setComposite (AlphaComposite.getInstance (AlphaComposite.SRC_OVER, (float) 1.0));
|
|
|
|
int count = 0;
|
|
for (Icon icon : icons)
|
|
{
|
|
g2d.drawImage (icon.largeImage.image, x, y, null);
|
|
x += maxWidth + gap;
|
|
count++;
|
|
if (count % columns == 0)
|
|
{
|
|
x = base;
|
|
y += maxHeight + gap;
|
|
}
|
|
}
|
|
g2d.dispose ();
|
|
}
|
|
|
|
@Override
|
|
public String getText ()
|
|
{
|
|
StringBuilder text = new StringBuilder ("Name : " + name + "\n\n");
|
|
|
|
text.append (String.format ("Next Icon file .. %d%n", iBlkNext));
|
|
text.append (String.format ("Block ID ........ %d%n", iBlkID));
|
|
text.append (String.format ("Block path ...... %d%n", iBlkPath));
|
|
text.append (String.format ("Block name ...... %s%n", iBlkName));
|
|
|
|
text.append ("\n");
|
|
for (Icon icon : icons)
|
|
{
|
|
text.append (icon);
|
|
text.append ("\n\n");
|
|
}
|
|
|
|
return text.toString ();
|
|
}
|
|
|
|
class Icon
|
|
{
|
|
byte[] buffer;
|
|
int iDataLen;
|
|
String pathName;
|
|
String dataName;
|
|
int iDataType;
|
|
int iDataAux;
|
|
Image largeImage;
|
|
Image smallImage;
|
|
|
|
public Icon (byte[] fullBuffer, int ptr)
|
|
{
|
|
iDataLen = HexFormatter.unsignedShort (fullBuffer, ptr);
|
|
|
|
buffer = new byte[iDataLen];
|
|
System.arraycopy (fullBuffer, ptr, buffer, 0, buffer.length);
|
|
|
|
int len = buffer[2] & 0xFF;
|
|
pathName = new String (buffer, 3, len);
|
|
|
|
len = buffer[66] & 0xFF;
|
|
dataName = new String (buffer, 67, len);
|
|
|
|
iDataType = HexFormatter.unsignedShort (buffer, 82);
|
|
iDataAux = HexFormatter.unsignedShort (buffer, 84);
|
|
|
|
largeImage = new Image (buffer, 86);
|
|
smallImage = new Image (buffer, 86 + largeImage.size ());
|
|
}
|
|
|
|
@Override
|
|
public String toString ()
|
|
{
|
|
StringBuilder text = new StringBuilder ();
|
|
text.append (String.format ("Data length .. %04X%n", iDataLen));
|
|
text.append (String.format ("Path name .... %s%n", pathName));
|
|
text.append (String.format ("Data name .... %s%n", dataName));
|
|
text.append ("\n");
|
|
text.append (largeImage);
|
|
text.append ("\n");
|
|
text.append ("\n");
|
|
text.append (smallImage);
|
|
return text.toString ();
|
|
}
|
|
}
|
|
|
|
class Image
|
|
{
|
|
int iconType;
|
|
int iconSize;
|
|
int iconHeight;
|
|
int iconWidth;
|
|
byte[] iconImage;
|
|
byte[] iconMask;
|
|
boolean colour;
|
|
private final BufferedImage image;
|
|
|
|
public Image (byte[] buffer, int ptr)
|
|
{
|
|
iconType = HexFormatter.unsignedShort (buffer, ptr);
|
|
iconSize = HexFormatter.unsignedShort (buffer, ptr + 2);
|
|
iconHeight = HexFormatter.unsignedShort (buffer, ptr + 4);
|
|
iconWidth = HexFormatter.unsignedShort (buffer, ptr + 6);
|
|
|
|
iconImage = new byte[iconSize];
|
|
iconMask = new byte[iconSize];
|
|
|
|
colour = (iconType & 0x80) != 0;
|
|
|
|
System.arraycopy (buffer, ptr + 8, iconImage, 0, iconSize);
|
|
System.arraycopy (buffer, ptr + 8 + iconSize, iconMask, 0, iconSize);
|
|
|
|
int[] colours = palette.getColours ();
|
|
int gap = 5;
|
|
|
|
image = new BufferedImage (iconWidth, iconHeight, BufferedImage.TYPE_INT_RGB);
|
|
|
|
DataBuffer dataBuffer = image.getRaster ().getDataBuffer ();
|
|
int element = 0;
|
|
// System.out.println ("*** " + dataBuffer.getSize ());
|
|
// System.out.printf ("width %d height %d%n", iconWidth, iconHeight);
|
|
// System.out.printf ("icon image length %d%n", iconImage.length);
|
|
|
|
int rowBytes = (iconWidth - 1) / 2 + 1;
|
|
if (true)
|
|
for (int i = 0; i < iconImage.length; i += rowBytes)
|
|
{
|
|
int max = Math.min (i + rowBytes, dataBuffer.getSize ());
|
|
// System.out.printf ("max %d%n", max);
|
|
for (int j = i; j < max; j++)
|
|
{
|
|
int left = (byte) ((iconImage[j] & 0xF0) >>> 4);
|
|
int right = (byte) (iconImage[j] & 0x0F);
|
|
int maskLeft = (byte) ((iconMask[j] & 0xF0) >>> 4);
|
|
int maskRight = (byte) (iconMask[j] & 0x0F);
|
|
|
|
// see WhatIsThe2gs/System 6 and Free Games.hdv/SWAREGAME.ICONS
|
|
if (element < dataBuffer.getSize ())
|
|
{
|
|
dataBuffer.setElem (element++, colours[left & maskLeft]);
|
|
dataBuffer.setElem (element++, colours[right & maskRight]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public int size ()
|
|
{
|
|
return 8 + iconSize * 2;
|
|
}
|
|
|
|
@Override
|
|
public String toString ()
|
|
{
|
|
StringBuilder text = new StringBuilder ();
|
|
|
|
text.append (String.format ("Icon type .... %04X%n", iconType));
|
|
text.append (String.format ("Icon size .... %d%n", iconSize));
|
|
text.append (String.format ("Icon height .. %d%n", iconHeight));
|
|
text.append (String.format ("Icon width ... %d%n%n", iconWidth));
|
|
appendIcon (text, iconImage);
|
|
text.append ("\n\n");
|
|
appendIcon (text, iconMask);
|
|
|
|
return text.toString ();
|
|
}
|
|
|
|
/*
|
|
Offset Color RGB Mini-Palette
|
|
|
|
0 Black 000 0
|
|
1 Blue 00F 1
|
|
2 Yellow FF0 2
|
|
3 White FFF 3
|
|
4 Black 000 0
|
|
5 Red D00 1
|
|
6 Green 0E0 2
|
|
7 White FFF 3
|
|
|
|
8 Black 000 0
|
|
9 Blue 00F 1
|
|
10 Yellow FF0 2
|
|
11 White FFF 3
|
|
12 Black 000 0
|
|
13 Red D00 1
|
|
14 Green 0E0 2
|
|
15 White FFF 3
|
|
|
|
The displayMode word bits are defined as:
|
|
|
|
Bit 0 selectedIconBit 1 = invert image before copying
|
|
Bit 1 openIconBit 1 = copy light-gray pattern instead of image
|
|
Bit 2 offLineBit 1 = AND light-gray pattern to image being copied
|
|
Bits 3-7 reserved.
|
|
Bits 8-11 foreground color to apply to black part of black & white icons
|
|
Bits 12-15 background color to apply to white part of black & white icons
|
|
|
|
Bits 0-2 can occur at once and are tested in the order 1-2-0.
|
|
|
|
"Color is only applied to the black and white icons if bits 15-8 are not all 0.
|
|
Colored pixels in an icon are inverted by black pixels becoming white and any
|
|
other color of pixel becoming black."
|
|
*/
|
|
|
|
private void appendIcon (StringBuilder text, byte[] buffer)
|
|
{
|
|
int rowBytes = (iconWidth - 1) / 2 + 1;
|
|
for (int i = 0; i < iconImage.length; i += rowBytes)
|
|
{
|
|
for (int ptr = i, max = i + rowBytes; ptr < max; ptr++)
|
|
{
|
|
int left = (byte) ((buffer[ptr] & 0xF0) >>> 4);
|
|
int right = (byte) (buffer[ptr] & 0x0F);
|
|
text.append (String.format ("%X %X ", left, right));
|
|
}
|
|
text.append ("\n");
|
|
}
|
|
if (text.length () > 0)
|
|
text.deleteCharAt (text.length () - 1);
|
|
}
|
|
}
|
|
} |