Related
I've got an application window using JavaFX.
This window contains a simple WebView to display a HTML document.
Inside the HTML document, there is a script tag, executing a Java function, which returns the pixels as int[].
I'm using the following code to draw the image onto the canvas:
var context = canvas.getContext('2d');
var imageData = context.createImageData(canvas.width, canvas.height);
var buffer8 = new Uint8ClampedArray(imageData.data.buffer);
var buffer32 = new Uint32Array(imageData.data.buffer);
buffer32.set(pixels);
context.putImageData(imageData, 0, 0);
This works, however performance is about 0.07 seconds per frame, giving me a total of ~ 15 FPS, using a 640x480 canvas currently. My goal is to get at last 30fps for 1920x1080 (currently 5 FPS), and even higher values. The only solution i come up with is to create/populate the whole buffer at once on the java side, but i have no idea how to manage that. Any help would be appreciated.
I'm messing around with the examples of mt4j multitouch Java library and in the "advanced.drawing" example, i'm trying to change the background color of the drawingScene. Since it has set the setClear to false i'm not able to do it with the clearColor option. Any other ideas? Thanks
I've found with the help of TherioN from NUIGroup forums a way to do it. It is possible to add a MTRectangle with the fill color and then add the SceneTexture of the drawing example to that rectangle. I leav the piece of code as reference:
final MTSceneTexture sceneTexture = new MTSceneTexture(mtApplication,0, 0, mtApplication.width, mtApplication.height, drawingScene);
sceneTexture.getFbo().clear(true, 255, 255, 255, 0, true);
sceneTexture.setStrokeColor(new MTColor(155,155,155));
//Background
MTRectangle background = new MTRectangle(0,0,mtApplication.width, mtApplication.height , mtApplication);
background.setFillColor(new MTColor(255,244,150,255));
//Add the scene texture as a child of the background rectangle so the scene texture is drawn in front
background.addChild(sceneTexture);
frame.addChild(background);
We're using JFreeChart to build an engine to display graphs. This is a web service that runs on Tomcat + Java 1.5.0, and renders charts to PNGs and JPEGs (using ChartUtilities.writeChartAs{PNG,JPEG}() ).
We've run into a problem where JFreeChart seems to scale everything inside the Plot area, but only by a few pixels. The result is that the graph looks inconsistent, e.g.:
Minor ticks are sometimes stretched horizontally, so that they seem to be two pixels wide instead of one.
We use a small image in the top-right of the plot area as a watermark. This is stretched by one pixel horizontally and vertically somewhere near (but not exactly) its middle.
Background grid lines seem to appear on sub-pixel boundaries. I have not found a way to create an accurately dotted grid line.
We have tried both 1.0.9 and 1.0.13, with exactly the same results (except for the minor ticks, which were not available in the older version). Also, rendering the image to a Frame instead of JPEG/PNG produced an identical result.
Help is greatly appreciated, in advance :)
EDIT: An SSCCE:
#Test
public void testScaling1() throws InterruptedException {
// Load Image:
Component dummy = new Component() {};
MediaTracker tracker = new MediaTracker(dummy);
Image img = Toolkit.getDefaultToolkit().getImage("C:\\My\Image.gif");
tracker.addImage(img, 0);
tracker.waitForAll();
// Build Data set and base chart.
TimeSeriesCollection dataset = new TimeSeriesCollection();
TimeSeries ts = new TimeSeries("Sample");
ts.add(new Second(0, 0, 0, 1, 1, 1900), 1.0);
ts.add(new Second(1, 0, 0, 1, 1, 1900), 3.0);
ts.add(new Second(2, 0, 0, 1, 1, 1900), 4.0);
ts.add(new Second(3, 0, 0, 1, 1, 1900), 2.0);
dataset.addSeries(ts);
JFreeChart chart = ChartFactory.createTimeSeriesChart(
"blabla",
null,
null,
dataset,
true,
true,
false
);
// Add BG image in top-right corner.
XYPlot xy = chart.getXYPlot();
xy.setBackgroundAlpha(0.0F);
xy.setBackgroundImage(img);
xy.setBackgroundImageAlignment(Align.NORTH_WEST);
xy.setBackgroundImageAlpha(1.0F);
paintChart(chart);
}
Use an image with small-font text, or a grid. This will show the scaling effect on the background image.
Edit 2:
We've resorted to subclassing or proxying Renderers and drawing the label in text in their drawItem() (or similar) methods. This works well.
However, minor ticks are now a problem - they also seem to be getting scaled. E.g.: See the 9th and 15th ticks.
look at the bottom http://img14.imageshack.us/img14/3625/76676732.jpg
I am unable to reproduce the effect you describe using either saveChartAsJPEG() or writeChartAsPNG() with version 1.0.13, Java 1.5, Mac OS X, in code like this:
try {
ChartUtilities.writeChartAsPNG(new FileOutputStream(
new File("test.png")), chart, 600, 400);
} catch (IOException ex) {
ex.printStackTrace();
}
Does the screen exhibit the same artifacts? What happens when you change the WIDTH and HEIGHT parameters or omit the watermark? Are you using special fonts with unusual metrics? Have you tried a different platform?
You can run TimeSeriesChartDemo1 as follows:
java -cp jfreechart-1.0.13.jar:jcommon-1.0.16.jar org.jfree.chart.demo.TimeSeriesChartDemo1
Mac OS 10.5.8, Java 1.5.0_24, JFreeChart 1.0.13, TimeSeriesDemo1, using saveChartAsPNG(), ImageIO.read() and setBackgroundImage(). setBackgroundImageAlignment(Align.NORTH_WEST) is a little funky, though.
I need to resize PNG, JPEG and GIF files. How can I do this using Java?
FWIW I just released (Apache 2, hosted on GitHub) a simple image-scaling library for Java called imgscalr (available on Maven central).
The library implements a few different approaches to image-scaling (including Chris Campbell's incremental approach with a few minor enhancements) and will either pick the most optimal approach for you if you ask it to, or give you the fastest or best looking (if you ask for that).
Usage is dead-simple, just a bunch of static methods. The simplest use-case is:
BufferedImage scaledImage = Scalr.resize(myImage, 200);
All operations maintain the image's original proportions, so in this case you are asking imgscalr to resize your image within a bounds of 200 pixels wide and 200 pixels tall and by default it will automatically select the best-looking and fastest approach for that since it wasn't specified.
I realize on the outset this looks like self-promotion (it is), but I spent my fair share of time googling this exact same subject and kept coming up with different results/approaches/thoughts/suggestions and decided to sit down and write a simple implementation that would address that 80-85% use-cases where you have an image and probably want a thumbnail for it -- either as fast as possible or as good-looking as possible (for those that have tried, you'll notice doing a Graphics.drawImage even with BICUBIC interpolation to a small enough image, it still looks like garbage).
After loading the image you can try:
BufferedImage createResizedCopy(Image originalImage,
int scaledWidth, int scaledHeight,
boolean preserveAlpha)
{
System.out.println("resizing...");
int imageType = preserveAlpha ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
BufferedImage scaledBI = new BufferedImage(scaledWidth, scaledHeight, imageType);
Graphics2D g = scaledBI.createGraphics();
if (preserveAlpha) {
g.setComposite(AlphaComposite.Src);
}
g.drawImage(originalImage, 0, 0, scaledWidth, scaledHeight, null);
g.dispose();
return scaledBI;
}
Thumbnailator is an open-source image resizing library for Java with a fluent interface, distributed under the MIT license.
I wrote this library because making high-quality thumbnails in Java can be surprisingly difficult, and the resulting code could be pretty messy. With Thumbnailator, it's possible to express fairly complicated tasks using a simple fluent API.
A simple example
For a simple example, taking a image and resizing it to 100 x 100 (preserving the aspect ratio of the original image), and saving it to an file can achieved in a single statement:
Thumbnails.of("path/to/image")
.size(100, 100)
.toFile("path/to/thumbnail");
An advanced example
Performing complex resizing tasks is simplified with Thumbnailator's fluent interface.
Let's suppose we want to do the following:
take the images in a directory and,
resize them to 100 x 100, with the aspect ratio of the original image,
save them all to JPEGs with quality settings of 0.85,
where the file names are taken from the original with thumbnail. appended to the beginning
Translated to Thumbnailator, we'd be able to perform the above with the following:
Thumbnails.of(new File("path/to/directory").listFiles())
.size(100, 100)
.outputFormat("JPEG")
.outputQuality(0.85)
.toFiles(Rename.PREFIX_DOT_THUMBNAIL);
A note about image quality and speed
This library also uses the progressive bilinear scaling method highlighted in Filthy Rich Clients by Chet Haase and Romain Guy in order to generate high-quality thumbnails while ensuring acceptable runtime performance.
You don't need a library to do this. You can do it with Java itself.
Chris Campbell has an excellent and detailed write-up on scaling images - see this article.
Chet Haase and Romain Guy also have a detailed and very informative write-up of image scaling in their book, Filthy Rich Clients.
Java Advanced Imaging is now open source, and provides the operations you need.
If you are dealing with large images or want a nice looking result it's not a trivial task in java. Simply doing it via a rescale op via Graphics2D will not create a high quality thumbnail. You can do it using JAI, but it requires more work than you would imagine to get something that looks good and JAI has a nasty habit of blowing our your JVM with OutOfMemory errors.
I suggest using ImageMagick as an external executable if you can get away with it. Its simple to use and it does the job right so that you don't have to.
If, having imagemagick installed on your maschine is an option, I recommend im4java. It is a very thin abstraction layer upon the command line interface, but does its job very well.
The Java API does not provide a standard scaling feature for images and downgrading image quality.
Because of this I tried to use cvResize from JavaCV but it seems to cause problems.
I found a good library for image scaling: simply add the dependency for "java-image-scaling" in your pom.xml.
<dependency>
<groupId>com.mortennobel</groupId>
<artifactId>java-image-scaling</artifactId>
<version>0.8.6</version>
</dependency>
In the maven repository you will get the recent version for this.
Ex. In your java program
ResampleOp resamOp = new ResampleOp(50, 40);
BufferedImage modifiedImage = resamOp.filter(originalBufferedImage, null);
You could try to use GraphicsMagick Image Processing System with im4java as a comand-line interface for Java.
There are a lot of advantages of GraphicsMagick, but one for all:
GM is used to process billions of
files at the world's largest photo
sites (e.g. Flickr and Etsy).
Image Magick has been mentioned. There is a JNI front end project called JMagick. It's not a particularly stable project (and Image Magick itself has been known to change a lot and even break compatibility). That said, we've had good experience using JMagick and a compatible version of Image Magick in a production environment to perform scaling at a high throughput, low latency rate. Speed was substantially better then with an all Java graphics library that we previously tried.
http://www.jmagick.org/index.html
Simply use Burkhard's answer but add this line after creating the graphics:
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
You could also set the value to BICUBIC, it will produce a better quality image but is a more expensive operation. There are other rendering hints you can set but I have found that interpolation produces the most notable effect.
Keep in mind if you want to zoom in in a lot, java code most likely will be very slow. I find larger images start to produce lag around 300% zoom even with all rendering hints set to optimize for speed over quality.
You can use Marvin (pure Java image processing framework) for this kind of operation:
http://marvinproject.sourceforge.net
Scale plug-in:
http://marvinproject.sourceforge.net/en/plugins/scale.html
It turns out that writing a performant scaler is not trivial. I did it once for an open source project: ImageScaler.
In principle 'java.awt.Image#getScaledInstance(int, int, int)' would do the job as well, but there is a nasty bug with this - refer to my link for details.
I have developed a solution with the freely available classes ( AnimatedGifEncoder, GifDecoder, and LWZEncoder) available for handling GIF Animation.
You can download the jgifcode jar and run the GifImageUtil class.
Link: http://www.jgifcode.com
you can use following popular product: thumbnailator
If you dont want to import imgScalr like #Riyad Kalla answer above which i tested too works fine, you can do this
taken from Peter Walser answer #Peter Walser on another issue though:
/**
* utility method to get an icon from the resources of this class
* #param name the name of the icon
* #return the icon, or null if the icon wasn't found.
*/
public Icon getIcon(String name) {
Icon icon = null;
URL url = null;
ImageIcon imgicon = null;
BufferedImage scaledImage = null;
try {
url = getClass().getResource(name);
icon = new ImageIcon(url);
if (icon == null) {
System.out.println("Couldn't find " + url);
}
BufferedImage bi = new BufferedImage(
icon.getIconWidth(),
icon.getIconHeight(),
BufferedImage.TYPE_INT_RGB);
Graphics g = bi.createGraphics();
// paint the Icon to the BufferedImage.
icon.paintIcon(null, g, 0,0);
g.dispose();
bi = resizeImage(bi,30,30);
scaledImage = bi;// or replace with this line Scalr.resize(bi, 30,30);
imgicon = new ImageIcon(scaledImage);
} catch (Exception e) {
System.out.println("Couldn't find " + getClass().getName() + "/" + name);
e.printStackTrace();
}
return imgicon;
}
public static BufferedImage resizeImage (BufferedImage image, int areaWidth, int areaHeight) {
float scaleX = (float) areaWidth / image.getWidth();
float scaleY = (float) areaHeight / image.getHeight();
float scale = Math.min(scaleX, scaleY);
int w = Math.round(image.getWidth() * scale);
int h = Math.round(image.getHeight() * scale);
int type = image.getTransparency() == Transparency.OPAQUE ? BufferedImage.TYPE_INT_RGB : BufferedImage.TYPE_INT_ARGB;
boolean scaleDown = scale < 1;
if (scaleDown) {
// multi-pass bilinear div 2
int currentW = image.getWidth();
int currentH = image.getHeight();
BufferedImage resized = image;
while (currentW > w || currentH > h) {
currentW = Math.max(w, currentW / 2);
currentH = Math.max(h, currentH / 2);
BufferedImage temp = new BufferedImage(currentW, currentH, type);
Graphics2D g2 = temp.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g2.drawImage(resized, 0, 0, currentW, currentH, null);
g2.dispose();
resized = temp;
}
return resized;
} else {
Object hint = scale > 2 ? RenderingHints.VALUE_INTERPOLATION_BICUBIC : RenderingHints.VALUE_INTERPOLATION_BILINEAR;
BufferedImage resized = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = resized.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
g2.drawImage(image, 0, 0, w, h, null);
g2.dispose();
return resized;
}
}
Try this folowing method :
ImageIcon icon = new ImageIcon("image.png");
Image img = icon.getImage();
Image newImg = img.getScaledInstance(350, 350, java.evt.Image.SCALE_SMOOTH);
icon = new ImageIcon(img);
JOptionPane.showMessageDialog(null, "image on The frame", "Display Image", JOptionPane.INFORMATION_MESSAGE, icon);
you can also use
Process p = Runtime.getRuntime().exec("convert " + origPath + " -resize 75% -quality 70 " + largePath + "");
p.waitFor();
Design jLabel first:
JLabel label1 = new JLabel("");
label1.setHorizontalAlignment(SwingConstants.CENTER);
label1.setBounds(628, 28, 169, 125);
frame1.getContentPane().add(label1); //frame1 = "Jframe name"
Then you can code below code(add your own height and width):
ImageIcon imageIcon1 = new ImageIcon(new ImageIcon("add location url").getImage().getScaledInstance(100, 100, Image.SCALE_DEFAULT)); //100, 100 add your own size
label1.setIcon(imageIcon1);
I'm working on a simple 2D game engine in Java, and having no trouble with FSEM, buffer strategies, and so on; my issue is with the mouse cursor. In windowed mode, I can hide the mouse cursor, no problem, by using setCursor() from my JFrame to set a wholly-transparent cursor. However, after a call to device.setFullScreenWindow(this) to go into FSEM, the mouse cursor comes back, and subsequent calls to setCursor() to set it back to my blank cursor have no effect. Calling device.setFullScreenWindow(null) allows me to get rid of the cursor again - it's only while I'm in FSEM that I can't get rid of it.
I'm working under JDK 6, target platform is JDK 5+.
UPDATE: I've done some more testing, and it looks like this issue occurs under MacOS X 10.5 w/Java 6u7, but not under Windows XP SP3 with Java 6u7. So, it could possibly be a bug in the Mac version of the JVM.
Try Creating a custom invisible cursor:
Toolkit toolkit = Toolkit.getDefaultToolkit();
Point hotSpot = new Point(0,0);
BufferedImage cursorImage = new BufferedImage(1, 1, BufferedImage.TRANSLUCENT);
Cursor invisibleCursor = toolkit.createCustomCursor(cursorImage, hotSpot, "InvisibleCursor");
setCursor(invisibleCursor);
One developer found a way around it by creating a one pixel cursor out of a transparent GIF.
http://sevensoft.livejournal.com/23460.html
I know you tried that, but his is specifically addressing the issue of full-screen mode, exactly as you say, so perhaps there's something he's done that you haven't.
I think I've finally found the solution:
System.setProperty("apple.awt.fullscreenhidecursor","true");
This is an Apple-proprietary system property that hides the mouse cursor when an application is in full-screen mode. It's the only way I've found to fix it.
Here's what has been working for me:
Toolkit toolkit = Toolkit.getDefaultToolkit();
// get the smallest valid cursor size
Dimension dim = toolkit.getBestCursorSize(1, 1);
// create a new image of that size with an alpha channel
BufferedImage cursorImg = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB);
// get a Graphics2D object to draw to the image
Graphics2D g2d = cursorImg.createGraphics();
// set the background 'color' with 0 alpha and clear the image
g2d.setBackground(new Color(0.0f, 0.0f, 0.0f, 0.0f));
g2d.clearRect(0, 0, dim.width, dim.height);
// dispose the Graphics2D object
g2d.dispose();
// now create your cursor using that transparent image
hiddenCursor = toolkit.createCustomCursor(cursorImg, new Point(0,0), "hiddenCursor");
Granted, I haven't tested it on Mac (yet), only Windows. But when I used the common methods I was getting the cursor as black box, so I use the code above the create a transparent box and set it as the cursor instead. Of course you have to use the setCursor method on an AWT object (such as your app's Frame) to set this hiddenCursor. Here is my hideMouse method ('fr' is my Frame):
public void hideMouse(boolean hide) {
if(hide) {
fr.setCursor(hiddenCursor);
} else {
fr.setCursor(Cursor.getDefaultCursor());
}
}
I don't know if this knowledge applies but in a old VB6 app I had the same problem and I got rid of it moving the cursor out of the screen giving it some very large values.
Hope it helps.
If you're running only on Windows, it looks like you'll need to call ShowCursor(FALSE) through JNI. At least, to make the cursor hide complete.
Here's some code which creates the 1x1 cursor. It works for me, though I still get a 1x1 cursor.
Toolkit toolkit = Toolkit.getDefaultToolkit();
Dimension dim = toolkit.getBestCursorSize(1,1);
transCursor = toolkit.createCustomCursor(gc.createCompatibleImage(dim.width, dim.height),
new Point(0, 0), "transCursor");
((Component)mainFrame).setCursor(transCursor);
Specifically for your Mac problem, through JNI you could use the following:
Quartz Display Services Reference - CGDisplayHideCursor