fix gitignore, remove chart io vector package
This commit is contained in:
parent
58a6e85062
commit
11d563570e
261 changed files with 61 additions and 34756 deletions
3
chart/build.gradle
Normal file
3
chart/build.gradle
Normal file
|
@ -0,0 +1,3 @@
|
|||
dependencies {
|
||||
implementation project(':io-vector')
|
||||
}
|
|
@ -13,5 +13,6 @@ module org.xbib.graphics.chart {
|
|||
exports org.xbib.graphics.chart.style;
|
||||
exports org.xbib.graphics.chart.theme;
|
||||
exports org.xbib.graphics.chart.xy;
|
||||
requires org.xbib.graphics.io.vector;
|
||||
requires transitive java.desktop;
|
||||
}
|
||||
|
|
|
@ -9,10 +9,10 @@ import org.xbib.graphics.chart.legend.Legend;
|
|||
import org.xbib.graphics.chart.plot.Plot;
|
||||
import org.xbib.graphics.chart.series.Series;
|
||||
import org.xbib.graphics.chart.style.Styler;
|
||||
import org.xbib.graphics.chart.io.vector.EPSGraphics2D;
|
||||
import org.xbib.graphics.chart.io.vector.PDFGraphics2D;
|
||||
import org.xbib.graphics.chart.io.vector.ProcessingPipeline;
|
||||
import org.xbib.graphics.chart.io.vector.SVGGraphics2D;
|
||||
import org.xbib.graphics.io.vector.VectorGraphics2D;
|
||||
import org.xbib.graphics.io.vector.eps.EPSGraphics2D;
|
||||
import org.xbib.graphics.io.vector.pdf.PDFGraphics2D;
|
||||
import org.xbib.graphics.io.vector.svg.SVGGraphics2D;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
|
@ -306,7 +306,7 @@ public abstract class Chart<ST extends Styler, S extends Series> {
|
|||
* @throws IIOInvalidTreeException if setting fails
|
||||
*/
|
||||
private static void setDPI(IIOMetadata metadata, int DPI) throws IIOInvalidTreeException {
|
||||
// for PNG, it's dots per millimeter
|
||||
// for PNG, it's dots per millimeter?
|
||||
double dotsPerMilli = 1.0 * DPI / 10 / 2.54;
|
||||
IIOMetadataNode horiz = new IIOMetadataNode("HorizontalPixelSize");
|
||||
horiz.setAttribute("value", Double.toString(dotsPerMilli));
|
||||
|
@ -368,7 +368,7 @@ public abstract class Chart<ST extends Styler, S extends Series> {
|
|||
|
||||
public void write(OutputStream outputStream, VectorGraphicsFormat vectorGraphicsFormat)
|
||||
throws IOException {
|
||||
ProcessingPipeline g = null;
|
||||
VectorGraphics2D g = null;
|
||||
switch (vectorGraphicsFormat) {
|
||||
case EPS:
|
||||
g = new EPSGraphics2D(0.0, 0.0, getWidth(), getHeight());
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.CommandHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public interface Document extends CommandHandler {
|
||||
void write(OutputStream out) throws IOException;
|
||||
|
||||
void close();
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.eps.EPSProcessor;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* {@code Graphics2D} implementation that saves all operations to a string
|
||||
* in the <i>Encapsulated PostScript®</i> (EPS) format.
|
||||
*/
|
||||
public class EPSGraphics2D extends ProcessingPipeline {
|
||||
|
||||
private final Processor processor;
|
||||
|
||||
/**
|
||||
* Initializes a new VectorGraphics2D pipeline for translating Graphics2D
|
||||
* commands to EPS data. The document dimensions must be specified as
|
||||
* parameters.
|
||||
*
|
||||
* @param x Left offset.
|
||||
* @param y Top offset
|
||||
* @param width Width.
|
||||
* @param height Height.
|
||||
*/
|
||||
public EPSGraphics2D(double x, double y, double width, double height) {
|
||||
super(x, y, width, height);
|
||||
processor = new EPSProcessor();
|
||||
/*
|
||||
* The following are the default settings for the graphics state in an EPS file.
|
||||
* Although they currently appear in the document output, they do not have to be set explicitly.
|
||||
*/
|
||||
// TODO: Default graphics state does not need to be printed in the document
|
||||
setColor(Color.BLACK);
|
||||
setStroke(new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, null, 0f));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Processor getProcessor() {
|
||||
return processor;
|
||||
}
|
||||
}
|
|
@ -1,275 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.util.GraphicsUtils;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Font;
|
||||
import java.awt.Paint;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.NoninvertibleTransformException;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.Objects;
|
||||
|
||||
public class GraphicsState implements Cloneable {
|
||||
/**
|
||||
* Default background color.
|
||||
*/
|
||||
public static final Color DEFAULT_BACKGROUND = Color.BLACK;
|
||||
/**
|
||||
* Default color.
|
||||
*/
|
||||
public static final Color DEFAULT_COLOR = Color.WHITE;
|
||||
/**
|
||||
* Default clipping shape.
|
||||
*/
|
||||
public static final Shape DEFAULT_CLIP = null;
|
||||
/**
|
||||
* Default composite mode.
|
||||
*/
|
||||
public static final Composite DEFAULT_COMPOSITE = AlphaComposite.SrcOver;
|
||||
/**
|
||||
* Default font.
|
||||
*/
|
||||
public static final Font DEFAULT_FONT = Font.decode(null);
|
||||
/**
|
||||
* Default paint.
|
||||
*/
|
||||
public static final Color DEFAULT_PAINT = DEFAULT_COLOR;
|
||||
/**
|
||||
* Default stroke.
|
||||
*/
|
||||
public static final Stroke DEFAULT_STROKE = new BasicStroke();
|
||||
/**
|
||||
* Default transformation.
|
||||
*/
|
||||
public static final AffineTransform DEFAULT_TRANSFORM =
|
||||
new AffineTransform();
|
||||
/**
|
||||
* Default XOR mode.
|
||||
*/
|
||||
public static final Color DEFAULT_XOR_MODE = Color.BLACK;
|
||||
|
||||
/**
|
||||
* Rendering hints.
|
||||
*/
|
||||
private RenderingHints hints;
|
||||
/**
|
||||
* Current background color.
|
||||
*/
|
||||
private Color background;
|
||||
/**
|
||||
* Current foreground color.
|
||||
*/
|
||||
private Color color;
|
||||
/**
|
||||
* Shape used for clipping paint operations.
|
||||
*/
|
||||
private Shape clip;
|
||||
/**
|
||||
* Method used for compositing.
|
||||
*/
|
||||
private Composite composite;
|
||||
/**
|
||||
* Current font.
|
||||
*/
|
||||
private Font font;
|
||||
/**
|
||||
* Paint used to fill shapes.
|
||||
*/
|
||||
private Paint paint;
|
||||
/**
|
||||
* Stroke used for drawing shapes.
|
||||
*/
|
||||
private Stroke stroke;
|
||||
/**
|
||||
* Current transformation matrix.
|
||||
*/
|
||||
private AffineTransform transform;
|
||||
/**
|
||||
* XOR mode used for rendering.
|
||||
*/
|
||||
private Color xorMode;
|
||||
|
||||
public GraphicsState() {
|
||||
hints = new RenderingHints(null);
|
||||
background = DEFAULT_BACKGROUND;
|
||||
color = DEFAULT_COLOR;
|
||||
clip = DEFAULT_CLIP;
|
||||
composite = DEFAULT_COMPOSITE;
|
||||
font = DEFAULT_FONT;
|
||||
paint = DEFAULT_PAINT;
|
||||
stroke = DEFAULT_STROKE;
|
||||
transform = new AffineTransform(DEFAULT_TRANSFORM);
|
||||
xorMode = DEFAULT_XOR_MODE;
|
||||
}
|
||||
|
||||
private static Shape transformShape(Shape s, AffineTransform tx) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
if (tx == null || tx.isIdentity()) {
|
||||
return GraphicsUtils.clone(s);
|
||||
}
|
||||
boolean isRectangle = s instanceof Rectangle2D;
|
||||
int nonRectlinearTxMask = AffineTransform.TYPE_GENERAL_TRANSFORM |
|
||||
AffineTransform.TYPE_GENERAL_ROTATION;
|
||||
boolean isRectlinearTx = (tx.getType() & nonRectlinearTxMask) == 0;
|
||||
if (isRectangle && isRectlinearTx) {
|
||||
Rectangle2D rect = (Rectangle2D) s;
|
||||
double[] corners = new double[]{
|
||||
rect.getMinX(), rect.getMinY(),
|
||||
rect.getMaxX(), rect.getMaxY()
|
||||
};
|
||||
tx.transform(corners, 0, corners, 0, 2);
|
||||
rect = new Rectangle2D.Double();
|
||||
rect.setFrameFromDiagonal(corners[0], corners[1], corners[2],
|
||||
corners[3]);
|
||||
return rect;
|
||||
}
|
||||
return tx.createTransformedShape(s);
|
||||
}
|
||||
|
||||
private static Shape untransformShape(Shape s, AffineTransform tx) {
|
||||
if (s == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
AffineTransform inverse = tx.createInverse();
|
||||
return transformShape(s, inverse);
|
||||
} catch (NoninvertibleTransformException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
GraphicsState clone = (GraphicsState) super.clone();
|
||||
clone.hints = (RenderingHints) hints.clone();
|
||||
clone.clip = GraphicsUtils.clone(clip);
|
||||
clone.transform = new AffineTransform(transform);
|
||||
return clone;
|
||||
}
|
||||
|
||||
public Shape transformShape(Shape shape) {
|
||||
return transformShape(shape, transform);
|
||||
}
|
||||
|
||||
public Shape untransformShape(Shape shape) {
|
||||
return untransformShape(shape, transform);
|
||||
}
|
||||
|
||||
public RenderingHints getHints() {
|
||||
return hints;
|
||||
}
|
||||
|
||||
public Color getBackground() {
|
||||
return background;
|
||||
}
|
||||
|
||||
public void setBackground(Color background) {
|
||||
this.background = background;
|
||||
}
|
||||
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public void setColor(Color color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public Shape getClip() {
|
||||
return untransformShape(clip);
|
||||
}
|
||||
|
||||
public void setClip(Shape clip) {
|
||||
this.clip = transformShape(clip);
|
||||
}
|
||||
|
||||
public Composite getComposite() {
|
||||
return composite;
|
||||
}
|
||||
|
||||
public void setComposite(Composite composite) {
|
||||
this.composite = composite;
|
||||
}
|
||||
|
||||
public Font getFont() {
|
||||
return font;
|
||||
}
|
||||
|
||||
public void setFont(Font font) {
|
||||
this.font = font;
|
||||
}
|
||||
|
||||
public Paint getPaint() {
|
||||
return paint;
|
||||
}
|
||||
|
||||
public void setPaint(Paint paint) {
|
||||
this.paint = paint;
|
||||
}
|
||||
|
||||
public Stroke getStroke() {
|
||||
return stroke;
|
||||
}
|
||||
|
||||
public void setStroke(Stroke stroke) {
|
||||
this.stroke = stroke;
|
||||
}
|
||||
|
||||
public AffineTransform getTransform() {
|
||||
return new AffineTransform(transform);
|
||||
}
|
||||
|
||||
public void setTransform(AffineTransform tx) {
|
||||
transform.setTransform(tx);
|
||||
}
|
||||
|
||||
public Color getXorMode() {
|
||||
return xorMode;
|
||||
}
|
||||
|
||||
public void setXorMode(Color xorMode) {
|
||||
this.xorMode = xorMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof GraphicsState)) {
|
||||
return false;
|
||||
}
|
||||
GraphicsState o = (GraphicsState) obj;
|
||||
return !(!hints.equals(o.hints) || !background.equals(o.background) ||
|
||||
!color.equals(o.color) || !composite.equals(o.composite) ||
|
||||
!font.equals(o.font) || !paint.equals(o.paint) ||
|
||||
!stroke.equals(o.stroke) || !transform.equals(o.transform) ||
|
||||
!xorMode.equals(o.xorMode) ||
|
||||
((clip == null || o.clip == null) && clip != o.clip) ||
|
||||
(clip != null && !clip.equals(o.clip)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(hints, background, color, composite, font, paint,
|
||||
stroke, transform, xorMode, clip);
|
||||
}
|
||||
|
||||
public boolean isDefault() {
|
||||
return hints.isEmpty() && background.equals(DEFAULT_BACKGROUND) &&
|
||||
color.equals(DEFAULT_COLOR) && composite.equals(DEFAULT_COMPOSITE) &&
|
||||
font.equals(DEFAULT_FONT) && paint.equals(DEFAULT_PAINT) &&
|
||||
stroke.equals(DEFAULT_STROKE) && transform.equals(DEFAULT_TRANSFORM) &&
|
||||
xorMode.equals(DEFAULT_XOR_MODE) && clip == DEFAULT_CLIP;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.pdf.PDFProcessor;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* {@code Graphics2D} implementation that saves all operations to a string
|
||||
* in the <i>Portable Document Format</i> (PDF).
|
||||
*/
|
||||
public class PDFGraphics2D extends ProcessingPipeline {
|
||||
private final Processor processor;
|
||||
|
||||
/**
|
||||
* Initializes a new VectorGraphics2D pipeline for translating Graphics2D
|
||||
* commands to PDF data. The document dimensions must be specified as
|
||||
* parameters.
|
||||
*
|
||||
* @param x Left offset.
|
||||
* @param y Top offset
|
||||
* @param width Width.
|
||||
* @param height Height.
|
||||
*/
|
||||
public PDFGraphics2D(double x, double y, double width, double height) {
|
||||
super(x, y, width, height);
|
||||
processor = new PDFProcessor();
|
||||
|
||||
// TODO: Default graphics state does not need to be printed in the document
|
||||
setColor(Color.BLACK);
|
||||
setStroke(new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, null, 0f));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Processor getProcessor() {
|
||||
return processor;
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.util.PageSize;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Base class for convenience implementations of {@code VectorGraphics2D}.
|
||||
*/
|
||||
public abstract class ProcessingPipeline extends VectorGraphics2D {
|
||||
private final PageSize pageSize;
|
||||
|
||||
/**
|
||||
* Initializes a processing pipeline.
|
||||
*
|
||||
* @param x Left offset.
|
||||
* @param y Top offset
|
||||
* @param width Width.
|
||||
* @param height Height.
|
||||
*/
|
||||
public ProcessingPipeline(double x, double y, double width, double height) {
|
||||
pageSize = new PageSize(x, y, width, height);
|
||||
}
|
||||
|
||||
public PageSize getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
protected abstract Processor getProcessor();
|
||||
|
||||
public void writeTo(OutputStream out) throws IOException {
|
||||
Document doc = getProcessor().process(getCommands(), getPageSize());
|
||||
doc.write(out);
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try {
|
||||
writeTo(out);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.util.PageSize;
|
||||
|
||||
public interface Processor {
|
||||
Document process(Iterable<Command<?>> commands, PageSize pageSize);
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.svg.SVGProcessor;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* {@code Graphics2D} implementation that saves all operations to a string
|
||||
* in the <i>Scaled Vector Graphics</i> (SVG) format.
|
||||
*/
|
||||
public class SVGGraphics2D extends ProcessingPipeline {
|
||||
private final Processor processor;
|
||||
|
||||
/**
|
||||
* Initializes a new VectorGraphics2D pipeline for translating Graphics2D
|
||||
* commands to SVG data. The document dimensions must be specified as
|
||||
* parameters.
|
||||
*
|
||||
* @param x Left offset.
|
||||
* @param y Top offset
|
||||
* @param width Width.
|
||||
* @param height Height.
|
||||
*/
|
||||
public SVGGraphics2D(double x, double y, double width, double height) {
|
||||
super(x, y, width, height);
|
||||
processor = new SVGProcessor();
|
||||
|
||||
// Make graphics state match default state of Graphics2D
|
||||
setColor(Color.BLACK);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Processor getProcessor() {
|
||||
return processor;
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.util.PageSize;
|
||||
|
||||
public abstract class SizedDocument implements Document {
|
||||
private final PageSize pageSize;
|
||||
|
||||
public SizedDocument(PageSize pageSize) {
|
||||
this.pageSize = pageSize;
|
||||
}
|
||||
|
||||
public PageSize getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,894 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.CreateCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DisposeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawImageCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawShapeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawStringCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.FillShapeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.RotateCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.ScaleCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetBackgroundCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetClipCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetColorCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetCompositeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetFontCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetHintCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetPaintCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetStrokeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetTransformCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetXORModeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.ShearCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.TransformCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.TranslateCommand;
|
||||
import org.xbib.graphics.chart.io.vector.util.GraphicsUtils;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Image;
|
||||
import java.awt.Paint;
|
||||
import java.awt.Polygon;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.RenderingHints.Key;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Arc2D;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.awt.image.AffineTransformOp;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.BufferedImageOp;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.awt.image.renderable.RenderableImage;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Base for classes that want to implement vector export.
|
||||
*/
|
||||
public class VectorGraphics2D extends Graphics2D implements Cloneable {
|
||||
/**
|
||||
* List of operations that were performed on this graphics object and its
|
||||
* derived objects.
|
||||
*/
|
||||
private final List<Command<?>> commands;
|
||||
/**
|
||||
* Device configuration settings.
|
||||
*/
|
||||
//private final GraphicsConfiguration deviceConfig;
|
||||
/**
|
||||
* Context settings used to render fonts.
|
||||
*/
|
||||
private final FontRenderContext fontRenderContext;
|
||||
/**
|
||||
* Flag that tells whether this graphics object has been disposed.
|
||||
*/
|
||||
private boolean disposed;
|
||||
|
||||
private GraphicsState state;
|
||||
|
||||
private Graphics2D _debug_validate_graphics;
|
||||
|
||||
public VectorGraphics2D() {
|
||||
commands = new LinkedList<Command<?>>();
|
||||
emit(new CreateCommand(this));
|
||||
fontRenderContext = new FontRenderContext(null, false, true);
|
||||
|
||||
state = new GraphicsState();
|
||||
|
||||
BufferedImage _debug_validate_bimg = new BufferedImage(200, 250, BufferedImage.TYPE_INT_ARGB);
|
||||
_debug_validate_graphics = (Graphics2D) _debug_validate_bimg.getGraphics();
|
||||
_debug_validate_graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
}
|
||||
|
||||
private static Shape intersectShapes(Shape s1, Shape s2) {
|
||||
if (s1 instanceof Rectangle2D && s2 instanceof Rectangle2D) {
|
||||
Rectangle2D r1 = (Rectangle2D) s1;
|
||||
Rectangle2D r2 = (Rectangle2D) s2;
|
||||
double x1 = Math.max(r1.getMinX(), r2.getMinX());
|
||||
double y1 = Math.max(r1.getMinY(), r2.getMinY());
|
||||
double x2 = Math.min(r1.getMaxX(), r2.getMaxX());
|
||||
double y2 = Math.min(r1.getMaxY(), r2.getMaxY());
|
||||
|
||||
Rectangle2D intersection = new Rectangle2D.Double();
|
||||
if ((x2 < x1) || (y2 < y1)) {
|
||||
intersection.setFrameFromDiagonal(0, 0, 0, 0);
|
||||
} else {
|
||||
intersection.setFrameFromDiagonal(x1, y1, x2, y2);
|
||||
}
|
||||
return intersection;
|
||||
} else {
|
||||
Area intersection = new Area(s1);
|
||||
intersection.intersect(new Area(s2));
|
||||
return intersection;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() throws CloneNotSupportedException {
|
||||
try {
|
||||
VectorGraphics2D clone = (VectorGraphics2D) super.clone();
|
||||
clone.state = (GraphicsState) state.clone();
|
||||
return clone;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRenderingHints(Map<?, ?> hints) {
|
||||
if (isDisposed()) {
|
||||
return;
|
||||
}
|
||||
for (Entry<?, ?> entry : hints.entrySet()) {
|
||||
setRenderingHint((Key) entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clip(Shape s) {
|
||||
_debug_validate_graphics.clip(s);
|
||||
Shape clipOld = getClip();
|
||||
|
||||
Shape clip = getClip();
|
||||
if ((clip != null) && (s != null)) {
|
||||
s = intersectShapes(clip, s);
|
||||
}
|
||||
setClip(s);
|
||||
|
||||
Shape clipNew = getClip();
|
||||
if ((clipNew == null || _debug_validate_graphics.getClip() == null) && clipNew != _debug_validate_graphics.getClip()) {
|
||||
System.err.println("clip() validation failed: clip(" + clipOld + ", " + s + ") => " + clipNew + " != " + _debug_validate_graphics.getClip());
|
||||
}
|
||||
if (clipNew != null && !GraphicsUtils.equals(clipNew, _debug_validate_graphics.getClip())) {
|
||||
System.err.println("clip() validation failed: clip(" + clipOld + ", " + s + ") => " + clipNew + " != " + _debug_validate_graphics.getClip());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Shape s) {
|
||||
if (isDisposed() || s == null) {
|
||||
return;
|
||||
}
|
||||
emit(new DrawShapeCommand(s));
|
||||
|
||||
_debug_validate_graphics.draw(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawGlyphVector(GlyphVector g, float x, float y) {
|
||||
Shape s = g.getOutline(x, y);
|
||||
draw(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {
|
||||
BufferedImage bimg = getTransformedImage(img, xform);
|
||||
return drawImage(bimg, bimg.getMinX(), bimg.getMinY(),
|
||||
bimg.getWidth(), bimg.getHeight(), null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a transformed version of an image.
|
||||
*
|
||||
* @param image Image to be transformed
|
||||
* @param xform Affine transform to be applied
|
||||
* @return Image with transformed content
|
||||
*/
|
||||
private BufferedImage getTransformedImage(Image image,
|
||||
AffineTransform xform) {
|
||||
Integer interpolationType =
|
||||
(Integer) getRenderingHint(RenderingHints.KEY_INTERPOLATION);
|
||||
if (RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR
|
||||
.equals(interpolationType)) {
|
||||
interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
|
||||
} else if (RenderingHints.VALUE_INTERPOLATION_BILINEAR
|
||||
.equals(interpolationType)) {
|
||||
interpolationType = AffineTransformOp.TYPE_BILINEAR;
|
||||
} else {
|
||||
interpolationType = AffineTransformOp.TYPE_BICUBIC;
|
||||
}
|
||||
AffineTransformOp op = new AffineTransformOp(xform, interpolationType);
|
||||
BufferedImage bufferedImage = GraphicsUtils.toBufferedImage(image);
|
||||
return op.filter(bufferedImage, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) {
|
||||
if (op != null) {
|
||||
img = op.filter(img, null);
|
||||
}
|
||||
drawImage(img, x, y, img.getWidth(), img.getHeight(), null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
|
||||
drawRenderedImage(img.createDefaultRendering(), xform);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
|
||||
BufferedImage bimg = GraphicsUtils.toBufferedImage(img);
|
||||
drawImage(bimg, xform, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString(String str, int x, int y) {
|
||||
drawString(str, (float) x, (float) y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString(String str, float x, float y) {
|
||||
if (isDisposed() || str == null || str.trim().length() == 0) {
|
||||
return;
|
||||
}
|
||||
boolean isTextAsVectors = false;
|
||||
if (isTextAsVectors) {
|
||||
TextLayout layout = new TextLayout(str, getFont(),
|
||||
getFontRenderContext());
|
||||
Shape s = layout.getOutline(
|
||||
AffineTransform.getTranslateInstance(x, y));
|
||||
fill(s);
|
||||
} else {
|
||||
emit(new DrawStringCommand(str, x, y));
|
||||
|
||||
_debug_validate_graphics.drawString(str, x, y);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString(AttributedCharacterIterator iterator, int x, int y) {
|
||||
drawString(iterator, (float) x, (float) y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawString(AttributedCharacterIterator iterator, float x,
|
||||
float y) {
|
||||
// TODO Draw styled text
|
||||
StringBuilder buf = new StringBuilder();
|
||||
for (char c = iterator.first(); c != AttributedCharacterIterator.DONE;
|
||||
c = iterator.next()) {
|
||||
buf.append(c);
|
||||
}
|
||||
drawString(buf.toString(), x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fill(Shape s) {
|
||||
if (isDisposed() || s == null) {
|
||||
return;
|
||||
}
|
||||
emit(new FillShapeCommand(s));
|
||||
|
||||
_debug_validate_graphics.fill(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getBackground() {
|
||||
return state.getBackground();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackground(Color color) {
|
||||
if (isDisposed() || color == null || getColor().equals(color)) {
|
||||
return;
|
||||
}
|
||||
emit(new SetBackgroundCommand(color));
|
||||
state.setBackground(color);
|
||||
|
||||
_debug_validate_graphics.setBackground(color);
|
||||
if (!getBackground().equals(_debug_validate_graphics.getBackground())) {
|
||||
System.err.println("setBackground() validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Composite getComposite() {
|
||||
return state.getComposite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setComposite(Composite comp) {
|
||||
if (isDisposed()) {
|
||||
return;
|
||||
}
|
||||
if (comp == null) {
|
||||
throw new IllegalArgumentException("Cannot set a null composite.");
|
||||
}
|
||||
emit(new SetCompositeCommand(comp));
|
||||
state.setComposite(comp);
|
||||
|
||||
_debug_validate_graphics.setComposite(comp);
|
||||
if (!getComposite().equals(_debug_validate_graphics.getComposite())) {
|
||||
System.err.println("setComposite() validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraphicsConfiguration getDeviceConfiguration() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FontRenderContext getFontRenderContext() {
|
||||
return fontRenderContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Paint getPaint() {
|
||||
return state.getPaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPaint(Paint paint) {
|
||||
if (isDisposed() || paint == null) {
|
||||
return;
|
||||
}
|
||||
if (paint instanceof Color) {
|
||||
setColor((Color) paint);
|
||||
return;
|
||||
}
|
||||
if (getPaint().equals(paint)) {
|
||||
return;
|
||||
}
|
||||
emit(new SetPaintCommand(paint));
|
||||
state.setPaint(paint);
|
||||
|
||||
_debug_validate_graphics.setPaint(paint);
|
||||
if (!getPaint().equals(_debug_validate_graphics.getPaint())) {
|
||||
System.err.println("setPaint() validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getRenderingHint(Key hintKey) {
|
||||
if (RenderingHints.KEY_ANTIALIASING.equals(hintKey)) {
|
||||
return RenderingHints.VALUE_ANTIALIAS_OFF;
|
||||
} else if (RenderingHints.KEY_TEXT_ANTIALIASING.equals(hintKey)) {
|
||||
return RenderingHints.VALUE_TEXT_ANTIALIAS_OFF;
|
||||
} else if (RenderingHints.KEY_FRACTIONALMETRICS.equals(hintKey)) {
|
||||
return RenderingHints.VALUE_FRACTIONALMETRICS_ON;
|
||||
}
|
||||
return state.getHints().get(hintKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RenderingHints getRenderingHints() {
|
||||
return (RenderingHints) state.getHints().clone();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRenderingHints(Map<?, ?> hints) {
|
||||
if (isDisposed()) {
|
||||
return;
|
||||
}
|
||||
state.getHints().clear();
|
||||
for (Entry<?, ?> hint : hints.entrySet()) {
|
||||
setRenderingHint((Key) hint.getKey(), hint.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stroke getStroke() {
|
||||
return state.getStroke();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStroke(Stroke s) {
|
||||
if (isDisposed()) {
|
||||
return;
|
||||
}
|
||||
if (s == null) {
|
||||
throw new IllegalArgumentException("Cannot set a null stroke.");
|
||||
}
|
||||
emit(new SetStrokeCommand(s));
|
||||
state.setStroke(s);
|
||||
|
||||
_debug_validate_graphics.setStroke(s);
|
||||
if (!getStroke().equals(_debug_validate_graphics.getStroke())) {
|
||||
System.err.println("setStroke() validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
|
||||
Shape hitShape = s;
|
||||
if (onStroke) {
|
||||
hitShape = getStroke().createStrokedShape(hitShape);
|
||||
}
|
||||
hitShape = state.transformShape(hitShape);
|
||||
boolean hit = hitShape.intersects(rect);
|
||||
|
||||
boolean _debug_hit = _debug_validate_graphics.hit(rect, s, onStroke);
|
||||
if (hit != _debug_hit) {
|
||||
System.err.println("setClip() validation failed");
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRenderingHint(Key hintKey, Object hintValue) {
|
||||
if (isDisposed()) {
|
||||
return;
|
||||
}
|
||||
state.getHints().put(hintKey, hintValue);
|
||||
emit(new SetHintCommand(hintKey, hintValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AffineTransform getTransform() {
|
||||
return new AffineTransform(state.getTransform());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransform(AffineTransform tx) {
|
||||
if (isDisposed() || tx == null || state.getTransform().equals(tx)) {
|
||||
return;
|
||||
}
|
||||
emit(new SetTransformCommand(tx));
|
||||
state.setTransform(tx);
|
||||
|
||||
_debug_validate_graphics.setTransform(tx);
|
||||
if (!getTransform().equals(_debug_validate_graphics.getTransform())) {
|
||||
System.err.println("setTransform() validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shear(double shx, double shy) {
|
||||
if (shx == 0.0 && shy == 0.0) {
|
||||
return;
|
||||
}
|
||||
AffineTransform txNew = getTransform();
|
||||
txNew.shear(shx, shy);
|
||||
emit(new ShearCommand(shx, shy));
|
||||
state.setTransform(txNew);
|
||||
|
||||
_debug_validate_graphics.shear(shx, shy);
|
||||
if (!getTransform().equals(_debug_validate_graphics.getTransform())) {
|
||||
System.err.println("shear() validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void transform(AffineTransform tx) {
|
||||
if (tx.isIdentity()) {
|
||||
return;
|
||||
}
|
||||
AffineTransform txNew = getTransform();
|
||||
txNew.concatenate(tx);
|
||||
emit(new TransformCommand(tx));
|
||||
state.setTransform(txNew);
|
||||
|
||||
_debug_validate_graphics.transform(tx);
|
||||
if (!getTransform().equals(_debug_validate_graphics.getTransform())) {
|
||||
System.err.println("transform() validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(int x, int y) {
|
||||
translate((double) x, (double) y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void translate(double tx, double ty) {
|
||||
if (tx == 0.0 && ty == 0.0) {
|
||||
return;
|
||||
}
|
||||
AffineTransform txNew = getTransform();
|
||||
txNew.translate(tx, ty);
|
||||
emit(new TranslateCommand(tx, ty));
|
||||
state.setTransform(txNew);
|
||||
|
||||
_debug_validate_graphics.translate(tx, ty);
|
||||
if (!getTransform().equals(_debug_validate_graphics.getTransform())) {
|
||||
System.err.println("translate() validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rotate(double theta) {
|
||||
rotate(theta, 0.0, 0.0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rotate(double theta, double x, double y) {
|
||||
if (theta == 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
AffineTransform txNew = getTransform();
|
||||
if (x == 0.0 && y == 0.0) {
|
||||
txNew.rotate(theta);
|
||||
} else {
|
||||
txNew.rotate(theta, x, y);
|
||||
}
|
||||
|
||||
emit(new RotateCommand(theta, x, y));
|
||||
state.setTransform(txNew);
|
||||
|
||||
if (x == 0.0 && y == 0.0) {
|
||||
_debug_validate_graphics.rotate(theta);
|
||||
if (!getTransform().equals(_debug_validate_graphics.getTransform())) {
|
||||
System.err.println("rotate(theta) validation failed");
|
||||
}
|
||||
} else {
|
||||
_debug_validate_graphics.rotate(theta, x, y);
|
||||
if (!getTransform().equals(_debug_validate_graphics.getTransform())) {
|
||||
System.err.println("rotate(theta,x,y) validation failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scale(double sx, double sy) {
|
||||
if (sx == 1.0 && sy == 1.0) {
|
||||
return;
|
||||
}
|
||||
AffineTransform txNew = getTransform();
|
||||
txNew.scale(sx, sy);
|
||||
emit(new ScaleCommand(sx, sy));
|
||||
state.setTransform(txNew);
|
||||
|
||||
_debug_validate_graphics.scale(sx, sy);
|
||||
if (!getTransform().equals(_debug_validate_graphics.getTransform())) {
|
||||
System.err.println("scale() validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearRect(int x, int y, int width, int height) {
|
||||
Color colorOld = getColor();
|
||||
setColor(getBackground());
|
||||
fillRect(x, y, width, height);
|
||||
setColor(colorOld);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clipRect(int x, int y, int width, int height) {
|
||||
clip(new Rectangle(x, y, width, height));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copyArea(int x, int y, int width, int height, int dx, int dy) {
|
||||
// TODO Implement
|
||||
//throw new UnsupportedOperationException("copyArea() isn't supported by VectorGraphics2D.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Graphics create() {
|
||||
if (isDisposed()) {
|
||||
return null;
|
||||
}
|
||||
VectorGraphics2D clone = null;
|
||||
try {
|
||||
clone = (VectorGraphics2D) this.clone();
|
||||
emit(new CreateCommand(clone));
|
||||
} catch (CloneNotSupportedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (clone != null) {
|
||||
clone._debug_validate_graphics = (Graphics2D) _debug_validate_graphics.create();
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
if (isDisposed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
emit(new DisposeCommand(this));
|
||||
|
||||
disposed = true;
|
||||
|
||||
_debug_validate_graphics.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawArc(int x, int y, int width, int height, int startAngle,
|
||||
int arcAngle) {
|
||||
draw(new Arc2D.Double(x, y, width, height,
|
||||
startAngle, arcAngle, Arc2D.OPEN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
|
||||
return drawImage(img, x, y, img.getWidth(observer),
|
||||
img.getHeight(observer), null, observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drawImage(Image img, int x, int y, Color bgcolor,
|
||||
ImageObserver observer) {
|
||||
return drawImage(img, x, y, img.getWidth(observer),
|
||||
img.getHeight(observer), bgcolor, observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drawImage(Image img, int x, int y, int width, int height,
|
||||
ImageObserver observer) {
|
||||
return drawImage(img, x, y, width, height, null, observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drawImage(Image img, int x, int y, int width, int height,
|
||||
Color bgcolor, ImageObserver observer) {
|
||||
if (isDisposed() || img == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int imageWidth = img.getWidth(observer);
|
||||
int imageHeight = img.getHeight(observer);
|
||||
Rectangle bounds = new Rectangle(x, y, width, height);
|
||||
|
||||
if (bgcolor != null) {
|
||||
// Fill rectangle with bgcolor
|
||||
Color bgcolorOld = getColor();
|
||||
setColor(bgcolor);
|
||||
fill(bounds);
|
||||
setColor(bgcolorOld);
|
||||
}
|
||||
|
||||
emit(new DrawImageCommand(img, imageWidth, imageHeight, x, y, width, height));
|
||||
|
||||
_debug_validate_graphics.drawImage(img, x, y, width, height, bgcolor, observer);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
|
||||
int sx1, int sy1, int sx2, int sy2, ImageObserver observer) {
|
||||
return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null,
|
||||
observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2,
|
||||
int sx1, int sy1, int sx2, int sy2, Color bgcolor,
|
||||
ImageObserver observer) {
|
||||
if (img == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
int sx = Math.min(sx1, sx2);
|
||||
int sy = Math.min(sy1, sy2);
|
||||
int sw = Math.abs(sx2 - sx1);
|
||||
int sh = Math.abs(sy2 - sy1);
|
||||
int dx = Math.min(dx1, dx2);
|
||||
int dy = Math.min(dy1, dy2);
|
||||
int dw = Math.abs(dx2 - dx1);
|
||||
int dh = Math.abs(dy2 - dy1);
|
||||
|
||||
// Draw image on rectangle
|
||||
BufferedImage bufferedImg = GraphicsUtils.toBufferedImage(img);
|
||||
Image cropped = bufferedImg.getSubimage(sx, sy, sw, sh);
|
||||
return drawImage(cropped, dx, dy, dw, dh, bgcolor, observer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawLine(int x1, int y1, int x2, int y2) {
|
||||
draw(new Line2D.Double(x1, y1, x2, y2));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOval(int x, int y, int width, int height) {
|
||||
draw(new Ellipse2D.Double(x, y, width, height));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawPolygon(Polygon p) {
|
||||
draw(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {
|
||||
draw(new Polygon(xPoints, yPoints, nPoints));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {
|
||||
Path2D p = new Path2D.Float();
|
||||
for (int i = 0; i < nPoints; i++) {
|
||||
if (i > 0) {
|
||||
p.lineTo(xPoints[i], yPoints[i]);
|
||||
} else {
|
||||
p.moveTo(xPoints[i], yPoints[i]);
|
||||
}
|
||||
}
|
||||
draw(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawRect(int x, int y, int width, int height) {
|
||||
draw(new Rectangle(x, y, width, height));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawRoundRect(int x, int y, int width, int height,
|
||||
int arcWidth, int arcHeight) {
|
||||
draw(new RoundRectangle2D.Double(x, y, width, height,
|
||||
arcWidth, arcHeight));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillArc(int x, int y, int width, int height,
|
||||
int startAngle, int arcAngle) {
|
||||
fill(new Arc2D.Double(x, y, width, height,
|
||||
startAngle, arcAngle, Arc2D.PIE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillOval(int x, int y, int width, int height) {
|
||||
fill(new Ellipse2D.Double(x, y, width, height));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillPolygon(Polygon p) {
|
||||
fill(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
|
||||
fill(new Polygon(xPoints, yPoints, nPoints));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillRect(int x, int y, int width, int height) {
|
||||
fill(new Rectangle(x, y, width, height));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillRoundRect(int x, int y, int width, int height,
|
||||
int arcWidth, int arcHeight) {
|
||||
fill(new RoundRectangle2D.Double(x, y, width, height,
|
||||
arcWidth, arcHeight));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Shape getClip() {
|
||||
return state.getClip();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClip(Shape clip) {
|
||||
if (isDisposed()) {
|
||||
return;
|
||||
}
|
||||
emit(new SetClipCommand(clip));
|
||||
state.setClip(clip);
|
||||
|
||||
_debug_validate_graphics.setClip(clip);
|
||||
if (getClip() == null) {
|
||||
if (_debug_validate_graphics.getClip() != null) {
|
||||
System.err.printf("setClip() validation failed: clip=null, validation=%s\n", _debug_validate_graphics.getClip());
|
||||
}
|
||||
} else if (!GraphicsUtils.equals(getClip(), _debug_validate_graphics.getClip())) {
|
||||
System.err.printf("setClip() validation failed: clip=%s, validation=%s\n", getClip(), _debug_validate_graphics.getClip());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rectangle getClipBounds() {
|
||||
if (getClip() == null) {
|
||||
return null;
|
||||
}
|
||||
return getClip().getBounds();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getColor() {
|
||||
return state.getColor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColor(Color c) {
|
||||
if (isDisposed() || c == null || getColor().equals(c)) {
|
||||
return;
|
||||
}
|
||||
emit(new SetColorCommand(c));
|
||||
state.setColor(c);
|
||||
state.setPaint(c);
|
||||
|
||||
_debug_validate_graphics.setColor(c);
|
||||
if (!getColor().equals(_debug_validate_graphics.getColor())) {
|
||||
System.err.println("setColor() validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Font getFont() {
|
||||
return state.getFont();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFont(Font font) {
|
||||
if (isDisposed() || (font != null && getFont().equals(font))) {
|
||||
return;
|
||||
}
|
||||
emit(new SetFontCommand(font));
|
||||
state.setFont(font);
|
||||
|
||||
_debug_validate_graphics.setFont(font);
|
||||
if (!getFont().equals(_debug_validate_graphics.getFont())) {
|
||||
System.err.println("setFont() validation failed");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FontMetrics getFontMetrics(Font f) {
|
||||
BufferedImage bi =
|
||||
new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
|
||||
Graphics g = bi.getGraphics();
|
||||
FontMetrics fontMetrics = g.getFontMetrics(getFont());
|
||||
g.dispose();
|
||||
return fontMetrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClip(int x, int y, int width, int height) {
|
||||
setClip(new Rectangle(x, y, width, height));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPaintMode() {
|
||||
setComposite(AlphaComposite.SrcOver);
|
||||
|
||||
_debug_validate_graphics.setPaintMode();
|
||||
}
|
||||
|
||||
public Color getXORMode() {
|
||||
return state.getXorMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setXORMode(Color c1) {
|
||||
if (isDisposed() || c1 == null) {
|
||||
return;
|
||||
}
|
||||
emit(new SetXORModeCommand(c1));
|
||||
state.setXorMode(c1);
|
||||
|
||||
_debug_validate_graphics.setXORMode(c1);
|
||||
}
|
||||
|
||||
private void emit(Command<?> command) {
|
||||
commands.add(command);
|
||||
}
|
||||
|
||||
protected Iterable<Command<?>> getCommands() {
|
||||
return commands;
|
||||
}
|
||||
|
||||
protected boolean isDisposed() {
|
||||
return disposed;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector;
|
||||
|
||||
import java.awt.RenderingHints;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class VectorHints {
|
||||
public static final Key KEY_EXPORT = new Key(0, "Vector export mode");
|
||||
public static final Object VALUE_EXPORT_READABILITY = new Value(KEY_EXPORT, 0, "Maximize readability for humans");
|
||||
public static final Object VALUE_EXPORT_QUALITY = new Value(KEY_EXPORT, 1, "Maximize render quality");
|
||||
public static final Object VALUE_EXPORT_SIZE = new Value(KEY_EXPORT, 2, "Minimize data size");
|
||||
public static final Key KEY_TEXT = new Key(1, "Text export mode");
|
||||
public static final Object VALUE_TEXT_DEFAULT = new Value(KEY_TEXT, 0, "Keep text");
|
||||
public static final Object VALUE_TEXT_VECTOR = new Value(KEY_TEXT, 1, "Convert text to vector shapes");
|
||||
|
||||
protected VectorHints() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static class Key extends RenderingHints.Key {
|
||||
private final String description;
|
||||
|
||||
public Key(int privateKey, String description) {
|
||||
super(privateKey);
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return intKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCompatibleValue(Object val) {
|
||||
return val instanceof Value && ((Value) val).isCompatibleKey(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Value {
|
||||
private static final Set<String> values = new HashSet<String>();
|
||||
private final Key key;
|
||||
private final int index;
|
||||
private final String description;
|
||||
|
||||
public Value(Key key, int index, String description) {
|
||||
this.key = key;
|
||||
this.index = index;
|
||||
this.description = description;
|
||||
register(this);
|
||||
}
|
||||
|
||||
private synchronized static void register(Value value) {
|
||||
String id = value.getId();
|
||||
if (values.contains(id)) {
|
||||
throw new ExceptionInInitializerError(
|
||||
"Duplicate index: " + value.getIndex());
|
||||
}
|
||||
values.add(id);
|
||||
}
|
||||
|
||||
public boolean isCompatibleKey(RenderingHints.Key key) {
|
||||
return this.key == key;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return key.getIndex() + ":" + getIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,476 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.eps;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.GraphicsState;
|
||||
import org.xbib.graphics.chart.io.vector.SizedDocument;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.CreateCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DisposeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawImageCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawShapeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawStringCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.FillShapeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.RotateCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.ScaleCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetClipCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetColorCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetCompositeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetFontCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetPaintCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetStrokeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetTransformCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.ShearCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.TransformCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.TranslateCommand;
|
||||
import org.xbib.graphics.chart.io.vector.util.ASCII85EncodeStream;
|
||||
import org.xbib.graphics.chart.io.vector.util.AlphaToMaskOp;
|
||||
import org.xbib.graphics.chart.io.vector.util.DataUtils;
|
||||
import org.xbib.graphics.chart.io.vector.util.FlateEncodeStream;
|
||||
import org.xbib.graphics.chart.io.vector.util.GraphicsUtils;
|
||||
import org.xbib.graphics.chart.io.vector.util.ImageDataStream;
|
||||
import org.xbib.graphics.chart.io.vector.util.ImageDataStream.Interleaving;
|
||||
import org.xbib.graphics.chart.io.vector.util.LineWrapOutputStream;
|
||||
import org.xbib.graphics.chart.io.vector.util.PageSize;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Image;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.geom.Arc2D;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class EPSDocument extends SizedDocument {
|
||||
/**
|
||||
* Constant to convert values from millimeters to PostScript® units
|
||||
* (1/72th inch).
|
||||
*/
|
||||
private static final double UNITS_PER_MM = 72.0 / 25.4;
|
||||
private static final String CHARSET = "ISO-8859-1";
|
||||
private static final String EOL = "\n";
|
||||
private static final int MAX_LINE_WIDTH = 255;
|
||||
private static final Pattern ELEMENT_SEPARATION_PATTERN = Pattern.compile("(.{1," + MAX_LINE_WIDTH + "})(\\s+|$)");
|
||||
|
||||
/**
|
||||
* Mapping of stroke endcap values from Java to PostScript®.
|
||||
*/
|
||||
private static final Map<Integer, Integer> STROKE_ENDCAPS = DataUtils.map(
|
||||
new Integer[]{BasicStroke.CAP_BUTT, BasicStroke.CAP_ROUND, BasicStroke.CAP_SQUARE},
|
||||
new Integer[]{0, 1, 2}
|
||||
);
|
||||
|
||||
/**
|
||||
* Mapping of line join values for path drawing from Java to
|
||||
* PostScript®.
|
||||
*/
|
||||
private static final Map<Integer, Integer> STROKE_LINEJOIN = DataUtils.map(
|
||||
new Integer[]{BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND, BasicStroke.JOIN_BEVEL},
|
||||
new Integer[]{0, 1, 2}
|
||||
);
|
||||
|
||||
private static final String FONT_LATIN1_SUFFIX = "Lat";
|
||||
|
||||
private final List<String> elements;
|
||||
|
||||
public EPSDocument(PageSize pageSize) {
|
||||
super(pageSize);
|
||||
elements = new LinkedList<String>();
|
||||
addHeader();
|
||||
}
|
||||
|
||||
private static String getOutput(Color c) {
|
||||
// TODO Handle transparency
|
||||
return String.valueOf(c.getRed() / 255.0) + " " + c.getGreen() / 255.0 + " " + c.getBlue() / 255.0 + " rgb";
|
||||
}
|
||||
|
||||
private static String getOutput(Shape s) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
out.append("newpath ");
|
||||
if (s instanceof Line2D) {
|
||||
Line2D l = (Line2D) s;
|
||||
out.append(l.getX1()).append(" ").append(l.getY1()).append(" M ")
|
||||
.append(l.getX2()).append(" ").append(l.getY2()).append(" L");
|
||||
} else if (s instanceof Rectangle2D) {
|
||||
Rectangle2D r = (Rectangle2D) s;
|
||||
out.append(r.getX()).append(" ").append(r.getY()).append(" ")
|
||||
.append(r.getWidth()).append(" ").append(r.getHeight())
|
||||
.append(" rect Z");
|
||||
} else if (s instanceof Ellipse2D) {
|
||||
Ellipse2D e = (Ellipse2D) s;
|
||||
double x = e.getX() + e.getWidth() / 2.0;
|
||||
double y = e.getY() + e.getHeight() / 2.0;
|
||||
double rx = e.getWidth() / 2.0;
|
||||
double ry = e.getHeight() / 2.0;
|
||||
out.append(x).append(" ").append(y).append(" ")
|
||||
.append(rx).append(" ").append(ry).append(" ")
|
||||
.append(360.0).append(" ").append(0.0)
|
||||
.append(" ellipse Z");
|
||||
} else if (s instanceof Arc2D) {
|
||||
Arc2D e = (Arc2D) s;
|
||||
double x = (e.getX() + e.getWidth() / 2.0);
|
||||
double y = (e.getY() + e.getHeight() / 2.0);
|
||||
double rx = e.getWidth() / 2.0;
|
||||
double ry = e.getHeight() / 2.0;
|
||||
double startAngle = -e.getAngleStart();
|
||||
double endAngle = -(e.getAngleStart() + e.getAngleExtent());
|
||||
out.append(x).append(" ").append(y).append(" ")
|
||||
.append(rx).append(" ").append(ry).append(" ")
|
||||
.append(startAngle).append(" ").append(endAngle)
|
||||
.append(" ellipse");
|
||||
if (e.getArcType() == Arc2D.CHORD) {
|
||||
out.append(" Z");
|
||||
} else if (e.getArcType() == Arc2D.PIE) {
|
||||
out.append(" ").append(x).append(" ").append(y).append(" L Z");
|
||||
}
|
||||
} else {
|
||||
PathIterator segments = s.getPathIterator(null);
|
||||
double[] coordsCur = new double[6];
|
||||
double[] pointPrev = new double[2];
|
||||
for (int i = 0; !segments.isDone(); i++, segments.next()) {
|
||||
if (i > 0) {
|
||||
out.append(" ");
|
||||
}
|
||||
int segmentType = segments.currentSegment(coordsCur);
|
||||
switch (segmentType) {
|
||||
case PathIterator.SEG_MOVETO:
|
||||
out.append(coordsCur[0]).append(" ").append(coordsCur[1])
|
||||
.append(" M");
|
||||
pointPrev[0] = coordsCur[0];
|
||||
pointPrev[1] = coordsCur[1];
|
||||
break;
|
||||
case PathIterator.SEG_LINETO:
|
||||
out.append(coordsCur[0]).append(" ").append(coordsCur[1])
|
||||
.append(" L");
|
||||
pointPrev[0] = coordsCur[0];
|
||||
pointPrev[1] = coordsCur[1];
|
||||
break;
|
||||
case PathIterator.SEG_CUBICTO:
|
||||
out.append(coordsCur[0]).append(" ").append(coordsCur[1])
|
||||
.append(" ").append(coordsCur[2]).append(" ")
|
||||
.append(coordsCur[3]).append(" ").append(coordsCur[4])
|
||||
.append(" ").append(coordsCur[5]).append(" C");
|
||||
pointPrev[0] = coordsCur[4];
|
||||
pointPrev[1] = coordsCur[5];
|
||||
break;
|
||||
case PathIterator.SEG_QUADTO:
|
||||
double x1 = pointPrev[0] + 2.0 / 3.0 * (coordsCur[0] - pointPrev[0]);
|
||||
double y1 = pointPrev[1] + 2.0 / 3.0 * (coordsCur[1] - pointPrev[1]);
|
||||
double x2 = coordsCur[0] + 1.0 / 3.0 * (coordsCur[2] - coordsCur[0]);
|
||||
double y2 = coordsCur[1] + 1.0 / 3.0 * (coordsCur[3] - coordsCur[1]);
|
||||
double x3 = coordsCur[2];
|
||||
double y3 = coordsCur[3];
|
||||
out.append(x1).append(" ").append(y1).append(" ")
|
||||
.append(x2).append(" ").append(y2).append(" ")
|
||||
.append(x3).append(" ").append(y3).append(" C");
|
||||
pointPrev[0] = x3;
|
||||
pointPrev[1] = y3;
|
||||
break;
|
||||
case PathIterator.SEG_CLOSE:
|
||||
out.append("Z");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown path operation.");
|
||||
}
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private static String getOutput(Image image, int imageWidth, int imageHeight,
|
||||
double x, double y, double width, double height) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
|
||||
BufferedImage bufferedImage = GraphicsUtils.toBufferedImage(image);
|
||||
int bands = bufferedImage.getSampleModel().getNumBands();
|
||||
int bitsPerSample = DataUtils.max(bufferedImage.getSampleModel().getSampleSize());
|
||||
bitsPerSample = (int) (Math.ceil(bitsPerSample / 8.0) * 8.0);
|
||||
if (bands > 3) {
|
||||
bands = 3;
|
||||
}
|
||||
|
||||
out.append("gsave").append(EOL);
|
||||
if (x != 0.0 || y != 0.0) {
|
||||
out.append(x).append(" ").append(y).append(" translate").append(EOL);
|
||||
}
|
||||
if (width != 1.0 || height != 1.0) {
|
||||
out.append(width).append(" ").append(height).append(" scale").append(EOL);
|
||||
}
|
||||
|
||||
int decodeScale = 1;
|
||||
if (bufferedImage.getColorModel().hasAlpha()) {
|
||||
// TODO Use different InterleaveType (2 or 3) for more efficient compression
|
||||
out.append("<< /ImageType 3 /InterleaveType 1 ")
|
||||
.append("/MaskDict ")
|
||||
.append(imageWidth).append(" ").append(imageHeight).append(" ")
|
||||
.append(1).append(" ").append(bitsPerSample).append(" ").append(decodeScale).append(" ")
|
||||
.append(false).append(" ").append(0).append(" imgdict ")
|
||||
.append("/DataDict ")
|
||||
.append(imageWidth).append(" ").append(imageHeight).append(" ")
|
||||
.append(bands).append(" ").append(bitsPerSample).append(" ").append(decodeScale).append(" ")
|
||||
.append(true).append(" currentfile /ASCII85Decode filter ")
|
||||
.append("<< /BitsPerComponent ").append(bitsPerSample).append(" >> ")
|
||||
.append("/FlateDecode filter ")
|
||||
.append("imgdict ")
|
||||
.append(">> image").append(EOL);
|
||||
|
||||
// Convert alpha values to binary mask
|
||||
// FIXME Do alpha conversion in a preprocessing step on commands
|
||||
bufferedImage = new AlphaToMaskOp(true).filter(bufferedImage, null);
|
||||
output(bufferedImage, out);
|
||||
} else {
|
||||
if (bands == 1) {
|
||||
out.append("/DeviceGray setcolorspace").append(EOL);
|
||||
}
|
||||
if (bufferedImage.getType() == BufferedImage.TYPE_BYTE_BINARY) {
|
||||
decodeScale = 255;
|
||||
}
|
||||
out.append(imageWidth).append(" ").append(imageHeight).append(" ")
|
||||
.append(bands).append(" ").append(bitsPerSample).append(" ").append(decodeScale).append(" ")
|
||||
.append(true).append(" currentfile /ASCII85Decode filter ")
|
||||
.append("<< /BitsPerComponent ").append(bitsPerSample).append(" >> ")
|
||||
.append("/FlateDecode filter ")
|
||||
.append("imgdict ")
|
||||
.append("image").append(EOL);
|
||||
output(bufferedImage, out);
|
||||
}
|
||||
|
||||
out.append("grestore");
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private static void output(BufferedImage image, StringBuilder out) {
|
||||
InputStream imageDataStream =
|
||||
new ImageDataStream(image, Interleaving.SAMPLE);
|
||||
ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
|
||||
OutputStream compressionStream = new FlateEncodeStream(
|
||||
new ASCII85EncodeStream(
|
||||
new LineWrapOutputStream(outBytes, 80)));
|
||||
try {
|
||||
DataUtils.transfer(imageDataStream, compressionStream, 1024);
|
||||
compressionStream.close();
|
||||
String compressed = outBytes.toString(CHARSET);
|
||||
out.append(compressed).append(EOL);
|
||||
} catch (IOException e) {
|
||||
// TODO Handle exception
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static String getOutput(String str, double x, double y) {
|
||||
|
||||
return "gsave 1 -1 scale " + x + " " + -y + " M " + getOutput(str) + " show " + "grestore";
|
||||
}
|
||||
|
||||
private static StringBuilder getOutput(String str) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
|
||||
// Escape text
|
||||
str = str.replaceAll("\\\\", "\\\\\\\\")
|
||||
.replaceAll("\t", "\\\\t")
|
||||
.replaceAll("\b", "\\\\b")
|
||||
.replaceAll("\f", "\\\\f")
|
||||
.replaceAll("\\(", "\\\\(")
|
||||
.replaceAll("\\)", "\\\\)")
|
||||
.replaceAll("[\r\n]", "");
|
||||
|
||||
out.append("(").append(str).append(")");
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private static String getOutput(Stroke s) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
if (s instanceof BasicStroke) {
|
||||
BasicStroke bs = (BasicStroke) s;
|
||||
out.append(bs.getLineWidth()).append(" setlinewidth ")
|
||||
.append(STROKE_LINEJOIN.get(bs.getLineJoin())).append(" setlinejoin ")
|
||||
.append(STROKE_ENDCAPS.get(bs.getEndCap())).append(" setlinecap ")
|
||||
.append("[").append(DataUtils.join(" ", bs.getDashArray())).append("] ")
|
||||
.append(bs.getDashPhase()).append(" setdash");
|
||||
} else {
|
||||
out.append("% Custom strokes aren't supported at the moment");
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private static String getOutput(Font font) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
font = GraphicsUtils.getPhysicalFont(font);
|
||||
String fontName = font.getPSName();
|
||||
|
||||
// Convert font to ISO-8859-1 encoding
|
||||
String fontNameLatin1 = fontName + FONT_LATIN1_SUFFIX;
|
||||
out.append("/").append(fontNameLatin1).append(" ")
|
||||
.append("/").append(font.getPSName()).append(" latinize ");
|
||||
|
||||
// Use encoded font
|
||||
out.append("/").append(fontNameLatin1).append(" ")
|
||||
.append(font.getSize2D()).append(" selectfont");
|
||||
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private void addHeader() {
|
||||
double x = getPageSize().x * UNITS_PER_MM,
|
||||
y = getPageSize().y * UNITS_PER_MM,
|
||||
width = getPageSize().width * UNITS_PER_MM,
|
||||
height = getPageSize().height * UNITS_PER_MM;
|
||||
elements.addAll(Arrays.asList(
|
||||
"%!PS-Adobe-3.0 EPSF-3.0",
|
||||
"%%BoundingBox: " + ((int) Math.floor(x)) + " " + ((int) Math.floor(y)) + " " + ((int) Math.ceil(x + width)) + " " + ((int) Math.ceil(y + height)),
|
||||
"%%HiResBoundingBox: " + x + " " + y + " " + (x + width) + " " + (y + height),
|
||||
"%%LanguageLevel: 3",
|
||||
"%%Pages: 1",
|
||||
"%%EndComments",
|
||||
"%%Page: 1 1",
|
||||
"/M /moveto load def",
|
||||
"/L /lineto load def",
|
||||
"/C /curveto load def",
|
||||
"/Z /closepath load def",
|
||||
"/RL /rlineto load def",
|
||||
"/rgb /setrgbcolor load def",
|
||||
"/rect { /height exch def /width exch def /y exch def /x exch def x y M width 0 RL 0 height RL width neg 0 RL } bind def",
|
||||
"/ellipse { /endangle exch def /startangle exch def /ry exch def /rx exch def /y exch def /x exch def /savematrix matrix currentmatrix def x y translate rx ry scale 0 0 1 startangle endangle arcn savematrix setmatrix } bind def",
|
||||
"/imgdict { /datastream exch def /hasdata exch def /decodeScale exch def /bits exch def /bands exch def /imgheight exch def /imgwidth exch def << /ImageType 1 /Width imgwidth /Height imgheight /BitsPerComponent bits /Decode [bands {0 decodeScale} repeat] /ImageMatrix [imgwidth 0 0 imgheight 0 0] hasdata { /DataSource datastream } if >> } bind def",
|
||||
"/latinize { /fontName exch def /fontNameNew exch def fontName findfont 0 dict copy begin /Encoding ISOLatin1Encoding def fontNameNew /FontName def currentdict end dup /FID undef fontNameNew exch definefont pop } bind def",
|
||||
getOutput(GraphicsState.DEFAULT_FONT),
|
||||
"gsave",
|
||||
"clipsave",
|
||||
"/DeviceRGB setcolorspace",
|
||||
"0 " + height + " translate",
|
||||
UNITS_PER_MM + " " + (-UNITS_PER_MM) + " scale",
|
||||
"/basematrix matrix currentmatrix def"
|
||||
));
|
||||
}
|
||||
|
||||
public void write(OutputStream out) throws IOException {
|
||||
OutputStreamWriter o = new OutputStreamWriter(out, CHARSET);
|
||||
for (String element : elements) {
|
||||
if (element == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Write current element in lines of 255 bytes (excluding line terminators)
|
||||
// Numbers must not be separated by line breaks or errors will occur
|
||||
// TODO: Integrate functionality into LineWrapOutputStream
|
||||
Matcher chunkMatcher = ELEMENT_SEPARATION_PATTERN.matcher(element);
|
||||
|
||||
boolean chunkFound = false;
|
||||
while (chunkMatcher.find()) {
|
||||
chunkFound = true;
|
||||
String chunk = chunkMatcher.group();
|
||||
o.write(chunk, 0, chunk.length());
|
||||
o.append(EOL);
|
||||
}
|
||||
if (!chunkFound) {
|
||||
// TODO: Exception, if no whitespace can be found in the chunk
|
||||
System.err.println("Unable to divide eps element into lines: " + element);
|
||||
}
|
||||
}
|
||||
o.append("%%EOF");
|
||||
o.flush();
|
||||
}
|
||||
|
||||
public void handle(Command<?> command) {
|
||||
if (command instanceof SetClipCommand) {
|
||||
SetClipCommand c = (SetClipCommand) command;
|
||||
Shape clip = c.getValue();
|
||||
elements.add("cliprestore");
|
||||
if (clip != null) {
|
||||
elements.add(getOutput(clip) + " clip");
|
||||
}
|
||||
} else if (command instanceof SetColorCommand) {
|
||||
SetColorCommand c = (SetColorCommand) command;
|
||||
elements.add(getOutput(c.getValue()));
|
||||
} else if (command instanceof SetCompositeCommand) {
|
||||
SetCompositeCommand c = (SetCompositeCommand) command;
|
||||
// TODO Implement composite rendering for EPS
|
||||
elements.add("% composite not yet implemented: " + c.getValue());
|
||||
} else if (command instanceof SetFontCommand) {
|
||||
SetFontCommand c = (SetFontCommand) command;
|
||||
elements.add(getOutput(c.getValue()));
|
||||
} else if (command instanceof SetPaintCommand) {
|
||||
SetPaintCommand c = (SetPaintCommand) command;
|
||||
// TODO Implement paint rendering for EPS
|
||||
elements.add("% paint not yet implemented: " + c.getValue());
|
||||
} else if (command instanceof SetStrokeCommand) {
|
||||
SetStrokeCommand c = (SetStrokeCommand) command;
|
||||
elements.add(getOutput(c.getValue()));
|
||||
} else if (command instanceof SetTransformCommand) {
|
||||
SetTransformCommand c = (SetTransformCommand) command;
|
||||
StringBuilder e = new StringBuilder();
|
||||
double[] matrix = new double[6];
|
||||
c.getValue().getMatrix(matrix);
|
||||
e.append("basematrix setmatrix [")
|
||||
.append(DataUtils.join(" ", matrix)).append("] concat");
|
||||
elements.add(e.toString());
|
||||
} else if (command instanceof RotateCommand) {
|
||||
RotateCommand c = (RotateCommand) command;
|
||||
StringBuilder e = new StringBuilder();
|
||||
double x = c.getCenterX();
|
||||
double y = c.getCenterY();
|
||||
boolean translated = x != 0.0 || y != 0.0;
|
||||
if (translated) {
|
||||
e.append(x).append(" ").append(y).append(" translate ");
|
||||
}
|
||||
e.append(Math.toDegrees(c.getTheta())).append(" rotate");
|
||||
if (translated) {
|
||||
e.append(" ");
|
||||
e.append(-x).append(" ").append(-y).append(" translate");
|
||||
}
|
||||
elements.add(e.toString());
|
||||
} else if (command instanceof ScaleCommand) {
|
||||
ScaleCommand c = (ScaleCommand) command;
|
||||
elements.add(DataUtils.format(c.getScaleX()) + " " + DataUtils.format(c.getScaleY()) + " scale");
|
||||
} else if (command instanceof ShearCommand) {
|
||||
ShearCommand c = (ShearCommand) command;
|
||||
elements.add("[1 " + DataUtils.format(c.getShearY()) + " " + DataUtils.format(c.getShearX()) + " 1 0 0] concat");
|
||||
} else if (command instanceof TransformCommand) {
|
||||
TransformCommand c = (TransformCommand) command;
|
||||
StringBuilder e = new StringBuilder();
|
||||
double[] matrix = new double[6];
|
||||
c.getValue().getMatrix(matrix);
|
||||
e.append("[").append(DataUtils.join(" ", matrix))
|
||||
.append("] concat");
|
||||
elements.add(e.toString());
|
||||
} else if (command instanceof TranslateCommand) {
|
||||
TranslateCommand c = (TranslateCommand) command;
|
||||
elements.add(String.valueOf(c.getDeltaX()) + " " + c.getDeltaY() + " translate");
|
||||
} else if (command instanceof DrawImageCommand) {
|
||||
DrawImageCommand c = (DrawImageCommand) command;
|
||||
String e = getOutput(c.getValue(),
|
||||
c.getImageWidth(), c.getImageHeight(),
|
||||
c.getX(), c.getY(), c.getWidth(), c.getHeight());
|
||||
elements.add(e);
|
||||
} else if (command instanceof DrawShapeCommand) {
|
||||
DrawShapeCommand c = (DrawShapeCommand) command;
|
||||
elements.add(getOutput(c.getValue()) + " stroke");
|
||||
} else if (command instanceof DrawStringCommand) {
|
||||
DrawStringCommand c = (DrawStringCommand) command;
|
||||
elements.add(getOutput(c.getValue(), c.getX(), c.getY()));
|
||||
} else if (command instanceof FillShapeCommand) {
|
||||
FillShapeCommand c = (FillShapeCommand) command;
|
||||
elements.add(getOutput(c.getValue()) + " fill");
|
||||
} else if (command instanceof CreateCommand) {
|
||||
elements.add("gsave");
|
||||
} else if (command instanceof DisposeCommand) {
|
||||
elements.add("grestore");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.eps;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.Document;
|
||||
import org.xbib.graphics.chart.io.vector.Processor;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.filters.FillPaintedShapeAsImageFilter;
|
||||
import org.xbib.graphics.chart.io.vector.util.PageSize;
|
||||
|
||||
public class EPSProcessor implements Processor {
|
||||
public Document process(Iterable<Command<?>> commands, PageSize pageSize) {
|
||||
// TODO Apply rotate(theta,x,y) => translate-rotate-translate filter
|
||||
// TODO Apply image transparency => image mask filter
|
||||
// TODO Apply optimization filter
|
||||
FillPaintedShapeAsImageFilter paintedShapeAsImageFilter = new FillPaintedShapeAsImageFilter(commands);
|
||||
EPSDocument doc = new EPSDocument(pageSize);
|
||||
for (Command<?> command : paintedShapeAsImageFilter) {
|
||||
doc.handle(command);
|
||||
}
|
||||
doc.close();
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
|
||||
public interface CommandHandler {
|
||||
void handle(Command<?> command);
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
|
||||
public abstract class AffineTransformCommand extends StateCommand<AffineTransform> {
|
||||
public AffineTransformCommand(AffineTransform transform) {
|
||||
super(transform);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public abstract class Command<T> {
|
||||
private final T value;
|
||||
|
||||
public Command(T value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format((Locale) null, "%s[value=%s]",
|
||||
getClass().getName(), getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == null || !getClass().equals(obj.getClass())) {
|
||||
return false;
|
||||
}
|
||||
Command<?> o = (Command<?>) obj;
|
||||
return value == o.value || value.equals(o.value);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.VectorGraphics2D;
|
||||
|
||||
public class CreateCommand extends StateCommand<VectorGraphics2D> {
|
||||
public CreateCommand(VectorGraphics2D graphics) {
|
||||
super(graphics);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.VectorGraphics2D;
|
||||
|
||||
public class DisposeCommand extends StateCommand<VectorGraphics2D> {
|
||||
public DisposeCommand(VectorGraphics2D graphics) {
|
||||
super(graphics);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.awt.Image;
|
||||
import java.util.Locale;
|
||||
|
||||
public class DrawImageCommand extends Command<Image> {
|
||||
private final int imageWidth;
|
||||
private final int imageHeight;
|
||||
private final double x;
|
||||
private final double y;
|
||||
private final double width;
|
||||
private final double height;
|
||||
|
||||
public DrawImageCommand(Image image, int imageWidth, int imageHeight,
|
||||
double x, double y, double width, double height) {
|
||||
super(image);
|
||||
this.imageWidth = imageWidth;
|
||||
this.imageHeight = imageHeight;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public int getImageWidth() {
|
||||
return imageWidth;
|
||||
}
|
||||
|
||||
public int getImageHeight() {
|
||||
return imageHeight;
|
||||
}
|
||||
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public double getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public double getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format((Locale) null,
|
||||
"%s[value=%s, imageWidth=%d, imageHeight=%d, x=%f, y=%f, width=%f, height=%f]",
|
||||
getClass().getName(), getValue(),
|
||||
getImageWidth(), getImageHeight(),
|
||||
getX(), getY(), getWidth(), getHeight());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.util.GraphicsUtils;
|
||||
|
||||
import java.awt.Shape;
|
||||
|
||||
public class DrawShapeCommand extends Command<Shape> {
|
||||
public DrawShapeCommand(Shape shape) {
|
||||
super(GraphicsUtils.clone(shape));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
|
||||
public class DrawStringCommand extends Command<String> {
|
||||
private final double x;
|
||||
private final double y;
|
||||
|
||||
public DrawStringCommand(String string, double x, double y) {
|
||||
super(string);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format((Locale) null, "%s[value=%s, x=%f, y=%f]",
|
||||
getClass().getName(), getValue(), getX(), getY());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.util.GraphicsUtils;
|
||||
|
||||
import java.awt.Shape;
|
||||
|
||||
public class FillShapeCommand extends Command<Shape> {
|
||||
public FillShapeCommand(Shape shape) {
|
||||
super(GraphicsUtils.clone(shape));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class Group extends Command<List<Command<?>>> {
|
||||
public Group() {
|
||||
super(new LinkedList<Command<?>>());
|
||||
}
|
||||
|
||||
public void add(Command<?> command) {
|
||||
List<Command<?>> group = getValue();
|
||||
group.add(command);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.util.Locale;
|
||||
|
||||
public class RotateCommand extends AffineTransformCommand {
|
||||
private final double theta;
|
||||
private final double centerX;
|
||||
private final double centerY;
|
||||
|
||||
public RotateCommand(double theta, double centerX, double centerY) {
|
||||
super(AffineTransform.getRotateInstance(theta, centerX, centerY));
|
||||
this.theta = theta;
|
||||
this.centerX = centerX;
|
||||
this.centerY = centerY;
|
||||
}
|
||||
|
||||
public double getTheta() {
|
||||
return theta;
|
||||
}
|
||||
|
||||
public double getCenterX() {
|
||||
return centerX;
|
||||
}
|
||||
|
||||
public double getCenterY() {
|
||||
return centerY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format((Locale) null,
|
||||
"%s[theta=%f, centerX=%f, centerY=%f, value=%s]",
|
||||
getClass().getName(), getTheta(), getCenterX(), getCenterY(),
|
||||
getValue());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.util.Locale;
|
||||
|
||||
public class ScaleCommand extends AffineTransformCommand {
|
||||
private final double scaleX;
|
||||
private final double scaleY;
|
||||
|
||||
public ScaleCommand(double scaleX, double scaleY) {
|
||||
super(AffineTransform.getScaleInstance(scaleX, scaleY));
|
||||
this.scaleX = scaleX;
|
||||
this.scaleY = scaleY;
|
||||
}
|
||||
|
||||
public double getScaleX() {
|
||||
return scaleX;
|
||||
}
|
||||
|
||||
public double getScaleY() {
|
||||
return scaleY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format((Locale) null,
|
||||
"%s[scaleX=%f, scaleY=%f, value=%s]", getClass().getName(),
|
||||
getScaleX(), getScaleY(), getValue());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
public class SetBackgroundCommand extends StateCommand<Color> {
|
||||
public SetBackgroundCommand(Color color) {
|
||||
super(color);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.awt.Shape;
|
||||
|
||||
public class SetClipCommand extends StateCommand<Shape> {
|
||||
public SetClipCommand(Shape shape) {
|
||||
super(shape);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
public class SetColorCommand extends StateCommand<Color> {
|
||||
public SetColorCommand(Color color) {
|
||||
super(color);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.awt.Composite;
|
||||
|
||||
public class SetCompositeCommand extends StateCommand<Composite> {
|
||||
public SetCompositeCommand(Composite composite) {
|
||||
super(composite);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.awt.Font;
|
||||
|
||||
public class SetFontCommand extends StateCommand<Font> {
|
||||
public SetFontCommand(Font font) {
|
||||
super(font);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class SetHintCommand extends StateCommand<Object> {
|
||||
private final Object key;
|
||||
|
||||
public SetHintCommand(Object hintKey, Object hintValue) {
|
||||
super(hintValue);
|
||||
key = hintKey;
|
||||
}
|
||||
|
||||
public Object getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format((Locale) null,
|
||||
"%s[key=%s, value=%s]", getClass().getName(),
|
||||
getKey(), getValue());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.awt.Paint;
|
||||
|
||||
public class SetPaintCommand extends StateCommand<Paint> {
|
||||
public SetPaintCommand(Paint paint) {
|
||||
super(paint);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.awt.Stroke;
|
||||
|
||||
public class SetStrokeCommand extends StateCommand<Stroke> {
|
||||
public SetStrokeCommand(Stroke stroke) {
|
||||
super(stroke);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
|
||||
public class SetTransformCommand extends StateCommand<AffineTransform> {
|
||||
public SetTransformCommand(AffineTransform transform) {
|
||||
super(new AffineTransform(transform));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
public class SetXORModeCommand extends StateCommand<Color> {
|
||||
public SetXORModeCommand(Color mode) {
|
||||
super(mode);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.util.Locale;
|
||||
|
||||
public class ShearCommand extends AffineTransformCommand {
|
||||
private final double shearX;
|
||||
private final double shearY;
|
||||
|
||||
public ShearCommand(double shearX, double shearY) {
|
||||
super(AffineTransform.getShearInstance(shearX, shearY));
|
||||
this.shearX = shearX;
|
||||
this.shearY = shearY;
|
||||
}
|
||||
|
||||
public double getShearX() {
|
||||
return shearX;
|
||||
}
|
||||
|
||||
public double getShearY() {
|
||||
return shearY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format((Locale) null,
|
||||
"%s[shearX=%f, shearY=%f, value=%s]", getClass().getName(),
|
||||
getShearX(), getShearY(), getValue());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
public abstract class StateCommand<T> extends Command<T> {
|
||||
public StateCommand(T value) {
|
||||
super(value);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
|
||||
public class TransformCommand extends AffineTransformCommand {
|
||||
private final AffineTransform transform;
|
||||
|
||||
public TransformCommand(AffineTransform transform) {
|
||||
super(transform);
|
||||
this.transform = new AffineTransform(transform);
|
||||
}
|
||||
|
||||
public AffineTransform getTransform() {
|
||||
return transform;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.commands;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.util.Locale;
|
||||
|
||||
public class TranslateCommand extends AffineTransformCommand {
|
||||
private final double deltaX;
|
||||
private final double deltaY;
|
||||
|
||||
public TranslateCommand(double x, double y) {
|
||||
super(AffineTransform.getTranslateInstance(x, y));
|
||||
this.deltaX = x;
|
||||
this.deltaY = y;
|
||||
}
|
||||
|
||||
public double getDeltaX() {
|
||||
return deltaX;
|
||||
}
|
||||
|
||||
public double getDeltaY() {
|
||||
return deltaY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format((Locale) null,
|
||||
"%s[deltaX=%f, deltaY=%f, value=%s]", getClass().getName(),
|
||||
getDeltaX(), getDeltaY(), getValue());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.filters;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.AffineTransformCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.CreateCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DisposeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetTransformCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.TransformCommand;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.NoninvertibleTransformException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
public class AbsoluteToRelativeTransformsFilter extends Filter {
|
||||
private Stack<AffineTransform> transforms;
|
||||
|
||||
public AbsoluteToRelativeTransformsFilter(Iterable<Command<?>> stream) {
|
||||
super(stream);
|
||||
transforms = new Stack<AffineTransform>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command<?> next() {
|
||||
Command<?> nextCommand = super.next();
|
||||
if (nextCommand instanceof AffineTransformCommand) {
|
||||
AffineTransformCommand affineTransformCommand = (AffineTransformCommand) nextCommand;
|
||||
getCurrentTransform().concatenate(affineTransformCommand.getValue());
|
||||
} else if (nextCommand instanceof CreateCommand) {
|
||||
AffineTransform newTransform = transforms.isEmpty() ? new AffineTransform() : new AffineTransform(getCurrentTransform());
|
||||
transforms.push(newTransform);
|
||||
} else if (nextCommand instanceof DisposeCommand) {
|
||||
transforms.pop();
|
||||
}
|
||||
|
||||
return nextCommand;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Command<?>> filter(Command<?> command) {
|
||||
if (command instanceof SetTransformCommand) {
|
||||
SetTransformCommand setTransformCommand = (SetTransformCommand) command;
|
||||
AffineTransform absoluteTransform = setTransformCommand.getValue();
|
||||
AffineTransform relativeTransform = new AffineTransform();
|
||||
try {
|
||||
AffineTransform invertedOldTransformation = getCurrentTransform().createInverse();
|
||||
relativeTransform.concatenate(invertedOldTransformation);
|
||||
} catch (NoninvertibleTransformException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
relativeTransform.concatenate(absoluteTransform);
|
||||
TransformCommand transformCommand = new TransformCommand(relativeTransform);
|
||||
return Arrays.<Command<?>>asList(transformCommand);
|
||||
}
|
||||
return Arrays.<Command<?>>asList(command);
|
||||
}
|
||||
|
||||
private AffineTransform getCurrentTransform() {
|
||||
return transforms.peek();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.filters;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DisposeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawImageCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.FillShapeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetPaintCommand;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class FillPaintedShapeAsImageFilter extends Filter {
|
||||
private SetPaintCommand lastSetPaintCommand;
|
||||
|
||||
public FillPaintedShapeAsImageFilter(Iterable<Command<?>> stream) {
|
||||
super(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command<?> next() {
|
||||
Command<?> nextCommand = super.next();
|
||||
|
||||
if (nextCommand instanceof SetPaintCommand) {
|
||||
lastSetPaintCommand = (SetPaintCommand) nextCommand;
|
||||
} else if (nextCommand instanceof DisposeCommand) {
|
||||
lastSetPaintCommand = null;
|
||||
}
|
||||
|
||||
return nextCommand;
|
||||
}
|
||||
|
||||
private DrawImageCommand getDrawImageCommand(FillShapeCommand shapeCommand, SetPaintCommand paintCommand) {
|
||||
Shape shape = shapeCommand.getValue();
|
||||
Rectangle2D shapeBounds = shape.getBounds2D();
|
||||
double x = shapeBounds.getX();
|
||||
double y = shapeBounds.getY();
|
||||
double width = shapeBounds.getWidth();
|
||||
double height = shapeBounds.getHeight();
|
||||
int imageWidth = (int) Math.round(width);
|
||||
int imageHeight = (int) Math.round(height);
|
||||
BufferedImage image = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D imageGraphics = (Graphics2D) image.getGraphics();
|
||||
imageGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
imageGraphics.scale(imageWidth / width, imageHeight / height);
|
||||
imageGraphics.translate(-shapeBounds.getX(), -shapeBounds.getY());
|
||||
imageGraphics.setPaint(paintCommand.getValue());
|
||||
imageGraphics.fill(shape);
|
||||
imageGraphics.dispose();
|
||||
|
||||
DrawImageCommand drawImageCommand = new DrawImageCommand(image, imageWidth, imageHeight, x, y, width, height);
|
||||
return drawImageCommand;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Command<?>> filter(Command<?> command) {
|
||||
if (lastSetPaintCommand != null && command instanceof FillShapeCommand) {
|
||||
FillShapeCommand fillShapeCommand = (FillShapeCommand) command;
|
||||
DrawImageCommand drawImageCommand = getDrawImageCommand(fillShapeCommand, lastSetPaintCommand);
|
||||
return Arrays.<Command<?>>asList(drawImageCommand);
|
||||
}
|
||||
|
||||
return Arrays.<Command<?>>asList(command);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.filters;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
|
||||
public abstract class Filter implements Iterable<Command<?>>, Iterator<Command<?>> {
|
||||
private final Queue<Command<?>> buffer;
|
||||
private final Iterator<Command<?>> iterator;
|
||||
|
||||
public Filter(Iterable<Command<?>> stream) {
|
||||
buffer = new LinkedList<Command<?>>();
|
||||
iterator = stream.iterator();
|
||||
}
|
||||
|
||||
public Iterator<Command<?>> iterator() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean hasNext() {
|
||||
findNextCommand();
|
||||
return !buffer.isEmpty();
|
||||
}
|
||||
|
||||
private void findNextCommand() {
|
||||
while (buffer.isEmpty() && iterator.hasNext()) {
|
||||
Command<?> command = iterator.next();
|
||||
List<Command<?>> commands = filter(command);
|
||||
if (commands != null) {
|
||||
buffer.addAll(commands);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Command<?> next() {
|
||||
findNextCommand();
|
||||
return buffer.poll();
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
}
|
||||
|
||||
protected abstract List<Command<?>> filter(Command<?> command);
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.filters;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Group;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public abstract class GroupingFilter extends Filter {
|
||||
private Group group;
|
||||
|
||||
public GroupingFilter(Iterable<Command<?>> stream) {
|
||||
super(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return group != null || super.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command<?> next() {
|
||||
if (group == null) {
|
||||
return super.next();
|
||||
}
|
||||
Group g = group;
|
||||
group = null;
|
||||
return g;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Command<?>> filter(Command<?> command) {
|
||||
boolean grouped = isGrouped(command);
|
||||
if (grouped) {
|
||||
if (group == null) {
|
||||
group = new Group();
|
||||
}
|
||||
group.add(command);
|
||||
return null;
|
||||
}
|
||||
return Arrays.<Command<?>>asList(command);
|
||||
}
|
||||
|
||||
protected abstract boolean isGrouped(Command<?> command);
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.filters;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.AffineTransformCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetHintCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.StateCommand;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
|
||||
public class OptimizeFilter extends Filter {
|
||||
private final Queue<Command<?>> buffer;
|
||||
|
||||
public OptimizeFilter(Iterable<Command<?>> stream) {
|
||||
super(stream);
|
||||
buffer = new LinkedList<Command<?>>();
|
||||
}
|
||||
|
||||
private static boolean isStateChange(Command<?> command) {
|
||||
return (command instanceof StateCommand) &&
|
||||
!(command instanceof AffineTransformCommand) &&
|
||||
!(command instanceof SetHintCommand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return super.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Command<?> next() {
|
||||
if (buffer.isEmpty()) {
|
||||
return super.next();
|
||||
}
|
||||
return buffer.poll();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Command<?>> filter(Command<?> command) {
|
||||
if (!isStateChange(command)) {
|
||||
return Arrays.<Command<?>>asList(command);
|
||||
}
|
||||
Iterator<Command<?>> i = buffer.iterator();
|
||||
Class<?> cls = command.getClass();
|
||||
while (i.hasNext()) {
|
||||
if (cls.equals(i.next().getClass())) {
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
buffer.add(command);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.filters;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.StateCommand;
|
||||
|
||||
|
||||
public class StateChangeGroupingFilter extends GroupingFilter {
|
||||
|
||||
public StateChangeGroupingFilter(Iterable<Command<?>> stream) {
|
||||
super(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isGrouped(Command<?> command) {
|
||||
return command instanceof StateCommand;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.pdf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public abstract class GeneratedPayload extends Payload {
|
||||
|
||||
public GeneratedPayload(boolean stream) {
|
||||
super(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getBytes() {
|
||||
try {
|
||||
for (byte b : generatePayload()) {
|
||||
super.write(b);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return super.getBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
throw new UnsupportedOperationException("Payload will be calculated and is read only.");
|
||||
}
|
||||
|
||||
protected abstract byte[] generatePayload();
|
||||
}
|
||||
|
|
@ -1,647 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.pdf;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.GraphicsState;
|
||||
import org.xbib.graphics.chart.io.vector.SizedDocument;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.AffineTransformCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.CreateCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DisposeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawImageCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawShapeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawStringCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.FillShapeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Group;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetBackgroundCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetClipCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetColorCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetFontCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetHintCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetPaintCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetStrokeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetTransformCommand;
|
||||
import org.xbib.graphics.chart.io.vector.util.DataUtils;
|
||||
import org.xbib.graphics.chart.io.vector.util.FlateEncodeStream;
|
||||
import org.xbib.graphics.chart.io.vector.util.FormattingWriter;
|
||||
import org.xbib.graphics.chart.io.vector.util.GraphicsUtils;
|
||||
import org.xbib.graphics.chart.io.vector.util.ImageDataStream;
|
||||
import org.xbib.graphics.chart.io.vector.util.ImageDataStream.Interleaving;
|
||||
import org.xbib.graphics.chart.io.vector.util.PageSize;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Image;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
public class PDFDocument extends SizedDocument {
|
||||
private static final String EOL = "\n";
|
||||
private static final String CHARSET = "ISO-8859-1";
|
||||
private static final String HEADER = "%PDF-1.4";
|
||||
private static final String FOOTER = "%%EOF";
|
||||
|
||||
/**
|
||||
* Constant to convert values from millimeters to PDF units (1/72th inch).
|
||||
*/
|
||||
private static final double MM_IN_UNITS = 72.0 / 25.4;
|
||||
|
||||
/**
|
||||
* Mapping of stroke endcap values from Java to PDF.
|
||||
*/
|
||||
private static final Map<Integer, Integer> STROKE_ENDCAPS = DataUtils.map(
|
||||
new Integer[]{BasicStroke.CAP_BUTT, BasicStroke.CAP_ROUND, BasicStroke.CAP_SQUARE},
|
||||
new Integer[]{0, 1, 2}
|
||||
);
|
||||
|
||||
/**
|
||||
* Mapping of line join values for path drawing from Java to PDF.
|
||||
*/
|
||||
private static final Map<Integer, Integer> STROKE_LINEJOIN = DataUtils.map(
|
||||
new Integer[]{BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND, BasicStroke.JOIN_BEVEL},
|
||||
new Integer[]{0, 1, 2}
|
||||
);
|
||||
|
||||
private final List<PDFObject> objects;
|
||||
private final Map<PDFObject, Long> xref;
|
||||
private final Map<Integer, PDFObject> images;
|
||||
private final Stack<GraphicsState> states;
|
||||
private int objectIdCounter;
|
||||
private PDFObject contents;
|
||||
private Resources resources;
|
||||
private boolean transformed;
|
||||
|
||||
private boolean compressed;
|
||||
|
||||
public PDFDocument(PageSize pageSize) {
|
||||
super(pageSize);
|
||||
states = new Stack<>();
|
||||
states.push(new GraphicsState());
|
||||
objects = new LinkedList<>();
|
||||
objectIdCounter = 1;
|
||||
xref = new HashMap<>();
|
||||
images = new HashMap<>();
|
||||
initPage();
|
||||
}
|
||||
|
||||
public static String toString(PDFObject obj) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
out.append(obj.id).append(" ").append(obj.version).append(" obj")
|
||||
.append(EOL);
|
||||
if (!obj.dict.isEmpty()) {
|
||||
out.append(serialize(obj.dict)).append(EOL);
|
||||
}
|
||||
if (obj.payload != null) {
|
||||
String content;
|
||||
try {
|
||||
content = new String(obj.payload.getBytes(), CHARSET);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
content = "";
|
||||
}
|
||||
if (content.length() > 0) {
|
||||
if (obj.payload.isStream()) {
|
||||
out.append("stream").append(EOL);
|
||||
}
|
||||
out.append(content);
|
||||
if (obj.payload.isStream()) {
|
||||
out.append("endstream");
|
||||
}
|
||||
out.append(EOL);
|
||||
}
|
||||
}
|
||||
out.append("endobj");
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private static String serialize(Object obj) {
|
||||
if (obj instanceof String) {
|
||||
return "/" + obj.toString();
|
||||
} else if (obj instanceof float[]) {
|
||||
return serialize(DataUtils.asList((float[]) obj));
|
||||
} else if (obj instanceof double[]) {
|
||||
return serialize(DataUtils.asList((double[]) obj));
|
||||
} else if (obj instanceof Object[]) {
|
||||
return serialize(Arrays.asList((Object[]) obj));
|
||||
} else if (obj instanceof List) {
|
||||
List<?> list = (List<?>) obj;
|
||||
StringBuilder out = new StringBuilder();
|
||||
out.append("[");
|
||||
int i = 0;
|
||||
for (Object elem : list) {
|
||||
if (i++ > 0) {
|
||||
out.append(" ");
|
||||
}
|
||||
out.append(serialize(elem));
|
||||
}
|
||||
out.append("]");
|
||||
return out.toString();
|
||||
} else if (obj instanceof Map) {
|
||||
Map<?, ?> dict = (Map<?, ?>) obj;
|
||||
StringBuilder out = new StringBuilder();
|
||||
out.append("<<").append(EOL);
|
||||
for (Map.Entry<?, ?> entry : dict.entrySet()) {
|
||||
String key = entry.getKey().toString();
|
||||
out.append(serialize(key)).append(" ");
|
||||
|
||||
Object value = entry.getValue();
|
||||
out.append(serialize(value)).append(EOL);
|
||||
}
|
||||
out.append(">>");
|
||||
return out.toString();
|
||||
} else if (obj instanceof PDFObject) {
|
||||
PDFObject pdfObj = (PDFObject) obj;
|
||||
return String.valueOf(pdfObj.id) + " " + pdfObj.version + " R";
|
||||
} else {
|
||||
return DataUtils.format(obj);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getOutput(Color c) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
String r = serialize(c.getRed() / 255.0);
|
||||
String g = serialize(c.getGreen() / 255.0);
|
||||
String b = serialize(c.getBlue() / 255.0);
|
||||
out.append(r).append(" ").append(g).append(" ").append(b).append(" rg ")
|
||||
.append(r).append(" ").append(g).append(" ").append(b).append(" RG");
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private static String getOutput(Shape s) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
PathIterator segments = s.getPathIterator(null);
|
||||
double[] coordsCur = new double[6];
|
||||
double[] pointPrev = new double[2];
|
||||
for (int i = 0; !segments.isDone(); i++, segments.next()) {
|
||||
if (i > 0) {
|
||||
out.append(" ");
|
||||
}
|
||||
int segmentType = segments.currentSegment(coordsCur);
|
||||
switch (segmentType) {
|
||||
case PathIterator.SEG_MOVETO:
|
||||
out.append(serialize(coordsCur[0])).append(" ")
|
||||
.append(serialize(coordsCur[1])).append(" m");
|
||||
pointPrev[0] = coordsCur[0];
|
||||
pointPrev[1] = coordsCur[1];
|
||||
break;
|
||||
case PathIterator.SEG_LINETO:
|
||||
out.append(serialize(coordsCur[0])).append(" ")
|
||||
.append(serialize(coordsCur[1])).append(" l");
|
||||
pointPrev[0] = coordsCur[0];
|
||||
pointPrev[1] = coordsCur[1];
|
||||
break;
|
||||
case PathIterator.SEG_CUBICTO:
|
||||
out.append(serialize(coordsCur[0])).append(" ")
|
||||
.append(serialize(coordsCur[1])).append(" ")
|
||||
.append(serialize(coordsCur[2])).append(" ")
|
||||
.append(serialize(coordsCur[3])).append(" ")
|
||||
.append(serialize(coordsCur[4])).append(" ")
|
||||
.append(serialize(coordsCur[5])).append(" c");
|
||||
pointPrev[0] = coordsCur[4];
|
||||
pointPrev[1] = coordsCur[5];
|
||||
break;
|
||||
case PathIterator.SEG_QUADTO:
|
||||
double x1 = pointPrev[0] + 2.0 / 3.0 * (coordsCur[0] - pointPrev[0]);
|
||||
double y1 = pointPrev[1] + 2.0 / 3.0 * (coordsCur[1] - pointPrev[1]);
|
||||
double x2 = coordsCur[0] + 1.0 / 3.0 * (coordsCur[2] - coordsCur[0]);
|
||||
double y2 = coordsCur[1] + 1.0 / 3.0 * (coordsCur[3] - coordsCur[1]);
|
||||
double x3 = coordsCur[2];
|
||||
double y3 = coordsCur[3];
|
||||
out.append(serialize(x1)).append(" ")
|
||||
.append(serialize(y1)).append(" ")
|
||||
.append(serialize(x2)).append(" ")
|
||||
.append(serialize(y2)).append(" ")
|
||||
.append(serialize(x3)).append(" ")
|
||||
.append(serialize(y3)).append(" c");
|
||||
pointPrev[0] = x3;
|
||||
pointPrev[1] = y3;
|
||||
break;
|
||||
case PathIterator.SEG_CLOSE:
|
||||
out.append("h");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown path operation.");
|
||||
}
|
||||
}
|
||||
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private static String getOutput(GraphicsState state, Resources resources, boolean first) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
|
||||
if (!first) {
|
||||
out.append("Q").append(EOL);
|
||||
}
|
||||
out.append("q").append(EOL);
|
||||
|
||||
if (!state.getColor().equals(GraphicsState.DEFAULT_COLOR)) {
|
||||
if (state.getColor().getAlpha() != GraphicsState.DEFAULT_COLOR.getAlpha()) {
|
||||
double a = state.getColor().getAlpha() / 255.0;
|
||||
String resourceId = resources.getId(a);
|
||||
out.append("/").append(resourceId).append(" gs").append(EOL);
|
||||
}
|
||||
out.append(getOutput(state.getColor())).append(EOL);
|
||||
}
|
||||
if (!state.getTransform().equals(GraphicsState.DEFAULT_TRANSFORM)) {
|
||||
out.append(getOutput(state.getTransform())).append(" cm").append(EOL);
|
||||
}
|
||||
if (!state.getStroke().equals(GraphicsState.DEFAULT_STROKE)) {
|
||||
out.append(getOutput(state.getStroke())).append(EOL);
|
||||
}
|
||||
if (state.getClip() != GraphicsState.DEFAULT_CLIP) {
|
||||
out.append(getOutput(state.getClip())).append(" W n").append(EOL);
|
||||
}
|
||||
if (!state.getFont().equals(GraphicsState.DEFAULT_FONT)) {
|
||||
Font font = state.getFont();
|
||||
String fontResourceId = resources.getId(font);
|
||||
float fontSize = font.getSize2D();
|
||||
out.append("/").append(fontResourceId).append(" ").append(fontSize)
|
||||
.append(" Tf").append(EOL);
|
||||
}
|
||||
|
||||
return DataUtils.stripTrailing(out.toString(), EOL);
|
||||
}
|
||||
|
||||
private static String getOutput(Stroke s) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
if (s instanceof BasicStroke) {
|
||||
BasicStroke strokeDefault = (BasicStroke) GraphicsState.DEFAULT_STROKE;
|
||||
BasicStroke strokeNew = (BasicStroke) s;
|
||||
if (strokeNew.getLineWidth() != strokeDefault.getLineWidth()) {
|
||||
out.append(serialize(strokeNew.getLineWidth()))
|
||||
.append(" w").append(EOL);
|
||||
}
|
||||
if (strokeNew.getLineJoin() == BasicStroke.JOIN_MITER && strokeNew.getMiterLimit() != strokeDefault.getMiterLimit()) {
|
||||
out.append(serialize(strokeNew.getMiterLimit()))
|
||||
.append(" M").append(EOL);
|
||||
}
|
||||
if (strokeNew.getLineJoin() != strokeDefault.getLineJoin()) {
|
||||
out.append(serialize(STROKE_LINEJOIN.get(strokeNew.getLineJoin())))
|
||||
.append(" j").append(EOL);
|
||||
}
|
||||
if (strokeNew.getEndCap() != strokeDefault.getEndCap()) {
|
||||
out.append(serialize(STROKE_ENDCAPS.get(strokeNew.getEndCap())))
|
||||
.append(" J").append(EOL);
|
||||
}
|
||||
if (strokeNew.getDashArray() != strokeDefault.getDashArray()) {
|
||||
if (strokeNew.getDashArray() != null) {
|
||||
out.append(serialize(strokeNew.getDashArray())).append(" ")
|
||||
.append(serialize(strokeNew.getDashPhase()))
|
||||
.append(" d").append(EOL);
|
||||
} else {
|
||||
out.append(EOL).append("[] 0 d").append(EOL);
|
||||
}
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private static String getOutput(AffineTransform transform) {
|
||||
double[] matrix = new double[6];
|
||||
transform.getMatrix(matrix);
|
||||
return DataUtils.join(" ", matrix);
|
||||
}
|
||||
|
||||
private static String getOutput(String str, double x, double y) {
|
||||
|
||||
// Save current graphics state
|
||||
// Undo swapping of y axis
|
||||
// Render text
|
||||
// Restore previous graphics state
|
||||
|
||||
return "q " + "1 0 0 -1 " + x + " " + y + " cm " + "BT " + getOutput(str) + " Tj ET " + "Q";
|
||||
}
|
||||
|
||||
private static StringBuilder getOutput(String str) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
|
||||
// Escape string
|
||||
str = str.replaceAll("\\\\", "\\\\\\\\")
|
||||
.replaceAll("\t", "\\\\t")
|
||||
.replaceAll("\b", "\\\\b")
|
||||
.replaceAll("\f", "\\\\f")
|
||||
.replaceAll("\\(", "\\\\(")
|
||||
.replaceAll("\\)", "\\\\)")
|
||||
.replaceAll("[\r\n]", "");
|
||||
|
||||
out.append("(").append(str).append(")");
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
private static String getOutput(PDFObject image, double x, double y,
|
||||
double width, double height, Resources resources) {
|
||||
// Query image resource id
|
||||
String resourceId = resources.getId(image);
|
||||
|
||||
// Save graphics state
|
||||
// Move image to correct position and scale it to (width, height)
|
||||
// Swap y axis
|
||||
// Draw image
|
||||
// Restore old graphics state
|
||||
|
||||
return "q " + width + " 0 0 " + height + " " + x + " " + y + " cm " + "1 0 0 -1 0 1 cm " + "/" + resourceId + " Do " + "Q";
|
||||
}
|
||||
|
||||
private GraphicsState getCurrentState() {
|
||||
return states.peek();
|
||||
}
|
||||
|
||||
private void initPage() {
|
||||
Map<String, Object> dict;
|
||||
|
||||
// Catalog
|
||||
dict = DataUtils.map(
|
||||
new String[]{"Type"},
|
||||
new Object[]{"Catalog"}
|
||||
);
|
||||
PDFObject catalog = addObject(dict, null);
|
||||
|
||||
// Pages
|
||||
List<PDFObject> pagesKids = new LinkedList<>();
|
||||
dict = DataUtils.map(
|
||||
new String[]{"Type", "Kids", "Count"},
|
||||
new Object[]{"Pages", pagesKids, 1}
|
||||
);
|
||||
PDFObject pages = addObject(dict, null);
|
||||
catalog.dict.put("Pages", pages);
|
||||
|
||||
// Page
|
||||
double x = getPageSize().x * MM_IN_UNITS;
|
||||
double y = getPageSize().y * MM_IN_UNITS;
|
||||
double width = getPageSize().width * MM_IN_UNITS;
|
||||
double height = getPageSize().height * MM_IN_UNITS;
|
||||
dict = DataUtils.map(
|
||||
new String[]{"Type", "Parent", "MediaBox"},
|
||||
new Object[]{"Page", pages, new double[]{x, y, width, height}}
|
||||
);
|
||||
PDFObject page = addObject(dict, null);
|
||||
pagesKids.add(page);
|
||||
|
||||
// Contents
|
||||
Payload contentsPayload = new Payload(true);
|
||||
contents = addObject(null, contentsPayload);
|
||||
page.dict.put("Contents", contents);
|
||||
|
||||
// Compression
|
||||
if (compressed) {
|
||||
try {
|
||||
contentsPayload.addFilter(FlateEncodeStream.class);
|
||||
contents.dict.put("Filter", new Object[]{"FlateDecode"});
|
||||
} catch (NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
// Initial content
|
||||
try {
|
||||
contentsPayload.write(DataUtils.join("", new Object[]{
|
||||
"q", EOL,
|
||||
getOutput(getCurrentState().getColor()), EOL,
|
||||
MM_IN_UNITS, " 0 0 ", -MM_IN_UNITS, " 0 ", height, " cm", EOL
|
||||
}).getBytes(CHARSET));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// Content length
|
||||
Payload contentLengthPayload = new SizePayload(contents, CHARSET, false);
|
||||
PDFObject contentLength = addObject(null, contentLengthPayload);
|
||||
contents.dict.put("Length", contentLength);
|
||||
|
||||
// Resources
|
||||
resources = new Resources(objectIdCounter++, 0);
|
||||
objects.add(resources);
|
||||
page.dict.put("Resources", resources);
|
||||
|
||||
// Create initial font
|
||||
Font font = getCurrentState().getFont();
|
||||
String fontResourceId = resources.getId(font);
|
||||
float fontSize = font.getSize2D();
|
||||
StringBuilder out = new StringBuilder();
|
||||
out.append("/").append(fontResourceId).append(" ").append(fontSize).append(" Tf").append(EOL);
|
||||
try {
|
||||
contentsPayload.write(out.toString().getBytes(CHARSET));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private PDFObject addObject(Map<String, Object> dict, Payload payload) {
|
||||
final int id = objectIdCounter++;
|
||||
final int version = 0;
|
||||
PDFObject object = new PDFObject(id, version, dict, payload);
|
||||
objects.add(object);
|
||||
return object;
|
||||
}
|
||||
|
||||
private PDFObject addObject(Image image) {
|
||||
BufferedImage bufferedImage = GraphicsUtils.toBufferedImage(image);
|
||||
|
||||
int width = bufferedImage.getWidth();
|
||||
int height = bufferedImage.getHeight();
|
||||
int bitsPerSample = DataUtils.max(bufferedImage.getSampleModel().getSampleSize());
|
||||
int bands = bufferedImage.getSampleModel().getNumBands();
|
||||
String colorSpaceName = (bands == 1) ? "DeviceGray" : "DeviceRGB";
|
||||
|
||||
Payload imagePayload = new Payload(true);
|
||||
|
||||
// Compression
|
||||
String[] imageFilters = {};
|
||||
if (compressed) {
|
||||
try {
|
||||
imagePayload.addFilter(FlateEncodeStream.class);
|
||||
imageFilters = new String[]{"FlateDecode"};
|
||||
} catch (NoSuchMethodException | InstantiationException | InvocationTargetException | IllegalAccessException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
InputStream imageDataStream =
|
||||
new ImageDataStream(bufferedImage, Interleaving.WITHOUT_ALPHA);
|
||||
|
||||
try {
|
||||
DataUtils.transfer(imageDataStream, imagePayload, 1024);
|
||||
imagePayload.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
int length = imagePayload.getBytes().length;
|
||||
|
||||
Map<String, Object> imageDict = DataUtils.map(
|
||||
new String[]{"Type", "Subtype", "Width", "Height", "ColorSpace",
|
||||
"BitsPerComponent", "Length", "Filter"},
|
||||
new Object[]{"XObject", "Image", width, height, colorSpaceName,
|
||||
bitsPerSample, length, imageFilters}
|
||||
);
|
||||
|
||||
PDFObject imageObject = addObject(imageDict, imagePayload);
|
||||
|
||||
boolean hasAlpha = bufferedImage.getColorModel().hasAlpha();
|
||||
if (hasAlpha) {
|
||||
BufferedImage mask = GraphicsUtils.getAlphaImage(bufferedImage);
|
||||
|
||||
PDFObject maskObject = addObject(mask);
|
||||
|
||||
boolean isBitmask = mask.getSampleModel().getSampleSize(0) == 1;
|
||||
if (isBitmask) {
|
||||
maskObject.dict.put("ImageMask", true);
|
||||
maskObject.dict.remove("ColorSpace");
|
||||
imageObject.dict.put("Mask", maskObject);
|
||||
} else {
|
||||
imageObject.dict.put("SMask", maskObject);
|
||||
}
|
||||
}
|
||||
|
||||
return imageObject;
|
||||
}
|
||||
|
||||
public void write(OutputStream out) throws IOException {
|
||||
FormattingWriter o = new FormattingWriter(out, CHARSET, EOL);
|
||||
|
||||
o.writeln(HEADER);
|
||||
|
||||
for (PDFObject obj : objects) {
|
||||
xref.put(obj, o.tell());
|
||||
o.writeln(toString(obj));
|
||||
o.flush();
|
||||
}
|
||||
|
||||
long xrefPos = o.tell();
|
||||
o.writeln("xref");
|
||||
o.write(0).write(" ").writeln(objects.size() + 1);
|
||||
o.format("%010d %05d f ", 0, 65535).writeln();
|
||||
for (PDFObject obj : objects) {
|
||||
o.format("%010d %05d n ", xref.get(obj), 0).writeln();
|
||||
}
|
||||
o.flush();
|
||||
|
||||
o.writeln("trailer");
|
||||
o.writeln(serialize(DataUtils.map(
|
||||
new String[]{"Size", "Root"},
|
||||
new Object[]{objects.size() + 1, objects.get(0)}
|
||||
)));
|
||||
|
||||
o.writeln("startxref");
|
||||
o.writeln(xrefPos);
|
||||
|
||||
o.writeln(FOOTER);
|
||||
o.flush();
|
||||
}
|
||||
|
||||
public void handle(Command<?> command) {
|
||||
String s = "";
|
||||
if (command instanceof Group) {
|
||||
Group c = (Group) command;
|
||||
applyStateCommands(c.getValue());
|
||||
s = getOutput(getCurrentState(), resources, !transformed);
|
||||
transformed = true;
|
||||
} else if (command instanceof DrawShapeCommand) {
|
||||
DrawShapeCommand c = (DrawShapeCommand) command;
|
||||
s = getOutput(c.getValue()) + " S";
|
||||
} else if (command instanceof FillShapeCommand) {
|
||||
FillShapeCommand c = (FillShapeCommand) command;
|
||||
s = getOutput(c.getValue()) + " f";
|
||||
} else if (command instanceof DrawStringCommand) {
|
||||
DrawStringCommand c = (DrawStringCommand) command;
|
||||
s = getOutput(c.getValue(), c.getX(), c.getY());
|
||||
} else if (command instanceof DrawImageCommand) {
|
||||
DrawImageCommand c = (DrawImageCommand) command;
|
||||
// Create object for image data
|
||||
Image image = c.getValue();
|
||||
PDFObject imageObject = images.get(image.hashCode());
|
||||
if (imageObject == null) {
|
||||
imageObject = addObject(image);
|
||||
images.put(image.hashCode(), imageObject);
|
||||
}
|
||||
s = getOutput(imageObject, c.getX(), c.getY(),
|
||||
c.getWidth(), c.getHeight(), resources);
|
||||
}
|
||||
|
||||
try {
|
||||
Payload contentsPayload = contents.payload;
|
||||
contentsPayload.write(s.getBytes(CHARSET));
|
||||
contentsPayload.write(EOL.getBytes(CHARSET));
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyStateCommands(List<Command<?>> commands) {
|
||||
for (Command<?> command : commands) {
|
||||
if (command instanceof SetHintCommand) {
|
||||
SetHintCommand c = (SetHintCommand) command;
|
||||
getCurrentState().getHints().put(c.getKey(), c.getValue());
|
||||
} else if (command instanceof SetBackgroundCommand) {
|
||||
SetBackgroundCommand c = (SetBackgroundCommand) command;
|
||||
getCurrentState().setBackground(c.getValue());
|
||||
} else if (command instanceof SetColorCommand) {
|
||||
SetColorCommand c = (SetColorCommand) command;
|
||||
getCurrentState().setColor(c.getValue());
|
||||
} else if (command instanceof SetPaintCommand) {
|
||||
SetPaintCommand c = (SetPaintCommand) command;
|
||||
getCurrentState().setPaint(c.getValue());
|
||||
} else if (command instanceof SetStrokeCommand) {
|
||||
SetStrokeCommand c = (SetStrokeCommand) command;
|
||||
getCurrentState().setStroke(c.getValue());
|
||||
} else if (command instanceof SetFontCommand) {
|
||||
SetFontCommand c = (SetFontCommand) command;
|
||||
getCurrentState().setFont(c.getValue());
|
||||
} else if (command instanceof SetTransformCommand) {
|
||||
throw new UnsupportedOperationException("The PDF format has no means of setting the transformation matrix.");
|
||||
} else if (command instanceof AffineTransformCommand) {
|
||||
AffineTransformCommand c = (AffineTransformCommand) command;
|
||||
AffineTransform stateTransform = getCurrentState().getTransform();
|
||||
AffineTransform transformToBeApplied = c.getValue();
|
||||
stateTransform.concatenate(transformToBeApplied);
|
||||
getCurrentState().setTransform(stateTransform);
|
||||
} else if (command instanceof SetClipCommand) {
|
||||
SetClipCommand c = (SetClipCommand) command;
|
||||
getCurrentState().setClip(c.getValue());
|
||||
} else if (command instanceof CreateCommand) {
|
||||
try {
|
||||
states.push((GraphicsState) getCurrentState().clone());
|
||||
} catch (CloneNotSupportedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else if (command instanceof DisposeCommand) {
|
||||
states.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
try {
|
||||
String footer = "Q" + EOL;
|
||||
if (transformed) {
|
||||
footer += "Q" + EOL;
|
||||
}
|
||||
Payload contentsPayload = contents.payload;
|
||||
contentsPayload.write(footer.getBytes(CHARSET));
|
||||
contentsPayload.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
super.close();
|
||||
}
|
||||
|
||||
public void setCompressed(boolean compressed) {
|
||||
this.compressed = compressed;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.pdf;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PDFObject {
|
||||
public final int id;
|
||||
public final int version;
|
||||
public final Map<String, Object> dict;
|
||||
public final Payload payload;
|
||||
|
||||
public PDFObject(int id, int version, Map<String, Object> dict, Payload payload) {
|
||||
this.dict = new LinkedHashMap<>();
|
||||
this.id = id;
|
||||
this.version = version;
|
||||
this.payload = payload;
|
||||
if (dict != null) {
|
||||
this.dict.putAll(dict);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.pdf;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.Document;
|
||||
import org.xbib.graphics.chart.io.vector.Processor;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.filters.AbsoluteToRelativeTransformsFilter;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.filters.FillPaintedShapeAsImageFilter;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.filters.StateChangeGroupingFilter;
|
||||
import org.xbib.graphics.chart.io.vector.util.PageSize;
|
||||
|
||||
public class PDFProcessor implements Processor {
|
||||
|
||||
public Document process(Iterable<Command<?>> commands, PageSize pageSize) {
|
||||
AbsoluteToRelativeTransformsFilter absoluteToRelativeTransformsFilter = new AbsoluteToRelativeTransformsFilter(commands);
|
||||
FillPaintedShapeAsImageFilter paintedShapeAsImageFilter = new FillPaintedShapeAsImageFilter(absoluteToRelativeTransformsFilter);
|
||||
Iterable<Command<?>> filtered = new StateChangeGroupingFilter(paintedShapeAsImageFilter);
|
||||
PDFDocument doc = new PDFDocument(pageSize);
|
||||
for (Command<?> command : filtered) {
|
||||
doc.handle(command);
|
||||
}
|
||||
doc.close();
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.pdf;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.util.FlateEncodeStream;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class Payload extends OutputStream {
|
||||
private final ByteArrayOutputStream byteStream;
|
||||
private final boolean stream;
|
||||
private OutputStream filteredStream;
|
||||
private boolean empty;
|
||||
|
||||
public Payload(boolean stream) {
|
||||
byteStream = new ByteArrayOutputStream();
|
||||
filteredStream = byteStream;
|
||||
this.stream = stream;
|
||||
empty = true;
|
||||
}
|
||||
|
||||
public byte[] getBytes() {
|
||||
return byteStream.toByteArray();
|
||||
}
|
||||
|
||||
public boolean isStream() {
|
||||
return stream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
filteredStream.write(b);
|
||||
empty = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
filteredStream.close();
|
||||
}
|
||||
|
||||
public void addFilter(Class<FlateEncodeStream> filterClass) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
|
||||
if (!empty) {
|
||||
throw new IllegalStateException("unable to add filter after writing to payload");
|
||||
}
|
||||
filteredStream = filterClass.getConstructor(OutputStream.class).newInstance(filteredStream);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.pdf;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.util.DataUtils;
|
||||
import org.xbib.graphics.chart.io.vector.util.GraphicsUtils;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public class Resources extends PDFObject {
|
||||
|
||||
private static final String KEY_PROC_SET = "ProcSet";
|
||||
private static final String KEY_TRANSPARENCY = "ExtGState";
|
||||
private static final String KEY_FONT = "Font";
|
||||
private static final String KEY_IMAGE = "XObject";
|
||||
|
||||
private static final String[] VALUE_PROC_SET = {"PDF", "Text", "ImageB", "ImageC", "ImageI"};
|
||||
|
||||
private static final String PREFIX_FONT = "Fnt";
|
||||
private static final String PREFIX_IMAGE = "Img";
|
||||
private static final String PREFIX_TRANSPARENCY = "Trp";
|
||||
|
||||
private final Map<Font, String> fonts;
|
||||
private final Map<PDFObject, String> images;
|
||||
private final Map<Double, String> transparencies;
|
||||
|
||||
private final AtomicInteger currentFontId = new AtomicInteger();
|
||||
private final AtomicInteger currentImageId = new AtomicInteger();
|
||||
private final AtomicInteger currentTransparencyId = new AtomicInteger();
|
||||
|
||||
public Resources(int id, int version) {
|
||||
super(id, version, null, null);
|
||||
fonts = new HashMap<>();
|
||||
images = new HashMap<>();
|
||||
transparencies = new HashMap<>();
|
||||
dict.put(KEY_PROC_SET, VALUE_PROC_SET);
|
||||
}
|
||||
|
||||
private <T> String getResourceId(Map<T, String> resources, T resource,
|
||||
String idPrefix, AtomicInteger idCounter) {
|
||||
String id = resources.get(resource);
|
||||
if (id == null) {
|
||||
id = String.format("%s%d", idPrefix, idCounter.getAndIncrement());
|
||||
resources.put(resource, id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public String getId(Font font) {
|
||||
Map<String, Map<String, Object>> dictEntry =
|
||||
(Map<String, Map<String, Object>>) dict.get(KEY_FONT);
|
||||
if (dictEntry == null) {
|
||||
dictEntry = new LinkedHashMap<>();
|
||||
dict.put(KEY_FONT, dictEntry);
|
||||
}
|
||||
font = GraphicsUtils.getPhysicalFont(font);
|
||||
String resourceId = getResourceId(fonts, font, PREFIX_FONT, currentFontId);
|
||||
String fontName = font.getPSName();
|
||||
// TODO: Determine font encoding (e.g. MacRomanEncoding, MacExpertEncoding, WinAnsiEncoding)
|
||||
String fontEncoding = "WinAnsiEncoding";
|
||||
dictEntry.put(resourceId, DataUtils.map(
|
||||
new String[]{"Type", "Subtype", "Encoding", "BaseFont"},
|
||||
new Object[]{"Font", "TrueType", fontEncoding, fontName}
|
||||
));
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public String getId(PDFObject image) {
|
||||
Map<String, PDFObject> dictEntry = (Map<String, PDFObject>) dict.get(KEY_IMAGE);
|
||||
if (dictEntry == null) {
|
||||
dictEntry = new LinkedHashMap<>();
|
||||
dict.put(KEY_IMAGE, dictEntry);
|
||||
}
|
||||
String resourceId = getResourceId(images, image, PREFIX_IMAGE, currentImageId);
|
||||
dictEntry.put(resourceId, image);
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public String getId(Double transparency) {
|
||||
Map<String, Map<String, Object>> dictEntry =
|
||||
(Map<String, Map<String, Object>>) dict.get(KEY_TRANSPARENCY);
|
||||
if (dictEntry == null) {
|
||||
dictEntry = new LinkedHashMap<>();
|
||||
dict.put(KEY_TRANSPARENCY, dictEntry);
|
||||
}
|
||||
String resourceId = getResourceId(transparencies, transparency,
|
||||
PREFIX_TRANSPARENCY, currentTransparencyId);
|
||||
dictEntry.put(resourceId, DataUtils.map(
|
||||
new String[]{"Type", "ca", "CA"},
|
||||
new Object[]{"ExtGState", transparency, transparency}
|
||||
));
|
||||
return resourceId;
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.pdf;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.util.DataUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class SizePayload extends GeneratedPayload {
|
||||
private final PDFObject object;
|
||||
private final String charset;
|
||||
|
||||
public SizePayload(PDFObject object, String charset, boolean stream) {
|
||||
super(stream);
|
||||
this.object = object;
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] generatePayload() {
|
||||
try {
|
||||
object.payload.close();
|
||||
String content = DataUtils.format(object.payload.getBytes().length);
|
||||
return content.getBytes(charset);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,552 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.svg;
|
||||
|
||||
import org.w3c.dom.DOMImplementation;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.DocumentType;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xbib.graphics.chart.io.vector.GraphicsState;
|
||||
import org.xbib.graphics.chart.io.vector.SizedDocument;
|
||||
import org.xbib.graphics.chart.io.vector.VectorHints;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.AffineTransformCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.CreateCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DisposeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawImageCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawShapeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawStringCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.FillShapeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Group;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetBackgroundCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetClipCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetColorCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetCompositeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetFontCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetHintCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetPaintCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetStrokeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetTransformCommand;
|
||||
import org.xbib.graphics.chart.io.vector.util.Base64EncodeStream;
|
||||
import org.xbib.graphics.chart.io.vector.util.DataUtils;
|
||||
import org.xbib.graphics.chart.io.vector.util.GraphicsUtils;
|
||||
import org.xbib.graphics.chart.io.vector.util.PageSize;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.transform.OutputKeys;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Image;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
|
||||
public class SVGDocument extends SizedDocument {
|
||||
private static final String SVG_DOCTYPE_QNAME = "svg";
|
||||
private static final String SVG_DOCTYPE_PUBLIC_ID = "-//W3C//DTD SVG 1.1//EN";
|
||||
private static final String SVG_DOCTYPE_SYSTEM_ID = "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd";
|
||||
private static final String SVG_NAMESPACE_URI = "http://www.w3.org/2000/svg";
|
||||
private static final String XLINK_NAMESPACE = "xlink";
|
||||
private static final String XLINK_NAMESPACE_URI = "http://www.w3.org/1999/xlink";
|
||||
|
||||
private static final String PREFIX_CLIP = "clip";
|
||||
|
||||
private static final String CHARSET = "UTF-8";
|
||||
|
||||
private static final double DOTS_PER_MM = 2.834646; // 72 dpi
|
||||
//private static final double DOTS_PER_MM = 11.811024; // 300 dpi
|
||||
|
||||
/**
|
||||
* Mapping of stroke endcap values from Java to SVG.
|
||||
*/
|
||||
private static final Map<Integer, String> STROKE_ENDCAPS =
|
||||
DataUtils.map(new Integer[]{BasicStroke.CAP_BUTT, BasicStroke.CAP_ROUND, BasicStroke.CAP_SQUARE},
|
||||
new String[]{"butt", "round", "square"}
|
||||
);
|
||||
/**
|
||||
* Mapping of line join values for path drawing from Java to SVG.
|
||||
*/
|
||||
private static final Map<Integer, String> STROKE_LINEJOIN =
|
||||
DataUtils.map(new Integer[]{BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND, BasicStroke.JOIN_BEVEL},
|
||||
new String[]{"miter", "round", "bevel"}
|
||||
);
|
||||
private final Stack<GraphicsState> states;
|
||||
private final Document doc;
|
||||
private final Element root;
|
||||
private final Map<Integer, Element> clippingPathElements;
|
||||
private Element group;
|
||||
private boolean groupAdded;
|
||||
private Element defs;
|
||||
|
||||
public SVGDocument(PageSize pageSize) {
|
||||
super(pageSize);
|
||||
|
||||
states = new Stack<GraphicsState>();
|
||||
states.push(new GraphicsState());
|
||||
clippingPathElements = new HashMap<Integer, Element>();
|
||||
|
||||
// Prepare DOM
|
||||
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
|
||||
docFactory.setValidating(false);
|
||||
DocumentBuilder docBuilder;
|
||||
try {
|
||||
docBuilder = docFactory.newDocumentBuilder();
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new IllegalStateException("Could not create XML builder.");
|
||||
}
|
||||
|
||||
// Create XML document with DOCTYPE
|
||||
DOMImplementation domImpl = docBuilder.getDOMImplementation();
|
||||
DocumentType docType = domImpl.createDocumentType(SVG_DOCTYPE_QNAME, SVG_DOCTYPE_PUBLIC_ID, SVG_DOCTYPE_SYSTEM_ID);
|
||||
doc = domImpl.createDocument(SVG_NAMESPACE_URI, "svg", docType);
|
||||
// FIXME: Some XML parsers don't support setting standalone to "false"
|
||||
try {
|
||||
doc.setXmlStandalone(false);
|
||||
} catch (AbstractMethodError e) {
|
||||
System.err.println("Your XML parser does not support standalone XML documents.");
|
||||
}
|
||||
|
||||
root = doc.getDocumentElement();
|
||||
initRoot();
|
||||
|
||||
group = root;
|
||||
}
|
||||
|
||||
private static void appendStyle(StringBuilder style, String attribute, Object value) {
|
||||
style.append(attribute).append(":")
|
||||
.append(DataUtils.format(value)).append(";");
|
||||
}
|
||||
|
||||
private static String getOutput(AffineTransform tx) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
// FIXME: Use tx.getType() to check for transformation components
|
||||
if (AffineTransform.getTranslateInstance(tx.getTranslateX(),
|
||||
tx.getTranslateY()).equals(tx)) {
|
||||
out.append("translate(")
|
||||
.append(DataUtils.format(tx.getTranslateX())).append(" ")
|
||||
.append(DataUtils.format(tx.getTranslateY())).append(")");
|
||||
} else {
|
||||
double[] matrix = new double[6];
|
||||
tx.getMatrix(matrix);
|
||||
out.append("matrix(").append(DataUtils.join(" ", matrix)).append(")");
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private static String getOutput(Color color) {
|
||||
return String.format((Locale) null, "rgb(%d,%d,%d)",
|
||||
color.getRed(), color.getGreen(), color.getBlue());
|
||||
}
|
||||
|
||||
private static String getOutput(Shape shape) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
PathIterator segments = shape.getPathIterator(null);
|
||||
double[] coords = new double[6];
|
||||
for (int i = 0; !segments.isDone(); i++, segments.next()) {
|
||||
if (i > 0) {
|
||||
out.append(" ");
|
||||
}
|
||||
int segmentType = segments.currentSegment(coords);
|
||||
switch (segmentType) {
|
||||
case PathIterator.SEG_MOVETO:
|
||||
out.append("M").append(coords[0]).append(",").append(coords[1]);
|
||||
break;
|
||||
case PathIterator.SEG_LINETO:
|
||||
out.append("L").append(coords[0]).append(",").append(coords[1]);
|
||||
break;
|
||||
case PathIterator.SEG_CUBICTO:
|
||||
out.append("C")
|
||||
.append(coords[0]).append(",").append(coords[1]).append(" ")
|
||||
.append(coords[2]).append(",").append(coords[3]).append(" ")
|
||||
.append(coords[4]).append(",").append(coords[5]);
|
||||
break;
|
||||
case PathIterator.SEG_QUADTO:
|
||||
out.append("Q")
|
||||
.append(coords[0]).append(",").append(coords[1]).append(" ")
|
||||
.append(coords[2]).append(",").append(coords[3]);
|
||||
break;
|
||||
case PathIterator.SEG_CLOSE:
|
||||
out.append("Z");
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown path operation.");
|
||||
}
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private static String getOutput(Font font) {
|
||||
StringBuilder out = new StringBuilder();
|
||||
if (!GraphicsState.DEFAULT_FONT.getFamily().equals(font.getFamily())) {
|
||||
String physicalFamily = GraphicsUtils.getPhysicalFont(font).getFamily();
|
||||
out.append("font-family:\"").append(physicalFamily).append("\";");
|
||||
}
|
||||
if (font.getSize2D() != GraphicsState.DEFAULT_FONT.getSize2D()) {
|
||||
out.append("font-size:").append(DataUtils.format(font.getSize2D())).append("px;");
|
||||
}
|
||||
if ((font.getStyle() & Font.ITALIC) != 0) {
|
||||
out.append("font-style:italic;");
|
||||
}
|
||||
if ((font.getStyle() & Font.BOLD) != 0) {
|
||||
out.append("font-weight:bold;");
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
private static String getOutput(Image image, boolean lossyAllowed) {
|
||||
BufferedImage bufferedImage = GraphicsUtils.toBufferedImage(image);
|
||||
|
||||
String encoded = encodeImage(bufferedImage, "png");
|
||||
if (!GraphicsUtils.usesAlpha(bufferedImage) && lossyAllowed) {
|
||||
String encodedLossy = encodeImage(bufferedImage, "jpeg");
|
||||
if (encodedLossy.length() > 0 && encodedLossy.length() < encoded.length()) {
|
||||
encoded = encodedLossy;
|
||||
}
|
||||
}
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
private static String encodeImage(BufferedImage bufferedImage, String format) {
|
||||
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
|
||||
Base64EncodeStream encodeStream = new Base64EncodeStream(byteStream);
|
||||
try {
|
||||
ImageIO.write(bufferedImage, format, encodeStream);
|
||||
encodeStream.close();
|
||||
String encoded = byteStream.toString("ISO-8859-1");
|
||||
return String.format("data:image/%s;base64,%s", format, encoded);
|
||||
} catch (IOException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private GraphicsState getCurrentState() {
|
||||
return states.peek();
|
||||
}
|
||||
|
||||
private void initRoot() {
|
||||
double x = getPageSize().x;
|
||||
double y = getPageSize().y;
|
||||
double width = getPageSize().width;
|
||||
double height = getPageSize().height;
|
||||
|
||||
// Add svg element
|
||||
root.setAttribute("xmlns:" + XLINK_NAMESPACE, XLINK_NAMESPACE_URI);
|
||||
root.setAttribute("version", "1.1");
|
||||
root.setAttribute("x", DataUtils.format(x / DOTS_PER_MM) + "mm");
|
||||
root.setAttribute("y", DataUtils.format(y / DOTS_PER_MM) + "mm");
|
||||
root.setAttribute("width", DataUtils.format(width / DOTS_PER_MM) + "mm");
|
||||
root.setAttribute("height", DataUtils.format(height / DOTS_PER_MM) + "mm");
|
||||
root.setAttribute("viewBox", DataUtils.join(" ", new double[]{x, y, width, height}));
|
||||
}
|
||||
|
||||
public void write(OutputStream out) throws IOException {
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
try {
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
|
||||
transformer.setOutputProperty(OutputKeys.STANDALONE, "no");
|
||||
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
|
||||
transformer.setOutputProperty(OutputKeys.ENCODING, CHARSET);
|
||||
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,
|
||||
doc.getDoctype().getPublicId());
|
||||
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
|
||||
doc.getDoctype().getSystemId());
|
||||
transformer.transform(new DOMSource(doc), new StreamResult(out));
|
||||
} catch (TransformerException e) {
|
||||
throw new IOException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try {
|
||||
write(out);
|
||||
return out.toString(CHARSET);
|
||||
} catch (IOException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private void newGroup() {
|
||||
group = doc.createElement("g");
|
||||
groupAdded = false;
|
||||
|
||||
Shape clip = getCurrentState().getClip();
|
||||
if (clip != GraphicsState.DEFAULT_CLIP) {
|
||||
Element clipElem = getClipElement(clip);
|
||||
String ref = "url(#" + clipElem.getAttribute("id") + ")";
|
||||
group.setAttribute("clip-path", ref);
|
||||
}
|
||||
|
||||
AffineTransform tx = getCurrentState().getTransform();
|
||||
if (!GraphicsState.DEFAULT_TRANSFORM.equals(tx)) {
|
||||
group.setAttribute("transform", getOutput(tx));
|
||||
}
|
||||
}
|
||||
|
||||
private Element getClipElement(Shape clip) {
|
||||
// Look for existing entries
|
||||
Element path = clippingPathElements.get(clip.hashCode());
|
||||
if (path != null) {
|
||||
return path;
|
||||
}
|
||||
|
||||
// Make sure <defs> exists
|
||||
if (defs == null) {
|
||||
defs = doc.createElement("defs");
|
||||
root.insertBefore(defs, root.getFirstChild());
|
||||
}
|
||||
|
||||
// Store clipping path in <defs> without styling information
|
||||
path = doc.createElement("clipPath");
|
||||
path.setAttribute("id", PREFIX_CLIP + clip.hashCode());
|
||||
Element shape = getElement(clip);
|
||||
shape.removeAttribute("style");
|
||||
path.appendChild(shape);
|
||||
defs.appendChild(path);
|
||||
|
||||
// Register path
|
||||
clippingPathElements.put(clip.hashCode(), path);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private void addToGroup(Element e) {
|
||||
group.appendChild(e);
|
||||
if (!groupAdded && group != root) {
|
||||
root.appendChild(group);
|
||||
groupAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void handle(Command<?> command) {
|
||||
if (command instanceof Group) {
|
||||
Group c = (Group) command;
|
||||
applyStateCommands(c.getValue());
|
||||
if (containsGroupCommand(c.getValue())) {
|
||||
newGroup();
|
||||
}
|
||||
} else if (command instanceof DrawImageCommand) {
|
||||
DrawImageCommand c = (DrawImageCommand) command;
|
||||
Element e = getElement(c.getValue(),
|
||||
c.getX(), c.getY(), c.getWidth(), c.getHeight());
|
||||
addToGroup(e);
|
||||
} else if (command instanceof DrawShapeCommand) {
|
||||
DrawShapeCommand c = (DrawShapeCommand) command;
|
||||
Element e = getElement(c.getValue());
|
||||
e.setAttribute("style", getStyle(false));
|
||||
addToGroup(e);
|
||||
} else if (command instanceof DrawStringCommand) {
|
||||
DrawStringCommand c = (DrawStringCommand) command;
|
||||
Element e = getElement(c.getValue(), c.getX(), c.getY());
|
||||
e.setAttribute("style", getStyle(getCurrentState().getFont()));
|
||||
addToGroup(e);
|
||||
} else if (command instanceof FillShapeCommand) {
|
||||
FillShapeCommand c = (FillShapeCommand) command;
|
||||
Element e = getElement(c.getValue());
|
||||
e.setAttribute("style", getStyle(true));
|
||||
addToGroup(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyStateCommands(List<Command<?>> commands) {
|
||||
for (Command<?> command : commands) {
|
||||
GraphicsState state = getCurrentState();
|
||||
if (command instanceof SetBackgroundCommand) {
|
||||
SetBackgroundCommand c = (SetBackgroundCommand) command;
|
||||
state.setBackground(c.getValue());
|
||||
} else if (command instanceof SetClipCommand) {
|
||||
SetClipCommand c = (SetClipCommand) command;
|
||||
state.setClip(c.getValue());
|
||||
} else if (command instanceof SetColorCommand) {
|
||||
SetColorCommand c = (SetColorCommand) command;
|
||||
state.setColor(c.getValue());
|
||||
} else if (command instanceof SetCompositeCommand) {
|
||||
SetCompositeCommand c = (SetCompositeCommand) command;
|
||||
state.setComposite(c.getValue());
|
||||
} else if (command instanceof SetFontCommand) {
|
||||
SetFontCommand c = (SetFontCommand) command;
|
||||
state.setFont(c.getValue());
|
||||
} else if (command instanceof SetPaintCommand) {
|
||||
SetPaintCommand c = (SetPaintCommand) command;
|
||||
state.setPaint(c.getValue());
|
||||
} else if (command instanceof SetStrokeCommand) {
|
||||
SetStrokeCommand c = (SetStrokeCommand) command;
|
||||
state.setStroke(c.getValue());
|
||||
} else if (command instanceof SetTransformCommand) {
|
||||
SetTransformCommand c = (SetTransformCommand) command;
|
||||
state.setTransform(c.getValue());
|
||||
} else if (command instanceof AffineTransformCommand) {
|
||||
AffineTransformCommand c = (AffineTransformCommand) command;
|
||||
AffineTransform stateTransform = state.getTransform();
|
||||
AffineTransform transformToBeApplied = c.getValue();
|
||||
stateTransform.concatenate(transformToBeApplied);
|
||||
state.setTransform(stateTransform);
|
||||
} else if (command instanceof SetHintCommand) {
|
||||
SetHintCommand c = (SetHintCommand) command;
|
||||
state.getHints().put(c.getKey(), c.getValue());
|
||||
} else if (command instanceof CreateCommand) {
|
||||
try {
|
||||
states.push((GraphicsState) getCurrentState().clone());
|
||||
} catch (CloneNotSupportedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else if (command instanceof DisposeCommand) {
|
||||
states.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean containsGroupCommand(List<Command<?>> commands) {
|
||||
for (Command<?> command : commands) {
|
||||
if ((command instanceof SetClipCommand) ||
|
||||
(command instanceof SetTransformCommand) ||
|
||||
(command instanceof AffineTransformCommand)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String getStyle(boolean filled) {
|
||||
StringBuilder style = new StringBuilder();
|
||||
|
||||
Color color = getCurrentState().getColor();
|
||||
String colorOutput = getOutput(color);
|
||||
double opacity = color.getAlpha() / 255.0;
|
||||
|
||||
if (filled) {
|
||||
appendStyle(style, "fill", colorOutput);
|
||||
if (color.getAlpha() < 255) {
|
||||
appendStyle(style, "fill-opacity", opacity);
|
||||
}
|
||||
} else {
|
||||
appendStyle(style, "fill", "none");
|
||||
}
|
||||
|
||||
if (!filled) {
|
||||
appendStyle(style, "stroke", colorOutput);
|
||||
if (color.getAlpha() < 255) {
|
||||
appendStyle(style, "stroke-opacity", opacity);
|
||||
}
|
||||
Stroke stroke = getCurrentState().getStroke();
|
||||
if (stroke instanceof BasicStroke) {
|
||||
BasicStroke bs = (BasicStroke) stroke;
|
||||
if (bs.getLineWidth() != 1f) {
|
||||
appendStyle(style, "stroke-width", bs.getLineWidth());
|
||||
}
|
||||
if (bs.getMiterLimit() != 4f) {
|
||||
appendStyle(style, "stroke-miterlimit", bs.getMiterLimit());
|
||||
}
|
||||
if (bs.getEndCap() != BasicStroke.CAP_BUTT) {
|
||||
appendStyle(style, "stroke-linecap", STROKE_ENDCAPS.get(bs.getEndCap()));
|
||||
}
|
||||
if (bs.getLineJoin() != BasicStroke.JOIN_MITER) {
|
||||
appendStyle(style, "stroke-linejoin", STROKE_LINEJOIN.get(bs.getLineJoin()));
|
||||
}
|
||||
if (bs.getDashArray() != null) {
|
||||
appendStyle(style, "stroke-dasharray", DataUtils.join(",", bs.getDashArray()));
|
||||
if (bs.getDashPhase() != 0f) {
|
||||
appendStyle(style, "stroke-dashoffset", bs.getDashPhase());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
appendStyle(style, "stroke", "none");
|
||||
}
|
||||
|
||||
return style.toString();
|
||||
}
|
||||
|
||||
private String getStyle(Font font) {
|
||||
String style = getStyle(true);
|
||||
if (!GraphicsState.DEFAULT_FONT.equals(font)) {
|
||||
style += getOutput(font);
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
private Element getElement(Shape shape) {
|
||||
Element elem;
|
||||
if (shape instanceof Line2D) {
|
||||
Line2D s = (Line2D) shape;
|
||||
elem = doc.createElement("line");
|
||||
elem.setAttribute("x1", DataUtils.format(s.getX1()));
|
||||
elem.setAttribute("y1", DataUtils.format(s.getY1()));
|
||||
elem.setAttribute("x2", DataUtils.format(s.getX2()));
|
||||
elem.setAttribute("y2", DataUtils.format(s.getY2()));
|
||||
} else if (shape instanceof Rectangle2D) {
|
||||
Rectangle2D s = (Rectangle2D) shape;
|
||||
elem = doc.createElement("rect");
|
||||
elem.setAttribute("x", DataUtils.format(s.getX()));
|
||||
elem.setAttribute("y", DataUtils.format(s.getY()));
|
||||
elem.setAttribute("width", DataUtils.format(s.getWidth()));
|
||||
elem.setAttribute("height", DataUtils.format(s.getHeight()));
|
||||
} else if (shape instanceof RoundRectangle2D) {
|
||||
RoundRectangle2D s = (RoundRectangle2D) shape;
|
||||
elem = doc.createElement("rect");
|
||||
elem.setAttribute("x", DataUtils.format(s.getX()));
|
||||
elem.setAttribute("y", DataUtils.format(s.getY()));
|
||||
elem.setAttribute("width", DataUtils.format(s.getWidth()));
|
||||
elem.setAttribute("height", DataUtils.format(s.getHeight()));
|
||||
elem.setAttribute("rx", DataUtils.format(s.getArcWidth() / 2.0));
|
||||
elem.setAttribute("ry", DataUtils.format(s.getArcHeight() / 2.0));
|
||||
} else if (shape instanceof Ellipse2D) {
|
||||
Ellipse2D s = (Ellipse2D) shape;
|
||||
elem = doc.createElement("ellipse");
|
||||
elem.setAttribute("cx", DataUtils.format(s.getCenterX()));
|
||||
elem.setAttribute("cy", DataUtils.format(s.getCenterY()));
|
||||
elem.setAttribute("rx", DataUtils.format(s.getWidth() / 2.0));
|
||||
elem.setAttribute("ry", DataUtils.format(s.getHeight() / 2.0));
|
||||
} else {
|
||||
elem = doc.createElement("path");
|
||||
elem.setAttribute("d", getOutput(shape));
|
||||
}
|
||||
return elem;
|
||||
}
|
||||
|
||||
private Element getElement(String text, double x, double y) {
|
||||
Element elem = doc.createElement("text");
|
||||
elem.appendChild(doc.createTextNode(text));
|
||||
elem.setAttribute("x", DataUtils.format(x));
|
||||
elem.setAttribute("y", DataUtils.format(y));
|
||||
return elem;
|
||||
}
|
||||
|
||||
private Element getElement(Image image, double x, double y, double width, double height) {
|
||||
Element elem = doc.createElement("image");
|
||||
elem.setAttribute("x", DataUtils.format(x));
|
||||
elem.setAttribute("y", DataUtils.format(y));
|
||||
elem.setAttribute("width", DataUtils.format(width));
|
||||
elem.setAttribute("height", DataUtils.format(height));
|
||||
elem.setAttribute("preserveAspectRatio", "none");
|
||||
boolean lossyAllowed = getCurrentState().getHints().get(VectorHints.KEY_EXPORT) ==
|
||||
VectorHints.VALUE_EXPORT_SIZE;
|
||||
elem.setAttribute("xlink:href", getOutput(image, lossyAllowed));
|
||||
return elem;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.svg;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.Document;
|
||||
import org.xbib.graphics.chart.io.vector.Processor;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.filters.FillPaintedShapeAsImageFilter;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.filters.StateChangeGroupingFilter;
|
||||
import org.xbib.graphics.chart.io.vector.util.PageSize;
|
||||
|
||||
public class SVGProcessor implements Processor {
|
||||
public Document process(Iterable<Command<?>> commands, PageSize pageSize) {
|
||||
FillPaintedShapeAsImageFilter shapesAsImages = new FillPaintedShapeAsImageFilter(commands);
|
||||
Iterable<Command<?>> filtered = new StateChangeGroupingFilter(shapesAsImages);
|
||||
SVGDocument doc = new SVGDocument(pageSize);
|
||||
for (Command<?> command : filtered) {
|
||||
doc.handle(command);
|
||||
}
|
||||
doc.close();
|
||||
return doc;
|
||||
}
|
||||
}
|
|
@ -1,102 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.util;
|
||||
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ASCII85EncodeStream extends FilterOutputStream {
|
||||
private static final Charset ISO88591 = Charset.forName("ISO-8859-1");
|
||||
private static final int BASE = 85;
|
||||
private static final int[] POW_85 =
|
||||
{BASE * BASE * BASE * BASE, BASE * BASE * BASE, BASE * BASE, BASE, 1};
|
||||
private static final char[] CHAR_MAP =
|
||||
"!\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu"
|
||||
.toCharArray();
|
||||
private final byte[] data;
|
||||
private final byte[] prefixBytes;
|
||||
private final byte[] suffixBytes;
|
||||
private final byte[] encoded;
|
||||
private boolean closed;
|
||||
private int dataSize;
|
||||
private boolean prefixDone;
|
||||
|
||||
public ASCII85EncodeStream(OutputStream out, String prefix, String suffix) {
|
||||
super(out);
|
||||
prefixBytes = (prefix != null ? prefix : "").getBytes(ISO88591);
|
||||
suffixBytes = (suffix != null ? suffix : "").getBytes(ISO88591);
|
||||
data = new byte[4];
|
||||
encoded = new byte[5];
|
||||
}
|
||||
|
||||
public ASCII85EncodeStream(OutputStream out) {
|
||||
this(out, "", "~>");
|
||||
}
|
||||
|
||||
private static long toUInt32(byte[] bytes, int size) {
|
||||
long uint32 = 0L;
|
||||
for (int i = 0; i < 4 && i < size; i++) {
|
||||
uint32 |= (bytes[i] & 0xff) << (3 - i) * 8;
|
||||
}
|
||||
return toUnsignedInt(uint32);
|
||||
}
|
||||
|
||||
private static long toUnsignedInt(long x) {
|
||||
return x & 0x00000000ffffffffL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
if (!prefixDone) {
|
||||
out.write(prefixBytes);
|
||||
prefixDone = true;
|
||||
}
|
||||
if (dataSize == data.length) {
|
||||
writeChunk();
|
||||
dataSize = 0;
|
||||
}
|
||||
data[dataSize++] = (byte) (b & 0xff);
|
||||
}
|
||||
|
||||
private void writeChunk() throws IOException {
|
||||
if (dataSize == 0) {
|
||||
return;
|
||||
}
|
||||
long uint32 = toUInt32(data, dataSize);
|
||||
int padByteCount = data.length - dataSize;
|
||||
int encodedSize = encodeChunk(uint32, padByteCount);
|
||||
out.write(encoded, 0, encodedSize);
|
||||
}
|
||||
|
||||
private int encodeChunk(long uint32, int padByteCount) {
|
||||
Arrays.fill(encoded, (byte) 0);
|
||||
if (uint32 == 0L && padByteCount == 0) {
|
||||
encoded[0] = 'z';
|
||||
return 1;
|
||||
}
|
||||
int size = encoded.length - padByteCount;
|
||||
for (int i = 0; i < size; i++) {
|
||||
encoded[i] = (byte) CHAR_MAP[(int) (uint32 / POW_85[i] % BASE)];
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
writeChunk();
|
||||
|
||||
out.write(suffixBytes);
|
||||
|
||||
super.close();
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.util;
|
||||
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.BufferedImageOp;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class AlphaToMaskOp implements BufferedImageOp {
|
||||
private final boolean inverted;
|
||||
|
||||
public AlphaToMaskOp(boolean inverted) {
|
||||
this.inverted = inverted;
|
||||
}
|
||||
|
||||
public AlphaToMaskOp() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public boolean isInverted() {
|
||||
return inverted;
|
||||
}
|
||||
|
||||
public BufferedImage filter(BufferedImage src, BufferedImage dest) {
|
||||
ColorModel cm = src.getColorModel();
|
||||
|
||||
if (dest == null) {
|
||||
dest = createCompatibleDestImage(src, cm);
|
||||
} else if (dest.getWidth() != src.getWidth() || dest.getHeight() != src.getHeight()) {
|
||||
throw new IllegalArgumentException("Source and destination images have different dimensions.");
|
||||
} else if (dest.getColorModel() != cm) {
|
||||
throw new IllegalArgumentException("Color models don't match.");
|
||||
}
|
||||
|
||||
if (cm.hasAlpha()) {
|
||||
Raster srcRaster = src.getRaster();
|
||||
WritableRaster destRaster = dest.getRaster();
|
||||
|
||||
for (int y = 0; y < srcRaster.getHeight(); y++) {
|
||||
for (int x = 0; x < srcRaster.getWidth(); x++) {
|
||||
int argb = cm.getRGB(srcRaster.getDataElements(x, y, null));
|
||||
int alpha = argb >>> 24;
|
||||
if (alpha >= 127 && !isInverted() || alpha < 127 && isInverted()) {
|
||||
argb |= 0xff000000;
|
||||
} else {
|
||||
argb &= 0x00ffffff;
|
||||
}
|
||||
destRaster.setDataElements(x, y, cm.getDataElements(argb, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
public Rectangle2D getBounds2D(BufferedImage src) {
|
||||
Rectangle2D bounds = new Rectangle2D.Double();
|
||||
bounds.setRect(src.getRaster().getBounds());
|
||||
return bounds;
|
||||
}
|
||||
|
||||
public BufferedImage createCompatibleDestImage(BufferedImage src,
|
||||
ColorModel destCM) {
|
||||
if (destCM == null) {
|
||||
destCM = src.getColorModel();
|
||||
}
|
||||
WritableRaster raster = destCM.createCompatibleWritableRaster(
|
||||
src.getWidth(), src.getHeight());
|
||||
boolean isRasterPremultiplied = destCM.isAlphaPremultiplied();
|
||||
Hashtable<String, Object> properties = null;
|
||||
if (src.getPropertyNames() != null) {
|
||||
properties = new Hashtable<String, Object>();
|
||||
for (String key : src.getPropertyNames()) {
|
||||
properties.put(key, src.getProperty(key));
|
||||
}
|
||||
}
|
||||
|
||||
BufferedImage bimage = new BufferedImage(destCM, raster,
|
||||
isRasterPremultiplied, properties);
|
||||
src.copyData(raster);
|
||||
return bimage;
|
||||
}
|
||||
|
||||
public Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
|
||||
if (dstPt == null) {
|
||||
dstPt = new Point2D.Double();
|
||||
}
|
||||
dstPt.setLocation(srcPt);
|
||||
return dstPt;
|
||||
}
|
||||
|
||||
public RenderingHints getRenderingHints() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.util;
|
||||
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Base64EncodeStream extends FilterOutputStream {
|
||||
private static final int BASE = 64;
|
||||
private static final int[] POW_64 =
|
||||
{BASE * BASE * BASE, BASE * BASE, BASE, 1};
|
||||
private static final char[] CHAR_MAP =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
.toCharArray();
|
||||
private final byte[] data;
|
||||
private final byte[] encoded;
|
||||
private boolean closed;
|
||||
private int dataSize;
|
||||
|
||||
public Base64EncodeStream(OutputStream out) {
|
||||
super(out);
|
||||
data = new byte[3];
|
||||
encoded = new byte[4];
|
||||
}
|
||||
|
||||
private static long toUInt32(byte[] bytes, int size) {
|
||||
long uint32 = 0L;
|
||||
int offset = (3 - size) * 8;
|
||||
for (int i = size - 1; i >= 0; i--) {
|
||||
uint32 |= (bytes[i] & 0xff) << offset;
|
||||
offset += 8;
|
||||
}
|
||||
return toUnsignedInt(uint32);
|
||||
}
|
||||
|
||||
private static long toUnsignedInt(long x) {
|
||||
return x & 0x00000000ffffffffL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
if (dataSize == data.length) {
|
||||
writeChunk();
|
||||
dataSize = 0;
|
||||
}
|
||||
data[dataSize++] = (byte) (b & 0xff);
|
||||
}
|
||||
|
||||
private void writeChunk() throws IOException {
|
||||
if (dataSize == 0) {
|
||||
return;
|
||||
}
|
||||
long uint32 = toUInt32(data, dataSize);
|
||||
int padByteCount = data.length - dataSize;
|
||||
int encodedSize = encodeChunk(uint32, padByteCount);
|
||||
out.write(encoded, 0, encodedSize);
|
||||
}
|
||||
|
||||
private int encodeChunk(long uint32, int padByteCount) {
|
||||
Arrays.fill(encoded, (byte) '=');
|
||||
int size = encoded.length - padByteCount;
|
||||
for (int i = 0; i < size; i++) {
|
||||
encoded[i] = (byte) CHAR_MAP[(int) (uint32 / POW_64[i] % BASE)];
|
||||
}
|
||||
return encoded.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
writeChunk();
|
||||
|
||||
super.close();
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,240 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Abstract class that contains utility functions for working with data
|
||||
* collections like maps or lists.
|
||||
*/
|
||||
public abstract class DataUtils {
|
||||
/**
|
||||
* Default constructor that prevents creation of class.
|
||||
*/
|
||||
protected DataUtils() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mapping from two arrays, one with keys, one with values.
|
||||
*
|
||||
* @param <K> Data type of the keys.
|
||||
* @param <V> Data type of the values.
|
||||
* @param keys Array containing the keys.
|
||||
* @param values Array containing the values.
|
||||
* @return Map with keys and values from the specified arrays.
|
||||
*/
|
||||
public static <K, V> Map<K, V> map(K[] keys, V[] values) {
|
||||
// Check for valid parameters
|
||||
if (keys.length != values.length) {
|
||||
throw new IllegalArgumentException(
|
||||
"Cannot create a Map: " +
|
||||
"The number of keys and values differs.");
|
||||
}
|
||||
// Fill map with keys and values
|
||||
Map<K, V> map = new LinkedHashMap<K, V>(keys.length);
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
K key = keys[i];
|
||||
V value = values[i];
|
||||
map.put(key, value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string containing all elements concatenated by a specified
|
||||
* separator.
|
||||
*
|
||||
* @param separator Separator string.
|
||||
* @param elements List of elements that should be concatenated.
|
||||
* @return a concatenated string.
|
||||
*/
|
||||
public static String join(String separator, List<?> elements) {
|
||||
if (elements == null || elements.size() == 0) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder(elements.size() * 3);
|
||||
int i = 0;
|
||||
for (Object elem : elements) {
|
||||
if (separator.length() > 0 && i++ > 0) {
|
||||
sb.append(separator);
|
||||
}
|
||||
sb.append(format(elem));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string containing all elements concatenated by a specified
|
||||
* separator.
|
||||
*
|
||||
* @param separator Separator string.
|
||||
* @param elements Array of elements that should be concatenated.
|
||||
* @return a concatenated string.
|
||||
*/
|
||||
public static String join(String separator, Object[] elements) {
|
||||
if (elements == null || elements.length == 0) {
|
||||
return "";
|
||||
}
|
||||
return join(separator, Arrays.asList(elements));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string containing all double numbers concatenated by a
|
||||
* specified separator.
|
||||
*
|
||||
* @param separator Separator string.
|
||||
* @param elements Array of double numbers that should be concatenated.
|
||||
* @return a concatenated string.
|
||||
*/
|
||||
public static String join(String separator, double[] elements) {
|
||||
if (elements == null || elements.length == 0) {
|
||||
return "";
|
||||
}
|
||||
List<Double> list = new ArrayList<Double>(elements.length);
|
||||
for (Double element : elements) {
|
||||
list.add(element);
|
||||
}
|
||||
return join(separator, list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string containing all float numbers concatenated by a
|
||||
* specified separator.
|
||||
*
|
||||
* @param separator Separator string.
|
||||
* @param elements Array of float numbers that should be concatenated.
|
||||
* @return a concatenated string.
|
||||
*/
|
||||
public static String join(String separator, float[] elements) {
|
||||
if (elements == null || elements.length == 0) {
|
||||
return "";
|
||||
}
|
||||
List<Float> list = new ArrayList<Float>(elements.length);
|
||||
for (Float element : elements) {
|
||||
list.add(element);
|
||||
}
|
||||
return join(separator, list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the largest of all specified values.
|
||||
*
|
||||
* @param values Several integer values.
|
||||
* @return largest value.
|
||||
*/
|
||||
public static int max(int... values) {
|
||||
int max = values[0];
|
||||
for (int i = 1; i < values.length; i++) {
|
||||
if (values[i] > max) {
|
||||
max = values[i];
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies data from an input stream to an output stream using a buffer of
|
||||
* specified size.
|
||||
*
|
||||
* @param in Input stream.
|
||||
* @param out Output stream.
|
||||
* @param bufferSize Size of the copy buffer.
|
||||
* @throws IOException when an error occurs while copying.
|
||||
*/
|
||||
public static void transfer(InputStream in, OutputStream out, int bufferSize)
|
||||
throws IOException {
|
||||
byte[] buffer = new byte[bufferSize];
|
||||
int bytesRead;
|
||||
while ((bytesRead = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted string of the specified number. All trailing zeroes
|
||||
* or decimal points will be stripped.
|
||||
*
|
||||
* @param number Number to convert to a string.
|
||||
* @return A formatted string.
|
||||
*/
|
||||
public static String format(Number number) {
|
||||
String formatted;
|
||||
if (number instanceof Double || number instanceof Float) {
|
||||
formatted = Double.toString(number.doubleValue())
|
||||
.replaceAll("\\.0+$", "")
|
||||
.replaceAll("(\\.[0-9]*[1-9])0+$", "$1");
|
||||
} else {
|
||||
formatted = number.toString();
|
||||
}
|
||||
return formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted string of the specified object.
|
||||
*
|
||||
* @param obj Object to convert to a string.
|
||||
* @return A formatted string.
|
||||
*/
|
||||
public static String format(Object obj) {
|
||||
if (obj instanceof Number) {
|
||||
return format((Number) obj);
|
||||
} else {
|
||||
return obj.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of {@code float} numbers to a list of {@code Float}s.
|
||||
* The list will be empty if the array is empty or {@code null}.
|
||||
*
|
||||
* @param elements Array of float numbers.
|
||||
* @return A list with all numbers as {@code Float}.
|
||||
*/
|
||||
public static List<Float> asList(float[] elements) {
|
||||
int size = (elements != null) ? elements.length : 0;
|
||||
List<Float> list = new ArrayList<Float>(size);
|
||||
if (elements != null) {
|
||||
for (Float elem : elements) {
|
||||
list.add(elem);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of {@code double} numbers to a list of {@code Double}s.
|
||||
* The list will be empty if the array is empty or {@code null}.
|
||||
*
|
||||
* @param elements Array of double numbers.
|
||||
* @return A list with all numbers as {@code Double}.
|
||||
*/
|
||||
public static List<Double> asList(double[] elements) {
|
||||
int size = (elements != null) ? elements.length : 0;
|
||||
List<Double> list = new ArrayList<Double>(size);
|
||||
if (elements != null) {
|
||||
for (Double elem : elements) {
|
||||
list.add(elem);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified trailing pattern from a string.
|
||||
*
|
||||
* @param s string.
|
||||
* @param substr trailing pattern.
|
||||
* @return A string without the trailing pattern.
|
||||
*/
|
||||
public static String stripTrailing(String s, String substr) {
|
||||
return s.replaceAll("(" + Pattern.quote(substr) + ")+$", "");
|
||||
}
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.util;
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
|
||||
public class FlateEncodeStream extends DeflaterOutputStream {
|
||||
public FlateEncodeStream(OutputStream out) {
|
||||
super(out);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.util;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.Flushable;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class FormattingWriter implements Closeable, Flushable {
|
||||
private final OutputStream out;
|
||||
private final String encoding;
|
||||
private final String eolString;
|
||||
private long position;
|
||||
|
||||
public FormattingWriter(OutputStream out, String encoding, String eol) {
|
||||
this.out = out;
|
||||
this.encoding = encoding;
|
||||
this.eolString = eol;
|
||||
}
|
||||
|
||||
public FormattingWriter write(String string) throws IOException {
|
||||
byte[] bytes = string.getBytes(encoding);
|
||||
out.write(bytes, 0, bytes.length);
|
||||
position += bytes.length;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FormattingWriter write(Number number) throws IOException {
|
||||
write(DataUtils.format(number));
|
||||
return this;
|
||||
}
|
||||
|
||||
public FormattingWriter writeln() throws IOException {
|
||||
write(eolString);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FormattingWriter writeln(String string) throws IOException {
|
||||
write(string);
|
||||
write(eolString);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FormattingWriter writeln(Number number) throws IOException {
|
||||
write(number);
|
||||
write(eolString);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FormattingWriter format(String format, Object... args) throws IOException {
|
||||
write(String.format(null, format, args));
|
||||
return this;
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
out.flush();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
out.close();
|
||||
}
|
||||
|
||||
public long tell() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,411 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.util;
|
||||
|
||||
import javax.swing.ImageIcon;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.HeadlessException;
|
||||
import java.awt.Image;
|
||||
import java.awt.Polygon;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Transparency;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.TextLayout;
|
||||
import java.awt.geom.Arc2D;
|
||||
import java.awt.geom.CubicCurve2D;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.awt.geom.QuadCurve2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.ComponentColorModel;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.PixelGrabber;
|
||||
import java.awt.image.Raster;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.awt.image.WritableRaster;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.Hashtable;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Abstract class that contains utility functions for working with graphics.
|
||||
* For example, this includes font handling.
|
||||
*/
|
||||
public abstract class GraphicsUtils {
|
||||
private static final FontRenderContext FONT_RENDER_CONTEXT =
|
||||
new FontRenderContext(null, false, true);
|
||||
private static final String FONT_TEST_STRING =
|
||||
"Falsches Üben von Xylophonmusik quält jeden größeren Zwerg";
|
||||
private static final FontExpressivenessComparator FONT_EXPRESSIVENESS_COMPARATOR =
|
||||
new FontExpressivenessComparator();
|
||||
|
||||
/**
|
||||
* Default constructor that prevents creation of class.
|
||||
*/
|
||||
protected GraphicsUtils() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns {@code true} if the specified image has the
|
||||
* possibility to store transparent pixels.
|
||||
* Inspired by http://www.exampledepot.com/egs/java.awt.image/HasAlpha.html
|
||||
*
|
||||
* @param image Image that should be checked for alpha channel.
|
||||
* @return {@code true} if the specified image can have transparent pixels,
|
||||
* {@code false} otherwise
|
||||
*/
|
||||
public static boolean hasAlpha(Image image) {
|
||||
ColorModel cm;
|
||||
// If buffered image, the color model is readily available
|
||||
if (image instanceof BufferedImage) {
|
||||
BufferedImage bimage = (BufferedImage) image;
|
||||
cm = bimage.getColorModel();
|
||||
} else {
|
||||
// Use a pixel grabber to retrieve the image's color model;
|
||||
// grabbing a single pixel is usually sufficient
|
||||
PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
|
||||
try {
|
||||
pg.grabPixels();
|
||||
} catch (InterruptedException e) {
|
||||
return false;
|
||||
}
|
||||
// Get the image's color model
|
||||
cm = pg.getColorModel();
|
||||
}
|
||||
return cm.hasAlpha();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns {@code true} if the specified image has at least one
|
||||
* pixel that is not fully opaque.
|
||||
*
|
||||
* @param image Image that should be checked for non-opaque pixels.
|
||||
* @return {@code true} if the specified image has transparent pixels,
|
||||
* {@code false} otherwise
|
||||
*/
|
||||
public static boolean usesAlpha(Image image) {
|
||||
if (image == null) {
|
||||
return false;
|
||||
}
|
||||
BufferedImage bimage = toBufferedImage(image);
|
||||
Raster alphaRaster = bimage.getAlphaRaster();
|
||||
if (alphaRaster == null) {
|
||||
return false;
|
||||
}
|
||||
DataBuffer dataBuffer = alphaRaster.getDataBuffer();
|
||||
for (int i = 0; i < dataBuffer.getSize(); i++) {
|
||||
int alpha = dataBuffer.getElem(i);
|
||||
if (alpha < 255) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an arbitrary image to a {@code BufferedImage}.
|
||||
*
|
||||
* @param image Image that should be converted.
|
||||
* @return a buffered image containing the image pixels, or the original
|
||||
* instance if the image already was of type {@code BufferedImage}.
|
||||
*/
|
||||
public static BufferedImage toBufferedImage(RenderedImage image) {
|
||||
if (image instanceof BufferedImage) {
|
||||
return (BufferedImage) image;
|
||||
}
|
||||
|
||||
ColorModel cm = image.getColorModel();
|
||||
WritableRaster raster = cm.createCompatibleWritableRaster(
|
||||
image.getWidth(), image.getHeight());
|
||||
boolean isRasterPremultiplied = cm.isAlphaPremultiplied();
|
||||
Hashtable<String, Object> properties = null;
|
||||
if (image.getPropertyNames() != null) {
|
||||
properties = new Hashtable<String, Object>();
|
||||
for (String key : image.getPropertyNames()) {
|
||||
properties.put(key, image.getProperty(key));
|
||||
}
|
||||
}
|
||||
|
||||
BufferedImage bimage = new BufferedImage(cm, raster,
|
||||
isRasterPremultiplied, properties);
|
||||
image.copyData(raster);
|
||||
return bimage;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a buffered image with the contents of an image.
|
||||
* Taken from http://www.exampledepot.com/egs/java.awt.image/Image2Buf.html
|
||||
*
|
||||
* @param image Image to be converted
|
||||
* @return a buffered image with the contents of the specified image
|
||||
*/
|
||||
public static BufferedImage toBufferedImage(Image image) {
|
||||
if (image instanceof BufferedImage) {
|
||||
return (BufferedImage) image;
|
||||
}
|
||||
// This code ensures that all the pixels in the image are loaded
|
||||
image = new ImageIcon(image).getImage();
|
||||
// Determine if the image has transparent pixels
|
||||
boolean hasAlpha = hasAlpha(image);
|
||||
|
||||
// Create a buffered image with a format that's compatible with the
|
||||
// screen
|
||||
BufferedImage bimage;
|
||||
GraphicsEnvironment ge = GraphicsEnvironment
|
||||
.getLocalGraphicsEnvironment();
|
||||
try {
|
||||
// Determine the type of transparency of the new buffered image
|
||||
int transparency = Transparency.OPAQUE;
|
||||
if (hasAlpha) {
|
||||
transparency = Transparency.TRANSLUCENT;
|
||||
}
|
||||
// Create the buffered image
|
||||
GraphicsDevice gs = ge.getDefaultScreenDevice();
|
||||
GraphicsConfiguration gc = gs.getDefaultConfiguration();
|
||||
bimage = gc.createCompatibleImage(
|
||||
image.getWidth(null), image.getHeight(null), transparency);
|
||||
} catch (HeadlessException e) {
|
||||
// The system does not have a screen
|
||||
bimage = null;
|
||||
}
|
||||
if (bimage == null) {
|
||||
// Create a buffered image using the default color model
|
||||
int type = BufferedImage.TYPE_INT_RGB;
|
||||
if (hasAlpha) {
|
||||
type = BufferedImage.TYPE_INT_ARGB;
|
||||
}
|
||||
bimage = new BufferedImage(
|
||||
image.getWidth(null), image.getHeight(null), type);
|
||||
}
|
||||
// Copy image to buffered image
|
||||
Graphics g = bimage.createGraphics();
|
||||
// Paint the image onto the buffered image
|
||||
g.drawImage(image, 0, 0, null);
|
||||
g.dispose();
|
||||
return bimage;
|
||||
}
|
||||
|
||||
public static Shape clone(Shape shape) {
|
||||
if (shape == null) {
|
||||
return null;
|
||||
}
|
||||
Shape clone;
|
||||
if (shape instanceof Line2D) {
|
||||
clone = (shape instanceof Line2D.Float) ?
|
||||
new Line2D.Float() : new Line2D.Double();
|
||||
((Line2D) clone).setLine((Line2D) shape);
|
||||
} else if (shape instanceof Rectangle) {
|
||||
clone = new Rectangle((Rectangle) shape);
|
||||
} else if (shape instanceof Rectangle2D) {
|
||||
clone = (shape instanceof Rectangle2D.Float) ?
|
||||
new Rectangle2D.Float() : new Rectangle2D.Double();
|
||||
((Rectangle2D) clone).setRect((Rectangle2D) shape);
|
||||
} else if (shape instanceof RoundRectangle2D) {
|
||||
clone = (shape instanceof RoundRectangle2D.Float) ?
|
||||
new RoundRectangle2D.Float() : new RoundRectangle2D.Double();
|
||||
((RoundRectangle2D) clone).setRoundRect((RoundRectangle2D) shape);
|
||||
} else if (shape instanceof Ellipse2D) {
|
||||
clone = (shape instanceof Ellipse2D.Float) ?
|
||||
new Ellipse2D.Float() : new Ellipse2D.Double();
|
||||
((Ellipse2D) clone).setFrame(((Ellipse2D) shape).getFrame());
|
||||
} else if (shape instanceof Arc2D) {
|
||||
clone = (shape instanceof Arc2D.Float) ?
|
||||
new Arc2D.Float() : new Arc2D.Double();
|
||||
((Arc2D) clone).setArc((Arc2D) shape);
|
||||
} else if (shape instanceof Polygon) {
|
||||
Polygon p = (Polygon) shape;
|
||||
clone = new Polygon(p.xpoints, p.ypoints, p.npoints);
|
||||
} else if (shape instanceof CubicCurve2D) {
|
||||
clone = (shape instanceof CubicCurve2D.Float) ?
|
||||
new CubicCurve2D.Float() : new CubicCurve2D.Double();
|
||||
((CubicCurve2D) clone).setCurve((CubicCurve2D) shape);
|
||||
} else if (shape instanceof QuadCurve2D) {
|
||||
clone = (shape instanceof QuadCurve2D.Float) ?
|
||||
new QuadCurve2D.Float() : new QuadCurve2D.Double();
|
||||
((QuadCurve2D) clone).setCurve((QuadCurve2D) shape);
|
||||
} else if (shape instanceof Path2D.Float) {
|
||||
clone = new Path2D.Float(shape);
|
||||
} else {
|
||||
clone = new Path2D.Double(shape);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
private static boolean isLogicalFontFamily(String family) {
|
||||
return (Font.DIALOG.equals(family) ||
|
||||
Font.DIALOG_INPUT.equals(family) ||
|
||||
Font.SANS_SERIF.equals(family) ||
|
||||
Font.SERIF.equals(family) ||
|
||||
Font.MONOSPACED.equals(family));
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to guess physical font from the properties of a logical font, like
|
||||
* "Dialog", "Serif", "Monospaced" etc.
|
||||
*
|
||||
* @param logicalFont Logical font object.
|
||||
* @param testText Text used to determine font properties.
|
||||
* @return An object of the first matching physical font. The original font
|
||||
* object is returned if it was a physical font or no font matched.
|
||||
*/
|
||||
public static Font getPhysicalFont(Font logicalFont, String testText) {
|
||||
String logicalFamily = logicalFont.getFamily();
|
||||
if (!isLogicalFontFamily(logicalFamily)) {
|
||||
return logicalFont;
|
||||
}
|
||||
|
||||
final TextLayout logicalLayout =
|
||||
new TextLayout(testText, logicalFont, FONT_RENDER_CONTEXT);
|
||||
|
||||
// Create a list of matches sorted by font expressiveness (in descending order)
|
||||
Queue<Font> physicalFonts =
|
||||
new PriorityQueue<Font>(1, FONT_EXPRESSIVENESS_COMPARATOR);
|
||||
|
||||
Font[] allPhysicalFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
|
||||
for (Font physicalFont : allPhysicalFonts) {
|
||||
String physicalFamily = physicalFont.getFamily();
|
||||
// Skip logical fonts
|
||||
if (isLogicalFontFamily(physicalFamily)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Derive identical variant of physical font
|
||||
physicalFont = physicalFont.deriveFont(
|
||||
logicalFont.getStyle(), logicalFont.getSize2D());
|
||||
TextLayout physicalLayout =
|
||||
new TextLayout(testText, physicalFont, FONT_RENDER_CONTEXT);
|
||||
|
||||
// Compare various properties of physical and logical font
|
||||
if (physicalLayout.getBounds().equals(logicalLayout.getBounds()) &&
|
||||
physicalLayout.getAscent() == logicalLayout.getAscent() &&
|
||||
physicalLayout.getDescent() == logicalLayout.getDescent() &&
|
||||
physicalLayout.getLeading() == logicalLayout.getLeading() &&
|
||||
physicalLayout.getAdvance() == logicalLayout.getAdvance() &&
|
||||
physicalLayout.getVisibleAdvance() == logicalLayout.getVisibleAdvance()) {
|
||||
// Store matching font in list
|
||||
physicalFonts.add(physicalFont);
|
||||
}
|
||||
}
|
||||
|
||||
// Return a valid font even when no matching font could be found
|
||||
if (physicalFonts.isEmpty()) {
|
||||
return logicalFont;
|
||||
}
|
||||
|
||||
return physicalFonts.poll();
|
||||
}
|
||||
|
||||
public static Font getPhysicalFont(Font logicalFont) {
|
||||
return getPhysicalFont(logicalFont, FONT_TEST_STRING);
|
||||
}
|
||||
|
||||
public static BufferedImage getAlphaImage(BufferedImage image) {
|
||||
WritableRaster alphaRaster = image.getAlphaRaster();
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
|
||||
ColorModel cm;
|
||||
WritableRaster raster;
|
||||
// TODO Handle bitmap masks (work on ImageDataStream is necessary)
|
||||
/*
|
||||
if (image.getTransparency() == BufferedImage.BITMASK) {
|
||||
byte[] arr = {(byte) 0, (byte) 255};
|
||||
|
||||
cm = new IndexColorModel(1, 2, arr, arr, arr);
|
||||
raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
|
||||
width, height, 1, 1, null);
|
||||
} else {*/
|
||||
ColorSpace colorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);
|
||||
int[] bits = {8};
|
||||
cm = new ComponentColorModel(colorSpace, bits, false, true,
|
||||
Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
|
||||
raster = cm.createCompatibleWritableRaster(width, height);
|
||||
//}
|
||||
|
||||
BufferedImage alphaImage = new BufferedImage(cm, raster, false, null);
|
||||
|
||||
int[] alphaValues = new int[image.getWidth() * alphaRaster.getNumBands()];
|
||||
for (int y = 0; y < image.getHeight(); y++) {
|
||||
alphaRaster.getPixels(0, y, image.getWidth(), 1, alphaValues);
|
||||
// FIXME Don't force 8-bit alpha channel (see TODO above)
|
||||
if (image.getTransparency() == BufferedImage.BITMASK) {
|
||||
for (int i = 0; i < alphaValues.length; i++) {
|
||||
if (alphaValues[i] > 0) {
|
||||
alphaValues[i] = 255;
|
||||
}
|
||||
}
|
||||
}
|
||||
alphaImage.getRaster().setPixels(0, y, image.getWidth(), 1, alphaValues);
|
||||
}
|
||||
|
||||
return alphaImage;
|
||||
}
|
||||
|
||||
public static boolean equals(Shape shapeA, Shape shapeB) {
|
||||
PathIterator pathAIterator = shapeA.getPathIterator(null);
|
||||
PathIterator pathBIterator = shapeB.getPathIterator(null);
|
||||
|
||||
if (pathAIterator.getWindingRule() != pathBIterator.getWindingRule()) {
|
||||
return false;
|
||||
}
|
||||
double[] pathASegment = new double[6];
|
||||
double[] pathBSegment = new double[6];
|
||||
while (!pathAIterator.isDone()) {
|
||||
int pathASegmentType = pathAIterator.currentSegment(pathASegment);
|
||||
int pathBSegmentType = pathBIterator.currentSegment(pathBSegment);
|
||||
if (pathASegmentType != pathBSegmentType) {
|
||||
return false;
|
||||
}
|
||||
for (int segmentIndex = 0; segmentIndex < pathASegment.length; segmentIndex++) {
|
||||
if (pathASegment[segmentIndex] != pathBSegment[segmentIndex]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
pathAIterator.next();
|
||||
pathBIterator.next();
|
||||
}
|
||||
// When the iterator of shapeA is done and shapeA equals shapeB, the iterator of shapeB must also be done
|
||||
if (!pathBIterator.isDone()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static class FontExpressivenessComparator implements Comparator<Font> {
|
||||
private static final int[] STYLES = {
|
||||
Font.PLAIN, Font.ITALIC, Font.BOLD, Font.BOLD | Font.ITALIC
|
||||
};
|
||||
|
||||
public int compare(Font font1, Font font2) {
|
||||
if (font1 == font2) {
|
||||
return 0;
|
||||
}
|
||||
Set<String> variantNames1 = new HashSet<String>();
|
||||
Set<String> variantNames2 = new HashSet<String>();
|
||||
for (int style : STYLES) {
|
||||
variantNames1.add(font1.deriveFont(style).getPSName());
|
||||
variantNames2.add(font2.deriveFont(style).getPSName());
|
||||
}
|
||||
if (variantNames1.size() < variantNames2.size()) {
|
||||
return 1;
|
||||
} else if (variantNames1.size() > variantNames2.size()) {
|
||||
return -1;
|
||||
}
|
||||
return font1.getName().compareTo(font2.getName());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.util;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.Raster;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
public class ImageDataStream extends InputStream {
|
||||
private final BufferedImage image;
|
||||
private final int width;
|
||||
private final int height;
|
||||
private final Interleaving interleaving;
|
||||
private final Raster raster;
|
||||
private final boolean opaque;
|
||||
private final Queue<Integer> byteBuffer;
|
||||
private final int[] sampleValues;
|
||||
private final int[] sampleSizes;
|
||||
private int x;
|
||||
private int y;
|
||||
|
||||
public ImageDataStream(BufferedImage image, Interleaving interleaving) {
|
||||
this.image = image;
|
||||
this.interleaving = interleaving;
|
||||
|
||||
width = image.getWidth();
|
||||
height = image.getHeight();
|
||||
x = -1;
|
||||
y = 0;
|
||||
|
||||
Raster alphaRaster = image.getAlphaRaster();
|
||||
if (interleaving == Interleaving.ALPHA_ONLY) {
|
||||
raster = alphaRaster;
|
||||
} else {
|
||||
raster = image.getRaster();
|
||||
}
|
||||
opaque = alphaRaster == null;
|
||||
|
||||
byteBuffer = new LinkedList<Integer>();
|
||||
sampleValues = new int[raster.getNumBands()];
|
||||
sampleSizes = raster.getSampleModel().getSampleSize();
|
||||
}
|
||||
|
||||
public BufferedImage getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
public Interleaving getInterleaving() {
|
||||
return interleaving;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (!byteBuffer.isEmpty()) {
|
||||
return byteBuffer.poll();
|
||||
} else {
|
||||
if (!nextSample()) {
|
||||
return -1;
|
||||
}
|
||||
int bands = sampleValues.length;
|
||||
if (interleaving == Interleaving.WITHOUT_ALPHA ||
|
||||
interleaving == Interleaving.ALPHA_ONLY) {
|
||||
if (interleaving == Interleaving.WITHOUT_ALPHA && !opaque) {
|
||||
// Ignore alpha band
|
||||
bands--;
|
||||
}
|
||||
for (int band = 0; band < bands; band++) {
|
||||
bufferSampleValue(band);
|
||||
}
|
||||
} else {
|
||||
if (opaque) {
|
||||
for (int band = 0; band < bands; band++) {
|
||||
bufferSampleValue(band);
|
||||
}
|
||||
} else {
|
||||
for (int band = 0; band < bands; band++) {
|
||||
// Fix order to be ARGB instead of RGBA
|
||||
if (band == 0) {
|
||||
bufferSampleValue(bands - 1);
|
||||
} else {
|
||||
bufferSampleValue(band - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!byteBuffer.isEmpty()) {
|
||||
return byteBuffer.poll();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void bufferSampleValue(int band) {
|
||||
if (sampleSizes[band] < 8) {
|
||||
int byteValue = sampleValues[band] & 0xFF;
|
||||
byteBuffer.offer(byteValue);
|
||||
} else {
|
||||
int byteCount = sampleSizes[band] / 8;
|
||||
for (int i = byteCount - 1; i >= 0; i--) {
|
||||
int byteValue = (sampleValues[band] >> i * 8) & 0xFF;
|
||||
byteBuffer.offer(byteValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean nextSample() {
|
||||
if (interleaving == Interleaving.SAMPLE || interleaving == Interleaving.WITHOUT_ALPHA) {
|
||||
x++;
|
||||
if (x >= width) {
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
if (x < 0 || x >= width || y < 0 || y >= height) {
|
||||
return false;
|
||||
} else {
|
||||
raster.getPixel(x, y, sampleValues);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public enum Interleaving {
|
||||
SAMPLE,
|
||||
ROW,
|
||||
WITHOUT_ALPHA,
|
||||
ALPHA_ONLY
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.util;
|
||||
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class LineWrapOutputStream extends FilterOutputStream {
|
||||
public static final String STANDARD_EOL = "\r\n";
|
||||
|
||||
private final int lineWidth;
|
||||
private final byte[] eolBytes;
|
||||
private int written;
|
||||
|
||||
public LineWrapOutputStream(OutputStream sink, int lineWidth, String eol) {
|
||||
super(sink);
|
||||
this.lineWidth = lineWidth;
|
||||
this.eolBytes = eol.getBytes();
|
||||
if (lineWidth <= 0) {
|
||||
throw new IllegalArgumentException("Width must be at least 0.");
|
||||
}
|
||||
}
|
||||
|
||||
public LineWrapOutputStream(OutputStream sink, int lineWidth) {
|
||||
this(sink, lineWidth, STANDARD_EOL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
if (written == lineWidth) {
|
||||
out.write(eolBytes);
|
||||
written = 0;
|
||||
}
|
||||
out.write(b);
|
||||
written++;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.util;
|
||||
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
public class PageSize {
|
||||
private static final double MM_PER_INCH = 2.54;
|
||||
public static final PageSize TABLOID = new PageSize(11.0 * MM_PER_INCH, 17.0 * MM_PER_INCH);
|
||||
public static final PageSize LETTER = new PageSize(8.5 * MM_PER_INCH, 11.0 * MM_PER_INCH);
|
||||
public static final PageSize LEGAL = new PageSize(8.5 * MM_PER_INCH, 14.0 * MM_PER_INCH);
|
||||
public static final PageSize LEDGER = TABLOID.getLandscape();
|
||||
public static final PageSize A3 = new PageSize(297.0, 420.0);
|
||||
public static final PageSize A4 = new PageSize(210.0, 297.0);
|
||||
public static final PageSize A5 = new PageSize(148.0, 210.0);
|
||||
public final double x;
|
||||
public final double y;
|
||||
public final double width;
|
||||
public final double height;
|
||||
|
||||
public PageSize(double x, double y, double width, double height) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public PageSize(double width, double height) {
|
||||
this(0.0, 0.0, width, height);
|
||||
}
|
||||
|
||||
public PageSize(Rectangle2D size) {
|
||||
this(size.getX(), size.getY(), size.getWidth(), size.getHeight());
|
||||
}
|
||||
|
||||
public PageSize getPortrait() {
|
||||
if (width <= height) {
|
||||
return this;
|
||||
}
|
||||
return new PageSize(x, y, height, width);
|
||||
}
|
||||
|
||||
public PageSize getLandscape() {
|
||||
if (width >= height) {
|
||||
return this;
|
||||
}
|
||||
return new PageSize(x, y, height, width);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class GraphicsStateTest {
|
||||
|
||||
@Test
|
||||
public void testInitialStateIsEqualToGraphics2D() {
|
||||
BufferedImage image = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g2d = (Graphics2D) image.getGraphics();
|
||||
GraphicsState state = new GraphicsState();
|
||||
|
||||
assertEquals(state.getBackground(), g2d.getBackground());
|
||||
assertEquals(state.getColor(), g2d.getColor());
|
||||
assertEquals(state.getClip(), g2d.getClip());
|
||||
assertEquals(state.getComposite(), g2d.getComposite());
|
||||
assertEquals(state.getFont(), g2d.getFont());
|
||||
assertEquals(state.getPaint(), g2d.getPaint());
|
||||
assertEquals(state.getStroke(), g2d.getStroke());
|
||||
assertEquals(state.getTransform(), g2d.getTransform());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
GraphicsState state1 = new GraphicsState();
|
||||
state1.setBackground(Color.WHITE);
|
||||
state1.setColor(Color.BLACK);
|
||||
state1.setClip(new Rectangle2D.Double(0, 0, 10, 10));
|
||||
|
||||
GraphicsState state2 = new GraphicsState();
|
||||
state2.setBackground(Color.WHITE);
|
||||
state2.setColor(Color.BLACK);
|
||||
state2.setClip(new Rectangle2D.Double(0, 0, 10, 10));
|
||||
|
||||
assertEquals(state1, state2);
|
||||
|
||||
state2.setTransform(AffineTransform.getTranslateInstance(5, 5));
|
||||
|
||||
assertFalse(state1.equals(state2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClone() throws CloneNotSupportedException {
|
||||
GraphicsState state = new GraphicsState();
|
||||
state.setBackground(Color.BLUE);
|
||||
state.setColor(Color.GREEN);
|
||||
state.setClip(new Rectangle2D.Double(2, 3, 4, 2));
|
||||
|
||||
GraphicsState clone = (GraphicsState) state.clone();
|
||||
|
||||
assertNotSame(state, clone);
|
||||
assertEquals(state, clone);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,267 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public abstract class TestUtils {
|
||||
|
||||
protected TestUtils() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public static void assertTemplateEquals(Template expected, Template actual) {
|
||||
Iterator<Object> itExpected = expected.iterator();
|
||||
Iterator<Object> itActual = actual.iterator();
|
||||
while (itExpected.hasNext() && itActual.hasNext()) {
|
||||
Object lineExpected = itExpected.next();
|
||||
Object lineActual = itActual.next();
|
||||
|
||||
if (lineExpected == null) {
|
||||
continue;
|
||||
}
|
||||
assertTrue(lineActual instanceof String,
|
||||
String.format("Line is of type %s, expected String.", lineActual.getClass()));
|
||||
|
||||
if (lineExpected instanceof String) {
|
||||
assertEquals(lineExpected, lineActual);
|
||||
} else if (lineExpected instanceof Pattern) {
|
||||
Pattern expectedPattern = (Pattern) lineExpected;
|
||||
Matcher matcher = expectedPattern.matcher((String) lineActual);
|
||||
assertTrue(matcher.matches(),
|
||||
String.format("Line didn't match pattern.\nExpected: \"%s\"\nActual: \"%s\"", matcher.pattern(), lineActual));
|
||||
}
|
||||
}
|
||||
assertEquals(expected.size(), actual.size(), "Wrong number of lines in template.");
|
||||
}
|
||||
|
||||
private static List<XMLFragment> parseXML(String xmlString) {
|
||||
XMLFragment frag;
|
||||
List<XMLFragment> fragments = new LinkedList<XMLFragment>();
|
||||
int startPos = 0;
|
||||
while ((frag = XMLFragment.parse(xmlString, startPos)) != null) {
|
||||
fragments.add(frag);
|
||||
startPos = frag.matchEnd;
|
||||
}
|
||||
return fragments;
|
||||
}
|
||||
|
||||
public static void assertXMLEquals(String expected, String actual) {
|
||||
List<XMLFragment> expectedFrags = parseXML(expected);
|
||||
List<XMLFragment> actualFrags = parseXML(actual);
|
||||
|
||||
Iterator<XMLFragment> itExpected = expectedFrags.iterator();
|
||||
Iterator<XMLFragment> itActual = actualFrags.iterator();
|
||||
while (itExpected.hasNext() && itActual.hasNext()) {
|
||||
XMLFragment expectedFrag = itExpected.next();
|
||||
XMLFragment actualFrag = itActual.next();
|
||||
assertEquals(expectedFrag, actualFrag);
|
||||
}
|
||||
|
||||
assertEquals(expectedFrags.size(), actualFrags.size());
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class Template extends LinkedList<Object> {
|
||||
public Template(Object[] lines) {
|
||||
Collections.addAll(this, lines);
|
||||
}
|
||||
|
||||
public Template(Template[] templates) {
|
||||
for (Template template : templates) {
|
||||
addAll(template);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class XMLFragment {
|
||||
|
||||
private static final Pattern CDATA = Pattern.compile("\\s*<!\\[CDATA\\[(.*?)\\]\\]>");
|
||||
|
||||
private static final Pattern COMMENT = Pattern.compile("\\s*<!--(.*?)-->");
|
||||
|
||||
private static final Pattern TAG_BEGIN = Pattern.compile("\\s*<(/|\\?|!)?\\s*([^\\s>/\\?]+)");
|
||||
|
||||
private static final Pattern TAG_END = Pattern.compile("\\s*(/|\\?)?>");
|
||||
|
||||
private static final Pattern TAG_ATTRIBUTE = Pattern.compile("\\s*([^\\s>=]+)=(\"[^\"]*\"|'[^']*')");
|
||||
|
||||
private static final Pattern DOCTYPE_PART = Pattern.compile("\\s*(\"[^\"]*\"|'[^']*'|[^\\s>]+)");
|
||||
|
||||
public final String name;
|
||||
|
||||
public final FragmentType type;
|
||||
|
||||
public final Map<String, String> attributes;
|
||||
|
||||
public final int matchStart;
|
||||
|
||||
public final int matchEnd;
|
||||
|
||||
public XMLFragment(String name, FragmentType type, Map<String, String> attributes,
|
||||
int matchStart, int matchEnd) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.attributes = Collections.unmodifiableMap(
|
||||
new TreeMap<String, String>(attributes));
|
||||
this.matchStart = matchStart;
|
||||
this.matchEnd = matchEnd;
|
||||
}
|
||||
|
||||
public static XMLFragment parse(String xmlString, int matchStart) {
|
||||
Map<String, String> attrs = new IdentityHashMap<String, String>();
|
||||
|
||||
Matcher cdataMatch = CDATA.matcher(xmlString);
|
||||
cdataMatch.region(matchStart, xmlString.length());
|
||||
if (cdataMatch.lookingAt()) {
|
||||
attrs.put("value", cdataMatch.group(1));
|
||||
return new XMLFragment("", FragmentType.CDATA, attrs, matchStart, cdataMatch.end());
|
||||
}
|
||||
|
||||
Matcher commentMatch = COMMENT.matcher(xmlString);
|
||||
commentMatch.region(matchStart, xmlString.length());
|
||||
if (commentMatch.lookingAt()) {
|
||||
attrs.put("value", commentMatch.group(1).trim());
|
||||
return new XMLFragment("", FragmentType.COMMENT, attrs, matchStart, commentMatch.end());
|
||||
}
|
||||
|
||||
Matcher beginMatch = TAG_BEGIN.matcher(xmlString);
|
||||
beginMatch.region(matchStart, xmlString.length());
|
||||
if (!beginMatch.lookingAt()) {
|
||||
return null;
|
||||
}
|
||||
int matchEndPrev = beginMatch.end();
|
||||
|
||||
String modifiers = beginMatch.group(1);
|
||||
String name = beginMatch.group(2);
|
||||
boolean endTag = "/".equals(modifiers);
|
||||
boolean declarationStart = "?".equals(modifiers);
|
||||
boolean doctype = "!".equals(modifiers) && "DOCTYPE".equals(name);
|
||||
|
||||
if (doctype) {
|
||||
int partNo = 0;
|
||||
while (true) {
|
||||
Matcher attrMatch = DOCTYPE_PART.matcher(xmlString);
|
||||
attrMatch.region(matchEndPrev, xmlString.length());
|
||||
if (!attrMatch.lookingAt()) {
|
||||
break;
|
||||
}
|
||||
matchEndPrev = attrMatch.end();
|
||||
|
||||
String partValue = attrMatch.group(1);
|
||||
if (partValue.startsWith("\"") || partValue.startsWith("'")) {
|
||||
partValue = partValue.substring(1, partValue.length() - 1);
|
||||
}
|
||||
|
||||
String partId = String.format("doctype %02d", partNo++);
|
||||
attrs.put(partId, partValue);
|
||||
}
|
||||
} else {
|
||||
while (true) {
|
||||
Matcher attrMatch = TAG_ATTRIBUTE.matcher(xmlString);
|
||||
attrMatch.region(matchEndPrev, xmlString.length());
|
||||
if (!attrMatch.lookingAt()) {
|
||||
break;
|
||||
}
|
||||
matchEndPrev = attrMatch.end();
|
||||
|
||||
String attrName = attrMatch.group(1);
|
||||
String attrValue = attrMatch.group(2);
|
||||
attrValue = attrValue.substring(1, attrValue.length() - 1);
|
||||
attrs.put(attrName, attrValue);
|
||||
}
|
||||
}
|
||||
|
||||
Matcher endMatch = TAG_END.matcher(xmlString);
|
||||
endMatch.region(matchEndPrev, xmlString.length());
|
||||
if (!endMatch.lookingAt()) {
|
||||
throw new AssertionError(String.format("No tag end found: %s", xmlString.substring(0, matchEndPrev)));
|
||||
}
|
||||
matchEndPrev = endMatch.end();
|
||||
|
||||
modifiers = endMatch.group(1);
|
||||
boolean emptyElement = "/".equals(modifiers);
|
||||
boolean declarationEnd = "?".equals(modifiers);
|
||||
|
||||
FragmentType type = FragmentType.START_TAG;
|
||||
if (endTag) {
|
||||
type = FragmentType.END_TAG;
|
||||
} else if (emptyElement) {
|
||||
type = FragmentType.EMPTY_ELEMENT;
|
||||
} else if (declarationStart && declarationEnd) {
|
||||
type = FragmentType.DECLARATION;
|
||||
} else if (doctype) {
|
||||
type = FragmentType.DOCTYPE;
|
||||
}
|
||||
|
||||
return new XMLFragment(name, type, attrs, matchStart, matchEndPrev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof XMLFragment)) {
|
||||
return false;
|
||||
}
|
||||
XMLFragment frag = (XMLFragment) o;
|
||||
if (!type.equals(frag.type) || !name.equals(frag.name)) {
|
||||
return false;
|
||||
}
|
||||
Iterator<Map.Entry<String, String>> itThis = attributes.entrySet().iterator();
|
||||
Iterator<Map.Entry<String, String>> itFrag = frag.attributes.entrySet().iterator();
|
||||
while (itThis.hasNext() && itFrag.hasNext()) {
|
||||
Map.Entry<String, String> attrThis = itThis.next();
|
||||
Map.Entry<String, String> attrFrag = itFrag.next();
|
||||
if (!attrThis.getKey().equals(attrFrag.getKey()) ||
|
||||
!attrThis.getValue().equals(attrFrag.getValue())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return type.hashCode() ^ attributes.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder("<");
|
||||
if (FragmentType.END_TAG.equals(type)) {
|
||||
s.append("/");
|
||||
} else if (FragmentType.DECLARATION.equals(type)) {
|
||||
s.append("?");
|
||||
}
|
||||
|
||||
if (FragmentType.DOCTYPE.equals(type)) {
|
||||
s.append("!").append(name);
|
||||
for (String partValue : attributes.values()) {
|
||||
s.append(" ").append(partValue);
|
||||
}
|
||||
} else {
|
||||
s.append(name);
|
||||
for (Map.Entry<String, String> attr : attributes.entrySet()) {
|
||||
s.append(" ").append(attr.getKey()).append("=\"").append(attr.getValue()).append("\"");
|
||||
}
|
||||
}
|
||||
if (FragmentType.DECLARATION.equals(type)) {
|
||||
s.append("?");
|
||||
}
|
||||
s.append(">");
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
public enum FragmentType {
|
||||
START_TAG, END_TAG, EMPTY_ELEMENT, CDATA,
|
||||
DECLARATION, DOCTYPE, COMMENT
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,191 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.graphics.chart.io.vector.TestUtils.XMLFragment;
|
||||
|
||||
|
||||
public class TestUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testParseXmlStartTag() throws Exception {
|
||||
String xmlTagName = "foo:bar.baz_tag";
|
||||
String xmlString;
|
||||
XMLFragment frag;
|
||||
|
||||
xmlString = "<" + xmlTagName + ">";
|
||||
frag = XMLFragment.parse(xmlString, 0);
|
||||
assertEquals(xmlTagName, frag.name);
|
||||
assertEquals(XMLFragment.FragmentType.START_TAG, frag.type);
|
||||
assertTrue(frag.attributes.isEmpty());
|
||||
assertEquals(0, frag.matchStart);
|
||||
assertEquals(xmlString.length(), frag.matchEnd);
|
||||
|
||||
xmlString = "< " + xmlTagName + " >";
|
||||
frag = XMLFragment.parse(xmlString, 0);
|
||||
assertEquals(xmlTagName, frag.name);
|
||||
assertEquals(XMLFragment.FragmentType.START_TAG, frag.type);
|
||||
assertTrue(frag.attributes.isEmpty());
|
||||
assertEquals(0, frag.matchStart);
|
||||
assertEquals(xmlString.length(), frag.matchEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseXmlEndTag() throws Exception {
|
||||
String xmlTagName = "foo:bar.baz_tag";
|
||||
String xmlString;
|
||||
XMLFragment frag;
|
||||
|
||||
xmlString = "</" + xmlTagName + ">";
|
||||
frag = XMLFragment.parse(xmlString, 0);
|
||||
assertEquals(xmlTagName, frag.name);
|
||||
assertEquals(XMLFragment.FragmentType.END_TAG, frag.type);
|
||||
assertTrue(frag.attributes.isEmpty());
|
||||
assertEquals(0, frag.matchStart);
|
||||
assertEquals(xmlString.length(), frag.matchEnd);
|
||||
|
||||
xmlString = "</ " + xmlTagName + " >";
|
||||
frag = XMLFragment.parse(xmlString, 0);
|
||||
assertEquals(xmlTagName, frag.name);
|
||||
assertEquals(XMLFragment.FragmentType.END_TAG, frag.type);
|
||||
assertTrue(frag.attributes.isEmpty());
|
||||
assertEquals(0, frag.matchStart);
|
||||
assertEquals(xmlString.length(), frag.matchEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseXmlEmptyElement() throws Exception {
|
||||
String xmlTagName = "foo:bar.baz_tag";
|
||||
String xmlString;
|
||||
XMLFragment frag;
|
||||
|
||||
xmlString = "<" + xmlTagName + "/>";
|
||||
frag = XMLFragment.parse(xmlString, 0);
|
||||
assertEquals(xmlTagName, frag.name);
|
||||
assertEquals(XMLFragment.FragmentType.EMPTY_ELEMENT, frag.type);
|
||||
assertTrue(frag.attributes.isEmpty());
|
||||
assertEquals(0, frag.matchStart);
|
||||
assertEquals(xmlString.length(), frag.matchEnd);
|
||||
|
||||
xmlString = "< " + xmlTagName + " />";
|
||||
frag = XMLFragment.parse(xmlString, 0);
|
||||
assertEquals(xmlTagName, frag.name);
|
||||
assertEquals(XMLFragment.FragmentType.EMPTY_ELEMENT, frag.type);
|
||||
assertTrue(frag.attributes.isEmpty());
|
||||
assertEquals(0, frag.matchStart);
|
||||
assertEquals(xmlString.length(), frag.matchEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseXmlCDATA() throws Exception {
|
||||
String xmlString;
|
||||
XMLFragment frag;
|
||||
|
||||
xmlString = "<![CDATA[foo bar]]>";
|
||||
frag = XMLFragment.parse(xmlString, 0);
|
||||
assertEquals("", frag.name);
|
||||
assertEquals(XMLFragment.FragmentType.CDATA, frag.type);
|
||||
assertEquals("foo bar", frag.attributes.get("value"));
|
||||
assertEquals(0, frag.matchStart);
|
||||
assertEquals(xmlString.length(), frag.matchEnd);
|
||||
|
||||
xmlString = "<![CDATA[<nested>foo bar</nested>]]>";
|
||||
frag = XMLFragment.parse(xmlString, 0);
|
||||
assertEquals("", frag.name);
|
||||
assertEquals(XMLFragment.FragmentType.CDATA, frag.type);
|
||||
assertEquals("<nested>foo bar</nested>", frag.attributes.get("value"));
|
||||
assertEquals(0, frag.matchStart);
|
||||
assertEquals(xmlString.length(), frag.matchEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseXmlDeclaration() throws Exception {
|
||||
String xmlString;
|
||||
XMLFragment frag;
|
||||
|
||||
xmlString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
|
||||
frag = XMLFragment.parse(xmlString, 0);
|
||||
assertEquals("xml", frag.name);
|
||||
assertEquals(XMLFragment.FragmentType.DECLARATION, frag.type);
|
||||
assertEquals("1.0", frag.attributes.get("version"));
|
||||
assertEquals("UTF-8", frag.attributes.get("encoding"));
|
||||
assertEquals(0, frag.matchStart);
|
||||
assertEquals(xmlString.length(), frag.matchEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseXmlDoctype() throws Exception {
|
||||
String xmlString;
|
||||
XMLFragment frag;
|
||||
|
||||
xmlString = "<!DOCTYPE html>";
|
||||
frag = XMLFragment.parse(xmlString, 0);
|
||||
assertEquals(XMLFragment.FragmentType.DOCTYPE, frag.type);
|
||||
assertEquals("html", frag.attributes.get("doctype 00"));
|
||||
assertEquals(0, frag.matchStart);
|
||||
assertEquals(xmlString.length(), frag.matchEnd);
|
||||
|
||||
xmlString = "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1 Tiny//EN\"\n" +
|
||||
"\t\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd\">";
|
||||
frag = XMLFragment.parse(xmlString, 0);
|
||||
assertEquals(XMLFragment.FragmentType.DOCTYPE, frag.type);
|
||||
assertEquals("svg", frag.attributes.get("doctype 00"));
|
||||
assertEquals("PUBLIC", frag.attributes.get("doctype 01"));
|
||||
assertEquals("-//W3C//DTD SVG 1.1 Tiny//EN", frag.attributes.get("doctype 02"));
|
||||
assertEquals("http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd", frag.attributes.get("doctype 03"));
|
||||
assertEquals(0, frag.matchStart);
|
||||
assertEquals(xmlString.length(), frag.matchEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseXmlComment() throws Exception {
|
||||
String xmlString;
|
||||
XMLFragment frag;
|
||||
|
||||
xmlString = "<!-- foo bar -->";
|
||||
frag = XMLFragment.parse(xmlString, 0);
|
||||
assertEquals("", frag.name);
|
||||
assertEquals(XMLFragment.FragmentType.COMMENT, frag.type);
|
||||
assertEquals("foo bar", frag.attributes.get("value"));
|
||||
assertEquals(0, frag.matchStart);
|
||||
assertEquals(xmlString.length(), frag.matchEnd);
|
||||
|
||||
xmlString = "<!-- <nested>foo bar</nested> -->";
|
||||
frag = XMLFragment.parse(xmlString, 0);
|
||||
assertEquals("", frag.name);
|
||||
assertEquals(XMLFragment.FragmentType.COMMENT, frag.type);
|
||||
assertEquals("<nested>foo bar</nested>", frag.attributes.get("value"));
|
||||
assertEquals(0, frag.matchStart);
|
||||
assertEquals(xmlString.length(), frag.matchEnd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseXMLAttributesTag() throws Exception {
|
||||
String xmlTagName = "foo:bar.baz_tag";
|
||||
String xmlString;
|
||||
XMLFragment frag;
|
||||
|
||||
xmlString = "<" + xmlTagName + " foo='bar'>";
|
||||
frag = XMLFragment.parse(xmlString, 0);
|
||||
assertEquals(xmlTagName, frag.name);
|
||||
assertEquals("bar", frag.attributes.get("foo"));
|
||||
assertEquals(0, frag.matchStart);
|
||||
assertEquals(xmlString.length(), frag.matchEnd);
|
||||
|
||||
xmlString = "<" + xmlTagName + " foo=\"bar\">";
|
||||
frag = XMLFragment.parse(xmlString, 0);
|
||||
assertEquals(xmlTagName, frag.name);
|
||||
assertEquals("bar", frag.attributes.get("foo"));
|
||||
assertEquals(0, frag.matchStart);
|
||||
assertEquals(xmlString.length(), frag.matchEnd);
|
||||
|
||||
xmlString = "<" + xmlTagName + " foo=\"bar\" baz='qux'>";
|
||||
frag = XMLFragment.parse(xmlString, 0);
|
||||
assertEquals(xmlTagName, frag.name);
|
||||
assertEquals("bar", frag.attributes.get("foo"));
|
||||
assertEquals("qux", frag.attributes.get("baz"));
|
||||
assertEquals(0, frag.matchStart);
|
||||
assertEquals(xmlString.length(), frag.matchEnd);
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.CreateCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DisposeCommand;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class VectorGraphics2DTest {
|
||||
|
||||
@Test
|
||||
public void testEmptyVectorGraphics2DStartsWithCreateCommand() {
|
||||
VectorGraphics2D g = new VectorGraphics2D();
|
||||
Iterable<Command<?>> commands = g.getCommands();
|
||||
Iterator<Command<?>> commandIterator = commands.iterator();
|
||||
assertTrue(commandIterator.hasNext());
|
||||
Command<?> firstCommand = commandIterator.next();
|
||||
assertTrue(firstCommand instanceof CreateCommand);
|
||||
assertEquals(g, ((CreateCommand) firstCommand).getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateEmitsCreateCommand() {
|
||||
VectorGraphics2D g = new VectorGraphics2D();
|
||||
Iterable<Command<?>> gCommands = g.getCommands();
|
||||
Iterator<Command<?>> gCommandIterator = gCommands.iterator();
|
||||
CreateCommand gCreateCommand = (CreateCommand) gCommandIterator.next();
|
||||
|
||||
VectorGraphics2D g2 = (VectorGraphics2D) g.create();
|
||||
CreateCommand g2CreateCommand = null;
|
||||
for (Command<?> g2Command : g2.getCommands()) {
|
||||
if (g2Command instanceof CreateCommand) {
|
||||
g2CreateCommand = (CreateCommand) g2Command;
|
||||
}
|
||||
}
|
||||
assertNotNull(g2CreateCommand);
|
||||
assertNotEquals(gCreateCommand, g2CreateCommand);
|
||||
assertEquals(g2, g2CreateCommand.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisposeCommandEmitted() {
|
||||
VectorGraphics2D g = new VectorGraphics2D();
|
||||
g.setColor(Color.RED);
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
g2.setColor(Color.BLUE);
|
||||
g2.dispose();
|
||||
Iterable<Command<?>> commands = g.getCommands();
|
||||
Command<?> lastCommand = null;
|
||||
for (Command<?> command : commands) {
|
||||
lastCommand = command;
|
||||
}
|
||||
assertTrue(lastCommand instanceof DisposeCommand);
|
||||
assertEquals(Color.BLUE, ((DisposeCommand) lastCommand).getValue().getColor());
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.eps;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.graphics.chart.io.vector.Document;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.util.PageSize;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.xbib.graphics.chart.io.vector.TestUtils.Template;
|
||||
import static org.xbib.graphics.chart.io.vector.TestUtils.assertTemplateEquals;
|
||||
|
||||
public class EPSProcessorTest {
|
||||
private static final String EOL = "\n";
|
||||
private static final Object[] HEADER = {
|
||||
"%!PS-Adobe-3.0 EPSF-3.0",
|
||||
"%%BoundingBox: 0 28 57 114",
|
||||
"%%HiResBoundingBox: 0.0 28.34645669291339 56.69291338582678 113.38582677165356",
|
||||
"%%LanguageLevel: 3",
|
||||
"%%Pages: 1",
|
||||
"%%EndComments",
|
||||
"%%Page: 1 1",
|
||||
"/M /moveto load def",
|
||||
"/L /lineto load def",
|
||||
"/C /curveto load def",
|
||||
"/Z /closepath load def",
|
||||
"/RL /rlineto load def",
|
||||
"/rgb /setrgbcolor load def",
|
||||
"/rect { /height exch def /width exch def /y exch def /x exch def x y M width 0 RL 0 height RL width neg 0 RL } bind def",
|
||||
"/ellipse { /endangle exch def /startangle exch def /ry exch def /rx exch def /y exch def /x exch def /savematrix matrix currentmatrix def x y translate rx ry scale 0 0 1 startangle endangle arcn savematrix setmatrix } bind def",
|
||||
"/imgdict { /datastream exch def /hasdata exch def /decodeScale exch def /bits exch def /bands exch def /imgheight exch def /imgwidth exch def << /ImageType 1 /Width imgwidth /Height imgheight /BitsPerComponent bits /Decode [bands {0 decodeScale} repeat] ",
|
||||
"/ImageMatrix [imgwidth 0 0 imgheight 0 0] hasdata { /DataSource datastream } if >> } bind def",
|
||||
"/latinize { /fontName exch def /fontNameNew exch def fontName findfont 0 dict copy begin /Encoding ISOLatin1Encoding def fontNameNew /FontName def currentdict end dup /FID undef fontNameNew exch definefont pop } bind def",
|
||||
Pattern.compile("/\\S+?Lat /\\S+ latinize /\\S+?Lat 12.0 selectfont"),
|
||||
"gsave",
|
||||
"clipsave",
|
||||
"/DeviceRGB setcolorspace",
|
||||
"0 85.03937007874016 translate",
|
||||
"2.834645669291339 -2.834645669291339 scale",
|
||||
"/basematrix matrix currentmatrix def",
|
||||
"%%EOF"
|
||||
};
|
||||
private static final PageSize PAGE_SIZE = new PageSize(0.0, 10.0, 20.0, 30.0);
|
||||
|
||||
private final EPSProcessor processor = new EPSProcessor();
|
||||
private final List<Command<?>> commands = new LinkedList<Command<?>>();
|
||||
private final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
private String process(Command<?>... commands) throws IOException {
|
||||
Collections.addAll(this.commands, commands);
|
||||
Document processed = processor.process(this.commands, PAGE_SIZE);
|
||||
processed.write(bytes);
|
||||
return bytes.toString(StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void envelopeForEmptyDocument() throws IOException {
|
||||
String result = process();
|
||||
Template actual = new Template(result.split(EOL));
|
||||
Template expected = new Template(HEADER);
|
||||
assertTemplateEquals(expected, actual);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.filters;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.CreateCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DisposeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetTransformCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.TransformCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.TranslateCommand;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
public class AbsoluteToRelativeTransformsFilterTest {
|
||||
|
||||
@Test
|
||||
public void testAbsoluteAndRelativeTransformsIdentical() {
|
||||
AffineTransform absoluteTransform = new AffineTransform();
|
||||
absoluteTransform.rotate(42.0);
|
||||
absoluteTransform.translate(4.0, 2.0);
|
||||
List<Command<?>> commands = wrapCommands(
|
||||
new SetTransformCommand(absoluteTransform)
|
||||
);
|
||||
|
||||
AbsoluteToRelativeTransformsFilter filter = new AbsoluteToRelativeTransformsFilter(commands);
|
||||
|
||||
filter.next();
|
||||
AffineTransform relativeTransform = ((TransformCommand) filter.next()).getValue();
|
||||
assertThat(relativeTransform, is(absoluteTransform));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTranslateCorrect() {
|
||||
AffineTransform absoluteTransform = new AffineTransform();
|
||||
absoluteTransform.scale(2.0, 2.0);
|
||||
absoluteTransform.translate(4.2, 4.2); // (8.4, 8.4)
|
||||
List<Command<?>> commands = wrapCommands(
|
||||
new TranslateCommand(4.0, 2.0),
|
||||
new SetTransformCommand(absoluteTransform)
|
||||
);
|
||||
|
||||
AbsoluteToRelativeTransformsFilter filter = new AbsoluteToRelativeTransformsFilter(commands);
|
||||
|
||||
TransformCommand transformCommand = null;
|
||||
while (filter.hasNext()) {
|
||||
Command<?> filteredCommand = filter.next();
|
||||
if (filteredCommand instanceof TransformCommand) {
|
||||
transformCommand = (TransformCommand) filteredCommand;
|
||||
}
|
||||
}
|
||||
AffineTransform relativeTransform = transformCommand.getValue();
|
||||
assertThat(relativeTransform.getTranslateX(), is(4.4));
|
||||
assertThat(relativeTransform.getTranslateY(), is(6.4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRelativeTransformAfterDispose() {
|
||||
AffineTransform absoluteTransform = new AffineTransform();
|
||||
absoluteTransform.rotate(42.0);
|
||||
absoluteTransform.translate(4.0, 2.0);
|
||||
List<Command<?>> commands = wrapCommands(
|
||||
new CreateCommand(null),
|
||||
new TransformCommand(absoluteTransform),
|
||||
new DisposeCommand(null),
|
||||
new SetTransformCommand(absoluteTransform)
|
||||
);
|
||||
|
||||
AbsoluteToRelativeTransformsFilter filter = new AbsoluteToRelativeTransformsFilter(commands);
|
||||
TransformCommand lastTransformCommand = null;
|
||||
for (Command<?> filteredCommand : filter) {
|
||||
if (filteredCommand instanceof TransformCommand) {
|
||||
lastTransformCommand = (TransformCommand) filteredCommand;
|
||||
}
|
||||
}
|
||||
assertThat(lastTransformCommand.getValue(), is(absoluteTransform));
|
||||
}
|
||||
|
||||
private List<Command<?>> wrapCommands(Command<?>... commands) {
|
||||
List<Command<?>> commandList = new ArrayList<Command<?>>(commands.length + 2);
|
||||
commandList.add(new CreateCommand(null));
|
||||
commandList.addAll(Arrays.asList(commands));
|
||||
commandList.add(new DisposeCommand(null));
|
||||
return commandList;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.filters;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawImageCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.FillShapeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.RotateCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetPaintCommand;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.GradientPaint;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.any;
|
||||
import static org.hamcrest.CoreMatchers.hasItem;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
||||
public class FillPaintedShapeAsImageFilterTest {
|
||||
|
||||
@Test
|
||||
public void testFillShapeReplacedWithDrawImage() {
|
||||
List<Command<?>> commands = new LinkedList<Command<?>>();
|
||||
commands.add(new SetPaintCommand(new GradientPaint(0.0f, 0.0f, Color.BLACK, 100.0f, 100.0f, Color.WHITE)));
|
||||
commands.add(new RotateCommand(10.0, 4.0, 2.0));
|
||||
commands.add(new FillShapeCommand(new Rectangle2D.Double(10.0, 10.0, 100.0, 100.0)));
|
||||
|
||||
FillPaintedShapeAsImageFilter filter = new FillPaintedShapeAsImageFilter(commands);
|
||||
|
||||
assertThat(filter, hasItem(any(DrawImageCommand.class)));
|
||||
assertThat(filter, not(hasItem(any(FillShapeCommand.class))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFillShapeNotReplacedWithoutPaintCommand() {
|
||||
List<Command<?>> commands = new LinkedList<Command<?>>();
|
||||
commands.add(new RotateCommand(10.0, 4.0, 2.0));
|
||||
commands.add(new FillShapeCommand(new Rectangle2D.Double(10.0, 10.0, 100.0, 100.0)));
|
||||
|
||||
FillPaintedShapeAsImageFilter filter = new FillPaintedShapeAsImageFilter(commands);
|
||||
|
||||
Iterator<Command<?>> filterIterator = filter.iterator();
|
||||
for (Command<?> command : commands) {
|
||||
assertEquals(command, filterIterator.next());
|
||||
}
|
||||
assertFalse(filterIterator.hasNext());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.filters;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawShapeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetColorCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetStrokeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetTransformCommand;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class FilterTest {
|
||||
|
||||
@Test
|
||||
public void filterNone() {
|
||||
List<Command<?>> stream = new LinkedList<Command<?>>();
|
||||
stream.add(new SetColorCommand(Color.BLACK));
|
||||
stream.add(new SetStrokeCommand(new BasicStroke(1f)));
|
||||
stream.add(new DrawShapeCommand(new Line2D.Double(0.0, 1.0, 10.0, 11.0)));
|
||||
stream.add(new SetTransformCommand(AffineTransform.getTranslateInstance(5.0, 5.0)));
|
||||
stream.add(new DrawShapeCommand(new Line2D.Double(0.0, 1.0, 5.0, 6.0)));
|
||||
|
||||
Iterator<Command<?>> unfiltered = stream.iterator();
|
||||
|
||||
Filter filtered = new Filter(stream) {
|
||||
@Override
|
||||
protected List<Command<?>> filter(Command<?> command) {
|
||||
return Arrays.<Command<?>>asList(command);
|
||||
}
|
||||
};
|
||||
|
||||
while (filtered.hasNext() || unfiltered.hasNext()) {
|
||||
Command<?> expected = unfiltered.next();
|
||||
Command<?> result = filtered.next();
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterAll() {
|
||||
List<Command<?>> stream = new LinkedList<Command<?>>();
|
||||
stream.add(new SetColorCommand(Color.BLACK));
|
||||
stream.add(new SetStrokeCommand(new BasicStroke(1f)));
|
||||
stream.add(new DrawShapeCommand(new Line2D.Double(0.0, 1.0, 10.0, 11.0)));
|
||||
stream.add(new SetTransformCommand(AffineTransform.getTranslateInstance(5.0, 5.0)));
|
||||
stream.add(new DrawShapeCommand(new Line2D.Double(0.0, 1.0, 5.0, 6.0)));
|
||||
|
||||
Iterator<Command<?>> unfiltered = stream.iterator();
|
||||
|
||||
Filter filtered = new Filter(stream) {
|
||||
@Override
|
||||
protected List<Command<?>> filter(Command<?> command) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
assertTrue(unfiltered.hasNext());
|
||||
assertFalse(filtered.hasNext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void duplicate() {
|
||||
List<Command<?>> stream = new LinkedList<Command<?>>();
|
||||
stream.add(new SetColorCommand(Color.BLACK));
|
||||
stream.add(new SetStrokeCommand(new BasicStroke(1f)));
|
||||
stream.add(new DrawShapeCommand(new Line2D.Double(0.0, 1.0, 10.0, 11.0)));
|
||||
stream.add(new SetTransformCommand(AffineTransform.getTranslateInstance(5.0, 5.0)));
|
||||
stream.add(new DrawShapeCommand(new Line2D.Double(0.0, 1.0, 5.0, 6.0)));
|
||||
|
||||
Iterator<Command<?>> unfiltered = stream.iterator();
|
||||
|
||||
Filter filtered = new Filter(stream) {
|
||||
@Override
|
||||
protected List<Command<?>> filter(Command<?> command) {
|
||||
return Arrays.asList(command, command);
|
||||
}
|
||||
};
|
||||
|
||||
while (filtered.hasNext() || unfiltered.hasNext()) {
|
||||
Command<?> expected = unfiltered.next();
|
||||
Command<?> result1 = filtered.next();
|
||||
Command<?> result2 = filtered.next();
|
||||
assertEquals(expected, result1);
|
||||
assertEquals(expected, result2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.intermediate.filters;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawShapeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Group;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetColorCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetStrokeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.SetTransformCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.StateCommand;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class GroupingFilterTest {
|
||||
|
||||
@Test
|
||||
public void filtered() {
|
||||
List<Command<?>> resultStream = new LinkedList<Command<?>>();
|
||||
resultStream.add(new SetColorCommand(Color.BLACK));
|
||||
resultStream.add(new SetStrokeCommand(new BasicStroke(1f)));
|
||||
resultStream.add(new DrawShapeCommand(new Line2D.Double(0.0, 1.0, 10.0, 11.0)));
|
||||
resultStream.add(new SetTransformCommand(AffineTransform.getTranslateInstance(5.0, 5.0)));
|
||||
resultStream.add(new DrawShapeCommand(new Line2D.Double(0.0, 1.0, 5.0, 6.0)));
|
||||
List<Command<?>> expectedStream = new LinkedList<Command<?>>();
|
||||
Iterator<Command<?>> resultCloneIterator = resultStream.iterator();
|
||||
Group group1 = new Group();
|
||||
group1.add(resultCloneIterator.next());
|
||||
group1.add(resultCloneIterator.next());
|
||||
expectedStream.add(group1);
|
||||
expectedStream.add(resultCloneIterator.next());
|
||||
Group group2 = new Group();
|
||||
group2.add(resultCloneIterator.next());
|
||||
expectedStream.add(group2);
|
||||
expectedStream.add(resultCloneIterator.next());
|
||||
Iterator<Command<?>> expectedIterator = expectedStream.iterator();
|
||||
Filter resultIterator = new GroupingFilter(resultStream) {
|
||||
@Override
|
||||
protected boolean isGrouped(Command<?> command) {
|
||||
return command instanceof StateCommand;
|
||||
}
|
||||
};
|
||||
while (resultIterator.hasNext() || expectedIterator.hasNext()) {
|
||||
Command<?> result = resultIterator.next();
|
||||
Command<?> expected = expectedIterator.next();
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.pdf;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.graphics.chart.io.vector.Document;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.util.PageSize;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.xbib.graphics.chart.io.vector.TestUtils.Template;
|
||||
import static org.xbib.graphics.chart.io.vector.TestUtils.assertTemplateEquals;
|
||||
|
||||
public class PDFProcessorTest {
|
||||
private static final String EOL = "\n";
|
||||
private static final String HEADER = "%PDF-1.4";
|
||||
private static final String FOOTER = "%%EOF";
|
||||
private static final PageSize PAGE_SIZE = new PageSize(0.0, 10.0, 20.0, 30.0);
|
||||
|
||||
private final PDFProcessor processor = new PDFProcessor();
|
||||
private final List<Command<?>> commands = new LinkedList<Command<?>>();
|
||||
private final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
private String process(Command<?>... commands) throws IOException {
|
||||
Collections.addAll(this.commands, commands);
|
||||
Document processed = processor.process(this.commands, PAGE_SIZE);
|
||||
processed.write(bytes);
|
||||
return bytes.toString(StandardCharsets.ISO_8859_1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void envelopeForEmptyDocument() throws IOException {
|
||||
String result = process();
|
||||
Template actual = new Template(result.split(EOL));
|
||||
Template expected = new Template(new Object[]{
|
||||
HEADER,
|
||||
"1 0 obj",
|
||||
"<<",
|
||||
"/Type /Catalog",
|
||||
"/Pages 2 0 R",
|
||||
">>",
|
||||
"endobj",
|
||||
"2 0 obj",
|
||||
"<<",
|
||||
"/Type /Pages",
|
||||
"/Kids [3 0 R]",
|
||||
"/Count 1",
|
||||
">>",
|
||||
"endobj",
|
||||
"3 0 obj",
|
||||
"<<",
|
||||
"/Type /Page",
|
||||
"/Parent 2 0 R",
|
||||
"/MediaBox [0 28.34645669291339 56.69291338582678 85.03937007874016]",
|
||||
"/Contents 4 0 R",
|
||||
"/Resources 6 0 R",
|
||||
">>",
|
||||
"endobj",
|
||||
"4 0 obj",
|
||||
"<<",
|
||||
"/Length 5 0 R",
|
||||
">>",
|
||||
"stream",
|
||||
"q",
|
||||
"1 1 1 rg 1 1 1 RG",
|
||||
"2.834645669291339 0 0 -2.834645669291339 0 85.03937007874016 cm",
|
||||
"/Fnt0 12.0 Tf",
|
||||
"Q",
|
||||
"endstream",
|
||||
"endobj",
|
||||
"5 0 obj",
|
||||
"100",
|
||||
"endobj",
|
||||
"6 0 obj",
|
||||
"<<",
|
||||
"/ProcSet [/PDF /Text /ImageB /ImageC /ImageI]",
|
||||
"/Font <<",
|
||||
"/Fnt0 <<",
|
||||
"/Type /Font",
|
||||
"/Subtype /TrueType",
|
||||
"/Encoding /WinAnsiEncoding",
|
||||
Pattern.compile("/BaseFont /\\S+"),
|
||||
">>",
|
||||
">>",
|
||||
">>",
|
||||
"endobj",
|
||||
"xref",
|
||||
"0 7",
|
||||
"0000000000 65535 f ",
|
||||
Pattern.compile("\\d{10} 00000 n "),
|
||||
Pattern.compile("\\d{10} 00000 n "),
|
||||
Pattern.compile("\\d{10} 00000 n "),
|
||||
Pattern.compile("\\d{10} 00000 n "),
|
||||
Pattern.compile("\\d{10} 00000 n "),
|
||||
Pattern.compile("\\d{10} 00000 n "),
|
||||
"trailer",
|
||||
"<<",
|
||||
"/Size 7",
|
||||
"/Root 1 0 R",
|
||||
">>",
|
||||
"startxref",
|
||||
Pattern.compile("[1-9]\\d*"),
|
||||
FOOTER
|
||||
});
|
||||
|
||||
assertTemplateEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.svg;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.xbib.graphics.chart.io.vector.Document;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.Command;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.DrawShapeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.intermediate.commands.FillShapeCommand;
|
||||
import org.xbib.graphics.chart.io.vector.util.PageSize;
|
||||
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.xbib.graphics.chart.io.vector.TestUtils.assertXMLEquals;
|
||||
|
||||
public class SVGProcessorTest {
|
||||
private static final String EOL = "\n";
|
||||
private static final String HEADER =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>" + EOL +
|
||||
"<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">" + EOL +
|
||||
"<svg height=\"10.583332098611255mm\" version=\"1.1\" viewBox=\"0 10 20 30\" width=\"7.0555547324075025mm\" x=\"0mm\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" y=\"3.5277773662037513mm\">" + EOL;
|
||||
private static final String FOOTER = "</svg>";
|
||||
private static final PageSize PAGE_SIZE = new PageSize(0.0, 10.0, 20.0, 30.0);
|
||||
|
||||
private final SVGProcessor processor = new SVGProcessor();
|
||||
private final List<Command<?>> commands = new LinkedList<Command<?>>();
|
||||
private final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
|
||||
private String process(Command<?>... commands) throws IOException {
|
||||
Collections.addAll(this.commands, commands);
|
||||
Document processed = processor.process(this.commands, PAGE_SIZE);
|
||||
processed.write(bytes);
|
||||
return bytes.toString(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void envelopeForEmptyDocument() throws Exception {
|
||||
String result = process();
|
||||
String expected = HEADER.replaceAll(">$", "/>");
|
||||
assertXMLEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void drawShapeBlack() throws Exception {
|
||||
String result = process(
|
||||
new DrawShapeCommand(new Rectangle2D.Double(1, 2, 3, 4))
|
||||
);
|
||||
String expected =
|
||||
HEADER + EOL +
|
||||
" <rect height=\"4\" style=\"fill:none;stroke:rgb(255,255,255);stroke-miterlimit:10;stroke-linecap:square;\" width=\"3\" x=\"1\" y=\"2\"/>" + EOL +
|
||||
FOOTER;
|
||||
assertXMLEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fillShapeBlack() throws Exception {
|
||||
String result = process(
|
||||
new FillShapeCommand(new Rectangle2D.Double(1, 2, 3, 4))
|
||||
);
|
||||
String expected =
|
||||
HEADER + EOL +
|
||||
" <rect height=\"4\" style=\"fill:rgb(255,255,255);stroke:none;\" width=\"3\" x=\"1\" y=\"2\"/>" + EOL +
|
||||
FOOTER;
|
||||
assertXMLEquals(expected, result);
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class ASCII85EncodeStreamTest {
|
||||
|
||||
private static void assertEncodedString(String expected, String input) throws IOException {
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(input.getBytes());
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||
OutputStream encodeStream = new ASCII85EncodeStream(outStream);
|
||||
byte[] buffer = new byte[1024];
|
||||
for (int count = inputStream.read(buffer); count >= 0; count = inputStream.read(buffer)) {
|
||||
encodeStream.write(buffer, 0, count);
|
||||
}
|
||||
encodeStream.close();
|
||||
String encoded = outStream.toString(StandardCharsets.ISO_8859_1);
|
||||
assertEquals(expected, encoded);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncoding() throws IOException {
|
||||
String input =
|
||||
"Man is distinguished, not only by his reason, but by this singular passion " +
|
||||
"from other animals, which is a lust of the mind, that by a perseverance of " +
|
||||
"delight in the continued and indefatigable generation of knowledge, exceeds " +
|
||||
"the short vehemence of any carnal pleasure.";
|
||||
|
||||
String expected =
|
||||
"9jqo^BlbD-BleB1DJ+*+F(f,q/0JhKF<GL>Cj@.4Gp$d7F!,L7@<6@)/0JDEF<G%<+EV:2F!,O<DJ+*." +
|
||||
"@<*K0@<6L(Df-\\0Ec5e;DffZ(EZee.Bl.9pF\"AGXBPCsi+DGm>@3BB/F*&OCAfu2/AKYi(DIb:@FD,*)" +
|
||||
"+C]U=@3BN#EcYf8ATD3s@q?d$AftVqCh[NqF<G:8+EV:.+Cf>-FD5W8ARlolDIal(DId<j@<?3r@:F%a" +
|
||||
"+D58'ATD4$Bl@l3De:,-DJs`8ARoFb/0JMK@qB4^F!,R<AKZ&-DfTqBG%G>uD.RTpAKYo'+CT/5+Cei#" +
|
||||
"DII?(E,9)oF*2M7/c~>";
|
||||
|
||||
assertEncodedString(expected, input);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPadding() throws IOException {
|
||||
assertEncodedString("/c~>", ".");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmpty() throws IOException {
|
||||
assertEncodedString("~>", "");
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class Base64EncodeStreamTest {
|
||||
|
||||
private static void assertEncodedString(String expected, String input) throws IOException {
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(input.getBytes());
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||
OutputStream encodeStream = new Base64EncodeStream(outStream);
|
||||
byte[] buffer = new byte[1024];
|
||||
for (int count = inputStream.read(buffer); count >= 0; count = inputStream.read(buffer)) {
|
||||
encodeStream.write(buffer, 0, count);
|
||||
}
|
||||
encodeStream.close();
|
||||
String encoded = outStream.toString(StandardCharsets.ISO_8859_1);
|
||||
assertEquals(expected, encoded);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncoding() throws IOException {
|
||||
String input =
|
||||
"Man is distinguished, not only by his reason, but by this singular passion " +
|
||||
"from other animals, which is a lust of the mind, that by a perseverance of " +
|
||||
"delight in the continued and indefatigable generation of knowledge, exceeds " +
|
||||
"the short vehemence of any carnal pleasure.";
|
||||
|
||||
String expected =
|
||||
"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlz" +
|
||||
"IHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2Yg" +
|
||||
"dGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGlu" +
|
||||
"dWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRo" +
|
||||
"ZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4=";
|
||||
|
||||
assertEncodedString(expected, input);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPadding() throws IOException {
|
||||
assertEncodedString("YW55IGNhcm5hbCBwbGVhc3VyZS4=", "any carnal pleasure.");
|
||||
assertEncodedString("YW55IGNhcm5hbCBwbGVhc3VyZQ==", "any carnal pleasure");
|
||||
assertEncodedString("YW55IGNhcm5hbCBwbGVhc3Vy", "any carnal pleasur");
|
||||
assertEncodedString("YW55IGNhcm5hbCBwbGVhc3U=", "any carnal pleasu");
|
||||
assertEncodedString("YW55IGNhcm5hbCBwbGVhcw==", "any carnal pleas");
|
||||
|
||||
assertEncodedString("cGxlYXN1cmUu", "pleasure.");
|
||||
assertEncodedString("bGVhc3VyZS4=", "leasure.");
|
||||
assertEncodedString("ZWFzdXJlLg==", "easure.");
|
||||
assertEncodedString("YXN1cmUu", "asure.");
|
||||
assertEncodedString("c3VyZS4=", "sure.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmpty() throws IOException {
|
||||
assertEncodedString("", "");
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class DataUtilsTest {
|
||||
|
||||
@Test
|
||||
public void stripTrailingSpaces() {
|
||||
String result = DataUtils.stripTrailing(" foo bar! ", " ");
|
||||
String expected = " foo bar!";
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stripTrailingSpacesInMultilineString() {
|
||||
String result = DataUtils.stripTrailing(" foo bar! \n ", " ");
|
||||
String expected = " foo bar! \n";
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void stripComplexSubstring() {
|
||||
String result = DataUtils.stripTrailing("+bar foo+bar+bar+bar", "+bar");
|
||||
String expected = "+bar foo";
|
||||
assertEquals(expected, result);
|
||||
}
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.util;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import java.awt.Font;
|
||||
import java.awt.Image;
|
||||
import java.awt.Polygon;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Shape;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.geom.Arc2D;
|
||||
import java.awt.geom.CubicCurve2D;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.PathIterator;
|
||||
import java.awt.geom.QuadCurve2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.FilteredImageSource;
|
||||
import java.awt.image.RGBImageFilter;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* On Linux, the package msttcorefonts need to be installed
|
||||
*/
|
||||
public class GraphicsUtilsTest {
|
||||
private static final double DELTA = 1e-15;
|
||||
|
||||
private static void assertShapeEquals(Shape expected, Shape actual) {
|
||||
if ((expected instanceof Line2D) && (actual instanceof Line2D)) {
|
||||
assertEquals(((Line2D) expected).getP1(), ((Line2D) actual).getP1());
|
||||
assertEquals(((Line2D) expected).getP2(), ((Line2D) actual).getP2());
|
||||
} else if ((expected instanceof Polygon) && (actual instanceof Polygon)) {
|
||||
int n = ((Polygon) actual).npoints;
|
||||
assertEquals(((Polygon) expected).npoints, n);
|
||||
if (n > 0) {
|
||||
assertArrayEquals(((Polygon) expected).xpoints, ((Polygon) actual).xpoints);
|
||||
assertArrayEquals(((Polygon) expected).ypoints, ((Polygon) actual).ypoints);
|
||||
}
|
||||
} else if ((expected instanceof QuadCurve2D) && (actual instanceof QuadCurve2D)) {
|
||||
assertEquals(((QuadCurve2D) expected).getP1(), ((QuadCurve2D) actual).getP1());
|
||||
assertEquals(((QuadCurve2D) expected).getCtrlPt(), ((QuadCurve2D) actual).getCtrlPt());
|
||||
assertEquals(((QuadCurve2D) expected).getP2(), ((QuadCurve2D) actual).getP2());
|
||||
} else if ((expected instanceof CubicCurve2D) && (actual instanceof CubicCurve2D)) {
|
||||
assertEquals(((CubicCurve2D) expected).getP1(), ((CubicCurve2D) actual).getP1());
|
||||
assertEquals(((CubicCurve2D) expected).getCtrlP1(), ((CubicCurve2D) actual).getCtrlP1());
|
||||
assertEquals(((CubicCurve2D) expected).getCtrlP2(), ((CubicCurve2D) actual).getCtrlP2());
|
||||
assertEquals(((CubicCurve2D) expected).getP2(), ((CubicCurve2D) actual).getP2());
|
||||
} else if ((expected instanceof Path2D) && (actual instanceof Path2D)) {
|
||||
PathIterator itExpected = expected.getPathIterator(null);
|
||||
PathIterator itActual = actual.getPathIterator(null);
|
||||
double[] segmentExpected = new double[6];
|
||||
double[] segmentActual = new double[6];
|
||||
for (; !itExpected.isDone() || !itActual.isDone(); itExpected.next(), itActual.next()) {
|
||||
assertEquals(itExpected.getWindingRule(), itActual.getWindingRule());
|
||||
itExpected.currentSegment(segmentExpected);
|
||||
itActual.currentSegment(segmentActual);
|
||||
assertArrayEquals(segmentExpected, segmentActual, DELTA);
|
||||
}
|
||||
} else {
|
||||
assertEquals(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToBufferedImage() {
|
||||
Image[] images = {
|
||||
new BufferedImage(320, 240, BufferedImage.TYPE_INT_ARGB),
|
||||
new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB),
|
||||
Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(
|
||||
new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB).getSource(),
|
||||
new RGBImageFilter() {
|
||||
@Override
|
||||
public int filterRGB(int x, int y, int rgb) {
|
||||
return rgb & 0xff;
|
||||
}
|
||||
}
|
||||
))
|
||||
};
|
||||
|
||||
for (Image image : images) {
|
||||
BufferedImage bimage = GraphicsUtils.toBufferedImage(image);
|
||||
assertNotNull(bimage);
|
||||
assertEquals(BufferedImage.class, bimage.getClass());
|
||||
assertEquals(image.getWidth(null), bimage.getWidth());
|
||||
assertEquals(image.getHeight(null), bimage.getHeight());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHasAlpha() {
|
||||
Image image;
|
||||
image = new BufferedImage(320, 240, BufferedImage.TYPE_INT_ARGB);
|
||||
assertTrue(GraphicsUtils.hasAlpha(image));
|
||||
image = new BufferedImage(320, 240, BufferedImage.TYPE_INT_RGB);
|
||||
assertFalse(GraphicsUtils.hasAlpha(image));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPhysicalFont() {
|
||||
Font font = new Font("Monospaced", Font.PLAIN, 12);
|
||||
assertNotSame(font, GraphicsUtils.getPhysicalFont(font));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCloneShape()
|
||||
throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
|
||||
Class<?>[] shapeClasses = {
|
||||
Line2D.Float.class,
|
||||
Line2D.Double.class,
|
||||
Rectangle.class,
|
||||
Rectangle2D.Float.class,
|
||||
Rectangle2D.Double.class,
|
||||
RoundRectangle2D.Float.class,
|
||||
RoundRectangle2D.Double.class,
|
||||
Ellipse2D.Float.class,
|
||||
Ellipse2D.Double.class,
|
||||
Arc2D.Float.class,
|
||||
Arc2D.Double.class,
|
||||
Polygon.class,
|
||||
CubicCurve2D.Float.class,
|
||||
CubicCurve2D.Double.class,
|
||||
QuadCurve2D.Float.class,
|
||||
QuadCurve2D.Double.class,
|
||||
Path2D.Float.class,
|
||||
Path2D.Double.class
|
||||
};
|
||||
for (Class<?> shapeClass : shapeClasses) {
|
||||
Shape shape = (Shape) shapeClass.getDeclaredConstructor().newInstance();
|
||||
Shape clone = GraphicsUtils.clone(shape);
|
||||
assertNotNull(clone);
|
||||
assertShapeEquals(shape, clone);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.visual;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.EPSGraphics2D;
|
||||
import org.xbib.graphics.chart.io.vector.PDFGraphics2D;
|
||||
import org.xbib.graphics.chart.io.vector.SVGGraphics2D;
|
||||
import org.xbib.graphics.chart.io.vector.util.PageSize;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public abstract class AbstractTest {
|
||||
|
||||
private final PageSize pageSize;
|
||||
|
||||
private final BufferedImage reference;
|
||||
|
||||
private final EPSGraphics2D epsGraphics;
|
||||
|
||||
private final PDFGraphics2D pdfGraphics;
|
||||
|
||||
private final SVGGraphics2D svgGraphics;
|
||||
|
||||
public AbstractTest() {
|
||||
int width = 150;
|
||||
int height = 150;
|
||||
pageSize = new PageSize(0.0, 0.0, width, height);
|
||||
epsGraphics = new EPSGraphics2D(0, 0, width, height);
|
||||
draw(epsGraphics);
|
||||
pdfGraphics = new PDFGraphics2D(0, 0, width, height);
|
||||
draw(pdfGraphics);
|
||||
svgGraphics = new SVGGraphics2D(0, 0, width, height);
|
||||
draw(svgGraphics);
|
||||
reference = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D referenceGraphics = reference.createGraphics();
|
||||
referenceGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
referenceGraphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
referenceGraphics.setBackground(new Color(1f, 1f, 1f, 0f));
|
||||
referenceGraphics.clearRect(0, 0, reference.getWidth(), reference.getHeight());
|
||||
referenceGraphics.setColor(Color.BLACK);
|
||||
draw(referenceGraphics);
|
||||
try {
|
||||
File referenceImage = File.createTempFile(getClass().getName() + ".reference", ".png");
|
||||
referenceImage.deleteOnExit();
|
||||
ImageIO.write(reference, "png", referenceImage);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void draw(Graphics2D g);
|
||||
|
||||
public PageSize getPageSize() {
|
||||
return pageSize;
|
||||
}
|
||||
|
||||
public BufferedImage getReference() {
|
||||
return reference;
|
||||
}
|
||||
|
||||
public InputStream getEPS() {
|
||||
return new ByteArrayInputStream(epsGraphics.getBytes());
|
||||
}
|
||||
|
||||
public InputStream getPDF() {
|
||||
return new ByteArrayInputStream(pdfGraphics.getBytes());
|
||||
}
|
||||
|
||||
public InputStream getSVG() {
|
||||
return new ByteArrayInputStream(svgGraphics.getBytes());
|
||||
}
|
||||
|
||||
/*public BufferedImage getRasterizedEPS() throws GhostscriptException, IOException {
|
||||
if (rasterizedEPS != null) {
|
||||
return rasterizedEPS;
|
||||
}
|
||||
|
||||
File epsInputFile = File.createTempFile(getClass().getName() + ".testEPS", ".eps");
|
||||
epsInputFile.deleteOnExit();
|
||||
OutputStream epsInput = new FileOutputStream(epsInputFile);
|
||||
epsInput.write(epsGraphics.getBytes());
|
||||
epsInput.close();
|
||||
|
||||
File pngOutputFile = File.createTempFile(getClass().getName() + ".testEPS", "png");
|
||||
pngOutputFile.deleteOnExit();
|
||||
Ghostscript gs = Ghostscript.getInstance();
|
||||
gs.initialize(new String[]{
|
||||
"-dBATCH",
|
||||
"-dQUIET",
|
||||
"-dNOPAUSE",
|
||||
"-dSAFER",
|
||||
String.format("-g%dx%d", Math.round(getPageSize().width), Math.round(getPageSize().height)),
|
||||
"-dGraphicsAlphaBits=4",
|
||||
"-dAlignToPixels=0",
|
||||
"-dEPSCrop",
|
||||
"-dPSFitPage",
|
||||
"-sDEVICE=pngalpha",
|
||||
"-sOutputFile=" + pngOutputFile.toString(),
|
||||
epsInputFile.toString()
|
||||
});
|
||||
gs.exit();
|
||||
rasterizedEPS = ImageIO.read(pngOutputFile);
|
||||
return rasterizedEPS;
|
||||
}*/
|
||||
|
||||
/*public BufferedImage getRasterizedPDF() throws GhostscriptException, IOException {
|
||||
if (rasterizedPDF != null) {
|
||||
return rasterizedPDF;
|
||||
}
|
||||
|
||||
File pdfInputFile = File.createTempFile(getClass().getName() + ".testPDF", ".pdf");
|
||||
pdfInputFile.deleteOnExit();
|
||||
OutputStream pdfInput = new FileOutputStream(pdfInputFile);
|
||||
pdfInput.write(pdfGraphics.getBytes());
|
||||
pdfInput.close();
|
||||
|
||||
File pngOutputFile = File.createTempFile(getClass().getName() + ".testPDF", "png");
|
||||
pngOutputFile.deleteOnExit();
|
||||
Ghostscript gs = Ghostscript.getInstance();
|
||||
gs.initialize(new String[]{
|
||||
"-dBATCH",
|
||||
"-dQUIET",
|
||||
"-dNOPAUSE",
|
||||
"-dSAFER",
|
||||
String.format("-g%dx%d", Math.round(getPageSize().width), Math.round(getPageSize().height)),
|
||||
"-dGraphicsAlphaBits=4",
|
||||
// TODO: More robust settings for gs? DPI value is estimated.
|
||||
"-r25",
|
||||
"-dAlignToPixels=0",
|
||||
"-dPDFFitPage",
|
||||
"-sDEVICE=pngalpha",
|
||||
"-sOutputFile=" + pngOutputFile.toString(),
|
||||
pdfInputFile.toString()
|
||||
});
|
||||
gs.exit();
|
||||
rasterizedPDF = ImageIO.read(pngOutputFile);
|
||||
return rasterizedPDF;
|
||||
}*/
|
||||
|
||||
/*public BufferedImage getRasterizedSVG() throws TranscoderException {
|
||||
if (rasterizedSVG != null) {
|
||||
return rasterizedSVG;
|
||||
}
|
||||
|
||||
rasterizedSVG = new BufferedImage(
|
||||
(int) Math.round(getPageSize().width), (int) Math.round(getPageSize().height),
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
ImageTranscoder transcoder = new ImageTranscoder() {
|
||||
@Override
|
||||
public BufferedImage createImage(int width, int height) {
|
||||
return rasterizedSVG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeImage(BufferedImage bufferedImage, TranscoderOutput transcoderOutput) throws TranscoderException {
|
||||
}
|
||||
};
|
||||
|
||||
transcoder.transcode(new TranscoderInput(getSVG()), null);
|
||||
|
||||
return rasterizedSVG;
|
||||
}*/
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.visual;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class CharacterTest extends AbstractTest {
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g) {
|
||||
double w = getPageSize().width;
|
||||
double h = getPageSize().height;
|
||||
Charset latin1 = StandardCharsets.ISO_8859_1;
|
||||
CharsetEncoder latin1Encoder = latin1.newEncoder();
|
||||
List<String> charactersInCharset = new ArrayList<>();
|
||||
for (char char_ = Character.MIN_VALUE; char_ < Character.MAX_VALUE; char_++) {
|
||||
String javaString = String.valueOf(char_);
|
||||
if (latin1Encoder.canEncode(char_)) {
|
||||
charactersInCharset.add(javaString);
|
||||
}
|
||||
}
|
||||
final int colCount = (int) Math.ceil(Math.sqrt(charactersInCharset.size()));
|
||||
final int rowCount = colCount;
|
||||
double tileWidth = w / colCount;
|
||||
double tileHeight = h / rowCount;
|
||||
int charIndex = 0;
|
||||
for (double y = 0.0; y < h; y += tileHeight) {
|
||||
for (double x = 0.0; x < w; x += tileWidth) {
|
||||
String c = charactersInCharset.get(charIndex);
|
||||
double tileCenterX = x + tileWidth / 2.0;
|
||||
double tileCenterY = y + tileHeight / 2.0;
|
||||
g.drawString(c, (float) tileCenterX, (float) tileCenterY);
|
||||
charIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.visual;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
|
||||
public class ClippingTest extends AbstractTest {
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g) {
|
||||
double w = getPageSize().width;
|
||||
double h = getPageSize().height;
|
||||
|
||||
AffineTransform txOrig = g.getTransform();
|
||||
g.translate(w / 2.0, h / 2.0);
|
||||
|
||||
g.setClip(new Ellipse2D.Double(-0.6 * w / 2.0, -h / 2.0, 0.6 * w, h));
|
||||
for (double x = -w / 2.0; x < w / 2.0; x += 4.0) {
|
||||
g.draw(new Line2D.Double(x, -h / 2.0, x, h / 2.0));
|
||||
}
|
||||
|
||||
g.rotate(Math.toRadians(-90.0));
|
||||
g.clip(new Ellipse2D.Double(-0.6 * w / 2.0, -h / 2.0, 0.6 * w, h));
|
||||
for (double x = -h / 2.0; x < h / 2.0; x += 4.0) {
|
||||
g.draw(new Line2D.Double(x, -w / 2.0, x, w / 2.0));
|
||||
}
|
||||
|
||||
g.setTransform(txOrig);
|
||||
g.setClip(null);
|
||||
g.draw(new Line2D.Double(0.0, 0.0, w, h));
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.visual;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
public class ColorTest extends AbstractTest {
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g) {
|
||||
final float wPage = (float) getPageSize().width;
|
||||
final float hPage = (float) getPageSize().height;
|
||||
final float wTile = Math.min(wPage / 15f, hPage / 15f);
|
||||
final float hTile = wTile;
|
||||
float w = wPage - wTile;
|
||||
float h = hPage - hTile;
|
||||
for (float y = (hPage - h) / 2f; y < h; y += hTile) {
|
||||
float yRel = y / h;
|
||||
for (float x = (wPage - w) / 2f; x < w; x += wTile) {
|
||||
float xRel = x / w;
|
||||
Color c = Color.getHSBColor(yRel, 1f, 1f);
|
||||
int alpha = 255 - (int) (xRel * 255f);
|
||||
g.setColor(new Color(c.getRed(), c.getGreen(), c.getBlue(), alpha));
|
||||
g.fill(new Rectangle2D.Float(x, y, wTile, hTile));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.visual;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
public class EmptyFileTest extends AbstractTest {
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g) {
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.visual;
|
||||
|
||||
import org.xbib.graphics.chart.io.vector.GraphicsState;
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
public class FontTest extends AbstractTest {
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g) {
|
||||
final int tileCountH = 4;
|
||||
final int tileCountV = 8;
|
||||
final double wTile = getPageSize().width / tileCountH;
|
||||
final double hTile = getPageSize().height / tileCountV;
|
||||
final double xOrigin = (getPageSize().width - tileCountH * wTile) / 2.0;
|
||||
final double yOrigin = (getPageSize().height - tileCountV * hTile) / 2.0;
|
||||
double x = xOrigin;
|
||||
double y = yOrigin;
|
||||
|
||||
final float[] sizes = {
|
||||
GraphicsState.DEFAULT_FONT.getSize2D(), GraphicsState.DEFAULT_FONT.getSize2D() / 2f
|
||||
};
|
||||
final String[] names = {
|
||||
GraphicsState.DEFAULT_FONT.getName(), Font.SERIF, Font.MONOSPACED, "Monospaced"
|
||||
};
|
||||
final int[] styles = {
|
||||
Font.PLAIN, Font.ITALIC, Font.BOLD, Font.BOLD | Font.ITALIC
|
||||
};
|
||||
|
||||
for (float size : sizes) {
|
||||
for (String name : names) {
|
||||
for (int style : styles) {
|
||||
Font font = new Font(name, style, 10).deriveFont(size);
|
||||
g.setFont(font);
|
||||
g.drawString("vg2d", (float) x, (float) y);
|
||||
|
||||
x += wTile;
|
||||
if (x >= tileCountH * wTile) {
|
||||
x = xOrigin;
|
||||
y += hTile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.visual;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.GradientPaint;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
public class ImageTest extends AbstractTest {
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g) {
|
||||
// Draw an image
|
||||
BufferedImage image = new BufferedImage(4, 3, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D gImage = (Graphics2D) image.getGraphics();
|
||||
gImage.setPaint(new GradientPaint(
|
||||
new Point2D.Double(0.0, 0.0), Color.RED,
|
||||
new Point2D.Double(3.0, 2.0), Color.BLUE)
|
||||
);
|
||||
gImage.fill(new Rectangle2D.Double(0.0, 0.0, 4.0, 3.0));
|
||||
|
||||
g.drawImage(image, 0, 0, (int) getPageSize().width, (int) (0.5 * getPageSize().height), null);
|
||||
|
||||
g.rotate(-10.0 / 180.0 * Math.PI, 2.0, 1.5);
|
||||
g.drawImage(image, (int) (0.1 * getPageSize().width), (int) (0.6 * getPageSize().height),
|
||||
(int) (0.33 * getPageSize().width), (int) (0.33 * getPageSize().height), null);
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.visual;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.GradientPaint;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
public class PaintTest extends AbstractTest {
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g) {
|
||||
// Draw multiple rotated rectangles
|
||||
final int steps = 25;
|
||||
final int cols = 5;
|
||||
final int rows = steps / cols;
|
||||
final double tileWidth = getPageSize().width / cols;
|
||||
final double tileHeight = getPageSize().height / rows;
|
||||
g.translate(tileWidth / 2, tileHeight / 2);
|
||||
|
||||
final double rectWidth = tileWidth * 0.8;
|
||||
final double rectHeight = tileHeight * 0.8;
|
||||
Rectangle2D rect = new Rectangle2D.Double(-rectWidth / 2, -rectHeight / 2, rectWidth, rectHeight);
|
||||
g.setPaint(new GradientPaint(0f, (float) (-rectHeight / 2), Color.RED, 0f, (float) (rectHeight / 2), Color.BLUE));
|
||||
for (int i = 0; i < steps; i++) {
|
||||
AffineTransform txOld = g.getTransform();
|
||||
AffineTransform tx = new AffineTransform(txOld);
|
||||
int col = i % 5;
|
||||
int row = i / 5;
|
||||
tx.translate(col * tileWidth, row * tileHeight);
|
||||
tx.rotate(i * Math.toRadians(360.0 / steps));
|
||||
g.setTransform(tx);
|
||||
g.fill(rect);
|
||||
g.setTransform(txOld);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.visual;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Polygon;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Arc2D;
|
||||
import java.awt.geom.CubicCurve2D;
|
||||
import java.awt.geom.Ellipse2D;
|
||||
import java.awt.geom.Line2D;
|
||||
import java.awt.geom.Path2D;
|
||||
import java.awt.geom.QuadCurve2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
|
||||
public class ShapesTest extends AbstractTest {
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g) {
|
||||
final int tileCountH = 4;
|
||||
final int tileCountV = 6;
|
||||
final double wTile = getPageSize().width / tileCountH;
|
||||
final double hTile = getPageSize().height / tileCountV;
|
||||
final double xOrigin = (getPageSize().width - tileCountH * wTile) / 2.0;
|
||||
final double yOrigin = (getPageSize().height - tileCountV * hTile) / 2.0;
|
||||
double x = xOrigin;
|
||||
double y = yOrigin;
|
||||
|
||||
g.draw(new Line2D.Double(x, y, x + 0.8 * wTile, y + 0.6 * hTile));
|
||||
x += wTile;
|
||||
g.draw(new QuadCurve2D.Double(x, y, x + 0.8 * wTile, y, x + 0.8 * wTile, y + 0.6 * hTile));
|
||||
x += wTile;
|
||||
g.draw(new CubicCurve2D.Double(x, y, x + 0.8 * wTile, y, x, y + 0.6 * hTile, x + 0.8 * wTile, y + 0.6 * hTile));
|
||||
|
||||
x = xOrigin;
|
||||
y += hTile;
|
||||
g.fill(new Rectangle2D.Double(x, y, 0.8 * wTile, 0.6 * hTile));
|
||||
x += wTile;
|
||||
g.draw(new Rectangle2D.Double(x, y, 0.8 * wTile, 0.6 * hTile));
|
||||
x += wTile;
|
||||
|
||||
g.fill(new RoundRectangle2D.Double(x, y, 0.8 * wTile, 0.6 * hTile, 0.2 * wTile, 0.2 * hTile));
|
||||
x += wTile;
|
||||
g.draw(new RoundRectangle2D.Double(x, y, 0.8 * wTile, 0.6 * hTile, 0.2 * wTile, 0.2 * hTile));
|
||||
x += wTile;
|
||||
|
||||
|
||||
x = xOrigin;
|
||||
y += hTile;
|
||||
g.fill(new Ellipse2D.Double(x, y, 0.8 * wTile, 0.6 * hTile));
|
||||
x += wTile;
|
||||
g.draw(new Ellipse2D.Double(x, y, 0.8 * wTile, 0.6 * hTile));
|
||||
x += wTile;
|
||||
|
||||
g.fill(new Polygon(
|
||||
new int[]{(int) (x), (int) (x + 0.8 * wTile / 2.0), (int) (x + 0.8 * wTile)},
|
||||
new int[]{(int) (y + 0.6 * hTile), (int) (y), (int) (y + 0.6 * hTile)},
|
||||
3
|
||||
));
|
||||
x += wTile;
|
||||
g.draw(new Polygon(
|
||||
new int[]{(int) (x), (int) (x + 0.8 * wTile / 2.0), (int) (x + 0.8 * wTile)},
|
||||
new int[]{(int) (y + 0.6 * hTile), (int) (y), (int) (y + 0.6 * hTile)},
|
||||
3
|
||||
));
|
||||
|
||||
|
||||
x = xOrigin;
|
||||
y += hTile;
|
||||
g.fill(new Arc2D.Double(x, y, 0.8 * wTile, 0.6 * hTile, 110, 320, Arc2D.PIE));
|
||||
x += wTile;
|
||||
g.draw(new Arc2D.Double(x, y, 0.8 * wTile, 0.6 * hTile, 110, 320, Arc2D.PIE));
|
||||
x += wTile;
|
||||
g.fill(new Arc2D.Double(x, y, 0.6 * hTile, 0.8 * wTile, 10, 320, Arc2D.CHORD));
|
||||
x += wTile;
|
||||
g.draw(new Arc2D.Double(x, y, 0.6 * hTile, 0.8 * wTile, 10, 320, Arc2D.CHORD));
|
||||
|
||||
|
||||
x = xOrigin;
|
||||
y += hTile;
|
||||
g.fill(new Arc2D.Double(x, y, 0.6 * hTile, 0.8 * wTile, 10, 320, Arc2D.OPEN));
|
||||
x += wTile;
|
||||
g.draw(new Arc2D.Double(x, y, 0.6 * hTile, 0.8 * wTile, 10, 320, Arc2D.OPEN));
|
||||
x += wTile;
|
||||
g.fill(new Arc2D.Double(x, y, 0.6 * hTile, 0.8 * wTile, 10, 320, Arc2D.PIE));
|
||||
x += wTile;
|
||||
g.draw(new Arc2D.Double(x, y, 0.6 * hTile, 0.8 * wTile, 10, 320, Arc2D.PIE));
|
||||
|
||||
|
||||
x = xOrigin;
|
||||
y += hTile;
|
||||
|
||||
final Path2D path1 = new Path2D.Double();
|
||||
path1.moveTo(0.00, 0.00);
|
||||
path1.lineTo(0.33, 1.00);
|
||||
path1.lineTo(0.67, 0.00);
|
||||
path1.quadTo(0.33, 0.00, 0.33, 0.50);
|
||||
path1.quadTo(0.33, 1.00, 0.67, 1.00);
|
||||
path1.quadTo(1.00, 1.00, 1.00, 0.50);
|
||||
path1.lineTo(0.67, 0.50);
|
||||
path1.transform(AffineTransform.getScaleInstance(0.8 * wTile, 0.6 * hTile));
|
||||
|
||||
path1.transform(AffineTransform.getTranslateInstance(x, y));
|
||||
g.fill(path1);
|
||||
x += wTile;
|
||||
path1.transform(AffineTransform.getTranslateInstance(wTile, 0.0));
|
||||
g.draw(path1);
|
||||
x += wTile;
|
||||
|
||||
final Path2D path2 = new Path2D.Double();
|
||||
path2.moveTo(0.0, 0.4);
|
||||
path2.curveTo(0.0, 0.3, 0.0, 0.0, 0.2, 0.0);
|
||||
path2.curveTo(0.3, 0.0, 0.4, 0.1, 0.4, 0.3);
|
||||
path2.curveTo(0.4, 0.5, 0.2, 0.8, 0.0, 1.0);
|
||||
path2.lineTo(0.6, 1.0);
|
||||
path2.lineTo(0.6, 0.0);
|
||||
path2.curveTo(0.8, 0.0, 1.0, 0.2, 1.0, 0.5);
|
||||
path2.curveTo(1.0, 0.6, 1.0, 0.8, 0.9, 0.9);
|
||||
path2.closePath();
|
||||
path2.transform(AffineTransform.getScaleInstance(0.8 * wTile, 0.6 * hTile));
|
||||
|
||||
path2.transform(AffineTransform.getTranslateInstance(x, y));
|
||||
g.fill(path2);
|
||||
x += wTile;
|
||||
path2.transform(AffineTransform.getTranslateInstance(wTile, 0.0));
|
||||
g.draw(path2);
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.visual;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Stroke;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Path2D;
|
||||
|
||||
public class StrokeTest extends AbstractTest {
|
||||
|
||||
private static final Stroke[] strokes = {
|
||||
// Width
|
||||
new BasicStroke(0.0f),
|
||||
new BasicStroke(0.5f),
|
||||
new BasicStroke(1.0f),
|
||||
new BasicStroke(2.0f),
|
||||
// Cap
|
||||
new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER),
|
||||
new BasicStroke(1f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER),
|
||||
new BasicStroke(1f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER),
|
||||
null,
|
||||
// Join
|
||||
new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL),
|
||||
new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER),
|
||||
new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND),
|
||||
null,
|
||||
// Miter limit
|
||||
new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1f),
|
||||
new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 2f),
|
||||
new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 3f),
|
||||
new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f),
|
||||
// Dash pattern
|
||||
new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[]{1f}, 0f),
|
||||
new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[]{1f, 1f}, 0f),
|
||||
new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[]{3f, 1f, 1f}, 0f),
|
||||
new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[]{3f, 1f, 4f, 1f}, 0f),
|
||||
// Dash phase
|
||||
new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[]{3f, 1f}, 0.5f),
|
||||
new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[]{3f, 1f}, 1.0f),
|
||||
new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[]{3f, 1f}, 1.5f),
|
||||
new BasicStroke(1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10f, new float[]{3f, 1f}, 2.5f),
|
||||
};
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g) {
|
||||
final int tileCountH = 4;
|
||||
final int tileCountV = 6;
|
||||
final double wTile = getPageSize().width / tileCountH;
|
||||
final double hTile = getPageSize().height / tileCountV;
|
||||
final double xOrigin = (getPageSize().width - tileCountH * wTile) / 2.0;
|
||||
final double yOrigin = (getPageSize().height - tileCountV * hTile) / 2.0;
|
||||
|
||||
final Path2D path = new Path2D.Double();
|
||||
path.moveTo(0.00, 0.00);
|
||||
path.lineTo(0.33, 1.00);
|
||||
path.lineTo(0.67, 0.00);
|
||||
path.quadTo(0.33, 0.00, 0.33, 0.50);
|
||||
path.quadTo(0.33, 1.00, 0.67, 1.00);
|
||||
path.quadTo(1.00, 1.00, 1.00, 0.50);
|
||||
path.lineTo(0.67, 0.50);
|
||||
path.moveTo(1.0, 0.4);
|
||||
path.curveTo(1.0, 0.3, 1.0, 0.0, 1.2, 0.0);
|
||||
path.curveTo(1.3, 0.0, 1.4, 0.1, 1.4, 0.3);
|
||||
path.curveTo(1.4, 0.5, 1.2, 0.8, 1.0, 1.0);
|
||||
path.lineTo(1.6, 1.0);
|
||||
path.lineTo(1.6, 0.0);
|
||||
path.curveTo(1.8, 0.0, 2.0, 0.2, 2.0, 0.5);
|
||||
path.curveTo(2.0, 0.6, 2.0, 0.8, 1.9, 0.9);
|
||||
|
||||
path.transform(AffineTransform.getScaleInstance(0.8 * wTile / 2.0, 0.6 * hTile));
|
||||
|
||||
double x = xOrigin;
|
||||
double y = yOrigin;
|
||||
for (Stroke stroke : strokes) {
|
||||
if (stroke != null) {
|
||||
Path2D p = new Path2D.Double(path);
|
||||
p.transform(AffineTransform.getTranslateInstance(x, y));
|
||||
|
||||
g.setStroke(stroke);
|
||||
g.draw(p);
|
||||
}
|
||||
|
||||
x += wTile;
|
||||
if (x >= tileCountH * wTile) {
|
||||
x = xOrigin;
|
||||
y += hTile;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.visual;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JSlider;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
public class SwingExportTest extends AbstractTest {
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g) {
|
||||
JFrame frame = new JFrame();
|
||||
frame.getContentPane().add(new JButton("Hello Swing!"), BorderLayout.CENTER);
|
||||
frame.getContentPane().add(new JSlider(), BorderLayout.NORTH);
|
||||
frame.setSize(200, 250);
|
||||
|
||||
//g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
frame.setVisible(true);
|
||||
frame.printAll(g);
|
||||
frame.setVisible(false);
|
||||
frame.dispose();
|
||||
}
|
||||
}
|
|
@ -1,263 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.visual;
|
||||
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.DefaultListCellRenderer;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.WindowConstants;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Component;
|
||||
import java.awt.event.ItemEvent;
|
||||
import java.awt.event.ItemListener;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class TestBrowser extends JFrame {
|
||||
|
||||
private final List<AbstractTest> testCases;
|
||||
|
||||
private final ImageComparisonPanel imageComparisonPanel;
|
||||
|
||||
private AbstractTest testCase;
|
||||
|
||||
public TestBrowser() {
|
||||
super("Test browser");
|
||||
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
|
||||
setSize(1024, 768);
|
||||
testCases = new ArrayList<>();
|
||||
testCases.add(new ColorTest());
|
||||
testCases.add(new StrokeTest());
|
||||
testCases.add(new ShapesTest());
|
||||
testCases.add(new FontTest());
|
||||
testCases.add(new CharacterTest());
|
||||
testCases.add(new EmptyFileTest());
|
||||
testCases.add(new ImageTest());
|
||||
testCases.add(new ClippingTest());
|
||||
testCases.add(new PaintTest());
|
||||
testCases.add(new SwingExportTest());
|
||||
testCases.add(new TransformTest());
|
||||
final JList<?> testList = new JList<>(testCases.toArray());
|
||||
testList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
testList.setCellRenderer(new DefaultListCellRenderer() {
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
String testName = value.getClass().getSimpleName();
|
||||
return super.getListCellRendererComponent(list, testName, index, isSelected, cellHasFocus);
|
||||
}
|
||||
});
|
||||
testList.addListSelectionListener(e -> {
|
||||
if (!e.getValueIsAdjusting()) {
|
||||
int index = testList.getSelectedIndex();
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
AbstractTest test = testCases.get(index);
|
||||
testCase = test;
|
||||
try {
|
||||
setTestCase(test);
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
getContentPane().add(testList, BorderLayout.WEST);
|
||||
|
||||
JPanel configurableImageComparisonPanel = new JPanel(new BorderLayout());
|
||||
getContentPane().add(configurableImageComparisonPanel, BorderLayout.CENTER);
|
||||
|
||||
ImageFormat startingImageFormat = ImageFormat.EPS;
|
||||
JComboBox<?> imageFormatSelector = new JComboBox<>(ImageFormat.values());
|
||||
configurableImageComparisonPanel.add(imageFormatSelector, BorderLayout.NORTH);
|
||||
imageFormatSelector.setSelectedItem(startingImageFormat);
|
||||
imageFormatSelector.addItemListener(new ItemListener() {
|
||||
@Override
|
||||
public void itemStateChanged(ItemEvent itemEvent) {
|
||||
ImageFormat format = (ImageFormat) itemEvent.getItem();
|
||||
imageComparisonPanel.setImageFormat(format);
|
||||
|
||||
AbstractTest test = getTestCase();
|
||||
if (test != null) {
|
||||
try {
|
||||
setTestCase(test);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
imageComparisonPanel = new ImageComparisonPanel(startingImageFormat);
|
||||
configurableImageComparisonPanel.add(imageComparisonPanel, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
new TestBrowser().setVisible(true);
|
||||
}
|
||||
|
||||
public AbstractTest getTestCase() {
|
||||
return testCase;
|
||||
}
|
||||
|
||||
public void setTestCase(AbstractTest test) throws IOException {
|
||||
BufferedImage reference = test.getReference();
|
||||
imageComparisonPanel.setLeftComponent(new ImageDisplayPanel(reference, null));
|
||||
//ImageDisplayPanel imageDisplayPanel;
|
||||
switch (imageComparisonPanel.getImageFormat()) {
|
||||
case EPS:
|
||||
//imageDisplayPanel = new ImageDisplayPanel(test.getRasterizedEPS(), test.getEPS());
|
||||
//imageComparisonPanel.setRightComponent(imageDisplayPanel);
|
||||
break;
|
||||
case PDF:
|
||||
//imageDisplayPanel = new ImageDisplayPanel(test.getRasterizedPDF(), test.getPDF());
|
||||
//imageComparisonPanel.setRightComponent(imageDisplayPanel);
|
||||
break;
|
||||
case SVG:
|
||||
//imageDisplayPanel = new ImageDisplayPanel(test.getRasterizedSVG(), test.getSVG());
|
||||
//imageComparisonPanel.setRightComponent(imageDisplayPanel);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown image format: " + imageComparisonPanel.getImageFormat());
|
||||
}
|
||||
}
|
||||
|
||||
private enum ImageFormat {
|
||||
EPS("EPS"),
|
||||
PDF("PDF"),
|
||||
SVG("SVG");
|
||||
|
||||
private final String name;
|
||||
|
||||
ImageFormat(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ImageComparisonPanel extends Box {
|
||||
|
||||
private final Box leftPanel;
|
||||
|
||||
private final Box rightPanel;
|
||||
|
||||
private ImageFormat imageFormat;
|
||||
|
||||
private JComponent leftComponent;
|
||||
|
||||
private JComponent rightComponent;
|
||||
|
||||
public ImageComparisonPanel(ImageFormat imageFormat) {
|
||||
super(BoxLayout.PAGE_AXIS);
|
||||
|
||||
this.imageFormat = imageFormat;
|
||||
|
||||
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
|
||||
splitPane.setResizeWeight(0.5);
|
||||
add(splitPane);
|
||||
|
||||
leftPanel = new Box(BoxLayout.PAGE_AXIS);
|
||||
leftPanel.add(new JLabel("Graphics2D"));
|
||||
splitPane.setTopComponent(leftPanel);
|
||||
|
||||
rightPanel = new Box(BoxLayout.PAGE_AXIS);
|
||||
rightPanel.add(new JLabel(imageFormat.getName()));
|
||||
splitPane.setBottomComponent(rightPanel);
|
||||
}
|
||||
|
||||
public void setLeftComponent(JComponent leftComponent) {
|
||||
if (this.leftComponent != null) {
|
||||
leftPanel.remove(this.leftComponent);
|
||||
}
|
||||
this.leftComponent = leftComponent;
|
||||
leftPanel.add(leftComponent);
|
||||
leftPanel.revalidate();
|
||||
leftPanel.repaint();
|
||||
}
|
||||
|
||||
public void setRightComponent(JComponent rightComponent) {
|
||||
if (this.rightComponent != null) {
|
||||
rightPanel.remove(this.rightComponent);
|
||||
}
|
||||
this.rightComponent = rightComponent;
|
||||
rightPanel.add(rightComponent);
|
||||
rightPanel.revalidate();
|
||||
rightPanel.repaint();
|
||||
}
|
||||
|
||||
public ImageFormat getImageFormat() {
|
||||
return imageFormat;
|
||||
}
|
||||
|
||||
public void setImageFormat(ImageFormat imageFormat) {
|
||||
this.imageFormat = imageFormat;
|
||||
JLabel imageFormatLabel = (JLabel) rightPanel.getComponent(0);
|
||||
imageFormatLabel.setText(imageFormat.getName());
|
||||
imageFormatLabel.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
private static class ImageDisplayPanel extends JPanel {
|
||||
private final InputStream imageData;
|
||||
|
||||
public ImageDisplayPanel(BufferedImage renderedImage, InputStream imageData) {
|
||||
super(new BorderLayout());
|
||||
this.imageData = imageData;
|
||||
|
||||
JLabel imageLabel = new JLabel(new ImageIcon(renderedImage));
|
||||
add(imageLabel, BorderLayout.CENTER);
|
||||
|
||||
JButton saveToFileButton = new JButton("Save as...");
|
||||
if (imageData == null) {
|
||||
saveToFileButton.setEnabled(false);
|
||||
}
|
||||
saveToFileButton.addActionListener(e -> {
|
||||
JFileChooser saveFileDialog = new JFileChooser();
|
||||
saveFileDialog.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
saveFileDialog.setMultiSelectionEnabled(false);
|
||||
int userChoice = saveFileDialog.showSaveDialog(ImageDisplayPanel.this);
|
||||
if (userChoice != JFileChooser.APPROVE_OPTION) {
|
||||
return;
|
||||
}
|
||||
|
||||
File dest = saveFileDialog.getSelectedFile();
|
||||
FileOutputStream destStream = null;
|
||||
try {
|
||||
destStream = new FileOutputStream(dest);
|
||||
int imageDataChunk;
|
||||
while ((imageDataChunk = ImageDisplayPanel.this.imageData.read()) != -1) {
|
||||
destStream.write(imageDataChunk);
|
||||
}
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
} finally {
|
||||
if (destStream != null) {
|
||||
try {
|
||||
destStream.close();
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
add(saveToFileButton, BorderLayout.SOUTH);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
package org.xbib.graphics.chart.io.vector.visual;
|
||||
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Shape;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
public class TransformTest extends AbstractTest {
|
||||
|
||||
@Override
|
||||
public void draw(Graphics2D g) {
|
||||
final int rowCount = 2;
|
||||
final int colCount = 4;
|
||||
double wTile = getPageSize().width / colCount;
|
||||
double hTile = wTile;
|
||||
|
||||
g.translate(0.5 * wTile, 0.5 * hTile);
|
||||
AffineTransform txOrig = g.getTransform();
|
||||
|
||||
Shape s = new Rectangle2D.Double(0.0, 0.0, 0.5 * wTile, 0.75 * hTile);
|
||||
|
||||
// Row 1
|
||||
|
||||
g.draw(s);
|
||||
|
||||
g.translate(wTile, 0.0);
|
||||
g.draw(s);
|
||||
|
||||
g.translate(wTile, 0.0);
|
||||
{
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
g2.scale(0.5, 0.5);
|
||||
g2.draw(s);
|
||||
g2.dispose();
|
||||
}
|
||||
|
||||
g.translate(wTile, 0.0);
|
||||
{
|
||||
Graphics2D g2 = (Graphics2D) g.create();
|
||||
g2.rotate(Math.toRadians(30.0));
|
||||
g2.draw(s);
|
||||
g2.dispose();
|
||||
}
|
||||
|
||||
// Row 2
|
||||
|
||||
g.setTransform(txOrig);
|
||||
g.translate(0.0, hTile);
|
||||
|
||||
g.shear(0.5, 0.0);
|
||||
g.draw(s);
|
||||
g.shear(-0.5, 0.0);
|
||||
g.translate(wTile, 0.0);
|
||||
|
||||
g.shear(0.0, 0.5);
|
||||
g.draw(s);
|
||||
g.shear(0.0, -0.5);
|
||||
}
|
||||
}
|
|
@ -1,372 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!-- NewPage -->
|
||||
<html lang="de">
|
||||
<head>
|
||||
<!-- Generated by javadoc -->
|
||||
<title>All Classes (io-vector 3.0.0 API)</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="description" content="class index">
|
||||
<meta name="generator" content="javadoc/AllClassesIndexWriter">
|
||||
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
|
||||
<link rel="stylesheet" type="text/css" href="script-dir/jquery-ui.min.css" title="Style">
|
||||
<link rel="stylesheet" type="text/css" href="jquery-ui.overrides.css" title="Style">
|
||||
<script type="text/javascript" src="script.js"></script>
|
||||
<script type="text/javascript" src="script-dir/jquery-3.5.1.min.js"></script>
|
||||
<script type="text/javascript" src="script-dir/jquery-ui.min.js"></script>
|
||||
</head>
|
||||
<body class="all-classes-index-page">
|
||||
<script type="text/javascript">var data = {"i0":2,"i1":2,"i2":2,"i3":2,"i4":2,"i5":2,"i6":2,"i7":2,"i8":2,"i9":2,"i10":2,"i11":2,"i12":2,"i13":2,"i14":2,"i15":2,"i16":2,"i17":2,"i18":2,"i19":2,"i20":2,"i21":2,"i22":2,"i23":2,"i24":2,"i25":2,"i26":4,"i27":2,"i28":2,"i29":2,"i30":2,"i31":2,"i32":2,"i33":2,"i34":2,"i35":1,"i36":1,"i37":2,"i38":2,"i39":2,"i40":2,"i41":2,"i42":2,"i43":2,"i44":2,"i45":2,"i46":2,"i47":2,"i48":2,"i49":2,"i50":2,"i51":2,"i52":2,"i53":2,"i54":2,"i55":2,"i56":2,"i57":2,"i58":2,"i59":2,"i60":4,"i61":2,"i62":2,"i63":2};
|
||||
var tabs = {65535:["t0","All Classes"],1:["t1","Interface Summary"],2:["t2","Class Summary"],4:["t3","Enum Summary"]};
|
||||
var altColor = "alt-color";
|
||||
var rowColor = "row-color";
|
||||
var tableTab = "table-tab";
|
||||
var activeTableTab = "active-table-tab";
|
||||
var pathtoroot = "./";
|
||||
loadScripts(document, 'script');</script>
|
||||
<noscript>
|
||||
<div>JavaScript is disabled on your browser.</div>
|
||||
</noscript>
|
||||
<div class="flex-box">
|
||||
<header role="banner" class="flex-header">
|
||||
<nav role="navigation">
|
||||
<!-- ========= START OF TOP NAVBAR ======= -->
|
||||
<div class="top-nav" id="navbar.top">
|
||||
<div class="skip-nav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
|
||||
<ul id="navbar.top.firstrow" class="nav-list" title="Navigation">
|
||||
<li><a href="org.xbib.graphics.io.vector/module-summary.html">Module</a></li>
|
||||
<li>Package</li>
|
||||
<li>Class</li>
|
||||
<li><a href="overview-tree.html">Tree</a></li>
|
||||
<li><a href="deprecated-list.html">Deprecated</a></li>
|
||||
<li><a href="index-all.html">Index</a></li>
|
||||
<li><a href="help-doc.html">Help</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sub-nav">
|
||||
<div class="nav-list-search"><label for="search">SEARCH:</label>
|
||||
<input type="text" id="search" value="search" disabled="disabled">
|
||||
<input type="reset" id="reset" value="reset" disabled="disabled">
|
||||
</div>
|
||||
</div>
|
||||
<!-- ========= END OF TOP NAVBAR ========= -->
|
||||
<span class="skip-nav" id="skip.navbar.top">
|
||||
<!-- -->
|
||||
</span></nav>
|
||||
</header>
|
||||
<div class="flex-content">
|
||||
<main role="main">
|
||||
<div class="header">
|
||||
<h1 title="All&nbsp;Classes" class="title">All Classes</h1>
|
||||
</div>
|
||||
<div class="type-summary" id="all-classes-table">
|
||||
<div class="table-tabs" role="tablist" aria-orientation="horizontal"><button role="tab" aria-selected="true" aria-controls="all-classes-table.tabpanel" tabindex="0" onkeydown="switchTab(event)" id="t0" class="active-table-tab">All Classes</button><button role="tab" aria-selected="false" aria-controls="all-classes-table.tabpanel" tabindex="-1" onkeydown="switchTab(event)" id="t1" class="table-tab" onclick="show(1);">Interface Summary</button><button role="tab" aria-selected="false" aria-controls="all-classes-table.tabpanel" tabindex="-1" onkeydown="switchTab(event)" id="t2" class="table-tab" onclick="show(2);">Class Summary</button><button role="tab" aria-selected="false" aria-controls="all-classes-table.tabpanel" tabindex="-1" onkeydown="switchTab(event)" id="t3" class="table-tab" onclick="show(4);">Enum Summary</button></div>
|
||||
<div id="all-classes-table.tabpanel" role="tabpanel">
|
||||
<table class="summary-table" aria-labelledby="t0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-first" scope="col">Class</th>
|
||||
<th class="col-last" scope="col">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="alt-color" id="i0">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/filters/AbsoluteToRelativeTransformsFilter.html" title="class in org.xbib.graphics.io.vector.filters">AbsoluteToRelativeTransformsFilter</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i1">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/AffineTransformCommand.html" title="class in org.xbib.graphics.io.vector.commands">AffineTransformCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i2">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/util/AlphaToMaskOp.html" title="class in org.xbib.graphics.io.vector.util">AlphaToMaskOp</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i3">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/util/ASCII85EncodeStream.html" title="class in org.xbib.graphics.io.vector.util">ASCII85EncodeStream</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i4">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/util/Base64EncodeStream.html" title="class in org.xbib.graphics.io.vector.util">Base64EncodeStream</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i5">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/Command.html" title="class in org.xbib.graphics.io.vector">Command</a><<a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/Command.html" title="type parameter in Command">T</a>></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i6">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/CreateCommand.html" title="class in org.xbib.graphics.io.vector.commands">CreateCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i7">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/util/DataUtils.html" title="class in org.xbib.graphics.io.vector.util">DataUtils</a></td>
|
||||
<th class="col-last" scope="row">
|
||||
<div class="block">Abstract class that contains utility functions for working with data
|
||||
collections like maps or lists.</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i8">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/DisposeCommand.html" title="class in org.xbib.graphics.io.vector.commands">DisposeCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i9">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/DrawImageCommand.html" title="class in org.xbib.graphics.io.vector.commands">DrawImageCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i10">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/DrawShapeCommand.html" title="class in org.xbib.graphics.io.vector.commands">DrawShapeCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i11">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/DrawStringCommand.html" title="class in org.xbib.graphics.io.vector.commands">DrawStringCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i12">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/eps/EPSGraphics2D.html" title="class in org.xbib.graphics.io.vector.eps">EPSGraphics2D</a></td>
|
||||
<th class="col-last" scope="row">
|
||||
<div class="block"><code>Graphics2D</code> implementation that saves all operations to a string
|
||||
in the <i>Encapsulated PostScript®</i> (EPS) format.</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i13">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/eps/EPSProcessor.html" title="class in org.xbib.graphics.io.vector.eps">EPSProcessor</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i14">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/eps/EPSProcessorResult.html" title="class in org.xbib.graphics.io.vector.eps">EPSProcessorResult</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i15">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/filters/FillPaintedShapeAsImageFilter.html" title="class in org.xbib.graphics.io.vector.filters">FillPaintedShapeAsImageFilter</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i16">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/FillShapeCommand.html" title="class in org.xbib.graphics.io.vector.commands">FillShapeCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i17">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/filters/Filter.html" title="class in org.xbib.graphics.io.vector.filters">Filter</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i18">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/util/FlateEncodeStream.html" title="class in org.xbib.graphics.io.vector.util">FlateEncodeStream</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i19">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/util/FormattingWriter.html" title="class in org.xbib.graphics.io.vector.util">FormattingWriter</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i20">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/pdf/GeneratedPayload.html" title="class in org.xbib.graphics.io.vector.pdf">GeneratedPayload</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i21">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/GraphicsState.html" title="class in org.xbib.graphics.io.vector">GraphicsState</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i22">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/util/GraphicsUtils.html" title="class in org.xbib.graphics.io.vector.util">GraphicsUtils</a></td>
|
||||
<th class="col-last" scope="row">
|
||||
<div class="block">Abstract class that contains utility functions for working with graphics.</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i23">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/Group.html" title="class in org.xbib.graphics.io.vector.commands">Group</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i24">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/filters/GroupingFilter.html" title="class in org.xbib.graphics.io.vector.filters">GroupingFilter</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i25">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/util/ImageDataStream.html" title="class in org.xbib.graphics.io.vector.util">ImageDataStream</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i26">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/util/ImageDataStream.Interleaving.html" title="enum in org.xbib.graphics.io.vector.util">ImageDataStream.Interleaving</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i27">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/util/LineWrapOutputStream.html" title="class in org.xbib.graphics.io.vector.util">LineWrapOutputStream</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i28">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/filters/OptimizeFilter.html" title="class in org.xbib.graphics.io.vector.filters">OptimizeFilter</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i29">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/PageSize.html" title="class in org.xbib.graphics.io.vector">PageSize</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i30">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/pdf/Payload.html" title="class in org.xbib.graphics.io.vector.pdf">Payload</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i31">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/pdf/PDFGraphics2D.html" title="class in org.xbib.graphics.io.vector.pdf">PDFGraphics2D</a></td>
|
||||
<th class="col-last" scope="row">
|
||||
<div class="block"><code>Graphics2D</code> implementation that saves all operations to a string
|
||||
in the <i>Portable Document Format</i> (PDF).</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i32">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/pdf/PDFObject.html" title="class in org.xbib.graphics.io.vector.pdf">PDFObject</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i33">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/pdf/PDFProcessor.html" title="class in org.xbib.graphics.io.vector.pdf">PDFProcessor</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i34">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/pdf/PDFProcessorResult.html" title="class in org.xbib.graphics.io.vector.pdf">PDFProcessorResult</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i35">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/Processor.html" title="interface in org.xbib.graphics.io.vector">Processor</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i36">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/ProcessorResult.html" title="interface in org.xbib.graphics.io.vector">ProcessorResult</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i37">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/pdf/Resources.html" title="class in org.xbib.graphics.io.vector.pdf">Resources</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i38">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/RotateCommand.html" title="class in org.xbib.graphics.io.vector.commands">RotateCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i39">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/ScaleCommand.html" title="class in org.xbib.graphics.io.vector.commands">ScaleCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i40">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/SetBackgroundCommand.html" title="class in org.xbib.graphics.io.vector.commands">SetBackgroundCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i41">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/SetClipCommand.html" title="class in org.xbib.graphics.io.vector.commands">SetClipCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i42">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/SetColorCommand.html" title="class in org.xbib.graphics.io.vector.commands">SetColorCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i43">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/SetCompositeCommand.html" title="class in org.xbib.graphics.io.vector.commands">SetCompositeCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i44">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/SetFontCommand.html" title="class in org.xbib.graphics.io.vector.commands">SetFontCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i45">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/SetHintCommand.html" title="class in org.xbib.graphics.io.vector.commands">SetHintCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i46">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/SetPaintCommand.html" title="class in org.xbib.graphics.io.vector.commands">SetPaintCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i47">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/SetStrokeCommand.html" title="class in org.xbib.graphics.io.vector.commands">SetStrokeCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i48">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/SetTransformCommand.html" title="class in org.xbib.graphics.io.vector.commands">SetTransformCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i49">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/SetXORModeCommand.html" title="class in org.xbib.graphics.io.vector.commands">SetXORModeCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i50">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/ShearCommand.html" title="class in org.xbib.graphics.io.vector.commands">ShearCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i51">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/pdf/SizePayload.html" title="class in org.xbib.graphics.io.vector.pdf">SizePayload</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i52">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/filters/StateChangeGroupingFilter.html" title="class in org.xbib.graphics.io.vector.filters">StateChangeGroupingFilter</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i53">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/StateCommand.html" title="class in org.xbib.graphics.io.vector.commands">StateCommand</a><<a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/StateCommand.html" title="type parameter in StateCommand">T</a>></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i54">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/svg/SVGGraphics2D.html" title="class in org.xbib.graphics.io.vector.svg">SVGGraphics2D</a></td>
|
||||
<th class="col-last" scope="row">
|
||||
<div class="block"><code>Graphics2D</code> implementation that saves all operations to a string
|
||||
in the <i>Scaled Vector Graphics</i> (SVG) format.</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i55">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/svg/SVGProcessor.html" title="class in org.xbib.graphics.io.vector.svg">SVGProcessor</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i56">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/svg/SVGProcessorResult.html" title="class in org.xbib.graphics.io.vector.svg">SVGProcessorResult</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i57">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/TransformCommand.html" title="class in org.xbib.graphics.io.vector.commands">TransformCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i58">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/TranslateCommand.html" title="class in org.xbib.graphics.io.vector.commands">TranslateCommand</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i59">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/VectorGraphics2D.html" title="class in org.xbib.graphics.io.vector">VectorGraphics2D</a></td>
|
||||
<th class="col-last" scope="row">
|
||||
<div class="block">Base for classes that want to implement vector export.</div>
|
||||
</th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i60">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/VectorGraphicsFormat.html" title="enum in org.xbib.graphics.io.vector">VectorGraphicsFormat</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i61">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/util/VectorHints.html" title="class in org.xbib.graphics.io.vector.util">VectorHints</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="alt-color" id="i62">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/util/VectorHints.Key.html" title="class in org.xbib.graphics.io.vector.util">VectorHints.Key</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
<tr class="row-color" id="i63">
|
||||
<td class="col-first"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/util/VectorHints.Value.html" title="class in org.xbib.graphics.io.vector.util">VectorHints.Value</a></td>
|
||||
<th class="col-last" scope="row"> </th>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<footer role="contentinfo">
|
||||
<nav role="navigation">
|
||||
<!-- ======= START OF BOTTOM NAVBAR ====== -->
|
||||
<div class="bottom-nav" id="navbar.bottom">
|
||||
<div class="skip-nav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
|
||||
<ul id="navbar.bottom.firstrow" class="nav-list" title="Navigation">
|
||||
<li><a href="org.xbib.graphics.io.vector/module-summary.html">Module</a></li>
|
||||
<li>Package</li>
|
||||
<li>Class</li>
|
||||
<li><a href="overview-tree.html">Tree</a></li>
|
||||
<li><a href="deprecated-list.html">Deprecated</a></li>
|
||||
<li><a href="index-all.html">Index</a></li>
|
||||
<li><a href="help-doc.html">Help</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- ======== END OF BOTTOM NAVBAR ======= -->
|
||||
<span class="skip-nav" id="skip.navbar.bottom">
|
||||
<!-- -->
|
||||
</span></nav>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,120 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!-- NewPage -->
|
||||
<html lang="de">
|
||||
<head>
|
||||
<!-- Generated by javadoc -->
|
||||
<title>All Packages (io-vector 3.0.0 API)</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="description" content="package index">
|
||||
<meta name="generator" content="javadoc/AllPackagesIndexWriter">
|
||||
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
|
||||
<link rel="stylesheet" type="text/css" href="script-dir/jquery-ui.min.css" title="Style">
|
||||
<link rel="stylesheet" type="text/css" href="jquery-ui.overrides.css" title="Style">
|
||||
<script type="text/javascript" src="script.js"></script>
|
||||
<script type="text/javascript" src="script-dir/jquery-3.5.1.min.js"></script>
|
||||
<script type="text/javascript" src="script-dir/jquery-ui.min.js"></script>
|
||||
</head>
|
||||
<body class="all-packages-index-page">
|
||||
<script type="text/javascript">var pathtoroot = "./";
|
||||
loadScripts(document, 'script');</script>
|
||||
<noscript>
|
||||
<div>JavaScript is disabled on your browser.</div>
|
||||
</noscript>
|
||||
<div class="flex-box">
|
||||
<header role="banner" class="flex-header">
|
||||
<nav role="navigation">
|
||||
<!-- ========= START OF TOP NAVBAR ======= -->
|
||||
<div class="top-nav" id="navbar.top">
|
||||
<div class="skip-nav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
|
||||
<ul id="navbar.top.firstrow" class="nav-list" title="Navigation">
|
||||
<li><a href="org.xbib.graphics.io.vector/module-summary.html">Module</a></li>
|
||||
<li>Package</li>
|
||||
<li>Class</li>
|
||||
<li><a href="overview-tree.html">Tree</a></li>
|
||||
<li><a href="deprecated-list.html">Deprecated</a></li>
|
||||
<li><a href="index-all.html">Index</a></li>
|
||||
<li><a href="help-doc.html">Help</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sub-nav">
|
||||
<div class="nav-list-search"><label for="search">SEARCH:</label>
|
||||
<input type="text" id="search" value="search" disabled="disabled">
|
||||
<input type="reset" id="reset" value="reset" disabled="disabled">
|
||||
</div>
|
||||
</div>
|
||||
<!-- ========= END OF TOP NAVBAR ========= -->
|
||||
<span class="skip-nav" id="skip.navbar.top">
|
||||
<!-- -->
|
||||
</span></nav>
|
||||
</header>
|
||||
<div class="flex-content">
|
||||
<main role="main">
|
||||
<div class="header">
|
||||
<h1 title="All&nbsp;Packages" class="title">All Packages</h1>
|
||||
</div>
|
||||
<div class="packages-summary">
|
||||
<table class="summary-table">
|
||||
<caption><span>Package Summary</span></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-first" scope="col">Package</th>
|
||||
<th class="col-last" scope="col">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="alt-color">
|
||||
<th class="col-first" scope="row"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/package-summary.html">org.xbib.graphics.io.vector</a></th>
|
||||
<td class="col-last"> </td>
|
||||
</tr>
|
||||
<tr class="row-color">
|
||||
<th class="col-first" scope="row"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/commands/package-summary.html">org.xbib.graphics.io.vector.commands</a></th>
|
||||
<td class="col-last"> </td>
|
||||
</tr>
|
||||
<tr class="alt-color">
|
||||
<th class="col-first" scope="row"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/eps/package-summary.html">org.xbib.graphics.io.vector.eps</a></th>
|
||||
<td class="col-last"> </td>
|
||||
</tr>
|
||||
<tr class="row-color">
|
||||
<th class="col-first" scope="row"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/filters/package-summary.html">org.xbib.graphics.io.vector.filters</a></th>
|
||||
<td class="col-last"> </td>
|
||||
</tr>
|
||||
<tr class="alt-color">
|
||||
<th class="col-first" scope="row"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/pdf/package-summary.html">org.xbib.graphics.io.vector.pdf</a></th>
|
||||
<td class="col-last"> </td>
|
||||
</tr>
|
||||
<tr class="row-color">
|
||||
<th class="col-first" scope="row"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/svg/package-summary.html">org.xbib.graphics.io.vector.svg</a></th>
|
||||
<td class="col-last"> </td>
|
||||
</tr>
|
||||
<tr class="alt-color">
|
||||
<th class="col-first" scope="row"><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/util/package-summary.html">org.xbib.graphics.io.vector.util</a></th>
|
||||
<td class="col-last"> </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
<footer role="contentinfo">
|
||||
<nav role="navigation">
|
||||
<!-- ======= START OF BOTTOM NAVBAR ====== -->
|
||||
<div class="bottom-nav" id="navbar.bottom">
|
||||
<div class="skip-nav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
|
||||
<ul id="navbar.bottom.firstrow" class="nav-list" title="Navigation">
|
||||
<li><a href="org.xbib.graphics.io.vector/module-summary.html">Module</a></li>
|
||||
<li>Package</li>
|
||||
<li>Class</li>
|
||||
<li><a href="overview-tree.html">Tree</a></li>
|
||||
<li><a href="deprecated-list.html">Deprecated</a></li>
|
||||
<li><a href="index-all.html">Index</a></li>
|
||||
<li><a href="help-doc.html">Help</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- ======== END OF BOTTOM NAVBAR ======= -->
|
||||
<span class="skip-nav" id="skip.navbar.bottom">
|
||||
<!-- -->
|
||||
</span></nav>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,111 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!-- NewPage -->
|
||||
<html lang="de">
|
||||
<head>
|
||||
<!-- Generated by javadoc -->
|
||||
<title>Constant Field Values (io-vector 3.0.0 API)</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="description" content="summary of constants">
|
||||
<meta name="generator" content="javadoc/ConstantsSummaryWriterImpl">
|
||||
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
|
||||
<link rel="stylesheet" type="text/css" href="script-dir/jquery-ui.min.css" title="Style">
|
||||
<link rel="stylesheet" type="text/css" href="jquery-ui.overrides.css" title="Style">
|
||||
<script type="text/javascript" src="script.js"></script>
|
||||
<script type="text/javascript" src="script-dir/jquery-3.5.1.min.js"></script>
|
||||
<script type="text/javascript" src="script-dir/jquery-ui.min.js"></script>
|
||||
</head>
|
||||
<body class="constants-summary-page">
|
||||
<script type="text/javascript">var pathtoroot = "./";
|
||||
loadScripts(document, 'script');</script>
|
||||
<noscript>
|
||||
<div>JavaScript is disabled on your browser.</div>
|
||||
</noscript>
|
||||
<div class="flex-box">
|
||||
<header role="banner" class="flex-header">
|
||||
<nav role="navigation">
|
||||
<!-- ========= START OF TOP NAVBAR ======= -->
|
||||
<div class="top-nav" id="navbar.top">
|
||||
<div class="skip-nav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
|
||||
<ul id="navbar.top.firstrow" class="nav-list" title="Navigation">
|
||||
<li><a href="org.xbib.graphics.io.vector/module-summary.html">Module</a></li>
|
||||
<li>Package</li>
|
||||
<li>Class</li>
|
||||
<li><a href="overview-tree.html">Tree</a></li>
|
||||
<li><a href="deprecated-list.html">Deprecated</a></li>
|
||||
<li><a href="index-all.html">Index</a></li>
|
||||
<li><a href="help-doc.html">Help</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sub-nav">
|
||||
<div class="nav-list-search"><label for="search">SEARCH:</label>
|
||||
<input type="text" id="search" value="search" disabled="disabled">
|
||||
<input type="reset" id="reset" value="reset" disabled="disabled">
|
||||
</div>
|
||||
</div>
|
||||
<!-- ========= END OF TOP NAVBAR ========= -->
|
||||
<span class="skip-nav" id="skip.navbar.top">
|
||||
<!-- -->
|
||||
</span></nav>
|
||||
</header>
|
||||
<div class="flex-content">
|
||||
<main role="main">
|
||||
<div class="header">
|
||||
<h1 title="Constant Field Values" class="title">Constant Field Values</h1>
|
||||
<section class="packages">
|
||||
<h2 title="Contents">Contents</h2>
|
||||
<ul>
|
||||
<li><a href="#org.xbib">org.xbib.*</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
<section class="constants-summary" id="org.xbib">
|
||||
<h2 title="org.xbib">org.xbib.*</h2>
|
||||
<ul class="block-list">
|
||||
<li>
|
||||
<div class="constants-summary">
|
||||
<table class="summary-table">
|
||||
<caption><span>org.xbib.graphics.io.vector.util.<a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/util/LineWrapOutputStream.html" title="class in org.xbib.graphics.io.vector.util">LineWrapOutputStream</a></span></caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="col-first" scope="col">Modifier and Type</th>
|
||||
<th class="col-second" scope="col">Constant Field</th>
|
||||
<th class="col-last" scope="col">Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="alt-color">
|
||||
<td class="col-first"><code id="org.xbib.graphics.io.vector.util.LineWrapOutputStream.STANDARD_EOL">public static final java.lang.String</code></td>
|
||||
<th class="col-second" scope="row"><code><a href="org.xbib.graphics.io.vector/org/xbib/graphics/io/vector/util/LineWrapOutputStream.html#STANDARD_EOL">STANDARD_EOL</a></code></th>
|
||||
<td class="col-last"><code>"\r\n"</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</main>
|
||||
<footer role="contentinfo">
|
||||
<nav role="navigation">
|
||||
<!-- ======= START OF BOTTOM NAVBAR ====== -->
|
||||
<div class="bottom-nav" id="navbar.bottom">
|
||||
<div class="skip-nav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
|
||||
<ul id="navbar.bottom.firstrow" class="nav-list" title="Navigation">
|
||||
<li><a href="org.xbib.graphics.io.vector/module-summary.html">Module</a></li>
|
||||
<li>Package</li>
|
||||
<li>Class</li>
|
||||
<li><a href="overview-tree.html">Tree</a></li>
|
||||
<li><a href="deprecated-list.html">Deprecated</a></li>
|
||||
<li><a href="index-all.html">Index</a></li>
|
||||
<li><a href="help-doc.html">Help</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- ======== END OF BOTTOM NAVBAR ======= -->
|
||||
<span class="skip-nav" id="skip.navbar.bottom">
|
||||
<!-- -->
|
||||
</span></nav>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,80 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!-- NewPage -->
|
||||
<html lang="de">
|
||||
<head>
|
||||
<!-- Generated by javadoc -->
|
||||
<title>Deprecated List (io-vector 3.0.0 API)</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="description" content="deprecated elements">
|
||||
<meta name="generator" content="javadoc/DeprecatedListWriter">
|
||||
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
|
||||
<link rel="stylesheet" type="text/css" href="script-dir/jquery-ui.min.css" title="Style">
|
||||
<link rel="stylesheet" type="text/css" href="jquery-ui.overrides.css" title="Style">
|
||||
<script type="text/javascript" src="script.js"></script>
|
||||
<script type="text/javascript" src="script-dir/jquery-3.5.1.min.js"></script>
|
||||
<script type="text/javascript" src="script-dir/jquery-ui.min.js"></script>
|
||||
</head>
|
||||
<body class="deprecated-list-page">
|
||||
<script type="text/javascript">var pathtoroot = "./";
|
||||
loadScripts(document, 'script');</script>
|
||||
<noscript>
|
||||
<div>JavaScript is disabled on your browser.</div>
|
||||
</noscript>
|
||||
<div class="flex-box">
|
||||
<header role="banner" class="flex-header">
|
||||
<nav role="navigation">
|
||||
<!-- ========= START OF TOP NAVBAR ======= -->
|
||||
<div class="top-nav" id="navbar.top">
|
||||
<div class="skip-nav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
|
||||
<ul id="navbar.top.firstrow" class="nav-list" title="Navigation">
|
||||
<li><a href="org.xbib.graphics.io.vector/module-summary.html">Module</a></li>
|
||||
<li>Package</li>
|
||||
<li>Class</li>
|
||||
<li><a href="overview-tree.html">Tree</a></li>
|
||||
<li class="nav-bar-cell1-rev">Deprecated</li>
|
||||
<li><a href="index-all.html">Index</a></li>
|
||||
<li><a href="help-doc.html">Help</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sub-nav">
|
||||
<div class="nav-list-search"><label for="search">SEARCH:</label>
|
||||
<input type="text" id="search" value="search" disabled="disabled">
|
||||
<input type="reset" id="reset" value="reset" disabled="disabled">
|
||||
</div>
|
||||
</div>
|
||||
<!-- ========= END OF TOP NAVBAR ========= -->
|
||||
<span class="skip-nav" id="skip.navbar.top">
|
||||
<!-- -->
|
||||
</span></nav>
|
||||
</header>
|
||||
<div class="flex-content">
|
||||
<main role="main">
|
||||
<div class="header">
|
||||
<h1 title="Deprecated API" class="title">Deprecated API</h1>
|
||||
<h2 title="Contents">Contents</h2>
|
||||
</div>
|
||||
</main>
|
||||
<footer role="contentinfo">
|
||||
<nav role="navigation">
|
||||
<!-- ======= START OF BOTTOM NAVBAR ====== -->
|
||||
<div class="bottom-nav" id="navbar.bottom">
|
||||
<div class="skip-nav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
|
||||
<ul id="navbar.bottom.firstrow" class="nav-list" title="Navigation">
|
||||
<li><a href="org.xbib.graphics.io.vector/module-summary.html">Module</a></li>
|
||||
<li>Package</li>
|
||||
<li>Class</li>
|
||||
<li><a href="overview-tree.html">Tree</a></li>
|
||||
<li class="nav-bar-cell1-rev">Deprecated</li>
|
||||
<li><a href="index-all.html">Index</a></li>
|
||||
<li><a href="help-doc.html">Help</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- ======== END OF BOTTOM NAVBAR ======= -->
|
||||
<span class="skip-nav" id="skip.navbar.bottom">
|
||||
<!-- -->
|
||||
</span></nav>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,8 +0,0 @@
|
|||
module:org.xbib.graphics.io.vector
|
||||
org.xbib.graphics.io.vector
|
||||
org.xbib.graphics.io.vector.commands
|
||||
org.xbib.graphics.io.vector.eps
|
||||
org.xbib.graphics.io.vector.filters
|
||||
org.xbib.graphics.io.vector.pdf
|
||||
org.xbib.graphics.io.vector.svg
|
||||
org.xbib.graphics.io.vector.util
|
|
@ -1,185 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<!-- NewPage -->
|
||||
<html lang="de">
|
||||
<head>
|
||||
<!-- Generated by javadoc -->
|
||||
<title>API Help (io-vector 3.0.0 API)</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="description" content="help">
|
||||
<meta name="generator" content="javadoc/HelpWriter">
|
||||
<link rel="stylesheet" type="text/css" href="stylesheet.css" title="Style">
|
||||
<link rel="stylesheet" type="text/css" href="script-dir/jquery-ui.min.css" title="Style">
|
||||
<link rel="stylesheet" type="text/css" href="jquery-ui.overrides.css" title="Style">
|
||||
<script type="text/javascript" src="script.js"></script>
|
||||
<script type="text/javascript" src="script-dir/jquery-3.5.1.min.js"></script>
|
||||
<script type="text/javascript" src="script-dir/jquery-ui.min.js"></script>
|
||||
</head>
|
||||
<body class="help-page">
|
||||
<script type="text/javascript">var pathtoroot = "./";
|
||||
loadScripts(document, 'script');</script>
|
||||
<noscript>
|
||||
<div>JavaScript is disabled on your browser.</div>
|
||||
</noscript>
|
||||
<div class="flex-box">
|
||||
<header role="banner" class="flex-header">
|
||||
<nav role="navigation">
|
||||
<!-- ========= START OF TOP NAVBAR ======= -->
|
||||
<div class="top-nav" id="navbar.top">
|
||||
<div class="skip-nav"><a href="#skip.navbar.top" title="Skip navigation links">Skip navigation links</a></div>
|
||||
<ul id="navbar.top.firstrow" class="nav-list" title="Navigation">
|
||||
<li><a href="org.xbib.graphics.io.vector/module-summary.html">Module</a></li>
|
||||
<li>Package</li>
|
||||
<li>Class</li>
|
||||
<li><a href="overview-tree.html">Tree</a></li>
|
||||
<li><a href="deprecated-list.html">Deprecated</a></li>
|
||||
<li><a href="index-all.html">Index</a></li>
|
||||
<li class="nav-bar-cell1-rev">Help</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="sub-nav">
|
||||
<div class="nav-list-search"><label for="search">SEARCH:</label>
|
||||
<input type="text" id="search" value="search" disabled="disabled">
|
||||
<input type="reset" id="reset" value="reset" disabled="disabled">
|
||||
</div>
|
||||
</div>
|
||||
<!-- ========= END OF TOP NAVBAR ========= -->
|
||||
<span class="skip-nav" id="skip.navbar.top">
|
||||
<!-- -->
|
||||
</span></nav>
|
||||
</header>
|
||||
<div class="flex-content">
|
||||
<main role="main">
|
||||
<div class="header">
|
||||
<h1 class="title">How This API Document Is Organized</h1>
|
||||
<div class="sub-title">This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.</div>
|
||||
</div>
|
||||
<section class="help-section">
|
||||
<h2>Module</h2>
|
||||
<p>Each module has a page that contains a list of its packages, dependencies on other modules, and services, with a summary for each. These pages may contain three categories:</p>
|
||||
<ul class="help-section-list">
|
||||
<li>Packages</li>
|
||||
<li>Modules</li>
|
||||
<li>Services</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="help-section">
|
||||
<h2>Package</h2>
|
||||
<p>Each package has a page that contains a list of its classes and interfaces, with a summary for each. These pages may contain six categories:</p>
|
||||
<ul class="help-section-list">
|
||||
<li>Interfaces</li>
|
||||
<li>Classes</li>
|
||||
<li>Enums</li>
|
||||
<li>Exceptions</li>
|
||||
<li>Errors</li>
|
||||
<li>Annotation Types</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="help-section">
|
||||
<h2>Class or Interface</h2>
|
||||
<p>Each class, interface, nested class and nested interface has its own separate page. Each of these pages has three sections consisting of a class/interface description, summary tables, and detailed member descriptions:</p>
|
||||
<ul class="help-section-list">
|
||||
<li>Class Inheritance Diagram</li>
|
||||
<li>Direct Subclasses</li>
|
||||
<li>All Known Subinterfaces</li>
|
||||
<li>All Known Implementing Classes</li>
|
||||
<li>Class or Interface Declaration</li>
|
||||
<li>Class or Interface Description</li>
|
||||
</ul>
|
||||
<br>
|
||||
<ul class="help-section-list">
|
||||
<li>Nested Class Summary</li>
|
||||
<li>Field Summary</li>
|
||||
<li>Property Summary</li>
|
||||
<li>Constructor Summary</li>
|
||||
<li>Method Summary</li>
|
||||
</ul>
|
||||
<br>
|
||||
<ul class="help-section-list">
|
||||
<li>Field Details</li>
|
||||
<li>Property Details</li>
|
||||
<li>Constructor Details</li>
|
||||
<li>Method Details</li>
|
||||
</ul>
|
||||
<p>The summary entries are alphabetical, while the detailed descriptions are in the order they appear in the source code. This preserves the logical groupings established by the programmer.</p>
|
||||
</section>
|
||||
<section class="help-section">
|
||||
<h2>Annotation Type</h2>
|
||||
<p>Each annotation type has its own separate page with the following sections:</p>
|
||||
<ul class="help-section-list">
|
||||
<li>Annotation Type Declaration</li>
|
||||
<li>Annotation Type Description</li>
|
||||
<li>Required Element Summary</li>
|
||||
<li>Optional Element Summary</li>
|
||||
<li>Element Details</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="help-section">
|
||||
<h2>Enum</h2>
|
||||
<p>Each enum has its own separate page with the following sections:</p>
|
||||
<ul class="help-section-list">
|
||||
<li>Enum Declaration</li>
|
||||
<li>Enum Description</li>
|
||||
<li>Enum Constant Summary</li>
|
||||
<li>Enum Constant Details</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="help-section">
|
||||
<h2>Tree (Class Hierarchy)</h2>
|
||||
<p>There is a <a href="overview-tree.html">Class Hierarchy</a> page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. Classes are organized by inheritance structure starting with <code>java.lang.Object</code>. Interfaces do not inherit from <code>java.lang.Object</code>.</p>
|
||||
<ul class="help-section-list">
|
||||
<li>When viewing the Overview page, clicking on "Tree" displays the hierarchy for all packages.</li>
|
||||
<li>When viewing a particular package, class or interface page, clicking on "Tree" displays the hierarchy for only that package.</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section class="help-section">
|
||||
<h2>Deprecated API</h2>
|
||||
<p>The <a href="deprecated-list.html">Deprecated API</a> page lists all of the API that have been deprecated. A deprecated API is not recommended for use, generally due to shortcomings, and a replacement API is usually given. Deprecated APIs may be removed in future implementations.</p>
|
||||
</section>
|
||||
<section class="help-section">
|
||||
<h2>Index</h2>
|
||||
<p>The <a href="index-all.html">Index</a> contains an alphabetic index of all classes, interfaces, constructors, methods, and fields, as well as lists of all packages and all classes.</p>
|
||||
</section>
|
||||
<section class="help-section">
|
||||
<h2>Serialized Form</h2>
|
||||
<p>Each serializable or externalizable class has a description of its serialization fields and methods. This information is of interest to those who implement rather than use the API. While there is no link in the navigation bar, you can get to this information by going to any serialized class and clicking "Serialized Form" in the "See Also" section of the class description.</p>
|
||||
</section>
|
||||
<section class="help-section">
|
||||
<h2>Constant Field Values</h2>
|
||||
<p>The <a href="constant-values.html">Constant Field Values</a> page lists the static final fields and their values.</p>
|
||||
</section>
|
||||
<section class="help-section">
|
||||
<h2>Search</h2>
|
||||
<p>You can search for definitions of modules, packages, types, fields, methods, system properties and other terms defined in the API, using some or all of the name, optionally using "camel-case" abbreviations. For example:</p>
|
||||
<ul class="help-section-list">
|
||||
<li><code>j.l.obj</code> will match "java.lang.Object"</li>
|
||||
<li><code>InpStr</code> will match "java.io.InputStream"</li>
|
||||
<li><code>HM.cK</code> will match "java.util.HashMap.containsKey(Object)"</li>
|
||||
</ul>
|
||||
<p>Refer to <a href="https://docs.oracle.com/en/java/javase/15/docs/specs/javadoc/javadoc-search-spec.html">the Javadoc Search Specification</a> for a full description of search features.</p>
|
||||
</section>
|
||||
<hr>
|
||||
<span class="help-footnote">This help file applies to API documentation generated by the standard doclet.</span></main>
|
||||
<footer role="contentinfo">
|
||||
<nav role="navigation">
|
||||
<!-- ======= START OF BOTTOM NAVBAR ====== -->
|
||||
<div class="bottom-nav" id="navbar.bottom">
|
||||
<div class="skip-nav"><a href="#skip.navbar.bottom" title="Skip navigation links">Skip navigation links</a></div>
|
||||
<ul id="navbar.bottom.firstrow" class="nav-list" title="Navigation">
|
||||
<li><a href="org.xbib.graphics.io.vector/module-summary.html">Module</a></li>
|
||||
<li>Package</li>
|
||||
<li>Class</li>
|
||||
<li><a href="overview-tree.html">Tree</a></li>
|
||||
<li><a href="deprecated-list.html">Deprecated</a></li>
|
||||
<li><a href="index-all.html">Index</a></li>
|
||||
<li class="nav-bar-cell1-rev">Help</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- ======== END OF BOTTOM NAVBAR ======= -->
|
||||
<span class="skip-nav" id="skip.navbar.bottom">
|
||||
<!-- -->
|
||||
</span></nav>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue