Deathloop .bimage files

Get your graphics formats figures out here! Got details for others? Post here!
Post Reply
mariachiscalpi
ultra-n00b
Posts: 2
Joined: Sun Sep 19, 2021 8:53 pm
Has thanked: 3 times

Deathloop .bimage files

Post by mariachiscalpi » Thu Sep 23, 2021 5:28 pm

Hey!

I spent some time snooping around the forum looking for means of converting the .bimage files I extracted from Deathloop using QuickBMS, and while I have managed to find scripts meant to aid in the conversion of the aforementioned file type in RAGE, The Old Blood or The Evil Within 2, none of them seem to work for the .bimage files specific to Deathloop. Needless to say, I'd greatly appreciate any and all help in streamlining the process for converting these texture files to a more palatable extension.

Here's a Google Drive link to a few of them. Do let me know should you need me to upload anything else to figure it out. Cheers!

wully
ultra-n00b
Posts: 2
Joined: Thu Sep 30, 2021 12:23 am

Re: Deathloop .bimage files

Post by wully » Thu Sep 30, 2021 6:10 pm

Looking for help with this also. I've pulled out the 3d models, but I just need the slab textures

I tried running the Dishonored2_tex.exe directly. It wouldn't pick up the bimage files. Renaming them to bimage7 got the converter to read them but it says they are in an unknown format. Are Deathloops files bimage 6 or 7?

Code: Select all

PS F:\Development\Games\Deathloop\generated\model\models\equipment\slabs\texture> .\Dishonored2_tex.exe ./ .\output\
Dishonored 2: Texture Converter v1.03 by Volfin

Converting ./\slab_curves_01_d.bimage7 ( 1 / 3 )
  - Unknown Format 6 - 1
Converting ./\slab_curves_01_n.bimage7 ( 2 / 3 )
  - Unknown Format 4 - 1
Converting ./\slab_curves_01_p.bimage7 ( 3 / 3 )
  - Unknown Format 5 - 1

cidqu
ultra-n00b
Posts: 3
Joined: Wed Sep 29, 2021 4:36 pm

Extracting .bimage files

Post by cidqu » Fri Oct 01, 2021 12:31 pm

Hi, I was translating Deathloop. Thanks to 'ikskoks' I managed to paste data from .decl files. But I got something different, Turkish Language has some different characters than the normal Latin Alphabet (ışöçüğ) and Deathloop Fonts don't support this. I want to change the font but couldn't manage to extract .bimage files. Can anyone help, please? I left an example.
You do not have the required permissions to view the files attached to this post.

CrazyHairGuy
ultra-n00b
Posts: 1
Joined: Wed Nov 11, 2020 7:24 am

Re: Deathloop .bimage files

Post by CrazyHairGuy » Sat Oct 02, 2021 5:07 am

wully wrote:
Thu Sep 30, 2021 6:10 pm
Looking for help with this also. I've pulled out the 3d models, but I just need the slab textures

I tried running the Dishonored2_tex.exe directly. It wouldn't pick up the bimage files. Renaming them to bimage7 got the converter to read them but it says they are in an unknown format. Are Deathloops files bimage 6 or 7?

Code: Select all

PS F:\Development\Games\Deathloop\generated\model\models\equipment\slabs\texture> .\Dishonored2_tex.exe ./ .\output\
Dishonored 2: Texture Converter v1.03 by Volfin

Converting ./\slab_curves_01_d.bimage7 ( 1 / 3 )
  - Unknown Format 6 - 1
Converting ./\slab_curves_01_n.bimage7 ( 2 / 3 )
  - Unknown Format 4 - 1
Converting ./\slab_curves_01_p.bimage7 ( 3 / 3 )
  - Unknown Format 5 - 1
As far as I can gather, the Deathloop .bimages are a new version/revision that have only been used in Deathloop so far, so someone would have to do some poking around in the files themselves and figure out the differences between them and the older versions, and then update the .bimage converter.

kidaXV
ultra-n00b
Posts: 1
Joined: Wed Jun 26, 2019 5:26 am
Been thanked: 2 times

Re: Deathloop .bimage files

Post by kidaXV » Sun Oct 17, 2021 11:24 am

I'm new to this but I managed to create a rough python script that can convert a handful of compression types from .bimage to .dds. It seems to work for UI and model skins now, although there might be some compression types it doesn't handle.

I was able to figure out the addresses of the image size via 010 editor (using the template from here as a guideline), and knew from Dishonored 2 images that they used DXT5. I also used rawtexcmd to test this out and figure out what kind of "magic header" to add to these files to make them readable as DDS.

Code: Select all

import argparse
import binascii
import os
import struct

