Export image data

Scripting in Blender with Python, and working on the API

Moderators: jesterKing, stiv

Traxmate
Posts: 4
Joined: Thu Jun 21, 2012 1:33 am

Export image data

Postby Traxmate » Thu Jun 21, 2012 1:34 am

I'm trying to export image data from blender. Getting width, height and size works fine but something is wrong when I write the pixels to file.

This is the image I have loaded in blender: http://localhostr.com/files/6WHyRnC/Crate.jpg
this is how it looks in my game engine when I load it: http://localhostr.com/files/l4oWGWF/Untitled.png

I know I can just load the texture file from my game but I want to have the images packed inside the model file along with the vertices, normals etc...

This is how I export the image data from blender, am I doing something completely wrong here?

Code: Select all

# Write number of images
WriteInt(File, len(bpy.data.images))

for i, Image in enumerate(bpy.data.images):
    # Write width
    WriteInt(File, Image.size[0])
   
    # Write height
    WriteInt(File, Image.size[1])
   
    # Write size
    WriteInt(File, len(Image.pixels))
   
    # Write pixels
    Pixels = array('f', Image.pixels)
    Pixels.tofile(File)

stiv
Posts: 3646
Joined: Tue Aug 05, 2003 7:58 am
Location: 45N 86W

Postby stiv » Thu Jun 21, 2012 4:24 pm

If you are writing PNGs, they have a header and a bunch of chunks, not just a linear stream of pixels.

Traxmate
Posts: 4
Joined: Thu Jun 21, 2012 1:33 am

Postby Traxmate » Thu Jun 21, 2012 10:54 pm

I'm not writing as a image file so I don't need the header. I want the raw pixels only.

CoDEmanX
Posts: 894
Joined: Sun Apr 05, 2009 7:42 pm
Location: Germany

Postby CoDEmanX » Fri Jun 22, 2012 11:48 am

looks like the byte order is messed up...

i've done this to export to bmp:

Code: Select all

import bpy
import struct

def hx(float_color):
    return int(float_color * 255)

with open("D:\\imgg.bmp", "wb") as f:

    i = bpy.data.images[0]
    p = i.pixels
    w, h = i.size
   
    f.write(bytearray("BM", 'ASCII'))
    f.write(struct.pack("iiiiiihhiiiiii",
                        (54+len(p)*3), 0, 54, 40, w, h, 1, 24, 0, 0, 0, 0,
                        0, 0 ))

    c = 0
    for i in range(len(p)//4):
        f.write(struct.pack("BBB", hx(p[c+2]), hx(p[c+1]), hx(p[c])))
        c += 4
       

as you see, i need to process the values (float to int, different order)

i had similar stripes like you in my first attempt, 'cause Blender's Image.pixels are stored like

RGBA RGBA RGBA ...

but the output format was bitmap 24bpp, which is like:
BGR BGR BGR ...

see the mismatch:

Code: Select all

BGR BGR BGR BGR
RGB ARG BAR GBA


so you may have to pick the proper data type (e.g. 32bpp) or process the input before outputting
I'm sitting, waiting, wishing, building Blender in superstition...

spaces
Posts: 22
Joined: Sat Sep 10, 2011 7:03 am

Postby spaces » Sat Jun 23, 2012 1:51 am

Interesting topic. Anyway, I tried your code and it works.

But srsly.... but it's just slow. And with slow I mean it's freaking mighty slow.

Why is that?

Traxmate
Posts: 4
Joined: Thu Jun 21, 2012 1:33 am

Postby Traxmate » Sat Jun 23, 2012 11:49 pm

CoDEmanX wrote:looks like the byte order is messed up...

i've done this to export to bmp:

Code: Select all

import bpy
import struct

def hx(float_color):
    return int(float_color * 255)

with open("D:\\imgg.bmp", "wb") as f:

    i = bpy.data.images[0]
    p = i.pixels
    w, h = i.size
   
    f.write(bytearray("BM", 'ASCII'))
    f.write(struct.pack("iiiiiihhiiiiii",
                        (54+len(p)*3), 0, 54, 40, w, h, 1, 24, 0, 0, 0, 0,
                        0, 0 ))

    c = 0
    for i in range(len(p)//4):
        f.write(struct.pack("BBB", hx(p[c+2]), hx(p[c+1]), hx(p[c])))
        c += 4
       

as you see, i need to process the values (float to int, different order)

i had similar stripes like you in my first attempt, 'cause Blender's Image.pixels are stored like

RGBA RGBA RGBA ...

but the output format was bitmap 24bpp, which is like:
BGR BGR BGR ...

see the mismatch:

Code: Select all

BGR BGR BGR BGR
RGB ARG BAR GBA


so you may have to pick the proper data type (e.g. 32bpp) or process the input before outputting


Thanks, it works! To bad though that it's so slow :/

CoDEmanX
Posts: 894
Joined: Sun Apr 05, 2009 7:42 pm
Location: Germany

Postby CoDEmanX » Sun Jun 24, 2012 9:31 pm

it's not optimized, could be improved i bet

however, i rather switched to TGA format, as it officially supports alpha (RGBA)

did some speed tests and came up with this:

Code: Select all

import bpy
import struct, time

def write_tga(image_index, filepath):
   
    with open(filepath, "wb") as f:
   
        try:
            img = bpy.data.images[image_index]
        except IndexError:
            print("Error: bpy.data.images[%i] does not exist!" % image_index)
            return
       
        w, h = img.size
       
        f.write(struct.pack("<HBIIBHHBB", 0, 2, 0, 0, 0, w, h, 32, 8))
        f.write(bytes([int(pix*255) for pix in img.pixels]))

        f.close()

filepath = "D:\\imgg.tga"

t = time.clock()
write_tga(0, filepath)
print("Time: %.2f" % (time.clock() - t))


with comments (incl. other methods i tried out):
http://www.pasteall.org/33208/python

struct.pack byte for byte was really slow, all others varying between 6.4 and 7.5 seconds

the one i finally put takes 6.1 - 6.5, for a 1024*1024 pixel image
I'm sitting, waiting, wishing, building Blender in superstition...

Traxmate
Posts: 4
Joined: Thu Jun 21, 2012 1:33 am

Postby Traxmate » Wed Jun 27, 2012 2:17 pm

Thanks :) works perfect now!

spaces
Posts: 22
Joined: Sat Sep 10, 2011 7:03 am

Postby spaces » Tue Aug 14, 2012 1:19 pm

Woah it's fast now. :D

Can you make it so Red channel is swapped with Blue? I mean convert RGBA -> BGRA.

spaces
Posts: 22
Joined: Sat Sep 10, 2011 7:03 am

Postby spaces » Tue Aug 14, 2012 2:25 pm

Ok, to answer my own question: need to convert bytearray instead and then it's free to manipulate in any way to wish.


Return to “Python”

Who is online

Users browsing this forum: No registered users and 2 guests