def split_normal(self, image: bpy.types.Image):
        roughness_name = self.new_texture_name_with_suffix(
            image.name, 'roughness', 'tga')
        if image.get('normalmap_converted', None):
            return image, bpy.data.images.get(roughness_name, None)
        if bpy.app.version > (2, 83, 0):
            buffer = np.zeros(image.size[0] * image.size[1] * 4, np.float32)
            image.pixels.foreach_get(buffer)
        else:
            buffer = np.array(image.pixels[:])

        mask = buffer[2::4]
        roughness_rgb = np.dstack((mask, mask, mask, np.ones_like(mask)))

        roughness_texture = Source2ShaderBase.make_texture(
            roughness_name, image.size, roughness_rgb, True)
        buffer[1::4] = np.subtract(1, buffer[1::4])
        buffer[2::4] = 1.0
        if bpy.app.version > (2, 83, 0):
            image.pixels.foreach_set(buffer.tolist())
        else:
            image.pixels[:] = buffer.tolist()
        image.pack()
        image['normalmap_converted'] = True
        return image, roughness_texture
Esempio n. 2
0
def _encode_temp_image(tmp_image: bpy.types.Image, file_format: str) -> bytes:
    with tempfile.TemporaryDirectory() as tmpdirname:
        tmpfilename = tmpdirname + '/img'
        tmp_image.filepath_raw = tmpfilename

        tmp_image.file_format = file_format

        tmp_image.save()

        with open(tmpfilename, "rb") as f:
            return f.read()
Esempio n. 3
0
def cache_image_file(image: bpy.types.Image, cache_check=True):
    image_path = Path(image.filepath_from_user())
    if not image.packed_file and image.source != 'GENERATED':
        if not image_path.is_file():
            log.warn("Image is missing", image, image_path)
            return None

        image_suffix = Path(image.filepath).suffix.lower()

        if image_suffix in SUPPORTED_FORMATS and f".{image.file_format.lower()}" in SUPPORTED_FORMATS:
            return image_path

        if image_suffix in READONLY_IMAGE_FORMATS:
            return image_path

    old_filepath = image.filepath_raw
    old_file_format = image.file_format

    temp_path = get_temp_file(DEFAULT_FORMAT, image.name)
    if cache_check and image.source != 'GENERATED' and temp_path.is_file():
        return temp_path

    image_source = image.source
    image.filepath_raw = str(temp_path)
    image.file_format = BLENDER_DEFAULT_FORMAT

    try:
        image.save()
    finally:
        image.filepath_raw = old_filepath
        image.file_format = old_file_format
        image.source = image_source

    return temp_path
Esempio n. 4
0
def _encode_temp_image(tmp_image: bpy.types.Image, file_format: str) -> bytes:
    with tempfile.TemporaryDirectory() as tmpdirname:
        tmpfilename = tmpdirname + '/img'
        tmp_image.filepath_raw = tmpfilename

        # NOT A TYPO!!! If you delete this line, the
        # assignment on the next line will not work.
        tmp_image.file_format
        tmp_image.file_format = file_format

        tmp_image.save()

        with open(tmpfilename, "rb") as f:
            return f.read()
Esempio n. 5
0
    def convert_normalmap(image: bpy.types.Image):
        if image.get('normalmap_converted', None):
            return image
        if bpy.app.version > (2, 83, 0):
            buffer = np.zeros(image.size[0] * image.size[1] * 4, np.float32)
            image.pixels.foreach_get(buffer)
        else:
            buffer = np.array(image.pixels[:])

        buffer[1::4] = np.subtract(1, buffer[1::4])
        if bpy.app.version > (2, 83, 0):
            image.pixels.foreach_set(buffer.tolist())
        else:
            image.pixels[:] = buffer.tolist()
        image.pack()
        image['normalmap_converted'] = True
        return image
Esempio n. 6
0
def tmp_encode_movie(image: bpy.types.Image):
    """
    Reads the image bytes from disk back.
    """
    path = image.filepath_from_user()
    with open(path, "rb") as f:
        encoded_image = f.read()

    return encoded_image