"""
Scuffed python script to convert Deathloop .bimage files to .dds

Usage: 
`python bimage.py <file.bimage>` - Makes a best attempt at generating file.bimage.dds

`python bimage.py <directory>` - Will attempt to convert images in directory, and act recursively on all subdirectories
"""

parser = argparse.ArgumentParser()
parser.add_argument('file', help='.bimage file or directory to convert. Works recursively for directories.')

ext = '.bimage'
ext_mip0 = '_mip0'

size_int_bytes = 4
size_long_bytes = 8
heighttomipmapstart = 47
dds_header_height_offset = 12

compchar_to_header = {
    # BC1 (DXT1)
    14: 'RERTIHwAAAAHEAAAAAQAAAAEAAAAAAgAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAEAAAARFhUMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
    # BC3 (DXT5)
    16: 'RERTIHwAAAAHEAAAAAEAAAABAAAAAAEAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAEAAAARFhUNQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==',
    # BC4 (ATI1)
    17: 'RERTIHwAAAAHEAAAAAEAAAABAAAAgAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAEAAAAQVRJMQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=',
    # (DX10)
    18: 'RERTIHwAAAAHEAAAAAQAAAAEAAAAABAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAEAAAARFgxMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABUAAAAAwAAAAAAAAABAAAAAAAAAA==',
    # (DX10)
    19: 'RERTIHwAAAAHEAAAAAEAAAABAAAAAAEAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAEAAAARFgxMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABfAAAAAwAAAAAAAAABAAAAAAAAAA==',
    # BC7 (DX10)
    20: 'RERTIHwAAAAHEAAAcAgAAAAPAAAAkH4AAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAEAAAARFgxMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiAAAAAwAAAAAAAAABAAAAAAAAAA=='
}

buffersize = 2048

def bytesToInt(b):
    return struct.unpack('<I', b)[0]

def getDdsHeader(compchar, height, width, area):
    if compchar in compchar_to_header:
        header = bytearray(binascii.a2b_base64(compchar_to_header[compchar]))
        struct.pack_into('<III', header, dds_header_height_offset, height, width, area)
        return header
    else:
        print('unknown compression format! ', compchar)
        return None

def processFile(file):
    outputFileName = file[:-len(ext)] + '.dds'
    with open(file, 'rb') as bimageFile:
        bimageFile.read(size_long_bytes) # id
        compcharBytes = bimageFile.read(size_int_bytes) # determine dxt format
        compchar = struct.unpack('<I', compcharBytes)[0]
        bimageFile.read(size_int_bytes) # unknown
        bimageFile.read(size_int_bytes) # unknown
        bimageFile.read(size_int_bytes) # width
        bimageFile.read(size_int_bytes) # height

        width = bytesToInt(bimageFile.read(size_int_bytes))
        height = bytesToInt(bimageFile.read(size_int_bytes))
        area = width * height

        header = getDdsHeader(compchar, height, width, area)
        if header == None:
            print('{}: unable to generate header'.format(file))
            return False

        with open(outputFileName, 'wb') as outFile:
            outFile.write(header)
            # Determine whether to read from here or a separate mipmap file
            mipFile = file + ext_mip0
            if not os.path.exists(mipFile):
                bimageFile.read(heighttomipmapstart) # skip to beginning of first mipmap
                buffer = bimageFile.read(buffersize)
                while buffer:
                    outFile.write(buffer)
                    buffer = bimageFile.read(buffersize)
            else:
                # Copy from mipmap file
                with open(mipFile, 'rb') as mip:
                    buffer = mip.read(buffersize)
                    while buffer:
                        outFile.write(buffer)
                        buffer = mip.read(buffersize)
    return True

def processDir(dir):
    numProcessed = 0
    numSuccess = 0
    for root, _, files in os.walk(dir):
        for file in files:
            if file.endswith(ext):
                numProcessed += 1
                if processFile(os.path.join(root, file)):
                    numSuccess += 1
    print('{}/{} bimage files converted to dds.'.format(numSuccess, numProcessed))

def main():
    args = parser.parse_args()
    if os.path.isdir(args.file):
        processDir(args.file)
    elif os.path.isfile(args.file):
        if args.file.endswith(ext):
            if processFile(args.file):
                print('1 bimage file converted to dds.')
            else:
                print('unable to convert.')
        else:
            print('please use a .bimage file.')
    else:
        print('no eligible file or directory found')

if __name__ == "__main__":
    main()
Edit: Updated to handle dx10 images
Edit 2: Updated to handle more images
Edit 3: Updated to handle more images
Google Drive link with some of the interesting textures
You do not have the required permissions to view the files attached to this post.

Post Reply