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