如何使用openGL(JGL)缩放图像?

时间:2010-03-28 14:11:52

标签: java opengl image-scaling

我想使用openGL缩放图像,任何人都可以向我提供有关如何执行此操作的代码吗? PS,我使用JGL作为Java的openGL库。

1 个答案:

答案 0 :(得分:1)

我将简要介绍一下这个问题,因为你可以找到几乎所有解决方案的教程。

您需要从磁盘加载图像,并创建纹理。

您需要创建一个具有所需目标尺寸的帧缓冲对象(FBO)(在您的情况下,双倍宽度,双倍高度)。使FBO处于活动状态以进行渲染。

渲染全屏四边形并应用纹理。

使用glReadPixels()读取结果。

这就是......纹理映射硬件将负责为您重新调整它。但它可能比在CPU上做得慢,特别是对于"缩放2x"。

编辑:根据OP的要求,必须包含源代码。

所以...要用Java加载图像,你可以这样做:

BufferedImage img;
try {
    img = ImageIO.read(new File("myLargeImage.jpg"));
} catch (IOException e) { /* ... */ }
int w = img.getWidth(), h = img.getHeight();

对于JGL,可能想要将图像转换为数组:

byte [][][] imageData = new byte[img.getWidth()][img.getHeight()][3]; // alloc buffer for RGB data
for(int y = 0; y < h; ++ y) {
    for(int x = 0; x < w; ++ x) {
        int RGBA = img.getRGB(x, y);
        imageData[x][y][0] = RGBA & 0xff;
        imageData[x][y][1] = (RGBA >> 8) & 0xff;
        imageData[x][y][2] = (RGBA >> 16) & 0xff;
    }
}

请注意,也可能存在alpha通道(透明度),这可能会非常慢。人们也可以使用:

int[] rgbaData = img.GetRGB(0, 0, w, h, new int[w * h], 0, w);

但是,这并没有以JGL预期的正确格式返回数据。倒霉。 然后你需要填充纹理:

int[] texId = {0};
gl.glGenTextures(1, texId); // generate texture id for your texture (can skip this line)
gl.glEnable(GL.GL_TEXTURE_2D);
gl.glBindTexture(GL.GL_TEXTURE_2D, texId[0]); // bind the texture
gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, 1); // set alignment of data in memory (a good thing to do before glTexImage)
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP); // set clamp (GL_CLAMP_TO_EDGE would be better)
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR); // set linear filtering (so you can scale your image)
gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB, w, h, 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, imageData); // upload image data to the texture

一旦你有了纹理,就可以画出东西。让我们重新拍摄您的图片:

int newW = ..., newH = ...; // fill-in your values
gl.glViewport(0, 0, newW, newH); // set viewport

gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
gl.glColor3f(1.0f, 1.0f, 1.0f); // set "white" color
gl.glDisable(GL.GL_CULL_FACE); // disable backface culling
gl.glDisable(GL.GL_LIGHTING); // disable lighting
gl.glDisable(GL.GL_DEPTH_TEST); // disable depth test
// setup OpenGL so that it renders texture colors without modification (some of that is not required by default)

gl.glBegin(GL_QUADS);
gl.glTexCoord2f(0.0f, 1.0f);
gl.glVertex2f(-1.0f, -1.0f);
gl.glTexCoord2f(1.0f, 1.0f);
gl.glVertex2f(+1.0f, -1.0f);
gl.glTexCoord2f(1.0f, 0.0f);
gl.glVertex2f(+1.0f, +1.0f);
gl.glTexCoord2f(0.0f, 0.0f);
gl.glVertex2f(-1.0f, +1.0f);
gl.glEnd();
// draw a fullscreen quad with your texture on it (scaling is performed here)

现在已经渲染了缩放图像,只需要下载它。

byte[][][] newImageData = new byte[newW][newH][3];
gl.glPixelStorei(GL.GL_PACK_ALIGNMENT, 1); // set alignment of data in memory (this time pack alignment; a good thing to do before glReadPixels)
gl.glReadPixels(0, 0, newW, newH, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, newImageData);

然后可以将输入图像img转换为imageData的方式将数据转换为BufferedImage。

请注意,我使用了变量gl,它是GL类的一个实例。将代码放入一些JGL示例中它应该可以工作。

提醒一句,JGL似乎不支持帧缓冲对象,因此您受OpenGL窗口大小的输出图像大小限制(尝试创建更大的图像将导致黑色边框)。它可以通过使用多通道渲染来解决(通过平铺渲染图像并将整个图像组合在内存中)。