1
$\begingroup$

I'm using PIL to an addon I'm working on and at some point I need to open images using pillow. The usual way to do is

from PIL import Image
Image.open('whatever your image is')

But with images created within Blender, the only access is using bpy.data.image['the image'] which causes error using Image.open from PIL.

I get the following error when I type: Image.open(bpy.data.image['test'])

Traceback (most recent call last):
  File "C:\Users\myName\AppData\Roaming\Python\Python39\site-packages\PIL\Image.py", line 3096, in open
    fp.seek(0)
AttributeError: 'Image' object has no attribute 'seek'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<blender_console>", line 1, in <module>
  File "C:\Users\myName\AppData\Roaming\Python\Python39\site-packages\PIL\Image.py", line 3098, in open
    fp = io.BytesIO(fp.read())
AttributeError: 'Image' object has no attribute 'read'

I found some idea using pixels and Image.fromarray but nothing conclusive so far...

How do you load Blender's image like bpy.data.image['the image'] into PIL image?

$\endgroup$
8
  • 1
    $\begingroup$ I guess you installed PIL to your local python, but have you installed it in your Blender installation's own python? AFAIK they are completelly independant. How to install python modules in blender Besides, this raises the question: how will you distribute your addon and make it easier for its users to install it with its dependencies. $\endgroup$
    – Lauloque
    Commented Aug 1, 2022 at 19:32
  • $\begingroup$ The installation folder doesn't seems to be the issue, I made a similar thing to the link you share (thanks by the way). The issue here is opening the image. $\endgroup$
    – teebi
    Commented Aug 1, 2022 at 19:53
  • $\begingroup$ If you're asking a question about a script it's usually a good idea to post the script in the question. The error can only tell us so much about your issue. $\endgroup$
    – Jakemoyo
    Commented Aug 1, 2022 at 20:33
  • $\begingroup$ It seems like you are trying to reference a blender bpy.types.Image as if it were a PIL.Image but those are not the same thing. bpy vs. PIL objects. $\endgroup$
    – Jakemoyo
    Commented Aug 1, 2022 at 20:46
  • $\begingroup$ stackoverflow.com/questions/71397984/… $\endgroup$
    – Chris
    Commented Aug 2, 2022 at 7:54

2 Answers 2

1
+50
$\begingroup$

The method Image.open is only used to open file paths. But you can simply transform the pixels into bytes and use Image.frombytes instead to get the pillow image:

import bpy
from PIL import Image
import io
import struct

img = bpy.data.images['test']

pixels = [int(px * 255) for px in img.pixels[:]]
bytes = struct.pack("%sB" % len(pixels), *pixels)

image = Image.frombytes('RGBA', (img.size[0], img.size[1]), bytes)
image = image.transpose(Image.FLIP_LEFT_RIGHT).rotate(180)

image.show()

For those who have not installed the PIL module. You can install it with the following script using pip.

import subprocess
import sys
import os
 
python_exe = os.path.join(sys.prefix, 'bin', 'python.exe')

subprocess.call([python_exe, '-m', 'ensurepip'])
subprocess.call([python_exe, '-m', 'pip', 'install', '--upgrade', 'pip'])
subprocess.call([python_exe, '-m', 'pip', 'install', '--upgrade', 'pillow'])

You can read more about installing python modules here. Note that the original Python Imaging Library (PIL) was the popular image processing library for Python. However, development on PIL ceased a long time ago, and the project was dormant for several years. As a result, the community created a fork of PIL called Pillow to continue its development and maintenance.

$\endgroup$
1
$\begingroup$

Based on great answer of Harry McKenzie just for convenience for the next guy looking for this:

import bpy
import os
import subprocess
import sys
import io
import struct
import numpy as np

try:
    from PIL import Image
except: 
    python_exe = os.path.join(sys.prefix, 'bin', 'python.exe')
    subprocess.call([python_exe, '-m', 'ensurepip'])
    subprocess.call([python_exe, '-m', 'pip', 'install', '--upgrade', 'pip'])
    subprocess.call([python_exe, '-m', 'pip', 'install', '--upgrade', 'pillow'])
    
def pil_to_image(pil_image, name='NewImage'):
    width, height = pil_image.width, pil_image.height
    normalized = 1.0 / 255.0
    bpy_image = bpy.data.images.new(name, width=width, height=height)
    bpy_image.pixels[:] = (np.asarray(pil_image.convert('RGBA'),dtype=np.float32) * normalized).ravel()
    return bpy_image

def image_to_pil(bpy_image):
    img = bpy_image
    pixels = [int(px * 255) for px in bpy_image.pixels[:]]
    bytes = struct.pack("%sB" % len(pixels), *pixels)
    pil_image = Image.frombytes('RGBA', (bpy_image.size[0], bpy_image.size[1]), bytes)
    return pil_image


im = image_to_pil(bpy.data.images["test"])
im = im.transpose(Image.FLIP_LEFT_RIGHT).rotate(45)
pil_to_image(im)
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .