3

I've got code along the lines of the following which generates a new image out of some existing images.

from PIL import Image as pyImage

def create_compound_image(back_image_path, fore_image_path, fore_x_position):

    back_image_size = get_image_size(back_image_path)
    fore_image_size = get_image_size(fore_image_path)

    new_image_width = (fore_image_size[0] / 2) + back_image_size[0]
    new_image_height = fore_image_size[1] + back_image_size[1]

    new_image = create_new_image_canvas(new_image_width, new_image_height)

    back_image = pyImage.open(back_image_path)
    fore_image = pyImage.open(fore_image_path)

    new_image.paste(back_image, (0, 0), mask = None) 
    new_image.paste(fore_image, (fore_x_position, back_image_size[1]), mask = None)

    return new_image

Later in the code, I've got something like this:

from kivy.uix.image import Image
img = Image(source = create_compound_image(...))

If I do the above, I get the message that Image.source only accepts string/unicode.

If I create a StringIO.StringIO() object from the new image, and try to use that as the source, the error message is the same as above. If I use the output of the StringIO object's getvalue() method as the source, the message is that the source must be encoded string without NULL bytes, not str.

What is the proper way to use the output of the create_compound_image() function as the source when creating a kivy Image object?

James_L
  • 1,225
  • 5
  • 19
  • 26

2 Answers2

3

It seems you want to just combine two images into one, you can actually just create a texture using Texture.create and blit the data to a particular pos using Texture.blit_buffer .

from kivy.core.image import Image
from kivy.graphics import Texture

bkimg = Image(bk_img_path)
frimg = Image(fr_img_path)

new_size = ((frimg.texture.size[0]/2) + bkimg.texture.size[0],
            frimg.texture.size[1] + bkimg.texture.size[1])

tex = Texture.create(size=new_size)
tex.blit_buffer(pbuffer=bkimg.texture.pixels, pos=(0, 0), size=bkimg.texture.size)
tex.blit_buffer(pbuffer=frimg.texture.pixels, pos=(fore_x_position, bkimg.texture.size[1]), size=frimg.texture.size)

Now you can use this texture anywhere directly like::

from kivy.uix.image import Image
image = Image()
image.texture = tex
qua-non
  • 4,152
  • 1
  • 21
  • 25
  • I have a question about this method. When pasting into 'tex', it seems that rather than pasting into a blank surface, the program attempts to fill 'tex' with the pixels in 'bkimg' or 'frimg'; this, in turn, seems to scale 'tex'. Is there a way to simply make it act is if pasting into a blank canvas, as intended? Thanks! – James_L Jan 06 '14 at 18:46
  • Nevermind - took care of it using pygame Surfaces. Thanks again! – James_L Jan 06 '14 at 20:58
  • 1
    glad to see you got it working. I seem to have omitted the `size` parameter from blit_buffer which would be useful in this case to achieve what you are after. – qua-non Jan 06 '14 at 21:43
2

source is a StringProperty and is expecting a path to file. That's why you got errors when you tried to pass PIL.Image object, StringIO object or string representation of image. It's not what framework wants. As for getting image from StringIO, it was discussed before here:

You can also try much simpler, quick and dirty method - just save your image as a tmp file and read it normal way.

Nykakin
  • 8,657
  • 2
  • 29
  • 42
  • 1
    Thanks, Nykakin. I'd like to avoid the tmp file approach in order to avoid the time-consuming I/O operations. Thanks for the links - it does seem a bit convoluted, although useful; I guess that the Texture approach, as suggested below, might be the more feasible option for this particular problem. – James_L Jan 06 '14 at 12:17