
最近要做一个位图转矢量图的功能,设计到png,jpg等位图的图像处理算法应用。于是分析一下友商的开源软件,Snapmaker Luban。
主要是图片导入的工具,跟踪选中图片会,代码都是怎么处理的。
我使用的激光模式,
导入图片的工具图片是定义在 SVGLeftBar.jsx

这里有一个隐藏的文件输入框。当选择文件后,就会触发props.onChangeFile函数。
该函数是从父级组件传下来的,allowedFiles参数定义了能够导入的文件类型,也是从父级组件传下来的。
找一下他的父级组件,搜了一下,父级组件叫做SVGEditor.tsx

然后我们发现allowedFiles参数与onChangeFile 参数 也是从上游传下来,我们就找。
为什么要费劲找这两个参数那?因为这个两个参数定义这个功能的绝大部份交互和业务逻辑。
SVGEditor.tsx组件被两个组件引用,如下图,我们要找的是LaserVisualizer下的

在该组件Visualizer.tsx中排查,我们发现参数allowedFiles 最多支持这些格式
.svg, .png, .jpg, .jpeg, .bmp, .dxf, .stl, .amf, .3mf
以下是oncan
onChangeFile: async (event) => {
const file = event.target.files[0];
const extname = path.extname(file.name).toLowerCase();
if (extname === '.stl' && this.props.materials.isRotate) {
modal({
cancelTitle: i18n._('key-Laser/Edit/ContextMenu-Close'),
title: i18n._('key-Laser/Edit/ContextMenu-Import Error'),
body: i18n._('Failed to import this object. \nPlease select a supported file format.')
});
return;
}
let uploadMode;
if (extname === '.svg') {
uploadMode = PROCESS_MODE_VECTOR;
} else if (extname === '.dxf') {
uploadMode = PROCESS_MODE_VECTOR;
} else {
uploadMode = PROCESS_MODE_GREYSCALE;
}
this.setState({
file,
uploadMode
});
// Switch to PAGE_EDITOR page if new image being uploaded
this.props.switchToPage(PAGE_EDITOR);
if ((extname === '.stl' || extname === '.amf' || extname === '.3mf') && !this.props.materials.isRotate) {
this.props.cutModel(file, () => {
modal({
cancelTitle: i18n._('key-Laser/Edit/ContextMenu-Close'),
title: i18n._('key-Laser/Edit/ContextMenu-Import Error'),
body: i18n._('Failed to import this object. \nPlease select a supported file format.')
});
});
} else if (extname === '.dxf' || extname === '.svg' || extname === '.png' || extname === '.jpg' || extname === '.jpeg' || extname === '.jpeg, .bmp') {
debugger
const fileInfo = await this.props.checkIsOversizeImage(file, () => {
modal({
cancelTitle: i18n._('key-Laser/Edit/ContextMenu-Close'),
title: i18n._('key-Laser/Edit/ContextMenu-Import Error'),
body: i18n._('Failed to import this object. \nPlease select a supported file format.')
});
});
this.fileInfo.current = fileInfo;
} else {
this.props.uploadImage(file, uploadMode, () => {
modal({
cancelTitle: i18n._('key-Laser/Edit/ContextMenu-Close'),
title: i18n._('key-Laser/Edit/ContextMenu-Import Error'),
body: i18n._('Failed to import this object. \nPlease select a supported file format.')
});
}, true);
}
},当上传png图片后, 触发上游的函数 checkIsOversizeImage
这也是一个比较重要的函数 内容入下
checkIsOversizeImage: (headType, file, onError) => async (dispatch, getState) => {
const { materials, progressStatesManager, coordinateSize } = getState()[headType];
const formData = new FormData();
formData.append('image', file);
formData.append('isRotate', materials.isRotate);
return new Promise((resolve) => {
api.uploadImage(formData)
.then(res => {
resolve(res.body);
// Ensure promise is completed first
setTimeout(() => {
const { sourceWidth, sourceHeight } = res.body;
const isOverSize = isOverSizeModel(coordinateSize, sourceWidth, sourceHeight);
dispatch(
actions.updateState(headType, {
isOverSize: isOverSize
})
);
});
})
.catch(err => {
resolve();
onError && onError(err);
dispatch(
actions.updateState(headType, {
stage: STEP_STAGE.CNC_LASER_UPLOAD_IMAGE_FAILED,
progress: 1
})
);
progressStatesManager.finishProgress(false);
});
});
},