Skip to content

Commit a4a4b13

Browse files
authored
fix: skip jimp processing for SVGs and prevent image-fill collapse (#298)
* fix: skip jimp processing for SVGs and prevent image-fill collapse Two fixes: 1. SVGs are vector files that jimp can't parse. Skip dimension detection and cropping for SVG downloads — just save the file. Previously this crashed with "Could not find MIME for Buffer". 2. The SVG container collapse logic was swallowing frames that contain image fills. A carousel with 4 image-filled children would cascade- collapse into a single IMAGE-SVG node, losing all child structure. Now checks for image fills in the subtree before collapsing. * perf: check only direct children for image fills during SVG collapse afterChildren runs bottom-up, so if a deeper descendant has image fills, its parent won't collapse and stays FRAME—which isn't SVG-eligible, naturally breaking the cascade. No need to walk the full subtree.
1 parent 0417766 commit a4a4b13

2 files changed

Lines changed: 33 additions & 1 deletion

File tree

src/extractors/built-in.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,8 @@ export function collapseSvgContainers(
239239

240240
if (
241241
(node.type === "FRAME" || node.type === "GROUP" || node.type === "INSTANCE") &&
242-
allChildrenAreSvgEligible
242+
allChildrenAreSvgEligible &&
243+
!hasImageFillInChildren(node)
243244
) {
244245
// Collapse to IMAGE-SVG and omit children
245246
result.type = "IMAGE-SVG";
@@ -249,3 +250,22 @@ export function collapseSvgContainers(
249250
// Include all children normally
250251
return children;
251252
}
253+
254+
/**
255+
* Check whether a node or its direct children have image fills.
256+
*
257+
* Only direct children need checking because afterChildren runs bottom-up:
258+
* if a deeper descendant has image fills, its parent won't collapse (stays FRAME),
259+
* and FRAME isn't SVG-eligible, so the chain breaks naturally at each level.
260+
*/
261+
function hasImageFillInChildren(node: FigmaDocumentNode): boolean {
262+
if (hasValue("fills", node) && node.fills.some((fill) => fill.type === "IMAGE")) {
263+
return true;
264+
}
265+
if (hasValue("children", node)) {
266+
return node.children.some(
267+
(child) => hasValue("fills", child) && child.fills.some((fill) => fill.type === "IMAGE"),
268+
);
269+
}
270+
return false;
271+
}

src/utils/image-processing.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,18 @@ export async function downloadAndProcessImage(
105105
const originalPath = await downloadFigmaImage(fileName, localPath, imageUrl);
106106
Logger.log(`Downloaded original image: ${originalPath}`);
107107

108+
// SVGs are vector — jimp can't read them and cropping/dimensions don't apply
109+
const isSvg = fileName.toLowerCase().endsWith(".svg");
110+
if (isSvg) {
111+
return {
112+
filePath: originalPath,
113+
originalDimensions: { width: 0, height: 0 },
114+
finalDimensions: { width: 0, height: 0 },
115+
wasCropped: false,
116+
processingLog,
117+
};
118+
}
119+
108120
// Get original dimensions before any processing
109121
const originalDimensions = await getImageDimensions(originalPath);
110122
Logger.log(`Original dimensions: ${originalDimensions.width}x${originalDimensions.height}`);

0 commit comments

Comments
 (0)