I need to save an image as Windows Bitmap BMP A1R5G5B5 16bpp.
Source files are 32bpp image files (PNG and/or Windows Bitmap).

Preview saves BMP images at 32bpp.

XnConvert saves BMP images at 24bpp.

Imagemagick, Acorn, GraphicConverter do not support saving at 16bpp.

Photoshop can do it, but I don't own it.

Any ideas? GUI or command line is fine for me.

  • 1
    16bpp as in R5G6B5? Or 16bpp as in 48 bpp, meaning a full 16 bits for each of the individual channels? Also, what is your input file format, and what is the desired output format? (I know, 'bmp' suggests a Windows Bitmap, but I'd like to see that confirmed.) – usr2564301 Dec 17 '18 at 21:40
  • 1
    just came back to state its actually A1R5G5B5 Windows bitmap. – Matt Sephton Dec 17 '18 at 21:44
  • 1
    Can you handle a Python script? – usr2564301 Dec 17 '18 at 21:48
  • Yes I certainly can – Matt Sephton Dec 17 '18 at 21:49
  • 1
    (cracks knuckles) Gimme a mo'. – usr2564301 Dec 17 '18 at 22:08

This rather quick – and possibly dirty – Python program will read a 32bpp BMP image, assert it is indeed 32 bpp, and if so convert it to a 16-bit ARGB image and write out to a new file.

import sys, struct

def convertBmp(filename):
    with open(filename, 'rb') as in_file:
        data = in_file.read()

    type1,type2,size,reserved1,reserved2,offset,dib,wide,high,planes,bpp = struct.unpack('<ccIHHIIIIHH',data[:30])
    if type1 != b'B' or type2 != b'M':
        raise ValueError('Not a BMP image')
    if planes != 1 or bpp != 32:
        raise ValueError('Not a 32bpp BMP image')

    header = bytearray(data[:offset])
    data = bytearray(data[offset:])
    # process data
    newdata = bytearray()
    for y in range(high):
        for x in range(wide):
            b,g,r,a = data[4*wide*y+4*x:4*wide*y+4*x+4]
            a = 32768 if a < 127 else 0
            r >>= 3
            g >>= 3
            b >>= 3
            newdata += struct.pack('<H',a+(r<<10)+(g<<5)+b)
        # add row padding
        if wide & 1:
            newdata += b'\x00\x00'
    # update total size
    header[2:6] = struct.pack('<I',len(header)+len(newdata))
    # update bpp
    header[28] = 16
    # update planes
    header[30] = 0
    # update raw image size
    header[34:38] = struct.pack('<I',len(newdata))
    return header+newdata

if len(sys.argv) != 3:
    print ('usage: python convbmp.py input.bmp output.bmp')
    image = convertBmp(sys.argv[1])
    with open(sys.argv[1], 'wb') as out_file:
        out_file.write (image)

It should only touch the BMP data fields that are actually changed for the conversion and leave the rest alone. Testing was a bit troublesome as I don't appear to have any software to view the resulting ARGB; both Photoshop and Apple's Preview (again!) let me down by not showing if this one-bit alpha channel actually worked. Photoshop always seems to import the alpha channel as if everything is set. (If alpha does not work for you, experiment with the value of the setting of that a variable; its logic may need inverting.)

This should cover the basics. Expanding it to be able to accept multiple arguments or loop over an entire folder of data, is left as an implementation detail.

  • I'm getting "Not a BMP image" with this file I saved using Preview: 0x0.st/skxy.bmp and in fact python convbmp.py with no files gives me that error also – Matt Sephton Dec 17 '18 at 23:42
  • 1
    @MattSephton: hm. It worked for me... It's late at nite over here, will run some tests with that image later. – usr2564301 Dec 17 '18 at 23:43
  • FWIW in GIMP, I picked X1R5G5B5 which is the same format with unused alpha? I'll check back tomorrow, it's late here too. Thanks! – Matt Sephton Dec 17 '18 at 23:44
  • This is what I get running the python script: imgur.com/Xc0c5G6 – Matt Sephton Dec 18 '18 at 16:34
  • 1
    @MattSephton: I, sir, am an Idiot. ... I ran it from within an IDE and tested with a hardcoded command line. But when run from a terminal, the first argument is actually the script itself. Sorry for that! – usr2564301 Dec 19 '18 at 11:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.