This commit is contained in:
2025-02-26 14:49:25 +07:00
commit 1c1d9c4474
6403 changed files with 1953774 additions and 0 deletions

395
nv/html/ApiPacs.php Normal file
View File

@@ -0,0 +1,395 @@
<?php
/*
* Use Case: Untuk API antara BISONE dengan DCM4CHE PACS Server
* Location: PACS Server /data/docker/nv/html/ApiPacs.php
* Input: JSON
* Proses: HL7 ke DCM4CHE
* Return: JSON
* Version: 1.0
* Date: 2024-12-13
*/
header('Content-Type: application/json');
// Entry point
require_once 'ApiPacs.php';
// Create an instance and route the request
$apiPacs = new ApiPacs();
$apiPacs->route();
class ApiPacs
{
private $dcmHost = '128.199.154.150';
private $dcmPort = 2575;
public function route()
{
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$action = basename($path);
if (method_exists($this, $action)) {
$this->$action();
} else {
http_response_code(404);
$this->sys_error("Endpoint not found");
}
}
public function sendOrder()
{
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
$json = file_get_contents('php://input');
$payload = json_decode($json, true);
if (!$payload) {
http_response_code(400);
$this->sys_error("Invalid JSON");
exit;
}
$hl7json = $this->mapToXml($payload, "XO"); // XO = Send Order
$hl7Message = $this->mapToHL7($hl7json);
$result = $this->sendHL7($hl7Message, $this->dcmHost, $this->dcmPort);
$this->sys_ok([
'accession_no' => $payload['accession_no'],
'study_instance_uid' => $payload['study_instance_uid'],
'hl7_response' => $result,
], "Successfully sent order");
} catch (\Exception $e) {
$this->sys_error($e->getMessage());
exit;
}
} else {
http_response_code(405);
$this->sys_error("Method not allowed");
exit;
}
}
public function cancelOrder()
{
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
try {
// Get the raw POST data
$json = file_get_contents('php://input');
$payload = json_decode($json, true);
if (!$payload) {
http_response_code(400);
$this->sys_error("Invalid JSON");
exit;
}
$hl7json = $this->mapToXml($payload, "CA"); // CA = Cancel Order
$hl7Message = $this->mapToHL7($hl7json);
$result = $this->sendHL7($hl7Message, $this->dcmHost, $this->dcmPort);
$this->sys_ok([
'accession_no' => $payload['accession_no'],
'study_instance_uid' => $payload['study_instance_uid'],
'hl7_response' => $result,
], "Successfully canceled order");
} catch (\Exception $e) {
$this->sys_error($e->getMessage());
exit;
}
} else {
http_response_code(405);
$this->sys_error("Method not allowed");
exit;
}
}
private function mapToXml($payload, $act)
{
// Extract variables from JSON payload
$DepartemenID = isset($payload['departemen_id']) ? $payload['departemen_id'] : "";
$message_seq_id = "2006 - 1010";
$patient_mrn = isset($payload['patient_mrn']) ? $payload['patient_mrn'] : "";
$patient_nm = isset($payload['patient_nm']) ? $payload['patient_nm'] : "";
$patient_birth_dt = isset($payload['patient_birth_dt']) ? $payload['patient_birth_dt'] : "";
$patient_gender = isset($payload['patient_gender']) ? $payload['patient_gender'] : "";
$referring_physician_id = isset($payload['referring_physician_id']) ? $payload['referring_physician_id'] : "";
$referring_physician_nm = isset($payload['referring_physician_nm']) ? $payload['referring_physician_nm'] : "";
$admission_dttm = isset($payload['admission_dttm']) ? $payload['admission_dttm'] : "";
$admission_id = isset($payload['admission_id']) ? $payload['admission_id'] : "";
$ordering_physician_id = isset($payload['ordering_physician_id']) ? $payload['ordering_physician_id'] : "";
$ordering_physician_nm = isset($payload['ordering_physician_nm']) ? $payload['ordering_physician_nm'] : "";
$NamaDepartemen = isset($payload['nama_departemen']) ? $payload['nama_departemen'] : "";
$placer_order_id = isset($payload['placer_order_id']) ? $payload['placer_order_id'] : "";
$filler_order_id = isset($payload['filler_order_id']) ? $payload['filler_order_id'] : "";
$procedure_cd = isset($payload['procedure_cd']) ? $payload['procedure_cd'] : "";
$procedure_nm = isset($payload['procedure_nm']) ? $payload['procedure_nm'] : "";
$order_dttm = isset($payload['order_dttm']) ? $payload['order_dttm'] : "";
$accession_no = isset($payload['accession_no']) ? $payload['accession_no'] : "";
$requested_proc_id = isset($payload['requested_proc_id']) ? $payload['requested_proc_id'] : "";
$scheduled_proc_step_id = isset($payload['scheduled_proc_step_id']) ? $payload['scheduled_proc_step_id'] : "";
$modality_cd = isset($payload['modality_cd']) ? $payload['modality_cd'] : "";
$study_instance_uid = isset($payload['study_instance_uid']) ? $payload['study_instance_uid'] : "";
$scheduled_station_ae = isset($payload['scheduled_station_ae']) ? $payload['scheduled_station_ae'] : "";
$scheduled_station_name = isset($payload['scheduled_station_name']) ? $payload['scheduled_station_name'] : "";
$trxLayananID = isset($payload['trx_layanan_id']) ? $payload['trx_layanan_id'] : "";
$hl7json = [
"MSH" => [
"MSH.3.1" => "HIMS", // Sending Application ID
"MSH.4.1" => $DepartemenID, // Sending Facility ID
"MSH.5.1" => "ABPACS", // Receiving Application ID
"MSH.6.1" => "RAD", // Receiving Facility ID
"MSH.7.1" => $this->getCurrentDate("YmdHis"),
"MSH.10" => $message_seq_id, /// Messeage Sequence ID
],
"PID" => [
"PID.3.1" => $patient_mrn,
"PID.5.1" => $patient_nm,
"PID.7.1" => date("Ymd", strtotime($patient_birth_dt)),
"PID.8.1" => $patient_gender,
"PID.10.1" => "2038-8",
"PID.11.1" => "", // Street Address
"PID.11.2" => "", // Other Designation
"PID.11.3" => "", // City
"PID.11.4" => "", // State or Province
"PID.11.5" => "", // Zip Code
"PID.13.1" => "", // Phone Number
"PID.18.1" => "", // Patient Account Number
],
"PV1" => [
"PV1.8.1" => $referring_physician_id,
"PV1.8.2" => $referring_physician_nm,
"PV1.44.1" => date("YmdHis", strtotime($admission_dttm)),
"PV1.19.1" => $admission_id, // (0038,0010) Admission ID / RegID
"PV1.19.4" => "RSAB", // (0038,0011) Issuer of Admission ID
],
"ORC" => [
"ORC.1.1" => $act, // Action Code
"ORC.2.1" => $placer_order_id, // Placer Order Number
"ORC.2.2" => "HIMS", // Placer Order Application Name
"ORC.3.1" => $filler_order_id, // Filler Order Number
"ORC.3.2" => "", // Filler Order Application Name
"ORC.10.1" => "", // User ID created
"ORC.10.2" => "", // User last name who created
"ORC.10.3" => "", // User first name who created
"ORC.12.1" => $ordering_physician_id, // Ordering physician ID
"ORC.12.2" => $ordering_physician_nm, // Ordering physician name
"ORC.12.3" => "", // Given name
"ORC.12.4" => "", // Middle initial
"ORC.12.5" => "", // Suffix
"ORC.12.6" => "", // Prefix
"ORC.13.1" => $NamaDepartemen, // Enterer's point of care
"ORC.14.1" => "", // Call back phone number
"ORC.15.1" => "", // Order effective datetime
"ORC.21.1" => $NamaDepartemen, // Enterer's location
],
"OBR" => [
"OBR.2.1" => $placer_order_id, // Placer Order Number
"OBR.2.2" => "HIMS", // Placer Order Number Namespace ID
"OBR.3.1" => $filler_order_id, // Filler Order Number
"OBR.3.2" => "", // Filler Order Number Namespace ID
"OBR.4.1" => $procedure_cd, // Service ID
"OBR.4.2" => $procedure_nm, // Service Name
"OBR.4.3" => "RSABPRC", // Coding for Service Identifier
"OBR.4.4" => $procedure_cd, // Alternate Service ID
"OBR.4.5" => $procedure_nm, // Alternate Service Name
"OBR.4.6" => "L", // Name of Alternate Coding System
"OBR.6.1" => date("YmdHis", strtotime($order_dttm)), // Order Request Datetime
"OBR.16.1" => $ordering_physician_id, // Ordering physician ID
"OBR.16.2" => $ordering_physician_nm, // Ordering physician name
"OBR.18.1" => $accession_no, // Accession Number
"OBR.19.1" => $trxLayananID, // Requested Procedure ID
"OBR.20.1" => $scheduled_proc_step_id, // Scheduled Procedure Step ID
"OBR.24.1" => $modality_cd, // Modality Code
"OBR.44.1" => $procedure_cd, // Procedure Code
"OBR.44.2" => $procedure_nm, // Study Description
"OBR.44.3" => "RSAB-PCS", // Procedure Coding System
],
"ZDS" => [
"ZDS.1.1" => $study_instance_uid, // (0020,000D) Study Instance UID
"ZDS.2.1" => $scheduled_station_ae, // (0040,0001) Scheduled Station AE Title
"ZDS.3.1" => $scheduled_station_name, /// (0040,0010) Scheduled Station Name
],
"TQ1" => [
"TQ1.7.1" => date("YmdHis", strtotime($order_dttm)),
"TQ1.9.1" => "S", // Priority S = Stat, A = ASAP
"TQ1.12.1" => "C", // C = Time is Actuation Time
],
];
return $hl7json;
}
private function mapToHL7($hl7json)
{
$segments = [];
// MSH Segment
$segments[] = "MSH|^~\\&|" .
$hl7json["MSH"]["MSH.3.1"] . "|" .
$hl7json["MSH"]["MSH.4.1"] . "|" .
$hl7json["MSH"]["MSH.5.1"] . "|" .
$hl7json["MSH"]["MSH.6.1"] . "|" .
$hl7json["MSH"]["MSH.7.1"] . "||" .
"ORM^O01|" .
$hl7json["MSH"]["MSH.10"] . "|P|2.3.1";
// PID Segment
$segments[] = "PID|||" .
$hl7json["PID"]["PID.3.1"] . "^^^ADT1||" .
$hl7json["PID"]["PID.5.1"] . "||" .
$hl7json["PID"]["PID.7.1"] . "|" .
$hl7json["PID"]["PID.8.1"] . "||" .
$hl7json["PID"]["PID.10.1"] . "|" .
implode("^", [
$hl7json["PID"]["PID.11.1"],
$hl7json["PID"]["PID.11.2"],
$hl7json["PID"]["PID.11.3"],
$hl7json["PID"]["PID.11.4"],
$hl7json["PID"]["PID.11.5"]
]) . "|" .
$hl7json["PID"]["PID.13.1"] . "|" .
$hl7json["PID"]["PID.18.1"];
// PV1 Segment
$segments[] = "PV1||O||||||" .
$hl7json["PV1"]["PV1.8.1"] . "^" .
$hl7json["PV1"]["PV1.8.2"] . "|||||||||||" .
$hl7json["PV1"]["PV1.19.1"] . "^^^" .
$hl7json["PV1"]["PV1.19.4"] . "||||||||" .
$hl7json["PV1"]["PV1.44.1"];
// ORC Segment
$segments[] = "ORC|" . $hl7json["ORC"]["ORC.1.1"] . "|" .
$hl7json["ORC"]["ORC.2.1"] . "^" . $hl7json["ORC"]["ORC.2.2"] . "|" .
$hl7json["ORC"]["ORC.3.1"] . "^" . $hl7json["ORC"]["ORC.3.2"] . "||||||||" .
$hl7json["ORC"]["ORC.10.1"] . "^" .
$hl7json["ORC"]["ORC.10.2"] . "^" .
$hl7json["ORC"]["ORC.10.3"] . "|||" .
$hl7json["ORC"]["ORC.12.1"] . "^" .
$hl7json["ORC"]["ORC.12.2"] . "^" .
$hl7json["ORC"]["ORC.12.3"] . "^" .
$hl7json["ORC"]["ORC.12.4"] . "^" .
$hl7json["ORC"]["ORC.12.5"] . "^" .
$hl7json["ORC"]["ORC.12.6"] . "|" .
$hl7json["ORC"]["ORC.13.1"];
// OBR Segment
$segments[] = "OBR|1|" .
$hl7json["OBR"]["OBR.2.1"] . "^" . $hl7json["OBR"]["OBR.2.2"] . "|" .
$hl7json["OBR"]["OBR.3.1"] . "^" . $hl7json["OBR"]["OBR.3.2"] . "|" .
$hl7json["OBR"]["OBR.4.1"] . "^" .
$hl7json["OBR"]["OBR.4.2"] . "^" .
$hl7json["OBR"]["OBR.4.3"] . "^" .
$hl7json["OBR"]["OBR.4.4"] . "^" .
$hl7json["OBR"]["OBR.4.5"] . "^" .
$hl7json["OBR"]["OBR.4.6"] . "||" .
$hl7json["OBR"]["OBR.6.1"] . "||||||||" .
$hl7json["OBR"]["OBR.16.1"] . "^" .
$hl7json["OBR"]["OBR.16.2"] . "||||" .
$hl7json["OBR"]["OBR.18.1"] . "|" .
$hl7json["OBR"]["OBR.19.1"] . "|" .
$hl7json["OBR"]["OBR.20.1"] . "|||||||||" .
$hl7json["OBR"]["OBR.24.1"] . "|||||||" .
$hl7json["OBR"]["OBR.44.1"] . "^" .
$hl7json["OBR"]["OBR.44.2"] . "^" .
$hl7json["OBR"]["OBR.44.3"];
// ZDS Segment
$segments[] = "ZDS|" .
$hl7json["ZDS"]["ZDS.1.1"] . "^100^Application^DICOM|" .
$hl7json["ZDS"]["ZDS.2.1"] . "|" .
$hl7json["ZDS"]["ZDS.3.1"];
// TQ1 Segment
$segments[] = "TQ1|||||||" .
$hl7json["TQ1"]["TQ1.7.1"] . "||" .
$hl7json["TQ1"]["TQ1.9.1"] . "|||" .
$hl7json["TQ1"]["TQ1.12.1"];
// Join all segments with newline
return implode("\n", $segments);
}
private function sendHL7($hl7Message, $host, $port)
{
// MLLP delimiters
define('MLLP_START', "\x0b"); // <VT>
define('MLLP_END', "\x1c\x0d"); // <FS><CR>
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($socket === false) {
$this->sys_error("Socket creation failed: " . socket_strerror(socket_last_error()));
exit;
}
$result = socket_connect($socket, $host, $port);
if ($result === false) {
$this->sys_error("Connection failed: " . socket_strerror(socket_last_error()));
exit;
}
// Wrap message in MLLP container
$mlllpMessage = MLLP_START . $hl7Message . MLLP_END;
// Send message
$sentBytes = socket_write($socket, $mlllpMessage, strlen($mlllpMessage));
if ($sentBytes === false) {
$this->sys_error("Send failed: " . socket_strerror(socket_last_error()));
exit;
}
$response = '';
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, ["sec" => 5, "usec" => 0]); // Set timeout
while (($buf = socket_read($socket, 1024))) {
$response .= $buf;
if (strpos($response, MLLP_END)) {
break;
}
}
$returned = '';
if (strpos($response, "MSA|AA") !== false) {
$returned = "Application Accepted"; // Acknowledgment Accepted
} elseif (strpos($response, "MSA|AR") !== false) {
$returned = "Application Rejected"; // Acknowledgment Rejected
} elseif (strpos($response, "MSA|AE") !== false) {
$returned = "Application Error"; // Application Error
} else {
$returned = "Unknown Response"; // In case none of the expected segments are found
}
return $returned;
}
public function getCurrentDate($format)
{
return date($format);
}
public function sys_ok($data, $message = "")
{
$result = array(
'status' => 'OK',
'message' => $message,
'data' => $data
);
echo json_encode($result);
}
public function sys_error($message)
{
$result = array(
'status' => 'ERROR',
'message' => $message,
'data' => ''
);
echo json_encode($result);
}
}

56
nv/html/Step Normal file
View File

