Skip to content

fix(studio): make image background removal reliable - #3967

Closed
Miguel07Alm wants to merge 1 commit into
heygen-com:mainfrom
Miguel07Alm:fix/studio-image-background-removal
Closed

Miguel07Alm wants to merge 1 commit into
heygen-com:mainfrom
Miguel07Alm:fix/studio-image-background-removal

Conversation

@Miguel07Alm

Copy link
Copy Markdown
Contributor

Summary

  • Add a shared resolveProjectAssetPath helper so both classic and flat media property panels normalize project-local image/video src values (relative paths and Studio /api/projects/.../preview/... URLs) before calling remove-background.
  • Reject external http(s), data:, blob:, file:, protocol-relative, and non-preview /api URLs; strip query/hash; safely URI-decode; normalize ./ / .. segments.
  • Cover positive image Remove BG flows in both panels, path-normalization unit tests, and the studio-server JPG → default PNG cutout success path.

Test plan

  • bun run --cwd packages/studio test src/utils/projectAssetPath.test.ts src/components/editor/propertyPanelFlatMediaSection.test.tsx src/components/editor/propertyPanelMediaSection.test.tsx
  • bun run --cwd packages/studio-server test src/routes/media.test.ts
  • bunx oxlint + bunx oxfmt --check on changed files
  • In Studio: select a project-local image (including one whose preview src is an /api/projects/.../preview/... URL), confirm Remove BG is enabled, and that the cutout applies as a PNG under assets/cutouts/

Normalize project-local media src (including Studio preview URLs) so
Remove BG works for images in both property panels, and cover the
JPG-to-PNG default cutout path on the media route.
Copilot AI lite review requested due to automatic review settings September 15, 2026 21:32

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Moderate issues remain in path validation and nested-composition cutout path handling.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds shared project-asset path resolution for reliable background removal in Studio’s classic and flat media panels.

Changes:

  • Normalize and validate project-local asset paths and preview URLs.
  • Integrate resolution into both media panels.
  • Add resolver, cutout-flow, and JPG-to-PNG server tests.
File summaries
File Summary Review status
packages/studio/src/utils/projectAssetPath.ts Shared asset-path resolver Moderate changes needed for traversal rejection, origin/project validation, and nested bare-path handling.
packages/studio/src/utils/projectAssetPath.test.ts Resolver tests Add coverage for the identified traversal, external preview, and nested-source cases.
packages/studio/src/components/editor/propertyPanelMediaSection.tsx Classic panel integration Moderate change needed to write cutout paths relative to nested composition files.
packages/studio/src/components/editor/propertyPanelMediaSection.test.tsx Classic panel cutout tests Add nested-composition regression coverage.
packages/studio/src/components/editor/propertyPanelFlatMediaSection.tsx Flat panel integration Moderate change needed to write cutout paths relative to nested composition files.
packages/studio/src/components/editor/propertyPanelFlatMediaSection.test.tsx Flat panel cutout tests Add nested-composition regression coverage.
packages/studio-server/src/routes/media.test.ts JPG-to-PNG route coverage Adds coverage for the default PNG cutout output.
Review details

Suppressed comments (3)

packages/studio/src/components/editor/propertyPanelFlatMediaSection.tsx:91

  • Using sourceFile here makes the input path project-root relative for nested compositions, but applyCutoutResult later writes the server's project-root-relative result.outputPath directly back into the authored src. For an image in scenes/intro.html, assets/cutouts/...png resolves as scenes/assets/cutouts/...png, so the applied cutout is broken; convert the output back to a path relative to element.sourceFile and cover the nested case.
  const projectSrc = resolveProjectAssetPath(srcAttr, element.sourceFile || "index.html") ?? "";

packages/studio/src/components/editor/propertyPanelMediaSection.tsx:89

  • Using sourceFile here makes the input path project-root relative for nested compositions, but applyCutoutResult later writes the server's project-root-relative result.outputPath directly back into the authored src. For an image in scenes/intro.html, assets/cutouts/...png resolves as scenes/assets/cutouts/...png, so the applied cutout is broken; convert the output back to a path relative to element.sourceFile and cover the nested case.
  const projectSrc = resolveProjectAssetPath(srcAttr, element.sourceFile || "index.html") ?? "";

packages/studio/src/utils/projectAssetPath.ts:91

  • Only ./ and ../ references should be resolved against sourceFile; bare paths are the project-root convention in Studio previews. With this unconditional join, assets/photo.jpg from compositions/scene.html becomes compositions/assets/photo.jpg, so a valid nested-composition asset is sent to the wrong server path. Keep bare paths root-relative and add a nested-source test.
  if (!fromPreviewUrl) {
    const sourceDir = sourceFile.includes("/")
      ? sourceFile.slice(0, sourceFile.lastIndexOf("/"))
      : "";
    path = sourceDir ? `${sourceDir}/${path}` : path;
  • Files reviewed: 7/7 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +31 to +39
function normalizeRelativeSegments(path: string): string {
const parts = path.split("/");
const normalized: string[] = [];
for (const part of parts) {
if (!part || part === ".") continue;
if (part === "..") {
normalized.pop();
continue;
}
Comment on lines +64 to +68
if (/^https?:\/\//i.test(path)) {
try {
path = new URL(path).pathname;
} catch {
return null;
@miguel-heygen

Copy link
Copy Markdown
Collaborator

Superseded by #3969 — same change, opened from heygen-com as miguel-heygen (work).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants