          self._icons = self._load_icons()
          logger.debug("Initialized %s", self.__class__.__name__)
  
      @property
      def previewoutput(self) -> Tuple[Image.Image, ImageTk.PhotoImage]:
          """ Tuple: First item in the tuple is the extract or convert preview image
          (:class:`PIL.Image`), the second item is the image in a format that tkinter can display
          (:class:`PIL.ImageTK.PhotoImage`).
  
          The value of the property is ``None`` if no extract or convert task is running or there are
          no files available in the output folder. """
          assert self._previewoutput is not None
          return self._previewoutput
 
</s> remove     def __init__(self) -> None:
        logger.debug("Initializing %s", self.__class__.__name__)
        self._pathpreview = os.path.join(PATHCACHE, "preview")
        self._pathoutput: Optional[str] = None
        self._batch_mode = False
        self._previewoutput: Optional[Tuple[Image.Image, ImageTk.PhotoImage]] = None
        self._previewtrain: Dict[str, List[Union[Image.Image,
                                                 ImageTk.PhotoImage,
                                                 None,
                                                 float]]] = {}
        self._previewcache: Dict[str, Union[None, float, np.ndarray, List[str]]] = dict(
            modified=None,  # cache for extract and convert
            images=None,
            filenames=[],
            placeholder=None)
        self._errcount = 0
        self._icons = self._load_icons()
 </s> add     logger.debug("Getting images: '%s'", image_path)
    if not os.path.isdir(image_path):
        logger.debug("Folder does not exist")
        return []
    files = [os.path.join(image_path, f)
             for f in os.listdir(image_path) if f.lower().endswith((".png", ".jpg"))]
    logger.debug("Image files: %s", files)
    return files


