001/***************************************************************************** 002 * Copyright by The HDF Group. * 003 * Copyright by the Board of Trustees of the University of Illinois. * 004 * All rights reserved. * 005 * * 006 * This file is part of the HDF Java Products distribution. * 007 * The full copyright notice, including terms governing use, modification, * 008 * and redistribution, is contained in the files COPYING and Copyright.html. * 009 * COPYING can be found at the root of the source code distribution tree. * 010 * Or, see https://support.hdfgroup.org/products/licenses.html * 011 * If you do not have access to either file, you may request a copy from * 012 * help@hdfgroup.org. * 013 ****************************************************************************/ 014 015package hdf.view; 016 017import java.awt.Graphics; 018import java.awt.Image; 019import java.awt.Toolkit; 020import java.awt.image.BufferedImage; 021import java.awt.image.ColorModel; 022import java.awt.image.DataBufferInt; 023import java.awt.image.DirectColorModel; 024import java.awt.image.MemoryImageSource; 025import java.awt.image.PixelGrabber; 026import java.io.BufferedInputStream; 027import java.io.BufferedOutputStream; 028import java.io.BufferedReader; 029import java.io.DataOutputStream; 030import java.io.File; 031import java.io.FileInputStream; 032import java.io.FileOutputStream; 033import java.io.FileReader; 034import java.io.IOException; 035import java.io.RandomAccessFile; 036import java.lang.reflect.Array; 037import java.lang.reflect.Constructor; 038import java.lang.reflect.Method; 039import java.math.BigInteger; 040import java.nio.ByteBuffer; 041import java.nio.ByteOrder; 042import java.nio.DoubleBuffer; 043import java.nio.FloatBuffer; 044import java.nio.IntBuffer; 045import java.nio.LongBuffer; 046import java.nio.ShortBuffer; 047import java.util.BitSet; 048import java.util.Iterator; 049import java.util.List; 050import java.util.StringTokenizer; 051 052import javax.imageio.ImageIO; 053 054import org.eclipse.jface.dialogs.MessageDialog; 055import org.eclipse.swt.widgets.Display; 056import org.eclipse.swt.widgets.Shell; 057 058import hdf.object.Datatype; 059import hdf.object.FileFormat; 060import hdf.object.Group; 061import hdf.object.ScalarDS; 062import hdf.view.ViewProperties.BITMASK_OP; 063 064/** 065 * The "Tools" class contains various tools for HDF files such as jpeg to HDF 066 * converter. 067 * 068 * @author Peter X. Cao 069 * @version 2.4 9/6/2007 070 */ 071public final class Tools { 072 private final static Display display = Display.getDefault(); 073 074 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Tools.class); 075 076 public static final long MAX_INT8 = 127; 077 public static final long MAX_UINT8 = 255; 078 public static final long MAX_INT16 = 32767; 079 public static final long MAX_UINT16 = 65535; 080 public static final long MAX_INT32 = 2147483647; 081 public static final long MAX_UINT32 = 4294967295L; 082 public static final long MAX_INT64 = 9223372036854775807L; 083 public static final BigInteger MAX_UINT64 = new BigInteger("18446744073709551615"); 084 085 private static final int FLOAT_BUFFER_SIZE = 524288; 086 private static final int INT_BUFFER_SIZE = 524288; 087 private static final int SHORT_BUFFER_SIZE = 1048576; 088 private static final int LONG_BUFFER_SIZE = 262144; 089 private static final int DOUBLE_BUFFER_SIZE = 262144; 090 private static final int BYTE_BUFFER_SIZE = 2097152; 091 092 /** Key for JPEG image file type. */ 093 public static final String FILE_TYPE_JPEG = "JPEG"; 094 095 /** Key for TIFF image file type. */ 096 public static final String FILE_TYPE_TIFF = "TIFF"; 097 098 /** Key for PNG image file type. */ 099 public static final String FILE_TYPE_PNG = "PNG"; 100 101 /** Key for GIF image file type. */ 102 public static final String FILE_TYPE_GIF = "GIF"; 103 104 /** Key for BMP image file type. */ 105 public static final String FILE_TYPE_BMP = "BMP"; 106 107 /** Key for all image file type. */ 108 public static final String FILE_TYPE_IMAGE = "IMG"; 109 110 /** Print out debug information 111 * @param caller 112 * the caller object. 113 * @param msg 114 * the message to be displayed. 115 */ 116 public static final void debug(Object caller, Object msg) { 117 if (caller != null) System.out.println("*** " + caller.getClass().getName() + ": " + msg); 118 } 119 120 /** 121 * Converts unsigned 64-bit integer data to a BigInteger since Java does not 122 * have unsigned types. 123 * 124 * @param l 125 * The long value to convert to a BigInteger 126 * 127 * @return A BigInteger representing the unsigned value of the given long. 128 */ 129 public static BigInteger convertUINT64toBigInt(Long l) { 130 if (l < 0) { 131 l = (l << 1) >>> 1; 132 BigInteger big1 = new BigInteger("9223372036854775808"); // 2^65 133 BigInteger big2 = new BigInteger(l.toString()); 134 return big1.add(big2); 135 } 136 else { 137 return new BigInteger(l.toString()); 138 } 139 } 140 141 /** 142 * Converts an image file into HDF4/5 file. 143 * 144 * @param imgFileName 145 * the input image file. 146 * @param hFileName 147 * the name of the HDF4/5 file. 148 * @param fromType 149 * the type of image. 150 * @param toType 151 * the type of file converted to. 152 * 153 * @throws Exception if a failure occurred 154 */ 155 public static void convertImageToHDF(String imgFileName, String hFileName, String fromType, String toType) 156 throws Exception { 157 File imgFile = null; 158 159 if (imgFileName == null) { 160 throw new NullPointerException("The source image file is null."); 161 } 162 else if (!(imgFile = new File(imgFileName)).exists()) { 163 throw new NullPointerException("The source image file does not exist."); 164 } 165 else if (hFileName == null) { 166 throw new NullPointerException("The target HDF file is null."); 167 } 168 169 if (!fromType.equals(FILE_TYPE_IMAGE)) { 170 throw new UnsupportedOperationException("Unsupported image type."); 171 } 172 else if (!(toType.equals(FileFormat.FILE_TYPE_HDF4) || toType.equals(FileFormat.FILE_TYPE_HDF5))) { 173 throw new UnsupportedOperationException("Unsupported destination file type."); 174 } 175 176 BufferedImage image = null; 177 try { 178 BufferedInputStream in = new BufferedInputStream(new FileInputStream(imgFileName)); 179 image = ImageIO.read(in); 180 in.close(); 181 } 182 catch (Throwable err) { 183 image = null; 184 } 185 186 if (image == null) throw new UnsupportedOperationException("Failed to read image: " + imgFileName); 187 188 long h = image.getHeight(); 189 long w = image.getWidth(); 190 byte[] data = null; 191 192 try { 193 data = new byte[(int)(3 * h * w)]; 194 } 195 catch (OutOfMemoryError err) { 196 err.printStackTrace(); 197 throw new RuntimeException("Out of memory error."); 198 } 199 200 int idx = 0; 201 int rgb = 0; 202 for (int i = 0; i < h; i++) { 203 for (int j = 0; j < w; j++) { 204 rgb = image.getRGB(j, i); 205 data[idx++] = (byte) (rgb >> 16); 206 data[idx++] = (byte) (rgb >> 8); 207 data[idx++] = (byte) rgb; 208 } 209 } 210 211 long[] dims = null; 212 Datatype type = null; 213 Group pgroup = null; 214 String imgName = imgFile.getName(); 215 FileFormat newfile = null, thefile = null; 216 if (toType.equals(FileFormat.FILE_TYPE_HDF5)) { 217 thefile = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5); 218 long[] h5dims = { h, w, 3 }; // RGB pixel interlace 219 dims = h5dims; 220 } 221 else if (toType.equals(FileFormat.FILE_TYPE_HDF4)) { 222 thefile = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4); 223 long[] h4dims = { w, h, 3 }; // RGB pixel interlace 224 dims = h4dims; 225 } 226 else { 227 thefile = null; 228 } 229 230 if (thefile != null) { 231 newfile = thefile.createInstance(hFileName, FileFormat.CREATE); 232 newfile.open(); 233 pgroup = (Group) newfile.getRootObject(); 234 type = newfile.createDatatype(Datatype.CLASS_CHAR, 1, Datatype.NATIVE, Datatype.SIGN_NONE); 235 newfile.createImage(imgName, pgroup, type, dims, null, null, -1, 3, ScalarDS.INTERLACE_PIXEL, data); 236 newfile.close(); 237 } 238 239 // clean up memory 240 data = null; 241 image = null; 242 Runtime.getRuntime().gc(); 243 } 244 245 /** 246 * Save a BufferedImage into an image file. 247 * 248 * @param image 249 * the BufferedImage to save. 250 * @param file 251 * the image file. 252 * @param type 253 * the image type. 254 * 255 * @throws Exception if a failure occurred 256 */ 257 public static void saveImageAs(BufferedImage image, File file, String type) throws Exception { 258 if (image == null) { 259 throw new NullPointerException("The source image is null."); 260 } 261 262 ImageIO.write(image, type, file); 263 } 264 265 /** 266 * Creates the gray palette of the indexed 256-color table. 267 * <p> 268 * The palette values are stored in a two-dimensional byte array and arrange 269 * by color components of red, green and blue. palette[][] = byte[3][256], 270 * where, palette[0][], palette[1][] and palette[2][] are the red, green and 271 * blue components respectively. 272 * 273 * @return the gray palette in the form of byte[3][256] 274 */ 275 public static final byte[][] createGrayPalette() { 276 byte[][] p = new byte[3][256]; 277 278 for (int i = 0; i < 256; i++) { 279 p[0][i] = p[1][i] = p[2][i] = (byte) (i); 280 } 281 282 return p; 283 } 284 285 /** 286 * Creates the reverse gray palette of the indexed 256-color table. 287 * <p> 288 * The palette values are stored in a two-dimensional byte array and arrange 289 * by color components of red, green and blue. palette[][] = byte[3][256], 290 * where, palette[0][], palette[1][] and palette[2][] are the red, green and 291 * blue components respectively. 292 * 293 * @return the gray palette in the form of byte[3][256] 294 */ 295 public static final byte[][] createReverseGrayPalette() { 296 byte[][] p = new byte[3][256]; 297 298 for (int i = 0; i < 256; i++) { 299 p[0][i] = p[1][i] = p[2][i] = (byte) (255 - i); 300 } 301 302 return p; 303 } 304 305 /** 306 * Creates the gray wave palette of the indexed 256-color table. 307 * <p> 308 * The palette values are stored in a two-dimensional byte array and arrange 309 * by color components of red, green and blue. palette[][] = byte[3][256], 310 * where, palette[0][], palette[1][] and palette[2][] are the red, green and 311 * blue components respectively. 312 * 313 * @return the gray palette in the form of byte[3][256] 314 */ 315 public static final byte[][] createGrayWavePalette() { 316 byte[][] p = new byte[3][256]; 317 318 for (int i = 0; i < 256; i++) { 319 p[0][i] = p[1][i] = p[2][i] = (byte) (255 / 2 + (255 / 2) * Math.sin((i - 32) / 20.3)); 320 } 321 322 return p; 323 } 324 325 /** 326 * Creates the rainbow palette of the indexed 256-color table. 327 * <p> 328 * The palette values are stored in a two-dimensional byte array and arrange 329 * by color components of red, green and blue. palette[][] = byte[3][256], 330 * where, palette[0][], palette[1][] and palette[2][] are the red, green and 331 * blue components respectively. 332 * 333 * @return the rainbow palette in the form of byte[3][256] 334 */ 335 public static final byte[][] createRainbowPalette() { 336 byte r, g, b; 337 byte[][] p = new byte[3][256]; 338 339 for (int i = 1; i < 255; i++) { 340 if (i <= 29) { 341 r = (byte) (129.36 - i * 4.36); 342 g = 0; 343 b = (byte) 255; 344 } 345 else if (i <= 86) { 346 r = 0; 347 g = (byte) (-133.54 + i * 4.52); 348 b = (byte) 255; 349 } 350 else if (i <= 141) { 351 r = 0; 352 g = (byte) 255; 353 b = (byte) (665.83 - i * 4.72); 354 } 355 else if (i <= 199) { 356 r = (byte) (-635.26 + i * 4.47); 357 g = (byte) 255; 358 b = 0; 359 } 360 else { 361 r = (byte) 255; 362 g = (byte) (1166.81 - i * 4.57); 363 b = 0; 364 } 365 366 p[0][i] = r; 367 p[1][i] = g; 368 p[2][i] = b; 369 } 370 371 p[0][0] = p[1][0] = p[2][0] = 0; 372 p[0][255] = p[1][255] = p[2][255] = (byte) 255; 373 374 return p; 375 } 376 377 /** 378 * Creates the nature palette of the indexed 256-color table. 379 * <p> 380 * The palette values are stored in a two-dimensional byte array and arrange 381 * by color components of red, green and blue. palette[][] = byte[3][256], 382 * where, palette[0][], palette[1][] and palette[2][] are the red, green and 383 * blue components respectively. 384 * 385 * @return the nature palette in the form of byte[3][256] 386 */ 387 public static final byte[][] createNaturePalette() { 388 byte[][] p = new byte[3][256]; 389 390 for (int i = 1; i < 210; i++) { 391 p[0][i] = (byte) ((Math.sin((double) (i - 5) / 16) + 1) * 90); 392 p[1][i] = (byte) ((1 - Math.sin((double) (i - 30) / 12)) * 64 * (1 - (double) i / 255) + 128 - i / 2); 393 p[2][i] = (byte) ((1 - Math.sin((double) (i - 8) / 9)) * 110 + 30); 394 } 395 396 for (int i = 210; i < 255; i++) { 397 p[0][i] = (byte) 80; 398 p[1][i] = (byte) 0; 399 p[2][i] = (byte) 200; 400 } 401 402 p[0][0] = p[1][0] = p[2][0] = 0; 403 p[0][255] = p[1][255] = p[2][255] = (byte) 255; 404 405 return p; 406 } 407 408 /** 409 * Creates the wave palette of the indexed 256-color table. 410 * <p> 411 * The palette values are stored in a two-dimensional byte array and arrange 412 * by color components of red, green and blue. palette[][] = byte[3][256], 413 * where, palette[0][], palette[1][] and palette[2][] are the red, green and 414 * blue components respectively. 415 * 416 * @return the wave palette in the form of byte[3][256] 417 */ 418 public static final byte[][] createWavePalette() { 419 byte[][] p = new byte[3][256]; 420 421 for (int i = 1; i < 255; i++) { 422 p[0][i] = (byte) ((Math.sin(((double) i / 40 - 3.2)) + 1) * 128); 423 p[1][i] = (byte) ((1 - Math.sin((i / 2.55 - 3.1))) * 70 + 30); 424 p[2][i] = (byte) ((1 - Math.sin(((double) i / 40 - 3.1))) * 128); 425 } 426 427 p[0][0] = p[1][0] = p[2][0] = 0; 428 p[0][255] = p[1][255] = p[2][255] = (byte) 255; 429 430 return p; 431 } 432 433 /** 434 * read an image palette from a file. 435 * 436 * A palette file has format of (value, red, green, blue). The color value 437 * in palette file can be either unsigned char [0..255] or float [0..1]. 438 * Float value will be converted to [0..255]. 439 * 440 * The color table in file can have any number of entries between 2 to 256. 441 * It will be converted to a color table of 256 entries. Any missing index 442 * will calculated by linear interpolation between the neighboring index 443 * values. For example, index 11 is missing in the following table 10 200 60 444 * 20 12 100 100 60 Index 11 will be calculated based on index 10 and index 445 * 12, i.e. 11 150 80 40 446 * 447 * @param filename 448 * the name of the palette file. 449 * 450 * @return the wave palette in the form of byte[3][256] 451 */ 452 public static final byte[][] readPalette(String filename) { 453 final int COLOR256 = 256; 454 BufferedReader in = null; 455 String line = null; 456 int nentries = 0, i, j, idx; 457 float v, r, g, b, ratio, max_v, min_v, max_color, min_color; 458 float[][] tbl = new float[COLOR256][4]; /* value, red, green, blue */ 459 460 if (filename == null) return null; 461 462 try { 463 in = new BufferedReader(new FileReader(filename)); 464 } 465 catch (Exception ex) { 466 log.debug("input file:", ex); 467 in = null; 468 } 469 470 if (in == null) return null; 471 472 idx = 0; 473 v = r = g = b = ratio = max_v = min_v = max_color = min_color = 0; 474 do { 475 try { 476 line = in.readLine(); 477 } 478 catch (Exception ex) { 479 log.debug("input file:", ex); 480 line = null; 481 } 482 483 if (line == null) continue; 484 485 StringTokenizer st = new StringTokenizer(line); 486 487 // invalid line 488 if (st.countTokens() != 4) { 489 continue; 490 } 491 492 try { 493 v = Float.valueOf(st.nextToken()); 494 r = Float.valueOf(st.nextToken()); 495 g = Float.valueOf(st.nextToken()); 496 b = Float.valueOf(st.nextToken()); 497 } 498 catch (NumberFormatException ex) { 499 log.debug("input file:", ex); 500 continue; 501 } 502 503 tbl[idx][0] = v; 504 tbl[idx][1] = r; 505 tbl[idx][2] = g; 506 tbl[idx][3] = b; 507 508 if (idx == 0) { 509 max_v = min_v = v; 510 max_color = min_color = r; 511 } 512 513 max_v = Math.max(max_v, v); 514 max_color = Math.max(max_color, r); 515 max_color = Math.max(max_color, g); 516 max_color = Math.max(max_color, b); 517 518 min_v = Math.min(min_v, v); 519 min_color = Math.min(min_color, r); 520 min_color = Math.min(min_color, g); 521 min_color = Math.min(min_color, b); 522 523 idx++; 524 if (idx >= COLOR256) break; /* only support to 256 colors */ 525 } while (line != null); 526 527 try { 528 in.close(); 529 } 530 catch (Exception ex) { 531 log.debug("input file:", ex); 532 } 533 534 nentries = idx; 535 if (nentries <= 1) // must have more than one entries 536 return null; 537 538 // convert color table to byte 539 nentries = idx; 540 if (max_color <= 1) { 541 ratio = (min_color == max_color) ? 1.0f : ((COLOR256 - 1.0f) / (max_color - min_color)); 542 543 for (i = 0; i < nentries; i++) { 544 for (j = 1; j < 4; j++) 545 tbl[i][j] = (tbl[i][j] - min_color) * ratio; 546 } 547 } 548 549 // convert table to 256 entries 550 idx = 0; 551 ratio = (min_v == max_v) ? 1.0f : ((COLOR256 - 1.0f) / (max_v - min_v)); 552 553 int[][] p = new int[3][COLOR256]; 554 for (i = 0; i < nentries; i++) { 555 idx = (int) ((tbl[i][0] - min_v) * ratio); 556 for (j = 0; j < 3; j++) 557 p[j][idx] = (int) tbl[i][j + 1]; 558 } 559 560 /* linear interpolating missing values in the color table */ 561 for (i = 1; i < COLOR256; i++) { 562 if ((p[0][i] + p[1][i] + p[2][i]) == 0) { 563 j = i + 1; 564 565 // figure out number of missing points between two given points 566 while (j < COLOR256 && (p[0][j] + p[1][j] + p[2][j]) == 0) 567 j++; 568 569 if (j >= COLOR256) break; // nothing in the table to interpolating 570 571 float d1 = (p[0][j] - p[0][i - 1]) / (j - i); 572 float d2 = (p[1][j] - p[1][i - 1]) / (j - i); 573 float d3 = (p[2][j] - p[2][i - 1]) / (j - i); 574 575 for (int k = i; k <= j; k++) { 576 p[0][k] = (int) (p[0][i - 1] + d1 * (k - i + 1)); 577 p[1][k] = (int) (p[1][i - 1] + d2 * (k - i + 1)); 578 p[2][k] = (int) (p[2][i - 1] + d3 * (k - i + 1)); 579 } 580 i = j + 1; 581 } // if ((p[0][i] + p[1][i] + p[2][i]) == 0) 582 } // for (i = 1; i < COLOR256; i++) { 583 584 byte[][] pal = new byte[3][COLOR256]; 585 for (i = 1; i < COLOR256; i++) { 586 for (j = 0; j < 3; j++) 587 pal[j][i] = (byte) (p[j][i]); 588 } 589 590 return pal; 591 } 592 593 /** 594 * This method returns true if the specified image has transparent pixels. 595 * 596 * @param image 597 * the image to be check if has alpha. 598 * 599 * @return true if the image has alpha setting. 600 */ 601 public static boolean hasAlpha(Image image) { 602 if (image == null) { 603 return false; 604 } 605 606 // If buffered image, the color model is readily available 607 if (image instanceof BufferedImage) { 608 BufferedImage bimage = (BufferedImage) image; 609 return bimage.getColorModel().hasAlpha(); 610 } 611 612 // Use a pixel grabber to retrieve the image's color model; 613 // grabbing a single pixel is usually sufficient 614 PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false); 615 try { 616 pg.grabPixels(); 617 } 618 catch (InterruptedException e) { 619 log.debug("transparent pixels:", e); 620 } 621 ColorModel cm = pg.getColorModel(); 622 623 return cm.hasAlpha(); 624 } 625 626 /** 627 * Creates a RGB indexed image of 256 colors. 628 * 629 * @param bufferedImage 630 * the target image. 631 * @param imageData 632 * the byte array of the image data. 633 * @param palette 634 * the color lookup table. 635 * @param w 636 * the width of the image. 637 * @param h 638 * the height of the image. 639 * 640 * @return the image. 641 */ 642 public static Image createIndexedImage(BufferedImage bufferedImage, byte[] imageData, byte[][] palette, long w, long h) 643 { 644 if (imageData==null || w<=0 || h<=0) 645 return null; 646 647 if (palette==null) 648 palette = Tools.createGrayPalette(); 649 650 if (bufferedImage == null) 651 bufferedImage = new BufferedImage((int)w, (int)h, BufferedImage.TYPE_INT_ARGB); 652 653 final int[] pixels = ( (DataBufferInt) bufferedImage.getRaster().getDataBuffer() ).getData(); 654 int len = pixels.length; 655 656 for (int i=0; i<len; i++) { 657 int idx = imageData[i] & 0xff; 658 int r = (palette[0][idx] & 0xff)<<16; 659 int g = (palette[1][idx] & 0xff)<<8; 660 int b = palette[2][idx] & 0xff; 661 662 pixels[i] = 0xff000000 | r | g | b; 663 } 664 665 return bufferedImage; 666 } 667 668 /** 669 * Creates a true color image. 670 * <p> 671 * DirectColorModel is used to construct the image from raw data. The 672 * DirectColorModel model is similar to an X11 TrueColor visual, which has 673 * the following parameters: <br> 674 * 675 * <pre> 676 * Number of bits: 32 677 * Red mask: 0x00ff0000 678 * Green mask: 0x0000ff00 679 * Blue mask: 0x000000ff 680 * Alpha mask: 0xff000000 681 * Color space: sRGB 682 * isAlphaPremultiplied: False 683 * Transparency: Transparency.TRANSLUCENT 684 * transferType: DataBuffer.TYPE_INT 685 * </pre> 686 * <p> 687 * The data may be arranged in one of two ways: by pixel or by plane. In 688 * both cases, the dataset will have a dataspace with three dimensions, 689 * height, width, and components. 690 * <p> 691 * For HDF4, the interlace modes specify orders for the dimensions as: 692 * 693 * <pre> 694 * INTERLACE_PIXEL = [width][height][pixel components] 695 * INTERLACE_PLANE = [pixel components][width][height] 696 * </pre> 697 * <p> 698 * For HDF5, the interlace modes specify orders for the dimensions as: 699 * 700 * <pre> 701 * INTERLACE_PIXEL = [height][width][pixel components] 702 * INTERLACE_PLANE = [pixel components][height][width] 703 * </pre> 704 * 705 * @param imageData 706 * the byte array of the image data. 707 * @param planeInterlace 708 * flag if the image is plane intelace. 709 * @param w 710 * the width of the image. 711 * @param h 712 * the height of the image. 713 * 714 * @return the image. 715 */ 716 public static Image createTrueColorImage(byte[] imageData, boolean planeInterlace, long w, long h) { 717 Image theImage = null; 718 long imgSize = w * h; 719 int packedImageData[] = new int[(int)imgSize]; 720 int pixel = 0, idx = 0, r = 0, g = 0, b = 0; 721 for (int i = 0; i < h; i++) { 722 for (int j = 0; j < w; j++) { 723 pixel = r = g = b = 0; 724 if (planeInterlace) { 725 r = imageData[idx]; 726 g = imageData[(int)imgSize + idx]; 727 b = imageData[(int)imgSize * 2 + idx]; 728 } 729 else { 730 r = imageData[idx * 3]; 731 g = imageData[idx * 3 + 1]; 732 b = imageData[idx * 3 + 2]; 733 } 734 735 r = (r << 16) & 0x00ff0000; 736 g = (g << 8) & 0x0000ff00; 737 b = b & 0x000000ff; 738 739 // bits packed into alpha (1), red (r), green (g) and blue (b) 740 // as 11111111rrrrrrrrggggggggbbbbbbbb 741 pixel = 0xff000000 | r | g | b; 742 packedImageData[idx++] = pixel; 743 } // for (int j=0; j<w; j++) 744 } // for (int i=0; i<h; i++) 745 746 DirectColorModel dcm = (DirectColorModel) ColorModel.getRGBdefault(); 747 theImage = Toolkit.getDefaultToolkit().createImage(new MemoryImageSource((int)w, (int)h, dcm, packedImageData, 0, (int)w)); 748 749 packedImageData = null; 750 751 return theImage; 752 } 753 754 /** 755 * This method returns a buffered image with the contents of an image. 756 * 757 * @param image 758 * the plain image object. 759 * 760 * @return buffered image for the given image. 761 */ 762 public static BufferedImage toBufferedImage(Image image) { 763 if (image == null) { 764 return null; 765 } 766 767 if (image instanceof BufferedImage) { 768 return (BufferedImage) image; 769 } 770 771 // !!!!!!!!!!!!!!!!!! NOTICE !!!!!!!!!!!!!!!!!!!!! 772 // the following way of creating a buffered image is using 773 // Component.createImage(). This method can be used only if the 774 // component is visible on the screen. Also, this method returns 775 // buffered images that do not support transparent pixels. 776 // The buffered image created by this way works for package 777 // com.sun.image.codec.jpeg.* 778 // It does not work well with JavaTM Advanced Imaging 779 // com.sun.media.jai.codec.*; 780 // if the screen setting is less than 32-bit color 781 int w = image.getWidth(null); 782 int h = image.getHeight(null); 783 BufferedImage bimage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); 784 Graphics g = bimage.createGraphics(); 785 g.drawImage(image, 0, 0, null); 786 787 g.dispose(); 788 return bimage; 789 } 790 791 /** 792 * Convert an array of raw data into array of a byte data. 793 * 794 * @param rawData 795 * The input raw data. 796 * @param minmax 797 * the range of the raw data. 798 * @param w 799 * the width of the raw data. 800 * @param h 801 * the height of the raw data. 802 * @param isTransposed 803 * if the data is transposed. 804 * @param byteData 805 * the data in. 806 * 807 * @return the byte array of pixel data. 808 */ 809 public static byte[] getBytes(Object rawData, double[] minmax, long w, long h, boolean isTransposed, byte[] byteData) { 810 return Tools.getBytes(rawData, minmax, w, h, isTransposed, null, false, byteData); 811 } 812 813 public static byte[] getBytes(Object rawData, double[] minmax, long w, long h, boolean isTransposed, 814 List<Number> invalidValues, byte[] byteData) { 815 return getBytes(rawData, minmax, w, h, isTransposed, invalidValues, false, byteData); 816 } 817 818 public static byte[] getBytes(Object rawData, double[] minmax, long w, long h, boolean isTransposed, 819 List<Number> invalidValues, boolean convertByteData, byte[] byteData) { 820 return getBytes(rawData, minmax, w, h, isTransposed,invalidValues, convertByteData, byteData, null); 821 } 822 823 /** 824 * Convert an array of raw data into array of a byte data. 825 * 826 * @param rawData 827 * The input raw data. 828 * @param minmax 829 * the range of the raw data. 830 * @param w 831 * the width of the raw data. 832 * @param h 833 * the height of the raw data. 834 * @param isTransposed 835 * if the data is transposed. 836 * @param invalidValues 837 * the list of invalid values. 838 * @param convertByteData 839 * the converted data out. 840 * @param byteData 841 * the data in. 842 * @param list 843 * the list of integers. 844 * 845 * @return the byte array of pixel data. 846 */ 847 public static byte[] getBytes(Object rawData, double[] minmax, long w, long h, boolean isTransposed, 848 List<Number> invalidValues, boolean convertByteData, byte[] byteData, List<Integer> list) 849 { 850 double fillValue[] = null; 851 852 // no input data 853 if (rawData == null || w<=0 || h<=0) { 854 return null; 855 } 856 857 // input data is not an array 858 if (!rawData.getClass().isArray()) { 859 return null; 860 } 861 862 double min = Double.MAX_VALUE, max = -Double.MAX_VALUE, ratio = 1.0d; 863 String cname = rawData.getClass().getName(); 864 char dname = cname.charAt(cname.lastIndexOf("[") + 1); 865 int size = Array.getLength(rawData); 866 867 if (minmax == null) { 868 minmax = new double[2]; 869 minmax[0] = minmax[1] = 0; 870 } 871 872 if (dname == 'B') { 873 return convertByteData((byte[]) rawData, minmax, w, h, isTransposed, fillValue, convertByteData, byteData, list); 874 } 875 876 if ((byteData == null) || (size != byteData.length)) { 877 byteData = new byte[size]; // reuse the old buffer 878 } 879 880 if (minmax[0] == minmax[1]) { 881 Tools.findMinMax(rawData, minmax, fillValue); 882 } 883 884 min = minmax[0]; 885 max = minmax[1]; 886 887 if (invalidValues!=null && invalidValues.size()>0) { 888 int n = invalidValues.size(); 889 fillValue = new double[n]; 890 for (int i=0; i<n; i++) { 891 fillValue[i] = invalidValues.get(i).doubleValue(); 892 } 893 } 894 ratio = (min == max) ? 1.00d : (double) (255.00 / (max - min)); 895 long idxSrc = 0, idxDst = 0; 896 switch (dname) { 897 case 'S': 898 short[] s = (short[]) rawData; 899 for (long i = 0; i < h; i++) { 900 for (long j = 0; j < w; j++) { 901 idxSrc = idxDst =j * h + i; 902 if (isTransposed) idxDst = i * w + j; 903 byteData[(int)idxDst] = toByte(s[(int)idxSrc], ratio, min, max, fillValue, (int)idxSrc, list); 904 } 905 } 906 break; 907 908 case 'I': 909 int[] ia = (int[]) rawData; 910 for (long i = 0; i < h; i++) { 911 for (long j = 0; j < w; j++) { 912 idxSrc = idxDst = (j * h + i); 913 if (isTransposed) idxDst = i * w + j; 914 byteData[(int)idxDst] = toByte(ia[(int)idxSrc], ratio, min, max, fillValue, (int)idxSrc, list); 915 } 916 } 917 break; 918 919 case 'J': 920 long[] l = (long[]) rawData; 921 for (long i = 0; i < h; i++) { 922 for (long j = 0; j < w; j++) { 923 idxSrc = idxDst =j * h + i; 924 if (isTransposed) idxDst = i * w + j; 925 byteData[(int)idxDst] = toByte(l[(int)idxSrc], ratio, min, max, fillValue, (int)idxSrc, list); 926 } 927 } 928 break; 929 930 case 'F': 931 float[] f = (float[]) rawData; 932 for (long i = 0; i < h; i++) { 933 for (long j = 0; j < w; j++) { 934 idxSrc = idxDst =j * h + i; 935 if (isTransposed) idxDst = i * w + j; 936 byteData[(int)idxDst] = toByte(f[(int)idxSrc], ratio, min, max, fillValue, (int)idxSrc, list); 937 } 938 } 939 break; 940 941 case 'D': 942 double[] d = (double[]) rawData; 943 for (long i = 0; i < h; i++) { 944 for (long j = 0; j < w; j++) { 945 idxSrc = idxDst =j * h + i; 946 if (isTransposed) idxDst = i * w + j; 947 byteData[(int)idxDst] = toByte(d[(int)idxSrc], ratio, min, max, fillValue, (int)idxSrc, list); 948 } 949 } 950 break; 951 952 default: 953 byteData = null; 954 break; 955 } // switch (dname) 956 957 return byteData; 958 } 959 960 private static byte toByte(double in, double ratio, double min, double max, double[] fill, int idx, List<Integer> list) 961 { 962 byte out = 0; 963 964 if (in < min || in > max || isFillValue(in, fill) || isNaNINF(in)) { 965 out = 0; 966 if (list!=null) 967 list.add(idx); 968 } 969 else 970 out = (byte) ((in-min)*ratio); 971 972 return out; 973 } 974 975 private static boolean isFillValue(double in, double[] fill) { 976 977 if (fill==null) 978 return false; 979 980 for (int i=0; i<fill.length; i++) { 981 if (fill[i] == in) 982 return true; 983 } 984 985 return false; 986 } 987 988 private static byte[] convertByteData(byte[] rawData, double[] minmax, long w, long h, boolean isTransposed, 989 Object fillValue, boolean convertByteData, byte[] byteData, List<Integer> list) { 990 double min = Double.MAX_VALUE, max = -Double.MAX_VALUE, ratio = 1.0d; 991 992 if (rawData == null) return null; 993 994 if (convertByteData) { 995 if (minmax[0] == minmax[1]) { 996 Tools.findMinMax(rawData, minmax, fillValue); 997 } 998 } 999 1000 if (minmax[0] == 0 && minmax[1] == 255) convertByteData = false; // no need to convert data 1001 1002 // no conversion and no transpose 1003 if (!convertByteData && !isTransposed) { 1004 if (byteData != null && byteData.length == rawData.length) { 1005 System.arraycopy(rawData, 0, byteData, 0, rawData.length); 1006 return byteData; 1007 } 1008 1009 return rawData; 1010 } 1011 1012 // don't want to change the original raw data 1013 if (byteData == null || rawData == byteData) byteData = new byte[rawData.length]; 1014 1015 if (!convertByteData) { 1016 // do not convert data, just transpose the data 1017 minmax[0] = 0; 1018 minmax[1] = 255; 1019 if (isTransposed) { 1020 for (long i = 0; i < h; i++) { 1021 for (long j = 0; j < w; j++) { 1022 byteData[(int)(i * w + j)] = rawData[(int)(j * h + i)]; 1023 } 1024 } 1025 } 1026 return byteData; 1027 } 1028 1029 // special data range used, must convert the data 1030 min = minmax[0]; 1031 max = minmax[1]; 1032 ratio = (min == max) ? 1.00d : (double) (255.00 / (max - min)); 1033 long idxSrc = 0, idxDst = 0; 1034 for (long i = 0; i < h; i++) { 1035 for (long j = 0; j < w; j++) { 1036 idxSrc = idxDst =j * h + i; 1037 if (isTransposed) idxDst = i * w + j; 1038 1039 if (rawData[(int) idxSrc] > max || rawData[(int) idxSrc] < min) { 1040 byteData[(int)idxDst] = (byte) 0; 1041 if (list!=null) 1042 list.add((int)idxSrc); 1043 } 1044 else 1045 byteData[(int)idxDst] = (byte) ((rawData[(int)idxSrc] - min) * ratio); 1046 } 1047 } 1048 1049 return byteData; 1050 } 1051 1052 /** 1053 * Create and initialize a new instance of the given class. 1054 * 1055 * @param cls 1056 * the class of the instance 1057 * @param initargs 1058 * array of objects to be passed as arguments. 1059 * 1060 * @return a new instance of the given class. 1061 * 1062 * @throws Exception if a failure occurred 1063 */ 1064 public static Object newInstance(Class<?> cls, Object[] initargs) throws Exception { 1065 log.trace("newInstance(Class = {}): start", cls); 1066 1067 if (cls == null) { 1068 return null; 1069 } 1070 1071 Object instance = null; 1072 1073 if ((initargs == null) || (initargs.length == 0)) { 1074 instance = cls.getDeclaredConstructor().newInstance(); 1075 } 1076 else { 1077 Constructor<?>[] constructors = cls.getConstructors(); 1078 if ((constructors == null) || (constructors.length == 0)) { 1079 return null; 1080 } 1081 1082 boolean isConstructorMatched = false; 1083 Constructor<?> constructor = null; 1084 Class<?>[] params = null; 1085 int m = constructors.length; 1086 int n = initargs.length; 1087 for (int i = 0; i < m; i++) { 1088 constructor = constructors[i]; 1089 params = constructor.getParameterTypes(); 1090 if (params.length == n) { 1091 // check if all the parameters are matched 1092 isConstructorMatched = params[0].isInstance(initargs[0]); 1093 for (int j = 0; j < n; j++) { 1094 isConstructorMatched = isConstructorMatched && params[j].isInstance(initargs[j]); 1095 } 1096 1097 if (isConstructorMatched) { 1098 try { 1099 instance = constructor.newInstance(initargs); 1100 } 1101 catch (Exception ex) { 1102 log.debug("Error creating instance of {}: ", cls, ex); 1103 ex.printStackTrace(); 1104 } 1105 break; 1106 } 1107 } 1108 } // for (int i=0; i<m; i++) { 1109 } 1110 log.trace("newInstance(Class = {}): finish", cls); 1111 1112 return instance; 1113 } 1114 1115 /** 1116 * Computes autocontrast parameters (gain equates to contrast and bias 1117 * equates to brightness) for integers. 1118 * <p> 1119 * The computation is based on the following scaling 1120 * 1121 * <pre> 1122 * int_8 [0, 127] 1123 * uint_8 [0, 255] 1124 * int_16 [0, 32767] 1125 * uint_16 [0, 65535] 1126 * int_32 [0, 2147483647] 1127 * uint_32 [0, 4294967295] 1128 * int_64 [0, 9223372036854775807] 1129 * uint_64 [0, 18446744073709551615] // Not supported. 1130 * </pre> 1131 * 1132 * @param data 1133 * the raw data array of signed/unsigned integers 1134 * @param params 1135 * the auto gain parameter. params[0]=gain, params[1]=bias, 1136 * @param isUnsigned 1137 * the flag to indicate if the data array is unsigned integer. 1138 * 1139 * @return non-negative if successful; otherwise, returns negative 1140 */ 1141 public static int autoContrastCompute(Object data, double[] params, boolean isUnsigned) { 1142 int retval = 1; 1143 long maxDataValue = 255; 1144 double[] minmax = new double[2]; 1145 1146 // check parameters 1147 if ((data == null) || (params == null) || (Array.getLength(data) <= 0) || (params.length < 2)) { 1148 return -1; 1149 } 1150 1151 retval = autoContrastComputeMinMax(data, minmax); 1152 1153 // force the min_max method so we can look at the target grids data sets 1154 if ((retval < 0) || (minmax[1] - minmax[0] < 10)) { 1155 retval = findMinMax(data, minmax, null); 1156 } 1157 1158 if (retval < 0) { 1159 return -1; 1160 } 1161 1162 String cname = data.getClass().getName(); 1163 char dname = cname.charAt(cname.lastIndexOf("[") + 1); 1164 switch (dname) { 1165 case 'B': 1166 maxDataValue = MAX_INT8; 1167 break; 1168 case 'S': 1169 maxDataValue = MAX_INT16; 1170 if (isUnsigned) { 1171 maxDataValue = MAX_UINT8; // data was upgraded from unsigned byte 1172 } 1173 break; 1174 case 'I': 1175 maxDataValue = MAX_INT32; 1176 if (isUnsigned) { 1177 maxDataValue = MAX_UINT16; // data was upgraded from unsigned short 1178 } 1179 break; 1180 case 'J': 1181 maxDataValue = MAX_INT64; 1182 if (isUnsigned) { 1183 maxDataValue = MAX_UINT32; // data was upgraded from unsigned int 1184 } 1185 break; 1186 default: 1187 retval = -1; 1188 break; 1189 } // switch (dname) 1190 1191 if (minmax[0] == minmax[1]) { 1192 params[0] = 1.0; 1193 params[1] = 0.0; 1194 } 1195 else { 1196 // This histogram method has a tendency to stretch the 1197 // range of values to be a bit too big, so we can 1198 // account for this by adding and subtracting some percent 1199 // of the difference to the max/min values 1200 // to prevent the gain from going too high. 1201 double diff = minmax[1] - minmax[0]; 1202 double newmax = (minmax[1] + (diff * 0.1)); 1203 double newmin = (minmax[0] - (diff * 0.1)); 1204 1205 if (newmax <= maxDataValue) { 1206 minmax[1] = newmax; 1207 } 1208 1209 if (newmin >= 0) { 1210 minmax[0] = newmin; 1211 } 1212 1213 params[0] = maxDataValue / (minmax[1] - minmax[0]); 1214 params[1] = -minmax[0]; 1215 } 1216 1217 return retval; 1218 } 1219 1220 /** 1221 * Apply autocontrast parameters to the original data in place (destructive) 1222 * 1223 * @param data_in 1224 * the original data array of signed/unsigned integers 1225 * @param data_out 1226 * the converted data array of signed/unsigned integers 1227 * @param params 1228 * the auto gain parameter. params[0]=gain, params[1]=bias 1229 * @param minmax 1230 * the data range. minmax[0]=min, minmax[1]=max 1231 * @param isUnsigned 1232 * the flag to indicate if the data array is unsigned integer 1233 * 1234 * @return the data array with the auto contrast conversion; otherwise, 1235 * returns null 1236 */ 1237 public static Object autoContrastApply(Object data_in, Object data_out, double[] params, double[] minmax, 1238 boolean isUnsigned) { 1239 int size = 0; 1240 double min = -MAX_INT64, max = MAX_INT64; 1241 1242 if ((data_in == null) || (params == null) || (params.length < 2)) { 1243 return null; 1244 } 1245 1246 if (minmax != null) { 1247 min = minmax[0]; 1248 max = minmax[1]; 1249 } 1250 // input and output array must be the same size 1251 size = Array.getLength(data_in); 1252 if ((data_out != null) && (size != Array.getLength(data_out))) { 1253 return null; 1254 } 1255 1256 double gain = params[0]; 1257 double bias = params[1]; 1258 double value_out, value_in; 1259 String cname = data_in.getClass().getName(); 1260 char dname = cname.charAt(cname.lastIndexOf("[") + 1); 1261 1262 switch (dname) { 1263 case 'B': 1264 byte[] b_in = (byte[]) data_in; 1265 if (data_out == null) { 1266 data_out = new byte[size]; 1267 } 1268 byte[] b_out = (byte[]) data_out; 1269 byte b_max = (byte) MAX_INT8; 1270 1271 for (int i = 0; i < size; i++) { 1272 value_in = Math.max(b_in[i], min); 1273 value_in = Math.min(b_in[i], max); 1274 value_out = (value_in + bias) * gain; 1275 value_out = Math.max(value_out, 0.0); 1276 value_out = Math.min(value_out, b_max); 1277 b_out[i] = (byte) value_out; 1278 } 1279 break; 1280 case 'S': 1281 short[] s_in = (short[]) data_in; 1282 if (data_out == null) { 1283 data_out = new short[size]; 1284 } 1285 short[] s_out = (short[]) data_out; 1286 short s_max = (short) MAX_INT16; 1287 1288 if (isUnsigned) { 1289 s_max = (short) MAX_UINT8; // data was upgraded from unsigned byte 1290 } 1291 1292 for (int i = 0; i < size; i++) { 1293 value_in = Math.max(s_in[i], min); 1294 value_in = Math.min(s_in[i], max); 1295 value_out = (value_in + bias) * gain; 1296 value_out = Math.max(value_out, 0.0); 1297 value_out = Math.min(value_out, s_max); 1298 s_out[i] = (byte) value_out; 1299 } 1300 break; 1301 case 'I': 1302 int[] i_in = (int[]) data_in; 1303 if (data_out == null) { 1304 data_out = new int[size]; 1305 } 1306 int[] i_out = (int[]) data_out; 1307 int i_max = (int) MAX_INT32; 1308 if (isUnsigned) { 1309 i_max = (int) MAX_UINT16; // data was upgraded from unsigned short 1310 } 1311 1312 for (int i = 0; i < size; i++) { 1313 value_in = Math.max(i_in[i], min); 1314 value_in = Math.min(i_in[i], max); 1315 value_out = (value_in + bias) * gain; 1316 value_out = Math.max(value_out, 0.0); 1317 value_out = Math.min(value_out, i_max); 1318 i_out[i] = (byte) value_out; 1319 } 1320 break; 1321 case 'J': 1322 long[] l_in = (long[]) data_in; 1323 if (data_out == null) { 1324 data_out = new long[size]; 1325 } 1326 long[] l_out = (long[]) data_out; 1327 long l_max = MAX_INT64; 1328 if (isUnsigned) { 1329 l_max = MAX_UINT32; // data was upgraded from unsigned int 1330 } 1331 1332 for (int i = 0; i < size; i++) { 1333 value_in = Math.max(l_in[i], min); 1334 value_in = Math.min(l_in[i], max); 1335 value_out = (value_in + bias) * gain; 1336 value_out = Math.max(value_out, 0.0); 1337 value_out = Math.min(value_out, l_max); 1338 l_out[i] = (byte) value_out; 1339 } 1340 break; 1341 default: 1342 break; 1343 } // switch (dname) 1344 1345 return data_out; 1346 } 1347 1348 /** 1349 * Converts image raw data to bytes. 1350 * 1351 * The integer data is converted to byte data based on the following rule 1352 * 1353 * <pre> 1354 * uint_8 x 1355 * int_8 (x & 0x7F) << 1 1356 * uint_16 (x >> 8) & 0xFF 1357 * int_16 (x >> 7) & 0xFF 1358 * uint_32 (x >> 24) & 0xFF 1359 * int_32 (x >> 23) & 0xFF 1360 * uint_64 (x >> 56) & 0xFF 1361 * int_64 (x >> 55) & 0xFF 1362 * </pre> 1363 * 1364 * @param src 1365 * the source data array of signed integers or unsigned shorts 1366 * @param dst 1367 * the destination data array of bytes 1368 * @param isUnsigned 1369 * the flag to indicate if the data array is unsigned integer. 1370 * 1371 * @return non-negative if successful; otherwise, returns negative 1372 */ 1373 public static int autoContrastConvertImageBuffer(Object src, byte[] dst, boolean isUnsigned) { 1374 int retval = 0; 1375 1376 if ((src == null) || (dst == null) || (dst.length != Array.getLength(src))) { 1377 return -1; 1378 } 1379 1380 int size = dst.length; 1381 String cname = src.getClass().getName(); 1382 char dname = cname.charAt(cname.lastIndexOf("[") + 1); 1383 switch (dname) { 1384 case 'B': 1385 byte[] b_src = (byte[]) src; 1386 if (isUnsigned) { 1387 for (int i = 0; i < size; i++) { 1388 dst[i] = b_src[i]; 1389 } 1390 } 1391 else { 1392 for (int i = 0; i < size; i++) { 1393 dst[i] = (byte) ((b_src[i] & 0x7F) << 1); 1394 } 1395 } 1396 break; 1397 case 'S': 1398 short[] s_src = (short[]) src; 1399 if (isUnsigned) { // data was upgraded from unsigned byte 1400 for (int i = 0; i < size; i++) { 1401 dst[i] = (byte) s_src[i]; 1402 } 1403 } 1404 else { 1405 for (int i = 0; i < size; i++) { 1406 dst[i] = (byte) ((s_src[i] >> 7) & 0xFF); 1407 } 1408 } 1409 break; 1410 case 'I': 1411 int[] i_src = (int[]) src; 1412 if (isUnsigned) { // data was upgraded from unsigned short 1413 for (int i = 0; i < size; i++) { 1414 dst[i] = (byte) ((i_src[i] >> 8) & 0xFF); 1415 } 1416 } 1417 else { 1418 for (int i = 0; i < size; i++) { 1419 dst[i] = (byte) ((i_src[i] >> 23) & 0xFF); 1420 } 1421 } 1422 break; 1423 case 'J': 1424 long[] l_src = (long[]) src; 1425 if (isUnsigned) { // data was upgraded from unsigned int 1426 for (int i = 0; i < size; i++) { 1427 dst[i] = (byte) ((l_src[i] >> 24) & 0xFF); 1428 } 1429 } 1430 else { 1431 for (int i = 0; i < size; i++) { 1432 dst[i] = (byte) ((l_src[i] >> 55) & 0xFF); 1433 } 1434 } 1435 break; 1436 default: 1437 retval = -1; 1438 break; 1439 } // switch (dname) 1440 1441 return retval; 1442 } 1443 1444 /** 1445 * Computes autocontrast parameters by 1446 * 1447 * <pre> 1448 * min = mean - 3 * std.dev 1449 * max = mean + 3 * std.dev 1450 * </pre> 1451 * 1452 * @param data 1453 * the raw data array 1454 * @param minmax 1455 * the min and max values. 1456 * 1457 * @return non-negative if successful; otherwise, returns negative 1458 */ 1459 public static int autoContrastComputeMinMax(Object data, double[] minmax) { 1460 int retval = 1; 1461 1462 if ((data == null) || (minmax == null) || (Array.getLength(data) <= 0) || (Array.getLength(minmax) < 2)) { 1463 return -1; 1464 } 1465 1466 double[] avgstd = { 0, 0 }; 1467 retval = computeStatistics(data, avgstd, null); 1468 if (retval < 0) { 1469 return retval; 1470 } 1471 1472 minmax[0] = avgstd[0] - 3.0 * avgstd[1]; 1473 minmax[1] = avgstd[0] + 3.0 * avgstd[1]; 1474 1475 return retval; 1476 } 1477 1478 /** 1479 * Finds the min and max values of the data array 1480 * 1481 * @param data 1482 * the raw data array 1483 * @param minmax 1484 * the mmin and max values of the array. 1485 * @param fillValue 1486 * the missing value or fill value. Exclude this value when check 1487 * for min/max 1488 * 1489 * @return non-negative if successful; otherwise, returns negative 1490 */ 1491 public static int findMinMax(Object data, double[] minmax, Object fillValue) { 1492 int retval = 1; 1493 1494 if ((data == null) || (minmax == null) || (Array.getLength(data) <= 0) || (Array.getLength(minmax) < 2)) { 1495 return -1; 1496 } 1497 1498 int n = Array.getLength(data); 1499 double fill = 0.0; 1500 boolean hasFillValue = (fillValue != null && fillValue.getClass().isArray()); 1501 1502 String cname = data.getClass().getName(); 1503 char dname = cname.charAt(cname.lastIndexOf("[") + 1); 1504 log.trace("findMinMax() cname={} : dname={}", cname, dname); 1505 1506 minmax[0] = Float.MAX_VALUE; 1507 minmax[1] = -Float.MAX_VALUE; 1508 1509 switch (dname) { 1510 case 'B': 1511 byte[] b = (byte[]) data; 1512 minmax[0] = minmax[1] = b[0]; 1513 1514 if (hasFillValue) fill = ((byte[]) fillValue)[0]; 1515 for (int i = 0; i < n; i++) { 1516 if (hasFillValue && b[i] == fill) continue; 1517 if (minmax[0] > b[i]) { 1518 minmax[0] = b[i]; 1519 } 1520 if (minmax[1] < b[i]) { 1521 minmax[1] = b[i]; 1522 } 1523 } 1524 break; 1525 case 'S': 1526 short[] s = (short[]) data; 1527 minmax[0] = minmax[1] = s[0]; 1528 1529 if (hasFillValue) fill = ((short[]) fillValue)[0]; 1530 1531 for (int i = 0; i < n; i++) { 1532 if (hasFillValue && s[i] == fill) continue; 1533 if (minmax[0] > s[i]) { 1534 minmax[0] = s[i]; 1535 } 1536 if (minmax[1] < s[i]) { 1537 minmax[1] = s[i]; 1538 } 1539 } 1540 break; 1541 case 'I': 1542 int[] ia = (int[]) data; 1543 minmax[0] = minmax[1] = ia[0]; 1544 1545 if (hasFillValue) fill = ((int[]) fillValue)[0]; 1546 1547 for (int i = 0; i < n; i++) { 1548 if (hasFillValue && ia[i] == fill) continue; 1549 if (minmax[0] > ia[i]) { 1550 minmax[0] = ia[i]; 1551 } 1552 if (minmax[1] < ia[i]) { 1553 minmax[1] = ia[i]; 1554 } 1555 } 1556 break; 1557 case 'J': 1558 long[] l = (long[]) data; 1559 minmax[0] = minmax[1] = l[0]; 1560 1561 if (hasFillValue) fill = ((long[]) fillValue)[0]; 1562 for (int i = 0; i < n; i++) { 1563 if (hasFillValue && l[i] == fill) continue; 1564 if (minmax[0] > l[i]) { 1565 minmax[0] = l[i]; 1566 } 1567 if (minmax[1] < l[i]) { 1568 minmax[1] = l[i]; 1569 } 1570 } 1571 break; 1572 case 'F': 1573 float[] f = (float[]) data; 1574 minmax[0] = minmax[1] = f[0]; 1575 1576 if (hasFillValue) fill = ((float[]) fillValue)[0]; 1577 for (int i = 0; i < n; i++) { 1578 if ((hasFillValue && f[i] == fill) || isNaNINF(f[i])) continue; 1579 if (minmax[0] > f[i]) { 1580 minmax[0] = f[i]; 1581 } 1582 if (minmax[1] < f[i]) { 1583 minmax[1] = f[i]; 1584 } 1585 } 1586 1587 break; 1588 case 'D': 1589 double[] d = (double[]) data; 1590 minmax[0] = minmax[1] = d[0]; 1591 1592 if (hasFillValue) fill = ((double[]) fillValue)[0]; 1593 for (int i = 0; i < n; i++) { 1594 if ((hasFillValue && d[i] == fill) || isNaNINF(d[i])) continue; 1595 1596 if (minmax[0] > d[i]) { 1597 minmax[0] = d[i]; 1598 } 1599 if (minmax[1] < d[i]) { 1600 minmax[1] = d[i]; 1601 } 1602 } 1603 break; 1604 default: 1605 retval = -1; 1606 break; 1607 } // switch (dname) 1608 1609 return retval; 1610 } 1611 1612 /** 1613 * Finds the distribution of data values 1614 * 1615 * @param data 1616 * the raw data array 1617 * @param dataDist 1618 * the data distirbution. 1619 * @param minmax 1620 * the data range 1621 * 1622 * @return non-negative if successful; otherwise, returns negative 1623 */ 1624 public static int findDataDist(Object data, int[] dataDist, double[] minmax) { 1625 int retval = 0; 1626 double delt = 1; 1627 1628 if ((data == null) || (minmax == null) || dataDist == null) return -1; 1629 1630 int n = Array.getLength(data); 1631 1632 if (minmax[1] != minmax[0]) delt = (dataDist.length - 1) / (minmax[1] - minmax[0]); 1633 1634 for (int i = 0; i < dataDist.length; i++) 1635 dataDist[i] = 0; 1636 1637 int idx; 1638 double val; 1639 for (int i = 0; i < n; i++) { 1640 val = ((Number) Array.get(data, i)).doubleValue(); 1641 if (val>=minmax[0] && val <=minmax[1]) { 1642 idx = (int) ((val - minmax[0]) * delt); 1643 dataDist[idx]++; 1644 } // don't count invalid values 1645 } 1646 1647 return retval; 1648 } 1649 1650 /** 1651 * Computes mean and standard deviation of a data array 1652 * 1653 * @param data 1654 * the raw data array 1655 * @param avgstd 1656 * the statistics: avgstd[0]=mean and avgstd[1]=stdev. 1657 * @param fillValue 1658 * the missing value or fill value. Exclude this value when 1659 * compute statistics 1660 * 1661 * @return non-negative if successful; otherwise, returns negative 1662 */ 1663 public static int computeStatistics(Object data, double[] avgstd, Object fillValue) { 1664 int retval = 1, npoints = 0; 1665 double sum = 0, avg = 0.0, var = 0.0, diff = 0.0, fill = 0.0; 1666 1667 if ((data == null) || (avgstd == null) || (Array.getLength(data) <= 0) || (Array.getLength(avgstd) < 2)) { 1668 return -1; 1669 } 1670 1671 int n = Array.getLength(data); 1672 boolean hasFillValue = (fillValue != null && fillValue.getClass().isArray()); 1673 1674 String cname = data.getClass().getName(); 1675 char dname = cname.charAt(cname.lastIndexOf("[") + 1); 1676 log.trace("computeStatistics() cname={} : dname={}", cname, dname); 1677 1678 npoints = 0; 1679 switch (dname) { 1680 case 'B': 1681 byte[] b = (byte[]) data; 1682 if (hasFillValue) fill = ((byte[]) fillValue)[0]; 1683 for (int i = 0; i < n; i++) { 1684 if (hasFillValue && b[i] == fill) continue; 1685 sum += b[i]; 1686 npoints++; 1687 } 1688 avg = sum / npoints; 1689 for (int i = 0; i < n; i++) { 1690 if (hasFillValue && b[i] == fill) continue; 1691 diff = b[i] - avg; 1692 var += diff * diff; 1693 } 1694 break; 1695 case 'S': 1696 short[] s = (short[]) data; 1697 if (hasFillValue) fill = ((short[]) fillValue)[0]; 1698 for (int i = 0; i < n; i++) { 1699 if (hasFillValue && s[i] == fill) continue; 1700 sum += s[i]; 1701 npoints++; 1702 } 1703 avg = sum / npoints; 1704 for (int i = 0; i < n; i++) { 1705 if (hasFillValue && s[i] == fill) continue; 1706 diff = s[i] - avg; 1707 var += diff * diff; 1708 } 1709 break; 1710 case 'I': 1711 int[] ia = (int[]) data; 1712 if (hasFillValue) fill = ((int[]) fillValue)[0]; 1713 for (int i = 0; i < n; i++) { 1714 if (hasFillValue && ia[i] == fill) continue; 1715 sum += ia[i]; 1716 npoints++; 1717 } 1718 avg = sum / npoints; 1719 for (int i = 0; i < n; i++) { 1720 if (hasFillValue && ia[i] == fill) continue; 1721 diff = ia[i] - avg; 1722 var += diff * diff; 1723 } 1724 break; 1725 case 'J': 1726 long[] l = (long[]) data; 1727 if (hasFillValue) fill = ((long[]) fillValue)[0]; 1728 for (int i = 0; i < n; i++) { 1729 if (hasFillValue && l[i] == fill) continue; 1730 sum += l[i]; 1731 npoints++; 1732 } 1733 1734 avg = sum / npoints; 1735 for (int i = 0; i < n; i++) { 1736 if (hasFillValue && l[i] == fill) continue; 1737 diff = l[i] - avg; 1738 var += diff * diff; 1739 } 1740 break; 1741 case 'F': 1742 float[] f = (float[]) data; 1743 if (hasFillValue) fill = ((float[]) fillValue)[0]; 1744 for (int i = 0; i < n; i++) { 1745 if (hasFillValue && f[i] == fill) continue; 1746 sum += f[i]; 1747 npoints++; 1748 } 1749 1750 avg = sum / npoints; 1751 for (int i = 0; i < n; i++) { 1752 if (hasFillValue && f[i] == fill) continue; 1753 diff = f[i] - avg; 1754 var += diff * diff; 1755 } 1756 break; 1757 case 'D': 1758 double[] d = (double[]) data; 1759 if (hasFillValue) fill = ((double[]) fillValue)[0]; 1760 for (int i = 0; i < n; i++) { 1761 if (hasFillValue && d[i] == fill) continue; 1762 sum += d[i]; 1763 npoints++; 1764 } 1765 avg = sum / npoints; 1766 for (int i = 0; i < n; i++) { 1767 if (hasFillValue && d[i] == fill) continue; 1768 diff = d[i] - avg; 1769 var += diff * diff; 1770 } 1771 break; 1772 default: 1773 retval = -1; 1774 break; 1775 } // switch (dname) 1776 1777 if (npoints <= 1) { 1778 if (npoints < 1) avgstd[0] = fill; 1779 avgstd[1] = 0; 1780 } 1781 else { 1782 avgstd[0] = avg; 1783 avgstd[1] = Math.sqrt(var / (npoints - 1)); 1784 } 1785 1786 return retval; 1787 } 1788 1789 public static void saveAsBinary(DataOutputStream out, Object data, ByteOrder order) throws Exception { 1790 String cname = data.getClass().getName(); 1791 char dname = cname.charAt(cname.lastIndexOf("[") + 1); 1792 ByteBuffer bb = null; 1793 1794 int size = Array.getLength(data); 1795 1796 if (dname == 'B') { 1797 byte[] bdata = new byte[size]; 1798 bdata = (byte[]) data; 1799 1800 bb = ByteBuffer.allocate(BYTE_BUFFER_SIZE); 1801 bb.order(order); 1802 1803 int remainingSize = size - BYTE_BUFFER_SIZE; 1804 int allocValue = 0; 1805 int iterationNumber = 0; 1806 do { 1807 if (remainingSize <= 0) { 1808 allocValue = remainingSize + BYTE_BUFFER_SIZE; 1809 } 1810 else { 1811 allocValue = BYTE_BUFFER_SIZE; 1812 } 1813 bb.clear(); 1814 bb.put(bdata, (iterationNumber * BYTE_BUFFER_SIZE), allocValue); 1815 out.write(bb.array(), 0, allocValue); 1816 remainingSize = remainingSize - BYTE_BUFFER_SIZE; 1817 iterationNumber++; 1818 } while (remainingSize > -BYTE_BUFFER_SIZE); 1819 1820 out.flush(); 1821 out.close(); 1822 } 1823 else if (dname == 'S') { 1824 short[] sdata = new short[size]; 1825 sdata = (short[]) data; 1826 bb = ByteBuffer.allocate(SHORT_BUFFER_SIZE * 2); 1827 bb.order(order); 1828 1829 ShortBuffer sb = bb.asShortBuffer(); 1830 int remainingSize = size - SHORT_BUFFER_SIZE; 1831 int allocValue = 0; 1832 int iterationNumber = 0; 1833 do { 1834 if (remainingSize <= 0) { 1835 allocValue = remainingSize + SHORT_BUFFER_SIZE; 1836 } 1837 else { 1838 allocValue = SHORT_BUFFER_SIZE; 1839 } 1840 bb.clear(); 1841 sb.clear(); 1842 sb.put(sdata, (iterationNumber * SHORT_BUFFER_SIZE), allocValue); 1843 out.write(bb.array(), 0, allocValue * 2); 1844 remainingSize = remainingSize - SHORT_BUFFER_SIZE; 1845 iterationNumber++; 1846 } while (remainingSize > -SHORT_BUFFER_SIZE); 1847 1848 out.flush(); 1849 out.close(); 1850 } 1851 else if (dname == 'I') { 1852 int[] idata = new int[size]; 1853 idata = (int[]) data; 1854 bb = ByteBuffer.allocate(INT_BUFFER_SIZE * 4); 1855 bb.order(order); 1856 1857 IntBuffer ib = bb.asIntBuffer(); 1858 int remainingSize = size - INT_BUFFER_SIZE; 1859 int allocValue = 0; 1860 int iterationNumber = 0; 1861 do { 1862 if (remainingSize <= 0) { 1863 allocValue = remainingSize + INT_BUFFER_SIZE; 1864 } 1865 else { 1866 allocValue = INT_BUFFER_SIZE; 1867 } 1868 bb.clear(); 1869 ib.clear(); 1870 ib.put(idata, (iterationNumber * INT_BUFFER_SIZE), allocValue); 1871 out.write(bb.array(), 0, allocValue * 4); 1872 remainingSize = remainingSize - INT_BUFFER_SIZE; 1873 iterationNumber++; 1874 } while (remainingSize > -INT_BUFFER_SIZE); 1875 1876 out.flush(); 1877 out.close(); 1878 } 1879 else if (dname == 'J') { 1880 long[] ldata = new long[size]; 1881 ldata = (long[]) data; 1882 1883 bb = ByteBuffer.allocate(LONG_BUFFER_SIZE * 8); 1884 bb.order(order); 1885 1886 LongBuffer lb = bb.asLongBuffer(); 1887 int remainingSize = size - LONG_BUFFER_SIZE; 1888 int allocValue = 0; 1889 int iterationNumber = 0; 1890 do { 1891 if (remainingSize <= 0) { 1892 allocValue = remainingSize + LONG_BUFFER_SIZE; 1893 } 1894 else { 1895 allocValue = LONG_BUFFER_SIZE; 1896 } 1897 bb.clear(); 1898 lb.clear(); 1899 lb.put(ldata, (iterationNumber * LONG_BUFFER_SIZE), allocValue); 1900 out.write(bb.array(), 0, allocValue * 8); 1901 remainingSize = remainingSize - LONG_BUFFER_SIZE; 1902 iterationNumber++; 1903 } while (remainingSize > -LONG_BUFFER_SIZE); 1904 1905 out.flush(); 1906 out.close(); 1907 } 1908 else if (dname == 'F') { 1909 float[] fdata = new float[size]; 1910 fdata = (float[]) data; 1911 1912 bb = ByteBuffer.allocate(FLOAT_BUFFER_SIZE * 4); 1913 bb.order(order); 1914 1915 FloatBuffer fb = bb.asFloatBuffer(); 1916 int remainingSize = size - FLOAT_BUFFER_SIZE; 1917 int allocValue = 0; 1918 int iterationNumber = 0; 1919 do { 1920 if (remainingSize <= 0) { 1921 allocValue = remainingSize + FLOAT_BUFFER_SIZE; 1922 } 1923 else { 1924 allocValue = FLOAT_BUFFER_SIZE; 1925 } 1926 bb.clear(); 1927 fb.clear(); 1928 fb.put(fdata, (iterationNumber * FLOAT_BUFFER_SIZE), allocValue); 1929 out.write(bb.array(), 0, allocValue * 4); 1930 remainingSize = remainingSize - FLOAT_BUFFER_SIZE; 1931 iterationNumber++; 1932 } while (remainingSize > -FLOAT_BUFFER_SIZE); 1933 1934 out.flush(); 1935 out.close(); 1936 } 1937 else if (dname == 'D') { 1938 double[] ddata = new double[size]; 1939 ddata = (double[]) data; 1940 1941 bb = ByteBuffer.allocate(DOUBLE_BUFFER_SIZE * 8); 1942 bb.order(order); 1943 1944 DoubleBuffer db = bb.asDoubleBuffer(); 1945 int remainingSize = size - DOUBLE_BUFFER_SIZE; 1946 int allocValue = 0; 1947 int iterationNumber = 0; 1948 do { 1949 if (remainingSize <= 0) { 1950 allocValue = remainingSize + DOUBLE_BUFFER_SIZE; 1951 } 1952 else { 1953 allocValue = DOUBLE_BUFFER_SIZE; 1954 } 1955 bb.clear(); 1956 db.clear(); 1957 db.put(ddata, (iterationNumber * DOUBLE_BUFFER_SIZE), allocValue); 1958 out.write(bb.array(), 0, allocValue * 8); 1959 remainingSize = remainingSize - DOUBLE_BUFFER_SIZE; 1960 iterationNumber++; 1961 } while (remainingSize > -DOUBLE_BUFFER_SIZE); 1962 1963 out.flush(); 1964 out.close(); 1965 } 1966 } 1967 1968 /** 1969 * Reads data from a binary file into a buffer. 1970 * 1971 * @param dataOut 1972 * the output stream 1973 * @param fileName 1974 * the file to read binary data from 1975 * @param order 1976 * the new byte order, either BIG_ENDIAN or LITTLE_ENDIAN 1977 * 1978 * @return true if successful; otherwise, false. 1979 */ 1980 public static boolean getBinaryDataFromFile(Object dataOut, String fileName, ByteOrder order) { 1981 if (dataOut == null) return false; 1982 1983 String fname = fileName; 1984 FileInputStream inputFile = null; 1985 BufferedInputStream in = null; 1986 ByteBuffer byteBuffer = null; 1987 boolean valChanged = false; 1988 1989 try { 1990 inputFile = new FileInputStream(fname); 1991 long fileSize = inputFile.getChannel().size(); 1992 in = new BufferedInputStream(inputFile); 1993 1994 int datasetSize = Array.getLength(dataOut); 1995 String cname = dataOut.getClass().getName(); 1996 char dname = cname.charAt(cname.lastIndexOf("[") + 1); 1997 1998 if (dname == 'B') { 1999 long datasetByteSize = datasetSize; 2000 byteBuffer = ByteBuffer.allocate(BYTE_BUFFER_SIZE); 2001 byteBuffer.order(order); 2002 2003 int bufferSize = (int) Math.min(fileSize, datasetByteSize); 2004 2005 int remainingSize = bufferSize - (BYTE_BUFFER_SIZE); 2006 int allocValue = 0; 2007 int iterationNumber = 0; 2008 byte[] byteArray = new byte[BYTE_BUFFER_SIZE]; 2009 do { 2010 if (remainingSize <= 0) { 2011 allocValue = remainingSize + (BYTE_BUFFER_SIZE); 2012 } 2013 else { 2014 allocValue = (BYTE_BUFFER_SIZE); 2015 } 2016 2017 in.read(byteBuffer.array(), 0, allocValue); 2018 2019 byteBuffer.get(byteArray, 0, allocValue); 2020 System.arraycopy(byteArray, 0, dataOut, (iterationNumber * BYTE_BUFFER_SIZE), allocValue); 2021 byteBuffer.clear(); 2022 remainingSize = remainingSize - (BYTE_BUFFER_SIZE); 2023 iterationNumber++; 2024 } while (remainingSize > -(BYTE_BUFFER_SIZE)); 2025 2026 valChanged = true; 2027 } 2028 else if (dname == 'S') { 2029 long datasetShortSize = datasetSize * 2; 2030 byteBuffer = ByteBuffer.allocate(SHORT_BUFFER_SIZE * 2); 2031 byteBuffer.order(order); 2032 2033 int bufferSize = (int) Math.min(fileSize, datasetShortSize); 2034 int remainingSize = bufferSize - (SHORT_BUFFER_SIZE * 2); 2035 int allocValue = 0; 2036 int iterationNumber = 0; 2037 ShortBuffer sb = byteBuffer.asShortBuffer(); 2038 short[] shortArray = new short[SHORT_BUFFER_SIZE]; 2039 2040 do { 2041 if (remainingSize <= 0) { 2042 allocValue = remainingSize + (SHORT_BUFFER_SIZE * 2); 2043 } 2044 else { 2045 allocValue = (SHORT_BUFFER_SIZE * 2); 2046 } 2047 in.read(byteBuffer.array(), 0, allocValue); 2048 sb.get(shortArray, 0, allocValue / 2); 2049 System.arraycopy(shortArray, 0, dataOut, (iterationNumber * SHORT_BUFFER_SIZE), allocValue / 2); 2050 byteBuffer.clear(); 2051 sb.clear(); 2052 remainingSize = remainingSize - (SHORT_BUFFER_SIZE * 2); 2053 iterationNumber++; 2054 } while (remainingSize > -(SHORT_BUFFER_SIZE * 2)); 2055 2056 valChanged = true; 2057 } 2058 else if (dname == 'I') { 2059 long datasetIntSize = datasetSize * 4; 2060 byteBuffer = ByteBuffer.allocate(INT_BUFFER_SIZE * 4); 2061 byteBuffer.order(order); 2062 2063 int bufferSize = (int) Math.min(fileSize, datasetIntSize); 2064 int remainingSize = bufferSize - (INT_BUFFER_SIZE * 4); 2065 int allocValue = 0; 2066 int iterationNumber = 0; 2067 int[] intArray = new int[INT_BUFFER_SIZE]; 2068 byte[] tmpBuf = byteBuffer.array(); 2069 IntBuffer ib = byteBuffer.asIntBuffer(); 2070 2071 do { 2072 if (remainingSize <= 0) { 2073 allocValue = remainingSize + (INT_BUFFER_SIZE * 4); 2074 } 2075 else { 2076 allocValue = (INT_BUFFER_SIZE * 4); 2077 } 2078 in.read(tmpBuf, 0, allocValue); 2079 ib.get(intArray, 0, allocValue / 4); 2080 System.arraycopy(intArray, 0, dataOut, (iterationNumber * INT_BUFFER_SIZE), allocValue / 4); 2081 byteBuffer.clear(); 2082 ib.clear(); 2083 remainingSize = remainingSize - (INT_BUFFER_SIZE * 4); 2084 iterationNumber++; 2085 } while (remainingSize > -(INT_BUFFER_SIZE * 4)); 2086 2087 valChanged = true; 2088 } 2089 else if (dname == 'J') { 2090 long datasetLongSize = datasetSize * 8; 2091 byteBuffer = ByteBuffer.allocate(LONG_BUFFER_SIZE * 8); 2092 byteBuffer.order(order); 2093 2094 int bufferSize = (int) Math.min(fileSize, datasetLongSize); 2095 int remainingSize = bufferSize - (LONG_BUFFER_SIZE * 8); 2096 int allocValue = 0; 2097 int iterationNumber = 0; 2098 long[] longArray = new long[LONG_BUFFER_SIZE]; 2099 LongBuffer lb = byteBuffer.asLongBuffer(); 2100 2101 do { 2102 if (remainingSize <= 0) { 2103 allocValue = remainingSize + (LONG_BUFFER_SIZE * 8); 2104 } 2105 else { 2106 allocValue = (LONG_BUFFER_SIZE * 8); 2107 } 2108 2109 in.read(byteBuffer.array(), 0, allocValue); 2110 lb.get(longArray, 0, allocValue / 8); 2111 System.arraycopy(longArray, 0, dataOut, (iterationNumber * LONG_BUFFER_SIZE), allocValue / 8); 2112 byteBuffer.clear(); 2113 lb.clear(); 2114 remainingSize = remainingSize - (LONG_BUFFER_SIZE * 8); 2115 iterationNumber++; 2116 } while (remainingSize > -(LONG_BUFFER_SIZE * 8)); 2117 2118 valChanged = true; 2119 } 2120 else if (dname == 'F') { 2121 long datasetFloatSize = datasetSize * 4; 2122 byteBuffer = ByteBuffer.allocate(FLOAT_BUFFER_SIZE * 4); 2123 byteBuffer.order(order); 2124 2125 int bufferSize = (int) Math.min(fileSize, datasetFloatSize); 2126 int remainingSize = bufferSize - (FLOAT_BUFFER_SIZE * 4); 2127 int allocValue = 0; 2128 int iterationNumber = 0; 2129 FloatBuffer fb = byteBuffer.asFloatBuffer(); 2130 float[] floatArray = new float[FLOAT_BUFFER_SIZE]; 2131 do { 2132 if (remainingSize <= 0) { 2133 allocValue = remainingSize + (FLOAT_BUFFER_SIZE * 4); 2134 } 2135 else { 2136 allocValue = (FLOAT_BUFFER_SIZE * 4); 2137 } 2138 2139 in.read(byteBuffer.array(), 0, allocValue); 2140 fb.get(floatArray, 0, allocValue / 4); 2141 System.arraycopy(floatArray, 0, dataOut, (iterationNumber * FLOAT_BUFFER_SIZE), allocValue / 4); 2142 byteBuffer.clear(); 2143 fb.clear(); 2144 remainingSize = remainingSize - (FLOAT_BUFFER_SIZE * 4); 2145 iterationNumber++; 2146 } while (remainingSize > -(FLOAT_BUFFER_SIZE * 4)); 2147 2148 valChanged = true; 2149 } 2150 else if (dname == 'D') { 2151 long datasetDoubleSize = datasetSize * 8; 2152 byteBuffer = ByteBuffer.allocate(DOUBLE_BUFFER_SIZE * 8); 2153 byteBuffer.order(order); 2154 2155 int bufferSize = (int) Math.min(fileSize, datasetDoubleSize); 2156 int remainingSize = bufferSize - (DOUBLE_BUFFER_SIZE * 8); 2157 int allocValue = 0; 2158 int iterationNumber = 0; 2159 DoubleBuffer db = byteBuffer.asDoubleBuffer(); 2160 double[] doubleArray = new double[DOUBLE_BUFFER_SIZE]; 2161 2162 do { 2163 if (remainingSize <= 0) { 2164 allocValue = remainingSize + (DOUBLE_BUFFER_SIZE * 8); 2165 } 2166 else { 2167 allocValue = (DOUBLE_BUFFER_SIZE * 8); 2168 } 2169 2170 in.read(byteBuffer.array(), 0, allocValue); 2171 db.get(doubleArray, 0, allocValue / 8); 2172 System.arraycopy(doubleArray, 0, dataOut, (iterationNumber * DOUBLE_BUFFER_SIZE), allocValue / 8); 2173 byteBuffer.clear(); 2174 db.clear(); 2175 remainingSize = remainingSize - (DOUBLE_BUFFER_SIZE * 8); 2176 iterationNumber++; 2177 } while (remainingSize > -(DOUBLE_BUFFER_SIZE * 8)); 2178 2179 valChanged = true; 2180 } 2181 } 2182 catch (Exception es) { 2183 es.printStackTrace(); 2184 } 2185 finally { 2186 try { 2187 in.close(); 2188 inputFile.close(); 2189 } 2190 catch (IOException ex) { 2191 log.debug("close binary file {}:", fname, ex); 2192 } 2193 } 2194 2195 return valChanged; 2196 } 2197 2198 /** 2199 * Returns a string representation of the long argument as an unsigned 2200 * integer in base 2. This is different from Long.toBinaryString(long i). 2201 * This function add padding (0's) to the string based on the nbytes. For 2202 * example, if v=15, nbytes=1, the string will be "00001111". 2203 * 2204 * @param v 2205 * the long value 2206 * @param nbytes 2207 * number of bytes in the integer 2208 * 2209 * @return the string representation of the unsigned long value represented 2210 * by the argument in binary (base 2). 2211 */ 2212 public static final String toBinaryString(long v, int nbytes) { 2213 if (nbytes <= 0) return null; 2214 2215 int nhex = nbytes * 2; 2216 short[] hex = new short[nhex]; 2217 2218 for (int i = 0; i < nhex; i++) 2219 hex[i] = (short) (0x0F & (v >> (i * 4))); 2220 2221 StringBuffer sb = new StringBuffer(); 2222 boolean isEven = true; 2223 for (int i = nhex - 1; i >= 0; i--) { 2224 if (isEven && i < nhex - 1) sb.append(" "); 2225 isEven = !isEven; // toggle 2226 2227 switch (hex[i]) { 2228 case 0: 2229 sb.append("0000"); 2230 break; 2231 case 1: 2232 sb.append("0001"); 2233 break; 2234 case 2: 2235 sb.append("0010"); 2236 break; 2237 case 3: 2238 sb.append("0011"); 2239 break; 2240 case 4: 2241 sb.append("0100"); 2242 break; 2243 case 5: 2244 sb.append("0101"); 2245 break; 2246 case 6: 2247 sb.append("0110"); 2248 break; 2249 case 7: 2250 sb.append("0111"); 2251 break; 2252 case 8: 2253 sb.append("1000"); 2254 break; 2255 case 9: 2256 sb.append("1001"); 2257 break; 2258 case 10: 2259 sb.append("1010"); 2260 break; 2261 case 11: 2262 sb.append("1011"); 2263 break; 2264 case 12: 2265 sb.append("1100"); 2266 break; 2267 case 13: 2268 sb.append("1101"); 2269 break; 2270 case 14: 2271 sb.append("1110"); 2272 break; 2273 case 15: 2274 sb.append("1111"); 2275 break; 2276 } 2277 } 2278 2279 return sb.toString(); 2280 } 2281 2282 public static final String toBinaryString(BigInteger v, int nbytes) { 2283 StringBuffer sb = new StringBuffer(); 2284 String val = String.format("%" + (8 * nbytes) + "s", v.toString(2)).replace(" ", "0").toUpperCase(); 2285 2286 // Insert spacing 2287 for (int i = 0; i < nbytes; i++) { 2288 sb.append(val.substring(i * nbytes, nbytes * (i + 1))); 2289 if (i < nbytes - 1) sb.append(" "); 2290 } 2291 2292 return sb.toString(); 2293 } 2294 2295 final static char[] HEXCHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 2296 2297 /** 2298 * Returns a string representation of the long argument as an unsigned integer in base 16. This 2299 * is different from Long.toHexString(long i). This function add padding (0's) to the string 2300 * based on the nbytes. For example, if v=42543, nbytes=4, the string will be "0000A62F". 2301 * 2302 * @param v 2303 * the long value 2304 * @param nbytes 2305 * number of bytes in the integer 2306 * @return the string representation of the unsigned long value represented by the argument in 2307 * hexadecimal (base 16). 2308 */ 2309 public static final String toHexString (long v, int nbytes) { 2310 if (nbytes <= 0) return null; 2311 2312 int nhex = nbytes * 2; 2313 short[] hex = new short[nhex]; 2314 2315 for (int i = 0; i < nhex; i++) { 2316 hex[i] = (short) (0x0F & (v >> (i * 4))); 2317 } 2318 2319 StringBuffer sb = new StringBuffer(); 2320 for (int i = nhex - 1; i >= 0; i--) { 2321 sb.append(HEXCHARS[hex[i]]); 2322 } 2323 2324 return sb.toString(); 2325 } 2326 2327 /** 2328 * Returns a string representation of the BigInteger argument as an unsigned integer in base 16. 2329 * This is different from BigInteger.toString(16). This function adds padding (0's) to the string 2330 * based on the nbytes. For example, if v=42543, nbytes=4, the string will be "0000A62F". 2331 * 2332 * @param v 2333 * the BigInteger value 2334 * @param nbytes 2335 * number of bytes in the integer 2336 * @return the string representation of the unsigned long value represented by the argument in 2337 * hexadecimal (base 16). 2338 */ 2339 public static final String toHexString (BigInteger v, int nbytes) { 2340 return String.format("%" + nbytes + "s", v.toString(16)).replace(" ", "0").toUpperCase(); 2341 } 2342 2343 /** 2344 * Apply bitmask to a data array. 2345 * 2346 * @param theData 2347 * the data array which the bitmask is applied to. 2348 * @param theMask 2349 * the bitmask to be applied to the data array. 2350 * @param op 2351 * the bitmask op to be applied 2352 * 2353 * @return true if bitmask is applied successfuly; otherwise, false. 2354 */ 2355 public static final boolean applyBitmask(Object theData, BitSet theMask, ViewProperties.BITMASK_OP op) { 2356 if ( theData == null 2357 || !(theData instanceof Array) 2358 || ((theData instanceof Array) && (Array.getLength(theData) <= 0)) 2359 || theMask == null) return false; 2360 2361 char nt = '0'; 2362 String cName = theData.getClass().getName(); 2363 int cIndex = cName.lastIndexOf("["); 2364 if (cIndex >= 0) { 2365 nt = cName.charAt(cIndex + 1); 2366 } 2367 2368 // only deal with 8/16/32/64 bit datasets 2369 if (!(nt == 'B' || nt == 'S' || nt == 'I' || nt == 'J')) return false; 2370 2371 long bmask = 0, theValue = 0, packedValue = 0, bitValue = 0; 2372 2373 int nbits = theMask.length(); 2374 int len = Array.getLength(theData); 2375 2376 for (int i = 0; i < nbits; i++) { 2377 if (theMask.get(i)) bmask += 1 << i; 2378 } 2379 2380 for (int i = 0; i < len; i++) { 2381 if (nt == 'B') 2382 theValue = ((byte[]) theData)[i] & bmask; 2383 else if (nt == 'S') 2384 theValue = ((short[]) theData)[i] & bmask; 2385 else if (nt == 'I') 2386 theValue = ((int[]) theData)[i] & bmask; 2387 else if (nt == 'J') 2388 theValue = ((long[]) theData)[i] & bmask; 2389 2390 // apply bitmask only 2391 if (op == BITMASK_OP.AND) 2392 packedValue = theValue; 2393 else { 2394 // extract bits 2395 packedValue = 0; 2396 int bitPosition = 0; 2397 bitValue = 0; 2398 2399 for (int j = 0; j < nbits; j++) { 2400 if (theMask.get(j)) { 2401 bitValue = (theValue & 1); 2402 packedValue += (bitValue << bitPosition); 2403 bitPosition++; 2404 } 2405 // move to the next bit 2406 theValue = theValue >> 1; 2407 } 2408 } 2409 2410 if (nt == 'B') 2411 ((byte[]) theData)[i] = (byte) packedValue; 2412 else if (nt == 'S') 2413 ((short[]) theData)[i] = (short) packedValue; 2414 else if (nt == 'I') 2415 ((int[]) theData)[i] = (int) packedValue; 2416 else if (nt == 'J') 2417 ((long[]) theData)[i] = packedValue; 2418 } /* for (int i = 0; i < len; i++) */ 2419 2420 return true; 2421 } /* public static final boolean applyBitmask() */ 2422 2423 /** 2424 * Read HDF5 user block data into byte array. 2425 * 2426 * @param filename the HDF5 file from which to get the user block 2427 * 2428 * @return a byte array of user block, or null if there is user data. 2429 */ 2430 public static byte[] getHDF5UserBlock(String filename) { 2431 byte[] userBlock = null; 2432 RandomAccessFile raf = null; 2433 2434 try { 2435 raf = new RandomAccessFile(filename, "r"); 2436 } 2437 catch (Exception ex) { 2438 try { 2439 raf.close(); 2440 } 2441 catch (Throwable err) { 2442 ; 2443 } 2444 raf = null; 2445 } 2446 2447 if (raf == null) { 2448 return null; 2449 } 2450 2451 byte[] header = new byte[8]; 2452 long fileSize = 0; 2453 try { 2454 fileSize = raf.length(); 2455 } 2456 catch (Exception ex) { 2457 fileSize = 0; 2458 } 2459 if (fileSize <= 0) { 2460 try { 2461 raf.close(); 2462 } 2463 catch (Throwable err) { 2464 ; 2465 } 2466 return null; 2467 } 2468 2469 // The super block is located by searching for the HDF5 file signature 2470 // at byte offset 0, byte offset 512 and at successive locations in the 2471 // file, each a multiple of two of the previous location, i.e. 0, 512, 2472 // 1024, 2048, etc 2473 long offset = 0; 2474 boolean ish5 = false; 2475 while (offset < fileSize) { 2476 try { 2477 raf.seek(offset); 2478 raf.read(header); 2479 } 2480 catch (Exception ex) { 2481 header = null; 2482 } 2483 2484 if ((header[0] == -119) && (header[1] == 72) && (header[2] == 68) 2485 && (header[3] == 70) && (header[4] == 13) 2486 && (header[5] == 10) && (header[6] == 26) 2487 && (header[7] == 10)) { 2488 ish5 = true; 2489 break; // find the end of user block 2490 } 2491 else { 2492 ish5 = false; 2493 if (offset == 0) { 2494 offset = 512; 2495 } 2496 else { 2497 offset *= 2; 2498 } 2499 } 2500 } 2501 2502 if (!ish5 || (offset == 0)) { 2503 try { 2504 raf.close(); 2505 } 2506 catch (Throwable err) { 2507 ; 2508 } 2509 return null; 2510 } 2511 2512 int blockSize = (int) offset; 2513 userBlock = new byte[blockSize]; 2514 try { 2515 raf.seek(0); 2516 raf.read(userBlock, 0, blockSize); 2517 } 2518 catch (Exception ex) { 2519 userBlock = null; 2520 } 2521 2522 try { 2523 raf.close(); 2524 } 2525 catch (Exception ex) { 2526 } 2527 2528 return userBlock; 2529 } 2530 2531 /** 2532 * Write HDF5 user block data into byte array. 2533 * 2534 * @param fin the input filename 2535 * @param fout the output filename 2536 * @param buf the data to write into the user block 2537 * 2538 * @return a byte array of user block, or null if there is user data. 2539 */ 2540 public static boolean setHDF5UserBlock(String fin, String fout, byte[] buf) { 2541 boolean ish5 = false; 2542 2543 if ((buf == null) || (buf.length <= 0)) { 2544 return false; 2545 } 2546 2547 File tmpFile = new File(fin); 2548 if (!tmpFile.exists()) { 2549 return false; 2550 } 2551 2552 // find the end of user block for the input file; 2553 RandomAccessFile raf = null; 2554 try { 2555 raf = new RandomAccessFile(fin, "r"); 2556 } 2557 catch (Exception ex) { 2558 raf = null; 2559 } 2560 2561 if (raf == null) { 2562 return false; 2563 } 2564 2565 byte[] header = new byte[8]; 2566 long fileSize = 0; 2567 try { 2568 fileSize = raf.length(); 2569 } 2570 catch (Exception ex) { 2571 fileSize = 0; 2572 } 2573 try { 2574 fileSize = raf.length(); 2575 } 2576 catch (Exception ex) { 2577 fileSize = 0; 2578 } 2579 if (fileSize <= 0) { 2580 try { 2581 raf.close(); 2582 } 2583 catch (Throwable err) { 2584 ; 2585 } 2586 return false; 2587 } 2588 2589 // The super block is located by searching for the HDF5 file signature 2590 // at byte offset 0, byte offset 512 and at successive locations in the 2591 // file, each a multiple of two of the previous location, i.e. 0, 512, 2592 // 1024, 2048, etc 2593 long offset = 0; 2594 while (offset < fileSize) { 2595 try { 2596 raf.seek(offset); 2597 raf.read(header); 2598 } 2599 catch (Exception ex) { 2600 header = null; 2601 } 2602 2603 if ((header[0] == -119) && (header[1] == 72) && (header[2] == 68) 2604 && (header[3] == 70) && (header[4] == 13) 2605 && (header[5] == 10) && (header[6] == 26) 2606 && (header[7] == 10)) { 2607 ish5 = true; 2608 break; 2609 } 2610 else { 2611 ish5 = false; 2612 if (offset == 0) { 2613 offset = 512; 2614 } 2615 else { 2616 offset *= 2; 2617 } 2618 } 2619 } 2620 try { 2621 raf.close(); 2622 } 2623 catch (Throwable err) { 2624 ; 2625 } 2626 2627 if (!ish5) { 2628 return false; 2629 } 2630 2631 int length = 0; 2632 int bsize = 1024; 2633 byte[] buffer; 2634 BufferedInputStream bi = null; 2635 BufferedOutputStream bo = null; 2636 2637 try { 2638 bi = new BufferedInputStream(new FileInputStream(fin)); 2639 } 2640 catch (Exception ex) { 2641 try { 2642 bi.close(); 2643 } 2644 catch (Exception ex2) { 2645 } 2646 return false; 2647 } 2648 2649 try { 2650 bo = new BufferedOutputStream(new FileOutputStream(fout)); 2651 } 2652 catch (Exception ex) { 2653 try { 2654 bo.close(); 2655 } 2656 catch (Exception ex2) { 2657 } 2658 try { 2659 bi.close(); 2660 } 2661 catch (Exception ex2) { 2662 } 2663 return false; 2664 } 2665 2666 // skip the header of original file 2667 try { 2668 bi.skip(offset); 2669 } 2670 catch (Exception ex) { 2671 } 2672 2673 // write the header into the new file 2674 try { 2675 bo.write(buf, 0, buf.length); 2676 } 2677 catch (Exception ex) { 2678 } 2679 2680 // The super block space is allocated by offset 0, 512, 1024, 2048, etc 2681 offset = 512; 2682 while (offset < buf.length) { 2683 offset *= 2; 2684 } 2685 int padSize = (int) (offset - buf.length); 2686 if (padSize > 0) { 2687 byte[] padBuf = new byte[padSize]; 2688 try { 2689 bo.write(padBuf, 0, padSize); 2690 } 2691 catch (Exception ex) { 2692 } 2693 } 2694 2695 // copy the hdf5 file content from input file to the output file 2696 buffer = new byte[bsize]; 2697 try { 2698 length = bi.read(buffer, 0, bsize); 2699 } 2700 catch (Exception ex) { 2701 length = 0; 2702 } 2703 while (length > 0) { 2704 try { 2705 bo.write(buffer, 0, length); 2706 length = bi.read(buffer, 0, bsize); 2707 } 2708 catch (Exception ex) { 2709 length = 0; 2710 } 2711 } 2712 2713 try { 2714 bo.flush(); 2715 } 2716 catch (Exception ex) { 2717 } 2718 try { 2719 bi.close(); 2720 } 2721 catch (Exception ex) { 2722 } 2723 try { 2724 bo.close(); 2725 } 2726 catch (Exception ex) { 2727 } 2728 return true; 2729 } 2730 2731 /** 2732 * look at the first 4 bytes of the file to see if it is an HDF4 file. 2733 * byte[0]=14, byte[1]=3, byte[2]=19, byte[3]=1 or if it is a netCDF file 2734 * byte[0]=67, byte[1]=68, byte[2]=70, byte[3]=1 2735 * 2736 * @param filename the file to test if HDF4 2737 * 2738 * @return true if the file is of type HDF4 2739 */ 2740 public static boolean isHDF4(String filename) { 2741 boolean ish4 = false; 2742 RandomAccessFile raf = null; 2743 2744 try { 2745 raf = new RandomAccessFile(filename, "r"); 2746 } 2747 catch (Exception ex) { 2748 raf = null; 2749 } 2750 2751 if (raf == null) { 2752 return false; 2753 } 2754 2755 byte[] header = new byte[4]; 2756 try { 2757 raf.read(header); 2758 } 2759 catch (Exception ex) { 2760 header = null; 2761 } 2762 2763 if (header != null) { 2764 if ( 2765 // HDF4 2766 ((header[0] == 14) && (header[1] == 3) && (header[2] == 19) && (header[3] == 1)) 2767 /* 2768 * // netCDF || (header[0]==67 && header[1]==68 && header[2]==70 && 2769 * header[3]==1) 2770 */ 2771 ) { 2772 ish4 = true; 2773 } 2774 else { 2775 ish4 = false; 2776 } 2777 } 2778 2779 try { 2780 raf.close(); 2781 } 2782 catch (Exception ex) { 2783 } 2784 2785 return ish4; 2786 } 2787 2788 /** 2789 * look at the first 8 bytes of the file to see if it is an HDF5 file. 2790 * byte[0]=-199 which is 137 in unsigned byte, byte[1]=72, byte[2]=68, 2791 * byte[3]=70, byte[4]=13, byte[5]=10, byte[6]=26, byte[7]=10 2792 * 2793 * @param filename the file to test if HDF5 2794 * 2795 * @return true if the file is of type HDF5 2796 */ 2797 public static boolean isHDF5(String filename) { 2798 boolean ish5 = false; 2799 RandomAccessFile raf = null; 2800 2801 try { 2802 raf = new RandomAccessFile(filename, "r"); 2803 } 2804 catch (Exception ex) { 2805 raf = null; 2806 } 2807 2808 if (raf == null) { 2809 return false; 2810 } 2811 2812 byte[] header = new byte[8]; 2813 long fileSize = 0; 2814 try { 2815 fileSize = raf.length(); 2816 } 2817 catch (Exception ex) { 2818 } 2819 2820 // The super block is located by searching for the HDF5 file signature 2821 // at byte offset 0, byte offset 512 and at successive locations in the 2822 // file, each a multiple of two of the previous location, i.e. 0, 512, 2823 // 1024, 2048, etc 2824 long offset = 0; 2825 while (!ish5 && (offset < fileSize)) { 2826 try { 2827 raf.seek(offset); 2828 raf.read(header); 2829 } 2830 catch (Exception ex) { 2831 header = null; 2832 } 2833 2834 if ((header[0] == -119) && (header[1] == 72) && (header[2] == 68) 2835 && (header[3] == 70) && (header[4] == 13) 2836 && (header[5] == 10) && (header[6] == 26) 2837 && (header[7] == 10)) { 2838 ish5 = true; 2839 } 2840 else { 2841 ish5 = false; 2842 if (offset == 0) { 2843 offset = 512; 2844 } 2845 else { 2846 offset *= 2; 2847 } 2848 } 2849 } 2850 2851 try { 2852 raf.close(); 2853 } 2854 catch (Exception ex) { 2855 } 2856 2857 return ish5; 2858 } 2859 2860 /** 2861 * look at the first 4 bytes of the file to see if it is a netCDF file 2862 * byte[0]=67, byte[1]=68, byte[2]=70, byte[3]=1 or 2863 * 2864 * @param filename the file to test if netcdf 2865 * 2866 * @return true if the file is of type netcdf 2867 */ 2868 public static boolean isNetcdf(String filename) { 2869 boolean isnc = false; 2870 RandomAccessFile raf = null; 2871 2872 try { 2873 raf = new RandomAccessFile(filename, "r"); 2874 } 2875 catch (Exception ex) { 2876 raf = null; 2877 } 2878 2879 if (raf == null) { 2880 return false; 2881 } 2882 2883 byte[] header = new byte[4]; 2884 try { 2885 raf.read(header); 2886 } 2887 catch (Exception ex) { 2888 header = null; 2889 } 2890 2891 if (header != null) { 2892 if ( 2893 // netCDF 2894 (header[0] == 67) && (header[1] == 68) && (header[2] == 70) 2895 && (header[3] == 1)) { 2896 isnc = true; 2897 } 2898 else { 2899 isnc = false; 2900 } 2901 } 2902 2903 try { 2904 raf.close(); 2905 } 2906 catch (Exception ex) { 2907 } 2908 2909 return isnc; 2910 } 2911 2912 /** 2913 * Launch default browser for a given URL. 2914 * 2915 * @param url 2916 * the URL to open. 2917 * 2918 * @throws Exception if a failure occurred 2919 */ 2920 public static final void launchBrowser(String url) throws Exception { 2921 String os = System.getProperty("os.name"); 2922 Runtime runtime = Runtime.getRuntime(); 2923 2924 // Block for Windows Platform 2925 if (os.startsWith("Windows")) { 2926 String cmd = "rundll32 url.dll,FileProtocolHandler " + url; 2927 2928 if (new File(url).exists()) cmd = "cmd /c start \"\" \"" + url + "\""; 2929 runtime.exec(cmd); 2930 } 2931 // Block for Mac OS 2932 else if (os.startsWith("Mac OS")) { 2933 Class<?> fileMgr = Class.forName("com.apple.eio.FileManager"); 2934 Method openURL = fileMgr.getDeclaredMethod("openURL", new Class[] { String.class }); 2935 2936 if (new File(url).exists()) { 2937 // local file 2938 url = "file://" + url; 2939 } 2940 openURL.invoke(null, new Object[] { url }); 2941 } 2942 // Block for UNIX Platform 2943 else { 2944 String[] browsers = { "firefox", "opera", "konqueror", "epiphany", "mozilla", "netscape" }; 2945 String browser = null; 2946 for (int count = 0; count < browsers.length && browser == null; count++) 2947 if (runtime.exec(new String[] { "which", browsers[count] }).waitFor() == 0) browser = browsers[count]; 2948 if (browser == null) 2949 throw new Exception("Could not find web browser"); 2950 else 2951 runtime.exec(new String[] { browser, url }); 2952 } 2953 } /* public static final void launchBrowser(String url) */ 2954 2955 /** Create a new HDF file with default file creation properties 2956 * 2957 * @param filename 2958 * the file to create 2959 * @param dir 2960 * the directory for file 2961 * @param type 2962 * the type of the file 2963 * @param openFiles 2964 * the list of already opened files 2965 * 2966 * @return the FileFormat instance of the newly created file 2967 * 2968 * @throws Exception if a failure occurred 2969 */ 2970 public static FileFormat createNewFile(String filename, String dir, 2971 String type, List<FileFormat> openFiles) throws Exception { 2972 log.trace("createNewFile: {} start", filename); 2973 File f = new File(filename); 2974 2975 String fname = f.getAbsolutePath(); 2976 if (fname == null) return null; 2977 2978 fname = fname.trim(); 2979 if ((fname == null) || (fname.length() == 0)) { 2980 throw new Exception("Invalid file name."); 2981 } 2982 2983 String extensions = FileFormat.getFileExtensions(); 2984 boolean noExtension = true; 2985 if ((extensions != null) && (extensions.length() > 0)) { 2986 java.util.StringTokenizer currentExt = new java.util.StringTokenizer(extensions, ","); 2987 String extension = ""; 2988 String tmpFilename = fname.toLowerCase(); 2989 while (currentExt.hasMoreTokens() && noExtension) { 2990 extension = currentExt.nextToken().trim().toLowerCase(); 2991 noExtension = !tmpFilename.endsWith("." + extension); 2992 } 2993 } 2994 2995 if (noExtension) { 2996 if (type == FileFormat.FILE_TYPE_HDF4) { 2997 fname += ".hdf"; 2998 f = new File(fname); 2999 //setSelectedFile(f); 3000 } 3001 else if (type == FileFormat.FILE_TYPE_HDF5) { 3002 fname += ".h5"; 3003 f = new File(fname); 3004 //setSelectedFile(f); 3005 } 3006 } 3007 3008 if (f.exists() && f.isDirectory()) { 3009 throw new Exception("File is a directory."); 3010 } 3011 log.trace("createNewFile: {} not a directory", filename); 3012 3013 File pfile = f.getParentFile(); 3014 if (pfile == null) { 3015 fname = dir + File.separator + fname; 3016 f = new File(fname); 3017 } 3018 else if (!pfile.exists()) { 3019 throw new Exception("File path does not exist at\n" + pfile.getPath()); 3020 } 3021 3022 // check if the file is in use 3023 log.trace("createNewFile: {} check if the file is in use", filename); 3024 if (openFiles != null) { 3025 FileFormat theFile = null; 3026 Iterator<FileFormat> iterator = openFiles.iterator(); 3027 while (iterator.hasNext()) { 3028 theFile = iterator.next(); 3029 if (theFile.getFilePath().equals(fname)) { 3030 throw new Exception("Unable to create the new file. \nThe file is being used."); 3031 } 3032 } 3033 } 3034 3035 if (f.exists()) { 3036 log.trace("createNewFile: {} file exists", filename); 3037 3038 if (!MessageDialog.openConfirm(display.getShells()[0], "Create New File", 3039 "File exists. Do you want to replace it?")) { 3040 return null; 3041 } 3042 } 3043 3044 try { 3045 int aFlag = FileFormat.FILE_CREATE_DELETE; 3046 if (!ViewProperties.getEarlyLib().equalsIgnoreCase("Latest")) { 3047 aFlag = FileFormat.FILE_CREATE_DELETE | FileFormat.FILE_CREATE_EARLY_LIB; 3048 FileFormat.getFileFormat(type).setNewLibBounds(ViewProperties.getEarlyLib(), ViewProperties.getLateLib()); 3049 } 3050 log.trace("createNewFile: {} FileFormat create", filename); 3051 FileFormat theFile = FileFormat.getFileFormat(type).createFile(fname, aFlag); 3052 return theFile; 3053 } 3054 catch (Exception ex) { 3055 throw new Exception(ex.getMessage()); 3056 } 3057 } 3058 3059 /** 3060 * Check and find a non-exist file. 3061 * 3062 * @param path 3063 * -- the path that the new file will be checked. 3064 * @param ext 3065 * -- the extention of the new file. 3066 * 3067 * @return -- the new file. 3068 */ 3069 public static final File checkNewFile(String path, String ext) { 3070 File file = new File(path + "new" + ext); 3071 int i = 1; 3072 3073 while (file.exists()) { 3074 file = new File(path + "new" + i + ext); 3075 i++; 3076 } 3077 3078 return file; 3079 } 3080 3081 /** 3082 * Check if a given number if NaN or INF. 3083 * 3084 * @param val 3085 * the nubmer to be checked 3086 * 3087 * @return true if the number is Nan or INF; otherwise, false. 3088 */ 3089 public static final boolean isNaNINF(double val) { 3090 if (Double.isNaN(val) || val == Float.NEGATIVE_INFINITY || val == Float.POSITIVE_INFINITY 3091 || val == Double.NEGATIVE_INFINITY || val == Double.POSITIVE_INFINITY) return true; 3092 3093 return false; 3094 } 3095 3096 /** 3097 * Since Java does not allow array indices to be larger than int type, check the 3098 * given value to see if it is within the valid range of a Java int. 3099 * 3100 * @param value 3101 * The value to check 3102 * 3103 * @return false if the value is outside the range of a Java int, true 3104 * otherwise. 3105 */ 3106 public static boolean checkValidJavaArrayIndex(final long value) { 3107 if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) return false; 3108 3109 return true; 3110 } 3111 3112 /** 3113 * Retrieves the Java Runtime Class of the given Object. B = byte array, S = 3114 * short array, I = int array, J = long array, F = float array, D = double 3115 * array, L = class or interface 3116 * 3117 * @param o 3118 * the Object to determine the Runtime Class of 3119 * @return the Java Runtime Class of the given Object. 3120 */ 3121 public static char getJavaObjectRuntimeClass(Object o) { 3122 if (o == null) return ' '; 3123 3124 String cName = o.getClass().getName(); 3125 3126 if (cName.equals("java.lang.String")) return 'L'; 3127 3128 int cIndex = cName.lastIndexOf("["); 3129 if (cIndex >= 0) { 3130 return cName.charAt(cIndex + 1); 3131 } 3132 3133 return ' '; 3134 } 3135 3136 /** 3137 * Show an SWT error dialog with the given error message. 3138 * @param parent 3139 * The parent Shell of the MessageDialog 3140 * @param title 3141 * The title to set for the MessageDialog 3142 * @param errorMsg 3143 * The error message to display in the MessageDialog 3144 */ 3145 public static void showError(Shell parent, String title, String errorMsg) { 3146 String dlgTitlePrefix = ""; 3147 String dlgTitleSuffix = (title == null) ? "" : title; 3148 3149 if (parent != null) { 3150 dlgTitlePrefix = parent.getText(); 3151 if (dlgTitlePrefix.length() > 0) 3152 dlgTitlePrefix += " - "; 3153 } 3154 3155 MessageDialog.openError(parent, dlgTitlePrefix + dlgTitleSuffix, (errorMsg == null) ? "UNKNOWN" : errorMsg); 3156 } 3157 3158 /** 3159 * Show an SWT Information dialog with the given message. 3160 * @param parent 3161 * The parent Shell of the MessageDialog 3162 * @param title 3163 * The title to set for the MessageDialog 3164 * @param infoMsg 3165 * The message to display in the MessageDialog 3166 */ 3167 public static void showInformation(Shell parent, String title, String infoMsg) { 3168 String dlgTitlePrefix = ""; 3169 String dlgTitleSuffix = (title == null) ? "" : title; 3170 3171 if (parent != null) { 3172 dlgTitlePrefix = parent.getText(); 3173 if (dlgTitlePrefix.length() > 0) 3174 dlgTitlePrefix += " - "; 3175 } 3176 3177 MessageDialog.openInformation(parent, dlgTitlePrefix + dlgTitleSuffix, (infoMsg == null) ? "UNKNOWN" : infoMsg); 3178 } 3179 3180 /** 3181 * Show an SWT Confirm dialog with the given message. 3182 * 3183 * @param parent 3184 * The parent Shell of the MessageDialog 3185 * @param title 3186 * The title to set for the MessageDialog 3187 * @param confMsg 3188 * The message to display in the MessageDialog 3189 * @return The status of the dialog after closing 3190 */ 3191 public static boolean showConfirm(Shell parent, String title, String confMsg) { 3192 String dlgTitlePrefix = ""; 3193 String dlgTitleSuffix = (title == null) ? "" : title; 3194 3195 if (parent != null) { 3196 dlgTitlePrefix = parent.getText(); 3197 if (dlgTitlePrefix.length() > 0) 3198 dlgTitlePrefix += " - "; 3199 } 3200 3201 return MessageDialog.openConfirm(parent, dlgTitlePrefix + dlgTitleSuffix, (confMsg == null) ? "UNKNOWN" : confMsg); 3202 } 3203 3204 /** 3205 * Show an SWT Warning dialog with the given message. 3206 * @param parent 3207 * The parent Shell of the MessageDialog 3208 * @param title 3209 * The title to set for the MessageDialog 3210 * @param warnMsg 3211 * The message to display in the MessageDialog 3212 */ 3213 public static void showWarning(Shell parent, String title, String warnMsg) { 3214 String dlgTitlePrefix = ""; 3215 String dlgTitleSuffix = (title == null) ? "" : title; 3216 3217 if (parent != null) { 3218 dlgTitlePrefix = parent.getText(); 3219 if (dlgTitlePrefix.length() > 0) 3220 dlgTitlePrefix += " - "; 3221 } 3222 3223 MessageDialog.openWarning(parent, dlgTitlePrefix + dlgTitleSuffix, (warnMsg == null) ? "UNKNOWN" : warnMsg); 3224 } 3225}