Coverage for thumbhash / decode.py: 9%

55 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-28 17:06 +0000

1from base64 import b64decode 

2 

3from PIL import Image 

4 

5from thumbhash.hash import Hash 

6 

7 

8def thumbhash_to_image( 

9 hash: bytes | str, base_size: int = 32, saturation_boost: float = 1.25 

10) -> Image.Image: 

11 hash = b64decode(hash) if isinstance(hash, str) else hash 

12 

13 width, height, rgba_data = thumbhash_to_rgba(hash, base_size, saturation_boost) 

14 

15 return Image.frombytes("RGBA", (width, height), bytes(rgba_data)) 

16 

17 

18def thumbhash_to_rgba( 

19 hash: bytes, base_size: int = 32, saturation_boost: float = 1.25 

20) -> tuple[int, int, list[int]]: 

21 hash_decoded = Hash.decode(hash, saturation_boost) 

22 

23 w, h = hash_decoded.size(base_size) 

24 

25 idx = 0 

26 data: list[int] = [0] * (w * h * 4) 

27 

28 for y in range(h): 

29 for x in range(w): 

30 fx, fy = hash_decoded.coefficients(x, y, w, h) 

31 

32 l = hash_decoded.l_dc # noqa: E741 

33 j = 0 

34 for cy in range(hash_decoded.ly): 

35 cx = 1 if cy == 0 else 0 

36 fy2 = fy[cy] * 2.0 

37 

38 while cx * hash_decoded.ly < hash_decoded.lx * (hash_decoded.ly - cy): 

39 l += hash_decoded.l_ac[j] * fx[cx] * fy2 # noqa: E741 

40 j += 1 

41 cx += 1 

42 

43 p = hash_decoded.p_dc 

44 q = hash_decoded.q_dc 

45 

46 j = 0 

47 for cy in range(3): 

48 cx = 1 if cy == 0 else 0 

49 fy2 = fy[cy] * 2.0 

50 

51 while cx < 3 - cy: 

52 f = fx[cx] * fy2 

53 p += hash_decoded.p_ac[j] * f 

54 q += hash_decoded.q_ac[j] * f 

55 j += 1 

56 cx += 1 

57 

58 a = hash_decoded.a_dc 

59 

60 if hash_decoded.has_alpha: 

61 j = 0 

62 for cy in range(5): 

63 cx = 1 if cy == 0 else 0 

64 fy2 = fy[cy] * 2.0 

65 

66 while cx < 5 - cy: 

67 a += hash_decoded.a_ac[j] * fx[cx] * fy2 

68 j += 1 

69 cx += 1 

70 

71 b = l - 2.0 / 3.0 * p 

72 r = (3.0 * l - b + q) / 2.0 

73 g = r - q 

74 

75 data[idx] = round(max(0.0, min(1.0, r) * 255.0)) 

76 data[idx + 1] = round(max(0.0, min(1.0, g) * 255.0)) 

77 data[idx + 2] = round(max(0.0, min(1.0, b) * 255.0)) 

78 data[idx + 3] = round(max(0.0, min(1.0, a) * 255.0)) 

79 

80 idx += 4 

81 

82 return w, h, data