{"id":13508384,"url":"https://github.com/yuce/png","last_synced_at":"2025-07-23T16:08:30.116Z","repository":{"id":57535345,"uuid":"38942436","full_name":"yuce/png","owner":"yuce","description":"A pure Erlang library for creating PNG images. It can currently create 8 and 16 bit RGB, RGB with alpha, indexed, grayscale and grayscale with alpha images.","archived":false,"fork":false,"pushed_at":"2020-06-03T19:34:28.000Z","size":24,"stargazers_count":57,"open_issues_count":1,"forks_count":10,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-07-12T03:49:28.471Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yuce.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-11T22:24:03.000Z","updated_at":"2024-12-03T00:18:48.000Z","dependencies_parsed_at":"2022-08-29T00:30:19.769Z","dependency_job_id":null,"html_url":"https://github.com/yuce/png","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/yuce/png","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yuce%2Fpng","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yuce%2Fpng/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yuce%2Fpng/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yuce%2Fpng/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yuce","download_url":"https://codeload.github.com/yuce/png/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yuce%2Fpng/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266708514,"owners_count":23971946,"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-07-23T02:00:09.312Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"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":[],"created_at":"2024-08-01T02:00:52.335Z","updated_at":"2025-07-23T16:08:30.093Z","avatar_url":"https://github.com/yuce.png","language":"Erlang","funding_links":[],"categories":["Images"],"sub_categories":[],"readme":"png\n=====\n\n**png** is a pure Erlang library for creating PNG images. It can currently create *8* and *16* bit *RGB*, *RGB with alpha*, *indexed*, *grayscale* and *grayscale with alpha* images.\n\nInstall (Erlang)\n----------------\n\n**png** requires at least Erlang 17.0, since it uses maps.\n\nInclude the library in your *rebar* configuration:\n\n    {deps, [\n        {png, \".*\", {git, \"https://github.com/yuce/png.git\", \"master\"}}]}.\n\nAlternatively, for *rebar 3*:\n\n    {deps, [png]}.\n\n\nTaster\n------\n\n```erlang\nrandom:seed(erlang:now()),\nWidth = 30,\nHeight = 30,\n% define an 8bit RGB palette with 4 colors:\nPalette = {rgb, 8, [{255, 0, 0}, {128, 255, 128}, {64, 64, 255}, {0, 0, 0}]},\n{ok, File} = file:open(\"sample.png\", [write]),\n\n% We create an 8bit indexed PNG\nPng = png:create(#{size =\u003e {Width, Height},\n                   mode =\u003e {indexed, 8},\n                   file =\u003e File,\n                   palette =\u003e Palette}),\n\n% make the png image row by row\nAppendRow = fun(_) -\u003e\n                % An image row is composed of palette indices for indexed PNGs\n                Row = lists:map(fun(_) -\u003e random:uniform(4) - 1 end,\n                                    lists:seq(1, Width)),\n                png:append(Png, {row, Row}) end,\nlists:foreach(AppendRow, lists:seq(1, Height)),\n% need to finalize the image\nok = png:close(Png),\nok = file:close(File).\n```\n\nMini-Tutorial\n-------------\n\nCreating a PNG image using **png** is a 3-step process:\n\n1. Pass configuration and initialize the image,\n2. Append the pixels, row by row or all at once,\n3. Finalize the image.\n\nThe configuration currently is a `map` which consists of the dimensions (size) of the image, color mode and bits per pixel (or index), an optional palette (for indexed PNGs) and finally a callback which is called every time **png** needs to write some data.\n\n```erlang\nWidth = 100,\nHeight = 150,\nColorMode = indexed,\nBits = 8,\nPalette = {ColorMode, Bits, [{255, 0, 0}, {0, 0, 128}]},\nCallback = fun(IoData) -\u003e io:format(\"Received: ~p~n\", [IoData]) end,\nConfig = #{size =\u003e {Width, Height},\n           mode =\u003e {ColorMode, Bits},\n           palette =\u003e Palette,\n           call =\u003e Callback},\n```\n\nThere is a shortcut for writing to a file instead of a callback, using the `file` key:\n\n```erlang\n{ok, File} = file:open(\"my.png\", [write]),\nConfig = #{size =\u003e {Width, Height},\n           mode =\u003e {ColorMode, Bits},\n           palette =\u003e Palette,\n           file =\u003e File},\n```\n\nOnce we have the configuration, let's start creating the image:\n\n```erlang\nPng = png:create(Config),\n```\n\n`png:create` writes the PNG header and the palette to the callback or the file and returns a `map` with the configuration + some state data.\n\nNext step is appending pixels to the image.\n\nThe representation of a pixel depends on the *color mode* and *bits*. Here's a summary of currently supported image modes:\n\nColor Mode Name  | Color Mode        | Bits | Representation\n------------------|-------------------|------|---------------\nGrayscale         | `grayscale`       |   8  | `\u003c\u003cL:8\u003e\u003e`\nGrayscale + Alpha | `grayscale_alpha` |   8  | `\u003c\u003cL:8, A:8\u003e\u003e`\nIndexed           | `indexed`         |   8  | `\u003c\u003cI:8\u003e\u003e`\nRGB               | `rgb`             |   8  | `\u003c\u003cR:8, G:8, B:8\u003e\u003e`\nRGB + Alpha       | `rgba`            |   8  | `\u003c\u003cR:8, G:8, B:8, A:8\u003e\u003e`\nGrayscale         | `grayscale`       |  16  | `\u003c\u003cL:16\u003e\u003e`\nGrayscale + Alpha | `grayscale_alpha` |  16  | `\u003c\u003cL:16, A:16\u003e\u003e`\nIndexed           | `indexed`         |  16  | `\u003c\u003cI:16\u003e\u003e`\nRGB               | `rgb`             |  16  | `\u003c\u003cR:16, G:16, B:16\u003e\u003e`\nRGB + Alpha       | `rgba`            |  16  | `\u003c\u003cR:16, G:16, B:16, A:16\u003e\u003e`\n\nWhere, `L` is the luminance, `A` is alpha (*opacity*), `I` is the palette index, `R`, `G` and `B` are red, green and blue respectively.\n\nA palette is required for `indexed` images. The palette is represented as a tuple of color mode, bits and list of red, green, blue tuples:\n\n```erlang\nColorMode = indexed,\nBits = 8,\nRed = {255, 0, 0},\nGreen = {0, 255, 0},\nBlue = {0, 0, 255},\nBlack = {0, 0, 0},\nPalette = {ColorMode, Bits, [Red, Green, Blue, Black]},\n```\n\n**png** supports adding pixels row by row (PNG specification uses the term *scanline*), a list of rows or as raw data. Being able to add partial image data is important when you want to keep the required memory low, e.g., creating an image on the fly in response to a web request and sending it in chunks.\n\nHere are supported data layouts:\n\nName     | Atom | Data Type       | Example\n---------|------|-----------------|--------\nA Row    | row  | binary          | `{row, \u003c\u003c1, 2, 3\u003e\u003e}`\nRows     | rows | binary list     | `{rows, [\u003c\u003c1, 2, 3\u003e\u003e, \u003c\u003c2, 3, 1\u003e\u003e]}`\nRaw data | data | binary          | `{data, \u003c\u003c0, 1, 2, 3\u003e\u003e}`\n\nNote that, each row (*scanline*) must start with a *filter method ID*. Currently only filter `0` (no filter) is supported (see [PNG specification](http://www.libpng.org/pub/png/spec/1.2/PNG-DataRep.html#DR.Filtering) for more information). For `row` and `rows`, **png** prepends the filter method ID to each row, but for `data`, you must prepend `0` to every row yourself.\n\nAppending image data is done with `png:append` (*surprise!*). An example:\n\n```erlang\nData = {row, \u003c\u003c1, 2, 3\u003e\u003e},\nPng = png:append(Png, Data),\n```\n\nYou can call `png:append` as much as as necessary. After appending all data, you must finalize the image with `png:close`:\n\n```erlang\nok = png:close(Png)\n```\n\nExamples\n--------\n\nThere are some examples on https://github.com/yuce/png/tree/master/examples which show the usage and adding PNG chunks manually.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyuce%2Fpng","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyuce%2Fpng","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyuce%2Fpng/lists"}