Package ca.eandb.jmist.framework.loader.openexr

Source Code of ca.eandb.jmist.framework.loader.openexr.OpenEXRImage

/**
* Java Modular Image Synthesis Toolkit (JMIST)
* Copyright (C) 2008-2013 Bradley W. Kimmel
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package ca.eandb.jmist.framework.loader.openexr;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.stream.FileImageInputStream;
import javax.imageio.stream.FileImageOutputStream;
import javax.imageio.stream.IIOByteBuffer;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;

import ca.eandb.jmist.framework.color.RGB;
import ca.eandb.jmist.framework.loader.openexr.attribute.Attribute;
import ca.eandb.jmist.framework.loader.openexr.attribute.AttributeFactory;
import ca.eandb.jmist.framework.loader.openexr.attribute.Box2i;
import ca.eandb.jmist.framework.loader.openexr.attribute.Channel;
import ca.eandb.jmist.framework.loader.openexr.attribute.ChannelList;
import ca.eandb.jmist.framework.loader.openexr.attribute.CompressionMethod;
import ca.eandb.jmist.framework.loader.openexr.attribute.FloatAttribute;
import ca.eandb.jmist.framework.loader.openexr.attribute.LineOrder;
import ca.eandb.jmist.framework.loader.openexr.attribute.OpenEXRAttributeType;
import ca.eandb.jmist.framework.loader.openexr.attribute.PixelType;
import ca.eandb.jmist.framework.loader.openexr.attribute.TileDescription;
import ca.eandb.jmist.framework.loader.openexr.attribute.TileDescription.RoundingMode;
import ca.eandb.jmist.framework.loader.openexr.attribute.V2f;
import ca.eandb.jmist.framework.loader.openexr.attribute.V2i;
import ca.eandb.jmist.math.MathUtil;
import ca.eandb.util.UnexpectedException;
import ca.eandb.util.UnimplementedException;
import ca.eandb.util.io.StreamUtil;

/**
* @author brad
*
*/
public final class OpenEXRImage {

  private static final int MAGIC = 20000630;

  private static final int TILE_FLAG = 0x0200;

  private static final int VERSION_MASK = 0xff;

  private static final int VERSION = 2;

  private static final Map<String, Class<?>> ATTRIBUTE_TYPES;
  static
  {
    Map<String, Class<?>> types = new HashMap<String, Class<?>>();
    types.put("channels", ChannelList.class);
    types.put("compression", CompressionMethod.class);
    types.put("dataWindow", Box2i.class);
    types.put("displayWindow", Box2i.class);
    types.put("lineOrder", LineOrder.class);
    types.put("pixelAspectRatio", FloatAttribute.class);
    types.put("screenWindowCenter", V2f.class);
    types.put("screenWindowWidth", FloatAttribute.class);
    ATTRIBUTE_TYPES = Collections.unmodifiableMap(types);
  }

  private final Map<String, Attribute> attributes = new HashMap<String, Attribute>();

  private final Map<String, Buffer> data = new HashMap<String, Buffer>();

  public OpenEXRImage(int w, int h) {
    this(new Box2i(0, 0, w - 1, h - 1));
  }

  public OpenEXRImage(Box2i dataWindow) {
    this(dataWindow, dataWindow);
  }

  public OpenEXRImage(Box2i dataWindow, Box2i displayWindow) {
    attributes.put("channels", new ChannelList());
    attributes.put("compression", CompressionMethod.NONE);
    attributes.put("dataWindow", dataWindow);
    attributes.put("displayWindow", displayWindow);
    attributes.put("lineOrder", LineOrder.INCREASING_Y);
    attributes.put("pixelAspectRatio", new FloatAttribute(1.0f));
    attributes.put("screenWindowCenter", new V2f(0.0f, 0.0f));
    attributes.put("screenWindowWidth", new FloatAttribute(1.0f));
  }

  private OpenEXRImage(ImageInputStream source) throws IOException {

    FileOutputStream f = new FileOutputStream("/home/brad/test.dat");
    source.setByteOrder(ByteOrder.LITTLE_ENDIAN);

    if (source.readInt() != MAGIC) {
      throw new IOException("Unrecognized format");
    }
    int version = source.readInt();
    boolean tiled = (version & TILE_FLAG) != 0;

    version &= VERSION_MASK;
    if (version != VERSION) {
      throw new IOException("Unsupported version");
    }

    source.flush();

    AttributeFactory factory = AttributeFactory.getInstance();

    while (true) {
      String name = StreamUtil.readNullTerminatedString(source);
      if (name.isEmpty()) {
        break;
      }

      String type = StreamUtil.readNullTerminatedString(source);
      int size = source.readInt();

      source.flush();
      Attribute attribute = factory.create(type, size, source);

      if (attribute != null) {
        attributes.put(name, attribute);
      }

      source.seek(source.getFlushedPosition() + size);
      source.flush();
    }

    Box2i dw = getDataWindow();
    CompressionMethod cm = getCompressionMethod();

    source.flush();

    if (tiled) {
      TileDescription td = getTiles();
      int numTiles;
      switch (td.getLevelMode()) {
      case ONE_LEVEL:
        numTiles = (1 + (dw.getYSize() - 1) / td.getYSize())
            * (1 + (dw.getXSize() - 1) / td.getXSize());
        break;

      case MIPMAP_LEVELS:
      {
        int w = dw.getXSize();
        int h = dw.getYSize();
        int tw = td.getXSize();
        int th = td.getYSize();
        RoundingMode rm = td.getRoundingMode();
        int n = 1 + round(Math.log(Math.max(w, h)) / Math.log(2.0), rm);
        numTiles = 0;
        for (int i = 0; i < n; i++) {
          int lx = round(w / Math.pow(2.0, i), rm);
          int ly = round(h / Math.pow(2.0, i), rm);
          int tx = 1 + (lx - 1) / tw;
          int ty = 1 + (ly - 1) / th;
          numTiles += tx * ty;
        }
        break;
      }

      case RIPMAP_LEVELS:
      {
        int w = dw.getXSize();
        int h = dw.getYSize();
        int tw = td.getXSize();
        int th = td.getYSize();
        RoundingMode rm = td.getRoundingMode();
        int nx = 1 + round(Math.log(w) / Math.log(2.0), rm);
        int ny = 1 + round(Math.log(h) / Math.log(2.0), rm);
        numTiles = 0;
        for (int j = 0; j < ny; j++) {
          int ly = round(h / Math.pow(2.0, j), rm);
          int ty = 1 + (ly - 1) / th;
          for (int i = 0; i < nx; i++) {
            int lx = round(w / Math.pow(2.0, i), rm);
            int tx = 1 + (lx - 1) / tw;
            numTiles += tx * ty;
          }
        }
        break;
      }

      default:
        throw new UnexpectedException("Invalid level mode.");
      }
      source.seek(source.getFlushedPosition() + 8 * numTiles);
      source.flush();

      throw new UnimplementedException();

    } else { // scan lines
      int w = dw.getXSize();
      int h = dw.getYSize();
      int ymin = dw.getYMin();
      int ymax = dw.getYMax();
      int blockHeight = cm.getScanLinesPerBlock();
      int numBlocks = 1 + (h - 1) / blockHeight;
      ChannelList chlist = getChannelList();

      source.seek(source.getFlushedPosition() + 8 * numBlocks);

      for (int i = 0; i < numBlocks; i++) {
        source.flush();

        int x0 = dw.getXMin();
        int x1 = dw.getXMax();
        int y0 = source.readInt();
        int y1 = Math.min(y0 + blockHeight - 1, ymax);
        Box2i block = new Box2i(x0, y0, x1, y1);
        int size = source.readInt();
        int blockSize = computeTileSize(block);

        IIOByteBuffer buf = new IIOByteBuffer(null, 0, 0);
        source.readBytes(buf, size);
        if (size < blockSize) {
          cm.decompress(buf, block);
          if (buf.getLength() < blockSize) {
            throw new RuntimeException("Undersized block");
          }
        }
        f.write(buf.getData(), buf.getOffset(), buf.getLength());

        ByteBuffer inBuf = ByteBuffer.wrap(buf.getData(), buf.getOffset(), buf.getLength())
            .order(ByteOrder.LITTLE_ENDIAN);

        for (int y = y0; y <= y1; y++) {
          for (Channel channel : chlist.channels()) {
            String name = channel.getName();
            int sx = channel.getxSampling();
            int sy = channel.getySampling();

            if ((y % sy) == 0) {
              int numElem = 1 + (w - 1) / sx;
              PixelType pt = channel.getPixelType();
              switch (pt) {
              case UINT:
                {
                  IntBuffer chBuf = (IntBuffer) getChannelBuffer(name);
                  chBuf.position(((y - ymin) / sy) * numElem);
                  chBuf.put((IntBuffer) inBuf.asIntBuffer().limit(numElem));
                  break;
                }

              case HALF:
                {
                  ShortBuffer chBuf = (ShortBuffer) getChannelBuffer(name);
                  chBuf.position(((y - ymin) / sy) * numElem);
                  chBuf.put((ShortBuffer) inBuf.asShortBuffer().limit(numElem));
                  break;
                }

              case FLOAT:
                {
                  FloatBuffer chBuf = (FloatBuffer) getChannelBuffer(name);
                  chBuf.position(((y - ymin) / sy) * numElem);
                  chBuf.put((FloatBuffer) inBuf.asFloatBuffer().limit(numElem));
                  break;
                }

              } // switch (channel.getPixelType())

              inBuf.position(inBuf.position() + numElem * pt.getSampleSize());
            } // if ((y % sy) == 0)
          } // for (c)
        } // for (y)
      } // for (i)
    } // if (tiled)

    source.flush();
    f.close();
  }

