{"id":15494459,"url":"https://github.com/addisonelliott/pypdn","last_synced_at":"2025-10-14T16:10:44.225Z","repository":{"id":54946610,"uuid":"131067648","full_name":"addisonElliott/pypdn","owner":"addisonElliott","description":"Python package to read Paint.NET (PDN) images.","archived":false,"fork":false,"pushed_at":"2024-02-22T03:07:49.000Z","size":2167,"stargazers_count":33,"open_issues_count":3,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-07T05:31:55.686Z","etag":null,"topics":["binaryformatter","nrbf","paint","paintdotnet","pypi","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/addisonElliott.png","metadata":{"files":{"readme":"README.rst","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":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-04-25T21:51:44.000Z","updated_at":"2025-08-08T08:37:45.000Z","dependencies_parsed_at":"2024-10-02T08:14:24.538Z","dependency_job_id":"ae6b3bd9-dc2f-43e2-883f-9c8a9d398d48","html_url":"https://github.com/addisonElliott/pypdn","commit_stats":{"total_commits":73,"total_committers":3,"mean_commits":"24.333333333333332","dds":0.136986301369863,"last_synced_commit":"ebffd52f9b8a56f2e885e1a9c51a58fc4b30e3bb"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/addisonElliott/pypdn","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/addisonElliott%2Fpypdn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/addisonElliott%2Fpypdn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/addisonElliott%2Fpypdn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/addisonElliott%2Fpypdn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/addisonElliott","download_url":"https://codeload.github.com/addisonElliott/pypdn/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/addisonElliott%2Fpypdn/sbom","scorecard":{"id":165963,"data":{"date":"2025-08-11","repo":{"name":"github.com/addisonElliott/pypdn","commit":"3481b08b3579daf8ab50ecbd03f14619b9c76c8c"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.1,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":2,"reason":"Found 6/22 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/generateChangelog.yml:1","Warn: no topLevel permission defined: .github/workflows/pythonpublish.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: third-party GitHubAction not pinned by hash: .github/workflows/generateChangelog.yml:10: update your workflow using https://app.stepsecurity.io/secureworkflow/addisonElliott/pypdn/generateChangelog.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pythonpublish.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/addisonElliott/pypdn/pythonpublish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pythonpublish.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/addisonElliott/pypdn/pythonpublish.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/pythonpublish.yml:23","Warn: pipCommand not pinned by hash: .github/workflows/pythonpublish.yml:24","Warn: pipCommand not pinned by hash: .github/workflows/pythonpublish.yml:25","Info:   0 out of   2 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   3 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":4,"reason":"6 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2021-856 / GHSA-5545-2q6w-2gh6","Warn: Project is vulnerable to: GHSA-6p56-wp2h-9hxr","Warn: Project is vulnerable to: PYSEC-2019-108 / GHSA-9fq2-x9r6-wfmf","Warn: Project is vulnerable to: PYSEC-2021-857 / GHSA-f7c7-j99h-c22f","Warn: Project is vulnerable to: GHSA-fpfv-jqm9-f5jm","Warn: Project is vulnerable to: PYSEC-2017-1 / GHSA-frgw-fgh6-9g52"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 16 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-16T14:52:10.214Z","repository_id":54946610,"created_at":"2025-08-16T14:52:10.214Z","updated_at":"2025-08-16T14:52:10.214Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279019555,"owners_count":26086749,"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-10-14T02:00:06.444Z","response_time":60,"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":["binaryformatter","nrbf","paint","paintdotnet","pypi","python","python3"],"created_at":"2024-10-02T08:14:18.548Z","updated_at":"2025-10-14T16:10:44.190Z","avatar_url":"https://github.com/addisonElliott.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"Introduction\n=================\npypdn is a Python package for reading Paint.NET (PDN) images.\n\n\"Paint.NET is image and photo editing software for PCs that run Windows. It features an intuitive and innovative user interface with support for layers, unlimited undo, special effects, and a wide variety of useful and powerful tools. An active and growing online community provides friendly help, tutorials, and plugins.\"\n\nWhen using Paint.NET, the default file format that the images are saved in are PDN's, which is a proprietary format Paint.NET uses. The benefit of this format over BMP, PNG, JPEG, etc is that it stores layer information and properties that are not present in traditional image formats.\n\nYou can get Paint.NET `here \u003chttps://www.getpaint.net/\u003e`_.\n\nPaint.NET is developed using C# (hence the .NET). Besides a basic XML header at the beginning, it primarily uses the\nBinaryFormatter class in C# to save the relevant classes when saving an image. This uses the `NRBF protocol\n\u003chttps://msdn.microsoft.com/en-us/library/cc236844.aspx\u003e`_. A custom reader was developed to read the NRBF file and\nthen this library essentially just parses the data from NRBF into more readable and user-friendly format. You can\naccess the NRBF reader from the pypdn module as well in case you have any use for it.\n\nInstalling\n=================\nPrerequisites\n-------------\n* Python 3.4+\n* Dependencies:\n    * numpy\n    * aenum\n\nInstalling pypdn\n-------------------------\npypdn is currently available on `PyPi \u003chttps://pypi.python.org/pypi/pypdn/\u003e`_. The simplest way to\ninstall alone is using ``pip`` at a command line::\n\n  pip install pypdn\n\nwhich installs the latest release.  To install the latest code from the repository (usually stable, but may have\nundocumented changes or bugs)::\n\n  pip install git+https://github.com/addisonElliott/pypdn.git\n\n\nFor developers, you can clone the pypdn repository and run the ``setup.py`` file. Use the following commands to get\na copy from GitHub and install all dependencies::\n\n  git clone pip install git+https://github.com/addisonElliott/pypdn.git\n  cd pypdn\n  pip install .\n\nor, for the last line, instead use::\n\n  pip install -e .\n\nto install in 'develop' or 'editable' mode, where changes can be made to the local working code and Python will use\nthe updated code.\n\nTest and coverage\n=================\nTo test the code on any platform, make sure to clone the GitHub repository to get the tests and run the following from\nthe repository directory::\n\n  python -m unittest discover -v tests\n\nExample\n=================\nFor the below example, any PDN file will do. If you are looking for an example, check out the tests/data directory for\nsome!\n\n.. code-block:: python\n\n    import pypdn\n    import matplotlib.pyplot as plt\n\n    layeredImage = pypdn.read('Untitled3.pdn')\n    print(layeredImage)\n    # Contains width, height, version and layers of the image within the class\n    # Version being the Paint.NET version that the image was saved with\n\n    # Each layer contains the name, visibility boolean, opacity (0-255), isBackground and blendMode\n    # From what I can tell, the isBackground property is not that useful\n    # The blend mode is how the layer should be blended with the layers below it\n    # These attributes are loaded from the PDN file but can be edited in the code as well\n    print(layeredImage.layers)\n    layer = layeredImage.layers[0]\n    layer.visible = True\n    layer.opacity = 255\n    layer.blendMode = pypdn.BlendType.Normal\n\n    layer = layeredImage.layers[1]\n    layer.visible = True\n    layer.opacity = 161\n    layer.blendMode = pypdn.BlendType.Additive\n\n    # Finally, the most useful thing is being able to combine the layers and flattn them into one image\n    # Call the flatten function to do so\n    # It will go through each layer and apply them IF the visibility is true!\n    # The layer opacity and blend mode will be taken into effect\n    #\n    # The flattened image is a RGBA Numpy array image\n    # The asByte parameter determines the data type of the flattened image\n    # If asByte is True, then the dtype will be uint8, otherwise it will be a float in range (0.0, 1.0)\n    flatImage = layeredImage.flatten(asByte=True)\n\n    plt.figure()\n    plt.imshow(flatImage)\n\n    # Individual layer images can be retrieved as well\n    # Note: This does NOT apply blending or the layer opacity\n    # Rather, it is the image data that is saved by Paint.NET for the layer\n    plt.figure()\n    plt.imshow(layeredImage.layers[1].image)\n\n    plt.show()\n\nUsing the Untitled3.pdn in the tests/data directory, this is the text output:\n\n.. code-block::\n\n    \u003e\u003e\u003e print(layeredImage)\n    pypdn.LayeredImage(width=800, height=600, version=System_Version(Major=4, Minor=21, Build=6589, Revision=7045), layers=[pypdn.Layer(name=Background, visible=True, isBackground=True, opacity=255, blendMode=\u003cBlendType.Normal: 0\u003e), pypdn.Layer(name=Layer 2, visible=True, isBackground=False, opacity=161, blendMode=\u003cBlendType.Additive: 2\u003e)])\n\n    \u003e\u003e\u003e print(layeredImage.layers)\n    [pypdn.Layer(name=Background, visible=True, isBackground=True, opacity=255, blendMode=\u003cBlendType.Normal: 0\u003e), pypdn.Layer(name=Layer 2, visible=True, isBackground=False, opacity=161, blendMode=\u003cBlendType.Additive: 2\u003e)]\n\nRoadmap \u0026 Bugs\n=================\n- Write docstrings and create basic documentation for NRBF and PDN classes\n- Fix issue where _id and _classID are mixed up in NRBF reader\n- Add support for writing NRBF files\n- Write unit tests for NRBF\n- Add support for writing PDN files (must complete writing NRBF files first)\n\nPull requests are welcome (and encouraged) for any or all issues!\n\nLicense\n=================\npypdn has an MIT-based `license \u003chttps://github.com/addisonElliott/pypdn/blob/master/LICENSE\u003e`_.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faddisonelliott%2Fpypdn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faddisonelliott%2Fpypdn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faddisonelliott%2Fpypdn/lists"}