//============================================================================= // Copyright 2006-2010 Daniel W. Dyer // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //============================================================================= package org.uncommons.watchmaker.examples.monalisa; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.util.List; import javax.swing.JComponent; import org.uncommons.watchmaker.framework.interactive.Renderer; /** * Converts a {@link BufferedImage} to a {@link JComponent} that displays that image * alongside a pre-specified target image. * @author Daniel Dyer */ public class PolygonImageSwingRenderer implements Renderer<List<ColouredPolygon>, JComponent> { private final BufferedImage targetImage; private final Renderer<List<ColouredPolygon>, BufferedImage> delegate; /** * @param targetImage This image is displayed on the left side of the * JComponent. */ public PolygonImageSwingRenderer(BufferedImage targetImage) { // Convert the target image into the most efficient format for rendering. this.targetImage = new BufferedImage(targetImage.getWidth(), targetImage.getHeight(), BufferedImage.TYPE_INT_RGB); this.targetImage.getGraphics().drawImage(targetImage, 0, 0, null); this.targetImage.setAccelerationPriority(1); this.delegate = new PolygonImageRenderer(new Dimension(targetImage.getWidth(), targetImage.getHeight()), true, // Anti-alias. null); } /** * Renders the specified image as a JComponent with the image on the * right and the pre-specified target image on the left. * @param entity The image to render on the right side of the component. * @return A Swing component that displays the rendered image. */ public JComponent render(List<ColouredPolygon> entity) { return new ImageComponent(entity); } /** * Swing component for rendering a fixed size image. If the image is smaller * than the component, it is centered. */ private final class ImageComponent extends JComponent { private static final int GAP = 10; private static final int FOOTER = 20; private final List<ColouredPolygon> candidate; private final Dimension minimumSize; ImageComponent(List<ColouredPolygon> candidate) { this.candidate = candidate; this.minimumSize = new Dimension(targetImage.getWidth() * 2 + GAP, targetImage.getHeight() + FOOTER); } @Override public Dimension getPreferredSize() { return minimumSize; } @Override public Dimension getMinimumSize() { return minimumSize; } @Override protected void paintComponent(Graphics graphics) { int x = Math.max(0, (getWidth() - minimumSize.width) / 2); int y = Math.max(0, (getHeight() - minimumSize.height) / 2); graphics.drawImage(targetImage, x, y, this); BufferedImage candidateImage = delegate.render(candidate); candidateImage.setAccelerationPriority(1); Graphics clip = graphics.create(x + targetImage.getWidth() + GAP, y, candidateImage.getWidth(), candidateImage.getHeight() + FOOTER); clip.drawImage(candidateImage, 0, 0, this); clip.setColor(getForeground()); String info = candidate.size() + " polygons, " + countVertices(candidate) + " vertices"; FontMetrics fontMetrics = clip.getFontMetrics(); int width = fontMetrics.stringWidth(info); int height = Math.round(fontMetrics.getLineMetrics(info, clip).getHeight()); clip.drawString(info, candidateImage.getWidth() - width, candidateImage.getHeight() + height); } /** * Count the number of vertices in each polygon in the image and return * the total. * @param image The image to inspect. * @return The total number of vertices in all polygons in the image. */ private int countVertices(List<ColouredPolygon> image) { int count = 0; for (ColouredPolygon polygon : image) { count += polygon.getVertices().size(); } return count; } } }