  private static int round(double x, TileDescription.RoundingMode mode) {
    switch (mode) {
    case DOWN: return (int) Math.floor(x);
    case UP: return (int) Math.ceil(x);
    default: throw new UnexpectedException("Invalid rounding mode");
    }
  }

  public static OpenEXRImage read(ImageInputStream source) throws IOException {
    return new OpenEXRImage(source);
  }

  private Buffer getChannelBuffer(String name) {
    Buffer buf = data.get(name);
    return buf != null ? buf : getChannelBufferSync(name);
  }

  private synchronized Buffer getChannelBufferSync(String name) {
    Buffer buf = data.get(name);
    if (buf == null) {
      ChannelList chlist = getChannelList();
      Channel channel = chlist.getChannel(name);
      Box2i dataWindow = getDataWindow();
      int w = dataWindow.getXSize();
      int h = dataWindow.getYSize();
      int sx = 1 + (w - 1) / channel.getxSampling();
      int sy = 1 + (h - 1) / channel.getySampling();
      PixelType pt = channel.getPixelType();

      switch (pt) {
      case UINT:
        buf = IntBuffer.allocate(sx * sy);
        break;

      case FLOAT:
        buf = FloatBuffer.allocate(sx * sy);
        break;

      case HALF:
        buf = ShortBuffer.allocate(sx * sy);
        break;

      default:
        throw new UnexpectedException("Invalid pixel type");
      }

      data.put(name, buf);
    }
    return buf;
  }

  private int computeTileSize(Box2i tile) {
    ChannelList chlist = getChannelList();
    int x0 = tile.getXMin();
    int y0 = tile.getYMin();
    int x1 = tile.getXMax();
    int y1 = tile.getYMax();

    int size = 0;
    for (Channel channel : chlist.channels()) {
      PixelType type = channel.getPixelType();
      int sx = channel.getxSampling();
      int sy = channel.getySampling();
      int nx = 1 + (x1 - x0 - (x1 % sx)) / sx;
      int ny = 1 + (y1 - y0 - (y1 % sy)) / sy;
      size += nx * ny * type.getSampleSize();
    }
    return size;
  }

