GIMP関連

GIMP関連を置いておくページ。

使用・改変・配布など自由にしていただいてOKですが、無保証です。利用することで生じた一切の事柄に対して作者は責任を負いません。自己の責任においてご利用ください。

PIC loader

ダウンロード

X68000シリーズを中心に使われていた画像フォーマットPICをGIMPで開くためのプラグイン(Python-fu)です。

メモ

ソース

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from gimpfu import *
from struct import *

bitCounter = 0      #1ビットずつ読むためのビット位置を表す
bitBuffer = '0'     #1ビットずつ読むためのバッファ
width = 0
height = 0
cBuff = [-1]


class ColorTable:
    def __init__(self, color, next, prev):
        self.color = color
        self.next = next
        self.prev = prev

table = []
for i in range(128):
    table.append(ColorTable(0, i-1, i+1))

table[127].prev = 0
table[0].next = 127

color_p = 0
colorbits = 15
octa = [0]*64    #パレット計算用テーブル

def picload(filename, raw_filename):
    #:param str filename: ファイルパス
    #:param str raw_filename: 選択ファイル名
    #:rtype: gimp.Image
    #:return: 読み込んだ画像
    global colorbits
    global octa
    global width
    global height
    global cBuff

    fp = open(filename, 'rb')
    
    header = fp.read(3)
    if not header[0:3] == "PIC":
        gimp.message("X68 PICファイルではありません")
        fp.close()
        return 0

    
    comment = ''
    a = fp.read(1)
    while ( a !=chr(0x1A) ): #コメント読み込み
        comment = comment + a
        a = fp.read(1)
    a = ""
    while ( a!=chr(0) ):       #真のコメント終了まで読み飛ばし
        a = fp.read(1)
    a=fp.read(1)                    #予約1バイト読み飛ばし

    comtype = ord(fp.read(1))       #機種タイプとモード
    platform = comtype & 0x0F       #機種タイプ
                                    #0:X68k
                                    #1:PC-88VA
                                    #2:FM-TOWNS
                                    #3:MAC
                                    #$F:汎用
    mode = comtype >> 4             #機種ごとのモード
    if (platform != 0):
        gimp.message("対応していないPICです")
        return 0

    colorbits = unpack('>H', fp.read(2))[0]  #色のビット数
    width  = unpack('>H', fp.read(2))[0]    #横サイズ
    height = unpack('>H', fp.read(2))[0]    #縦サイズ

    if (colorbits == 16):  #5bit+1bit を 8bit に
        for i in range(64):
            octa[i] = int(round(i * 255 * 1.0 / 63))
    else:            #5bit を 8bit に
        octa = [0]*64
        for i in range(32):
            octa[i*2] = int(round(i * 255 * 1.0 / 31))
            octa[i*2+1] = octa[i*2]

    # 連鎖記録バッファ
    cBuff = [-1]* width * height

    #GIMPに画像を作成
    image = gimp.Image(width, height, RGB)
    image.filename = filename

    #レイヤー作成
    layer = pdb.gimp_layer_new(image, width, height, RGB, filename, 100, NORMAL_MODE )
    image.add_layer(layer, 0)

    #コメント追加
    if ( comment != '' ):
        comment_utf8 = unicode(comment, 'shift_jis').encode('utf-8')
        image.attach_new_parasite('gimp-comment',TRUE,comment_utf8)

    # 展開
    x = -1  # 展開中の位置 X
    y = 0   # 展開中の位置 Y
    c = 0   # 現在の色(X68) 初期値は0
    color =[0,0,0]  # 現在の色(GIMP)
    
    while ( TRUE ):
        l = read_len( fp )    # 長さを読む
        l -= 1

        # 次の変化点まで繰り返す
        while ( l ):
            # 右端の処理
            x += 1
            if ( x == width ):
                y += 1
                if ( y >= height ):
                    return image
                x = 0
                gimp.progress_update(float(y)/float(height)) # プログレスバーの更新

            # 連鎖点上を通過した時は、現在の色を変更
            c = cBuff[y*width+x]
            if ( c != -1 ):
                color = x68toGimp( c )
            
            # 現在の色を書き込む
            layer.set_pixel( x,y, color )

            l -= 1

        # 右端の処理
        x += 1
        if ( x == width ):
            y += 1
            if ( y >= height ):
                return image
            x = 0
            gimp.progress_update(float(y)/float(height)) # プログレスバーの更新

        # 新しい色の読み込み
        c = read_color( fp )
        color = x68toGimp( c )
        layer.set_pixel( x,y, color )
        
        # 連鎖ありなら、連鎖の展開
        if ( bit_load(1, fp) != 0):
            expand_chain(x, y, c, fp )



# キャッシュから色を取り出し
# その色が最新になるように更新する。
def get_color( idx ):
    global color_p
    global table
    if ( color_p != idx ):
        # まず位置idxをキャッシュから切り離す
        table[table[idx].prev].next = table[idx].next
        table[table[idx].next].prev = table[idx].prev
        # 最新色の次にidxを新たにセット
        table[table[color_p].prev].next = idx
	table[idx].prev = table[color_p].prev
	table[color_p].prev = idx
	table[idx].next = color_p
        # 最新色位置を更新
        color_p = idx

    return table[idx].color

    
# 新しい色をキャッシュに登録
def new_color( c ):
    global color_p
    global table
    color_p = table[color_p].prev
    table[color_p].color = c
    return ( c )

    

# 色の読み込み
def read_color(fp):
    global colorbits
    if ( bit_load(1,fp) == 0 ):    # キャッシュミス
        if ( colorbits == 15 ):
            c = bit_load(15,fp)<<1
        elif ( colorbits == 16 ):
            c = bit_load(16,fp)
	return ( new_color( c ))
    else:                       # キャッシュヒット
	return ( get_color( bit_load(7,fp)))


    
# 連鎖の展開
def expand_chain( x, y, c, fp ):
    global width
    global height
    global cBuff

    while (TRUE):
        a = bit_load(2,fp)
        if ( a == 0 ):
            if ( bit_load(1,fp) == 0 ): # 終わり
                return
            if ( bit_load(1,fp) == 0 ): # 左2つ
                x -= 2
            else:                    # 右2つ
                x += 2
        elif ( a == 1 ):             # 左1つ
            x -= 1
        elif ( a == 2 ):             # 真下
            pass
        elif ( a == 3 ):             # 右1つ
            x += 1

        y += 1
        if ( y < height ):     #画面を超えていないのなら連鎖を書き込む
            cBuff[width*y+x] = c

    

