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

25 statements  

« prev     ^ index     » next       coverage.py v7.10.3, created at 2025-08-16 08:31 +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 image to whatever mode the user asked for ... 

103 tmpImg = tmpImg.convert(mode) 

104 case PIL.Image.Image(): 

105 # Copy image as RGB (even if it is paletted) ... 

106 tmpImg = img.convert("RGB") 

107 

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

109 # screen size ... 

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

111 # Resize image in place ... 

112 tmpImg.thumbnail( 

113 (screenWidth, screenHeight), 

114 resample = PIL.Image.Resampling.LANCZOS, 

115 ) 

116 

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

118 tmpImg = tmpImg.convert(mode) 

119 case _: 

120 # Crash ... 

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

122 

123 # Save it as a GIF ... 

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

125 tmpImg.save( 

126 gif, 

127 optimise = optimise, 

128 ) 

129 

130 # Optimise GIF ... 

131 if optimise or strip: 

132 optimise_image( 

133 gif, 

134 chunksize = chunksize, 

135 debug = debug, 

136 exiftoolPath = exiftoolPath, 

137 gifsiclePath = gifsiclePath, 

138 jpegtranPath = jpegtranPath, 

139 optipngPath = optipngPath, 

140 pool = None, 

141 strip = strip, 

142 timeout = timeout, 

143 )