/*
* Copyright © 2009-2011 Rebecca G. Bettencourt / Kreative Software
* <p>
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* <a href="http://www.mozilla.org/MPL/">http://www.mozilla.org/MPL/</a>
* <p>
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
* <p>
* Alternatively, the contents of this file may be used under the terms
* of the GNU Lesser General Public License (the "LGPL License"), in which
* case the provisions of LGPL License are applicable instead of those
* above. If you wish to allow use of your version of this file only
* under the terms of the LGPL License and not to allow others to use
* your version of this file under the MPL, indicate your decision by
* deleting the provisions above and replace them with the notice and
* other provisions required by the LGPL License. If you do not delete
* the provisions above, a recipient may use your version of this file
* under either the MPL or the LGPL License.
* @since PowerPaint 1.0
* @author Rebecca G. Bettencourt, Kreative Software
*/
package com.kreative.paint.io;
import java.awt.*;
import java.awt.geom.*;
import java.io.*;
/* This more or less covers the java.awt.geom package. */
/* This and AWTSerializer more or less cover the java.awt package. */
public class ShapeSerializer extends Serializer {
private static final int TYPE_AFFINE_TRANSFORM = fcc("AfTx");
private static final int TYPE_ARC2D_DOUBLE = fcc("ArcD");
private static final int TYPE_ARC2D_FLOAT = fcc("ArcF");
private static final int TYPE_AREA = fcc("Area");
private static final int TYPE_CUBIC_CURVE_DOUBLE = fcc("CubD");
private static final int TYPE_CUBIC_CURVE_FLOAT = fcc("CubF");
private static final int TYPE_DIMENSION = fcc("Dime");
private static final int TYPE_ELLIPSE_DOUBLE = fcc("EllD");
private static final int TYPE_ELLIPSE_FLOAT = fcc("EllF");
private static final int TYPE_GENERAL_PATH = fcc("Path");
private static final int TYPE_LINE2D_DOUBLE = fcc("LinD");
private static final int TYPE_LINE2D_FLOAT = fcc("LinF");
private static final int TYPE_POINT = fcc("Poin");
private static final int TYPE_POINT_DOUBLE = fcc("PoiD");
private static final int TYPE_POINT_FLOAT = fcc("PoiF");
private static final int TYPE_POLYGON = fcc("Poly");
private static final int TYPE_QUAD_CURVE_DOUBLE = fcc("QuaD");
private static final int TYPE_QUAD_CURVE_FLOAT = fcc("QuaF");
private static final int TYPE_RECTANGLE = fcc("Rect");
private static final int TYPE_RECTANGLE_DOUBLE = fcc("RecD");
private static final int TYPE_RECTANGLE_FLOAT = fcc("RecF");
private static final int TYPE_ROUND_RECT_DOUBLE = fcc("RReD");
private static final int TYPE_ROUND_RECT_FLOAT = fcc("RReF");
protected void loadRecognizedTypesAndClasses() {
addTypeAndClass(TYPE_AFFINE_TRANSFORM, 1, AffineTransform.class);
addTypeAndClass(TYPE_ARC2D_DOUBLE, 1, Arc2D.Double.class);
addTypeAndClass(TYPE_ARC2D_FLOAT, 1, Arc2D.Float.class);
addTypeAndClass(TYPE_AREA, 1, Area.class);
addTypeAndClass(TYPE_CUBIC_CURVE_DOUBLE, 1, CubicCurve2D.Double.class);
addTypeAndClass(TYPE_CUBIC_CURVE_FLOAT, 1, CubicCurve2D.Float.class);
addTypeAndClass(TYPE_DIMENSION, 1, Dimension.class);
addTypeAndClass(TYPE_ELLIPSE_DOUBLE, 1, Ellipse2D.Double.class);
addTypeAndClass(TYPE_ELLIPSE_FLOAT, 1, Ellipse2D.Float.class);
addTypeAndClass(TYPE_GENERAL_PATH, 1, GeneralPath.class);
addTypeAndClass(TYPE_LINE2D_DOUBLE, 1, Line2D.Double.class);
addTypeAndClass(TYPE_LINE2D_FLOAT, 1, Line2D.Float.class);
addTypeAndClass(TYPE_POINT, 1, Point.class);
addTypeAndClass(TYPE_POINT_DOUBLE, 1, Point2D.Double.class);
addTypeAndClass(TYPE_POINT_FLOAT, 1, Point2D.Float.class);
addTypeAndClass(TYPE_POLYGON, 1, Polygon.class);
addTypeAndClass(TYPE_QUAD_CURVE_DOUBLE, 1, QuadCurve2D.Double.class);
addTypeAndClass(TYPE_QUAD_CURVE_FLOAT, 1, QuadCurve2D.Float.class);
addTypeAndClass(TYPE_RECTANGLE, 1, Rectangle.class);
addTypeAndClass(TYPE_RECTANGLE_DOUBLE, 1, Rectangle2D.Double.class);
addTypeAndClass(TYPE_RECTANGLE_FLOAT, 1, Rectangle2D.Float.class);
addTypeAndClass(TYPE_ROUND_RECT_DOUBLE, 1, RoundRectangle2D.Double.class);
addTypeAndClass(TYPE_ROUND_RECT_FLOAT, 1, RoundRectangle2D.Float.class);
}
public void serializeObject(Object o, DataOutputStream stream) throws IOException {
if (o instanceof AffineTransform) {
AffineTransform v = (AffineTransform)o;
double[] m = new double[6];
v.getMatrix(m);
for (int i = 0; i < 6; i++) {
stream.writeDouble(m[i]);
}
}
else if (o instanceof Arc2D.Double) {
Arc2D.Double v = (Arc2D.Double)o;
stream.writeDouble(v.x);
stream.writeDouble(v.y);
stream.writeDouble(v.width);
stream.writeDouble(v.height);
stream.writeDouble(v.start);
stream.writeDouble(v.extent);
stream.writeInt(v.getArcType());
}
else if (o instanceof Arc2D.Float) {
Arc2D.Float v = (Arc2D.Float)o;
stream.writeFloat(v.x);
stream.writeFloat(v.y);
stream.writeFloat(v.width);
stream.writeFloat(v.height);
stream.writeFloat(v.start);
stream.writeFloat(v.extent);
stream.writeInt(v.getArcType());
}
else if (o instanceof Area) {
Area v = (Area)o;
PathIterator i = v.getPathIterator(null);
while (!i.isDone()) {
float[] coords = new float[6];
int type = i.currentSegment(coords);
int wind = i.getWindingRule();
int n = 0;
switch (type) {
case PathIterator.SEG_CLOSE: stream.writeShort(0x436C); n = 0; break;
case PathIterator.SEG_CUBICTO: stream.writeShort(0x4375); n = 6; break;
case PathIterator.SEG_LINETO: stream.writeShort(0x4C69); n = 2; break;
case PathIterator.SEG_MOVETO: stream.writeShort(0x4D6F); n = 2; break;
case PathIterator.SEG_QUADTO: stream.writeShort(0x5175); n = 4; break;
default: stream.writeShort(0x3F3F); n = 0; break;
}
switch (wind) {
case PathIterator.WIND_EVEN_ODD: stream.writeShort(0x454F); break;
case PathIterator.WIND_NON_ZERO: stream.writeShort(0x4E5A); break;
default: stream.writeShort(0x3F3F); break;
}
stream.writeInt(n);
for (int j = 0; j < n; j++) {
stream.writeFloat(coords[j]);
}
i.next();
}
stream.writeShort(-1);
stream.writeShort(-1);
stream.writeInt(-1);
}
else if (o instanceof CubicCurve2D.Double) {
CubicCurve2D.Double v = (CubicCurve2D.Double)o;
stream.writeDouble(v.x1);
stream.writeDouble(v.y1);
stream.writeDouble(v.ctrlx1);
stream.writeDouble(v.ctrly1);
stream.writeDouble(v.ctrlx2);
stream.writeDouble(v.ctrly2);
stream.writeDouble(v.x2);
stream.writeDouble(v.y2);
}
else if (o instanceof CubicCurve2D.Float) {
CubicCurve2D.Float v = (CubicCurve2D.Float)o;
stream.writeFloat(v.x1);
stream.writeFloat(v.y1);
stream.writeFloat(v.ctrlx1);
stream.writeFloat(v.ctrly1);
stream.writeFloat(v.ctrlx2);
stream.writeFloat(v.ctrly2);
stream.writeFloat(v.x2);
stream.writeFloat(v.y2);
}
else if (o instanceof Dimension) {
Dimension v = (Dimension)o;
stream.writeInt(v.width);
stream.writeInt(v.height);
}
else if (o instanceof Ellipse2D.Double) {
Ellipse2D.Double v = (Ellipse2D.Double)o;
stream.writeDouble(v.x);
stream.writeDouble(v.y);
stream.writeDouble(v.width);
stream.writeDouble(v.height);
}
else if (o instanceof Ellipse2D.Float) {
Ellipse2D.Float v = (Ellipse2D.Float)o;
stream.writeFloat(v.x);
stream.writeFloat(v.y);
stream.writeFloat(v.width);
stream.writeFloat(v.height);
}
else if (o instanceof GeneralPath) {
GeneralPath v = (GeneralPath)o;
PathIterator i = v.getPathIterator(null);
while (!i.isDone()) {
float[] coords = new float[6];
int type = i.currentSegment(coords);
int wind = i.getWindingRule();
int n = 0;
switch (type) {
case PathIterator.SEG_CLOSE: stream.writeShort(0x436C); n = 0; break;
case PathIterator.SEG_CUBICTO: stream.writeShort(0x4375); n = 6; break;
case PathIterator.SEG_LINETO: stream.writeShort(0x4C69); n = 2; break;
case PathIterator.SEG_MOVETO: stream.writeShort(0x4D6F); n = 2; break;
case PathIterator.SEG_QUADTO: stream.writeShort(0x5175); n = 4; break;
default: stream.writeShort(0x3F3F); n = 0; break;
}
switch (wind) {
case PathIterator.WIND_EVEN_ODD: stream.writeShort(0x454F); break;
case PathIterator.WIND_NON_ZERO: stream.writeShort(0x4E5A); break;
default: stream.writeShort(0x3F3F); break;
}
stream.writeInt(n);
for (int j = 0; j < n; j++) {
stream.writeFloat(coords[j]);
}
i.next();
}
stream.writeShort(-1);
stream.writeShort(-1);
stream.writeInt(-1);
}
else if (o instanceof Line2D.Double) {
Line2D.Double v = (Line2D.Double)o;
stream.writeDouble(v.x1);
stream.writeDouble(v.y1);
stream.writeDouble(v.x2);
stream.writeDouble(v.y2);
}
else if (o instanceof Line2D.Float) {
Line2D.Float v = (Line2D.Float)o;
stream.writeFloat(v.x1);
stream.writeFloat(v.y1);
stream.writeFloat(v.x2);
stream.writeFloat(v.y2);
}
else if (o instanceof Point) {
Point v = (Point)o;
stream.writeInt(v.x);
stream.writeInt(v.y);
}
else if (o instanceof Point2D.Double) {
Point2D.Double v = (Point2D.Double)o;
stream.writeDouble(v.x);
stream.writeDouble(v.y);
}
else if (o instanceof Point2D.Float) {
Point2D.Float v = (Point2D.Float)o;
stream.writeFloat(v.x);
stream.writeFloat(v.y);
}
else if (o instanceof Polygon) {
Polygon v = (Polygon)o;
stream.writeInt(v.npoints);
for (int i = 0; i < v.npoints; i++) {
stream.writeInt(v.xpoints[i]);
stream.writeInt(v.ypoints[i]);
}
}
else if (o instanceof QuadCurve2D.Double) {
QuadCurve2D.Double v = (QuadCurve2D.Double)o;
stream.writeDouble(v.x1);
stream.writeDouble(v.y1);
stream.writeDouble(v.ctrlx);
stream.writeDouble(v.ctrly);
stream.writeDouble(v.x2);
stream.writeDouble(v.y2);
}
else if (o instanceof QuadCurve2D.Float) {
QuadCurve2D.Float v = (QuadCurve2D.Float)o;
stream.writeFloat(v.x1);
stream.writeFloat(v.y1);
stream.writeFloat(v.ctrlx);
stream.writeFloat(v.ctrly);
stream.writeFloat(v.x2);
stream.writeFloat(v.y2);
}
else if (o instanceof Rectangle) {
Rectangle v = (Rectangle)o;
stream.writeInt(v.x);
stream.writeInt(v.y);
stream.writeInt(v.width);
stream.writeInt(v.height);
}
else if (o instanceof Rectangle2D.Double) {
Rectangle2D.Double v = (Rectangle2D.Double)o;
stream.writeDouble(v.x);
stream.writeDouble(v.y);
stream.writeDouble(v.width);
stream.writeDouble(v.height);
}
else if (o instanceof Rectangle2D.Float) {
Rectangle2D.Float v = (Rectangle2D.Float)o;
stream.writeFloat(v.x);
stream.writeFloat(v.y);
stream.writeFloat(v.width);
stream.writeFloat(v.height);
}
else if (o instanceof RoundRectangle2D.Double) {
RoundRectangle2D.Double v = (RoundRectangle2D.Double)o;
stream.writeDouble(v.x);
stream.writeDouble(v.y);
stream.writeDouble(v.width);
stream.writeDouble(v.height);
stream.writeDouble(v.arcwidth);
stream.writeDouble(v.archeight);
}
else if (o instanceof RoundRectangle2D.Float) {
RoundRectangle2D.Float v = (RoundRectangle2D.Float)o;
stream.writeFloat(v.x);
stream.writeFloat(v.y);
stream.writeFloat(v.width);
stream.writeFloat(v.height);
stream.writeFloat(v.arcwidth);
stream.writeFloat(v.archeight);
}
}
public Object deserializeObject(int type, int version, DataInputStream stream) throws IOException {
if (version != 1) throw new IOException("Invalid version number.");
else if (type == TYPE_AFFINE_TRANSFORM) {
double[] m = new double[6];
for (int i = 0; i < 6; i++) {
m[i] = stream.readDouble();
}
return new AffineTransform(m);
}
else if (type == TYPE_ARC2D_DOUBLE) {
double x = stream.readDouble();
double y = stream.readDouble();
double w = stream.readDouble();
double h = stream.readDouble();
double s = stream.readDouble();
double e = stream.readDouble();
int t = stream.readInt();
return new Arc2D.Double(x,y,w,h,s,e,t);
}
else if (type == TYPE_ARC2D_FLOAT) {
float x = stream.readFloat();
float y = stream.readFloat();
float w = stream.readFloat();
float h = stream.readFloat();
float s = stream.readFloat();
float e = stream.readFloat();
int t = stream.readInt();
return new Arc2D.Float(x,y,w,h,s,e,t);
}
else if (type == TYPE_AREA) {
GeneralPath p = new GeneralPath();
while (true) {
short t = stream.readShort();
if (t < 0) break;
short w = stream.readShort();
if (t < 0) break;
int n = stream.readInt();
if (n < 0) break;
float[] c = new float[n];
for (int i = 0; i < n; i++) {
c[i] = stream.readFloat();
}
switch (t) {
case 0x436C: p.closePath(); break;
case 0x4375: p.curveTo(c[0], c[1], c[2], c[3], c[4], c[5]); break;
case 0x4C69: p.lineTo(c[0], c[1]); break;
case 0x4D6F: p.moveTo(c[0], c[1]); break;
case 0x5175: p.quadTo(c[0], c[1], c[2], c[3]); break;
}
switch (w) {
case 0x454F: p.setWindingRule(GeneralPath.WIND_EVEN_ODD); break;
case 0x4E5A: p.setWindingRule(GeneralPath.WIND_NON_ZERO); break;
}
}
return new Area(p);
}
else if (type == TYPE_CUBIC_CURVE_DOUBLE) {
double x1 = stream.readDouble();
double y1 = stream.readDouble();
double cx1 = stream.readDouble();
double cy1 = stream.readDouble();
double cx2 = stream.readDouble();
double cy2 = stream.readDouble();
double x2 = stream.readDouble();
double y2 = stream.readDouble();
return new CubicCurve2D.Double(x1,y1,cx1,cy1,cx2,cy2,x2,y2);
}
else if (type == TYPE_CUBIC_CURVE_FLOAT) {
float x1 = stream.readFloat();
float y1 = stream.readFloat();
float cx1 = stream.readFloat();
float cy1 = stream.readFloat();
float cx2 = stream.readFloat();
float cy2 = stream.readFloat();
float x2 = stream.readFloat();
float y2 = stream.readFloat();
return new CubicCurve2D.Float(x1,y1,cx1,cy1,cx2,cy2,x2,y2);
}
else if (type == TYPE_DIMENSION) {
int w = stream.readInt();
int h = stream.readInt();
return new Dimension(w,h);
}
else if (type == TYPE_ELLIPSE_DOUBLE) {
double x = stream.readDouble();
double y = stream.readDouble();
double w = stream.readDouble();
double h = stream.readDouble();
return new Ellipse2D.Double(x,y,w,h);
}
else if (type == TYPE_ELLIPSE_FLOAT) {
float x = stream.readFloat();
float y = stream.readFloat();
float w = stream.readFloat();
float h = stream.readFloat();
return new Ellipse2D.Float(x,y,w,h);
}
else if (type == TYPE_GENERAL_PATH) {
GeneralPath p = new GeneralPath();
while (true) {
short t = stream.readShort();
if (t < 0) break;
short w = stream.readShort();
if (t < 0) break;
int n = stream.readInt();
if (n < 0) break;
float[] c = new float[n];
for (int i = 0; i < n; i++) {
c[i] = stream.readFloat();
}
switch (t) {
case 0x436C: p.closePath(); break;
case 0x4375: p.curveTo(c[0], c[1], c[2], c[3], c[4], c[5]); break;
case 0x4C69: p.lineTo(c[0], c[1]); break;
case 0x4D6F: p.moveTo(c[0], c[1]); break;
case 0x5175: p.quadTo(c[0], c[1], c[2], c[3]); break;
}
switch (w) {
case 0x454F: p.setWindingRule(GeneralPath.WIND_EVEN_ODD); break;
case 0x4E5A: p.setWindingRule(GeneralPath.WIND_NON_ZERO); break;
}
}
return p;
}
else if (type == TYPE_LINE2D_DOUBLE) {
double x1 = stream.readDouble();
double y1 = stream.readDouble();
double x2 = stream.readDouble();
double y2 = stream.readDouble();
return new Line2D.Double(x1,y1,x2,y2);
}
else if (type == TYPE_LINE2D_FLOAT) {
float x1 = stream.readFloat();
float y1 = stream.readFloat();
float x2 = stream.readFloat();
float y2 = stream.readFloat();
return new Line2D.Float(x1,y1,x2,y2);
}
else if (type == TYPE_POINT) {
int x = stream.readInt();
int y = stream.readInt();
return new Point(x,y);
}
else if (type == TYPE_POINT_DOUBLE) {
double x = stream.readDouble();
double y = stream.readDouble();
return new Point2D.Double(x,y);
}
else if (type == TYPE_POINT_FLOAT) {
float x = stream.readFloat();
float y = stream.readFloat();
return new Point2D.Float(x,y);
}
else if (type == TYPE_POLYGON) {
int n = stream.readInt();
int[] x = new int[n];
int[] y = new int[n];
for (int i = 0; i < n; i++) {
x[i] = stream.readInt();
y[i] = stream.readInt();
}
return new Polygon(x, y, n);
}
else if (type == TYPE_QUAD_CURVE_DOUBLE) {
double x1 = stream.readDouble();
double y1 = stream.readDouble();
double cx = stream.readDouble();
double cy = stream.readDouble();
double x2 = stream.readDouble();
double y2 = stream.readDouble();
return new QuadCurve2D.Double(x1,y1,cx,cy,x2,y2);
}
else if (type == TYPE_QUAD_CURVE_FLOAT) {
float x1 = stream.readFloat();
float y1 = stream.readFloat();
float cx = stream.readFloat();
float cy = stream.readFloat();
float x2 = stream.readFloat();
float y2 = stream.readFloat();
return new QuadCurve2D.Float(x1,y1,cx,cy,x2,y2);
}
else if (type == TYPE_RECTANGLE) {
int x = stream.readInt();
int y = stream.readInt();
int w = stream.readInt();
int h = stream.readInt();
return new Rectangle(x,y,w,h);
}
else if (type == TYPE_RECTANGLE_DOUBLE) {
double x = stream.readDouble();
double y = stream.readDouble();
double w = stream.readDouble();
double h = stream.readDouble();
return new Rectangle2D.Double(x,y,w,h);
}
else if (type == TYPE_RECTANGLE_FLOAT) {
float x = stream.readFloat();
float y = stream.readFloat();
float w = stream.readFloat();
float h = stream.readFloat();
return new Rectangle2D.Float(x,y,w,h);
}
else if (type == TYPE_ROUND_RECT_DOUBLE) {
double x = stream.readDouble();
double y = stream.readDouble();
double w = stream.readDouble();
double h = stream.readDouble();
double aw = stream.readDouble();
double ah = stream.readDouble();
return new RoundRectangle2D.Double(x,y,w,h,aw,ah);
}
else if (type == TYPE_ROUND_RECT_FLOAT) {
float x = stream.readFloat();
float y = stream.readFloat();
float w = stream.readFloat();
float h = stream.readFloat();
float aw = stream.readFloat();
float ah = stream.readFloat();
return new RoundRectangle2D.Float(x,y,w,h,aw,ah);
}
else return null;
}
}