{"id":13741060,"url":"https://github.com/jbaiter/pdiiif","last_synced_at":"2025-09-23T09:42:29.965Z","repository":{"id":65932161,"uuid":"295329463","full_name":"jbaiter/pdiiif","owner":"jbaiter","description":"Create PDFs from IIIF manifests, completely client-side (with server-based fallback for unsupported browsers)","archived":false,"fork":false,"pushed_at":"2024-07-30T21:34:17.000Z","size":2469,"stargazers_count":38,"open_issues_count":2,"forks_count":4,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-22T10:35:38.731Z","etag":null,"topics":["iiif","ocr","pdf-generation"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jbaiter.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","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}},"created_at":"2020-09-14T06:51:32.000Z","updated_at":"2025-03-12T10:51:40.000Z","dependencies_parsed_at":"2024-07-10T23:45:52.114Z","dependency_job_id":"c4607b0a-d26c-409b-95bc-d8dc3bbbfb56","html_url":"https://github.com/jbaiter/pdiiif","commit_stats":null,"previous_names":[],"tags_count":17,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbaiter%2Fpdiiif","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbaiter%2Fpdiiif/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbaiter%2Fpdiiif/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbaiter%2Fpdiiif/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jbaiter","download_url":"https://codeload.github.com/jbaiter/pdiiif/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250221595,"owners_count":21394735,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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","ocr","pdf-generation"],"created_at":"2024-08-03T04:00:55.027Z","updated_at":"2025-09-23T09:42:24.917Z","avatar_url":"https://github.com/jbaiter.png","language":"TypeScript","funding_links":[],"categories":["Presentation Manifest Tools"],"sub_categories":["Image viewers (Image API only)"],"readme":"[![pdiiif logo](pdiiif-web/assets/logo.svg)](https://pdiiif.jbaiter.de)\n\n[**Demo**](https://pdiiif.jbaiter.de)\n\n[**Sample PDF generated with the library**](https://pdiiif.jbaiter.de/wunder.pdf)\n\n[**Library API Documentation**](https://jbaiter.github.io/pdiiif)\n\n**pdiiif** is a JavaScript library to **create PDFs from IIIF Manifests.**\nFor the most part, it runs both in browsers and as a Node.js server-side\napplication. When generating a PDF in the browser, almost all communication happens\ndirectly between the user's browser and the IIIF APIs referenced from the Manifest.\nThe only exception is for generating the cover page, which by default needs to be\ngenerated on the server. (see [this section](#cover-page-endpoints) for more details)\n\nIt comes with a small **sample web application** that demonstrates\nhow to use the library in the browser, you can check out a public instance\nof it at https://pdiiif.jbaiter.de, the source code is located in the\n[`pdiiif-web` subdirectory](https://github.com/jbaiter/pdiiif/tree/main/pdiiif-web).\n\nA main goal of the library is to be as _memory-efficient_ as possible, by\nnever holding more than a few pages in memory and streaming directly to\nthe user's disk (precise method depends on the environment).\n\nIt is also well-suited for embedding in other applications due to\nits relatively small footprint, for example, the example web application comes\nin at **~120KiB gzipped** with all dependencies.\n\nIn addition to the images on the IIIF Canvases referenced in the manifest,\nthe library can create a **hidden text layer** from OCR associated with\neach canvas (ALTO or hOCR referenced from a canvas' `seeAlso` property).\n\nIn order to not sever the connection between the PDF and the original IIIF\nresources on the Web, every PDF generated by `pdiiif` includes the IIIF Manifest\nas a PDF attachment, as well as every OCR file referenced in `seeAlso`.\nAdditionally, `pdiiif` can generate the PDFs in a way that also makes them\nvalid ZIP files that contain the manifest and all of the images and OCR files,\nwith almost no storage overhead. (thanks to [Ange Albertini](https://github.com/corkami)\nand his work on [Poc||GTFO](https://pocorgtfo.hacke.rs/) for the inspiration!)\n\n\n## Features\n\n- [x] PDF Page for every single-image Canvas in a Manifest\n- [x] Rendering Canvases with multiple images\n- [x] PDF Table of Contents from IIIF Ranges\n- [x] Cover page with metadata, attribution and licensing information\n- [x] Hidden text layer from ALTO or hOCR OCR\n- [x] Render IIIF layers as PDF \"optional content groups\" that can be toggled\n- [x] Rendering of IIIF Annotations as PDF annotations\n- [x] Include IIIF Manifest and referenced OCR files as PDF attachments\n- [x] Generate polyglot PDFs that are also ZIP files of all resources\n\n\n## Quickstart\n\nBesides using the public instance at https://pdiiif.jbaiter.de, you can also run the app yourself.\nThe easiest way to do this is with Docker:\n\n```\n$ docker build . -t pdiiif\n# SYS_ADMIN capabilities are required (for Puppeteer's headless Chrome instance to generate cover page PDFs)\n$ docker run -p 8080:8080 --cap-add=SYS_ADMIN --name pdiiif pdiiif\n```\n\n\n## Cookbook Matrix\n\nThe [IIIF Cookbook](https://iiif.io/api/cookbook/) has a matrix of \"recipes\" with viewer support, here's an overview\nof the recipe support in pdiiif:\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eBasic Recipes\u003c/strong\u003e (4 of 6 supported)\u003c/summary\u003e\n\n- [x] [Simplest Manifest - Single Image File](https://iiif.io/api/cookbook/recipe/0001-mvm-image/): Partial, only for JPEG and PNG images. \n- [ ] [Simplest Manifest - Audio](https://iiif.io/api/cookbook/recipe/0002-mvm-audio/): NO, PDF has support for audio, but support in pdiiif unlikely, unless there is substantial demand for it\n- [ ] [Simplest Manifest - Video](https://iiif.io/api/cookbook/recipe/0003-mvm-video/): NO, PDF has support for video, but support in pdiiif unlikely, unless there is substantial demand for it\n- [x] [Support Deep Viewing with Basic Use of a IIIF Image Service](https://iiif.io/api/cookbook/recipe/0005-image-service/): YES, Deep Viewing isn't useful in PDF, but IIIF Image Services are fully supported\n- [x] [Internationalization and Multi-language Values (label, summary, metadata, requiredStatement)](https://iiif.io/api/cookbook/recipe/0006-text-language/): YES\n- [x] [Simple Manifest - Book](https://iiif.io/api/cookbook/recipe/0009-book-1/): YES\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eIIIF Properties\u003c/strong\u003e (8 of 15 supported)\u003c/summary\u003e\n\n- [x] [Embedding HTML in descriptive properties (label, summary, metadata, requiredStatement)](https://iiif.io/api/cookbook/recipe/0007-string-formats/): Partially, only for server-generated cover page\n- [x] [Rights statement (rights, requiredStatement)](https://iiif.io/api/cookbook/recipe/0008-rights/): YES\n- [x] [Viewing direction and Its Effect on Navigation (viewingDirection)](https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/): Partially, `right-to-left` and `left-to-right` only, viewer support very spotty\n- [ ] [Book 'behavior' Variations (continuous, individuals) (behaviorimage)](https://iiif.io/api/cookbook/recipe/0011-book-3-behavior/): NO, general support unlikely since paging preference is global in PDF, but if behavior is global for the manifest, it should be doable\n- [ ] [Load a Preview Image Before the Main Content (placeholderCanvas)](https://iiif.io/api/cookbook/recipe/0013-placeholderCanvas/): NO, not applicable\n- [ ] [Audio Presentation with Accompanying Image (accompanyingCanvas)](https://iiif.io/api/cookbook/recipe/0014-accompanyingcanvas/): NO, no support for audio\n- [ ] [Begin playback at a specific point - Time-based media (start)](https://iiif.io/api/cookbook/recipe/0015-start/): NO, no support for time-based media\n- [x] [Metadata on any Resource (metadata)](https://iiif.io/api/cookbook/recipe/0029-metadata-anywhere/): Partial, only Manifest metadata\n- [ ] [Providing Alternative Representations (rendering)](https://iiif.io/api/cookbook/recipe/0046-rendering/): NO, utility in PDF questionable\n- [ ] [Linking to Structured Metadata (seeAlso)](https://iiif.io/api/cookbook/recipe/0053-seeAlso/): NO, could be placed on the cover page\n- [x] [Image Thumbnail for Manifest (thumbnail)](https://iiif.io/api/cookbook/recipe/0117-add-image-thumbnail/): YES\n- [x] [Displaying Multiple Values with Language Maps (label, summary, metadata, requiredStatement)](https://iiif.io/api/cookbook/recipe/0118_multivalue/): YES\n- [x] [Load Manifest Beginning with a Specific Canvas (start)](https://iiif.io/api/cookbook/recipe/0202-start-canvas/): NO, but support possible\n- [ ] [Navigation by Chronology (navDate)](https://iiif.io/api/cookbook/recipe/0230-navdate/): NO\n- [x] [Acknowledge Content Contributors (provider)](https://iiif.io/api/cookbook/recipe/0234-provider/): YES\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eStructuring Resources\u003c/strong\u003e (3 of 6 supported)\u003c/summary\u003e\n\n- [x] [Table of Contents for Book Chapters (structures)](https://iiif.io/api/cookbook/recipe/0024-book-4-toc/): YES\n- [ ] [Table of Contents for A/V Content](https://iiif.io/api/cookbook/recipe/0026-toc-opera/): NO\n- [ ] [Multi-volume Work with Individually-bound Volumes](https://iiif.io/api/cookbook/recipe/0030-multi-volume/): NO\n- [x] [Multiple Choice of Images in a Single View (Canvas)](https://iiif.io/api/cookbook/recipe/0033-choice/): YES\n- [ ] [Foldouts, Flaps, and Maps (behavior)](https://iiif.io/api/cookbook/recipe/0035-foldouts/): NO, support unlikely due to global paging preference in PDF\n- [x] [Composition from Multiple Images](https://iiif.io/api/cookbook/recipe/0036-composition-from-multiple-images/): Partial, as long as all images have a JPEG representation\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eImage Recipes\u003c/strong\u003e (6 of 6 supported)\u003c/summary\u003e\n\n- [x] [Simplest Manifest - Single Image File](https://iiif.io/api/cookbook/recipe/0001-mvm-image/): Partial, only for JPEG and PNG images\n- [x] [Image and Canvas with Differing Dimensions](https://iiif.io/api/cookbook/recipe/0004-canvas-size/): YES\n- [x] [Support Deep Viewing with Basic Use of a IIIF Image Service](https://iiif.io/api/cookbook/recipe/0005-image-service/): YES, Deep Viewing isn't useful in PDF, but IIIF Image Services are fully supported\n- [x] [Simple Manifest - Book](https://iiif.io/api/cookbook/recipe/0009-book-1/): YES\n- [x] [Viewing direction and Its Effect on Navigation (viewingDirection)](https://iiif.io/api/cookbook/recipe/0010-book-2-viewing-direction/): Partially, `right-to-left` and `left-to-right` only, viewer support very spotty\n- [x] [Load Manifest Beginning with a Specific Canvas (start)](https://iiif.io/api/cookbook/recipe/0202-start-canvas/): YES\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cstrong\u003eAnnotation Recipes\u003c/strong\u003e (4 of 5 supported)\u003c/summary\u003e\n\n- [x] Simple Annotation — Tagging: YES\n- [ ] Tagging with an External Resource: NO\n- [x] Annotation with a Non-Rectangular Polygon: YES\n- [x] Simplest Annotation: YES\n- [x] Embedded or referenced Annotations: YES\n\u003c/details\u003e\n\n## Structure of the repository\n\n- [`./pdiiif-lib`](https://github.com/jbaiter/pdiiif/tree/main/pdiiif-lib): Contains the library source code\n- [`./pdiiif-api`](https://github.com/jbaiter/pdiiif/tree/main/pdiiif-api): Small node.js server application that\n  is responsible for generating the cover pages and that can be used as a fallback for browsers that don't support\n    the Native Filesystem API or service workers.\n- [`./pdiiif-web`](https://github.com/jbaiter/pdiiif/tree/main/pdiiif-web): Sample web application (using Svelte)\n  to demonstrate using pdiiif in the browser\n\n## Cover Page Endpoints\n\npdiiif tries to includes a cover page with a thumbnail, descriptive metadata and rights and attribution information.\nSince typesetting these pages is beyond the scope of what our bespoke PDF generator can provide (most notably, TTF/OTF\nfont retrieval for arbitrary languages/scripts and font subsetting), this cover page currently needs to be generated\nelsewhere. By default, the library is using a public endpoint at https://pdiiif.jbaiter.de/api/coverpage, which generates\na PDF with the default template. The endpoint can be changed with the `coverPageEndpoint` configuration parameter in the\noptions passed to the `convertManifest` function.\n\nIf you want to customize the template that is being used, you can either host the API provided in this repository yourself\n(see [Quickstart](quickstart)) and override the template by mounting your own custom [Handlebars](https://handlebarsjs.com/)\ntemplate into the image at `/opt/pdiiif/pdiiif-api/dist/asses/coverpage.hbs`. For a list of available helpers that you can\nuse, refer to [`handlebars-helpers`](https://github.com/helpers/handlebars-helpers#helpers). Also available are these two\ncustom helpers:\n- `qrcode`, takes a value and an optional `{ width, height, padding, color, background, ecl }` options object and returns\n  the value encoded as a SVG QR code image\n- `sanitize-html`, takes an arbitrary HTML string and sanitizes it according to the [IIIF HTML rules](https://iiif.io/api/presentation/3.0/#45-html-markup-in-property-values)\n\nIf you want to provide your own implementation, make sure that your HTTP endpoint generates a valid PDF and accepts a JSON\nPOST body with the following shape (i.e. does not throw an error when encountering any of these fields):\n\n```typescript\n{\n  title: string;\n  manifestUrl: string;\n  thumbnail?: {\n    url: string;\n    iiifImageService?: string;\n  };\n  provider?: {\n    label: string;\n    homepage?: string;\n    logo?: string;\n  };\n  requiredStatement?: {\n    label: string;\n    value: string;\n  };\n  rights?: {\n    text: string;\n    url?: string;\n    logo?: string;\n  };\n  // [key, value] pairs, with value either single- or multi-valued\n  metadata?: Array\u003c[string, string | Array\u003cstring\u003e]\u003e;\n  pdiiifVersion: string;\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjbaiter%2Fpdiiif","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjbaiter%2Fpdiiif","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjbaiter%2Fpdiiif/lists"}