Ok, ecco qualcosa per iniziare. Dato che non conosco in modo specifico quale formato sia il tuo file BMP, ho gestito solo un caso specifico di BMP con il canale alfa completo che mi capita di avere. Il tipo di BMP che sto gestendo qui può essere ottenuto convertendo, per esempio, PNG con alpha in BMP usando ImageMagick. Questo creerà ciò che viene chiamato "BITMAPV5". Data la tua descrizione, non hai un BitmapV5 (perché PIL non riuscirebbe nemmeno ad aprirlo), quindi avremo bisogno di un'iterazione con discussioni per risolvere il tuo caso specifico.
Quindi, è necessario un nuovo decodificatore di file o un patch BmpImagePlugin.py
. Come fare il primo è descritto nel manuale di PIL. Per i successivi dovrai ovviamente inviare una patch e sperare di averla nella prossima versione PIL. Il mio obiettivo è quello di creare un nuovo decoder:
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))]
Per utilizzare correttamente questo, il modo canonico è presumibilmente da eseguire:
from PIL import Image
Image.register_open(BmpAlphaImageFile.format, BmpAlphaImageFile)
# XXX register_save
Image.register_extension(BmpAlphaImageFile.format, ".bmp")
Il problema è che c'è già un plugin per la gestione di" .bmp ", e non mi sono preoccupato di scoprire come potrei anteporre questa nuova estensione in modo che venga utilizzata prima che BmpImagePlugin venga utilizzato (non so nemmeno se sia possibile farlo in PIL). Detto questo, Ho utilizzato il codice direttamente, come in:
from BmpAlphaImagePlugin import BmpAlphaImageFile
x = BmpAlphaImageFile('gearscolor.bmp')
print x.mode
x.save('abc1.png')
Dove gearscolor.bmp è una bitmap campione con canale full alfa come descritto in precedenza. Il png risultante viene salvato con dati alfa. Se si controlla il codice BmpImagePlugin.py
, si noterà che ho riutilizzato gran parte del suo codice.
Penso che un file bitmap a 32 bit sia un formato non standard che PIL non supporta. Cercando di scrivere un'immagine RGBA in .bmp si produce l'errore 'impossibile scrivere modalità RGBA come BMP'. –