最近开发android,在网上发现一个很好的工具,可以自动生成drawable文件夹下的图片,具体运行效果如下图所示
现在分享一下生成过程
eclispe创建一个java环境,结构如下
现将三个类的源码分享一下
AndroidDrawableFactory.java
public class AndroidDrawableFactory {
//constants
public static final String[] DENSITIES = {"ldpi", "mdpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"};
public static final double[] DENSITY_MULTIPLIERS = {.75, 1, 1.5, 2, 3, 4};
public static void main(String... args)
{
initLaF();
Main mainWindow = new Main();
mainWindow.pack();
mainWindow.setTitle("Android Drawable Factory");
mainWindow.setLocationRelativeTo(null);
mainWindow.setResizable(false);
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setVisible(true);
}
private static void initLaF()
{
UIManager.LookAndFeelInfo[] lafs = UIManager.getInstalledLookAndFeels();
try
{
boolean hasGTK = false;
for(UIManager.LookAndFeelInfo info : lafs)
{
if(info.getName().equals("GTK+"))
{
hasGTK = true;
break;
}
}
if(hasGTK)
{
UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
}
else
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(UnsupportedLookAndFeelException e){e.printStackTrace();}
catch(ClassNotFoundException e){e.printStackTrace();}
catch(InstantiationException e){e.printStackTrace();}
catch(IllegalAccessException e){e.printStackTrace();}
}
ImageUtils.java
public class ImageUtils {
public static double getAspectRatio(BufferedImage img, int newWidth, int newHeight)
{
int imgWidth = img.getWidth(null);
int imgHeight = img.getHeight(null);
double xRatio = (double) newWidth / (double) imgWidth;
double yRatio = (double) newHeight / (double) imgHeight;
return Math.min(xRatio, yRatio);
}
public static Image resizeImage(BufferedImage bImg, int newWidth, int newHeight) throws FileNotFoundException, IOException
{
double ratio = getAspectRatio(bImg, newWidth, newHeight);
newWidth = (int) (bImg.getWidth(null) * ratio);
newHeight = (int) (bImg.getHeight(null) * ratio);
Image resizedImage = bImg.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH);
return resizedImage;
}
public static int getMaxWidth(File img) throws FileNotFoundException, IOException
{
BufferedImage bImg= ImageIO.read(new FileInputStream(img));
int width = bImg.getWidth();
int height = bImg.getHeight();
return Math.max(width, height);
}
Main.java
@SuppressWarnings("serial")
public class Main extends JFrame{
//Instance parameters
JLabel imageCanvas; //canvas that store the image to modify
JFileChooser imageChooser, projectPathChooser; //JFileChooser for the source image and project path
JTextField projectPathField, sourceSizeTextField; //fields to store projectPath and source image size
JButton projectPathButton, createButton; //Buttons to open the path chooser and to start drawables conversion
JLabel sourceDensityLabel, sourceSizeLabel; //labels for source density and source size fields
JComboBox<String> sourceDensityComboBox; //list of available densities
LinkedHashMap<String, JCheckBox> densitiesCheckBox; //HashMap that stores the available density checkboxes
JPanel mainPanel, densitiesPanel; //panel containing checkboxes
private File lastUsedSourceDirectory;
private File lastUsedProjectDirectory;
//JProgressBar progressBar;
File sourceImg; //source Image File object
String sourceFileName; //source file name
BufferedImage bufferedSource; //Source image BufferedImage object
public Main()
{
super("Main Window");
initUI(); //initialize ui elements
initListeners(); //initialize ui event listeners
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void initUI()
{
//create components
imageCanvas = new JLabel(); //image to be used
imageCanvas.setIcon(new ImageIcon(getClass().getResource("/placeholder.png")));
imageCanvas.setBackground(Color.decode("#33B5E5"));
imageCanvas.setBorder(BorderFactory.createLineBorder(Color.black));
imageCanvas.setToolTipText("Click to select an Image");
projectPathChooser = new JFileChooser(); //Launch directory selection
projectPathField = new JTextField(); //Retains the path selected with JFileChooser
projectPathField.setEditable(false);
projectPathField.setText("project path");
projectPathButton = new JButton("Browse"); //Button that launch JFileChooser
sourceDensityLabel = new JLabel("Source Density"); //Label for the source density field
sourceDensityComboBox = new JComboBox<String>(AndroidDrawableFactory.DENSITIES); //selector for the source density
sourceSizeLabel = new JLabel("Source Size"); //Label for source image's size
sourceSizeTextField = new JTextField(); //Field for source image's size
sourceSizeTextField.setEditable(false);
densitiesCheckBox = new LinkedHashMap<String, JCheckBox>(); //checkbox Map with densities
createButton = new JButton("make"); //button to begin drawable conversion
densitiesPanel = new JPanel();
//initialize checkboxes
for(int i = 0; i < AndroidDrawableFactory.DENSITIES.length; i++)
{
String density = AndroidDrawableFactory.DENSITIES[i];
densitiesCheckBox.put(density, new JCheckBox(density));
}
for(JCheckBox e : densitiesCheckBox.values())
{
e.setSelected(true);
densitiesPanel.add(e);
}
densitiesPanel.add(createButton);
//create and set LayoutManager
this.setLayout(new BoxLayout(this.getContentPane(), BoxLayout.PAGE_AXIS));
mainPanel = new JPanel();
GroupLayout gp = new GroupLayout(mainPanel);
gp.setAutoCreateContainerGaps(true);
gp.setAutoCreateGaps(true);
mainPanel.setLayout(gp);
//set alignment criteria
GroupLayout.Alignment hAlign = GroupLayout.Alignment.TRAILING;
GroupLayout.Alignment vAlign = GroupLayout.Alignment.BASELINE;
//add component into layout
//set horizontal group
gp.setHorizontalGroup(gp.createSequentialGroup()
.addGroup(gp.createParallelGroup(hAlign)
.addComponent(imageCanvas, 80, 80, 80))
.addGroup(gp.createParallelGroup(hAlign)
.addComponent(projectPathField, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE)
//.addComponent(projectPathField)
.addComponent(sourceDensityLabel, Alignment.LEADING)
.addComponent(sourceSizeLabel, Alignment.LEADING))
.addGroup(gp.createParallelGroup(hAlign)
.addComponent(projectPathButton)
.addComponent(sourceDensityComboBox,GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)
.addComponent(sourceSizeTextField,GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, 50))
);
//set vertical group
gp.setVerticalGroup(gp.createSequentialGroup()
.addGroup(gp.createParallelGroup(vAlign)
.addComponent(imageCanvas, 80, 80, 80)
.addGroup(gp.createSequentialGroup()
.addGroup(gp.createParallelGroup(vAlign)
.addComponent(projectPathField)
.addComponent(projectPathButton))
.addGroup(gp.createParallelGroup(vAlign)
.addComponent(sourceDensityLabel)
.addComponent(sourceDensityComboBox))
.addGroup(gp.createParallelGroup(vAlign)
.addComponent(sourceSizeLabel)
.addComponent(sourceSizeTextField)))
)
);
this.add(mainPanel);
this.add(densitiesPanel);
}
private void initListeners()
{
//Source Image click listener
imageCanvas.addMouseListener(new MouseListener(){
public void mouseClicked(MouseEvent arg0) {
// TODO Auto-generated method stub
JFileChooser imageChooser = new JFileChooser();
if (lastUsedSourceDirectory != null) {
imageChooser.setCurrentDirectory(lastUsedSourceDirectory);
}
imageChooser.setDialogTitle("Select an image");
imageChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
imageChooser.setFileFilter(new FileFilter(){
@Override
public boolean accept(File file) {
if(file.getName().endsWith(".jpg") ||
file.getName().endsWith(".png") || file.isDirectory())
{
return true;
}
else return false;
}
@Override
public String getDescription() {
return "Images (.jpg;.png)";
}
});
imageChooser.setAcceptAllFileFilterUsed(false);
switch(imageChooser.showOpenDialog(imageCanvas))
{
case(JFileChooser.APPROVE_OPTION):
try {
sourceImg = new File(imageChooser.getSelectedFile().getPath());
lastUsedSourceDirectory = sourceImg.getParentFile();
sourceFileName = sourceImg.getName();
bufferedSource = ImageIO.read(sourceImg);
Image sourceResized = ImageUtils.resizeImage(bufferedSource, 80, 80);
imageCanvas.setIcon(new ImageIcon(sourceResized));
sourceSizeTextField.setText(Integer.toString(ImageUtils.getMaxWidth(sourceImg)));
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
});
projectPathButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
projectPathChooser = new JFileChooser();
if (lastUsedProjectDirectory != null) {
projectPathChooser.setCurrentDirectory(lastUsedProjectDirectory);
}
projectPathChooser.setDialogTitle("Project root directory of your app");
projectPathChooser.setAcceptAllFileFilterUsed(false);
projectPathChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
if(projectPathChooser.showOpenDialog(projectPathButton) == JFileChooser.APPROVE_OPTION) {
projectPathField.setText(projectPathChooser.getSelectedFile().getPath());
lastUsedProjectDirectory = projectPathChooser.getSelectedFile();
}
}
});
//"Make" button action listener
createButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
if(bufferedSource == null || projectPathField.getText().equals("project path"))
{
JOptionPane.showMessageDialog(rootPane, "Please select an image and a valid project path", "Error", JOptionPane.ERROR_MESSAGE);
}
else
{
//disable make button
createButton.setEnabled(false);
resizeThread = new Thread(resizeRunnable);
resizeThread.start();
}
}
});
}
Thread resizeThread;
Runnable resizeRunnable = new Runnable(){
public void run() {
// TODO Auto-generated method stub
//handy references to AndroidDrawableFactory.class constants
String[] densities = AndroidDrawableFactory.DENSITIES;
double[] density_ratio = AndroidDrawableFactory.DENSITY_MULTIPLIERS;
//create hashmap with density and density ratio
HashMap<String, Double> densityMap = new HashMap<String, Double>();
for(int i = 0; i < densities.length; i++)
{
densityMap.put(densities[i], density_ratio[i]);
}
double targetDensity = densityMap.get(sourceDensityComboBox.getSelectedItem().toString());
for(Map.Entry<String, Double> e : densityMap.entrySet())
{
JCheckBox singleDensity = densitiesCheckBox.get(e.getKey());
String projectPath = projectPathField.getText();
File projectResourceRoot = new File(projectPath);
/*if (!"res".equals(projectResourceRoot.getName())) {
projectResourceRoot = new File(projectResourceRoot, "res");
}*/
if(singleDensity.isSelected())
{
String folderName = "drawable-" + e.getKey();
double densityRatio = e.getValue();
int newWidth = Math.round((float)(bufferedSource.getWidth() / targetDensity * densityRatio));
int newHeight = Math.round((float)(bufferedSource.getHeight() / targetDensity * densityRatio));
try {
Image newImg = ImageUtils.resizeImage(bufferedSource, newWidth, newHeight);
File targetDir = new File(projectResourceRoot, folderName);
boolean dirExists = false;
//check if project dir exists, if not create it
dirExists = targetDir.exists() || targetDir.mkdir();
if(dirExists)
{
BufferedImage bufImg = new BufferedImage(newImg.getWidth(null), newImg.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D img2D = bufImg.createGraphics();
img2D.drawImage(newImg, null, null);
RenderedImage targetImg = (RenderedImage) bufImg;
File newFile = new File(targetDir + File.separator + sourceFileName);
ImageIO.write(targetImg, "png", newFile);
}
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
// TODO Auto-generated method stub
JOptionPane.showMessageDialog(getContentPane(), "Resize Completed!", "Completed", JOptionPane.INFORMATION_MESSAGE);
createButton.setEnabled(true);
}
});
}
};
导出jar包
下载exe4j,安装,将jar转换为.exe文件,根据系统版本位数下载32位或64位的exe4j
next
next
填写需要生成的文件名与输出位置
如果是64位系统,点击Advance Options,选择64-bit,勾选Generate 64-bit
选择生成的jar
然后一路next
Exit
就可以直接运行生成的.exe文件