Python에서 프레젠테이션 주석 관리

개요

이 문서는 Aspose.Slides for Python via .NET을 사용하여 프레젠테이션 주석을 관리하는 방법을 설명합니다. 주요 주석 관련 타입을 소개하고 슬라이드에 주석을 추가하고, 기존 주석에 접근하고, 회신 및 최신 주석을 활용하며, 프레젠테이션에서 주석을 제거하는 방법을 보여줍니다.

예제는 PowerPoint에서 일반적인 검토 및 협업 시나리오를 다룹니다. 예를 들어 작성자에게 주석을 할당하고, 주석 텍스트 및 메타데이터를 읽고, 회신 체인을 구축하고, 선택된 주석 또는 모든 주석을 제거하는 방법 등을 포함합니다.

PowerPoint에서 주석은 슬라이드에 표시되는 주석(annotation) 형태로 나타납니다. 주석을 선택하면 해당 텍스트와 관련된 토론이 표시됩니다.

프레젠테이션을 열 때 주석을 변경하지 않고 주석을 표시하거나 숨기려면 프레젠테이션 열 때 주석 표시 또는 숨기기를 참조하세요.

프레젠테이션에 주석을 추가하는 이유는?

프레젠테이션을 검토할 때 피드백을 제공하고 동료와 협업하기 위해 주석을 사용할 수 있습니다.

Aspose.Slides for Python via .NET은 주석 작업을 위한 다음 API를 제공합니다:

  • The Presentation 클래스는 프레젠테이션의 주석 작성자에 대한 접근을 제공합니다.
  • The CommentCollection 클래스는 개별 작성자와 연관된 주석을 나타냅니다.
  • The Comment 클래스는 작성자, 생성 시간, 위치 및 텍스트 등을 포함한 주석 정보를 제공합니다.
  • The CommentAuthor 클래스는 이름, 이니셜 및 연관된 주석을 포함한 작성자 정보를 제공합니다.

슬라이드 주석 추가

다음 예제는 PowerPoint 프레젠테이션의 슬라이드에 주석을 추가하는 방법을 보여줍니다:

from datetime import datetime

import aspose.pydrawing as draw
import aspose.slides as slides

with slides.Presentation() as presentation:
    first_slide = presentation.slides[0]
    second_slide = presentation.slides.add_empty_slide(presentation.layout_slides[0])
    author = presentation.comment_authors.add_author("Jawad", "MF")
    position = draw.PointF(0.2, 0.2)
    created_time = datetime.now()

    author.comments.add_comment("Hello Jawad, this is a slide comment", first_slide, position, created_time)
    author.comments.add_comment("Hello Jawad, this is the second slide comment", second_slide, position, created_time)

    comments = first_slide.get_slide_comments(author)
    if len(comments) > 0:
        first_comment = comments[0]
        print(first_comment.text)

        comment_text = first_comment.author.comments[0].text
        print(comment_text)

    presentation.save("Comments_out.pptx", slides.export.SaveFormat.PPTX)

슬라이드 주석 접근

다음 예제는 PowerPoint 프레젠테이션에서 기존 주석에 접근하는 방법을 보여줍니다:

import aspose.slides as slides

with slides.Presentation("Comments1.pptx") as presentation:
    for author in presentation.comment_authors:
        for comment in author.comments:
            print("Slide: " + str(comment.slide.slide_number))
            print("Comment: " + comment.text)
            print("Author: " + comment.author.name)
            print("Posted at: " + str(comment.created_time))
            print()

주석에 회신

상위 주석은 회신 계층의 최상위 원본 주석입니다. Comment 클래스의 parent_comment 속성을 사용하여 주석의 상위 주석을 가져오거나 설정할 수 있습니다.

다음 예제는 회신을 추가하고 결과 주석 계층 구조를 조사하는 방법을 보여줍니다:

from datetime import datetime

import aspose.pydrawing as draw
import aspose.slides as slides

