Skip to main content
GameDev.net gamedev.net
🔒 Locked

[java] Generating transparent images using createImage() in Java 1.1.8

Started by HairyTroll Aug 22, 2003 at 5:08 PM 7 replies 3.5k views
Original Post
HairyTroll
HairyTroll
I''m developing an applet based game and have thus far been developing using Java 1.4. I am generating a lot of images on the fly using Component.createImage(). I implement transparency by overwriting the background (using pixelGrabber) with all pixels not equal to 0. This works just fine and is fast enough using the 1.4 VM, however it is dog slow when running within a browser as I am limited to the old 1.1.8 VM. I know I can use GIF''s for transparency, however, as I say, I am generating a lot of images on the fly (blitting numbers over sprites etc.). Is there a way to create a ''simulated gif'' within an applet ? i.e. use the indexed color space to create an image so that Java thinks that a normal gif with transparency is being used ?
CaptainJester
CaptainJester
I think you have to use BufferedImage and ColorModel etc. I don''t know if they existed in v1.1.8 though.



First make it work,
then make it fast.

--Brian Kernighan

"I’m happy to share what I can, because I’m in it for the love of programming. The Ferraris are just gravy, honest!" --John Carmack: Forward to Graphics Programming Black Book
"None of us learn in a vacuum; we all stand on the shoulders of giants such as Wirth and Knuth and thousands of others. Lend your shoulders to building the future!" - Michael Abrash[JavaGaming.org][The Java Tutorial][Slick][LWJGL][
HairyTroll
HairyTroll
quote:
Original post by CaptainJester
I think you have to use BufferedImage and ColorModel etc. I don''t know if they existed in v1.1.8 though.



BufferedImage is exactly what I need, unfortunately it was added after 1.1.8. It''s not supported in the Microsoft VM unfortunately.

-Luke
CaptainJester
CaptainJester
It looks like you can use the following combination with that version:

Toolkit.createImage(ImageProducer producer)
- You then write a class that implements ImageProducer
- An ImageConsumer will be registered with your ImageProducer
- On the ImageConsumer you call
setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize);
- you then use the IndexColorModel to specify a transparent bit and a color table. IndexColorModel is shown below.


IndexColorModel
public IndexColorModel(int bits,
int size,
byte[] cmap,
int start,
boolean hasalpha,
int trans)
Constructs an IndexColorModel from a single array of interleaved red, green, blue and optional alpha components. The specified transparent index represents a pixel that is considered entirely transparent regardless of any alpha value specified for it. The array must have enough values in it to fill all of the needed component arrays of the specified size. The ColorSpace is the default sRGB space. The transparency value is Transparency.TRANSLUCENT if hasAlpha is true; otherwise it is Transparency.BITMASK if trans is a valid index into the colormap (between 0 and size - 1) or Transparency.OPAQUE if trans is not a valid index. The transfer type is the smallest of DataBuffer.TYPE_BYTE or DataBuffer.TYPE_USHORT that can hold a single pixel.

Parameters:
bits - the number of bits each pixel occupies
size - the size of the color component arrays
cmap - the array of color components
start - the starting offset of the first color component
hasalpha - indicates whether alpha values are contained in the cmap array
trans - the index of the fully transparent pixel
Throws:
IllegalArgumentException - if bits is less than 1 or greater than 16
IllegalArgumentException - if size is less than 1


I haven''t tried it yet, but it doesn''t look to hard. Just read the API docs on the classes above and you should be able to figure it out.



First make it work,
then make it fast.

--Brian Kernighan

