
ncsa.hdf.view.Tools Maven / Gradle / Ivy
Show all versions of hdf-java Show documentation
/*****************************************************************************
* 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.io.*;
import ncsa.hdf.object.*;
import java.awt.Image;
import java.awt.Toolkit;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.BitSet;
import java.util.StringTokenizer;
import javax.imageio.ImageIO;
import javax.swing.tree.DefaultMutableTreeNode;
/**
* 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;
/** 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> 16);
data[idx++] = (byte) (rgb >> 8);
data[idx++] = (byte) rgb;
}
}
int fid = -1;
long[] dims = null;
Datatype type = null;
Group pgroup = null;
Dataset dataset = 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);
fid = newfile.open();
pgroup = (Group)((DefaultMutableTreeNode) newfile.getRootNode()).getUserObject();
type = newfile.createDatatype(Datatype.CLASS_CHAR, 1, Datatype.NATIVE, Datatype.SIGN_NONE);
dataset = 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)
{
int ncolors = 256;
byte[][] p = new byte[3][ncolors];
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[ncolors][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 >= ncolors)
break; /* only support to 256 colors */
} while ( line != null);
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 : ((ncolors-1.0f)/(max_color-min_color));
for (i=0; i=ncolors)
return p; /* nothing in the table to interpolating */
}
p[0][i] = (byte) (p[0][i-1] + (float)(p[0][j]-p[0][i-1])/(j-i));
p[1][i] = (byte) (p[1][i-1] + (float)(p[1][j]-p[1][i-1])/(j-i));
p[2][i] = (byte) (p[2][i-1] + (float)(p[2][j]-p[2][i-1])/(j-i));
}
}
return p;
}
/**
* 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
* @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));
switch (dname)
{
case 'S':
short[] s = (short[])rawData;
// set fill value to zero
if (fillValue != null)
{
short fvalue = ((short[])fillValue)[0];
if (fvalue != 0) {
for (int i=0; i= max)
byteData[i*w+j] = (byte)255;
else
byteData[i*w+j] = (byte)((s[j*h+i]-min)*ratio);
}
}
}
else {
for (int i=0; i= max)
byteData[i] = (byte)255;
else
byteData[i] = (byte)((s[i]-min)*ratio);
}
}
break;
case 'I':
int[] ia = (int[])rawData;
// set fill value to zero
if (fillValue != null)
{
int fvalue = ((int[])fillValue)[0];
if (fvalue != 0) {
for (int i=0; i= max)
byteData[i*w+j] = (byte)255;
else
byteData[i*w+j] = (byte)((ia[j*h+i]-min)*ratio);
}
}
}
else {
for (int i=0; i= max)
byteData[i] = (byte)255;
else
byteData[i] = (byte)((ia[i] - min)*ratio);
}
}
break;
case 'J':
long[] l = (long[])rawData;
// set fill value to zero
if (fillValue != null)
{
long fvalue = ((long[])fillValue)[0];
if (fvalue != 0) {
for (int i=0; i= max)
byteData[i*w+j] = (byte)255;
else
byteData[i*w+j] = (byte)((l[j*h+i]-min)*ratio);
}
}
} else {
for (int i=0; i= max)
byteData[i] = (byte)255;
else
byteData[i] = (byte)((l[i]-min)*ratio);
}
}
break;
case 'F':
float[] f = (float[])rawData;
// set fill value to zero
if (fillValue != null)
{
float fvalue = ((float[])fillValue)[0];
if (fvalue != 0) {
for (int i=0; i= max)
byteData[i*w+j] = (byte)255;
else
byteData[i*w+j] = (byte)((f[j*h+i]-min)*ratio);
}
}
} else {
for (int i=0; i= max)
byteData[i] = (byte)255;
else
byteData[i] = (byte)((f[i]-min)*ratio);
}
}
break;
case 'D':
double[] d = (double[])rawData;
// set fill value to zero
if (fillValue != null)
{
double fvalue = ((double[])fillValue)[0];
if (fvalue != 0) {
for (int i=0; i= max)
byteData[i*w+j] = (byte)255;
else
byteData[i*w+j] = (byte)((d[j*h+i]-min)*ratio);
}
}
} else {
for (int i=0; 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 (byteData == null)
byteData = rawData;
else
System.arraycopy(rawData, 0, byteData, 0, rawData.length);
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
if (!convertByteData) {
minmax[0] = 0;
minmax[1] = 255;
if ( isTransposed) {
for (int i=0; i=max)
byteData[i*w+j] = (byte)255;
else if (rawData[j*h+i] <= min)
byteData[i*w+j] = (byte)0;
else
byteData[i*w+j] = (byte)((rawData[j*h+i]-min)*ratio);
}
}
} else {
for (int i=0; i= max)
rawData[i] = (byte)255;
else if (rawData[i] <= min)
rawData[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
* 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 unsiged 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; // upgaded from unsigned byte
}
break;
case 'I':
maxDataValue = MAX_INT32;
if (isUnsigned) {
maxDataValue = MAX_UINT16; // upgaded from unsigned short
}
break;
case 'J':
maxDataValue = MAX_INT64;
if (isUnsigned) {
maxDataValue = MAX_UINT32; // upgaded 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 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 isUnsigned the flag to indicate if the data array is unsiged 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, boolean isUnsigned)
{
int size=0;
if ((data_in==null) || (params==null) || (params.length<2)) {
return null;
}
// 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;
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 b_max ) {
b_out[i] = b_max;
} else {
b_out[i] = (byte)value;
}
}
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; // upgaded from unsigned byte
}
for( int i = 0; i s_max ) {
s_out[i] = s_max;
} else {
s_out[i] = (short)value;
}
}
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; // upgaded from unsigned short
}
for( int i = 0; i i_max ) {
i_out[i] = i_max;
} else {
i_out[i] = (int)value;
}
}
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; // upgaded from unsigned int
}
for( int i = 0; i l_max ) {
l_out[i] = l_max;
} else {
l_out[i] = (long)value;
}
}
break;
default:
break;
} // switch (dname)
return data_out;
}
/**
* Auto-ranging of gain/bias sliders
*
* Given the results of autogaining an image, compute reasonable
* min and max values for gain/bias sliders.
*
* @param params the auto gain parameter: params[0]=gain, params[1]=bias
* @param gain the range of the gain: gain[0]=min, gain[1]=mas
* @param bias the range of the bias: bias[0]=min, bias[1]=max
* @return non-negative if successful; otherwise, returns negative
*/
public static int autoContrastComputeSliderRange( double[] params, double[] gain, double[] bias)
{
if ((params == null) || (gain == null) || (bias == null) ||
(params.length<2) || (gain.length<2) || (bias.length<2)) {
return -1;
}
gain[0] = 0;
gain[1] = params[0] * 3.0;
bias[1] = 256.0;
if ((params[1] >= 0.001) || (params[1] <= -0.001) ) {
bias[1] = Math.abs( params[1] ) * 3.0;
}
bias[0] = -bias[1];
return 1;
}
/**
* 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 unsiged 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> 7) & 0xFF);
}
}
break;
case 'I':
int[] i_src = (int[])src;
if (isUnsigned) { // upgaded from unsigned short
for( int i = 0; i> 8) & 0xFF);
}
} else {
for( int i = 0; i> 23) & 0xFF);
}
}
break;
case 'J':
long[] l_src = (long[])src;
if (isUnsigned) { // upgaded from unsigned int
for( int i = 0; i> 24) & 0xFF);
}
} else {
for( int i = 0; 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, Object minmax)
{
int retval = 1;
double[] avgstd = new double[2];
if ((data == null) || (minmax == null) || (Array.getLength(data)<=0) || (Array.getLength(minmax)<2)) {
return -1;
}
retval = computeStatistics(data, avgstd, null);
if (retval < 0) {
return retval;
}
double min = avgstd[0] - 3.0*avgstd[1];
double max = avgstd[0] + 3.0*avgstd[1];
String cname = minmax.getClass().getName();
char dname = cname.charAt(cname.lastIndexOf("[")+1);
switch (dname)
{
case 'B':
byte[] b = (byte[])minmax;
b[0] = (byte)min; b[1] = (byte)max;
break;
case 'S':
short[] s = (short[])minmax;
s[0] = (short)min; s[1] = (short)max;
break;
case 'I':
int[] ia = (int[])minmax;
ia[0] = (int)min; ia[1] = (int)max;
break;
case 'J':
long[] l = (long[])minmax;
l[0] = (long)min; l[1] = (long)max;
break;
case 'F':
float[] f = (float[])minmax;
f[0] = (float)min; f[1] = (float)max;
break;
case 'D':
double[] d = (double[])minmax;
d[0] = min; d[1] = max;
break;
default:
retval = -1;
break;
} // switch (dname)
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;
if (hasFillValue)
fill = ((byte[])fillValue)[0];
for (int i=0; ib[i]) {
minmax[0] = b[i];
}
if (minmax[1]s[i]) {
minmax[0] = s[i];
}
if (minmax[1]ia[i]) {
minmax[0] = ia[i];
}
if (minmax[1]l[i]) {
minmax[0] = l[i];
}
if (minmax[1]f[i]) {
minmax[0] = f[i];
}
if (minmax[1]d[i]) {
minmax[0] = d[i];
}
if (minmax[1]> (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)
{
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 n = theMask.length();
for (int i=0; i=0; j--) {
if (theMask.get(j)) {
if ((packedValue & 1) == 1)
packedValue = packedValue << 1;
packedValue += (theValue >> j) & 1;
}
}
bdata[i] = (byte)packedValue;
}
} else {
short[] sdata = (short[])theData;
for (int i=0; i=0; j--) {
if (theMask.get(j)) {
if ((packedValue & 1) == 1)
packedValue = packedValue << 1;
packedValue += (theValue >> j) & 1;
}
}
sdata[i] = (short)packedValue;
}
}
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+"\"";
Process p = 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});
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) */
}