首页 > 解决方案 > Nativescript 图像缩略图

问题描述

我正在使用带有 NativeScript 相机插件的 Angular 8.0 + NativeScript 6.0 来拍照并将它们存储在我的应用程序的图库中。当我列出我在应用程序中拍摄的图像时,它会加载全尺寸图像,这会减慢整个应用程序的速度。

有没有办法获得画廊图像的缩略图而不是完整图像?

目前,我通过将完整图像的 URL 存储在名为receipt_url 的字符串中并将其传递给后端来将完整图像的URL 保存在我的数据库中。这是我拍照并存储 URL 的代码;

onTakeReceiptTap(args) {
    requestPermissions().then(
        () => {
            takePicture({width: 640, height: 480, keepAspectRatio: true})
                .then((imageAsset: any) => {
                    this.receiptImage = imageAsset;

                    console.log("Taken receipt")
                    let that = this;

                    if (imageAsset.android) {
                        this._dataItem.receipt_url = imageAsset.android;
                    } else if (imageAsset.ios) {
                        this._dataItem.receipt_url = imageAsset.ios;
                    }

                }, (error) => {
                    console.log("Error: " + error);
                });
        },
        () => alert('permissions rejected')
    );
} // onTakeReceiptTap

执行列表时,我只需从数据库中获取所有记录,其中包括收据 url,然后像这样显示图片;

        <Image rowspan="2" col="1" [src]="item.receipt_url" stretch="aspectFit"></Image>

鉴于我所拥有的只是一个 URL,我想知道 Android/iOS 是否创建一个缩略图,我可以在其中获取 URL 并将其存储并在我的列表中使用,或者我是否必须以某种方式自己创建缩略图并发送来自后端的缩略图还是保存缩略图的 URL?

更新:虚拟滚动

我尝试像这样添加虚拟滚动,并尝试了不同的高度(150、500 和 1000),所有这些滚动仍然非常缓慢且生涩。

  <GridLayout row="1" columns="*, auto">
    <RadListView [items]="dataItems"
                 [filteringFunction]="filterItems"
                 pullToRefresh="true"
                 (pullToRefreshInitiated)="onPullToRefreshInitiated($event)">

      <ScrollView height="500">
        <ng-template tkListItemTemplate let-item="item">
          <StackLayout orientation="vertical">
            <GridLayout class="itemContainer" rows="50,*" columns="*,100">

              <!-- Currently these images are full size and slowing down the listing -->
              <Image rowspan="2" col="1" [src]="item.picture_url" stretch="aspectFit"></Image>

              <Label row="0" col="0" class="nameLabel" [text]="item.name"></Label>

            </GridLayout>

            <!-- <StackLayout orientation="horizontal">
                 <Label text="Price: "></Label>
                 <Label class="gross_centsLabel" [text]="item.gross_cents"></Label>
                 </StackLayout> -->
          </StackLayout>
        </ng-template>
      </ScrollView>

    </RadListView>
  </GridLayout>

更新:使用 ImageSource

如果我尝试对列表中的每个图像使用 ImageSource,则会收到以下错误;

LOG from device Galaxy S8: ERROR Error: java.lang.OutOfMemoryError: Failed to allocate a 36578316 byte allocation with 16269904 free bytes and 15MB until OOM

这是我设置 ImageSources 的方式;

loadData() {
    this._dataItemService.listing()
        .subscribe(loadedItems => {
            loadedItems.forEach((itemObject) => {
                itemObject.picture = fromFile(itemObject.picture_url);
                this._dataItems.unshift(itemObject) ;
            });
        })
}

'picture' 属性在数据模型中设置为 ImageSource。

更新:保存缩略图

我设法在前端保存了一个缩略图并将其显示在我的列表中。现在上市速度要快得多。

                    const source = new ImageSource();
                    source.fromAsset(imageAsset)
                        .then((imageSource: ImageSource) => {
                            const folderPath = knownFolders.documents().path;
                            const fileName = "test.jpg";
                            const filePath = path.join(folderPath, fileName);
                            const saved: boolean = imageSource.saveToFile(filePath, "jpg");
                            if (saved) {
                                console.log("Gallery: " + this._dataItem.picture_url);
                                console.log("Saved: " + filePath);
                                console.log("Image saved successfully!");
                            }
                        });

标签: angularimageandroid-cameranativescriptthumbnails

解决方案


如前所述,您可以在后端创建缩略图。我建议使用Sharp(或libvips)更快。

您可以做的另一件好事是避免使用*ngFor您知道会变得冗长的列表。改为使用ListView

ListView回收视图并仅渲染/加载应用程序需要的视图。从而避免加载到不可见的内存视图中。

<ListView [items]="countries" (itemTap)="onItemTap($event)" class="list-group">
    <ng-template let-item="item">
        <GridLayout class="itemContainer" rows="50,*" columns="*,100">
              <!-- Currently these images are full size and slowing down the listing -->
              <Image rowspan="2" col="1" [src]="item.picture_url" stretch="aspectFit"></Image>
              <Label row="0" col="0" class="nameLabel" [text]="item.name"></Lab
        </GridLayout>
    </ng-template>
</ListView>

更新:修复RadListView实现

在您的 实现中RadListView,有一个ScrollView内部。

请记住:

  • 在 RadListView 内,您必须仅使用项目的模板:<ng-template tkListItemTemplate let-item="item">...
  • ( RadListViewas the ListView) 是一个滚动小部件。你不需要一个ScrollView.
    <RadListView [items]="dataItems"
                 [filteringFunction]="filterItems"
                 pullToRefresh="true"
                 (pullToRefreshInitiated)="onPullToRefreshInitiated($event)">
        <ng-template tkListItemTemplate let-item="item">
            <GridLayout class="itemContainer" rows="50,*" columns="*,100">

              <!-- Currently these images are full size and slowing down the listing -->
              <Image rowspan="2" col="1" [src]="item.picture_url" stretch="aspectFit"></Image>

              <Label row="0" col="0" class="nameLabel" [text]="item.name"></Label>

            </GridLayout>
        </ng-template>
    </RadListView>

推荐阅读