Bug ID: annotation-cross-environment-rendering
修复日期: 2025-12-16
版本: 1.10.2
提交哈希: 8b4fe68
浏览器端保存的图像注释数据,在桌面端(Electron)环境下无法正确渲染显示。
注释数据在保存时,会记录图像的引用 URL(referencedImageId 和 referencedImageURI),这些 URL 包含了完整的服务器地址信息。
示例:
{
metadata: {
referencedImageId: "dicomweb:http://192.168.110.245:6001/dicomweb/studies/...",
referencedImageURI: "http://192.168.110.245:6001/dicomweb/studies/..."
}
}
当用户在不同环境下访问应用时:
http://localhost:6001 或其他代理地址访问http://192.168.110.245:6001 或配置的其他地址访问注释数据中硬编码的服务器地址与当前环境不匹配,导致:
referencedImageId 找到对应的图像// 渲染注释时的逻辑
const imageId = annotation.metadata?.referencedImageId;
// 如果 imageId 中的服务器地址与当前环境不匹配
// 则无法找到对应的 viewport,注释渲染失败
const elements = this.findElementsByFOR(imageId);
if (elements.length === 0) {
console.warn('未找到对应的 viewport');
return; // 渲染失败
}
在渲染注释之前,自动将注释对象中的服务器地址替换为当前环境的服务器地址,确保注释数据能够正确匹配当前环境下的图像引用。
在 AnnotationManager 类中新增 updateAnnotationUrls 私有方法:
/**
* 更新注释对象中的 URL,替换为当前服务器地址
* @param annotation 注释对象
* @returns 更新后的注释对象
*/
private updateAnnotationUrls(annotation: any): any {
try {
const currentIpPort = getIpPort();
if (!currentIpPort) {
console.warn('【annotationmanager】无法获取当前服务器地址,跳过 URL 更新');
return annotation;
}
// 正则表达式:匹配 URL 中的协议+域名/IP+端口部分
// 例如:dicomweb:http://192.168.110.245:6001/path -> 提取 http://192.168.110.245:6001
const urlRegex = /(https?:\/\/[^\/]+)/;
// 更新 metadata.referencedImageId
if (annotation.metadata?.referencedImageId) {
const originalUrl = annotation.metadata.referencedImageId;
const updatedUrl = originalUrl.replace(urlRegex, currentIpPort);
annotation.metadata.referencedImageId = updatedUrl;
console.log(`【annotationmanager】已更新 referencedImageId: ${originalUrl} -> ${updatedUrl}`);
}
// 更新 metadata.referencedImageURI(如果存在)
if (annotation.metadata?.referencedImageURI) {
const originalUrl = annotation.metadata.referencedImageURI;
const updatedUrl = originalUrl.replace(urlRegex, currentIpPort);
annotation.metadata.referencedImageURI = updatedUrl;
console.log(`【annotationmanager】已更新 referencedImageURI: ${originalUrl} -> ${updatedUrl}`);
}
return annotation;
} catch (error) {
console.error('【annotationmanager】更新注释 URL 失败:', error);
return annotation;
}
}
在 renderAnnotations 方法中,反序列化后立即调用 URL 更新:
private async renderAnnotations(annotationStrings: string[]): Promise<void> {
console.log(`【annotationmanager】🎨 渲染 ${annotationStrings.length} 个注释`);
for (const annotationString of annotationStrings) {
try {
// 1. 反序列化为Cornerstone格式
let deserializedAnnotation = this.serializer.deserialize(annotationString);
// 2. 更新注释中的 URL,替换为当前服务器地址
deserializedAnnotation = this.updateAnnotationUrls(deserializedAnnotation);
// 3. 继续后续的渲染逻辑...
const imageId = deserializedAnnotation.metadata?.referencedImageId;
// ...
} catch (error) {
console.error('【annotationmanager】渲染注释失败:', error);
}
}
}
使用正则表达式 /(https?:\/\/[^\/]+)/ 精确匹配 URL 的服务器部分:
匹配示例:
// 输入
"dicomweb:http://192.168.110.245:6001/dicomweb/studies/1.2.3/series/4.5.6"
// 匹配到
"http://192.168.110.245:6001"
// 替换为当前服务器地址
"dicomweb:http://localhost:6001/dicomweb/studies/1.2.3/series/4.5.6"
import { getIpPort } from '../../../API/config';
getIpPort(): 获取当前环境的服务器地址(如 http://localhost:6001)?. 避免空指针异常【annotationmanager】已更新 referencedImageId:
dicomweb:http://192.168.110.245:6001/dicomweb/...
-> dicomweb:http://localhost:6001/dicomweb/...
✅ 注释数据可以在不同服务器环境之间无缝切换 ✅ 支持浏览器端和桌面端的数据共享
✅ 无需手动修改注释数据 ✅ 自动检测并替换服务器地址
✅ 服务器地址获取失败时不影响渲染 ✅ 完整的错误处理和日志记录
✅ 代码结构清晰,易于理解 ✅ 日志输出详细,便于调试
src/features/imageAnnotation/services/AnnotationManager.tsimport { getIpPort } from '../../../API/config';
package.json: 1.10.1 → 1.10.2CHANGELOG.md: 添加版本 1.10.2 的变更记录Commit: 8b4fe68
Message:
fix: 修复注释跨环境渲染问题
- 新增 updateAnnotationUrls 方法,自动更新注释对象中的服务器地址
- 修复浏览器端保存的注释数据在桌面端(Electron)无法渲染的问题
- 在渲染注释时自动替换 referencedImageId 和 referencedImageURI 中的服务器地址
- 使用正则表达式匹配并替换 URL 中的协议+域名/IP+端口部分
- 新增服务器地址获取失败的容错处理和日志记录
改动文件:
- src/features/imageAnnotation/services/AnnotationManager.ts
- CHANGELOG.md
- package.json (版本更新: 1.10.1 -> 1.10.2)
这是一个典型的跨环境数据同步问题。通过在渲染时动态更新服务器地址,而不是在保存时硬编码,成功解决了注释数据在不同环境下的兼容性问题。
核心思想:将环境相关的信息(服务器地址)延迟到使用时再确定,而不是在存储时固化,从而提高系统的灵活性和可移植性。