Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

3shape-dcm

Reads 3Shape .dcm intraoral scan files in JavaScript and hands you the mesh. Writes STL and PLY back out. No dependencies, no build step. Runs in Node and in a browser.

A 3Shape .dcm is not a DICOM file. It shares the extension and nothing else. Inside is an HPS packed scan: XML, with the vertices and triangles packed into base64 blocks. This is why medical imaging tools refuse to open one.

Some scans are encrypted. This library reads those too. See Encrypted scans.

Use

import { parse, toSTL, toPLY } from './parser.mjs';

const mesh = parse(arrayBuffer);

mesh.vertices        // Float32Array, three floats per point
mesh.indices         // Uint32Array, three per triangle
mesh.meta.schema     // 'CA', 'CC' or 'CE'
mesh.meta.encrypted  // true if the file was encrypted

writeFileSync('scan.stl', Buffer.from(toSTL(mesh.vertices, mesh.indices)));
writeFileSync('scan.ply', Buffer.from(toPLY(mesh.vertices, mesh.indices)));

parse throws an HPSError with a code you can switch on: NOT_HPS, UNSUPPORTED_SCHEMA, DECRYPT_FAILED, PARSE_ERROR, BAD_INPUT.

Needs Node 18 or newer. In a browser, import the same file and pass it the ArrayBuffer from a FileReader.

What it reads

Schema Encrypted Status
CA no reads
CC no reads
CE yes reads, decrypts
CB no not supported

Triangles are stored as a small opcode program, not a plain list. The parser runs that program. All eleven opcodes are handled, for both 16 bit and 32 bit index files. Vertex colors are read when the file has them.

Encrypted scans

CE files hide the vertex coordinates behind Blowfish. The triangles stay in the clear. The key is built from values inside the file itself, so no server call is needed:

  1. Start with a fixed 16 byte base key.
  2. If the file has EKID of 1 and a PackageLockList, take the MD5 of that list in canonical form and append its 32 hex digits as ASCII. The key is now 48 bytes.
  3. Decrypt the vertex block with Blowfish in ECB mode. No IV. Each 8 byte block is two 32 bit words, little endian.
  4. Pad with zeros to a block boundary, then cut back to vertexCount * 12.

Canonical form of the lock list means: split on ;, drop the empty parts, sort them, remove repeats, join back with a trailing ;.

Every file carries an Adler-32 of its own plaintext vertex bytes. The parser checks it. If the check fails you get DECRYPT_FAILED instead of a garbage mesh.

Some scans use a key that lives on 3Shape's Key Exchange service. Those cannot be opened offline by anything. They fail the checksum and report DECRYPT_FAILED.

crypto.mjs has its own MD5, Blowfish and Adler-32 so the whole thing works in a browser tab. Both are tested against the published RFC and Blowfish test vectors, and against OpenSSL at five key lengths.

Note on the reference docs

The Open3SDCM README describes CBC mode with PKCS#7 padding and a truncated MD5. Its own source code does not do that. The steps above match the source, and they match real files. Follow the code, not the README.

Tests

node test.mjs

Four real scans, two of them encrypted. Every coordinate is compared against a reference mesh produced by a different tool, so a wrong answer cannot pass. Last run: 4 of 4 decoded, all coordinates exact.

Files

parser.mjs   the reader, plus the STL and PLY writers
crypto.mjs   MD5, Blowfish, Adler-32, CE key derivation
test.mjs     the test run
samples/     real scans and their reference meshes

Credits

The format work rests on two projects, and the sample files come from them:

See samples/README.md for what each file is and which license covers it.

Viewer

If you want to open a scan without writing code, ScanLoupe uses this parser in the browser. The file stays on your machine.

License

MIT

About

Read 3Shape .dcm intraoral scans in JavaScript, including encrypted CE files. Exports STL and PLY. No dependencies.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages