Revision 46118

View differences:

tags/org.gvsig.desktop-2.0.344/org.gvsig.desktop.compat.cdc/org.gvsig.basicformats/src/main/java/org/gvsig/basicformats/CLRFile.java
1
/*
2
 * To change this license header, choose License Headers in Project Properties.
3
 * To change this template file, choose Tools | Templates
4
 * and open the template in the editor.
5
 */
6
package org.gvsig.basicformats;
7

  
8
import org.gvsig.raster.lib.legend.api.colortable.ColorTable;
9

  
10

  
11
public interface CLRFile extends FormatFile {
12

  
13
    public String FILE_EXTENSION = "clr";
14
    
15
    ColorTable getColorTable();
16

  
17
    void setColorTable(ColorTable colorTable);
18
    
19
}
tags/org.gvsig.desktop-2.0.344/org.gvsig.desktop.compat.cdc/org.gvsig.basicformats/src/main/java/org/gvsig/basicformats/impl/DefaultCPGFile.java
1
package org.gvsig.basicformats.impl;
2

  
3
import java.io.File;
4
import java.io.IOException;
5
import org.apache.commons.io.FileUtils;
6
import org.apache.commons.io.FilenameUtils;
7
import org.apache.commons.lang3.StringUtils;
8
import org.gvsig.basicformats.CPGFile;
9
import org.slf4j.Logger;
10
import org.slf4j.LoggerFactory;
11

  
12

  
13
public class DefaultCPGFile extends AbstractFormatFile implements CPGFile {
14

  
15
    private static final Logger logger = LoggerFactory.getLogger(DefaultPRJFile.class);
16

  
17

  
18
    private File source;
19
    private String charsetName = null;
20

  
21
    /**
22
     * Define the valid code pages (equivalent to MSDOS code pages). 
23
     * This codes are used on the byte 29 of the DBF header to define the DBF
24
     * codepage.
25
     *
26
     * The equivalences of these charsets using Java NIO charset names are
27
     * defined on the {@link #charsetNames} array (so 0x01 is
28
     * equivalent to IBM437, 0x02 to IBM850, etc)
29
     *
30
     * See some other equivalences in:
31
     * https://github.com/infused/dbf/blob/master/docs/supported_encodings.csv
32
     * https://github.com/olemb/dbfread/blob/master/dbfread/codepages.py
33
     * https://joinup.ec.europa.eu/svn/gvsig-desktop/trunk/libraries/libFMap/src/com/iver/cit/gvsig/fmap/drivers/dbf/DbfEncodings.java
34
     */
35
    private static final short[] codePages = {
36
        0x01, 0x02, 0x03, 0x04,
37
        0x08, 0x09, 0x0a, 0x0b,
38
        0x0d, 0x0e, 0x0f, 0x10,
39
        0x11, 0x12, 0x13, 0x14,
40
        0x15, 0x16, 0x17, 0x18,
41
        0x19, 0x1a, 0x1b, 0x1c,
42
        0x1d, 0x1f, 0x22, 0x23,
43
        0x24, 0x25, 0x26, 0x37,
44
        0x40, 0x4d, 0x4e, 0x4f,
45
        0x50, 0x57, 0x58, 0x59,
46
        0x64, 0x65, 0x66, 0x67,
47
        0x68, 0x69, 0x6a, 0x6b,
48
        0x6c, 0x78, 0x79, 0x7a,
49
        0x7b, 0x7c, 0x7d, 0x7d,
50
        0x86, 0x87, 0x88, 0xc8,
51
        0xc9, 0xca, 0xcb, 0xcc};
52

  
53
    /**
54
     * Equivalent Java charset names to the code pages defined in
55
     * {@link #codePages}, using Java NIO Charset names (which differ
56
     * from JAVA IO names, see
57
     * https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html)
58
     */
59
    private static final String[] charsetNames = new String[]{
60
        "IBM437", "IBM850", "windows-1252", "x-MacRoman",
61
        "IBM865", "IBM437", "IBM850", "IBM437",
62
        "IBM437", "IBM850", "IBM437", "IBM850",
63
        "IBM437", "IBM850", "x-IBM943", "IBM850",
64
        "IBM437", "IBM850", "IBM865", "IBM437",
65
        "IBM437", "IBM850", "IBM437", "IBM863",
66
        "IBM850", "IBM852", "IBM852", "IBM852",
67
        "IBM860", "IBM850", "IBM866", "IBM850",
68
        "IBM852", "x-mswin-936", "x-IBM949", "IBM950",
69
        "x-IBM874", "windows-1252", "windows-1252", "windows-1252",
70
        "IBM852", "IBM866", "IBM865", "IBM861",
71
        // 0x68 and 0x69 are unofficial "Codepage 895 Kamenicky (Czech) MS-DOS" and "Codepage 620  Mazovia (Polish) MS-DOS",
72
        // but there is no Java equivalent
73
        // so we use CP437 which is the closest charset for the latin characters part
74
        "IBM437", "IBM437", "x-IBM737", "IBM857",
75
        "IBM863", "x-IBM950", "x-IBM949", "x-mswin-936",
76
        "x-IBM942", "x-IBM874", "windows-1255", "windows-1256",
77
        "x-IBM737", "IBM852", "IBM857", "windows-1250",
78
        "windows-1251", "windows-1254", "windows-1253", "windows-1257"};
79

  
80
    public DefaultCPGFile() {
81
        this.charsetName = null;
82
        this.source = null;
83
    }
84

  
85
    @Override
86
    public File getFile(File file) {
87
        File f = new File(FilenameUtils.removeExtension(file.getAbsolutePath()) + "." + FILE_EXTENSION);
88
        return f;
89
    }
90

  
91
    @Override
92
    public File getFile() {
93
        return source;
94
    }
95

  
96
    @Override
97
    public String getCharsetName() {
98
        return this.charsetName;
99
    }
100

  
101
    @Override
102
    public void setCharsetName(String charsetName) {
103
        this.charsetName = charsetName;
104
    }
105

  
106
    @Override
107
    public String toCharsetName(String codePageName) {
108
        if (codePageName.equals("UTF8")) {
109
            return "UTF-8";
110
        }
111
        if (codePageName.equals("SJIS")) {
112
            return "Shift_JIS";
113
        }
114

  
115
        if (StringUtils.isNumeric(codePageName)) {
116
            if (codePageName.startsWith("8859") && codePageName.length() > 4) {
117
                return "ISO-8859-" + codePageName.substring(4);
118
            }
119
            if (codePageName.startsWith("125") && codePageName.length() == 4) {
120
                return "windows-" + codePageName;
121
            }
122
            if (codePageName.length() == 3) {
123
                return "IBM-" + codePageName;
124
            }
125
            for (int i = 0; i < charsetNames.length; i++) {
126
                if (charsetNames[i].contains(codePageName)) {
127
                    return codePageName;
128
                }
129
            }
130
        }
131
        if (codePageName.equals("65001")) {
132
            return "UTF-8";
133
        }
134
        return codePageName;
135
    }
136

  
137
    /**
138
     * Gets the Java NIO charset name equivalent to the provided code page.
139
     * Gets null if the provided code page is not recognised
140
     * as a valid code
141
     *
142
     * @param codePage
143
     * @return
144
     */
145
    @Override
146
    public String toCharsetName(int codePage) {
147
        if (codePage != 0) {
148
            for (int i = 0; i < codePages.length; i++) {
149
                if (codePages[i] == codePage) {
150
                    return charsetNames[i];
151
                }
152
            }
153
        }
154
        return null;
155
    }
156

  
157
    @Override
158
    public String toCPGName(String charsetName) {
159
        if (charsetName.startsWith("windows-")
160
                || charsetName.startsWith("ISO-8859")
161
                || charsetName.startsWith("IBM-")
162
                || charsetName.startsWith("x-IBM")
163
                || charsetName.startsWith("x-mswin-")) {
164
            return charsetName.replaceAll("[^\\d]", "");
165
        }
166
        if (charsetName.equals("Shift_JIS")) {
167
            return "SJIS";
168
        }
169
        // For the rest of the charsets, we'll directly write the Java NIO Charset
170
        // Probably they will only be recognized by gvSIG, but it's better than nothing
171
        return charsetName;
172
    }
173

  
174
    /**
175
     * Returns the code page corresponding to the
176
     * provided charset name
177
     *
178
     * @param charsetName
179
     * @return The code page, or 0x00 if no equivalent code page was found for
180
     * the provided charsetName
181
     */
182
    @Override
183
    public int toCPG(String charsetName) {
184
        for (int i = 0; i < charsetNames.length; i++) {
185
            if (charsetNames[i].equals(charsetName)) {
186
                return codePages[i];
187
            }
188
        }
189
        // default
190
        return 0x00;
191
    }
192

  
193
    @Override
194
    public void read(File file) throws IOException {
195
        File f = this.getFile(file);
196
        if (f.exists()) {
197
            try {
198
                String theContents = FileUtils.readFileToString(f);
199
                theContents = StringUtils.trim(theContents);
200
                if (StringUtils.isNotEmpty(theContents)) {
201
                    String theCharset = toCharsetName(theContents);
202
                    this.charsetName = theCharset;
203
                    this.source = f.getAbsoluteFile();
204
                }
205
            } catch (IOException e) {
206
                logger.warn("Couldn't read " + FILE_EXTENSION + " file (" + f.getAbsolutePath() + ").", e);
207
                throw e;
208
            }
209
        }
210
    }
211

  
212
    @Override
213
    public void write(File file) throws IOException {
214
        File f = this.getFile(file);
215
        try {
216
            String export = toCPGName(this.charsetName) + "\n";
217
            FileUtils.writeStringToFile(f, export, "ISO-8859-1");
218
            this.source = f;
219
        } catch (Exception e) {
220
            logger.warn("Couldn't write " + FILE_EXTENSION + " file (" + f.getAbsolutePath() + ").", e);
221
            throw e;
222
        }
223
    }
224

  
225
}
tags/org.gvsig.desktop-2.0.344/org.gvsig.desktop.compat.cdc/org.gvsig.basicformats/src/main/java/org/gvsig/basicformats/impl/DefaultPRJFile.java
1

  
2
package org.gvsig.basicformats.impl;
3

  
4

  
5
import java.io.File;
6
import java.io.IOException;
7
import org.apache.commons.io.FileUtils;
8
import org.apache.commons.io.FilenameUtils;
9
import org.apache.commons.lang3.StringUtils;
10
import org.cresques.cts.ICRSFactory;
11
import org.cresques.cts.IProjection;
12
import org.gvsig.basicformats.PRJFile;
13
import org.gvsig.fmap.crs.CRSFactory;
14
import org.slf4j.Logger;
15
import org.slf4j.LoggerFactory;
16

  
17

  
18
public class DefaultPRJFile extends AbstractFormatFile implements PRJFile {
19
            
20
    private static final Logger logger = LoggerFactory.getLogger(DefaultPRJFile.class);
21
    
22
        
23
    private File source;
24
    private IProjection crs;
25
    
26
    public DefaultPRJFile() {
27
        this.source = null;
28
        this.crs = null;        
29
    }
30

  
31
    @Override
32
    public File getFile(File file) {
33
        File f = new File(FilenameUtils.removeExtension(file.getAbsolutePath())+"."+FILE_EXTENSION);
34
        return f;
35
    }
36
    
37
    @Override
38
    public File getFile() {
39
        return source;
40
    }
41
    
42
    @Override
43
    public IProjection getCRS() {
44
        return this.crs;
45
    }
46
    
47
    @Override
48
    public void setCRS(IProjection crs) {
49
        this.crs = crs;
50
    }
51
    
52
    @Override
53
    public void read(File file) throws IOException {
54
        File f = this.getFile(file);
55
        if (f.exists()) {
56
            try {
57
                String theContents = FileUtils.readFileToString(f);
58
                if (StringUtils.isNotEmpty(theContents)){
59
                    IProjection theCrs=CRSFactory.getCRSFactory().get(ICRSFactory.FORMAT_WKT_ESRI, theContents);
60
                    this.crs = theCrs;
61
                    this.source = f.getAbsoluteFile();
62
                }
63
            } catch (IOException e) {
64
                logger.warn("Couldn't read "+FILE_EXTENSION+" file ("+f.getAbsolutePath()+").",e);
65
                throw e;
66
            }
67
        }
68
            
69
    }
70
    
71
    @Override
72
    public void write(File file) throws IOException {
73
        File f = this.getFile(file);
74
        try {
75
            String export = crs.export(ICRSFactory.FORMAT_WKT_ESRI);
76
            if(export!=null){
77
                FileUtils.writeStringToFile(f, export);
78
                this.source = f;
79
            }
80
        } catch (Exception e) {
81
            logger.warn("Couldn't write "+FILE_EXTENSION+" file ("+f.getAbsolutePath()+").",e);
82
            throw e;
83
        }
84
    }
85
}
tags/org.gvsig.desktop-2.0.344/org.gvsig.desktop.compat.cdc/org.gvsig.basicformats/src/main/java/org/gvsig/basicformats/impl/DefaultHDRFile.java
1
package org.gvsig.basicformats.impl;
2

  
3

  
4
import java.io.File;
5
import java.io.IOException;
6
import java.nio.ByteOrder;
7
import java.util.List;
8
import org.apache.commons.io.FileUtils;
9
import org.apache.commons.io.FilenameUtils;
10
import org.apache.commons.lang3.StringUtils;
11
import org.gvsig.basicformats.HDRFile;
12
import org.gvsig.fmap.geom.Geometry;
13
import org.gvsig.fmap.geom.GeometryLocator;
14
import org.gvsig.fmap.geom.primitive.Envelope;
15
import org.gvsig.fmap.geom.primitive.Point;
16
import org.gvsig.raster.lib.buffer.api.BufferManager;
17
import org.slf4j.Logger;
18
import org.slf4j.LoggerFactory;
19

  
20
public class DefaultHDRFile extends AbstractFormatFile implements HDRFile {
21

  
22
    // http://resources.esri.com/help/9.3/arcgisdesktop/com/gp_toolref/spatial_analyst_tools/esri_ascii_raster_format.htm
23
    private static final Logger logger = LoggerFactory.getLogger(DefaultHDRFile.class);
24

  
25
    private File source;
26
    private String comments;
27

  
28
    private int nrows = NONE;
29
    private int ncols = NONE;
30
    private int nbands = 1;
31
    private int nbits = 8;
32
    private String pixeltype;
33
    private String byteorder_word;
34
    private ByteOrder byteorder = ByteOrder.nativeOrder();
35
    private String layout = LAYOUT_BIL;
36
    private int skipbytes = 0;
37
    private double ulxmax = Double.NaN;
38
    private double ulymax = Double.NaN;
39
    private double xdim = Double.NaN;
40
    private double ydim = Double.NaN;
41
    private int bandrowbytes = NONE;
42
    private int totalrowbytes = NONE;
43
    private int bandgapbytes = 0;
44
    private boolean valid = false;
45
    private double nodata_value = Double.NaN;
46

  
47
    // X coordinate of the origin (by center or lower left corner of the cell).
48
    private double xllcorner = Double.NaN;
49

  
50
    // Y coordinate of the origin (by center or lower left corner of the cell).
51
    private double yllcorner = Double.NaN;
52

  
53
    private int cellsize = NONE;
54

  
55
    public DefaultHDRFile() {
56
        this.source = null;
57
    }
58

  
59
    @Override
60
    public File getFile(File file) {
61
        File f = new File(FilenameUtils.removeExtension(file.getAbsolutePath()) + "." + FILE_EXTENSION);
62
        return f;
63
    }
64

  
65
    @Override
66
    public File getFile() {
67
        return source;
68
    }
69

  
70
    @Override
71
    public void read(File file) throws IOException {
72
        File f = this.getFile(file);
73
        if (f.exists()) {
74
            try {
75
                List<String> lines = FileUtils.readLines(f);
76
                if (lines != null) {
77
                    this.source = f.getAbsoluteFile();
78
                    int lineno = 1;
79
                    for (String line : lines) {
80
                        String[] words = StringUtils.split(line.trim().toLowerCase());
81
                        try {
82
                            switch (words[0]) {
83
                                case "nrows":
84
                                    this.nrows = Integer.parseInt(words[1]);
85
                                    break;
86
                                case "ncols":
87
                                    this.ncols = Integer.parseInt(words[1]);
88
                                    break;
89
                                case "nbands":
90
                                    this.nbands = Integer.parseInt(words[1]);
91
                                    break;
92
                                case "nbits":
93
                                    this.nbits = Integer.parseInt(words[1]);
94
                                    break;
95
                                case "pixeltype":
96
                                    this.pixeltype = words[1];
97
                                    break;
98
                                case "byteorder":
99
                                    this.byteorder_word = words[1];
100
                                    break;
101
                                case "layout":
102
                                    this.layout = words[1];
103
                                    break;
104
                                case "skipbytes":
105
                                    this.skipbytes = Integer.parseInt(words[1]);
106
                                    break;
107
                                case "nodata_value":
108
                                    this.nodata_value = Double.parseDouble(words[1]);
109
                                    break;
110
                                case "cellsize":
111
                                    this.cellsize = Integer.parseInt(words[1]);
112
                                    break;
113
                                case "xllcorner":
114
                                case "xllcenter":
115
                                    this.xllcorner = Double.parseDouble(words[1]);
116
                                    break;
117
                                case "yllcorner":
118
                                case "yllcenter":
119
                                    this.yllcorner = Double.parseDouble(words[1]);
120
                                    break;
121
                                case "ulxmax":
122
                                    this.ulxmax = Double.parseDouble(words[1]);
123
                                    break;
124
                                case "ulymax":
125
                                    this.ulymax = Double.parseDouble(words[1]);
126
                                    break;
127
                                case "xdim":
128
                                    this.xdim = Double.parseDouble(words[1]);
129
                                    break;
130
                                case "ydim":
131
                                    this.ydim = Double.parseDouble(words[1]);
132
                                    break;
133
                                case "bandrowbytes":
134
                                    this.bandrowbytes = Integer.parseInt(words[1]);
135
                                    break;
136
                                case "totalrowbytes":
137
                                    this.totalrowbytes = Integer.parseInt(words[1]);
138
                                    break;
139
                                case "bandgapbytes":
140
                                    this.bandgapbytes = Integer.parseInt(words[1]);
141
                                    break;
142
                            }
143
                        } catch (NumberFormatException e) {
144
                            logger.warn("Can't parse keyword '" + words[0]
145
                                    + "' (value='" + words[1]
146
                                    + "', lineno=+" + lineno
147
                                    + ", file=" + f.getAbsoluteFile()
148
                                    + ").", e);
149
                        }
150
                        lineno++;
151
                    }
152
                    this.fixValues();
153
                }
154

  
155
            } catch (IOException e) {
156
                logger.warn("Couldn't read " + FILE_EXTENSION + " file (" + f.getAbsoluteFile() + ")", e);
157
                throw e;
158
            } catch (Exception e) {
159
                String msg = "Couldn't read " + FILE_EXTENSION + " file (" + f.getAbsoluteFile() + ")";
160
                logger.warn(msg, e);
161
                throw new IOException(msg, e);
162
            }
163
        }
164
    }
165

  
166
    private void fixValues() {
167
        @SuppressWarnings("LocalVariableHidesMemberVariable")
168
        boolean valid = true;
169

  
170
        if (this.pixeltype != null) {
171
            switch (this.pixeltype) {
172
                case "signedint":
173
                    this.nbits = 32;
174
                    break;
175
                case "byte_unsigned":
176
                    this.nbits = 8;
177
                    break;
178
            }
179
        }
180

  
181
        switch (this.getNbits()) {
182
            case 1:
183
            case 4:
184
                logger.warn("nbits keyword has a non supported value of " + this.getNbits() + " (" + this.source.getAbsolutePath() + ").");
185
                valid = false;
186
                break;
187
            case 8:
188
            case 16:
189
            case 32:
190
            case 64:
191
                break;
192
            default:
193
                logger.warn("nbits keyword has an invalid value of " + this.getNbits() + " (" + this.source.getAbsolutePath() + ").");
194
                this.nbits = 1;
195
                valid = false;
196
                break;
197
        }
198

  
199
        switch (this.getLayout()) {
200
            case LAYOUT_BIL:
201
            case LAYOUT_BIP:
202
            case LAYOUT_BSQ:
203
                break;
204
            default:
205
                logger.warn("layout keyword has an invalid value of '" + this.getLayout() + "' (" + this.source.getAbsolutePath() + ").");
206
                this.layout = LAYOUT_BIL;
207
                valid = false;
208
                break;
209
        }
210

  
211
        if( StringUtils.isEmpty(this.byteorder_word) ) {
212
            this.byteorder = ByteOrder.nativeOrder();
213
            if( this.byteorder == ByteOrder.BIG_ENDIAN ) {
214
                this.byteorder_word = "msbfirst";
215
            } else {
216
                this.byteorder_word = "lsbfirst";
217
            }
218
        } else {
219
            switch(this.byteorder_word) {
220
                case "lsbfirst":
221
                case "little_endian":
222
                case "littleendian":
223
                case "intel":
224
                case "i":
225
                    this.byteorder = ByteOrder.LITTLE_ENDIAN;
226
                    break;
227
                case "motorola":
228
                case "m":
229
                case "msbfirst":
230
                case "big_endian":
231
                case "bigendian":
232
                    this.byteorder = ByteOrder.BIG_ENDIAN;
233
                    break;
234
                default:
235
                    logger.warn("byteorder keyword has an invalid value of '" + this.byteorder_word + "' (" + this.source.getAbsolutePath() + ").");
236
                    this.byteorder = ByteOrder.nativeOrder();
237
            }
238
        }
239
        if (this.getNrows() == NONE || this.getNcols() == NONE) {
240
            logger.warn("nrows/ncols keywords has an invalid value of '" + this.getNrows() + "/" + this.getNcols() + "' (" + this.source.getAbsolutePath() + ").");
241
            valid = false;
242
        }
243
        if (this.getUlymax() == NONE) {
244
            this.ulymax = this.getNrows() - 1;
245
        }
246
        if (this.getBandrowbytes() == NONE) {
247
            this.bandrowbytes = (this.getNcols() * this.getNbits()) / 8;
248
        }
249
        switch (this.getLayout()) {
250
            case LAYOUT_BIL:
251
                if (this.getTotalrowbytes() == NONE) {
252
                    this.totalrowbytes = this.getNbands() * this.getBandrowbytes();
253
                }
254
                this.bandgapbytes = 0;
255
                break;
256
            case LAYOUT_BIP:
257
                if (this.getTotalrowbytes() == NONE) {
258
                    this.totalrowbytes = (this.getNcols() * this.getNbands() * this.getNbits()) / 8;
259
                }
260
                this.bandgapbytes = 0;
261
                break;
262
            case LAYOUT_BSQ:
263
                if (this.getTotalrowbytes() == NONE) {
264
                    this.totalrowbytes = 0;
265
                }
266
                if (this.getBandgapbytes() == NONE) {
267
                    this.bandgapbytes = 0;
268
                }
269
                break;
270
        }
271
        this.valid = valid;
272
    }
273

  
274
    @Override
275
    public int getDataType() {
276
        if (this.pixeltype != null) {
277
            switch (this.pixeltype) {
278
                case "signedint":
279
                    return BufferManager.TYPE_INT;
280
                case "byte_unsigned":
281
                    return BufferManager.TYPE_BYTE;
282
            }
283
        }
284
        switch (this.getNbits()) {
285
            case 1:
286
            case 4:
287
            default:
288
                return BufferManager.TYPE_UNDEFINED;
289
            case 8:
290
                return BufferManager.TYPE_BYTE;
291
            case 16:
292
                return BufferManager.TYPE_USHORT;
293
            case 32:
294
                return BufferManager.TYPE_INT;
295
            case 64:
296
                return BufferManager.TYPE_DOUBLE;
297
        }
298
    }
299

  
300
    @Override
301
    public void write(File file) throws IOException {
302
        File f = this.getFile(file);
303
        StringBuilder builder = new StringBuilder();
304
        builder.append("; ").append(this.comments).append("\n");
305
        builder.append("nrows ").append(this.nrows).append("\n");
306
        builder.append("ncols ").append(this.ncols).append("\n");
307
        builder.append("nbands ").append(this.nbands).append("\n");
308
        builder.append("nbits ").append(this.nbits).append("\n");
309
        builder.append("layout ").append(LAYOUT_BSQ).append("\n");
310
        builder.append("byteorder ").append(this.byteorder_word).append("\n");
311
        builder.append("ulxmax ").append(this.ulxmax).append("\n");
312
        builder.append("ulymax ").append(this.ulymax).append("\n");
313
        builder.append("ydim ").append(this.ydim).append("\n");
314
        builder.append("xdim ").append(this.xdim).append("\n");
315
        
316
        FileUtils.write(file, builder.toString());
317
    }
318
    
319
    @Override
320
    public void setByteOrder(ByteOrder order) {
321
        this.byteorder = order;
322
        if( order == ByteOrder.BIG_ENDIAN ) {
323
            this.byteorder_word = "msbfirst";
324
        } else {
325
            this.byteorder_word = "lsbfirst";
326
        }
327
    }
328
    
329
    @Override
330
    public void setNBands(int nbands) {
331
        this.nbands = nbands;
332
    }
333
    
334
    @Override
335
    public void setDataType(int dataType) {
336
        switch(dataType) {
337
            case BufferManager.TYPE_BYTE:
338
                this.nbits = 8;
339
                break;
340
            case BufferManager.TYPE_USHORT:
341
                this.nbits = 16;
342
                break;
343
            case BufferManager.TYPE_INT:
344
                this.nbits = 32;
345
                break;
346
            case BufferManager.TYPE_DOUBLE:
347
                this.nbits = 64;
348
                break;
349
            default:
350
                throw new IllegalArgumentException("The data type "+dataType +" is not supported");
351
        }
352
        
353
    }
354
    
355
    @Override
356
    public void setDimensions(int nrows, int ncols, Envelope envelope) {
357
        this.ncols = ncols;
358
        this.nrows = nrows;
359

  
360
        Point min = envelope.getLowerCorner();
361
        Point max = envelope.getUpperCorner();
362
        
363
        this.ulxmax = min.getX();
364
        this.ulymax = max.getY();
365
        this.ydim = (min.getY() - max.getY()) / this.nrows;
366
        this.xdim = (max.getX() - min.getX()) / this.ncols;
367
    }
368
    
369
    @Override
370
    public Envelope getEnvelope() {
371
        Envelope envelope = null;
372
        try {
373
            if (!Double.isNaN(this.xllcorner)
374
                    && !Double.isNaN(this.yllcorner)
375
                    && this.cellsize > 0) {
376
                envelope = GeometryLocator.getGeometryManager().createEnvelope(
377
                        this.xllcorner,
378
                        this.yllcorner,
379
                        this.xllcorner + (this.ncols * this.cellsize),
380
                        this.yllcorner + (this.nrows * this.cellsize),
381
                        Geometry.SUBTYPES.GEOM2D);
382
            }
383
            if (envelope == null && !Double.isNaN(this.ulxmax)
384
                    && !Double.isNaN(this.ulymax)
385
                    && !Double.isNaN(this.xdim)
386
                    && !Double.isNaN(this.ydim)) {
387
                envelope = GeometryLocator.getGeometryManager().createEnvelope(
388
                        this.ulxmax,
389
                        this.ulymax - (this.nrows * this.ydim),
390
                        this.ulxmax + (this.ncols * this.xdim),
391
                        this.ulymax,
392
                        Geometry.SUBTYPES.GEOM2D);
393
            }
394
            if (envelope == null && !Double.isNaN(this.xdim)
395
                    && !Double.isNaN(this.ydim)) {
396
                envelope = GeometryLocator.getGeometryManager().createEnvelope(
397
                        0,
398
                        0,
399
                        this.ncols * this.xdim,
400
                        this.nrows * this.ydim,
401
                        Geometry.SUBTYPES.GEOM2D);
402
            }
403
            if (envelope == null && this.cellsize > 0) {
404
                envelope = GeometryLocator.getGeometryManager().createEnvelope(
405
                        0,
406
                        0,
407
                        this.ncols * this.cellsize,
408
                        this.nrows * this.cellsize,
409
                        Geometry.SUBTYPES.GEOM2D);
410
            }
411
            if (envelope == null) {
412
                envelope = GeometryLocator.getGeometryManager().createEnvelope(
413
                        0,
414
                        0,
415
                        this.ncols,
416
                        this.nrows,
417
                        Geometry.SUBTYPES.GEOM2D);
418
            }
419
        } catch (Exception ex) {
420
            logger.debug("Can't calculate envelope.", ex);
421
        }
422
        return envelope;
423
    }
424

  
425
    /**
426
     * @return the nrows
427
     */
428
    @Override
429
    public int getNrows() {
430
        return nrows;
431
    }
432

  
433
    /**
434
     * @return the ncols
435
     */
436
    @Override
437
    public int getNcols() {
438
        return ncols;
439
    }
440

  
441
    /**
442
     * @return the nbands
443
     */
444
    @Override
445
    public int getNbands() {
446
        return nbands;
447
    }
448

  
449
    /**
450
     * @return the nbits
451
     */
452
    @Override
453
    public int getNbits() {
454
        return nbits;
455
    }
456

  
457
    /**
458
     * @return the byteorder
459
     */
460
    @Override
461
    public ByteOrder getByteorder() {
462
        return byteorder;
463
    }
464

  
465
    /**
466
     * @return the layout
467
     */
468
    @Override
469
    public String getLayout() {
470
        return layout;
471
    }
472

  
473
    /**
474
     * @return the skipbytes
475
     */
476
    @Override
477
    public int getSkipbytes() {
478
        return skipbytes;
479
    }
480

  
481
    /**
482
     * @return the ulxmax
483
     */
484
    @Override
485
    public double getUlxmax() {
486
        return ulxmax;
487
    }
488

  
489
    /**
490
     * @return the ulymax
491
     */
492
    @Override
493
    public double getUlymax() {
494
        return ulymax;
495
    }
496

  
497
    /**
498
     * @return the xdim
499
     */
500
    @Override
501
    public double getXdim() {
502
        return xdim;
503
    }
504

  
505
    /**
506
     * @return the ydim
507
     */
508
    @Override
509
    public double getYdim() {
510
        return ydim;
511
    }
512

  
513
    /**
514
     * @return the bandrowbytes
515
     */
516
    @Override
517
    public int getBandrowbytes() {
518
        return bandrowbytes;
519
    }
520

  
521
    /**
522
     * @return the totalrowbytes
523
     */
524
    @Override
525
    public int getTotalrowbytes() {
526
        return totalrowbytes;
527
    }
528

  
529
    /**
530
     * @return the bandgapbytes
531
     */
532
    @Override
533
    public int getBandgapbytes() {
534
        return bandgapbytes;
535
    }
536

  
537
    /**
538
     * @return the isValid
539
     */
540
    @Override
541
    public boolean isValid() {
542
        return valid;
543
    }
544

  
545
    /**
546
     * @return the comments
547
     */
548
    @Override
549
    public String getComments() {
550
        return comments;
551
    }
552

  
553
    /**
554
     * @param comments the comments to set
555
     */
556
    @Override
557
    public void setComments(String comments) {
558
        this.comments = comments;
559
    }
560

  
561
    /**
562
     * @return the nodata_value
563
     */
564
    @Override
565
    public double getNodata_value() {
566
        return nodata_value;
567
    }
568

  
569
    /**
570
     * @return the xllcorner
571
     */
572
    @Override
573
    public double getXllcorner() {
574
        return xllcorner;
575
    }
576

  
577
    /**
578
     * @return the yllcorner
579
     */
580
    @Override
581
    public double getYllcorner() {
582
        return yllcorner;
583
    }
584

  
585
    /**
586
     * @return the cellsize
587
     */
588
    @Override
589
    public int getCellsize() {
590
        return cellsize;
591
    }
592

  
593
    @Override
594
    public int getBandSize() {
595
        return (this.nrows * this.ncols * this.nbits) + this.bandgapbytes;
596
    }
597

  
598
}
tags/org.gvsig.desktop-2.0.344/org.gvsig.desktop.compat.cdc/org.gvsig.basicformats/src/main/java/org/gvsig/basicformats/impl/DefaultSTXFile.java
1

  
2
package org.gvsig.basicformats.impl;
3

  
4
import java.io.File;
5
import java.io.IOException;
6
import java.util.ArrayList;
7
import java.util.Collections;
8
import java.util.List;
9
import org.apache.commons.io.FileUtils;
10
import org.apache.commons.io.FilenameUtils;
11
import org.apache.commons.lang3.StringUtils;
12
import org.gvsig.basicformats.STXFile;
13
import org.slf4j.Logger;
14
import org.slf4j.LoggerFactory;
15

  
16

  
17
public class DefaultSTXFile extends AbstractFormatFile implements STXFile {
18

  
19
    private static final Logger logger = LoggerFactory.getLogger(DefaultSTXFile.class);
20

  
21

  
22
    private File source;
23
    private List<STXBand> bands;
24

  
25
    public static class DefaultSTXBand implements STXBand {
26

  
27
        private int band;
28
        private double minimum;
29
        private double maximum;
30
        private double mean; // Optional
31
        private double std_deviation; // Optional
32
        private double linear_stretch_min; // Optional
33
        private double linear_stretch_max; // Optional
34

  
35
        private boolean valid = false;
36

  
37
        public DefaultSTXBand() {
38

  
39
        }
40

  
41
        public DefaultSTXBand(
42
            int band,
43
            double minimum,
44
            double maximum,
45
            double mean,
46
            double std_deviation,
47
            double linear_stretch_min,
48
            double linear_stretch_max
49
            ) {
50
            this();
51
            this.band = band;
52
            this.minimum = minimum;
53
            this.maximum = maximum;
54
            this.mean = mean;
55
            this.std_deviation = std_deviation;
56
            this.linear_stretch_min = linear_stretch_min;
57
            this.linear_stretch_max = linear_stretch_max;
58
        }
59

  
60
        @SuppressWarnings("OverridableMethodCallInConstructor")
61
        public DefaultSTXBand(String line) {
62
            this();
63
            this.parse(line);
64
        }
65

  
66
        @Override
67
        public void parse(String line) {
68
            valid = false;
69
            String[] words = StringUtils.split(line.trim().toLowerCase());
70
            if( words.length < 7 ) {
71
                throw new IllegalArgumentException("At least 7 parameters are needed ("+line+").");
72
            }
73
            this.band = Integer.parseInt(words[0]);
74
            this.minimum = Double.parseDouble(words[1]);
75
            this.maximum = Double.parseDouble(words[2]);
76
            if( "#".equals(words[3]) ) {
77
                this.mean = Double.NaN;
78
            } else {
79
                this.mean = Double.parseDouble(words[3]);
80
            }
81
            if( "#".equals(words[4]) ) {
82
                this.std_deviation = Double.NaN;
83
            } else {
84
                this.std_deviation = Double.parseDouble(words[4]);
85
            }
86
            if( "#".equals(words[5]) ) {
87
                this.linear_stretch_min = Double.NaN;
88
            } else {
89
                this.linear_stretch_min = Double.parseDouble(words[5]);
90
            }
91
            if( "#".equals(words[6]) ) {
92
                this.linear_stretch_max = Double.NaN;
93
            } else {
94
                this.linear_stretch_max = Double.parseDouble(words[6]);
95
            }
96
            valid = true;
97
        }
98

  
99
        @Override
100
        public String toString() {
101
            StringBuilder builder = new StringBuilder();
102
            builder.append(this.band).append(" ");
103
            builder.append(this.minimum).append(" ");
104
            builder.append(this.maximum).append(" ");
105
            if( Double.isNaN(this.mean) ) {
106
                builder.append("# ");
107
            } else {
108
                builder.append(this.mean).append(" ");
109
            }
110
            if( Double.isNaN(this.std_deviation) ) {
111
                builder.append("# ");
112
            } else {
113
                builder.append(this.std_deviation).append(" ");
114
            }
115
            if( Double.isNaN(this.linear_stretch_min) ) {
116
                builder.append("# ");
117
            } else {
118
                builder.append(this.linear_stretch_min).append(" ");
119
            }
120
            if( Double.isNaN(this.linear_stretch_max) ) {
121
                builder.append("# ");
122
            } else {
123
                builder.append(this.linear_stretch_max).append(" ");
124
            }
125
            return builder.toString();
126
        }
127

  
128
        @Override
129
        public int getBand() {
130
            return band;
131
        }
132

  
133
        @Override
134
        public double getMinimum() {
135
            return minimum;
136
        }
137

  
138
        @Override
139
        public double getMaximum() {
140
            return maximum;
141
        }
142

  
143
        @Override
144
        public double getMean() {
145
            return mean;
146
        }
147

  
148
        @Override
149
        public double getStdDeviation() {
150
            return std_deviation;
151
        }
152

  
153
        @Override
154
        public double getLinearStretchMin() {
155
            return linear_stretch_min;
156
        }
157

  
158
        @Override
159
        public double getLinearStretchMax() {
160
            return linear_stretch_max;
161
        }
162

  
163
        @Override
164
        public boolean isValid() {
165
            return valid;
166
        }
167
    }
168

  
169
   public DefaultSTXFile() {
170
        this.source = null;
171
        this.bands = new ArrayList<>();
172
    }
173

  
174
    @Override
175
    public File getFile(File file) {
176
        File f = new File(FilenameUtils.removeExtension(file.getAbsolutePath())+"."+FILE_EXTENSION);
177
        return f;
178
    }
179

  
180
    @Override
181
    public File getFile() {
182
        return source;
183
    }
184

  
185
    @Override
186
    public void read(File file) throws IOException {
187
        File f = this.getFile(file);
188
        if (f.exists()) {
189
            try {
190
                this.bands = new ArrayList<>();
191
                List<String> lines = FileUtils.readLines(f);
192
                if (lines != null) {
193
                    this.source = f.getAbsoluteFile();
194
                    int lineno = 1;
195
                    for (String line : lines) {
196
                        try {
197
                            DefaultSTXBand band = new DefaultSTXBand(line.trim());
198
                            this.bands.add(band);
199
                        } catch(IllegalArgumentException e) {
200
                            logger.warn("Can't parse line '" + line
201
                                    + "' (lineno=+" + lineno
202
                                    + ", file=" + f.getAbsoluteFile()
203
                                    + ").", e);
204

  
205
                        }
206
                    }
207
                }
208
                this.bands = Collections.unmodifiableList(this.bands);
209
            } catch (IOException e) {
210
                logger.warn("Couldn't read "+FILE_EXTENSION+" file (" + f.getAbsoluteFile() + ")", e);
211
                throw e;
212
            }
213
        }
214
    }
215

  
216
    @Override
217
    public List<STXBand> getBands() {
218
        return this.bands;
219
    }
220

  
221
    @Override
222
    public void clear() {
223
        this.bands = new ArrayList<>();
224
    }
225

  
226
    @Override
227
    public void addBand(
228
            int band,
229
            double minimum,
230
            double maximum,
231
            double mean,
232
            double std_deviation,
233
            double linear_stretch_min,
234
            double linear_stretch_max
235
        ) {
236
        DefaultSTXBand b = new DefaultSTXBand(band, minimum, maximum, mean, std_deviation, linear_stretch_min, linear_stretch_max);
237
        this.bands.add(b);
238
    }
239

  
240
    @Override
241
    public void write(File file) throws IOException {
242
        File f = this.getFile(file);
243
        List<String> lines = new ArrayList<>();
244
        for (STXBand band : this.bands) {
245
            lines.add(band.toString());
246
        }
247
        FileUtils.writeLines(f, lines);
248
        this.source = f;
249
    }
250
}
tags/org.gvsig.desktop-2.0.344/org.gvsig.desktop.compat.cdc/org.gvsig.basicformats/src/main/java/org/gvsig/basicformats/impl/DefaultCLRFile.java
1
package org.gvsig.basicformats.impl;
2

  
3
import java.awt.Color;
4
import java.io.File;
5
import java.io.IOException;
6
import java.util.ArrayList;
7
import java.util.List;
8
import org.apache.commons.io.FileUtils;
9
import org.apache.commons.io.FilenameUtils;
10
import org.apache.commons.lang3.StringUtils;
11
import org.gvsig.basicformats.CLRFile;
12
import org.gvsig.raster.lib.legend.api.RasterLegendLocator;
13
import org.gvsig.raster.lib.legend.api.RasterLegendManager;
14
import org.gvsig.raster.lib.legend.api.colortable.ColorTable;
15
import org.gvsig.raster.lib.legend.api.colortable.colortableclass.ColorTableClass;
16
import org.slf4j.Logger;
17
import org.slf4j.LoggerFactory;
18

  
19
public class DefaultCLRFile extends AbstractFormatFile implements CLRFile {
20

  
21
    private static final Logger logger = LoggerFactory.getLogger(DefaultCLRFile.class);
22

  
23
    private File source;
24
    private ColorTable colorTable;
25

  
26
    public DefaultCLRFile() {
27
        this.source = null;
28
        this.colorTable = null;
29
    }
30

  
31
    @Override
32
    public File getFile(File file) {
33
        File f = new File(FilenameUtils.removeExtension(file.getAbsolutePath()) + "." + FILE_EXTENSION);
34
        return f;
35
    }
36

  
37
    @Override
38
    public File getFile() {
39
        return source;
40
    }
41

  
42
    @Override
43
    public ColorTable getColorTable() {
44
        return this.colorTable;
45
    }
46

  
47
    @Override
48
    public void setColorTable(ColorTable colorTable) {
49
        this.colorTable = colorTable;
50
    }
51

  
52
    @Override
53
    public void read(File file) throws IOException {
54
        File f = this.getFile(file);
55
        if (f.exists()) {
56
            try {
57
                RasterLegendManager legendManager = RasterLegendLocator.getRasterLegendManager();
58
                List<ColorTableClass> colors = new ArrayList<>();
59
                List<String> lines = FileUtils.readLines(f);
60
                if (lines != null) {
61
                    this.source = f.getAbsoluteFile();
62
                    int lineno = 1;
63
                    double interpolation = 50.0;
64
                    for (String line : lines) {
65
                        line = line.trim();
66
                        if (!Character.isDigit(line.charAt(0))) {
67
                            continue;
68
                        }
69
                        try {
70
                            String[] words = StringUtils.split(line);
71
                            if (words.length < 4) {
72
                                continue;
73
                            }
74
                            int value = Integer.parseInt(words[0]);
75
                            int r = Integer.parseInt(words[1]);
76
                            int g = Integer.parseInt(words[2]);
77
                            int b = Integer.parseInt(words[3]);
78
                            Color color = new Color(r, g, b);
79

  
80
                            ColorTableClass colorTableClass = legendManager.createColorTableClass(
81
                                    String.valueOf(value), value, interpolation, color);
82

  
83
                            colors.add(colorTableClass);
84
                        } catch (Exception e) {
85
                            logger.warn("Can't parse line '" + line
86
                                    + "' (lineno=+" + lineno
87
                                    + ", file=" + f.getAbsoluteFile()
88
                                    + ").", e);
89

  
90
                        }
91
                    }
92
                }
93
                if( !colors.isEmpty() ) {
94
                    String colorTableName = FilenameUtils.getBaseName(f.getName());
95
                    this.colorTable = legendManager.createColorTable(colorTableName, colors, true);
96
                }
97
            } catch (IOException e) {
98
                logger.warn("Couldn't read " + FILE_EXTENSION + " file (" + f.getAbsoluteFile() + ")", e);
99
                throw e;
100
            }
101
        }
102

  
103
    }
104

  
105
    @Override
106
    public void write(File file) throws IOException {
107
        File f = this.getFile(file);
108
        // TODO: falta implementar guardar la CLR
109
    }
110

  
111
}
tags/org.gvsig.desktop-2.0.344/org.gvsig.desktop.compat.cdc/org.gvsig.basicformats/src/main/java/org/gvsig/basicformats/impl/DefaultWLDFile.java
1
package org.gvsig.basicformats.impl;
2

  
3
import java.io.File;
4
import java.io.IOException;
5
import java.util.List;
6
import org.apache.commons.io.FileUtils;
7
import org.apache.commons.io.FilenameUtils;
8
import org.gvsig.basicformats.WLDFile;
9
import org.gvsig.fmap.geom.Geometry;
10
import org.gvsig.fmap.geom.GeometryLocator;
11
import org.gvsig.fmap.geom.primitive.Envelope;
12
import org.slf4j.Logger;
13
import org.slf4j.LoggerFactory;
14

  
15

  
16
public class DefaultWLDFile extends AbstractFormatFile implements WLDFile {
17
    
18
    private static final Logger logger = LoggerFactory.getLogger(DefaultWLDFile.class);
19
    
20
        
21
    private File source;
22
    
23
    private double pixelSizeX;
24
    private double rotationAxisY;
25
    private double rotationAxisX;
26
    private double pixelSizeY;
27
    private double upperLeftPixelCenterCoordX;
28
    private double upperLeftPixelCenterCoordY;
29

  
30
    public DefaultWLDFile() {
31
        this.source = null;
32
    }
33
    
34
    @Override
35
    public File getFile(File file) {
36
        File f = new File(FilenameUtils.removeExtension(file.getAbsolutePath())+"."+FILE_EXTENSION);
37
        return f;
38
    }
39
    
40
    @Override
41
    public File getFile() {
42
        return source;
43
    }
44

  
45
    @Override
46
    public void read(File file) throws IOException {
47
        File f = this.getFile(file);
48
        if (f.exists()) {
49
            try {
50
                List<String> lines = FileUtils.readLines(f);
51
                if (lines!=null ) {
52
                    this.source = f.getAbsoluteFile();
53
                    int lineno = 0;
54
                    for (String line : lines) {
55
                        line = line.trim();
56
                        char ch = line.charAt(0);
57
                        if( lineno>5 || Character.isLetter(ch) || ch==';' || ch=='#' ) {
58
                            continue;
59
                        }
60
                        try {
61
                            double value = Double.parseDouble(line);
62
                            switch(lineno) {
63
                                case 0:
64
                                    this.pixelSizeX=value;
65
                                    break;
66
                                case 1:
67
                                    this.rotationAxisY = value;
68
                                    break;
69
                                case 2:
70
                                    this.rotationAxisX = value;
71
                                    break;
72
                                case 3:
73
                                    this.pixelSizeY = value;
74
                                    break;
75
                                case 4:
76
                                    this.upperLeftPixelCenterCoordX = value;
77
                                    break;
78
                                case 5:
79
                                    this.upperLeftPixelCenterCoordY = value;
80
                                    break;
81
                            }
82
                            lineno++;
83
                        } catch(NumberFormatException e) {
84
                            
85
                        }
86
                    }
87
                }
88

  
89
            } catch (IOException e) {
90
                logger.warn("Couldn't read "+FILE_EXTENSION+" file ("+f.getAbsolutePath()+").",e);
91
                throw e;
92
            }
93
        }
94
    }
95

  
96
    @Override
97
    public Envelope getEnvelope(int rows, int columns) {
98
        Envelope envelope = null;
99
        if (0.0 != getRotationAxisX() || 0.0 != getRotationAxisY()) {
100
            logger.warn("Rotation in wld file not implemented yet. It will be ignored");
101
        }
102

  
103
        double leftMostX = 0;
104
        double upperMostY = 0;
105
        double height = 0;
106
        double width = 0;
107
        try {
108
            leftMostX = getUpperLeftPixelCenterCoordX() - (getPixelSizeX() * 0.5);
109
            upperMostY = getUpperLeftPixelCenterCoordY() - (getPixelSizeY() * 0.5);
110
            height=rows*getPixelSizeY();
111
            width=columns*getPixelSizeX();
112

  
113
            envelope = GeometryLocator.getGeometryManager().createEnvelope(
114
                Math.min(leftMostX,leftMostX + width),
115
                Math.min(upperMostY,upperMostY + height),
116
                Math.max(leftMostX,leftMostX + width),
117
                Math.max(upperMostY,upperMostY + height),
118
                Geometry.SUBTYPES.GEOM2D);
119
        } catch (Exception e) {
120
            logger.warn(
121
                "Failed to create envelope from wld file with coords: minx:"+leftMostX+
122
                ", miny:"+upperMostY+", maxX: "+leftMostX + width+", maxY: "+upperMostY + height, e);
123
        }
124
        return envelope;        
125
    }
126
    
127
    @Override
128
    public void write(File file) {
129
        // TODO: Falta implementar el write del WLDFile
130
        File f = this.getFile(file);
131

  
132
    }
133
    
134
    @Override
135
    public void setValue(Envelope envelope, int rows, int columns) {
136
        // TODO: Falta implementar el setValue del WLDFile
137
    }
138

  
139
    /**
140
     * @return the pixelSizeX
141
     */
142
    @Override
143
    public double getPixelSizeX() {
144
        return pixelSizeX;
145
    }
146

  
147
    /**
148
     * @return the rotationAxisY
149
     */
150
    @Override
151
    public double getRotationAxisY() {
152
        return rotationAxisY;
153
    }
154

  
155
    /**
156
     * @return the rotationAxisX
157
     */
158
    @Override
159
    public double getRotationAxisX() {
160
        return rotationAxisX;
161
    }
162

  
163
    /**
164
     * @return the pixelSizeY
165
     */
166
    @Override
167
    public double getPixelSizeY() {
168
        return pixelSizeY;
169
    }
170

  
171
    /**
172
     * @return the upperLeftPixelCenterCoordX
173
     */
174
    @Override
175
    public double getUpperLeftPixelCenterCoordX() {
176
        return upperLeftPixelCenterCoordX;
177
    }
178

  
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff