Merge "Adjust the background text image width to reduce its size"
This commit is contained in:
commit
4ef9cb27eb
2 changed files with 82 additions and 27 deletions
|
@ -101,7 +101,7 @@ TEST_P(ResourcesTest, ValidateLocale) {
|
|||
EXPECT_LT(0, len) << "Locale string should be non-empty.";
|
||||
EXPECT_NE(0, row[5]) << "Locale string is missing.";
|
||||
|
||||
ASSERT_GT(png_->height(), y + 1 + h) << "Locale: " << kLocale << " is not found in the file.";
|
||||
ASSERT_GE(png_->height(), y + 1 + h) << "Locale: " << kLocale << " is not found in the file.";
|
||||
char* loc = reinterpret_cast<char*>(&row[5]);
|
||||
if (matches_locale(loc, kLocale.c_str())) {
|
||||
EXPECT_TRUE(android::base::StartsWith(loc, kLocale));
|
||||
|
|
|
@ -60,8 +60,9 @@ public class ImageGenerator {
|
|||
// This is the canvas we used to draw texts.
|
||||
private BufferedImage mBufferedImage;
|
||||
|
||||
// The width in pixels of our image. Once set, its value won't change.
|
||||
private final int mImageWidth;
|
||||
// The width in pixels of our image. The value will be adjusted once when we calculate the
|
||||
// maximum width to fit the wrapped text strings.
|
||||
private int mImageWidth;
|
||||
|
||||
// The current height in pixels of our image. We will adjust the value when drawing more texts.
|
||||
private int mImageHeight;
|
||||
|
@ -79,6 +80,9 @@ public class ImageGenerator {
|
|||
// The directory that contains all the needed font files (e.g. ttf, otf, ttc files).
|
||||
private final String mFontDirPath;
|
||||
|
||||
// Align the text in the center of the image.
|
||||
private final boolean mCenterAlignment;
|
||||
|
||||
// An explicit map from language to the font name to use.
|
||||
// The map is extracted from frameworks/base/data/fonts/fonts.xml.
|
||||
// And the language-subtag-registry is found in:
|
||||
|
@ -130,7 +134,9 @@ public class ImageGenerator {
|
|||
};
|
||||
|
||||
// Languages that breaks on arbitrary characters.
|
||||
// TODO(xunchang) switch to icu library if possible.
|
||||
// TODO(xunchang) switch to icu library if possible. For example, for Thai and Khmer, there is
|
||||
// no space between words; and word breaking is based on grammatical analysis and on word
|
||||
// matching in dictionaries.
|
||||
private static final Set<String> LOGOGRAM_LANGUAGE =
|
||||
new HashSet<String>() {
|
||||
{
|
||||
|
@ -138,6 +144,7 @@ public class ImageGenerator {
|
|||
add("km"); // Khmer
|
||||
add("ko"); // Korean
|
||||
add("lo"); // Lao
|
||||
add("th"); // Thai
|
||||
add("zh"); // Chinese
|
||||
}
|
||||
};
|
||||
|
@ -154,8 +161,13 @@ public class ImageGenerator {
|
|||
}
|
||||
|
||||
/** Initailizes the fields of the image image. */
|
||||
public ImageGenerator(int imageWidth, String textName, float fontSize, String fontDirPath) {
|
||||
mImageWidth = imageWidth;
|
||||
public ImageGenerator(
|
||||
int initialImageWidth,
|
||||
String textName,
|
||||
float fontSize,
|
||||
String fontDirPath,
|
||||
boolean centerAlignment) {
|
||||
mImageWidth = initialImageWidth;
|
||||
mImageHeight = INITIAL_HEIGHT;
|
||||
mVerticalOffset = 0;
|
||||
|
||||
|
@ -165,6 +177,8 @@ public class ImageGenerator {
|
|||
mTextName = textName;
|
||||
mFontSize = fontSize;
|
||||
mFontDirPath = fontDirPath;
|
||||
|
||||
mCenterAlignment = centerAlignment;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -299,8 +313,6 @@ public class ImageGenerator {
|
|||
List<String> wrappedText = new ArrayList<>();
|
||||
StringTokenizer st = new StringTokenizer(text, " \n");
|
||||
|
||||
// TODO(xunchang). We assume that all words can fit on the screen. Raise an
|
||||
// IllegalStateException if the word is wider than the image width.
|
||||
StringBuilder line = new StringBuilder();
|
||||
while (st.hasMoreTokens()) {
|
||||
String token = st.nextToken();
|
||||
|
@ -373,6 +385,43 @@ public class ImageGenerator {
|
|||
return info;
|
||||
}
|
||||
|
||||
/** Returns Graphics2D object that uses the given locale. */
|
||||
private Graphics2D createGraphics(Locale locale) throws IOException, FontFormatException {
|
||||
Graphics2D graphics = mBufferedImage.createGraphics();
|
||||
graphics.setColor(Color.WHITE);
|
||||
graphics.setRenderingHint(
|
||||
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
|
||||
graphics.setFont(loadFontsByLocale(locale.getLanguage()));
|
||||
|
||||
return graphics;
|
||||
}
|
||||
|
||||
/** Returns the maximum screen width needed to fit the given text after wrapping. */
|
||||
private int measureTextWidth(String text, Locale locale)
|
||||
throws IOException, FontFormatException {
|
||||
Graphics2D graphics = createGraphics(locale);
|
||||
FontMetrics fontMetrics = graphics.getFontMetrics();
|
||||
List<String> wrappedText = wrapText(text, fontMetrics, locale.getLanguage());
|
||||
|
||||
int textWidth = 0;
|
||||
for (String line : wrappedText) {
|
||||
textWidth = Math.max(textWidth, fontMetrics.stringWidth(line));
|
||||
}
|
||||
|
||||
// This may happen if one single word is larger than the image width.
|
||||
if (textWidth > mImageWidth) {
|
||||
throw new IllegalStateException(
|
||||
"Wrapped text width "
|
||||
+ textWidth
|
||||
+ " is larger than image width "
|
||||
+ mImageWidth
|
||||
+ " for locale: "
|
||||
+ locale);
|
||||
}
|
||||
|
||||
return textWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws the text string on the canvas for given locale.
|
||||
*
|
||||
|
@ -381,16 +430,11 @@ public class ImageGenerator {
|
|||
* @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.
|
||||
*/
|
||||
private void drawText(String text, Locale locale, String languageTag, boolean centralAlignment)
|
||||
private void drawText(String text, Locale locale, String languageTag)
|
||||
throws IOException, FontFormatException {
|
||||
Graphics2D graphics = mBufferedImage.createGraphics();
|
||||
graphics.setColor(Color.WHITE);
|
||||
graphics.setRenderingHint(
|
||||
RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
|
||||
graphics.setFont(loadFontsByLocale(locale.getLanguage()));
|
||||
|
||||
System.out.println("Encoding \"" + locale + "\" as \"" + languageTag + "\": " + text);
|
||||
|
||||
Graphics2D graphics = createGraphics(locale);
|
||||
FontMetrics fontMetrics = graphics.getFontMetrics();
|
||||
List<String> wrappedText = wrapText(text, fontMetrics, locale.getLanguage());
|
||||
|
||||
|
@ -402,7 +446,7 @@ public class ImageGenerator {
|
|||
int lineHeight = fontMetrics.getHeight();
|
||||
// Doubles the height of the image if we are short of space.
|
||||
if (mVerticalOffset + lineHeight >= mImageHeight) {
|
||||
resizeHeight(mImageHeight * 2);
|
||||
resize(mImageWidth, mImageHeight * 2);
|
||||
}
|
||||
|
||||
// Draws the text at mVerticalOffset and increments the offset with line space.
|
||||
|
@ -410,7 +454,7 @@ public class ImageGenerator {
|
|||
|
||||
// Draws from right if it's an RTL language.
|
||||
int x =
|
||||
centralAlignment
|
||||
mCenterAlignment
|
||||
? (mImageWidth - fontMetrics.stringWidth(line)) / 2
|
||||
: RTL_LANGUAGE.contains(languageTag)
|
||||
? mImageWidth - fontMetrics.stringWidth(line)
|
||||
|
@ -431,18 +475,19 @@ public class ImageGenerator {
|
|||
}
|
||||
|
||||
/**
|
||||
* Redraws the image with the new height.
|
||||
* Redraws the image with the new width and new height.
|
||||
*
|
||||
* @param width the new width of the image in pixels.
|
||||
* @param height the new height of the image in pixels.
|
||||
*/
|
||||
private void resizeHeight(int height) {
|
||||
BufferedImage resizedImage =
|
||||
new BufferedImage(mImageWidth, height, BufferedImage.TYPE_BYTE_GRAY);
|
||||
private void resize(int width, int height) {
|
||||
BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
|
||||
Graphics2D graphic = resizedImage.createGraphics();
|
||||
graphic.drawImage(mBufferedImage, 0, 0, null);
|
||||
graphic.dispose();
|
||||
|
||||
mBufferedImage = resizedImage;
|
||||
mImageWidth = width;
|
||||
mImageHeight = height;
|
||||
}
|
||||
|
||||
|
@ -458,11 +503,16 @@ public class ImageGenerator {
|
|||
public void generateImage(Map<Locale, String> localizedTextMap, String outputPath)
|
||||
throws FontFormatException, IOException {
|
||||
Map<String, Integer> languageCount = new TreeMap<>();
|
||||
int textWidth = 0;
|
||||
for (Locale locale : localizedTextMap.keySet()) {
|
||||
String language = locale.getLanguage();
|
||||
languageCount.put(language, languageCount.getOrDefault(language, 0) + 1);
|
||||
textWidth = Math.max(textWidth, measureTextWidth(localizedTextMap.get(locale), locale));
|
||||
}
|
||||
|
||||
// Removes the black margins to reduce the size of the image.
|
||||
resize(textWidth, mImageHeight);
|
||||
|
||||
for (Locale locale : localizedTextMap.keySet()) {
|
||||
Integer count = languageCount.get(locale.getLanguage());
|
||||
// Recovery expects en-US instead of en_US.
|
||||
|
@ -475,12 +525,10 @@ public class ImageGenerator {
|
|||
languageCount.put(locale.getLanguage(), count - 1);
|
||||
}
|
||||
|
||||
drawText(localizedTextMap.get(locale), locale, languageTag, false);
|
||||
drawText(localizedTextMap.get(locale), locale, languageTag);
|
||||
}
|
||||
|
||||
// TODO(xunchang) adjust the width to save some space if all texts are smaller than
|
||||
// imageWidth.
|
||||
resizeHeight(mVerticalOffset);
|
||||
resize(mImageWidth, mVerticalOffset);
|
||||
ImageIO.write(mBufferedImage, "png", new File(outputPath));
|
||||
}
|
||||
|
||||
|
@ -528,11 +576,17 @@ public class ImageGenerator {
|
|||
|
||||
options.addOption(
|
||||
OptionBuilder.withLongOpt("output_file")
|
||||
.withDescription("Path to the generated image")
|
||||
.withDescription("Path to the generated image.")
|
||||
.hasArgs(1)
|
||||
.isRequired()
|
||||
.create());
|
||||
|
||||
options.addOption(
|
||||
OptionBuilder.withLongOpt("center_alignment")
|
||||
.withDescription("Align the text in the center of the screen.")
|
||||
.hasArg(false)
|
||||
.create());
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
|
@ -557,7 +611,8 @@ public class ImageGenerator {
|
|||
imageWidth,
|
||||
cmd.getOptionValue("text_name"),
|
||||
DEFAULT_FONT_SIZE,
|
||||
cmd.getOptionValue("font_dir"));
|
||||
cmd.getOptionValue("font_dir"),
|
||||
cmd.hasOption("center_alignment"));
|
||||
|
||||
Map<Locale, String> localizedStringMap =
|
||||
imageGenerator.readLocalizedStringFromXmls(cmd.getOptionValue("resource_dir"));
|
||||
|
|
Loading…
Reference in a new issue