Solved

How do I write a colour-map rotation filter?

Posted on 1998-02-28
15
255 Views
Last Modified: 2008-02-01
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.
0
Comment
Question by:wagtail
  • 8
  • 7
15 Comments
 
LVL 16

Expert Comment

by:imladris
ID: 1233284
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
 

Author Comment

by:wagtail
ID: 1233285
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
 
LVL 16

Expert Comment

by:imladris
ID: 1233286
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
 

Author Comment

by:wagtail
ID: 1233287
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
 
LVL 16

Expert Comment

by:imladris
ID: 1233288
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
 

Author Comment

by:wagtail
ID: 1233289
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
 
LVL 16

Expert Comment

by:imladris
ID: 1233290
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
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 
LVL 16

Expert Comment

by:imladris
ID: 1233291
P.S. Have you actually tried using the ImageFilter approach? What happened?

0
 

Author Comment

by:wagtail
ID: 1233292
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
 

Author Comment

by:wagtail
ID: 1233293
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
 
LVL 16

Accepted Solution

by:
imladris earned 150 total points
ID: 1233294
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
 

Author Comment

by:wagtail
ID: 1233295
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
 
LVL 16

Expert Comment

by:imladris
ID: 1233296
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
 

Author Comment

by:wagtail
ID: 1233297
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
 

Author Comment

by:wagtail
ID: 1233298
woops - that third sentence should read "when canFilterIndexColorModel is *true*".

Too many late nights staring at the screen... 8^)
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

INTRODUCTION Working with files is a moderately common task in Java.  For most projects hard coding the file names, using parameters in configuration files, or using command-line arguments is sufficient.   However, when your application has vi…
This was posted to the Netbeans forum a Feb, 2010 and I also sent it to Verisign. Who didn't help much in my struggles to get my application signed. ------------------------- Start The idea here is to target your cell phones with the correct…
Viewers learn about the “for” loop and how it works in Java. By comparing it to the while loop learned before, viewers can make the transition easily. You will learn about the formatting of the for loop as we write a program that prints even numbers…
This theoretical tutorial explains exceptions, reasons for exceptions, different categories of exception and exception hierarchy.

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now