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