diff --git a/.babelrc b/.babelrc
new file mode 100644
index 0000000..89b37f2
--- /dev/null
+++ b/.babelrc
@@ -0,0 +1,26 @@
+{
+ "presets": [
+ [
+ "env",
+ {
+ "modules": false,
+ "targets": {
+ "browsers": "> 1%",
+ "uglify": true
+ },
+ "useBuiltIns": true
+ }
+ ],
+ "react",
+ "stage-2"
+ ],
+ "plugins": [
+ "syntax-dynamic-import",
+ [
+ "transform-class-properties",
+ {
+ "spec": true
+ }
+ ]
+ ]
+}
diff --git a/.eslintrc b/.eslintrc
index d40482e..73e0fbf 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -3,5 +3,8 @@
"extends": "airbnb",
"globals": {
"React": true
- }
+ },
+ "env": {
+ "browser": true
+ },
}
diff --git a/.gitignore b/.gitignore
index 80dd26f..cafd3ab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -33,3 +33,5 @@ node_modules
# Ignore redis dumps
*.rdb
+/public/packs
+/node_modules
diff --git a/.postcssrc.yml b/.postcssrc.yml
new file mode 100644
index 0000000..bc4f02a
--- /dev/null
+++ b/.postcssrc.yml
@@ -0,0 +1,4 @@
+plugins:
+ postcss-smart-import: {}
+ precss: {}
+ autoprefixer: {}
diff --git a/.travis.yml b/.travis.yml
index 4cc8614..825f21e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,7 +4,11 @@ rvm:
dist: trusty
sudo: false
before_script:
+ - curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 0.27.5
+ - export PATH=$HOME/.yarn/bin:$PATH
- pip3 install https://github.com/sul-cidr/histonets-cv/archive/master.zip
- RAILS_ENV=test bundle exec rake db:migrate
- RAILS_ENV=test bundle exec rake assets:precompile
+cache:
+ yarn: true
# sudo: false Leaving this commented out, as we may need this to install the correct python version etc.
diff --git a/Gemfile b/Gemfile
index fdf557c..620bc27 100644
--- a/Gemfile
+++ b/Gemfile
@@ -19,6 +19,8 @@ gem 'coffee-rails', '~> 4.2'
gem 'jquery-rails'
gem 'react-rails'
+gem 'webpacker'
+
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
@@ -45,8 +47,6 @@ gem 'honeybadger', '~> 3.1'
source 'https://rails-assets.org' do
gem 'rails-assets-tether', '>= 1.1.0' # Required for tooltips/popover for twbs
- gem 'rails-assets-leaflet-iiif', '~> 1.0'
- gem 'rails-assets-leaflet', '~> 1.0'
gem 'rails-assets-css-toggle-switch'
end
diff --git a/Gemfile.lock b/Gemfile.lock
index 804b72a..9b5bcf2 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -194,8 +194,6 @@ GEM
railties (= 5.0.4)
sprockets-rails (>= 2.0.0)
rails-assets-css-toggle-switch (4.0.2)
- rails-assets-leaflet (1.0.2)
- rails-assets-leaflet-iiif (1.0.2)
rails-assets-tether (1.3.7)
rails-controller-testing (1.0.1)
actionpack (~> 5.x)
@@ -216,9 +214,8 @@ GEM
rb-fsevent (0.9.8)
rb-inotify (0.9.7)
ffi (>= 0.5.0)
- react-rails (1.9.0)
+ react-rails (2.2.1)
babel-transpiler (>= 0.7.0)
- coffee-script-source (~> 1.8)
connection_pool
execjs
railties (>= 3.2)
@@ -298,6 +295,10 @@ GEM
activemodel (>= 5.0)
debug_inspector
railties (>= 5.0)
+ webpacker (2.0)
+ activesupport (>= 4.2)
+ multi_json (~> 1.2)
+ railties (>= 4.2)
websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
@@ -334,8 +335,6 @@ DEPENDENCIES
puma (~> 3.0)
rails (~> 5.0.4)
rails-assets-css-toggle-switch!
- rails-assets-leaflet (~> 1.0)!
- rails-assets-leaflet-iiif (~> 1.0)!
rails-assets-tether (>= 1.1.0)!
rails-controller-testing
react-rails
@@ -350,6 +349,7 @@ DEPENDENCIES
tzinfo-data
uglifier (>= 1.3.0)
web-console
+ webpacker
wicked
BUNDLED WITH
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 930cd16..0286bff 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -10,16 +10,11 @@
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
-//= require leaflet
-//= require leaflet-iiif
-//= require leaflet-areaselect
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require tether
-//= require bootstrap-sprockets
//= require react
//= require react_ujs
-//= require components
//= require image-picker.min
//= require_tree .
diff --git a/app/assets/javascripts/components.js b/app/assets/javascripts/components.js
deleted file mode 100644
index 9ce7a4f..0000000
--- a/app/assets/javascripts/components.js
+++ /dev/null
@@ -1 +0,0 @@
-//= require_tree ./components
diff --git a/app/assets/javascripts/components/.gitkeep b/app/assets/javascripts/components/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 917acf2..57c4aaa 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -1,5 +1,3 @@
-@import "leaflet";
-@import "leaflet-areaselect";
@import "css-toggle-switch";
@import "bootstrap_custom_variables";
@import "bootstrap";
diff --git a/app/javascript/app-styles.sass b/app/javascript/app-styles.sass
new file mode 100644
index 0000000..d68ae8e
--- /dev/null
+++ b/app/javascript/app-styles.sass
@@ -0,0 +1 @@
+@import '~leaflet/dist/leaflet'
diff --git a/app/assets/javascripts/components/histogram.es6.jsx b/app/javascript/components/histogram.jsx
similarity index 87%
rename from app/assets/javascripts/components/histogram.es6.jsx
rename to app/javascript/components/histogram.jsx
index 84c9a7c..e89626c 100644
--- a/app/assets/javascripts/components/histogram.es6.jsx
+++ b/app/javascript/components/histogram.jsx
@@ -1,4 +1,7 @@
-class Histogram extends React.Component {
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default class Histogram extends React.Component {
// Tried to push some of this into a seperate es6 model, but PhantomJS would
// not comply. :(
static formattedColor(color) {
@@ -69,12 +72,12 @@ class Histogram extends React.Component {
}
Histogram.propTypes = {
- histogram: React.PropTypes.arrayOf(
- React.PropTypes.string,
+ histogram: PropTypes.arrayOf(
+ PropTypes.string,
),
- pathName: React.PropTypes.string.isRequired,
- imagePaths: React.PropTypes.arrayOf(
- React.PropTypes.string,
+ pathName: PropTypes.string.isRequired,
+ imagePaths: PropTypes.arrayOf(
+ PropTypes.string,
),
};
diff --git a/app/assets/javascripts/components/iiif_cropper.es6.jsx b/app/javascript/components/iiif_cropper.jsx
similarity index 75%
rename from app/assets/javascripts/components/iiif_cropper.es6.jsx
rename to app/javascript/components/iiif_cropper.jsx
index ca9e00a..08225d6 100644
--- a/app/assets/javascripts/components/iiif_cropper.es6.jsx
+++ b/app/javascript/components/iiif_cropper.jsx
@@ -1,6 +1,9 @@
-/* global L, LeafletIiif, LeafletIiifCropper */
+import React from 'react';
+import PropTypes from 'prop-types';
+import LeafletIiif from './leaflet_iiif';
+import LeafletIiifCropper from './leaflet_iiif_cropper';
-class IiifCropper extends React.Component {
+export default class IiifCropper extends React.Component {
constructor(props) {
super(props);
this.state = {
@@ -20,7 +23,7 @@ class IiifCropper extends React.Component {
}
onLoad(leafletState) {
- this.setState({ ...leafletState });
+ this.setState(leafletState);
}
onRegionChanged(region) {
@@ -50,6 +53,6 @@ class IiifCropper extends React.Component {
}
IiifCropper.propTypes = {
- iiifImage: React.PropTypes.string.isRequired,
- cropperName: React.PropTypes.string.isRequired,
+ iiifImage: PropTypes.string.isRequired,
+ cropperName: PropTypes.string.isRequired,
};
diff --git a/app/assets/javascripts/components/image_match_results.es6.jsx b/app/javascript/components/image_match_results.jsx
similarity index 72%
rename from app/assets/javascripts/components/image_match_results.es6.jsx
rename to app/javascript/components/image_match_results.jsx
index 8ee3b17..e00ee66 100644
--- a/app/assets/javascripts/components/image_match_results.es6.jsx
+++ b/app/javascript/components/image_match_results.jsx
@@ -1,6 +1,9 @@
-/* global L, LeafletIiif, LeafletGeometry */
+import React from 'react';
+import PropTypes from 'prop-types';
+import LeafletIiif from './leaflet_iiif';
+import LeafletGeometry from './leaflet_geometry';
-class ImageMatchResults extends React.Component {
+export default class ImageMatchResults extends React.Component {
constructor(props) {
super(props);
this.state = {
@@ -18,7 +21,7 @@ class ImageMatchResults extends React.Component {
}
onLoad(leafletState) {
- this.setState({ ...leafletState });
+ this.setState(leafletState);
}
render() {
@@ -42,8 +45,8 @@ class ImageMatchResults extends React.Component {
}
ImageMatchResults.propTypes = {
- iiifImage: React.PropTypes.string.isRequired,
- matches: React.PropTypes.arrayOf(
- React.PropTypes.array,
+ iiifImage: PropTypes.string.isRequired,
+ matches: PropTypes.arrayOf(
+ PropTypes.array,
),
};
diff --git a/app/assets/javascripts/components/image_template_container.es6.jsx b/app/javascript/components/image_template_container.jsx
similarity index 85%
rename from app/assets/javascripts/components/image_template_container.es6.jsx
rename to app/javascript/components/image_template_container.jsx
index e8540c9..8fea6ad 100644
--- a/app/assets/javascripts/components/image_template_container.es6.jsx
+++ b/app/javascript/components/image_template_container.jsx
@@ -1,6 +1,11 @@
-/* global ImageTemplateCropper, ImageTemplateList, $ */
+/* global $ */
-class ImageTemplateContainer extends React.Component {
+import React from 'react';
+import PropTypes from 'prop-types';
+import ImageTemplateCropper from './image_template_cropper';
+import ImageTemplateList from './image_template_list';
+
+export default class ImageTemplateContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
@@ -82,11 +87,11 @@ class ImageTemplateContainer extends React.Component {
}
ImageTemplateContainer.propTypes = {
- imageTemplates: React.PropTypes.arrayOf(
- React.PropTypes.object,
+ imageTemplates: PropTypes.arrayOf(
+ PropTypes.object,
),
- iiifImage: React.PropTypes.string,
- templateDestroyRoute: React.PropTypes.string,
+ iiifImage: PropTypes.string,
+ templateDestroyRoute: PropTypes.string,
};
ImageTemplateContainer.defaultProps = {
diff --git a/app/assets/javascripts/components/image_template_cropper.es6.jsx b/app/javascript/components/image_template_cropper.jsx
similarity index 71%
rename from app/assets/javascripts/components/image_template_cropper.es6.jsx
rename to app/javascript/components/image_template_cropper.jsx
index 20deee7..44e9821 100644
--- a/app/assets/javascripts/components/image_template_cropper.es6.jsx
+++ b/app/javascript/components/image_template_cropper.jsx
@@ -1,6 +1,8 @@
-/* global IiifCropper */
+import React from 'react';
+import PropTypes from 'prop-types';
+import IiifCropper from './iiif_cropper';
-class ImageTemplateCropper extends React.Component {
+export default class ImageTemplateCropper extends React.Component {
addTemplate() {
this.props.onAddNewTemplate(this.cropper.state);
}
@@ -27,5 +29,5 @@ class ImageTemplateCropper extends React.Component {
}
ImageTemplateCropper.propTypes = {
- onAddNewTemplate: () => {},
+ onAddNewTemplate: PropTypes.func,
};
diff --git a/app/assets/javascripts/components/image_template_list.es6.jsx b/app/javascript/components/image_template_list.jsx
similarity index 78%
rename from app/assets/javascripts/components/image_template_list.es6.jsx
rename to app/javascript/components/image_template_list.jsx
index 00a048b..da92d2d 100644
--- a/app/assets/javascripts/components/image_template_list.es6.jsx
+++ b/app/javascript/components/image_template_list.jsx
@@ -1,6 +1,8 @@
-/* global ImageTemplateViewer */
+import React from 'react';
+import PropTypes from 'prop-types';
+import ImageTemplateViewer from './image_template_viewer';
-class ImageTemplateList extends React.Component {
+export default class ImageTemplateList extends React.Component {
constructor(props) {
super(props);
@@ -45,11 +47,11 @@ class ImageTemplateList extends React.Component {
}
ImageTemplateList.propTypes = {
- imageTemplates: React.PropTypes.arrayOf(
- React.PropTypes.object,
+ imageTemplates: PropTypes.arrayOf(
+ PropTypes.object,
),
- updateRemovedItems: React.PropTypes.func,
- updateImageTemplates: React.PropTypes.func,
+ updateRemovedItems: PropTypes.func,
+ updateImageTemplates: PropTypes.func,
};
ImageTemplateList.defaultProps = {
diff --git a/app/assets/javascripts/components/image_template_viewer.es6.jsx b/app/javascript/components/image_template_viewer.jsx
similarity index 84%
rename from app/assets/javascripts/components/image_template_viewer.es6.jsx
rename to app/javascript/components/image_template_viewer.jsx
index bfc7cb4..85ff399 100644
--- a/app/assets/javascripts/components/image_template_viewer.es6.jsx
+++ b/app/javascript/components/image_template_viewer.jsx
@@ -1,6 +1,8 @@
-/* global Range */
+import React from 'react';
+import PropTypes from 'prop-types';
+import Range from './range';
-class ImageTemplateViewer extends React.Component {
+export default class ImageTemplateViewer extends React.Component {
constructor(props) {
super(props);
this.state = { value: parseInt(props.match_options.threshold, 10) };
@@ -84,20 +86,20 @@ class ImageTemplateViewer extends React.Component {
}
ImageTemplateViewer.propTypes = {
- image_url: React.PropTypes.string,
- id: React.PropTypes.oneOfType([
- React.PropTypes.string,
- React.PropTypes.number,
+ image_url: PropTypes.string,
+ id: PropTypes.oneOfType([
+ PropTypes.string,
+ PropTypes.number,
]),
- match_options: React.PropTypes.shape({
- threshold: React.PropTypes.oneOfType([
- React.PropTypes.number,
- React.PropTypes.string,
+ match_options: PropTypes.shape({
+ threshold: PropTypes.oneOfType([
+ PropTypes.number,
+ PropTypes.string,
]),
}),
- removeItem: React.PropTypes.func,
- index: React.PropTypes.number,
- updateImageTemplates: React.PropTypes.func,
+ removeItem: PropTypes.func,
+ index: PropTypes.number,
+ updateImageTemplates: PropTypes.func,
};
ImageTemplateViewer.defaultProps = {
diff --git a/app/assets/javascripts/components/leaflet_geometry.es6.jsx b/app/javascript/components/leaflet_geometry.jsx
similarity index 74%
rename from app/assets/javascripts/components/leaflet_geometry.es6.jsx
rename to app/javascript/components/leaflet_geometry.jsx
index b8f4e98..c2e7717 100644
--- a/app/assets/javascripts/components/leaflet_geometry.es6.jsx
+++ b/app/javascript/components/leaflet_geometry.jsx
@@ -1,6 +1,8 @@
-/* global L */
+import L from 'leaflet';
+import React from 'react';
+import PropTypes from 'prop-types';
-class LeafletGeometry extends React.Component {
+export default class LeafletGeometry extends React.Component {
constructor(props) {
super(props);
this.state = {
@@ -27,8 +29,8 @@ class LeafletGeometry extends React.Component {
}
LeafletGeometry.propTypes = {
- matches: React.PropTypes.arrayOf(
- React.PropTypes.array,
+ matches: PropTypes.arrayOf(
+ PropTypes.array,
),
- unprojectZoom: React.PropTypes.number,
+ unprojectZoom: PropTypes.number,
};
diff --git a/app/assets/javascripts/components/leaflet_iiif.es6.jsx b/app/javascript/components/leaflet_iiif.jsx
similarity index 73%
rename from app/assets/javascripts/components/leaflet_iiif.es6.jsx
rename to app/javascript/components/leaflet_iiif.jsx
index 09df110..a00289d 100644
--- a/app/assets/javascripts/components/leaflet_iiif.es6.jsx
+++ b/app/javascript/components/leaflet_iiif.jsx
@@ -1,11 +1,16 @@
-/* global L */
+import L from 'leaflet';
+import React from 'react';
+import PropTypes from 'prop-types';
+import 'leaflet-iiif';
+import '../../../vendor/assets/javascripts/leaflet-areaselect';
+import '../../../vendor/assets/stylesheets/leaflet-areaselect.css';
const mapStyle = {
height: '500px',
width: '100%',
};
-class LeafletIiif extends React.Component {
+export default class LeafletIiif extends React.Component {
constructor(props) {
super(props);
this.state = {
@@ -54,8 +59,8 @@ class LeafletIiif extends React.Component {
}
LeafletIiif.propTypes = {
- iiifImage: React.PropTypes.string.isRequired,
- onLoad: React.PropTypes.func,
+ iiifImage: PropTypes.string.isRequired,
+ onLoad: PropTypes.func,
};
LeafletIiif.defaultProps = {
diff --git a/app/assets/javascripts/components/leaflet_iiif_cropper.es6.jsx b/app/javascript/components/leaflet_iiif_cropper.jsx
similarity index 77%
rename from app/assets/javascripts/components/leaflet_iiif_cropper.es6.jsx
rename to app/javascript/components/leaflet_iiif_cropper.jsx
index bd613f2..b316672 100644
--- a/app/assets/javascripts/components/leaflet_iiif_cropper.es6.jsx
+++ b/app/javascript/components/leaflet_iiif_cropper.jsx
@@ -1,6 +1,8 @@
-/* global L */
+import L from 'leaflet';
+import React from 'react';
+import PropTypes from 'prop-types';
-class LeafletIiifCropper extends React.Component {
+export default class LeafletIiifCropper extends React.Component {
constructor(props) {
super(props);
this.state = {
@@ -61,15 +63,15 @@ class LeafletIiifCropper extends React.Component {
}
LeafletIiifCropper.propTypes = {
- cropperName: React.PropTypes.string.isRequired,
- iiifLayer: React.PropTypes.shape({
- getTileUrl: React.PropTypes.func.isRequired,
+ cropperName: PropTypes.string.isRequired,
+ iiifLayer: PropTypes.shape({
+ getTileUrl: PropTypes.func.isRequired,
}).isRequired,
- map: React.PropTypes.shape({
- getZoom: React.PropTypes.func.isRequired,
+ map: PropTypes.shape({
+ getZoom: PropTypes.func.isRequired,
}).isRequired,
- onRegionChanged: React.PropTypes.func,
- region: React.PropTypes.arrayOf(React.PropTypes.number).isRequired,
+ onRegionChanged: PropTypes.func,
+ region: PropTypes.arrayOf(PropTypes.number).isRequired,
};
LeafletIiifCropper.defaultProps = {
diff --git a/app/assets/javascripts/components/posterize_form.es6.jsx b/app/javascript/components/posterize_form.jsx
similarity index 83%
rename from app/assets/javascripts/components/posterize_form.es6.jsx
rename to app/javascript/components/posterize_form.jsx
index 3a06abd..2be9399 100644
--- a/app/assets/javascripts/components/posterize_form.es6.jsx
+++ b/app/javascript/components/posterize_form.jsx
@@ -1,6 +1,8 @@
-/* global ToggleForm, RadioSet */
+import React from 'react';
+import ToggleForm from './toggle_form';
+import RadioSet from './radio_set';
-class PosterizeForm extends React.Component {
+export default class PosterizeForm extends React.Component {
constructor(props) {
super(props);
this.state = {
diff --git a/app/assets/javascripts/components/radio_set.es6.jsx b/app/javascript/components/radio_set.jsx
similarity index 89%
rename from app/assets/javascripts/components/radio_set.es6.jsx
rename to app/javascript/components/radio_set.jsx
index 50cf65f..0f22f5f 100644
--- a/app/assets/javascripts/components/radio_set.es6.jsx
+++ b/app/javascript/components/radio_set.jsx
@@ -1,4 +1,7 @@
-class RadioSet extends React.Component {
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default class RadioSet extends React.Component {
constructor(props) {
super(props);
@@ -78,10 +81,10 @@ class RadioSet extends React.Component {
}
RadioSet.propTypes = {
- defaultRadio: React.PropTypes.string,
- enabled: React.PropTypes.bool,
- formName: React.PropTypes.string,
- otherRadio: React.PropTypes.string,
+ defaultRadio: PropTypes.string,
+ enabled: PropTypes.bool,
+ formName: PropTypes.string,
+ otherRadio: PropTypes.string,
};
RadioSet.defaultProps = {
diff --git a/app/assets/javascripts/components/range.es6.jsx b/app/javascript/components/range.jsx
similarity index 70%
rename from app/assets/javascripts/components/range.es6.jsx
rename to app/javascript/components/range.jsx
index c2c3450..852b9f8 100644
--- a/app/assets/javascripts/components/range.es6.jsx
+++ b/app/javascript/components/range.jsx
@@ -1,4 +1,7 @@
-class Range extends React.Component {
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default class Range extends React.Component {
constructor(props) {
super(props);
this.state = { value: props.value, enabled: false };
@@ -31,14 +34,14 @@ class Range extends React.Component {
}
Range.propTypes = {
- min: React.PropTypes.number,
- max: React.PropTypes.number,
- value: React.PropTypes.number,
- fieldName: React.PropTypes.string,
- customLabel: React.PropTypes.string,
- enabled: React.PropTypes.bool,
- onUpdate: React.PropTypes.func,
- className: React.PropTypes.string,
+ min: PropTypes.number,
+ max: PropTypes.number,
+ value: PropTypes.number,
+ fieldName: PropTypes.string,
+ customLabel: PropTypes.string,
+ enabled: PropTypes.bool,
+ onUpdate: PropTypes.func,
+ className: PropTypes.string,
};
Range.defaultProps = {
diff --git a/app/assets/javascripts/components/select.es6.jsx b/app/javascript/components/select.jsx
similarity index 65%
rename from app/assets/javascripts/components/select.es6.jsx
rename to app/javascript/components/select.jsx
index 3f6c2a1..040214a 100644
--- a/app/assets/javascripts/components/select.es6.jsx
+++ b/app/javascript/components/select.jsx
@@ -1,4 +1,7 @@
-class Select extends React.Component {
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default class Select extends React.Component {
render() {
if (!this.props) {
return null;
@@ -19,10 +22,10 @@ class Select extends React.Component {
}
Select.propTypes = {
- customLabel: React.PropTypes.string,
- enabled: React.PropTypes.bool,
- fieldName: React.PropTypes.string,
- options: React.PropTypes.arrayOf(React.PropTypes.string),
+ customLabel: PropTypes.string,
+ enabled: PropTypes.bool,
+ fieldName: PropTypes.string,
+ options: PropTypes.arrayOf(PropTypes.string),
};
Select.defaultProps = {
diff --git a/app/assets/javascripts/components/toggle_form.es6.jsx b/app/javascript/components/toggle_form.jsx
similarity index 85%
rename from app/assets/javascripts/components/toggle_form.es6.jsx
rename to app/javascript/components/toggle_form.jsx
index ddd9563..b5e95fb 100644
--- a/app/assets/javascripts/components/toggle_form.es6.jsx
+++ b/app/javascript/components/toggle_form.jsx
@@ -1,6 +1,11 @@
-/* globals $, Range, Select */
+/* globals $ */
+import 'bootstrap';
+import React from 'react';
+import PropTypes from 'prop-types';
+import Range from './range';
+import Select from './select';
-class ToggleForm extends React.Component {
+export default class ToggleForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: props.value, enabled: false };
@@ -107,13 +112,13 @@ class ToggleForm extends React.Component {
}
ToggleForm.propTypes = {
- object: React.PropTypes.string.isRequired,
- attribute: React.PropTypes.string.isRequired,
- type: React.PropTypes.string.isRequired,
- value: React.PropTypes.number,
- handleEnableChange: React.PropTypes.func,
- helpText: React.PropTypes.string,
- formType: React.PropTypes.oneOf(['Range', 'Select']),
+ object: PropTypes.string.isRequired,
+ attribute: PropTypes.string.isRequired,
+ type: PropTypes.string.isRequired,
+ value: PropTypes.number,
+ handleEnableChange: PropTypes.func,
+ helpText: PropTypes.string,
+ formType: PropTypes.oneOf(['Range', 'Select']),
};
ToggleForm.defaultProps = {
diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js
new file mode 100644
index 0000000..c66678a
--- /dev/null
+++ b/app/javascript/packs/application.js
@@ -0,0 +1 @@
+import '../app-styles.sass';
diff --git a/app/javascript/packs/create_image_paths.jsx b/app/javascript/packs/create_image_paths.jsx
new file mode 100644
index 0000000..1e35dfa
--- /dev/null
+++ b/app/javascript/packs/create_image_paths.jsx
@@ -0,0 +1,18 @@
+import ReactDOM from 'react-dom';
+import LeafletIiif from '../components/leaflet_iiif';
+import Histogram from '../components/histogram';
+
+document.addEventListener('DOMContentLoaded', () => {
+ const node = document.getElementById('image-path-image');
+ const data = JSON.parse(node.getAttribute('data'));
+ ReactDOM.render(, node);
+
+ const histograms = document.getElementsByClassName('histogram');
+
+ for (let i = 1; i <= histograms.length; i += 1) {
+ const nodeId = `image-path-histogram-${String(i)}`;
+ const histogramNode = document.getElementById(nodeId);
+ const dataHistogram = JSON.parse(histogramNode.getAttribute('data'));
+ ReactDOM.render(, histogramNode);
+ }
+});
diff --git a/app/javascript/packs/create_image_templates.jsx b/app/javascript/packs/create_image_templates.jsx
new file mode 100644
index 0000000..2fe2939
--- /dev/null
+++ b/app/javascript/packs/create_image_templates.jsx
@@ -0,0 +1,9 @@
+import ReactDOM from 'react-dom';
+import ImageTemplateContainer from '../components/image_template_container';
+
+document.addEventListener('DOMContentLoaded', () => {
+ const node = document.getElementById('image-template-container');
+ const data = JSON.parse(node.getAttribute('data'));
+
+ ReactDOM.render(, node);
+});
diff --git a/app/javascript/packs/crop_image.jsx b/app/javascript/packs/crop_image.jsx
new file mode 100644
index 0000000..3bf01b9
--- /dev/null
+++ b/app/javascript/packs/crop_image.jsx
@@ -0,0 +1,9 @@
+import ReactDOM from 'react-dom';
+import IiifCropper from '../components/iiif_cropper';
+
+document.addEventListener('DOMContentLoaded', () => {
+ const node = document.getElementById('iiif-cropper');
+ const data = JSON.parse(node.getAttribute('data'));
+
+ ReactDOM.render(, node);
+});
diff --git a/app/javascript/packs/image_clean.jsx b/app/javascript/packs/image_clean.jsx
new file mode 100644
index 0000000..336d626
--- /dev/null
+++ b/app/javascript/packs/image_clean.jsx
@@ -0,0 +1,29 @@
+import ReactDOM from 'react-dom';
+import ToggleForm from '../components/toggle_form';
+import PosterizeForm from '../components/posterize_form';
+
+document.addEventListener('DOMContentLoaded', () => {
+ const denoiseNode = document.getElementById('image-clean-denoise');
+ const denoiseData = JSON.parse(denoiseNode.getAttribute('data'));
+ ReactDOM.render(, denoiseNode);
+
+ const equalizeNode = document.getElementById('image-clean-equalize');
+ const equalizeData = JSON.parse(equalizeNode.getAttribute('data'));
+ ReactDOM.render(, equalizeNode);
+
+ const brightnessNode = document.getElementById('image-clean-brightness');
+ const brightnessData = JSON.parse(brightnessNode.getAttribute('data'));
+ ReactDOM.render(, brightnessNode);
+
+ const contrastNode = document.getElementById('image-clean-contrast');
+ const contrastData = JSON.parse(contrastNode.getAttribute('data'));
+ ReactDOM.render(, contrastNode);
+
+ const smoothNode = document.getElementById('image-clean-smooth');
+ const smoothData = JSON.parse(smoothNode.getAttribute('data'));
+ ReactDOM.render(, smoothNode);
+
+ const posterizeNode = document.getElementById('image-clean-posterize');
+ const posterizeData = JSON.parse(posterizeNode.getAttribute('data'));
+ ReactDOM.render(, posterizeNode);
+});
diff --git a/app/javascript/packs/post_process_image_paths.jsx b/app/javascript/packs/post_process_image_paths.jsx
new file mode 100644
index 0000000..9fa843c
--- /dev/null
+++ b/app/javascript/packs/post_process_image_paths.jsx
@@ -0,0 +1,9 @@
+import ReactDOM from 'react-dom';
+import LeafletIiif from '../components/leaflet_iiif';
+
+document.addEventListener('DOMContentLoaded', () => {
+ const node = document.getElementById('post-processed-image-paths');
+ const data = JSON.parse(node.getAttribute('data'));
+
+ ReactDOM.render(, node);
+});
diff --git a/app/javascript/packs/review_template_match_results.jsx b/app/javascript/packs/review_template_match_results.jsx
new file mode 100644
index 0000000..cdd1590
--- /dev/null
+++ b/app/javascript/packs/review_template_match_results.jsx
@@ -0,0 +1,9 @@
+import ReactDOM from 'react-dom';
+import ImageMatchResults from '../components/image_match_results';
+
+document.addEventListener('DOMContentLoaded', () => {
+ const node = document.getElementById('image-match-results');
+ const data = JSON.parse(node.getAttribute('data'));
+
+ ReactDOM.render(, node);
+});
diff --git a/app/views/collection_templates/build/create_image_paths.html.erb b/app/views/collection_templates/build/create_image_paths.html.erb
index c359625..c451083 100644
--- a/app/views/collection_templates/build/create_image_paths.html.erb
+++ b/app/views/collection_templates/build/create_image_paths.html.erb
@@ -12,22 +12,30 @@
- <%= react_component('LeafletIiif', {
- iiifImage: Riiif::Engine.routes.url_helpers.info_path(
- @collection_template.cleaned_image
- )
- }) %>
+ <%= content_tag :div,
+ id: "image-path-image",
+ data: {
+ iiifImage: Riiif::Engine.routes.url_helpers.info_path(
+ @collection_template.cleaned_image
+ )
+ }.to_json do %>
+ <% end %>
<%= t 'create_image_paths.instruction' %>
+ <% counter = 1 %>
<% @collection_template.parsed_histogram.each do |histogram| %>
- <%= react_component('Histogram', {
- histogram: histogram,
- pathName: 'collection_template[image_paths][]',
- imagePaths: @collection_template.image_paths
- })
- %>
+ <%= content_tag :div,
+ id: "image-path-histogram-" + counter.to_s,
+ class: "histogram",
+ data: {
+ histogram: histogram,
+ pathName: 'collection_template[image_paths][]',
+ imagePaths: @collection_template.image_paths
+ }.to_json do %>
+ <% end %>
+ <% counter = counter + 1 %>
<% end %>
@@ -35,3 +43,4 @@
<%= f.submit t('navigation.next_step'), class: 'btn btn-primary' %>
<% end %>
+<%= javascript_pack_tag 'create_image_paths' %>
diff --git a/app/views/collection_templates/build/create_image_templates.html.erb b/app/views/collection_templates/build/create_image_templates.html.erb
index 34f9efc..52c4bab 100644
--- a/app/views/collection_templates/build/create_image_templates.html.erb
+++ b/app/views/collection_templates/build/create_image_templates.html.erb
@@ -7,14 +7,19 @@
<% # Add in a hidden field just so that the BuildController stays happy %>
<%= f.hidden_field :id, value: @collection_template.id %>
- <%= react_component('ImageTemplateContainer', {
+ <%= content_tag :div,
+ id: "image-template-container",
+ data: {
iiifImage: Riiif::Engine.routes.url_helpers.info_path(
@collection_template.cleaned_image
),
imageTemplates: @collection_template.image_templates,
cropperName: 'collection_template[crop_bounds]',
templateDestroyRoute: collection_template_image_template_path.gsub('create_image_templates', '')
- }) %>
+ }.to_json do %>
+ <% end %>
<%= f.submit t('navigation.next_step'), class: 'btn btn-primary' %>
<% end %>
+<%= javascript_pack_tag 'create_image_templates' %>
+<%= stylesheet_pack_tag 'create_image_templates' %>
diff --git a/app/views/collection_templates/build/crop_image.html.erb b/app/views/collection_templates/build/crop_image.html.erb
index 7466ac1..2762430 100644
--- a/app/views/collection_templates/build/crop_image.html.erb
+++ b/app/views/collection_templates/build/crop_image.html.erb
@@ -10,12 +10,17 @@
<% # Add in a hidden field just so that the BuildController stays happy %>
<%= f.hidden_field :id, value: @collection_template.id %>
- <%= react_component('IiifCropper', {
+ <%= content_tag :div,
+ id: "iiif-cropper",
+ data: {
iiifImage: Riiif::Engine.routes.url_helpers.info_path(
@collection_template.image.file_name_no_extension
),
cropperName: 'collection_template[crop_bounds]'
- }) %>
+ }.to_json do %>
+ <% end %>
<%= f.submit t('navigation.next_step'), class: 'btn btn-primary' %>
<% end %>
+<%= javascript_pack_tag 'crop_image' %>
+<%= stylesheet_pack_tag 'crop_image' %>
diff --git a/app/views/collection_templates/build/image_clean.html.erb b/app/views/collection_templates/build/image_clean.html.erb
index 5637d4c..c864754 100644
--- a/app/views/collection_templates/build/image_clean.html.erb
+++ b/app/views/collection_templates/build/image_clean.html.erb
@@ -12,25 +12,44 @@
<% end %>
<% # Add in a hidden field just so that the BuildController stays happy %>
<%= f.hidden_field :id, value: @collection_template.id %>
- <%= react_component('ToggleForm', {
- object: f.object_name, attribute: 'image_clean', type: 'denoise', helpText: t('image_clean.denoise.help')
- }) %>
- <%= react_component('ToggleForm', {
- object: f.object_name, attribute: 'image_clean', type: 'equalize', helpText: t('image_clean.equalize.help')
- }) %>
- <%= react_component('ToggleForm', {
- value: 100, max: 200, object: f.object_name, attribute: 'image_clean', type: 'brightness', helpText: t('image_clean.brightness.help')
- }) %>
- <%= react_component('ToggleForm', {
- value: 100, max: 200, object: f.object_name, attribute: 'image_clean', type: 'contrast', helpText: t('image_clean.brightness.help')
- }) %>
- <%= react_component('ToggleForm', {
- object: f.object_name, attribute: 'image_clean', type: 'smooth', helpText: t('image_clean.brightness.help')
- }) %>
- <%= react_component('PosterizeForm', {
- object: f.object_name, attribute: 'image_clean', type: 'posterize', helpText: t('image_clean.posterize.help')
- }) %>
+ <%= content_tag :div,
+ id: "image-clean-denoise",
+ data: {
+ object: f.object_name, attribute: 'image_clean', type: 'denoise', helpText: t('image_clean.denoise.help')
+ }.to_json do %>
+ <% end %>
+ <%= content_tag :div,
+ id: "image-clean-equalize",
+ data: {
+ object: f.object_name, attribute: 'image_clean', type: 'equalize', helpText: t('image_clean.equalize.help')
+ }.to_json do %>
+ <% end %>
+ <%= content_tag :div,
+ id: "image-clean-brightness",
+ data: {
+ value: 100, max: 200, object: f.object_name, attribute: 'image_clean', type: 'brightness', helpText: t('image_clean.brightness.help')
+ }.to_json do %>
+ <% end %>
+ <%= content_tag :div,
+ id: "image-clean-contrast",
+ data: {
+ value: 100, max: 200, object: f.object_name, attribute: 'image_clean', type: 'contrast', helpText: t('image_clean.brightness.help')
+ }.to_json do %>
+ <% end %>
+ <%= content_tag :div,
+ id: "image-clean-smooth",
+ data: {
+ object: f.object_name, attribute: 'image_clean', type: 'smooth', helpText: t('image_clean.brightness.help')
+ }.to_json do %>
+ <% end %>
+ <%= content_tag :div,
+ id: "image-clean-posterize",
+ data: {
+ object: f.object_name, attribute: 'image_clean', type: 'posterize', helpText: t('image_clean.posterize.help')
+ }.to_json do %>
+ <% end %>
<%= f.submit 'Next Step', class: 'btn btn-primary' %>
<% end %>
<%= render 'collection_templates/cropped_image' %>
+<%= javascript_pack_tag 'image_clean' %>
diff --git a/app/views/collection_templates/build/post_process_image_paths.html.erb b/app/views/collection_templates/build/post_process_image_paths.html.erb
index 5648c48..4bded57 100644
--- a/app/views/collection_templates/build/post_process_image_paths.html.erb
+++ b/app/views/collection_templates/build/post_process_image_paths.html.erb
@@ -12,11 +12,14 @@
<%= f.hidden_field :id, value: @collection_template.id %>
- <%= react_component('LeafletIiif', {
- iiifImage: Riiif::Engine.routes.url_helpers.info_path(
- @collection_template.pathselected_image
- )
- }) %>
+ <%= content_tag :div,
+ id: "post-processed-image-paths",
+ data: {
+ iiifImage: Riiif::Engine.routes.url_helpers.info_path(
+ @collection_template.pathselected_image
+ )
+ }.to_json do %>
+ <% end %>
@@ -24,3 +27,4 @@
<%= f.submit t('navigation.next_step'), class: 'btn btn-primary' %>
<% end %>
+<%= javascript_pack_tag 'post_process_image_paths' %>
diff --git a/app/views/collection_templates/build/review_template_match_results.html.erb b/app/views/collection_templates/build/review_template_match_results.html.erb
index 89bf2a5..8d7e245 100644
--- a/app/views/collection_templates/build/review_template_match_results.html.erb
+++ b/app/views/collection_templates/build/review_template_match_results.html.erb
@@ -13,12 +13,15 @@
@@ -37,3 +40,4 @@
<%= image_tag 'iiif-drag-icon', width: 16 %>
<% end %>
<% end %>
+<%= javascript_pack_tag 'review_template_match_results' %>
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 2b0bc5b..242d890 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -10,6 +10,8 @@
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
+ <%= javascript_pack_tag 'application' %>
+ <%= stylesheet_pack_tag 'application' %>
diff --git a/bin/__pycache__/createfontdatachunk.cpython-35.pyc b/bin/__pycache__/createfontdatachunk.cpython-35.pyc
new file mode 100755
index 0000000..d6d6407
Binary files /dev/null and b/bin/__pycache__/createfontdatachunk.cpython-35.pyc differ
diff --git a/bin/__pycache__/enhancer.cpython-35.pyc b/bin/__pycache__/enhancer.cpython-35.pyc
new file mode 100755
index 0000000..e606f24
Binary files /dev/null and b/bin/__pycache__/enhancer.cpython-35.pyc differ
diff --git a/bin/__pycache__/explode.cpython-35.pyc b/bin/__pycache__/explode.cpython-35.pyc
new file mode 100755
index 0000000..9abbd7c
Binary files /dev/null and b/bin/__pycache__/explode.cpython-35.pyc differ
diff --git a/bin/__pycache__/gifmaker.cpython-35.pyc b/bin/__pycache__/gifmaker.cpython-35.pyc
new file mode 100755
index 0000000..43f9a07
Binary files /dev/null and b/bin/__pycache__/gifmaker.cpython-35.pyc differ
diff --git a/bin/__pycache__/painter.cpython-35.pyc b/bin/__pycache__/painter.cpython-35.pyc
new file mode 100755
index 0000000..759252e
Binary files /dev/null and b/bin/__pycache__/painter.cpython-35.pyc differ
diff --git a/bin/__pycache__/pilconvert.cpython-35.pyc b/bin/__pycache__/pilconvert.cpython-35.pyc
new file mode 100755
index 0000000..56e0fef
Binary files /dev/null and b/bin/__pycache__/pilconvert.cpython-35.pyc differ
diff --git a/bin/__pycache__/pildriver.cpython-35.pyc b/bin/__pycache__/pildriver.cpython-35.pyc
new file mode 100755
index 0000000..3532897
Binary files /dev/null and b/bin/__pycache__/pildriver.cpython-35.pyc differ
diff --git a/bin/__pycache__/pilfile.cpython-35.pyc b/bin/__pycache__/pilfile.cpython-35.pyc
new file mode 100755
index 0000000..c6bb22b
Binary files /dev/null and b/bin/__pycache__/pilfile.cpython-35.pyc differ
diff --git a/bin/__pycache__/pilfont.cpython-35.pyc b/bin/__pycache__/pilfont.cpython-35.pyc
new file mode 100755
index 0000000..718cbe3
Binary files /dev/null and b/bin/__pycache__/pilfont.cpython-35.pyc differ
diff --git a/bin/__pycache__/pilprint.cpython-35.pyc b/bin/__pycache__/pilprint.cpython-35.pyc
new file mode 100755
index 0000000..45d3f2b
Binary files /dev/null and b/bin/__pycache__/pilprint.cpython-35.pyc differ
diff --git a/bin/__pycache__/player.cpython-35.pyc b/bin/__pycache__/player.cpython-35.pyc
new file mode 100755
index 0000000..f230226
Binary files /dev/null and b/bin/__pycache__/player.cpython-35.pyc differ
diff --git a/bin/__pycache__/rst2html.cpython-35.pyc b/bin/__pycache__/rst2html.cpython-35.pyc
new file mode 100755
index 0000000..27f4233
Binary files /dev/null and b/bin/__pycache__/rst2html.cpython-35.pyc differ
diff --git a/bin/__pycache__/rst2latex.cpython-35.pyc b/bin/__pycache__/rst2latex.cpython-35.pyc
new file mode 100755
index 0000000..e3b68cd
Binary files /dev/null and b/bin/__pycache__/rst2latex.cpython-35.pyc differ
diff --git a/bin/__pycache__/rst2man.cpython-35.pyc b/bin/__pycache__/rst2man.cpython-35.pyc
new file mode 100755
index 0000000..e3dc23c
Binary files /dev/null and b/bin/__pycache__/rst2man.cpython-35.pyc differ
diff --git a/bin/__pycache__/rst2odt.cpython-35.pyc b/bin/__pycache__/rst2odt.cpython-35.pyc
new file mode 100755
index 0000000..a3db99e
Binary files /dev/null and b/bin/__pycache__/rst2odt.cpython-35.pyc differ
diff --git a/bin/__pycache__/rst2odt_prepstyles.cpython-35.pyc b/bin/__pycache__/rst2odt_prepstyles.cpython-35.pyc
new file mode 100755
index 0000000..9e66653
Binary files /dev/null and b/bin/__pycache__/rst2odt_prepstyles.cpython-35.pyc differ
diff --git a/bin/__pycache__/rst2pseudoxml.cpython-35.pyc b/bin/__pycache__/rst2pseudoxml.cpython-35.pyc
new file mode 100755
index 0000000..32f9b56
Binary files /dev/null and b/bin/__pycache__/rst2pseudoxml.cpython-35.pyc differ
diff --git a/bin/__pycache__/rst2s5.cpython-35.pyc b/bin/__pycache__/rst2s5.cpython-35.pyc
new file mode 100755
index 0000000..408791a
Binary files /dev/null and b/bin/__pycache__/rst2s5.cpython-35.pyc differ
diff --git a/bin/__pycache__/rst2xetex.cpython-35.pyc b/bin/__pycache__/rst2xetex.cpython-35.pyc
new file mode 100755
index 0000000..55f04a3
Binary files /dev/null and b/bin/__pycache__/rst2xetex.cpython-35.pyc differ
diff --git a/bin/__pycache__/rst2xml.cpython-35.pyc b/bin/__pycache__/rst2xml.cpython-35.pyc
new file mode 100755
index 0000000..60f3c4a
Binary files /dev/null and b/bin/__pycache__/rst2xml.cpython-35.pyc differ
diff --git a/bin/__pycache__/rstpep2html.cpython-35.pyc b/bin/__pycache__/rstpep2html.cpython-35.pyc
new file mode 100755
index 0000000..68f66c5
Binary files /dev/null and b/bin/__pycache__/rstpep2html.cpython-35.pyc differ
diff --git a/bin/__pycache__/thresholder.cpython-35.pyc b/bin/__pycache__/thresholder.cpython-35.pyc
new file mode 100755
index 0000000..2bfb07a
Binary files /dev/null and b/bin/__pycache__/thresholder.cpython-35.pyc differ
diff --git a/bin/__pycache__/viewer.cpython-35.pyc b/bin/__pycache__/viewer.cpython-35.pyc
new file mode 100755
index 0000000..0657c79
Binary files /dev/null and b/bin/__pycache__/viewer.cpython-35.pyc differ
diff --git a/bin/activate b/bin/activate
new file mode 100755
index 0000000..ffb6549
--- /dev/null
+++ b/bin/activate
@@ -0,0 +1,76 @@
+# This file must be used with "source bin/activate" *from bash*
+# you cannot run it directly
+
+deactivate () {
+ # reset old environment variables
+ if [ -n "$_OLD_VIRTUAL_PATH" ] ; then
+ PATH="$_OLD_VIRTUAL_PATH"
+ export PATH
+ unset _OLD_VIRTUAL_PATH
+ fi
+ if [ -n "$_OLD_VIRTUAL_PYTHONHOME" ] ; then
+ PYTHONHOME="$_OLD_VIRTUAL_PYTHONHOME"
+ export PYTHONHOME
+ unset _OLD_VIRTUAL_PYTHONHOME
+ fi
+
+ # This should detect bash and zsh, which have a hash command that must
+ # be called to get it to forget past commands. Without forgetting
+ # past commands the $PATH changes we made may not be respected
+ if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then
+ hash -r
+ fi
+
+ if [ -n "$_OLD_VIRTUAL_PS1" ] ; then
+ PS1="$_OLD_VIRTUAL_PS1"
+ export PS1
+ unset _OLD_VIRTUAL_PS1
+ fi
+
+ unset VIRTUAL_ENV
+ if [ ! "$1" = "nondestructive" ] ; then
+ # Self destruct!
+ unset -f deactivate
+ fi
+}
+
+# unset irrelavent variables
+deactivate nondestructive
+
+VIRTUAL_ENV="/Users/csb5t/projects/histonets"
+export VIRTUAL_ENV
+
+_OLD_VIRTUAL_PATH="$PATH"
+PATH="$VIRTUAL_ENV/bin:$PATH"
+export PATH
+
+# unset PYTHONHOME if set
+# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
+# could use `if (set -u; : $PYTHONHOME) ;` in bash
+if [ -n "$PYTHONHOME" ] ; then
+ _OLD_VIRTUAL_PYTHONHOME="$PYTHONHOME"
+ unset PYTHONHOME
+fi
+
+if [ -z "$VIRTUAL_ENV_DISABLE_PROMPT" ] ; then
+ _OLD_VIRTUAL_PS1="$PS1"
+ if [ "x(histonets) " != x ] ; then
+ PS1="(histonets) $PS1"
+ else
+ if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then
+ # special case for Aspen magic directories
+ # see http://www.zetadev.com/software/aspen/
+ PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1"
+ else
+ PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1"
+ fi
+ fi
+ export PS1
+fi
+
+# This should detect bash and zsh, which have a hash command that must
+# be called to get it to forget past commands. Without forgetting
+# past commands the $PATH changes we made may not be respected
+if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then
+ hash -r
+fi
diff --git a/bin/activate.csh b/bin/activate.csh
new file mode 100755
index 0000000..4f50951
--- /dev/null
+++ b/bin/activate.csh
@@ -0,0 +1,37 @@
+# This file must be used with "source bin/activate.csh" *from csh*.
+# You cannot run it directly.
+# Created by Davide Di Blasi
.
+# Ported to Python 3.3 venv by Andrew Svetlov
+
+alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate'
+
+# Unset irrelavent variables.
+deactivate nondestructive
+
+setenv VIRTUAL_ENV "/Users/csb5t/projects/histonets"
+
+set _OLD_VIRTUAL_PATH="$PATH"
+setenv PATH "$VIRTUAL_ENV/bin:$PATH"
+
+
+set _OLD_VIRTUAL_PROMPT="$prompt"
+
+if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
+ if ("histonets" != "") then
+ set env_name = "histonets"
+ else
+ if (`basename "VIRTUAL_ENV"` == "__") then
+ # special case for Aspen magic directories
+ # see http://www.zetadev.com/software/aspen/
+ set env_name = `basename \`dirname "$VIRTUAL_ENV"\``
+ else
+ set env_name = `basename "$VIRTUAL_ENV"`
+ endif
+ endif
+ set prompt = "[$env_name] $prompt"
+ unset env_name
+endif
+
+alias pydoc python -m pydoc
+
+rehash
diff --git a/bin/activate.fish b/bin/activate.fish
new file mode 100755
index 0000000..889d994
--- /dev/null
+++ b/bin/activate.fish
@@ -0,0 +1,74 @@
+# This file must be used with ". bin/activate.fish" *from fish* (http://fishshell.org)
+# you cannot run it directly
+
+function deactivate -d "Exit virtualenv and return to normal shell environment"
+ # reset old environment variables
+ if test -n "$_OLD_VIRTUAL_PATH"
+ set -gx PATH $_OLD_VIRTUAL_PATH
+ set -e _OLD_VIRTUAL_PATH
+ end
+ if test -n "$_OLD_VIRTUAL_PYTHONHOME"
+ set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
+ set -e _OLD_VIRTUAL_PYTHONHOME
+ end
+
+ if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
+ functions -e fish_prompt
+ set -e _OLD_FISH_PROMPT_OVERRIDE
+ . ( begin
+ printf "function fish_prompt\n\t#"
+ functions _old_fish_prompt
+ end | psub )
+ functions -e _old_fish_prompt
+ end
+
+ set -e VIRTUAL_ENV
+ if test "$argv[1]" != "nondestructive"
+ # Self destruct!
+ functions -e deactivate
+ end
+end
+
+# unset irrelavent variables
+deactivate nondestructive
+
+set -gx VIRTUAL_ENV "/Users/csb5t/projects/histonets"
+
+set -gx _OLD_VIRTUAL_PATH $PATH
+set -gx PATH "$VIRTUAL_ENV/bin" $PATH
+
+# unset PYTHONHOME if set
+if set -q PYTHONHOME
+ set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
+ set -e PYTHONHOME
+end
+
+if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
+ # fish uses a function instead of an env var to generate the prompt.
+
+ # save the current fish_prompt function as the function _old_fish_prompt
+ . ( begin
+ printf "function _old_fish_prompt\n\t#"
+ functions fish_prompt
+ end | psub )
+
+ # with the original prompt function renamed, we can override with our own.
+ function fish_prompt
+ # Prompt override?
+ if test -n "(histonets) "
+ printf "%s%s%s" "(histonets) " (set_color normal) (_old_fish_prompt)
+ return
+ end
+ # ...Otherwise, prepend env
+ set -l _checkbase (basename "$VIRTUAL_ENV")
+ if test $_checkbase = "__"
+ # special case for Aspen magic directories
+ # see http://www.zetadev.com/software/aspen/
+ printf "%s[%s]%s %s" (set_color -b blue white) (basename (dirname "$VIRTUAL_ENV")) (set_color normal) (_old_fish_prompt)
+ else
+ printf "%s(%s)%s%s" (set_color -b blue white) (basename "$VIRTUAL_ENV") (set_color normal) (_old_fish_prompt)
+ end
+ end
+
+ set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
+end
diff --git a/bin/bumpversion b/bin/bumpversion
new file mode 100755
index 0000000..8986104
--- /dev/null
+++ b/bin/bumpversion
@@ -0,0 +1,11 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+
+# -*- coding: utf-8 -*-
+import re
+import sys
+
+from bumpversion import main
+
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/bin/codecov b/bin/codecov
new file mode 100755
index 0000000..734a574
--- /dev/null
+++ b/bin/codecov
@@ -0,0 +1,11 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+
+# -*- coding: utf-8 -*-
+import re
+import sys
+
+from codecov import main
+
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/bin/coverage b/bin/coverage
new file mode 100755
index 0000000..912c648
--- /dev/null
+++ b/bin/coverage
@@ -0,0 +1,10 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+# EASY-INSTALL-ENTRY-SCRIPT: 'coverage==4.1','console_scripts','coverage'
+__requires__ = 'coverage==4.1'
+import sys
+from pkg_resources import load_entry_point
+
+if __name__ == '__main__':
+ sys.exit(
+ load_entry_point('coverage==4.1', 'console_scripts', 'coverage')()
+ )
diff --git a/bin/coverage-3.5 b/bin/coverage-3.5
new file mode 100755
index 0000000..c3e5a9c
--- /dev/null
+++ b/bin/coverage-3.5
@@ -0,0 +1,10 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+# EASY-INSTALL-ENTRY-SCRIPT: 'coverage==4.1','console_scripts','coverage-3.5'
+__requires__ = 'coverage==4.1'
+import sys
+from pkg_resources import load_entry_point
+
+if __name__ == '__main__':
+ sys.exit(
+ load_entry_point('coverage==4.1', 'console_scripts', 'coverage-3.5')()
+ )
diff --git a/bin/coverage3 b/bin/coverage3
new file mode 100755
index 0000000..fc3dde4
--- /dev/null
+++ b/bin/coverage3
@@ -0,0 +1,10 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+# EASY-INSTALL-ENTRY-SCRIPT: 'coverage==4.1','console_scripts','coverage3'
+__requires__ = 'coverage==4.1'
+import sys
+from pkg_resources import load_entry_point
+
+if __name__ == '__main__':
+ sys.exit(
+ load_entry_point('coverage==4.1', 'console_scripts', 'coverage3')()
+ )
diff --git a/bin/createfontdatachunk.py b/bin/createfontdatachunk.py
new file mode 100755
index 0000000..c0889db
--- /dev/null
+++ b/bin/createfontdatachunk.py
@@ -0,0 +1,16 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+from __future__ import print_function
+import base64
+import os
+import sys
+
+if __name__ == "__main__":
+ # create font data chunk for embedding
+ font = "Tests/images/courB08"
+ print(" f._load_pilfont_data(")
+ print(" # %s" % os.path.basename(font))
+ print(" BytesIO(base64.decodestring(b'''")
+ base64.encode(open(font + ".pil", "rb"), sys.stdout)
+ print("''')), Image.open(BytesIO(base64.decodestring(b'''")
+ base64.encode(open(font + ".pbm", "rb"), sys.stdout)
+ print("'''))))")
diff --git a/bin/easy_install b/bin/easy_install
new file mode 100755
index 0000000..e60836a
--- /dev/null
+++ b/bin/easy_install
@@ -0,0 +1,11 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+
+# -*- coding: utf-8 -*-
+import re
+import sys
+
+from setuptools.command.easy_install import main
+
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/bin/easy_install-3.5 b/bin/easy_install-3.5
new file mode 100755
index 0000000..e60836a
--- /dev/null
+++ b/bin/easy_install-3.5
@@ -0,0 +1,11 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+
+# -*- coding: utf-8 -*-
+import re
+import sys
+
+from setuptools.command.easy_install import main
+
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/bin/enhancer.py b/bin/enhancer.py
new file mode 100755
index 0000000..ff573f2
--- /dev/null
+++ b/bin/enhancer.py
@@ -0,0 +1,63 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+#
+# The Python Imaging Library
+# $Id$
+#
+# this demo script creates four windows containing an image and a slider.
+# drag the slider to modify the image.
+#
+
+try:
+ from tkinter import Tk, Toplevel, Frame, Label, Scale, HORIZONTAL
+except ImportError:
+ from Tkinter import Tk, Toplevel, Frame, Label, Scale, HORIZONTAL
+
+from PIL import Image, ImageTk, ImageEnhance
+import sys
+
+#
+# enhancer widget
+
+
+class Enhance(Frame):
+ def __init__(self, master, image, name, enhancer, lo, hi):
+ Frame.__init__(self, master)
+
+ # set up the image
+ self.tkim = ImageTk.PhotoImage(image.mode, image.size)
+ self.enhancer = enhancer(image)
+ self.update("1.0") # normalize
+
+ # image window
+ Label(self, image=self.tkim).pack()
+
+ # scale
+ s = Scale(self, label=name, orient=HORIZONTAL,
+ from_=lo, to=hi, resolution=0.01,
+ command=self.update)
+ s.set(self.value)
+ s.pack()
+
+ def update(self, value):
+ self.value = float(value)
+ self.tkim.paste(self.enhancer.enhance(self.value))
+
+#
+# main
+
+if len(sys.argv) != 2:
+ print("Usage: enhancer file")
+ sys.exit(1)
+
+root = Tk()
+
+im = Image.open(sys.argv[1])
+
+im.thumbnail((200, 200))
+
+Enhance(root, im, "Color", ImageEnhance.Color, 0.0, 4.0).pack()
+Enhance(Toplevel(), im, "Sharpness", ImageEnhance.Sharpness, -2.0, 2.0).pack()
+Enhance(Toplevel(), im, "Brightness", ImageEnhance.Brightness, -1.0, 3.0).pack()
+Enhance(Toplevel(), im, "Contrast", ImageEnhance.Contrast, -1.0, 3.0).pack()
+
+root.mainloop()
diff --git a/bin/explode.py b/bin/explode.py
new file mode 100755
index 0000000..d04d341
--- /dev/null
+++ b/bin/explode.py
@@ -0,0 +1,112 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+#
+# The Python Imaging Library
+# $Id$
+#
+# split an animation into a number of frame files
+#
+
+from __future__ import print_function
+
+from PIL import Image
+import os
+import sys
+
+
+class Interval(object):
+
+ def __init__(self, interval="0"):
+
+ self.setinterval(interval)
+
+ def setinterval(self, interval):
+
+ self.hilo = []
+
+ for s in interval.split(","):
+ if not s.strip():
+ continue
+ try:
+ v = int(s)
+ if v < 0:
+ lo, hi = 0, -v
+ else:
+ lo = hi = v
+ except ValueError:
+ i = s.find("-")
+ lo, hi = int(s[:i]), int(s[i+1:])
+
+ self.hilo.append((hi, lo))
+
+ if not self.hilo:
+ self.hilo = [(sys.maxsize, 0)]
+
+ def __getitem__(self, index):
+
+ for hi, lo in self.hilo:
+ if hi >= index >= lo:
+ return 1
+ return 0
+
+# --------------------------------------------------------------------
+# main program
+
+html = 0
+
+if sys.argv[1:2] == ["-h"]:
+ html = 1
+ del sys.argv[1]
+
+if not sys.argv[2:]:
+ print()
+ print("Syntax: python explode.py infile template [range]")
+ print()
+ print("The template argument is used to construct the names of the")
+ print("individual frame files. The frames are numbered file001.ext,")
+ print("file002.ext, etc. You can insert %d to control the placement")
+ print("and syntax of the frame number.")
+ print()
+ print("The optional range argument specifies which frames to extract.")
+ print("You can give one or more ranges like 1-10, 5, -15 etc. If")
+ print("omitted, all frames are extracted.")
+ sys.exit(1)
+
+infile = sys.argv[1]
+outfile = sys.argv[2]
+
+frames = Interval(",".join(sys.argv[3:]))
+
+try:
+ # check if outfile contains a placeholder
+ outfile % 1
+except TypeError:
+ file, ext = os.path.splitext(outfile)
+ outfile = file + "%03d" + ext
+
+ix = 1
+
+im = Image.open(infile)
+
+if html:
+ file, ext = os.path.splitext(outfile)
+ html = open(file+".html", "w")
+ html.write("\n\n")
+
+while True:
+
+ if frames[ix]:
+ im.save(outfile % ix)
+ print(outfile % ix)
+
+ if html:
+ html.write("
\n" % outfile % ix)
+
+ try:
+ im.seek(ix)
+ except EOFError:
+ break
+
+ ix += 1
+
+if html:
+ html.write("\n\n")
diff --git a/bin/f2py3.5 b/bin/f2py3.5
new file mode 100755
index 0000000..fad007b
--- /dev/null
+++ b/bin/f2py3.5
@@ -0,0 +1,28 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+# See http://cens.ioc.ee/projects/f2py2e/
+from __future__ import division, print_function
+
+import os
+import sys
+for mode in ["g3-numpy", "2e-numeric", "2e-numarray", "2e-numpy"]:
+ try:
+ i = sys.argv.index("--" + mode)
+ del sys.argv[i]
+ break
+ except ValueError:
+ pass
+os.environ["NO_SCIPY_IMPORT"] = "f2py"
+if mode == "g3-numpy":
+ sys.stderr.write("G3 f2py support is not implemented, yet.\\n")
+ sys.exit(1)
+elif mode == "2e-numeric":
+ from f2py2e import main
+elif mode == "2e-numarray":
+ sys.argv.append("-DNUMARRAY")
+ from f2py2e import main
+elif mode == "2e-numpy":
+ from numpy.f2py import main
+else:
+ sys.stderr.write("Unknown mode: " + repr(mode) + "\\n")
+ sys.exit(1)
+main()
diff --git a/bin/flake8 b/bin/flake8
new file mode 100755
index 0000000..45f0132
--- /dev/null
+++ b/bin/flake8
@@ -0,0 +1,11 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+
+# -*- coding: utf-8 -*-
+import re
+import sys
+
+from flake8.main import main
+
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/bin/gifmaker.py b/bin/gifmaker.py
new file mode 100755
index 0000000..f0d4dfb
--- /dev/null
+++ b/bin/gifmaker.py
@@ -0,0 +1,31 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+#
+# The Python Imaging Library
+# $Id$
+#
+# convert sequence format to GIF animation
+#
+# history:
+# 97-01-03 fl created
+#
+# Copyright (c) Secret Labs AB 1997. All rights reserved.
+# Copyright (c) Fredrik Lundh 1997.
+#
+# See the README file for information on usage and redistribution.
+#
+
+from __future__ import print_function
+
+from PIL import Image
+
+if __name__ == "__main__":
+
+ import sys
+
+ if len(sys.argv) < 3:
+ print("GIFMAKER -- create GIF animations")
+ print("Usage: gifmaker infile outfile")
+ sys.exit(1)
+
+ im = Image.open(sys.argv[1])
+ im.save(sys.argv[2], save_all=True)
diff --git a/bin/histonets b/bin/histonets
new file mode 100755
index 0000000..ef7a9e1
--- /dev/null
+++ b/bin/histonets
@@ -0,0 +1,11 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+
+# -*- coding: utf-8 -*-
+import re
+import sys
+
+from histonets.cli import main
+
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/bin/noteshrink b/bin/noteshrink
new file mode 100755
index 0000000..4acf53e
--- /dev/null
+++ b/bin/noteshrink
@@ -0,0 +1,11 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+
+# -*- coding: utf-8 -*-
+import re
+import sys
+
+from noteshrink import main
+
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/bin/painter.py b/bin/painter.py
new file mode 100755
index 0000000..d797e8c
--- /dev/null
+++ b/bin/painter.py
@@ -0,0 +1,82 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+#
+# The Python Imaging Library
+# $Id$
+#
+# this demo script illustrates pasting into an already displayed
+# photoimage. note that the current version of Tk updates the whole
+# image every time we paste, so to get decent performance, we split
+# the image into a set of tiles.
+#
+
+try:
+ from tkinter import Tk, Canvas, NW
+except ImportError:
+ from Tkinter import Tk, Canvas, NW
+
+from PIL import Image, ImageTk
+import sys
+
+#
+# painter widget
+
+
+class PaintCanvas(Canvas):
+ def __init__(self, master, image):
+ Canvas.__init__(self, master, width=image.size[0], height=image.size[1])
+
+ # fill the canvas
+ self.tile = {}
+ self.tilesize = tilesize = 32
+ xsize, ysize = image.size
+ for x in range(0, xsize, tilesize):
+ for y in range(0, ysize, tilesize):
+ box = x, y, min(xsize, x+tilesize), min(ysize, y+tilesize)
+ tile = ImageTk.PhotoImage(image.crop(box))
+ self.create_image(x, y, image=tile, anchor=NW)
+ self.tile[(x, y)] = box, tile
+
+ self.image = image
+
+ self.bind("", self.paint)
+
+ def paint(self, event):
+ xy = event.x - 10, event.y - 10, event.x + 10, event.y + 10
+ im = self.image.crop(xy)
+
+ # process the image in some fashion
+ im = im.convert("L")
+
+ self.image.paste(im, xy)
+ self.repair(xy)
+
+ def repair(self, box):
+ # update canvas
+ dx = box[0] % self.tilesize
+ dy = box[1] % self.tilesize
+ for x in range(box[0]-dx, box[2]+1, self.tilesize):
+ for y in range(box[1]-dy, box[3]+1, self.tilesize):
+ try:
+ xy, tile = self.tile[(x, y)]
+ tile.paste(self.image.crop(xy))
+ except KeyError:
+ pass # outside the image
+ self.update_idletasks()
+
+#
+# main
+
+if len(sys.argv) != 2:
+ print("Usage: painter file")
+ sys.exit(1)
+
+root = Tk()
+
+im = Image.open(sys.argv[1])
+
+if im.mode != "RGB":
+ im = im.convert("RGB")
+
+PaintCanvas(root, im).pack()
+
+root.mainloop()
diff --git a/bin/pilconvert.py b/bin/pilconvert.py
new file mode 100755
index 0000000..65c628e
--- /dev/null
+++ b/bin/pilconvert.py
@@ -0,0 +1,99 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+#
+# The Python Imaging Library.
+# $Id$
+#
+# convert image files
+#
+# History:
+# 0.1 96-04-20 fl Created
+# 0.2 96-10-04 fl Use draft mode when converting images
+# 0.3 96-12-30 fl Optimize output (PNG, JPEG)
+# 0.4 97-01-18 fl Made optimize an option (PNG, JPEG)
+# 0.5 98-12-30 fl Fixed -f option (from Anthony Baxter)
+#
+
+from __future__ import print_function
+
+import getopt
+import string
+import sys
+
+from PIL import Image
+
+
+def usage():
+ print("PIL Convert 0.5/1998-12-30 -- convert image files")
+ print("Usage: pilconvert [option] infile outfile")
+ print()
+ print("Options:")
+ print()
+ print(" -c convert to format (default is given by extension)")
+ print()
+ print(" -g convert to greyscale")
+ print(" -p convert to palette image (using standard palette)")
+ print(" -r convert to rgb")
+ print()
+ print(" -o optimize output (trade speed for size)")
+ print(" -q set compression quality (0-100, JPEG only)")
+ print()
+ print(" -f list supported file formats")
+ sys.exit(1)
+
+if len(sys.argv) == 1:
+ usage()
+
+try:
+ opt, argv = getopt.getopt(sys.argv[1:], "c:dfgopq:r")
+except getopt.error as v:
+ print(v)
+ sys.exit(1)
+
+output_format = None
+convert = None
+
+options = {}
+
+for o, a in opt:
+
+ if o == "-f":
+ Image.init()
+ id = sorted(Image.ID)
+ print("Supported formats (* indicates output format):")
+ for i in id:
+ if i in Image.SAVE:
+ print(i+"*", end=' ')
+ else:
+ print(i, end=' ')
+ sys.exit(1)
+
+ elif o == "-c":
+ output_format = a
+
+ if o == "-g":
+ convert = "L"
+ elif o == "-p":
+ convert = "P"
+ elif o == "-r":
+ convert = "RGB"
+
+ elif o == "-o":
+ options["optimize"] = 1
+ elif o == "-q":
+ options["quality"] = string.atoi(a)
+
+if len(argv) != 2:
+ usage()
+
+try:
+ im = Image.open(argv[0])
+ if convert and im.mode != convert:
+ im.draft(convert, im.size)
+ im = im.convert(convert)
+ if output_format:
+ im.save(argv[1], output_format, **options)
+ else:
+ im.save(argv[1], **options)
+except:
+ print("cannot convert image", end=' ')
+ print("(%s:%s)" % (sys.exc_info()[0], sys.exc_info()[1]))
diff --git a/bin/pildriver.py b/bin/pildriver.py
new file mode 100755
index 0000000..d069238
--- /dev/null
+++ b/bin/pildriver.py
@@ -0,0 +1,526 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+"""PILdriver, an image-processing calculator using PIL.
+
+An instance of class PILDriver is essentially a software stack machine
+(Polish-notation interpreter) for sequencing PIL image
+transformations. The state of the instance is the interpreter stack.
+
+The only method one will normally invoke after initialization is the
+`execute' method. This takes an argument list of tokens, pushes them
+onto the instance's stack, and then tries to clear the stack by
+successive evaluation of PILdriver operators. Any part of the stack
+not cleaned off persists and is part of the evaluation context for
+the next call of the execute method.
+
+PILDriver doesn't catch any exceptions, on the theory that these
+are actually diagnostic information that should be interpreted by
+the calling code.
+
+When called as a script, the command-line arguments are passed to
+a PILDriver instance. If there are no command-line arguments, the
+module runs an interactive interpreter, each line of which is split into
+space-separated tokens and passed to the execute method.
+
+In the method descriptions below, a first line beginning with the string
+`usage:' means this method can be invoked with the token that follows
+it. Following <>-enclosed arguments describe how the method interprets
+the entries on the stack. Each argument specification begins with a
+type specification: either `int', `float', `string', or `image'.
+
+All operations consume their arguments off the stack (use `dup' to
+keep copies around). Use `verbose 1' to see the stack state displayed
+before each operation.
+
+Usage examples:
+
+ `show crop 0 0 200 300 open test.png' loads test.png, crops out a portion
+of its upper-left-hand corner and displays the cropped portion.
+
+ `save rotated.png rotate 30 open test.tiff' loads test.tiff, rotates it
+30 degrees, and saves the result as rotated.png (in PNG format).
+"""
+# by Eric S. Raymond
+# $Id$
+
+# TO DO:
+# 1. Add PILFont capabilities, once that's documented.
+# 2. Add PILDraw operations.
+# 3. Add support for composing and decomposing multiple-image files.
+#
+
+from __future__ import print_function
+
+from PIL import Image
+
+
+class PILDriver(object):
+
+ verbose = 0
+
+ def do_verbose(self):
+ """usage: verbose
+
+ Set verbosity flag from top of stack.
+ """
+ self.verbose = int(self.do_pop())
+
+ # The evaluation stack (internal only)
+
+ stack = [] # Stack of pending operations
+
+ def push(self, item):
+ "Push an argument onto the evaluation stack."
+ self.stack.insert(0, item)
+
+ def top(self):
+ "Return the top-of-stack element."
+ return self.stack[0]
+
+ # Stack manipulation (callable)
+
+ def do_clear(self):
+ """usage: clear
+
+ Clear the stack.
+ """
+ self.stack = []
+
+ def do_pop(self):
+ """usage: pop
+
+ Discard the top element on the stack.
+ """
+ return self.stack.pop(0)
+
+ def do_dup(self):
+ """usage: dup
+
+ Duplicate the top-of-stack item.
+ """
+ if hasattr(self, 'format'): # If it's an image, do a real copy
+ dup = self.stack[0].copy()
+ else:
+ dup = self.stack[0]
+ self.push(dup)
+
+ def do_swap(self):
+ """usage: swap
+
+ Swap the top-of-stack item with the next one down.
+ """
+ self.stack = [self.stack[1], self.stack[0]] + self.stack[2:]
+
+ # Image module functions (callable)
+
+ def do_new(self):
+ """usage: new :
+
+ Create and push a greyscale image of given size and color.
+ """
+ xsize = int(self.do_pop())
+ ysize = int(self.do_pop())
+ color = int(self.do_pop())
+ self.push(Image.new("L", (xsize, ysize), color))
+
+ def do_open(self):
+ """usage: open
+
+ Open the indicated image, read it, push the image on the stack.
+ """
+ self.push(Image.open(self.do_pop()))
+
+ def do_blend(self):
+ """usage: blend
+
+ Replace two images and an alpha with the blended image.
+ """
+ image1 = self.do_pop()
+ image2 = self.do_pop()
+ alpha = float(self.do_pop())
+ self.push(Image.blend(image1, image2, alpha))
+
+ def do_composite(self):
+ """usage: composite
+
+ Replace two images and a mask with their composite.
+ """
+ image1 = self.do_pop()
+ image2 = self.do_pop()
+ mask = self.do_pop()
+ self.push(Image.composite(image1, image2, mask))
+
+ def do_merge(self):
+ """usage: merge
+ [ [ []]]
+
+ Merge top-of stack images in a way described by the mode.
+ """
+ mode = self.do_pop()
+ bandlist = []
+ for band in mode:
+ bandlist.append(self.do_pop())
+ self.push(Image.merge(mode, bandlist))
+
+ # Image class methods
+
+ def do_convert(self):
+ """usage: convert
+
+ Convert the top image to the given mode.
+ """
+ mode = self.do_pop()
+ image = self.do_pop()
+ self.push(image.convert(mode))
+
+ def do_copy(self):
+ """usage: copy
+
+ Make and push a true copy of the top image.
+ """
+ self.dup()
+
+ def do_crop(self):
+ """usage: crop
+
+
+ Crop and push a rectangular region from the current image.
+ """
+ left = int(self.do_pop())
+ upper = int(self.do_pop())
+ right = int(self.do_pop())
+ lower = int(self.do_pop())
+ image = self.do_pop()
+ self.push(image.crop((left, upper, right, lower)))
+
+ def do_draft(self):
+ """usage: draft
+
+ Configure the loader for a given mode and size.
+ """
+ mode = self.do_pop()
+ xsize = int(self.do_pop())
+ ysize = int(self.do_pop())
+ self.push(self.draft(mode, (xsize, ysize)))
+
+ def do_filter(self):
+ """usage: filter
+
+ Process the top image with the given filter.
+ """
+ from PIL import ImageFilter
+ imageFilter = getattr(ImageFilter, self.do_pop().upper())
+ image = self.do_pop()
+ self.push(image.filter(imageFilter))
+
+ def do_getbbox(self):
+ """usage: getbbox
+
+ Push left, upper, right, and lower pixel coordinates of the top image.
+ """
+ bounding_box = self.do_pop().getbbox()
+ self.push(bounding_box[3])
+ self.push(bounding_box[2])
+ self.push(bounding_box[1])
+ self.push(bounding_box[0])
+
+ def do_getextrema(self):
+ """usage: extrema
+
+ Push minimum and maximum pixel values of the top image.
+ """
+ extrema = self.do_pop().extrema()
+ self.push(extrema[1])
+ self.push(extrema[0])
+
+ def do_offset(self):
+ """usage: offset
+
+ Offset the pixels in the top image.
+ """
+ xoff = int(self.do_pop())
+ yoff = int(self.do_pop())
+ image = self.do_pop()
+ self.push(image.offset(xoff, yoff))
+
+ def do_paste(self):
+ """usage: paste
+
+
+ Paste figure image into ground with upper left at given offsets.
+ """
+ figure = self.do_pop()
+ xoff = int(self.do_pop())
+ yoff = int(self.do_pop())
+ ground = self.do_pop()
+ if figure.mode == "RGBA":
+ ground.paste(figure, (xoff, yoff), figure)
+ else:
+ ground.paste(figure, (xoff, yoff))
+ self.push(ground)
+
+ def do_resize(self):
+ """usage: resize
+
+ Resize the top image.
+ """
+ ysize = int(self.do_pop())
+ xsize = int(self.do_pop())
+ image = self.do_pop()
+ self.push(image.resize((xsize, ysize)))
+
+ def do_rotate(self):
+ """usage: rotate
+
+ Rotate image through a given angle
+ """
+ angle = int(self.do_pop())
+ image = self.do_pop()
+ self.push(image.rotate(angle))
+
+ def do_save(self):
+ """usage: save
+
+ Save image with default options.
+ """
+ filename = self.do_pop()
+ image = self.do_pop()
+ image.save(filename)
+
+ def do_save2(self):
+ """usage: save2
+
+ Save image with specified options.
+ """
+ filename = self.do_pop()
+ options = self.do_pop()
+ image = self.do_pop()
+ image.save(filename, None, options)
+
+ def do_show(self):
+ """usage: show
+
+ Display and pop the top image.
+ """
+ self.do_pop().show()
+
+ def do_thumbnail(self):
+ """usage: thumbnail
+
+ Modify the top image in the stack to contain a thumbnail of itself.
+ """
+ ysize = int(self.do_pop())
+ xsize = int(self.do_pop())
+ self.top().thumbnail((xsize, ysize))
+
+ def do_transpose(self):
+ """usage: transpose
+
+ Transpose the top image.
+ """
+ transpose = self.do_pop().upper()
+ image = self.do_pop()
+ self.push(image.transpose(transpose))
+
+ # Image attributes
+
+ def do_format(self):
+ """usage: format
+
+ Push the format of the top image onto the stack.
+ """
+ self.push(self.do_pop().format)
+
+ def do_mode(self):
+ """usage: mode
+
+ Push the mode of the top image onto the stack.
+ """
+ self.push(self.do_pop().mode)
+
+ def do_size(self):
+ """usage: size
+
+ Push the image size on the stack as (y, x).
+ """
+ size = self.do_pop().size
+ self.push(size[0])
+ self.push(size[1])
+
+ # ImageChops operations
+
+ def do_invert(self):
+ """usage: invert
+
+ Invert the top image.
+ """
+ from PIL import ImageChops
+ self.push(ImageChops.invert(self.do_pop()))
+
+ def do_lighter(self):
+ """usage: lighter
+
+ Pop the two top images, push an image of the lighter pixels of both.
+ """
+ from PIL import ImageChops
+ image1 = self.do_pop()
+ image2 = self.do_pop()
+ self.push(ImageChops.lighter(image1, image2))
+
+ def do_darker(self):
+ """usage: darker
+
+ Pop the two top images, push an image of the darker pixels of both.
+ """
+ from PIL import ImageChops
+ image1 = self.do_pop()
+ image2 = self.do_pop()
+ self.push(ImageChops.darker(image1, image2))
+
+ def do_difference(self):
+ """usage: difference
+
+ Pop the two top images, push the difference image
+ """
+ from PIL import ImageChops
+ image1 = self.do_pop()
+ image2 = self.do_pop()
+ self.push(ImageChops.difference(image1, image2))
+
+ def do_multiply(self):
+ """usage: multiply
+
+ Pop the two top images, push the multiplication image.
+ """
+ from PIL import ImageChops
+ image1 = self.do_pop()
+ image2 = self.do_pop()
+ self.push(ImageChops.multiply(image1, image2))
+
+ def do_screen(self):
+ """usage: screen
+
+ Pop the two top images, superimpose their inverted versions.
+ """
+ from PIL import ImageChops
+ image2 = self.do_pop()
+ image1 = self.do_pop()
+ self.push(ImageChops.screen(image1, image2))
+
+ def do_add(self):
+ """usage: add
+
+ Pop the two top images, produce the scaled sum with offset.
+ """
+ from PIL import ImageChops
+ image1 = self.do_pop()
+ image2 = self.do_pop()
+ scale = float(self.do_pop())
+ offset = int(self.do_pop())
+ self.push(ImageChops.add(image1, image2, scale, offset))
+
+ def do_subtract(self):
+ """usage: subtract
+
+ Pop the two top images, produce the scaled difference with offset.
+ """
+ from PIL import ImageChops
+ image1 = self.do_pop()
+ image2 = self.do_pop()
+ scale = float(self.do_pop())
+ offset = int(self.do_pop())
+ self.push(ImageChops.subtract(image1, image2, scale, offset))
+
+ # ImageEnhance classes
+
+ def do_color(self):
+ """usage: color
+
+ Enhance color in the top image.
+ """
+ from PIL import ImageEnhance
+ factor = float(self.do_pop())
+ image = self.do_pop()
+ enhancer = ImageEnhance.Color(image)
+ self.push(enhancer.enhance(factor))
+
+ def do_contrast(self):
+ """usage: contrast
+
+ Enhance contrast in the top image.
+ """
+ from PIL import ImageEnhance
+ factor = float(self.do_pop())
+ image = self.do_pop()
+ enhancer = ImageEnhance.Contrast(image)
+ self.push(enhancer.enhance(factor))
+
+ def do_brightness(self):
+ """usage: brightness
+
+ Enhance brightness in the top image.
+ """
+ from PIL import ImageEnhance
+ factor = float(self.do_pop())
+ image = self.do_pop()
+ enhancer = ImageEnhance.Brightness(image)
+ self.push(enhancer.enhance(factor))
+
+ def do_sharpness(self):
+ """usage: sharpness
+
+ Enhance sharpness in the top image.
+ """
+ from PIL import ImageEnhance
+ factor = float(self.do_pop())
+ image = self.do_pop()
+ enhancer = ImageEnhance.Sharpness(image)
+ self.push(enhancer.enhance(factor))
+
+ # The interpreter loop
+
+ def execute(self, list):
+ "Interpret a list of PILDriver commands."
+ list.reverse()
+ while len(list) > 0:
+ self.push(list[0])
+ list = list[1:]
+ if self.verbose:
+ print("Stack: " + repr(self.stack))
+ top = self.top()
+ if not isinstance(top, str):
+ continue
+ funcname = "do_" + top
+ if not hasattr(self, funcname):
+ continue
+ else:
+ self.do_pop()
+ func = getattr(self, funcname)
+ func()
+
+if __name__ == '__main__':
+ import sys
+
+ # If we see command-line arguments, interpret them as a stack state
+ # and execute. Otherwise go interactive.
+
+ driver = PILDriver()
+ if len(sys.argv[1:]) > 0:
+ driver.execute(sys.argv[1:])
+ else:
+ print("PILDriver says hello.")
+ while True:
+ try:
+ if sys.version_info[0] >= 3:
+ line = input('pildriver> ')
+ else:
+ line = raw_input('pildriver> ')
+ except EOFError:
+ print("\nPILDriver says goodbye.")
+ break
+ driver.execute(line.split())
+ print(driver.stack)
+
+# The following sets edit modes for GNU EMACS
+# Local Variables:
+# mode:python
+# End:
diff --git a/bin/pilfile.py b/bin/pilfile.py
new file mode 100755
index 0000000..3f32bb6
--- /dev/null
+++ b/bin/pilfile.py
@@ -0,0 +1,101 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+#
+# The Python Imaging Library.
+# $Id$
+#
+# a utility to identify image files
+#
+# this script identifies image files, extracting size and
+# pixel mode information for known file formats. Note that
+# you don't need the PIL C extension to use this module.
+#
+# History:
+# 0.0 1995-09-01 fl Created
+# 0.1 1996-05-18 fl Modified options, added debugging mode
+# 0.2 1996-12-29 fl Added verify mode
+# 0.3 1999-06-05 fl Don't mess up on class exceptions (1.5.2 and later)
+# 0.4 2003-09-30 fl Expand wildcards on Windows; robustness tweaks
+#
+
+from __future__ import print_function
+
+import getopt
+import glob
+import logging
+import sys
+
+from PIL import Image
+
+if len(sys.argv) == 1:
+ print("PIL File 0.4/2003-09-30 -- identify image files")
+ print("Usage: pilfile [option] files...")
+ print("Options:")
+ print(" -f list supported file formats")
+ print(" -i show associated info and tile data")
+ print(" -v verify file headers")
+ print(" -q quiet, don't warn for unidentified/missing/broken files")
+ sys.exit(1)
+
+try:
+ opt, args = getopt.getopt(sys.argv[1:], "fqivD")
+except getopt.error as v:
+ print(v)
+ sys.exit(1)
+
+verbose = quiet = verify = 0
+logging_level = "WARNING"
+
+for o, a in opt:
+ if o == "-f":
+ Image.init()
+ id = sorted(Image.ID)
+ print("Supported formats:")
+ for i in id:
+ print(i, end=' ')
+ sys.exit(1)
+ elif o == "-i":
+ verbose = 1
+ elif o == "-q":
+ quiet = 1
+ elif o == "-v":
+ verify = 1
+ elif o == "-D":
+ logging_level = "DEBUG"
+
+logging.basicConfig(level=logging_level)
+
+
+def globfix(files):
+ # expand wildcards where necessary
+ if sys.platform == "win32":
+ out = []
+ for file in files:
+ if glob.has_magic(file):
+ out.extend(glob.glob(file))
+ else:
+ out.append(file)
+ return out
+ return files
+
+for file in globfix(args):
+ try:
+ im = Image.open(file)
+ print("%s:" % file, im.format, "%dx%d" % im.size, im.mode, end=' ')
+ if verbose:
+ print(im.info, im.tile, end=' ')
+ print()
+ if verify:
+ try:
+ im.verify()
+ except:
+ if not quiet:
+ print("failed to verify image", end=' ')
+ print("(%s:%s)" % (sys.exc_info()[0], sys.exc_info()[1]))
+ except IOError as v:
+ if not quiet:
+ print(file, "failed:", v)
+ except:
+ import traceback
+ if not quiet:
+ print(file, "failed:", "unexpected error")
+ traceback.print_exc(file=sys.stdout)
diff --git a/bin/pilfont.py b/bin/pilfont.py
new file mode 100755
index 0000000..1d0a6d1
--- /dev/null
+++ b/bin/pilfont.py
@@ -0,0 +1,57 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+#
+# The Python Imaging Library
+# $Id$
+#
+# PIL raster font compiler
+#
+# history:
+# 1997-08-25 fl created
+# 2002-03-10 fl use "from PIL import"
+#
+
+from __future__ import print_function
+
+import glob
+import sys
+
+# drivers
+from PIL import BdfFontFile
+from PIL import PcfFontFile
+
+VERSION = "0.4"
+
+if len(sys.argv) <= 1:
+ print("PILFONT", VERSION, "-- PIL font compiler.")
+ print()
+ print("Usage: pilfont fontfiles...")
+ print()
+ print("Convert given font files to the PIL raster font format.")
+ print("This version of pilfont supports X BDF and PCF fonts.")
+ sys.exit(1)
+
+files = []
+for f in sys.argv[1:]:
+ files = files + glob.glob(f)
+
+for f in files:
+
+ print(f + "...", end=' ')
+
+ try:
+
+ fp = open(f, "rb")
+
+ try:
+ p = PcfFontFile.PcfFontFile(fp)
+ except SyntaxError:
+ fp.seek(0)
+ p = BdfFontFile.BdfFontFile(fp)
+
+ p.save(f)
+
+ except (SyntaxError, IOError):
+ print("failed")
+
+ else:
+ print("OK")
diff --git a/bin/pilprint.py b/bin/pilprint.py
new file mode 100755
index 0000000..d3dfb84
--- /dev/null
+++ b/bin/pilprint.py
@@ -0,0 +1,102 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+#
+# The Python Imaging Library.
+# $Id$
+#
+# print image files to postscript printer
+#
+# History:
+# 0.1 1996-04-20 fl Created
+# 0.2 1996-10-04 fl Use draft mode when converting.
+# 0.3 2003-05-06 fl Fixed a typo or two.
+#
+
+from __future__ import print_function
+import getopt
+import os
+import sys
+import subprocess
+
+VERSION = "pilprint 0.3/2003-05-05"
+
+from PIL import Image
+from PIL import PSDraw
+
+letter = (1.0*72, 1.0*72, 7.5*72, 10.0*72)
+
+
+def description(filepath, image):
+ title = os.path.splitext(os.path.split(filepath)[1])[0]
+ format = " (%dx%d "
+ if image.format:
+ format = " (" + image.format + " %dx%d "
+ return title + format % image.size + image.mode + ")"
+
+if len(sys.argv) == 1:
+ print("PIL Print 0.3/2003-05-05 -- print image files")
+ print("Usage: pilprint files...")
+ print("Options:")
+ print(" -c colour printer (default is monochrome)")
+ print(" -d debug (show available drivers)")
+ print(" -p print via lpr (default is stdout)")
+ print(" -P same as -p but use given printer")
+ sys.exit(1)
+
+try:
+ opt, argv = getopt.getopt(sys.argv[1:], "cdpP:")
+except getopt.error as v:
+ print(v)
+ sys.exit(1)
+
+printerArgs = [] # print to stdout
+monochrome = 1 # reduce file size for most common case
+
+for o, a in opt:
+ if o == "-d":
+ # debug: show available drivers
+ Image.init()
+ print(Image.ID)
+ sys.exit(1)
+ elif o == "-c":
+ # colour printer
+ monochrome = 0
+ elif o == "-p":
+ # default printer channel
+ printerArgs = ["lpr"]
+ elif o == "-P":
+ # printer channel
+ printerArgs = ["lpr", "-P%s" % a]
+
+for filepath in argv:
+ try:
+
+ im = Image.open(filepath)
+
+ title = description(filepath, im)
+
+ if monochrome and im.mode not in ["1", "L"]:
+ im.draft("L", im.size)
+ im = im.convert("L")
+
+ if printerArgs:
+ p = subprocess.Popen(printerArgs, stdin=subprocess.PIPE)
+ fp = p.stdin
+ else:
+ fp = sys.stdout
+
+ ps = PSDraw.PSDraw(fp)
+
+ ps.begin_document()
+ ps.setfont("Helvetica-Narrow-Bold", 18)
+ ps.text((letter[0], letter[3]+24), title)
+ ps.setfont("Helvetica-Narrow-Bold", 8)
+ ps.text((letter[0], letter[1]-30), VERSION)
+ ps.image(letter, im)
+ ps.end_document()
+
+ if printerArgs:
+ fp.close()
+
+ except:
+ print("cannot print image", end=' ')
+ print("(%s:%s)" % (sys.exc_info()[0], sys.exc_info()[1]))
diff --git a/bin/pip b/bin/pip
new file mode 100755
index 0000000..630fe28
--- /dev/null
+++ b/bin/pip
@@ -0,0 +1,11 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+
+# -*- coding: utf-8 -*-
+import re
+import sys
+
+from pip import main
+
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/bin/pip3 b/bin/pip3
new file mode 100755
index 0000000..630fe28
--- /dev/null
+++ b/bin/pip3
@@ -0,0 +1,11 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+
+# -*- coding: utf-8 -*-
+import re
+import sys
+
+from pip import main
+
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/bin/pip3.5 b/bin/pip3.5
new file mode 100755
index 0000000..630fe28
--- /dev/null
+++ b/bin/pip3.5
@@ -0,0 +1,11 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+
+# -*- coding: utf-8 -*-
+import re
+import sys
+
+from pip import main
+
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/bin/player.py b/bin/player.py
new file mode 100755
index 0000000..aa1d324
--- /dev/null
+++ b/bin/player.py
@@ -0,0 +1,102 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+#
+# The Python Imaging Library
+# $Id$
+#
+
+from __future__ import print_function
+
+try:
+ from tkinter import *
+except ImportError:
+ from Tkinter import *
+
+from PIL import Image, ImageTk
+import sys
+
+
+# --------------------------------------------------------------------
+# an image animation player
+
+class UI(Label):
+
+ def __init__(self, master, im):
+ if isinstance(im, list):
+ # list of images
+ self.im = im[1:]
+ im = self.im[0]
+ else:
+ # sequence
+ self.im = im
+
+ if im.mode == "1":
+ self.image = ImageTk.BitmapImage(im, foreground="white")
+ else:
+ self.image = ImageTk.PhotoImage(im)
+
+ Label.__init__(self, master, image=self.image, bg="black", bd=0)
+
+ self.update()
+
+ try:
+ duration = im.info["duration"]
+ except KeyError:
+ duration = 100
+ self.after(duration, self.next)
+
+ def next(self):
+
+ if isinstance(self.im, list):
+
+ try:
+ im = self.im[0]
+ del self.im[0]
+ self.image.paste(im)
+ except IndexError:
+ return # end of list
+
+ else:
+
+ try:
+ im = self.im
+ im.seek(im.tell() + 1)
+ self.image.paste(im)
+ except EOFError:
+ return # end of file
+
+ try:
+ duration = im.info["duration"]
+ except KeyError:
+ duration = 100
+ self.after(duration, self.next)
+
+ self.update_idletasks()
+
+
+# --------------------------------------------------------------------
+# script interface
+
+if __name__ == "__main__":
+
+ if not sys.argv[1:]:
+ print("Syntax: python player.py imagefile(s)")
+ sys.exit(1)
+
+ filename = sys.argv[1]
+
+ root = Tk()
+ root.title(filename)
+
+ if len(sys.argv) > 2:
+ # list of images
+ print("loading...")
+ im = []
+ for filename in sys.argv[1:]:
+ im.append(Image.open(filename))
+ else:
+ # sequence
+ im = Image.open(filename)
+
+ UI(root, im).pack()
+
+ root.mainloop()
diff --git a/bin/pybabel b/bin/pybabel
new file mode 100755
index 0000000..d63af2d
--- /dev/null
+++ b/bin/pybabel
@@ -0,0 +1,11 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+
+# -*- coding: utf-8 -*-
+import re
+import sys
+
+from babel.messages.frontend import main
+
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/bin/pycodestyle b/bin/pycodestyle
new file mode 100755
index 0000000..61ea2b8
--- /dev/null
+++ b/bin/pycodestyle
@@ -0,0 +1,11 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+
+# -*- coding: utf-8 -*-
+import re
+import sys
+
+from pycodestyle import _main
+
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(_main())
diff --git a/bin/pyflakes b/bin/pyflakes
new file mode 100755
index 0000000..4c4c6a6
--- /dev/null
+++ b/bin/pyflakes
@@ -0,0 +1,11 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+
+# -*- coding: utf-8 -*-
+import re
+import sys
+
+from pyflakes.api import main
+
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/bin/pygmentize b/bin/pygmentize
new file mode 100755
index 0000000..5556740
--- /dev/null
+++ b/bin/pygmentize
@@ -0,0 +1,11 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+
+# -*- coding: utf-8 -*-
+import re
+import sys
+
+from pygments.cmdline import main
+
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/bin/python b/bin/python
new file mode 120000
index 0000000..f549cea
--- /dev/null
+++ b/bin/python
@@ -0,0 +1 @@
+python3.5
\ No newline at end of file
diff --git a/bin/python3 b/bin/python3
new file mode 120000
index 0000000..f549cea
--- /dev/null
+++ b/bin/python3
@@ -0,0 +1 @@
+python3.5
\ No newline at end of file
diff --git a/bin/python3.5 b/bin/python3.5
new file mode 120000
index 0000000..47c22ac
--- /dev/null
+++ b/bin/python3.5
@@ -0,0 +1 @@
+/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5
\ No newline at end of file
diff --git a/bin/range-detector b/bin/range-detector
new file mode 100755
index 0000000..81555c4
--- /dev/null
+++ b/bin/range-detector
@@ -0,0 +1,107 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+# -*- coding: utf-8 -*-
+
+# USAGE: You need to specify a filter and "only one" image source
+#
+# (python) range-detector --filter RGB --image /path/to/image.png
+# or
+# (python) range-detector --filter HSV --webcam
+
+import cv2
+import argparse
+from operator import xor
+
+
+def callback(value):
+ pass
+
+
+def setup_trackbars(range_filter):
+ cv2.namedWindow("Trackbars", 0)
+
+ for i in ["MIN", "MAX"]:
+ v = 0 if i == "MIN" else 255
+
+ for j in range_filter:
+ cv2.createTrackbar("%s_%s" % (j, i), "Trackbars", v, 255, callback)
+
+
+def get_arguments():
+ ap = argparse.ArgumentParser()
+ ap.add_argument('-f', '--filter', required=True,
+ help='Range filter. RGB or HSV')
+ ap.add_argument('-i', '--image', required=False,
+ help='Path to the image')
+ ap.add_argument('-w', '--webcam', required=False,
+ help='Use webcam', action='store_true')
+ ap.add_argument('-p', '--preview', required=False,
+ help='Show a preview of the image after applying the mask',
+ action='store_true')
+ args = vars(ap.parse_args())
+
+ if not xor(bool(args['image']), bool(args['webcam'])):
+ ap.error("Please specify only one image source")
+
+ if not args['filter'].upper() in ['RGB', 'HSV']:
+ ap.error("Please speciy a correct filter.")
+
+ return args
+
+
+def get_trackbar_values(range_filter):
+ values = []
+
+ for i in ["MIN", "MAX"]:
+ for j in range_filter:
+ v = cv2.getTrackbarPos("%s_%s" % (j, i), "Trackbars")
+ values.append(v)
+
+ return values
+
+
+def main():
+ args = get_arguments()
+
+ range_filter = args['filter'].upper()
+
+ if args['image']:
+ image = cv2.imread(args['image'])
+
+ if range_filter == 'RGB':
+ frame_to_thresh = image.copy()
+ else:
+ frame_to_thresh = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
+ else:
+ camera = cv2.VideoCapture(0)
+
+ setup_trackbars(range_filter)
+
+ while True:
+ if args['webcam']:
+ ret, image = camera.read()
+
+ if not ret:
+ break
+
+ if range_filter == 'RGB':
+ frame_to_thresh = image.copy()
+ else:
+ frame_to_thresh = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
+
+ v1_min, v2_min, v3_min, v1_max, v2_max, v3_max = get_trackbar_values(range_filter)
+
+ thresh = cv2.inRange(frame_to_thresh, (v1_min, v2_min, v3_min), (v1_max, v2_max, v3_max))
+
+ if args['preview']:
+ preview = cv2.bitwise_and(image, image, mask=thresh)
+ cv2.imshow("Preview", preview)
+ else:
+ cv2.imshow("Original", image)
+ cv2.imshow("Thresh", thresh)
+
+ if cv2.waitKey(1) & 0xFF is ord('q'):
+ break
+
+
+if __name__ == '__main__':
+ main()
diff --git a/bin/rst2html.py b/bin/rst2html.py
new file mode 100755
index 0000000..7876d7c
--- /dev/null
+++ b/bin/rst2html.py
@@ -0,0 +1,23 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+
+# $Id: rst2html.py 4564 2006-05-21 20:44:42Z wiemann $
+# Author: David Goodger
+# Copyright: This module has been placed in the public domain.
+
+"""
+A minimal front end to the Docutils Publisher, producing HTML.
+"""
+
+try:
+ import locale
+ locale.setlocale(locale.LC_ALL, '')
+except:
+ pass
+
+from docutils.core import publish_cmdline, default_description
+
+
+description = ('Generates (X)HTML documents from standalone reStructuredText '
+ 'sources. ' + default_description)
+
+publish_cmdline(writer_name='html', description=description)
diff --git a/bin/rst2latex.py b/bin/rst2latex.py
new file mode 100755
index 0000000..8e35906
--- /dev/null
+++ b/bin/rst2latex.py
@@ -0,0 +1,26 @@
+#!/Users/csb5t/projects/histonets/bin/python3.5
+
+# $Id: rst2latex.py 5905 2009-04-16 12:04:49Z milde $
+# Author: David Goodger
+# Copyright: This module has been placed in the public domain.
+
+"""
+A minimal front end to the Docutils Publisher, producing LaTeX.
+"""
+
+try:
+ import locale
+ locale.setlocale(locale.LC_ALL, '')
+except:
+ pass
+
+from docutils.core import publish_cmdline
+
+description = ('Generates LaTeX documents from standalone reStructuredText '
+ 'sources. '
+ 'Reads from