图像加载失败问题分析
问题现象
- 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;
}
};
推荐解决步骤
- 首先尝试延迟加载方案(最简单)
- 如果仍有问题,添加错误重试机制
- 最后考虑 WebGL 状态检查