001: package com.vividsolutions.jump.workbench.imagery.mrsid;
002:
003: /*
004: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
005: * for visualizing and manipulating spatial features with geometry and attributes.
006: *
007: * Copyright (C) 2003 Vivid Solutions
008: *
009: * This program is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU General Public License
011: * as published by the Free Software Foundation; either version 2
012: * of the License, or (at your option) any later version.
013: *
014: * This program is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
017: * GNU General Public License for more details.
018: *
019: * You should have received a copy of the GNU General Public License
020: * along with this program; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
022: *
023: * For more information, contact:
024: *
025: * Vivid Solutions
026: * Suite #1A
027: * 2328 Government Street
028: * Victoria BC V8T 5G5
029: * Canada
030: *
031: * (250)385-6040
032: * www.vividsolutions.com
033: */
034: /*
035: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
036: * for visualizing and manipulating spatial features with geometry and attributes.
037: *
038: * JUMP is Copyright (C) 2003 Vivid Solutions
039: *
040: * This program implements extensions to JUMP and is
041: * Copyright (C) 2004 Integrated Systems Analysts, Inc.
042: *
043: * This program is free software; you can redistribute it and/or
044: * modify it under the terms of the GNU General Public License
045: * as published by the Free Software Foundation; either version 2
046: * of the License, or (at your option) any later version.
047: *
048: * This program is distributed in the hope that it will be useful,
049: * but WITHOUT ANY WARRANTY; without even the implied warranty of
050: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
051: * GNU General Public License for more details.
052: *
053: * You should have received a copy of the GNU General Public License
054: * along with this program; if not, write to the Free Software
055: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
056: *
057: * For more information, contact:
058: *
059: * Integrated Systems Analysts, Inc.
060: * 630C Anchors St., Suite 101
061: * Fort Walton Beach, Florida 32548
062: * USA
063: *
064: * (850)862-7321
065: * www.ashs.isa.com
066: */
067: import java.awt.AlphaComposite;
068: import java.awt.Graphics2D;
069: import java.awt.RenderingHints;
070: import java.awt.image.BufferedImage;
071: import java.io.File;
072:
073: import javax.imageio.ImageIO;
074: import javax.imageio.ImageReader;
075: import javax.imageio.stream.FileImageInputStream;
076:
077: import com.vividsolutions.jts.geom.Envelope;
078: import com.vividsolutions.jump.JUMPException;
079: import com.vividsolutions.jump.feature.Feature;
080: import com.vividsolutions.jump.workbench.imagery.ReferencedImage;
081: import com.vividsolutions.jump.workbench.ui.Viewport;
082:
083: public class MrSIDReferencedImage implements ReferencedImage {
084:
085: private SIDInfo sidInfo;
086: private String sidFilename;
087:
088: public MrSIDReferencedImage(SIDInfo info, String sidFilename) {
089: this .sidInfo = info;
090: this .sidFilename = sidFilename;
091: }
092:
093: public Envelope getEnvelope() {
094:
095: double xm = sidInfo.getUpperLeftX();
096: double xM = sidInfo.getUpperLeftX()
097: + (sidInfo.getPixelWidth() * sidInfo.getXRes());
098: double yM = sidInfo.getUpperLeftY()
099: + (sidInfo.getPixelHeight() * sidInfo.getYRes());
100: double ym = sidInfo.getUpperLeftY();
101:
102: return new Envelope(xm, xM, ym, yM);
103: }
104:
105: public void paint(Feature f, Graphics2D g, Viewport viewport)
106: throws JUMPException {
107:
108: //view and panel refer to the workbench portion with which the user is interacting
109: //raster refers to the visible portion of the SID file drawn onto the view panel
110: //image refers to the created image onto which is drawn the raster extracted from the SID file
111:
112: if (sidInfo == null) {
113: viewport.getPanel().getContext().setStatusMessage(
114: "Could not get SID info for " + sidFilename);
115: } else {
116: int sidPixelWidth = sidInfo.getPixelWidth();
117: int sidPixelHeight = sidInfo.getPixelHeight();
118: double sid_xres = sidInfo.getXRes();
119: double sid_ulx = sidInfo.getUpperLeftX(); //realworld coords
120: double sid_uly = sidInfo.getUpperLeftY(); //realworld coords
121:
122: int image_x = 0; //x position of raster in final image in pixels
123: int image_y = 0; //y position of raster in final image in pixels
124: int image_w = viewport.getPanel().getWidth(); //width of raster in final image in pixels
125: int image_h = viewport.getPanel().getHeight(); //height of raster in final image in pixels
126:
127: Envelope vpEnvelope = viewport
128: .getEnvelopeInModelCoordinates();
129: double view_res = 1 / viewport.getScale(); //panel resolution
130: double rwViewLeft = vpEnvelope.getMinX();
131: double rwViewRight = vpEnvelope.getMaxX();
132: double rwViewTop = vpEnvelope.getMaxY();
133: double rwViewBot = vpEnvelope.getMinY();
134: //java.awt.Toolkit.getDefaultToolkit().beep();
135:
136: //Here calculate the real world sid edges for level zero.
137: //These will be recalculated for the final level later in the code
138: //since the real world edges will walk away from the original edges
139: //as we go to higher levels.
140: //see paper on Georeferencing images.
141: double halfPixel = 0.5 * sid_xres;
142: double rwSidFileLeftEdge = sid_ulx - halfPixel;
143: double rwSidFileRightEdge = rwSidFileLeftEdge
144: + (sidPixelWidth * sid_xres);
145: double rwSidFileTopEdge = sid_uly + halfPixel;
146: double rwSidFileBotEdge = rwSidFileTopEdge
147: - (sidPixelHeight * sid_xres);
148:
149: double rwRasterLeft = Math.max(rwViewLeft,
150: rwSidFileLeftEdge);
151: double rwRasterRight = Math.min(rwViewRight,
152: rwSidFileRightEdge);
153: double rwRasterTop = Math.min(rwViewTop, rwSidFileTopEdge);
154: double rwRasterBot = Math.max(rwViewBot, rwSidFileBotEdge);
155:
156: //calculate the sid level which will return the number of pixels
157: //that is closest to the number of view pixels so that we can
158: //minimize the amount of needed stretching to make the file fit the view.
159: double rwViewWidth = rwViewRight - rwViewLeft;
160: double widthInFilePixels = rwViewWidth / sid_xres; //file pixels
161: double widthInViewPixels = rwViewWidth / view_res; //view pixels
162: int sidLevel = (int) Math.round(Math.log(widthInFilePixels
163: / widthInViewPixels)
164: / Math.log(2));
165: if (sidLevel < 0)
166: sidLevel = 0;
167: if (sidLevel > sidInfo.getNumLevels())
168: sidLevel = sidInfo.getNumLevels();
169: double lvlres = sid_xres * Math.pow(2, sidLevel);
170: viewport.getPanel().getContext().setStatusMessage(
171: "MrSID " + sidLevel + " OF "
172: + sidInfo.getNumLevels());
173:
174: //calculate the number of pixels at this level
175: int lvl = 0;
176: int sidLvlPixelWidth = sidPixelWidth;
177: int sidLvlPixelHeight = sidPixelHeight;
178:
179: while (lvl < sidLevel) {
180: sidLvlPixelWidth = round(0.5 * sidLvlPixelWidth);
181: sidLvlPixelHeight = round(0.5 * sidLvlPixelHeight);
182: lvl++;
183: }
184:
185: //now calculate the real world edges of the sid file at this level
186: halfPixel = 0.5 * lvlres;
187: rwSidFileLeftEdge = sid_ulx - halfPixel;
188: rwSidFileRightEdge = rwSidFileLeftEdge
189: + (sidLvlPixelWidth * lvlres);
190: rwSidFileTopEdge = sid_uly + halfPixel;
191: rwSidFileBotEdge = rwSidFileTopEdge
192: - (sidLvlPixelHeight * lvlres);
193:
194: //check to see if this sid is inside the view area
195: if (!((rwSidFileRightEdge <= rwViewLeft)
196: || (rwSidFileLeftEdge >= rwViewRight)
197: || (rwSidFileTopEdge <= rwViewBot) || (rwSidFileBotEdge >= rwViewTop))) {
198: int sidLeftPixel = (int) ((rwRasterLeft - rwSidFileLeftEdge) / lvlres); //trunc
199: int sidRightPixel = (int) ((rwRasterRight - rwSidFileLeftEdge) / lvlres); //trunc
200: if (sidRightPixel == sidLvlPixelWidth)
201: sidRightPixel = sidLvlPixelWidth - 1;
202: int sidTopPixel = (int) ((rwSidFileTopEdge - rwRasterTop) / lvlres); //trunc
203: int sidBotPixel = (int) ((rwSidFileTopEdge - rwRasterBot) / lvlres); //trunc
204: if (sidBotPixel == sidLvlPixelHeight)
205: sidBotPixel = sidLvlPixelHeight - 1;
206:
207: double rwSidLeft = rwSidFileLeftEdge
208: + (sidLeftPixel * lvlres);
209: double rwSidRight = rwSidFileLeftEdge
210: + (sidRightPixel * lvlres) + lvlres;
211: double rwSidTop = rwSidFileTopEdge
212: - (sidTopPixel * lvlres);
213: double rwSidBot = rwSidFileTopEdge
214: - (sidBotPixel * lvlres) - lvlres;
215:
216: int leftOffset = round((rwRasterLeft - rwSidLeft)
217: / view_res);
218: int rightOffset = round((rwSidRight - rwRasterRight)
219: / view_res);
220: int topOffset = round((rwSidTop - rwRasterTop)
221: / view_res);
222: int botOffset = round((rwRasterBot - rwSidBot)
223: / view_res);
224:
225: int sid_x = sidLeftPixel;
226: int sid_y = sidTopPixel;
227:
228: int sid_w = sidRightPixel - sidLeftPixel + 1;
229: if (sid_w <= 0)
230: sid_w = 1;
231:
232: int sid_h = sidBotPixel - sidTopPixel + 1;
233: if (sid_h <= 0)
234: sid_h = 1;
235:
236: image_x = round(rwRasterLeft / view_res)
237: - round(rwViewLeft / view_res);
238: image_w = round(rwRasterRight / view_res)
239: - round(rwRasterLeft / view_res);
240: if (image_w <= 0)
241: image_w = 1;
242:
243: image_y = round(rwViewTop / view_res)
244: - round(rwRasterTop / view_res);
245: image_h = round(rwRasterTop / view_res)
246: - round(rwRasterBot / view_res);
247: if (image_h <= 0)
248: image_h = 1;
249:
250: image_x -= leftOffset;
251: image_y -= topOffset;
252: image_w += (leftOffset + rightOffset);
253: image_h += (topOffset + botOffset);
254:
255: try {
256: File jpgFile = File.createTempFile("Temp", ".jpg");
257: String jpgFilename = jpgFile.getCanonicalPath();
258:
259: String[] runStr = { MrSIDImageFactory.MRSIDDECODE,
260: "-i", sidFilename, "-s", "" + sidLevel,
261: "-ulxy", "" + sid_x, "" + sid_y, "-wh",
262: "" + sid_w, "" + sid_h, "-o", jpgFilename,
263: "-jpg", "-quiet", "-coord", "image" };
264:
265: Process p = Runtime.getRuntime().exec(runStr);
266: p.waitFor();
267: p.destroy();
268:
269: if (((jpgFile.exists()) && (jpgFile.isFile()) && (jpgFile
270: .canRead()))) {
271: //-- [sstein 02.04.2006] changed to javax to work with free JavaVM
272: // as proposed by Petter Reinholdtsen (see jpp-devel 12.03.2006)
273: FileImageInputStream in = new FileImageInputStream(
274: new File(jpgFilename));
275: ImageReader decoder = (ImageReader) ImageIO
276: .getImageReadersByFormatName("JPEG")
277: .next();
278: decoder.setInput(in);
279: BufferedImage image = decoder.read(0);
280: decoder.dispose();
281: in.close();
282:
283: if (!sidInfo.getColorSpace()
284: .equals("GREYSCALE")) {
285: RenderingHints rh = new RenderingHints(
286: RenderingHints.KEY_INTERPOLATION,
287: RenderingHints.VALUE_INTERPOLATION_BILINEAR);
288: g.setRenderingHints(rh);
289: }
290:
291: g.setComposite(AlphaComposite.Src);
292: g.drawImage(image, image_x, image_y, image_w,
293: image_h, viewport.getPanel());
294: new File(jpgFilename).delete(); //so they don't accumulate in the tmp dir
295: }
296:
297: } catch (Throwable t) {
298: throw new JUMPException(t.getMessage());
299: }
300: }
301: }
302: }
303:
304: private int round(double num) {
305: return (int) Math.round(num);
306: }
307:
308: public String getType() {
309: return "MrSID";
310: }
311:
312: }
|