diff --git a/03.Code/업로드용/converters/hwpx_table_injector.py b/03.Code/업로드용/converters/hwpx_table_injector.py
new file mode 100644
index 0000000..2f29dca
--- /dev/null
+++ b/03.Code/업로드용/converters/hwpx_table_injector.py
@@ -0,0 +1,191 @@
+# -*- coding: utf-8 -*-
+"""
+HWPX
+ 鍮
+ 湲 v2
+
+import zipfile
+import rePX
+from pathlib import Path
+import tempfile 鍮
+import shutil
+"""
+# mm HWPML 蹂 283.46 HWPML units)
+MM_TO_HWPML = 7200 / 25.4 # 283.46
+
+def inject_table_widths(hwpx_path: str, table_widths_list: list):
+ """
+ HWPX
+ 鍮
+
+
+ Args:
+ hwpx_path: HWPX
+ table_widths_list: [[w1, w2, w3], [w1, w2], ...] (mm
+ )
+ """
+ if not table_widths_list:
+ print(" [INFO] ")
+ return
+
+ print(f"
+ 鍮
+ ... ({len(table_widths_list)}媛 )")
+
+ # HWPX 異 댁
+ temp_dir = Path(tempfile.mkdtemp(prefix="hwpx_table_"))
+
+ with zipfile.ZipFile(hwpx_path, 'r') as zf:
+ zf.extractall(temp_dir)
+
+ # section*.xml ㅼ
+ 李얘린
+ contents_dir = temp_dir / "Contents"
+
+ table_idx = 0
+ total_modified = 0
+
+ for section_file in sorted(contents_dir.glob("section*.xml")):
+ with open(section_file, 'r', encoding='utf-8') as f:
+ content = f.read()
+
+ original_content = content
+
+ # 紐⑤ (...) 李얘린
+ tbl_pattern = re.compile(r'(]*>)(.*?)()', re.DOTALL)
+
+ def process_table(match):
+ nonlocal table_idx, total_modified
+
+ if table_idx >= len(table_widths_list):
+ return match.group(0)
+
+ tbl_open = match.group(1)
+ tbl_content = match.group(2)
+ tbl_close = match.group(3)
+
+ col_widths_mm = table_widths_list[table_idx]
+ col_widths_hwpml = [int(w * MM_TO_HWPML) for w in col_widths_mm]
+
+ #
+ 泥
+ 鍮
+ (hp:sz width="...")
+ total_width = int(sum(col_widths_mm) * MM_TO_HWPML)
+ tbl_content = re.sub(
+ r'(= len(col_widths_hwpml):
+ return tc_content
+
+ new_width = col_widths_hwpml[col_idx]
+
+ # cellSz width 援
+ tc_content = re.sub(
+ r'(... 釉濡
+ tbl_content = re.sub(
+ r']*>.*?',
+ replace_cell_width,
+ tbl_content,
+ flags=re.DOTALL
+ )
+
+ print(f"
+ # {table_idx + 1}: {col_widths_mm} mm HWPML ")
+ table_idx += 1
+ total_modified += 1
+
+ return tbl_open + tbl_content + tbl_close
+
+ # 泥
+ new_content = tbl_pattern.sub(process_table, content)
+
+ # 蹂寃쎌ы 쇰㈃
+ if new_content != original_content:
+ with open(section_file, 'w', encoding='utf-8') as f:
+ f.write(new_content)
+ print(f" {section_file.name} ")
+
+ # ㅼ 異
+ repack_hwpx(temp_dir, hwpx_path)
+
+ #
+ 대
+ shutil.rmtree(temp_dir)
+
+ print(f"
+ 珥
+ 鍮
+ 猷")
+
+
+def repack_hwpx(source_dir: Path, output_path: str):
+ """HWPX ㅼ 異"""
+ import os
+ import time
+
+ temp_output = output_path + ".tmp"
+
+ with zipfile.ZipFile(temp_output, 'w', zipfile.ZIP_DEFLATED) as zf:
+ # mimetype 異 吏몃
+ mimetype_path = source_dir / "mimetype"
+ if mimetype_path.exists():
+ zf.write(mimetype_path, "mimetype", compress_type=zipfile.ZIP_STORED)
+
+ # 몄
+ for root, dirs, files in os.walk(source_dir):
+ for file in files:
+ if file == "mimetype":
+ continue
+ file_path = Path(root) / file
+ arcname = file_path.relative_to(source_dir)
+ zf.write(file_path, arcname)
+
+ # 援
+ for attempt in range(3):
+ try:
+ if os.path.exists(output_path):
+ os.remove(output_path)
+ os.rename(temp_output, output_path)
+ break
+ except PermissionError:
+ time.sleep(0.5)
+
+
+#
+ㅽ몄
+if __name__ == "__main__":
+ test_widths = [
+ [18.2, 38.9, 42.8, 70.1],
+ [19.9, 79.6, 70.5],
+ [28.7, 81.4, 59.9],
+ [19.2, 61.4, 89.5],
+ ]
+
+ hwpx_path = r"C:\Users\User\AppData\Local\Temp\geulbeot_output.hwpx"
+ inject_table_widths(hwpx_path, test_widths)