// Copyright 2001-2006, FreeHEP. package org.freehep.postscript; import java.awt.Paint; import java.awt.geom.AffineTransform; import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; /** * Form and Pattern Operators for PostScript Processor * * @author Mark Donszelmann * @version $Id: FormOperator.java 10178 2006-12-08 09:03:07Z duns $ */ public class FormOperator extends PSOperator { public static Class[] operators = { MakePattern.class, SetPattern.class, ExecForm.class }; public boolean execute(OperandStack os) { throw new RuntimeException("Cannot execute class: "+getClass()); } } class MakePattern extends FormOperator { private PSDictionary pattern; private Paint paint; private MakePattern(PSDictionary d, Paint p) { pattern = d; paint = p; } public MakePattern() { } public boolean execute(OperandStack os) { if (pattern == null) { if (!os.checkType(PSDictionary.class, PSPackedArray.class)) { error(os, new TypeCheck()); return true; } AffineTransform m = new AffineTransform(os.popPackedArray().toDoubles()); PSDictionary d = os.popDictionary(); // FIXME: no checking // FIXME: no copy int type = d.getInteger("PatternType"); switch(type) { case 1: // tiling pattern PSPackedArray proc = (PSPackedArray)d.getPackedArray("PaintProc").copy(); double[] bbox = d.getPackedArray("BBox").toDoubles(); double xStep = d.getNumber("XStep").getDouble(); double yStep = d.getNumber("YStep").getDouble(); int paintType = d.getInteger("PaintType"); // FIXME: ignored int tilingType = d.getInteger("TilingType"); // gsave, create image, set modified gstate os.push(d); os.gsave(); AffineTransform inverse = new AffineTransform(); try { inverse = m.createInverse(); } catch (NoninvertibleTransformException e) { System.err.println("Internal MakePattern Error"); } Point2D bb = inverse.deltaTransform(new Point2D.Double(1.0, 1.0), null); double w = bbox[2]-bbox[0]+bb.getX(); double h = bbox[3]-bbox[1]+bb.getY(); Point2D biSize = m.deltaTransform(new Point2D.Double(xStep, yStep), null); int biWidth = (int)biSize.getX(); int biHeight = (int)biSize.getY(); BufferedImage bi = os.gstate().convertToImage(biWidth, biHeight); AffineTransform ctm = os.gstate().getTransform(); os.gstate().setTransform(m); // FIXME: offset may not be completely correct (HEART2) os.gstate().translate(-bbox[0], -bbox[1]); os.gstate().newPath(); os.gstate().clip(new Rectangle2D.Double(bbox[0], bbox[1], w, h)); Point2D offset = inverse.transform(new Point2D.Double(bbox[0], bbox[1]), null); Rectangle2D box = new Rectangle2D.Double(offset.getX(), offset.getY(), biWidth, biHeight); Paint p = new FixedTexturePaint(os, ctm, bi, box); os.execStack().pop(); os.execStack().push(new MakePattern(d, p)); os.execStack().push(proc); switch(paintType) { case 1: break; case 2: os.gstate().setColorSpace("DeviceRGB"); os.gstate().setColor(new float[] {1.0f, 0.0f, 0.0f}); break; default: error(os, new RangeCheck()); return true; } return false; default: // FIXME error(os, new RangeCheck()); return true; } } os.grestore(); // retrieve paint and save as implementation pattern.put("Implementation", new PSPaint(paint)); os.push(pattern); return true; } } class SetPattern extends FormOperator { { operandTypes = new Class[] {PSDictionary.class}; } public boolean execute(OperandStack os) { PSDictionary pattern = os.popDictionary(); // FIXME: no checking int type = pattern.getInteger("PatternType"); switch(type) { case 1: // tiling PSPaint implementation = (PSPaint)pattern.get("Implementation"); Paint paint = implementation.getValue(); int paintType = pattern.getInteger("PaintType"); System.out.println("PaintType..."+paintType); switch (paintType) { case 1: os.gstate().setColor(paint); break; case 2: // FIXME: parameters os.gstate().setColor(paint, new PSObject[0]); break; default: error(os, new RangeCheck()); return true; } break; default: error(os, new RangeCheck()); break; } return true; } } class ExecForm extends FormOperator { private boolean done; private ExecForm(boolean d) { done = d; } public ExecForm() { } public boolean execute(OperandStack os) { if (!done) { if (!os.checkType(PSDictionary.class)) { error(os, new TypeCheck()); return true; } PSDictionary form = os.popDictionary(); try { if (form.getInteger("FormType") != 1) { error(os, new RangeCheck()); return true; } AffineTransform matrix = new AffineTransform(form.getPackedArray("Matrix").toDoubles()); double[] bbox = form.getPackedArray("BBox").toDoubles(); PSPackedArray proc = (PSPackedArray)form.getPackedArray("PaintProc").clone(); proc.setExecutable(); // gsave, concat matrix, rectclip bbox os.gsave(); os.gstate().transform(matrix); os.gstate().clip(new Rectangle2D.Double(bbox[0], bbox[1], bbox[2]-bbox[0], bbox[3]-bbox[1])); os.execStack().pop(); os.execStack().push(new ExecForm(true)); os.execStack().push(proc); os.push(form); return false; } catch (ClassCastException e) { error(os, new TypeCheck()); return true; } } os.grestore(); return true; } }