image-loading-failure-analysis.md 3.0 KB

图像加载失败问题分析

问题现象

  • WebGL 警告出现但不崩溃
  • 图像没有显示出来
  • 错误发生在切换胶片时的自动加载 (loadImageFromProps)

根本原因

时序竞争问题

// 当组件重新创建时(由于 React key 修复)
1. useEffect() 开始执行 - 初始化渲染引擎和 viewport
2. useEffect([imageId, stackViewport]) 同时触发 - 尝试加载图像
3. 但是 WebGL 上下文可能还没有完全稳定
4. 导致图像加载在不稳定的上下文中失败

WebGL 上下文初始化不完整

  • 新创建的 WebGL 上下文需要时间来检查和加载扩展
  • OES_texture_float_linear 检查失败可能影响后续的纹理操作
  • 虽然 Cornerstone 会尝试降级,但可能导致初次加载失败

解决方案

方案1:延迟图像加载

useEffect(() => {
  const loadImageFromProps = async () => {
    if (!stackViewport) return;
    
    // 给 WebGL 上下文一些时间稳定
    await new Promise(resolve => setTimeout(resolve, 100));
    
    // 避免重复加载相同图像
    if (imageId === currentImageId) return;
    
    if (imageId && imageId.trim() !== '') {
      console.log(`[DcmCell] 开始从 props 加载图像: ${imageId}`);
      const success = await loadImage(imageId, 'props');
      if (success) {
        setCurrentImageId(imageId);
      }
    } else {
      // 清空逻辑...
    }
  };

  loadImageFromProps();
}, [imageId, stackViewport]);

方案2:检查 WebGL 状态

const isWebGLContextStable = () => {
  const canvas = viewportRef.current?.querySelector('canvas');
  if (!canvas) return false;
  
  const gl = canvas.getContext('webgl') || canvas.getContext('webgl2');
  return gl && gl.getError() === gl.NO_ERROR;
};

方案3:改进错误处理和重试

const loadImage = async (targetImageId: string, source: 'props' | 'drag' = 'props', retryCount = 0): Promise<boolean> => {
  if (!stackViewport || !targetImageId) return false;
  
  try {
    const fullImageUrl = targetImageId.startsWith('dicomweb:')
      ? targetImageId
      : getDcmImageUrl(targetImageId);
    
    await stackViewport.setStack([fullImageUrl], 0);
    stackViewport.render();
    setHasImage(true);
    
    console.log(`[DcmCell] 图像加载成功 (${source}): ${targetImageId}`);
    return true;
  } catch (error) {
    console.error(`[DcmCell] 图像加载失败 (${source}):`, error);
    
    // 如果是 WebGL 相关错误且还没重试过,进行重试
    if (retryCount === 0 && error.message && 
        (error.message.includes('WebGL') || error.message.includes('texture'))) {
      console.log(`[DcmCell] WebGL 错误,1秒后重试...`);
      await new Promise(resolve => setTimeout(resolve, 1000));
      return loadImage(targetImageId, source, 1);
    }
    
    setHasImage(false);
    return false;
  }
};

推荐解决步骤

  1. 首先尝试延迟加载方案(最简单)
  2. 如果仍有问题,添加错误重试机制
  3. 最后考虑 WebGL 状态检查