@bylqwjc/media-editor-image 1.0.26

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 (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +48 -0
  3. package/dist/chunk-5TBO732O.js +1 -0
  4. package/dist/index-CU3vkvDR.d.ts +44 -0
  5. package/dist/index.css +1 -0
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +36 -0
  8. package/dist/lazy.css +1 -0
  9. package/dist/lazy.d.ts +8 -0
  10. package/dist/lazy.js +1 -0
  11. package/node_modules/@media-editor/core/LICENSE +21 -0
  12. package/node_modules/@media-editor/core/README.md +14 -0
  13. package/node_modules/@media-editor/core/dist/browser.cjs +1 -0
  14. package/node_modules/@media-editor/core/dist/browser.d.ts +117 -0
  15. package/node_modules/@media-editor/core/dist/browser.js +1 -0
  16. package/node_modules/@media-editor/core/dist/chunk-7D4QE3R2.js +1 -0
  17. package/node_modules/@media-editor/core/dist/chunk-7PSQLYXL.js +1 -0
  18. package/node_modules/@media-editor/core/dist/chunk-FAFKY4LX.js +1 -0
  19. package/node_modules/@media-editor/core/dist/chunk-VDEZTXEA.js +1 -0
  20. package/node_modules/@media-editor/core/dist/engine.cjs +1 -0
  21. package/node_modules/@media-editor/core/dist/engine.d.ts +663 -0
  22. package/node_modules/@media-editor/core/dist/engine.js +1 -0
  23. package/node_modules/@media-editor/core/dist/filerobot.cjs +1 -0
  24. package/node_modules/@media-editor/core/dist/filerobot.d.ts +88 -0
  25. package/node_modules/@media-editor/core/dist/filerobot.js +1 -0
  26. package/node_modules/@media-editor/core/dist/index.cjs +1 -0
  27. package/node_modules/@media-editor/core/dist/index.d.ts +250 -0
  28. package/node_modules/@media-editor/core/dist/index.js +1 -0
  29. package/node_modules/@media-editor/core/dist/platform-presets-Ca2LbKQ3.d.ts +80 -0
  30. package/node_modules/@media-editor/core/dist/state-D2oM5s1a.d.ts +2098 -0
  31. package/node_modules/@media-editor/core/node_modules/zod/LICENSE +21 -0
  32. package/node_modules/@media-editor/core/node_modules/zod/README.md +208 -0
  33. package/node_modules/@media-editor/core/node_modules/zod/index.cjs +1 -0
  34. package/node_modules/@media-editor/core/node_modules/zod/index.d.cts +4 -0
  35. package/node_modules/@media-editor/core/node_modules/zod/index.js +1 -0
  36. package/node_modules/@media-editor/core/node_modules/zod/package.json +76 -0
  37. package/node_modules/@media-editor/core/node_modules/zod/v3/ZodError.cjs +1 -0
  38. package/node_modules/@media-editor/core/node_modules/zod/v3/ZodError.d.cts +164 -0
  39. package/node_modules/@media-editor/core/node_modules/zod/v3/ZodError.js +1 -0
  40. package/node_modules/@media-editor/core/node_modules/zod/v3/errors.cjs +1 -0
  41. package/node_modules/@media-editor/core/node_modules/zod/v3/errors.d.cts +5 -0
  42. package/node_modules/@media-editor/core/node_modules/zod/v3/errors.js +1 -0
  43. package/node_modules/@media-editor/core/node_modules/zod/v3/external.cjs +1 -0
  44. package/node_modules/@media-editor/core/node_modules/zod/v3/external.d.cts +6 -0
  45. package/node_modules/@media-editor/core/node_modules/zod/v3/external.js +1 -0
  46. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/enumUtil.cjs +1 -0
  47. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/enumUtil.d.cts +8 -0
  48. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/enumUtil.js +1 -0
  49. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/errorUtil.cjs +1 -0
  50. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/errorUtil.d.cts +9 -0
  51. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/errorUtil.js +1 -0
  52. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/parseUtil.cjs +1 -0
  53. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/parseUtil.d.cts +78 -0
  54. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/parseUtil.js +1 -0
  55. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/partialUtil.cjs +1 -0
  56. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/partialUtil.d.cts +8 -0
  57. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/partialUtil.js +1 -0
  58. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/typeAliases.cjs +1 -0
  59. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/typeAliases.d.cts +2 -0
  60. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/typeAliases.js +1 -0
  61. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/util.cjs +1 -0
  62. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/util.d.cts +85 -0
  63. package/node_modules/@media-editor/core/node_modules/zod/v3/helpers/util.js +1 -0
  64. package/node_modules/@media-editor/core/node_modules/zod/v3/index.cjs +1 -0
  65. package/node_modules/@media-editor/core/node_modules/zod/v3/index.d.cts +4 -0
  66. package/node_modules/@media-editor/core/node_modules/zod/v3/index.js +1 -0
  67. package/node_modules/@media-editor/core/node_modules/zod/v3/locales/en.cjs +1 -0
  68. package/node_modules/@media-editor/core/node_modules/zod/v3/locales/en.d.cts +3 -0
  69. package/node_modules/@media-editor/core/node_modules/zod/v3/locales/en.js +1 -0
  70. package/node_modules/@media-editor/core/node_modules/zod/v3/standard-schema.cjs +1 -0
  71. package/node_modules/@media-editor/core/node_modules/zod/v3/standard-schema.d.cts +102 -0
  72. package/node_modules/@media-editor/core/node_modules/zod/v3/standard-schema.js +1 -0
  73. package/node_modules/@media-editor/core/node_modules/zod/v3/types.cjs +1 -0
  74. package/node_modules/@media-editor/core/node_modules/zod/v3/types.d.cts +1031 -0
  75. package/node_modules/@media-editor/core/node_modules/zod/v3/types.js +1 -0
  76. package/node_modules/@media-editor/core/package.json +42 -0
  77. package/package.json +34 -0
package/dist/lazy.css ADDED
@@ -0,0 +1 @@
1
+ .tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1}.tippy-box[data-animation=scale][data-placement^=top]{transform-origin:bottom}.tippy-box[data-animation=scale][data-placement^=bottom]{transform-origin:top}.tippy-box[data-animation=scale][data-placement^=left]{transform-origin:right}.tippy-box[data-animation=scale][data-placement^=right]{transform-origin:left}.tippy-box[data-animation=scale][data-state=hidden]{transform:scale(.5);opacity:0}
package/dist/lazy.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ import { M as MountImageEditorOptions, I as ImageEditorHandle, _ as __index } from './index-CU3vkvDR.js';
2
+ import '@media-editor/core/filerobot';
3
+
4
+ type ImageEditorRuntime = typeof __index;
5
+ declare function preloadImageEditor(): Promise<ImageEditorRuntime>;
6
+ declare function mountImageEditorLazy(target: HTMLElement, opts: MountImageEditorOptions): Promise<ImageEditorHandle>;
7
+
8
+ export { ImageEditorHandle, MountImageEditorOptions, mountImageEditorLazy, preloadImageEditor };
package/dist/lazy.js ADDED
@@ -0,0 +1 @@
1
+ import"./chunk-5TBO732O.js";var t=null;function n(){return t??(t=import("./index.js")),t}async function r(t,r){return(await n()).mountImageEditor(t,r)}export{r as mountImageEditorLazy,n as preloadImageEditor};
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 media-editor-sdk contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,14 @@
1
+ # @media-editor/core
2
+
3
+ 框架无关核心包。包含视频编辑状态、时间轴、导出参数、滤镜、平台比例、图片编辑器配置工厂和浏览器 canvas 工具。
4
+
5
+ ## 子路径
6
+
7
+ ```ts
8
+ import { defaultVideoEditState } from '@media-editor/core';
9
+ import { VideoEditorEngine } from '@media-editor/core/engine';
10
+ import { buildVideoExportFormData } from '@media-editor/core/browser';
11
+ import { createImageEditorConfig } from '@media-editor/core/filerobot';
12
+ ```
13
+
14
+ `@media-editor/core` 不依赖 React 或 Vue,适合服务端和自定义 UI 复用。
@@ -0,0 +1 @@
1
+ "use strict";var zod=require("zod"),DEG2RAD=Math.PI/180,TEXT_FONT_STACK='-apple-system, "PingFang SC", "Microsoft YaHei", sans-serif';function isDrawableOverlay(e){return"adjust"!==e.type}function isOverlayHidden(e){return Boolean(e.hidden)}function isOverlayLocked(e){return Boolean(e.locked)}function overlayTrack(e,t){const o=Number(e.timelineTrack);return Number.isFinite(o)?Math.max(0,Math.round(o)):t}function overlayLayerRenderOrder(e){return e.map((e,t)=>({overlay:e,index:t,track:overlayTrack(e,t)})).sort((e,t)=>t.track-e.track||e.index-t.index).map(e=>e.overlay)}function strokeStyle(e,t,o){e.strokeStyle=t,e.lineWidth=o,e.lineCap="round",e.lineJoin="round"}function drawArrowHead(e,t,o,n,r,a){const i=Math.atan2(r-o,n-t),s=Math.max(12,3.5*a);e.beginPath(),e.moveTo(n,r),e.lineTo(n-s*Math.cos(i-Math.PI/7),r-s*Math.sin(i-Math.PI/7)),e.moveTo(n,r),e.lineTo(n-s*Math.cos(i+Math.PI/7),r-s*Math.sin(i+Math.PI/7)),e.stroke()}function normalizeOverlayRotation(e){if(!Number.isFinite(e))return 0;let t=e%360;return t>180&&(t-=360),t<-180&&(t+=360),Math.abs(t)<.001?0:t}function getOverlayRotation(e){return normalizeOverlayRotation(e.rotation??0)}function overlayBBox(e){switch(e.type){case"pen":{let t=1/0,o=1/0,n=-1/0,r=-1/0;for(let a=0;a<e.points.length;a+=2)t=Math.min(t,e.points[a]),n=Math.max(n,e.points[a]),o=Math.min(o,e.points[a+1]),r=Math.max(r,e.points[a+1]);return{x:t,y:o,w:n-t,h:r-o}}case"line":case"arrow":return{x:Math.min(e.x1,e.x2),y:Math.min(e.y1,e.y2),w:Math.abs(e.x2-e.x1),h:Math.abs(e.y2-e.y1)};case"rect":case"ellipse":case"sticker":case"adjust":return{x:e.x,y:e.y,w:e.w,h:e.h};case"text":return textBBox(e)}}function textLines(e){return String(e.text||"").split(/\r?\n/)}function textLineHeight(e){return e.fontSize*(e.lineHeight??1.15)}function textPaddingX(e){return e.paddingX??0}function textPaddingY(e){return e.paddingY??0}function textContentWidth(e){const t=Math.max(.6*e.fontSize,...textLines(e).map(t=>Math.max(1,t.length)*e.fontSize*.6));return Math.max(1,e.width??t+2*textPaddingX(e))}function textBBox(e){const t=textLines(e);return{x:e.x,y:e.y,w:textContentWidth(e),h:Math.max(e.fontSize,t.length*textLineHeight(e))+2*textPaddingY(e)}}function textFont(e){const t=e.fontWeight??"700",o=e.italic?"italic ":"",n=e.fontFamily?`"${e.fontFamily}", ${TEXT_FONT_STACK}`:TEXT_FONT_STACK;return`${o}${t} ${e.fontSize}px ${n}`}function textLineX(e,t,o,n){const r=textPaddingX(t),a=t.align??"left",i=e.measureText(o||" ").width;return"center"===a?t.x+n/2-i/2:"right"===a?t.x+n-r-i:t.x+r}function overlayCenter(e){const t=overlayBBox(e);return{x:t.x+t.w/2,y:t.y+t.h/2}}function rotatePoint(e,t,o,n,r){const a=r*DEG2RAD,i=Math.cos(a),s=Math.sin(a),l=e-o,d=t-n;return{x:o+l*i-d*s,y:n+l*s+d*i}}function scalePoint(e,t,o,n,r){return{x:o+(e-o)*r,y:n+(t-n)*r}}function overlayTimeRange(e){const t=e,o=Number.isFinite(t.startAt)?Math.max(0,Number(t.startAt)):null,n=Number.isFinite(t.endAt)?Math.max(o??0,Number(t.endAt)):null;if(null==o&&null==n)return null;const r=o??0;return{start:r,end:Math.max(r,n??r)}}function isOverlayActiveAt(e,t){const o=overlayTimeRange(e);return!o||Number.isFinite(t)&&t>=o.start&&t<=o.end}function filterOverlaysAtTime(e,t){if(!e?.length)return[];const o=e.filter(e=>!isOverlayHidden(e));return Number.isFinite(t)?o.filter(e=>isOverlayActiveAt(e,t)):o}function drawOverlay(e,t,o){if(isOverlayHidden(t))return;if(!isDrawableOverlay(t))return;const n=getOverlayRotation(t);if(n){const r=overlayCenter(t);return e.save(),e.translate(r.x,r.y),e.rotate(n*DEG2RAD),e.translate(-r.x,-r.y),drawOverlayBase(e,t,o),void e.restore()}drawOverlayBase(e,t,o)}function drawOverlayBase(e,t,o){switch(t.type){case"pen":strokeStyle(e,t.color,t.width),e.beginPath(),e.moveTo(t.points[0],t.points[1]);for(let o=2;o<t.points.length;o+=2)e.lineTo(t.points[o],t.points[o+1]);e.stroke();break;case"line":case"arrow":strokeStyle(e,t.color,t.width),e.beginPath(),e.moveTo(t.x1,t.y1),e.lineTo(t.x2,t.y2),e.stroke(),"arrow"===t.type&&drawArrowHead(e,t.x1,t.y1,t.x2,t.y2,t.width);break;case"rect":strokeStyle(e,t.color,t.width),e.strokeRect(t.x,t.y,t.w,t.h);break;case"ellipse":strokeStyle(e,t.color,t.width),e.beginPath(),e.ellipse(t.x+t.w/2,t.y+t.h/2,Math.abs(t.w/2),Math.abs(t.h/2),0,0,2*Math.PI),e.stroke();break;case"text":{const o=textBBox(t),n=textLines(t),r=Number.isFinite(t.opacity)?Math.min(1,Math.max(0,(t.opacity??100)/100)):1;e.save(),e.globalAlpha*=r,t.backgroundColor&&"transparent"!==t.backgroundColor&&(e.fillStyle=t.backgroundColor,e.fillRect(t.x,t.y,o.w,o.h)),e.fillStyle=t.color,e.font=textFont(t),e.textBaseline="top",e.strokeStyle=t.strokeColor??"rgba(0,0,0,0.45)",e.lineWidth=t.borderWidth??Math.max(2,t.fontSize/16),e.lineJoin="round",n.forEach((n,r)=>{const a=textLineX(e,t,n,o.w),i=t.y+textPaddingY(t)+r*textLineHeight(t),s=e.measureText(n||" ").width;if(e.lineWidth>0&&e.strokeText(n,a,i),e.fillText(n,a,i),(t.underline||t.strikethrough)&&s>0){const o=Math.max(1,t.fontSize/18);e.fillStyle=t.color,t.underline&&e.fillRect(a,i+.92*t.fontSize,s,o),t.strikethrough&&e.fillRect(a,i+.52*t.fontSize,s,o)}}),e.restore();break}case"sticker":if(t.emoji)e.save(),e.font=.86*Math.min(t.w,t.h)+'px -apple-system, "Apple Color Emoji", "Segoe UI Emoji", sans-serif',e.textAlign="center",e.textBaseline="middle",e.fillText(t.emoji,t.x+t.w/2,t.y+t.h/2),e.restore();else if(t.src){const n=o?.get(t.src);n&&e.drawImage(n,t.x,t.y,t.w,t.h)}}}function drawOverlays(e,t,o,n){const r="number"==typeof n?filterOverlaysAtTime(t,n):t;for(const t of r)!isOverlayHidden(t)&&isDrawableOverlay(t)&&drawOverlay(e,t,o)}async function loadOverlayImages(e){const t=new Map,o=[...new Set(e.filter(e=>"sticker"===e.type&&e.src).map(e=>e.src))];return await Promise.all(o.map(e=>new Promise(o=>{const n=new Image;n.onload=()=>{t.set(e,n),o()},n.onerror=()=>o(),n.src=e}))),t}async function renderOverlaysToPng(e,t,o){const n=e?.filter(e=>!isOverlayHidden(e)&&isDrawableOverlay(e))??[];if(!n.length)return null;const r=document.createElement("canvas");r.width=t,r.height=o;const a=r.getContext("2d");return a?(drawOverlays(a,n,await loadOverlayImages(n)),new Promise(e=>r.toBlob(t=>e(t),"image/png"))):null}function hitTestOverlay(e,t,o,n=12){for(let r=e.length-1;r>=0;r--){const a=e[r];if(!isOverlayHidden(a)&&hitOne(a,t,o,n))return r}return-1}function near(e,t,o,n,r){return Math.abs(e-o)<=r&&Math.abs(t-n)<=r}function nearSegment(e,t,o,n,r,a,i){const s=r-o,l=a-n,d=s*s+l*l||1,m=Math.max(0,Math.min(1,((e-o)*s+(t-n)*l)/d));return(e-(o+m*s))**2+(t-(n+m*l))**2<=i*i}function hitOne(e,t,o,n){const r=getOverlayRotation(e);if(r){const a=overlayCenter(e),i=rotatePoint(t,o,a.x,a.y,-r);return hitOneBase(e,i.x,i.y,n)}return hitOneBase(e,t,o,n)}function hitOneBase(e,t,o,n){switch(e.type){case"pen":for(let r=0;r+3<e.points.length;r+=2)if(nearSegment(t,o,e.points[r],e.points[r+1],e.points[r+2],e.points[r+3],n+e.width/2))return!0;return!1;case"line":case"arrow":return nearSegment(t,o,e.x1,e.y1,e.x2,e.y2,n+e.width/2);case"rect":case"ellipse":return t>=e.x-n&&t<=e.x+e.w+n&&o>=e.y-n&&o<=e.y+e.h+n;case"text":{const r=textBBox(e);return t>=r.x-n&&t<=r.x+r.w+n&&o>=r.y-n&&o<=r.y+r.h+n}case"sticker":return near(t,o,e.x+e.w/2,e.y+e.h/2,Math.max(e.w,e.h)/2+n);case"adjust":return!1}}function fitStickerBox(e,t,o){const n=Math.max(8,o);if(!(e>0&&t>0))return{w:n,h:n};const r=n/Math.max(e,t);return{w:Math.max(8,Math.round(e*r)),h:Math.max(8,Math.round(t*r))}}function scaleOverlay(e,t){const o=Math.max(.05,t),n=overlayCenter(e);switch(e.type){case"pen":return{...e,points:e.points.map((e,t)=>t%2==0?n.x+(e-n.x)*o:n.y+(e-n.y)*o)};case"line":case"arrow":{const t=scalePoint(e.x1,e.y1,n.x,n.y,o),r=scalePoint(e.x2,e.y2,n.x,n.y,o);return{...e,x1:t.x,y1:t.y,x2:r.x,y2:r.y}}case"rect":case"ellipse":case"sticker":case"adjust":return{...e,w:Math.max(8,e.w*o),h:Math.max(8,e.h*o)};case"text":return{...e,fontSize:Math.min(512,Math.max(8,e.fontSize*o)),width:e.width?Math.max(16,e.width*o):e.width,paddingX:e.paddingX?Math.max(0,e.paddingX*o):e.paddingX,paddingY:e.paddingY?Math.max(0,e.paddingY*o):e.paddingY,borderWidth:e.borderWidth?Math.max(0,e.borderWidth*o):e.borderWidth};default:return e}}function rotateOverlay(e,t){return{...e,rotation:normalizeOverlayRotation(t)}}function translateOverlay(e,t,o){switch(e.type){case"pen":{const n=e.points.map((e,n)=>n%2==0?e+t:e+o);return{...e,points:n}}case"line":case"arrow":return{...e,x1:e.x1+t,y1:e.y1+o,x2:e.x2+t,y2:e.y2+o};case"rect":case"ellipse":case"sticker":case"adjust":case"text":return{...e,x:e.x+t,y:e.y+o}}}var DEG2RAD2=Math.PI/180;function rotatedSize(e,t,o){const n=normalizeDeg(o);if(0===n||180===n)return{w:e,h:t};if(90===n||270===n)return{w:t,h:e};const r=n*DEG2RAD2;return{w:Math.round(Math.abs(e*Math.cos(r))+Math.abs(t*Math.sin(r))),h:Math.round(Math.abs(e*Math.sin(r))+Math.abs(t*Math.cos(r)))}}function normalizeDeg(e){return(e%360+360)%360}function evenize(e){const t=Math.round(e);return t-t%2}function centeredMaxRect(e,t){let o=e.w,n=o/t;return n>e.h&&(n=e.h,o=n*t),{x:Math.round((e.w-o)/2),y:Math.round((e.h-n)/2),width:Math.round(o),height:Math.round(n)}}function fitRects(e,t,o){const n={x:0,y:0,width:e.width,height:e.height},r={x:0,y:0,width:t.w,height:t.h};return"cover"===o?{src:centeredMaxRect({w:e.width,h:e.height},t.w/t.h),dst:r}:"contain"===o?{src:n,dst:centeredMaxRect({w:t.w,h:t.h},e.width/e.height)}:{src:n,dst:r}}function outputSize(e,t){if(t.scale)return{w:evenize(t.scale.width),h:evenize(t.scale.height)};if(t.crop)return{w:evenize(t.crop.width),h:evenize(t.crop.height)};const o=rotatedSize(e.w,e.h,t.rotation);return{w:evenize(o.w),h:evenize(o.h)}}function dataUrlToBlob(e){const t=e.match(/^data:(image\/(?:png|jpe?g));base64,([a-z0-9+/=]+)$/i);if(!t)return null;const o=atob(t[2]),n=new Uint8Array(o.length);for(let e=0;e<o.length;e++)n[e]=o.charCodeAt(e);return new Blob([n],{type:t[1].toLowerCase()})}async function buildVideoExportFormData(e,t,o=[]){const n=e.getExportPlan(),r=new FormData;n.videoSrcOrder.forEach((e,o)=>{const n=t[e];n&&("undefined"!=typeof File&&n instanceof File?r.append(`video_${o}`,n,n.name||`video_${o}.mp4`):"url"in n&&"string"==typeof n.url&&n.url&&(r.append(`videoUrl_${o}`,n.url),n.name&&r.append(`videoName_${o}`,n.name),n.type&&r.append(`videoType_${o}`,n.type),null!=n.size&&r.append(`videoSize_${o}`,String(n.size))))}),n.audioSrcOrder.forEach((e,t)=>{const n=o[e];n&&r.append(`audio_${t}`,n,n.name||`audio_${t}`)});const a=overlayLayerRenderOrder(n.state.overlays??[]).filter(e=>!isOverlayHidden(e)&&isDrawableOverlay(e)),i=outputSize(n.state.canvas,n.state);(await Promise.all(a.map(e=>renderOverlaysToPng([e],i.w,i.h)))).forEach((e,t)=>{e&&r.append(`textOverlay_${t}`,e,`textOverlay_${t}.png`)});const s=n.state.poster?.useAsVideoCover?n.state.poster.preview||n.state.poster.src:"",l=s?dataUrlToBlob(s):null;if(l){const e="image/png"===l.type?"video-cover.png":"video-cover.jpg";r.append("videoCover",l,e)}const d=n.state.poster?.preview||n.state.poster?.src?{...n.state,poster:{...n.state.poster,preview:void 0,src:void 0}}:n.state;return r.append("editState",JSON.stringify(d)),r}var StrokeCommon={color:zod.z.string().max(32),width:zod.z.number().positive().max(200)},RotationCommon={rotation:zod.z.number().min(-180).max(180).optional()},TimelineCommon={startAt:zod.z.number().min(0).optional(),endAt:zod.z.number().min(0).optional(),timelineTrack:zod.z.number().int().min(0).max(99).optional(),hidden:zod.z.boolean().optional(),locked:zod.z.boolean().optional()},FilterCommon={brightness:zod.z.number().min(-1).max(1).default(0),contrast:zod.z.number().min(-1).max(1).default(0),saturation:zod.z.number().min(-1).max(1).default(0),temperature:zod.z.number().min(-1).max(1).default(0),tint:zod.z.number().min(-1).max(1).default(0),vibrance:zod.z.number().min(-1).max(1).default(0),gamma:zod.z.number().min(-1).max(1).default(0),highlights:zod.z.number().min(-1).max(1).default(0),shadows:zod.z.number().min(-1).max(1).default(0),whites:zod.z.number().min(-1).max(1).default(0),blacks:zod.z.number().min(-1).max(1).default(0),lightSense:zod.z.number().min(-1).max(1).default(0),sharpen:zod.z.number().min(0).max(1).default(0),clarity:zod.z.number().min(0).max(1).default(0),grain:zod.z.number().min(0).max(1).default(0),fade:zod.z.number().min(0).max(1).default(0),vignette:zod.z.number().min(0).max(1).default(0)},Overlay=zod.z.discriminatedUnion("type",[zod.z.object({type:zod.z.literal("pen"),points:zod.z.array(zod.z.number()).min(4),...StrokeCommon,...TimelineCommon,...RotationCommon}),zod.z.object({type:zod.z.literal("line"),x1:zod.z.number(),y1:zod.z.number(),x2:zod.z.number(),y2:zod.z.number(),...StrokeCommon,...TimelineCommon,...RotationCommon}),zod.z.object({type:zod.z.literal("arrow"),x1:zod.z.number(),y1:zod.z.number(),x2:zod.z.number(),y2:zod.z.number(),...StrokeCommon,...TimelineCommon,...RotationCommon}),zod.z.object({type:zod.z.literal("rect"),x:zod.z.number(),y:zod.z.number(),w:zod.z.number(),h:zod.z.number(),...StrokeCommon,...TimelineCommon,...RotationCommon}),zod.z.object({type:zod.z.literal("ellipse"),x:zod.z.number(),y:zod.z.number(),w:zod.z.number(),h:zod.z.number(),...StrokeCommon,...TimelineCommon,...RotationCommon}),zod.z.object({type:zod.z.literal("text"),x:zod.z.number(),y:zod.z.number(),text:zod.z.string().max(500),color:zod.z.string().max(32),fontSize:zod.z.number().positive().max(512),fontFamily:zod.z.string().max(120).optional(),fontWeight:zod.z.string().max(20).optional(),italic:zod.z.boolean().optional(),underline:zod.z.boolean().optional(),strikethrough:zod.z.boolean().optional(),align:zod.z.enum(["left","center","right"]).optional(),width:zod.z.number().positive().max(8192).optional(),backgroundColor:zod.z.string().max(32).optional(),strokeColor:zod.z.string().max(32).optional(),borderWidth:zod.z.number().min(0).max(64).optional(),paddingX:zod.z.number().min(0).max(256).optional(),paddingY:zod.z.number().min(0).max(256).optional(),lineHeight:zod.z.number().positive().max(4).optional(),opacity:zod.z.number().min(0).max(100).optional(),...TimelineCommon,...RotationCommon}),zod.z.object({type:zod.z.literal("sticker"),x:zod.z.number(),y:zod.z.number(),w:zod.z.number().positive(),h:zod.z.number().positive(),emoji:zod.z.string().max(16).optional(),src:zod.z.string().optional(),...TimelineCommon,...RotationCommon}),zod.z.object({type:zod.z.literal("adjust"),x:zod.z.number(),y:zod.z.number(),w:zod.z.number().positive(),h:zod.z.number().positive(),layerKind:zod.z.enum(["adjust","filter"]).optional(),filterPreset:zod.z.string().max(32).optional(),...FilterCommon,...TimelineCommon,...RotationCommon})]),Clip=zod.z.object({srcIdx:zod.z.number().int().min(0).max(7),in:zod.z.number().min(0),out:zod.z.number().min(0),hidden:zod.z.boolean().optional(),locked:zod.z.boolean().optional()}),AudioClip=zod.z.object({srcIdx:zod.z.number().int().min(0).max(2),track:zod.z.number().int().min(0).default(0),startAt:zod.z.number().min(0),in:zod.z.number().min(0),out:zod.z.number().min(0),speed:zod.z.number().min(.5).max(2).default(1),volume:zod.z.number().min(0).max(10),muted:zod.z.boolean().optional(),locked:zod.z.boolean().optional(),fadeIn:zod.z.number().min(0).default(0),fadeOut:zod.z.number().min(0).default(0)}),Transition=zod.z.object({type:zod.z.enum(["none","fade","slide","wipe","flip","clockWipe","star","circle","rectangle"]).default("none"),duration:zod.z.number().min(0).max(2).default(.4)}),ExportSettings=zod.z.object({fileName:zod.z.string().max(120).optional(),format:zod.z.enum(["mp4","mov","mxf"]).default("mp4"),width:zod.z.number().int().min(2).max(8192).optional(),height:zod.z.number().int().min(2).max(8192).optional(),frameRate:zod.z.number().int().min(12).max(120).default(30),bitrateMode:zod.z.enum(["auto","custom"]).optional(),videoBitrateKbps:zod.z.number().int().min(100).max(5e4).optional(),audioBitrateKbps:zod.z.number().int().min(32).max(1024).optional(),audioCodec:zod.z.enum(["aac","mp3"]).default("aac")}).optional(),DEFAULT_FILTERS={brightness:0,contrast:0,saturation:0,temperature:0,tint:0,vibrance:0,gamma:0,highlights:0,shadows:0,whites:0,blacks:0,lightSense:0,sharpen:0,clarity:0,grain:0,fade:0,vignette:0};zod.z.object({clips:zod.z.array(Clip).min(1).max(50),audioClips:zod.z.array(AudioClip).max(8).default([]),canvas:zod.z.object({w:zod.z.number().int().min(2).max(4096),h:zod.z.number().int().min(2).max(4096)}),crop:zod.z.object({x:zod.z.number().min(0),y:zod.z.number().min(0),width:zod.z.number().positive(),height:zod.z.number().positive()}).optional(),scale:zod.z.object({width:zod.z.number().positive(),height:zod.z.number().positive(),fit:zod.z.enum(["contain","cover","force"]),backgroundColor:zod.z.string().max(32).optional()}).optional(),rotation:zod.z.number().min(-180).max(180).default(0),flipX:zod.z.boolean().default(!1),flipY:zod.z.boolean().default(!1),filters:zod.z.object(FilterCommon).default(DEFAULT_FILTERS),filterPreset:zod.z.string().max(32).optional(),overlays:zod.z.array(Overlay).max(200).optional(),transitions:zod.z.array(Transition).max(49).default([]),keepAudio:zod.z.boolean().default(!0),poster:zod.z.object({time:zod.z.number().min(0),src:zod.z.string().optional(),useAsVideoCover:zod.z.boolean().optional(),preview:zod.z.string().optional()}).optional(),exportSettings:ExportSettings}).superRefine((e,t)=>{e.clips.forEach((e,o)=>{e.out<=e.in&&t.addIssue({code:zod.z.ZodIssueCode.custom,message:`clips[${o}].out 必须大于 in`,path:["clips",o,"out"]})}),e.audioClips?.forEach((e,o)=>{e.out<=e.in&&t.addIssue({code:zod.z.ZodIssueCode.custom,message:`audioClips[${o}].out 必须大于 in`,path:["audioClips",o,"out"]})}),e.canvas.w%2==0&&e.canvas.h%2==0||t.addIssue({code:zod.z.ZodIssueCode.custom,message:"canvas 宽高必须为偶数",path:["canvas"]}),null!=e.exportSettings?.width&&e.exportSettings.width%2!=0&&t.addIssue({code:zod.z.ZodIssueCode.custom,message:"exportSettings.width must be even",path:["exportSettings","width"]}),null!=e.exportSettings?.height&&e.exportSettings.height%2!=0&&t.addIssue({code:zod.z.ZodIssueCode.custom,message:"exportSettings.height must be even",path:["exportSettings","height"]})});var FILTER_PRESETS=[{id:"bw",label:"黑白",vf:"hue=s=0",css:"grayscale(1)"},{id:"sepia",label:"复古",vf:"colorchannelmixer=.393:.769:.189:0:.349:.686:.168:0:.272:.534:.131",css:"sepia(0.85)"},{id:"warm",label:"暖阳",vf:"colorbalance=rs=.15:gs=.04:bs=-.15",css:"sepia(0.25) saturate(1.25) brightness(1.03)"},{id:"cool",label:"冷调",vf:"colorbalance=rs=-.14:bs=.16",css:"hue-rotate(12deg) saturate(0.95) brightness(1.02)"},{id:"vivid",label:"鲜艳",vf:"eq=saturation=1.45:contrast=1.08",css:"saturate(1.45) contrast(1.08)"}];function findFilterPreset(e){return e?FILTER_PRESETS.find(t=>t.id===e):void 0}function buildFilterCss(e,t){const o=findFilterPreset(t)?.css??"",n=e.temperature??0,r=e.tint??0,a=e.vibrance??0,i=e.gamma??0,s=e.sharpen??0,l=e.clarity??0;return[`brightness(${1+e.brightness})`,`contrast(${1+e.contrast})`,`saturate(${1+e.saturation})`,o,a?`saturate(${(1+.65*a).toFixed(3)})`:"",n>0?`sepia(${Math.min(.36,.28*n).toFixed(3)})`:"",n?`hue-rotate(${(14*-n).toFixed(2)}deg)`:"",r?`hue-rotate(${(10*r).toFixed(2)}deg)`:"",i?`brightness(${(1+.08*i).toFixed(3)})`:"",l||s?`contrast(${(1+.16*l+.1*s).toFixed(3)})`:""].filter(Boolean).join(" ")}var DEFAULT_SCALE_BACKGROUND="#000000";function normalizeScaleBackgroundColor(e){if("string"!=typeof e)return DEFAULT_SCALE_BACKGROUND;const t=e.trim(),o=t.match(/^#?([0-9a-fA-F]{3})$/);if(o)return`#${o[1].split("").map(e=>e+e).join("").toLowerCase()}`;const n=t.match(/^#?([0-9a-fA-F]{6})$/);return n?`#${n[1].toLowerCase()}`:DEFAULT_SCALE_BACKGROUND}function hasAdjustmentEffect(e){return Boolean(e.filterPreset)||Object.keys(DEFAULT_FILTERS).some(t=>Math.abs(Number(e[t])||0)>1e-4)}function applyAdjustmentOverlay(e,t,o,n){if(!hasAdjustmentEffect(o))return;const r=Math.max(0,Math.round(o.x*n)),a=Math.max(0,Math.round(o.y*n)),i=Math.min(t.width-r,Math.max(1,Math.round(o.w*n))),s=Math.min(t.height-a,Math.max(1,Math.round(o.h*n)));if(i<=0||s<=0)return;const l=document.createElement("canvas");l.width=i,l.height=s;const d=l.getContext("2d");d&&(d.drawImage(t,r,a,i,s,0,0,i,s),e.save(),e.filter=buildFilterCss({...DEFAULT_FILTERS,...o},o.filterPreset),e.drawImage(l,r,a,i,s),e.restore(),e.filter="none")}function drawLayeredOverlays(e,t,o,n,r,a=1){if(o?.length){e.setTransform(a,0,0,a,0,0);for(const i of overlayLayerRenderOrder(o))isOverlayHidden(i)||("number"!=typeof r||isOverlayActiveAt(i,r))&&("adjust"===i.type?(e.setTransform(1,0,0,1,0,0),applyAdjustmentOverlay(e,t,i,a),e.setTransform(a,0,0,a,0,0)):drawOverlay(e,i,n));e.setTransform(1,0,0,1,0,0)}}function drawVideoFrame(e,t,o,n,r,a=1,i,s=!0){const l=outputSize(n,r);e.width=Math.max(2,Math.round(l.w*a)),e.height=Math.max(2,Math.round(l.h*a));const d=e.getContext("2d");if(!d)return;if(Boolean(r.__mePreviewVideoHidden)){d.fillStyle="#000000",d.fillRect(0,0,e.width,e.height);const t=Number.isFinite(r.__mePreviewTimelineTime)?Number(r.__mePreviewTimelineTime):void 0;return void(s&&r.overlays?.length&&drawLayeredOverlays(d,e,r.overlays,i,t,a))}const m=rotatedSize(n.w,n.h,r.rotation),u=r.crop??{x:0,y:0,width:m.w,height:m.h},c=r.scale?.fit??"force",{src:h,dst:z}=fitRects({width:u.width,height:u.height},l,c);"contain"===c&&(d.fillStyle=normalizeScaleBackgroundColor(r.scale?.backgroundColor),d.fillRect(0,0,e.width,e.height)),d.filter=buildFilterCss(r.filters,r.filterPreset),d.save(),"contain"===c&&(d.beginPath(),d.rect(a*z.x,a*z.y,a*z.width,a*z.height),d.clip()),d.translate(a*z.x,a*z.y),d.scale(a*z.width/h.width,a*z.height/h.height),d.translate(-(u.x+h.x),-(u.y+h.y)),d.translate(m.w/2,m.h/2),d.rotate(r.rotation*DEG2RAD2),d.scale(r.flipX?-1:1,r.flipY?-1:1);const p=fitRects({width:o.w,height:o.h},{w:n.w,h:n.h},"cover");d.drawImage(t,p.src.x,p.src.y,p.src.width,p.src.height,-n.w/2,-n.h/2,n.w,n.h),d.restore(),d.filter="none";const x=Number.isFinite(r.__mePreviewTimelineTime)?Number(r.__mePreviewTimelineTime):void 0;s&&r.overlays?.length&&drawLayeredOverlays(d,e,r.overlays,i,x,a)}function seekVideo(e,t){return new Promise(o=>{const n=()=>{e.removeEventListener("seeked",n),o()};e.addEventListener("seeked",n),e.currentTime=Math.min(Math.max(0,t),e.duration||t)})}async function generateThumbnails(e,t,o=160){const n=e.duration;if(!n||!isFinite(n)||t<=0)return[];const r=e.videoWidth||16,a=e.videoHeight||9,i=Math.min(o,r),s=Math.max(1,Math.round(i*a/r)),l=document.createElement("canvas");l.width=i,l.height=s;const d=l.getContext("2d");if(!d)return[];const m=[];for(let o=0;o<t;o++)await seekVideo(e,n*(o+.5)/t),d.drawImage(e,0,0,i,s),m.push(l.toDataURL("image/jpeg",.6));return m}function createFullscreenToggle(e,t={}){const o=t.mode??"overlay",n=document.createElement("button");n.type="button",n.className=["me-fullscreen-toggle",t.className].filter(Boolean).join(" "),n.dataset.meFullscreenToggle="true",n.dataset.mode=o,n.title="全屏 / 退出全屏",n.style.cssText=["overlay"===o?"position:absolute;left:8px;bottom:8px;z-index:30;":"position:static;","width:32px;height:32px;padding:0;","display:inline-flex;align-items:center;justify-content:center;","border:1px solid var(--me-border,#26262b);border-radius:6px;","background:var(--me-chip,#1c1c20);color:var(--me-fg,#e7e7ee);","cursor:pointer;font-size:15px;line-height:1;opacity:0.9;font:inherit;"].join(""),e.classList.add("me-fullscreen-host");const r=()=>{const t=document.fullscreenElement===e;n.textContent=t?"×":"⛶",n.setAttribute("aria-label",t?"退出全屏":"全屏"),e.classList.toggle("me-is-fullscreen",t),e.dataset.meFullscreen=t?"true":"false"};r();const a=()=>r(),i=()=>{const t=document.fullscreenElement===e?document.exitFullscreen?.():e.requestFullscreen?.();t?.catch?.(()=>{})};return n.addEventListener("click",i),document.addEventListener("fullscreenchange",a),{button:n,dispose:()=>{document.removeEventListener("fullscreenchange",a),n.removeEventListener("click",i),n.remove(),e.classList.remove("me-fullscreen-host","me-is-fullscreen"),delete e.dataset.meFullscreen}}}exports.buildVideoExportFormData=buildVideoExportFormData,exports.createFullscreenToggle=createFullscreenToggle,exports.drawLayeredOverlays=drawLayeredOverlays,exports.drawOverlay=drawOverlay,exports.drawOverlays=drawOverlays,exports.drawVideoFrame=drawVideoFrame,exports.filterOverlaysAtTime=filterOverlaysAtTime,exports.fitStickerBox=fitStickerBox,exports.generateThumbnails=generateThumbnails,exports.getOverlayRotation=getOverlayRotation,exports.hitTestOverlay=hitTestOverlay,exports.isDrawableOverlay=isDrawableOverlay,exports.isOverlayActiveAt=isOverlayActiveAt,exports.isOverlayHidden=isOverlayHidden,exports.isOverlayLocked=isOverlayLocked,exports.loadOverlayImages=loadOverlayImages,exports.overlayBBox=overlayBBox,exports.overlayLayerRenderOrder=overlayLayerRenderOrder,exports.overlayTimeRange=overlayTimeRange,exports.renderOverlaysToPng=renderOverlaysToPng,exports.rotateOverlay=rotateOverlay,exports.scaleOverlay=scaleOverlay,exports.translateOverlay=translateOverlay;
@@ -0,0 +1,117 @@
1
+ import { O as OverlayT, V as VideoEditStateT } from './state-D2oM5s1a.js';
2
+ import { VideoEditorEngine } from './engine.js';
3
+ import 'zod';
4
+
5
+ /**
6
+ * editor-core/overlay-render —— 标注/贴纸绘制(浏览器环境,Canvas API;零框架依赖)。
7
+ * 交互画布与导出 PNG 共用 drawOverlays,保证所见即所得。
8
+ * 坐标系 = 最终输出空间(旋转/裁剪/缩放后),导出 PNG 即按输出分辨率渲染。
9
+ */
10
+
11
+ declare function isDrawableOverlay(o: OverlayT): boolean;
12
+ declare function isOverlayHidden(o: OverlayT): boolean;
13
+ declare function isOverlayLocked(o: OverlayT): boolean;
14
+ declare function overlayLayerRenderOrder<T extends OverlayT>(overlays: readonly T[]): T[];
15
+ declare function getOverlayRotation(o: OverlayT): number;
16
+ declare function overlayBBox(o: OverlayT): {
17
+ x: number;
18
+ y: number;
19
+ w: number;
20
+ h: number;
21
+ };
22
+ declare function overlayTimeRange(o: OverlayT): {
23
+ start: number;
24
+ end: number;
25
+ } | null;
26
+ declare function isOverlayActiveAt(o: OverlayT, time: number): boolean;
27
+ declare function filterOverlaysAtTime(overlays: OverlayT[] | undefined, time: number): OverlayT[];
28
+ /** 单个对象绘制;sticker 的位图经 imageCache 提供(加载由调用方负责) */
29
+ declare function drawOverlay(ctx: CanvasRenderingContext2D, o: OverlayT, imageCache?: Map<string, HTMLImageElement>): void;
30
+ declare function drawOverlays(ctx: CanvasRenderingContext2D, overlays: OverlayT[], imageCache?: Map<string, HTMLImageElement>, time?: number): void;
31
+ /** sticker 位图预加载(dataURL → HTMLImageElement) */
32
+ declare function loadOverlayImages(overlays: OverlayT[]): Promise<Map<string, HTMLImageElement>>;
33
+ /** 导出:把 overlays 渲染成输出分辨率的透明 PNG Blob(无 overlay 返回 null) */
34
+ declare function renderOverlaysToPng(overlays: OverlayT[] | undefined, width: number, height: number): Promise<Blob | null>;
35
+ /** 命中检测(选中/拖动用):返回最上层命中的 overlay 下标,无命中 -1 */
36
+ declare function hitTestOverlay(overlays: OverlayT[], x: number, y: number, tolerance?: number): number;
37
+ /**
38
+ * 贴纸图片等比落盒:长边 = boxSide、短边按原始宽高比,下限 8px。
39
+ * 上传任意比例图片不再被压成正方形(drawImage 是拉伸语义,入库 w/h 必须等比)。
40
+ */
41
+ declare function fitStickerBox(natW: number, natH: number, boxSide: number): {
42
+ w: number;
43
+ h: number;
44
+ };
45
+ /**
46
+ * 缩放 overlay(选中后拖右下角把手):以对象左上角为锚,按 ratio 等比。
47
+ * sticker/rect/ellipse 改 w/h;text 改 fontSize;pen/line/arrow 不支持(原样返回)。
48
+ */
49
+ declare function scaleOverlay(o: OverlayT, ratio: number): OverlayT;
50
+ /** 旋转 overlay:以对象 bbox 中心为视觉锚点;坐标本身不变,绘制/命中检测按 rotation 处理。 */
51
+ declare function rotateOverlay(o: OverlayT, deg: number): OverlayT;
52
+ /** 平移 overlay(拖动选中对象) */
53
+ declare function translateOverlay(o: OverlayT, dx: number, dy: number): OverlayT;
54
+
55
+ /**
56
+ * 把引擎导出计划 + 浏览器端 File 组装成服务端约定的 FormData
57
+ * (video_0../audio_0../overlay/editState),供 @media-editor/client.exportVideo 直接发。
58
+ * 触碰 DOM(overlay → canvas PNG),故归 @media-editor/core/browser,React/Vue 共用。
59
+ */
60
+
61
+ type VideoExportSource = File | {
62
+ url: string;
63
+ name?: string;
64
+ type?: string;
65
+ size?: number;
66
+ };
67
+ /**
68
+ * @param videoFiles 以「原始 srcIdx」为下标的视频 File 数组(引擎按 videoSrcOrder 取并重排)
69
+ * @param audioFiles 同上(音频)
70
+ */
71
+ declare function buildVideoExportFormData(engine: VideoEditorEngine, videoFiles: ReadonlyArray<VideoExportSource | undefined>, audioFiles?: ReadonlyArray<File | undefined>): Promise<FormData>;
72
+
73
+ /**
74
+ * 帧合成器(框架无关 canvas)—— 把「源帧 → 输出画布 + 完整效果链 + overlays」绘到 canvas。
75
+ * 从 SocialEcho VideoFramePreview.drawFinalFrame 抽出,供实时预览与封面导出复用。
76
+ *
77
+ * 效果链与 ffmpeg 导出严格同构:源→画布 cover 归一 → flips → rotate → crop → scale + 调色/滤镜 css。
78
+ */
79
+
80
+ /** drawImage 可接受的源(video / image / canvas) */
81
+ type FrameSource = CanvasImageSource;
82
+ declare function drawLayeredOverlays(ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement, overlays: OverlayT[] | undefined, imageCache?: Map<string, HTMLImageElement>, time?: number, k?: number): void;
83
+ /**
84
+ * 把一帧合成绘到 canvas(物理分辨率 = 输出尺寸 × k)。
85
+ * @param srcDims 活动源原始分辨率(逐片段可能不同)
86
+ * @param canvasDims 输出画布(= 首素材分辨率),全局效果链的「源 dims」
87
+ * @param k 物理像素倍率(预览用 ≤1 控带宽,封面导出用 1 全分辨率)
88
+ * @param imageCache 贴纸图片缓存(loadOverlayImages 产出)
89
+ */
90
+ declare function drawVideoFrame(canvas: HTMLCanvasElement, source: FrameSource, srcDims: {
91
+ w: number;
92
+ h: number;
93
+ }, canvasDims: {
94
+ w: number;
95
+ h: number;
96
+ }, state: VideoEditStateT, k?: number, imageCache?: Map<string, HTMLImageElement>, withOverlays?: boolean): void;
97
+ /**
98
+ * 抽 count 张等距缩略图(dataURL,jpeg)。供时间轴缩略图条 / 封面条。
99
+ * 传入**专用离屏 video 元素**(勿用主预览源,seek 会打断播放)。
100
+ */
101
+ declare function generateThumbnails(videoEl: HTMLVideoElement, count: number, maxW?: number): Promise<string[]>;
102
+
103
+ /**
104
+ * 全屏切换按钮(框架无关 DOM)。点按对 host 进/出全屏;监听 fullscreenchange 切图标和 host 状态类。
105
+ * 图片/视频 mount 共用:默认可作为覆盖按钮,也可放进宿主自己的返回工具栏。
106
+ */
107
+ interface FullscreenToggle {
108
+ button: HTMLButtonElement;
109
+ dispose: () => void;
110
+ }
111
+ interface FullscreenToggleOptions {
112
+ mode?: 'overlay' | 'inline';
113
+ className?: string;
114
+ }
115
+ declare function createFullscreenToggle(host: HTMLElement, options?: FullscreenToggleOptions): FullscreenToggle;
116
+
117
+ export { type FrameSource, type FullscreenToggle, type FullscreenToggleOptions, type VideoExportSource, buildVideoExportFormData, createFullscreenToggle, drawLayeredOverlays, drawOverlay, drawOverlays, drawVideoFrame, filterOverlaysAtTime, fitStickerBox, generateThumbnails, getOverlayRotation, hitTestOverlay, isDrawableOverlay, isOverlayActiveAt, isOverlayHidden, isOverlayLocked, loadOverlayImages, overlayBBox, overlayLayerRenderOrder, overlayTimeRange, renderOverlaysToPng, rotateOverlay, scaleOverlay, translateOverlay };
@@ -0,0 +1 @@
1
+ import{overlayLayerRenderOrder as e,isOverlayHidden as t,isDrawableOverlay as r,outputSize as n,renderOverlaysToPng as a,isOverlayActiveAt as i,drawOverlay as o,rotatedSize as s,fitRects as l,buildFilterCss as c,DEG2RAD as d}from"./chunk-VDEZTXEA.js";export{drawOverlay,drawOverlays,filterOverlaysAtTime,fitStickerBox,getOverlayRotation,hitTestOverlay,isDrawableOverlay,isOverlayActiveAt,isOverlayHidden,isOverlayLocked,loadOverlayImages,overlayBBox,overlayLayerRenderOrder,overlayTimeRange,renderOverlaysToPng,rotateOverlay,scaleOverlay,translateOverlay}from"./chunk-VDEZTXEA.js";import{DEFAULT_FILTERS as h}from"./chunk-7PSQLYXL.js";async function m(i,o,s=[]){const l=i.getExportPlan(),c=new FormData;l.videoSrcOrder.forEach((e,t)=>{const r=o[e];r&&("undefined"!=typeof File&&r instanceof File?c.append(`video_${t}`,r,r.name||`video_${t}.mp4`):"url"in r&&"string"==typeof r.url&&r.url&&(c.append(`videoUrl_${t}`,r.url),r.name&&c.append(`videoName_${t}`,r.name),r.type&&c.append(`videoType_${t}`,r.type),null!=r.size&&c.append(`videoSize_${t}`,String(r.size))))}),l.audioSrcOrder.forEach((e,t)=>{const r=s[e];r&&c.append(`audio_${t}`,r,r.name||`audio_${t}`)});const d=l.state.overlays??[],h=e(d).filter(e=>!t(e)&&r(e)),m=n(l.state.canvas,l.state);(await Promise.all(h.map(e=>a([e],m.w,m.h)))).forEach((e,t)=>{e&&c.append(`textOverlay_${t}`,e,`textOverlay_${t}.png`)});const u=l.state.poster?.useAsVideoCover?l.state.poster.preview||l.state.poster.src:"",f=u?function(e){const t=e.match(/^data:(image\/(?:png|jpe?g));base64,([a-z0-9+/=]+)$/i);if(!t)return null;const r=atob(t[2]),n=new Uint8Array(r.length);for(let e=0;e<r.length;e++)n[e]=r.charCodeAt(e);return new Blob([n],{type:t[1].toLowerCase()})}(u):null;if(f){const e="image/png"===f.type?"video-cover.png":"video-cover.jpg";c.append("videoCover",f,e)}const v=l.state.poster?.preview||l.state.poster?.src?{...l.state,poster:{...l.state.poster,preview:void 0,src:void 0}}:l.state;return c.append("editState",JSON.stringify(v)),c}var u="#000000";function f(e,t,r,n){if(a=r,!Boolean(a.filterPreset)&&!Object.keys(h).some(e=>Math.abs(Number(a[e])||0)>1e-4))return;var a;const i=Math.max(0,Math.round(r.x*n)),o=Math.max(0,Math.round(r.y*n)),s=Math.min(t.width-i,Math.max(1,Math.round(r.w*n))),l=Math.min(t.height-o,Math.max(1,Math.round(r.h*n)));if(s<=0||l<=0)return;const d=document.createElement("canvas");d.width=s,d.height=l;const m=d.getContext("2d");m&&(m.drawImage(t,i,o,s,l,0,0,s,l),e.save(),e.filter=c({...h,...r},r.filterPreset),e.drawImage(d,i,o,s,l),e.restore(),e.filter="none")}function v(r,n,a,s,l,c=1){if(a?.length){r.setTransform(c,0,0,c,0,0);for(const d of e(a))t(d)||("number"!=typeof l||i(d,l))&&("adjust"===d.type?(r.setTransform(1,0,0,1,0,0),f(r,n,d,c),r.setTransform(c,0,0,c,0,0)):o(r,d,s));r.setTransform(1,0,0,1,0,0)}}function p(e,t,r,a,i,o=1,h,m=!0){const f=n(a,i);e.width=Math.max(2,Math.round(f.w*o)),e.height=Math.max(2,Math.round(f.h*o));const p=e.getContext("2d");if(!p)return;if(Boolean(i.__mePreviewVideoHidden)){p.fillStyle="#000000",p.fillRect(0,0,e.width,e.height);const t=Number.isFinite(i.__mePreviewTimelineTime)?Number(i.__mePreviewTimelineTime):void 0;return void(m&&i.overlays?.length&&v(p,e,i.overlays,h,t,o))}const g=s(a.w,a.h,i.rotation),y=i.crop??{x:0,y:0,width:g.w,height:g.h},w=i.scale?.fit??"force",{src:x,dst:b}=l({width:y.width,height:y.height},f,w);"contain"===w&&(p.fillStyle=function(e){if("string"!=typeof e)return u;const t=e.trim(),r=t.match(/^#?([0-9a-fA-F]{3})$/);if(r)return`#${r[1].split("").map(e=>e+e).join("").toLowerCase()}`;const n=t.match(/^#?([0-9a-fA-F]{6})$/);return n?`#${n[1].toLowerCase()}`:u}(i.scale?.backgroundColor),p.fillRect(0,0,e.width,e.height)),p.filter=c(i.filters,i.filterPreset),p.save(),"contain"===w&&(p.beginPath(),p.rect(o*b.x,o*b.y,o*b.width,o*b.height),p.clip()),p.translate(o*b.x,o*b.y),p.scale(o*b.width/x.width,o*b.height/x.height),p.translate(-(y.x+x.x),-(y.y+x.y)),p.translate(g.w/2,g.h/2),p.rotate(i.rotation*d),p.scale(i.flipX?-1:1,i.flipY?-1:1);const T=l({width:r.w,height:r.h},{w:a.w,h:a.h},"cover");p.drawImage(t,T.src.x,T.src.y,T.src.width,T.src.height,-a.w/2,-a.h/2,a.w,a.h),p.restore(),p.filter="none";const O=Number.isFinite(i.__mePreviewTimelineTime)?Number(i.__mePreviewTimelineTime):void 0;m&&i.overlays?.length&&v(p,e,i.overlays,h,O,o)}function g(e,t){return new Promise(r=>{const n=()=>{e.removeEventListener("seeked",n),r()};e.addEventListener("seeked",n),e.currentTime=Math.min(Math.max(0,t),e.duration||t)})}async function y(e,t,r=160){const n=e.duration;if(!n||!isFinite(n)||t<=0)return[];const a=e.videoWidth||16,i=e.videoHeight||9,o=Math.min(r,a),s=Math.max(1,Math.round(o*i/a)),l=document.createElement("canvas");l.width=o,l.height=s;const c=l.getContext("2d");if(!c)return[];const d=[];for(let r=0;r<t;r++)await g(e,n*(r+.5)/t),c.drawImage(e,0,0,o,s),d.push(l.toDataURL("image/jpeg",.6));return d}function w(e,t={}){const r=t.mode??"overlay",n=document.createElement("button");n.type="button",n.className=["me-fullscreen-toggle",t.className].filter(Boolean).join(" "),n.dataset.meFullscreenToggle="true",n.dataset.mode=r,n.title="全屏 / 退出全屏",n.style.cssText=["overlay"===r?"position:absolute;left:8px;bottom:8px;z-index:30;":"position:static;","width:32px;height:32px;padding:0;","display:inline-flex;align-items:center;justify-content:center;","border:1px solid var(--me-border,#26262b);border-radius:6px;","background:var(--me-chip,#1c1c20);color:var(--me-fg,#e7e7ee);","cursor:pointer;font-size:15px;line-height:1;opacity:0.9;font:inherit;"].join(""),e.classList.add("me-fullscreen-host");const a=()=>{const t=document.fullscreenElement===e;n.textContent=t?"×":"⛶",n.setAttribute("aria-label",t?"退出全屏":"全屏"),e.classList.toggle("me-is-fullscreen",t),e.dataset.meFullscreen=t?"true":"false"};a();const i=()=>a(),o=()=>{const t=document.fullscreenElement===e?document.exitFullscreen?.():e.requestFullscreen?.();t?.catch?.(()=>{})};return n.addEventListener("click",o),document.addEventListener("fullscreenchange",i),{button:n,dispose:()=>{document.removeEventListener("fullscreenchange",i),n.removeEventListener("click",o),n.remove(),e.classList.remove("me-fullscreen-host","me-is-fullscreen"),delete e.dataset.meFullscreen}}}export{m as buildVideoExportFormData,w as createFullscreenToggle,v as drawLayeredOverlays,p as drawVideoFrame,y as generateThumbnails};
@@ -0,0 +1 @@
1
+ var t=.1;function n(t){return t.out-t.in}function e(t){return t.reduce((t,e)=>t+n(e),0)}function r(t,e){let r=0;for(let u=0;u<e&&u<t.length;u++)r+=n(t[u]);return r}function u(t,e){if(!t.length||e<0)return null;let r=0;for(let u=0;u<t.length;u++){const i=n(t[u]);if(e<r+i)return{idx:u,srcTime:t[u].in+(e-r)};r+=i}if(Math.abs(e-r)<1e-9||e<=r){const n=t.length-1;return{idx:n,srcTime:t[n].out}}return null}function i(n,e){const r=u(n,e);if(!r)return n;const i=n[r.idx];return r.srcTime<i.in+t||r.srcTime>i.out-t?n:[...n.slice(0,r.idx),{...i,out:r.srcTime},{...i,in:r.srcTime},...n.slice(r.idx+1)]}function s(t,n){return t.length<=1||!t[n]?t:t.filter((t,e)=>e!==n)}function c(t,n){const e=t[n];return e?[...t.slice(0,n+1),{...e},...t.slice(n+1)]:t}function o(t,n,e){if(n===e||!t[n]||e<0||e>=t.length)return t;const r=[...t],[u]=r.splice(n,1);return r.splice(e,0,u),r}function a(n,e,r,u,i){if(!n[e])return n;const s=n.map(t=>({...t}));return"in"===r?s[e].in=Math.min(Math.max(u,0),s[e].out-t):s[e].out=Math.max(Math.min(u,i),s[e].in+t),s}function f(n,e,r){const u=Math.max(Math.min(n.out,e),t),i=Math.min(Math.max(n.in,0),u-t),s=Math.min(Math.max(n.startAt,0),Math.max(0,r-t));return{...n,in:i,out:u,startAt:s}}function p(t,n=[]){const r=e(t),u=n.reduce((t,n)=>Math.max(t,n.startAt+(n.out-n.in)/Math.max(.01,n.speed??1)),0);return Math.max(r,u)}function h(t){return[...new Set(t.map(t=>t.srcIdx))].sort((t,n)=>t-n)}function l(t,n){const e=new Map(n.map((t,n)=>[t,n]));return t.map(t=>({...t,srcIdx:e.get(t.srcIdx)??0}))}function m(t){return{past:[],present:t,future:[]}}function x(t,n){if(n===t.present)return t;const e=[...t.past,t.present];return e.length>100&&e.shift(),{past:e,present:n,future:[]}}function M(t,n){return n===t.present?t:{...t,present:n}}function d(t){return t.past.length>0}function g(t){return t.future.length>0}function T(t){return d(t)?{past:t.past.slice(0,-1),present:t.past[t.past.length-1],future:[t.present,...t.future]}:t}function A(t){if(!g(t))return t;const[n,...e]=t.future;return{past:[...t.past,t.present],present:n,future:e}}export{t as MIN_CLIP,g as canRedo,d as canUndo,f as clampAudioClip,n as clipDuration,r as clipStartsAt,p as contentDuration,m as createHistory,c as duplicateClip,u as locateOutput,x as pushHistory,A as redo,l as remapSrcIndices,s as removeClip,o as reorderClips,M as replacePresent,i as splitAtOutput,e as totalDuration,a as trimClipEdge,T as undo,h as usedVideoSrcIndices};
@@ -0,0 +1 @@
1
+ import{z as e}from"zod";var t={color:e.string().max(32),width:e.number().positive().max(200)},n={rotation:e.number().min(-180).max(180).optional()},i={startAt:e.number().min(0).optional(),endAt:e.number().min(0).optional(),timelineTrack:e.number().int().min(0).max(99).optional(),hidden:e.boolean().optional(),locked:e.boolean().optional()},a={brightness:e.number().min(-1).max(1).default(0),contrast:e.number().min(-1).max(1).default(0),saturation:e.number().min(-1).max(1).default(0),temperature:e.number().min(-1).max(1).default(0),tint:e.number().min(-1).max(1).default(0),vibrance:e.number().min(-1).max(1).default(0),gamma:e.number().min(-1).max(1).default(0),highlights:e.number().min(-1).max(1).default(0),shadows:e.number().min(-1).max(1).default(0),whites:e.number().min(-1).max(1).default(0),blacks:e.number().min(-1).max(1).default(0),lightSense:e.number().min(-1).max(1).default(0),sharpen:e.number().min(0).max(1).default(0),clarity:e.number().min(0).max(1).default(0),grain:e.number().min(0).max(1).default(0),fade:e.number().min(0).max(1).default(0),vignette:e.number().min(0).max(1).default(0)},o=e.discriminatedUnion("type",[e.object({type:e.literal("pen"),points:e.array(e.number()).min(4),...t,...i,...n}),e.object({type:e.literal("line"),x1:e.number(),y1:e.number(),x2:e.number(),y2:e.number(),...t,...i,...n}),e.object({type:e.literal("arrow"),x1:e.number(),y1:e.number(),x2:e.number(),y2:e.number(),...t,...i,...n}),e.object({type:e.literal("rect"),x:e.number(),y:e.number(),w:e.number(),h:e.number(),...t,...i,...n}),e.object({type:e.literal("ellipse"),x:e.number(),y:e.number(),w:e.number(),h:e.number(),...t,...i,...n}),e.object({type:e.literal("text"),x:e.number(),y:e.number(),text:e.string().max(500),color:e.string().max(32),fontSize:e.number().positive().max(512),fontFamily:e.string().max(120).optional(),fontWeight:e.string().max(20).optional(),italic:e.boolean().optional(),underline:e.boolean().optional(),strikethrough:e.boolean().optional(),align:e.enum(["left","center","right"]).optional(),width:e.number().positive().max(8192).optional(),backgroundColor:e.string().max(32).optional(),strokeColor:e.string().max(32).optional(),borderWidth:e.number().min(0).max(64).optional(),paddingX:e.number().min(0).max(256).optional(),paddingY:e.number().min(0).max(256).optional(),lineHeight:e.number().positive().max(4).optional(),opacity:e.number().min(0).max(100).optional(),...i,...n}),e.object({type:e.literal("sticker"),x:e.number(),y:e.number(),w:e.number().positive(),h:e.number().positive(),emoji:e.string().max(16).optional(),src:e.string().optional(),...i,...n}),e.object({type:e.literal("adjust"),x:e.number(),y:e.number(),w:e.number().positive(),h:e.number().positive(),layerKind:e.enum(["adjust","filter"]).optional(),filterPreset:e.string().max(32).optional(),...a,...i,...n})]),m=e.object({srcIdx:e.number().int().min(0).max(7),in:e.number().min(0),out:e.number().min(0),hidden:e.boolean().optional(),locked:e.boolean().optional()}),r=e.object({srcIdx:e.number().int().min(0).max(2),track:e.number().int().min(0).default(0),startAt:e.number().min(0),in:e.number().min(0),out:e.number().min(0),speed:e.number().min(.5).max(2).default(1),volume:e.number().min(0).max(10),muted:e.boolean().optional(),locked:e.boolean().optional(),fadeIn:e.number().min(0).default(0),fadeOut:e.number().min(0).default(0)}),u=e.object({type:e.enum(["none","fade","slide","wipe","flip","clockWipe","star","circle","rectangle"]).default("none"),duration:e.number().min(0).max(2).default(.4)}),l=e.object({fileName:e.string().max(120).optional(),format:e.enum(["mp4","mov","mxf"]).default("mp4"),width:e.number().int().min(2).max(8192).optional(),height:e.number().int().min(2).max(8192).optional(),frameRate:e.number().int().min(12).max(120).default(30),bitrateMode:e.enum(["auto","custom"]).optional(),videoBitrateKbps:e.number().int().min(100).max(5e4).optional(),audioBitrateKbps:e.number().int().min(32).max(1024).optional(),audioCodec:e.enum(["aac","mp3"]).default("aac")}).optional(),s={brightness:0,contrast:0,saturation:0,temperature:0,tint:0,vibrance:0,gamma:0,highlights:0,shadows:0,whites:0,blacks:0,lightSense:0,sharpen:0,clarity:0,grain:0,fade:0,vignette:0},b=e.object({clips:e.array(m).min(1).max(50),audioClips:e.array(r).max(8).default([]),canvas:e.object({w:e.number().int().min(2).max(4096),h:e.number().int().min(2).max(4096)}),crop:e.object({x:e.number().min(0),y:e.number().min(0),width:e.number().positive(),height:e.number().positive()}).optional(),scale:e.object({width:e.number().positive(),height:e.number().positive(),fit:e.enum(["contain","cover","force"]),backgroundColor:e.string().max(32).optional()}).optional(),rotation:e.number().min(-180).max(180).default(0),flipX:e.boolean().default(!1),flipY:e.boolean().default(!1),filters:e.object(a).default(s),filterPreset:e.string().max(32).optional(),overlays:e.array(o).max(200).optional(),transitions:e.array(u).max(49).default([]),keepAudio:e.boolean().default(!0),poster:e.object({time:e.number().min(0),src:e.string().optional(),useAsVideoCover:e.boolean().optional(),preview:e.string().optional()}).optional(),exportSettings:l}).superRefine((t,n)=>{t.clips.forEach((t,i)=>{t.out<=t.in&&n.addIssue({code:e.ZodIssueCode.custom,message:`clips[${i}].out 必须大于 in`,path:["clips",i,"out"]})}),t.audioClips?.forEach((t,i)=>{t.out<=t.in&&n.addIssue({code:e.ZodIssueCode.custom,message:`audioClips[${i}].out 必须大于 in`,path:["audioClips",i,"out"]})}),t.canvas.w%2==0&&t.canvas.h%2==0||n.addIssue({code:e.ZodIssueCode.custom,message:"canvas 宽高必须为偶数",path:["canvas"]}),null!=t.exportSettings?.width&&t.exportSettings.width%2!=0&&n.addIssue({code:e.ZodIssueCode.custom,message:"exportSettings.width must be even",path:["exportSettings","width"]}),null!=t.exportSettings?.height&&t.exportSettings.height%2!=0&&n.addIssue({code:e.ZodIssueCode.custom,message:"exportSettings.height must be even",path:["exportSettings","height"]})});function p(){return{clips:[],audioClips:[],canvas:{w:2,h:2},rotation:0,flipX:!1,flipY:!1,filters:s,transitions:[],keepAudio:!0}}export{r as AudioClip,m as Clip,s as DEFAULT_FILTERS,l as ExportSettings,o as Overlay,u as Transition,b as VideoEditState,p as defaultVideoEditState};
@@ -0,0 +1 @@
1
+ var e={"tool.trim":"剪辑","tool.crop":"裁剪","tool.tune":"调色","tool.filter":"滤镜","tool.annotate":"标注","tool.sticker":"贴纸","tool.resize":"比例","tune.brightness":"亮度","tune.contrast":"对比","tune.saturation":"饱和","tune.gamma":"Gamma","tune.temperature":"色温","tune.tint":"色调","tune.vibrance":"自然饱和","tune.highlights":"高光","tune.shadows":"阴影","tune.whites":"白色","tune.blacks":"黑色","tune.lightSense":"光感","tune.sharpen":"锐化","tune.clarity":"清晰度","tune.grain":"颗粒","tune.fade":"褪色","tune.vignette":"暗角","overlay.select":"选择","overlay.pen":"画笔","overlay.eraser":"橡皮","overlay.line":"直线","overlay.arrow":"箭头","overlay.rect":"矩形","overlay.ellipse":"椭圆","overlay.text":"文字","overlay.color":"线色","overlay.width":"线宽","overlay.fontSize":"字号","overlay.font":"字体","overlay.align":"对齐","overlay.background":"背景","overlay.copySelected":"复制","overlay.delSelected":"删除选中","overlay.editSelected":"编辑","overlay.pickImage":"选择图片","overlay.hint":"点 emoji/图片添加 → 画布上拖动摆位,拖右下角紫色把手缩放","overlay.textPlaceholder":"输入文字,回车确认","filter.none":"原图","filter.bw":"黑白","filter.sepia":"复古","filter.warm":"暖阳","filter.cool":"冷调","filter.vivid":"鲜艳","ratio.orig":"原始","ratio.free":"自由比例","ratio.9:16":"竖屏 9:16","ratio.16:9":"横屏 16:9","ratio.1:1":"方形 1:1","ratio.4:5":"竖图 4:5","ratio.3:4":"竖图 3:4","ratio.2:3":"竖图 2:3","ratio.1.91:1":"横幅 1.91:1","act.fit":"适应","act.zoomFit":"缩放至适当大小","act.zoomTo":"缩放至 {value}%","act.split":"分割","act.copy":"复制","act.delete":"删除","act.restore":"还原","act.deleteMusic":"删除音乐","act.cancel":"取消","act.exportPoster":"导出封面","act.exporting":"导出中…","act.poster":"🖼 封面","act.again":"再次下载","act.saveDrive":"存网盘","act.changeImage":"← 换一张","act.changeVideo":"← 换一个","crop.rotateLeft":"↺ 向左旋转","crop.flipX":"⇋ 水平翻转","crop.flipY":"⇵ 垂直翻转","crop.rotateLeftShort":"左转","crop.flipXShort":"横翻","crop.flipYShort":"竖翻","tip.close":"关闭(换文件)","tip.undo":"撤销","tip.redo":"重做","tip.resetOpened":"重置到打开文件时","tip.previewZoom":"预览缩放比例","tip.previewZoomOut":"缩小预览","tip.previewZoomIn":"放大预览","tip.previewZoomFit":"适应预览","tip.previewPointer":"指针工具","tip.previewPan":"手工具:拖动画面","tip.poster":"预览并选择封面帧","tip.keepAudio":"原视频声音开关(与音乐混音;预览同步)","tip.split":"在播放头处把当前片段一分为二","tip.zoomOut":"缩小时间轴(Ctrl+滚轮)","tip.zoomIn":"放大时间轴(Ctrl+滚轮)","tip.fit":"缩放到适应宽度","tip.addVideo":"添加视频片段","tip.addAudio":"添加音乐(音频文件,或选含声音的视频自动提取音轨;与原声混音)","tip.dupClip":"复制该片段(插到其后)","tip.delClip":"删除该片段","tip.lockAspect":"锁定纵横比","tip.dblConfirm":"双击确认裁剪","err.notVideo":"请选择视频文件","err.maxVideo":"最多 {max} 个视频素材","err.videoLoad":"视频加载失败,请换一个文件","err.notAudio":"请选择音频文件(mp3/wav/m4a),或含声音的视频(自动提取音轨)","err.maxAudio":"最多 {max} 个音频素材","err.audioLoad":"音频加载失败,请换一个文件","err.processFailed":"处理失败","err.posterFailed":"封面渲染失败","err.canvas":"canvas 不可用","err.imageRead":"图片读取失败,请换一张","err.notImage":"请选择图片文件","err.fileType":"只支持图片或视频文件","err.saveDrive":"存网盘失败","msg.processing":"正在导出中…","msg.exportPrepare":"正在准备素材…","msg.exportUpload":"正在上传素材…","msg.exportEncode":"正在编码视频…","msg.exportDownload":"正在接收结果…","msg.exportingHint":"请稍候,导出完成后会自动返回结果。","msg.done":"完成 ✓","msg.loading":"素材加载中…","msg.exported":"已导出:","msg.saving":"存网盘中…","msg.saved":"已存到网盘 ✓","lbl.ratioSection":"画面比例(裁剪,不变形)","lbl.dragToReposition":"↔ 拖动预览可调整裁剪位置","lbl.sizeSection":"导出尺寸(像素;比例不符时 cover 居中裁剪)","lbl.currentOut":"当前输出","lbl.zoomSize":"大小","lbl.noScale":"(未缩放)","lbl.coverNote":"· 比例不一致时居中裁剪(cover),不变形","lbl.audioTrackHint":"♪ 音频轨(右侧 + 添加音乐,与原声混音)","lbl.volume":"音量","lbl.volNote":"(预览最大 100%,导出按设定值)","lbl.music":"音乐","kbd.fit":"⇧ F","poster.title":"选择封面帧","panel.title":"媒体编辑器","panel.subtitle":"上传图片 / 视频,裁剪 · 滤镜 · 文字 · 导出","panel.pick":"点击选择图片或视频","panel.pickHint":"图片用 Filerobot · 视频可裁剪/静音/封面"},o={"简":"簡","体":"體","图":"圖","频":"頻","视":"視","辑":"輯","调":"調","滤":"濾","标":"標","注":"註","贴":"貼","选":"選","择":"擇","线":"線","箭":"箭","头":"頭","复":"複","删":"刪","除":"除","编":"編","边":"邊","输":"輸","入":"入","确":"確","认":"認","饱":"飽","对":"對","暖":"暖","阳":"陽","冷":"冷","纵":"縱","横":"橫","适":"適","应":"應","缩":"縮","实":"實","际":"際","导":"導","出":"出","封":"封","面":"面","换":"換","张":"張","预":"預","览":"覽","动":"動","声":"聲","开":"開","关":"關","与":"與","乐":"樂","混":"混","处":"處","载":"載","错":"錯","误":"誤","读":"讀","仅":"僅","终":"終","稍":"稍","候":"候","返回":"返回","当前":"目前","输出":"輸出","画":"畫","变":"變","音频":"音訊","音轨":"音軌","添加":"新增","删除":"刪除","保存":"儲存","加载":"載入","网盘":"網盤"},t=e=>{let t=e;for(const[e,a]of Object.entries(o).sort((e,o)=>o[0].length-e[0].length))t=t.replaceAll(e,a);return t},a={zh:e,en:{"tool.trim":"Trim","tool.crop":"Crop","tool.tune":"Tune","tool.filter":"Filters","tool.annotate":"Annotate","tool.sticker":"Stickers","tool.resize":"Ratio","tune.brightness":"Brightness","tune.contrast":"Contrast","tune.saturation":"Saturation","tune.gamma":"Gamma","tune.temperature":"Temperature","tune.tint":"Tint","tune.vibrance":"Vibrance","tune.highlights":"Highlights","tune.shadows":"Shadows","tune.whites":"Whites","tune.blacks":"Blacks","tune.lightSense":"Light","tune.sharpen":"Sharpen","tune.clarity":"Clarity","tune.grain":"Grain","tune.fade":"Fade","tune.vignette":"Vignette","overlay.select":"Select","overlay.pen":"Pen","overlay.eraser":"Eraser","overlay.line":"Line","overlay.arrow":"Arrow","overlay.rect":"Rect","overlay.ellipse":"Ellipse","overlay.text":"Text","overlay.color":"Color","overlay.width":"Width","overlay.fontSize":"Size","overlay.font":"Font","overlay.align":"Align","overlay.background":"Background","overlay.copySelected":"Copy","overlay.delSelected":"Delete selected","overlay.editSelected":"Edit","overlay.pickImage":"Pick image","overlay.hint":"Tap emoji/image to add → drag to place, drag the purple corner handle to scale","overlay.textPlaceholder":"Type text, Enter to confirm","filter.none":"Original","filter.bw":"B&W","filter.sepia":"Sepia","filter.warm":"Warm","filter.cool":"Cool","filter.vivid":"Vivid","ratio.orig":"Original","ratio.free":"Free ratio","ratio.9:16":"Portrait 9:16","ratio.16:9":"Landscape 16:9","ratio.1:1":"Square 1:1","ratio.4:5":"Vertical 4:5","ratio.3:4":"Vertical 3:4","ratio.2:3":"Vertical 2:3","ratio.1.91:1":"Wide 1.91:1","act.fit":"Fit","act.zoomFit":"Zoom to fit","act.zoomTo":"Zoom to {value}%","act.split":"Split","act.copy":"Copy","act.delete":"Delete","act.restore":"Reset","act.deleteMusic":"Remove music","act.cancel":"Cancel","act.exportPoster":"Export cover","act.exporting":"Exporting…","act.poster":"🖼 Cover","act.again":"Download again","act.saveDrive":"Save to drive","act.changeImage":"← Change image","act.changeVideo":"← Change file","crop.rotateLeft":"↺ Rotate left","crop.flipX":"⇋ Flip horizontal","crop.flipY":"⇵ Flip vertical","crop.rotateLeftShort":"Rot","crop.flipXShort":"Flip","crop.flipYShort":"Flip","tip.close":"Close (change file)","tip.undo":"Undo","tip.redo":"Redo","tip.resetOpened":"Reset to opened file","tip.previewZoom":"Preview zoom","tip.previewZoomOut":"Zoom out preview","tip.previewZoomIn":"Zoom in preview","tip.previewZoomFit":"Fit preview","tip.previewPointer":"Pointer tool","tip.previewPan":"Hand tool: pan canvas","tip.poster":"Preview and pick a cover frame","tip.keepAudio":"Original audio on/off (mixed with music; preview follows)","tip.split":"Split the current clip at the playhead","tip.zoomOut":"Zoom out timeline (Ctrl+wheel)","tip.zoomIn":"Zoom in timeline (Ctrl+wheel)","tip.fit":"Fit to width","tip.addVideo":"Add video clip","tip.addAudio":"Add music (audio file, or a video with sound to extract its track; mixed with original)","tip.dupClip":"Duplicate clip (insert after)","tip.delClip":"Delete clip","tip.lockAspect":"Lock aspect ratio","tip.dblConfirm":"Double-click to confirm crop","err.notVideo":"Please choose a video file","err.maxVideo":"Up to {max} video sources","err.videoLoad":"Failed to load video, try another file","err.notAudio":"Choose an audio file (mp3/wav/m4a), or a video with sound (audio auto-extracted)","err.maxAudio":"Up to {max} audio sources","err.audioLoad":"Failed to load audio, try another file","err.processFailed":"Processing failed","err.posterFailed":"Failed to render cover","err.canvas":"Canvas unavailable","err.imageRead":"Failed to read image, try another","err.notImage":"Please choose an image file","err.fileType":"Only image or video files are supported","err.saveDrive":"Failed to save to drive","msg.processing":"Exporting…","msg.exportPrepare":"Preparing media…","msg.exportUpload":"Uploading media…","msg.exportEncode":"Encoding video…","msg.exportDownload":"Receiving result…","msg.exportingHint":"Please wait. The result will be returned automatically when export finishes.","msg.done":"Done ✓","msg.loading":"Loading media…","msg.exported":"Exported: ","msg.saving":"Saving…","msg.saved":"Saved to drive ✓","lbl.ratioSection":"Frame ratio (crop, no distortion)","lbl.dragToReposition":"↔ Drag the preview to reposition the crop","lbl.sizeSection":"Export size (px; cover center-crop when ratios differ)","lbl.currentOut":"Output","lbl.zoomSize":"Size","lbl.noScale":"(no scaling)","lbl.coverNote":"· center-cropped (cover) when ratios differ, no distortion","lbl.audioTrackHint":"♪ Audio track (+ on the right to add music, mixed with original)","lbl.volume":"Volume","lbl.volNote":"(preview caps at 100%, export uses the set value)","lbl.music":"Music","kbd.fit":"⇧ F","poster.title":"Pick a cover frame","panel.title":"Media Editor","panel.subtitle":"Upload an image / video — crop · filters · text · export","panel.pick":"Click to choose an image or video","panel.pickHint":"Images via Filerobot · videos: trim/mute/cover"},es:{"tool.trim":"Editar","tool.crop":"Recortar","tool.tune":"Ajustar color","tool.filter":"Filtros","tool.annotate":"Anotar","tool.sticker":"Stickers","tool.resize":"Proporción","tune.brightness":"Brillo","tune.contrast":"Contraste","tune.saturation":"Saturación","tune.gamma":"Gamma","tune.temperature":"Temperatura","tune.tint":"Tinte","tune.vibrance":"Intensidad","tune.highlights":"Altas luces","tune.shadows":"Sombras","tune.whites":"Blancos","tune.blacks":"Negros","tune.lightSense":"Luz","tune.sharpen":"Enfoque","tune.clarity":"Claridad","tune.grain":"Grano","tune.fade":"Desvanecer","tune.vignette":"Viñeta","overlay.select":"Seleccionar","overlay.pen":"Pincel","overlay.eraser":"Borrador","overlay.line":"Línea","overlay.arrow":"Flecha","overlay.rect":"Rectángulo","overlay.ellipse":"Elipse","overlay.text":"Texto","overlay.color":"Color","overlay.width":"Grosor","overlay.fontSize":"Tamaño","overlay.font":"Fuente","overlay.align":"Alinear","overlay.background":"Fondo","overlay.copySelected":"Copiar","overlay.delSelected":"Eliminar seleccionado","overlay.editSelected":"Editar","overlay.pickImage":"Elegir imagen","overlay.hint":"Toca un emoji/imagen para añadirlo → arrastra para colocarlo, arrastra el tirador morado para escalar","overlay.textPlaceholder":"Escribe texto, Enter para confirmar","filter.none":"Original","filter.bw":"Blanco y negro","filter.sepia":"Sepia","filter.warm":"Cálido","filter.cool":"Frío","filter.vivid":"Intenso","ratio.orig":"Original","ratio.free":"Libre","ratio.9:16":"Vertical 9:16","ratio.16:9":"Horizontal 16:9","ratio.1:1":"Cuadrado 1:1","ratio.4:5":"Vertical 4:5","ratio.3:4":"Vertical 3:4","ratio.2:3":"Vertical 2:3","ratio.1.91:1":"Panorámico 1.91:1","act.fit":"Ajustar","act.zoomFit":"Ajustar a pantalla","act.zoomTo":"Zoom al {value}%","act.split":"Dividir","act.copy":"Copiar","act.delete":"Eliminar","act.restore":"Restablecer","act.deleteMusic":"Quitar música","act.cancel":"Cancelar","act.exportPoster":"Exportar portada","act.exporting":"Exportando…","act.poster":"🖼 Portada","act.again":"Descargar de nuevo","act.saveDrive":"Guardar en disco","act.changeImage":"← Cambiar imagen","act.changeVideo":"← Cambiar archivo","crop.rotateLeft":"↺ Girar a la izquierda","crop.flipX":"⇋ Voltear horizontal","crop.flipY":"⇵ Voltear vertical","crop.rotateLeftShort":"Giro","crop.flipXShort":"Flip","crop.flipYShort":"Flip","tip.close":"Cerrar (cambiar archivo)","tip.undo":"Deshacer","tip.redo":"Rehacer","tip.resetOpened":"Restablecer al archivo abierto","tip.previewZoom":"Zoom de vista previa","tip.previewZoomOut":"Reducir vista previa","tip.previewZoomIn":"Ampliar vista previa","tip.previewZoomFit":"Ajustar vista previa","tip.previewPointer":"Herramienta de puntero","tip.previewPan":"Mano: desplazar lienzo","tip.poster":"Previsualizar y elegir portada","tip.keepAudio":"Activar/desactivar audio original (mezclado con música; la vista previa lo refleja)","tip.split":"Dividir el clip actual en el cursor","tip.zoomOut":"Reducir línea de tiempo (Ctrl+rueda)","tip.zoomIn":"Ampliar línea de tiempo (Ctrl+rueda)","tip.fit":"Ajustar al ancho","tip.addVideo":"Añadir clip de vídeo","tip.addAudio":"Añadir música (archivo de audio o vídeo con sonido para extraer la pista; se mezcla con el original)","tip.dupClip":"Duplicar clip (insertar después)","tip.delClip":"Eliminar clip","tip.lockAspect":"Bloquear proporción","tip.dblConfirm":"Doble clic para confirmar recorte","err.notVideo":"Elige un archivo de vídeo","err.maxVideo":"Máximo {max} vídeos","err.videoLoad":"No se pudo cargar el vídeo, prueba con otro archivo","err.notAudio":"Elige un audio (mp3/wav/m4a) o un vídeo con sonido (se extrae automáticamente)","err.maxAudio":"Máximo {max} audios","err.audioLoad":"No se pudo cargar el audio, prueba con otro archivo","err.processFailed":"Error de procesamiento","err.posterFailed":"No se pudo renderizar la portada","err.canvas":"Canvas no disponible","err.imageRead":"No se pudo leer la imagen, prueba con otra","err.notImage":"Elige un archivo de imagen","err.fileType":"Solo se admiten archivos de imagen o vídeo","err.saveDrive":"No se pudo guardar en disco","msg.processing":"Exportando…","msg.exportPrepare":"Preparando medios…","msg.exportUpload":"Subiendo medios…","msg.exportEncode":"Codificando video…","msg.exportDownload":"Recibiendo resultado…","msg.exportingHint":"Espera un momento. El resultado se devolverá automáticamente al finalizar.","msg.done":"Listo ✓","msg.loading":"Cargando medios…","msg.exported":"Exportado: ","msg.saving":"Guardando…","msg.saved":"Guardado en disco ✓","lbl.ratioSection":"Proporción de imagen (recorte, sin deformar)","lbl.dragToReposition":"↔ Arrastra la vista previa para reposicionar el recorte","lbl.sizeSection":"Tamaño de exportación (px; recorte cover centrado si la proporción difiere)","lbl.currentOut":"Salida","lbl.zoomSize":"Tamaño","lbl.noScale":"(sin escala)","lbl.coverNote":"· recorte centrado (cover) cuando la proporción difiere, sin deformar","lbl.audioTrackHint":"♪ Pista de audio (+ a la derecha para añadir música, mezclada con el original)","lbl.volume":"Volumen","lbl.volNote":"(la vista previa limita a 100%, la exportación usa el valor definido)","lbl.music":"Música","kbd.fit":"⇧ F","poster.title":"Elegir portada","panel.title":"Editor multimedia","panel.subtitle":"Sube una imagen / vídeo — recorta · filtros · texto · exporta","panel.pick":"Haz clic para elegir una imagen o vídeo","panel.pickHint":"Imágenes con Filerobot · vídeos: cortar/silenciar/portada"},"zh-Hant":Object.fromEntries(Object.entries(e).map(([e,o])=>[e,t(o)]))};function i(e,o,t){let i=a[e]?.[o]??a.zh[o]??o;if(t)for(const[e,o]of Object.entries(t))i=i.replaceAll(`{${e}}`,String(o));return i}var r=[{platform:"tiktok",postType:"video",label:"TikTok Video",shortLabel:"TT·Video",ratio:"9:16",imageSize:"1440x2560",videoRatio:"9:16",videoResolution:"720p"},{platform:"instagram",postType:"post",label:"Instagram Post",shortLabel:"IG·Post",ratio:"1:1",imageSize:"2048x2048"},{platform:"instagram",postType:"reels",label:"Instagram Reels",shortLabel:"IG·Reels",ratio:"9:16",imageSize:"1440x2560",videoRatio:"9:16",videoResolution:"720p"},{platform:"instagram",postType:"story",label:"Instagram Story",shortLabel:"IG·Story",ratio:"9:16",imageSize:"1440x2560",videoRatio:"9:16",videoResolution:"720p"},{platform:"facebook",postType:"post",label:"Facebook Post",shortLabel:"FB·Post",ratio:"1:1",imageSize:"2048x2048"},{platform:"facebook",postType:"reels",label:"Facebook Reels",shortLabel:"FB·Reels",ratio:"9:16",imageSize:"1440x2560",videoRatio:"9:16",videoResolution:"720p"},{platform:"youtube",postType:"video",label:"YouTube Video",shortLabel:"YT·Video",ratio:"16:9",imageSize:"2560x1440",videoRatio:"16:9",videoResolution:"1080p"},{platform:"youtube",postType:"shorts",label:"YouTube Shorts",shortLabel:"YT·Shorts",ratio:"9:16",imageSize:"1440x2560",videoRatio:"9:16",videoResolution:"720p"},{platform:"pinterest",postType:"pin",label:"Pinterest Pin",shortLabel:"PIN",ratio:"2:3",imageSize:"1664x2496",videoRatio:"9:16",videoResolution:"720p"},{platform:"x",postType:"post",label:"X Post",shortLabel:"X·Post",ratio:"16:9",imageSize:"2560x1440",videoRatio:"16:9",videoResolution:"720p"},{platform:"linkedin",postType:"post",label:"LinkedIn Post",shortLabel:"LI·Post",ratio:"1:1",imageSize:"2048x2048"},{platform:"linkedin",postType:"video",label:"LinkedIn Video",shortLabel:"LI·Video",ratio:"16:9",imageSize:"2560x1440",videoRatio:"16:9",videoResolution:"1080p"},{platform:"threads",postType:"post",label:"Threads Post",shortLabel:"TH·Post",ratio:"1:1",imageSize:"2048x2048"},{platform:"telegram",postType:"post",label:"Telegram Post",shortLabel:"TG·Post",ratio:"1:1",imageSize:"2048x2048",videoRatio:"9:16",videoResolution:"720p"},{platform:"reddit",postType:"post",label:"Reddit Post",shortLabel:"RD·Post",ratio:"16:9",imageSize:"2560x1440",videoRatio:"16:9",videoResolution:"720p"}],l={"1:1":"方形 1:1","4:5":"竖图 4:5","3:4":"竖图 3:4","9:16":"竖屏 9:16","16:9":"横屏 16:9","2:3":"竖图 2:3","1.91:1":"横幅 1.91:1"};function n(e){const[o,t]=e.split(":").map(Number);return o&&t?o/t:1}function p(e){const o=new Set,t=[];for(const a of e)a&&!o.has(a)&&(o.add(a),t.push({ratio:a,value:n(a),label:l[a]??a}));return t}var s=p(["1:1","4:5","3:4","2:3","9:16","16:9","1.91:1"]),c=p(["9:16","16:9","1:1","4:5","3:4","2:3","1.91:1"]);function d(e=r){const o=new Set,t=[];for(const a of e){if(!a.videoRatio)continue;const e=`${a.platform}:${a.postType}:${a.videoRatio}`;if(o.has(e))continue;o.add(e);const i=a.label.split(" ").slice(0,-1).join(" ")||a.label;t.push({platform:a.platform,postType:a.postType,label:`${i} ${a.videoRatio}`,ratio:a.videoRatio,value:n(a.videoRatio)})}return t}var m=d();function u(e=r){const o=new Map;for(const t of e){const e=o.get(t.platform);(!e||"post"!==e.postType&&"post"===t.postType)&&o.set(t.platform,t)}return Array.from(o.values()).map(e=>{const[o,t]=e.imageSize.split("x").map(Number),a=e.label.split(" ").slice(0,-1).join(" ")||e.label;return{platform:e.platform,label:`${a} ${e.ratio}`,ratio:e.ratio,value:n(e.ratio),w:o,h:t}})}var v=u();function g(e,o){return e>=1?{w:2*Math.round(o*e/2),h:o}:{w:o,h:2*Math.round(o/e/2)}}function f(e=r){const o=new Set,t=[];for(const a of e){if(!a.videoRatio||!a.videoResolution)continue;const e="1080p"===a.videoResolution?1080:720,{w:i,h:r}=g(n(a.videoRatio),e),l=`${i}x${r}`;o.has(l)||(o.add(l),t.push({label:`${a.shortLabel} ${i}×${r}`,w:i,h:r}))}return t}var h=f();function b(e,o){if(e.isDuplicated)return{};if(0!==(e.rotation??0))return{};const t=o.adjustments?.rotation??0;return t?{rotation:-t}:{}}export{r as DEFAULT_PLATFORM_TARGETS,a as EDITOR_MESSAGES,v as IMAGE_PLATFORM_PRESETS,s as IMAGE_RATIO_PRESETS,m as VIDEO_PLATFORM_RATIO_PRESETS,c as VIDEO_RATIO_PRESETS,h as VIDEO_SIZE_PRESETS,u as buildImagePlatformPresets,d as buildVideoPlatformRatioPresets,f as buildVideoSizePresets,b as compensateAnnotationRotation,n as parseRatio,i as tEditor,t as toHant};
@@ -0,0 +1 @@
1
+ var t=Math.PI/180;function n(n,r,a){const i=e(a);if(0===i||180===i)return{w:n,h:r};if(90===i||270===i)return{w:r,h:n};const o=i*t;return{w:Math.round(Math.abs(n*Math.cos(o))+Math.abs(r*Math.sin(o))),h:Math.round(Math.abs(n*Math.sin(o))+Math.abs(r*Math.cos(o)))}}function e(t){return(t%360+360)%360}function r(t){const n=Math.round(t);return n-n%2}function a(t,n,e=40){const r=Math.min(Math.max(e,t.width),n.w),a=Math.min(Math.max(e,t.height),n.h),i=Math.min(Math.max(0,t.x),n.w-r),o=Math.min(Math.max(0,t.y),n.h-a);return{x:Math.round(i),y:Math.round(o),width:Math.round(r),height:Math.round(a)}}function i(t,n){let e=t.w,r=e/n;return r>t.h&&(r=t.h,e=r*n),{x:Math.round((t.w-e)/2),y:Math.round((t.h-r)/2),width:Math.round(e),height:Math.round(r)}}function o(t,n,e){const r={x:0,y:0,width:t.width,height:t.height},a={x:0,y:0,width:n.w,height:n.h};return"cover"===e?{src:i({w:t.width,h:t.height},n.w/n.h),dst:a}:"contain"===e?{src:r,dst:i({w:n.w,h:n.h},t.width/t.height)}:{src:r,dst:a}}function s(t,e){if(e.scale)return{w:r(e.scale.width),h:r(e.scale.height)};if(e.crop)return{w:r(e.crop.width),h:r(e.crop.height)};const a=n(t.w,t.h,e.rotation);return{w:r(a.w),h:r(a.h)}}var h=[{id:"bw",label:"黑白",vf:"hue=s=0",css:"grayscale(1)"},{id:"sepia",label:"复古",vf:"colorchannelmixer=.393:.769:.189:0:.349:.686:.168:0:.272:.534:.131",css:"sepia(0.85)"},{id:"warm",label:"暖阳",vf:"colorbalance=rs=.15:gs=.04:bs=-.15",css:"sepia(0.25) saturate(1.25) brightness(1.03)"},{id:"cool",label:"冷调",vf:"colorbalance=rs=-.14:bs=.16",css:"hue-rotate(12deg) saturate(0.95) brightness(1.02)"},{id:"vivid",label:"鲜艳",vf:"eq=saturation=1.45:contrast=1.08",css:"saturate(1.45) contrast(1.08)"}];function c(t){return t?h.find(n=>n.id===t):void 0}function u(t,n){const e=c(n)?.css??"",r=t.temperature??0,a=t.tint??0,i=t.vibrance??0,o=t.gamma??0,s=t.sharpen??0,h=t.clarity??0;return[`brightness(${1+t.brightness})`,`contrast(${1+t.contrast})`,`saturate(${1+t.saturation})`,e,i?`saturate(${(1+.65*i).toFixed(3)})`:"",r>0?`sepia(${Math.min(.36,.28*r).toFixed(3)})`:"",r?`hue-rotate(${(14*-r).toFixed(2)}deg)`:"",a?`hue-rotate(${(10*a).toFixed(2)}deg)`:"",o?`brightness(${(1+.08*o).toFixed(3)})`:"",h||s?`contrast(${(1+.16*h+.1*s).toFixed(3)})`:""].filter(Boolean).join(" ")}var l=Math.PI/180,d='-apple-system, "PingFang SC", "Microsoft YaHei", sans-serif';function x(t){return"adjust"!==t.type}function f(t){return Boolean(t.hidden)}function m(t){return Boolean(t.locked)}function M(t,n){const e=Number(t.timelineTrack);return Number.isFinite(e)?Math.max(0,Math.round(e)):n}function w(t){return t.map((t,n)=>({overlay:t,index:n,track:M(t,n)})).sort((t,n)=>n.track-t.track||t.index-n.index).map(t=>t.overlay)}function p(t,n,e){t.strokeStyle=n,t.lineWidth=e,t.lineCap="round",t.lineJoin="round"}function y(t){if(!Number.isFinite(t))return 0;let n=t%360;return n>180&&(n-=360),n<-180&&(n+=360),Math.abs(n)<.001?0:n}function g(t){return y(t.rotation??0)}function b(t){switch(t.type){case"pen":{let n=1/0,e=1/0,r=-1/0,a=-1/0;for(let i=0;i<t.points.length;i+=2)n=Math.min(n,t.points[i]),r=Math.max(r,t.points[i]),e=Math.min(e,t.points[i+1]),a=Math.max(a,t.points[i+1]);return{x:n,y:e,w:r-n,h:a-e}}case"line":case"arrow":return{x:Math.min(t.x1,t.x2),y:Math.min(t.y1,t.y2),w:Math.abs(t.x2-t.x1),h:Math.abs(t.y2-t.y1)};case"rect":case"ellipse":case"sticker":case"adjust":return{x:t.x,y:t.y,w:t.w,h:t.h};case"text":return $(t)}}function k(t){return String(t.text||"").split(/\r?\n/)}function v(t){return t.fontSize*(t.lineHeight??1.15)}function S(t){return t.paddingX??0}function F(t){return t.paddingY??0}function P(t){const n=Math.max(.6*t.fontSize,...k(t).map(n=>Math.max(1,n.length)*t.fontSize*.6));return Math.max(1,t.width??n+2*S(t))}function $(t){const n=k(t);return{x:t.x,y:t.y,w:P(t),h:Math.max(t.fontSize,n.length*v(t))+2*F(t)}}function T(t){const n=b(t);return{x:n.x+n.w/2,y:n.y+n.h/2}}function z(t,n,e,r,a){return{x:e+(t-e)*a,y:r+(n-r)*a}}function j(t){const n=t,e=Number.isFinite(n.startAt)?Math.max(0,Number(n.startAt)):null,r=Number.isFinite(n.endAt)?Math.max(e??0,Number(n.endAt)):null;if(null==e&&null==r)return null;const a=e??0;return{start:a,end:Math.max(a,r??a)}}function I(t,n){const e=j(t);return!e||Number.isFinite(n)&&n>=e.start&&n<=e.end}function N(t,n){if(!t?.length)return[];const e=t.filter(t=>!f(t));return Number.isFinite(n)?e.filter(t=>I(t,n)):e}function W(t,n,e){if(f(n))return;if(!x(n))return;const r=g(n);if(r){const a=T(n);return t.save(),t.translate(a.x,a.y),t.rotate(r*l),t.translate(-a.x,-a.y),C(t,n,e),void t.restore()}C(t,n,e)}function C(t,n,e){switch(n.type){case"pen":p(t,n.color,n.width),t.beginPath(),t.moveTo(n.points[0],n.points[1]);for(let e=2;e<n.points.length;e+=2)t.lineTo(n.points[e],n.points[e+1]);t.stroke();break;case"line":case"arrow":p(t,n.color,n.width),t.beginPath(),t.moveTo(n.x1,n.y1),t.lineTo(n.x2,n.y2),t.stroke(),"arrow"===n.type&&function(t,n,e,r,a,i){const o=Math.atan2(a-e,r-n),s=Math.max(12,3.5*i);t.beginPath(),t.moveTo(r,a),t.lineTo(r-s*Math.cos(o-Math.PI/7),a-s*Math.sin(o-Math.PI/7)),t.moveTo(r,a),t.lineTo(r-s*Math.cos(o+Math.PI/7),a-s*Math.sin(o+Math.PI/7)),t.stroke()}(t,n.x1,n.y1,n.x2,n.y2,n.width);break;case"rect":p(t,n.color,n.width),t.strokeRect(n.x,n.y,n.w,n.h);break;case"ellipse":p(t,n.color,n.width),t.beginPath(),t.ellipse(n.x+n.w/2,n.y+n.h/2,Math.abs(n.w/2),Math.abs(n.h/2),0,0,2*Math.PI),t.stroke();break;case"text":{const e=$(n),r=k(n),a=Number.isFinite(n.opacity)?Math.min(1,Math.max(0,(n.opacity??100)/100)):1;t.save(),t.globalAlpha*=a,n.backgroundColor&&"transparent"!==n.backgroundColor&&(t.fillStyle=n.backgroundColor,t.fillRect(n.x,n.y,e.w,e.h)),t.fillStyle=n.color,t.font=function(t){const n=t.fontWeight??"700",e=t.italic?"italic ":"",r=t.fontFamily?`"${t.fontFamily}", ${d}`:d;return`${e}${n} ${t.fontSize}px ${r}`}(n),t.textBaseline="top",t.strokeStyle=n.strokeColor??"rgba(0,0,0,0.45)",t.lineWidth=n.borderWidth??Math.max(2,n.fontSize/16),t.lineJoin="round",r.forEach((r,a)=>{const i=function(t,n,e,r){const a=S(n),i=n.align??"left",o=t.measureText(e||" ").width;return"center"===i?n.x+r/2-o/2:"right"===i?n.x+r-a-o:n.x+a}(t,n,r,e.w),o=n.y+F(n)+a*v(n),s=t.measureText(r||" ").width;if(t.lineWidth>0&&t.strokeText(r,i,o),t.fillText(r,i,o),(n.underline||n.strikethrough)&&s>0){const e=Math.max(1,n.fontSize/18);t.fillStyle=n.color,n.underline&&t.fillRect(i,o+.92*n.fontSize,s,e),n.strikethrough&&t.fillRect(i,o+.52*n.fontSize,s,e)}}),t.restore();break}case"sticker":if(n.emoji)t.save(),t.font=.86*Math.min(n.w,n.h)+'px -apple-system, "Apple Color Emoji", "Segoe UI Emoji", sans-serif',t.textAlign="center",t.textBaseline="middle",t.fillText(n.emoji,n.x+n.w/2,n.y+n.h/2),t.restore();else if(n.src){const r=e?.get(n.src);r&&t.drawImage(r,n.x,n.y,n.w,n.h)}}}function A(t,n,e,r){const a="number"==typeof r?N(n,r):n;for(const n of a)!f(n)&&x(n)&&W(t,n,e)}async function B(t){const n=new Map,e=[...new Set(t.filter(t=>"sticker"===t.type&&t.src).map(t=>t.src))];return await Promise.all(e.map(t=>new Promise(e=>{const r=new Image;r.onload=()=>{n.set(t,r),e()},r.onerror=()=>e(),r.src=t}))),n}async function Y(t,n,e){const r=t?.filter(t=>!f(t)&&x(t))??[];if(!r.length)return null;const a=document.createElement("canvas");a.width=n,a.height=e;const i=a.getContext("2d");return i?(A(i,r,await B(r)),new Promise(t=>a.toBlob(n=>t(n),"image/png"))):null}function X(t,n,e,r=12){for(let a=t.length-1;a>=0;a--){const i=t[a];if(!f(i)&&R(i,n,e,r))return a}return-1}function E(t,n,e,r,a,i,o){const s=a-e,h=i-r,c=s*s+h*h||1,u=Math.max(0,Math.min(1,((t-e)*s+(n-r)*h)/c));return(t-(e+u*s))**2+(n-(r+u*h))**2<=o*o}function R(t,n,e,r){const a=g(t);if(a){const i=T(t),o=function(t,n,e,r,a){const i=a*l,o=Math.cos(i),s=Math.sin(i),h=t-e,c=n-r;return{x:e+h*o-c*s,y:r+h*s+c*o}}(n,e,i.x,i.y,-a);return H(t,o.x,o.y,r)}return H(t,n,e,r)}function H(t,n,e,r){switch(t.type){case"pen":for(let a=0;a+3<t.points.length;a+=2)if(E(n,e,t.points[a],t.points[a+1],t.points[a+2],t.points[a+3],r+t.width/2))return!0;return!1;case"line":case"arrow":return E(n,e,t.x1,t.y1,t.x2,t.y2,r+t.width/2);case"rect":case"ellipse":return n>=t.x-r&&n<=t.x+t.w+r&&e>=t.y-r&&e<=t.y+t.h+r;case"text":{const a=$(t);return n>=a.x-r&&n<=a.x+a.w+r&&e>=a.y-r&&e<=a.y+a.h+r}case"sticker":return function(t,n,e,r,a){return Math.abs(t-e)<=a&&Math.abs(n-r)<=a}(n,e,t.x+t.w/2,t.y+t.h/2,Math.max(t.w,t.h)/2+r);case"adjust":return!1}}function J(t,n,e){const r=Math.max(8,e);if(!(t>0&&n>0))return{w:r,h:r};const a=r/Math.max(t,n);return{w:Math.max(8,Math.round(t*a)),h:Math.max(8,Math.round(n*a))}}function q(t,n){const e=Math.max(.05,n),r=T(t);switch(t.type){case"pen":return{...t,points:t.points.map((t,n)=>n%2==0?r.x+(t-r.x)*e:r.y+(t-r.y)*e)};case"line":case"arrow":{const n=z(t.x1,t.y1,r.x,r.y,e),a=z(t.x2,t.y2,r.x,r.y,e);return{...t,x1:n.x,y1:n.y,x2:a.x,y2:a.y}}case"rect":case"ellipse":case"sticker":case"adjust":return{...t,w:Math.max(8,t.w*e),h:Math.max(8,t.h*e)};case"text":return{...t,fontSize:Math.min(512,Math.max(8,t.fontSize*e)),width:t.width?Math.max(16,t.width*e):t.width,paddingX:t.paddingX?Math.max(0,t.paddingX*e):t.paddingX,paddingY:t.paddingY?Math.max(0,t.paddingY*e):t.paddingY,borderWidth:t.borderWidth?Math.max(0,t.borderWidth*e):t.borderWidth};default:return t}}function U(t,n){return{...t,rotation:y(n)}}function D(t,n,e){switch(t.type){case"pen":{const r=t.points.map((t,r)=>r%2==0?t+n:t+e);return{...t,points:r}}case"line":case"arrow":return{...t,x1:t.x1+n,y1:t.y1+e,x2:t.x2+n,y2:t.y2+e};case"rect":case"ellipse":case"sticker":case"adjust":case"text":return{...t,x:t.x+n,y:t.y+e}}}export{t as DEG2RAD,h as FILTER_PRESETS,u as buildFilterCss,i as centeredMaxRect,a as clampRect,W as drawOverlay,A as drawOverlays,r as evenize,N as filterOverlaysAtTime,c as findFilterPreset,o as fitRects,J as fitStickerBox,g as getOverlayRotation,X as hitTestOverlay,x as isDrawableOverlay,I as isOverlayActiveAt,f as isOverlayHidden,m as isOverlayLocked,B as loadOverlayImages,e as normalizeDeg,s as outputSize,b as overlayBBox,w as overlayLayerRenderOrder,j as overlayTimeRange,Y as renderOverlaysToPng,U as rotateOverlay,n as rotatedSize,q as scaleOverlay,D as translateOverlay};
@@ -0,0 +1 @@
1
+ "use strict";var zod=require("zod"),StrokeCommon={color:zod.z.string().max(32),width:zod.z.number().positive().max(200)},RotationCommon={rotation:zod.z.number().min(-180).max(180).optional()},TimelineCommon={startAt:zod.z.number().min(0).optional(),endAt:zod.z.number().min(0).optional(),timelineTrack:zod.z.number().int().min(0).max(99).optional(),hidden:zod.z.boolean().optional(),locked:zod.z.boolean().optional()},FilterCommon={brightness:zod.z.number().min(-1).max(1).default(0),contrast:zod.z.number().min(-1).max(1).default(0),saturation:zod.z.number().min(-1).max(1).default(0),temperature:zod.z.number().min(-1).max(1).default(0),tint:zod.z.number().min(-1).max(1).default(0),vibrance:zod.z.number().min(-1).max(1).default(0),gamma:zod.z.number().min(-1).max(1).default(0),highlights:zod.z.number().min(-1).max(1).default(0),shadows:zod.z.number().min(-1).max(1).default(0),whites:zod.z.number().min(-1).max(1).default(0),blacks:zod.z.number().min(-1).max(1).default(0),lightSense:zod.z.number().min(-1).max(1).default(0),sharpen:zod.z.number().min(0).max(1).default(0),clarity:zod.z.number().min(0).max(1).default(0),grain:zod.z.number().min(0).max(1).default(0),fade:zod.z.number().min(0).max(1).default(0),vignette:zod.z.number().min(0).max(1).default(0)},Overlay=zod.z.discriminatedUnion("type",[zod.z.object({type:zod.z.literal("pen"),points:zod.z.array(zod.z.number()).min(4),...StrokeCommon,...TimelineCommon,...RotationCommon}),zod.z.object({type:zod.z.literal("line"),x1:zod.z.number(),y1:zod.z.number(),x2:zod.z.number(),y2:zod.z.number(),...StrokeCommon,...TimelineCommon,...RotationCommon}),zod.z.object({type:zod.z.literal("arrow"),x1:zod.z.number(),y1:zod.z.number(),x2:zod.z.number(),y2:zod.z.number(),...StrokeCommon,...TimelineCommon,...RotationCommon}),zod.z.object({type:zod.z.literal("rect"),x:zod.z.number(),y:zod.z.number(),w:zod.z.number(),h:zod.z.number(),...StrokeCommon,...TimelineCommon,...RotationCommon}),zod.z.object({type:zod.z.literal("ellipse"),x:zod.z.number(),y:zod.z.number(),w:zod.z.number(),h:zod.z.number(),...StrokeCommon,...TimelineCommon,...RotationCommon}),zod.z.object({type:zod.z.literal("text"),x:zod.z.number(),y:zod.z.number(),text:zod.z.string().max(500),color:zod.z.string().max(32),fontSize:zod.z.number().positive().max(512),fontFamily:zod.z.string().max(120).optional(),fontWeight:zod.z.string().max(20).optional(),italic:zod.z.boolean().optional(),underline:zod.z.boolean().optional(),strikethrough:zod.z.boolean().optional(),align:zod.z.enum(["left","center","right"]).optional(),width:zod.z.number().positive().max(8192).optional(),backgroundColor:zod.z.string().max(32).optional(),strokeColor:zod.z.string().max(32).optional(),borderWidth:zod.z.number().min(0).max(64).optional(),paddingX:zod.z.number().min(0).max(256).optional(),paddingY:zod.z.number().min(0).max(256).optional(),lineHeight:zod.z.number().positive().max(4).optional(),opacity:zod.z.number().min(0).max(100).optional(),...TimelineCommon,...RotationCommon}),zod.z.object({type:zod.z.literal("sticker"),x:zod.z.number(),y:zod.z.number(),w:zod.z.number().positive(),h:zod.z.number().positive(),emoji:zod.z.string().max(16).optional(),src:zod.z.string().optional(),...TimelineCommon,...RotationCommon}),zod.z.object({type:zod.z.literal("adjust"),x:zod.z.number(),y:zod.z.number(),w:zod.z.number().positive(),h:zod.z.number().positive(),layerKind:zod.z.enum(["adjust","filter"]).optional(),filterPreset:zod.z.string().max(32).optional(),...FilterCommon,...TimelineCommon,...RotationCommon})]),Clip=zod.z.object({srcIdx:zod.z.number().int().min(0).max(7),in:zod.z.number().min(0),out:zod.z.number().min(0),hidden:zod.z.boolean().optional(),locked:zod.z.boolean().optional()}),AudioClip=zod.z.object({srcIdx:zod.z.number().int().min(0).max(2),track:zod.z.number().int().min(0).default(0),startAt:zod.z.number().min(0),in:zod.z.number().min(0),out:zod.z.number().min(0),speed:zod.z.number().min(.5).max(2).default(1),volume:zod.z.number().min(0).max(10),muted:zod.z.boolean().optional(),locked:zod.z.boolean().optional(),fadeIn:zod.z.number().min(0).default(0),fadeOut:zod.z.number().min(0).default(0)}),Transition=zod.z.object({type:zod.z.enum(["none","fade","slide","wipe","flip","clockWipe","star","circle","rectangle"]).default("none"),duration:zod.z.number().min(0).max(2).default(.4)}),ExportSettings=zod.z.object({fileName:zod.z.string().max(120).optional(),format:zod.z.enum(["mp4","mov","mxf"]).default("mp4"),width:zod.z.number().int().min(2).max(8192).optional(),height:zod.z.number().int().min(2).max(8192).optional(),frameRate:zod.z.number().int().min(12).max(120).default(30),bitrateMode:zod.z.enum(["auto","custom"]).optional(),videoBitrateKbps:zod.z.number().int().min(100).max(5e4).optional(),audioBitrateKbps:zod.z.number().int().min(32).max(1024).optional(),audioCodec:zod.z.enum(["aac","mp3"]).default("aac")}).optional(),DEFAULT_FILTERS={brightness:0,contrast:0,saturation:0,temperature:0,tint:0,vibrance:0,gamma:0,highlights:0,shadows:0,whites:0,blacks:0,lightSense:0,sharpen:0,clarity:0,grain:0,fade:0,vignette:0},VideoEditState=zod.z.object({clips:zod.z.array(Clip).min(1).max(50),audioClips:zod.z.array(AudioClip).max(8).default([]),canvas:zod.z.object({w:zod.z.number().int().min(2).max(4096),h:zod.z.number().int().min(2).max(4096)}),crop:zod.z.object({x:zod.z.number().min(0),y:zod.z.number().min(0),width:zod.z.number().positive(),height:zod.z.number().positive()}).optional(),scale:zod.z.object({width:zod.z.number().positive(),height:zod.z.number().positive(),fit:zod.z.enum(["contain","cover","force"]),backgroundColor:zod.z.string().max(32).optional()}).optional(),rotation:zod.z.number().min(-180).max(180).default(0),flipX:zod.z.boolean().default(!1),flipY:zod.z.boolean().default(!1),filters:zod.z.object(FilterCommon).default(DEFAULT_FILTERS),filterPreset:zod.z.string().max(32).optional(),overlays:zod.z.array(Overlay).max(200).optional(),transitions:zod.z.array(Transition).max(49).default([]),keepAudio:zod.z.boolean().default(!0),poster:zod.z.object({time:zod.z.number().min(0),src:zod.z.string().optional(),useAsVideoCover:zod.z.boolean().optional(),preview:zod.z.string().optional()}).optional(),exportSettings:ExportSettings}).superRefine((t,e)=>{t.clips.forEach((t,i)=>{t.out<=t.in&&e.addIssue({code:zod.z.ZodIssueCode.custom,message:`clips[${i}].out 必须大于 in`,path:["clips",i,"out"]})}),t.audioClips?.forEach((t,i)=>{t.out<=t.in&&e.addIssue({code:zod.z.ZodIssueCode.custom,message:`audioClips[${i}].out 必须大于 in`,path:["audioClips",i,"out"]})}),t.canvas.w%2==0&&t.canvas.h%2==0||e.addIssue({code:zod.z.ZodIssueCode.custom,message:"canvas 宽高必须为偶数",path:["canvas"]}),null!=t.exportSettings?.width&&t.exportSettings.width%2!=0&&e.addIssue({code:zod.z.ZodIssueCode.custom,message:"exportSettings.width must be even",path:["exportSettings","width"]}),null!=t.exportSettings?.height&&t.exportSettings.height%2!=0&&e.addIssue({code:zod.z.ZodIssueCode.custom,message:"exportSettings.height must be even",path:["exportSettings","height"]})});function defaultVideoEditState(){return{clips:[],audioClips:[],canvas:{w:2,h:2},rotation:0,flipX:!1,flipY:!1,filters:DEFAULT_FILTERS,transitions:[],keepAudio:!0}}var MAX_DEPTH=100;function createHistory(t){return{past:[],present:t,future:[]}}function pushHistory(t,e){if(e===t.present)return t;const i=[...t.past,t.present];return i.length>MAX_DEPTH&&i.shift(),{past:i,present:e,future:[]}}function replacePresent(t,e){return e===t.present?t:{...t,present:e}}function canUndo(t){return t.past.length>0}function canRedo(t){return t.future.length>0}function undo(t){return canUndo(t)?{past:t.past.slice(0,-1),present:t.past[t.past.length-1],future:[t.present,...t.future]}:t}function redo(t){if(!canRedo(t))return t;const[e,...i]=t.future;return{past:[...t.past,t.present],present:e,future:i}}var MIN_CLIP=.1;function clipDuration(t){return t.out-t.in}function totalDuration(t){return t.reduce((t,e)=>t+clipDuration(e),0)}function locateOutput(t,e){if(!t.length||e<0)return null;let i=0;for(let o=0;o<t.length;o++){const n=clipDuration(t[o]);if(e<i+n)return{idx:o,srcTime:t[o].in+(e-i)};i+=n}if(Math.abs(e-i)<1e-9||e<=i){const e=t.length-1;return{idx:e,srcTime:t[e].out}}return null}function splitAtOutput(t,e){const i=locateOutput(t,e);if(!i)return t;const o=t[i.idx];return i.srcTime<o.in+MIN_CLIP||i.srcTime>o.out-MIN_CLIP?t:[...t.slice(0,i.idx),{...o,out:i.srcTime},{...o,in:i.srcTime},...t.slice(i.idx+1)]}function removeClip(t,e){return t.length<=1||!t[e]?t:t.filter((t,i)=>i!==e)}function duplicateClip(t,e){const i=t[e];return i?[...t.slice(0,e+1),{...i},...t.slice(e+1)]:t}function reorderClips(t,e,i){if(e===i||!t[e]||i<0||i>=t.length)return t;const o=[...t],[n]=o.splice(e,1);return o.splice(i,0,n),o}function trimClipEdge(t,e,i,o,n){if(!t[e])return t;const r=t.map(t=>({...t}));return"in"===i?r[e].in=Math.min(Math.max(o,0),r[e].out-MIN_CLIP):r[e].out=Math.max(Math.min(o,n),r[e].in+MIN_CLIP),r}function clampAudioClip(t,e,i){const o=Math.max(Math.min(t.out,e),MIN_CLIP),n=Math.min(Math.max(t.in,0),o-MIN_CLIP),r=Math.min(Math.max(t.startAt,0),Math.max(0,i-MIN_CLIP));return{...t,in:n,out:o,startAt:r}}function contentDuration(t,e=[]){const i=totalDuration(t),o=e.reduce((t,e)=>Math.max(t,e.startAt+(e.out-e.in)/Math.max(.01,e.speed??1)),0);return Math.max(i,o)}function usedVideoSrcIndices(t){return[...new Set(t.map(t=>t.srcIdx))].sort((t,e)=>t-e)}function remapSrcIndices(t,e){const i=new Map(e.map((t,e)=>[t,e]));return t.map(t=>({...t,srcIdx:i.get(t.srcIdx)??0}))}function evenize(t){const e=Math.min(Math.max(Math.round(t),2),4096);return e%2==0?e:e-1}var clampRotation=t=>Math.min(Math.max(t,-180),180),VideoEditorEngine=class{constructor(t=defaultVideoEditState()){this.videoSources=[],this.audioSources=[],this.listeners=new Set,this.transientBase=null,this.getSnapshot=()=>this.history.present,this.subscribe=t=>(this.listeners.add(t),()=>this.listeners.delete(t)),this.history=createHistory(t)}getState(){return this.history.present}emit(){const t=this.history.present;for(const e of this.listeners)e(t)}canUndo(){return canUndo(this.history)}canRedo(){return canRedo(this.history)}undo(){this.transientBase=null,this.history=undo(this.history),this.emit()}redo(){this.transientBase=null,this.history=redo(this.history),this.emit()}applyMut(t,e=!1){if(e)null===this.transientBase&&(this.transientBase=this.history.present),this.history=replacePresent(this.history,t(this.transientBase));else{const e=t(this.transientBase??this.history.present),i=this.transientBase?{...this.history,present:this.transientBase}:this.history;this.history=pushHistory(i,e),this.transientBase=null}this.emit()}registerVideoSource(t){const e=this.videoSources.length;this.videoSources.push(t);const i={srcIdx:e,in:0,out:t.duration};return 0===e||0===this.history.present.clips.length?(this.transientBase=null,this.history=createHistory({...defaultVideoEditState(),clips:[i],canvas:{w:evenize(t.width),h:evenize(t.height)}}),this.emit()):this.applyMut(t=>({...t,clips:[...t.clips,i]})),e}registerAudioSource(t){const e=this.audioSources.length;return this.audioSources.push(t),this.applyMut(i=>{const o=i.audioClips.reduce((t,e)=>{const i=Math.max(0,(e.out-e.in)/Math.max(.01,e.speed??1));return Math.max(t,e.startAt+i)},0),n=clampAudioClip({srcIdx:e,track:0,startAt:o,in:0,out:t.duration,speed:1,volume:1,fadeIn:0,fadeOut:0},t.duration,Math.max(totalDuration(i.clips),o+MIN_CLIP));return{...i,audioClips:[...i.audioClips.map(t=>({...t,track:0})),n]}}),e}getVideoSource(t){return this.videoSources[t]}getAudioSource(t){return this.audioSources[t]}addClipFromSource(t){const e=this.videoSources[t];e&&this.applyMut(i=>({...i,clips:[...i.clips,{srcIdx:t,in:0,out:e.duration}]}))}splitAtPlayhead(t){this.applyMut(e=>({...e,clips:splitAtOutput(e.clips,t)}))}removeClip(t){this.applyMut(e=>({...e,clips:removeClip(e.clips,t)}))}duplicateClip(t){this.applyMut(e=>({...e,clips:duplicateClip(e.clips,t)}))}reorderClips(t,e){this.applyMut(i=>({...i,clips:reorderClips(i.clips,t,e)}))}trimClip(t,e,i,o){this.applyMut(o=>{const n=o.clips[t];if(!n)return o;const r=this.videoSources[n.srcIdx]?.duration??n.out;return{...o,clips:trimClipEdge(o.clips,t,e,i,r)}},o?.transient)}moveAudioClip(t,e,i){this.applyMut(i=>this.patchAudio(i,t,t=>({...t,startAt:e})),i?.transient)}trimAudioClip(t,e,i,o){this.applyMut(o=>this.patchAudio(o,t,t=>{if("in"===e){const e=i-t.in;return{...t,in:i,startAt:t.startAt+e}}return{...t,out:i}}),o?.transient)}setAudioVolume(t,e,i){this.applyMut(i=>this.patchAudio(i,t,t=>({...t,volume:e}),!1),i?.transient)}removeAudioClip(t){this.applyMut(e=>({...e,audioClips:e.audioClips.filter((e,i)=>i!==t)}))}patchAudio(t,e,i,o=!0){const n=t.audioClips[e];if(!n)return t;let r=i(n);if(o){const e=this.audioSources[n.srcIdx]?.duration??n.out;r=clampAudioClip(r,e,totalDuration(t.clips))}return{...t,audioClips:t.audioClips.map((t,i)=>i===e?r:t)}}setCrop(t,e){this.applyMut(e=>({...e,crop:t}),e?.transient)}clearCrop(){this.applyMut(t=>({...t,crop:void 0}))}setScale(t){this.applyMut(e=>({...e,scale:t}))}clearScale(){this.applyMut(t=>({...t,scale:void 0}))}setRotation(t,e){this.applyMut(e=>({...e,rotation:clampRotation(t)}),e?.transient)}rotateBy(t){this.applyMut(e=>{let i=e.rotation+t;return i>180&&(i-=360),i<-180&&(i+=360),{...e,rotation:clampRotation(i)}})}flipX(){this.applyMut(t=>({...t,flipX:!t.flipX}))}flipY(){this.applyMut(t=>({...t,flipY:!t.flipY}))}setFilter(t,e,i){this.applyMut(i=>({...i,filters:{...i.filters,[t]:e}}),i?.transient)}setFilters(t,e){this.applyMut(e=>({...e,filters:{...e.filters,...t}}),e?.transient)}setFilterPreset(t){this.applyMut(e=>({...e,filterPreset:t}))}addOverlay(t){this.applyMut(e=>({...e,overlays:[...e.overlays??[],t]}))}updateOverlay(t,e,i){this.applyMut(i=>{const o=i.overlays??[];return o[t]?{...i,overlays:o.map((i,o)=>o===t?{...i,...e}:i)}:i},i?.transient)}removeOverlay(t){this.applyMut(e=>({...e,overlays:(e.overlays??[]).filter((e,i)=>i!==t)}))}patch(t,e){e?.transient?(null===this.transientBase&&(this.transientBase=this.history.present),this.history=replacePresent(this.history,{...this.transientBase,...t}),this.emit()):this.commit(t)}commit(t){const e=t?{...this.history.present,...t}:this.history.present,i=this.transientBase;this.transientBase=null,this.history=pushHistory(i?{...this.history,present:i}:this.history,e),this.emit()}setKeepAudio(t){this.applyMut(e=>({...e,keepAudio:t}))}setPoster(t){this.applyMut(e=>({...e,poster:{time:Math.max(0,t)}}))}totalDuration(){return totalDuration(this.history.present.clips)}contentDuration(){const t=this.history.present;return contentDuration(t.clips,t.audioClips)}locate(t){return locateOutput(this.history.present.clips,t)}usedVideoSources(){return usedVideoSrcIndices(this.history.present.clips)}getExportPlan(){const t=this.history.present,e=usedVideoSrcIndices(t.clips),i=t.audioClips.filter(t=>!t.muted),o=[...new Set(i.map(t=>t.srcIdx))].sort((t,e)=>t-e),n=new Map(o.map((t,e)=>[t,e]));return{state:{...t,clips:remapSrcIndices(t.clips,e),audioClips:i.map(t=>({...t,srcIdx:n.get(t.srcIdx)??0}))},videoSrcOrder:e,audioSrcOrder:o}}validate(){return VideoEditState.safeParse(this.getExportPlan().state)}reset(t=defaultVideoEditState()){this.transientBase=null,this.history=createHistory(t),this.emit()}};exports.VideoEditorEngine=VideoEditorEngine;