gt:         if (bi16.getSampleModel().getNumBands() == 1) {
context: /*
   *     Orbit, a versatile image analysis software for biological image-based quantification.
   *     Copyright (C) 2009 - 2018 Idorsia Pharmaceuticals Ltd., Hegenheimermattweg 91, CH-4123 Allschwil, Switzerland.
   *
   *     This program is free software: you can redistribute it and/or modify
   *     it under the terms of the GNU General Public License as published by
   *     the Free Software Foundation, either version 3 of the License, or
   *     (at your option) any later version.
   *
   *     This program is distributed in the hope that it will be useful,
   *     but WITHOUT ANY WARRANTY; without even the implied warranty of
   *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *     GNU General Public License for more details.
   *
   *     You should have received a copy of the GNU General Public License
   *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
   *
   */
  
  package com.actelion.research.orbit.imageAnalysis.utils;
  
  import com.actelion.research.orbit.beans.RawData;
  import com.actelion.research.orbit.beans.RawDataFile;
  import com.actelion.research.orbit.beans.RawMeta;
  import com.actelion.research.orbit.imageAnalysis.dal.DALConfig;
  import com.actelion.research.orbit.utils.RawUtilsCommon;
  import com.sun.media.imageio.plugins.jpeg2000.J2KImageWriteParam;
  import ij.ImagePlus;
  import ij.process.ShortProcessor;
  import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
  
  import javax.imageio.IIOImage;
  import javax.imageio.ImageIO;
  import javax.imageio.ImageWriter;
  import javax.imageio.stream.FileImageOutputStream;
  import javax.imageio.stream.ImageOutputStream;
  import java.awt.*;
  import java.awt.image.BufferedImage;
  import java.awt.image.WritableRaster;
  import java.io.ByteArrayOutputStream;
  import java.io.File;
  import java.io.IOException;
  import java.util.HashMap;
  import java.util.List;
  
  
  /**
   * Created by wirthma1 on 6/12/2014.
   */
  public class ImageUtils {
  
      public enum PlateScalingMin {min, p01, p05, p1, p5}
  
      ;
  
      public enum PlateScalingMax {max, p95, p99, p995, p999}
  
      ;
      public static PlateScalingMin defaultPlateScalingMin = PlateScalingMin.p05;
      public static PlateScalingMax defaultPlateScalingMax = PlateScalingMax.p99;
  
      static {
          ImageIO.scanForPlugins();
      }
  
      /**
       * Converts image file into a BufferedImage
       *
       * @param inputFile
       * @return
       * @throws IOException
       */
      public static BufferedImage convertImageFileToBI(String inputFile) throws IOException {
  
          BufferedImage bi = null;
  
  
          try {
              ImageIO.setUseCache(false);
              bi = ImageIO.read(new File(inputFile));
          } catch (javax.imageio.IIOException e) // in case tiff format is not recognized, try to resolve exception using ImagePlus (ImageJ) methods
          {
              if (inputFile.endsWith(".tif") || inputFile.endsWith(".tiff")) {
                  ImagePlus ip = new ImagePlus(inputFile); // :TODO validate if tiff to be read is truly 16 bit :: otherwise there could be a scaling issue occurring afterwards
                  bi = ((ShortProcessor) ip.getProcessor().convertToShort(false)).get16BitBufferedImage();
              } else {
                  throw e;
              }
          }
  
          return bi;
      }
  
  
      /**
       * Stores BufferedImage as JPEG2000 encoded file.
       *
       * @param bi
       * @param filename
       * @param dEncRate
       * @param lossless
       * @throws IOException
       */
      public static void storeBIAsJP2File(BufferedImage bi, String filename, double dEncRate, boolean lossless) throws IOException {
  
          if (hasJPEG2000FileTag(filename)) {
  
              IIOImage iioImage = new IIOImage(bi, null, null);
  
              ImageWriter jp2iw = ImageIO.getImageWritersBySuffix("jp2").next();
              J2KImageWriteParam writeParam = (J2KImageWriteParam) jp2iw.getDefaultWriteParam();
  
              // Indicates using the lossless scheme or not. It is equivalent to use reversible quantization and 5x3 integer wavelet filters. The default is true.
              writeParam.setLossless(lossless);
  
              if (lossless)
                  writeParam.setFilter(J2KImageWriteParam.FILTER_53); // Specifies which wavelet filters to use for the specified tile-components. JPEG 2000 part I only supports w5x3 and w9x7 filters.
              else
                  writeParam.setFilter(J2KImageWriteParam.FILTER_97);
  
              if (!lossless) {
                  // The bitrate in bits-per-pixel for encoding. Should be set when lossy compression scheme is used. With the default value Double.MAX_VALUE, a lossless compression will be done.
                  writeParam.setEncodingRate(dEncRate);
  
                  // changes in compression rate are done in the following way
                  // however JPEG2000 implementation seems not to support this <-- no differences visible
                  //                writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
                  //                writeParam.setCompressionType(writeParam.getCompressionTypes()[0]);
                  //                writeParam.setCompressionQuality(1.0f);
              }
  
              ImageOutputStream ios = null;
              try {
                  ios = new FileImageOutputStream(new File(filename));
                  jp2iw.setOutput(ios);
                  jp2iw.write(null, iioImage, writeParam);
                  jp2iw.dispose();
                  ios.flush();
              } finally {
                  if (ios != null) ios.close();
              }
          } else
              System.err.println("please name your file as valid JPEG2000 file: ends with .jp2");
      }
  
      /**
       * Verifies JPEG2000 file tag
       *
       * @param filename
       * @return
       */
      private static boolean hasJPEG2000FileTag(String filename) {
  
          return filename.endsWith(".jp2");
      }
  
  
      /**
       * Stores BufferedImage as JPEG2000 encoded bytestream
       *
       * @param bi
       * @return
       * @throws IOException
       */
      public static byte[] encodeBufferedImageAsJP2(BufferedImage bi) throws IOException {
  
          byte[] byteStream = null;
  
          ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
          ImageIO.write(bi, "jpeg2000", baos);
          baos.flush();
          byteStream = baos.toByteArray();
          baos.close();
  
          return byteStream;
      }
  
      /**
       * Stores BufferedImage as JPEG encoded bytestream
       *
       * @param bi
       * @return
       * @throws IOException
       */
      public static byte[] encodeBufferedImageAsJPEG(BufferedImage bi) throws IOException {
  
          byte[] byteStream = null;
  
          ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
          ImageIO.write(bi, "jpeg", baos);
          baos.flush();
          byteStream = baos.toByteArray();
          baos.close();
  
          return byteStream;
      }
  
      /**
       * Rescales using min/max intensities and converts to 8bit. Works for gray color images.
       *
       * @param bi16
       * @return
       */
      public static BufferedImage convertTo8bit(BufferedImage bi16, int rdfId) {
          if (rdfId > 0)
              try {
                  return convertTo8bit(rdfId, bi16, defaultPlateScalingMin, defaultPlateScalingMax);
              } catch (Exception e) {
                  e.printStackTrace();
                  return convertTo8bit(bi16, 0d, 100d); // use local percentiles instead
              }
          else return convertTo8bit(bi16, 0d, 100d); // use local percentiles instead
      }
  
  
      /**
       * Rescales using arbitrary intensities and converts to 8bit. Works for gray- and rgb color images.
       *
       * @param bi16
       * @return
       */
      public static BufferedImage convertTo8bit(BufferedImage bi16, double intScalingMin, double intScalignMax) {
          // TODO: use min,max from plate meta data, not image specific
          int[][] minMax = ImageUtils.getMinMaxIntensitiesOfBI(bi16);
          BufferedImage bi = null;
          if (bi16.getSampleModel().getNumBands() == 1) {
              bi16 = ImageUtils.scaleIntensities(bi16, getPercentileIntensity(bi16, intScalingMin), getPercentileIntensity(bi16, intScalignMax));
              bi = new BufferedImage(bi16.getWidth(), bi16.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
          } else if (bi16.getSampleModel().getNumBands() == 3) {
              bi16 = ImageUtils.scaleIntensities(bi16, getPercentileIntensity(bi16, intScalingMin), getPercentileIntensity(bi16, intScalignMax));
              bi = new BufferedImage(bi16.getWidth(), bi16.getHeight(), BufferedImage.TYPE_INT_RGB);
          } else {
              throw new IllegalArgumentException("Only images with 1 band (gray-color) or 3 bands (rgb) supported. This image has " + bi16.getSampleModel().getNumBands() + " bands.");
          }
          Graphics2D g2d = bi.createGraphics();
          g2d.drawImage(bi16, 0, 0, null);
          g2d.dispose();
          return bi;
      }
  
  
      /**
       * Rescales using plate intensities and converts to 8bit. Works for gray- and rgb color images.
       *
       * @param bi16
       * @return
       */
      public static BufferedImage convertTo8bit(int rdfId, BufferedImage bi16, PlateScalingMin plateScalingMin, PlateScalingMax plateScalingMax) throws Exception {
          RawDataFile rdf = DALConfig.getImageProvider().LoadRawDataFile(rdfId);
                  /*
                  if (plateScalingMin==defaultPlateScalingMin && plateScalingMax==defaultPlateScalingMax) {
                      // /orbitvol1/2014-11/4309324.1002.jpg
                      String url = RawUtils.STR_SERVER+"/rawFile?rawFile="+rdf.getDataPath()+"/"+rdfId+"."+RawUtils.LEVEL_8BITPREVIEW+".jpg";
                      System.out.println("url: " + url);
                      return ImageIO.read(new URL(url));
                  }
                  */
  
          RawData rd = DALConfig.getImageProvider().LoadRawData(rdf.getRawDataId());
          List<RawMeta> rmList = DALConfig.getImageProvider().LoadRawMetasByRawDataFile(rdfId);
          List<RawMeta> rmDataList = DALConfig.getImageProvider().LoadRawMetasByRawData(rd.getRawDataId());
          rmList.addAll(rmDataList);
          HashMap<String, RawMeta> rmHash = RawUtilsCommon.getHashFromMetaList(rmList);
  
          if (!rmHash.containsKey(RawUtilsCommon.STR_META_CHANNEL))
              throw new Exception("Error: Meta data 'Channel' not available for RawDataFile " + rdfId);
          //int channel = Integer.parseInt(rmHash.get(RawUtils.STR_META_CHANNEL).getValue()) - 1;
          int channel = Integer.parseInt(rmHash.get(RawUtilsCommon.STR_META_CHANNEL).getValue());
          String metaKey = "Percentiles_wvlength_" + channel + "_channel_0";
          if (!rmHash.containsKey(metaKey))
              throw new Exception("Error: Meta data '" + metaKey + "' not available for RawDataFile " + rdfId);
          String val = rmHash.get(metaKey).getValue();
          int[] minmax = parseMinMax(val, plateScalingMin, plateScalingMax);
  
          BufferedImage bi = null;
          if (bi16.getSampleModel().getNumBands() == 1) {
              bi16 = ImageUtils.scaleIntensities(bi16, new int[]{minmax[0]}, new int[]{minmax[1]});
              bi = new BufferedImage(bi16.getWidth(), bi16.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
          } else {
              throw new IllegalArgumentException("Only images with 1 band (gray-color) supported. This image has " + bi16.getSampleModel().getNumBands() + " bands.");
          }
          Graphics2D g2d = bi.createGraphics();
          g2d.drawImage(bi16, 0, 0, null);
          g2d.dispose();
          return bi;
      }
  
      /**
       * input format is e.g. "MIN=82;0.1%=176;0.5%=186;1%=191;5%=204;95%=1726;99%=4239;99.5%=4832;99.9%=6079;MAX=65535";
       * returns int[2] with int[0]=minValue and int[1]=maxValue
       *
       * @param percentiles
       * @return
       */
      public static int[] parseMinMax(String percentiles, PlateScalingMin min, PlateScalingMax max) {
          //String percentiles = "MIN=82;0.1%=176;0.5%=186;1%=191;5%=204;95%=1726;99%=4239;99.5%=4832;99.9%=6079;MAX=65535";
          int[] minmax = new int[2];
          String[] split = percentiles.split(";", -1);
          for (String s : split) {
              String[] keyval = s.split("=", -1);
              //System.out.println("test: "+keyval[0]+" min: "+min.toString()+" max: "+max.toString());
              if (keyval[0].equalsIgnoreCase(getMinIntensityName(min))) minmax[0] = Integer.parseInt(keyval[1]);
              if (keyval[0].equalsIgnoreCase(getMaxIntensityName(max))) minmax[1] = Integer.parseInt(keyval[1]);
          }
          return minmax;
      }
  
  
      /**
       * Rescales using predefined min,max intensities and converts to 8bit. Works for gray- and rgb color images.
       *
       * @param bi16
       * @return
       */
      public static BufferedImage convertTo8bit(BufferedImage bi16, int min, int max) {
          BufferedImage bi = null;
  