Source Code Cross Referenced for TextRecordImageReader.java in  » GIS » GeoTools-2.4.1 » org » geotools » image » io » text » 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.image.io.text 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2003-2006, Geotools Project Managment Committee (PMC)
005:         *    (C) 2001, Institut de Recherche pour le D�veloppement
006:         *
007:         *    This library is free software; you can redistribute it and/or
008:         *    modify it under the terms of the GNU Lesser General Public
009:         *    License as published by the Free Software Foundation; either
010:         *    version 2.1 of the License, or (at your option) any later version.
011:         *
012:         *    This library is distributed in the hope that it will be useful,
013:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         *    Lesser General Public License for more details.
016:         */
017:        package org.geotools.image.io.text;
018:
019:        import java.awt.Point;
020:        import java.awt.Rectangle;
021:        import java.awt.geom.AffineTransform;
022:        import java.awt.image.BufferedImage;
023:        import java.awt.image.DataBuffer;
024:        import java.awt.image.WritableRaster;
025:        import java.io.BufferedReader;
026:        import java.io.IOException;
027:        import java.text.ParseException;
028:        import java.util.ArrayList;
029:        import java.util.Iterator;
030:        import java.util.List;
031:        import java.util.Locale;
032:        import javax.imageio.IIOException;
033:        import javax.imageio.ImageReadParam;
034:        import javax.imageio.ImageReader;
035:        import javax.imageio.ImageTypeSpecifier;
036:        import javax.imageio.metadata.IIOMetadata;
037:        import javax.imageio.spi.ImageReaderSpi;
038:
039:        import org.geotools.io.LineFormat;
040:        import org.geotools.resources.XArray;
041:        import org.geotools.resources.i18n.Errors;
042:        import org.geotools.resources.i18n.ErrorKeys;
043:        import org.geotools.resources.i18n.Descriptions;
044:        import org.geotools.resources.i18n.DescriptionKeys;
045:        import org.geotools.image.io.metadata.ImageGeometry;
046:        import org.geotools.image.io.metadata.GeographicMetadata;
047:
048:        /**
049:         * Image decoder for text files storing pixel values as records.
050:         * Such text files use one line (record) by pixel. Each line contains
051:         * at least 3 columns (in arbitrary order):
052:         *
053:         * <ul>
054:         *   <li>Pixel's <var>x</var> coordinate.</li>
055:         *   <li>Pixel's <var>y</var> coordinate.</li>
056:         *   <li>An arbitrary number of pixel values.</li>
057:         * </ul>
058:         *
059:         * For example, some Sea Level Anomaly (SLA) files contains rows of longitude
060:         * (degrees), latitude (degrees), SLA (cm), East/West current (cm/s) and
061:         * North/South current (cm/s), as below:
062:         *
063:         * <blockquote><pre>
064:         * 45.1250 -29.8750    -7.28     10.3483     -0.3164
065:         * 45.1250 -29.6250    -4.97     11.8847      3.6192
066:         * 45.1250 -29.3750    -2.91      3.7900      3.0858
067:         * 45.1250 -29.1250    -3.48     -5.1833     -5.0759
068:         * 45.1250 -28.8750    -4.36     -1.8129    -16.3689
069:         * 45.1250 -28.6250    -3.91      7.5577    -24.6801
070:         * </pre>(...etc...)
071:         * </blockquote>
072:         *
073:         * From this decoder point of view, the two first columns (longitude and latitude)
074:         * are pixel's logical coordinate (<var>x</var>,<var>y</var>), while the three last
075:         * columns are three image's bands. The whole file contains only one image (unless
076:         * {@link #getNumImages} has been overridden). All (<var>x</var>,<var>y</var>)
077:         * coordinates belong to pixel's center. This decoder will automatically translate
078:         * (<var>x</var>,<var>y</var>) coordinates from logical space to pixel space. The
079:         * {@link #getTransform} method provides a convenient {@link AffineTransform} for
080:         * performing coordinate transformations between pixel and logical spaces.
081:         * <p>
082:         * By default, {@code TextRecordImageReader} assumes that <var>x</var> and
083:         * <var>y</var> coordinates appear in column #0 and 1 respectively. It also assumes
084:         * that numeric values are encoded using current defaults {@link java.nio.charset.Charset}
085:         * and {@link java.util.Locale}, and that there is no pad value. The easiest way to change
086:         * the default setting is to create a {@link Spi} subclass. There is no need to subclass
087:         * {@code TextRecordImageReader}, unless you want more control on the decoding process.
088:         *
089:         * @since 2.1
090:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/coverageio/src/main/java/org/geotools/image/io/text/TextRecordImageReader.java $
091:         * @version $Id: TextRecordImageReader.java 27629 2007-10-26 09:59:20Z desruisseaux $
092:         * @author Martin Desruisseaux
093:         */
094:        public class TextRecordImageReader extends TextImageReader {
095:            /**
096:             * Petit facteur de tol�rance servant � tenir compte des erreurs d'arrondissement.
097:             */
098:            private static final float EPS = 1E-5f;
099:
100:            /**
101:             * Intervalle (en nombre d'octets) entre les rapports de progr�s.
102:             */
103:            private static final int PROGRESS_INTERVAL = 4096;
104:
105:            /**
106:             * Lorsque la lecture se fait par-dessus une image {@link BufferedReader} existante,
107:             * indique s'il faut effacer la r�gion dans laquelle sera plac�e l'image avant de la
108:             * lire. La valeur {@code false} permettra de conserver les anciens pixels dans
109:             * les r�gions ou le fichier ne d�finit pas de nouvelles valeurs.
110:             */
111:            private static final boolean CLEAR = true;
112:
113:            /**
114:             * Donn�es des images, ou {@code null} si aucune lecture n'a encore �t�
115:             * faite. Chaque �l�ment contient les donn�es de l'image � l'index correspondant
116:             * (i.e. l'�l�ment {@code data[0]} contient les donn�es de l'image #0,
117:             * {@code data[1]} contient les donn�es de l'image #1, etc.). Des �l�ments
118:             * de ce tableau peuvent �tre nuls si les donn�es des images correspondantes
119:             * ne sont pas retenues apr�s chaque lecture (c'est-�-dire si
120:             * <code>{@link #seekForwardOnly}==true</code>).
121:             */
122:            private RecordList[] data;
123:
124:            /**
125:             * Index de la prochaine image � lire. Cet index n'est pas n�cessairement
126:             * �gal � la longueur du tableau {@link #data}. Il peut �tre aussi bien
127:             * plus petit que plus grand.
128:             */
129:            private int nextImageIndex;
130:
131:            /**
132:             * Nombre moyen de caract�res par donn�es (incluant les espaces et les codes
133:             * de fin de ligne). Cette information n'est qu'� titre indicative, mais son
134:             * exactitude peut aider � accelerer la lecture et rendre les rapport des
135:             * progr�s plus pr�cis. Elle sera automatiquement mise � jour en fonction
136:             * des lignes lues.
137:             */
138:            private float expectedDatumLength = 10.4f;
139:
140:            /**
141:             * Constructs a new image reader.
142:             *
143:             * @param provider the provider that is invoking this constructor, or {@code null} if none.
144:             */
145:            public TextRecordImageReader(final ImageReaderSpi provider) {
146:                super (provider);
147:            }
148:
149:            /**
150:             * Returns the grid tolerance (epsilon) value.
151:             */
152:            private float getGridTolerance() {
153:                return (originatingProvider instanceof  Spi) ? ((Spi) originatingProvider).gridTolerance
154:                        : EPS;
155:            }
156:
157:            /**
158:             * Returns the column number for <var>x</var> values. The default implementation returns
159:             * {@link TextRecordImageReader.Spi#xColumn}. Subclasses should override this method if
160:             * this information should be obtained in an other way.
161:             *
162:             * @param  imageIndex The index of the image to be queried.
163:             * @throws IOException If an error occurs reading the from the input source.
164:             */
165:            protected int getColumnX(final int imageIndex) throws IOException {
166:                return (originatingProvider instanceof  Spi) ? ((Spi) originatingProvider).xColumn
167:                        : 0;
168:            }
169:
170:            /**
171:             * Invokes {@link #getColumnX} and checks the result.
172:             */
173:            private int getCheckedColumnX(final int imageIndex)
174:                    throws IOException {
175:                final int xColumn = getColumnX(imageIndex);
176:                if (xColumn < 0) {
177:                    throw new IllegalStateException(Errors.format(
178:                            ErrorKeys.NEGATIVE_COLUMN_$2, "x", new Integer(
179:                                    xColumn)));
180:                }
181:                return xColumn;
182:            }
183:
184:            /**
185:             * Returns the column number for <var>x</var> values. The default implementation returns
186:             * {@link TextRecordImageReader.Spi#yColumn}. Subclasses should override this method if
187:             * this information should be obtained in an other way.
188:             *
189:             * @param  imageIndex The index of the image to be queried.
190:             * @throws IOException If an error occurs reading the from the input source.
191:             */
192:            protected int getColumnY(final int imageIndex) throws IOException {
193:                return (originatingProvider instanceof  Spi) ? ((Spi) originatingProvider).yColumn
194:                        : 1;
195:            }
196:
197:            /**
198:             * Invokes {@link #getColumnY} and checks the result.
199:             */
200:            private int getCheckedColumnY(final int imageIndex)
201:                    throws IOException {
202:                final int yColumn = getColumnY(imageIndex);
203:                if (yColumn < 0) {
204:                    throw new IllegalStateException(Errors.format(
205:                            ErrorKeys.NEGATIVE_COLUMN_$2, "y", new Integer(
206:                                    yColumn)));
207:                }
208:                return yColumn;
209:            }
210:
211:            /**
212:             * Retourne le num�ro de colonne dans laquelle se trouvent les donn�es de la
213:             * bande sp�cifi�e. L'impl�mentation par d�faut retourne {@code band}+1
214:             * ou 2 si la bande est plus grand ou �gal � {@link #getColumnX} et/ou
215:             * {@link #getColumnY}. Cette impl�mentation devrait convenir pour des donn�es
216:             * se trouvant aussi bien avant qu'apr�s les colonnes <var>x</var>
217:             * et <var>y</var>, m�me si ces derni�res ne sont pas cons�cutives.
218:             *
219:             * @param  imageIndex Index de l'image � lire.
220:             * @param  band Bande de l'image � lire.
221:             * @return Num�ro de colonne des donn�es de l'image.
222:             * @throws IOException si l'op�ration n�cessitait une lecture du fichier (par exemple
223:             *         des informations inscrites dans un en-t�te) et que cette lecture a �chou�e.
224:             */
225:            private int getColumn(final int imageIndex, int band)
226:                    throws IOException {
227:                final int xColumn = getCheckedColumnX(imageIndex);
228:                final int yColumn = getCheckedColumnY(imageIndex);
229:                if (band >= Math.min(xColumn, yColumn))
230:                    band++;
231:                if (band >= Math.max(xColumn, yColumn))
232:                    band++;
233:                return band;
234:            }
235:
236:            /**
237:             * Set the input source. It should be one of the following object, in preference order:
238:             * {@link java.io.File}, {@link java.net.URL}, {@link java.io.BufferedReader}.
239:             * {@link java.io.Reader}, {@link java.io.InputStream} or
240:             * {@link javax.imageio.stream.ImageInputStream}.
241:             */
242:            //@Override
243:            public void setInput(final Object input,
244:                    final boolean seekForwardOnly, final boolean ignoreMetadata) {
245:                clear();
246:                super .setInput(input, seekForwardOnly, ignoreMetadata);
247:            }
248:
249:            /**
250:             * Returns the number of bands available for the specified image.
251:             *
252:             * @param  imageIndex  The image index.
253:             * @throws IOException if an error occurs reading the information from the input source.
254:             */
255:            //@Override
256:            public int getNumBands(final int imageIndex) throws IOException {
257:                return getRecords(imageIndex).getColumnCount()
258:                        - (getCheckedColumnX(imageIndex) == getCheckedColumnY(imageIndex) ? 1
259:                                : 2);
260:            }
261:
262:            /**
263:             * Returns the width in pixels of the given image within the input source.
264:             *
265:             * @param  imageIndex the index of the image to be queried.
266:             * @return Image width.
267:             * @throws IOException If an error occurs reading the width information from the input source.
268:             */
269:            public int getWidth(final int imageIndex) throws IOException {
270:                return getRecords(imageIndex).getPointCount(
271:                        getCheckedColumnX(imageIndex), getGridTolerance());
272:            }
273:
274:            /**
275:             * Returns the height in pixels of the given image within the input source.
276:             *
277:             * @param  imageIndex the index of the image to be queried.
278:             * @return Image height.
279:             * @throws IOException If an error occurs reading the height information from the input source.
280:             */
281:            public int getHeight(final int imageIndex) throws IOException {
282:                return getRecords(imageIndex).getPointCount(
283:                        getCheckedColumnY(imageIndex), getGridTolerance());
284:            }
285:
286:            /**
287:             * Returns metadata associated with the given image.
288:             * Calling this method may force loading of full image.
289:             *
290:             * @param  imageIndex The image index.
291:             * @return The metadata, or {@code null} if none.
292:             * @throws IOException If an error occurs reading the data information from the input source.
293:             */
294:            //@Override
295:            public IIOMetadata getImageMetadata(final int imageIndex)
296:                    throws IOException {
297:                checkImageIndex(imageIndex);
298:                if (ignoreMetadata) {
299:                    return null;
300:                }
301:                final GeographicMetadata metadata = new GeographicMetadata(this );
302:                final ImageGeometry geometry = metadata.getGeometry();
303:                /*
304:                 * Computes the smallest bounding box containing the full image in user coordinates.
305:                 * This implementation searchs for minimum and maximum values in x and y columns as
306:                 * returned by getColumnX() and getColumnY(). Reminder: xmax and ymax are INCLUSIVE
307:                 * in the code below, as well as (width-1) and (height-1).
308:                 */
309:                final float tolerance = getGridTolerance();
310:                final RecordList records = getRecords(imageIndex);
311:                final int xColumn = getCheckedColumnX(imageIndex);
312:                final int yColumn = getCheckedColumnY(imageIndex);
313:                final int width = records.getPointCount(xColumn, tolerance);
314:                final int height = records.getPointCount(yColumn, tolerance);
315:                final double xmin = records.getMinimum(xColumn);
316:                final double ymin = records.getMinimum(yColumn);
317:                final double xmax = records.getMaximum(xColumn);
318:                final double ymax = records.getMaximum(yColumn);
319:                geometry.addCoordinateRange(0, width - 1, xmin, xmax);
320:                geometry.addCoordinateRange(0, height - 1, ymin, ymax);
321:                geometry.setPixelOrientation("center");
322:                /*
323:                 * Now adds the valid range of sample values for each band.
324:                 */
325:                final int numBands = records.getColumnCount()
326:                        - (xColumn == yColumn ? 1 : 2);
327:                for (int band = 0; band < numBands; band++) {
328:                    final int column = getColumn(imageIndex, band);
329:                    metadata.getBand(band).setValidRange(
330:                            records.getMinimum(column),
331:                            records.getMaximum(column));
332:                }
333:                return metadata;
334:            }
335:
336:            /**
337:             * Rounds the specified values. This method is invoked automatically by the {@link #read read}
338:             * method while reading an image. It provides a place where to fix rounding errors in latitude
339:             * and longitude coordinates. For example if longitudes have a step 1/6� but are written with
340:             * only 3 decimal digits, then we get {@linkplain #getColumnX x} values like {@code 10.000},
341:             * {@code 10.167}, {@code 10.333}, <cite>etc.</cite>, which can leads to an error of 0.001�
342:             * in longitude. This error may cause {@code TextRecordImageReader} to fails validation tests
343:             * and throws an {@link javax.imageio.IIOException}: "<cite>Points dont seem to be distributed
344:             * on a regular grid</cite>". A work around is to multiply the <var>x</var> and <var>y</var>
345:             * coordinates by 6, round to the nearest integer and divide them by 6.
346:             * <p>
347:             * The default implementation do nothing.
348:             *
349:             * @param values The values to round in place.
350:             */
351:            protected void round(double[] values) {
352:            }
353:
354:            /**
355:             * Retourne les donn�es de l'image � l'index sp�cifi�. Si cette image avait d�j� �t� lue, ses
356:             * donn�es seront retourn�es imm�diatement.  Sinon, cette image sera lue ainsi que toutes les
357:             * images qui pr�c�dent {@code imageIndex} et qui n'avaient pas encore �t� lues. Que ces
358:             * images pr�c�dentes soient m�moris�es ou oubli�es d�pend de {@link #seekForwardOnly}.
359:             *
360:             * @param  imageIndex Index de l'image � lire.
361:             * @return Les donn�es de l'image. Cette m�thode ne retourne jamais {@code null}.
362:             * @throws IOException si une erreur est survenue lors de la lecture du flot,
363:             *         ou si des nombres n'�taient pas correctement format�s dans le flot.
364:             * @throws IndexOutOfBoundsException si l'index sp�cifi� est en dehors des
365:             *         limites permises ou si aucune image n'a �t� conserv�e � cet index.
366:             */
367:            private RecordList getRecords(final int imageIndex)
368:                    throws IOException {
369:                clearAbortRequest();
370:                checkImageIndex(imageIndex);
371:                if (imageIndex >= nextImageIndex) {
372:                    processImageStarted(imageIndex);
373:                    final BufferedReader reader = getReader();
374:                    final long origine = getStreamPosition(reader);
375:                    final long length = getStreamLength(nextImageIndex,
376:                            imageIndex + 1);
377:                    long nextProgressPosition = (origine >= 0 && length > 0) ? 0
378:                            : Long.MAX_VALUE;
379:                    for (; nextImageIndex <= imageIndex; nextImageIndex++) {
380:                        /*
381:                         * R�duit la consommation de m�moire des images pr�c�dentes. On ne r�duit
382:                         * pas celle de l'image courante,  puisque la plupart du temps le tableau
383:                         * sera bient�t d�truit de toute fa�on.
384:                         */
385:                        if (seekForwardOnly) {
386:                            minIndex = nextImageIndex;
387:                        }
388:                        if (nextImageIndex != 0 && data != null) {
389:                            final RecordList records = data[nextImageIndex - 1];
390:                            if (records != null) {
391:                                if (seekForwardOnly) {
392:                                    data[nextImageIndex - 1] = null;
393:                                } else {
394:                                    records.trimToSize();
395:                                }
396:                            }
397:                        }
398:                        /*
399:                         * Proc�de � la lecture de chacune des lignes de donn�es. Que ces lignes
400:                         * soient m�moris�es ou pas d�pend de l'image que l'on est en train de
401:                         * d�coder ainsi que de la valeur de {@link #seekForwardOnly}.
402:                         */
403:                        double[] values = null;
404:                        RecordList records = null;
405:                        final boolean keep = (nextImageIndex == imageIndex)
406:                                || !seekForwardOnly;
407:                        final int xColumn = getCheckedColumnX(nextImageIndex);
408:                        final int yColumn = getCheckedColumnY(nextImageIndex);
409:                        final double padValue = getPadValue(nextImageIndex);
410:                        final LineFormat lineFormat = getLineFormat(nextImageIndex);
411:                        try {
412:                            String line;
413:                            while ((line = reader.readLine()) != null) {
414:                                if (isComment(line)
415:                                        || lineFormat.setLine(line) == 0) {
416:                                    continue;
417:                                }
418:                                values = lineFormat.getValues(values);
419:                                for (int i = 0; i < values.length; i++) {
420:                                    if (i != xColumn && i != yColumn
421:                                            && values[i] == padValue) {
422:                                        values[i] = Double.NaN;
423:                                    }
424:                                }
425:                                round(values);
426:                                if (keep) {
427:                                    if (records == null) {
428:                                        final int expectedLineCount = Math
429:                                                .max(
430:                                                        8,
431:                                                        Math
432:                                                                .min(
433:                                                                        65536,
434:                                                                        Math
435:                                                                                .round(length
436:                                                                                        / (expectedDatumLength * values.length))));
437:                                        records = new RecordList(values.length,
438:                                                expectedLineCount);
439:                                    }
440:                                    records.add(values);
441:                                }
442:                                final long position = getStreamPosition(reader)
443:                                        - origine;
444:                                if (position >= nextProgressPosition) {
445:                                    processImageProgress(position
446:                                            * (100f / length));
447:                                    nextProgressPosition = position
448:                                            + PROGRESS_INTERVAL;
449:                                    if (abortRequested()) {
450:                                        processReadAborted();
451:                                        return records;
452:                                    }
453:                                }
454:                            }
455:                        } catch (ParseException exception) {
456:                            throw new IIOException(getPositionString(exception
457:                                    .getLocalizedMessage()), exception);
458:                        }
459:                        /*
460:                         * Apr�s la lecture d'une image, v�rifie s'il y avait un nombre suffisant de lignes.
461:                         * Une exception sera lanc�e si l'image ne contenait pas au moins deux lignes. On
462:                         * ajustera ensuite le nombre moyens de caract�res par donn�es.
463:                         */
464:                        if (records != null) {
465:                            final int lineCount = records.getLineCount();
466:                            if (lineCount < 2) {
467:                                throw new IIOException(
468:                                        getPositionString(Errors
469:                                                .format(ErrorKeys.FILE_HAS_TOO_FEW_DATA)));
470:                            }
471:                            if (data == null) {
472:                                data = new RecordList[imageIndex + 1];
473:                            } else if (data.length <= imageIndex) {
474:                                data = (RecordList[]) XArray.resize(data,
475:                                        imageIndex + 1);
476:                            }
477:                            data[nextImageIndex] = records;
478:                            final float meanDatumLength = (getStreamPosition(reader) - origine)
479:                                    / (float) records.getDataCount();
480:                            if (meanDatumLength > 0)
481:                                expectedDatumLength = meanDatumLength;
482:                        }
483:                    }
484:                    processImageComplete();
485:                }
486:                /*
487:                 * Une fois les lectures termin�es, retourne les donn�es de l'image
488:                 * demand�e. Une exception sera lanc�e si ces donn�es n'ont pas �t�
489:                 * conserv�es.
490:                 */
491:                if (data != null && imageIndex < data.length) {
492:                    final RecordList records = data[imageIndex];
493:                    if (records != null) {
494:                        return records;
495:                    }
496:                }
497:                throw new IndexOutOfBoundsException(String.valueOf(imageIndex));
498:            }
499:
500:            /**
501:             * Reads the image indexed by {@code imageIndex} and returns it as a complete buffered image.
502:             *
503:             * @param  imageIndex the index of the image to be retrieved.
504:             * @param  param Parameters used to control the reading process, or {@code null}.
505:             * @return the desired portion of the image.
506:             * @throws IOException if an error occurs during reading.
507:             */
508:            public BufferedImage read(final int imageIndex,
509:                    final ImageReadParam param) throws IOException {
510:                final float tolerance = getGridTolerance();
511:                final int xColumn = getCheckedColumnX(imageIndex);
512:                final int yColumn = getCheckedColumnY(imageIndex);
513:                final RecordList records = getRecords(imageIndex);
514:                final int width = records.getPointCount(xColumn, tolerance);
515:                final int height = records.getPointCount(yColumn, tolerance);
516:                final int numSrcBands = records.getColumnCount()
517:                        - (xColumn == yColumn ? 1 : 2);
518:                /*
519:                 * Extracts user's parameters
520:                 */
521:                final int[] srcBands;
522:                final int[] dstBands;
523:                final int sourceXSubsampling;
524:                final int sourceYSubsampling;
525:                final int subsamplingXOffset;
526:                final int subsamplingYOffset;
527:                final int destinationXOffset;
528:                final int destinationYOffset;
529:                if (param != null) {
530:                    srcBands = param.getSourceBands();
531:                    dstBands = param.getDestinationBands();
532:                    final Point offset = param.getDestinationOffset();
533:                    sourceXSubsampling = param.getSourceXSubsampling();
534:                    sourceYSubsampling = param.getSourceYSubsampling();
535:                    subsamplingXOffset = param.getSubsamplingXOffset();
536:                    subsamplingYOffset = param.getSubsamplingYOffset();
537:                    destinationXOffset = offset.x;
538:                    destinationYOffset = offset.y;
539:                } else {
540:                    srcBands = null;
541:                    dstBands = null;
542:                    sourceXSubsampling = 1;
543:                    sourceYSubsampling = 1;
544:                    subsamplingXOffset = 0;
545:                    subsamplingYOffset = 0;
546:                    destinationXOffset = 0;
547:                    destinationYOffset = 0;
548:                }
549:                /*
550:                 * Initializes...
551:                 */
552:                final int numDstBands = (dstBands != null) ? dstBands.length
553:                        : (srcBands != null) ? srcBands.length : numSrcBands;
554:                final BufferedImage image = getDestination(imageIndex, param,
555:                        width, height, null); // TODO
556:                checkReadParamBandSettings(param, numSrcBands, image
557:                        .getSampleModel().getNumBands());
558:
559:                final Rectangle srcRegion = new Rectangle();
560:                final Rectangle dstRegion = new Rectangle();
561:                computeRegions(param, width, height, image, srcRegion,
562:                        dstRegion);
563:                final int sourceXMin = srcRegion.x;
564:                final int sourceYMin = srcRegion.y;
565:                final int sourceXMax = srcRegion.width + sourceXMin;
566:                final int sourceYMax = srcRegion.height + sourceYMin;
567:
568:                final WritableRaster raster = image.getRaster();
569:                final int rasterWidth = raster.getWidth();
570:                final int rasterHeigth = raster.getHeight();
571:                final int columnCount = records.getColumnCount();
572:                final int dataCount = records.getDataCount();
573:                final float[] data = records.getData();
574:                final double xmin = records.getMinimum(xColumn);
575:                final double ymin = records.getMinimum(yColumn);
576:                final double xmax = records.getMaximum(xColumn);
577:                final double ymax = records.getMaximum(yColumn);
578:                final double scaleX = (width - 1) / (xmax - xmin);
579:                final double scaleY = (height - 1) / (ymax - ymin);
580:                /*
581:                 * Clears the image area. All values are set to NaN.
582:                 */
583:                if (CLEAR) {
584:                    final int minX = dstRegion.x;
585:                    final int minY = dstRegion.y;
586:                    final int maxX = dstRegion.width + minX;
587:                    final int maxY = dstRegion.height + minY;
588:                    for (int b = (dstBands != null) ? dstBands.length
589:                            : numDstBands; --b >= 0;) {
590:                        final int band = (dstBands != null) ? dstBands[b] : b;
591:                        for (int y = minY; y < maxY; y++) {
592:                            for (int x = minX; x < maxX; x++) {
593:                                raster.setSample(x, y, band, Float.NaN);
594:                            }
595:                        }
596:                    }
597:                }
598:                /*
599:                 * Computes column numbers corresponding to source bands,
600:                 * and start storing values into the image.
601:                 */
602:                final int[] columns = new int[(srcBands != null) ? srcBands.length
603:                        : numDstBands];
604:                for (int i = 0; i < columns.length; i++) {
605:                    columns[i] = getColumn(imageIndex,
606:                            srcBands != null ? srcBands[i] : i);
607:                }
608:                for (int i = 0; i < dataCount; i += columnCount) {
609:                    /*
610:                     * On convertit maintenant la coordonn�e (x,y) logique en coordonn�e pixel. Cette
611:                     * coordonn�e pixel se r�f�re � l'image "source";  elle ne se r�f�re pas encore �
612:                     * l'image destination. Elle doit obligatoirement �tre enti�re. Plus loin, nous
613:                     * tiendrons compte du "subsampling".
614:                     */
615:                    final double fx = (data[i + xColumn] - xmin) * scaleX; // (fx,fy) may be NaN: Use
616:                    final double fy = (ymax - data[i + yColumn]) * scaleY; // "!(abs(...)<=tolerance)".
617:                    int x = (int) Math.round(fx); // This conversion is not the same than
618:                    int y = (int) Math.round(fy); // getTransform(), but it should be ok.
619:                    if (!(Math.abs(x - fx) <= tolerance)) {
620:                        fireBadCoordinate(data[i + xColumn]);
621:                        continue;
622:                    }
623:                    if (!(Math.abs(y - fy) <= tolerance)) {
624:                        fireBadCoordinate(data[i + yColumn]);
625:                        continue;
626:                    }
627:                    if (x >= sourceXMin && x < sourceXMax && y >= sourceYMin
628:                            && y < sourceYMax) {
629:                        x -= subsamplingXOffset;
630:                        y -= subsamplingYOffset;
631:                        if ((x % sourceXSubsampling) == 0
632:                                && (y % sourceYSubsampling) == 0) {
633:                            x = x / sourceXSubsampling
634:                                    + (destinationXOffset - sourceXMin);
635:                            y = y / sourceYSubsampling
636:                                    + (destinationYOffset - sourceYMin);
637:                            if (x < rasterWidth && y < rasterHeigth) {
638:                                for (int j = 0; j < columns.length; j++) {
639:                                    raster
640:                                            .setSample(
641:                                                    x,
642:                                                    y,
643:                                                    (dstBands != null ? dstBands[j]
644:                                                            : j), data[i
645:                                                            + columns[j]]);
646:                                }
647:                            }
648:                        }
649:                    }
650:                }
651:                return image;
652:            }
653:
654:            /**
655:             * Pr�vient qu'une coordonn�e est mauvaise. Cette m�thode est appel�e lors de la lecture
656:             * s'il a �t� d�tect� qu'une coordonn�e est en dehors des limites pr�vues, ou qu'elle ne
657:             * correspond pas � des coordonn�es pixels enti�res.
658:             */
659:            private void fireBadCoordinate(final float coordinate) {
660:                processWarningOccurred(getPositionString(Errors.format(
661:                        ErrorKeys.BAD_COORDINATE_$1, new Float(coordinate))));
662:            }
663:
664:            /**
665:             * Supprime les donn�es de toutes les images
666:             * qui avait �t� conserv�es en m�moire.
667:             */
668:            private void clear() {
669:                data = null;
670:                nextImageIndex = 0;
671:                expectedDatumLength = 10.4f;
672:            }
673:
674:            /**
675:             * Restores the {@code TextRecordImageReader} to its initial state.
676:             */
677:            //@Override
678:            public void reset() {
679:                clear();
680:                super .reset();
681:            }
682:
683:            /**
684:             * Service provider interface (SPI) for {@link TextRecordImageReader}s. This SPI provides
685:             * necessary implementation for creating default {@link TextRecordImageReader} using default
686:             * locale and character set. Subclasses can set some fields at construction time in order to
687:             * tune the reader to a particular environment, e.g.:
688:             *
689:             * <blockquote><pre>
690:             * public final class CLSImageReaderSpi extends TextRecordImageReader.Spi {
691:             *     public CLSImageReaderSpi() {
692:             *         {@link #names      names}      = new String[] {"CLS"};
693:             *         {@link #MIMETypes  MIMETypes}  = new String[] {"text/x-records-CLS"};
694:             *         {@link #vendorName vendorName} = "Institut de Recherche pour le D�veloppement";
695:             *         {@link #version    version}    = "1.0";
696:             *         {@link #locale     locale}     = Locale.US;
697:             *         {@link #charset    charset}    = Charset.forName("ISO-LATIN-1");
698:             *         {@link #padValue   padValue}   = 9999;
699:             *     }
700:             * }
701:             * </pre></blockquote>
702:             *
703:             * (Note: fields {@code vendorName} and {@code version} are only informatives).
704:             * There is no need to override any method in this example. However, developers
705:             * can gain more control by creating subclasses of {@link TextRecordImageReader}
706:             * and {@code Spi}.
707:             *
708:             * @since 2.1
709:             * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/coverageio/src/main/java/org/geotools/image/io/text/TextRecordImageReader.java $
710:             * @version $Id: TextRecordImageReader.java 27629 2007-10-26 09:59:20Z desruisseaux $
711:             * @author Martin Desruisseaux
712:             */
713:            public static class Spi extends TextImageReader.Spi {
714:                /**
715:                 * The format names for the default {@link TextRecordImageReader} configuration.
716:                 */
717:                private static final String[] NAMES = { "records" };
718:
719:                /**
720:                 * The mime types for the default {@link TextRecordImageReader} configuration.
721:                 */
722:                private static final String[] MIME_TYPES = { "text/x-records" };
723:
724:                /**
725:                 * 0-based column number for <var>x</var> values. The default value is 0.
726:                 *
727:                 * @see TextRecordImageReader#getColumnX
728:                 * @see TextRecordImageReader#parseLine
729:                 */
730:                protected int xColumn;
731:
732:                /**
733:                 * 0-based column number for <var>y</var> values. The default value is 1.
734:                 *
735:                 * @see TextRecordImageReader#getColumnY
736:                 * @see TextRecordImageReader#parseLine
737:                 */
738:                protected int yColumn;
739:
740:                /**
741:                 * A tolerance factor during decoding, between 0 and 1. During decoding,
742:                 * the image reader compute cell's width and height   (i.e. the smallest
743:                 * non-null difference between ordinates in a given column: <var>x</var>
744:                 * for cell's width and <var>y</var> for cell's height). Then, it checks
745:                 * if every coordinate points fall on a grid having this cell's size. If
746:                 * a point depart from more than {@code gridTolerance} percent of cell's
747:                 * width or height, an exception is thrown.
748:                 * <p>
749:                 * {@code gridTolerance} should be a small number like {@code 1E-5f}
750:                 * or {@code 1E-3f}. The later is more tolerant than the former.
751:                 */
752:                protected float gridTolerance = EPS;
753:
754:                /**
755:                 * Constructs a default {@code TextRecordImageReader.Spi}. This constructor
756:                 * provides the following defaults in addition to the defaults defined in the
757:                 * {@linkplain TextImageReader.Spi#Spi super-class constructor}:
758:                 *
759:                 * <ul>
760:                 *   <li>{@link #names}           = {@code "records"}</li>
761:                 *   <li>{@link #MIMETypes}       = {@code "text/x-records"}</li>
762:                 *   <li>{@link #pluginClassName} = {@code "org.geotools.image.io.text.TextRecordImageReader"}</li>
763:                 *   <li>{@link #vendorName}      = {@code "Geotools"}</li>
764:                 *   <li>{@link #xColumn}         = {@code 0}</li>
765:                 *   <li>{@link #yColumn}         = {@code 1}</li>
766:                 * </ul>
767:                 *
768:                 * For efficienty reasons, the above fields are initialized to shared arrays. Subclasses
769:                 * can assign new arrays, but should not modify the default array content.
770:                 */
771:                public Spi() {
772:                    names = NAMES;
773:                    MIMETypes = MIME_TYPES;
774:                    pluginClassName = "org.geotools.image.io.text.TextRecordImageReader";
775:                    vendorName = "Geotools";
776:                    version = "2.4";
777:                    xColumn = 0;
778:                    yColumn = 1;
779:                    gridTolerance = EPS;
780:                }
781:
782:                /**
783:                 * Returns a brief, human-readable description of this service provider
784:                 * and its associated implementation. The resulting string should be
785:                 * localized for the supplied locale, if possible.
786:                 *
787:                 * @param  locale A Locale for which the return value should be localized.
788:                 * @return A String containing a description of this service provider.
789:                 */
790:                public String getDescription(final Locale locale) {
791:                    return Descriptions.getResources(locale).getString(
792:                            DescriptionKeys.CODEC_GRID);
793:                }
794:
795:                /**
796:                 * Returns an instance of the ImageReader implementation associated
797:                 * with this service provider.
798:                 *
799:                 * @param  extension An optional extension object, which may be null.
800:                 * @return An image reader instance.
801:                 * @throws IOException if the attempt to instantiate the reader fails.
802:                 */
803:                public ImageReader createReaderInstance(final Object extension)
804:                        throws IOException {
805:                    return new TextRecordImageReader(this );
806:                }
807:
808:                /**
809:                 * Returns {@code true} if the specified row length is valid. The default implementation
810:                 * returns {@code true} if the row seems "short", where "short" is arbitrary fixed to 10
811:                 * columns. This is an arbitrary choice, which is why this method is not public. It may
812:                 * be changed in any future Geotools version.
813:                 */
814:                //@Override
815:                boolean isValidColumnCount(final int count) {
816:                    return count >= (xColumn == yColumn ? 2 : 3) && count <= 10;
817:                }
818:            }
819:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.