[IDEs, Libraries, & Programming Tools] poohshoes:
While working on an Android game I got to the point where I was concerned with sorting out different resolutions. There's no way I was going to manually change my asset sizes for all current and future assets and all screen sizes. Here is a quick piece of code to do it for you.

package resourceGenerator;

import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class ResourceGenerator {

public static void main(String[] args) {
if(args.length < 2 || args.length > 3 || (args.length == 3 && !args[2].equals("-overwrite"))){
System.out.println("Resource Generator will take resources from one of your ldpi, mdpi, hdpi, xhdpi, or xxhdpi resource folders and generate default resources of the correct size for any other of those folders.");
System.out.println("Usage: ResourceGenerator.java sourceFolder destinationFolder -overwrite");
}
else{
String source = args[0];
String destination = args[1];
boolean overwrite = false;
if(args.length == 3){
overwrite = true;
}

int sourceScalingValue = getScalingValue(source);
int destinationScalingValue = getScalingValue(destination);

if(sourceScalingValue == 0 || destinationScalingValue == 0){
System.out.println("Source Folder and/or Destination Folder was invalid, should end with one of drawable-ldpi, drawable-mdpi, drawable-hdpi, or drawable-xhdpi.");
}
else {
float scale = (float) destinationScalingValue / (float) sourceScalingValue;
copyFiles(source, destination, overwrite, scale);
}
}
}

private static void copyFiles(String source, String destination, boolean overwrite, float scale) {
File sourceFolder = new File(source);

for (File file : sourceFolder.listFiles()) {
if (file.isDirectory()) {
File destinationFile = new File(destination, file.getName());
copyFiles(file.getPath(), destinationFile.getPath(), overwrite, scale);
}
else if (file.isFile()){
String extension = file.getName().substring(file.getName().lastIndexOf(".")+1);
if(extension.equalsIgnoreCase("jpg") || extension.equalsIgnoreCase("png") || extension.equalsIgnoreCase("gif")){
try {
File outputFile = new File(destination, file.getName());
if(overwrite || !outputFile.exists()){
createFolderIfRequired(destination);
BufferedImage scaledImage = getScaledImage(ImageIO.read(file), scale);
ImageIO.write(scaledImage, extension, outputFile);
System.out.println("Completed " + outputFile.getPath());
}
else{
System.out.println("Skipped as file already exists " + file.getPath());
}
} catch (IOException e) {
System.out.println("Failed to read file " + file.getPath());
}
}
else{
System.out.println("Skipping as we only process jpg, png, and gif " + file.getPath());
}
}
}
}

private static void createFolderIfRequired(String folderPath) {
File folder = new File(folderPath);
if(!folder.exists()){
folder.mkdir();
}
}

public static BufferedImage getScaledImage(BufferedImage image, double scale) throws IOException {
AffineTransform scaleTransform = AffineTransform.getScaleInstance(scale, scale);
AffineTransformOp bilinearScaleOp = new AffineTransformOp(scaleTransform, AffineTransformOp.TYPE_BICUBIC);
return bilinearScaleOp.filter(image, new BufferedImage((int)(image.getWidth() * scale), (int)(image.getHeight() * scale), image.getType()));
}

private static int getScalingValue(String folderString) {
File file=new File(folderString);

if(!file.isDirectory()){
return 0;
}

if(file.getName().equals("drawable-ldpi")){
return 120;
}
else if(file.getName().equals("drawable-mdpi")){
return 160;
}
else if(file.getName().equals("drawable-hdpi")){
return 240;
}
else if(file.getName().equals("drawable-xhdpi")){
return 320;
}
else {
return 0;
}
}

}

(Also posted on my website, hernblog.com)