  private int computeMaximumTileSize(V2i tileSize) {
    ChannelList chlist = getChannelList();
    int tw = tileSize.getX();
    int th = tileSize.getY();

    int size = 0;
    for (Channel channel : chlist.channels()) {
      PixelType type = channel.getPixelType();
      int sx = channel.getxSampling();
      int sy = channel.getySampling();
      int nx = 1 + (tw - 1) / sx;
      int ny = 1 + (th - 1) / sy;
      size += nx * ny * type.getSampleSize();
    }
    return size;
  }

  public void write(ImageOutputStream out) throws IOException {
    ChannelList chlist = getChannelList();
    long start = out.getStreamPosition();

    out.setByteOrder(ByteOrder.LITTLE_ENDIAN);
    out.writeInt(MAGIC);
    out.writeInt(VERSION);

    for (Map.Entry<String, Attribute> entry : attributes.entrySet()) {
      Attribute attr = entry.getValue();
      String name = entry.getKey();
      String type = attr.getClass().getAnnotation(OpenEXRAttributeType.class).value();
      out.writeBytes(name);
      out.writeByte(0);
      out.writeBytes(type);
      out.writeByte(0);
      out.flush();
      long attrStart = out.getStreamPosition() + 4;
      out.seek(attrStart);
      attr.write(out);
      long attrEnd = out.getStreamPosition();
      out.seek(out.getFlushedPosition());
      out.writeInt((int) (attrEnd - attrStart));
      out.seek(attrEnd);
      out.flush();
    }
    out.writeByte(0);

    CompressionMethod cm = getCompressionMethod();
    Box2i dw = getDataWindow();
    int xmin = dw.getXMin();
    int ymin = dw.getYMin();
    int xmax = dw.getXMax();
    int ymax = dw.getYMax();

    int numBlocks = dw.getYSize() / cm.getScanLinesPerBlock();
    long blockPtrPos = out.getStreamPosition();
    long blockPos = blockPtrPos + 8 * numBlocks;

    int maximumBlockSize = computeMaximumTileSize(new V2i(dw.getXSize(),
        Math.min(dw.getYSize(), cm.getScanLinesPerBlock())));
    byte[] blockData = new byte[maximumBlockSize];
    IIOByteBuffer buf = new IIOByteBuffer(null, 0, 0);
    ByteBuffer bytes = ByteBuffer.wrap(blockData).order(ByteOrder.LITTLE_ENDIAN);

    int firstBlock;
    int lastBlock;
    int blockIncr;
    switch (getLineOrder()) {
    case INCREASING_Y:
    case RANDOM_Y:
      firstBlock = 0;
      lastBlock = numBlocks;
      blockIncr = 1;
      break;

    case DECREASING_Y:
      firstBlock = numBlocks - 1;
      lastBlock = -1;
      blockIncr = -1;
      break;

    default:
      throw new UnexpectedException("Invalid line order");
    }

    for (int i = firstBlock; i != lastBlock; i += blockIncr) {
      out.seek(blockPtrPos + 8 * i);
      out.writeLong(blockPos - start);
      out.seek(blockPos);
      bytes.rewind();

      // TODO write the next block here
      int x0 = dw.getXMin();
      int x1 = dw.getXMax();
      int y0 = dw.getYMin() + i * cm.getScanLinesPerBlock();
      int y1 = Math.min(y0 + cm.getScanLinesPerBlock() - 1, dw.getYMax());
      Box2i block = new Box2i(x0, y0, x1, y1);
      int blockSize = computeTileSize(block);

      for (int y = y0; y <= y1; y++) {
        for (Channel channel : chlist.channels()) {
          String name = channel.getName();
          int sx = channel.getxSampling();
          int sy = channel.getySampling();
          if (y % sy == 0) {
            int nx = 1 + (x1 - x0 - (x1 % sx)) / sx;
            int offset = ((y - ymin) / sy) * nx;
            Buffer chBuf = getChannelBuffer(name);
            PixelType pt = channel.getPixelType();

            switch (pt) {
            case UINT:
              bytes.asIntBuffer().put((IntBuffer)
                  ((IntBuffer) chBuf).duplicate().position(offset).limit(offset + nx));
              break;

            case HALF:
              bytes.asShortBuffer().put((ShortBuffer)
                  ((ShortBuffer) chBuf).duplicate().position(offset).limit(offset + nx));
              break;

            case FLOAT:
              bytes.asFloatBuffer().put((FloatBuffer)
                  ((FloatBuffer) chBuf).duplicate().position(offset).limit(offset + nx));
              break;

            default:
              throw new UnexpectedException("Invalid pixel type");
            }

            bytes.position(bytes.position() + nx * pt.getSampleSize());
          }
        }
      }

      buf.setData(blockData);
      buf.setOffset(0);
      buf.setLength(blockSize);
      cm.compress(buf, block);

      out.writeInt(y0);
      if (buf.getLength() < blockSize) {
        out.writeInt(buf.getLength());
        out.write(buf.getData(), buf.getOffset(), buf.getLength());
      } else {
        out.writeInt(blockSize);
        out.write(blockData);
      }

      blockPos = out.getStreamPosition();
    }

    out.flush();
    out.close();
  }

