如何从 Observable 中 return Imagebitmaps 数组

How to return an array of Imagebitmaps from within an Observable

我需要从一组 URL 创建一个 Imagebitmaps 的数组。 HTTP 请求应该与取消请求数组的能力并行完成,例如如果提供了一组新的 URL。

收到每个图像 blob 后,应将其转换为 Imagebitmap,并在将所有 Imagebitmap 作为数组返回给订阅者之前进行一些额外处理。

到目前为止我有这个:

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}'`))
})

以上代码满足:

  1. 并行 HTTP 请求
  2. 可以取消 HTTP 请求(在调用 nexImagesSubject.next() 时)
  3. 所有数据都作为数组返回给订阅者。

然而它不满足:

  1. Return Imagebitmap
  2. 的数组
  3. 不允许在收到后对 Blob 数据进行额外处理,即转换为 ImageBitmap

创建 Imagebitmap 很简单,但导致我出现问题的是对 Promise 的处理。例如:

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})});
     }))))

这不起作用,因为它不是从 map 返回的 {image, url, index}

如何在 pipe 中创建 Imagebitmap 并将所有 Imagebitmap 作为数组返回给订阅者(并满足上述其他要求)?

每个 url / 图片你有很多工作要做。我建议在这样的方法中定义所有每个 url 操作:

private async loadImageBitmap(url: string): Promise<ImageBitmap> {

    // Step 1: Load the blob for the single specified url.
    const blob = await this.beService.getImageBlob(url).toPromise();

    // Step 2: Create the ImageBitmap.
    const image = new ImageBitmap();

    // Step 3: Perform additional processing.
    /* Do some additional compute on image */

    return image;
}

有了这个指定,管道看起来更干净,更易读:

this.nextImagesSubscription = this.nextImagesSubject.pipe(
  map(urls => urls.map(url => this.loadImageBitmap(url))),
  switchMap(requests => combineLatest(requests))
).subscribe(images => {
  /* Do what ever you want with the images */
});

我唯一不确定的是取消部分:既不在我的代码中,也不在你的代码中。我不认为 http 请求会在另一组 url 发出时被取消。

要处理图像,您可以创建一个接受 Blob 和 returns ImageBitmap 的异步函数,例如:

async function processImage(blob: Blob): Promise<ImageBitmap> {
  const imageBitmap = await createImageBitmap(blob);

  //image post process ...

  return imageBitmap;
}

然后在您的 forkJoin 中使用 from 围绕函数调用的 Promise 创建一个 Observable。

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
    )
  )
)

干杯