init
395
nv/html/ApiPacs.php
Normal 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
@@ -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;
|
||||
|
||||
|
||||
792
nv/html/adminer/adminer-3.6.3-mysql.php
Normal file
2035
nv/html/adminer/adminer-4.7.5-en.php
Normal file
225
nv/html/adminer/adminer.css
Normal 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
32
nv/html/adminer/edit-foreign.php
Normal 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>";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
15
nv/html/adminer/edit-textarea.php
Normal 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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
345
nv/html/adminer/plugins/plugin.php
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
40
nv/html/adminer/plugins/pretty-json-column.php
Normal 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));
|
||||
}
|
||||
}
|
||||
69
nv/html/adminer/plugins/tables-filter.php
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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ó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();
|
||||
}
|
||||
|
||||
98
nv/html/dcmgw/dcmgwConfig.php
Normal 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
@@ -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
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
phpinfo();
|
||||
18979
nv/html/dcmgw/php_error.log
Normal file
32
nv/html/dcmgw/tmp/DEADJOE
Normal 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
41513
nv/html/dcmgw/tmp/olddebuglog
Normal file
73
nv/html/dcmgw/xml/qr_cfind.xml
Normal 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>
|
||||
36
nv/html/dcmgw/xml/qr_cfind.xsd
Normal 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>
|
||||
35
nv/html/dcmgw/xml/qr_study.xml
Normal 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>
|
||||
47
nv/html/dcmgw/xml/qr_study.xsd
Normal 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>
|
||||
22
nv/html/dwv/.codeclimate.yml
Normal 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
@@ -0,0 +1,2 @@
|
||||
--exclude-exts=.min.css
|
||||
--ignore=adjoining-classes,box-model,ids,order-alphabetical,unqualified-attributes
|
||||
1
nv/html/dwv/.eslintignore
Normal file
@@ -0,0 +1 @@
|
||||
**/*{.,-}min.js
|
||||
213
nv/html/dwv/.eslintrc
Normal 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
@@ -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
@@ -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
@@ -0,0 +1,4 @@
|
||||
/.settings
|
||||
build
|
||||
node_modules
|
||||
bower_components
|
||||
13
nv/html/dwv/.jshintrc
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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%; }
|
||||
185
nv/html/dwv/decoders/pdfjs/arithmetic_decoder.js
Normal 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;
|
||||
})();
|
||||
18
nv/html/dwv/decoders/pdfjs/decode-jpeg2000.js
Normal 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);
|
||||
18
nv/html/dwv/decoders/pdfjs/decode-jpegbaseline.js
Normal 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);
|
||||
1072
nv/html/dwv/decoders/pdfjs/jpg.js
Normal file
2237
nv/html/dwv/decoders/pdfjs/jpx.js
Normal file
15
nv/html/dwv/decoders/pdfjs/readme.md
Normal 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.
|
||||
1588
nv/html/dwv/decoders/pdfjs/util.js
Normal file
37
nv/html/dwv/decoders/rii-mango/decode-jpegloss.js
Normal 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);
|
||||
1
nv/html/dwv/decoders/rii-mango/lossless-min.js
vendored
Normal file
1756
nv/html/dwv/decoders/rii-mango/lossless.js
Normal file
12
nv/html/dwv/decoders/rii-mango/readme.md
Normal 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
3
nv/html/dwv/dist/dwv.min.js
vendored
Normal file
8
nv/html/dwv/ext/flot/jquery.flot.min.js
vendored
Normal file
22
nv/html/dwv/ext/flot/license.txt
Normal 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.
|
||||
13
nv/html/dwv/ext/flot/readme.md
Normal 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.
|
||||
2053
nv/html/dwv/ext/i18next/i18next.js
Normal file
2
nv/html/dwv/ext/i18next/i18next.min.js
vendored
Normal file
263
nv/html/dwv/ext/i18next/i18nextBrowserLanguageDetector.js
Normal 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;
|
||||
|
||||
}));
|
||||
1
nv/html/dwv/ext/i18next/i18nextBrowserLanguageDetector.min.js
vendored
Normal 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});
|
||||
198
nv/html/dwv/ext/i18next/i18nextXHRBackend.js
Normal 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;
|
||||
|
||||
})));
|
||||
1
nv/html/dwv/ext/i18next/i18nextXHRBackend.min.js
vendored
Normal 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});
|
||||
30
nv/html/dwv/ext/i18next/readme.md
Normal 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.
|
||||
BIN
nv/html/dwv/ext/jquery-mobile/images/ajax-loader.gif
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/action-black.png
Normal file
|
After Width: | Height: | Size: 219 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/action-white.png
Normal file
|
After Width: | Height: | Size: 227 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/alert-black.png
Normal file
|
After Width: | Height: | Size: 244 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/alert-white.png
Normal file
|
After Width: | Height: | Size: 243 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/arrow-d-black.png
Normal file
|
After Width: | Height: | Size: 146 B |
|
After Width: | Height: | Size: 167 B |
|
After Width: | Height: | Size: 173 B |
|
After Width: | Height: | Size: 159 B |
|
After Width: | Height: | Size: 171 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/arrow-d-white.png
Normal file
|
After Width: | Height: | Size: 149 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/arrow-l-black.png
Normal file
|
After Width: | Height: | Size: 149 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/arrow-l-white.png
Normal file
|
After Width: | Height: | Size: 156 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/arrow-r-black.png
Normal file
|
After Width: | Height: | Size: 147 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/arrow-r-white.png
Normal file
|
After Width: | Height: | Size: 152 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/arrow-u-black.png
Normal file
|
After Width: | Height: | Size: 147 B |
|
After Width: | Height: | Size: 163 B |
|
After Width: | Height: | Size: 169 B |
|
After Width: | Height: | Size: 163 B |
|
After Width: | Height: | Size: 165 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/arrow-u-white.png
Normal file
|
After Width: | Height: | Size: 151 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/audio-black.png
Normal file
|
After Width: | Height: | Size: 307 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/audio-white.png
Normal file
|
After Width: | Height: | Size: 314 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/back-black.png
Normal file
|
After Width: | Height: | Size: 233 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/back-white.png
Normal file
|
After Width: | Height: | Size: 240 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/bars-black.png
Normal file
|
After Width: | Height: | Size: 132 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/bars-white.png
Normal file
|
After Width: | Height: | Size: 135 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/bullets-black.png
Normal file
|
After Width: | Height: | Size: 147 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/bullets-white.png
Normal file
|
After Width: | Height: | Size: 152 B |
|
After Width: | Height: | Size: 146 B |
|
After Width: | Height: | Size: 143 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/camera-black.png
Normal file
|
After Width: | Height: | Size: 250 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/camera-white.png
Normal file
|
After Width: | Height: | Size: 251 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/carat-d-black.png
Normal file
|
After Width: | Height: | Size: 207 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/carat-d-white.png
Normal file
|
After Width: | Height: | Size: 213 B |
BIN
nv/html/dwv/ext/jquery-mobile/images/icons-png/carat-l-black.png
Normal file
|
After Width: | Height: | Size: 174 B |