7

PIL を使用して 32 ビット ビットマップを 32 ビット PNG に変換しようとしました。

from PIL import Image
im = Image.open('example.bmp')
print im.mode
# it prints 'RGB', but expected was 'RGBA'
im.save('output.png', format='PNG')

予想される画像モードは「RGBA」ですが、実際には「RGB」を取得します。

次のコードも試しましたが、うまくいきません。

from PIL import Image
im = Image.open('example.bmp')
im = im.convert('RGBA')
im.save('output.png', format='PNG')
4

3 に答える 3

4

わかりました、ここから始めましょう。あなたの BMP ファイルが具体的にどの形式なのかわからないので、私がたまたま持っていた完全なアルファ チャンネルを持つ BMP の特定のケースのみを扱いました。ここで扱う BMP の種類は、たとえばアルファ付きの PNG を ImageMagick を使用して BMP に変換することで取得できます。これにより、「BITMAPV5」と呼ばれるものが作成されます。あなたの説明を考えると、あなたは BitmapV5 を持っていません (PIL はそれを開くことさえできないため)。そのため、あなたの特定のケースを解決するには、議論を繰り返す必要があります。

そのため、新しいファイル デコーダーまたはパッチを適用しBmpImagePlugin.pyた . 前者を行う方法は、PIL のマニュアルに記載されています。後者については、明らかにパッチを送信する必要があり、それを次の PIL バージョンに入れることを望んでいます。私の焦点は、新しいデコーダーの作成です。

from PIL import ImageFile, BmpImagePlugin

_i16, _i32 = BmpImagePlugin.i16, BmpImagePlugin.i32

class BmpAlphaImageFile(ImageFile.ImageFile):
    format = "BMP+Alpha"
    format_description = "BMP with full alpha channel"

    def _open(self):
        s = self.fp.read(14)
        if s[:2] != 'BM':
            raise SyntaxError("Not a BMP file")
        offset = _i32(s[10:])

        self._read_bitmap(offset)

    def _read_bitmap(self, offset):

        s = self.fp.read(4)
        s += ImageFile._safe_read(self.fp, _i32(s) - 4)

        if len(s) not in (40, 108, 124):
            # Only accept BMP v3, v4, and v5.
            raise IOError("Unsupported BMP header type (%d)" % len(s))

        bpp = _i16(s[14:])
        if bpp != 32:
            # Only accept BMP with alpha.
            raise IOError("Unsupported BMP pixel depth (%d)" % bpp)

        compression = _i32(s[16:])
        if compression == 3:
            # BI_BITFIELDS compression
            mask = (_i32(self.fp.read(4)), _i32(self.fp.read(4)),
                    _i32(self.fp.read(4)), _i32(self.fp.read(4)))
            # XXX Handle mask.
        elif compression != 0:
            # Only accept uncompressed BMP.
            raise IOError("Unsupported BMP compression (%d)" % compression)

        self.mode, rawmode = 'RGBA', 'BGRA'

        self.size = (_i32(s[4:]), _i32(s[8:]))
        direction = -1
        if s[11] == '\xff':
            # upside-down storage
            self.size = self.size[0], 2**32 - self.size[1]
            direction = 0

        self.info["compression"] = compression

        # data descriptor
        self.tile = [("raw", (0, 0) + self.size, offset,
            (rawmode, 0, direction))]

これを適切に使用するには、標準的な方法で次のように実行する必要があります。

from PIL import Image
Image.register_open(BmpAlphaImageFile.format, BmpAlphaImageFile)
# XXX register_save

Image.register_extension(BmpAlphaImageFile.format, ".bmp")

問題は、「.bmp」を処理するためのプラグインが既に存在することです。この新しい拡張子を先頭に追加する方法をわざわざ調べなかったので、BmpImagePlugin が使用される前に使用されます (それが使用されるかどうかもわかりません)。 PILでそのようなことを行うことは可能です)。と言いましたが、実際には次のようにコードを直接使用しました。

from BmpAlphaImagePlugin import BmpAlphaImageFile

x = BmpAlphaImageFile('gearscolor.bmp')
print x.mode
x.save('abc1.png')

前述のように、gearscolor.bmp はフル アルファ チャネルを含むサンプル ビットマップです。結果の png は、アルファ データと共に保存されます。のコードをチェックするBmpImagePlugin.pyと、そのコードのほとんどを再利用したことがわかります。

于 2012-12-08T20:58:22.043 に答える
0

PIL にはバグがあり、透明な BMP ファイルでは正しく動作しません。

私がよく覚えていれば、wxPython はそれらで適切に動作するようです。コードを見つけることができた場合にのみ、約1年前に2つの間の小さなラッパーを書きました。

于 2012-05-07T19:14:56.373 に答える
0

@mmgp によるコードは Alpha で BMP ファイルをロードするのに最適ですが、Python 3 では 2 つの小さな変更が必要です:

if s[:2] != 'BM':

になります:

if s[:2] != b'BM':

self.size は使用する場所を変更する必要があるため、コードの最後は次のようになります。

self._size = (_i32(s[4:]), _i32(s[8:]))
direction = -1
if s[11] == '\xff':
    # upside-down storage
    self._size = self._size[0], 2**32 - self._size[1]
    direction = 0

self.info["compression"] = compression

# data descriptor
self.tile = [("raw", (0, 0) + self._size, offset,
    (rawmode, 0, direction))]

さらに、一部の BMP が正しい形式ではないため、失敗することもあります。次のいずれかを事前に選択できます。

if typename != "alpha":
    img = Image.open(filename)
else:
    img = BmpAlphaImageFile(filename)

または、フォールバックとして try/catch ブロックを使用します。

try:
    img = BmpAlphaImageFile(filename)
except IOError:
    img = Image.open(filename)
于 2020-10-17T14:28:52.053 に答える