/** * Writes the <code>shape</code>, <code>coords</code>, <code>href</code>, * <code>nohref</code> Attribute for the specified figure and shape. * * @return Returns true, if the polygon is inside of the image bounds. */ private boolean writePolyAttributes(IXMLElement elem, SVGFigure f, Shape shape) { AffineTransform t = TRANSFORM.getClone(f); if (t == null) { t = drawingTransform; } else { t.preConcatenate(drawingTransform); } StringBuilder buf = new StringBuilder(); float[] coords = new float[6]; GeneralPath path = new GeneralPath(); for (PathIterator i = shape.getPathIterator(t, 1.5f); ! i.isDone(); i.next()) { switch (i.currentSegment(coords)) { case PathIterator.SEG_MOVETO : if (buf.length() != 0) { throw new IllegalArgumentException("Illegal shape "+shape); } if (buf.length() != 0) { buf.append(','); } buf.append((int) coords[0]); buf.append(','); buf.append((int) coords[1]); path.moveTo(coords[0], coords[1]); break; case PathIterator.SEG_LINETO : if (buf.length() != 0) { buf.append(','); } buf.append((int) coords[0]); buf.append(','); buf.append((int) coords[1]); path.lineTo(coords[0], coords[1]); break; case PathIterator.SEG_CLOSE : path.closePath(); break; default : throw new InternalError("Illegal segment type "+i.currentSegment(coords)); } } elem.setAttribute("shape", "poly"); elem.setAttribute("coords", buf.toString()); writeHrefAttribute(elem, f); return path.intersects(new Rectangle2D.Float(bounds.x, bounds.y, bounds.width, bounds.height)); }
@Override public void keyPressed(KeyEvent evt) { Figure f = getOwner(); if (f.isTransformable()) { AffineTransform tx = new AffineTransform(); switch (evt.getKeyCode()) { case KeyEvent.VK_UP: tx.translate(0, -1); evt.consume(); break; case KeyEvent.VK_DOWN: tx.translate(0, +1); evt.consume(); break; case KeyEvent.VK_LEFT: tx.translate(-1, 0); evt.consume(); break; case KeyEvent.VK_RIGHT: tx.translate(+1, 0); evt.consume(); break; } f.willChange(); f.transform(tx); f.changed(); fireUndoableEditHappened(new TransformEdit(f, tx)); } }
/** * Paints the icon. * * @param c the component on which it is painted * @param _g the graphics context * @param x the x coordinate of the icon * @param y the y coordinate of the icon */ public void paintIcon(Component c, Graphics _g, int x, int y) { Graphics2D g = (Graphics2D) _g; AffineTransform at = AffineTransform.getTranslateInstance(x + offsetX, y + offsetY); // save current graphics paint and clip Paint gPaint = g.getPaint(); Shape gClip = g.getClip(); // render shape(s) g.setPaint(color); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.clipRect(x, y, w, h); // paint shape, if any if (shape != null) { g.fill(at.createTransformedShape(shape)); } // paint decoration, if any if (decoration != null) { g.setPaint(decoColor); g.fill(at.createTransformedShape(decoration)); } // restore graphics paint and clip g.setPaint(gPaint); g.setClip(gClip); }
public void drawScaledImage(BufferedImage im, int x, int y, int w, int h) { float scaleX = w * 1.0f / im.getWidth(); float scaleY = h * 1.0f / im.getHeight(); AffineTransform tx = new AffineTransform(); tx.scale(scaleX, scaleY); BufferedImageOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_BILINEAR); drawImage(im, op, x, y); }
@Override public void trackEnd(Point anchor, Point lead, int modifiersEx) { if (getOwner().isTransformable()) { AffineTransform tx = new AffineTransform(); tx.translate(lead.x - anchor.x, lead.y - anchor.y); fireUndoableEditHappened(new TransformEdit(getOwner(), tx)); } }
/** * Gets the mark for the specified panel. * * @param trackerPanel the tracker panel * @return the mark */ protected Mark getMark(TrackerPanel trackerPanel) { Mark mark = marks.get(trackerPanel); TPoint selection = null; if (mark == null) { selection = trackerPanel.getSelectedPoint(); Point p = null; valid = true; // assume true for (int n = 0; n < points.length; n++) { if (!valid) continue; // determine if point is valid (ie not NaN) valid = valid && !Double.isNaN(points[n].getX()) && !Double.isNaN(points[n].getY()); screenPoints[n] = points[n].getScreenPosition(trackerPanel); if (valid && selection == points[n]) p = screenPoints[n]; } mark = footprint.getMark(screenPoints); if (p != null) { // point is selected, so draw selection shape transform.setToTranslation(p.x, p.y); int scale = FontSizer.getIntegerFactor(); if (scale > 1) { transform.scale(scale, scale); } final Color color = footprint.getColor(); final Mark stepMark = mark; final Shape selectedShape = transform.createTransformedShape(selectionShape); mark = new Mark() { public void draw(Graphics2D g, boolean highlighted) { stepMark.draw(g, false); Paint gpaint = g.getPaint(); g.setPaint(color); g.fill(selectedShape); g.setPaint(gpaint); } public Rectangle getBounds(boolean highlighted) { Rectangle bounds = selectedShape.getBounds(); bounds.add(stepMark.getBounds(false)); return bounds; } }; } final Mark theMark = mark; mark = new Mark() { public void draw(Graphics2D g, boolean highlighted) { if (!valid) return; theMark.draw(g, false); } public Rectangle getBounds(boolean highlighted) { return theMark.getBounds(highlighted); } }; marks.put(trackerPanel, mark); } return mark; }
private AffineTransform makeTransform(Object o) { AffineTransform r = (AffineTransform) ((AffineTransform) o).clone(); // System.out.println("r:"+r); if (origTransform != null) { AffineTransform r2 = (AffineTransform) origTransform.clone(); // System.out.println("r2:"+r2); r2.concatenate(r); r = r2; } return r; }
/** * synchronize frame shape and location (TextLayout only) ; this is called by syncShape(), so that * subclasser might override easily when only rectangular shapes are availables. */ protected void syncFrame() { PicText te = (PicText) element; if (!te.isFramed()) { return; } AffineTransform tr = new AffineTransform(); // maps Image coordinates to Model coordinates (see paint) tr.setToIdentity(); // reset PicPoint anchor = te.getCtrlPt(TextEditable.P_ANCHOR, ptBuf); tr.rotate(getRotation(), anchor.x, anchor.y); // rotate along P_ANCHOR ! shape = tr.createTransformedShape(te.getShapeOfFrame()); }
/** * Zoom, preserving the center point on the screen. (When we draw, the center point may be moved * in order to maximize the amount of image seen on screen.) * */ void adjustZoom(double z, Point2D cp) { if (cp == null) cp = new Point2D.Double(getWidth() / 2, getHeight() / 2); Point2D cxt = componentToImage(cp); double tx = cp.getX() - cxt.getX() * z; double ty = cp.getY() - cxt.getY() * z; t = new AffineTransform(); t.translate(tx, ty); t.scale(z, z); fit = false; repaint(); }
void draw(Graphics2D g) { // toX/toY is tip of arrow and fx/fy is a point on the line - // fx/fy is used to determine direction & angle AffineTransform at = AffineTransform.getTranslateInstance(toX, toY); int b = 9; double theta = Math.toRadians(20); // The idea of using a GeneralPath is so we can // create the (three lines that make up the) arrow // (only) one time and then use AffineTransform to // place it anywhere we want. GeneralPath path = new GeneralPath(); // distance between line and the arrow mark <** not ** // Start a new line segment from the position of (0,0). path.moveTo(0, 0); // Create one of the two arrow head lines. int x = (int) (-b * Math.cos(theta)); int y = (int) (b * Math.sin(theta)); path.lineTo(x, y); // distance between line and the arrow mark <** not ** // Make the other arrow head line. int x2 = (int) (-b * Math.cos(-theta)); int y2 = (int) (b * Math.sin(-theta)); // path.moveTo(0,0); path.lineTo(x2, y2); path.closePath(); // theta is in radians double s, t; s = toY - fy; // calculate slopes. t = toX - fx; if (t != 0) { s = s / t; theta = Math.atan(s); if (t < 0) theta += Math.PI; } else if (s < 0) theta = -(Math.PI / 2); else theta = Math.PI / 2; at.rotate(theta); // at.rotate(theta,toX,toY); Shape shape = at.createTransformedShape(path); if (checkStatus == Status.UNCHECKED) g.setColor(Color.BLACK); else if (checkStatus == Status.COMPATIBLE) g.setColor(FOREST_GREEN); else g.setColor(ORANGE_RED); g.fill(shape); g.draw(shape); }
@Override public void trackStep(Point anchor, Point lead, int modifiersEx) { Figure f = getOwner(); if (f.isTransformable()) { Point2D.Double newPoint = view.getConstrainer().constrainPoint(view.viewToDrawing(lead)); AffineTransform tx = new AffineTransform(); tx.translate(newPoint.x - oldPoint.x, newPoint.y - oldPoint.y); f.willChange(); f.transform(tx); f.changed(); oldPoint = newPoint; } }
public void mouseDragged(MouseEvent e) { int mods = e.getModifiersEx(); Point dragEnd = e.getPoint(); boolean shift = (mods & MouseEvent.SHIFT_DOWN_MASK) > 0; boolean ctrl = (mods & MouseEvent.CTRL_DOWN_MASK) > 0; boolean alt = shift & ctrl; ctrl = ctrl & (!alt); shift = shift & (!alt); boolean nomods = !(shift | ctrl | alt); if (dragBegin == null) dragBegin = dragEnd; nodrag = false; if ((mods & InputEvent.BUTTON3_DOWN_MASK) > 0 || true) { double dx = dragEnd.getX() - dragBegin.getX(); double dy = dragEnd.getY() - dragBegin.getY(); synchronized (JImage.this) { t.preConcatenate(AffineTransform.getTranslateInstance(dx, dy)); } dragBegin = dragEnd; repaint(); } }
/** * This implementation calls <code>super.hitTest</code> and returns the result if non-null (this * should be a HitInfo.Point), then returns a HitInfo.Interior if the mouse-click occured inside * the text bound (as defined by text layout) * * @return a HitInfo corresponding to the given mouse-event */ public HitInfo hitTest(PEMouseEvent e) { // from Bitmap: if (image != null) { if (getBounds().contains(e.getPicPoint())) { return new HitInfo.Interior((PicText) element, e); } return null; } // from TextLayout: if (!getBounds().contains(e.getPicPoint())) return null; PicText te = (PicText) element; // recompute textlayout b-box, but store it in a temporary field ! Rectangle2D tb = textLayout.getBounds(); Shape text_bounds = text2ModelTr.createTransformedShape(tb); if (text_bounds.contains(e.getPicPoint())) { // [SR:pending] for the hitInfo to be reliable, getPicPoint() should first be transformed by // inverse text2ModelTr ! (especially when rotationAngle != 0) TextHitInfo thi = textLayout.hitTestChar( (float) (e.getPicPoint().x - strx), (float) (e.getPicPoint().y - stry)); // guaranteed to return a non-null thi return new HitInfo.Text((PicText) element, thi, e); } // test hit on textlayout's bounding rectangle : // else if (bounds.contains(e.getPicPoint())) return new HitInfo.Interior(element,e); return null; }
public void setFontSize(float size) { // FONT_SIZE.basicSet(this, new Double(size)); Point2D.Double p = new Point2D.Double(0, size); AffineTransform tx = TRANSFORM.get(this); if (tx != null) { try { tx.inverseTransform(p, p); Point2D.Double p0 = new Point2D.Double(0, 0); tx.inverseTransform(p0, p0); p.y -= p0.y; } catch (NoninvertibleTransformException ex) { ex.printStackTrace(); } } FONT_SIZE.set(this, Math.abs(p.y)); }
protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D)g; AffineTransform origXform = g2d.getTransform(); AffineTransform newXform = (AffineTransform)(origXform.clone()); //center of rotation is center of the panel int xRot = this.getWidth()/2; int yRot = this.getHeight()/2; newXform.rotate(Math.toRadians(currentAngle), xRot, yRot); g2d.setTransform(newXform); //draw image centered in panel int x = (getWidth() - image.getWidth(this))/2; int y = (getHeight() - image.getHeight(this))/2; g2d.drawImage(image, x, y, this); g2d.setTransform(origXform); }
public void paint(Graphics g) { Graphics2D g2d = (Graphics2D) g; AffineTransform trans = new AffineTransform(); int width = getSize().width; int height = getSize().height; g2d.setColor(Color.BLACK); g2d.fillRect(0, 0, width, height); trans.setTransform(identity); trans.scale(scale, scale); g2d.drawImage(image, trans, this); }
public void addGlyph(GlyphData gv, float x, float y) { AffineTransform at = AffineTransform.getTranslateInstance(x, y); PathIterator pi = gv.gp.getPathIterator(at); float[] coords = new float[6]; while (!pi.isDone()) { int type = pi.currentSegment(coords); switch (type) { case PathIterator.SEG_MOVETO: moveTo(coords[0], coords[1]); break; case PathIterator.SEG_LINETO: lineTo(coords[0], coords[1]); break; case PathIterator.SEG_CUBICTO: curveTo(coords[0], coords[1], coords[2], coords[3], coords[4], coords[5]); break; case PathIterator.SEG_CLOSE: closePath(); break; default: System.out.println("Unknown path type: " + type); break; } pi.next(); } }
/** * Code to paint the specific shape * * @param w2v 2D affine transform * @param g graphics context */ public void paintShape(Graphics2D g, AffineTransform w2v) { double x = startPoint.getX(); double y = startPoint.getY(); double xEnd = endPoint.getX(); double yEnd = endPoint.getY(); g.setStroke(new BasicStroke(this.getThickness(), BasicStroke.CAP_ROUND, BasicStroke.CAP_ROUND)); Point2D v0 = w2v.transform(new Point2D.Double(x, y), null); int ix = (int) v0.getX(); int iy = (int) v0.getY(); Point2D v1 = w2v.transform(new Point2D.Double(xEnd, yEnd), null); g.drawLine(ix, iy, (int) v1.getX(), (int) v1.getY()); }
/** * Method to create a new picture by scaling the current picture by the given x and y factors * * @param xFactor the amount to scale in x * @param yFactor the amount to scale in y * @return the resulting picture */ public Picture scale(double xFactor, double yFactor) { // set up the scale transform AffineTransform scaleTransform = new AffineTransform(); scaleTransform.scale(xFactor, yFactor); // create a new picture object that is the right size Picture result = new Picture((int) (getWidth() * xFactor), (int) (getHeight() * yFactor)); // get the graphics 2d object to draw on the result Graphics graphics = result.getGraphics(); Graphics2D g2 = (Graphics2D) graphics; // draw the current image onto the result image scaled g2.drawImage(this.getImage(), scaleTransform, null); return result; }
public float getFontSize() { // return FONT_SIZE.get(this).floatValue(); Point2D.Double p = new Point2D.Double(0, FONT_SIZE.get(this)); AffineTransform tx = TRANSFORM.get(this); if (tx != null) { tx.transform(p, p); Point2D.Double p0 = new Point2D.Double(0, 0); tx.transform(p0, p0); p.y -= p0.y; /* try { tx.inverseTransform(p, p); } catch (NoninvertibleTransformException ex) { ex.printStackTrace(); }*/ } return (float) Math.abs(p.y); }
public void vec2FieldMagnitude(Field field, AffineTransform ftoi) { AffineTransform itof = null; try { itof = ftoi.createInverse(); } catch (NoninvertibleTransformException niv) { TDebug.println(0, "NoninvertibleTransformException: " + niv); } Vector3d v = new Vector3d(); Point2D.Double p = new Point2D.Double(); for (int j = 0, k = 0; j < height; ++j) for (int i = 0; i < width; ++i, ++k) { p.x = i; p.y = j; itof.transform(p, p); v = field.get(p.x, p.y, 0.0); f[k] = (float) Math.sqrt(v.x * v.x + v.y * v.y); } }
public void vec2FieldZero(Field field, AffineTransform ftoi) { AffineTransform itof = null; try { itof = ftoi.createInverse(); } catch (NoninvertibleTransformException niv) { TDebug.println(0, "NoninvertibleTransformException: " + niv); } Vector3d v = new Vector3d(); Point2D.Double p = new Point2D.Double(); for (int j = 0, k = 0; j < height; ++j) for (int i = 0; i < width; ++i, ++k) { p.x = i; p.y = j; itof.transform(p, p); v = field.get(p.x, p.y, 0.0); if ((v.x == 0.0) && (v.y == 0.0)) f[k] = 1.0f; else f[k] = 0.0f; } }
public void validateCompositeState( Composite comp, AffineTransform xform, Paint paint, SunGraphics2D sg2d) { boolean updatePaint = (paint != validatedPaint) || paint == null; // validate composite if ((comp != validatedComp)) { if (comp != null) { setComposite(comp); } else { comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER); setComposite(comp); } // the paint state is dependent on the composite state, so make // sure we update the color below updatePaint = true; validatedComp = comp; } if (sg2d != null && validatedPixel != sg2d.pixel) { validatedPixel = sg2d.pixel; setForeground(validatedPixel); } // validate paint if (updatePaint) { if (paint != null && sg2d != null && sg2d.paintState >= SunGraphics2D.PAINT_GRADIENT) { XRPaints.setPaint(sg2d, paint); } else { XRResetPaint(); } validatedPaint = paint; } if (src != solidSrcPict) { AffineTransform at = (AffineTransform) xform.clone(); try { at.invert(); } catch (NoninvertibleTransformException e) { at.setToIdentity(); } src.validateAsSource(at, -1, -1); } }
/** Synchronizes bounding box with the model ; */ protected void syncBounds() { PicText te = (PicText) element; // [pending] Il faut tenir compte de la rotation ! Rectangle2D latexBB = null; // BB relative to latex dimensions (including rotation) (without frame) Rectangle2D textLayoutBB = null; // BB relative to textLayout dimensions (including rotation) (without frame) Rectangle2D textBB = null; // BB of the text (including rotation), without frame if (areDimensionsComputed) { // compute latexBB Rectangle2D nonRotated = new Rectangle2D.Double( te.getLeftX(), te.getBottomY(), te.getWidth(), te.getHeight() + te.getDepth()); AffineTransform tr = new AffineTransform(); // maps Image coordinates to Model coordinates (see paint) tr.setToIdentity(); // reset PicPoint anchor = te.getCtrlPt(TextEditable.P_ANCHOR, ptBuf); tr.rotate(getRotation(), anchor.x, anchor.y); // rotate along P_ANCHOR ! latexBB = tr.createTransformedShape(nonRotated).getBounds2D(); } if (image == null) { // compute textLayoutBB Rectangle2D nonRotated = textLayout.getBounds(); textLayoutBB = text2ModelTr.createTransformedShape(nonRotated).getBounds2D(); } // use textLayoutBB or latexBB or their union if (image != null) textBB = latexBB; else { if (!areDimensionsComputed) textBB = textLayoutBB; else { textBB = latexBB.createUnion(textLayoutBB); } } // union with frame BB if (te.isFramed()) { super.syncBounds(); // update bounds of the frame if necessary Rectangle2D.union(super.bounds, textBB, this.bounds); } else this.bounds = textBB; }
public Point2D componentToImage(Point2D p) { Point2D tp = null; try { tp = t.inverseTransform(p, null); } catch (NoninvertibleTransformException ex) { // can't happen. } return tp; }
/** * WhiteboardShapeLine constructor * * @param id String that uniquely identifies this WhiteboardObject. * @param t number of pixels that this object (or its border) * @param c WhiteboardShapeLine's color (or rather it's border) * @param startPoint the start coordinates of this line. * @param endPoint the end coordinates of this line. * @param v2w 2D affine transform */ public WhiteboardShapeLine( String id, int t, Color c, WhiteboardPoint startPoint, WhiteboardPoint endPoint, AffineTransform v2w) { super(id); this.setThickness(t); setColor(c); Point2D v0 = new Point2D.Double(startPoint.getX(), startPoint.getY()); Point2D w0 = v2w.transform(v0, null); this.startPoint = new WhiteboardPoint(w0.getX(), w0.getY()); Point2D v1 = new Point2D.Double(endPoint.getX(), endPoint.getY()); Point2D w1 = v2w.transform(v1, null); this.endPoint = new WhiteboardPoint(w1.getX(), w1.getY()); }
/** * Writes the <code>shape</code>, <code>coords</code>, <code>href</code>, * <code>nohref</code> Attribute for the specified figure and ellipse. * * @return Returns true, if the circle is inside of the image bounds. */ private boolean writeCircleAttributes(IXMLElement elem, SVGFigure f, Ellipse2D.Double ellipse) { AffineTransform t = TRANSFORM.getClone(f); if (t == null) { t = drawingTransform; } else { t.preConcatenate(drawingTransform); } if ((t.getType() & (AffineTransform.TYPE_UNIFORM_SCALE | AffineTransform.TYPE_TRANSLATION)) == t.getType() && ellipse.width == ellipse.height ) { Point2D.Double start = new Point2D.Double(ellipse.x, ellipse.y); Point2D.Double end = new Point2D.Double(ellipse.x + ellipse.width, ellipse.y + ellipse.height); t.transform(start, start); t.transform(end, end); ellipse.x = Math.min(start.x, end.x); ellipse.y = Math.min(start.y, end.y); ellipse.width = Math.abs(start.x - end.x); ellipse.height = Math.abs(start.y - end.y); elem.setAttribute("shape", "circle"); elem.setAttribute("coords", (int) (ellipse.x + ellipse.width / 2d)+","+ (int) (ellipse.y + ellipse.height / 2d)+","+ (int) (ellipse.width / 2d) ); writeHrefAttribute(elem, f); return bounds.intersects(ellipse.getBounds()); } else { return writePolyAttributes(elem, f, (Shape) ellipse); } }
/** * Transforms the figure. * * @param tx the transformation. */ public void transform(AffineTransform tx) { if (TRANSFORM.get(this) != null || tx.getType() != (tx.getType() & AffineTransform.TYPE_TRANSLATION)) { if (TRANSFORM.get(this) == null) { TRANSFORM.basicSet(this, (AffineTransform) tx.clone()); } else { AffineTransform t = TRANSFORM.getClone(this); t.preConcatenate(tx); TRANSFORM.basicSet(this, t); } } else { for (int i = 0; i < coordinates.length; i++) { tx.transform(coordinates[i], coordinates[i]); } if (FILL_GRADIENT.get(this) != null && !FILL_GRADIENT.get(this).isRelativeToFigureBounds()) { Gradient g = FILL_GRADIENT.getClone(this); g.transform(tx); FILL_GRADIENT.basicSet(this, g); } if (STROKE_GRADIENT.get(this) != null && !STROKE_GRADIENT.get(this).isRelativeToFigureBounds()) { Gradient g = STROKE_GRADIENT.getClone(this); g.transform(tx); STROKE_GRADIENT.basicSet(this, g); } } invalidate(); }
/** * Method to get the coordinates of the enclosing rectangle after this transformation is applied * to the current picture * * @return the enclosing rectangle */ public Rectangle2D getTransformEnclosingRect(AffineTransform trans) { int width = getWidth(); int height = getHeight(); double maxX = width - 1; double maxY = height - 1; double minX, minY; Point2D.Double p1 = new Point2D.Double(0, 0); Point2D.Double p2 = new Point2D.Double(maxX, 0); Point2D.Double p3 = new Point2D.Double(maxX, maxY); Point2D.Double p4 = new Point2D.Double(0, maxY); Point2D.Double result = new Point2D.Double(0, 0); Rectangle2D.Double rect = null; // get the new points and min x and y and max x and y trans.deltaTransform(p1, result); minX = result.getX(); maxX = result.getX(); minY = result.getY(); maxY = result.getY(); trans.deltaTransform(p2, result); minX = Math.min(minX, result.getX()); maxX = Math.max(maxX, result.getX()); minY = Math.min(minY, result.getY()); maxY = Math.max(maxY, result.getY()); trans.deltaTransform(p3, result); minX = Math.min(minX, result.getX()); maxX = Math.max(maxX, result.getX()); minY = Math.min(minY, result.getY()); maxY = Math.max(maxY, result.getY()); trans.deltaTransform(p4, result); minX = Math.min(minX, result.getX()); maxX = Math.max(maxX, result.getX()); minY = Math.min(minY, result.getY()); maxY = Math.max(maxY, result.getY()); // create the bounding rectangle to return rect = new Rectangle2D.Double(minX, minY, maxX - minX + 1, maxY - minY + 1); return rect; }
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { if (image != null && showimage) { // TODO: add ability to scale maintaining aspect ratio fitting to size of parent // TODO: Need to add not zoom all the way, but zoom to a box of aspect ratio 4/3 Graphics2D g2 = (Graphics2D) g; AffineTransform tran = new AffineTransform(1f, 0f, 0f, 1f, 0, 0); float widthscale = (float) c.getWidth() / image.getWidth(); float heightscale = (float) c.getHeight() / image.getHeight(); switch (drawmode) { case DRAW_MODE_ASPECT: float scale; if (widthscale < heightscale) { scale = widthscale; } else { scale = heightscale; } tran.scale(scale, scale); g2.drawImage( image, new AffineTransformOp(tran, AffineTransformOp.TYPE_BILINEAR), (int) (c.getWidth() - image.getWidth() * scale) / 2, (int) (c.getHeight() - image.getHeight() * scale) / 2); break; case DRAW_MODE_WIDTH: tran.scale(widthscale, widthscale); g2.drawImage(image, tran, null); break; case DRAW_MODE_HEIGHT: tran.scale(heightscale, heightscale); g2.drawImage(image, tran, null); break; default: tran.scale(widthscale, heightscale); g2.drawImage(image, tran, null); break; } } }