본문 바로가기
아래아한글 자동화/python+hwp 중급

[QnA] (5/5) 특정단어를 포함한 문단을 표로 감싸기-최종

by 일코 2022. 9. 19.
안녕하세요.
한글 자동화 프로그램을 공부하고 있는데 궁금한 사항이 있어 질문합니다.

<질문>

특정 글자가 들어가 있는 문단을 찾아서 그 곳에 글뒤로 속성으로 표를 삽입하고 싶습니다.
1. 자동으로 표 생성시 속성을 "본문과의배치"에서 "글뒤로" 선택하여 생성할 수 있나요?
이 속성없이 생성시 문단에 삽입되면서 글자가 밀려나는 현상이 발생합니다.

2. 찾은 문단의 위치값을 HWPUNIT 값으로 알 수 있나요?
표 생성시 위치값은 HWPUNIT으로 지정해야 하는데 현재 찾은 위치의 속성은 줄,칸으로 알려주네요.
이상입니다.

자, 이전포스팅까지의 내용을 통해

드디어 모든 재료가 완성되었습니다.

 

2022.09.19 - [업무자동화/파이썬-아래아한글 자동화 응용] - [QnA] (2/?) 표 생성하고, 수정하기

 

[QnA] (2/?) 표 생성하고, 수정하기

안녕하세요. 한글 자동화 프로그램을 공부하고 있는데 궁금한 사항이 있어 질문합니다. <질문> 특정 글자가 들어가 있는 문단을 찾아서 그 곳에 글뒤로 속성으로 표를 삽입하고 싶습니다. 1. 자

martinii.fun

2022.09.19 - [업무자동화/파이썬-아래아한글 자동화 응용] - [QnA] (3/?) 문단의 높이(HwpUnit) 구하기

 

[QnA] (3/?) 문단의 높이(HwpUnit) 구하기

안녕하세요. 한글 자동화 프로그램을 공부하고 있는데 궁금한 사항이 있어 질문합니다. <질문> 특정 글자가 들어가 있는 문단을 찾아서 그 곳에 글뒤로 속성으로 표를 삽입하고 싶습니다. 1. 자

martinii.fun

2022.09.19 - [업무자동화/파이썬-아래아한글 자동화 응용] - [QnA] (4/?) 특정 단어를 포함한 문단 검색하기

 

[QnA] (4/?) 특정 단어를 포함한 문단 검색하기

안녕하세요. 한글 자동화 프로그램을 공부하고 있는데 궁금한 사항이 있어 질문합니다. <질문> 특정 글자가 들어가 있는 문단을 찾아서 그 곳에 글뒤로 속성으로 표를 삽입하고 싶습니다. 1. 자

martinii.fun

 

이제 이들을 조립해서 최종 프로그램을 완성해봅시다.

완성된 코드를 실행하면 아래 영상과 같은 작업이 자동화됩니다.

특정 단어를 검색해서 해당 단어가 포함된 문단을 1x1의 표로 감싸는 작업입니다.

한 마디로 표를 글자 밑에 깔게 됩니다. 표 안에 문단을 잘라넣는 게 아니고요.

이 방법의 장점은 표 안의 텍스트 및 전체 구조가 틀어지지 않는다는 것입니다.

(표 밖의 여러 줄 텍스트를 표 안에 넣은 후 자간조정작업을 해 보신 분들, 그 번거로움 아시죠?)

 

검색어가 포함된 모든 문단이 표로 감싸졌습니다.

 

최종 파이썬 코드는 아래와 같습니다.

(셀에 음영을 랜덤하게 넣는 함수를 만들어 넣어보았습니다. 실제로는 이렇게 쓰이지 않겠지요.)

import os
import win32com.client as win32
import random


hwp = win32.gencache.EnsureDispatch("hwpframe.hwpobject")
hwp.XHwpWindows.Item(0).Visible = True
hwp.RegisterModule("FilePathCheckDLL", "FilePathCheckerModule")
hwp.Open(os.path.join(os.getcwd(), "20220919_원하는위치에표생성", "예시문서#한줄.hwp"))