Esempio n. 7
0
def cache_image_file(image: bpy.types.Image, depsgraph) -> str:
    """
    See if image is a file, cache image pixels to temporary folder if not.
    Return image file path.
    """
    if image.source != 'FILE':
        temp_path = _get_temp_image_path(image)
        if image.is_dirty or not os.path.isfile(temp_path):
            image.save_render(temp_path)

        return temp_path

    file_path = image.filepath_from_user()

    if file_path.lower().endswith('.ies'):
        if os.path.isfile(file_path):
            return file_path

        if not image.packed_file:
            log.warn("Can't load image", image, file_path)
            return None

        temp_path = _get_temp_image_path(image, "ies")
        if not os.path.isfile(temp_path):
            # save data of packed file
            Path(temp_path).write_bytes(image.packed_file.data)

        return temp_path

    if image.is_dirty or not os.path.isfile(file_path) \
            or file_path.lower().endswith(UNSUPPORTED_IMAGES):
        target_format, target_extension = IMAGE_FORMATS.get(
            image.file_format, DEFAULT_FORMAT)

        # getting file path from image cache and if such file not exist saving image to cache
        temp_path = _get_temp_image_path(image, target_extension)
        if image.is_dirty or not os.path.isfile(temp_path):
            _save_temp_image(image, target_format, temp_path, depsgraph)

        return temp_path

    return file_path
Esempio n. 8
0
def _make_temp_image_copy(guard: TmpImageGuard, src_image: bpy.types.Image):
    """Makes a temporary copy of src_image. Will be cleaned up with guard."""
    guard.image = src_image.copy()
    tmp_image = guard.image

    tmp_image.update()

    if src_image.is_dirty:
        # Unsaved changes aren't copied by .copy(), so do them ourselves
        tmp_buf = np.empty(src_image.size[0] * src_image.size[1] * 4, np.float32)
        src_image.pixels.foreach_get(tmp_buf)
        tmp_image.pixels.foreach_set(tmp_buf)
Esempio n. 9
0
 def convert_ssbump(image: bpy.types.Image):
     if image.get('ssbump_converted', None):
         return image
     if bpy.app.version > (2, 83, 0):
         buffer = np.zeros(image.size[0] * image.size[1] * 4, np.float32)
         image.pixels.foreach_get(buffer)
     else:
         buffer = np.array(image.pixels[:])
     buffer[0::4] *= 0.5
     buffer[0::4] += 0.33
     buffer[1::4] *= 0.5
     buffer[1::4] += 0.33
     buffer[2::4] *= 0.2
     buffer[2::4] += 0.8
     if bpy.app.version > (2, 83, 0):
         image.pixels.foreach_set(buffer.tolist())
     else:
         image.pixels[:] = buffer.tolist()
     image.pack()
     image['ssbump_converted'] = True
     return image
def save_image_targetdir(arg_image: bpy.types.Image,
                         arg_directory: str,
                         arg_colormode: str = 'RGBA',
                         arg_colordepth: str = '8',
                         arg_compression: int = 15) -> bool:
    """指定ディレクトリにテクスチャをPNG形式で保存する

    Args:
        arg_image (bpy.types.Image): 保存テクスチャ
        arg_directory (str): 指定ディレクトリ
        arg_colormode (str, optional): カラーモード指定. Defaults to 'RGBA'.
        arg_colordepth (str, optional): 色深度指定. Defaults to '8'.
        arg_compression (int, optional): 圧縮率指定. Defaults to 15.

    Returns:
        bool: 実行正否
    """

    # 保存ファイルパスを作成する
    savepath = arg_directory + "\\" + arg_image.name + ".png"

    # 保存ファイルパスを指定する
    arg_image.filepath_raw = savepath

    # ファイルフォーマットをPNGに設定する
    arg_image.file_format = 'PNG'

    # 参照パスを保存するため、一度保存を行う
    arg_image.save()

    # レンダー色空間で保存するためのシーンを取得する
    # (https://docs.blender.org/api/current/bpy.types.Scene.html)
    render_scene = bpy.context.scene

    # 現在のカラーマネジメントのビュー変換を取得する
    current_view_transform = render_scene.view_settings.view_transform

    # カラーマネジメントのビュー変換を[標準]に設定する(Filmicだと灰色に出力されるため)
    # (https://docs.blender.org/api/current/bpy.types.ColorManagedViewSettings.html)
    render_scene.view_settings.view_transform = 'Standard'

    # シーンのレンダリング設定からイメージフォーマット設定の参照を取得する
    scene_imagesettings = render_scene.render.image_settings

    # カラーフォーマットを設定する
    scene_imagesettings.color_mode = arg_colormode

    # 色深度を設定する
    scene_imagesettings.color_depth = arg_colordepth

    # 圧縮率を設定する
    scene_imagesettings.compression = arg_compression

    # シーンのレンダリング設定を利用して画像を保存する
    arg_image.save_render(filepath=savepath, scene=render_scene)

    # 変更したビュー変換を元に戻す
    render_scene.view_settings.view_transform = current_view_transform

    return True
