Documentation: Islandora 'Large Image' workflow

Created on 27 Mar 2017  路  37Comments  路  Source: Islandora/documentation

Meta ticket to handle all of our 'large image' needs.

  • [x] Add OpenJPEG Support to Imagemagick in Vagrant install. Pull.
  • [x] Add IIIF server back to install. Pull
  • [x] Create API-X Silex middleware Ticket
  • [x] Develop image micro service. Ticket
  • [x] Add ability to add TIFF NonRdfSources
  • [x] Add ability to add JP2 NonRdfSources
  • [ ] Serve JP2s from IIIF
  • [x] Add a 'deep zoom' viewer (e.g. OpenSeaDragon) as a Media provider for JP2 NonRdfSources
Crayfish MVP Vagrant drupal

Most helpful comment

openseadragon2

All 37 comments

We should be able to replace our IIIF image server with whatever image server we choose in the future. But the _default_ Islandora install should use one that doesn't require Kakadu to function. That keeps our licensing easier, and makes sure that we have a fully open source option, even if people choose to deploy in another way.

That narrows down the possible options for a IIIF server substantially.

  • IIP Image

    • C++

    • Can be built against either: JPEG2000 (open) or Kakadu (commercial).

  • digilib

    • Java

    • Uses the java image library for image manipulations

  • Cantaloupe

    • Java (In contatiner)

    • Two decoding options: Kakadu and OpenJPEG.

Loris-redux removed as it isn't complete.

Based on this I'm thinking we should use IIPImage as our default in vagrant. Anyone have any other options I missed? Thoughts?

Having looked at the three, I'm inclined to agree with you on IIP Image, and if that doesn't pan out, try digilib. I'd shy away from LORIS-redux, seems to have WIP warnings aplenty.

This also seems like it may be fairly useful:
https://www.drupal.org/project/mirador

That does indeed look useful. I wonder how well that would play with the Media entity thing we've got going on. Definitely worth investigating.

Quick look at the code reveals it's a field formatter, which _should_ be useable on a media entity no problem. This looks promising.

Thus far my attempts to get IIP going with OpenJPEG are meeting with failure. I made a ticket above to see if they had any troubleshooting ideas. I'm going to abandon IIP for now and try using Cantaloupe.

@dannylamb @jonathangreen we need to add islandora_image to claw_vagrant, right? If so, I'm happy to take care of that after https://github.com/Islandora-CLAW/islandora/pull/53 and https://github.com/Islandora-CLAW/islandora_image/pull/11 land.

Islandora-CLAW/CLAW#618 added the ability to ingest TIFFs and JP2s, resolving two more check boxes on that list.

I have an OpenSeadragon module.

To test inside a claw_vagrant you need to:

  1. cd /var/www/html/drupal/web/modules/contrib
  2. git clone https://github.com/whikloj/openseadragon.git
  3. cd openseadragon
  4. drupal module:install openseadragon

    • This will prompt you to install a version of libraries, there is only one option so use it.

  5. cp openseadragon.json /var/www/html/drupal/web/sites/default/files/library-definitions/
  6. cd /var/www/html/drupal/web/sites
  7. mkdir -p all/assets/vendor
  8. cd all/assets/vendor
  9. wget "https://github.com/openseadragon/openseadragon/releases/download/v2.2.1/openseadragon-bin-2.2.1.tar.gz"
  10. tar xf openseadragon-bin-2.2.1.tar.gz
  11. mv openseadragon-bin-2.2.1 openseadragon
  12. Edit /etc/default/tomcat8, change the last line to CATALINA_OPTS="${CATALINA_OPTS} -Dcantaloupe.config=/opt/cantaloupe/cantaloupe.properties -Dorg.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true"
  13. Restart tomcat sudo service tomcat8 restart

Now for Cantaloupe. Edit the /opt/cantaloupe/cantaloupe.properties file.

At line 110, you want

resolver.static = FilesystemResolver

At line 129, you want

FilesystemResolver.BasicLookupStrategy.path_prefix = /var/www/html/drupal/web/

Close and save the file.

Now in Drupal, go to Administration -> Structure -> Media Bundles.

Beside JP2 choose the down arrow and select Manage Display.

I'd remove all the fields except File and for the format choose OpenSeadragon, don't forget to save.
media_bundle1

Then go to Administration -> Configuration -> Media -> OpenSeadragon Settings

Set the IIIF Image server location to http://localhost:8080/cantaloupe/iiif/2.
There is some validation on this field. But something better is probably needed.

The OpenSeadragon settings can be set or leave as default. Save the form.
openseadragon1

