[PATCH] SDK Texture editor invert color channel filter

I wanted to invert the green channel of an image so I hacked this little filter for the texture editor. The icon-PNG isn’t used anywhere but since I created one anyway I attached it.



Edit: orly, even between patch tags 8 ) becomes 8) that was unexpected :slight_smile:



[patch]# This patch file was generated by NetBeans IDE

This patch can be applied using context Tools: Patch action on respective folder.

It uses platform neutral UTF-8 encoding and n newlines.

Above lines and this line are ignored by the patching process.

Index: src/com/jme3/gde/textureeditor/ImageEditorComponent.java

— src/com/jme3/gde/textureeditor/ImageEditorComponent.java Base (BASE)

+++ src/com/jme3/gde/textureeditor/ImageEditorComponent.java Locally Modified (Based On LOCAL)

@@ -36,6 +36,7 @@

import com.jme3.gde.textureeditor.filters.BrightFilter;

import com.jme3.gde.textureeditor.filters.BumpMapFilter;

import com.jme3.gde.textureeditor.filters.GrayscaleFilter;

+import com.jme3.gde.textureeditor.filters.InvertFilter;

import com.jme3.gde.textureeditor.filters.MirrorFilter;

import com.jme3.gde.textureeditor.filters.ResizeFilter;

import com.jme3.gde.textureeditor.filters.RotateLeftFilter;

@@ -369,6 +370,13 @@

final JMenuItem gray = filters.add("Grayscale");

final JMenuItem bright = filters.add("Brightness");

final JMenuItem spheremap = filters.add("SphereMapped");

  •    final JMenu invertMenu = new JMenu(&quot;Invert&quot;) ;<br />
    
  •    final JMenuItem invertAll = invertMenu.add(&quot;All&quot;) ;<br />
    
  •    final JMenuItem invertAlpha = invertMenu.add(&quot;Alpha&quot;) ;<br />
    
  •    final JMenuItem invertRed = invertMenu.add(&quot;Red&quot;) ;<br />
    
  •    final JMenuItem invertGreen = invertMenu.add(&quot;Green&quot;) ;<br />
    
  •    final JMenuItem invertBlue = invertMenu.add(&quot;Blue&quot;) ;<br />
    
  •    filters.add(invertMenu) ;<br />
    

ActionListener al = new ActionListener() {

@@ -386,12 +394,21 @@
spawnEditor(BrightFilter.create().filter(editedImage, ImageEditorComponent.this));
} else if (source == spheremap) {
spawnEditor(SphereMappedFilter.create().filter(editedImage));
+ } else if (source == invertAll) {
+ spawnEditor(new InvertFilter().filter(editedImage, InvertFilter.Channel.All));
+ } else if (source == invertAlpha) {
+ spawnEditor(new InvertFilter().filter(editedImage, InvertFilter.Channel.Alpha));
+ } else if (source == invertRed) {
+ spawnEditor(new InvertFilter().filter(editedImage, InvertFilter.Channel.Red));
+ } else if (source == invertGreen) {
+ spawnEditor(new InvertFilter().filter(editedImage, InvertFilter.Channel.Green));
+ } else if (source == invertBlue) {
+ spawnEditor(new InvertFilter().filter(editedImage, InvertFilter.Channel.Blue));
}
-
}
};

