Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b97f7e53 authored by Tianjie Xu's avatar Tianjie Xu
Browse files

image generator: format the java file

Format the file with google-java-format --aosp. This makes the presubmit
hook happy.

Bug: 74397117
Test: mma
Change-Id: Ie342ed11449414b63f2d1ae781023e940b136bcb
parent 02a94555
Loading
Loading
Loading
Loading
+482 −469
Original line number Diff line number Diff line
@@ -50,9 +50,7 @@ import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

/**
 * Command line tool to generate the localized image for recovery mode.
 */
/** Command line tool to generate the localized image for recovery mode. */
public class ImageGenerator {
    // Initial height of the image to draw.
    private static final int INITIAL_HEIGHT = 20000;
@@ -86,7 +84,9 @@ public class ImageGenerator {
    // And the language-subtag-registry is found in:
    // https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
    private static final String DEFAULT_FONT_NAME = "Roboto-Regular";
  private static final Map<String, String> LANGUAGE_TO_FONT_MAP = new TreeMap<String, String>() {{
    private static final Map<String, String> LANGUAGE_TO_FONT_MAP =
            new TreeMap<String, String>() {
                {
                    put("am", "NotoSansEthiopic-Regular");
                    put("ar", "NotoNaskhArabicUI-Regular");
                    put("as", "NotoSansBengaliUI-Regular");
@@ -114,30 +114,35 @@ public class ImageGenerator {
                    put("th", "NotoSansThaiUI-Regular");
                    put("ur", "NotoNaskhArabicUI-Regular");
                    put("zh", "NotoSansCJK-Regular");
  }};
                }
            };

    // Languages that write from right to left.
  private static final Set<String> RTL_LANGUAGE = new HashSet<String>() {{
    private static final Set<String> RTL_LANGUAGE =
            new HashSet<String>() {
                {
                    add("ar"); // Arabic
                    add("fa"); // Persian
                    add("he"); // Hebrew
                    add("iw"); // Hebrew
                    add("ur"); // Urdu
  }};
                }
            };

    // Languages that breaks on arbitrary characters.
    // TODO(xunchang) switch to icu library if possible.
  private static final Set<String> LOGOGRAM_LANGUAGE = new HashSet<String>() {{
    private static final Set<String> LOGOGRAM_LANGUAGE =
            new HashSet<String>() {
                {
                    add("ja"); // Japanese
                    add("km"); // Khmer
                    add("ko"); // Korean
                    add("lo"); // Lao
                    add("zh"); // Chinese
  }};
                }
            };

  /**
   * Exception to indicate the failure to find the translated text strings.
   */
    /** Exception to indicate the failure to find the translated text strings. */
    public static class LocalizedStringNotFoundException extends Exception {
        public LocalizedStringNotFoundException(String message) {
            super(message);
@@ -148,9 +153,7 @@ public class ImageGenerator {
        }
    }

  /**
   * Initailizes the fields of the image image.
   */
    /** Initailizes the fields of the image image. */
    public ImageGenerator(int imageWidth, String textName, float fontSize, String fontDirPath) {
        mImageWidth = imageWidth;
        mImageHeight = INITIAL_HEIGHT;
@@ -165,20 +168,18 @@ public class ImageGenerator {
    }

    /**
   * Finds the translated text string for the given textName by parsing the resourceFile.
   * Example of the xml fields:
   * <resources xmlns:android="http://schemas.android.com/apk/res/android">
   *   <string name="recovery_installing_security" msgid="9184031299717114342">
   * "Sicherheitsupdate wird installiert"</string>
   * </resources>
     * Finds the translated text string for the given textName by parsing the resourceFile. Example
     * of the xml fields: <resources xmlns:android="http://schemas.android.com/apk/res/android">
     * <string name="recovery_installing_security" msgid="9184031299717114342"> "Sicherheitsupdate
     * wird installiert"</string> </resources>
     *
     * @param resourceFile the input resource file in xml format.
     * @param textName the name description of the text.
   *
     * @return the string representation of the translated text.
     */
  private String getTextString(File resourceFile, String textName) throws IOException,
      ParserConfigurationException, org.xml.sax.SAXException, LocalizedStringNotFoundException {
    private String getTextString(File resourceFile, String textName)
            throws IOException, ParserConfigurationException, org.xml.sax.SAXException,
                    LocalizedStringNotFoundException {
        DocumentBuilderFactory builder = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = builder.newDocumentBuilder();

@@ -194,13 +195,11 @@ public class ImageGenerator {
            }
        }

    throw new LocalizedStringNotFoundException(textName + " not found in "
        + resourceFile.getName());
        throw new LocalizedStringNotFoundException(
                textName + " not found in " + resourceFile.getName());
    }

  /**
   * Constructs the locale from the name of the resource file.
   */
    /** Constructs the locale from the name of the resource file. */
    private Locale getLocaleFromFilename(String filename) throws IOException {
        // Gets the locale string by trimming the top "values-".
        String localeString = filename.substring(7);
@@ -226,23 +225,22 @@ public class ImageGenerator {
     * directory and collect the translated text.
     *
     * @param resourcePath the path to the resource directory
   *
     * @return a map with the locale as key, and translated text as value
   *
     * @throws LocalizedStringNotFoundException if we cannot find the translated text for the given
     *     locale
   **/
  public Map<Locale, String> readLocalizedStringFromXmls(String resourcePath) throws
      IOException, LocalizedStringNotFoundException {
     */
    public Map<Locale, String> readLocalizedStringFromXmls(String resourcePath)
            throws IOException, LocalizedStringNotFoundException {
        File resourceDir = new File(resourcePath);
        if (!resourceDir.isDirectory()) {
            throw new LocalizedStringNotFoundException(resourcePath + " is not a directory.");
        }

        Map<Locale, String> result =
        // Overrides the string comparator so that sr is sorted behind sr-Latn. And thus recovery
        // can find the most relevant locale when going down the list.
        new TreeMap<>((Locale l1, Locale l2) -> {
                // Overrides the string comparator so that sr is sorted behind sr-Latn. And thus
                // recovery can find the most relevant locale when going down the list.
                new TreeMap<>(
                        (Locale l1, Locale l2) -> {
                            if (l1.toLanguageTag().equals(l2.toLanguageTag())) {
                                return 0;
                            }
@@ -256,8 +254,8 @@ public class ImageGenerator {
                        });

        // Find all the localized resource subdirectories in the format of values-$LOCALE
    String[] nameList = resourceDir.list(
        (File file, String name) -> name.startsWith("values-"));
        String[] nameList =
                resourceDir.list((File file, String name) -> name.startsWith("values-"));
        for (String name : nameList) {
            File textFile = new File(resourcePath, name + "/strings.xml");
            String localizedText;
@@ -292,12 +290,11 @@ public class ImageGenerator {
            }
        }

    throw new IOException("Can not find the font file " + fontName + " for language " + language);
        throw new IOException(
                "Can not find the font file " + fontName + " for language " + language);
    }

  /**
   * Separates the text string by spaces and wraps it by words.
  **/
    /** Separates the text string by spaces and wraps it by words. */
    private List<String> wrapTextByWords(String text, FontMetrics metrics) {
        List<String> wrappedText = new ArrayList<>();
        StringTokenizer st = new StringTokenizer(text, " \n");
@@ -318,9 +315,7 @@ public class ImageGenerator {
        return wrappedText;
    }

  /**
   * One character is a word for CJK.
   */
    /** One character is a word for CJK. */
    private List<String> wrapTextByCharacters(String text, FontMetrics metrics) {
        List<String> wrappedText = new ArrayList<>();

@@ -343,7 +338,6 @@ public class ImageGenerator {
     * @param text the string representation of text to wrap
     * @param metrics the metrics of the Font used to draw the text; it gives the width in pixels of
     *     the text given its string representation
   *
     * @return a list of strings with their width smaller than mImageWidth pixels
     */
    private List<String> wrapText(String text, FontMetrics metrics, String language) {
@@ -355,16 +349,20 @@ public class ImageGenerator {
    }

    /**
   * Encodes the information of the text image for |locale|.
   * According to minui/resources.cpp, the width, height and locale of the image is decoded as:
   *   int w = (row[1] << 8) | row[0];
   *   int h = (row[3] << 8) | row[2];
   *   __unused int len = row[4];
   *   char* loc = reinterpret_cast<char*>(&row[5]);
     * Encodes the information of the text image for |locale|. According to minui/resources.cpp, the
     * width, height and locale of the image is decoded as: int w = (row[1] << 8) | row[0]; int h =
     * (row[3] << 8) | row[2]; __unused int len = row[4]; char* loc =
     * reinterpret_cast<char*>(&row[5]);
     */
    private List<Integer> encodeTextInfo(int width, int height, String locale) {
    List<Integer> info = new ArrayList<>(Arrays.asList(width & 0xff, width >> 8,
        height & 0xff, height >> 8, locale.length()));
        List<Integer> info =
                new ArrayList<>(
                        Arrays.asList(
                                width & 0xff,
                                width >> 8,
                                height & 0xff,
                                height >> 8,
                                locale.length()));

        byte[] localeBytes = locale.getBytes();
        for (byte b : localeBytes) {
@@ -380,7 +378,6 @@ public class ImageGenerator {
     *
     * @param text the string to draw on canvas
     * @param locale the current locale tag of the string to draw
   *
     * @throws IOException if we cannot find the corresponding font file for the given locale.
     * @throws FontFormatException if we failed to load the font file for the given locale.
     */
@@ -412,8 +409,12 @@ public class ImageGenerator {
            int baseLine = mVerticalOffset + lineHeight - fontMetrics.getDescent();

            // Draws from right if it's an RTL language.
      int x = centralAlignment ? (mImageWidth - fontMetrics.stringWidth(line)) / 2 :
          RTL_LANGUAGE.contains(languageTag) ? mImageWidth - fontMetrics.stringWidth(line) : 0;
            int x =
                    centralAlignment
                            ? (mImageWidth - fontMetrics.stringWidth(line)) / 2
                            : RTL_LANGUAGE.contains(languageTag)
                                    ? mImageWidth - fontMetrics.stringWidth(line)
                                    : 0;

            graphics.drawString(line, x, baseLine);

@@ -424,7 +425,7 @@ public class ImageGenerator {
        int currentImageHeight = mVerticalOffset - currentImageStart - 1;
        List<Integer> info = encodeTextInfo(mImageWidth, currentImageHeight, languageTag);
        for (int i = 0; i < info.size(); i++) {
      int pixel[] =  { info.get(i) };
            int[] pixel = {info.get(i)};
            mBufferedImage.getRaster().setPixel(i, currentImageStart, pixel);
        }
    }
@@ -450,13 +451,12 @@ public class ImageGenerator {
     *
     * @param localizedTextMap a map from locale to its translated text string
     * @param outputPath the path to write the generated image file.
   *
     * @throws FontFormatException if there's a format error in one of the font file
     * @throws IOException if we cannot find the font file for one of the locale, or we failed to
     *     write the image file.
     */
  public void generateImage(Map<Locale, String> localizedTextMap, String outputPath) throws
      FontFormatException, IOException {
    public void generateImage(Map<Locale, String> localizedTextMap, String outputPath)
            throws FontFormatException, IOException {
        Map<String, Integer> languageCount = new TreeMap<>();
        for (Locale locale : localizedTextMap.keySet()) {
            String language = locale.getLanguage();
@@ -468,7 +468,8 @@ public class ImageGenerator {
            // Recovery expects en-US instead of en_US.
            String languageTag = locale.toLanguageTag();
            if (count == 1) {
        // Make the last country variant for a given language be the catch-all for that language.
                // Make the last country variant for a given language be the catch-all for that
                // language.
                languageTag = locale.getLanguage();
            } else {
                languageCount.put(locale.getLanguage(), count - 1);
@@ -477,50 +478,56 @@ public class ImageGenerator {
            drawText(localizedTextMap.get(locale), locale, languageTag, false);
        }

    // TODO(xunchang) adjust the width to save some space if all texts are smaller than imageWidth.
        // TODO(xunchang) adjust the width to save some space if all texts are smaller than
        // imageWidth.
        resizeHeight(mVerticalOffset);
        ImageIO.write(mBufferedImage, "png", new File(outputPath));
    }

    /** Prints the helper message. */
    public static void printUsage(Options options) {
        new HelpFormatter().printHelp("java -jar path_to_jar [required_options]", options);

    }

    /** Creates the command line options. */
    public static Options createOptions() {
        Options options = new Options();
    options.addOption(OptionBuilder
        .withLongOpt("image_width")
        options.addOption(
                OptionBuilder.withLongOpt("image_width")
                        .withDescription("The initial width of the image in pixels.")
                        .hasArgs(1)
                        .isRequired()
                        .create());

    options.addOption(OptionBuilder
        .withLongOpt("text_name")
        .withDescription("The description of the text string, e.g. recovery_erasing")
        options.addOption(
                OptionBuilder.withLongOpt("text_name")
                        .withDescription(
                                "The description of the text string, e.g. recovery_erasing")
                        .hasArgs(1)
                        .isRequired()
                        .create());

    options.addOption(OptionBuilder
        .withLongOpt("font_dir")
        .withDescription("The directory that contains all the support font format files, e.g."
            + " $OUT/system/fonts/")
        options.addOption(
                OptionBuilder.withLongOpt("font_dir")
                        .withDescription(
                                "The directory that contains all the support font format files, "
                                        + "e.g. $OUT/system/fonts/")
                        .hasArgs(1)
                        .isRequired()
                        .create());

    options.addOption(OptionBuilder
        .withLongOpt("resource_dir")
        .withDescription("The resource directory that contains all the translated strings in xml"
            + " format, e.g. bootable/recovery/tools/recovery_l10n/res/")
        options.addOption(
                OptionBuilder.withLongOpt("resource_dir")
                        .withDescription(
                                "The resource directory that contains all the translated strings in"
                                        + " xml format, e.g."
                                        + " bootable/recovery/tools/recovery_l10n/res/")
                        .hasArgs(1)
                        .isRequired()
                        .create());

    options.addOption(OptionBuilder
        .withLongOpt("output_file")
        options.addOption(
                OptionBuilder.withLongOpt("output_file")
                        .withDescription("Path to the generated image")
                        .hasArgs(1)
                        .isRequired()
@@ -529,8 +536,10 @@ public class ImageGenerator {
        return options;
    }

  public static void main(String[] args) throws NumberFormatException, IOException,
      FontFormatException, LocalizedStringNotFoundException {
    /** The main function parses the command line options and generates the desired text image. */
    public static void main(String[] args)
            throws NumberFormatException, IOException, FontFormatException,
                    LocalizedStringNotFoundException {
        Options options = createOptions();
        CommandLine cmd;
        try {
@@ -543,8 +552,12 @@ public class ImageGenerator {

        int imageWidth = Integer.parseUnsignedInt(cmd.getOptionValue("image_width"));

    ImageGenerator imageGenerator = new ImageGenerator(imageWidth, cmd.getOptionValue("text_name"),
        DEFAULT_FONT_SIZE, cmd.getOptionValue("font_dir"));
        ImageGenerator imageGenerator =
                new ImageGenerator(
                        imageWidth,
                        cmd.getOptionValue("text_name"),
                        DEFAULT_FONT_SIZE,
                        cmd.getOptionValue("font_dir"));

        Map<Locale, String> localizedStringMap =
                imageGenerator.readLocalizedStringFromXmls(cmd.getOptionValue("resource_dir"));