  public Attribute getAttribute(String name) {
    return attributes.get(name);
  }

  public void setAttribute(String name, Attribute value) {
    if (name.equals("dataWindow")) {
      throw new IllegalArgumentException("Cannot set dataWindow after instantiation");
    }
    Class<?> type = ATTRIBUTE_TYPES.get(name);
    if (type != null && value.getClass() != type) {
      String msg = String.format(
          "value is of incorrect type, expected `%s' but got `%s'",
          type.getName(), value.getClass().getName());
      throw new IllegalArgumentException(msg);
    }
    attributes.put(name, value);
  }

  public ChannelList getChannelList() {
    return (ChannelList) attributes.get("channels");
  }

  public CompressionMethod getCompressionMethod() {
    return (CompressionMethod) attributes.get("compression");
  }

  public void setCompressionMethod(CompressionMethod value) {
    attributes.put("compression", value);
  }

  public Box2i getDataWindow() {
    return (Box2i) attributes.get("dataWindow");
  }

  public Box2i getDisplayWindow() {
    return (Box2i) attributes.get("displayWindow");
  }

  public void setDisplayWindow(Box2i value) {
    attributes.put("displayWindow", value);
  }

  public LineOrder getLineOrder() {
    return (LineOrder) attributes.get("lineOrder");
  }

  public void setLineOrder(LineOrder value) {
    attributes.put("lineOrder", value);
  }

  public float getPixelAspectRatio() {
    return ((FloatAttribute) attributes.get("pixelAspectRatio")).getValue();
  }

  public void setPixelAspectRatio(float value) {
    attributes.put("pixelAspectRatio", new FloatAttribute(value));
  }

  public V2f getScreenWindowCenter() {
    return (V2f) attributes.get("screenWindowCenter");
  }

  public void setScreenWindowCenter(V2f value) {
    attributes.put("screenWindowCenter", value);
  }

  public float getScreenWindowWidth() {
    return ((FloatAttribute) attributes.get("screenWindowWidth")).getValue();
  }

  public void setScreenWindowWidth(float value) {
    attributes.put("screenWindowWidth", new FloatAttribute(value));
  }

  public TileDescription getTiles() {
    return (TileDescription) attributes.get("tiles");
  }

  public void setTiles(TileDescription value) {
    attributes.put("tiles", value);
  }

  public RGB getRGB(int x, int y) {
    return new RGB(
        getFloat(x, y, "R"),
        getFloat(x, y, "G"),
        getFloat(x, y, "B"));
  }

  public void setRGB(int x, int y, RGB rgb) {
    setFloat(x, y, "R", (float) rgb.r());
    setFloat(x, y, "G", (float) rgb.g());
    setFloat(x, y, "B", (float) rgb.b());
  }

