tui.image-editor icon indicating copy to clipboard operation
tui.image-editor copied to clipboard

Is the bottom control button unavailable after loading a remote image using loadImageFromURL?

Open dodu2014 opened this issue 1 year ago • 2 comments

environment: vue3 typescript

core methods:

type ImageEditorOptions = tuiImageEditor.IOptions & { includeUI: { locale?: Record<string, string> } };
async function init() {
  if (!instanceRef.value) return;
  // 单独列出来,避免 ts 报错
  const options: ImageEditorOptions = {
    includeUI: {
      loadImage: { path: '', name: 'image' }, // 默认加载的图片
      // menu: ['resize', 'crop', 'rotate', 'draw', 'shape', 'icon', 'text', 'filter'], // 底部菜单按钮列表 隐藏镜像flip和遮罩mask
      initMenu: 'crop', // 默认打开的菜单项
      menuBarPosition: 'bottom', // 菜单所在的位置
      locale: localeCN
    },
    cssMaxWidth: 1000, // canvas 最大宽度
    cssMaxHeight: 800, // canvas 最大高度
    selectionStyle: {
      cornerSize: 20,
      rotatingPointOffset: 70
    }
  };
  try {
    // 1. 预加载图片,确保资源可用
    const img = new Image();
    img.src = props.imgUrl;
    await new Promise((resolve, reject) => {
      img.onload = resolve;
      img.onerror = reject;
    });

    // 2. 销毁旧实例(如果存在)
    if (instance.value) {
      instance.value.destroy();
      instance.value = null;
    }

    instance.value = markRaw(new ImageEditor(instanceRef.value, options));
    await instance.value.loadImageFromURL(props.imgUrl, 'image.jpg');
    await instance.value.clearObjects();
  } catch (error) {
    console.error('图片加载失败:', error);
  }
}

Summary After loading the remote image, the bottom control button is not available

Screenshots

Image The red part is not available

Version v3.15.3

Additional context Control buttons are available when using local images

dodu2014 avatar Apr 14 '25 17:04 dodu2014

Is no one maintaining the project?

dodu2014 avatar May 01 '25 02:05 dodu2014

Currently I fetch the image and save it as blob into a state (but it has to be cors allow) then convert to base64 and load it into TuiEditor

// 1. Fetch Function
export async function fetchImageAsBlob(imageUrl: string): Promise<Blob> {
  const response = await fetch(imageUrl, { mode: 'cors' })
  const blob = await response.blob()
  return blob
}

// 2. Convert to base64
export function convertToBase64(blobOrFile: Blob | File) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()

    // Event listener for when the file reading is complete
    reader.onloadend = () => {
      resolve(reader.result) // This contains the Base64 string
    }

    // Event listener for errors
    reader.onerror = (error) => {
      reject(error)
    }

    // Start reading the file as a Data URL (Base64)
    reader.readAsDataURL(blobOrFile)
  })
}

// 3. Load Image
 useEffect(() => {
 convertToBase64(imageFile).then((base64) => {
      if (!editorRef.current) return
      const tuiEditor = new TuiEditor(editorRef.current as Element, {
        includeUI: {
          loadImage: {
            path: base64 as string,
            name: imageFile.name
          },
          locale: langs[i18n.language],
          theme: whiteTheme,
          menuBarPosition: 'left',
          menu: ['resize', 'crop', 'flip', 'rotate', 'draw', 'shape', 'icon', 'text']
        } as tuiImageEditor.IIncludeUIOptions,
       ///...
      })
    })
}, [imageFile, i18n.language])

um1chc5 avatar Jun 25 '25 03:06 um1chc5