Coloring badges from Google

    Application design is a very important part of development. Google greatly simplifies it, providing in the public domain about 150 ready-made icons, prepared for different pixel densities. However, by default they are gray. This is done specifically so that the designer himself painted them. But if we just want to give the icons some color - there is no point in editing each separately. It’s easier to write a script that does the work for us.

    This article will introduce a small Java program that automatically paints all the icons in a given color, the algorithm by which it works, and also an archive of already painted icons that you can immediately use in your applications.

    I’ll make a reservation right away — it is quite possible that Adobe Illustrator can do everything that is written in the article and there are already ready-made scripts. But it is not under Linux and in general it is expensive. I think Linux users and free software proponents will appreciate my approach.



    Introduction

    At developer.android.com, anyone can download an archive of design resources that, according to NOTICE.TXT , can be used without any restrictions. Among them are Action Bar Icons . Let's look at them in more detail. There are two sets - for the themes Holo Light and Holo Dark . Accordingly, for a dark theme, the icons are white, and for white - gray. As I understand it, the source for the icons are in Adobe Illustrator (* .ai) format. But for me this program is too expensive, and indeed I am a supporter of free software. So we will colorize already prepared png files, since their size has already been adjusted for different pixel densities.

    What for?

    Of course, it would be better for a large company to hire a professional designer who will draw unique icons from scratch. Or modify the existing ones. However, if you make a small application on order, it makes no sense to introduce a new design. Android users are accustomed to the standard set of icons, to their outlines. It seems to me that you just need to add color to these shapes and please the user.

    But the main benefit of such icons is when a programmer makes a program for himself, and he has no desire and time to engage in design. I want the program to look like everyone else, but at the same time provide some of its unique functions. For example, if you are a beginner programmer and are learning Android, it will be very useful to develop your own program in parallel with the training and demonstrate the knowledge gained in it. However, with colored icons, it will look much better.

    What we have

    Consider the gray icon set in more detail. For each icon, there are four versions corresponding to different pixel densities. You only use the final name in the program - for example R.id.ic_action_important , and Android itself selects the desired folder. This is very convenient and looks amazing due to the fact that on screens for mobile devices, ppi is much higher than on a conventional monitor. Image appears smoother.

    By the way, the icons are quite universal and they can be used not only in the Action Bar.

    The first problem I encountered is that there is no general overview of all the icons. Twenty minutes of programming - and Java code is already ready, which runs through the directories and reads the icons from there, gluing them into one common picture. Here she is:



    Now, let's try to color them. I will use desktop Java for these purposes. No matter how scolded, she provides many ready-made and working solutions. We will use awt - libraries for working with 2D graphics. The first thing I did was upload a picture in BufferedImage and walked through each pixel, highlighting its 4 components (ARGB). A quick analysis of the output showed that the picture essentially uses only one color - gray. And in those places where the image itself is smoothed out - the alpha channel is simply reduced.

    Based on this, in order to colorize the icon, we just need to replace the gray color with the necessary one, without affecting the alpha channel. I tried to take an asterisk and paint it blue, and then test it on my device - and it looked great there!

    Program

    After working for some time, I made a script that distills all the icons from the library to the specified color. True, the directory should contain only icons and folders - nothing more.

    I think that most Android developers had at least a little experience with desktop Java - compiling and running would not cause difficulties. In principle, everything is simple.

    Main.java
    import javax.imageio.ImageIO;
    import java.awt.*;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.util.ArrayList;
    import java.util.List;
    public class Main {
        static final int COLUMNS_COUNT = 15;
        static final String DIR_WITH_GRAY_IMAGES = "E:\\wsys\\prj\\ImagePainter\\test\\gray";
        static final String OUTPUT_DIR = "E:\\wsys\\prj\\ImagePainter\\test";
        static final Color myColor = new Color(177, 0, 140);//Цвет, в который перекрашиваем
        static List fileList = new ArrayList<>();
        public static void main(String[] strings) throws Throwable {
            painter();
        }
        private static void outputImages(File dir) {
            for (File subDir : dir.listFiles()) {
                if (subDir.getName().contains("hdpi")) {
                    File pngFile = subDir.listFiles()[0];
                    fileList.add(pngFile);
                    break;
                }
                if (subDir.isDirectory()) {
                    outputImages(subDir);
                }
            }
        }
        private static void painter() throws Throwable {
            File dirWithImages = new File(DIR_WITH_GRAY_IMAGES);
            File outputDir = new File(OUTPUT_DIR);
            String nameFolder = Integer.toHexString(myColor.getRGB());
            for (File subDir : dirWithImages.listFiles()) {
                for (File drawable : subDir.listFiles()) {
                    System.out.println(drawable);
                    for (File pngFile : drawable.listFiles()) {
                        System.out.println(pngFile);
                        BufferedImage okImage = handlePngFile(pngFile, myColor);
                        String partPath = pngFile.getAbsolutePath().replace(dirWithImages.getAbsolutePath(), "");
                        File newPngPath = new File(outputDir.getAbsolutePath() + "\\" + nameFolder + "\\" + partPath);
                        newPngPath.mkdirs();
                        ImageIO.write(okImage, "png", newPngPath);
                    }
                }
            }
            File targetDir = new File(outputDir, "\\" + nameFolder);
            outputImages(targetDir);
            ImageIO.write(getComplexImage(), "png", new File(targetDir, "all.png"));
        }
        private static BufferedImage getComplexImage() {
            BufferedImage bufferedImage = new BufferedImage(800, 500, BufferedImage.TYPE_INT_ARGB);
            Graphics g = bufferedImage.getGraphics();
            int i = 0;
            int j = 0;
            int counter = 0;
            try {
                for (File pngFile : fileList) {
                    BufferedImage image = ImageIO.read(pngFile);
                    g.drawImage(image, i, j, null);
                    i += image.getWidth();
                    counter++;
                    if (counter == COLUMNS_COUNT) {
                        i = 0;
                        counter = 0;
                        j += image.getHeight();
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return bufferedImage;
        }
        private static BufferedImage handlePngFile(File pngFile, Color myColor) {
            try {
                BufferedImage image = ImageIO.read(pngFile);
                for (int i = 0; i < image.getWidth(); i++) {
                    for (int j = 0; j < image.getHeight(); j++) {
                        Color pixelColor = new Color(image.getRGB(i, j), true);
                        int a = pixelColor.getAlpha();
                        //a += 50;//Повышаем интенсивность - уменьшаем прозрачность
                        if (pixelColor.getRed() != 0) {
                            int r = myColor.getRed();
                            int g = myColor.getGreen();
                            int b = myColor.getBlue();
                            Color newColor = new Color(r, g, b, a);
                            image.setRGB(i, j, newColor.getRGB());
                        }
                    }
                }
                return image;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    Archive and conclusion

    I posted the badges already repainted in different colors - use your health! Or you can deal with the script and repaint it in the color that you specifically need. And do not forget that all the icons with the alpha channel, respectively, on a white background, they will look lighter than the color that you set for them.

    In addition, the idea came up to write a script that changes the existing large icon to different sizes with smoothing and stuffs it into folders for different pixel densities. If there are no ready-made and free scripts that do this in automatic mode, I will definitely write my own and post it.

    As it turned out in the comments, there is a site http://romannurik.github.io/AndroidAssetStudio/index.htmlwhich paints the icons more conveniently and provides a bunch of other functions. True, he obliges to indicate a back link when using and does not know how to process icons in bulk, so my approach also makes some sense.

    Also popular now: