{"id":50956351,"url":"https://github.com/dkosarevsky/ajpegli","last_synced_at":"2026-06-18T07:03:45.051Z","repository":{"id":358722328,"uuid":"1242451165","full_name":"dKosarevsky/ajpegli","owner":"dKosarevsky","description":"Fast JPEG-to-NumPy image loading powered by Google jpegli","archived":false,"fork":false,"pushed_at":"2026-05-18T21:33:41.000Z","size":139,"stargazers_count":3,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-18T21:34:53.225Z","etag":null,"topics":["albumentations","augmentation","computer-vision","image","image-classification","image-load","image-loader","image-loading","image-loading-library","image-processing","images","python","pytorch","tensorflow"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/ajpegli","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dKosarevsky.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":"docs/roadmap.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-18T12:45:35.000Z","updated_at":"2026-05-18T21:32:31.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dKosarevsky/ajpegli","commit_stats":null,"previous_names":["dkosarevsky/ajpegli"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/dKosarevsky/ajpegli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dKosarevsky%2Fajpegli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dKosarevsky%2Fajpegli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dKosarevsky%2Fajpegli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dKosarevsky%2Fajpegli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dKosarevsky","download_url":"https://codeload.github.com/dKosarevsky/ajpegli/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dKosarevsky%2Fajpegli/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34479555,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-18T02:00:06.871Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["albumentations","augmentation","computer-vision","image","image-classification","image-load","image-loader","image-loading","image-loading-library","image-processing","images","python","pytorch","tensorflow"],"created_at":"2026-06-18T07:03:44.163Z","updated_at":"2026-06-18T07:03:45.043Z","avatar_url":"https://github.com/dKosarevsky.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ajpegli\n\n[![PyPI package](https://img.shields.io/pypi/v/ajpegli?label=pypi%20package)](https://pypi.org/project/ajpegli/)\n[![CI](https://img.shields.io/github/actions/workflow/status/dKosarevsky/ajpegli/ci.yml?branch=main\u0026label=CI\u0026logo=github)](https://github.com/dKosarevsky/ajpegli/actions/workflows/ci.yml)\n[![ruff](https://img.shields.io/github/actions/workflow/status/dKosarevsky/ajpegli/ruff.yml?branch=main\u0026label=ruff)](https://github.com/dKosarevsky/ajpegli/actions/workflows/ruff.yml)\n[![ty](https://img.shields.io/github/actions/workflow/status/dKosarevsky/ajpegli/ty.yml?branch=main\u0026label=ty)](https://github.com/dKosarevsky/ajpegli/actions/workflows/ty.yml)\n[![PyPI downloads](https://img.shields.io/pypi/dm/ajpegli?label=PyPI%20downloads)](https://pypistats.org/packages/ajpegli)\n![Coverage](badges/coverage.svg)\n[![License: BSD-3-Clause](https://img.shields.io/badge/license-BSD--3--Clause-blue.svg)](LICENSE)\n\nFast JPEG-to-NumPy image loading powered by Google jpegli.\n\n`ajpegli` is a dependency-light JPEG loader for Python: pass a file path or\npreloaded JPEG bytes, get a NumPy array. Decoding is powered by Google jpegli\nand built for high-throughput data pipelines. The path API is `cv2.imread`-like,\nbut it is not a drop-in OpenCV replacement: color images are returned as RGB by\ndefault. Pass `mode=\"BGR\"` for OpenCV-style pipelines.\n\nCurrent status: stable Python API. `imread()` and `imdecode()` are the primary\nloading APIs, with `encode()` and `info()` available for production use in the\ndocumented v1 scope. Benchmarks are published as measured regression baselines,\nnot as claims that `ajpegli` is faster than OpenCV or Pillow.\n\n## Development\n\nClone with submodules before building native wheels:\n\n```bash\ngit submodule update --init --recursive\nuv sync --extra dev\njust check\njust build\njust bench-imread\n```\n\n`third_party/jpegli` is pinned as a submodule. The pinned commit is exposed at\nruntime through `ajpegli.__jpegli_commit__` and `ajpegli.jpegli_commit()`.\n\nRelease and publishing instructions live in [releasing.md](docs/releasing.md).\n\n## Installation\n\nInstall from PyPI:\n\n```bash\npip install ajpegli\n```\n\nWith uv:\n\n```bash\nuv add ajpegli\n```\n\n## Quickstart\n\najpegli ships prebuilt wheels for common Linux, macOS, and Windows CPython\nbuilds. NumPy is the only runtime dependency.\n\n```python\nimport ajpegli\n\nimage = ajpegli.imread(\"image.jpg\")\nassert image.dtype == \"uint8\"\nassert image.ndim == 3\n\nrgb = ajpegli.imread(\"image.jpg\", mode=\"RGB\")  # default\nbgr = ajpegli.imread(\"image.jpg\", mode=\"BGR\")  # for OpenCV-style pipelines\ngray = ajpegli.imread(\"image.jpg\", mode=\"L\")\n\nwith open(\"image.jpg\", \"rb\") as file:\n    data = file.read()\n\nrgb_from_memory = ajpegli.imdecode(data, mode=\"RGB\")\nbgr_from_memory = ajpegli.imdecode(data, mode=\"BGR\")\n\njpeg = ajpegli.encode(rgb_from_memory, quality=90, progressive=2)\nheader = ajpegli.info(jpeg)\nassert header.width == rgb_from_memory.shape[1]\n```\n\n`imread()` reads the file in the native extension and returns a NumPy array.\n`imdecode()` accepts JPEG `bytes` or another bytes-like object and decodes from\nmemory with the same mode options. `decode()` is kept as an equivalent alias.\nThe v1 decode API supports `uint8` RGB, BGR, grayscale, CMYK, and native output\nmodes. File I/O and jpegli decode work release the GIL so threaded callers and\nDataLoader workers do not serialize on Python while the native codec is\nrunning.\n\n## RAM / bytes decode\n\nUse `imdecode()` when the benchmark or input pipeline has already loaded JPEG\nbytes into memory:\n\n```python\nfrom pathlib import Path\n\nimport ajpegli\n\ndata = Path(\"image.jpg\").read_bytes()\nimage = ajpegli.imdecode(data, mode=\"RGB\")\n```\n\n`imdecode()` is the direct comparison point for `cv2.imdecode()`. It accepts\n`bytes`, `bytearray`, `memoryview`, and contiguous NumPy `uint8` buffers without\nmaking a Python-side copy before entering the native decoder.\n\nNumPy is the only runtime dependency. OpenCV, Pillow, and PyTorch are optional\nbenchmark tools and are not required by `pip install ajpegli`.\n\n## Encode and Info\n\n`encode()` writes JPEG bytes from `uint8` NumPy arrays. The stable v1 encode\nscope is grayscale (`HxW` or `HxWx1`) and RGB (`HxWx3`) input with explicit\nalpha rejection unless `alpha=\"drop\"` is passed. It supports quality,\ndistance/PSNR controls, progressive level, RGB subsampling, adaptive\nquantization, and raw ICC/EXIF/XMP/comment marker writing. `info()` reads JPEG\nheaders without full image decode and returns `JpegInfo` dimensions, component\ncount, mode, progressive flag, subsampling, density, and ICC/EXIF/XMP presence.\n\nUnsupported paths fail explicitly instead of silently changing data. `uint16`,\n`float32`, `float16`, CMYK encode, XYB encode, and parsed EXIF metadata are\noutside the v1 stable scope.\n\n## Stability Contract\n\nStarting with `1.0.0`, ajpegli follows SemVer for the documented Python API.\nFunction names, keyword names, default values, exception classes, and return\ntypes documented in this README are stable across `1.x`. The private\n`ajpegli._ajpegli` extension module is not public API.\n\nThe exact JPEG bitstream produced by `encode()` and benchmark throughput are\nnot part of the stability contract: both can change when the pinned jpegli\ncommit changes. Runtime dependencies stay limited to NumPy throughout `1.x`\nunless a future major version changes that contract.\n\nFor local source builds, clone with submodules:\n\n```bash\ngit clone --recursive https://github.com/dKosarevsky/ajpegli.git\ncd ajpegli\nuv sync --extra dev\njust check\n```\n\n## Benchmarks\n\nThe benchmark script keeps comparison tools optional so `pip install ajpegli`\nonly needs NumPy at runtime. See [Benchmarks](docs/benchmarks.md),\n[Benchmark Results](docs/benchmark-results.md),\n[DataLoader Benchmarking](docs/dataloader.md), and\n[DataLoader Results](docs/dataloader-results.md).\n\n```bash\njust bench-imread path/to/a.jpg 1000 8 RGB ajpegli,cv2,pillow\njust bench-imread-dataloader path/to/a.jpg 1000 4 RGB 32\n```\n\n`benchmarks/bench_imread.py` reports JSON with sequential throughput, threaded\nthroughput, and optional PyTorch `DataLoader` throughput. Missing optional\ncomparison packages are reported as skipped entries instead of failing the run.\nUse `--thread-workers` for threaded reader throughput and\n`--dataloader-workers` for PyTorch `DataLoader` worker count. Use\n`--source bytes` when benchmarking preloaded JPEG bytes from RAM instead of\npath reads.\nThe checked-in reports are intentionally honest: on the current vendored smoke\ncorpora, OpenCV and Pillow are still faster than `ajpegli`. Treat them as\nregression baselines and do not make project-level speed claims without broader\ndataset-specific measurements.\n\nFor local comparison runs, install only what you want to measure in that\nenvironment:\n\n```bash\nuv pip install opencv-python-headless pillow\nuv pip install torch  # only for --include-dataloader\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdkosarevsky%2Fajpegli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdkosarevsky%2Fajpegli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdkosarevsky%2Fajpegli/lists"}