package com.vividsolutions.jump.workbench.imagery.mrsid; /* * 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.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.io.File; import javax.imageio.ImageIO; import javax.imageio.ImageReader; import javax.imageio.stream.FileImageInputStream; import javax.media.jai.RenderedOp; import javax.media.jai.operator.FileLoadDescriptor; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jump.JUMPException; import com.vividsolutions.jump.feature.Feature; import com.vividsolutions.jump.workbench.imagery.ReferencedImage; import com.vividsolutions.jump.workbench.ui.Viewport; public class MrSIDReferencedImage implements ReferencedImage{ private SIDInfo sidInfo; private String sidFilename; public MrSIDReferencedImage(SIDInfo info, String sidFilename) { this.sidInfo = info; this.sidFilename = sidFilename; } public Envelope getEnvelope() { double xm = sidInfo.getUpperLeftX(); double xM = sidInfo.getUpperLeftX()+(sidInfo.getPixelWidth() * sidInfo.getXRes()); double yM = sidInfo.getUpperLeftY()+(sidInfo.getPixelHeight() * sidInfo.getYRes()); double ym = sidInfo.getUpperLeftY(); return new Envelope(xm, xM, ym, yM); } public void paint(Feature f, Graphics2D g, Viewport viewport) throws JUMPException { //view and panel refer to the workbench portion with which the user is interacting //raster refers to the visible portion of the SID file drawn onto the view panel //image refers to the created image onto which is drawn the raster extracted from the SID file if (sidInfo == null) { viewport.getPanel().getContext().setStatusMessage("Could not get SID info for " + sidFilename); } else { int sidDRmin = 0; //LDB: added int sidDRmax = 255; //LDB: added int sidPixelWidth = sidInfo.getPixelWidth(); int sidPixelHeight = sidInfo.getPixelHeight(); double sid_xres = sidInfo.getXRes(); double sid_ulx = sidInfo.getUpperLeftX(); //realworld coords double sid_uly = sidInfo.getUpperLeftY(); //realworld coords 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(); //java.awt.Toolkit.getDefaultToolkit().beep(); //Here calculate the real world sid edges for level zero. //These will be recalculated for the final level later in the code //since the real world edges will walk away from the original edges //as we go to higher levels. //see paper on Georeferencing images. double halfPixel = 0.5 * sid_xres; double rwSidFileLeftEdge = sid_ulx - halfPixel; double rwSidFileRightEdge = rwSidFileLeftEdge + (sidPixelWidth * sid_xres); double rwSidFileTopEdge = sid_uly + halfPixel; double rwSidFileBotEdge = rwSidFileTopEdge - (sidPixelHeight * sid_xres); double rwRasterLeft = Math.max(rwViewLeft, rwSidFileLeftEdge); double rwRasterRight = Math.min(rwViewRight, rwSidFileRightEdge); double rwRasterTop = Math.min(rwViewTop, rwSidFileTopEdge); double rwRasterBot = Math.max(rwViewBot, rwSidFileBotEdge); //calculate the sid level which will return the number of pixels //that is closest to the number of view pixels so that we can //minimize the amount of needed stretching to make the file fit the view. double rwViewWidth = rwViewRight - rwViewLeft; double widthInFilePixels = rwViewWidth / sid_xres; //file pixels double widthInViewPixels = rwViewWidth / view_res; //view pixels int sidLevel = (int)Math.round(Math.log(widthInFilePixels / widthInViewPixels) / Math.log(2)); if (sidLevel < 0) sidLevel = 0; if (sidLevel > sidInfo.getNumLevels()) sidLevel = sidInfo.getNumLevels(); double lvlres = sid_xres * Math.pow(2, sidLevel); viewport.getPanel().getContext().setStatusMessage("MrSID " + sidLevel + " OF " + sidInfo.getNumLevels()); //calculate the number of pixels at this level int lvl = 0; int sidLvlPixelWidth = sidPixelWidth; int sidLvlPixelHeight = sidPixelHeight; while (lvl < sidLevel) { sidLvlPixelWidth = round(0.5 * sidLvlPixelWidth); sidLvlPixelHeight = round(0.5 * sidLvlPixelHeight); lvl++; } //now calculate the real world edges of the sid file at this level halfPixel = 0.5 * lvlres; rwSidFileLeftEdge = sid_ulx - halfPixel; rwSidFileRightEdge = rwSidFileLeftEdge + (sidLvlPixelWidth * lvlres); rwSidFileTopEdge = sid_uly + halfPixel; rwSidFileBotEdge = rwSidFileTopEdge - (sidLvlPixelHeight * lvlres); //check to see if this sid is inside the view area if (!((rwSidFileRightEdge <= rwViewLeft) || (rwSidFileLeftEdge >= rwViewRight) || (rwSidFileTopEdge <= rwViewBot) || (rwSidFileBotEdge >= rwViewTop))) { int sidLeftPixel = (int)((rwRasterLeft - rwSidFileLeftEdge) / lvlres); //trunc int sidRightPixel = (int)((rwRasterRight - rwSidFileLeftEdge) / lvlres); //trunc if (sidRightPixel == sidLvlPixelWidth) sidRightPixel = sidLvlPixelWidth - 1; int sidTopPixel = (int)((rwSidFileTopEdge - rwRasterTop) / lvlres); //trunc int sidBotPixel = (int)((rwSidFileTopEdge - rwRasterBot) / lvlres); //trunc if (sidBotPixel == sidLvlPixelHeight) sidBotPixel = sidLvlPixelHeight - 1; double rwSidLeft = rwSidFileLeftEdge + (sidLeftPixel * lvlres); double rwSidRight = rwSidFileLeftEdge + (sidRightPixel * lvlres) + lvlres; double rwSidTop = rwSidFileTopEdge - (sidTopPixel * lvlres); double rwSidBot = rwSidFileTopEdge - (sidBotPixel * lvlres) - lvlres; int leftOffset = round((rwRasterLeft - rwSidLeft) / view_res); int rightOffset = round((rwSidRight - rwRasterRight) / view_res); int topOffset = round((rwSidTop - rwRasterTop) / view_res); int botOffset = round((rwRasterBot - rwSidBot) / view_res); int sid_x = sidLeftPixel; int sid_y = sidTopPixel; int sid_w = sidRightPixel - sidLeftPixel + 1; if (sid_w <= 0) sid_w = 1; int sid_h = sidBotPixel - sidTopPixel + 1; if (sid_h <= 0) sid_h = 1; 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); try { File jpgDir = new File(MrSIDImageFactory.TMP_PATH); File jpgFile = File.createTempFile("Temp", ".jpg", jpgDir); String jpgFilename = jpgFile.getCanonicalPath(); String [] runStr = { MrSIDImageFactory.MRSIDDECODE, //"C:\\ashsii\\jump\\etc\\mrsidgeodecode.exe", "-i", sidFilename, "-s", "" + sidLevel, "-ulxy", "" + sid_x, "" + sid_y, "-wh", "" + sid_w, "" + sid_h, "-o", jpgFilename, "-jpg", "-quiet", "-coord", "image", "-drmin", ""+sidDRmin, "-drmax", ""+sidDRmax }; Process p = Runtime.getRuntime().exec(runStr); p.waitFor(); p.destroy(); //--[sstein 03.Mai.2008] note: I checked, that until here everything is fine (i.e. the jpg image correctly created) // with respect to creating a jpg file out of the sid image and store it in the tmp folder if (((jpgFile.exists()) && (jpgFile.isFile()) && (jpgFile.canRead()))) { //-- [sstein 3.Mai.2008] old stuff /* //-- [sstein 02.04.2006] changed to javax to work with free JavaVM // as proposed by Petter Reinholdtsen (see jpp-devel 12.03.2006) FileImageInputStream in = new FileImageInputStream(new File(jpgFilename)); ImageReader decoder = (ImageReader) ImageIO.getImageReadersByFormatName("JPEG").next(); decoder.setInput(in); BufferedImage image = decoder.read(0); decoder.dispose(); in.close(); if (!sidInfo.getColorSpace().equals("GREYSCALE")) { RenderingHints rh = new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.setRenderingHints(rh); } g.setComposite(AlphaComposite.Src); g.drawImage(image, image_x, image_y, image_w, image_h, viewport.getPanel()); new File(jpgFilename).delete(); //so they don't accumulate in the tmp dir */ //--- [sstein 3.Mai.2008] new stuff (note: the grey values are a bit different now: lighter) RenderedOp image = FileLoadDescriptor.create(jpgFile.getPath(),null,null,null); RenderingHints rh = new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g.setRenderingHints(rh); Composite composite = g.getComposite(); g.setComposite(AlphaComposite.Src); BufferedImage img = image.getAsBufferedImage(); g.drawImage(img, image_x, image_y, image_w, image_h, viewport.getPanel()); g.setComposite(composite); //-- testing, since some files are not deleted properly boolean done = false; //int count=0; //while (!done){ done = jpgFile.delete(); //so they don't accumulate in the tmp dir //count++; //System.out.print("."); //if (count == 1000){ //done = true; if (!done){jpgFile.delete();} if (!done){jpgFile.deleteOnExit();} //System.out.print("not deleted in 1000 rounds"); //} //} //System.out.println(""); } } catch (Throwable t) { t.printStackTrace(); throw new JUMPException(t.getMessage()); } } } } private int round(double num) { return (int)Math.round(num); } public String getType() { return "MrSID"; } }