Generate transparent icon from model

I think it specifically does something to avoid this… because it used to export transparency until it was fixed to not.

I mean, it creates a different viewport I think. I don’t know if you can alter AtlasGeneratorState locally until it breaks or not.

…not sure I ever “Gradle-ized” sim-arboreal.

1 Like

Okay, Paul I just build SimArboreal-Editor with JME 3.3 locally and no transparency is exported now

Ahah!

…it’s that piece-of-… JME at fault again. :wink:

And finding that faulty piece is going to be a pain in… :grinning:

Step 1: see if it’s broken in 3.2… then 3.1.

…narrow down the list of suspects.

If it works in game maybe it’s the saving process that is at fault?

1 Like

Tested result:
3.3 → no transparency
3.2 → no transparency
3.1 (stable, alpha5,4,3,2) → could not test with SimArboreal-Editor due to this error :

java.lang.NullPointerException
	at com.jme3.util.BufferUtils.destroyDirectBuffer(BufferUtils.java:1332)
	at com.jme3.util.BufferUtils.destroyDirectBuffer(BufferUtils.java:1337)
	at com.simsilica.arboreal.TreeBuilderReference.releaseMesh(TreeBuilderReference.java:290)
	at com.simsilica.arboreal.TreeBuilderReference.releaseGeometry(TreeBuilderReference.java:281)
	at com.simsilica.arboreal.TreeBuilderReference$LevelGeometry.release(TreeBuilderReference.java:503)
	at com.simsilica.arboreal.TreeBuilderReference.apply(TreeBuilderReference.java:244)
	at com.simsilica.builder.Builder$PrioritizedRef.apply(Builder.java:484)
	at com.simsilica.builder.Builder.applyUpdates(Builder.java:302)
	at com.simsilica.builder.BuilderState.update(BuilderState.java:127)
	at com.jme3.app.state.AppStateManager.update(AppStateManager.java:287)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:236)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
	at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:192)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:232)
	at java.base/java.lang.Thread.run(Thread.java:844)

so I tested on my example code and there was no transparency.

Yes.

I tried to export it to dds with @RiccardoBlb 's DDSWriter and it worked.

I tried to see what version of JME that SimArboreal is using but it was not apparent. JME didn’t embed any versioning back then.

1 Like

Okay, found it.

Most probably it uses JME 3.0.

in JME 3.0

in JME 3.1 and later

I tested with the old one and transparency works now.
https://i.imgur.com/ucEmOSS.png

1 Like

Older versions:

BufferedImage awtImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);

Newer versions:

BufferedImage awtImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);

Can’t say for sure without looking at the Screenshots class, but those lines suggest that the transparency is being stripped out of the images - possibly for the sake of the added jPEG support (jPEG doesn’t support transparency).

That’s certainly consistent with the behaviour you’re observing.

I guess so. Exporting to jpg with old one results in this exception:

javax.imageio.IIOException: Invalid argument to native writeImage
	at java.desktop/com.sun.imageio.plugins.jpeg.JPEGImageWriter.writeImage(Native Method)
	at java.desktop/com.sun.imageio.plugins.jpeg.JPEGImageWriter.writeOnThread(JPEGImageWriter.java:1067)
	at java.desktop/com.sun.imageio.plugins.jpeg.JPEGImageWriter.write(JPEGImageWriter.java:363)
	at java.desktop/javax.imageio.ImageWriter.write(ImageWriter.java:613)
	at java.desktop/javax.imageio.ImageIO.doWrite(ImageIO.java:1628)
	at java.desktop/javax.imageio.ImageIO.write(ImageIO.java:1594)
	at com.jme3.system.JmeDesktopSystem.writeImageFile(JmeDesktopSystem.java:96)
	at com.jme3.system.JmeSystem.writeImageFile(JmeSystem.java:134)
	at com.overthemoon.main.TestIconGenerator2.savePng(TestIconGenerator2.java:139)
	at com.overthemoon.main.TestIconGenerator2.simpleRender(TestIconGenerator2.java:200)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:271)
	at com.jme3.system.lwjgl.LwjglWindow.runLoop(LwjglWindow.java:499)
	at com.jme3.system.lwjgl.LwjglWindow.run(LwjglWindow.java:581)
	at com.jme3.system.lwjgl.LwjglWindow.create(LwjglWindow.java:423)
	at com.jme3.app.LegacyApplication.start(LegacyApplication.java:463)
	at com.jme3.app.LegacyApplication.start(LegacyApplication.java:424)
	at com.jme3.app.SimpleApplication.start(SimpleApplication.java:125)
	at com.overthemoon.main.TestIconGenerator2.main(TestIconGenerator2.java:74)

