package com.vividsolutions.jump.workbench.imagery.graphic; /* * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI * for visualizing and manipulating spatial features with geometry and attributes. * * Copyright (C) 2003 Vivid Solutions * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * For more information, contact: * * Vivid Solutions * Suite #1A * 2328 Government Street * Victoria BC V8T 5G5 * Canada * * (250)385-6040 * www.vividsolutions.com */ /* * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI * for visualizing and manipulating spatial features with geometry and attributes. * * JUMP is Copyright (C) 2003 Vivid Solutions * * This program implements extensions to JUMP and is * Copyright (C) 2004 Integrated Systems Analysts, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * For more information, contact: * * Integrated Systems Analysts, Inc. * 630C Anchors St., Suite 101 * Fort Walton Beach, Florida 32548 * USA * * (850)862-7321 * www.ashs.isa.com */ import java.awt.AlphaComposite; import java.awt.Composite; import java.awt.RenderingHints; import java.io.File; import javax.media.jai.RenderedOp; import javax.media.jai.operator.FileLoadDescriptor; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jump.feature.Feature; import com.vividsolutions.jump.workbench.imagery.ReferencedImage; import com.vividsolutions.jump.workbench.ui.Viewport; /** * An image whose source is a bitmap * * Much of this code was donated by Larry Becker and Robert Littlefield of Integrated Systems Analysts, Inc. */ public class GraphicImage implements ReferencedImage { private File file; private WorldFile wf; private boolean initialload; private Envelope env; private String type = null; public GraphicImage(File file, WorldFile wf) { this.wf = wf; this.file = file; this.initialload = true; if(wf == null) this.wf = WorldFile.DEFAULT; int i = file.getName().lastIndexOf("."); if(i>-1 && i<file.getName().length()){ type = file.getName().substring(i+1).toUpperCase(); }else{ type = file.getName(); } } public Envelope getEnvelope(){ if(env == null) env = computeEnvelope(); return env; } private Envelope computeEnvelope() { double xm,xM, ym,yM; RenderedOp image = null; if(file.exists() && file.isFile() && file.canRead()){ image = FileLoadDescriptor.create(file.getPath(),null,null,null); }else{ return new Envelope(); } xm = 0; xM = image.getWidth() * wf.getXSize(); ym = 0; yM = image.getHeight() * wf.getYSize(); xm = xm+wf.getXUpperLeft(); xM = xM+wf.getXUpperLeft(); ym = ym+wf.getYUpperLeft(); yM = yM+wf.getYUpperLeft(); return new Envelope(xm, xM, ym, yM ); } // public void paint(Feature f, java.awt.Graphics2D g, Viewport viewport) // { // // update the control frame, in case it has changed // // AffineTransform originalTransform; // originalTransform = g.getTransform(); // try { // transformByBaseline(g, viewport, (new GeometryFactory()).toGeometry(getEnvelope())); // //transformGraphics(g, viewport, env); // g.drawImage(image, 0, 0, null); // } // finally { // g.setTransform(originalTransform); // } // } // // private void transformByBaseline(java.awt.Graphics2D g, Viewport viewport, Geometry geom) // { // Coordinate[] pts = geom.getCoordinates(); // Coordinate anchorPt = pts[0]; // Coordinate controlPt = pts[1]; // // // scale // double frameSize = anchorPt.distance(controlPt); // double imageWorldScale = frameSize/image.getWidth(null); // double imageViewScale = viewport.getScale() * imageWorldScale; // g.scale(imageViewScale, imageViewScale); // // // translate // double maxYWorld = imageWorldScale * image.getHeight(null); // Coordinate topLeftWorld = new Coordinate(anchorPt.x, anchorPt.y + maxYWorld); // Point2D topLeftView = null; // try { // topLeftView = viewport.toViewPoint(topLeftWorld); // } catch(java.awt.geom.NoninvertibleTransformException e) { // e.printStackTrace(); // } // g.translate(topLeftView.getX()/imageViewScale, topLeftView.getY()/imageViewScale); // // // rotate // double dx = controlPt.x - anchorPt.x; // double dy = controlPt.y - anchorPt.y; // double theta = Math.atan2(dy, dx); // g.rotate(-theta, 0.0, image.getHeight(null)); // // // } public void paint(Feature f, java.awt.Graphics2D g, Viewport viewport){ // BufferedImage image = null; // if (((jpgFile.exists()) && (jpgFile.isFile()) && (jpgFile.canRead()))) // { // FileInputStream in = new FileInputStream(jpgFilename); // JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(in); // image = decoder.decodeAsBufferedImage(); // jpg_colorspace = decoder.getJPEGDecodeParam().getEncodedColorID(); // in.close(); // } // else // { // return; // } RenderedOp image = null; if(file.exists() && file.isFile() && file.canRead()){ image = FileLoadDescriptor.create(file.getPath(),null,null,null); }else{ return; } int jpgPixelWidth = image.getWidth(); int jpgPixelHeight = image.getHeight(); // Use features internal envelope for upper left coordinates [Ed Deen : Dec 1, 2006] // Note: This solves the problem where the user moves the image but only the bounding box moves ... a default worldfile // variable was anchoring it. Now, use the World File (if it exists) only on the initial load of the image. // TODO: Add these world file attributes into the actual image feature. Then copy the world file information into // the feature at load and extract the following information always from the feature. // This will allow for sizing the images, sizing to fit, etc, etc. // and later the ability to write the actual World File out for // future referencing. [Ed Deen : Dec 1, 2006] // Note: Will also need to add the jpg_yres support as well, rotation, etc. double jpg_xres = wf.getXSize(); // Default wf.Xsize is always 1.0 double jpg_ulx = f.getGeometry().getEnvelopeInternal().getMinX(); double jpg_uly = f.getGeometry().getEnvelopeInternal().getMaxY(); // Check for initial load if (this.initialload == true) { // If Initial Load; check if World File exists if (wf.getFilename() != null) { // If World File exists then use worldfile for initial upper left coordinates jpg_xres = wf.getXSize(); jpg_ulx = wf.getXUpperLeft(); //realworld coords jpg_uly = wf.getYUpperLeft(); //realworld coords } // Set Inital Load to false this.initialload = false; } int image_x = 0; //x position of raster in final image in pixels int image_y = 0; //y position of raster in final image in pixels int image_w = viewport.getPanel().getWidth(); //width of raster in final image in pixels int image_h = viewport.getPanel().getHeight(); //height of raster in final image in pixels Envelope vpEnvelope = viewport.getEnvelopeInModelCoordinates(); double view_res = 1 / viewport.getScale(); //panel resolution double rwViewLeft = vpEnvelope.getMinX(); double rwViewRight = vpEnvelope.getMaxX(); double rwViewTop = vpEnvelope.getMaxY(); double rwViewBot = vpEnvelope.getMinY(); //Here calculate the real world jpg edges. //NOTE: world file coordinates are center of pixels double halfPixel = 0.5 * jpg_xres; double rwJpgFileLeftEdge = jpg_ulx - halfPixel; double rwJpgFileRightEdge = rwJpgFileLeftEdge + (jpgPixelWidth * jpg_xres); double rwJpgFileTopEdge = jpg_uly + halfPixel; double rwJpgFileBotEdge = rwJpgFileTopEdge - (jpgPixelHeight * jpg_xres); double rwRasterLeft = Math.max(rwViewLeft, rwJpgFileLeftEdge); double rwRasterRight = Math.min(rwViewRight, rwJpgFileRightEdge); double rwRasterTop = Math.min(rwViewTop, rwJpgFileTopEdge); double rwRasterBot = Math.max(rwViewBot, rwJpgFileBotEdge); //check to see if this jpg is inside the view area if (!((rwJpgFileRightEdge <= rwViewLeft) || (rwJpgFileLeftEdge >= rwViewRight) || (rwJpgFileTopEdge <= rwViewBot) || (rwJpgFileBotEdge >= rwViewTop))) { //calculate which pixels in the jpg file fit inside the view int jpgLeftPixel = (int)((rwRasterLeft - rwJpgFileLeftEdge) / jpg_xres); //trunc int jpgRightPixel = (int)((rwRasterRight - rwJpgFileLeftEdge) / jpg_xres); //trunc if (jpgRightPixel == jpgPixelWidth) jpgRightPixel = jpgPixelWidth - 1; int jpgTopPixel = (int)((rwJpgFileTopEdge - rwRasterTop) / jpg_xres); //trunc int jpgBotPixel = (int)((rwJpgFileTopEdge - rwRasterBot) / jpg_xres); //trunc if (jpgBotPixel == jpgPixelHeight) jpgBotPixel = jpgPixelHeight - 1; //calculate the real world coords of the included pixels double rwJpgLeft = rwJpgFileLeftEdge + (jpgLeftPixel * jpg_xres); double rwJpgRight = rwJpgFileLeftEdge + (jpgRightPixel * jpg_xres) + jpg_xres; double rwJpgTop = rwJpgFileTopEdge - (jpgTopPixel * jpg_xres); double rwJpgBot = rwJpgFileTopEdge - (jpgBotPixel * jpg_xres) - jpg_xres; //calculate the pixel offset on the panel of the included portion of the jpg file int leftOffset = round((rwRasterLeft - rwJpgLeft) / view_res); int rightOffset = round((rwJpgRight - rwRasterRight) / view_res); int topOffset = round((rwJpgTop - rwRasterTop) / view_res); int botOffset = round((rwRasterBot - rwJpgBot) / view_res); image_x = round(rwRasterLeft / view_res) - round(rwViewLeft / view_res); image_w = round(rwRasterRight / view_res) - round(rwRasterLeft / view_res); if (image_w <= 0) image_w = 1; image_y = round(rwViewTop / view_res) - round(rwRasterTop / view_res); image_h = round(rwRasterTop / view_res) - round(rwRasterBot / view_res); if (image_h <= 0) image_h = 1; image_x -= leftOffset; image_y -= topOffset; image_w += (leftOffset + rightOffset); image_h += (topOffset + botOffset); RenderingHints rh = new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.setRenderingHints(rh); //parameters: destination corners then source corners //source corners are defined in terms of infinitely thin coordinates //which define the edges of the pixel space so that we have //to add 1 to the right bottom coordinate of the source rectangle //since jpgRightPixel & jpgBotPixel are defined in terms of array element position //any questions, see Java documentation for Graphics object Composite composite = g.getComposite(); g.setComposite(AlphaComposite.Src); g.drawImage(image.getAsBufferedImage(), image_x, image_y, image_x + image_w, image_y + image_h, jpgLeftPixel, jpgTopPixel, jpgRightPixel + 1, jpgBotPixel + 1, viewport.getPanel()); g.setComposite(composite); } } private int round(double num) { return (int)Math.round(num); } public String getType() { return type; } }