var __defProp = Object.defineProperty;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
  for (var prop in b || (b = {}))
    if (__hasOwnProp.call(b, prop))
      __defNormalProp(a, prop, b[prop]);
  if (__getOwnPropSymbols)
    for (var prop of __getOwnPropSymbols(b)) {
      if (__propIsEnum.call(b, prop))
        __defNormalProp(a, prop, b[prop]);
    }
  return a;
};
import { l as lodash, X as Promise$1 } from "./index.js";
import { A as isMobile, e as editorDefaults, l as loader, B as newDrawImageToCanvas, x as createCanvas, C as cleanupCanvasMemory } from "./watermark.js";
import { W as WorkerWrapper, s as sendMessage } from "./gif-apng.worker.js";
const _isMobile = isMobile();
const getMaxFramesLength = (w, h) => {
  if (w > 1600 || h > 1600) {
    return _isMobile ? 15 : 30;
  } else if (w > 1e3 || h > 1e3) {
    return _isMobile ? 20 : 40;
  } else if (w > 700 || h > 700) {
    return _isMobile ? 40 : 70;
  } else {
    return _isMobile ? 40 : 100;
  }
};
function seekFrame(listData, currentTime) {
  const result = [];
  listData.forEach((data) => {
    if (!Array.isArray(data)) {
      result.push(data);
      return;
    }
    let curFrame;
    data.some((frame) => {
      const startTime = frame.startTime;
      if (startTime > currentTime) {
        return true;
      } else if (startTime <= currentTime) {
        curFrame = frame;
        return false;
      }
      return false;
    });
    result.push(__spreadValues({}, curFrame));
  });
  return result;
}
async function clipFrame(element, frameCanvas) {
  const {
    width,
    height,
    imageTransform,
    naturalWidth,
    naturalHeight,
    $imageWidth,
    $imageHeight
  } = element;
  if (element.width === $imageWidth && element.height === $imageHeight && lodash.exports.isEqual(element.imageTransform.toJSON(), editorDefaults.element.transform)) {
    return frameCanvas;
  }
  const mask = element.mask ? await loader.loadImage(element.mask) : null;
  return newDrawImageToCanvas({
    canvas: createCanvas(width, height),
    image: frameCanvas,
    mask,
    width,
    height,
    naturalWidth,
    naturalHeight,
    imageTransformArray: imageTransform.toArray(),
    blendMode: mask ? "source-in" : "source-over",
    imageSmoothingEnabled: false
  });
}
function combineFrames(elementCanvasList, { canvasWidth, canvasHeight } = {}) {
  const framesList = elementCanvasList.filter(Array.isArray);
  if (!framesList.length)
    return elementCanvasList;
  const endTimes = framesList.map((frames) => {
    let i = 0;
    const totalTime = frames.reduce((time, frame) => {
      frame.i = i;
      i++;
      return time + frame.delay;
    }, 0);
    return totalTime;
  });
  const maxEndTime = Math.max(...endTimes);
  endTimes.forEach((time, index) => {
    const frames = framesList[index].slice();
    const ratio = Math.ceil(maxEndTime / time);
    for (let i = 1; i < ratio; i++) {
      const copyFrames = frames.map((item) => __spreadValues({}, item));
      framesList[index].push(...copyFrames);
    }
  });
  let startTimes = [];
  framesList.forEach((frames) => {
    frames.reduce((time, frame) => {
      frame.startTime = time;
      if (time >= maxEndTime)
        return time + frame.delay;
      startTimes.push(time);
      return time + frame.delay;
    }, 0);
  });
  startTimes = lodash.exports.uniq(startTimes).sort((a, b) => a - b);
  const newFrames = [];
  startTimes.forEach((time, i) => {
    const nextTime = startTimes[i + 1] === void 0 ? maxEndTime : startTimes[i + 1];
    const frameLayers = seekFrame(elementCanvasList, time);
    const delay = Math.max(30, nextTime - time);
    frameLayers.forEach((item) => {
      if (item.delay !== void 0) {
        item.delay = delay;
      }
    });
    newFrames.push(frameLayers);
  });
  const maxFramesLength = getMaxFramesLength(canvasWidth, canvasHeight);
  if (maxFramesLength - newFrames.length < 0) {
    return getSampleFrames(newFrames, maxFramesLength - newFrames.length);
  }
  return newFrames;
}
function getFrames(element, { decode, canvasWidth, canvasHeight, lazy = false } = {}) {
  if (element.type === "video") {
    return getVideoFrames(element, { canvasWidth, canvasHeight });
  }
  const maxFramesLength = getMaxFramesLength(canvasWidth, canvasHeight);
  return Promise$1.try(() => {
    return decode ? decode(element) : decodeGifOrApng(element, { needBuffer: true });
  }).then(async (result) => {
    if (maxFramesLength - result.frames.length < 0) {
      result.frames = getSampleFrames(result.frames, maxFramesLength - result.frames.length);
    }
    return Promise$1.map(result.frames, async (item, i) => {
      const lazyFn = async () => {
        const canvas = createCanvas(result.width, result.height);
        const ctx = canvas.getContext("2d");
        const imageData = ctx.createImageData(result.width, result.height);
        if (item.buffer) {
          const uint8 = new Uint8Array(item.buffer);
          imageData.data.set(uint8);
          ctx.putImageData(imageData, 0, 0);
          if (i !== 0 && item.delay === 0) {
            item.delay = 10;
          }
        } else if (item.image) {
          ctx.drawImage(item.image, 0, 0);
        }
        const clipCanvas = await clipFrame(element, canvas);
        clipCanvas !== canvas && cleanupCanvasMemory(canvas);
        if (clipCanvas.width === Math.round(element.width) && clipCanvas.height === Math.round(element.height)) {
          return clipCanvas;
        }
        const newCanvas = createCanvas(element.width, element.height);
        const newCtx = newCanvas.getContext("2d");
        newCtx.drawImage(clipCanvas, 0, 0, element.width, element.height);
        cleanupCanvasMemory(clipCanvas);
        return newCanvas;
      };
      return {
        delay: element.isGif ? item.delay * 10 : item.delay,
        canvas: lazy ? () => lazyFn() : await lazyFn()
      };
    });
  });
}
function seekVideoCanvas({ time, video, width, height } = {}) {
  video.currentTime = time;
  return new Promise$1((resolve) => {
    video.ontimeupdate = resolve;
  }).then(() => {
    width = width || video.videoWidth;
    height = height || video.videoHeight;
    const canvas = createCanvas(width, height);
    const ctx = canvas.getContext("2d");
    ctx.drawImage(video, 0, 0, width, height);
    return canvas;
  });
}
async function getVideoFrames(element, { canvasWidth, canvasHeight } = {}) {
  const maxFramesLength = getMaxFramesLength(canvasWidth, canvasHeight);
  const { naturalDuration, url } = element;
  const delay = 100;
  let frames = [];
  let currentTime = 0;
  for (let i = 0; i < naturalDuration / delay; i++) {
    frames.push({
      delay: (i + 1) * delay > naturalDuration ? naturalDuration % 100 : delay,
      currentTime
    });
    currentTime += delay;
  }
  if (maxFramesLength - frames.length < 0) {
    frames = getSampleFrames(frames, maxFramesLength - frames.length);
  }
  const video = await loader._loadVideo(url);
  const useVideoSize = video.videoWidth * video.videoHeight < element.$imageWidth * element.$imageHeight;
  frames = await Promise$1.mapSeries(frames, (frame) => {
    return seekVideoCanvas({
      time: frame.currentTime / 1e3,
      video,
      width: useVideoSize ? video.videoWidth : element.$imageWidth,
      height: useVideoSize ? video.videoHeight : element.$imageHeight
    }).then((canvas) => {
      return clipFrame(element, canvas);
    }).then((canvas) => {
      frame.canvas = canvas;
      return frame;
    });
  });
  return frames;
}
async function toArrayBuffer(url) {
  const fetchedSourceImage = await fetch(url);
  const arrayBuffer = await fetchedSourceImage.arrayBuffer();
  return new Uint8Array(arrayBuffer);
}
function getSampleFrames(frames, diffLength) {
  frames = frames.slice();
  const frameLength = frames.length - 2;
  const absDiffLength = Math.abs(diffLength);
  const indexs = [];
  for (let i = 0; i < absDiffLength; i++) {
    const index = Math.round((i + 1) * frameLength / absDiffLength);
    indexs.push(index);
  }
  if (diffLength < 0) {
    let totalDelay = 0;
    indexs.reverse().forEach((index) => {
      const frame = frames[index];
      totalDelay += frame.delay !== void 0 ? frame.delay : frames[index][0].delay;
      frames.splice(index, 1);
    });
    const addDelay = Math.round(totalDelay / frames.length);
    frames.forEach((layers) => {
      if (!Array.isArray(layers) && layers.delay !== void 0) {
        layers.delay += addDelay;
      } else if (Array.isArray(layers)) {
        layers.forEach((item) => {
          if (item.delay !== void 0) {
            item.delay += addDelay;
          }
        });
      }
    });
  } else if (diffLength > 0) {
    indexs.reverse().forEach((index) => {
      frames.splice(index, 0, frames[index]);
    });
  }
  return frames;
}
async function decodeGifOrApng(element, { needBuffer } = {}) {
  const buffer = await toArrayBuffer(element.url);
  let result = {};
  const worker = new WorkerWrapper();
  const data = {
    type: element.isGif ? "gif" : "apng",
    buffer,
    needBuffer
  };
  try {
    result = await sendMessage("decodeGifOrApng", data, worker);
  } catch (e) {
    await loader.loadImage(element.url).then((image) => {
      result.width = image.width;
      result.height = image.height;
      result.frames = [
        {
          image
        }
      ];
    });
    console.error(e);
  }
  worker.terminate();
  let totalDuration = 0;
  const defaultDelahy = element.isApng ? 100 : 10;
  result.frames.forEach((frame) => {
    frame.delay = frame.delay || defaultDelahy;
    totalDuration += frame.delay;
  });
  result.duration = element.isGif ? totalDuration * 10 : totalDuration;
  return result;
}
export { clipFrame as a, combineFrames as c, decodeGifOrApng as d, getFrames as g };
