Java에서 사용자 정의 애니메이션 동작 만들기 및 수정
개요
사용자 지정 애니메이션 동작을 사용하면 색상 변경, 도형 회전 또는 편집 가능한 움직임 경로 따라가기와 같은 애니메이션 효과 내의 개별 작업을 제어할 수 있습니다. 이 가이드에서는 동작을 만들고 결합하는 방법, 타이밍을 구성하는 방법, 기존 애니메이션을 검사·수정하는 방법, 그리고 프레젠테이션을 저장·다시 열었을 때 속성이 유지되는지 확인하는 방법을 보여줍니다.
미리 정의된 효과와 클릭 트리거에 대해서는 도형 애니메이션을 참조하십시오.
애니메이션 모델 이해
애니메이션은 Timeline → Sequence → Effect → Behaviors 형태로 구성됩니다:
- getTimeline 메서드는 슬라이드 타임라인을 반환하며, 여기에는 메인 시퀀스와 인터랙티브 시퀀스가 포함됩니다.
- ISequence 은 효과들을 포함하며, 서로 다른 도형을 대상으로 할 수 있습니다.
- IEffect 은 대상 도형, 프리셋, 서브타입 및 효과 타이밍을 식별합니다.
- IEffect.getBehaviors 가 반환하는 컬렉션에는 색상 변경, 이동, 회전, 속성 설정 등 효과를 구현하는 작업이 들어 있습니다.
개별 동작 만들기
ISequence.addEffect 를 호출해 효과를 만든 뒤 getBehaviors 컬렉션에 접근합니다. 프리셋을 사용하면 이 컬렉션이 자동으로 채워집니다. 프리셋을 확장할 때는 기존 작업을 유지하고, 의도적으로 교체할 경우에는 clear 를 사용하십시오.
IBehaviorFactory 는 아래에 예시된 8가지 동작 유형을 생성합니다. 움직임은 Build a Motion Path에서 다룹니다. 각 스니펫에는 import 문이 포함되어 있으며, 실행 가능한 문장은 메서드 내부에 배치합니다. 이후 편집 예제는 어떤 출력 파일을 사용하는지 명시합니다.
회전
createRotationEffect 로 회전 효과를 생성합니다. getBy 는 상대 각도를 도 단위로 지정하고, getFrom 와 getTo 은 시작·끝 지점을 지정합니다.
예제는 Spin 효과를 시작으로, 프리셋 작업을 하나의 회전 동작으로 교체하고 해당 동작에 2초 지속 시간을 부여합니다. 90도 상대 각도는 도형의 초기 방향에서 ¼ 회전을 의미하므로 명시적인 시작 각도는 필요하지 않습니다.
import com.aspose.slides.*;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 160, 80);
IEffect effect = slide.getTimeline().getMainSequence().addEffect(shape, EffectType.Spin, EffectSubtype.None, EffectTriggerType.OnClick);
effect.getBehaviors().clear();
IBehaviorFactory factory = new BehaviorFactory();
IRotationEffect rotation = factory.createRotationEffect();
rotation.setBy(90f);
rotation.getTiming().setDuration(2f);
effect.getBehaviors().add(rotation);
presentation.save("rotation.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
rotation.pptx 에는 하나의 도형과 하나의 회전 동작이 들어 있습니다. 아래 컬렉션, 타이밍 및 회전 편집 예제는 이 파일을 사용합니다.
크기 조정
createScaleEffect 를 X/Y 백분율과 함께 사용합니다. getFrom 와 getTo 은 시작·끝 크기를 설명하고, getBy 은 상대 변화를 설명합니다. 여기서 100은 원본 크기를 의미합니다.
예제는 두 차원을 100%에서 125% 로 2초 동안 확대합니다. 가로·세로 비율을 동일하게 유지하면 도형의 비율이 보존되고, 비율이 다르면 한 차원이 더 늘어납니다.
import com.aspose.slides.*;
import java.awt.geom.Point2D;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 160, 80);
IEffect effect = slide.getTimeline().getMainSequence().addEffect(shape, EffectType.GrowShrink, EffectSubtype.None, EffectTriggerType.OnClick);
effect.getBehaviors().clear();
IBehaviorFactory factory = new BehaviorFactory();
IScaleEffect scale = factory.createScaleEffect();
scale.setFrom(new Point2D.Float(100, 100));
scale.setTo(new Point2D.Float(125, 125));
scale.getTiming().setDuration(2f);
effect.getBehaviors().add(scale);
presentation.save("scale.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
색상
createColorEffect 로 채우기 색을 파란색에서 주황색으로 변경합니다. getFrom 와 getTo 은 색상이고, getBy 는 색상 오프셋입니다. IBehavior.getProperties 는 애니메이션 대상 속성을 식별합니다.
도형의 단색 채우기는 파란색으로 초기화되어 애니메이션 시작 색과 일치합니다. 채우기 색 속성을 선택하면 동작이 어느 부분을 바꿔야 하는지 알려 주며, 색상 끝점만으로는 속성을 지정할 수 없습니다. 저장된 효과는 2초 동안 주황색으로 전환된다고 설명합니다.
import com.aspose.slides.*;
import java.awt.Color;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 160, 80);
shape.getFillFormat().setFillType(FillType.Solid);
shape.getFillFormat().getSolidFillColor().setColor(Color.BLUE);
IEffect effect = slide.getTimeline().getMainSequence().addEffect(shape, EffectType.ChangeFillColor, EffectSubtype.None, EffectTriggerType.OnClick);
effect.getBehaviors().clear();
IBehaviorFactory factory = new BehaviorFactory();
IColorEffect color = factory.createColorEffect();
color.getProperties().add(BehaviorProperty.getFillColor().getValue());
color.getFrom().setColor(Color.BLUE);
Color orange = new Color(255, 165, 0);
color.getTo().setColor(orange);
color.getTiming().setDuration(2f);
effect.getBehaviors().add(color);
presentation.save("color.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
필터
createFilterEffect 로 와이프 효과를 선택합니다. getType, getSubtype, getReveal 은 필터 종류, 방향, 그리고 도형을 표시할지 숨길지를 지정합니다.
이 예제는 오른쪽 방향 서브타입을 사용해 도형을 표시하는 2초 와이프를 구성합니다. 필터 설정은 효과 내부 동작에 속하므로 프리셋의 원래 작업을 제거한 뒤에 설정합니다.
import com.aspose.slides.*;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 160, 80);
IEffect effect = slide.getTimeline().getMainSequence().addEffect(shape, EffectType.Wipe, EffectSubtype.None, EffectTriggerType.OnClick);
effect.getBehaviors().clear();
IBehaviorFactory factory = new BehaviorFactory();
IFilterEffect filter = factory.createFilterEffect();
filter.setType(FilterEffectType.Wipe);
filter.setSubtype(FilterEffectSubtype.Right);
filter.setReveal(FilterEffectRevealType.In);
filter.getTiming().setDuration(2f);
effect.getBehaviors().add(filter);
presentation.save("filter.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
속성
createPropertyEffect 로 불투명도를 애니메이션합니다. getFrom, getTo, getBy 은 문자열이며, getValueType 과 getCalcMode 로 해석됩니다. 세 값을 모두 설정하기보다 끝점이나 상대 오프셋을 선택하십시오.
여기서는 속성으로 불투명도를 선택했고, 문자열은 25% 불투명도에서 완전 불투명도로 변함을 의미합니다. 선형 보간법은 두 값 사이를 점진적으로 변화시킵니다. 다른 속성에 적용할 경우 해당 속성에 맞는 값 유형과 끝점 값을 선택하십시오.
import com.aspose.slides.*;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 160, 80);
IEffect effect = slide.getTimeline().getMainSequence().addEffect(shape, EffectType.Fade, EffectSubtype.None, EffectTriggerType.OnClick);
effect.getBehaviors().clear();
IBehaviorFactory factory = new BehaviorFactory();
IPropertyEffect property = factory.createPropertyEffect();
property.getProperties().add(BehaviorProperty.getStyleOpacity().getValue());
property.setValueType(PropertyValueType.Number);
property.setCalcMode(PropertyCalcModeType.Linear);
property.setFrom("0.25");
property.setTo("1");
property.getTiming().setDuration(2f);
effect.getBehaviors().add(property);
presentation.save("property.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
설정
createSetEffect 로 getTo 를 사용해 가시성을 지정합니다. 설정 동작은 끝점 사이를 보간하지 않습니다.
예제는 가시성 속성을 선택하고 동작이 실행될 때 문자열 visible 을 할당합니다. 이 최소 프레젠테이션의 사각형은 이미 보이므로 단독으로는 눈에 띄는 변화가 없을 수 있습니다. 하지만 더 큰 효과의 일부로 도형을 숨기거나 표시하는 시점과 함께 사용할 때 유용합니다.
import com.aspose.slides.*;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 160, 80);
IEffect effect = slide.getTimeline().getMainSequence().addEffect(shape, EffectType.Appear, EffectSubtype.None, EffectTriggerType.OnClick);
effect.getBehaviors().clear();
IBehaviorFactory factory = new BehaviorFactory();
ISetEffect set = factory.createSetEffect();
set.getProperties().add(BehaviorProperty.getStyleVisibility().getValue());
set.setTo("visible");
effect.getBehaviors().add(set);
presentation.save("set.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
명령
createCommandEffect 를 사용하고 getType, getCommandString, getShapeTarget 를 구성합니다. 작업 디렉터리에 sample.wav 라는 WAV 파일을 배치하십시오. 이 예제는 addAudioFrameEmbedded 로 파일을 삽입하고 오디오 프레임에 재생 명령을 연결합니다.
오디오 프레임은 효과와 명령 모두의 대상이 됩니다. 이렇게 하면 삽입된 녹음에 대한 재생 요청이 연결되며, 명령 문자열만으로는 어떤 미디어 객체를 제어할지 알 수 없습니다. 효과는 슬라이드 쇼 중 클릭 시 시작하도록 구성됩니다.
import com.aspose.slides.*;
import java.io.FileInputStream;
import java.io.IOException;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
try (FileInputStream audioStream = new FileInputStream("sample.wav")) {
IAudioFrame audioFrame = slide.getShapes().addAudioFrameEmbedded(100, 100, 40, 40, audioStream);
IEffect effect = slide.getTimeline().getMainSequence().addEffect(audioFrame, EffectType.MediaPlay, EffectSubtype.None, EffectTriggerType.OnClick);
effect.getBehaviors().clear();
IBehaviorFactory factory = new BehaviorFactory();
ICommandEffect command = factory.createCommandEffect();
command.setType(CommandEffectType.Call);
command.setCommandString("play");
command.setShapeTarget(audioFrame);
effect.getBehaviors().add(command);
presentation.save("command.pptx", SaveFormat.Pptx);
} catch (IOException exception) {
System.out.println("Unable to read sample.wav: " + exception.getMessage());
}
} finally {
presentation.dispose();
}
저장하면 command.pptx 에 명령이 저장되지만 녹음은 재생되지 않습니다. 재생하려면 해당 명령과 미디어 대상을 지원하는 슬라이드 쇼 플레이어가 필요합니다.
동작 컬렉션 관리
IBehaviorCollection 은 add, insert, remove, removeAt 를 지원합니다. 이 예제는 rotation.pptx 를 열어 스케일을 추가하고 회전 앞에 배치한 뒤 회전을 제거합니다. 동일 객체를 제거하고 다시 삽입하면 복제 없이 위치만 변경됩니다.
편집 순서는 컬렉션을 회전‑스케일 → 스케일‑회전 → 스케일만으로 변경합니다. 인덱스는 현재 컬렉션을 기준으로 하므로, 재정렬 후 회전의 새로운 인덱스를 사용해 제거합니다. 최종 열거를 통해 저장될 동작을 확인합니다.
import com.aspose.slides.*;
import java.awt.geom.Point2D;
Presentation presentation = new Presentation("rotation.pptx");
try {
IEffect effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
IBehaviorCollection behaviors = effect.getBehaviors();
IBehaviorFactory factory = new BehaviorFactory();
IScaleEffect scale = factory.createScaleEffect();
scale.setTo(new Point2D.Float(125, 125));
scale.getTiming().setDuration(2f);
behaviors.add(scale);
behaviors.remove(scale);
behaviors.insert(0, scale);
behaviors.removeAt(1);
for (IBehavior behavior : behaviors)
System.out.println(behavior.getClass().getSimpleName());
presentation.save("collection-edited.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
출력은 ScaleEffect 로, 스케일만 남습니다. 컬렉션 순서 자체가 동작을 연속 실행하게 하지는 않습니다. 모든 작업을 교체할 때만 컬렉션을 비우십시오.
동작 타이밍 구성
IBehavior.getTiming 은 ITiming 을 노출하며, 이는 IEffect.getTiming 과는 별개입니다. 효과 타이밍은 전체 효과를 스케줄링하고, 동작 타이밍은 그 안의 개별 작업을 스케줄링합니다.
지속 시간, 지연, 반복 및 가속 설정
rotation.pptx 를 열어 지속 시간(getDuration) 과 트리거 지연(getTriggerDelayTime) 을 초 단위로 설정하고, setRepeatCount 로 반복 횟수를 지정합니다. getAccelerate 와 getDecelerate 은 지속 시간의 비율이며, 두 값의 합은 1을 초과하지 않아야 합니다.
입력 파일은 회전 예제에서 만든 파일이며, 첫 번째 동작이 회전임이 알려져 있습니다. 이 예제는 해당 동작의 타이밍만 변경하고, 90도 회전 각도는 그대로 유지합니다. 각도와 타이밍을 분리하면 애니메이션 속도를 재구성 없이 조정하기가 쉽습니다.
import com.aspose.slides.*;
Presentation presentation = new Presentation("rotation.pptx");
try {
IEffect effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
IRotationEffect rotation = (IRotationEffect)effect.getBehaviors().get_Item(0);
rotation.getTiming().setDuration(2f);
rotation.getTiming().setTriggerDelayTime(0.5f);
rotation.getTiming().setRepeatCount(3f);
rotation.getTiming().setAccelerate(0.2f);
rotation.getTiming().setDecelerate(0.2f);
presentation.save("timing.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
동작은 2초 지속, 0.5초 지연, 반복 횟수 3을 사용합니다. 전체 지속 시간의 앞·뒤 20%는 가속·감속에 사용됩니다.
다른 반복 정책으로는 getRepeatDuration, getRepeatUntilEndSlide, getRepeatUntilNextClick 가 있으며, 모두를 동시에 활성화하지 말고 하나를 선택하십시오. getAutoReverse 은 전방 재생 후 역방향 재생을 실행합니다. 가속·감속은 연속적인 변화에만 적용되며, 이산적인 할당이나 명령에는 적용되지 않습니다.
움직임 경로 만들기
createMotionEffect 로 움직임을 생성합니다. getFrom, getTo, getBy 은 백분율 기반 좌표 또는 오프셋을 설명합니다. 편집 가능한 경로를 만들려면 MotionPath 를 생성하고 IMotionEffect.setPath 로 할당합니다. IMotionPath 는 경로 명령을 저장합니다.
MotionCommandPathType 은 동작을 선택합니다:
| Command | Points | Meaning |
|---|---|---|
| MoveTo | One | 시작 위치를 설정합니다. |
| LineTo | One | 직선 구간을 끝점까지 이동합니다. |
| CurveTo | Three | 두 개의 제어점과 끝점으로 정의된 3차 곡선을 따릅니다. |
| CloseLoop | None | 시작 위치로 돌아갑니다. |
| End | None | 경로를 종료합니다. |
MotionPathPointsType 은 코너 포인트·스무스 포인트 등 포인트 편집 특성을 설명합니다. 이는 명령 타입을 대체하지 않으며, 아래 곡선 예제에서는 곡선 포인트 타입을, 직선 구간에서는 코너 포인트 타입을 사용합니다.
경로 좌표는 슬라이드 크기에 정규화됩니다. X 이동 0.25 는 슬라이드 너비의 ¼을 의미하며, 0.25 포인트가 아닙니다. Y 좌표는 아래쪽이 양수입니다. 절대 명령은 경로 좌표계에서 위치를 지정하고, 상대 명령은 현재 위치에서의 오프셋을 지정합니다. 이는 getOrigin 이 경로 기준 프레임을 선택하고, getPathEditMode 가 도형 이동 시 경로가 어떻게 움직이는지를 제어하는 것과는 별개입니다.
직선 경로 만들기
시작점, 하나의 직선 구간, 종료 명령을 가진 움직임 동작을 생성합니다. IMotionPath.add 은 명령 타입, 포인트 배열, 포인트 타입, 상대 좌표 플래그를 받습니다.
시작 명령은 (0, 0)을 설정하고, 직선은 (0.25, 0) 으로 끝나 슬라이드 너비의 ¼ 만큼 수평 이동합니다. 종료 명령은 좌표가 없습니다. 경로를 할당한 뒤 움직임 동작을 효과에 추가하면 해당 경로가 사각형에 연결됩니다.
import com.aspose.slides.*;
import java.awt.geom.Point2D;
Presentation presentation = new Presentation();
try {
ISlide slide = presentation.getSlides().get_Item(0);
IAutoShape shape = slide.getShapes().addAutoShape(ShapeType.Rectangle, 100, 100, 160, 80);
IEffect effect = slide.getTimeline().getMainSequence().addEffect(shape, EffectType.PathRight, EffectSubtype.None, EffectTriggerType.OnClick);
effect.getBehaviors().clear();
IBehaviorFactory factory = new BehaviorFactory();
IMotionEffect motion = factory.createMotionEffect();
motion.setOrigin(MotionOriginType.Layout);
motion.getTiming().setDuration(2f);
IMotionPath path = new MotionPath();
path.add(MotionCommandPathType.MoveTo, new Point2D.Float[] { new Point2D.Float(0, 0) }, MotionPathPointsType.Auto, false);
path.add(MotionCommandPathType.LineTo, new Point2D.Float[] { new Point2D.Float(0.25f, 0) }, MotionPathPointsType.Corner, false);
path.add(MotionCommandPathType.End, new Point2D.Float[0], MotionPathPointsType.None, false);
motion.setPath(path);
effect.getBehaviors().add(motion);
presentation.save("motion.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
motion.pptx 에는 세 개의 경로 명령을 가진 하나의 움직임 동작이 포함됩니다. 아래 파일 편집 예제는 이 구조를 전제로 합니다.
절대 좌표와 상대 좌표 비교
다음 두 경로 객체는 같은 경로를 나타냅니다. 절대 명령은 (0.3, 0.1) 에 끝나고, 상대 명령은 현재 위치에 (0.1, 0.1)을 더해 (0.2, 0) 로 이동합니다.
두 경로 모두 같은 시작 위치에서 시작합니다. 상대 직선의 경우 현재 위치에 X·Y 오프셋을 더해 끝점을 구하고, 절대 직선은 끝점을 직접 읽습니다. 좌표 변환 없이 플래그만 전환하면 다른 경로가 됩니다.
import com.aspose.slides.*;
import java.awt.geom.Point2D;
MotionPath absolutePath = new MotionPath();
absolutePath.add(MotionCommandPathType.MoveTo, new Point2D.Float[] { new Point2D.Float(0.2f, 0) }, MotionPathPointsType.Auto, false);
absolutePath.add(MotionCommandPathType.LineTo, new Point2D.Float[] { new Point2D.Float(0.3f, 0.1f) }, MotionPathPointsType.Corner, false);
MotionPath relativePath = new MotionPath();
relativePath.add(MotionCommandPathType.MoveTo, new Point2D.Float[] { new Point2D.Float(0.2f, 0) }, MotionPathPointsType.Auto, false);
relativePath.add(MotionCommandPathType.LineTo, new Point2D.Float[] { new Point2D.Float(0.1f, 0.1f) }, MotionPathPointsType.Corner, true);
경로를 움직임 동작에 할당하면 프레젠테이션에서 사용할 수 있습니다. 마지막 Boolean 인자는 해당 명령에 상대 좌표를 사용할지 여부를 선택합니다.
직선을 곡선으로 교체
motion.pptx 를 열어 직선 명령을 3차 곡선으로 교체합니다. 먼저 두 개의 제어점을 제공하고 끝점을 지정합니다.
시작 위치는 앞선 명령이 제공합니다. 첫 두 포인트가 곡선을 만들고, 세 번째 포인트가 곡선의 목적지가 됩니다; 이것은 세 개의 연속 목적지가 아니라는 점을 기억하십시오. 명령 타입, 포인트 편집 타입, 포인트 배열을 함께 업데이트하면 새 기하학에 맞게 구간이 일관됩니다.
import com.aspose.slides.*;
import java.awt.geom.Point2D;
Presentation presentation = new Presentation("motion.pptx");
try {
IEffect effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
IMotionEffect motion = (IMotionEffect)effect.getBehaviors().get_Item(0);
IMotionPath path = motion.getPath();
path.get_Item(1).setCommandType(MotionCommandPathType.CurveTo);
path.get_Item(1).setPointsType(MotionPathPointsType.CurveSmooth);
path.get_Item(1).setPoints(new Point2D.Float[] { new Point2D.Float(0.1f, 0), new Point2D.Float(0.2f, 0.1f), new Point2D.Float(0.3f, 0.1f) });
presentation.save("curve.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
curve.pptx 의 경로는 여전히 세 개의 명령을 가지고 있지만, 중간 명령이 이제 곡선을 정의합니다.
저장된 경로 검사 및 편집
각 IMotionCmdPath 은 getPoints, getCommandType, getPointsType, isRelative 를 제공한다. 아래 예제는 motion.pptx 에 있는 알려진 세 명령 경로를 사용한다. 임의 입력의 경우, 편집하기 전에 원하는 효과를 찾아 명령 타입과 포인트 수를 확인하고 인덱스로 접근한다.
명령과 좌표 읽기
경로를 변경 없이 읽어들인다. 종료 및 닫힘 명령은 포인트가 필요 없으므로 null 포인트 배열을 허용한다.
출력은 각 숫자형 명령 타입과 상대 좌표 플래그를 쌍으로 표시하고, 그 뒤에 포인트를 나열한다. 이렇게 하면 경로를 수정하기 전에 끝점과 오프셋을 구분할 수 있다. 곡선은 세 개의 포인트를, 이 파일의 직선은 하나만 나열한다.
import com.aspose.slides.*;
import java.awt.geom.Point2D;
Presentation presentation = new Presentation("motion.pptx");
try {
IEffect effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
IMotionEffect motion = (IMotionEffect)effect.getBehaviors().get_Item(0);
IMotionPath path = motion.getPath();
for (IMotionCmdPath segment : path)
{
System.out.println(segment.getCommandType() + ", relative: " + segment.isRelative());
if (segment.getPoints() != null)
for (Point2D.Float point : segment.getPoints())
System.out.println("X=" + point.x + ", Y=" + point.y);
}
} finally {
presentation.dispose();
}
목록에는 시작점, (0.25, 0) 에 끝나는 절대 직선, 그리고 종료 명령이 포함된다.
끝점 변경
motion.pptx 를 열어 직선의 포인트 배열을 교체해 끝점을 이동시킨다.
입력 파일에서 인덱스 0 은 시작 명령, 인덱스 1 은 직선이다. 직선의 단일 포인트를 교체하면 명령 타입, 타이밍, 컬렉션 내 위치는 그대로 두고 목적지만 바뀐다. 명령이 절대 좌표를 사용하므로 새 쌍은 추가 오프셋이 아니라 위치를 지정한다.
import com.aspose.slides.*;
import java.awt.geom.Point2D;
Presentation presentation = new Presentation("motion.pptx");
try {
IEffect effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
IMotionEffect motion = (IMotionEffect)effect.getBehaviors().get_Item(0);
motion.getPath().get_Item(1).setPoints(new Point2D.Float[] { new Point2D.Float(0.4f, 0.1f) });
presentation.save("motion-endpoint.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
motion-endpoint.pptx 의 직선은 (0.4, 0.1) 에 끝나며 원본 파일은 변경되지 않는다.
구간 교체
insert 와 removeAt 를 사용해 motion.pptx 의 직선을 교체한다. 삽입 시 기존 직선은 인덱스 2 로 이동한다.
이는 기존 좌표를 편집하는 대신 명령 객체 자체를 교체한다는 것을 보여준다. 삽입 후 컬렉션은 일시적으로 시작 명령, 새 직선, 오래된 직선, 종료 명령 순으로 구성된다. 인덱스 2 를 제거하면 오래된 직선이 사라지고 새 경로가 남는다.
import com.aspose.slides.*;
import java.awt.geom.Point2D;
Presentation presentation = new Presentation("motion.pptx");
try {
IEffect effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
IMotionEffect motion = (IMotionEffect)effect.getBehaviors().get_Item(0);
IMotionPath path = motion.getPath();
path.insert(1, MotionCommandPathType.LineTo, new Point2D.Float[] { new Point2D.Float(0.2f, 0.1f) }, MotionPathPointsType.Corner, false);
path.removeAt(2);
presentation.save("motion-edited.pptx", SaveFormat.Pptx);
} finally {
presentation.dispose();
}
저장된 경로는 여전히 세 개의 명령을 가지고 있으며, 새 직선은 (0.2, 0.1) 에 끝나고 종료 명령이 마지막에 있다.
기존 동작 수정 및 검증
동작의 인덱스를 모를 경우 타입으로 선택한다. 이 예제는 rotation.pptx 를 열어 IRotationEffect 를 찾고 각도를 변경한 뒤 다시 열어 저장된 값을 확인한다.
타입 검사를 통해 회전이 아닌 동작은 루프에서 건너뛰게 된다. 두 번째 로드는 저장된 파일을 별도 프레젠테이션 객체에 읽어 들여 메모리에 남아 있는 값이 아니라 지속된 데이터를 비교한다. 이 예제는 알려진 효과가 메인 시퀀스 첫 번째에 있다고 가정한다; 타입으로 동작을 선택한다고 해서 임의 프레젠테이션에서 정확한 효과를 찾을 수는 없다.
import com.aspose.slides.*;
Presentation presentation = new Presentation("rotation.pptx");
try {
IEffect effect = presentation.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
for (IBehavior behavior : effect.getBehaviors())
{
if (behavior instanceof IRotationEffect) {
IRotationEffect rotation = (IRotationEffect) behavior;
rotation.setBy(180f);
}
}
presentation.save("rotation-edited.pptx", SaveFormat.Pptx);
Presentation reopened = new Presentation("rotation-edited.pptx");
try {
IEffect savedEffect = reopened.getSlides().get_Item(0).getTimeline().getMainSequence().get_Item(0);
for (IBehavior behavior : savedEffect.getBehaviors())
{
if (behavior instanceof IRotationEffect) {
IRotationEffect rotation = (IRotationEffect) behavior;
System.out.println("Rotation preserved: " + (Math.abs(rotation.getBy() - 180f) < 0.001f));
}
}
} finally {
reopened.dispose();
}
} finally {
presentation.dispose();
}
출력은 Rotation preserved: true 이다. 동일한 타입 검사 패턴을 다른 동작에도 적용한다. 완전한 보존 검증을 위해서는 대상 도형, 효과, 동작 타입 및 순서, 타이밍, 경로 명령을 비교하고 부동소수점 값은 수치적 허용오차를 사용한다. 애니메이션 레이아웃을 모르는 경우 Read Shape Animations 를 참고해 메인 및 인터랙티브 시퀀스를 순회한다.
동작 순서, 프리셋 및 재생
IBehaviorCollection 내 순서는 효과 작업의 저장 순서이며, 각각이 자동으로 앞의 동작을 기다리는 재생 목록이 아니다. 타이밍과 포함된 효과가 스케줄을 결정한다. 동작은 겹칠 수 있으며, 동일 속성에 대한 작업은 getAdditive 와 getAccumulate 로 상호 작용할 수 있다. “이동 후 회전” 과 같이 컬렉션 순서만으로 스케줄링하지 말고, Shape Animation 에 설명된 대로 명시적 타이밍이나 별도 효과를 사용한다.
효과의 getType 와 getSubtype 은 프리셋을 설명하지만, 편집된 동작 트리의 전체 설명은 아니다. 프리셋과 서브타입을 선택한 뒤 동작을 사용자 정의하고, 프리셋을 변경하면 컬렉션이 다시 구축되어 사용자 정의 작업이 사라질 수 있다. 예를 들어, 사용자 정의 Spin 효과를 Fade 로 바꾸면 회전 동작이 설정·필터 동작으로 교체된다. 프리셋이나 서브타입을 바꾼 뒤 컬렉션을 다시 검사한다. 프리셋 동작을 비우면 프리셋에 필요한 가시성 또는 초기화 작업도 사라질 수 있다. 예제는 가시적인 도형을 사용하고 동작을 교체했으며, 모든 프리셋 구현을 재구성하지는 않는다.
포맷 호환성
보존된 동작 트리가 모든 뷰어나 내보내기 렌더러에서 동일하게 재생된다는 보장은 하지 않는다. 저장된 데이터와 실제 렌더링 결과를 별도로 확인한다.
| 포맷 또는 출력 | 확인 항목 |
|---|---|
| PPTX | 예제의 기본 포맷으로 사용한다. 다시 열어 편집 가능한 동작 트리를 검증한 뒤, 목표 PowerPoint 버전에서 재생을 확인한다. |
| PPT | 레거시 바이너리 형식은 PPTX 와 다를 수 있다. 별도의 저장·재열 및 재생 테스트를 수행하고, PPTX 출력만으로 모든 사용자 정의 조합이 지원된다고 추론하지 않는다. |
| PDF, PNG, JPEG 및 기타 정적 슬라이드 이미지 | 정적인 슬라이드 표현이며, 재생 가능한 동작 타임라인이나 최종 애니메이션 프레임을 보장하지 않는다. |
| HTML5 | 내보내기 옵션에서 도형 애니메이션을 활성화하면 지원되는 애니메이션을 재생할 수 있다. 브라우저에서 사용자 정의 조합을 테스트한다. |
| Animated GIF | 렌더링된 프레임을 저장하지만, 편집 가능한 동작이나 클릭 트리거 인터랙션은 포함되지 않는다. 실제 렌더링된 움직임을 확인한다. |
| Video | 애니메이션 프레임을 렌더링하고 비디오로 인코딩한다. 지원은 렌더러의 supported animations and effects 에 제한되며, 명령 및 인터랙티브 이벤트는 편집 가능한 타임라인이 되지 않는다. |
FAQ
내 효과에 동작이 추가된 이유가 무엇인가요?
미리 정의된 효과를 만들면 기본 작업이 자동으로 생성될 수 있습니다. 프리셋을 확장하거나 동작을 교체할지 결정하기 전에 이를 확인하십시오.
동작을 시작 부분으로 이동하면 먼저 재생되나요?
반드시 그렇지는 않습니다. 컬렉션 순서는 타이밍을 대신하지 못합니다. 지연, 지속 시간 및 동일 속성에 대한 작업 간 상호 작용을 확인하십시오.
종료 명령에 포인트가 없는 이유는?
종료 명령은 경로의 끝을 표시하며 좌표가 필요하지 않습니다. 파일에서 경로를 읽을 때 null 포인트 배열을 검사하십시오.
라운드 트립이 성공했다고 해서 재생이 보장되나요?
아니요. 재열은 확인한 속성의 보존을 증명하지만, 슬라이드 쇼 플레이어나 애니메이션 내보내기로 시각적 동작을 별도 테스트해야 합니다.