Source Code Cross Referenced for ArcSDERasterReader.java in  » GIS » GeoTools-2.4.1 » org » geotools » arcsde » gce » imageio » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.arcsde.gce.imageio 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    Geotools2 - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2002, Geotools Project Managment Committee (PMC)
005:         *
006:         *    This library is free software; you can redistribute it and/or
007:         *    modify it under the terms of the GNU Lesser General Public
008:         *    License as published by the Free Software Foundation;
009:         *    version 2.1 of the License.
010:         *
011:         *    This library is distributed in the hope that it will be useful,
012:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
013:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014:         *    Lesser General Public License for more details.
015:         *
016:         */
017:        package org.geotools.arcsde.gce.imageio;
018:
019:        import java.awt.Color;
020:        import java.awt.Dimension;
021:        import java.awt.Font;
022:        import java.awt.Graphics2D;
023:        import java.awt.Point;
024:        import java.awt.Rectangle;
025:        import java.awt.image.BufferedImage;
026:        import java.awt.image.WritableRaster;
027:        import java.io.IOException;
028:        import java.util.ArrayList;
029:        import java.util.HashMap;
030:        import java.util.Iterator;
031:        import java.util.logging.Level;
032:        import java.util.logging.Logger;
033:
034:        import javax.imageio.ImageReadParam;
035:        import javax.imageio.ImageReader;
036:        import javax.imageio.ImageTypeSpecifier;
037:        import javax.imageio.metadata.IIOMetadata;
038:
039:        import org.geotools.arcsde.gce.ArcSDEPyramid;
040:        import org.geotools.arcsde.gce.ArcSDEPyramidLevel;
041:        import org.geotools.arcsde.gce.band.ArcSDERasterBandCopier;
042:        import org.geotools.arcsde.pool.ArcSDEConnectionPool;
043:        import org.geotools.arcsde.pool.ArcSDEPooledConnection;
044:        import org.geotools.arcsde.pool.UnavailableArcSDEConnectionException;
045:        import org.geotools.data.DataSourceException;
046:
047:        import com.esri.sde.sdk.client.SeConnection;
048:        import com.esri.sde.sdk.client.SeException;
049:        import com.esri.sde.sdk.client.SeQuery;
050:        import com.esri.sde.sdk.client.SeRaster;
051:        import com.esri.sde.sdk.client.SeRasterAttr;
052:        import com.esri.sde.sdk.client.SeRasterBand;
053:        import com.esri.sde.sdk.client.SeRasterConstraint;
054:        import com.esri.sde.sdk.client.SeRasterTile;
055:        import com.esri.sde.sdk.client.SeRow;
056:        import com.esri.sde.sdk.client.SeSqlConstruct;
057:
058:        public class ArcSDERasterReader extends ImageReader {
059:
060:            private static final boolean DEBUG = false;
061:
062:            private static final ArrayList supportedImageTypes;
063:            static {
064:                supportedImageTypes = new ArrayList();
065:                supportedImageTypes
066:                        .add(ImageTypeSpecifier
067:                                .createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB));
068:            }
069:
070:            private final Logger LOGGER = org.geotools.util.logging.Logging
071:                    .getLogger(this .getClass().toString());
072:            private final ArcSDEPyramid _rasterPyramid;
073:            private final Dimension _tileSize;
074:            private final String _rasterTable, _rasterColumn;
075:
076:            public ArcSDERasterReader(ArcSDERasterReaderSpi parent,
077:                    ArcSDEPyramid rasterPyramid, String rasterTable,
078:                    String rasterColumn) {
079:                super (parent);
080:                _tileSize = rasterPyramid.getTileDimension();
081:                _rasterPyramid = rasterPyramid;
082:                _rasterTable = rasterTable;
083:                _rasterColumn = rasterColumn;
084:            }
085:
086:            public int getHeight(int imageIndex) throws IOException {
087:                return _rasterPyramid.getPyramidLevel(imageIndex).size.height;
088:            }
089:
090:            public int getWidth(int imageIndex) throws IOException {
091:                return _rasterPyramid.getPyramidLevel(imageIndex).size.width;
092:            }
093:
094:            public Iterator getImageTypes(int imageIndex) throws IOException {
095:                return supportedImageTypes.iterator();
096:            }
097:
098:            public int getNumImages(boolean allowSearch) throws IOException {
099:                return _rasterPyramid.getNumLevels();
100:            }
101:
102:            /**
103:             * This method is THREADSAFE.
104:             * 
105:             * Reads from its configured ArcSDE Raster "row" (one row in a raster table
106:             * corresponds to one ArcSDERasterReader) in the manner described by the
107:             * supplied ImageReadParam.
108:             * 
109:             *  @param param This must be an ArcSDERasterImageReadParam, containing a valid, live
110:             *  SeConnection through which this reader will "suck" its raster data from SDE.
111:             *  @param imageIndex This parameter specifies which image pyramid level (if there's more than one)
112:             *  to read from.  If there's only one pyramid level, this value should be 0.
113:             *  
114:             *  @throws IOException 
115:             */
116:            public BufferedImage read(int imageIndex, ImageReadParam param)
117:                    throws IOException {
118:
119:                // we only read from ArcSDERasterImageReadParams. 
120:                if (!(param instanceof  ArcSDERasterImageReadParam)) {
121:                    throw new IllegalArgumentException(
122:                            "read() must be called with an ArcSDERasterReadImageParam, not a "
123:                                    + param.getClass());
124:                }
125:                final ArcSDERasterImageReadParam sdeirp = (ArcSDERasterImageReadParam) param;
126:
127:                //double-check that all the required info is present.
128:                if (sdeirp.getSourceBands() == null) {
129:                    throw new IllegalArgumentException(
130:                            "You must provide source bands to the ArcSDERasterReader via param.setSourceBands()");
131:                }
132:                if (sdeirp.getConnection() == null) {
133:                    throw new IllegalArgumentException(
134:                            "You must provide a connection to the ArcSDERasterReader via the param.setConnection() method.");
135:                }
136:                if (sdeirp.getBandMapper() == null) {
137:                    throw new IllegalArgumentException(
138:                            "You must provide a hashmap bandmapper to the ArcSDERasterReader via the param.setBandMapper() method");
139:                }
140:
141:                // start collecting our background information for doing the read.
142:
143:                // the source region is the actual pixel extent of this particar pyramid layer
144:                final Rectangle sourceRegion = param.getSourceRegion();
145:
146:                final ArcSDEPyramidLevel curLevel = _rasterPyramid
147:                        .getPyramidLevel(imageIndex);
148:
149:                // if we're reading "off the top" or "off the left" side of the image, then there's some "blank" part of
150:                // the returned image that we need to leave blank.  This offset tells us where to start writing into the
151:                // destination image in that case.  (Note, if we're reading "off the bottom" or "off the right" side of
152:                // the image, this doesn't affect us as we just stop writing at the end of the tile and the rest is
153:                // left blank automatically).
154:                final Point destOffset = param.getDestinationOffset() == null ? new Point(
155:                        0, 0)
156:                        : param.getDestinationOffset();
157:                if (curLevel.getXOffset() != 0) {
158:                    sourceRegion.x += curLevel.getXOffset();
159:                }
160:                if (curLevel.getYOffset() != 0) {
161:                    if (LOGGER.isLoggable(Level.FINER))
162:                        LOGGER.finer("y-axis is offset by "
163:                                + curLevel.getYOffset()
164:                                + " at SDE pyramid level "
165:                                + curLevel.getLevel());
166:                    sourceRegion.y += curLevel.getYOffset();
167:                }
168:
169:                // the destination image for our eventual raster read.  Can be provided (if the given one is non-null)
170:                // or we can be expected to generate it (if the given one is null)
171:                BufferedImage destination = param.getDestination();
172:                if (destination == null
173:                        && (destOffset.x == 0 && destOffset.y == 0)) {
174:                    destination = new BufferedImage(sourceRegion.width,
175:                            sourceRegion.height, BufferedImage.TYPE_INT_ARGB);
176:                } else if (destination == null) {
177:                    final int imageWidth = destOffset.x + sourceRegion.width;
178:                    final int imageHeight = destOffset.y + sourceRegion.height;
179:                    destination = new BufferedImage(imageWidth, imageHeight,
180:                            BufferedImage.TYPE_INT_ARGB);
181:                } else if (destination != null
182:                        && !(destOffset.x == 0 && destOffset.y == 0)) {
183:                    int destWidth = sourceRegion.width, destHeight = sourceRegion.height;
184:                    if (destOffset.x + sourceRegion.width > destination
185:                            .getWidth())
186:                        destWidth = destination.getWidth() - destOffset.x;
187:                    if (destOffset.y + sourceRegion.height > destination
188:                            .getHeight())
189:                        destHeight = destination.getHeight() - destOffset.y;
190:                    destination = destination.getSubimage(destOffset.x,
191:                            destOffset.y, destWidth, destHeight);
192:                } else {
193:                    //we've got a non-null destination image and there's no offset.  Nothing to do!
194:                }
195:
196:                // figure out which tiles exactly, we'll be fetching
197:                final int minTileX = sourceRegion.x / _tileSize.width;
198:                final int minTileY = sourceRegion.y / _tileSize.height;
199:                if (LOGGER.isLoggable(Level.FINER))
200:                    LOGGER.finer("figured minTiles: " + minTileX + ","
201:                            + minTileY + ".  Image is "
202:                            + curLevel.getNumTilesWide() + "x"
203:                            + curLevel.getNumTilesHigh() + " tiles wxh.");
204:                int maxTileX = (sourceRegion.x + sourceRegion.width)
205:                        / _tileSize.width;
206:                int maxTileY = (sourceRegion.y + sourceRegion.height)
207:                        / _tileSize.height;
208:                if (maxTileX > curLevel.getNumTilesWide())
209:                    maxTileX = curLevel.getNumTilesWide() - 1;
210:                if (maxTileY > curLevel.getNumTilesHigh())
211:                    maxTileY = curLevel.getNumTilesHigh() - 1;
212:
213:                //figure out what our offset into the tile grid is
214:                final int tilegridOffsetX = sourceRegion.x % _tileSize.width;
215:                final int tilegridOffsetY = sourceRegion.y % _tileSize.height;
216:
217:                if (LOGGER.isLoggable(Level.INFO))
218:                    LOGGER.info("Reading " + param.getSourceRegion()
219:                            + " offset by " + sdeirp.getDestinationOffset()
220:                            + " (tiles " + minTileX + "," + minTileY + " to "
221:                            + maxTileX + "," + maxTileY + " in level "
222:                            + imageIndex + ")");
223:
224:                // Now we do the actual reading from SDE.
225:                ArcSDEPooledConnection scon = sdeirp.getConnection();
226:                SeQuery query = null;
227:
228:                try {
229:                    // This rather strange set of query operations is apparently the way
230:                    // one gets SDE Raster output. First, query the
231:                    // database for the single row in the raster business table.
232:                    //FIXME: Raster catalogs need to specify what their row number is.
233:                    query = new SeQuery(scon, new String[] { _rasterColumn },
234:                            new SeSqlConstruct(_rasterTable));
235:                    query.prepareQuery();
236:                    query.execute();
237:                    // Next, fetch the single row back.
238:                    final SeRow r = query.fetch();
239:
240:                    // Now build a SeRasterConstraint object which queries the db for
241:                    // the right tiles/bands/pyramid level
242:                    SeRasterConstraint rConstraint = new SeRasterConstraint();
243:                    rConstraint.setEnvelope(minTileX, minTileY, maxTileX,
244:                            maxTileY);
245:                    rConstraint.setLevel(imageIndex);
246:                    rConstraint.setBands(sdeirp.getSourceBands());
247:
248:                    // Finally, execute the raster query aganist the already-opened
249:                    // SeQuery object which already has an SeRow fetched against it.
250:                    query.queryRasterTile(rConstraint);
251:
252:                    // Now, magically, calls to r.getRasterTile() will fetch our list
253:                    // of tiles.
254:                    SeRasterTile curTile = r.getRasterTile();
255:
256:                    // the bit of our destination image that overlaps this tile
257:                    WritableRaster destinationSubTile;
258:
259:                    // the offsets into the CURRENT TILE of where we should start
260:                    // copying from the tile to the destination image.  Will only be non-zero
261:                    // if we're at the "leading edge" or "top edge" of the grid of tiles.
262:                    int curTileOffsetX, curTileOffsetY;
263:
264:                    // When we copy from the current SeRasterTile into the destination image, we'll create
265:                    // a BufferedImage.getSubImage() of the destitation that perfectly overlaps the current
266:                    // SeRasterTile, and copy the data from the current SeRasterTile to that sub-image.  These
267:                    // vars hold the proper offsets, width and height into the DESTINATION IMAGE.
268:                    int destImageOffsetX, destImageOffsetY;
269:                    int destImageTileWidth, destImageTileHeight;
270:
271:                    // Copying from an ArcSDE Raster to the specified image format, we can optionally have a
272:                    // band mapper which specifies which data band goes to which image band.
273:                    HashMap bandMapper = sdeirp.getBandMapper();
274:
275:                    // And we need to create a bandcopier for this raster type.
276:                    final ArcSDERasterBandCopier bandCopier = ArcSDERasterBandCopier
277:                            .getInstance(r.getRaster(0).getPixelType(),
278:                                    _tileSize.width, _tileSize.height);
279:
280:                    while (curTile != null) {
281:                        // LOGGER.info("tile at " + curTile.getColumnIndex() + "," +
282:                        // curTile.getRowIndex() + " has " + curTile.getNumPixels() + "
283:                        // pixels");
284:                        if (curTile.getNumPixels() == 0 && false) {
285:                            curTile = r.getRasterTile();
286:                            continue;
287:                        }
288:
289:                        // Does our image start at the exact tile boundary?  If we're in the middle of a range of tiles,
290:                        // it does, otherwise it's probably going to start slighty in from the edge of the tile.
291:                        if (curTile.getColumnIndex() == minTileX) {
292:                            curTileOffsetX = tilegridOffsetX;
293:                        } else {
294:                            curTileOffsetX = 0;
295:                        }
296:
297:                        if (curTile.getRowIndex() == minTileY) {
298:                            curTileOffsetY = tilegridOffsetY;
299:                        } else {
300:                            curTileOffsetY = 0;
301:                        }
302:
303:                        // Now we figure out how far into the destination image we go to create a mini sub-tile
304:                        // that overlaps this current tile.  If we're at the first tile, we start at zero.
305:                        final int curTileX = curTile.getColumnIndex()
306:                                - minTileX;
307:                        if (curTileX == 0) {
308:                            destImageOffsetX = 0;
309:                        } else {
310:                            destImageOffsetX = (_tileSize.width - tilegridOffsetX)
311:                                    + ((curTileX - 1) * _tileSize.width);
312:                        }
313:
314:                        final int curTileY = curTile.getRowIndex() - minTileY;
315:                        if (curTileY == 0) {
316:                            destImageOffsetY = 0;
317:                        } else {
318:                            destImageOffsetY = (_tileSize.height - tilegridOffsetY)
319:                                    + ((curTileY - 1) * _tileSize.height);
320:                        }
321:
322:                        if (curTile.getColumnIndex() == maxTileX
323:                                && (destImageOffsetX + _tileSize.width > destination
324:                                        .getWidth())) {
325:                            // if we're at the end of the row or column, we might try to grab too large of a sub-image.  Make sure
326:                            // that we're only grabbing up to the actual size of the image.
327:                            destImageTileWidth = destination.getWidth()
328:                                    - destImageOffsetX;
329:                        } else if (curTileX == 0) {
330:                            // if we're at the beginning of a row or column, we don't need to grab the entire
331:                            // sub-image.  We need to grab just the bit that overlaps the current tile.
332:                            destImageTileWidth = (_tileSize.width - curTileOffsetX);
333:                        } else {
334:                            destImageTileWidth = _tileSize.width;
335:                        }
336:
337:                        if (curTile.getRowIndex() == maxTileY
338:                                && (destImageOffsetY + _tileSize.height > destination
339:                                        .getHeight())) {
340:                            destImageTileHeight = destination.getHeight()
341:                                    - destImageOffsetY;
342:                        } else if (curTileY == 0) {
343:                            destImageTileHeight = (_tileSize.height - curTileOffsetY);
344:                        } else {
345:                            destImageTileHeight = _tileSize.height;
346:                        }
347:
348:                        //LOGGER.info("creating subtile at " + new Rectangle(destImageOffsetX, destImageOffsetY, destImageTileWidth, destImageTileHeight));
349:                        if (destImageTileWidth == 0 || destImageTileHeight == 0) {
350:                            if (LOGGER.isLoggable(Level.FINER))
351:                                LOGGER.finer("Skipping tile " + curTileX + ","
352:                                        + curTileY
353:                                        + " because it has imagetile height "
354:                                        + destImageTileHeight + " and width "
355:                                        + destImageTileWidth);
356:                            curTile = r.getRasterTile();
357:                            continue;
358:                        }
359:                        BufferedImage subtile = destination.getSubimage(
360:                                destImageOffsetX, destImageOffsetY,
361:                                destImageTileWidth, destImageTileHeight);
362:                        destinationSubTile = subtile.getRaster();
363:
364:                        final Integer curBandId = new Integer((int) curTile
365:                                .getBandId().longValue());
366:                        final int targetBand = ((Integer) bandMapper
367:                                .get(curBandId)).intValue();
368:                        bandCopier.copyPixelData(curTile, destinationSubTile,
369:                                curTileOffsetX, curTileOffsetY, targetBand);
370:
371:                        if (DEBUG) {
372:                            int[] blackpixel = new int[] { 0x00, 0x00, 0x00,
373:                                    0xff };
374:                            for (int x = 0; x < destinationSubTile.getWidth(); x++) {
375:                                destinationSubTile.setPixel(x, 0, blackpixel);
376:                                destinationSubTile.setPixel(x,
377:                                        destinationSubTile.getHeight() - 1,
378:                                        blackpixel);
379:                            }
380:                            for (int y = 0; y < destinationSubTile.getHeight(); y++) {
381:                                destinationSubTile.setPixel(0, y, blackpixel);
382:                                destinationSubTile.setPixel(destinationSubTile
383:                                        .getWidth() - 1, y, blackpixel);
384:                            }
385:
386:                            final Graphics2D graphics = subtile
387:                                    .createGraphics();
388:                            graphics.setFont(new Font("Sans-serif", Font.BOLD,
389:                                    10));
390:                            graphics.setColor(Color.yellow);
391:                            graphics.drawString(curTile.getRowIndex() + ","
392:                                    + curTile.getColumnIndex(), 10, 10);
393:
394:                            graphics.drawString(destImageOffsetX + ","
395:                                    + destImageOffsetY + " -- "
396:                                    + destImageTileWidth + "x"
397:                                    + destImageTileHeight, 10, 25);
398:
399:                            graphics.dispose();
400:                        }
401:
402:                        // fetch the next tile
403:                        curTile = r.getRasterTile();
404:                    }
405:                    curTile = null;
406:                    destinationSubTile = null;
407:
408:                    //don't need to close connections, cause that's done in the 'finally' block
409:                } catch (SeException se) {
410:                    LOGGER.log(Level.SEVERE, se.getSeError().getErrDesc(), se);
411:                    throw new DataSourceException(se);
412:                } finally {
413:                    try {
414:                        if (query != null)
415:                            query.close();
416:                        /*if (scon != null && !scon.isClosed())
417:                            scon.close();*/
418:                    } catch (SeException se) {
419:                        LOGGER.log(Level.SEVERE, se.getSeError().getErrDesc(),
420:                                se);
421:                        throw new DataSourceException(
422:                                "Unable to clean up connections to database.  May have left one hanging.",
423:                                se);
424:                    }
425:                }
426:
427:                return destination;
428:            }
429:
430:            /**
431:             * Not implemented
432:             */
433:            public IIOMetadata getImageMetadata(int imageIndex)
434:                    throws IOException {
435:                return null;
436:            }
437:
438:            /**
439:             * Not implemented
440:             */
441:            public IIOMetadata getStreamMetadata() throws IOException {
442:                return null;
443:            }
444:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.