Coverage for src/rtflite/figure.py: 97%

30 statements  

« prev     ^ index     » next       coverage.py v7.10.5, created at 2025-08-25 22:35 +0000

1"""RTF Figure handling utilities. 

2 

3This module provides functions for reading and processing images 

4for embedding in RTF documents. 

5""" 

6 

7import mimetypes 

8from collections.abc import Sequence 

9from pathlib import Path 

10 

11 

12def rtf_read_figure( 

13 file_paths: str | Path | Sequence[str | Path], 

14) -> tuple[Sequence[bytes], Sequence[str]]: 

15 """Read image files and return their binary data with format information. 

16 

17 This function reads image files from disk and prepares them for embedding 

18 in RTF documents. It supports PNG, JPEG, and EMF formats. 

19 

20 Args: 

21 file_paths: Single file path or list of file paths to image files 

22 

23 Returns: 

24 Tuple of (figure_data, figure_formats) where: 

25 - figure_data: List of image binary data as bytes 

26 - figure_formats: List of format strings ('png', 'jpeg', 'emf') 

27 

28 Raises: 

29 FileNotFoundError: If any image file cannot be found 

30 ValueError: If image format is not supported 

31 """ 

32 # Ensure file_paths is a list 

33 if isinstance(file_paths, (str, Path)): 

34 file_paths = [file_paths] 

35 

36 figure_data = [] 

37 figure_formats = [] 

38 

39 for file_path in file_paths: 

40 path = Path(file_path) 

41 

42 # Check if file exists 

43 if not path.exists(): 

44 raise FileNotFoundError(f"Image file not found: {file_path}") 

45 

46 # Determine format and read data 

47 img_format = _determine_image_format(path) 

48 data = _read_image_data(path) 

49 

50 figure_data.append(data) 

51 figure_formats.append(img_format) 

52 

53 return figure_data, figure_formats 

54 

55 

56def _determine_image_format(path: Path) -> str: 

57 """Determine image format from file extension or MIME type.""" 

58 extension = path.suffix.lower() 

59 format_map = {".png": "png", ".jpg": "jpeg", ".jpeg": "jpeg", ".emf": "emf"} 

60 

61 if extension in format_map: 

62 return format_map[extension] 

63 

64 # Fallback to MIME type detection 

65 mime_type, _ = mimetypes.guess_type(str(path)) 

66 mime_to_format = {"image/png": "png", "image/jpeg": "jpeg", "image/jpg": "jpeg"} 

67 

68 if mime_type in mime_to_format: 

69 return mime_to_format[mime_type] 

70 

71 raise ValueError( 

72 f"Unsupported image format: {extension}. Supported formats: PNG, JPEG, EMF" 

73 ) 

74 

75 

76def _read_image_data(path: Path) -> bytes: 

77 """Read binary data from image file.""" 

78 with open(path, "rb") as f: 

79 return f.read()