Javaで16進数の文字からアルファ(半透明)値を持ったColorを作成する。
アルファ値が128以上の16進数文字列(0x80000000以上)をデコードしようとすると、Integerの桁があふれてうまくデコードできないよ、という話。
Color.decode(String) による作成
基本のデコード方法。アルファ値無し。
@Test public void decodeHexString() { Color color = Color.decode("#000000"); assertEquals("no-alpha", 255, color.getAlpha()); assertEquals("red", 0, color.getRed()); assertEquals("blue", 0, color.getBlue()); assertEquals("green", 0, color.getGreen()); }
Color#decode は解釈値にアルファ値を持っていても無視されるので、通常のコンストラクタ Color(int rgba, boolean hasalpha) から Integer#decode を利用して作成。
@Test public void decodeHexStringWithAlphaDigits() { assertEquals("decode method ignores alpha digits", 255, Color.decode("#00000000").getAlpha()); assertEquals("color construction with alpha", 0, new Color(Integer.decode("#00000000").intValue(), true).getAlpha()); }
ところがどっこい
Integerは符号付き32ビット整数なので、0x80000000以上はデコードできません。
@Test public void overflowToDecodeHexString() { assertEquals("max value of integer", 127, new Color(Integer.decode("#7FFFFFFF").intValue(), true).getAlpha()); Integer result = null; try { result = Integer.decode("#80000000"); } catch (NumberFormatException expected) { assertNull("cannot format #80000000", result); return; } fail("unreachable"); }
解決法
@Test public void decodeHexStringUsingDecodeOfLong() { Color decode = new Color(Long.decode("#FFFFFFFF").intValue(), true); assertEquals("alpha", 255, decode.getAlpha()); assertEquals("red", 255, decode.getRed()); assertEquals("blue", 255, decode.getBlue()); assertEquals("green", 255, decode.getGreen()); }
補足
Long.parseLong(String, 16)を使ってもOK。