def cache_image_file(image: bpy.types.Image, cache_check=True):
    image_path = Path(image.filepath_from_user())
    if not image.packed_file and image.source != 'GENERATED':
        if not image_path.is_file():
            log.warn("Image is missing", image, image_path)
            return None

        image_suffix = image_path.suffix.lower()

        if image_suffix in SUPPORTED_FORMATS and\
                f".{image.file_format.lower()}" in SUPPORTED_FORMATS and not image.is_dirty:
            return image_path

        if image_suffix in READONLY_IMAGE_FORMATS:
            return image_path

    temp_path = get_temp_file(DEFAULT_FORMAT, image_path.stem)
    if cache_check and image.source != 'GENERATED' and temp_path.is_file():
        return temp_path

    scene = bpy.context.scene
    user_format = scene.render.image_settings.file_format
    user_color_mode = scene.render.image_settings.color_mode

    # in some scenes the color_mode is undefined
    # we can read it but unable to assign back, so switch it to 'RGB' if color_mode isn't selected
    if not user_color_mode:
        user_color_mode = 'RGB'

    scene.render.image_settings.file_format = BLENDER_DEFAULT_FORMAT
    scene.render.image_settings.color_mode = BLENDER_DEFAULT_COLOR_MODE

    try:
        image.save_render(filepath=str(temp_path))
    finally:
        scene.render.image_settings.file_format = user_format
        scene.render.image_settings.color_mode = user_color_mode

    return temp_path
def _make_temp_image_copy(guard: TmpImageGuard, src_image: bpy.types.Image):
    """Makes a temporary copy of src_image. Will be cleaned up with guard."""
    guard.image = src_image.copy()
    tmp_image = guard.image

    tmp_image.update()
    # See #1564 and T95616
    tmp_image.scale(*src_image.size)

    if src_image.is_dirty:  # Warning, img size change doesn't make it dirty, see T95616
        # Unsaved changes aren't copied by .copy(), so do them ourselves
        tmp_buf = np.empty(src_image.size[0] * src_image.size[1] * 4,
                           np.float32)
        src_image.pixels.foreach_get(tmp_buf)
        tmp_image.pixels.foreach_set(tmp_buf)
Esempio n. 13
0
    def __encode_from_image(self, image: bpy.types.Image) -> bytes:
        # See if there is an existing file we can use.
        data = None
        if image.source == 'FILE' and image.file_format == self.file_format and \
                not image.is_dirty:
            if image.packed_file is not None:
                data = image.packed_file.data
            else:
                src_path = bpy.path.abspath(image.filepath_raw)
                if os.path.isfile(src_path):
                    with open(src_path, 'rb') as f:
                        data = f.read()
        # Check magic number is right
        if data:
            if self.file_format == 'PNG':
                if data.startswith(b'\x89PNG'):
                    return data
            elif self.file_format == 'JPEG':
                if data.startswith(b'\xff\xd8\xff'):
                    return data

        # Copy to a temp image and save.
        tmp_image = None
        try:
            tmp_image = image.copy()
            tmp_image.update()

            if image.is_dirty:
                # Copy the pixels to get the changes
                tmp_buf = np.empty(image.size[0] * image.size[1] * 4,
                                   np.float32)
                image.pixels.foreach_get(tmp_buf)
                tmp_image.pixels.foreach_set(tmp_buf)
                tmp_buf = None  # GC this

            return _encode_temp_image(tmp_image, self.file_format)
        finally:
            if tmp_image is not None:
                bpy.data.images.remove(tmp_image, do_unlink=True)