with slides.Presentation() as presentation:
    slide = presentation.slides[0]
    position = draw.PointF(10, 10)
    created_time = datetime.now()

    author1 = presentation.comment_authors.add_author("Author_1", "A.A.")
    comment1 = author1.comments.add_comment("comment 1", slide, position, created_time)

    author2 = presentation.comment_authors.add_author("Author_2", "B.B.")
    reply1 = author2.comments.add_comment("reply 1 for comment 1", slide, position, created_time)
    reply1.parent_comment = comment1

    reply2 = author2.comments.add_comment("reply 2 for comment 1", slide, position, created_time)
    reply2.parent_comment = comment1

    sub_reply = author1.comments.add_comment("subreply 3 for reply 2", slide, position, created_time)
    sub_reply.parent_comment = reply2

    author2.comments.add_comment("comment 2", slide, position, created_time)
    comment3 = author2.comments.add_comment("comment 3", slide, position, created_time)

    reply3 = author1.comments.add_comment("reply 4 for comment 3", slide, position, created_time)
    reply3.parent_comment = comment3

    comments = slide.get_slide_comments(None)
    for current_comment in comments:
        comment = current_comment
        while comment.parent_comment is not None:
            print("\t", end="")
            comment = comment.parent_comment

        print(current_comment.author.name + ": " + current_comment.text)

    presentation.save("parent_comment.pptx", slides.export.SaveFormat.PPTX)

    comment1.remove()
    presentation.save("remove_comment.pptx", slides.export.SaveFormat.PPTX)

최신 주석 추가

최신 주석은 슬라이드 자체, 특정 모양, 또는 AutoShape 내부의 텍스트 범위와 연관될 수 있습니다. CommentCollection.add_modern_comment 메서드는 슬라이드와 주석 마커 좌표 외에 Shape 인수를 허용합니다.

None을 shape 인수로 전달하면 주석은 슬라이드 수준 주석이 됩니다. 마커는 제공된 좌표에 따라 배치되지만 특정 모양과 연결되지 않으므로 ModernComment.shape은 None을 반환합니다. Shape가 제공되면 주석은 해당 모양에 고정됩니다. 좌표는 여전히 슬라이드상의 주석 마커 위치를 정의하고, 모양 연관성은 ModernComment.shape을 통해 확인할 수 있습니다.

모양에 최신 주석 고정

다음 예제는 슬라이드 수준 최신 주석과 특정 AutoShape에 고정된 최신 주석을 모두 생성하고, 각 주석에서 연관된 모양을 읽어옵니다.

from datetime import datetime

import aspose.pydrawing as draw
import aspose.slides as slides

with slides.Presentation() as presentation:
    slide = presentation.slides[0]
    author = presentation.comment_authors.add_author("Reviewer", "RV")
    shape = slide.shapes.add_auto_shape(slides.ShapeType.RECTANGLE, 50, 50, 300, 80)
    shape.name = "Revenue title"
    shape.text_frame.text = "Quarterly revenue"

    created_time = datetime.now()
    slide_comment_position = draw.PointF(20, 20)
    shape_comment_position = draw.PointF(60, 60)
    slide_comment = author.comments.add_modern_comment("Review the overall slide layout.", slide, None, slide_comment_position, created_time)
    shape_comment = author.comments.add_modern_comment("Check this title.", slide, shape, shape_comment_position, created_time)

    print(slide_comment.shape is None)
    print(shape_comment.shape.name)

    presentation.save("modern_comments.pptx", slides.export.SaveFormat.PPTX)

다양한 모양 유형에 주석 고정

Shape에서 파생된 모든 슬라이드 객체를 모양 고정점으로 사용할 수 있습니다. 일반적인 예로 AutoShape, PictureFrame, GroupShape, Connector, 그리고 차트와 같은 GraphicalObject 인스턴스가 있습니다.

다음 예제는 여러 일반적인 모양 유형을 생성하고 각각에 최신 주석을 연관시킵니다.

import base64
from datetime import datetime

import aspose.pydrawing as draw
import aspose.slides as slides

