{"id":20287622,"url":"https://github.com/rhettbull/cgmetadata","last_synced_at":"2025-09-10T03:38:19.533Z","repository":{"id":204360867,"uuid":"711547677","full_name":"RhetTbull/CGMetadata","owner":"RhetTbull","description":"Use native ImageIO / Core Graphics API on macOS from Python to access and change image metadata","archived":false,"fork":false,"pushed_at":"2024-10-01T12:35:26.000Z","size":78667,"stargazers_count":4,"open_issues_count":4,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-08-20T23:57:42.329Z","etag":null,"topics":["apple","cli","image","mac","macos","metadata","osx","python","python3"],"latest_commit_sha":null,"homepage":"","language":"Python","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/RhetTbull.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.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":"2023-10-29T15:51:18.000Z","updated_at":"2025-06-19T17:13:11.000Z","dependencies_parsed_at":null,"dependency_job_id":"10d614af-9096-480b-8407-a08897cf9a1a","html_url":"https://github.com/RhetTbull/CGMetadata","commit_stats":{"total_commits":36,"total_committers":1,"mean_commits":36.0,"dds":0.0,"last_synced_commit":"ed082c2d6ba4c690a042833663e926f7cc21799a"},"previous_names":["rhettbull/cgmetadata"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/RhetTbull/CGMetadata","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RhetTbull%2FCGMetadata","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RhetTbull%2FCGMetadata/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RhetTbull%2FCGMetadata/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RhetTbull%2FCGMetadata/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/RhetTbull","download_url":"https://codeload.github.com/RhetTbull/CGMetadata/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/RhetTbull%2FCGMetadata/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274407513,"owners_count":25279298,"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","status":"online","status_checked_at":"2025-09-10T02:00:12.551Z","response_time":83,"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":["apple","cli","image","mac","macos","metadata","osx","python","python3"],"created_at":"2024-11-14T14:41:06.229Z","updated_at":"2025-09-10T03:38:19.511Z","avatar_url":"https://github.com/RhetTbull.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CGMetadata\n\nRead and write image metadata on macOS from Python using the native [ImageIO / Core Graphics frameworks](https://developer.apple.com/documentation/imageio).\n\nCGMetadata is a Python wrapper around the macOS ImageIO and Core Graphics frameworks. It provides a simple interface for reading and writing image metadata, including EXIF, IPTC, and XMP data. Reading is supported for all image formats supported by ImageIO. Reading is also supported for video formats using AVFoundation.\n\nWriting is not currently supported for RAW file formats nor for video formats.  Writing of metadata has been tested on JPEG, PNG, TIFF, and HEIC files however it should be considered experimental. If you are using CGMetadata to write metadata to image files, please make sure you have tested the results before using it in production.\n\n## Synopsis\n\n\u003c!--\nSetup for doctest:\n\n```pycon\n\u003e\u003e\u003e import shutil\n\u003e\u003e\u003e import os\n\u003e\u003e\u003e try:\n...     os.remove(\"test.jpeg\")\n... except Exception:\n...     pass\n...\n\u003e\u003e\u003e try:\n...     os.remove(\"test.xmp\")\n... except Exception:\n...     pass\n...\n\u003e\u003e\u003e try:\n...     os.remove(\"test.MOV\")\n... except Exception:\n...     pass\n...\n\u003e\u003e\u003e  \n\u003e\u003e\u003e cwd = os.getcwd()\n\u003e\u003e\u003e _ = shutil.copy(\"tests/data/test.jpeg\", os.path.join(cwd, \"test.jpeg\"))\n\u003e\u003e\u003e \n\u003e\u003e\u003e _ = shutil.copy(\"tests/data/test.MOV\", os.path.join(cwd, \"test.MOV\"))\n\u003e\u003e\u003e \n```\n--\u003e\n\n```pycon\n\u003e\u003e\u003e from cgmetadata import ImageMetadata, VideoMetadata, IPTC, XMP\n\u003e\u003e\u003e md = ImageMetadata(\"test.jpeg\")\n\u003e\u003e\u003e md.exif[\"LensMake\"]\n'Apple'\n\u003e\u003e\u003e md.iptc[\"Keywords\"]\n['fruit', 'tree']\n\u003e\u003e\u003e md.xmp[\"dc:description\"]\n['A pair of pears on a tree']\n\u003e\u003e\u003e # get XMP sidecar as a str\n\u003e\u003e\u003e xmp = md.xmp_dumps()\n\u003e\u003e\u003e # write an XMP sidecar file for the image\n\u003e\u003e\u003e with open(\"test.xmp\", \"w\") as f:\n...     md.xmp_dump(f)\n...\n\u003e\u003e\u003e # read metadata from  XMP sidecar file and apply to image\n\u003e\u003e\u003e with open(\"test.xmp\", \"r\") as f:\n...     md.xmp_load(f)\n...\n\u003e\u003e\u003e \n\u003e\u003e\u003e md.write()\n\u003e\u003e\u003e # set metadata\n\u003e\u003e\u003e md.set(XMP, \"dc:description\", [\"Test image\"])\n\u003e\u003e\u003e md.set(IPTC, \"Keywords\", [\"foo\", \"bar\"])\n\u003e\u003e\u003e md.write()\n\u003e\u003e\u003e md.xmp[\"dc:description\"]\n['Test image']\n\u003e\u003e\u003e md.iptc[\"Keywords\"]\n['foo', 'bar']\n\u003e\u003e\u003e \n\u003e\u003e\u003e # update values with context manager\n\u003e\u003e\u003e with ImageMetadata(\"test.jpeg\") as md:\n...     md.set(IPTC, \"Keywords\", [\"Fizz\", \"Buzz\"])\n...     md.set(XMP, \"dc:creator\", [\"CGMetadata\"])\n...\n\u003e\u003e\u003e md.iptc[\"Keywords\"]\n['Fizz', 'Buzz']\n\u003e\u003e\u003e \n\u003e\u003e\u003e # read metadata from video file\n\u003e\u003e\u003e md = VideoMetadata(\"test.MOV\")\n\u003e\u003e\u003e md.xmp.get(\"dc:subject\")\n['Coffee', 'Espresso']\n\u003e\u003e\u003e \n```\n\nCGMetadata also include a utility function for reading an XMP file and returning a dictionary of metadata using native macOS APIs. This may be useful by itself as it doesn't require the use of external libraries or XML parsers.\n\n\u003c!--\nSetup for doctest:\n\n```pycon\n\u003e\u003e\u003e import shutil\n\u003e\u003e\u003e import os\n\u003e\u003e\u003e try:\n...     os.remove(\"test.xmp\")\n... except Exception:\n...     pass\n...\n\u003e\u003e\u003e  \n\u003e\u003e\u003e cwd = os.getcwd()\n\u003e\u003e\u003e _ = shutil.copy(\"tests/data/test.MOV.xmp\", os.path.join(cwd, \"test.xmp\"))\n\u003e\u003e\u003e \n```\n--\u003e\n\n```pycon\n\u003e\u003e\u003e from cgmetadata import metadata_dictionary_from_xmp_packet\n\u003e\u003e\u003e xmp_data = open(\"test.xmp\").read()\n\u003e\u003e\u003e metadata_dictionary_from_xmp_packet(xmp_data)\n{'dc:subject': ['Coffee', 'Espresso'], 'iio:hasXMP': 'True'}\n\u003e\u003e\u003e\n```\n\n## Installation\n\n```bash\npip install cgmetadata\n```\n\n## Documentation\n\nThe documentation for CGMetadata is available at [https://RhetTbull.github.io/CGMetadata/](https://RhetTbull.github.io/CGMetadata/).\n\n## Source Code\n\nThe source code for this project is available on [GitHub](https://github.com/RhetTbull/CGMetadata).\n\n## Command Line Interface\n\nThe package will install a small command line interface (CLI), `cgmd`, which prints\nmetadata for an image file in tabular, JSON, CSV, TSV, or XMP formats. The CLI can also\nbe run by executing `python3 -m cgmetadata`.\n\n```\nusage: cgmd [-h] [--version] [--csv] [--tsv] [--json] [--xmp] [--indent INDENT] [--no-header] IMAGE_OR_VIDEO\n\nPrint metadata for image files in various formats.\n\npositional arguments:\n  IMAGE_OR_VIDEO        path to image or video file\n\noptions:\n  -h, --help            show this help message and exit\n  --version, -v         show program's version number and exit\n  --csv, -c             output as comma separated values (CSV); see also --no-header\n  --tsv, -t             output as tab separated values (TSV); see also --no-header\n  --json, -j            output as JSON; see also --indent\n  --xmp, -x             output XMP sidecar for image; see also --no-header\n  --indent INDENT, -i INDENT\n                        indent level for JSON; default 4, use 0 for no indentation\n  --no-header, -H       when used with --csv, --tsv, omit column headers; when used with --xmp, omit XMP packet header\n```\n\n## Supported Versions\n\nCGMetadata has been tested on macOS 13 (Ventura) but should work on macOS 11 (Big Sur) and later. It will not work on earlier versions of macOS due to the use of certain APIs that were introduced in macOS 11. It is compatible with Python 3.9 and later.\n\n## License\n\nMIT License, copyright Rhet Turnbull, 2023.\n\n\u003c!--\nCleanup for doctest:\n\n```pycon\n\u003e\u003e\u003e import os\n\u003e\u003e\u003e os.remove(\"test.jpeg\")\n\u003e\u003e\u003e os.remove(\"test.xmp\")\n\u003e\u003e\u003e os.remove(\"test.MOV\")\n\u003e\u003e\u003e \n```\n--\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhettbull%2Fcgmetadata","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frhettbull%2Fcgmetadata","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frhettbull%2Fcgmetadata/lists"}