iiif_print 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +2 -0
- data/.env +5 -0
- data/.fcrepo_wrapper +4 -0
- data/.github/release.yml +20 -0
- data/.github/workflows/branches.yml +24 -0
- data/.github/workflows/build-lint-test-action.yaml +33 -0
- data/.github/workflows/release_labels.yml +25 -0
- data/.gitignore +52 -0
- data/.rubocop.yml +177 -0
- data/.solr_wrapper +8 -0
- data/.travis.yml +49 -0
- data/CONTRIBUTING.md +181 -0
- data/Dockerfile +15 -0
- data/Gemfile +52 -0
- data/LICENSE +203 -0
- data/README.md +203 -0
- data/Rakefile +38 -0
- data/app/actors/iiif_print/actors/file_set_actor_decorator.rb +56 -0
- data/app/assets/config/iiif_print_manifest.js +2 -0
- data/app/assets/images/iiif_print/.keep +0 -0
- data/app/assets/javascripts/iiif_print/autocomplete_fix.js +33 -0
- data/app/assets/javascripts/iiif_print/ocr_search.js.erb +6 -0
- data/app/assets/javascripts/iiif_print.js +3 -0
- data/app/assets/stylesheets/iiif_print/_iiif_print.scss +4 -0
- data/app/assets/stylesheets/iiif_print/_issue_search.scss +13 -0
- data/app/assets/stylesheets/iiif_print/_issues_calendar.scss +18 -0
- data/app/assets/stylesheets/iiif_print/_newspapers_search.scss +38 -0
- data/app/assets/stylesheets/iiif_print/_search_results.scss +6 -0
- data/app/helpers/hyrax/iiif_helper.rb +22 -0
- data/app/helpers/iiif_print/application_helper.rb +5 -0
- data/app/helpers/iiif_print_helper.rb +64 -0
- data/app/indexers/concerns/iiif_print/child_indexer.rb +34 -0
- data/app/indexers/concerns/iiif_print/file_set_indexer.rb +29 -0
- data/app/mailers/iiif_print/application_mailer.rb +8 -0
- data/app/models/concerns/iiif_print/set_child_flag.rb +29 -0
- data/app/models/concerns/iiif_print/solr/document.rb +47 -0
- data/app/models/iiif_print/application_record.rb +6 -0
- data/app/models/iiif_print/derivative_attachment.rb +8 -0
- data/app/models/iiif_print/iiif_search_response_decorator.rb +17 -0
- data/app/models/iiif_print/ingest_file_relation.rb +14 -0
- data/app/models/iiif_print/pending_relationship.rb +7 -0
- data/app/presenters/iiif_print/iiif_manifest_presenter_behavior.rb +10 -0
- data/app/presenters/iiif_print/iiif_manifest_presenter_factory_behavior.rb +33 -0
- data/app/presenters/iiif_print/work_show_presenter_decorator.rb +29 -0
- data/app/renderers/hyrax/renderers/faceted_attribute_renderer_decorator.rb +18 -0
- data/app/search_builders/concerns/iiif_print/exclude_models.rb +17 -0
- data/app/search_builders/concerns/iiif_print/highlight_search_params.rb +14 -0
- data/app/services/iiif_print/manifest_builder_service_behavior.rb +97 -0
- data/app/services/iiif_print/pluggable_derivative_service.rb +120 -0
- data/app/views/catalog/_snippets_more.html.erb +16 -0
- data/app/views/hyrax/base/_representative_media.html.erb +9 -0
- data/app/views/hyrax/base/iiif_viewers/_universal_viewer.html.erb +8 -0
- data/app/views/hyrax/file_sets/_actions.html.erb +45 -0
- data/bin/rails +13 -0
- data/config/fcrepo_wrapper_test.yml +5 -0
- data/config/initializers/assets.rb +2 -0
- data/config/locales/iiif_print.de.yml +148 -0
- data/config/locales/iiif_print.en.yml +119 -0
- data/config/locales/iiif_print.es.yml +148 -0
- data/config/locales/iiif_print.fr.yml +149 -0
- data/config/locales/iiif_print.it.yml +142 -0
- data/config/locales/iiif_print.pt-BR.yml +148 -0
- data/config/locales/iiif_print.zh.yml +142 -0
- data/config/solr_wrapper_test.yml +9 -0
- data/config/test-fixture/solr-config/_rest_managed.json +3 -0
- data/config/test-fixture/solr-config/admin-extra.html +31 -0
- data/config/test-fixture/solr-config/elevate.xml +36 -0
- data/config/test-fixture/solr-config/mapping-ISOLatin1Accent.txt +246 -0
- data/config/test-fixture/solr-config/protwords.txt +21 -0
- data/config/test-fixture/solr-config/schema.xml +366 -0
- data/config/test-fixture/solr-config/scripts.conf +24 -0
- data/config/test-fixture/solr-config/solrconfig.xml +322 -0
- data/config/test-fixture/solr-config/spellings.txt +2 -0
- data/config/test-fixture/solr-config/stopwords.txt +58 -0
- data/config/test-fixture/solr-config/stopwords_en.txt +58 -0
- data/config/test-fixture/solr-config/synonyms.txt +31 -0
- data/config/test-fixture/solr-config/xslt/example.xsl +132 -0
- data/config/test-fixture/solr-config/xslt/example_atom.xsl +67 -0
- data/config/test-fixture/solr-config/xslt/example_rss.xsl +66 -0
- data/config/test-fixture/solr-config/xslt/luke.xsl +337 -0
- data/config/vendor/fits.xml +55 -0
- data/config/vendor/imagemagick-6-policy.xml +76 -0
- data/db/migrate/20181214181358_create_iiif_print_derivative_attachments.rb +12 -0
- data/db/migrate/20190107165909_create_iiif_print_ingest_file_relations.rb +11 -0
- data/db/migrate/20230109000000_create_iiif_print_pending_relationships.rb +11 -0
- data/docker-compose.yml +129 -0
- data/iiif_print.gemspec +43 -0
- data/lib/generators/iiif_print/assets_generator.rb +29 -0
- data/lib/generators/iiif_print/catalog_controller_generator.rb +32 -0
- data/lib/generators/iiif_print/install_generator.rb +52 -0
- data/lib/generators/iiif_print/templates/config/initializers/iiif_print.rb +22 -0
- data/lib/generators/iiif_print/templates/iiif_print.scss +1 -0
- data/lib/iiif_print/base_derivative_service.rb +113 -0
- data/lib/iiif_print/blacklight_iiif_search/annotation_decorator.rb +84 -0
- data/lib/iiif_print/catalog_search_builder.rb +31 -0
- data/lib/iiif_print/configuration.rb +99 -0
- data/lib/iiif_print/data/fileset_helper.rb +25 -0
- data/lib/iiif_print/data/path_helper.rb +40 -0
- data/lib/iiif_print/data/work_derivatives.rb +323 -0
- data/lib/iiif_print/data/work_file.rb +92 -0
- data/lib/iiif_print/data/work_files.rb +199 -0
- data/lib/iiif_print/data.rb +35 -0
- data/lib/iiif_print/engine.rb +77 -0
- data/lib/iiif_print/errors.rb +9 -0
- data/lib/iiif_print/image_tool.rb +119 -0
- data/lib/iiif_print/jobs/application_job.rb +8 -0
- data/lib/iiif_print/jobs/child_works_from_pdf_job.rb +107 -0
- data/lib/iiif_print/jobs/create_relationships_job.rb +78 -0
- data/lib/iiif_print/jp2_derivative_service.rb +118 -0
- data/lib/iiif_print/jp2_image_metadata.rb +81 -0
- data/lib/iiif_print/lineage_service.rb +41 -0
- data/lib/iiif_print/metadata.rb +125 -0
- data/lib/iiif_print/pdf_derivative_service.rb +42 -0
- data/lib/iiif_print/split_pdfs/child_work_creation_from_pdf_service.rb +75 -0
- data/lib/iiif_print/split_pdfs/pages_into_images_service.rb +130 -0
- data/lib/iiif_print/split_pdfs/pdf_image_extraction_service.rb +85 -0
- data/lib/iiif_print/text_extraction/alto_reader.rb +123 -0
- data/lib/iiif_print/text_extraction/hocr_reader.rb +172 -0
- data/lib/iiif_print/text_extraction/page_ocr.rb +87 -0
- data/lib/iiif_print/text_extraction/render_alto.rb +84 -0
- data/lib/iiif_print/text_extraction/word_coords_builder.rb +38 -0
- data/lib/iiif_print/text_extraction.rb +11 -0
- data/lib/iiif_print/text_extraction_derivative_service.rb +47 -0
- data/lib/iiif_print/text_formats_from_alto_service.rb +77 -0
- data/lib/iiif_print/tiff_derivative_service.rb +50 -0
- data/lib/iiif_print/version.rb +3 -0
- data/lib/iiif_print/works_controller_behavior.rb +9 -0
- data/lib/iiif_print.rb +136 -0
- data/lib/tasks/set_child_works.rake +22 -0
- data/spec/.keep.txt +1 -0
- data/spec/factories/ability.rb +6 -0
- data/spec/factories/newspaper_issue.rb +7 -0
- data/spec/factories/newspaper_page.rb +7 -0
- data/spec/factories/newspaper_page_solr_document.rb +12 -0
- data/spec/factories/newspaper_title.rb +8 -0
- data/spec/factories/uploaded_pdf_file.rb +9 -0
- data/spec/factories/uploaded_txt_file.rb +9 -0
- data/spec/factories/user.rb +13 -0
- data/spec/fixtures/files/4.1.07.jp2 +0 -0
- data/spec/fixtures/files/4.1.07.tiff +0 -0
- data/spec/fixtures/files/README.md +7 -0
- data/spec/fixtures/files/alto-2-0.xsd +714 -0
- data/spec/fixtures/files/broken-truncated.pdf +0 -0
- data/spec/fixtures/files/credits.md +16 -0
- data/spec/fixtures/files/lowres-gray-via-ndnp-sample.tiff +0 -0
- data/spec/fixtures/files/minimal-1-page.pdf +0 -0
- data/spec/fixtures/files/minimal-2-page.pdf +0 -0
- data/spec/fixtures/files/minimal-alto.xml +31 -0
- data/spec/fixtures/files/ndnp-alto-sample.xml +24 -0
- data/spec/fixtures/files/ndnp-sample1-json.json +1 -0
- data/spec/fixtures/files/ndnp-sample1-txt.txt +1 -0
- data/spec/fixtures/files/ndnp-sample1.pdf +0 -0
- data/spec/fixtures/files/ocr_alto.xml +202 -0
- data/spec/fixtures/files/ocr_alto_scaled_4pts_per_px.xml +202 -0
- data/spec/fixtures/files/ocr_color.tiff +0 -0
- data/spec/fixtures/files/ocr_gray.jp2 +0 -0
- data/spec/fixtures/files/ocr_gray.tiff +0 -0
- data/spec/fixtures/files/ocr_mono.tiff +0 -0
- data/spec/fixtures/files/ocr_mono_text_hocr.html +78 -0
- data/spec/fixtures/files/page1.tiff +0 -0
- data/spec/fixtures/files/sample-4page-issue.pdf +0 -0
- data/spec/fixtures/files/sample-color-newsletter.pdf +0 -0
- data/spec/fixtures/files/thumbnail.jpg +0 -0
- data/spec/helpers/hyrax/iiif_helper_spec.rb +65 -0
- data/spec/helpers/iiif_print_helper_spec.rb +43 -0
- data/spec/iiif_print/base_derivative_service_spec.rb +11 -0
- data/spec/iiif_print/blacklight_iiif_search/annotation_decorator_spec.rb +51 -0
- data/spec/iiif_print/catalog_search_builder_spec.rb +60 -0
- data/spec/iiif_print/configuration_spec.rb +67 -0
- data/spec/iiif_print/data/work_derivatives_spec.rb +245 -0
- data/spec/iiif_print/data/work_file_spec.rb +99 -0
- data/spec/iiif_print/data/work_files_spec.rb +237 -0
- data/spec/iiif_print/image_tool_spec.rb +109 -0
- data/spec/iiif_print/jobs/child_works_from_pdf_job_spec.rb +30 -0
- data/spec/iiif_print/jobs/create_relationships_job_spec.rb +17 -0
- data/spec/iiif_print/jp2_image_metadata_spec.rb +37 -0
- data/spec/iiif_print/lineage_service_spec.rb +13 -0
- data/spec/iiif_print/metadata_spec.rb +115 -0
- data/spec/iiif_print/split_pdfs/pages_into_images_service_spec.rb +6 -0
- data/spec/iiif_print/text_extraction/alto_reader_spec.rb +49 -0
- data/spec/iiif_print/text_extraction/hocr_reader_spec.rb +45 -0
- data/spec/iiif_print/text_extraction/page_ocr_spec.rb +84 -0
- data/spec/iiif_print/text_extraction/render_alto_spec.rb +54 -0
- data/spec/iiif_print/text_extraction/word_coords_builder_spec.rb +44 -0
- data/spec/iiif_print_spec.rb +51 -0
- data/spec/misc_shared.rb +111 -0
- data/spec/models/iiif_print/derivative_attachment_spec.rb +37 -0
- data/spec/models/iiif_print/ingest_file_relation_spec.rb +56 -0
- data/spec/models/solr_document_spec.rb +14 -0
- data/spec/presenters/iiif_print/iiif_manifest_presenter_behavior_spec.rb +19 -0
- data/spec/presenters/iiif_print/iiif_manifest_presenter_factory_behavior_spec.rb +49 -0
- data/spec/services/iiif_print/jp2_derivative_service_spec.rb +59 -0
- data/spec/services/iiif_print/pdf_derivative_service_spec.rb +66 -0
- data/spec/services/iiif_print/pluggable_derivative_service_spec.rb +178 -0
- data/spec/services/iiif_print/text_extraction_derivative_service_spec.rb +82 -0
- data/spec/services/iiif_print/text_formats_from_alto_service_spec.rb +127 -0
- data/spec/services/iiif_print/tiff_derivative_service_spec.rb +65 -0
- data/spec/spec_helper.rb +181 -0
- data/spec/support/controller_level_helpers.rb +28 -0
- data/spec/support/iiif_print_models.rb +127 -0
- data/spec/test_app_templates/blacklight.yml +9 -0
- data/spec/test_app_templates/fedora.yml +15 -0
- data/spec/test_app_templates/lib/generators/test_app_generator.rb +40 -0
- data/spec/test_app_templates/redis.yml +9 -0
- data/spec/test_app_templates/solr/conf/schema.xml +362 -0
- data/spec/test_app_templates/solr/conf/solrconfig.xml +322 -0
- data/spec/test_app_templates/solr.yml +7 -0
- data/tasks/iiif_print_dev.rake +34 -0
- data/tmp/.keep +0 -0
- metadata +605 -0
data/docker-compose.yml
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
version: '3.8'
|
2
|
+
|
3
|
+
x-app: &app
|
4
|
+
build:
|
5
|
+
context: .
|
6
|
+
target: hyku-base
|
7
|
+
args:
|
8
|
+
- EXTRA_APK_PACKAGES=less vim bash openjdk11-jre ffmpeg rsync exiftool
|
9
|
+
# image: ghcr.io/scientist-softserv/palni-palci:${TAG:-latest}
|
10
|
+
env_file:
|
11
|
+
- .env
|
12
|
+
# NOTE: all common env variables moved to .env
|
13
|
+
volumes:
|
14
|
+
- node_modules:/app/samvera/hyrax-webapp/node_modules:cached
|
15
|
+
- uploads:/app/samvera/hyrax-webapp/public/uploads:cached
|
16
|
+
- assets:/app/samvera/hyrax-webapp/public/assets:cached
|
17
|
+
- cache:/app/samvera/hyrax-webapp/tmp/cache:cached
|
18
|
+
- .:/app/samvera/hyrax-webapp
|
19
|
+
networks:
|
20
|
+
internal:
|
21
|
+
|
22
|
+
volumes:
|
23
|
+
assets:
|
24
|
+
cache:
|
25
|
+
db:
|
26
|
+
fcrepo:
|
27
|
+
node_modules:
|
28
|
+
redis:
|
29
|
+
solr:
|
30
|
+
uploads:
|
31
|
+
zk:
|
32
|
+
zoo:
|
33
|
+
|
34
|
+
networks:
|
35
|
+
internal:
|
36
|
+
|
37
|
+
services:
|
38
|
+
solr:
|
39
|
+
image: solr:7.7.2
|
40
|
+
environment:
|
41
|
+
- VIRTUAL_PORT=8983
|
42
|
+
- VIRTUAL_HOST=solr.iiif_print.test
|
43
|
+
command:
|
44
|
+
- sh
|
45
|
+
- "-c"
|
46
|
+
- "precreate-core hyrax_test /opt/solr/server/configsets/hyraxconf; solr-precreate hyrax /opt/solr/server/configsets/hyraxconf"
|
47
|
+
volumes:
|
48
|
+
- solr:/var/solr/data:cached
|
49
|
+
- ./spec/test_app_templates/solr/conf/:/opt/solr/server/configsets/hyraxconf
|
50
|
+
networks:
|
51
|
+
- internal
|
52
|
+
|
53
|
+
fcrepo:
|
54
|
+
image: ghcr.io/samvera/fcrepo4:4.7.5
|
55
|
+
volumes:
|
56
|
+
- fcrepo:/data:cached
|
57
|
+
env_file:
|
58
|
+
- .env
|
59
|
+
environment:
|
60
|
+
- VIRTUAL_PORT=8080
|
61
|
+
- VIRTUAL_HOST=fcrepo.hyku.test
|
62
|
+
- JAVA_OPTS=${JAVA_OPTS} -Dfcrepo.modeshape.configuration="classpath:/config/file-simple/repository.json" -Dfcrepo.object.directory="/data/objects" -Dfcrepo.binary.directory="/data/binaries"
|
63
|
+
expose:
|
64
|
+
- 8080
|
65
|
+
networks:
|
66
|
+
internal:
|
67
|
+
|
68
|
+
db:
|
69
|
+
image: postgres:11.1
|
70
|
+
env_file:
|
71
|
+
- .env
|
72
|
+
environment:
|
73
|
+
- POSTGRES_DB=${DB_NAME}
|
74
|
+
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
75
|
+
- POSTGRES_USER=${DB_USER}
|
76
|
+
- VIRTUAL_PORT=5432
|
77
|
+
- VIRTUAL_HOST=db.hyku.test
|
78
|
+
volumes:
|
79
|
+
- db:/var/lib/postgresql/data
|
80
|
+
networks:
|
81
|
+
internal:
|
82
|
+
|
83
|
+
web:
|
84
|
+
<<: *app
|
85
|
+
environment:
|
86
|
+
- VIRTUAL_PORT=3000
|
87
|
+
- VIRTUAL_HOST=.hyku.test
|
88
|
+
command: tail -f /dev/null
|
89
|
+
##
|
90
|
+
## Similar to the above, except we will bundle and then tell the container
|
91
|
+
## to wait. You'll then need to bash into the web container to do much of
|
92
|
+
## anything.
|
93
|
+
# command: sh -l -c "bundle && echo \"Finished bundling now waiting...\" && tail -f /dev/null"
|
94
|
+
depends_on:
|
95
|
+
db:
|
96
|
+
condition: service_started
|
97
|
+
solr:
|
98
|
+
condition: service_started
|
99
|
+
fcrepo:
|
100
|
+
condition: service_started
|
101
|
+
redis:
|
102
|
+
condition: service_started
|
103
|
+
chrome:
|
104
|
+
condition: service_started
|
105
|
+
expose:
|
106
|
+
- 3000
|
107
|
+
|
108
|
+
redis:
|
109
|
+
image: redis:5
|
110
|
+
command: redis-server
|
111
|
+
volumes:
|
112
|
+
- redis:/data
|
113
|
+
networks:
|
114
|
+
internal:
|
115
|
+
|
116
|
+
chrome:
|
117
|
+
# password is 'secret'
|
118
|
+
image: selenium/standalone-chrome-debug:3.141.59-20201010
|
119
|
+
logging:
|
120
|
+
driver: none
|
121
|
+
volumes:
|
122
|
+
- /dev/shm:/dev/shm
|
123
|
+
shm_size: 3G
|
124
|
+
networks:
|
125
|
+
internal:
|
126
|
+
environment:
|
127
|
+
- JAVA_OPTS=-Dwebdriver.chrome.whitelistedIps=
|
128
|
+
- VIRTUAL_PORT=7900
|
129
|
+
- VIRTUAL_HOST=chrome.hyku.test
|
data/iiif_print.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
|
2
|
+
|
3
|
+
# version updated in one place:
|
4
|
+
require 'iiif_print/version'
|
5
|
+
|
6
|
+
# Gem description:
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'iiif_print'
|
9
|
+
spec.version = IiifPrint::VERSION
|
10
|
+
spec.authors = ['Sean Upton', 'Jacob Reed', 'Brian McBride',
|
11
|
+
'Eben English', 'Kirk Wang', 'LaRita Robinson', 'Jeremy Friesen']
|
12
|
+
spec.email = ['sean.upton@utah.edu', 'jacob.reed@utah.edu',
|
13
|
+
'brian.mcbride@utah.edu', 'eenglish@bpl.org', 'kirk.wang@scientist.com',
|
14
|
+
'larita@scientist.com', 'jeremy.n.friesen@gmail.com']
|
15
|
+
spec.homepage = 'https://github.com/samvera-labs/iiif_print'
|
16
|
+
spec.description = 'Gem/Engine for IIIF Print works in Hyrax-based Samvera Application.'
|
17
|
+
spec.summary = <<-SUMMARY
|
18
|
+
iiif_print is a Rails Engine gem providing model and administrative
|
19
|
+
functions to Hyrax-based Samvera applications, for management of
|
20
|
+
(primarily scanned) content.
|
21
|
+
SUMMARY
|
22
|
+
spec.license = 'Apache-2.0'
|
23
|
+
spec.files = `git ls-files`.split($OUTPUT_RECORD_SEPARATOR)
|
24
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
25
|
+
spec.add_dependency 'blacklight_iiif_search', '~> 1.0'
|
26
|
+
spec.add_dependency 'dry-monads', '~> 1.4.0'
|
27
|
+
spec.add_dependency 'hyrax', '>= 2.5', '< 4.0'
|
28
|
+
spec.add_dependency 'nokogiri', '>=1.13.2'
|
29
|
+
spec.add_dependency 'rails', '~> 5.0'
|
30
|
+
spec.add_dependency 'rdf-vocab', '~> 3.0'
|
31
|
+
|
32
|
+
spec.add_development_dependency 'bixby'
|
33
|
+
spec.add_development_dependency 'database_cleaner', '~> 1.3'
|
34
|
+
spec.add_development_dependency 'engine_cart', '~> 2.2'
|
35
|
+
spec.add_development_dependency "factory_bot", '~> 4.4'
|
36
|
+
spec.add_development_dependency 'fcrepo_wrapper', '~> 0.5', '>= 0.5.1'
|
37
|
+
spec.add_development_dependency 'newspaper_works_fixtures', '~> 0.3', '>=0.3.1'
|
38
|
+
spec.add_development_dependency 'rails-controller-testing', '~> 1'
|
39
|
+
spec.add_development_dependency 'rspec-rails', '~> 3.1'
|
40
|
+
spec.add_development_dependency 'rspec-activemodel-mocks'
|
41
|
+
spec.add_development_dependency 'shoulda-matchers', '~> 3.1'
|
42
|
+
spec.add_development_dependency 'solr_wrapper', '>= 1.1', '< 3.0'
|
43
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module IiifPrint
|
4
|
+
class AssetsGenerator < Rails::Generators::Base
|
5
|
+
desc "This generator installs the iiif_print CSS assets into your application"
|
6
|
+
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
|
9
|
+
def inject_css
|
10
|
+
copy_file "iiif_print.scss", "app/assets/stylesheets/iiif_print.scss"
|
11
|
+
end
|
12
|
+
|
13
|
+
def inject_js
|
14
|
+
return if iiif_print_js_installed?
|
15
|
+
insert_into_file 'app/assets/javascripts/application.js', after: '//= require hyrax' do
|
16
|
+
<<-JS.strip_heredoc
|
17
|
+
|
18
|
+
//= require iiif_print
|
19
|
+
JS
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def iiif_print_js_installed?
|
26
|
+
IO.read("app/assets/javascripts/application.js").include?('iiif_print')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# adds controller-scope behavior to the implementing application
|
2
|
+
require 'rails/generators'
|
3
|
+
|
4
|
+
module IiifPrint
|
5
|
+
class CatalogControllerGenerator < Rails::Generators::Base
|
6
|
+
desc "
|
7
|
+
This generator makes the following changes to your app:
|
8
|
+
1. Adds index fields in CatalogController
|
9
|
+
2. Adjusts Blacklight IIIF Search configuration settings in CatalogController
|
10
|
+
"
|
11
|
+
|
12
|
+
def add_index_fields_to_catalog_controller
|
13
|
+
marker = 'configure_blacklight do |config|'
|
14
|
+
inject_into_file 'app/controllers/catalog_controller.rb', after: marker do
|
15
|
+
"\n\n # IiifPrint index fields\n"\
|
16
|
+
" config.add_index_field 'all_text_tsimv', highlight: true, helper_method: :render_ocr_snippets\n"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def adjust_catalog_controller_all_text_config
|
21
|
+
gsub_file('app/controllers/catalog_controller.rb',
|
22
|
+
" full_text_field: 'text',",
|
23
|
+
" full_text_field: 'all_text_tsimv',")
|
24
|
+
end
|
25
|
+
|
26
|
+
def adjust_catalog_controller_is_page_of_config
|
27
|
+
gsub_file('app/controllers/catalog_controller.rb',
|
28
|
+
" object_relation_field: 'is_page_of_s',",
|
29
|
+
" object_relation_field: 'is_page_of_ssim',")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module IiifPrint
|
4
|
+
# Install Generator Class
|
5
|
+
# rubocop:disable Metrics/ClassLength
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
|
9
|
+
def copy_migrations
|
10
|
+
rake "iiif_print:install:migrations"
|
11
|
+
end
|
12
|
+
|
13
|
+
def verify_biiif_installed
|
14
|
+
return if IO.read('app/controllers/catalog_controller.rb').include?('include BlacklightIiifSearch::Controller')
|
15
|
+
say_status('info',
|
16
|
+
'BLACKLIGHT IIIF SEARCH NOT INSTALLED; INSTALLING BLACKLIGHT IIIF SEARCH',
|
17
|
+
:blue)
|
18
|
+
generate 'blacklight_iiif_search:install'
|
19
|
+
end
|
20
|
+
|
21
|
+
def catalog_controller_configuration
|
22
|
+
generate 'iiif_print:catalog_controller'
|
23
|
+
end
|
24
|
+
|
25
|
+
def inject_configuration
|
26
|
+
copy_file 'config/initializers/iiif_print.rb'
|
27
|
+
end
|
28
|
+
|
29
|
+
def inject_assets
|
30
|
+
generate 'iiif_print:assets'
|
31
|
+
end
|
32
|
+
|
33
|
+
# Blacklight IIIF Search generator has some linting that does not agree with CircleCI on Hyku
|
34
|
+
# ref https://github.com/boston-library/blacklight_iiif_search/blob/v1.0.0/lib/generators/blacklight_iiif_search/controller_generator.rb
|
35
|
+
# the follow two methods does a clean up to appease Rubocop
|
36
|
+
def lint_catalog_controller
|
37
|
+
file = "app/controllers/catalog_controller.rb"
|
38
|
+
contents = File.read(file)
|
39
|
+
contents.gsub!(/\n\s*\n\s*# IiifPrint index fields/, "\n # IiifPrint index fields")
|
40
|
+
contents.gsub!(/\n\s*\n\s*# configuration for Blacklight IIIF Content Search/, "\n\n # configuration for Blacklight IIIF Content Search")
|
41
|
+
File.write(file, contents)
|
42
|
+
end
|
43
|
+
|
44
|
+
# ref https://github.com/boston-library/blacklight_iiif_search/blob/v1.0.0/lib/generators/blacklight_iiif_search/templates/iiif_search_builder.rb
|
45
|
+
def lint_iiif_search_builder
|
46
|
+
file = "app/models/iiif_search_builder.rb"
|
47
|
+
contents = File.read(file)
|
48
|
+
contents.insert(0, "# frozen_string_literal: true\n\n")
|
49
|
+
File.write(file, contents)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
IiifPrint.config do |config|
|
2
|
+
# NOTE: WorkTypes and models are used synonymously here.
|
3
|
+
# Add models to be excluded from search so the user
|
4
|
+
# would not see them in the search results.
|
5
|
+
# by default, use the human readable versions like:
|
6
|
+
# @example
|
7
|
+
# # config.excluded_model_name_solr_field_values = ['Generic Work', 'Image']
|
8
|
+
#
|
9
|
+
# config.excluded_model_name_solr_field_values = []
|
10
|
+
|
11
|
+
# Add configurable solr field key for searching,
|
12
|
+
# default key is: 'human_readable_type_sim'
|
13
|
+
# if another key is used, make sure to adjust the
|
14
|
+
# config.excluded_model_name_solr_field_values to match
|
15
|
+
# @example
|
16
|
+
# config.excluded_model_name_solr_field_key = 'some_solr_field_key'
|
17
|
+
|
18
|
+
# Configure how the manifest sorts the canvases, by default it sorts by :title,
|
19
|
+
# but a different model property may be desired such as :date_published
|
20
|
+
# @example
|
21
|
+
# config.sort_iiif_manifest_canvases_by = :date_published
|
22
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
@import 'iiif_print/iiif_print';
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module IiifPrint
|
2
|
+
# Base type for IiifPrint derivative services
|
3
|
+
class BaseDerivativeService
|
4
|
+
attr_reader :file_set, :master_format
|
5
|
+
delegate :uri, to: :file_set
|
6
|
+
|
7
|
+
class_attribute :target_extension, default: nil
|
8
|
+
|
9
|
+
def initialize(file_set)
|
10
|
+
@file_set = file_set
|
11
|
+
@dest_path = nil
|
12
|
+
@source_path = nil
|
13
|
+
@source_meta = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
##
|
17
|
+
# We assume that for the file set's parent that this is an acceptable plugin. Now, we ask for
|
18
|
+
# this specific file_set is it valid. For example, we would not attempt to extract text from a
|
19
|
+
# movie even though the parent work says to attempt to extract text on any attached file sets.
|
20
|
+
# Put another way, we can upload a PDF or a Movie to the parent.
|
21
|
+
#
|
22
|
+
# In subclass, you'll want to consider the attributes of the file_set and whether that subclass
|
23
|
+
# should process the given file_set.
|
24
|
+
#
|
25
|
+
# @see IiifPrint::PluggableDerivativeService#plugins_for
|
26
|
+
# @return [Boolean]
|
27
|
+
def valid?
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
def derivative_path_factory
|
32
|
+
Hyrax::DerivativePath
|
33
|
+
end
|
34
|
+
|
35
|
+
# prepare full path for passed extension/destination name, return path
|
36
|
+
def prepare_path(extension)
|
37
|
+
dest_path = derivative_path_factory.derivative_path_for_reference(
|
38
|
+
@file_set,
|
39
|
+
extension
|
40
|
+
)
|
41
|
+
dir = File.join(dest_path.split('/')[0..-2])
|
42
|
+
FileUtils.mkdir_p(dir) unless Dir.exist?(dir)
|
43
|
+
dest_path
|
44
|
+
end
|
45
|
+
|
46
|
+
# calculate and ensure directory components for singular @dest_path
|
47
|
+
# should only be used by subclasses producing a single derivative
|
48
|
+
def load_destpath
|
49
|
+
@dest_path = prepare_path(target_extension)
|
50
|
+
end
|
51
|
+
|
52
|
+
def identify
|
53
|
+
return @source_meta unless @source_meta.nil?
|
54
|
+
@source_meta = IiifPrint::ImageTool.new(@source_path).metadata
|
55
|
+
end
|
56
|
+
|
57
|
+
def mime_type
|
58
|
+
identify[:content_type]
|
59
|
+
end
|
60
|
+
|
61
|
+
def use_color?
|
62
|
+
identify[:color] == 'color'
|
63
|
+
end
|
64
|
+
|
65
|
+
# is source one-bit monochrome?
|
66
|
+
def one_bit?
|
67
|
+
identify[:color] == 'monochrome'
|
68
|
+
end
|
69
|
+
|
70
|
+
def create_derivatives(filename)
|
71
|
+
# presuming that filename is full path to source file
|
72
|
+
@source_path = filename
|
73
|
+
|
74
|
+
# Get destination path from Hyrax for file extension defined in
|
75
|
+
# self.target_extension constant on respective derivative service subclass.
|
76
|
+
load_destpath
|
77
|
+
end
|
78
|
+
|
79
|
+
def cleanup_derivatives(extension = target_extension, *_args)
|
80
|
+
derivative_path_factory.derivatives_for_reference(file_set).each do |path|
|
81
|
+
FileUtils.rm_f(path) if path.ends_with?(extension)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def jp2_to_intermediate
|
86
|
+
intermediate_path = File.join(Dir.mktmpdir, 'intermediate.tif')
|
87
|
+
jp2_cmd = "opj_decompress -i #{@source_path} -o #{intermediate_path}"
|
88
|
+
# make intermediate, then...
|
89
|
+
`#{jp2_cmd}`
|
90
|
+
intermediate_path
|
91
|
+
end
|
92
|
+
|
93
|
+
def convert_cmd
|
94
|
+
raise NotImplementedError, 'Calling subclass missing convert_cmd method'
|
95
|
+
end
|
96
|
+
|
97
|
+
# convert non-JP2 source/primary file to PDF derivative with ImageMagick6
|
98
|
+
# calls convert_cmd on calling subclasses
|
99
|
+
def im_convert
|
100
|
+
`#{convert_cmd}`
|
101
|
+
end
|
102
|
+
|
103
|
+
# convert JP2 source/primary file to PDF derivative, via
|
104
|
+
# opj_decompress to intermediate TIFF, then ImageMagick6 convert
|
105
|
+
def jp2_convert
|
106
|
+
# jp2 source -> intermediate
|
107
|
+
intermediate_path = jp2_to_intermediate
|
108
|
+
@source_path = intermediate_path
|
109
|
+
# intermediate -> PDF
|
110
|
+
im_convert
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# customize behavior for IiifSearch
|
2
|
+
module IiifPrint
|
3
|
+
module BlacklightIiifSearch
|
4
|
+
module AnnotationDecorator
|
5
|
+
##
|
6
|
+
# Create a URL for the annotation
|
7
|
+
# use a Hyrax-y URL syntax:
|
8
|
+
# protocol://host:port/concern/model_type/work_id/manifest/canvas/file_set_id/annotation/index
|
9
|
+
# @return [String]
|
10
|
+
def annotation_id
|
11
|
+
"#{base_url}/manifest/canvas/#{file_set_id}/annotation/#{hl_index}"
|
12
|
+
end
|
13
|
+
|
14
|
+
##
|
15
|
+
# Create a URL for the canvas that the annotation refers to
|
16
|
+
# match the Hyrax default canvas URL syntax:
|
17
|
+
# protocol://host:port/concern/model_type/work_id/manifest/canvas/file_set_id
|
18
|
+
# @return [String]
|
19
|
+
def canvas_uri_for_annotation
|
20
|
+
"#{base_url}/manifest/canvas/#{file_set_id}#{coordinates}"
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
##
|
26
|
+
# return a string like "#xywh=100,100,250,20"
|
27
|
+
# corresponding to coordinates of query term on image
|
28
|
+
# @return [String]
|
29
|
+
def coordinates
|
30
|
+
return default_coords if query.blank?
|
31
|
+
coords_json = fetch_and_parse_coords
|
32
|
+
return default_coords unless coords_json && coords_json['coords']
|
33
|
+
query_terms = query.split(' ').map(&:downcase)
|
34
|
+
matches = coords_json['coords'].select do |k, _v|
|
35
|
+
k.downcase =~ /(#{query_terms.join('|')})/
|
36
|
+
end
|
37
|
+
return default_coords if matches.blank?
|
38
|
+
coords_array = matches.values.flatten(1)[hl_index]
|
39
|
+
return default unless coords_array
|
40
|
+
"#xywh=#{coords_array.join(',')}"
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# return the JSON word-coordinates file contents
|
45
|
+
# @return [JSON]
|
46
|
+
def fetch_and_parse_coords
|
47
|
+
coords = IiifPrint::Data::WorkDerivatives.data(from: file_set_id, of_type: 'json')
|
48
|
+
return nil if coords.blank?
|
49
|
+
begin
|
50
|
+
JSON.parse(coords)
|
51
|
+
rescue JSON::ParserError
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# a default set of coordinates
|
58
|
+
# @return [String]
|
59
|
+
def default_coords
|
60
|
+
'#xywh=0,0,0,0'
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# the base URL for the Newspaper object
|
65
|
+
# use polymorphic_url, since we deal with multiple object types
|
66
|
+
# @return [String]
|
67
|
+
def base_url
|
68
|
+
host = controller.request.base_url
|
69
|
+
controller.polymorphic_url(parent_document, host: host, locale: nil)
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# return the first file set id
|
74
|
+
# @return [String]
|
75
|
+
def file_set_id
|
76
|
+
return document['id'] if document.file_set?
|
77
|
+
|
78
|
+
file_set_ids = document['file_set_ids_ssim']
|
79
|
+
raise "#{self.class}: NO FILE SET ID" if file_set_ids.blank?
|
80
|
+
file_set_ids.first
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'hyrax/catalog_search_builder'
|
2
|
+
|
3
|
+
module IiifPrint
|
4
|
+
# This class extends the base Hyrax::CatalogSearchBuilder by:
|
5
|
+
#
|
6
|
+
# - supporting highlighting of snippets in results
|
7
|
+
# - excluding models from search result; with complex works you might want to skip some of those
|
8
|
+
# works.
|
9
|
+
class CatalogSearchBuilder < Hyrax::CatalogSearchBuilder
|
10
|
+
# TODO: Do we need the following as a module? It hides the behavior
|
11
|
+
include IiifPrint::HighlightSearchParams
|
12
|
+
# TODO: Do we need the following as a module? It hides the behavior
|
13
|
+
include IiifPrint::ExcludeModels
|
14
|
+
|
15
|
+
# NOTE: If you are using advanced_search, the :exclude_models and :highlight_search_params must
|
16
|
+
# be added after the advanced_search methods (which are not part of this gem). In other tests,
|
17
|
+
# we found that having the advanced search processing after the two aforementioned processors
|
18
|
+
# resulted in improper evaluation of keyword querying.
|
19
|
+
self.default_processor_chain += [:exclude_models, :highlight_search_params, :show_parents_only]
|
20
|
+
|
21
|
+
# rubocop:enable Naming/PredicateName
|
22
|
+
def show_parents_only(solr_parameters)
|
23
|
+
query = if blacklight_params["include_child_works"] == 'true'
|
24
|
+
ActiveFedora::SolrQueryBuilder.construct_query(is_child_bsi: 'true')
|
25
|
+
else
|
26
|
+
ActiveFedora::SolrQueryBuilder.construct_query(is_child_bsi: nil)
|
27
|
+
end
|
28
|
+
solr_parameters[:fq] += [query]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module IiifPrint
|
2
|
+
class Configuration
|
3
|
+
attr_writer :after_create_fileset_handler
|
4
|
+
|
5
|
+
# @param file_set [FileSet]
|
6
|
+
# @param user [User]
|
7
|
+
def handle_after_create_fileset(file_set, user)
|
8
|
+
if defined? @after_create_fileset_handler
|
9
|
+
@after_create_fileset_handler.call(file_set, user)
|
10
|
+
else
|
11
|
+
IiifPrint::Data.handle_after_create_fileset(file_set, user)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_writer :excluded_model_name_solr_field_values
|
16
|
+
# By default, this uses an array of human readable types
|
17
|
+
# ex: ['Generic Work', 'Image']
|
18
|
+
# @return [Array<String>]
|
19
|
+
def excluded_model_name_solr_field_values
|
20
|
+
return @excluded_model_name_solr_field_values unless @excluded_model_name_solr_field_values.nil?
|
21
|
+
@excluded_model_name_solr_field_values = []
|
22
|
+
end
|
23
|
+
|
24
|
+
# This method wraps Hyrax's configuration so we can sniff out the correct method to use. The
|
25
|
+
# {Hyrax::Configuration#whitelisted_ingest_dirs} is deprecated in favor of
|
26
|
+
# {Hyrax::Configuration#registered_ingest_dirs}.
|
27
|
+
#
|
28
|
+
# @return [Array<String>]
|
29
|
+
def registered_ingest_dirs
|
30
|
+
if Hyrax.config.respond_to?(:registered_ingest_dirs)
|
31
|
+
Hyrax.config.registered_ingest_dirs
|
32
|
+
else
|
33
|
+
Hyrax.config.whitelisted_ingest_dirs
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
attr_writer :excluded_model_name_solr_field_key
|
38
|
+
# A string of a solr field key
|
39
|
+
# @return [String]
|
40
|
+
def excluded_model_name_solr_field_key
|
41
|
+
return "human_readable_type_sim" unless defined?(@excluded_model_name_solr_field_key)
|
42
|
+
@excluded_model_name_solr_field_key
|
43
|
+
end
|
44
|
+
|
45
|
+
attr_writer :default_iiif_manifest_version
|
46
|
+
def default_iiif_manifest_version
|
47
|
+
@default_iiif_manifest_version || 2
|
48
|
+
end
|
49
|
+
|
50
|
+
attr_writer :metadata_fields
|
51
|
+
# rubocop:disable Metrics/MethodLength
|
52
|
+
# @api private
|
53
|
+
# @note These fields will appear in rendering order.
|
54
|
+
# @todo To move this to an `@api public` state, we need to consider what a proper configuration looks like.
|
55
|
+
def metadata_fields
|
56
|
+
@metadata_fields ||= {
|
57
|
+
title: {},
|
58
|
+
description: {},
|
59
|
+
collection: {},
|
60
|
+
abstract: {},
|
61
|
+
date_modified: {},
|
62
|
+
creator: { render_as: :faceted },
|
63
|
+
contributor: { render_as: :faceted },
|
64
|
+
subject: { render_as: :faceted },
|
65
|
+
publisher: { render_as: :faceted },
|
66
|
+
language: { render_as: :faceted },
|
67
|
+
identifier: { render_as: :linked },
|
68
|
+
keyword: { render_as: :faceted },
|
69
|
+
date_created: { render_as: :linked },
|
70
|
+
based_near_label: {},
|
71
|
+
related_url: { render_as: :external_link },
|
72
|
+
resource_type: { render_as: :faceted },
|
73
|
+
source: {},
|
74
|
+
extent: {},
|
75
|
+
rights_statement: { render_as: :rights_statement },
|
76
|
+
rights_notes: {},
|
77
|
+
access_right: {},
|
78
|
+
license: { render_as: :license },
|
79
|
+
searchable_text: {}
|
80
|
+
}
|
81
|
+
end
|
82
|
+
# rubocop:enable Metrics/MethodLength
|
83
|
+
|
84
|
+
attr_writer :sort_iiif_manifest_canvases_by
|
85
|
+
def sort_iiif_manifest_canvases_by
|
86
|
+
@sort_iiif_manifest_canvases_by || :title
|
87
|
+
end
|
88
|
+
|
89
|
+
attr_writer :additional_tessearct_options
|
90
|
+
##
|
91
|
+
# The additional options to pass to the Tesseract configuration
|
92
|
+
#
|
93
|
+
# @see https://tesseract-ocr.github.io/tessdoc/Command-Line-Usage.html
|
94
|
+
# @return [String]
|
95
|
+
def additional_tessearct_options
|
96
|
+
@additional_tessearct_options || ""
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module IiifPrint
|
2
|
+
module Data
|
3
|
+
# Mixin module for fileset methods for work, presumes an @work
|
4
|
+
# instance attribute refering to a work object
|
5
|
+
module FilesetHelper
|
6
|
+
def fileset_id
|
7
|
+
# if context is itself a string, presume it is a file set id
|
8
|
+
return @work if @work.is_a? String
|
9
|
+
# if context is not a String, presume a work or fileset context:
|
10
|
+
fileset.nil? ? nil : fileset.id
|
11
|
+
end
|
12
|
+
|
13
|
+
def first_fileset
|
14
|
+
# if context is fileset id (e.g. caller is view partial) string,
|
15
|
+
# get the fileset from that id
|
16
|
+
return FileSet.find(@work) if @work.is_a?(String)
|
17
|
+
# if "work" context is a FileSet, not actual work, return it
|
18
|
+
return @work if @work.is_a? FileSet
|
19
|
+
# in most cases, get from work's members:
|
20
|
+
filesets = @work.members.select { |m| m.is_a? FileSet }
|
21
|
+
filesets.empty? ? nil : filesets[0]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|