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 log.trace("newInstance(Class = {}): finish", cls); 1099 1100 return instance; 1101 } 1102 1103 /** 1104 * Computes autocontrast parameters (gain equates to contrast and bias 1105 * equates to brightness) for integers. 1106 * <p> 1107 * The computation is based on the following scaling 1108 * 1109 * <pre> 1110 * int_8 [0, 127] 1111 * uint_8 [0, 255] 1112 * int_16 [0, 32767] 1113 * uint_16 [0, 65535] 1114 * int_32 [0, 2147483647] 1115 * uint_32 [0, 4294967295] 1116 * int_64 [0, 9223372036854775807] 1117 * uint_64 [0, 18446744073709551615] // Not supported. 1118 * </pre> 1119 * 1120 * @param data 1121 * the raw data array of signed/unsigned integers 1122 * @param params 1123 * the auto gain parameter. params[0]=gain, params[1]=bias, 1124 * @param isUnsigned 1125 * the flag to indicate if the data array is unsigned integer. 1126 * 1127 * @return non-negative if successful; otherwise, returns negative 1128 */ 1129 public static int autoContrastCompute(Object data, double[] params, boolean isUnsigned) { 1130 int retval = 1; 1131 long maxDataValue = 255; 1132 double[] minmax = new double[2]; 1133 1134 // check parameters 1135 if ((data == null) || (params == null) || (Array.getLength(data) <= 0) || (params.length < 2)) { 1136 return -1; 1137 } 1138 1139 retval = autoContrastComputeMinMax(data, minmax); 1140 1141 // force the min_max method so we can look at the target grids data sets 1142 if ((retval < 0) || (minmax[1] - minmax[0] < 10)) { 1143 retval = findMinMax(data, minmax, null); 1144 } 1145 1146 if (retval < 0) { 1147 return -1; 1148 } 1149 1150 String cname = data.getClass().getName(); 1151 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 1152 switch (dname) { 1153 case 'B': 1154 maxDataValue = MAX_INT8; 1155 break; 1156 case 'S': 1157 maxDataValue = MAX_INT16; 1158 if (isUnsigned) { 1159 maxDataValue = MAX_UINT8; // data was upgraded from unsigned byte 1160 } 1161 break; 1162 case 'I': 1163 maxDataValue = MAX_INT32; 1164 if (isUnsigned) { 1165 maxDataValue = MAX_UINT16; // data was upgraded from unsigned short 1166 } 1167 break; 1168 case 'J': 1169 maxDataValue = MAX_INT64; 1170 if (isUnsigned) { 1171 maxDataValue = MAX_UINT32; // data was upgraded from unsigned int 1172 } 1173 break; 1174 default: 1175 retval = -1; 1176 break; 1177 } // (dname) 1178 1179 if (minmax[0] == minmax[1]) { 1180 params[0] = 1.0; 1181 params[1] = 0.0; 1182 } 1183 else { 1184 // This histogram method has a tendency to stretch the 1185 // range of values to be a bit too big, so we can 1186 // account for this by adding and subtracting some percent 1187 // of the difference to the max/min values 1188 // to prevent the gain from going too high. 1189 double diff = minmax[1] - minmax[0]; 1190 double newmax = (minmax[1] + (diff * 0.1)); 1191 double newmin = (minmax[0] - (diff * 0.1)); 1192 1193 if (newmax <= maxDataValue) { 1194 minmax[1] = newmax; 1195 } 1196 1197 if (newmin >= 0) { 1198 minmax[0] = newmin; 1199 } 1200 1201 params[0] = maxDataValue / (minmax[1] - minmax[0]); 1202 params[1] = -minmax[0]; 1203 } 1204 1205 return retval; 1206 } 1207 1208 /** 1209 * Apply autocontrast parameters to the original data in place (destructive) 1210 * 1211 * @param dataIN 1212 * the original data array of signed/unsigned integers 1213 * @param dataOUT 1214 * the converted data array of signed/unsigned integers 1215 * @param params 1216 * the auto gain parameter. params[0]=gain, params[1]=bias 1217 * @param minmax 1218 * the data range. minmax[0]=min, minmax[1]=max 1219 * @param isUnsigned 1220 * the flag to indicate if the data array is unsigned integer 1221 * 1222 * @return the data array with the auto contrast conversion; otherwise, 1223 * returns null 1224 */ 1225 public static Object autoContrastApply(Object dataIN, Object dataOUT, double[] params, double[] minmax, 1226 boolean isUnsigned) { 1227 int size = 0; 1228 double min = -MAX_INT64; 1229 double max = MAX_INT64; 1230 1231 if ((dataIN == null) || (params == null) || (params.length < 2)) { 1232 return null; 1233 } 1234 1235 if (minmax != null) { 1236 min = minmax[0]; 1237 max = minmax[1]; 1238 } 1239 // input and output array must be the same size 1240 size = Array.getLength(dataIN); 1241 if ((dataOUT != null) && (size != Array.getLength(dataOUT))) { 1242 return null; 1243 } 1244 1245 double gain = params[0]; 1246 double bias = params[1]; 1247 double valueOut; 1248 double valueIn; 1249 String cname = dataIN.getClass().getName(); 1250 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 1251 1252 switch (dname) { 1253 case 'B': 1254 byte[] bIn = (byte[]) dataIN; 1255 if (dataOUT == null) { 1256 dataOUT = new byte[size]; 1257 } 1258 byte[] bOut = (byte[]) dataOUT; 1259 byte bMax = (byte) MAX_INT8; 1260 1261 for (int i = 0; i < size; i++) { 1262 valueIn = Math.max(bIn[i], min); 1263 valueIn = Math.min(valueIn, max); 1264 valueOut = (valueIn + bias) * gain; 1265 valueOut = Math.max(valueOut, 0.0); 1266 valueOut = Math.min(valueOut, bMax); 1267 bOut[i] = (byte) valueOut; 1268 } 1269 break; 1270 case 'S': 1271 short[] sIn = (short[]) dataIN; 1272 if (dataOUT == null) { 1273 dataOUT = new short[size]; 1274 } 1275 short[] sOut = (short[]) dataOUT; 1276 short sMax = (short) MAX_INT16; 1277 1278 if (isUnsigned) { 1279 sMax = (short) MAX_UINT8; // data was upgraded from unsigned byte 1280 } 1281 1282 for (int i = 0; i < size; i++) { 1283 valueIn = Math.max(sIn[i], min); 1284 valueIn = Math.min(valueIn, max); 1285 valueOut = (valueIn + bias) * gain; 1286 valueOut = Math.max(valueOut, 0.0); 1287 valueOut = Math.min(valueOut, sMax); 1288 sOut[i] = (byte) valueOut; 1289 } 1290 break; 1291 case 'I': 1292 int[] iIn = (int[]) dataIN; 1293 if (dataOUT == null) { 1294 dataOUT = new int[size]; 1295 } 1296 int[] iOut = (int[]) dataOUT; 1297 int iMax = (int) MAX_INT32; 1298 if (isUnsigned) { 1299 iMax = (int) MAX_UINT16; // data was upgraded from unsigned short 1300 } 1301 1302 for (int i = 0; i < size; i++) { 1303 valueIn = Math.max(iIn[i], min); 1304 valueIn = Math.min(valueIn, max); 1305 valueOut = (valueIn + bias) * gain; 1306 valueOut = Math.max(valueOut, 0.0); 1307 valueOut = Math.min(valueOut, iMax); 1308 iOut[i] = (byte) valueOut; 1309 } 1310 break; 1311 case 'J': 1312 long[] lIn = (long[]) dataIN; 1313 if (dataOUT == null) { 1314 dataOUT = new long[size]; 1315 } 1316 long[] lOut = (long[]) dataOUT; 1317 long lMax = MAX_INT64; 1318 if (isUnsigned) { 1319 lMax = MAX_UINT32; // data was upgraded from unsigned int 1320 } 1321 1322 for (int i = 0; i < size; i++) { 1323 valueIn = Math.max(lIn[i], min); 1324 valueIn = Math.min(valueIn, max); 1325 valueOut = (valueIn + bias) * gain; 1326 valueOut = Math.max(valueOut, 0.0); 1327 valueOut = Math.min(valueOut, lMax); 1328 lOut[i] = (byte) valueOut; 1329 } 1330 break; 1331 default: 1332 break; 1333 } // (dname) 1334 1335 return dataOUT; 1336 } 1337 1338 /** 1339 * Converts image raw data to bytes. 1340 * 1341 * The integer data is converted to byte data based on the following rule 1342 * 1343 * <pre> 1344 * uint_8 x 1345 * int_8 (x & 0x7F) << 1 1346 * uint_16 (x >> 8) & 0xFF 1347 * int_16 (x >> 7) & 0xFF 1348 * uint_32 (x >> 24) & 0xFF 1349 * int_32 (x >> 23) & 0xFF 1350 * uint_64 (x >> 56) & 0xFF 1351 * int_64 (x >> 55) & 0xFF 1352 * </pre> 1353 * 1354 * @param src 1355 * the source data array of signed integers or unsigned shorts 1356 * @param dst 1357 * the destination data array of bytes 1358 * @param isUnsigned 1359 * the flag to indicate if the data array is unsigned integer. 1360 * 1361 * @return non-negative if successful; otherwise, returns negative 1362 */ 1363 public static int autoContrastConvertImageBuffer(Object src, byte[] dst, boolean isUnsigned) { 1364 int retval = 0; 1365 1366 if ((src == null) || (dst == null) || (dst.length != Array.getLength(src))) { 1367 return -1; 1368 } 1369 1370 int size = dst.length; 1371 String cname = src.getClass().getName(); 1372 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 1373 switch (dname) { 1374 case 'B': 1375 byte[] bSrc = (byte[]) src; 1376 if (isUnsigned) { 1377 for (int i = 0; i < size; i++) { 1378 dst[i] = bSrc[i]; 1379 } 1380 } 1381 else { 1382 for (int i = 0; i < size; i++) { 1383 dst[i] = (byte) ((bSrc[i] & 0x7F) << 1); 1384 } 1385 } 1386 break; 1387 case 'S': 1388 short[] sSrc = (short[]) src; 1389 if (isUnsigned) { // data was upgraded from unsigned byte 1390 for (int i = 0; i < size; i++) { 1391 dst[i] = (byte) sSrc[i]; 1392 } 1393 } 1394 else { 1395 for (int i = 0; i < size; i++) { 1396 dst[i] = (byte) ((sSrc[i] >> 7) & 0xFF); 1397 } 1398 } 1399 break; 1400 case 'I': 1401 int[] iSrc = (int[]) src; 1402 if (isUnsigned) { // data was upgraded from unsigned short 1403 for (int i = 0; i < size; i++) { 1404 dst[i] = (byte) ((iSrc[i] >> 8) & 0xFF); 1405 } 1406 } 1407 else { 1408 for (int i = 0; i < size; i++) { 1409 dst[i] = (byte) ((iSrc[i] >> 23) & 0xFF); 1410 } 1411 } 1412 break; 1413 case 'J': 1414 long[] lSrc = (long[]) src; 1415 if (isUnsigned) { // data was upgraded from unsigned int 1416 for (int i = 0; i < size; i++) { 1417 dst[i] = (byte) ((lSrc[i] >> 24) & 0xFF); 1418 } 1419 } 1420 else { 1421 for (int i = 0; i < size; i++) { 1422 dst[i] = (byte) ((lSrc[i] >> 55) & 0xFF); 1423 } 1424 } 1425 break; 1426 default: 1427 retval = -1; 1428 break; 1429 } // (dname) 1430 1431 return retval; 1432 } 1433 1434 /** 1435 * Computes autocontrast parameters by 1436 * 1437 * <pre> 1438 * min = mean - 3 * std.dev 1439 * max = mean + 3 * std.dev 1440 * </pre> 1441 * 1442 * @param data 1443 * the raw data array 1444 * @param minmax 1445 * the min and max values. 1446 * 1447 * @return non-negative if successful; otherwise, returns negative 1448 */ 1449 public static int autoContrastComputeMinMax(Object data, double[] minmax) { 1450 int retval = 1; 1451 1452 if ((data == null) || (minmax == null) || (Array.getLength(data) <= 0) || (Array.getLength(minmax) < 2)) { 1453 return -1; 1454 } 1455 1456 double[] avgstd = { 0, 0 }; 1457 retval = computeStatistics(data, avgstd, null); 1458 if (retval < 0) { 1459 return retval; 1460 } 1461 1462 minmax[0] = avgstd[0] - 3.0 * avgstd[1]; 1463 minmax[1] = avgstd[0] + 3.0 * avgstd[1]; 1464 1465 return retval; 1466 } 1467 1468 /** 1469 * Finds the min and max values of the data array 1470 * 1471 * @param data 1472 * the raw data array 1473 * @param minmax 1474 * the mmin and max values of the array. 1475 * @param fillValue 1476 * the missing value or fill value. Exclude this value when check 1477 * for min/max 1478 * 1479 * @return non-negative if successful; otherwise, returns negative 1480 */ 1481 public static int findMinMax(Object data, double[] minmax, Object fillValue) { 1482 int retval = 1; 1483 1484 if ((data == null) || (minmax == null) || (Array.getLength(data) <= 0) || (Array.getLength(minmax) < 2)) { 1485 return -1; 1486 } 1487 1488 int n = Array.getLength(data); 1489 double fill = 0.0; 1490 boolean hasFillValue = (fillValue != null && fillValue.getClass().isArray()); 1491 1492 String cname = data.getClass().getName(); 1493 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 1494 log.trace("findMinMax() cname={} : dname={}", cname, dname); 1495 1496 minmax[0] = Float.MAX_VALUE; 1497 minmax[1] = -Float.MAX_VALUE; 1498 1499 switch (dname) { 1500 case 'B': 1501 byte[] b = (byte[]) data; 1502 minmax[0] = minmax[1] = b[0]; 1503 1504 if (hasFillValue) fill = ((byte[]) fillValue)[0]; 1505 for (int i = 0; i < n; i++) { 1506 if (hasFillValue && b[i] == fill) continue; 1507 if (minmax[0] > b[i]) { 1508 minmax[0] = b[i]; 1509 } 1510 if (minmax[1] < b[i]) { 1511 minmax[1] = b[i]; 1512 } 1513 } 1514 break; 1515 case 'S': 1516 short[] s = (short[]) data; 1517 minmax[0] = minmax[1] = s[0]; 1518 1519 if (hasFillValue) fill = ((short[]) fillValue)[0]; 1520 1521 for (int i = 0; i < n; i++) { 1522 if (hasFillValue && s[i] == fill) continue; 1523 if (minmax[0] > s[i]) { 1524 minmax[0] = s[i]; 1525 } 1526 if (minmax[1] < s[i]) { 1527 minmax[1] = s[i]; 1528 } 1529 } 1530 break; 1531 case 'I': 1532 int[] ia = (int[]) data; 1533 minmax[0] = minmax[1] = ia[0]; 1534 1535 if (hasFillValue) fill = ((int[]) fillValue)[0]; 1536 1537 for (int i = 0; i < n; i++) { 1538 if (hasFillValue && ia[i] == fill) continue; 1539 if (minmax[0] > ia[i]) { 1540 minmax[0] = ia[i]; 1541 } 1542 if (minmax[1] < ia[i]) { 1543 minmax[1] = ia[i]; 1544 } 1545 } 1546 break; 1547 case 'J': 1548 long[] l = (long[]) data; 1549 minmax[0] = minmax[1] = l[0]; 1550 1551 if (hasFillValue) fill = ((long[]) fillValue)[0]; 1552 for (int i = 0; i < n; i++) { 1553 if (hasFillValue && l[i] == fill) continue; 1554 if (minmax[0] > l[i]) { 1555 minmax[0] = l[i]; 1556 } 1557 if (minmax[1] < l[i]) { 1558 minmax[1] = l[i]; 1559 } 1560 } 1561 break; 1562 case 'F': 1563 float[] f = (float[]) data; 1564 minmax[0] = minmax[1] = f[0]; 1565 1566 if (hasFillValue) fill = ((float[]) fillValue)[0]; 1567 for (int i = 0; i < n; i++) { 1568 if ((hasFillValue && f[i] == fill) || isNaNINF(f[i])) continue; 1569 if (minmax[0] > f[i]) { 1570 minmax[0] = f[i]; 1571 } 1572 if (minmax[1] < f[i]) { 1573 minmax[1] = f[i]; 1574 } 1575 } 1576 1577 break; 1578 case 'D': 1579 double[] d = (double[]) data; 1580 minmax[0] = minmax[1] = d[0]; 1581 1582 if (hasFillValue) fill = ((double[]) fillValue)[0]; 1583 for (int i = 0; i < n; i++) { 1584 if ((hasFillValue && d[i] == fill) || isNaNINF(d[i])) continue; 1585 1586 if (minmax[0] > d[i]) { 1587 minmax[0] = d[i]; 1588 } 1589 if (minmax[1] < d[i]) { 1590 minmax[1] = d[i]; 1591 } 1592 } 1593 break; 1594 default: 1595 retval = -1; 1596 break; 1597 } // (dname) 1598 1599 return retval; 1600 } 1601 1602 /** 1603 * Finds the distribution of data values 1604 * 1605 * @param data 1606 * the raw data array 1607 * @param dataDist 1608 * the data distirbution. 1609 * @param minmax 1610 * the data range 1611 * 1612 * @return non-negative if successful; otherwise, returns negative 1613 */ 1614 public static int findDataDist(Object data, int[] dataDist, double[] minmax) { 1615 int retval = 0; 1616 double delt = 1; 1617 1618 if ((data == null) || (minmax == null) || dataDist == null) return -1; 1619 1620 int n = Array.getLength(data); 1621 1622 if (minmax[1] != minmax[0]) delt = (dataDist.length - 1) / (minmax[1] - minmax[0]); 1623 1624 for (int i = 0; i < dataDist.length; i++) 1625 dataDist[i] = 0; 1626 1627 int idx; 1628 double val; 1629 for (int i = 0; i < n; i++) { 1630 val = ((Number) Array.get(data, i)).doubleValue(); 1631 if (val>=minmax[0] && val <=minmax[1]) { 1632 idx = (int) ((val - minmax[0]) * delt); 1633 dataDist[idx]++; 1634 } // don't count invalid values 1635 } 1636 1637 return retval; 1638 } 1639 1640 /** 1641 * Computes mean and standard deviation of a data array 1642 * 1643 * @param data 1644 * the raw data array 1645 * @param avgstd 1646 * the statistics: avgstd[0]=mean and avgstd[1]=stdev. 1647 * @param fillValue 1648 * the missing value or fill value. Exclude this value when 1649 * compute statistics 1650 * 1651 * @return non-negative if successful; otherwise, returns negative 1652 */ 1653 public static int computeStatistics(Object data, double[] avgstd, Object fillValue) { 1654 int retval = 1; 1655 double sum = 0; 1656 double avg = 0.0; 1657 double var = 0.0; 1658 double diff = 0.0; 1659 double fill = 0.0; 1660 1661 if ((data == null) || (avgstd == null) || (Array.getLength(data) <= 0) || (Array.getLength(avgstd) < 2)) { 1662 return -1; 1663 } 1664 1665 int n = Array.getLength(data); 1666 boolean hasFillValue = (fillValue != null && fillValue.getClass().isArray()); 1667 1668 String cname = data.getClass().getName(); 1669 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 1670 log.trace("computeStatistics() cname={} : dname={}", cname, dname); 1671 1672 int npoints = 0; 1673 switch (dname) { 1674 case 'B': 1675 byte[] b = (byte[]) data; 1676 if (hasFillValue) fill = ((byte[]) fillValue)[0]; 1677 for (int i = 0; i < n; i++) { 1678 if (hasFillValue && b[i] == fill) continue; 1679 sum += b[i]; 1680 npoints++; 1681 } 1682 if (npoints > 0) { 1683 avg = sum / npoints; 1684 for (int i = 0; i < n; i++) { 1685 if (hasFillValue && b[i] == fill) 1686 continue; 1687 diff = b[i] - avg; 1688 var += diff * diff; 1689 } 1690 } 1691 break; 1692 case 'S': 1693 short[] s = (short[]) data; 1694 if (hasFillValue) fill = ((short[]) fillValue)[0]; 1695 for (int i = 0; i < n; i++) { 1696 if (hasFillValue && s[i] == fill) continue; 1697 sum += s[i]; 1698 npoints++; 1699 } 1700 if (npoints > 0) { 1701 avg = sum / npoints; 1702 for (int i = 0; i < n; i++) { 1703 if (hasFillValue && s[i] == fill) 1704 continue; 1705 diff = s[i] - avg; 1706 var += diff * diff; 1707 } 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 if (npoints > 0) { 1719 avg = sum / npoints; 1720 for (int i = 0; i < n; i++) { 1721 if (hasFillValue && ia[i] == fill) 1722 continue; 1723 diff = ia[i] - avg; 1724 var += diff * diff; 1725 } 1726 } 1727 break; 1728 case 'J': 1729 long[] l = (long[]) data; 1730 if (hasFillValue) fill = ((long[]) fillValue)[0]; 1731 for (int i = 0; i < n; i++) { 1732 if (hasFillValue && l[i] == fill) continue; 1733 sum += l[i]; 1734 npoints++; 1735 } 1736 if (npoints > 0) { 1737 avg = sum / npoints; 1738 for (int i = 0; i < n; i++) { 1739 if (hasFillValue && l[i] == fill) 1740 continue; 1741 diff = l[i] - avg; 1742 var += diff * diff; 1743 } 1744 } 1745 break; 1746 case 'F': 1747 float[] f = (float[]) data; 1748 if (hasFillValue) fill = ((float[]) fillValue)[0]; 1749 for (int i = 0; i < n; i++) { 1750 if (hasFillValue && f[i] == fill) continue; 1751 sum += f[i]; 1752 npoints++; 1753 } 1754 if (npoints > 0) { 1755 avg = sum / npoints; 1756 for (int i = 0; i < n; i++) { 1757 if (hasFillValue && f[i] == fill) 1758 continue; 1759 diff = f[i] - avg; 1760 var += diff * diff; 1761 } 1762 } 1763 break; 1764 case 'D': 1765 double[] d = (double[]) data; 1766 if (hasFillValue) fill = ((double[]) fillValue)[0]; 1767 for (int i = 0; i < n; i++) { 1768 if (hasFillValue && d[i] == fill) continue; 1769 sum += d[i]; 1770 npoints++; 1771 } 1772 if (npoints > 0) { 1773 avg = sum / npoints; 1774 for (int i = 0; i < n; i++) { 1775 if (hasFillValue && d[i] == fill) 1776 continue; 1777 diff = d[i] - avg; 1778 var += diff * diff; 1779 } 1780 } 1781 break; 1782 default: 1783 retval = -1; 1784 break; 1785 } // (dname) 1786 1787 if (npoints <= 1) { 1788 if (npoints < 1) avgstd[0] = fill; 1789 avgstd[1] = 0; 1790 } 1791 else { 1792 avgstd[0] = avg; 1793 avgstd[1] = Math.sqrt(var / (npoints - 1)); 1794 } 1795 1796 return retval; 1797 } 1798 1799 public static void saveAsBinary(DataOutputStream out, Object data, ByteOrder order) throws Exception { 1800 String cname = data.getClass().getName(); 1801 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 1802 ByteBuffer bb = null; 1803 1804 int size = Array.getLength(data); 1805 1806 if (dname == 'B') { 1807 byte[] bdata = (byte[]) data; 1808 1809 bb = ByteBuffer.allocate(BYTE_BUFFER_SIZE); 1810 bb.order(order); 1811 1812 int remainingSize = size - BYTE_BUFFER_SIZE; 1813 int allocValue = 0; 1814 int iterationNumber = 0; 1815 do { 1816 if (remainingSize <= 0) { 1817 allocValue = remainingSize + BYTE_BUFFER_SIZE; 1818 } 1819 else { 1820 allocValue = BYTE_BUFFER_SIZE; 1821 } 1822 bb.clear(); 1823 bb.put(bdata, (iterationNumber * BYTE_BUFFER_SIZE), allocValue); 1824 out.write(bb.array(), 0, allocValue); 1825 remainingSize = remainingSize - BYTE_BUFFER_SIZE; 1826 iterationNumber++; 1827 } while (remainingSize > -BYTE_BUFFER_SIZE); 1828 1829 out.flush(); 1830 out.close(); 1831 } 1832 else if (dname == 'S') { 1833 short[] sdata = (short[]) data; 1834 bb = ByteBuffer.allocate(SHORT_BUFFER_SIZE * 2); 1835 bb.order(order); 1836 1837 ShortBuffer sb = bb.asShortBuffer(); 1838 int remainingSize = size - SHORT_BUFFER_SIZE; 1839 int allocValue = 0; 1840 int iterationNumber = 0; 1841 do { 1842 if (remainingSize <= 0) { 1843 allocValue = remainingSize + SHORT_BUFFER_SIZE; 1844 } 1845 else { 1846 allocValue = SHORT_BUFFER_SIZE; 1847 } 1848 bb.clear(); 1849 sb.clear(); 1850 sb.put(sdata, (iterationNumber * SHORT_BUFFER_SIZE), allocValue); 1851 out.write(bb.array(), 0, allocValue * 2); 1852 remainingSize = remainingSize - SHORT_BUFFER_SIZE; 1853 iterationNumber++; 1854 } while (remainingSize > -SHORT_BUFFER_SIZE); 1855 1856 out.flush(); 1857 out.close(); 1858 } 1859 else if (dname == 'I') { 1860 int[] idata = (int[]) data; 1861 bb = ByteBuffer.allocate(INT_BUFFER_SIZE * 4); 1862 bb.order(order); 1863 1864 IntBuffer ib = bb.asIntBuffer(); 1865 int remainingSize = size - INT_BUFFER_SIZE; 1866 int allocValue = 0; 1867 int iterationNumber = 0; 1868 do { 1869 if (remainingSize <= 0) { 1870 allocValue = remainingSize + INT_BUFFER_SIZE; 1871 } 1872 else { 1873 allocValue = INT_BUFFER_SIZE; 1874 } 1875 bb.clear(); 1876 ib.clear(); 1877 ib.put(idata, (iterationNumber * INT_BUFFER_SIZE), allocValue); 1878 out.write(bb.array(), 0, allocValue * 4); 1879 remainingSize = remainingSize - INT_BUFFER_SIZE; 1880 iterationNumber++; 1881 } while (remainingSize > -INT_BUFFER_SIZE); 1882 1883 out.flush(); 1884 out.close(); 1885 } 1886 else if (dname == 'J') { 1887 long[] ldata = (long[]) data; 1888 1889 bb = ByteBuffer.allocate(LONG_BUFFER_SIZE * 8); 1890 bb.order(order); 1891 1892 LongBuffer lb = bb.asLongBuffer(); 1893 int remainingSize = size - LONG_BUFFER_SIZE; 1894 int allocValue = 0; 1895 int iterationNumber = 0; 1896 do { 1897 if (remainingSize <= 0) { 1898 allocValue = remainingSize + LONG_BUFFER_SIZE; 1899 } 1900 else { 1901 allocValue = LONG_BUFFER_SIZE; 1902 } 1903 bb.clear(); 1904 lb.clear(); 1905 lb.put(ldata, (iterationNumber * LONG_BUFFER_SIZE), allocValue); 1906 out.write(bb.array(), 0, allocValue * 8); 1907 remainingSize = remainingSize - LONG_BUFFER_SIZE; 1908 iterationNumber++; 1909 } while (remainingSize > -LONG_BUFFER_SIZE); 1910 1911 out.flush(); 1912 out.close(); 1913 } 1914 else if (dname == 'F') { 1915 float[] fdata = (float[]) data; 1916 1917 bb = ByteBuffer.allocate(FLOAT_BUFFER_SIZE * 4); 1918 bb.order(order); 1919 1920 FloatBuffer fb = bb.asFloatBuffer(); 1921 int remainingSize = size - FLOAT_BUFFER_SIZE; 1922 int allocValue = 0; 1923 int iterationNumber = 0; 1924 do { 1925 if (remainingSize <= 0) { 1926 allocValue = remainingSize + FLOAT_BUFFER_SIZE; 1927 } 1928 else { 1929 allocValue = FLOAT_BUFFER_SIZE; 1930 } 1931 bb.clear(); 1932 fb.clear(); 1933 fb.put(fdata, (iterationNumber * FLOAT_BUFFER_SIZE), allocValue); 1934 out.write(bb.array(), 0, allocValue * 4); 1935 remainingSize = remainingSize - FLOAT_BUFFER_SIZE; 1936 iterationNumber++; 1937 } while (remainingSize > -FLOAT_BUFFER_SIZE); 1938 1939 out.flush(); 1940 out.close(); 1941 } 1942 else if (dname == 'D') { 1943 double[] ddata = (double[]) data; 1944 1945 bb = ByteBuffer.allocate(DOUBLE_BUFFER_SIZE * 8); 1946 bb.order(order); 1947 1948 DoubleBuffer db = bb.asDoubleBuffer(); 1949 int remainingSize = size - DOUBLE_BUFFER_SIZE; 1950 int allocValue = 0; 1951 int iterationNumber = 0; 1952 do { 1953 if (remainingSize <= 0) { 1954 allocValue = remainingSize + DOUBLE_BUFFER_SIZE; 1955 } 1956 else { 1957 allocValue = DOUBLE_BUFFER_SIZE; 1958 } 1959 bb.clear(); 1960 db.clear(); 1961 db.put(ddata, (iterationNumber * DOUBLE_BUFFER_SIZE), allocValue); 1962 out.write(bb.array(), 0, allocValue * 8); 1963 remainingSize = remainingSize - DOUBLE_BUFFER_SIZE; 1964 iterationNumber++; 1965 } while (remainingSize > -DOUBLE_BUFFER_SIZE); 1966 1967 out.flush(); 1968 out.close(); 1969 } 1970 } 1971 1972 /** 1973 * Reads data from a binary file into a buffer. 1974 * 1975 * @param dataOut 1976 * the output stream 1977 * @param fileName 1978 * the file to read binary data from 1979 * @param order 1980 * the new byte order, either BIG_ENDIAN or LITTLE_ENDIAN 1981 * 1982 * @return true if successful; otherwise, false. 1983 */ 1984 public static boolean getBinaryDataFromFile(Object dataOut, String fileName, ByteOrder order) { 1985 if (dataOut == null) return false; 1986 1987 String fname = fileName; 1988 BufferedInputStream in = null; 1989 ByteBuffer byteBuffer = null; 1990 boolean valChanged = false; 1991 1992 try (FileInputStream inputFile = new FileInputStream(fname)) { 1993 long fileSize = inputFile.getChannel().size(); 1994 in = new BufferedInputStream(inputFile); 1995 1996 int datasetSize = Array.getLength(dataOut); 1997 String cname = dataOut.getClass().getName(); 1998 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 1999 2000 if (dname == 'B') { 2001 long datasetByteSize = datasetSize; 2002 byteBuffer = ByteBuffer.allocate(BYTE_BUFFER_SIZE); 2003 byteBuffer.order(order); 2004 2005 int bufferSize = (int) Math.min(fileSize, datasetByteSize); 2006 2007 int remainingSize = bufferSize - (BYTE_BUFFER_SIZE); 2008 int allocValue = 0; 2009 int iterationNumber = 0; 2010 byte[] byteArray = new byte[BYTE_BUFFER_SIZE]; 2011 do { 2012 if (remainingSize <= 0) { 2013 allocValue = remainingSize + (BYTE_BUFFER_SIZE); 2014 } 2015 else { 2016 allocValue = (BYTE_BUFFER_SIZE); 2017 } 2018 2019 in.read(byteBuffer.array(), 0, allocValue); 2020 2021 byteBuffer.get(byteArray, 0, allocValue); 2022 System.arraycopy(byteArray, 0, dataOut, (iterationNumber * BYTE_BUFFER_SIZE), allocValue); 2023 byteBuffer.clear(); 2024 remainingSize = remainingSize - (BYTE_BUFFER_SIZE); 2025 iterationNumber++; 2026 } while (remainingSize > -(BYTE_BUFFER_SIZE)); 2027 2028 valChanged = true; 2029 } 2030 else if (dname == 'S') { 2031 long datasetShortSize = (long) datasetSize * 2; 2032 byteBuffer = ByteBuffer.allocate(SHORT_BUFFER_SIZE * 2); 2033 byteBuffer.order(order); 2034 2035 int bufferSize = (int) Math.min(fileSize, datasetShortSize); 2036 int remainingSize = bufferSize - (SHORT_BUFFER_SIZE * 2); 2037 int allocValue = 0; 2038 int iterationNumber = 0; 2039 ShortBuffer sb = byteBuffer.asShortBuffer(); 2040 short[] shortArray = new short[SHORT_BUFFER_SIZE]; 2041 2042 do { 2043 if (remainingSize <= 0) { 2044 allocValue = remainingSize + (SHORT_BUFFER_SIZE * 2); 2045 } 2046 else { 2047 allocValue = (SHORT_BUFFER_SIZE * 2); 2048 } 2049 in.read(byteBuffer.array(), 0, allocValue); 2050 sb.get(shortArray, 0, allocValue / 2); 2051 System.arraycopy(shortArray, 0, dataOut, (iterationNumber * SHORT_BUFFER_SIZE), allocValue / 2); 2052 byteBuffer.clear(); 2053 sb.clear(); 2054 remainingSize = remainingSize - (SHORT_BUFFER_SIZE * 2); 2055 iterationNumber++; 2056 } while (remainingSize > -(SHORT_BUFFER_SIZE * 2)); 2057 2058 valChanged = true; 2059 } 2060 else if (dname == 'I') { 2061 long datasetIntSize = (long) datasetSize * 4; 2062 byteBuffer = ByteBuffer.allocate(INT_BUFFER_SIZE * 4); 2063 byteBuffer.order(order); 2064 2065 int bufferSize = (int) Math.min(fileSize, datasetIntSize); 2066 int remainingSize = bufferSize - (INT_BUFFER_SIZE * 4); 2067 int allocValue = 0; 2068 int iterationNumber = 0; 2069 int[] intArray = new int[INT_BUFFER_SIZE]; 2070 byte[] tmpBuf = byteBuffer.array(); 2071 IntBuffer ib = byteBuffer.asIntBuffer(); 2072 2073 do { 2074 if (remainingSize <= 0) { 2075 allocValue = remainingSize + (INT_BUFFER_SIZE * 4); 2076 } 2077 else { 2078 allocValue = (INT_BUFFER_SIZE * 4); 2079 } 2080 in.read(tmpBuf, 0, allocValue); 2081 ib.get(intArray, 0, allocValue / 4); 2082 System.arraycopy(intArray, 0, dataOut, (iterationNumber * INT_BUFFER_SIZE), allocValue / 4); 2083 byteBuffer.clear(); 2084 ib.clear(); 2085 remainingSize = remainingSize - (INT_BUFFER_SIZE * 4); 2086 iterationNumber++; 2087 } while (remainingSize > -(INT_BUFFER_SIZE * 4)); 2088 2089 valChanged = true; 2090 } 2091 else if (dname == 'J') { 2092 long datasetLongSize = (long) datasetSize * 8; 2093 byteBuffer = ByteBuffer.allocate(LONG_BUFFER_SIZE * 8); 2094 byteBuffer.order(order); 2095 2096 int bufferSize = (int) Math.min(fileSize, datasetLongSize); 2097 int remainingSize = bufferSize - (LONG_BUFFER_SIZE * 8); 2098 int allocValue = 0; 2099 int iterationNumber = 0; 2100 long[] longArray = new long[LONG_BUFFER_SIZE]; 2101 LongBuffer lb = byteBuffer.asLongBuffer(); 2102 2103 do { 2104 if (remainingSize <= 0) { 2105 allocValue = remainingSize + (LONG_BUFFER_SIZE * 8); 2106 } 2107 else { 2108 allocValue = (LONG_BUFFER_SIZE * 8); 2109 } 2110 2111 in.read(byteBuffer.array(), 0, allocValue); 2112 lb.get(longArray, 0, allocValue / 8); 2113 System.arraycopy(longArray, 0, dataOut, (iterationNumber * LONG_BUFFER_SIZE), allocValue / 8); 2114 byteBuffer.clear(); 2115 lb.clear(); 2116 remainingSize = remainingSize - (LONG_BUFFER_SIZE * 8); 2117 iterationNumber++; 2118 } while (remainingSize > -(LONG_BUFFER_SIZE * 8)); 2119 2120 valChanged = true; 2121 } 2122 else if (dname == 'F') { 2123 long datasetFloatSize = (long) datasetSize * 4; 2124 byteBuffer = ByteBuffer.allocate(FLOAT_BUFFER_SIZE * 4); 2125 byteBuffer.order(order); 2126 2127 int bufferSize = (int) Math.min(fileSize, datasetFloatSize); 2128 int remainingSize = bufferSize - (FLOAT_BUFFER_SIZE * 4); 2129 int allocValue = 0; 2130 int iterationNumber = 0; 2131 FloatBuffer fb = byteBuffer.asFloatBuffer(); 2132 float[] floatArray = new float[FLOAT_BUFFER_SIZE]; 2133 do { 2134 if (remainingSize <= 0) { 2135 allocValue = remainingSize + (FLOAT_BUFFER_SIZE * 4); 2136 } 2137 else { 2138 allocValue = (FLOAT_BUFFER_SIZE * 4); 2139 } 2140 2141 in.read(byteBuffer.array(), 0, allocValue); 2142 fb.get(floatArray, 0, allocValue / 4); 2143 System.arraycopy(floatArray, 0, dataOut, (iterationNumber * FLOAT_BUFFER_SIZE), allocValue / 4); 2144 byteBuffer.clear(); 2145 fb.clear(); 2146 remainingSize = remainingSize - (FLOAT_BUFFER_SIZE * 4); 2147 iterationNumber++; 2148 } while (remainingSize > -(FLOAT_BUFFER_SIZE * 4)); 2149 2150 valChanged = true; 2151 } 2152 else if (dname == 'D') { 2153 long datasetDoubleSize = (long) datasetSize * 8; 2154 byteBuffer = ByteBuffer.allocate(DOUBLE_BUFFER_SIZE * 8); 2155 byteBuffer.order(order); 2156 2157 int bufferSize = (int) Math.min(fileSize, datasetDoubleSize); 2158 int remainingSize = bufferSize - (DOUBLE_BUFFER_SIZE * 8); 2159 int allocValue = 0; 2160 int iterationNumber = 0; 2161 DoubleBuffer db = byteBuffer.asDoubleBuffer(); 2162 double[] doubleArray = new double[DOUBLE_BUFFER_SIZE]; 2163 2164 do { 2165 if (remainingSize <= 0) { 2166 allocValue = remainingSize + (DOUBLE_BUFFER_SIZE * 8); 2167 } 2168 else { 2169 allocValue = (DOUBLE_BUFFER_SIZE * 8); 2170 } 2171 2172 in.read(byteBuffer.array(), 0, allocValue); 2173 db.get(doubleArray, 0, allocValue / 8); 2174 System.arraycopy(doubleArray, 0, dataOut, (iterationNumber * DOUBLE_BUFFER_SIZE), allocValue / 8); 2175 byteBuffer.clear(); 2176 db.clear(); 2177 remainingSize = remainingSize - (DOUBLE_BUFFER_SIZE * 8); 2178 iterationNumber++; 2179 } while (remainingSize > -(DOUBLE_BUFFER_SIZE * 8)); 2180 2181 valChanged = true; 2182 } 2183 } 2184 catch (Exception es) { 2185 es.printStackTrace(); 2186 } 2187 finally { 2188 try { 2189 in.close(); 2190 } 2191 catch (IOException ex) { 2192 // Empty on purpose 2193 } 2194 } 2195 2196 return valChanged; 2197 } 2198 2199 /** 2200 * Returns a string representation of the long argument as an unsigned 2201 * integer in base 2. This is different from Long.toBinaryString(long i). 2202 * This function add padding (0's) to the string based on the nbytes. For 2203 * example, if v=15, nbytes=1, the string will be "00001111". 2204 * 2205 * @param v 2206 * the long value 2207 * @param nbytes 2208 * number of bytes in the integer 2209 * 2210 * @return the string representation of the unsigned long value represented 2211 * by the argument in binary (base 2). 2212 */ 2213 public static final String toBinaryString(long v, int nbytes) { 2214 if (nbytes <= 0) return null; 2215 2216 int nhex = nbytes * 2; 2217 short[] hex = new short[nhex]; 2218 2219 for (int i = 0; i < nhex; i++) 2220 hex[i] = (short) (0x0F & (v >> (i * 4))); 2221 2222 StringBuilder sb = new StringBuilder(); 2223 boolean isEven = true; 2224 for (int i = nhex - 1; i >= 0; i--) { 2225 if (isEven && i < nhex - 1) sb.append(" "); 2226 isEven = !isEven; // toggle 2227 2228 switch (hex[i]) { 2229 case 0: 2230 sb.append("0000"); 2231 break; 2232 case 1: 2233 sb.append("0001"); 2234 break; 2235 case 2: 2236 sb.append("0010"); 2237 break; 2238 case 3: 2239 sb.append("0011"); 2240 break; 2241 case 4: 2242 sb.append("0100"); 2243 break; 2244 case 5: 2245 sb.append("0101"); 2246 break; 2247 case 6: 2248 sb.append("0110"); 2249 break; 2250 case 7: 2251 sb.append("0111"); 2252 break; 2253 case 8: 2254 sb.append("1000"); 2255 break; 2256 case 9: 2257 sb.append("1001"); 2258 break; 2259 case 10: 2260 sb.append("1010"); 2261 break; 2262 case 11: 2263 sb.append("1011"); 2264 break; 2265 case 12: 2266 sb.append("1100"); 2267 break; 2268 case 13: 2269 sb.append("1101"); 2270 break; 2271 case 14: 2272 sb.append("1110"); 2273 break; 2274 case 15: 2275 sb.append("1111"); 2276 break; 2277 default: 2278 break; 2279 } 2280 } 2281 2282 return sb.toString(); 2283 } 2284 2285 public static final String toBinaryString(BigInteger v, int nbytes) { 2286 StringBuilder sb = new StringBuilder(); 2287 String val = String.format("%" + (8 * nbytes) + "s", v.toString(2)).replace(" ", "0").toUpperCase(); 2288 2289 // Insert spacing 2290 for (int i = 0; i < nbytes; i++) { 2291 sb.append(val.substring(i * nbytes, nbytes * (i + 1))); 2292 if (i < nbytes - 1) sb.append(" "); 2293 } 2294 2295 return sb.toString(); 2296 } 2297 2298 static final char[] HEXCHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 2299 2300 /** 2301 * Returns a string representation of the long argument as an unsigned integer in base 16. This 2302 * is different from Long.toHexString(long i). This function add padding (0's) to the string 2303 * based on the nbytes. For example, if v=42543, nbytes=4, the string will be "0000A62F". 2304 * 2305 * @param v 2306 * the long value 2307 * @param nbytes 2308 * number of bytes in the integer 2309 * @return the string representation of the unsigned long value represented by the argument in 2310 * hexadecimal (base 16). 2311 */ 2312 public static final String toHexString (long v, int nbytes) { 2313 if (nbytes <= 0) return null; 2314 2315 int nhex = nbytes * 2; 2316 short[] hex = new short[nhex]; 2317 2318 for (int i = 0; i < nhex; i++) { 2319 hex[i] = (short) (0x0F & (v >> (i * 4))); 2320 } 2321 2322 StringBuilder sb = new StringBuilder(); 2323 for (int i = nhex - 1; i >= 0; i--) { 2324 sb.append(HEXCHARS[hex[i]]); 2325 } 2326 2327 return sb.toString(); 2328 } 2329 2330 /** 2331 * Returns a string representation of the BigInteger argument as an unsigned integer in base 16. 2332 * This is different from BigInteger.toString(16). This function adds padding (0's) to the string 2333 * based on the nbytes. For example, if v=42543, nbytes=4, the string will be "0000A62F". 2334 * 2335 * @param v 2336 * the BigInteger value 2337 * @param nbytes 2338 * number of bytes in the integer 2339 * @return the string representation of the unsigned long value represented by the argument in 2340 * hexadecimal (base 16). 2341 */ 2342 public static final String toHexString (BigInteger v, int nbytes) { 2343 return String.format("%" + (2 * nbytes) + "s", v.toString(16)).replace(" ", "0").toUpperCase(); 2344 } 2345 2346 /** 2347 * Apply bitmask to a data array. 2348 * 2349 * @param theData 2350 * the data array which the bitmask is applied to. 2351 * @param theMask 2352 * the bitmask to be applied to the data array. 2353 * @param op 2354 * the bitmask op to be applied 2355 * 2356 * @return true if bitmask is applied successfully; otherwise, false. 2357 */ 2358 public static final boolean applyBitmask(Object theData, BitSet theMask, ViewProperties.BITMASK_OP op) { 2359 if ( theData == null 2360 || !(theData instanceof Array) 2361 || ((theData instanceof Array) && (Array.getLength(theData) <= 0)) 2362 || theMask == null) return false; 2363 2364 char nt = '0'; 2365 String cName = theData.getClass().getName(); 2366 int cIndex = cName.lastIndexOf('['); 2367 if (cIndex >= 0) { 2368 nt = cName.charAt(cIndex + 1); 2369 } 2370 2371 // only deal with 8/16/32/64 bit datasets 2372 if (!(nt == 'B' || nt == 'S' || nt == 'I' || nt == 'J')) return false; 2373 2374 long bmask = 0; 2375 long theValue = 0; 2376 long packedValue = 0; 2377 2378 int nbits = theMask.length(); 2379 int len = Array.getLength(theData); 2380 2381 for (int i = 0; i < nbits; i++) { 2382 if (theMask.get(i)) bmask += 1 << i; 2383 } 2384 2385 for (int i = 0; i < len; i++) { 2386 if (nt == 'B') 2387 theValue = ((byte[]) theData)[i] & bmask; 2388 else if (nt == 'S') 2389 theValue = ((short[]) theData)[i] & bmask; 2390 else if (nt == 'I') 2391 theValue = ((int[]) theData)[i] & bmask; 2392 else if (nt == 'J') 2393 theValue = ((long[]) theData)[i] & bmask; 2394 2395 // apply bitmask only 2396 if (op == BITMASK_OP.AND) 2397 packedValue = theValue; 2398 else { 2399 // extract bits 2400 packedValue = 0; 2401 int bitPosition = 0; 2402 2403 for (int j = 0; j < nbits; j++) { 2404 if (theMask.get(j)) { 2405 long bitValue = (theValue & 1); 2406 packedValue += (bitValue << bitPosition); 2407 bitPosition++; 2408 } 2409 // move to the next bit 2410 theValue = theValue >> 1; 2411 } 2412 } 2413 2414 if (nt == 'B') 2415 ((byte[]) theData)[i] = (byte) packedValue; 2416 else if (nt == 'S') 2417 ((short[]) theData)[i] = (short) packedValue; 2418 else if (nt == 'I') 2419 ((int[]) theData)[i] = (int) packedValue; 2420 else if (nt == 'J') 2421 ((long[]) theData)[i] = packedValue; 2422 } // (int i = 0; i < len; i++) 2423 2424 return true; 2425 } /* public static final boolean applyBitmask() */ 2426 2427 /** 2428 * Read HDF5 user block data into byte array. 2429 * 2430 * @param filename the HDF5 file from which to get the user block 2431 * 2432 * @return a byte array of user block, or null if there is user data. 2433 */ 2434 public static byte[] getHDF5UserBlock(String filename) { 2435 byte[] userBlock = null; 2436 2437 try (RandomAccessFile raf = new RandomAccessFile(filename, "r")) { 2438 byte[] header = new byte[8]; 2439 long fileSize = raf.length(); 2440 2441 // The super block is located by searching for the HDF5 file signature 2442 // at byte offset 0, byte offset 512 and at successive locations in the 2443 // file, each a multiple of two of the previous location, i.e. 0, 512, 2444 // 1024, 2048, etc 2445 long offset = 0; 2446 boolean ish5 = false; 2447 while (offset < fileSize) { 2448 raf.seek(offset); 2449 raf.read(header); 2450 2451 if ((header[0] == -119) && (header[1] == 72) && (header[2] == 68) && (header[3] == 70) && (header[4] == 13) && (header[5] == 10) && (header[6] == 26) 2452 && (header[7] == 10)) { 2453 ish5 = true; 2454 break; // find the end of user block 2455 } 2456 else { 2457 ish5 = false; 2458 if (offset == 0) { 2459 offset = 512; 2460 } 2461 else { 2462 offset *= 2; 2463 } 2464 } 2465 } 2466 2467 if (!ish5 || (offset == 0)) { 2468 return null; 2469 } 2470 2471 int blockSize = (int) offset; 2472 userBlock = new byte[blockSize]; 2473 raf.seek(0); 2474 raf.read(userBlock, 0, blockSize); 2475 } 2476 catch (Exception ex) { 2477 userBlock = null; 2478 } 2479 2480 return userBlock; 2481 } 2482 2483 /** 2484 * Write HDF5 user block data into byte array. 2485 * 2486 * @param fin the input filename 2487 * @param fout the output filename 2488 * @param buf the data to write into the user block 2489 * 2490 * @return a byte array of user block, or null if there is user data. 2491 */ 2492 public static boolean setHDF5UserBlock(String fin, String fout, byte[] buf) { 2493 boolean ish5 = false; 2494 2495 if ((buf == null) || (buf.length <= 0)) { 2496 return false; 2497 } 2498 2499 File tmpFile = new File(fin); 2500 if (!tmpFile.exists()) { 2501 return false; 2502 } 2503 2504 long offset = 0; 2505 // find the end of user block for the input file 2506 try (RandomAccessFile raf = new RandomAccessFile(fin, "r")) { 2507 byte[] header = new byte[8]; 2508 long fileSize = raf.length(); 2509 2510 // The super block is located by searching for the HDF5 file signature 2511 // at byte offset 0, byte offset 512 and at successive locations in the 2512 // file, each a multiple of two of the previous location, i.e. 0, 512, 2513 // 1024, 2048, etc 2514 while (offset < fileSize) { 2515 raf.seek(offset); 2516 raf.read(header); 2517 2518 if ((header[0] == -119) && (header[1] == 72) && (header[2] == 68) && (header[3] == 70) && (header[4] == 13) && (header[5] == 10) && (header[6] == 26) 2519 && (header[7] == 10)) { 2520 ish5 = true; 2521 break; 2522 } 2523 else { 2524 ish5 = false; 2525 if (offset == 0) { 2526 offset = 512; 2527 } 2528 else { 2529 offset *= 2; 2530 } 2531 } 2532 } 2533 } 2534 catch (Exception ex) { 2535 return false; 2536 } 2537 2538 if (!ish5) { 2539 return false; 2540 } 2541 2542 int length = 0; 2543 int bsize = 1024; 2544 byte[] buffer; 2545 2546 try (BufferedInputStream bi = new BufferedInputStream(new FileInputStream(fin))) { 2547 try (BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream(fout))) { 2548 // skip the header of original file 2549 try { 2550 long count = bi.skip(offset); 2551 if (count != offset) 2552 log.debug("file skip actual:{} req:{}", count, offset); 2553 } 2554 catch (Exception ex) { 2555 // Empty on purpose 2556 } 2557 2558 // write the header into the new file 2559 try { 2560 bo.write(buf, 0, buf.length); 2561 } 2562 catch (Exception ex) { 2563 // Empty on purpose 2564 } 2565 2566 // The super block space is allocated by offset 0, 512, 1024, 2048, etc 2567 offset = 512; 2568 while (offset < buf.length) { 2569 offset *= 2; 2570 } 2571 int padSize = (int) (offset - buf.length); 2572 if (padSize > 0) { 2573 byte[] padBuf = new byte[padSize]; 2574 try { 2575 bo.write(padBuf, 0, padSize); 2576 } 2577 catch (Exception ex) { 2578 // Empty on purpose 2579 } 2580 } 2581 2582 // copy the hdf5 file content from input file to the output file 2583 buffer = new byte[bsize]; 2584 try { 2585 length = bi.read(buffer, 0, bsize); 2586 } 2587 catch (Exception ex) { 2588 length = 0; 2589 } 2590 while (length > 0) { 2591 try { 2592 bo.write(buffer, 0, length); 2593 length = bi.read(buffer, 0, bsize); 2594 } 2595 catch (Exception ex) { 2596 length = 0; 2597 } 2598 } 2599 2600 try { 2601 bo.flush(); 2602 } 2603 catch (Exception ex) { 2604 // Empty on purpose 2605 } 2606 } 2607 catch (Exception ex) { 2608 return false; 2609 } 2610 } 2611 catch (Exception ex) { 2612 return false; 2613 } 2614 return true; 2615 } 2616 2617 /** 2618 * look at the first 4 bytes of the file to see if it is an HDF4 file. 2619 * byte[0]=14, byte[1]=3, byte[2]=19, byte[3]=1 or if it is a netCDF file 2620 * byte[0]=67, byte[1]=68, byte[2]=70, byte[3]=1 2621 * 2622 * @param filename the file to test if HDF4 2623 * 2624 * @return true if the file is of type HDF4 2625 */ 2626 public static boolean isHDF4(String filename) { 2627 boolean ish4 = false; 2628 2629 try (RandomAccessFile raf = new RandomAccessFile(filename, "r")) { 2630 byte[] header = new byte[4]; 2631 raf.read(header); 2632 2633 if ((header[0] == 14) && (header[1] == 3) && (header[2] == 19) && (header[3] == 1)) { 2634 ish4 = true; 2635 } 2636 else { 2637 ish4 = false; 2638 } 2639 } 2640 catch (Exception ex) { 2641 return false; 2642 } 2643 2644 return ish4; 2645 } 2646 2647 /** 2648 * look at the first 8 bytes of the file to see if it is an HDF5 file. 2649 * byte[0]=-199 which is 137 in unsigned byte, byte[1]=72, byte[2]=68, 2650 * byte[3]=70, byte[4]=13, byte[5]=10, byte[6]=26, byte[7]=10 2651 * 2652 * @param filename the file to test if HDF5 2653 * 2654 * @return true if the file is of type HDF5 2655 */ 2656 public static boolean isHDF5(String filename) { 2657 boolean ish5 = false; 2658 2659 try (RandomAccessFile raf = new RandomAccessFile(filename, "r")) { 2660 byte[] header = new byte[8]; 2661 long fileSize = raf.length(); 2662 2663 // The super block is located by searching for the HDF5 file signature 2664 // at byte offset 0, byte offset 512 and at successive locations in the 2665 // file, each a multiple of two of the previous location, i.e. 0, 512, 2666 // 1024, 2048, etc 2667 long offset = 0; 2668 while (!ish5 && (offset < fileSize)) { 2669 raf.seek(offset); 2670 raf.read(header); 2671 2672 if ((header[0] == -119) && (header[1] == 72) && (header[2] == 68) && (header[3] == 70) && (header[4] == 13) && (header[5] == 10) && (header[6] == 26) 2673 && (header[7] == 10)) { 2674 ish5 = true; 2675 } 2676 else { 2677 ish5 = false; 2678 if (offset == 0) { 2679 offset = 512; 2680 } 2681 else { 2682 offset *= 2; 2683 } 2684 } 2685 } 2686 } 2687 catch (Exception ex) { 2688 return false; 2689 } 2690 2691 return ish5; 2692 } 2693 2694 /** 2695 * look at the first 4 bytes of the file to see if it is a netCDF file 2696 * byte[0]=67, byte[1]=68, byte[2]=70, byte[3]=1 or 2697 * 2698 * @param filename the file to test if netcdf 2699 * 2700 * @return true if the file is of type netcdf 2701 */ 2702 public static boolean isNetcdf(String filename) { 2703 boolean isnc = false; 2704 2705 try (RandomAccessFile raf = new RandomAccessFile(filename, "r")) { 2706 2707 byte[] header = new byte[4]; 2708 raf.read(header); 2709 // netCDF 2710 if ((header[0] == 67) && (header[1] == 68) && (header[2] == 70) 2711 && (header[3] == 1)) { 2712 isnc = true; 2713 } 2714 else { 2715 isnc = false; 2716 } 2717 } 2718 catch (Exception ex) { 2719 return false; 2720 } 2721 2722 return isnc; 2723 } 2724 2725 /** 2726 * Launch default browser for a given URL. 2727 * 2728 * @param url 2729 * the URL to open. 2730 * 2731 * @throws Exception if a failure occurred 2732 */ 2733 public static final void launchBrowser(String url) throws Exception { 2734 String os = System.getProperty("os.name"); 2735 Runtime runtime = Runtime.getRuntime(); 2736 2737 // Block for Windows Platform 2738 if (os.startsWith("Windows")) { 2739 String cmd = "rundll32 url.dll,FileProtocolHandler " + url; 2740 2741 if (new File(url).exists()) cmd = "cmd /c start \"\" \"" + url + "\""; 2742 runtime.exec(cmd); 2743 } 2744 // Block for Mac OS 2745 else if (os.startsWith("Mac OS")) { 2746 Class<?> fileMgr = Class.forName("com.apple.eio.FileManager"); 2747 Method openURL = fileMgr.getDeclaredMethod("openURL", new Class[] { String.class }); 2748 2749 if (new File(url).exists()) { 2750 // local file 2751 url = "file://" + url; 2752 } 2753 openURL.invoke(null, new Object[] { url }); 2754 } 2755 // Block for UNIX Platform 2756 else { 2757 String[] browsers = { "firefox", "opera", "konqueror", "epiphany", "mozilla", "netscape" }; 2758 String browser = null; 2759 for (int count = 0; count < browsers.length && browser == null; count++) 2760 if (runtime.exec(new String[] { "which", browsers[count] }).waitFor() == 0) browser = browsers[count]; 2761 if (browser == null) 2762 throw new Exception("Could not find web browser"); 2763 else 2764 runtime.exec(new String[] { browser, url }); 2765 } 2766 } 2767 2768 /** Create a new HDF file with default file creation properties 2769 * 2770 * @param filename 2771 * the file to create 2772 * @param dir 2773 * the directory for file 2774 * @param type 2775 * the type of the file 2776 * @param openFiles 2777 * the list of already opened files 2778 * 2779 * @return the FileFormat instance of the newly created file 2780 * 2781 * @throws Exception if a failure occurred 2782 */ 2783 public static FileFormat createNewFile(String filename, String dir, 2784 String type, List<FileFormat> openFiles) throws Exception { 2785 log.trace("createNewFile: {} start", filename); 2786 File f = new File(filename); 2787 2788 String fname = f.getAbsolutePath(); 2789 if (fname == null) return null; 2790 2791 fname = fname.trim(); 2792 if ((fname == null) || (fname.length() == 0)) { 2793 throw new Exception("Invalid file name."); 2794 } 2795 2796 String extensions = FileFormat.getFileExtensions(); 2797 boolean noExtension = true; 2798 if ((extensions != null) && (extensions.length() > 0)) { 2799 java.util.StringTokenizer currentExt = new java.util.StringTokenizer(extensions, ","); 2800 String extension = ""; 2801 String tmpFilename = fname.toLowerCase(); 2802 while (currentExt.hasMoreTokens() && noExtension) { 2803 extension = currentExt.nextToken().trim().toLowerCase(); 2804 noExtension = !tmpFilename.endsWith("." + extension); 2805 } 2806 } 2807 2808 if (noExtension) { 2809 if (type.equals(FileFormat.FILE_TYPE_HDF4)) { 2810 fname += ".hdf"; 2811 f = new File(fname); 2812 } 2813 else if (type.equals(FileFormat.FILE_TYPE_HDF5)) { 2814 fname += ".h5"; 2815 f = new File(fname); 2816 } 2817 } 2818 2819 if (f.exists() && f.isDirectory()) { 2820 throw new Exception("File is a directory."); 2821 } 2822 log.trace("createNewFile: {} not a directory", filename); 2823 2824 File pfile = f.getParentFile(); 2825 if (pfile == null) { 2826 fname = dir + File.separator + fname; 2827 f = new File(fname); 2828 } 2829 else if (!pfile.exists()) { 2830 throw new Exception("File path does not exist at\n" + pfile.getPath()); 2831 } 2832 2833 // check if the file is in use 2834 log.trace("createNewFile: {} check if the file is in use", filename); 2835 if (openFiles != null) { 2836 FileFormat theFile = null; 2837 Iterator<FileFormat> iterator = openFiles.iterator(); 2838 while (iterator.hasNext()) { 2839 theFile = iterator.next(); 2840 if (theFile.getFilePath().equals(fname)) { 2841 throw new Exception("Unable to create the new file. \nThe file is being used."); 2842 } 2843 } 2844 } 2845 2846 if (f.exists()) { 2847 log.trace("createNewFile: {} file exists", filename); 2848 2849 if (!MessageDialog.openConfirm(display.getShells()[0], "Create New File", 2850 "File exists. Do you want to replace it?")) { 2851 return null; 2852 } 2853 } 2854 2855 try { 2856 int aFlag = FileFormat.FILE_CREATE_DELETE; 2857 if (!ViewProperties.getEarlyLib().equalsIgnoreCase("Latest")) { 2858 aFlag = FileFormat.FILE_CREATE_DELETE | FileFormat.FILE_CREATE_EARLY_LIB; 2859 FileFormat.getFileFormat(type).setNewLibBounds(ViewProperties.getEarlyLib(), ViewProperties.getLateLib()); 2860 } 2861 log.trace("createNewFile: {} FileFormat create", filename); 2862 return FileFormat.getFileFormat(type).createFile(fname, aFlag); 2863 } 2864 catch (Exception ex) { 2865 throw new Exception(ex.getMessage()); 2866 } 2867 } 2868 2869 /** 2870 * Check and find a non-exist file. 2871 * 2872 * @param path 2873 * -- the path that the new file will be checked. 2874 * @param ext 2875 * -- the extention of the new file. 2876 * 2877 * @return -- the new file. 2878 */ 2879 public static final File checkNewFile(String path, String ext) { 2880 File file = new File(path + "new" + ext); 2881 int i = 1; 2882 2883 while (file.exists()) { 2884 file = new File(path + "new" + i + ext); 2885 i++; 2886 } 2887 2888 return file; 2889 } 2890 2891 /** 2892 * Check if a given number if NaN or INF. 2893 * 2894 * @param val 2895 * the number to be checked 2896 * 2897 * @return true if the number is Nan or INF; otherwise, false. 2898 */ 2899 public static final boolean isNaNINF(double val) { 2900 return (Double.isNaN(val) || val == Float.NEGATIVE_INFINITY || val == Float.POSITIVE_INFINITY || val == Double.NEGATIVE_INFINITY || val == Double.POSITIVE_INFINITY); 2901 } 2902 2903 /** 2904 * Since Java does not allow array indices to be larger than int type, check the 2905 * given value to see if it is within the valid range of a Java int. 2906 * 2907 * @param value 2908 * The value to check 2909 * 2910 * @return false if the value is outside the range of a Java int, true 2911 * otherwise. 2912 */ 2913 public static boolean checkValidJavaArrayIndex(final long value) { 2914 return (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE); 2915 } 2916 2917 /** 2918 * Show an SWT error dialog with the given error message. 2919 * @param parent 2920 * The parent Shell of the MessageDialog 2921 * @param title 2922 * The title to set for the MessageDialog 2923 * @param errorMsg 2924 * The error message to display in the MessageDialog 2925 */ 2926 public static void showError(Shell parent, String title, String errorMsg) { 2927 String dlgTitlePrefix = ""; 2928 String dlgTitleSuffix = (title == null) ? "" : title; 2929 2930 if (parent != null) { 2931 dlgTitlePrefix = parent.getText(); 2932 if (dlgTitlePrefix.length() > 0) 2933 dlgTitlePrefix += " - "; 2934 } 2935 2936 MessageDialog.openError(parent, dlgTitlePrefix + dlgTitleSuffix, (errorMsg == null) ? "UNKNOWN" : errorMsg); 2937 } 2938 2939 /** 2940 * Show an SWT Information dialog with the given message. 2941 * @param parent 2942 * The parent Shell of the MessageDialog 2943 * @param title 2944 * The title to set for the MessageDialog 2945 * @param infoMsg 2946 * The message to display in the MessageDialog 2947 */ 2948 public static void showInformation(Shell parent, String title, String infoMsg) { 2949 String dlgTitlePrefix = ""; 2950 String dlgTitleSuffix = (title == null) ? "" : title; 2951 2952 if (parent != null) { 2953 dlgTitlePrefix = parent.getText(); 2954 if (dlgTitlePrefix.length() > 0) 2955 dlgTitlePrefix += " - "; 2956 } 2957 2958 MessageDialog.openInformation(parent, dlgTitlePrefix + dlgTitleSuffix, (infoMsg == null) ? "UNKNOWN" : infoMsg); 2959 } 2960 2961 /** 2962 * Show an SWT Confirm dialog with the given message. 2963 * 2964 * @param parent 2965 * The parent Shell of the MessageDialog 2966 * @param title 2967 * The title to set for the MessageDialog 2968 * @param confMsg 2969 * The message to display in the MessageDialog 2970 * @return The status of the dialog after closing 2971 */ 2972 public static boolean showConfirm(Shell parent, String title, String confMsg) { 2973 String dlgTitlePrefix = ""; 2974 String dlgTitleSuffix = (title == null) ? "" : title; 2975 2976 if (parent != null) { 2977 dlgTitlePrefix = parent.getText(); 2978 if (dlgTitlePrefix.length() > 0) 2979 dlgTitlePrefix += " - "; 2980 } 2981 2982 return MessageDialog.openConfirm(parent, dlgTitlePrefix + dlgTitleSuffix, (confMsg == null) ? "UNKNOWN" : confMsg); 2983 } 2984 2985 /** 2986 * Show an SWT Warning dialog with the given message. 2987 * @param parent 2988 * The parent Shell of the MessageDialog 2989 * @param title 2990 * The title to set for the MessageDialog 2991 * @param warnMsg 2992 * The message to display in the MessageDialog 2993 */ 2994 public static void showWarning(Shell parent, String title, String warnMsg) { 2995 String dlgTitlePrefix = ""; 2996 String dlgTitleSuffix = (title == null) ? "" : title; 2997 2998 if (parent != null) { 2999 dlgTitlePrefix = parent.getText(); 3000 if (dlgTitlePrefix.length() > 0) 3001 dlgTitlePrefix += " - "; 3002 } 3003 3004 MessageDialog.openWarning(parent, dlgTitlePrefix + dlgTitleSuffix, (warnMsg == null) ? "UNKNOWN" : warnMsg); 3005 } 3006}