A PHP library for working with DICOM medical images. Handles tag reading and writing, JPEG conversion, compression, and DICOM networking (C-ECHO, C-STORE send and receive) by wrapping the DCMTK command-line toolkit.
Originally created by Dean Vaughan (deanvaughan.org).
- PHP 8.0 or later (CLI or web)
- DCMTK command-line utilities installed and accessible
By default the library looks for DCMTK binaries in /usr/local/bin. If your installation is elsewhere, edit the TOOLKIT_DIR constant at the top of class_dicom.php.
On Debian/Ubuntu:
apt install php-cli dcmtkcomposer require rbraunm/class_dicomCopy class_dicom.php into your project and require it directly:
require_once('class_dicom.php');$d = new dicom_tag('/path/to/image.dcm');
$patient_name = $d->get_tag('0010', '0010');
$modality = $d->get_tag('0008', '0060');
// All loaded tags are available in $d->tags as an associative array
// keyed by "group,element" (e.g. "0010,0010")The constructor calls load_tags() automatically if the file exists and passes the is_dcm() check. Tags can also be loaded manually:
$d = new dicom_tag;
$d->file = '/path/to/image.dcm';
$d->load_tags();$d = new dicom_tag('/path/to/image.dcm');
$d->write_tags([
'0010,0010' => 'DOE^JOHN',
'0008,0080' => 'General Hospital',
]);This modifies the file in place using dcmodify.
$c = new dicom_convert('/path/to/image.dcm');
// Full-size JPEG
$c->jpg_quality = 90; // 0-100, default 100
$jpg_path = $c->dcm_to_jpg();
// Thumbnail
$c->tn_size = 200; // width in pixels, default 125
$tn_path = $c->dcm_to_tn();$c = new dicom_convert('/path/to/image.dcm');
// Decompress to a new file (or omit the argument to overwrite)
$c->uncompress('/path/to/output.dcm');
// JPEG lossless compress
$c->compress('/path/to/compressed.dcm');Known issue:
jpg_to_dcm()treats any output fromxml2dcmas a fatal error. The bundled XML template (examples/jpg_to_dcm.xml) produces a SOPInstanceUID mismatch warning on current DCMTK versions, which causes the function to return early without embedding pixel data. The resulting file is a valid DICOM header but contains no image. This will be fixed in v2.0.0.
The intended usage (once fixed) follows the pattern in examples/jpg_to_dcm.php:
$c = new dicom_convert;
$c->jpg_file = '/path/to/photo.jpg';
$c->template = '/path/to/jpg_to_dcm.xml'; // see examples/jpg_to_dcm.xml
$c->temp_dir = '/tmp/dcm_temp';
$dcm_path = $c->jpg_to_dcm([
'0008,0012' => date('Ymd'),
'0008,0013' => date('Gis'),
'0008,0050' => 'ACCESSION123',
'0008,0080' => 'General Hospital',
'0008,0090' => 'Dr. Smith',
'0008,1030' => 'Study Description',
'0008,103e' => 'Series Description',
'0010,0010' => 'DOE^JOHN',
'0010,0020' => 'PATIENT001',
'0010,0030' => '19700101',
'0010,0040' => 'M',
'0010,21b0' => 'Patient History',
'0010,4000' => 'Patient Comments',
'0018,0015' => 'Head',
'0020,000d' => '1.3.51.0.7.2822962297.26312.19209.44846.7354.10266.42',
'0020,000e' => '1.3.51.5156.4083.' . date('Ymd') . '.42',
'0020,0011' => '1',
'0020,0012' => '1',
'0020,0013' => '1',
]);The tag keys must match the (group,element) placeholders in the XML template. See examples/jpg_to_dcm.php for the full tag mapping.
$c = new dicom_convert('/path/to/multiframe.dcm');
$video_path = $c->multiframe_to_video('mp4', 24, '/tmp/video_temp');Requires ffmpeg on the system.
$n = new dicom_net;
// C-ECHO (DICOM ping)
$result = $n->echoscu('192.168.1.100', 104, 'MY_AE', 'REMOTE_AE');
// Returns 0 on success, error output string on failure
// C-STORE send (single file)
$n->file = '/path/to/image.dcm';
$n->send_dcm('192.168.1.100', 104, 'MY_AE', 'REMOTE_AE');
// C-STORE send (batch — all files in the same directory)
$n->file = '/path/to/image.dcm';
$n->send_dcm('192.168.1.100', 104, 'MY_AE', 'REMOTE_AE', 1);
// C-STORE receive (blocking — starts a DICOM listener)
$n->store_server(
11112, // port
'/var/dicom/incoming', // storage directory
'/path/to/handler_script.php', // called after each file received
'/path/to/store_server_config.cfg', // storescp config
);See examples/store_server.php, examples/store_server_handler.php, and examples/store_server_config.cfg for a working receive setup.
// Check if a file is valid DICOM
if (is_dcm('/path/to/file')) {
// it's DICOM
}The test suite uses PHP + DCMTK for the code under test and Python for independent validation. This ensures DICOM files produced by the library are verified by a completely separate implementation, not just read back by the same tools that wrote them.
# System packages
apt install php-cli dcmtk
# Python packages
pip install pydicom pynetdicom Pillow numpypython3 tests/test_class_dicom.pyThe test runner exercises every public method against real DICOM files:
- Tag reads are cross-validated against pydicom
- Tag writes are confirmed by both PHP re-read and pydicom
- JPEG conversions are validated with Pillow (magic bytes, full decode, dimension matching)
- Compress/uncompress cycles verify transfer syntax changes, demographic preservation, and pixel data integrity
- Network operations run against a pynetdicom SCP that confirms C-ECHO events server-side and validates C-STORE round-trips down to pixel-level array equality
| Class | Purpose |
|---|---|
dicom_tag |
Read and write DICOM tags via dcmdump/dcmodify |
dicom_convert |
Image format conversion, compression, thumbnails |
dicom_net |
DICOM networking: C-ECHO, C-STORE SCU/SCP |
| Function | Purpose |
|---|---|
is_dcm($file) |
Returns 1 if the file is valid DICOM, 0 otherwise |
Execute($command) |
Shell execution wrapper (captures stdout + stderr) |
The examples/ directory contains working scripts for common operations:
| File | Description |
|---|---|
get_tags.php |
Read and display tags from a DICOM file |
get_tags_webbased.php |
Same, formatted for browser output |
write_tags.php |
Modify tags in a DICOM file |
dcm_to_jpg.php |
Convert DICOM to JPEG |
jpg_to_dcm.php |
Convert JPEG to DICOM with custom tags |
jpg_to_dcm.xml |
XML template for JPEG-to-DICOM conversion |
compress.php |
JPEG lossless compress a DICOM file |
uncompress.php |
Decompress a DICOM file |
send_dcm.php |
Send a DICOM file to a remote host |
send_directory.php |
Send all files in a directory |
store_server.php |
Start a DICOM receive server |
store_server_handler.php |
Handler script called after each received file |
store_server_config.cfg |
Configuration for the receive server |
MIT