Previous Thread  Next Thread

chat icon Export image data

Traxmate

Posted: Thu Jun 21, 2012 12:34 am
Joined: 21 Jun 2012
Posts: 4
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:
# 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)
Reply with quote


stiv

Posted: Thu Jun 21, 2012 3:24 pm
Joined: 05 Aug 2003
Posts: 3485
If you are writing PNGs, they have a header and a bunch of chunks, not just a linear stream of pixels.
Reply with quote


Traxmate

Posted: Thu Jun 21, 2012 9:54 pm
Joined: 21 Jun 2012
Posts: 4
I'm not writing as a image file so I don't need the header. I want the raw pixels only.
Reply with quote


CoDEmanX

Posted: Fri Jun 22, 2012 10:48 am
Joined: 05 Apr 2009
Posts: 680
looks like the byte order is messed up...

i've done this to export to bmp:

Code:
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:

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...
Reply with quote


spaces

Posted: Sat Jun 23, 2012 12:51 am
Joined: 10 Sep 2011
Posts: 22
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?
Reply with quote


Traxmate

Posted: Sat Jun 23, 2012 10:49 pm
Joined: 21 Jun 2012
Posts: 4
CoDEmanX wrote:
looks like the byte order is messed up...

i've done this to export to bmp:

Code:
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:

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 :/
Reply with quote


CoDEmanX

Posted: Sun Jun 24, 2012 8:31 pm
Joined: 05 Apr 2009
Posts: 680
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:
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...
Reply with quote


Traxmate

Posted: Wed Jun 27, 2012 1:17 pm
Joined: 21 Jun 2012
Posts: 4
Thanks Smile works perfect now!
Reply with quote


spaces

Posted: Tue Aug 14, 2012 12:19 pm
Joined: 10 Sep 2011
Posts: 22
Woah it's fast now. Very Happy

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


spaces

Posted: Tue Aug 14, 2012 1:25 pm
Joined: 10 Sep 2011
Posts: 22
Ok, to answer my own question: need to convert bytearray instead and then it's free to manipulate in any way to wish.
Reply with quote


 
Jump to:  
Powered by phpBB © 2001, 2005 phpBB Group