How should I do image animation? - java

I plan to have an animated character (the character's image changing multiple times to make it appear to be moving), and I would like to know the best way to do it. I am currently planning to do something like this:
String fileLocation = "./images/picture";
BufferedImage img;
int numImages = 10;
for(int i = 0; i < numImages; i++){
img = ImageIO.read(new File(fileLocation + i + ".png"));
Thread.sleep(100);
g.drawImage(img, 0, 0, null);
}
This is an incredibly simplified version, missing a few things, but I'm sure you get what I mean. Are there any problems doing it this way? (Note: the for loop would repeat again straight after finishing, and there would be files called "picture0.png", "picture1.png", etc. in the "images" folder)

If the images are not huge and don't require a lot of memory for storing them, I would rather read the images first and cache them. When they need to be displayed, I would read them from memory rather than from disk.

Related

Need help batch adding images with 00 in name of filepath (Java)

I'm having trouble batch adding images to a JButton grid. I'm trying to use a for loop who's variable is used in the string name.
The names of the images are like:
32px-Shuffle001.png
32px-Shuffle821.png
etc.
Here's the part of the code that I'm trying to add in images with. The third setIcon works, but the first two don't. I'm confused on why this is.
Additionally, the image files are not consecutive numbers. For example, I have 001,002,003,004,005, but not 007,008, then continuing at 009,010. I'm trying to figure out a good way to make it skip to the next available image.
Overall, this code is for a match 3 puzzle solver, and this is a selection grid for icons to put on the puzzle grid, so I need to be able to call the correct image associated to a button ID.
for (int i = 0; i < 1000; i++) {
JButton selectionClicky = new JButton();
if (i < 10) {
selectionClicky.setIcon(new ImageIcon("src/img/32px-Shuffle" + "00"
+ i + ".png"));
}
if (i < 100){
selectionClicky.setIcon(new ImageIcon("src/img/32px-Shuffle"+ "0"
+ i + ".png"));
}
if (i < 1000){
selectionClicky.setIcon(new ImageIcon("src/img/32px-Shuffle"
+ i + ".png"));
}
selectionClicky.setFocusable(false);
selectionMainPanel.add(selectionClicky);
selectionButtonList.add(selectionClicky);
}
Don't ever use src in any path reference, this is a good indication that things will go wrong, instead use Class#getResource or Class#getResourceAsStream depending on your requirements.
Basically, the general idea would be to test if the resource actually existed before trying to load it, for example...
String path = String.format("/img/32px-Shuffle%03d", i);
URL resource = getClass().getResource(path);
if (resource != null) {
BufferedImage img = ImageIO.read(resource);
selectionClicky.setIcon(new ImageIcon(img));
}
Generally, ImageIO is preferred over using ImageIcon, mostly because ImageIO throws an IOException when the image can't be loaded for some reason (instead of failing silently) and won't return until the image is fully loaded
See Reading/Loading an Image for more details about ImageIO

Finding best fit from a list of images

I'm using a library called Image4j to load an ico file, choose one of the images from the list, scale it (if necessary) and put it in a JLabel as an ImageIcon.
The library has a method read(File icoFile) which returns a List<BufferedImage> , a list of all the images contained within the ico file.
What I want to be able to do is quickly choose the image from the list that is the closest fit for the size of the label. Both the labels and the ico images will be square.
I've come up with the most naive way, but I suspect there's a faster one. I'd settle for this one, but my program will be doing this routine a lot so I want this part to be as efficient as possible.
public class IconUtil() {
private final List<BufferedImage> list;
public IconUtil(List<BufferedImage> list) {
this.list = list;
}
public BufferedImage getBestFit(int sizeToFit) {
int indexOfBestFit = 0; // assume it's the first image
int bestMargin = Math.abs(list.get(0).getWidth() - sizeToFit);
int margin;
for(int i = 1; i < list.size(); i++) {
margin = Math.abs(list.get(i).getWidth() - sizeToFit);
if(margin < bestMargin) {
bestMargin = margin;
indexOfBestFit = i;
}
}
return list[indexOfBestFit];
}
}
The choice to compare the images by their width was arbitrary because they're all square.
Also, as the main reason for picking the best fit is to try and maintain the quality of the images, should this method discard any images which are smaller than the target size? If so, how would that change the algorithm?
I have little experience with re-scaling images in Java. Is it even necessary to find the closest match in size? Maybe there are ways to re-scale without losing much quality even if the original is much bigger?

Looking for Java method to bundle multiple button image data in one file

I am writing a javaFx based POS system that will receive input via a touch screen monitor. The input screen will have lots of buttons (50+) with different image data on each button. I have been looking for a method to contain all these graphic images (small 75x75px) in one file that can be read at startup instead of opening 50 different image files. I imagine that this will speed up the start up process.
I have looked at java resource bundles as a method but it looks like this system is designed to store local specific content and it seems like it would be complex to implement for my needs.
I am wondering if anyone knows of some java or javaFx utilities or routines that would be suited to this problem. Maybe something where I could load all the image data, store it in some object, and then write this object out on one file. Maybe some sort of dictionary object that I could just write out to a file and then read back in on startup.
Thanks.
#FXML
private Button btn1;
Image img = new Image("/images/2013-07-14_14-40-17_89.jpg");
ImageView iv = new ImageView();
iv.setImage(img);
Rectangle2D viewportRect = new Rectangle2D(100, 250, 50, 50);
iv.setViewport(viewportRect);
btn1.setGraphic(iv);
You can load one Image and create an ImageView (a Node) for every button. The ImageView picks a view port rectangle inside the large image.
To create a single file from several images, something like:
BufferedImage totalImage = new BufferedImage(...);
Graphics2D g = totalImage.createGraphics();
String[] files = { ... };
for (int i = 0; i < files.length; ++i) {
BufferedImage img = ImageIO.read(files[i]);
int x = i * 75;
int y = 0;
g.drawImage(x, y, img, ...);
}
ImageIO.write(totalImage, ...);
g.dispose();

Android alternative to java.awt (BufferedImage and Raster)

for my final year project I am developing an android app that can capture the image of a leaf and identify what type of tree it came from. I have a nearly completed PC version (developed in java) and i am starting the process of porting it to android. Although BufferedImage and Raster make up a key part of my program, this is a problem because java.awt is missing in android, so this means i have to alter the library.
I am using a library that was developed by my lecturer, the method below converts a BufferedImage to an IntImage(a type that is used throughout the package) using Raster.
I'm basically asking are there any android alternatives to java.awt that i can use?
Here's the code:
public static int[][] readAsInts(String fileName) throws IOException {
int[][] pixels;
System.out.println("File: " + fileName);
String [] types = ImageIO.getReaderFileSuffixes();
for (int l = 0; l < types.length; l++) {
System.out.println("Type " + l + ": " + types[l]);
}
File f = new File(fileName);
BufferedImage bi;
bi = ImageIO.read(f);
int cols = bi.getWidth();
int rows = bi.getHeight();
System.err.println("Number of bands: " + bi.getRaster().getNumBands());
Raster rast = bi.getRaster();
pixels = new int[rows][cols];
for (int r = 0; r < rows; r++) {
rast.getSamples(0, r, cols, 1, 0, pixels[r]);
}
return pixels;
} // readAsInts
Thanks guys!
EDIT: For anyone who doesn't know the raster stores the pixel values for the BufferedImage, along with the number of bands (red, green, blue, alpha), so this algorithm takes the pixel values ad stores them in a 2d array (pixels).
Sounds like you just want to work with bitmaps and be able to manipulate the pixels themselves in an array. The Bitmap class comes to mind along with its getPixels method. Remember though that you have much more limited memory on a mobile device. It's easy to run into out of memory problems when working with large bitmaps.
Another route would be to use the NDK. I don't have much experience there, but AndroidBitmap_lockPixels and AndroidBitmap_unlockPixels are probably a good place to start.
Lastly, yet another option that should perform pretty well is to use RenderScript.
If all you're looking to do is load an image into an int array though, Bitmap.getPixels should be quite sufficient.
You can convert a BufferedImage to a PNG or JPEG, then send it via HTTP to Android which can then convert the PNG or JPEG back to a Bitmap and use it.
When Android needs to send any image, send it as PNG or JPEG via network, and then convert the PNG to BufferedImage and use it in your program.

Java's Graphics.drawImage produces an inaccurate image

I'm trying to draw one image onto another using graphics.drawImage() but it's only working accurately for some images, others it messes up. My code's below, I've made sure texture is the right image when it enters the method so that's definitely not it. Any ideas?
private BufferedImage currentSheet;
public void swapRegionWithTexture(Rectangle region, Image texture) {
Graphics sheetGraphics = currentSheet.createGraphics();
for (int ix = region.x; ix < region.x + region.width; ix++) {
for (int iy = region.y; iy < region.y + region.height; iy++) {
currentSheet.setRGB(ix, iy, 0x000000);
}
}
sheetGraphics.drawImage(texture, region.x, region.y, null);
sheetGraphics.dispose();
}
The general idea is:
Grab the graphics to draw to.
Clear out the section of the graphics that will be drawn on.
Draw the image at the given location on the graphics.
Dispose of the graphics.
Your current atomic steps are thus:
create a new buffered image
write to that buffered image some crazy manipulation of the original texture (looks like you're reversing it?)
write the original image to the current sheet.
So what if you change this
sheetGraphics.drawImage(texture, region.x, region.y, null);
to this
sheetGraphics.drawImage(bufferedTexture, region.x, region.y, null);
Otherwise you're spending time reversing the image and putting into buffered texture and then never doing anything with that buffer... so chances are you intended to use that buffered texture somewhere.

Categories