class PreviewTrain():
    """ Handles the loading of the training preview image(s) and adding to the display buffer

    Parameters
    ----------
    cache_path: str
        Full path to the cache folder that contains the preview images
    """
    def __init__(self, cache_path: str) -> None:
        logger.debug("Initializing %s: (cache_path: '%s')", self.__class__.__name__, cache_path)
        self._buffer = PreviewBuffer()
        self._cache_path = cache_path
        self._modified: float = 0.0
        self._error_count: int = 0 </s> remove     @property
    def icons(self) -> Dict[str, ImageTk.PhotoImage]:
        """ dict: The faceswap icons for all parts of the GUI. The dictionary key is the icon
        name (`str`) the value is the icon sized and formatted for display
        (:class:`PIL.ImageTK.PhotoImage`).
 </s> add  </s> remove         self._pathoutput = location
 </s> add         self._output_path = location </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. </s> remove         size = get_config().user_config_dict.get("icon_size", 16)
        size = int(round(size * get_config().scaling_factor))
        icons: Dict[str, ImageTk.PhotoImage] = {}
        pathicons = os.path.join(PATHCACHE, "icons")
        for fname in os.listdir(pathicons):
            name, ext = os.path.splitext(fname)
            if ext != ".png":
                continue
            img = Image.open(os.path.join(pathicons, fname))
            img = ImageTk.PhotoImage(img.resize((size, size), resample=Image.HAMMING))
            icons[name] = img
        logger.debug(icons)
        return icons
 </s> add         logger.debug("Saving preview to %s", filename)
        assert self._preview_image is not None
        self._preview_image.save(filename)
    def buffer(self) -> PreviewBuffer:
        """ :class:`~lib.training.PreviewBuffer` The preview buffer for the training preview
        image. """
        return self._buffer

    def load(self) -> bool:
        """ Load the latest training preview image(s) from disk and add to :attr:`buffer` """
        logger.trace("Loading Training preview images")  # type:ignore
        image_files = _get_previews(self._cache_path)
        filename = next((fname for fname in image_files
                         if os.path.basename(fname) == TRAININGPREVIEW), "")
        if not filename:
            logger.trace("No preview to display")  # type:ignore
            return False
        try:
            modified = os.path.getmtime(filename)
            if modified <= self._modified:
                logger.trace("preview '%s' not updated. Current timestamp: %s, "  # type:ignore
                             "existing timestamp: %s", filename, modified, self._modified)
                return False

            logger.debug("Loading preview: '%s'", filename)
            img = cv2.imread(filename, cv2.IMREAD_UNCHANGED)
            self._modified = modified
            self._buffer.add_image(os.path.basename(filename), img)
            self._error_count = 0
        except ValueError:
            # This is probably an error reading the file whilst it's being saved so ignore it
            # for now and only pick up if there have been multiple consecutive fails
            logger.warning("Unable to display preview: (image: '%s', attempt: %s)",
                           img, self._error_count)
            if self._error_count < 10:
                self._error_count += 1
            else:
                logger.error("Error reading the preview file for '%s'", filename)
            return False
          self._icons = self._load_icons()
          logger.debug("Initialized %s", self.__class__.__name__)
  
      @property
    def buffer(self) -> PreviewBuffer:
        """ :class:`~lib.training.PreviewBuffer` The preview buffer for the training preview
        image. """
        return self._buffer

    def load(self) -> bool:
        """ Load the latest training preview image(s) from disk and add to :attr:`buffer` """
        logger.trace("Loading Training preview images")  # type:ignore
        image_files = _get_previews(self._cache_path)
        filename = next((fname for fname in image_files
                         if os.path.basename(fname) == TRAININGPREVIEW), "")
        if not filename:
            logger.trace("No preview to display")  # type:ignore
            return False
        try:
            modified = os.path.getmtime(filename)
            if modified <= self._modified:
                logger.trace("preview '%s' not updated. Current timestamp: %s, "  # type:ignore
                             "existing timestamp: %s", filename, modified, self._modified)
                return False

            logger.debug("Loading preview: '%s'", filename)
            img = cv2.imread(filename, cv2.IMREAD_UNCHANGED)
            self._modified = modified
            self._buffer.add_image(os.path.basename(filename), img)
            self._error_count = 0
        except ValueError:
            # This is probably an error reading the file whilst it's being saved so ignore it
            # for now and only pick up if there have been multiple consecutive fails
            logger.warning("Unable to display preview: (image: '%s', attempt: %s)",
                           img, self._error_count)
            if self._error_count < 10:
                self._error_count += 1
            else:
                logger.error("Error reading the preview file for '%s'", filename)
            return False
    def buffer(self) -> PreviewBuffer:
        """ :class:`~lib.training.PreviewBuffer` The preview buffer for the training preview
        image. """
        return self._buffer

    def load(self) -> bool:
        """ Load the latest training preview image(s) from disk and add to :attr:`buffer` """
        logger.trace("Loading Training preview images")  # type:ignore
        image_files = _get_previews(self._cache_path)
        filename = next((fname for fname in image_files
                         if os.path.basename(fname) == TRAININGPREVIEW), "")
        if not filename:
            logger.trace("No preview to display")  # type:ignore
            return False
        try:
            modified = os.path.getmtime(filename)
            if modified <= self._modified:
                logger.trace("preview '%s' not updated. Current timestamp: %s, "  # type:ignore
                             "existing timestamp: %s", filename, modified, self._modified)
                return False

            logger.debug("Loading preview: '%s'", filename)
            img = cv2.imread(filename, cv2.IMREAD_UNCHANGED)
            self._modified = modified
            self._buffer.add_image(os.path.basename(filename), img)
            self._error_count = 0
        except ValueError:
            # This is probably an error reading the file whilst it's being saved so ignore it
            # for now and only pick up if there have been multiple consecutive fails
            logger.warning("Unable to display preview: (image: '%s', attempt: %s)",
                           img, self._error_count)
            if self._error_count < 10:
                self._error_count += 1
            else:
                logger.error("Error reading the preview file for '%s'", filename)
            return False
    def buffer(self) -> PreviewBuffer:
        """ :class:`~lib.training.PreviewBuffer` The preview buffer for the training preview
        image. """
        return self._buffer

    def load(self) -> bool:
        """ Load the latest training preview image(s) from disk and add to :attr:`buffer` """
        logger.trace("Loading Training preview images")  # type:ignore
        image_files = _get_previews(self._cache_path)
        filename = next((fname for fname in image_files
                         if os.path.basename(fname) == TRAININGPREVIEW), "")
        if not filename:
            logger.trace("No preview to display")  # type:ignore
            return False
        try:
            modified = os.path.getmtime(filename)
            if modified <= self._modified:
                logger.trace("preview '%s' not updated. Current timestamp: %s, "  # type:ignore
                             "existing timestamp: %s", filename, modified, self._modified)
                return False

            logger.debug("Loading preview: '%s'", filename)
            img = cv2.imread(filename, cv2.IMREAD_UNCHANGED)
            self._modified = modified
            self._buffer.add_image(os.path.basename(filename), img)
            self._error_count = 0
        except ValueError:
            # This is probably an error reading the file whilst it's being saved so ignore it
            # for now and only pick up if there have been multiple consecutive fails
            logger.warning("Unable to display preview: (image: '%s', attempt: %s)",
                           img, self._error_count)
            if self._error_count < 10:
                self._error_count += 1
            else:
                logger.error("Error reading the preview file for '%s'", filename)
            return False
    def buffer(self) -> PreviewBuffer:
        """ :class:`~lib.training.PreviewBuffer` The preview buffer for the training preview
        image. """
        return self._buffer

    def load(self) -> bool:
        """ Load the latest training preview image(s) from disk and add to :attr:`buffer` """
        logger.trace("Loading Training preview images")  # type:ignore
        image_files = _get_previews(self._cache_path)
        filename = next((fname for fname in image_files
                         if os.path.basename(fname) == TRAININGPREVIEW), "")
        if not filename:
            logger.trace("No preview to display")  # type:ignore
            return False
        try:
            modified = os.path.getmtime(filename)
            if modified <= self._modified:
                logger.trace("preview '%s' not updated. Current timestamp: %s, "  # type:ignore
                             "existing timestamp: %s", filename, modified, self._modified)
                return False

            logger.debug("Loading preview: '%s'", filename)
            img = cv2.imread(filename, cv2.IMREAD_UNCHANGED)
            self._modified = modified
            self._buffer.add_image(os.path.basename(filename), img)
            self._error_count = 0
        except ValueError:
            # This is probably an error reading the file whilst it's being saved so ignore it
            # for now and only pick up if there have been multiple consecutive fails
            logger.warning("Unable to display preview: (image: '%s', attempt: %s)",
                           img, self._error_count)
            if self._error_count < 10:
                self._error_count += 1
            else:
                logger.error("Error reading the preview file for '%s'", filename)
            return False
  
          The value of the property is ``None`` if no extract or convert task is running or there are
          no files available in the output folder. """
          assert self._previewoutput is not None
          return self._previewoutput
keep keep keep keep replace replace replace 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