ncsa.hdf.view.Tools Maven / Gradle / Ivy
/*****************************************************************************
* Copyright by The HDF Group. *
* Copyright by the Board of Trustees of the University of Illinois. *
* All rights reserved. *
* *
* This file is part of the HDF Java Products distribution. *
* The full copyright notice, including terms governing use, modification, *
* and redistribution, is contained in the files COPYING and Copyright.html. *
* COPYING can be found at the root of the source code distribution tree. *
* Or, see http://hdfgroup.org/products/hdf-java/doc/Copyright.html. *
* If you do not have access to either file, you may request a copy from *
* [email protected]. *
****************************************************************************/
package ncsa.hdf.view;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.DirectColorModel;
import java.awt.image.IndexColorModel;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.util.BitSet;
import java.util.StringTokenizer;
import javax.imageio.ImageIO;
import javax.swing.tree.DefaultMutableTreeNode;
import ncsa.hdf.object.Datatype;
import ncsa.hdf.object.FileFormat;
import ncsa.hdf.object.Group;
import ncsa.hdf.object.ScalarDS;
import ncsa.hdf.view.ViewProperties.BITMASK_OP;
/**
* The "Tools" class contains various of tools for HDF files such as jpeg to HDF
* converter.
*
* @author Peter X. Cao
* @version 2.4 9/6/2007
*/
public final class Tools {
public static final long MAX_INT8 = 127;
public static final long MAX_UINT8 = 255;
public static final long MAX_INT16 = 32767;
public static final long MAX_UINT16 = 65535;
public static final long MAX_INT32 = 2147483647;
public static final long MAX_UINT32 = 4294967295L;
public static final long MAX_INT64 = 9223372036854775807L;
public static final BigInteger MAX_UINT64 = new BigInteger("18446744073709551615");
/** Key for JPEG image file type. */
public static final String FILE_TYPE_JPEG = "JPEG";
/** Key for TIFF image file type. */
public static final String FILE_TYPE_TIFF = "TIFF";
/** Key for PNG image file type. */
public static final String FILE_TYPE_PNG = "PNG";
/** Key for GIF image file type. */
public static final String FILE_TYPE_GIF = "GIF";
/** Key for BMP image file type. */
public static final String FILE_TYPE_BMP = "BMP";
/** Key for all image file type. */
public static final String FILE_TYPE_IMAGE = "IMG";
/** Print out debug information */
public static final void debug(Object caller, Object msg) {
if (caller != null) System.out.println("*** " + caller.getClass().getName() + ": " + msg);
}
/**
* Converts an image file into HDF4/5 file.
*
* @param imgFileName
* the input image file.
* @param hFileName
* the name of the HDF4/5 file.
* @param fromType
* the type of image.
* @param toType
* the type of file converted to.
*/
public static void convertImageToHDF(String imgFileName, String hFileName, String fromType, String toType)
throws Exception {
File imgFile = null;
if (imgFileName == null) {
throw new NullPointerException("The source image file is null.");
}
else if (!(imgFile = new File(imgFileName)).exists()) {
throw new NullPointerException("The source image file does not exist.");
}
else if (hFileName == null) {
throw new NullPointerException("The target HDF file is null.");
}
if (!fromType.equals(FILE_TYPE_IMAGE)) {
throw new UnsupportedOperationException("Unsupported image type.");
}
else if (!(toType.equals(FileFormat.FILE_TYPE_HDF4) || toType.equals(FileFormat.FILE_TYPE_HDF5))) {
throw new UnsupportedOperationException("Unsupported destination file type.");
}
BufferedImage image = null;
try {
BufferedInputStream in = new BufferedInputStream(new FileInputStream(imgFileName));
image = ImageIO.read(in);
in.close();
}
catch (Throwable err) {
image = null;
}
if (image == null) throw new UnsupportedOperationException("Failed to read image: " + imgFileName);
int h = image.getHeight();
int w = image.getWidth();
byte[] data = null;
try {
data = new byte[3 * h * w];
}
catch (OutOfMemoryError err) {
err.printStackTrace();
throw new RuntimeException("Out of memory error.");
}
int idx = 0;
int rgb = 0;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
rgb = image.getRGB(j, i);
data[idx++] = (byte) (rgb >> 16);
data[idx++] = (byte) (rgb >> 8);
data[idx++] = (byte) rgb;
}
}
long[] dims = null;
Datatype type = null;
Group pgroup = null;
String imgName = imgFile.getName();
FileFormat newfile = null, thefile = null;
if (toType.equals(FileFormat.FILE_TYPE_HDF5)) {
thefile = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5);
long[] h5dims = { h, w, 3 }; // RGB pixel interlace
dims = h5dims;
}
else if (toType.equals(FileFormat.FILE_TYPE_HDF4)) {
thefile = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4);
long[] h4dims = { w, h, 3 }; // RGB pixel interlace
dims = h4dims;
}
else {
thefile = null;
}
if (thefile != null) {
newfile = thefile.createInstance(hFileName, FileFormat.CREATE);
newfile.open();
pgroup = (Group) ((DefaultMutableTreeNode) newfile.getRootNode()).getUserObject();
type = newfile.createDatatype(Datatype.CLASS_CHAR, 1, Datatype.NATIVE, Datatype.SIGN_NONE);
newfile.createImage(imgName, pgroup, type, dims, null, null, -1, 3, ScalarDS.INTERLACE_PIXEL, data);
newfile.close();
}
// clean up memory
data = null;
image = null;
Runtime.getRuntime().gc();
}
/**
* Save a BufferedImage into an image file.
*
* @param image
* the BufferedImage to save.
* @param file
* the image file.
* @param type
* the image type.
*/
public static void saveImageAs(BufferedImage image, File file, String type) throws Exception {
if (image == null) {
throw new NullPointerException("The source image is null.");
}
ImageIO.write(image, type, file);
}
/**
* Creates the gray palette of the indexed 256-color table.
*
* The palette values are stored in a two-dimensional byte array and arrange
* by color components of red, green and blue. palette[][] = byte[3][256],
* where, palette[0][], palette[1][] and palette[2][] are the red, green and
* blue components respectively.
*
* @return the gray palette in the form of byte[3][256]
*/
public static final byte[][] createGrayPalette() {
byte[][] p = new byte[3][256];
for (int i = 0; i < 256; i++) {
p[0][i] = p[1][i] = p[2][i] = (byte) (i);
}
return p;
}
/**
* Creates the reverse gray palette of the indexed 256-color table.
*
* The palette values are stored in a two-dimensional byte array and arrange
* by color components of red, green and blue. palette[][] = byte[3][256],
* where, palette[0][], palette[1][] and palette[2][] are the red, green and
* blue components respectively.
*
* @return the gray palette in the form of byte[3][256]
*/
public static final byte[][] createReverseGrayPalette() {
byte[][] p = new byte[3][256];
for (int i = 0; i < 256; i++) {
p[0][i] = p[1][i] = p[2][i] = (byte) (255 - i);
}
return p;
}
/**
* Creates the gray wave palette of the indexed 256-color table.
*
* The palette values are stored in a two-dimensional byte array and arrange
* by color components of red, green and blue. palette[][] = byte[3][256],
* where, palette[0][], palette[1][] and palette[2][] are the red, green and
* blue components respectively.
*
* @return the gray palette in the form of byte[3][256]
*/
public static final byte[][] createGrayWavePalette() {
byte[][] p = new byte[3][256];
for (int i = 0; i < 256; i++) {
p[0][i] = p[1][i] = p[2][i] = (byte) (255 / 2 + (255 / 2) * Math.sin((i - 32) / 20.3));
}
return p;
}
/**
* Creates the rainbow palette of the indexed 256-color table.
*
* The palette values are stored in a two-dimensional byte array and arrange
* by color components of red, green and blue. palette[][] = byte[3][256],
* where, palette[0][], palette[1][] and palette[2][] are the red, green and
* blue components respectively.
*
* @return the rainbow palette in the form of byte[3][256]
*/
public static final byte[][] createRainbowPalette() {
byte r, g, b;
byte[][] p = new byte[3][256];
for (int i = 1; i < 255; i++) {
if (i <= 29) {
r = (byte) (129.36 - i * 4.36);
g = 0;
b = (byte) 255;
}
else if (i <= 86) {
r = 0;
g = (byte) (-133.54 + i * 4.52);
b = (byte) 255;
}
else if (i <= 141) {
r = 0;
g = (byte) 255;
b = (byte) (665.83 - i * 4.72);
}
else if (i <= 199) {
r = (byte) (-635.26 + i * 4.47);
g = (byte) 255;
b = 0;
}
else {
r = (byte) 255;
g = (byte) (1166.81 - i * 4.57);
b = 0;
}
p[0][i] = r;
p[1][i] = g;
p[2][i] = b;
}
p[0][0] = p[1][0] = p[2][0] = 0;
p[0][255] = p[1][255] = p[2][255] = (byte) 255;
return p;
}
/**
* Creates the nature palette of the indexed 256-color table.
*
* The palette values are stored in a two-dimensional byte array and arrange
* by color components of red, green and blue. palette[][] = byte[3][256],
* where, palette[0][], palette[1][] and palette[2][] are the red, green and
* blue components respectively.
*
* @return the nature palette in the form of byte[3][256]
*/
public static final byte[][] createNaturePalette() {
byte[][] p = new byte[3][256];
for (int i = 1; i < 210; i++) {
p[0][i] = (byte) ((Math.sin((double) (i - 5) / 16) + 1) * 90);
p[1][i] = (byte) ((1 - Math.sin((double) (i - 30) / 12)) * 64 * (1 - (double) i / 255) + 128 - i / 2);
p[2][i] = (byte) ((1 - Math.sin((double) (i - 8) / 9)) * 110 + 30);
}
for (int i = 210; i < 255; i++) {
p[0][i] = (byte) 80;
p[1][i] = (byte) 0;
p[2][i] = (byte) 200;
}
p[0][0] = p[1][0] = p[2][0] = 0;
p[0][255] = p[1][255] = p[2][255] = (byte) 255;
return p;
}
/**
* Creates the wave palette of the indexed 256-color table.
*
* The palette values are stored in a two-dimensional byte array and arrange
* by color components of red, green and blue. palette[][] = byte[3][256],
* where, palette[0][], palette[1][] and palette[2][] are the red, green and
* blue components respectively.
*
* @return the wave palette in the form of byte[3][256]
*/
public static final byte[][] createWavePalette() {
byte[][] p = new byte[3][256];
for (int i = 1; i < 255; i++) {
p[0][i] = (byte) ((Math.sin(((double) i / 40 - 3.2)) + 1) * 128);
p[1][i] = (byte) ((1 - Math.sin((i / 2.55 - 3.1))) * 70 + 30);
p[2][i] = (byte) ((1 - Math.sin(((double) i / 40 - 3.1))) * 128);
}
p[0][0] = p[1][0] = p[2][0] = 0;
p[0][255] = p[1][255] = p[2][255] = (byte) 255;
return p;
}
/**
* read an image palette from a file.
*
* A palette file has format of (value, red, green, blue). The color value
* in palette file can be either unsigned char [0..255] or float [0..1].
* Float value will be converted to [0..255].
*
* The color table in file can have any number of entries between 2 to 256.
* It will be converted to a color table of 256 entries. Any missing index
* will calculated by linear interpolation between the neighboring index
* values. For example, index 11 is missing in the following table 10 200 60
* 20 12 100 100 60 Index 11 will be calculated based on index 10 and index
* 12, i.e. 11 150 80 40
*
* @param filename
* the name of the palette file.
*
* @return the wave palette in the form of byte[3][256]
*/
public static final byte[][] readPalette(String filename) {
final int COLOR256 = 256;
BufferedReader in = null;
String line = null;
int nentries = 0, i, j, idx;
float v, r, g, b, ratio, max_v, min_v, max_color, min_color;
float[][] tbl = new float[COLOR256][4]; /* value, red, green, blue */
if (filename == null) return null;
try {
in = new BufferedReader(new FileReader(filename));
}
catch (Exception ex) {
in = null;
}
if (in == null) return null;
idx = 0;
v = r = g = b = ratio = max_v = min_v = max_color = min_color = 0;
do {
try {
line = in.readLine();
}
catch (Exception ex) {
line = null;
}
if (line == null) continue;
StringTokenizer st = new StringTokenizer(line);
// invalid line
if (st.countTokens() != 4) {
continue;
}
try {
v = Float.valueOf(st.nextToken());
r = Float.valueOf(st.nextToken());
g = Float.valueOf(st.nextToken());
b = Float.valueOf(st.nextToken());
}
catch (NumberFormatException ex) {
continue;
}
tbl[idx][0] = v;
tbl[idx][1] = r;
tbl[idx][2] = g;
tbl[idx][3] = b;
if (idx == 0) {
max_v = min_v = v;
max_color = min_color = r;
}
max_v = Math.max(max_v, v);
max_color = Math.max(max_color, r);
max_color = Math.max(max_color, g);
max_color = Math.max(max_color, b);
min_v = Math.min(min_v, v);
min_color = Math.min(min_color, r);
min_color = Math.min(min_color, g);
min_color = Math.min(min_color, b);
idx++;
if (idx >= COLOR256) break; /* only support to 256 colors */
} while (line != null);
try {
in.close();
}
catch (Exception ex) {
}
nentries = idx;
if (nentries <= 1) // must have more than one entries
return null;
// convert color table to byte
nentries = idx;
if (max_color <= 1) {
ratio = (min_color == max_color) ? 1.0f : ((COLOR256 - 1.0f) / (max_color - min_color));
for (i = 0; i < nentries; i++) {
for (j = 1; j < 4; j++)
tbl[i][j] = (tbl[i][j] - min_color) * ratio;
}
}
// convert table to 256 entries
idx = 0;
ratio = (min_v == max_v) ? 1.0f : ((COLOR256 - 1.0f) / (max_v - min_v));
int[][] p = new int[3][COLOR256];
for (i = 0; i < nentries; i++) {
idx = (int) ((tbl[i][0] - min_v) * ratio);
for (j = 0; j < 3; j++)
p[j][idx] = (int) tbl[i][j + 1];
}
/* linear interpolating missing values in the color table */
for (i = 1; i < COLOR256; i++) {
if ((p[0][i] + p[1][i] + p[2][i]) == 0) {
j = i + 1;
// figure out number of missing points between two given points
while (j < COLOR256 && (p[0][j] + p[1][j] + p[2][j]) == 0)
j++;
if (j >= COLOR256) break; // nothing in the table to interpolating
float d1 = (p[0][j] - p[0][i - 1]) / (j - i);
float d2 = (p[1][j] - p[1][i - 1]) / (j - i);
float d3 = (p[2][j] - p[2][i - 1]) / (j - i);
for (int k = i; k <= j; k++) {
p[0][k] = (int) (p[0][i - 1] + d1 * (k - i + 1));
p[1][k] = (int) (p[1][i - 1] + d2 * (k - i + 1));
p[2][k] = (int) (p[2][i - 1] + d3 * (k - i + 1));
}
i = j + 1;
} // if ((p[0][i] + p[1][i] + p[2][i]) == 0)
} // for (i = 1; i < COLOR256; i++) {
byte[][] pal = new byte[3][COLOR256];
for (i = 1; i < COLOR256; i++) {
for (j = 0; j < 3; j++)
pal[j][i] = (byte) (p[j][i]);
}
return pal;
}
/**
* This method returns true if the specified image has transparent pixels.
*
* @param image
* the image to be check if has alpha.
* @return true if the image has alpha setting.
*/
public static boolean hasAlpha(Image image) {
if (image == null) {
return false;
}
// If buffered image, the color model is readily available
if (image instanceof BufferedImage) {
BufferedImage bimage = (BufferedImage) image;
return bimage.getColorModel().hasAlpha();
}
// Use a pixel grabber to retrieve the image's color model;
// grabbing a single pixel is usually sufficient
PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
try {
pg.grabPixels();
}
catch (InterruptedException e) {
}
ColorModel cm = pg.getColorModel();
return cm.hasAlpha();
}
/**
* Creates a RGB indexed image of 256 colors.
*
* @param imageData
* the byte array of the image data.
* @param palette
* the color lookup table.
* @param w
* the width of the image.
* @param h
* the height of the image.
* @return the image.
*/
public static Image createIndexedImage(byte[] imageData, byte[][] palette, int w, int h) {
Image theImage = null;
IndexColorModel colorModel = new IndexColorModel(8, // bits - the number
// of bits each
// pixel occupies
256, // size - the size of the color component arrays
palette[0], // r - the array of red color components
palette[1], // g - the array of green color components
palette[2]); // b - the array of blue color components
theImage = Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(w, h, colorModel, imageData, 0, w));
return theImage;
}
/**
* Creates a true color image.
*
* DirectColorModel is used to construct the image from raw data. The
* DirectColorModel model is similar to an X11 TrueColor visual, which has
* the following parameters:
*
*
* Number of bits: 32
* Red mask: 0x00ff0000
* Green mask: 0x0000ff00
* Blue mask: 0x000000ff
* Alpha mask: 0xff000000
* Color space: sRGB
* isAlphaPremultiplied: False
* Transparency: Transparency.TRANSLUCENT
* transferType: DataBuffer.TYPE_INT
*
*
* The data may be arranged in one of two ways: by pixel or by plane. In
* both cases, the dataset will have a dataspace with three dimensions,
* height, width, and components.
*
* For HDF4, the interlace modes specify orders for the dimensions as:
*
*
* INTERLACE_PIXEL = [width][height][pixel components]
* INTERLACE_PLANE = [pixel components][width][height]
*
*
* For HDF5, the interlace modes specify orders for the dimensions as:
*
*
* INTERLACE_PIXEL = [height][width][pixel components]
* INTERLACE_PLANE = [pixel components][height][width]
*
*
*
* @param imageData
* the byte array of the image data.
* @param planeInterlace
* flag if the image is plane intelace.
* @param w
* the width of the image.
* @param h
* the height of the image.
* @return the image.
*/
public static Image createTrueColorImage(byte[] imageData, boolean planeInterlace, int w, int h) {
Image theImage = null;
int imgSize = w * h;
int packedImageData[] = new int[imgSize];
int pixel = 0, idx = 0, r = 0, g = 0, b = 0;
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
pixel = r = g = b = 0;
if (planeInterlace) {
r = imageData[idx];
g = imageData[imgSize + idx];
b = imageData[imgSize * 2 + idx];
}
else {
r = imageData[idx * 3];
g = imageData[idx * 3 + 1];
b = imageData[idx * 3 + 2];
}
r = (r << 16) & 0x00ff0000;
g = (g << 8) & 0x0000ff00;
b = b & 0x000000ff;
// bits packed into alpha (1), red (r), green (g) and blue (b)
// as 11111111rrrrrrrrggggggggbbbbbbbb
pixel = 0xff000000 | r | g | b;
packedImageData[idx++] = pixel;
} // for (int j=0; j
*
* @param rawData
* The input raw data.
* @param minmax
* the range of the raw data.
* @return the byte array of pixel data.
*/
public static byte[] getBytes(Object rawData, double[] minmax, byte[] byteData) {
return Tools.getBytes(rawData, minmax, -1, -1, false, null, false, byteData);
}
public static byte[] getBytes(Object rawData, double[] minmax, int w, int h, boolean isTransposed, byte[] byteData) {
return Tools.getBytes(rawData, minmax, w, h, isTransposed, null, false, byteData);
}
public static byte[] getBytes(Object rawData, double[] minmax, Object fillValue, byte[] byteData) {
return Tools.getBytes(rawData, minmax, -1, -1, false, fillValue, false, byteData);
}
public static byte[] getBytes(Object rawData, double[] minmax, int w, int h, boolean isTransposed,
Object fillValue, byte[] byteData) {
return getBytes(rawData, minmax, w, h, isTransposed, fillValue, false, byteData);
}
/**
* Convert an array of raw data into array of a byte data.
*
*
* @param rawData
* The input raw data.
* @param minmax
* the range of the raw data.
* @param isTransposed
* if the data is transposeed
* @return the byte array of pixel data.
*/
public static byte[] getBytes(Object rawData, double[] minmax, int w, int h, boolean isTransposed,
Object fillValue, boolean convertByteData, byte[] byteData) {
// no input data
if (rawData == null) {
return null;
}
// input data is not an array
if (!rawData.getClass().isArray()) {
return null;
}
double min = Double.MAX_VALUE, max = -Double.MAX_VALUE, ratio = 1.0d;
String cname = rawData.getClass().getName();
char dname = cname.charAt(cname.lastIndexOf("[") + 1);
int size = Array.getLength(rawData);
if (minmax == null) {
minmax = new double[2];
minmax[0] = minmax[1] = 0;
}
if (dname == 'B') {
return convertByteData((byte[]) rawData, minmax, w, h, isTransposed, fillValue, convertByteData, byteData);
}
if ((byteData == null) || (size != byteData.length)) {
byteData = new byte[size]; // reuse the old buffer
}
if (minmax[0] == minmax[1]) {
Tools.findMinMax(rawData, minmax, fillValue);
}
min = minmax[0];
max = minmax[1];
ratio = (min == max) ? 1.00d : (double) (255.00 / (max - min));
int idxSrc = 0, idxDst = 0;
switch (dname) {
case 'S':
short[] s = (short[]) rawData;
short fvs = 0;
// set fill value to zero
if (fillValue != null) {
fvs = ((short[]) fillValue)[0];
}
if (isTransposed) {
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
idxSrc = j * h + i;
idxDst = i * w + j;
if (s[idxSrc] <= min || s[idxSrc] == fvs)
byteData[idxDst] = 0;
else if (s[idxSrc] >= max)
byteData[idxDst] = (byte) 255;
else
byteData[idxDst] = (byte) ((s[idxSrc] - min) * ratio);
}
}
}
else {
for (int i = 0; i < size; i++) {
if (s[i] <= min || s[i] == fvs)
byteData[i] = 0;
else if (s[i] >= max)
byteData[i] = (byte) 255;
else
byteData[i] = (byte) ((s[i] - min) * ratio);
}
}
break;
case 'I':
int[] ia = (int[]) rawData;
int fvi = 0;
// set fill value to zero
if (fillValue != null) {
fvi = ((int[]) fillValue)[0];
}
if (isTransposed) {
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
idxSrc = j * h + i;
idxDst = i * w + j;
if (ia[idxSrc] <= min || ia[idxSrc] == fvi)
byteData[idxDst] = 0;
else if (ia[idxSrc] >= max)
byteData[idxDst] = (byte) 255;
else
byteData[idxDst] = (byte) ((ia[idxSrc] - min) * ratio);
}
}
}
else {
for (int i = 0; i < size; i++) {
if (ia[i] <= min || ia[i] == fvi)
byteData[i] = 0;
else if (ia[i] >= max)
byteData[i] = (byte) 255;
else
byteData[i] = (byte) ((ia[i] - min) * ratio);
}
}
break;
case 'J':
long[] l = (long[]) rawData;
long fvl = 0;
// set fill value to zero
if (fillValue != null) {
fvl = ((long[]) fillValue)[0];
}
if (isTransposed) {
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
idxSrc = j * h + i;
idxDst = i * w + j;
if (l[idxSrc] <= min || l[idxSrc] == fvl)
byteData[idxDst] = 0;
else if (l[idxSrc] >= max)
byteData[idxDst] = (byte) 255;
else
byteData[idxDst] = (byte) ((l[idxSrc] - min) * ratio);
}
}
}
else {
for (int i = 0; i < size; i++) {
if (l[i] <= min || l[i] == fvl)
byteData[i] = 0;
else if (l[i] >= max)
byteData[i] = (byte) 255;
else
byteData[i] = (byte) ((l[i] - min) * ratio);
}
}
break;
case 'F':
float[] f = (float[]) rawData;
float fvf = 0;
// set fill value to zero
if (fillValue != null) {
fvf = ((float[]) fillValue)[0];
}
if (isTransposed) {
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
idxSrc = j * h + i;
idxDst = i * w + j;
if (f[idxSrc] <= min || f[idxSrc] == fvf || isNaNINF((double) f[idxSrc]))
byteData[idxDst] = 0;
else if (f[idxSrc] >= max)
byteData[idxDst] = (byte) 255;
else
byteData[idxDst] = (byte) ((f[idxSrc] - min) * ratio);
}
}
}
else {
for (int i = 0; i < size; i++) {
if (f[i] <= min | f[i] == fvf || isNaNINF((double) f[i]))
byteData[i] = 0;
else if (f[i] >= max)
byteData[i] = (byte) 255;
else
byteData[i] = (byte) ((f[i] - min) * ratio);
}
}
break;
case 'D':
double[] d = (double[]) rawData;
double fvd = 0;
// set fill value to zero
if (fillValue != null) {
fvd = ((double[]) fillValue)[0];
}
if (isTransposed) {
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
idxSrc = j * h + i;
idxDst = i * w + j;
if (d[idxSrc] <= min || d[idxSrc] == fvd || isNaNINF(d[idxSrc]))
byteData[idxDst] = 0;
else if (d[idxSrc] >= max)
byteData[idxDst] = (byte) 255;
else
byteData[idxDst] = (byte) ((d[idxSrc] - min) * ratio);
}
}
}
else {
for (int i = 0; i < size; i++) {
if (d[i] <= min || d[i] == fvd || isNaNINF(d[i]))
byteData[i] = 0;
else if (d[i] >= max)
byteData[i] = (byte) 255;
else
byteData[i] = (byte) ((d[i] - min) * ratio);
}
}
break;
default:
byteData = null;
break;
} // switch (dname)
return byteData;
}
private static byte[] convertByteData(byte[] rawData, double[] minmax, int w, int h, boolean isTransposed,
Object fillValue, boolean convertByteData, byte[] byteData) {
double min = Double.MAX_VALUE, max = -Double.MAX_VALUE, ratio = 1.0d;
if (rawData == null) return null;
if (convertByteData) {
if (minmax[0] == minmax[1]) {
Tools.findMinMax(rawData, minmax, fillValue);
}
}
if (minmax[0] == 0 && minmax[1] == 255) convertByteData = false; // no need to convert data
// no conversion and no transpose
if (!convertByteData && !isTransposed) {
if (byteData != null && byteData.length == rawData.length) {
System.arraycopy(rawData, 0, byteData, 0, rawData.length);
return byteData;
}
return rawData;
}
// don't want to change the original raw data
if (byteData == null || rawData == byteData) byteData = new byte[rawData.length];
if (!convertByteData) {
// do not convert data, just transpose the data
minmax[0] = 0;
minmax[1] = 255;
if (isTransposed) {
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
byteData[i * w + j] = rawData[j * h + i];
}
}
}
return byteData;
}
// special data range used, must convert the data
min = minmax[0];
max = minmax[1];
ratio = (min == max) ? 1.00d : (double) (255.00 / (max - min));
if (isTransposed) {
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
int idxSrc = j * h + i;
int idxDst = i * w + j;
if (rawData[idxSrc] >= max)
byteData[idxDst] = (byte) 255;
else if (rawData[idxSrc] <= min)
byteData[idxDst] = (byte) 0;
else
byteData[idxDst] = (byte) ((rawData[idxSrc] - min) * ratio);
}
}
}
else {
for (int i = 0; i < rawData.length; i++) {
if (rawData[i] >= max)
byteData[i] = (byte) 255;
else if (rawData[i] <= min)
byteData[i] = (byte) 0;
else
byteData[i] = (byte) ((rawData[i] - min) * ratio);
}
}
return byteData;
}
/**
* Create and initialize a new instance of the given class.
*
* @param initargs
* - array of objects to be passed as arguments
* @return a new instance of the given class.
*/
public static Object newInstance(Class> cls, Object[] initargs) throws Exception {
Object instance = null;
if (cls == null) {
return null;
}
if ((initargs == null) || (initargs.length == 0)) {
instance = cls.newInstance();
}
else {
Constructor>[] constructors = cls.getConstructors();
if ((constructors == null) || (constructors.length == 0)) {
return null;
}
boolean isConstructorMatched = false;
Constructor> constructor = null;
Class>[] params = null;
int m = constructors.length;
int n = initargs.length;
for (int i = 0; i < m; i++) {
constructor = constructors[i];
params = constructor.getParameterTypes();
if (params.length == n) {
// check if all the parameters are matched
isConstructorMatched = params[0].isInstance(initargs[0]);
for (int j = 1; j < n; j++) {
isConstructorMatched = isConstructorMatched && params[j].isInstance(initargs[j]);
}
if (isConstructorMatched) {
instance = constructor.newInstance(initargs);
break;
}
}
} // for (int i=0; i
* The computation is based on the following scaling
*
*
* int_8 [0, 127]
* uint_8 [0, 255]
* int_16 [0, 32767]
* uint_16 [0, 65535]
* int_32 [0, 2147483647]
* uint_32 [0, 4294967295]
* int_64 [0, 9223372036854775807]
* uint_64 [0, 18446744073709551615] // Not supported.
*
*
* @param data
* the raw data array of signed/unsigned integers
* @param params
* the auto gain parameter. params[0]=gain, params[1]=bias,
* @param isUnsigned
* the flag to indicate if the data array is unsigned integer
* @return non-negative if successful; otherwise, returns negative
*/
public static int autoContrastCompute(Object data, double[] params, boolean isUnsigned) {
int retval = 1;
long maxDataValue = 255;
double[] minmax = new double[2];
// check parameters
if ((data == null) || (params == null) || (Array.getLength(data) <= 0) || (params.length < 2)) {
return -1;
}
retval = autoContrastComputeMinMax(data, minmax);
// force the min_max method so we can look at the target grids data sets
if ((retval < 0) || (minmax[1] - minmax[0] < 10)) {
retval = findMinMax(data, minmax, null);
}
if (retval < 0) {
return -1;
}
String cname = data.getClass().getName();
char dname = cname.charAt(cname.lastIndexOf("[") + 1);
switch (dname) {
case 'B':
maxDataValue = MAX_INT8;
break;
case 'S':
maxDataValue = MAX_INT16;
if (isUnsigned) {
maxDataValue = MAX_UINT8; // data was upgraded from unsigned byte
}
break;
case 'I':
maxDataValue = MAX_INT32;
if (isUnsigned) {
maxDataValue = MAX_UINT16; // data was upgraded from unsigned short
}
break;
case 'J':
maxDataValue = MAX_INT64;
if (isUnsigned) {
maxDataValue = MAX_UINT32; // data was upgraded from unsigned int
}
break;
default:
retval = -1;
break;
} // switch (dname)
if (minmax[0] == minmax[1]) {
params[0] = 1.0;
params[1] = 0.0;
}
else {
// This histogram method has a tendency to stretch the
// range of values to be a bit too big, so we can
// account for this by adding and subtracting some percent
// of the difference to the max/min values
// to prevent the gain from going too high.
double diff = minmax[1] - minmax[0];
double newmax = (minmax[1] + (diff * 0.1));
double newmin = (minmax[0] - (diff * 0.1));
if (newmax <= maxDataValue) {
minmax[1] = newmax;
}
if (newmin >= 0) {
minmax[0] = newmin;
}
params[0] = maxDataValue / (minmax[1] - minmax[0]);
params[1] = -minmax[0];
}
return retval;
}
/**
* Apply autocontrast parameters to the original data in place (destructive)
*
* @param data_in
* the original data array of signed/unsigned integers
* @param data_out
* the converted data array of signed/unsigned integers
* @param params
* the auto gain parameter. params[0]=gain, params[1]=bias
* @param minmax
* the data range. minmax[0]=min, minmax[1]=max
* @param isUnsigned
* the flag to indicate if the data array is unsigned integer
*
* @return the data array with the auto contrast conversion; otherwise,
* returns null
*/
public static Object autoContrastApply(Object data_in, Object data_out, double[] params, double[] minmax,
boolean isUnsigned) {
int size = 0;
double min = -MAX_INT64, max = MAX_INT64;
if ((data_in == null) || (params == null) || (params.length < 2)) {
return null;
}
if (minmax != null) {
min = minmax[0];
max = minmax[1];
}
// input and output array must be the same size
size = Array.getLength(data_in);
if ((data_out != null) && (size != Array.getLength(data_out))) {
return null;
}
double gain = params[0];
double bias = params[1];
double value_out, value_in;
String cname = data_in.getClass().getName();
char dname = cname.charAt(cname.lastIndexOf("[") + 1);
switch (dname) {
case 'B':
byte[] b_in = (byte[]) data_in;
if (data_out == null) {
data_out = new byte[size];
}
byte[] b_out = (byte[]) data_out;
byte b_max = (byte) MAX_INT8;
for (int i = 0; i < size; i++) {
value_in = Math.max(b_in[i], min);
value_in = Math.min(b_in[i], max);
value_out = (value_in + bias) * gain;
value_out = Math.max(value_out, 0.0);
value_out = Math.min(value_out, b_max);
b_out[i] = (byte) value_out;
}
break;
case 'S':
short[] s_in = (short[]) data_in;
if (data_out == null) {
data_out = new short[size];
}
short[] s_out = (short[]) data_out;
short s_max = (short) MAX_INT16;
if (isUnsigned) {
s_max = (short) MAX_UINT8; // data was upgraded from unsigned byte
}
for (int i = 0; i < size; i++) {
value_in = Math.max(s_in[i], min);
value_in = Math.min(s_in[i], max);
value_out = (value_in + bias) * gain;
value_out = Math.max(value_out, 0.0);
value_out = Math.min(value_out, s_max);
s_out[i] = (byte) value_out;
}
break;
case 'I':
int[] i_in = (int[]) data_in;
if (data_out == null) {
data_out = new int[size];
}
int[] i_out = (int[]) data_out;
int i_max = (int) MAX_INT32;
if (isUnsigned) {
i_max = (int) MAX_UINT16; // data was upgraded from unsigned short
}
for (int i = 0; i < size; i++) {
value_in = Math.max(i_in[i], min);
value_in = Math.min(i_in[i], max);
value_out = (value_in + bias) * gain;
value_out = Math.max(value_out, 0.0);
value_out = Math.min(value_out, i_max);
i_out[i] = (byte) value_out;
}
break;
case 'J':
long[] l_in = (long[]) data_in;
if (data_out == null) {
data_out = new long[size];
}
long[] l_out = (long[]) data_out;
long l_max = MAX_INT64;
if (isUnsigned) {
l_max = MAX_UINT32; // data was upgraded from unsigned int
}
for (int i = 0; i < size; i++) {
value_in = Math.max(l_in[i], min);
value_in = Math.min(l_in[i], max);
value_out = (value_in + bias) * gain;
value_out = Math.max(value_out, 0.0);
value_out = Math.min(value_out, l_max);
l_out[i] = (byte) value_out;
}
break;
default:
break;
} // switch (dname)
return data_out;
}
/**
* Converts image raw data to bytes.
*
* The integer data is converted to byte data based on the following rule
*
*
* uint_8 x
* int_8 (x & 0x7F) << 1
* uint_16 (x >> 8) & 0xFF
* int_16 (x >> 7) & 0xFF
* uint_32 (x >> 24) & 0xFF
* int_32 (x >> 23) & 0xFF
* uint_64 (x >> 56) & 0xFF
* int_64 (x >> 55) & 0xFF
*
*
* @param src
* the source data array of signed integers or unsigned shorts
* @param dst
* the destination data array of bytes
* @param isUnsigned
* the flag to indicate if the data array is unsigned integer
* @return non-negative if successful; otherwise, returns negative
*/
public static int autoContrastConvertImageBuffer(Object src, byte[] dst, boolean isUnsigned) {
int retval = 0;
if ((src == null) || (dst == null) || (dst.length != Array.getLength(src))) {
return -1;
}
int size = dst.length;
String cname = src.getClass().getName();
char dname = cname.charAt(cname.lastIndexOf("[") + 1);
switch (dname) {
case 'B':
byte[] b_src = (byte[]) src;
if (isUnsigned) {
for (int i = 0; i < size; i++) {
dst[i] = b_src[i];
}
}
else {
for (int i = 0; i < size; i++) {
dst[i] = (byte) ((b_src[i] & 0x7F) << 1);
}
}
break;
case 'S':
short[] s_src = (short[]) src;
if (isUnsigned) { // data was upgraded from unsigned byte
for (int i = 0; i < size; i++) {
dst[i] = (byte) s_src[i];
}
}
else {
for (int i = 0; i < size; i++) {
dst[i] = (byte) ((s_src[i] >> 7) & 0xFF);
}
}
break;
case 'I':
int[] i_src = (int[]) src;
if (isUnsigned) { // data was upgraded from unsigned short
for (int i = 0; i < size; i++) {
dst[i] = (byte) ((i_src[i] >> 8) & 0xFF);
}
}
else {
for (int i = 0; i < size; i++) {
dst[i] = (byte) ((i_src[i] >> 23) & 0xFF);
}
}
break;
case 'J':
long[] l_src = (long[]) src;
if (isUnsigned) { // data was upgraded from unsigned int
for (int i = 0; i < size; i++) {
dst[i] = (byte) ((l_src[i] >> 24) & 0xFF);
}
}
else {
for (int i = 0; i < size; i++) {
dst[i] = (byte) ((l_src[i] >> 55) & 0xFF);
}
}
break;
default:
retval = -1;
break;
} // switch (dname)
return retval;
}
/**
* Computes autocontrast parameters by
*
*
* min = mean - 3 * std.dev
* max = mean + 3 * std.dev
*
*
* @param data
* the raw data array
* @param minmax
* the min and max values.
* @return non-negative if successful; otherwise, returns negative
*/
public static int autoContrastComputeMinMax(Object data, double[] minmax) {
int retval = 1;
if ((data == null) || (minmax == null) || (Array.getLength(data) <= 0) || (Array.getLength(minmax) < 2)) {
return -1;
}
double[] avgstd = { 0, 0 };
retval = computeStatistics(data, avgstd, null);
if (retval < 0) {
return retval;
}
minmax[0] = avgstd[0] - 3.0 * avgstd[1];
minmax[1] = avgstd[0] + 3.0 * avgstd[1];
return retval;
}
/**
* Finds the min and max values of the data array
*
* @param data
* the raw data array
* @param minmax
* the mmin and max values of the array.
* @param fillValue
* the missing value or fill value. Exclude this value when check
* for min/max
* @return non-negative if successful; otherwise, returns negative
*/
public static int findMinMax(Object data, double[] minmax, Object fillValue) {
int retval = 1;
if ((data == null) || (minmax == null) || (Array.getLength(data) <= 0) || (Array.getLength(minmax) < 2)) {
return -1;
}
int n = Array.getLength(data);
double fill = 0.0;
boolean hasFillValue = (fillValue != null && fillValue.getClass().isArray());
String cname = data.getClass().getName();
char dname = cname.charAt(cname.lastIndexOf("[") + 1);
minmax[0] = Float.MAX_VALUE;
minmax[1] = -Float.MAX_VALUE;
switch (dname) {
case 'B':
byte[] b = (byte[]) data;
minmax[0] = minmax[1] = b[0];
if (hasFillValue) fill = ((byte[]) fillValue)[0];
for (int i = 0; i < n; i++) {
if (hasFillValue && b[i] == fill) continue;
if (minmax[0] > b[i]) {
minmax[0] = b[i];
}
if (minmax[1] < b[i]) {
minmax[1] = b[i];
}
}
break;
case 'S':
short[] s = (short[]) data;
minmax[0] = minmax[1] = s[0];
if (hasFillValue) fill = ((short[]) fillValue)[0];
for (int i = 0; i < n; i++) {
if (hasFillValue && s[i] == fill) continue;
if (minmax[0] > s[i]) {
minmax[0] = s[i];
}
if (minmax[1] < s[i]) {
minmax[1] = s[i];
}
}
break;
case 'I':
int[] ia = (int[]) data;
minmax[0] = minmax[1] = ia[0];
if (hasFillValue) fill = ((int[]) fillValue)[0];
for (int i = 0; i < n; i++) {
if (hasFillValue && ia[i] == fill) continue;
if (minmax[0] > ia[i]) {
minmax[0] = ia[i];
}
if (minmax[1] < ia[i]) {
minmax[1] = ia[i];
}
}
break;
case 'J':
long[] l = (long[]) data;
minmax[0] = minmax[1] = l[0];
if (hasFillValue) fill = ((long[]) fillValue)[0];
for (int i = 0; i < n; i++) {
if (hasFillValue && l[i] == fill) continue;
if (minmax[0] > l[i]) {
minmax[0] = l[i];
}
if (minmax[1] < l[i]) {
minmax[1] = l[i];
}
}
break;
case 'F':
float[] f = (float[]) data;
minmax[0] = minmax[1] = f[0];
if (hasFillValue) fill = ((float[]) fillValue)[0];
for (int i = 0; i < n; i++) {
if ((hasFillValue && f[i] == fill) || isNaNINF((double) f[i])) continue;
if (minmax[0] > f[i]) {
minmax[0] = f[i];
}
if (minmax[1] < f[i]) {
minmax[1] = f[i];
}
}
break;
case 'D':
double[] d = (double[]) data;
minmax[0] = minmax[1] = d[0];
if (hasFillValue) fill = ((double[]) fillValue)[0];
for (int i = 0; i < n; i++) {
if ((hasFillValue && d[i] == fill) || isNaNINF(d[i])) continue;
if (minmax[0] > d[i]) {
minmax[0] = d[i];
}
if (minmax[1] < d[i]) {
minmax[1] = d[i];
}
}
break;
default:
retval = -1;
break;
} // switch (dname)
return retval;
}
/**
* Finds the distribution of data values
*
* @param data
* the raw data array
* @param dataDist
* the data distirbution.
* @param minmax
* the data range
* @return non-negative if successful; otherwise, returns negative
*/
public static int findDataDist(Object data, int[] dataDist, double[] minmax) {
int retval = 0;
double delt = 1;
if ((data == null) || (minmax == null) || dataDist == null) return -1;
int n = Array.getLength(data);
if (minmax[1] != minmax[0]) delt = (dataDist.length - 1) / (minmax[1] - minmax[0]);
for (int i = 0; i < dataDist.length; i++)
dataDist[i] = 0;
int idx;
double val;
for (int i = 0; i < n; i++) {
val = ((Number) Array.get(data, i)).doubleValue();
idx = (int) ((val - minmax[0]) * delt);
dataDist[idx]++;
}
return retval;
}
/**
* Computes mean and standard deviation of a data array
*
* @param data
* the raw data array
* @param avgstd
* the statistics: avgstd[0]=mean and avgstd[1]=stdev.
* @param fillValue
* the missing value or fill value. Exclude this value when
* compute statistics
* @return non-negative if successful; otherwise, returns negative
*/
public static int computeStatistics(Object data, double[] avgstd, Object fillValue) {
int retval = 1, npoints = 0;
double sum = 0, avg = 0.0, var = 0.0, diff = 0.0, fill = 0.0;
if ((data == null) || (avgstd == null) || (Array.getLength(data) <= 0) || (Array.getLength(avgstd) < 2)) {
return -1;
}
int n = Array.getLength(data);
boolean hasFillValue = (fillValue != null && fillValue.getClass().isArray());
String cname = data.getClass().getName();
char dname = cname.charAt(cname.lastIndexOf("[") + 1);
npoints = 0;
switch (dname) {
case 'B':
byte[] b = (byte[]) data;
if (hasFillValue) fill = ((byte[]) fillValue)[0];
for (int i = 0; i < n; i++) {
if (hasFillValue && b[i] == fill) continue;
sum += b[i];
npoints++;
}
avg = sum / npoints;
for (int i = 0; i < n; i++) {
if (hasFillValue && b[i] == fill) continue;
diff = b[i] - avg;
var += diff * diff;
}
break;
case 'S':
short[] s = (short[]) data;
if (hasFillValue) fill = ((short[]) fillValue)[0];
for (int i = 0; i < n; i++) {
if (hasFillValue && s[i] == fill) continue;
sum += s[i];
npoints++;
}
avg = sum / npoints;
for (int i = 0; i < n; i++) {
if (hasFillValue && s[i] == fill) continue;
diff = s[i] - avg;
var += diff * diff;
}
break;
case 'I':
int[] ia = (int[]) data;
if (hasFillValue) fill = ((int[]) fillValue)[0];
for (int i = 0; i < n; i++) {
if (hasFillValue && ia[i] == fill) continue;
sum += ia[i];
npoints++;
}
avg = sum / npoints;
for (int i = 0; i < n; i++) {
if (hasFillValue && ia[i] == fill) continue;
diff = ia[i] - avg;
var += diff * diff;
}
break;
case 'J':
long[] l = (long[]) data;
if (hasFillValue) fill = ((long[]) fillValue)[0];
for (int i = 0; i < n; i++) {
if (hasFillValue && l[i] == fill) continue;
sum += l[i];
npoints++;
}
avg = sum / npoints;
for (int i = 0; i < n; i++) {
if (hasFillValue && l[i] == fill) continue;
diff = l[i] - avg;
var += diff * diff;
}
break;
case 'F':
float[] f = (float[]) data;
if (hasFillValue) fill = ((float[]) fillValue)[0];
for (int i = 0; i < n; i++) {
if (hasFillValue && f[i] == fill) continue;
sum += f[i];
npoints++;
}
avg = sum / npoints;
for (int i = 0; i < n; i++) {
if (hasFillValue && f[i] == fill) continue;
diff = f[i] - avg;
var += diff * diff;
}
break;
case 'D':
double[] d = (double[]) data;
if (hasFillValue) fill = ((double[]) fillValue)[0];
for (int i = 0; i < n; i++) {
if (hasFillValue && d[i] == fill) continue;
sum += d[i];
npoints++;
}
avg = sum / npoints;
for (int i = 0; i < n; i++) {
if (hasFillValue && d[i] == fill) continue;
diff = d[i] - avg;
var += diff * diff;
}
break;
default:
retval = -1;
break;
} // switch (dname)
if (npoints <= 1) {
if (npoints < 1) avgstd[0] = fill;
avgstd[1] = 0;
}
else {
avgstd[0] = avg;
avgstd[1] = Math.sqrt(var / (npoints - 1));
}
return retval;
}
/**
* Returns a string representation of the long argument as an unsigned
* integer in base 2. This is different from Long.toBinaryString(long i).
* This function add padding (0's) to the string based on the nbytes. For
* example, if v=15, nbytes=1, the string will be "00001111".
*
* @param v
* the lon value
* @param nbytes
* nubmer of bytes in the integer
* @return the string representation of the unsigned long value represented
* by the argument in binary (base 2).
*/
public static final String toBinaryString(long v, int nbytes) {
if (nbytes <= 0) return null;
int nhex = nbytes * 2;
short[] hex = new short[nhex];
for (int i = 0; i < nhex; i++)
hex[i] = (short) (0x0F & (v >> (i * 4)));
StringBuffer sb = new StringBuffer();
boolean isEven = true;
for (int i = nhex - 1; i >= 0; i--) {
if (isEven) sb.append(" ");
isEven = !isEven; // toggle
switch (hex[i]) {
case 0:
sb.append("0000");
break;
case 1:
sb.append("0001");
break;
case 2:
sb.append("0010");
break;
case 3:
sb.append("0011");
break;
case 4:
sb.append("0100");
break;
case 5:
sb.append("0101");
break;
case 6:
sb.append("0110");
break;
case 7:
sb.append("0111");
break;
case 8:
sb.append("1000");
break;
case 9:
sb.append("1001");
break;
case 10:
sb.append("1010");
break;
case 11:
sb.append("1011");
break;
case 12:
sb.append("1100");
break;
case 13:
sb.append("1101");
break;
case 14:
sb.append("1110");
break;
case 15:
sb.append("1111");
break;
}
}
return sb.toString();
}
/**
* Apply bitmask to a data array.
*
* @param theData
* the data array which the bitmask is applied to.
* @param theMask
* the bitmask to be applied to the data array.
* @return true if bitmask is applied successfuly; otherwise, false.
*/
public static final boolean applyBitmask(Object theData, BitSet theMask, ViewProperties.BITMASK_OP op) {
if (theData == null || Array.getLength(theData) <= 0 || theMask == null) return false;
char nt = '0';
String cName = theData.getClass().getName();
int cIndex = cName.lastIndexOf("[");
if (cIndex >= 0) {
nt = cName.charAt(cIndex + 1);
}
// only deal with 8 or 16 bit data
if (!(nt == 'B' || nt == 'S')) return false;
int bmask = 0, theValue = 0, packedValue = 0;
int nbits = theMask.length();
int len = Array.getLength(theData);
for (int i = 0; i < nbits; i++) {
if (theMask.get(i)) bmask += 1 << i;
}
for (int i = 0; i < len; i++) {
if (nt == 'B')
theValue = ((byte[]) theData)[i] & bmask;
else
theValue = ((short[]) theData)[i] & bmask;
// apply bitmask only
if (op == BITMASK_OP.AND)
packedValue = theValue;
else {
// extract bits
packedValue = 0;
int bitPosition = 0, bitValue = 0;
;
for (int j = 0; j < nbits; j++) {
if (theMask.get(j)) {
bitValue = (theValue & 1);
packedValue += (bitValue << bitPosition);
bitPosition++;
}
// move to the next bit
theValue = theValue >> 1;
}
}
if (nt == 'B')
((byte[]) theData)[i] = (byte) packedValue;
else
((short[]) theData)[i] = (short) packedValue;
} /* for (int i = 0; i < len; i++) */
return true;
} /* public static final boolean applyBitmask() */
/**
* Launch default browser for a given URL.
*
* @param url
* -- the URL to open.
* @throws Exception
*/
public static final void launchBrowser(String url) throws Exception {
String os = System.getProperty("os.name");
Runtime runtime = Runtime.getRuntime();
// Block for Windows Platform
if (os.startsWith("Windows")) {
String cmd = "rundll32 url.dll,FileProtocolHandler " + url;
if (new File(url).exists()) cmd = "cmd /c start \"\" \"" + url + "\"";
runtime.exec(cmd);
}
// Block for Mac OS
else if (os.startsWith("Mac OS")) {
Class> fileMgr = Class.forName("com.apple.eio.FileManager");
Method openURL = fileMgr.getDeclaredMethod("openURL", new Class[] { String.class });
if (new File(url).exists()) {
// local file
url = "file://" + url;
}
openURL.invoke(null, new Object[] { url });
}
// Block for UNIX Platform
else {
String[] browsers = { "firefox", "opera", "konqueror", "epiphany", "mozilla", "netscape" };
String browser = null;
for (int count = 0; count < browsers.length && browser == null; count++)
if (runtime.exec(new String[] { "which", browsers[count] }).waitFor() == 0) browser = browsers[count];
if (browser == null)
throw new Exception("Could not find web browser");
else
runtime.exec(new String[] { browser, url });
}
} /* public static final void launchBrowser(String url) */
/**
* Check and find a non-exist file.
*
* @param path
* -- the path that the new file will be checked.
* @param ext
* -- the extention of the new file.
* @return -- the new file.
*/
public static final File checkNewFile(String path, String ext) {
File file = new File(path + "new" + ext);
int i = 1;
while (file.exists()) {
file = new File(path + "new" + i + ext);
i++;
}
return file;
}
/**
* Check if a given number if NaN or INF.
*
* @param val
* the nubmer to be checked
* @return true if the number is Nan or INF; otherwise, false.
*/
public static final boolean isNaNINF(double val) {
if (Double.isNaN(val) || val == Float.NEGATIVE_INFINITY || val == Float.POSITIVE_INFINITY
|| val == Double.NEGATIVE_INFINITY || val == Double.POSITIVE_INFINITY) return true;
return false;
}
}