Coverage for pyguymer3/image/image2gif.py: 5%

22 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-08 18:47 +0000

1#!/usr/bin/env python3 

2 

3# Define function ... 

4def image2gif( 

5 img, 

6 gif, 

7 /, 

8 *, 

9 chunksize = 1048576, 

10 debug = __debug__, 

11 exiftoolPath = None, 

12 gifsiclePath = None, 

13 jpegtranPath = None, 

14 mode = "RGB", 

15 optimise = True, 

16 optipngPath = None, 

17 screenHeight = -1, 

18 screenWidth = -1, 

19 strip = False, 

20 timeout = 60.0, 

21): 

22 """Save an image as a GIF 

23 

24 This function accepts either a PIL Image or a file path and saves the image 

25 as a GIF. 

26 

27 Parameters 

28 ---------- 

29 img : PIL.Image.Image or str 

30 the input PIL Image or path to the input image 

31 gif : str 

32 the path to the output GIF 

33 chunksize : int, optional 

34 the size of the chunks of any files which are read in (in bytes) 

35 debug : bool, optional 

36 print debug messages (default False) 

37 exiftoolPath : str, optional 

38 the path to the "exiftool" binary (if not provided then Python will attempt to 

39 find the binary itself) 

40 gifsiclePath : str, optional 

41 the path to the "gifsicle" binary (if not provided then Python will attempt to 

42 find the binary itself) 

43 jpegtranPath : str, optional 

44 the path to the "jpegtran" binary (if not provided then Python will attempt to 

45 find the binary itself) 

46 mode : str, optional 

47 the mode of the outout GIF (default "RGB") 

48 optimise : bool, optional 

49 optimise the output GIF (default True) 

50 optipngPath : str, optional 

51 the path to the "optipng" binary (if not provided then Python will attempt to 

52 find the binary itself) 

53 screenHeight : int, optional 

54 the height of the screen to downscale the input image to fit within, 

55 currently only implemented if "img" is a str (default -1; integers less 

56 than 100 imply no downscaling) 

57 screenWidth : int, optional 

58 the width of the screen to downscale the input image to fit within, 

59 currently only implemented if "img" is a str (default -1; integers less 

60 than 100 imply no downscaling) 

61 strip : bool, optional 

62 strip metadata from the output GIF (default False) 

63 timeout : float, optional 

64 the timeout for any requests/subprocess calls 

65 

66 Notes 

67 ----- 

68 Copyright 2017 Thomas Guymer [1]_ 

69 

70 References 

71 ---------- 

72 .. [1] PyGuymer3, https://github.com/Guymer/PyGuymer3 

73 """ 

74 

75 # Import special modules ... 

76 try: 

77 import PIL 

78 import PIL.Image 

79 PIL.Image.MAX_IMAGE_PIXELS = 1024 * 1024 * 1024 # [px] 

80 except: 

81 raise Exception("\"PIL\" is not installed; run \"pip install --user Pillow\"") from None 

82 

83 # Import sub-functions ... 

84 from .optimise_image import optimise_image 

85 

86 # Find out what the user supplied ... 

87 match img: 

88 case str(): 

89 # Open image as RGB (even if it is paletted) ... 

90 with PIL.Image.open(img) as iObj: 

91 tmpImg = iObj.convert("RGB") 

92 

93 # Check if the user wants to scale the image down to fit within a 

94 # screen size ... 

95 if screenWidth >= 100 and screenHeight >= 100: 

96 # Resize image in place ... 

97 tmpImg.thumbnail( 

98 (screenWidth, screenHeight), 

99 resample = PIL.Image.Resampling.LANCZOS, 

100 ) 

101 

102 # Convert it to whatever mode the user asked for ... 

103 tmpImg = tmpImg.convert(mode) 

104 case PIL.Image.Image(): 

105 # Convert image to whatever mode the user asked for ... 

106 tmpImg = img.convert(mode) 

107 case _: 

108 # Crash ... 

109 raise TypeError(f"\"img\" is an unexpected type ({repr(type(img))})") from None 

110 

111 # Save it as a GIF ... 

112 # NOTE: See https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif 

113 tmpImg.save( 

114 gif, 

115 optimise = optimise, 

116 ) 

117 

118 # Optimise GIF ... 

119 if optimise or strip: 

120 optimise_image( 

121 gif, 

122 chunksize = chunksize, 

123 debug = debug, 

124 exiftoolPath = exiftoolPath, 

125 gifsiclePath = gifsiclePath, 

126 jpegtranPath = jpegtranPath, 

127 optipngPath = optipngPath, 

128 pool = None, 

129 strip = strip, 

130 timeout = timeout, 

131 )