public static BufferedImage convertImageData(ImageData data) {
    BufferedImage bimg = null;
    int height = data.getHeight(), width = data.getWidth();
    Object pixels = data.getData();
    if (pixels instanceof int[] && data.getElementWidth() == 1) {
      int[] arr = (int[]) pixels;
      byte[] barray = new byte[arr.length * 3];
      int k = 0;
      for (int j = 0; j < arr.length; j++) {
        int l = arr[j];
        barray[k++] = (byte) (l & 0xFF);
        barray[k++] = (byte) ((l >>> 8) & 0xFF);
        barray[k++] = (byte) ((l >>> 16) & 0xFF);
      }
      ColorModel ccm =
          new ComponentColorModel(
              ICC_ColorSpace.getInstance(ICC_ColorSpace.CS_sRGB),
              new int[] {8, 8, 8},
              false,
              false,
              Transparency.OPAQUE,
              DataBuffer.TYPE_BYTE);
      DataBuffer bbuf = new DataBufferByte(barray, barray.length);
      SampleModel bmodel =
          new PixelInterleavedSampleModel(
              DataBuffer.TYPE_BYTE, width, height, 3, 3 * width, new int[] {2, 1, 0});

      WritableRaster raster = Raster.createWritableRaster(bmodel, bbuf, new Point(0, 0));
      bimg = new BufferedImage(ccm, raster, false, new Hashtable());
    } else if (pixels instanceof byte[]
        && data.getElementWidth() == 1) { // Assume gray scale model?
      byte[] arr = (byte[]) pixels;
      byte[] barray = new byte[arr.length * 3];
      int k = 0;
      for (int j = 0; j < arr.length; j++) {
        byte l = arr[j];
        barray[k++] = l;
        barray[k++] = l;
        barray[k++] = l;
      }
      ColorModel ccm =
          new ComponentColorModel(
              ICC_ColorSpace.getInstance(ICC_ColorSpace.CS_sRGB),
              new int[] {8, 8, 8},
              false,
              false,
              Transparency.OPAQUE,
              DataBuffer.TYPE_BYTE);
      DataBuffer bbuf = new DataBufferByte(barray, barray.length);
      SampleModel bmodel =
          new PixelInterleavedSampleModel(
              DataBuffer.TYPE_BYTE, width, height, 3, 3 * width, new int[] {2, 1, 0});

      WritableRaster raster = Raster.createWritableRaster(bmodel, bbuf, new Point(0, 0));
      bimg = new BufferedImage(ccm, raster, false, new Hashtable());
    } else {
      throw new RuntimeException("Unexpected data.");
    }
    return bimg;
  }
Exemple #2
0
 // returns a value specifying some kind of average brightness in the image.
 protected int getAverageBrightness(BufferedImage img) {
   Raster r = img.getData();
   int total = 0;
   for (int y = 0; y < r.getHeight(); y++) {
     for (int x = 0; x < r.getWidth(); x++) {
       total += r.getSample(r.getMinX() + x, r.getMinY() + y, 0);
     }
   }
   return (int) (total / ((r.getWidth() / factorD) * (r.getHeight() / factorD)));
 }
