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