/* * AppleCommander - An Apple ][ image utility. * Copyright (C) 2002-3 by Robert Greene * robgreene at users.sourceforge.net * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.webcodepro.applecommander.storage.filters; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import com.webcodepro.applecommander.storage.FileEntry; import com.webcodepro.applecommander.storage.FileFilter; import com.webcodepro.applecommander.storage.filters.imagehandlers.AppleImage; import com.webcodepro.applecommander.util.AppleUtil; /** * Filter the given file as if it were a graphics image. *
* Address for Apple2 HGR/DHR address is calculated from an observation of a pattern:
* line number bits: 87654321
* 87 are multiplied by 0x0028
* 65 are multiplied by 0x0100
* 4 is multiplied by 0x0080
* 321 are multiplied by 0x0400
*
* HGR bit values ignore the high bit, as that switches the "palette", and for B&W mode, * the bit does nothing. The other 7 bits simply toggle the pixel on or off. Double hires * does not follow this - it uses a real 4 bit value, but the high bit is still ignored for * graphics (hence, the 560 instead of 640 resolution). *
* SHR has been implemented in "16 color" mode as well as 3200 color mode. Note that * 16 color mode is really 16 palettes of 16 colors while 3200 color mode is 200 * palettes of 16 colors (one palette per line). *
* NOTE: The design is feeling kludgy. There are 6 distinct variations - possibly a * subclass is needed to interpret the various graphic image or some such redesign. *
* Date created: Nov 3, 2002 12:06:36 PM
* @author Rob Greene
*/
public class GraphicsFileFilter implements FileFilter {
public static final int MODE_HGR_BLACK_AND_WHITE = 1;
public static final int MODE_HGR_COLOR = 2;
public static final int MODE_DHR_BLACK_AND_WHITE = 3;
public static final int MODE_DHR_COLOR = 4;
public static final int MODE_SHR_16 = 5;
public static final int MODE_SHR_3200 = 6;
public static final int MODE_QUICKDRAW2_ICON = 7;
private int mode = MODE_HGR_COLOR;
private static AppleImage referenceImage = AppleImage.create(1,1);
/**
* Constructor for GraphicsFileFilter.
*/
public GraphicsFileFilter() {
super();
}
/**
* Indicate if a codec is available (assist with interface requirements).
*/
public static boolean isCodecAvailable() {
return referenceImage != null;
}
/**
* Filter the file data and produce an image.
* @see com.webcodepro.applecommander.storage.FileFilter#filter(FileEntry)
*/
public byte[] filter(FileEntry fileEntry) {
byte[] fileData = fileEntry.getFileData();
AppleImage image = null;
if (isHiresColorMode()) {
image = AppleImage.create(280, 192);
} else if (isDoubleHiresMode()) {
image = AppleImage.create(560, 192*2);
} else if (isSuperHiresMode()) {
image = AppleImage.create(640, 400);
} else if (isQuickDraw2Icon()) {
// Build later...
} else {
return new byte[0];
}
if (isQuickDraw2Icon()) {
AppleImage[] icons = buildQuickDraw2Icons(fileEntry);
int width = 0;
for (int i=0; i
* The names of pixels is a bit confusion - pixel0 is really the left-most
* pixel (not the low-value bit).
* To alleviate my bad naming, here is a color table to assist:
* From the Apple2
* technical note:
*
* The color map varies depending upon the SCB value(s) and the pallettes
* stored with the image. The SCB does not apple to 3200 SHR mode!
*
*/
protected void processSuperHiresLine(byte[] lineData,
AppleImage image, int y, byte scb, byte[] pallettes) {
int palletteNumber = (scb & 0x0f);
boolean fillMode = (scb & 0x20) != 0;
boolean mode320 = (scb & 0x80) == 0;
if (isSuperHires3200Mode()) {
int numPallettes = pallettes.length / 32;
palletteNumber = y % numPallettes;
fillMode = false; // never
mode320 = true; // always
}
int width = mode320 ? 320 : 640;
int yPosition = y*2;
int lastColorValue = 0;
for (int x=0; x
* @see File Types
*/
public AppleImage[] buildQuickDraw2Icons(FileEntry fileEntry) {
List
*
* Color Bits RGB
* ======= ==== ========
* Black1 000 0x000000
* Green 001 0x00ff00
* Violet 010 0xff00ff
* White1 011 0xffffff
* Black2 100 0x000000
* Orange 101 0xff8000
* Blue 110 0x0000ff
* White2 111 0xffffff
*
* Remember: bits are listed as "highbit", "pixel0", "pixel1"!
*/
protected void processHiresColorLine(byte[] lineData, AppleImage image, int y) {
for (int x=0; x<140; x++) {
int x0 = x*2;
int x1 = x0+1;
int offset0 = x0 / 7; // byte across row
int bit0 = x0 % 7; // bit to test
boolean pixel0 = AppleUtil.isBitSet(lineData[offset0], bit0);
int offset1 = x1 / 7; // byte across row
int bit1 = x1 % 7; // bit to test
boolean pixel1 = AppleUtil.isBitSet(lineData[offset1], bit1);
int color;
if (pixel0 && pixel1) {
color = 0xffffff; // white
} else if (!pixel0 && !pixel1) {
color = 0; // black
} else {
boolean highbit = pixel0 ? AppleUtil.isBitSet(lineData[offset0], 7) :
AppleUtil.isBitSet(lineData[offset1], 7);
if (pixel0 && highbit) {
color = 0x0000ff; // blue
} else if (pixel0 && !highbit) {
color = 0xff00ff; // violet
} else if (pixel1 && !highbit) {
color = 0x00ff00; // green
} else { // pixel1 && highbit
color = 0xff8000; // orange
}
}
if (pixel0) image.setPoint(x0, y, color);
if (pixel1) image.setPoint(x1, y, color);
}
}
/**
* Given a specific line in the image, process it in double hires black and white
* mode.
*/
protected void processDoubleHiresBlackAndWhiteLine(byte[] lineData1, byte[] lineData2,
AppleImage image, int y) {
for (int x=0; x<560; x++) {
// alternate bytes - switching memory banks
byte[] lineData = (x % 14 < 7) ? lineData1 : lineData2;
int rowOffset = x / 14; // byte across row
int bit = x % 7; // bit to test
byte byt = lineData[rowOffset];
if (AppleUtil.isBitSet(byt, bit)) {
image.setPoint(x, y*2, 0xffffff);
image.setPoint(x, y*2+1, 0xffffff);
} else {
image.setPoint(x, y*2, 0x0);
image.setPoint(x, y*2+1, 0x0);
}
}
}
/**
* Given a specific line in the image, process it in double hires color
* mode. Treat image as 140x192 mode.
*
* Repeated
*/
protected void processDoubleHiresColorLine(byte[] lineData1, byte[] lineData2,
AppleImage image, int y) {
int[] bitValues = { 8,4,2,1 };
int[] colorValues = {
0x000000, 0xff0000, 0x800000, 0xff8000, // black, magenta, brown, orange
0x008000, 0x808080, 0x00ff00, 0xffff00, // dark green, grey1, green, yellow
0x000080, 0xff00ff, 0x808080, 0xff80c0, // dark blue, violet, grey2, pink
0x0000a0, 0x0000ff, 0x00c080, 0xffffff // medium blue, light blue, aqua, white
};
for (int x=0; x<560; x+=4) {
int colorValue = 0;
for (int b = 0; b < 4; b++) {
int xb = x+b;
// alternate bytes - switching memory banks
byte[] lineData = (xb % 14 < 7) ? lineData1 : lineData2;
int rowOffset = xb / 14; // byte across row
int bit = xb % 7; // bit to test
byte byt = lineData[rowOffset];
if (AppleUtil.isBitSet(byt, bit)) {
colorValue+= bitValues[b];
}
}
for (int b = 0; b < 4; b++) {
image.setPoint(x+b, y*2, colorValues[colorValue]);
image.setPoint(x+b, y*2+1, colorValues[colorValue]);
}
}
}
/**
* Given a specific line in the image, process it in super hires color
* mode.
*
* Binary
* Color aux1 main1 aux2 main2 Pattern
* Black 00 00 00 00 0000
* Magenta 08 11 22 44 0001
* Brown 44 08 11 22 0010
* Orange 4C 19 33 66 0011
* Dark Green 22 44 08 11 0100
* Grey1 2A 55 2A 55 0101
* Green 66 4C 19 33 0110
* Yellow 6E 5D 3B 77 0111
* Dark Blue 11 22 44 08 1000
* Violet 19 33 66 4C 1001
* Grey2 55 2A 55 2A 1010
* Pink 5D 3B 77 6E 1011
* Medium Blue 33 66 4C 19 1100
* Light Blue 3B 77 6E 5D 1101
* Aqua 77 6E 5D 3B 1110
* White 7F 7F 7F 7F 1111
*