Esempio n. 14
0
    def __encode_from_image(self, image: bpy.types.Image) -> bytes:
        # See if there is an existing file we can use.
        if image.source == 'FILE' and image.file_format == self.file_format and \
                not image.is_dirty:
            if image.packed_file is not None:
                return image.packed_file.data
            else:
                src_path = bpy.path.abspath(image.filepath_raw)
                if os.path.isfile(src_path):
                    with open(src_path, 'rb') as f:
                        return f.read()

        # Copy to a temp image and save.
        tmp_image = None
        try:
            tmp_image = image.copy()
            if image.is_dirty:
                tmp_image.pixels = image.pixels[:]

            return _encode_temp_image(tmp_image, self.file_format)
        finally:
            if tmp_image is not None:
                bpy.data.images.remove(tmp_image, do_unlink=True)
Esempio n. 15
0
def load_texture(texture: bpy.types.Image) -> int:
    """Load the texture, return OpenGL error code."""
    return texture.gl_load(filter=bgl.GL_NEAREST, mag=bgl.GL_NEAREST)
Esempio n. 16
0
def sync(rpr_context,
         image: bpy.types.Image,
         use_color_space=None,
         frame_number=None):
    """ Creates pyrpr.Image from bpy.types.Image """
    from rprblender.engine.export_engine import ExportEngine

    color_space = image.colorspace_settings.name
    if use_color_space:
        color_space = use_color_space

    if image.source == 'SEQUENCE':
        image_key = key(image, color_space, frame_number=frame_number)
    else:
        if image.size[0] * image.size[1] * image.channels == 0:
            log.warn("Image has no data", image)
            return None
        image_key = key(image, color_space)

    if image_key in rpr_context.images:
        return rpr_context.images[image_key]

    log("sync", image)

    if image.source == 'TILED':  # UDIM Tiles
        rpr_image = rpr_context.create_tiled_image(key=image_key)
        if rpr_image:  # if context doesn't support tiles - export as regular image
            udim_path_split = image.filepath_from_user().split('.')
            for tile in image.tiles:
                tile_path = '.'.join(udim_path_split[:-2] + [tile.label] +
                                     udim_path_split[-1:])
                tile_key = key(image, color_space, UDIM_tile=tile.label)

                tile_image = rpr_context.create_image_file(tile_key, tile_path)
                set_image_gamma(tile_image, image, color_space)
                tile_image.set_name(str(tile_key))

                rpr_image.set_udim_tile(tile.number, tile_image)

            rpr_image.set_name(str(image_key))

            return rpr_image

    pixels = image.pixels
    if image.source == 'SEQUENCE':
        file_path = get_sequence_frame_file_path(image.filepath_from_user(),
                                                 frame_number)
        if not file_path:
            return None
        rpr_image = rpr_context.create_image_file(image_key, file_path)

    elif rpr_context.engine_type != ExportEngine.TYPE and hasattr(
            pixels, 'foreach_get'):
        data = utils.get_prop_array_data(pixels)
        data = np.flipud(
            data.reshape(image.size[1], image.size[0], image.channels))
        rpr_image = rpr_context.create_image_data(image_key,
                                                  np.ascontiguousarray(data))

    elif image.source in ('FILE', 'GENERATED'):
        file_path = cache_image_file(image,
                                     rpr_context.blender_data['depsgraph'])
        rpr_image = rpr_context.create_image_file(image_key, file_path)

    else:
        # loading image by pixels
        data = utils.get_prop_array_data(pixels)
        data = np.flipud(
            data.reshape(image.size[1], image.size[0], image.channels))
        rpr_image = rpr_context.create_image_data(image_key,
                                                  np.ascontiguousarray(data))

    rpr_image.set_name(str(image_key))

    set_image_gamma(rpr_image, image, color_space)

    return rpr_image
