Categories
AE

[익스프레션] 한글 타이핑 자막 효과 개선

한글 타이핑 자막 효과의 시작 시간을 정할 수 있도록 개선

let cCho = ["ㄱ", "ㄲ", "ㄴ", "ㄷ", "ㄸ", "ㄹ", "ㅁ", "ㅂ", "ㅃ", "ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅉ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"],
cJung = ["ㅏ", "ㅐ", "ㅑ", "ㅒ", "ㅓ", "ㅔ", "ㅕ", "ㅖ", "ㅗ", "ㅘ", "ㅙ", "ㅚ", "ㅛ", "ㅜ", "ㅝ", "ㅞ", "ㅟ", "ㅠ", "ㅡ", "ㅢ", "ㅣ"],
cJong = ["", "ㄱ", "ㄲ", "ㄳ", "ㄴ", "ㄵ", "ㄶ", "ㄷ", "ㄹ", "ㄺ", "ㄻ", "ㄼ", "ㄽ", "ㄾ", "ㄿ", "ㅀ", "ㅁ", "ㅂ", "ㅄ", "ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"]

let toStringFromCharCode = (cho, jung, jong) =>
String.fromCharCode(44032 + cho * 588 + jung * 28 + (jong || 0));

let seperateChar = (char) => {
let cCode = char.charCodeAt() - 0xac00;
let jong = cCode % 28;
let jung = ((cCode - jong) / 28) % 21;
let cho = ((cCode - jong) / 28 - jung) / 21;
return []
.concat(cCho[cho])
.concat(toStringFromCharCode(cho, jung))
.concat(cJong[jong] !== "" ? toStringFromCharCode(cho, jung, jong) : []);
};

let toKorChars = (char) => {
let cCode = char.charCodeAt();
return [].concat(
(!cCode && []) ||
(cCode === 32 && " ") ||
((cCode < 0xac00 || cCode > 0xd7a3) && char) ||
seperateChar(char)
);
};

let typing = (str) =>
str
.split("")
.map((char) => toKorChars(char))
.reduce(
(pre, cur) =>
pre.concat(
cur.map((v) => (pre.length !== 0 ? pre[pre.length - 1] : "") + v)
),
[""]
);

let p = thisLayer.effect("Speed")("Slider");
let strList = typing(thisLayer.text.sourceText);

if (time > 2) {
let adjustedTime = time - 2;
let strListIndex = Math.round(adjustedTime*p);
[strList[strList.length > strListIndex ? strListIndex : strList.length-1]]
} else {
[]
}

//------------초성, 중성 종성 글자 수 세기--------------
/*let countCharComponents = (str) => {
return str.split("").reduce((count, char) => {
let components = toKorChars(char);
return count + components.length;
}, 0);
};

[countCharComponents(thisLayer.text.sourceText)]*/
//------------초성, 중성 종성 글자 수 세기--------------
Categories
AE

[익스프레션] 포인트텍스트 기준 문장 나누기

타입 1

const layerNameNum = parseInt(thisLayer.name.replace(/[^0-9]/g, ""));
const totalText = thisComp.layer("Text_" + layerNameNum).text.sourceText;
const pointTextArray = thisComp.layer("PointText_" + layerNameNum).text.sourceText.split("$$");

function splitTextByWords(text, words) {
let currentIndex = 0;
const result = [];

for (const word of words) {
const index = text.indexOf(word, currentIndex);
if (index !== -1) {
const preWord = text.substring(currentIndex, index).trim();
if (preWord !== '') result.push(preWord);
result.push(word);
currentIndex = index + word.length;
}
}

// 마지막 단어 이후의 텍스트를 결과에 추가
if (currentIndex < text.length) {
const lastText = text.substring(currentIndex).trim();
if (lastText !== '') result.push(lastText);
}

return result;
}

const thisLayerRenderText = splitTextByWords(totalText, pointTextArray);


[thisLayerRenderText]

타입 2

const layerNameNum = parseInt(thisLayer.name.replace(/[^0-9]/g, ""));
const totalText = thisComp.layer("Text_" + layerNameNum).text.sourceText;
const pointTextArray = thisComp.layer("PointText_" + layerNameNum).text.sourceText.split("$$");