@@ -0,0 +1,56 @@
1. Mapping masterlayanan dengan modality code.
Daftar code ada di table: modalitycodes
2. Create table pacs_order_mwl, pacs_result_series
CREATE TABLE `pacs_order_mwl` (
`AccessionNumber` char(15) NOT NULL DEFAULT '',
`MEDRECID` char(50) NOT NULL DEFAULT '',
`RegID` char(20) NOT NULL DEFAULT '',
`TrxLayananID` bigint(20) unsigned NOT NULL DEFAULT '0',
`TrxDepartemenID` bigint(20) NOT NULL DEFAULT '0',
`StudyIUID` char(100) NOT NULL DEFAULT '',
`ScheduledProcStepID` char(20) NOT NULL DEFAULT '',
`CreatedDateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`NA` enum('N','Y') NOT NULL DEFAULT 'N',
PRIMARY KEY (`AccessionNumber`,`TrxLayananID`),
KEY `x_medrec` (`MEDRECID`),
KEY `x_regid` (`RegID`),
KEY `x_trx` (`TrxLayananID`),
KEY `x_dttm` (`CreatedDateTime`),
KEY `x_na` (`NA`),
KEY `TrxDepartemenID` (`TrxDepartemenID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE `pacs_result_series` (
`AccessionNumber` char(15) NOT NULL DEFAULT '',
`MEDRECID` char(50) NOT NULL DEFAULT '',
`RegID` char(20) NOT NULL DEFAULT '',
`TrxLayananID` bigint(20) unsigned NOT NULL DEFAULT '0',
`TrxDepartemenID` bigint(20) NOT NULL DEFAULT '0',
`StudyIUID` char(100) NOT NULL DEFAULT '',
`StudyDescription` char(200) NOT NULL DEFAULT '',
`StudyDatetime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`SeriesIUID` char(100) NOT NULL DEFAULT '',
`SeriesNumber` int(10) unsigned NOT NULL DEFAULT '0',
`SeriesDescription` char(200) NOT NULL DEFAULT '',
`NumberOfInstance` int(10) unsigned NOT NULL DEFAULT '0',
`SOPIUID` char(100) NOT NULL DEFAULT '',
`CreatedDateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`Published` enum('N','Y') NOT NULL DEFAULT 'N',
`PublisheDateTime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`NA` enum('N','Y') NOT NULL DEFAULT 'N',
PRIMARY KEY (`AccessionNumber`,`SeriesIUID`),
UNIQUE KEY `x_uk` (`StudyIUID`,`SeriesIUID`),
KEY `x_acs` (`AccessionNumber`),
KEY `x_medrec` (`MEDRECID`),
KEY `x_regid` (`RegID`),
KEY `x_trx` (`TrxLayananID`),
KEY `x_sdttm` (`StudyDatetime`),
KEY `x_dttm` (`CreatedDateTime`),
KEY `x_na` (`NA`),
KEY `x_pub` (`Published`),
KEY `TrxDepartemenID` (`TrxDepartemenID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

225
nv/html/adminer/adminer.css Normal file
View File

@@ -0,0 +1,225 @@
* {
font: 13px/1.5 Verdana, 'Geneva CE', lucida, sans-serif;
color:#333333;
margin:0px;
padding:0px;
}
a,a:visited {
color:#006aeb;
text-decoration:none;
padding:3px 1px;
}
#content table thead span, #content table thead a {
font-weight:bold;
color:black;
}
#content table thead a:hover {
background:none;
text-decoration:underline;
color:black;
}
a:hover {
color:white;
background:#006aeb;
}
h1 {
font-size:1.9em;
font-weight:normal;
background:white;
color:#1e5eb6;
border-bottom:1px solid #f4f4f4;
padding:20px;
margin:0px;
}
#menu h1 {
padding:0px 0px 5px 20px;
background:none;
}
h2,h3 {
font-size:1.5em;
font-weight:normal;
background:white;
color:#1e5eb6;
border-bottom:1px solid #f4f4f4;
padding:20px 0px;
margin:0px;
}
fieldset {
padding:5px;
border:1px solid #f4f4f4;
}
input,select,textarea {
border:1px solid #e5e5e5;
margin:1px;
padding:3px;
}
input[type=submit] {
color:white;
background:#3390e6;
padding:3px 10px;
cursor:pointer;
border:0px solid;
}
input[type=submit]:hover{
background:blue;
}
input[type=checkbox]{
margin-right:5px;
}
input[type=image] {
border:1px solid #d0cdc4;
}
input[type=checkbox],input[type=radio]{
border:1px solid #e5e5e5;
padding:2px 5px;
}
code{
background:#f0ffe1;
border:1px dashed #d5f1b9;
padding:2px 4px;
font-family:"Courier New";
}
code a:hover{background:transparent}
table{
margin:10px 0px;
border:1px solid #d0cdc4;
border-collapse:collapse;
}
tbody tr:hover td,tbody tr:hover th{
background:#edf4ff
}
thead th, thead td {
text-align:center;
vertical-align:middle;
font-weight:bold;
white-space:nowrap;
background:#f2eee1;
color:#808080;
}
th,td{
border:1px solid #d0cdc4;
padding:3px 6px;
vertical-align:top;
}
th a {
font-weight:bold;
padding-bottom:0px;
}
th {
background:white;
}
tr.odd td {
background:#fcfaf5;
}
#content tbody tr.checked td, tr.checked.odd td {
background:#fbe2e2;
color:red;
}
.hidden{
display:none
}
.error,.message{
padding:0px;
background:transparent;
font-weight:bold
}
.error{
color:#c00
}
.message{
color:#090
}
#content{
margin:0px 0px 0px 320px;
padding:50px 20px 40px 0px;
height:100%;
}
#lang {
background:#f2eee1;
color:#808080;
position:fixed;
top:0px;
left:0px;
width:100%;
padding:10px 20px;
z-index:1;
}
#breadcrumb {
position:fixed;
top:0px;
left:300px;
background:#f2eee1;
z-index:2;
width:100%;
padding:10px;
}
#menu {
background:#fcfaf5;
position:fixed;
top:-10px;
padding:20px;
padding-top:40px;
bottom:0px;
overflow:auto;
left:0px;
width:240px;
border-right:5px solid #f2eee1;
}
#schema .table {
padding:5px;
background:#fcfaf5;
border:1px solid #d0cdc4;
}
#schema .table b {
color:#006aeb;
font-weight:bold;
text-decoration:underline;
}
#schema .table b:hover {
color:white;
}
input[name=logout] {
color:#fce2e2;
background:#d73e3e;
}
input[name=logout]:hover {
background:#ea0202;
}

1833
nv/html/adminer/adminer.php Normal file

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,32 @@
<?php
/** Select foreign key in edit form
* @link http://www.adminer.org/plugins/#use
* @author Jakub Vrana, http://www.vrana.cz/
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
*/
class AdminerEditForeign {
function editInput($table, $field, $attrs, $value) {
static $foreignTables = array();
static $values = array();
$foreignKeys = &$foreignTables[$table];
if ($foreignKeys === null) {
$foreignKeys = column_foreign_keys($table);
}
foreach ((array) $foreignKeys[$field["field"]] as $foreignKey) {
if (count($foreignKey["source"]) == 1) {
$target = $foreignKey["table"];
$id = $foreignKey["target"][0];
$options = &$values[$target][$id];
if (!$options) {
$options = array("" => "") + get_vals("SELECT " . idf_escape($id) . " FROM " . table($target) . " ORDER BY 1");
}
return "<select$attrs>" . optionlist($options, $value) . "</select>";
}
}
}
}

View File

@@ -0,0 +1,15 @@
nk http://www.adminer.org/plugins/#use
* @author Jakub Vrana, http://www.vrana.cz/
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
*/
class AdminerEditTextarea {
function editInput($table, $field, $attrs, $value) {
if (ereg('char', $field["type"])) {
return "<textarea cols='30' rows='1' style='height: 1.2em;'$attrs>" . h($value) . '</textarea>';
}
}
}

31
nv/html/adminer/index.php Normal file
View File

@@ -0,0 +1,31 @@
<?php
if(false) {
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
}
function adminer_object() {
// required to run any plugin
include_once "./plugins/plugin.php";
// autoloader
foreach (glob("plugins/*.php") as $filename) {
include_once "./$filename";
}
$plugins = array(
new AdminerTablesFilter()
);
/* It is possible to combine customization and plugins:
class AdminerCustomization extends AdminerPlugin {
}
return new AdminerCustomization($plugins);
*/
return new AdminerPlugin($plugins);
}
// include original Adminer or Adminer Editor
//include "adminer.php";
include "adminer-4.7.5-en.php";
?>

342
nv/html/adminer/plugin.php Normal file
View File

@@ -0,0 +1,342 @@
nk http://www.adminer.org/plugins/#use
* @author Jakub Vrana, http://www.vrana.cz/
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
*/
class AdminerPlugin extends Adminer {
/** @access protected */
var $plugins;
function _findRootClass($class) { // is_subclass_of(string, string) is available since PHP 5.0.3
do {
$return = $class;
} while ($class = get_parent_class($class));
return $return;
}
/** Register plugins
* @param array object instances or null to register all classes starting by 'Adminer'
*/
function AdminerPlugin($plugins) {
if ($plugins === null) {
$plugins = array();
foreach (get_declared_classes() as $class) {
if (preg_match('~^Adminer.~i', $class) && strcasecmp($this->_findRootClass($class), 'Adminer')) { // can use interface since PHP 5
$plugins[$class] = new $class;
}
}
}
$this->plugins = $plugins;
// it is possible to use ReflectionObject in PHP 5 to find out which plugins defines which methods at once
}
function _callParent($function, $args) {
switch (count($args)) { // call_user_func_array(array('parent', $function), $args) works since PHP 5
case 0: return parent::$function();
case 1: return parent::$function($args[0]);
case 2: return parent::$function($args[0], $args[1]);
case 3: return parent::$function($args[0], $args[1], $args[2]);
case 4: return parent::$function($args[0], $args[1], $args[2], $args[3]);
case 5: return parent::$function($args[0], $args[1], $args[2], $args[3], $args[4]);
case 6: return parent::$function($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]);
default: trigger_error('Too many parameters.', E_USER_WARNING);
}
}
function _applyPlugin($function, $args) {
foreach ($this->plugins as $plugin) {
if (method_exists($plugin, $function)) {
switch (count($args)) { // call_user_func_array() doesn't work well with references
case 0: $return = $plugin->$function(); break;
case 1: $return = $plugin->$function($args[0]); break;
case 2: $return = $plugin->$function($args[0], $args[1]); break;
case 3: $return = $plugin->$function($args[0], $args[1], $args[2]); break;
case 4: $return = $plugin->$function($args[0], $args[1], $args[2], $args[3]); break;
case 5: $return = $plugin->$function($args[0], $args[1], $args[2], $args[3], $args[4]); break;
case 6: $return = $plugin->$function($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]); break;
default: trigger_error('Too many parameters.', E_USER_WARNING);
}
if ($return !== null) {
return $return;
}
}
}
return $this->_callParent($function, $args);
}
function _appendPlugin($function, $args) {
$return = $this->_callParent($function, $args);
foreach ($this->plugins as $plugin) {
if (method_exists($plugin, $function)) {
$return += call_user_func_array(array($plugin, $function), $args);
}
}
return $return;
}
// appendPlugin
function dumpFormat() {
$args = func_get_args();
return $this->_appendPlugin(__FUNCTION__, $args);
}
function dumpOutput() {
$args = func_get_args();
return $this->_appendPlugin(__FUNCTION__, $args);
}
function editFunctions() {
$args = func_get_args();
return $this->_appendPlugin(__FUNCTION__, $args);
}
// applyPlugin
function name() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function credentials() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function permanentLogin() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function database() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function databases() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function queryTimeout() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function headers() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function head() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function loginForm() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function login() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function tableName() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function fieldName() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectLinks() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function foreignKeys() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function backwardKeys() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function backwardKeysPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectQuery() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function rowDescription() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function rowDescriptions() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectLink() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectVal() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function editVal() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectColumnsPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectSearchPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectOrderPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectLimitPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectLengthPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectActionPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectCommandPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectImportPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectEmailPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectColumnsProcess() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectSearchProcess() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectOrderProcess() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectLimitProcess() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectLengthProcess() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectEmailProcess() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectQueryBuild() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function messageQuery() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function editInput() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function processInput() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function dumpTable() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function dumpData() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function dumpFilename() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function dumpHeaders() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function homepage() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function navigation() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function databasesPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function tablesPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
}

View File

@@ -0,0 +1,345 @@
<?php
/** Adminer customization allowing usage of plugins
* @link http://www.adminer.org/plugins/#use
* @author Jakub Vrana, http://www.vrana.cz/
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @license http://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
*/
class AdminerPlugin extends Adminer {
/** @access protected */
var $plugins;
function _findRootClass($class) { // is_subclass_of(string, string) is available since PHP 5.0.3
do {
$return = $class;
} while ($class = get_parent_class($class));
return $return;
}
/** Register plugins
* @param array object instances or null to register all classes starting by 'Adminer'
*/
function AdminerPlugin($plugins) {
if ($plugins === null) {
$plugins = array();
foreach (get_declared_classes() as $class) {
if (preg_match('~^Adminer.~i', $class) && strcasecmp($this->_findRootClass($class), 'Adminer')) { //! can use interface
$plugins[$class] = new $class;
}
}
}
$this->plugins = $plugins;
//! it is possible to use ReflectionObject to find out which plugins defines which methods at once
}
function _callParent($function, $args) {
return call_user_func_array(array('parent', $function), $args);
}
function _applyPlugin($function, $args) {
foreach ($this->plugins as $plugin) {
if (method_exists($plugin, $function)) {
switch (count($args)) { // call_user_func_array() doesn't work well with references
case 0: $return = $plugin->$function(); break;
case 1: $return = $plugin->$function($args[0]); break;
case 2: $return = $plugin->$function($args[0], $args[1]); break;
case 3: $return = $plugin->$function($args[0], $args[1], $args[2]); break;
case 4: $return = $plugin->$function($args[0], $args[1], $args[2], $args[3]); break;
case 5: $return = $plugin->$function($args[0], $args[1], $args[2], $args[3], $args[4]); break;
case 6: $return = $plugin->$function($args[0], $args[1], $args[2], $args[3], $args[4], $args[5]); break;
default: trigger_error('Too many parameters.', E_USER_WARNING);
}
if ($return !== null) {
return $return;
}
}
}
return $this->_callParent($function, $args);
}
function _appendPlugin($function, $args) {
$return = $this->_callParent($function, $args);
foreach ($this->plugins as $plugin) {
if (method_exists($plugin, $function)) {
$return += call_user_func_array(array($plugin, $function), $args);
}
}
return $return;
}
// appendPlugin
function dumpFormat() {
$args = func_get_args();
return $this->_appendPlugin(__FUNCTION__, $args);
}
function dumpOutput() {
$args = func_get_args();
return $this->_appendPlugin(__FUNCTION__, $args);
}
function editFunctions() {
$args = func_get_args();
return $this->_appendPlugin(__FUNCTION__, $args);
}
// applyPlugin
function name() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function credentials() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function permanentLogin() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function database() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function schemas() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function databases() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function queryTimeout() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function headers() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function head() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function loginForm() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function login() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function tableName() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function fieldName() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectLinks() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function foreignKeys() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function backwardKeys() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function backwardKeysPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectQuery() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function rowDescription() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function rowDescriptions() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectLink() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectVal() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function editVal() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectColumnsPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectSearchPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectOrderPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectLimitPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectLengthPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectActionPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectCommandPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectImportPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectEmailPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectColumnsProcess() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectSearchProcess() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectOrderProcess() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectLimitProcess() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectLengthProcess() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectEmailProcess() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function selectQueryBuild() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function messageQuery() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function editInput() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function processInput() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function dumpDatabase() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function dumpTable() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function dumpData() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function dumpFilename() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function dumpHeaders() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function homepage() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function navigation() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function databasesPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
function tablesPrint() {
$args = func_get_args();
return $this->_applyPlugin(__FUNCTION__, $args);
}
}

View File

@@ -0,0 +1,40 @@
<?php
/** Pretty print JSON values in edit
*/
class AdminerPrettyJsonColumn {
/** @var AdminerPlugin */
protected $adminer;
public function __construct($adminer) {
$this->adminer = $adminer;
}
private function _testJson($value) {
if ((substr($value, 0, 1) == '{' || substr($value, 0, 1) == '[') && ($json = json_decode($value, true))) {
return $json;
}
return $value;
}
function editInput($table, $field, $attrs, $value) {
$json = $this->_testJson($value);
if ($json !== $value) {
$jsonText = json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
return <<<HTML
<textarea $attrs cols="50" rows="20">$jsonText</textarea>
HTML;
}
return '';
}
function processInput($field, $value, $function = '') {
if ($function === '') {
$json = $this->_testJson($value);
if ($json !== $value) {
$value = json_encode($json);
}
}
return $this->adminer->_callParent('processInput', array($field, $value, $function));
}
}

View File

