DICOM Basics using Java - Introduction to DICOMweb
Introduction
This article is part of my series of articles on the DICOM standard. If you are totally new to DICOM, please have a quick look at my earlier article titled "Introduction to the DICOM Standard" for a quick introduction. In this tutorial, we will explore DICOMweb, which is the modern RESTful approach to accessing and manipulating DICOM data over HTTP/HTTPS.
What is DICOMweb?
DICOMweb is a set of RESTful services for medical imaging defined in the DICOM standard. It provides a simpler, web-friendly alternative to the traditional DICOM network protocols (DIMSE). DICOMweb makes it easier to build web applications, mobile apps, and cloud-based solutions for medical imaging.
The three core DICOMweb services are:
- QIDO-RS (Query based on ID for DICOM Objects - RESTful Services) - Search for DICOM objects
- WADO-RS (Web Access to DICOM Objects - RESTful Services) - Retrieve DICOM objects
- STOW-RS (Store Over the Web - RESTful Services) - Store DICOM objects
Benefits of DICOMweb
- Simplicity - Uses standard HTTP methods (GET, POST) familiar to web developers
- Interoperability - Works with standard web technologies and infrastructure
- Scalability - Can leverage HTTP caching, load balancing, and CDNs
- Security - Uses standard HTTPS and authentication mechanisms
- Mobile-friendly - Easier to access from mobile devices and web browsers
The Theory Behind DICOMweb
DICOMweb represents a fundamental architectural shift from connection-oriented stateful protocols to stateless RESTful services. Understanding this shift helps explain both DICOMweb's advantages and its design decisions.
The Limitations of Traditional DICOM Networking
Traditional DICOM networking (DIMSE over TCP) was designed in the early 1990s with assumptions that don't match modern IT infrastructure:
- Stateful Associations: Each operation requires establishing an association (negotiating presentation contexts), which adds latency and doesn't work well through firewalls/load balancers
- Binary Protocol: The DIMSE protocol is not human-readable and requires specialized tools to debug
- Non-Standard Port: Port 104/11112 is often blocked by firewalls, unlike HTTP/HTTPS (80/443)
- No Caching: Every request hits the origin server; no HTTP caching infrastructure can help
- Complex Security: TLS for DICOM requires bilateral certificate exchange, unlike web PKI
RESTful Design Principles
DICOMweb follows REST (Representational State Transfer) architectural constraints:
- Stateless: Each request contains all information needed; no session state on server
- Resource-Based: Studies, series, and instances are addressable resources with URLs
- Uniform Interface: Standard HTTP methods (GET, POST) with standard semantics
- Cacheable: Responses can indicate cacheability, enabling CDN and proxy caching
- Layered System: Clients don't know if they're talking directly to origin or through proxies
The Multipart Response Challenge
One complexity in DICOMweb is handling DICOM's binary format over HTTP. WADO-RS uses multipart/related responses to return multiple DICOM instances in a single HTTP response. This is necessary because:
- A study may contain hundreds of instances
- Each instance must maintain its binary DICOM format
- HTTP doesn't natively support returning multiple "files" in one response
The multipart format wraps each DICOM instance with boundary markers and content-type headers, allowing extraction of individual instances from the response stream.
Cloud-Native Medical Imaging
DICOMweb enables "cloud-native" medical imaging architectures:
- Horizontal Scaling: Stateless servers can scale behind load balancers
- Edge Caching: CDNs can cache frequently-accessed images closer to users
- API Gateways: Standard OAuth2/OIDC authentication at the gateway layer
- Microservices: Different services can handle QIDO, WADO, STOW independently
- Serverless: Functions can process DICOMweb requests without persistent servers
Tools for Tutorial
- JDK 1.8 SDK or higher
- Eclipse or any other Java IDE
- Orthanc Server with DICOMweb plugin - download here
- You can find the source code used in this tutorial on GitHub
“The Web as I envisaged it, we have not seen it yet. The future is still so much bigger than the past.” ~ Tim Berners-Lee
QIDO-RS: Querying DICOM Objects
QIDO-RS is the RESTful equivalent of C-FIND. It allows you to search for studies, series, and instances using HTTP GET requests with query parameters.
Key QIDO-RS Endpoints:
/studies- Search for studies/studies/{studyUID}/series- Search for series within a study/studies/{studyUID}/series/{seriesUID}/instances- Search for instances
Common Query Parameters:
PatientName,PatientID- Patient matchingStudyDate,StudyTime- Date/time filteringModality,ModalitiesInStudy- Modality filteringAccessionNumber- Accession matchinglimit,offset- Paginationincludefield- Specify fields to return
Example: QIDO-RS Query in Java
package com.saravanansubramanian.dicom.pixelmedtutorial;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
/**
* DICOM QIDO-RS Query Demo
*/
public class QidoRsQueryDemo {
// Orthanc DICOMweb base URL (requires DICOMweb plugin)
private static final String DICOMWEB_BASE_URL = "http://localhost:8042/dicom-web";
public static void main(String[] args) {
try {
System.out.println("=== DICOM QIDO-RS Query Demo ===\n");
// Query all studies with limit
System.out.println("--- Query All Studies (limit 10) ---");
queryStudies(null, null, null, 10, 0);
// Query by patient name
System.out.println("\n--- Query by Patient Name ---");
queryStudies("Doe*", null, null, 10, 0);
// Query by modality
System.out.println("\n--- Query CT Studies ---");
queryStudies(null, "CT", null, 10, 0);
// Query by date range
System.out.println("\n--- Query by Date Range ---");
queryStudies(null, null, "20240101-20241231", 10, 0);
System.out.println("\n=== QIDO-RS Demo Complete ===");
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
/**
* Query for studies with optional filters
*/
private static void queryStudies(String patientName, String modality,
String studyDate, int limit, int offset) {
try {
StringBuilder urlBuilder = new StringBuilder(DICOMWEB_BASE_URL + "/studies?");
// Add query parameters
if (patientName != null && !patientName.isEmpty()) {
urlBuilder.append("PatientName=")
.append(URLEncoder.encode(patientName, "UTF-8")).append("&");
}
if (modality != null && !modality.isEmpty()) {
urlBuilder.append("ModalitiesInStudy=")
.append(URLEncoder.encode(modality, "UTF-8")).append("&");
}
if (studyDate != null && !studyDate.isEmpty()) {
urlBuilder.append("StudyDate=")
.append(URLEncoder.encode(studyDate, "UTF-8")).append("&");
}
// Pagination
urlBuilder.append("limit=").append(limit).append("&");
urlBuilder.append("offset=").append(offset);
// Specify fields to include
urlBuilder.append("&includefield=").append(URLEncoder.encode("00100010", "UTF-8")); // PatientName
urlBuilder.append("&includefield=").append(URLEncoder.encode("00100020", "UTF-8")); // PatientID
urlBuilder.append("&includefield=").append(URLEncoder.encode("0020000D", "UTF-8")); // StudyInstanceUID
String url = urlBuilder.toString();
System.out.println("URL: " + url);
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/dicom+json");
int responseCode = conn.getResponseCode();
System.out.println("Response Code: " + responseCode);
if (responseCode == 200) {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(conn.getInputStream()))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
System.out.println("Response length: " + response.length() + " chars");
}
} else {
System.out.println("Error: " + conn.getResponseMessage());
}
conn.disconnect();
} catch (Exception e) {
System.out.println("Error querying studies: " + e.getMessage());
}
}
}
“Any sufficiently advanced technology is indistinguishable from magic.” ~ Arthur C. Clarke
WADO-RS: Retrieving DICOM Objects
WADO-RS is used to retrieve DICOM objects. It supports multiple response formats including DICOM (multipart/related) and JSON metadata.
Key WADO-RS Endpoints:
/studies/{studyUID}- Retrieve all instances in a study/studies/{studyUID}/series/{seriesUID}- Retrieve all instances in a series/studies/{studyUID}/series/{seriesUID}/instances/{instanceUID}- Retrieve a specific instance/studies/{studyUID}/series/{seriesUID}/instances/{instanceUID}/rendered- Retrieve rendered image
STOW-RS: Storing DICOM Objects
STOW-RS allows you to store DICOM objects on a server using HTTP POST with multipart/related content.
Key STOW-RS Endpoints:
POST /studies- Store DICOM instancesPOST /studies/{studyUID}- Store instances to a specific study
Example: STOW-RS Store in Java
package com.saravanansubramanian.dicom.pixelmedtutorial;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.util.UUID;
/**
* DICOM STOW-RS Store Demo
*/
public class StowRsStoreDemo {
private static final String DICOMWEB_BASE_URL = "http://localhost:8042/dicom-web";
public static void main(String[] args) {
try {
System.out.println("=== DICOM STOW-RS Store Demo ===\n");
String dicomFilePath = "C:\\path\\to\\sample.dcm";
storeDicomFile(dicomFilePath);
System.out.println("\n=== STOW-RS Demo Complete ===");
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
/**
* Store a DICOM file using STOW-RS
*/
private static void storeDicomFile(String filePath) {
try {
File file = new File(filePath);
if (!file.exists()) {
System.out.println("File not found: " + filePath);
return;
}
String boundary = "----DicomBoundary" + UUID.randomUUID().toString();
String url = DICOMWEB_BASE_URL + "/studies";
System.out.println("Storing file: " + filePath);
System.out.println("URL: " + url);
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type",
"multipart/related; type=\"application/dicom\"; boundary=" + boundary);
conn.setRequestProperty("Accept", "application/dicom+json");
byte[] fileContent = Files.readAllBytes(file.toPath());
try (OutputStream out = conn.getOutputStream()) {
// Write multipart boundary and headers
out.write(("--" + boundary + "\r\n").getBytes());
out.write("Content-Type: application/dicom\r\n\r\n".getBytes());
// Write DICOM file content
out.write(fileContent);
// Write closing boundary
out.write(("\r\n--" + boundary + "--\r\n").getBytes());
}
int responseCode = conn.getResponseCode();
System.out.println("Response Code: " + responseCode);
if (responseCode == 200 || responseCode == 202) {
System.out.println("File stored successfully!");
} else {
System.out.println("Error: " + conn.getResponseMessage());
}
conn.disconnect();
} catch (Exception e) {
System.out.println("Error storing file: " + e.getMessage());
}
}
}
DICOMweb Response Format
DICOMweb typically returns data in JSON format (application/dicom+json). The JSON structure uses DICOM tag numbers as keys with value representations:
[
{
"00100010": {
"vr": "PN",
"Value": [
{
"Alphabetic": "DOE^JOHN"
}
]
},
"00100020": {
"vr": "LO",
"Value": ["12345"]
},
"0020000D": {
"vr": "UI",
"Value": ["1.2.3.4.5.6.7.8.9"]
}
}
]
Setting Up Orthanc with DICOMweb
To use DICOMweb with Orthanc, you need to enable the DICOMweb plugin in your Orthanc configuration:
{
"Plugins": ["DICOMweb"],
"DicomWeb": {
"Enable": true,
"Root": "/dicom-web/",
"EnableWado": true,
"WadoRoot": "/wado",
"Ssl": false
}
}
Conclusion
DICOMweb provides a modern, web-friendly approach to working with DICOM data. Its RESTful architecture makes it easier to build web applications, mobile apps, and cloud-based medical imaging solutions. The three core services (QIDO-RS, WADO-RS, and STOW-RS) provide complete query, retrieve, and store capabilities over HTTP. This concludes the DICOM Java programming series. I hope you have found these tutorials helpful in understanding the many aspects of the DICOM standard and how to implement them using Java. For more information about DICOM, please visit my series of articles on the DICOM standard.