Upload hwpx_table_injector.py
This commit is contained in:
191
03.Code/업로드용/converters/hwpx_table_injector.py
Normal file
191
03.Code/업로드용/converters/hwpx_table_injector.py
Normal file
@@ -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
|
||||||
|
|
||||||
|
# 紐⑤ (<hp:tbl>...</hp:tbl>) 李얘린
|
||||||
|
tbl_pattern = re.compile(r'(<hp:tbl\b[^>]*>)(.*?)(</hp:tbl>)', 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'(<hp:sz\s+width=")(\d+)(")',
|
||||||
|
lambda m: f'{m.group(1)}{total_width}{m.group(3)}',
|
||||||
|
tbl_content,
|
||||||
|
count=1
|
||||||
|
)
|
||||||
|
|
||||||
|
# 媛
|
||||||
|
# 諛⑸ : colAddr蹂
|
||||||
|
濡
|
||||||
|
鍮
|
||||||
|
留㼼
|
||||||
|
def replace_cell_width(tc_match):
|
||||||
|
tc_content = tc_match.group(0)
|
||||||
|
|
||||||
|
# colAddr 異異
|
||||||
|
col_addr_match = re.search(r'<hp:cellAddr\s+colAddr="(\d+)"', tc_content)
|
||||||
|
if not col_addr_match:
|
||||||
|
return tc_content
|
||||||
|
|
||||||
|
col_idx = int(col_addr_match.group(1))
|
||||||
|
if col_idx >= len(col_widths_hwpml):
|
||||||
|
return tc_content
|
||||||
|
|
||||||
|
new_width = col_widths_hwpml[col_idx]
|
||||||
|
|
||||||
|
# cellSz width 援
|
||||||
|
tc_content = re.sub(
|
||||||
|
r'(<hp:cellSz\s+width=")(\d+)(")',
|
||||||
|
lambda m: f'{m.group(1)}{new_width}{m.group(3)}',
|
||||||
|
tc_content
|
||||||
|
)
|
||||||
|
|
||||||
|
return tc_content
|
||||||
|
|
||||||
|
# 媛 <hp:tc>...</hp:tc> 釉濡
|
||||||
|
tbl_content = re.sub(
|
||||||
|
r'<hp:tc\b[^>]*>.*?</hp:tc>',
|
||||||
|
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)
|
||||||
Reference in New Issue
Block a user