@@ -0,0 +1,69 @@
<?php
/** Use filter in tables list
* @link https://www.adminer.org/plugins/#use
* @author Jakub Vrana, https://www.vrana.cz/
* @license https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0
* @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License, version 2 (one or other)
*/
class AdminerTablesFilter {
function tablesPrint($tables) { ?>
<script<?php echo nonce(); ?>>
var tablesFilterTimeout = null;
var tablesFilterValue = '';
function tablesFilter(){
var value = qs('#filter-field').value.toLowerCase();
if (value == tablesFilterValue) {
return;
}
tablesFilterValue = value;
if (value != '') {
var reg = (value + '').replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, '\\$1');
reg = new RegExp('('+ reg + ')', 'gi');
}
if (sessionStorage) {
sessionStorage.setItem('adminer_tables_filter', value);
}
var tables = qsa('li', qs('#tables'));
for (var i = 0; i < tables.length; i++) {
var a = null;
var text = tables[i].getAttribute('data-table-name');
if (text == null) {
a = qsa('a', tables[i])[1];
text = a.innerHTML.trim();
tables[i].setAttribute('data-table-name', text);
a.setAttribute('data-link', 'main');
} else {
a = qs('a[data-link="main"]', tables[i]);
}
if (value == '') {
tables[i].className = '';
a.innerHTML = text;
} else {
tables[i].className = (text.toLowerCase().indexOf(value) == -1 ? 'hidden' : '');
a.innerHTML = text.replace(reg, '<strong>$1</strong>');
}
}
}
function tablesFilterInput() {
window.clearTimeout(tablesFilterTimeout);
tablesFilterTimeout = window.setTimeout(tablesFilter, 200);
}
sessionStorage && document.addEventListener('DOMContentLoaded', function () {
var db = qs('#dbs').querySelector('select');
db = db.options[db.selectedIndex].text;
if (db == sessionStorage.getItem('adminer_tables_filter_db') && sessionStorage.getItem('adminer_tables_filter')){
qs('#filter-field').value = sessionStorage.getItem('adminer_tables_filter');
tablesFilter();
}
sessionStorage.setItem('adminer_tables_filter_db', db);
});
</script>
<p class="jsonly"><input id="filter-field" autocomplete="off"><?php echo script("qs('#filter-field').oninput = tablesFilterInput;"); ?>
<?php
}
}

503
nv/html/api.php Normal file
View File

@@ -0,0 +1,503 @@
<?php
/*
Copyright (C) 2013 Jose Antonio Perez
[ http://goo.gl/lW17d ]
This file is part of dcmgw (Dicom gateway)
[ https://github.com/jap1968/dcmgw ]
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/gpl.html
*/
define('DCMGW_INCLUDE', './dcmgw/');
include_once(DCMGW_INCLUDE . 'dcmgwPacs.php');
include_once(DCMGW_INCLUDE . 'dcmgwConfig.php');
include_once('class/database.php');
$pdttm = date("Y-m-d H:i:s");
_debuglog("$pdttm REQUEST");
_dumpvar($_REQUEST);
// *****************************************************************************
dicomQR($pacs);
// *****************************************************************************
// *****************************************************************************
// dcmqr Example
// JAVA_HOME=/usr/lib/jvm/jdk1.7.0_80 LANG=en_US.iso-8859-1 /usr/local/dcm4che/dcm4che2/bin/dcmqr -device DCMGW -S ABPACS@127.0.0.1:11112 -q 0020000D=1.2.840.113704.1.111.2840.1518168560.1 -r 00080060 -r 0008103E -r 00200011 -r 00201209
// API Call Example
// http://192.168.2.5/api.php?AccessionNumber=CT.000023.18
// *****************************************************************************
// 20120112: Parameters are obtained directly from $_GET
// ToDo: Dealing with errors (returning error information) in the case of incorrect parameters
function dicomQR($pacs)
{
header('Content-type: text/json');
$db = new Database("128.199.154.150", "pacs", "pacs", "pacsdb_his", 3306);
$dbhis = new Database("dvlp.sismedika.com", "hispacs", "s1sm3d1k4123!", "sansanilive", 3306);
// Nivel Q/R | | -P | -S | -I
$extraFields = '-r 00080061 -r 00081030 -r 00100010 -r 00100021 -r 00100030 -r 00100040 -r 00201206 -r 00201208';
// (0008,0061) Modalities in Study
// (0008,1030) Study Description
// (0010,0010) Patient's Name
// (0010,0021) Issuer of Patient ID
// (0010,0030) Patient's Birth Date
// (0010,0040) Patient's Sex
// (0020,1206) Number of Study Related Series
// (0020,1208) Number of Study Related Instances
// (0020,000D) Study IUID
// ToDo: Take also into account PatientIdIssuer
$qPatId = isset($_GET['patId']) ? " -q 00100020='" . $_GET['patId'] . "'" : "";
$qAccessionNumber = isset($_GET['AccessionNumber']) ? " -q 00080050='" . $_GET['AccessionNumber'] . "'" : "";
$qStudyDate = isset($_GET['studyDate']) ? " -q StudyDate={$_GET['studyDate']}" : ""; // AAAAMMDD ???
$qFilter = $qPatId . $qAccessionNumber . $qStudyDate . " ";
// $command = 'LANG='.$pacs->getLocale().' '.PATH_BASE_DCM4CHE2.'dcmqr -device '.AETITLE_GATEWAY.' '.$pacs->getDicomServer()." -q 00100020='$patientId' $extraFields";
if (strlen($qFilter) > 1) {
$command = 'JAVA_HOME=/usr/lib/jvm/jdk1.8.0_144 LANG=' . $pacs->getLocale() . ' ' . PATH_BASE_DCM4CHE2 . 'dcmqr -device ' . AETITLE_GATEWAY . ' ' . $pacs->getDicomServer() . $qFilter . $extraFields;
// echo $command;
$outputRes = array();
exec($command, $outputRes);
//echo "cmd:\n$command";
//print_r($outputRes);
//exit;
_debuglog($command);
// _dumpvar($outputRes);
$dicom = processResponse($outputRes, $pacs->encoding, TRUE);
// header('Content-type: text/plain; charset='.XML_ENCODING);
// print_r($dicom);
$accession_no = $dicom["0008,0050"]["value"];
$study_iuid = $dicom["0020,000D"]["value"];
$study_id = $dicom["0020,0010"]["value"];
$study_description = addslashes(trim($dicom["0008,1030"]["value"]));
$study_date = $dicom["0008,0020"]["value"];
$study_time = $dicom["0008,0030"]["value"];
$study_datetime = $study_date . $study_time;
$number_of_series = $dicom["0020,1206"]["value"];
$number_of_instances = $dicom["0020,1208"]["value"];
$modality = $dicom["0008,0061"]["value"];
if (trim($study_iuid) == "") { ////////// empty study iuid, image not pushed yet to the pacs
$ret["response"] = NULL;
$json = json_encode($ret);
echo $json;
exit(0);
}
$dicom = dicomQRSeries($pacs, $study_iuid);
$ret = array();
$ret["response"]["accession_no"] = $accession_no;
$ret["response"]["study_iuid"] = $study_iuid;
$ret["response"]["study_description"] = $study_description;
$ret["response"]["study_datetime"] = $study_datetime;
$ret["response"]["number_of_series"] = $number_of_series;
$ret["response"]["number_of_instances"] = $number_of_instances;
$ret["response"]["modality"] = $modality;
$sql = "DELETE FROM pacs_result_series WHERE AccessionNumber = '$accession_no'";
$dbhis->query($sql);
$series_number_json = 0;
foreach ($dicom as $k => $v) {
$cnt = count($v);
if ($cnt > 10) {
$idx = floor($cnt * 31 / 51);
} else {
$idx = 1;
}
$n = 1;
foreach ($v as $kk => $vv) {
if ($n == $idx) {
$sop_iuid = $vv["0008,0018"]["value"];
$series_iuid = $vv["0020,000E"]["value"];
$series_description = addslashes(trim($vv["0008,103E"]["value"]));
$series_number = $vv["0020,0011"]["value"];
$series_number_json++;
$number_of_instances = $cnt;
$ret["response"]["series"][$series_number_json]["series_iuid"] = $series_iuid;
$ret["response"]["series"][$series_number_json]["series_description"] = $series_description;
$ret["response"]["series"][$series_number_json]["number_of_instances"] = $number_of_instances;
$ret["response"]["series"][$series_number_json]["sop_iuid"] = $sop_iuid;
$sql = "SELECT MEDRECID,RegID,TrxLayananID FROM pacs_order_mwl WHERE AccessionNumber = '$accession_no'";
$result = $dbhis->query($sql);
if ($db->getRowsNum($result) > 0) {
list($MEDRECID, $RegID, $TrxLayananID) = $db->fetchRow($result);
$sql = "INSERT INTO pacs_result_series (AccessionNumber,MEDRECID,RegID,TrxLayananID,StudyIUID,StudyDescription,StudyDatetime,SeriesIUID,SeriesNumber,SeriesDescription,NumberOfInstance,SOPIUID,Published,PublisheDateTime)"
. " VALUES ('$accession_no','$MEDRECID','$RegID','$TrxLayananID','$study_iuid','$study_description','$study_datetime','$series_iuid','$series_number','$series_description','$number_of_instances','$sop_iuid','N',now())";
$dbhis->query($sql);
_debuglog($sql);
}
_debuglog("$series_number : $series_description");
$wado_thumb = "http://128.199.154.150:8080/wado?requestType=WADO&studyUID=${study_iuid}&seriesUID=${series_iuid}&objectUID=${sop_iuid}&columns=128";
$ret["response"]["series"][$series_number_json]["thumbnail"] = $wado_thumb;
break;
}
$n++;
}
}
$json = json_encode($ret, JSON_PRETTY_PRINT);
echo $json;
}
/*
Example of a Q/R answer (at study level)
14:28:31,609 INFO - Query Response #4:
(0008,0005) CS #10 [ISO_IR 100] Specific Character Set
(0008,0020) DA #8 [20080410] Study Date
(0008,0030) TM #14 [103025.000000] Study Time
(0008,0050) SH #0 [] Accession Number
(0008,0052) CS #6 [STUDY] Query/Retrieve Level
(0008,0054) AE #8 [PACSECO] Retrieve AE Title
(0008,0056) CS #6 [ONLINE] Instance Availability
(0010,0020) LO #6 [72471] Patient ID
(0020,000D) UI #62 [1.2.840.113543.6.6.3.4.617968937028517893191307041671843345256] Study Instance U
(0020,0010) SH #4 [3379] Study ID
(0020,1206) IS #2 [1] Number of Study Related Series
(0020,1208) IS #2 [2] Number of Study Related Instances
(0088,0130) SH #0 [] Storage Media File-set ID
(0088,0140) UI #0 [] Storage Media File-set UID
*/
}
// *****************************************************************************
/**
* Performa a QR operation to get series and instances from a given study
*/
function dicomQRSeries($pacs, $study_IUID)
{
// Nivel Q/R | | -P | -S | -I
// Problema: Algun campo extra lo pide en la subquery de instancias, pero no en la query principal de series
$extraFields = '-r 00080060 -r 0008103E -r 00200011 -r 00201209';
// (0008,0060) Modality
// (0008,103E) Series Description // Solo se envia en las subquery
// (0020,0011) Series Number
// (0020,1209) Number of Series Related Instances // Solo se envia en las subquery
$command = 'JAVA_HOME=/usr/lib/jvm/jdk1.8.0_144 LANG=' . $pacs->getLocale() . ' ' . PATH_BASE_DCM4CHE2 . 'dcmqr -device ' . AETITLE_GATEWAY . ' -I ' . $pacs->getDicomServer() . " -q 0020000D=$study_IUID $extraFields";
_debuglog("$command ###");
$outputRes = array();
exec($command, $outputRes);
$dicom = processResponse($outputRes, $pacs->encoding, TRUE, TRUE);
return $dicom;
}
/**
* The Query/Retrieve answer is processed
* outputRes: Q/R answer string
*/
function processResponse($outputRes, $encoding, $return_array = FALSE, $series = FALSE)
{
$pattern = "/^((?:[0|1][0-9]|2[0-3])(?::[0-5][0-9]){2},[0-9]{3})\s([A-Z]+)\s+-\s(.+)$/";
$dicom = array();
$ret = array();
foreach ($outputRes as $numLine => $strLine) {
$matches = array();
$numMatches = preg_match($pattern, $strLine, $matches);
if ($numMatches == 1) {
// $matches[1]: time (hh:mm:ss,mil)
// $matches[2]: INFO|ERROR|???
$outputType = $matches[2];
// $matches[3]: info string
$outputStr = $matches[3];
if ($outputType == 'ERROR') {
return false;
}
if ($element = identifyPattern($outputStr)) {
$lineNum = $numLine + 1;
$xmlString = '';
if (isset($element["qrequest"]) && isset($element["number"])) {
$request_key = $element["qrequest"] . "/" . $element["number"];
} else {
$request_key = NULL;
}
while (strlen($outputRes[$lineNum]) > 0) {
if ($df = processDicomField($outputRes[$lineNum], $encoding)) {
$key = $df["tagGroup"] . "," . $df["tagElement"];
if (isset($request_key)) {
$k0 = $element["qrequest"];
$k1 = $element["number"];
$ret[$k0][$k1][$key] = $df;
} else {
if ($series === FALSE) {
$ret[$key] = $df;
}
}
$xmlString .= $df['xmlString'] . "\n";
}
$lineNum++;
}
$element['xmlString'] = $element['xmlPre'] . $xmlString . $element['xmlPost'];
array_push($dicom, $element);
}
}
}
if ($return_array) {
return $ret;
}
return $dicom;
} // function processResponse(...)
function processDicomField($dcmString, $encoding)
{
/*
// (0008,0020) DA #8 [20080410] Study Date
// Returned values (string):
tagGroup = 0008
tagElement = 0020
value = 20080410
tagName = Study Date
valueRepr = DA
valueLength = 8 (int)
*/
if (DEBUG_LEVEL >= DEBUG_INFO) {
echo "processDicomField($dcmString)<br>";
}
$matches = array();
$pattern = "/^\(([0-9A-F]{4}),([0-9A-F]{4})\)\s([A-Z]{2})\s#([0-9]+)\s\[([^\]]*)\]\s(.*)$/";
$numMatches = preg_match($pattern, $dcmString, $matches);
if ($numMatches == 1) {
$d = array();
if (DEBUG_LEVEL >= DEBUG_DUMP) {
echo "<pre>";
print_r($matches);
echo "</pre>";
}
$d['tagGroup'] = $matches[1];
$d['tagElement'] = $matches[2];
$d['valueRepr'] = $matches[3];
$d['valueLength'] = $matches[4];
$d['value'] = $matches[5];
$d['tagName'] = $matches[6];
// Characters to convert to UTF-8: Elements with VR=PN, SH, LO, ST, LT, UT in the Data Set.
$vr = $d['valueRepr'];
if ($vr == 'PN' || $vr == 'SH' || $vr == 'LO' || $vr == 'ST' || $vr == 'LT' || $vr == 'UT') {
$d['value'] = iconv($encoding, XML_ENCODING, $d['value']);
$d['value'] = htmlspecialchars($d['value'], ENT_QUOTES); // Convert non valid XML characters
}
$xmlString = "<!--{$d['tagName']}-->\n";
$xmlString = "";
$xmlString .= "<attr tag=\"{$d['tagGroup']}{$d['tagElement']}\" vr=\"{$d['valueRepr']}\" len=\"{$d['valueLength']}\">";
$xmlString .= "{$d['value']}</attr>";
$d['xmlString'] = $xmlString;
} else {
if (DEBUG_LEVEL >= DEBUG_DUMP) {
echo "NO match!!!<br>";
}
$d = false;
}
return $d;
}
function identifyPattern($testStr)
{
$patterns = array();
$element = false;
if (SHOW_REQUEST) {
// Send Query Request using 1.2.840.10008.5.1.4.1.2.2.1/Study Root Query/Retrieve Information Model - FIND:
$patterns[QUERY_REQUEST_ROOT] = "/^Send Query Request using ([0-9]+(?:\.[0-9]+)+)\/([[:alpha:][:space:]\/\-]+):$/";
// Send Query Request #1/3 using 1.2.840.10008.5.1.4.1.2.2.1/Study Root Query/Retrieve Information Model - FIND:
$patterns[QUERY_REQUEST] = "/^Send Query Request #([1-9][0-9]*)\/([1-9][0-9]*) using ([0-9]+(?:\.[0-9]+)+)\/([[:alpha:][:space:]\/\-]+):$/";
}
// Query Response #1:
$patterns[QUERY_RESPONSE_ROOT] = "/^Query Response #([1-9][0-9]*):$/";
// Query Response #1 for Query Request #1/3:
$patterns[QUERY_RESPONSE] = "/^Query Response #([1-9][0-9]*) for Query Request #([1-9][0-9]*)\/([1-9][0-9]*):$/";
$matches = array();
$numMatches = 0;
foreach ($patterns as $type => $pattern) {
if (DEBUG_LEVEL >= DEBUG_INFO) {
echo "Testing $testStr<br>against pattern: $pattern<br>";
}
$numMatches = preg_match($pattern, $testStr, $matches);
if ($numMatches == 1) {
$element = array();
$element['xmlPre'] = "<!--{$matches[0]}-->\n";
$element['type'] = $type;
switch ($type) {
case QUERY_REQUEST_ROOT:
$element['tag'] = 'request';
$element['xmlPre'] .= "<{$element['tag']} qrim='{$matches[1]}'>\n";
break;
case QUERY_RESPONSE_ROOT:
$element['tag'] = 'response';
$element['xmlPre'] .= "<{$element['tag']} number='{$matches[1]}'>\n";
$element['number'] = $matches[1];
break;
case QUERY_REQUEST:
$element['tag'] = 'qrequest';
$element['xmlPre'] .= "<{$element['tag']} number='{$matches[1]}' qrim='{$matches[3]}'>\n";
$element['number'] = $matches[1];
$element['qrim'] = $matches[2];
break;
case QUERY_RESPONSE:
$element['tag'] = 'qresponse';
$element['xmlPre'] .= "<{$element['tag']} number='{$matches[1]}' qrequest='{$matches[2]}'>\n";
$element['number'] = $matches[1];
$element['qrequest'] = $matches[2];
break;
default:
$element['tag'] = 'dummy';
$element['xmlPre'] .= "<{$element['tag']}>\n";
break;
}
$element['xmlPost'] = "</{$element['tag']}>\n";
break; // break 2 ???
}
}
return $element;
}
/**
* Recovers a Dicom object via WADO
*/
function getWado($pacs, $studyUID, $seriesUID, $objectUID)
{
// $tStart = microtime(true);
$uriWado = $pacs->getUriWado($studyUID, $seriesUID, $objectUID);
if (isset($_GET['contentType']) && $_GET['contentType'] == 'application/dicom') {
$header = "Content-Type: application/dicom";
$uriWado .= "&contentType=application%2Fdicom";
// 20130502: Force transfer syntax to Explicit VR little endian
$uriWado .= "&transferSyntax=1.2.840.10008.1.2.1";
} else {
error_log("ERROR jpeg/WADO files should not be used anymore");
$header = "Content-Type: image/jpeg";
}
// To get thumbnails:
if (isset($_GET['rows']) && isset($_GET['cols'])) {
// $uriWado .= "&rows={$_GET['rows']}&cols={$_GET['cols']}";
$uriWado .= "&rows=" . THUMBNAIL_SIZE . "&cols=" . THUMBNAIL_SIZE;
}
if (RETRIEVE_LOCAL) {
// Store a local copy of the Dicom file to obtain its size.
$tmpFWado = tempnam('/tmp', 'dicom_');
// $tmpFWado = tempnam('/dev/shm/dicom', 'dicom_');
if ($getOk = getLocalWado($uriWado, $tmpFWado)) {
$fp = fopen($tmpFWado, 'rb');
header("Content-Type: application/dicom");
header("Content-Length: " . filesize($tmpFWado));
header("Content-Disposition: inline");
fpassthru($fp);
fclose($fp);
} else {
error_log("Error retrieving WADO/Dicom object");
}
unlink($tmpFWado);
} else {
// header("Cache-Control: public");
// header('Expires: '.gmdate('D, d M Y H:i:s', strtotime('+1 day')).' GMT');
header($header);
readfile($uriWado);
}
/*
$tEnd = microtime(true);
$tDelta = round(1000 * ($tEnd - $tStart));
$logMsg = "getWado: $tDelta ms";
error_log($logMsg);
*/
}
// ******* ********* ********* ********* ********* ********* ********* *********
function getLocalWado($uriWado, $tmpFWado)
{
$getOk = false;
$numTry = 0;
$maxTry = 3;
$delayTry = 1;
while (!$getOk && $numTry < $maxTry) {
if ($numTry > 0) {
sleep($delayTry);
}
$retrieveCommand = PATH_WGET . " '$uriWado' -O $tmpFWado --server-response 2> /dev/stdout | grep Content-Type | awk -F\"Content-Type: \" '{print $2}'";
// error_log($retrieveCommand);
$outputCommand = array();
exec($retrieveCommand, $outputCommand);
// Verification: The returned contents is a dicom object
$getOk = $outputCommand[0] == 'application/dicom';
$numTry++;
}
return $getOk;
}
// ******* ********* ********* ********* ********* ********* ********* *********
function _debuglog($cmd)
{
error_log("$cmd\n", 3, "/var/www/html/dcmgw/tmp/debuglog");
}
function _dumpvar($var)
{
ob_start();
print_r($var);
_debuglog(ob_get_contents());
ob_end_clean();
}

