6

is it possible to display an image within the blender UI interface ?

let say that i want to display a 500x500px image in the N panel in layout.box().column(), how to do that ?

blender can already do that when clicking on an enum with preview so it must be possible within the api right ? enter image description here

Fox
  • 1,892
  • 18
  • 48

3 Answers3

13

Easy Way

Have you looked at template_preview

tex = bpy.data.textures['.hidden']
col = layout.box().column()
col.template_preview(tex)

Hard Way

So this works, but it requires a lot of finesse to make it usable. Not figured out yet how to create a layout of a fixed size to append to the panel layout for rendering over the top of. This code will render over the top of the properties panel, as opposed to the Panel UI element.

import bpy
import gpu
import bgl
from gpu_extras.batch import batch_for_shader

def draw():

x1 = 0
x2 = 200
y1 = 0
y2 = 200

shader = gpu.shader.from_builtin('2D_IMAGE')
batch = batch_for_shader(
    shader, 'TRI_FAN',
    {
        "pos": ((x1, y1), (x2, y1), (x2, y2), (x1, y2)),
        "texCoord": ((0, 0), (1, 0), (1, 1), (0, 1)),
    },
)

image = bpy.data.images['logo']

if image.gl_load():
    return # an exception happened

bgl.glActiveTexture(bgl.GL_TEXTURE0)
bgl.glBindTexture(bgl.GL_TEXTURE_2D, image.bindcode)
shader.bind()
shader.uniform_int("image", 0)
batch.draw(shader)

image.gl_free()

handler = bpy.types.SpaceProperties.draw_handler_add(draw,(),'WINDOW','POST_PIXEL')

then remove the handler with ...

bpy.types.SpaceProperties.draw_handler_remove(handler, 'WINDOW')

The hard way is maybe not the best way

brockmann
  • 12,613
  • 4
  • 50
  • 93
Moog
  • 2,202
  • 13
  • 17
  • Thanks a lot for te answer. I’ll try this tonight :) is it possible to an image from an os folder ? I don’t like the fact that I will need to import all image of the folder into blender first to generate This image only in the ui. The user don’t need to see this data ? Maybe it’s possible to hide it ? – Fox Oct 17 '19 at 16:28
  • prefix the texture name with a . so that it is hidden – Moog Oct 17 '19 at 17:52
  • wait it only works with textures list ? not images ? – Fox Oct 18 '19 at 11:24
  • There's also this https://docs.blender.org/api/blender2.8/bpy.utils.previews.html – Moog Oct 18 '19 at 16:28
  • There is a way to control the opacity of the added image? – Alfonso Annarumma Mar 03 '20 at 16:52
6

if the quality desired is not important this technique may work (icons) this script will display all the .jpg file of the directory folder in the n panel


import os
import bpy
import bpy.utils.previews

directory   = os.path.join(bpy.utils.user_resource('SCRIPTS'), "presets", "scatter_presets_custom\\")
list_raw = []

from os import listdir
from os.path import isfile, join
onlyfiles = [f for f in listdir(directory) if isfile(join(directory, f))]

for f in onlyfiles:
    if f[-4:] == ".jpg":
        list_raw.append(f)

class Panel(bpy.types.Panel):
    """Creates a Panel in the 3D view Tools panel"""
    bl_idname = "TEST_PT_Panel" 
    bl_label = "Scatter Icon test"
    bl_category = "Scatter BETA"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_context = "objectmode"

    def draw(self, context):
        global custom_icons

        for z in list_raw:
            self.layout.template_icon(icon_value=custom_icons[z[:-4]].icon_id,scale=10)

# global variable to store icons in
custom_icons = None

def register():
    global custom_icons
    custom_icons = bpy.utils.previews.new()

    for z in list_raw:
        custom_icons.load(z[:-4], os.path.join(directory, z), 'IMAGE')


    bpy.utils.register_class(Panel)

def unregister():
    global custom_icons
    bpy.utils.previews.remove(custom_icons)

    bpy.utils.unregister_class(Panel)

if __name__ == "__main__":
    register()
```
Fox
  • 1,892
  • 18
  • 48
3

To the "Easy Way" from Moog i would add how to load the image and create the texture using an image:

img = bpy.data.images.load(path, check_existing=True) # load img from disk 
img = bpy.data.images['test2.png'] # load from within blend file
texture = bpy.data.textures.new(name="previewTexture", type="IMAGE")
texture.image = img
tex = bpy.data.textures['previewTexture']
tex.extension = 'CLIP'  #EXTEND # CLIP # CLIP_CUBE # REPEAT # CHECKER

In draw():

col = self.layout.box().column() col.template_preview(self.tex) # if tex is a variable in the same class

or

col.template_preview(bpy.data.textures['previewTexture'])