Converting to ARGB and writing to a bitmap

Tim Roberts timr at probo.com
Sun Mar 19 03:40:24 CET 2006


heathimself at gmail.com wrote:
>
>I don't know what type of files they are, but the script allows me to
>save to a bitmap just fine. But I do know they need to be in RGBA 4444
>format, so I've followed what most of the tutorials for RGBA
>conversions said to do...shifting the bytes.

It wasn't until I looked at your sample image that I realized you meant the
INCOMING image is ARGB 4444, and you're trying to convert it to ARGB 8888.

>The major problem is that everything is in green, it's shifted up by x
>pixels, and it's..um..flipped from left to right. I've been working on
>this for a few weeks now and any insight to the problem is greatly
>appreciated.

There are a couple of issues here.  Depth 32 is not one of the standard
formats for DIBs.  24 is (B G R B G R), but not 32.  To create 32-bit DIBs,
you are supposed to set biCompression to BI_BITFIELDS, and then supply
bitmasks in the three dwords that follow the BITMAPINFOHEADER telling
exactly where the R, G, and B values can be found.  However, NT happens to
handle the format as you have it, so we'll leave it alone.

DIBs have no concept of an alpha channel.  What are you going to use to
read this?

># since bitmaps are upside down, gotta flip it over
>data = f2.read()
>
>i = size-21
>while i >= 0:
>    nm = 0x100
>
>    f1.seek(i)
>    temp1 = struct.unpack('B', f1.read(1))[0]

This reads one 8 bit value, and then tries to pull 32 bits of information
from it.  You need to read a 16-bit value and crack it 4 bits at a time,
not 8 bits.

>    peek = temp1
>
>    a = nm*(peek >> 24) & 0xff
>    r = nm*(peek >> 16) & 0xff
>    g = nm*(peek >> 8 ) & 0xff
>    b = nm*(peek & 0xff)

What is the "multiply by 0x100" supposed to be doing?  As near as I can
tell, since "*" binds more tightly than "&", this will result in a, r, and
always being 0.

>    sh = (a<<24)|(r<<16)|(g<<8)|b
>
>    f2.write(struct.pack('H', sh))

"sh" is a 32-bit value.  You almost certainly want 'L' here, not 'H'.

Here is one that works, although it creates the DIB upside down, as you
note.  I'll leave that as an exercise for the reader.

import os
import struct
import array

IN = 'testimg'
OUT = 'xxx.bmp'

fin = file(IN,'rb')

width = 100
insize = os.stat(IN)[6]
height = insize / width / 2

fout = file(OUT,'wb')

# Do the BITMAPFILEHEADER.

fout.write('BM')
bmfh = struct.pack( 'LLL', insize*2 + 14 + 40, 0, 14+40 )
fout.write(bmfh)

# Do the BITMAPINFOHEADER.

bmih = struct.pack('LLLHHLLLLLL',
	40,
	width,
	height,
	1,
	32,
	0, 0, 0, 0, 0, 0 )
fout.write(bmih)

# Expand the pixels, scan by scan.

for i in range(height):
    words = array.array('H')
    words.fromfile( fin, width )
    rgba = array.array('B')
    for word in words:
	a = ((word >> 12) & 0xf) * 0x11
	r = ((word >> 8) & 0xf) * 0x11
	g = ((word >> 4) & 0xf) * 0x11
	b = ((word >> 0) & 0xf) * 0x11
	rgba.extend( [b,g,r,a] )
    rgba.tofile(fout)
    print '*',
-- 
- Tim Roberts, timr at probo.com
  Providenza & Boekelheide, Inc.



More information about the Python-list mailing list