{"id":13632139,"url":"https://github.com/ascorbic/unpic","last_synced_at":"2025-05-14T19:10:27.935Z","repository":{"id":65424427,"uuid":"591589984","full_name":"ascorbic/unpic","owner":"ascorbic","description":"Universal image CDN translator","archived":false,"fork":false,"pushed_at":"2025-02-04T08:40:42.000Z","size":1526,"stargazers_count":356,"open_issues_count":25,"forks_count":46,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-07T06:01:49.732Z","etag":null,"topics":["cdn","hacktoberfest","image-manipulation","images"],"latest_commit_sha":null,"homepage":"https://unpic.pics/lib","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ascorbic.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG-old.md","contributing":"CONTRIBUTING.md","funding":null,"license":null,"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":"2023-01-21T07:36:02.000Z","updated_at":"2025-04-27T20:17:24.000Z","dependencies_parsed_at":"2023-03-06T13:30:20.473Z","dependency_job_id":"cf41421a-b720-42de-abd7-672e9f95bceb","html_url":"https://github.com/ascorbic/unpic","commit_stats":{"total_commits":123,"total_committers":22,"mean_commits":5.590909090909091,"dds":"0.44715447154471544","last_synced_commit":"c8cadc5a299a0ca34ffa0441b9c5ee127ae0a478"},"previous_names":[],"tags_count":47,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ascorbic%2Funpic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ascorbic%2Funpic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ascorbic%2Funpic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ascorbic%2Funpic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ascorbic","download_url":"https://codeload.github.com/ascorbic/unpic/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254209859,"owners_count":22032897,"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":["cdn","hacktoberfest","image-manipulation","images"],"created_at":"2024-08-01T22:02:53.133Z","updated_at":"2025-05-14T19:10:26.967Z","avatar_url":"https://github.com/ascorbic.png","language":"TypeScript","readme":"# 🖼 Unpic\n\n**Universal image CDN URL translator**\n\nThere are many image CDNs that provide a URL API for transforming images. There\nis little consistency in these APIs, and it's often unclear what the API is for\na given URL. This library aims to provide a consistent interface for detecting\nimage CDN URLs and transforming them.\n\nIf you'd like to use this on the web, you might want to try\n[Unpic img](https://github.com/ascorbic/unpic-img), a multi-framework image\ncomponent, powered by Unpic.\n\nIt designed to work with image URLs from sources such as CMSs and other\nuser-generated content, where the source image may or may not be from an image\nCDN, and may already have transforms applied. This allow different transforms to\nbe applied for display on a website. A web framework may need to transform an\nimage for display on a site. Rather than doing this by downloading and resizing\nit locally or re-processing it with a separate image service, this library can\nbe used to transform the URL to use the original image CDN, which will then\ntransform the image on the fly.\n\n## Usage\n\nThis library is available via NPM as `unpic` and JSR as\n[`@unpic/lib`](https://jsr.io/@unpic/lib).\n\nTo use it in Node, install it from npm:\n\n```sh\nnpm install unpic\n```\n\nThen import it in your code:\n\n```ts\nimport { transformUrl } from \"unpic\";\n```\n\nTo use it in Deno, import [the module from JSR](https://jsr.io/@unpic/lib):\n\n```ts\nimport { transformUrl } from \"jsr:@unpic/lib\";\n```\n\nIf you previously installed the library from deno.land/x, you should update to\nuse JSR instead as the deno.land/x version is no longer updated.\n\nYou can then use the `transformUrl` function to transform a URL:\n\n```ts\nconst url = transformUrl(\n\t\"https://cdn.shopify.com/static/sample-images/bath_grande_crop_center.jpeg\",\n\t{\n\t\twidth: 800,\n\t\theight: 600,\n\t},\n);\n\nconsole.log(url);\n// https://cdn.shopify.com/static/sample-images/bath.jpeg?width=800\u0026height=600\u0026crop=center\n```\n\nYou can also use the `parseUrl` function to parse a URL and get information\nabout the image:\n\n```ts\nconst parsed = parseUrl(\n\t\"https://cdn.shopify.com/static/sample-images/bath_800x600_crop_center.jpeg\",\n);\n\nconsole.log(parsed);\n// {\n//   provider: \"shopify\",\n//   src: \"https://cdn.shopify.com/static/sample-images/bath.jpeg\",\n//   operations: {\n//     width: 800,\n//     height: 600,\n//     crop: \"center\"\n//   }\n// }\n```\n\nYou can bypass auto-detection by specifying the provider:\n\n```ts\nconst url = transformUrl(\n\t\"https://cdn.shopify.com/static/sample-images/bath_grande_crop_center.jpeg\",\n\t{\n\t\twidth: 800,\n\t\theight: 600,\n\t\tprovider: \"shopify\",\n\t},\n);\n```\n\nThis is particularly useful if you are using the CDN with a custom domain which\nis not auto-detected.\n\nYou can also specify a fallback provider to use if the URL is not recognised as\ncoming from a known CDN:\n\n```ts\nconst url = transformUrl(\n\t\"https://example.com/image.jpg\",\n\t{\n\t\twidth: 800,\n\t\theight: 600,\n\t\tfallback: \"netlify\",\n\t},\n);\n```\n\nThis is useful if you are using a CDN provider that supports external images,\nbut you still want to use the original CDN if possible.\n\n## Custom operations\n\nDifferent CDNs support different operations. By default, the transform function\naccepts the operations `width`, `height`, `quality` and `format`. You can pass\nprovider-specific operations as the third argument to the `transformUrl`\nfunction:\n\n```ts\nconst url = transformUrl(\n\t\"https://cdn.shopify.com/static/sample-images/bath.jpeg\",\n\t{\n\t\twidth: 800,\n\t\theight: 600,\n\t},\n\t{\n\t\tshopify: {\n\t\t\tcrop: \"center\",\n\t\t},\n\t},\n);\n```\n\nYou can pass options for multiple providers, which will be passed to the\nprovider depending on the detected CDN:\n\n```ts\nconst url = transformUrl(\n\tsrc,\n\t{\n\t\twidth: 800,\n\t\theight: 600,\n\t},\n\t{\n\t\tshopify: {\n\t\t\tcrop: \"left\",\n\t\t},\n\t\timgix: {\n\t\t\tposition: \"left\",\n\t\t},\n\t},\n);\n```\n\nThese options are type-safe, as we include the types for each provider.\n\nYou can do the same for provider options, such as base URLs project keys.\n\n```ts\nconst url = transformUrl(\n\tsrc,\n\t{\n\t\twidth: 800,\n\t\theight: 600,\n\t\tfallback: \"cloudinary\",\n\t},\n\t{\n\t\tshopify: {\n\t\t\tcrop: \"left\",\n\t\t},\n\t},\n\t{\n\t\tcloudinary: {\n\t\t\tcloudName: \"demo\",\n\t\t},\n\t},\n);\n```\n\n## Provider imports\n\nIf you know which providers you will be using, you can import them directly.\nThis will reduce the bundle size of your application, as only the providers you\nuse will be included. In this case you can pass provider-specific operations in\nthe object.\n\n```ts\nimport { transform } from \"unpic/providers/shopify\";\n\nconst url = transform(\n\t\"https://cdn.shopify.com/static/sample-images/bath.jpeg\",\n\t{\n\t\twidth: 800,\n\t\theight: 600,\n\t\tcrop: \"center\",\n\t},\n);\n```\n\n## Supported Providers\n\n- Adobe Dynamic Media (Scene7) `scene7`\n- Astro image service `astro`\n- Builder.io `builder.io`\n- Bunny.net, including caisy `bunny`\n- Cloudflare `cloudflare` and `cloudflare_images`\n- Cloudimage `cloudimage`\n- Cloudinary `cloudinary`\n- Contentful `contentful`\n- Contentstack `contentstack`\n- Directus `directus`\n- Hygraph `hygraph`\n- ImageEngine `imageengine`\n- ImageKit `imagekit`\n- Imgix, including Unsplash, DatoCMS, Sanity and Prismic `imgix`\n- IPX `ipx`\n- KeyCDN `keycdn`\n- Kontent.ai `kontent.ai`\n- Netlify `netlify`\n- Next.js image service `nextjs`\n- Shopify `shopify`\n- Storyblok `storyblok`\n- Supabase `supabase`\n- Uploadcare `uploadcare`\n- Vercel `vercel`\n- WordPress.com and Jetpack Site Accelerator `wordpress`\n\n## FAQs\n\n- **What is an image CDN?** An image CDN is a service that provides a URL API\n  for transforming images. This is often used to resize images on the fly, but\n  can also be used to apply other transforms such as cropping, rotation,\n  compression, etc. This includes dedicated image CDNs such as Imgix and\n  Cloudinary, CMSs such as Contentful, Builder.io and Sanity, general CDNs such\n  as Bunny.net that provide an image API, but also other service providers such\n  as Shopify. The CMSs and other service providers often use a dedicated image\n  CDN to provide the image API, most commonly Imgix. In most cases they support\n  the same API, but in others they may proxy the image through their own CDN, or\n  use a different API.\n\n- **Why would I use this instead of the CDN's own SDK?** If you you know that\n  your images will all come from one CDN, then you probably should use the CDN's\n  own SDK. This library is designed to work with images from multiple CDNs, and\n  to work with images that may or may not be from a CDN. It is particularly\n  useful for images that may come from an arbitrary source, such as a CMS. It is\n  also useful for parsing URLs that may already have transforms applied, because\n  most CDN SDKs will not parse these URLs correctly.\n\n- **Can you add support for CDN X?** If it supports a URL API and doesn't\n  require signed URLs then yes, please open an issue or PR.\n\n- **Can you add my domain to CDN X?** If you provide a service where end-users\n  use your URLs then probably. Examples may be image providers such as Unsplash,\n  or CMSs. If it is just your own site then probably not. You can manually\n  specify the provider in the arguments to `transformUrl` and `parseUrl`.\n\n- **What params can I use?** The library provides a standard set of operations\n  (`width`, `height`, `format`, `quality`) that work across all providers. You\n  can also use provider-specific operations by passing them as the third\n  argument to `transformUrl`. These are fully type-safe - your IDE will show you\n  which operations are available for each provider.\n\n- **Why do you set auto format?** If the CDN support is, and no format is\n  specified in `transformUrl`, the library will remove any format set in the\n  source image, changing it to auto-format. In most cases, this is what you\n  want. Almost all browsers now support modern formats such as WebP, and setting\n  auto-format will allow the CDN to serve the best format for the browser. If\n  you want to force a specific format, you can set it in `transformUrl`.\n\n- **Why do you set fit=cover (or equivalent)?** If the CDN supports it, and no\n  fit is specified in `transformUrl`, the library will set fit to cover. This is\n  because in most cases you want the image to fill the space, rather than be\n  contained within it. Every CDN has its own syntax for this, so it's best if we\n  set a default that applies to all images. If you want to force a specific fit,\n  you can set it in `transformUrl`.\n\n- **Do you support SVG, animated GIF etc?** If the CDN supports it, then yes. We\n  don't attempt to check if a format is valid - we will just pass it through to\n  the CDN. If the CDN doesn't support it, then it will return an error or a\n  default.\n\n- **Do you support video, etc?** No, this library is only for images. If you\n  pass a video URL to `transformUrl`, it will return `undefined`, as it will for\n  any URL that is not recognised as an image CDN URL. It is up to you to handle\n  this case.\n\n## Contributing\n\nSee the [contributing guide](CONTRIBUTING.md).\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fascorbic%2Funpic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fascorbic%2Funpic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fascorbic%2Funpic/lists"}