@eternalheart/vue-file-preview 1.5.4 → 1.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/lib/chunks/{index-DX_csr-A.mjs → index-7BsnK6tk.mjs} +67 -67
  2. package/lib/chunks/{index-DX_csr-A.mjs.map → index-7BsnK6tk.mjs.map} +1 -1
  3. package/lib/chunks/{index-CeQ3X5A0.mjs → index-BPqo3A5l.mjs} +31 -31
  4. package/lib/chunks/{index-CeQ3X5A0.mjs.map → index-BPqo3A5l.mjs.map} +1 -1
  5. package/lib/chunks/{index-CftjnCD3.mjs → index-BS5s-1VM.mjs} +2 -2
  6. package/lib/chunks/{index-CftjnCD3.mjs.map → index-BS5s-1VM.mjs.map} +1 -1
  7. package/lib/chunks/{index-D6e4OqEP.mjs → index-BT3eCnY-.mjs} +561 -481
  8. package/lib/chunks/index-BT3eCnY-.mjs.map +1 -0
  9. package/lib/chunks/{index-ClxPMbSW.mjs → index-BbeGqRx_.mjs} +18 -18
  10. package/lib/chunks/{index-ClxPMbSW.mjs.map → index-BbeGqRx_.mjs.map} +1 -1
  11. package/lib/chunks/{index-BNub3BMM.mjs → index-C0ECy9HN.mjs} +32 -32
  12. package/lib/chunks/{index-BNub3BMM.mjs.map → index-C0ECy9HN.mjs.map} +1 -1
  13. package/lib/chunks/{index-MpkzsEnQ.mjs → index-C7LwvE1J.mjs} +21 -21
  14. package/lib/chunks/{index-MpkzsEnQ.mjs.map → index-C7LwvE1J.mjs.map} +1 -1
  15. package/lib/chunks/{index-DFgOIsmL.mjs → index-CFg_fG9C.mjs} +99 -81
  16. package/lib/chunks/index-CFg_fG9C.mjs.map +1 -0
  17. package/lib/chunks/{index-CiNV11PZ.mjs → index-CMuseCKM.mjs} +2 -2
  18. package/lib/chunks/{index-CiNV11PZ.mjs.map → index-CMuseCKM.mjs.map} +1 -1
  19. package/lib/chunks/{index-y-o-uhN7.mjs → index-CSoHcoT7.mjs} +2 -2
  20. package/lib/chunks/{index-y-o-uhN7.mjs.map → index-CSoHcoT7.mjs.map} +1 -1
  21. package/lib/chunks/{index-BOqceW1a.mjs → index-CWpPLr2T.mjs} +21 -21
  22. package/lib/chunks/{index-BOqceW1a.mjs.map → index-CWpPLr2T.mjs.map} +1 -1
  23. package/lib/chunks/{index-JukJdgu9.mjs → index-DBvTfFQh.mjs} +2 -2
  24. package/lib/chunks/{index-JukJdgu9.mjs.map → index-DBvTfFQh.mjs.map} +1 -1
  25. package/lib/chunks/{index-IMsmPEyV.mjs → index-DOR4QbyZ.mjs} +2 -2
  26. package/lib/chunks/{index-IMsmPEyV.mjs.map → index-DOR4QbyZ.mjs.map} +1 -1
  27. package/lib/chunks/{index-C3LVlj74.mjs → index-DgSQ23bq.mjs} +2 -2
  28. package/lib/chunks/{index-C3LVlj74.mjs.map → index-DgSQ23bq.mjs.map} +1 -1
  29. package/lib/chunks/{index-Cknc_5FD.mjs → index-EDVCM75e.mjs} +14 -14
  30. package/lib/chunks/{index-Cknc_5FD.mjs.map → index-EDVCM75e.mjs.map} +1 -1
  31. package/lib/chunks/{index-DJuJHCEr.mjs → index-JjIHjBoy.mjs} +8 -8
  32. package/lib/chunks/{index-DJuJHCEr.mjs.map → index-JjIHjBoy.mjs.map} +1 -1
  33. package/lib/chunks/{index-_LiTOnzg.mjs → index-LTS1Kvcb.mjs} +15 -15
  34. package/lib/chunks/{index-_LiTOnzg.mjs.map → index-LTS1Kvcb.mjs.map} +1 -1
  35. package/lib/chunks/{index-vAawymJZ.mjs → index-osDrgXb8.mjs} +15 -15
  36. package/lib/chunks/{index-vAawymJZ.mjs.map → index-osDrgXb8.mjs.map} +1 -1
  37. package/lib/chunks/{index-BA78ONnG.mjs → index-qW8LA0vV.mjs} +24 -24
  38. package/lib/chunks/{index-BA78ONnG.mjs.map → index-qW8LA0vV.mjs.map} +1 -1
  39. package/lib/chunks/{useShikiHighlight-P6H6Zwbu.mjs → useShikiHighlight-CopYqwcg.mjs} +6 -6
  40. package/lib/chunks/{useShikiHighlight-P6H6Zwbu.mjs.map → useShikiHighlight-CopYqwcg.mjs.map} +1 -1
  41. package/lib/index.cjs +39 -39
  42. package/lib/index.cjs.map +1 -1
  43. package/lib/index.d.ts.map +1 -1
  44. package/lib/index.mjs +11 -12
  45. package/lib/index.mjs.map +1 -1
  46. package/lib/renderers/Pdf/index.vue.d.ts.map +1 -1
  47. package/package.json +1 -1
  48. package/lib/chunks/index-D6e4OqEP.mjs.map +0 -1
  49. package/lib/chunks/index-DFgOIsmL.mjs.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import { defineComponent as Me, ref as s, watch as H, onBeforeUnmount as ee, onMounted as _e, computed as te, openBlock as x, createElementBlock as C, normalizeStyle as ae, createVNode as Re, unref as le, createElementVNode as X, createTextVNode as Le, toDisplayString as S, createCommentVNode as L, createBlock as oe, normalizeClass as ke } from "vue";
2
2
  import { ZoomOut as Ee, ZoomIn as Ce, Scan as Te, Maximize2 as Ue, RotateCcw as Ye, RotateCw as ze, RefreshCw as Se, Loader2 as Xe } from "lucide-vue-next";
3
- import { u as De, G as We, q as Be, C as Oe } from "./index-D6e4OqEP.mjs";
3
+ import { u as De, n as We, o as Be, N as Oe } from "./index-BT3eCnY-.mjs";
4
4
  import { _ as ne } from "./RendererError.vue_vue_type_script_setup_true_lang-BNoENOWX.mjs";
5
5
  import { T as je } from "./base.types-DaftHyg7.mjs";
