
업무중 DWG라는 포맷을 가진 파일을 DXF로 변환해야하는 일이 생겼다.
웹에서 캐드 도면을 보여주기 위함이었는데, React로 DXF를 보여줄 수 있는 라이브러리를 사용하기 위해서였다.
DWG랑 DXF는 무엇인지 정리해보자.
DWG : DWG ("drawing")는 2차원/3차원 도면 정보를 저장하는 데 사용되는 파일 형식이다.
오토데스크사가 제정한 고유한 형식이지만, 많은 캐드 개발사들이 오토캐드와의 호환성을 유지하기 위하여,
이 포맷을 지원하고 있다.
DXF : DXF는 미국 오토데스크 사의 오토캐드 와 다른 수많은 캐드(CAD) 소프트웨어들 간의 파일 교환을 위한 포맷이며,
캐드 데이터 상호 운용성을 위한 사실상(de facto) 표준이 되었다.
먼저 아래와 같이 생각하였다.
1. 자바 진영의 변환 라이브러리 사용
2. 자바 스크립트 라이브러리 사용
3. 리눅스 지원 프로그램을 사용
물론 상용으로 사용이 가능한 무료 라이센스를 중심으로 알아보았지만, 결과는 일부 지원하거나 API 형식으로
사용량에 따른 과금이 되는 방식으로 제공되고 있었다. 유료로 사용하면 간단히 해결했지만, 사정상 불가했기 때문에
나는 3번을 선택하여 진행하였다.
파일 변환 구현을 위해 리눅스에 설치할 수 있는
CLI TOOL을 지원하는 오픈 소스 소프트웨어를 찾아보았다.
다행히QCAD라는 소프트웨어를 찾을 수 있었고GUI지만CLI로도 변환이 가능했다.
물론 오픈 소스이긴 하지만 공식 문서와 포럼을 알아보다 보니 Community Edition의 경우에는 Professional Trial버전에서
일부 Plugin을 제거 하면 Community Edition을 무료로 이용할 수 있다고 한다.
(하지만 Community Edition은 내가 이용하려는 기능이 제외된다.)
할 수 없이 일단 테스트는 진행하고 라이센스와 비용을 알아보니 사용자 1명당 6만원 돈에서 영구 라이센스다.😄
비용이 얼마 들지 않으니 성능과 속도만 괜찮다면 사용해도 될듯 했다.
먼저 위에 있는 QCAD를 리눅스용 설치 파일을 다운로드 받자.
그리고 다운로드 받은 파일을 sftp를 이용해 Download 파일에 업로드 했다. (나는 Ubuntu 20.04 LTS를 사용중이다.)
dev@dev-desktop:~$ cd Downloads
dev@dev-desktop:~/Downloads$ ls
qcad-3.31.2-trial-linux-qt5.14-x86_64.run
다운로드 받은 설치파일이 제대로 업로드 되었다면 ./qcad-3.31.2-trial-linux-qt5.14-x86_64.run 커멘드로 실행하여 설치를 진행하자.
dev@dev-desktop:~/Downloads$ ./qcad-3.31.2-trial-linux-qt5.14-x86_64.run
Verifying archive integrity... All good.
Uncompressing QCAD................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
QCAD Setup...
Making dir /home/dev/opt/qcad-3.31.2-trial-linux-qt5.14-x86_64...
Copying files...
Invoking postinstall.sh...
Installing mimetypes...
Installing mimetype icons...
Installing desktop menu entries...
Installing desktop icon...
Creating uninstall script...
Setting executable flag...
QCAD Setup finished.
위와 같이 출력이 되면 설치가 완료되었을거다. 해당 경로에 들어가 제대로 설치 되어있는지 확인하자
dev@dev-desktop:~$ cd opt
dev@dev-desktop:~/opt$ ls
qcad-3.31.2-trial-linux-qt5.14-x86_64
dev@dev-desktop:~/opt$ cd^C
dev@dev-desktop:~/opt$ cd qcad-3.31.2-trial-linux-qt5.14-x86_64
dev@dev-desktop:~/opt/qcad-3.31.2-trial-linux-qt5.14-x86_64$ ls
adinit.dat dwghatch libicuio.so.56 libqcadgrid.so libQt5Help.so.5 libQt5Qml.so.5 libQt5ScriptTools.so.5 libQt5XmlPatterns.so.5 platforms svg2dwg
bbox dwghatcharea libicule.so.56 libqcadgui.so libQt5MultimediaGstTools.so.5 libQt5QmlWorkerScript.so.5 libQt5Sensors.so.5 libQt5Xml.so.5 plugins themes
bmp2dwg dwginfo libiculx.so.56 libqcadoperations.so libQt5MultimediaQuick.so.5 libQt5QuickControls2.so.5 libQt5Sql.so.5 libraries proj.db ts
cc-by-3.0.txt dwgmapconvert libicutest.so.56 libqcadsnap.so libQt5Multimedia.so.5 libQt5QuickParticles.so.5 libQt5Svg.so.5 libspatialindexnavel.so qcad uninstall
dwg2bmp examples libicutu.so.56 libqcadspatialindex.so libQt5MultimediaWidgets.so.5 libQt5QuickShapes.so.5 libQt5WaylandClient.so.5 LICENSE.txt qcad-bin xcbglintegrations
dwg2csv fonts libicuuc.so.56 libqcadstemmer.so libQt5Network.so.5 libQt5Quick.so.5 libQt5WebChannel.so.5 linetypes qcad_icon.png xdg
dwg2dwg gpl-3.0-exceptions.txt liblibcrypto.so libQt5Concurrent.so.5 libQt5OpenGL.so.5 libQt5QuickTemplates2.so.5 libQt5WebSockets.so.5 merge qcad-mimetypes.xml
dwg2maptiles gpl-3.0.txt libpdfium.so libQt5Core.so.5 libQt5PositioningQuick.so.5 libQt5QuickTest.so.5 libQt5WebView.so.5 mimetype.png readme.txt
dwg2pdf lgpl.txt libqcadcore.so libQt5DBus.so.5 libQt5Positioning.so.5 libQt5QuickWidgets.so.5 libQt5Widgets.so.5 patterns revision.txt
dwg2svg libicudata.so.56 libqcadecmaapi.so libQt5EglFsKmsSupport.so.5 libQt5PrintSupport.so.5 libQt5RemoteObjects.so.5 libQt5X11Extras.so.5 pdf2dwg Ribbonsoft-qcad.desktop
dwgexplode libicui18n.so.56 libqcadentity.so libQt5Gui.so.5 libQt5QmlModels.so.5 libQt5Script.so.5 libQt5XcbQpa.so.5 platforminputcontexts scripts
설치가 되었다면 해당 경로에 위와 같이 파일들이 보일거다. 내가 사용할 기능은 dwg2dwg인데 이 녀석이 DWG를 DXF로
혹은 그 반대로도 변환이 가능하다.
이제 QCAD는 설치했으니 API를 만들어 호출했을때, 리눅스에 있는 QCAD의 CLI TOOL을 이용하여 파일을 변환해보자
나는 아래와 같은 프로세스로 진행했다.
- API호출
- JAVA어플리케이션에서 SSH로 리모트 서버 접근
- JAVA어플리케이션 경로에 존재하는
DWG파일을 리모트 서버로 업로드- JAVA어플리케이션에서 리눅스로
CLI Command호출- 리눅스에 설치된
QCAD가 파일 변환을 진행- 변환된 파일을 JAVA어플리케이션으로 다운로드
나는 spring boot를 이용해서 진행했다.
ssh, sftp등을 이용할건데 그때마다 서버의 정보를 일일히 입력하기 번거롭기 때문에 application.yml에 설정했다.
host:
ip: [리모트 서버의 주소]
port: [ssh port]
username: [사용자명]
password: [비밀번호]
그리고 아래와 같이 Controller에서 @Value를 사용해 필드 변수에 주입받아 사용했다.
@RestController
@RequiredArgsConstructor
@Slf4j
@RequestMapping("api/v1/convert")
public class ConvertController {
@Value("${host.ip}")
private String hostIp;
@Value("${host.username}")
private String user;
@Value("${host.password}")
private String password;
@Value("${host.port}")
private int port;
호출할 수 있는 API를 아래와 같이 추가 하였다.
@GetMapping("/convert-dxf")
public ResponseEntity<byte[]> convertDwgToDxf() {
log.info("변환 요청 시작: DWG -> DXF");
Resource dwgResource = resourceLoader.getResource("classpath:/static/dwg/Web.dwg");
String tempDxfFilePath = "/home/dev/tmp/Web.dxf";
String dxfFilePath = new File("src/main/resources/static/dxf/Web.dxf").getAbsolutePath();
Session session = null;
ChannelSftp sftpChannel = null;
try {
JSch jsch = new JSch();
session = jsch.getSession(user, hostIp, port);
configureSession(session);
sftpChannel = createSftpChannel(session);
// DWG 파일을 서버로 전송
uploadFile(sftpChannel, dwgResource, "/tmp/Web.dwg");
// QCAD 변환 명령어 실행
String command = String.format("%s -platform offscreen -r R2010 -f -o %s %s", QCAD_PATH, tempDxfFilePath, "/tmp/Web.dwg");
String output = executeCommand(session, command);
log.info("QCAD 변환 결과: {}", output);
// 임시 DXF 파일 존재 여부 확인
if (!checkFileExists(session, tempDxfFilePath)) {
log.error("임시 DXF 파일이 존재하지 않습니다: {}", tempDxfFilePath);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
// 임시 DXF 파일 다운로드
downloadFile(sftpChannel, tempDxfFilePath, dxfFilePath);
} catch (Exception e) {
log.error("Exception 발생: {}", e.getMessage(), e);
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
} finally {
closeResources(sftpChannel, session);
}
return prepareDxfResponse(dxfFilePath);
}
SSH로 접근하기 위해서
JSch가 필요하다. 미리 의존성을 추가해주자
호출해서 클라이언트쪽으로는 Byte[] 형태로 응답하는 형태로 진행하였다. 호출시 정상적으로 동작하는 것을 확인했다.
각 메서드는 분리하여 작성하였으나, 따로 기재하지는 않겠다.
원하던 기능을 구현하긴 하였으나. 프로그램이 변환하고 응답하기까지의 시간이 15초정도 소요되어
Viewer에서 사용하기는 힘들다는 결론이었다. 한가지 사용할 수 있는 방법으로 생각한것은QCAD의dwg2dwg가DXF->DWG도 가능하다는 것이었다. 그럼 서버에서DXF를 가지고Viewer에 보여주는 용도로만 사용하다가 사용자가DWG를 다운로드 받을때 해당API를 호출해서 서버에서 변환하여 내려주는것이다.물론 서버가 변환하는 프로그램을 실행하고 리소스를 사용하는 과정에서 서버의 부하는 커지겠지만,
저장공간 리소스를 굉장히 많이 50% 정도 절약하고 확보할 수 있다는 장점이 있기 때문에 일단 이렇게 사용을 해볼 생각이다.