From 54bd6d6d2cc05eb488f63f3469ab8415473449ad Mon Sep 17 00:00:00 2001 From: Darwin Bautista Date: Sat, 3 Feb 2018 15:04:47 +0800 Subject: [PATCH 1/2] Fix PNG transparency (Fixes #2) This is a JME issue. Since the modified code is internal to JME, a new class with the same interface is created instead. --- .../shapenet/jme3/viewer/JmeSystemMod.java | 81 +++++++++++++++++++ .../shapenet/jme3/viewer/OffscreenView.scala | 2 +- .../jme3/viewer/ScreenshotAppState.java | 2 +- 3 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 src/main/scala/edu/stanford/graphics/shapenet/jme3/viewer/JmeSystemMod.java diff --git a/src/main/scala/edu/stanford/graphics/shapenet/jme3/viewer/JmeSystemMod.java b/src/main/scala/edu/stanford/graphics/shapenet/jme3/viewer/JmeSystemMod.java new file mode 100644 index 0000000..92f9e0c --- /dev/null +++ b/src/main/scala/edu/stanford/graphics/shapenet/jme3/viewer/JmeSystemMod.java @@ -0,0 +1,81 @@ +package edu.stanford.graphics.shapenet.jme3.viewer; + +import com.jme3.util.Screenshots; + +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.plugins.jpeg.JPEGImageWriteParam; +import javax.imageio.stream.ImageOutputStream; +import javax.imageio.stream.MemoryCacheImageOutputStream; +import java.awt.*; +import java.awt.geom.AffineTransform; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.awt.image.DataBufferInt; +import java.awt.image.WritableRaster; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; + +public final class JmeSystemMod { + + private static void fixAlphaAndSwapChannels(BufferedImage img) { + final WritableRaster wr = img.getRaster(); + final DataBufferInt db = (DataBufferInt)wr.getDataBuffer(); + final int[] cpuArray = db.getData(); + for (int i = 0; i < cpuArray.length; i++) { + // Fix alpha channel (set to 0 for complete transparency) + if (cpuArray[i] == -1) { + cpuArray[i] &= 0x00ffffff; + } else { + // ABGR to ARGB + int p = cpuArray[i]; + int b = p >> 16 & 0xff; + int r = p & 0xff; + cpuArray[i] = (p & 0xff00ff00) | r << 16 | b; + } + } + } + + private static BufferedImage verticalFlip(BufferedImage original) { + AffineTransform tx = AffineTransform.getScaleInstance(1, -1); + tx.translate(0, -original.getHeight()); + AffineTransformOp transformOp = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + BufferedImage awtImage = new BufferedImage(original.getWidth(), original.getHeight(), BufferedImage.TYPE_INT_ARGB); + Graphics2D g2d = awtImage.createGraphics(); + g2d.setRenderingHint(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_SPEED); + g2d.drawImage(original, transformOp, 0, 0); + g2d.dispose(); + return awtImage; + } + + public static void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException { + BufferedImage awtImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + Screenshots.convertScreenShot2(imageData.asIntBuffer(), awtImage); + fixAlphaAndSwapChannels(awtImage); + + ImageWriter writer = ImageIO.getImageWritersByFormatName(format).next(); + ImageWriteParam writeParam = writer.getDefaultWriteParam(); + + if (format.equals("jpg")) { + JPEGImageWriteParam jpegParam = (JPEGImageWriteParam) writeParam; + jpegParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + jpegParam.setCompressionQuality(0.95f); + } + + awtImage = verticalFlip(awtImage); + + ImageOutputStream imgOut = new MemoryCacheImageOutputStream(outStream); + writer.setOutput(imgOut); + IIOImage outputImage = new IIOImage(awtImage, null, null); + try { + writer.write(null, outputImage, writeParam); + } finally { + imgOut.close(); + writer.dispose(); + } + } +} diff --git a/src/main/scala/edu/stanford/graphics/shapenet/jme3/viewer/OffscreenView.scala b/src/main/scala/edu/stanford/graphics/shapenet/jme3/viewer/OffscreenView.scala index 684e8e9..d23939f 100644 --- a/src/main/scala/edu/stanford/graphics/shapenet/jme3/viewer/OffscreenView.scala +++ b/src/main/scala/edu/stanford/graphics/shapenet/jme3/viewer/OffscreenView.scala @@ -89,7 +89,7 @@ class OffscreenView(val renderManager: RenderManager, logger.info("Saving offscreen view to: {0}", file.getAbsolutePath()) try { outStream = IOUtils.fileOutputStream(filename) - JmeSystem.writeImageFile(outStream, imageFormat, outBuf, width, height) + JmeSystemMod.writeImageFile(outStream, imageFormat, outBuf, width, height) } catch { case ex: IOException => { logger.error("Error while saving offscreen view", ex) diff --git a/src/main/scala/edu/stanford/graphics/shapenet/jme3/viewer/ScreenshotAppState.java b/src/main/scala/edu/stanford/graphics/shapenet/jme3/viewer/ScreenshotAppState.java index ad8b05d..84a075f 100644 --- a/src/main/scala/edu/stanford/graphics/shapenet/jme3/viewer/ScreenshotAppState.java +++ b/src/main/scala/edu/stanford/graphics/shapenet/jme3/viewer/ScreenshotAppState.java @@ -201,7 +201,7 @@ public void postFrame(FrameBuffer out) { OutputStream outStream = null; try { outStream = new FileOutputStream(file); - JmeSystem.writeImageFile(outStream, imageFormat, outBuf, width, height); + JmeSystemMod.writeImageFile(outStream, imageFormat, outBuf, width, height); logger.log(Level.INFO, "Saved ScreenShot to: " + file.getAbsolutePath()); } catch (IOException ex) { logger.log(Level.SEVERE, "Error while saving screenshot", ex); From 2274a5a5a49ead8dcaa49df29010e8c3cf169629 Mon Sep 17 00:00:00 2001 From: Darwin Bautista Date: Sat, 3 Feb 2018 18:27:23 +0800 Subject: [PATCH 2/2] Lessen array lookups --- .../shapenet/jme3/viewer/JmeSystemMod.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/scala/edu/stanford/graphics/shapenet/jme3/viewer/JmeSystemMod.java b/src/main/scala/edu/stanford/graphics/shapenet/jme3/viewer/JmeSystemMod.java index 92f9e0c..48297c5 100644 --- a/src/main/scala/edu/stanford/graphics/shapenet/jme3/viewer/JmeSystemMod.java +++ b/src/main/scala/edu/stanford/graphics/shapenet/jme3/viewer/JmeSystemMod.java @@ -26,16 +26,17 @@ private static void fixAlphaAndSwapChannels(BufferedImage img) { final DataBufferInt db = (DataBufferInt)wr.getDataBuffer(); final int[] cpuArray = db.getData(); for (int i = 0; i < cpuArray.length; i++) { + int p = cpuArray[i]; // Fix alpha channel (set to 0 for complete transparency) - if (cpuArray[i] == -1) { - cpuArray[i] &= 0x00ffffff; + if (p == -1) { + p &= 0x00ffffff; } else { - // ABGR to ARGB - int p = cpuArray[i]; - int b = p >> 16 & 0xff; - int r = p & 0xff; - cpuArray[i] = (p & 0xff00ff00) | r << 16 | b; + // Convert ABGR to ARGB + final int b = p >> 16 & 0xff; + final int r = p & 0xff; + p = (p & 0xff00ff00) | r << 16 | b; } + cpuArray[i] = p; } }