最近要做一个位图转矢量图的功能,设计到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);
});
});
},