{"id":13740561,"url":"https://github.com/rogerhoward/djiiif","last_synced_at":"2026-04-08T15:31:10.557Z","repository":{"id":26032702,"uuid":"107158583","full_name":"rogerhoward/djiiif","owner":"rogerhoward","description":"Simple IIIF integration for Django.","archived":false,"fork":false,"pushed_at":"2023-09-06T00:21:09.000Z","size":58,"stargazers_count":9,"open_issues_count":6,"forks_count":0,"subscribers_count":1,"default_branch":"development","last_synced_at":"2025-12-17T01:40:26.646Z","etag":null,"topics":["django","iiif"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rogerhoward.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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}},"created_at":"2017-10-16T17:12:39.000Z","updated_at":"2024-10-29T19:15:30.000Z","dependencies_parsed_at":"2024-11-15T10:33:10.470Z","dependency_job_id":"94e18521-9050-4cd5-adea-3650d6be11b3","html_url":"https://github.com/rogerhoward/djiiif","commit_stats":{"total_commits":46,"total_committers":3,"mean_commits":"15.333333333333334","dds":"0.19565217391304346","last_synced_commit":"f45962653e4f8ef35eec8f48406879f7d95176d2"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/rogerhoward/djiiif","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogerhoward%2Fdjiiif","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogerhoward%2Fdjiiif/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogerhoward%2Fdjiiif/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogerhoward%2Fdjiiif/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rogerhoward","download_url":"https://codeload.github.com/rogerhoward/djiiif/tar.gz/refs/heads/development","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogerhoward%2Fdjiiif/sbom","scorecard":{"id":782698,"data":{"date":"2025-08-11","repo":{"name":"github.com/rogerhoward/djiiif","commit":"459bb10c1e1cf7675202fdea830cf06fcb917d6d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.5,"checks":[{"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":"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":"Code-Review","score":0,"reason":"Found 0/10 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":"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":"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":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"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":"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":"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":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Info: FSF or OSI recognized license: BSD 2-Clause \"Simplified\" License: LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"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":-1,"reason":"internal error: error during GetBranch(master): error during branchesHandler.query: internal error: githubv4.Query: Resource not accessible by integration","details":null,"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":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 26 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"}}]},"last_synced_at":"2025-08-23T05:17:10.302Z","repository_id":26032702,"created_at":"2025-08-23T05:17:10.302Z","updated_at":"2025-08-23T05:17:10.302Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31562685,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"ssl_error","status_checked_at":"2026-04-08T14:31:17.202Z","response_time":54,"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":["django","iiif"],"created_at":"2024-08-03T04:00:49.725Z","updated_at":"2026-04-08T15:31:10.530Z","avatar_url":"https://github.com/rogerhoward.png","language":"Python","funding_links":[],"categories":["Image Server Shims"],"sub_categories":["IIIF Extensions"],"readme":"# django-iiif\n\ndjango-iiif is a package designed to make integrating the [IIIF Image API](http://iiif.io/api/image/2.1/) easier by extending Django's ImageField. By defining one or more named \"profiles\", your ImageFields expose IIIF-compatible URLs for each profile.\n\n## Why Django-IIIF and not ImageKit\n\nI love ImageKit, but I recently worked on a project where we already had IIIF handling image derivative generation and serving, and Django ImageKit just got in the way. I wanted to still register my source images with Django, but serve them through an [IIIF server](https://github.com/loris-imageserver/loris), and this is what I came up with. I have lots of ideas for improvements here, but the initial release is just a santized version of what I used on my most recent project.\n\n## Installation\n\n`pip install djiiif`\n\n## Examples\n\nFirst, let's setup a new field (or convert an existing ImageField):\n\n`models.py`\n```python\nfrom djiiif import IIIFField\n\noriginal = IIIFField()\n```\n\nSecond, configure the relevant settings.\n\n`settings.py`\n```python\n\nIIIF_HOST = 'http://server/'\n\nIIIF_PROFILES = {\n    'thumbnail':\n        {'host': IIIF_HOST, \n        'region': 'full', \n        'size': '150,',\n        'rotation': '0',\n        'quality': 'default',\n        'format': 'jpg'}\n}\n```\n\n\nFinally, we can access profile(s) as attributes of the `iiif` attribute on an instance of `original`.\n\nIn Python:\n\n```python\nprint(instance.original.name)\n\u003e uploads/filename.jpg\n\nprint(instance.original.iiif.thumbnail)\n\u003e http://server/uploads/filename.jpg/full/150,/0/default.jpg\n```\n\n\nIn a Django template:\n\n```\n\u003cimg src=\"{{ instance.original.iiif.thumbnail }}\"\u003e\n```\n\nAs of version 0.15, we can also generate a IIIF info.json URL:\n\n```\nprint(instance.original.iiif.info)\n\u003e http://server/uploads/filename.jpg/info.json\n```\n\n### callable-based profiles\n\nYou can also use a callable to dynamically generate a URL. The callable will receive the parent `IIIFFieldFile` (a subclass of `ImageFieldFile`) as its sole parameter, `parent`, and must return a `dict` with the following keys: host, region, size, rotation, quality, and format. Using a callable allows you to implement more complex logic in your profile, including the ability to access the original file's name, width, and height.\n\nAn example of a callable-based profile named `square` is below, used to generate a square-cropped image.\n\n\n```python\ndef squareProfile(original):\n    width, height = original.width, original.height\n\n    if width \u003e height:\n        x = int((width - height) / 2)\n        y = 0\n        w = height\n        h = height\n        region = '{},{},{},{}'.format(x,y,w,h)\n    elif width \u003c height:\n        x = 0\n        y = int((height - width) / 2)\n        w = width\n        h = width\n        region = '{},{},{},{}'.format(x,y,w,h)\n    else:\n        region = 'full'\n\n    spec = {'host': IIIF_HOST, \n        'region': region, \n        'size': '256,256',\n        'rotation': '0',\n        'quality': 'default',\n        'format': 'jpg'}\n    return spec\n```\n\n```python\nIIIF_PROFILES = {\n    'thumbnail':\n        {'host': IIIF_HOST, \n        'region': 'full', \n        'size': '150,',\n        'rotation': '0',\n        'quality': 'default',\n        'format': 'jpg'},\n    'preview':\n        {'host': IIIF_HOST, \n        'region': 'full', \n        'size': '600,',\n        'rotation': '0',\n        'quality': 'default',\n        'format': 'jpg'},\n    'square': squareProfile\n}\n ```\n\n### IIIF Template Tag\n\nAn alternate way to access IIIF URLs for your IIIFField is via the `iiif` template tag.\n\nFirst, add `djiiif` to your `INSTALLED_APPS`:\n\n\n```\nINSTALLED_APPS = [\n    ...\n    'djiiif'\n]\n ```\n\n\nNext, load our template tag library `iiiftags` in your template:\n\n```\n{% load iiiftags %}\n```\n\nFinally, use it in a template:\n\n```\n{% iiif asset.original 'thumbnail' %}\n```\n\nThe first parameter (asset.original) is a reference to an IIIFField instance.\n\nThe second parameter ('thumbnail') is the name of one of your IIIF profiles.\n\nThis tag syntax is effectively the same as:\n\n```\n{{ asset.original.iiif.thumbnail }}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frogerhoward%2Fdjiiif","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frogerhoward%2Fdjiiif","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frogerhoward%2Fdjiiif/lists"}