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