I make an introduction of the scenario:
A web service (SpringMVC) through an action with parameters dynamically generate images with text and returns the response to the client.
This service processes about 500 images per minute.
The images are generated with the library SWT [1]. This works fine locally.
To test or production environments, the application is installed on a server without X (CentOS / Ubuntu). And that SWT can draw the images requires the DISPLAY environment variable set correctly. So on the server install Xvfb package to emulate an X environment virtually.
Xvfb: 1-screen 0 1x1x24-dpi 96 &
DISPLAY = localhost: 1.0
export DISPLAY
$TOMCAT/bin/startup.sh
This works fine the first few minutes, but eventually the memory occupied by the Xvfb process grows without limit (from 1 mb to 1.3 Gb and growing ...).
I tried with different configurations and parameters Xvfb [3], but have not had success.
Xvfb: 1-screen 0 1x1x24 -dpi 96 -noreset &
Xvfb: 1-screen 0 1x1x24 -dpi 96 -reset &
Xvfb: 1-screen 0 1x1x24 -dpi 96 -ld 262144 -ls 262144 -lf 1024 &
Took several days with this problem without a solution?
I could guide you more try or where freshened?
[1]
public BufferedImage drawImage () {
// example code, real code is more complex
FontData [] FontData fontData = new [] {new FontData ("Arial", 8, SWT.NORMAL)};
Display display = this.getDisplay ();
Image image = new Image (display, IMAGE_WIDTH, IMAGE_HEIGHT);
GC gc = new GC (image);
gc.setAntialias (SWT.ON);
gc.setInterpolation (SWT.HIGH);
gc.setBackground (display.getSystemColor (SWT.COLOR_WHITE));
gc.fillRectangle (0, 0, this.image.getBounds (). width, this.image.getBounds (). height);
gc.setFont (new Font (display, fontData [0]));
gc.setForeground (display.getSystemColor (SWT.COLOR_RED));
gc.drawText ("Text to draw in image", 5, 6);
BufferedImage bi = null;
bi = this.convertToAWT (hi.getImage (). getImageData ());
return bi;
}
#RequestMapping
public void RetrieveImage (HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType ("image / png");
BufferedImage image = drawImage ();
ByteArrayOutputStream os = new ByteArrayOutputStream ();
ImageIO.write (bi, "png", os);
InputStream is = new ByteArrayInputStream (os.toByteArray ());
IOUtils.copy (is, response.getOutputStream ());
}
Update:
Add getDisplay method.
private Display getDisplay() throws DrawImageException {
if (display == null || display.isDisposed()) {
LOGGER.debug("Initializing display...");
try {
display = Display.getDefault();
} catch (Exception e) {
throw new DrawImageException("Can't get default display", e);
}
}
return display;
}
Solved
As Baz and Niranjan said, the problem was with the release of SWT resources. Now work fine.
Related
I am facing a problem taking screenshots from Java on Linux with transparent windows.
The problem is that the screenshot taken with Robot deals with transparent windows as if they were opaque.
It is very similar to the problem stated at: Taking a screenshot in Java on Linux?
I wonder if there is any satisfactory solution to avoid this problem.
This is the code I use to take the screenshots:
protected BufferedImage getScreenShot()
{
BufferedImage screenShotImage = null;
try
{
screenShotImage = new Robot().createScreenCapture(new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()));
}
catch( Exception ex )
{
ex.printStackTrace();
}
return( screenShotImage );
}
The code to get the screenshot is the following (at the derived JFrame class):
public void M_repaint( )
{
long timeStamp = System.currentTimeMillis();
if( ( timeStamp - _lastScreenShotTimeStamp ) > 4000 )
{
updateAlpha( 0.0f );
SwingUtilities.invokeLater( new Runnable(){
#Override
public void run()
{
BufferedImage image = getScreenShot();
try
{
ImageIO.write(image, "png", new File( "robotScreenshotBefore.png"));
}
catch( Exception ex )
{
ex.printStackTrace();
}
try
{
String[] cmd = { "./lens.screenshot.sh" };
Process script_exec = Runtime.getRuntime().exec(cmd);
script_exec.waitFor();
}
catch( Exception ex )
{
ex.printStackTrace();
}
image = getScreenShot();
try
{
ImageIO.write(image, "png", new File( "robotScreenshotAfter.png"));
}
catch( Exception ex )
{
ex.printStackTrace();
}
_lensJPanel.setScreenShotImage( image );
updateAlpha( 1.0f );
}
});
_lastScreenShotTimeStamp = timeStamp;
}
repaint();
}
The script ./lens.screenshot.sh has the following contents:
#/bin/bash
rm gnome-screenshot.png
gnome-screenshot --file="gnome-screenshot.png"
The application is a magnifying lens.
The way the application works is that every time the window (the lens) changes its position on the screen, the function M_repaint( ) is called.
Inside that function there is a kind of timer, that makes that when 4 seconds have elapsed from last screenshot, a new screenshot is taken in case the window appearence has changed
Previously to take the screenshot, the JFrame in made invisible, so that it does not appear inside the screenshot itself.
But once the window has been painted on the screen, it appears in the screenshot even if it had been made invisible previously.
I attach one of the sets of screenshots taken from the application with the previus code ( robotScreenshotBefore.png, gnome-screenshot.png and robotScreenshotAfter.png)
I have updated the information on the question, and I will also attach the screenshots taken from a Linux machine
As we can see the first screenshot (the one that happens in a normal execution), shows the window just made transparent.
The following two screenshots show the window correctly made invisible (the first of them is taken directly from Linux and the last one, is taken with Robot, after having invoked the gnome screenshot tool)
The problem is that the application cannot wait for so much time before taking the screenshot, as this waiting time is showed as an anoying flicker.
robotScreenshotBefore.png
gnome-screenshot.png
robotScreenshotAfter.png
Finally the solution found was to wait for some milliseconds for the transparency to take effect before taking the screenshot, in case the OS was not Windows.
So, the final function used to paint is the following:
public void M_repaint( )
{
long timeStamp = System.currentTimeMillis();
if( ( timeStamp - _lastScreenShotTimeStamp ) > 4000 )
{
updateAlpha( 0.0f );
SwingUtilities.invokeLater( new Runnable(){
#Override
public void run()
{
if( !OSValidator.isWindows() )
{
try
{
Thread.sleep( 26 ); // if mac or linux (and may be others), give enough time for transparency to take effect.
}
catch( Exception ex )
{
ex.printStackTrace();
}
}
BufferedImage image = getScreenShot();
_lensJPanel.setScreenShotImage( image );
updateAlpha( 1.0f );
}
});
_lastScreenShotTimeStamp = timeStamp;
}
repaint();
}
When I simply create a new image from another like this:
public static void scaleByTwoRight(String src, String dest)
throws IOException {
BufferedImage bsrc = ImageIO.read(new File(src));
int width = bsrc.getWidth()/2;
int height = bsrc.getHeight();
BufferedImage bdest = bsrc.getSubimage(width, 0, width, height);
ImageIO.write(bdest,"PNG",new File(dest));
}
Source file (src) = C:...\Manga\Shonan Juna_ Gumi Tome 11\Shonan Junaï Gumi Tome 11 - 091B.png
Destination file (dest) = C:...\Manga\Shonan Junaï Gumi Tome 11 - 091B_A.png
Example of generated file: https://docs.google.com/file/d/0B1vKCZzB5hxqYzNsUWF5RHA2Wm8/edit?usp=sharing
Problem: The new image has mimetype: application instead of mimetype: image
How I arrive to this conclusion: I'm using a function to test if the file is an image or not:
public static boolean isImage(String src)
throws IOException {
File f = new File(src);
String mimetype= new MimetypesFileTypeMap().getContentType(f);
String type = mimetype.split("/")[0];
if(type.equals("image")){
return true;
}else{
System.out.println("mimetype: "+type);
return false;
}
}
It has not a huge impact if the Mime-type is not correct but I prefer to have that working properly..
Thanks for your help!
Note:
I'm running under Windows 7 / 32b
JVM 1.7 / Eclipse Helios
Your code is working fine in my machine.
I have windows XP,32 bit,
Tried with jpeg image and it is returning the mimetype as image/jpeg only.
Hope you are not trying to execute both the functions simultaneously.
Also the destination file name should contain proper extension like .jpeg or. png etc...
I am using Java port of ImageMagick called JMagick .I need to be able to create a new image and write an arbitrary text chunk into it.The docs are very poor and what I managed to get so far is to write text into the image which comes from IO.Also , in all the examples I have found it seems like the very first operation ,before writing new image data , is always loading of an existing image into ImageInfo instance.How do I create an image from scratch with JMagick and then write a text into it?
Here is what I do now :
try {
ImageInfo info = new ImageInfo();
info.setSize("512x512");
info.setUnits(ResolutionType.PixelsPerInchResolution);
info.setColorspace(ColorspaceType.RGBColorspace);
info.setBorderColor(PixelPacket.queryColorDatabase("red"));
info.setDepth(8);
BufferedImage img = new BufferedImage(512,512,BufferedImage.TYPE_4BYTE_ABGR);
byte[] imageBytes = ((DataBufferByte) img.getData().getDataBuffer()).getData();
MagickImage mimage = new MagickImage(info,imageBytes);
DrawInfo aInfo = new DrawInfo(info);
aInfo.setFill(PixelPacket.queryColorDatabase("green"));
aInfo.setUnderColor(PixelPacket.queryColorDatabase("yellow"));
aInfo.setOpacity(0);
aInfo.setPointsize(36);
aInfo.setFont("Arial");
aInfo.setTextAntialias(true);
aInfo.setText("JMagick Tutorial");
aInfo.setGeometry("+40+40");
mimage.annotateImage(aInfo);
mimage.setFileName("text.jpg");
mimage.writeImage(info);
} catch (MagickException ex) {
Logger.getLogger(LWJGL_IDOMOO_SIMPLE_TEST.class.getName()).log(Level.SEVERE, null, ex);
}
It doesn't work , the JVM crashes with access violation as it probably expects for the input image from IO.
I understand that it may be too late for the answer.Here I wrote this simple code to create a scenario of what you asked.!
private void createEmptyImage() throws MagickException{
ImageInfo newImageiInfo=new ImageInfo();
newImageiInfo.setFileName("src\\main\\resources\\test.jpg");
newImageiInfo.setSize("512x512");
newImageiInfo.setUnits(ResolutionType.PixelsPerInchResolution);
newImageiInfo.setColorspace(ColorspaceType.RGBColorspace);
newImageiInfo.setBorderColor(PixelPacket.queryColorDatabase("red"));
newImageiInfo.setDepth(8);
MagickImage addTextImage = new MagickImage();
addTextImage.allocateImage(newImageiInfo);
addTextImage.setYResolution(480);
addTextImage.setXResolution(640);
addTextImage.writeImage(newImageiInfo);
DrawInfo aInfo = new DrawInfo(newImageiInfo);
aInfo.setFill(PixelPacket.queryColorDatabase("green"));
aInfo.setUnderColor(PixelPacket.queryColorDatabase("yellow"));
aInfo.setOpacity(0);
aInfo.setPointsize(36);
aInfo.setFont("Arial");
aInfo.setTextAntialias(true);
aInfo.setText("JMagick Tutorial");
aInfo.setGeometry("+50+50");
addTextImage.annotateImage(aInfo);
addTextImage.setFileName("src\\main\\resources\\test-result.jpg");
addTextImage.writeImage(newImageiInfo);
}
Here is a Clojure example to create a blue image using JMagick:
(import '[magick MagickImage ImageInfo ColorspaceType])
(def image (MagickImage.))
(.constituteImage image 256 256 "RGB" (byte-array (take (* 3 256 256) (cycle [0 0 255]))))
(def info (ImageInfo.))
(.setSize info "256x256")
(.setDepth info 8)
(.setColorspace info ColorspaceType/RGBColorspace)
(.setFileName image "test.jpg")
(.writeImage image info)
I want to compress the "JPG" images,which are about 4M or more.here is my codes:
public static void Compress(String sourceFolder,String destFolder,double proportion) throws IOException
{
File source=new File(sourceFolder);
File[] sourceFiles=null;
if(source.isDirectory())
{
sourceFiles=source.listFiles();
for(int i=0;i<sourceFiles.length;i++)
{
String name="";
javax.imageio.ImageIO.setUseCache(false);
Image src = javax.imageio.ImageIO.read(sourceFiles[i]);
name=sourceFiles[i].getName();
int width=src.getWidth(null);
int height=src.getHeight(null);
destWidth=(int) (height*proportion);
destHeight=(int) (width*proportion);
BufferedImage tag=new BufferedImage(destWidth,destHeight,BufferedImage.TYPE_INT_RGB);
Graphics g = tag.getGraphics();
g.drawImage(src, 0, 0, destWidth, destHeight, null);
src.flush();
src=null;
FileOutputStream out = new FileOutputStream(destFolder+"/"+name);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(tag);
out.close();
}
}
else
System.exit(0);
}
When it runs
Image src = javax.imageio.ImageIO.read("filename");
Exception occured:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.awt.image.DataBufferByte.<init>(DataBufferByte.java:58)
at java.awt.image.ComponentSampleModel.createDataBuffer(ComponentSampleModel.java:397)
at java.awt.image.Raster.createWritableRaster(Raster.java:938)
at javax.imageio.ImageTypeSpecifier.createBufferedImage(ImageTypeSpecifier.java:1056)
at javax.imageio.ImageReader.getDestination(ImageReader.java:2879)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:943)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:915)
at javax.imageio.ImageIO.read(ImageIO.java:1422)
at javax.imageio.ImageIO.read(ImageIO.java:1282)
at functions.CompressImage.Compress(CompressImage.java:50)
at functions.CompressImage.main(CompressImage.java:24)
I tried the run arguments(-Xms=1g),it still doesn't work!
Who knows the solution? Please help me,thank you!
you need to get heap dump and analyze it. so the simplest way is to add JVM params like
-XX:+HeapDumpOnOutOfMemoryError
This will automatically create heap dump/ Later you can analyze what's wrong using java profilers(yourkit,jprofiler, etc)
A 4MB JPG will result in a huge BitMap File. I think, it will just need a lot of memory. I ofte read about large memory-sonsumption in javax.imagio.
To get the bitmap size, calculate image_X * image_Y * (8 to 10 bit * 3(colors))
update
Some Math:
I assume 8bit per colorchannel:
7000 * 4900 * 8 * 3 = 1029000000 bit
= 122MB
I beleave, there has to be a byte[] of 122MB within the Memory. If the operating system (not the JVM) can't create that memory block, you'll get that exception.
I am using a Java applet to take a screenshot of the web browser, using Java's Robot class.
Robot objRobot = new Robot ();
BufferedImage objBufferedImage = objRobot.createScreenCapture(objRectArea);
The thing works good in Windows system, taking screenshot. But in case of Mac OS X I get a blank image.
When I check the event viewer, I see the following error:
invalid context
invalid pixel format
CoreAnimation: rendering error 506
The problem is occurring for all the browsers Safari, Firefox and Chrome. My applet is a signed applet.
What might be the reason?
My machine configuration is as follows:
OS : MAC OS X
Version : 10.6.4
I've sent the error message invalid pixel format to google and received a long list of results (close to 10.000) - it looks as if the problem is not a Java problem but a configuration issue on your Mac.
Try to change display resolutions and re-run your applet. Good chance, that the error is linked to some screen resolutions (external display?). Some suggestions on the web were to fully update you OSX.
dir Robot objRobot = null;
try
{
objRobot = new Robot();
} catch(Exception ex)
{
}
Dimension screenDim = Toolkit.getDefaultToolkit().getScreenSize();
BufferedImage objBufferedImage = objRobot.createScreenCapture(new Rectangle(0, 0, (int)screenDim.getWidth(), (int)screenDim.getHeight()));
int areaToExportWidth = 1024;
int areaToExportHeight = 768;
//Create the image
BufferedImage exportImage =objRobot.createScreenCapture(new Rectangle(0, 0, (int)screenDim.getWidth(), (int)screenDim.getHeight()));
//Get graphics - Get the layer we can actually draw on
Graphics2D imageGraphics = (Graphics2D) exportImage.getGraphics();
//Cleanup after ourselves
imageGraphics.dispose();
//Setup to write the BufferedImage to a file
String pathToFile = "dir";
File outputDirectory = new File(pathToFile);
File outputFile = new File(pathToFile+"\\"+counter+"MyImage.png");
//Here we make sure the directory exists.
/*
* Returns TRUE if:
* The directory is MISSING
* and/or the directory IS NOT a directory
*/
if(!outputDirectory.exists() || !outputDirectory.isDirectory()){
outputDirectory.mkdirs(); //Make the directory
} // Else do nothing
//Write the file
try { //Attempt the write
ImageIO.write(exportImage, "png", outputFile);
} catch (IOException e) { //For some reason it failed so...
e.printStackTrace(); //... why did it fail?
}