June 11, 2013

Android resource scaler

While working on a game for android I came across the need to scale all of my resources from one drawable-?dmi folder to another. Here is a java program to do it for you. Pass in the source and destination folders and it handles all of the scaling. Optionally specify the -overwrite flag if you want it to write over existing resources of the same name.


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, null);
    }
    
    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;
        }
    }
}

July 26, 2013 Edit: updated to handle byte index png format without losing the alpha

<-- my history with programmingSpace Crazy Prototype -->

contact@hernblog.com