with slides.Presentation() as presentation:
    slide = presentation.slides[0]
    author = presentation.comment_authors.add_author("Reviewer", "RV")
    created_time = datetime.now()

    auto_shape = slide.shapes.add_auto_shape(slides.ShapeType.RECTANGLE, 20, 20, 180, 60)
    auto_shape.text_frame.text = "AutoShape"
    auto_shape_comment_position = draw.PointF(30, 30)
    author.comments.add_modern_comment("Comment on an AutoShape.", slide, auto_shape, auto_shape_comment_position, created_time)

    image_base64 = "iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAFklEQVR4nGP8//8/AwMDEwMDAwMDAwAkBgMB/DXemwAAAABJRU5ErkJggg=="
    image_data = base64.b64decode(image_base64)
    image = presentation.images.add_image(image_data)
    picture_frame = slide.shapes.add_picture_frame(slides.ShapeType.RECTANGLE, 220, 20, 120, 80, image)
    picture_comment_position = draw.PointF(230, 30)
    author.comments.add_modern_comment("Comment on a picture.", slide, picture_frame, picture_comment_position, created_time)

    group_shape = slide.shapes.add_group_shape()
    group_shape.shapes.add_auto_shape(slides.ShapeType.RECTANGLE, 0, 0, 80, 40)
    group_shape.shapes.add_auto_shape(slides.ShapeType.ELLIPSE, 100, 0, 80, 40)
    group_comment_position = draw.PointF(40, 150)
    author.comments.add_modern_comment("Comment on a group.", slide, group_shape, group_comment_position, created_time)

    connector = slide.shapes.add_connector(slides.ShapeType.STRAIGHT_CONNECTOR1, 220, 150, 140, 40)
    connector_comment_position = draw.PointF(240, 150)
    author.comments.add_modern_comment("Comment on a connector.", slide, connector, connector_comment_position, created_time)

    chart = slide.shapes.add_chart(slides.charts.ChartType.CLUSTERED_COLUMN, 400, 20, 250, 180)
    chart_comment_position = draw.PointF(420, 40)
    author.comments.add_modern_comment("Comment on a graphical object.", slide, chart, chart_comment_position, created_time)

    presentation.save("modern_comment_shape_types.pptx", slides.export.SaveFormat.PPTX)

텍스트에 주석 고정 및 상태 설정

AutoShape에 연관된 최신 주석의 경우, ModernComment.text_selection_start은 모양의 텍스트 프레임에서 선택된 텍스트의 시작 위치를 지정하고, ModernComment.text_selection_length은 선택 길이를 지정합니다. 이 두 속성을 함께 사용하면 AutoShape 내부의 특정 텍스트 범위에 주석을 연관시킬 수 있습니다.

ModernComment.status 속성은 ModernCommentStatus 열거형 값으로 읽거나 업데이트할 수 있습니다:

  • NOT_DEFINED — 특정 최신 주석 상태가 정의되지 않음.
  • ACTIVE — 주석이 활성 상태임.
  • RESOLVED — 주석이 해결됨.
  • CLOSED — 주석이 닫힘.

다음 예제는 모양에 고정된 최신 주석을 생성하고, 텍스트 선택에 연관시키며, 해결된 상태로 표시하고, 프레젠테이션을 저장한 뒤 파일을 다시 열어 값을 확인합니다.

from datetime import datetime

import aspose.pydrawing as draw
import aspose.slides as slides

output_file = "modern_comment_text_anchor.pptx"
shape_text = "Review the quarterly revenue forecast."
selected_text = "quarterly revenue"
expected_selection_start = shape_text.index(selected_text)

with slides.Presentation() as presentation:
    slide = presentation.slides[0]
    shape = slide.shapes.add_auto_shape(slides.ShapeType.RECTANGLE, 50, 50, 400, 100)
    shape.name = "Forecast text"
    shape.text_frame.text = shape_text

    author = presentation.comment_authors.add_author("Reviewer", "RV")
    comment_position = draw.PointF(60, 60)
    comment = author.comments.add_modern_comment("Verify this forecast wording.", slide, shape, comment_position, datetime.now())
    comment.text_selection_start = expected_selection_start
    comment.text_selection_length = len(selected_text)
    comment.status = slides.ModernCommentStatus.RESOLVED

    presentation.save(output_file, slides.export.SaveFormat.PPTX)