107
nv/html/class/database.php Normal file
View File

@@ -0,0 +1,107 @@
<?php
//--------------------------------------------------------------------//
// Filename : class/database/mysql.php //
// Software : XOCP - X Open Community Portal //
// Version : 0.1 //
// Date : 2002-11-09 //
// Author : adiet //
// License : GPL //
//--------------------------------------------------------------------//
if ( !defined('MYSQL_DATABASE_DEFINED') ) {
define('MYSQL_DATABASE_DEFINED', TRUE);
class Database extends mysqli {
var $debug = TRUE;
public function __construct($dbhost=NULL,$dbuser=NULL,$dbpass=NULL,$dbname=NULL,$dbport=NULL) {
if(!isset($dbname)) {
parent::__construct(_XOCP_DB_HOST,_XOCP_DB_USER,_XOCP_DB_PASS,_XOCP_DB_NAME,_XOCP_DB_PORT);
} else {
parent::__construct($dbhost,$dbuser,$dbpass,$dbname,$dbport);
}
if (mysqli_connect_error()) {
die('Connect Error (' . mysqli_connect_errno() . ') ' . mysqli_connect_error());
}
}
public static function getInstance($dbhost=NULL,$dbuser=NULL,$dbpass=NULL,$dbname=NULL,$dbport=NULL) {
if(!isset($dbname)) {
return new Database(_XOCP_DB_HOST,_XOCP_DB_USER,_XOCP_DB_PASS,_XOCP_DB_NAME,_XOCP_DB_PORT);
} else {
return new Database($dbhost,$dbuser,$dbpass,$dbname,$dbport);
}
}
function getRowsNum(&$result) {
if(is_object($result)) return $result->num_rows;
return FALSE;
}
function getInsertId() {
return $this->insert_id;
}
function fetchRow(&$result) {
if(is_object($result)) return $result->fetch_row();
return FALSE;
}
function fetchArray(&$result) {
if(is_object($result)) return $result->fetch_array(MYSQLI_ASSOC);
return FALSE;
}
function fetchObject(&$result) {
if(is_object($result)) return $result->fetch_object();
return FALSE;
}
function fieldName(&$result,$i) {
if(is_object($result)) return $result->fetch_field($i);
return FALSE;
}
function fetchField(&$result,$i) {
if(is_object($result)) return $result->fetch_field_direct($i);
return FALSE;
}
function getFieldsNum(&$result) {
if(is_object($result)) return $result->field_count;
return FALSE;
}
function getAffectedRows() {
if(is_object($result)) return $this->affected_rows;
return FALSE;
}
function freeRecordSet(&$result) {
if(is_object($result)) return $result->free();
}
function error() {
return $this->error;
}
function errno() {
return $this->errno;
}
function &query($sql) {
$result = parent::query($sql);
if($this->errno!=0) {
if ( $this->debug ) {
$errorMsg = @$this->error;
$errorNum = @$this->errno;
_debuglog("MySQL Query Error: $sql\nError Number: $errorNum\nError Message: $errorMsg");
}
}
return $result;
}
}
} // MYSQL_DATABASE_DEFINED

18
nv/html/dcmgw/LICENSE.md Normal file
View File