Esempio n. 17
0
def sync(rpr_context,
         image: bpy.types.Image,
         use_color_space=None,
         frame_number=None):
    """ Creates pyrpr.Image from bpy.types.Image """
    from rprblender.engine.export_engine import ExportEngine

    color_space = image.colorspace_settings.name
    if use_color_space:
        color_space = use_color_space

    if image.source == 'SEQUENCE':
        image_key = key(image, color_space, frame_number)
    else:
        if image.size[0] * image.size[1] * image.channels == 0:
            log.warn("Image has no data", image)
            return None
        image_key = key(image, color_space)

    if image_key in rpr_context.images:
        return rpr_context.images[image_key]

    log("sync", image)

    pixels = image.pixels
    if image.source == 'SEQUENCE':
        file_path = get_sequence_frame_file_path(image.filepath_from_user(),
                                                 frame_number)
        if not file_path:
            return None
        rpr_image = rpr_context.create_image_file(image_key, file_path)

    elif rpr_context.engine_type != ExportEngine.TYPE and hasattr(
            pixels, 'foreach_get'):
        data = utils.get_prop_array_data(pixels)
        data = np.flipud(
            data.reshape(image.size[1], image.size[0], image.channels))
        rpr_image = rpr_context.create_image_data(image_key,
                                                  np.ascontiguousarray(data))

    elif image.source in ('FILE', 'GENERATED'):
        file_path = cache_image_file(image,
                                     rpr_context.blender_data['depsgraph'])
        rpr_image = rpr_context.create_image_file(image_key, file_path)

    else:
        # loading image by pixels
        data = utils.get_prop_array_data(pixels)
        data = np.flipud(
            data.reshape(image.size[1], image.size[0], image.channels))
        rpr_image = rpr_context.create_image_data(image_key,
                                                  np.ascontiguousarray(data))

    rpr_image.set_name(str(image_key))

    # TODO: implement more correct support of image color space types
    # RPRImageTexture node color space names are in caps, unlike in Blender
    if color_space in ('sRGB', 'BD16', 'Filmic Log', 'SRGB'):
        rpr_image.set_gamma(2.2)
    elif color_space not in ('Non-Color', 'Raw', 'Linear', 'LINEAR'):
        log.warn("Ignoring unsupported image color space type", color_space,
                 image)

    return rpr_image
Esempio n. 18
0
def load_texture(texture: bpy.types.Image) -> int:
    """Load the texture, return OpenGL error code."""
    return texture.gl_load()
Esempio n. 19
0
def draw_image(  # noqa: WPS210, WPS211
        x: float,  # noqa: WPS111
        y: float,  # noqa: WPS111
        width: float,
        height: float,
        image: bpy.types.Image,
        transparency: float,
        crop: Color = (0, 0, 1, 1),
) -> None:
    """Draw a image on the screen.

    Parameters:
        x: Bottom-left x-coordinate
        y: Bottom-left y-coordinate
        width: Width of the image
        height: Height of the image
        image: Image to be drawn
        transparency: Image transparency
        crop: Tuple describing how the image should be cropped

    Raises:
        Exception: Failed to load into an OpenGL texture
    """
    coords = [
        (x, y),
        (x + width, y),
        (x, y + height),
        (x + width, y + height),
    ]

    uvs = [
        (crop[0], crop[1]),
        (crop[2], crop[1]),
        (crop[0], crop[3]),
        (crop[2], crop[3]),
    ]

    indices = [(0, 1, 2), (2, 1, 3)]

    shader = gpu.shader.from_builtin('2D_IMAGE')
    batch = batch_for_shader(shader,
                             'TRIS', {
                                 'pos': coords,
                                 'texCoord': uvs
                             },
                             indices=indices)

    # send image to gpu if it isn't there already
    if image.gl_load():
        raise Exception()

    # texture identifier on gpu
    texture_id = image.bindcode

    # in case someone disabled it before
    bgl.glEnable(bgl.GL_BLEND)

    # bind texture to image unit 0
    bgl.glActiveTexture(bgl.GL_TEXTURE0)
    bgl.glBindTexture(bgl.GL_TEXTURE_2D, texture_id)

    shader.bind()
    # tell shader to use the image that is bound to image unit 0
    shader.uniform_int('image', 0)
    batch.draw(shader)

    bgl.glDisable(bgl.GL_TEXTURE_2D)
Esempio n. 20
0
def _has_missing_reference(image: bpy.types.Image):
    if not image.packed_file:
        path = image.filepath_from_user()
        return not os.path.exists(path)
    return False