with slides.Presentation(output_file) as reopened_presentation:
    reopened_slide = reopened_presentation.slides[0]
    reopened_comments = reopened_slide.get_slide_comments(None)

    for reopened_comment in reopened_comments:
        if not isinstance(reopened_comment, slides.ModernComment):
            continue

        shape_matches = reopened_comment.shape.name == "Forecast text"
        selection_start_matches = reopened_comment.text_selection_start == expected_selection_start
        selection_length_matches = reopened_comment.text_selection_length == len(selected_text)
        status_matches = reopened_comment.status == slides.ModernCommentStatus.RESOLVED

        print("Shape anchor preserved: " + str(shape_matches))
        print("Text selection start preserved: " + str(selection_start_matches))
        print("Text selection length preserved: " + str(selection_length_matches))
        print("Resolved status preserved: " + str(status_matches))

기존 최신 주석 검사

기존 프레젠테이션을 검사하려면 어떤 주석이 ModernComment 인스턴스인지 확인한 후, ModernComment.shape, ModernComment.text_selection_start, ModernComment.text_selection_length, 및 ModernComment.status를 조사합니다. None 모양은 슬라이드 수준 주석을 의미합니다. AutoShape에 고정된 경우 텍스트 선택 속성이 모양 텍스트 프레임 내의 연관된 범위를 식별합니다.

import aspose.slides as slides

with slides.Presentation("comments.pptx") as presentation:
    for slide in presentation.slides:
        comments = slide.get_slide_comments(None)
        for comment in comments:
            if not isinstance(comment, slides.ModernComment):
                continue

            print("Slide: " + str(slide.slide_number))
            print("Text: " + comment.text)
            print("Status: " + str(comment.status))

            shape = comment.shape
            if shape is None:
                print("Anchor: slide level")
            else:
                print("Anchor shape: " + shape.name)
                print("Anchor type: " + type(shape).__name__)

                if isinstance(shape, slides.AutoShape):
                    print("Text selection start: " + str(comment.text_selection_start))
                    print("Text selection length: " + str(comment.text_selection_length))

            print()

주석 제거

모든 주석 및 주석 작성자 제거

다음 예제는 프레젠테이션에서 모든 주석 및 주석 작성자를 제거하는 방법을 보여줍니다:

import aspose.slides as slides

with slides.Presentation("example.pptx") as presentation:
    for author in presentation.comment_authors:
        author.comments.clear()

    presentation.comment_authors.clear()
    presentation.save("example_out.pptx", slides.export.SaveFormat.PPTX)

특정 주석 제거

다음 예제는 슬라이드에서 특정 주석을 제거하는 방법을 보여줍니다:

from datetime import datetime

import aspose.pydrawing as draw
import aspose.slides as slides

with slides.Presentation() as presentation:
    slide = presentation.slides[0]
    author = presentation.comment_authors.add_author("Author", "A")
    created_time = datetime.now()

    first_comment_position = draw.PointF(0.2, 0.2)
    second_comment_position = draw.PointF(0.3, 0.2)
    author.comments.add_comment("comment 1", slide, first_comment_position, created_time)
    author.comments.add_comment("comment 2", slide, second_comment_position, created_time)

    for comment_author in presentation.comment_authors:
        comments_to_remove = []
        comments = slide.get_slide_comments(comment_author)

        for comment in comments:
            if comment.text == "comment 1":
                comments_to_remove.append(comment)

        for comment in comments_to_remove:
            comment_author.comments.remove(comment)

    presentation.save("pres.pptx", slides.export.SaveFormat.PPTX)

FAQ

Aspose.Slides는 최신 주석에 대한 해결된 상태를 지원합니까?

예. ModernComment.status는 ModernCommentStatus 값을 사용하여 읽고 설정할 수 있으며, RESOLVED도 포함됩니다. 이 상태는 프레젠테이션에 저장되며 파일을 다시 연 후에도 읽을 수 있습니다.

스레드형 토론(회신 체인)이 지원되며 중첩 제한이 있나요?

예. 각 주석은 parent comment을 참조할 수 있어 회신 체인을 만들 수 있습니다. API에서는 특정 중첩 깊이 제한을 정의하지 않습니다.

주석 마커 위치는 슬라이드의 어떤 좌표계로 정의되나요?

마커 위치는 슬라이드 좌표계의 부동 소수점 좌표로 정의되어 슬라이드에서 정확히 배치할 수 있습니다.