Headless support

So I developed an image resizing class and successfully tested it on local Windows environment. However, as soon as I tested this code on our Linux webserver, I started receiving x server connect errors. I did some research and discovered this was because the linux webserver is headless.

After doing more research, I found that in headless mode support has been available since the J2SE 1.4 platform. So, I set the headless mode system property to be true and my code still won't run. Now, instead of Tomcat shutting down with the x server connect error, I simply get Headless exceptions thrown.

I read stuff like, " Instead of setting up a dummy X server like Xvfb, just put the parameter "-Djava.awt.headless=true" in your Java invocation line, and that's it! Life is good." I'm confused, all this parameter seems to do is cause my code to throw an exception instead of completely bombing out. Methods such as:

java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment()

still don't seem like they can run in headless mode. So what purpose does it actually serve? Please help!

[1115 byte] By [theboogster100a] at [2007-11-26 20:17:04]
# 1

getLocalGraphicsEnvironment is not supposed to throw headless exception, if it does, it's a bug.

It would help if you posted the exact exception you're getting.

However, with headless toolkit you obviously will not be able to use some of the api (like any of the GUI stuff).

But you should be able to do rendering to offscreen images (BufferedImages), use ImageIO to load/write.

Dmitri

trembovetskia at 2007-7-10 0:40:06 > top of Java-index,Security,Cryptography...
# 2

Thank you for getting back to me. Alright, here are the details. First my code:

public class ImageScale {

public static void scale(File inFile, String photoDir) {

try {

FileInputStream fs = new FileInputStream(inFile);

JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(fs);

BufferedImage srcImg = decoder.decodeAsBufferedImage();

fs.close();

JPEGDecodeParam param = decoder.getJPEGDecodeParam();

int width = param.getWidth();

scaleHelper(width, 150, photoDir, srcImg, inFile);

}

catch (Exception e) {

System.out.println (e);

}

}

public static void scaleHelper(int width, int size, String photoDir, BufferedImage srcImg, File inFile) {

try {

double scale = calculateScale(width, size);

FileOutputStream out = new FileOutputStream (new File (photoDir + "/" + PicUploader.getPictureFileName(inFile.getName(),Integer.toString(size))));

Image img = getScaledInstance(srcImg, scale, getDefaultConfiguration());

BufferedImage biImg = toBufferedImage(img, BufferedImage.TYPE_INT_RGB);

JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out,JPEGCodec.getDefaultJPEGEncodeParam(biImg));

encoder.encode(biImg);

out.close();

}

catch (Exception e) {

System.out.println (e);

}

}

public static double calculateScale(int length, int limit) {

double scale;

if (length < limit) {

scale = 1d;

} else {

scale = (double)limit/(double)length ;

}

return scale;

}

public static GraphicsConfiguration getDefaultConfiguration() {

GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();

GraphicsDevice gd = ge.getDefaultScreenDevice();

return gd.getDefaultConfiguration();

}

public static BufferedImage copy(BufferedImage source, BufferedImage target, Object interpolationHint) {

Graphics2D g = target.createGraphics();

g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolationHint);

double scalex = (double) target.getWidth() / source.getWidth();

double scaley = (double) target.getHeight() / source.getHeight();

AffineTransform at = AffineTransform.getScaleInstance(scalex, scaley);

g.drawRenderedImage(source, at);

g.dispose();

return target;

}

public static BufferedImage getScaledInstance2D(BufferedImage source, double factor, Object interpolationHint, GraphicsConfiguration gc) {

if (gc == null)

gc = getDefaultConfiguration();

int w = (int) (source.getWidth() * factor);

int h = (int) (source.getHeight() * factor);

int transparency = source.getColorModel().getTransparency();

return copy(source, gc.createCompatibleImage(w, h, transparency), interpolationHint);

}

public static Image getScaledInstanceAWT(BufferedImage source, double factor, int hint) {

int w = (int) (source.getWidth() * factor);

int h = (int) (source.getHeight() * factor);

return source.getScaledInstance(w, h, hint);

}

public static Image getScaledInstance(BufferedImage source, double factor, GraphicsConfiguration gc) {

if (factor >= 1.0)

return getScaledInstance2D(source, factor, RenderingHints.VALUE_INTERPOLATION_BICUBIC, gc);

else

return getScaledInstanceAWT(source, factor, Image.SCALE_AREA_AVERAGING);

}

public static BufferedImage toBufferedImage(Image image, int type) {

int w = image.getWidth(null);

int h = image.getHeight(null);

BufferedImage result = new BufferedImage(w, h, type);

Graphics2D g = result.createGraphics();

g.drawImage(image, 0, 0, null);

g.dispose();

return result;

}

}

Really, right now, I'm only trying to create thumbnails on the server so only the getScaledInstance2D method is being invoked. Like I said, originally, I was getting the x server connection error. But, I added the headless attribute to my startup scripts and now I receive the following exception:

java.awt.HeadlessException

I don't understand what the headless attribute does then? Does anyone see a way I could change my code so that this problem doesn't happen on the server.

On a related note, I've tried using Xvfd without success also. I have a process running in the bg:

root25078 24923 0 21:48 pts/200:00:00 /usr/X11R6/bin/Xvfb :10 -screen 0 1152x900x8

And the DISPLAY var set to the correct server slot:

# echo $DISPLAY

localhost:10.0

And this doesn't seem to work either. Please help!

theboogster100a at 2007-7-10 0:40:06 > top of Java-index,Security,Cryptography...
# 3

The problem with your code is that you're trying to use GraphicsDevice/GraphicsConfiguration which would not work in headless mode, so there's no point in trying to create a "compatible" image.

Just create a BufferedImage with the same color model as your source image.

So my suggestion:

1. use javax.imageio.ImageIO for loading/writing images images

2. do not work with compatible images, they only make sense if you have a screen device (which they are compatible with) you copy them to, deal with BufferedImages instead.

BTW, using ImageIO you can use the thumbnails embedded in the image files directly, without loading the whole image into memory.

Check for ImageIO tutorial.

Dmitri

dmitri_trembovetskia at 2007-7-10 0:40:06 > top of Java-index,Security,Cryptography...