Upload hwp_style_mapping.py
This commit is contained in:
417
03.Code/업로드용/converters/hwp_style_mapping.py
Normal file
417
03.Code/업로드용/converters/hwp_style_mapping.py
Normal file
@@ -0,0 +1,417 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
HWP ㅽ 紐 v2.0
|
||||||
|
HTML (Role) HWP ㅽ
|
||||||
|
|
||||||
|
|
||||||
|
v2.0 蹂寃쎌ы:
|
||||||
|
- pyhwpx API apply_to_hwp()
|
||||||
|
|
||||||
|
- CharShape/ParaShape 吏
|
||||||
|
ㅼ 諛⑹ 媛 ㅽ
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Dict, Optional
|
||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class HwpStyleType(Enum):
|
||||||
|
"""HWP ㅽ """
|
||||||
|
PARAGRAPH = "paragraph"
|
||||||
|
CHARACTER = "character"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class HwpStyle:
|
||||||
|
"""HWP ㅽ
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# 湲곕낯 ㅽ
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
DEFAULT_STYLES: Dict[str, HwpStyle] = {
|
||||||
|
# 吏
|
||||||
|
"COVER_TITLE": HwpStyle(
|
||||||
|
id=100, name="吏紐", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=32, font_bold=True, align="center",
|
||||||
|
space_before=20, space_after=10, font_color="1a365d"
|
||||||
|
),
|
||||||
|
"COVER_SUBTITLE": HwpStyle(
|
||||||
|
id=101, name="吏遺", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=18, font_bold=False, align="center",
|
||||||
|
font_color="555555"
|
||||||
|
),
|
||||||
|
"COVER_INFO": HwpStyle(
|
||||||
|
id=102, name="吏 蹂", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=12, align="center", font_color="666666"
|
||||||
|
),
|
||||||
|
|
||||||
|
# 紐⑹감
|
||||||
|
"TOC_H1": HwpStyle(
|
||||||
|
id=110, name="紐⑹감1", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=12, font_bold=True, indent_left=0
|
||||||
|
),
|
||||||
|
"TOC_H2": HwpStyle(
|
||||||
|
id=111, name="紐⑹감2", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=11, indent_left=20
|
||||||
|
),
|
||||||
|
"TOC_H3": HwpStyle(
|
||||||
|
id=112, name="紐⑹감3", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=10, indent_left=40, font_color="666666"
|
||||||
|
),
|
||||||
|
|
||||||
|
# 紐
|
||||||
|
痢 (媛 1~7 留ㅽ)
|
||||||
|
"H1": HwpStyle(
|
||||||
|
id=1, name="媛 1", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=20, font_bold=True, align="left",
|
||||||
|
space_before=30, space_after=15, font_color="1a365d"
|
||||||
|
),
|
||||||
|
"H2": HwpStyle(
|
||||||
|
id=2, name="媛 2", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=16, font_bold=True, align="left",
|
||||||
|
space_before=20, space_after=10, font_color="2c5282"
|
||||||
|
),
|
||||||
|
"H3": HwpStyle(
|
||||||
|
id=3, name="媛 3", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=14, font_bold=True, align="left",
|
||||||
|
space_before=15, space_after=8, font_color="2b6cb0"
|
||||||
|
),
|
||||||
|
"H4": HwpStyle(
|
||||||
|
id=4, name="媛 4", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=12, font_bold=True, align="left",
|
||||||
|
space_before=10, space_after=5, indent_left=10
|
||||||
|
),
|
||||||
|
"H5": HwpStyle(
|
||||||
|
id=5, name="媛 5", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=11, font_bold=True, align="left",
|
||||||
|
space_before=8, space_after=4, indent_left=20
|
||||||
|
),
|
||||||
|
"H6": HwpStyle(
|
||||||
|
id=6, name="媛 6", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=11, font_bold=False, align="left",
|
||||||
|
indent_left=30
|
||||||
|
),
|
||||||
|
"H7": HwpStyle(
|
||||||
|
id=7, name="媛 7", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=10.5, font_bold=False, align="left",
|
||||||
|
indent_left=40
|
||||||
|
),
|
||||||
|
|
||||||
|
# 蹂몃Ц
|
||||||
|
"BODY": HwpStyle(
|
||||||
|
id=20, name="諛湲", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=11, align="justify",
|
||||||
|
line_spacing=180, indent_first=10
|
||||||
|
),
|
||||||
|
"LIST_ITEM": HwpStyle(
|
||||||
|
id=8, name="媛 8", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=11, align="left",
|
||||||
|
indent_left=15, line_spacing=160
|
||||||
|
),
|
||||||
|
"HIGHLIGHT_BOX": HwpStyle(
|
||||||
|
id=21, name="媛議ꕕ", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=10.5, align="left",
|
||||||
|
bg_color="f7fafc", indent_left=10, indent_first=0
|
||||||
|
),
|
||||||
|
|
||||||
|
#
|
||||||
|
"TABLE": HwpStyle(
|
||||||
|
id=30, name=" ", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=10, align="center"
|
||||||
|
),
|
||||||
|
"TH": HwpStyle(
|
||||||
|
id=11, name="紐", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=10, font_bold=True, align="center",
|
||||||
|
bg_color="e2e8f0"
|
||||||
|
),
|
||||||
|
"TD": HwpStyle(
|
||||||
|
id=31, name=" 댁 ", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=10, align="left"
|
||||||
|
),
|
||||||
|
"TABLE_CAPTION": HwpStyle(
|
||||||
|
id=19, name=" 罹
|
||||||
|
몃┝
|
||||||
|
"FIGURE": HwpStyle(
|
||||||
|
id=32, name="洹몃┝", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=10, align="center"
|
||||||
|
),
|
||||||
|
"FIGURE_CAPTION": HwpStyle(
|
||||||
|
id=18, name="洹몃┝罹
|
||||||
|
고
|
||||||
|
"UNKNOWN": HwpStyle(
|
||||||
|
id=0, name="諛湲", type=HwpStyleType.PARAGRAPH,
|
||||||
|
font_size=10, align="left"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
# 媛 踰 留㼼 (StyleShortcut )
|
||||||
|
ROLE_TO_OUTLINE_NUM = {
|
||||||
|
"H1": 1,
|
||||||
|
"H2": 2,
|
||||||
|
"H3": 3,
|
||||||
|
"H4": 4,
|
||||||
|
"H5": 5,
|
||||||
|
"H6": 6,
|
||||||
|
"H7": 7,
|
||||||
|
"LIST_ITEM": 8,
|
||||||
|
"BODY": 0, # 諛湲
|
||||||
|
"COVER_TITLE": 0,
|
||||||
|
"COVER_SUBTITLE": 0,
|
||||||
|
"COVER_INFO": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
# HWP ㅽ
|
||||||
|
留㼼
|
||||||
|
ROLE_TO_STYLE_NAME = {
|
||||||
|
"H1": "媛 1",
|
||||||
|
"H2": "媛 2",
|
||||||
|
"H3": "媛 3",
|
||||||
|
"H4": "媛 4",
|
||||||
|
"H5": "媛 5",
|
||||||
|
"H6": "媛 6",
|
||||||
|
"H7": "媛 7",
|
||||||
|
"LIST_ITEM": "媛 8",
|
||||||
|
"BODY": "諛湲",
|
||||||
|
"COVER_TITLE": "吏紐",
|
||||||
|
"COVER_SUBTITLE": "吏遺",
|
||||||
|
"TH": "紐",
|
||||||
|
"TD": " 댁 ",
|
||||||
|
"TABLE_CAPTION": " 罹
|
||||||
|
몃┝罹
|
||||||
|
湲",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class HwpStyleMapper:
|
||||||
|
"""HTML HWP ㅽ """
|
||||||
|
|
||||||
|
def __init__(self, custom_styles: Optional[Dict[str, HwpStyle]] = None):
|
||||||
|
self.styles = DEFAULT_STYLES.copy()
|
||||||
|
if custom_styles:
|
||||||
|
self.styles.update(custom_styles)
|
||||||
|
|
||||||
|
def get_style(self, role: str) -> HwpStyle:
|
||||||
|
return self.styles.get(role, self.styles["UNKNOWN"])
|
||||||
|
|
||||||
|
def get_style_id(self, role: str) -> int:
|
||||||
|
return self.get_style(role).id
|
||||||
|
|
||||||
|
def get_all_styles(self) -> Dict[str, HwpStyle]:
|
||||||
|
return self.styles
|
||||||
|
|
||||||
|
|
||||||
|
class HwpStyGenerator:
|
||||||
|
"""
|
||||||
|
HTML ㅽ HWP ㅽ⑷린
|
||||||
|
|
||||||
|
pyhwpx API瑜 ъ :
|
||||||
|
1. 蹂
|
||||||
|
ㅽ蹂
|
||||||
|
2.
|
||||||
|
ㅽ 쎌
|
||||||
|
CharShape/ParaShape 吏
|
||||||
|
3. 媛 ㅽ 留㼼 諛
|
||||||
|
異異 ㅽ
|
||||||
|
곗 """
|
||||||
|
for role, style_dict in html_styles.items():
|
||||||
|
if role in DEFAULT_STYLES:
|
||||||
|
base = DEFAULT_STYLES[role]
|
||||||
|
|
||||||
|
# color 泥 - # 嫄
|
||||||
|
color = style_dict.get('color', base.font_color)
|
||||||
|
if isinstance(color, str):
|
||||||
|
color = color.lstrip('#')
|
||||||
|
|
||||||
|
self.styles[role] = HwpStyle(
|
||||||
|
id=base.id,
|
||||||
|
name=base.name,
|
||||||
|
type=base.type,
|
||||||
|
font_size=style_dict.get('font_size', base.font_size),
|
||||||
|
font_bold=style_dict.get('bold', base.font_bold),
|
||||||
|
font_color=color,
|
||||||
|
align=style_dict.get('align', base.align),
|
||||||
|
line_spacing=style_dict.get('line_spacing', base.line_spacing),
|
||||||
|
space_before=style_dict.get('space_before', base.space_before),
|
||||||
|
space_after=style_dict.get('space_after', base.space_after),
|
||||||
|
indent_left=style_dict.get('indent_left', base.indent_left),
|
||||||
|
indent_first=style_dict.get('indent_first', base.indent_first),
|
||||||
|
bg_color=style_dict.get('bg_color', base.bg_color),
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# 湲곕낯 ㅽ ъ
|
||||||
|
self.styles[role] = DEFAULT_STYLES.get('UNKNOWN')
|
||||||
|
|
||||||
|
#
|
||||||
|
대 湲곕낯媛쇰 梨
|
||||||
|
|
||||||
|
for role in DEFAULT_STYLES:
|
||||||
|
if role not in self.styles:
|
||||||
|
self.styles[role] = DEFAULT_STYLES[role]
|
||||||
|
|
||||||
|
def apply_to_hwp(self, hwp) -> Dict[str, HwpStyle]:
|
||||||
|
""" HwpStyle 留㼼 諛 ㅽ
|
||||||
|
鍮
|
||||||
|
|
||||||
|
깊 (API 臾몄 )
|
||||||
|
# for role, style in self.styles.items():
|
||||||
|
# self._create_or_update_style(hwp, role, style)
|
||||||
|
|
||||||
|
if not self.styles:
|
||||||
|
self.styles = DEFAULT_STYLES.copy()
|
||||||
|
|
||||||
|
print(f"
|
||||||
|
ㅽ
|
||||||
|
猷: {len(self.styles)}媛")
|
||||||
|
return self.styles
|
||||||
|
|
||||||
|
def _create_or_update_style(self, hwp, role: str, style: HwpStyle):
|
||||||
|
"""HWP ㅽ
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# 1. ㅽ 紐⑤
|
||||||
|
hwp.HAction.GetDefault("ModifyStyle", hwp.HParameterSet.HStyle.HSet)
|
||||||
|
hwp.HParameterSet.HStyle.StyleName = style.name
|
||||||
|
|
||||||
|
# 2. 湲 ⑥
|
||||||
|
color_hex = style.font_color.lstrip('#')
|
||||||
|
if len(color_hex) == 6:
|
||||||
|
r, g, b = int(color_hex[0:2], 16), int(color_hex[2:4], 16), int(color_hex[4:6], 16)
|
||||||
|
text_color = hwp.RGBColor(r, g, b)
|
||||||
|
else:
|
||||||
|
text_color = hwp.RGBColor(0, 0, 0)
|
||||||
|
|
||||||
|
hwp.HParameterSet.HStyle.CharShape.Height = hwp.PointToHwpUnit(style.font_size)
|
||||||
|
hwp.HParameterSet.HStyle.CharShape.Bold = style.font_bold
|
||||||
|
hwp.HParameterSet.HStyle.CharShape.TextColor = text_color
|
||||||
|
|
||||||
|
# 3. 臾몃 紐⑥
|
||||||
|
align_map = {'left': 0, 'center': 1, 'right': 2, 'justify': 3}
|
||||||
|
hwp.HParameterSet.HStyle.ParaShape.Align = align_map.get(style.align, 3)
|
||||||
|
hwp.HParameterSet.HStyle.ParaShape.LineSpacing = int(style.line_spacing)
|
||||||
|
hwp.HParameterSet.HStyle.ParaShape.SpaceBeforePara = hwp.PointToHwpUnit(style.space_before)
|
||||||
|
hwp.HParameterSet.HStyle.ParaShape.SpaceAfterPara = hwp.PointToHwpUnit(style.space_after)
|
||||||
|
|
||||||
|
# 4. ㅽ
|
||||||
|
hwp.HAction.Execute("ModifyStyle", hwp.HParameterSet.HStyle.HSet)
|
||||||
|
print(f" ㅽ ")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f" [寃쎄 ] ㅽ
|
||||||
|
ㅽ : {e}")
|
||||||
|
|
||||||
|
def get_style(self, role: str) -> HwpStyle:
|
||||||
|
"""대 ㅽ
|
||||||
|
|
||||||
|
⑥ """
|
||||||
|
style = self.get_style(role)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# RGB 蹂 ⑥
|
||||||
|
ㅼ
|
||||||
|
hwp.HAction.GetDefault("CharShape", hwp.HParameterSet.HCharShape.HSet)
|
||||||
|
hwp.HParameterSet.HCharShape.Height = hwp.PointToHwpUnit(style.font_size)
|
||||||
|
hwp.HParameterSet.HCharShape.Bold = style.font_bold
|
||||||
|
hwp.HParameterSet.HCharShape.TextColor = text_color
|
||||||
|
hwp.HAction.Execute("CharShape", hwp.HParameterSet.HCharShape.HSet)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f" [寃쎄 ] 湲 ⑥ ㅽ ({role}): {e}")
|
||||||
|
|
||||||
|
def apply_para_shape(self, hwp, role: str):
|
||||||
|
"""
|
||||||
|
臾몃 紐⑥ """
|
||||||
|
style = self.get_style(role)
|
||||||
|
|
||||||
|
try:
|
||||||
|
#
|
||||||
|
align_actions = {
|
||||||
|
'left': "ParagraphShapeAlignLeft",
|
||||||
|
'center': "ParagraphShapeAlignCenter",
|
||||||
|
'right': "ParagraphShapeAlignRight",
|
||||||
|
'justify': "ParagraphShapeAlignJustify"
|
||||||
|
}
|
||||||
|
if style.align in align_actions:
|
||||||
|
hwp.HAction.Run(align_actions[style.align])
|
||||||
|
|
||||||
|
# 臾몃 紐⑥
|
||||||
|
|
||||||
|
ㅼ
|
||||||
|
hwp.HAction.GetDefault("ParagraphShape", hwp.HParameterSet.HParaShape.HSet)
|
||||||
|
p = hwp.HParameterSet.HParaShape
|
||||||
|
p.LineSpaceType = 0 # 쇱
|
||||||
|
쇳
|
||||||
|
p.LineSpacing = int(style.line_spacing)
|
||||||
|
p.LeftMargin = hwp.MiliToHwpUnit(style.indent_left)
|
||||||
|
p.IndentMargin = hwp.MiliToHwpUnit(style.indent_first)
|
||||||
|
p.SpaceBeforePara = hwp.PointToHwpUnit(style.space_before)
|
||||||
|
p.SpaceAfterPara = hwp.PointToHwpUnit(style.space_after)
|
||||||
|
hwp.HAction.Execute("ParagraphShape", p.HSet)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f" [寃쎄 ] 臾몃 紐⑥ ㅽ ({role}): {e}")
|
||||||
|
|
||||||
|
def apply_style(self, hwp, role: str):
|
||||||
|
"""
|
||||||
|
泥 ㅽ (湲몃 )"""
|
||||||
|
self.apply_char_shape(hwp, role)
|
||||||
|
self.apply_para_shape(hwp, role)
|
||||||
|
|
||||||
|
def export_sty(self, hwp, output_path: str) -> bool:
|
||||||
|
"""ㅽ대낫닿린 (
|
||||||
|
誘몄由] .sty 대낫닿린
|
||||||
|
誘몄 嫄 대━
|
||||||
|
# =============================================================================
|
||||||
|
import re
|
||||||
|
|
||||||
|
NUMBERING_PATTERNS = {
|
||||||
|
'H1': re.compile(r'^(\d+)\.\s*'), # "1. " 嫄
|
||||||
|
'H2': re.compile(r'^(\d+)\.(\d+)\s*'), # "1.1 " 嫄
|
||||||
|
'H3': re.compile(r'^(\d+)\.(\d+)\.(\d+)\s*'), # "1.1.1 " 嫄
|
||||||
|
'H4': re.compile(r'^[媛- . " 嫄
|
||||||
|
'H5': re.compile(r'^(\d+)\)\s*'), # "1) " 嫄
|
||||||
|
'H6': re.compile(r'^\((\d+)\)\s*'), # "(1) " 嫄
|
||||||
|
'H7': re.compile(r'^[△™bㅲβ╈㎮ⓥ]\s*'), # " " 嫄
|
||||||
|
'LIST_ITEM': re.compile(r'^[\-]\s*'), # " " 嫄
|
||||||
|
}
|
||||||
|
|
||||||
|
def strip_numbering(text: str, role: str) -> str:
|
||||||
|
"""
|
||||||
|
곕
|
||||||
|
ㅽ /湲고 嫄
|
||||||
|
HWP 媛 湲곕μ
|
||||||
|
깊濡 以蹂 諛⑹
|
||||||
|
"""
|
||||||
|
if not text:
|
||||||
|
return text
|
||||||
|
|
||||||
|
pattern = NUMBERING_PATTERNS.get(role)
|
||||||
|
if pattern:
|
||||||
|
return pattern.sub('', text).strip()
|
||||||
|
|
||||||
|
return text.strip()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
#
|
||||||
|
ㅽ
|
||||||
|
print("=== ㅽ
|
||||||
|
ㅽ ===")
|
||||||
|
|
||||||
|
gen = HwpStyGenerator()
|
||||||
|
|
||||||
|
# HTML ㅽ裕щ
|
||||||
|
size={style.font_size}pt, bold={style.font_bold}, color=#{style.font_color}")
|
||||||
Reference in New Issue
Block a user