def 표_생성(width_mm, height_mm):
    width_mm -= 3.6  # 표의 안 여백(1.8mm * 2)을 빼줘야 여백을 넘지 않음
    hwp.HAction.GetDefault("TableCreate", hwp.HParameterSet.HTableCreation.HSet)
    hwp.HParameterSet.HTableCreation.Rows = 1
    hwp.HParameterSet.HTableCreation.Cols = 1
    hwp.HParameterSet.HTableCreation.WidthType = 2
    hwp.HParameterSet.HTableCreation.HeightType = 1
    hwp.HParameterSet.HTableCreation.WidthValue = hwp.MiliToHwpUnit(width_mm)
    hwp.HParameterSet.HTableCreation.HeightValue = hwp.MiliToHwpUnit(height_mm)
    hwp.HParameterSet.HTableCreation.CreateItemArray("ColWidth", 1)
    hwp.HParameterSet.HTableCreation.ColWidth.SetItem(0, hwp.MiliToHwpUnit(width_mm))
    hwp.HParameterSet.HTableCreation.CreateItemArray("RowHeight", 1)
    hwp.HParameterSet.HTableCreation.RowHeight.SetItem(0, hwp.MiliToHwpUnit(height_mm))
    hwp.HParameterSet.HTableCreation.TableProperties.TreatAsChar = 0  # 글자처럼 취급안함
    hwp.HParameterSet.HTableCreation.TableProperties.Width = hwp.MiliToHwpUnit(width_mm)
    hwp.HAction.Execute("TableCreate", hwp.HParameterSet.HTableCreation.HSet)
    try:
        hwp.HAction.GetDefault("TablePropertyDialog", hwp.HParameterSet.HShapeObject.HSet)
        hwp.HParameterSet.HShapeObject.TextWrap = hwp.TextWrapType("BehindText")
        hwp.HParameterSet.HShapeObject.HSet.SetItem("ShapeType", 6)
        hwp.HAction.Execute("TablePropertyDialog", hwp.HParameterSet.HShapeObject.HSet)
    except:
        pass
    try:
        hwp.HAction.GetDefault("TablePropertyDialog", hwp.HParameterSet.HShapeObject.HSet)
        hwp.HParameterSet.HShapeObject.OutsideMarginBottom = hwp.MiliToHwpUnit(0.0)
        hwp.HParameterSet.HShapeObject.OutsideMarginTop = hwp.MiliToHwpUnit(0.0)
        hwp.HParameterSet.HShapeObject.OutsideMarginRight = hwp.MiliToHwpUnit(0.0)
        hwp.HParameterSet.HShapeObject.OutsideMarginLeft = hwp.MiliToHwpUnit(0.0)
        hwp.HParameterSet.HShapeObject.HSet.SetItem("ShapeType", 6)
        hwp.HParameterSet.HShapeObject.VertOffset = hwp.MiliToHwpUnit(0.0)
        hwp.HAction.Execute("TablePropertyDialog", hwp.HParameterSet.HShapeObject.HSet)
    except:
        pass


def 줄바꿈_지우기():
    hwp.HAction.Run("CloseEx")
    hwp.HAction.Run("DeleteBack")
    hwp.HAction.Run("Delete")
    hwp.FindCtrl()
    try:
        hwp.HAction.GetDefault("TablePropertyDialog", hwp.HParameterSet.HShapeObject.HSet)
        hwp.HParameterSet.HShapeObject.VertOffset = hwp.MiliToHwpUnit(0.0)
        hwp.HAction.Execute("TablePropertyDialog", hwp.HParameterSet.HShapeObject.HSet)
    except:
        pass


def 줄수계산():
    hwp.Run("MoveParaBegin")
    시작위치 = hwp.GetPos()
    줄수 = 1
    while True:
        직전위치 = hwp.GetPos()
        hwp.HAction.Run("MoveDown")
        현재위치 = hwp.GetPos()
        if 현재위치[1] != 시작위치[1]:
            hwp.HAction.Run("MoveUp")
            hwp.Run("MoveParaBegin")
            break
        elif 현재위치 == 직전위치:
            hwp.Run("MoveParaBegin")
            break
        else:
            줄수 += 1
    return 줄수


def 문단높이():
    줄수 = 줄수계산()
    글자크기 = hwp.CharShape.Item("Height")  # HU
    줄간격 = hwp.ParaShape.Item("LineSpacing")  # %
    문단높이 = 글자크기 * (줄간격 * 줄수 - 30) / 100
    return int(문단높이 / 283.465)  # HwpUnit to mm


