Skip to main content

I encountered an odd problem about using “figma.createImage” to create a image hash. I have 3000+ image urls, I want to fetch image data, then convert to image hash  to display. When an error occurs, the console shows: "in :<unknow> Attempted to invoke callback with invalid id -xxxx". Are there any limitations on fetching images in Figma?

this is call stack:

It seems fine when image requests are fewer than 2,000, but ​​when they exceed 2,000​​, errors often occur.

 

code:

interface ImageLoadTask {
figmaElement: RectangleNode | FrameNode
url: string
width: number
height: number
transform?: number[]
depth: number
}

const ImageLoader = {
queue: [] as ImageLoadTask[],
MAX_IMAGES_PER_SECOND: 500,
isProcessing: false,
imageUrl2Hash: {} as Record<string, string>,
imageUrl2Promise: {} as Record<string, Promise<string>>,

async load(
figmaElement: RectangleNode | FrameNode,
url: string,
width = -1,
height = -1,
transform?: number[],
depth = 0,
): Promise<void> {
this.queue.push({ figmaElement, url, width, height, transform, depth })
if (!this.isProcessing) {
this.isProcessing = true
await this.processQueue()
}
},

async processQueue(): Promise<void> {
while (this.queue.length) {
const batch = this.queue.splice(0, this.MAX_IMAGES_PER_SECOND)
await Promise.all(
batch.map((task) =>
this.loadImageFromUrl(task.figmaElement, task.url, task.depth),
),
)
await new Promise((resolve) => setTimeout(resolve, 1000))
}
this.isProcessing = false
},

async loadImageFromUrl(
figmaElement: RectangleNode | FrameNode,
urlRaw: string,
depth = 0,
): Promise<void> {
const url = urlRaw.replace(/^http:/, 'https:')
try {
const hash = await this.fetchAndStoreImageHash(url)
figmaElement.fills = [
{
type: 'IMAGE',
scaleMode: figmaElement.type === 'FRAME' ? 'FIT' : 'CROP',
imageHash: hash,
},
]
} catch (e) {
figmaElement.fills = [{ type: 'SOLID', color: { r: 1, g: 1, b: 1 } }]
}
},

fetchAndStoreImageHash(url: string): Promise<string> {
if (this.imageUrl2Hash[url]) {
return Promise.resolve(this.imageUrl2Hash[url])
}
if (this.imageUrl2Promise[url]) {
return this.imageUrl2Promise[url]
}
const p = fetch(url)
.then((r) => r.arrayBuffer())
.then((buf) => {
const hash = figma.createImage(new Uint8Array(buf)).hash
this.imageUrl2Hash[url] = hash
delete this.imageUrl2Promise[url]
return hash
})
.catch((e) => {
delete this.imageUrl2Promise[url]
throw e
})
this.imageUrl2Promise[url] = p
return p
},
}

 

Be the first to reply!