# X68色をGIMP色に換算
def x68toGimp( c ):
    global octa
    
    i = c & 0b0000000000000001
    g = ( (c & 0b1111100000000000)>>10 ) + i
    r = ( (c & 0b0000011111000000)>>5 ) + i
    b = c & 0b0000000000111111
    color = [octa[r],octa[g],octa[b]]

    return color


# 長さの読み込み
def read_len( fp ):
    a = 1
    while ( bit_load(1,fp) != 0 ):
        a += 1
    return ( bit_load(a,fp) + (1 << a) - 1)


# 1ビットずつ読む/ sizeビット分を返す
def bit_load( size, fp ):
    global bitCounter
    global bitBuffer
    a = 0
    b = 0
    size0 = size
    mask = [
        0b00000001,
        0b00000010,
        0b00000100,
        0b00001000,
        0b00010000,
        0b00100000,
        0b01000000,
        0b10000000 ]
    
    while ( size > 0 ):
        if ( bitCounter == 0 ):  # 0(空)なら1バイト読む
            bitBuffer = fp.read(1)
            bitCounter = 7
        else:
            bitCounter -= 1
        n = ord(bitBuffer) & mask[bitCounter]
        b = 1 if n else 0
        a = (a<<1) + b

        size -= 1

    return a
    
    




# 登録ハンドラ
def register_load_handlers():
    gimp.register_load_handler('python_fu_PIC_load', 'pic,xpic', '')
    pdb['gimp-register-file-handler-mime']('python_fu_PIC_load', 'image/xpic')
#    pdb['gimp-register-thumbnail-loader']('python_fu_PIC_load', '')


register(
    "python_fu_PIC_load", #コマンド名
    "X68用PIC形式画像を読み込みます", #プロシージャブラウザに表示されるプラグインに関する情報
    "X68用PIC形式画像を読み込みます", #プラグインのヘルプ
    "Akira M", #プラグインの作成者
    "Akira M", #プラグインの著作権保有者
    "2017", #年
    "X68 PIC", #メニューの中でプラグインに使用されるラベル
    None, #プラグインで処理する対象となる画像のタイプ
    [   #input args. Format (type, name, description, default [, extra])
        (PF_STRING, 'filename', 'The name of the file to load', None),
        (PF_STRING, 'raw-filename', 'The name entered', None),
    ], #プラグインのメソッドのパラメーター
    [(PF_IMAGE, 'image', 'Output image')], #プラグインのメソッドの結果 Format (type, name, description) 
    picload,
    on_query = register_load_handlers,
    menu = "<Load>",
)


main()

おまけ: PIC形式ファイルフォーマット

やなぎさわさんによる解説。LHAだったのをZIPで圧縮し直して転載します。

PICファイルフォーマット解説

MAG loader

ダウンロード

パソコン通信時代に使われていた画像フォーマットMAGをGIMPで開くためのプラグイン(Python-fu)です。

メモ

ソース

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from gimpfu import *
from struct import *

colors = 16
width = 640

def magload(filename, raw_filename):
    #:param str filename: ファイルパス
    #:param str raw_filename: 選択ファイル名
    #:rtype: gimp.Image
    #:return: 読み込んだ画像

    global colors
    global width
    
    fp = open(filename, 'rb')
    
    id = fp.read(8)
    if not id == "MAKI02  ":
        gimp.message("MAG形式ファイルではありません")
        fp.close()
        return 0
    platform = fp.read(4) # 機種コード
    username = fp.read(18) # ユーザー名

    comment = ''
    a = fp.read(1)
    while ( a !=chr(0x1A) ): #コメント読み込み
        comment = comment + a
        a = fp.read(1)

    # ヘッダ部スタート
    headerPoint = fp.tell()   # ヘッダ開始位置
    a = ord(fp.read(1))
    if not a == 0:
        gimp.message("MAG形式ファイルではありません")
        fp.close()
        return 0

    pcCode = ord(fp.read(1))     # 機種コード
    pcFlag = ord(fp.read(1))     # 機種依存フラグ
    screenMode = ord(fp.read(1)) # 画面モード
    x0 = unpack('<H', fp.read(2))[0]   # 表示開始位置X
    y0 = unpack('<H', fp.read(2))[0]   # 表示開始位置Y
    x1 = unpack('<H', fp.read(2))[0]   # 表示終了位置X
    y1 = unpack('<H', fp.read(2))[0]   # 表示終了位置Y
    flagAoffset = unpack('<L', fp.read(4))[0]   # フラグAのオフセット
    flagBoffset = unpack('<L', fp.read(4))[0]   # フラグBのオフセット
    flagBsize   = unpack('<L', fp.read(4))[0]   # フラグBのサイズ
    pixelOffset = unpack('<L', fp.read(4))[0]   # ピクセルのオフセット
    pixelSize   = unpack('<L', fp.read(4))[0]   # ピクセルのサイズ

    # パレットを読む
    color256 = screenMode >> 7    # 1なら256色モード
    if ( color256 ):
        colors = 256
        dotParPix = 2
        pal = [0] * 256 * 3
    else:
        colors = 16
        dotParPix = 4
        pal = [0] * 16 * 3

    tempX = x0 % dotParPix
    if ( tempX ): # x0がピクセル境界にないなら
        x00 = ( x0 // dotParPix ) * dotParPix
    else: x00 = x0
    tempX = (x1+1) % dotParPix
    if ( tempX ): # x1がピクセル境界にないなら
        x11 = ( (x1+1) // dotParPix ) * dotParPix + dotParPix -1
    else: x11 = x1
    
    width = x11 - x00 +1
    height = y1 - y0 +1

    for i in range( colors ):
        g = ord(fp.read(1))
        r = ord(fp.read(1))
        b = ord(fp.read(1))
        pal[i*3]   = r
        pal[i*3+1] = g
        pal[i*3+2] = b

    #GIMPに画像を作成
    image = gimp.Image(width, height, INDEXED)
    image.filename = filename

    #パレット(カラーマップ)を設定
    pdb.gimp_image_set_colormap(image, colors*3, pal)

    #レイヤー作成
    layer = pdb.gimp_layer_new(image, width, height, INDEXEDA_IMAGE, filename, 100, NORMAL_MODE )
    image.add_layer(layer, 0)
    
    #コメント追加
    comment_utf8 = ''
    if ( comment != '' ):
        comment_utf8 = unicode(comment, 'shift_jis').encode('utf-8')
    plat_utf8 = unicode(platform, 'shift_jis').encode('utf-8')
    uname_utf8 = unicode(username, 'shift_jis').encode('utf-8')
    pluscomm = "saved:"+plat_utf8+"\nuser :"+uname_utf8+"\nmemo :"
    comment_utf8 = pluscomm + comment_utf8
    image.attach_new_parasite('gimp-comment',TRUE,comment_utf8)

    


    # データを読むよ
    fp.seek( headerPoint+flagAoffset )
    flagA = fp.read( flagBoffset - flagAoffset )
    fp.seek( headerPoint+flagBoffset )
    flagB = fp.read( flagBsize )
    fp.seek( headerPoint+pixelOffset )
    pixels = fp.read( pixelSize )
    fp.close()

    # 展開するよ
    lineBuf = ''
    bitMask = 0x80
    countA = 0
    countB = 0
    countC = 0
    countPix = 0
    pixelWidth = width / dotParPix
    pixelBuf = [0] * pixelWidth * height

    x = 0
    y = 0
    while ( y < height ):
        while ( x < pixelWidth ):
            flagAbit = ord(flagA[countA]) & bitMask
            if( flagAbit != 0 ):
                flag = flagB[countB]
                countB += 1
            else:
                flag = chr(0)
            if ( y != 0 ):
                flag = chr( ord(flag) ^ ord(prevBuf[countC]) )
            lineBuf = lineBuf + flag
            countC += 1

            flagOne = ord(flag) >> 4
            if ( flagOne != 0 ):
                p = getPos( flagOne )
                pixelBuf[ y*pixelWidth + x ] = pixelBuf[ y*pixelWidth + x - p]
            else:
                pixelBuf[ y*pixelWidth + x ] = pixels[countPix]+pixels[countPix+1]
                countPix += 2
            x += 1
            flagTwo = ord(flag) & 0x0f
            if ( flagTwo != 0 ):
                p = getPos( flagTwo )
                pixelBuf[ y*pixelWidth + x ] = pixelBuf[ y*pixelWidth + x - p]
            else:
                pixelBuf[ y*pixelWidth + x ] = pixels[countPix]+pixels[countPix+1]
                countPix += 2
            x += 1

            bitMask = bitMask >> 1
            if( bitMask == 0 ):
                bitMask = 0x80
                countA += 1
        
        # 1ライン終了
        prevBuf = lineBuf[:]
        lineBuf = ''
	gimp.progress_update(float(y)/float(height*2)) # プログレスバーの更新
        y += 1
        x = 0
        countC = 0

    # 「ピクセル」(2バイト分の詰め合わせ)をドットに直すよ
    pixelWidthScreen = (x11 +1) / dotParPix
    for y in range(height):
        for x in range(pixelWidth):
            cc = pixelBuf[y*pixelWidth + x]
            if ( colors == 16 ):
                layer.set_pixel( x*4,   y, ( (ord(cc[0]) & 0xf0)>>4 ,255 ) )
                layer.set_pixel( x*4+1, y, ( ord(cc[0]) & 0x0f ,255 ) )
                layer.set_pixel( x*4+2, y, ( (ord(cc[1]) & 0xf0)>>4 ,255 ) )
                layer.set_pixel( x*4+3, y, ( ord(cc[1]) & 0x0f ,255 ) )
            else:
                layer.set_pixel( x*2,   y, ( ord(cc[0]) ,255 ) )
                layer.set_pixel( x*2+1, y, ( ord(cc[1]) ,255 ) )

	    gimp.progress_update(float(y+height)/float(height*2)) # プログレスバーの更新


    return image


    
    
# コピーすべきピクセルの位置を返す
# ラインの右端と次の左端が繋がってるとみて何個前になるか
def getPos ( num ):
    global colors
    global width

    if ( colors == 16 ):
        w = width/4
    else:
        w = width/2
    
    pos = 0
    # num:同じ色のピクセルの位置
    if   ( num == 0  ):  #0  同じものはない
        pos = 0
    elif ( num == 1  ):  #1  1つ左
        pos = 1
    elif ( num == 2  ):  #2  2つ左
        pos = 2
    elif ( num == 3  ):  #3  4つ左
        pos = 4
    elif ( num == 4  ):  #4  1つ上
        pos = w
    elif ( num == 5  ):  #5  1つ左で1つ上
        pos = w + 1
    elif ( num == 6  ):  #6  2つ上
        pos = w * 2
    elif ( num == 7  ):  #7  1つ左で2つ上
        pos = w * 2 + 1
    elif ( num == 8  ):  #8  2つ左で2つ上
        pos = w * 2 + 2
    elif ( num == 9  ):  #9  4つ上
        pos = w * 4
    elif ( num == 10 ):  #10 1つ左で4つ上
        pos = w * 4 + 1
    elif ( num == 11 ):  #11 2つ左で4つ上
        pos = w * 4 + 2
    elif ( num == 12 ):  #12 8つ上
        pos = w * 8
    elif ( num == 13 ):  #13 1つ左で8つ上
        pos = w * 8 + 1
    elif ( num == 14 ):  #14 2つ左で8つ上
        pos = w * 8 + 2
    elif ( num == 15 ):  #15 16つ上
        pos = w * 16
    
    return pos



# 登録ハンドラ
def register_load_handlers():
    gimp.register_load_handler('python_fu_MAG_load', 'mag', '')
    pdb['gimp-register-file-handler-mime']('python_fu_MAG_load', 'image/xmag')
#    pdb['gimp-register-thumbnail-loader']('python_fu_MAG_load', '')


register(
    "python_fu_MAG_load", #コマンド名
    "MAG形式画像を読み込みます", #プロシージャブラウザに表示されるプラグインに関する情報
    "MAG形式画像を読み込みます", #プラグインのヘルプ
    "Akira M", #プラグインの作成者
    "Akira M", #プラグインの著作権保有者
    "2017", #年
    "MAG", #メニューの中でプラグインに使用されるラベル
    None, #プラグインで処理する対象となる画像のタイプ
    [   #input args. Format (type, name, description, default [, extra])
        (PF_STRING, 'filename', 'The name of the file to load', None),
        (PF_STRING, 'raw-filename', 'The name entered', None),
    ], #プラグインのメソッドのパラメーター
    [(PF_IMAGE, 'image', 'Output image')], #プラグインのメソッドの結果 Format (type, name, description) 
    magload,
    on_query = register_load_handlers,
    menu = "<Load>",
)


main()

PIX loader

ダウンロード

X68000シリーズのSX-WINDOWで使われていた16色画像フォーマットPIXをGIMPで開くためのプラグイン(Python-fu)です。

メモ

拡張子が"pix"の画像フォーマットはほかにもあり、そのローダーがGIMPにすでに入ってる場合はそちらが優先されてしまい、画像が開けません。そんな時は画像ファイルの拡張子を "xpix" に変えてから開いてください。

ソース

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from gimpfu import *
import struct

def pixload(filename, raw_filename):
    #:param str filename: ファイルパス
    #:param str raw_filename: 選択ファイル名
    #:rtype: gimp.Image
    #:return: 読み込んだ画像
    fp = open(filename, 'rb')
    header = fp.read(48)
    if not header[0:4] == "TX16":
        gimp.message("X68 PIXファイルではありません")
        fp.close()
        return 0
    data_length = ord(header[4])*256*256*256 + ord(header[5])*256*256 + ord(header[6])*256+ ord(header[7])
    x0 =  ord(header[8])*256 + ord(header[9])
    y0 =  ord(header[10])*256 + ord(header[11])
    x1 =  ord(header[12])*256 + ord(header[13])
    y1 =  ord(header[14])*256 + ord(header[15])
    palx = [0]*16
    for i in range(16):
        palx[i] = ord(header[16+i*2])*256 + ord(header[17+i*2])
    #ヘッダ終わり

    #パレット計算用テーブル 5bit+1bit を 8bit に
    octa = [0]*64
    for i in range(64):
        octa[i] = int(round( i * 255 * 1.0 / 63))

    #GIMP用のパレットを計算するよ 16ビットカラーを24ビットに
    palg = [0]*16*3
    for i in range(16):
        g = ( (palx[i] & 0b1111100000000000)>>10 ) + (palx[i] & 0b0000000000000001)
        r = ( (palx[i] & 0b0000011111000000)>>5 ) + (palx[i] & 0b0000000000000001)
        b = palx[i] & 0b0000000000111111
        palg[i*3] = octa[r]
        palg[i*3+1] = octa[g]
        palg[i*3+2] = octa[b]
        
    #GIMPに画像を作成
    width = x1-x0
    height = y1-y0
    image = gimp.Image(width, height, INDEXED)
    image.filename = filename

    #パレット(カラーマップ)を設定
    pdb.gimp_image_set_colormap(image, 16*3, palg)

    #レイヤー作成
    layer = pdb.gimp_layer_new(image, width, height, INDEXEDA_IMAGE, 'PIX', 100, NORMAL_MODE )
    
    #画像展開
    plain = [0]*height*width
    w16 = width//16
    wamari = width % 16
    mask =[0b10000000,
           0b01000000,
           0b00100000,
           0b00010000,
           0b00001000,
           0b00000100,
           0b00000010,
           0b00000001]

    j = 0
    for pl in range(4):
        for i in range(height):
            for j in range(w16):
                buf1 = ord(fp.read(1))
                buf2 = ord(fp.read(1))
                for p in range(8):
                    plain[(width*i)+(j*16)+p] += (buf1 & mask[p])>>(7-p)<<pl
                    plain[(width*i)+(j*16)+8+p] += (buf2 & mask[p])>>(7-p)<<pl
                    p +=1
                j += 1

            if ( wamari > 0 ):#あまり処理 やってることは同じ
                buf1 = ord(fp.read(1))
                buf2 = ord(fp.read(1))
                if ( wamari > 7 ):
                    ama = 8
                else:
                    ama = wamari
                for p in range(ama):
                    plain[(width*i)+(j*16)+p] += (buf1 & mask[p])>>(7-p)<<pl
                    p +=1
                ama = wamari - ama
                for p in range(ama):
                    plain[(width*i)+(j*16)+8+p] += (buf2 & mask[p])>>(7-p)<<pl
                    p +=1
            i += 1
        pl += 1
        gimp.progress_update(float(pl)/8.0) # プログレスバーの更新

    for i in range(height):
        for j in range(width):
            pixel = plain[(width*i)+j]
            layer.set_pixel( j, i, (pixel,255) )

	gimp.progress_update(float(i+height)/float(height*2)) # プログレスバーの更新
    
    image.add_layer(layer, 0)

    return image

# 登録ハンドラ
def register_load_handlers():
    gimp.register_load_handler('python_fu_PIX_load', 'pix,xpix', '')
    pdb['gimp-register-file-handler-mime']('python_fu_PIX_load', 'image/x68pix')
#    pdb['gimp-register-thumbnail-loader']('python_fu_PIX_load', '')


register(
    "python_fu_PIX_load", #コマンド名
    "Load X68 PIX image", #プロシージャブラウザに表示されるプラグインに関する情報
    "X68用PIX形式画像を読み込みます", #プラグインのヘルプ
    "Akira M", #プラグインの作成者
    "Akira M", #プラグインの著作権保有者
    "2017", #年
    "X68 PIX", #メニューの中でプラグインに使用されるラベル
    None, #プラグインで処理する対象となる画像のタイプ
    [   #input args. Format (type, name, description, default [, extra])
        (PF_STRING, 'filename', 'The name of the file to load', None),
        (PF_STRING, 'raw-filename', 'The name entered', None),
    ], #プラグインのメソッドのパラメーター
    [(PF_IMAGE, 'image', 'Output image')], #プラグインのメソッドの結果 Format (type, name, description) 
    pixload,
    on_query = register_load_handlers,
    menu = "<Load>/Load x68PIX..",
)

main()

おまけ: PIX形式ファイルフォーマット

Easypaint SX-68K ユーザーマニュアル より
フィールド名長さ(byte)内容
ファイル識別子4'TX16'
データ長4これより後に続くバイト数
イメージサイズ8イメージを取り囲むレクタングル
パレットデータ3216色分のパレットデータ
ビットイメージ不定G_TXT形式のビットイメージ

補足(間違いがあるかも):

PNT loader

ダウンロード

X68000シリーズのSX-WINDOW用ペイントツール「Easypaint SX-68K」の16色画像フォーマットPNTをGIMPで開くためのプラグイン(Python-fu)です。

ソース

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from gimpfu import *
import struct

def pntload(filename, raw_filename):
    #:param str filename: ファイルパス
    #:param str raw_filename: 選択ファイル名
    #:rtype: gimp.Image
    #:return: 読み込んだ画像
    fp = open(filename, 'rb')
    header = fp.read(4)
    if not header[0:4] == "SXTF":
        gimp.message("PNTファイルではありません")
        fp.close()
        return 0

    #ヘッダ・ブロックを読む
    header_length = struct.unpack('>I', fp.read(4))[0]
    HeaderBlocks = {"dumyyyyy":(0,0)}
    while (header_length > 0):
        dbname = fp.read(4)
        offset = struct.unpack('>I', fp.read(4))[0]
        dataLength = struct.unpack('>I', fp.read(4))[0]
        HeaderBlocks[dbname] = (offset, dataLength)
        header_length -= 12

    #画像サイズ
    size = HeaderBlocks['SIZE'][0]
    width = size>>16
    height = size & 0xffff

    #パレット
    palx = [0]*16
    offset = HeaderBlocks['PALT'][0]
    #dataLength = HeaderBlocks['PALT'][1] #32のはず
    fp.seek(offset)
    for i in range(16):
        palx[i] = struct.unpack('>H', fp.read(2))[0]
        i +=1
    
    #パレット計算用テーブル 5bit+1bit を 8bit に
    octa = [0]*64
    for i in range(64):
        octa[i] = int(round( i * 255 * 1.0 / 63))

    #GIMP用のパレットを計算するよ 16ビットカラーを24ビットに
    palg = [0]*16*3
    for i in range(16):
        g = ( (palx[i] & 0b1111100000000000)>>10 ) + (palx[i] & 0b0000000000000001)
        r = ( (palx[i] & 0b0000011111000000)>>5 ) + (palx[i] & 0b0000000000000001)
        b = palx[i] & 0b0000000000111111
        palg[i*3] = octa[r]
        palg[i*3+1] = octa[g]
        palg[i*3+2] = octa[b]

    #GIMPに画像を作成
    image = gimp.Image(width, height, INDEXED)
    image.filename = filename

    #パレット(カラーマップ)を設定
    pdb.gimp_image_set_colormap(image, 16*3, palg)

    #レイヤー作成
    layer = pdb.gimp_layer_new(image, width, height, INDEXEDA_IMAGE, filename, 100, NORMAL_MODE )

    #画像展開
    if ( width%2 ):
        w2 = width+1
    else:
        w2 = width
    plain = [0]*w2*height

    offset = HeaderBlocks['GR2Z'][0]
    dataLength = HeaderBlocks['GR2Z'][1]
    fp.seek(offset)
    buf = fp.read(dataLength)
    dp = 0
    for y in range( height ):
        x = 0
        while ( x < w2 ):
            shiji = ord(buf[dp])
            dp += 1
            if ( shiji < 0x80 ):         #shiji+1バイト分そのまま出力
                for i in range(shiji+1):
                    ps = ord( buf[dp] )
                    dp += 1
                    p1 = ps>>4
                    p2 = ps & 0b00001111
                    plain[y*w2+x]   = p1
                    plain[y*w2+x+1] = p2
                    i +=1
                    x +=2
            else:                        #次の1バイトを繰り返し
                ps = ord( buf[dp])
                dp += 1
                p1 = ps>>4
                p2 = ps & 0b00001111
                for i in range(257 - shiji):
                    plain[y*w2+x]   = p1
                    plain[y*w2+x+1] = p2
                    i +=1
                    x += 2
        y +=1
        gimp.progress_update(float(y)/float(height*2)) # プログレスバーの更新

    for y in range(height):
        for x in range(width):
            pixel = plain[y*w2+x]
            layer.set_pixel( x, y, (pixel,255) )

        #pdb.gimp_drawable_update( layer, 0, 0, width, height)
	gimp.progress_update(float(y+height)/float(height*2)) # プログレスバーの更新
    
    image.add_layer(layer, 0)

    return image

# 登録ハンドラ
def register_load_handlers():
    gimp.register_load_handler('python_fu_PNT_load', 'pnt', '')
    pdb['gimp-register-file-handler-mime']('python_fu_PNT_load', 'image/pnt')
#    pdb['gimp-register-thumbnail-loader']('python_fu_PNT_load', '')


register(
    "python_fu_PNT_load", #コマンド名
    "X68用PNT形式画像を読み込みます", #プロシージャブラウザに表示されるプラグインに関する情報
    "X68用PNT形式画像を読み込みます", #プラグインのヘルプ
    "Akira M", #プラグインの作成者
    "Akira M", #プラグインの著作権保有者
    "2017", #年
    "X68 PNT", #メニューの中でプラグインに使用されるラベル
    None, #プラグインで処理する対象となる画像のタイプ
    [   #input args. Format (type, name, description, default [, extra])
        (PF_STRING, 'filename', 'The name of the file to load', None),
        (PF_STRING, 'raw-filename', 'The name entered', None),
    ], #プラグインのメソッドのパラメーター
    [(PF_IMAGE, 'image', 'Output image')], #プラグインのメソッドの結果 Format (type, name, description) 
    pntload,
    on_query = register_load_handlers,
    menu = "<Load>",
)

main()

おまけ: PNT形式ファイルフォーマット

PNT形式は、Easypaintのイメージデータを保存するための標準ファイル・フォーマットです。PIX形式のファイル・フォーマットを基本としてはいますが、アプリケーション間での高度なデータ交換を可能とするために、パターンやツールのデータや環境設定情報なども保存できるようになっています。また、ファイル・サイズを縮小し、かつセーブ/ロード時間を短縮するために、ビットイメージの圧縮を行なっています。

ファイルは、ヘッダ部分およびデータ部分で構成されます。

ファイル構造

フィールド名長さ(byte)内容
ファイル識別子4'SXTF'
データ長4これ以降、ヘッダ終端までのバイト数
データ・ブロック識別子4データ・ブロックのデータ形式を表す識別子
オフセット4ファイル先頭からデータ・ブロックまでのオフセット(バイト数)
データ長4データ・ブロックの長さ(バイト数)
(以後、データ・ブロック識別子、オフセット、データ長が必要な個数分繰り返される)
ヘッダ終端符号4ヘッダの終り(0)
以降、各データ・ブロックが続く (順不同)

データ・ブロック識別子とその内容

データ・ブロック識別子フィールド名長さ(byte)内容
'KIND'データ識別子4'PaDT'
'SIZE'絵のサイズ4絵の縦横のドット数
'PALT'パレットデータ3216色分パレットのデータ
'PaPP'パターンデータ32×32縦横16ドットのビットイメージ
'PaBR'ブラシ形状データ84×16ホットスポットおよび縦横20ドットのビットイメージ
'PaSP'スプレー形状データ84×16ホットスポットおよび縦横20ドットのビットイメージ
'ENV.'環境不定環境設定ファイルと同じ形式の文字列
'GR2Z'ビットイメージ不定G_GR2形式のビットイメージ (横1ライン単位で圧縮されている)

Easypaint SX-68K ユーザーマニュアルより

補足(間違いがあるかも):

GLM loader

ダウンロード

X68000シリーズのSX-WINDOWで使われていた6万色画像フォーマットGLMをGIMPで開くためのプラグイン(Python-fu)です。

ソース

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from gimpfu import *
from struct import *

def glmload(filename, raw_filename):
    #:param str filename: ファイルパス
    #:param str raw_filename: 選択ファイル名
    #:rtype: gimp.Image
    #:return: 読み込んだ画像
    fp = open(filename, 'rb')

    header = fp.read(8)
    if not header[0:4] == "GR65":
        gimp.message("GLMファイルではありません")
        fp.close()
        return

    x0 = unpack('>H', fp.read(2))[0]
    y0 = unpack('>H', fp.read(2))[0]
    x1 = unpack('>H', fp.read(2))[0]
    y1 = unpack('>H', fp.read(2))[0]

    width = x1-x0
    height = y1-y0
    
    #パレット計算用テーブル 5bit+1bit を 8bit に
    octa = [0]*64
    for i in range(64):
        octa[i] = int(round( i * 255 * 1.0 / 63))
        
    #GIMPに画像を作成
    image = gimp.Image(width, height, RGB)
    image.filename = filename

    #レイヤー作成
    layer = pdb.gimp_layer_new(image, width, height, RGB, 'GLX', 100, NORMAL_MODE )

    image.add_layer(layer, 0)

    #画像展開
    for y in range(height):
        for x in range(width):
            p =  unpack('>H', fp.read(2))[0]
            g = ( (p & 0b1111100000000000)>>10 ) + (p & 0b0000000000000001)
            r = ( (p & 0b0000011111000000)>>5 ) + (p & 0b0000000000000001)
            b = p & 0b0000000000111111
            color = [octa[r],octa[g],octa[b]]
            layer.set_pixel( x,y, color )
            x +=1
        y +=1
	gimp.progress_update(float(y)/float(height)) # プログレスバーの更新

        
    return image

# 登録ハンドラ
def register_load_handlers():
    gimp.register_load_handler('python_fu_GLM_load', 'glm', '')
    pdb['gimp-register-file-handler-mime']('python_fu_GLM_load', 'image/x68glm')
#    pdb['gimp-register-thumbnail-loader']('python_fu_GLM_load', '')


register(
    "python_fu_GLM_load", #コマンド名
    "Load X68 GLM image", #プロシージャブラウザに表示されるプラグインに関する情報
    "X68用GLM形式画像を読み込みます", #プラグインのヘルプ
    "Akira M", #プラグインの作成者
    "Akira M", #プラグインの著作権保有者
    "2017", #年
    "X68 GLM", #メニューの中でプラグインに使用されるラベル
    None, #プラグインで処理する対象となる画像のタイプ
    [   #input args. Format (type, name, description, default [, extra])
        (PF_STRING, 'filename', 'The name of the file to load', None),
        (PF_STRING, 'raw-filename', 'The name entered', None),
    ], #プラグインのメソッドのパラメーター
    [(PF_IMAGE, 'image', 'Output image')], #プラグインのメソッドの結果 Format (type, name, description) 
    glmload,
    on_query = register_load_handlers,
    menu = "<Load>/Load x68GLM..",
)

main()

おまけ: GLM形式ファイルフォーマット

フィールド名長さ(byte)内容
ファイル識別子4'GR65'
データ長4これより後に続くバイト数
イメージサイズ8イメージを取り囲むレクタングル
ビットイメージ不定1ピクセル2バイトのビットイメージ

補足:

GLX loader

ダウンロード

X68000シリーズ用グラフィックエディタMatierの画像フォーマットGLXをGIMPで開くためのプラグイン(Python-fu)です。

オプション

輝度ビットをどう扱うか指定できます。

色:輝度ビットを考慮する (初期値:Yes)
Matierでは輝度ビットをマスクとして扱い、色の表現には利用していません。そのため輝度ビットを考慮に入れずに24ビットカラーへの変換をする場合はこのオプションを「No」にしてください。
変換例
元データ「Yes」での読み込み「No」での読み込み
0xFFFE (輝度ビットのない白色)0xFAFAFA0xFFFFFF
0xFFFF (輝度ビット付きの白色)0xFFFFFF0xFFFFFF
輝度ビットを選択範囲に (初期値:No)
輝度ビットのついたピクセルを選択状態にします。

ソース

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from gimpfu import *
from struct import *

def glxload(filename, raw_filename, dummy, ibitcolor, ibitmask):
    #:param str filename: ファイルパス
    #:param str raw_filename: 選択ファイル名
    #:rtype: gimp.Image
    #:return: 読み込んだ画像

    fp = open(filename, 'rb')

    width = unpack('<H', fp.read(2))[0]
    height = unpack('<H', fp.read(2))[0]

    if (ibitcolor):
        #パレット計算用テーブル 5bit+1bit を 8bit に
        octa = [0]*64
        for i in range(64):
            octa[i] = int(round( i * 255 * 1.0 / 63))
    else:
        #パレット計算用テーブル 5bit を 8bit に
        octa = [0]*32
        for i in range(32):
            octa[i] = int(round( i * 255 * 1.0 / 31))
    
    #GIMPに画像を作成
    image = gimp.Image(width, height, RGB)
    image.filename = filename

    #レイヤー作成
    layer = pdb.gimp_layer_new(image, width, height, RGB, 'GLX', 100, NORMAL_MODE )

    image.add_layer(layer, 0)

    #選択範囲用にチャンネルを追加
    if(ibitmask):
        channel = pdb.gimp_channel_new(image, width, height, 'i-bit', 50, (0xf0,0,0))
        pdb.gimp_image_add_channel(image, channel, 0)
    
    #画像展開
    if(ibitcolor):
        for y in range(height):
            for x in range(width):
                p =  unpack('>H', fp.read(2))[0]
                i = p & 0b0000000000000001
                g = ( (p & 0b1111100000000000)>>10 ) + i
                r = ( (p & 0b0000011111000000)>>5 ) + i
                b = p & 0b0000000000111111
                color = [octa[r],octa[g],octa[b]]
                layer.set_pixel( x,y, color )
                if(ibitmask):
                    mask = i*255
                    channel.set_pixel( x,y, (mask,) )
                x +=1
            y +=1
	    gimp.progress_update(float(y)/float(height)) # プログレスバーの更新
    else:
        for y in range(height):
            for x in range(width):
                p =  unpack('>H', fp.read(2))[0]
                g = ( (p & 0b1111100000000000)>>11 )
                r = ( (p & 0b0000011111000000)>>6 )
                b = ( (p & 0b0000000000111111)>>1 )
                color = [octa[r],octa[g],octa[b]]
                layer.set_pixel( x,y, color )
                if(ibitmask):
                    i = p & 0b0000000000000001
                    mask = i*255
                    channel.set_pixel( x,y, (mask,) )
                x +=1
            y +=1
	    gimp.progress_update(float(y)/float(height)) # プログレスバーの更新

    if(ibitmask):
        pdb.gimp_selection_load(channel) #チャンネルを選択範囲に
        pdb.gimp_item_set_visible(channel, FALSE) #チャンネルを非表示に

    return image

# 登録ハンドラ
def register_load_handlers():
    gimp.register_load_handler('python_fu_GLX_load', 'glx', '')
    pdb['gimp-register-file-handler-mime']('python_fu_GLX_load', 'image/x68glx')
#    pdb['gimp-register-thumbnail-loader']('python_fu_GLX_load', '')


register(
    "python_fu_GLX_load", #コマンド名
    "X68用GLX形式画像を読み込みます", #プロシージャブラウザに表示されるプラグインに関する情報
    "X68用GLX形式画像を読み込みます", #プラグインのヘルプ
    "Akira M", #プラグインの作成者
    "Akira M", #プラグインの著作権保有者
    "2017", #年
    "X68 GLX", #メニューの中でプラグインに使用されるラベル
    None, #プラグインで処理する対象となる画像のタイプ
    [   #input args. Format (type, name, description, default [, extra])
        (PF_STRING, 'filename', 'The name of the file to load', None),
        (PF_STRING, 'raw-filename', 'The name entered', None),
        (PF_STRING, 'dummy', 'ここは気にしなくてよいはず', None),
        (PF_TOGGLE, "ibitcolor" , "色:輝度ビットを考慮する", TRUE),
        (PF_TOGGLE, "ibitmask" , "輝度ビットを選択範囲に", FALSE),
    ], #プラグインのメソッドのパラメーター
    [(PF_IMAGE, 'image', 'Output image')], #プラグインのメソッドの結果 Format (type, name, description) 
    glxload,
    on_query = register_load_handlers,
    menu = "<Load>/Load x68GLX..",
)


main()

おまけ: GLX形式ファイルフォーマット

イメージサイズX2横サイズ
イメージサイズY2縦サイズ
ビットイメージ不定1ピクセル2バイトのビットイメージ

補足:

RGB loader

ダウンロード

ベタ画像フォーマットRGB形式をGIMPで開くためのプラグイン(Python-fu)です。

メモ

RGBファイルと同じフォルダにIPRファイル(画像サイズなどの情報を記録したファイル)が必要です。RGBファイルとIPRファイルのどちらからでも画像を開けます。

既知の問題

拡張子は大文字決め打ち("RGB"と"IPR")でファイルにアクセスしますので、拡張子が小文字のファイルの場合、Linuxなどの環境では開けません。その時はファイルの拡張子を大文字に変更してください。

ソース

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from gimpfu import *
from struct import *
import os

def rgbload(filename, raw_filename):
    #:param str filename: ファイルパス
    #:param str raw_filename: 選択ファイル名
    #:rtype: gimp.Image
    #:return: 読み込んだ画像

    path, ext = os.path.splitext(filename)

    dp = open(path+".RGB", 'rb')
    if dp == IOError:
        gimp.message("RGBファイルが開けません")
        return 0
        
    hp = open(path+".IPR", 'rb')
    if hp == IOError:
        gimp.message("IRPファイルが開けません")
        return 0

    head_line = hp.readline()
    head = head_line.split()
    
    width = int(head[0])
    height = int(head[1])


    #GIMPに画像を作成
    image = gimp.Image(width, height, RGB)
    image.filename = filename

    #レイヤー作成
    layer = pdb.gimp_layer_new(image, width, height, RGB, path, 100, NORMAL_MODE )

    image.add_layer(layer, 0)

    #画像展開
    buf = layer.get_pixel_rgn( 0, 0, width, height, True, True )
    
    for y in range(height):
        for x in range(width):
            buf[x,y] = dp.read(3)
	gimp.progress_update(float(y)/float(height)) # プログレスバーの更新

    layer.flush()
    layer.merge_shadow(True)
    layer.update(0, 0, width, height)

    return image

# 登録ハンドラ
def register_load_handlers():
    gimp.register_load_handler('python_fu_RGB_load', 'rgb,ipr', '')
    pdb['gimp-register-file-handler-mime']('python_fu_RGB_load', 'image/xrgb')
#    pdb['gimp-register-thumbnail-loader']('python_fu_RGB_load', '')


register(
    "python_fu_RGB_load", #コマンド名
    "RGB形式ベタ画像を読み込みます", #プロシージャブラウザに表示されるプラグインに関する情報
    "RGB形式ベタ画像を読み込みます", #プラグインのヘルプ
    "Akira M", #プラグインの作成者
    "Akira M", #プラグインの著作権保有者
    "2017", #年
    "RGBベタ", #メニューの中でプラグインに使用されるラベル
    None, #プラグインで処理する対象となる画像のタイプ
    [   #input args. Format (type, name, description, default [, extra])
        (PF_STRING, 'filename', 'The name of the file to load', None),
        (PF_STRING, 'raw-filename', 'The name entered', None),
    ], #プラグインのメソッドのパラメーター
    [(PF_IMAGE, 'image', 'Output image')], #プラグインのメソッドの結果 Format (type, name, description) 
    rgbload,
    on_query = register_load_handlers,
    menu = "<Load>/Load RGB..",
)


main()

ボーダー作成(縁取り)

ダウンロード

文字などのオブジェクトに対して簡単に縁取りをつけられるGIMP用スクリプト(Script-fu)です。

使用方法など

Photoshopにある レイヤースタイル>境界線 のモドキです。 ボーダー使用例このように文字の縁取りなどに使えると思います。

縁取りしたいモノがあるレイヤーを選択した状態でこのスクリプトを起動してください。 (フィルター > ボーダー作成... ) そのレイヤーの下に縁取りレイヤーができます。

このスクリプトでどういうことをしているかというと。

  1. 対象レイヤーの不透明部分を選択領域に。
  2. 新しくレイヤーを作り、対象レイヤーの下へ移動。
  3. 指定された色で塗りつぶし。

ダイアログ レイヤーが通常モード不透明度100%以外だと問題ありそうなので、オプションを用意しています。

レイヤーをコピー
通常は縁取りレイヤーは塗りつぶしだけですが、このオプションをオンにすると対象レイヤーの内容を縁取りレイヤーにコピーして処理します。
中をくりぬく
縁取りレイヤーの塗りつぶし部分から対象レイヤーの内容部分をくりぬいて縁取り部分のみにします。

状況によって使い分けてください。

ソース

(define (script-fu-make-border img layer bordersize bordercolor flag-copy flag-cut)
  
  ;; 前処理
  (let* ((old-fg (car (gimp-palette-get-foreground)))
         (old-bg (car (gimp-palette-get-background)))
         (layer-position (gimp-image-get-layer-position img layer))
         (width (car (gimp-image-width img)))
         (height (car (gimp-image-height img)))
         (border-layer (car (gimp-layer-new img width height RGBA-IMAGE "Border" 100 NORMAL-MODE)))
         (copy-layer 0)
         )
    (gimp-undo-push-group-start img)

    ;;縁取りレイヤー作成
    (gimp-image-add-layer img border-layer -1)
    (gimp-image-lower-layer img border-layer)
    (gimp-drawable-fill border-layer TRANS-IMAGE-FILL)        ; 透明でレイヤーを初期化

    ;;縁取り領域作成
    (gimp-selection-layer-alpha layer)
    (gimp-selection-grow img bordersize)
    (gimp-palette-set-foreground bordercolor)
    (gimp-edit-fill border-layer FOREGROUND-FILL)

    (if (= flag-copy FALSE) ;;レイヤーをコピーするか
        (
          ;; コピーしないので何もしない
         )
        (begin
         (set! copy-layer (car (gimp-layer-copy layer 1))) ;;レイヤーを複製して
         (gimp-image-add-layer img copy-layer -1)
         (set! border-layer (car (gimp-image-merge-down img copy-layer 1)))    ;;下のレイヤー(エッジレイヤー)と統合
         )
        ) ; end of if
    (if (= flag-cut FALSE) ;;くりぬくか
        (
         ;; なにもしない
         )
        (begin
         (gimp-selection-layer-alpha layer) ;;もとのレイヤーから選択領域を作り
;         (gimp-edit-fill border-layer TRANS-IMAGE-FILL) ;;透明色で塗りつぶし
;         (gimp-edit-cut border-layer) ;; カット
         (gimp-edit-clear  border-layer) ;;透明色で塗りつぶし
         )
        ) ; end of if

    ;; 後処理
    (gimp-selection-none img)
    (gimp-palette-set-foreground old-fg)
    (gimp-palette-set-background old-bg)
    (gimp-undo-push-group-end img)
    (gimp-displays-flush)
    )
  )

(script-fu-register
 "script-fu-make-border"
 "<Image>/Filters/ボーダー作成..."
 "ボーダーを作ります。"
 "Akira M"
 "Akira M"
 "May 17, 2009"
 "RGB*"
 SF-IMAGE     "Image"     0
 SF-DRAWABLE  "Drawable"  0
 SF-ADJUSTMENT "ボーダーサイズ (ピクセル)" '(3 1 250 1 1 0 0)
 SF-COLOR      "ボーダー色" '(0 0 0)
 SF-TOGGLE     "レイヤーをコピー" FALSE
 SF-TOGGLE     "中をくりぬく" FALSE
)

Gimpへプラグイン/スクリプトをインストールする方法

Gimpへプラグイン/スクリプトをインストールするには、プラグインやスクリプトのファイルを所定のフォルダに入れるだけです。とはいえ、その「所定のフォルダ」がどこなのかよくわからなかったりします。では確認しましょう。

Gimpを起動し、編集メニューの「設定」から設定ダイアログを開きます(Mac用は「Gimp」メニューにあります)。左側の項目の中の「フォルダー」からプラグイン、またはスクリプトを選ぶとフォルダの場所が表示されます。
Gimp環境設定ダイアログ 2つあると思いますが、通常は上にあるのが個人用、下にあるのがそのマシンにログインできるすべてのユーザー用(正確には違いますが)です。下のフォルダにファイルを入れるには管理者権限が必要だったりするので、普通は上の個人用のフォルダに入れます。

さて、この個人用のフォルダ、「.gimp-2なんとか」というドットで始まる名前のフォルダの中にある場合がほとんどです。このようなドットで始まる名前のファイルやフォルダは設定用で、Unix系(Macも含む)ではデスクトップなどからフォルダを開いていっても表示されないのがお約束です。でも大丈夫。フォルダの場所はわかっているのでちゃんと開けます。

まずフォルダの場所をコピーしておきましょう。設定ダイアログでは選んだフォルダの場所が上の欄に表示されるのでこれをコピーします。そして Macの場合は Finder の「移動」メニューから「フォルダに移動...」を選ぶと入力欄が出てくるのでそこに貼り付け。Windowsの場合は、フォルダウィンドウの上の方に場所の欄が最初からあるのでそこに貼り付け。 Linuxの場合はMac式かWindows式のどちらかが使えるはずです(Ubuntuの場合はどちらもOK)。 これで所定のフォルダが開きますので、プラグインやスクリプトのファイルを入れればインストール完了です。

おまけ。「所定のフォルダ」は、最初から設定されているフォルダを変更したり追加することができますので、自分の管理しやすいように変えてしまうのもアリです。