// splitTextByWords 함수 정의
function splitTextByWords(text, words) {
let result = [];
let currentIndex = 0;

for (let i = 0; i < words.length; i++) {
const word = words[i];
const index = text.indexOf(word, currentIndex);

if (index !== -1) {
// 단어 이전의 텍스트를 결과에 추가
if (index > currentIndex) {
result.push(text.substring(currentIndex, index).trim());
}
result.push(word);
currentIndex = index + word.length;
}
// 해당 단어가 발견되지 않았을 때는 다음 단어를 찾기 위해 현재 인덱스를 유지
}

// 마지막 단어 이후의 텍스트를 결과에 추가
if (currentIndex < text.length) {
result.push(text.substring(currentIndex).trim());
}

// 결과 배열에서 빈 문자열을 필터링하여 반환
return result.filter(word => word !== "");
}

// 결과 계산
const thisLayerRenderText = splitTextByWords(totalText, pointTextArray);
[thisLayerRenderText]

포지션

const layerNameNum = parseInt(thisLayer.name.replace(/[^0-9]/g, ""))-1;
const totalText = thisComp.layer("Text_1").text.sourceText.toString();
const thisLayerText = thisLayer.text.sourceText.toString();

baseTextLayer = thisComp.layer("SecondLine_Render_Text_" + layerNameNum);
baseTextXPosition = baseTextLayer.transform.position[0];
baseTextWidth = baseTextLayer.sourceRectAtTime().width;

spaceBlankWidth = thisComp.layer("Control_Text_1").effect("Space_Blank_Width")("Slider");
spaceDefaultWidth = thisComp.layer("Control_Text_1").effect("Space_Default_Width")("Slider");

const checkSpaceBefore = (totalCheckText, word) => {
const thisTextindex = totalCheckText.indexOf(word);
return thisTextindex > 0 && totalCheckText[thisTextindex - 1] === ' ';
};

const spaceBefore = checkSpaceBefore(totalText, thisLayerText);

if (spaceBefore === true) {
x = baseTextXPosition + baseTextWidth + spaceBlankWidth;
} else {
x = baseTextXPosition + baseTextWidth + spaceDefaultWidth;
}

[x, baseTextLayer.transform.position[1]]
Categories
AE

[익스프레션] 포인트 텍스트 색칠하기(끝 점 찾기)

줄바꿈에 상관없이 포인트 텍스트의 끝 점을 찾는다

const pointTextArrayNum = 1;

const startIndex = thisComp.layer("RenderText").text.animator("Animator 1").selector("Range Selector " + pointTextArrayNum).start;
const pointText = thisComp.layer("PointText").text.sourceText.split("$$")[pointTextArrayNum-1];

[(startIndex == -1 || pointText == null) ? 0 : startIndex + pointText.length]
Categories
AE

[익스프레션] 포인트 텍스트 색칠하기(시작점 찾기)

줄바꿈에 상관없이 포인트 텍스트의 위치를 찾는다

const pointTextArrayNum = 1;

const renderText = thisComp.layer("RenderText")
  .text.sourceText.replace(/\r/g, "");
const pointTextArray = thisComp.layer("PointText")
  .text.sourceText.split("$$");


const findStartPositions = (renderText, pointTextArray, curIndex = 0) =>
	pointTextArray.map(pt => {
		const startIndex = renderText.indexOf(pt, curIndex);
		curIndex = (startIndex > 0 ? startIndex : curIndex) + pt.length;
		return startIndex;
	})

result = findStartPositions(renderText, pointTextArray);

[result[pointTextArrayNum-1] ?? -1]
Categories
AE

[익스프레션] 특정문구 아래 라인 만들기

특정 문구의 위치를 확인하여 밑줄 만들기

totalCount = thisComp.layer("Text").text.sourceText.split("\r").length;
lineCount = thisComp.layer("Text").text.sourceText.split("\r").findIndex(w => w.includes(thisComp.layer("underbarText").text.sourceText));

a=thisComp.layer("Text").sourceRectAtTime();
h=thisComp.layer("Text").transform.position[1]+(lineCount - totalCount)*79.56;
t=thisComp.layer("ControlEffect").effect("top")("Slider");
l=thisComp.layer("ControlEffect").effect("left")("Slider");

