我尝试创建一个解决方案,允许我在 Java 中读取 OpenExr 图像并将像素数据用于 JOGL 中的纹理。因为在 Java 中没有免费的 OpenExr 库(没有找到任何工作),我的想法是使用 ILM OpenExr 库编写一个小型 c++ 程序并用 Swig 包装它,这样我就可以使用 JNI 加载和使用 dll爪哇。
我构建了 OpenExr 库并在 Visual Studio 2005 中设置了 Swig。它已经创建了一个 dll,允许我获取图像的尺寸,所以我猜工具链运行正常。
h 文件:
#include <ImfRgbaFile.h>
#include <ImathBox.h>
#include <ImathVec.h>
#include <ImfRgba.h>
#include <ImfArray.h>
#include <iostream>
#include "String.h"
#include "RgbaStruct.h"
using namespace std;
class OpenExrReader {
private:
int width;
int height;
Imf::Array2D<Imf::Rgba> newPixels;
Rgba rgba;
public:
//constructor
OpenExrReader::OpenExrReader();
//destructor
OpenExrReader::~OpenExrReader();
//methods
int OpenExrReader::readExrFile(const char *filePath);
int OpenExrReader::getHeight();
int OpenExrReader::getWidth();
Rgba OpenExrReader::getScruct(int i, int j);
};
.cpp 文件:
#include "OpenExrReader.h"
OpenExrReader::OpenExrReader() {
width = 0;
height = 0;
}
OpenExrReader::~OpenExrReader() {
}
int OpenExrReader::readExrFile(const char *filePath) {
const char* fileName = filePath;
try {
Imf::RgbaInputFile file(fileName);
Imath::Box2i dw = file.dataWindow();
Imath::V2i dim(dw.max.x - dw.min.x + 1, dw.max.y - dw.min.y + 1);
width = dw.max.x - dw.min.x + 1;
height = dw.max.y - dw.min.y + 1;
newPixels.resizeErase(height, width);
int dx = dw.min.x;
int dy = dw.min.y;
file.setFrameBuffer(&newPixels[0][0] - dw.min.x - dw.min.y * width, 1, width);
file.readPixels(dw.min.y, dw.max.y);
}
catch (Iex::BaseExc &e) {
std::cerr << e.what() << std::endl;
}
return 0;
}
int OpenExrReader::getHeight() {
return height;
}
int OpenExrReader::getWidth() {
return width;
}
Rgba OpenExrReader::getScruct(int i, int j) {
struct Rgba rgba = {newPixels[i][j].r,
newPixels[i][j].g,
newPixels[i][j].b,
newPixels[i][j].a};
return rgba;
}
Rgba 结构:
#include <half.h>
#ifndef RGBASTRUCT_H
#define RGBASTRUCT_H
struct Rgba{
half r;
half g;
half b;
half a;
};
#endif
Swig 接口文件:
/* File : OpenExrReader.i */
%module OpenExrReaderDll
%{
/* Put header files here or function declarations like below */
#include "OpenExrReader.h"
#include "RgbaStruct.h"
%}
%include "OpenExrReader.h"
%include "RgbaStruct.h"
Java测试程序:
public class OpenExrReaderMain {
static {
System.loadLibrary("OpenExrReader");
}
/**
* @param args
*/
public static void main(String[] args) {
OpenExrReader reader = new OpenExrReader();
reader.readExrFile("C:\\path\\someExrFile.exr");
int height = reader.getHeight();
int width = reader.getWidth();
for(int i = 0; i < height; i++) {
for(int j = 0; j < width; j++) {
Rgba rgba = reader.getScruct(i, j);
SWIGTYPE_p_half r = rgba.getR();
SWIGTYPE_p_half g = rgba.getG();
SWIGTYPE_p_half b = rgba.getB();
SWIGTYPE_p_half a = rgba.getA();
System.out.print("r: " + r + " || ");
System.out.print("g: " + g + " || ");
System.out.print("b: " + b + " || ");
System.out.print("a: " + a);
System.out.println();
}
}
}
}
就像我说的那样,这是可行的,但我不是为每个像素得到这个像素数据:
r: SWIGTYPE_p_half@6b8741 || g: SWIGTYPE_p_half@17cfa2a || b: SWIGTYPE_p_half@c0a52 || a: SWIGTYPE_p_half@79c3e2
最初的想法是我必须在某个时候将像素数据复制到 Java 缓冲区中才能在 JOGL 中使用它。所以我写了getScuct(int i, int j) 方法来获取一个像素的rgba-data,并尽量保持JNI接口简单。
现在的问题是 Swig 不知道如何将 ILM half 数据类型转换为 Java 数据类型。起初我尝试将浮点值存储在 Rgba 结构中,因为 Swig 知道如何转换这些值。根据 OpenExr 文档,将 half 转换为 float 应该没问题,但每次我尝试这样的事情时:
half a = newPixels[i][j].r;
float b = a;
我从 VS 收到一条错误消息,上面写着:
OpenExrReader.obj : error LNK2001: unresolved external symbol "private: static union half::uif const * const half::_toFloat" (?_toFloat@half@@0QBTuif@1@B)
我想出的另一个解决方案是使用 Swig 类型映射并告诉包装器将 ILM 一半转换为 Java 浮点数,但我不确定这是否可能。
因为我对 c++ 和 VS 知之甚少,而且这是我第一次使用 Swig 和 JNI,所以我完全不知道如何解决这个问题。
那么,有谁知道如何解决这个问题,以便我可以将像素数据转换为 java 数据类型?