I have a requirement to create an array of Imagebitmaps from an array of URLs. HTTP requests should be done in parallel with the ability to cancel the array of requests e.g. if a new array of URLs is provided.
Upon the receipt of each image blob it should be transformed into an Imagebitmap and be subject to some additional processing before ALL the Imagebitmaps are returned as an array to a subscriber.
So far I have this:
this.nextImagesSubscription = this.nextImagesSubject.pipe(switchMap((urls: string[]) => {
console.log(`received new images`)
return forkJoin(urls.map((url, index) => this.beService.getImageBlob(url).pipe(map(blob => ({blob, url, index})))))
})).subscribe((blobData: {blob: Blob, url: string, index: number}[]) => {
console.log(`Received blobs: ${blobData.length}`);
blobData.forEach(image => console.log(`${image.index}: '${image.url}'`))
})
The above code satisfies:
nexImagesSubject.next()
)However it does NOT satisfy:
Imagebitmap
ImageBitmap
.Creating an Imagebitmap is straightforward but it is the handling of the Promise that is causing me issues. For example:
return forkJoin(urls.map((url, index) => this.beService.getImageBlob(url)
.pipe(map(blob => {
createImageBitmap(blob).then(image => {
/* Do some additional compute on image */
return ({image, url, index})});
}))))
This does not work because it is not {image, url, index}
that is returned from the map
.
How can I create the Imagebitmap in the pipe
and have ALL the Imagebitmaps returned as an array to the subscriber (and fulfill the other requirments mentioned above)?
To process the images you can create an async function that accepts the Blob and returns the ImageBitmap, like:
async function processImage(blob: Blob): Promise<ImageBitmap> {
const imageBitmap = await createImageBitmap(blob);
//image post process ...
return imageBitmap;
}
And then in your forkJoin
use from
to create an Observable around the Promise of the function call.
return forkJoin(
urls.map((url, index) =>
this.beService.getImageBlob(url).pipe(
switchMap(blob => from(processImage(blob))),
map(image => ({ image, url, index })) //<- Only required if you want to export also the url and index
)
)
)
Cheers