グラデーション画像からAndroidのXMLを自動生成する

Androidでは、画像ファイルをそのままアプリにはめこむのではなく、XMLでスタイルを定義することで、画像を作成することができます。

ここで、デザイナが下記のような画像ファイルでボタンを作成したとします。

![](http://3.bp.blogspot.com/-hXTgLY-nrnU/UMBmCGxycJI/AAAAAAAADSQ/9vCKqfAjMmA/s1600/test.png)
が、エンジニアは、ここで困ります。XMLでグラデーションを描画するためには、グラデーションの始まりと終わりの色の16進数を入力する必要があるからです。エンジニアがカラーピッカーを立ち上げ、RGBを取得し、16進数に変換する・・・なんて非常に手間がかかります。

というわけで、画像を引数として与えると、XMLを生成してくれるPythonスクリプトを書きました。画像ライブラリとしてPILが必要です。

`python generateDrawableXML.py [img_path]`

```python:generateDrawableXML.py
    #! /usr/bin/env python  
    # -*- coding: utf-8 -*-  
      
    import sys  
    from PIL import Image  
      
    def getCenterList(_list, order=1):  
        if order > 0:  
            return [i for (i, x) in enumerate(_list) if x == max(_list)]  
        else:  
            return [i for (i, x) in enumerate(_list) if x == min(_list)]  
      
    def getHexColor(rgb):  
        return '#FF' + getHexStr(rgb[0]) + getHexStr(rgb[1]) + getHexStr(rgb[2])  
      
    def getHexStr(color):  
        hexStr = hex(color)[2:].upper()  
        return hexStr if len(hexStr) == 2 else '0' + hexStr  
      
    def main(path):  
        img = Image.open(path)  
        img = img.resize((1, img.size[1]))  
        img = img.convert("RGB")  
      
        rgbs        = list(img.getdata())  
        height      = len(rgbs)  
        startRGB    = rgbs[0]  
        endRGB      = rgbs[len(rgbs) - 1]  
        centerRGB   = None  
        centerIndex = 0  
      
        rs, gs, bs = [], [], []  
        for rgb in rgbs:  
            rs.append(rgb[0])  
            gs.append(rgb[1])  
            bs.append(rgb[2])  
      
        for i in [-1, 1]:  
            centerSet = set(getCenterList(rs, i)) & set(getCenterList(gs, i)) & set(getCenterList(bs, i))  
            if len(centerSet) == 0: continue  
            index = list(centerSet)[0]  
            if index != 0 and index != (height - 1):  
                centerRGB   = rgbs[index]  
                centerIndex = index  
      
        centerStr = ""  
        if centerRGB:  
            centerStr = """ 
            android:centerColor="%s" 
            android:centerY="%s" 
            """ % (getHexColor(centerRGB), round(float(centerIndex) / float(height - 1), 1))  
      
      
        print """ 
    <?xml version="1.0" encoding="utf-8"?> 
    <shape xmlns:android="http://schemas.android.com/apk/res/android" 
        android:shape="rectangle"> 
        <gradient 
            android:angle="270" 
            android:type="linear" 
            android:startColor="%s" 
            android:endColor="%s"%s 
            /> 
    </shape>""" % (getHexColor(startRGB), getHexColor(endRGB), centerStr)  
      
    if __name__ == '__main__':  
        argvs = sys.argv  
        if len(argvs) != 2:  
            print("python " + argvs[0] + " [img_path]")  
        else:  
            main(argvs[1])  
```


実行すると下記XMLが生成されます。

```xml
    <?xml version="1.0" encoding="utf-8"?>  
    <shape xmlns:android="http://schemas.android.com/apk/res/android"  
        android:shape="rectangle">  
        <gradient  
            android:angle="270"  
            android:type="linear"  
            android:startColor="#FF330F55"  
            android:endColor="#FFC45D19"  
            />  
    </shape>
```


また、center要素がある画像でも大丈夫。
![](http://1.bp.blogspot.com/-OCXcUvk26j4/UMBoNKX20XI/AAAAAAAADSY/z58sSneRcyY/s1600/gradient+2.png)

```xml
    <?xml version="1.0" encoding="utf-8"?>  
    <shape xmlns:android="http://schemas.android.com/apk/res/android"  
        android:shape="rectangle">  
        <gradient  
            android:angle="270"  
            android:type="linear"  
            android:startColor="#FFFFC081"  
            android:endColor="#FFFFA349"  
            android:centerColor="#FFFF8101"  
            android:centerY="0.6"  
            />  
    </shape>  
```

※横方向のグラデーションや、円型のグラデーションには対応していません。