How do I write a colour-map rotation filter?

How do I write an ImageFilter that will rotate an Image Producer's colour map?

Ideally I'd like to be able to directly access the color map and shift the colour entries one to the right.

If this isn't possible, can I read the colour map into an array somehow?

Thanks.
wagtailAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

imladrisCommented:
An image filter looks like this:

class TransFilter extends RGBImageFilter
{      TransFilter()
      {      canFilterIndexColorModel=true;
            return;
      }

      public int filterRGB(int x,int y,int rgb)
      {      int a=rgb&0xff;
                                return(((rgb&0xffffff)>>8) | (a<<16));
      }
}

This one shifts the red, green and blue components one to the right. (Java uses a 24bit model internally). Since canFilterIndexColorModel is set to true, the runtime knows that the transformation is position independent, and will only call the filter for each different colour in the palette.

It can be  used like:

Image buf=tk.getImage(path+File.separator+f+".gif");
ImageFilter flt=new TransFilter();
ImageProducer p=new FilteredImageSource(buf.getSource(),flt);
pi=window.createImage(p);


0
wagtailAuthor Commented:
imladris,

Thanks for the detailed answer, but I already know this.

I don't want to just shift the colours of an individual palette entry... I want to take palette entry say, 10, and copy it into palette entry 9.

Basically I want to preserve all the image's original colours, but rotate them...

Sorry, but I must reopen the question.
0
imladrisCommented:
It seems to me that the only way to change the presentation,
without changing the data, is to twiddle the hardware (e.g. the
palette register, which is what your alluding to). However, Java
is agnostic about the hardware it runs on.

Furthermore what would be the advantage of introducing such a
hardware dependency in a case like this? It will not be noticably
faster (with canFilterIndexColorModel=true, it will only
manipulate the colormodel, not the whole image). The ColorModel
IS in a sense the palette. Nor does it give greater range of
options. Nor does it preserve the data any better. The filtered
image comes through the filter, the original is still there.

0
Bootstrap 4: Exploring New Features

Learn how to use and navigate the new features included in Bootstrap 4, the most popular HTML, CSS, and JavaScript framework for developing responsive, mobile-first websites.

wagtailAuthor Commented:
I had hoped this might be possible without twiddling any hardware - I definitely want to avoid hardware dependency!

I'm trying to create a "colour-map rotating applet". The idea is to implement a kind of palette animation in software, for small images.

The applet would paint, then rotate the colours using the filter, then paint again in a loop... giving the illusion of a living image.

I'd be using fractal images which have strictly ordered colour maps - the colours flow into each other gradually. The applet should use these and only these colours to create the flowing effect that I'm after.

Is this beyond the capabilities of the java.awt.image package? Maybe I should be looking at creating a special purpose image class?
0
imladrisCommented:
What is the problem with the ImageFilter approach? Is it not
rotating fast enough? Would it help to "precalculate"? How many
do you think you need? How big are they?

0
wagtailAuthor Commented:
The problem is that I can't read the colours in the image's original colour map, so I've no way of knowing what they are.

Speed isn't a problem (at the moment!), and no need to precalculate. We are talking about 196 colours or so.

I see two options. One, build my own image class which will read in gif colour map info. Two,  provide a set of default palettes to rotate. Option one is preferable as it will keep the applet small and handle the colours of any image it loads.
0
imladrisCommented:
Still confused. With the extension to the RGBImageFilter, your filter is handed every colour in the image one by one. You can then return any colour you like for each one. Doesn't that implicitly tell you what colours there are? Is it that you are dealing with a 24bit colour space, and changing from 0x000200 to 0x000100, for example, has no visible effect since there are only 256 colours displayed on the screen?

0
imladrisCommented:
P.S. Have you actually tried using the ImageFilter approach? What happened?

0
wagtailAuthor Commented:
OK... here's how I see it.

I'm using standard .gif files, 256 colours. I load in my image - it's a fractal, all shades of orange and yellow...
     image = getImage(getDocumentBase(), "images/snowman.gif");
     while (image.getHeight(null) < 0); //wait for image to load
      
then I create my filtered producer...
     ImageProducer producer = image.getSource();
     TestFilter filter = new TestFilter();
      filteredProducer = new FilteredImageSource(producer, filter);

...then I generate a new, filtered image, which replaces the old image...
     image = createImage(filteredProducer);

The filtering takes place in the TestFilter object's filterRGB() method...

     public int filterRGB(int x, int y, int rgb)
     {
          int a = rgb & 0xff;
          return( ((rgb & 0xffffff) >> 8) | (a << 16) );
     }

Every pixel in the original image is passed in here when I generate my new image.

Let's say there were only 3 different colours in the original .gif colour table - yellow, orange and red. Let's also say that the image itself is composed of three wide bands of each colour side by side - 20 yellow pixels, then 20 orange pixels, then 20 red pixels, repeating for 60 lines.

The filterRGB method above takes each pixel and shifts its rgb components one to the right. (In fact when I tried it it turned every pixel white). The filterRGB code example in the Java API documentation swaps the red and blue components, and would turn my hypothetical example into three shades of blue.

This isn't what I want to do though. I want to change my yellow band to an orange band, my orange band to a red band, and my red band to a yellow band. And I want to use the exact colours found in the original .gif file. It's no good applying an arbitrary formula to create the new colour - I need to get the next (or previous) colour in the .gif colour table, and return *that*.

I see that the RGBImageFilter has a "setColorModel" method, but there doesn't seem to be a corresponding "getColorModel", otherwise I could have maybe grabbed the filter's IndexedColorModel, rotated the r, g and b arrays inside it, constructed a new IndexedColorModel with the adjusted arrays and passed it back into the filter?
 
Strewth. This package... :o(

0
wagtailAuthor Commented:
OK... here's how I see it.

I'm using standard .gif files, 256 colours. I load in my image - it's a fractal, all shades of orange and yellow...
     image = getImage(getDocumentBase(), "images/snowman.gif");
     while (image.getHeight(null) < 0); //wait for image to load
      
then I create my filtered producer...
     ImageProducer producer = image.getSource();
     TestFilter filter = new TestFilter();
      filteredProducer = new FilteredImageSource(producer, filter);

...then I generate a new, filtered image, which replaces the old image...
     image = createImage(filteredProducer);

The filtering takes place in the TestFilter object's filterRGB() method...

     public int filterRGB(int x, int y, int rgb)
     {
          int a = rgb & 0xff;
          return( ((rgb & 0xffffff) >> 8) | (a << 16) );
     }

Every pixel in the original image is passed in here when I generate my new image.

Let's say there were only 3 different colours in the original .gif colour table - yellow, orange and red. Let's also say that the image itself is composed of three wide bands of each colour side by side - 20 yellow pixels, then 20 orange pixels, then 20 red pixels, repeating for 60 lines.

The filterRGB method above takes each pixel and shifts its rgb components one to the right. (In fact when I tried it it turned every pixel white). The filterRGB code example in the Java API documentation swaps the red and blue components, and would turn my hypothetical example into three shades of blue.

This isn't what I want to do though. I want to change my yellow band to an orange band, my orange band to a red band, and my red band to a yellow band. And I want to use the exact colours found in the original .gif file. It's no good applying an arbitrary formula to create the new colour - I need to get the next (or previous) colour in the .gif colour table, and return *that*.

I see that the RGBImageFilter has a "setColorModel" method, but there doesn't seem to be a corresponding "getColorModel", otherwise I could have maybe grabbed the filter's IndexedColorModel, rotated the r, g and b arrays inside it, constructed a new IndexedColorModel with the adjusted arrays and passed it back into the filter?
 
What d'you reckon?

0
imladrisCommented:
OK, I think I got it.

First a tangential point. If canFilterIndexColorModel is set to true, it will NOT in fact call the filter for every pixel. It will call it for every color (with x and y set to -1).

How about the following dodge:

First display the image using a "nothing" filter (i.e. it returns the rgb value it gets). However, what it does do, is note the values that go by in an array. You can collect an array containing each different value the image uses.

Then to rotate, you use a different filter that compares the incoming rgb value to the values in the array, and returns a value from some fixed (for this display run) offset further down the array.

For the next image you could increase the "fixed" offset mod the number of elements in the array.


0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
wagtailAuthor Commented:
Thanks. This looks good, but there are some problems...

The "zero" filter will produce an array of pixel colours, the size of the original image.
 
For the applet to be fast enough, I need to group all the pixel colours into a 256 element array which will represent the image's colour map.

The image's pixels, however, know nothing of the *order* of the colours in the original colour map. Therefore, although it is possible to recreate the *colours* in the colour map by this method, it is not possible to arrange them in the right order.

Without the right order, the animated colours will not flow into each other - they'll jump about all over the place at random.

I'm going to experiment with writing an image class which will allow direct access to the image's original colour map. I'll then pass the map to a custom filter.

Thanks for your efforts. This has turned out to be a tricky question, and your input has been helpful.
0
imladrisCommented:
Had another stray thought. If you set canFilterIndexColorModel to false for the "nothing" filter, then you WOULD get positional information with the colors. That might allow you to sort it (based on the y value for instance). Would that help?

0
wagtailAuthor Commented:
Yes it might - thanks for this.

However, I've just found a really great solution - I override RGBFilterIndex's filterIndexColorModel() method. It actually does the colour model filtering when canFilterIndexColorModel is false. Takes the original colour model as input,
puts the 256 colour entries through filterRGB with (-1, -1) for positional data,
and then outputs a new, altered colour model.

I make filterRGB just pass the rgb value straight through unchanged, but plug
my rotation code straight into filterIndexColorModel(). Works a treat!


0
wagtailAuthor Commented:
woops - that third sentence should read "when canFilterIndexColorModel is *true*".

Too many late nights staring at the screen... 8^)
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Java

From novice to tech pro — start learning today.