"I’m happy to share what I can, because I’m in it for the love of programming. The Ferraris are just gravy, honest!" --John Carmack: Forward to Graphics Programming Black Book
"None of us learn in a vacuum; we all stand on the shoulders of giants such as Wirth and Knuth and thousands of others. Lend your shoulders to building the future!" - Michael Abrash[JavaGaming.org][The Java Tutorial][Slick][LWJGL][
CaptainJester
CaptainJester
Here is a working example:

ImageProducer

import java.awt.image.*;
import java.util.Vector;

public class MyImage implements ImageProducer {
Vector list=new Vector();
IndexColorModel icm;
int cmap[]=new int[256];
int pixels[]=new int[400];

public MyImage() {
int temp;
cmap[0]=0;
cmap[1]=0xff00ff00;
for(int i=2;i<256;i++) {
cmap[i]=(int)(Math.random()*16777216.0)|0xff000000;
}
icm=new IndexColorModel(8,256,cmap,0,true,0,DataBuffer.TYPE_USHORT);
for(int i=0;i<400;i++) {
temp=i%20;
if(temp==0 || temp==1 || temp==18 || temp==19 || i<40 || i>=360) {
pixels[i]=1;
}
else {
pixels[i]=0;
}
}
}
public void addConsumer(ImageConsumer ic) {
if(ic!=null) {
list.add(ic);
ic.setDimensions(20,20);
ic.setHints(ImageConsumer.SINGLEPASS);
ic.setPixels(0,0,20,20,icm,pixels,0,20);
ic.imageComplete(ImageConsumer.STATICIMAGEDONE);
}
}
public boolean isConsumer(ImageConsumer ic) {
if(ic!=null) {
return list.contains(ic);
}
else {
return false;
}
}
public void removeConsumer(ImageConsumer ic) {
if(ic!=null) {
if(list.contains(ic)) {
list.remove(ic);
}
}
}
public void requestTopDownLeftRightResend(ImageConsumer ic) {}
public void startProduction(ImageConsumer ic) {
ImageConsumer temp;
if(ic!=null) {
list.add(ic);
for(int i=0;i<list.size();i++) {
temp=(ImageConsumer)list.get(i);
temp.setDimensions(20,20);
temp.setHints(ImageConsumer.SINGLEPASS);
temp.setPixels(0,0,20,20,icm,pixels,0,20);
temp.imageComplete(ImageConsumer.STATICIMAGEDONE);
}
}
}
}


Test program

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Transparent extends Frame implements KeyListener {
Image im,buffer;
Dimension screen,image;
Graphics gr,gbuf;
static Point pos=new Point(20,20);
int maxX,maxY;
int startX,startY;
Insets border;

public Transparent() {
setResizable(false);
im=Toolkit.getDefaultToolkit().createImage(new MyImage());
MediaTracker t=new MediaTracker(this);
t.addImage(im,1);
try {
screen=Toolkit.getDefaultToolkit().getScreenSize();
t.waitForAll();
}
catch(Exception e) {
e.printStackTrace();
}
image=new Dimension(im.getWidth(null),im.getHeight(null));
setSize(screen);
setVisible(true);
border=getInsets();
maxX=screen.width-(image.width+border.right+border.left);
maxY=screen.height-(image.height+border.bottom+border.top);
startX=border.left;
startY=border.top;
buffer=createImage(screen.width-(border.right+border.left),screen.height-(border.bottom+border.top));
addKeyListener(this);
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}

public void update(Graphics g){
paint(g);
}
public void paint(Graphics g){
if(buffer!=null) {
gbuf=buffer.getGraphics();
}
if(g!=null && gbuf!=null) {
gbuf.setColor(Color.blue);
gbuf.fillRect(0,0,maxX+image.width,maxY+image.height);
gbuf.drawImage(im,pos.x,pos.y,null);
g.drawImage(buffer,startX,startY,this);
}
}

public void keyTyped(KeyEvent e){}
public void keyPressed(KeyEvent e) {
int code=e.getKeyCode();
if(code==KeyEvent.VK_ESCAPE) {
System.exit(0);
}
else if(code==KeyEvent.VK_UP) {
pos.y-=5;
}
else if(code==KeyEvent.VK_LEFT) {
pos.x-=5;
}
else if(code==KeyEvent.VK_DOWN) {
pos.y+=5;
}
else if(code==KeyEvent.VK_RIGHT) {
pos.x+=5;
}

if(pos.x<0) {
pos.x=0;
}
else if(pos.x>maxX) {
pos.x=maxX;
}
if(pos.y<0) {
pos.y=0;
}
else if(pos.y>maxY) {
pos.y=maxY;
}
repaint();
}
public void keyReleased(KeyEvent e){}
public static void main(String args[]) {
Transparent c=new Transparent();
c.repaint();
}
}




First make it work,
then make it fast.

--Brian Kernighan

"I’m happy to share what I can, because I’m in it for the love of programming. The Ferraris are just gravy, honest!" --John Carmack: Forward to Graphics Programming Black Book
"None of us learn in a vacuum; we all stand on the shoulders of giants such as Wirth and Knuth and thousands of others. Lend your shoulders to building the future!" - Michael Abrash[JavaGaming.org][The Java Tutorial][Slick][LWJGL][
HairyTroll
HairyTroll
quote:
Original post by CaptainJester
Here is a working example:



Whew... thanks very much for the tutorial on creating a custom ImageProducer This is something I am about to get into.

The function that would be most useful, and which Java 1.1.8 does not allow for, is creating a graphics context from such an ImageProducer. This would allow text to be blitted directly onto the image using e.g.


Graphics g = image_from_custom_producer.getGraphics();
g.drawString(str, 0, ascent);


As it stands in Java 1.1.8, in order to write text over an image you have write the text into a new image:


Image textImage = c.createImage(width, height);
Graphics g = textImage.getGraphics();

// Initialize image to pure black. This will allow
// us to overlay everything other than the black background
// onto an image.
g.setColor(new Color(0, 0, 0));
g.fillRect(0, 0, width, height);

g.setFont(font);
g.setColor(color);
g.setPaintMode();
g.drawString(str, 0, ascent);


(The new image unfortunately takes the current background color and is therefore not transparent).

Then grab the pixels from the text image and the original image using pixerGrabber and do a byte by byte comparison, overwritting pixels in the original image with all pixels from the text image that are not e.g. Color(0, 0, 0).

Then a new image has to be created from the pixel array.

Quite some work-around, and it eats up a lot of cycles especially when overlaying a lot of text onto a large image.

-Luke
CaptainJester
CaptainJester
Try using ImageProducer to produce your transparent image, then getGraphics on the produced image. Then do g.drawString to the transparent image. Then draw the transparent image to the screen. Since you are not loading the image into the ImageProducer every cycle, it should be fairly quick. So you can use the transparent image as sort of a back buffer. Though you will still have to clear the main background. Or use a real backbuffer and clear it.



First make it work,
then make it fast.

--Brian Kernighan

"The problems of this world cannot possibly be solved by skeptics or cynics whose horizons are limited by the obvious realities. We need men and women who can dream of things that never were." - John Fitzgerald Kennedy(35th US President)
"None of us learn in a vacuum; we all stand on the shoulders of giants such as Wirth and Knuth and thousands of others. Lend your shoulders to building the future!" - Michael Abrash[JavaGaming.org][The Java Tutorial][Slick][LWJGL][
HairyTroll
HairyTroll
quote:
Original post by CaptainJester
Try using ImageProducer to produce your transparent image, then getGraphics on the produced image.



If only...

getGraphics() only works on off-screen images. And in Java 1.1.8. the only method capable of creating an offscreen image is createImage(int width, int height)

Calling getGraphics() on an image created using any kind of Producer fails miserably.

I''m not sure if this was deliberate on Sun''s part, or simply an oversight.

-Luke
CaptainJester
CaptainJester
It was probably deliberate. Just create a backbuffer, clear the background to your colour, then copy your transparent image, then do your text.(If you have already thought of this, just ignore this post )



First make it work,
then make it fast.

--Brian Kernighan

"The problems of this world cannot possibly be solved by skeptics or cynics whose horizons are limited by the obvious realities. We need men and women who can dream of things that never were." - John Fitzgerald Kennedy(35th US President)
"None of us learn in a vacuum; we all stand on the shoulders of giants such as Wirth and Knuth and thousands of others. Lend your shoulders to building the future!" - Michael Abrash[JavaGaming.org][The Java Tutorial][Slick][LWJGL][

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.