icon.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. #-----------------------------------------------------------------------------
  2. # Copyright (c) 2022, PyInstaller Development Team.
  3. #
  4. # Distributed under the terms of the GNU General Public License (version 2
  5. # or later) with exception for distributing the bootloader.
  6. #
  7. # The full license is in the file COPYING.txt, distributed with this software.
  8. #
  9. # SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
  10. #-----------------------------------------------------------------------------
  11. from typing import Tuple
  12. import os
  13. import hashlib
  14. def normalize_icon_type(icon_path: str, allowed_types: Tuple[str], convert_type: str, workpath: str) -> str:
  15. """
  16. Returns a valid icon path or raises an Exception on error.
  17. Ensures that the icon exists, and, if necessary, attempts to convert it to correct OS-specific format using Pillow.
  18. Takes:
  19. icon_path - the icon given by the user
  20. allowed_types - a tuple of icon formats that should be allowed through
  21. EX: ("ico", "exe")
  22. convert_type - the type to attempt conversion too if necessary
  23. EX: "icns"
  24. workpath - the temp directory to save any newly generated image files
  25. """
  26. # explicitly error if file not found
  27. if not os.path.exists(icon_path):
  28. raise FileNotFoundError(f"Icon input file {icon_path} not found")
  29. _, extension = os.path.splitext(icon_path)
  30. extension = extension[1:] # get rid of the "." in ".whatever"
  31. # if the file is already in the right format, pass it back unchanged
  32. if extension in allowed_types:
  33. return icon_path
  34. # The icon type is wrong! Let's try and import PIL
  35. try:
  36. from PIL import Image as PILImage
  37. import PIL
  38. except ImportError:
  39. raise ValueError(
  40. f"Received icon image '{icon_path}' which exists but is not in the correct format. On this platform, "
  41. f"only {allowed_types} images may be used as icons. If Pillow is installed, automatic conversion will "
  42. f"be attempted. Please install Pillow or convert your '{extension}' file to one of {allowed_types} "
  43. f"and try again."
  44. )
  45. # Let's try to use PIL to convert the icon file type
  46. try:
  47. _generated_name = f"generated-{hashlib.sha256(icon_path.encode()).hexdigest()}.{convert_type}"
  48. generated_icon = os.path.join(workpath, _generated_name)
  49. with PILImage.open(icon_path) as im:
  50. im.save(generated_icon)
  51. icon_path = generated_icon
  52. except PIL.UnidentifiedImageError:
  53. raise ValueError(
  54. f"Something went wrong converting icon image '{icon_path}' to '.{convert_type}' with Pillow, "
  55. f"perhaps the image format is unsupported. Try again with a different file or use a file that can "
  56. f"be used without conversion on this platform: {allowed_types}"
  57. )
  58. return icon_path