- for (AbstractButton b : Arrays.asList(bumpSoft, bumpMedium, bumpStrong, gray, bright, spheremap)) {
+ for (AbstractButton b : Arrays.asList(bumpSoft, bumpMedium, bumpStrong, gray, bright, spheremap, invertAll, invertAlpha, invertRed, invertGreen, invertBlue)) {
b.addActionListener(al);
}
}
Index: src/com/jme3/gde/textureeditor/filters/InvertFilter.java
--- src/com/jme3/gde/textureeditor/filters/InvertFilter.java Locally New
+++ src/com/jme3/gde/textureeditor/filters/InvertFilter.java Locally New
@@ -0,0 +1,73 @@
+package com.jme3.gde.textureeditor.filters;
+
+import java.awt.image.BufferedImage;
+
+/**
+ * Invert channels in an image. It takes the ARGB color component and set it to 255 - value.
+ */
+public class InvertFilter implements BufferedImageFilter {
+
+ public enum Channel {
+
+ All, Red, Green, Blue, Alpha;
+ }
+
+ public BufferedImage filter(BufferedImage source, Object... args) {
+ final Channel channel;
+ if ((args == null) || (args.length < 1) || (!(args[0] instanceof Channel))) {
+ channel = Channel.All;
+ } else {
+ channel = (Channel) args[0];
+ }
+ BufferedImage result = new BufferedImage(
+ source.getWidth(),
+ source.getHeight(),
+ BufferedImage.TYPE_INT_ARGB);
+ final int height = source.getHeight();
+ final int width = source.getWidth();
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ final int sourceARGB = source.getRGB(x, y);
+ final int targetARGB = invert(sourceARGB, channel);
+ result.setRGB(x, y, targetARGB);
+ }
+ }
+ return result;
+ }
+
+ private int invert(final int sourceARGB, final Channel channel) {
+ int a = (sourceARGB >> 24) & 0xff;
+ int r = (sourceARGB >> 16) & 0xff;
+ int g = (sourceARGB >> 8 ) & 0xff;
+ int b = sourceARGB & 0xff;
+
+ switch (channel) {
+ case Alpha:
+ a = 255 - a;
+ break;
+ case Red:
+ r = 255 - r;
+ break;
+ case Green:
+ g = 255 - g;
+ break;
+ case Blue:
+ b = 255 - b;
+ break;
+ default:
+ a = 255 - a;
+ r = 255 - r;
+ g = 255 - g;
+ b = 255 - b;
+ }
+ return packPixel(a, r, g, b);
+ }
+
+ private int packPixel(int alpha, int red, int green, int blue) {
+ final int argb = ((alpha << 24) & 0xff000000)
+ | ((red << 16) & 0x00ff0000)
+ | ((green << 8 ) & 0x0000ff00)
+ | (blue & 0x000000ff);
+ return argb;
+ }
+}
Index: src/com/jme3/gde/textureeditor/resources/invert.png
MIME: application/octet-stream; encoding: Base64; length: 228
iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAIAAABvFaqvAAAAAXNSR0IArs4c
6QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAIlJREFUOMut1DESwCAIRFHKPRo3
5miUpDBjiHGirjq/5TUMSohs5oCanVLilJKgVQYO06qwUFFCYguqygj6ZQA3
02eag24lAQz0KKtQfu6uqvEB1qCiiMgWVJUtKCs81CgkBLQKA7023W0GGisz
EBxjZQjla5ysAxFKB3IwSgu9f0y2M0qEnFEiLoqGXOZZF5XhAAAAAElFTkSu
QmCC
[/patch]
4 Likes

I suppose this is useful for normal maps. :slight_smile: If the normalMap texture is baked in a different baker…

Oh great! So handy!!

Thank you

Sweat! :slight_smile:

Other useful features could be to swap channels of textures or even combine channels from different textures. A use case would be to pack a parallax map into the alpha channel of a normalmap, something the Lighting material already supports :slight_smile:

@mifth said:
I suppose this is useful for normal maps. :) If the normalMap texture is baked in a different baker...


Yeah, that's why I wanted it :D

@kwando That would be a bit more work to have some "choose the other texture" GUI, I don't know enough Netbeans to make that one easily.

There are a lot of fun things to do with an image in the SDK. One of the things I tried was to make operating on the image scriptable (JavaScript since that is built into the JDK). The use case for me was: I have a heightmap generator that spits out float arrays and I wanted to get a grey-scale preview and quickly be able to re-generate it when I changed input parameters to the generator in the JavaScript.
The bump I ran into was that I could not figure out how to make the script engine (executing in the SDK) have access to the classes in my project.

But coupled with your "mix channels from different images" would make for some really interesting tools for making terrain and splat maps.

Yay I have a patch that ended up in the SDK :slight_smile:



only problem is that this wasn’t applied on line 410:


  •    for (AbstractButton b : Arrays.asList(bumpSoft, bumpMedium, bumpStrong, gray, bright, spheremap)) {<br />
    
  •    for (AbstractButton b : Arrays.asList(bumpSoft, bumpMedium, bumpStrong, gray, bright, spheremap, invertAll, invertAlpha, invertRed, invertGreen, invertBlue)) {<br />
    

Still, you can enjoy the handsome menu even if nothing happens when you use it :D

Hah, my bad :wink: Guess thats why I didn’t announce it here yet :smiley:

Finally added the buttons to the list :wink:

2 Likes

Cool, thanks :slight_smile: