001/*
002 * Copyright 2010-2015 Institut Pasteur.
003 * 
004 * This file is part of Icy.
005 * 
006 * Icy is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 * 
011 * Icy is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 * GNU General Public License for more details.
015 * 
016 * You should have received a copy of the GNU General Public License
017 * along with Icy. If not, see <http://www.gnu.org/licenses/>.
018 */
019package icy.type;
020
021import icy.math.MathUtil;
022import icy.vtk.VtkUtil;
023
024import java.awt.image.DataBuffer;
025import java.util.ArrayList;
026
027import loci.formats.FormatTools;
028import ome.xml.model.enums.PixelType;
029
030/**
031 * DataType class.<br>
032 * This class is used to define the internal native data type of a given object.
033 * 
034 * @author Stephane
035 */
036public enum DataType
037{
038    // UBYTE (unsigned 8 bits integer)
039    UBYTE(Byte.SIZE, true, false, 0d, MathUtil.POW2_8_DOUBLE - 1d, Byte.TYPE, DataBuffer.TYPE_BYTE, PixelType.UINT8,
040            "unsigned byte (8 bits)", "8 bits"),
041    // BYTE (signed 8 bits integer)
042    BYTE(Byte.SIZE, true, true, Byte.MIN_VALUE, Byte.MAX_VALUE, Byte.TYPE, DataBuffer.TYPE_BYTE, PixelType.INT8,
043            "signed byte (8 bits)", "8 bits (signed)"),
044    // USHORT (unsigned 16 bits integer)
045    USHORT(Short.SIZE, true, false, 0d, MathUtil.POW2_16_DOUBLE - 1d, Short.TYPE, DataBuffer.TYPE_USHORT,
046            PixelType.UINT16, "unsigned short (16 bits)", "16 bits"),
047    // SHORT (signed 16 bits integer)
048    SHORT(Short.SIZE, true, true, Short.MIN_VALUE, Short.MAX_VALUE, Short.TYPE, DataBuffer.TYPE_SHORT, PixelType.INT16,
049            "signed short (16 bits)", "16 bits (signed)"),
050    // UINT (unsigned 32bits integer)
051    UINT(Integer.SIZE, true, false, 0d, MathUtil.POW2_32_DOUBLE - 1d, Integer.TYPE, DataBuffer.TYPE_INT,
052            PixelType.UINT32, "unsigned int (32 bits)", "32 bits"),
053    // INT (signed 32 bits integer)
054    INT(Integer.SIZE, true, true, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.TYPE, DataBuffer.TYPE_INT,
055            PixelType.INT32, "signed int (32 bits)", "32 bits (signed)"),
056    // ULONG (unsigned 64 bits integer)
057    // WARNING : double data type loss information here for min/max
058    ULONG(Long.SIZE, true, false, 0d, MathUtil.POW2_64_DOUBLE - 1d, Long.TYPE, DataBuffer.TYPE_UNDEFINED, null,
059            "unsigned long (64 bits)", "64 bits"),
060    // LONG (signed 64 bits integer)
061    // WARNING : double data type loss information here for min/max
062    LONG(Long.SIZE, true, true, Long.MIN_VALUE, Long.MAX_VALUE, Long.TYPE, DataBuffer.TYPE_UNDEFINED, null,
063            "signed long (64 bits)", "64 bits (signed)"),
064    // FLOAT (signed 32 bits float)
065    FLOAT(Float.SIZE, false, true, -Float.MAX_VALUE, Float.MAX_VALUE, Float.TYPE, DataBuffer.TYPE_FLOAT,
066            PixelType.FLOAT, "float (32 bits)", "float"),
067    // DOUBLE (signed 64 bits float)
068    DOUBLE(Double.SIZE, false, true, -Double.MAX_VALUE, Double.MAX_VALUE, Double.TYPE, DataBuffer.TYPE_DOUBLE,
069            PixelType.DOUBLE, "double (64 bits)", "double"),
070    // UNDEFINED (undefined data type)
071    /**
072     * @deprecated Use <code>null</code> instance instead
073     */
074    @SuppressWarnings("dep-ann")
075    UNDEFINED(0, true, false, 0d, 0d, null, DataBuffer.TYPE_UNDEFINED, null, "undefined", "undefined");
076
077    /**
078     * cached
079     */
080    public static final double UBYTE_MAX_VALUE = MathUtil.POW2_8_DOUBLE - 1;
081    public static final double USHORT_MAX_VALUE = MathUtil.POW2_16_DOUBLE - 1;
082    public static final double UINT_MAX_VALUE = MathUtil.POW2_32_DOUBLE - 1;
083    public static final double ULONG_MAX_VALUE = MathUtil.POW2_64_DOUBLE - 1;
084    public static final double INT_MIN_VALUE = Integer.MIN_VALUE;
085    public static final double LONG_MIN_VALUE = Long.MIN_VALUE;
086    public static final double INT_MAX_VALUE = Integer.MAX_VALUE;
087    public static final double LONG_MAX_VALUE = Long.MAX_VALUE;
088
089    public static final float UBYTE_MAX_VALUE_F = MathUtil.POW2_8_FLOAT - 1;
090    public static final float USHORT_MAX_VALUE_F = MathUtil.POW2_16_FLOAT - 1;
091    public static final float UINT_MAX_VALUE_F = MathUtil.POW2_32_FLOAT - 1;
092    public static final float ULONG_MAX_VALUE_F = MathUtil.POW2_64_FLOAT - 1;
093    public static final float INT_MIN_VALUE_F = Integer.MIN_VALUE;
094    public static final float LONG_MIN_VALUE_F = Long.MIN_VALUE;
095    public static final float INT_MAX_VALUE_F = Integer.MAX_VALUE;
096    public static final float LONG_MAX_VALUE_F = Long.MAX_VALUE;
097
098    /**
099     * Return all dataType as String items array (can be used for ComboBox).<br>
100     * 
101     * @param javaTypeOnly
102     *        Define if we want only java compatible data type (no unsigned integer types)
103     * @param longString
104     *        Define if we want long string format (bpp information)
105     * @param wantUndef
106     *        Define if we want the UNDEFINED data type in the list
107     */
108    public static String[] getItems(boolean javaTypeOnly, boolean longString, boolean wantUndef)
109    {
110        final ArrayList<String> result = new ArrayList<String>();
111
112        for (DataType dataType : DataType.values())
113            if (((!javaTypeOnly) || dataType.isJavaType()) && (wantUndef || (dataType != UNDEFINED)))
114                result.add(dataType.toString(longString));
115
116        return result.toArray(new String[result.size()]);
117    }
118
119    /**
120     * Return a DataType from the specified string.<br>
121     * ex : <code>getDataType("byte")</code> will return <code>DataType.BYTE</code>
122     */
123    public static DataType getDataType(String value)
124    {
125        for (DataType dataType : DataType.values())
126            if (dataType.toString(false).equals(value) || dataType.toString(true).equals(value))
127                return dataType;
128
129        return null;
130    }
131
132    /**
133     * Return a DataType from old dataType.<br>
134     * ex : <code>getDataTypeFromOldDataType(TypeUtil.BYTE, false)</code> will return <code>DataType.UBYTE</code>
135     */
136    public static DataType getDataType(int oldDataType, boolean signed)
137    {
138        switch (oldDataType)
139        {
140            case TypeUtil.TYPE_BYTE:
141                if (signed)
142                    return BYTE;
143                return UBYTE;
144            case TypeUtil.TYPE_SHORT:
145                if (signed)
146                    return SHORT;
147                return USHORT;
148            case TypeUtil.TYPE_INT:
149                if (signed)
150                    return INT;
151                return UINT;
152            case TypeUtil.TYPE_FLOAT:
153                return FLOAT;
154            case TypeUtil.TYPE_DOUBLE:
155                return DOUBLE;
156            default:
157                return null;
158        }
159    }
160
161    /**
162     * Return a DataType from old dataType.<br>
163     * ex : <code>getDataType(TypeUtil.BYTE)</code> will return <code>DataType.BYTE</code>
164     */
165    public static DataType getDataType(int oldDataType)
166    {
167        return getDataType(oldDataType, true);
168    }
169
170    /**
171     * Return a DataType from the specified primitive class type
172     */
173    public static DataType getDataType(Class<?> classType)
174    {
175        if (classType.equals(java.lang.Byte.TYPE))
176            return DataType.BYTE;
177        if (classType.equals(java.lang.Short.TYPE))
178            return DataType.SHORT;
179        if (classType.equals(java.lang.Integer.TYPE))
180            return DataType.INT;
181        if (classType.equals(java.lang.Long.TYPE))
182            return DataType.LONG;
183        if (classType.equals(java.lang.Float.TYPE))
184            return DataType.FLOAT;
185        if (classType.equals(java.lang.Double.TYPE))
186            return DataType.DOUBLE;
187
188        return null;
189    }
190
191    /**
192     * Return a DataType from the specified VTK type.<br>
193     * ex : <code>getDataTypeFromVTKType(VtkUtil.VTK_INT)</code> will return <code>DataType.INT</code>
194     */
195    public static DataType getDataTypeFromVTKType(int vtkType)
196    {
197        switch (vtkType)
198        {
199            case VtkUtil.VTK_UNSIGNED_CHAR:
200                return UBYTE;
201            case VtkUtil.VTK_CHAR:
202            case VtkUtil.VTK_SIGNED_CHAR:
203                return BYTE;
204            case VtkUtil.VTK_UNSIGNED_SHORT:
205                return USHORT;
206            case VtkUtil.VTK_SHORT:
207                return SHORT;
208            case VtkUtil.VTK_UNSIGNED_INT:
209                return UINT;
210            case VtkUtil.VTK_INT:
211                return INT;
212            case VtkUtil.VTK_FLOAT:
213                return FLOAT;
214            case VtkUtil.VTK_DOUBLE:
215                return DOUBLE;
216            case VtkUtil.VTK_UNSIGNED_LONG:
217                return ULONG;
218            case VtkUtil.VTK_LONG:
219                return LONG;
220            default:
221                return null;
222        }
223    }
224
225    /**
226     * Return a DataType from the specified DataBuffer type.<br>
227     * ex : <code>getDataTypeFromDataBufferType(DataBuffer.TYPE_BYTE)</code> will return <code>DataType.UBYTE</code>
228     */
229    public static DataType getDataTypeFromDataBufferType(int dataBufferType)
230    {
231        switch (dataBufferType)
232        {
233            case DataBuffer.TYPE_BYTE:
234                // consider as unsigned by default
235                return UBYTE;
236            case DataBuffer.TYPE_SHORT:
237                return SHORT;
238            case DataBuffer.TYPE_USHORT:
239                return USHORT;
240            case DataBuffer.TYPE_INT:
241                // consider as unsigned by default
242                return UINT;
243            case DataBuffer.TYPE_FLOAT:
244                return FLOAT;
245            case DataBuffer.TYPE_DOUBLE:
246                return DOUBLE;
247            default:
248                return null;
249        }
250    }
251
252    /**
253     * Return a DataType from the specified FormatTools type.<br>
254     * ex : <code>getDataTypeFromFormatToolsType(FormatTools.UINT8)</code> will return <code>DataType.UBYTE</code>
255     */
256    public static DataType getDataTypeFromFormatToolsType(int type)
257    {
258        switch (type)
259        {
260            case FormatTools.INT8:
261                return BYTE;
262            case FormatTools.UINT8:
263                return UBYTE;
264            case FormatTools.INT16:
265                return SHORT;
266            case FormatTools.UINT16:
267                return USHORT;
268            case FormatTools.INT32:
269                return INT;
270            case FormatTools.UINT32:
271                return UINT;
272            case FormatTools.FLOAT:
273                return FLOAT;
274            case FormatTools.DOUBLE:
275                return DOUBLE;
276            default:
277                return null;
278        }
279    }
280
281    /**
282     * Return a DataType from the specified PixelType.<br>
283     * ex : <code>getDataTypeFromPixelType(FormatTools.UINT8)</code> will return <code>DataType.UBYTE</code>
284     */
285    public static DataType getDataTypeFromPixelType(PixelType type)
286    {
287        switch (type)
288        {
289            case INT8:
290                return BYTE;
291            case UINT8:
292                return UBYTE;
293            case INT16:
294                return SHORT;
295            case UINT16:
296                return USHORT;
297            case INT32:
298                return INT;
299            case UINT32:
300                return UINT;
301            case FLOAT:
302                return FLOAT;
303            case DOUBLE:
304                return DOUBLE;
305            default:
306                return null;
307        }
308    }
309
310    /**
311     * internals properties
312     */
313    protected String longString;
314    protected String string;
315    protected int bitSize;
316    protected boolean integer;
317    protected boolean signed;
318    protected double min;
319    protected double max;
320    protected Class<?> primitiveClass;
321    protected int dataBufferType;
322    protected PixelType pixelType;
323
324    private DataType(int bitSize, boolean integer, boolean signed, double min, double max, Class<?> primitiveClass,
325            int dataBufferType, PixelType pixelType, String longString, String string)
326    {
327        this.bitSize = bitSize;
328        this.integer = integer;
329        this.signed = signed;
330        this.min = min;
331        this.max = max;
332        this.primitiveClass = primitiveClass;
333        this.dataBufferType = dataBufferType;
334        this.pixelType = pixelType;
335        this.longString = longString;
336        this.string = string;
337    }
338
339    /**
340     * Return the java compatible data type (signed integer type only).<br>
341     * Can be only one of the following :<br>
342     * {@link DataType#BYTE}<br>
343     * {@link DataType#SHORT}<br>
344     * {@link DataType#INT}<br>
345     * {@link DataType#LONG}<br>
346     * {@link DataType#FLOAT}<br>
347     * {@link DataType#DOUBLE}<br>
348     */
349    public DataType getJavaType()
350    {
351        switch (this)
352        {
353            case UBYTE:
354                return BYTE;
355            case USHORT:
356                return SHORT;
357            case UINT:
358                return INT;
359            case ULONG:
360                return LONG;
361
362            default:
363                return this;
364        }
365    }
366
367    /**
368     * Return the minimum value for current DataType
369     */
370    public double getMinValue()
371    {
372        return min;
373    }
374
375    /**
376     * Return the maximum value for current DataType
377     */
378    public double getMaxValue()
379    {
380        return max;
381    }
382
383    /**
384     * Get the default bounds for current DataType.<br>
385     * This actually returns <code>[0,1]</code> for Float or Double DataType.
386     */
387    public double[] getDefaultBounds()
388    {
389        if (!integer)
390            return new double[] {0d, 1d};
391
392        return new double[] {getMinValue(), getMaxValue()};
393    }
394
395    /**
396     * Get the bounds <code>[min,max]</code> for current DataType.
397     */
398    public double[] getBounds()
399    {
400        return new double[] {getMinValue(), getMaxValue()};
401    }
402
403    /**
404     * Return true if this is a compatible java data type (signed integer type only)
405     */
406    public boolean isJavaType()
407    {
408        return this == getJavaType();
409    }
410
411    /**
412     * Return true if this is a signed data type
413     */
414    public boolean isSigned()
415    {
416        return signed;
417    }
418
419    /**
420     * Return true if this is a float data type
421     */
422    public boolean isFloat()
423    {
424        return !isInteger();
425    }
426
427    /**
428     * Return true if this is an integer data type
429     */
430    public boolean isInteger()
431    {
432        return integer;
433    }
434
435    /**
436     * @deprecated Use {@link #getSize()} instead
437     */
438    @Deprecated
439    public int sizeOf()
440    {
441        return getSize();
442    }
443
444    /**
445     * Return the size (in byte) of the specified dataType
446     */
447    public int getSize()
448    {
449        return getBitSize() / 8;
450    }
451
452    /**
453     * Return the size (in bit) of the specified dataType
454     */
455    public int getBitSize()
456    {
457        return bitSize;
458    }
459
460    /**
461     * Return true if specified data type has same "basic" type (no sign information) data type
462     */
463    public boolean isSameJavaType(DataType dataType)
464    {
465        return dataType.getJavaType() == getJavaType();
466    }
467
468    /**
469     * Return the corresponding primitive class type corresponding to this DataType.
470     */
471    public Class<?> toPrimitiveClass()
472    {
473        return primitiveClass;
474    }
475
476    /**
477     * Return the DataBuffer type corresponding to current DataType
478     */
479    public int toDataBufferType()
480    {
481        return dataBufferType;
482    }
483
484    /**
485     * Return the PixelType corresponding to current DataType
486     */
487    public PixelType toPixelType()
488    {
489        return pixelType;
490    }
491
492    /**
493     * Convert DataType to String.<br>
494     * 
495     * @param longString
496     *        Define if we want long description (bpp information)
497     */
498    public String toString(boolean longString)
499    {
500        if (longString)
501            return toLongString();
502
503        return toString();
504    }
505
506    /**
507     * Convert DataType to long String (long description with bpp information)
508     */
509    public String toLongString()
510    {
511        return longString;
512    }
513
514    @Override
515    public String toString()
516    {
517        return string;
518    }
519}