Create a new Islandora Image object, add a title, add a JP2 to the JP2 field. Save and publish.

:crossed_fingers: See an image in Openseadragon?

openseadragon2

:+1: @whikloj++ I'll give this a whirl after I'm done testing https://github.com/Islandora-CLAW/claw_vagrant/pull/46

@dannylamb I'm working on a PR to add this to claw_vagrant. Should I transfer this over to Islandora-CLAW now or would you like to look at it first?

By "this" I meant, transfer https://github.com/whikloj/openseadragon to the Islandora-CLAW organization?

@whikloj only if @manez comes up with an adorable cuddly mascot!

@whikloj I was just going to install it myself, but I'll definitely take the claw_vagrant PR :+1:

Let me look over the module first and then we'll transfer.

@dannylamb give me a couple of seconds, I think I have it mostly worked out.

That should be _minutes_, I need to do a vagrant destroy; vagrant up to test

@whikloj So I've got a few comments. But since there's no PR it's a bit hard to review. So i'm just gonna dump it here:

@dannylamb ok, I can do 1 and 2.

I did think about tests, but right now I don't even have a good (non-deprecated) way to check the library version. So if you have the wrong library or your cantaloupe is not installed correctly. So much could be wrong.

I could use the template and javascript to add a hidden tag, sort of a <span class="a-ok"/> thing to look for. But I'm not sure if that is really verifying anything.

@whikloj Well let's do 1 and 2 and then I guess 3 falls squarely into my end-to-end integration test wishlist.

Definitely seems like an end-to-end test, but wouldn't it be enough in that test to retrieve a single image tile and check it against a rubric?

Followed the steps for openseadragon. Seems to install ok. Shows up as a format option. But it does not render the viewer or the image.

How I can verify that http://localhost:8080/cantaloupe/iiif is working properly. As there are some other issues related to the image bundle, I'll re-test this again at a later time.

@Natkeeran, @dannylamb pointed out that I had missed a step (or two) in my testing instructions. I have fixed them now so probably have to go back up and perform steps 12 & 13.

But I'm still having intermittent luck with OpenJpeg. You might be better off to follow the same steps above but make OpenSeadragon the viewer for your OBJ media bundle and upload a Tiff.

Oh, I forgot there is more. You may want to wait. But if not.
You need to go to Configuration -> Structure -> Content-Type -> Islandora Image
Go to Manage display and set OBJ and JP2 to a _format_ of Rendered entity.

@dannylamb @Natkeeran
I have made a branch of claw_vagrant which loads the openseadragon module and libraries.
https://github.com/whikloj/claw_vagrant/tree/issue-572
You can use that to test.

I haven't made a PR yet as I still need to have claw_vagrant update the default Islandora configuration to use OpenSeadragon for JP2s.

@dannylamb I have no idea how to write a file for unit testing this FileInformation class. I need to have a reference to a file so it can be file_loaded inside. If you have a suggestion, I am happy to hear it.

So I think I need to generate a media entity so I can reference it from the Entity so I can pass it into the method, maybe I'll switch the method back to just taking a Drupal\file\Entity\File which still means I need to access the file, but then I don't need to mess with the Entity and Media Bundles anymore.

@dannylamb forget my previous whining, I took my advice and altered the FileInformation class to operate on a File, which made it easier to mock up. I have added a fairly simple test to the module and I added the mime-type mappings for JP2 and Tiff to openseadragon as they are required to allow the image to display.

Last piece is probably a .travis.yml file. Not sure if I should copy from the Islandora examples or do something more generic.

I haven't been able to figure out how to export and import the config to alter to use openseadragon. I don't really want to depend on openseadragon in the individual modules. So I'll keep playing around and if I can figure it out then we can have claw_vagrant auto-configure JP2 to use OpenSeadragon.