  public long getUnsignedInt(int x, int y, String c) {
    Channel ch = getChannelList().getChannel(c);
    Box2i dw = getDataWindow();
    int xmin = dw.getXMin();
    int ymin = dw.getYMin();
    int sx = ch.getxSampling();
    int sy = ch.getySampling();
    int x0 = (x - xmin) / sx;
    int y0 = (y - ymin) / sy;
    int w0 = dw.getXSize() / sx;
    int index = y0 * w0 + x0;

    switch (ch.getPixelType()) {
    case UINT:
      IntBuffer ibuf = (IntBuffer) getChannelBuffer(c);
      return ((long) ibuf.get(index)) & 0xffffffffL;

    case HALF:
      ShortBuffer sbuf = (ShortBuffer) getChannelBuffer(c);
      return MathUtil.clamp(Half.fromShortBits(sbuf.get(index)).longValue(), 0, (0x1L << 32) - 1L);

    case FLOAT:
      FloatBuffer fbuf = (FloatBuffer) getChannelBuffer(c);
      return MathUtil.clamp((long) fbuf.get(index), 0, (0x1L << 32) - 1L);

    default:
      throw new UnexpectedException("Invalid pixel type");

    }
  }

  public Half getHalf(int x, int y, String c) {
    Channel ch = getChannelList().getChannel(c);
    Box2i dw = getDataWindow();
    int sx = ch.getxSampling();
    int sy = ch.getySampling();
    int xmin = dw.getXMin();
    int ymin = dw.getYMin();
    int x0 = (x - xmin) / sx;
    int y0 = (y - ymin) / sy;
    int w0 = dw.getXSize() / sx;
    int index = y0 * w0 + x0;

    switch (ch.getPixelType()) {
    case UINT:
      IntBuffer ibuf = (IntBuffer) getChannelBuffer(c);
      return Half.valueOf((double) (((long) ibuf.get(index)) & 0xffffffffL));

    case HALF:
      ShortBuffer sbuf = (ShortBuffer) getChannelBuffer(c);
      return Half.fromShortBits(sbuf.get(index));

    case FLOAT:
      FloatBuffer fbuf = (FloatBuffer) getChannelBuffer(c);
      return Half.valueOf(fbuf.get(index));

    default:
      throw new UnexpectedException("Invalid pixel type");

    }
  }

  public float getFloat(int x, int y, String c) {
    Channel ch = getChannelList().getChannel(c);
    Box2i dw = getDataWindow();
    int sx = ch.getxSampling();
    int sy = ch.getySampling();
    int xmin = dw.getXMin();
    int ymin = dw.getYMin();
    int x0 = (x - xmin) / sx;
    int y0 = (y - ymin) / sy;
    int w0 = dw.getXSize() / sx;
    int index = y0 * w0 + x0;

    switch (ch.getPixelType()) {
    case UINT:
      IntBuffer ibuf = (IntBuffer) getChannelBuffer(c);
      return (float) (((long) ibuf.get(index)) & 0xffffffffL);

    case HALF:
      ShortBuffer sbuf = (ShortBuffer) getChannelBuffer(c);
      return Half.fromShortBits(sbuf.get(index)).floatValue();

    case FLOAT:
      FloatBuffer fbuf = (FloatBuffer) getChannelBuffer(c);
      return fbuf.get(index);

    default:
      throw new UnexpectedException("Invalid pixel type");

    }
  }

  public void setUnsignedInt(int x, int y, String c, long value) {
    Channel ch = getChannelList().getChannel(c);
    Box2i dw = getDataWindow();
    int sx = ch.getxSampling();
    int sy = ch.getySampling();
    int xmin = dw.getXMax();
    int ymin = dw.getYMin();
    int x0 = (x - xmin) / sx;
    int y0 = (y - ymin) / sy;
    int w0 = dw.getXSize() / sx;
    int index = y0 * w0 + x0;

    switch (ch.getPixelType()) {
    case UINT:
      IntBuffer ibuf = (IntBuffer) getChannelBuffer(c);
      ibuf.put(index, (int) value);
      break;

    case HALF:
      ShortBuffer sbuf = (ShortBuffer) getChannelBuffer(c);
      sbuf.put(index, Half.valueOf((float) ((int) value)).toShortBits());
      break;

    case FLOAT:
      FloatBuffer fbuf = (FloatBuffer) getChannelBuffer(c);
      fbuf.put(index, (float) ((int) value));
      break;

    default:
      throw new UnexpectedException("invalid pixel type");
    }
  }

