Python Forum
ImageTk Paste - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: ImageTk Paste (/thread-33838.html)

Pages: 1 2


ImageTk Paste - KDog - May-31-2021

I'm back again with my camera app! Trying to overlay/merge two images when saving them.
The error i get is
Error:
AttributeError: 'PhotoImage' object has no attribute 'load'
Please see code below:
from tkinter import *
import cv2
from PIL import Image, ImageTk, ImageEnhance
import time
from tkinter import filedialog
import numpy as np


class App:
    def __init__(self, video_source=0):
        self.overlay_img = None
        self.appName = "Kamera"
        self.window = Tk()
        self.window.title(self.appName)
        self.window.resizable(0, 0)
        # self.window.wm_iconbitmap("cam.ico")
        self.window['bg'] = 'black'
        self.video_source = video_source

        self.vid = MyVideoCapture(self.video_source)
        # self.label = Label(self.window, text=self.appName, font=15, bg='blue', fg='white').pack(side=TOP, fill=BOTH)
        self.canvas = Canvas(self.window, width=self.vid.width, height=self.vid.height, bg='red')
        self.canvas.pack()

        self.btn_snapshot = Button(self.window, text="Snapshot", width=5, command=self.snapshot)
        self.btn_snapshot.pack(side=LEFT, padx=10)

        self.btn_overlay = Button(self.window, text="Overlay", width=7, command=self.overlay)
        self.btn_overlay.pack(side=LEFT, padx=10)

        self.btn_settings = Button(self.window, text="Settings", width=5, command=self.settings)
        self.btn_settings.pack(side=LEFT, padx=10)

        self.slide_value = 200
        self.update()
        self.window.mainloop()

    def settings(self):
        self.newWindow = Toplevel(self.window)
        self.newWindow.title("Settings")
        self.newWindow.geometry("400x400")
        self.btn_flip = Button(self.newWindow, text="Mirror Image", width=10, command=self.flip_img)
        self.btn_flip.pack(side=LEFT, padx=10)
            # self.brightness_lbl = Label(self.newWindow, text="Image Brightness")
            # self.brightness_lbl.pack(anchor=NW)
        #var = IntVar()
        self.brightness = Scale(
        self.newWindow, length=200, from_=0, to=255, orient=HORIZONTAL, label="Image Brightness",
                command=self.slide)
        self.brightness.set(200)
        self.brightness.pack(anchor=NW)

    def slide(self, var):
        self.slide_value = self.brightness.get()
        print(self.slide_value)

    def flip_img(self):
        self.vid.flipped = not self.vid.flipped

    def overlay(self):
        file = filedialog.askopenfile(
            mode='rb', defaultextension='.png',title="Choose Overlay Image", filetypes=[("PNG Files", '*.png')])
        if file:
            self.overlay_img = ImageTk.PhotoImage(file=file)

    def snapshot(self):
        isTrue, frame = self.vid.getFrame()

        if isTrue:
            filename = filedialog.asksaveasfilename(
                defaultextension='.jpg', title="Choose Filename", filetypes=[("JPEG Files", '*.jpg')])
            # image = "IMG-" + time.strftime("%H-%M-%S-%d-%m") + ".jpg"
            cv2.imwrite(filename, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
            # msg = Label(self.window, text='Image Saved' + image, bg='black', fg='green').place(x=430, y=510)

        else:
            messagebox.showerror("paint says", "unable to save image ,\n something went wrong")

        if isTrue and self.overlay_img:
            self.photo.paste(self.overlay_img, (0, 0))
            self.stamped_img = ImageTk.PhotoImage(self.photo)
            filename = filedialog.asksaveasfilename(
            defaultextension='.jpg', title="Choose Filename", filetypes=[("JPEG Files", '*.jpg')])
            filename = self.stamped_img

    def update(self):
        isTrue, frame = self.vid.getFrame()
        frame = cv2.normalize(frame, frame, 0, self.slide_value, cv2.NORM_MINMAX)

        if isTrue:
            self.photo = ImageTk.PhotoImage(image=Image.fromarray(frame))
            #self.canvas.tag_lower(self.photo)
            self.canvas.create_image(0, 0, image=self.photo, anchor=NW)

        if self.overlay_img:
            #self.canvas.tag_raise(self.overlay_img)
            self.canvas.create_image(0,0, image=self.overlay_img, anchor=NW)
            #self.stamped_img = self.photo.paste(self.overlay_img)
        self.window.after(100, self.update)


class MyVideoCapture:
    def __init__(self, video_source=0):
        self.vid = cv2.VideoCapture(video_source)
        if not self.vid.isOpened():
            raise ValueError("Unable to open this camera \n select another video source", video_source)

        self.width = self.vid.get(cv2.CAP_PROP_FRAME_WIDTH)
        self.height = self.vid.get(cv2.CAP_PROP_FRAME_HEIGHT)

        self.flipped = True

    def getFrame(self):
        if self.vid.isOpened():
            isTrue, frame = self.vid.read()
            if isTrue and self.flipped:
                frame = cv2.flip(frame, 1)
            if isTrue:
                return (isTrue, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
            else:
                return (isTrue, None)
        else:
            return (isTrue, None)

    def __del__(self):
        if self.vid.isOpened():
            self.vid.release()


if __name__ == "__main__":
    App()



RE: ImageTk Paste - bowlofred - May-31-2021

There is no load in your code, and you haven't included the entire traceback (which would show where the error is being produced). Is this all the code?


RE: ImageTk Paste - Yoriz - May-31-2021

Hello again, I don't see load used directly anywhere it must be called indirectly.
You should show the full error traceback as it indicates where it went wrong and more information.


RE: ImageTk Paste - KDog - Jun-01-2021

(May-31-2021, 10:31 PM)Yoriz Wrote: Hello again, I don't see load used directly anywhere it must be called indirectly.
You should show the full error traceback as it indicates where it went wrong and more information.

It's in ImageTk.py:
Error:
File "/home/kieran/PycharmProjects/Kamera/venv/lib/python3.8/site-packages/PIL/ImageTk.py", line 165, in paste im.load() AttributeError: 'PhotoImage' object has no attribute 'load'
ImageTk.py
#
# The Python Imaging Library.
# $Id$
#
# a Tk display interface
#
# History:
# 96-04-08 fl   Created
# 96-09-06 fl   Added getimage method
# 96-11-01 fl   Rewritten, removed image attribute and crop method
# 97-05-09 fl   Use PyImagingPaste method instead of image type
# 97-05-12 fl   Minor tweaks to match the IFUNC95 interface
# 97-05-17 fl   Support the "pilbitmap" booster patch
# 97-06-05 fl   Added file= and data= argument to image constructors
# 98-03-09 fl   Added width and height methods to Image classes
# 98-07-02 fl   Use default mode for "P" images without palette attribute
# 98-07-02 fl   Explicitly destroy Tkinter image objects
# 99-07-24 fl   Support multiple Tk interpreters (from Greg Couch)
# 99-07-26 fl   Automatically hook into Tkinter (if possible)
# 99-08-15 fl   Hook uses _imagingtk instead of _imaging
#
# Copyright (c) 1997-1999 by Secret Labs AB
# Copyright (c) 1996-1997 by Fredrik Lundh
#
# See the README file for information on usage and redistribution.
#

import tkinter
from io import BytesIO

from . import Image

# --------------------------------------------------------------------
# Check for Tkinter interface hooks

_pilbitmap_ok = None


def _pilbitmap_check():
    global _pilbitmap_ok
    if _pilbitmap_ok is None:
        try:
            im = Image.new("1", (1, 1))
            tkinter.BitmapImage(data=f"PIL:{im.im.id}")
            _pilbitmap_ok = 1
        except tkinter.TclError:
            _pilbitmap_ok = 0
    return _pilbitmap_ok


def _get_image_from_kw(kw):
    source = None
    if "file" in kw:
        source = kw.pop("file")
    elif "data" in kw:
        source = BytesIO(kw.pop("data"))
    if source:
        return Image.open(source)


# --------------------------------------------------------------------
# PhotoImage


class PhotoImage:
    """
    A Tkinter-compatible photo image.  This can be used
    everywhere Tkinter expects an image object.  If the image is an RGBA
    image, pixels having alpha 0 are treated as transparent.

    The constructor takes either a PIL image, or a mode and a size.
    Alternatively, you can use the ``file`` or ``data`` options to initialize
    the photo image object.

    :param image: Either a PIL image, or a mode string.  If a mode string is
                  used, a size must also be given.
    :param size: If the first argument is a mode string, this defines the size
                 of the image.
    :keyword file: A filename to load the image from (using
                   ``Image.open(file)``).
    :keyword data: An 8-bit string containing image data (as loaded from an
                   image file).
    """

    def __init__(self, image=None, size=None, **kw):

        # Tk compatibility: file or data
        if image is None:
            image = _get_image_from_kw(kw)

        if hasattr(image, "mode") and hasattr(image, "size"):
            # got an image instead of a mode
            mode = image.mode
            if mode == "P":
                # palette mapped data
                image.load()
                try:
                    mode = image.palette.mode
                except AttributeError:
                    mode = "RGB"  # default
            size = image.size
            kw["width"], kw["height"] = size
        else:
            mode = image
            image = None

        if mode not in ["1", "L", "RGB", "RGBA"]:
            mode = Image.getmodebase(mode)

        self.__mode = mode
        self.__size = size
        self.__photo = tkinter.PhotoImage(**kw)
        self.tk = self.__photo.tk
        if image:
            self.paste(image)

    def __del__(self):
        name = self.__photo.name
        self.__photo.name = None
        try:
            self.__photo.tk.call("image", "delete", name)
        except Exception:
            pass  # ignore internal errors

    def __str__(self):
        """
        Get the Tkinter photo image identifier.  This method is automatically
        called by Tkinter whenever a PhotoImage object is passed to a Tkinter
        method.

        :return: A Tkinter photo image identifier (a string).
        """
        return str(self.__photo)

    def width(self):
        """
        Get the width of the image.

        :return: The width, in pixels.
        """
        return self.__size[0]

    def height(self):
        """
        Get the height of the image.

        :return: The height, in pixels.
        """
        return self.__size[1]

    def paste(self, im, box=None):
        """
        Paste a PIL image into the photo image.  Note that this can
        be very slow if the photo image is displayed.

        :param im: A PIL image. The size must match the target region.  If the
                   mode does not match, the image is converted to the mode of
                   the bitmap image.
        :param box: A 4-tuple defining the left, upper, right, and lower pixel
                    coordinate. See :ref:`coordinate-system`. If None is given
                    instead of a tuple, all of the image is assumed.
        """

        # convert to blittable
        im.load()
        image = im.im
        if image.isblock() and im.mode == self.__mode:
            block = image
        else:
            block = image.new_block(self.__mode, im.size)
            image.convert2(block, image)  # convert directly between buffers

        tk = self.__photo.tk

        try:
            tk.call("PyImagingPhoto", self.__photo, block.id)
        except tkinter.TclError:
            # activate Tkinter hook
            try:
                from . import _imagingtk

                try:
                    if hasattr(tk, "interp"):
                        # Required for PyPy, which always has CFFI installed
                        from cffi import FFI

                        ffi = FFI()

                        # PyPy is using an FFI CDATA element
                        # (Pdb) self.tk.interp
                        #  <cdata 'Tcl_Interp *' 0x3061b50>
                        _imagingtk.tkinit(int(ffi.cast("uintptr_t", tk.interp)), 1)
                    else:
                        _imagingtk.tkinit(tk.interpaddr(), 1)
                except AttributeError:
                    _imagingtk.tkinit(id(tk), 0)
                tk.call("PyImagingPhoto", self.__photo, block.id)
            except (ImportError, AttributeError, tkinter.TclError):
                raise  # configuration problem; cannot attach to Tkinter


# --------------------------------------------------------------------
# BitmapImage


class BitmapImage:
    """
    A Tkinter-compatible bitmap image.  This can be used everywhere Tkinter
    expects an image object.

    The given image must have mode "1".  Pixels having value 0 are treated as
    transparent.  Options, if any, are passed on to Tkinter.  The most commonly
    used option is ``foreground``, which is used to specify the color for the
    non-transparent parts.  See the Tkinter documentation for information on
    how to specify colours.

    :param image: A PIL image.
    """

    def __init__(self, image=None, **kw):

        # Tk compatibility: file or data
        if image is None:
            image = _get_image_from_kw(kw)

        self.__mode = image.mode
        self.__size = image.size

        if _pilbitmap_check():
            # fast way (requires the pilbitmap booster patch)
            image.load()
            kw["data"] = f"PIL:{image.im.id}"
            self.__im = image  # must keep a reference
        else:
            # slow but safe way
            kw["data"] = image.tobitmap()
        self.__photo = tkinter.BitmapImage(**kw)

    def __del__(self):
        name = self.__photo.name
        self.__photo.name = None
        try:
            self.__photo.tk.call("image", "delete", name)
        except Exception:
            pass  # ignore internal errors

    def width(self):
        """
        Get the width of the image.

        :return: The width, in pixels.
        """
        return self.__size[0]

    def height(self):
        """
        Get the height of the image.

        :return: The height, in pixels.
        """
        return self.__size[1]

    def __str__(self):
        """
        Get the Tkinter bitmap image identifier.  This method is automatically
        called by Tkinter whenever a BitmapImage object is passed to a Tkinter
        method.

        :return: A Tkinter bitmap image identifier (a string).
        """
        return str(self.__photo)


def getimage(photo):
    """Copies the contents of a PhotoImage to a PIL image memory."""
    im = Image.new("RGBA", (photo.width(), photo.height()))
    block = im.im

    photo.tk.call("PyImagingPhotoGet", photo, block.id)

    return im


def _show(image, title):
    """Helper for the Image.show method."""

    class UI(tkinter.Label):
        def __init__(self, master, im):
            if im.mode == "1":
                self.image = BitmapImage(im, foreground="white", master=master)
            else:
                self.image = PhotoImage(im, master=master)
            super().__init__(master, image=self.image, bg="black", bd=0)

    if not tkinter._default_root:
        raise OSError("tkinter not initialized")
    top = tkinter.Toplevel()
    if title:
        top.title(title)
    UI(top, image).pack()



RE: ImageTk Paste - Yoriz - Jun-01-2021

I think due to Namespace flooding with * imports you've learnt your lesson in why to not do it.

The code is expecting a PIL Image instead I think its got a tkinter Image which has no load method see the tk Image class below.
class Image:
    """Base class for images."""
    _last_id = 0

    def __init__(self, imgtype, name=None, cnf={}, master=None, **kw):
        self.name = None
        if not master:
            master = _get_default_root('create image')
        self.tk = getattr(master, 'tk', master)
        if not name:
            Image._last_id += 1
            name = "pyimage%r" % (Image._last_id,) # tk itself would use image<x>
        if kw and cnf: cnf = _cnfmerge((cnf, kw))
        elif kw: cnf = kw
        options = ()
        for k, v in cnf.items():
            if callable(v):
                v = self._register(v)
            options = options + ('-'+k, v)
        self.tk.call(('image', 'create', imgtype, name,) + options)
        self.name = name

    def __str__(self): return self.name

    def __del__(self):
        if self.name:
            try:
                self.tk.call('image', 'delete', self.name)
            except TclError:
                # May happen if the root was destroyed
                pass

    def __setitem__(self, key, value):
        self.tk.call(self.name, 'configure', '-'+key, value)

    def __getitem__(self, key):
        return self.tk.call(self.name, 'configure', '-'+key)

    def configure(self, **kw):
        """Configure the image."""
        res = ()
        for k, v in _cnfmerge(kw).items():
            if v is not None:
                if k[-1] == '_': k = k[:-1]
                if callable(v):
                    v = self._register(v)
                res = res + ('-'+k, v)
        self.tk.call((self.name, 'config') + res)

    config = configure

    def height(self):
        """Return the height of the image."""
        return self.tk.getint(
            self.tk.call('image', 'height', self.name))

    def type(self):
        """Return the type of the image, e.g. "photo" or "bitmap"."""
        return self.tk.call('image', 'type', self.name)

    def width(self):
        """Return the width of the image."""
        return self.tk.getint(
            self.tk.call('image', 'width', self.name))
Try removing from tkinter import * and using import tkinter as tk from now on.


RE: ImageTk Paste - KDog - Jun-01-2021

Hi Yoriz!
I tried the above and subsequently had to add tk. before various objects such as
Canvas
and
Button
Still getting the same error:
Error:
/home/kieran/PycharmProjects/Kamera/venv/bin/python /home/kieran/PycharmProjects/Kamera/Kamera.py Exception in Tkinter callback Traceback (most recent call last): File "/usr/lib/python3.8/tkinter/__init__.py", line 1892, in __call__ return self.func(*args) File "/home/kieran/PycharmProjects/Kamera/Kamera.py", line 80, in snapshot self.photo.paste(self.overlay_img, (0, 0)) File "/home/kieran/PycharmProjects/Kamera/venv/lib/python3.8/site-packages/PIL/ImageTk.py", line 165, in paste im.load() AttributeError: 'PhotoImage' object has no attribute 'load' Process finished with exit code 0
Could this be a potential answer (which I don't fully understand): https://stackoverflow.com/questions/40137813/attributeerror-when-creating-tkinter-photoimage-object-with-pil-imagetk

My current code:
import tkinter as tk
import cv2
from PIL import Image, ImageTk, ImageEnhance
import time
from tkinter import filedialog
import numpy as np


class App:
    def __init__(self, video_source=0):
        self.overlay_img = None
        self.appName = "Kamera"
        self.window = tk.Tk()
        self.window.title(self.appName)
        self.window.resizable(0, 0)
        # self.window.wm_iconbitmap("cam.ico")
        self.window['bg'] = 'black'
        self.video_source = video_source

        self.vid = MyVideoCapture(self.video_source)
        # self.label = Label(self.window, text=self.appName, font=15, bg='blue', fg='white').pack(side=TOP, fill=BOTH)
        self.canvas = tk.Canvas(self.window, width=self.vid.width, height=self.vid.height, bg='red')
        self.canvas.pack()

        self.btn_snapshot = tk.Button(self.window, text="Snapshot", width=5, command=self.snapshot)
        self.btn_snapshot.pack(side=tk.LEFT, padx=10)

        self.btn_overlay = tk.Button(self.window, text="Overlay", width=7, command=self.overlay)
        self.btn_overlay.pack(side=tk.LEFT, padx=10)

        self.btn_settings = tk.Button(self.window, text="Settings", width=5, command=self.settings)
        self.btn_settings.pack(side=tk.LEFT, padx=10)

        self.slide_value = 200
        self.update()
        self.window.mainloop()

    def settings(self):
        self.newWindow = Toplevel(self.window)
        self.newWindow.title("Settings")
        self.newWindow.geometry("400x400")
        self.btn_flip = Button(self.newWindow, text="Mirror Image", width=10, command=self.flip_img)
        self.btn_flip.pack(side=LEFT, padx=10)
            # self.brightness_lbl = Label(self.newWindow, text="Image Brightness")
            # self.brightness_lbl.pack(anchor=NW)
        #var = IntVar()
        self.brightness = Scale(
        self.newWindow, length=200, from_=0, to=255, orient=HORIZONTAL, label="Image Brightness",
                command=self.slide)
        self.brightness.set(200)
        self.brightness.pack(anchor=NW)

    def slide(self, var):
        self.slide_value = self.brightness.get()
        print(self.slide_value)

    def flip_img(self):
        self.vid.flipped = not self.vid.flipped

    def overlay(self):
        file = filedialog.askopenfile(
            mode='rb', defaultextension='.png',title="Choose Overlay Image", filetypes=[("PNG Files", '*.png')])
        if file:
            self.overlay_img = ImageTk.PhotoImage(file=file)

    def snapshot(self):
        isTrue, frame = self.vid.getFrame()

        if isTrue:
            filename = filedialog.asksaveasfilename(
                defaultextension='.jpg', title="Choose Filename", filetypes=[("JPEG Files", '*.jpg')])
            # image = "IMG-" + time.strftime("%H-%M-%S-%d-%m") + ".jpg"
            cv2.imwrite(filename, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
            # msg = Label(self.window, text='Image Saved' + image, bg='black', fg='green').place(x=430, y=510)

        else:
            messagebox.showerror("paint says", "unable to save image ,\n something went wrong")

        if isTrue and self.overlay_img:
            self.photo.paste(self.overlay_img, (0, 0))
            self.stamped_img = ImageTk.PhotoImage(self.photo)
            filename = filedialog.asksaveasfilename(
            defaultextension='.jpg', title="Choose Filename", filetypes=[("JPEG Files", '*.jpg')])
            filename = self.stamped_img

    def update(self):
        isTrue, frame = self.vid.getFrame()
        frame = cv2.normalize(frame, frame, 0, self.slide_value, cv2.NORM_MINMAX)

        if isTrue:
            self.photo = ImageTk.PhotoImage(image=Image.fromarray(frame))
            #self.canvas.tag_lower(self.photo)
            self.canvas.create_image(0, 0, image=self.photo, anchor=tk.NW)

        if self.overlay_img:
            #self.canvas.tag_raise(self.overlay_img)
            self.canvas.create_image(0,0, image=self.overlay_img, anchor=tk.NW)
            #self.stamped_img = self.photo.paste(self.overlay_img)
        self.window.after(100, self.update)


class MyVideoCapture:
    def __init__(self, video_source=0):
        self.vid = cv2.VideoCapture(video_source)
        if not self.vid.isOpened():
            raise ValueError("Unable to open this camera \n select another video source", video_source)

        self.width = self.vid.get(cv2.CAP_PROP_FRAME_WIDTH)
        self.height = self.vid.get(cv2.CAP_PROP_FRAME_HEIGHT)

        self.flipped = True

    def getFrame(self):
        if self.vid.isOpened():
            isTrue, frame = self.vid.read()
            if isTrue and self.flipped:
                frame = cv2.flip(frame, 1)
            if isTrue:
                return (isTrue, cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
            else:
                return (isTrue, None)
        else:
            return (isTrue, None)

    def __del__(self):
        if self.vid.isOpened():
            self.vid.release()


if __name__ == "__main__":
    App()



RE: ImageTk Paste - Yoriz - Jun-01-2021

O Wall I thought that was going to fix it but it's good that you got rid of the * imports Big Grin

self.overlay_img = ImageTk.PhotoImage(file=file)
self.overlay_img is a Tkinter-compatible photo image

self.photo = ImageTk.PhotoImage(image=Image.fromarray(frame))
self.photo is also a Tkinter-compatible photo image

When calling paste I think the passed in image has to be an actual PIL image.
self.photo.paste(self.overlay_img, (0, 0))

as self.overlay_img is used in the update method You probably need to keep self.overlay_img as it is
    def update(self):
        ...
        ...
        if self.overlay_img:
            #self.canvas.tag_raise(self.overlay_img)
            self.canvas.create_image(0,0, image=self.overlay_img, anchor=NW)


Here is what I hope will fix it Pray

When you make self.overlay_img try also making a pill image
    def overlay(self):
        file = filedialog.askopenfile(
            mode='rb', defaultextension='.png',title="Choose Overlay Image", filetypes=[("PNG Files", '*.png')])
        if file:
            self.overlay_img = ImageTk.PhotoImage(file=file)
            self.pil_overlay_img = Image.open(file)
Then change
if isTrue and self.overlay_img:
    self.photo.paste(self.overlay_img, (0, 0))
to
if isTrue and self.pil_overlay_img:
    self.photo.paste(self.pil_overlay_img, (0, 0))



RE: ImageTk Paste - deanhystad - Jun-01-2021

This is from the documentation for PIL ImageTk module.

https://pillow.readthedocs.io/en/stable/reference/ImageTk.html

Quote:paste(im, box=None)[source]
Paste a PIL image into the photo image. Note that this can be very slow if the photo image is displayed.

Parameters
im – A PIL image. The size must match the target region. If the mode does not match, the image is converted to the mode of the bitmap image.

box – A 4-tuple defining the left, upper, right, and lower pixel coordinate. See Coordinate System. If None is given instead of a tuple, all of the image is assumed.

Notice that im is a PIL image, not an ImageTk.PhotoImage. You need to load your overlay using
Quote:PIL.Image.open(fp, mode='r', formats=None)



RE: ImageTk Paste - KDog - Jun-02-2021

Lesson learned on imports Smile

Unfortunately neither of the above work. I don't get an error but the image saves without the overlay on it.


RE: ImageTk Paste - Yoriz - Jun-02-2021

The error is gone, that's progress Wink
Try it with both images being pillow images
Paste another image into an image with Python, Pillow