From b4c34936ad4044a3f7be23ee074f9eb035c9cbbb Mon Sep 17 00:00:00 2001 From: biskyt Date: Fri, 10 Jul 2020 15:16:11 +0100 Subject: [PATCH] Initial copy from Wales --- .gitattributes | 43 + .gitignore | 7 + Gruntfile.js | 11 + OphInKowastereoModule.php | 31 + README.md | 4 + RELEASE | 6 + assets/css/.gitignore | 1 + assets/css/desktop.ini | Bin 0 -> 244 bytes assets/css/module.css | 30 + assets/desktop.ini | Bin 0 -> 244 bytes assets/img/desktop.ini | Bin 0 -> 244 bytes assets/img/medium.png | Bin 0 -> 5026 bytes assets/img/small.png | Bin 0 -> 4332 bytes assets/img/watermark.png | Bin 0 -> 6555 bytes assets/js/.gitignore | 1 + assets/js/desktop.ini | Bin 0 -> 244 bytes assets/js/imageLoader.js | 84 + assets/js/module.js | 16 + assets/sass/components/_event.scss | 25 + assets/sass/components/desktop.ini | Bin 0 -> 244 bytes assets/sass/desktop.ini | Bin 0 -> 244 bytes assets/sass/module.scss | 20 + commands/AnonymiseFieldsCommand.php | 243 + commands/AnonymiseFieldsCommand.php.anon-xml | 223 + commands/Gif2JPegCommand.php | 126 + commands/LegacyFieldsCommand.php | 239 + commands/ReCropImageCommand.php | 90 + commands/desktop.ini | Bin 0 -> 244 bytes components/desktop.ini | Bin 0 -> 244 bytes components/fhir_schema/desktop.ini | Bin 0 -> 244 bytes config/common.php | 58 + config/console.php | 34 + config/desktop.ini | Bin 0 -> 244 bytes config/test.php | 30 + controllers/DefaultController.php | 6 + controllers/desktop.ini | Bin 0 -> 244 bytes desktop.ini | Bin 0 -> 244 bytes fullsize.html | 1 + grunt/config/compass.js | 22 + grunt/config/connect.js | 13 + grunt/config/desktop.ini | Bin 0 -> 244 bytes grunt/config/index.js | 10 + grunt/config/mocha.js | 13 + grunt/config/test.js | 14 + grunt/config/watch.js | 8 + grunt/desktop.ini | Bin 0 -> 244 bytes grunt/tasks/build.js | 5 + grunt/tasks/compile.js | 5 + grunt/tasks/default.js | 5 + grunt/tasks/desktop.ini | Bin 0 -> 244 bytes grunt/tasks/test.js | 23 + index.html | 5 + migrations/data/desktop.ini | Bin 0 -> 244 bytes .../01_measurement_type.csv | 2 + .../01_ophinkowastereo_condition_ability.csv | 8 + .../m140731_130000_kowa_stereo/desktop.ini | Bin 0 -> 244 bytes migrations/desktop.ini | Bin 0 -> 244 bytes migrations/m140731_130000_kowa_stereo.php | 161 + migrations/m140731_130010_pattern_details.php | 419 + ...140731_130020_assessment_result_values.php | 20 + ...0731_130030_central_threshold_patterns.php | 18 + .../m140910_160147_add_secondary_image.php | 21 + models/Element_OphInKowastereo_Comments.php | 40 + models/Element_OphInKowastereo_Condition.php | 81 + ...owastereo_Condition_Ability_Assignment.php | 111 + models/Element_OphInKowastereo_Image.php | 73 + models/Element_OphInKowastereo_Result.php | 78 + ...owastereo_Result_Assessment_Assignment.php | 111 + models/OphInKowastereo_Condition_Ability.php | 112 + models/OphInKowastereo_Field_Measurement.php | 43 + models/OphInKowastereo_Result_Assessment.php | 107 + models/desktop.ini | Bin 0 -> 244 bytes package.json | 23 + services/MeasurementKowaStereo.php | 63 + services/MeasurementKowaStereo.php~ | 53 + services/MeasurementKowaStereoService.php | 40 + services/desktop.ini | Bin 0 -> 244 bytes .../fhir_templates/MeasurementKowaStereo.json | 8 + services/fhir_templates/desktop.ini | Bin 0 -> 244 bytes tests/bootstrap.php | 11 + tests/build.xml | 5 + tests/desktop.ini | Bin 0 -> 244 bytes tests/fields/desktop.ini | Bin 0 -> 244 bytes .../TEST_left_hfa_01_2014_03_20_14_09_38.fmes | 8301 ++++++++++++++++ .../TEST_left_hfa_02_2014_03_20_14_09_45.fmes | 8316 +++++++++++++++++ .../TEST_left_hfa_03_2014_03_20_14_09_44.fmes | 8070 ++++++++++++++++ .../TEST_left_hfa_04_2014_03_20_14_09_44.fmes | 8098 ++++++++++++++++ ...TEST_right_hfa_01_2014_03_20_14_09_38.fmes | 8301 ++++++++++++++++ ...TEST_right_hfa_02_2014_03_20_14_09_38.fmes | 8304 ++++++++++++++++ ...TEST_right_hfa_03_2014_03_20_14_09_37.fmes | 8080 ++++++++++++++++ ...TEST_right_hfa_04_2014_03_20_14_09_36.fmes | 8089 ++++++++++++++++ tests/fields/legacy/desktop.ini | Bin 0 -> 244 bytes .../unit/commands/LegacyFieldsCommandTest.php | 204 + tests/unit/commands/desktop.ini | Bin 0 -> 244 bytes tests/unit/desktop.ini | Bin 0 -> 244 bytes ...ent_OphInKowastereo_Humphrey_Scan_Pair.php | 15 + views/default/create.php | 42 + views/default/delete.php | 49 + views/default/desktop.ini | Bin 0 -> 244 bytes .../form_Element_OphInKowastereo_Comments.php | 22 + ...form_Element_OphInKowastereo_Condition.php | 23 + .../form_Element_OphInKowastereo_Image.php | 32 + ...orm_Element_OphInKowastereo_Image_side.php | 51 + .../form_Element_OphInKowastereo_Result.php | 23 + views/default/update.php | 42 + views/default/view.php | 44 + .../view_Element_OphInKowastereo_Comments.php | 33 + ...view_Element_OphInKowastereo_Condition.php | 39 + .../view_Element_OphInKowastereo_Image.php | 78 + .../view_Element_OphInKowastereo_Result.php | 38 + views/desktop.ini | Bin 0 -> 244 bytes ...InKowastereo_Episode_KowaStereoHistory.php | 57 + widgets/desktop.ini | Bin 0 -> 244 bytes ...InKowastereo_Episode_KowaStereoHistory.php | 112 + ...astereo_Episode_KowaStereoHistory_side.php | 30 + widgets/views/desktop.ini | Bin 0 -> 244 bytes 116 files changed, 69553 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 Gruntfile.js create mode 100644 OphInKowastereoModule.php create mode 100644 README.md create mode 100644 RELEASE create mode 100644 assets/css/.gitignore create mode 100644 assets/css/desktop.ini create mode 100644 assets/css/module.css create mode 100644 assets/desktop.ini create mode 100644 assets/img/desktop.ini create mode 100644 assets/img/medium.png create mode 100644 assets/img/small.png create mode 100644 assets/img/watermark.png create mode 100644 assets/js/.gitignore create mode 100644 assets/js/desktop.ini create mode 100644 assets/js/imageLoader.js create mode 100644 assets/js/module.js create mode 100644 assets/sass/components/_event.scss create mode 100644 assets/sass/components/desktop.ini create mode 100644 assets/sass/desktop.ini create mode 100644 assets/sass/module.scss create mode 100644 commands/AnonymiseFieldsCommand.php create mode 100644 commands/AnonymiseFieldsCommand.php.anon-xml create mode 100644 commands/Gif2JPegCommand.php create mode 100644 commands/LegacyFieldsCommand.php create mode 100644 commands/ReCropImageCommand.php create mode 100644 commands/desktop.ini create mode 100644 components/desktop.ini create mode 100644 components/fhir_schema/desktop.ini create mode 100644 config/common.php create mode 100644 config/console.php create mode 100644 config/desktop.ini create mode 100644 config/test.php create mode 100644 controllers/DefaultController.php create mode 100644 controllers/desktop.ini create mode 100644 desktop.ini create mode 100644 fullsize.html create mode 100644 grunt/config/compass.js create mode 100644 grunt/config/connect.js create mode 100644 grunt/config/desktop.ini create mode 100644 grunt/config/index.js create mode 100644 grunt/config/mocha.js create mode 100644 grunt/config/test.js create mode 100644 grunt/config/watch.js create mode 100644 grunt/desktop.ini create mode 100644 grunt/tasks/build.js create mode 100644 grunt/tasks/compile.js create mode 100644 grunt/tasks/default.js create mode 100644 grunt/tasks/desktop.ini create mode 100644 grunt/tasks/test.js create mode 100644 index.html create mode 100644 migrations/data/desktop.ini create mode 100644 migrations/data/m140731_130000_kowa_stereo/01_measurement_type.csv create mode 100644 migrations/data/m140731_130000_kowa_stereo/01_ophinkowastereo_condition_ability.csv create mode 100644 migrations/data/m140731_130000_kowa_stereo/desktop.ini create mode 100644 migrations/desktop.ini create mode 100644 migrations/m140731_130000_kowa_stereo.php create mode 100644 migrations/m140731_130010_pattern_details.php create mode 100644 migrations/m140731_130020_assessment_result_values.php create mode 100644 migrations/m140731_130030_central_threshold_patterns.php create mode 100644 migrations/m140910_160147_add_secondary_image.php create mode 100644 models/Element_OphInKowastereo_Comments.php create mode 100644 models/Element_OphInKowastereo_Condition.php create mode 100644 models/Element_OphInKowastereo_Condition_Ability_Assignment.php create mode 100644 models/Element_OphInKowastereo_Image.php create mode 100644 models/Element_OphInKowastereo_Result.php create mode 100644 models/Element_OphInKowastereo_Result_Assessment_Assignment.php create mode 100644 models/OphInKowastereo_Condition_Ability.php create mode 100644 models/OphInKowastereo_Field_Measurement.php create mode 100644 models/OphInKowastereo_Result_Assessment.php create mode 100644 models/desktop.ini create mode 100644 package.json create mode 100644 services/MeasurementKowaStereo.php create mode 100644 services/MeasurementKowaStereo.php~ create mode 100644 services/MeasurementKowaStereoService.php create mode 100644 services/desktop.ini create mode 100644 services/fhir_templates/MeasurementKowaStereo.json create mode 100644 services/fhir_templates/desktop.ini create mode 100644 tests/bootstrap.php create mode 100644 tests/build.xml create mode 100644 tests/desktop.ini create mode 100644 tests/fields/desktop.ini create mode 100644 tests/fields/legacy/TEST_left_hfa_01_2014_03_20_14_09_38.fmes create mode 100644 tests/fields/legacy/TEST_left_hfa_02_2014_03_20_14_09_45.fmes create mode 100644 tests/fields/legacy/TEST_left_hfa_03_2014_03_20_14_09_44.fmes create mode 100644 tests/fields/legacy/TEST_left_hfa_04_2014_03_20_14_09_44.fmes create mode 100644 tests/fields/legacy/TEST_right_hfa_01_2014_03_20_14_09_38.fmes create mode 100644 tests/fields/legacy/TEST_right_hfa_02_2014_03_20_14_09_38.fmes create mode 100644 tests/fields/legacy/TEST_right_hfa_03_2014_03_20_14_09_37.fmes create mode 100644 tests/fields/legacy/TEST_right_hfa_04_2014_03_20_14_09_36.fmes create mode 100644 tests/fields/legacy/desktop.ini create mode 100644 tests/unit/commands/LegacyFieldsCommandTest.php create mode 100644 tests/unit/commands/desktop.ini create mode 100644 tests/unit/desktop.ini create mode 100644 views/default/_view_Element_OphInKowastereo_Humphrey_Scan_Pair.php create mode 100644 views/default/create.php create mode 100644 views/default/delete.php create mode 100644 views/default/desktop.ini create mode 100644 views/default/form_Element_OphInKowastereo_Comments.php create mode 100644 views/default/form_Element_OphInKowastereo_Condition.php create mode 100644 views/default/form_Element_OphInKowastereo_Image.php create mode 100644 views/default/form_Element_OphInKowastereo_Image_side.php create mode 100644 views/default/form_Element_OphInKowastereo_Result.php create mode 100644 views/default/update.php create mode 100644 views/default/view.php create mode 100644 views/default/view_Element_OphInKowastereo_Comments.php create mode 100644 views/default/view_Element_OphInKowastereo_Condition.php create mode 100644 views/default/view_Element_OphInKowastereo_Image.php create mode 100644 views/default/view_Element_OphInKowastereo_Result.php create mode 100644 views/desktop.ini create mode 100644 widgets/OphInKowastereo_Episode_KowaStereoHistory.php create mode 100644 widgets/desktop.ini create mode 100644 widgets/views/OphInKowastereo_Episode_KowaStereoHistory.php create mode 100644 widgets/views/OphInKowastereo_Episode_KowaStereoHistory_side.php create mode 100644 widgets/views/desktop.ini diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..bd64155 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,43 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text eol=lf + +# Explicitly declare text files you want to always be normalized and converted +# to native line endings on checkout. +*.c text +*.h text +*.css text +*.html text +*.xml text +*.js text +*.conf text +*.sass text +*.scss text +*.md text + +# Declare files that will always have CRLF line endings on checkout. +*.bat text eol=crlf +*.cmd text eol=crlf + +# Declare files that will always have LF line endings on checkout. +*.sh text eol=lf +*.php text eol=lf + + +# Denote all files that are truly binary and should not be modified. +*.png binary +*.jpg binary +*.bmp binary +*.gif binary +*.tiff binary +*.dcm binary +*.pdf binary +*.otf binary +*.eot binary +*.ttf binary +*.woff binary +*.woff2 binary +*.odt binary +*.zip binary +wait binary +/web/wait binary +/dicomprocessor/wait binary \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..039a7b7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.settings +.buildpath +.project +node_modules +.sass-cache +.DS_Store +.vscode/* \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..322cb38 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,11 @@ +module.exports = function(grunt) { + + /* Set the config */ + grunt.initConfig(require('./grunt/config')(grunt)); + + /* Load the npm grunt tasks */ + require('load-grunt-tasks')(grunt, 'grunt-*'); + + /* Load our custom grunt tasks */ + grunt.loadTasks('./grunt/tasks'); +}; \ No newline at end of file diff --git a/OphInKowastereoModule.php b/OphInKowastereoModule.php new file mode 100644 index 0000000..f9a21b3 --- /dev/null +++ b/OphInKowastereoModule.php @@ -0,0 +1,31 @@ +. + * + * @package OpenEyes + * @link http://www.openeyes.org.uk + * @author OpenEyes + * @copyright Copyright (c) 2008-2011, Moorfields Eye Hospital NHS Foundation Trust + * @copyright Copyright (c) 2011-2012, OpenEyes Foundation + * @license http://www.gnu.org/licenses/gpl-3.0.html The GNU General Public License V3.0 + */ + +class OphInKowastereoModule extends BaseEventTypeModule +{ + public function init() { + $this->setImport(array( + 'OphInKowastereo.models.*', + 'OphInKowastereo.components.*', + 'OphInKowastereo.commands.*', + )); + + parent::init(); + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..930bc7b --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +OphInVisualfields +================= + +This module is currently under development and has no stable releases. diff --git a/RELEASE b/RELEASE new file mode 100644 index 0000000..6bebd89 --- /dev/null +++ b/RELEASE @@ -0,0 +1,6 @@ +Release History +=============== + +1.7.0 +----- +Initial release diff --git a/assets/css/.gitignore b/assets/css/.gitignore new file mode 100644 index 0000000..0953f01 --- /dev/null +++ b/assets/css/.gitignore @@ -0,0 +1 @@ +.x diff --git a/assets/css/desktop.ini b/assets/css/desktop.ini new file mode 100644 index 0000000000000000000000000000000000000000..3a4e71b7226fb57ef3d9c42f0bf32c9af36f43aa GIT binary patch literal 244 zcmY+8y9&ZU5JgWd_z(F2SyU`UNTozlDO$P~A*>pRuDB|GzBf}CWSE`Dee4`??70wV z6-#ABQk2{{5jiqspnbHt;lY)HM!dj=J2_)xl+?!AX`j@+#H`il(k}39HAl{RD>-C8 wk0fj@q{BK-&q|zzxB8xy>Bgt_!PK6aesz{}tN$LoLm{1$>Z2SnWn#B}0eHwMS^xk5 literal 0 HcmV?d00001 diff --git a/assets/css/module.css b/assets/css/module.css new file mode 100644 index 0000000..66f69d8 --- /dev/null +++ b/assets/css/module.css @@ -0,0 +1,30 @@ +/** Visual Fields module styles */ +/** + * OpenEyes + * + * (C) Moorfields Eye Hospital NHS Foundation Trust, 2008-2011 + * (C) OpenEyes Foundation, 2011-2013 + * This file is part of OpenEyes. + * OpenEyes 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 (at your option) any later version. + * OpenEyes 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 OpenEyes in a file titled COPYING. If not, see . + * + * @package OpenEyes + * @link http://www.openeyes.org.uk + * @author OpenEyes + * @copyright Copyright (c) 2008-2011, Moorfields Eye Hospital NHS Foundation Trust + * @copyright Copyright (c) 2011-2013, OpenEyes Foundation + * @license http://www.gnu.org/licenses/gpl-3.0.html The GNU General Public License V3.0 + */ +/* line 17, ../sass/components/_event.scss */ +.event { + border-color: #a5a0a9; +} +/* line 19, ../sass/components/_event.scss */ +.event .event-content { + background-image: url('../img/watermark.png?1400161568'); +} +/* line 22, ../sass/components/_event.scss */ +.event .event-title { + background-image: url('../img/medium.png?1400161568'); +} diff --git a/assets/desktop.ini b/assets/desktop.ini new file mode 100644 index 0000000000000000000000000000000000000000..3a4e71b7226fb57ef3d9c42f0bf32c9af36f43aa GIT binary patch literal 244 zcmY+8y9&ZU5JgWd_z(F2SyU`UNTozlDO$P~A*>pRuDB|GzBf}CWSE`Dee4`??70wV z6-#ABQk2{{5jiqspnbHt;lY)HM!dj=J2_)xl+?!AX`j@+#H`il(k}39HAl{RD>-C8 wk0fj@q{BK-&q|zzxB8xy>Bgt_!PK6aesz{}tN$LoLm{1$>Z2SnWn#B}0eHwMS^xk5 literal 0 HcmV?d00001 diff --git a/assets/img/desktop.ini b/assets/img/desktop.ini new file mode 100644 index 0000000000000000000000000000000000000000..3a4e71b7226fb57ef3d9c42f0bf32c9af36f43aa GIT binary patch literal 244 zcmY+8y9&ZU5JgWd_z(F2SyU`UNTozlDO$P~A*>pRuDB|GzBf}CWSE`Dee4`??70wV z6-#ABQk2{{5jiqspnbHt;lY)HM!dj=J2_)xl+?!AX`j@+#H`il(k}39HAl{RD>-C8 wk0fj@q{BK-&q|zzxB8xy>Bgt_!PK6aesz{}tN$LoLm{1$>Z2SnWn#B}0eHwMS^xk5 literal 0 HcmV?d00001 diff --git a/assets/img/medium.png b/assets/img/medium.png new file mode 100644 index 0000000000000000000000000000000000000000..3d5e2bf2fb8f1d834943ac85af7737a61901c01f GIT binary patch literal 5026 zcmeHLX;c$g7G{;j4HOpyNjiYWZjyo!P+~#|0ultl01{-;kQ5LJNvISi&?+i!ICe%j z=qL{00*-nF0}6R5wh5EAdHRzW4L?@=Iy0Q z44TWKU_zYy?EQqxz*w$#G6V)DuMA=*$FW^F7^~3 z9F~ymok&Cn^wPU;^G3>6957M zheY5+Nqm?k!SO}bDvD7K4^YI0xI&mK;G=|?*L4UN0eZ2V`5>^IE*hEQyI}4kg$XZ#2$duF`prYu>x2iiWLaIj2w5X z@e@$0bAX8vYPfozMzfDknB>QT;y`4ty;wXEs7~<77Xn5F z!Yo+5=rMuDCq$wp!m$EK6d(|BRZ=2;mBMH;hfNw?r+PRlIgJO8jz)((u1aSTkHwFn zU?eyW7|lxL!5Cl+0jPFG10e&S6RP;x5XgcB(1ZkmV8Z7KKI77O)m#(7Dl(W0^S}vI zn#5z(@;}e@6Ce4LlEEV6JO+VKyy*Xx>8sr2iTh4kHY(LJ0dfx5Fr6PQP?!1VF<3F4s57qzU>nxr{%(7J+=^_pumx>DgXy(Wa%P zKScMS1xcEEm~@earx~AqT%Iu}G^2po&+nN#(|rr1eaceDtaj^92KYZR8>u@c8x&e% zPeO-^YZoNY&^9-1^k*%VwoytsIL9X6l)Bgbd!tX-9?FMa1p6s2zsWfyh^%~?n4Ekk zk^`Na^G`GDfwnnopH3^)kHISxgtBJ2Pd=gfiR9+#ho=>FL&+asfbEJO&tJ)I0(WfO zs#uWRC=XkFu&x6v=SepWD8y%&cA+`9-rvgISmoYgQUKfoik@au?Btu@4gbq=wvmn{ zD!MPdKyJ3l3|0ByAF>h0yOV{DfA4S`y8WbVU~tt&%XPhm13H%P9#?JUKbA42%;g1K zPi2+sQ-fxmGfU?=R9KSR>$G|sHe1i9P@}~MR(D#>sCeI$$(>Jbr#0>xNhCG|7$lHy zE$3c*y9drV?>6^ps!Y0R!(dO>><=Slw_vJ+%gXyYEWPR1Nbe#Vy>n1j=~nK~kM&~* zK5QZykKDMp*Xr5YeAJdJ5h(-n{sxQdv4b6h%TK6YL@oOUWCIDK1QOI!qgPIphw5mRz|E5+fW>|;%? zMXB35bcwZ!TRFmJj?w5f-a6EhNpCJMbp2C1|WgR2%sRL9{v zdMkv#zkAUUtW*{U8yxRHh+9Isx4t_4tWdUQ6+0x-s!U(pK8v^rFeJTyKj?&?Qf(Z- zJT?E}3g5o{cU&%%1{`i3IDML)WWA&Lx?XWxKuAGOmRD!`O)8O0ve6eS1HlHY^_I(S zcCJppfQ7G?%m|l{tb0gQTG#00!5KBh*$<}u9yXk%TQ@V8o-4bebnU7=nk&1vquln* zzCb5~9E{a~+`9p%Yk*43a5>7x?e}piTZOrD{9LwW*%V7m^=tz@borCe8&?gLHK^{M zXLm++q9ZVT9>vuC8E_UsLic*L(!u=LBre2tV8}b$q~{S z9?=-xh2h&~&hJ4LWBk!C%s0+hlv=znlxvgFOwEitX@Oxh*1vgYOcHLMM}W}TDWrQtCoaIvr=NF#QSMyc7-^arNN;yjg6{* zW*2CCynnEpQ>Z&Fyw!Yi9`npk20eydt5;~Tk`#Qs#M_NSyCZX}(w3T94)ryf)QZHx zShGRW_K>&(@AZ^H8=|CM*J}NB77f;SE3$5;j_95Win>gkJJ0;zEA9ngIrEN+L(cls zvnz;gbI|?b^|bu$nR(Z5-7B2t6WOv)+hfviy@wmj_TO;b3q+XPt|PR@Hp#0Zv`$LQ zy&lZnT$xLWc%FB#`L?_Er2OsJMFD+_bqj5&Sm_#6x%Fx@pw8z}7-TEgi8DgKHeG5} z`FS|UB|9%9by%AweB^uc|g1QIMs2%^fv=Tp=i)6 zyTyiPI)CpB+kN4fPQo9O4lDD_;B7JdJf>ZiBryA0Zdj$d#|y=tcl literal 0 HcmV?d00001 diff --git a/assets/img/small.png b/assets/img/small.png new file mode 100644 index 0000000000000000000000000000000000000000..5db3ef8ccfc4dcd459df8dde4608ec5a7a8f25be GIT binary patch literal 4332 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S1|*9D%+3HQ$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWw2(4w)elB@w}FfdWj%4dKI|^K-~-sHue<-iOJciB??KY z>6v-9O7C~?S5nAKu~iB;^)>Jbs{}UJ3djZt>nkaMm6T-LDnT3-;TxdfoL`ixV4`QFXQZ2KU}mgfYOH5$ zYGh_)qN8ABU|^wdV6Ja$plfJhWngM$VyFNGN_JcdHbp6ERzWUqQ0ss^TcwPWk^(Dz z{qpj1y>er{{GxPyLrY6beFGzXBO_g)3fwM zQsi1ul9*Bi%LbV8&Y2~ZxMhQYB?mYS;4nQPIX?xMOd$yvi{T|jxC{?T%?Zyh0+u0I z^}6OJX5y0%ErQ8{6NC*oX(1H=z}SF@0SgvjnWhgf)S#&eTK>?A0*4l@42PLJY6&bP zh@wY>i>P3NDH;tfSV#~>j|LY}!30w@8eFiDAc`IhE~0`7rU+kfaUr@zsd>QmaXGNl z({fSzDFXwulc$SgNX4x+A>RJNffBaHbN%E4GQs=Lw20eW z>hZZFKiFfm|FHHRl;uvYQE>CDk!ECF?67jnC4+!p4Sw3W=~izm-iKyMZ<}-S%+B>c z_f_w+EVqcgzA;qbMe>`=;&&fzSbQw3`{)TJ5!cp}Du?!NmdvzlzEH!lwz~ZA{bz?S zA3yxSLT*>wp_j($f-~kiC#ZFN7C%?mc3HjZOO0Lsi%VQQO^jlzXR=JWu;*~A&olF9 z&5B|*zkZwK+|J3kyIETKu<{G*+ua!@tncsDGz1EK{P*^FbWNG9_on3&!$nktR~tyM zd}B(z75<4!=%dQyjeBHVlY^Dl#qB;c&3mtR_A`&pS`?TUjB zOQwjsDG7cG>Eo*@T*j9-U$wivB2@LuqPy*D>iI zS=PldTX(ZE-ux=#8Rf7sB4zg#6W&FhcXT$N+sB)>xpV97Z@(2L9G!XQ|C)KRawm$o zHvZu9`zn*ZX7cK{^HW!qxfyS*DBtwvO7Xog{b@^7fBdmC%Qum_Sh+>mS5LgG($?bE zU00zk1}mS=U75u=mGSjS$)y=(yCU6i|&N|%lyw_ Zz#vxNX(DqfQ3Evo;OXk;vd$@?2>|NRMbH2M literal 0 HcmV?d00001 diff --git a/assets/img/watermark.png b/assets/img/watermark.png new file mode 100644 index 0000000000000000000000000000000000000000..3a7d5ab71fefb9401ed6545df0739393821a1916 GIT binary patch literal 6555 zcmeHMdstH07RO6DlSz-MvBGSKtke=vQHep#i3;XlcmK(M_Bng4_51DpTWc@& z`AqZiT8c728z2w}l$)!I9|AE3jX>xrzDB|`VyKJ+4>KTI5aiDZhZ5*q0O8E!gaH^g zHa!CH1L(}e*gpUY9K09|2!et3@kGokYWIAA1*m@E?W2itR=(?T@_^^kf#rZ%HaYSBF-9TZOI_m*CD`CN+z7nYqD71F z1Z%vtwI%Ff$xDoe=zPm)-kbr5K@1mw$KZl75Xgzf3}Dj3IB}2z77N=kL*Putd+eAv zE=!BdWZ(f7zy_ir9^MLPg&*z@E8z!5L_)mxVbQ!Hm0`W{e0mHVLcnviJ|9KKL~#n3L62Ql%(J+$H4JPoqHUohE|&W!@#TrZ)s zcz~ARgKY&6<`2;!?WTtWdcPpDa~u@O;qrVqJa9lt*gl{zhQef!2luIc9hBUe1r5Fp zzOujpoyjbEbc6$zZ^;D0>2WLwiyw->4`f9bLcxCwIDpUK0(6MO9Y){}#C}Zh5th!X z#Tp(w00w~&3m68aBOa=j|9Gt*@F*XY4CKM*F#zDQdH*Y>QL!n*^G>D?N=4w^KnVadfL6+&Q#0FbcX4gTsW&bg+O&0Ef7vfd>Gr z6&xQ{tgTDgrINLGwYPLC72OKCQZ7?;tJJM;WF2jCd51#Xt?rU3+gdt1VV_pH ztWDn4skkx5(iDLhpW^1?9Ke6r`nZKFa{Y(E*Ju(3DzEp-y4hOx&g1l4X3G`Yc4}DY zEsedAZMOUFvUL}Zey_eQLOhk^8q^?Mkr_Q5^mi$D#l-hdy zwOX2g(R-hXQ-hFWbZ*+*`p&L2;-yHj@BRD2V}=cqGr1_*j4R8~p_DZdD7IPUB$Ii; zRO4Gf-P{@k18qNZoirnvIj6q%{Omujyp*Cqfiu~QSXO^ODdvEf0zU=s#alSm#Ruwx zflJQ&gdg+Yic0sMzdP1xu^ZrQm&;~Z^;YIec`KKX-xB6Wy-QD#y z?eC56N_VCjc_6nxYVK>5ysSPYZ?4F!Z4UfJDQdO9>FkbFEPK0}GA+rf>Tt)FG0kE= zt_Lgi@&g5TPdTm&`+xhOAe+cCzDa- zg$uHXmsaG49ITt)3EtBHSuf7zP06D;CK+WbADGr4B)rJF{d7%P_bTQ0f%t}>r;NMX z`-Br$N@8W}EwPRyacT=G9VVg`{V(42Pd2d+PsNqqoL_s}<3tUD>aW47diTe7fI%zz zo<4Zx@cMWQ((KTMgX|1_H99tMhU2`iZh@`~I8(M7rwSJ*D3)`!fLBcvNndvaY%Vy^1T5lD0}3+>+qUW#fR02 z!Ift3oPKL>HxuiXxm@dUd0bFbBoS08K~c*TP%zuP+_AuXZNQqiy1-N6tLx)bSojp} zHN%IL?ZI2%L;7n;w!T(ujVX#?+LVJ?fU|HKs|nrbdnhZ&18GP`_1b|!l&yap%S&_x z1^I+ulP1V3fA3jTG0|C6KMp=RIrN9~P{O2`RK#D)|@XnoGR86io@O&$>qScevY?i z6uK#~s_M@ja3V66x7w_|V3u1KQ3e{F4J$8Rj1Kj&m~gV>VZpQC*{o}NwkaX*+#)us zwya*nQc$fB?mXh&6j%S|13fMSS(*% z>YeZHirl!Lzr0>p4SHHT<;=ciks>dxjm>%8wiGRYgFH74KI%^w9$%MfinGgFqu<$; zB3YO63hWg4PZei|RMR}*V`ymXg%8MbJYaI{^$m}phy=7Rv-IKkKjBEkT;K6h***9? zIX^4}CGEcfd;_uG^>~liPKCV0dSMt`XzSTFEOm=NP_YwM*Sb+ou&mIjo5=3%+Z-ThEPT$4ih@t53wk9$hW_+t4z#JRNW--^csqh;!RfwSSlxxn z+jHA~;Q*ZJlnIHVaa)!nx0p?Ud2M1y6bs2b)XRwxa~`-YZGgM{{GHcHQ>CQ)?3=P# z!o-M%CFmpeYoa&{RC{ga?>UzrcKW4B@-$H3SiQ)!iF{M#w$a|o_cZl<<#Vs{G~(jh z^Gw>Se3Y5xPA4q3mG+}+5PfG$$YXkact+s`N@?PhoDlnTC%A(JbCcG^`|-{L$rsc7 z`?qaa3YS&rS$e#U59#6tTl0`zj}509l@})#5*K$g72O+u?W&~j`W>mX`KQGB9J&Wm z@t{j-WxKR$>#D7dbqDeauHNGmXJ_cYPH&ufvs!skaE1Rwf-O*l#x$X{ zwz6?g7+16E!0zt}9ifMV;PbiXXq~LN-7>YQ%@w;QpzZDSKKTwJyk;D=nQ$R&+Q~l8 z8ScEFTh2VsF&68s4-|Sn{;F5)CzQ*czP)S#SJ!Suj8krmCQ{Y!dp7T2fa}@lSFmHx z)41iUgz0uO=XpB4;~B@pzkB@ahQ8DpPo%PonoAdW#&AFBth3+!>>^6~a+UBH3T^?N zB*&UNh0m|V;<((631L#`?y=GYbC`9udH%{L{jJ@1i51^v5hmx8H>_R>r|G$H>9l1H zr}^rIibn=xWyWrwx)NYequdpAmw`>AT_%Pcbbh0d47)Ron+)&1Sn5ii1< fJSFeOPDfZIMV-!b6BP{nyTpy=<#PI;p+Ei$HUr(4 literal 0 HcmV?d00001 diff --git a/assets/js/.gitignore b/assets/js/.gitignore new file mode 100644 index 0000000..0953f01 --- /dev/null +++ b/assets/js/.gitignore @@ -0,0 +1 @@ +.x diff --git a/assets/js/desktop.ini b/assets/js/desktop.ini new file mode 100644 index 0000000000000000000000000000000000000000..3a4e71b7226fb57ef3d9c42f0bf32c9af36f43aa GIT binary patch literal 244 zcmY+8y9&ZU5JgWd_z(F2SyU`UNTozlDO$P~A*>pRuDB|GzBf}CWSE`Dee4`??70wV z6-#ABQk2{{5jiqspnbHt;lY)HM!dj=J2_)xl+?!AX`j@+#H`il(k}39HAl{RD>-C8 wk0fj@q{BK-&q|zzxB8xy>Bgt_!PK6aesz{}tN$LoLm{1$>Z2SnWn#B}0eHwMS^xk5 literal 0 HcmV?d00001 diff --git a/assets/js/imageLoader.js b/assets/js/imageLoader.js new file mode 100644 index 0000000..5169677 --- /dev/null +++ b/assets/js/imageLoader.js @@ -0,0 +1,84 @@ +var currentImage = 0; + +/** + * Changes the + */ +function ev_mousemove (ev, id, imageObj, images, idOtherSide, imageObjOtherSide, + imagesOtherSide, id_linked, imagesLinked) { + var canvas = document.getElementById(id); + var context = canvas.getContext("2d"); + var canvasOtherSide = document.getElementById(idOtherSide); + var contextOtherSide = canvasOtherSide.getContext("2d"); + + // Get the mouse position relative to the canvas element. + if (ev.layerX || ev.layerX == 0) { // Firefox + x = ev.layerX; + } else if (ev.offsetX || ev.offsetX == 0) { // Opera + x = ev.offsetX; + } + + // image_width / images + var incr = 300 / images.length; + // image_width / increment + + var rect = canvas.getBoundingClientRect(); + x = ev.clientX - rect.left; + var pos = x / incr; +// alert(x + ', ' + ev.clientX + ', ' + rect.left); +// alert(x + ', ' + incr + ', ' + pos + ', ' + images.length + ', ' + imagesLinked.length + ', ' + currentImage); + if (currentImage != Math.floor(pos)) { + currentImage = Math.floor(pos); + if (currentImage > images.length) { + currentImage = images.length-1; + } +// alert(currentImage); + imageObj.onload = function() { + context.drawImage(imageObj, 0, 0); + } + imageObjOtherSide.onload = function() { + contextOtherSide.drawImage(imageObjOtherSide, 0, 0); + } +// imageObjAlg.onload = function() { +// } + if (currentImage < images.length) { + imageObj.src = images[currentImage]; + imageObjOtherSide.src = imagesOtherSide[currentImage]; + } else { + return; + } + + var canvasLinked = document.getElementById(id_linked); + + if (canvasLinked != null) { + var context2 = canvasLinked.getContext("2d"); + var multiplier = 1; + if (images.length < imagesLinked.length) { + multiplier = Math.round(imagesLinked.length / images.length); + } else if (images.length > imagesLinked.length) { + multiplier = Math.round(images.length / imagesLinked.length); + } else { + multiplier = 1; + } + var imageObj2 = new Image(); + imageObj2.onload = function() { + context2.drawImage(imageObj2, 0, 0); + contextOtherSide.drawImage(imageObjOtherSide, 0, 0); + } + if (images.length < imagesLinked.length) { + var index = 0; + if (currentImage > 0) { + index = Math.round((currentImage+1) * multiplier ); + if (index > imagesLinked.length -1) { + index = imagesLinked.length -1; + } + } + imageObj2.src = imagesLinked[index]; + imageObjOtherSide.src = imagesOtherSide[index]; + } else { + var index = Math.floor( (currentImage + 1 ) / multiplier); + imageObj2.src = imagesLinked[index]; + imageObjOtherSide.src = imagesOtherSide[index]; + } + } + } +} \ No newline at end of file diff --git a/assets/js/module.js b/assets/js/module.js new file mode 100644 index 0000000..e3dfb2e --- /dev/null +++ b/assets/js/module.js @@ -0,0 +1,16 @@ +$(document).ready(function() { + function selectField(e) { + + var side = e.data.side, id = $(this).val(); + + var field = window["OphInKowastereo_available_fields_" + side][id]; + + $('#Element_OphInKowastereo_Image_image_' + side).attr('src', field.url); + $('#Element_OphInKowastereo_Image_strategy_' + side).text(field.strategy); + $('#Element_OphInKowastereo_Image_pattern_' + side).text(field.pattern); + } + + $('#Element_OphInKowastereo_Image_right_field_id').change({side: "right"}, selectField); + $('#Element_OphInKowastereo_Image_left_field_id').change({side: "left"}, selectField); +}); + diff --git a/assets/sass/components/_event.scss b/assets/sass/components/_event.scss new file mode 100644 index 0000000..a0566e1 --- /dev/null +++ b/assets/sass/components/_event.scss @@ -0,0 +1,25 @@ +// * OpenEyes +// * +// * (C) Moorfields Eye Hospital NHS Foundation Trust, 2008-2011 +// * (C) OpenEyes Foundation, 2011-2013 +// * This file is part of OpenEyes. +// * OpenEyes 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 (at your option) any later version. +// * OpenEyes 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 OpenEyes in a file titled COPYING. If not, see . +// * +// * @package OpenEyes +// * @link http://www.openeyes.org.uk +// * @author OpenEyes +// * @copyright Copyright (c) 2008-2011, Moorfields Eye Hospital NHS Foundation Trust +// * @copyright Copyright (c) 2011-2013, OpenEyes Foundation +// * @license http://www.gnu.org/licenses/gpl-3.0.html The GNU General Public License V3.0 + +.event { + border-color: #a5a0a9; + .event-content { + background-image: image-url("watermark.png"); + } + .event-title { + background-image: image-url("medium.png"); + } +} diff --git a/assets/sass/components/desktop.ini b/assets/sass/components/desktop.ini new file mode 100644 index 0000000000000000000000000000000000000000..3a4e71b7226fb57ef3d9c42f0bf32c9af36f43aa GIT binary patch literal 244 zcmY+8y9&ZU5JgWd_z(F2SyU`UNTozlDO$P~A*>pRuDB|GzBf}CWSE`Dee4`??70wV z6-#ABQk2{{5jiqspnbHt;lY)HM!dj=J2_)xl+?!AX`j@+#H`il(k}39HAl{RD>-C8 wk0fj@q{BK-&q|zzxB8xy>Bgt_!PK6aesz{}tN$LoLm{1$>Z2SnWn#B}0eHwMS^xk5 literal 0 HcmV?d00001 diff --git a/assets/sass/desktop.ini b/assets/sass/desktop.ini new file mode 100644 index 0000000000000000000000000000000000000000..3a4e71b7226fb57ef3d9c42f0bf32c9af36f43aa GIT binary patch literal 244 zcmY+8y9&ZU5JgWd_z(F2SyU`UNTozlDO$P~A*>pRuDB|GzBf}CWSE`Dee4`??70wV z6-#ABQk2{{5jiqspnbHt;lY)HM!dj=J2_)xl+?!AX`j@+#H`il(k}39HAl{RD>-C8 wk0fj@q{BK-&q|zzxB8xy>Bgt_!PK6aesz{}tN$LoLm{1$>Z2SnWn#B}0eHwMS^xk5 literal 0 HcmV?d00001 diff --git a/assets/sass/module.scss b/assets/sass/module.scss new file mode 100644 index 0000000..7e7e680 --- /dev/null +++ b/assets/sass/module.scss @@ -0,0 +1,20 @@ +// * OpenEyes +// * +// * (C) Moorfields Eye Hospital NHS Foundation Trust, 2008-2011 +// * (C) OpenEyes Foundation, 2011-2013 +// * This file is part of OpenEyes. +// * OpenEyes 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 (at your option) any later version. +// * OpenEyes 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 OpenEyes in a file titled COPYING. If not, see . +// * +// * @package OpenEyes +// * @link http://www.openeyes.org.uk +// * @author OpenEyes +// * @copyright Copyright (c) 2008-2011, Moorfields Eye Hospital NHS Foundation Trust +// * @copyright Copyright (c) 2011-2013, OpenEyes Foundation +// * @license http://www.gnu.org/licenses/gpl-3.0.html The GNU General Public License V3.0 + +/** Visual Fields module styles */ + +@import "openeyes/module"; +@import "components/event"; diff --git a/commands/AnonymiseFieldsCommand.php b/commands/AnonymiseFieldsCommand.php new file mode 100644 index 0000000..0cad40f --- /dev/null +++ b/commands/AnonymiseFieldsCommand.php @@ -0,0 +1,243 @@ +. + * + * @package OpenEyes + * @link http://www.openeyes.org.uk + * @author OpenEyes + * @copyright Copyright (c) 2008-2011, Moorfields Eye Hospital NHS Foundation Trust + * @copyright Copyright (c) 2011-2012, OpenEyes Foundation + * @license http://www.gnu.org/licenses/gpl-3.0.html The GNU General Public License V3.0 + */ +class AnonymiseFieldsCommand extends CConsoleCommand { + + public function getHelp() { + return "Usage:\n\n\tanonymisefields [command]\n\nwhere command can be any one of:\n" + . "\ntransformFmes --fmesDir=[inputdir] --outputDir=[outputDir] --realPidFile=[pidFile] --anonPidFile=[anonPidFile]\n\n" + . "\tTake the specified directory of FMES humphrey measurements, unpack the image from it, anonymise\n" + . "\tthe patient data, swap the recorded patient ID and swap it for the specified anonymous PID\n" + . "\tTwo files must be specified, each giving a newline separated list of patient IDs to substitute.\n" + . "\n\n" + . "anonymisefields redact --pattern=[filePattern]\n\n" + . "\tFor all files that match the specified pattern in the database, perform image oerations to remove name, PID etc.\n" + . "\tOnly images of the correct size (2400x3180) are transformed.\n" + . "\n\n" + . "anonymisefields redactTif --inDir=[tifInDir] --outDir=[tifOutDir]\n\n" + . "\tFor all files that match the specified pattern, perform image oerations to remove name, PID etc.\n" + . "\tOnly images of the correct size (2400x3180) are transformed.\n"; + + } + + /** + * Take a list of real patient identifiers that appear in a collection + * of FMES files, and remove the 'real' PID in the FMES file in favour + * of + * + * @param type $realPidFile + * @param type $anonPidFile + */ + public function actiontransformFmes($fmesDir, $outputDir, $realPidFile, $anonPidFile) { + foreach (array($fmesDir, $realPidFile, $anonPidFile) as $file) { + if (!file_exists($file)) { + echo $file . ' does not exist' . PHP_EOL; + exit(1); + } + } + + $realPids = file_get_contents($realPidFile); + $anonPids = file_get_contents($anonPidFile); + $rPids = explode(PHP_EOL, $realPids); + $aPids = explode(PHP_EOL, $anonPids); + // make sure PID count is equal: + if (count($rPids) != count($aPids)) { + echo 'Error: PID counts do not match; file contents must match 1-1' . PHP_EOL; + exit(1); + } + // check all real patients exist: + foreach ($aPids as $pid) { + if ($pid) { + if (count(Patient::model()->find("hos_num='" . $pid . "'")) < 1) { + echo 'Failed to find anonymous patient ' . $pid . PHP_EOL; + exit(1); + } + } + } + // now check that all 'real' patients are listed in the files: + $entries = array(); + // build up an array of matches we've encountered so far, and if it's + // been matched before, ignore it. + + $smgr = Yii::app()->service; + $fhirMarshal = Yii::app()->fhirMarshal; + if ($entry = glob($fmesDir . '/*.fmes')) { + foreach ($entry as $file) { + $field = file_get_contents($file); + $fieldObject = $fhirMarshal->parseXml($field); + $match = $this->getHosNum($file, $field); + if (!in_array($match, $entries)) { + // only add it if it's in the list of real patient IDs: + if (in_array($match, $rPids)) { + array_push($entries, $match); + } + } + } + } + // now create new FMES files + // need to go through each one, pairing anonymised IDs with real ones, + // replacing the real ID with the anonymised ID; note that we also + // need to swap out the image and do some redaction: + + if ($entry = glob($fmesDir . '/*.fmes')) { + foreach ($entry as $file) { + $field = file_get_contents($file); + $fieldObject = $fhirMarshal->parseXml($field); + // swap out hos nums: + $match = $this->getHosNum($file, $field); + if (in_array($match, $rPids)) { + $index = array_search($match, $rPids); + $anonPid = $aPids[$index]; + unset($fieldObject->patient_id); + $fieldObject->patient_id = "__OE_PATIENT_ID_" . $anonPid . "__"; + echo 'replacing ' . $match . ' with ' . $anonPid . PHP_EOL; + } else { + // not interested, move on: + continue; + } + // now swap out the actual image. This is slightly involved - + // we need to write the image to temporary file, perform + // image operations on it to anonymise PID, DoB etc., + // step 1: extract image: + $image = base64_decode($fieldObject->image_scan_data); + unset($fieldObject->image_scan_data); + // now redact it - we need to perform imagemagick operations: + $img = 'img.gif'; + file_put_contents($img, $image); + $image = new Imagick($img); + $this->fillImage($image); + $image->writeImage($img); + $contents = file_get_contents($img); + $fieldObject->image_scan_data = base64_encode($contents); + $doc = new DOMDocument; + file_put_contents($outputDir . '/' . basename($file), $fhirMarshal->renderXml($fieldObject)); + echo "Successfully written " . $file . PHP_EOL; + } + } + } + + /** + * Take images from the in-directory, anonymise them and place the resulting + * file in the sepcified out-directory. + * + * @param type $inDir + * @param type $outDir + */ + public function actionRedactTif($inDir, $outDir) { + + if ($entries = glob($inDir . '/*.tif')) { + foreach($entries as $entry) { + $this->anonymiseTif($inDir . '/' . basename($entry), $outDir); + } + } + } + + /** + * Trawl an existing OE database and find all files that match the given + * pattern. A pattern MUST be specified. + * + * If no pattern is specified, all images that match the standard humphrey + * image size are processed. + */ + public function actionRedact($pattern = null) { + $criteria = new CDbCriteria; + if ($pattern != null) { + $criteria->condition = 'name like :name'; + $criteria->params = array(':name' => $pattern); + } else { + echo 'You MUST specify a file pattern to match.'; + } + $files = ProtectedFile::model()->findAll($criteria); + // we can't really filter images, except on size - for now just + // assume the count is half the amount when taking thumbnails into + // consideration + echo (count($files)/2) . " files found for modification."; + if ($files) { + foreach ($files as $file) { + if (file_exists($file->getPath())) { + $this->anonymiseTif($file->getPath()); + } else { + echo 'Could not transform file; ' . $file->getPathName() + . ' does not exist.' . PHP_EOL; + } + } + } + } + + /** + * Create a new image based on the image passed in and anonymise. + * + * @param type $file specified image file to anonymise; must be a valid path + * and the image must be the correct size. + * @param type $out the directory to place the anonymised file. + */ + private function anonymiseTif($file, $out) { + $image = new Imagick($file); + $geo = $image->getImageGeometry(); + // only modify the main image, not the thumbnails: + if ($geo['width'] == 2400 + && $geo['height'] == 3180) { + echo 'Modifying ' . $file . PHP_EOL; + $this->fillImage($image); + echo $out.PHP_EOL; + $image->writeImage($file . '.tmp'); + copy($file . '.tmp', $out . '/' . basename($file, '.tif') . '.gif'); + } + } + + /** + * Fills the image at the specified locations. Designed specifically to + * grey-out patient name, DoB, PID and HFA serial number, + * + * @param Imagick $image + */ + private function fillImage($image) { + $draw = new ImagickDraw(); //Create a new drawing class (?) + + $draw->setFillColor('grey'); + // main patient details - name, pid, dob: + $draw->rectangle(190, 80, 2210, 254); + // date, time, age: + $draw->rectangle(1773, 291, 2160, 489); + // bottom of image - serial number etc.: + $draw->rectangle(190, 2960, 2160, 3099); + $image->drawImage($draw); + $image->setImageFormat('gif'); + } + + /** + * + * @param type $file + * @param type $field + * @param array $matches + * @return type + */ + private function getHosNum($file, $field) { + + $matches = array(); + preg_match("/__OE_PATIENT_ID_([0-9]*)__/", $field, $matches); + if (count($matches) < 2) { + echo "Failed to extract patient ID in " . basename($file) . "; moving to " . $this->errorDir . PHP_EOL; + $this->move($this->errorDir, $file); + continue; + } + return str_pad($matches[1], 7, '0', STR_PAD_LEFT); + } + +} diff --git a/commands/AnonymiseFieldsCommand.php.anon-xml b/commands/AnonymiseFieldsCommand.php.anon-xml new file mode 100644 index 0000000..726d13a --- /dev/null +++ b/commands/AnonymiseFieldsCommand.php.anon-xml @@ -0,0 +1,223 @@ +. + * + * @package OpenEyes + * @link http://www.openeyes.org.uk + * @author OpenEyes + * @copyright Copyright (c) 2008-2011, Moorfields Eye Hospital NHS Foundation Trust + * @copyright Copyright (c) 2011-2012, OpenEyes Foundation + * @license http://www.gnu.org/licenses/gpl-3.0.html The GNU General Public License V3.0 + */ +class AnonymiseFieldsCommand extends CConsoleCommand { + + public function getHelp() { + return "Usage(first form):\n\nanonymisefields transformFmes --fmesDir=[inputdir] --outputDir=[outputDir] --realPidFile=[pidFile] --anonPidFile\n\n" + . "Take the specified directory of FMES humphrey measurements, unpack the image from it, anonymise\n" + . "the patient data, swap the recorded patient ID and swap it for the specified anonymous PID\n" + . "Two files must be specified, each giving a newline separated list of patient IDs to substitute.\n" + . "\n" + . "Usage: (second form):\n\n" + . "anonymisefields redact --pattern=[filePattern]\n\n" + . "For all files that match the specified pattern, perform image oerations to remove name, PID etc.\n" + . "Only images of the correct size (2400x3180) are transformed.\n"; + + } + + /** + * Take a list of real patient identifiers that appear in a collection + * of FMES files, and remove the 'real' PID in the FMES file in favour + * of + * + * @param type $realPidFile + * @param type $anonPidFile + */ + public function actiontransformFmes($fmesDir, $outputDir, $realPidFile, $anonPidFile) { + foreach (array($fmesDir, $realPidFile, $anonPidFile) as $file) { + if (!file_exists($file)) { + echo $file . ' does not exist' . PHP_EOL; + exit(1); + } + } + + $realPids = file_get_contents($realPidFile); + $anonPids = file_get_contents($anonPidFile); + $rPids = explode(PHP_EOL, $realPids); + $aPids = explode(PHP_EOL, $anonPids); + // make sure PID count is equal: + if (count($rPids) != count($aPids)) { + echo 'Error: PID counts do not match; file contents must match 1-1' . PHP_EOL; + exit(1); + } + // check all real patients exist: + foreach ($aPids as $pid) { + if ($pid) { + if (count(Patient::model()->find("hos_num='" . $pid . "'")) < 1) { + echo 'Failed to find anonymous patient ' . $pid . PHP_EOL; + exit(1); + } + } + } + // now check that all 'real' patients are listed in the files: + $entries = array(); + // build up an array of matches we've encountered so far, and if it's + // been matched before, ignore it. + + $smgr = Yii::app()->service; + $fhirMarshal = Yii::app()->fhirMarshal; + if ($entry = glob($fmesDir . '/*.fmes')) { + foreach ($entry as $file) { + $field = file_get_contents($file); + $fieldObject = $fhirMarshal->parseXml($field); + $match = $this->getHosNum($file, $field); + if (!in_array($match, $entries)) { + // only add it if it's in the list of real patient IDs: + if (in_array($match, $rPids)) { + array_push($entries, $match); + } + } + } + } + // now create new FMES files + // need to go through each one, pairing anonymised IDs with real ones, + // replacing the real ID with the anonymised ID; note that we also + // need to swap out the image and do some redaction: + + if ($entry = glob($fmesDir . '/*.fmes')) { + foreach ($entry as $file) { + $field = file_get_contents($file); + $fieldObject = $fhirMarshal->parseXml($field); + // swap out hos nums: + $match = $this->getHosNum($file, $field); + if (in_array($match, $rPids)) { + $index = array_search($match, $rPids); + $anonPid = $aPids[$index]; + unset($fieldObject->patient_id); + $fieldObject->patient_id = "__OE_PATIENT_ID_" . $anonPid . "__"; + echo 'replacing ' . $match . ' with ' . $anonPid . PHP_EOL; + } else { + // not interested, move on: + continue; + } + if ($fieldObject->source) { + $source = $this->anonymiseXml(base64_decode($fieldObject->source)); + unset($fieldObject->source); + $fieldObject->source = $soruce; + } // now swap out the actual image. This is slightly involved - + // we need to write the image to temporary file, perform + // image operations on it to anonymise PID, DoB etc., + $image = base64_decode($fieldObject->image_scan_data); + unset($fieldObject->image_scan_data); + // now redact it - we need to perform imagemagick operations: + $img = 'img.gif'; + file_put_contents($img, $image); + $image = new Imagick($img); + $this->fillImage($image); + $image->writeImage($img); + $contents = file_get_contents($img); + $fieldObject->image_scan_data = base64_encode($contents); + $doc = new DOMDocument; + file_put_contents($outputDir . '/' . basename($file), $fhirMarshal->renderXml($fieldObject)); + echo "Successfully written " . $file . PHP_EOL; + } + } + } + + /** + * Trawl an existing OE database and find all files that match the given + * pattern. A pattern MUST be specified. + * + * If no pattern is specified, all images that match the standard humphrey + * image size are processed. + */ + public function actionRedact($pattern = null) { + $criteria = new CDbCriteria; + if ($pattern != null) { + $criteria->condition = 'name like :name'; + $criteria->params = array(':name' => $pattern); + } else { + echo 'You MUST specify a file pattern to match.'; + } + $files = ProtectedFile::model()->findAll($criteria); + // we can't really filter images, except on size - for now just + // assume the count is half the amount when taking thumbnails into + // consideration + echo (count($files)/2) . " files found for modification."; + if ($files) { + foreach ($files as $file) { + if (file_exists($file->getPath())) { + $image = new Imagick($file->getPath()); + $geo = $image->getImageGeometry(); + // only modify the main image, not the thumbnails: + if ($geo['width'] == 2400 + && $geo['height'] == 3180) { + echo 'Modifying ' . $file->getPath() . PHP_EOL; + $this->fillImage($image); + $image->writeImage($file->getPath()); + } + } else { + echo 'Could not transform file; ' . $file->getPathName() + . ' does not exist.' . PHP_EOL; + } + } + } + } + + /** + * Fills the image at the specified locations. Designed specifically to + * grey-out patient name, DoB, PID and HFA serial number, + * + * @param Imagick $image + */ + private function fillImage($image) { + $draw = new ImagickDraw(); //Create a new drawing class (?) + + $draw->setFillColor('grey'); + // main patient details - name, pid, dob: + $draw->rectangle(190, 80, 2210, 254); + // date, time, age: + $draw->rectangle(1773, 291, 2160, 489); + // bottom of image - serial number etc.: + $draw->rectangle(190, 2960, 2160, 3099); + $image->drawImage($draw); + } + + /** + * + * @param type $file + * @param type $field + * @param array $matches + * @return type + */ + private function getHosNum($file, $field) { + + $matches = array(); + preg_match("/__OE_PATIENT_ID_([0-9]*)__/", $field, $matches); + if (count($matches) < 2) { + echo "Failed to extract patient ID in " . basename($file) . "; moving to " . $this->errorDir . PHP_EOL; + $this->move($this->errorDir, $file); + continue; + } + return str_pad($matches[1], 7, '0', STR_PAD_LEFT); + } + + /** + * + * @param type $source + * @return type + */ + private function anonymiseXml($source) { + $xml = new SimpleXMLElement($source); +// echo $xml-> + return ""; + } + +} diff --git a/commands/Gif2JPegCommand.php b/commands/Gif2JPegCommand.php new file mode 100644 index 0000000..1bcc80a --- /dev/null +++ b/commands/Gif2JPegCommand.php @@ -0,0 +1,126 @@ +. + * + * @package OpenEyes + * @link http://www.openeyes.org.uk + * @author OpenEyes + * @copyright Copyright (c) 2008-2011, Moorfields Eye Hospital NHS Foundation Trust + * @copyright Copyright (c) 2011-2012, OpenEyes Foundation + * @license http://www.gnu.org/licenses/gpl-3.0.html The GNU General Public License V3.0 + */ +class Gif2JpegCommand extends CConsoleCommand { + + + /** + * Take a list of real patient identifiers that appear in a collection + * of FMES files, and remove the 'real' PID in the FMES file in favour + * of + * + * @param type $realPidFile + * @param type $anonPidFile + */ + public function actionTransform($archiveDir) { + print $archiveDir . PHP_EOL; + $files = glob($archiveDir . "/*.jpg"); + echo count($files) . PHP_EOL; + foreach ($files as $file) { + echo basename($file) . PHP_EOL; + $pfs = ProtectedFile::model()->findAll("name=\"" . basename($file) . "\""); +// echo count($pfs) . PHP_EOL; + foreach($pfs as $pf) { + echo $pf->getPath() . PHP_EOL; + $dims = getimagesize($pf->getPath()); + echo $dims[3] . PHP_EOL; + } + } + return; + + $realPids = file_get_contents($realPidFile); + $anonPids = file_get_contents($anonPidFile); + $rPids = explode(PHP_EOL, $realPids); + $aPids = explode(PHP_EOL, $anonPids); + // make sure PID count is equal: + if (count($rPids) != count($aPids)) { + echo 'Error: PID counts do not match; file contents must match 1-1' . PHP_EOL; + exit(1); + } + // check all real patients exist: + foreach ($aPids as $pid) { + if ($pid) { + if (count(Patient::model()->find("hos_num='" . $pid . "'")) < 1) { + echo 'Failed to find anonymous patient ' . $pid . PHP_EOL; + exit(1); + } + } + } + // now check that all 'real' patients are listed in the files: + $entries = array(); + // build up an array of matches we've encountered so far, and if it's + // been matched before, ignore it. + + $smgr = Yii::app()->service; + $fhirMarshal = Yii::app()->fhirMarshal; + if ($entry = glob($fmesDir . '/*.fmes')) { + foreach ($entry as $file) { + $field = file_get_contents($file); + $fieldObject = $fhirMarshal->parseXml($field); + $match = $this->getHosNum($file, $field); + if (!in_array($match, $entries)) { + // only add it if it's in the list of real patient IDs: + if (in_array($match, $rPids)) { + array_push($entries, $match); + } + } + } + } + // now create new FMES files + // need to go through each one, pairing anonymised IDs with real ones, + // replacing the real ID with the anonymised ID; note that we also + // need to swap out the image and do some redaction: + + if ($entry = glob($fmesDir . '/*.fmes')) { + foreach ($entry as $file) { + $field = file_get_contents($file); + $fieldObject = $fhirMarshal->parseXml($field); + // swap out hos nums: + $match = $this->getHosNum($file, $field); + if (in_array($match, $rPids)) { + $index = array_search($match, $rPids); + $anonPid = $aPids[$index]; + unset($fieldObject->patient_id); + $fieldObject->patient_id = "__OE_PATIENT_ID_" . $anonPid . "__"; + echo 'replacing ' . $match . ' with ' . $anonPid . PHP_EOL; + } else { + // not interested, move on: + continue; + } + // now swap out the actual image. This is slightly involved - + // we need to write the image to temporary file, perform + // image operations on it to anonymise PID, DoB etc., + // step 1: extract image: + $image = base64_decode($fieldObject->image_scan_data); + unset($fieldObject->image_scan_data); + // now redact it - we need to perform imagemagick operations: + $img = 'img.gif'; + file_put_contents($img, $image); + $image = new Imagick($img); + $this->fillImage($image); + $image->writeImage($img); + $contents = file_get_contents($img); + $fieldObject->image_scan_data = base64_encode($contents); + $doc = new DOMDocument; + file_put_contents($outputDir . '/' . basename($file), $fhirMarshal->renderXml($fieldObject)); + echo "Successfully written " . $file . PHP_EOL; + } + } + } +} diff --git a/commands/LegacyFieldsCommand.php b/commands/LegacyFieldsCommand.php new file mode 100644 index 0000000..8681bae --- /dev/null +++ b/commands/LegacyFieldsCommand.php @@ -0,0 +1,239 @@ +. + * + * @package OpenEyes + * @link http://www.openeyes.org.uk + * @author OpenEyes + * @copyright Copyright (c) 2008-2011, Moorfields Eye Hospital NHS Foundation Trust + * @copyright Copyright (c) 2011-2012, OpenEyes Foundation + * @license http://www.gnu.org/licenses/gpl-3.0.html The GNU General Public License V3.0 + */ +class LegacyFieldsCommand extends CConsoleCommand { + + public $importDir; + public $archiveDir; + public $errorDir; + public $dupDir; + public $interval; + + public function getHelp() { + return "Usage: legacyfields import --interval=