spaceValue = 12.68;
underbarText = thisComp.layer('underbarText');
leftLineText = thisComp.layer('leftLine');
uTWidth = underbarText.sourceRectAtTime().width;
flWidth = thisComp.layer('firstLine').sourceRectAtTime().width;
slWidth = thisComp.layer('secondLine').sourceRectAtTime().width;
llWidth = leftLineText.sourceRectAtTime().width;
lIndex = thisComp.layer("Text").text.sourceText.split("\r").findIndex(w => w.includes(thisComp.layer("underbarText").text.sourceText));

d = (flWidth - slWidth) / 2;
leftWidth = (lIndex ? (d > 0 ? d : 0) : (d > 0 ? 0 : Math.abs(d))) + llWidth; 
spaceWidth = thisComp.layer('Text').text.sourceText.split('\r')[lIndex].split(underbarText.text.sourceText)[0].replace(leftLineText.text.sourceText.trim(), '').length;

[(thisComp.width - a.width)/2 + leftWidth + spaceWidth * spaceValue + l, h + t]

Categories
AE

[익스프레션] 특정 문구 앞에 있는 문자 출력

특정 문구 앞에 있는 문자를 찾아서 출력하는 익스프레션

underbarText = thisComp.layer('underbarText').text.sourceText;
text.sourceText=thisComp.layer('Text').text.sourceText.split('\r').find(w => w.includes(underbarText))?.split(underbarText)[0];

Text레이어에 입력한 텍스트를 줄바꿈 기준으로 나누고, 그 중에서 underbarText를 포함한 줄을 찾은 다음, true면 underbarText를 기준으로 앞에 있는 텍스트를 출력함

Categories
AE

[익스프레션] 특정 문자열 끝나는 위치 찾기

익스프레션으로 특정 문자열이 끝나는 위치를 indexOf와 시작점으로 찾음

a=thisLayer.text.animator("Animator 1").selector("Range Selector 1").start;
t=thisComp.layer("searchText").text.sourceText.length;
n=thisLayer.text.sourceText;
m=n.indexOf(thisComp.layer("searchText").text.sourceText);
k=a+t;

if (m == -1) {
	[0]
} else {
	[k]
}

이 레이어의 텍스트 중에서 searchText의 텍스트와 일치하는텍스트의 시작점을 찾은값을 a로 두고, searchText 레이어의 길이(length)를 찾아 특정 문자열이 끝나는 위치를 값으로 찾음

만약 searchText와 완벽하게 일치하는 텍스트가 없으면 0을 출력하도록 if~else로 분기

Categories
AE

[익스프레션] 특정 문자열 위치 찾기

익스프레션으로 특정 문자열의 위치를 찾는 indexOf

a=thisLayer.text.sourceText;
b=a.indexOf(thisComp.layer("searchText").text.sourceText);
if (b == -1) {
	0
} else {
	[b]
}

이 레이어의 텍스트 중에서 searchText의 텍스트와 일치하는 텍스트를 찾아 그 시작 점(indexOf)을 값으로 찾음

만약 searchText와 완벽하게 일치하는 텍스트가 없으면 0을 출력하도록 if~else로 분기

Categories
AE

[익스프레션] 앵커 포인트 고정

sourceRectAtTime가 가지고 있는 속성으로 앵커 포인트 고정 또는 레이어 정보 불러오기

sourceRectAtTime은 4가지 속성을 가지고 있음

  1. left
  2. top
  3. width
  4. height

이를 활용해 레이어 또는 도형의 크기와 위치 값을 불러올 수 있음

a=sourceRectAtTime();
[a.left+a.width/2 , a.top+a.height/2]
Categories
AE

[익스프레션] 텍스트 스타일

텍스트 스타일 및 참조 텍스트 정의하기 익스프레션

myText = thisComp.layer("Text").text.sourceText;
myText.style.setText(myText.charAt(0));

익스프레션의 Text 레이어의 source Text 익스프레션에서 스타일과 불러올 참조 텍스트를 한 줄로 입력해야하므로 참조 텍스트를 setText 함수를 활용하여 작성함