|
@@ -1,14 +1,149 @@
|
|
|
+import { store } from "@/features/mark/store";
|
|
|
+import { PictureSlice } from "@/types";
|
|
|
+
|
|
|
+// 把store.currentTask当做 weakRef ,当它不存在时,就丢弃它所有的图片
|
|
|
+const weakedMapImages = new WeakMap<Object, Map<string, HTMLImageElement>>();
|
|
|
+
|
|
|
/**
|
|
|
* 异步获取图片
|
|
|
* @param url 完整的图片路径
|
|
|
* @returns Promise<HTMLImageElement>
|
|
|
*/
|
|
|
export async function loadImage(url: string): Promise<HTMLImageElement> {
|
|
|
+ if (store.currentTask && weakedMapImages.get(store.currentTask)) {
|
|
|
+ const imagesCache = weakedMapImages.get(store.currentTask);
|
|
|
+ if (imagesCache) {
|
|
|
+ // console.log("cached image");
|
|
|
+ const image = imagesCache.get(url);
|
|
|
+ if (image) return image;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // else loading image
|
|
|
+
|
|
|
return new Promise((resolve, reject) => {
|
|
|
const image = new Image();
|
|
|
image.setAttribute("crossorigin", "anonymous");
|
|
|
image.src = url;
|
|
|
- image.onload = () => resolve(image);
|
|
|
+ image.onload = () => {
|
|
|
+ if (store.currentTask) {
|
|
|
+ let imagesCache = weakedMapImages.get(store.currentTask);
|
|
|
+ if (!imagesCache) {
|
|
|
+ imagesCache = new Map<string, HTMLImageElement>();
|
|
|
+ weakedMapImages.set(store.currentTask, imagesCache);
|
|
|
+ }
|
|
|
+ imagesCache.set(url, image);
|
|
|
+ }
|
|
|
+ resolve(image);
|
|
|
+ };
|
|
|
image.onerror = reject;
|
|
|
});
|
|
|
}
|
|
|
+
|
|
|
+// 存放当前task的切片图的dataur
|
|
|
+const weakedMapDataUrls = new WeakMap<Object, Map<string, string>>();
|
|
|
+export function getDataUrlForSliceConfig(
|
|
|
+ image: HTMLImageElement,
|
|
|
+ sliceConfig: PictureSlice,
|
|
|
+ maxSliceWidth: number,
|
|
|
+ urlForCache: string
|
|
|
+) {
|
|
|
+ const { i, x, y, w, h } = sliceConfig;
|
|
|
+ const key = `${urlForCache}-${i}-${x}-${y}-${w}-${h}`;
|
|
|
+
|
|
|
+ if (store.currentTask && weakedMapDataUrls.get(store.currentTask)) {
|
|
|
+ const dataUrlsCache = weakedMapDataUrls.get(store.currentTask);
|
|
|
+ if (dataUrlsCache) {
|
|
|
+ // console.log("cached canvas");
|
|
|
+ const image = dataUrlsCache.get(key);
|
|
|
+ if (image) return image;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const canvas = document.createElement("canvas");
|
|
|
+ canvas.width = Math.max(sliceConfig.w, maxSliceWidth);
|
|
|
+ canvas.height = sliceConfig.h;
|
|
|
+ const ctx = canvas.getContext("2d");
|
|
|
+ if (!ctx) {
|
|
|
+ console.log('canvas.getContext("2d") error');
|
|
|
+ }
|
|
|
+ // drawImage 画图软件透明色
|
|
|
+ ctx?.drawImage(
|
|
|
+ image,
|
|
|
+ sliceConfig.x,
|
|
|
+ sliceConfig.y,
|
|
|
+ sliceConfig.w,
|
|
|
+ sliceConfig.h,
|
|
|
+ 0,
|
|
|
+ 0,
|
|
|
+ sliceConfig.w,
|
|
|
+ sliceConfig.h
|
|
|
+ );
|
|
|
+ // console.log(image, canvas.height, sliceConfig, ctx);
|
|
|
+ // console.log(canvas.toDataURL());
|
|
|
+
|
|
|
+ // 如果用toBlob,则产生异步,而且URL.createObjectURL还会需要手动释放
|
|
|
+ const dataurl = canvas.toDataURL();
|
|
|
+ if (store.currentTask) {
|
|
|
+ let dataUrlsCache = weakedMapDataUrls.get(store.currentTask);
|
|
|
+ if (!dataUrlsCache) {
|
|
|
+ dataUrlsCache = new Map<string, string>();
|
|
|
+ weakedMapDataUrls.set(store.currentTask, dataUrlsCache);
|
|
|
+ }
|
|
|
+ dataUrlsCache.set(key, dataurl);
|
|
|
+ }
|
|
|
+
|
|
|
+ return dataurl;
|
|
|
+}
|
|
|
+
|
|
|
+export function getDataUrlForSplitConfig(
|
|
|
+ image: HTMLImageElement,
|
|
|
+ config: [number, number],
|
|
|
+ maxSliceWidth: number,
|
|
|
+ urlForCache: string
|
|
|
+) {
|
|
|
+ const [start, end] = config;
|
|
|
+ const key = `${urlForCache}-${start}-${end}`;
|
|
|
+ if (store.currentTask && weakedMapDataUrls.get(store.currentTask)) {
|
|
|
+ const dataUrlsCache = weakedMapDataUrls.get(store.currentTask);
|
|
|
+ if (dataUrlsCache) {
|
|
|
+ // console.log("cached canvas");
|
|
|
+ const image = dataUrlsCache.get(key);
|
|
|
+ if (image) return image;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const width = image.naturalWidth * (end - start);
|
|
|
+ const canvas = document.createElement("canvas");
|
|
|
+ canvas.width = Math.max(width, maxSliceWidth);
|
|
|
+ canvas.height = image.naturalHeight;
|
|
|
+ const ctx = canvas.getContext("2d");
|
|
|
+ if (!ctx) {
|
|
|
+ console.log('canvas.getContext("2d") error');
|
|
|
+ }
|
|
|
+ // drawImage 画图软件透明色
|
|
|
+ ctx?.drawImage(
|
|
|
+ image,
|
|
|
+ image.naturalWidth * start,
|
|
|
+ 0,
|
|
|
+ image.naturalWidth * end,
|
|
|
+ image.naturalHeight,
|
|
|
+ 0,
|
|
|
+ 0,
|
|
|
+ image.naturalWidth * end,
|
|
|
+ image.naturalHeight
|
|
|
+ );
|
|
|
+
|
|
|
+ // 如果用toBlob,则产生异步,而且URL.createObjectURL还会需要手动释放
|
|
|
+ const dataurl = canvas.toDataURL();
|
|
|
+ if (store.currentTask) {
|
|
|
+ let dataUrlsCache = weakedMapDataUrls.get(store.currentTask);
|
|
|
+ if (!dataUrlsCache) {
|
|
|
+ dataUrlsCache = new Map<string, string>();
|
|
|
+ weakedMapDataUrls.set(store.currentTask, dataUrlsCache);
|
|
|
+ }
|
|
|
+ dataUrlsCache.set(key, dataurl);
|
|
|
+ }
|
|
|
+
|
|
|
+ return dataurl;
|
|
|
+}
|