{"id":17086063,"url":"https://github.com/smileychris/django-easy-images","last_synced_at":"2025-04-12T21:07:53.221Z","repository":{"id":19347236,"uuid":"22586452","full_name":"SmileyChris/django-easy-images","owner":"SmileyChris","description":null,"archived":false,"fork":false,"pushed_at":"2024-08-06T04:13:56.000Z","size":305,"stargazers_count":13,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-09T10:06:11.947Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://pypi.org/project/django-easy-images","language":"Python","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/SmileyChris.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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}},"created_at":"2014-08-03T23:51:09.000Z","updated_at":"2025-01-19T09:48:53.000Z","dependencies_parsed_at":"2024-05-08T22:42:11.486Z","dependency_job_id":"aed8ef78-ade5-4a62-a14f-6ae027079f2a","html_url":"https://github.com/SmileyChris/django-easy-images","commit_stats":null,"previous_names":["smileychris/django-easy-images"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmileyChris%2Fdjango-easy-images","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmileyChris%2Fdjango-easy-images/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmileyChris%2Fdjango-easy-images/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SmileyChris%2Fdjango-easy-images/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SmileyChris","download_url":"https://codeload.github.com/SmileyChris/django-easy-images/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248631677,"owners_count":21136562,"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":[],"created_at":"2024-10-14T13:27:00.919Z","updated_at":"2025-04-12T21:07:53.213Z","avatar_url":"https://github.com/SmileyChris.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# Django easy images\n\nEasily build responsive HTML `\u003cimg\u003e` tags by thumbnailing Django images using the VIPS fast image processing library.\n\nWhen an `\u003cimg\u003e` is generated, any thumbnails that don't already exist are queued for building (if aren't already queued) and left out of the HTML.\nFor example, an image built from `Img(width=\"md\")` will generate:\n\n```html\n\u003cimg src=\"/media/img/profiles/john.jpg\" alt=\"Profile photo for John Doe\"\u003e\n```\n\nBut after the images are built, the HTML will be:\n\n```html\n\u003cimg\n  src=\"/media/img/thumbs/f52fbd32b2b3b86ff88ef6c490628285.jpg\"\n  srcset=\"\n    /media/img/thumbs/18183dd9009f2b7e1b44f9c4af287589.webp,\n    /media/img/thumbs/fb8c2e2b85ca81eb4350199faddd983c.webp 2x\n  \"\n  alt=\"Profile photo for John Doe\"\n\u003e\n```\n\n## Installation \u0026 Configuration\n\nTo install django-easy-images, simply run the following command:\n\n```bash\npip install django-easy-images\n```\n\nOnce installed, add the `easy_images` app in your Django settings file:\n\n```python\nINSTALLED_APPS = [\n    \"easy_images\",\n    # ...\n]\n```\nSince this uses pyvips, you'll need to have the [libvips library installed on your system](https://www.libvips.org/install.html).\n\n## Documentation\n\nProject documentation is built using [mkdocs](https://www.mkdocs.org/). To build and serve the documentation locally:\n\n```bash\npip install mkdocs\nmkdocs serve\n```\n\nThen open http://localhost:8000 in your browser.\n\nThe documentation includes:\n- Usage examples\n- API reference\n- Configuration options\nSince this uses pyvips, you'll need to have the [libvips library installed on your system](https://www.libvips.org/install.html).\n\n\u003ctable\u003e\n\n\u003ctr\u003e\n\u003ctd\u003eMacOs\u003c/td\u003e\n\u003ctd\u003e\n\u003ccode\u003e\nbrew install vips\n\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\n\u003ctr\u003e\n\u003ctd\u003eUbuntu\u003c/td\u003e\n\u003ctd\u003e\n\u003ccode\u003e\nsudo apt-get install --no-install-recommends libvips\n\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\n\u003ctr\u003e\n\u003ctd\u003eArch\u003c/td\u003e\n\u003ctd\u003e\n\u003ccode\u003e\nsudo pacman -S libvips\n\u003c/code\u003e\n\u003c/td\u003e\n\u003c/tr\u003e\n\n\u003c/table\u003e\n\n## Usage\n\nYou use the `Img` class or `{% img %}` template tag to render a Django FieldFile (or ImageFieldFile) containing an image as a responsive HTML `\u003cimg\u003e` tag.\n\n### Summary\n\n1. Define your `Img` classes in your app's `images.py` file.\n2. Use these in your views / templates to generate the `\u003cimg\u003e` tags.\n3. Either set up a cron job to run the `build_img_queue` management command to build images, or use a celery task and the `queued_img` signal to build images as they are queued.\n4. Optionally, use the `Img.queue` method in your `apps.py` file to queue images for building as soon as they are uploaded (building the src/srcset inline if needed).\n\n### Img class\n\nThe `Img` class is used to create a generator for HTML `\u003cimg\u003e` elements. Here's an example of how to use it:\n\n```python\nfrom easy_images import Img\nthumb = Img(width=\"md\")\nthumb(profile.photo, alt=f\"Profile photo for {{ profile.name }}\").as_html()\n```\n\nAs you can see, `thumb` is an `Img` instance that is used to generate an HTML `\u003cimg\u003e` element for the `profile.photo` image. The output would look something like this:\n\n```html\n\u003cimg\n  src=\"/media/img/thumbs/f52fbd32b2b3b86ff88ef6c490628285.jpg\"\n  srcset=\"\n    /media/img/thumbs/18183dd9009f2b7e1b44f9c4af287589.webp,\n    /media/img/thumbs/fb8c2e2b85ca81eb4350199faddd983c.webp 2x\n  \"\n  alt=\"Profile photo for John Doe\"\n/\u003e\n```\n\nIn the following [options section](#options) you can see all the different options that you can pass to the `Img` instance.\n\nThere other optional arguments that you can pass to the instance:\n\n#### `alt`\n\nThe `alt` text for the image.\n\n#### `build`\n\nDetermines determines what should be built inline. Valid values are:\n\n- `None`: All images will be built out-of-band from the request *(default)*.\n- `\"src\"`: The base `src` image will be built inline, but the `srcset` images will be built out-of-band from the request.\n- `\"srcset\"`: Both the base `src` image and all `srcset` images will be built inline.\n\n#### `img_attrs`\n\nA dictionary of any additional attributes to add to the `\u003cimg\u003e` element.\n\n### The `{% img %}` tag\n\nThe `img` template tag is another way to generate a responsive HTML `\u003cimg\u003e` element.\n\n```jinja\n{% load easy_images %}\n{% img report.image width=\"md\" alt=\"\" %}\n```\n\nYou can also pass a `Img` instance to the `img` template tag:\n\n```jinja\n{% load easy_images %}\n{% img report.image thumb alt=\"\" %}\n```\n\nThe template tag never builds images inline.\n\n## Building images.\n\nWhenever a image is requested, any image versions not already built will be queued for building and excluded from the HTML.\n\nTo build the images in this queue, you can either:\n\n- run the `build_img_queue` management command (usually in a cron job), or\n- process it in a task using celery or another task runner (probably using the [`queued_img` signal](#queued_img-signal)).\n\n## Options\n\nThe `Img` class and the `img` template tag can be called with the following options.\n\n#### `width`\n\nLimit the width of the image. Either use an integer, or one of the following tailwind sizes as a string: \"xs\", \"sm\", \"md\", \"lg\", \"screen-sm\", \"screen-md\", \"screen-lg\", \"screen-xl\" or \"screen-2xl\"\n\n#### `ratio`\n\nThe aspect ratio of the image to build.\n\nUse a float representing the ratio (e.g. `4/5`) or one of the following strings: \"square\", \"video\" (meaning 16/9), \"video_vertical\", \"golden\" (using the golden ratio), \"golden_vertical\".\n\nThe default is `\"video\"` (16/9).\n\n#### `crop`\n\nWhether to crop the image.\n\nThe default is `True`.\n\nUse a boolean, or tuple of two floats, or the comma separated string equivalent. `True` is replaced with to `(0.5, 0.5)` meaning the image is cropped from the center. The numbers are percentages of the image size.\n\nYou can also use the following keywords: `tl` (top left), `tr` (top right), `bl` (bottom left), `br` (bottom right), `l`, `r`, `t` or `b`. This will set the percentage to 0 or 100 for the appropriate axis.\n\nIf crop is `False`, the image will be resized so that it will cover the requested ratio but not cropped down.\nThis is useful when you want to handle positioning in CSS using `object-fit`.\n\n#### `contain`\n\nWhen resizing the image (and not cropping), contain the image within the requested ratio. This ensures it will always fit within the requested dimensions. It also stops the image from being upscaled.\n\nThe default is `False`, meaning the image will be resized down to cover the requested ratio (which means the image dimensions may be larger than the requested dimensions).\n\n#### `focal_window`\n\nA focal window to zoom in on when shrinking the image. Use a tuple of four floats (or a comma separated string equivalent) where the first pair of percentages is the top left corner and the second pair of percentages is the bottom right corner.\n\n#### `quality`\n\nThe quality of the image. For example, `quality=90` means that the image will be compressed with a quality of 90. The default is 80.\n\n#### `densities`\n\nA list of higher density versions of the image to also create.\n\nThe default is `[2]`.\n\n#### `sizes`\n\nA dictionary of sizes to use at different media queries. The keys should either be an integer to represent a max-width, or a string to represent a specific media query. The keys can either be an int/string to represent the width, or a dictionary of options (that must contain a width).\n\nIf `densities` is set, a higher density version of the largest size (excluding 'print' media) will also be built to give the browser more options.\n\nFor example:\n\n```python\nimg_with_sizes = Img(\n    # Base size\n    width=300,\n    # Alternate sizes for different media queries\n    sizes={\n        # Print media query, larger width with higher quality\n        \"print\": {\"width\": 450, \"quality\": 90},\n        # A viewport max width of 800, smaller width.\n        800: 100\n    },\n)\nprint(img_with_sizes(model_instance.image, build=\"srcset\").as_html())\n```\n\nwill output:\n\n```html\n\u003cimg src=\"/media/img/thumbs/08efa8f7b11b7e9b24a037bb3f216369.jpg\" srcset=\"/media/img/thumbs/18183dd9009f2b7e1b44f9c4af287589.webp 100w, /media/img/thumbs/08efa8f7b11b7e9b24a037bb3f216369.webp 300w, /media/img/thumbs/fb8c2e2b85ca81eb4350199faddd983c.webp 450w, /media/img/thumbs/cfca1aebe161e09926c86f76d4e2f1b4.webp 600w\" sizes=\"(print) 450px, (max-width: 800) 100px\" alt=\"\"\u003e\n```\n\n#### `format`\n\nThe image format to build the `srcset` versions with. The valid values are `\"webp\"` *(default)*, `\"avif\"` or `\"jpeg\"`. \nNote that AVIF uses a lot of memory to build images. \n\nThe base `src` image format will always be built as a JPEG for backwards compatibility.\n\n## Signals\n\n### Queue from model.\n\n### `file_post_save` signal\n\nThis signal is triggered for each that `FileField` that was uncommitted when it's model instance is saved.\n\nIt can be used to build \u0026 pre-queue images for a model instance.\n\nThe most simplest usage is via the `Img` instance's helper method called `queue`. Here's an example of using that in a model's `apps.py` file:\n\n```python\nfrom django.apps import AppConfig\n\nfrom my_app.images import thumbnail\n\nclass MyAppConfig(AppConfig):\n    name = 'my_app'\n\n    def ready(self):\n        from my_app.models import Profile\n\n        thumbnail.queue(Profile, build=\"src\")\n```\n\nBy default, `queue` listens for saves to any `ImageField` on the model. Use the `fields` argument to limit which fields to queue images for:\n* `None` means all file fields on the model\n* a field class or subclass that the field must be *(default is `ImageField`)*\n* a list of field names to match (the signal will still only fire on file fields)\n\n### `queued_img` signal\n\nThis signal is triggered whenever an image element is missing and was not already queued for building.\n\nIt can be used to process the queue in a task using celery or another task runner. Here's an example `tasks.py`:\n\n```python\nfrom easy_images.management.process_queue import process_queue\n\n@app.task\ndef build_img_queue():\n    process_queue()\n```\n\nIn your apps `apps.py` file, connect this receiver:\n\n```python\nfrom django.apps import AppConfig\n\nfrom easy_images.signals import queued_img\n\nclass MyAppConfig(AppConfig):\n    name = 'my_app'\n\n    def ready(self):\n        from my_app.tasks import build_img_queue\n\n        # Kick off build task as soon as any image is queued.\n        queued_img.connect(lambda **kwargs: build_img_queue.delay(), weak=False)\n        # Also start the build task as soon as the app is ready in case there are already queued images.\n        build_img_queue.delay()\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmileychris%2Fdjango-easy-images","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmileychris%2Fdjango-easy-images","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmileychris%2Fdjango-easy-images/lists"}