サイエンスデザインノート

仕事やプログラミングやそうでないことwo覚え書くブログです

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");
    }

解決法

Long.decode(String)を使う。

    @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。