6
6
  const Pe = {
@@ -9,13 +9,13 @@ const Pe = {
9
9
  }, $e = { class: "vfp-mt-4 vfp-text-fg-secondary" }, He = { key: 0 }, Ze = {
10
10
  key: 2,
11
11
  class: "vfp-flex vfp-items-center vfp-justify-center"
12
- }, Ne = ["src"], Ge = {
12
+ }, Ne = ["src"], Ve = {
13
13
  key: 5,
14
14
  class: "vfp-absolute vfp-bottom-2 vfp-right-3 vfp-text-[10px] vfp-text-fg-disabled hover:vfp-text-fg-secondary vfp-transition-colors vfp-pointer-events-auto vfp-select-none vfp-cursor-default"
15
- }, Ve = {
15
+ }, Fe = {
16
16
  key: 6,
17
17
  class: "vfp-absolute vfp-bottom-2 vfp-left-1/2 -vfp-translate-x-1/2 vfp-flex vfp-items-center vfp-gap-2 vfp-px-3 vfp-py-1.5 vfp-bg-surface-toolbar vfp-border vfp-border-line vfp-rounded-lg vfp-text-sm vfp-text-fg-primary vfp-shadow-md"
18
- }, qe = ["disabled"], Fe = { class: "vfp-text-fg-secondary vfp-tabular-nums" }, Ie = ["disabled"], at = /* @__PURE__ */ Me({
18
+ }, Ge = ["disabled"], Ie = { class: "vfp-text-fg-secondary vfp-tabular-nums" }, Ae = ["disabled"], at = /* @__PURE__ */ Me({
19
19
  __name: "index",
20
20
  props: {
21
21
  url: {},
@@ -23,11 +23,11 @@ const Pe = {
23
23
  file: {}
24
24
  },
25
25
  setup(se, { expose: ie }) {
26
- const f = se, G = new je(), { t: m } = De(), i = s(1), k = s(0), E = s(!1), w = s(null), d = s(!1), D = s(0), M = s(null), _ = s(""), R = s(1), T = s(1), V = s(!1), o = s({ x: 0, y: 0 }), g = s(!1);
26
+ const f = se, V = new je(), { t: m } = De(), i = s(1), k = s(0), E = s(!1), w = s(null), d = s(!1), D = s(0), M = s(null), _ = s(""), R = s(1), T = s(1), F = s(!1), o = s({ x: 0, y: 0 }), g = s(!1);
27
27
  let U = { x: 0, y: 0 };
28
28
  const h = s(1), r = s({ width: 0, height: 0 });
29
29
  H([i, k], () => {
30
- G.notify();
30
+ V.notify();
31
31
  }), ie({
32
32
  getToolbarGroups: () => [
33
33
  {
@@ -59,7 +59,7 @@ const Pe = {
59
59
  type: "button",
60
60
  icon: Te,
61
61
  tooltip: m.value("toolbar.fit_to_window"),
62
- action: q
62
+ action: G
63
63
  },
64
64
  {
65
65
  type: "button",
@@ -96,7 +96,7 @@ const Pe = {
96
96
  ]
97
97
  }
98
98
  ],
99
- onToolbarChange: (e) => G.subscribe(e)
99
+ onToolbarChange: (e) => V.subscribe(e)
100
100
  });
101
101
  const ue = () => {
102
102
  i.value = Math.min(i.value + 0.1, 10);
@@ -109,8 +109,8 @@ const Pe = {
109
109
  }, fe = () => {
110
110
  i.value = 1, k.value = 0, o.value = { x: 0, y: 0 };
111
111
  }, de = () => {
112
- q();
113
- }, q = () => {
112
+ G();
113
+ }, G = () => {
114
114
  if (v.value && r.value.width > 0 && r.value.height > 0) {
115
115
  const e = v.value.clientWidth, t = v.value.clientHeight, a = e / r.value.width, u = t / r.value.height;
116
116
  i.value = Math.max(0.01, Math.min(10, Math.min(a, u))), o.value = { x: 0, y: 0 };
@@ -118,11 +118,11 @@ const Pe = {
118
118
  }, he = s(null), v = s(null);
119
119
  let Y = null, W = null, B = null;
120
120
  const p = /* @__PURE__ */ new Map();
121
- let O = !1, j = 0, F = 1, Z = { x: 0, y: 0 }, I = 0;
121
+ let O = !1, j = 0, I = 1, Z = { x: 0, y: 0 }, A = 0;
122
122
  H(
123
123
  () => [f.url, f.file],
124
124
  async () => {
125
- if (_.value = "", E.value = !1, w.value = null, d.value = !1, M.value = null, D.value = 0, o.value = { x: 0, y: 0 }, h.value = 1, i.value = 1, R.value = 1, T.value = 1, V.value = !1, Y && (URL.revokeObjectURL(Y), Y = null), p.forEach((e) => URL.revokeObjectURL(e)), p.clear(), W = null, B = null, !f.file) {
125
+ if (_.value = "", E.value = !1, w.value = null, d.value = !1, M.value = null, D.value = 0, o.value = { x: 0, y: 0 }, h.value = 1, i.value = 1, R.value = 1, T.value = 1, F.value = !1, Y && (URL.revokeObjectURL(Y), Y = null), p.forEach((e) => URL.revokeObjectURL(e)), p.clear(), W = null, B = null, !f.file) {
126
126
  _.value = f.url;
127
127
  return;
128
128
  }
@@ -141,7 +141,7 @@ const Pe = {
141
141
  if (!l.ok) throw new Error("Failed to fetch file");
142
142
  a = await l.blob();
143
143
  }
144
- if (W = a, B = t, e.startsWith("image/x-") && (V.value = !0), t.getMetadata)
144
+ if (W = a, B = t, e.startsWith("image/x-") && (F.value = !0), t.getMetadata)
145
145
  try {
146
146
  const l = await t.getMetadata(a);
147
147
  l.pageCount && l.pageCount > 1 && (T.value = l.pageCount);
@@ -161,7 +161,7 @@ const Pe = {
161
161
  },
162
162
  { immediate: !0 }
163
163
  );
164
- const A = async (e) => {
164
+ const K = async (e) => {
165
165
  if (!W || !B || e < 1 || e > T.value) return;
166
166
  const t = p.get(e);
167
167
  if (t) {
@@ -226,10 +226,10 @@ const Pe = {
226
226
  };
227
227
  _e(() => {
228
228
  const e = v.value;
229
- e && (e.addEventListener("wheel", N, { passive: !1 }), e.addEventListener("touchstart", Q, { passive: !1 }), e.addEventListener("touchmove", J, { passive: !1 }), e.addEventListener("touchend", $), e.addEventListener("touchcancel", $));
229
+ e && (e.addEventListener("wheel", N, { passive: !1 }), e.addEventListener("touchstart", q, { passive: !1 }), e.addEventListener("touchmove", J, { passive: !1 }), e.addEventListener("touchend", $), e.addEventListener("touchcancel", $));
230
230
  }), ee(() => {
231
231
  const e = v.value;
232
- e && (e.removeEventListener("wheel", N), e.removeEventListener("touchstart", Q), e.removeEventListener("touchmove", J), e.removeEventListener("touchend", $), e.removeEventListener("touchcancel", $));
232
+ e && (e.removeEventListener("wheel", N), e.removeEventListener("touchstart", q), e.removeEventListener("touchmove", J), e.removeEventListener("touchend", $), e.removeEventListener("touchcancel", $));
233
233
  });
234
234
  const ye = (e) => {
235
235
  O || e.button === 0 && (g.value = !0, U = {
@@ -244,9 +244,9 @@ const Pe = {
244
244
  },
245
245
  h.value
246
246
  ));
247
- }, K = () => {
247
+ }, Q = () => {
248
248
  O || (g.value = !1);
249
- }, Q = (e) => {
249
+ }, q = (e) => {
250
250
  O = !0, e.preventDefault();
251
251
  const t = e.touches;
252
252
  if (t.length === 1) {
@@ -255,11 +255,11 @@ const Pe = {
255
255
  y: t[0].clientY - o.value.y
256
256
  };
257
257
  const a = Date.now();
258
- a - I < 300 && (o.value = { x: 0, y: 0 }, i.value = 1), I = a;
258
+ a - A < 300 && (o.value = { x: 0, y: 0 }, i.value = 1), A = a;
259
259
  } else t.length === 2 && (g.value = !1, j = Math.hypot(
260
260
  t[1].clientX - t[0].clientX,
261
261
  t[1].clientY - t[0].clientY
262
- ), F = h.value, Z = { ...o.value });
262
+ ), I = h.value, Z = { ...o.value });
263
263
  }, J = (e) => {
264
264
  e.preventDefault();
265
265
  const t = e.touches;
@@ -279,7 +279,7 @@ const Pe = {
279
279
  t[1].clientY - t[0].clientY
280
280
  );
281
281
  if (Math.abs(u - j) < 5) return;
282
- const n = u / j, c = Math.max(0.01, Math.min(10, F * n)), l = a.getBoundingClientRect(), y = (t[0].clientX + t[1].clientX) / 2 - l.left - l.width / 2, b = (t[0].clientY + t[1].clientY) / 2 - l.top - l.height / 2, z = c / h.value;
282
+ const n = u / j, c = Math.max(0.01, Math.min(10, I * n)), l = a.getBoundingClientRect(), y = (t[0].clientX + t[1].clientX) / 2 - l.left - l.width / 2, b = (t[0].clientY + t[1].clientY) / 2 - l.top - l.height / 2, z = c / h.value;
283
283
  o.value = P(
284
284
  {
285
285
  x: y - z * (y - Z.x),
@@ -303,8 +303,8 @@ const Pe = {
303
303
  style: ae({ cursor: g.value ? "grabbing" : "grab", touchAction: "none" }),
304
304
  onMousedown: ye,
305
305
  onMousemove: be,
306
- onMouseup: K,
307
- onMouseleave: K
306
+ onMouseup: Q,
307
+ onMouseleave: Q
308
308
  }, [
309
309
  d.value ? (x(), C("div", Pe, [
310
310
  Re(le(Xe), { class: "vfp-w-12 vfp-h-12 vfp-text-fg-primary vfp-animate-spin" }),
@@ -338,21 +338,21 @@ const Pe = {
338
338
  onError: me,
339
339
  onDblclick: ge
340
340
  }, null, 46, Ne)) : L("", !0),
341
- E.value && !w.value && r.value.width > 0 ? (x(), C("div", Ge, S(r.value.width) + " × " + S(r.value.height) + S(we.value), 1)) : L("", !0),
342
- T.value > 1 ? (x(), C("div", Ve, [
341
+ E.value && !w.value && r.value.width > 0 ? (x(), C("div", Ve, S(r.value.width) + " × " + S(r.value.height) + S(we.value), 1)) : L("", !0),
342
+ T.value > 1 ? (x(), C("div", Fe, [
343
343
  X("button", {
344
344
  type: "button",
345
345
  disabled: R.value <= 1 || d.value,
346
346
  class: "vfp-px-2 vfp-py-0.5 vfp-rounded hover:vfp-bg-surface-nav-hover disabled:vfp-opacity-40 disabled:vfp-cursor-not-allowed",
347
- onClick: t[0] || (t[0] = (a) => A(R.value - 1))
348
- }, " 上一页 ", 8, qe),
349
- X("span", Fe, S(R.value) + " / " + S(T.value), 1),
347
+ onClick: t[0] || (t[0] = (a) => K(R.value - 1))
348
+ }, " 上一页 ", 8, Ge),
349
+ X("span", Ie, S(R.value) + " / " + S(T.value), 1),
350
350
  X("button", {
351
351
  type: "button",
352
352
  disabled: R.value >= T.value || d.value,
353
353
  class: "vfp-px-2 vfp-py-0.5 vfp-rounded hover:vfp-bg-surface-nav-hover disabled:vfp-opacity-40 disabled:vfp-cursor-not-allowed",
354
- onClick: t[1] || (t[1] = (a) => A(R.value + 1))
355
- }, " 下一页 ", 8, Ie)
354
+ onClick: t[1] || (t[1] = (a) => K(R.value + 1))
355
+ }, " 下一页 ", 8, Ae)
356
356
  ])) : L("", !0)
357
357
  ], 36));
358
358
  }
@@ -360,4 +360,4 @@ const Pe = {
360
360
  export {
361
361
  at as default
362
362
  };
363
- //# sourceMappingURL=index-CeQ3X5A0.mjs.map
363
+ //# sourceMappingURL=index-BPqo3A5l.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index-CeQ3X5A0.mjs","sources":["../../src/renderers/Image/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount, computed } from 'vue';\nimport { Loader2, ZoomIn, ZoomOut, RotateCw, RotateCcw, Scan, RefreshCw, Maximize2 } from 'lucide-vue-next';\nimport { formatFileSize, detectImageFormat, getLoaderForMimeType } from '@eternalheart/file-preview-core';\nimport type { PreviewFile } from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../composables/useTranslator';\nimport RendererError from '../RendererError.vue';\nimport { ToolbarEventEmitter } from '../base.types';\nimport type { RendererHandle } from '../base.types';\nimport type { ToolbarGroup } from '../toolbar.types';\n\nconst props = defineProps<{\n url: string;\n fileSize?: number;\n file?: PreviewFile | File;\n}>();\n\nconst emitter = new ToolbarEventEmitter();\n\nconst { t } = useTranslator();\n\n// 内部状态管理\nconst zoom = ref(1);\nconst rotation = ref(0);\nconst loaded = ref(false);\nconst error = ref<string | null>(null);\nconst decoding = ref(false);\nconst decodeProgress = ref(0);\nconst decodeError = ref<string | null>(null);\nconst imageSrc = ref<string>('');\nconst currentPage = ref(1);\nconst totalPages = ref(1);\nconst isRawThumbnail = ref(false);\nconst position = ref({ x: 0, y: 0 });\nconst isDragging = ref(false);\nlet dragStart = { x: 0, y: 0 };\nconst internalZoom = ref(1);\nconst naturalSize = ref({ width: 0, height: 0 });\n\n// 通知工具栏变化\nwatch([zoom, rotation], () => {\n emitter.notify();\n});\n\n// 工具栏配置(对齐 React 的 4 个按钮组)\nconst getToolbarGroups = (): ToolbarGroup[] => [\n {\n items: [\n {\n type: 'button',\n icon: ZoomOut,\n tooltip: t.value('toolbar.zoom_out'),\n action: handleZoomOut,\n disabled: zoom.value <= 0.01,\n },\n {\n type: 'text',\n content: `${Math.round(zoom.value * 100)}%`,\n minWidth: '3rem',\n },\n {\n type: 'button',\n icon: ZoomIn,\n tooltip: t.value('toolbar.zoom_in'),\n action: handleZoomIn,\n disabled: zoom.value >= 10,\n },\n ],\n },\n {\n items: [\n {\n type: 'button',\n icon: Scan,\n tooltip: t.value('toolbar.fit_to_window'),\n action: handleFitToWidth,\n },\n {\n type: 'button',\n icon: Maximize2,\n tooltip: t.value('toolbar.original_size'),\n action: handleOriginalSize,\n },\n ],\n },\n {\n items: [\n {\n type: 'button',\n icon: RotateCcw,\n tooltip: t.value('toolbar.rotate_left'),\n action: handleRotateLeft,\n },\n {\n type: 'button',\n icon: RotateCw,\n tooltip: t.value('toolbar.rotate_right'),\n action: handleRotateRight,\n },\n ],\n },\n {\n items: [\n {\n type: 'button',\n icon: RefreshCw,\n tooltip: t.value('toolbar.reset'),\n action: handleReset,\n },\n ],\n },\n];\n\n// 暴露接口\ndefineExpose<RendererHandle>({\n getToolbarGroups,\n onToolbarChange: (listener) => emitter.subscribe(listener),\n});\n\n// 工具栏操作\nconst handleZoomIn = () => {\n zoom.value = Math.min(zoom.value + 0.1, 10);\n};\n\nconst handleZoomOut = () => {\n zoom.value = Math.max(zoom.value - 0.1, 0.01);\n};\n\nconst handleRotateRight = () => {\n rotation.value = (rotation.value + 90) % 360;\n};\n\nconst handleRotateLeft = () => {\n rotation.value = (rotation.value - 90 + 360) % 360;\n};\n\nconst handleOriginalSize = () => {\n zoom.value = 1;\n rotation.value = 0;\n position.value = { x: 0, y: 0 };\n};\n\nconst handleReset = () => {\n handleFitToWidth();\n};\n\nconst handleFitToWidth = () => {\n if (containerRef.value && naturalSize.value.width > 0 && naturalSize.value.height > 0) {\n const containerWidth = containerRef.value.clientWidth;\n const containerHeight = containerRef.value.clientHeight;\n const scaleX = containerWidth / naturalSize.value.width;\n const scaleY = containerHeight / naturalSize.value.height;\n zoom.value = Math.max(0.01, Math.min(10, Math.min(scaleX, scaleY)));\n position.value = { x: 0, y: 0 };\n }\n};\n\nconst imgRef = ref<HTMLImageElement | null>(null);\nconst containerRef = ref<HTMLDivElement | null>(null);\nlet blobUrl: string | null = null;\nlet fileBlobCache: Blob | null = null;\nlet loaderCache: any = null;\nconst pageCache = new Map<number, string>();\n\nlet isTouchDevice = false;\nlet touchStartDistance = 0;\nlet touchStartZoom = 1;\nlet touchStartPos = { x: 0, y: 0 };\nlet lastTapTime = 0;\n\n// 解码逻辑\nwatch(\n () => [props.url, props.file] as const,\n async () => {\n // 重置状态:清空 src 以避免上一张图片的 onLoad/onError 误触发到新文件\n imageSrc.value = '';\n loaded.value = false;\n error.value = null;\n decoding.value = false;\n decodeError.value = null;\n decodeProgress.value = 0;\n position.value = { x: 0, y: 0 };\n internalZoom.value = 1;\n zoom.value = 1;\n currentPage.value = 1;\n totalPages.value = 1;\n isRawThumbnail.value = false;\n\n // 清理旧的 blob URL 与缓存\n if (blobUrl) {\n URL.revokeObjectURL(blobUrl);\n blobUrl = null;\n }\n pageCache.forEach((url) => URL.revokeObjectURL(url));\n pageCache.clear();\n fileBlobCache = null;\n loaderCache = null;\n\n // 如果没有 file 对象,直接使用 url\n if (!props.file) {\n imageSrc.value = props.url;\n return;\n }\n\n try {\n // 检测图片格式\n const mimeType = await detectImageFormat(props.file);\n const loader = await getLoaderForMimeType(mimeType);\n\n // 如果不需要解码,直接使用原 URL\n if (!loader || !(await loader.needsDecode(mimeType))) {\n imageSrc.value = props.url;\n return;\n }\n\n // 需要解码\n decoding.value = true;\n\n // 获取文件 Blob\n let fileBlob: Blob;\n if (props.file instanceof Blob) {\n fileBlob = props.file;\n } else {\n const response = await fetch(props.url);\n if (!response.ok) throw new Error('Failed to fetch file');\n fileBlob = await response.blob();\n }\n\n // 缓存 Blob 与 loader\n fileBlobCache = fileBlob;\n loaderCache = loader;\n\n // 标记 RAW 缩略图模式\n const isRaw = mimeType.startsWith('image/x-');\n if (isRaw) {\n isRawThumbnail.value = true;\n }\n\n // 获取元数据(用于检测多页 TIFF)\n if (loader.getMetadata) {\n try {\n const metadata = await loader.getMetadata(fileBlob);\n if (metadata.pageCount && metadata.pageCount > 1) {\n totalPages.value = metadata.pageCount;\n }\n } catch {\n // 忽略元数据获取失败\n }\n }\n\n // 调用 loader 解码(第 1 页 / 缩略图模式)\n const decodedBlob = await loader.decode(fileBlob, {\n page: 1,\n fullQuality: false,\n onProgress: (percent: number) => {\n decodeProgress.value = percent;\n },\n });\n\n // 生成 blob URL\n const url = typeof decodedBlob === 'string'\n ? decodedBlob\n : URL.createObjectURL(decodedBlob);\n\n blobUrl = url;\n pageCache.set(1, url);\n imageSrc.value = url;\n decoding.value = false;\n } catch (err: any) {\n decodeError.value = err?.message || '解码失败';\n decoding.value = false;\n }\n },\n { immediate: true }\n);\n\n// 多页 TIFF 翻页\nconst handlePageChange = async (page: number) => {\n if (!fileBlobCache || !loaderCache) return;\n if (page < 1 || page > totalPages.value) return;\n\n // 命中缓存:直接切换\n const cached = pageCache.get(page);\n if (cached) {\n currentPage.value = page;\n imageSrc.value = cached;\n return;\n }\n\n // 解码新页面\n decoding.value = true;\n try {\n const decodedBlob = await loaderCache.decode(fileBlobCache, { page });\n const url = typeof decodedBlob === 'string'\n ? decodedBlob\n : URL.createObjectURL(decodedBlob);\n\n // LRU:缓存超过 10 页时删除最早的\n if (pageCache.size >= 10) {\n const firstKey = pageCache.keys().next().value;\n if (firstKey !== undefined) {\n const oldUrl = pageCache.get(firstKey);\n if (oldUrl) URL.revokeObjectURL(oldUrl);\n pageCache.delete(firstKey);\n }\n }\n\n pageCache.set(page, url);\n currentPage.value = page;\n imageSrc.value = url;\n decoding.value = false;\n } catch (err: any) {\n decodeError.value = err?.message || '翻页解码失败';\n decoding.value = false;\n }\n};\n\n// Cleanup on unmount\nonBeforeUnmount(() => {\n if (blobUrl) {\n URL.revokeObjectURL(blobUrl);\n }\n pageCache.forEach((url) => URL.revokeObjectURL(url));\n pageCache.clear();\n const container = containerRef.value;\n if (container) {\n container.removeEventListener('wheel', handleWheelNative);\n }\n});\n\n// 同步 zoom 和 internalZoom\nwatch(zoom, (z) => {\n internalZoom.value = z;\n});\n\nwatch(internalZoom, (z) => {\n zoom.value = z;\n});\n\nconst clampPosition = (pos: { x: number; y: number }, currentZoom: number) => {\n const container = containerRef.value;\n if (!container || naturalSize.value.width === 0) return pos;\n\n const containerW = container.clientWidth;\n const containerH = container.clientHeight;\n const imgW = naturalSize.value.width * currentZoom;\n const imgH = naturalSize.value.height * currentZoom;\n\n const margin = Math.min(80, containerW * 0.15, containerH * 0.15);\n const rangeX = (containerW + imgW) / 2 - margin;\n const rangeY = (containerH + imgH) / 2 - margin;\n\n return {\n x: rangeX > 0 ? Math.max(-rangeX, Math.min(rangeX, pos.x)) : 0,\n y: rangeY > 0 ? Math.max(-rangeY, Math.min(rangeY, pos.y)) : 0,\n };\n};\n\nconst handleLoad = (e: Event) => {\n loaded.value = true;\n const img = e.currentTarget as HTMLImageElement;\n naturalSize.value = { width: img.naturalWidth, height: img.naturalHeight };\n\n // 自动适应窗口\n if (containerRef.value && naturalSize.value.width > 0 && naturalSize.value.height > 0) {\n const containerWidth = containerRef.value.clientWidth;\n const containerHeight = containerRef.value.clientHeight;\n const scaleX = containerWidth / naturalSize.value.width;\n const scaleY = containerHeight / naturalSize.value.height;\n const newZoom = Math.min(scaleX, scaleY);\n zoom.value = Math.max(0.01, Math.min(10, newZoom));\n position.value = { x: 0, y: 0 };\n }\n};\n\nconst handleError = () => {\n error.value = t.value('image.load_failed');\n loaded.value = true;\n};\n\nconst handleDoubleClick = () => {\n position.value = { x: 0, y: 0 };\n zoom.value = 1;\n};\n\n// 鼠标滚轮缩放\nconst handleWheelNative = (e: WheelEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n const container = containerRef.value;\n if (!container) return;\n\n const rect = container.getBoundingClientRect();\n const mouseX = e.clientX - rect.left - rect.width / 2;\n const mouseY = e.clientY - rect.top - rect.height / 2;\n\n const delta = e.deltaY > 0 ? -0.05 : 0.05;\n const prev = internalZoom.value;\n const newZoom = Math.max(0.01, Math.min(10, prev + delta));\n const scale = newZoom / prev;\n\n position.value = clampPosition(\n {\n x: mouseX - scale * (mouseX - position.value.x),\n y: mouseY - scale * (mouseY - position.value.y),\n },\n newZoom\n );\n\n internalZoom.value = newZoom;\n};\n\nonMounted(() => {\n const container = containerRef.value;\n if (container) {\n container.addEventListener('wheel', handleWheelNative, { passive: false });\n container.addEventListener('touchstart', handleTouchStart, { passive: false });\n container.addEventListener('touchmove', handleTouchMove, { passive: false });\n container.addEventListener('touchend', handleTouchEnd);\n container.addEventListener('touchcancel', handleTouchEnd);\n }\n});\n\nonBeforeUnmount(() => {\n const container = containerRef.value;\n if (container) {\n container.removeEventListener('wheel', handleWheelNative);\n container.removeEventListener('touchstart', handleTouchStart);\n container.removeEventListener('touchmove', handleTouchMove);\n container.removeEventListener('touchend', handleTouchEnd);\n container.removeEventListener('touchcancel', handleTouchEnd);\n }\n});\n\nconst handleMouseDown = (e: MouseEvent) => {\n if (isTouchDevice) return;\n if (e.button !== 0) return;\n isDragging.value = true;\n dragStart = {\n x: e.clientX - position.value.x,\n y: e.clientY - position.value.y,\n };\n};\n\nconst handleMouseMove = (e: MouseEvent) => {\n if (isTouchDevice) return;\n if (!isDragging.value) return;\n position.value = clampPosition(\n {\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n },\n internalZoom.value\n );\n};\n\nconst handleMouseUp = () => {\n if (isTouchDevice) return;\n isDragging.value = false;\n};\n\n// 触屏事件处理\nconst handleTouchStart = (e: TouchEvent) => {\n isTouchDevice = true;\n e.preventDefault();\n\n const touches = e.touches;\n if (touches.length === 1) {\n // 单指拖拽\n isDragging.value = true;\n dragStart = {\n x: touches[0].clientX - position.value.x,\n y: touches[0].clientY - position.value.y,\n };\n\n // 双击检测\n const now = Date.now();\n if (now - lastTapTime < 300) {\n // 双击复原:居中 + 缩放100%\n position.value = { x: 0, y: 0 };\n zoom.value = 1;\n }\n lastTapTime = now;\n } else if (touches.length === 2) {\n // 双指缩放初始化\n isDragging.value = false;\n const distance = Math.hypot(\n touches[1].clientX - touches[0].clientX,\n touches[1].clientY - touches[0].clientY\n );\n touchStartDistance = distance;\n touchStartZoom = internalZoom.value;\n touchStartPos = { ...position.value };\n }\n};\n\nconst handleTouchMove = (e: TouchEvent) => {\n e.preventDefault();\n\n const touches = e.touches;\n if (touches.length === 1 && isDragging.value) {\n // 单指拖拽\n position.value = clampPosition(\n {\n x: touches[0].clientX - dragStart.x,\n y: touches[0].clientY - dragStart.y,\n },\n internalZoom.value\n );\n } else if (touches.length === 2) {\n // 双指缩放\n const container = containerRef.value;\n if (!container) return;\n\n const distance = Math.hypot(\n touches[1].clientX - touches[0].clientX,\n touches[1].clientY - touches[0].clientY\n );\n\n // 最小距离变化阈值,防止抖动\n if (Math.abs(distance - touchStartDistance) < 5) return;\n\n const scale = distance / touchStartDistance;\n const newZoom = Math.max(0.01, Math.min(10, touchStartZoom * scale));\n\n // 双指中心点作为缩放原点\n const rect = container.getBoundingClientRect();\n const centerX = (touches[0].clientX + touches[1].clientX) / 2 - rect.left - rect.width / 2;\n const centerY = (touches[0].clientY + touches[1].clientY) / 2 - rect.top - rect.height / 2;\n\n const zoomScale = newZoom / internalZoom.value;\n position.value = clampPosition(\n {\n x: centerX - zoomScale * (centerX - touchStartPos.x),\n y: centerY - zoomScale * (centerY - touchStartPos.y),\n },\n newZoom\n );\n\n internalZoom.value = newZoom;\n }\n};\n\nconst handleTouchEnd = () => {\n isDragging.value = false;\n touchStartDistance = 0;\n};\n\nconst transformStyle = computed(() => ({\n transform: `translate(${position.value.x}px, ${position.value.y}px) scale(${internalZoom.value}) rotate(${rotation.value}deg)`,\n transformOrigin: 'center',\n transition: isDragging.value ? 'none' : 'transform 0.3s ease-out',\n opacity: loaded.value && !error.value && !decodeError.value ? 1 : 0,\n}));\n\nconst sizeText = computed(() => {\n if (props.fileSize == null) return '';\n return ` · ${formatFileSize(props.fileSize)}`;\n});\n</script>\n\n<template>\n <div\n ref=\"containerRef\"\n class=\"vfp-relative vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full vfp-overflow-hidden\"\n :style=\"{ cursor: isDragging ? 'grabbing' : 'grab', touchAction: 'none' }\"\n @mousedown=\"handleMouseDown\"\n @mousemove=\"handleMouseMove\"\n @mouseup=\"handleMouseUp\"\n @mouseleave=\"handleMouseUp\"\n >\n <!-- 解码中 -->\n <div\n v-if=\"decoding\"\n class=\"vfp-absolute vfp-inset-0 vfp-flex vfp-flex-col vfp-items-center vfp-justify-center vfp-bg-surface-1/80 vfp-z-10\"\n >\n <Loader2 class=\"vfp-w-12 vfp-h-12 vfp-text-fg-primary vfp-animate-spin\" />\n <p class=\"vfp-mt-4 vfp-text-fg-secondary\">\n 正在解码... <span v-if=\"decodeProgress > 0\">{{ Math.round(decodeProgress) }}%</span>\n </p>\n </div>\n\n <!-- 解码错误 -->\n <RendererError v-if=\"decodeError\" :message=\"t('image.decode_failed')\" :detail=\"decodeError\" />\n\n <div v-if=\"!loaded && !error && !decoding && !decodeError\" class=\"vfp-flex vfp-items-center vfp-justify-center\">\n <div\n class=\"vfp-w-12 vfp-h-12 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin\"\n />\n </div>\n\n <RendererError v-if=\"error\" :message=\"error\" />\n\n <img\n v-if=\"imageSrc\"\n ref=\"imgRef\"\n :src=\"imageSrc\"\n alt=\"Preview\"\n :class=\"['vfp-max-w-none vfp-select-none', (!loaded || error || decodeError) && 'vfp-hidden']\"\n :style=\"transformStyle\"\n :draggable=\"false\"\n @load=\"handleLoad\"\n @error=\"handleError\"\n @dblclick=\"handleDoubleClick\"\n />\n\n <div\n v-if=\"loaded && !error && naturalSize.width > 0\"\n class=\"vfp-absolute vfp-bottom-2 vfp-right-3 vfp-text-[10px] vfp-text-fg-disabled hover:vfp-text-fg-secondary vfp-transition-colors vfp-pointer-events-auto vfp-select-none vfp-cursor-default\"\n >\n {{ naturalSize.width }} × {{ naturalSize.height }}{{ sizeText }}\n </div>\n\n <!-- 多页 TIFF 翻页器 -->\n <div\n v-if=\"totalPages > 1\"\n class=\"vfp-absolute vfp-bottom-2 vfp-left-1/2 -vfp-translate-x-1/2 vfp-flex vfp-items-center vfp-gap-2 vfp-px-3 vfp-py-1.5 vfp-bg-surface-toolbar vfp-border vfp-border-line vfp-rounded-lg vfp-text-sm vfp-text-fg-primary vfp-shadow-md\"\n >\n <button\n type=\"button\"\n :disabled=\"currentPage <= 1 || decoding\"\n class=\"vfp-px-2 vfp-py-0.5 vfp-rounded hover:vfp-bg-surface-nav-hover disabled:vfp-opacity-40 disabled:vfp-cursor-not-allowed\"\n @click=\"handlePageChange(currentPage - 1)\"\n >\n 上一页\n </button>\n <span class=\"vfp-text-fg-secondary vfp-tabular-nums\">\n {{ currentPage }} / {{ totalPages }}\n </span>\n <button\n type=\"button\"\n :disabled=\"currentPage >= totalPages || decoding\"\n class=\"vfp-px-2 vfp-py-0.5 vfp-rounded hover:vfp-bg-surface-nav-hover disabled:vfp-opacity-40 disabled:vfp-cursor-not-allowed\"\n @click=\"handlePageChange(currentPage + 1)\"\n >\n 下一页\n </button>\n </div>\n </div>\n</template>\n"],"names":["props","__props","emitter","ToolbarEventEmitter","t","useTranslator","zoom","ref","rotation","loaded","error","decoding","decodeProgress","decodeError","imageSrc","currentPage","totalPages","isRawThumbnail","position","isDragging","dragStart","internalZoom","naturalSize","watch","__expose","ZoomOut","handleZoomOut","ZoomIn","handleZoomIn","Scan","handleFitToWidth","Maximize2","handleOriginalSize","RotateCcw","handleRotateLeft","RotateCw","handleRotateRight","RefreshCw","handleReset","listener","containerRef","containerWidth","containerHeight","scaleX","scaleY","imgRef","blobUrl","fileBlobCache","loaderCache","pageCache","isTouchDevice","touchStartDistance","touchStartZoom","touchStartPos","lastTapTime","url","mimeType","detectImageFormat","loader","getLoaderForMimeType","fileBlob","response","metadata","decodedBlob","percent","err","handlePageChange","page","cached","firstKey","oldUrl","onBeforeUnmount","container","handleWheelNative","z","clampPosition","pos","currentZoom","containerW","containerH","imgW","imgH","margin","rangeX","rangeY","handleLoad","img","newZoom","handleError","handleDoubleClick","rect","mouseX","mouseY","delta","prev","scale","onMounted","handleTouchStart","handleTouchMove","handleTouchEnd","handleMouseDown","handleMouseMove","handleMouseUp","touches","now","distance","centerX","centerY","zoomScale","transformStyle","computed","sizeText","formatFileSize","_createElementBlock","_openBlock","_hoisted_1","_createVNode","_unref","Loader2","_createElementVNode","_hoisted_2","_createBlock","RendererError","_hoisted_4","_cache","_normalizeClass","_hoisted_6","_toDisplayString","_hoisted_7","$event","_hoisted_8","_hoisted_9","_hoisted_10"],"mappings":"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"}
1
+ {"version":3,"file":"index-BPqo3A5l.mjs","sources":["../../src/renderers/Image/index.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, watch, onMounted, onBeforeUnmount, computed } from 'vue';\nimport { Loader2, ZoomIn, ZoomOut, RotateCw, RotateCcw, Scan, RefreshCw, Maximize2 } from 'lucide-vue-next';\nimport { formatFileSize, detectImageFormat, getLoaderForMimeType } from '@eternalheart/file-preview-core';\nimport type { PreviewFile } from '@eternalheart/file-preview-core';\nimport { useTranslator } from '../../composables/useTranslator';\nimport RendererError from '../RendererError.vue';\nimport { ToolbarEventEmitter } from '../base.types';\nimport type { RendererHandle } from '../base.types';\nimport type { ToolbarGroup } from '../toolbar.types';\n\nconst props = defineProps<{\n url: string;\n fileSize?: number;\n file?: PreviewFile | File;\n}>();\n\nconst emitter = new ToolbarEventEmitter();\n\nconst { t } = useTranslator();\n\n// 内部状态管理\nconst zoom = ref(1);\nconst rotation = ref(0);\nconst loaded = ref(false);\nconst error = ref<string | null>(null);\nconst decoding = ref(false);\nconst decodeProgress = ref(0);\nconst decodeError = ref<string | null>(null);\nconst imageSrc = ref<string>('');\nconst currentPage = ref(1);\nconst totalPages = ref(1);\nconst isRawThumbnail = ref(false);\nconst position = ref({ x: 0, y: 0 });\nconst isDragging = ref(false);\nlet dragStart = { x: 0, y: 0 };\nconst internalZoom = ref(1);\nconst naturalSize = ref({ width: 0, height: 0 });\n\n// 通知工具栏变化\nwatch([zoom, rotation], () => {\n emitter.notify();\n});\n\n// 工具栏配置(对齐 React 的 4 个按钮组)\nconst getToolbarGroups = (): ToolbarGroup[] => [\n {\n items: [\n {\n type: 'button',\n icon: ZoomOut,\n tooltip: t.value('toolbar.zoom_out'),\n action: handleZoomOut,\n disabled: zoom.value <= 0.01,\n },\n {\n type: 'text',\n content: `${Math.round(zoom.value * 100)}%`,\n minWidth: '3rem',\n },\n {\n type: 'button',\n icon: ZoomIn,\n tooltip: t.value('toolbar.zoom_in'),\n action: handleZoomIn,\n disabled: zoom.value >= 10,\n },\n ],\n },\n {\n items: [\n {\n type: 'button',\n icon: Scan,\n tooltip: t.value('toolbar.fit_to_window'),\n action: handleFitToWidth,\n },\n {\n type: 'button',\n icon: Maximize2,\n tooltip: t.value('toolbar.original_size'),\n action: handleOriginalSize,\n },\n ],\n },\n {\n items: [\n {\n type: 'button',\n icon: RotateCcw,\n tooltip: t.value('toolbar.rotate_left'),\n action: handleRotateLeft,\n },\n {\n type: 'button',\n icon: RotateCw,\n tooltip: t.value('toolbar.rotate_right'),\n action: handleRotateRight,\n },\n ],\n },\n {\n items: [\n {\n type: 'button',\n icon: RefreshCw,\n tooltip: t.value('toolbar.reset'),\n action: handleReset,\n },\n ],\n },\n];\n\n// 暴露接口\ndefineExpose<RendererHandle>({\n getToolbarGroups,\n onToolbarChange: (listener) => emitter.subscribe(listener),\n});\n\n// 工具栏操作\nconst handleZoomIn = () => {\n zoom.value = Math.min(zoom.value + 0.1, 10);\n};\n\nconst handleZoomOut = () => {\n zoom.value = Math.max(zoom.value - 0.1, 0.01);\n};\n\nconst handleRotateRight = () => {\n rotation.value = (rotation.value + 90) % 360;\n};\n\nconst handleRotateLeft = () => {\n rotation.value = (rotation.value - 90 + 360) % 360;\n};\n\nconst handleOriginalSize = () => {\n zoom.value = 1;\n rotation.value = 0;\n position.value = { x: 0, y: 0 };\n};\n\nconst handleReset = () => {\n handleFitToWidth();\n};\n\nconst handleFitToWidth = () => {\n if (containerRef.value && naturalSize.value.width > 0 && naturalSize.value.height > 0) {\n const containerWidth = containerRef.value.clientWidth;\n const containerHeight = containerRef.value.clientHeight;\n const scaleX = containerWidth / naturalSize.value.width;\n const scaleY = containerHeight / naturalSize.value.height;\n zoom.value = Math.max(0.01, Math.min(10, Math.min(scaleX, scaleY)));\n position.value = { x: 0, y: 0 };\n }\n};\n\nconst imgRef = ref<HTMLImageElement | null>(null);\nconst containerRef = ref<HTMLDivElement | null>(null);\nlet blobUrl: string | null = null;\nlet fileBlobCache: Blob | null = null;\nlet loaderCache: any = null;\nconst pageCache = new Map<number, string>();\n\nlet isTouchDevice = false;\nlet touchStartDistance = 0;\nlet touchStartZoom = 1;\nlet touchStartPos = { x: 0, y: 0 };\nlet lastTapTime = 0;\n\n// 解码逻辑\nwatch(\n () => [props.url, props.file] as const,\n async () => {\n // 重置状态:清空 src 以避免上一张图片的 onLoad/onError 误触发到新文件\n imageSrc.value = '';\n loaded.value = false;\n error.value = null;\n decoding.value = false;\n decodeError.value = null;\n decodeProgress.value = 0;\n position.value = { x: 0, y: 0 };\n internalZoom.value = 1;\n zoom.value = 1;\n currentPage.value = 1;\n totalPages.value = 1;\n isRawThumbnail.value = false;\n\n // 清理旧的 blob URL 与缓存\n if (blobUrl) {\n URL.revokeObjectURL(blobUrl);\n blobUrl = null;\n }\n pageCache.forEach((url) => URL.revokeObjectURL(url));\n pageCache.clear();\n fileBlobCache = null;\n loaderCache = null;\n\n // 如果没有 file 对象,直接使用 url\n if (!props.file) {\n imageSrc.value = props.url;\n return;\n }\n\n try {\n // 检测图片格式\n const mimeType = await detectImageFormat(props.file);\n const loader = await getLoaderForMimeType(mimeType);\n\n // 如果不需要解码,直接使用原 URL\n if (!loader || !(await loader.needsDecode(mimeType))) {\n imageSrc.value = props.url;\n return;\n }\n\n // 需要解码\n decoding.value = true;\n\n // 获取文件 Blob\n let fileBlob: Blob;\n if (props.file instanceof Blob) {\n fileBlob = props.file;\n } else {\n const response = await fetch(props.url);\n if (!response.ok) throw new Error('Failed to fetch file');\n fileBlob = await response.blob();\n }\n\n // 缓存 Blob 与 loader\n fileBlobCache = fileBlob;\n loaderCache = loader;\n\n // 标记 RAW 缩略图模式\n const isRaw = mimeType.startsWith('image/x-');\n if (isRaw) {\n isRawThumbnail.value = true;\n }\n\n // 获取元数据(用于检测多页 TIFF)\n if (loader.getMetadata) {\n try {\n const metadata = await loader.getMetadata(fileBlob);\n if (metadata.pageCount && metadata.pageCount > 1) {\n totalPages.value = metadata.pageCount;\n }\n } catch {\n // 忽略元数据获取失败\n }\n }\n\n // 调用 loader 解码(第 1 页 / 缩略图模式)\n const decodedBlob = await loader.decode(fileBlob, {\n page: 1,\n fullQuality: false,\n onProgress: (percent: number) => {\n decodeProgress.value = percent;\n },\n });\n\n // 生成 blob URL\n const url = typeof decodedBlob === 'string'\n ? decodedBlob\n : URL.createObjectURL(decodedBlob);\n\n blobUrl = url;\n pageCache.set(1, url);\n imageSrc.value = url;\n decoding.value = false;\n } catch (err: any) {\n decodeError.value = err?.message || '解码失败';\n decoding.value = false;\n }\n },\n { immediate: true }\n);\n\n// 多页 TIFF 翻页\nconst handlePageChange = async (page: number) => {\n if (!fileBlobCache || !loaderCache) return;\n if (page < 1 || page > totalPages.value) return;\n\n // 命中缓存:直接切换\n const cached = pageCache.get(page);\n if (cached) {\n currentPage.value = page;\n imageSrc.value = cached;\n return;\n }\n\n // 解码新页面\n decoding.value = true;\n try {\n const decodedBlob = await loaderCache.decode(fileBlobCache, { page });\n const url = typeof decodedBlob === 'string'\n ? decodedBlob\n : URL.createObjectURL(decodedBlob);\n\n // LRU:缓存超过 10 页时删除最早的\n if (pageCache.size >= 10) {\n const firstKey = pageCache.keys().next().value;\n if (firstKey !== undefined) {\n const oldUrl = pageCache.get(firstKey);\n if (oldUrl) URL.revokeObjectURL(oldUrl);\n pageCache.delete(firstKey);\n }\n }\n\n pageCache.set(page, url);\n currentPage.value = page;\n imageSrc.value = url;\n decoding.value = false;\n } catch (err: any) {\n decodeError.value = err?.message || '翻页解码失败';\n decoding.value = false;\n }\n};\n\n// Cleanup on unmount\nonBeforeUnmount(() => {\n if (blobUrl) {\n URL.revokeObjectURL(blobUrl);\n }\n pageCache.forEach((url) => URL.revokeObjectURL(url));\n pageCache.clear();\n const container = containerRef.value;\n if (container) {\n container.removeEventListener('wheel', handleWheelNative);\n }\n});\n\n// 同步 zoom 和 internalZoom\nwatch(zoom, (z) => {\n internalZoom.value = z;\n});\n\nwatch(internalZoom, (z) => {\n zoom.value = z;\n});\n\nconst clampPosition = (pos: { x: number; y: number }, currentZoom: number) => {\n const container = containerRef.value;\n if (!container || naturalSize.value.width === 0) return pos;\n\n const containerW = container.clientWidth;\n const containerH = container.clientHeight;\n const imgW = naturalSize.value.width * currentZoom;\n const imgH = naturalSize.value.height * currentZoom;\n\n const margin = Math.min(80, containerW * 0.15, containerH * 0.15);\n const rangeX = (containerW + imgW) / 2 - margin;\n const rangeY = (containerH + imgH) / 2 - margin;\n\n return {\n x: rangeX > 0 ? Math.max(-rangeX, Math.min(rangeX, pos.x)) : 0,\n y: rangeY > 0 ? Math.max(-rangeY, Math.min(rangeY, pos.y)) : 0,\n };\n};\n\nconst handleLoad = (e: Event) => {\n loaded.value = true;\n const img = e.currentTarget as HTMLImageElement;\n naturalSize.value = { width: img.naturalWidth, height: img.naturalHeight };\n\n // 自动适应窗口\n if (containerRef.value && naturalSize.value.width > 0 && naturalSize.value.height > 0) {\n const containerWidth = containerRef.value.clientWidth;\n const containerHeight = containerRef.value.clientHeight;\n const scaleX = containerWidth / naturalSize.value.width;\n const scaleY = containerHeight / naturalSize.value.height;\n const newZoom = Math.min(scaleX, scaleY);\n zoom.value = Math.max(0.01, Math.min(10, newZoom));\n position.value = { x: 0, y: 0 };\n }\n};\n\nconst handleError = () => {\n error.value = t.value('image.load_failed');\n loaded.value = true;\n};\n\nconst handleDoubleClick = () => {\n position.value = { x: 0, y: 0 };\n zoom.value = 1;\n};\n\n// 鼠标滚轮缩放\nconst handleWheelNative = (e: WheelEvent) => {\n e.preventDefault();\n e.stopPropagation();\n\n const container = containerRef.value;\n if (!container) return;\n\n const rect = container.getBoundingClientRect();\n const mouseX = e.clientX - rect.left - rect.width / 2;\n const mouseY = e.clientY - rect.top - rect.height / 2;\n\n const delta = e.deltaY > 0 ? -0.05 : 0.05;\n const prev = internalZoom.value;\n const newZoom = Math.max(0.01, Math.min(10, prev + delta));\n const scale = newZoom / prev;\n\n position.value = clampPosition(\n {\n x: mouseX - scale * (mouseX - position.value.x),\n y: mouseY - scale * (mouseY - position.value.y),\n },\n newZoom\n );\n\n internalZoom.value = newZoom;\n};\n\nonMounted(() => {\n const container = containerRef.value;\n if (container) {\n container.addEventListener('wheel', handleWheelNative, { passive: false });\n container.addEventListener('touchstart', handleTouchStart, { passive: false });\n container.addEventListener('touchmove', handleTouchMove, { passive: false });\n container.addEventListener('touchend', handleTouchEnd);\n container.addEventListener('touchcancel', handleTouchEnd);\n }\n});\n\nonBeforeUnmount(() => {\n const container = containerRef.value;\n if (container) {\n container.removeEventListener('wheel', handleWheelNative);\n container.removeEventListener('touchstart', handleTouchStart);\n container.removeEventListener('touchmove', handleTouchMove);\n container.removeEventListener('touchend', handleTouchEnd);\n container.removeEventListener('touchcancel', handleTouchEnd);\n }\n});\n\nconst handleMouseDown = (e: MouseEvent) => {\n if (isTouchDevice) return;\n if (e.button !== 0) return;\n isDragging.value = true;\n dragStart = {\n x: e.clientX - position.value.x,\n y: e.clientY - position.value.y,\n };\n};\n\nconst handleMouseMove = (e: MouseEvent) => {\n if (isTouchDevice) return;\n if (!isDragging.value) return;\n position.value = clampPosition(\n {\n x: e.clientX - dragStart.x,\n y: e.clientY - dragStart.y,\n },\n internalZoom.value\n );\n};\n\nconst handleMouseUp = () => {\n if (isTouchDevice) return;\n isDragging.value = false;\n};\n\n// 触屏事件处理\nconst handleTouchStart = (e: TouchEvent) => {\n isTouchDevice = true;\n e.preventDefault();\n\n const touches = e.touches;\n if (touches.length === 1) {\n // 单指拖拽\n isDragging.value = true;\n dragStart = {\n x: touches[0].clientX - position.value.x,\n y: touches[0].clientY - position.value.y,\n };\n\n // 双击检测\n const now = Date.now();\n if (now - lastTapTime < 300) {\n // 双击复原:居中 + 缩放100%\n position.value = { x: 0, y: 0 };\n zoom.value = 1;\n }\n lastTapTime = now;\n } else if (touches.length === 2) {\n // 双指缩放初始化\n isDragging.value = false;\n const distance = Math.hypot(\n touches[1].clientX - touches[0].clientX,\n touches[1].clientY - touches[0].clientY\n );\n touchStartDistance = distance;\n touchStartZoom = internalZoom.value;\n touchStartPos = { ...position.value };\n }\n};\n\nconst handleTouchMove = (e: TouchEvent) => {\n e.preventDefault();\n\n const touches = e.touches;\n if (touches.length === 1 && isDragging.value) {\n // 单指拖拽\n position.value = clampPosition(\n {\n x: touches[0].clientX - dragStart.x,\n y: touches[0].clientY - dragStart.y,\n },\n internalZoom.value\n );\n } else if (touches.length === 2) {\n // 双指缩放\n const container = containerRef.value;\n if (!container) return;\n\n const distance = Math.hypot(\n touches[1].clientX - touches[0].clientX,\n touches[1].clientY - touches[0].clientY\n );\n\n // 最小距离变化阈值,防止抖动\n if (Math.abs(distance - touchStartDistance) < 5) return;\n\n const scale = distance / touchStartDistance;\n const newZoom = Math.max(0.01, Math.min(10, touchStartZoom * scale));\n\n // 双指中心点作为缩放原点\n const rect = container.getBoundingClientRect();\n const centerX = (touches[0].clientX + touches[1].clientX) / 2 - rect.left - rect.width / 2;\n const centerY = (touches[0].clientY + touches[1].clientY) / 2 - rect.top - rect.height / 2;\n\n const zoomScale = newZoom / internalZoom.value;\n position.value = clampPosition(\n {\n x: centerX - zoomScale * (centerX - touchStartPos.x),\n y: centerY - zoomScale * (centerY - touchStartPos.y),\n },\n newZoom\n );\n\n internalZoom.value = newZoom;\n }\n};\n\nconst handleTouchEnd = () => {\n isDragging.value = false;\n touchStartDistance = 0;\n};\n\nconst transformStyle = computed(() => ({\n transform: `translate(${position.value.x}px, ${position.value.y}px) scale(${internalZoom.value}) rotate(${rotation.value}deg)`,\n transformOrigin: 'center',\n transition: isDragging.value ? 'none' : 'transform 0.3s ease-out',\n opacity: loaded.value && !error.value && !decodeError.value ? 1 : 0,\n}));\n\nconst sizeText = computed(() => {\n if (props.fileSize == null) return '';\n return ` · ${formatFileSize(props.fileSize)}`;\n});\n</script>\n\n<template>\n <div\n ref=\"containerRef\"\n class=\"vfp-relative vfp-flex vfp-items-center vfp-justify-center vfp-w-full vfp-h-full vfp-overflow-hidden\"\n :style=\"{ cursor: isDragging ? 'grabbing' : 'grab', touchAction: 'none' }\"\n @mousedown=\"handleMouseDown\"\n @mousemove=\"handleMouseMove\"\n @mouseup=\"handleMouseUp\"\n @mouseleave=\"handleMouseUp\"\n >\n <!-- 解码中 -->\n <div\n v-if=\"decoding\"\n class=\"vfp-absolute vfp-inset-0 vfp-flex vfp-flex-col vfp-items-center vfp-justify-center vfp-bg-surface-1/80 vfp-z-10\"\n >\n <Loader2 class=\"vfp-w-12 vfp-h-12 vfp-text-fg-primary vfp-animate-spin\" />\n <p class=\"vfp-mt-4 vfp-text-fg-secondary\">\n 正在解码... <span v-if=\"decodeProgress > 0\">{{ Math.round(decodeProgress) }}%</span>\n </p>\n </div>\n\n <!-- 解码错误 -->\n <RendererError v-if=\"decodeError\" :message=\"t('image.decode_failed')\" :detail=\"decodeError\" />\n\n <div v-if=\"!loaded && !error && !decoding && !decodeError\" class=\"vfp-flex vfp-items-center vfp-justify-center\">\n <div\n class=\"vfp-w-12 vfp-h-12 vfp-border-4 vfp-border-line-strong vfp-border-t-spinner-head vfp-rounded-full vfp-animate-spin\"\n />\n </div>\n\n <RendererError v-if=\"error\" :message=\"error\" />\n\n <img\n v-if=\"imageSrc\"\n ref=\"imgRef\"\n :src=\"imageSrc\"\n alt=\"Preview\"\n :class=\"['vfp-max-w-none vfp-select-none', (!loaded || error || decodeError) && 'vfp-hidden']\"\n :style=\"transformStyle\"\n :draggable=\"false\"\n @load=\"handleLoad\"\n @error=\"handleError\"\n @dblclick=\"handleDoubleClick\"\n />\n\n <div\n v-if=\"loaded && !error && naturalSize.width > 0\"\n class=\"vfp-absolute vfp-bottom-2 vfp-right-3 vfp-text-[10px] vfp-text-fg-disabled hover:vfp-text-fg-secondary vfp-transition-colors vfp-pointer-events-auto vfp-select-none vfp-cursor-default\"\n >\n {{ naturalSize.width }} × {{ naturalSize.height }}{{ sizeText }}\n </div>\n\n <!-- 多页 TIFF 翻页器 -->\n <div\n v-if=\"totalPages > 1\"\n class=\"vfp-absolute vfp-bottom-2 vfp-left-1/2 -vfp-translate-x-1/2 vfp-flex vfp-items-center vfp-gap-2 vfp-px-3 vfp-py-1.5 vfp-bg-surface-toolbar vfp-border vfp-border-line vfp-rounded-lg vfp-text-sm vfp-text-fg-primary vfp-shadow-md\"\n >\n <button\n type=\"button\"\n :disabled=\"currentPage <= 1 || decoding\"\n class=\"vfp-px-2 vfp-py-0.5 vfp-rounded hover:vfp-bg-surface-nav-hover disabled:vfp-opacity-40 disabled:vfp-cursor-not-allowed\"\n @click=\"handlePageChange(currentPage - 1)\"\n >\n 上一页\n </button>\n <span class=\"vfp-text-fg-secondary vfp-tabular-nums\">\n {{ currentPage }} / {{ totalPages }}\n </span>\n <button\n type=\"button\"\n :disabled=\"currentPage >= totalPages || decoding\"\n class=\"vfp-px-2 vfp-py-0.5 vfp-rounded hover:vfp-bg-surface-nav-hover disabled:vfp-opacity-40 disabled:vfp-cursor-not-allowed\"\n @click=\"handlePageChange(currentPage + 1)\"\n >\n 下一页\n </button>\n </div>\n </div>\n</template>\n"],"names":["props","__props","emitter","ToolbarEventEmitter","t","useTranslator","zoom","ref","rotation","loaded","error","decoding","decodeProgress","decodeError","imageSrc","currentPage","totalPages","isRawThumbnail","position","isDragging","dragStart","internalZoom","naturalSize","watch","__expose","ZoomOut","handleZoomOut","ZoomIn","handleZoomIn","Scan","handleFitToWidth","Maximize2","handleOriginalSize","RotateCcw","handleRotateLeft","RotateCw","handleRotateRight","RefreshCw","handleReset","listener","containerRef","containerWidth","containerHeight","scaleX","scaleY","imgRef","blobUrl","fileBlobCache","loaderCache","pageCache","isTouchDevice","touchStartDistance","touchStartZoom","touchStartPos","lastTapTime","url","mimeType","detectImageFormat","loader","getLoaderForMimeType","fileBlob","response","metadata","decodedBlob","percent","err","handlePageChange","page","cached","firstKey","oldUrl","onBeforeUnmount","container","handleWheelNative","z","clampPosition","pos","currentZoom","containerW","containerH","imgW","imgH","margin","rangeX","rangeY","handleLoad","img","newZoom","handleError","handleDoubleClick","rect","mouseX","mouseY","delta","prev","scale","onMounted","handleTouchStart","handleTouchMove","handleTouchEnd","handleMouseDown","handleMouseMove","handleMouseUp","touches","now","distance","centerX","centerY","zoomScale","transformStyle","computed","sizeText","formatFileSize","_createElementBlock","_openBlock","_hoisted_1","_createVNode","_unref","Loader2","_createElementVNode","_hoisted_2","_createBlock","RendererError","_hoisted_4","_cache","_normalizeClass","_hoisted_6","_toDisplayString","_hoisted_7","$event","_hoisted_8","_hoisted_9","_hoisted_10"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { defineComponent as er, ref as qe, watch as tr, computed as te, openBlock as J, createElementBlock as Q, createElementVNode as F, createBlock as rr, unref as se, toDisplayString as ne, createVNode as he, createCommentVNode as oe, normalizeStyle as ir, Fragment as nr, renderList as ar, createTextVNode as sr, normalizeClass as or } from "vue";
2
2
  import { User as cr, Users as Ve, Calendar as mt, Clock as Et, Tag as gt, Mail as fr, Paperclip as ur, Hash as hr } from "lucide-vue-next";
3
- import { u as lr, a as dr, _ as pr } from "./index-D6e4OqEP.mjs";
3
+ import { u as lr, a as dr, _ as pr } from "./index-BT3eCnY-.mjs";
4
4
  import { _ as yr } from "./RendererError.vue_vue_type_script_setup_true_lang-BNoENOWX.mjs";
5
5
  var fe = typeof globalThis < "u" ? globalThis : typeof window < "u" ? window : typeof global < "u" ? global : typeof self < "u" ? self : {};
6
6
  function br(e) {
@@ -13189,4 +13189,4 @@ const Bi = /* @__PURE__ */ br(Vt), Ui = {
13189
13189
  export {
13190
13190
  Pn as default
13191
13191
  };
13192
- //# sourceMappingURL=index-CftjnCD3.mjs.map
13192
+ //# sourceMappingURL=index-BS5s-1VM.mjs.map