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.BigDecimal; 040import java.math.BigInteger; 041import java.nio.ByteBuffer; 042import java.nio.ByteOrder; 043import java.nio.DoubleBuffer; 044import java.nio.FloatBuffer; 045import java.nio.IntBuffer; 046import java.nio.LongBuffer; 047import java.nio.ShortBuffer; 048import java.util.BitSet; 049import java.util.Iterator; 050import java.util.List; 051import java.util.StringTokenizer; 052 053import javax.imageio.ImageIO; 054 055import org.eclipse.jface.dialogs.MessageDialog; 056import org.eclipse.swt.widgets.Display; 057import org.eclipse.swt.widgets.Shell; 058 059import hdf.object.Datatype; 060import hdf.object.FileFormat; 061import hdf.object.Group; 062import hdf.object.ScalarDS; 063import hdf.view.ViewProperties.BITMASK_OP; 064 065/** 066 * The "Tools" class contains various tools for HDF files such as jpeg to HDF 067 * converter. 068 * 069 * @author Peter X. Cao 070 * @version 2.4 9/6/2007 071 */ 072public final class Tools { 073 private static final Display display = Display.getDefault(); 074 075 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Tools.class); 076 077 public static final long MAX_INT8 = 127; 078 public static final long MAX_UINT8 = 255; 079 public static final long MAX_INT16 = 32767; 080 public static final long MAX_UINT16 = 65535; 081 public static final long MAX_INT32 = 2147483647; 082 public static final long MAX_UINT32 = 4294967295L; 083 public static final long MAX_INT64 = 9223372036854775807L; 084 public static final BigInteger MAX_UINT64 = new BigInteger("18446744073709551615"); 085 086 private static final int FLOAT_BUFFER_SIZE = 524288; 087 private static final int INT_BUFFER_SIZE = 524288; 088 private static final int SHORT_BUFFER_SIZE = 1048576; 089 private static final int LONG_BUFFER_SIZE = 262144; 090 private static final int DOUBLE_BUFFER_SIZE = 262144; 091 private static final int BYTE_BUFFER_SIZE = 2097152; 092 093 /** Key for JPEG image file type. */ 094 public static final String FILE_TYPE_JPEG = "JPEG"; 095 096 /** Key for TIFF image file type. */ 097 public static final String FILE_TYPE_TIFF = "TIFF"; 098 099 /** Key for PNG image file type. */ 100 public static final String FILE_TYPE_PNG = "PNG"; 101 102 /** Key for GIF image file type. */ 103 public static final String FILE_TYPE_GIF = "GIF"; 104 105 /** Key for BMP image file type. */ 106 public static final String FILE_TYPE_BMP = "BMP"; 107 108 /** Key for all image file type. */ 109 public static final String FILE_TYPE_IMAGE = "IMG"; 110 111 /** 112 * Converts unsigned 64-bit integer data to a BigInteger since Java does not 113 * have unsigned types. 114 * 115 * @param l 116 * The long value to convert to a BigInteger 117 * 118 * @return A BigInteger representing the unsigned value of the given long. 119 */ 120 public static BigInteger convertUINT64toBigInt(Long l) { 121 if (l < 0) { 122 l = (l << 1) >>> 1; 123 BigInteger big1 = new BigInteger("9223372036854775808"); // 2^65 124 BigInteger big2 = new BigInteger(l.toString()); 125 return big1.add(big2); 126 } 127 else { 128 return new BigInteger(l.toString()); 129 } 130 } 131 132 /** 133 * Converts an image file into HDF4/5 file. 134 * 135 * @param imgFileName 136 * the input image file. 137 * @param hFileName 138 * the name of the HDF4/5 file. 139 * @param fromType 140 * the type of image. 141 * @param toType 142 * the type of file converted to. 143 * 144 * @throws Exception if a failure occurred 145 */ 146 public static void convertImageToHDF(String imgFileName, String hFileName, String fromType, String toType) 147 throws Exception { 148 File imgFile = null; 149 150 if (imgFileName == null) { 151 throw new NullPointerException("The source image file is null."); 152 } 153 imgFile = new File(imgFileName); 154 if (!imgFile.exists()) { 155 throw new NullPointerException("The source image file does not exist."); 156 } 157 if (hFileName == null) { 158 throw new NullPointerException("The target HDF file is null."); 159 } 160 161 if (!fromType.equals(FILE_TYPE_IMAGE)) { 162 throw new UnsupportedOperationException("Unsupported image type."); 163 } 164 else if (!(toType.equals(FileFormat.FILE_TYPE_HDF4) || toType.equals(FileFormat.FILE_TYPE_HDF5))) { 165 throw new UnsupportedOperationException("Unsupported destination file type."); 166 } 167 168 BufferedImage image = null; 169 try { 170 BufferedInputStream in = new BufferedInputStream(new FileInputStream(imgFileName)); 171 image = ImageIO.read(in); 172 in.close(); 173 } 174 catch (Exception err) { 175 image = null; 176 } 177 178 if (image == null) throw new UnsupportedOperationException("Failed to read image: " + imgFileName); 179 180 long h = image.getHeight(); 181 long w = image.getWidth(); 182 byte[] data = null; 183 184 try { 185 data = new byte[(int)(3 * h * w)]; 186 } 187 catch (OutOfMemoryError err) { 188 err.printStackTrace(); 189 throw err; 190 } 191 192 int idx = 0; 193 int rgb = 0; 194 for (int i = 0; i < h; i++) { 195 for (int j = 0; j < w; j++) { 196 rgb = image.getRGB(j, i); 197 data[idx++] = (byte) (rgb >> 16); 198 data[idx++] = (byte) (rgb >> 8); 199 data[idx++] = (byte) rgb; 200 } 201 } 202 203 long[] dims = null; 204 Datatype type = null; 205 Group pgroup = null; 206 String imgName = imgFile.getName(); 207 FileFormat newfile = null; 208 FileFormat thefile = null; 209 if (toType.equals(FileFormat.FILE_TYPE_HDF5)) { 210 thefile = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5); 211 long[] h5dims = { h, w, 3 }; // RGB pixel interlace 212 dims = h5dims; 213 } 214 else if (toType.equals(FileFormat.FILE_TYPE_HDF4)) { 215 thefile = FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4); 216 long[] h4dims = { w, h, 3 }; // RGB pixel interlace 217 dims = h4dims; 218 } 219 else { 220 thefile = null; 221 } 222 223 if (thefile != null) { 224 newfile = thefile.createInstance(hFileName, FileFormat.CREATE); 225 newfile.open(); 226 pgroup = (Group) newfile.getRootObject(); 227 type = newfile.createDatatype(Datatype.CLASS_CHAR, 1, Datatype.NATIVE, Datatype.SIGN_NONE); 228 newfile.createImage(imgName, pgroup, type, dims, null, null, -1, 3, ScalarDS.INTERLACE_PIXEL, data); 229 newfile.close(); 230 } 231 232 Runtime.getRuntime().gc(); 233 } 234 235 /** 236 * Save a BufferedImage into an image file. 237 * 238 * @param image 239 * the BufferedImage to save. 240 * @param file 241 * the image file. 242 * @param type 243 * the image type. 244 * 245 * @throws IOException 246 * if a failure occurred 247 */ 248 public static void saveImageAs(BufferedImage image, File file, String type) throws IOException { 249 if (image == null) { 250 throw new NullPointerException("The source image is null."); 251 } 252 253 ImageIO.write(image, type, file); 254 } 255 256 /** 257 * Creates the gray palette of the indexed 256-color table. 258 * <p> 259 * The palette values are stored in a two-dimensional byte array and arrange 260 * by color components of red, green and blue. palette[][] = byte[3][256], 261 * where, palette[0][], palette[1][] and palette[2][] are the red, green and 262 * blue components respectively. 263 * 264 * @return the gray palette in the form of byte[3][256] 265 */ 266 public static final byte[][] createGrayPalette() { 267 byte[][] p = new byte[3][256]; 268 269 for (int i = 0; i < 256; i++) { 270 p[0][i] = p[1][i] = p[2][i] = (byte) (i); 271 } 272 273 return p; 274 } 275 276 /** 277 * Creates the reverse gray palette of the indexed 256-color table. 278 * <p> 279 * The palette values are stored in a two-dimensional byte array and arrange 280 * by color components of red, green and blue. palette[][] = byte[3][256], 281 * where, palette[0][], palette[1][] and palette[2][] are the red, green and 282 * blue components respectively. 283 * 284 * @return the gray palette in the form of byte[3][256] 285 */ 286 public static final byte[][] createReverseGrayPalette() { 287 byte[][] p = new byte[3][256]; 288 289 for (int i = 0; i < 256; i++) { 290 p[0][i] = p[1][i] = p[2][i] = (byte) (255 - i); 291 } 292 293 return p; 294 } 295 296 /** 297 * Creates the gray wave palette of the indexed 256-color table. 298 * <p> 299 * The palette values are stored in a two-dimensional byte array and arrange 300 * by color components of red, green and blue. palette[][] = byte[3][256], 301 * where, palette[0][], palette[1][] and palette[2][] are the red, green and 302 * blue components respectively. 303 * 304 * @return the gray palette in the form of byte[3][256] 305 */ 306 public static final byte[][] createGrayWavePalette() { 307 byte[][] p = new byte[3][256]; 308 309 for (int i = 0; i < 256; i++) { 310 p[0][i] = p[1][i] = p[2][i] = (byte) ((double) 255 / 2 + ((double) 255 / 2) * Math.sin((i - 32) / 20.3)); 311 } 312 313 return p; 314 } 315 316 /** 317 * Creates the rainbow palette of the indexed 256-color table. 318 * <p> 319 * The palette values are stored in a two-dimensional byte array and arrange 320 * by color components of red, green and blue. palette[][] = byte[3][256], 321 * where, palette[0][], palette[1][] and palette[2][] are the red, green and 322 * blue components respectively. 323 * 324 * @return the rainbow palette in the form of byte[3][256] 325 */ 326 public static final byte[][] createRainbowPalette() { 327 byte r; 328 byte g; 329 byte b; 330 byte[][] p = new byte[3][256]; 331 332 for (int i = 1; i < 255; i++) { 333 if (i <= 29) { 334 r = (byte) (129.36 - i * 4.36); 335 g = 0; 336 b = (byte) 255; 337 } 338 else if (i <= 86) { 339 r = 0; 340 g = (byte) (-133.54 + i * 4.52); 341 b = (byte) 255; 342 } 343 else if (i <= 141) { 344 r = 0; 345 g = (byte) 255; 346 b = (byte) (665.83 - i * 4.72); 347 } 348 else if (i <= 199) { 349 r = (byte) (-635.26 + i * 4.47); 350 g = (byte) 255; 351 b = 0; 352 } 353 else { 354 r = (byte) 255; 355 g = (byte) (1166.81 - i * 4.57); 356 b = 0; 357 } 358 359 p[0][i] = r; 360 p[1][i] = g; 361 p[2][i] = b; 362 } 363 364 p[0][0] = p[1][0] = p[2][0] = 0; 365 p[0][255] = p[1][255] = p[2][255] = (byte) 255; 366 367 return p; 368 } 369 370 /** 371 * Creates the nature palette of the indexed 256-color table. 372 * <p> 373 * The palette values are stored in a two-dimensional byte array and arrange 374 * by color components of red, green and blue. palette[][] = byte[3][256], 375 * where, palette[0][], palette[1][] and palette[2][] are the red, green and 376 * blue components respectively. 377 * 378 * @return the nature palette in the form of byte[3][256] 379 */ 380 public static final byte[][] createNaturePalette() { 381 byte[][] p = new byte[3][256]; 382 383 for (int i = 1; i < 210; i++) { 384 p[0][i] = (byte) ((Math.sin((double) (i - 5) / 16) + 1) * 90); 385 p[1][i] = (byte) ((1 - Math.sin((double) (i - 30) / 12)) * 64 * (1 - (double) i / 255) + 128 - (double) i / 2); 386 p[2][i] = (byte) ((1 - Math.sin((double) (i - 8) / 9)) * 110 + 30); 387 } 388 389 for (int i = 210; i < 255; i++) { 390 p[0][i] = (byte) 80; 391 p[1][i] = (byte) 0; 392 p[2][i] = (byte) 200; 393 } 394 395 p[0][0] = p[1][0] = p[2][0] = 0; 396 p[0][255] = p[1][255] = p[2][255] = (byte) 255; 397 398 return p; 399 } 400 401 /** 402 * Creates the wave palette of the indexed 256-color table. 403 * <p> 404 * The palette values are stored in a two-dimensional byte array and arrange 405 * by color components of red, green and blue. palette[][] = byte[3][256], 406 * where, palette[0][], palette[1][] and palette[2][] are the red, green and 407 * blue components respectively. 408 * 409 * @return the wave palette in the form of byte[3][256] 410 */ 411 public static final byte[][] createWavePalette() { 412 byte[][] p = new byte[3][256]; 413 414 for (int i = 1; i < 255; i++) { 415 p[0][i] = (byte) ((Math.sin(((double) i / 40 - 3.2)) + 1) * 128); 416 p[1][i] = (byte) ((1 - Math.sin((i / 2.55 - 3.1))) * 70 + 30); 417 p[2][i] = (byte) ((1 - Math.sin(((double) i / 40 - 3.1))) * 128); 418 } 419 420 p[0][0] = p[1][0] = p[2][0] = 0; 421 p[0][255] = p[1][255] = p[2][255] = (byte) 255; 422 423 return p; 424 } 425 426 /** 427 * read an image palette from a file. 428 * 429 * A palette file has format of (value, red, green, blue). The color value 430 * in palette file can be either unsigned char [0..255] or float [0..1]. 431 * Float value will be converted to [0..255]. 432 * 433 * The color table in file can have any number of entries between 2 to 256. 434 * It will be converted to a color table of 256 entries. Any missing index 435 * will calculated by linear interpolation between the neighboring index 436 * values. For example, index 11 is missing in the following table 10 200 60 437 * 20 12 100 100 60 Index 11 will be calculated based on index 10 and index 438 * 12, i.e. 11 150 80 40 439 * 440 * @param filename 441 * the name of the palette file. 442 * 443 * @return the wave palette in the form of byte[3][256] 444 */ 445 public static final byte[][] readPalette(String filename) { 446 final int COLOR256 = 256; 447 int nentries = 0; 448 int i = 0; 449 int j = 0; 450 int idx = 0; 451 float v = 0; 452 float r = 0; 453 float g = 0; 454 float b = 0; 455 float ratio = 0; 456 float maxV = 0; 457 float minV = 0; 458 float maxColor = 0; 459 float minColor = 0; 460 float[][] tbl = new float[COLOR256][4]; /* value, red, green, blue */ 461 462 if (filename == null) return null; 463 464 try (BufferedReader in = new BufferedReader(new FileReader(filename))) { 465 String line = null; 466 do { 467 try { 468 line = in.readLine(); 469 } 470 catch (Exception ex) { 471 log.debug("input file:", ex); 472 line = null; 473 } 474 475 if (line == null) 476 continue; 477 478 StringTokenizer st = new StringTokenizer(line); 479 480 // invalid line 481 if (st.countTokens() != 4) { 482 continue; 483 } 484 485 try { 486 v = Float.valueOf(st.nextToken()); 487 r = Float.valueOf(st.nextToken()); 488 g = Float.valueOf(st.nextToken()); 489 b = Float.valueOf(st.nextToken()); 490 } 491 catch (NumberFormatException ex) { 492 log.debug("input file:", ex); 493 continue; 494 } 495 496 tbl[idx][0] = v; 497 tbl[idx][1] = r; 498 tbl[idx][2] = g; 499 tbl[idx][3] = b; 500 501 if (idx == 0) { 502 maxV = minV = v; 503 maxColor = minColor = r; 504 } 505 506 maxV = Math.max(maxV, v); 507 maxColor = Math.max(maxColor, r); 508 maxColor = Math.max(maxColor, g); 509 maxColor = Math.max(maxColor, b); 510 511 minV = Math.min(minV, v); 512 minColor = Math.min(minColor, r); 513 minColor = Math.min(minColor, g); 514 minColor = Math.min(minColor, b); 515 516 idx++; 517 if (idx >= COLOR256) 518 break; /* only support to 256 colors */ 519 } while (line != null); 520 } 521 catch (Exception ex) { 522 log.debug("input file:", ex); 523 } 524 525 nentries = idx; 526 if (nentries <= 1) // must have more than one entries 527 return null; 528 529 // convert color table to byte 530 nentries = idx; 531 if (maxColor <= 1) { 532 ratio = (minColor == maxColor) ? 1.0f : ((COLOR256 - 1.0f) / (maxColor - minColor)); 533 534 for (i = 0; i < nentries; i++) { 535 for (j = 1; j < 4; j++) 536 tbl[i][j] = (tbl[i][j] - minColor) * ratio; 537 } 538 } 539 540 // convert table to 256 entries 541 idx = 0; 542 ratio = (minV == maxV) ? 1.0f : ((COLOR256 - 1.0f) / (maxV - minV)); 543 544 int[][] p = new int[3][COLOR256]; 545 for (i = 0; i < nentries; i++) { 546 idx = (int) ((tbl[i][0] - minV) * ratio); 547 for (j = 0; j < 3; j++) 548 p[j][idx] = (int) tbl[i][j + 1]; 549 } 550 551 /* linear interpolating missing values in the color table */ 552 for (i = 1; i < COLOR256; i++) { 553 if ((p[0][i] + p[1][i] + p[2][i]) == 0) { 554 j = i + 1; 555 556 // figure out number of missing points between two given points 557 while (j < COLOR256 && (p[0][j] + p[1][j] + p[2][j]) == 0) 558 j++; 559 560 if (j >= COLOR256) break; // nothing in the table to interpolating 561 562 float d1 = (p[0][j] - p[0][i - 1]) / (float) (j - i); 563 float d2 = (p[1][j] - p[1][i - 1]) / (float) (j - i); 564 float d3 = (p[2][j] - p[2][i - 1]) / (float) (j - i); 565 566 for (int k = i; k <= j; k++) { 567 p[0][k] = (int) (p[0][i - 1] + d1 * (k - i + 1)); 568 p[1][k] = (int) (p[1][i - 1] + d2 * (k - i + 1)); 569 p[2][k] = (int) (p[2][i - 1] + d3 * (k - i + 1)); 570 } 571 i = j + 1; 572 } // ((p[0][i] + p[1][i] + p[2][i]) == 0) 573 } // (i = 1; i < COLOR256; i++) 574 575 byte[][] pal = new byte[3][COLOR256]; 576 for (i = 1; i < COLOR256; i++) { 577 for (j = 0; j < 3; j++) 578 pal[j][i] = (byte) (p[j][i]); 579 } 580 581 return pal; 582 } 583 584 /** 585 * This method returns true if the specified image has transparent pixels. 586 * 587 * @param image 588 * the image to be check if has alpha. 589 * 590 * @return true if the image has alpha setting. 591 */ 592 public static boolean hasAlpha(Image image) { 593 if (image == null) { 594 return false; 595 } 596 597 // If buffered image, the color model is readily available 598 if (image instanceof BufferedImage) { 599 BufferedImage bimage = (BufferedImage) image; 600 return bimage.getColorModel().hasAlpha(); 601 } 602 603 // Use a pixel grabber to retrieve the image's color model 604 // grabbing a single pixel is usually sufficient 605 PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false); 606 try { 607 pg.grabPixels(); 608 } 609 catch (InterruptedException e) { 610 log.debug("transparent pixels:", e); 611 } 612 ColorModel cm = pg.getColorModel(); 613 614 return cm.hasAlpha(); 615 } 616 617 /** 618 * Creates a RGB indexed image of 256 colors. 619 * 620 * @param bufferedImage 621 * the target image. 622 * @param imageData 623 * the byte array of the image data. 624 * @param palette 625 * the color lookup table. 626 * @param w 627 * the width of the image. 628 * @param h 629 * the height of the image. 630 * 631 * @return the image. 632 */ 633 public static Image createIndexedImage(BufferedImage bufferedImage, byte[] imageData, byte[][] palette, long w, long h) 634 { 635 if (imageData==null || w<=0 || h<=0) 636 return null; 637 638 if (palette==null) 639 palette = Tools.createGrayPalette(); 640 641 if (bufferedImage == null) 642 bufferedImage = new BufferedImage((int)w, (int)h, BufferedImage.TYPE_INT_ARGB); 643 644 final int[] pixels = ( (DataBufferInt) bufferedImage.getRaster().getDataBuffer() ).getData(); 645 int len = pixels.length; 646 647 for (int i=0; i<len; i++) { 648 int idx = imageData[i] & 0xff; 649 int r = (palette[0][idx] & 0xff)<<16; 650 int g = (palette[1][idx] & 0xff)<<8; 651 int b = palette[2][idx] & 0xff; 652 653 pixels[i] = 0xff000000 | r | g | b; 654 } 655 656 return bufferedImage; 657 } 658 659 /** 660 * Creates a true color image. 661 * <p> 662 * DirectColorModel is used to construct the image from raw data. The DirectColorModel model is 663 * similar to an X11 TrueColor visual, which has the following parameters: <br> 664 * 665 * <pre> 666 * Number of bits: 32 667 * Red mask: 0x00ff0000 668 * Green mask: 0x0000ff00 669 * Blue mask: 0x000000ff 670 * Alpha mask: 0xff000000 671 * Color space: sRGB 672 * isAlphaPremultiplied: False 673 * Transparency: Transparency.TRANSLUCENT 674 * transferType: DataBuffer.TYPE_INT 675 * </pre> 676 * <p> 677 * The data may be arranged in one of two ways: by pixel or by plane. In both cases, the dataset 678 * will have a dataspace with three dimensions, height, width, and components. 679 * <p> 680 * For HDF4, the interlace modes specify orders for the dimensions as: 681 * 682 * <pre> 683 * INTERLACE_PIXEL = [width][height][pixel components] 684 * INTERLACE_PLANE = [pixel components][width][height] 685 * </pre> 686 * <p> 687 * For HDF5, the interlace modes specify orders for the dimensions as: 688 * 689 * <pre> 690 * INTERLACE_PIXEL = [height][width][pixel components] 691 * INTERLACE_PLANE = [pixel components][height][width] 692 * </pre> 693 * 694 * @param imageData 695 * the byte array of the image data. 696 * @param planeInterlace 697 * flag if the image is plane interlace. 698 * @param w 699 * the width of the image. 700 * @param h 701 * the height of the image. 702 * 703 * @return the image. 704 */ 705 public static Image createTrueColorImage(byte[] imageData, boolean planeInterlace, long w, long h) { 706 Image theImage = null; 707 long imgSize = w * h; 708 int[] packedImageData = new int[(int) imgSize]; 709 int pixel = 0; 710 int idx = 0; 711 int r = 0; 712 int g = 0; 713 int b = 0; 714 for (int i = 0; i < h; i++) { 715 for (int j = 0; j < w; j++) { 716 if (planeInterlace) { 717 r = imageData[idx]; 718 g = imageData[(int)imgSize + idx]; 719 b = imageData[(int)imgSize * 2 + idx]; 720 } 721 else { 722 r = imageData[idx * 3]; 723 g = imageData[idx * 3 + 1]; 724 b = imageData[idx * 3 + 2]; 725 } 726 727 r = (r << 16) & 0x00ff0000; 728 g = (g << 8) & 0x0000ff00; 729 b = b & 0x000000ff; 730 731 // bits packed into alpha (1), red (r), green (g) and blue (b) 732 // as 11111111rrrrrrrrggggggggbbbbbbbb 733 pixel = 0xff000000 | r | g | b; 734 packedImageData[idx++] = pixel; 735 } // (int j=0; j<w; j++) 736 } // (int i=0; i<h; i++) 737 738 DirectColorModel dcm = (DirectColorModel) ColorModel.getRGBdefault(); 739 theImage = Toolkit.getDefaultToolkit().createImage(new MemoryImageSource((int)w, (int)h, dcm, packedImageData, 0, (int)w)); 740 741 return theImage; 742 } 743 744 /** 745 * This method returns a buffered image with the contents of an image. 746 * 747 * @param image 748 * the plain image object. 749 * 750 * @return buffered image for the given image. 751 */ 752 public static BufferedImage toBufferedImage(Image image) { 753 if (image == null) { 754 return null; 755 } 756 757 if (image instanceof BufferedImage) { 758 return (BufferedImage) image; 759 } 760 761 // !!!!!!!!!!!!!!!!!! NOTICE !!!!!!!!!!!!!!!!!!!!! 762 // the following way of creating a buffered image is using 763 // Component.createImage(). This method can be used only if the 764 // component is visible on the screen. Also, this method returns 765 // buffered images that do not support transparent pixels. 766 // The buffered image created by this way works for package 767 // com.sun.image.codec.jpeg.* 768 // It does not work well with JavaTM Advanced Imaging 769 // com.sun.media.jai.codec.* 770 // if the screen setting is less than 32-bit color 771 int w = image.getWidth(null); 772 int h = image.getHeight(null); 773 BufferedImage bimage = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); 774 Graphics g = bimage.createGraphics(); 775 g.drawImage(image, 0, 0, null); 776 777 g.dispose(); 778 return bimage; 779 } 780 781 /** 782 * Convert an array of raw data into array of a byte data. 783 * 784 * @param rawData 785 * The input raw data. 786 * @param minmax 787 * the range of the raw data. 788 * @param w 789 * the width of the raw data. 790 * @param h 791 * the height of the raw data. 792 * @param isTransposed 793 * if the data is transposed. 794 * @param byteData 795 * the data in. 796 * 797 * @return the byte array of pixel data. 798 */ 799 public static byte[] getBytes(Object rawData, double[] minmax, long w, long h, boolean isTransposed, byte[] byteData) { 800 return Tools.getBytes(rawData, minmax, w, h, isTransposed, null, false, byteData); 801 } 802 803 public static byte[] getBytes(Object rawData, double[] minmax, long w, long h, boolean isTransposed, 804 List<Number> invalidValues, byte[] byteData) { 805 return getBytes(rawData, minmax, w, h, isTransposed, invalidValues, false, byteData); 806 } 807 808 public static byte[] getBytes(Object rawData, double[] minmax, long w, long h, boolean isTransposed, 809 List<Number> invalidValues, boolean convertByteData, byte[] byteData) { 810 return getBytes(rawData, minmax, w, h, isTransposed,invalidValues, convertByteData, byteData, null); 811 } 812 813 /** 814 * Convert an array of raw data into array of a byte data. 815 * 816 * @param rawData 817 * The input raw data. 818 * @param minmax 819 * the range of the raw data. 820 * @param w 821 * the width of the raw data. 822 * @param h 823 * the height of the raw data. 824 * @param isTransposed 825 * if the data is transposed. 826 * @param invalidValues 827 * the list of invalid values. 828 * @param convertByteData 829 * the converted data out. 830 * @param byteData 831 * the data in. 832 * @param list 833 * the list of integers. 834 * 835 * @return the byte array of pixel data. 836 */ 837 public static byte[] getBytes(Object rawData, double[] minmax, long w, long h, boolean isTransposed, 838 List<Number> invalidValues, boolean convertByteData, byte[] byteData, List<Integer> list) 839 { 840 double[] fillValue = null; 841 842 // no input data 843 if (rawData == null || w<=0 || h<=0) { 844 return null; 845 } 846 847 // input data is not an array 848 if (!rawData.getClass().isArray()) { 849 return null; 850 } 851 852 String cname = rawData.getClass().getName(); 853 char dname = cname.charAt(cname.lastIndexOf('[') + 1); 854 int size = Array.getLength(rawData); 855 856 if (minmax == null) { 857 minmax = new double[2]; 858 minmax[0] = minmax[1] = 0; 859 } 860 861 if (dname == 'B') { 862 return convertByteData((byte[]) rawData, minmax, w, h, isTransposed, fillValue, convertByteData, byteData, list); 863 } 864 865 if ((byteData == null) || (size != byteData.length)) { 866 byteData = new byte[size]; // reuse the old buffer 867 } 868 869 if (minmax[0] == minmax[1]) { 870 Tools.findMinMax(rawData, minmax, fillValue); 871 } 872 873 double min = minmax[0]; 874 double max = minmax[1]; 875 876 if (invalidValues != null && !invalidValues.isEmpty()) { 877 int n = invalidValues.size(); 878 fillValue = new double[n]; 879 for (int i=0; i<n; i++) { 880 fillValue[i] = invalidValues.get(i).doubleValue(); 881 } 882 } 883 double ratio = (min == max) ? 1.00d : (double) (255.00 / (max - min)); 884 long idxSrc = 0; 885 long idxDst = 0; 886 switch (dname) { 887 case 'S': 888 short[] s = (short[]) rawData; 889 for (long i = 0; i < h; i++) { 890 for (long j = 0; j < w; j++) { 891 idxSrc = idxDst =j * h + i; 892 if (isTransposed) idxDst = i * w + j; 893 byteData[(int)idxDst] = toByte(s[(int)idxSrc], ratio, min, max, fillValue, (int)idxSrc, list); 894 } 895 } 896 break; 897 898 case 'I': 899 int[] ia = (int[]) rawData; 900 for (long i = 0; i < h; i++) { 901 for (long j = 0; j < w; j++) { 902 idxSrc = idxDst = (j * h + i); 903 if (isTransposed) idxDst = i * w + j; 904 byteData[(int)idxDst] = toByte(ia[(int)idxSrc], ratio, min, max, fillValue, (int)idxSrc, list); 905 } 906 } 907 break; 908 909 case 'J': 910 long[] l = (long[]) rawData; 911 for (long i = 0; i < h; i++) { 912 for (long j = 0; j < w; j++) { 913 idxSrc = idxDst =j * h + i; 914 if (isTransposed) idxDst = i * w + j; 915 byteData[(int)idxDst] = toByte(l[(int)idxSrc], ratio, min, max, fillValue, (int)idxSrc, list); 916 } 917 } 918 break; 919 920 case 'F': 921 float[] f = (float[]) rawData; 922 for (long i = 0; i < h; i++) { 923 for (long j = 0; j < w; j++) { 924 idxSrc = idxDst =j * h + i; 925 if (isTransposed) idxDst = i * w + j; 926 byteData[(int)idxDst] = toByte(f[(int)idxSrc], ratio, min, max, fillValue, (int)idxSrc, list); 927 } 928 } 929 break; 930 931 case 'D': 932 double[] d = (double[]) rawData; 933 for (long i = 0; i < h; i++) { 934 for (long j = 0; j < w; j++) { 935 idxSrc = idxDst =j * h + i; 936 if (isTransposed) idxDst = i * w + j; 937 byteData[(int)idxDst] = toByte(d[(int)idxSrc], ratio, min, max, fillValue, (int)idxSrc, list); 938 } 939 } 940 break; 941 942 default: 943 byteData = null; 944 break; 945 } // (dname) 946 947 return byteData; 948 } 949 950 private static byte toByte(double in, double ratio, double min, double max, double[] fill, int idx, List<Integer> list) 951 { 952 byte out = 0; 953 954 if (in < min || in > max || isFillValue(in, fill) || isNaNINF(in)) { 955 out = 0; 956 if (list!=null) 957 list.add(idx); 958 } 959 else 960 out = (byte) ((in-min)*ratio); 961 962 return out; 963 } 964 965 private static boolean isFillValue(double in, double[] fill) { 966 967 if (fill==null) 968 return false; 969 970 for (int i=0; i<fill.length; i++) { 971 if (fill[i] == in) 972 return true; 973 } 974 975 return false; 976 } 977 978 private static byte[] convertByteData(byte[] rawData, double[] minmax, long w, long h, boolean isTransposed, 979 Object fillValue, boolean convertByteData, byte[] byteData, List<Integer> list) { 980 if (rawData == null) return null; 981 982 if (convertByteData) { 983 if (minmax[0] == minmax[1]) { 984 Tools.findMinMax(rawData, minmax, fillValue); 985 } 986 } 987 988 if (minmax[0] == 0 && minmax[1] == 255) convertByteData = false; // no need to convert data 989 990 // no conversion and no transpose 991 if (!convertByteData && !isTransposed) { 992 if (byteData != null && byteData.length == rawData.length) { 993 System.arraycopy(rawData, 0, byteData, 0, rawData.length); 994 return byteData; 995 } 996 997 return rawData; 998 } 999 1000 // don't want to change the original raw data 1001 if (byteData == null || rawData == byteData) byteData = new byte[rawData.length]; 1002 1003 if (!convertByteData) { 1004 // do not convert data, just transpose the data 1005 minmax[0] = 0; 1006 minmax[1] = 255; 1007 if (isTransposed) { 1008 for (long i = 0; i < h; i++) { 1009 for (long j = 0; j < w; j++) { 1010 byteData[(int)(i * w + j)] = rawData[(int)(j * h + i)]; 1011 } 1012 } 1013 } 1014 return byteData; 1015 } 1016 1017 // special data range used, must convert the data 1018 double min = minmax[0]; 1019 double max = minmax[1]; 1020 double ratio = (min == max) ? 1.00d : (double) (255.00 / (max - min)); 1021 long idxSrc = 0; 1022 long idxDst = 0; 1023 for (long i = 0; i < h; i++) { 1024 for (long j = 0; j < w; j++) { 1025 idxSrc = idxDst =j * h + i; 1026 if (isTransposed) idxDst = i * w + j; 1027 1028 if (rawData[(int) idxSrc] > max || rawData[(int) idxSrc] < min) { 1029 byteData[(int)idxDst] = (byte) 0; 1030 if (list!=null) 1031 list.add((int)idxSrc); 1032 } 1033 else 1034 byteData[(int)idxDst] = (byte) ((rawData[(int)idxSrc] - min) * ratio); 1035 } 1036 } 1037 1038 return byteData; 1039 } 1040 1041 /** 1042 * Create and initialize a new instance of the given class. 1043 * 1044 * @param cls 1045 * the class of the instance 1046 * @param initargs 1047 * array of objects to be passed as arguments. 1048 * 1049 * @return a new instance of the given class. 1050 * 1051 * @throws Exception if a failure occurred 1052 */ 1053 public static Object newInstance(Class<?> cls, Object[] initargs) throws Exception { 1054 log.trace("newInstance(Class = {}): start", cls); 1055 1056 if (cls == null) { 1057 return null; 1058 } 1059 1060 Object instance = null; 1061 1062 if ((initargs == null) || (initargs.length == 0)) { 1063 instance = cls.getDeclaredConstructor().newInstance(); 1064 } 1065 else { 1066 Constructor<?>[] constructors = cls.getConstructors(); 1067 if ((constructors == null) || (constructors.length == 0)) { 1068 return null; 1069 } 1070 1071 boolean isConstructorMatched = false; 1072 Constructor<?> constructor = null; 1073 Class<?>[] params = null; 1074 int m = constructors.length; 1075 int n = initargs.length; 1076 for (int i = 0; i < m; i++) { 1077 constructor = constructors[i]; 1078 params = constructor.getParameterTypes(); 1079 if (params.length == n) { 1080 // check if all the parameters are matched 1081 isConstructorMatched = params[0].isInstance(initargs[0]); 1082 for (int j = 0; j < n; j++) { 1083 isConstructorMatched = isConstructorMatched && params[j].isInstance(initargs[j]); 1084 } 1085 1086 if (isConstructorMatched) { 1087 try { 1088 instance = constructor.newInstance(initargs); 1089 } 1090 catch (Exception ex) { 1091 log.debug("Error creating instance of {}: ", cls, ex); 1092 ex.printStackTrace(); 1093 } 1094 break; 1095 } 1096 } 1097 } // (int i=0; i<m; i++) 1098 } 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(BigDecimal v, int nbytes) { 2286 StringBuilder sb = new StringBuilder(); 2287 /* 2288 * String val = String.format("%" + (8 * nbytes) + "s", v.toString(2)).replace(" ", "0").toUpperCase(); // 2289 * Insert spacing for (int i = 0; i < nbytes; i++) { sb.append(val.substring(i * nbytes, nbytes * (i + 1))); if 2290 * (i < nbytes - 1) sb.append(" "); } 2291 */ 2292 return sb.toString(); 2293 } 2294 2295 public static final String toBinaryString(BigInteger v, int nbytes) { 2296 StringBuilder sb = new StringBuilder(); 2297 String val = String.format("%" + (8 * nbytes) + "s", v.toString(2)).replace(" ", "0").toUpperCase(); 2298 2299 // Insert spacing 2300 for (int i = 0; i < nbytes; i++) { 2301 sb.append(val.substring(i * nbytes, nbytes * (i + 1))); 2302 if (i < nbytes - 1) sb.append(" "); 2303 } 2304 2305 return sb.toString(); 2306 } 2307 2308 static final char[] HEXCHARS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 2309 2310 /** 2311 * Returns a string representation of the long argument as an unsigned integer in base 16. This 2312 * is different from Long.toHexString(long i). This function add padding (0's) to the string 2313 * based on the nbytes. For example, if v=42543, nbytes=4, the string will be "0000A62F". 2314 * 2315 * @param v 2316 * the long value 2317 * @param nbytes 2318 * number of bytes in the integer 2319 * @return the string representation of the unsigned long value represented by the argument in 2320 * hexadecimal (base 16). 2321 */ 2322 public static final String toHexString (long v, int nbytes) { 2323 if (nbytes <= 0) return null; 2324 2325 int nhex = nbytes * 2; 2326 short[] hex = new short[nhex]; 2327 2328 for (int i = 0; i < nhex; i++) { 2329 hex[i] = (short) (0x0F & (v >> (i * 4))); 2330 } 2331 2332 StringBuilder sb = new StringBuilder(); 2333 for (int i = nhex - 1; i >= 0; i--) { 2334 sb.append(HEXCHARS[hex[i]]); 2335 } 2336 2337 return sb.toString(); 2338 } 2339 2340 /** 2341 * Returns a string representation of the BigInteger argument as an unsigned integer in base 16. 2342 * This is different from BigInteger.toString(16). This function adds padding (0's) to the string 2343 * based on the nbytes. For example, if v=42543, nbytes=4, the string will be "0000A62F". 2344 * 2345 * @param v 2346 * the BigInteger value 2347 * @param nbytes 2348 * number of bytes in the integer 2349 * @return the string representation of the unsigned long value represented by the argument in 2350 * hexadecimal (base 16). 2351 */ 2352 public static final String toHexString (BigInteger v, int nbytes) { 2353 return String.format("%" + (2 * nbytes) + "s", v.toString(16)).replace(" ", "0").toUpperCase(); 2354 } 2355 2356 public static final String toHexString (BigDecimal v, int nbytes) { 2357 return null; // String.format("%" + (2 * nbytes) + "s", v.toString(16)).replace(" ", "0").toUpperCase(); 2358 } 2359 2360 /** 2361 * Apply bitmask to a data array. 2362 * 2363 * @param theData 2364 * the data array which the bitmask is applied to. 2365 * @param theMask 2366 * the bitmask to be applied to the data array. 2367 * @param op 2368 * the bitmask op to be applied 2369 * 2370 * @return true if bitmask is applied successfully; otherwise, false. 2371 */ 2372 public static final boolean applyBitmask(Object theData, BitSet theMask, ViewProperties.BITMASK_OP op) { 2373 if ( theData == null 2374 || !(theData instanceof Array) 2375 || ((theData instanceof Array) && (Array.getLength(theData) <= 0)) 2376 || theMask == null) return false; 2377 2378 char nt = '0'; 2379 String cName = theData.getClass().getName(); 2380 int cIndex = cName.lastIndexOf('['); 2381 if (cIndex >= 0) { 2382 nt = cName.charAt(cIndex + 1); 2383 } 2384 2385 // only deal with 8/16/32/64 bit datasets 2386 if (!(nt == 'B' || nt == 'S' || nt == 'I' || nt == 'J')) return false; 2387 2388 long bmask = 0; 2389 long theValue = 0; 2390 long packedValue = 0; 2391 2392 int nbits = theMask.length(); 2393 int len = Array.getLength(theData); 2394 2395 for (int i = 0; i < nbits; i++) { 2396 if (theMask.get(i)) bmask += 1 << i; 2397 } 2398 2399 for (int i = 0; i < len; i++) { 2400 if (nt == 'B') 2401 theValue = ((byte[]) theData)[i] & bmask; 2402 else if (nt == 'S') 2403 theValue = ((short[]) theData)[i] & bmask; 2404 else if (nt == 'I') 2405 theValue = ((int[]) theData)[i] & bmask; 2406 else if (nt == 'J') 2407 theValue = ((long[]) theData)[i] & bmask; 2408 2409 // apply bitmask only 2410 if (op == BITMASK_OP.AND) 2411 packedValue = theValue; 2412 else { 2413 // extract bits 2414 packedValue = 0; 2415 int bitPosition = 0; 2416 2417 for (int j = 0; j < nbits; j++) { 2418 if (theMask.get(j)) { 2419 long bitValue = (theValue & 1); 2420 packedValue += (bitValue << bitPosition); 2421 bitPosition++; 2422 } 2423 // move to the next bit 2424 theValue = theValue >> 1; 2425 } 2426 } 2427 2428 if (nt == 'B') 2429 ((byte[]) theData)[i] = (byte) packedValue; 2430 else if (nt == 'S') 2431 ((short[]) theData)[i] = (short) packedValue; 2432 else if (nt == 'I') 2433 ((int[]) theData)[i] = (int) packedValue; 2434 else if (nt == 'J') 2435 ((long[]) theData)[i] = packedValue; 2436 } // (int i = 0; i < len; i++) 2437 2438 return true; 2439 } /* public static final boolean applyBitmask() */ 2440 2441 /** 2442 * Read HDF5 user block data into byte array. 2443 * 2444 * @param filename the HDF5 file from which to get the user block 2445 * 2446 * @return a byte array of user block, or null if there is user data. 2447 */ 2448 public static byte[] getHDF5UserBlock(String filename) { 2449 byte[] userBlock = null; 2450 2451 try (RandomAccessFile raf = new RandomAccessFile(filename, "r")) { 2452 byte[] header = new byte[8]; 2453 long fileSize = raf.length(); 2454 2455 // The super block is located by searching for the HDF5 file signature 2456 // at byte offset 0, byte offset 512 and at successive locations in the 2457 // file, each a multiple of two of the previous location, i.e. 0, 512, 2458 // 1024, 2048, etc 2459 long offset = 0; 2460 boolean ish5 = false; 2461 while (offset < fileSize) { 2462 raf.seek(offset); 2463 raf.read(header); 2464 2465 if ((header[0] == -119) && (header[1] == 72) && (header[2] == 68) && (header[3] == 70) && (header[4] == 13) && (header[5] == 10) && (header[6] == 26) 2466 && (header[7] == 10)) { 2467 ish5 = true; 2468 break; // find the end of user block 2469 } 2470 else { 2471 ish5 = false; 2472 if (offset == 0) { 2473 offset = 512; 2474 } 2475 else { 2476 offset *= 2; 2477 } 2478 } 2479 } 2480 2481 if (!ish5 || (offset == 0)) { 2482 return null; 2483 } 2484 2485 int blockSize = (int) offset; 2486 userBlock = new byte[blockSize]; 2487 raf.seek(0); 2488 raf.read(userBlock, 0, blockSize); 2489 } 2490 catch (Exception ex) { 2491 userBlock = null; 2492 } 2493 2494 return userBlock; 2495 } 2496 2497 /** 2498 * Write HDF5 user block data into byte array. 2499 * 2500 * @param fin the input filename 2501 * @param fout the output filename 2502 * @param buf the data to write into the user block 2503 * 2504 * @return a byte array of user block, or null if there is user data. 2505 */ 2506 public static boolean setHDF5UserBlock(String fin, String fout, byte[] buf) { 2507 boolean ish5 = false; 2508 2509 if ((buf == null) || (buf.length <= 0)) { 2510 return false; 2511 } 2512 2513 File tmpFile = new File(fin); 2514 if (!tmpFile.exists()) { 2515 return false; 2516 } 2517 2518 long offset = 0; 2519 // find the end of user block for the input file 2520 try (RandomAccessFile raf = new RandomAccessFile(fin, "r")) { 2521 byte[] header = new byte[8]; 2522 long fileSize = raf.length(); 2523 2524 // The super block is located by searching for the HDF5 file signature 2525 // at byte offset 0, byte offset 512 and at successive locations in the 2526 // file, each a multiple of two of the previous location, i.e. 0, 512, 2527 // 1024, 2048, etc 2528 while (offset < fileSize) { 2529 raf.seek(offset); 2530 raf.read(header); 2531 2532 if ((header[0] == -119) && (header[1] == 72) && (header[2] == 68) && (header[3] == 70) && (header[4] == 13) && (header[5] == 10) && (header[6] == 26) 2533 && (header[7] == 10)) { 2534 ish5 = true; 2535 break; 2536 } 2537 else { 2538 ish5 = false; 2539 if (offset == 0) { 2540 offset = 512; 2541 } 2542 else { 2543 offset *= 2; 2544 } 2545 } 2546 } 2547 } 2548 catch (Exception ex) { 2549 return false; 2550 } 2551 2552 if (!ish5) { 2553 return false; 2554 } 2555 2556 int length = 0; 2557 int bsize = 1024; 2558 byte[] buffer; 2559 2560 try (BufferedInputStream bi = new BufferedInputStream(new FileInputStream(fin))) { 2561 try (BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream(fout))) { 2562 // skip the header of original file 2563 try { 2564 long count = bi.skip(offset); 2565 if (count != offset) 2566 log.debug("file skip actual:{} req:{}", count, offset); 2567 } 2568 catch (Exception ex) { 2569 // Empty on purpose 2570 } 2571 2572 // write the header into the new file 2573 try { 2574 bo.write(buf, 0, buf.length); 2575 } 2576 catch (Exception ex) { 2577 // Empty on purpose 2578 } 2579 2580 // The super block space is allocated by offset 0, 512, 1024, 2048, etc 2581 offset = 512; 2582 while (offset < buf.length) { 2583 offset *= 2; 2584 } 2585 int padSize = (int) (offset - buf.length); 2586 if (padSize > 0) { 2587 byte[] padBuf = new byte[padSize]; 2588 try { 2589 bo.write(padBuf, 0, padSize); 2590 } 2591 catch (Exception ex) { 2592 // Empty on purpose 2593 } 2594 } 2595 2596 // copy the hdf5 file content from input file to the output file 2597 buffer = new byte[bsize]; 2598 try { 2599 length = bi.read(buffer, 0, bsize); 2600 } 2601 catch (Exception ex) { 2602 length = 0; 2603 } 2604 while (length > 0) { 2605 try { 2606 bo.write(buffer, 0, length); 2607 length = bi.read(buffer, 0, bsize); 2608 } 2609 catch (Exception ex) { 2610 length = 0; 2611 } 2612 } 2613 2614 try { 2615 bo.flush(); 2616 } 2617 catch (Exception ex) { 2618 // Empty on purpose 2619 } 2620 } 2621 catch (Exception ex) { 2622 return false; 2623 } 2624 } 2625 catch (Exception ex) { 2626 return false; 2627 } 2628 return true; 2629 } 2630 2631 /** 2632 * look at the first 4 bytes of the file to see if it is an HDF4 file. 2633 * byte[0]=14, byte[1]=3, byte[2]=19, byte[3]=1 or if it is a netCDF file 2634 * byte[0]=67, byte[1]=68, byte[2]=70, byte[3]=1 2635 * 2636 * @param filename the file to test if HDF4 2637 * 2638 * @return true if the file is of type HDF4 2639 */ 2640 public static boolean isHDF4(String filename) { 2641 boolean ish4 = false; 2642 2643 try (RandomAccessFile raf = new RandomAccessFile(filename, "r")) { 2644 byte[] header = new byte[4]; 2645 raf.read(header); 2646 2647 if ((header[0] == 14) && (header[1] == 3) && (header[2] == 19) && (header[3] == 1)) { 2648 ish4 = true; 2649 } 2650 else { 2651 ish4 = false; 2652 } 2653 } 2654 catch (Exception ex) { 2655 return false; 2656 } 2657 2658 return ish4; 2659 } 2660 2661 /** 2662 * look at the first 8 bytes of the file to see if it is an HDF5 file. 2663 * byte[0]=-199 which is 137 in unsigned byte, byte[1]=72, byte[2]=68, 2664 * byte[3]=70, byte[4]=13, byte[5]=10, byte[6]=26, byte[7]=10 2665 * 2666 * @param filename the file to test if HDF5 2667 * 2668 * @return true if the file is of type HDF5 2669 */ 2670 public static boolean isHDF5(String filename) { 2671 boolean ish5 = false; 2672 2673 try (RandomAccessFile raf = new RandomAccessFile(filename, "r")) { 2674 byte[] header = new byte[8]; 2675 long fileSize = raf.length(); 2676 2677 // The super block is located by searching for the HDF5 file signature 2678 // at byte offset 0, byte offset 512 and at successive locations in the 2679 // file, each a multiple of two of the previous location, i.e. 0, 512, 2680 // 1024, 2048, etc 2681 long offset = 0; 2682 while (!ish5 && (offset < fileSize)) { 2683 raf.seek(offset); 2684 raf.read(header); 2685 2686 if ((header[0] == -119) && (header[1] == 72) && (header[2] == 68) && (header[3] == 70) && (header[4] == 13) && (header[5] == 10) && (header[6] == 26) 2687 && (header[7] == 10)) { 2688 ish5 = true; 2689 } 2690 else { 2691 ish5 = false; 2692 if (offset == 0) { 2693 offset = 512; 2694 } 2695 else { 2696 offset *= 2; 2697 } 2698 } 2699 } 2700 } 2701 catch (Exception ex) { 2702 return false; 2703 } 2704 2705 return ish5; 2706 } 2707 2708 /** 2709 * look at the first 4 bytes of the file to see if it is a netCDF file 2710 * byte[0]=67, byte[1]=68, byte[2]=70, byte[3]=1 or 2711 * 2712 * @param filename the file to test if netcdf 2713 * 2714 * @return true if the file is of type netcdf 2715 */ 2716 public static boolean isNetcdf(String filename) { 2717 boolean isnc = false; 2718 2719 try (RandomAccessFile raf = new RandomAccessFile(filename, "r")) { 2720 2721 byte[] header = new byte[4]; 2722 raf.read(header); 2723 // netCDF 2724 if ((header[0] == 67) && (header[1] == 68) && (header[2] == 70) 2725 && (header[3] == 1)) { 2726 isnc = true; 2727 } 2728 else { 2729 isnc = false; 2730 } 2731 } 2732 catch (Exception ex) { 2733 return false; 2734 } 2735 2736 return isnc; 2737 } 2738 2739 /** 2740 * Launch default browser for a given URL. 2741 * 2742 * @param url 2743 * the URL to open. 2744 * 2745 * @throws Exception if a failure occurred 2746 */ 2747 public static final void launchBrowser(String url) throws Exception { 2748 String os = System.getProperty("os.name"); 2749 Runtime runtime = Runtime.getRuntime(); 2750 2751 // Block for Windows Platform 2752 if (os.startsWith("Windows")) { 2753 String cmd = "rundll32 url.dll,FileProtocolHandler " + url; 2754 2755 if (new File(url).exists()) cmd = "cmd /c start \"\" \"" + url + "\""; 2756 runtime.exec(cmd); 2757 } 2758 // Block for Mac OS 2759 else if (os.startsWith("Mac OS")) { 2760 Class<?> fileMgr = Class.forName("com.apple.eio.FileManager"); 2761 Method openURL = fileMgr.getDeclaredMethod("openURL", new Class[] { String.class }); 2762 2763 if (new File(url).exists()) { 2764 // local file 2765 url = "file://" + url; 2766 } 2767 openURL.invoke(null, new Object[] { url }); 2768 } 2769 // Block for UNIX Platform 2770 else { 2771 String[] browsers = { "firefox", "opera", "konqueror", "epiphany", "mozilla", "netscape" }; 2772 String browser = null; 2773 for (int count = 0; count < browsers.length && browser == null; count++) 2774 if (runtime.exec(new String[] { "which", browsers[count] }).waitFor() == 0) browser = browsers[count]; 2775 if (browser == null) 2776 throw new Exception("Could not find web browser"); 2777 else 2778 runtime.exec(new String[] { browser, url }); 2779 } 2780 } 2781 2782 /** Create a new HDF file with default file creation properties 2783 * 2784 * @param filename 2785 * the file to create 2786 * @param dir 2787 * the directory for file 2788 * @param type 2789 * the type of the file 2790 * @param openFiles 2791 * the list of already opened files 2792 * 2793 * @return the FileFormat instance of the newly created file 2794 * 2795 * @throws Exception if a failure occurred 2796 */ 2797 public static FileFormat createNewFile(String filename, String dir, 2798 String type, List<FileFormat> openFiles) throws Exception { 2799 log.trace("createNewFile: {} start", filename); 2800 File f = new File(filename); 2801 2802 String fname = f.getAbsolutePath(); 2803 if (fname == null) return null; 2804 2805 fname = fname.trim(); 2806 if ((fname == null) || (fname.length() == 0)) { 2807 throw new Exception("Invalid file name."); 2808 } 2809 2810 String extensions = FileFormat.getFileExtensions(); 2811 boolean noExtension = true; 2812 if ((extensions != null) && (extensions.length() > 0)) { 2813 java.util.StringTokenizer currentExt = new java.util.StringTokenizer(extensions, ","); 2814 String extension = ""; 2815 String tmpFilename = fname.toLowerCase(); 2816 while (currentExt.hasMoreTokens() && noExtension) { 2817 extension = currentExt.nextToken().trim().toLowerCase(); 2818 noExtension = !tmpFilename.endsWith("." + extension); 2819 } 2820 } 2821 2822 if (noExtension) { 2823 if (type.equals(FileFormat.FILE_TYPE_HDF4)) { 2824 fname += ".hdf"; 2825 f = new File(fname); 2826 } 2827 else if (type.equals(FileFormat.FILE_TYPE_HDF5)) { 2828 fname += ".h5"; 2829 f = new File(fname); 2830 } 2831 } 2832 2833 if (f.exists() && f.isDirectory()) { 2834 throw new Exception("File is a directory."); 2835 } 2836 log.trace("createNewFile: {} not a directory", filename); 2837 2838 File pfile = f.getParentFile(); 2839 if (pfile == null) { 2840 fname = dir + File.separator + fname; 2841 f = new File(fname); 2842 } 2843 else if (!pfile.exists()) { 2844 throw new Exception("File path does not exist at\n" + pfile.getPath()); 2845 } 2846 2847 // check if the file is in use 2848 log.trace("createNewFile: {} check if the file is in use", filename); 2849 if (openFiles != null) { 2850 FileFormat theFile = null; 2851 Iterator<FileFormat> iterator = openFiles.iterator(); 2852 while (iterator.hasNext()) { 2853 theFile = iterator.next(); 2854 if (theFile.getFilePath().equals(fname)) { 2855 throw new Exception("Unable to create the new file. \nThe file is being used."); 2856 } 2857 } 2858 } 2859 2860 if (f.exists()) { 2861 log.trace("createNewFile: {} file exists", filename); 2862 2863 if (!MessageDialog.openConfirm(display.getShells()[0], "Create New File", 2864 "File exists. Do you want to replace it?")) { 2865 return null; 2866 } 2867 } 2868 2869 try { 2870 int aFlag = FileFormat.FILE_CREATE_DELETE; 2871 if (!ViewProperties.getEarlyLib().equalsIgnoreCase("Latest")) { 2872 aFlag = FileFormat.FILE_CREATE_DELETE | FileFormat.FILE_CREATE_EARLY_LIB; 2873 FileFormat.getFileFormat(type).setNewLibBounds(ViewProperties.getEarlyLib(), ViewProperties.getLateLib()); 2874 } 2875 log.trace("createNewFile: {} FileFormat create", filename); 2876 return FileFormat.getFileFormat(type).createFile(fname, aFlag); 2877 } 2878 catch (Exception ex) { 2879 throw new Exception(ex.getMessage()); 2880 } 2881 } 2882 2883 /** 2884 * Check and find a non-exist file. 2885 * 2886 * @param path 2887 * -- the path that the new file will be checked. 2888 * @param ext 2889 * -- the extention of the new file. 2890 * 2891 * @return -- the new file. 2892 */ 2893 public static final File checkNewFile(String path, String ext) { 2894 File file = new File(path + "new" + ext); 2895 int i = 1; 2896 2897 while (file.exists()) { 2898 file = new File(path + "new" + i + ext); 2899 i++; 2900 } 2901 2902 return file; 2903 } 2904 2905 /** 2906 * Check if a given number if NaN or INF. 2907 * 2908 * @param val 2909 * the number to be checked 2910 * 2911 * @return true if the number is Nan or INF; otherwise, false. 2912 */ 2913 public static final boolean isNaNINF(double val) { 2914 return (Double.isNaN(val) || val == Float.NEGATIVE_INFINITY || val == Float.POSITIVE_INFINITY || val == Double.NEGATIVE_INFINITY || val == Double.POSITIVE_INFINITY); 2915 } 2916 2917 /** 2918 * Since Java does not allow array indices to be larger than int type, check the 2919 * given value to see if it is within the valid range of a Java int. 2920 * 2921 * @param value 2922 * The value to check 2923 * 2924 * @return false if the value is outside the range of a Java int, true 2925 * otherwise. 2926 */ 2927 public static boolean checkValidJavaArrayIndex(final long value) { 2928 return (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE); 2929 } 2930 2931 /** 2932 * Show an SWT error dialog with the given error message. 2933 * @param parent 2934 * The parent Shell of the MessageDialog 2935 * @param title 2936 * The title to set for the MessageDialog 2937 * @param errorMsg 2938 * The error message to display in the MessageDialog 2939 */ 2940 public static void showError(Shell parent, String title, String errorMsg) { 2941 String dlgTitlePrefix = ""; 2942 String dlgTitleSuffix = (title == null) ? "" : title; 2943 2944 if (parent != null) { 2945 dlgTitlePrefix = parent.getText(); 2946 if (dlgTitlePrefix.length() > 0) 2947 dlgTitlePrefix += " - "; 2948 } 2949 2950 MessageDialog.openError(parent, dlgTitlePrefix + dlgTitleSuffix, (errorMsg == null) ? "UNKNOWN" : errorMsg); 2951 } 2952 2953 /** 2954 * Show an SWT Information dialog with the given message. 2955 * @param parent 2956 * The parent Shell of the MessageDialog 2957 * @param title 2958 * The title to set for the MessageDialog 2959 * @param infoMsg 2960 * The message to display in the MessageDialog 2961 */ 2962 public static void showInformation(Shell parent, String title, String infoMsg) { 2963 String dlgTitlePrefix = ""; 2964 String dlgTitleSuffix = (title == null) ? "" : title; 2965 2966 if (parent != null) { 2967 dlgTitlePrefix = parent.getText(); 2968 if (dlgTitlePrefix.length() > 0) 2969 dlgTitlePrefix += " - "; 2970 } 2971 2972 MessageDialog.openInformation(parent, dlgTitlePrefix + dlgTitleSuffix, (infoMsg == null) ? "UNKNOWN" : infoMsg); 2973 } 2974 2975 /** 2976 * Show an SWT Confirm dialog with the given message. 2977 * 2978 * @param parent 2979 * The parent Shell of the MessageDialog 2980 * @param title 2981 * The title to set for the MessageDialog 2982 * @param confMsg 2983 * The message to display in the MessageDialog 2984 * @return The status of the dialog after closing 2985 */ 2986 public static boolean showConfirm(Shell parent, String title, String confMsg) { 2987 String dlgTitlePrefix = ""; 2988 String dlgTitleSuffix = (title == null) ? "" : title; 2989 2990 if (parent != null) { 2991 dlgTitlePrefix = parent.getText(); 2992 if (dlgTitlePrefix.length() > 0) 2993 dlgTitlePrefix += " - "; 2994 } 2995 2996 return MessageDialog.openConfirm(parent, dlgTitlePrefix + dlgTitleSuffix, (confMsg == null) ? "UNKNOWN" : confMsg); 2997 } 2998 2999 /** 3000 * Show an SWT Warning dialog with the given message. 3001 * @param parent 3002 * The parent Shell of the MessageDialog 3003 * @param title 3004 * The title to set for the MessageDialog 3005 * @param warnMsg 3006 * The message to display in the MessageDialog 3007 */ 3008 public static void showWarning(Shell parent, String title, String warnMsg) { 3009 String dlgTitlePrefix = ""; 3010 String dlgTitleSuffix = (title == null) ? "" : title; 3011 3012 if (parent != null) { 3013 dlgTitlePrefix = parent.getText(); 3014 if (dlgTitlePrefix.length() > 0) 3015 dlgTitlePrefix += " - "; 3016 } 3017 3018 MessageDialog.openWarning(parent, dlgTitlePrefix + dlgTitleSuffix, (warnMsg == null) ? "UNKNOWN" : warnMsg); 3019 } 3020}