So maybe test it out with my issue-572 branch (https://github.com/whikloj/claw_vagrant/tree/issue-572) and see what you think is missing.

@whikloj++ vagrant up

@whikloj I just tested it and it works fine for Tiffs, but not for JP2. Just getting a black screen and this gem in the logs:

2017-06-22 15:17:33,960 INFO [http-nio-8080-exec-3] e.i.l.c.r.AbstractResource [AbstractResource.java:231] doInit(): handling GET http://localhost:8080/cantaloupe/iiif/2/sites%2Fdefault%2Ffiles%2F2017-06%2FTC_NG_Tokyo_JP_Geo.jp2
2017-06-22 15:17:33,966 DEBUG [http-nio-8080-exec-3] e.i.l.c.r.AbstractResource [AbstractResource.java:192] Base URI assembled from request: http://localhost:8080/cantaloupe
2017-06-22 15:17:34,266 INFO [http-nio-8080-exec-10] e.i.l.c.r.AbstractResource [AbstractResource.java:231] doInit(): handling GET http://localhost:8080/cantaloupe/iiif/2/sites%2Fdefault%2Ffiles%2F2017-06%2FTC_NG_Tokyo_JP_Geo.jp2/full/17,/0/default.jpg
2017-06-22 15:17:34,288 INFO [http-nio-8080-exec-10] e.i.l.c.r.SourceImageWrangler [SourceImageWrangler.java:117] FileResolver -> FileProcessor connection between FilesystemResolver and OpenJpegProcessor
2017-06-22 15:17:34,297 INFO [http-nio-8080-exec-10] e.i.l.c.r.FilesystemResolver [FilesystemResolver.java:89] Resolved sites/default/files/2017-06/TC_NG_Tokyo_JP_Geo.jp2 to /var/www/html/drupal/web/sites/default/files/2017-06/TC_NG_Tokyo_JP_Geo.jp2
2017-06-22 15:17:34,304 INFO [http-nio-8080-exec-10] e.i.l.c.p.OpenJpegProcessor [OpenJpegProcessor.java:213] Invoking /opt/openjpeg/bin/opj_dump -i /var/www/html/drupal/web/sites/default/files/2017-06/TC_NG_Tokyo_JP_Geo.jp2
2017-06-22 15:17:34,403 DEBUG [http-nio-8080-exec-10] e.i.l.c.r.AbstractResource [AbstractResource.java:648] readInfo(): read from sites/default/files/2017-06/TC_NG_Tokyo_JP_Geo.jp2 in 99 msec
2017-06-22 15:17:34,406 DEBUG [http-nio-8080-exec-10] e.i.l.c.r.AbstractResource [AbstractResource.java:449] checkAuthorization(): delegate script is disabled; allowing.
2017-06-22 15:17:34,408 DEBUG [http-nio-8080-exec-10] e.i.l.c.r.AbstractResource [AbstractResource.java:272] addNonEndpointOperations(): redactions are disabled; skipping.
2017-06-22 15:17:34,410 DEBUG [http-nio-8080-exec-10] e.i.l.c.r.AbstractResource [AbstractResource.java:328] addNonEndpointOperations(): overlays are disabled; skipping.
2017-06-22 15:17:34,428 DEBUG [http-nio-8080-exec-10] e.i.l.c.r.AbstractResource [AbstractResource.java:192] Base URI assembled from request: http://localhost:8080/cantaloupe
2017-06-22 15:17:34,444 DEBUG [http-nio-8080-exec-10] e.i.l.c.r.AbstractResource [AbstractResource.java:648] readInfo(): read from sites/default/files/2017-06/TC_NG_Tokyo_JP_Geo.jp2 in 15 msec
2017-06-22 15:17:34,498 INFO [http-nio-8080-exec-10] e.i.l.c.p.OpenJpegProcessor [OpenJpegProcessor.java:252] Invoking /opt/openjpeg/bin/opj_decompress -i /var/www/html/drupal/web/sites/default/files/2017-06/TC_NG_Tokyo_JP_Geo.jp2 -r 5 -o /tmp/tomcat8-tomcat8-tmp/cantaloupe-45d0cd08-5195-468d-b139-20d558b1de09.bmp
2017-06-22 15:17:34,500 DEBUG [http-nio-8080-exec-10] e.i.l.c.p.i.AbstractImageReader [AbstractImageReader.java:116] createReader(): ignoring metadata? true
2017-06-22 15:17:34,516 DEBUG [http-nio-8080-exec-10] e.i.l.c.p.i.AbstractImageReader [AbstractImageReader.java:121] createReader(): using com.sun.media.imageioimpl.plugins.bmp.BMPImageReader
2017-06-22 15:17:35,302 ERROR [http-nio-8080-exec-10] o.r.C.Server [Slf4jLogger.java:230] An exception occurred writing the response entity
java.io.IOException: java.lang.IllegalArgumentException: Invalid magic value for BMP file.

@dannylamb Can I try that JP2, I still get this type of error for a small 1 bit JP2 of mine, but the rest seem to work so perhaps the concern about OpenJpeg being twitchy about JP2 produced by other software is valid. :man_shrugging:

@whikloj I'm testing with http://www.terracolor.net/download/tc_ng_tokyo_jp_jp2.zip. It's 20 MB, so I had to bump the max upload size in apache's php.ini.

@whikloj And as a follow up, I'll generate a JP2 using Houdini and see how that goes.

@dannylamb cool, I'm just rebuilding a fresh vagrant with my issue-572 branch and then I'll see what I can figure out.

Hrm.. getting a black screen with a different error message after uploading a jp2 i generated with this tiff. I went to go see if it was a config thing and got the WSOD at admin/config/media/openseadragon:

[Thu Jun 22 16:48:46.638433 2017] [:error] [pid 13519] [client 10.0.2.2:48308] Error: Call to a member function get() on null in /var/www/html/drupal/web/modules/contrib/openseadragon/src/Form/OpenSeadragonSettingsForm.php on line 95 #0 [internal function]: Drupal\\openseadragon\\Form\\OpenSeadragonSettingsForm->buildForm(Array, Object(Drupal\\Core\\Form\\FormState))\n#1 /var/www/html/drupal/web/core/lib/Drupal/Core/Form/FormBuilder.php(514): call_user_func_array(Array, Array)\n#2 /var/www/html/drupal/web/core/lib/Drupal/Core/Form/FormBuilder.php(271): Drupal\\Core\\Form\\FormBuilder->retrieveForm('openseadragon.a...', Object(Drupal\\Core\\Form\\FormState))\n#3 /var/www/html/drupal/web/core/lib/Drupal/Core/Controller/FormController.php(74): Drupal\\Core\\Form\\FormBuilder->buildForm('openseadragon.a...', Object(Drupal\\Core\\Form\\FormState))\n#4 [internal function]: Drupal\\Core\\Controller\\FormController->getContentResult(Object(Symfony\\Component\\HttpFoundation\\Request), Object(Drupal\\Core\\Routing\\RouteMatch))\n#5 /var/www/html/drupal/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array)\n#6 /var/www/html/drupal/web/core/lib/Drupal/Core/Render/Renderer.php(574): Drupal\\Core\\EventSubscriber\\EarlyRenderingControllerWrapperSubscriber->Drupal\\Core\\EventSubscriber\\{closure}()\n#7 /var/www/html/drupal/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(124): Drupal\\Core\\Render\\Renderer->executeInRenderContext(Object(Drupal\\Core\\Render\\RenderContext), Object(Closure))\n#8 /var/www/html/drupal/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\\Core\\EventSubscriber\\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array)\n#9 [internal function]: Drupal\\Core\\EventSubscriber\\EarlyRenderingControllerWrapperSubscriber->Drupal\\Core\\EventSubscriber\\{closure}()\n#10 /var/www/html/drupal/vendor/symfony/http-kernel/HttpKernel.php(144): call_user_func_array(Object(Closure), Array)\n#11 /var/www/html/drupal/vendor/symfony/http-kernel/HttpKernel.php(64): Symfony\\Component\\HttpKernel\\HttpKernel->handleRaw(Object(Symfony\\Component\\HttpFoundation\\Request), 1)\n#12 /var/www/html/drupal/web/core/lib/Drupal/Core/StackMiddleware/Session.php(57): Symfony\\Component\\HttpKernel\\HttpKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#13 /var/www/html/drupal/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\\Core\\StackMiddleware\\Session->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#14 /var/www/html/drupal/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(99): Drupal\\Core\\StackMiddleware\\KernelPreHandle->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#15 /var/www/html/drupal/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(78): Drupal\\page_cache\\StackMiddleware\\PageCache->pass(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#16 /var/www/html/drupal/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Drupal\\page_cache\\StackMiddleware\\PageCache->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#17 /var/www/html/drupal/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(50): Drupal\\Core\\StackMiddleware\\ReverseProxyMiddleware->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#18 /var/www/html/drupal/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\\Core\\StackMiddleware\\NegotiationMiddleware->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#19 /var/www/html/drupal/web/core/lib/Drupal/Core/DrupalKernel.php(656): Stack\\StackedHttpKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request), 1, true)\n#20 /var/www/html/drupal/web/index.php(19): Drupal\\Core\\DrupalKernel->handle(Object(Symfony\\Component\\HttpFoundation\\Request))\n#21 {main}, referer: http://localhost:8000/admin/config

Follow up from IRC: We're going to take what works with Tiffs and put off JP2 support for later.

@whikloj @jonathangreen Given that we've got everything checked off but JP2 support, and we've decided to put JP2s on hold for a bit, I think we're good to close this for now.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ruebot picture ruebot  路  4Comments

akuckartz picture akuckartz  路  3Comments

DiegoPino picture DiegoPino  路  5Comments

acoburn picture acoburn  路  4Comments

ruebot picture ruebot  路  3Comments