C.W.K.
Stream
Lesson 03 of 05 · published

변형 없이 capture 하기

~12 min · uxp, capture, imaging-api, memory, non-destructive

Level 0툴 임차인
0 XP0/33 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"아티스트의 캔버스를 둘째 윈도우에 보여주려면, 픽셀을 읽어야 해 — flatten, merge, 또는 아직 작업 중인 document 를 건드리지 않고."

속기 쉽게 단순한 작업

Cinder 는 포토샵 캔버스에 뭐가 있는지 라이브 그림이 필요해. 사소하게 들려 — 그냥 이미지 가져와. 근데 document 가 아티스트의 활성 작업이야, 레이어로 가득하고, 편집 중이고. 레이어를 flatten 하거나 merge 하는 순진한 '이미지 가져오기' 는 아티스트가 그리는 바로 그걸 변형해. 진짜 작업은: document 를 전혀 안 바꾸고 캔버스의 composite 스냅샷을 읽는 거야.

옳은 도구: 읽기 전용 imaging 경로

플러그인 플랫폼이 document 의 composite 픽셀 — 모든 보이는 레이어가 한 이미지로 merge 된 — 을 document 변형 없이 읽기로 반환하는 imaging API 를 제공해. document 는 모든 레이어를 지키고; 넌 그것들의 flatten 된 view 만 받아. 이게 '이거 지금 어떻게 보여?'(읽기)랑 'document 를 flatten 해'(파괴적 변형)의 차이야. 같은 시각 결과, 아티스트 파일엔 완전히 다른 결과.

상태를 바꾸는 연산보다 스냅샷을 만드는 읽기를 선호해. 라이브 데이터의 flatten 또는 aggregate view 가 필요하면, source 를 그 모양으로 변형하는 게 아니라 그 view 를 계산해 반환하는 API 를 찾아. 읽기는 다음 읽기를 위해 source 를 온전히 남겨; 변형은 편도 문이야.

일부러 더 작은 이미지를 요청해

capture 가 target 크기를 요청해 — full 해상도 캔버스가 아니라 downscaled preview. 그냥 대역폭 절약이 아니야. 더 작은 target 요청은 플랫폼이 내부 image pyramid 에서 미리-downscaled 된 레벨을 서빙하게 해, 매번 full 이미지를 읽고 줄이는 것보다 극적으로 빨라. 아티스트가 작업하면서 업데이트되는 라이브 preview 엔, 빠르고-작음이 완벽하고-느림을 이겨. 작업에 옳은 크기는 목적을 서빙하는 가장 작은 크기야.

덜 요청하는 게 그냥 가벼운 게 아니라 빠를 수 있어. downscaled 결과 요청은 작은 payload 만이 아니야 — 많은 시스템이 cache 나 pyramid 에서 축소 버전을 full 만드는 것보다 훨씬 빨리 서빙할 수 있어. preview 만 필요하면, preview 해상도 요청이 양쪽 끝에서 성능 승리야, 받아들이는 품질 타협이 아니라.

필수 cleanup

날카로운 가장자리가 있어: capture 된 image data 가 호스트 앱 메모리를 들고, 각 capture 후 명시적으로 해제돼야 해. 해제를 건너뛰면, 반복 capture 하는 라이브 preview 에서, 플러그인이 호스트가 플러그인이 한계 넘었다고 경고할 때까지 꾸준히 메모리를 누수해. capture 는 바이트를 가졌을 때 끝난 게 아니야 — 메모리도 도로 건넸을 때 끝나. 모든 capture 가 acquire-use-release 고, release 는 선택이 아니야.

반복 연산에서, 빠진 cleanup 은 슬로모션 크래시야. 일회성 capture 에선 절대 안 알아챌 누수가 수백 번 발동하는 라이브 preview 에선 치명적이 돼. 위험이 반복으로 scale 해: 경로가 자주 돌수록, 빠진 release 가 빨리 누적돼. 모든 acquire 를 acquire 쓰는 순간 그 release 랑 짝지어, 반복 호출자가 나중에 안 봐주니까.

피파의 고백

처음에 양쪽 절반 다 틀렸어. flatten 하는 연산에 손 뻗었어 — 아티스트가 stroke 중인 document 를 변형했을 거란 걸 깨닫기 전까진. 그리고 release 를 까먹었어, 첫 일회성 테스트에선 안 중요했으니까; 누수는 preview 가 라이브고 끊임없이 발동하고서야 나타났어. 두 실수가 같은 교훈을 가르쳤어: 라이브, 반복 상태를 capture 하는 건 값 한 번 가져오는 것보다 더 조심이 필요해. 반복이 엉성한 읽기를 크래시로 바꾸는 거야.

Code

acquire, use, 그리고 선택 아닌 release·javascript
// 아티스트 document 변형 없이 composite 스냅샷을 읽어.
const { app, imaging } = require("photoshop");

// 1. acquire: composite 픽셀을 읽기로. layerID 생략 = full composite
//    (모든 보이는 레이어가 반환 view 로 merge; document 안 건드림).
//    targetSize 가 내부 image pyramid 에서 downscaled 레벨 요청
//    -> full 캔버스 읽고 + 줄이는 것보다 극적으로 빠름.
const obj = await imaging.getPixels({
  documentID: app.activeDocument.id,
  targetSize: { width: 512 },        // 일부러 preview 해상도
});

// 2. use: 작업실로 보낼 compact 형태로 encode.
const jpegBase64 = await imaging.encodeImageData({
  imageData: obj.imageData,
  base64: true,
});

// 3. RELEASE: 필수. 호스트 메모리를 즉시 도로 건넴.
obj.imageData.dispose();             // 라이브 preview 에서 이거 건너뜀 -> 누수 -> 크래시

// document 는 여전히 모든 레이어 가짐. 아무것도 flatten/merge 안 됨.

External links

Exercise

네 코드에서 라이브 source 로부터 도출/aggregate 상태를 읽는 곳을 찾아 (썸네일, 요약, 스냅샷). 두 점검: (1) 읽기가 source 를 변형해, 아니면 온전히 남겨? (2) 읽기가 명시적 release 필요한 자원을 acquire 해, 그러면 release 가 반복 경로에서도 보장돼? 빠진 거 고쳐.
Hint
점검 2 는 실패 양상이 반복에서만 나타나 — 일회성 테스트는 누수 있어도 통과해. 한 번이 아니라 천 번 도는 경우 뭐가 일어날지 추론해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.