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