Bläddra i källkod

缓存 & 提前绘制裁切图

Michael Wang 4 år sedan
förälder
incheckning
a8ce6d9f62
3 ändrade filer med 90 tillägg och 22 borttagningar
  1. 5 5
      src/features/mark/CommonMarkBody.vue
  2. 5 3
      src/features/mark/Mark.vue
  3. 80 14
      src/utils/utils.ts

+ 5 - 5
src/features/mark/CommonMarkBody.vue

@@ -167,12 +167,12 @@ export default defineComponent({
         const indexInSliceUrls = sliceConfig.i;
         const image = images[indexInSliceUrls - 1];
 
-        const dataUrl = await getDataUrlForSliceConfig(
+        const dataUrl = (await getDataUrlForSliceConfig(
           image,
           sliceConfig,
           maxSliceWidth,
           url
-        );
+        )) as string;
 
         let trackLists = [] as Array<Track>;
         if (useMarkResult) {
@@ -259,16 +259,16 @@ export default defineComponent({
       for (const url of store.currentTask.sliceUrls) {
         for (const config of splitConfigPairs) {
           const indexInSliceUrls = store.currentTask.sliceUrls.indexOf(url) + 1;
-          const image = images[store.currentTask.sliceUrls.indexOf(url)];
+          const image = images[indexInSliceUrls - 1];
 
           accumBottomHeight += image.naturalHeight;
 
-          const dataUrl = await getDataUrlForSplitConfig(
+          const dataUrl = (await getDataUrlForSplitConfig(
             image,
             config,
             maxSliceWidth,
             url
-          );
+          )) as string;
 
           let trackLists = [] as Array<Track>;
           if (useMarkResult) {

+ 5 - 3
src/features/mark/Mark.vue

@@ -63,6 +63,7 @@ import MinimapModal from "./MinimapModal.vue";
 import AllPaperModal from "./AllPaperModal.vue";
 import SheetViewModal from "./SheetViewModal.vue";
 import SpecialTagModal from "./SpecialTagModal.vue";
+import { preDrawImage } from "@/utils/utils";
 
 export default defineComponent({
   name: "Mark",
@@ -147,9 +148,10 @@ export default defineComponent({
           // 如果不是当前任务,则先等3秒再去取任务,以免和其他请求争夺网络资源
           await new Promise((resolve) => setTimeout(resolve, 3000));
         }
-        for (const sliceUrl of (res.data as Task).sliceUrls) {
-          fetch(sliceUrl);
-        }
+        // for (const sliceUrl of (res.data as Task).sliceUrls) {
+        //   fetch(sliceUrl);
+        // }
+        preDrawImage(res.data);
       } else {
         store.message = res.data.message;
       }

+ 80 - 14
src/utils/utils.ts

@@ -1,5 +1,5 @@
 import { store } from "@/features/mark/store";
-import { PictureSlice } from "@/types";
+import { PictureSlice, Task } from "@/types";
 
 // TODO: 打开cache后,会造成没有 vue devtools 时,canvas缓存错误,暂时不知道原因
 // 通过回看的测试,打开回看,再关闭回看,稍等一会儿再打开回看,确实可以看到该缓存时缓存了,该丢弃时丢弃了
@@ -90,6 +90,15 @@ export async function getDataUrlForSliceConfig(
   });
   const dataurl = URL.createObjectURL(blob);
 
+  cacheFIFO();
+
+  objectUrlMap.set(key, dataurl);
+
+  return dataurl;
+}
+
+// 清理缓存的过时数据(清除头10张),First in first out
+function cacheFIFO() {
   if (objectUrlMap.size > OBJECT_URLS_MAP_MAX_SIZE) {
     const ary = [...objectUrlMap.entries()];
     const toRelease = ary.splice(0, 10);
@@ -98,10 +107,6 @@ export async function getDataUrlForSliceConfig(
     }
     objectUrlMap = new Map(ary);
   }
-
-  objectUrlMap.set(key, dataurl);
-
-  return dataurl;
 }
 
 export async function getDataUrlForSplitConfig(
@@ -145,16 +150,77 @@ export async function getDataUrlForSplitConfig(
     canvas.toBlob(res);
   });
   const dataurl = URL.createObjectURL(blob);
-
-  if (objectUrlMap.size > OBJECT_URLS_MAP_MAX_SIZE) {
-    const ary = [...objectUrlMap.entries()];
-    const toRelease = ary.splice(0, 10);
-    for (const u of toRelease) {
-      URL.revokeObjectURL(u[1]);
-    }
-    objectUrlMap = new Map(ary);
-  }
+  cacheFIFO();
 
   objectUrlMap.set(key, dataurl);
   return dataurl;
 }
+
+export async function preDrawImage(_currentTask: Task) {
+  if (!_currentTask?.libraryId) return;
+
+  let maxSliceWidth = 0; // 最大的裁切块宽度,图片容器以此为准
+
+  const hasSliceConfig = store.currentTask?.sliceConfig?.length;
+
+  const images = [];
+  const urls = [];
+
+  if (hasSliceConfig) {
+    // 必须要先加载一遍,把“选择整图”的宽高重置后,再算总高度
+    for (const sliceConfig of _currentTask.sliceConfig) {
+      const url = _currentTask.sliceUrls[sliceConfig.i - 1];
+      const image = await loadImage(url);
+      images.push(image);
+      urls.push(url);
+      if (sliceConfig.w === 0 && sliceConfig.h === 0) {
+        // 选择整图时,w/h 为0
+        sliceConfig.w = image.naturalWidth;
+        sliceConfig.h = image.naturalHeight;
+      }
+    }
+
+    maxSliceWidth = Math.max(..._currentTask.sliceConfig.map((v) => v.w));
+
+    // 用来保存sliceImage在整个图片容器中(不包括image-seperator)的高度范围
+    for (const sliceConfig of _currentTask.sliceConfig) {
+      const url = _currentTask.sliceUrls[sliceConfig.i - 1];
+      const indexInSliceUrls = sliceConfig.i;
+      const image = images[indexInSliceUrls - 1];
+
+      (await getDataUrlForSliceConfig(
+        image,
+        sliceConfig,
+        maxSliceWidth,
+        url
+      )) as string;
+    }
+  } else {
+    for (const url of _currentTask.sliceUrls) {
+      const image = await loadImage(url);
+      images.push(image);
+    }
+
+    const splitConfigPairs = store.setting.splitConfig
+      .map((v, index, ary) => (index % 2 === 0 ? [v, ary[index + 1]] : false))
+      .filter((v) => v) as unknown as Array<[number, number]>;
+
+    const maxSplitConfig = Math.max(...store.setting.splitConfig);
+    maxSliceWidth =
+      Math.max(...images.map((v) => v.naturalWidth)) * maxSplitConfig;
+
+    for (const url of _currentTask.sliceUrls) {
+      for (const config of splitConfigPairs) {
+        const indexInSliceUrls = _currentTask.sliceUrls.indexOf(url) + 1;
+        const image = images[indexInSliceUrls - 1];
+
+        (await getDataUrlForSplitConfig(
+          image,
+          config,
+          maxSliceWidth,
+          url
+        )) as string;
+      }
+    }
+  }
+}