mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-04 03:55:28 -04:00
#423: Finally fixed region parsing to Area (seems to work, but slow)!
Bonus: Implemented more transfer modes, better QT parsing/debug output.
This commit is contained in:
parent
5c8b4e0edf
commit
ce7fb1cb94
@ -332,7 +332,7 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
*
|
*
|
||||||
* @param pGraphics the graphics object to draw onto.
|
* @param pGraphics the graphics object to draw onto.
|
||||||
*
|
*
|
||||||
* @throws javax.imageio.IIOException if the data can not be read.
|
* @throws IIOException if the data can not be read.
|
||||||
* @throws IOException if an I/O error occurs while reading the image.
|
* @throws IOException if an I/O error occurs while reading the image.
|
||||||
*/
|
*/
|
||||||
private void drawOnto(Graphics2D pGraphics) throws IOException {
|
private void drawOnto(Graphics2D pGraphics) throws IOException {
|
||||||
@ -351,8 +351,8 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
*
|
*
|
||||||
* @param pStream the stream to read from
|
* @param pStream the stream to read from
|
||||||
*
|
*
|
||||||
* @throws javax.imageio.IIOException if the data can not be read.
|
* @throws IIOException if the data can not be read.
|
||||||
* @throws java.io.IOException if an I/O error occurs while reading the image.
|
* @throws IOException if an I/O error occurs while reading the image.
|
||||||
*/
|
*/
|
||||||
private void readPICTopcodes(ImageInputStream pStream) throws IOException {
|
private void readPICTopcodes(ImageInputStream pStream) throws IOException {
|
||||||
pStream.seek(imageStartStreamPos);
|
pStream.seek(imageStartStreamPos);
|
||||||
@ -371,7 +371,7 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
String text;
|
String text;
|
||||||
Rectangle bounds = new Rectangle();
|
Rectangle bounds = new Rectangle();
|
||||||
Polygon polygon = new Polygon();
|
Polygon polygon = new Polygon();
|
||||||
Polygon region = new Polygon();
|
Area region = new Area();
|
||||||
int pixmapCount = 0;
|
int pixmapCount = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -1312,27 +1312,27 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
case PICT.OP_INVERT_SAME_RGN:// OK, not tested
|
case PICT.OP_INVERT_SAME_RGN:// OK, not tested
|
||||||
case PICT.OP_FILL_SAME_RGN:// OK, not tested
|
case PICT.OP_FILL_SAME_RGN:// OK, not tested
|
||||||
// Draw
|
// Draw
|
||||||
if (region != null && region.npoints > 1) {
|
if (region != null && !region.getBounds().isEmpty()) {
|
||||||
switch (opCode) {
|
switch (opCode) {
|
||||||
case PICT.OP_FRAME_RGN:
|
case PICT.OP_FRAME_RGN:
|
||||||
case PICT.OP_FRAME_SAME_RGN:
|
case PICT.OP_FRAME_SAME_RGN:
|
||||||
context.frameRegion(new Area(region));
|
context.frameRegion(region);
|
||||||
break;
|
break;
|
||||||
case PICT.OP_PAINT_RGN:
|
case PICT.OP_PAINT_RGN:
|
||||||
case PICT.OP_PAINT_SAME_RGN:
|
case PICT.OP_PAINT_SAME_RGN:
|
||||||
context.paintRegion(new Area(region));
|
context.paintRegion(region);
|
||||||
break;
|
break;
|
||||||
case PICT.OP_ERASE_RGN:
|
case PICT.OP_ERASE_RGN:
|
||||||
case PICT.OP_ERASE_SAME_RGN:
|
case PICT.OP_ERASE_SAME_RGN:
|
||||||
context.eraseRegion(new Area(region));
|
context.eraseRegion(region);
|
||||||
break;
|
break;
|
||||||
case PICT.OP_INVERT_RGN:
|
case PICT.OP_INVERT_RGN:
|
||||||
case PICT.OP_INVERT_SAME_RGN:
|
case PICT.OP_INVERT_SAME_RGN:
|
||||||
context.invertRegion(new Area(region));
|
context.invertRegion(region);
|
||||||
break;
|
break;
|
||||||
case PICT.OP_FILL_RGN:
|
case PICT.OP_FILL_RGN:
|
||||||
case PICT.OP_FILL_SAME_RGN:
|
case PICT.OP_FILL_SAME_RGN:
|
||||||
context.fillRegion(new Area(region), fill);
|
context.fillRegion(region, fill);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1395,29 +1395,10 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
// map replaces the bitmap, a color table has been added, and pixData replaces bitData.
|
// map replaces the bitmap, a color table has been added, and pixData replaces bitData.
|
||||||
// [5] For opcodes $0090 (BitsRect) and $0091 (BitsRgn), the data is unpacked. These
|
// [5] For opcodes $0090 (BitsRect) and $0091 (BitsRgn), the data is unpacked. These
|
||||||
// opcodes can be used only when rowBytes is less than 8.
|
// opcodes can be used only when rowBytes is less than 8.
|
||||||
/*
|
|
||||||
pixMap: PixMap; {pixel map}
|
|
||||||
ColorTable: ColorTable; {ColorTable record}
|
|
||||||
srcRect: Rect; {source rectangle}
|
|
||||||
dstRect: Rect; {destination rectangle}
|
|
||||||
mode: Word; {transfer mode (may include }
|
|
||||||
{ new transfer modes)}
|
|
||||||
pixData: PixData;
|
|
||||||
*/
|
|
||||||
readOpBits(pStream, false);
|
readOpBits(pStream, false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PICT.OP_BITS_RGN:
|
case PICT.OP_BITS_RGN:
|
||||||
/*
|
|
||||||
pixMap: PixMap;
|
|
||||||
colorTable: ColorTable;
|
|
||||||
srcRect: Rect; {source rectangle}
|
|
||||||
dstRect: Rect; {destination rectangle}
|
|
||||||
mode: Word; {transfer mode (may }
|
|
||||||
{ include new modes)}
|
|
||||||
maskRgn: Rgn; {region for masking}
|
|
||||||
pixData: PixData;
|
|
||||||
*/
|
|
||||||
readOpBits(pStream, true);
|
readOpBits(pStream, true);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -1486,10 +1467,6 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
case PICT.OP_COMPRESSED_QUICKTIME:
|
case PICT.OP_COMPRESSED_QUICKTIME:
|
||||||
// $8200: CompressedQuickTime Data length (Long), data (private to QuickTime) 4 + data length
|
// $8200: CompressedQuickTime Data length (Long), data (private to QuickTime) 4 + data length
|
||||||
if (DEBUG) {
|
|
||||||
System.out.println("compressedQuickTime");
|
|
||||||
}
|
|
||||||
|
|
||||||
readCompressedQT(pStream);
|
readCompressedQT(pStream);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -1585,43 +1562,56 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
int dataLength = pStream.readInt();
|
int dataLength = pStream.readInt();
|
||||||
long pos = pStream.getStreamPosition();
|
long pos = pStream.getStreamPosition();
|
||||||
|
|
||||||
if (DEBUG) {
|
int version = pStream.readUnsignedShort();
|
||||||
System.out.println("QT data length: " + dataLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Need to figure out what the skipped data is?
|
|
||||||
for (int i = 0; i < 13; i++) {
|
|
||||||
int value = pStream.readInt();
|
|
||||||
if (DEBUG) {
|
|
||||||
System.out.println(String.format("%2d: 0x%08x", i * 4, value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the destination rectangle
|
|
||||||
Rectangle destination = new Rectangle();
|
|
||||||
readRectangle(pStream, destination);
|
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
System.out.println("...");
|
System.out.print("compressedQuickTime");
|
||||||
|
System.out.println(", size: " + dataLength + ", version: " + version);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 2; i++) {
|
// Matrix
|
||||||
int value = pStream.readInt();
|
int[] matrix = new int[9];
|
||||||
if (DEBUG) {
|
for (int i = 0; i < matrix.length; i++) {
|
||||||
System.out.println(String.format("%2d: 0x%08x", (i + 15) * 4, value));
|
matrix[i] = pStream.readInt();
|
||||||
}
|
}
|
||||||
|
if (DEBUG) {
|
||||||
|
System.out.println(String.format("matrix: %s", Arrays.toString(matrix)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Matte
|
||||||
|
long matteSize = pStream.readUnsignedInt();
|
||||||
|
Rectangle matteRect = new Rectangle();
|
||||||
|
readRectangle(pStream, matteRect);
|
||||||
|
|
||||||
|
// Transfer mode
|
||||||
|
int mode = pStream.readUnsignedShort();
|
||||||
|
|
||||||
|
// Read the source rectangle
|
||||||
|
Rectangle srcRect = new Rectangle();
|
||||||
|
readRectangle(pStream, srcRect);
|
||||||
|
|
||||||
|
// ...and more
|
||||||
|
int accuracy = pStream.readInt();
|
||||||
|
int maskSize = pStream.readInt();
|
||||||
|
|
||||||
|
if (DEBUG) {
|
||||||
|
System.out.print("matteSize: " + matteSize);
|
||||||
|
System.out.print(", matteRect: " + matteRect);
|
||||||
|
System.out.print(", mode: " + mode);
|
||||||
|
System.out.print(", srcRect: " + srcRect);
|
||||||
|
System.out.print(", accuracy: " + accuracy);
|
||||||
|
System.out.println(", maskSize: " + maskSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferedImage image = QuickTime.decompress(pStream);
|
BufferedImage image = QuickTime.decompress(pStream);
|
||||||
|
|
||||||
if (image != null) {
|
if (image != null) {
|
||||||
context.copyBits(image, new Rectangle(image.getWidth(), image.getHeight()), destination, QuickDraw.SRC_COPY, null);
|
context.copyBits(image, srcRect, srcRect, mode, null);
|
||||||
|
|
||||||
pStream.seek(pos + dataLength); // Might be word-align mismatch here
|
pStream.seek(pos + dataLength); // Might be word-align mismatch here
|
||||||
|
|
||||||
// Skip "QuickTime™ and a ... decompressor required" text
|
// Skip "QuickTime™ and a ... decompressor required" text
|
||||||
// TODO: Verify that this is correct. It works with all my test data, but the algorithm is
|
// NOTE: This algorithm is reverse-engineered by looking at various test inputs and not from any spec...
|
||||||
// reverse-engineered by looking at the input data and not from any spec I've seen...
|
|
||||||
int penSizeMagic = pStream.readInt();
|
int penSizeMagic = pStream.readInt();
|
||||||
if (penSizeMagic == 0x000700ae) { // OP_PN_SIZE + bogus x value..?
|
if (penSizeMagic == 0x000700ae) { // OP_PN_SIZE + bogus x value..?
|
||||||
int skip = pStream.readUnsignedShort(); // bogus y value is the number of bytes to skip
|
int skip = pStream.readUnsignedShort(); // bogus y value is the number of bytes to skip
|
||||||
@ -1803,10 +1793,15 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle regionBounds = new Rectangle();
|
Rectangle regionBounds = new Rectangle();
|
||||||
Polygon region = hasRegion ? readRegion(pStream, regionBounds) : null;
|
Area region = hasRegion ? readRegion(pStream, regionBounds) : null;
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
System.out.println(hasRegion ? ", region: " + region : "" );
|
if (hasRegion) {
|
||||||
|
verboseRegionCmd(", region", regionBounds, region);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up pixel buffer for the RGB values
|
// Set up pixel buffer for the RGB values
|
||||||
@ -1882,8 +1877,7 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
BufferedImage img = images.get(pPixmapCount);
|
BufferedImage img = images.get(pPixmapCount);
|
||||||
if (img != null) {
|
if (img != null) {
|
||||||
srcRect.setLocation(0, 0); // Raster always start at 0,0
|
srcRect.setLocation(0, 0); // Raster always start at 0,0
|
||||||
// dstRect.translate(-frame.x, -frame.y);
|
context.copyBits(img, srcRect, dstRect, transferMode, region);
|
||||||
context.copyBits(img, srcRect, dstRect, transferMode, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Line break at the end
|
// Line break at the end
|
||||||
@ -1899,8 +1893,8 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
* @param pPixmapCount the index of the bitmap in the PICT file, used for
|
* @param pPixmapCount the index of the bitmap in the PICT file, used for
|
||||||
* cahcing.
|
* cahcing.
|
||||||
*
|
*
|
||||||
* @throws javax.imageio.IIOException if the data can not be read.
|
* @throws IIOException if the data can not be read.
|
||||||
* @throws java.io.IOException if an I/O error occurs while reading the image.
|
* @throws IOException if an I/O error occurs while reading the image.
|
||||||
*/
|
*/
|
||||||
private void readOpDirectBits(final ImageInputStream pStream, final boolean hasRegion, final int pPixmapCount) throws IOException {
|
private void readOpDirectBits(final ImageInputStream pStream, final boolean hasRegion, final int pPixmapCount) throws IOException {
|
||||||
// Skip PixMap pointer (always 0x000000FF);
|
// Skip PixMap pointer (always 0x000000FF);
|
||||||
@ -2039,7 +2033,7 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
System.out.print(", mode: " + transferMode);
|
System.out.print(", mode: " + transferMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
Polygon region = hasRegion ? readRegion(pStream, new Rectangle()) : null;
|
Area region = hasRegion ? readRegion(pStream, new Rectangle()) : null;
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
System.out.println(hasRegion ? ", region: " + region : "");
|
System.out.println(hasRegion ? ", region: " + region : "");
|
||||||
@ -2196,8 +2190,7 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
BufferedImage img = images.get(pPixmapCount);
|
BufferedImage img = images.get(pPixmapCount);
|
||||||
if (img != null) {
|
if (img != null) {
|
||||||
srcRect.setLocation(0, 0); // Raster always starts at 0,0
|
srcRect.setLocation(0, 0); // Raster always starts at 0,0
|
||||||
// dstRect.translate(-frame.x, -frame.y);
|
context.copyBits(img, srcRect, dstRect, transferMode, region);
|
||||||
context.copyBits(img, srcRect, dstRect, transferMode, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Line break at the end
|
// Line break at the end
|
||||||
@ -2206,6 +2199,16 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
pixMap: PixMap;
|
||||||
|
colorTable: ColorTable;
|
||||||
|
srcRect: Rect; {source rectangle}
|
||||||
|
dstRect: Rect; {destination rectangle}
|
||||||
|
mode: Word; {transfer mode (may }
|
||||||
|
{ include new modes)}
|
||||||
|
maskRgn: Rgn; {region for masking}
|
||||||
|
pixData: PixData;
|
||||||
|
*/
|
||||||
private void readOpBits(ImageInputStream pStream, boolean hasRegion) throws IOException {
|
private void readOpBits(ImageInputStream pStream, boolean hasRegion) throws IOException {
|
||||||
// Get rowBytes
|
// Get rowBytes
|
||||||
int rowBytesRaw = pStream.readUnsignedShort();
|
int rowBytesRaw = pStream.readUnsignedShort();
|
||||||
@ -2323,7 +2326,7 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
// Get transfer mode
|
// Get transfer mode
|
||||||
int mode = pStream.readUnsignedShort();
|
int mode = pStream.readUnsignedShort();
|
||||||
|
|
||||||
Polygon region = hasRegion ? readRegion(pStream, new Rectangle()) : null;
|
Area region = hasRegion ? readRegion(pStream, new Rectangle()) : null;
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
System.out.print(", bounds: " + bounds);
|
System.out.print(", bounds: " + bounds);
|
||||||
@ -2347,8 +2350,7 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
// Draw pixel data
|
// Draw pixel data
|
||||||
srcRect.setLocation(0, 0); // Raster always start at 0,0
|
srcRect.setLocation(0, 0); // Raster always start at 0,0
|
||||||
// dstRect.translate(-frame.x, -frame.y);
|
context.copyBits(image, srcRect, dstRect, mode, region);
|
||||||
context.copyBits(image, srcRect, dstRect, mode, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2368,84 +2370,90 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
pDestRect.setLocation(getXPtCoord(x), getYPtCoord(y));
|
pDestRect.setLocation(getXPtCoord(x), getYPtCoord(y));
|
||||||
pDestRect.setSize(getXPtCoord(w - x), getYPtCoord(h - y));
|
pDestRect.setSize(getXPtCoord(w - x), getYPtCoord(h - y));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read in a region. The input stream should be positioned at the first byte
|
* Read in a region. The input stream should be positioned at the first byte
|
||||||
* of the region. {@code pBoundsRect} is a rectangle that will be set to the
|
* of the region. {@code pBounds} is a rectangle that will be set to the
|
||||||
* region bounds.
|
* region bounds.
|
||||||
* The point array may therefore be empty if the region is just a rectangle.
|
* The point array may therefore be empty if the region is just a rectangle.
|
||||||
*
|
*
|
||||||
* @param pStream the stream to read from
|
* @param pStream the stream to read from
|
||||||
* @param pBoundsRect the bounds rectangle to read into
|
* @param pBounds the bounds rectangle to read into
|
||||||
*
|
*
|
||||||
* @return the polygon containing the region, or an empty polygon if the
|
* @return the area containing the region, or an empty polygon if the
|
||||||
* region is a rectangle.
|
* region is a rectangle.
|
||||||
*
|
*
|
||||||
* @throws IOException if an I/O error occurs while reading the image.
|
* @throws IOException if an I/O error occurs while reading the image.
|
||||||
*/
|
*/
|
||||||
private Polygon readRegion(DataInput pStream, Rectangle pBoundsRect) throws IOException {
|
private Area readRegion(DataInput pStream, Rectangle pBounds) throws IOException {
|
||||||
// Get minimal region
|
|
||||||
|
|
||||||
// Get region data size
|
// Get region data size
|
||||||
int size = pStream.readUnsignedShort();
|
int size = pStream.readUnsignedShort();
|
||||||
|
|
||||||
// Get region bounds
|
// Get region bounds
|
||||||
int y = getYPtCoord(pStream.readShort());
|
readRectangle(pStream, pBounds);
|
||||||
int x = getXPtCoord(pStream.readShort());
|
|
||||||
pBoundsRect.setLocation(x, y);
|
|
||||||
|
|
||||||
y = getYPtCoord(pStream.readShort()) - pBoundsRect.getLocation().y;
|
|
||||||
x = getXPtCoord(pStream.readShort()) - pBoundsRect.getLocation().x;
|
|
||||||
pBoundsRect.setSize(x, y);
|
|
||||||
|
|
||||||
Polygon polygon = new Polygon();
|
|
||||||
int count = (size - 10) / 2;
|
int count = (size - 10) / 2;
|
||||||
boolean nextIsV = true;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
if (count == 0) {
|
||||||
short point = pStream.readShort();
|
// Minimal region, just the bounds
|
||||||
|
return new Area(pBounds);
|
||||||
if (nextIsV) {
|
|
||||||
if (point == 0x7fff) {
|
|
||||||
// Done
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
y = point;
|
|
||||||
nextIsV = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (point == 0x7fff) {
|
|
||||||
nextIsV = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
x = point;
|
|
||||||
polygon.addPoint(x, y);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
// Normal region, parse inversion points and build area
|
||||||
|
Area area = new Area();
|
||||||
|
|
||||||
return polygon;
|
boolean nextIsVertical = true;
|
||||||
|
|
||||||
|
int x, y = 0;
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
short point = pStream.readShort();
|
||||||
|
|
||||||
|
if (nextIsVertical) {
|
||||||
|
if (point == 0x7fff) {
|
||||||
|
// Done
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
y = point;
|
||||||
|
nextIsVertical = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (point == 0x7fff) {
|
||||||
|
nextIsVertical = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = point;
|
||||||
|
area.exclusiveOr(new Area(new Rectangle(x, y, pBounds.x + pBounds.width - x, pBounds.y + pBounds.height - y)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pBounds.contains(area.getBounds())) {
|
||||||
|
processWarningOccurred("Bad region, contains point(s) out of bounds " + pBounds + ": " + area);
|
||||||
|
}
|
||||||
|
|
||||||
|
return area;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* Read in a polygon. The input stream should be positioned at the first byte
|
* Read in a polygon. The input stream should be positioned at the first byte
|
||||||
* of the polygon.
|
* of the polygon.
|
||||||
|
*
|
||||||
|
* @param pStream the stream to read from
|
||||||
|
* @param pBounds the bounds rectangle to read into
|
||||||
|
*
|
||||||
|
* @return the polygon
|
||||||
|
*
|
||||||
|
* @throws IOException if an I/O error occurs while reading the image.
|
||||||
*/
|
*/
|
||||||
private Polygon readPoly(DataInput pStream, Rectangle pBoundsRect) throws IOException {
|
private Polygon readPoly(DataInput pStream, Rectangle pBounds) throws IOException {
|
||||||
// Get polygon data size
|
// Get polygon data size
|
||||||
int size = pStream.readUnsignedShort();
|
int size = pStream.readUnsignedShort();
|
||||||
|
|
||||||
// Get poly bounds
|
// Get poly bounds
|
||||||
int y = getYPtCoord(pStream.readShort());
|
readRectangle(pStream, pBounds);
|
||||||
int x = getXPtCoord(pStream.readShort());
|
|
||||||
pBoundsRect.setLocation(x, y);
|
|
||||||
|
|
||||||
y = getYPtCoord(pStream.readShort()) - pBoundsRect.getLocation().y;
|
|
||||||
x = getXPtCoord(pStream.readShort()) - pBoundsRect.getLocation().x;
|
|
||||||
pBoundsRect.setSize(x, y);
|
|
||||||
|
|
||||||
// Initialize the point array to the right size
|
// Initialize the point array to the right size
|
||||||
int points = (size - 10) / 4;
|
int points = (size - 10) / 4;
|
||||||
@ -2454,11 +2462,15 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
Polygon polygon = new Polygon();
|
Polygon polygon = new Polygon();
|
||||||
|
|
||||||
for (int i = 0; i < points; i++) {
|
for (int i = 0; i < points; i++) {
|
||||||
y = getYPtCoord(pStream.readShort());
|
int y = getYPtCoord(pStream.readShort());
|
||||||
x = getXPtCoord(pStream.readShort());
|
int x = getXPtCoord(pStream.readShort());
|
||||||
polygon.addPoint(x, y);
|
polygon.addPoint(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!pBounds.contains(polygon.getBounds())) {
|
||||||
|
processWarningOccurred("Bad poly, contains point(s) out of bounds " + pBounds + ": " + polygon);
|
||||||
|
}
|
||||||
|
|
||||||
return polygon;
|
return polygon;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2540,15 +2552,15 @@ public final class PICTImageReader extends ImageReaderBase {
|
|||||||
/*
|
/*
|
||||||
* Write out region command, bounds and points.
|
* Write out region command, bounds and points.
|
||||||
*/
|
*/
|
||||||
private void verboseRegionCmd(String pCmd, Rectangle pBounds, Polygon pPolygon) {
|
private void verboseRegionCmd(String pCmd, Rectangle pBounds, Area pRegion) {
|
||||||
System.out.println(pCmd + ": " + pBounds);
|
System.out.println(pCmd + ": " + pBounds);
|
||||||
System.out.print("Region points: ");
|
// System.out.print("Region points: ");
|
||||||
if (pPolygon != null && pPolygon.npoints > 0) {
|
// if (pPolygon != null && pPolygon.npoints > 0) {
|
||||||
System.out.print("(" + pPolygon.xpoints[0] + "," + pPolygon.ypoints[0] + ")");
|
// System.out.print("(" + pPolygon.xpoints[0] + "," + pPolygon.ypoints[0] + ")");
|
||||||
}
|
// }
|
||||||
for (int i = 1; pPolygon != null && i < pPolygon.npoints; i++) {
|
// for (int i = 1; pPolygon != null && i < pPolygon.npoints; i++) {
|
||||||
System.out.print(", (" + pPolygon.xpoints[i] + "," + pPolygon.ypoints[i] + ")");
|
// System.out.print(", (" + pPolygon.xpoints[i] + "," + pPolygon.ypoints[i] + ")");
|
||||||
}
|
// }
|
||||||
System.out.println();
|
System.out.println();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
78
imageio/imageio-pict/src/main/java/com/twelvemonkeys/imageio/plugins/pict/QuickDraw.java
Executable file → Normal file
78
imageio/imageio-pict/src/main/java/com/twelvemonkeys/imageio/plugins/pict/QuickDraw.java
Executable file → Normal file
@ -28,8 +28,9 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.pict;
|
package com.twelvemonkeys.imageio.plugins.pict;
|
||||||
|
|
||||||
import java.awt.image.*;
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.awt.image.DataBuffer;
|
||||||
|
import java.awt.image.IndexColorModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* QuickDraw constants.
|
* QuickDraw constants.
|
||||||
@ -61,6 +62,18 @@ interface QuickDraw {
|
|||||||
// http://developer.apple.com/documentation/mac/quickdraw/QuickDraw-196.html#HEADING196-2
|
// http://developer.apple.com/documentation/mac/quickdraw/QuickDraw-196.html#HEADING196-2
|
||||||
// http://developer.apple.com/documentation/mac/quickdraw/QuickDraw-269.html#HEADING269-2
|
// http://developer.apple.com/documentation/mac/quickdraw/QuickDraw-269.html#HEADING269-2
|
||||||
// See http://developer.apple.com/documentation/mac/quickdraw/QuickDraw-199.html#HEADING199-76 for color!
|
// See http://developer.apple.com/documentation/mac/quickdraw/QuickDraw-199.html#HEADING199-76 for color!
|
||||||
|
/*
|
||||||
|
Source mode Action on destination pixel
|
||||||
|
If source pixel is black If source pixel is white If source pixel is any other color
|
||||||
|
srcCopy Apply foreground color Apply background color Apply weighted portions of foreground and background colors
|
||||||
|
notSrcCopy Apply background color Apply foreground color Apply weighted portions of background and foreground colors
|
||||||
|
srcOr Apply foreground color Leave alone Apply weighted portions of foreground color
|
||||||
|
notSrcOr Leave alone Apply foreground color Apply weighted portions of foreground color
|
||||||
|
srcXor Invert (undefined for colored destination pixel) Leave alone Leave alone
|
||||||
|
notSrcXor Leave alone Invert (undefined for colored destination pixel) Leave alone
|
||||||
|
srcBic Apply background color Leave alone Apply weighted portions of background color
|
||||||
|
notSrcBic Leave alone Apply background color Apply weighted portions of background color
|
||||||
|
*/
|
||||||
int SRC_COPY = 0;
|
int SRC_COPY = 0;
|
||||||
int SRC_OR = 1;
|
int SRC_OR = 1;
|
||||||
int SRC_XOR = 2;
|
int SRC_XOR = 2;
|
||||||
@ -84,16 +97,73 @@ interface QuickDraw {
|
|||||||
|
|
||||||
// Arithmetic Transfer Modes
|
// Arithmetic Transfer Modes
|
||||||
// http://developer.apple.com/documentation/mac/quickdraw/QuickDraw-199.html#HEADING199-112
|
// http://developer.apple.com/documentation/mac/quickdraw/QuickDraw-199.html#HEADING199-112
|
||||||
|
/*
|
||||||
|
CONST
|
||||||
|
blend = 32; {replace destination pixel with a blend }
|
||||||
|
{ of the source and destination pixel }
|
||||||
|
{ colors; if the destination is a bitmap or }
|
||||||
|
{ 1-bit pixel map, revert to srcCopy mode}
|
||||||
|
addPin = 33; {replace destination pixel with the sum of }
|
||||||
|
{ the source and destination pixel colors-- }
|
||||||
|
{ up to a maximum allowable value; if }
|
||||||
|
{ the destination is a bitmap or }
|
||||||
|
{ 1-bit pixel map, revert to srcBic mode}
|
||||||
|
addOver = 34; {replace destination pixel with the sum of }
|
||||||
|
{ the source and destination pixel colors-- }
|
||||||
|
{ but if the value of the red, green, or }
|
||||||
|
{ blue component exceeds 65,536, then }
|
||||||
|
{ subtract 65,536 from that value; if the }
|
||||||
|
{ destination is a bitmap or 1-bit }
|
||||||
|
{ pixel map, revert to srcXor mode}
|
||||||
|
subPin = 35; {replace destination pixel with the }
|
||||||
|
{ difference of the source and destination }
|
||||||
|
{ pixel colors--but not less than a minimum }
|
||||||
|
{ allowable value; if the destination }
|
||||||
|
{ is a bitmap or 1-bit pixel map, revert to }
|
||||||
|
{ srcOr mode}
|
||||||
|
transparent = 36; {replace the destination pixel with the }
|
||||||
|
{ source pixel if the source pixel isn't }
|
||||||
|
{ equal to the background color}
|
||||||
|
addMax = 37; {compare the source and destination pixels, }
|
||||||
|
{ and replace the destination pixel with }
|
||||||
|
{ the color containing the greater }
|
||||||
|
{ saturation of each of the RGB components; }
|
||||||
|
{ if the destination is a bitmap or }
|
||||||
|
{ 1-bit pixel map, revert to srcBic mode}
|
||||||
|
subOver = 38; {replace destination pixel with the }
|
||||||
|
{ difference of the source and destination }
|
||||||
|
{ pixel colors--but if the value of a red, }
|
||||||
|
{ green, or blue component is }
|
||||||
|
{ less than 0, add the negative result to }
|
||||||
|
{ 65,536; if the destination is a bitmap or }
|
||||||
|
{ 1-bit pixel map, revert to srcXor mode}
|
||||||
|
adMin = 39; {compare the source and destination pixels, }
|
||||||
|
{ and replace the destination pixel with }
|
||||||
|
{ the color containing the lesser }
|
||||||
|
{ saturation of each of the RGB components; }
|
||||||
|
{ if the destination is a bitmap or }
|
||||||
|
{ 1-bit pixel map, revert to srcOr mode}
|
||||||
|
*/
|
||||||
int BLEND = 32; // dest = source weight/65,535 + destination (1 - weight/65,535)
|
int BLEND = 32; // dest = source weight/65,535 + destination (1 - weight/65,535)
|
||||||
int ADD_PIN = 33;
|
int ADD_PIN = 33;
|
||||||
int ADD_OVER = 34;
|
int ADD_OVER = 34;
|
||||||
int SUB_PIN = 35;
|
int SUB_PIN = 35;
|
||||||
int TRANSPARENT = 36;
|
int TRANSPARENT = 36;
|
||||||
int AD_MAX = 37;
|
int ADD_MAX = 37;
|
||||||
int SUB_OVER = 38;
|
int SUB_OVER = 38;
|
||||||
int AD_MIN = 39;
|
int ADD_MIN = 39;
|
||||||
|
|
||||||
|
// Transfer mode for text only
|
||||||
|
/*
|
||||||
|
If the destination device is color and grayishTextOr is the transfer mode,
|
||||||
|
QuickDraw draws with a blend of the foreground and background colors. If
|
||||||
|
the destination device is black and white, the grayishTextOr mode dithers
|
||||||
|
black and white.
|
||||||
|
|
||||||
|
Note that grayishTextOr is not considered a standard transfer mode because
|
||||||
|
currently it is not stored in pictures, and printing with it is undefined.
|
||||||
|
*/
|
||||||
int GRAYISH_TEXT_OR = 49;
|
int GRAYISH_TEXT_OR = 49;
|
||||||
// int MASK = 64; // ?! From Käry's code..
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Text face masks.
|
* Text face masks.
|
||||||
|
@ -0,0 +1,156 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.pict;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.image.ColorModel;
|
||||||
|
import java.awt.image.Raster;
|
||||||
|
import java.awt.image.WritableRaster;
|
||||||
|
|
||||||
|
import static java.lang.Math.max;
|
||||||
|
import static java.lang.Math.min;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QuickDrawComposite
|
||||||
|
*/
|
||||||
|
interface QuickDrawComposite extends Composite {
|
||||||
|
|
||||||
|
QuickDrawComposite NotSrcXor = new NotSrcXor();
|
||||||
|
QuickDrawComposite AddMax = new AddMax();
|
||||||
|
QuickDrawComposite AddMin = new AddMin();
|
||||||
|
|
||||||
|
class NotSrcXor implements QuickDrawComposite {
|
||||||
|
|
||||||
|
// TODO: Src can probably be any color model that can be encoded in PICT, dst is always RGB/TYPE_INT
|
||||||
|
public CompositeContext createContext(final ColorModel srcColorModel, final ColorModel dstColorModel, RenderingHints hints) {
|
||||||
|
{
|
||||||
|
if (!srcColorModel.getColorSpace().isCS_sRGB() || !dstColorModel.getColorSpace().isCS_sRGB()) {
|
||||||
|
throw new IllegalArgumentException("Only sRGB supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CompositeContext() {
|
||||||
|
public void dispose() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
|
||||||
|
int width = min(src.getWidth(), dstIn.getWidth());
|
||||||
|
|
||||||
|
// We always work in RGB, using DataBuffer.TYPE_INT transfer type.
|
||||||
|
int[] srcData = null;
|
||||||
|
int[] dstData = null;
|
||||||
|
int[] resData = new int[width - src.getMinX()];
|
||||||
|
|
||||||
|
for (int y = src.getMinY(); y < src.getHeight(); y++) {
|
||||||
|
srcData = (int[]) src.getDataElements(src.getMinX(), y, width, 1, srcData);
|
||||||
|
dstData = (int[]) dstIn.getDataElements(src.getMinX(), y, width, 1, dstData);
|
||||||
|
|
||||||
|
for (int x = src.getMinX(); x < width; x++) {
|
||||||
|
// TODO: Decide how to handle alpha (if at all)
|
||||||
|
resData[x] = 0xff000000 | ((~srcData[x] ^ dstData[x])) & 0xffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
dstOut.setDataElements(src.getMinX(), y, width, 1, resData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AddMax implements QuickDrawComposite {
|
||||||
|
// TODO: Src can probably be any color model that can be encoded in PICT, dst is always RGB/TYPE_INT
|
||||||
|
public CompositeContext createContext(final ColorModel srcColorModel, final ColorModel dstColorModel, RenderingHints hints) {
|
||||||
|
{
|
||||||
|
if (!srcColorModel.getColorSpace().isCS_sRGB() || !dstColorModel.getColorSpace().isCS_sRGB()) {
|
||||||
|
throw new IllegalArgumentException("Only sRGB supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CompositeContext() {
|
||||||
|
public void dispose() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
|
||||||
|
int width = min(src.getWidth(), dstIn.getWidth());
|
||||||
|
|
||||||
|
// We always work in RGB, using DataBuffer.TYPE_INT transfer type.
|
||||||
|
int[] srcData = null;
|
||||||
|
int[] dstData = null;
|
||||||
|
|
||||||
|
int[] resData = new int[width - src.getMinX()];
|
||||||
|
|
||||||
|
for (int y = src.getMinY(); y < src.getHeight(); y++) {
|
||||||
|
srcData = (int[]) src.getDataElements(src.getMinX(), y, width, 1, srcData);
|
||||||
|
dstData = (int[]) dstIn.getDataElements(src.getMinX(), y, width, 1, dstData);
|
||||||
|
|
||||||
|
for (int x = src.getMinX(); x < width; x++) {
|
||||||
|
int sAlpha = (srcData[x] >>> 24) & 0xFF;
|
||||||
|
int sRed = sAlpha * ((srcData[x] >> 16) & 0xFF) / 0xFF;
|
||||||
|
int sGreen = sAlpha * ((srcData[x] >> 8) & 0xFF) / 0xFF;
|
||||||
|
int sBlue = sAlpha * ((srcData[x]) & 0xFF) / 0xFF;
|
||||||
|
|
||||||
|
int dAlpha = (dstData[x] >>> 24) & 0xFF;
|
||||||
|
int dRed = dAlpha * ((dstData[x] >> 16) & 0xFF) / 0xFF;
|
||||||
|
int dGreen = dAlpha * ((dstData[x] >> 8) & 0xFF) / 0xFF;
|
||||||
|
int dBlue = dAlpha * ((dstData[x]) & 0xFF) / 0xFF;
|
||||||
|
|
||||||
|
resData[x] = (max(sAlpha, dAlpha) << 24)
|
||||||
|
| (max(sRed, dRed) << 16)
|
||||||
|
| (max(sGreen, dGreen) << 8)
|
||||||
|
| (max(sBlue, dBlue));
|
||||||
|
}
|
||||||
|
|
||||||
|
dstOut.setDataElements(src.getMinX(), y, width, 1, resData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AddMin implements QuickDrawComposite {
|
||||||
|
// TODO: Src can probably be any color model that can be encoded in PICT, dst is always RGB/TYPE_INT
|
||||||
|
public CompositeContext createContext(final ColorModel srcColorModel, final ColorModel dstColorModel, RenderingHints hints) {
|
||||||
|
{
|
||||||
|
if (!srcColorModel.getColorSpace().isCS_sRGB() || !dstColorModel.getColorSpace().isCS_sRGB()) {
|
||||||
|
throw new IllegalArgumentException("Only sRGB supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CompositeContext() {
|
||||||
|
public void dispose() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
|
||||||
|
int width = min(src.getWidth(), dstIn.getWidth());
|
||||||
|
|
||||||
|
// We always work in RGB, using DataBuffer.TYPE_INT transfer type.
|
||||||
|
int[] srcData = null;
|
||||||
|
int[] dstData = null;
|
||||||
|
int[] resData = new int[width - src.getMinX()];
|
||||||
|
|
||||||
|
for (int y = src.getMinY(); y < src.getHeight(); y++) {
|
||||||
|
srcData = (int[]) src.getDataElements(src.getMinX(), y, width, 1, srcData);
|
||||||
|
dstData = (int[]) dstIn.getDataElements(src.getMinX(), y, width, 1, dstData);
|
||||||
|
|
||||||
|
for (int x = src.getMinX(); x < width; x++) {
|
||||||
|
int sAlpha = (srcData[x] >>> 24) & 0xFF;
|
||||||
|
int sRed = sAlpha * ((srcData[x] >> 16) & 0xFF) / 0xFF;
|
||||||
|
int sGreen = sAlpha * ((srcData[x] >> 8) & 0xFF) / 0xFF;
|
||||||
|
int sBlue = sAlpha * ((srcData[x]) & 0xFF) / 0xFF;
|
||||||
|
|
||||||
|
int dAlpha = (dstData[x] >>> 24) & 0xFF;
|
||||||
|
int dRed = dAlpha * ((dstData[x] >> 16) & 0xFF) / 0xFF;
|
||||||
|
int dGreen = dAlpha * ((dstData[x] >> 8) & 0xFF) / 0xFF;
|
||||||
|
int dBlue = dAlpha * ((dstData[x]) & 0xFF) / 0xFF;
|
||||||
|
|
||||||
|
resData[x] = (min(sAlpha, dAlpha) << 24)
|
||||||
|
| (min(sRed, dRed) << 16)
|
||||||
|
| (min(sGreen, dGreen) << 8)
|
||||||
|
| (min(sBlue, dBlue));
|
||||||
|
}
|
||||||
|
|
||||||
|
dstOut.setDataElements(src.getMinX(), y, width, 1, resData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
274
imageio/imageio-pict/src/main/java/com/twelvemonkeys/imageio/plugins/pict/QuickDrawContext.java
Executable file → Normal file
274
imageio/imageio-pict/src/main/java/com/twelvemonkeys/imageio/plugins/pict/QuickDrawContext.java
Executable file → Normal file
@ -33,9 +33,8 @@ import com.twelvemonkeys.lang.Validate;
|
|||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.geom.*;
|
import java.awt.geom.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.awt.image.ColorModel;
|
|
||||||
import java.awt.image.Raster;
|
import static java.lang.Math.sqrt;
|
||||||
import java.awt.image.WritableRaster;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emulates an Apple QuickDraw rendering context, backed by a Java {@link Graphics2D}.
|
* Emulates an Apple QuickDraw rendering context, backed by a Java {@link Graphics2D}.
|
||||||
@ -170,7 +169,7 @@ class QuickDrawContext {
|
|||||||
// Sets the text's font style (0..255)
|
// Sets the text's font style (0..255)
|
||||||
void setTextFace(final int face) {
|
void setTextFace(final int face) {
|
||||||
int style = 0;
|
int style = 0;
|
||||||
if ((face & QuickDraw.TX_BOLD_MASK) > 0) {
|
if ((face & QuickDraw.TX_BOLD_MASK) > 0) {
|
||||||
style |= Font.BOLD;
|
style |= Font.BOLD;
|
||||||
}
|
}
|
||||||
if ((face & QuickDraw.TX_ITALIC_MASK) > 0) {
|
if ((face & QuickDraw.TX_ITALIC_MASK) > 0) {
|
||||||
@ -308,9 +307,9 @@ class QuickDrawContext {
|
|||||||
case QuickDraw.ADD_OVER:
|
case QuickDraw.ADD_OVER:
|
||||||
case QuickDraw.SUB_PIN:
|
case QuickDraw.SUB_PIN:
|
||||||
case QuickDraw.TRANSPARENT:
|
case QuickDraw.TRANSPARENT:
|
||||||
case QuickDraw.AD_MAX:
|
case QuickDraw.ADD_MAX:
|
||||||
case QuickDraw.SUB_OVER:
|
case QuickDraw.SUB_OVER:
|
||||||
case QuickDraw.AD_MIN:
|
case QuickDraw.ADD_MIN:
|
||||||
case QuickDraw.GRAYISH_TEXT_OR:
|
case QuickDraw.GRAYISH_TEXT_OR:
|
||||||
penMode = pPenMode;
|
penMode = pPenMode;
|
||||||
break;
|
break;
|
||||||
@ -365,12 +364,11 @@ class QuickDrawContext {
|
|||||||
case QuickDraw.SRC_BIC:
|
case QuickDraw.SRC_BIC:
|
||||||
return AlphaComposite.Clear;
|
return AlphaComposite.Clear;
|
||||||
case QuickDraw.NOT_SRC_XOR:
|
case QuickDraw.NOT_SRC_XOR:
|
||||||
return new NotSrcXor();
|
return QuickDrawComposite.NotSrcXor;
|
||||||
case QuickDraw.NOT_SRC_COPY:
|
case QuickDraw.NOT_SRC_COPY:
|
||||||
case QuickDraw.NOT_SRC_OR:
|
case QuickDraw.NOT_SRC_OR:
|
||||||
case QuickDraw.NOT_SRC_BIC:
|
case QuickDraw.NOT_SRC_BIC:
|
||||||
throw new UnsupportedOperationException("Not implemented for mode " + pMode);
|
throw new UnsupportedOperationException("Not implemented for mode " + pMode);
|
||||||
// return null;
|
|
||||||
// Boolean pattern transfer modes
|
// Boolean pattern transfer modes
|
||||||
case QuickDraw.PAT_COPY:
|
case QuickDraw.PAT_COPY:
|
||||||
return AlphaComposite.Src; // Tested
|
return AlphaComposite.Src; // Tested
|
||||||
@ -385,8 +383,22 @@ class QuickDrawContext {
|
|||||||
case QuickDraw.NOT_PAT_XOR:
|
case QuickDraw.NOT_PAT_XOR:
|
||||||
case QuickDraw.NOT_PAT_BIC:
|
case QuickDraw.NOT_PAT_BIC:
|
||||||
throw new UnsupportedOperationException("Not implemented for mode " + pMode);
|
throw new UnsupportedOperationException("Not implemented for mode " + pMode);
|
||||||
// return null;
|
// Aritmetic transfer modes
|
||||||
// TODO: Aritmetic transfer modes
|
case QuickDraw.BLEND:
|
||||||
|
return AlphaComposite.SrcOver.derive(.5f);
|
||||||
|
case QuickDraw.ADD_PIN:
|
||||||
|
case QuickDraw.ADD_OVER:
|
||||||
|
case QuickDraw.SUB_PIN:
|
||||||
|
case QuickDraw.TRANSPARENT:
|
||||||
|
throw new UnsupportedOperationException("Not implemented for mode " + pMode);
|
||||||
|
case QuickDraw.ADD_MAX:
|
||||||
|
return QuickDrawComposite.AddMax;
|
||||||
|
case QuickDraw.SUB_OVER:
|
||||||
|
throw new UnsupportedOperationException("Not implemented for mode " + pMode);
|
||||||
|
case QuickDraw.ADD_MIN:
|
||||||
|
return QuickDrawComposite.AddMin;
|
||||||
|
case QuickDraw.GRAYISH_TEXT_OR:
|
||||||
|
throw new UnsupportedOperationException("Not implemented for mode " + pMode);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unknown pnMode: " + pMode);
|
throw new IllegalArgumentException("Unknown pnMode: " + pMode);
|
||||||
@ -401,7 +413,6 @@ class QuickDrawContext {
|
|||||||
graphics.setComposite(getCompositeFor(textMode));
|
graphics.setComposite(getCompositeFor(textMode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up context for line drawing/painting.
|
* Sets up context for line drawing/painting.
|
||||||
*/
|
*/
|
||||||
@ -575,8 +586,8 @@ class QuickDrawContext {
|
|||||||
* the graphics pen.
|
* the graphics pen.
|
||||||
*
|
*
|
||||||
* @param pRectangle the rectangle to frame
|
* @param pRectangle the rectangle to frame
|
||||||
* @param pArcW width of the oval defining the rounded corner.
|
* @param pArcW width of the oval defining the rounded corner.
|
||||||
* @param pArcH height of the oval defining the rounded corner.
|
* @param pArcH height of the oval defining the rounded corner.
|
||||||
*/
|
*/
|
||||||
public void frameRoundRect(final Rectangle2D pRectangle, int pArcW, int pArcH) {
|
public void frameRoundRect(final Rectangle2D pRectangle, int pArcW, int pArcH) {
|
||||||
frameShape(toRoundRect(pRectangle, pArcW, pArcH));
|
frameShape(toRoundRect(pRectangle, pArcW, pArcH));
|
||||||
@ -587,8 +598,8 @@ class QuickDrawContext {
|
|||||||
* graphics pen, using the pattern mode of the graphics pen.
|
* graphics pen, using the pattern mode of the graphics pen.
|
||||||
*
|
*
|
||||||
* @param pRectangle the rectangle to paint
|
* @param pRectangle the rectangle to paint
|
||||||
* @param pArcW width of the oval defining the rounded corner.
|
* @param pArcW width of the oval defining the rounded corner.
|
||||||
* @param pArcH height of the oval defining the rounded corner.
|
* @param pArcH height of the oval defining the rounded corner.
|
||||||
*/
|
*/
|
||||||
public void paintRoundRect(final Rectangle2D pRectangle, int pArcW, int pArcH) {
|
public void paintRoundRect(final Rectangle2D pRectangle, int pArcW, int pArcH) {
|
||||||
paintShape(toRoundRect(pRectangle, pArcW, pArcH));
|
paintShape(toRoundRect(pRectangle, pArcW, pArcH));
|
||||||
@ -694,75 +705,75 @@ class QuickDrawContext {
|
|||||||
/**
|
/**
|
||||||
* Converts a rectangle to an arc.
|
* Converts a rectangle to an arc.
|
||||||
*
|
*
|
||||||
* @param pRectangle the framing rectangle
|
* @param pRectangle the framing rectangle
|
||||||
* @param pStartAngle start angle in degrees (starting from 12'o clock, this differs from Java)
|
* @param pStartAngle start angle in degrees (starting from 12'o clock, this differs from Java)
|
||||||
* @param pArcAngle rotation angle in degrees (starting from {@code pStartAngle}, this differs from Java arcs)
|
* @param pArcAngle rotation angle in degrees (starting from {@code pStartAngle}, this differs from Java arcs)
|
||||||
* @param pClosed specifies if the arc should be closed
|
* @param pClosed specifies if the arc should be closed
|
||||||
* @return the arc
|
* @return the arc
|
||||||
*/
|
*/
|
||||||
private static Arc2D.Double toArc(final Rectangle2D pRectangle, int pStartAngle, int pArcAngle, final boolean pClosed) {
|
private static Arc2D.Double toArc(final Rectangle2D pRectangle, int pStartAngle, int pArcAngle, final boolean pClosed) {
|
||||||
return new Arc2D.Double(pRectangle, 90 - pStartAngle, -pArcAngle, pClosed ? Arc2D.PIE : Arc2D.OPEN);
|
return new Arc2D.Double(pRectangle, 90 - pStartAngle, -pArcAngle, pClosed ? Arc2D.PIE : Arc2D.OPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FrameArc(r,int,int) // outline arc with the size, pattern, and pattern mode of
|
* FrameArc(r,int,int) // outline arc with the size, pattern, and pattern mode of
|
||||||
* the graphics pen.
|
* the graphics pen.
|
||||||
*
|
*
|
||||||
* @param pRectangle the rectangle to frame
|
* @param pRectangle the rectangle to frame
|
||||||
* @param pStartAngle start angle in degrees (starting from 12'o clock, this differs from Java)
|
* @param pStartAngle start angle in degrees (starting from 12'o clock, this differs from Java)
|
||||||
* @param pArcAngle rotation angle in degrees (starting from {@code pStartAngle}, this differs from Java arcs)
|
* @param pArcAngle rotation angle in degrees (starting from {@code pStartAngle}, this differs from Java arcs)
|
||||||
*/
|
*/
|
||||||
public void frameArc(final Rectangle2D pRectangle, int pStartAngle, int pArcAngle) {
|
public void frameArc(final Rectangle2D pRectangle, int pStartAngle, int pArcAngle) {
|
||||||
frameShape(toArc(pRectangle, pStartAngle, pArcAngle, false));
|
frameShape(toArc(pRectangle, pStartAngle, pArcAngle, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PaintArc(r,int,int) // fills an arc's interior with the pattern of the
|
* PaintArc(r,int,int) // fills an arc's interior with the pattern of the
|
||||||
* graphics pen, using the pattern mode of the graphics pen.
|
* graphics pen, using the pattern mode of the graphics pen.
|
||||||
*
|
*
|
||||||
* @param pRectangle the rectangle to paint
|
* @param pRectangle the rectangle to paint
|
||||||
* @param pStartAngle start angle in degrees (starting from 12'o clock, this differs from Java)
|
* @param pStartAngle start angle in degrees (starting from 12'o clock, this differs from Java)
|
||||||
* @param pArcAngle rotation angle in degrees (starting from {@code pStartAngle}, this differs from Java arcs)
|
* @param pArcAngle rotation angle in degrees (starting from {@code pStartAngle}, this differs from Java arcs)
|
||||||
*/
|
*/
|
||||||
public void paintArc(final Rectangle2D pRectangle, int pStartAngle, int pArcAngle) {
|
public void paintArc(final Rectangle2D pRectangle, int pStartAngle, int pArcAngle) {
|
||||||
paintShape(toArc(pRectangle, pStartAngle, pArcAngle, true));
|
paintShape(toArc(pRectangle, pStartAngle, pArcAngle, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FillArc(r,int,int, pat) // fills an arc's interior with any pattern you
|
* FillArc(r,int,int, pat) // fills an arc's interior with any pattern you
|
||||||
* specify. The procedure transfers the pattern with the patCopy pattern
|
* specify. The procedure transfers the pattern with the patCopy pattern
|
||||||
* mode, which directly copies your requested pattern into the shape.
|
* mode, which directly copies your requested pattern into the shape.
|
||||||
*
|
*
|
||||||
* @param pRectangle the rectangle to fill
|
* @param pRectangle the rectangle to fill
|
||||||
* @param pStartAngle start angle in degrees (starting from 12'o clock, this differs from Java)
|
* @param pStartAngle start angle in degrees (starting from 12'o clock, this differs from Java)
|
||||||
* @param pArcAngle rotation angle in degrees (starting from {@code pStartAngle}, this differs from Java arcs)
|
* @param pArcAngle rotation angle in degrees (starting from {@code pStartAngle}, this differs from Java arcs)
|
||||||
* @param pPattern the pattern to use
|
* @param pPattern the pattern to use
|
||||||
*/
|
*/
|
||||||
public void fillArc(final Rectangle2D pRectangle, int pStartAngle, int pArcAngle, Pattern pPattern) {
|
public void fillArc(final Rectangle2D pRectangle, int pStartAngle, int pArcAngle, Pattern pPattern) {
|
||||||
fillShape(toArc(pRectangle, pStartAngle, pArcAngle, true), pPattern);
|
fillShape(toArc(pRectangle, pStartAngle, pArcAngle, true), pPattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EraseArc(r,int,int) // fills the arc's interior with the background pattern
|
* EraseArc(r,int,int) // fills the arc's interior with the background pattern
|
||||||
*
|
*
|
||||||
* @param pRectangle the rectangle to erase
|
* @param pRectangle the rectangle to erase
|
||||||
* @param pStartAngle start angle in degrees (starting from 12'o clock, this differs from Java)
|
* @param pStartAngle start angle in degrees (starting from 12'o clock, this differs from Java)
|
||||||
* @param pArcAngle rotation angle in degrees (starting from {@code pStartAngle}, this differs from Java arcs)
|
* @param pArcAngle rotation angle in degrees (starting from {@code pStartAngle}, this differs from Java arcs)
|
||||||
*/
|
*/
|
||||||
public void eraseArc(final Rectangle2D pRectangle, int pStartAngle, int pArcAngle) {
|
public void eraseArc(final Rectangle2D pRectangle, int pStartAngle, int pArcAngle) {
|
||||||
eraseShape(toArc(pRectangle, pStartAngle, pArcAngle, true));
|
eraseShape(toArc(pRectangle, pStartAngle, pArcAngle, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* InvertArc(r,int,int) // reverses the color of all pixels in the arc
|
* InvertArc(r,int,int) // reverses the color of all pixels in the arc
|
||||||
*
|
*
|
||||||
* @param pRectangle the rectangle to invert
|
* @param pRectangle the rectangle to invert
|
||||||
* @param pStartAngle start angle in degrees (starting from 12'o clock, this differs from Java)
|
* @param pStartAngle start angle in degrees (starting from 12'o clock, this differs from Java)
|
||||||
* @param pArcAngle rotation angle in degrees (starting from {@code pStartAngle}, this differs from Java arcs)
|
* @param pArcAngle rotation angle in degrees (starting from {@code pStartAngle}, this differs from Java arcs)
|
||||||
*/
|
*/
|
||||||
public void invertArc(final Rectangle2D pRectangle, int pStartAngle, int pArcAngle) {
|
public void invertArc(final Rectangle2D pRectangle, int pStartAngle, int pArcAngle) {
|
||||||
invertShape(toArc(pRectangle, pStartAngle, pArcAngle, true));
|
invertShape(toArc(pRectangle, pStartAngle, pArcAngle, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// http://developer.apple.com/documentation/mac/quickdraw/QuickDraw-120.html#HEADING120-0
|
// http://developer.apple.com/documentation/mac/quickdraw/QuickDraw-120.html#HEADING120-0
|
||||||
@ -776,7 +787,7 @@ class QuickDrawContext {
|
|||||||
|
|
||||||
// Drawing Polygons:
|
// Drawing Polygons:
|
||||||
// TODO: What is the Xxx2D equivalent of Polygon!? GeneralPath?
|
// TODO: What is the Xxx2D equivalent of Polygon!? GeneralPath?
|
||||||
// FramePoly
|
// FramePoly
|
||||||
public void framePoly(final Polygon pPolygon) {
|
public void framePoly(final Polygon pPolygon) {
|
||||||
// TODO: The old PICTImageReader does not draw the last connection line,
|
// TODO: The old PICTImageReader does not draw the last connection line,
|
||||||
// unless the start and end point is the same...
|
// unless the start and end point is the same...
|
||||||
@ -905,18 +916,19 @@ class QuickDrawContext {
|
|||||||
|
|
||||||
// Copying Images (SKIP?):
|
// Copying Images (SKIP?):
|
||||||
*/
|
*/
|
||||||
/**
|
|
||||||
* CopyBits.
|
/**
|
||||||
* <p/>
|
* CopyBits.
|
||||||
* Note that the destination is always {@code this}.
|
* <p/>
|
||||||
*
|
* Note that the destination is always {@code this}.
|
||||||
* @param pSrcBitmap the source bitmap to copy pixels from
|
*
|
||||||
* @param pSrcRect the source rectangle
|
* @param pSrcBitmap the source bitmap to copy pixels from
|
||||||
* @param pDstRect the destination rectangle
|
* @param pSrcRect the source rectangle
|
||||||
* @param pMode the blending mode
|
* @param pDstRect the destination rectangle
|
||||||
* @param pMaskRgn the mask region
|
* @param pMode the blending mode
|
||||||
*/
|
* @param pMaskRgn the mask region
|
||||||
public void copyBits(BufferedImage pSrcBitmap, Rectangle pSrcRect, Rectangle pDstRect, int pMode, Shape pMaskRgn) {
|
*/
|
||||||
|
public void copyBits(BufferedImage pSrcBitmap, Rectangle pSrcRect, Rectangle pDstRect, int pMode, Shape pMaskRgn) {
|
||||||
graphics.setComposite(getCompositeFor(pMode));
|
graphics.setComposite(getCompositeFor(pMode));
|
||||||
if (pMaskRgn != null) {
|
if (pMaskRgn != null) {
|
||||||
setClipRegion(pMaskRgn);
|
setClipRegion(pMaskRgn);
|
||||||
@ -924,7 +936,7 @@ class QuickDrawContext {
|
|||||||
|
|
||||||
graphics.drawImage(
|
graphics.drawImage(
|
||||||
pSrcBitmap,
|
pSrcBitmap,
|
||||||
pDstRect.x,
|
pDstRect.x,
|
||||||
pDstRect.y,
|
pDstRect.y,
|
||||||
pDstRect.x + pDstRect.width,
|
pDstRect.x + pDstRect.width,
|
||||||
pDstRect.y + pDstRect.height,
|
pDstRect.y + pDstRect.height,
|
||||||
@ -935,22 +947,34 @@ class QuickDrawContext {
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
setClipRegion(null);
|
setClipRegion(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CopyMask
|
* CopyMask
|
||||||
*/
|
*/
|
||||||
public void copyMask(BufferedImage pSrcBitmap, BufferedImage pMaskBitmap, Rectangle pSrcRect, Rectangle pMaskRect, Rectangle pDstRect, int pSrcCopy, Shape pMaskRgn) {
|
public void copyMask(BufferedImage pSrcBitmap,
|
||||||
throw new UnsupportedOperationException("Method copyMask not implemented"); // TODO: Implement
|
BufferedImage pMaskBitmap,
|
||||||
|
Rectangle pSrcRect,
|
||||||
|
Rectangle pMaskRect,
|
||||||
|
Rectangle pDstRect,
|
||||||
|
int pSrcCopy,
|
||||||
|
Shape pMaskRgn) {
|
||||||
|
throw new UnsupportedOperationException("Method copyMask not implemented"); // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CopyDeepMask -- available to basic QuickDraw only in System 7, combines the functionality of both CopyBits and CopyMask
|
* CopyDeepMask -- available to basic QuickDraw only in System 7, combines the functionality of both CopyBits and CopyMask
|
||||||
*/
|
*/
|
||||||
public void copyDeepMask(BufferedImage pSrcBitmap, BufferedImage pMaskBitmap, Rectangle pSrcRect, Rectangle pMaskRect, Rectangle pDstRect, int pSrcCopy, Shape pMaskRgn) {
|
public void copyDeepMask(BufferedImage pSrcBitmap,
|
||||||
|
BufferedImage pMaskBitmap,
|
||||||
|
Rectangle pSrcRect,
|
||||||
|
Rectangle pMaskRect,
|
||||||
|
Rectangle pDstRect,
|
||||||
|
int pSrcCopy,
|
||||||
|
Shape pMaskRgn) {
|
||||||
throw new UnsupportedOperationException("Method copyDeepMask not implemented"); // TODO: Implement
|
throw new UnsupportedOperationException("Method copyDeepMask not implemented"); // TODO: Implement
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// Drawing With the Eight-Color System:
|
// Drawing With the Eight-Color System:
|
||||||
@ -978,15 +1002,15 @@ class QuickDrawContext {
|
|||||||
DrawChar // draws the glyph of a single 1-byte character.
|
DrawChar // draws the glyph of a single 1-byte character.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DrawString - draws the text of a Pascal string.
|
* DrawString - draws the text of a Pascal string.
|
||||||
*
|
*
|
||||||
* @param pString a Pascal string (a string of length less than or equal to 255 chars).
|
* @param pString a Pascal string (a string of length less than or equal to 255 chars).
|
||||||
*/
|
*/
|
||||||
public void drawString(String pString) {
|
public void drawString(String pString) {
|
||||||
setupForText();
|
setupForText();
|
||||||
graphics.drawString(pString, (float) getPenPosition().getX(), (float) getPenPosition().getY());
|
graphics.drawString(pString, (float) getPenPosition().getX(), (float) getPenPosition().getY());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
DrawText // draws the glyphs of a sequence of characters.
|
DrawText // draws the glyphs of a sequence of characters.
|
||||||
@ -1079,7 +1103,7 @@ class QuickDrawContext {
|
|||||||
thisY = points[1];
|
thisY = points[1];
|
||||||
float dx = thisX - lastX;
|
float dx = thisX - lastX;
|
||||||
float dy = thisY - lastY;
|
float dy = thisY - lastY;
|
||||||
float distance = (float) Math.sqrt(dx * dx + dy * dy);
|
float distance = (float) sqrt(dx * dx + dy * dy);
|
||||||
if (distance >= next) {
|
if (distance >= next) {
|
||||||
float r = 1.0f / distance;
|
float r = 1.0f / distance;
|
||||||
//float angle = (float) Math.atan2(dy, dx);
|
//float angle = (float) Math.atan2(dy, dx);
|
||||||
@ -1106,43 +1130,5 @@ class QuickDrawContext {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private static class NotSrcXor implements Composite {
|
|
||||||
// TODO: Src can probably be any color model that can be encoded in PICT, dst is always RGB/TYPE_INT
|
|
||||||
public CompositeContext createContext(final ColorModel srcColorModel, final ColorModel dstColorModel, RenderingHints hints) {
|
|
||||||
{
|
|
||||||
if (!srcColorModel.getColorSpace().isCS_sRGB() || !dstColorModel.getColorSpace().isCS_sRGB()) {
|
|
||||||
throw new IllegalArgumentException("Only sRGB supported");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CompositeContext() {
|
|
||||||
public void dispose() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
|
|
||||||
// We always work in RGB, using DataBuffer.TYPE_INT transfer type.
|
|
||||||
int[] srcData = null;
|
|
||||||
int[] dstData = null;
|
|
||||||
int[] resData = new int[src.getWidth() - src.getMinX()];
|
|
||||||
|
|
||||||
for (int y = src.getMinY(); y < src.getHeight(); y++) {
|
|
||||||
srcData = (int[]) src.getDataElements(src.getMinX(), y, src.getWidth(), 1, srcData);
|
|
||||||
dstData = (int[]) dstIn.getDataElements(src.getMinX(), y, src.getWidth(), 1, dstData);
|
|
||||||
|
|
||||||
for (int x = src.getMinX(); x < src.getWidth(); x++) {
|
|
||||||
// TODO: Decide how to handle alpha (if at all)
|
|
||||||
resData[x] = 0xff000000 | ((~ srcData[x] ^ dstData[x])) & 0xffffff ;
|
|
||||||
// resData[x] = ~ srcData[x] ^ dstData[x];
|
|
||||||
}
|
|
||||||
|
|
||||||
dstOut.setDataElements(src.getMinX(), y, src.getWidth(), 1, resData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user