  
          Parameters
          ----------
          thumbnail_size: int
              The size of the thumbnail that the placeholder should replicate
          """
          logger.debug("Creating placeholder. thumbnail_size: %s", thumbnail_size)
          placeholder = Image.new("RGB", (thumbnail_size, thumbnail_size))
          draw = ImageDraw.Draw(placeholder)
          draw.rectangle(((0, 0), (thumbnail_size, thumbnail_size)), outline="#E5E5E5", width=1)
 
</s> remove         asamples = np.array(samples)
        if not np.any(asamples):
            logger.debug("No preview images collected.")
            return False

        self._previewcache["filenames"] = (cast(List[str], self._previewcache["filenames"]) +
                                           filenames)[-num_images:]
        cache = cast(Optional[np.ndarray], self._previewcache["images"])
        if cache is None:
            logger.debug("Creating new cache")
            cache = asamples[-num_images:]
        else:
            logger.debug("Appending to existing cache")
            cache = np.concatenate((cache, asamples))[-num_images:]
        self._previewcache["images"] = cache
        logger.debug("Cache shape: %s", cast(np.ndarray, self._previewcache["images"]).shape)
        return True
 </s> add         logger.debug("Creating placeholder. thumbnail_size: %s", thumbnail_size)
        placeholder = Image.new("RGB", (thumbnail_size, thumbnail_size))
        draw = ImageDraw.Draw(placeholder)
        draw.rectangle(((0, 0), (thumbnail_size, thumbnail_size)), outline="#E5E5E5", width=1)
        placeholder = np.array(placeholder)
        self._placeholder = placeholder
        logger.debug("Created placeholder. shape: %s", placeholder.shape) </s> remove     def _pad_and_border(self, image: Image.Image, size: int) -> np.ndarray:
        """ Pad rectangle images to a square and draw borders

        Parameters
        ----------
        image: :class:`PIL.Image`
            The image to process
        size: int
            The size of the image as it should be displayed

        Returns
        -------
        :class:`PIL.Image`:
            The processed image
        """
        if image.size[0] != image.size[1]:
            # Pad to square
            new_img = Image.new("RGB", (size, size))
            new_img.paste(image, ((size - image.size[0]) // 2, (size - image.size[1]) // 2))
            image = new_img
        draw = ImageDraw.Draw(image)
        draw.rectangle(((0, 0), (size, size)), outline="#E5E5E5", width=1)
        retval = np.array(image)
        logger.trace("image shape: %s", retval.shape)  # type: ignore
        return retval

    def _process_samples(self,
                         samples: List[np.ndarray],
                         filenames: List[str],
                         num_images: int) -> bool:
        """ Process the latest sample images into a displayable image.
 </s> add     def _create_placeholder(self, thumbnail_size: int) -> None:
        """ Create a placeholder image for when there are fewer thumbnails available
        than columns to display them. </s> remove     def load_training_preview(self) -> None:
        """ Load the training preview images.
 </s> add  </s> remove         logger.trace("Displaying preview")  # type:ignore
        sortednames = sorted(list(get_images().previewtrain.keys()))
        existing = self.subnotebook_get_titles_ids()
        should_update = self.update_preview.get()

        for name in sortednames:
            if name not in existing:
                self.add_child(name)
            elif should_update:
                tab_id = existing[name]
                self.update_child(tab_id, name)

        if should_update:
            self.update_preview.set(False)

    def add_child(self, name: str) -> None:
        """ Add the preview canvas child

        Parameters
        ----------
        name: str
            The name of the notebook tab to add
        """
        logger.debug("Adding child")
        preview = PreviewTrainCanvas(self.subnotebook, name)
        preview = self.subnotebook_add_page(name, widget=preview)
        Tooltip(preview, text=self.helptext, wrap_length=200)
        self.vars["modified"].set(get_images().previewtrain[name][2])

    def update_child(self, tab_id: int, name: str) -> None:
        """ Update the preview canvas
 </s> add         if self.subnotebook.children:
            return </s> remove         Parameters
        ----------
        name: str
            The name of the training image to be resized
        frame_dims: tuple, optional
            The (width (`int`), height (`int`)) of the display panel that will display the preview.
            ``None`` if the frame dimensions are not known.
 </s> add         Should be called when terminating tasks, or when Faceswap starts up or shuts down.
            The size of each thumbnail that should be created
        frame_dims: tuple
            The (width (`int`), height (`int`)) of the display panel that will display the preview

        Returns
        -------
        bool
            ``True`` if a preview was succesfully loaded otherwise ``False``
  
          Parameters
          ----------
          thumbnail_size: int
            The size of each thumbnail that should be created
        frame_dims: tuple
            The (width (`int`), height (`int`)) of the display panel that will display the preview

        Returns
        -------
        bool
            ``True`` if a preview was succesfully loaded otherwise ``False``
          """
          logger.debug("Creating placeholder. thumbnail_size: %s", thumbnail_size)
          placeholder = Image.new("RGB", (thumbnail_size, thumbnail_size))
          draw = ImageDraw.Draw(placeholder)
          draw.rectangle(((0, 0), (thumbnail_size, thumbnail_size)), outline="#E5E5E5", width=1)
keep keep keep keep replace keep keep keep keep keep
 GUI - Preview updates
  - Training preview. Embed preview pop-out window
  - Bugfix - convert/extract previews 
lib/gui/utils/image.py