@@ -0,0 +1,18 @@
Copyright (C) 2013 Jose Antonio Perez
[ http://goo.gl/lW17d ]
dcmgw: DICOM c-find gateway
[ https://github.com/jap1968/dcmgw ]
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/gpl.html

15
nv/html/dcmgw/README.md Normal file
View File

@@ -0,0 +1,15 @@
dcmgw is a script acting as a gateway allowing to do c-find requests to a Dicom server.
The results are returned as XML contents. The xml folder contains the XSD specification
of the response messages as well as some XML samples.
dcmgw relies upon dcmqr, from the [dcm4che2 toolkit](http://www.dcm4che.org/confluence/display/d2/dcm4che2+DICOM+Toolkit).
Dicom servers are intended to be accessed just by Dicom clients. This is one important limitation in order to access
these servers from web applications.
Currently, things are changing and there are new proposals in order to extend the Dicom protocol by means of
RESTful web services.
In particular, QIDO-RS (Query based on ID for DICOM Objects by RESTful Services) will be included
in Dicom [supplement 166](http://www.dclunie.com/dicom-status/status.html). Meanwhile, applications like dcmgw provide similar functionality allowing
to access Dicom servers from web applications right now.

478
nv/html/dcmgw/dcmgw.php Normal file
View File

@@ -0,0 +1,478 @@
<?php
/*
Copyright (C) 2013 Jose Antonio Perez
[ http://goo.gl/lW17d ]
This file is part of dcmgw (Dicom gateway)
[ https://github.com/jap1968/dcmgw ]
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/gpl.html
*/
define('DCMGW_INCLUDE', './');
include_once(DCMGW_INCLUDE.'dcmgwPacs.php');
include_once(DCMGW_INCLUDE.'dcmgwConfig.php');
// *****************************************************************************
_dumpvar($_REQUEST);
// operation: cfind | dicomfields | wado | binarydata
$operation = isset($_GET['operation']) ? $_GET['operation'] : 'cfind';
if ($operation == 'cfind') {
if (isset($_GET['studyUID'])) {
$studyUID = $_GET['studyUID'];
dicomQRStudy($pacs, $studyUID);
}
else {
dicomQR($pacs);
}
}
else if ($operation == 'dicomfields') {
$studyUID = $_GET['studyUID'];
$seriesUID = $_GET['seriesUID'];
$objectUID = $_GET['objectUID'];
getDicomWadoFields($pacs, $studyUID, $seriesUID, $objectUID);
}
else if ($operation == 'binarydata') {
$studyUID = $_GET['studyUID'];
$seriesUID = $_GET['seriesUID'];
$objectUID = $_GET['objectUID'];
$len = $_GET['len'];
$src = $_GET['src'];
getBinaryData($pacs, $studyUID, $seriesUID, $objectUID, $len, $src);
}
else {
// define('TAM_MAX_THUMB', 120);
$studyUID = $_GET['studyUID'];
$seriesUID = $_GET['seriesUID'];
$objectUID = $_GET['objectUID'];
getWado($pacs, $studyUID, $seriesUID, $objectUID);
/*
$uriWado = $pacs->getUriWado($studyUID, $seriesUID, $objectUID);
// To get thumbnails:
if (isset($_GET['rows']) && isset($_GET['cols'])) {
$uriWado .= "&rows={$_GET['rows']}&cols={$_GET['cols']}";
}
// header("Cache-Control: public");
// header('Expires: '.gmdate('D, d M Y H:i:s', strtotime('+1 day')).' GMT');
header("Content-Type: image/jpeg");
readfile($uriWado);
*/
}
// *****************************************************************************
// *****************************************************************************
/**
* The Query/Retrieve answer is processed
* outputRes: Q/R answer string
*/
function processResponse($outputRes, $encoding) {
$pattern = "/^((?:[0|1][0-9]|2[0-3])(?::[0-5][0-9]){2},[0-9]{3})\s([A-Z]+)\s+-\s(.+)$/";
$dicom = array();
foreach ($outputRes as $numLine => $strLine) {
$matches = array();
$numMatches = preg_match($pattern, $strLine, $matches);
if ($numMatches == 1) {
// $matches[1]: time (hh:mm:ss,mil)
// $matches[2]: INFO|ERROR|???
$outputType = $matches[2];
// $matches[3]: info string
$outputStr = $matches[3];
if (DEBUG_LEVEL >= DEBUG_DUMP) {
// Mensajes de tipo INFO / ERROR
echo "<div style='color:red; margin:2em 0.5em;'>Patr&oacute;n reconocido (I)</div>";
echo "<pre>";
print_r($matches);
echo "</pre>";
}
// 20120120: ToDo: Dealing with errors. Inform the client about the error
if ($outputType == 'ERROR') {
echo "ERROR";
if (DEBUG_LEVEL >= DEBUG_INFO) {
echo ": $outputStr";
}
echo "<br>\n";
return false;
}
if ($element = identifyPattern($outputStr)) {
$lineNum = $numLine + 1;
_dumpvar($element);
$xmlString = '';
while(strlen($outputRes[$lineNum]) > 0) {
if (DEBUG_LEVEL >= DEBUG_INFO) {
echo $outputRes[$lineNum]."<br>\n";
}
if ($df = processDicomField($outputRes[$lineNum], $encoding)) {
_dumpvar($df);
$xmlString .= $df['xmlString']."\n";
}
$lineNum++;
}
$element['xmlString'] = $element['xmlPre'].$xmlString.$element['xmlPost'];
if (DEBUG_LEVEL >= DEBUG_DUMP) {
// print_r($dicomHeaders);
echo $element['xmlString'];
}
array_push($dicom, $element);
}
}
}
if (DEBUG_LEVEL >= DEBUG_INFO) {
echo "<pre>";
// print_r($result);
echo "</pre>";
}
elseif (DEBUG_LEVEL == DEBUG_NONE) {
header('Content-type: text/xml; charset='.XML_ENCODING);
echo "<?xml version=\"1.0\" encoding=\"".XML_ENCODING."\"?>\n";
$fechaAhora = strftime("%Y%m%d%H%M%S%z");
echo "<dicom datetime=\"$fechaAhora\">\n";
foreach ($dicom as $response) {
echo $response['xmlString'];
}
echo "</dicom>\n";
}
} // function processResponse(...)
// *****************************************************************************
function identifyPattern($testStr) {
$patterns = array();
$element = false;
if (SHOW_REQUEST)
{
// Send Query Request using 1.2.840.10008.5.1.4.1.2.2.1/Study Root Query/Retrieve Information Model - FIND:
$patterns[QUERY_REQUEST_ROOT] = "/^Send Query Request using ([0-9]+(?:\.[0-9]+)+)\/([[:alpha:][:space:]\/\-]+):$/";
// Send Query Request #1/3 using 1.2.840.10008.5.1.4.1.2.2.1/Study Root Query/Retrieve Information Model - FIND:
$patterns[QUERY_REQUEST] = "/^Send Query Request #([1-9][0-9]*)\/([1-9][0-9]*) using ([0-9]+(?:\.[0-9]+)+)\/([[:alpha:][:space:]\/\-]+):$/";
}
// Query Response #1:
$patterns[QUERY_RESPONSE_ROOT] = "/^Query Response #([1-9][0-9]*):$/";
// Query Response #1 for Query Request #1/3:
$patterns[QUERY_RESPONSE] = "/^Query Response #([1-9][0-9]*) for Query Request #([1-9][0-9]*)\/([1-9][0-9]*):$/";
$matches = array();
$numMatches = 0;
foreach ($patterns as $type => $pattern)
{
if (DEBUG_LEVEL >= DEBUG_INFO) {
echo "Testing $testStr<br>against pattern: $pattern<br>";
}
$numMatches = preg_match($pattern, $testStr, $matches);
if($numMatches == 1)
{
$element = array();
$element['xmlPre'] = "<!--{$matches[0]}-->\n";
$element['type'] = $type;
switch ($type) {
case QUERY_REQUEST_ROOT:
$element['tag'] = 'request';
$element['xmlPre'] .= "<{$element['tag']} qrim='{$matches[1]}'>\n";
break;
case QUERY_RESPONSE_ROOT:
$element['tag'] = 'response';
$element['xmlPre'] .= "<{$element['tag']} number='{$matches[1]}'>\n";
break;
case QUERY_REQUEST:
$element['tag'] = 'qrequest';
$element['xmlPre'] .= "<{$element['tag']} number='{$matches[1]}' qrim='{$matches[3]}'>\n";
break;
case QUERY_RESPONSE:
$element['tag'] = 'qresponse';
$element['xmlPre'] .= "<{$element['tag']} number='{$matches[1]}' qrequest='{$matches[2]}'>\n";
break;
default:
$element['tag'] = 'dummy';
$element['xmlPre'] .= "<{$element['tag']}>\n";
}
$element['xmlPost'] = "</{$element['tag']}>\n";
break; // break 2 ???
}
}
return $element;
}
// 20120112: Parameters are obtained directly from $_GET
// ToDo: Dealing with errors (returning error information) in the case of incorrect parameters
function dicomQR ($pacs)
{
// Nivel Q/R | | -P | -S | -I
$extraFields = '-r 00080061 -r 00081030 -r 00100010 -r 00100021 -r 00100030 -r 00100040 -r 00201206 -r 00201208';
// (0008,0061) Modalities in Study
// (0008,1030) Study Description
// (0010,0010) Patient's Name
// (0010,0021) Issuer of Patient ID
// (0010,0030) Patient's Birth Date
// (0010,0040) Patient's Sex
// (0020,1206) Number of Study Related Series
// (0020,1208) Number of Study Related Instances
// (0020,000D) Study IUID
// ToDo: Take also into account PatientIdIssuer
$qPatId = isset($_GET['patId']) ? " -q 00100020='" . $_GET['patId'] . "'" : "";
$qAccessionNo = isset($_GET['AccessionNo']) ? " -q 00080050='" . $_GET['AccessionNo'] . "'" : "";
$qStudyDate = isset($_GET['studyDate']) ? " -q StudyDate={$_GET['studyDate']}" : ""; // AAAAMMDD ???
$qFilter = $qPatId . $qAccessionNo . $qStudyDate . " ";
// $command = 'LANG='.$pacs->getLocale().' '.PATH_BASE_DCM4CHE2.'dcmqr -device '.AETITLE_GATEWAY.' '.$pacs->getDicomServer()." -q 00100020='$patientId' $extraFields";
if (strlen($qFilter) > 1) {
$command = 'JAVA_HOME=/usr/lib/jvm/jdk1.7.0_80 LANG='.$pacs->getLocale().' '.PATH_BASE_DCM4CHE2.'dcmqr -device '.AETITLE_GATEWAY.' '.$pacs->getDicomServer() . $qFilter . $extraFields;
// echo $command;
$outputRes = array();
exec($command, $outputRes);
if (DEBUG_LEVEL >= DEBUG_DUMP) {
echo "<pre>";
print_r($outputRes);
echo "</pre>";
}
processResponse($outputRes, $pacs->encoding);
}
/*
Example of a Q/R answer (at study level)
14:28:31,609 INFO - Query Response #4:
(0008,0005) CS #10 [ISO_IR 100] Specific Character Set
(0008,0020) DA #8 [20080410] Study Date
(0008,0030) TM #14 [103025.000000] Study Time
(0008,0050) SH #0 [] Accession Number
(0008,0052) CS #6 [STUDY] Query/Retrieve Level
(0008,0054) AE #8 [PACSECO] Retrieve AE Title
(0008,0056) CS #6 [ONLINE] Instance Availability
(0010,0020) LO #6 [72471] Patient ID
(0020,000D) UI #62 [1.2.840.113543.6.6.3.4.617968937028517893191307041671843345256] Study Instance U
(0020,0010) SH #4 [3379] Study ID
(0020,1206) IS #2 [1] Number of Study Related Series
(0020,1208) IS #2 [2] Number of Study Related Instances
(0088,0130) SH #0 [] Storage Media File-set ID
(0088,0140) UI #0 [] Storage Media File-set UID
*/
}
// *****************************************************************************
/**
* Performa a QR operation to get series and instances from a given study
*/
function dicomQRStudy ($pacs, $study_IUID)
{
// Nivel Q/R | | -P | -S | -I
// Problema: Algun campo extra lo pide en la subquery de instancias, pero no en la query principal de series
$extraFields = '-r 00080060 -r 0008103E -r 00200011 -r 00201209';
// (0008,0060) Modality
// (0008,103E) Series Description // Solo se envia en las subquery
// (0020,0011) Series Number
// (0020,1209) Number of Series Related Instances // Solo se envia en las subquery
$command = 'JAVA_HOME=/usr/lib/jvm/jdk1.7.0_80 LANG='.$pacs->getLocale().' '.PATH_BASE_DCM4CHE2.'dcmqr -device '.AETITLE_GATEWAY.' -I '.$pacs->getDicomServer()." -q 0020000D=$study_IUID $extraFields";
_debuglog($command);
$outputRes = array();
exec($command, $outputRes);
if (DEBUG_LEVEL >= DEBUG_DUMP) {
echo "<pre>";
print_r($outputRes);
echo "</pre>";
}
processResponse($outputRes, $pacs->encoding);
}
function processDicomField($dcmString, $encoding) {
/*
// (0008,0020) DA #8 [20080410] Study Date
// Returned values (string):
tagGroup = 0008
tagElement = 0020
value = 20080410
tagName = Study Date
valueRepr = DA
valueLength = 8 (int)
*/
if (DEBUG_LEVEL >= DEBUG_INFO) {
echo "processDicomField($dcmString)<br>";
}
$matches = array();
$pattern = "/^\(([0-9A-F]{4}),([0-9A-F]{4})\)\s([A-Z]{2})\s#([0-9]+)\s\[([^\]]*)\]\s(.*)$/";
$numMatches = preg_match($pattern, $dcmString, $matches);
if($numMatches == 1) {
$d = array();
if (DEBUG_LEVEL >= DEBUG_DUMP) {
echo "<pre>";
print_r($matches);
echo "</pre>";
}
$d['tagGroup'] = $matches[1];
$d['tagElement'] = $matches[2];
$d['valueRepr'] = $matches[3];
$d['valueLength'] = $matches[4];
$d['value'] = $matches[5];
$d['tagName'] = $matches[6];
// Characters to convert to UTF-8: Elements with VR=PN, SH, LO, ST, LT, UT in the Data Set.
$vr = $d['valueRepr'];
if ($vr == 'PN' || $vr == 'SH' || $vr == 'LO' || $vr == 'ST' || $vr == 'LT' || $vr == 'UT') {
$d['value'] = iconv($encoding, XML_ENCODING, $d['value']);
$d['value'] = htmlspecialchars($d['value'], ENT_QUOTES); // Convert non valid XML characters
}
$xmlString = "<!--{$d['tagName']}-->\n";
$xmlString .= "<attr tag=\"{$d['tagGroup']}{$d['tagElement']}\" vr=\"{$d['valueRepr']}\" len=\"{$d['valueLength']}\">";
$xmlString .= "{$d['value']}</attr>";
$d['xmlString'] = $xmlString;
}
else {
if (DEBUG_LEVEL >= DEBUG_DUMP) {
echo "NO match!!!<br>";
}
$d = false;
}
return $d;
}
// *****************************************************************************
/**
* Recovers a Dicom object via WADO
*/
function getWado($pacs, $studyUID, $seriesUID, $objectUID) {
// $tStart = microtime(true);
$uriWado = $pacs->getUriWado($studyUID, $seriesUID, $objectUID);
if (isset($_GET['contentType']) && $_GET['contentType'] == 'application/dicom') {
$header = "Content-Type: application/dicom";
$uriWado .= "&contentType=application%2Fdicom";
// 20130502: Force transfer syntax to Explicit VR little endian
$uriWado .= "&transferSyntax=1.2.840.10008.1.2.1";
}
else {
error_log("ERROR jpeg/WADO files should not be used anymore");
$header = "Content-Type: image/jpeg";
}
// To get thumbnails:
if (isset($_GET['rows']) && isset($_GET['cols']))
{
// $uriWado .= "&rows={$_GET['rows']}&cols={$_GET['cols']}";
$uriWado .= "&rows=".THUMBNAIL_SIZE."&cols=".THUMBNAIL_SIZE;
}
if (RETRIEVE_LOCAL) {
// Store a local copy of the Dicom file to obtain its size.
$tmpFWado = tempnam('/tmp', 'dicom_');
// $tmpFWado = tempnam('/dev/shm/dicom', 'dicom_');
if ($getOk = getLocalWado($uriWado, $tmpFWado))
{
$fp = fopen($tmpFWado, 'rb');
header("Content-Type: application/dicom");
header("Content-Length: " . filesize($tmpFWado));
header("Content-Disposition: inline");
fpassthru($fp);
fclose($fp);
}
else
{
error_log("Error retrieving WADO/Dicom object");
}
unlink($tmpFWado);
}
else
{
// header("Cache-Control: public");
// header('Expires: '.gmdate('D, d M Y H:i:s', strtotime('+1 day')).' GMT');
header($header);
readfile($uriWado);
}
/*
$tEnd = microtime(true);
$tDelta = round(1000 * ($tEnd - $tStart));
$logMsg = "getWado: $tDelta ms";
error_log($logMsg);
*/
}
// ******* ********* ********* ********* ********* ********* ********* *********
function getLocalWado($uriWado, $tmpFWado) {
$getOk = false;
$numTry = 0;
$maxTry = 3;
$delayTry = 1;
while (!$getOk && $numTry < $maxTry)
{
if ($numTry > 0)
{
sleep($delayTry);
}
$retrieveCommand = PATH_WGET." '$uriWado' -O $tmpFWado --server-response 2> /dev/stdout | grep Content-Type | awk -F\"Content-Type: \" '{print $2}'";
// error_log($retrieveCommand);
$outputCommand = array();
exec($retrieveCommand, $outputCommand);
// Verification: The returned contents is a dicom object
$getOk = $outputCommand[0] == 'application/dicom';
$numTry++;
}
return $getOk;
}
// ******* ********* ********* ********* ********* ********* ********* *********
function _debuglog($cmd) {
error_log("$cmd\n",3,"/var/www/html/dcmgw/tmp/debuglog");
}
function _dumpvar($var) {
ob_start();
print_r($var);
_debuglog(ob_get_contents());
ob_end_clean();
}

View File

@@ -0,0 +1,98 @@
<?php
ini_set("log_errors",1);
ini_set("error_log","/var/www/html/dcmgw/php_error.log");
/*
Copyright (C) 2013 Jose Antonio Perez
[ http://goo.gl/lW17d ]
This file is part of dcmgw (Dicom gateway)
[ https://github.com/jap1968/dcmgw ]
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/gpl.html
*/
// ******* ********* ********* ********* ********* ********* ********* *********
/**
* Avoids direct execution of the script
*/
if (!defined('DCMGW_INCLUDE')) {
header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
die;
}
// ******* ********* ********* ********* ********* ********* ********* *********
// Configuration: Change values to fit your environment
// ******* ********* ********* ********* ********* ********* ********* *********
// You should end up having a variable $pacs pointing to your PACS server.
// You can find below some configuration samples for public servers
// Please, for testing purposes use your own server (if possible) to avoid overloading the public servers
// http://www.dicomserver.co.uk/
// http://wado.medicalconnections.co.uk/WADO/WADO.asp
//$pacsMedicalConnections = new PACS('ABPACS', '127.0.0.1', '11112');
//$pacsMedicalConnections->setWado('http', '127.0.0.1', '80', 'wado/wadp.asp');
// DC's public PixelMed PACS.
// No WADO?
//$pacsPixelMed = new PACS('ABPACS', '127.0.0.1', '11112');
// Public JVSdicom Server. Not sure if this one has any contents.
// No WADO ?
// More information: http://153.1.200.58/?q=dicom_images
//$pacsJVSdicom = new PACS('JVSDICOM', '153.1.200.58', '104');
// My own PACS
$pacsHome = new DCM4CHEE('ABPACS', '128.199.154.150');
$pacs = $pacsHome;
// ******* ********* ********* ********* ********* ********* ********* *********
// This script makes use of dcmqr, from the dcm4che2 Dicom toolkit
// dcm4che2 Dicom toolkit: http://www.dcm4che.org/confluence/display/d2/dcm4che2+DICOM+Toolkit
// dcmqr: http://www.dcm4che.org/confluence/display/d2/dcmqr
//define ('PATH_BASE_DCM4CHE2', '/usr/local/dcm4che/dcm4che2/bin/');
define ('PATH_BASE_DCM4CHE2', '/var/www/dcm4che/dcm4che2/bin/');
define ('PATH_BASE_DICOM_CACHE', '/tmp/dicom/');
define ('PATH_WGET', '/usr/bin/wget');
define ('RETRIEVE_LOCAL', true);
define('SHOW_REQUEST', false);
define('XML_ENCODING', 'UTF-8');
define ('DEBUG_NONE', 0);
define ('DEBUG_INFO', 5);
define ('DEBUG_DUMP', 9);
define ('DEBUG_LEVEL', DEBUG_NONE);
define ('AETITLE_GATEWAY', 'DCMGW');
define ('THUMBNAIL_SIZE', '200');
// ******* ********* ********* ********* ********* ********* ********* *********
define('QUERY_REQUEST_ROOT', '0');
define('QUERY_RESPONSE_ROOT', '1');
define('QUERY_REQUEST', '2');
define('QUERY_RESPONSE', '3');
// ******* ********* ********* ********* ********* ********* ********* *********

133
nv/html/dcmgw/dcmgwPacs.php Normal file
View File

@@ -0,0 +1,133 @@
<?php
/*
Copyright (C) 2013 Jose Antonio Perez
[ http://goo.gl/lW17d ]
This file is part of dcmgw (Dicom gateway)
[ https://github.com/jap1968/dcmgw ]
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/gpl.html
*/
// ******* ********* ********* ********* ********* ********* ********* *********
/**
* Avoids direct execution of the script
*/
if (!defined('DCMGW_INCLUDE')) {
header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
die;
}
// ******* ********* ********* ********* ********* ********* ********* *********
// Configuration: Generic Dicom Storage SCP
// ******* ********* ********* ********* ********* ********* ********* *********
class PACS
{
// DICOM setup
public $AETitle;
public $host;
public $port;
// WADO setup
public $wadoProtocol;
public $wadoHost;
public $wadoPort;
public $wadoScript;
public $lang = 'en_US'; // No need to change
public $encoding = 'iso-8859-1'; // May need to change to UTF-8
function __construct($AETitle, $host, $port) {
$this->AETitle = $AETitle;
$this->host = $host;
$this->port = $port;
$this->wadoProtocol = 'http';
$this->wadoHost = $host;
$this->wadoPort = $port;
}
public function getDicomServer() {
$dicomServer = $this->AETitle.'@'.$this->host.':'.$this->port;
return $dicomServer;
}
/**
* Force Dicom Q/R execution under a given locale to deal properly with non-ascii characters
*/
public function getLocale() {
return $this->lang.'.'.$this->encoding;
}
/**
* In some environments Wado server runs independently of Dicom server
*/
public function setWado($wadoProtocol, $wadoHost, $wadoPort, $wadoScript) {
$this->wadoProtocol = $wadoProtocol;
$this->wadoHost = $wadoHost;
$this->wadoPort = $wadoPort;
$this->wadoScript = $wadoScript;
}
public function setWadoScript($wadoScript) {
$this->wadoScript = $wadoScript;
}
public function getUriWado($studyUID, $seriesUID, $objectUID) {
// Additional parameters ???
// contentType
// transferSyntax (UID)
$codeBase = "{$this->wadoProtocol}://{$this->wadoHost}:{$this->wadoPort}/{$this->wadoScript}?";
$queryString = "requestType=WADO&studyUID={$studyUID}&seriesUID={$seriesUID}&objectUID={$objectUID}";
$uriWado = $codeBase.$queryString;
return $uriWado;
}
}
// ******* ********* ********* ********* ********* ********* ********* *********
// Specific subclasses for some popular Dicom servers
class DCM4CHEE extends PACS {
function __construct($AETitle, $host) {
$port = '11112';
parent::__construct($AETitle, $host, $port);
$this->wadoPort = '8080';
$this->setWadoScript('wado');
}
}
class CONQUEST extends PACS {
function __construct($AETitle, $host, $port) {
parent::__construct($AETitle, $host, $port);
$this->setWadoScript('cgi-bin/dgate.exe');
}
}
class CLEARCANVAS extends PACS {
function __construct($AETitle, $host, $port) {
parent::__construct($AETitle, $host, $port);
$this->wadoPort = '1000';
$this->setWadoScript('wado/'.$AETitle);
}
}
// ******* ********* ********* ********* ********* ********* ********* *********

3
nv/html/dcmgw/info.php Normal file
View File

@@ -0,0 +1,3 @@
<?php
phpinfo();

18979
nv/html/dcmgw/php_error.log Normal file

File diff suppressed because it is too large Load Diff

32
nv/html/dcmgw/tmp/DEADJOE Normal file
View File

@@ -0,0 +1,32 @@
*** These modified files were found in JOE when it aborted on Thu Apr 12 07:54:04 2018
*** JOE was aborted because the terminal closed
*** File '(Unnamed)'
while
for
debug
dumpvar
port
8080
8080
mysql
mysql
mysql
*** File '(Unnamed)'
/tmp/ck.log
mcserver
docs/README.txt
mcservice
mcservice.vmoptions
conf/mirth.properties
conf/mirth.properties
conf/dbdrivers.xml
mcservice
mcservice
debuglog
*** File '* Startup Log *'
Processing '/etc/joe/joerc'...
Finished processing /etc/joe/joerc

133137
nv/html/dcmgw/tmp/debuglog Normal file

File diff suppressed because it is too large Load Diff

41513
nv/html/dcmgw/tmp/olddebuglog Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?>
<dicom datetime="20130526224447+0200">
<!--Query Response #1:-->
<response number='1'>
<!--Specific Character Set-->
<attr tag="00080005" vr="CS" len="0"></attr>
<!--Study Date-->
<attr tag="00080020" vr="DA" len="8">19991223</attr>
<!--Study Time-->
<attr tag="00080030" vr="TM" len="6">100545</attr>
<!--Accession Number-->
<attr tag="00080050" vr="SH" len="4">0001</attr>
<!--Query/Retrieve Level-->
<attr tag="00080052" vr="CS" len="6">STUDY</attr>
<!--Retrieve AE Title-->
<attr tag="00080054" vr="AE" len="4">TEST</attr>
<!--Modalities in Study-->
<attr tag="00080061" vr="CS" len="4">ECG</attr>
<!--Study Description-->
<attr tag="00081030" vr="LO" len="0"></attr>
<!--Patient?s Name-->
<attr tag="00100010" vr="PN" len="12">Patient^Test</attr>
<!--Patient ID-->
<attr tag="00100020" vr="LO" len="8">123-654</attr>
<!--Patient?s Birth Date-->
<attr tag="00100030" vr="DA" len="8">19440102</attr>
<!--Patient?s Sex-->
<attr tag="00100040" vr="CS" len="2">M</attr>
<!--Study Instance UID-->
<attr tag="0020000D" vr="UI" len="22">1.3.6.1.4.1.6018.4.999</attr>
<!--Study ID-->
<attr tag="00200010" vr="SH" len="6">43288</attr>
<!--Number of Study Related Series-->
<attr tag="00201206" vr="IS" len="2">1</attr>
<!--Number of Study Related Instances-->
<attr tag="00201208" vr="IS" len="2">1</attr>
</response>
<!--Query Response #2:-->
<response number='2'>
<!--Specific Character Set-->
<attr tag="00080005" vr="CS" len="0"></attr>
<!--Study Date-->
<attr tag="00080020" vr="DA" len="8">19940323</attr>
<!--Study Time-->
<attr tag="00080030" vr="TM" len="6">115104</attr>
<!--Accession Number-->
<attr tag="00080050" vr="SH" len="0"></attr>
<!--Query/Retrieve Level-->
<attr tag="00080052" vr="CS" len="6">STUDY</attr>
<!--Retrieve AE Title-->
<attr tag="00080054" vr="AE" len="4">TEST</attr>
<!--Modalities in Study-->
<attr tag="00080061" vr="CS" len="2">US</attr>
<!--Study Description-->
<attr tag="00081030" vr="LO" len="14">Echocardiogram</attr>
<!--Patient?s Name-->
<attr tag="00100010" vr="PN" len="10">Rubo DEMO</attr>
<!--Patient ID-->
<attr tag="00100020" vr="LO" len="12">123-45-6789</attr>
<!--Patient?s Birth Date-->
<attr tag="00100030" vr="DA" len="8">19231016</attr>
<!--Patient?s Sex-->
<attr tag="00100040" vr="CS" len="2">F</attr>
<!--Study Instance UID-->
<attr tag="0020000D" vr="UI" len="16">999.999.3859744</attr>
<!--Study ID-->
<attr tag="00200010" vr="SH" len="10">027893462</attr>
<!--Number of Study Related Series-->
<attr tag="00201206" vr="IS" len="2">1</attr>
<!--Number of Study Related Instances-->
<attr tag="00201208" vr="IS" len="2">1</attr>
</response>
</dicom>

View File

@@ -0,0 +1,36 @@
<?xml version="1.0"?>
<!-- Generated using Flame-Ware Solutions XML-2-XSD v2.0 at http://www.flame-ware.com/Products/XML-2-XSD/ -->
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="dicom">
<xs:complexType>
<xs:sequence>
<xs:element name="response" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="attr" nillable="true" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent msdata:ColumnName="attr_Text" msdata:Ordinal="3">
<xs:extension base="xs:string">
<xs:attribute name="tag" type="xs:string" />
<xs:attribute name="vr" type="xs:string" />
<xs:attribute name="len" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="number" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="datetime" type="xs:string" />
</xs:complexType>
</xs:element>
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="dicom" />
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<dicom datetime="20130526224718+0200">
<!--Query Response #1:-->
<response number='1'>
<!--Specific Character Set-->
<attr tag="00080005" vr="CS" len="0"></attr>
<!--Query/Retrieve Level-->
<attr tag="00080052" vr="CS" len="6">SERIES</attr>
<!--Retrieve AE Title-->
<attr tag="00080054" vr="AE" len="4">TEST</attr>
<!--Modality-->
<attr tag="00080060" vr="CS" len="2">US</attr>
<!--Study Instance UID-->
<attr tag="0020000D" vr="UI" len="16">999.999.3859744</attr>
<!--Series Instance UID-->
<attr tag="0020000E" vr="UI" len="16">999.999.94827453</attr>
<!--Series Number-->
<attr tag="00200011" vr="IS" len="4">5829</attr>
</response>
<!--Query Response #1 for Query Request #1/1:-->
<qresponse number='1' qrequest='1'>
<!--SOP Class UID-->
<attr tag="00080016" vr="UI" len="28">1.2.840.10008.5.1.4.1.1.3.1</attr>
<!--SOP Instance UID-->
<attr tag="00080018" vr="UI" len="30">999.999.133.1996.1.1800.1.6.29</attr>
<!--Query/Retrieve Level-->
<attr tag="00080052" vr="CS" len="6">IMAGE</attr>
<!--Retrieve AE Title-->
<attr tag="00080054" vr="AE" len="4">TEST</attr>
<!--Series Instance UID-->
<attr tag="0020000E" vr="UI" len="16">999.999.94827453</attr>
<!--Instance Number-->
<attr tag="00200013" vr="IS" len="2">28</attr>
</qresponse>
</dicom>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0"?>
<!-- Generated using Flame-Ware Solutions XML-2-XSD v2.0 at http://www.flame-ware.com/Products/XML-2-XSD/ -->
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="attr" nillable="true">
<xs:complexType>
<xs:simpleContent msdata:ColumnName="attr_Text" msdata:Ordinal="3">
<xs:extension base="xs:string">
<xs:attribute name="tag" type="xs:string" />
<xs:attribute name="vr" type="xs:string" />
<xs:attribute name="len" type="xs:string" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="dicom">
<xs:complexType>
<xs:sequence>
<xs:element name="response" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element ref="attr" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="number" type="xs:string" />
</xs:complexType>
</xs:element>
<xs:element name="qresponse" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element ref="attr" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="number" type="xs:string" />
<xs:attribute name="qrequest" type="xs:string" />
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="datetime" type="xs:string" />
</xs:complexType>
</xs:element>
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element ref="attr" />
<xs:element ref="dicom" />
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>

View File

@@ -0,0 +1,22 @@
---
engines:
csslint:
enabled: true
duplication:
enabled: true
config:
languages:
- javascript
eslint:
enabled: true
fixme:
enabled: true
ratings:
paths:
- "**.css"
- "**.inc"
- "**.js"
exclude_paths:
- dist/
- ext/
- decoders/

2
nv/html/dwv/.csslintrc Normal file
View File

@@ -0,0 +1,2 @@
--exclude-exts=.min.css
--ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes

View File

@@ -0,0 +1 @@
**/*{.,-}min.js

213
nv/html/dwv/.eslintrc Normal file
View File

@@ -0,0 +1,213 @@
ecmaFeatures:
modules: true
jsx: true
env:
amd: true
browser: true
es6: true
jquery: true
node: true
# http://eslint.org/docs/rules/
rules:
# Possible Errors
comma-dangle: [2, never]
no-cond-assign: 2
no-console: 0
no-constant-condition: 2
no-control-regex: 2
no-debugger: 2
no-dupe-args: 2
no-dupe-keys: 2
no-duplicate-case: 2
no-empty: 2
no-empty-character-class: 2
no-ex-assign: 2
no-extra-boolean-cast: 2
no-extra-parens: 0
no-extra-semi: 2
no-func-assign: 2
no-inner-declarations: [2, functions]
no-invalid-regexp: 2
no-irregular-whitespace: 2
no-negated-in-lhs: 2
no-obj-calls: 2
no-regex-spaces: 2
no-sparse-arrays: 2
no-unexpected-multiline: 2
no-unreachable: 2
use-isnan: 2
valid-jsdoc: 0
valid-typeof: 2
# Best Practices
accessor-pairs: 2
block-scoped-var: 0
complexity: [2, 6]
consistent-return: 0
curly: 0
default-case: 0
dot-location: 0
dot-notation: 0
eqeqeq: 2
guard-for-in: 2
no-alert: 2
no-caller: 2
no-case-declarations: 2
no-div-regex: 2
no-else-return: 0
no-empty-label: 2
no-empty-pattern: 2
no-eq-null: 2
no-eval: 2
no-extend-native: 2
no-extra-bind: 2
no-fallthrough: 2
no-floating-decimal: 0
no-implicit-coercion: 0
no-implied-eval: 2
no-invalid-this: 0
no-iterator: 2
no-labels: 0
no-lone-blocks: 2
no-loop-func: 2
no-magic-number: 0
no-multi-spaces: 0
no-multi-str: 0
no-native-reassign: 2
no-new-func: 2
no-new-wrappers: 2
no-new: 2
no-octal-escape: 2
no-octal: 2
no-proto: 2
no-redeclare: 2
no-return-assign: 2
no-script-url: 2
no-self-compare: 2
no-sequences: 0
no-throw-literal: 0
no-unused-expressions: 2
no-useless-call: 2
no-useless-concat: 2
no-void: 2
no-warning-comments: 0
no-with: 2
radix: 2
vars-on-top: 0
wrap-iife: 2
yoda: 0
# Strict
strict: 0
# Variables
init-declarations: 0
no-catch-shadow: 2
no-delete-var: 2
no-label-var: 2
no-shadow-restricted-names: 2
no-shadow: 0
no-undef-init: 2
no-undef: 0
no-undefined: 0
no-unused-vars: 0
no-use-before-define: 0
# Node.js and CommonJS
callback-return: 2
global-require: 2
handle-callback-err: 2
no-mixed-requires: 0
no-new-require: 0
no-path-concat: 2
no-process-exit: 2
no-restricted-modules: 0
no-sync: 0
# Stylistic Issues
array-bracket-spacing: 0
block-spacing: 0
brace-style: 0
camelcase: 0
comma-spacing: 0
comma-style: 0
computed-property-spacing: 0
consistent-this: 0
eol-last: 0
func-names: 0
func-style: 0
id-length: 0
id-match: 0
indent: 0
jsx-quotes: 0
key-spacing: 0
linebreak-style: 0
lines-around-comment: 0
max-depth: 0
max-len: 0
max-nested-callbacks: 0
max-params: 0
max-statements: [2, 30]
new-cap: 0
new-parens: 0
newline-after-var: 0
no-array-constructor: 0
no-bitwise: 0
no-continue: 0
no-inline-comments: 0
no-lonely-if: 0
no-mixed-spaces-and-tabs: 0
no-multiple-empty-lines: 0
no-negated-condition: 0
no-nested-ternary: 0
no-new-object: 0
no-plusplus: 0
no-restricted-syntax: 0
no-spaced-func: 0
no-ternary: 0
no-trailing-spaces: 0
no-underscore-dangle: 0
no-unneeded-ternary: 0
object-curly-spacing: 0
one-var: 0
operator-assignment: 0
operator-linebreak: 0
padded-blocks: 0
quote-props: 0
quotes: 0
require-jsdoc: 0
semi-spacing: 0
semi: 0
sort-vars: 0
space-after-keywords: 0
space-before-blocks: 0
space-before-function-paren: 0
space-before-keywords: 0
space-in-parens: 0
space-infix-ops: 0
space-return-throw-case: 0
space-unary-ops: 0
spaced-comment: 0
wrap-regex: 0
# ECMAScript 6
arrow-body-style: 0
arrow-parens: 0
arrow-spacing: 0
constructor-super: 0
generator-star-spacing: 0
no-arrow-condition: 0
no-class-assign: 0
no-const-assign: 0
no-dupe-class-members: 0
no-this-before-super: 0
no-var: 0
object-shorthand: 0
prefer-arrow-callback: 0
prefer-const: 0
prefer-reflect: 0
prefer-spread: 0
prefer-template: 0
require-yield: 0

33
nv/html/dwv/.gitattributes vendored Normal file
View File

@@ -0,0 +1,33 @@
# Auto detect text files and perform LF normalization
* text=auto
# source code
*.js text
*.json text
*.lua text
*.sh text
*.html text
*.css text
*.xml text
*.svg text
# git config
.gitattributes text
.gitignore text
# misc config
.jshintrc text
.project text
*.epf text
*.webapp text
*.yml text
*.map text
# documentation
*.md text
# binary (should be left untouched)
*.dcm binary
*.png binary
*.jpg binary
*.gif binary

38
nv/html/dwv/.github/contributing.md vendored Normal file
View File

@@ -0,0 +1,38 @@
Contributing to DWV
===================
First off, thanks for taking the time to contribute!
The following is a set of guidelines for contributing to DWV,
which is hosted at https://github.com/ivmartel/dwv on GitHub.
Steps
-----
If something is not right, the first step is to submit an issue with as much detail
about your problem and your configuration. This is to make sure this behaviour is not
intended (a 'feature').
The second step, for the braves, is to fork the repository and work on a fix. Don't hesitate
to ask for help, I am here for that! Once finished, you can propose a pull request. I will review
it, make comments and hopefully merge it.
License Terms
-------------
Code committed by you to this repository, whether written by you or a third party, must be
governed by the GNU General Public License version 3 ([GNU GPL v3](http://www.gnu.org/licenses/gpl-3.0.en.html)). By contributing Code,
you confirm that, to the best of your knowledge, the code does not violate the
rights of any person or entity.
You hereby grant me (Yves Martelli) and to recipients of software distributed by me
a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright
license to reproduce, prepare derivative works of, publicly display, publicly perform,
sublicense, relicense, and distribute Your Contributions and such derivative works. Except for this license
You reserve all right, title, and interest in and to Your Contributions.
_In plain English, I do this to simplify the licensing process and not have to ask every contributor
for his approval each time. Rest assured, the code and your contributions will always stay GPL._
Some references about Contributor License Agreement (CLA):
* This text was inspired from [The Apache Software Foundation Individual Contributor License Agreement](https://www.apache.org/licenses/icla.txt)
* [in-defense-of-contributor-license-agreements](https://julien.ponge.org/blog/in-defense-of-contributor-license-agreements/)
* [should-open-source-communities-avoid-contributor-agreements](http://www.computerworlduk.com/blogs/simon-says/should-open-source-communities-avoid-contributor-agreements-3569648/)

4
nv/html/dwv/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
/.settings
build
node_modules
bower_components

13
nv/html/dwv/.jshintrc Normal file
View File

@@ -0,0 +1,13 @@
{
"browser": true,
"devel": true,
"jquery": true,
"unused": true,
"undef": true,
"globals": {
"dwv": true
},
"curly": true,
"newcap": true,
"indent": 4
}

16
nv/html/dwv/.travis.yml Normal file
View File

@@ -0,0 +1,16 @@
# not using sudo
sudo: false
language: node_js
node_js:
- '4'
# setup the travis token
env:
global:
- secure: jWTxnnLGmoM+j3148tIF2SJMEyub2j9kmR15vEKVeP6BbUvNgWH9jTSwf6Ddv3qjbAb3D8p9nhYBOZgRub1stwjWCH+DS17AoKFeRVj4Q8Sf0XBHGzJbn0FkstilVmGv3Zr/FVmDSEm1xSSHanWCUQX0uH9r/XB8z7khp4pLryo=
# update gh-pages if all good
after_success:
- chmod +x ./resources/scripts/update-gh-pages.sh
- ./resources/scripts/update-gh-pages.sh

72
nv/html/dwv/Gruntfile.js Normal file
View File

@@ -0,0 +1,72 @@
/* global module */
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
jshint: {
files: ['Gruntfile.js', 'src/**/*.js', 'viewers/**/*.js', 'tests/**/*.js'],
options: {
jshintrc: '.jshintrc'
}
},
qunit: {
all: ['tests/index.html'],
options: {
'--web-security': 'no',
coverage: {
disposeCollector: true,
src: [ "src/**/*.js" ],
instrumentedFiles: "/tmp/ivmartel/dwv",
htmlReport: "build/report/coverage",
lcovReport: "build/report/lcov",
linesThresholdPct: 0
}
}
},
coveralls: {
options: {
// don't fail if coveralls fails
force: true
},
main_target: {
src: "build/report/lcov/lcov.info"
}
},
concat: {
dist: {
src: ['resources/module/intro.js', 'src/**/*.js', 'resources/module/outro.js'],
dest: 'build/dist/<%= pkg.name %>.js'
}
},
uglify: {
options: {
banner: '/*! <%= pkg.name %> <%= pkg.version %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
},
dist: {
files: {
'build/dist/<%= pkg.name %>-<%= pkg.version %>.min.js': ['<%= concat.dist.dest %>']
}
}
},
jsdoc: {
dist : {
src: ['src/**/*.js', 'tests/**/*.js', 'resources/doc/readme-doc.md'],
options: {
destination: 'build/doc',
template: 'node_modules/ink-docstrap/template',
configure: 'resources/doc/jsdoc.conf.json'
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-qunit-istanbul');
grunt.loadNpmTasks('grunt-coveralls');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-jsdoc');
// Task to run tests
grunt.registerTask('publish', ['jshint', 'qunit', 'coveralls', 'concat', 'uglify', 'jsdoc']);
};

45
nv/html/dwv/bower.json Normal file
View File

@@ -0,0 +1,45 @@
{
"name": "dwv",
"description": "DICOM Web Viewer.",
"keywords": ["DICOM", "medical", "imaging"],
"license": "GPL-3.0",
"authors" : ["ivmartel <ivmartel@gmail.com>"],
"homepage": "https://ivmartel.github.io/dwv/",
"repository": {
"type": "git",
"url": "git://github.com/ivmartel/dwv.git"
},
"main": "dist/dwv.js",
"dependencies": {
"modernizr": "~3.5.0",
"i18next": "~10.0.7",
"i18next-xhr-backend": "~1.5.0",
"i18next-browser-languagedetector": "~2.1.0",
"jszip": "~3.1.3",
"konva": "~1.7.3"
},
"devDependencies": {
"qunit": "~2.4.0"
},
"moduleType": [
"amd",
"globals",
"node"
],
"ignore": [
"**/.*",
"css",
"ext",
"resources/conquest",
"resources/doc",
"resources/module",
"resources/scripts",
"src",
"tests",
"viewers",
"eclipse.epf",
"Gruntfile.js",
"manifest.json",
"package.json"
]
}

36
nv/html/dwv/css/style.css Normal file
View File

@@ -0,0 +1,36 @@
body { font-family: Arial, Helvetica, sans-serif; }
/* Layers */
.layerContainer { position: relative; padding: 0; }
.imageLayer { position: absolute; }
.drawDiv { position: absolute; pointer-events: none; }
.dropBox { border: 5px dashed #ccc; }
.dropBox.hover { border: 5px dashed #cc0; }
/* Info */
.info { color: #cde; text-shadow: 1px 1px #000; font-size: 80%; }
.infoc { color: #ff0; text-shadow: 1px 1px #000; font-size: 120%; }
.infotl { position: absolute; top: 0; left: 0; text-align: left; }
.infotc { position: absolute; top: 0; left: 50%; right: 50%; text-align: center; }
.infotr { position: absolute; top: 0; right: 0; text-align: right; }
.infocl { position: absolute; bottom: 50%; left: 0; text-align: left; }
.infocr { position: absolute; bottom: 50%; right: 2px; text-align: right; }
.infobl { position: absolute; bottom: 0; left: 0; text-align: left; }
.infobc { position: absolute; bottom: 0; left: 50%; right: 50%; text-align: center; }
.infobr { position: absolute; bottom: 0; right: 0; text-align: right; }
.plot { position: absolute; width: 100px; height: 50px; bottom: 15px; right: 0; }
.infoLayer ul { margin: 0; padding: 2px; list-style-type: none; }
.infoLayer li { margin-top: 0; }
.infoLayer canvas { margin: 0; padding: 2px; }
/* Tag list */
table.tagsTable { border-collapse: collapse; }
table.tagsTable thead th { text-transform: uppercase;
font-weight: bold; opacity: 0.5;}
table.drawsTable { border-collapse: collapse; }
table.drawsTable td { vertical-align: middle; }
table.drawsTable thead th { text-transform: uppercase;
font-weight: bold; opacity: 0.5;}
.highlighted { background: #f87217; }
.tags form { width: 50%; }

View File

@@ -0,0 +1,185 @@
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* Copyright 2012 Mozilla Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
/* This class implements the QM Coder decoding as defined in
* JPEG 2000 Part I Final Committee Draft Version 1.0
* Annex C.3 Arithmetic decoding procedure
* available at http://www.jpeg.org/public/fcd15444-1.pdf
*
* The arithmetic decoder is used in conjunction with context models to decode
* JPEG2000 and JBIG2 streams.
*/
var ArithmeticDecoder = (function ArithmeticDecoderClosure() {
// Table C-2
var QeTable = [
{qe: 0x5601, nmps: 1, nlps: 1, switchFlag: 1},
{qe: 0x3401, nmps: 2, nlps: 6, switchFlag: 0},
{qe: 0x1801, nmps: 3, nlps: 9, switchFlag: 0},
{qe: 0x0AC1, nmps: 4, nlps: 12, switchFlag: 0},
{qe: 0x0521, nmps: 5, nlps: 29, switchFlag: 0},
{qe: 0x0221, nmps: 38, nlps: 33, switchFlag: 0},
{qe: 0x5601, nmps: 7, nlps: 6, switchFlag: 1},
{qe: 0x5401, nmps: 8, nlps: 14, switchFlag: 0},
{qe: 0x4801, nmps: 9, nlps: 14, switchFlag: 0},
{qe: 0x3801, nmps: 10, nlps: 14, switchFlag: 0},
{qe: 0x3001, nmps: 11, nlps: 17, switchFlag: 0},
{qe: 0x2401, nmps: 12, nlps: 18, switchFlag: 0},
{qe: 0x1C01, nmps: 13, nlps: 20, switchFlag: 0},
{qe: 0x1601, nmps: 29, nlps: 21, switchFlag: 0},
{qe: 0x5601, nmps: 15, nlps: 14, switchFlag: 1},
{qe: 0x5401, nmps: 16, nlps: 14, switchFlag: 0},
{qe: 0x5101, nmps: 17, nlps: 15, switchFlag: 0},
{qe: 0x4801, nmps: 18, nlps: 16, switchFlag: 0},
{qe: 0x3801, nmps: 19, nlps: 17, switchFlag: 0},
{qe: 0x3401, nmps: 20, nlps: 18, switchFlag: 0},
{qe: 0x3001, nmps: 21, nlps: 19, switchFlag: 0},
{qe: 0x2801, nmps: 22, nlps: 19, switchFlag: 0},
{qe: 0x2401, nmps: 23, nlps: 20, switchFlag: 0},
{qe: 0x2201, nmps: 24, nlps: 21, switchFlag: 0},
{qe: 0x1C01, nmps: 25, nlps: 22, switchFlag: 0},
{qe: 0x1801, nmps: 26, nlps: 23, switchFlag: 0},
{qe: 0x1601, nmps: 27, nlps: 24, switchFlag: 0},
{qe: 0x1401, nmps: 28, nlps: 25, switchFlag: 0},
{qe: 0x1201, nmps: 29, nlps: 26, switchFlag: 0},
{qe: 0x1101, nmps: 30, nlps: 27, switchFlag: 0},
{qe: 0x0AC1, nmps: 31, nlps: 28, switchFlag: 0},
{qe: 0x09C1, nmps: 32, nlps: 29, switchFlag: 0},
{qe: 0x08A1, nmps: 33, nlps: 30, switchFlag: 0},
{qe: 0x0521, nmps: 34, nlps: 31, switchFlag: 0},
{qe: 0x0441, nmps: 35, nlps: 32, switchFlag: 0},
{qe: 0x02A1, nmps: 36, nlps: 33, switchFlag: 0},
{qe: 0x0221, nmps: 37, nlps: 34, switchFlag: 0},
{qe: 0x0141, nmps: 38, nlps: 35, switchFlag: 0},
{qe: 0x0111, nmps: 39, nlps: 36, switchFlag: 0},
{qe: 0x0085, nmps: 40, nlps: 37, switchFlag: 0},
{qe: 0x0049, nmps: 41, nlps: 38, switchFlag: 0},
{qe: 0x0025, nmps: 42, nlps: 39, switchFlag: 0},
{qe: 0x0015, nmps: 43, nlps: 40, switchFlag: 0},
{qe: 0x0009, nmps: 44, nlps: 41, switchFlag: 0},
{qe: 0x0005, nmps: 45, nlps: 42, switchFlag: 0},
{qe: 0x0001, nmps: 45, nlps: 43, switchFlag: 0},
{qe: 0x5601, nmps: 46, nlps: 46, switchFlag: 0}
];
// C.3.5 Initialisation of the decoder (INITDEC)
function ArithmeticDecoder(data, start, end) {
this.data = data;
this.bp = start;
this.dataEnd = end;
this.chigh = data[start];
this.clow = 0;
this.byteIn();
this.chigh = ((this.chigh << 7) & 0xFFFF) | ((this.clow >> 9) & 0x7F);
this.clow = (this.clow << 7) & 0xFFFF;
this.ct -= 7;
this.a = 0x8000;
}
ArithmeticDecoder.prototype = {
// C.3.4 Compressed data input (BYTEIN)
byteIn: function ArithmeticDecoder_byteIn() {
var data = this.data;
var bp = this.bp;
if (data[bp] === 0xFF) {
var b1 = data[bp + 1];
if (b1 > 0x8F) {
this.clow += 0xFF00;
this.ct = 8;
} else {
bp++;
this.clow += (data[bp] << 9);
this.ct = 7;
this.bp = bp;
}
} else {
bp++;
this.clow += bp < this.dataEnd ? (data[bp] << 8) : 0xFF00;
this.ct = 8;
this.bp = bp;
}
if (this.clow > 0xFFFF) {
this.chigh += (this.clow >> 16);
this.clow &= 0xFFFF;
}
},
// C.3.2 Decoding a decision (DECODE)
readBit: function ArithmeticDecoder_readBit(contexts, pos) {
// contexts are packed into 1 byte:
// highest 7 bits carry cx.index, lowest bit carries cx.mps
var cx_index = contexts[pos] >> 1, cx_mps = contexts[pos] & 1;
var qeTableIcx = QeTable[cx_index];
var qeIcx = qeTableIcx.qe;
var d;
var a = this.a - qeIcx;
if (this.chigh < qeIcx) {
// exchangeLps
if (a < qeIcx) {
a = qeIcx;
d = cx_mps;
cx_index = qeTableIcx.nmps;
} else {
a = qeIcx;
d = 1 ^ cx_mps;
if (qeTableIcx.switchFlag === 1) {
cx_mps = d;
}
cx_index = qeTableIcx.nlps;
}
} else {
this.chigh -= qeIcx;
if ((a & 0x8000) !== 0) {
this.a = a;
return cx_mps;
}
// exchangeMps
if (a < qeIcx) {
d = 1 ^ cx_mps;
if (qeTableIcx.switchFlag === 1) {
cx_mps = d;
}
cx_index = qeTableIcx.nlps;
} else {
d = cx_mps;
cx_index = qeTableIcx.nmps;
}
}
// C.3.3 renormD;
do {
if (this.ct === 0) {
this.byteIn();
}
a <<= 1;
this.chigh = ((this.chigh << 1) & 0xFFFF) | ((this.clow >> 15) & 1);
this.clow = (this.clow << 1) & 0xFFFF;
this.ct--;
} while ((a & 0x8000) === 0);
this.a = a;
contexts[pos] = cx_index << 1 | cx_mps;
return d;
}
};
return ArithmeticDecoder;
})();

View File

@@ -0,0 +1,18 @@
/**
* JPEG 2000 decoder worker.
*/
// Do not warn if these variables were not defined before.
/* global importScripts, self, JpxImage */
importScripts('jpx.js', 'util.js', 'arithmetic_decoder.js');
self.addEventListener('message', function (event) {
// decode DICOM buffer
var decoder = new JpxImage();
decoder.parse( event.data.buffer );
// post decoded data
var res = decoder.tiles[0].items;
self.postMessage([res]);
}, false);

View File

@@ -0,0 +1,18 @@
/**
* JPEG Baseline decoder worker.
*/
// Do not warn if these variables were not defined before.
/* global importScripts, self, JpegImage */
importScripts('jpg.js');
self.addEventListener('message', function (event) {
// decode DICOM buffer
var decoder = new JpegImage();
decoder.parse( event.data.buffer );
// post decoded data
var res = decoder.getData(decoder.width,decoder.height);
self.postMessage([res]);
}, false);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
Third Party: pdf.js
=====================
* Web: https://github.com/mozilla/pdf.js
* Version: v1.1.1 (pdf.js) and commit fcaf281 of jpambrun
* Date: copied on 05/05/2015
* Download:
* [jpg.js](https://github.com/mozilla/pdf.js/blob/master/src/core/jpg.js) modified as in
https://github.com/notmasteryet/jpgjs/pull/33
* [jpx.js](https://github.com/jpambrun/jpx-medical/blob/master/jpx.js)
* [arithmetic_decoder.js](https://github.com/mozilla/pdf.js/blob/v1.1.1/src/core/arithmetic_decoder.js)
* [util.js](https://github.com/mozilla/pdf.js/blob/v1.1.1/src/shared/util.js)
* License: Apache 2.0 (see [license.txt](https://github.com/mozilla/pdf.js/blob/master/LICENSE))
* Description: Mozilla's JPEG and JPEG2000 decoder from PDF.js with added support for 16 bit signed grayscale images.
* Purpose for dwv: read DICOM files containing JPEG or JPEG2000 data.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
/**
* JPEG Lossless decoder worker.
*/
// Do not warn if these variables were not defined before.
/* global importScripts, self, jpeg */
importScripts('lossless-min.js');
self.addEventListener('message', function (event) {
// bytes per element
var bpe = event.data.bitsAllocated / 8;
// decode DICOM buffer
var buf = new Uint8Array(event.data.buffer);
var decoder = new jpeg.lossless.Decoder();
var decoded = decoder.decode(buf.buffer, 0, buf.buffer.byteLength, bpe);
// post decoded data
var res = null;
if (event.data.bitsAllocated === 8) {
if (event.data.isSigned) {
res = new Int8Array(decoded.buffer);
}
else {
res = new Uint8Array(decoded.buffer);
}
}
else if (event.data.bitsAllocated === 16) {
if (event.data.isSigned) {
res = new Int16Array(decoded.buffer);
}
else {
res = new Uint16Array(decoded.buffer);
}
}
self.postMessage([res]);
}, false);

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
Third Party: rii-mango
======================
JPEGLosslessDecoderJS
---------------------
* Web: https://github.com/rii-mango/JPEGLosslessDecoderJS
* Version: [2.0.2](https://github.com/rii-mango/JPEGLosslessDecoderJS/releases/tag/v2.0.2)
* Date: 19/03/2017
* Download: see release
* License: MIT (see https://github.com/rii-mango/JPEGLosslessDecoderJS/blob/v2.0.2/LICENSE)
* Description: JPEG Lossless decoder.
* Purpose for dwv: Decode JPEG embeded in DICOM.

25789
nv/html/dwv/dist/dwv.js vendored Normal file

File diff suppressed because it is too large Load Diff

3
nv/html/dwv/dist/dwv.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,22 @@
Copyright (c) 2007-2014 IOLA and Ole Laursen
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,13 @@
Third Party: flot
=================
* Web: http://www.flotcharts.org/
* Version: [0.8.3](http://www.flotcharts.org/blog/2014/04/21/flot-083-released/)
* Date: 21/04/2014
* Download: [flot-0.8.3.zip](http://www.flotcharts.org/downloads/flot-0.8.3.zip)
* License: [MIT](http://www.opensource.org/licenses/mit-license.php)
(see [license.txt](/ivmartel/dwv/blob/master/ext/flot/license.txt))
* Description: Flot is a pure Javascript plotting library for jQuery.
It produces graphical plots of arbitrary datasets on-the-fly
client-side.
* Purpose for dwv: Used for the plotting of the image data histogram.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,263 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.i18nextBrowserLanguageDetector = factory());
}(this, function () { 'use strict';
var arr = [];
var each = arr.forEach;
var slice = arr.slice;
function defaults(obj) {
each.call(slice.call(arguments, 1), function (source) {
if (source) {
for (var prop in source) {
if (obj[prop] === undefined) obj[prop] = source[prop];
}
}
});
return obj;
}
var cookie = {
create: function create(name, value, minutes, domain) {
var expires = void 0;
if (minutes) {
var date = new Date();
date.setTime(date.getTime() + minutes * 60 * 1000);
expires = '; expires=' + date.toGMTString();
} else expires = '';
domain = domain ? 'domain=' + domain + ';' : '';
document.cookie = name + '=' + value + expires + ';' + domain + 'path=/';
},
read: function read(name) {
var nameEQ = name + '=';
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1, c.length);
}if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
}
return null;
},
remove: function remove(name) {
this.create(name, '', -1);
}
};
var cookie$1 = {
name: 'cookie',
lookup: function lookup(options) {
var found = void 0;
if (options.lookupCookie && typeof document !== 'undefined') {
var c = cookie.read(options.lookupCookie);
if (c) found = c;
}
return found;
},
cacheUserLanguage: function cacheUserLanguage(lng, options) {
if (options.lookupCookie && typeof document !== 'undefined') {
cookie.create(options.lookupCookie, lng, options.cookieMinutes, options.cookieDomain);
}
}
};
var querystring = {
name: 'querystring',
lookup: function lookup(options) {
var found = void 0;
if (typeof window !== 'undefined') {
var query = window.location.search.substring(1);
var params = query.split('&');
for (var i = 0; i < params.length; i++) {
var pos = params[i].indexOf('=');
if (pos > 0) {
var key = params[i].substring(0, pos);
if (key === options.lookupQuerystring) {
found = params[i].substring(pos + 1);
}
}
}
}
return found;
}
};
var hasLocalStorageSupport = void 0;
try {
hasLocalStorageSupport = window !== 'undefined' && window.localStorage !== null;
var testKey = 'i18next.translate.boo';
window.localStorage.setItem(testKey, 'foo');
window.localStorage.removeItem(testKey);
} catch (e) {
hasLocalStorageSupport = false;
}
var localStorage = {
name: 'localStorage',
lookup: function lookup(options) {
var found = void 0;
if (options.lookupLocalStorage && hasLocalStorageSupport) {
var lng = window.localStorage.getItem(options.lookupLocalStorage);
if (lng) found = lng;
}
return found;
},
cacheUserLanguage: function cacheUserLanguage(lng, options) {
if (options.lookupLocalStorage && hasLocalStorageSupport) {
window.localStorage.setItem(options.lookupLocalStorage, lng);
}
}
};
var navigator$1 = {
name: 'navigator',
lookup: function lookup(options) {
var found = [];
if (typeof navigator !== 'undefined') {
if (navigator.languages) {
// chrome only; not an array, so can't use .push.apply instead of iterating
for (var i = 0; i < navigator.languages.length; i++) {
found.push(navigator.languages[i]);
}
}
if (navigator.userLanguage) {
found.push(navigator.userLanguage);
}
if (navigator.language) {
found.push(navigator.language);
}
}
return found.length > 0 ? found : undefined;
}
};
var htmlTag = {
name: 'htmlTag',
lookup: function lookup(options) {
var found = void 0;
var htmlTag = options.htmlTag || (typeof document !== 'undefined' ? document.documentElement : null);
if (htmlTag && typeof htmlTag.getAttribute === 'function') {
found = htmlTag.getAttribute('lang');
}
return found;
}
};
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function getDefaults() {
return {
order: ['querystring', 'cookie', 'localStorage', 'navigator', 'htmlTag'],
lookupQuerystring: 'lng',
lookupCookie: 'i18next',
lookupLocalStorage: 'i18nextLng',
// cache user language
caches: ['localStorage'],
excludeCacheFor: ['cimode']
//cookieMinutes: 10,
//cookieDomain: 'myDomain'
};
}
var Browser = function () {
function Browser(services) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, Browser);
this.type = 'languageDetector';
this.detectors = {};
this.init(services, options);
}
_createClass(Browser, [{
key: 'init',
value: function init(services) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var i18nOptions = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
this.services = services;
this.options = defaults(options, this.options || {}, getDefaults());
this.i18nOptions = i18nOptions;
this.addDetector(cookie$1);
this.addDetector(querystring);
this.addDetector(localStorage);
this.addDetector(navigator$1);
this.addDetector(htmlTag);
}
}, {
key: 'addDetector',
value: function addDetector(detector) {
this.detectors[detector.name] = detector;
}
}, {
key: 'detect',
value: function detect(detectionOrder) {
var _this = this;
if (!detectionOrder) detectionOrder = this.options.order;
var detected = [];
detectionOrder.forEach(function (detectorName) {
if (_this.detectors[detectorName]) {
var lookup = _this.detectors[detectorName].lookup(_this.options);
if (lookup && typeof lookup === 'string') lookup = [lookup];
if (lookup) detected = detected.concat(lookup);
}
});
var found = void 0;
detected.forEach(function (lng) {
if (found) return;
var cleanedLng = _this.services.languageUtils.formatLanguageCode(lng);
if (_this.services.languageUtils.isWhitelisted(cleanedLng)) found = cleanedLng;
});
return found || this.i18nOptions.fallbackLng[0];
}
}, {
key: 'cacheUserLanguage',
value: function cacheUserLanguage(lng, caches) {
var _this2 = this;
if (!caches) caches = this.options.caches;
if (!caches) return;
if (this.options.excludeCacheFor && this.options.excludeCacheFor.indexOf(lng) > -1) return;
caches.forEach(function (cacheName) {
if (_this2.detectors[cacheName]) _this2.detectors[cacheName].cacheUserLanguage(lng, _this2.options);
});
}
}]);
return Browser;
}();
Browser.type = 'languageDetector';
return Browser;
}));

View File

@@ -0,0 +1 @@
!function(e,o){"object"==typeof exports&&"undefined"!=typeof module?module.exports=o():"function"==typeof define&&define.amd?define(o):e.i18nextBrowserLanguageDetector=o()}(this,function(){"use strict";function e(e){return i.call(a.call(arguments,1),function(o){if(o)for(var t in o)void 0===e[t]&&(e[t]=o[t])}),e}function o(e,o){if(!(e instanceof o))throw new TypeError("Cannot call a class as a function")}function t(){return{order:["querystring","cookie","localStorage","navigator","htmlTag"],lookupQuerystring:"lng",lookupCookie:"i18next",lookupLocalStorage:"i18nextLng",caches:["localStorage"],excludeCacheFor:["cimode"]}}var n=[],i=n.forEach,a=n.slice,r={create:function(e,o,t,n){var i=void 0;if(t){var a=new Date;a.setTime(a.getTime()+60*t*1e3),i="; expires="+a.toGMTString()}else i="";n=n?"domain="+n+";":"",document.cookie=e+"="+o+i+";"+n+"path=/"},read:function(e){for(var o=e+"=",t=document.cookie.split(";"),n=0;n<t.length;n++){for(var i=t[n];" "===i.charAt(0);)i=i.substring(1,i.length);if(0===i.indexOf(o))return i.substring(o.length,i.length)}return null},remove:function(e){this.create(e,"",-1)}},u={name:"cookie",lookup:function(e){var o=void 0;if(e.lookupCookie&&"undefined"!=typeof document){var t=r.read(e.lookupCookie);t&&(o=t)}return o},cacheUserLanguage:function(e,o){o.lookupCookie&&"undefined"!=typeof document&&r.create(o.lookupCookie,e,o.cookieMinutes,o.cookieDomain)}},c={name:"querystring",lookup:function(e){var o=void 0;if("undefined"!=typeof window)for(var t=window.location.search.substring(1),n=t.split("&"),i=0;i<n.length;i++){var a=n[i].indexOf("=");if(a>0){var r=n[i].substring(0,a);r===e.lookupQuerystring&&(o=n[i].substring(a+1))}}return o}},l=void 0;try{l="undefined"!==window&&null!==window.localStorage;var s="i18next.translate.boo";window.localStorage.setItem(s,"foo"),window.localStorage.removeItem(s)}catch(g){l=!1}var f={name:"localStorage",lookup:function(e){var o=void 0;if(e.lookupLocalStorage&&l){var t=window.localStorage.getItem(e.lookupLocalStorage);t&&(o=t)}return o},cacheUserLanguage:function(e,o){o.lookupLocalStorage&&l&&window.localStorage.setItem(o.lookupLocalStorage,e)}},d={name:"navigator",lookup:function(e){var o=[];if("undefined"!=typeof navigator){if(navigator.languages)for(var t=0;t<navigator.languages.length;t++)o.push(navigator.languages[t]);navigator.userLanguage&&o.push(navigator.userLanguage),navigator.language&&o.push(navigator.language)}return o.length>0?o:void 0}},v={name:"htmlTag",lookup:function(e){var o=void 0,t=e.htmlTag||("undefined"!=typeof document?document.documentElement:null);return t&&"function"==typeof t.getAttribute&&(o=t.getAttribute("lang")),o}},h=function(){function e(e,o){for(var t=0;t<o.length;t++){var n=o[t];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(o,t,n){return t&&e(o.prototype,t),n&&e(o,n),o}}(),p=function(){function n(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};o(this,n),this.type="languageDetector",this.detectors={},this.init(e,t)}return h(n,[{key:"init",value:function(o){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};this.services=o,this.options=e(n,this.options||{},t()),this.i18nOptions=i,this.addDetector(u),this.addDetector(c),this.addDetector(f),this.addDetector(d),this.addDetector(v)}},{key:"addDetector",value:function(e){this.detectors[e.name]=e}},{key:"detect",value:function(e){var o=this;e||(e=this.options.order);var t=[];e.forEach(function(e){if(o.detectors[e]){var n=o.detectors[e].lookup(o.options);n&&"string"==typeof n&&(n=[n]),n&&(t=t.concat(n))}});var n=void 0;return t.forEach(function(e){if(!n){var t=o.services.languageUtils.formatLanguageCode(e);o.services.languageUtils.isWhitelisted(t)&&(n=t)}}),n||this.i18nOptions.fallbackLng[0]}},{key:"cacheUserLanguage",value:function(e,o){var t=this;o||(o=this.options.caches),o&&(this.options.excludeCacheFor&&this.options.excludeCacheFor.indexOf(e)>-1||o.forEach(function(o){t.detectors[o]&&t.detectors[o].cacheUserLanguage(e,t.options)}))}}]),n}();return p.type="languageDetector",p});

View File

@@ -0,0 +1,198 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.i18nextXHRBackend = factory());
}(this, (function () { 'use strict';
var arr = [];
var each = arr.forEach;
var slice = arr.slice;
function defaults(obj) {
each.call(slice.call(arguments, 1), function (source) {
if (source) {
for (var prop in source) {
if (obj[prop] === undefined) obj[prop] = source[prop];
}
}
});
return obj;
}
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
function addQueryString(url, params) {
if (params && (typeof params === 'undefined' ? 'undefined' : _typeof(params)) === 'object') {
var queryString = '',
e = encodeURIComponent;
// Must encode data
for (var paramName in params) {
queryString += '&' + e(paramName) + '=' + e(params[paramName]);
}
if (!queryString) {
return url;
}
url = url + (url.indexOf('?') !== -1 ? '&' : '?') + queryString.slice(1);
}
return url;
}
// https://gist.github.com/Xeoncross/7663273
function ajax(url, options, callback, data, cache) {
if (data && (typeof data === 'undefined' ? 'undefined' : _typeof(data)) === 'object') {
if (!cache) {
data['_t'] = new Date();
}
// URL encoded form data must be in querystring format
data = addQueryString('', data).slice(1);
}
if (options.queryStringParams) {
url = addQueryString(url, options.queryStringParams);
}
try {
var x;
if (XMLHttpRequest) {
x = new XMLHttpRequest();
} else {
x = new ActiveXObject('MSXML2.XMLHTTP.3.0');
}
x.open(data ? 'POST' : 'GET', url, 1);
if (!options.crossDomain) {
x.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
}
x.withCredentials = !!options.withCredentials;
if (data) {
x.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
}
if (x.overrideMimeType) {
x.overrideMimeType("application/json");
}
var h = options.customHeaders;
if (h) {
for (var i in h) {
x.setRequestHeader(i, h[i]);
}
}
x.onreadystatechange = function () {
x.readyState > 3 && callback && callback(x.responseText, x);
};
x.send(data);
} catch (e) {
console && console.log(e);
}
}
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function getDefaults() {
return {
loadPath: '/locales/{{lng}}/{{ns}}.json',
addPath: 'locales/add/{{lng}}/{{ns}}',
allowMultiLoading: false,
parse: JSON.parse,
crossDomain: false,
ajax: ajax
};
}
var Backend = function () {
function Backend(services) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
_classCallCheck(this, Backend);
this.init(services, options);
this.type = 'backend';
}
_createClass(Backend, [{
key: 'init',
value: function init(services) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
this.services = services;
this.options = defaults(options, this.options || {}, getDefaults());
}
}, {
key: 'readMulti',
value: function readMulti(languages, namespaces, callback) {
var loadPath = this.options.loadPath;
if (typeof this.options.loadPath === 'function') {
loadPath = this.options.loadPath(languages, namespaces);
}
var url = this.services.interpolator.interpolate(loadPath, { lng: languages.join('+'), ns: namespaces.join('+') });
this.loadUrl(url, callback);
}
}, {
key: 'read',
value: function read(language, namespace, callback) {
var loadPath = this.options.loadPath;
if (typeof this.options.loadPath === 'function') {
loadPath = this.options.loadPath([language], [namespace]);
}
var url = this.services.interpolator.interpolate(loadPath, { lng: language, ns: namespace });
this.loadUrl(url, callback);
}
}, {
key: 'loadUrl',
value: function loadUrl(url, callback) {
var _this = this;
this.options.ajax(url, this.options, function (data, xhr) {
if (xhr.status >= 500 && xhr.status < 600) return callback('failed loading ' + url, true /* retry */);
if (xhr.status >= 400 && xhr.status < 500) return callback('failed loading ' + url, false /* no retry */);
var ret = void 0,
err = void 0;
try {
ret = _this.options.parse(data, url);
} catch (e) {
err = 'failed parsing ' + url + ' to json';
}
if (err) return callback(err, false);
callback(null, ret);
});
}
}, {
key: 'create',
value: function create(languages, namespace, key, fallbackValue) {
var _this2 = this;
if (typeof languages === 'string') languages = [languages];
var payload = {};
payload[key] = fallbackValue || '';
languages.forEach(function (lng) {
var url = _this2.services.interpolator.interpolate(_this2.options.addPath, { lng: lng, ns: namespace });
_this2.options.ajax(url, _this2.options, function (data, xhr) {
//const statusCode = xhr.status.toString();
// TODO: if statusCode === 4xx do log
}, payload);
});
}
}]);
return Backend;
}();
Backend.type = 'backend';
return Backend;
})));

View File

@@ -0,0 +1 @@
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.i18nextXHRBackend=e()}(this,function(){"use strict";function t(t){return r.call(s.call(arguments,1),function(e){if(e)for(var n in e)void 0===t[n]&&(t[n]=e[n])}),t}function e(t,e){if(e&&"object"===(void 0===e?"undefined":l(e))){var n="",o=encodeURIComponent;for(var i in e)n+="&"+o(i)+"="+o(e[i]);if(!n)return t;t=t+(t.indexOf("?")!==-1?"&":"?")+n.slice(1)}return t}function n(t,n,o,i,a){i&&"object"===(void 0===i?"undefined":l(i))&&(a||(i._t=new Date),i=e("",i).slice(1)),n.queryStringParams&&(t=e(t,n.queryStringParams));try{var r;r=XMLHttpRequest?new XMLHttpRequest:new ActiveXObject("MSXML2.XMLHTTP.3.0"),r.open(i?"POST":"GET",t,1),n.crossDomain||r.setRequestHeader("X-Requested-With","XMLHttpRequest"),r.withCredentials=!!n.withCredentials,i&&r.setRequestHeader("Content-type","application/x-www-form-urlencoded"),r.overrideMimeType&&r.overrideMimeType("application/json");var s=n.customHeaders;if(s)for(var u in s)r.setRequestHeader(u,s[u]);r.onreadystatechange=function(){r.readyState>3&&o&&o(r.responseText,r)},r.send(i)}catch(t){console&&console.log(t)}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function i(){return{loadPath:"/locales/{{lng}}/{{ns}}.json",addPath:"locales/add/{{lng}}/{{ns}}",allowMultiLoading:!1,parse:JSON.parse,crossDomain:!1,ajax:n}}var a=[],r=a.forEach,s=a.slice,l="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},u=function(){function t(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}return function(e,n,o){return n&&t(e.prototype,n),o&&t(e,o),e}}(),c=function(){function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};o(this,e),this.init(t,n),this.type="backend"}return u(e,[{key:"init",value:function(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};this.services=e,this.options=t(n,this.options||{},i())}},{key:"readMulti",value:function(t,e,n){var o=this.options.loadPath;"function"==typeof this.options.loadPath&&(o=this.options.loadPath(t,e));var i=this.services.interpolator.interpolate(o,{lng:t.join("+"),ns:e.join("+")});this.loadUrl(i,n)}},{key:"read",value:function(t,e,n){var o=this.options.loadPath;"function"==typeof this.options.loadPath&&(o=this.options.loadPath([t],[e]));var i=this.services.interpolator.interpolate(o,{lng:t,ns:e});this.loadUrl(i,n)}},{key:"loadUrl",value:function(t,e){var n=this;this.options.ajax(t,this.options,function(o,i){if(i.status>=500&&i.status<600)return e("failed loading "+t,!0);if(i.status>=400&&i.status<500)return e("failed loading "+t,!1);var a=void 0,r=void 0;try{a=n.options.parse(o,t)}catch(e){r="failed parsing "+t+" to json"}if(r)return e(r,!1);e(null,a)})}},{key:"create",value:function(t,e,n,o){var i=this;"string"==typeof t&&(t=[t]);var a={};a[n]=o||"",t.forEach(function(t){var n=i.services.interpolator.interpolate(i.options.addPath,{lng:t,ns:e});i.options.ajax(n,i.options,function(t,e){},a)})}}]),e}();return c.type="backend",c});

View File

@@ -0,0 +1,30 @@
Third Party: i18next
====================
* Web: http://i18next.com/
* Version: [10.0.7](https://github.com/i18next/i18next/releases/tag/v10.0.7)
* Date: 31/10/2017
* Download: https://github.com/i18next/i18next/blob/v10.0.7/i18next.min.js
* License: MIT (see https://github.com/i18next/i18next/blob/v10.0.7/LICENSE)
* Description: internationalization framework.
* Purpose for dwv: internationalization of GUI and messages.
i18next-xhr-backend
-------------------
* Web: https://github.com/i18next/i18next-xhr-backend
* Version: [1.5.0](https://github.com/i18next/i18next-xhr-backend/releases/tag/v1.5.0)
* Date: 06/11/2017
* Download: https://github.com/i18next/i18next-xhr-backend/blob/v1.5.0/i18nextXHRBackend.min.js
* License: MIT (see https://github.com/i18next/i18next-xhr-backend/blob/v1.5.0/LICENSE)
* Description: backend layer for i18next using browsers xhr.
* Purpose for dwv: load translation files.
i18next-browser-languageDetector
--------------------------------
* Web: https://github.com/i18next/i18next-browser-languageDetector
* Version: [2.1.0](https://github.com/i18next/i18next-browser-languageDetector/releases/tag/v2.1.0)
* Date: 06/11/2017
* Download: https://github.com/i18next/i18next-browser-languageDetector/blob/v2.1.0/i18nextBrowserLanguageDetector.min.js
* License: MIT (see https://github.com/i18next/i18next-browser-languageDetector/blob/v2.1.0/LICENSE)
* Description: language detector used in browser environment for i18next
* Purpose for dwv: detect user language.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 240 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Some files were not shown because too many files have changed in this diff Show More