def 문단너비():
    Act = hwp.CreateAction("PageSetup")
    Set = Act.CreateSet()
    Act.GetDefault(Set)
    용지너비 = Set.Item("PageDef").Item("PaperWidth")  # HwpUnit
    왼쪽여백 = Set.Item("PageDef").Item("LeftMargin")
    오른쪽여백 = Set.Item("PageDef").Item("RightMargin")
    문단너비 = 용지너비 - 왼쪽여백 - 오른쪽여백
    return int(문단너비 / 283.465)  # HwpUnit to mm


def 찾기(단어):
    hwp.HAction.GetDefault("RepeatFind", hwp.HParameterSet.HFindReplace.HSet)
    hwp.HParameterSet.HFindReplace.FindString = 단어
    hwp.HParameterSet.HFindReplace.Direction = hwp.FindDir("Forward")
    hwp.HParameterSet.HFindReplace.IgnoreMessage = 1
    hwp.HParameterSet.HFindReplace.FindType = 1
    return hwp.HAction.Execute("RepeatFind", hwp.HParameterSet.HFindReplace.HSet)


def 음영넣기():
    hwp.HAction.Run("TableCellBlock")
    hwp.HAction.GetDefault("CellFill", hwp.HParameterSet.HCellBorderFill.HSet)
    hwp.HParameterSet.HCellBorderFill.FillAttr.type = hwp.BrushType("NullBrush|WinBrush")
    hwp.HParameterSet.HCellBorderFill.FillAttr.WinBrushFaceColor = hwp.RGBColor(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
    hwp.HParameterSet.HCellBorderFill.FillAttr.WinBrushHatchColor = hwp.RGBColor(153, 153, 153)
    hwp.HParameterSet.HCellBorderFill.FillAttr.WinBrushFaceStyle = hwp.HatchStyle("None")
    hwp.HParameterSet.HCellBorderFill.FillAttr.WindowsBrush = 1
    hwp.HAction.Execute("CellFill", hwp.HParameterSet.HCellBorderFill.HSet)
    hwp.HAction.Run("Cancel")

if __name__ == '__main__':
    단어 = "줄"
    문단리스트 = []
    while True:
        if 찾기(단어):
            문단리스트.append(hwp.GetPos()[:2])
        else:
            break
    문단리스트 = sorted(list(set(문단리스트)), reverse=True)

    for i in 문단리스트:
        hwp.SetPos(*i, 0)
        표_생성(width_mm=문단너비(), height_mm=문단높이())
        음영넣기()
        줄바꿈_지우기()

위 코드 전체를 실행해보면

보기 좋게 잘 실행되네요.

 

마지막으로 이 예제를 직접 실행해보고 싶은 분을 위해

제가 사용한 hwp파일을 첨부해놓습니다.

코드는 포스팅에서 복사하셔서 파일 경로만 수정하시면 됩니다.

예시문서#한줄.hwp
0.02MB

포스팅을 마치며

개인적으로는 이 질문글을 읽으면서

"글자모양이나 메모도 있는데, 굳이 이런 방법을?" 하고 생각할 만큼, 생소하고 창의적인 아이디어였습니다.

그런데 구현해보고 나니 "이렇게 강조하는 방법도 유용하겠구나!" 라는 생각이 들 만큼 유익한 도전이었습니다.

 

이 코드의 아쉬운 점을 조금 나열해보면,

① 문단 중간에 표나 그림 등 개체가 삽입되어 있는 경우, 개체 위까지만 한 문단으로 인식합니다. 어쩔 수 없나;;

② 줄간격과 글자크기 외에도 분명히 문단높이에 영향을 주는 인자들이 있을텐데, 적용해보지 못했습니다.

③ 한 문단이 두 페이지에 걸쳐 있는 경우, 페이지 사이에 불가피하게 생기는 여백 때문에 작은 오차가 발생합니다.

④ 한/글의 문제일 수 있지만, 어떤 액션은 필수파라미터가 빠졌을 때 오류를 뱉는데, 그런 해결이 쉽지 않네요.

등등..입니다.

 

이번 시리즈는 여기서 마칩니다.

긴 글 읽어주셔서 감사합니다.

행복한 하루 되세요!

앞으로도 도움이 되는 콘텐츠를 만들어 가겠습니다.

 

댓글