Exemple #3
0
  public void decode() throws IOException {
    readTagDescriptors();

    final MessageDigest md;
    try {
      md = MessageDigest.getInstance("SHA-512");
    } catch (NoSuchAlgorithmException e) {
      e.printStackTrace();
      return;
    }

    final ComponentColorModel colorModel =
        new ComponentColorModel(
            ColorSpace.getInstance(ColorSpace.CS_sRGB),
            true,
            false,
            Transparency.TRANSLUCENT,
            DataBuffer.TYPE_BYTE);
    final int[] bandOffsets = {2, 1, 0, 3};
    final Map<String, String> duplicateGuard = new HashMap<String, String>();
    final byte[] bytes = data.array();
    final int[] tags = new int[8];

    final List<String> symLinkCommand = new ArrayList<String>(4);
    symLinkCommand.add("ln");
    symLinkCommand.add("-s");
    symLinkCommand.add(null);
    symLinkCommand.add(null);

    for (int fileIndex = 0; fileIndex < fileCount; fileIndex++) {
      data.position(fileDescriptorsOffset + ((4 + 8) * fileIndex));
      final int fileDataOffset = data.getInt();
      int numOfTags = 8;
      for (int i = 0; i < 8; i++) {
        int tag = data.get() & 0xff;
        if (tag == 0) {
          numOfTags = i;
          break;
        }
        tags[i] = tag;
      }

      data.position(fileDataSectionOffset + fileDataOffset);
      final int artRows = data.getShort();
      final int artColumns = data.getShort();
      // skip unknown
      data.position(data.position() + 28);

      final int[] subimageOffsets = readNumericArray(9, false);
      final int[] subimageWidths = readNumericArray(9, true);
      final int[] subimageHeights = readNumericArray(9, true);

      assert numOfTags >= 2;
      final File dir;
      final int tagStartIndexForFilename;
      if (numOfTags == 2) {
        tagStartIndexForFilename = 1;
        dir = new File(outputDir, names[tags[0]].toString());
      } else {
        tagStartIndexForFilename = 2;
        dir = new File(outputDir, names[tags[0]] + "/" + names[tags[1]]);
      }

      boolean dirCreated = false;

      final int imageCount = artRows * artColumns;
      for (int subImageIndex = 0; subImageIndex < imageCount; subImageIndex++) {
        final int w = subimageWidths[subImageIndex];
        final int h = subimageHeights[subImageIndex];
        if (w <= 0 || h <= 0) {
          continue;
        }

        final int srcPos = fileDataSectionOffset + fileDataOffset + subimageOffsets[subImageIndex];
        final int srcLength = w * h * 4;

        md.update(bytes, srcPos, srcLength);
        md.update((byte) w);
        md.update((byte) h);
        final String digest = convertToHex(md.digest());
        md.reset();

        if (!dirCreated) {
          //noinspection ResultOfMethodCallIgnored
          dir.mkdirs();
          dirCreated = true;
        }

        final byte[] bgra = new byte[srcLength];
        // cannot pass bytes directly, offset in DataBufferByte is not working
        System.arraycopy(bytes, srcPos, bgra, 0, bgra.length);
        BufferedImage image =
            new BufferedImage(
                colorModel,
                (WritableRaster)
                    Raster.createRaster(
                        new PixelInterleavedSampleModel(
                            DataBuffer.TYPE_BYTE, w, h, 4, w * 4, bandOffsets),
                        new DataBufferByte(bgra, bgra.length),
                        null),
                false,
                null);

        final StringBuilder outFilename =
            createOutpuFile(
                numOfTags, tags, tagStartIndexForFilename, imageCount > 0, subImageIndex);
        final String oldOutFilename = duplicateGuard.get(digest);
        if (oldOutFilename == null) {
          File file = new File(dir, outFilename.toString());
          duplicateGuard.put(digest, file.getPath());
          ImageIO.write(image, "png", file);
        } else {
          symLinkCommand.set(2, oldOutFilename);
          symLinkCommand.set(3, dir + "/" + outFilename);
          Process process = new ProcessBuilder(symLinkCommand).start();
          try {
            if (process.waitFor() != 0) {
              throw new IOException(
                  "Can't create symlink " + symLinkCommand.get(2) + " " + symLinkCommand.get(3));
            }
          } catch (InterruptedException e) {
            throw new IOException(e);
          }
        }
      }
    }
  }
  public void build_bricks() {

    ImagePlus imp;
    ImagePlus orgimp;
    ImageStack stack;
    FileInfo finfo;

    if (lvImgTitle.isEmpty()) return;
    orgimp = WindowManager.getImage(lvImgTitle.get(0));
    imp = orgimp;

    finfo = imp.getFileInfo();
    if (finfo == null) return;

    int[] dims = imp.getDimensions();
    int imageW = dims[0];
    int imageH = dims[1];
    int nCh = dims[2];
    int imageD = dims[3];
    int nFrame = dims[4];
    int bdepth = imp.getBitDepth();
    double xspc = finfo.pixelWidth;
    double yspc = finfo.pixelHeight;
    double zspc = finfo.pixelDepth;
    double z_aspect = Math.max(xspc, yspc) / zspc;

    int orgW = imageW;
    int orgH = imageH;
    int orgD = imageD;
    double orgxspc = xspc;
    double orgyspc = yspc;
    double orgzspc = zspc;

    lv = lvImgTitle.size();
    if (filetype == "JPEG") {
      for (int l = 0; l < lv; l++) {
        if (WindowManager.getImage(lvImgTitle.get(l)).getBitDepth() != 8) {
          IJ.error("A SOURCE IMAGE MUST BE 8BIT GLAYSCALE");
          return;
        }
      }
    }

    // calculate levels
    /*		int baseXY = 256;
    		int baseZ = 256;

    		if (z_aspect < 0.5) baseZ = 128;
    		if (z_aspect > 2.0) baseXY = 128;
    		if (z_aspect >= 0.5 && z_aspect < 1.0) baseZ = (int)(baseZ*z_aspect);
    		if (z_aspect > 1.0 && z_aspect <= 2.0) baseXY = (int)(baseXY/z_aspect);

    		IJ.log("Z_aspect: " + z_aspect);
    		IJ.log("BaseXY: " + baseXY);
    		IJ.log("BaseZ: " + baseZ);
    */

    int baseXY = 256;
    int baseZ = 128;
    int dbXY = Math.max(orgW, orgH) / baseXY;
    if (Math.max(orgW, orgH) % baseXY > 0) dbXY *= 2;
    int dbZ = orgD / baseZ;
    if (orgD % baseZ > 0) dbZ *= 2;
    lv = Math.max(log2(dbXY), log2(dbZ)) + 1;

    int ww = orgW;
    int hh = orgH;
    int dd = orgD;
    for (int l = 0; l < lv; l++) {
      int bwnum = ww / baseXY;
      if (ww % baseXY > 0) bwnum++;
      int bhnum = hh / baseXY;
      if (hh % baseXY > 0) bhnum++;
      int bdnum = dd / baseZ;
      if (dd % baseZ > 0) bdnum++;

      if (bwnum % 2 == 0) bwnum++;
      if (bhnum % 2 == 0) bhnum++;
      if (bdnum % 2 == 0) bdnum++;

      int bw = (bwnum <= 1) ? ww : ww / bwnum + 1 + (ww % bwnum > 0 ? 1 : 0);
      int bh = (bhnum <= 1) ? hh : hh / bhnum + 1 + (hh % bhnum > 0 ? 1 : 0);
      int bd = (bdnum <= 1) ? dd : dd / bdnum + 1 + (dd % bdnum > 0 ? 1 : 0);

      bwlist.add(bw);
      bhlist.add(bh);
      bdlist.add(bd);

      IJ.log("LEVEL: " + l);
      IJ.log("  width: " + ww);
      IJ.log("  hight: " + hh);
      IJ.log("  depth: " + dd);
      IJ.log("  bw: " + bw);
      IJ.log("  bh: " + bh);
      IJ.log("  bd: " + bd);

      int xyl2 = Math.max(ww, hh) / baseXY;
      if (Math.max(ww, hh) % baseXY > 0) xyl2 *= 2;
      if (lv - 1 - log2(xyl2) <= l) {
        ww /= 2;
        hh /= 2;
      }
      IJ.log("  xyl2: " + (lv - 1 - log2(xyl2)));

      int zl2 = dd / baseZ;
      if (dd % baseZ > 0) zl2 *= 2;
      if (lv - 1 - log2(zl2) <= l) dd /= 2;
      IJ.log("  zl2: " + (lv - 1 - log2(zl2)));

      if (l < lv - 1) {
        lvImgTitle.add(lvImgTitle.get(0) + "_level" + (l + 1));
        IJ.selectWindow(lvImgTitle.get(0));
        IJ.run(
            "Scale...",
            "x=- y=- z=- width="
                + ww
                + " height="
                + hh
                + " depth="
                + dd
                + " interpolation=Bicubic average process create title="
                + lvImgTitle.get(l + 1));
      }
    }

    for (int l = 0; l < lv; l++) {
      IJ.log(lvImgTitle.get(l));
    }

    Document doc = newXMLDocument();
    Element root = doc.createElement("BRK");
    root.setAttribute("version", "1.0");
    root.setAttribute("nLevel", String.valueOf(lv));
    root.setAttribute("nChannel", String.valueOf(nCh));
    root.setAttribute("nFrame", String.valueOf(nFrame));
    doc.appendChild(root);

    for (int l = 0; l < lv; l++) {
      IJ.showProgress(0.0);

      int[] dims2 = imp.getDimensions();
      IJ.log(
          "W: "
              + String.valueOf(dims2[0])
              + " H: "
              + String.valueOf(dims2[1])
              + " C: "
              + String.valueOf(dims2[2])
              + " D: "
              + String.valueOf(dims2[3])
              + " T: "
              + String.valueOf(dims2[4])
              + " b: "
              + String.valueOf(bdepth));

      bw = bwlist.get(l).intValue();
      bh = bhlist.get(l).intValue();
      bd = bdlist.get(l).intValue();

      boolean force_pow2 = false;
      /*			if(IsPowerOf2(bw) && IsPowerOf2(bh) && IsPowerOf2(bd)) force_pow2 = true;

      			if(force_pow2){
      				//force pow2
      				if(Pow2(bw) > bw) bw = Pow2(bw)/2;
      				if(Pow2(bh) > bh) bh = Pow2(bh)/2;
      				if(Pow2(bd) > bd) bd = Pow2(bd)/2;
      			}

      			if(bw > imageW) bw = (Pow2(imageW) == imageW) ? imageW : Pow2(imageW)/2;
      			if(bh > imageH) bh = (Pow2(imageH) == imageH) ? imageH : Pow2(imageH)/2;
      			if(bd > imageD) bd = (Pow2(imageD) == imageD) ? imageD : Pow2(imageD)/2;

      */
      if (bw > imageW) bw = imageW;
      if (bh > imageH) bh = imageH;
      if (bd > imageD) bd = imageD;

      if (bw <= 1 || bh <= 1 || bd <= 1) break;

      if (filetype == "JPEG" && (bw < 8 || bh < 8)) break;

      Element lvnode = doc.createElement("Level");
      lvnode.setAttribute("lv", String.valueOf(l));
      lvnode.setAttribute("imageW", String.valueOf(imageW));
      lvnode.setAttribute("imageH", String.valueOf(imageH));
      lvnode.setAttribute("imageD", String.valueOf(imageD));
      lvnode.setAttribute("xspc", String.valueOf(xspc));
      lvnode.setAttribute("yspc", String.valueOf(yspc));
      lvnode.setAttribute("zspc", String.valueOf(zspc));
      lvnode.setAttribute("bitDepth", String.valueOf(bdepth));
      root.appendChild(lvnode);

      Element brksnode = doc.createElement("Bricks");
      brksnode.setAttribute("brick_baseW", String.valueOf(bw));
      brksnode.setAttribute("brick_baseH", String.valueOf(bh));
      brksnode.setAttribute("brick_baseD", String.valueOf(bd));
      lvnode.appendChild(brksnode);

      ArrayList<Brick> bricks = new ArrayList<Brick>();
      int mw, mh, md, mw2, mh2, md2;
      double tx0, ty0, tz0, tx1, ty1, tz1;
      double bx0, by0, bz0, bx1, by1, bz1;
      for (int k = 0; k < imageD; k += bd) {
        if (k > 0) k--;
        for (int j = 0; j < imageH; j += bh) {
          if (j > 0) j--;
          for (int i = 0; i < imageW; i += bw) {
            if (i > 0) i--;
            mw = Math.min(bw, imageW - i);
            mh = Math.min(bh, imageH - j);
            md = Math.min(bd, imageD - k);

            if (force_pow2) {
              mw2 = Pow2(mw);
              mh2 = Pow2(mh);
              md2 = Pow2(md);
            } else {
              mw2 = mw;
              mh2 = mh;
              md2 = md;
            }

            if (filetype == "JPEG") {
              if (mw2 < 8) mw2 = 8;
              if (mh2 < 8) mh2 = 8;
            }

            tx0 = i == 0 ? 0.0d : ((mw2 - mw + 0.5d) / mw2);
            ty0 = j == 0 ? 0.0d : ((mh2 - mh + 0.5d) / mh2);
            tz0 = k == 0 ? 0.0d : ((md2 - md + 0.5d) / md2);

            tx1 = 1.0d - 0.5d / mw2;
            if (mw < bw) tx1 = 1.0d;
            if (imageW - i == bw) tx1 = 1.0d;

            ty1 = 1.0d - 0.5d / mh2;
            if (mh < bh) ty1 = 1.0d;
            if (imageH - j == bh) ty1 = 1.0d;

            tz1 = 1.0d - 0.5d / md2;
            if (md < bd) tz1 = 1.0d;
            if (imageD - k == bd) tz1 = 1.0d;

            bx0 = i == 0 ? 0.0d : (i + 0.5d) / (double) imageW;
            by0 = j == 0 ? 0.0d : (j + 0.5d) / (double) imageH;
            bz0 = k == 0 ? 0.0d : (k + 0.5d) / (double) imageD;

            bx1 = Math.min((i + bw - 0.5d) / (double) imageW, 1.0d);
            if (imageW - i == bw) bx1 = 1.0d;

            by1 = Math.min((j + bh - 0.5d) / (double) imageH, 1.0d);
            if (imageH - j == bh) by1 = 1.0d;

            bz1 = Math.min((k + bd - 0.5d) / (double) imageD, 1.0d);
            if (imageD - k == bd) bz1 = 1.0d;

            int x, y, z;
            x = i - (mw2 - mw);
            y = j - (mh2 - mh);
            z = k - (md2 - md);
            bricks.add(
                new Brick(
                    x, y, z, mw2, mh2, md2, 0, 0, tx0, ty0, tz0, tx1, ty1, tz1, bx0, by0, bz0, bx1,
                    by1, bz1));
          }
        }
      }

      Element fsnode = doc.createElement("Files");
      lvnode.appendChild(fsnode);

      stack = imp.getStack();

      int totalbricknum = nFrame * nCh * bricks.size();
      int curbricknum = 0;
      for (int f = 0; f < nFrame; f++) {
        for (int ch = 0; ch < nCh; ch++) {
          int sizelimit = bdsizelimit * 1024 * 1024;
          int bytecount = 0;
          int filecount = 0;
          int pd_bufsize = Math.max(sizelimit, bw * bh * bd * bdepth / 8);
          byte[] packed_data = new byte[pd_bufsize];
          String base_dataname =
              basename
                  + "_Lv"
                  + String.valueOf(l)
                  + "_Ch"
                  + String.valueOf(ch)
                  + "_Fr"
                  + String.valueOf(f);
          String current_dataname = base_dataname + "_data" + filecount;

          Brick b_first = bricks.get(0);
          if (b_first.z_ != 0) IJ.log("warning");
          int st_z = b_first.z_;
          int ed_z = b_first.z_ + b_first.d_;
          LinkedList<ImageProcessor> iplist = new LinkedList<ImageProcessor>();
          for (int s = st_z; s < ed_z; s++)
            iplist.add(stack.getProcessor(imp.getStackIndex(ch + 1, s + 1, f + 1)));

          //					ImagePlus test;
          //					ImageStack tsst;
          //					test = NewImage.createByteImage("test", imageW, imageH, imageD,
          // NewImage.FILL_BLACK);
          //					tsst = test.getStack();
          for (int i = 0; i < bricks.size(); i++) {
            Brick b = bricks.get(i);

            if (ed_z > b.z_ || st_z < b.z_ + b.d_) {
              if (b.z_ > st_z) {
                for (int s = 0; s < b.z_ - st_z; s++) iplist.pollFirst();
                st_z = b.z_;
              } else if (b.z_ < st_z) {
                IJ.log("warning");
                for (int s = st_z - 1; s > b.z_; s--)
                  iplist.addFirst(stack.getProcessor(imp.getStackIndex(ch + 1, s + 1, f + 1)));
                st_z = b.z_;
              }

              if (b.z_ + b.d_ > ed_z) {
                for (int s = ed_z; s < b.z_ + b.d_; s++)
                  iplist.add(stack.getProcessor(imp.getStackIndex(ch + 1, s + 1, f + 1)));
                ed_z = b.z_ + b.d_;
              } else if (b.z_ + b.d_ < ed_z) {
                IJ.log("warning");
                for (int s = 0; s < ed_z - (b.z_ + b.d_); s++) iplist.pollLast();
                ed_z = b.z_ + b.d_;
              }
            } else {
              IJ.log("warning");
              iplist.clear();
              st_z = b.z_;
              ed_z = b.z_ + b.d_;
              for (int s = st_z; s < ed_z; s++)
                iplist.add(stack.getProcessor(imp.getStackIndex(ch + 1, s + 1, f + 1)));
            }

            if (iplist.size() != b.d_) {
              IJ.log("Stack Error");
              return;
            }

            //						int zz = st_z;

            int bsize = 0;
            byte[] bdata = new byte[b.w_ * b.h_ * b.d_ * bdepth / 8];
            Iterator<ImageProcessor> ipite = iplist.iterator();
            while (ipite.hasNext()) {

              //							ImageProcessor tsip = tsst.getProcessor(zz+1);

              ImageProcessor ip = ipite.next();
              ip.setRoi(b.x_, b.y_, b.w_, b.h_);
              if (bdepth == 8) {
                byte[] data = (byte[]) ip.crop().getPixels();
                System.arraycopy(data, 0, bdata, bsize, data.length);
                bsize += data.length;
              } else if (bdepth == 16) {
                ByteBuffer buffer = ByteBuffer.allocate(b.w_ * b.h_ * bdepth / 8);
                buffer.order(ByteOrder.LITTLE_ENDIAN);
                short[] data = (short[]) ip.crop().getPixels();
                for (short e : data) buffer.putShort(e);
                System.arraycopy(buffer.array(), 0, bdata, bsize, buffer.array().length);
                bsize += buffer.array().length;
              } else if (bdepth == 32) {
                ByteBuffer buffer = ByteBuffer.allocate(b.w_ * b.h_ * bdepth / 8);
                buffer.order(ByteOrder.LITTLE_ENDIAN);
                float[] data = (float[]) ip.crop().getPixels();
                for (float e : data) buffer.putFloat(e);
                System.arraycopy(buffer.array(), 0, bdata, bsize, buffer.array().length);
                bsize += buffer.array().length;
              }
            }

            String filename =
                basename
                    + "_Lv"
                    + String.valueOf(l)
                    + "_Ch"
                    + String.valueOf(ch)
                    + "_Fr"
                    + String.valueOf(f)
                    + "_ID"
                    + String.valueOf(i);

            int offset = bytecount;
            int datasize = bdata.length;

            if (filetype == "RAW") {
              int dummy = -1;
              // do nothing
            }
            if (filetype == "JPEG" && bdepth == 8) {
              try {
                DataBufferByte db = new DataBufferByte(bdata, datasize);
                Raster raster = Raster.createPackedRaster(db, b.w_, b.h_ * b.d_, 8, null);
                BufferedImage img =
                    new BufferedImage(b.w_, b.h_ * b.d_, BufferedImage.TYPE_BYTE_GRAY);
                img.setData(raster);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ImageOutputStream ios = ImageIO.createImageOutputStream(baos);
                String format = "jpg";
                Iterator<javax.imageio.ImageWriter> iter =
                    ImageIO.getImageWritersByFormatName("jpeg");
                javax.imageio.ImageWriter writer = iter.next();
                ImageWriteParam iwp = writer.getDefaultWriteParam();
                iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
                iwp.setCompressionQuality((float) jpeg_quality * 0.01f);
                writer.setOutput(ios);
                writer.write(null, new IIOImage(img, null, null), iwp);
                // ImageIO.write(img, format, baos);
                bdata = baos.toByteArray();
                datasize = bdata.length;
              } catch (IOException e) {
                e.printStackTrace();
                return;
              }
            }
            if (filetype == "ZLIB") {
              byte[] tmpdata = new byte[b.w_ * b.h_ * b.d_ * bdepth / 8];
              Deflater compresser = new Deflater();
              compresser.setInput(bdata);
              compresser.setLevel(Deflater.DEFAULT_COMPRESSION);
              compresser.setStrategy(Deflater.DEFAULT_STRATEGY);
              compresser.finish();
              datasize = compresser.deflate(tmpdata);
              bdata = tmpdata;
              compresser.end();
            }

            if (bytecount + datasize > sizelimit && bytecount > 0) {
              BufferedOutputStream fis = null;
              try {
                File file = new File(directory + current_dataname);
                fis = new BufferedOutputStream(new FileOutputStream(file));
                fis.write(packed_data, 0, bytecount);
              } catch (IOException e) {
                e.printStackTrace();
                return;
              } finally {
                try {
                  if (fis != null) fis.close();
                } catch (IOException e) {
                  e.printStackTrace();
                  return;
                }
              }
              filecount++;
              current_dataname = base_dataname + "_data" + filecount;
              bytecount = 0;
              offset = 0;
              System.arraycopy(bdata, 0, packed_data, bytecount, datasize);
              bytecount += datasize;
            } else {
              System.arraycopy(bdata, 0, packed_data, bytecount, datasize);
              bytecount += datasize;
            }

            Element filenode = doc.createElement("File");
            filenode.setAttribute("filename", current_dataname);
            filenode.setAttribute("channel", String.valueOf(ch));
            filenode.setAttribute("frame", String.valueOf(f));
            filenode.setAttribute("brickID", String.valueOf(i));
            filenode.setAttribute("offset", String.valueOf(offset));
            filenode.setAttribute("datasize", String.valueOf(datasize));
            filenode.setAttribute("filetype", String.valueOf(filetype));

            fsnode.appendChild(filenode);

            curbricknum++;
            IJ.showProgress((double) (curbricknum) / (double) (totalbricknum));
          }
          if (bytecount > 0) {
            BufferedOutputStream fis = null;
            try {
              File file = new File(directory + current_dataname);
              fis = new BufferedOutputStream(new FileOutputStream(file));
              fis.write(packed_data, 0, bytecount);
            } catch (IOException e) {
              e.printStackTrace();
              return;
            } finally {
              try {
                if (fis != null) fis.close();
              } catch (IOException e) {
                e.printStackTrace();
                return;
              }
            }
          }
        }
      }

      for (int i = 0; i < bricks.size(); i++) {
        Brick b = bricks.get(i);
        Element bricknode = doc.createElement("Brick");
        bricknode.setAttribute("id", String.valueOf(i));
        bricknode.setAttribute("st_x", String.valueOf(b.x_));
        bricknode.setAttribute("st_y", String.valueOf(b.y_));
        bricknode.setAttribute("st_z", String.valueOf(b.z_));
        bricknode.setAttribute("width", String.valueOf(b.w_));
        bricknode.setAttribute("height", String.valueOf(b.h_));
        bricknode.setAttribute("depth", String.valueOf(b.d_));
        brksnode.appendChild(bricknode);

        Element tboxnode = doc.createElement("tbox");
        tboxnode.setAttribute("x0", String.valueOf(b.tx0_));
        tboxnode.setAttribute("y0", String.valueOf(b.ty0_));
        tboxnode.setAttribute("z0", String.valueOf(b.tz0_));
        tboxnode.setAttribute("x1", String.valueOf(b.tx1_));
        tboxnode.setAttribute("y1", String.valueOf(b.ty1_));
        tboxnode.setAttribute("z1", String.valueOf(b.tz1_));
        bricknode.appendChild(tboxnode);

        Element bboxnode = doc.createElement("bbox");
        bboxnode.setAttribute("x0", String.valueOf(b.bx0_));
        bboxnode.setAttribute("y0", String.valueOf(b.by0_));
        bboxnode.setAttribute("z0", String.valueOf(b.bz0_));
        bboxnode.setAttribute("x1", String.valueOf(b.bx1_));
        bboxnode.setAttribute("y1", String.valueOf(b.by1_));
        bboxnode.setAttribute("z1", String.valueOf(b.bz1_));
        bricknode.appendChild(bboxnode);
      }

      if (l < lv - 1) {
        imp = WindowManager.getImage(lvImgTitle.get(l + 1));
        int[] newdims = imp.getDimensions();
        imageW = newdims[0];
        imageH = newdims[1];
        imageD = newdims[3];
        xspc = orgxspc * ((double) orgW / (double) imageW);
        yspc = orgyspc * ((double) orgH / (double) imageH);
        zspc = orgzspc * ((double) orgD / (double) imageD);
        bdepth = imp.getBitDepth();
      }
    }

    File newXMLfile = new File(directory + basename + ".vvd");
    writeXML(newXMLfile, doc);

    for (int l = 1; l < lv; l++) {
      imp = WindowManager.getImage(lvImgTitle.get(l));
      imp.changes = false;
      imp.close();
    }
  }
  /** Convert standard img to a buffered image. */
  public static BufferedImage convertImage(Image img) {
    int height = img.getHeight(null), width = img.getWidth(null);
    // FloatMatrix fm = new FloatMatrix( height, width ) ;
    PixelGrabber grabber = new PixelGrabber(img, 0, 0, width, height, false);
    try {
      grabber.grabPixels();
    } catch (InterruptedException e) {
      System.out.println(e);
    }
    Object pixels = grabber.getPixels();
    ColorModel cm = grabber.getColorModel();

    BufferedImage bimg = null;

    // REVISIT  Makes some unwarranted assumptions about the layout of the PixelGrabber data
    // as being either int (ARGB?) or byte (gray scale?)
    if (pixels instanceof int[]) {
      int[] arr = (int[]) pixels;
      byte[] barray = new byte[arr.length * 3];
      int k = 0;
      for (int j = 0; j < arr.length; j++) {
        int l = arr[j];
        barray[k++] = (byte) (l & 0xFF);
        barray[k++] = (byte) ((l >>> 8) & 0xFF);
        barray[k++] = (byte) ((l >>> 16) & 0xFF);
      }
      ColorModel ccm =
          new ComponentColorModel(
              ICC_ColorSpace.getInstance(ICC_ColorSpace.CS_sRGB),
              new int[] {8, 8, 8},
              false,
              false,
              Transparency.OPAQUE,
              DataBuffer.TYPE_BYTE);
      DataBuffer bbuf = new DataBufferByte(barray, barray.length);
      SampleModel bmodel =
          new PixelInterleavedSampleModel(
              DataBuffer.TYPE_BYTE, width, height, 3, 3 * width, new int[] {2, 1, 0});

      WritableRaster raster = Raster.createWritableRaster(bmodel, bbuf, new Point(0, 0));
      bimg = new BufferedImage(ccm, raster, false, new Hashtable());
    } else if (pixels instanceof byte[]) { // Assume gray scale model?
      byte[] arr = (byte[]) pixels;
      byte[] barray = new byte[arr.length * 3];
      int k = 0;
      for (int j = 0; j < arr.length; j++) {
        byte l = arr[j];
        barray[k++] = l;
        barray[k++] = l;
        barray[k++] = l;
      }
      ColorModel ccm =
          new ComponentColorModel(
              ICC_ColorSpace.getInstance(ICC_ColorSpace.CS_sRGB),
              new int[] {8, 8, 8},
              false,
              false,
              Transparency.OPAQUE,
              DataBuffer.TYPE_BYTE);
      DataBuffer bbuf = new DataBufferByte(barray, barray.length);
      SampleModel bmodel =
          new PixelInterleavedSampleModel(
              DataBuffer.TYPE_BYTE, width, height, 3, 3 * width, new int[] {2, 1, 0});

      WritableRaster raster = Raster.createWritableRaster(bmodel, bbuf, new Point(0, 0));
      bimg = new BufferedImage(ccm, raster, false, new Hashtable());
    } else {
      throw new RuntimeException("Unexpected data.");
    }
    return bimg;
  }
  /**
   * Loads PNG files and returns the result as an int[][]. The only PNG formats permitted are those
   * with up to 256 grays (including simple black and white) or indexed colors from an up to
   * 256-sized color table. Each integer value represents the gray level or the color table index
   * value of the pixel. The Y dimension is not flipped.
   */
  public static int[][] loadPNGFile(InputStream str) throws IOException {
    // read the bytes into a byte array
    BufferedInputStream stream = new BufferedInputStream(str);
    ArrayList list = new ArrayList();
    int count = 0;
    while (true) {
      byte[] buffer = new byte[16384 * 16];
      int len = stream.read(buffer);
      if (len <= 0) // all done
      break;
      else if (len < buffer.length) {
        byte[] buf2 = new byte[len];
        System.arraycopy(buffer, 0, buf2, 0, len);
        buffer = buf2;
      }
      count += len;
      list.add(buffer);
    }
    byte[] data = new byte[count];
    int cur = 0;
    for (int i = 0; i < list.size(); i++) {
      byte[] b = (byte[]) (list.get(i));
      System.arraycopy(b, 0, data, cur, b.length);
      cur += b.length;
    }

    // Next convert the byte array to a buffered image
    BufferedImage image = ((ToolkitImage) (new ImageIcon(data).getImage())).getBufferedImage();

    // Is the color model something we can use?
    int type = image.getType();
    if (type == BufferedImage.TYPE_BYTE_BINARY || type == BufferedImage.TYPE_BYTE_GRAY) {
      int w = image.getWidth();
      int h = image.getHeight();
      int[][] result = new int[w][h];
      // obviously this could be done more efficiently
      for (int i = 0; i < w; i++)
        for (int j = 0; j < h; j++) result[i][j] = (image.getRGB(i, j) & 0xFF);
      return result;
    } else if (type == BufferedImage.TYPE_BYTE_INDEXED) {
      Raster raster = image.getRaster();
      if (raster.getTransferType() != DataBuffer.TYPE_BYTE) // uh oh
      throw new IOException("Input Stream must contain an image with byte data if indexed.");
      byte[] pixel = new byte[1];
      int w = image.getWidth();
      int h = image.getHeight();
      int[][] result = new int[w][h];
      // obviously this could be done more efficiently
      for (int i = 0; i < w; i++)
        for (int j = 0; j < h; j++) {
          result[i][j] = ((byte[]) (raster.getDataElements(i, j, pixel)))[0];
          if (result[i][j] < 0) result[i][j] += 256;
        }
      return result;
    }
    // else if (type == TYPE_USHORT_GRAY)   // at present we don't handle shorts
    //    {
    //    }
    else
      throw new IOException(
          "Input Stream must contain a binary, byte-sized grayscale, or byte-sized indexed color scheme: "
              + image);
  }
  public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException {
    checkIndex(imageIndex);
    readHeader();

    if (iis == null) throw new IllegalStateException("input is null");

    BufferedImage img;

    clearAbortRequest();
    processImageStarted(imageIndex);

    if (param == null) param = getDefaultReadParam();

    sourceRegion = new Rectangle(0, 0, 0, 0);
    destinationRegion = new Rectangle(0, 0, 0, 0);

    computeRegions(
        param, this.width, this.height, param.getDestination(), sourceRegion, destinationRegion);

    scaleX = param.getSourceXSubsampling();
    scaleY = param.getSourceYSubsampling();

    // If the destination band is set used it
    sourceBands = param.getSourceBands();
    destBands = param.getDestinationBands();

    seleBand = (sourceBands != null) && (destBands != null);
    noTransform = destinationRegion.equals(new Rectangle(0, 0, width, height)) || seleBand;

    if (!seleBand) {
      sourceBands = new int[colorPlanes];
      destBands = new int[colorPlanes];
      for (int i = 0; i < colorPlanes; i++) destBands[i] = sourceBands[i] = i;
    }

    // If the destination is provided, then use it.  Otherwise, create new one
    bi = param.getDestination();

    // Get the image data.
    WritableRaster raster = null;

    if (bi == null) {
      if (sampleModel != null && colorModel != null) {
        sampleModel =
            sampleModel.createCompatibleSampleModel(
                destinationRegion.width + destinationRegion.x,
                destinationRegion.height + destinationRegion.y);
        if (seleBand) sampleModel = sampleModel.createSubsetSampleModel(sourceBands);
        raster = Raster.createWritableRaster(sampleModel, new Point(0, 0));
        bi = new BufferedImage(colorModel, raster, false, null);
      }
    } else {
      raster = bi.getWritableTile(0, 0);
      sampleModel = bi.getSampleModel();
      colorModel = bi.getColorModel();

      noTransform &= destinationRegion.equals(raster.getBounds());
    }

    byte bdata[] = null; // buffer for byte data

    if (sampleModel.getDataType() == DataBuffer.TYPE_BYTE)
      bdata = (byte[]) ((DataBufferByte) raster.getDataBuffer()).getData();

    readImage(bdata);

    if (abortRequested()) processReadAborted();
    else processImageComplete();

    return bi;
  }
  private void writeGrayscaleImage(BufferedImage image, AVList params) throws IOException {
    int type = image.getType();

    int bitsPerSample =
        (BufferedImage.TYPE_USHORT_GRAY == type)
            ? Tiff.BitsPerSample.MONOCHROME_UINT16
            : Tiff.BitsPerSample.MONOCHROME_UINT8;

    int numBands = image.getSampleModel().getNumBands();
    // well, numBands for GrayScale images must be 1

    int bytesPerSample = numBands * bitsPerSample / Byte.SIZE;

    this.writeTiffHeader();

    // write the image data...
    int numRows = image.getHeight();
    int numCols = image.getWidth();
    int[] stripCounts = new int[numRows];
    int[] stripOffsets = new int[numRows];
    ByteBuffer dataBuff = ByteBuffer.allocateDirect(numCols * bytesPerSample);
    Raster rast = image.getRaster();

    for (int i = 0; i < numRows; i++) {
      stripOffsets[i] = (int) this.theChannel.position();
      stripCounts[i] = numCols * bytesPerSample;
      int[] rowData = rast.getPixels(0, i, image.getWidth(), 1, (int[]) null);
      dataBuff.clear();

      if (BufferedImage.TYPE_USHORT_GRAY == type) {
        for (int j = 0; j < numCols * numBands; j++) {
          this.putUnsignedShort(dataBuff, rowData[j]);
        }
      } else if (BufferedImage.TYPE_BYTE_GRAY == type) {
        for (int j = 0; j < numCols * numBands; j++) {
          this.putUnsignedByte(dataBuff, rowData[j]);
        }
      }
      dataBuff.flip();
      this.theChannel.write(dataBuff);
    }

    // write out values for the tiff tags and build up the IFD. These are supposed to be sorted; for
    // now
    // do this manually here.
    ArrayList<TiffIFDEntry> ifds = new ArrayList<TiffIFDEntry>(10);

    ifds.add(new TiffIFDEntry(Tiff.Tag.IMAGE_WIDTH, Tiff.Type.LONG, 1, numCols));
    ifds.add(new TiffIFDEntry(Tiff.Tag.IMAGE_LENGTH, Tiff.Type.LONG, 1, numRows));
    ifds.add(new TiffIFDEntry(Tiff.Tag.BITS_PER_SAMPLE, Tiff.Type.SHORT, 1, bitsPerSample));
    ifds.add(new TiffIFDEntry(Tiff.Tag.COMPRESSION, Tiff.Type.LONG, 1, Tiff.Compression.NONE));
    ifds.add(
        new TiffIFDEntry(
            Tiff.Tag.PHOTO_INTERPRETATION,
            Tiff.Type.SHORT,
            1,
            Tiff.Photometric.Grayscale_BlackIsZero));
    ifds.add(
        new TiffIFDEntry(Tiff.Tag.SAMPLE_FORMAT, Tiff.Type.SHORT, 1, Tiff.SampleFormat.UNSIGNED));

    long offset = this.theChannel.position();
    dataBuff = ByteBuffer.allocateDirect(stripOffsets.length * INTEGER_SIZEOF);
    for (int stripOffset : stripOffsets) {
      dataBuff.putInt(stripOffset);
    }
    dataBuff.flip();
    this.theChannel.write(dataBuff);
    ifds.add(new TiffIFDEntry(Tiff.Tag.STRIP_OFFSETS, Tiff.Type.LONG, stripOffsets.length, offset));

    ifds.add(new TiffIFDEntry(Tiff.Tag.SAMPLES_PER_PIXEL, Tiff.Type.SHORT, 1, numBands));
    ifds.add(new TiffIFDEntry(Tiff.Tag.ROWS_PER_STRIP, Tiff.Type.LONG, 1, 1));

    offset = this.theChannel.position();
    dataBuff.clear(); // stripOffsets and stripCounts are same length by design; can reuse the
    // ByteBuffer...

    for (int stripCount : stripCounts) {
      dataBuff.putInt(stripCount);
    }
    dataBuff.flip();
    this.theChannel.write(dataBuff);
    ifds.add(
        new TiffIFDEntry(Tiff.Tag.STRIP_BYTE_COUNTS, Tiff.Type.LONG, stripCounts.length, offset));

    this.appendGeoTiff(ifds, params);

    this.writeIFDs(ifds);
  }
  private void writeColorImage(BufferedImage image, AVList params) throws IOException {
    int numBands = image.getRaster().getNumBands();
    long offset;

    this.writeTiffHeader();

    // write the image data...
    int numRows = image.getHeight();
    int numCols = image.getWidth();
    int[] stripCounts = new int[numRows];
    int[] stripOffsets = new int[numRows];
    ByteBuffer dataBuff = ByteBuffer.allocateDirect(numCols * numBands);
    Raster rast = image.getRaster();

    for (int i = 0; i < numRows; i++) {
      stripOffsets[i] = (int) this.theChannel.position();
      stripCounts[i] = numCols * numBands;
      int[] rowData = rast.getPixels(0, i, image.getWidth(), 1, (int[]) null);
      dataBuff.clear();
      for (int j = 0; j < numCols * numBands; j++) {
        putUnsignedByte(dataBuff, rowData[j]);
      }
      dataBuff.flip();
      this.theChannel.write(dataBuff);
    }

    // write out values for the tiff tags and build up the IFD. These are supposed to be sorted; for
    // now
    // do this manually here.
    ArrayList<TiffIFDEntry> ifds = new ArrayList<TiffIFDEntry>(10);

    ifds.add(new TiffIFDEntry(Tiff.Tag.IMAGE_WIDTH, Tiff.Type.LONG, 1, numCols));
    ifds.add(new TiffIFDEntry(Tiff.Tag.IMAGE_LENGTH, Tiff.Type.LONG, 1, numRows));

    ifds.add(
        new TiffIFDEntry(
            Tiff.Tag.PLANAR_CONFIGURATION, Tiff.Type.SHORT, 1, Tiff.PlanarConfiguration.CHUNKY));
    ifds.add(new TiffIFDEntry(Tiff.Tag.SAMPLES_PER_PIXEL, Tiff.Type.SHORT, 1, numBands));
    ifds.add(new TiffIFDEntry(Tiff.Tag.COMPRESSION, Tiff.Type.LONG, 1, Tiff.Compression.NONE));
    ifds.add(
        new TiffIFDEntry(
            Tiff.Tag.PHOTO_INTERPRETATION, Tiff.Type.SHORT, 1, Tiff.Photometric.Color_RGB));

    ifds.add(new TiffIFDEntry(Tiff.Tag.ORIENTATION, Tiff.Type.SHORT, 1, Tiff.Orientation.DEFAULT));

    offset = this.theChannel.position();

    short[] bps = new short[numBands];
    for (int i = 0; i < numBands; i++) {
      bps[i] = Tiff.BitsPerSample.MONOCHROME_BYTE;
    }
    this.theChannel.write(ByteBuffer.wrap(this.getBytes(bps)));
    ifds.add(new TiffIFDEntry(Tiff.Tag.BITS_PER_SAMPLE, Tiff.Type.SHORT, numBands, offset));

    offset = this.theChannel.position();
    dataBuff = ByteBuffer.allocateDirect(stripOffsets.length * INTEGER_SIZEOF);
    for (int stripOffset : stripOffsets) {
      dataBuff.putInt(stripOffset);
    }
    dataBuff.flip();
    this.theChannel.write(dataBuff);
    ifds.add(new TiffIFDEntry(Tiff.Tag.STRIP_OFFSETS, Tiff.Type.LONG, stripOffsets.length, offset));
    ifds.add(new TiffIFDEntry(Tiff.Tag.ROWS_PER_STRIP, Tiff.Type.LONG, 1, 1));

    offset = this.theChannel.position();
    dataBuff.clear();
    // stripOffsets and stripCounts are same length by design; can reuse the ByteBuffer...
    for (int stripCount : stripCounts) {
      dataBuff.putInt(stripCount);
    }
    dataBuff.flip();
    this.theChannel.write(dataBuff);
    ifds.add(
        new TiffIFDEntry(Tiff.Tag.STRIP_BYTE_COUNTS, Tiff.Type.LONG, stripCounts.length, offset));

    this.appendGeoTiff(ifds, params);

    this.writeIFDs(ifds);
  }