{"id":13551201,"url":"https://github.com/go-iiif/go-iiif","last_synced_at":"2026-01-14T18:18:29.269Z","repository":{"id":43330115,"uuid":"67228421","full_name":"go-iiif/go-iiif","owner":"go-iiif","description":"Go package to implement the IIIF Image API.","archived":false,"fork":false,"pushed_at":"2025-08-13T18:42:04.000Z","size":242155,"stargazers_count":96,"open_issues_count":50,"forks_count":11,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-11-22T17:20:45.390Z","etag":null,"topics":["iiif","iiif-image"],"latest_commit_sha":null,"homepage":"https://go-iiif.github.io/go-iiif/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/go-iiif.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2016-09-02T14:16:38.000Z","updated_at":"2025-10-13T03:12:49.000Z","dependencies_parsed_at":"2023-12-13T01:34:47.441Z","dependency_job_id":"f51b3e2c-5a65-4a45-b5ac-429bfc4f0934","html_url":"https://github.com/go-iiif/go-iiif","commit_stats":{"total_commits":621,"total_committers":16,"mean_commits":38.8125,"dds":0.536231884057971,"last_synced_commit":"7563cea0c24d074565e2d54dc831ed2e4028a40a"},"previous_names":["aaronland/go-iiif","thisisaaronland/go-iiif"],"tags_count":86,"template":false,"template_full_name":null,"purl":"pkg:github/go-iiif/go-iiif","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-iiif%2Fgo-iiif","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-iiif%2Fgo-iiif/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-iiif%2Fgo-iiif/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-iiif%2Fgo-iiif/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/go-iiif","download_url":"https://codeload.github.com/go-iiif/go-iiif/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/go-iiif%2Fgo-iiif/sbom","scorecard":{"id":431990,"data":{"date":"2025-08-11","repo":{"name":"github.com/go-iiif/go-iiif","commit":"67747d75999f1bd581db89f5fef7e61756d55b57"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.5,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/26 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":8,"reason":"10 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 8","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":9,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Warn: project license file does not contain an FSF or OSI license."],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: containerImage not pinned by hash: Dockerfile:1","Warn: containerImage not pinned by hash: Dockerfile:11: pin your Docker image by updating alpine to alpine@sha256:4bcff63911fcb4448bd4fdacec207030997caf25e9bea4045fa6c8c44de311d1","Info:   0 out of   2 containerImage dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 10 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":8,"reason":"2 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GO-2022-0635","Warn: Project is vulnerable to: GO-2022-0646"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-19T03:35:38.988Z","repository_id":43330115,"created_at":"2025-08-19T03:35:38.988Z","updated_at":"2025-08-19T03:35:38.988Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28430289,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T16:38:47.836Z","status":"ssl_error","status_checked_at":"2026-01-14T16:34:59.695Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["iiif","iiif-image"],"created_at":"2024-08-01T12:01:44.057Z","updated_at":"2026-01-14T18:18:29.262Z","avatar_url":"https://github.com/go-iiif.png","language":"Go","funding_links":[],"categories":["Go","others"],"sub_categories":[],"readme":"# go-iiif\n\n![spanking cat](misc/go-iiif-spanking-cat.png)\n\n## Motivation\n\nThis began as a fork of [@greut's iiif](https://github.com/greut/iiif) package that moves all of the processing logic for the [IIIF Image API](http://iiif.io/api/image/) in to discrete Go packages and defines source, derivative and graphics details in a [JSON config file](README.md#config-files). There is an additional caching layer for both source images and derivatives.\n\nI did this to better understand the architecture behind (and to address my own concerns about) the [IIIF Image API](http://iiif.io/api/image/2.1/index.html). For the time being this package will probably not support the other IIIF Metadata or Publication APIs.\n\n_And by \"forked\" I mean that [@greut](https://github.com/greut) and I decided that [it was best](https://github.com/greut/iiif/pull/2) for this code and his code to wave at each other across the divide but not necessarily to hold hands._\n\n## Releases\n\nThe current release is `github.com/go-iiif/go-iiif/v8`.\n\nDocumentation for releases has been moved in to [RELEASES.md](RELEASES.md).\n\n## Command-line tools\n\n_Note: command-line tools and utilities are included at the top of this document to accomodate the busy and/or curious. There are a number of important concepts to understand in how the `go-iiif` package is used (in particular config files) which are discussed in detail below._\n\n### Building\n\nRun the handy `cli` Makefile target to build all the tools:\n\n```\n$\u003e make cli\ngo build -mod vendor -ldflags=\"-s -w\" -o bin/iiif-transform cmd/iiif-transform/main.go\ngo build -mod vendor -ldflags=\"-s -w\" -o bin/iiif-tile-seed cmd/iiif-tile-seed/main.go\ngo build -mod vendor -ldflags=\"-s -w\" -o bin/iiif-process cmd/iiif-process/main.go\ngo build -mod vendor -ldflags=\"-s -w\" -o bin/iiif-server cmd/iiif-server/main.go\ngo build -mod vendor -ldflags=\"-s -w\" -o bin/iiif-dump-config cmd/iiif-dump-config/main.go\n```\n\n### Config files\n\nDetailed documentation for config files has been moved in to [config/README.md](config/README.md).\n\nIn the interest of trying to keep simple things simple all of the command line tools use a default configuration file, indicated by the URI `default://` which is defined in the [defaults/config.json](defaults/config.json) file. The default configuration looks and writes source and cache images, respectively, to an in-memory provider. As such, until you define at least an alternative source location (or your own config file) the tools won't _do_ very much.\n\nCustom source and cache locations are defined as fully-qualified URIs mapped to implementations of the `Source` and `Cache` interfaces (discussed below). For example to define a custom on-disk location for reading source images you would do this:\n\n```\n\t-config-images-source-uri file:///usr/local/src/go-iiif/fixtures/images\n```\n\nAnd to define a custom on-disk location to write (cache) derivate image files you would do this:\n\n```\n\t-config-derivatives-cache-uri file:///usr/local/src/go-iiif/fixtures/cache\n```\n\n### iiif-transform\n\nTransform one or more images using the IIIF API. For detailed usage consult [cmd/iiif-transform/README.md](cmd/iiif-transform/README.md)\n\n### iiif-tile-seed\n\nFor detailed usage consult [cmd/iiif-tile-seed/README.md](cmd/iiif-tile-seed/README.md)\n\n_[Example provided below.](#generating-level-0-tiles)_\n\n### iiif-process\n\nGenerate IIIF Level-0 image tiles for one or images. For detailed usage consult [cmd/iiif-process/README.md](cmd/iiif-proces/README.md)\n\n_[Example provided below.](#generating-derivatives-using-an-instructions-file)_\n\n### iiif-server\n\nExpose the IIIF Image API via an HTTP endpoint. For detailed usage consult [cmd/iiif-server/README.md](cmd/iiif-server/README.md)\n\n_[Example provided below.](#running-a-iiif-api-endpoint)_\n\n### iiif-dump-config\n\nEmit a go-iiif config file as Markdown. For detailed usage consult [cmd/iiif-dump-config/README.md](cmd/iiif-dump-config/README.md)\n\n### Examples\n\nThe easiest way to try things out is to use the handy `debug-{SOMETHING}` Makefile targets which will perform operations on files bundled with this package (in the [fixtures](fixtures) directory).\n\n#### Generating IIIF Level 0 tiles (debug-seed)\n\nGenerate IIIF Level 0 tiles for the [fixtures/spanking-cat.jpg](fixtures/spanking-cat.jpg) image and store those tiles in a folder named `spank`.\n\n```\n$\u003e make debug-seed\nif test -d /usr/local/src/go-iiif/fixtures/cache/spank; then rm -rf /usr/local/src/go-iiif/fixtures/cache/spank; fi\ngo run cmd/iiif-tile-seed/main.go \\\n\t\t-config-images-source-uri file:///usr/local/src/go-iiif/fixtures/images \\\n\t\t-config-derivatives-cache-uri file:///usr/local/src/go-iiif/fixtures/cache \\\n\t\t-verbose \\\n\t\t-generate-html \\\n\t\t'rewrite:///spanking-cat.jpg?target=spank'\n2025/03/24 17:55:42 DEBUG Verbose logging enabled\n2025/03/24 17:55:42 DEBUG New tiled image origin=spanking-cat.jpg target=spank\n\n... time passes, with lots of debugging information\n\n2025/03/24 17:56:08 DEBUG Tile seeding complete source=spanking-cat.jpg target=spank count=340\n2025/03/24 17:56:08 INFO Generate HTML index page for tiles source=spanking-cat.jpg alt=spank\n2025/03/24 17:56:08 DEBUG Successfully wrote blob \"bucket uri\"=file:///usr/local/src/go-iiif/fixtures/cache uri=spank/leaflet.iiif.bundle.js\n2025/03/24 17:56:08 DEBUG Successfully wrote blob \"bucket uri\"=file:///usr/local/src/go-iiif/fixtures/cache uri=spank/leaflet.css\n2025/03/24 17:56:08 DEBUG Successfully wrote blob \"bucket uri\"=file:///usr/local/src/go-iiif/fixtures/cache uri=spank/index.html\n2025/03/24 17:56:08 DEBUG Time to seed tiles source=spanking-cat.jpg target=spank time=25.699858709s\n```\n\nAnd then because the `-generate-html` flag was specified you can do this:\n\n```\n$\u003e open fixtures/cache/spank/index.html\n```\n\nAnd see something like this in your web browser:\n\n![](docs/images/go-iiif-v7-seed.png)\n\nThe folder containing the IIIF Level 0 tiles also contains just enough HTML and JavaScript code to show those tiles in a traditional \"zoomable image\" interface. These views are disabled by default and are mostly meant for reviewing the output of the seeding operation. For a more sophiticated \"zoomable image\" interface see the [sfomuseum/webcomponent-zoomable-image](https://github.com/sfomuseum/webcomponent-zoomable-image) package.\n\n#### Generating Level 0 tiles from a CSV file (debug-seed-csv)\n\nGenerate a CSV file containing information about images in the [fixtures](fixtures) folder and then generate Level 0 tiles for each image in the CSV file.\n\n```\n$\u003e make debug-seed-csv\nif test -d /usr/local/src/go-iiif/fixtures/cache/spanking-csv; then rm -rf /usr/local/src/go-iiif/fixtures/cache/spanking-csv; fi\nif test -d /usr/local/src/go-iiif/fixtures/cache/walrus-csv; then rm -rf /usr/local/src/go-iiif/fixtures/cache/walrus-csv; fi\nif test -f /usr/local/src/go-iiif/fixtures/seed.csv; then /usr/local/src/go-iiif/fixtures/seed.csv; fi\n\necho \"source_filename,source_root,target_filename,target_root\" \u003e /usr/local/src/go-iiif/fixtures/seed.csv\necho \"spanking-cat.jpg,/usr/local/src/go-iiif/fixtures/images,spanking-csv,/usr/local/src/go-iiif/fixtures/cache\" \u003e\u003e /usr/local/src/go-iiif/fixtures/seed.csv\necho \"walrus.jpg,/usr/local/src/go-iiif/fixtures/images,walrus-csv,/usr/local/src/go-iiif/fixtures/cache\" \u003e\u003e /usr/local/src/go-iiif/fixtures/seed.csv\n\ngo run cmd/iiif-tile-seed/main.go \\\n\t\t-mode csv \\\n\t\t-generate-html \\\n\t\t-verbose \\\n\t\t/usr/local/src/go-iiif/fixtures/seed.csv\n\t\t\n2025/03/25 14:39:51 DEBUG Verbose logging enabled\n2025/03/25 14:39:51 INFO Assign new source URI path=/usr/local/src/go-iiif/fixtures/seed.csv uri=file:///usr/local/src/go-iiif/fixtures/images\n2025/03/25 14:39:51 INFO Assign new cache URI path=/usr/local/src/go-iiif/fixtures/seed.csv uri=file:///usr/local/src/go-iiif/fixtures/cache\n2025/03/25 14:39:51 INFO Seed tiles path=/usr/local/src/go-iiif/fixtures/seed.csv source=spanking-cat.jpg target=spanking-csv\n2025/03/25 14:39:51 DEBUG Tile waiting to seed source=spanking-cat.jpg time=1.338917ms\n2025/03/25 14:39:51 INFO Assign new source URI path=/usr/local/src/go-iiif/fixtures/seed.csv uri=file:///usr/local/src/go-iiif/fixtures/images\n2025/03/25 14:39:51 INFO Assign new cache URI path=/usr/local/src/go-iiif/fixtures/seed.csv uri=file:///usr/local/src/go-iiif/fixtures/cache\n2025/03/25 14:39:51 INFO Seed tiles path=/usr/local/src/go-iiif/fixtures/seed.csv source=walrus.jpg target=walrus-csv\n2025/03/25 14:39:51 INFO Seed tiles for image \"source id\"=spanking-cat.jpg \"alt id\"=spanking-csv \"image cache\"=memory:// \"derivatives cache\"=file:///usr/local/src/go-iiif/fixtures/cache processes=10 scales=\"[8 4 2 1]\"\n\n... time passes, with lots of debugging information\n```\n\nAnd then eventually:\n\n```\n$\u003e ll fixtures/cache/*-csv/info.json\n-rw-r--r--  1 asc  staff  336 Mar 25 14:40 fixtures/cache/spanking-csv/info.json\n-rw-r--r--  1 asc  staff  334 Mar 25 14:39 fixtures/cache/walrus-csv/info.json\n```\n\n_Note the way we passed the `-generate-html` flag like we did in the first example ensuring that each set of tiles has its own HTML \"zoomable image\" representation._\n\nPlease make sure to consult the [usage documentation](cmd/iiif-tile-seed/README.md#csv-input) for the `iiif-tile-seed` tool for details on how CSV files should be structured.\n\n#### Generating named (labeled) derivatives using an \"instructions\" file (debug-process)\n\nGenerate a series of named (labeled) derivatives images for the [fixtures/spanking-cat.jpg](fixtures/spanking-cat.jpg) image from an \"instructions\" file, storing each derivative in a nested tree.\n\n```\n$\u003e make debug-process\nif test -d /usr/local/src/go-iiif/fixtures/cache/999; then rm -rf /usr/local/src/go-iiif/fixtures/cache/999; fi\ngo run cmd/iiif-process/main.go \\\n\t\t-config-derivatives-cache-uri file:///usr/local/src/go-iiif/fixtures/cache \\\n\t\t-config-images-source-uri file:///usr/local/src/go-iiif/fixtures/images \\\n\t\t-report \\\n\t\t-report-bucket-uri file:///usr/local/src/go-iiif/fixtures/reports \\\n\t\t-report-html \\\n\t\t-verbose \\\n\t\t'idsecret:///spanking-cat.jpg?id=9998\u0026secret=abc\u0026secret_o=def\u0026format=jpg\u0026label=x'\n2025/03/24 17:57:13 DEBUG Verbose logging enabled\n\n... time passes, with lots of debugging information\n\n2025/03/24 17:57:17 DEBUG Successfully wrote blob \"bucket uri\"=file:///usr/local/src/go-iiif/fixtures/cache uri=999/8/9998_abc_k.jpg\n2025/03/24 17:57:17 DEBUG Return transformation uri=\"rewrite:///spanking-cat.jpg?target=999%2F8%2F9998_abc_k.jpg\" origin=spanking-cat.jpg target=999/8/9998_abc_k.jpg \"source cache\"=memory:// \"destination cache\"=file:///usr/local/src/go-iiif/fixtures/cache \"new uri\"=file:///999/8/9998_abc_k.jpg\n2025/03/24 17:57:17 DEBUG Successfully wrote blob \"bucket uri\"=file:///usr/local/src/go-iiif/fixtures/cache uri=999/8/index.html\n```\n\nAnd then because the `-report-html` flag was specified you can do this:\n\n```\n$\u003e open fixtures/cache/999/8/index.html\n```\n\nAnd see something like this in your web browser:\n\n![](docs/images/go-iiif-v7-process-html.png)\n\nThe folder contained the \"processed\" derivative images also contains a simple HTML file displaying each of the derivative images. These views are disabled by default and are mostly for reviewing the output of the process(ing) operation.\n\nPlease make sure to consult the [usage documentation](cmd/iiif-proces/README.md) for the `iiif-process` tool for details on \"instructions\" and \"reports\".\n\n#### Running a IIIF API (HTTP) endpoint (debug-server)\n\nRun a IIIF API endpoint (server).\n\n```\n$\u003e make debug-server\nmkdir -p fixtures/cache\ngo run cmd/iiif-server/main.go \\\n\t\t-config-derivatives-cache-uri file:///usr/local/src/go-iiif/fixtures/cache \\\n\t\t-config-images-source-uri file:///usr/local/src/go-iiif/fixtures/images \\\n\t\t-example \\\n\t\t-verbose\n2025/03/24 17:55:18 DEBUG Verbose logging enabled\n2025/03/24 17:55:18 INFO Listening for requests address=http://localhost:8080\n```\n\nAnd then, because the `-example` flag was specified, when you open your web browser to `http://localhost:8080` you'll see this:\n\n![](docs/images/go-iiif-v7-server.png)\n\nThe \"example\" handler provides just enough HTML and JavaScript code to render tile images in a traditional \"zoomable image\" interface using the IIIF Image API endpoints. This handler is disabled by default and is mostly meant for ensuring that everything is working. For a more sophiticated \"zoomable image\" interface see the [sfomuseum/webcomponent-zoomable-image](https://github.com/sfomuseum/webcomponent-zoomable-image) package.\n\n### Extending the command line tools\n\nThe \"guts\" of all the command line tools live in the [app](app) package. This allows the definitions for the actual command line tools to be small and easy to extend.\n\nFor example if you want to extend the `iiif-tile-seed` tool to use a custom caching layer (discussed below) not included in this package by default you'll need to clone [cmd/iiif-tile-seed/main.go](cmd/iiif-tile-seed/main.go) and then add the relevant import statement. For example:\n\n```\npackage main\n\nimport (\n\t\"context\"\n\t\"log\"\n\n\t_ \"github.com/aaronland/gocloud-blob/s3\"\n\t_ \"github.com/go-iiif/go-iiif/v8/native\"\n\t_ \"gocloud.dev/blob/fileblob\"\n\t_ \"gocloud.dev/blob/memblob\"\n\t_ \"gocloud.dev/blob/s3blob\"\t\n        _ \"yourprovider.host/go-iiif-cache\"\t// YOUR CUSTOM CODE\n       \n\t\"github.com/go-iiif/go-iiif/v8/app/seed\"\n)\n\nfunc main() {\n\n\tctx := context.Background()\n\terr := seed.Run(ctx)\n\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n}\n```\n\nWhich is not ideal but is at least short and sweet and easy.\n\n## Drivers\n\n`go-iiif` was first written with the [libvips](https://github.com/jcupitt/libvips) library and [bimg](https://github.com/h2non/bimg/) Go wrapper for image processing. `libvips` is pretty great but it introduces non-trivial build and setup requirements. As of version 2.0 `go-iiif` no longer uses `libvips` by default but instead does all its image processing using native (Go) code. This allows `go-iiif` to run on any platform supported by Go without the need for external dependencies.\n\nDetailed documentation for drivers has been moved in to [driver/README.md](driver/README.md])\n\n## Data sources\n\nData sources in `go-iiif` are not so much \"complicated\" as they are \"nuanced\". By default IIIF assumes that everything is on a local disk (or \"mount\") and that everything references the canonical filename of an image. There is nothing wrong with these assumptions but they don't always reflect the reality of how data is organized or meant to be exposed.\n\nAs such, `go-iiif` makes use of the following constructs when working with data sources:\n\n### Image and cache \"sources\"\n\nThe first are the `Source` and `Cache` interfaces. These define common (Go language) interfaces for data sources (images) and any caching layers necessary for working with those images or the derivative products produced by the IIIF Image API.\n\nThe `Source` interface looks like this:\n\n```\n// Source is an interface representing a primary image source.\ntype Source interface {\n\t// Read returns the body of the file located at 'uri'.\n\tRead(uri string) ([]byte, error)\n\t// Close performs any final operations specific to a data source.\n\tClose() error\n}\n```\n\nThe `Cache` interface looks like this:\n\n```\n// A Cache is a representation of a cache provider.\ntype Cache interface {\n\t// Exists returns a boolean value indicating whether a key exists in the cache.\n\tExists(string) bool\n\t// Get returns the value for a specific key in the cache.\n\tGet(string) ([]byte, error)\n\t// Set assigns the value for a specific key in the cache.\n\tSet(string, []byte) error\n\t// Unset removes a specific key from the cache.\n\tUnset(string) error\n\t// Close performs any final operations specific to a cache provider.\t\n\tClose() error\n}\n```\n\nThis package provides the following default implementations for both interfaces:\n\n* Any registered [Go Cloud](https://gocloud.dev/) `Bucket` source (for example: files, in-memory, S3 or other cloud providers). See [source/blob.go](source/blob.go) and [cache/blob.go](cache/blob.go) for details.\n\n#### Default source implementations\n\nThis package also provides the following default implementations for the `Source` interface:\n\n* A source provider to yield images using the Flickr API. See [source/flickr.go](source/flickr.go) for details.\n* A source provider to yield images using a custom URI template. See [source/uritemplate.go](source/uritemplate.go) for details.\n\n#### Default cache implementations\n\nThis package also provides the following default implementations for the `Cache` interface:\n\n* In-memory key-value storage. See [cache/blob.go](cache/blob.go) for details.\n\n#### Custom implementations\n\nTo define custom source or cache implementations you need to do two things:\n\n1. Implement all the relevant interface methods\n2. \"Register\" a interface-implementation callback method using the `RegisterCache` (or `RegisterSource`) method.\n\nFor example, here is how you might implement a custom cache implementation:\n\n```\nimport (\n       \"context\"\n\n       iiifcache \"github.com/go-iiif/go-iiif/v8/cache\"\n)\n\ntype CustomCache struct {\n\tCache\n\t// your details here\n}\n\nfunc init() {\n     iiiicache.RegisterCache(context.Background(), \"custom\", NewCusomCache)\n}\n\nfunc NewCusomCache(ctx context.Context, uri string) (Cache, error) {\n\tc := CustomCache{}\n\treturn \u0026c, nil\n}\n\n// Cache interface methods here\n```\n\nAnd then in your code you would import your custom package like this:\n\n```\nimport (\n       _ \"yourprovider.host/go-iiif-cache\"\n)\n```\n\nAnd in your config file you would do something like this:\n\n```\n    \"derivatives\": {\n\t\"cache\": { \"uri\": \"custom://?{YOUR_CUSTOM_PARAMETERS}\" }\t\n    }        \n```\n\n### \"Buckets\"\n\nStarting with version 2 the `go-iiif` package uses the [Go Cloud](https://gocloud.dev/) `Bucket` and `Blob` interfaces for reading and writing all files. For example, instead of doing this:\n\n```\ncfg, _ := config.NewConfigFromFile(\"/etc/go-iiif/config.json\")\n```\n\nIt is now necessary to do this:\n\n```\nconfig_bucket, _ := bucket.OpenBucket(ctx, \"file:///etc/go-iiif\")\ncfg, _ := config.NewConfigFromBucket(ctx, config_bucket, \"config.json\")\n```\nThis allows for configuration files, and others, to be stored and retrieved from [any \"bucket\" source that is supported by the Go Cloud package](https://gocloud.dev/howto/blob/#services), notably remote storage services like AWS S3.\n\n### \"URIs\"\n\n_[go-iiif-uri](https://github.com/go-iiif/go-iiif-uri) URI strings are technically still a \"work in progress\" but since they haven't meaningfully changed in a few years they are probably close to being considered stable._\n\n`go-iiif-uri` URI strings are defined by a named scheme which indicates how an URI should be processed, a path which is a reference to an image and zero or more query parameters which are the specific instructions for processing the URI.\n\n### file\n\n```\nfile:///path/to/source/image.jpg\n```\n\n```\nfile:///path/to/source/image.jpg?target=/path/to/target/image.jpg\n```\n\nThe `file://` URI scheme is basically just a path or filename. It has an option `target` property which allows the name of the source image to be changed. These filenames are _not_ the final name of the image as processed by `go-iiif` but the name of the directory structure that files will be written to, as in the weird IIIF instructions-based URIs. \n\nValid parameters for the `file://` URI scheme are:\n\n| Name | Type | Required |\n| --- | --- | --- |\n| target | string | no |\n\n### idsecret\n\n```\nidsecret:///path/to/source/image.jpg?id=1234\u0026secret=s33kret\u0026secret_o=seekr3t\u0026label\n```\n\nThe `idsecret://` URI scheme is designed to rewrite a source image URI to {UNIQUE_ID} + {SECRET} + {LABEL} style filenames. For example `cat.jpg` becomes `1234_s33kret_b.jpg` and specifically `123/4/1234_s33kret_b.jpg` where the unique ID is used to generate a nested directory tree in which the final image lives.\n\nThe `idsecret://` URI scheme was developed for use with `go-iiif` \"instructions\" files where a single image produced multiple derivatives that need to share commonalities in their final URIs.\n\nValid parameters for the `idsecret://` URI scheme are:\n\n| Name | Type | Required |\n| --- | --- | --- |\n| id | int64 | yes |\n| label | string | yes |\n| format | string | yes |\n| original | string | no |\n| secret | string | no |\n| secret_o | string | no |\n\nIf either the `secret` or `secret_o` parameters are absent they will be auto-generated.\n\n### rewrite\n\n```\nrewrite:///path/to/source/image.jpg?target=/path/to/target/picture.jpg\n```\n\nThe `rewrite://` URI scheme is a variant of the `file://` URI scheme except that the `target` query parameter is required and it will be used to redefine the final URI, rather than just its directory tree, of the processed image.\n\n| Name | Type | Required |\n| --- | --- | --- |\n| target | string | yes |\n\n### Example\n\nHere's a excerpted example taken from the [process/parallel.go](process/parallel.go) package that processes a single source image, defined as an `idsecret://` URI, in to multiple derivatives defined in an \"instructions\" file.\n\nThe `idsecret://` URI is output as a string using the instructions set to define the `label` and other query parameters. That string is then used to create a new `rewrite://` URI where source is derived from the original `idsecret://` URI and the target is newly generate URI string.\n\n```\ngo func(ctx context.Context, u iiifuri.URI, label Label, i IIIFInstructions) {\n\n\tvar process_uri iiifuri.URI\n\n\tswitch u.Driver() {\n\tcase \"idsecret\":\n\n\t\tstr_label := fmt.Sprintf(\"%s\", label)\n\n\t\topts := \u0026url.Values{}\n\t\topts.Set(\"label\", str_label)\n\t\topts.Set(\"format\", i.Format)\n\n\t\tif str_label == \"o\" {\n\t\t\topts.Set(\"original\", \"1\")\n\t\t}\n\n\t\ttarget_str, _ := u.Target(opts)\n\n\t\torigin := u.Origin()\n\n\t\trw_str := fmt.Sprintf(\"%s?target=%s\", origin, target_str)\n\t\trw_str = iiifuri.NewRewriteURIString(rw_str)\n\n\t\trw_uri, err := iiifuri.NewURI(rw_str)\n\t\tprocess_uri = rw_uri\n\n\tdefault:\n\t\tprocess_uri = u\n\t}\n\n\tnew_uri, im, _ := pr.ProcessURIWithInstructions(ctx, process_uri, label, i)\n\t// do something with new_uri and im here...\n\t\n}(...)\n```\n\n## Image formats\n\nUnder the hood this package uses the [aaronland/go-image/v2](https://github.com/aaronland/go-image) package for encoding and decoding images.\n\n### Decoders\n\nThe following image decoders are supported by default (but you should consult the `aaronland/go-image` documentation for an authoritative list):\n\n* `image/bmp`\n* `image/gif`\n* `image/heic` (if built with `libheif` tag)\n* `image/jpeg`\n* `image/png`\n* `image/tiff`\n* `image/webp`\n\n#### HEIC images\n\nBy default this package supports decoding HEIC images using the [strukturag/libheif-go](http://github.com/strukturag/libheif-go) package which, in turn, depends on the presence of the `libheif` library when you are compiling your code (or the command line tools) so you will need to pass in the `-tags libheif` flag.\n\n### Encoders\n\nThe following image encoders are supported by default (but you should consult the `aaronland/go-image` documentation for an authoritative list):\n\n* `image/bmp`\n* `image/heic` (if built with `libheif` tag)\n* `image/jpeg`\n* `image/png`\n* `image/tiff`\n\n#### HEIC images\n\nBy default this package supports encoding HEIC images using the [strukturag/libheif-go](http://github.com/strukturag/libheif-go) package which, in turn, depends on the presence of the `libheif` library when you are compiling your code (or the command line tools) so you will need to pass in the `-tags libheif` flag.\n\n## Performance and load testing\n\nFor processing large, or large volumes of, images the bottlenecks will be:\n\n* CPU usage crunching pixels\n* Disk I/O writing tiles to disk\n* Running out of inodes\n\nThat said on a machine with 8 CPUs and 32GB RAM I was able to run the machine hot with all the CPUs pegged at 100% usage and seed 100, 000 (2048x pixel) images yielding a little over 3 million, or approximately 70GB of, tiles in 24 hours. Some meaningful but not overwhelming amount of time was spent fetching source images across the network so presumably things would be faster reading from a local filesystem.\n\nMemory usage across all the `iiif-tile-seed` processes never went above 5GB and, in the end, I ran out of inodes.\n\nThe current strategy for seeding tiles may also be directly responsible for some of the bottlenecks. Specifically, when processing large volumes of images (defined in a CSV file) the `ifff-tile-seed` will spawn and queue as many concurrent Go routines as there are CPUs. For each of those processes then another (n) CPUs * 2 subprocesses will be spawned to generate tiles. Maybe this is just too image concurrent image processing routines to have? I mean it works but still... Or maybe it's just that every one is waiting for bytes to be written to disk. Or all of the above. I'm not sure yet.\n\n## Bugs?\n\nSure, maybe. Please consult [the currently known-known issues](https://github.com/go-iiif/go-iiif/issues) and if you don't see what ails you please feel free to add it.\n\n## See also\n\n### IIIF stuff\n\n* http://iiif.io/api/image/2.1/\n\n### go-iiig stuff\n\n* https://github.com/go-iiif/go-iiif-vips\n* https://github.com/go-iiif/go-iiif-uri\n* https://github.com/go-iiif/go-iiif-www\n\n### Go stuff\n\n* https://github.com/greut/iiif/\n* https://github.com/anthonynsimon/bild\n* https://github.com/muesli/smartcrop\n\n### Slippy map stuff\n\n* https://github.com/mejackreed/Leaflet-IIIF\n* https://github.com/mapbox/leaflet-image\n\n### Blog posts\n\n* http://www.aaronland.info/weblog/2016/09/18/marshmallows/#iiif\n* http://www.aaronland.info/weblog/2017/03/05/record/#numbers\n* https://labs.cooperhewitt.org/2017/parting-gifts/\n* https://millsfield.sfomuseum.org/blog/2018/07/18/iiif/\n* https://millsfield.sfomuseum.org/blog/2019/02/12/iiif-aws/\n* https://millsfield.sfomuseum.org/blog/2019/11/13/iiif-v2/\n\n### Other stuff\n\n* [Spanking Cat](https://collection.cooperhewitt.org/objects/18382391/)\n* [Airplane Walrus](https://collection.sfomuseum.org/objects/1511908311/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgo-iiif%2Fgo-iiif","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgo-iiif%2Fgo-iiif","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgo-iiif%2Fgo-iiif/lists"}