  public void setHalf(int x, int y, String c, Half value) {
    Channel ch = getChannelList().getChannel(c);
    Box2i dw = getDataWindow();
    int sx = ch.getxSampling();
    int sy = ch.getySampling();
    int x0 = x / sx;
    int y0 = y / sy;
    int w0 = dw.getXSize() / sx;
    int index = y0 * w0 + x0;

    switch (ch.getPixelType()) {
    case UINT:
      IntBuffer ibuf = (IntBuffer) getChannelBuffer(c);
      ibuf.put(index, (int) MathUtil.clamp(value.longValue(), 0, (0x1L << 32) - 1));
      break;

    case HALF:
      ShortBuffer sbuf = (ShortBuffer) getChannelBuffer(c);
      sbuf.put(index, value.toShortBits());
      break;

    case FLOAT:
      FloatBuffer fbuf = (FloatBuffer) getChannelBuffer(c);
      fbuf.put(index, value.floatValue());
      break;

    default:
      throw new UnexpectedException("Invalid pixel type");
    }
  }

  public void setFloat(int x, int y, String c, float value) {
    Channel ch = getChannelList().getChannel(c);
    Box2i dw = getDataWindow();
    int sx = ch.getxSampling();
    int sy = ch.getySampling();
    int x0 = x / sx;
    int y0 = y / sy;
    int w0 = dw.getXSize() / sx;
    int index = y0 * w0 + x0;

    switch (ch.getPixelType()) {
    case UINT:
      IntBuffer ibuf = (IntBuffer) getChannelBuffer(c);
      ibuf.put(index, (int) MathUtil.clamp((long) value, 0, (0x1L << 32) - 1));
      break;

    case HALF:
      ShortBuffer sbuf = (ShortBuffer) getChannelBuffer(c);
      sbuf.put(index, Half.valueOf(value).toShortBits());
      break;

    case FLOAT:
      FloatBuffer fbuf = (FloatBuffer) getChannelBuffer(c);
      fbuf.put(index, value);
      break;

    default:
      throw new UnexpectedException("Invalid pixel type");
    }
  }

  public static void main(String[] args) {
    try {


//      OpenEXRImage image = new OpenEXRImage(new FileImageInputStream(new File("/home/brad/Downloads/openexr-images-1.5.0/ScanLines/Blobbies.exr")));
      OpenEXRImage image = new OpenEXRImage(640, 480);
      image.getChannelList().addChannel(new Channel("R", PixelType.FLOAT));
      image.getChannelList().addChannel(new Channel("G", PixelType.FLOAT));
      image.getChannelList().addChannel(new Channel("B", PixelType.FLOAT));
      image.setCompressionMethod(CompressionMethod.ZIP);
      image.setRGB(320, 240, new RGB(1,0,0));
//      image.attributes.put("compression", CompressionMethod.NONE);

//      PrintStream out = new PrintStream(new FileOutputStream("/home/brad/Downloads/openexr-images-1.5.0/ScanLines/Blobbies2.test"));
//      for (int y = -20; y < 1020; y++) {
//        for (int x = -20; x < 1020; x++) {
//          out.printf("% 8.6e,% 8.6e,% 8.6e,% 8.6e,% 8.6e",
//              image.getFloat(x, y, "A"),
//              image.getFloat(x, y, "B"),
//              image.getFloat(x, y, "G"),
//              image.getFloat(x, y, "R"),
//              image.getFloat(x, y, "Z"));
//          out.println();
//        }
//      }
//      out.flush();
//      out.close();

      image.write(new FileImageOutputStream(new File("/home/brad/Downloads/openexr-images-1.5.0/ScanLines/Test.exr")));
    } catch (FileNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }

}
TOP

Related Classes of ca.eandb.jmist.framework.loader.openexr.OpenEXRImage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.