|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+from openpyxl import load_workbook, Workbook
|
|
|
2
|
+from datetime import datetime
|
|
|
3
|
+from openpyxl.drawing.image import Image
|
|
|
4
|
+import re
|
|
|
5
|
+
|
|
|
6
|
+from openpyxl.drawing.spreadsheet_drawing import AbsoluteAnchor
|
|
|
7
|
+from openpyxl.drawing.xdr import XDRPoint2D, XDRPositiveSize2D
|
|
|
8
|
+from openpyxl.utils.units import pixels_to_EMU
|
|
|
9
|
+from openpyxl.utils import get_column_letter
|
|
|
10
|
+
|
|
|
11
|
+def center_image_in_cell(ws, cell_address, img_path):
|
|
|
12
|
+ """
|
|
|
13
|
+ Center an image in a specific cell.
|
|
|
14
|
+
|
|
|
15
|
+ Args:
|
|
|
16
|
+ ws: The worksheet object.
|
|
|
17
|
+ cell_address (str): The cell address (e.g., "B2") where the image will be centered.
|
|
|
18
|
+ img_path (str): Path to the image file.
|
|
|
19
|
+
|
|
|
20
|
+ Returns:
|
|
|
21
|
+ None
|
|
|
22
|
+ """
|
|
|
23
|
+ # Load the image
|
|
|
24
|
+ img = Image(img_path)
|
|
|
25
|
+ img.width = img.height = 20
|
|
|
26
|
+
|
|
|
27
|
+ # Get the cell
|
|
|
28
|
+ cell = ws[cell_address]
|
|
|
29
|
+
|
|
|
30
|
+ # Approximate pixel dimensions of the cell
|
|
|
31
|
+ col_letter = get_column_letter(cell.column)
|
|
|
32
|
+ col_width = ws.column_dimensions[col_letter].width or 10 # Default width
|
|
|
33
|
+ row_height = ws.row_dimensions[cell.row].height or 15 # Default height
|
|
|
34
|
+
|
|
|
35
|
+ # Convert dimensions to pixels
|
|
|
36
|
+ col_width_pixels = col_width * 7 # Approximation: 1 Excel unit = ~7 pixels
|
|
|
37
|
+ row_height_pixels = row_height * 0.75 # Approximation: 1 Excel unit = ~0.75 pixels
|
|
|
38
|
+
|
|
|
39
|
+ # Calculate the center position
|
|
|
40
|
+ cell_left = pixels_to_EMU(cell.column - 1) # Column start position in EMU
|
|
|
41
|
+ cell_top = pixels_to_EMU((cell.row - 1) * row_height_pixels) # Row start position in EMU
|
|
|
42
|
+ x_center = cell_left + pixels_to_EMU((col_width_pixels - img.width) / 2)
|
|
|
43
|
+ y_center = cell_top + pixels_to_EMU((row_height_pixels - img.height) / 2)
|
|
|
44
|
+
|
|
|
45
|
+ # Set the image position and size
|
|
|
46
|
+ position = XDRPoint2D(x_center, y_center)
|
|
|
47
|
+ size = XDRPositiveSize2D(pixels_to_EMU(img.width), pixels_to_EMU(img.height))
|
|
|
48
|
+ img.anchor = AbsoluteAnchor(pos=position, ext=size)
|
|
|
49
|
+
|
|
|
50
|
+ # Add the image to the worksheet
|
|
|
51
|
+ ws.add_image(img)
|
|
|
52
|
+
|
|
|
53
|
+
|
|
|
54
|
+def gen_xlsx4(template_file, selected_sheets, prefix_filename, data):
|
|
|
55
|
+ """
|
|
|
56
|
+ Generate an Excel file from a template, fill placeholders, and include only selected sheets.
|
|
|
57
|
+
|
|
|
58
|
+ Args:
|
|
|
59
|
+ template_file (str): Path to the Excel template file.
|
|
|
60
|
+ selected_sheets (list): List of sheet names to include in the output file.
|
|
|
61
|
+ prefix_filename (str): Prefix for the output filename.
|
|
|
62
|
+ data (dict): Data dictionary with sheet-specific keys and fallback keys.
|
|
|
63
|
+
|
|
|
64
|
+ Returns:
|
|
|
65
|
+ str: Path of the generated Excel file.
|
|
|
66
|
+ """
|
|
|
67
|
+ checked_image_path = "./checkbox_checked.jpg" # Path to the checked checkbox image
|
|
|
68
|
+ unchecked_image_path = "./checkbox_unchecked.jpg" # Path to the unchecked checkbox image
|
|
|
69
|
+
|
|
|
70
|
+ # Load the template workbook
|
|
|
71
|
+ workbook = load_workbook(template_file)
|
|
|
72
|
+
|
|
|
73
|
+ # Remove sheets not in selected_sheets
|
|
|
74
|
+ for sheet_name in workbook.sheetnames:
|
|
|
75
|
+ if sheet_name not in selected_sheets:
|
|
|
76
|
+ del workbook[sheet_name]
|
|
|
77
|
+
|
|
|
78
|
+ # Process the selected sheets
|
|
|
79
|
+ for sheet_name in selected_sheets:
|
|
|
80
|
+ if sheet_name not in workbook.sheetnames:
|
|
|
81
|
+ raise ValueError(f"Sheet '{sheet_name}' not found in the template.")
|
|
|
82
|
+
|
|
|
83
|
+ sheet = workbook[sheet_name]
|
|
|
84
|
+
|
|
|
85
|
+ # Replace placeholders with actual values
|
|
|
86
|
+ # Handle hiding rows based on patterns in data
|
|
|
87
|
+
|
|
|
88
|
+ for row in sheet.iter_rows():
|
|
|
89
|
+ for cell in row:
|
|
|
90
|
+ if cell.value and isinstance(cell.value, str) and cell.value.startswith("<") and cell.value.endswith(">"):
|
|
|
91
|
+ placeholder = cell.value.strip("<>")
|
|
|
92
|
+
|
|
|
93
|
+ # Determine value priority: `sheet_name.key` > `key`
|
|
|
94
|
+ value = None
|
|
|
95
|
+ sheet_specific_key = f"{sheet_name}.{placeholder}"
|
|
|
96
|
+ if sheet_specific_key in data:
|
|
|
97
|
+ value = data[sheet_specific_key]
|
|
|
98
|
+ elif placeholder in data:
|
|
|
99
|
+ value = data[placeholder]
|
|
|
100
|
+
|
|
|
101
|
+ if value is not None:
|
|
|
102
|
+ if value is True:
|
|
|
103
|
+ img = Image(checked_image_path)
|
|
|
104
|
+ img.width = img.height = 20
|
|
|
105
|
+ print(f"{cell.coordinate}")
|
|
|
106
|
+ sheet.add_image(img, cell.coordinate)
|
|
|
107
|
+ cell.value = None # Remove the placeholder text
|
|
|
108
|
+ elif value is False:
|
|
|
109
|
+ img = Image(unchecked_image_path)
|
|
|
110
|
+ img.width = img.height = 20
|
|
|
111
|
+ sheet.add_image(img, cell.coordinate)
|
|
|
112
|
+ # center_image_in_cell(sheet, cell.coordinate, unchecked_image_path)
|
|
|
113
|
+ cell.value = None # Remove the placeholder text
|
|
|
114
|
+ else:
|
|
|
115
|
+ # Insert the text value directly
|
|
|
116
|
+ cell.value = value
|
|
|
117
|
+
|
|
|
118
|
+ for key, value in data.items():
|
|
|
119
|
+ if isinstance(value, str) and re.match(r"^\d+\[\d+:\d+\]$", value):
|
|
|
120
|
+ # Parse the prefix and row range
|
|
|
121
|
+ prefix, row_range = value.split("[")
|
|
|
122
|
+ row_start, row_end = map(int, row_range[:-1].split(":"))
|
|
|
123
|
+
|
|
|
124
|
+ # Hide rows if the prefix matches the condition
|
|
|
125
|
+ if prefix == "0": # Adjust the condition as needed
|
|
|
126
|
+ sheet.row_dimensions.group(row_start, row_end, hidden=True)
|
|
|
127
|
+
|
|
|
128
|
+
|
|
|
129
|
+ # Generate the output filename with a timestamp
|
|
|
130
|
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
|
131
|
+ output_path = f"{prefix_filename}_{timestamp}.xlsx"
|
|
|
132
|
+ workbook.save(output_path)
|
|
|
133
|
+
|
|
|
134
|
+ return output_path
|
|
|
135
|
+
|
|
|
136
|
+if __name__ == "__main__":
|
|
|
137
|
+ # Example usage
|
|
|
138
|
+ data = {
|
|
|
139
|
+ "customer": "Tum Coder",
|
|
|
140
|
+ "inspect_date": "2025-01-15",
|
|
|
141
|
+ "lot_no": "12345",
|
|
|
142
|
+ "size": "Large",
|
|
|
143
|
+ "pcs": "10 pcs",
|
|
|
144
|
+ "spec": "Spec-A",
|
|
|
145
|
+ "hardness.d1_act": "10",
|
|
|
146
|
+ "hardness.d2_act": "0[24:28]", # Hide rows 24 to 28 if the prefix is "0"
|
|
|
147
|
+ "hardness.acc": True, # Hide rows 24 to 28 if the prefix is "0"
|
|
|
148
|
+ "hardness.spe_acc": False, # Hide rows 24 to 28 if the prefix is "0"
|
|
|
149
|
+ "dimension_app.d1_act": "33",
|
|
|
150
|
+ "dimension_app.d2_act": "0[26:32]", # Hide rows 24 to 28 if the prefix is "0"
|
|
|
151
|
+ "dimension_app.acc": True, # Hide rows 24 to 28 if the prefix is "0"
|
|
|
152
|
+ "dimension_app.spe_acc": False, # Hide rows 24 to 28 if the prefix is "0"
|
|
|
153
|
+ }
|
|
|
154
|
+
|
|
|
155
|
+
|
|
|
156
|
+
|
|
|
157
|
+
|
|
|
158
|
+ output_file = gen_xlsx4(
|
|
|
159
|
+ template_file="./hardness.xlsx",
|
|
|
160
|
+ selected_sheets=["hardness", "dimension_app"], # Replace with your actual sheet names
|
|
|
161
|
+ prefix_filename="./output/output",
|
|
|
162
|
+ data=data
|
|
|
163
|
+ )
|
|
|
164
|
+
|
|
|
165
|
+ print(f"Generated file: {output_file}")
|