orthanc 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fdfad2aeeae25d4ff088160e28a91ea86b64fa01
4
+ data.tar.gz: d87077c820484914845e550b003562b5cb19b6b7
5
+ SHA512:
6
+ metadata.gz: dbe6ececc0c65bc59f7da9f6dc76ebc06227dab0cad6b2af44cb7f259a742f225d9e6d91dc1daee4d45cc3bbaa76c10de30186e093976d0bb69cb4bf8133eeb3
7
+ data.tar.gz: 7f5ac39bbe99b695cce5c3099c954144bbaf12914fd46f9463bc337881d072bf8a34f8d040739903c48c91395975fe8ac2faf1ae1fc1b4578202862ecc50627a
@@ -0,0 +1,12 @@
1
+ lib/.DS_Store
2
+ lib/orthanc/.DS_Store
3
+ /.bundle/
4
+ /.yardoc
5
+ /Gemfile.lock
6
+ /_yardoc/
7
+ /coverage/
8
+ /doc/
9
+ /pkg/
10
+ /spec/reports/
11
+ /tmp/
12
+ *.gem
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in orthanc.gemspec
4
+ gemspec
@@ -0,0 +1,52 @@
1
+ # Orthanc-ruby
2
+
3
+ ##### A Ruby implementation of the [Orthanc](http://orthanc-server.com) DICOM server v0.8.6 REST API
4
+
5
+ ##### Extremely Alpha!! Not ready for production. Anything may change, including resource nesting and naming schemes.
6
+
7
+ (This is my first API client gem, experienced help or advice would be most appreciated) :)
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'orthanc'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install orthanc
24
+
25
+ ## Usage
26
+ The gem tries to follow the Orthanc API naming scheme as closely as possible, converting methods and response items to snake case to make the experience more ruby-like.
27
+
28
+ api=Orthanc::Client.new("localhost", "8042")
29
+ api.all_patients
30
+ api.all_patients.first
31
+ api.system.database_version => 5
32
+ api.statistics.count_studies => 14
33
+
34
+ You get the picture.
35
+
36
+ ## Development
37
+
38
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
39
+
40
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
41
+
42
+ ## Contributing
43
+
44
+ 1. Fork it ( https://github.com/[my-github-username]/orthanc/fork )
45
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
46
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
47
+ 4. Push to the branch (`git push origin my-new-feature`)
48
+ 5. Create a new Pull Request
49
+
50
+ ## License
51
+
52
+ MIT License
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "orthanc"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,9 @@
1
+ require "orthanc/version"
2
+
3
+ require 'rest-client'
4
+ require 'recursive-open-struct'
5
+ require 'plissken'
6
+ require 'orthanc/client'
7
+
8
+ module Orthanc
9
+ end
@@ -0,0 +1,72 @@
1
+ require 'orthanc/tools'
2
+ require 'orthanc/plugins'
3
+ require 'orthanc/modalities'
4
+ require 'orthanc/peers'
5
+ require 'orthanc/patients'
6
+ require 'orthanc/studies'
7
+ require 'orthanc/series'
8
+ require 'orthanc/instances'
9
+
10
+ module Orthanc
11
+ class Client
12
+
13
+ attr_accessor :base_uri
14
+
15
+ def initialize(host,port = 8042)
16
+ self.base_uri = RestClient::Resource.new("http://#{host}:#{port}")
17
+ end
18
+
19
+ # ------------- General -------------
20
+ def system
21
+ objectify(base_uri["system"].get)
22
+ end
23
+
24
+ def statistics
25
+ objectify(base_uri["statistics"].get)
26
+ end
27
+
28
+ def changes(params = {}) # "last", "limit" and "since" arguments
29
+ objectify(base_uri["changes"].get({params: params}))
30
+ end
31
+
32
+ def delete_changes(params = {}) # "last", "limit" and "since" arguments
33
+ objectify(base_uri["changes"].delete({params: params}))
34
+ end
35
+
36
+ def exports(params = {}) # "last", "limit" and "since" arguments
37
+ objectify(base_uri["exports"].get({params: params}))
38
+ end
39
+
40
+ def delete_exports(params = {}) # "last", "limit" and "since" arguments
41
+ objectify(base_uri["exports"].delete({params: params}))
42
+ end
43
+
44
+
45
+ private
46
+
47
+ def bool_to_num(bool)
48
+ return 0 if bool == false
49
+ return 1 if bool == true
50
+ end
51
+
52
+ def num_to_bool(num)
53
+ return false if num == "0"
54
+ return true if num == "1"
55
+ end
56
+
57
+ def lowkey(h)
58
+ Hash[h.map{|k,v| v.class == Array ? [k,v.map{|r| f r}.to_a] : [k.downcase,v]}]
59
+ end
60
+
61
+ def objectify(response)
62
+ if JSON.parse(response).class == Array
63
+ return JSON.parse(response)
64
+ elsif JSON.parse(response).class == Hash
65
+ return RecursiveOpenStruct.new(JSON.parse(response).to_snake_keys, recurse_over_arrays: true )
66
+ else
67
+ return response
68
+ end
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,223 @@
1
+ module Orthanc
2
+ class Client
3
+ # ------------- Instances -------------
4
+
5
+ # GET /instances
6
+ def all_instances
7
+ objectify(base_uri["instances"].get)
8
+ end
9
+
10
+ # POST /instances
11
+ def instances(dicom_file) # POST = Add the new DICOM file given in the POST body
12
+ objectify(base_uri["instances"].post(dicom_file))
13
+ end
14
+
15
+ # GET /instances/{id}
16
+ def instance(id)
17
+ objectify(base_uri["instances/#{id}"].get)
18
+ end
19
+
20
+ # DELETE /instances/{id}
21
+ def delete_instance(id)
22
+ objectify(base_uri["instances/#{id}"].delete)
23
+ end
24
+
25
+ # POST /instances/{id}/anonymize
26
+ def anonymize_instance(id, payload = {}) # https://code.google.com/p/orthanc/wiki/Anonymization
27
+ objectify(base_uri["instances/#{id}/anonymize"].post(payload))
28
+ end
29
+
30
+ # GET /instances/{id}/content/
31
+ def instance_content(id) # List the first-level DICOM tags
32
+ objectify(base_uri["instances/#{id}/frames"].get)
33
+ end
34
+
35
+ # GET /instances/{id}/content/{group}-{element}
36
+ def instance_content_tag(id, group, element) # Raw access to the value of DICOM tags (comprising the padding character)
37
+ objectify(base_uri["instances/#{id}/content/#{group}-#{element}"].get)
38
+ end
39
+
40
+ # GET /instances/{id}/content/{group}-{element}/{index}/...
41
+ def instance_content_sequence(id, group, element, index) # Raw access to the content of DICOM sequences
42
+ objectify(base_uri["instances/#{id}/content/#{group}-#{element}/#{index}"].get)
43
+ end
44
+
45
+ # POST /instances/{id}/export
46
+ def instance_export(id) # Write the DICOM file in the filesystem where Orthanc is running
47
+ objectify(base_uri["instances/#{id}/export"].post)
48
+ end
49
+
50
+ # GET /instances/{id}/file
51
+ def instance_file(id)
52
+ objectify(base_uri["instances/#{id}/file"].get)
53
+ end
54
+
55
+ # GET /instances/{id}/frames
56
+ def instance_frames(id) # Instance frames array
57
+ objectify(base_uri["instances/#{id}/frames"].get)
58
+ end
59
+
60
+ # GET /instances/{id}/frames/{frameNumber}/image-int16
61
+ def instance_frame_image_int16(id, frame_number) # Truncated image to the [-32768;32767] range
62
+ objectify(base_uri["instances/#{id}/frames/#{frame_number}/image-int16"].get)
63
+ end
64
+
65
+ # GET /instances/{id}/frames/{frameNumber}/image-uint16
66
+ def instance_frame_image_uint16(id, frame_number) # Truncated image to the [0;65535] range
67
+ objectify(base_uri["instances/#{id}/frames/#{frame_number}/image-uint16"].get)
68
+ end
69
+
70
+ # GET /instances/{id}/frames/{frameNumber}/image-uint8
71
+ def instance_frame_image_uint8(id, frame_number) # Truncated image to the [0;255] range
72
+ objectify(base_uri["instances/#{id}/frames/#{frame_number}/image-uint8"].get)
73
+ end
74
+
75
+ # GET /instances/{id}/frames/{frameNumber}/matlab
76
+ def instance_frame_matlab(id, frame_number) # a = eval(urlread('http://localhost:8042/instances/.../matlab'))
77
+ objectify(base_uri["instances/#{id}/frames/#{frame_number}/matlab"].get)
78
+ end
79
+
80
+ # GET /instances/{id}/frames/{frameNumber}/preview
81
+ def instance_preview(id, frame_number) # Rescaled image (so that all the range [0;255] is used)
82
+ objectify(base_uri["instances/#{id}/frames/#{frame_number}/preview"].get)
83
+ end
84
+
85
+ # GET /instances/{id}/image-int16
86
+ def instance_image_int16(id) # Truncated image to the [-32768;32767] range
87
+ objectify(base_uri["instances/#{id}/image-int16"].get)
88
+ end
89
+
90
+ # GET /instances/{id}/image-uint16
91
+ def instance_image_uint16(id) # Truncated image to the [0;65535] range
92
+ objectify(base_uri["instances/#{id}/image-uint16"].get)
93
+ end
94
+
95
+ # GET /instances/{id}/image-uint8
96
+ def instance_image_uint8(id) # Truncated image to the [0;255] range
97
+ objectify(base_uri["instances/#{id}/image-uint8"].get)
98
+ end
99
+
100
+ # GET /instances/{id}/matlab
101
+ def instance_matlab(id) # a = eval(urlread('http://localhost:8042/instances/.../matlab'))
102
+ objectify(base_uri["instances/#{id}/matlab"].get)
103
+ end
104
+
105
+ # POST /instances/{id}/modify
106
+ def modify_instance(id, payload = {}) # https://code.google.com/p/orthanc/wiki/Anonymization
107
+ objectify(base_uri["instances/#{id}/modify"].post(payload))
108
+ end
109
+
110
+ # GET /instances/{id}/module
111
+ def instance_module(id)
112
+ objectify(base_uri["instances/#{id}/module"].get)
113
+ end
114
+
115
+ # GET /instances/{id}/patient
116
+ def instance_patient(id)
117
+ objectify(base_uri["instances/#{id}/patient"].get)
118
+ end
119
+
120
+ # GET /instances/{id}/preview
121
+ def instance_preview(id) # Rescaled image (so that all the range [0;255] is used)
122
+ objectify(base_uri["instances/#{id}/preview"].get)
123
+ end
124
+
125
+ # GET /instances/{id}/series
126
+ def instance_series(id)
127
+ objectify(base_uri["instances/#{id}/series"].get)
128
+ end
129
+
130
+ # GET /instances/{id}/simplified-tags
131
+ def instance_shared_tags(id) # "?simplify" argument to simplify output
132
+ objectify(base_uri["instances/#{id}/shared-tags"].get)
133
+ end
134
+
135
+ # GET /instances/{id}/statistics
136
+ def instance_statistics(id)
137
+ objectify(base_uri["instances/#{id}/statistics"].get)
138
+ end
139
+
140
+ # GET /instances/{id}/study
141
+ def instance_study(id)
142
+ objectify(base_uri["instances/#{id}/study"].get)
143
+ end
144
+
145
+ # GET /instances/{id}/tags
146
+ def instance_tags(id) # TODO: "?simplify" argument to simplify output (same as "simplified-tags")
147
+ objectify(base_uri["instances/#{id}/tags"].get)
148
+ end
149
+
150
+ # TODO: Polymorphic resourceType resources. Repetitive. must refactor
151
+
152
+ # GET /{resourceType}/{id}/attachments
153
+ def instance_attachments(id)
154
+ objectify(base_uri["instances/#{id}/attachments"].get)
155
+ end
156
+
157
+ # DELETE /{resourceType}/{id}/attachments/{name}
158
+ def delete_instance_attachment(id, name)
159
+ objectify(base_uri["instances/#{id}/attachments/#{name}"].delete)
160
+ end
161
+
162
+ # PUT /{resourceType}/{id}/attachments/{name}
163
+ def instance_attachment(id, name, payload = {})
164
+ objectify(base_uri["instances/#{id}/attachments/#{name}"].put(payload))
165
+ end
166
+
167
+ # GET /{resourceType}/{id}/attachments/{name}/compressed-data
168
+ def instance_attachment_compressed_data(id, name)
169
+ objectify(base_uri["instances/#{id}/attachments/#{name}/compressed-data"].get)
170
+ end
171
+
172
+ # GET /{resourceType}/{id}/attachments/{name}/compressed-md5
173
+ def instance_attachment_compressed_md5(id, name)
174
+ objectify(base_uri["instances/#{id}/attachments/#{name}/compressed-md5"].get)
175
+ end
176
+
177
+ # GET /{resourceType}/{id}/attachments/{name}/compressed-size
178
+ def instance_attachment_compressed_size(id, name)
179
+ objectify(base_uri["instances/#{id}/attachments/#{name}/compressed-size"].get)
180
+ end
181
+
182
+ # GET /{resourceType}/{id}/attachments/{name}/data
183
+ def instance_attachment_data(id, name)
184
+ objectify(base_uri["instances/#{id}/attachments/#{name}/data"].get)
185
+ end
186
+
187
+ # GET /{resourceType}/{id}/attachments/{name}/md5
188
+ def instance_attachment_md5(id, name)
189
+ objectify(base_uri["instances/#{id}/attachments/#{name}/md5"].get)
190
+ end
191
+
192
+ # GET /{resourceType}/{id}/attachments/{name}/size
193
+ def instance_attachment_size(id, name)
194
+ objectify(base_uri["instances/#{id}/attachments/#{name}/size"].get)
195
+ end
196
+
197
+ # POST /{resourceType}/{id}/attachments/{name}/verify-md5
198
+ def instance_attachment_verify_md5(id, name)
199
+ objectify(base_uri["instances/#{id}/attachments/#{name}/verify-md5"].get)
200
+ end
201
+
202
+ # GET /{resourceType}/{id}/metadata
203
+ def instance_all_metadata(id)
204
+ objectify(base_uri["instances/#{id}/metadata"].get)
205
+ end
206
+
207
+ # GET /{resourceType}/{id}/metadata/{name}
208
+ def instance_metadata(id, name)
209
+ objectify(base_uri["instances/#{id}/metadata/#{name}"].get)
210
+ end
211
+
212
+ # DELETE /{resourceType}/{id}/metadata/{name}
213
+ def instance_delete_metadata(id, name)
214
+ objectify(base_uri["instances/#{id}/metadata/#{name}"].delete)
215
+ end
216
+
217
+ # PUT /{resourceType}/{id}/metadata/{name}
218
+ def instance_update_metadata(id, name, payload = {})
219
+ objectify(base_uri["instances/#{id}/metadata/#{name}"].put(payload))
220
+ end
221
+
222
+ end
223
+ end
@@ -0,0 +1,55 @@
1
+ module Orthanc
2
+ class Client
3
+ # ------------- Modalities -------------
4
+ # GET /modalities
5
+ def modalities
6
+ objectify(base_uri["modalities"].get)
7
+ end
8
+
9
+ # GET /modalities/{dicom}
10
+ def modality(dicom)
11
+ objectify(base_uri["modalities/#{dicom}"].get)
12
+ end
13
+
14
+ # DELETE /modalities/{dicom}
15
+ def delete_modality(dicom)
16
+ objectify(base_uri["modalities/#{dicom}"].delete)
17
+ end
18
+
19
+ # PUT /modalities/{dicom}
20
+ def modify_modality(dicom)
21
+ objectify(base_uri["modalities/#{dicom}"].put)
22
+ end
23
+
24
+ # POST /modalities/{dicom}/echo
25
+ def modality_echo(dicom, payload = {}) # C-Echo SCU
26
+ objectify(base_uri["modalities/#{dicom}/echo"].post(payload))
27
+ end
28
+
29
+ # POST /modalities/{dicom}/find
30
+ def modality_find(dicom, payload = {})
31
+ objectify(base_uri["modalities/#{dicom}/find"].post(payload))
32
+ end
33
+
34
+ # POST /modalities/{dicom}/find-patient
35
+ def modality_find_patient(dicom, payload = {})
36
+ objectify(base_uri["modalities/#{dicom}/find-patient"].post(payload))
37
+ end
38
+
39
+ # POST /modalities/{dicom}/find-series
40
+ def modality_find_series(dicom, payload = {})
41
+ objectify(base_uri["modalities/#{dicom}/find-series"].post(payload))
42
+ end
43
+
44
+ # POST /modalities/{dicom}/find-study
45
+ def modality_find_study(dicom, payload = {})
46
+ objectify(base_uri["modalities/#{dicom}/find-study"].post(payload))
47
+ end
48
+
49
+ # POST /modalities/{dicom}/store
50
+ def modality_store(dicom, payload = {}) # POST body = UUID series, UUID instance, or raw DICOM file
51
+ objectify(base_uri["modalities/#{dicom}/store"].post(payload))
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,154 @@
1
+ module Orthanc
2
+ class Client
3
+ # ------------- Patients -------------
4
+ # GET /patients
5
+ def all_patients
6
+ objectify(base_uri["patients"].get)
7
+ end
8
+
9
+ # GET /patients/{id}
10
+ def patient(id)
11
+ objectify(base_uri["patients/#{id}"].get)
12
+ end
13
+
14
+ # DELETE /patients/{id}
15
+ def delete_patient(id)
16
+ objectify(base_uri["patients/#{id}"].delete)
17
+ end
18
+
19
+ # POST /patients/{id}/anonymize
20
+ def anonymize_patient(id, payload = {}) # https://code.google.com/p/orthanc/wiki/Anonymization
21
+ objectify(base_uri["patients/#{id}/anonymize"].post(payload))
22
+ end
23
+
24
+ # GET /patients/{id}/archive
25
+ def archive_patient(id) # Create ZIP
26
+ base_uri["patients/#{id}/archive"].get # CAREFUL! Returns the whole zipfile
27
+ end
28
+
29
+ # GET /patients/{id}/instances
30
+ def patient_instances(id) # Retrieve all the instances of this patient in a single REST call
31
+ objectify(base_uri["patients/#{id}/instances"].get)
32
+ end
33
+
34
+ # GET /patients/{id}/media
35
+ def patient_media(id) # Create a ZIP archive for media storage with DICOMDIR
36
+ base_uri["patients/#{id}/media"].get # CAREFUL! Returns the whole zipfile
37
+ end
38
+
39
+ # POST /patients/{id}/modify
40
+ def modify_patient(id, payload = {}) # https://code.google.com/p/orthanc/wiki/Anonymization
41
+ objectify(base_uri["patients/#{id}/modify"].post(payload))
42
+ end
43
+
44
+ # GET /patients/{id}/module
45
+ def patient_module(id)
46
+ objectify(base_uri["patients/#{id}/module"].get)
47
+ end
48
+
49
+ # GET /patients/{id}/protected
50
+ def is_patient_protected?(id) # Protection against recycling: "0" means unprotected, "1" protected
51
+ num_to_bool(base_uri["patients/#{id}/protected"].get)
52
+ end
53
+
54
+ # PUT /patients/{id}/protected
55
+ def set_patient_protected(id, boolstatus = true) # Protection against recycling: "0" means unprotected, "1" protected
56
+ status = bool_to_num(boolstatus)
57
+ base_uri["patients/#{id}/protected"].put("#{status}")
58
+ return nil # API returns ""
59
+ end
60
+
61
+ # GET /patients/{id}/series
62
+ def patient_series(id) # Retrieve all the series of this patient in a single REST call
63
+ objectify(base_uri["patients/#{id}/series"].get)
64
+ end
65
+
66
+ # GET /patients/{id}/shared-tags
67
+ def patient_shared_tags(id) # "?simplify" argument to simplify output
68
+ objectify(base_uri["patients/#{id}/shared-tags"].get)
69
+ end
70
+
71
+ # GET /patients/{id}/statistics
72
+ def patient_statistics(id)
73
+ objectify(base_uri["patients/#{id}/statistics"].get)
74
+ end
75
+
76
+ # GET /patients/{id}/studies
77
+ def patient_studies(id) # Retrieve all the studies of this patient in a single REST call
78
+ objectify(base_uri["patients/#{id}/studies"].get)
79
+ end
80
+
81
+ # TODO: Polymorphic resourceType resources. Repetitive. must refactor
82
+
83
+ # GET /{resourceType}/{id}/attachments
84
+ def patient_attachments(id)
85
+ objectify(base_uri["patients/#{id}/attachments"].get)
86
+ end
87
+
88
+ # DELETE /{resourceType}/{id}/attachments/{name}
89
+ def delete_patient_attachment(id, name)
90
+ objectify(base_uri["patients/#{id}/attachments/#{name}"].delete)
91
+ end
92
+
93
+ # PUT /{resourceType}/{id}/attachments/{name}
94
+ def patient_attachment(id, name, payload = {})
95
+ objectify(base_uri["patients/#{id}/attachments/#{name}"].put(payload))
96
+ end
97
+
98
+ # GET /{resourceType}/{id}/attachments/{name}/compressed-data
99
+ def patient_attachment_compressed_data(id, name)
100
+ objectify(base_uri["patients/#{id}/attachments/#{name}/compressed-data"].get)
101
+ end
102
+
103
+ # GET /{resourceType}/{id}/attachments/{name}/compressed-md5
104
+ def patient_attachment_compressed_md5(id, name)
105
+ objectify(base_uri["patients/#{id}/attachments/#{name}/compressed-md5"].get)
106
+ end
107
+
108
+ # GET /{resourceType}/{id}/attachments/{name}/compressed-size
109
+ def patient_attachment_compressed_size(id, name)
110
+ objectify(base_uri["patients/#{id}/attachments/#{name}/compressed-size"].get)
111
+ end
112
+
113
+ # GET /{resourceType}/{id}/attachments/{name}/data
114
+ def patient_attachment_data(id, name)
115
+ objectify(base_uri["patients/#{id}/attachments/#{name}/data"].get)
116
+ end
117
+
118
+ # GET /{resourceType}/{id}/attachments/{name}/md5
119
+ def patient_attachment_md5(id, name)
120
+ objectify(base_uri["patients/#{id}/attachments/#{name}/md5"].get)
121
+ end
122
+
123
+ # GET /{resourceType}/{id}/attachments/{name}/size
124
+ def patient_attachment_size(id, name)
125
+ objectify(base_uri["patients/#{id}/attachments/#{name}/size"].get)
126
+ end
127
+
128
+ # POST /{resourceType}/{id}/attachments/{name}/verify-md5
129
+ def patient_attachment_verify_md5(id, name)
130
+ objectify(base_uri["patients/#{id}/attachments/#{name}/verify-md5"].get)
131
+ end
132
+
133
+ # GET /{resourceType}/{id}/metadata
134
+ def patient_all_metadata(id)
135
+ objectify(base_uri["patients/#{id}/metadata"].get)
136
+ end
137
+
138
+ # GET /{resourceType}/{id}/metadata/{name}
139
+ def patient_metadata(id, name)
140
+ objectify(base_uri["patients/#{id}/metadata/#{name}"].get)
141
+ end
142
+
143
+ # DELETE /{resourceType}/{id}/metadata/{name}
144
+ def patient_delete_metadata(id, name)
145
+ objectify(base_uri["patients/#{id}/metadata/#{name}"].delete)
146
+ end
147
+
148
+ # PUT /{resourceType}/{id}/metadata/{name}
149
+ def patient_update_metadata(id, name, payload = {})
150
+ objectify(base_uri["patients/#{id}/metadata/#{name}"].put(payload))
151
+ end
152
+
153
+ end
154
+ end
@@ -0,0 +1,30 @@
1
+ module Orthanc
2
+ class Client
3
+ # ------------- Peers -------------
4
+ # GET /peers
5
+ def peers # Get the list of all the registered plugins
6
+ objectify(base_uri["peers"].get)
7
+ end
8
+
9
+ # GET /peers/{peer}
10
+ def peer(peer)
11
+ objectify(base_uri["peers/#{peer}"].get)
12
+ end
13
+
14
+ # DELETE /peers/{peer}
15
+ def delete_peer(peer)
16
+ objectify(base_uri["peers/#{peer}"].delete)
17
+ end
18
+
19
+ # PUT /peers/{peer}
20
+ def modify_peer(peer, payload = {})
21
+ objectify(base_uri["peers/#{peer}"].put(payload))
22
+ end
23
+
24
+ # GET /peers/{peer}/store
25
+ def peer_store(peer, payload = {}) # POST body = UUID series, UUID instance, or raw DICOM file
26
+ objectify(base_uri["peers/#{peer}/store"].post(payload))
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,20 @@
1
+ module Orthanc
2
+ class Client
3
+ # ------------- Plugins -------------
4
+ # GET /plugins
5
+ def plugins # Get the list of all the registered plugins
6
+ objectify(base_uri["plugins"].get)
7
+ end
8
+
9
+ # GET /plugins/explorer.js
10
+ def plugins_explorerjs # Get the JavaScript code that is injected by plugins into Orthanc Explorer
11
+ objectify(base_uri["plugins/explorer.js"].get)
12
+ end
13
+
14
+ # GET /plugins/{id}
15
+ def plugin(id) # Get information about some plugin
16
+ objectify(base_uri["plugins/#{id}"].get)
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,142 @@
1
+ module Orthanc
2
+ class Client
3
+ # ------------- Series -------------
4
+ # GET /series
5
+ def all_series # Darn DICOM, why did you have to call them something that's spelled the same singular and plural?
6
+ objectify(base_uri["series"].get)
7
+ end
8
+
9
+ # GET /series/{id}
10
+ def series(id)
11
+ objectify(base_uri["series/#{id}"].get)
12
+ end
13
+
14
+ # DELETE /series/{id}
15
+ def delete_series(id)
16
+ objectify(base_uri["series/#{id}"].delete)
17
+ end
18
+
19
+ # POST /series/{id}/anonymize
20
+ def anonymize_series(id, payload = {}) # https://code.google.com/p/orthanc/wiki/Anonymization
21
+ objectify(base_uri["series/#{id}/anonymize"].post(payload))
22
+ end
23
+
24
+ # GET /series/{id}/archive
25
+ def archive_series(id) # Create ZIP
26
+ base_uri["series/#{id}/archive"].get # CAREFUL! Returns the whole zipfile
27
+ end
28
+
29
+ # GET /series/{id}/instances
30
+ def series_instances(id) # Retrieve all the instances of this patient in a single REST call
31
+ objectify(base_uri["series/#{id}/instances"].get)
32
+ end
33
+
34
+ # GET /series/{id}/media
35
+ def series_media(id) # Create a ZIP archive for media storage with DICOMDIR
36
+ base_uri["series/#{id}/media"].get # CAREFUL! Returns the whole zipfile
37
+ end
38
+
39
+ # POST /series/{id}/modify
40
+ def modify_series(id, payload = {}) # https://code.google.com/p/orthanc/wiki/Anonymization
41
+ objectify(base_uri["series/#{id}/modify"].post(payload))
42
+ end
43
+
44
+ # GET /series/{id}/module
45
+ def series_module(id)
46
+ objectify(base_uri["series/#{id}/module"].get)
47
+ end
48
+
49
+ # GET /series/{id}/patient
50
+ def series_patient(id)
51
+ objectify(base_uri["series/#{id}/patient"].get)
52
+ end
53
+
54
+ # GET /series/{id}/shared-tags
55
+ def series_shared_tags(id) # "?simplify" argument to simplify output
56
+ objectify(base_uri["series/#{id}/shared-tags"].get)
57
+ end
58
+
59
+ # GET /series/{id}/statistics
60
+ def series_statistics(id)
61
+ objectify(base_uri["series/#{id}/statistics"].get)
62
+ end
63
+
64
+ # GET /series/{id}/study
65
+ def series_study(id)
66
+ objectify(base_uri["series/#{id}/study"].get)
67
+ end
68
+
69
+ # TODO: Polymorphic resourceType resources. Repetitive. must refactor
70
+
71
+ # GET /{resourceType}/{id}/attachments
72
+ def series_attachments(id)
73
+ objectify(base_uri["series/#{id}/attachments"].get)
74
+ end
75
+
76
+ # DELETE /{resourceType}/{id}/attachments/{name}
77
+ def delete_series_attachment(id, name)
78
+ objectify(base_uri["series/#{id}/attachments/#{name}"].delete)
79
+ end
80
+
81
+ # PUT /{resourceType}/{id}/attachments/{name}
82
+ def series_attachment(id, name, payload = {})
83
+ objectify(base_uri["series/#{id}/attachments/#{name}"].put(payload))
84
+ end
85
+
86
+ # GET /{resourceType}/{id}/attachments/{name}/compressed-data
87
+ def series_attachment_compressed_data(id, name)
88
+ objectify(base_uri["series/#{id}/attachments/#{name}/compressed-data"].get)
89
+ end
90
+
91
+ # GET /{resourceType}/{id}/attachments/{name}/compressed-md5
92
+ def series_attachment_compressed_md5(id, name)
93
+ objectify(base_uri["series/#{id}/attachments/#{name}/compressed-md5"].get)
94
+ end
95
+
96
+ # GET /{resourceType}/{id}/attachments/{name}/compressed-size
97
+ def series_attachment_compressed_size(id, name)
98
+ objectify(base_uri["series/#{id}/attachments/#{name}/compressed-size"].get)
99
+ end
100
+
101
+ # GET /{resourceType}/{id}/attachments/{name}/data
102
+ def series_attachment_data(id, name)
103
+ objectify(base_uri["series/#{id}/attachments/#{name}/data"].get)
104
+ end
105
+
106
+ # GET /{resourceType}/{id}/attachments/{name}/md5
107
+ def series_attachment_md5(id, name)
108
+ objectify(base_uri["series/#{id}/attachments/#{name}/md5"].get)
109
+ end
110
+
111
+ # GET /{resourceType}/{id}/attachments/{name}/size
112
+ def series_attachment_size(id, name)
113
+ objectify(base_uri["series/#{id}/attachments/#{name}/size"].get)
114
+ end
115
+
116
+ # POST /{resourceType}/{id}/attachments/{name}/verify-md5
117
+ def series_attachment_verify_md5(id, name)
118
+ objectify(base_uri["series/#{id}/attachments/#{name}/verify-md5"].get)
119
+ end
120
+
121
+ # GET /{resourceType}/{id}/metadata
122
+ def series_all_metadata(id)
123
+ objectify(base_uri["series/#{id}/metadata"].get)
124
+ end
125
+
126
+ # GET /{resourceType}/{id}/metadata/{name}
127
+ def series_metadata(id, name)
128
+ objectify(base_uri["series/#{id}/metadata/#{name}"].get)
129
+ end
130
+
131
+ # DELETE /{resourceType}/{id}/metadata/{name}
132
+ def series_delete_metadata(id, name)
133
+ objectify(base_uri["series/#{id}/metadata/#{name}"].delete)
134
+ end
135
+
136
+ # GET /{resourceType}/{id}/metadata/{name}
137
+ def series_update_metadata(id, name, payload = {})
138
+ objectify(base_uri["series/#{id}/metadata/#{name}"].put(payload))
139
+ end
140
+
141
+ end
142
+ end
@@ -0,0 +1,147 @@
1
+ module Orthanc
2
+ class Client
3
+ # ------------- Studies -------------
4
+ # GET /studies
5
+ def all_studies
6
+ objectify(base_uri["studies"].get)
7
+ end
8
+
9
+ # GET /studies/{id}
10
+ def study(id)
11
+ objectify(base_uri["studies/#{id}"].get)
12
+ end
13
+
14
+ # DELETE /studies/{id}
15
+ def delete_study(id)
16
+ objectify(base_uri["studies/#{id}"].delete)
17
+ end
18
+
19
+ # POST /studies/{id}/anonymize
20
+ def anonymize_study(id, payload = {}) # https://code.google.com/p/orthanc/wiki/Anonymization
21
+ objectify(base_uri["studies/#{id}/anonymize"].post(payload))
22
+ end
23
+
24
+ # GET /studies/{id}/archive
25
+ def archive_study(id) # Create ZIP
26
+ base_uri["studies/#{id}/archive"].get # CAREFUL! Returns the whole zipfile
27
+ end
28
+
29
+ # GET /studies/{id}/instances
30
+ def study_instances(id) # Retrieve all the instances of this patient in a single REST call
31
+ objectify(base_uri["studies/#{id}/instances"].get)
32
+ end
33
+
34
+ # GET /studies/{id}/media
35
+ def study_media(id) # Create a ZIP archive for media storage with DICOMDIR
36
+ base_uri["studies/#{id}/media"].get # CAREFUL! Returns the whole zipfile
37
+ end
38
+
39
+ # POST /studies/{id}/modify
40
+ def modify_study(id, payload = {}) # https://code.google.com/p/orthanc/wiki/Anonymization
41
+ objectify(base_uri["studies/#{id}/modify"].post(payload))
42
+ end
43
+
44
+ # GET /studies/{id}/module
45
+ def study_module(id)
46
+ objectify(base_uri["studies/#{id}/module"].get)
47
+ end
48
+
49
+ # GET /studies/{id}/module-patient
50
+ def study_module_patient(id)
51
+ objectify(base_uri["studies/#{id}/module-patient"].get)
52
+ end
53
+
54
+ # GET /studies/{id}/patient
55
+ def study_patient(id)
56
+ objectify(base_uri["studies/#{id}/patient"].get)
57
+ end
58
+
59
+ # GET /studies/{id}/series
60
+ def study_series(id) # Retrieve all the series of this patient in a single REST call
61
+ objectify(base_uri["studies/#{id}/series"].get)
62
+ end
63
+
64
+ # GET /studies/{id}/shared-tags
65
+ def study_shared_tags(id) # "?simplify" argument to simplify output
66
+ objectify(base_uri["studies/#{id}/shared-tags"].get)
67
+ end
68
+
69
+ # GET /studies/{id}/statistics
70
+ def study_statistics(id)
71
+ objectify(base_uri["studies/#{id}/statistics"].get)
72
+ end
73
+
74
+ # TODO: Polymorphic resourceType resources. Repetitive. must refactor
75
+
76
+ # GET /{resourceType}/{id}/attachments
77
+ def study_attachments(id)
78
+ objectify(base_uri["studies/#{id}/attachments"].get)
79
+ end
80
+
81
+ # DELETE /{resourceType}/{id}/attachments/{name}
82
+ def delete_study_attachment(id, name)
83
+ objectify(base_uri["studies/#{id}/attachments/#{name}"].delete)
84
+ end
85
+
86
+ # PUT /{resourceType}/{id}/attachments/{name}
87
+ def study_attachment(id, name, payload = {})
88
+ objectify(base_uri["studies/#{id}/attachments/#{name}"].put(payload))
89
+ end
90
+
91
+ # GET /{resourceType}/{id}/attachments/{name}/compressed-data
92
+ def study_attachment_compressed_data(id, name)
93
+ objectify(base_uri["studies/#{id}/attachments/#{name}/compressed-data"].get)
94
+ end
95
+
96
+ # GET /{resourceType}/{id}/attachments/{name}/compressed-md5
97
+ def study_attachment_compressed_md5(id, name)
98
+ objectify(base_uri["studies/#{id}/attachments/#{name}/compressed-md5"].get)
99
+ end
100
+
101
+ # GET /{resourceType}/{id}/attachments/{name}/compressed-size
102
+ def study_attachment_compressed_size(id, name)
103
+ objectify(base_uri["studies/#{id}/attachments/#{name}/compressed-size"].get)
104
+ end
105
+
106
+ # GET /{resourceType}/{id}/attachments/{name}/data
107
+ def study_attachment_data(id, name)
108
+ objectify(base_uri["studies/#{id}/attachments/#{name}/data"].get)
109
+ end
110
+
111
+ # GET /{resourceType}/{id}/attachments/{name}/md5
112
+ def study_attachment_md5(id, name)
113
+ objectify(base_uri["studies/#{id}/attachments/#{name}/md5"].get)
114
+ end
115
+
116
+ # GET /{resourceType}/{id}/attachments/{name}/size
117
+ def study_attachment_size(id, name)
118
+ objectify(base_uri["studies/#{id}/attachments/#{name}/size"].get)
119
+ end
120
+
121
+ # POST /{resourceType}/{id}/attachments/{name}/verify-md5
122
+ def study_attachment_verify_md5(id, name)
123
+ objectify(base_uri["studies/#{id}/attachments/#{name}/verify-md5"].get)
124
+ end
125
+
126
+ # GET /{resourceType}/{id}/metadata
127
+ def study_all_metadata(id)
128
+ objectify(base_uri["studies/#{id}/metadata"].get)
129
+ end
130
+
131
+ # GET /{resourceType}/{id}/metadata/{name}
132
+ def study_metadata(id, name)
133
+ objectify(base_uri["studies/#{id}/metadata/#{name}"].get)
134
+ end
135
+
136
+ # DELETE /{resourceType}/{id}/metadata/{name}
137
+ def study_delete_metadata(id, name)
138
+ objectify(base_uri["studies/#{id}/metadata/#{name}"].delete)
139
+ end
140
+
141
+ # PUT /{resourceType}/{id}/metadata/{name}
142
+ def study_update_metadata(id, name, payload = {})
143
+ objectify(base_uri["studies/#{id}/metadata/#{name}"].put(payload))
144
+ end
145
+
146
+ end
147
+ end
@@ -0,0 +1,41 @@
1
+ module Orthanc
2
+ class Client
3
+ # ------------- Tools -------------
4
+
5
+ # POST /tools/create-dicom
6
+ def tools_create_dicom(payload = {}) # Create and store a new DICOM instance (experimental)
7
+ objectify(base_uri["tools/create-dicom"].post(payload))
8
+ end
9
+
10
+ # GET /tools/dicom-conformance
11
+ def tools_dicom_conformance # DICOM conformance statement of this version of Orthanc
12
+ base_uri["tools/dicom-conformance"].get
13
+ end
14
+
15
+ # POST /tools/execute-script
16
+ def tools_execute_script(payload = {}) # Execute the Lua script in the POST body (experimental)
17
+ objectify(base_uri["tools/execute-script"].post(payload))
18
+ end
19
+
20
+ # GET /tools/generate-uid
21
+ def tools_generate_uid(level) # "level" argument among "patient", "study", "series" and "instance"
22
+ objectify(base_uri["tools/generate-uid"].get({params: {level: level}}))
23
+ end
24
+
25
+ # POST /tools/lookup
26
+ def tools_lookup(payload = {}) # Map DICOM UIDs to Orthanc identifiers
27
+ objectify(base_uri["tools/lookup"].post(payload))
28
+ end
29
+
30
+ # GET /tools/now
31
+ def tools_now # Returns the current datetime in the ISO 8601 format
32
+ base_uri["tools/now"].get
33
+ end
34
+
35
+ # POST /tools/reset
36
+ def tools_reset(payload = {}) # Hot restart of Orthanc, the configuration file will be read again
37
+ objectify(base_uri["tools/reset"].post(payload))
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module Orthanc
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'orthanc/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "orthanc"
8
+ spec.version = Orthanc::VERSION
9
+ spec.authors = ["Simon Rascovsky"]
10
+ spec.email = ["simonmd@gmail.com"]
11
+
12
+ spec.summary = "Client for the Orthanc DICOM server API"
13
+ spec.description = "Client for the Orthanc DICOM server REST API"
14
+ spec.homepage = "https://github.com/simonmd/orthanc-ruby"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.9"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+
25
+
26
+ spec.add_dependency 'rest-client', "~> 1.8"
27
+ spec.add_dependency 'recursive-open-struct', "~> 0.6.3"
28
+ spec.add_dependency 'plissken', "~> 0.2.0"
29
+ end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: orthanc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Simon Rascovsky
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-04-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.9'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rest-client
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.8'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.8'
55
+ - !ruby/object:Gem::Dependency
56
+ name: recursive-open-struct
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.6.3
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.6.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: plissken
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 0.2.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 0.2.0
83
+ description: Client for the Orthanc DICOM server REST API
84
+ email:
85
+ - simonmd@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".travis.yml"
92
+ - Gemfile
93
+ - README.md
94
+ - Rakefile
95
+ - bin/console
96
+ - bin/setup
97
+ - lib/orthanc.rb
98
+ - lib/orthanc/client.rb
99
+ - lib/orthanc/instances.rb
100
+ - lib/orthanc/modalities.rb
101
+ - lib/orthanc/patients.rb
102
+ - lib/orthanc/peers.rb
103
+ - lib/orthanc/plugins.rb
104
+ - lib/orthanc/series.rb
105
+ - lib/orthanc/studies.rb
106
+ - lib/orthanc/tools.rb
107
+ - lib/orthanc/version.rb
108
+ - orthanc.gemspec
109
+ homepage: https://github.com/simonmd/orthanc-ruby
110
+ licenses:
111
+ - MIT
112
+ metadata: {}
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: '0'
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubyforge_project:
129
+ rubygems_version: 2.4.6
130
+ signing_key:
131
+ specification_version: 4
132
+ summary: Client for the Orthanc DICOM server API
133
+ test_files: []