Then should we use TYPE_4BYTE_ABGR if format is png and TYPE_INT_BGR if it is jpg ?

Edit: I wonder why the author of that method just did not do this in the first place.

1 Like

I think so… don’t see what else to do, except possibly choose the format depending on the value of a passed “does output support transparency” boolean parameter. Just going off of jPEG (or other supported formats that don’t allow transparency)/non-jPEG would probably make more sense though. Not sure why the original author didn’t do that.

Changed here for what it’s worth:
https://github.com/jMonkeyEngine/jmonkeyengine/commit/30efc7ce86311f8be10c0ced2ffcb0fae51cc975

Quick glance through the Java ImageIO stuff, I don’t see an easy way to determine if an output format supports transparency or not.

Barring that, moving the image copying down below the if jpeg block and moving image creation into the jpeg block and an else branch might be nice. At least we’d know jpeg and png would work like we want.

Good catch, guys.

3 Likes

@pspeed are you alright with this ?

public void writeImageFile(OutputStream outStream, String format, ByteBuffer imageData, int width, int height) throws IOException {       
        ImageWriter writer = ImageIO.getImageWritersByFormatName(format).next();
        ImageWriteParam writeParam = writer.getDefaultWriteParam();
        
        BufferedImage awtImage;
        if (format.equals("jpg")) {
            JPEGImageWriteParam jpegParam = (JPEGImageWriteParam) writeParam;
            jpegParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            jpegParam.setCompressionQuality(0.95f);
            awtImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
            Screenshots.convertScreenShot2(imageData.asIntBuffer(), awtImage);
            awtImage = verticalFlip(awtImage);
        } else {
            awtImage = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
            Screenshots.convertScreenShot(imageData, 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();
        }
    }

Maybe making it configurable and throw an exception if someone wants alpha for png?
Because in some cases someone might want a non transparent png? (Could you imagine use cases?)

If it works, I’m ok with it… unless someone knows a good way to detect target transparency support. But even so, in the mean time it would be nice to have something working again.

You mean for jpg?

If you want a non-transparent PNG then you could always make a non-transparent image, I guess. Then you’re just writing extra bytes.

This method is part of an API I think so we probably don’t want to add parameters just to fix this problem that used to work and doesn’t anymore. But that’s maybe something to look into next?

That’s a solid reason, yes.

Well I thought in general “boolean useAlpha” or not, so you can in fact write 3 Byte per Pixel Images. Because regular screenshots (as implied by the “bad” naming) never want alpha, it would look odd.

But that could also help us, if we wrap the exception and someone tries to export a .bmp, which doesn’t support transparency, the user could fix it by specifying useAlpha=false. But not sure if that’s the best way because when someone cares about the format, an override which allows you to specify the format type would be much better anyway (as future feature suggestion)

Wikipedia says it does support it.

Raster file formats that support transparency include GIF, PNG, BMP, TIFF, and JPEG 2000, through either a transparent color or an alpha channel.

based on javadoc
https://docs.oracle.com/javase/7/docs/api/javax/imageio/package-summary.html
ImageIO only supports JPEG, PNG, BMP, WBMP, GIF and among them I think only JPEG not supports transparency.

1 Like