Improve support of SSA (V4+) PrimaryColour style
This commit is contained in:
parent
0ead2af22c
commit
1364c01e09
@ -308,8 +308,8 @@ public final class SsaDecoder extends SimpleSubtitleDecoder {
|
||||
|
||||
// Apply primary color.
|
||||
if (style != null) {
|
||||
if (style.primaryColor != SsaStyle.SSA_COLOR_UNKNOWN) {
|
||||
spannableText.setSpan(new ForegroundColorSpan(style.primaryColor),
|
||||
if (style.primaryColor.isSet) {
|
||||
spannableText.setSpan(new ForegroundColorSpan(style.primaryColor.value),
|
||||
0, spannableText.length(), SpannableString.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
|
@ -89,9 +89,9 @@ import java.util.regex.Pattern;
|
||||
|
||||
public final String name;
|
||||
@SsaAlignment public final int alignment;
|
||||
@ColorInt public int primaryColor;
|
||||
public SsaColor primaryColor;
|
||||
|
||||
private SsaStyle(String name, @SsaAlignment int alignment, @ColorInt int primaryColor) {
|
||||
private SsaStyle(String name, @SsaAlignment int alignment, SsaColor primaryColor) {
|
||||
this.name = name;
|
||||
this.alignment = alignment;
|
||||
this.primaryColor = primaryColor;
|
||||
@ -152,14 +152,33 @@ import java.util.regex.Pattern;
|
||||
}
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
private static int parsePrimaryColor(String primaryColorStr) {
|
||||
private static SsaColor parsePrimaryColor(String primaryColorStr) {
|
||||
try {
|
||||
return ColorParser.parseSsaColor(primaryColorStr);
|
||||
return SsaColor.from(ColorParser.parseSsaColor(primaryColorStr.trim()));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
Log.w(TAG, "Failed parsing color value: " + primaryColorStr);
|
||||
}
|
||||
return SSA_COLOR_UNKNOWN;
|
||||
return SsaColor.UNSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an SSA V4+ style color in ARGB format.
|
||||
*/
|
||||
/* package */ static final class SsaColor {
|
||||
|
||||
public static SsaColor UNSET = new SsaColor(0, false);
|
||||
|
||||
public final @ColorInt int value;
|
||||
public final boolean isSet;
|
||||
|
||||
private SsaColor(@ColorInt int value, boolean isSet) {
|
||||
this.value = value;
|
||||
this.isSet = isSet;
|
||||
}
|
||||
|
||||
public static SsaColor from(@ColorInt int value) {
|
||||
return new SsaColor(value, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,17 +75,35 @@ public final class ColorParser {
|
||||
*/
|
||||
@ColorInt
|
||||
public static int parseSsaColor(String colorExpression) {
|
||||
// SSA V4+ color format is &HAABBGGRR.
|
||||
if (colorExpression.length() != 10 || !"&H".equals(colorExpression.substring(0, 2))) {
|
||||
throw new IllegalArgumentException();
|
||||
// The SSA V4+ color can be represented in hex (&HAABBGGRR) or in decimal format (byte order
|
||||
// AABBGGRR) and in both cases the alpha channel's value needs to be inverted as in case of SSA
|
||||
// the 0xFF alpha value means transparent and 0x00 means opaque which is the opposite from the
|
||||
// @ColorInt representation.
|
||||
int abgr;
|
||||
try {
|
||||
// Parse color from hex format (&HAABBGGRR).
|
||||
if (colorExpression.startsWith("&H")) {
|
||||
StringBuilder rgbaStringBuilder = new StringBuilder(colorExpression);
|
||||
if (colorExpression.length() < 10) {
|
||||
// Add leading zeros if necessary.
|
||||
while (rgbaStringBuilder.length() != 10) {
|
||||
rgbaStringBuilder.insert(2, "0");
|
||||
}
|
||||
// Convert &HAABBGGRR to #RRGGBBAA.
|
||||
String rgba = new StringBuilder()
|
||||
.append(colorExpression.substring(2))
|
||||
.append("#")
|
||||
.reverse()
|
||||
.toString();
|
||||
return parseColorInternal(rgba, true);
|
||||
}
|
||||
abgr = (int) Long.parseLong(colorExpression.substring(2), 16);
|
||||
} else {
|
||||
// Parse color from decimal format (bytes order AABBGGRR).
|
||||
abgr = (int) Long.parseLong(colorExpression);
|
||||
}
|
||||
} catch (NumberFormatException ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
// Convert ABGR to ARGB.
|
||||
int a = ((abgr >> 24) & 0xFF) ^ 0xFF; // Flip alpha.
|
||||
int b = (abgr >> 16) & 0xFF;
|
||||
int g = (abgr >> 8) & 0xFF;
|
||||
int r = abgr & 0xff;
|
||||
return Color.argb(a, r, g, b);
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
|
@ -16,6 +16,8 @@
|
||||
package com.google.android.exoplayer2.util;
|
||||
|
||||
import static android.graphics.Color.BLACK;
|
||||
import static android.graphics.Color.BLUE;
|
||||
import static android.graphics.Color.GREEN;
|
||||
import static android.graphics.Color.RED;
|
||||
import static android.graphics.Color.WHITE;
|
||||
import static android.graphics.Color.YELLOW;
|
||||
@ -66,9 +68,21 @@ public final class ColorParserTest {
|
||||
// Hex colors in ColorParser are RGBA, where-as {@link Color#parseColor} takes ARGB.
|
||||
assertThat(parseTtmlColor("#FFFFFF00")).isEqualTo(parseColor("#00FFFFFF"));
|
||||
assertThat(parseTtmlColor("#12345678")).isEqualTo(parseColor("#78123456"));
|
||||
// SSA colors are in &HAABBGGRR format.
|
||||
assertThat(parseSsaColor("&HFF0000FF")).isEqualTo(RED);
|
||||
assertThat(parseSsaColor("&HFF00FFFF")).isEqualTo(YELLOW);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void ssaColorParsing() {
|
||||
// Hex format (&HAABBGGRR).
|
||||
assertThat(parseSsaColor("&H000000FF")).isEqualTo(RED);
|
||||
assertThat(parseSsaColor("&H0000FFFF")).isEqualTo(YELLOW);
|
||||
assertThat(parseSsaColor("&H400000FF")).isEqualTo(parseColor("#BFFF0000"));
|
||||
// Leading zeros.
|
||||
assertThat(parseSsaColor("&HFF")).isEqualTo(RED);
|
||||
assertThat(parseSsaColor("&HFF00")).isEqualTo(GREEN);
|
||||
assertThat(parseSsaColor("&HFF0000")).isEqualTo(BLUE);
|
||||
// Decimal format (AABBGGRR byte order).
|
||||
assertThat(parseSsaColor(/*#000000FF*/"255")).isEqualTo(parseColor("#FFFF0000"));
|
||||
assertThat(parseSsaColor(/*#FF0000FF*/"4278190335")).isEqualTo(parseColor("#00FF0000"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
x
Reference in New Issue
Block a user