dmolony-DiskBrowser/src/com/bytezone/diskbrowser/applefile/IconFile.java

355 lines
12 KiB
Java
Raw Normal View History

2015-06-01 09:35:51 +00:00
package com.bytezone.diskbrowser.applefile;
2017-01-23 06:56:42 +00:00
import java.awt.AlphaComposite;
2017-01-23 10:02:02 +00:00
import java.awt.Color;
2017-01-23 06:56:42 +00:00
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
2015-06-01 09:35:51 +00:00
import java.util.ArrayList;
import java.util.List;
2019-08-21 21:47:19 +00:00
import com.bytezone.diskbrowser.prodos.ProdosConstants;
2016-02-24 21:11:14 +00:00
import com.bytezone.diskbrowser.utilities.HexFormatter;
2019-11-07 03:06:09 +00:00
import com.bytezone.diskbrowser.utilities.Utility;
2015-06-01 09:35:51 +00:00
2019-11-07 03:06:09 +00:00
// -----------------------------------------------------------------------------------//
2019-08-21 21:47:19 +00:00
public class IconFile extends AbstractFile implements ProdosConstants
2019-11-07 03:06:09 +00:00
// -----------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
private final int iBlkNext;
private final int iBlkID;
private final int iBlkPath;
private final String iBlkName;
2019-11-04 21:07:20 +00:00
private final List<Icon> icons = new ArrayList<> ();
2019-08-21 21:47:19 +00:00
private final boolean debug = false;
2015-06-01 09:35:51 +00:00
2019-11-07 03:06:09 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
public IconFile (String name, byte[] buffer)
2019-11-07 03:06:09 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
super (name, buffer);
iBlkNext = Utility.getLong (buffer, 0);
iBlkID = Utility.getShort (buffer, 4);
iBlkPath = Utility.getLong (buffer, 6);
2015-06-01 09:35:51 +00:00
iBlkName = HexFormatter.getHexString (buffer, 10, 16);
int ptr = 26;
2019-08-21 21:47:19 +00:00
2015-06-01 09:35:51 +00:00
while (true)
{
int dataLen = Utility.getShort (buffer, ptr);
2016-02-24 02:34:00 +00:00
if (dataLen == 0 || (dataLen + ptr) > buffer.length)
2015-06-01 09:35:51 +00:00
break;
2019-08-25 04:16:36 +00:00
2019-08-21 00:31:11 +00:00
Icon icon = new Icon (buffer, ptr);
2019-08-25 04:16:36 +00:00
if (icon.smallImage != null) // didn't have an exception
icons.add (icon);
2015-06-01 09:35:51 +00:00
ptr += dataLen;
}
2017-01-23 06:56:42 +00:00
2017-01-23 10:02:02 +00:00
// calculate maximum width and height for every icon
2017-01-23 06:56:42 +00:00
int maxHeight = 0;
int maxWidth = 0;
for (Icon icon : icons)
{
maxHeight = Math.max (maxHeight, icon.largeImage.iconHeight);
maxWidth = Math.max (maxWidth, icon.largeImage.iconWidth);
}
int base = 10;
int x = base;
int y = base;
int gap = 5;
2017-01-23 10:02:02 +00:00
int columns = Math.min (icons.size (), 4);
2017-01-23 06:56:42 +00:00
int rows = (icons.size () - 1) / columns + 1;
2019-11-07 03:06:09 +00:00
image = new BufferedImage ( //
Utility.dimension (columns, base, maxWidth, gap), //
Utility.dimension (rows, base, maxHeight, gap), //
2019-08-25 04:16:36 +00:00
BufferedImage.TYPE_INT_RGB);
2017-01-23 10:02:02 +00:00
Graphics2D graphics = image.createGraphics ();
graphics.setBackground (Color.WHITE);
graphics.clearRect (0, 0, image.getWidth (), image.getHeight ());
2017-01-23 06:56:42 +00:00
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 ();
2019-08-25 04:16:36 +00:00
graphics.dispose ();
2015-06-01 09:35:51 +00:00
}
2019-11-04 21:07:20 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
@Override
public String getText ()
2019-11-07 03:06:09 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
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 ();
}
2019-11-07 03:06:09 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
class Icon
2019-11-07 03:06:09 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
byte[] buffer;
int iDataLen;
String pathName;
String dataName;
int iDataType;
int iDataAux;
Image largeImage;
Image smallImage;
2019-11-07 03:06:09 +00:00
// -------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
public Icon (byte[] fullBuffer, int ptr)
2019-11-07 03:06:09 +00:00
// -------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
iDataLen = Utility.getShort (fullBuffer, ptr);
2015-06-01 09:35:51 +00:00
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 = Utility.getShort (buffer, 82);
iDataAux = Utility.getShort (buffer, 84);
2015-06-01 09:35:51 +00:00
2019-08-21 21:47:19 +00:00
if (debug)
{
System.out.printf ("Len %,d%n", iDataLen);
System.out.printf ("Path %,d %s%n", len, pathName);
System.out.printf ("Data %,d %s%n", len, dataName);
System.out.printf ("Type %04X %s%n", iDataType, fileTypes[iDataType]);
System.out.printf ("Aux %04X%n", iDataAux);
}
2019-08-21 00:31:11 +00:00
try
{
largeImage = new Image (buffer, 86);
smallImage = new Image (buffer, 86 + largeImage.size ());
}
catch (InvalidImageException e)
{
System.out.println (e.getMessage ());
}
2015-06-01 09:35:51 +00:00
}
2019-11-07 03:06:09 +00:00
// -------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
@Override
public String toString ()
2019-11-07 03:06:09 +00:00
// -------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
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 ();
}
}
2019-11-07 03:06:09 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
class Image
2019-11-07 03:06:09 +00:00
// ---------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
int iconType;
int iconSize;
int iconHeight;
int iconWidth;
2017-01-23 10:02:02 +00:00
byte[] iconImage;
byte[] iconMask;
boolean colour;
2017-01-23 06:56:42 +00:00
private final BufferedImage image;
2015-06-01 09:35:51 +00:00
2019-11-07 03:06:09 +00:00
// -------------------------------------------------------------------------------//
2019-08-21 00:31:11 +00:00
public Image (byte[] buffer, int ptr) throws InvalidImageException
2019-11-07 03:06:09 +00:00
// -------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
iconType = Utility.getShort (buffer, ptr);
iconSize = Utility.getShort (buffer, ptr + 2);
iconHeight = Utility.getShort (buffer, ptr + 4);
iconWidth = Utility.getShort (buffer, ptr + 6);
2015-06-01 09:35:51 +00:00
2019-08-21 21:47:19 +00:00
if (debug)
{
System.out.printf ("Icon type ... %04X %<d%n", iconType);
System.out.printf ("Icon size ... %d%n", iconSize);
System.out.printf ("Icon height . %d%n", iconHeight);
System.out.printf ("Icon width .. %d%n", iconWidth);
System.out.println ();
}
2019-11-04 21:07:20 +00:00
if (iconWidth == 0 || iconHeight == 0)
throw new InvalidImageException (
String.format ("Invalid icon: Height: %d, Width: %d", iconHeight, iconWidth));
2019-08-25 04:16:36 +00:00
if (iconType != 0 && iconType != 0x8000 && iconType != 0xFFFF && iconType != 0x00FF)
2019-08-21 00:31:11 +00:00
throw new InvalidImageException (String.format ("Bad icon type: %04X", iconType));
2019-11-07 03:06:09 +00:00
// have also seen 0x7FFF and 0x8001
2019-08-21 00:31:11 +00:00
2017-01-23 10:02:02 +00:00
iconImage = new byte[iconSize];
iconMask = new byte[iconSize];
colour = (iconType & 0x80) != 0;
2015-06-01 09:35:51 +00:00
2017-01-23 10:02:02 +00:00
System.arraycopy (buffer, ptr + 8, iconImage, 0, iconSize);
System.arraycopy (buffer, ptr + 8 + iconSize, iconMask, 0, iconSize);
2017-01-23 06:56:42 +00:00
2019-08-25 04:16:36 +00:00
int[] colours = HiResImage.getPaletteFactory ().get (0).getColours ();
2017-01-23 06:56:42 +00:00
image = new BufferedImage (iconWidth, iconHeight, BufferedImage.TYPE_INT_RGB);
2017-01-23 10:02:02 +00:00
2017-01-23 06:56:42 +00:00
DataBuffer dataBuffer = image.getRaster ().getDataBuffer ();
int element = 0;
int rowBytes = (iconWidth - 1) / 2 + 1;
2017-01-23 10:02:02 +00:00
if (true)
for (int i = 0; i < iconImage.length; i += rowBytes)
2017-01-23 06:56:42 +00:00
{
2017-01-24 08:59:40 +00:00
int max = Math.min (i + rowBytes, dataBuffer.getSize ());
for (int j = i; j < max; j++)
2017-01-23 10:02:02 +00:00
{
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);
2017-01-24 08:59:40 +00:00
// 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]);
}
2017-01-23 10:02:02 +00:00
}
2017-01-23 06:56:42 +00:00
}
2015-06-01 09:35:51 +00:00
}
2019-11-07 03:06:09 +00:00
// -------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
public int size ()
2019-11-07 03:06:09 +00:00
// -------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
return 8 + iconSize * 2;
}
2019-11-07 03:06:09 +00:00
// -------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
@Override
public String toString ()
2019-11-07 03:06:09 +00:00
// -------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
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));
2017-01-23 10:02:02 +00:00
appendIcon (text, iconImage);
2015-06-01 09:35:51 +00:00
text.append ("\n\n");
2017-01-23 10:02:02 +00:00
appendIcon (text, iconMask);
2015-06-01 09:35:51 +00:00
return text.toString ();
}
/*
Offset Color RGB Mini-Palette
2019-11-04 21:07:20 +00:00
2015-06-01 09:35:51 +00:00
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
2019-11-04 21:07:20 +00:00
2015-06-01 09:35:51 +00:00
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
2019-11-04 21:07:20 +00:00
2015-06-01 09:35:51 +00:00
The displayMode word bits are defined as:
2019-11-04 21:07:20 +00:00
2015-06-01 09:35:51 +00:00
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
2019-11-04 21:07:20 +00:00
2015-06-01 09:35:51 +00:00
Bits 0-2 can occur at once and are tested in the order 1-2-0.
2019-11-04 21:07:20 +00:00
2015-06-01 09:35:51 +00:00
"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."
*/
2019-11-07 03:06:09 +00:00
// -------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
private void appendIcon (StringBuilder text, byte[] buffer)
2019-11-07 03:06:09 +00:00
// -------------------------------------------------------------------------------//
2015-06-01 09:35:51 +00:00
{
2017-01-22 00:01:15 +00:00
int rowBytes = (iconWidth - 1) / 2 + 1;
2017-01-23 10:02:02 +00:00
for (int i = 0; i < iconImage.length; i += rowBytes)
2015-06-01 09:35:51 +00:00
{
for (int ptr = i, max = i + rowBytes; ptr < max; ptr++)
{
2017-01-22 00:01:15 +00:00
int left = (byte) ((buffer[ptr] & 0xF0) >>> 4);
2015-06-01 09:35:51 +00:00
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);
}
}
2019-08-21 00:31:11 +00:00
2019-11-07 03:06:09 +00:00
// ---------------------------------------------------------------------------------//
2019-08-21 00:31:11 +00:00
class InvalidImageException extends Exception
2019-11-07 03:06:09 +00:00
// ---------------------------------------------------------------------------------//
2019-08-21 00:31:11 +00:00
{
2019-11-07 03:06:09 +00:00
// -------------------------------------------------------------------------------//
2019-08-21 00:31:11 +00:00
public InvalidImageException (String message)
2019-11-07 03:06:09 +00:00
// -------------------------------------------------------------------------------//
2019-08-21 00:31:11 +00:00
{
super (message);
}
}
2015-06-01 09:35:51 +00:00
}