The PHP Controller:
<?php
class OrthancDevController extends Controller
{
/**
* Construct this object by extending the basic Controller class
*/
// For API calls to AMBRA, filter out my access level inidividual calls later.
private $Orthanc;
private $postuuid;
private $withtags;
private $tagcodes;
private $display_results;
public function __construct()
{
parent::__construct();
Auth::checkAuthentication([7,8]);
if ($_SERVER['REQUEST_METHOD'] == "POST") {
$this->Orthanc = new OrthancModel;
$this->postuuid = $_POST["uuid"];
$this->withtags = $_POST["withtags"];
$this->tagcodes = $_POST["tagcodes"]; // can also be an array of code content/0008-1250/0/0040-a170/0/0008-0104
}
else {
$this->Orthanc = new OrthancModel;
}
// check the $_POST
}
public function readers() {
// [uuid] => 0dfe0cd8-09750032-c51e0164-4514808d-b3758b72
// [patient_name] => SCOTTI^STEPHEN^D
// [patientid] => 1001915751
// [patient_sex] => M
// [birth_date] => 19571116
// [accession_number] => A15382757
// [referring_physican] => STROTHMAN^DAVID^HOWARD
// [study_description] => MR SPINE LUMBAR WO
// [institution] => ABBOTT NORTHWESTERN HOSPITAL
// [study_date] => 20181130
// [study_time] => 123600.181
// [cpt_no_mods] => 72148.0
// [instanceUID] => 1.2.826.0.1.3680043.2.133.1.3.1.36.26.99500
$_SESSION['view'] = "orthanc_reader";
$allstudies = $this->getStudies(true);
$this->View->render('readers/orthanc_index', array ("studies" => $allstudies, "omitold" => true));
}
public function renderiFrame ($src) {
}
public function apitool()
{
$this->View->render('apitool/orthancRESTtool');
}
// These all send null for the entire list or a uuid for just one.
function getPatients () { // gets all or just a specific UUID.
// var_dump($this->Orthanc->getPatients($this->postuuid));
print_r($this->Orthanc->getPatients($this->postuuid));
//var_dump($this->Orthanc->getPatients($this->postuuid));
}
function getStudies($return = false) { // // gets all or just a specific UUID.
if (!empty($this->postuuid)) {
if($return) return $this->Orthanc->getStudyDetails($this->postuuid);
else echo print_r($this->Orthanc->getStudyDetails($this->postuuid));
}
else {
if($return) return $this->Orthanc->getStudies();
else echo print_r($this->Orthanc->getStudies());
}
// $data['studies'] = $studydetails;
// (new View)->renderWithoutHeaderAndFooter('studies/worklisttable', $data );
}
function getSeries() { // gets a specific UUID
print_r( $this->Orthanc->getSeries($this->postuuid));
}
// this also has a $withtags option that can be simplified-tags or tag, for later
function getInstances() { // gets a specific UUID
print_r($this->Orthanc->getInstances($this->postuuid, "simplified-tags"));
}
function getDICOMTagValueforUUID() { // return empty mrn if no matches, otherwise returns 1 result. increment the suffix and return the result
echo print_r((array)$this->Orthanc->getDICOMTagValueforUUID($this->postuuid, $this->tagcodes), true);
}
function getInstanceDICOM() { // return empty mrn if no matches, otherwise returns 1 result. increment the suffix and return the result
echo print_r((array)$this->Orthanc->getInstanceDICOM($this->postuuid), true);
}
function getInstancePNGPreview() { // return empty mrn if no matches, otherwise returns 1 result. increment the suffix and return the result
$image_data_base64 = base64_encode ($this->Orthanc->getInstancePNGPreview($this->postuuid, "image/png" )); // also image/jpeg
echo '<img src="data:image/png;base64,' . $image_data_base64 . 'alt="img"/ >';
}
function downloadZipStudyUUID() {
// disposition is inline for new window, attachment for download
header('Content-disposition:' . 'attachment; filename=download.zip');
header('Content-type: application/zip');
echo $this->Orthanc->downloadZipStudyUUID($this->postuuid);
}
function downloadDCMStudyUUID() {
header('Content-disposition:' . 'attachment; filename=download.zip');
header('Content-type: application/zip');
echo $this->Orthanc->downloadZipStudyUUID($this->postuuid);
}
function performQuery() {
$result = $this->Orthanc->performQuery("Study", '{"PatientID":"*","StudyDescription":"*","PatientName":"*"}');
print_r(json_decode($result));
}
function openViewerWithStudyUUID() {
echo '<iframe style="height:1300px;width:100%;" src="http://localhost:8042/osimis-viewer/app/index.html?study=' . $this->postuuid . '"></iframe>';
}
function openOrthancViewer() {
echo '<iframe style="height:1300px;width:100%;" src="http://localhost:8042/"></iframe>';
}
}
?>
The Model:
<?php
Class OrthancModel {
private $OrthancURL;
private $lastQueryID;
private $lastQueryPath;
private $mapFromOrthanc;
public $result;
public function __construct($data = null) {
$this->OrthancURL = "http://localhost:8042/";
$this->mapFromOrthanc = array(
"ID" => "uuid",
"PatientID" => "patientid",
"PatientBirthDate" => "birth_date",
"PatientName" => "hipaa_name",
"PatientSex" => "patient_sex",
"AccessionNumber" => "accession_number",
"ReferringPhysicianName" => "referring_physican",
"InstitutionName" => "institution",
"StudyDate" => "study_date",
"StudyTime" => "study_time",
"study_description" => "accession_number",
"StudyID" => "cpt_no_mods", // ? CPT or other.
"StudyInstanceUID" => "study_uid"
);
}
public function executeCURL($CURLOPT_URL) {
// Generated by curl-to-PHP: http://incarnate.github.io/curl-to-php/
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->OrthancURL . $CURLOPT_URL);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$this->result = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
curl_close($ch);
}
public function executeCURLWithHeaders($CURLOPT_URL, $headerfield = "") {
// Generated by curl-to-PHP: http://incarnate.github.io/curl-to-php/
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->OrthancURL . $CURLOPT_URL);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
$headers = array();
$headers[] = 'Accept: ' . $headerfield;
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$this->result = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
curl_close($ch);
}
public function executeCURLQuery($object, $JSONQuery) {
// * is a wildcard in a search
// Dates are Ymd format, - is used for range, after or before.
// Generated by curl-to-PHP: http://incarnate.github.io/curl-to-php/
// "ID": "5af318ac-78fb-47ff-b0b0-0df18b0588e0", The ID can be used for subsequent queries
// "Path": "/queries/5af318ac-78fb-47ff-b0b0-0df18b0588e0"
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->OrthancURL . '/tools/find');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{"Level":"' . $object . '","Query":' . $JSONQuery . '}');
// {"PatientID":"","StudyDescription":"*Chest*","PatientName":""}
$headers = array();
$headers[] = 'Content-Type: application/x-www-form-urlencoded';
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$this->result = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
curl_close($ch);
// $this->lastQueryID = $result->ID;
// $this->lastQueryPath = $result->Path;
}
public function getPatients($uuid = "") {
$this->executeCURL("patients/" . $uuid);
return json_decode($this->result);
}
public function getStudies() { // same as constructor for subsequent calls.
$this->executeCURL("studies/");
$uuidlist = json_decode($this->result);
//print_r($uuidlist);
$studydetails = array();
foreach ($uuidlist as $uuid) {
$studydetails[] = $this->getStudyDetails($uuid);
}
return $studydetails;
}
public function getStudyDetails ($uuid) {
$this->executeCURL("studies/" . $uuid);
$raw = json_decode($this->result);
$patientdata = $raw->PatientMainDicomTags;
$maindicom = $raw->MainDicomTags;
$details = new \stdClass();
$details->uuid = $raw->ID;
$details->patient_name = $patientdata->PatientName;
$details->patientid = $patientdata->PatientID;
$details->patient_sex = $patientdata->PatientSex;
$details->birth_date = $patientdata->PatientBirthDate;
$details->accession_number = $maindicom->AccessionNumber;
$details->referring_physican = $maindicom->ReferringPhysicianName;
$details->study_description = $maindicom->StudyDescription;
$details->institution = $maindicom->InstitutionName;
$details->study_date = $maindicom->StudyDate;
$details->study_time = $maindicom->StudyTime;
$details->cpt_no_mods = $maindicom->StudyID;
$details->instanceUID = $maindicom->StudyInstanceUID;
return (array)$details;
}
public function getSeries($uuid = false) { // same as constructor for subsequent calls.
$this->executeCURL("series/" . $uuid);
return json_decode($this->result);
}
public function getInstances($uuid = false, $withtags = false) {
$withtags = ($withtags?"/tags":""); // detailed info
$this->executeCURL("instances/" . $uuid . $withtags);
return json_decode($this->result);
}
public function getDICOMTagValueforUUID ($uuid, $tagcodes) {
// can be a single value or an $array in which case it goes down the hierarchy.
if (is_array($tagcodes)) $tagcodes = implode("/", $tagcodes);
$this->executeCURL("instances/" . $uuid . '/content/' . $tagcodes);
return $this->result;
}
public function getDICOMTagListforUUID($uuid) {
$this->executeCURL("instances/" . $uuid . '/content');
return $this->result;
}
public function getInstanceDICOM($uuid) {
$this->executeCURL("instances/" . $uuid . '/file');
return $this->result;
}
public function getInstancePNGPreview ($uuid, $pngjpg) {
$this->executeCURLWithHeaders("instances/" . $uuid . '/preview/', $pngjpg);
return $this->result;
}
public function downloadZipStudyUUID ($uuid) {
$this->executeCURL("studies/" . $uuid . '/archive');
return $this->result;
}
public function downloadDCMStudyUUID ($uuid) {
$this->executeCURL("studies/" . $uuid . '/media');
return $this->result;
}
public function performQuery ($object, $JSONQuery) {
//{"Level":"Study","Query": {"PatientID":"","StudyDescription":"*Chest*","PatientName":""}}
$this->executeCURLQuery($object, $JSONQuery);
return $this->result;
}
/*
All instances of a study can be retrieved as a zip file as follows:
$ curl http://localhost:8042/studies/6b9e19d9-62094390-5f9ddb01-4a191ae7-9766b715/archive > Study.zip
It is also possible to download a zipped DICOMDIR through:
$ curl http://localhost:8042/studies/6b9e19d9-62094390-5f9ddb01-4a191ae7-9766b715/media > Study.zip
*/
}
?>
There is a view for listing the studies with a number of links for viewing .zip file download, reports, etc that integrates many of the API calls into a single view.