1

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?

Harry McKenzie
  • 10,995
  • 8
  • 23
  • 51
teebi
  • 11
  • 2
  • 1
    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. – L0Lock Aug 01 '22 at 19:32
  • 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. – teebi Aug 01 '22 at 19:53
  • 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. – Jakemoyo Aug 01 '22 at 20:33
  • 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. – Jakemoyo Aug 01 '22 at 20:46
  • https://stackoverflow.com/questions/71397984/how-can-i-use-pil-in-python – Chris Aug 02 '22 at 07:54
  • added the command line that generates the error, thanks for the comments above. – teebi Aug 02 '22 at 18:24
  • Try to pass the filepath of the image, instead of the image object: Image.open(bpy.data.images['imgName.png'].filepath_raw). Or another way could be to save the created image to actually create the file in the disk, and then pass that filepath to Image.open(). – Giuseppe G. Aug 03 '22 at 08:06
  • Yes that's the current workaround I consider, though some images are generated in blender and not imported. Saving them locally works indeed, but at larger scale with 100+ Textures and images for large scenes it might become heavy and space/memory consuming (even if deleting the temporary images). – teebi Aug 03 '22 at 09:52

2 Answers2

1

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.

Harry McKenzie
  • 10,995
  • 8
  • 23
  • 51
1

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)

Martynas Žiemys
  • 24,274
  • 2
  • 34
  • 77